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