diff options
Diffstat (limited to 'sound/sh')
-rw-r--r-- | sound/sh/aica.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 131ec4812288..88dc840152ce 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c | |||
@@ -106,11 +106,14 @@ static void spu_write_wait(void) | |||
106 | static void spu_memset(u32 toi, u32 what, int length) | 106 | static void spu_memset(u32 toi, u32 what, int length) |
107 | { | 107 | { |
108 | int i; | 108 | int i; |
109 | unsigned long flags; | ||
109 | snd_assert(length % 4 == 0, return); | 110 | snd_assert(length % 4 == 0, return); |
110 | for (i = 0; i < length; i++) { | 111 | for (i = 0; i < length; i++) { |
111 | if (!(i % 8)) | 112 | if (!(i % 8)) |
112 | spu_write_wait(); | 113 | spu_write_wait(); |
114 | local_irq_save(flags); | ||
113 | writel(what, toi + SPU_MEMORY_BASE); | 115 | writel(what, toi + SPU_MEMORY_BASE); |
116 | local_irq_restore(flags); | ||
114 | toi++; | 117 | toi++; |
115 | } | 118 | } |
116 | } | 119 | } |
@@ -118,6 +121,7 @@ static void spu_memset(u32 toi, u32 what, int length) | |||
118 | /* spu_memload - write to SPU address space */ | 121 | /* spu_memload - write to SPU address space */ |
119 | static void spu_memload(u32 toi, void *from, int length) | 122 | static void spu_memload(u32 toi, void *from, int length) |
120 | { | 123 | { |
124 | unsigned long flags; | ||
121 | u32 *froml = from; | 125 | u32 *froml = from; |
122 | u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi); | 126 | u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi); |
123 | int i; | 127 | int i; |
@@ -128,7 +132,9 @@ static void spu_memload(u32 toi, void *from, int length) | |||
128 | if (!(i % 8)) | 132 | if (!(i % 8)) |
129 | spu_write_wait(); | 133 | spu_write_wait(); |
130 | val = *froml; | 134 | val = *froml; |
135 | local_irq_save(flags); | ||
131 | writel(val, to); | 136 | writel(val, to); |
137 | local_irq_restore(flags); | ||
132 | froml++; | 138 | froml++; |
133 | to++; | 139 | to++; |
134 | } | 140 | } |
@@ -138,28 +144,36 @@ static void spu_memload(u32 toi, void *from, int length) | |||
138 | static void spu_disable(void) | 144 | static void spu_disable(void) |
139 | { | 145 | { |
140 | int i; | 146 | int i; |
147 | unsigned long flags; | ||
141 | u32 regval; | 148 | u32 regval; |
142 | spu_write_wait(); | 149 | spu_write_wait(); |
143 | regval = readl(ARM_RESET_REGISTER); | 150 | regval = readl(ARM_RESET_REGISTER); |
144 | regval |= 1; | 151 | regval |= 1; |
145 | spu_write_wait(); | 152 | spu_write_wait(); |
153 | local_irq_save(flags); | ||
146 | writel(regval, ARM_RESET_REGISTER); | 154 | writel(regval, ARM_RESET_REGISTER); |
155 | local_irq_restore(flags); | ||
147 | for (i = 0; i < 64; i++) { | 156 | for (i = 0; i < 64; i++) { |
148 | spu_write_wait(); | 157 | spu_write_wait(); |
149 | regval = readl(SPU_REGISTER_BASE + (i * 0x80)); | 158 | regval = readl(SPU_REGISTER_BASE + (i * 0x80)); |
150 | regval = (regval & ~0x4000) | 0x8000; | 159 | regval = (regval & ~0x4000) | 0x8000; |
151 | spu_write_wait(); | 160 | spu_write_wait(); |
161 | local_irq_save(flags); | ||
152 | writel(regval, SPU_REGISTER_BASE + (i * 0x80)); | 162 | writel(regval, SPU_REGISTER_BASE + (i * 0x80)); |
163 | local_irq_restore(flags); | ||
153 | } | 164 | } |
154 | } | 165 | } |
155 | 166 | ||
156 | /* spu_enable - set spu registers to enable sound output */ | 167 | /* spu_enable - set spu registers to enable sound output */ |
157 | static void spu_enable(void) | 168 | static void spu_enable(void) |
158 | { | 169 | { |
170 | unsigned long flags; | ||
159 | u32 regval = readl(ARM_RESET_REGISTER); | 171 | u32 regval = readl(ARM_RESET_REGISTER); |
160 | regval &= ~1; | 172 | regval &= ~1; |
161 | spu_write_wait(); | 173 | spu_write_wait(); |
174 | local_irq_save(flags); | ||
162 | writel(regval, ARM_RESET_REGISTER); | 175 | writel(regval, ARM_RESET_REGISTER); |
176 | local_irq_restore(flags); | ||
163 | } | 177 | } |
164 | 178 | ||
165 | /* | 179 | /* |
@@ -168,25 +182,34 @@ static void spu_enable(void) | |||
168 | */ | 182 | */ |
169 | static void spu_reset(void) | 183 | static void spu_reset(void) |
170 | { | 184 | { |
185 | unsigned long flags; | ||
171 | spu_disable(); | 186 | spu_disable(); |
172 | spu_memset(0, 0, 0x200000 / 4); | 187 | spu_memset(0, 0, 0x200000 / 4); |
173 | /* Put ARM7 in endless loop */ | 188 | /* Put ARM7 in endless loop */ |
189 | local_irq_save(flags); | ||
174 | ctrl_outl(0xea000002, SPU_MEMORY_BASE); | 190 | ctrl_outl(0xea000002, SPU_MEMORY_BASE); |
191 | local_irq_restore(flags); | ||
175 | spu_enable(); | 192 | spu_enable(); |
176 | } | 193 | } |
177 | 194 | ||
178 | /* aica_chn_start - write to spu to start playback */ | 195 | /* aica_chn_start - write to spu to start playback */ |
179 | static void aica_chn_start(void) | 196 | static void aica_chn_start(void) |
180 | { | 197 | { |
198 | unsigned long flags; | ||
181 | spu_write_wait(); | 199 | spu_write_wait(); |
200 | local_irq_save(flags); | ||
182 | writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT); | 201 | writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT); |
202 | local_irq_restore(flags); | ||
183 | } | 203 | } |
184 | 204 | ||
185 | /* aica_chn_halt - write to spu to halt playback */ | 205 | /* aica_chn_halt - write to spu to halt playback */ |
186 | static void aica_chn_halt(void) | 206 | static void aica_chn_halt(void) |
187 | { | 207 | { |
208 | unsigned long flags; | ||
188 | spu_write_wait(); | 209 | spu_write_wait(); |
210 | local_irq_save(flags); | ||
189 | writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT); | 211 | writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT); |
212 | local_irq_restore(flags); | ||
190 | } | 213 | } |
191 | 214 | ||
192 | /* ALSA code below */ | 215 | /* ALSA code below */ |
@@ -213,12 +236,13 @@ static int aica_dma_transfer(int channels, int buffer_size, | |||
213 | int q, err, period_offset; | 236 | int q, err, period_offset; |
214 | struct snd_card_aica *dreamcastcard; | 237 | struct snd_card_aica *dreamcastcard; |
215 | struct snd_pcm_runtime *runtime; | 238 | struct snd_pcm_runtime *runtime; |
216 | err = 0; | 239 | unsigned long flags; |
217 | dreamcastcard = substream->pcm->private_data; | 240 | dreamcastcard = substream->pcm->private_data; |
218 | period_offset = dreamcastcard->clicks; | 241 | period_offset = dreamcastcard->clicks; |
219 | period_offset %= (AICA_PERIOD_NUMBER / channels); | 242 | period_offset %= (AICA_PERIOD_NUMBER / channels); |
220 | runtime = substream->runtime; | 243 | runtime = substream->runtime; |
221 | for (q = 0; q < channels; q++) { | 244 | for (q = 0; q < channels; q++) { |
245 | local_irq_save(flags); | ||
222 | err = dma_xfer(AICA_DMA_CHANNEL, | 246 | err = dma_xfer(AICA_DMA_CHANNEL, |
223 | (unsigned long) (runtime->dma_area + | 247 | (unsigned long) (runtime->dma_area + |
224 | (AICA_BUFFER_SIZE * q) / | 248 | (AICA_BUFFER_SIZE * q) / |
@@ -228,9 +252,12 @@ static int aica_dma_transfer(int channels, int buffer_size, | |||
228 | AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET + | 252 | AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET + |
229 | AICA_PERIOD_SIZE * period_offset, | 253 | AICA_PERIOD_SIZE * period_offset, |
230 | buffer_size / channels, AICA_DMA_MODE); | 254 | buffer_size / channels, AICA_DMA_MODE); |
231 | if (unlikely(err < 0)) | 255 | if (unlikely(err < 0)) { |
256 | local_irq_restore(flags); | ||
232 | break; | 257 | break; |
258 | } | ||
233 | dma_wait_for_completion(AICA_DMA_CHANNEL); | 259 | dma_wait_for_completion(AICA_DMA_CHANNEL); |
260 | local_irq_restore(flags); | ||
234 | } | 261 | } |
235 | return err; | 262 | return err; |
236 | } | 263 | } |