|
@@ -156,14 +156,10 @@ struct pl08x_driver_data {
|
|
|
#define PL08X_BOUNDARY_SHIFT (10) /* 1KB 0x400 */
|
|
|
#define PL08X_BOUNDARY_SIZE (1 << PL08X_BOUNDARY_SHIFT)
|
|
|
|
|
|
-/* Minimum period between work queue runs */
|
|
|
-#define PL08X_WQ_PERIODMIN 20
|
|
|
-
|
|
|
/* Size (bytes) of each LLI buffer allocated for one transfer */
|
|
|
# define PL08X_LLI_TSFR_SIZE 0x2000
|
|
|
|
|
|
/* Maximum times we call dma_pool_alloc on this pool without freeing */
|
|
|
-#define PL08X_MAX_ALLOCS 0x40
|
|
|
#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
|
|
|
#define PL08X_ALIGN 8
|
|
|
|
|
@@ -495,10 +491,10 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
|
|
|
|
|
|
struct pl08x_lli_build_data {
|
|
|
struct pl08x_txd *txd;
|
|
|
- struct pl08x_driver_data *pl08x;
|
|
|
struct pl08x_bus_data srcbus;
|
|
|
struct pl08x_bus_data dstbus;
|
|
|
size_t remainder;
|
|
|
+ u32 lli_bus;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -551,8 +547,7 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
|
|
|
llis_va[num_llis].src = bd->srcbus.addr;
|
|
|
llis_va[num_llis].dst = bd->dstbus.addr;
|
|
|
llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli);
|
|
|
- if (bd->pl08x->lli_buses & PL08X_AHB2)
|
|
|
- llis_va[num_llis].lli |= PL080_LLI_LM_AHB2;
|
|
|
+ llis_va[num_llis].lli |= bd->lli_bus;
|
|
|
|
|
|
if (cctl & PL080_CONTROL_SRC_INCR)
|
|
|
bd->srcbus.addr += len;
|
|
@@ -605,9 +600,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
|
|
|
cctl = txd->cctl;
|
|
|
|
|
|
bd.txd = txd;
|
|
|
- bd.pl08x = pl08x;
|
|
|
bd.srcbus.addr = txd->src_addr;
|
|
|
bd.dstbus.addr = txd->dst_addr;
|
|
|
+ bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0;
|
|
|
|
|
|
/* Find maximum width of the source bus */
|
|
|
bd.srcbus.maxwidth =
|
|
@@ -622,25 +617,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
|
|
|
/* Set up the bus widths to the maximum */
|
|
|
bd.srcbus.buswidth = bd.srcbus.maxwidth;
|
|
|
bd.dstbus.buswidth = bd.dstbus.maxwidth;
|
|
|
- dev_vdbg(&pl08x->adev->dev,
|
|
|
- "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
|
|
|
- __func__, bd.srcbus.buswidth, bd.dstbus.buswidth);
|
|
|
-
|
|
|
|
|
|
/*
|
|
|
* Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
|
|
|
*/
|
|
|
max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) *
|
|
|
PL080_CONTROL_TRANSFER_SIZE_MASK;
|
|
|
- dev_vdbg(&pl08x->adev->dev,
|
|
|
- "%s max bytes per lli = %zu\n",
|
|
|
- __func__, max_bytes_per_lli);
|
|
|
|
|
|
/* We need to count this down to zero */
|
|
|
bd.remainder = txd->len;
|
|
|
- dev_vdbg(&pl08x->adev->dev,
|
|
|
- "%s remainder = %zu\n",
|
|
|
- __func__, bd.remainder);
|
|
|
|
|
|
/*
|
|
|
* Choose bus to align to
|
|
@@ -649,6 +634,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
|
|
|
*/
|
|
|
pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
|
|
|
|
|
|
+ dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu llimax=%zu\n",
|
|
|
+ bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "",
|
|
|
+ bd.srcbus.buswidth,
|
|
|
+ bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "",
|
|
|
+ bd.dstbus.buswidth,
|
|
|
+ bd.remainder, max_bytes_per_lli);
|
|
|
+ dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n",
|
|
|
+ mbus == &bd.srcbus ? "src" : "dst",
|
|
|
+ sbus == &bd.srcbus ? "src" : "dst");
|
|
|
+
|
|
|
if (txd->len < mbus->buswidth) {
|
|
|
/* Less than a bus width available - send as single bytes */
|
|
|
while (bd.remainder) {
|
|
@@ -840,15 +835,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
+ dev_vdbg(&pl08x->adev->dev,
|
|
|
+ "%-3s %-9s %-10s %-10s %-10s %s\n",
|
|
|
+ "lli", "", "csrc", "cdst", "clli", "cctl");
|
|
|
for (i = 0; i < num_llis; i++) {
|
|
|
dev_vdbg(&pl08x->adev->dev,
|
|
|
- "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n",
|
|
|
- i,
|
|
|
- &llis_va[i],
|
|
|
- llis_va[i].src,
|
|
|
- llis_va[i].dst,
|
|
|
- llis_va[i].cctl,
|
|
|
- llis_va[i].lli
|
|
|
+ "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
|
|
+ i, &llis_va[i], llis_va[i].src,
|
|
|
+ llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl
|
|
|
);
|
|
|
}
|
|
|
}
|
|
@@ -1054,64 +1048,105 @@ pl08x_dma_tx_status(struct dma_chan *chan,
|
|
|
|
|
|
/* PrimeCell DMA extension */
|
|
|
struct burst_table {
|
|
|
- int burstwords;
|
|
|
+ u32 burstwords;
|
|
|
u32 reg;
|
|
|
};
|
|
|
|
|
|
static const struct burst_table burst_sizes[] = {
|
|
|
{
|
|
|
.burstwords = 256,
|
|
|
- .reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_256,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 128,
|
|
|
- .reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_128,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 64,
|
|
|
- .reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_64,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 32,
|
|
|
- .reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_32,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 16,
|
|
|
- .reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_16,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 8,
|
|
|
- .reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_8,
|
|
|
},
|
|
|
{
|
|
|
.burstwords = 4,
|
|
|
- .reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .reg = PL080_BSIZE_4,
|
|
|
},
|
|
|
{
|
|
|
- .burstwords = 1,
|
|
|
- .reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT),
|
|
|
+ .burstwords = 0,
|
|
|
+ .reg = PL080_BSIZE_1,
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * Given the source and destination available bus masks, select which
|
|
|
+ * will be routed to each port. We try to have source and destination
|
|
|
+ * on separate ports, but always respect the allowable settings.
|
|
|
+ */
|
|
|
+static u32 pl08x_select_bus(u8 src, u8 dst)
|
|
|
+{
|
|
|
+ u32 cctl = 0;
|
|
|
+
|
|
|
+ if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
|
|
|
+ cctl |= PL080_CONTROL_DST_AHB2;
|
|
|
+ if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
|
|
|
+ cctl |= PL080_CONTROL_SRC_AHB2;
|
|
|
+
|
|
|
+ return cctl;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 pl08x_cctl(u32 cctl)
|
|
|
+{
|
|
|
+ cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
|
|
|
+ PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
|
|
|
+ PL080_CONTROL_PROT_MASK);
|
|
|
+
|
|
|
+ /* Access the cell in privileged mode, non-bufferable, non-cacheable */
|
|
|
+ return cctl | PL080_CONTROL_PROT_SYS;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 pl08x_width(enum dma_slave_buswidth width)
|
|
|
+{
|
|
|
+ switch (width) {
|
|
|
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
|
|
+ return PL080_WIDTH_8BIT;
|
|
|
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
|
|
+ return PL080_WIDTH_16BIT;
|
|
|
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
|
|
+ return PL080_WIDTH_32BIT;
|
|
|
+ default:
|
|
|
+ return ~0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static u32 pl08x_burst(u32 maxburst)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
|
|
|
+ if (burst_sizes[i].burstwords <= maxburst)
|
|
|
+ break;
|
|
|
+
|
|
|
+ return burst_sizes[i].reg;
|
|
|
+}
|
|
|
+
|
|
|
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;
|
|
|
- struct pl08x_channel_data *cd = plchan->cd;
|
|
|
enum dma_slave_buswidth addr_width;
|
|
|
- dma_addr_t addr;
|
|
|
- u32 maxburst;
|
|
|
+ u32 width, burst, maxburst;
|
|
|
u32 cctl = 0;
|
|
|
- int i;
|
|
|
|
|
|
if (!plchan->slave)
|
|
|
return -EINVAL;
|
|
@@ -1119,11 +1154,9 @@ static int dma_set_runtime_config(struct dma_chan *chan,
|
|
|
/* Transfer direction */
|
|
|
plchan->runtime_direction = config->direction;
|
|
|
if (config->direction == DMA_TO_DEVICE) {
|
|
|
- addr = config->dst_addr;
|
|
|
addr_width = config->dst_addr_width;
|
|
|
maxburst = config->dst_maxburst;
|
|
|
} else if (config->direction == DMA_FROM_DEVICE) {
|
|
|
- addr = config->src_addr;
|
|
|
addr_width = config->src_addr_width;
|
|
|
maxburst = config->src_maxburst;
|
|
|
} else {
|
|
@@ -1132,46 +1165,40 @@ static int dma_set_runtime_config(struct dma_chan *chan,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- switch (addr_width) {
|
|
|
- case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
|
|
- cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) |
|
|
|
- (PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT);
|
|
|
- break;
|
|
|
- case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
|
|
- cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) |
|
|
|
- (PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT);
|
|
|
- break;
|
|
|
- case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
|
|
- cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) |
|
|
|
- (PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT);
|
|
|
- break;
|
|
|
- default:
|
|
|
+ width = pl08x_width(addr_width);
|
|
|
+ if (width == ~0) {
|
|
|
dev_err(&pl08x->adev->dev,
|
|
|
"bad runtime_config: alien address width\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ cctl |= width << PL080_CONTROL_SWIDTH_SHIFT;
|
|
|
+ cctl |= width << PL080_CONTROL_DWIDTH_SHIFT;
|
|
|
+
|
|
|
/*
|
|
|
- * Now decide on a maxburst:
|
|
|
* If this channel will only request single transfers, set this
|
|
|
* down to ONE element. Also select one element if no maxburst
|
|
|
* is specified.
|
|
|
*/
|
|
|
- if (plchan->cd->single || maxburst == 0) {
|
|
|
- cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
|
|
|
- (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
|
|
|
+ if (plchan->cd->single)
|
|
|
+ maxburst = 1;
|
|
|
+
|
|
|
+ burst = pl08x_burst(maxburst);
|
|
|
+ cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
|
|
|
+ cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
|
|
|
+
|
|
|
+ if (plchan->runtime_direction == DMA_FROM_DEVICE) {
|
|
|
+ plchan->src_addr = config->src_addr;
|
|
|
+ plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
|
|
|
+ pl08x_select_bus(plchan->cd->periph_buses,
|
|
|
+ pl08x->mem_buses);
|
|
|
} else {
|
|
|
- for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
|
|
|
- if (burst_sizes[i].burstwords <= maxburst)
|
|
|
- break;
|
|
|
- cctl |= burst_sizes[i].reg;
|
|
|
+ plchan->dst_addr = config->dst_addr;
|
|
|
+ plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR |
|
|
|
+ pl08x_select_bus(pl08x->mem_buses,
|
|
|
+ plchan->cd->periph_buses);
|
|
|
}
|
|
|
|
|
|
- plchan->runtime_addr = addr;
|
|
|
-
|
|
|
- /* Modify the default channel data to fit PrimeCell request */
|
|
|
- cd->cctl = cctl;
|
|
|
-
|
|
|
dev_dbg(&pl08x->adev->dev,
|
|
|
"configured channel %s (%s) for %s, data width %d, "
|
|
|
"maxburst %d words, LE, CCTL=0x%08x\n",
|
|
@@ -1270,23 +1297,6 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Given the source and destination available bus masks, select which
|
|
|
- * will be routed to each port. We try to have source and destination
|
|
|
- * on separate ports, but always respect the allowable settings.
|
|
|
- */
|
|
|
-static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst)
|
|
|
-{
|
|
|
- u32 cctl = 0;
|
|
|
-
|
|
|
- if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
|
|
|
- cctl |= PL080_CONTROL_DST_AHB2;
|
|
|
- if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
|
|
|
- cctl |= PL080_CONTROL_SRC_AHB2;
|
|
|
-
|
|
|
- return cctl;
|
|
|
-}
|
|
|
-
|
|
|
static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
|
|
|
unsigned long flags)
|
|
|
{
|
|
@@ -1338,8 +1348,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
|
|
|
txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
|
|
|
|
|
|
if (pl08x->vd->dualmaster)
|
|
|
- txd->cctl |= pl08x_select_bus(pl08x,
|
|
|
- pl08x->mem_buses, pl08x->mem_buses);
|
|
|
+ txd->cctl |= pl08x_select_bus(pl08x->mem_buses,
|
|
|
+ pl08x->mem_buses);
|
|
|
|
|
|
ret = pl08x_prep_channel_resources(plchan, txd);
|
|
|
if (ret)
|
|
@@ -1356,7 +1366,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
|
|
|
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
|
|
|
struct pl08x_driver_data *pl08x = plchan->host;
|
|
|
struct pl08x_txd *txd;
|
|
|
- u8 src_buses, dst_buses;
|
|
|
int ret;
|
|
|
|
|
|
/*
|
|
@@ -1390,42 +1399,22 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
|
|
|
txd->direction = direction;
|
|
|
txd->len = sgl->length;
|
|
|
|
|
|
- txd->cctl = plchan->cd->cctl &
|
|
|
- ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
|
|
|
- PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
|
|
|
- PL080_CONTROL_PROT_MASK);
|
|
|
-
|
|
|
- /* Access the cell in privileged mode, non-bufferable, non-cacheable */
|
|
|
- txd->cctl |= PL080_CONTROL_PROT_SYS;
|
|
|
-
|
|
|
if (direction == DMA_TO_DEVICE) {
|
|
|
txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
|
|
|
- txd->cctl |= PL080_CONTROL_SRC_INCR;
|
|
|
+ txd->cctl = plchan->dst_cctl;
|
|
|
txd->src_addr = sgl->dma_address;
|
|
|
- if (plchan->runtime_addr)
|
|
|
- txd->dst_addr = plchan->runtime_addr;
|
|
|
- else
|
|
|
- txd->dst_addr = plchan->cd->addr;
|
|
|
- src_buses = pl08x->mem_buses;
|
|
|
- dst_buses = plchan->cd->periph_buses;
|
|
|
+ txd->dst_addr = plchan->dst_addr;
|
|
|
} else if (direction == DMA_FROM_DEVICE) {
|
|
|
txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
|
|
|
- txd->cctl |= PL080_CONTROL_DST_INCR;
|
|
|
- if (plchan->runtime_addr)
|
|
|
- txd->src_addr = plchan->runtime_addr;
|
|
|
- else
|
|
|
- txd->src_addr = plchan->cd->addr;
|
|
|
+ txd->cctl = plchan->src_cctl;
|
|
|
+ txd->src_addr = plchan->src_addr;
|
|
|
txd->dst_addr = sgl->dma_address;
|
|
|
- src_buses = plchan->cd->periph_buses;
|
|
|
- dst_buses = pl08x->mem_buses;
|
|
|
} else {
|
|
|
dev_err(&pl08x->adev->dev,
|
|
|
"%s direction unsupported\n", __func__);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses);
|
|
|
-
|
|
|
ret = pl08x_prep_channel_resources(plchan, txd);
|
|
|
if (ret)
|
|
|
return NULL;
|
|
@@ -1676,6 +1665,20 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
|
|
|
return mask ? IRQ_HANDLED : IRQ_NONE;
|
|
|
}
|
|
|
|
|
|
+static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan)
|
|
|
+{
|
|
|
+ u32 cctl = pl08x_cctl(chan->cd->cctl);
|
|
|
+
|
|
|
+ chan->slave = true;
|
|
|
+ chan->name = chan->cd->bus_id;
|
|
|
+ chan->src_addr = chan->cd->addr;
|
|
|
+ chan->dst_addr = chan->cd->addr;
|
|
|
+ chan->src_cctl = cctl | PL080_CONTROL_DST_INCR |
|
|
|
+ pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses);
|
|
|
+ chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR |
|
|
|
+ pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialise the DMAC memcpy/slave channels.
|
|
|
* Make a local wrapper to hold required data
|
|
@@ -1707,9 +1710,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
|
|
|
chan->state = PL08X_CHAN_IDLE;
|
|
|
|
|
|
if (slave) {
|
|
|
- chan->slave = true;
|
|
|
- chan->name = pl08x->pd->slave_channels[i].bus_id;
|
|
|
chan->cd = &pl08x->pd->slave_channels[i];
|
|
|
+ pl08x_dma_slave_init(chan);
|
|
|
} else {
|
|
|
chan->cd = &pl08x->pd->memcpy_channel;
|
|
|
chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
|