Home | History | Annotate | Line # | Download | only in microcode
aica_arm.c revision 1.4
      1 /*	$NetBSD: aica_arm.c,v 1.4 2005/12/24 20:06:59 perry Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2003 SHIMIZU Ryo <ryo (at) 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()
     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()
    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()
    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