diff options
author | G, Manjunath Kondaiah <manjugk@ti.com> | 2010-12-20 21:27:19 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-12-20 21:38:31 -0500 |
commit | f31cc9622d75c1c6f041d786698daa425c0425c2 (patch) | |
tree | 4e52cc4a4d5a6c478823150d263cecbb08271f7b /arch/arm/mach-omap2/dma.c | |
parent | 59de3cf1ce9a961ba9ab657707727db2111e72fa (diff) |
OMAP: DMA: Convert DMA library into platform driver
Convert DMA library into DMA platform driver and make use of
platform data provided by hwmod data base for OMAP2+ onwards.
For OMAP1 processors, the DMA driver in mach-omap uses resource
structures for getting platform data.
Thanks to Tony Lindgren <tony@atomide.com> for fixing various
omap1 issues and testing the same on OSK5912 board.
Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
Tested-by: Kevin Hilman <khilman@deeprootsystems.com>
Acked-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/dma.c')
-rw-r--r-- | arch/arm/mach-omap2/dma.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index 2130059e98cb..d2f15f5cfd36 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c | |||
@@ -32,6 +32,61 @@ | |||
32 | #include <plat/omap_device.h> | 32 | #include <plat/omap_device.h> |
33 | #include <plat/dma.h> | 33 | #include <plat/dma.h> |
34 | 34 | ||
35 | #define OMAP2_DMA_STRIDE 0x60 | ||
36 | |||
37 | static u32 errata; | ||
38 | static u8 dma_stride; | ||
39 | |||
40 | static struct omap_dma_dev_attr *d; | ||
41 | |||
42 | static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end; | ||
43 | |||
44 | static u16 reg_map[] = { | ||
45 | [REVISION] = 0x00, | ||
46 | [GCR] = 0x78, | ||
47 | [IRQSTATUS_L0] = 0x08, | ||
48 | [IRQSTATUS_L1] = 0x0c, | ||
49 | [IRQSTATUS_L2] = 0x10, | ||
50 | [IRQSTATUS_L3] = 0x14, | ||
51 | [IRQENABLE_L0] = 0x18, | ||
52 | [IRQENABLE_L1] = 0x1c, | ||
53 | [IRQENABLE_L2] = 0x20, | ||
54 | [IRQENABLE_L3] = 0x24, | ||
55 | [SYSSTATUS] = 0x28, | ||
56 | [OCP_SYSCONFIG] = 0x2c, | ||
57 | [CAPS_0] = 0x64, | ||
58 | [CAPS_2] = 0x6c, | ||
59 | [CAPS_3] = 0x70, | ||
60 | [CAPS_4] = 0x74, | ||
61 | |||
62 | /* Common register offsets */ | ||
63 | [CCR] = 0x80, | ||
64 | [CLNK_CTRL] = 0x84, | ||
65 | [CICR] = 0x88, | ||
66 | [CSR] = 0x8c, | ||
67 | [CSDP] = 0x90, | ||
68 | [CEN] = 0x94, | ||
69 | [CFN] = 0x98, | ||
70 | [CSEI] = 0xa4, | ||
71 | [CSFI] = 0xa8, | ||
72 | [CDEI] = 0xac, | ||
73 | [CDFI] = 0xb0, | ||
74 | [CSAC] = 0xb4, | ||
75 | [CDAC] = 0xb8, | ||
76 | |||
77 | /* Channel specific register offsets */ | ||
78 | [CSSA] = 0x9c, | ||
79 | [CDSA] = 0xa0, | ||
80 | [CCEN] = 0xbc, | ||
81 | [CCFN] = 0xc0, | ||
82 | [COLOR] = 0xc4, | ||
83 | |||
84 | /* OMAP4 specific registers */ | ||
85 | [CDP] = 0xd0, | ||
86 | [CNDP] = 0xd4, | ||
87 | [CCDN] = 0xd8, | ||
88 | }; | ||
89 | |||
35 | static struct omap_device_pm_latency omap2_dma_latency[] = { | 90 | static struct omap_device_pm_latency omap2_dma_latency[] = { |
36 | { | 91 | { |
37 | .deactivate_func = omap_device_idle_hwmods, | 92 | .deactivate_func = omap_device_idle_hwmods, |
@@ -40,13 +95,151 @@ static struct omap_device_pm_latency omap2_dma_latency[] = { | |||
40 | }, | 95 | }, |
41 | }; | 96 | }; |
42 | 97 | ||
98 | static void __iomem *dma_base; | ||
99 | static inline void dma_write(u32 val, int reg, int lch) | ||
100 | { | ||
101 | u8 stride; | ||
102 | u32 offset; | ||
103 | |||
104 | stride = (reg >= dma_common_ch_start) ? dma_stride : 0; | ||
105 | offset = reg_map[reg] + (stride * lch); | ||
106 | __raw_writel(val, dma_base + offset); | ||
107 | } | ||
108 | |||
109 | static inline u32 dma_read(int reg, int lch) | ||
110 | { | ||
111 | u8 stride; | ||
112 | u32 offset, val; | ||
113 | |||
114 | stride = (reg >= dma_common_ch_start) ? dma_stride : 0; | ||
115 | offset = reg_map[reg] + (stride * lch); | ||
116 | val = __raw_readl(dma_base + offset); | ||
117 | return val; | ||
118 | } | ||
119 | |||
120 | static inline void omap2_disable_irq_lch(int lch) | ||
121 | { | ||
122 | u32 val; | ||
123 | |||
124 | val = dma_read(IRQENABLE_L0, lch); | ||
125 | val &= ~(1 << lch); | ||
126 | dma_write(val, IRQENABLE_L0, lch); | ||
127 | } | ||
128 | |||
129 | static void omap2_clear_dma(int lch) | ||
130 | { | ||
131 | int i = dma_common_ch_start; | ||
132 | |||
133 | for (; i <= dma_common_ch_end; i += 1) | ||
134 | dma_write(0, i, lch); | ||
135 | } | ||
136 | |||
137 | static void omap2_show_dma_caps(void) | ||
138 | { | ||
139 | u8 revision = dma_read(REVISION, 0) & 0xff; | ||
140 | printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n", | ||
141 | revision >> 4, revision & 0xf); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | static u32 configure_dma_errata(void) | ||
146 | { | ||
147 | |||
148 | /* | ||
149 | * Errata applicable for OMAP2430ES1.0 and all omap2420 | ||
150 | * | ||
151 | * I. | ||
152 | * Erratum ID: Not Available | ||
153 | * Inter Frame DMA buffering issue DMA will wrongly | ||
154 | * buffer elements if packing and bursting is enabled. This might | ||
155 | * result in data gets stalled in FIFO at the end of the block. | ||
156 | * Workaround: DMA channels must have BUFFERING_DISABLED bit set to | ||
157 | * guarantee no data will stay in the DMA FIFO in case inter frame | ||
158 | * buffering occurs | ||
159 | * | ||
160 | * II. | ||
161 | * Erratum ID: Not Available | ||
162 | * DMA may hang when several channels are used in parallel | ||
163 | * In the following configuration, DMA channel hanging can occur: | ||
164 | * a. Channel i, hardware synchronized, is enabled | ||
165 | * b. Another channel (Channel x), software synchronized, is enabled. | ||
166 | * c. Channel i is disabled before end of transfer | ||
167 | * d. Channel i is reenabled. | ||
168 | * e. Steps 1 to 4 are repeated a certain number of times. | ||
169 | * f. A third channel (Channel y), software synchronized, is enabled. | ||
170 | * Channel x and Channel y may hang immediately after step 'f'. | ||
171 | * Workaround: | ||
172 | * For any channel used - make sure NextLCH_ID is set to the value j. | ||
173 | */ | ||
174 | if (cpu_is_omap2420() || (cpu_is_omap2430() && | ||
175 | (omap_type() == OMAP2430_REV_ES1_0))) { | ||
176 | |||
177 | SET_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING); | ||
178 | SET_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Erratum ID: i378: OMAP2+: sDMA Channel is not disabled | ||
183 | * after a transaction error. | ||
184 | * Workaround: SW should explicitely disable the channel. | ||
185 | */ | ||
186 | if (cpu_class_is_omap2()) | ||
187 | SET_DMA_ERRATA(DMA_ERRATA_i378); | ||
188 | |||
189 | /* | ||
190 | * Erratum ID: i541: sDMA FIFO draining does not finish | ||
191 | * If sDMA channel is disabled on the fly, sDMA enters standby even | ||
192 | * through FIFO Drain is still in progress | ||
193 | * Workaround: Put sDMA in NoStandby more before a logical channel is | ||
194 | * disabled, then put it back to SmartStandby right after the channel | ||
195 | * finishes FIFO draining. | ||
196 | */ | ||
197 | if (cpu_is_omap34xx()) | ||
198 | SET_DMA_ERRATA(DMA_ERRATA_i541); | ||
199 | |||
200 | /* | ||
201 | * Erratum ID: i88 : Special programming model needed to disable DMA | ||
202 | * before end of block. | ||
203 | * Workaround: software must ensure that the DMA is configured in No | ||
204 | * Standby mode(DMAx_OCP_SYSCONFIG.MIDLEMODE = "01") | ||
205 | */ | ||
206 | if (omap_type() == OMAP3430_REV_ES1_0) | ||
207 | SET_DMA_ERRATA(DMA_ERRATA_i88); | ||
208 | |||
209 | /* | ||
210 | * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is | ||
211 | * read before the DMA controller finished disabling the channel. | ||
212 | */ | ||
213 | SET_DMA_ERRATA(DMA_ERRATA_3_3); | ||
214 | |||
215 | /* | ||
216 | * Erratum ID: Not Available | ||
217 | * A bug in ROM code leaves IRQ status for channels 0 and 1 uncleared | ||
218 | * after secure sram context save and restore. | ||
219 | * Work around: Hence we need to manually clear those IRQs to avoid | ||
220 | * spurious interrupts. This affects only secure devices. | ||
221 | */ | ||
222 | if (cpu_is_omap34xx() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) | ||
223 | SET_DMA_ERRATA(DMA_ROMCODE_BUG); | ||
224 | |||
225 | return errata; | ||
226 | } | ||
227 | |||
43 | /* One time initializations */ | 228 | /* One time initializations */ |
44 | static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) | 229 | static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) |
45 | { | 230 | { |
46 | struct omap_device *od; | 231 | struct omap_device *od; |
47 | struct omap_system_dma_plat_info *p; | 232 | struct omap_system_dma_plat_info *p; |
233 | struct resource *mem; | ||
48 | char *name = "omap_dma_system"; | 234 | char *name = "omap_dma_system"; |
49 | 235 | ||
236 | dma_stride = OMAP2_DMA_STRIDE; | ||
237 | dma_common_ch_start = CSDP; | ||
238 | if (cpu_is_omap3630() || cpu_is_omap4430()) | ||
239 | dma_common_ch_end = CCDN; | ||
240 | else | ||
241 | dma_common_ch_end = CCFN; | ||
242 | |||
50 | p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); | 243 | p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); |
51 | if (!p) { | 244 | if (!p) { |
52 | pr_err("%s: Unable to allocate pdata for %s:%s\n", | 245 | pr_err("%s: Unable to allocate pdata for %s:%s\n", |
@@ -54,6 +247,17 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) | |||
54 | return -ENOMEM; | 247 | return -ENOMEM; |
55 | } | 248 | } |
56 | 249 | ||
250 | p->dma_attr = (struct omap_dma_dev_attr *)oh->dev_attr; | ||
251 | p->disable_irq_lch = omap2_disable_irq_lch; | ||
252 | p->show_dma_caps = omap2_show_dma_caps; | ||
253 | p->clear_dma = omap2_clear_dma; | ||
254 | p->dma_write = dma_write; | ||
255 | p->dma_read = dma_read; | ||
256 | |||
257 | p->clear_lch_regs = NULL; | ||
258 | |||
259 | p->errata = configure_dma_errata(); | ||
260 | |||
57 | od = omap_device_build(name, 0, oh, p, sizeof(*p), | 261 | od = omap_device_build(name, 0, oh, p, sizeof(*p), |
58 | omap2_dma_latency, ARRAY_SIZE(omap2_dma_latency), 0); | 262 | omap2_dma_latency, ARRAY_SIZE(omap2_dma_latency), 0); |
59 | kfree(p); | 263 | kfree(p); |
@@ -63,6 +267,25 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) | |||
63 | return IS_ERR(od); | 267 | return IS_ERR(od); |
64 | } | 268 | } |
65 | 269 | ||
270 | mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0); | ||
271 | if (!mem) { | ||
272 | dev_err(&od->pdev.dev, "%s: no mem resource\n", __func__); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | dma_base = ioremap(mem->start, resource_size(mem)); | ||
276 | if (!dma_base) { | ||
277 | dev_err(&od->pdev.dev, "%s: ioremap fail\n", __func__); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | |||
281 | d = oh->dev_attr; | ||
282 | d->chan = kzalloc(sizeof(struct omap_dma_lch) * | ||
283 | (d->lch_count), GFP_KERNEL); | ||
284 | |||
285 | if (!d->chan) { | ||
286 | dev_err(&od->pdev.dev, "%s: kzalloc fail\n", __func__); | ||
287 | return -ENOMEM; | ||
288 | } | ||
66 | return 0; | 289 | return 0; |
67 | } | 290 | } |
68 | 291 | ||