diff options
author | Timur Tabi <timur@freescale.com> | 2010-08-02 13:44:36 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-08-12 09:00:16 -0400 |
commit | 1a3c5a491af6756dbba6ee166a9dee72bb414ba8 (patch) | |
tree | 68544188a561476d6070417f147b76b00c216c6b /sound | |
parent | 6e6f66226f0092a39526f8d6f02ebb447d995be2 (diff) |
asoc/multi-component: fsl: add support for 36-bit physical addresses
Update the DMA driver used by the Freescale MPC8610 HPCD audio driver to
support 36-bit physical addresses, for both DMA buffers and the SSI registers.
The DMA driver calls snd_dma_alloc_pages() to allocate the DMA buffers for
playback and capture. This function is just a front-end for
dma_alloc_coherent(). Currently, dma_alloc_coherent() only allocates buffers
in low memory (it ignores GFP_HIGHMEM), so we never actually get a DMA buffer
with a real 36-bit physical address.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/fsl/fsl_dma.c | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index d09e1941b1fa..4450f9d845c6 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -175,13 +175,23 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private) | |||
175 | struct fsl_dma_link_descriptor *link = | 175 | struct fsl_dma_link_descriptor *link = |
176 | &dma_private->link[dma_private->current_link]; | 176 | &dma_private->link[dma_private->current_link]; |
177 | 177 | ||
178 | /* Update our link descriptors to point to the next period */ | 178 | /* Update our link descriptors to point to the next period. On a 36-bit |
179 | if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 179 | * system, we also need to update the ESAD bits. We also set (keep) the |
180 | link->source_addr = | 180 | * snoop bits. See the comments in fsl_dma_hw_params() about snooping. |
181 | cpu_to_be32(dma_private->dma_buf_next); | 181 | */ |
182 | else | 182 | if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
183 | link->dest_addr = | 183 | link->source_addr = cpu_to_be32(dma_private->dma_buf_next); |
184 | cpu_to_be32(dma_private->dma_buf_next); | 184 | #ifdef CONFIG_PHYS_64BIT |
185 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | | ||
186 | upper_32_bits(dma_private->dma_buf_next)); | ||
187 | #endif | ||
188 | } else { | ||
189 | link->dest_addr = cpu_to_be32(dma_private->dma_buf_next); | ||
190 | #ifdef CONFIG_PHYS_64BIT | ||
191 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | | ||
192 | upper_32_bits(dma_private->dma_buf_next)); | ||
193 | #endif | ||
194 | } | ||
185 | 195 | ||
186 | /* Update our variables for next time */ | 196 | /* Update our variables for next time */ |
187 | dma_private->dma_buf_next += dma_private->period_size; | 197 | dma_private->dma_buf_next += dma_private->period_size; |
@@ -273,11 +283,19 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) | |||
273 | * This function is called when the codec driver calls snd_soc_new_pcms(), | 283 | * This function is called when the codec driver calls snd_soc_new_pcms(), |
274 | * once for each .dai_link in the machine driver's snd_soc_card | 284 | * once for each .dai_link in the machine driver's snd_soc_card |
275 | * structure. | 285 | * structure. |
286 | * | ||
287 | * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which | ||
288 | * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM | ||
289 | * is specified. Therefore, any DMA buffers we allocate will always be in low | ||
290 | * memory, but we support for 36-bit physical addresses anyway. | ||
291 | * | ||
292 | * Regardless of where the memory is actually allocated, since the device can | ||
293 | * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. | ||
276 | */ | 294 | */ |
277 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, | 295 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, |
278 | struct snd_pcm *pcm) | 296 | struct snd_pcm *pcm) |
279 | { | 297 | { |
280 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); | 298 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); |
281 | int ret; | 299 | int ret; |
282 | 300 | ||
283 | if (!card->dev->dma_mask) | 301 | if (!card->dev->dma_mask) |
@@ -609,12 +627,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
609 | 627 | ||
610 | link->count = cpu_to_be32(period_size); | 628 | link->count = cpu_to_be32(period_size); |
611 | 629 | ||
612 | /* Even though the DMA controller supports 36-bit addressing, | 630 | /* The snoop bit tells the DMA controller whether it should tell |
613 | * for simplicity we allow only 32-bit addresses for the audio | ||
614 | * buffer itself. This was enforced in fsl_dma_new() with the | ||
615 | * DMA mask. | ||
616 | * | ||
617 | * The snoop bit tells the DMA controller whether it should tell | ||
618 | * the ECM to snoop during a read or write to an address. For | 631 | * the ECM to snoop during a read or write to an address. For |
619 | * audio, we use DMA to transfer data between memory and an I/O | 632 | * audio, we use DMA to transfer data between memory and an I/O |
620 | * device (the SSI's STX0 or SRX0 register). Snooping is only | 633 | * device (the SSI's STX0 or SRX0 register). Snooping is only |
@@ -629,20 +642,24 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
629 | * flush out the data for the previous period. So if you | 642 | * flush out the data for the previous period. So if you |
630 | * increased period_bytes_min to a large enough size, you might | 643 | * increased period_bytes_min to a large enough size, you might |
631 | * get more performance by not snooping, and you'll still be | 644 | * get more performance by not snooping, and you'll still be |
632 | * okay. | 645 | * okay. You'll need to update fsl_dma_update_pointers() also. |
633 | */ | 646 | */ |
634 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 647 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
635 | link->source_addr = cpu_to_be32(temp_addr); | 648 | link->source_addr = cpu_to_be32(temp_addr); |
636 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | 649 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | |
650 | upper_32_bits(temp_addr)); | ||
637 | 651 | ||
638 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); | 652 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); |
639 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); | 653 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | |
654 | upper_32_bits(ssi_sxx_phys)); | ||
640 | } else { | 655 | } else { |
641 | link->source_addr = cpu_to_be32(ssi_sxx_phys); | 656 | link->source_addr = cpu_to_be32(ssi_sxx_phys); |
642 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); | 657 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | |
658 | upper_32_bits(ssi_sxx_phys)); | ||
643 | 659 | ||
644 | link->dest_addr = cpu_to_be32(temp_addr); | 660 | link->dest_addr = cpu_to_be32(temp_addr); |
645 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | 661 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | |
662 | upper_32_bits(temp_addr)); | ||
646 | } | 663 | } |
647 | 664 | ||
648 | temp_addr += period_size; | 665 | temp_addr += period_size; |
@@ -673,10 +690,23 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) | |||
673 | dma_addr_t position; | 690 | dma_addr_t position; |
674 | snd_pcm_uframes_t frames; | 691 | snd_pcm_uframes_t frames; |
675 | 692 | ||
676 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 693 | /* Obtain the current DMA pointer, but don't read the ESAD bits if we |
694 | * only have 32-bit DMA addresses. This function is typically called | ||
695 | * in interrupt context, so we need to optimize it. | ||
696 | */ | ||
697 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
677 | position = in_be32(&dma_channel->sar); | 698 | position = in_be32(&dma_channel->sar); |
678 | else | 699 | #ifdef CONFIG_PHYS_64BIT |
700 | position |= (u64)(in_be32(&dma_channel->satr) & | ||
701 | CCSR_DMA_ATR_ESAD_MASK) << 32; | ||
702 | #endif | ||
703 | } else { | ||
679 | position = in_be32(&dma_channel->dar); | 704 | position = in_be32(&dma_channel->dar); |
705 | #ifdef CONFIG_PHYS_64BIT | ||
706 | position |= (u64)(in_be32(&dma_channel->datr) & | ||
707 | CCSR_DMA_ATR_ESAD_MASK) << 32; | ||
708 | #endif | ||
709 | } | ||
680 | 710 | ||
681 | /* | 711 | /* |
682 | * When capture is started, the SSI immediately starts to fill its FIFO. | 712 | * When capture is started, the SSI immediately starts to fill its FIFO. |
@@ -936,11 +966,6 @@ static void __exit fsl_soc_dma_exit(void) | |||
936 | of_unregister_platform_driver(&fsl_soc_dma_driver); | 966 | of_unregister_platform_driver(&fsl_soc_dma_driver); |
937 | } | 967 | } |
938 | 968 | ||
939 | /* We want the DMA driver to be initialized before the SSI driver, so that | ||
940 | * when the SSI driver calls fsl_soc_dma_dai_from_node(), the DMA driver | ||
941 | * will already have been probed. The easiest way to do that is to make the | ||
942 | * __init function called via arch_initcall(). | ||
943 | */ | ||
944 | module_init(fsl_soc_dma_init); | 969 | module_init(fsl_soc_dma_init); |
945 | module_exit(fsl_soc_dma_exit); | 970 | module_exit(fsl_soc_dma_exit); |
946 | 971 | ||