mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma
Pull dmaengine updates from Vinod Koul:
"This update brings:
- the big cleanup up by Maxime for device control and slave
capabilities. This makes the API much cleaner.
- new IMG MDC driver by Andrew
- new Renesas R-Car Gen2 DMA Controller driver by Laurent along with
bunch of fixes on rcar drivers
- odd fixes and updates spread over driver"
* 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma: (130 commits)
dmaengine: pl330: add DMA_PAUSE feature
dmaengine: pl330: improve pl330_tx_status() function
dmaengine: rcar-dmac: Disable channel 0 when using IOMMU
dmaengine: rcar-dmac: Work around descriptor mode IOMMU errata
dmaengine: rcar-dmac: Allocate hardware descriptors with DMAC device
dmaengine: rcar-dmac: Fix oops due to unintialized list in error ISR
dmaengine: rcar-dmac: Fix spinlock issues in interrupt
dmaenegine: edma: fix sparse warnings
dmaengine: rcar-dmac: Fix uninitialized variable usage
dmaengine: shdmac: extend PM methods
dmaengine: shdmac: use SET_RUNTIME_PM_OPS()
dmaengine: pl330: fix bug that cause start the same descs in cyclic
dmaengine: at_xdmac: allow muliple dwidths when doing slave transfers
dmaengine: at_xdmac: simplify channel configuration stuff
dmaengine: at_xdmac: introduce save_cc field
dmaengine: at_xdmac: wait for in-progress transaction to complete after pausing a channel
ioat: fail self-test if wait_for_completion times out
dmaengine: dw: define DW_DMA_MAX_NR_MASTERS
dmaengine: dw: amend description of dma_dev field
dmatest: move src_off, dst_off, len inside loop
...
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
* IMG Multi-threaded DMA Controller (MDC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "img,pistachio-mdc-dma".
|
||||
- reg: Must contain the base address and length of the MDC registers.
|
||||
- interrupts: Must contain all the per-channel DMA interrupts.
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
See ../clock/clock-bindings.txt for details.
|
||||
- clock-names: Must include the following entries:
|
||||
- sys: MDC system interface clock.
|
||||
- img,cr-periph: Must contain a phandle to the peripheral control syscon
|
||||
node which contains the DMA request to channel mapping registers.
|
||||
- img,max-burst-multiplier: Must be the maximum supported burst size multiplier.
|
||||
The maximum burst size is this value multiplied by the hardware-reported bus
|
||||
width.
|
||||
- #dma-cells: Must be 3:
|
||||
- The first cell is the peripheral's DMA request line.
|
||||
- The second cell is a bitmap specifying to which channels the DMA request
|
||||
line may be mapped (i.e. bit N set indicates channel N is usable).
|
||||
- The third cell is the thread ID to be used by the channel.
|
||||
|
||||
Optional properties:
|
||||
- dma-channels: Number of supported DMA channels, up to 32. If not specified
|
||||
the number reported by the hardware is used.
|
||||
|
||||
Example:
|
||||
|
||||
mdc: dma-controller@18143000 {
|
||||
compatible = "img,pistachio-mdc-dma";
|
||||
reg = <0x18143000 0x1000>;
|
||||
interrupts = <GIC_SHARED 27 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 28 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 29 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 30 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 31 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 32 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 33 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 34 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 35 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 36 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 37 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SHARED 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&system_clk>;
|
||||
clock-names = "sys";
|
||||
|
||||
img,max-burst-multiplier = <16>;
|
||||
img,cr-periph = <&cr_periph>;
|
||||
|
||||
#dma-cells = <3>;
|
||||
};
|
||||
|
||||
spi@18100f00 {
|
||||
...
|
||||
dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>;
|
||||
dma-names = "tx", "rx";
|
||||
...
|
||||
};
|
||||
@@ -5,9 +5,6 @@ controller instances named DMAC capable of serving multiple clients. Channels
|
||||
can be dedicated to specific clients or shared between a large number of
|
||||
clients.
|
||||
|
||||
DMA clients are connected to the DMAC ports referenced by an 8-bit identifier
|
||||
called MID/RID.
|
||||
|
||||
Each DMA client is connected to one dedicated port of the DMAC, identified by
|
||||
an 8-bit port number called the MID/RID. A DMA controller can thus serve up to
|
||||
256 clients in total. When the number of hardware channels is lower than the
|
||||
|
||||
@@ -38,7 +38,7 @@ Example:
|
||||
chan_allocation_order = <1>;
|
||||
chan_priority = <1>;
|
||||
block_size = <0xfff>;
|
||||
data_width = <3 3 0 0>;
|
||||
data_width = <3 3>;
|
||||
};
|
||||
|
||||
DMA clients connected to the Designware DMA controller must use the format
|
||||
|
||||
@@ -113,6 +113,31 @@ need to initialize a few fields in there:
|
||||
* channels: should be initialized as a list using the
|
||||
INIT_LIST_HEAD macro for example
|
||||
|
||||
* src_addr_widths:
|
||||
- should contain a bitmask of the supported source transfer width
|
||||
|
||||
* dst_addr_widths:
|
||||
- should contain a bitmask of the supported destination transfer
|
||||
width
|
||||
|
||||
* directions:
|
||||
- should contain a bitmask of the supported slave directions
|
||||
(i.e. excluding mem2mem transfers)
|
||||
|
||||
* residue_granularity:
|
||||
- Granularity of the transfer residue reported to dma_set_residue.
|
||||
- This can be either:
|
||||
+ Descriptor
|
||||
-> Your device doesn't support any kind of residue
|
||||
reporting. The framework will only know that a particular
|
||||
transaction descriptor is done.
|
||||
+ Segment
|
||||
-> Your device is able to report which chunks have been
|
||||
transferred
|
||||
+ Burst
|
||||
-> Your device is able to report which burst have been
|
||||
transferred
|
||||
|
||||
* dev: should hold the pointer to the struct device associated
|
||||
to your current driver instance.
|
||||
|
||||
@@ -274,48 +299,36 @@ supported.
|
||||
account the current period.
|
||||
- This function can be called in an interrupt context.
|
||||
|
||||
* device_control
|
||||
- Used by client drivers to control and configure the channel it
|
||||
has a handle on.
|
||||
- Called with a command and an argument
|
||||
+ The command is one of the values listed by the enum
|
||||
dma_ctrl_cmd. The valid commands are:
|
||||
+ DMA_PAUSE
|
||||
+ Pauses a transfer on the channel
|
||||
+ This command should operate synchronously on the channel,
|
||||
pausing right away the work of the given channel
|
||||
+ DMA_RESUME
|
||||
+ Restarts a transfer on the channel
|
||||
+ This command should operate synchronously on the channel,
|
||||
resuming right away the work of the given channel
|
||||
+ DMA_TERMINATE_ALL
|
||||
+ Aborts all the pending and ongoing transfers on the
|
||||
channel
|
||||
+ This command should operate synchronously on the channel,
|
||||
terminating right away all the channels
|
||||
+ DMA_SLAVE_CONFIG
|
||||
+ Reconfigures the channel with passed configuration
|
||||
+ This command should NOT perform synchronously, or on any
|
||||
currently queued transfers, but only on subsequent ones
|
||||
+ In this case, the function will receive a
|
||||
dma_slave_config structure pointer as an argument, that
|
||||
will detail which configuration to use.
|
||||
+ Even though that structure contains a direction field,
|
||||
this field is deprecated in favor of the direction
|
||||
argument given to the prep_* functions
|
||||
+ FSLDMA_EXTERNAL_START
|
||||
+ TODO: Why does that even exist?
|
||||
+ The argument is an opaque unsigned long. This actually is a
|
||||
pointer to a struct dma_slave_config that should be used only
|
||||
in the DMA_SLAVE_CONFIG.
|
||||
* device_config
|
||||
- Reconfigures the channel with the configuration given as
|
||||
argument
|
||||
- This command should NOT perform synchronously, or on any
|
||||
currently queued transfers, but only on subsequent ones
|
||||
- In this case, the function will receive a dma_slave_config
|
||||
structure pointer as an argument, that will detail which
|
||||
configuration to use.
|
||||
- Even though that structure contains a direction field, this
|
||||
field is deprecated in favor of the direction argument given to
|
||||
the prep_* functions
|
||||
- This call is mandatory for slave operations only. This should NOT be
|
||||
set or expected to be set for memcpy operations.
|
||||
If a driver support both, it should use this call for slave
|
||||
operations only and not for memcpy ones.
|
||||
|
||||
* device_slave_caps
|
||||
- Called through the framework by client drivers in order to have
|
||||
an idea of what are the properties of the channel allocated to
|
||||
them.
|
||||
- Such properties are the buswidth, available directions, etc.
|
||||
- Required for every generic layer doing DMA transfers, such as
|
||||
ASoC.
|
||||
* device_pause
|
||||
- Pauses a transfer on the channel
|
||||
- This command should operate synchronously on the channel,
|
||||
pausing right away the work of the given channel
|
||||
|
||||
* device_resume
|
||||
- Resumes a transfer on the channel
|
||||
- This command should operate synchronously on the channel,
|
||||
pausing right away the work of the given channel
|
||||
|
||||
* device_terminate_all
|
||||
- Aborts all the pending and ongoing transfers on the channel
|
||||
- This command should operate synchronously on the channel,
|
||||
terminating right away all the channels
|
||||
|
||||
Misc notes (stuff that should be documented, but don't really know
|
||||
where to put them)
|
||||
|
||||
@@ -8503,6 +8503,7 @@ SYNOPSYS DESIGNWARE DMAC DRIVER
|
||||
M: Viresh Kumar <viresh.linux@gmail.com>
|
||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
S: Maintained
|
||||
F: include/linux/dma/dw.h
|
||||
F: include/linux/platform_data/dma-dw.h
|
||||
F: drivers/dma/dw/
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
chan_allocation_order = <0>;
|
||||
chan_priority = <1>;
|
||||
block_size = <0x7ff>;
|
||||
data_width = <2 0 0 0>;
|
||||
data_width = <2>;
|
||||
clocks = <&ahb_clk>;
|
||||
clock-names = "hclk";
|
||||
};
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
chan_priority = <1>;
|
||||
block_size = <0xfff>;
|
||||
dma-masters = <2>;
|
||||
data_width = <3 3 0 0>;
|
||||
data_width = <3 3>;
|
||||
};
|
||||
|
||||
dma@eb000000 {
|
||||
@@ -133,7 +133,7 @@
|
||||
chan_allocation_order = <1>;
|
||||
chan_priority = <1>;
|
||||
block_size = <0xfff>;
|
||||
data_width = <3 3 0 0>;
|
||||
data_width = <3 3>;
|
||||
};
|
||||
|
||||
fsmc: flash@b0000000 {
|
||||
|
||||
@@ -607,7 +607,7 @@ static struct dw_dma_platform_data dw_dmac0_data = {
|
||||
.nr_channels = 3,
|
||||
.block_size = 4095U,
|
||||
.nr_masters = 2,
|
||||
.data_width = { 2, 2, 0, 0 },
|
||||
.data_width = { 2, 2 },
|
||||
};
|
||||
|
||||
static struct resource dw_dmac0_resource[] = {
|
||||
|
||||
@@ -606,12 +606,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx)
|
||||
dev_dbg(ctx->device->dev, "[%s]: ", __func__);
|
||||
|
||||
chan = ctx->device->dma.chan_mem2cryp;
|
||||
dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
|
||||
dmaengine_terminate_all(chan);
|
||||
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
|
||||
ctx->device->dma.sg_src_len, DMA_TO_DEVICE);
|
||||
|
||||
chan = ctx->device->dma.chan_cryp2mem;
|
||||
dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
|
||||
dmaengine_terminate_all(chan);
|
||||
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
|
||||
ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ static void hash_dma_done(struct hash_ctx *ctx)
|
||||
struct dma_chan *chan;
|
||||
|
||||
chan = ctx->device->dma.chan_mem2hash;
|
||||
dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
|
||||
dmaengine_terminate_all(chan);
|
||||
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
|
||||
ctx->device->dma.sg_len, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
@@ -416,6 +416,15 @@ config NBPFAXI_DMA
|
||||
help
|
||||
Support for "Type-AXI" NBPF DMA IPs from Renesas
|
||||
|
||||
config IMG_MDC_DMA
|
||||
tristate "IMG MDC support"
|
||||
depends on MIPS || COMPILE_TEST
|
||||
depends on MFD_SYSCON
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
help
|
||||
Enable support for the IMG multi-threaded DMA controller (MDC).
|
||||
|
||||
config DMA_ENGINE
|
||||
bool
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
|
||||
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
|
||||
obj-$(CONFIG_MX3_IPU) += ipu/
|
||||
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
|
||||
obj-$(CONFIG_SH_DMAE_BASE) += sh/
|
||||
obj-$(CONFIG_RENESAS_DMA) += sh/
|
||||
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
|
||||
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
|
||||
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
|
||||
@@ -50,3 +50,4 @@ obj-y += xilinx/
|
||||
obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
|
||||
obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
|
||||
obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
|
||||
obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
|
||||
|
||||
+92
-68
@@ -1386,32 +1386,6 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
|
||||
return pl08x_cctl(cctl);
|
||||
}
|
||||
|
||||
static int dma_set_runtime_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
||||
struct pl08x_driver_data *pl08x = plchan->host;
|
||||
|
||||
if (!plchan->slave)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reject definitely invalid configurations */
|
||||
if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
|
||||
config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
|
||||
return -EINVAL;
|
||||
|
||||
if (config->device_fc && pl08x->vd->pl080s) {
|
||||
dev_err(&pl08x->adev->dev,
|
||||
"%s: PL080S does not support peripheral flow control\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plchan->cfg = *config;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Slave transactions callback to the slave device to allow
|
||||
* synchronization of slave DMA signals with the DMAC enable
|
||||
@@ -1693,20 +1667,71 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
|
||||
return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
|
||||
}
|
||||
|
||||
static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
static int pl08x_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
||||
struct pl08x_driver_data *pl08x = plchan->host;
|
||||
|
||||
if (!plchan->slave)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reject definitely invalid configurations */
|
||||
if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
|
||||
config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
|
||||
return -EINVAL;
|
||||
|
||||
if (config->device_fc && pl08x->vd->pl080s) {
|
||||
dev_err(&pl08x->adev->dev,
|
||||
"%s: PL080S does not support peripheral flow control\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plchan->cfg = *config;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl08x_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
||||
struct pl08x_driver_data *pl08x = plchan->host;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
/* Controls applicable to inactive channels */
|
||||
if (cmd == DMA_SLAVE_CONFIG) {
|
||||
return dma_set_runtime_config(chan,
|
||||
(struct dma_slave_config *)arg);
|
||||
spin_lock_irqsave(&plchan->vc.lock, flags);
|
||||
if (!plchan->phychan && !plchan->at) {
|
||||
spin_unlock_irqrestore(&plchan->vc.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
plchan->state = PL08X_CHAN_IDLE;
|
||||
|
||||
if (plchan->phychan) {
|
||||
/*
|
||||
* Mark physical channel as free and free any slave
|
||||
* signal
|
||||
*/
|
||||
pl08x_phy_free(plchan);
|
||||
}
|
||||
/* Dequeue jobs and free LLIs */
|
||||
if (plchan->at) {
|
||||
pl08x_desc_free(&plchan->at->vd);
|
||||
plchan->at = NULL;
|
||||
}
|
||||
/* Dequeue jobs not yet fired as well */
|
||||
pl08x_free_txd_list(pl08x, plchan);
|
||||
|
||||
spin_unlock_irqrestore(&plchan->vc.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl08x_pause(struct dma_chan *chan)
|
||||
{
|
||||
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Anything succeeds on channels with no physical allocation and
|
||||
* no queued transfers.
|
||||
@@ -1717,42 +1742,35 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_TERMINATE_ALL:
|
||||
plchan->state = PL08X_CHAN_IDLE;
|
||||
|
||||
if (plchan->phychan) {
|
||||
/*
|
||||
* Mark physical channel as free and free any slave
|
||||
* signal
|
||||
*/
|
||||
pl08x_phy_free(plchan);
|
||||
}
|
||||
/* Dequeue jobs and free LLIs */
|
||||
if (plchan->at) {
|
||||
pl08x_desc_free(&plchan->at->vd);
|
||||
plchan->at = NULL;
|
||||
}
|
||||
/* Dequeue jobs not yet fired as well */
|
||||
pl08x_free_txd_list(pl08x, plchan);
|
||||
break;
|
||||
case DMA_PAUSE:
|
||||
pl08x_pause_phy_chan(plchan->phychan);
|
||||
plchan->state = PL08X_CHAN_PAUSED;
|
||||
break;
|
||||
case DMA_RESUME:
|
||||
pl08x_resume_phy_chan(plchan->phychan);
|
||||
plchan->state = PL08X_CHAN_RUNNING;
|
||||
break;
|
||||
default:
|
||||
/* Unknown command */
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
pl08x_pause_phy_chan(plchan->phychan);
|
||||
plchan->state = PL08X_CHAN_PAUSED;
|
||||
|
||||
spin_unlock_irqrestore(&plchan->vc.lock, flags);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl08x_resume(struct dma_chan *chan)
|
||||
{
|
||||
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Anything succeeds on channels with no physical allocation and
|
||||
* no queued transfers.
|
||||
*/
|
||||
spin_lock_irqsave(&plchan->vc.lock, flags);
|
||||
if (!plchan->phychan && !plchan->at) {
|
||||
spin_unlock_irqrestore(&plchan->vc.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pl08x_resume_phy_chan(plchan->phychan);
|
||||
plchan->state = PL08X_CHAN_RUNNING;
|
||||
|
||||
spin_unlock_irqrestore(&plchan->vc.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
|
||||
@@ -2048,7 +2066,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
|
||||
pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
|
||||
pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
|
||||
pl08x->memcpy.device_control = pl08x_control;
|
||||
pl08x->memcpy.device_config = pl08x_config;
|
||||
pl08x->memcpy.device_pause = pl08x_pause;
|
||||
pl08x->memcpy.device_resume = pl08x_resume;
|
||||
pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
|
||||
|
||||
/* Initialize slave engine */
|
||||
dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
|
||||
@@ -2061,7 +2082,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
pl08x->slave.device_issue_pending = pl08x_issue_pending;
|
||||
pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
|
||||
pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
|
||||
pl08x->slave.device_control = pl08x_control;
|
||||
pl08x->slave.device_config = pl08x_config;
|
||||
pl08x->slave.device_pause = pl08x_pause;
|
||||
pl08x->slave.device_resume = pl08x_resume;
|
||||
pl08x->slave.device_terminate_all = pl08x_terminate_all;
|
||||
|
||||
/* Get the platform data */
|
||||
pl08x->pd = dev_get_platdata(&adev->dev);
|
||||
|
||||
+83
-49
@@ -42,6 +42,11 @@
|
||||
#define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
|
||||
#define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \
|
||||
|ATC_DIF(AT_DMA_MEM_IF))
|
||||
#define ATC_DMA_BUSWIDTHS\
|
||||
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
|
||||
|
||||
/*
|
||||
* Initial number of descriptors to allocate for each channel. This could
|
||||
@@ -972,11 +977,13 @@ err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int set_runtime_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *sconfig)
|
||||
static int atc_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *sconfig)
|
||||
{
|
||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
/* Check if it is chan is configured for slave transfers */
|
||||
if (!chan->private)
|
||||
return -EINVAL;
|
||||
@@ -989,9 +996,7 @@ static int set_runtime_config(struct dma_chan *chan,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
static int atc_pause(struct dma_chan *chan)
|
||||
{
|
||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
struct at_dma *atdma = to_at_dma(chan->device);
|
||||
@@ -1000,60 +1005,82 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
if (cmd == DMA_PAUSE) {
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
|
||||
dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
|
||||
set_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
|
||||
set_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
} else if (cmd == DMA_RESUME) {
|
||||
if (!atc_chan_is_paused(atchan))
|
||||
return 0;
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
|
||||
clear_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
static int atc_resume(struct dma_chan *chan)
|
||||
{
|
||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
struct at_dma *atdma = to_at_dma(chan->device);
|
||||
int chan_id = atchan->chan_common.chan_id;
|
||||
unsigned long flags;
|
||||
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
} else if (cmd == DMA_TERMINATE_ALL) {
|
||||
struct at_desc *desc, *_desc;
|
||||
/*
|
||||
* This is only called when something went wrong elsewhere, so
|
||||
* we don't really care about the data. Just disable the
|
||||
* channel. We still have to poll the channel enable bit due
|
||||
* to AHB/HSB limitations.
|
||||
*/
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
LIST_HEAD(list);
|
||||
|
||||
/* disabling channel: must also remove suspend state */
|
||||
dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
/* confirm that this channel is disabled */
|
||||
while (dma_readl(atdma, CHSR) & atchan->mask)
|
||||
cpu_relax();
|
||||
if (!atc_chan_is_paused(atchan))
|
||||
return 0;
|
||||
|
||||
/* active_list entries will end up before queued entries */
|
||||
list_splice_init(&atchan->queue, &list);
|
||||
list_splice_init(&atchan->active_list, &list);
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
|
||||
/* Flush all pending and queued descriptors */
|
||||
list_for_each_entry_safe(desc, _desc, &list, desc_node)
|
||||
atc_chain_complete(atchan, desc);
|
||||
dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
|
||||
clear_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
|
||||
clear_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
/* if channel dedicated to cyclic operations, free it */
|
||||
clear_bit(ATC_IS_CYCLIC, &atchan->status);
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
} else if (cmd == DMA_SLAVE_CONFIG) {
|
||||
return set_runtime_config(chan, (struct dma_slave_config *)arg);
|
||||
} else {
|
||||
return -ENXIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atc_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||
struct at_dma *atdma = to_at_dma(chan->device);
|
||||
int chan_id = atchan->chan_common.chan_id;
|
||||
struct at_desc *desc, *_desc;
|
||||
unsigned long flags;
|
||||
|
||||
LIST_HEAD(list);
|
||||
|
||||
dev_vdbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
/*
|
||||
* This is only called when something went wrong elsewhere, so
|
||||
* we don't really care about the data. Just disable the
|
||||
* channel. We still have to poll the channel enable bit due
|
||||
* to AHB/HSB limitations.
|
||||
*/
|
||||
spin_lock_irqsave(&atchan->lock, flags);
|
||||
|
||||
/* disabling channel: must also remove suspend state */
|
||||
dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
|
||||
|
||||
/* confirm that this channel is disabled */
|
||||
while (dma_readl(atdma, CHSR) & atchan->mask)
|
||||
cpu_relax();
|
||||
|
||||
/* active_list entries will end up before queued entries */
|
||||
list_splice_init(&atchan->queue, &list);
|
||||
list_splice_init(&atchan->active_list, &list);
|
||||
|
||||
/* Flush all pending and queued descriptors */
|
||||
list_for_each_entry_safe(desc, _desc, &list, desc_node)
|
||||
atc_chain_complete(atchan, desc);
|
||||
|
||||
clear_bit(ATC_IS_PAUSED, &atchan->status);
|
||||
/* if channel dedicated to cyclic operations, free it */
|
||||
clear_bit(ATC_IS_CYCLIC, &atchan->status);
|
||||
|
||||
spin_unlock_irqrestore(&atchan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1505,7 +1532,14 @@ static int __init at_dma_probe(struct platform_device *pdev)
|
||||
/* controller can do slave DMA: can trigger cyclic transfers */
|
||||
dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask);
|
||||
atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
|
||||
atdma->dma_common.device_control = atc_control;
|
||||
atdma->dma_common.device_config = atc_config;
|
||||
atdma->dma_common.device_pause = atc_pause;
|
||||
atdma->dma_common.device_resume = atc_resume;
|
||||
atdma->dma_common.device_terminate_all = atc_terminate_all;
|
||||
atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS;
|
||||
atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS;
|
||||
atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
|
||||
}
|
||||
|
||||
dma_writel(atdma, EN, AT_DMA_ENABLE);
|
||||
@@ -1622,7 +1656,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan)
|
||||
if (!atc_chan_is_paused(atchan)) {
|
||||
dev_warn(chan2dev(chan),
|
||||
"cyclic channel not paused, should be done by channel user\n");
|
||||
atc_control(chan, DMA_PAUSE, 0);
|
||||
atc_pause(chan);
|
||||
}
|
||||
|
||||
/* now preserve additional data for cyclic operations */
|
||||
|
||||
@@ -232,7 +232,8 @@ enum atc_status {
|
||||
* @save_dscr: for cyclic operations, preserve next descriptor address in
|
||||
* the cyclic list on suspend/resume cycle
|
||||
* @remain_desc: to save remain desc length
|
||||
* @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
|
||||
* @dma_sconfig: configuration for slave transfers, passed via
|
||||
* .device_config
|
||||
* @lock: serializes enqueue/dequeue operations to descriptors lists
|
||||
* @active_list: list of descriptors dmaengine is being running on
|
||||
* @queue: list of descriptors ready to be submitted to engine
|
||||
|
||||
+104
-94
@@ -25,6 +25,7 @@
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_dma.h>
|
||||
@@ -174,6 +175,13 @@
|
||||
|
||||
#define AT_XDMAC_MAX_CHAN 0x20
|
||||
|
||||
#define AT_XDMAC_DMA_BUSWIDTHS\
|
||||
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
|
||||
|
||||
enum atc_status {
|
||||
AT_XDMAC_CHAN_IS_CYCLIC = 0,
|
||||
AT_XDMAC_CHAN_IS_PAUSED,
|
||||
@@ -184,15 +192,15 @@ struct at_xdmac_chan {
|
||||
struct dma_chan chan;
|
||||
void __iomem *ch_regs;
|
||||
u32 mask; /* Channel Mask */
|
||||
u32 cfg[3]; /* Channel Configuration Register */
|
||||
#define AT_XDMAC_CUR_CFG 0 /* Current channel conf */
|
||||
#define AT_XDMAC_DEV_TO_MEM_CFG 1 /* Predifined dev to mem channel conf */
|
||||
#define AT_XDMAC_MEM_TO_DEV_CFG 2 /* Predifined mem to dev channel conf */
|
||||
u32 cfg[2]; /* Channel Configuration Register */
|
||||
#define AT_XDMAC_DEV_TO_MEM_CFG 0 /* Predifined dev to mem channel conf */
|
||||
#define AT_XDMAC_MEM_TO_DEV_CFG 1 /* Predifined mem to dev channel conf */
|
||||
u8 perid; /* Peripheral ID */
|
||||
u8 perif; /* Peripheral Interface */
|
||||
u8 memif; /* Memory Interface */
|
||||
u32 per_src_addr;
|
||||
u32 per_dst_addr;
|
||||
u32 save_cc;
|
||||
u32 save_cim;
|
||||
u32 save_cnda;
|
||||
u32 save_cndc;
|
||||
@@ -344,20 +352,13 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
|
||||
|
||||
/*
|
||||
* When doing memory to memory transfer we need to use the next
|
||||
* When doing non cyclic transfer we need to use the next
|
||||
* descriptor view 2 since some fields of the configuration register
|
||||
* depend on transfer size and src/dest addresses.
|
||||
*/
|
||||
if (is_slave_direction(first->direction)) {
|
||||
if (at_xdmac_chan_is_cyclic(atchan)) {
|
||||
reg = AT_XDMAC_CNDC_NDVIEW_NDV1;
|
||||
if (first->direction == DMA_MEM_TO_DEV)
|
||||
atchan->cfg[AT_XDMAC_CUR_CFG] =
|
||||
atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
|
||||
else
|
||||
atchan->cfg[AT_XDMAC_CUR_CFG] =
|
||||
atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CC,
|
||||
atchan->cfg[AT_XDMAC_CUR_CFG]);
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
|
||||
} else {
|
||||
/*
|
||||
* No need to write AT_XDMAC_CC reg, it will be done when the
|
||||
@@ -561,7 +562,6 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
struct at_xdmac_desc *first = NULL, *prev = NULL;
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
u32 cfg;
|
||||
unsigned int xfer_size = 0;
|
||||
|
||||
if (!sgl)
|
||||
@@ -583,7 +583,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
/* Prepare descriptors. */
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
struct at_xdmac_desc *desc = NULL;
|
||||
u32 len, mem;
|
||||
u32 len, mem, dwidth, fixed_dwidth;
|
||||
|
||||
len = sg_dma_len(sg);
|
||||
mem = sg_dma_address(sg);
|
||||
@@ -608,17 +608,21 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
||||
if (direction == DMA_DEV_TO_MEM) {
|
||||
desc->lld.mbr_sa = atchan->per_src_addr;
|
||||
desc->lld.mbr_da = mem;
|
||||
cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
|
||||
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
|
||||
} else {
|
||||
desc->lld.mbr_sa = mem;
|
||||
desc->lld.mbr_da = atchan->per_dst_addr;
|
||||
cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
|
||||
desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
|
||||
}
|
||||
desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 /* next descriptor view */
|
||||
| AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */
|
||||
| AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */
|
||||
| (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */
|
||||
| len / (1 << at_xdmac_get_dwidth(cfg)); /* microblock length */
|
||||
dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
|
||||
fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
|
||||
? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
|
||||
: AT_XDMAC_CC_DWIDTH_BYTE;
|
||||
desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 /* next descriptor view */
|
||||
| AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */
|
||||
| AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */
|
||||
| (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */
|
||||
| (len >> fixed_dwidth); /* microblock length */
|
||||
dev_dbg(chan2dev(chan),
|
||||
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
|
||||
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
|
||||
@@ -882,7 +886,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
||||
enum dma_status ret;
|
||||
int residue;
|
||||
u32 cur_nda, mask, value;
|
||||
u8 dwidth = at_xdmac_get_dwidth(atchan->cfg[AT_XDMAC_CUR_CFG]);
|
||||
u8 dwidth = 0;
|
||||
|
||||
ret = dma_cookie_status(chan, cookie, txstate);
|
||||
if (ret == DMA_COMPLETE)
|
||||
@@ -912,7 +916,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
||||
*/
|
||||
mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
|
||||
value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
|
||||
if ((atchan->cfg[AT_XDMAC_CUR_CFG] & mask) == value) {
|
||||
if ((desc->lld.mbr_cfg & mask) == value) {
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
|
||||
while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
|
||||
cpu_relax();
|
||||
@@ -926,6 +930,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
||||
*/
|
||||
descs_list = &desc->descs_list;
|
||||
list_for_each_entry_safe(desc, _desc, descs_list, desc_node) {
|
||||
dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
|
||||
residue -= (desc->lld.mbr_ubc & 0xffffff) << dwidth;
|
||||
if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
|
||||
break;
|
||||
@@ -1107,58 +1112,80 @@ static void at_xdmac_issue_pending(struct dma_chan *chan)
|
||||
return;
|
||||
}
|
||||
|
||||
static int at_xdmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
static int at_xdmac_device_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
int ret;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_bh(&atchan->lock);
|
||||
ret = at_xdmac_set_slave_config(chan, config);
|
||||
spin_unlock_bh(&atchan->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int at_xdmac_device_pause(struct dma_chan *chan)
|
||||
{
|
||||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
if (test_and_set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status))
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&atchan->lock);
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
|
||||
while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
|
||||
& (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
|
||||
cpu_relax();
|
||||
spin_unlock_bh(&atchan->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_xdmac_device_resume(struct dma_chan *chan)
|
||||
{
|
||||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_bh(&atchan->lock);
|
||||
if (!at_xdmac_chan_is_paused(atchan))
|
||||
return 0;
|
||||
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
|
||||
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
|
||||
spin_unlock_bh(&atchan->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_xdmac_device_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct at_xdmac_desc *desc, *_desc;
|
||||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(chan2dev(chan), "%s: cmd=%d\n", __func__, cmd);
|
||||
dev_dbg(chan2dev(chan), "%s\n", __func__);
|
||||
|
||||
spin_lock_bh(&atchan->lock);
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
|
||||
while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
|
||||
cpu_relax();
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_PAUSE:
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
|
||||
set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
|
||||
break;
|
||||
|
||||
case DMA_RESUME:
|
||||
if (!at_xdmac_chan_is_paused(atchan))
|
||||
break;
|
||||
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
|
||||
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
|
||||
break;
|
||||
|
||||
case DMA_TERMINATE_ALL:
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
|
||||
while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
|
||||
cpu_relax();
|
||||
|
||||
/* Cancel all pending transfers. */
|
||||
list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
|
||||
at_xdmac_remove_xfer(atchan, desc);
|
||||
|
||||
clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
|
||||
break;
|
||||
|
||||
case DMA_SLAVE_CONFIG:
|
||||
ret = at_xdmac_set_slave_config(chan,
|
||||
(struct dma_slave_config *)arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(chan2dev(chan),
|
||||
"unmanaged or unknown dma control cmd: %d\n", cmd);
|
||||
ret = -ENXIO;
|
||||
}
|
||||
/* Cancel all pending transfers. */
|
||||
list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
|
||||
at_xdmac_remove_xfer(atchan, desc);
|
||||
|
||||
clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
|
||||
spin_unlock_bh(&atchan->lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
|
||||
@@ -1217,27 +1244,6 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan)
|
||||
return;
|
||||
}
|
||||
|
||||
#define AT_XDMAC_DMA_BUSWIDTHS\
|
||||
(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |\
|
||||
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
|
||||
|
||||
static int at_xdmac_device_slave_caps(struct dma_chan *dchan,
|
||||
struct dma_slave_caps *caps)
|
||||
{
|
||||
|
||||
caps->src_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
|
||||
caps->dstn_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
|
||||
caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
caps->cmd_pause = true;
|
||||
caps->cmd_terminate = true;
|
||||
caps->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int atmel_xdmac_prepare(struct device *dev)
|
||||
{
|
||||
@@ -1268,9 +1274,10 @@ static int atmel_xdmac_suspend(struct device *dev)
|
||||
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
|
||||
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
|
||||
|
||||
atchan->save_cc = at_xdmac_chan_read(atchan, AT_XDMAC_CC);
|
||||
if (at_xdmac_chan_is_cyclic(atchan)) {
|
||||
if (!at_xdmac_chan_is_paused(atchan))
|
||||
at_xdmac_control(chan, DMA_PAUSE, 0);
|
||||
at_xdmac_device_pause(chan);
|
||||
atchan->save_cim = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
|
||||
atchan->save_cnda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA);
|
||||
atchan->save_cndc = at_xdmac_chan_read(atchan, AT_XDMAC_CNDC);
|
||||
@@ -1290,7 +1297,6 @@ static int atmel_xdmac_resume(struct device *dev)
|
||||
struct at_xdmac_chan *atchan;
|
||||
struct dma_chan *chan, *_chan;
|
||||
int i;
|
||||
u32 cfg;
|
||||
|
||||
clk_prepare_enable(atxdmac->clk);
|
||||
|
||||
@@ -1305,8 +1311,7 @@ static int atmel_xdmac_resume(struct device *dev)
|
||||
at_xdmac_write(atxdmac, AT_XDMAC_GE, atxdmac->save_gs);
|
||||
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
|
||||
atchan = to_at_xdmac_chan(chan);
|
||||
cfg = atchan->cfg[AT_XDMAC_CUR_CFG];
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CC, cfg);
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
|
||||
if (at_xdmac_chan_is_cyclic(atchan)) {
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda);
|
||||
at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
|
||||
@@ -1407,8 +1412,14 @@ static int at_xdmac_probe(struct platform_device *pdev)
|
||||
atxdmac->dma.device_prep_dma_cyclic = at_xdmac_prep_dma_cyclic;
|
||||
atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy;
|
||||
atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg;
|
||||
atxdmac->dma.device_control = at_xdmac_control;
|
||||
atxdmac->dma.device_slave_caps = at_xdmac_device_slave_caps;
|
||||
atxdmac->dma.device_config = at_xdmac_device_config;
|
||||
atxdmac->dma.device_pause = at_xdmac_device_pause;
|
||||
atxdmac->dma.device_resume = at_xdmac_device_resume;
|
||||
atxdmac->dma.device_terminate_all = at_xdmac_device_terminate_all;
|
||||
atxdmac->dma.src_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
|
||||
atxdmac->dma.dst_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
|
||||
atxdmac->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
atxdmac->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
|
||||
|
||||
/* Disable all chans and interrupts. */
|
||||
at_xdmac_off(atxdmac);
|
||||
@@ -1507,7 +1518,6 @@ static struct platform_driver at_xdmac_driver = {
|
||||
.remove = at_xdmac_remove,
|
||||
.driver = {
|
||||
.name = "at_xdmac",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(atmel_xdmac_dt_ids),
|
||||
.pm = &atmel_xdmac_dev_pm_ops,
|
||||
}
|
||||
|
||||
+11
-35
@@ -436,9 +436,11 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
|
||||
return vchan_tx_prep(&c->vc, &d->vd, flags);
|
||||
}
|
||||
|
||||
static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
|
||||
struct dma_slave_config *cfg)
|
||||
static int bcm2835_dma_slave_config(struct dma_chan *chan,
|
||||
struct dma_slave_config *cfg)
|
||||
{
|
||||
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
|
||||
|
||||
if ((cfg->direction == DMA_DEV_TO_MEM &&
|
||||
cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
|
||||
(cfg->direction == DMA_MEM_TO_DEV &&
|
||||
@@ -452,8 +454,9 @@ static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
|
||||
static int bcm2835_dma_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
|
||||
struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
|
||||
unsigned long flags;
|
||||
int timeout = 10000;
|
||||
@@ -495,24 +498,6 @@ static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_SLAVE_CONFIG:
|
||||
return bcm2835_dma_slave_config(c,
|
||||
(struct dma_slave_config *)arg);
|
||||
|
||||
case DMA_TERMINATE_ALL:
|
||||
return bcm2835_dma_terminate_all(c);
|
||||
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
|
||||
{
|
||||
struct bcm2835_chan *c;
|
||||
@@ -565,18 +550,6 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
|
||||
return chan;
|
||||
}
|
||||
|
||||
static int bcm2835_dma_device_slave_caps(struct dma_chan *dchan,
|
||||
struct dma_slave_caps *caps)
|
||||
{
|
||||
caps->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
caps->dstn_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
caps->cmd_pause = false;
|
||||
caps->cmd_terminate = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_dma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835_dmadev *od;
|
||||
@@ -615,9 +588,12 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
|
||||
od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
|
||||
od->ddev.device_tx_status = bcm2835_dma_tx_status;
|
||||
od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
|
||||
od->ddev.device_slave_caps = bcm2835_dma_device_slave_caps;
|
||||
od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
|
||||
od->ddev.device_control = bcm2835_dma_control;
|
||||
od->ddev.device_config = bcm2835_dma_slave_config;
|
||||
od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
|
||||
od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
od->ddev.dev = &pdev->dev;
|
||||
INIT_LIST_HEAD(&od->ddev.channels);
|
||||
spin_lock_init(&od->lock);
|
||||
|
||||
+70
-83
@@ -1690,7 +1690,7 @@ static u32 coh901318_get_bytes_left(struct dma_chan *chan)
|
||||
* Pauses a transfer without losing data. Enables power save.
|
||||
* Use this function in conjunction with coh901318_resume.
|
||||
*/
|
||||
static void coh901318_pause(struct dma_chan *chan)
|
||||
static int coh901318_pause(struct dma_chan *chan)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
@@ -1730,12 +1730,13 @@ static void coh901318_pause(struct dma_chan *chan)
|
||||
enable_powersave(cohc);
|
||||
|
||||
spin_unlock_irqrestore(&cohc->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resumes a transfer that has been stopped via 300_dma_stop(..).
|
||||
Power save is handled.
|
||||
*/
|
||||
static void coh901318_resume(struct dma_chan *chan)
|
||||
static int coh901318_resume(struct dma_chan *chan)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
@@ -1760,6 +1761,7 @@ static void coh901318_resume(struct dma_chan *chan)
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cohc->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
|
||||
@@ -2114,6 +2116,57 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int coh901318_terminate_all(struct dma_chan *chan)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct coh901318_chan *cohc = to_coh901318_chan(chan);
|
||||
struct coh901318_desc *cohd;
|
||||
void __iomem *virtbase = cohc->base->virtbase;
|
||||
|
||||
/* The remainder of this function terminates the transfer */
|
||||
coh901318_pause(chan);
|
||||
spin_lock_irqsave(&cohc->lock, flags);
|
||||
|
||||
/* Clear any pending BE or TC interrupt */
|
||||
if (cohc->id < 32) {
|
||||
writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1);
|
||||
writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1);
|
||||
} else {
|
||||
writel(1 << (cohc->id - 32), virtbase +
|
||||
COH901318_BE_INT_CLEAR2);
|
||||
writel(1 << (cohc->id - 32), virtbase +
|
||||
COH901318_TC_INT_CLEAR2);
|
||||
}
|
||||
|
||||
enable_powersave(cohc);
|
||||
|
||||
while ((cohd = coh901318_first_active_get(cohc))) {
|
||||
/* release the lli allocation*/
|
||||
coh901318_lli_free(&cohc->base->pool, &cohd->lli);
|
||||
|
||||
/* return desc to free-list */
|
||||
coh901318_desc_remove(cohd);
|
||||
coh901318_desc_free(cohc, cohd);
|
||||
}
|
||||
|
||||
while ((cohd = coh901318_first_queued(cohc))) {
|
||||
/* release the lli allocation*/
|
||||
coh901318_lli_free(&cohc->base->pool, &cohd->lli);
|
||||
|
||||
/* return desc to free-list */
|
||||
coh901318_desc_remove(cohd);
|
||||
coh901318_desc_free(cohc, cohd);
|
||||
}
|
||||
|
||||
|
||||
cohc->nbr_active_done = 0;
|
||||
cohc->busy = 0;
|
||||
|
||||
spin_unlock_irqrestore(&cohc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coh901318_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct coh901318_chan *cohc = to_coh901318_chan(chan);
|
||||
@@ -2156,7 +2209,7 @@ coh901318_free_chan_resources(struct dma_chan *chan)
|
||||
|
||||
spin_unlock_irqrestore(&cohc->lock, flags);
|
||||
|
||||
dmaengine_terminate_all(chan);
|
||||
coh901318_terminate_all(chan);
|
||||
}
|
||||
|
||||
|
||||
@@ -2461,8 +2514,8 @@ static const struct burst_table burst_sizes[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
|
||||
struct dma_slave_config *config)
|
||||
static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct coh901318_chan *cohc = to_coh901318_chan(chan);
|
||||
dma_addr_t addr;
|
||||
@@ -2482,7 +2535,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
|
||||
maxburst = config->dst_maxburst;
|
||||
} else {
|
||||
dev_err(COHC_2_DEV(cohc), "illegal channel mode\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n",
|
||||
@@ -2528,7 +2581,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
|
||||
default:
|
||||
dev_err(COHC_2_DEV(cohc),
|
||||
"bad runtimeconfig: alien address width\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl |= burst_sizes[i].reg;
|
||||
@@ -2538,84 +2591,12 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
|
||||
|
||||
cohc->addr = addr;
|
||||
cohc->ctrl = ctrl;
|
||||
}
|
||||
|
||||
static int
|
||||
coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct coh901318_chan *cohc = to_coh901318_chan(chan);
|
||||
struct coh901318_desc *cohd;
|
||||
void __iomem *virtbase = cohc->base->virtbase;
|
||||
|
||||
if (cmd == DMA_SLAVE_CONFIG) {
|
||||
struct dma_slave_config *config =
|
||||
(struct dma_slave_config *) arg;
|
||||
|
||||
coh901318_dma_set_runtimeconfig(chan, config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd == DMA_PAUSE) {
|
||||
coh901318_pause(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd == DMA_RESUME) {
|
||||
coh901318_resume(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd != DMA_TERMINATE_ALL)
|
||||
return -ENXIO;
|
||||
|
||||
/* The remainder of this function terminates the transfer */
|
||||
coh901318_pause(chan);
|
||||
spin_lock_irqsave(&cohc->lock, flags);
|
||||
|
||||
/* Clear any pending BE or TC interrupt */
|
||||
if (cohc->id < 32) {
|
||||
writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1);
|
||||
writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1);
|
||||
} else {
|
||||
writel(1 << (cohc->id - 32), virtbase +
|
||||
COH901318_BE_INT_CLEAR2);
|
||||
writel(1 << (cohc->id - 32), virtbase +
|
||||
COH901318_TC_INT_CLEAR2);
|
||||
}
|
||||
|
||||
enable_powersave(cohc);
|
||||
|
||||
while ((cohd = coh901318_first_active_get(cohc))) {
|
||||
/* release the lli allocation*/
|
||||
coh901318_lli_free(&cohc->base->pool, &cohd->lli);
|
||||
|
||||
/* return desc to free-list */
|
||||
coh901318_desc_remove(cohd);
|
||||
coh901318_desc_free(cohc, cohd);
|
||||
}
|
||||
|
||||
while ((cohd = coh901318_first_queued(cohc))) {
|
||||
/* release the lli allocation*/
|
||||
coh901318_lli_free(&cohc->base->pool, &cohd->lli);
|
||||
|
||||
/* return desc to free-list */
|
||||
coh901318_desc_remove(cohd);
|
||||
coh901318_desc_free(cohc, cohd);
|
||||
}
|
||||
|
||||
|
||||
cohc->nbr_active_done = 0;
|
||||
cohc->busy = 0;
|
||||
|
||||
spin_unlock_irqrestore(&cohc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
|
||||
struct coh901318_base *base)
|
||||
static void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
|
||||
struct coh901318_base *base)
|
||||
{
|
||||
int chans_i;
|
||||
int i = 0;
|
||||
@@ -2717,7 +2698,10 @@ static int __init coh901318_probe(struct platform_device *pdev)
|
||||
base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg;
|
||||
base->dma_slave.device_tx_status = coh901318_tx_status;
|
||||
base->dma_slave.device_issue_pending = coh901318_issue_pending;
|
||||
base->dma_slave.device_control = coh901318_control;
|
||||
base->dma_slave.device_config = coh901318_dma_set_runtimeconfig;
|
||||
base->dma_slave.device_pause = coh901318_pause;
|
||||
base->dma_slave.device_resume = coh901318_resume;
|
||||
base->dma_slave.device_terminate_all = coh901318_terminate_all;
|
||||
base->dma_slave.dev = &pdev->dev;
|
||||
|
||||
err = dma_async_device_register(&base->dma_slave);
|
||||
@@ -2737,7 +2721,10 @@ static int __init coh901318_probe(struct platform_device *pdev)
|
||||
base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy;
|
||||
base->dma_memcpy.device_tx_status = coh901318_tx_status;
|
||||
base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
|
||||
base->dma_memcpy.device_control = coh901318_control;
|
||||
base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig;
|
||||
base->dma_memcpy.device_pause = coh901318_pause;
|
||||
base->dma_memcpy.device_resume = coh901318_resume;
|
||||
base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
|
||||
base->dma_memcpy.dev = &pdev->dev;
|
||||
/*
|
||||
* This controller can only access address at even 32bit boundaries,
|
||||
|
||||
+1
-29
@@ -525,12 +525,6 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
|
||||
return &c->txd;
|
||||
}
|
||||
|
||||
static int cpp41_cfg_chan(struct cppi41_channel *c,
|
||||
struct dma_slave_config *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cppi41_compute_td_desc(struct cppi41_desc *d)
|
||||
{
|
||||
d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
|
||||
@@ -647,28 +641,6 @@ static int cppi41_stop_chan(struct dma_chan *chan)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct cppi41_channel *c = to_cpp41_chan(chan);
|
||||
int ret;
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_SLAVE_CONFIG:
|
||||
ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
|
||||
break;
|
||||
|
||||
case DMA_TERMINATE_ALL:
|
||||
ret = cppi41_stop_chan(chan);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cleanup_chans(struct cppi41_dd *cdd)
|
||||
{
|
||||
while (!list_empty(&cdd->ddev.channels)) {
|
||||
@@ -953,7 +925,7 @@ static int cppi41_dma_probe(struct platform_device *pdev)
|
||||
cdd->ddev.device_tx_status = cppi41_dma_tx_status;
|
||||
cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
|
||||
cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
|
||||
cdd->ddev.device_control = cppi41_dma_control;
|
||||
cdd->ddev.device_terminate_all = cppi41_stop_chan;
|
||||
cdd->ddev.dev = dev;
|
||||
INIT_LIST_HEAD(&cdd->ddev.channels);
|
||||
cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
|
||||
|
||||
@@ -210,7 +210,7 @@ static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst)
|
||||
}
|
||||
|
||||
static int jz4740_dma_slave_config(struct dma_chan *c,
|
||||
const struct dma_slave_config *config)
|
||||
struct dma_slave_config *config)
|
||||
{
|
||||
struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
|
||||
struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
|
||||
@@ -290,21 +290,6 @@ static int jz4740_dma_terminate_all(struct dma_chan *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4740_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct dma_slave_config *config = (struct dma_slave_config *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_SLAVE_CONFIG:
|
||||
return jz4740_dma_slave_config(chan, config);
|
||||
case DMA_TERMINATE_ALL:
|
||||
return jz4740_dma_terminate_all(chan);
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan)
|
||||
{
|
||||
struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
|
||||
@@ -561,7 +546,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
|
||||
dd->device_issue_pending = jz4740_dma_issue_pending;
|
||||
dd->device_prep_slave_sg = jz4740_dma_prep_slave_sg;
|
||||
dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
|
||||
dd->device_control = jz4740_dma_control;
|
||||
dd->device_config = jz4740_dma_slave_config;
|
||||
dd->device_terminate_all = jz4740_dma_terminate_all;
|
||||
dd->dev = &pdev->dev;
|
||||
INIT_LIST_HEAD(&dd->channels);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user