s5pv210 audio dma分配
1. 音频播放
这里我们使用内部DMA,就是将CPU内部SRAM地址0xc0000000(MP3_SRAM output buffer),通过ioremap映射到内核地址空间上进行操作。
<5>[ 0.000000] Virtual kernel memory layout:
<5>[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
<5>[ 0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
<5>[ 0.000000] DMA : 0xff000000 - 0xffe00000 ( 14 MB)
<5>[ 0.000000] vmalloc : 0xf0800000 - 0xfc000000 ( 184 MB)
<5>[ 0.000000] lowmem : 0xc0000000 - 0xf0000000 ( 768 MB)
<5>[ 0.000000] modules : 0xbf000000 - 0xc0000000 ( 16 MB)
<5>[ 0.000000] .init : 0xc0008000 - 0xc002d000 ( 148 kB)
<5>[ 0.000000] .text : 0xc002d000 - 0xc0579000 (5424 kB)
<5>[ 0.000000] .data : 0xc057a000 - 0xc05c0ec0 ( 284 kB)
<6>[ 0.245925] s3c_idma_preallocate_buffer: VA-f08c0000 PA-C0000000 163840bytes
<6>[ 1133.522560] DmaAddr=@c0000000 Total=16384bytes PrdSz=4096 #Prds=4 dma_area=0xf08c0000
上面红色地址在vmalloc中,说明ioremap是将物理地址映射到vmalloc区。
linux/sound/soc/s3c24xx/s3c-idma.c
static int s3c_idma_preallocate_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
pr_debug("Entered %s\n", __func__);
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
/* Assign PCM buffer pointers */
buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
buf->addr = LP_TXBUFF_ADDR;
buf->bytes = s3c_idma_hardware.buffer_bytes_max;
buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
pr_info("%s: VA-%p PA-%X %ubytes\n",
__func__, buf->area, buf->addr, buf->bytes);
return 0;
}
linux/sound/soc/s3c24xx/s3c-idma.h
#define LP_TXBUFF_ADDR (0xC0000000)
如下图为s5pv210中的地址分布图,其中0xC000_0000~0xCFFFF_FFFF为Low Power Audio SRAM.
2. 录音
录音使用外部DMA方式,申请的是外部RAM,就是我们的物理内存。
<6>[ 1358.710296] DmaAddr=@2fe80000 Total=16384bytes PrdSz=4096 #Prds=4 dma_area=0xff007000
通过上面log可以知道申请的物理地址为0x2fe80000,映射linux内核地址0xff007000,可以知道这是内核
DMA虚拟地址。
申请DMA函数:dma_alloc_writecombine()
linux/sound/soc/s3c24xx/s3c-dma.c
static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = s3c_dma_hardware.buffer_bytes_max;
pr_debug("Entered %s\n", __func__);
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
buf->bytes = size;
return 0;
}