aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ste_dma40.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-08-01 19:46:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-01 19:46:37 -0400
commit12ff47e7f5fb64c566f62e6cf6a3b291c51bd337 (patch)
treed9fba3780142af380ccfaf90d8b13363e3475bd7 /drivers/dma/ste_dma40.c
parent73bcbac130a59f236ae78ed70ef7a05b45caa19e (diff)
parent1ae105aa7416087f2920c35c3cd16831d0d09c9c (diff)
Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma
* 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma: (37 commits) Improve slave/cyclic DMA engine documentation dmaengine: pl08x: handle the rest of enums in pl08x_width DMA: PL08x: cleanup selection of burst size DMA: PL08x: avoid recalculating cctl at each prepare DMA: PL08x: cleanup selection of buswidth DMA: PL08x: constify plchan->cd and plat->slave_channels DMA: PL08x: separately store source/destination cctl DMA: PL08x: separately store source/destination slave address DMA: PL08x: clean up LLI debugging DMA: PL08x: select LLI bus only once per LLI setup DMA: PL08x: remove unused constants ARM: mxs-dma: reset after disable channel dma: intel_mid_dma: remove redundant pci_set_drvdata calls dma: mxs-dma: fix unterminated platform_device_id table dmaengine: pl330: make platform data optional dmaengine: imx-sdma: return proper error if kzalloc fails pch_dma: Fix CTL register access issue dmaengine: mxs-dma: skip request_irq for NO_IRQ dmaengine/coh901318: fix slave submission semantics dmaengine/ste_dma40: allow memory buswidth/burst to be configured ... Fix trivial whitespace conflict in drivers/dma/mv_xor.c
Diffstat (limited to 'drivers/dma/ste_dma40.c')
-rw-r--r--drivers/dma/ste_dma40.c270
1 files changed, 155 insertions, 115 deletions
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 29d1addbe0cf..cd3a7c726bf8 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -14,6 +14,7 @@
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/amba/bus.h>
17 18
18#include <plat/ste_dma40.h> 19#include <plat/ste_dma40.h>
19 20
@@ -45,9 +46,6 @@
45#define D40_ALLOC_PHY (1 << 30) 46#define D40_ALLOC_PHY (1 << 30)
46#define D40_ALLOC_LOG_FREE 0 47#define D40_ALLOC_LOG_FREE 0
47 48
48/* Hardware designer of the block */
49#define D40_HW_DESIGNER 0x8
50
51/** 49/**
52 * enum 40_command - The different commands and/or statuses. 50 * enum 40_command - The different commands and/or statuses.
53 * 51 *
@@ -186,6 +184,8 @@ struct d40_base;
186 * @log_def: Default logical channel settings. 184 * @log_def: Default logical channel settings.
187 * @lcla: Space for one dst src pair for logical channel transfers. 185 * @lcla: Space for one dst src pair for logical channel transfers.
188 * @lcpa: Pointer to dst and src lcpa settings. 186 * @lcpa: Pointer to dst and src lcpa settings.
187 * @runtime_addr: runtime configured address.
188 * @runtime_direction: runtime configured direction.
189 * 189 *
190 * This struct can either "be" a logical or a physical channel. 190 * This struct can either "be" a logical or a physical channel.
191 */ 191 */
@@ -200,6 +200,7 @@ struct d40_chan {
200 struct dma_chan chan; 200 struct dma_chan chan;
201 struct tasklet_struct tasklet; 201 struct tasklet_struct tasklet;
202 struct list_head client; 202 struct list_head client;
203 struct list_head pending_queue;
203 struct list_head active; 204 struct list_head active;
204 struct list_head queue; 205 struct list_head queue;
205 struct stedma40_chan_cfg dma_cfg; 206 struct stedma40_chan_cfg dma_cfg;
@@ -645,7 +646,20 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
645 646
646static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) 647static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
647{ 648{
648 list_add_tail(&desc->node, &d40c->queue); 649 list_add_tail(&desc->node, &d40c->pending_queue);
650}
651
652static struct d40_desc *d40_first_pending(struct d40_chan *d40c)
653{
654 struct d40_desc *d;
655
656 if (list_empty(&d40c->pending_queue))
657 return NULL;
658
659 d = list_first_entry(&d40c->pending_queue,
660 struct d40_desc,
661 node);
662 return d;
649} 663}
650 664
651static struct d40_desc *d40_first_queued(struct d40_chan *d40c) 665static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
@@ -802,6 +816,11 @@ static void d40_term_all(struct d40_chan *d40c)
802 d40_desc_free(d40c, d40d); 816 d40_desc_free(d40c, d40d);
803 } 817 }
804 818
819 /* Release pending descriptors */
820 while ((d40d = d40_first_pending(d40c))) {
821 d40_desc_remove(d40d);
822 d40_desc_free(d40c, d40d);
823 }
805 824
806 d40c->pending_tx = 0; 825 d40c->pending_tx = 0;
807 d40c->busy = false; 826 d40c->busy = false;
@@ -2092,7 +2111,7 @@ dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
2092 struct scatterlist *sg; 2111 struct scatterlist *sg;
2093 int i; 2112 int i;
2094 2113
2095 sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL); 2114 sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_NOWAIT);
2096 for (i = 0; i < periods; i++) { 2115 for (i = 0; i < periods; i++) {
2097 sg_dma_address(&sg[i]) = dma_addr; 2116 sg_dma_address(&sg[i]) = dma_addr;
2098 sg_dma_len(&sg[i]) = period_len; 2117 sg_dma_len(&sg[i]) = period_len;
@@ -2152,24 +2171,87 @@ static void d40_issue_pending(struct dma_chan *chan)
2152 2171
2153 spin_lock_irqsave(&d40c->lock, flags); 2172 spin_lock_irqsave(&d40c->lock, flags);
2154 2173
2155 /* Busy means that pending jobs are already being processed */ 2174 list_splice_tail_init(&d40c->pending_queue, &d40c->queue);
2175
2176 /* Busy means that queued jobs are already being processed */
2156 if (!d40c->busy) 2177 if (!d40c->busy)
2157 (void) d40_queue_start(d40c); 2178 (void) d40_queue_start(d40c);
2158 2179
2159 spin_unlock_irqrestore(&d40c->lock, flags); 2180 spin_unlock_irqrestore(&d40c->lock, flags);
2160} 2181}
2161 2182
2183static int
2184dma40_config_to_halfchannel(struct d40_chan *d40c,
2185 struct stedma40_half_channel_info *info,
2186 enum dma_slave_buswidth width,
2187 u32 maxburst)
2188{
2189 enum stedma40_periph_data_width addr_width;
2190 int psize;
2191
2192 switch (width) {
2193 case DMA_SLAVE_BUSWIDTH_1_BYTE:
2194 addr_width = STEDMA40_BYTE_WIDTH;
2195 break;
2196 case DMA_SLAVE_BUSWIDTH_2_BYTES:
2197 addr_width = STEDMA40_HALFWORD_WIDTH;
2198 break;
2199 case DMA_SLAVE_BUSWIDTH_4_BYTES:
2200 addr_width = STEDMA40_WORD_WIDTH;
2201 break;
2202 case DMA_SLAVE_BUSWIDTH_8_BYTES:
2203 addr_width = STEDMA40_DOUBLEWORD_WIDTH;
2204 break;
2205 default:
2206 dev_err(d40c->base->dev,
2207 "illegal peripheral address width "
2208 "requested (%d)\n",
2209 width);
2210 return -EINVAL;
2211 }
2212
2213 if (chan_is_logical(d40c)) {
2214 if (maxburst >= 16)
2215 psize = STEDMA40_PSIZE_LOG_16;
2216 else if (maxburst >= 8)
2217 psize = STEDMA40_PSIZE_LOG_8;
2218 else if (maxburst >= 4)
2219 psize = STEDMA40_PSIZE_LOG_4;
2220 else
2221 psize = STEDMA40_PSIZE_LOG_1;
2222 } else {
2223 if (maxburst >= 16)
2224 psize = STEDMA40_PSIZE_PHY_16;
2225 else if (maxburst >= 8)
2226 psize = STEDMA40_PSIZE_PHY_8;
2227 else if (maxburst >= 4)
2228 psize = STEDMA40_PSIZE_PHY_4;
2229 else
2230 psize = STEDMA40_PSIZE_PHY_1;
2231 }
2232
2233 info->data_width = addr_width;
2234 info->psize = psize;
2235 info->flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2236
2237 return 0;
2238}
2239
2162/* Runtime reconfiguration extension */ 2240/* Runtime reconfiguration extension */
2163static void d40_set_runtime_config(struct dma_chan *chan, 2241static int d40_set_runtime_config(struct dma_chan *chan,
2164 struct dma_slave_config *config) 2242 struct dma_slave_config *config)
2165{ 2243{
2166 struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); 2244 struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
2167 struct stedma40_chan_cfg *cfg = &d40c->dma_cfg; 2245 struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
2168 enum dma_slave_buswidth config_addr_width; 2246 enum dma_slave_buswidth src_addr_width, dst_addr_width;
2169 dma_addr_t config_addr; 2247 dma_addr_t config_addr;
2170 u32 config_maxburst; 2248 u32 src_maxburst, dst_maxburst;
2171 enum stedma40_periph_data_width addr_width; 2249 int ret;
2172 int psize; 2250
2251 src_addr_width = config->src_addr_width;
2252 src_maxburst = config->src_maxburst;
2253 dst_addr_width = config->dst_addr_width;
2254 dst_maxburst = config->dst_maxburst;
2173 2255
2174 if (config->direction == DMA_FROM_DEVICE) { 2256 if (config->direction == DMA_FROM_DEVICE) {
2175 dma_addr_t dev_addr_rx = 2257 dma_addr_t dev_addr_rx =
@@ -2188,8 +2270,11 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2188 cfg->dir); 2270 cfg->dir);
2189 cfg->dir = STEDMA40_PERIPH_TO_MEM; 2271 cfg->dir = STEDMA40_PERIPH_TO_MEM;
2190 2272
2191 config_addr_width = config->src_addr_width; 2273 /* Configure the memory side */
2192 config_maxburst = config->src_maxburst; 2274 if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
2275 dst_addr_width = src_addr_width;
2276 if (dst_maxburst == 0)
2277 dst_maxburst = src_maxburst;
2193 2278
2194 } else if (config->direction == DMA_TO_DEVICE) { 2279 } else if (config->direction == DMA_TO_DEVICE) {
2195 dma_addr_t dev_addr_tx = 2280 dma_addr_t dev_addr_tx =
@@ -2208,68 +2293,39 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2208 cfg->dir); 2293 cfg->dir);
2209 cfg->dir = STEDMA40_MEM_TO_PERIPH; 2294 cfg->dir = STEDMA40_MEM_TO_PERIPH;
2210 2295
2211 config_addr_width = config->dst_addr_width; 2296 /* Configure the memory side */
2212 config_maxburst = config->dst_maxburst; 2297 if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
2213 2298 src_addr_width = dst_addr_width;
2299 if (src_maxburst == 0)
2300 src_maxburst = dst_maxburst;
2214 } else { 2301 } else {
2215 dev_err(d40c->base->dev, 2302 dev_err(d40c->base->dev,
2216 "unrecognized channel direction %d\n", 2303 "unrecognized channel direction %d\n",
2217 config->direction); 2304 config->direction);
2218 return; 2305 return -EINVAL;
2219 } 2306 }
2220 2307
2221 switch (config_addr_width) { 2308 if (src_maxburst * src_addr_width != dst_maxburst * dst_addr_width) {
2222 case DMA_SLAVE_BUSWIDTH_1_BYTE:
2223 addr_width = STEDMA40_BYTE_WIDTH;
2224 break;
2225 case DMA_SLAVE_BUSWIDTH_2_BYTES:
2226 addr_width = STEDMA40_HALFWORD_WIDTH;
2227 break;
2228 case DMA_SLAVE_BUSWIDTH_4_BYTES:
2229 addr_width = STEDMA40_WORD_WIDTH;
2230 break;
2231 case DMA_SLAVE_BUSWIDTH_8_BYTES:
2232 addr_width = STEDMA40_DOUBLEWORD_WIDTH;
2233 break;
2234 default:
2235 dev_err(d40c->base->dev, 2309 dev_err(d40c->base->dev,
2236 "illegal peripheral address width " 2310 "src/dst width/maxburst mismatch: %d*%d != %d*%d\n",
2237 "requested (%d)\n", 2311 src_maxburst,
2238 config->src_addr_width); 2312 src_addr_width,
2239 return; 2313 dst_maxburst,
2314 dst_addr_width);
2315 return -EINVAL;
2240 } 2316 }
2241 2317
2242 if (chan_is_logical(d40c)) { 2318 ret = dma40_config_to_halfchannel(d40c, &cfg->src_info,
2243 if (config_maxburst >= 16) 2319 src_addr_width,
2244 psize = STEDMA40_PSIZE_LOG_16; 2320 src_maxburst);
2245 else if (config_maxburst >= 8) 2321 if (ret)
2246 psize = STEDMA40_PSIZE_LOG_8; 2322 return ret;
2247 else if (config_maxburst >= 4)
2248 psize = STEDMA40_PSIZE_LOG_4;
2249 else
2250 psize = STEDMA40_PSIZE_LOG_1;
2251 } else {
2252 if (config_maxburst >= 16)
2253 psize = STEDMA40_PSIZE_PHY_16;
2254 else if (config_maxburst >= 8)
2255 psize = STEDMA40_PSIZE_PHY_8;
2256 else if (config_maxburst >= 4)
2257 psize = STEDMA40_PSIZE_PHY_4;
2258 else if (config_maxburst >= 2)
2259 psize = STEDMA40_PSIZE_PHY_2;
2260 else
2261 psize = STEDMA40_PSIZE_PHY_1;
2262 }
2263 2323
2264 /* Set up all the endpoint configs */ 2324 ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info,
2265 cfg->src_info.data_width = addr_width; 2325 dst_addr_width,
2266 cfg->src_info.psize = psize; 2326 dst_maxburst);
2267 cfg->src_info.big_endian = false; 2327 if (ret)
2268 cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; 2328 return ret;
2269 cfg->dst_info.data_width = addr_width;
2270 cfg->dst_info.psize = psize;
2271 cfg->dst_info.big_endian = false;
2272 cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2273 2329
2274 /* Fill in register values */ 2330 /* Fill in register values */
2275 if (chan_is_logical(d40c)) 2331 if (chan_is_logical(d40c))
@@ -2282,12 +2338,14 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2282 d40c->runtime_addr = config_addr; 2338 d40c->runtime_addr = config_addr;
2283 d40c->runtime_direction = config->direction; 2339 d40c->runtime_direction = config->direction;
2284 dev_dbg(d40c->base->dev, 2340 dev_dbg(d40c->base->dev,
2285 "configured channel %s for %s, data width %d, " 2341 "configured channel %s for %s, data width %d/%d, "
2286 "maxburst %d bytes, LE, no flow control\n", 2342 "maxburst %d/%d elements, LE, no flow control\n",
2287 dma_chan_name(chan), 2343 dma_chan_name(chan),
2288 (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", 2344 (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
2289 config_addr_width, 2345 src_addr_width, dst_addr_width,
2290 config_maxburst); 2346 src_maxburst, dst_maxburst);
2347
2348 return 0;
2291} 2349}
2292 2350
2293static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 2351static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -2308,9 +2366,8 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
2308 case DMA_RESUME: 2366 case DMA_RESUME:
2309 return d40_resume(d40c); 2367 return d40_resume(d40c);
2310 case DMA_SLAVE_CONFIG: 2368 case DMA_SLAVE_CONFIG:
2311 d40_set_runtime_config(chan, 2369 return d40_set_runtime_config(chan,
2312 (struct dma_slave_config *) arg); 2370 (struct dma_slave_config *) arg);
2313 return 0;
2314 default: 2371 default:
2315 break; 2372 break;
2316 } 2373 }
@@ -2341,6 +2398,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
2341 2398
2342 INIT_LIST_HEAD(&d40c->active); 2399 INIT_LIST_HEAD(&d40c->active);
2343 INIT_LIST_HEAD(&d40c->queue); 2400 INIT_LIST_HEAD(&d40c->queue);
2401 INIT_LIST_HEAD(&d40c->pending_queue);
2344 INIT_LIST_HEAD(&d40c->client); 2402 INIT_LIST_HEAD(&d40c->client);
2345 2403
2346 tasklet_init(&d40c->tasklet, dma_tasklet, 2404 tasklet_init(&d40c->tasklet, dma_tasklet,
@@ -2502,25 +2560,6 @@ static int __init d40_phy_res_init(struct d40_base *base)
2502 2560
2503static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) 2561static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
2504{ 2562{
2505 static const struct d40_reg_val dma_id_regs[] = {
2506 /* Peripheral Id */
2507 { .reg = D40_DREG_PERIPHID0, .val = 0x0040},
2508 { .reg = D40_DREG_PERIPHID1, .val = 0x0000},
2509 /*
2510 * D40_DREG_PERIPHID2 Depends on HW revision:
2511 * DB8500ed has 0x0008,
2512 * ? has 0x0018,
2513 * DB8500v1 has 0x0028
2514 * DB8500v2 has 0x0038
2515 */
2516 { .reg = D40_DREG_PERIPHID3, .val = 0x0000},
2517
2518 /* PCell Id */
2519 { .reg = D40_DREG_CELLID0, .val = 0x000d},
2520 { .reg = D40_DREG_CELLID1, .val = 0x00f0},
2521 { .reg = D40_DREG_CELLID2, .val = 0x0005},
2522 { .reg = D40_DREG_CELLID3, .val = 0x00b1}
2523 };
2524 struct stedma40_platform_data *plat_data; 2563 struct stedma40_platform_data *plat_data;
2525 struct clk *clk = NULL; 2564 struct clk *clk = NULL;
2526 void __iomem *virtbase = NULL; 2565 void __iomem *virtbase = NULL;
@@ -2529,8 +2568,9 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
2529 int num_log_chans = 0; 2568 int num_log_chans = 0;
2530 int num_phy_chans; 2569 int num_phy_chans;
2531 int i; 2570 int i;
2532 u32 val; 2571 u32 pid;
2533 u32 rev; 2572 u32 cid;
2573 u8 rev;
2534 2574
2535 clk = clk_get(&pdev->dev, NULL); 2575 clk = clk_get(&pdev->dev, NULL);
2536 2576
@@ -2554,32 +2594,32 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
2554 if (!virtbase) 2594 if (!virtbase)
2555 goto failure; 2595 goto failure;
2556 2596
2557 /* HW version check */ 2597 /* This is just a regular AMBA PrimeCell ID actually */
2558 for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) { 2598 for (pid = 0, i = 0; i < 4; i++)
2559 if (dma_id_regs[i].val != 2599 pid |= (readl(virtbase + resource_size(res) - 0x20 + 4 * i)
2560 readl(virtbase + dma_id_regs[i].reg)) { 2600 & 255) << (i * 8);
2561 d40_err(&pdev->dev, 2601 for (cid = 0, i = 0; i < 4; i++)
2562 "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n", 2602 cid |= (readl(virtbase + resource_size(res) - 0x10 + 4 * i)
2563 dma_id_regs[i].val, 2603 & 255) << (i * 8);
2564 dma_id_regs[i].reg,
2565 readl(virtbase + dma_id_regs[i].reg));
2566 goto failure;
2567 }
2568 }
2569 2604
2570 /* Get silicon revision and designer */ 2605 if (cid != AMBA_CID) {
2571 val = readl(virtbase + D40_DREG_PERIPHID2); 2606 d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n");
2572 2607 goto failure;
2573 if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) != 2608 }
2574 D40_HW_DESIGNER) { 2609 if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) {
2575 d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n", 2610 d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n",
2576 val & D40_DREG_PERIPHID2_DESIGNER_MASK, 2611 AMBA_MANF_BITS(pid),
2577 D40_HW_DESIGNER); 2612 AMBA_VENDOR_ST);
2578 goto failure; 2613 goto failure;
2579 } 2614 }
2580 2615 /*
2581 rev = (val & D40_DREG_PERIPHID2_REV_MASK) >> 2616 * HW revision:
2582 D40_DREG_PERIPHID2_REV_POS; 2617 * DB8500ed has revision 0
2618 * ? has revision 1
2619 * DB8500v1 has revision 2
2620 * DB8500v2 has revision 3
2621 */
2622 rev = AMBA_REV_BITS(pid);
2583 2623
2584 /* The number of physical channels on this HW */ 2624 /* The number of physical channels on this HW */
2585 num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4; 2625 num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;