diff options
author | Timur Tabi <timur@freescale.com> | 2009-02-05 18:56:02 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-02-06 07:08:15 -0500 |
commit | 85ef2375ef2ebbb2bf660ad3a27c644d0ebf1b1a (patch) | |
tree | bc4b8904b3d74437f03744ecc37bb0a79828b027 /sound/soc | |
parent | 8836c273e4d44d088157b7ccbd2c108cefe70565 (diff) |
ASoC: optimize init sequence of Freescale MPC8610 sound drivers
In the Freescale MPC8610 sound drivers, relocate all code from the _prepare
functions into the corresponding _hw_params functions. These drivers assumed
that the sample size is known in the _prepare function and not in the
_hw_params function, but this is not true.
Move the code in fsl_dma_prepare() into fsl_dma_hw_param(). Create
fsl_ssi_hw_params() and move the code from fsl_ssi_prepare() into it.
Turn off snooping for DMA operations to/from I/O registers, since that's not
necessary.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/fsl/fsl_dma.c | 178 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 19 |
2 files changed, 94 insertions, 103 deletions
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 64993eda5679..58a3fa497503 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -464,11 +464,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
464 | sizeof(struct fsl_dma_link_descriptor); | 464 | sizeof(struct fsl_dma_link_descriptor); |
465 | 465 | ||
466 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 466 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
467 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 467 | dma_private->link[i].next = cpu_to_be64(temp_link); |
468 | |||
469 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
470 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
471 | link->next = cpu_to_be64(temp_link); | ||
472 | 468 | ||
473 | temp_link += sizeof(struct fsl_dma_link_descriptor); | 469 | temp_link += sizeof(struct fsl_dma_link_descriptor); |
474 | } | 470 | } |
@@ -525,79 +521,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
525 | * This function obtains hardware parameters about the opened stream and | 521 | * This function obtains hardware parameters about the opened stream and |
526 | * programs the DMA controller accordingly. | 522 | * programs the DMA controller accordingly. |
527 | * | 523 | * |
528 | * Note that due to a quirk of the SSI's STX register, the target address | 524 | * One drawback of big-endian is that when copying integers of different |
529 | * for the DMA operations depends on the sample size. So we don't program | 525 | * sizes to a fixed-sized register, the address to which the integer must be |
530 | * the dest_addr (for playback -- source_addr for capture) fields in the | 526 | * copied is dependent on the size of the integer. |
531 | * link descriptors here. We do that in fsl_dma_prepare() | ||
532 | */ | ||
533 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | ||
534 | struct snd_pcm_hw_params *hw_params) | ||
535 | { | ||
536 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
537 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
538 | |||
539 | dma_addr_t temp_addr; /* Pointer to next period */ | ||
540 | |||
541 | unsigned int i; | ||
542 | |||
543 | /* Get all the parameters we need */ | ||
544 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
545 | size_t period_size = params_period_bytes(hw_params); | ||
546 | |||
547 | /* Initialize our DMA tracking variables */ | ||
548 | dma_private->period_size = period_size; | ||
549 | dma_private->num_periods = params_periods(hw_params); | ||
550 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
551 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
552 | (NUM_DMA_LINKS * period_size); | ||
553 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
554 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
555 | |||
556 | /* | ||
557 | * The actual address in STX0 (destination for playback, source for | ||
558 | * capture) is based on the sample size, but we don't know the sample | ||
559 | * size in this function, so we'll have to adjust that later. See | ||
560 | * comments in fsl_dma_prepare(). | ||
561 | * | ||
562 | * The DMA controller does not have a cache, so the CPU does not | ||
563 | * need to tell it to flush its cache. However, the DMA | ||
564 | * controller does need to tell the CPU to flush its cache. | ||
565 | * That's what the SNOOP bit does. | ||
566 | * | ||
567 | * Also, even though the DMA controller supports 36-bit addressing, for | ||
568 | * simplicity we currently support only 32-bit addresses for the audio | ||
569 | * buffer itself. | ||
570 | */ | ||
571 | temp_addr = substream->dma_buffer.addr; | ||
572 | |||
573 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
574 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
575 | |||
576 | link->count = cpu_to_be32(period_size); | ||
577 | |||
578 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
579 | link->source_addr = cpu_to_be32(temp_addr); | ||
580 | else | ||
581 | link->dest_addr = cpu_to_be32(temp_addr); | ||
582 | |||
583 | temp_addr += period_size; | ||
584 | } | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /** | ||
590 | * fsl_dma_prepare - prepare the DMA registers for playback. | ||
591 | * | ||
592 | * This function is called after the specifics of the audio data are known, | ||
593 | * i.e. snd_pcm_runtime is initialized. | ||
594 | * | ||
595 | * In this function, we finish programming the registers of the DMA | ||
596 | * controller that are dependent on the sample size. | ||
597 | * | ||
598 | * One of the drawbacks with big-endian is that when copying integers of | ||
599 | * different sizes to a fixed-sized register, the address to which the | ||
600 | * integer must be copied is dependent on the size of the integer. | ||
601 | * | 527 | * |
602 | * For example, if P is the address of a 32-bit register, and X is a 32-bit | 528 | * For example, if P is the address of a 32-bit register, and X is a 32-bit |
603 | * integer, then X should be copied to address P. However, if X is a 16-bit | 529 | * integer, then X should be copied to address P. However, if X is a 16-bit |
@@ -613,22 +539,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
613 | * and 8 bytes at a time). So we do not support packed 24-bit samples. | 539 | * and 8 bytes at a time). So we do not support packed 24-bit samples. |
614 | * 24-bit data must be padded to 32 bits. | 540 | * 24-bit data must be padded to 32 bits. |
615 | */ | 541 | */ |
616 | static int fsl_dma_prepare(struct snd_pcm_substream *substream) | 542 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, |
543 | struct snd_pcm_hw_params *hw_params) | ||
617 | { | 544 | { |
618 | struct snd_pcm_runtime *runtime = substream->runtime; | 545 | struct snd_pcm_runtime *runtime = substream->runtime; |
619 | struct fsl_dma_private *dma_private = runtime->private_data; | 546 | struct fsl_dma_private *dma_private = runtime->private_data; |
547 | |||
548 | /* Number of bits per sample */ | ||
549 | unsigned int sample_size = | ||
550 | snd_pcm_format_physical_width(params_format(hw_params)); | ||
551 | |||
552 | /* Number of bytes per frame */ | ||
553 | unsigned int frame_size = 2 * (sample_size / 8); | ||
554 | |||
555 | /* Bus address of SSI STX register */ | ||
556 | dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; | ||
557 | |||
558 | /* Size of the DMA buffer, in bytes */ | ||
559 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
560 | |||
561 | /* Number of bytes per period */ | ||
562 | size_t period_size = params_period_bytes(hw_params); | ||
563 | |||
564 | /* Pointer to next period */ | ||
565 | dma_addr_t temp_addr = substream->dma_buffer.addr; | ||
566 | |||
567 | /* Pointer to DMA controller */ | ||
620 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | 568 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; |
621 | u32 mr; | 569 | |
570 | u32 mr; /* DMA Mode Register */ | ||
571 | |||
622 | unsigned int i; | 572 | unsigned int i; |
623 | dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */ | ||
624 | unsigned int frame_size; /* Number of bytes per frame */ | ||
625 | 573 | ||
626 | ssi_sxx_phys = dma_private->ssi_sxx_phys; | 574 | /* Initialize our DMA tracking variables */ |
575 | dma_private->period_size = period_size; | ||
576 | dma_private->num_periods = params_periods(hw_params); | ||
577 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
578 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
579 | (NUM_DMA_LINKS * period_size); | ||
580 | |||
581 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
582 | /* This happens if the number of periods == NUM_DMA_LINKS */ | ||
583 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
627 | 584 | ||
628 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | | 585 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | |
629 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); | 586 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); |
630 | 587 | ||
631 | switch (runtime->sample_bits) { | 588 | /* Due to a quirk of the SSI's STX register, the target address |
589 | * for the DMA operations depends on the sample size. So we calculate | ||
590 | * that offset here. While we're at it, also tell the DMA controller | ||
591 | * how much data to transfer per sample. | ||
592 | */ | ||
593 | switch (sample_size) { | ||
632 | case 8: | 594 | case 8: |
633 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; | 595 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; |
634 | ssi_sxx_phys += 3; | 596 | ssi_sxx_phys += 3; |
@@ -641,12 +603,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
641 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; | 603 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; |
642 | break; | 604 | break; |
643 | default: | 605 | default: |
606 | /* We should never get here */ | ||
644 | dev_err(substream->pcm->card->dev, | 607 | dev_err(substream->pcm->card->dev, |
645 | "unsupported sample size %u\n", runtime->sample_bits); | 608 | "unsupported sample size %u\n", sample_size); |
646 | return -EINVAL; | 609 | return -EINVAL; |
647 | } | 610 | } |
648 | 611 | ||
649 | frame_size = runtime->frame_bits / 8; | ||
650 | /* | 612 | /* |
651 | * BWC should always be a multiple of the frame size. BWC determines | 613 | * BWC should always be a multiple of the frame size. BWC determines |
652 | * how many bytes are sent/received before the DMA controller checks the | 614 | * how many bytes are sent/received before the DMA controller checks the |
@@ -655,7 +617,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
655 | * capture, the receive FIFO is triggered when it contains one frame, so | 617 | * capture, the receive FIFO is triggered when it contains one frame, so |
656 | * we want to receive one frame at a time. | 618 | * we want to receive one frame at a time. |
657 | */ | 619 | */ |
658 | |||
659 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 620 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
660 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); | 621 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); |
661 | else | 622 | else |
@@ -663,16 +624,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
663 | 624 | ||
664 | out_be32(&dma_channel->mr, mr); | 625 | out_be32(&dma_channel->mr, mr); |
665 | 626 | ||
666 | /* | ||
667 | * Program the address of the DMA transfer to/from the SSI. | ||
668 | */ | ||
669 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 627 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
670 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 628 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; |
671 | 629 | ||
672 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 630 | link->count = cpu_to_be32(period_size); |
631 | |||
632 | /* Even though the DMA controller supports 36-bit addressing, | ||
633 | * for simplicity we allow only 32-bit addresses for the audio | ||
634 | * buffer itself. This was enforced in fsl_dma_new() with the | ||
635 | * DMA mask. | ||
636 | * | ||
637 | * The snoop bit tells the DMA controller whether it should tell | ||
638 | * the ECM to snoop during a read or write to an address. For | ||
639 | * audio, we use DMA to transfer data between memory and an I/O | ||
640 | * device (the SSI's STX0 or SRX0 register). Snooping is only | ||
641 | * needed if there is a cache, so we need to snoop memory | ||
642 | * addresses only. For playback, that means we snoop the source | ||
643 | * but not the destination. For capture, we snoop the | ||
644 | * destination but not the source. | ||
645 | * | ||
646 | * Note that failing to snoop properly is unlikely to cause | ||
647 | * cache incoherency if the period size is larger than the | ||
648 | * size of L1 cache. This is because filling in one period will | ||
649 | * flush out the data for the previous period. So if you | ||
650 | * increased period_bytes_min to a large enough size, you might | ||
651 | * get more performance by not snooping, and you'll still be | ||
652 | * okay. | ||
653 | */ | ||
654 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
655 | link->source_addr = cpu_to_be32(temp_addr); | ||
656 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
657 | |||
673 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); | 658 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); |
674 | else | 659 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); |
660 | } else { | ||
675 | link->source_addr = cpu_to_be32(ssi_sxx_phys); | 661 | link->source_addr = cpu_to_be32(ssi_sxx_phys); |
662 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); | ||
663 | |||
664 | link->dest_addr = cpu_to_be32(temp_addr); | ||
665 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
666 | } | ||
667 | |||
668 | temp_addr += period_size; | ||
676 | } | 669 | } |
677 | 670 | ||
678 | return 0; | 671 | return 0; |
@@ -808,7 +801,6 @@ static struct snd_pcm_ops fsl_dma_ops = { | |||
808 | .ioctl = snd_pcm_lib_ioctl, | 801 | .ioctl = snd_pcm_lib_ioctl, |
809 | .hw_params = fsl_dma_hw_params, | 802 | .hw_params = fsl_dma_hw_params, |
810 | .hw_free = fsl_dma_hw_free, | 803 | .hw_free = fsl_dma_hw_free, |
811 | .prepare = fsl_dma_prepare, | ||
812 | .pointer = fsl_dma_pointer, | 804 | .pointer = fsl_dma_pointer, |
813 | }; | 805 | }; |
814 | 806 | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6d6eb71dc1d..6844009833db 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -400,7 +400,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
400 | } | 400 | } |
401 | 401 | ||
402 | /** | 402 | /** |
403 | * fsl_ssi_prepare: prepare the SSI. | 403 | * fsl_ssi_hw_params - program the sample size |
404 | * | 404 | * |
405 | * Most of the SSI registers have been programmed in the startup function, | 405 | * Most of the SSI registers have been programmed in the startup function, |
406 | * but the word length must be programmed here. Unfortunately, programming | 406 | * but the word length must be programmed here. Unfortunately, programming |
@@ -412,20 +412,19 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
412 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the | 412 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the |
413 | * clock master. | 413 | * clock master. |
414 | */ | 414 | */ |
415 | static int fsl_ssi_prepare(struct snd_pcm_substream *substream, | 415 | static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, |
416 | struct snd_soc_dai *dai) | 416 | struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) |
417 | { | 417 | { |
418 | struct snd_pcm_runtime *runtime = substream->runtime; | 418 | struct fsl_ssi_private *ssi_private = cpu_dai->private_data; |
419 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
420 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
421 | |||
422 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
423 | 419 | ||
424 | if (substream == ssi_private->first_stream) { | 420 | if (substream == ssi_private->first_stream) { |
421 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
422 | unsigned int sample_size = | ||
423 | snd_pcm_format_width(params_format(hw_params)); | ||
425 | u32 wl; | 424 | u32 wl; |
426 | 425 | ||
427 | /* The SSI should always be disabled at this points (SSIEN=0) */ | 426 | /* The SSI should always be disabled at this points (SSIEN=0) */ |
428 | wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format)); | 427 | wl = CCSR_SSI_SxCCR_WL(sample_size); |
429 | 428 | ||
430 | /* In synchronous mode, the SSI uses STCCR for capture */ | 429 | /* In synchronous mode, the SSI uses STCCR for capture */ |
431 | clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); | 430 | clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); |
@@ -579,7 +578,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = { | |||
579 | }, | 578 | }, |
580 | .ops = { | 579 | .ops = { |
581 | .startup = fsl_ssi_startup, | 580 | .startup = fsl_ssi_startup, |
582 | .prepare = fsl_ssi_prepare, | 581 | .hw_params = fsl_ssi_hw_params, |
583 | .shutdown = fsl_ssi_shutdown, | 582 | .shutdown = fsl_ssi_shutdown, |
584 | .trigger = fsl_ssi_trigger, | 583 | .trigger = fsl_ssi_trigger, |
585 | .set_sysclk = fsl_ssi_set_sysclk, | 584 | .set_sysclk = fsl_ssi_set_sysclk, |