OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From e0dcf539876b6da0763bd87d0f072a0197c97ee1 Mon Sep 17 00:00:00 2001 |
2 | From: Florian Meier <florian.meier@koalo.de> |
||
3 | Date: Fri, 22 Nov 2013 14:22:53 +0100 |
||
4 | Subject: [PATCH 039/454] dmaengine: Add support for BCM2708 |
||
5 | MIME-Version: 1.0 |
||
6 | Content-Type: text/plain; charset=UTF-8 |
||
7 | Content-Transfer-Encoding: 8bit |
||
8 | |||
9 | Add support for DMA controller of BCM2708 as used in the Raspberry Pi. |
||
10 | Currently it only supports cyclic DMA. |
||
11 | |||
12 | Signed-off-by: Florian Meier <florian.meier@koalo.de> |
||
13 | |||
14 | dmaengine: expand functionality by supporting scatter/gather transfers sdhci-bcm2708 and dma.c: fix for LITE channels |
||
15 | |||
16 | DMA: fix cyclic LITE length overflow bug |
||
17 | |||
18 | dmaengine: bcm2708: Remove chancnt affectations |
||
19 | |||
20 | Mirror bcm2835-dma.c commit 9eba5536a7434c69d8c185d4bd1c70734d92287d: |
||
21 | chancnt is already filled by dma_async_device_register, which uses the channel |
||
22 | list to know how much channels there is. |
||
23 | |||
24 | Since it's already filled, we can safely remove it from the drivers' probe |
||
25 | function. |
||
26 | |||
27 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
28 | |||
29 | dmaengine: bcm2708: overwrite dreq only if it is not set |
||
30 | |||
31 | dreq is set when the DMA channel is fetched from Device Tree. |
||
32 | slave_id is set using dmaengine_slave_config(). |
||
33 | Only overwrite dreq with slave_id if it is not set. |
||
34 | |||
35 | dreq/slave_id in the cyclic DMA case is not touched, because I don't |
||
36 | have hardware to test with. |
||
37 | |||
38 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
39 | |||
40 | dmaengine: bcm2708: do device registration in the board file |
||
41 | |||
42 | Don't register the device in the driver. Do it in the board file. |
||
43 | |||
44 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
45 | |||
46 | dmaengine: bcm2708: don't restrict DT support to ARCH_BCM2835 |
||
47 | |||
48 | Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now. |
||
49 | Add Device Tree support to the non ARCH_BCM2835 case. |
||
50 | Use the same driver name regardless of architecture. |
||
51 | |||
52 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
53 | |||
54 | BCM270x_DT: add bcm2835-dma entry |
||
55 | |||
56 | Add Device Tree entry for bcm2835-dma. |
||
57 | The entry doesn't contain any resources since they are handled |
||
58 | by the arch/arm/mach-bcm270x/dma.c driver. |
||
59 | In non-DT mode, don't add the device in the board file. |
||
60 | |||
61 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
62 | |||
63 | bcm2708-dmaengine: Add debug options |
||
64 | |||
65 | BCM270x: Add memory and irq resources to dmaengine device and DT |
||
66 | |||
67 | Prepare for merging of the legacy DMA API arch driver dma.c |
||
68 | with bcm2708-dmaengine by adding memory and irq resources both |
||
69 | to platform file device and Device Tree node. |
||
70 | Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h |
||
71 | |||
72 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
73 | |||
74 | dmaengine: bcm2708: Merge with arch dma.c driver and disable dma.c |
||
75 | |||
76 | Merge the legacy DMA API driver with bcm2708-dmaengine. |
||
77 | This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox |
||
78 | driver is also needed). |
||
79 | |||
80 | Changes to the dma.c code: |
||
81 | - Use BIT() macro. |
||
82 | - Cutdown some comments to one line. |
||
83 | - Add mutex to vc_dmaman and use this, since the dev lock is locked |
||
84 | during probing of the engine part. |
||
85 | - Add global g_dmaman variable since drvdata is used by the engine part. |
||
86 | - Restructure for readability: |
||
87 | vc_dmaman_chan_alloc() |
||
88 | vc_dmaman_chan_free() |
||
89 | bcm_dma_chan_free() |
||
90 | - Restructure bcm_dma_chan_alloc() to simplify error handling. |
||
91 | - Use device irq resources instead of hardcoded bcm_dma_irqs table. |
||
92 | - Remove dev_dmaman_register() and code it directly. |
||
93 | - Remove dev_dmaman_deregister() and code it directly. |
||
94 | - Simplify bcm_dmaman_probe() using devm_* functions. |
||
95 | - Get dmachans from DT if available. |
||
96 | - Keep 'dma.dmachans' module argument name for backwards compatibility. |
||
97 | |||
98 | Make it available on ARCH_BCM2835 as well. |
||
99 | |||
100 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
101 | |||
102 | dmaengine: bcm2708: set residue_granularity field |
||
103 | |||
104 | bcm2708-dmaengine supports residue reporting at burst level |
||
105 | but didn't report this via the residue_granularity field. |
||
106 | |||
107 | Without this field set properly we get playback issues with I2S cards. |
||
108 | |||
109 | dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer |
||
110 | |||
111 | bcm2708-dmaengine: Use more DMA channels (but not 12) |
||
112 | |||
113 | 1) Only the bcm2708_fb drivers uses the legacy DMA API, and |
||
114 | it requires a BULK-capable channel, so all other types |
||
115 | (FAST, NORMAL and LITE) can be made available to the regular |
||
116 | DMA API. |
||
117 | |||
118 | 2) DMA channels 11-14 share an interrupt. The driver can't |
||
119 | handle this, so don't use channels 12-14 (12 was used, probably |
||
120 | because it appears to have an interrupt, but in reality that |
||
121 | interrupt is for activity on ANY channel). This may explain |
||
122 | a lockup encountered when running out of DMA channels. |
||
123 | |||
124 | The combined effect of this patch is to leave 7 DMA channels |
||
125 | available + channel 0 for bcm2708_fb via the legacy API. |
||
126 | |||
127 | See: https://github.com/raspberrypi/linux/issues/1110 |
||
128 | https://github.com/raspberrypi/linux/issues/1108 |
||
129 | |||
130 | dmaengine: bcm2708: Make legacy API available for bcm2835-dma |
||
131 | |||
132 | bcm2708_fb uses the legacy DMA API, so in order to start using |
||
133 | bcm2835-dma, bcm2835-dma has to support the legacy API. Make this |
||
134 | possible by exporting bcm_dmaman_probe() and bcm_dmaman_remove(). |
||
135 | |||
136 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
137 | |||
138 | dmaengine: bcm2708: Change DT compatible string |
||
139 | |||
140 | Both bcm2835-dma and bcm2708-dmaengine have the same compatible string. |
||
141 | So change compatible to "brcm,bcm2708-dma". |
||
142 | |||
143 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
144 | |||
145 | dmaengine: bcm2708: Remove driver but keep legacy API |
||
146 | |||
147 | Dropping non-DT support means we don't need this driver, |
||
148 | but we still need the legacy DMA API. |
||
149 | |||
150 | Signed-off-by: Noralf Trønnes <noralf@tronnes.org> |
||
151 | |||
152 | bcm2708-dmaengine - Fix arm64 portability/build issues |
||
153 | --- |
||
154 | drivers/dma/Kconfig | 6 +- |
||
155 | drivers/dma/Makefile | 1 + |
||
156 | drivers/dma/bcm2708-dmaengine.c | 281 ++++++++++++++++++++++ |
||
157 | include/linux/platform_data/dma-bcm2708.h | 143 +++++++++++ |
||
158 | 4 files changed, 430 insertions(+), 1 deletion(-) |
||
159 | create mode 100644 drivers/dma/bcm2708-dmaengine.c |
||
160 | create mode 100644 include/linux/platform_data/dma-bcm2708.h |
||
161 | |||
162 | --- a/drivers/dma/Kconfig |
||
163 | +++ b/drivers/dma/Kconfig |
||
164 | @@ -131,7 +131,7 @@ config COH901318 |
||
165 | |||
166 | config DMA_BCM2835 |
||
167 | tristate "BCM2835 DMA engine support" |
||
168 | - depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 |
||
169 | + depends on ARCH_BCM2835 |
||
170 | select DMA_ENGINE |
||
171 | select DMA_VIRTUAL_CHANNELS |
||
172 | |||
173 | @@ -535,6 +535,10 @@ config TIMB_DMA |
||
174 | help |
||
175 | Enable support for the Timberdale FPGA DMA engine. |
||
176 | |||
177 | +config DMA_BCM2708 |
||
178 | + tristate "BCM2708 DMA legacy API support" |
||
179 | + depends on DMA_BCM2835 |
||
180 | + |
||
181 | config TI_CPPI41 |
||
182 | tristate "CPPI 4.1 DMA support" |
||
183 | depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX) |
||
184 | --- a/drivers/dma/Makefile |
||
185 | +++ b/drivers/dma/Makefile |
||
186 | @@ -21,6 +21,7 @@ obj-$(CONFIG_AT_XDMAC) += at_xdmac.o |
||
187 | obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o |
||
188 | obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o |
||
189 | obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o |
||
190 | +obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o |
||
191 | obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o |
||
192 | obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o |
||
193 | obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o |
||
194 | --- /dev/null |
||
195 | +++ b/drivers/dma/bcm2708-dmaengine.c |
||
196 | @@ -0,0 +1,281 @@ |
||
197 | +/* |
||
198 | + * BCM2708 legacy DMA API |
||
199 | + * |
||
200 | + * This program is free software; you can redistribute it and/or modify |
||
201 | + * it under the terms of the GNU General Public License as published by |
||
202 | + * the Free Software Foundation; either version 2 of the License, or |
||
203 | + * (at your option) any later version. |
||
204 | + * |
||
205 | + * This program is distributed in the hope that it will be useful, |
||
206 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
207 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
208 | + * GNU General Public License for more details. |
||
209 | + */ |
||
210 | + |
||
211 | +#include <linux/init.h> |
||
212 | +#include <linux/interrupt.h> |
||
213 | +#include <linux/list.h> |
||
214 | +#include <linux/module.h> |
||
215 | +#include <linux/platform_data/dma-bcm2708.h> |
||
216 | +#include <linux/platform_device.h> |
||
217 | +#include <linux/slab.h> |
||
218 | +#include <linux/io.h> |
||
219 | +#include <linux/spinlock.h> |
||
220 | + |
||
221 | +#include "virt-dma.h" |
||
222 | + |
||
223 | +#define CACHE_LINE_MASK 31 |
||
224 | +#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */ |
||
225 | + |
||
226 | +/* valid only for channels 0 - 14, 15 has its own base address */ |
||
227 | +#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */ |
||
228 | +#define BCM2708_DMA_CHANIO(dma_base, n) \ |
||
229 | + ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n))) |
||
230 | + |
||
231 | +struct vc_dmaman { |
||
232 | + void __iomem *dma_base; |
||
233 | + u32 chan_available; /* bitmap of available channels */ |
||
234 | + u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */ |
||
235 | + struct mutex lock; |
||
236 | +}; |
||
237 | + |
||
238 | +static struct device *dmaman_dev; /* we assume there's only one! */ |
||
239 | +static struct vc_dmaman *g_dmaman; /* DMA manager */ |
||
240 | + |
||
241 | +/* DMA Auxiliary Functions */ |
||
242 | + |
||
243 | +/* A DMA buffer on an arbitrary boundary may separate a cache line into a |
||
244 | + section inside the DMA buffer and another section outside it. |
||
245 | + Even if we flush DMA buffers from the cache there is always the chance that |
||
246 | + during a DMA someone will access the part of a cache line that is outside |
||
247 | + the DMA buffer - which will then bring in unwelcome data. |
||
248 | + Without being able to dictate our own buffer pools we must insist that |
||
249 | + DMA buffers consist of a whole number of cache lines. |
||
250 | +*/ |
||
251 | +extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len) |
||
252 | +{ |
||
253 | + int i; |
||
254 | + |
||
255 | + for (i = 0; i < sg_len; i++) { |
||
256 | + if (sg_ptr[i].offset & CACHE_LINE_MASK || |
||
257 | + sg_ptr[i].length & CACHE_LINE_MASK) |
||
258 | + return 0; |
||
259 | + } |
||
260 | + |
||
261 | + return 1; |
||
262 | +} |
||
263 | +EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma); |
||
264 | + |
||
265 | +extern void bcm_dma_start(void __iomem *dma_chan_base, |
||
266 | + dma_addr_t control_block) |
||
267 | +{ |
||
268 | + dsb(sy); /* ARM data synchronization (push) operation */ |
||
269 | + |
||
270 | + writel(control_block, dma_chan_base + BCM2708_DMA_ADDR); |
||
271 | + writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS); |
||
272 | +} |
||
273 | +EXPORT_SYMBOL_GPL(bcm_dma_start); |
||
274 | + |
||
275 | +extern void bcm_dma_wait_idle(void __iomem *dma_chan_base) |
||
276 | +{ |
||
277 | + dsb(sy); |
||
278 | + |
||
279 | + /* ugly busy wait only option for now */ |
||
280 | + while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE) |
||
281 | + cpu_relax(); |
||
282 | +} |
||
283 | +EXPORT_SYMBOL_GPL(bcm_dma_wait_idle); |
||
284 | + |
||
285 | +extern bool bcm_dma_is_busy(void __iomem *dma_chan_base) |
||
286 | +{ |
||
287 | + dsb(sy); |
||
288 | + |
||
289 | + return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE; |
||
290 | +} |
||
291 | +EXPORT_SYMBOL_GPL(bcm_dma_is_busy); |
||
292 | + |
||
293 | +/* Complete an ongoing DMA (assuming its results are to be ignored) |
||
294 | + Does nothing if there is no DMA in progress. |
||
295 | + This routine waits for the current AXI transfer to complete before |
||
296 | + terminating the current DMA. If the current transfer is hung on a DREQ used |
||
297 | + by an uncooperative peripheral the AXI transfer may never complete. In this |
||
298 | + case the routine times out and return a non-zero error code. |
||
299 | + Use of this routine doesn't guarantee that the ongoing or aborted DMA |
||
300 | + does not produce an interrupt. |
||
301 | +*/ |
||
302 | +extern int bcm_dma_abort(void __iomem *dma_chan_base) |
||
303 | +{ |
||
304 | + unsigned long int cs; |
||
305 | + int rc = 0; |
||
306 | + |
||
307 | + cs = readl(dma_chan_base + BCM2708_DMA_CS); |
||
308 | + |
||
309 | + if (BCM2708_DMA_ACTIVE & cs) { |
||
310 | + long int timeout = 10000; |
||
311 | + |
||
312 | + /* write 0 to the active bit - pause the DMA */ |
||
313 | + writel(0, dma_chan_base + BCM2708_DMA_CS); |
||
314 | + |
||
315 | + /* wait for any current AXI transfer to complete */ |
||
316 | + while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0) |
||
317 | + cs = readl(dma_chan_base + BCM2708_DMA_CS); |
||
318 | + |
||
319 | + if (0 != (cs & BCM2708_DMA_ISPAUSED)) { |
||
320 | + /* we'll un-pause when we set of our next DMA */ |
||
321 | + rc = -ETIMEDOUT; |
||
322 | + |
||
323 | + } else if (BCM2708_DMA_ACTIVE & cs) { |
||
324 | + /* terminate the control block chain */ |
||
325 | + writel(0, dma_chan_base + BCM2708_DMA_NEXTCB); |
||
326 | + |
||
327 | + /* abort the whole DMA */ |
||
328 | + writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE, |
||
329 | + dma_chan_base + BCM2708_DMA_CS); |
||
330 | + } |
||
331 | + } |
||
332 | + |
||
333 | + return rc; |
||
334 | +} |
||
335 | +EXPORT_SYMBOL_GPL(bcm_dma_abort); |
||
336 | + |
||
337 | + /* DMA Manager Device Methods */ |
||
338 | + |
||
339 | +static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base, |
||
340 | + u32 chans_available) |
||
341 | +{ |
||
342 | + dmaman->dma_base = dma_base; |
||
343 | + dmaman->chan_available = chans_available; |
||
344 | + dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */ |
||
345 | + dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */ |
||
346 | + dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */ |
||
347 | + dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */ |
||
348 | +} |
||
349 | + |
||
350 | +static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman, |
||
351 | + unsigned required_feature_set) |
||
352 | +{ |
||
353 | + u32 chans; |
||
354 | + int chan = 0; |
||
355 | + int feature; |
||
356 | + |
||
357 | + chans = dmaman->chan_available; |
||
358 | + for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++) |
||
359 | + /* select the subset of available channels with the desired |
||
360 | + features */ |
||
361 | + if (required_feature_set & (1 << feature)) |
||
362 | + chans &= dmaman->has_feature[feature]; |
||
363 | + |
||
364 | + if (!chans) |
||
365 | + return -ENOENT; |
||
366 | + |
||
367 | + /* return the ordinal of the first channel in the bitmap */ |
||
368 | + while (chans != 0 && (chans & 1) == 0) { |
||
369 | + chans >>= 1; |
||
370 | + chan++; |
||
371 | + } |
||
372 | + /* claim the channel */ |
||
373 | + dmaman->chan_available &= ~(1 << chan); |
||
374 | + |
||
375 | + return chan; |
||
376 | +} |
||
377 | + |
||
378 | +static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan) |
||
379 | +{ |
||
380 | + if (chan < 0) |
||
381 | + return -EINVAL; |
||
382 | + |
||
383 | + if ((1 << chan) & dmaman->chan_available) |
||
384 | + return -EIDRM; |
||
385 | + |
||
386 | + dmaman->chan_available |= (1 << chan); |
||
387 | + |
||
388 | + return 0; |
||
389 | +} |
||
390 | + |
||
391 | +/* DMA Manager Monitor */ |
||
392 | + |
||
393 | +extern int bcm_dma_chan_alloc(unsigned required_feature_set, |
||
394 | + void __iomem **out_dma_base, int *out_dma_irq) |
||
395 | +{ |
||
396 | + struct vc_dmaman *dmaman = g_dmaman; |
||
397 | + struct platform_device *pdev = to_platform_device(dmaman_dev); |
||
398 | + struct resource *r; |
||
399 | + int chan; |
||
400 | + |
||
401 | + if (!dmaman_dev) |
||
402 | + return -ENODEV; |
||
403 | + |
||
404 | + mutex_lock(&dmaman->lock); |
||
405 | + chan = vc_dmaman_chan_alloc(dmaman, required_feature_set); |
||
406 | + if (chan < 0) |
||
407 | + goto out; |
||
408 | + |
||
409 | + r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan); |
||
410 | + if (!r) { |
||
411 | + dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n", |
||
412 | + chan); |
||
413 | + vc_dmaman_chan_free(dmaman, chan); |
||
414 | + chan = -ENOENT; |
||
415 | + goto out; |
||
416 | + } |
||
417 | + |
||
418 | + *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan); |
||
419 | + *out_dma_irq = r->start; |
||
420 | + dev_dbg(dmaman_dev, |
||
421 | + "Legacy API allocated channel=%d, base=%p, irq=%i\n", |
||
422 | + chan, *out_dma_base, *out_dma_irq); |
||
423 | + |
||
424 | +out: |
||
425 | + mutex_unlock(&dmaman->lock); |
||
426 | + |
||
427 | + return chan; |
||
428 | +} |
||
429 | +EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc); |
||
430 | + |
||
431 | +extern int bcm_dma_chan_free(int channel) |
||
432 | +{ |
||
433 | + struct vc_dmaman *dmaman = g_dmaman; |
||
434 | + int rc; |
||
435 | + |
||
436 | + if (!dmaman_dev) |
||
437 | + return -ENODEV; |
||
438 | + |
||
439 | + mutex_lock(&dmaman->lock); |
||
440 | + rc = vc_dmaman_chan_free(dmaman, channel); |
||
441 | + mutex_unlock(&dmaman->lock); |
||
442 | + |
||
443 | + return rc; |
||
444 | +} |
||
445 | +EXPORT_SYMBOL_GPL(bcm_dma_chan_free); |
||
446 | + |
||
447 | +int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base, |
||
448 | + u32 chans_available) |
||
449 | +{ |
||
450 | + struct device *dev = &pdev->dev; |
||
451 | + struct vc_dmaman *dmaman; |
||
452 | + |
||
453 | + dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL); |
||
454 | + if (!dmaman) |
||
455 | + return -ENOMEM; |
||
456 | + |
||
457 | + mutex_init(&dmaman->lock); |
||
458 | + vc_dmaman_init(dmaman, base, chans_available); |
||
459 | + g_dmaman = dmaman; |
||
460 | + dmaman_dev = dev; |
||
461 | + |
||
462 | + dev_info(dev, "DMA legacy API manager at %p, dmachans=0x%x\n", |
||
463 | + base, chans_available); |
||
464 | + |
||
465 | + return 0; |
||
466 | +} |
||
467 | +EXPORT_SYMBOL(bcm_dmaman_probe); |
||
468 | + |
||
469 | +int bcm_dmaman_remove(struct platform_device *pdev) |
||
470 | +{ |
||
471 | + dmaman_dev = NULL; |
||
472 | + |
||
473 | + return 0; |
||
474 | +} |
||
475 | +EXPORT_SYMBOL(bcm_dmaman_remove); |
||
476 | + |
||
477 | +MODULE_LICENSE("GPL"); |
||
478 | --- /dev/null |
||
479 | +++ b/include/linux/platform_data/dma-bcm2708.h |
||
480 | @@ -0,0 +1,143 @@ |
||
481 | +/* |
||
482 | + * Copyright (C) 2010 Broadcom |
||
483 | + * |
||
484 | + * This program is free software; you can redistribute it and/or modify |
||
485 | + * it under the terms of the GNU General Public License version 2 as |
||
486 | + * published by the Free Software Foundation. |
||
487 | + */ |
||
488 | + |
||
489 | +#ifndef _PLAT_BCM2708_DMA_H |
||
490 | +#define _PLAT_BCM2708_DMA_H |
||
491 | + |
||
492 | +/* DMA CS Control and Status bits */ |
||
493 | +#define BCM2708_DMA_ACTIVE BIT(0) |
||
494 | +#define BCM2708_DMA_INT BIT(2) |
||
495 | +#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ |
||
496 | +#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ |
||
497 | +#define BCM2708_DMA_ERR BIT(8) |
||
498 | +#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */ |
||
499 | +#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */ |
||
500 | + |
||
501 | +/* DMA control block "info" field bits */ |
||
502 | +#define BCM2708_DMA_INT_EN BIT(0) |
||
503 | +#define BCM2708_DMA_TDMODE BIT(1) |
||
504 | +#define BCM2708_DMA_WAIT_RESP BIT(3) |
||
505 | +#define BCM2708_DMA_D_INC BIT(4) |
||
506 | +#define BCM2708_DMA_D_WIDTH BIT(5) |
||
507 | +#define BCM2708_DMA_D_DREQ BIT(6) |
||
508 | +#define BCM2708_DMA_S_INC BIT(8) |
||
509 | +#define BCM2708_DMA_S_WIDTH BIT(9) |
||
510 | +#define BCM2708_DMA_S_DREQ BIT(10) |
||
511 | + |
||
512 | +#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12) |
||
513 | +#define BCM2708_DMA_PER_MAP(x) ((x) << 16) |
||
514 | +#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21) |
||
515 | + |
||
516 | +#define BCM2708_DMA_DREQ_EMMC 11 |
||
517 | +#define BCM2708_DMA_DREQ_SDHOST 13 |
||
518 | + |
||
519 | +#define BCM2708_DMA_CS 0x00 /* Control and Status */ |
||
520 | +#define BCM2708_DMA_ADDR 0x04 |
||
521 | +/* the current control block appears in the following registers - read only */ |
||
522 | +#define BCM2708_DMA_INFO 0x08 |
||
523 | +#define BCM2708_DMA_SOURCE_AD 0x0c |
||
524 | +#define BCM2708_DMA_DEST_AD 0x10 |
||
525 | +#define BCM2708_DMA_NEXTCB 0x1C |
||
526 | +#define BCM2708_DMA_DEBUG 0x20 |
||
527 | + |
||
528 | +#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS) |
||
529 | +#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR) |
||
530 | + |
||
531 | +#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) |
||
532 | + |
||
533 | +/* When listing features we can ask for when allocating DMA channels give |
||
534 | + those with higher priority smaller ordinal numbers */ |
||
535 | +#define BCM_DMA_FEATURE_FAST_ORD 0 |
||
536 | +#define BCM_DMA_FEATURE_BULK_ORD 1 |
||
537 | +#define BCM_DMA_FEATURE_NORMAL_ORD 2 |
||
538 | +#define BCM_DMA_FEATURE_LITE_ORD 3 |
||
539 | +#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD) |
||
540 | +#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD) |
||
541 | +#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD) |
||
542 | +#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD) |
||
543 | +#define BCM_DMA_FEATURE_COUNT 4 |
||
544 | + |
||
545 | +struct bcm2708_dma_cb { |
||
546 | + u32 info; |
||
547 | + u32 src; |
||
548 | + u32 dst; |
||
549 | + u32 length; |
||
550 | + u32 stride; |
||
551 | + u32 next; |
||
552 | + u32 pad[2]; |
||
553 | +}; |
||
554 | + |
||
555 | +struct scatterlist; |
||
556 | +struct platform_device; |
||
557 | + |
||
558 | +#ifdef CONFIG_DMA_BCM2708 |
||
559 | + |
||
560 | +int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); |
||
561 | +void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block); |
||
562 | +void bcm_dma_wait_idle(void __iomem *dma_chan_base); |
||
563 | +bool bcm_dma_is_busy(void __iomem *dma_chan_base); |
||
564 | +int bcm_dma_abort(void __iomem *dma_chan_base); |
||
565 | + |
||
566 | +/* return channel no or -ve error */ |
||
567 | +int bcm_dma_chan_alloc(unsigned preferred_feature_set, |
||
568 | + void __iomem **out_dma_base, int *out_dma_irq); |
||
569 | +int bcm_dma_chan_free(int channel); |
||
570 | + |
||
571 | +int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base, |
||
572 | + u32 chans_available); |
||
573 | +int bcm_dmaman_remove(struct platform_device *pdev); |
||
574 | + |
||
575 | +#else /* CONFIG_DMA_BCM2708 */ |
||
576 | + |
||
577 | +static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, |
||
578 | + int sg_len) |
||
579 | +{ |
||
580 | + return 0; |
||
581 | +} |
||
582 | + |
||
583 | +static inline void bcm_dma_start(void __iomem *dma_chan_base, |
||
584 | + dma_addr_t control_block) { } |
||
585 | + |
||
586 | +static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { } |
||
587 | + |
||
588 | +static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base) |
||
589 | +{ |
||
590 | + return false; |
||
591 | +} |
||
592 | + |
||
593 | +static inline int bcm_dma_abort(void __iomem *dma_chan_base) |
||
594 | +{ |
||
595 | + return -EINVAL; |
||
596 | +} |
||
597 | + |
||
598 | +static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set, |
||
599 | + void __iomem **out_dma_base, |
||
600 | + int *out_dma_irq) |
||
601 | +{ |
||
602 | + return -EINVAL; |
||
603 | +} |
||
604 | + |
||
605 | +static inline int bcm_dma_chan_free(int channel) |
||
606 | +{ |
||
607 | + return -EINVAL; |
||
608 | +} |
||
609 | + |
||
610 | +static inline int bcm_dmaman_probe(struct platform_device *pdev, |
||
611 | + void __iomem *base, u32 chans_available) |
||
612 | +{ |
||
613 | + return 0; |
||
614 | +} |
||
615 | + |
||
616 | +static inline int bcm_dmaman_remove(struct platform_device *pdev) |
||
617 | +{ |
||
618 | + return 0; |
||
619 | +} |
||
620 | + |
||
621 | +#endif /* CONFIG_DMA_BCM2708 */ |
||
622 | + |
||
623 | +#endif /* _PLAT_BCM2708_DMA_H */ |