diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-01 19:46:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-01 19:46:37 -0400 |
commit | 12ff47e7f5fb64c566f62e6cf6a3b291c51bd337 (patch) | |
tree | d9fba3780142af380ccfaf90d8b13363e3475bd7 /drivers/dma/ste_dma40.c | |
parent | 73bcbac130a59f236ae78ed70ef7a05b45caa19e (diff) | |
parent | 1ae105aa7416087f2920c35c3cd16831d0d09c9c (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.c | 270 |
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 | ||
646 | static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) | 647 | static 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 | |||
652 | static 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 | ||
651 | static struct d40_desc *d40_first_queued(struct d40_chan *d40c) | 665 | static 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 | ||
2183 | static int | ||
2184 | dma40_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 */ |
2163 | static void d40_set_runtime_config(struct dma_chan *chan, | 2241 | static 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 | ||
2293 | static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 2351 | static 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 | ||
2503 | static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) | 2561 | static 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; |