2024-03-25 14:54:36

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH v11 3/7] clk: meson: g12a: make VCLK2 and ENCL clock path configurable by CCF

In order to setup the DSI clock, let's make the unused VCLK2 clock path
configuration via CCF.

The nocache option is removed from following clocks:
- vclk2_sel
- vclk2_input
- vclk2_div
- vclk2
- vclk_div1
- vclk2_div2_en
- vclk2_div4_en
- vclk2_div6_en
- vclk2_div12_en
- vclk2_div2
- vclk2_div4
- vclk2_div6
- vclk2_div12
- cts_encl_sel

vclk2 and vclk2_div uses the newly introduced vclk regmap driver
to handle the enable and reset bits.

In order to set a rate on cts_encl via the vclk2 clock path,
the NO_REPARENT flag is set on cts_encl_sel & vclk2_sel in order
to keep CCF from selection a parent.
The parents of cts_encl_sel & vclk2_sel are expected to be defined
in DT or manually set by the display driver at some point.

The following clock scheme is to be used for DSI:

xtal
\_ gp0_pll_dco
\_ gp0_pll
|- vclk2_sel
| \_ vclk2_input
| \_ vclk2_div
| \_ vclk2
| \_ vclk2_div1
| \_ cts_encl_sel
| \_ cts_encl -> to VPU LCD Encoder
|- mipi_dsi_pxclk_sel
\_ mipi_dsi_pxclk_div
\_ mipi_dsi_pxclk -> to DSI controller

The mipi_dsi_pxclk_div is set as bypass with a single /1 entry in div_table
in order to use the same GP0 for mipi_dsi_pxclk and vclk2_input.

The SET_RATE_PARENT is only set on the mipi_dsi_pxclk_sel clock so the
DSI bitclock is the reference base clock to calculate the vclk2_div value
when pixel clock is set on the cts_encl endpoint.

Signed-off-by: Neil Armstrong <[email protected]>
---
drivers/clk/meson/Kconfig | 1 +
drivers/clk/meson/g12a.c | 72 ++++++++++++++++++++++++++++++++++-------------
2 files changed, 53 insertions(+), 20 deletions(-)

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 8a9823789fa3..59a40a49f8e1 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -144,6 +144,7 @@ config COMMON_CLK_G12A
select COMMON_CLK_MESON_EE_CLKC
select COMMON_CLK_MESON_CPU_DYNDIV
select COMMON_CLK_MESON_VID_PLL_DIV
+ select COMMON_CLK_MESON_VCLK
select MFD_SYSCON
help
Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index 90f4c6103014..083882e53b65 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -22,6 +22,7 @@
#include "clk-regmap.h"
#include "clk-cpu-dyndiv.h"
#include "vid-pll-div.h"
+#include "vclk.h"
#include "meson-eeclk.h"
#include "g12a.h"

@@ -3165,7 +3166,7 @@ static struct clk_regmap g12a_vclk2_sel = {
.ops = &clk_regmap_mux_ops,
.parent_hws = g12a_vclk_parent_hws,
.num_parents = ARRAY_SIZE(g12a_vclk_parent_hws),
- .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_NO_REPARENT,
},
};

@@ -3193,7 +3194,6 @@ static struct clk_regmap g12a_vclk2_input = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};

@@ -3215,19 +3215,32 @@ static struct clk_regmap g12a_vclk_div = {
};

static struct clk_regmap g12a_vclk2_div = {
- .data = &(struct clk_regmap_div_data){
- .offset = HHI_VIID_CLK_DIV,
- .shift = 0,
- .width = 8,
+ .data = &(struct meson_vclk_div_data){
+ .div = {
+ .reg_off = HHI_VIID_CLK_DIV,
+ .shift = 0,
+ .width = 8,
+ },
+ .enable = {
+ .reg_off = HHI_VIID_CLK_DIV,
+ .shift = 16,
+ .width = 1,
+ },
+ .reset = {
+ .reg_off = HHI_VIID_CLK_DIV,
+ .shift = 17,
+ .width = 1,
+ },
+ .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "vclk2_div",
- .ops = &clk_regmap_divider_ops,
+ .ops = &meson_vclk_div_ops,
.parent_hws = (const struct clk_hw *[]) {
&g12a_vclk2_input.hw
},
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_GATE,
},
};

@@ -3246,16 +3259,24 @@ static struct clk_regmap g12a_vclk = {
};

static struct clk_regmap g12a_vclk2 = {
- .data = &(struct clk_regmap_gate_data){
- .offset = HHI_VIID_CLK_CNTL,
- .bit_idx = 19,
+ .data = &(struct meson_vclk_gate_data){
+ .enable = {
+ .reg_off = HHI_VIID_CLK_CNTL,
+ .shift = 19,
+ .width = 1,
+ },
+ .reset = {
+ .reg_off = HHI_VIID_CLK_CNTL,
+ .shift = 15,
+ .width = 1,
+ },
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2",
- .ops = &clk_regmap_gate_ops,
+ .ops = &meson_vclk_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3339,7 +3360,7 @@ static struct clk_regmap g12a_vclk2_div1 = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3353,7 +3374,7 @@ static struct clk_regmap g12a_vclk2_div2_en = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3367,7 +3388,7 @@ static struct clk_regmap g12a_vclk2_div4_en = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3381,7 +3402,7 @@ static struct clk_regmap g12a_vclk2_div6_en = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3395,7 +3416,7 @@ static struct clk_regmap g12a_vclk2_div12_en = {
.ops = &clk_regmap_gate_ops,
.parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3461,6 +3482,7 @@ static struct clk_fixed_factor g12a_vclk2_div2 = {
&g12a_vclk2_div2_en.hw
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3474,6 +3496,7 @@ static struct clk_fixed_factor g12a_vclk2_div4 = {
&g12a_vclk2_div4_en.hw
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3487,6 +3510,7 @@ static struct clk_fixed_factor g12a_vclk2_div6 = {
&g12a_vclk2_div6_en.hw
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3500,6 +3524,7 @@ static struct clk_fixed_factor g12a_vclk2_div12 = {
&g12a_vclk2_div12_en.hw
},
.num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};

@@ -3561,7 +3586,7 @@ static struct clk_regmap g12a_cts_encl_sel = {
.ops = &clk_regmap_mux_ops,
.parent_hws = g12a_cts_parent_hws,
.num_parents = ARRAY_SIZE(g12a_cts_parent_hws),
- .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};

@@ -3717,15 +3742,22 @@ static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
.ops = &clk_regmap_mux_ops,
.parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
.num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
- .flags = CLK_SET_RATE_NO_REPARENT,
+ .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
},
};

+/* Force as bypass by forcing a single /1 table entry, and not rely of boot value */
+static const struct clk_div_table g12a_mipi_dsi_pxclk_div_table[] = {
+ { .val = 0, .div = 1 },
+ { /* sentinel */ },
+};
+
static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MIPIDSI_PHY_CLK_CNTL,
.shift = 0,
.width = 7,
+ .table = g12a_mipi_dsi_pxclk_div_table,
},
.hw.init = &(struct clk_init_data){
.name = "mipi_dsi_pxclk_div",

--
2.34.1



2024-03-29 13:52:07

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v11 3/7] clk: meson: g12a: make VCLK2 and ENCL clock path configurable by CCF


On Mon 25 Mar 2024 at 12:09, Neil Armstrong <[email protected]> wrote:

> In order to setup the DSI clock, let's make the unused VCLK2 clock path
> configuration via CCF.
>
> The nocache option is removed from following clocks:
> - vclk2_sel
> - vclk2_input
> - vclk2_div
> - vclk2
> - vclk_div1
> - vclk2_div2_en
> - vclk2_div4_en
> - vclk2_div6_en
> - vclk2_div12_en
> - vclk2_div2
> - vclk2_div4
> - vclk2_div6
> - vclk2_div12
> - cts_encl_sel
>
> vclk2 and vclk2_div uses the newly introduced vclk regmap driver
> to handle the enable and reset bits.
>
> In order to set a rate on cts_encl via the vclk2 clock path,
> the NO_REPARENT flag is set on cts_encl_sel & vclk2_sel in order
> to keep CCF from selection a parent.
> The parents of cts_encl_sel & vclk2_sel are expected to be defined
> in DT or manually set by the display driver at some point.
>
> The following clock scheme is to be used for DSI:
>
> xtal
> \_ gp0_pll_dco
> \_ gp0_pll
> |- vclk2_sel
> | \_ vclk2_input
> | \_ vclk2_div
> | \_ vclk2
> | \_ vclk2_div1
> | \_ cts_encl_sel
> | \_ cts_encl -> to VPU LCD Encoder
> |- mipi_dsi_pxclk_sel
> \_ mipi_dsi_pxclk_div
> \_ mipi_dsi_pxclk -> to DSI controller
>
> The mipi_dsi_pxclk_div is set as bypass with a single /1 entry in div_table
> in order to use the same GP0 for mipi_dsi_pxclk and vclk2_input.
>
> The SET_RATE_PARENT is only set on the mipi_dsi_pxclk_sel clock so the
> DSI bitclock is the reference base clock to calculate the vclk2_div value
> when pixel clock is set on the cts_encl endpoint.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> drivers/clk/meson/Kconfig | 1 +
> drivers/clk/meson/g12a.c | 72 ++++++++++++++++++++++++++++++++++-------------
> 2 files changed, 53 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 8a9823789fa3..59a40a49f8e1 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -144,6 +144,7 @@ config COMMON_CLK_G12A
> select COMMON_CLK_MESON_EE_CLKC
> select COMMON_CLK_MESON_CPU_DYNDIV
> select COMMON_CLK_MESON_VID_PLL_DIV
> + select COMMON_CLK_MESON_VCLK
> select MFD_SYSCON
> help
> Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
> diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
> index 90f4c6103014..083882e53b65 100644
> --- a/drivers/clk/meson/g12a.c
> +++ b/drivers/clk/meson/g12a.c
> @@ -22,6 +22,7 @@
> #include "clk-regmap.h"
> #include "clk-cpu-dyndiv.h"
> #include "vid-pll-div.h"
> +#include "vclk.h"
> #include "meson-eeclk.h"
> #include "g12a.h"
>
> @@ -3165,7 +3166,7 @@ static struct clk_regmap g12a_vclk2_sel = {
> .ops = &clk_regmap_mux_ops,
> .parent_hws = g12a_vclk_parent_hws,
> .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws),
> - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> + .flags = CLK_SET_RATE_NO_REPARENT,
> },
> };
>
> @@ -3193,7 +3194,6 @@ static struct clk_regmap g12a_vclk2_input = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> },
> };
>
> @@ -3215,19 +3215,32 @@ static struct clk_regmap g12a_vclk_div = {
> };
>
> static struct clk_regmap g12a_vclk2_div = {
> - .data = &(struct clk_regmap_div_data){
> - .offset = HHI_VIID_CLK_DIV,
> - .shift = 0,
> - .width = 8,
> + .data = &(struct meson_vclk_div_data){
> + .div = {
> + .reg_off = HHI_VIID_CLK_DIV,
> + .shift = 0,
> + .width = 8,
> + },
> + .enable = {
> + .reg_off = HHI_VIID_CLK_DIV,
> + .shift = 16,
> + .width = 1,
> + },
> + .reset = {
> + .reg_off = HHI_VIID_CLK_DIV,
> + .shift = 17,
> + .width = 1,
> + },
> + .flags = CLK_DIVIDER_ROUND_CLOSEST,
> },
> .hw.init = &(struct clk_init_data){
> .name = "vclk2_div",
> - .ops = &clk_regmap_divider_ops,
> + .ops = &meson_vclk_div_ops,
> .parent_hws = (const struct clk_hw *[]) {
> &g12a_vclk2_input.hw
> },
> .num_parents = 1,
> - .flags = CLK_GET_RATE_NOCACHE,
> + .flags = CLK_SET_RATE_GATE,
> },
> };
>
> @@ -3246,16 +3259,24 @@ static struct clk_regmap g12a_vclk = {
> };
>
> static struct clk_regmap g12a_vclk2 = {
> - .data = &(struct clk_regmap_gate_data){
> - .offset = HHI_VIID_CLK_CNTL,
> - .bit_idx = 19,
> + .data = &(struct meson_vclk_gate_data){
> + .enable = {
> + .reg_off = HHI_VIID_CLK_CNTL,
> + .shift = 19,
> + .width = 1,
> + },
> + .reset = {
> + .reg_off = HHI_VIID_CLK_CNTL,
> + .shift = 15,
> + .width = 1,
> + },
> },
> .hw.init = &(struct clk_init_data) {
> .name = "vclk2",
> - .ops = &clk_regmap_gate_ops,
> + .ops = &meson_vclk_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3339,7 +3360,7 @@ static struct clk_regmap g12a_vclk2_div1 = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3353,7 +3374,7 @@ static struct clk_regmap g12a_vclk2_div2_en = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3367,7 +3388,7 @@ static struct clk_regmap g12a_vclk2_div4_en = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3381,7 +3402,7 @@ static struct clk_regmap g12a_vclk2_div6_en = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3395,7 +3416,7 @@ static struct clk_regmap g12a_vclk2_div12_en = {
> .ops = &clk_regmap_gate_ops,
> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
> .num_parents = 1,
> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3461,6 +3482,7 @@ static struct clk_fixed_factor g12a_vclk2_div2 = {
> &g12a_vclk2_div2_en.hw
> },
> .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3474,6 +3496,7 @@ static struct clk_fixed_factor g12a_vclk2_div4 = {
> &g12a_vclk2_div4_en.hw
> },
> .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3487,6 +3510,7 @@ static struct clk_fixed_factor g12a_vclk2_div6 = {
> &g12a_vclk2_div6_en.hw
> },
> .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3500,6 +3524,7 @@ static struct clk_fixed_factor g12a_vclk2_div12 = {
> &g12a_vclk2_div12_en.hw
> },
> .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> },
> };
>
> @@ -3561,7 +3586,7 @@ static struct clk_regmap g12a_cts_encl_sel = {
> .ops = &clk_regmap_mux_ops,
> .parent_hws = g12a_cts_parent_hws,
> .num_parents = ARRAY_SIZE(g12a_cts_parent_hws),
> - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
> + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> },
> };
>
> @@ -3717,15 +3742,22 @@ static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
> .ops = &clk_regmap_mux_ops,
> .parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
> .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
> - .flags = CLK_SET_RATE_NO_REPARENT,
> + .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
> },
> };
>
> +/* Force as bypass by forcing a single /1 table entry, and not rely of boot value */

The comment here is not entirely accurate.

The table below will actually force to only use a 1 divider on
set_rate(), not on boot, AFAICT.

The boot value will stay in the register until the first call to set_rate().

Considering this is quite fragile as it is, It would be nice to prefix
the updated comment with "FIXME"

> +static const struct clk_div_table g12a_mipi_dsi_pxclk_div_table[] = {
> + { .val = 0, .div = 1 },
> + { /* sentinel */ },
> +};
> +
> static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
> .data = &(struct clk_regmap_div_data){
> .offset = HHI_MIPIDSI_PHY_CLK_CNTL,
> .shift = 0,
> .width = 7,
> + .table = g12a_mipi_dsi_pxclk_div_table,
> },
> .hw.init = &(struct clk_init_data){
> .name = "mipi_dsi_pxclk_div",


--
Jerome

2024-03-29 16:07:23

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v11 3/7] clk: meson: g12a: make VCLK2 and ENCL clock path configurable by CCF

On 29/03/2024 13:35, Jerome Brunet wrote:
>
> On Mon 25 Mar 2024 at 12:09, Neil Armstrong <[email protected]> wrote:
>
>> In order to setup the DSI clock, let's make the unused VCLK2 clock path
>> configuration via CCF.
>>
>> The nocache option is removed from following clocks:
>> - vclk2_sel
>> - vclk2_input
>> - vclk2_div
>> - vclk2
>> - vclk_div1
>> - vclk2_div2_en
>> - vclk2_div4_en
>> - vclk2_div6_en
>> - vclk2_div12_en
>> - vclk2_div2
>> - vclk2_div4
>> - vclk2_div6
>> - vclk2_div12
>> - cts_encl_sel
>>
>> vclk2 and vclk2_div uses the newly introduced vclk regmap driver
>> to handle the enable and reset bits.
>>
>> In order to set a rate on cts_encl via the vclk2 clock path,
>> the NO_REPARENT flag is set on cts_encl_sel & vclk2_sel in order
>> to keep CCF from selection a parent.
>> The parents of cts_encl_sel & vclk2_sel are expected to be defined
>> in DT or manually set by the display driver at some point.
>>
>> The following clock scheme is to be used for DSI:
>>
>> xtal
>> \_ gp0_pll_dco
>> \_ gp0_pll
>> |- vclk2_sel
>> | \_ vclk2_input
>> | \_ vclk2_div
>> | \_ vclk2
>> | \_ vclk2_div1
>> | \_ cts_encl_sel
>> | \_ cts_encl -> to VPU LCD Encoder
>> |- mipi_dsi_pxclk_sel
>> \_ mipi_dsi_pxclk_div
>> \_ mipi_dsi_pxclk -> to DSI controller
>>
>> The mipi_dsi_pxclk_div is set as bypass with a single /1 entry in div_table
>> in order to use the same GP0 for mipi_dsi_pxclk and vclk2_input.
>>
>> The SET_RATE_PARENT is only set on the mipi_dsi_pxclk_sel clock so the
>> DSI bitclock is the reference base clock to calculate the vclk2_div value
>> when pixel clock is set on the cts_encl endpoint.
>>
>> Signed-off-by: Neil Armstrong <[email protected]>
>> ---
>> drivers/clk/meson/Kconfig | 1 +
>> drivers/clk/meson/g12a.c | 72 ++++++++++++++++++++++++++++++++++-------------
>> 2 files changed, 53 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 8a9823789fa3..59a40a49f8e1 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -144,6 +144,7 @@ config COMMON_CLK_G12A
>> select COMMON_CLK_MESON_EE_CLKC
>> select COMMON_CLK_MESON_CPU_DYNDIV
>> select COMMON_CLK_MESON_VID_PLL_DIV
>> + select COMMON_CLK_MESON_VCLK
>> select MFD_SYSCON
>> help
>> Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>> diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
>> index 90f4c6103014..083882e53b65 100644
>> --- a/drivers/clk/meson/g12a.c
>> +++ b/drivers/clk/meson/g12a.c
>> @@ -22,6 +22,7 @@
>> #include "clk-regmap.h"
>> #include "clk-cpu-dyndiv.h"
>> #include "vid-pll-div.h"
>> +#include "vclk.h"
>> #include "meson-eeclk.h"
>> #include "g12a.h"
>>
>> @@ -3165,7 +3166,7 @@ static struct clk_regmap g12a_vclk2_sel = {
>> .ops = &clk_regmap_mux_ops,
>> .parent_hws = g12a_vclk_parent_hws,
>> .num_parents = ARRAY_SIZE(g12a_vclk_parent_hws),
>> - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> + .flags = CLK_SET_RATE_NO_REPARENT,
>> },
>> };
>>
>> @@ -3193,7 +3194,6 @@ static struct clk_regmap g12a_vclk2_input = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> },
>> };
>>
>> @@ -3215,19 +3215,32 @@ static struct clk_regmap g12a_vclk_div = {
>> };
>>
>> static struct clk_regmap g12a_vclk2_div = {
>> - .data = &(struct clk_regmap_div_data){
>> - .offset = HHI_VIID_CLK_DIV,
>> - .shift = 0,
>> - .width = 8,
>> + .data = &(struct meson_vclk_div_data){
>> + .div = {
>> + .reg_off = HHI_VIID_CLK_DIV,
>> + .shift = 0,
>> + .width = 8,
>> + },
>> + .enable = {
>> + .reg_off = HHI_VIID_CLK_DIV,
>> + .shift = 16,
>> + .width = 1,
>> + },
>> + .reset = {
>> + .reg_off = HHI_VIID_CLK_DIV,
>> + .shift = 17,
>> + .width = 1,
>> + },
>> + .flags = CLK_DIVIDER_ROUND_CLOSEST,
>> },
>> .hw.init = &(struct clk_init_data){
>> .name = "vclk2_div",
>> - .ops = &clk_regmap_divider_ops,
>> + .ops = &meson_vclk_div_ops,
>> .parent_hws = (const struct clk_hw *[]) {
>> &g12a_vclk2_input.hw
>> },
>> .num_parents = 1,
>> - .flags = CLK_GET_RATE_NOCACHE,
>> + .flags = CLK_SET_RATE_GATE,
>> },
>> };
>>
>> @@ -3246,16 +3259,24 @@ static struct clk_regmap g12a_vclk = {
>> };
>>
>> static struct clk_regmap g12a_vclk2 = {
>> - .data = &(struct clk_regmap_gate_data){
>> - .offset = HHI_VIID_CLK_CNTL,
>> - .bit_idx = 19,
>> + .data = &(struct meson_vclk_gate_data){
>> + .enable = {
>> + .reg_off = HHI_VIID_CLK_CNTL,
>> + .shift = 19,
>> + .width = 1,
>> + },
>> + .reset = {
>> + .reg_off = HHI_VIID_CLK_CNTL,
>> + .shift = 15,
>> + .width = 1,
>> + },
>> },
>> .hw.init = &(struct clk_init_data) {
>> .name = "vclk2",
>> - .ops = &clk_regmap_gate_ops,
>> + .ops = &meson_vclk_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3339,7 +3360,7 @@ static struct clk_regmap g12a_vclk2_div1 = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3353,7 +3374,7 @@ static struct clk_regmap g12a_vclk2_div2_en = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3367,7 +3388,7 @@ static struct clk_regmap g12a_vclk2_div4_en = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3381,7 +3402,7 @@ static struct clk_regmap g12a_vclk2_div6_en = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3395,7 +3416,7 @@ static struct clk_regmap g12a_vclk2_div12_en = {
>> .ops = &clk_regmap_gate_ops,
>> .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw },
>> .num_parents = 1,
>> - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3461,6 +3482,7 @@ static struct clk_fixed_factor g12a_vclk2_div2 = {
>> &g12a_vclk2_div2_en.hw
>> },
>> .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3474,6 +3496,7 @@ static struct clk_fixed_factor g12a_vclk2_div4 = {
>> &g12a_vclk2_div4_en.hw
>> },
>> .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3487,6 +3510,7 @@ static struct clk_fixed_factor g12a_vclk2_div6 = {
>> &g12a_vclk2_div6_en.hw
>> },
>> .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3500,6 +3524,7 @@ static struct clk_fixed_factor g12a_vclk2_div12 = {
>> &g12a_vclk2_div12_en.hw
>> },
>> .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> @@ -3561,7 +3586,7 @@ static struct clk_regmap g12a_cts_encl_sel = {
>> .ops = &clk_regmap_mux_ops,
>> .parent_hws = g12a_cts_parent_hws,
>> .num_parents = ARRAY_SIZE(g12a_cts_parent_hws),
>> - .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
>> + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
>> },
>> };
>>
>> @@ -3717,15 +3742,22 @@ static struct clk_regmap g12a_mipi_dsi_pxclk_sel = {
>> .ops = &clk_regmap_mux_ops,
>> .parent_hws = g12a_mipi_dsi_pxclk_parent_hws,
>> .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws),
>> - .flags = CLK_SET_RATE_NO_REPARENT,
>> + .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
>> },
>> };
>>
>> +/* Force as bypass by forcing a single /1 table entry, and not rely of boot value */
>
> The comment here is not entirely accurate.
>
> The table below will actually force to only use a 1 divider on
> .set_rate(), not on boot, AFAICT.
>
> The boot value will stay in the register until the first call to set_rate().
>
> Considering this is quite fragile as it is, It would be nice to prefix
> the updated comment with "FIXME"

Ack

>
>> +static const struct clk_div_table g12a_mipi_dsi_pxclk_div_table[] = {
>> + { .val = 0, .div = 1 },
>> + { /* sentinel */ },
>> +};
>> +
>> static struct clk_regmap g12a_mipi_dsi_pxclk_div = {
>> .data = &(struct clk_regmap_div_data){
>> .offset = HHI_MIPIDSI_PHY_CLK_CNTL,
>> .shift = 0,
>> .width = 7,
>> + .table = g12a_mipi_dsi_pxclk_div_table,
>> },
>> .hw.init = &(struct clk_init_data){
>> .name = "mipi_dsi_pxclk_div",
>
>