diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/system.h | 13 | ||||
-rw-r--r-- | firmware/pcm_playback.c | 354 |
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 | ||
346 | static inline void enable_fiq(void) | 346 | static 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 | ||
357 | static 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 | |||
323 | static bool pcm_playing; | 325 | static bool pcm_playing; |
324 | static bool pcm_paused; | 326 | static bool pcm_paused; |
325 | static int pcm_freq = 0x6; /* 44.1 is default */ | 327 | static int pcm_freq = 0x6; /* 44.1 is default */ |
326 | 328 | ||
327 | /* the registered callback function to ask for more mp3 data */ | 329 | unsigned short* p IBSS_ATTR; |
328 | static void (*callback_for_more)(unsigned char**, size_t*) = NULL; | 330 | long p_size IBSS_ATTR; |
329 | static unsigned short *p IBSS_ATTR; | ||
330 | static size_t size IBSS_ATTR; | ||
331 | |||
332 | /* Stops the DMA transfer and interrupt */ | ||
333 | static void dma_stop(void) | ||
334 | { | ||
335 | pcm_playing = false; | ||
336 | 331 | ||
337 | p = NULL; | 332 | static 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 | |||
347 | void 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 | ||
367 | void 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 | ||
373 | void fiq(void) ICODE_ATTR; | 343 | /* Clear the FIQ disable bit in cpsr_c */ |
374 | void 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 | ||
400 | void 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) | 365 | static 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 */ | 380 | void 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) { | 386 | static 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) { | 388 | void 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; | 404 | size_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)) { | 409 | void 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 | ||
440 | void pcm_play_stop(void) | 416 | void pcm_play_stop(void) |
@@ -444,22 +420,66 @@ void pcm_play_stop(void) | |||
444 | } | 420 | } |
445 | } | 421 | } |
446 | 422 | ||
447 | void pcm_mute(bool mute) | ||
448 | { | ||
449 | (void)mute; | ||
450 | } | ||
451 | |||
452 | void pcm_play_pause(bool play) | 423 | void 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 | ||
477 | size_t pcm_get_bytes_waiting(void) | 497 | unsigned 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 | ||
488 | static bool pcm_playing; | 499 | void fiq(void) ICODE_ATTR; |
489 | static bool pcm_paused; | 500 | void fiq(void) |
490 | static int pcm_freq = 0x6; /* 44.1 is default */ | ||
491 | |||
492 | static unsigned char *next_start; | ||
493 | static long next_size; | ||
494 | |||
495 | /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ | ||
496 | static 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 */ |
524 | static 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 | |||
541 | void pcm_init(void) | 529 | void 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 | ||
561 | void 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 */ | ||
568 | static void (*callback_for_more)(unsigned char**, long*) = NULL; | ||
569 | |||
570 | void 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 | |||
583 | void pcm_play_stop(void) | ||
584 | { | ||
585 | if (pcm_playing) { | ||
586 | dma_stop(); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | void 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 | |||
605 | bool pcm_is_paused(void) | ||
606 | { | ||
607 | return pcm_paused; | ||
608 | } | ||
609 | |||
610 | bool pcm_is_playing(void) | ||
611 | { | ||
612 | return pcm_playing; | ||
613 | } | ||
614 | |||
615 | |||
616 | long 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; |