diff options
Diffstat (limited to 'general-meson-aiu-Fix-HDMI-codec-control-selection.patch')
-rw-r--r-- | general-meson-aiu-Fix-HDMI-codec-control-selection.patch | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/general-meson-aiu-Fix-HDMI-codec-control-selection.patch b/general-meson-aiu-Fix-HDMI-codec-control-selection.patch new file mode 100644 index 000000000000..03428e12142f --- /dev/null +++ b/general-meson-aiu-Fix-HDMI-codec-control-selection.patch @@ -0,0 +1,233 @@ +From 712edc341073c350a11658186609eafd292dbe8a Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl <martin.blumenstingl@googlemail.com> +Date: Sun, 3 Oct 2021 05:35:48 +0000 +Subject: [PATCH 27/90] FROMLIST(v1): ASoC: meson: aiu: Fix HDMI codec control + selection + +The HDMI controllers on Amlogic Meson SoCs which use the AIU +audio-controller have two different audio format inputs: +- I2S which is also the only configuration supported on GXBB, GXL and + GXM SoCs since there's no SPDIF support in the DesignWare HDMI + controller driver (at the time of writing this) +- SPDIF can be used optionally, including pass-through formats + +Switching between these requires us to set different registers: +AIU_HDMI_CLK_DATA_CTRL[1:0] "HDMI_DATA_CLK_SEL": +- 0x0 disables the HDMI output clock +- 0x1 selects the PCM clock +- 0x2 selects the AIU clock +- 0x3 is reserved + +AIU_HDMI_CLK_DATA_CTRL[5:4] "HDMI_DATA_SEL": +- 0x0 outputs constant zero, disables HDMI data +- 0x1 selects PCM data +- 0x2 selects AIU I2S data +- 0x3 is reserved + +AIU_CLK_CTRL_MORE[6] "HDMITX_SEL_AOCLKX2": +- 0x0 selects cts_i958 as AIU clk to hdmi_tx_audio_master_clk +- 0x1 selects cts_aoclkx2_int as AIU clk to hdmi_tx_audio_master_clk + +The Meson8/8b/8m2 vendor driver uses the following settings: +SPDIF output to the HDMI controller: +- 0x2 (AIU clock) in AIU_HDMI_CLK_DATA_CTRL[1:0] +- 0x0 (no HDMI data) in AIU_HDMI_CLK_DATA_CTRL[5:4] +- 0x0 (using cts_i958 as AIU clk) in AIU_CLK_CTRL_MORE[6] +I2S output to the HDMI controller: +- 0x2 (AIU clock) in AIU_HDMI_CLK_DATA_CTRL[1:0] +- 0x2 (I2S data) in AIU_HDMI_CLK_DATA_CTRL[5:4] +- 0x0 (using cts_aoclkx2_int as AIU clk) in AIU_CLK_CTRL_MORE[6] + +The GXBB/GXL/GXM vendor driver uses the following settings: +SPDIF output to the HDMI controller: +- not setting AIU_HDMI_CLK_DATA_CTRL at all +- 0x0 (using cts_i958 as AIU clk) in AIU_CLK_CTRL_MORE[6] +I2S output to the HDMI controller: +- 0x2 (AIU clock) in AIU_HDMI_CLK_DATA_CTRL[1:0] +- 0x2 (I2S data) in AIU_HDMI_CLK_DATA_CTRL[5:4] +- 0x0 (using cts_aoclkx2_int as AIU clk) in AIU_CLK_CTRL_MORE[6] + +Set the three registers at the same time following what the vendor +driver does on Meson8/8b/8m2 SoCs. This makes the SPDIF output to the +HDMI controller work. The entries and order of the entries in the enum +is not changed on purpose to not break old configurations. + +Fixes: b82b734c0e9a7 ("ASoC: meson: aiu: add hdmi codec control support") +Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> +--- + sound/soc/meson/aiu-codec-ctrl.c | 108 ++++++++++++++++++++++-------- + sound/soc/meson/aiu-encoder-i2s.c | 6 -- + 2 files changed, 80 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c +index c3ea733fce91..2b8575491aeb 100644 +--- a/sound/soc/meson/aiu-codec-ctrl.c ++++ b/sound/soc/meson/aiu-codec-ctrl.c +@@ -12,14 +12,60 @@ + #include "aiu.h" + #include "meson-codec-glue.h" + +-#define CTRL_CLK_SEL GENMASK(1, 0) +-#define CTRL_DATA_SEL_SHIFT 4 +-#define CTRL_DATA_SEL (0x3 << CTRL_DATA_SEL_SHIFT) +- +-static const char * const aiu_codec_ctrl_mux_texts[] = { +- "DISABLED", "PCM", "I2S", ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL GENMASK(1, 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_DISABLE 0x0 ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_PCM 0x1 ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_AIU 0x2 ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL GENMASK(5, 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_OUTPUT_ZERO 0x0 ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_PCM_DATA 0x1 ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_I2S_DATA 0x2 ++ ++#define AIU_CLK_CTRL_MORE_AMCLK BIT(6) ++ ++#define AIU_HDMI_CTRL_MUX_DISABLED 0 ++#define AIU_HDMI_CTRL_MUX_PCM 1 ++#define AIU_HDMI_CTRL_MUX_I2S 2 ++ ++static const char * const aiu_codec_hdmi_ctrl_mux_texts[] = { ++ [AIU_HDMI_CTRL_MUX_DISABLED] = "DISABLED", ++ [AIU_HDMI_CTRL_MUX_PCM] = "PCM", ++ [AIU_HDMI_CTRL_MUX_I2S] = "I2S", + }; + ++static int aiu_codec_ctrl_mux_get_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_kcontrol_component(kcontrol); ++ unsigned int ctrl, more, mux = AIU_HDMI_CTRL_MUX_DISABLED; ++ ++ ctrl = snd_soc_component_read(component, AIU_HDMI_CLK_DATA_CTRL); ++ if (FIELD_GET(AIU_HDMI_CLK_DATA_CTRL_CLK_SEL, ctrl) != ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_AIU) { ++ goto out; ++ } ++ ++ more = snd_soc_component_read(component, AIU_CLK_CTRL_MORE); ++ if (FIELD_GET(AIU_HDMI_CLK_DATA_CTRL_DATA_SEL, ctrl) == ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_I2S_DATA && ++ !!(more & AIU_CLK_CTRL_MORE_AMCLK)) { ++ mux = AIU_HDMI_CTRL_MUX_I2S; ++ goto out; ++ } ++ ++ if (FIELD_GET(AIU_HDMI_CLK_DATA_CTRL_DATA_SEL, ctrl) == ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_OUTPUT_ZERO && ++ !(more & AIU_CLK_CTRL_MORE_AMCLK)) { ++ mux = AIU_HDMI_CTRL_MUX_PCM; ++ goto out; ++ } ++ ++out: ++ ucontrol->value.enumerated.item[0] = mux; ++ return 0; ++} ++ + static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -28,45 +74,51 @@ static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +- unsigned int mux, changed; ++ unsigned int mux, ctrl, more; + + mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); +- changed = snd_soc_component_test_bits(component, e->reg, +- CTRL_DATA_SEL, +- FIELD_PREP(CTRL_DATA_SEL, mux)); + +- if (!changed) +- return 0; ++ if (mux == AIU_HDMI_CTRL_MUX_I2S) { ++ ctrl = FIELD_PREP(AIU_HDMI_CLK_DATA_CTRL_DATA_SEL, ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_I2S_DATA); ++ more = AIU_CLK_CTRL_MORE_AMCLK; ++ } else { ++ ctrl = FIELD_PREP(AIU_HDMI_CLK_DATA_CTRL_DATA_SEL, ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_OUTPUT_ZERO); ++ more = 0; ++ } ++ ++ if (mux == AIU_HDMI_CTRL_MUX_DISABLED) { ++ ctrl |= FIELD_PREP(AIU_HDMI_CLK_DATA_CTRL_CLK_SEL, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_DISABLE); ++ } else { ++ ctrl |= FIELD_PREP(AIU_HDMI_CLK_DATA_CTRL_CLK_SEL, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_AIU); ++ } + + /* Force disconnect of the mux while updating */ + snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); + +- /* Reset the source first */ +- snd_soc_component_update_bits(component, e->reg, +- CTRL_CLK_SEL | +- CTRL_DATA_SEL, +- FIELD_PREP(CTRL_CLK_SEL, 0) | +- FIELD_PREP(CTRL_DATA_SEL, 0)); ++ snd_soc_component_update_bits(component, AIU_HDMI_CLK_DATA_CTRL, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL | ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL, ++ ctrl); + +- /* Set the appropriate source */ +- snd_soc_component_update_bits(component, e->reg, +- CTRL_CLK_SEL | +- CTRL_DATA_SEL, +- FIELD_PREP(CTRL_CLK_SEL, mux) | +- FIELD_PREP(CTRL_DATA_SEL, mux)); ++ snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE, ++ AIU_CLK_CTRL_MORE_AMCLK, ++ more); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + + return 0; + } + +-static SOC_ENUM_SINGLE_DECL(aiu_hdmi_ctrl_mux_enum, AIU_HDMI_CLK_DATA_CTRL, +- CTRL_DATA_SEL_SHIFT, +- aiu_codec_ctrl_mux_texts); ++static SOC_ENUM_SINGLE_VIRT_DECL(aiu_hdmi_ctrl_mux_enum, ++ aiu_codec_hdmi_ctrl_mux_texts); + + static const struct snd_kcontrol_new aiu_hdmi_ctrl_mux = + SOC_DAPM_ENUM_EXT("HDMI Source", aiu_hdmi_ctrl_mux_enum, +- snd_soc_dapm_get_enum_double, ++ aiu_codec_ctrl_mux_get_enum, + aiu_codec_ctrl_mux_put_enum); + + static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = { +diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c +index 67729de41a73..88637deb2d7a 100644 +--- a/sound/soc/meson/aiu-encoder-i2s.c ++++ b/sound/soc/meson/aiu-encoder-i2s.c +@@ -23,7 +23,6 @@ + #define AIU_CLK_CTRL_AOCLK_INVERT BIT(6) + #define AIU_CLK_CTRL_LRCLK_INVERT BIT(7) + #define AIU_CLK_CTRL_LRCLK_SKEW GENMASK(9, 8) +-#define AIU_CLK_CTRL_MORE_HDMI_AMCLK BIT(6) + #define AIU_CLK_CTRL_MORE_I2S_DIV GENMASK(5, 0) + #define AIU_CODEC_DAC_LRCLK_CTRL_DIV GENMASK(11, 0) + +@@ -176,11 +175,6 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, + if (ret) + return ret; + +- /* Make sure amclk is used for HDMI i2s as well */ +- snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE, +- AIU_CLK_CTRL_MORE_HDMI_AMCLK, +- AIU_CLK_CTRL_MORE_HDMI_AMCLK); +- + return 0; + } + +-- +2.35.1 + |