]>
Commit | Line | Data |
---|---|---|
6d831c65 RM |
1 | /* |
2 | * arch/arm/mach-ep93xx/dma-m2p.c | |
3 | * M2P DMA handling for Cirrus EP93xx chips. | |
4 | * | |
5 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | |
6 | * Copyright (C) 2006 Applied Data Systems | |
7 | * | |
8 | * Copyright (C) 2009 Ryan Mallon <ryan@bluewatersys.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or (at | |
13 | * your option) any later version. | |
14 | */ | |
15 | ||
16 | /* | |
17 | * On the EP93xx chip the following peripherals my be allocated to the 10 | |
18 | * Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive). | |
19 | * | |
20 | * I2S contains 3 Tx and 3 Rx DMA Channels | |
21 | * AAC contains 3 Tx and 3 Rx DMA Channels | |
22 | * UART1 contains 1 Tx and 1 Rx DMA Channels | |
23 | * UART2 contains 1 Tx and 1 Rx DMA Channels | |
24 | * UART3 contains 1 Tx and 1 Rx DMA Channels | |
25 | * IrDA contains 1 Tx and 1 Rx DMA Channels | |
26 | * | |
27 | * SSP and IDE use the Memory to Memory (M2M) channels and are not covered | |
28 | * with this implementation. | |
29 | */ | |
30 | ||
31 | #include <linux/kernel.h> | |
32 | #include <linux/clk.h> | |
33 | #include <linux/err.h> | |
34 | #include <linux/interrupt.h> | |
35 | #include <linux/module.h> | |
a0b98ec8 | 36 | #include <linux/io.h> |
6d831c65 RM |
37 | |
38 | #include <mach/dma.h> | |
39 | #include <mach/hardware.h> | |
40 | ||
41 | #define M2P_CONTROL 0x00 | |
42 | #define M2P_CONTROL_STALL_IRQ_EN (1 << 0) | |
43 | #define M2P_CONTROL_NFB_IRQ_EN (1 << 1) | |
44 | #define M2P_CONTROL_ERROR_IRQ_EN (1 << 3) | |
45 | #define M2P_CONTROL_ENABLE (1 << 4) | |
46 | #define M2P_INTERRUPT 0x04 | |
47 | #define M2P_INTERRUPT_STALL (1 << 0) | |
48 | #define M2P_INTERRUPT_NFB (1 << 1) | |
49 | #define M2P_INTERRUPT_ERROR (1 << 3) | |
50 | #define M2P_PPALLOC 0x08 | |
51 | #define M2P_STATUS 0x0c | |
52 | #define M2P_REMAIN 0x14 | |
53 | #define M2P_MAXCNT0 0x20 | |
54 | #define M2P_BASE0 0x24 | |
55 | #define M2P_MAXCNT1 0x30 | |
56 | #define M2P_BASE1 0x34 | |
57 | ||
58 | #define STATE_IDLE 0 /* Channel is inactive. */ | |
59 | #define STATE_STALL 1 /* Channel is active, no buffers pending. */ | |
60 | #define STATE_ON 2 /* Channel is active, one buffer pending. */ | |
61 | #define STATE_NEXT 3 /* Channel is active, two buffers pending. */ | |
62 | ||
63 | struct m2p_channel { | |
64 | char *name; | |
65 | void __iomem *base; | |
66 | int irq; | |
67 | ||
68 | struct clk *clk; | |
69 | spinlock_t lock; | |
70 | ||
71 | void *client; | |
72 | unsigned next_slot:1; | |
73 | struct ep93xx_dma_buffer *buffer_xfer; | |
74 | struct ep93xx_dma_buffer *buffer_next; | |
75 | struct list_head buffers_pending; | |
76 | }; | |
77 | ||
78 | static struct m2p_channel m2p_rx[] = { | |
79 | {"m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1}, | |
80 | {"m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3}, | |
81 | {"m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5}, | |
82 | {"m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7}, | |
83 | {"m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9}, | |
84 | {NULL}, | |
85 | }; | |
86 | ||
87 | static struct m2p_channel m2p_tx[] = { | |
88 | {"m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0}, | |
89 | {"m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2}, | |
90 | {"m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4}, | |
91 | {"m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6}, | |
92 | {"m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8}, | |
93 | {NULL}, | |
94 | }; | |
95 | ||
96 | static void feed_buf(struct m2p_channel *ch, struct ep93xx_dma_buffer *buf) | |
97 | { | |
98 | if (ch->next_slot == 0) { | |
99 | writel(buf->size, ch->base + M2P_MAXCNT0); | |
100 | writel(buf->bus_addr, ch->base + M2P_BASE0); | |
101 | } else { | |
102 | writel(buf->size, ch->base + M2P_MAXCNT1); | |
103 | writel(buf->bus_addr, ch->base + M2P_BASE1); | |
104 | } | |
105 | ch->next_slot ^= 1; | |
106 | } | |
107 | ||
108 | static void choose_buffer_xfer(struct m2p_channel *ch) | |
109 | { | |
110 | struct ep93xx_dma_buffer *buf; | |
111 | ||
112 | ch->buffer_xfer = NULL; | |
113 | if (!list_empty(&ch->buffers_pending)) { | |
114 | buf = list_entry(ch->buffers_pending.next, | |
115 | struct ep93xx_dma_buffer, list); | |
116 | list_del(&buf->list); | |
117 | feed_buf(ch, buf); | |
118 | ch->buffer_xfer = buf; | |
119 | } | |
120 | } | |
121 | ||
122 | static void choose_buffer_next(struct m2p_channel *ch) | |
123 | { | |
124 | struct ep93xx_dma_buffer *buf; | |
125 | ||
126 | ch->buffer_next = NULL; | |
127 | if (!list_empty(&ch->buffers_pending)) { | |
128 | buf = list_entry(ch->buffers_pending.next, | |
129 | struct ep93xx_dma_buffer, list); | |
130 | list_del(&buf->list); | |
131 | feed_buf(ch, buf); | |
132 | ch->buffer_next = buf; | |
133 | } | |
134 | } | |
135 | ||
136 | static inline void m2p_set_control(struct m2p_channel *ch, u32 v) | |
137 | { | |
138 | /* | |
139 | * The control register must be read immediately after being written so | |
140 | * that the internal state machine is correctly updated. See the ep93xx | |
141 | * users' guide for details. | |
142 | */ | |
143 | writel(v, ch->base + M2P_CONTROL); | |
144 | readl(ch->base + M2P_CONTROL); | |
145 | } | |
146 | ||
147 | static inline int m2p_channel_state(struct m2p_channel *ch) | |
148 | { | |
149 | return (readl(ch->base + M2P_STATUS) >> 4) & 0x3; | |
150 | } | |
151 | ||
152 | static irqreturn_t m2p_irq(int irq, void *dev_id) | |
153 | { | |
154 | struct m2p_channel *ch = dev_id; | |
155 | struct ep93xx_dma_m2p_client *cl; | |
156 | u32 irq_status, v; | |
157 | int error = 0; | |
158 | ||
159 | cl = ch->client; | |
160 | ||
161 | spin_lock(&ch->lock); | |
162 | irq_status = readl(ch->base + M2P_INTERRUPT); | |
163 | ||
164 | if (irq_status & M2P_INTERRUPT_ERROR) { | |
165 | writel(M2P_INTERRUPT_ERROR, ch->base + M2P_INTERRUPT); | |
166 | error = 1; | |
167 | } | |
168 | ||
169 | if ((irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)) == 0) { | |
170 | spin_unlock(&ch->lock); | |
171 | return IRQ_NONE; | |
172 | } | |
173 | ||
174 | switch (m2p_channel_state(ch)) { | |
175 | case STATE_IDLE: | |
176 | pr_crit("m2p_irq: dma interrupt without a dma buffer\n"); | |
177 | BUG(); | |
178 | break; | |
179 | ||
180 | case STATE_STALL: | |
181 | cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error); | |
182 | if (ch->buffer_next != NULL) { | |
183 | cl->buffer_finished(cl->cookie, ch->buffer_next, | |
184 | 0, error); | |
185 | } | |
186 | choose_buffer_xfer(ch); | |
187 | choose_buffer_next(ch); | |
188 | if (ch->buffer_xfer != NULL) | |
189 | cl->buffer_started(cl->cookie, ch->buffer_xfer); | |
190 | break; | |
191 | ||
192 | case STATE_ON: | |
193 | cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error); | |
194 | ch->buffer_xfer = ch->buffer_next; | |
195 | choose_buffer_next(ch); | |
196 | cl->buffer_started(cl->cookie, ch->buffer_xfer); | |
197 | break; | |
198 | ||
199 | case STATE_NEXT: | |
200 | pr_crit("m2p_irq: dma interrupt while next\n"); | |
201 | BUG(); | |
202 | break; | |
203 | } | |
204 | ||
205 | v = readl(ch->base + M2P_CONTROL) & ~(M2P_CONTROL_STALL_IRQ_EN | | |
206 | M2P_CONTROL_NFB_IRQ_EN); | |
207 | if (ch->buffer_xfer != NULL) | |
208 | v |= M2P_CONTROL_STALL_IRQ_EN; | |
209 | if (ch->buffer_next != NULL) | |
210 | v |= M2P_CONTROL_NFB_IRQ_EN; | |
211 | m2p_set_control(ch, v); | |
212 | ||
213 | spin_unlock(&ch->lock); | |
214 | return IRQ_HANDLED; | |
215 | } | |
216 | ||
217 | static struct m2p_channel *find_free_channel(struct ep93xx_dma_m2p_client *cl) | |
218 | { | |
219 | struct m2p_channel *ch; | |
220 | int i; | |
221 | ||
222 | if (cl->flags & EP93XX_DMA_M2P_RX) | |
223 | ch = m2p_rx; | |
224 | else | |
225 | ch = m2p_tx; | |
226 | ||
227 | for (i = 0; ch[i].base; i++) { | |
228 | struct ep93xx_dma_m2p_client *client; | |
229 | ||
230 | client = ch[i].client; | |
231 | if (client != NULL) { | |
232 | int port; | |
233 | ||
234 | port = cl->flags & EP93XX_DMA_M2P_PORT_MASK; | |
235 | if (port == (client->flags & | |
236 | EP93XX_DMA_M2P_PORT_MASK)) { | |
237 | pr_warning("DMA channel already used by %s\n", | |
238 | cl->name ? : "unknown client"); | |
239 | return ERR_PTR(-EBUSY); | |
240 | } | |
241 | } | |
242 | } | |
243 | ||
244 | for (i = 0; ch[i].base; i++) { | |
245 | if (ch[i].client == NULL) | |
246 | return ch + i; | |
247 | } | |
248 | ||
249 | pr_warning("No free DMA channel for %s\n", | |
250 | cl->name ? : "unknown client"); | |
251 | return ERR_PTR(-ENODEV); | |
252 | } | |
253 | ||
254 | static void channel_enable(struct m2p_channel *ch) | |
255 | { | |
256 | struct ep93xx_dma_m2p_client *cl = ch->client; | |
257 | u32 v; | |
258 | ||
259 | clk_enable(ch->clk); | |
260 | ||
261 | v = cl->flags & EP93XX_DMA_M2P_PORT_MASK; | |
262 | writel(v, ch->base + M2P_PPALLOC); | |
263 | ||
264 | v = cl->flags & EP93XX_DMA_M2P_ERROR_MASK; | |
265 | v |= M2P_CONTROL_ENABLE | M2P_CONTROL_ERROR_IRQ_EN; | |
266 | m2p_set_control(ch, v); | |
267 | } | |
268 | ||
269 | static void channel_disable(struct m2p_channel *ch) | |
270 | { | |
271 | u32 v; | |
272 | ||
273 | v = readl(ch->base + M2P_CONTROL); | |
274 | v &= ~(M2P_CONTROL_STALL_IRQ_EN | M2P_CONTROL_NFB_IRQ_EN); | |
275 | m2p_set_control(ch, v); | |
276 | ||
277 | while (m2p_channel_state(ch) == STATE_ON) | |
278 | cpu_relax(); | |
279 | ||
280 | m2p_set_control(ch, 0x0); | |
281 | ||
282 | while (m2p_channel_state(ch) == STATE_STALL) | |
283 | cpu_relax(); | |
284 | ||
285 | clk_disable(ch->clk); | |
286 | } | |
287 | ||
288 | int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *cl) | |
289 | { | |
290 | struct m2p_channel *ch; | |
291 | int err; | |
292 | ||
293 | ch = find_free_channel(cl); | |
294 | if (IS_ERR(ch)) | |
295 | return PTR_ERR(ch); | |
296 | ||
297 | err = request_irq(ch->irq, m2p_irq, 0, cl->name ? : "dma-m2p", ch); | |
298 | if (err) | |
299 | return err; | |
300 | ||
301 | ch->client = cl; | |
302 | ch->next_slot = 0; | |
303 | ch->buffer_xfer = NULL; | |
304 | ch->buffer_next = NULL; | |
305 | INIT_LIST_HEAD(&ch->buffers_pending); | |
306 | ||
307 | cl->channel = ch; | |
308 | ||
309 | channel_enable(ch); | |
310 | ||
311 | return 0; | |
312 | } | |
313 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_register); | |
314 | ||
315 | void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *cl) | |
316 | { | |
317 | struct m2p_channel *ch = cl->channel; | |
318 | ||
319 | channel_disable(ch); | |
320 | free_irq(ch->irq, ch); | |
321 | ch->client = NULL; | |
322 | } | |
323 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_unregister); | |
324 | ||
325 | void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *cl, | |
326 | struct ep93xx_dma_buffer *buf) | |
327 | { | |
328 | struct m2p_channel *ch = cl->channel; | |
329 | unsigned long flags; | |
330 | u32 v; | |
331 | ||
332 | spin_lock_irqsave(&ch->lock, flags); | |
333 | v = readl(ch->base + M2P_CONTROL); | |
334 | if (ch->buffer_xfer == NULL) { | |
335 | ch->buffer_xfer = buf; | |
336 | feed_buf(ch, buf); | |
337 | cl->buffer_started(cl->cookie, buf); | |
338 | ||
339 | v |= M2P_CONTROL_STALL_IRQ_EN; | |
340 | m2p_set_control(ch, v); | |
341 | ||
342 | } else if (ch->buffer_next == NULL) { | |
343 | ch->buffer_next = buf; | |
344 | feed_buf(ch, buf); | |
345 | ||
346 | v |= M2P_CONTROL_NFB_IRQ_EN; | |
347 | m2p_set_control(ch, v); | |
348 | } else { | |
349 | list_add_tail(&buf->list, &ch->buffers_pending); | |
350 | } | |
351 | spin_unlock_irqrestore(&ch->lock, flags); | |
352 | } | |
353 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit); | |
354 | ||
355 | void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *cl, | |
356 | struct ep93xx_dma_buffer *buf) | |
357 | { | |
358 | struct m2p_channel *ch = cl->channel; | |
359 | ||
360 | list_add_tail(&buf->list, &ch->buffers_pending); | |
361 | } | |
362 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit_recursive); | |
363 | ||
364 | void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *cl) | |
365 | { | |
366 | struct m2p_channel *ch = cl->channel; | |
367 | ||
368 | channel_disable(ch); | |
369 | ch->next_slot = 0; | |
370 | ch->buffer_xfer = NULL; | |
371 | ch->buffer_next = NULL; | |
372 | INIT_LIST_HEAD(&ch->buffers_pending); | |
373 | channel_enable(ch); | |
374 | } | |
375 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_flush); | |
376 | ||
377 | static int init_channel(struct m2p_channel *ch) | |
378 | { | |
379 | ch->clk = clk_get(NULL, ch->name); | |
380 | if (IS_ERR(ch->clk)) | |
381 | return PTR_ERR(ch->clk); | |
382 | ||
383 | spin_lock_init(&ch->lock); | |
384 | ch->client = NULL; | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | static int __init ep93xx_dma_m2p_init(void) | |
390 | { | |
391 | int i; | |
392 | int ret; | |
393 | ||
394 | for (i = 0; m2p_rx[i].base; i++) { | |
395 | ret = init_channel(m2p_rx + i); | |
396 | if (ret) | |
397 | return ret; | |
398 | } | |
399 | ||
400 | for (i = 0; m2p_tx[i].base; i++) { | |
401 | ret = init_channel(m2p_tx + i); | |
402 | if (ret) | |
403 | return ret; | |
404 | } | |
405 | ||
406 | pr_info("M2P DMA subsystem initialized\n"); | |
407 | return 0; | |
408 | } | |
409 | arch_initcall(ep93xx_dma_m2p_init); |