1 /* $NetBSD: aica_arm.c,v 1.6 2019/05/06 17:12:50 ryo 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 aica_stop(); 271 play_state = 0; 272 273 blksize = aicacmd->blocksize; 274 275 REG_WRITE_4(0x28b4, 0x0020); /* INT Enable to SH4 */ 276 277 CH_WRITE_4(0, 0x00, 0x8000); 278 CH_WRITE_4(1, 0x00, 0x8000); 279 280 switch (aicacmd->precision) { 281 case 16: 282 loopend = blksize; 283 break; 284 case 8: 285 loopend = blksize * 2; 286 break; 287 case 4: 288 loopend = blksize * 4; 289 break; 290 } 291 loophalf = loopend / 2; 292 293 ratepitch = rate2reg(aicacmd->rate); 294 295 /* setup left */ 296 CH_WRITE_4(0, 0x08, 0); /* loop start */ 297 CH_WRITE_4(0, 0x0c, loopend); /* loop end */ 298 CH_WRITE_4(0, 0x18, ratepitch); /* SamplingRate */ 299 CH_WRITE_4(0, 0x24, 0x0f1f); /* volume MAX, 300 right PAN */ 301 302 /* setup right */ 303 CH_WRITE_4(1, 0x08,0); /* loop start */ 304 CH_WRITE_4(1, 0x0c, loopend); /* loop end */ 305 CH_WRITE_4(1, 0x18, ratepitch); /* SamplingRate */ 306 CH_WRITE_4(1, 0x24, 0x0f0f); /* volume MAX, 307 right PAN */ 308 309 { 310 uint32_t mode, lparam, rparam; 311 312 if (aicacmd->precision == 4) 313 mode = 3 << 7; /* 4bit ADPCM */ 314 else if (aicacmd->precision == 8) 315 mode = 1 << 7; /* 8bit */ 316 else 317 mode = 0; /* 16bit */ 318 319 switch (aicacmd->channel) { 320 case 2: 321 CH_WRITE_4(0, 0x04, 322 AICA_DMABUF_LEFT & 0xffff); 323 CH_WRITE_4(1, 0x04, 324 AICA_DMABUF_RIGHT & 0xffff); 325 lparam = 0xc000 /*PLAY*/ | 326 0x0200 /*LOOP*/ | mode | 327 (AICA_DMABUF_LEFT >> 16); 328 rparam = 0xc000 /*PLAY*/ | 329 0x0200 /*LOOP*/ | mode | 330 (AICA_DMABUF_RIGHT >> 16); 331 CH_WRITE_4(0, 0x00, lparam); 332 CH_WRITE_4(1, 0x00, rparam); 333 break; 334 case 1: 335 CH_WRITE_1(0, 0x24, 0); /* middle 336 balance */ 337 CH_WRITE_4(0, 0x04, 338 AICA_DMABUF_LEFT & 0xffff); 339 CH_WRITE_4(0, 0x00, 0xc000 /*PLAY*/ | 340 0x0200 /*LOOP*/ | mode | 341 (AICA_DMABUF_LEFT >> 16)); 342 break; 343 } 344 } 345 play_state = 1; 346 break; 347 348 case AICA_COMMAND_STOP: 349 switch (play_state) { 350 case 1: 351 bzero_4((void *)(AICA_DMABUF_LEFT + blksize), 352 blksize); 353 bzero_4((void *)(AICA_DMABUF_RIGHT + blksize), 354 blksize); 355 play_state = 3; 356 break; 357 case 2: 358 bzero_4((void *)AICA_DMABUF_LEFT, blksize); 359 bzero_4((void *)AICA_DMABUF_RIGHT, blksize); 360 play_state = 4; 361 break; 362 default: 363 aica_stop(); 364 play_state = 0; 365 break; 366 } 367 break; 368 369 case AICA_COMMAND_INIT: 370 aica_stop(); 371 play_state = 0; 372 break; 373 374 case AICA_COMMAND_MVOL: 375 REG_WRITE_4(0x2800, L256TO16(aicacmd->l_param)); 376 break; 377 378 case AICA_COMMAND_VOL: 379 CH_WRITE_1(0, 0x29, 0xff - (aicacmd->l_param & 0xff)); 380 CH_WRITE_1(1, 0x29, 0xff - (aicacmd->r_param & 0xff)); 381 break; 382 383 } 384 } 385 } 386