1 /* $NetBSD: aica_arm.c,v 1.5 2009/03/18 10:22:27 cegger Exp $ */ 2 3 /* 4 * Copyright (c) 2003 SHIMIZU Ryo <ryo@misakimix.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 typedef unsigned char uint8_t; 32 typedef unsigned short uint16_t; 33 typedef unsigned long uint32_t; 34 35 #include <arch/dreamcast/dev/g2/aicavar.h> 36 37 #define DC_REG_ADDR 0x00800000 38 39 #define REG_READ_1(off) \ 40 (*(volatile uint8_t *)(DC_REG_ADDR + (off))) 41 #define REG_READ_2(off) \ 42 (*(volatile uint16_t *)(DC_REG_ADDR + (off))) 43 #define REG_READ_4(off) \ 44 (*(volatile uint32_t *)(DC_REG_ADDR + (off))) 45 #define REG_WRITE_1(off,val) \ 46 ((*(volatile uint8_t *)(DC_REG_ADDR + (off))) = (val)) 47 #define REG_WRITE_2(off,val) \ 48 ((*(volatile uint16_t *)(DC_REG_ADDR + (off))) = (val)) 49 #define REG_WRITE_4(off,val) \ 50 ((*(volatile uint32_t *)((DC_REG_ADDR)+(off))) = (val)) 51 52 #define CH_READ_1(ch,off) REG_READ_1(((ch) << 7) + (off)) 53 #define CH_READ_2(ch,off) REG_READ_2(((ch) << 7) + (off)) 54 #define CH_READ_4(ch,off) REG_READ_4(((ch) << 7) + (off)) 55 #define CH_WRITE_1(ch,off,val) REG_WRITE_1(((ch) << 7) + (off), val) 56 #define CH_WRITE_2(ch,off,val) REG_WRITE_2(((ch) << 7) + (off), val) 57 #define CH_WRITE_4(ch,off,val) REG_WRITE_4(((ch) << 7) + (off), val) 58 59 void aica_init(void); 60 inline int in_first_half(unsigned int); 61 inline int in_second_half(unsigned int); 62 void bzero_4(void *, unsigned int); 63 void bzero(void *, unsigned int); 64 uint32_t rate2reg(unsigned int); 65 void aica_stop(void); 66 void aica_main(void); 67 68 void 69 aica_init(void) 70 { 71 int ch, off; 72 73 /* Initialize AICA channels */ 74 REG_WRITE_4(0x2800, 0x0000); /* Master volume: Min */ 75 76 for (ch = 0; ch < 64; ch++) { 77 CH_WRITE_4(ch, 0x00, 0x8000); /* Key off */ 78 CH_WRITE_4(ch, 0x04, 0x0000); /* DataAddress (low) */ 79 CH_WRITE_4(ch, 0x08, 0x0000); /* LoopStartPosition */ 80 CH_WRITE_4(ch, 0x0c, 0x0000); /* LoopEndPosition */ 81 CH_WRITE_4(ch, 0x10, 0x001f); /* AR = 0x1f = 0 msec */ 82 CH_WRITE_4(ch, 0x14, 0x001f); /* RR = 0x1f = 0 msec */ 83 CH_WRITE_4(ch, 0x18, 0x0000); /* Pitch */ 84 CH_WRITE_4(ch, 0x1c, 0x0000); /* LFO Control */ 85 CH_WRITE_4(ch, 0x20, 0x0000); /* DSP Channel to send */ 86 CH_WRITE_4(ch, 0x24, 0x0000); /* Pan & Volume */ 87 CH_WRITE_4(ch, 0x28, 0x0024); /* Volume & LowPassFilter */ 88 CH_WRITE_4(ch, 0x2c, 0x0000); /* LowPassFilter for Attack */ 89 CH_WRITE_4(ch, 0x30, 0x0000); /* LowPassFilter for Decay */ 90 CH_WRITE_4(ch, 0x34, 0x0000); /* LowPassFilter for Sustain */ 91 CH_WRITE_4(ch, 0x38, 0x0000); /* LowPassFilter for Keyoff */ 92 CH_WRITE_4(ch, 0x3c, 0x0000); /* LowPassFilter for Release */ 93 CH_WRITE_4(ch, 0x40, 0x0000); /* LowPassFilter transition 94 for Attack, Decay */ 95 CH_WRITE_4(ch, 0x44, 0x0000); /* LowPassFilter transition 96 for Decay, Release */ 97 98 for (off = 0x48; off < 0x80; off+=4) { 99 CH_WRITE_4(ch, off, 0x0000); /* other = 0 */ 100 } 101 } 102 103 REG_WRITE_4(0x2800, 0x000f); /* Master volume: Max */ 104 } 105 106 107 inline int 108 in_first_half(unsigned int loophalf) 109 { 110 111 REG_WRITE_1(0x280d, 0); /* select channel 0 */ 112 return REG_READ_4(0x2814) < loophalf; 113 } 114 115 inline int 116 in_second_half(unsigned int loophalf) 117 { 118 119 REG_WRITE_1(0x280d, 0); /* select channel 0 */ 120 return REG_READ_4(0x2814) >= loophalf; 121 } 122 123 124 void 125 bzero_4(void *b, unsigned int len) 126 { 127 uint32_t *p; 128 129 p = b; 130 len = (len + 3) & ~3; 131 for (; len != 0; len -= 4) 132 *p++ = 0; 133 } 134 135 void 136 bzero(void *b,unsigned int len) 137 { 138 uint8_t *p; 139 140 p = b; 141 for (; len != 0; len--) 142 *p++ = 0; 143 } 144 145 146 uint32_t 147 rate2reg(unsigned int rate) 148 { 149 uint32_t base, fns; 150 int oct; 151 152 base = 44100 << 7; 153 for (oct = 7; oct >= -8 && rate < base; oct--) 154 base >>= 1; 155 156 if (rate < base) 157 return (oct << 11) & 0xf800; 158 159 rate -= base; 160 161 #if 0 162 /* (base / 2) : round off */ 163 fns = (rate * 1024 + (base / 2)) / base; 164 #else 165 /* avoid using udivsi3() */ 166 { 167 uint32_t tmp = (rate * 1024 + (base / 2)); 168 for (fns = 0; tmp >= base; tmp -= base, fns++) 169 ; 170 } 171 #endif 172 173 /* adjustment */ 174 if (fns == 1024) { 175 oct++; 176 fns = 0; 177 } else { 178 if ((rate > base * fns / 1024) && 179 (fns < 1023) && 180 (rate == base * (fns + 1) / 1024)) { 181 fns++; 182 } else if ((rate < base * fns / 1024) && 183 (fns > 0) && 184 (rate == base * (fns - 1)/ 1024)) { 185 fns--; 186 } 187 } 188 189 return ((oct << 11) & 0xf800) + fns; 190 } 191 192 193 194 void 195 aica_stop(void) 196 { 197 198 CH_WRITE_4(0, 0x00, 0x8000); 199 CH_WRITE_4(1, 0x00, 0x8000); 200 bzero_4((void *)AICA_DMABUF_LEFT, AICA_DMABUF_SIZE); 201 bzero_4((void *)AICA_DMABUF_RIGHT, AICA_DMABUF_SIZE); 202 } 203 204 void 205 aica_main(void) 206 { 207 volatile aica_cmd_t *aicacmd = (volatile aica_cmd_t *)AICA_ARM_CMD; 208 int play_state; 209 unsigned int loopend = 0,loophalf = 0; 210 unsigned int blksize = 0, ratepitch; 211 uint32_t cmd, serial; 212 213 aica_init(); 214 215 REG_WRITE_4(0x28b4, 0x0020); /* INT Enable to SH4 */ 216 217 bzero_4((void *)AICA_DMABUF_LEFT, AICA_DMABUF_SIZE); 218 bzero_4((void *)AICA_DMABUF_RIGHT, AICA_DMABUF_SIZE); 219 220 play_state = 0; 221 serial = aicacmd->serial = 0; 222 223 for (;;) { 224 if (serial != aicacmd->serial) { 225 serial = aicacmd->serial; 226 cmd = aicacmd->command; 227 aicacmd->command = AICA_COMMAND_NOP; 228 } else { 229 cmd = AICA_COMMAND_NOP; 230 } 231 232 switch (cmd) { 233 case AICA_COMMAND_NOP: 234 /* 235 * AICA_COMMAND_NOP - Idle process 236 */ 237 switch (play_state) { 238 case 0: /* not playing */ 239 break; 240 case 1: /* first half */ 241 if (in_second_half(loophalf)) { 242 /* Send INT to SH4 */ 243 REG_WRITE_4(0x28b8, 0x0020); 244 play_state = 2; 245 } 246 break; 247 case 2: /* second half */ 248 if (in_first_half(loophalf)) { 249 /* Send INT to SH4 */ 250 REG_WRITE_4(0x28b8, 0x0020); 251 play_state = 1; 252 } 253 break; 254 case 3: 255 if (in_second_half(loophalf)) { 256 aica_stop(); 257 play_state = 0; 258 } 259 break; 260 case 4: 261 if (in_first_half(loophalf)) { 262 aica_stop(); 263 play_state = 0; 264 } 265 break; 266 } 267 break; 268 269 case AICA_COMMAND_PLAY: 270 blksize = aicacmd->blocksize; 271 272 CH_WRITE_4(0, 0x00, 0x8000); 273 CH_WRITE_4(1, 0x00, 0x8000); 274 275 switch (aicacmd->precision) { 276 case 16: 277 loopend = blksize; 278 break; 279 case 8: 280 loopend = blksize * 2; 281 break; 282 case 4: 283 loopend = blksize * 4; 284 break; 285 } 286 loophalf = loopend / 2; 287 288 ratepitch = rate2reg(aicacmd->rate); 289 290 /* setup left */ 291 CH_WRITE_4(0, 0x08, 0); /* loop start */ 292 CH_WRITE_4(0, 0x0c, loopend); /* loop end */ 293 CH_WRITE_4(0, 0x18, ratepitch); /* SamplingRate */ 294 CH_WRITE_4(0, 0x24, 0x0f1f); /* volume MAX, 295 right PAN */ 296 297 /* setup right */ 298 CH_WRITE_4(1, 0x08,0); /* loop start */ 299 CH_WRITE_4(1, 0x0c, loopend); /* loop end */ 300 CH_WRITE_4(1, 0x18, ratepitch); /* SamplingRate */ 301 CH_WRITE_4(1, 0x24, 0x0f0f); /* volume MAX, 302 right PAN */ 303 304 { 305 uint32_t mode, lparam, rparam; 306 307 if (aicacmd->precision == 4) 308 mode = 3 << 7; /* 4bit ADPCM */ 309 else if (aicacmd->precision == 8) 310 mode = 1 << 7; /* 8bit */ 311 else 312 mode = 0; /* 16bit */ 313 314 switch (aicacmd->channel) { 315 case 2: 316 CH_WRITE_4(0, 0x04, 317 AICA_DMABUF_LEFT & 0xffff); 318 CH_WRITE_4(1, 0x04, 319 AICA_DMABUF_RIGHT & 0xffff); 320 lparam = 0xc000 /*PLAY*/ | 321 0x0200 /*LOOP*/ | mode | 322 (AICA_DMABUF_LEFT >> 16); 323 rparam = 0xc000 /*PLAY*/ | 324 0x0200 /*LOOP*/ | mode | 325 (AICA_DMABUF_RIGHT >> 16); 326 CH_WRITE_4(0, 0x00, lparam); 327 CH_WRITE_4(1, 0x00, rparam); 328 break; 329 case 1: 330 CH_WRITE_1(0, 0x24, 0); /* middle 331 balance */ 332 CH_WRITE_4(0, 0x04, 333 AICA_DMABUF_LEFT & 0xffff); 334 CH_WRITE_4(0, 0x00, 0xc000 /*PLAY*/ | 335 0x0200 /*LOOP*/ | mode | 336 (AICA_DMABUF_LEFT >> 16)); 337 break; 338 } 339 } 340 play_state = 1; 341 break; 342 343 case AICA_COMMAND_STOP: 344 switch (play_state) { 345 case 1: 346 bzero_4((void *)(AICA_DMABUF_LEFT + blksize), 347 blksize); 348 bzero_4((void *)(AICA_DMABUF_RIGHT + blksize), 349 blksize); 350 play_state = 3; 351 break; 352 case 2: 353 bzero_4((void *)AICA_DMABUF_LEFT, blksize); 354 bzero_4((void *)AICA_DMABUF_RIGHT, blksize); 355 play_state = 4; 356 break; 357 default: 358 aica_stop(); 359 play_state = 0; 360 break; 361 } 362 break; 363 364 case AICA_COMMAND_INIT: 365 aica_stop(); 366 play_state = 0; 367 break; 368 369 case AICA_COMMAND_MVOL: 370 REG_WRITE_4(0x2800, L256TO16(aicacmd->l_param)); 371 break; 372 373 case AICA_COMMAND_VOL: 374 CH_WRITE_1(0, 0x29, 0xff - (aicacmd->l_param & 0xff)); 375 CH_WRITE_1(1, 0x29, 0xff - (aicacmd->r_param & 0xff)); 376 break; 377 378 } 379 } 380 } 381