2020-07-29 15:44:44

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH 0/3] clk: meson: axg-audio: fix tdmout sclk inverter

The patchset fixes a problem with TDMOUT sclk inverter found on the
g12a and following SoCs.

On the the axg, a single bit was enough to drive the inverter. On
the g12a a bit was added to, somehow, change how the clock is sampled.
For the inverter to behave as intended, the new bit should be the
inverse of the inverter bit at all time.

Quite a lot of lines for a single bit ...

Jerome Brunet (3):
clk: meson: add sclk-ws driver
clk: meson: axg-audio: separate axg and g12a regmap tables
clk: meson: axg-audio: fix g12a tdmout sclk inverter

drivers/clk/meson/axg-audio.c | 214 +++++++++++++++++++++++++++++-----
drivers/clk/meson/clk-phase.c | 56 +++++++++
drivers/clk/meson/clk-phase.h | 6 +
3 files changed, 246 insertions(+), 30 deletions(-)

--
2.25.4


2020-07-29 15:45:06

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH 2/3] clk: meson: axg-audio: separate axg and g12a regmap tables

There are more differences than what we initially thought.
Let's keeps things clear and separate the axg and g12a regmap tables of the
audio clock controller.

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/axg-audio.c | 135 ++++++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index 53715e36326c..9918cb375de3 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -1209,13 +1209,132 @@ static struct clk_hw_onecell_data sm1_audio_hw_onecell_data = {
};


-/* Convenience table to populate regmap in .probe()
- * Note that this table is shared between both AXG and G12A,
- * with spdifout_b clocks being exclusive to G12A. Since those
- * clocks are not declared within the AXG onecell table, we do not
- * feel the need to have separate AXG/G12A regmap tables.
- */
+/* Convenience table to populate regmap in .probe(). */
static struct clk_regmap *const axg_clk_regmaps[] = {
+ &ddr_arb,
+ &pdm,
+ &tdmin_a,
+ &tdmin_b,
+ &tdmin_c,
+ &tdmin_lb,
+ &tdmout_a,
+ &tdmout_b,
+ &tdmout_c,
+ &frddr_a,
+ &frddr_b,
+ &frddr_c,
+ &toddr_a,
+ &toddr_b,
+ &toddr_c,
+ &loopback,
+ &spdifin,
+ &spdifout,
+ &resample,
+ &power_detect,
+ &mst_a_mclk_sel,
+ &mst_b_mclk_sel,
+ &mst_c_mclk_sel,
+ &mst_d_mclk_sel,
+ &mst_e_mclk_sel,
+ &mst_f_mclk_sel,
+ &mst_a_mclk_div,
+ &mst_b_mclk_div,
+ &mst_c_mclk_div,
+ &mst_d_mclk_div,
+ &mst_e_mclk_div,
+ &mst_f_mclk_div,
+ &mst_a_mclk,
+ &mst_b_mclk,
+ &mst_c_mclk,
+ &mst_d_mclk,
+ &mst_e_mclk,
+ &mst_f_mclk,
+ &spdifout_clk_sel,
+ &spdifout_clk_div,
+ &spdifout_clk,
+ &spdifin_clk_sel,
+ &spdifin_clk_div,
+ &spdifin_clk,
+ &pdm_dclk_sel,
+ &pdm_dclk_div,
+ &pdm_dclk,
+ &pdm_sysclk_sel,
+ &pdm_sysclk_div,
+ &pdm_sysclk,
+ &mst_a_sclk_pre_en,
+ &mst_b_sclk_pre_en,
+ &mst_c_sclk_pre_en,
+ &mst_d_sclk_pre_en,
+ &mst_e_sclk_pre_en,
+ &mst_f_sclk_pre_en,
+ &mst_a_sclk_div,
+ &mst_b_sclk_div,
+ &mst_c_sclk_div,
+ &mst_d_sclk_div,
+ &mst_e_sclk_div,
+ &mst_f_sclk_div,
+ &mst_a_sclk_post_en,
+ &mst_b_sclk_post_en,
+ &mst_c_sclk_post_en,
+ &mst_d_sclk_post_en,
+ &mst_e_sclk_post_en,
+ &mst_f_sclk_post_en,
+ &mst_a_sclk,
+ &mst_b_sclk,
+ &mst_c_sclk,
+ &mst_d_sclk,
+ &mst_e_sclk,
+ &mst_f_sclk,
+ &mst_a_lrclk_div,
+ &mst_b_lrclk_div,
+ &mst_c_lrclk_div,
+ &mst_d_lrclk_div,
+ &mst_e_lrclk_div,
+ &mst_f_lrclk_div,
+ &mst_a_lrclk,
+ &mst_b_lrclk,
+ &mst_c_lrclk,
+ &mst_d_lrclk,
+ &mst_e_lrclk,
+ &mst_f_lrclk,
+ &tdmin_a_sclk_sel,
+ &tdmin_b_sclk_sel,
+ &tdmin_c_sclk_sel,
+ &tdmin_lb_sclk_sel,
+ &tdmout_a_sclk_sel,
+ &tdmout_b_sclk_sel,
+ &tdmout_c_sclk_sel,
+ &tdmin_a_sclk_pre_en,
+ &tdmin_b_sclk_pre_en,
+ &tdmin_c_sclk_pre_en,
+ &tdmin_lb_sclk_pre_en,
+ &tdmout_a_sclk_pre_en,
+ &tdmout_b_sclk_pre_en,
+ &tdmout_c_sclk_pre_en,
+ &tdmin_a_sclk_post_en,
+ &tdmin_b_sclk_post_en,
+ &tdmin_c_sclk_post_en,
+ &tdmin_lb_sclk_post_en,
+ &tdmout_a_sclk_post_en,
+ &tdmout_b_sclk_post_en,
+ &tdmout_c_sclk_post_en,
+ &tdmin_a_sclk,
+ &tdmin_b_sclk,
+ &tdmin_c_sclk,
+ &tdmin_lb_sclk,
+ &tdmout_a_sclk,
+ &tdmout_b_sclk,
+ &tdmout_c_sclk,
+ &tdmin_a_lrclk,
+ &tdmin_b_lrclk,
+ &tdmin_c_lrclk,
+ &tdmin_lb_lrclk,
+ &tdmout_a_lrclk,
+ &tdmout_b_lrclk,
+ &tdmout_c_lrclk,
+};
+
+static struct clk_regmap *const g12a_clk_regmaps[] = {
&ddr_arb,
&pdm,
&tdmin_a,
@@ -1713,8 +1832,8 @@ static const struct audioclk_data axg_audioclk_data = {
};

static const struct audioclk_data g12a_audioclk_data = {
- .regmap_clks = axg_clk_regmaps,
- .regmap_clk_num = ARRAY_SIZE(axg_clk_regmaps),
+ .regmap_clks = g12a_clk_regmaps,
+ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
.hw_onecell_data = &g12a_audio_hw_onecell_data,
.reset_offset = AUDIO_SW_RESET,
.reset_num = 26,
--
2.25.4

2020-07-29 15:45:23

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH 1/3] clk: meson: add sclk-ws driver

This is yet another simple but odd driver for the audio block of the g12a
and sm1 SoC families.

For TDMOUT's sclk to be properly inverted, bit 29 of
AUDIO_CLK_TDMOUT_x_CTRL should be the inverse of bit 28.
IOW bit28 == !bit29 at all times

This setting is automatically applied on axg and the manual setting was
added on g12a.

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/clk-phase.c | 56 +++++++++++++++++++++++++++++++++++
drivers/clk/meson/clk-phase.h | 6 ++++
2 files changed, 62 insertions(+)

diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c
index fe22e171121a..a6763439f7d2 100644
--- a/drivers/clk/meson/clk-phase.c
+++ b/drivers/clk/meson/clk-phase.c
@@ -125,6 +125,62 @@ const struct clk_ops meson_clk_triphase_ops = {
};
EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);

+/*
+ * This is a special clock for the audio controller.
+ * This drive a bit clock inverter for which the
+ * opposite value of the inverter bit needs to be manually
+ * set into another bit
+ */
+static inline struct meson_sclk_ws_inv_data *
+meson_sclk_ws_inv_data(struct clk_regmap *clk)
+{
+ return (struct meson_sclk_ws_inv_data *)clk->data;
+}
+
+static int meson_sclk_ws_inv_sync(struct clk_hw *hw)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk);
+ unsigned int val;
+
+ /* Get phase and sync the inverted value to ws */
+ val = meson_parm_read(clk->map, &tph->ph);
+ meson_parm_write(clk->map, &tph->ws, val ? 0 : 1);
+
+ return 0;
+}
+
+static int meson_sclk_ws_inv_get_phase(struct clk_hw *hw)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk);
+ unsigned int val;
+
+ val = meson_parm_read(clk->map, &tph->ph);
+
+ return meson_clk_degrees_from_val(val, tph->ph.width);
+}
+
+static int meson_sclk_ws_inv_set_phase(struct clk_hw *hw, int degrees)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk);
+ unsigned int val;
+
+ val = meson_clk_degrees_to_val(degrees, tph->ph.width);
+ meson_parm_write(clk->map, &tph->ph, val);
+ meson_parm_write(clk->map, &tph->ws, val ? 0 : 1);
+ return 0;
+}
+
+const struct clk_ops meson_sclk_ws_inv_ops = {
+ .init = meson_sclk_ws_inv_sync,
+ .get_phase = meson_sclk_ws_inv_get_phase,
+ .set_phase = meson_sclk_ws_inv_set_phase,
+};
+EXPORT_SYMBOL_GPL(meson_sclk_ws_inv_ops);
+
+
MODULE_DESCRIPTION("Amlogic phase driver");
MODULE_AUTHOR("Jerome Brunet <[email protected]>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-phase.h b/drivers/clk/meson/clk-phase.h
index 5579f9ced142..b637b9b227bc 100644
--- a/drivers/clk/meson/clk-phase.h
+++ b/drivers/clk/meson/clk-phase.h
@@ -20,7 +20,13 @@ struct meson_clk_triphase_data {
struct parm ph2;
};

+struct meson_sclk_ws_inv_data {
+ struct parm ph;
+ struct parm ws;
+};
+
extern const struct clk_ops meson_clk_phase_ops;
extern const struct clk_ops meson_clk_triphase_ops;
+extern const struct clk_ops meson_sclk_ws_inv_ops;

#endif /* __MESON_CLK_PHASE_H */
--
2.25.4

2020-07-29 15:47:53

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH 3/3] clk: meson: axg-audio: fix g12a tdmout sclk inverter

Fix the tdmout inverter of the g12a and following SoC families.
This inverter is special and needs two bits to be the inverse of each other
for the inverter to operate properly.

Fixes: 075001385c66 ("clk: meson: axg-audio: add g12a support")
Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/axg-audio.c | 85 ++++++++++++++++++++++++-----------
1 file changed, 60 insertions(+), 25 deletions(-)

diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index 9918cb375de3..7c8d02164443 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -147,6 +147,29 @@
}, \
}

+#define AUD_SCLK_WS(_name, _reg, _width, _shift_ph, _shift_ws, _pname, \
+ _iflags) { \
+ .data = &(struct meson_sclk_ws_inv_data) { \
+ .ph = { \
+ .reg_off = (_reg), \
+ .shift = (_shift_ph), \
+ .width = (_width), \
+ }, \
+ .ws = { \
+ .reg_off = (_reg), \
+ .shift = (_shift_ws), \
+ .width = (_width), \
+ }, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = "aud_"#_name, \
+ .ops = &meson_clk_phase_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = (_iflags), \
+ }, \
+}
+
/* Audio Master Clocks */
static const struct clk_parent_data mst_mux_parent_data[] = {
{ .fw_name = "mst_in0", },
@@ -254,6 +277,10 @@ static const struct clk_parent_data tdm_lrclk_parent_data[] = {
AUD_PHASE(tdm##_name##_sclk, _reg, 1, 29, \
aud_tdm##_name##_sclk_post_en, \
CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)
+#define AUD_TDM_SCLK_WS(_name, _reg) \
+ AUD_SCLK_WS(tdm##_name##_sclk, _reg, 1, 29, 28, \
+ aud_tdm##_name##_sclk_post_en, \
+ CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)

#define AUD_TDM_LRLCK(_name, _reg) \
AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
@@ -499,12 +526,6 @@ static struct clk_regmap tdmin_c_sclk =
AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL);
static struct clk_regmap tdmin_lb_sclk =
AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
-static struct clk_regmap tdmout_a_sclk =
- AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
-static struct clk_regmap tdmout_b_sclk =
- AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
-static struct clk_regmap tdmout_c_sclk =
- AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);

static struct clk_regmap tdmin_a_lrclk =
AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL);
@@ -521,6 +542,14 @@ static struct clk_regmap tdmout_b_lrclk =
static struct clk_regmap tdmout_c_lrclk =
AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);

+/* AXG Clocks */
+static struct clk_regmap axg_tdmout_a_sclk =
+ AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static struct clk_regmap axg_tdmout_b_sclk =
+ AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static struct clk_regmap axg_tdmout_c_sclk =
+ AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
/* AXG/G12A Clocks */
static struct clk_hw axg_aud_top = {
.init = &(struct clk_init_data) {
@@ -591,7 +620,13 @@ static struct clk_regmap g12a_tdm_sclk_pad_1 = AUD_TDM_PAD_CTRL(
static struct clk_regmap g12a_tdm_sclk_pad_2 = AUD_TDM_PAD_CTRL(
sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, sclk_pad_ctrl_parent_data);

-/* G12a/SM1 clocks */
+static struct clk_regmap g12a_tdmout_a_sclk =
+ AUD_TDM_SCLK_WS(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static struct clk_regmap g12a_tdmout_b_sclk =
+ AUD_TDM_SCLK_WS(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static struct clk_regmap g12a_tdmout_c_sclk =
+ AUD_TDM_SCLK_WS(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
static struct clk_regmap toram =
AUD_PCLK_GATE(toram, AUDIO_CLK_GATE_EN, 20);
static struct clk_regmap spdifout_b =
@@ -889,9 +924,9 @@ static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
[AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw,
[AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw,
[AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw,
- [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw,
- [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw,
- [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw,
+ [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw,
[AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw,
[AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw,
[AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw,
@@ -1026,9 +1061,9 @@ static struct clk_hw_onecell_data g12a_audio_hw_onecell_data = {
[AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw,
[AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw,
[AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw,
- [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw,
- [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw,
- [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw,
+ [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw,
[AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw,
[AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw,
[AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw,
@@ -1170,9 +1205,9 @@ static struct clk_hw_onecell_data sm1_audio_hw_onecell_data = {
[AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw,
[AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw,
[AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw,
- [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw,
- [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw,
- [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw,
+ [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw,
[AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw,
[AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw,
[AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw,
@@ -1322,9 +1357,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&tdmin_b_sclk,
&tdmin_c_sclk,
&tdmin_lb_sclk,
- &tdmout_a_sclk,
- &tdmout_b_sclk,
- &tdmout_c_sclk,
+ &axg_tdmout_a_sclk,
+ &axg_tdmout_b_sclk,
+ &axg_tdmout_c_sclk,
&tdmin_a_lrclk,
&tdmin_b_lrclk,
&tdmin_c_lrclk,
@@ -1447,9 +1482,9 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&tdmin_b_sclk,
&tdmin_c_sclk,
&tdmin_lb_sclk,
- &tdmout_a_sclk,
- &tdmout_b_sclk,
- &tdmout_c_sclk,
+ &g12a_tdmout_a_sclk,
+ &g12a_tdmout_b_sclk,
+ &g12a_tdmout_c_sclk,
&tdmin_a_lrclk,
&tdmin_b_lrclk,
&tdmin_c_lrclk,
@@ -1584,9 +1619,9 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
&tdmin_b_sclk,
&tdmin_c_sclk,
&tdmin_lb_sclk,
- &tdmout_a_sclk,
- &tdmout_b_sclk,
- &tdmout_c_sclk,
+ &g12a_tdmout_a_sclk,
+ &g12a_tdmout_b_sclk,
+ &g12a_tdmout_c_sclk,
&tdmin_a_lrclk,
&tdmin_b_lrclk,
&tdmin_c_lrclk,
--
2.25.4