diff options
| -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 | } |
