diff options
-rw-r--r-- | drivers/dma/pl330.c | 75 |
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 | */ | ||
2130 | static enum dma_data_direction | ||
2131 | pl330_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 | |||
2145 | static 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 | |||
2154 | static 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 | |||
2123 | static int pl330_config(struct dma_chan *chan, | 2174 | static 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 | ||
2240 | static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, | 2293 | static 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); |