summaryrefslogtreecommitdiff
path: root/firmware/target/sh/archos/audio-archos.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/sh/archos/audio-archos.c')
-rw-r--r--firmware/target/sh/archos/audio-archos.c543
1 files changed, 0 insertions, 543 deletions
diff --git a/firmware/target/sh/archos/audio-archos.c b/firmware/target/sh/archos/audio-archos.c
deleted file mode 100644
index 2c2579bec5..0000000000
--- a/firmware/target/sh/archos/audio-archos.c
+++ /dev/null
@@ -1,543 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Code that has been in mpeg.c before, now creating an encapsulated play
11 * data module, to be used by other sources than file playback as well.
12 *
13 * Copyright (C) 2004 by Linus Nielsen Feltzing
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include <stdbool.h>
25#include "config.h"
26#include "debug.h"
27#include "panic.h"
28#include <kernel.h>
29#include "mp3_playback.h"
30#include "sound.h"
31#include "i2c.h"
32#include "system.h"
33#include "audiohw.h"
34
35/* hacking into mpeg.c, recording is still there */
36#if CONFIG_CODEC == MAS3587F
37enum
38{
39 MPEG_DECODER,
40 MPEG_ENCODER
41} mpeg_mode;
42#endif /* #ifdef MAS3587F */
43
44#if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
45extern unsigned long shadow_io_control_main;
46extern unsigned shadow_codec_reg0;
47#endif
48
49/**** globals ****/
50
51/* own version, independent of mpeg.c */
52static bool paused; /* playback is paused */
53static bool playing; /* We are playing an MP3 stream */
54
55/* the registered callback function to ask for more mp3 data */
56static mp3_play_callback_t callback_for_more;
57
58/* list of tracks in memory */
59#define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
60#define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
61
62bool audio_is_initialized = false;
63
64/* FIX: this code pretty much assumes a MAS */
65
66/* dirty calls to mpeg.c */
67extern void playback_tick(void);
68extern void rec_tick(void);
69
70unsigned long mas_version_code;
71
72#if CONFIG_CODEC == MAS3507D
73static void mas_poll_start(void)
74{
75 unsigned int count;
76
77 count = 9 * FREQ / 10000 / 8; /* 0.9 ms */
78
79 /* We are using timer 1 */
80
81 TSTR &= ~0x02; /* Stop the timer */
82 TSNC &= ~0x02; /* No synchronization */
83 TMDR &= ~0x02; /* Operate normally */
84
85 TCNT1 = 0; /* Start counting at 0 */
86 GRA1 = count;
87 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
88
89 /* Enable interrupt on level 5 */
90 IPRC = (IPRC & ~0x000f) | 0x0005;
91
92 TSR1 &= ~0x02;
93 TIER1 = 0xf9; /* Enable GRA match interrupt */
94
95 TSTR |= 0x02; /* Start timer 1 */
96}
97#elif CONFIG_CODEC != SWCODEC
98static void postpone_dma_tick(void)
99{
100 unsigned int count;
101
102 count = 8 * FREQ / 10000 / 8; /* 0.8 ms */
103
104 /* We are using timer 1 */
105
106 TSTR &= ~0x02; /* Stop the timer */
107 TSNC &= ~0x02; /* No synchronization */
108 TMDR &= ~0x02; /* Operate normally */
109
110 TCNT1 = 0; /* Start counting at 0 */
111 GRA1 = count;
112 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
113
114 /* Enable interrupt on level 5 */
115 IPRC = (IPRC & ~0x000f) | 0x0005;
116
117 TSR1 &= ~0x02;
118 TIER1 = 0xf9; /* Enable GRA match interrupt */
119
120 TSTR |= 0x02; /* Start timer 1 */
121}
122#endif
123
124#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
125void demand_irq_enable(bool on)
126{
127 int oldlevel = disable_irq_save();
128
129 if(on)
130 {
131 IPRA = (IPRA & 0xfff0) | 0x000b;
132 ICR &= ~0x0010; /* IRQ3 level sensitive */
133 }
134 else
135 IPRA &= 0xfff0;
136
137 restore_irq(oldlevel);
138}
139#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
140
141
142static void play_tick(void)
143{
144 if(playing && !paused)
145 {
146 /* Start DMA if it is disabled and the DEMAND pin is high */
147 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
148 {
149 SCR0 |= 0x80;
150 }
151
152 playback_tick(); /* dirty call to mpeg.c */
153 }
154}
155
156void DEI3(void) __attribute__((interrupt_handler));
157void DEI3(void)
158{
159 const void* start;
160 size_t size = 0;
161
162 if (callback_for_more != NULL)
163 {
164 callback_for_more(&start, &size);
165 }
166
167 if (size > 0)
168 {
169 DTCR3 = size & 0xffff;
170 SAR3 = (unsigned int) start;
171 }
172 else
173 {
174 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
175 }
176
177 CHCR3 &= ~0x0002; /* Clear DMA interrupt */
178}
179
180void IMIA1(void) __attribute__((interrupt_handler));
181void IMIA1(void) /* Timer 1 interrupt */
182{
183 if(playing)
184 play_tick();
185 TSR1 &= ~0x01;
186#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
187 /* Disable interrupt */
188 IPRC &= ~0x000f;
189#endif
190}
191
192void IRQ6(void) __attribute__((interrupt_handler));
193void IRQ6(void) /* PB14: MAS stop demand IRQ */
194{
195 SCR0 &= ~0x80;
196}
197
198#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
199void IRQ3(void) __attribute__((interrupt_handler));
200void IRQ3(void) /* PA15: MAS demand IRQ */
201{
202 /* Begin with setting the IRQ to edge sensitive */
203 ICR |= 0x0010;
204
205#if CONFIG_CODEC == MAS3587F
206 if(mpeg_mode == MPEG_ENCODER)
207 rec_tick();
208 else
209#endif
210 postpone_dma_tick();
211
212 /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs
213 * (invalid cross-jump optimisation) */
214 asm volatile ("");
215}
216#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
217
218static void setup_sci0(void)
219{
220 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
221 PBCR1 = (PBCR1 & 0x0cff) | 0x1208;
222
223 /* Set PB12 to output */
224 or_b(0x10, &PBIORH);
225
226 /* Disable serial port */
227 SCR0 = 0x00;
228
229 /* Synchronous, no prescale */
230 SMR0 = 0x80;
231
232 /* Set baudrate 1Mbit/s */
233 BRR0 = 0x02;
234
235 /* use SCK as serial clock output */
236 SCR0 = 0x01;
237
238 /* Clear FER and PER */
239 SSR0 &= 0xe7;
240
241 /* Set interrupt ITU2 and SCI0 priority to 0 */
242 IPRD &= 0x0ff0;
243
244 /* set PB15 and PB14 to inputs */
245 and_b(~0x80, &PBIORH);
246 and_b(~0x40, &PBIORH);
247
248 /* Enable End of DMA interrupt at prio 8 */
249 IPRC = (IPRC & 0xf0ff) | 0x0800;
250
251 /* Enable Tx (only!) */
252 SCR0 |= 0x20;
253}
254
255#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
256static void init_playback(void)
257{
258 unsigned long val;
259 int rc;
260
261 mp3_play_pause(false);
262
263 mas_reset();
264
265 /* Enable the audio CODEC and the DSP core, max analog voltage range */
266 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
267 if(rc < 0)
268 panicf("mas_ctrl_w: %d", rc);
269
270 /* Stop the current application */
271 val = 0;
272 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
273 do
274 {
275 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
276 } while(val);
277
278 /* Enable the D/A Converter */
279 shadow_codec_reg0 = 0x0001;
280 mas_codec_writereg(0x0, shadow_codec_reg0);
281
282 /* ADC scale 0%, DSP scale 100% */
283 mas_codec_writereg(6, 0x0000);
284 mas_codec_writereg(7, 0x4000);
285
286#ifdef HAVE_SPDIF_OUT
287 val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
288#else
289 val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
290#endif
291 mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
292
293 /* Set Demand mode and validate all settings */
294 shadow_io_control_main = 0x25;
295 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
296
297 /* Start the Layer2/3 decoder applications */
298 val = 0x0c;
299 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
300 do
301 {
302 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
303 } while((val & 0x0c) != 0x0c);
304
305#if CONFIG_CODEC == MAS3587F
306 mpeg_mode = MPEG_DECODER;
307#endif
308
309 /* set IRQ6 to edge detect */
310 ICR |= 0x02;
311
312 /* set IRQ6 prio 8 */
313 IPRB = ( IPRB & 0xff0f ) | 0x0080;
314
315 DEBUGF("MAS Decoding application started\n");
316}
317#endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
318
319void mp3_init(int volume, int bass, int treble, int balance, int loudness,
320 int avc, int channel_config, int stereo_width,
321 int mdb_strength, int mdb_harmonics,
322 int mdb_center, int mdb_shape, bool mdb_enable,
323 bool superbass)
324{
325#if CONFIG_CODEC == MAS3507D
326 unsigned long val;
327 (void)loudness;
328 (void)avc;
329 (void)mdb_strength;
330 (void)mdb_harmonics;
331 (void)mdb_center;
332 (void)mdb_shape;
333 (void)mdb_enable;
334 (void)superbass;
335#endif
336
337 setup_sci0();
338
339#ifdef HAVE_MAS_SIBI_CONTROL
340 and_b(~0x01, &PBDRH); /* drive SIBI low */
341 or_b(0x01, &PBIORH); /* output for PB8 */
342#endif
343
344#if CONFIG_CODEC == MAS3507D
345 mas_reset();
346#elif CONFIG_CODEC == MAS3587F
347 or_b(0x08, &PAIORH); /* output for /PR */
348 init_playback();
349
350 mas_version_code = mas_readver();
351 DEBUGF("MAS3587 derivate %d, version %c%d\n",
352 (mas_version_code & 0xf000) >> 12,
353 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
354#elif CONFIG_CODEC == MAS3539F
355 or_b(0x08, &PAIORH); /* output for /PR */
356 init_playback();
357
358 mas_version_code = mas_readver();
359 DEBUGF("MAS3539 derivate %d, version %c%d\n",
360 (mas_version_code & 0xf000) >> 12,
361 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
362#endif
363
364#ifdef HAVE_DAC3550A
365 dac_init();
366#endif
367
368#if CONFIG_CODEC == MAS3507D
369 /* set IRQ6 to edge detect */
370 ICR |= 0x02;
371
372 /* set IRQ6 prio 8 */
373 IPRB = ( IPRB & 0xff0f ) | 0x0080;
374
375 mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1);
376
377 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
378 mas_run(1);
379 sleep(HZ);
380
381 /* Clear the upper 12 bits of the 32-bit samples */
382 mas_writereg(0xc5, 0);
383 mas_writereg(0xc6, 0);
384
385 /* We need to set the PLL for a 14.31818MHz crystal */
386 if(mas_version_code == 0x0601) /* Version F10? */
387 {
388 val = 0x5d9d0;
389 mas_writemem(MAS_BANK_D0, 0x32d, &val, 1);
390 val = 0xfffceceb;
391 mas_writemem(MAS_BANK_D0, 0x32e, &val, 1);
392 val = 0x0;
393 mas_writemem(MAS_BANK_D0, 0x32f, &val, 1);
394 mas_run(0x475);
395 }
396 else
397 {
398 val = 0x5d9d0;
399 mas_writemem(MAS_BANK_D0, 0x36d, &val, 1);
400 val = 0xfffceceb;
401 mas_writemem(MAS_BANK_D0, 0x36e, &val, 1);
402 val = 0x0;
403 mas_writemem(MAS_BANK_D0, 0x36f, &val, 1);
404 mas_run(0xfcb);
405 }
406
407#endif
408
409#if CONFIG_CODEC == MAS3507D
410 mas_poll_start();
411
412 mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
413 dac_enable(true);
414#endif
415
416#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
417 ICR &= ~0x0010; /* IRQ3 level sensitive */
418 PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */
419#endif
420
421 /* Must be done before calling sound_set() */
422 audio_is_initialized = true;
423
424 sound_set(SOUND_BASS, bass);
425 sound_set(SOUND_TREBLE, treble);
426 sound_set(SOUND_BALANCE, balance);
427 sound_set(SOUND_VOLUME, volume);
428 sound_set(SOUND_CHANNELS, channel_config);
429 sound_set(SOUND_STEREO_WIDTH, stereo_width);
430
431#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
432 sound_set(SOUND_LOUDNESS, loudness);
433 sound_set(SOUND_AVC, avc);
434 sound_set(SOUND_MDB_STRENGTH, mdb_strength);
435 sound_set(SOUND_MDB_HARMONICS, mdb_harmonics);
436 sound_set(SOUND_MDB_CENTER, mdb_center);
437 sound_set(SOUND_MDB_SHAPE, mdb_shape);
438 sound_set(SOUND_MDB_ENABLE, mdb_enable);
439 sound_set(SOUND_SUPERBASS, superbass);
440#endif
441
442 playing = false;
443 paused = true;
444}
445
446void mp3_shutdown(void)
447{
448#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
449 unsigned long val = 1;
450 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */
451#endif
452
453#if CONFIG_CODEC == MAS3507D
454 dac_volume(0, 0, false);
455#endif
456}
457
458/* new functions, to be exported to plugin API */
459
460#if CONFIG_CODEC == MAS3587F
461void mp3_play_init(void)
462{
463#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
464 init_playback();
465#endif
466 playing = false;
467 paused = true;
468 callback_for_more = NULL;
469}
470#endif
471
472void mp3_play_data(const void* start, size_t size,
473 mp3_play_callback_t get_more)
474{
475 /* init DMA */
476 DAR3 = 0x5FFFEC3;
477 CHCR3 &= ~0x0002; /* Clear interrupt */
478 CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
479 DMAOR = 0x0001; /* Enable DMA */
480
481 callback_for_more = get_more;
482
483 SAR3 = (unsigned int)start;
484 DTCR3 = size & 0xffff;
485
486 playing = true;
487 paused = true;
488
489 CHCR3 |= 0x0001; /* Enable DMA IRQ */
490
491#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
492 demand_irq_enable(true);
493#endif
494}
495
496void mp3_play_pause(bool play)
497{
498 if (paused && play)
499 { /* resume playback */
500 SCR0 |= 0x80;
501 paused = false;
502 }
503 else if (!paused && !play)
504 { /* stop playback */
505 SCR0 &= 0x7f;
506 paused = true;
507 }
508}
509
510bool mp3_pause_done(void)
511{
512 unsigned long frame_count;
513
514 if (!paused)
515 return false;
516
517 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1);
518 /* This works because the frame counter never wraps,
519 * i.e. zero always means lost sync. */
520 return frame_count == 0;
521}
522
523void mp3_play_stop(void)
524{
525 playing = false;
526 mp3_play_pause(false);
527 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
528#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
529 demand_irq_enable(false);
530#endif
531}
532
533bool mp3_is_playing(void)
534{
535 return playing;
536}
537
538
539/* returns the next byte position which would be transferred */
540unsigned char* mp3_get_pos(void)
541{
542 return (unsigned char*)SAR3;
543}