aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers/dma/dma-sh.c
diff options
context:
space:
mode:
authorNobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>2009-03-10 04:26:49 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-03-10 04:26:49 -0400
commit71b973a42c5456824c8712e00659d9616d395919 (patch)
tree1367c85de45159c66752a93fc062a6f67f616607 /arch/sh/drivers/dma/dma-sh.c
parentae68df5635a191c7edb75f5c1c1406353cb24a9f (diff)
sh: dma-sh updates for multi IRQ and new SH-4A CPUs.
This adds DMA support for newer SH-4A CPUs, particularly SH7763/64/80/85. This also enables multi IRQ support for platforms that have multiple vectors bound to the same IRQ source. Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com> Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers/dma/dma-sh.c')
-rw-r--r--arch/sh/drivers/dma/dma-sh.c172
1 files changed, 115 insertions, 57 deletions
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index 50887a592dd0..ab7b18dcbaba 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -17,28 +17,23 @@
17#include <mach-dreamcast/mach/dma.h> 17#include <mach-dreamcast/mach/dma.h>
18#include <asm/dma.h> 18#include <asm/dma.h>
19#include <asm/io.h> 19#include <asm/io.h>
20#include "dma-sh.h" 20#include <asm/dma-sh.h>
21 21
22static int dmte_irq_map[] = { 22#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
23 DMTE0_IRQ, 23 defined(CONFIG_CPU_SUBTYPE_SH7764) || \
24 DMTE1_IRQ, 24 defined(CONFIG_CPU_SUBTYPE_SH7780) || \
25 DMTE2_IRQ, 25 defined(CONFIG_CPU_SUBTYPE_SH7785)
26 DMTE3_IRQ, 26#define DMAC_IRQ_MULTI 1
27#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
28 defined(CONFIG_CPU_SUBTYPE_SH7721) || \
29 defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
30 defined(CONFIG_CPU_SUBTYPE_SH7760) || \
31 defined(CONFIG_CPU_SUBTYPE_SH7709) || \
32 defined(CONFIG_CPU_SUBTYPE_SH7780)
33 DMTE4_IRQ,
34 DMTE5_IRQ,
35#endif 27#endif
36#if defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ 28
37 defined(CONFIG_CPU_SUBTYPE_SH7760) || \ 29#if defined(DMAE1_IRQ)
38 defined(CONFIG_CPU_SUBTYPE_SH7780) 30#define NR_DMAE 2
39 DMTE6_IRQ, 31#else
40 DMTE7_IRQ, 32#define NR_DMAE 1
41#endif 33#endif
34
35static const char *dmae_name[] = {
36 "DMAC Address Error0", "DMAC Address Error1"
42}; 37};
43 38
44static inline unsigned int get_dmte_irq(unsigned int chan) 39static inline unsigned int get_dmte_irq(unsigned int chan)
@@ -46,7 +41,14 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
46 unsigned int irq = 0; 41 unsigned int irq = 0;
47 if (chan < ARRAY_SIZE(dmte_irq_map)) 42 if (chan < ARRAY_SIZE(dmte_irq_map))
48 irq = dmte_irq_map[chan]; 43 irq = dmte_irq_map[chan];
44
45#if defined(DMAC_IRQ_MULTI)
46 if (irq > DMTE6_IRQ)
47 return DMTE6_IRQ;
48 return DMTE0_IRQ;
49#else
49 return irq; 50 return irq;
51#endif
50} 52}
51 53
52/* 54/*
@@ -59,7 +61,7 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
59 */ 61 */
60static inline unsigned int calc_xmit_shift(struct dma_channel *chan) 62static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
61{ 63{
62 u32 chcr = ctrl_inl(CHCR[chan->chan]); 64 u32 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
63 65
64 return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT]; 66 return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT];
65} 67}
@@ -75,13 +77,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id)
75 struct dma_channel *chan = dev_id; 77 struct dma_channel *chan = dev_id;
76 u32 chcr; 78 u32 chcr;
77 79
78 chcr = ctrl_inl(CHCR[chan->chan]); 80 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
79 81
80 if (!(chcr & CHCR_TE)) 82 if (!(chcr & CHCR_TE))
81 return IRQ_NONE; 83 return IRQ_NONE;
82 84
83 chcr &= ~(CHCR_IE | CHCR_DE); 85 chcr &= ~(CHCR_IE | CHCR_DE);
84 ctrl_outl(chcr, CHCR[chan->chan]); 86 ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
85 87
86 wake_up(&chan->wait_queue); 88 wake_up(&chan->wait_queue);
87 89
@@ -94,7 +96,12 @@ static int sh_dmac_request_dma(struct dma_channel *chan)
94 return 0; 96 return 0;
95 97
96 return request_irq(get_dmte_irq(chan->chan), dma_tei, 98 return request_irq(get_dmte_irq(chan->chan), dma_tei,
97 IRQF_DISABLED, chan->dev_id, chan); 99#if defined(DMAC_IRQ_MULTI)
100 IRQF_SHARED,
101#else
102 IRQF_DISABLED,
103#endif
104 chan->dev_id, chan);
98} 105}
99 106
100static void sh_dmac_free_dma(struct dma_channel *chan) 107static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -115,7 +122,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
115 chan->flags &= ~DMA_TEI_CAPABLE; 122 chan->flags &= ~DMA_TEI_CAPABLE;
116 } 123 }
117 124
118 ctrl_outl(chcr, CHCR[chan->chan]); 125 ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
119 126
120 chan->flags |= DMA_CONFIGURED; 127 chan->flags |= DMA_CONFIGURED;
121 return 0; 128 return 0;
@@ -126,13 +133,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan)
126 int irq; 133 int irq;
127 u32 chcr; 134 u32 chcr;
128 135
129 chcr = ctrl_inl(CHCR[chan->chan]); 136 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
130 chcr |= CHCR_DE; 137 chcr |= CHCR_DE;
131 138
132 if (chan->flags & DMA_TEI_CAPABLE) 139 if (chan->flags & DMA_TEI_CAPABLE)
133 chcr |= CHCR_IE; 140 chcr |= CHCR_IE;
134 141
135 ctrl_outl(chcr, CHCR[chan->chan]); 142 ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
136 143
137 if (chan->flags & DMA_TEI_CAPABLE) { 144 if (chan->flags & DMA_TEI_CAPABLE) {
138 irq = get_dmte_irq(chan->chan); 145 irq = get_dmte_irq(chan->chan);
@@ -150,9 +157,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan)
150 disable_irq(irq); 157 disable_irq(irq);
151 } 158 }
152 159
153 chcr = ctrl_inl(CHCR[chan->chan]); 160 chcr = ctrl_inl(dma_base_addr[chan->chan] + CHCR);
154 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); 161 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
155 ctrl_outl(chcr, CHCR[chan->chan]); 162 ctrl_outl(chcr, (dma_base_addr[chan->chan] + CHCR));
156} 163}
157 164
158static int sh_dmac_xfer_dma(struct dma_channel *chan) 165static int sh_dmac_xfer_dma(struct dma_channel *chan)
@@ -183,12 +190,13 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
183 */ 190 */
184 if (chan->sar || (mach_is_dreamcast() && 191 if (chan->sar || (mach_is_dreamcast() &&
185 chan->chan == PVR2_CASCADE_CHAN)) 192 chan->chan == PVR2_CASCADE_CHAN))
186 ctrl_outl(chan->sar, SAR[chan->chan]); 193 ctrl_outl(chan->sar, (dma_base_addr[chan->chan]+SAR));
187 if (chan->dar || (mach_is_dreamcast() && 194 if (chan->dar || (mach_is_dreamcast() &&
188 chan->chan == PVR2_CASCADE_CHAN)) 195 chan->chan == PVR2_CASCADE_CHAN))
189 ctrl_outl(chan->dar, DAR[chan->chan]); 196 ctrl_outl(chan->dar, (dma_base_addr[chan->chan] + DAR));
190 197
191 ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]); 198 ctrl_outl(chan->count >> calc_xmit_shift(chan),
199 (dma_base_addr[chan->chan] + TCR));
192 200
193 sh_dmac_enable_dma(chan); 201 sh_dmac_enable_dma(chan);
194 202
@@ -197,36 +205,26 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
197 205
198static int sh_dmac_get_dma_residue(struct dma_channel *chan) 206static int sh_dmac_get_dma_residue(struct dma_channel *chan)
199{ 207{
200 if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE)) 208 if (!(ctrl_inl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE))
201 return 0; 209 return 0;
202 210
203 return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); 211 return ctrl_inl(dma_base_addr[chan->chan] + TCR)
212 << calc_xmit_shift(chan);
204} 213}
205 214
206#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \ 215static inline int dmaor_reset(int no)
207 defined(CONFIG_CPU_SUBTYPE_SH7721) || \
208 defined(CONFIG_CPU_SUBTYPE_SH7780) || \
209 defined(CONFIG_CPU_SUBTYPE_SH7709)
210#define dmaor_read_reg() ctrl_inw(DMAOR)
211#define dmaor_write_reg(data) ctrl_outw(data, DMAOR)
212#else
213#define dmaor_read_reg() ctrl_inl(DMAOR)
214#define dmaor_write_reg(data) ctrl_outl(data, DMAOR)
215#endif
216
217static inline int dmaor_reset(void)
218{ 216{
219 unsigned long dmaor = dmaor_read_reg(); 217 unsigned long dmaor = dmaor_read_reg(no);
220 218
221 /* Try to clear the error flags first, incase they are set */ 219 /* Try to clear the error flags first, incase they are set */
222 dmaor &= ~(DMAOR_NMIF | DMAOR_AE); 220 dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
223 dmaor_write_reg(dmaor); 221 dmaor_write_reg(no, dmaor);
224 222
225 dmaor |= DMAOR_INIT; 223 dmaor |= DMAOR_INIT;
226 dmaor_write_reg(dmaor); 224 dmaor_write_reg(no, dmaor);
227 225
228 /* See if we got an error again */ 226 /* See if we got an error again */
229 if ((dmaor_read_reg() & (DMAOR_AE | DMAOR_NMIF))) { 227 if ((dmaor_read_reg(no) & (DMAOR_AE | DMAOR_NMIF))) {
230 printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n"); 228 printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n");
231 return -EINVAL; 229 return -EINVAL;
232 } 230 }
@@ -237,10 +235,33 @@ static inline int dmaor_reset(void)
237#if defined(CONFIG_CPU_SH4) 235#if defined(CONFIG_CPU_SH4)
238static irqreturn_t dma_err(int irq, void *dummy) 236static irqreturn_t dma_err(int irq, void *dummy)
239{ 237{
240 dmaor_reset(); 238#if defined(DMAC_IRQ_MULTI)
239 int cnt = 0;
240 switch (irq) {
241#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
242 case DMTE6_IRQ:
243 cnt++;
244#endif
245 case DMTE0_IRQ:
246 if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
247 disable_irq(irq);
248 /* DMA multi and error IRQ */
249 return IRQ_HANDLED;
250 }
251 default:
252 return IRQ_NONE;
253 }
254#else
255 dmaor_reset(0);
256#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
257 defined(CONFIG_CPU_SUBTYPE_SH7780) || \
258 defined(CONFIG_CPU_SUBTYPE_SH7785)
259 dmaor_reset(1);
260#endif
241 disable_irq(irq); 261 disable_irq(irq);
242 262
243 return IRQ_HANDLED; 263 return IRQ_HANDLED;
264#endif
244} 265}
245#endif 266#endif
246 267
@@ -259,24 +280,57 @@ static struct dma_info sh_dmac_info = {
259 .flags = DMAC_CHANNELS_TEI_CAPABLE, 280 .flags = DMAC_CHANNELS_TEI_CAPABLE,
260}; 281};
261 282
283static unsigned int get_dma_error_irq(int n)
284{
285#if defined(DMAC_IRQ_MULTI)
286 return (n == 0) ? get_dmte_irq(0) : get_dmte_irq(6);
287#else
288 return (n == 0) ? DMAE0_IRQ :
289#if defined(DMAE1_IRQ)
290 DMAE1_IRQ;
291#else
292 -1;
293#endif
294#endif
295}
296
262static int __init sh_dmac_init(void) 297static int __init sh_dmac_init(void)
263{ 298{
264 struct dma_info *info = &sh_dmac_info; 299 struct dma_info *info = &sh_dmac_info;
265 int i; 300 int i;
266 301
267#ifdef CONFIG_CPU_SH4 302#ifdef CONFIG_CPU_SH4
268 i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0); 303 int n;
269 if (unlikely(i < 0)) 304
270 return i; 305 for (n = 0; n < NR_DMAE; n++) {
306 i = request_irq(get_dma_error_irq(n), dma_err,
307#if defined(DMAC_IRQ_MULTI)
308 IRQF_SHARED,
309#else
310 IRQF_DISABLED,
271#endif 311#endif
312 dmae_name[n], (void *)dmae_name[n]);
313 if (unlikely(i < 0)) {
314 printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
315 return i;
316 }
317 }
318#endif /* CONFIG_CPU_SH4 */
272 319
273 /* 320 /*
274 * Initialize DMAOR, and clean up any error flags that may have 321 * Initialize DMAOR, and clean up any error flags that may have
275 * been set. 322 * been set.
276 */ 323 */
277 i = dmaor_reset(); 324 i = dmaor_reset(0);
325 if (unlikely(i != 0))
326 return i;
327#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
328 defined(CONFIG_CPU_SUBTYPE_SH7780) || \
329 defined(CONFIG_CPU_SUBTYPE_SH7785)
330 i = dmaor_reset(1);
278 if (unlikely(i != 0)) 331 if (unlikely(i != 0))
279 return i; 332 return i;
333#endif
280 334
281 return register_dmac(info); 335 return register_dmac(info);
282} 336}
@@ -284,8 +338,12 @@ static int __init sh_dmac_init(void)
284static void __exit sh_dmac_exit(void) 338static void __exit sh_dmac_exit(void)
285{ 339{
286#ifdef CONFIG_CPU_SH4 340#ifdef CONFIG_CPU_SH4
287 free_irq(DMAE_IRQ, 0); 341 int n;
288#endif 342
343 for (n = 0; n < NR_DMAE; n++) {
344 free_irq(get_dma_error_irq(n), (void *)dmae_name[n]);
345 }
346#endif /* CONFIG_CPU_SH4 */
289 unregister_dmac(&sh_dmac_info); 347 unregister_dmac(&sh_dmac_info);
290} 348}
291 349