Doom: re-add the missing modulus operation I removed in r22097
[kugel-rb.git] / firmware / mp3_playback.c
blob2bbd08d78939a18569876c52f78231a5b9496b0d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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.
13 * Copyright (C) 2004 by Linus Nielsen Feltzing
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.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
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 #ifndef SIMULATOR
32 #include "i2c.h"
33 #include "mas.h"
34 #include "dac.h"
35 #include "system.h"
36 #endif
37 #include "audiohw.h"
39 /* hacking into mpeg.c, recording is still there */
40 #if CONFIG_CODEC == MAS3587F
41 enum
43 MPEG_DECODER,
44 MPEG_ENCODER
45 } mpeg_mode;
46 #endif /* #ifdef MAS3587F */
48 #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR)
49 extern unsigned long shadow_io_control_main;
50 extern unsigned shadow_codec_reg0;
51 #endif
53 /**** globals ****/
55 /* own version, independent of mpeg.c */
56 static bool paused; /* playback is paused */
57 static bool playing; /* We are playing an MP3 stream */
59 #ifndef SIMULATOR
60 /* for measuring the play time */
61 static long playstart_tick;
62 static long cumulative_ticks;
64 /* the registered callback function to ask for more mp3 data */
65 static void (*callback_for_more)(unsigned char**, size_t*);
66 #endif /* #ifndef SIMULATOR */
68 /* list of tracks in memory */
69 #define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */
70 #define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)
72 #ifndef SIMULATOR
73 bool audio_is_initialized = false;
74 #endif
76 /* FIX: this code pretty much assumes a MAS */
78 /* dirty calls to mpeg.c */
79 extern void playback_tick(void);
80 extern void rec_tick(void);
82 #ifndef SIMULATOR
84 unsigned long mas_version_code;
86 #if CONFIG_CODEC == MAS3507D
87 static void mas_poll_start(void)
89 unsigned int count;
91 count = 9 * FREQ / 10000 / 8; /* 0.9 ms */
93 /* We are using timer 1 */
95 TSTR &= ~0x02; /* Stop the timer */
96 TSNC &= ~0x02; /* No synchronization */
97 TMDR &= ~0x02; /* Operate normally */
99 TCNT1 = 0; /* Start counting at 0 */
100 GRA1 = count;
101 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
103 /* Enable interrupt on level 5 */
104 IPRC = (IPRC & ~0x000f) | 0x0005;
106 TSR1 &= ~0x02;
107 TIER1 = 0xf9; /* Enable GRA match interrupt */
109 TSTR |= 0x02; /* Start timer 1 */
111 #elif CONFIG_CODEC != SWCODEC
112 static void postpone_dma_tick(void)
114 unsigned int count;
116 count = 8 * FREQ / 10000 / 8; /* 0.8 ms */
118 /* We are using timer 1 */
120 TSTR &= ~0x02; /* Stop the timer */
121 TSNC &= ~0x02; /* No synchronization */
122 TMDR &= ~0x02; /* Operate normally */
124 TCNT1 = 0; /* Start counting at 0 */
125 GRA1 = count;
126 TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
128 /* Enable interrupt on level 5 */
129 IPRC = (IPRC & ~0x000f) | 0x0005;
131 TSR1 &= ~0x02;
132 TIER1 = 0xf9; /* Enable GRA match interrupt */
134 TSTR |= 0x02; /* Start timer 1 */
136 #endif
139 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
140 void demand_irq_enable(bool on)
142 int oldlevel = disable_irq_save();
144 if(on)
146 IPRA = (IPRA & 0xfff0) | 0x000b;
147 ICR &= ~0x0010; /* IRQ3 level sensitive */
149 else
150 IPRA &= 0xfff0;
152 restore_irq(oldlevel);
154 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
157 static void play_tick(void)
159 if(playing && !paused)
161 /* Start DMA if it is disabled and the DEMAND pin is high */
162 if(!(SCR0 & 0x80) && (PBDR & 0x4000))
164 SCR0 |= 0x80;
167 playback_tick(); /* dirty call to mpeg.c */
171 void DEI3(void) __attribute__((interrupt_handler));
172 void DEI3(void)
174 unsigned char* start;
175 size_t size = 0;
177 if (callback_for_more != NULL)
179 callback_for_more(&start, &size);
182 if (size > 0)
184 DTCR3 = size & 0xffff;
185 SAR3 = (unsigned int) start;
187 else
189 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
192 CHCR3 &= ~0x0002; /* Clear DMA interrupt */
195 void IMIA1(void) __attribute__((interrupt_handler));
196 void IMIA1(void) /* Timer 1 interrupt */
198 if(playing)
199 play_tick();
200 TSR1 &= ~0x01;
201 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
202 /* Disable interrupt */
203 IPRC &= ~0x000f;
204 #endif
207 void IRQ6(void) __attribute__((interrupt_handler));
208 void IRQ6(void) /* PB14: MAS stop demand IRQ */
210 SCR0 &= ~0x80;
213 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
214 void IRQ3(void) __attribute__((interrupt_handler));
215 void IRQ3(void) /* PA15: MAS demand IRQ */
217 /* Begin with setting the IRQ to edge sensitive */
218 ICR |= 0x0010;
220 #if CONFIG_CODEC == MAS3587F
221 if(mpeg_mode == MPEG_ENCODER)
222 rec_tick();
223 else
224 #endif
225 postpone_dma_tick();
227 /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs
228 * (invalid cross-jump optimisation) */
229 asm volatile ("");
231 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
233 static void setup_sci0(void)
235 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
236 PBCR1 = (PBCR1 & 0x0cff) | 0x1208;
238 /* Set PB12 to output */
239 or_b(0x10, &PBIORH);
241 /* Disable serial port */
242 SCR0 = 0x00;
244 /* Synchronous, no prescale */
245 SMR0 = 0x80;
247 /* Set baudrate 1Mbit/s */
248 BRR0 = 0x02;
250 /* use SCK as serial clock output */
251 SCR0 = 0x01;
253 /* Clear FER and PER */
254 SSR0 &= 0xe7;
256 /* Set interrupt ITU2 and SCI0 priority to 0 */
257 IPRD &= 0x0ff0;
259 /* set PB15 and PB14 to inputs */
260 and_b(~0x80, &PBIORH);
261 and_b(~0x40, &PBIORH);
263 /* Enable End of DMA interrupt at prio 8 */
264 IPRC = (IPRC & 0xf0ff) | 0x0800;
266 /* Enable Tx (only!) */
267 SCR0 |= 0x20;
270 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
271 static void init_playback(void)
273 unsigned long val;
274 int rc;
276 mp3_play_pause(false);
278 mas_reset();
280 /* Enable the audio CODEC and the DSP core, max analog voltage range */
281 rc = mas_direct_config_write(MAS_CONTROL, 0x8c00);
282 if(rc < 0)
283 panicf("mas_ctrl_w: %d", rc);
285 /* Stop the current application */
286 val = 0;
287 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
290 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
291 } while(val);
293 /* Enable the D/A Converter */
294 shadow_codec_reg0 = 0x0001;
295 mas_codec_writereg(0x0, shadow_codec_reg0);
297 /* ADC scale 0%, DSP scale 100% */
298 mas_codec_writereg(6, 0x0000);
299 mas_codec_writereg(7, 0x4000);
301 #ifdef HAVE_SPDIF_OUT
302 val = 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
303 #else
304 val = 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
305 #endif
306 mas_writemem(MAS_BANK_D0, MAS_D0_INTERFACE_CONTROL, &val, 1);
308 /* Set Demand mode and validate all settings */
309 shadow_io_control_main = 0x25;
310 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
312 /* Start the Layer2/3 decoder applications */
313 val = 0x0c;
314 mas_writemem(MAS_BANK_D0, MAS_D0_APP_SELECT, &val, 1);
317 mas_readmem(MAS_BANK_D0, MAS_D0_APP_RUNNING, &val, 1);
318 } while((val & 0x0c) != 0x0c);
320 #if CONFIG_CODEC == MAS3587F
321 mpeg_mode = MPEG_DECODER;
322 #endif
324 /* set IRQ6 to edge detect */
325 ICR |= 0x02;
327 /* set IRQ6 prio 8 */
328 IPRB = ( IPRB & 0xff0f ) | 0x0080;
330 DEBUGF("MAS Decoding application started\n");
332 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
333 #endif /* SIMULATOR */
335 void mp3_init(int volume, int bass, int treble, int balance, int loudness,
336 int avc, int channel_config, int stereo_width,
337 int mdb_strength, int mdb_harmonics,
338 int mdb_center, int mdb_shape, bool mdb_enable,
339 bool superbass)
341 #ifdef SIMULATOR
342 (void)volume;
343 (void)bass;
344 (void)treble;
345 (void)balance;
346 (void)loudness;
347 (void)avc;
348 (void)channel_config;
349 (void)stereo_width;
350 (void)mdb_strength;
351 (void)mdb_harmonics;
352 (void)mdb_center;
353 (void)mdb_shape;
354 (void)mdb_enable;
355 (void)superbass;
356 #else
357 #if CONFIG_CODEC == MAS3507D
358 unsigned long val;
359 (void)loudness;
360 (void)avc;
361 (void)mdb_strength;
362 (void)mdb_harmonics;
363 (void)mdb_center;
364 (void)mdb_shape;
365 (void)mdb_enable;
366 (void)superbass;
367 #endif
369 setup_sci0();
371 #ifdef HAVE_MAS_SIBI_CONTROL
372 and_b(~0x01, &PBDRH); /* drive SIBI low */
373 or_b(0x01, &PBIORH); /* output for PB8 */
374 #endif
376 #if CONFIG_CODEC == MAS3507D
377 mas_reset();
378 #elif CONFIG_CODEC == MAS3587F
379 or_b(0x08, &PAIORH); /* output for /PR */
380 init_playback();
382 mas_version_code = mas_readver();
383 DEBUGF("MAS3587 derivate %d, version %c%d\n",
384 (mas_version_code & 0xf000) >> 12,
385 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
386 #elif CONFIG_CODEC == MAS3539F
387 or_b(0x08, &PAIORH); /* output for /PR */
388 init_playback();
390 mas_version_code = mas_readver();
391 DEBUGF("MAS3539 derivate %d, version %c%d\n",
392 (mas_version_code & 0xf000) >> 12,
393 'A' + ((mas_version_code & 0x0f00) >> 8), mas_version_code & 0xff);
394 #endif
396 #ifdef HAVE_DAC3550A
397 dac_init();
398 #endif
400 #if CONFIG_CODEC == MAS3507D
401 /* set IRQ6 to edge detect */
402 ICR |= 0x02;
404 /* set IRQ6 prio 8 */
405 IPRB = ( IPRB & 0xff0f ) | 0x0080;
407 mas_readmem(MAS_BANK_D1, 0xff7, &mas_version_code, 1);
409 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
410 mas_run(1);
411 sleep(HZ);
413 /* Clear the upper 12 bits of the 32-bit samples */
414 mas_writereg(0xc5, 0);
415 mas_writereg(0xc6, 0);
417 /* We need to set the PLL for a 14.31818MHz crystal */
418 if(mas_version_code == 0x0601) /* Version F10? */
420 val = 0x5d9d0;
421 mas_writemem(MAS_BANK_D0, 0x32d, &val, 1);
422 val = 0xfffceceb;
423 mas_writemem(MAS_BANK_D0, 0x32e, &val, 1);
424 val = 0x0;
425 mas_writemem(MAS_BANK_D0, 0x32f, &val, 1);
426 mas_run(0x475);
428 else
430 val = 0x5d9d0;
431 mas_writemem(MAS_BANK_D0, 0x36d, &val, 1);
432 val = 0xfffceceb;
433 mas_writemem(MAS_BANK_D0, 0x36e, &val, 1);
434 val = 0x0;
435 mas_writemem(MAS_BANK_D0, 0x36f, &val, 1);
436 mas_run(0xfcb);
439 #endif
441 #if CONFIG_CODEC == MAS3507D
442 mas_poll_start();
444 mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
445 dac_enable(true);
446 #endif
448 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
449 ICR &= ~0x0010; /* IRQ3 level sensitive */
450 PACR1 = (PACR1 & 0x3fff) | 0x4000; /* PA15 is IRQ3 */
451 #endif
453 /* Must be done before calling sound_set() */
454 audio_is_initialized = true;
456 sound_set(SOUND_BASS, bass);
457 sound_set(SOUND_TREBLE, treble);
458 sound_set(SOUND_BALANCE, balance);
459 sound_set(SOUND_VOLUME, volume);
460 sound_set(SOUND_CHANNELS, channel_config);
461 sound_set(SOUND_STEREO_WIDTH, stereo_width);
463 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
464 sound_set(SOUND_LOUDNESS, loudness);
465 sound_set(SOUND_AVC, avc);
466 sound_set(SOUND_MDB_STRENGTH, mdb_strength);
467 sound_set(SOUND_MDB_HARMONICS, mdb_harmonics);
468 sound_set(SOUND_MDB_CENTER, mdb_center);
469 sound_set(SOUND_MDB_SHAPE, mdb_shape);
470 sound_set(SOUND_MDB_ENABLE, mdb_enable);
471 sound_set(SOUND_SUPERBASS, superbass);
472 #endif
473 #endif /* !SIMULATOR */
475 playing = false;
476 paused = true;
479 void mp3_shutdown(void)
481 #ifndef SIMULATOR
482 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
483 unsigned long val = 1;
484 mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &val, 1); /* Mute */
485 #endif
487 #if CONFIG_CODEC == MAS3507D
488 dac_volume(0, 0, false);
489 #endif
491 #endif
494 /* new functions, to be exported to plugin API */
496 #ifndef SIMULATOR
498 void mp3_play_init(void)
500 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
501 init_playback();
502 #endif
503 playing = false;
504 paused = true;
505 callback_for_more = NULL;
506 mp3_reset_playtime();
509 void mp3_play_data(const unsigned char* start, int size,
510 void (*get_more)(unsigned char** start, size_t* size) /* callback fn */
513 /* init DMA */
514 DAR3 = 0x5FFFEC3;
515 CHCR3 &= ~0x0002; /* Clear interrupt */
516 CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
517 DMAOR = 0x0001; /* Enable DMA */
519 callback_for_more = get_more;
521 SAR3 = (unsigned int)start;
522 DTCR3 = size & 0xffff;
524 playing = true;
525 paused = true;
527 CHCR3 |= 0x0001; /* Enable DMA IRQ */
529 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
530 demand_irq_enable(true);
531 #endif
534 void mp3_play_pause(bool play)
536 if (paused && play)
537 { /* resume playback */
538 SCR0 |= 0x80;
539 paused = false;
540 playstart_tick = current_tick;
542 else if (!paused && !play)
543 { /* stop playback */
544 SCR0 &= 0x7f;
545 paused = true;
546 cumulative_ticks += current_tick - playstart_tick;
550 bool mp3_pause_done(void)
552 unsigned long frame_count;
554 if (!paused)
555 return false;
557 mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count, 1);
558 /* This works because the frame counter never wraps,
559 * i.e. zero always means lost sync. */
560 return frame_count == 0;
563 void mp3_play_stop(void)
565 playing = false;
566 mp3_play_pause(false);
567 CHCR3 &= ~0x0001; /* Disable the DMA interrupt */
568 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
569 demand_irq_enable(false);
570 #endif
573 long mp3_get_playtime(void)
575 if (paused)
576 return cumulative_ticks;
577 else
578 return cumulative_ticks + current_tick - playstart_tick;
581 void mp3_reset_playtime(void)
583 cumulative_ticks = 0;
584 playstart_tick = current_tick;
587 bool mp3_is_playing(void)
589 return playing;
593 /* returns the next byte position which would be transferred */
594 unsigned char* mp3_get_pos(void)
596 return (unsigned char*)SAR3;
598 #else /* #ifndef SIMULATOR */
600 void mp3_play_pause(bool play)
602 (void)play;
604 void mp3_play_stop(void)
608 unsigned char* mp3_get_pos(void)
610 return NULL;
613 void mp3_play_data(const unsigned char* start, int size,
614 void (*get_more)(unsigned char** start, size_t* size) /* callback fn */
617 (void)start; (void)size; (void)get_more;
619 #endif