summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/system.h13
-rw-r--r--firmware/pcm_playback.c354
2 files changed, 153 insertions, 214 deletions
diff --git a/firmware/export/system.h b/firmware/export/system.h
index 380c229f1d..e88c793fae 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -345,7 +345,7 @@ static inline int set_irq_level(int level)
345 345
346static inline void enable_fiq(void) 346static inline void enable_fiq(void)
347{ 347{
348 /* enable FIQ */ 348 /* Clear FIQ disable bit */
349 asm volatile ( 349 asm volatile (
350 "mrs r0, cpsr \n"\ 350 "mrs r0, cpsr \n"\
351 "bic r0, r0, #0x40 \n"\ 351 "bic r0, r0, #0x40 \n"\
@@ -354,6 +354,17 @@ static inline void enable_fiq(void)
354 ); 354 );
355} 355}
356 356
357static inline void disable_fiq(void)
358{
359 /* Set FIQ disable bit */
360 asm volatile (
361 "mrs r0, cpsr \n"\
362 "orr r0, r0, #0x40 \n"\
363 "msr cpsr_c, r0 "
364 : : : "r0"
365 );
366}
367
357#define invalidate_icache() 368#define invalidate_icache()
358 369
359#if CONFIG_CPU == PNX0101 370#if CONFIG_CPU == PNX0101
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index d3e9f3eca5..5161a38e20 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -320,68 +320,36 @@ void pcm_init(void)
320 we will keep it separate during early development. 320 we will keep it separate during early development.
321*/ 321*/
322 322
323#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f0000) >> 16)
324
323static bool pcm_playing; 325static bool pcm_playing;
324static bool pcm_paused; 326static bool pcm_paused;
325static int pcm_freq = 0x6; /* 44.1 is default */ 327static int pcm_freq = 0x6; /* 44.1 is default */
326 328
327/* the registered callback function to ask for more mp3 data */ 329unsigned short* p IBSS_ATTR;
328static void (*callback_for_more)(unsigned char**, size_t*) = NULL; 330long p_size IBSS_ATTR;
329static unsigned short *p IBSS_ATTR;
330static size_t size IBSS_ATTR;
331
332/* Stops the DMA transfer and interrupt */
333static void dma_stop(void)
334{
335 pcm_playing = false;
336 331
337 p = NULL; 332static void dma_start(const void *addr, size_t size)
338 size = 0;
339 callback_for_more = NULL;
340 pcm_paused = false;
341
342 /* Disable playback FIFO */
343 IISCONFIG &= ~0x20000000;
344 // TODO: ??? disable_fiq();
345}
346
347void pcm_init(void)
348{ 333{
349 pcm_playing = false; 334 p=(unsigned short*)addr;
350 pcm_paused = false; 335 p_size=size;
351
352 /* Initialize default register values. */
353 wm8975_init();
354
355 /* The uda1380 needs a sleep(HZ) here - do we need one? */
356 336
357 /* Power on */ 337 pcm_playing = true;
358 wm8975_enable_output(true);
359
360 /* Unmute the master channel (DAC should be at zero point now). */
361 wm8975_mute(false);
362
363 /* Call dma_stop to initialize everything. */
364 dma_stop();
365}
366 338
367void pcm_set_frequency(unsigned int frequency) 339 /* setup I2S interrupt for FIQ */
368{ 340 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
369 (void)frequency; 341 outl(I2S_MASK, 0x60004024);
370 pcm_freq=frequency;
371}
372 342
373void fiq(void) ICODE_ATTR; 343 /* Clear the FIQ disable bit in cpsr_c */
374void fiq(void) 344 enable_fiq();
375{
376 /* Clear interrupt */
377 IISCONFIG &= ~0x2;
378 345
379 if ((size==0) && (callback_for_more)) { 346 /* Enable playback FIFO */
380 callback_for_more((unsigned char **)&p, &size); 347 IISCONFIG |= 0x20000000;
381 }
382 348
383 while (size > 0) { 349 /* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
384 if (((inl(0x7000280c) & 0x3f0000) >> 16) < 2) { 350 fill the 32-byte FIFO. */
351 while (p_size > 0) {
352 if (FIFO_FREE_COUNT < 2) {
385 /* Enable interrupt */ 353 /* Enable interrupt */
386 IISCONFIG |= 0x2; 354 IISCONFIG |= 0x2;
387 return; 355 return;
@@ -389,52 +357,60 @@ void fiq(void)
389 357
390 IISFIFO_WR = (*(p++))<<16; 358 IISFIFO_WR = (*(p++))<<16;
391 IISFIFO_WR = (*(p++))<<16; 359 IISFIFO_WR = (*(p++))<<16;
392 size-=4; 360 p_size-=4;
393
394 if ((size==0) && (callback_for_more)) {
395 callback_for_more((unsigned char **)&p, &size);
396 }
397 } 361 }
398} 362}
399 363
400void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), 364/* Stops the DMA transfer and interrupt */
401 unsigned char* _p, size_t _size) 365static void dma_stop(void)
402{ 366{
403 size_t free_count; 367 pcm_playing = false;
404
405 callback_for_more = get_more;
406 368
407 if (size > 0) { return; } 369 /* Disable playback FIFO */
370 IISCONFIG &= ~0x20000000;
408 371
409 p = (unsigned short *)_p; 372 /* Disable the interrupt */
410 size = _size; 373 IISCONFIG &= ~0x2;
411 374
412 /* setup I2S interrupt for FIQ */ 375 disable_fiq();
413 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
414 outl(I2S_MASK, 0x60004024);
415 376
416 enable_fiq(); /* Clear the FIQ disable bit in cpsr_c */ 377 pcm_paused = false;
378}
417 379
418 IISCONFIG |= 0x20000000; /* Enable playback FIFO */ 380void pcm_set_frequency(unsigned int frequency)
381{
382 pcm_freq=frequency;
383}
419 384
420 /* Fill the FIFO */ 385/* the registered callback function to ask for more PCM data */
421 while (size > 0) { 386static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL;
422 free_count = (inl(0x7000280c) & 0x3f0000) >> 16;
423 387
424 if (free_count < 2) { 388void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
425 /* Enable interrupt */ 389 unsigned char* start, size_t size)
426 IISCONFIG |= 0x2; 390{
391 callback_for_more = get_more;
392
393 if (!(start && size))
394 {
395 if (get_more)
396 get_more(&start, &size);
397 else
427 return; 398 return;
428 } 399 }
400 if (start && size)
401 dma_start(start, size);
402}
429 403
430 IISFIFO_WR = (*(p++))<<16; 404size_t pcm_get_bytes_waiting(void)
431 IISFIFO_WR = (*(p++))<<16; 405{
432 size-=4; 406 return p_size;
407}
433 408
434 if ((size==0) && (get_more)) { 409void pcm_mute(bool mute)
435 get_more((unsigned char **)&p, &size); 410{
436 } 411 wm8975_mute(mute);
437 } 412 if (mute)
413 sleep(HZ/16);
438} 414}
439 415
440void pcm_play_stop(void) 416void pcm_play_stop(void)
@@ -444,22 +420,66 @@ void pcm_play_stop(void)
444 } 420 }
445} 421}
446 422
447void pcm_mute(bool mute)
448{
449 (void)mute;
450}
451
452void pcm_play_pause(bool play) 423void pcm_play_pause(bool play)
453{ 424{
454 if(pcm_paused && play && size) 425 size_t next_size;
426 unsigned char *next_start;
427
428 if (!pcm_playing)
429 return ;
430
431 if(pcm_paused && play)
455 { 432 {
456 logf("unpause"); 433 if (pcm_get_bytes_waiting())
457 /* We need to enable DMA here */ 434 {
435 logf("unpause");
436 /* Enable the FIFO and fill it */
437
438 enable_fiq();
439
440 /* Enable playback FIFO */
441 IISCONFIG |= 0x20000000;
442
443 /* Fill the FIFO - we assume there are enough bytes in the
444 pcm buffer to fill the 32-byte FIFO. */
445 while (p_size > 0) {
446 if (FIFO_FREE_COUNT < 2) {
447 /* Enable interrupt */
448 IISCONFIG |= 0x2;
449 return;
450 }
451
452 IISFIFO_WR = (*(p++))<<16;
453 IISFIFO_WR = (*(p++))<<16;
454 p_size-=4;
455 }
456 }
457 else
458 {
459 logf("unpause, no data waiting");
460 void (*get_more)(unsigned char**, size_t*) = callback_for_more;
461 if (get_more)
462 get_more(&next_start, &next_size);
463 if (next_start && next_size)
464 dma_start(next_start, next_size);
465 else
466 {
467 dma_stop();
468 logf("unpause attempted, no data");
469 }
470 }
458 } 471 }
459 else if(!pcm_paused && !play) 472 else if(!pcm_paused && !play)
460 { 473 {
461 logf("pause"); 474 logf("pause");
462 /* We need to disable DMA here */ 475
476 /* Disable the interrupt */
477 IISCONFIG &= ~0x2;
478
479 /* Disable playback FIFO */
480 IISCONFIG &= ~0x20000000;
481
482 disable_fiq();
463 } 483 }
464 pcm_paused = !play; 484 pcm_paused = !play;
465} 485}
@@ -474,150 +494,58 @@ bool pcm_is_playing(void)
474 return pcm_playing; 494 return pcm_playing;
475} 495}
476 496
477size_t pcm_get_bytes_waiting(void) 497unsigned int fiq_count IBSS_ATTR;
478{
479 return size;
480}
481
482#elif defined(HAVE_WM8731L)
483
484/* We need to unify this code with the uda1380 code as much as possible, but
485 we will keep it separate during early development.
486*/
487 498
488static bool pcm_playing; 499void fiq(void) ICODE_ATTR;
489static bool pcm_paused; 500void fiq(void)
490static int pcm_freq = 0x6; /* 44.1 is default */
491
492static unsigned char *next_start;
493static long next_size;
494
495/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
496static void dma_start(const void *addr, long size)
497{ 501{
498 pcm_playing = true; 502 /* Clear interrupt */
499 503 IISCONFIG &= ~0x2;
500 addr = (void *)((unsigned long)addr & ~3); /* Align data */
501 size &= ~3; /* Size must be multiple of 4 */
502
503 /* Disable playback for now */
504 pcm_playing = false;
505 return;
506
507/* This is the uda1380 code */
508#if 0
509 /* Reset the audio FIFO */
510
511 /* Set up DMA transfer */
512 SAR0 = ((unsigned long)addr); /* Source address */
513 DAR0 = (unsigned long)&PDOR3; /* Destination address */
514 BCR0 = size; /* Bytes to transfer */
515 504
516 /* Enable the FIFO and force one write to it */ 505 fiq_count++;
517 IIS2CONFIG = IIS_DEFPARM(pcm_freq); 506 do {
507 while (p_size) {
508 if (FIFO_FREE_COUNT < 2) {
509 /* Enable interrupt */
510 IISCONFIG |= 0x2;
511 return;
512 }
518 513
519 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_SINC | DMA_START; 514 IISFIFO_WR = (*(p++))<<16;
520#endif 515 IISFIFO_WR = (*(p++))<<16;
521} 516 p_size-=4;
517 }
522 518
523/* Stops the DMA transfer and interrupt */ 519 /* p is empty, get some more data */
524static void dma_stop(void) 520 if (callback_for_more) {
525{ 521 callback_for_more((unsigned char**)&p,&p_size);
526 pcm_playing = false; 522 }
523 } while (p_size);
527 524
528#if 0 525 /* No more data, so disable the FIFO/FIQ */
529/* This is the uda1380 code */ 526 dma_stop();
530 DCR0 = 0;
531 DSR0 = 1;
532 /* Reset the FIFO */
533 IIS2CONFIG = IIS_RESET | IIS_DEFPARM(pcm_freq);
534#endif
535 next_start = NULL;
536 next_size = 0;
537 pcm_paused = false;
538} 527}
539 528
540
541void pcm_init(void) 529void pcm_init(void)
542{ 530{
543 pcm_playing = false; 531 pcm_playing = false;
544 pcm_paused = false; 532 pcm_paused = false;
545 533
546 /* Initialize default register values. */ 534 /* Initialize default register values. */
547 wm8731l_init(); 535 wm8975_init();
548 536
549 /* The uda1380 needs a sleep(HZ) here - do we need one? */ 537 /* The uda1380 needs a sleep(HZ) here - do we need one? */
550 538
551 /* Power on */ 539 /* Power on */
552 wm8731l_enable_output(true); 540 wm8975_enable_output(true);
553 541
554 /* Unmute the master channel (DAC should be at zero point now). */ 542 /* Unmute the master channel (DAC should be at zero point now). */
555 wm8731l_mute(false); 543 wm8975_mute(false);
556 544
557 /* Call dma_stop to initialize everything. */ 545 /* Call dma_stop to initialize everything. */
558 dma_stop(); 546 dma_stop();
559} 547}
560 548
561void pcm_set_frequency(unsigned int frequency)
562{
563 (void)frequency;
564 pcm_freq=frequency;
565}
566
567/* the registered callback function to ask for more mp3 data */
568static void (*callback_for_more)(unsigned char**, long*) = NULL;
569
570void pcm_play_data(void (*get_more)(unsigned char** start, long* size))
571{
572 unsigned char *start;
573 long size;
574
575 callback_for_more = get_more;
576
577 get_more((unsigned char **)&start, (long *)&size);
578 get_more(&next_start, &next_size);
579
580 dma_start(start, size);
581}
582
583void pcm_play_stop(void)
584{
585 if (pcm_playing) {
586 dma_stop();
587 }
588}
589
590void pcm_play_pause(bool play)
591{
592 if(pcm_paused && play && next_size)
593 {
594 logf("unpause");
595 /* We need to enable DMA here */
596 }
597 else if(!pcm_paused && !play)
598 {
599 logf("pause");
600 /* We need to disable DMA here */
601 }
602 pcm_paused = !play;
603}
604
605bool pcm_is_paused(void)
606{
607 return pcm_paused;
608}
609
610bool pcm_is_playing(void)
611{
612 return pcm_playing;
613}
614
615
616long pcm_get_bytes_waiting(void)
617{
618 return 0;
619}
620
621#elif CONFIG_CPU == PNX0101 549#elif CONFIG_CPU == PNX0101
622 550
623/* TODO: Implement for iFP7xx 551/* TODO: Implement for iFP7xx
@@ -698,7 +626,7 @@ void pcm_calculate_peaks(int *left, int *right)
698 long samples = (BCR0 & 0xffffff) / 4; 626 long samples = (BCR0 & 0xffffff) / 4;
699 short *addr = (short *) (SAR0 & ~3); 627 short *addr = (short *) (SAR0 & ~3);
700#elif defined(HAVE_WM8975) 628#elif defined(HAVE_WM8975)
701 long samples = size / 4; 629 long samples = p_size / 4;
702 short *addr = p; 630 short *addr = p;
703#elif defined(HAVE_WM8731L) 631#elif defined(HAVE_WM8731L)
704 long samples = next_size / 4; 632 long samples = next_size / 4;