Merge branch 'topic/sh' into for-linus
Conflicts: drivers/dma/sh/Kconfig drivers/dma/sh/shdmac.c Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
commit
265d9c673d
|
@ -22,42 +22,51 @@ Optional properties (currently unused):
|
||||||
* DMA controller
|
* DMA controller
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should be "renesas,shdma"
|
- compatible: should be of the form "renesas,shdma-<soc>", where <soc> should
|
||||||
|
be replaced with the desired SoC model, e.g.
|
||||||
|
"renesas,shdma-r8a73a4" for the system DMAC on r8a73a4 SoC
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
dmac: dma-mux0 {
|
dmac: dma-multiplexer@0 {
|
||||||
compatible = "renesas,shdma-mux";
|
compatible = "renesas,shdma-mux";
|
||||||
#dma-cells = <1>;
|
#dma-cells = <1>;
|
||||||
dma-channels = <6>;
|
dma-channels = <20>;
|
||||||
dma-requests = <256>;
|
dma-requests = <256>;
|
||||||
reg = <0 0>; /* Needed for AUXDATA */
|
#address-cells = <2>;
|
||||||
#address-cells = <1>;
|
#size-cells = <2>;
|
||||||
#size-cells = <1>;
|
|
||||||
ranges;
|
ranges;
|
||||||
|
|
||||||
dma0: shdma@fe008020 {
|
dma0: dma-controller@e6700020 {
|
||||||
compatible = "renesas,shdma";
|
compatible = "renesas,shdma-r8a73a4";
|
||||||
reg = <0xfe008020 0x270>,
|
reg = <0 0xe6700020 0 0x89e0>;
|
||||||
<0xfe009000 0xc>;
|
|
||||||
interrupt-parent = <&gic>;
|
interrupt-parent = <&gic>;
|
||||||
interrupts = <0 34 4
|
interrupts = <0 220 4
|
||||||
0 28 4
|
0 200 4
|
||||||
0 29 4
|
0 201 4
|
||||||
0 30 4
|
0 202 4
|
||||||
0 31 4
|
0 203 4
|
||||||
0 32 4
|
0 204 4
|
||||||
0 33 4>;
|
0 205 4
|
||||||
|
0 206 4
|
||||||
|
0 207 4
|
||||||
|
0 208 4
|
||||||
|
0 209 4
|
||||||
|
0 210 4
|
||||||
|
0 211 4
|
||||||
|
0 212 4
|
||||||
|
0 213 4
|
||||||
|
0 214 4
|
||||||
|
0 215 4
|
||||||
|
0 216 4
|
||||||
|
0 217 4
|
||||||
|
0 218 4
|
||||||
|
0 219 4>;
|
||||||
interrupt-names = "error",
|
interrupt-names = "error",
|
||||||
"ch0", "ch1", "ch2", "ch3",
|
"ch0", "ch1", "ch2", "ch3",
|
||||||
"ch4", "ch5";
|
"ch4", "ch5", "ch6", "ch7",
|
||||||
};
|
"ch8", "ch9", "ch10", "ch11",
|
||||||
|
"ch12", "ch13", "ch14", "ch15",
|
||||||
dma1: shdma@fe018020 {
|
"ch16", "ch17", "ch18", "ch19";
|
||||||
...
|
|
||||||
};
|
|
||||||
|
|
||||||
dma2: shdma@fe028020 {
|
|
||||||
...
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,3 +28,7 @@ config RCAR_HPB_DMAE
|
||||||
depends on SH_DMAE_BASE
|
depends on SH_DMAE_BASE
|
||||||
help
|
help
|
||||||
Enable support for the Renesas R-Car series DMA controllers.
|
Enable support for the Renesas R-Car series DMA controllers.
|
||||||
|
|
||||||
|
config SHDMA_R8A73A4
|
||||||
|
def_bool y
|
||||||
|
depends on ARCH_R8A73A4 && SH_DMAE != n
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
|
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
|
||||||
obj-$(CONFIG_SH_DMAE) += shdma.o
|
obj-$(CONFIG_SH_DMAE) += shdma.o
|
||||||
|
shdma-y := shdmac.o
|
||||||
|
ifeq ($(CONFIG_OF),y)
|
||||||
|
shdma-$(CONFIG_SHDMA_R8A73A4) += shdma-r8a73a4.o
|
||||||
|
endif
|
||||||
|
shdma-objs := $(shdma-y)
|
||||||
obj-$(CONFIG_SUDMAC) += sudmac.o
|
obj-$(CONFIG_SUDMAC) += sudmac.o
|
||||||
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
|
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Renesas SuperH DMA Engine support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Renesas Electronics, Inc.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of version 2 the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHDMA_ARM_H
|
||||||
|
#define SHDMA_ARM_H
|
||||||
|
|
||||||
|
#include "shdma.h"
|
||||||
|
|
||||||
|
/* Transmit sizes and respective CHCR register values */
|
||||||
|
enum {
|
||||||
|
XMIT_SZ_8BIT = 0,
|
||||||
|
XMIT_SZ_16BIT = 1,
|
||||||
|
XMIT_SZ_32BIT = 2,
|
||||||
|
XMIT_SZ_64BIT = 7,
|
||||||
|
XMIT_SZ_128BIT = 3,
|
||||||
|
XMIT_SZ_256BIT = 4,
|
||||||
|
XMIT_SZ_512BIT = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* log2(size / 8) - used to calculate number of transfers */
|
||||||
|
#define SH_DMAE_TS_SHIFT { \
|
||||||
|
[XMIT_SZ_8BIT] = 0, \
|
||||||
|
[XMIT_SZ_16BIT] = 1, \
|
||||||
|
[XMIT_SZ_32BIT] = 2, \
|
||||||
|
[XMIT_SZ_64BIT] = 3, \
|
||||||
|
[XMIT_SZ_128BIT] = 4, \
|
||||||
|
[XMIT_SZ_256BIT] = 5, \
|
||||||
|
[XMIT_SZ_512BIT] = 6, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TS_LOW_BIT 0x3 /* --xx */
|
||||||
|
#define TS_HI_BIT 0xc /* xx-- */
|
||||||
|
|
||||||
|
#define TS_LOW_SHIFT (3)
|
||||||
|
#define TS_HI_SHIFT (20 - 2) /* 2 bits for shifted low TS */
|
||||||
|
|
||||||
|
#define TS_INDEX2VAL(i) \
|
||||||
|
((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\
|
||||||
|
(((i) & TS_HI_BIT) << TS_HI_SHIFT))
|
||||||
|
|
||||||
|
#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
|
||||||
|
#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
|
||||||
|
|
||||||
|
#endif
|
|
@ -171,7 +171,8 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
|
static int shdma_setup_slave(struct shdma_chan *schan, int slave_id,
|
||||||
|
dma_addr_t slave_addr)
|
||||||
{
|
{
|
||||||
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
|
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
|
||||||
const struct shdma_ops *ops = sdev->ops;
|
const struct shdma_ops *ops = sdev->ops;
|
||||||
|
@ -179,7 +180,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
|
||||||
|
|
||||||
if (schan->dev->of_node) {
|
if (schan->dev->of_node) {
|
||||||
match = schan->hw_req;
|
match = schan->hw_req;
|
||||||
ret = ops->set_slave(schan, match, true);
|
ret = ops->set_slave(schan, match, slave_addr, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
|
||||||
if (test_and_set_bit(slave_id, shdma_slave_used))
|
if (test_and_set_bit(slave_id, shdma_slave_used))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
ret = ops->set_slave(schan, match, false);
|
ret = ops->set_slave(schan, match, slave_addr, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
clear_bit(slave_id, shdma_slave_used);
|
clear_bit(slave_id, shdma_slave_used);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -236,7 +237,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
|
||||||
if (!schan->dev->of_node && match >= slave_num)
|
if (!schan->dev->of_node && match >= slave_num)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ret = ops->set_slave(schan, match, true);
|
ret = ops->set_slave(schan, match, 0, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -259,7 +260,7 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
|
||||||
*/
|
*/
|
||||||
if (slave) {
|
if (slave) {
|
||||||
/* Legacy mode: .private is set in filter */
|
/* Legacy mode: .private is set in filter */
|
||||||
ret = shdma_setup_slave(schan, slave->slave_id);
|
ret = shdma_setup_slave(schan, slave->slave_id, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto esetslave;
|
goto esetslave;
|
||||||
} else {
|
} else {
|
||||||
|
@ -680,7 +681,9 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||||
* channel, while using it...
|
* channel, while using it...
|
||||||
*/
|
*/
|
||||||
config = (struct dma_slave_config *)arg;
|
config = (struct dma_slave_config *)arg;
|
||||||
ret = shdma_setup_slave(schan, config->slave_id);
|
ret = shdma_setup_slave(schan, config->slave_id,
|
||||||
|
config->direction == DMA_DEV_TO_MEM ?
|
||||||
|
config->src_addr : config->dst_addr);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
|
@ -831,8 +834,8 @@ static irqreturn_t chan_irqt(int irq, void *dev)
|
||||||
int shdma_request_irq(struct shdma_chan *schan, int irq,
|
int shdma_request_irq(struct shdma_chan *schan, int irq,
|
||||||
unsigned long flags, const char *name)
|
unsigned long flags, const char *name)
|
||||||
{
|
{
|
||||||
int ret = request_threaded_irq(irq, chan_irq, chan_irqt,
|
int ret = devm_request_threaded_irq(schan->dev, irq, chan_irq,
|
||||||
flags, name, schan);
|
chan_irqt, flags, name, schan);
|
||||||
|
|
||||||
schan->irq = ret < 0 ? ret : irq;
|
schan->irq = ret < 0 ? ret : irq;
|
||||||
|
|
||||||
|
@ -840,13 +843,6 @@ int shdma_request_irq(struct shdma_chan *schan, int irq,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(shdma_request_irq);
|
EXPORT_SYMBOL(shdma_request_irq);
|
||||||
|
|
||||||
void shdma_free_irq(struct shdma_chan *schan)
|
|
||||||
{
|
|
||||||
if (schan->irq >= 0)
|
|
||||||
free_irq(schan->irq, schan);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(shdma_free_irq);
|
|
||||||
|
|
||||||
void shdma_chan_probe(struct shdma_dev *sdev,
|
void shdma_chan_probe(struct shdma_dev *sdev,
|
||||||
struct shdma_chan *schan, int id)
|
struct shdma_chan *schan, int id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,9 +45,6 @@ static int shdma_of_probe(struct platform_device *pdev)
|
||||||
const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
|
const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!lookup)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ret = of_dma_controller_register(pdev->dev.of_node,
|
ret = of_dma_controller_register(pdev->dev.of_node,
|
||||||
shdma_of_xlate, pdev);
|
shdma_of_xlate, pdev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Renesas Electronics, Inc.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it under the
|
||||||
|
* terms of version 2 the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*/
|
||||||
|
#include <linux/sh_dma.h>
|
||||||
|
|
||||||
|
#include "shdma-arm.h"
|
||||||
|
|
||||||
|
const unsigned int dma_ts_shift[] = SH_DMAE_TS_SHIFT;
|
||||||
|
|
||||||
|
static const struct sh_dmae_slave_config dma_slaves[] = {
|
||||||
|
{
|
||||||
|
.chcr = CHCR_TX(XMIT_SZ_32BIT),
|
||||||
|
.mid_rid = 0xd1, /* MMC0 Tx */
|
||||||
|
}, {
|
||||||
|
.chcr = CHCR_RX(XMIT_SZ_32BIT),
|
||||||
|
.mid_rid = 0xd2, /* MMC0 Rx */
|
||||||
|
}, {
|
||||||
|
.chcr = CHCR_TX(XMIT_SZ_32BIT),
|
||||||
|
.mid_rid = 0xe1, /* MMC1 Tx */
|
||||||
|
}, {
|
||||||
|
.chcr = CHCR_RX(XMIT_SZ_32BIT),
|
||||||
|
.mid_rid = 0xe2, /* MMC1 Rx */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DMAE_CHANNEL(a, b) \
|
||||||
|
{ \
|
||||||
|
.offset = (a) - 0x20, \
|
||||||
|
.dmars = (a) - 0x20 + 0x40, \
|
||||||
|
.chclr_bit = (b), \
|
||||||
|
.chclr_offset = 0x80 - 0x20, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sh_dmae_channel dma_channels[] = {
|
||||||
|
DMAE_CHANNEL(0x8000, 0),
|
||||||
|
DMAE_CHANNEL(0x8080, 1),
|
||||||
|
DMAE_CHANNEL(0x8100, 2),
|
||||||
|
DMAE_CHANNEL(0x8180, 3),
|
||||||
|
DMAE_CHANNEL(0x8200, 4),
|
||||||
|
DMAE_CHANNEL(0x8280, 5),
|
||||||
|
DMAE_CHANNEL(0x8300, 6),
|
||||||
|
DMAE_CHANNEL(0x8380, 7),
|
||||||
|
DMAE_CHANNEL(0x8400, 8),
|
||||||
|
DMAE_CHANNEL(0x8480, 9),
|
||||||
|
DMAE_CHANNEL(0x8500, 10),
|
||||||
|
DMAE_CHANNEL(0x8580, 11),
|
||||||
|
DMAE_CHANNEL(0x8600, 12),
|
||||||
|
DMAE_CHANNEL(0x8680, 13),
|
||||||
|
DMAE_CHANNEL(0x8700, 14),
|
||||||
|
DMAE_CHANNEL(0x8780, 15),
|
||||||
|
DMAE_CHANNEL(0x8800, 16),
|
||||||
|
DMAE_CHANNEL(0x8880, 17),
|
||||||
|
DMAE_CHANNEL(0x8900, 18),
|
||||||
|
DMAE_CHANNEL(0x8980, 19),
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct sh_dmae_pdata r8a73a4_dma_pdata = {
|
||||||
|
.slave = dma_slaves,
|
||||||
|
.slave_num = ARRAY_SIZE(dma_slaves),
|
||||||
|
.channel = dma_channels,
|
||||||
|
.channel_num = ARRAY_SIZE(dma_channels),
|
||||||
|
.ts_low_shift = TS_LOW_SHIFT,
|
||||||
|
.ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT,
|
||||||
|
.ts_high_shift = TS_HI_SHIFT,
|
||||||
|
.ts_high_mask = TS_HI_BIT << TS_HI_SHIFT,
|
||||||
|
.ts_shift = dma_ts_shift,
|
||||||
|
.ts_shift_num = ARRAY_SIZE(dma_ts_shift),
|
||||||
|
.dmaor_init = DMAOR_DME,
|
||||||
|
.chclr_present = 1,
|
||||||
|
.chclr_bitwise = 1,
|
||||||
|
};
|
|
@ -28,18 +28,19 @@ struct sh_dmae_chan {
|
||||||
struct shdma_chan shdma_chan;
|
struct shdma_chan shdma_chan;
|
||||||
const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
|
const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
|
||||||
int xmit_shift; /* log_2(bytes_per_xfer) */
|
int xmit_shift; /* log_2(bytes_per_xfer) */
|
||||||
u32 __iomem *base;
|
void __iomem *base;
|
||||||
char dev_id[16]; /* unique name per DMAC of channel */
|
char dev_id[16]; /* unique name per DMAC of channel */
|
||||||
int pm_error;
|
int pm_error;
|
||||||
|
dma_addr_t slave_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sh_dmae_device {
|
struct sh_dmae_device {
|
||||||
struct shdma_dev shdma_dev;
|
struct shdma_dev shdma_dev;
|
||||||
struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS];
|
struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS];
|
||||||
struct sh_dmae_pdata *pdata;
|
const struct sh_dmae_pdata *pdata;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
u32 __iomem *chan_reg;
|
void __iomem *chan_reg;
|
||||||
u16 __iomem *dmars;
|
void __iomem *dmars;
|
||||||
unsigned int chcr_offset;
|
unsigned int chcr_offset;
|
||||||
u32 chcr_ie_bit;
|
u32 chcr_ie_bit;
|
||||||
};
|
};
|
||||||
|
@ -61,4 +62,11 @@ struct sh_dmae_desc {
|
||||||
#define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\
|
#define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\
|
||||||
struct sh_dmae_device, shdma_dev.dma_dev)
|
struct sh_dmae_device, shdma_dev.dma_dev)
|
||||||
|
|
||||||
|
#ifdef CONFIG_SHDMA_R8A73A4
|
||||||
|
extern const struct sh_dmae_pdata r8a73a4_dma_pdata;
|
||||||
|
#define r8a73a4_shdma_devid (&r8a73a4_dma_pdata)
|
||||||
|
#else
|
||||||
|
#define r8a73a4_shdma_devid NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __DMA_SHDMA_H */
|
#endif /* __DMA_SHDMA_H */
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
|
@ -35,6 +37,15 @@
|
||||||
#include "../dmaengine.h"
|
#include "../dmaengine.h"
|
||||||
#include "shdma.h"
|
#include "shdma.h"
|
||||||
|
|
||||||
|
/* DMA register */
|
||||||
|
#define SAR 0x00
|
||||||
|
#define DAR 0x04
|
||||||
|
#define TCR 0x08
|
||||||
|
#define CHCR 0x0C
|
||||||
|
#define DMAOR 0x40
|
||||||
|
|
||||||
|
#define TEND 0x18 /* USB-DMAC */
|
||||||
|
|
||||||
#define SH_DMAE_DRV_NAME "sh-dma-engine"
|
#define SH_DMAE_DRV_NAME "sh-dma-engine"
|
||||||
|
|
||||||
/* Default MEMCPY transfer size = 2^2 = 4 bytes */
|
/* Default MEMCPY transfer size = 2^2 = 4 bytes */
|
||||||
|
@ -49,27 +60,37 @@
|
||||||
static DEFINE_SPINLOCK(sh_dmae_lock);
|
static DEFINE_SPINLOCK(sh_dmae_lock);
|
||||||
static LIST_HEAD(sh_dmae_devices);
|
static LIST_HEAD(sh_dmae_devices);
|
||||||
|
|
||||||
static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data)
|
/*
|
||||||
|
* Different DMAC implementations provide different ways to clear DMA channels:
|
||||||
|
* (1) none - no CHCLR registers are available
|
||||||
|
* (2) one CHCLR register per channel - 0 has to be written to it to clear
|
||||||
|
* channel buffers
|
||||||
|
* (3) one CHCLR per several channels - 1 has to be written to the bit,
|
||||||
|
* corresponding to the specific channel to reset it
|
||||||
|
*/
|
||||||
|
static void channel_clear(struct sh_dmae_chan *sh_dc)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
||||||
|
const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel +
|
||||||
|
sh_dc->shdma_chan.id;
|
||||||
|
u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0;
|
||||||
|
|
||||||
__raw_writel(data, shdev->chan_reg +
|
__raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset);
|
||||||
shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
|
static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
|
||||||
{
|
{
|
||||||
__raw_writel(data, sh_dc->base + reg / sizeof(u32));
|
__raw_writel(data, sh_dc->base + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
|
static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
|
||||||
{
|
{
|
||||||
return __raw_readl(sh_dc->base + reg / sizeof(u32));
|
return __raw_readl(sh_dc->base + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16 dmaor_read(struct sh_dmae_device *shdev)
|
static u16 dmaor_read(struct sh_dmae_device *shdev)
|
||||||
{
|
{
|
||||||
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
|
void __iomem *addr = shdev->chan_reg + DMAOR;
|
||||||
|
|
||||||
if (shdev->pdata->dmaor_is_32bit)
|
if (shdev->pdata->dmaor_is_32bit)
|
||||||
return __raw_readl(addr);
|
return __raw_readl(addr);
|
||||||
|
@ -79,7 +100,7 @@ static u16 dmaor_read(struct sh_dmae_device *shdev)
|
||||||
|
|
||||||
static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
|
static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
|
||||||
{
|
{
|
||||||
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
|
void __iomem *addr = shdev->chan_reg + DMAOR;
|
||||||
|
|
||||||
if (shdev->pdata->dmaor_is_32bit)
|
if (shdev->pdata->dmaor_is_32bit)
|
||||||
__raw_writel(data, addr);
|
__raw_writel(data, addr);
|
||||||
|
@ -91,14 +112,14 @@ static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
||||||
|
|
||||||
__raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32));
|
__raw_writel(data, sh_dc->base + shdev->chcr_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 chcr_read(struct sh_dmae_chan *sh_dc)
|
static u32 chcr_read(struct sh_dmae_chan *sh_dc)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
|
||||||
|
|
||||||
return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32));
|
return __raw_readl(sh_dc->base + shdev->chcr_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -133,7 +154,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
|
||||||
for (i = 0; i < shdev->pdata->channel_num; i++) {
|
for (i = 0; i < shdev->pdata->channel_num; i++) {
|
||||||
struct sh_dmae_chan *sh_chan = shdev->chan[i];
|
struct sh_dmae_chan *sh_chan = shdev->chan[i];
|
||||||
if (sh_chan)
|
if (sh_chan)
|
||||||
chclr_write(sh_chan, 0);
|
channel_clear(sh_chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +188,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
|
||||||
static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
|
static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
||||||
struct sh_dmae_pdata *pdata = shdev->pdata;
|
const struct sh_dmae_pdata *pdata = shdev->pdata;
|
||||||
int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
|
int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
|
||||||
((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
|
((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
|
||||||
|
|
||||||
|
@ -180,7 +201,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
|
||||||
static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
|
static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
||||||
struct sh_dmae_pdata *pdata = shdev->pdata;
|
const struct sh_dmae_pdata *pdata = shdev->pdata;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < pdata->ts_shift_num; i++)
|
for (i = 0; i < pdata->ts_shift_num; i++)
|
||||||
|
@ -240,9 +261,9 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
|
||||||
static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
|
static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
||||||
struct sh_dmae_pdata *pdata = shdev->pdata;
|
const struct sh_dmae_pdata *pdata = shdev->pdata;
|
||||||
const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
|
const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
|
||||||
u16 __iomem *addr = shdev->dmars;
|
void __iomem *addr = shdev->dmars;
|
||||||
unsigned int shift = chan_pdata->dmars_bit;
|
unsigned int shift = chan_pdata->dmars_bit;
|
||||||
|
|
||||||
if (dmae_is_busy(sh_chan))
|
if (dmae_is_busy(sh_chan))
|
||||||
|
@ -253,8 +274,8 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
|
||||||
|
|
||||||
/* in the case of a missing DMARS resource use first memory window */
|
/* in the case of a missing DMARS resource use first memory window */
|
||||||
if (!addr)
|
if (!addr)
|
||||||
addr = (u16 __iomem *)shdev->chan_reg;
|
addr = shdev->chan_reg;
|
||||||
addr += chan_pdata->dmars / sizeof(u16);
|
addr += chan_pdata->dmars;
|
||||||
|
|
||||||
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
|
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
|
||||||
addr);
|
addr);
|
||||||
|
@ -309,7 +330,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
|
||||||
struct sh_dmae_chan *sh_chan, int match)
|
struct sh_dmae_chan *sh_chan, int match)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
|
||||||
struct sh_dmae_pdata *pdata = shdev->pdata;
|
const struct sh_dmae_pdata *pdata = shdev->pdata;
|
||||||
const struct sh_dmae_slave_config *cfg;
|
const struct sh_dmae_slave_config *cfg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -323,7 +344,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
|
||||||
} else {
|
} else {
|
||||||
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
|
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
|
||||||
if (cfg->mid_rid == match) {
|
if (cfg->mid_rid == match) {
|
||||||
sh_chan->shdma_chan.slave_id = cfg->slave_id;
|
sh_chan->shdma_chan.slave_id = i;
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,7 +353,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_dmae_set_slave(struct shdma_chan *schan,
|
static int sh_dmae_set_slave(struct shdma_chan *schan,
|
||||||
int slave_id, bool try)
|
int slave_id, dma_addr_t slave_addr, bool try)
|
||||||
{
|
{
|
||||||
struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
|
struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
|
||||||
shdma_chan);
|
shdma_chan);
|
||||||
|
@ -340,8 +361,10 @@ static int sh_dmae_set_slave(struct shdma_chan *schan,
|
||||||
if (!cfg)
|
if (!cfg)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
if (!try)
|
if (!try) {
|
||||||
sh_chan->config = cfg;
|
sh_chan->config = cfg;
|
||||||
|
sh_chan->slave_addr = slave_addr ? : cfg->addr;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -505,7 +528,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
|
||||||
struct shdma_chan *schan;
|
struct shdma_chan *schan;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sh_chan = kzalloc(sizeof(struct sh_dmae_chan), GFP_KERNEL);
|
sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!sh_chan) {
|
if (!sh_chan) {
|
||||||
dev_err(sdev->dma_dev.dev,
|
dev_err(sdev->dma_dev.dev,
|
||||||
"No free memory for allocating dma channels!\n");
|
"No free memory for allocating dma channels!\n");
|
||||||
|
@ -517,7 +541,7 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
|
||||||
|
|
||||||
shdma_chan_probe(sdev, schan, id);
|
shdma_chan_probe(sdev, schan, id);
|
||||||
|
|
||||||
sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32);
|
sh_chan->base = shdev->chan_reg + chan_pdata->offset;
|
||||||
|
|
||||||
/* set up channel irq */
|
/* set up channel irq */
|
||||||
if (pdev->id >= 0)
|
if (pdev->id >= 0)
|
||||||
|
@ -541,7 +565,6 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
|
||||||
err_no_irq:
|
err_no_irq:
|
||||||
/* remove from dmaengine device node */
|
/* remove from dmaengine device node */
|
||||||
shdma_chan_remove(schan);
|
shdma_chan_remove(schan);
|
||||||
kfree(sh_chan);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,14 +575,9 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
shdma_for_each_chan(schan, &shdev->shdma_dev, i) {
|
shdma_for_each_chan(schan, &shdev->shdma_dev, i) {
|
||||||
struct sh_dmae_chan *sh_chan = container_of(schan,
|
|
||||||
struct sh_dmae_chan, shdma_chan);
|
|
||||||
BUG_ON(!schan);
|
BUG_ON(!schan);
|
||||||
|
|
||||||
shdma_free_irq(&sh_chan->shdma_chan);
|
|
||||||
|
|
||||||
shdma_chan_remove(schan);
|
shdma_chan_remove(schan);
|
||||||
kfree(sh_chan);
|
|
||||||
}
|
}
|
||||||
dma_dev->chancnt = 0;
|
dma_dev->chancnt = 0;
|
||||||
}
|
}
|
||||||
|
@ -636,7 +654,7 @@ static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
|
||||||
* This is an exclusive slave DMA operation, may only be called after a
|
* This is an exclusive slave DMA operation, may only be called after a
|
||||||
* successful slave configuration.
|
* successful slave configuration.
|
||||||
*/
|
*/
|
||||||
return sh_chan->config->addr;
|
return sh_chan->slave_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
|
static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
|
||||||
|
@ -658,9 +676,15 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
|
||||||
.get_partial = sh_dmae_get_partial,
|
.get_partial = sh_dmae_get_partial,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id sh_dmae_of_match[] = {
|
||||||
|
{.compatible = "renesas,shdma-r8a73a4", .data = r8a73a4_shdma_devid,},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
|
||||||
|
|
||||||
static int sh_dmae_probe(struct platform_device *pdev)
|
static int sh_dmae_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sh_dmae_pdata *pdata = dev_get_platdata(&pdev->dev);
|
const struct sh_dmae_pdata *pdata;
|
||||||
unsigned long irqflags = IRQF_DISABLED,
|
unsigned long irqflags = IRQF_DISABLED,
|
||||||
chan_flag[SH_DMAE_MAX_CHANNELS] = {};
|
chan_flag[SH_DMAE_MAX_CHANNELS] = {};
|
||||||
int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
|
int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
|
||||||
|
@ -669,6 +693,11 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
||||||
struct dma_device *dma_dev;
|
struct dma_device *dma_dev;
|
||||||
struct resource *chan, *dmars, *errirq_res, *chanirq_res;
|
struct resource *chan, *dmars, *errirq_res, *chanirq_res;
|
||||||
|
|
||||||
|
if (pdev->dev.of_node)
|
||||||
|
pdata = of_match_device(sh_dmae_of_match, &pdev->dev)->data;
|
||||||
|
else
|
||||||
|
pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
|
||||||
/* get platform data */
|
/* get platform data */
|
||||||
if (!pdata || !pdata->channel_num)
|
if (!pdata || !pdata->channel_num)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -696,33 +725,22 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
||||||
if (!chan || !errirq_res)
|
if (!chan || !errirq_res)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) {
|
shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
|
||||||
dev_err(&pdev->dev, "DMAC register region already claimed\n");
|
GFP_KERNEL);
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) {
|
|
||||||
dev_err(&pdev->dev, "DMAC DMARS region already claimed\n");
|
|
||||||
err = -EBUSY;
|
|
||||||
goto ermrdmars;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = -ENOMEM;
|
|
||||||
shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL);
|
|
||||||
if (!shdev) {
|
if (!shdev) {
|
||||||
dev_err(&pdev->dev, "Not enough memory\n");
|
dev_err(&pdev->dev, "Not enough memory\n");
|
||||||
goto ealloc;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
dma_dev = &shdev->shdma_dev.dma_dev;
|
dma_dev = &shdev->shdma_dev.dma_dev;
|
||||||
|
|
||||||
shdev->chan_reg = ioremap(chan->start, resource_size(chan));
|
shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
|
||||||
if (!shdev->chan_reg)
|
if (IS_ERR(shdev->chan_reg))
|
||||||
goto emapchan;
|
return PTR_ERR(shdev->chan_reg);
|
||||||
if (dmars) {
|
if (dmars) {
|
||||||
shdev->dmars = ioremap(dmars->start, resource_size(dmars));
|
shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars);
|
||||||
if (!shdev->dmars)
|
if (IS_ERR(shdev->dmars))
|
||||||
goto emapdmars;
|
return PTR_ERR(shdev->dmars);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdata->slave_only)
|
if (!pdata->slave_only)
|
||||||
|
@ -783,7 +801,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
errirq = errirq_res->start;
|
errirq = errirq_res->start;
|
||||||
|
|
||||||
err = request_irq(errirq, sh_dmae_err, irqflags,
|
err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags,
|
||||||
"DMAC Address Error", shdev);
|
"DMAC Address Error", shdev);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
|
@ -862,7 +880,6 @@ chan_probe_err:
|
||||||
sh_dmae_chan_remove(shdev);
|
sh_dmae_chan_remove(shdev);
|
||||||
|
|
||||||
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
|
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
|
||||||
free_irq(errirq, shdev);
|
|
||||||
eirq_err:
|
eirq_err:
|
||||||
#endif
|
#endif
|
||||||
rst_err:
|
rst_err:
|
||||||
|
@ -873,21 +890,9 @@ rst_err:
|
||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
shdma_cleanup(&shdev->shdma_dev);
|
shdma_cleanup(&shdev->shdma_dev);
|
||||||
eshdma:
|
eshdma:
|
||||||
if (dmars)
|
|
||||||
iounmap(shdev->dmars);
|
|
||||||
emapdmars:
|
|
||||||
iounmap(shdev->chan_reg);
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
emapchan:
|
|
||||||
kfree(shdev);
|
|
||||||
ealloc:
|
|
||||||
if (dmars)
|
|
||||||
release_mem_region(dmars->start, resource_size(dmars));
|
|
||||||
ermrdmars:
|
|
||||||
release_mem_region(chan->start, resource_size(chan));
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -896,14 +901,9 @@ static int sh_dmae_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
|
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
|
||||||
struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
|
struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
|
||||||
struct resource *res;
|
|
||||||
int errirq = platform_get_irq(pdev, 0);
|
|
||||||
|
|
||||||
dma_async_device_unregister(dma_dev);
|
dma_async_device_unregister(dma_dev);
|
||||||
|
|
||||||
if (errirq > 0)
|
|
||||||
free_irq(errirq, shdev);
|
|
||||||
|
|
||||||
spin_lock_irq(&sh_dmae_lock);
|
spin_lock_irq(&sh_dmae_lock);
|
||||||
list_del_rcu(&shdev->node);
|
list_del_rcu(&shdev->node);
|
||||||
spin_unlock_irq(&sh_dmae_lock);
|
spin_unlock_irq(&sh_dmae_lock);
|
||||||
|
@ -913,31 +913,11 @@ static int sh_dmae_remove(struct platform_device *pdev)
|
||||||
sh_dmae_chan_remove(shdev);
|
sh_dmae_chan_remove(shdev);
|
||||||
shdma_cleanup(&shdev->shdma_dev);
|
shdma_cleanup(&shdev->shdma_dev);
|
||||||
|
|
||||||
if (shdev->dmars)
|
|
||||||
iounmap(shdev->dmars);
|
|
||||||
iounmap(shdev->chan_reg);
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
kfree(shdev);
|
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
if (res)
|
|
||||||
release_mem_region(res->start, resource_size(res));
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
|
||||||
if (res)
|
|
||||||
release_mem_region(res->start, resource_size(res));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sh_dmae_of_match[] = {
|
|
||||||
{ .compatible = "renesas,shdma", },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver sh_dmae_driver = {
|
static struct platform_driver sh_dmae_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
|
@ -150,7 +150,8 @@ static const struct sudmac_slave_config *sudmac_find_slave(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, bool try)
|
static int sudmac_set_slave(struct shdma_chan *schan, int slave_id,
|
||||||
|
dma_addr_t slave_addr, bool try)
|
||||||
{
|
{
|
||||||
struct sudmac_chan *sc = to_chan(schan);
|
struct sudmac_chan *sc = to_chan(schan);
|
||||||
const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
|
const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
|
||||||
|
@ -298,11 +299,8 @@ static void sudmac_chan_remove(struct sudmac_device *su_dev)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
|
shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
|
||||||
struct sudmac_chan *sc = to_chan(schan);
|
|
||||||
|
|
||||||
BUG_ON(!schan);
|
BUG_ON(!schan);
|
||||||
|
|
||||||
shdma_free_irq(&sc->shdma_chan);
|
|
||||||
shdma_chan_remove(schan);
|
shdma_chan_remove(schan);
|
||||||
}
|
}
|
||||||
dma_dev->chancnt = 0;
|
dma_dev->chancnt = 0;
|
||||||
|
@ -393,7 +391,6 @@ static int sudmac_probe(struct platform_device *pdev)
|
||||||
chan_probe_err:
|
chan_probe_err:
|
||||||
sudmac_chan_remove(su_dev);
|
sudmac_chan_remove(su_dev);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
shdma_cleanup(&su_dev->shdma_dev);
|
shdma_cleanup(&su_dev->shdma_dev);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -407,7 +404,6 @@ static int sudmac_remove(struct platform_device *pdev)
|
||||||
dma_async_device_unregister(dma_dev);
|
dma_async_device_unregister(dma_dev);
|
||||||
sudmac_chan_remove(su_dev);
|
sudmac_chan_remove(su_dev);
|
||||||
shdma_cleanup(&su_dev->shdma_dev);
|
shdma_cleanup(&su_dev->shdma_dev);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,44 @@ struct sh_dmae_slave_config {
|
||||||
char mid_rid;
|
char mid_rid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sh_dmae_channel - DMAC channel platform data
|
||||||
|
* @offset: register offset within the main IOMEM resource
|
||||||
|
* @dmars: channel DMARS register offset
|
||||||
|
* @chclr_offset: channel CHCLR register offset
|
||||||
|
* @dmars_bit: channel DMARS field offset within the register
|
||||||
|
* @chclr_bit: bit position, to be set to reset the channel
|
||||||
|
*/
|
||||||
struct sh_dmae_channel {
|
struct sh_dmae_channel {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned int dmars;
|
unsigned int dmars;
|
||||||
unsigned int dmars_bit;
|
|
||||||
unsigned int chclr_offset;
|
unsigned int chclr_offset;
|
||||||
|
unsigned char dmars_bit;
|
||||||
|
unsigned char chclr_bit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sh_dmae_pdata - DMAC platform data
|
||||||
|
* @slave: array of slaves
|
||||||
|
* @slave_num: number of slaves in the above array
|
||||||
|
* @channel: array of DMA channels
|
||||||
|
* @channel_num: number of channels in the above array
|
||||||
|
* @ts_low_shift: shift of the low part of the TS field
|
||||||
|
* @ts_low_mask: low TS field mask
|
||||||
|
* @ts_high_shift: additional shift of the high part of the TS field
|
||||||
|
* @ts_high_mask: high TS field mask
|
||||||
|
* @ts_shift: array of Transfer Size shifts, indexed by TS value
|
||||||
|
* @ts_shift_num: number of shifts in the above array
|
||||||
|
* @dmaor_init: DMAOR initialisation value
|
||||||
|
* @chcr_offset: CHCR address offset
|
||||||
|
* @chcr_ie_bit: CHCR Interrupt Enable bit
|
||||||
|
* @dmaor_is_32bit: DMAOR is a 32-bit register
|
||||||
|
* @needs_tend_set: the TEND register has to be set
|
||||||
|
* @no_dmars: DMAC has no DMARS registers
|
||||||
|
* @chclr_present: DMAC has one or several CHCLR registers
|
||||||
|
* @chclr_bitwise: channel CHCLR registers are bitwise
|
||||||
|
* @slave_only: DMAC cannot be used for MEMCPY
|
||||||
|
*/
|
||||||
struct sh_dmae_pdata {
|
struct sh_dmae_pdata {
|
||||||
const struct sh_dmae_slave_config *slave;
|
const struct sh_dmae_slave_config *slave;
|
||||||
int slave_num;
|
int slave_num;
|
||||||
|
@ -59,42 +90,22 @@ struct sh_dmae_pdata {
|
||||||
unsigned int needs_tend_set:1;
|
unsigned int needs_tend_set:1;
|
||||||
unsigned int no_dmars:1;
|
unsigned int no_dmars:1;
|
||||||
unsigned int chclr_present:1;
|
unsigned int chclr_present:1;
|
||||||
|
unsigned int chclr_bitwise:1;
|
||||||
unsigned int slave_only:1;
|
unsigned int slave_only:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* DMA register */
|
|
||||||
#define SAR 0x00
|
|
||||||
#define DAR 0x04
|
|
||||||
#define TCR 0x08
|
|
||||||
#define CHCR 0x0C
|
|
||||||
#define DMAOR 0x40
|
|
||||||
|
|
||||||
#define TEND 0x18 /* USB-DMAC */
|
|
||||||
|
|
||||||
/* DMAOR definitions */
|
/* DMAOR definitions */
|
||||||
#define DMAOR_AE 0x00000004
|
#define DMAOR_AE 0x00000004
|
||||||
#define DMAOR_NMIF 0x00000002
|
#define DMAOR_NMIF 0x00000002
|
||||||
#define DMAOR_DME 0x00000001
|
#define DMAOR_DME 0x00000001
|
||||||
|
|
||||||
/* Definitions for the SuperH DMAC */
|
/* Definitions for the SuperH DMAC */
|
||||||
#define REQ_L 0x00000000
|
|
||||||
#define REQ_E 0x00080000
|
|
||||||
#define RACK_H 0x00000000
|
|
||||||
#define RACK_L 0x00040000
|
|
||||||
#define ACK_R 0x00000000
|
|
||||||
#define ACK_W 0x00020000
|
|
||||||
#define ACK_H 0x00000000
|
|
||||||
#define ACK_L 0x00010000
|
|
||||||
#define DM_INC 0x00004000
|
#define DM_INC 0x00004000
|
||||||
#define DM_DEC 0x00008000
|
#define DM_DEC 0x00008000
|
||||||
#define DM_FIX 0x0000c000
|
#define DM_FIX 0x0000c000
|
||||||
#define SM_INC 0x00001000
|
#define SM_INC 0x00001000
|
||||||
#define SM_DEC 0x00002000
|
#define SM_DEC 0x00002000
|
||||||
#define SM_FIX 0x00003000
|
#define SM_FIX 0x00003000
|
||||||
#define RS_IN 0x00000200
|
|
||||||
#define RS_OUT 0x00000300
|
|
||||||
#define TS_BLK 0x00000040
|
|
||||||
#define TM_BUR 0x00000020
|
|
||||||
#define CHCR_DE 0x00000001
|
#define CHCR_DE 0x00000001
|
||||||
#define CHCR_TE 0x00000002
|
#define CHCR_TE 0x00000002
|
||||||
#define CHCR_IE 0x00000004
|
#define CHCR_IE 0x00000004
|
||||||
|
|
|
@ -96,7 +96,7 @@ struct shdma_ops {
|
||||||
dma_addr_t (*slave_addr)(struct shdma_chan *);
|
dma_addr_t (*slave_addr)(struct shdma_chan *);
|
||||||
int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
|
int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
|
||||||
dma_addr_t, dma_addr_t, size_t *);
|
dma_addr_t, dma_addr_t, size_t *);
|
||||||
int (*set_slave)(struct shdma_chan *, int, bool);
|
int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool);
|
||||||
void (*setup_xfer)(struct shdma_chan *, int);
|
void (*setup_xfer)(struct shdma_chan *, int);
|
||||||
void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
|
void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
|
||||||
struct shdma_desc *(*embedded_desc)(void *, int);
|
struct shdma_desc *(*embedded_desc)(void *, int);
|
||||||
|
@ -116,7 +116,6 @@ struct shdma_dev {
|
||||||
|
|
||||||
int shdma_request_irq(struct shdma_chan *, int,
|
int shdma_request_irq(struct shdma_chan *, int,
|
||||||
unsigned long, const char *);
|
unsigned long, const char *);
|
||||||
void shdma_free_irq(struct shdma_chan *);
|
|
||||||
bool shdma_reset(struct shdma_dev *sdev);
|
bool shdma_reset(struct shdma_dev *sdev);
|
||||||
void shdma_chan_probe(struct shdma_dev *sdev,
|
void shdma_chan_probe(struct shdma_dev *sdev,
|
||||||
struct shdma_chan *schan, int id);
|
struct shdma_chan *schan, int id);
|
||||||
|
|
Loading…
Reference in New Issue