aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/pl330.c75
1 files changed, 66 insertions, 9 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 8b0da7fa520d..a9451a14ad07 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -443,7 +443,10 @@ struct dma_pl330_chan {
443 /* For D-to-M and M-to-D channels */ 443 /* For D-to-M and M-to-D channels */
444 int burst_sz; /* the peripheral fifo width */ 444 int burst_sz; /* the peripheral fifo width */
445 int burst_len; /* the number of burst */ 445 int burst_len; /* the number of burst */
446 dma_addr_t fifo_addr; 446 phys_addr_t fifo_addr;
447 /* DMA-mapped view of the FIFO; may differ if an IOMMU is present */
448 dma_addr_t fifo_dma;
449 enum dma_data_direction dir;
447 450
448 /* for cyclic capability */ 451 /* for cyclic capability */
449 bool cyclic; 452 bool cyclic;
@@ -2120,11 +2123,60 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
2120 return 1; 2123 return 1;
2121} 2124}
2122 2125
2126/*
2127 * We need the data direction between the DMAC (the dma-mapping "device") and
2128 * the FIFO (the dmaengine "dev"), from the FIFO's point of view. Confusing!
2129 */
2130static enum dma_data_direction
2131pl330_dma_slave_map_dir(enum dma_transfer_direction dir)
2132{
2133 switch (dir) {
2134 case DMA_MEM_TO_DEV:
2135 return DMA_FROM_DEVICE;
2136 case DMA_DEV_TO_MEM:
2137 return DMA_TO_DEVICE;
2138 case DMA_DEV_TO_DEV:
2139 return DMA_BIDIRECTIONAL;
2140 default:
2141 return DMA_NONE;
2142 }
2143}
2144
2145static void pl330_unprep_slave_fifo(struct dma_pl330_chan *pch)
2146{
2147 if (pch->dir != DMA_NONE)
2148 dma_unmap_resource(pch->chan.device->dev, pch->fifo_dma,
2149 1 << pch->burst_sz, pch->dir, 0);
2150 pch->dir = DMA_NONE;
2151}
2152
2153
2154static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch,
2155 enum dma_transfer_direction dir)
2156{
2157 struct device *dev = pch->chan.device->dev;
2158 enum dma_data_direction dma_dir = pl330_dma_slave_map_dir(dir);
2159
2160 /* Already mapped for this config? */
2161 if (pch->dir == dma_dir)
2162 return true;
2163
2164 pl330_unprep_slave_fifo(pch);
2165 pch->fifo_dma = dma_map_resource(dev, pch->fifo_addr,
2166 1 << pch->burst_sz, dma_dir, 0);
2167 if (dma_mapping_error(dev, pch->fifo_dma))
2168 return false;
2169
2170 pch->dir = dma_dir;
2171 return true;
2172}
2173
2123static int pl330_config(struct dma_chan *chan, 2174static int pl330_config(struct dma_chan *chan,
2124 struct dma_slave_config *slave_config) 2175 struct dma_slave_config *slave_config)
2125{ 2176{
2126 struct dma_pl330_chan *pch = to_pchan(chan); 2177 struct dma_pl330_chan *pch = to_pchan(chan);
2127 2178
2179 pl330_unprep_slave_fifo(pch);
2128 if (slave_config->direction == DMA_MEM_TO_DEV) { 2180 if (slave_config->direction == DMA_MEM_TO_DEV) {
2129 if (slave_config->dst_addr) 2181 if (slave_config->dst_addr)
2130 pch->fifo_addr = slave_config->dst_addr; 2182 pch->fifo_addr = slave_config->dst_addr;
@@ -2235,6 +2287,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
2235 spin_unlock_irqrestore(&pl330->lock, flags); 2287 spin_unlock_irqrestore(&pl330->lock, flags);
2236 pm_runtime_mark_last_busy(pch->dmac->ddma.dev); 2288 pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
2237 pm_runtime_put_autosuspend(pch->dmac->ddma.dev); 2289 pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
2290 pl330_unprep_slave_fifo(pch);
2238} 2291}
2239 2292
2240static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, 2293static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
@@ -2564,6 +2617,9 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
2564 return NULL; 2617 return NULL;
2565 } 2618 }
2566 2619
2620 if (!pl330_prep_slave_fifo(pch, direction))
2621 return NULL;
2622
2567 for (i = 0; i < len / period_len; i++) { 2623 for (i = 0; i < len / period_len; i++) {
2568 desc = pl330_get_desc(pch); 2624 desc = pl330_get_desc(pch);
2569 if (!desc) { 2625 if (!desc) {
@@ -2593,12 +2649,12 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
2593 desc->rqcfg.src_inc = 1; 2649 desc->rqcfg.src_inc = 1;
2594 desc->rqcfg.dst_inc = 0; 2650 desc->rqcfg.dst_inc = 0;
2595 src = dma_addr; 2651 src = dma_addr;
2596 dst = pch->fifo_addr; 2652 dst = pch->fifo_dma;
2597 break; 2653 break;
2598 case DMA_DEV_TO_MEM: 2654 case DMA_DEV_TO_MEM:
2599 desc->rqcfg.src_inc = 0; 2655 desc->rqcfg.src_inc = 0;
2600 desc->rqcfg.dst_inc = 1; 2656 desc->rqcfg.dst_inc = 1;
2601 src = pch->fifo_addr; 2657 src = pch->fifo_dma;
2602 dst = dma_addr; 2658 dst = dma_addr;
2603 break; 2659 break;
2604 default: 2660 default:
@@ -2711,12 +2767,12 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
2711 struct dma_pl330_chan *pch = to_pchan(chan); 2767 struct dma_pl330_chan *pch = to_pchan(chan);
2712 struct scatterlist *sg; 2768 struct scatterlist *sg;
2713 int i; 2769 int i;
2714 dma_addr_t addr;
2715 2770
2716 if (unlikely(!pch || !sgl || !sg_len)) 2771 if (unlikely(!pch || !sgl || !sg_len))
2717 return NULL; 2772 return NULL;
2718 2773
2719 addr = pch->fifo_addr; 2774 if (!pl330_prep_slave_fifo(pch, direction))
2775 return NULL;
2720 2776
2721 first = NULL; 2777 first = NULL;
2722 2778
@@ -2742,13 +2798,13 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
2742 if (direction == DMA_MEM_TO_DEV) { 2798 if (direction == DMA_MEM_TO_DEV) {
2743 desc->rqcfg.src_inc = 1; 2799 desc->rqcfg.src_inc = 1;
2744 desc->rqcfg.dst_inc = 0; 2800 desc->rqcfg.dst_inc = 0;
2745 fill_px(&desc->px, 2801 fill_px(&desc->px, pch->fifo_dma, sg_dma_address(sg),
2746 addr, sg_dma_address(sg), sg_dma_len(sg)); 2802 sg_dma_len(sg));
2747 } else { 2803 } else {
2748 desc->rqcfg.src_inc = 0; 2804 desc->rqcfg.src_inc = 0;
2749 desc->rqcfg.dst_inc = 1; 2805 desc->rqcfg.dst_inc = 1;
2750 fill_px(&desc->px, 2806 fill_px(&desc->px, sg_dma_address(sg), pch->fifo_dma,
2751 sg_dma_address(sg), addr, sg_dma_len(sg)); 2807 sg_dma_len(sg));
2752 } 2808 }
2753 2809
2754 desc->rqcfg.brst_size = pch->burst_sz; 2810 desc->rqcfg.brst_size = pch->burst_sz;
@@ -2906,6 +2962,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
2906 pch->thread = NULL; 2962 pch->thread = NULL;
2907 pch->chan.device = pd; 2963 pch->chan.device = pd;
2908 pch->dmac = pl330; 2964 pch->dmac = pl330;
2965 pch->dir = DMA_NONE;
2909 2966
2910 /* Add the channel to the DMAC list */ 2967 /* Add the channel to the DMAC list */
2911 list_add_tail(&pch->chan.device_node, &pd->channels); 2968 list_add_tail(&pch->chan.device_node, &pd->channels);