aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/drivers/dma/dma-sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/drivers/dma/dma-sh.c')
-rw-r--r--arch/sh/drivers/dma/dma-sh.c134
1 files changed, 82 insertions, 52 deletions
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index 31dacd4444b2..cca26c4c9d1b 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Copyright (C) 2000 Takashi YOSHII 6 * Copyright (C) 2000 Takashi YOSHII
7 * Copyright (C) 2003, 2004 Paul Mundt 7 * Copyright (C) 2003, 2004 Paul Mundt
8 * Copyright (C) 2005 Andriy Skulysh
8 * 9 *
9 * This file is subject to the terms and conditions of the GNU General Public 10 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive 11 * License. See the file "COPYING" in the main directory of this archive
@@ -16,51 +17,28 @@
16#include <linux/irq.h> 17#include <linux/irq.h>
17#include <linux/interrupt.h> 18#include <linux/interrupt.h>
18#include <linux/module.h> 19#include <linux/module.h>
20#include <asm/dreamcast/dma.h>
19#include <asm/signal.h> 21#include <asm/signal.h>
20#include <asm/irq.h> 22#include <asm/irq.h>
21#include <asm/dma.h> 23#include <asm/dma.h>
22#include <asm/io.h> 24#include <asm/io.h>
23#include "dma-sh.h" 25#include "dma-sh.h"
24 26
25/*
26 * The SuperH DMAC supports a number of transmit sizes, we list them here,
27 * with their respective values as they appear in the CHCR registers.
28 *
29 * Defaults to a 64-bit transfer size.
30 */
31enum {
32 XMIT_SZ_64BIT,
33 XMIT_SZ_8BIT,
34 XMIT_SZ_16BIT,
35 XMIT_SZ_32BIT,
36 XMIT_SZ_256BIT,
37};
38
39/*
40 * The DMA count is defined as the number of bytes to transfer.
41 */
42static unsigned int ts_shift[] = {
43 [XMIT_SZ_64BIT] = 3,
44 [XMIT_SZ_8BIT] = 0,
45 [XMIT_SZ_16BIT] = 1,
46 [XMIT_SZ_32BIT] = 2,
47 [XMIT_SZ_256BIT] = 5,
48};
49
50static inline unsigned int get_dmte_irq(unsigned int chan) 27static inline unsigned int get_dmte_irq(unsigned int chan)
51{ 28{
52 unsigned int irq; 29 unsigned int irq = 0;
53 30
54 /* 31 /*
55 * Normally we could just do DMTE0_IRQ + chan outright, though in the 32 * Normally we could just do DMTE0_IRQ + chan outright, though in the
56 * case of the 7751R, the DMTE IRQs for channels > 4 start right above 33 * case of the 7751R, the DMTE IRQs for channels > 4 start right above
57 * the SCIF 34 * the SCIF
58 */ 35 */
59
60 if (chan < 4) { 36 if (chan < 4) {
61 irq = DMTE0_IRQ + chan; 37 irq = DMTE0_IRQ + chan;
62 } else { 38 } else {
39#ifdef DMTE4_IRQ
63 irq = DMTE4_IRQ + chan - 4; 40 irq = DMTE4_IRQ + chan - 4;
41#endif
64 } 42 }
65 43
66 return irq; 44 return irq;
@@ -78,9 +56,7 @@ static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
78{ 56{
79 u32 chcr = ctrl_inl(CHCR[chan->chan]); 57 u32 chcr = ctrl_inl(CHCR[chan->chan]);
80 58
81 chcr >>= 4; 59 return ts_shift[(chcr & CHCR_TS_MASK)>>CHCR_TS_SHIFT];
82
83 return ts_shift[chcr & 0x0007];
84} 60}
85 61
86/* 62/*
@@ -109,8 +85,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
109 85
110static int sh_dmac_request_dma(struct dma_channel *chan) 86static int sh_dmac_request_dma(struct dma_channel *chan)
111{ 87{
88 char name[32];
89
90 snprintf(name, sizeof(name), "DMAC Transfer End (Channel %d)",
91 chan->chan);
92
112 return request_irq(get_dmte_irq(chan->chan), dma_tei, 93 return request_irq(get_dmte_irq(chan->chan), dma_tei,
113 SA_INTERRUPT, "DMAC Transfer End", chan); 94 SA_INTERRUPT, name, chan);
114} 95}
115 96
116static void sh_dmac_free_dma(struct dma_channel *chan) 97static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -118,10 +99,18 @@ static void sh_dmac_free_dma(struct dma_channel *chan)
118 free_irq(get_dmte_irq(chan->chan), chan); 99 free_irq(get_dmte_irq(chan->chan), chan);
119} 100}
120 101
121static void sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) 102static void
103sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
122{ 104{
123 if (!chcr) 105 if (!chcr)
124 chcr = RS_DUAL; 106 chcr = RS_DUAL | CHCR_IE;
107
108 if (chcr & CHCR_IE) {
109 chcr &= ~CHCR_IE;
110 chan->flags |= DMA_TEI_CAPABLE;
111 } else {
112 chan->flags &= ~DMA_TEI_CAPABLE;
113 }
125 114
126 ctrl_outl(chcr, CHCR[chan->chan]); 115 ctrl_outl(chcr, CHCR[chan->chan]);
127 116
@@ -130,22 +119,32 @@ static void sh_dmac_configure_channel(struct dma_channel *chan, unsigned long ch
130 119
131static void sh_dmac_enable_dma(struct dma_channel *chan) 120static void sh_dmac_enable_dma(struct dma_channel *chan)
132{ 121{
133 int irq = get_dmte_irq(chan->chan); 122 int irq;
134 u32 chcr; 123 u32 chcr;
135 124
136 chcr = ctrl_inl(CHCR[chan->chan]); 125 chcr = ctrl_inl(CHCR[chan->chan]);
137 chcr |= CHCR_DE | CHCR_IE; 126 chcr |= CHCR_DE;
127
128 if (chan->flags & DMA_TEI_CAPABLE)
129 chcr |= CHCR_IE;
130
138 ctrl_outl(chcr, CHCR[chan->chan]); 131 ctrl_outl(chcr, CHCR[chan->chan]);
139 132
140 enable_irq(irq); 133 if (chan->flags & DMA_TEI_CAPABLE) {
134 irq = get_dmte_irq(chan->chan);
135 enable_irq(irq);
136 }
141} 137}
142 138
143static void sh_dmac_disable_dma(struct dma_channel *chan) 139static void sh_dmac_disable_dma(struct dma_channel *chan)
144{ 140{
145 int irq = get_dmte_irq(chan->chan); 141 int irq;
146 u32 chcr; 142 u32 chcr;
147 143
148 disable_irq(irq); 144 if (chan->flags & DMA_TEI_CAPABLE) {
145 irq = get_dmte_irq(chan->chan);
146 disable_irq(irq);
147 }
149 148
150 chcr = ctrl_inl(CHCR[chan->chan]); 149 chcr = ctrl_inl(CHCR[chan->chan]);
151 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); 150 chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
@@ -158,7 +157,7 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
158 * If we haven't pre-configured the channel with special flags, use 157 * If we haven't pre-configured the channel with special flags, use
159 * the defaults. 158 * the defaults.
160 */ 159 */
161 if (!(chan->flags & DMA_CONFIGURED)) 160 if (unlikely(!(chan->flags & DMA_CONFIGURED)))
162 sh_dmac_configure_channel(chan, 0); 161 sh_dmac_configure_channel(chan, 0);
163 162
164 sh_dmac_disable_dma(chan); 163 sh_dmac_disable_dma(chan);
@@ -178,9 +177,11 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
178 * cascading to the PVR2 DMAC. In this case, we still need to write 177 * cascading to the PVR2 DMAC. In this case, we still need to write
179 * SAR and DAR, regardless of value, in order for cascading to work. 178 * SAR and DAR, regardless of value, in order for cascading to work.
180 */ 179 */
181 if (chan->sar || (mach_is_dreamcast() && chan->chan == 2)) 180 if (chan->sar || (mach_is_dreamcast() &&
181 chan->chan == PVR2_CASCADE_CHAN))
182 ctrl_outl(chan->sar, SAR[chan->chan]); 182 ctrl_outl(chan->sar, SAR[chan->chan]);
183 if (chan->dar || (mach_is_dreamcast() && chan->chan == 2)) 183 if (chan->dar || (mach_is_dreamcast() &&
184 chan->chan == PVR2_CASCADE_CHAN))
184 ctrl_outl(chan->dar, DAR[chan->chan]); 185 ctrl_outl(chan->dar, DAR[chan->chan]);
185 186
186 ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]); 187 ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]);
@@ -198,17 +199,38 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)
198 return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); 199 return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan);
199} 200}
200 201
201#if defined(CONFIG_CPU_SH4) 202#ifdef CONFIG_CPU_SUBTYPE_SH7780
202static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs) 203#define dmaor_read_reg() ctrl_inw(DMAOR)
204#define dmaor_write_reg(data) ctrl_outw(data, DMAOR)
205#else
206#define dmaor_read_reg() ctrl_inl(DMAOR)
207#define dmaor_write_reg(data) ctrl_outl(data, DMAOR)
208#endif
209
210static inline int dmaor_reset(void)
203{ 211{
204 unsigned long dmaor = ctrl_inl(DMAOR); 212 unsigned long dmaor = dmaor_read_reg();
213
214 /* Try to clear the error flags first, incase they are set */
215 dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
216 dmaor_write_reg(dmaor);
205 217
206 printk("DMAE: DMAOR=%lx\n", dmaor); 218 dmaor |= DMAOR_INIT;
219 dmaor_write_reg(dmaor);
207 220
208 ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_NMIF, DMAOR); 221 /* See if we got an error again */
209 ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_AE, DMAOR); 222 if ((dmaor_read_reg() & (DMAOR_AE | DMAOR_NMIF))) {
210 ctrl_outl(ctrl_inl(DMAOR)|DMAOR_DME, DMAOR); 223 printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n");
224 return -EINVAL;
225 }
211 226
227 return 0;
228}
229
230#if defined(CONFIG_CPU_SH4)
231static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs)
232{
233 dmaor_reset();
212 disable_irq(irq); 234 disable_irq(irq);
213 235
214 return IRQ_HANDLED; 236 return IRQ_HANDLED;
@@ -224,8 +246,8 @@ static struct dma_ops sh_dmac_ops = {
224}; 246};
225 247
226static struct dma_info sh_dmac_info = { 248static struct dma_info sh_dmac_info = {
227 .name = "SuperH DMAC", 249 .name = "sh_dmac",
228 .nr_channels = 4, 250 .nr_channels = CONFIG_NR_ONCHIP_DMA_CHANNELS,
229 .ops = &sh_dmac_ops, 251 .ops = &sh_dmac_ops,
230 .flags = DMAC_CHANNELS_TEI_CAPABLE, 252 .flags = DMAC_CHANNELS_TEI_CAPABLE,
231}; 253};
@@ -248,7 +270,13 @@ static int __init sh_dmac_init(void)
248 make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY); 270 make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
249 } 271 }
250 272
251 ctrl_outl(0x8000 | DMAOR_DME, DMAOR); 273 /*
274 * Initialize DMAOR, and clean up any error flags that may have
275 * been set.
276 */
277 i = dmaor_reset();
278 if (i < 0)
279 return i;
252 280
253 return register_dmac(info); 281 return register_dmac(info);
254} 282}
@@ -258,10 +286,12 @@ static void __exit sh_dmac_exit(void)
258#ifdef CONFIG_CPU_SH4 286#ifdef CONFIG_CPU_SH4
259 free_irq(DMAE_IRQ, 0); 287 free_irq(DMAE_IRQ, 0);
260#endif 288#endif
289 unregister_dmac(&sh_dmac_info);
261} 290}
262 291
263subsys_initcall(sh_dmac_init); 292subsys_initcall(sh_dmac_init);
264module_exit(sh_dmac_exit); 293module_exit(sh_dmac_exit);
265 294
295MODULE_AUTHOR("Takashi YOSHII, Paul Mundt, Andriy Skulysh");
296MODULE_DESCRIPTION("SuperH On-Chip DMAC Support");
266MODULE_LICENSE("GPL"); 297MODULE_LICENSE("GPL");
267