sound: meson: add audio split mmap mode

PD#157943: sound: add audio split mmap mode on meson directory for gxl chip

1. i2s in mmap
2. pdm in mmap
3. pdm in supports sample rate
4. if enable to mmap, please enable  CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP

Change-Id: I08e94c0332269db7c3fa1e42e02a9b17cb4a4b84
Signed-off-by: Peipeng Zhao <peipeng.zhao@amlogic.com>
This commit is contained in:
Peipeng Zhao
2018-01-02 19:19:40 +08:00
committed by Jianxin Pan
parent 91f14cf381
commit eb5791462f
9 changed files with 173 additions and 35 deletions

View File

@@ -14212,4 +14212,8 @@ F: drivers/amlogic/media/vout/backlight/aml_ldim/*
AMLOGIC ADD LCD_EXTERN ST7701 DRIVER
M: Weiming Liu <weiming.liu@amlogic.com>
F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c
F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c
AMLOGIC MESONGXL ADD SOUND DMIC MMAP FUNCTION
M: peipeng.zhao <peipeng.zhao@amlogic.com>
F: sound/soc/amlogic/meson/dmic.h

View File

@@ -152,7 +152,8 @@ void chipset_set_spdif_pao(void)
0x1 << 1);
}
void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel)
void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel,
snd_pcm_format_t format)
{
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE
aml_aiu_write(AIU_MEM_I2S_START_PTR, addr & 0xffffff00);
@@ -288,15 +289,27 @@ void audio_in_clk_sel(void)
* din_sel 0:spdif 1:i2s 2:pcm 3: dmic
*/
static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode,
u32 i2s_sync, u32 din_sel, u32 ch)
u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format)
{
unsigned char mode = 0;
unsigned int sync_mode = 0, din_pos = 0;
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
unsigned int fifo_bytes = 0;
unsigned int i2s_size = 0;
#endif
if (i2s_sync)
sync_mode = i2s_sync;
if (i2s_mode & I2SIN_SLAVE_MODE)
mode = 1;
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
if (format == SNDRV_PCM_FORMAT_S16_LE) {
fifo_bytes = 1;
i2s_size = 0;
} else {
fifo_bytes = 2;
i2s_size = 3;
}
#endif
if (din_sel != 1)
din_pos = 1;
aml_audin_write(AUDIN_FIFO0_START, addr & 0xffffffc0);
@@ -308,14 +321,42 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode,
| (1 << AUDIN_FIFO_LOAD) /* load start address */
| (din_sel << AUDIN_FIFO_DIN_SEL) /*DIN from i2sin*/
| (4 << AUDIN_FIFO_ENDIAN) /*AUDIN_FIFO_ENDIAN*/
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
| (1 << AUDIN_FIFO_CHAN) /* ch mode ctl */
#else
| ((ch == 2?2:1) << AUDIN_FIFO_CHAN) /*ch mode ctl*/
#endif
| (1 << AUDIN_FIFO_UG) /* Urgent request. */
);
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
if (format == SNDRV_PCM_FORMAT_S16_LE)
aml_write_cbus(AUDIN_FIFO0_CTRL,
aml_read_cbus(AUDIN_FIFO0_CTRL) |
(7 << AUDIN_FIFO_ENDIAN));
else
aml_write_cbus(AUDIN_FIFO0_CTRL,
aml_read_cbus(AUDIN_FIFO0_CTRL) |
(6 << AUDIN_FIFO_ENDIAN));
#endif
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
aml_write_cbus(AUDIN_FIFO0_CTRL1, 0 << 4 /* fifo0_dest_sel */
| fifo_bytes << 2 /* fifo0_din_byte_num */
| 0 << 0); /* fifo0_din_pos */
#else
aml_audin_write(AUDIN_FIFO0_CTRL1, 0 << 4 /* fifo0_dest_sel */
| 2 << 2 /* 0: 8bit; 1:16bit; 2:32bit */
| din_pos << 0); /* fifo0_din_pos */
#endif
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
if (format == SNDRV_PCM_FORMAT_S16_LE)
aml_write_cbus(AUDIN_FIFO0_CTRL1,
aml_read_cbus(AUDIN_FIFO0_CTRL1) |
(0 << 0));
else
aml_write_cbus(AUDIN_FIFO0_CTRL1,
aml_read_cbus(AUDIN_FIFO0_CTRL1) |
(1 << 0));
#endif
if (audio_in_source == 1 && (!is_audin_ext_support())) {
aml_audin_write(AUDIN_I2SIN_CTRL, (1 << I2SIN_CHAN_EN)
| (0 << I2SIN_SIZE)
@@ -335,6 +376,17 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode,
| (1 << I2SIN_CLK_SEL)
| (1 << I2SIN_DIR));
} else {
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
aml_write_cbus(AUDIN_I2SIN_CTRL,
((0xf>>(4 - ch/2)) << I2SIN_CHAN_EN)
| (i2s_size << I2SIN_SIZE)
| (1 << I2SIN_LRCLK_INVT)
| (1 << I2SIN_LRCLK_SKEW)
| (sync_mode << I2SIN_POS_SYNC)
| (!mode << I2SIN_LRCLK_SEL)
| (!mode << I2SIN_CLK_SEL)
| (!mode << I2SIN_DIR));
#else
aml_audin_write(AUDIN_I2SIN_CTRL,
((0xf>>(4 - ch/2)) << I2SIN_CHAN_EN)
| (3 << I2SIN_SIZE)
@@ -344,6 +396,7 @@ static void i2sin_fifo0_set_buf(u32 addr, u32 size, u32 i2s_mode,
| (!mode << I2SIN_LRCLK_SEL)
| (!mode << I2SIN_CLK_SEL)
| (!mode << I2SIN_DIR));
#endif
}
}
@@ -473,11 +526,14 @@ static void spdifin_fifo1_set_buf(u32 addr, u32 size, u32 src)
aml_audin_write(AUDIN_FIFO1_CTRL1, 0x88);
}
void audio_in_i2s_set_buf(u32 addr, u32 size,
u32 i2s_mode, u32 i2s_sync, u32 din_sel, u32 ch)
void audio_in_i2s_set_buf(u32 addr, u32 size, u32 i2s_mode,
u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format)
{
pr_debug("i2sin_fifo0_set_buf din_sel:%d ch:%d\n", din_sel, ch);
i2sin_fifo0_set_buf(addr, size, i2s_mode, i2s_sync, din_sel, ch);
i2sin_fifo0_set_buf(addr, size, i2s_mode, i2s_sync,
din_sel, ch, format);
}
void audio_in_i2s2_set_buf(u32 addr, u32 size, u32 src, u32 ch)
@@ -580,6 +636,7 @@ int if_audio_in_spdif_enable(void)
unsigned int audio_in_i2s_rd_ptr(void)
{
unsigned int val;
val = aml_audin_read(AUDIN_FIFO0_RDPTR);
pr_info("audio in i2s rd ptr: %x\n", val);
return val;

View File

@@ -18,6 +18,8 @@
#ifndef __AML_AUDIO_HW_H__
#define __AML_AUDIO_HW_H__
#include "sound/asound.h"
#define AUDIO_CLK_GATE_ON(a) CLK_GATE_ON(a)
#define AUDIO_CLK_GATE_OFF(a) CLK_GATE_OFF(a)
@@ -137,10 +139,11 @@ extern unsigned int IEC958_MODE;
extern unsigned int I2S_MODE;
extern unsigned int audio_in_source;
void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel);
void audio_set_aiubuf(u32 addr, u32 size, unsigned int channel,
snd_pcm_format_t format);
void audio_set_958outbuf(u32 addr, u32 size, int flag);
void audio_in_i2s_set_buf(u32 addr, u32 size,
u32 i2s_mode, u32 i2s_sync, u32 din_sel, u32 ch);
void audio_in_i2s_set_buf(u32 addr, u32 size, u32 i2s_mode,
u32 i2s_sync, u32 din_sel, u32 ch, snd_pcm_format_t format);
void audio_in_spdif_set_buf(u32 addr, u32 size, u32 src);
void audio_in_i2s2_set_buf(u32 addr, u32 size, u32 src, u32 ch);
void audio_in_i2s_enable(int flag);

View File

@@ -24,6 +24,7 @@
#include <sound/soc.h>
#include <linux/reset.h>
#include <linux/pinctrl/consumer.h>
#include "dmic.h"
#define DRV_NAME "snd_dmic"
@@ -49,12 +50,7 @@
#define PDM_VOL_GAIN_R 0x45
#define PDM_STATUS 0x50
struct aml_dmic_priv {
void __iomem *pdm_base;
struct pinctrl *dmic_pins;
struct clk *clk_pdm;
struct clk *clk_mclk;
};
struct aml_dmic_priv *dmic_pub;
static int aml_dmic_codec_probe(struct snd_soc_codec *codec)
{
@@ -171,13 +167,14 @@ static int aml_dmic_platform_probe(struct platform_device *pdev)
return PTR_ERR(dmic_priv->pdm_base);
}
writel(0x100000, dmic_priv->pdm_base + (PDM_VOL_GAIN_L<<2));
writel(0x100000, dmic_priv->pdm_base + (PDM_VOL_GAIN_R<<2));
writel(0x10000, dmic_priv->pdm_base + (PDM_VOL_GAIN_L<<2));
writel(0x10000, dmic_priv->pdm_base + (PDM_VOL_GAIN_R<<2));
val = readl(dmic_priv->pdm_base + (PDM_CTRL<<2));
writel(1, dmic_priv->pdm_base + (PDM_CTRL<<2));
val = readl(dmic_priv->pdm_base + (PDM_CTRL<<2));
dmic_pub = dmic_priv;
return snd_soc_register_codec(&pdev->dev,
&aml_dmic, &aml_dmic_dai, 1);
err:

View File

@@ -0,0 +1,13 @@
#ifndef __DMIC_H__
#define __DMIC_H__
struct aml_dmic_priv {
void __iomem *pdm_base;
struct pinctrl *dmic_pins;
struct clk *clk_pdm;
struct clk *clk_mclk;
};
extern struct aml_dmic_priv *dmic_pub;
#endif

View File

@@ -166,18 +166,33 @@ static int aml_i2s_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 = aml_i2s_hardware.buffer_bytes_max;
size_t size;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* malloc DMA buffer */
size = aml_i2s_hardware.buffer_bytes_max;
buf->area = dmam_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
dev_info(pcm->card->dev, "aml-i2s %d: playback preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n",
stream, (void *) buf->area, (void *) buf->addr, size);
if (!buf->area)
return -ENOMEM;
} else {
/* malloc DMA buffer */
size = aml_i2s_capture.buffer_bytes_max;
buf->area = dmam_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
dev_info(pcm->card->dev, "aml-i2s %d: capture preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n",
stream, (void *) buf->area, (void *) buf->addr, size);
if (!buf->area)
return -ENOMEM;
}
buf->area = dmam_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
dev_info(pcm->card->dev, "aml-pcm %d: playback preallocate_dma_buffer: area=%p, addr=%p, size=%ld\n",
stream, (void *) buf->area, (void *) buf->addr, size);
if (!buf->area)
return -ENOMEM;
buf->bytes = size;
return 0;
@@ -521,7 +536,9 @@ static snd_pcm_uframes_t aml_i2s_pointer(struct snd_pcm_substream *substream)
ptr = read_iec958_rd_ptr();
addr = ptr - s->I2S_addr;
return bytes_to_frames(runtime, addr);
} else {
}
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
if (s->device_type == AML_AUDIO_I2SIN)
ptr = audio_in_i2s_wr_ptr();
else if (s->device_type == AML_AUDIO_I2SIN2)
@@ -529,10 +546,14 @@ static snd_pcm_uframes_t aml_i2s_pointer(struct snd_pcm_substream *substream)
else
ptr = audio_in_spdif_wr_ptr();
addr = ptr - s->I2S_addr;
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
return bytes_to_frames(runtime, addr);
#else
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE)
return bytes_to_frames(runtime, addr) >> 1;
else
return bytes_to_frames(runtime, addr);
#endif
}
return 0;
@@ -586,12 +607,17 @@ static void aml_i2s_timer_callback(unsigned long data)
last_ptr = audio_in_spdif_wr_ptr();
if (last_ptr < s->last_ptr) {
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
size = runtime->dma_bytes +
(last_ptr - (s->last_ptr));
#else
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE)
size = runtime->dma_bytes +
(last_ptr - (s->last_ptr)) / 2;
else
size = runtime->dma_bytes +
(last_ptr - (s->last_ptr));
#endif
prtd->xrun_num = 0;
} else if (last_ptr == s->last_ptr) {
if (prtd->xrun_num++ > XRUN_NUM) {
@@ -599,10 +625,14 @@ static void aml_i2s_timer_callback(unsigned long data)
s->size = runtime->period_size;
}
} else {
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
size = (last_ptr - (s->last_ptr));
#else
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE)
size = (last_ptr - (s->last_ptr)) / 2;
else
size = last_ptr - (s->last_ptr);
#endif
prtd->xrun_num = 0;
}

View File

@@ -172,14 +172,16 @@ static int aml_dai_i2s2_prepare(struct snd_pcm_substream *substream,
audio_in_i2s_set_buf(runtime->dma_addr,
runtime->dma_bytes * 2,
0, 1, 1,
runtime->channels);
runtime->channels,
runtime->format);
memset((void *)runtime->dma_area, 0,
runtime->dma_bytes * 2);
} else {
audio_in_i2s_set_buf(runtime->dma_addr,
runtime->dma_bytes,
0, 1, 1,
runtime->channels);
runtime->channels,
runtime->format);
memset((void *)runtime->dma_area, 0,
runtime->dma_bytes);
}

View File

@@ -47,6 +47,7 @@
#include "audio_hw.h"
#include <linux/amlogic/media/sound/aout_notify.h>
#include "spdif_dai.h"
#include "dmic.h"
#define AOUT_EVENT_IEC_60958_PCM 0x1
@@ -76,7 +77,7 @@ static void aml_hw_i2s_init(struct snd_pcm_runtime *runtime)
audio_set_i2s_mode(i2s_mode);
#endif
audio_set_aiubuf(runtime->dma_addr, runtime->dma_bytes,
runtime->channels);
runtime->channels, runtime->format);
}
static int aml_dai_i2s_startup(struct snd_pcm_substream *substream,
@@ -177,21 +178,35 @@ static int aml_dai_i2s_prepare(struct snd_pcm_substream *substream,
s->device_type = AML_AUDIO_I2SIN2;
} else {
if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
#ifdef CONFIG_AMLOGIC_SND_SPLIT_MODE_MMAP
audio_in_i2s_set_buf(runtime->dma_addr,
runtime->dma_bytes,
0, i2s->i2s_pos_sync,
i2s->audin_fifo_src,
runtime->channels,
runtime->format);
memset((void *)runtime->dma_area, 0,
runtime->dma_bytes);
#else
audio_in_i2s_set_buf(runtime->dma_addr,
runtime->dma_bytes * 2,
i2s->clk_data_pos,
i2s->i2s_pos_sync,
i2s->audin_fifo_src,
runtime->channels);
runtime->channels,
runtime->format);
memset((void *)runtime->dma_area, 0,
runtime->dma_bytes * 2);
#endif
} else {
audio_in_i2s_set_buf(runtime->dma_addr,
runtime->dma_bytes,
i2s->clk_data_pos,
i2s->i2s_pos_sync,
i2s->audin_fifo_src,
runtime->channels);
runtime->channels,
runtime->format);
memset((void *)runtime->dma_area, 0,
runtime->dma_bytes);
}
@@ -270,9 +285,25 @@ static int aml_dai_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct aml_i2s *i2s = snd_soc_dai_get_drvdata(dai);
int srate, mclk_rate;
int srate, mclk_rate, ret;
srate = params_rate(params);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
if (i2s->audin_fifo_src == 3) {
mclk_rate = srate * DEFAULT_MCLK_RATIO_SR;
ret = clk_set_rate(dmic_pub->clk_mclk, mclk_rate * 10);
if (ret)
return ret;
ret = clk_set_parent(dmic_pub->clk_pdm,
dmic_pub->clk_mclk);
if (ret)
return ret;
ret = clk_set_rate(dmic_pub->clk_pdm, mclk_rate/4);
if (ret)
return ret;
return 0;
}
}
if (i2s->old_samplerate != srate) {
if (audio_in_source == 0 || substream->stream
== SNDRV_PCM_STREAM_PLAYBACK) {

View File

@@ -65,7 +65,8 @@ static void aml_i2s_play(void)
audio_set_i2s_mode(AIU_I2S_MODE_PCM16);
#endif
memset(i2sbuf, 0, sizeof(i2sbuf));
audio_set_aiubuf((virt_to_phys(i2sbuf) + 63) & (~63), 128, 2);
audio_set_aiubuf((virt_to_phys(i2sbuf) + 63) & (~63), 128, 2,
SNDRV_PCM_FORMAT_S16_LE);
audio_out_i2s_enable(1);
}