linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] clk: meson: Add video clocks path
@ 2018-07-20  9:39 Neil Armstrong
  2018-07-20  9:39 ` [PATCH 1/2] clk: meson: Add vid_pll divider driver Neil Armstrong
  2018-07-20  9:39 ` [PATCH 2/2] clk: meson-gxbb: Add video clocks Neil Armstrong
  0 siblings, 2 replies; 8+ messages in thread
From: Neil Armstrong @ 2018-07-20  9:39 UTC (permalink / raw)
  To: jbrunet
  Cc: Neil Armstrong, linux-clk, linux-amlogic, linux-arm-kernel, linux-kernel

This patchset adds initial support the Video Clocks used in the Display
Pipelin from the DRM driver.
The DRM driver is in his way to finaly switch to the Common Clock Framework
to setup the clock path, this adds the clock entries that will be used
by the DRM driver in a near future.

The vid_pll programmable divider is introduced in its R/O form right now,
but will be extended to be R/W in a next iteration.

Until the DRM driver actually uses these clocks, the Gates are marked as
IGNORE_IF_UNSUSED and the MUX/Dividers as NOCACHE since the registers
will be modified directly.

Neil Armstrong (2):
  clk: meson: Add vid_pll divider driver
  clk: meson-gxbb: Add video clocks

 drivers/clk/meson/Makefile            |   2 +-
 drivers/clk/meson/clkc.h              |   6 +
 drivers/clk/meson/gxbb.c              | 667 ++++++++++++++++++++++++++++++++++
 drivers/clk/meson/gxbb.h              |  24 +-
 drivers/clk/meson/vid-pll-div.c       |  90 +++++
 include/dt-bindings/clock/gxbb-clkc.h |  17 +
 6 files changed, 803 insertions(+), 3 deletions(-)
 create mode 100644 drivers/clk/meson/vid-pll-div.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] clk: meson: Add vid_pll divider driver
  2018-07-20  9:39 [PATCH 0/2] clk: meson: Add video clocks path Neil Armstrong
@ 2018-07-20  9:39 ` Neil Armstrong
  2018-07-20 19:17   ` Martin Blumenstingl
  2018-07-20  9:39 ` [PATCH 2/2] clk: meson-gxbb: Add video clocks Neil Armstrong
  1 sibling, 1 reply; 8+ messages in thread
From: Neil Armstrong @ 2018-07-20  9:39 UTC (permalink / raw)
  To: jbrunet
  Cc: Neil Armstrong, linux-clk, linux-amlogic, linux-arm-kernel, linux-kernel

Add support the VID_PLL fully programmable divider used right after the
HDMI PLL clock source. It is used to achieve complex fractional division
with a programmble bitfield.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/clk/meson/Makefile      |  2 +-
 drivers/clk/meson/clkc.h        |  6 +++
 drivers/clk/meson/vid-pll-div.c | 90 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/meson/vid-pll-div.c

diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 72ec8c4..0234767 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -2,7 +2,7 @@
 # Makefile for Meson specific clk
 #
 
-obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
+obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
 obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 6b96d55..9166605 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -90,6 +90,11 @@ struct meson_clk_phase_data {
 int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
 unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
 
+struct meson_vid_pll_div_data {
+	struct parm val;
+	struct parm sel;
+};
+
 #define MESON_GATE(_name, _reg, _bit)					\
 struct clk_regmap _name = {						\
 	.data = &(struct clk_regmap_gate_data){				\
@@ -112,5 +117,6 @@ extern const struct clk_ops meson_clk_cpu_ops;
 extern const struct clk_ops meson_clk_mpll_ro_ops;
 extern const struct clk_ops meson_clk_mpll_ops;
 extern const struct clk_ops meson_clk_phase_ops;
+extern const struct clk_ops meson_vid_pll_div_ro_ops;
 
 #endif /* __CLKC_H */
diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
new file mode 100644
index 0000000..5f267be
--- /dev/null
+++ b/drivers/clk/meson/vid-pll-div.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include "clkc.h"
+
+static inline struct meson_vid_pll_div_data *
+meson_vid_pll_div_data(struct clk_regmap *clk)
+{
+	return (struct meson_vid_pll_div_data *)clk->data;
+}
+
+/*
+ * This vid_pll divided is a fully programmable fractionnal divider to
+ * achieve complex video clock rates.
+ *
+ * Here are provided the commonly used fraction values provided by Amlogic.
+ */
+
+struct vid_pll_div {
+	unsigned int shift_val;
+	unsigned int shift_sel;
+	unsigned int frac_top;
+	unsigned int frac_bot;
+};
+
+#define VID_PLL_DIV(_val, _sel, _ft, _fb)				\
+	{								\
+		.shift_val = (_val),					\
+		.shift_sel = (_sel),					\
+		.frac_top = (_ft),					\
+		.frac_bot = (_fb),					\
+	}
+
+static const struct vid_pll_div vid_pll_div_table[] = {
+	VID_PLL_DIV(0x0aaa, 0, 2, 1),	/* 2/1  => /2 */
+	VID_PLL_DIV(0x5294, 2, 5, 2),	/* 5/2  => /2.5 */
+	VID_PLL_DIV(0x0db6, 0, 3, 1),	/* 3/1  => /3 */
+	VID_PLL_DIV(0x36cc, 1, 7, 2),	/* 7/2  => /3.5 */
+	VID_PLL_DIV(0x6666, 2, 15, 4),	/* 15/4 => /3.75 */
+	VID_PLL_DIV(0x0ccc, 4, 4, 1),	/* 4/1  => /4 */
+	VID_PLL_DIV(0x739c, 2, 5, 1),	/* 5/1  => /5 */
+	VID_PLL_DIV(0x0e38, 0, 6, 1),	/* 6/1  => /6 */
+	VID_PLL_DIV(0x0000, 3, 25, 4),	/* 25/4 => /6.25 */
+	VID_PLL_DIV(0x3c78, 1, 7, 1),	/* 7/1  => /7 */
+	VID_PLL_DIV(0x78f0, 2, 15, 2),	/* 15/2 => /7.5 */
+	VID_PLL_DIV(0x0fc0, 0, 12, 1),	/* 12/1 => /12 */
+	VID_PLL_DIV(0x3f80, 1, 14, 1),	/* 14/1 => /14 */
+	VID_PLL_DIV(0x7f80, 2, 15, 1),	/* 15/1 => /15 */
+};
+
+#define to_meson_vid_pll_div(_hw) container_of(_hw, struct meson_vid_pll_div, hw)
+
+const struct vid_pll_div *_get_table_val(unsigned int shift_val,
+					 unsigned int shift_sel)
+{
+	int i;
+
+	for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
+		if (vid_pll_div_table[i].shift_val == shift_val &&
+		    vid_pll_div_table[i].shift_sel == shift_sel)
+			return &vid_pll_div_table[i];
+	}
+
+	return NULL;
+}
+
+static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
+						   unsigned long parent_rate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
+	const struct vid_pll_div *div;
+
+	div = _get_table_val(meson_parm_read(clk->map, &pll_div->val),
+			     meson_parm_read(clk->map, &pll_div->sel));
+	if (!div || !div->frac_top) {
+		pr_info("%s: Invalid config value for vid_pll_div\n", __func__);
+		return parent_rate;
+	}
+
+	return DIV_ROUND_UP_ULL(parent_rate * div->frac_bot, div->frac_top);
+}
+
+const struct clk_ops meson_vid_pll_div_ro_ops = {
+	.recalc_rate	= meson_vid_pll_div_recalc_rate,
+};
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] clk: meson-gxbb: Add video clocks
  2018-07-20  9:39 [PATCH 0/2] clk: meson: Add video clocks path Neil Armstrong
  2018-07-20  9:39 ` [PATCH 1/2] clk: meson: Add vid_pll divider driver Neil Armstrong
@ 2018-07-20  9:39 ` Neil Armstrong
  2018-07-20 19:00   ` Martin Blumenstingl
  1 sibling, 1 reply; 8+ messages in thread
From: Neil Armstrong @ 2018-07-20  9:39 UTC (permalink / raw)
  To: jbrunet
  Cc: Neil Armstrong, linux-clk, linux-amlogic, linux-arm-kernel, linux-kernel

Add the clocks entries used in the video clock path, the clock path
is doubled to permit having different synchronized clocks for different
parts of the video pipeline.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/clk/meson/gxbb.c              | 667 ++++++++++++++++++++++++++++++++++
 drivers/clk/meson/gxbb.h              |  24 +-
 include/dt-bindings/clock/gxbb-clkc.h |  17 +
 3 files changed, 706 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index f79ea33..5fabedf 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -1508,6 +1508,570 @@ static struct clk_regmap gxbb_vapb = {
 	},
 };
 
+/* Video Clocks */
+
+static struct clk_regmap gxbb_vid_pll_div = {
+	.data = &(struct meson_vid_pll_div_data){
+		.val = {
+			.reg_off = HHI_VID_PLL_CLK_DIV,
+			.shift   = 0,
+			.width   = 15,
+		},
+		.sel = {
+			.reg_off = HHI_VID_PLL_CLK_DIV,
+			.shift   = 16,
+			.width   = 2,
+		},
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vid_pll_div",
+		.ops = &meson_vid_pll_div_ro_ops,
+		.parent_names = (const char *[]){ "hdmi_pll" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static u32 mux_table_vid_pll[] = { 0, 1 };
+const char *gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" };
+
+static struct clk_regmap gxbb_vid_pll_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VID_PLL_CLK_DIV,
+		.mask = 0x1,
+		.shift = 18,
+		.table = mux_table_vid_pll,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vid_pll_sel",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * bit 18 selects from 2 possible parents:
+		 * vid_pll_div or hdmi_pll
+		 */
+		.parent_names = gxbb_vid_pll_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_vid_pll = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_PLL_CLK_DIV,
+		.bit_idx = 19,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vid_pll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vid_pll_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static u32 mux_table_vclk[] = { 0, 1, 2, 3, 4, 5, 6 };
+const char *gxbb_vclk_parent_names[] = {
+	"vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll",
+	"fclk_div7", "mpll1",
+};
+
+static struct clk_regmap gxbb_vclk_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.mask = 0x7,
+		.shift = 16,
+		.table = mux_table_vclk,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_sel",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * bits 16:18 selects from 8 possible parents:
+		 * vid_pll, fclk_div4, fclk_div3, fclk_div5,
+		 * vid_pll, fclk_div7, mp1
+		 */
+		.parent_names = gxbb_vclk_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.mask = 0x7,
+		.shift = 16,
+		.table = mux_table_vclk,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_sel",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * bits 16:18 selects from 8 possible parents:
+		 * vid_pll, fclk_div4, fclk_div3, fclk_div5,
+		 * vid_pll, fclk_div7, mp1
+		 */
+		.parent_names = gxbb_vclk_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_input = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_DIV,
+		.bit_idx = 16,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_input",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_input = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_DIV,
+		.bit_idx = 16,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_input",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HHI_VID_CLK_DIV,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_names = (const char *[]){ "vclk_input" },
+		.num_parents = 1,
+		.flags = CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = HHI_VIID_CLK_DIV,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_names = (const char *[]){ "vclk2_input" },
+		.num_parents = 1,
+		.flags = CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_vclk = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 19,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 19,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_div1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div2_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_div2_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div4_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_div4_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div6_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 3,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_div6_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk_div12_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL,
+		.bit_idx = 4,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk_div12_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_div1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div2_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_div2_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div4_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_div4_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div6_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 3,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_div6_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_vclk2_div12_en = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VIID_CLK_CNTL,
+		.bit_idx = 4,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk2_div12_en",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "vclk2" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk_div2_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk_div4 = {
+	.mult = 1,
+	.div = 4,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_div4",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk_div4_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk_div6 = {
+	.mult = 1,
+	.div = 6,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_div6",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk_div6_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk_div12 = {
+	.mult = 1,
+	.div = 12,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk_div12",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk_div12_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk2_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk2_div2_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk2_div4 = {
+	.mult = 1,
+	.div = 4,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_div4",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk2_div4_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk2_div6 = {
+	.mult = 1,
+	.div = 6,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_div6",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk2_div6_en" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor gxbb_vclk2_div12 = {
+	.mult = 1,
+	.div = 12,
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk2_div12",
+		.ops = &clk_fixed_factor_ops,
+		.parent_names = (const char *[]){ "vclk2_div12_en" },
+		.num_parents = 1,
+	},
+};
+
+static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+const char *gxbb_cts_parent_names[] = {
+	"vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
+	"vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
+	"vclk2_div6", "vclk2_div12"
+};
+
+static struct clk_regmap gxbb_cts_enci_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 28,
+		.table = mux_table_cts_sel,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cts_enci_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_names = gxbb_cts_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_cts_encp_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 20,
+		.table = mux_table_cts_sel,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cts_encp_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_names = gxbb_cts_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_cts_vdac_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_VIID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 28,
+		.table = mux_table_cts_sel,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cts_vdac_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_names = gxbb_cts_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+/* TOFIX: add support for cts_tcon */
+static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+const char *gxbb_cts_hdmi_tx_parent_names[] = {
+	"vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
+	"vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
+	"vclk2_div6", "vclk2_div12"
+};
+
+static struct clk_regmap gxbb_hdmi_tx_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = HHI_HDMI_CLK_CNTL,
+		.mask = 0xf,
+		.shift = 16,
+		.table = mux_table_hdmi_tx_sel,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hdmi_tx_sel",
+		.ops = &clk_regmap_mux_ops,
+		/*
+		 * bits 31:28 selects from 12 possible parents:
+		 * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12
+		 * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12,
+		 * cts_tcon
+		 */
+		.parent_names = gxbb_cts_hdmi_tx_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+	},
+};
+
+static struct clk_regmap gxbb_cts_enci = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL2,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cts_enci",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "cts_enci_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_cts_encp = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL2,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cts_encp",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "cts_encp_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_cts_vdac = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL2,
+		.bit_idx = 4,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cts_vdac",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "cts_vdac_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap gxbb_hdmi_tx = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = HHI_VID_CLK_CNTL2,
+		.bit_idx = 5,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hdmi_tx",
+		.ops = &clk_regmap_gate_ops,
+		.parent_names = (const char *[]){ "hdmi_tx_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
 /* VDEC clocks */
 
 static const char * const gxbb_vdec_parent_names[] = {
@@ -1919,6 +2483,43 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
 		[CLKID_HDMI_PLL_OD2]	    = &gxbb_hdmi_pll_od2.hw,
 		[CLKID_SYS_PLL_DCO]	    = &gxbb_sys_pll_dco.hw,
 		[CLKID_GP0_PLL_DCO]	    = &gxbb_gp0_pll_dco.hw,
+		[CLKID_VID_PLL_DIV]	    = &gxbb_vid_pll_div.hw,
+		[CLKID_VID_PLL_SEL]	    = &gxbb_vid_pll_sel.hw,
+		[CLKID_VID_PLL]		    = &gxbb_vid_pll.hw,
+		[CLKID_VCLK_SEL]	    = &gxbb_vclk_sel.hw,
+		[CLKID_VCLK2_SEL]	    = &gxbb_vclk2_sel.hw,
+		[CLKID_VCLK_INPUT]	    = &gxbb_vclk_input.hw,
+		[CLKID_VCLK2_INPUT]	    = &gxbb_vclk2_input.hw,
+		[CLKID_VCLK_DIV]	    = &gxbb_vclk_div.hw,
+		[CLKID_VCLK2_DIV]	    = &gxbb_vclk2_div.hw,
+		[CLKID_VCLK]		    = &gxbb_vclk.hw,
+		[CLKID_VCLK2]		    = &gxbb_vclk2.hw,
+		[CLKID_VCLK_DIV1]	    = &gxbb_vclk_div1.hw,
+		[CLKID_VCLK_DIV2_EN]	    = &gxbb_vclk_div2_en.hw,
+		[CLKID_VCLK_DIV2]	    = &gxbb_vclk_div2.hw,
+		[CLKID_VCLK_DIV4_EN]	    = &gxbb_vclk_div4_en.hw,
+		[CLKID_VCLK_DIV4]	    = &gxbb_vclk_div4.hw,
+		[CLKID_VCLK_DIV6_EN]	    = &gxbb_vclk_div6_en.hw,
+		[CLKID_VCLK_DIV6]	    = &gxbb_vclk_div6.hw,
+		[CLKID_VCLK_DIV12_EN]	    = &gxbb_vclk_div12_en.hw,
+		[CLKID_VCLK_DIV12]	    = &gxbb_vclk_div12.hw,
+		[CLKID_VCLK2_DIV1]	    = &gxbb_vclk2_div1.hw,
+		[CLKID_VCLK2_DIV2_EN]	    = &gxbb_vclk2_div2_en.hw,
+		[CLKID_VCLK2_DIV2]	    = &gxbb_vclk2_div2.hw,
+		[CLKID_VCLK2_DIV4_EN]	    = &gxbb_vclk2_div4_en.hw,
+		[CLKID_VCLK2_DIV4]	    = &gxbb_vclk2_div4.hw,
+		[CLKID_VCLK2_DIV6_EN]	    = &gxbb_vclk2_div6_en.hw,
+		[CLKID_VCLK2_DIV6]	    = &gxbb_vclk2_div6.hw,
+		[CLKID_VCLK2_DIV12_EN]	    = &gxbb_vclk2_div12_en.hw,
+		[CLKID_VCLK2_DIV12]	    = &gxbb_vclk2_div12.hw,
+		[CLKID_CTS_ENCI_SEL]	    = &gxbb_cts_enci_sel.hw,
+		[CLKID_CTS_ENCP_SEL]	    = &gxbb_cts_encp_sel.hw,
+		[CLKID_CTS_VDAC_SEL]	    = &gxbb_cts_vdac_sel.hw,
+		[CLKID_HDMI_TX_SEL]	    = &gxbb_hdmi_tx_sel.hw,
+		[CLKID_CTS_ENCI]	    = &gxbb_cts_enci.hw,
+		[CLKID_CTS_ENCP]	    = &gxbb_cts_encp.hw,
+		[CLKID_CTS_VDAC]	    = &gxbb_cts_vdac.hw,
+		[CLKID_HDMI_TX]		    = &gxbb_hdmi_tx.hw,
 		[NR_CLKS]		    = NULL,
 	},
 	.num = NR_CLKS,
@@ -2090,6 +2691,43 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
 		[CLKID_HDMI_PLL_OD2]	    = &gxl_hdmi_pll_od2.hw,
 		[CLKID_SYS_PLL_DCO]	    = &gxbb_sys_pll_dco.hw,
 		[CLKID_GP0_PLL_DCO]	    = &gxl_gp0_pll_dco.hw,
+		[CLKID_VID_PLL_DIV]	    = &gxbb_vid_pll_div.hw,
+		[CLKID_VID_PLL_SEL]	    = &gxbb_vid_pll_sel.hw,
+		[CLKID_VID_PLL]		    = &gxbb_vid_pll.hw,
+		[CLKID_VCLK_SEL]	    = &gxbb_vclk_sel.hw,
+		[CLKID_VCLK2_SEL]	    = &gxbb_vclk2_sel.hw,
+		[CLKID_VCLK_INPUT]	    = &gxbb_vclk_input.hw,
+		[CLKID_VCLK2_INPUT]	    = &gxbb_vclk2_input.hw,
+		[CLKID_VCLK_DIV]	    = &gxbb_vclk_div.hw,
+		[CLKID_VCLK2_DIV]	    = &gxbb_vclk2_div.hw,
+		[CLKID_VCLK]		    = &gxbb_vclk.hw,
+		[CLKID_VCLK2]		    = &gxbb_vclk2.hw,
+		[CLKID_VCLK_DIV1]	    = &gxbb_vclk_div1.hw,
+		[CLKID_VCLK_DIV2_EN]	    = &gxbb_vclk_div2_en.hw,
+		[CLKID_VCLK_DIV2]	    = &gxbb_vclk_div2.hw,
+		[CLKID_VCLK_DIV4_EN]	    = &gxbb_vclk_div4_en.hw,
+		[CLKID_VCLK_DIV4]	    = &gxbb_vclk_div4.hw,
+		[CLKID_VCLK_DIV6_EN]	    = &gxbb_vclk_div6_en.hw,
+		[CLKID_VCLK_DIV6]	    = &gxbb_vclk_div6.hw,
+		[CLKID_VCLK_DIV12_EN]	    = &gxbb_vclk_div12_en.hw,
+		[CLKID_VCLK_DIV12]	    = &gxbb_vclk_div12.hw,
+		[CLKID_VCLK2_DIV1]	    = &gxbb_vclk2_div1.hw,
+		[CLKID_VCLK2_DIV2_EN]	    = &gxbb_vclk2_div2_en.hw,
+		[CLKID_VCLK2_DIV2]	    = &gxbb_vclk2_div2.hw,
+		[CLKID_VCLK2_DIV4_EN]	    = &gxbb_vclk2_div4_en.hw,
+		[CLKID_VCLK2_DIV4]	    = &gxbb_vclk2_div4.hw,
+		[CLKID_VCLK2_DIV6_EN]	    = &gxbb_vclk2_div6_en.hw,
+		[CLKID_VCLK2_DIV6]	    = &gxbb_vclk2_div6.hw,
+		[CLKID_VCLK2_DIV12_EN]	    = &gxbb_vclk2_div12_en.hw,
+		[CLKID_VCLK2_DIV12]	    = &gxbb_vclk2_div12.hw,
+		[CLKID_CTS_ENCI_SEL]	    = &gxbb_cts_enci_sel.hw,
+		[CLKID_CTS_ENCP_SEL]	    = &gxbb_cts_encp_sel.hw,
+		[CLKID_CTS_VDAC_SEL]	    = &gxbb_cts_vdac_sel.hw,
+		[CLKID_HDMI_TX_SEL]	    = &gxbb_hdmi_tx_sel.hw,
+		[CLKID_CTS_ENCI]	    = &gxbb_cts_enci.hw,
+		[CLKID_CTS_ENCP]	    = &gxbb_cts_encp.hw,
+		[CLKID_CTS_VDAC]	    = &gxbb_cts_vdac.hw,
+		[CLKID_HDMI_TX]		    = &gxbb_hdmi_tx.hw,
 		[NR_CLKS]		    = NULL,
 	},
 	.num = NR_CLKS,
@@ -2265,6 +2903,35 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
 	&gxbb_hdmi_pll_dco,
 	&gxbb_sys_pll_dco,
 	&gxbb_gp0_pll,
+	&gxbb_vid_pll,
+	&gxbb_vid_pll_sel,
+	&gxbb_vid_pll_div,
+	&gxbb_vclk,
+	&gxbb_vclk_sel,
+	&gxbb_vclk_div,
+	&gxbb_vclk_input,
+	&gxbb_vclk_div1,
+	&gxbb_vclk_div2_en,
+	&gxbb_vclk_div4_en,
+	&gxbb_vclk_div6_en,
+	&gxbb_vclk_div12_en,
+	&gxbb_vclk2,
+	&gxbb_vclk2_sel,
+	&gxbb_vclk2_div,
+	&gxbb_vclk2_input,
+	&gxbb_vclk2_div1,
+	&gxbb_vclk2_div2_en,
+	&gxbb_vclk2_div4_en,
+	&gxbb_vclk2_div6_en,
+	&gxbb_vclk2_div12_en,
+	&gxbb_cts_enci,
+	&gxbb_cts_enci_sel,
+	&gxbb_cts_encp,
+	&gxbb_cts_encp_sel,
+	&gxbb_cts_vdac,
+	&gxbb_cts_vdac_sel,
+	&gxbb_hdmi_tx,
+	&gxbb_hdmi_tx_sel,
 };
 
 struct clkc_data {
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 72bc077..171b7d8 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -165,8 +165,28 @@
 #define CLKID_HDMI_PLL_OD2	  163
 #define CLKID_SYS_PLL_DCO	  164
 #define CLKID_GP0_PLL_DCO	  165
-
-#define NR_CLKS			  166
+#define CLKID_VID_PLL_SEL	  167
+#define CLKID_VID_PLL_DIV	  168
+#define CLKID_VCLK_SEL	  	  169
+#define CLKID_VCLK2_SEL		  170
+#define CLKID_VCLK_INPUT	  171
+#define CLKID_VCLK2_INPUT	  172
+#define CLKID_VCLK_DIV		  173
+#define CLKID_VCLK2_DIV		  174
+#define CLKID_VCLK_DIV2_EN	  177
+#define CLKID_VCLK_DIV4_EN	  178
+#define CLKID_VCLK_DIV6_EN	  179
+#define CLKID_VCLK_DIV12_EN	  180
+#define CLKID_VCLK2_DIV2_EN	  181
+#define CLKID_VCLK2_DIV4_EN	  182
+#define CLKID_VCLK2_DIV6_EN	  183
+#define CLKID_VCLK2_DIV12_EN	  184
+#define CLKID_CTS_ENCI_SEL	  195
+#define CLKID_CTS_ENCP_SEL	  196
+#define CLKID_CTS_VDAC_SEL	  197
+#define CLKID_HDMI_TX_SEL	  198
+
+#define NR_CLKS			  203
 
 /* include the CLKIDs that have been made part of the DT binding */
 #include <dt-bindings/clock/gxbb-clkc.h>
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 3979d48..9f7b99e 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -128,5 +128,22 @@
 #define CLKID_VDEC_1		153
 #define CLKID_VDEC_HEVC		156
 #define CLKID_GEN_CLK		159
+#define CLKID_VID_PLL		166
+#define CLKID_VCLK		175
+#define CLKID_VCLK2		176
+#define CLKID_VCLK_DIV1		185
+#define CLKID_VCLK_DIV2		186
+#define CLKID_VCLK_DIV4		187
+#define CLKID_VCLK_DIV6		188
+#define CLKID_VCLK_DIV12	189
+#define CLKID_VCLK2_DIV1	190
+#define CLKID_VCLK2_DIV2	191
+#define CLKID_VCLK2_DIV4	192
+#define CLKID_VCLK2_DIV6	193
+#define CLKID_VCLK2_DIV12	194
+#define CLKID_CTS_ENCI		199
+#define CLKID_CTS_ENCP		200
+#define CLKID_CTS_VDAC		201
+#define CLKID_HDMI_TX		202
 
 #endif /* __GXBB_CLKC_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] clk: meson-gxbb: Add video clocks
  2018-07-20  9:39 ` [PATCH 2/2] clk: meson-gxbb: Add video clocks Neil Armstrong
@ 2018-07-20 19:00   ` Martin Blumenstingl
  2018-07-24 12:04     ` Neil Armstrong
  0 siblings, 1 reply; 8+ messages in thread
From: Martin Blumenstingl @ 2018-07-20 19:00 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jbrunet, linux-amlogic, linux-kernel, linux-clk, linux-arm-kernel

Hi Neil,

On Fri, Jul 20, 2018 at 11:40 AM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Add the clocks entries used in the video clock path, the clock path
> is doubled to permit having different synchronized clocks for different
> parts of the video pipeline.
maybe you can add the comment about CLK_GET_RATE_NOCACHE here as well

> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/clk/meson/gxbb.c              | 667 ++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/gxbb.h              |  24 +-
>  include/dt-bindings/clock/gxbb-clkc.h |  17 +
>  3 files changed, 706 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
> index f79ea33..5fabedf 100644
> --- a/drivers/clk/meson/gxbb.c
> +++ b/drivers/clk/meson/gxbb.c
> @@ -1508,6 +1508,570 @@ static struct clk_regmap gxbb_vapb = {
>         },
>  };
>
> +/* Video Clocks */
> +
> +static struct clk_regmap gxbb_vid_pll_div = {
> +       .data = &(struct meson_vid_pll_div_data){
> +               .val = {
> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
> +                       .shift   = 0,
> +                       .width   = 15,
> +               },
> +               .sel = {
> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
> +                       .shift   = 16,
> +                       .width   = 2,
> +               },
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vid_pll_div",
> +               .ops = &meson_vid_pll_div_ro_ops,
> +               .parent_names = (const char *[]){ "hdmi_pll" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static u32 mux_table_vid_pll[] = { 0, 1 };
you can drop this mux table

> +const char *gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" };
> +
> +static struct clk_regmap gxbb_vid_pll_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VID_PLL_CLK_DIV,
> +               .mask = 0x1,
> +               .shift = 18,
> +               .table = mux_table_vid_pll,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vid_pll_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               /*
> +                * bit 18 selects from 2 possible parents:
> +                * vid_pll_div or hdmi_pll
> +                */
> +               .parent_names = gxbb_vid_pll_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vid_pll = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_PLL_CLK_DIV,
> +               .bit_idx = 19,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vid_pll",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vid_pll_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static u32 mux_table_vclk[] = { 0, 1, 2, 3, 4, 5, 6 };
you can drop this mux table

> +const char *gxbb_vclk_parent_names[] = {
> +       "vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll",
> +       "fclk_div7", "mpll1",
> +};
> +
> +static struct clk_regmap gxbb_vclk_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .mask = 0x7,
> +               .shift = 16,
> +               .table = mux_table_vclk,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               /*
> +                * bits 16:18 selects from 8 possible parents:
> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
> +                * vid_pll, fclk_div7, mp1
> +                */
> +               .parent_names = gxbb_vclk_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .mask = 0x7,
> +               .shift = 16,
> +               .table = mux_table_vclk,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               /*
> +                * bits 16:18 selects from 8 possible parents:
> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
> +                * vid_pll, fclk_div7, mp1
> +                */
> +               .parent_names = gxbb_vclk_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_input = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_DIV,
> +               .bit_idx = 16,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_input",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_input = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_DIV,
> +               .bit_idx = 16,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_input",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div = {
> +       .data = &(struct clk_regmap_div_data){
> +               .offset = HHI_VID_CLK_DIV,
> +               .shift = 0,
> +               .width = 8,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_div",
> +               .ops = &clk_regmap_divider_ops,
> +               .parent_names = (const char *[]){ "vclk_input" },
> +               .num_parents = 1,
> +               .flags = CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div = {
> +       .data = &(struct clk_regmap_div_data){
> +               .offset = HHI_VIID_CLK_DIV,
> +               .shift = 0,
> +               .width = 8,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_div",
> +               .ops = &clk_regmap_divider_ops,
> +               .parent_names = (const char *[]){ "vclk2_input" },
> +               .num_parents = 1,
> +               .flags = CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 19,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk_div" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2 = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 19,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2_div" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div1 = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 0,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_div1",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div2_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 1,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_div2_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div4_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 2,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_div4_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div6_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 3,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_div6_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk_div12_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL,
> +               .bit_idx = 4,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk_div12_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div1 = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 0,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_div1",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div2_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 1,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_div2_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div4_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 2,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_div4_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div6_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 3,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_div6_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_vclk2_div12_en = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VIID_CLK_CNTL,
> +               .bit_idx = 4,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "vclk2_div12_en",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "vclk2" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk_div2 = {
> +       .mult = 1,
> +       .div = 2,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_div2",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk_div2_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk_div4 = {
> +       .mult = 1,
> +       .div = 4,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_div4",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk_div4_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk_div6 = {
> +       .mult = 1,
> +       .div = 6,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_div6",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk_div6_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk_div12 = {
> +       .mult = 1,
> +       .div = 12,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk_div12",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk_div12_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk2_div2 = {
> +       .mult = 1,
> +       .div = 2,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_div2",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk2_div2_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk2_div4 = {
> +       .mult = 1,
> +       .div = 4,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_div4",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk2_div4_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk2_div6 = {
> +       .mult = 1,
> +       .div = 6,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_div6",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk2_div6_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static struct clk_fixed_factor gxbb_vclk2_div12 = {
> +       .mult = 1,
> +       .div = 12,
> +       .hw.init = &(struct clk_init_data){
> +               .name = "vclk2_div12",
> +               .ops = &clk_fixed_factor_ops,
> +               .parent_names = (const char *[]){ "vclk2_div12_en" },
> +               .num_parents = 1,
> +       },
> +};
> +
> +static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
> +const char *gxbb_cts_parent_names[] = {
> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
> +       "vclk2_div6", "vclk2_div12"
> +};
> +
> +static struct clk_regmap gxbb_cts_enci_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VID_CLK_DIV,
> +               .mask = 0xf,
> +               .shift = 28,
> +               .table = mux_table_cts_sel,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "cts_enci_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               .parent_names = gxbb_cts_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_cts_encp_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VID_CLK_DIV,
> +               .mask = 0xf,
> +               .shift = 20,
> +               .table = mux_table_cts_sel,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "cts_encp_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               .parent_names = gxbb_cts_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_cts_vdac_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_VIID_CLK_DIV,
> +               .mask = 0xf,
> +               .shift = 28,
> +               .table = mux_table_cts_sel,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "cts_vdac_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               .parent_names = gxbb_cts_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +/* TOFIX: add support for cts_tcon */
> +static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
> +const char *gxbb_cts_hdmi_tx_parent_names[] = {
> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
> +       "vclk2_div6", "vclk2_div12"
> +};
> +
> +static struct clk_regmap gxbb_hdmi_tx_sel = {
> +       .data = &(struct clk_regmap_mux_data){
> +               .offset = HHI_HDMI_CLK_CNTL,
> +               .mask = 0xf,
> +               .shift = 16,
> +               .table = mux_table_hdmi_tx_sel,
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "hdmi_tx_sel",
> +               .ops = &clk_regmap_mux_ops,
> +               /*
> +                * bits 31:28 selects from 12 possible parents:
> +                * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12
> +                * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12,
> +                * cts_tcon
> +                */
> +               .parent_names = gxbb_cts_hdmi_tx_parent_names,
> +               .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names),
> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_cts_enci = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL2,
> +               .bit_idx = 0,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "cts_enci",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "cts_enci_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_cts_encp = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL2,
> +               .bit_idx = 2,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "cts_encp",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "cts_encp_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_cts_vdac = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL2,
> +               .bit_idx = 4,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "cts_vdac",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "cts_vdac_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
> +static struct clk_regmap gxbb_hdmi_tx = {
> +       .data = &(struct clk_regmap_gate_data){
> +               .offset = HHI_VID_CLK_CNTL2,
> +               .bit_idx = 5,
> +       },
> +       .hw.init = &(struct clk_init_data) {
> +               .name = "hdmi_tx",
> +               .ops = &clk_regmap_gate_ops,
> +               .parent_names = (const char *[]){ "hdmi_tx_sel" },
> +               .num_parents = 1,
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +       },
> +};
> +
>  /* VDEC clocks */
>
>  static const char * const gxbb_vdec_parent_names[] = {
> @@ -1919,6 +2483,43 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
>                 [CLKID_HDMI_PLL_OD2]        = &gxbb_hdmi_pll_od2.hw,
>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>                 [CLKID_GP0_PLL_DCO]         = &gxbb_gp0_pll_dco.hw,
> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>                 [NR_CLKS]                   = NULL,
>         },
>         .num = NR_CLKS,
> @@ -2090,6 +2691,43 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
>                 [CLKID_HDMI_PLL_OD2]        = &gxl_hdmi_pll_od2.hw,
>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>                 [CLKID_GP0_PLL_DCO]         = &gxl_gp0_pll_dco.hw,
> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>                 [NR_CLKS]                   = NULL,
>         },
>         .num = NR_CLKS,
> @@ -2265,6 +2903,35 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
>         &gxbb_hdmi_pll_dco,
>         &gxbb_sys_pll_dco,
>         &gxbb_gp0_pll,
> +       &gxbb_vid_pll,
> +       &gxbb_vid_pll_sel,
> +       &gxbb_vid_pll_div,
> +       &gxbb_vclk,
> +       &gxbb_vclk_sel,
> +       &gxbb_vclk_div,
> +       &gxbb_vclk_input,
> +       &gxbb_vclk_div1,
> +       &gxbb_vclk_div2_en,
> +       &gxbb_vclk_div4_en,
> +       &gxbb_vclk_div6_en,
> +       &gxbb_vclk_div12_en,
> +       &gxbb_vclk2,
> +       &gxbb_vclk2_sel,
> +       &gxbb_vclk2_div,
> +       &gxbb_vclk2_input,
> +       &gxbb_vclk2_div1,
> +       &gxbb_vclk2_div2_en,
> +       &gxbb_vclk2_div4_en,
> +       &gxbb_vclk2_div6_en,
> +       &gxbb_vclk2_div12_en,
> +       &gxbb_cts_enci,
> +       &gxbb_cts_enci_sel,
> +       &gxbb_cts_encp,
> +       &gxbb_cts_encp_sel,
> +       &gxbb_cts_vdac,
> +       &gxbb_cts_vdac_sel,
> +       &gxbb_hdmi_tx,
> +       &gxbb_hdmi_tx_sel,
>  };
>
>  struct clkc_data {
> diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
> index 72bc077..171b7d8 100644
> --- a/drivers/clk/meson/gxbb.h
> +++ b/drivers/clk/meson/gxbb.h
> @@ -165,8 +165,28 @@
>  #define CLKID_HDMI_PLL_OD2       163
>  #define CLKID_SYS_PLL_DCO        164
>  #define CLKID_GP0_PLL_DCO        165
> -
> -#define NR_CLKS                          166
> +#define CLKID_VID_PLL_SEL        167
> +#define CLKID_VID_PLL_DIV        168
> +#define CLKID_VCLK_SEL           169
> +#define CLKID_VCLK2_SEL                  170
> +#define CLKID_VCLK_INPUT         171
> +#define CLKID_VCLK2_INPUT        172
> +#define CLKID_VCLK_DIV           173
> +#define CLKID_VCLK2_DIV                  174
> +#define CLKID_VCLK_DIV2_EN       177
> +#define CLKID_VCLK_DIV4_EN       178
> +#define CLKID_VCLK_DIV6_EN       179
> +#define CLKID_VCLK_DIV12_EN      180
> +#define CLKID_VCLK2_DIV2_EN      181
> +#define CLKID_VCLK2_DIV4_EN      182
> +#define CLKID_VCLK2_DIV6_EN      183
> +#define CLKID_VCLK2_DIV12_EN     184
> +#define CLKID_CTS_ENCI_SEL       195
> +#define CLKID_CTS_ENCP_SEL       196
> +#define CLKID_CTS_VDAC_SEL       197
> +#define CLKID_HDMI_TX_SEL        198
> +
> +#define NR_CLKS                          203
>
>  /* include the CLKIDs that have been made part of the DT binding */
>  #include <dt-bindings/clock/gxbb-clkc.h>
> diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
> index 3979d48..9f7b99e 100644
> --- a/include/dt-bindings/clock/gxbb-clkc.h
> +++ b/include/dt-bindings/clock/gxbb-clkc.h
shouldn't this go into a separate patch?

> @@ -128,5 +128,22 @@
>  #define CLKID_VDEC_1           153
>  #define CLKID_VDEC_HEVC                156
>  #define CLKID_GEN_CLK          159
> +#define CLKID_VID_PLL          166
> +#define CLKID_VCLK             175
> +#define CLKID_VCLK2            176
> +#define CLKID_VCLK_DIV1                185
> +#define CLKID_VCLK_DIV2                186
> +#define CLKID_VCLK_DIV4                187
> +#define CLKID_VCLK_DIV6                188
> +#define CLKID_VCLK_DIV12       189
> +#define CLKID_VCLK2_DIV1       190
> +#define CLKID_VCLK2_DIV2       191
> +#define CLKID_VCLK2_DIV4       192
> +#define CLKID_VCLK2_DIV6       193
> +#define CLKID_VCLK2_DIV12      194
at first I was confused why you need to export all the dividers,
instead of simply calling clk_set_rate with "parent_rate (taken vom
VCLK or VCLK2) divided by N"
then I noticed that the four muxes below can use VCLK *or* VCLK2
dividers as input (as far as I remember this is different on Meson8b:
there the muxes below take either the VCLK dividers or the VCLK2
dividers as input, but not both)

> +#define CLKID_CTS_ENCI         199
> +#define CLKID_CTS_ENCP         200
> +#define CLKID_CTS_VDAC         201
> +#define CLKID_HDMI_TX          202
is my assumption correct that you need to choose a specific input
clock (VCLK or VCLK2) for a specific use-case (ENCI, ENCP, VDAC,
HDMI_TX)?
let's say HDMI uses VLKC2 as input (I'm not sure if it really does):
could you skip the VCLK_DIV_* parents in the HDMI_TX clock definition
- or does the selection of a specific parent clock (VCLK or VCLK2)
depend on the output rate?


Regards
Martin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] clk: meson: Add vid_pll divider driver
  2018-07-20  9:39 ` [PATCH 1/2] clk: meson: Add vid_pll divider driver Neil Armstrong
@ 2018-07-20 19:17   ` Martin Blumenstingl
  2018-07-24 11:56     ` Neil Armstrong
  0 siblings, 1 reply; 8+ messages in thread
From: Martin Blumenstingl @ 2018-07-20 19:17 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: jbrunet, linux-amlogic, linux-kernel, linux-clk, linux-arm-kernel

Hi Neil,

On Fri, Jul 20, 2018 at 11:40 AM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Add support the VID_PLL fully programmable divider used right after the
> HDMI PLL clock source. It is used to achieve complex fractional division
> with a programmble bitfield.
I assume you have no other information that the S912 datasheet, pages
64 and 77 which describe the HHI_VID_PLL_CLK_DIV register?

more comments inline

> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>
> ---
>  drivers/clk/meson/Makefile      |  2 +-
>  drivers/clk/meson/clkc.h        |  6 +++
>  drivers/clk/meson/vid-pll-div.c | 90 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 97 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/clk/meson/vid-pll-div.c
>
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 72ec8c4..0234767 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -2,7 +2,7 @@
>  # Makefile for Meson specific clk
>  #
>
> -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
> +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
>  obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
> index 6b96d55..9166605 100644
> --- a/drivers/clk/meson/clkc.h
> +++ b/drivers/clk/meson/clkc.h
> @@ -90,6 +90,11 @@ struct meson_clk_phase_data {
>  int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
>  unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
>
> +struct meson_vid_pll_div_data {
> +       struct parm val;
> +       struct parm sel;
> +};
> +
>  #define MESON_GATE(_name, _reg, _bit)                                  \
>  struct clk_regmap _name = {                                            \
>         .data = &(struct clk_regmap_gate_data){                         \
> @@ -112,5 +117,6 @@ extern const struct clk_ops meson_clk_cpu_ops;
>  extern const struct clk_ops meson_clk_mpll_ro_ops;
>  extern const struct clk_ops meson_clk_mpll_ops;
>  extern const struct clk_ops meson_clk_phase_ops;
> +extern const struct clk_ops meson_vid_pll_div_ro_ops;
>
>  #endif /* __CLKC_H */
> diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
> new file mode 100644
> index 0000000..5f267be
> --- /dev/null
> +++ b/drivers/clk/meson/vid-pll-div.c
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Neil Armstrong <narmstrong@baylibre.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include "clkc.h"
> +
> +static inline struct meson_vid_pll_div_data *
> +meson_vid_pll_div_data(struct clk_regmap *clk)
> +{
> +       return (struct meson_vid_pll_div_data *)clk->data;
> +}
> +
> +/*
> + * This vid_pll divided is a fully programmable fractionnal divider to
> + * achieve complex video clock rates.
> + *
> + * Here are provided the commonly used fraction values provided by Amlogic.
> + */
> +
> +struct vid_pll_div {
> +       unsigned int shift_val;
> +       unsigned int shift_sel;
> +       unsigned int frac_top;
maybe call it divider?

> +       unsigned int frac_bot;
maybe call it multiplier?

> +};
> +
> +#define VID_PLL_DIV(_val, _sel, _ft, _fb)                              \
> +       {                                                               \
> +               .shift_val = (_val),                                    \
> +               .shift_sel = (_sel),                                    \
> +               .frac_top = (_ft),                                      \
> +               .frac_bot = (_fb),                                      \
> +       }
> +
> +static const struct vid_pll_div vid_pll_div_table[] = {
> +       VID_PLL_DIV(0x0aaa, 0, 2, 1),   /* 2/1  => /2 */
> +       VID_PLL_DIV(0x5294, 2, 5, 2),   /* 5/2  => /2.5 */
> +       VID_PLL_DIV(0x0db6, 0, 3, 1),   /* 3/1  => /3 */
> +       VID_PLL_DIV(0x36cc, 1, 7, 2),   /* 7/2  => /3.5 */
> +       VID_PLL_DIV(0x6666, 2, 15, 4),  /* 15/4 => /3.75 */
> +       VID_PLL_DIV(0x0ccc, 4, 4, 1),   /* 4/1  => /4 */
is the shift_sel (second parameter) correct here? the public S912
datasheet, page 77 states that CLK_SEL is only 2 bit wide (and "4"
exceeds that)

> +       VID_PLL_DIV(0x739c, 2, 5, 1),   /* 5/1  => /5 */
> +       VID_PLL_DIV(0x0e38, 0, 6, 1),   /* 6/1  => /6 */
> +       VID_PLL_DIV(0x0000, 3, 25, 4),  /* 25/4 => /6.25 */
> +       VID_PLL_DIV(0x3c78, 1, 7, 1),   /* 7/1  => /7 */
> +       VID_PLL_DIV(0x78f0, 2, 15, 2),  /* 15/2 => /7.5 */
> +       VID_PLL_DIV(0x0fc0, 0, 12, 1),  /* 12/1 => /12 */
> +       VID_PLL_DIV(0x3f80, 1, 14, 1),  /* 14/1 => /14 */
> +       VID_PLL_DIV(0x7f80, 2, 15, 1),  /* 15/1 => /15 */
> +};
> +
> +#define to_meson_vid_pll_div(_hw) container_of(_hw, struct meson_vid_pll_div, hw)
> +
> +const struct vid_pll_div *_get_table_val(unsigned int shift_val,
> +                                        unsigned int shift_sel)
> +{
> +       int i;
> +
> +       for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
> +               if (vid_pll_div_table[i].shift_val == shift_val &&
> +                   vid_pll_div_table[i].shift_sel == shift_sel)
> +                       return &vid_pll_div_table[i];
> +       }
> +
> +       return NULL;
> +}
> +
> +static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
> +                                                  unsigned long parent_rate)
> +{
> +       struct clk_regmap *clk = to_clk_regmap(hw);
> +       struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
> +       const struct vid_pll_div *div;
> +
> +       div = _get_table_val(meson_parm_read(clk->map, &pll_div->val),
> +                            meson_parm_read(clk->map, &pll_div->sel));
> +       if (!div || !div->frac_top) {
> +               pr_info("%s: Invalid config value for vid_pll_div\n", __func__);
> +               return parent_rate;
> +       }
> +
> +       return DIV_ROUND_UP_ULL(parent_rate * div->frac_bot, div->frac_top);
with the rename above this would read:
return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);


Regards
Martin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] clk: meson: Add vid_pll divider driver
  2018-07-20 19:17   ` Martin Blumenstingl
@ 2018-07-24 11:56     ` Neil Armstrong
  0 siblings, 0 replies; 8+ messages in thread
From: Neil Armstrong @ 2018-07-24 11:56 UTC (permalink / raw)
  To: Martin Blumenstingl
  Cc: jbrunet, linux-amlogic, linux-kernel, linux-clk, linux-arm-kernel

On 20/07/2018 21:17, Martin Blumenstingl wrote:
> Hi Neil,
> 
> On Fri, Jul 20, 2018 at 11:40 AM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Add support the VID_PLL fully programmable divider used right after the
>> HDMI PLL clock source. It is used to achieve complex fractional division
>> with a programmble bitfield.
> I assume you have no other information that the S912 datasheet, pages
> 64 and 77 which describe the HHI_VID_PLL_CLK_DIV register?

Exact

> 
> more comments inline
> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>
>> ---
>>  drivers/clk/meson/Makefile      |  2 +-
>>  drivers/clk/meson/clkc.h        |  6 +++
>>  drivers/clk/meson/vid-pll-div.c | 90 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 97 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/clk/meson/vid-pll-div.c
>>
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 72ec8c4..0234767 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -2,7 +2,7 @@
>>  # Makefile for Meson specific clk
>>  #
>>
>> -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
>> +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
>>  obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
>>  obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
>>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
>> index 6b96d55..9166605 100644
>> --- a/drivers/clk/meson/clkc.h
>> +++ b/drivers/clk/meson/clkc.h
>> @@ -90,6 +90,11 @@ struct meson_clk_phase_data {
>>  int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
>>  unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
>>
>> +struct meson_vid_pll_div_data {
>> +       struct parm val;
>> +       struct parm sel;
>> +};
>> +
>>  #define MESON_GATE(_name, _reg, _bit)                                  \
>>  struct clk_regmap _name = {                                            \
>>         .data = &(struct clk_regmap_gate_data){                         \
>> @@ -112,5 +117,6 @@ extern const struct clk_ops meson_clk_cpu_ops;
>>  extern const struct clk_ops meson_clk_mpll_ro_ops;
>>  extern const struct clk_ops meson_clk_mpll_ops;
>>  extern const struct clk_ops meson_clk_phase_ops;
>> +extern const struct clk_ops meson_vid_pll_div_ro_ops;
>>
>>  #endif /* __CLKC_H */
>> diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
>> new file mode 100644
>> index 0000000..5f267be
>> --- /dev/null
>> +++ b/drivers/clk/meson/vid-pll-div.c
>> @@ -0,0 +1,90 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2018 BayLibre, SAS.
>> + * Author: Neil Armstrong <narmstrong@baylibre.com>
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include "clkc.h"
>> +
>> +static inline struct meson_vid_pll_div_data *
>> +meson_vid_pll_div_data(struct clk_regmap *clk)
>> +{
>> +       return (struct meson_vid_pll_div_data *)clk->data;
>> +}
>> +
>> +/*
>> + * This vid_pll divided is a fully programmable fractionnal divider to
>> + * achieve complex video clock rates.
>> + *
>> + * Here are provided the commonly used fraction values provided by Amlogic.
>> + */
>> +
>> +struct vid_pll_div {
>> +       unsigned int shift_val;
>> +       unsigned int shift_sel;
>> +       unsigned int frac_top;
> maybe call it divider?

Yep, seems simpler !

> 
>> +       unsigned int frac_bot;
> maybe call it multiplier?

Thanks, I was in my code and forgot it was simpler...

> 
>> +};
>> +
>> +#define VID_PLL_DIV(_val, _sel, _ft, _fb)                              \
>> +       {                                                               \
>> +               .shift_val = (_val),                                    \
>> +               .shift_sel = (_sel),                                    \
>> +               .frac_top = (_ft),                                      \
>> +               .frac_bot = (_fb),                                      \
>> +       }
>> +
>> +static const struct vid_pll_div vid_pll_div_table[] = {
>> +       VID_PLL_DIV(0x0aaa, 0, 2, 1),   /* 2/1  => /2 */
>> +       VID_PLL_DIV(0x5294, 2, 5, 2),   /* 5/2  => /2.5 */
>> +       VID_PLL_DIV(0x0db6, 0, 3, 1),   /* 3/1  => /3 */
>> +       VID_PLL_DIV(0x36cc, 1, 7, 2),   /* 7/2  => /3.5 */
>> +       VID_PLL_DIV(0x6666, 2, 15, 4),  /* 15/4 => /3.75 */
>> +       VID_PLL_DIV(0x0ccc, 4, 4, 1),   /* 4/1  => /4 */
> is the shift_sel (second parameter) correct here? the public S912
> datasheet, page 77 states that CLK_SEL is only 2 bit wide (and "4"
> exceeds that)

It's a typo, it should be 0. Thanks.

> 
>> +       VID_PLL_DIV(0x739c, 2, 5, 1),   /* 5/1  => /5 */
>> +       VID_PLL_DIV(0x0e38, 0, 6, 1),   /* 6/1  => /6 */
>> +       VID_PLL_DIV(0x0000, 3, 25, 4),  /* 25/4 => /6.25 */
>> +       VID_PLL_DIV(0x3c78, 1, 7, 1),   /* 7/1  => /7 */
>> +       VID_PLL_DIV(0x78f0, 2, 15, 2),  /* 15/2 => /7.5 */
>> +       VID_PLL_DIV(0x0fc0, 0, 12, 1),  /* 12/1 => /12 */
>> +       VID_PLL_DIV(0x3f80, 1, 14, 1),  /* 14/1 => /14 */
>> +       VID_PLL_DIV(0x7f80, 2, 15, 1),  /* 15/1 => /15 */
>> +};
>> +
>> +#define to_meson_vid_pll_div(_hw) container_of(_hw, struct meson_vid_pll_div, hw)
>> +
>> +const struct vid_pll_div *_get_table_val(unsigned int shift_val,
>> +                                        unsigned int shift_sel)
>> +{
>> +       int i;
>> +
>> +       for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
>> +               if (vid_pll_div_table[i].shift_val == shift_val &&
>> +                   vid_pll_div_table[i].shift_sel == shift_sel)
>> +                       return &vid_pll_div_table[i];
>> +       }
>> +
>> +       return NULL;
>> +}
>> +
>> +static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
>> +                                                  unsigned long parent_rate)
>> +{
>> +       struct clk_regmap *clk = to_clk_regmap(hw);
>> +       struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
>> +       const struct vid_pll_div *div;
>> +
>> +       div = _get_table_val(meson_parm_read(clk->map, &pll_div->val),
>> +                            meson_parm_read(clk->map, &pll_div->sel));
>> +       if (!div || !div->frac_top) {
>> +               pr_info("%s: Invalid config value for vid_pll_div\n", __func__);
>> +               return parent_rate;
>> +       }
>> +
>> +       return DIV_ROUND_UP_ULL(parent_rate * div->frac_bot, div->frac_top);
> with the rename above this would read:
> return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);

Yep, this looks much better !

> 
> 
> Regards
> Martin
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] clk: meson-gxbb: Add video clocks
  2018-07-20 19:00   ` Martin Blumenstingl
@ 2018-07-24 12:04     ` Neil Armstrong
  2018-07-24 12:07       ` Neil Armstrong
  0 siblings, 1 reply; 8+ messages in thread
From: Neil Armstrong @ 2018-07-24 12:04 UTC (permalink / raw)
  To: Martin Blumenstingl
  Cc: jbrunet, linux-amlogic, linux-kernel, linux-clk, linux-arm-kernel

On 20/07/2018 21:00, Martin Blumenstingl wrote:
> Hi Neil,
> 
> On Fri, Jul 20, 2018 at 11:40 AM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Add the clocks entries used in the video clock path, the clock path
>> is doubled to permit having different synchronized clocks for different
>> parts of the video pipeline.
> maybe you can add the comment about CLK_GET_RATE_NOCACHE here as well

Yes

> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/clk/meson/gxbb.c              | 667 ++++++++++++++++++++++++++++++++++
>>  drivers/clk/meson/gxbb.h              |  24 +-
>>  include/dt-bindings/clock/gxbb-clkc.h |  17 +
>>  3 files changed, 706 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
>> index f79ea33..5fabedf 100644
>> --- a/drivers/clk/meson/gxbb.c
>> +++ b/drivers/clk/meson/gxbb.c
>> @@ -1508,6 +1508,570 @@ static struct clk_regmap gxbb_vapb = {
>>         },
>>  };
>>
>> +/* Video Clocks */
>> +
>> +static struct clk_regmap gxbb_vid_pll_div = {
>> +       .data = &(struct meson_vid_pll_div_data){
>> +               .val = {
>> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
>> +                       .shift   = 0,
>> +                       .width   = 15,
>> +               },
>> +               .sel = {
>> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
>> +                       .shift   = 16,
>> +                       .width   = 2,
>> +               },
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vid_pll_div",
>> +               .ops = &meson_vid_pll_div_ro_ops,
>> +               .parent_names = (const char *[]){ "hdmi_pll" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static u32 mux_table_vid_pll[] = { 0, 1 };
> you can drop this mux table

Yep

> 
>> +const char *gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" };
>> +
>> +static struct clk_regmap gxbb_vid_pll_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VID_PLL_CLK_DIV,
>> +               .mask = 0x1,
>> +               .shift = 18,
>> +               .table = mux_table_vid_pll,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vid_pll_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               /*
>> +                * bit 18 selects from 2 possible parents:
>> +                * vid_pll_div or hdmi_pll
>> +                */
>> +               .parent_names = gxbb_vid_pll_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vid_pll = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_PLL_CLK_DIV,
>> +               .bit_idx = 19,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vid_pll",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vid_pll_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static u32 mux_table_vclk[] = { 0, 1, 2, 3, 4, 5, 6 };
> you can drop this mux table

Yep

> 
>> +const char *gxbb_vclk_parent_names[] = {
>> +       "vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll",
>> +       "fclk_div7", "mpll1",
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .mask = 0x7,
>> +               .shift = 16,
>> +               .table = mux_table_vclk,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               /*
>> +                * bits 16:18 selects from 8 possible parents:
>> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
>> +                * vid_pll, fclk_div7, mp1
>> +                */
>> +               .parent_names = gxbb_vclk_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .mask = 0x7,
>> +               .shift = 16,
>> +               .table = mux_table_vclk,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               /*
>> +                * bits 16:18 selects from 8 possible parents:
>> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
>> +                * vid_pll, fclk_div7, mp1
>> +                */
>> +               .parent_names = gxbb_vclk_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_input = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_DIV,
>> +               .bit_idx = 16,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_input",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_input = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_DIV,
>> +               .bit_idx = 16,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_input",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div = {
>> +       .data = &(struct clk_regmap_div_data){
>> +               .offset = HHI_VID_CLK_DIV,
>> +               .shift = 0,
>> +               .width = 8,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_div",
>> +               .ops = &clk_regmap_divider_ops,
>> +               .parent_names = (const char *[]){ "vclk_input" },
>> +               .num_parents = 1,
>> +               .flags = CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div = {
>> +       .data = &(struct clk_regmap_div_data){
>> +               .offset = HHI_VIID_CLK_DIV,
>> +               .shift = 0,
>> +               .width = 8,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_div",
>> +               .ops = &clk_regmap_divider_ops,
>> +               .parent_names = (const char *[]){ "vclk2_input" },
>> +               .num_parents = 1,
>> +               .flags = CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 19,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk_div" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2 = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 19,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2_div" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div1 = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 0,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_div1",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div2_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 1,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_div2_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div4_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 2,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_div4_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div6_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 3,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_div6_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk_div12_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL,
>> +               .bit_idx = 4,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk_div12_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div1 = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 0,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_div1",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div2_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 1,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_div2_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div4_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 2,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_div4_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div6_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 3,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_div6_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_vclk2_div12_en = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VIID_CLK_CNTL,
>> +               .bit_idx = 4,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "vclk2_div12_en",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "vclk2" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk_div2 = {
>> +       .mult = 1,
>> +       .div = 2,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_div2",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk_div2_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk_div4 = {
>> +       .mult = 1,
>> +       .div = 4,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_div4",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk_div4_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk_div6 = {
>> +       .mult = 1,
>> +       .div = 6,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_div6",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk_div6_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk_div12 = {
>> +       .mult = 1,
>> +       .div = 12,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk_div12",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk_div12_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk2_div2 = {
>> +       .mult = 1,
>> +       .div = 2,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_div2",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk2_div2_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk2_div4 = {
>> +       .mult = 1,
>> +       .div = 4,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_div4",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk2_div4_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk2_div6 = {
>> +       .mult = 1,
>> +       .div = 6,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_div6",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk2_div6_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static struct clk_fixed_factor gxbb_vclk2_div12 = {
>> +       .mult = 1,
>> +       .div = 12,
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "vclk2_div12",
>> +               .ops = &clk_fixed_factor_ops,
>> +               .parent_names = (const char *[]){ "vclk2_div12_en" },
>> +               .num_parents = 1,
>> +       },
>> +};
>> +
>> +static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
>> +const char *gxbb_cts_parent_names[] = {
>> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
>> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
>> +       "vclk2_div6", "vclk2_div12"
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_enci_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VID_CLK_DIV,
>> +               .mask = 0xf,
>> +               .shift = 28,
>> +               .table = mux_table_cts_sel,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "cts_enci_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               .parent_names = gxbb_cts_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_encp_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VID_CLK_DIV,
>> +               .mask = 0xf,
>> +               .shift = 20,
>> +               .table = mux_table_cts_sel,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "cts_encp_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               .parent_names = gxbb_cts_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_vdac_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_VIID_CLK_DIV,
>> +               .mask = 0xf,
>> +               .shift = 28,
>> +               .table = mux_table_cts_sel,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "cts_vdac_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               .parent_names = gxbb_cts_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +/* TOFIX: add support for cts_tcon */
>> +static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
>> +const char *gxbb_cts_hdmi_tx_parent_names[] = {
>> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
>> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
>> +       "vclk2_div6", "vclk2_div12"
>> +};
>> +
>> +static struct clk_regmap gxbb_hdmi_tx_sel = {
>> +       .data = &(struct clk_regmap_mux_data){
>> +               .offset = HHI_HDMI_CLK_CNTL,
>> +               .mask = 0xf,
>> +               .shift = 16,
>> +               .table = mux_table_hdmi_tx_sel,
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "hdmi_tx_sel",
>> +               .ops = &clk_regmap_mux_ops,
>> +               /*
>> +                * bits 31:28 selects from 12 possible parents:
>> +                * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12
>> +                * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12,
>> +                * cts_tcon
>> +                */
>> +               .parent_names = gxbb_cts_hdmi_tx_parent_names,
>> +               .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names),
>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_enci = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL2,
>> +               .bit_idx = 0,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "cts_enci",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "cts_enci_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_encp = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL2,
>> +               .bit_idx = 2,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "cts_encp",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "cts_encp_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_cts_vdac = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL2,
>> +               .bit_idx = 4,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "cts_vdac",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "cts_vdac_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>> +static struct clk_regmap gxbb_hdmi_tx = {
>> +       .data = &(struct clk_regmap_gate_data){
>> +               .offset = HHI_VID_CLK_CNTL2,
>> +               .bit_idx = 5,
>> +       },
>> +       .hw.init = &(struct clk_init_data) {
>> +               .name = "hdmi_tx",
>> +               .ops = &clk_regmap_gate_ops,
>> +               .parent_names = (const char *[]){ "hdmi_tx_sel" },
>> +               .num_parents = 1,
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +       },
>> +};
>> +
>>  /* VDEC clocks */
>>
>>  static const char * const gxbb_vdec_parent_names[] = {
>> @@ -1919,6 +2483,43 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
>>                 [CLKID_HDMI_PLL_OD2]        = &gxbb_hdmi_pll_od2.hw,
>>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>>                 [CLKID_GP0_PLL_DCO]         = &gxbb_gp0_pll_dco.hw,
>> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
>> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
>> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
>> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
>> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
>> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
>> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
>> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
>> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
>> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
>> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
>> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
>> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
>> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
>> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
>> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
>> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
>> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
>> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
>> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
>> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
>> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
>> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
>> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
>> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
>> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
>> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
>> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
>> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
>> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
>> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
>> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
>> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
>> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
>> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
>> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
>> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>>                 [NR_CLKS]                   = NULL,
>>         },
>>         .num = NR_CLKS,
>> @@ -2090,6 +2691,43 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
>>                 [CLKID_HDMI_PLL_OD2]        = &gxl_hdmi_pll_od2.hw,
>>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>>                 [CLKID_GP0_PLL_DCO]         = &gxl_gp0_pll_dco.hw,
>> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
>> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
>> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
>> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
>> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
>> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
>> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
>> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
>> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
>> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
>> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
>> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
>> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
>> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
>> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
>> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
>> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
>> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
>> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
>> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
>> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
>> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
>> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
>> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
>> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
>> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
>> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
>> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
>> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
>> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
>> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
>> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
>> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
>> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
>> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
>> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
>> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>>                 [NR_CLKS]                   = NULL,
>>         },
>>         .num = NR_CLKS,
>> @@ -2265,6 +2903,35 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
>>         &gxbb_hdmi_pll_dco,
>>         &gxbb_sys_pll_dco,
>>         &gxbb_gp0_pll,
>> +       &gxbb_vid_pll,
>> +       &gxbb_vid_pll_sel,
>> +       &gxbb_vid_pll_div,
>> +       &gxbb_vclk,
>> +       &gxbb_vclk_sel,
>> +       &gxbb_vclk_div,
>> +       &gxbb_vclk_input,
>> +       &gxbb_vclk_div1,
>> +       &gxbb_vclk_div2_en,
>> +       &gxbb_vclk_div4_en,
>> +       &gxbb_vclk_div6_en,
>> +       &gxbb_vclk_div12_en,
>> +       &gxbb_vclk2,
>> +       &gxbb_vclk2_sel,
>> +       &gxbb_vclk2_div,
>> +       &gxbb_vclk2_input,
>> +       &gxbb_vclk2_div1,
>> +       &gxbb_vclk2_div2_en,
>> +       &gxbb_vclk2_div4_en,
>> +       &gxbb_vclk2_div6_en,
>> +       &gxbb_vclk2_div12_en,
>> +       &gxbb_cts_enci,
>> +       &gxbb_cts_enci_sel,
>> +       &gxbb_cts_encp,
>> +       &gxbb_cts_encp_sel,
>> +       &gxbb_cts_vdac,
>> +       &gxbb_cts_vdac_sel,
>> +       &gxbb_hdmi_tx,
>> +       &gxbb_hdmi_tx_sel,
>>  };
>>
>>  struct clkc_data {
>> diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
>> index 72bc077..171b7d8 100644
>> --- a/drivers/clk/meson/gxbb.h
>> +++ b/drivers/clk/meson/gxbb.h
>> @@ -165,8 +165,28 @@
>>  #define CLKID_HDMI_PLL_OD2       163
>>  #define CLKID_SYS_PLL_DCO        164
>>  #define CLKID_GP0_PLL_DCO        165
>> -
>> -#define NR_CLKS                          166
>> +#define CLKID_VID_PLL_SEL        167
>> +#define CLKID_VID_PLL_DIV        168
>> +#define CLKID_VCLK_SEL           169
>> +#define CLKID_VCLK2_SEL                  170
>> +#define CLKID_VCLK_INPUT         171
>> +#define CLKID_VCLK2_INPUT        172
>> +#define CLKID_VCLK_DIV           173
>> +#define CLKID_VCLK2_DIV                  174
>> +#define CLKID_VCLK_DIV2_EN       177
>> +#define CLKID_VCLK_DIV4_EN       178
>> +#define CLKID_VCLK_DIV6_EN       179
>> +#define CLKID_VCLK_DIV12_EN      180
>> +#define CLKID_VCLK2_DIV2_EN      181
>> +#define CLKID_VCLK2_DIV4_EN      182
>> +#define CLKID_VCLK2_DIV6_EN      183
>> +#define CLKID_VCLK2_DIV12_EN     184
>> +#define CLKID_CTS_ENCI_SEL       195
>> +#define CLKID_CTS_ENCP_SEL       196
>> +#define CLKID_CTS_VDAC_SEL       197
>> +#define CLKID_HDMI_TX_SEL        198
>> +
>> +#define NR_CLKS                          203
>>
>>  /* include the CLKIDs that have been made part of the DT binding */
>>  #include <dt-bindings/clock/gxbb-clkc.h>
>> diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
>> index 3979d48..9f7b99e 100644
>> --- a/include/dt-bindings/clock/gxbb-clkc.h
>> +++ b/include/dt-bindings/clock/gxbb-clkc.h
> shouldn't this go into a separate patch?
> 
>> @@ -128,5 +128,22 @@
>>  #define CLKID_VDEC_1           153
>>  #define CLKID_VDEC_HEVC                156
>>  #define CLKID_GEN_CLK          159
>> +#define CLKID_VID_PLL          166
>> +#define CLKID_VCLK             175
>> +#define CLKID_VCLK2            176
>> +#define CLKID_VCLK_DIV1                185
>> +#define CLKID_VCLK_DIV2                186
>> +#define CLKID_VCLK_DIV4                187
>> +#define CLKID_VCLK_DIV6                188
>> +#define CLKID_VCLK_DIV12       189
>> +#define CLKID_VCLK2_DIV1       190
>> +#define CLKID_VCLK2_DIV2       191
>> +#define CLKID_VCLK2_DIV4       192
>> +#define CLKID_VCLK2_DIV6       193
>> +#define CLKID_VCLK2_DIV12      194
> at first I was confused why you need to export all the dividers,
> instead of simply calling clk_set_rate with "parent_rate (taken vom
> VCLK or VCLK2) divided by N"
> then I noticed that the four muxes below can use VCLK *or* VCLK2
> dividers as input (as far as I remember this is different on Meson8b:
> there the muxes below take either the VCLK dividers or the VCLK2
> dividers as input, but not both)

Ok, I need to be sure both hdmi and enci/encp takes clock from the
same vclk tree, and in some HDMI mode you need to have a x2 clock
to cts_enci/encp from the same 1x clock to cts_htmi.

So I will need to manually setup the parents to make sure CCF doesn't
make a random choice.

Then I'll be able to do a set_rate on vclk to setup the proper PLL rate.

> 
>> +#define CLKID_CTS_ENCI         199
>> +#define CLKID_CTS_ENCP         200
>> +#define CLKID_CTS_VDAC         201
>> +#define CLKID_HDMI_TX          202
> is my assumption correct that you need to choose a specific input
> clock (VCLK or VCLK2) for a specific use-case (ENCI, ENCP, VDAC,
> HDMI_TX)?
> let's say HDMI uses VLKC2 as input (I'm not sure if it really does):
> could you skip the VCLK_DIV_* parents in the HDMI_TX clock definition
> - or does the selection of a specific parent clock (VCLK or VCLK2)
> depend on the output rate?

HDMI takes vclk2 (why ? I'll keep this path since it's always used by the
vendor code), and CBVS takes vclk.
I suspect they tried to make is possible to have CVBS and HDMI output
work at the same time using the VPP2 instance. But no idea how it works.

As I sais before, you need to feed a x2 factor to hdmi and enci/encp for
some modes, and I can't let CCF decide since they must take the same
clock path (VCLK or VCLK2, not both).

> 
> 
> Regards
> Martin
> 

Neil

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] clk: meson-gxbb: Add video clocks
  2018-07-24 12:04     ` Neil Armstrong
@ 2018-07-24 12:07       ` Neil Armstrong
  0 siblings, 0 replies; 8+ messages in thread
From: Neil Armstrong @ 2018-07-24 12:07 UTC (permalink / raw)
  To: Martin Blumenstingl
  Cc: jbrunet, linux-amlogic, linux-kernel, linux-clk, linux-arm-kernel

On 24/07/2018 14:04, Neil Armstrong wrote:
> On 20/07/2018 21:00, Martin Blumenstingl wrote:
>> Hi Neil,
>>
>> On Fri, Jul 20, 2018 at 11:40 AM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>>
>>> Add the clocks entries used in the video clock path, the clock path
>>> is doubled to permit having different synchronized clocks for different
>>> parts of the video pipeline.
>> maybe you can add the comment about CLK_GET_RATE_NOCACHE here as well
> 
> Yes
> 
>>
>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>> ---
>>>  drivers/clk/meson/gxbb.c              | 667 ++++++++++++++++++++++++++++++++++
>>>  drivers/clk/meson/gxbb.h              |  24 +-
>>>  include/dt-bindings/clock/gxbb-clkc.h |  17 +
>>>  3 files changed, 706 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
>>> index f79ea33..5fabedf 100644
>>> --- a/drivers/clk/meson/gxbb.c
>>> +++ b/drivers/clk/meson/gxbb.c
>>> @@ -1508,6 +1508,570 @@ static struct clk_regmap gxbb_vapb = {
>>>         },
>>>  };
>>>
>>> +/* Video Clocks */
>>> +
>>> +static struct clk_regmap gxbb_vid_pll_div = {
>>> +       .data = &(struct meson_vid_pll_div_data){
>>> +               .val = {
>>> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
>>> +                       .shift   = 0,
>>> +                       .width   = 15,
>>> +               },
>>> +               .sel = {
>>> +                       .reg_off = HHI_VID_PLL_CLK_DIV,
>>> +                       .shift   = 16,
>>> +                       .width   = 2,
>>> +               },
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vid_pll_div",
>>> +               .ops = &meson_vid_pll_div_ro_ops,
>>> +               .parent_names = (const char *[]){ "hdmi_pll" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static u32 mux_table_vid_pll[] = { 0, 1 };
>> you can drop this mux table
> 
> Yep
> 
>>
>>> +const char *gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" };
>>> +
>>> +static struct clk_regmap gxbb_vid_pll_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VID_PLL_CLK_DIV,
>>> +               .mask = 0x1,
>>> +               .shift = 18,
>>> +               .table = mux_table_vid_pll,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vid_pll_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               /*
>>> +                * bit 18 selects from 2 possible parents:
>>> +                * vid_pll_div or hdmi_pll
>>> +                */
>>> +               .parent_names = gxbb_vid_pll_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vid_pll = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_PLL_CLK_DIV,
>>> +               .bit_idx = 19,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vid_pll",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vid_pll_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static u32 mux_table_vclk[] = { 0, 1, 2, 3, 4, 5, 6 };
>> you can drop this mux table
> 
> Yep
> 
>>
>>> +const char *gxbb_vclk_parent_names[] = {
>>> +       "vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll",
>>> +       "fclk_div7", "mpll1",
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .mask = 0x7,
>>> +               .shift = 16,
>>> +               .table = mux_table_vclk,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               /*
>>> +                * bits 16:18 selects from 8 possible parents:
>>> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
>>> +                * vid_pll, fclk_div7, mp1
>>> +                */
>>> +               .parent_names = gxbb_vclk_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .mask = 0x7,
>>> +               .shift = 16,
>>> +               .table = mux_table_vclk,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               /*
>>> +                * bits 16:18 selects from 8 possible parents:
>>> +                * vid_pll, fclk_div4, fclk_div3, fclk_div5,
>>> +                * vid_pll, fclk_div7, mp1
>>> +                */
>>> +               .parent_names = gxbb_vclk_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_input = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_DIV,
>>> +               .bit_idx = 16,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_input",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_input = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_DIV,
>>> +               .bit_idx = 16,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_input",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div = {
>>> +       .data = &(struct clk_regmap_div_data){
>>> +               .offset = HHI_VID_CLK_DIV,
>>> +               .shift = 0,
>>> +               .width = 8,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_div",
>>> +               .ops = &clk_regmap_divider_ops,
>>> +               .parent_names = (const char *[]){ "vclk_input" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div = {
>>> +       .data = &(struct clk_regmap_div_data){
>>> +               .offset = HHI_VIID_CLK_DIV,
>>> +               .shift = 0,
>>> +               .width = 8,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_div",
>>> +               .ops = &clk_regmap_divider_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_input" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 19,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk_div" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2 = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 19,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_div" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div1 = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 0,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_div1",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div2_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 1,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_div2_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div4_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 2,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_div4_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div6_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 3,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_div6_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk_div12_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL,
>>> +               .bit_idx = 4,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk_div12_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div1 = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 0,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_div1",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div2_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 1,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_div2_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div4_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 2,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_div4_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div6_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 3,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_div6_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_vclk2_div12_en = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VIID_CLK_CNTL,
>>> +               .bit_idx = 4,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "vclk2_div12_en",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "vclk2" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk_div2 = {
>>> +       .mult = 1,
>>> +       .div = 2,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_div2",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk_div2_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk_div4 = {
>>> +       .mult = 1,
>>> +       .div = 4,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_div4",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk_div4_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk_div6 = {
>>> +       .mult = 1,
>>> +       .div = 6,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_div6",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk_div6_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk_div12 = {
>>> +       .mult = 1,
>>> +       .div = 12,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk_div12",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk_div12_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk2_div2 = {
>>> +       .mult = 1,
>>> +       .div = 2,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_div2",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_div2_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk2_div4 = {
>>> +       .mult = 1,
>>> +       .div = 4,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_div4",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_div4_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk2_div6 = {
>>> +       .mult = 1,
>>> +       .div = 6,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_div6",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_div6_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_fixed_factor gxbb_vclk2_div12 = {
>>> +       .mult = 1,
>>> +       .div = 12,
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "vclk2_div12",
>>> +               .ops = &clk_fixed_factor_ops,
>>> +               .parent_names = (const char *[]){ "vclk2_div12_en" },
>>> +               .num_parents = 1,
>>> +       },
>>> +};
>>> +
>>> +static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
>>> +const char *gxbb_cts_parent_names[] = {
>>> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
>>> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
>>> +       "vclk2_div6", "vclk2_div12"
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_enci_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VID_CLK_DIV,
>>> +               .mask = 0xf,
>>> +               .shift = 28,
>>> +               .table = mux_table_cts_sel,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "cts_enci_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               .parent_names = gxbb_cts_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_encp_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VID_CLK_DIV,
>>> +               .mask = 0xf,
>>> +               .shift = 20,
>>> +               .table = mux_table_cts_sel,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "cts_encp_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               .parent_names = gxbb_cts_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_vdac_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_VIID_CLK_DIV,
>>> +               .mask = 0xf,
>>> +               .shift = 28,
>>> +               .table = mux_table_cts_sel,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "cts_vdac_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               .parent_names = gxbb_cts_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +/* TOFIX: add support for cts_tcon */
>>> +static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
>>> +const char *gxbb_cts_hdmi_tx_parent_names[] = {
>>> +       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
>>> +       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
>>> +       "vclk2_div6", "vclk2_div12"
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_hdmi_tx_sel = {
>>> +       .data = &(struct clk_regmap_mux_data){
>>> +               .offset = HHI_HDMI_CLK_CNTL,
>>> +               .mask = 0xf,
>>> +               .shift = 16,
>>> +               .table = mux_table_hdmi_tx_sel,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "hdmi_tx_sel",
>>> +               .ops = &clk_regmap_mux_ops,
>>> +               /*
>>> +                * bits 31:28 selects from 12 possible parents:
>>> +                * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12
>>> +                * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12,
>>> +                * cts_tcon
>>> +                */
>>> +               .parent_names = gxbb_cts_hdmi_tx_parent_names,
>>> +               .num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names),
>>> +               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_enci = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL2,
>>> +               .bit_idx = 0,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "cts_enci",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "cts_enci_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_encp = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL2,
>>> +               .bit_idx = 2,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "cts_encp",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "cts_encp_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_cts_vdac = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL2,
>>> +               .bit_idx = 4,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "cts_vdac",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "cts_vdac_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>> +static struct clk_regmap gxbb_hdmi_tx = {
>>> +       .data = &(struct clk_regmap_gate_data){
>>> +               .offset = HHI_VID_CLK_CNTL2,
>>> +               .bit_idx = 5,
>>> +       },
>>> +       .hw.init = &(struct clk_init_data) {
>>> +               .name = "hdmi_tx",
>>> +               .ops = &clk_regmap_gate_ops,
>>> +               .parent_names = (const char *[]){ "hdmi_tx_sel" },
>>> +               .num_parents = 1,
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +       },
>>> +};
>>> +
>>>  /* VDEC clocks */
>>>
>>>  static const char * const gxbb_vdec_parent_names[] = {
>>> @@ -1919,6 +2483,43 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
>>>                 [CLKID_HDMI_PLL_OD2]        = &gxbb_hdmi_pll_od2.hw,
>>>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>>>                 [CLKID_GP0_PLL_DCO]         = &gxbb_gp0_pll_dco.hw,
>>> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
>>> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
>>> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
>>> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
>>> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
>>> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
>>> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
>>> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
>>> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
>>> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
>>> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
>>> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
>>> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
>>> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
>>> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
>>> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
>>> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
>>> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
>>> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
>>> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
>>> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
>>> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
>>> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
>>> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
>>> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
>>> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
>>> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
>>> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
>>> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
>>> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
>>> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
>>> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
>>> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
>>> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
>>> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
>>> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
>>> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>>>                 [NR_CLKS]                   = NULL,
>>>         },
>>>         .num = NR_CLKS,
>>> @@ -2090,6 +2691,43 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
>>>                 [CLKID_HDMI_PLL_OD2]        = &gxl_hdmi_pll_od2.hw,
>>>                 [CLKID_SYS_PLL_DCO]         = &gxbb_sys_pll_dco.hw,
>>>                 [CLKID_GP0_PLL_DCO]         = &gxl_gp0_pll_dco.hw,
>>> +               [CLKID_VID_PLL_DIV]         = &gxbb_vid_pll_div.hw,
>>> +               [CLKID_VID_PLL_SEL]         = &gxbb_vid_pll_sel.hw,
>>> +               [CLKID_VID_PLL]             = &gxbb_vid_pll.hw,
>>> +               [CLKID_VCLK_SEL]            = &gxbb_vclk_sel.hw,
>>> +               [CLKID_VCLK2_SEL]           = &gxbb_vclk2_sel.hw,
>>> +               [CLKID_VCLK_INPUT]          = &gxbb_vclk_input.hw,
>>> +               [CLKID_VCLK2_INPUT]         = &gxbb_vclk2_input.hw,
>>> +               [CLKID_VCLK_DIV]            = &gxbb_vclk_div.hw,
>>> +               [CLKID_VCLK2_DIV]           = &gxbb_vclk2_div.hw,
>>> +               [CLKID_VCLK]                = &gxbb_vclk.hw,
>>> +               [CLKID_VCLK2]               = &gxbb_vclk2.hw,
>>> +               [CLKID_VCLK_DIV1]           = &gxbb_vclk_div1.hw,
>>> +               [CLKID_VCLK_DIV2_EN]        = &gxbb_vclk_div2_en.hw,
>>> +               [CLKID_VCLK_DIV2]           = &gxbb_vclk_div2.hw,
>>> +               [CLKID_VCLK_DIV4_EN]        = &gxbb_vclk_div4_en.hw,
>>> +               [CLKID_VCLK_DIV4]           = &gxbb_vclk_div4.hw,
>>> +               [CLKID_VCLK_DIV6_EN]        = &gxbb_vclk_div6_en.hw,
>>> +               [CLKID_VCLK_DIV6]           = &gxbb_vclk_div6.hw,
>>> +               [CLKID_VCLK_DIV12_EN]       = &gxbb_vclk_div12_en.hw,
>>> +               [CLKID_VCLK_DIV12]          = &gxbb_vclk_div12.hw,
>>> +               [CLKID_VCLK2_DIV1]          = &gxbb_vclk2_div1.hw,
>>> +               [CLKID_VCLK2_DIV2_EN]       = &gxbb_vclk2_div2_en.hw,
>>> +               [CLKID_VCLK2_DIV2]          = &gxbb_vclk2_div2.hw,
>>> +               [CLKID_VCLK2_DIV4_EN]       = &gxbb_vclk2_div4_en.hw,
>>> +               [CLKID_VCLK2_DIV4]          = &gxbb_vclk2_div4.hw,
>>> +               [CLKID_VCLK2_DIV6_EN]       = &gxbb_vclk2_div6_en.hw,
>>> +               [CLKID_VCLK2_DIV6]          = &gxbb_vclk2_div6.hw,
>>> +               [CLKID_VCLK2_DIV12_EN]      = &gxbb_vclk2_div12_en.hw,
>>> +               [CLKID_VCLK2_DIV12]         = &gxbb_vclk2_div12.hw,
>>> +               [CLKID_CTS_ENCI_SEL]        = &gxbb_cts_enci_sel.hw,
>>> +               [CLKID_CTS_ENCP_SEL]        = &gxbb_cts_encp_sel.hw,
>>> +               [CLKID_CTS_VDAC_SEL]        = &gxbb_cts_vdac_sel.hw,
>>> +               [CLKID_HDMI_TX_SEL]         = &gxbb_hdmi_tx_sel.hw,
>>> +               [CLKID_CTS_ENCI]            = &gxbb_cts_enci.hw,
>>> +               [CLKID_CTS_ENCP]            = &gxbb_cts_encp.hw,
>>> +               [CLKID_CTS_VDAC]            = &gxbb_cts_vdac.hw,
>>> +               [CLKID_HDMI_TX]             = &gxbb_hdmi_tx.hw,
>>>                 [NR_CLKS]                   = NULL,
>>>         },
>>>         .num = NR_CLKS,
>>> @@ -2265,6 +2903,35 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
>>>         &gxbb_hdmi_pll_dco,
>>>         &gxbb_sys_pll_dco,
>>>         &gxbb_gp0_pll,
>>> +       &gxbb_vid_pll,
>>> +       &gxbb_vid_pll_sel,
>>> +       &gxbb_vid_pll_div,
>>> +       &gxbb_vclk,
>>> +       &gxbb_vclk_sel,
>>> +       &gxbb_vclk_div,
>>> +       &gxbb_vclk_input,
>>> +       &gxbb_vclk_div1,
>>> +       &gxbb_vclk_div2_en,
>>> +       &gxbb_vclk_div4_en,
>>> +       &gxbb_vclk_div6_en,
>>> +       &gxbb_vclk_div12_en,
>>> +       &gxbb_vclk2,
>>> +       &gxbb_vclk2_sel,
>>> +       &gxbb_vclk2_div,
>>> +       &gxbb_vclk2_input,
>>> +       &gxbb_vclk2_div1,
>>> +       &gxbb_vclk2_div2_en,
>>> +       &gxbb_vclk2_div4_en,
>>> +       &gxbb_vclk2_div6_en,
>>> +       &gxbb_vclk2_div12_en,
>>> +       &gxbb_cts_enci,
>>> +       &gxbb_cts_enci_sel,
>>> +       &gxbb_cts_encp,
>>> +       &gxbb_cts_encp_sel,
>>> +       &gxbb_cts_vdac,
>>> +       &gxbb_cts_vdac_sel,
>>> +       &gxbb_hdmi_tx,
>>> +       &gxbb_hdmi_tx_sel,
>>>  };
>>>
>>>  struct clkc_data {
>>> diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
>>> index 72bc077..171b7d8 100644
>>> --- a/drivers/clk/meson/gxbb.h
>>> +++ b/drivers/clk/meson/gxbb.h
>>> @@ -165,8 +165,28 @@
>>>  #define CLKID_HDMI_PLL_OD2       163
>>>  #define CLKID_SYS_PLL_DCO        164
>>>  #define CLKID_GP0_PLL_DCO        165
>>> -
>>> -#define NR_CLKS                          166
>>> +#define CLKID_VID_PLL_SEL        167
>>> +#define CLKID_VID_PLL_DIV        168
>>> +#define CLKID_VCLK_SEL           169
>>> +#define CLKID_VCLK2_SEL                  170
>>> +#define CLKID_VCLK_INPUT         171
>>> +#define CLKID_VCLK2_INPUT        172
>>> +#define CLKID_VCLK_DIV           173
>>> +#define CLKID_VCLK2_DIV                  174
>>> +#define CLKID_VCLK_DIV2_EN       177
>>> +#define CLKID_VCLK_DIV4_EN       178
>>> +#define CLKID_VCLK_DIV6_EN       179
>>> +#define CLKID_VCLK_DIV12_EN      180
>>> +#define CLKID_VCLK2_DIV2_EN      181
>>> +#define CLKID_VCLK2_DIV4_EN      182
>>> +#define CLKID_VCLK2_DIV6_EN      183
>>> +#define CLKID_VCLK2_DIV12_EN     184
>>> +#define CLKID_CTS_ENCI_SEL       195
>>> +#define CLKID_CTS_ENCP_SEL       196
>>> +#define CLKID_CTS_VDAC_SEL       197
>>> +#define CLKID_HDMI_TX_SEL        198
>>> +
>>> +#define NR_CLKS                          203
>>>
>>>  /* include the CLKIDs that have been made part of the DT binding */
>>>  #include <dt-bindings/clock/gxbb-clkc.h>
>>> diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
>>> index 3979d48..9f7b99e 100644
>>> --- a/include/dt-bindings/clock/gxbb-clkc.h
>>> +++ b/include/dt-bindings/clock/gxbb-clkc.h
>> shouldn't this go into a separate patch?
>>
>>> @@ -128,5 +128,22 @@
>>>  #define CLKID_VDEC_1           153
>>>  #define CLKID_VDEC_HEVC                156
>>>  #define CLKID_GEN_CLK          159
>>> +#define CLKID_VID_PLL          166
>>> +#define CLKID_VCLK             175
>>> +#define CLKID_VCLK2            176
>>> +#define CLKID_VCLK_DIV1                185
>>> +#define CLKID_VCLK_DIV2                186
>>> +#define CLKID_VCLK_DIV4                187
>>> +#define CLKID_VCLK_DIV6                188
>>> +#define CLKID_VCLK_DIV12       189
>>> +#define CLKID_VCLK2_DIV1       190
>>> +#define CLKID_VCLK2_DIV2       191
>>> +#define CLKID_VCLK2_DIV4       192
>>> +#define CLKID_VCLK2_DIV6       193
>>> +#define CLKID_VCLK2_DIV12      194
>> at first I was confused why you need to export all the dividers,
>> instead of simply calling clk_set_rate with "parent_rate (taken vom
>> VCLK or VCLK2) divided by N"
>> then I noticed that the four muxes below can use VCLK *or* VCLK2
>> dividers as input (as far as I remember this is different on Meson8b:
>> there the muxes below take either the VCLK dividers or the VCLK2
>> dividers as input, but not both)
> 
> Ok, I need to be sure both hdmi and enci/encp takes clock from the
> same vclk tree, and in some HDMI mode you need to have a x2 clock
> to cts_enci/encp from the same 1x clock to cts_htmi.
> 
> So I will need to manually setup the parents to make sure CCF doesn't
> make a random choice.
> 
> Then I'll be able to do a set_rate on vclk to setup the proper PLL rate.
> 
>>
>>> +#define CLKID_CTS_ENCI         199
>>> +#define CLKID_CTS_ENCP         200
>>> +#define CLKID_CTS_VDAC         201
>>> +#define CLKID_HDMI_TX          202
>> is my assumption correct that you need to choose a specific input
>> clock (VCLK or VCLK2) for a specific use-case (ENCI, ENCP, VDAC,
>> HDMI_TX)?
>> let's say HDMI uses VLKC2 as input (I'm not sure if it really does):
>> could you skip the VCLK_DIV_* parents in the HDMI_TX clock definition
>> - or does the selection of a specific parent clock (VCLK or VCLK2)
>> depend on the output rate?
> 
> HDMI takes vclk2 (why ? I'll keep this path since it's always used by the
> vendor code), and CBVS takes vclk.
> I suspect they tried to make is possible to have CVBS and HDMI output
> work at the same time using the VPP2 instance. But no idea how it works.
> 
> As I sais before, you need to feed a x2 factor to hdmi and enci/encp for
> some modes, and I can't let CCF decide since they must take the same
> clock path (VCLK or VCLK2, not both).
> 
>>
>>
>> Regards
>> Martin
>>
> 
> Neil
> 

Oh and for my own reference, I forgot to add the HDMI clk feeding the HDMI controller... HHI_HDMI_CLK_CNTL

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-07-24 12:07 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-20  9:39 [PATCH 0/2] clk: meson: Add video clocks path Neil Armstrong
2018-07-20  9:39 ` [PATCH 1/2] clk: meson: Add vid_pll divider driver Neil Armstrong
2018-07-20 19:17   ` Martin Blumenstingl
2018-07-24 11:56     ` Neil Armstrong
2018-07-20  9:39 ` [PATCH 2/2] clk: meson-gxbb: Add video clocks Neil Armstrong
2018-07-20 19:00   ` Martin Blumenstingl
2018-07-24 12:04     ` Neil Armstrong
2018-07-24 12:07       ` Neil Armstrong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).