1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 #include "mp3_playback.h"
39 /* hacking into mpeg.c, recording is still there */
40 #if CONFIG_CODEC == MAS3587F
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
;
55 /* own version, independent of mpeg.c */
56 static bool paused
; /* playback is paused */
57 static bool playing
; /* We are playing an MP3 stream */
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 bool audio_is_initialized
= false;
74 /* FIX: this code pretty much assumes a MAS */
76 /* dirty calls to mpeg.c */
77 extern void playback_tick(void);
78 extern void rec_tick(void);
82 unsigned long mas_version_code
;
84 #if CONFIG_CODEC == MAS3507D
85 static void mas_poll_start(void)
89 count
= 9 * FREQ
/ 10000 / 8; /* 0.9 ms */
91 /* We are using timer 1 */
93 TSTR
&= ~0x02; /* Stop the timer */
94 TSNC
&= ~0x02; /* No synchronization */
95 TMDR
&= ~0x02; /* Operate normally */
97 TCNT1
= 0; /* Start counting at 0 */
99 TCR1
= 0x23; /* Clear at GRA match, sysclock/8 */
101 /* Enable interrupt on level 5 */
102 IPRC
= (IPRC
& ~0x000f) | 0x0005;
105 TIER1
= 0xf9; /* Enable GRA match interrupt */
107 TSTR
|= 0x02; /* Start timer 1 */
109 #elif CONFIG_CODEC != SWCODEC
110 static void postpone_dma_tick(void)
114 count
= 8 * FREQ
/ 10000 / 8; /* 0.8 ms */
116 /* We are using timer 1 */
118 TSTR
&= ~0x02; /* Stop the timer */
119 TSNC
&= ~0x02; /* No synchronization */
120 TMDR
&= ~0x02; /* Operate normally */
122 TCNT1
= 0; /* Start counting at 0 */
124 TCR1
= 0x23; /* Clear at GRA match, sysclock/8 */
126 /* Enable interrupt on level 5 */
127 IPRC
= (IPRC
& ~0x000f) | 0x0005;
130 TIER1
= 0xf9; /* Enable GRA match interrupt */
132 TSTR
|= 0x02; /* Start timer 1 */
137 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
138 void demand_irq_enable(bool on
)
140 int oldlevel
= disable_irq_save();
144 IPRA
= (IPRA
& 0xfff0) | 0x000b;
145 ICR
&= ~0x0010; /* IRQ3 level sensitive */
150 restore_irq(oldlevel
);
152 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
155 static void play_tick(void)
157 if(playing
&& !paused
)
159 /* Start DMA if it is disabled and the DEMAND pin is high */
160 if(!(SCR0
& 0x80) && (PBDR
& 0x4000))
165 playback_tick(); /* dirty call to mpeg.c */
169 void DEI3(void) __attribute__((interrupt_handler
));
172 unsigned char* start
;
175 if (callback_for_more
!= NULL
)
177 callback_for_more(&start
, &size
);
182 DTCR3
= size
& 0xffff;
183 SAR3
= (unsigned int) start
;
187 CHCR3
&= ~0x0001; /* Disable the DMA interrupt */
190 CHCR3
&= ~0x0002; /* Clear DMA interrupt */
193 void IMIA1(void) __attribute__((interrupt_handler
));
194 void IMIA1(void) /* Timer 1 interrupt */
199 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
200 /* Disable interrupt */
205 void IRQ6(void) __attribute__((interrupt_handler
));
206 void IRQ6(void) /* PB14: MAS stop demand IRQ */
211 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
212 void IRQ3(void) __attribute__((interrupt_handler
));
213 void IRQ3(void) /* PA15: MAS demand IRQ */
215 /* Begin with setting the IRQ to edge sensitive */
218 #if CONFIG_CODEC == MAS3587F
219 if(mpeg_mode
== MPEG_ENCODER
)
225 /* Workaround for sh-elf-gcc 3.3.x bug with -O2 or -Os and ISRs
226 * (invalid cross-jump optimisation) */
229 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
231 static void setup_sci0(void)
233 /* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0, PB9 is TxD0 */
234 PBCR1
= (PBCR1
& 0x0cff) | 0x1208;
236 /* Set PB12 to output */
239 /* Disable serial port */
242 /* Synchronous, no prescale */
245 /* Set baudrate 1Mbit/s */
248 /* use SCK as serial clock output */
251 /* Clear FER and PER */
254 /* Set interrupt ITU2 and SCI0 priority to 0 */
257 /* set PB15 and PB14 to inputs */
258 and_b(~0x80, &PBIORH
);
259 and_b(~0x40, &PBIORH
);
261 /* Enable End of DMA interrupt at prio 8 */
262 IPRC
= (IPRC
& 0xf0ff) | 0x0800;
264 /* Enable Tx (only!) */
268 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
269 static void init_playback(void)
274 mp3_play_pause(false);
278 /* Enable the audio CODEC and the DSP core, max analog voltage range */
279 rc
= mas_direct_config_write(MAS_CONTROL
, 0x8c00);
281 panicf("mas_ctrl_w: %d", rc
);
283 /* Stop the current application */
285 mas_writemem(MAS_BANK_D0
, MAS_D0_APP_SELECT
, &val
, 1);
288 mas_readmem(MAS_BANK_D0
, MAS_D0_APP_RUNNING
, &val
, 1);
291 /* Enable the D/A Converter */
292 shadow_codec_reg0
= 0x0001;
293 mas_codec_writereg(0x0, shadow_codec_reg0
);
295 /* ADC scale 0%, DSP scale 100% */
296 mas_codec_writereg(6, 0x0000);
297 mas_codec_writereg(7, 0x4000);
299 #ifdef HAVE_SPDIF_OUT
300 val
= 0x09; /* Disable SDO and SDI, low impedance S/PDIF outputs */
302 val
= 0x2d; /* Disable SDO and SDI, disable S/PDIF output */
304 mas_writemem(MAS_BANK_D0
, MAS_D0_INTERFACE_CONTROL
, &val
, 1);
306 /* Set Demand mode and validate all settings */
307 shadow_io_control_main
= 0x25;
308 mas_writemem(MAS_BANK_D0
, MAS_D0_IO_CONTROL_MAIN
, &shadow_io_control_main
, 1);
310 /* Start the Layer2/3 decoder applications */
312 mas_writemem(MAS_BANK_D0
, MAS_D0_APP_SELECT
, &val
, 1);
315 mas_readmem(MAS_BANK_D0
, MAS_D0_APP_RUNNING
, &val
, 1);
316 } while((val
& 0x0c) != 0x0c);
318 #if CONFIG_CODEC == MAS3587F
319 mpeg_mode
= MPEG_DECODER
;
322 /* set IRQ6 to edge detect */
325 /* set IRQ6 prio 8 */
326 IPRB
= ( IPRB
& 0xff0f ) | 0x0080;
328 DEBUGF("MAS Decoding application started\n");
330 #endif /* #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
331 #endif /* SIMULATOR */
333 void mp3_init(int volume
, int bass
, int treble
, int balance
, int loudness
,
334 int avc
, int channel_config
, int stereo_width
,
335 int mdb_strength
, int mdb_harmonics
,
336 int mdb_center
, int mdb_shape
, bool mdb_enable
,
346 (void)channel_config
;
354 audio_is_initialized
= true;
356 #if CONFIG_CODEC == MAS3507D
370 #ifdef HAVE_MAS_SIBI_CONTROL
371 and_b(~0x01, &PBDRH
); /* drive SIBI low */
372 or_b(0x01, &PBIORH
); /* output for PB8 */
375 #if CONFIG_CODEC == MAS3507D
377 #elif CONFIG_CODEC == MAS3587F
378 or_b(0x08, &PAIORH
); /* output for /PR */
381 mas_version_code
= mas_readver();
382 DEBUGF("MAS3587 derivate %d, version %c%d\n",
383 (mas_version_code
& 0xf000) >> 12,
384 'A' + ((mas_version_code
& 0x0f00) >> 8), mas_version_code
& 0xff);
385 #elif CONFIG_CODEC == MAS3539F
386 or_b(0x08, &PAIORH
); /* output for /PR */
389 mas_version_code
= mas_readver();
390 DEBUGF("MAS3539 derivate %d, version %c%d\n",
391 (mas_version_code
& 0xf000) >> 12,
392 'A' + ((mas_version_code
& 0x0f00) >> 8), mas_version_code
& 0xff);
399 #if CONFIG_CODEC == MAS3507D
400 /* set IRQ6 to edge detect */
403 /* set IRQ6 prio 8 */
404 IPRB
= ( IPRB
& 0xff0f ) | 0x0080;
406 mas_readmem(MAS_BANK_D1
, 0xff7, &mas_version_code
, 1);
408 mas_writereg(0x3b, 0x20); /* Don't ask why. The data sheet doesn't say */
412 /* Clear the upper 12 bits of the 32-bit samples */
413 mas_writereg(0xc5, 0);
414 mas_writereg(0xc6, 0);
416 /* We need to set the PLL for a 14.31818MHz crystal */
417 if(mas_version_code
== 0x0601) /* Version F10? */
420 mas_writemem(MAS_BANK_D0
, 0x32d, &val
, 1);
422 mas_writemem(MAS_BANK_D0
, 0x32e, &val
, 1);
424 mas_writemem(MAS_BANK_D0
, 0x32f, &val
, 1);
430 mas_writemem(MAS_BANK_D0
, 0x36d, &val
, 1);
432 mas_writemem(MAS_BANK_D0
, 0x36e, &val
, 1);
434 mas_writemem(MAS_BANK_D0
, 0x36f, &val
, 1);
440 #if CONFIG_CODEC == MAS3507D
443 mas_writereg(MAS_REG_KPRESCALE
, 0xe9400);
447 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
448 ICR
&= ~0x0010; /* IRQ3 level sensitive */
449 PACR1
= (PACR1
& 0x3fff) | 0x4000; /* PA15 is IRQ3 */
452 /* Must be done before calling sound_set() */
453 audio_is_initialized
= true;
455 sound_set(SOUND_BASS
, bass
);
456 sound_set(SOUND_TREBLE
, treble
);
457 sound_set(SOUND_BALANCE
, balance
);
458 sound_set(SOUND_VOLUME
, volume
);
459 sound_set(SOUND_CHANNELS
, channel_config
);
460 sound_set(SOUND_STEREO_WIDTH
, stereo_width
);
462 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
463 sound_set(SOUND_LOUDNESS
, loudness
);
464 sound_set(SOUND_AVC
, avc
);
465 sound_set(SOUND_MDB_STRENGTH
, mdb_strength
);
466 sound_set(SOUND_MDB_HARMONICS
, mdb_harmonics
);
467 sound_set(SOUND_MDB_CENTER
, mdb_center
);
468 sound_set(SOUND_MDB_SHAPE
, mdb_shape
);
469 sound_set(SOUND_MDB_ENABLE
, mdb_enable
);
470 sound_set(SOUND_SUPERBASS
, superbass
);
472 #endif /* !SIMULATOR */
478 void mp3_shutdown(void)
481 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
482 unsigned long val
= 1;
483 mas_writemem(MAS_BANK_D0
, MAS_D0_SOFT_MUTE
, &val
, 1); /* Mute */
486 #if CONFIG_CODEC == MAS3507D
487 dac_volume(0, 0, false);
493 /* new functions, to be exported to plugin API */
497 void mp3_play_init(void)
499 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
504 callback_for_more
= NULL
;
505 mp3_reset_playtime();
508 void mp3_play_data(const unsigned char* start
, int size
,
509 void (*get_more
)(unsigned char** start
, size_t* size
) /* callback fn */
514 CHCR3
&= ~0x0002; /* Clear interrupt */
515 CHCR3
= 0x1504; /* Single address destination, TXI0, IE=1 */
516 DMAOR
= 0x0001; /* Enable DMA */
518 callback_for_more
= get_more
;
520 SAR3
= (unsigned int)start
;
521 DTCR3
= size
& 0xffff;
526 CHCR3
|= 0x0001; /* Enable DMA IRQ */
528 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
529 demand_irq_enable(true);
533 void mp3_play_pause(bool play
)
536 { /* resume playback */
539 playstart_tick
= current_tick
;
541 else if (!paused
&& !play
)
542 { /* stop playback */
545 cumulative_ticks
+= current_tick
- playstart_tick
;
549 bool mp3_pause_done(void)
551 unsigned long frame_count
;
556 mas_readmem(MAS_BANK_D0
, MAS_D0_MPEG_FRAME_COUNT
, &frame_count
, 1);
557 /* This works because the frame counter never wraps,
558 * i.e. zero always means lost sync. */
559 return frame_count
== 0;
562 void mp3_play_stop(void)
565 mp3_play_pause(false);
566 CHCR3
&= ~0x0001; /* Disable the DMA interrupt */
567 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
568 demand_irq_enable(false);
572 long mp3_get_playtime(void)
575 return cumulative_ticks
;
577 return cumulative_ticks
+ current_tick
- playstart_tick
;
580 void mp3_reset_playtime(void)
582 cumulative_ticks
= 0;
583 playstart_tick
= current_tick
;
586 bool mp3_is_playing(void)
592 /* returns the next byte position which would be transferred */
593 unsigned char* mp3_get_pos(void)
595 return (unsigned char*)SAR3
;
597 #else /* #ifndef SIMULATOR */
599 void mp3_play_pause(bool play
)
603 void mp3_play_stop(void)
607 unsigned char* mp3_get_pos(void)
612 void mp3_play_data(const unsigned char* start
, int size
,
613 void (*get_more
)(unsigned char** start
, size_t* size
) /* callback fn */
616 (void)start
; (void)size
; (void)get_more
;