diff options
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 83 |
1 files changed, 52 insertions, 31 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index e6d7228b1479..4d1de62510bf 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -937,9 +937,9 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, ch->signal = ret; /* Assign the flow control signal to this channel */ - if (txd->direction == DMA_TO_DEVICE) + if (txd->direction == DMA_MEM_TO_DEV) txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT; - else if (txd->direction == DMA_FROM_DEVICE) + else if (txd->direction == DMA_DEV_TO_MEM) txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT; } @@ -1118,12 +1118,10 @@ 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; + if (config->direction == DMA_MEM_TO_DEV) { addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; - } else if (config->direction == DMA_FROM_DEVICE) { - addr = config->src_addr; + } else if (config->direction == DMA_DEV_TO_MEM) { addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1157,9 +1155,18 @@ static int dma_set_runtime_config(struct dma_chan *chan, * 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_DEV_TO_MEM) { + 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) @@ -1176,7 +1183,7 @@ static int dma_set_runtime_config(struct dma_chan *chan, "configured channel %s (%s) for %s, data width %d, " "maxburst %d words, LE, CCTL=0x%08x\n", dma_chan_name(chan), plchan->name, - (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", + (config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX", addr_width, maxburst, cctl); @@ -1350,7 +1357,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); @@ -1398,26 +1405,12 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( /* 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->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; - } 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->dst_addr = sgl->dma_address; - src_buses = plchan->cd->periph_buses; - dst_buses = pl08x->mem_buses; + if (direction == DMA_MEM_TO_DEV) { + txd->cctl = plchan->dst_cctl; + slave_addr = plchan->dst_addr; + } else if (direction == DMA_DEV_TO_MEM) { + txd->cctl = plchan->src_cctl; + slave_addr = plchan->src_addr; } else { dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); @@ -1425,6 +1418,34 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( } txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); + if (plchan->cd->device_fc) + tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER : + PL080_FLOW_PER2MEM_PER; + else + tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER : + PL080_FLOW_PER2MEM; + + txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT; + + for_each_sg(sgl, sg, sg_len, tmp) { + dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT); + if (!dsg) { + pl08x_free_txd(pl08x, txd); + dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n", + __func__); + return NULL; + } + list_add_tail(&dsg->node, &txd->dsg_list); + + dsg->len = sg_dma_len(sg); + if (direction == DMA_MEM_TO_DEV) { + dsg->src_addr = sg_phys(sg); + dsg->dst_addr = slave_addr; + } else { + dsg->src_addr = slave_addr; + dsg->dst_addr = sg_phys(sg); + } + } ret = pl08x_prep_channel_resources(plchan, txd); if (ret) |