From eb5791462f42b0c335e6479f3a7e27bb2e8a8e41 Mon Sep 17 00:00:00 2001 From: Peipeng Zhao Date: Tue, 2 Jan 2018 19:19:40 +0800 Subject: [PATCH] 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 --- MAINTAINERS | 6 ++- sound/soc/amlogic/meson/audio_hw.c | 73 ++++++++++++++++++++++++++---- sound/soc/amlogic/meson/audio_hw.h | 9 ++-- sound/soc/amlogic/meson/dmic.c | 13 ++---- sound/soc/amlogic/meson/dmic.h | 13 ++++++ sound/soc/amlogic/meson/i2s.c | 46 +++++++++++++++---- sound/soc/amlogic/meson/i2s2_dai.c | 6 ++- sound/soc/amlogic/meson/i2s_dai.c | 39 ++++++++++++++-- sound/soc/amlogic/meson/meson.c | 3 +- 9 files changed, 173 insertions(+), 35 deletions(-) create mode 100644 sound/soc/amlogic/meson/dmic.h diff --git a/MAINTAINERS b/MAINTAINERS index ce5378777b36..b443c19c6526 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14212,4 +14212,8 @@ F: drivers/amlogic/media/vout/backlight/aml_ldim/* AMLOGIC ADD LCD_EXTERN ST7701 DRIVER M: Weiming Liu -F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c \ No newline at end of file +F: drivers/amlogic/media/vout/lcd/lcd_extern/mipi_ST7701.c + +AMLOGIC MESONGXL ADD SOUND DMIC MMAP FUNCTION +M: peipeng.zhao +F: sound/soc/amlogic/meson/dmic.h diff --git a/sound/soc/amlogic/meson/audio_hw.c b/sound/soc/amlogic/meson/audio_hw.c index aa7fac854c6a..260155dbc460 100644 --- a/sound/soc/amlogic/meson/audio_hw.c +++ b/sound/soc/amlogic/meson/audio_hw.c @@ -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; diff --git a/sound/soc/amlogic/meson/audio_hw.h b/sound/soc/amlogic/meson/audio_hw.h index 51dc3fb3f28b..d8c8471afea9 100644 --- a/sound/soc/amlogic/meson/audio_hw.h +++ b/sound/soc/amlogic/meson/audio_hw.h @@ -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); diff --git a/sound/soc/amlogic/meson/dmic.c b/sound/soc/amlogic/meson/dmic.c index 84e5c78a34b4..d3fa63e07423 100644 --- a/sound/soc/amlogic/meson/dmic.c +++ b/sound/soc/amlogic/meson/dmic.c @@ -24,6 +24,7 @@ #include #include #include +#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: diff --git a/sound/soc/amlogic/meson/dmic.h b/sound/soc/amlogic/meson/dmic.h new file mode 100644 index 000000000000..69afdf5a9b17 --- /dev/null +++ b/sound/soc/amlogic/meson/dmic.h @@ -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 diff --git a/sound/soc/amlogic/meson/i2s.c b/sound/soc/amlogic/meson/i2s.c index 266009966657..19cfab14755f 100644 --- a/sound/soc/amlogic/meson/i2s.c +++ b/sound/soc/amlogic/meson/i2s.c @@ -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; } diff --git a/sound/soc/amlogic/meson/i2s2_dai.c b/sound/soc/amlogic/meson/i2s2_dai.c index ce28c2b4f490..ee6a913ac1e9 100644 --- a/sound/soc/amlogic/meson/i2s2_dai.c +++ b/sound/soc/amlogic/meson/i2s2_dai.c @@ -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); } diff --git a/sound/soc/amlogic/meson/i2s_dai.c b/sound/soc/amlogic/meson/i2s_dai.c index b2ae493cfd0a..f68f090529ec 100644 --- a/sound/soc/amlogic/meson/i2s_dai.c +++ b/sound/soc/amlogic/meson/i2s_dai.c @@ -47,6 +47,7 @@ #include "audio_hw.h" #include #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) { diff --git a/sound/soc/amlogic/meson/meson.c b/sound/soc/amlogic/meson/meson.c index 87dbf80ca828..ce3d5b4e1411 100644 --- a/sound/soc/amlogic/meson/meson.c +++ b/sound/soc/amlogic/meson/meson.c @@ -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); }