summarylogtreecommitdiffstats
path: root/general-meson-aiu-Fix-HDMI-codec-control-selection.patch
diff options
context:
space:
mode:
Diffstat (limited to 'general-meson-aiu-Fix-HDMI-codec-control-selection.patch')
-rw-r--r--general-meson-aiu-Fix-HDMI-codec-control-selection.patch233
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
+