diff mbox series

[3/9] clk: renesas: rzg2l: Add DSI divider clk support

Message ID 20220318175113.8956-4-biju.das.jz@bp.renesas.com (mailing list archive)
State Changes Requested, archived
Headers show
Series Add RZ/G2L Display clock support | expand

Commit Message

Biju Das March 18, 2022, 5:51 p.m. UTC
M3 clock is sourced from DSI Divider (DSIDIVA * DSIDIVB)

This patch add support for DSI divider clk by combaining
DSIDIVA and DSIDIVB .

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
RFC->V1
 * Removed LUT and added an equation for computing VCLK.
---
 drivers/clk/renesas/rzg2l-cpg.c | 114 ++++++++++++++++++++++++++++++++
 drivers/clk/renesas/rzg2l-cpg.h |  13 ++++
 2 files changed, 127 insertions(+)

Comments

Geert Uytterhoeven April 21, 2022, 8:02 a.m. UTC | #1
Hi Biju,

On Fri, Mar 18, 2022 at 6:51 PM Biju Das <biju.das.jz@bp.renesas.com> wrote:
> M3 clock is sourced from DSI Divider (DSIDIVA * DSIDIVB)
>
> This patch add support for DSI divider clk by combaining
> DSIDIVA and DSIDIVB .
>
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> ---
> RFC->V1
>  * Removed LUT and added an equation for computing VCLK.

Thanks for the update!

> --- a/drivers/clk/renesas/rzg2l-cpg.c
> +++ b/drivers/clk/renesas/rzg2l-cpg.c
> @@ -279,6 +282,114 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core,
>         return clk_hw->clk;
>  }
>
> +struct dsi_div_hw_data {
> +       struct clk_hw hw;
> +       u32 conf;
> +       unsigned long rate;
> +       struct rzg2l_cpg_priv *priv;
> +};
> +
> +#define to_dsi_div_hw_data(_hw)        container_of(_hw, struct dsi_div_hw_data, hw)
> +
> +static unsigned long rzg2l_cpg_dsi_div_recalc_rate(struct clk_hw *hw,
> +                                                  unsigned long parent_rate)
> +{
> +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> +
> +       return dsi_div->rate;
> +}
> +
> +static long rzg2l_cpg_dsi_div_round_rate(struct clk_hw *hw,
> +                                        unsigned long rate,
> +                                        unsigned long *parent_rate)

Please implement the determine_rate() instead.

> +

Please drop the blank line.

> +{
> +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> +
> +       dsi_div->rate = rate;
> +
> +       priv->pll5_params.pl5_intin = rate / MEGA;

.round_rate() (and .determine_rate()) is used to check if a rate
is supported, without actually changing the clock rate.  Hence this
should not operate on priv->pll5_params, but on a local variable.

> +       priv->pll5_params.pl5_fracin = ((rate % MEGA) << 24) / MEGA;

While this works fine on 64-bit (RZ/G2L is arm64, so that's OK),
"(rate % MEGA) << 24" will overflow when compile-testing on 32-bit.
Taking into account the 64-by-32 division, I think this should be:

    div_u64(((u64)rate % MEGA) << 24, MEGA);

> +       priv->pll5_params.pl5_refdiv = 2;
> +       priv->pll5_params.pl5_postdiv1 = 1;
> +       priv->pll5_params.pl5_postdiv2 = 1;
> +       priv->pll5_params.clksrc = 1;
> +       priv->pll5_params.dsi_div_a = 1;
> +       priv->pll5_params.dsi_div_b = 2;
> +
> +       priv->pll5_params.frequency =
> +               EXTAL_FREQ_IN_MEGA_HZ * MEGA / priv->pll5_params.pl5_refdiv *
> +               ((((priv->pll5_params.pl5_intin << 24) + priv->pll5_params.pl5_fracin)) >> 24) /
> +               (priv->pll5_params.pl5_postdiv1 * priv->pll5_params.pl5_postdiv2);
> +
> +       if (priv->pll5_params.clksrc)
> +               priv->pll5_params.frequency /= 2;
> +
> +       *parent_rate = priv->pll5_params.frequency;
> +
> +       return dsi_div->rate;
> +}
> +
> +static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
> +                                     unsigned long rate,
> +                                     unsigned long parent_rate)
> +{
> +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> +

You should update priv->pll5_params here, instead of in your
.round_rate() callback.

> +       writel(CPG_PL5_SDIV_DIV_DSI_A_WEN | CPG_PL5_SDIV_DIV_DSI_B_WEN |
> +              (priv->pll5_params.dsi_div_a << 0) | (priv->pll5_params.dsi_div_b << 8),
> +              priv->base + CPG_PL5_SDIV);
> +
> +       return 0;
> +}

The rest LGTM.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

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
Biju Das April 22, 2022, 11:15 a.m. UTC | #2
Hi Geert,

Thanks for the feedback.

> Subject: Re: [PATCH 3/9] clk: renesas: rzg2l: Add DSI divider clk support
> 
> Hi Biju,
> 
> On Fri, Mar 18, 2022 at 6:51 PM Biju Das <biju.das.jz@bp.renesas.com>
> wrote:
> > M3 clock is sourced from DSI Divider (DSIDIVA * DSIDIVB)
> >
> > This patch add support for DSI divider clk by combaining DSIDIVA and
> > DSIDIVB .
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > ---
> > RFC->V1
> >  * Removed LUT and added an equation for computing VCLK.
> 
> Thanks for the update!
> 
> > --- a/drivers/clk/renesas/rzg2l-cpg.c
> > +++ b/drivers/clk/renesas/rzg2l-cpg.c
> > @@ -279,6 +282,114 @@ rzg2l_cpg_sd_mux_clk_register(const struct
> cpg_core_clk *core,
> >         return clk_hw->clk;
> >  }
> >
> > +struct dsi_div_hw_data {
> > +       struct clk_hw hw;
> > +       u32 conf;
> > +       unsigned long rate;
> > +       struct rzg2l_cpg_priv *priv;
> > +};
> > +
> > +#define to_dsi_div_hw_data(_hw)        container_of(_hw, struct
> dsi_div_hw_data, hw)
> > +
> > +static unsigned long rzg2l_cpg_dsi_div_recalc_rate(struct clk_hw *hw,
> > +                                                  unsigned long
> > +parent_rate) {
> > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > +
> > +       return dsi_div->rate;
> > +}
> > +
> > +static long rzg2l_cpg_dsi_div_round_rate(struct clk_hw *hw,
> > +                                        unsigned long rate,
> > +                                        unsigned long *parent_rate)
> 
> Please implement the determine_rate() instead.

OK.
> 
> > +
> 
> Please drop the blank line.
OK.
> 
> > +{
> > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > +
> > +       dsi_div->rate = rate;
> > +
> > +       priv->pll5_params.pl5_intin = rate / MEGA;
> 
> .round_rate() (and .determine_rate()) is used to check if a rate is
> supported, without actually changing the clock rate.  Hence this should not
> operate on priv->pll5_params, but on a local variable.
> 
> > +       priv->pll5_params.pl5_fracin = ((rate % MEGA) << 24) / MEGA;
> 
> While this works fine on 64-bit (RZ/G2L is arm64, so that's OK), "(rate %
> MEGA) << 24" will overflow when compile-testing on 32-bit.
> Taking into account the 64-by-32 division, I think this should be:
> 
>     div_u64(((u64)rate % MEGA) << 24, MEGA);

OK.

> 
> > +       priv->pll5_params.pl5_refdiv = 2;
> > +       priv->pll5_params.pl5_postdiv1 = 1;
> > +       priv->pll5_params.pl5_postdiv2 = 1;
> > +       priv->pll5_params.clksrc = 1;
> > +       priv->pll5_params.dsi_div_a = 1;
> > +       priv->pll5_params.dsi_div_b = 2;
> > +
> > +       priv->pll5_params.frequency =
> > +               EXTAL_FREQ_IN_MEGA_HZ * MEGA / priv-
> >pll5_params.pl5_refdiv *
> > +               ((((priv->pll5_params.pl5_intin << 24) + priv-
> >pll5_params.pl5_fracin)) >> 24) /
> > +               (priv->pll5_params.pl5_postdiv1 *
> > + priv->pll5_params.pl5_postdiv2);
> > +
> > +       if (priv->pll5_params.clksrc)
> > +               priv->pll5_params.frequency /= 2;
> > +
> > +       *parent_rate = priv->pll5_params.frequency;
> > +
> > +       return dsi_div->rate;
> > +}
> > +
> > +static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
> > +                                     unsigned long rate,
> > +                                     unsigned long parent_rate) {
> > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > +
> 
> You should update priv->pll5_params here, instead of in your
> .round_rate() callback.

I need to find parent_rate based on video clock during {determine,round rate}
I have added there to avoid duplication.

I agree, the following to be set here instead of round_rate() callback.
dsi_div->rate = rate;

Cheers,
Biju

> 
> > +       writel(CPG_PL5_SDIV_DIV_DSI_A_WEN | CPG_PL5_SDIV_DIV_DSI_B_WEN |
> > +              (priv->pll5_params.dsi_div_a << 0) | (priv-
> >pll5_params.dsi_div_b << 8),
> > +              priv->base + CPG_PL5_SDIV);
> > +
> > +       return 0;
> > +}
> 
> The rest LGTM.
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-
> m68k.org
> 
> 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
Geert Uytterhoeven April 22, 2022, 3:10 p.m. UTC | #3
Hi Biju,

On Fri, Apr 22, 2022 at 1:15 PM Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > Subject: Re: [PATCH 3/9] clk: renesas: rzg2l: Add DSI divider clk support
> > On Fri, Mar 18, 2022 at 6:51 PM Biju Das <biju.das.jz@bp.renesas.com>
> > wrote:
> > > M3 clock is sourced from DSI Divider (DSIDIVA * DSIDIVB)
> > >
> > > This patch add support for DSI divider clk by combaining DSIDIVA and
> > > DSIDIVB .
> > >
> > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>

> > > --- a/drivers/clk/renesas/rzg2l-cpg.c
> > > +++ b/drivers/clk/renesas/rzg2l-cpg.c
> > > +static long rzg2l_cpg_dsi_div_round_rate(struct clk_hw *hw,
> > > +                                        unsigned long rate,
> > > +                                        unsigned long *parent_rate)
> > > +{
> > > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > > +
> > > +       dsi_div->rate = rate;
> > > +
> > > +       priv->pll5_params.pl5_intin = rate / MEGA;
> >
> > .round_rate() (and .determine_rate()) is used to check if a rate is
> > supported, without actually changing the clock rate.  Hence this should not
> > operate on priv->pll5_params, but on a local variable.
> >
> > > +       priv->pll5_params.pl5_fracin = ((rate % MEGA) << 24) / MEGA;
> > > +       priv->pll5_params.pl5_refdiv = 2;
> > > +       priv->pll5_params.pl5_postdiv1 = 1;
> > > +       priv->pll5_params.pl5_postdiv2 = 1;
> > > +       priv->pll5_params.clksrc = 1;
> > > +       priv->pll5_params.dsi_div_a = 1;
> > > +       priv->pll5_params.dsi_div_b = 2;
> > > +
> > > +       priv->pll5_params.frequency =
> > > +               EXTAL_FREQ_IN_MEGA_HZ * MEGA / priv-
> > >pll5_params.pl5_refdiv *
> > > +               ((((priv->pll5_params.pl5_intin << 24) + priv-
> > >pll5_params.pl5_fracin)) >> 24) /
> > > +               (priv->pll5_params.pl5_postdiv1 *
> > > + priv->pll5_params.pl5_postdiv2);
> > > +
> > > +       if (priv->pll5_params.clksrc)
> > > +               priv->pll5_params.frequency /= 2;
> > > +
> > > +       *parent_rate = priv->pll5_params.frequency;
> > > +
> > > +       return dsi_div->rate;
> > > +}
> > > +
> > > +static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
> > > +                                     unsigned long rate,
> > > +                                     unsigned long parent_rate) {
> > > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > > +
> >
> > You should update priv->pll5_params here, instead of in your
> > .round_rate() callback.
>
> I need to find parent_rate based on video clock during {determine,round rate}

There is no guarantee that .set_rate() is called right after
.determine_rate() with the exact same parameters, or that it is called
at all. Modifying priv->pll5_params prematurely may affect the other
clocks in hard to debug ways.  So please modify priv->pll5_params
only when actually setting the clock rate.

> I have added there to avoid duplication.

You can use a helper that takes a pointer to a struct rzg2l_pll5_param,
calculates the values, and fills them in.
.{determine,round rate}() would call it with a pointer to a local variable.
.set_rate() would call it with a pointer to &priv->pll5_params.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

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
Biju Das April 26, 2022, 5:04 p.m. UTC | #4
Hi Geert,

Thanks for the feedback.

> Subject: Re: [PATCH 3/9] clk: renesas: rzg2l: Add DSI divider clk support
> 
> Hi Biju,
> 
> On Fri, Apr 22, 2022 at 1:15 PM Biju Das <biju.das.jz@bp.renesas.com>
> wrote:
> > > Subject: Re: [PATCH 3/9] clk: renesas: rzg2l: Add DSI divider clk
> > > support On Fri, Mar 18, 2022 at 6:51 PM Biju Das
> > > <biju.das.jz@bp.renesas.com>
> > > wrote:
> > > > M3 clock is sourced from DSI Divider (DSIDIVA * DSIDIVB)
> > > >
> > > > This patch add support for DSI divider clk by combaining DSIDIVA
> > > > and DSIDIVB .
> > > >
> > > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> 
> > > > --- a/drivers/clk/renesas/rzg2l-cpg.c
> > > > +++ b/drivers/clk/renesas/rzg2l-cpg.c
> > > > +static long rzg2l_cpg_dsi_div_round_rate(struct clk_hw *hw,
> > > > +                                        unsigned long rate,
> > > > +                                        unsigned long
> > > > +*parent_rate) {
> > > > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > > > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > > > +
> > > > +       dsi_div->rate = rate;
> > > > +
> > > > +       priv->pll5_params.pl5_intin = rate / MEGA;
> > >
> > > .round_rate() (and .determine_rate()) is used to check if a rate is
> > > supported, without actually changing the clock rate.  Hence this
> > > should not operate on priv->pll5_params, but on a local variable.
> > >
> > > > +       priv->pll5_params.pl5_fracin = ((rate % MEGA) << 24) / MEGA;
> > > > +       priv->pll5_params.pl5_refdiv = 2;
> > > > +       priv->pll5_params.pl5_postdiv1 = 1;
> > > > +       priv->pll5_params.pl5_postdiv2 = 1;
> > > > +       priv->pll5_params.clksrc = 1;
> > > > +       priv->pll5_params.dsi_div_a = 1;
> > > > +       priv->pll5_params.dsi_div_b = 2;
> > > > +
> > > > +       priv->pll5_params.frequency =
> > > > +               EXTAL_FREQ_IN_MEGA_HZ * MEGA / priv-
> > > >pll5_params.pl5_refdiv *
> > > > +               ((((priv->pll5_params.pl5_intin << 24) + priv-
> > > >pll5_params.pl5_fracin)) >> 24) /
> > > > +               (priv->pll5_params.pl5_postdiv1 *
> > > > + priv->pll5_params.pl5_postdiv2);
> > > > +
> > > > +       if (priv->pll5_params.clksrc)
> > > > +               priv->pll5_params.frequency /= 2;
> > > > +
> > > > +       *parent_rate = priv->pll5_params.frequency;
> > > > +
> > > > +       return dsi_div->rate;
> > > > +}
> > > > +
> > > > +static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
> > > > +                                     unsigned long rate,
> > > > +                                     unsigned long parent_rate) {
> > > > +       struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
> > > > +       struct rzg2l_cpg_priv *priv = dsi_div->priv;
> > > > +
> > >
> > > You should update priv->pll5_params here, instead of in your
> > > .round_rate() callback.
> >
> > I need to find parent_rate based on video clock during
> > {determine,round rate}
> 
> There is no guarantee that .set_rate() is called right after
> .determine_rate() with the exact same parameters, or that it is called at
> all. Modifying priv->pll5_params prematurely may affect the other clocks
> in hard to debug ways.  So please modify priv->pll5_params only when
> actually setting the clock rate.

OK will do this change in next version.
> 
> > I have added there to avoid duplication.
> 
> You can use a helper that takes a pointer to a struct rzg2l_pll5_param,
> calculates the values, and fills them in.
> .{determine,round rate}() would call it with a pointer to a local
> variable.
> .set_rate() would call it with a pointer to &priv->pll5_params.

OK. Will send these changes in next version 

Cheers,
Biju
diff mbox series

Patch

diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index f8e177ef3f93..6e52cdd1cffe 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -27,6 +27,7 @@ 
 #include <linux/pm_domain.h>
 #include <linux/reset-controller.h>
 #include <linux/slab.h>
+#include <linux/units.h>
 
 #include <dt-bindings/clock/renesas-cpg-mssr.h>
 
@@ -72,6 +73,8 @@  struct rzg2l_pll5_param {
 	u8 pl5_postdiv1;
 	u8 pl5_postdiv2;
 	u8 clksrc;
+	u8 dsi_div_a;
+	u8 dsi_div_b;
 };
 
 /**
@@ -279,6 +282,114 @@  rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core,
 	return clk_hw->clk;
 }
 
+struct dsi_div_hw_data {
+	struct clk_hw hw;
+	u32 conf;
+	unsigned long rate;
+	struct rzg2l_cpg_priv *priv;
+};
+
+#define to_dsi_div_hw_data(_hw)	container_of(_hw, struct dsi_div_hw_data, hw)
+
+static unsigned long rzg2l_cpg_dsi_div_recalc_rate(struct clk_hw *hw,
+						   unsigned long parent_rate)
+{
+	struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
+
+	return dsi_div->rate;
+}
+
+static long rzg2l_cpg_dsi_div_round_rate(struct clk_hw *hw,
+					 unsigned long rate,
+					 unsigned long *parent_rate)
+
+{
+	struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
+	struct rzg2l_cpg_priv *priv = dsi_div->priv;
+
+	dsi_div->rate = rate;
+
+	priv->pll5_params.pl5_intin = rate / MEGA;
+	priv->pll5_params.pl5_fracin = ((rate % MEGA) << 24) / MEGA;
+	priv->pll5_params.pl5_refdiv = 2;
+	priv->pll5_params.pl5_postdiv1 = 1;
+	priv->pll5_params.pl5_postdiv2 = 1;
+	priv->pll5_params.clksrc = 1;
+	priv->pll5_params.dsi_div_a = 1;
+	priv->pll5_params.dsi_div_b = 2;
+
+	priv->pll5_params.frequency =
+		EXTAL_FREQ_IN_MEGA_HZ * MEGA / priv->pll5_params.pl5_refdiv *
+		((((priv->pll5_params.pl5_intin << 24) + priv->pll5_params.pl5_fracin)) >> 24) /
+		(priv->pll5_params.pl5_postdiv1 * priv->pll5_params.pl5_postdiv2);
+
+	if (priv->pll5_params.clksrc)
+		priv->pll5_params.frequency /= 2;
+
+	*parent_rate = priv->pll5_params.frequency;
+
+	return dsi_div->rate;
+}
+
+static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
+				      unsigned long rate,
+				      unsigned long parent_rate)
+{
+	struct dsi_div_hw_data *dsi_div = to_dsi_div_hw_data(hw);
+	struct rzg2l_cpg_priv *priv = dsi_div->priv;
+
+	writel(CPG_PL5_SDIV_DIV_DSI_A_WEN | CPG_PL5_SDIV_DIV_DSI_B_WEN |
+	       (priv->pll5_params.dsi_div_a << 0) | (priv->pll5_params.dsi_div_b << 8),
+	       priv->base + CPG_PL5_SDIV);
+
+	return 0;
+}
+
+static const struct clk_ops rzg2l_cpg_dsi_div_ops = {
+	.recalc_rate = rzg2l_cpg_dsi_div_recalc_rate,
+	.round_rate = rzg2l_cpg_dsi_div_round_rate,
+	.set_rate = rzg2l_cpg_dsi_div_set_rate,
+};
+
+static struct clk * __init
+rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core,
+			       struct clk **clks,
+			       struct rzg2l_cpg_priv *priv)
+{
+	struct dsi_div_hw_data *clk_hw_data;
+	const struct clk *parent;
+	const char *parent_name;
+	struct clk_init_data init;
+	struct clk_hw *clk_hw;
+	int ret;
+
+	parent = clks[core->parent & 0xffff];
+	if (IS_ERR(parent))
+		return ERR_CAST(parent);
+
+	clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL);
+	if (!clk_hw_data)
+		return ERR_PTR(-ENOMEM);
+
+	clk_hw_data->priv = priv;
+
+	parent_name = __clk_get_name(parent);
+	init.name = core->name;
+	init.ops = &rzg2l_cpg_dsi_div_ops;
+	init.flags = CLK_SET_RATE_PARENT;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	clk_hw = &clk_hw_data->hw;
+	clk_hw->init = &init;
+
+	ret = devm_clk_hw_register(priv->dev, clk_hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return clk_hw->clk;
+}
+
 struct pll5_mux_hw_data {
 	struct clk_hw hw;
 	u32 conf;
@@ -654,6 +765,9 @@  rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
 	case CLK_TYPE_PLL5_4_MUX:
 		clk = rzg2l_cpg_pll5_4_mux_clk_register(core, priv);
 		break;
+	case CLK_TYPE_DSI_DIV:
+		clk = rzg2l_cpg_dsi_div_clk_register(core, priv->clks, priv);
+		break;
 	default:
 		goto fail;
 	}
diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h
index a4bdc1d7b5aa..c75db039b444 100644
--- a/drivers/clk/renesas/rzg2l-cpg.h
+++ b/drivers/clk/renesas/rzg2l-cpg.h
@@ -24,6 +24,7 @@ 
 #define CPG_PL3_SSEL		(0x408)
 #define CPG_PL6_SSEL		(0x414)
 #define CPG_PL6_ETH_SSEL	(0x418)
+#define CPG_PL5_SDIV		(0x420)
 #define CPG_OTHERFUNC1_REG	(0xBE8)
 
 #define CPG_SIPLL5_STBY_RESETB		BIT(0)
@@ -37,6 +38,11 @@ 
 
 #define CPG_OTHERFUNC1_REG_RES0_ON_WEN	BIT(16)
 
+#define CPG_PL5_SDIV_DIV_DSI_A_WEN	BIT(16)
+#define CPG_PL5_SDIV_DIV_DSI_B_WEN	BIT(24)
+
+#define EXTAL_FREQ_IN_MEGA_HZ		(24)
+
 #define CPG_CLKSTATUS_SELSDHI0_STS	BIT(28)
 #define CPG_CLKSTATUS_SELSDHI1_STS	BIT(29)
 
@@ -52,6 +58,7 @@ 
 		(((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
 #define DIVPL1A		DDIV_PACK(CPG_PL1_DDIV, 0, 2)
 #define DIVPL2A		DDIV_PACK(CPG_PL2_DDIV, 0, 3)
+#define DIVDSILPCLK	DDIV_PACK(CPG_PL2_DDIV, 12, 2)
 #define DIVPL3A		DDIV_PACK(CPG_PL3A_DDIV, 0, 3)
 #define DIVPL3B		DDIV_PACK(CPG_PL3A_DDIV, 4, 3)
 #define DIVPL3C		DDIV_PACK(CPG_PL3A_DDIV, 8, 3)
@@ -111,6 +118,10 @@  enum clk_types {
 
 	/* Clock for PLL5_4 clock source selector */
 	CLK_TYPE_PLL5_4_MUX,
+
+	/* Clock for DSI divider */
+	CLK_TYPE_DSI_DIV,
+
 };
 
 #define DEF_TYPE(_name, _id, _type...) \
@@ -139,6 +150,8 @@  enum clk_types {
 #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names, _num_parents) \
 	DEF_TYPE(_name, _id, CLK_TYPE_PLL5_4_MUX, .conf = _conf, \
 		 .parent_names = _parent_names, .num_parents = _num_parents)
+#define DEF_DSI_DIV(_name, _id, _parent, _flag) \
+	DEF_TYPE(_name, _id, CLK_TYPE_DSI_DIV, .parent = _parent, .flag = _flag)
 
 /**
  * struct rzg2l_mod_clk - Module Clocks definitions