From 52ae6581d76103f7509cada26faf3a8f6215aa0a Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Thu, 8 Aug 2019 18:00:35 +0530 Subject: [PATCH] asoc: codecs: bolero: Fix L/R swap issue on bolero RX Left and right channel content can get swapped in new cdc_dma interface. DMA interfaces underrun results in Channels being swapped. This issue is a side effect current SW setup for RX path: 1. HLOS Setup WCD Analog Path, Bolero CODEC. CODEC would drive Fs to LPASS DMAs requesting for PCM samples. 2. DSP setup RX Buffers in Memory : 3. DSP Configures RD DMAs and DMA RXTX CODEC interface (Enable CODEC DMA interface buffer and Enable DMA LPASS_RXTX_LPAIF_RDDMA_CTL0.ENABLE and LPASS_RXTX_LPAIF_RDDMA_CODEC_INTF0.ENABLE If CODEC Fs, aligns with DMA interface being enabled there is an underrun as DMA interface pingpong buffer is empty. This results in channels being swapped. Proposed work around while keeping current SW setup order. Provide a workaround to Keep Fs disabled until DMAs and CODEC DMA interface are enabled and HW could prefetch all buffers. SW would keep existing setup order: 1. HLOS Setup WCD Analog Path, Bolero CODEC. CODEC would drive Fs to LPASS DMAs requesting for PCM samples. 2. DSP setup RX Buffers in Memory : 3. DSP Configures DMAs and DMA CODEC interface (Enable CODEC DMA interface buffer and Enable DMA LPASS_RXTX_LPAIF_RDDMA_CTL0.ENABLE and LPASS_RXTX_LPAIF_RDDMA_CODEC_INTF0.ENABLE) 4. Enable Fs Set #LPASS_RX_CDC_RX0_RX_PATH_CTL. CLK_EN to ONE Change-Id: I7916667f5d857464cc7d77b51da307ab234cc7bb Signed-off-by: Laxminath Kasam --- asoc/codecs/bolero/rx-macro.c | 120 ++++++++++++++++++++++++----- asoc/codecs/bolero/wsa-macro.c | 134 +++++++++++++++++++++++++++++++-- 2 files changed, 227 insertions(+), 27 deletions(-) diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index c6a9d3dd62fb..98754bf91820 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -280,6 +280,7 @@ static int rx_macro_hw_params(struct snd_pcm_substream *substream, static int rx_macro_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); +static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute); static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); static int rx_macro_mux_get(struct snd_kcontrol *kcontrol, @@ -570,6 +571,7 @@ static const struct snd_kcontrol_new rx_mix_tx0_mux = static struct snd_soc_dai_ops rx_macro_dai_ops = { .hw_params = rx_macro_hw_params, .get_channel_map = rx_macro_get_channel_map, + .digital_mute = rx_macro_digital_mute, }; static struct snd_soc_dai_driver rx_macro_dai[] = { @@ -844,9 +846,9 @@ static int rx_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, component, int_mux_cfg0); int_mux_cfg1_val = snd_soc_component_read32( component, int_mux_cfg1); - inp0_sel = int_mux_cfg0_val & 0x07; - inp1_sel = (int_mux_cfg0_val >> 4) & 0x038; - inp2_sel = (int_mux_cfg1_val >> 4) & 0x038; + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; if ((inp0_sel == int_1_mix1_inp) || (inp1_sel == int_1_mix1_inp) || (inp2_sel == int_1_mix1_inp)) { @@ -897,7 +899,7 @@ static int rx_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, for (j = 0; j < INTERP_MAX; j++) { int_mux_cfg1_val = snd_soc_component_read32( component, int_mux_cfg1) & - 0x07; + 0x0F; if (int_mux_cfg1_val == int_2_inp) { int_fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + 0x80 * j; @@ -1056,6 +1058,57 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai, return 0; } +static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + + if (mute) + return 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case RX_MACRO_AIF1_PB: + case RX_MACRO_AIF2_PB: + case RX_MACRO_AIF3_PB: + case RX_MACRO_AIF4_PB: + for (j = 0; j < INTERP_MAX; j++) { + reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + mix_reg = BOLERO_CDC_RX_RX0_RX_PATH_MIX_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL + + (j * RX_MACRO_RX_PATH_OFFSET); + if (j == INTERP_AUX) + dsm_reg = BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL; + int_mux_cfg0 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read32(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32(component, + int_mux_cfg1); + if (snd_soc_component_read32(component, dsm_reg) & 0x01) { + if (int_mux_cfg0_val || (int_mux_cfg1_val & 0xF0)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + if (int_mux_cfg1_val & 0x0F) + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + } + } + break; + default: + break; + } + return 0; +} + static int rx_macro_mclk_enable(struct rx_macro_priv *rx_priv, bool mclk_enable, bool dapm) { @@ -1412,8 +1465,6 @@ static int rx_macro_enable_mix_path(struct snd_soc_dapm_widget *w, rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, INTERP_MIX_PATH); rx_macro_enable_interp_clk(component, event, w->shift); - /* Clk enable */ - snd_soc_component_update_bits(component, mix_reg, 0x20, 0x20); break; case SND_SOC_DAPM_POST_PMU: snd_soc_component_write(component, gain_reg, @@ -1432,6 +1483,42 @@ static int rx_macro_enable_mix_path(struct snd_soc_dapm_widget *w, return 0; } +static bool rx_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = BOLERO_CDC_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read32(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1 || + int_n_inp0 == INTn_1_INP_SEL_IIR0 || + int_n_inp0 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1 || + int_n_inp1 == INTn_1_INP_SEL_IIR0 || + int_n_inp1 == INTn_1_INP_SEL_IIR1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1 || + int_n_inp2 == INTn_1_INP_SEL_IIR0 || + int_n_inp2 == INTn_1_INP_SEL_IIR1) + return true; + + return false; +} + static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -1464,6 +1551,9 @@ static int rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, rx_macro_set_idle_detect_thr(component, rx_priv, w->shift, INTERP_MAIN_PATH); rx_macro_enable_interp_clk(component, event, w->shift); + if (rx_macro_adie_lb(component, w->shift)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); break; case SND_SOC_DAPM_POST_PMU: snd_soc_component_write(component, gain_reg, @@ -2240,9 +2330,6 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component, 0x10, 0x10); snd_soc_component_update_bits(component, dsm_reg, 0x01, 0x01); - /* Clk enable */ - snd_soc_component_update_bits(component, main_reg, - 0x20, 0x20); snd_soc_component_update_bits(component, rx_cfg2_reg, 0x03, 0x03); rx_macro_idle_detect_control(component, rx_priv, @@ -2313,17 +2400,21 @@ static int rx_macro_enable_rx_path_clk(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - u16 sidetone_reg = 0; + u16 sidetone_reg = 0, fs_reg = 0; dev_dbg(component->dev, "%s %d %d\n", __func__, event, w->shift); sidetone_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG1 + RX_MACRO_RX_PATH_OFFSET * (w->shift); + fs_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + + RX_MACRO_RX_PATH_OFFSET * (w->shift); switch (event) { case SND_SOC_DAPM_PRE_PMU: rx_macro_enable_interp_clk(component, event, w->shift); snd_soc_component_update_bits(component, sidetone_reg, 0x10, 0x10); + snd_soc_component_update_bits(component, fs_reg, + 0x20, 0x20); break; case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(component, sidetone_reg, @@ -3432,15 +3523,6 @@ static int rx_macro_init(struct snd_soc_component *component) snd_soc_dapm_ignore_suspend(dapm, "RX_TX DEC3_INP"); snd_soc_dapm_sync(dapm); - snd_soc_component_update_bits(component, - BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL, - 0x01, 0x01); - snd_soc_component_update_bits(component, - BOLERO_CDC_RX_RX1_RX_PATH_DSM_CTL, - 0x01, 0x01); - snd_soc_component_update_bits(component, - BOLERO_CDC_RX_RX2_RX_PATH_DSM_CTL, - 0x01, 0x01); snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX0_RX_PATH_SEC7, 0x07, 0x02); snd_soc_component_update_bits(component, BOLERO_CDC_RX_RX1_RX_PATH_SEC7, diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index dd12ad237362..623b64b0e5ec 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -88,6 +88,16 @@ enum { WSA_MACRO_SOFTCLIP_MAX }; +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, +}; + struct interp_sample_rate { int sample_rate; int rate_val; @@ -129,6 +139,7 @@ static int wsa_macro_hw_params(struct snd_pcm_substream *substream, static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); +static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute); /* Hold instance to soundwire platform device */ struct wsa_macro_swr_ctrl_data { struct platform_device *wsa_swr_pdev; @@ -358,6 +369,7 @@ static const struct snd_kcontrol_new rx_mix_ec1_mux = static struct snd_soc_dai_ops wsa_macro_dai_ops = { .hw_params = wsa_macro_hw_params, .get_channel_map = wsa_macro_get_channel_map, + .digital_mute = wsa_macro_digital_mute, }; static struct snd_soc_dai_driver wsa_macro_dai[] = { @@ -794,6 +806,53 @@ static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, return 0; } +static int wsa_macro_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + uint16_t j = 0, reg = 0, mix_reg = 0, dsm_reg = 0; + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + + if (mute) + return 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (dai->id) { + case WSA_MACRO_AIF1_PB: + case WSA_MACRO_AIF_MIX1_PB: + for (j = 0; j < NUM_INTERPOLATORS; j++) { + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET); + mix_reg = BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + (j * WSA_MACRO_RX_PATH_OFFSET) + + WSA_MACRO_RX_PATH_DSMDEM_OFFSET; + int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + j * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read32(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32(component, + int_mux_cfg1); + if (snd_soc_component_read32(component, dsm_reg) & 0x01) { + if (int_mux_cfg0_val || (int_mux_cfg1_val & 0x38)) + snd_soc_component_update_bits(component, reg, + 0x20, 0x20); + if (int_mux_cfg1_val & 0x07) + snd_soc_component_update_bits(component, + mix_reg, 0x20, 0x20); + } + } + break; + default: + break; + } + return 0; +} static int wsa_macro_mclk_enable(struct wsa_macro_priv *wsa_priv, bool mclk_enable, bool dapm) { @@ -1102,6 +1161,8 @@ static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, snd_soc_component_write(component, gain_reg, val); break; case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + w->reg, 0x20, 0x00); break; } @@ -1323,6 +1384,58 @@ static int wsa_macro_config_softclip(struct snd_soc_component *component, return 0; } +static bool wsa_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0 = 0, int_mux_cfg1 = 0; + u8 int_mux_cfg0_val = 0, int_mux_cfg1_val = 0; + u8 int_n_inp0 = 0, int_n_inp1 = 0, int_n_inp2 = 0; + + int_mux_cfg0 = BOLERO_CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read32(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read32(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1) + return true; + + return false; +} + +static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 reg = 0; + + reg = BOLERO_CDC_WSA_RX0_RX_PATH_CTL + + WSA_MACRO_RX_PATH_OFFSET * w->shift; + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wsa_macro_adie_lb(component, w->shift)) + snd_soc_component_update_bits(component, + reg, 0x20, 0x20); + break; + default: + break; + } + return 0; +} + static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind) { u16 prim_int_reg = 0; @@ -1370,8 +1483,6 @@ static int wsa_macro_enable_prim_interpolator( snd_soc_component_update_bits(component, prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, 0x1, 0x1); - snd_soc_component_update_bits(component, prim_int_reg, - 1 << 0x5, 1 << 0x5); } if ((reg != prim_int_reg) && ((snd_soc_component_read32( @@ -1384,6 +1495,9 @@ static int wsa_macro_enable_prim_interpolator( if (wsa_priv->prim_int_users[ind] == 0) { snd_soc_component_update_bits(component, prim_int_reg, 1 << 0x5, 0 << 0x5); + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + 0x1, 0x0); snd_soc_component_update_bits(component, prim_int_reg, 0x40, 0x40); snd_soc_component_update_bits(component, prim_int_reg, @@ -2382,8 +2496,8 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux, wsa_macro_enable_swr, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, 0, 0, - &rx0_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL, + 0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux, wsa_macro_enable_swr, @@ -2394,11 +2508,15 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux, wsa_macro_enable_swr, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, 0, 0, - &rx1_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL, + 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("WSA_RX INT1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, + 0, 0, NULL, 0, wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, + 1, 0, NULL, 0, wsa_macro_enable_main_path, + SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),