Re: [PATCH 1/6] clk: renesas: rzg2l: Add DSI divider clock support for RZ/G3L

From: Geert Uytterhoeven

Date: Fri Jul 10 2026 - 11:35:24 EST


Hi Biju,

On Fri, 19 Jun 2026 at 18:40, Biju <biju.das.au@xxxxxxxxx> wrote:
> From: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
>
> Add a new DSI divider clock type (CLK_TYPE_G3L_PLLDSI_DIV) for the RZ/G3L
> SoC, which requires a different divider implementation than the existing
> RZ/G2L DSI divider clock.
>
> The RZ/G3L DSI divider uses two cascaded dividers, DIV_DSI_A and
> DIV_DSI_B, where the effective divider is:
>
> rate = parent_rate / ((1 << div_a) * (div_b + 1))
>
> DIV_DSI_A is a power-of-two divider with values in the range [0, 5],
> and DIV_DSI_B is a linear divider with values in the range [1, 16].
>
> Introduce the g3l_dsi_div_hw_data structure, rzg3l_cpg_dsi_div_ops, and
> rzg3l_cpg_dsi_div_clk_register() to implement the new clock type, and add
> the DEF_G3L_PLLDSI_DIV() macro for use in clock table definitions.
>
> Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>

Thanks for your patch!

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c

> @@ -834,6 +837,134 @@ rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core,
> return clk_hw->clk;
> }
>
> +struct g3l_dsi_div_hw_data {
> + struct clk_hw hw;
> + struct rzg2l_cpg_priv *priv;
> + unsigned long rate;
> + u32 off;
> + u8 div_a;
> + u8 div_b;
> +};
> +
> +#define to_g3l_dsi_div_hw_data(_hw) container_of(_hw, struct g3l_dsi_div_hw_data, hw)
> +
> +static unsigned long rzg3l_cpg_dsi_div_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw);
> + struct rzg2l_cpg_priv *priv = dsi_div->priv;
> + int div_a, div_b, val;
> +
> + val = readl(priv->base + dsi_div->off);
> + div_a = FIELD_GET(GENMASK(2, 0), val);
> + div_b = FIELD_GET(GENMASK(7, 4), val);

Please add and use

#define DIV_DSI_A_SET GENMASK(2, 0)
#define DIV_DSI_B_SET GENMASK(7, 4)

(after having seen G3L_SDIV_DSI_C_SET, I kept on looking for similar
A_SET and B_SET use).

> +
> + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, (1 << div_a) * (div_b + 1));

You can simplify the divider to "(div_b + 1) << div_a".

> +}
> +
> +static int rzg3l_cpg_dsi_div_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw);
> + struct rzg2l_cpg_priv *priv = dsi_div->priv;
> + u32 divider = dsi_div_ab_desired;

unsigned int

> + bool divider_found = false;
> + unsigned int div_a, div_b;

Perhaps move the declarations of the loop counters inside the
for()-statements?

> +
> + if (dsi_div_target) {
> + /* Calculate the DIV_DSI_A and DIV_DSI_B */

Please drop "the".

> + for (div_a = 5; div_a >= 0 && !divider_found; div_a--) {

div_a is unsigned, so >= is always true

> + for (div_b = 0; div_b < 16; div_b++) {
> + divider = (1 << div_a) * (div_b + 1);

(div_b + 1) << div_a

> + if (divider == dsi_div_ab_desired) {

divider is 1..512, while dsi_div_ab_desired is only u8.

> + dsi_div->div_a = div_a;
> + dsi_div->div_b = div_b;
> + divider_found = true;
> + break;
> + }
> + }
> + }
> + } else {
> + dsi_div->div_b = 0;
> + /* Calculate the DIV_DSI_A */

Please drop "the"

> + for (div_a = 5; div_a >= 0 && !divider_found; div_a--) {
> + divider = (1 << div_a);
> + if (divider == dsi_div_ab_desired) {
> + dsi_div->div_a = div_a;
> + divider_found = true;
> + break;
> + }
> + }
> + }
> +
> + if (!divider_found) {
> + dev_err(priv->dev, "failed dsi div for: %u\n", divider);
> + return -EINVAL;
> + }
> +
> + req->best_parent_rate = req->rate * divider;
> +
> + return 0;
> +}
> +
> +static int rzg3l_cpg_dsi_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw);
> + struct rzg2l_cpg_priv *priv = dsi_div->priv;
> +
> + writel(RZG3L_SDIV_DIV_DSI_A_WEN | RZG3L_SDIV_DIV_DSI_B_WEN |
> + (dsi_div->div_a << 0) | (dsi_div->div_b << 4),

FIELD_PREP(DIV_DSI_A_SET, dsi_div->div_a) |
FIELD_PREP(DIV_DSI_B_SET, dsi_div->div_b)


> + priv->base + dsi_div->off);
> +
> + return 0;
> +}

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds