[PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support

Tommaso Merciai posted 22 patches 2 months, 2 weeks ago
There is a newer version of this series
[PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Tommaso Merciai 2 months, 2 weeks ago
Add PLLDSI clk mux support to select PLLDSI clock from different clock
sources.

Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
them in the clock driver.

Extend the determine_rate callback to calculate and propagate PLL
parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/clk/renesas/rzv2h-cpg.c | 131 ++++++++++++++++++++++++++++++++
 drivers/clk/renesas/rzv2h-cpg.h |   8 ++
 2 files changed, 139 insertions(+)

diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index 3f6299b9fec0..dd782fa269d7 100644
--- a/drivers/clk/renesas/rzv2h-cpg.c
+++ b/drivers/clk/renesas/rzv2h-cpg.c
@@ -418,6 +418,20 @@ bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
 }
 EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_divs_pars, "RZV2H_CPG");
 
+/**
+ * struct rzv2h_plldsi_mux_clk - PLL DSI MUX clock
+ *
+ * @priv: CPG private data
+ * @mux: mux clk
+ */
+struct rzv2h_plldsi_mux_clk {
+	struct rzv2h_cpg_priv *priv;
+	struct clk_mux mux;
+};
+
+#define to_plldsi_clk_mux(_mux) \
+	container_of(_mux, struct rzv2h_plldsi_mux_clk, mux)
+
 static unsigned long rzv2h_cpg_plldsi_div_recalc_rate(struct clk_hw *hw,
 						      unsigned long parent_rate)
 {
@@ -649,6 +663,120 @@ static int rzv2h_cpg_plldsi_set_rate(struct clk_hw *hw, unsigned long rate,
 	return rzv2h_cpg_pll_set_rate(pll_clk, &dsi_info->pll_dsi_parameters.pll, true);
 }
 
+static u8 rzv2h_cpg_plldsi_smux_get_parent(struct clk_hw *hw)
+{
+	return clk_mux_ops.get_parent(hw);
+}
+
+static int rzv2h_cpg_plldsi_smux_set_parent(struct clk_hw *hw, u8 index)
+{
+	return clk_mux_ops.set_parent(hw, index);
+}
+
+static int rzv2h_cpg_plldsi_smux_lvds_determine_rate(struct rzv2h_cpg_priv *priv,
+						     struct pll_clk *pll_clk,
+						     struct clk_rate_request *req)
+{
+	struct rzv2h_pll_div_pars *dsi_params;
+	struct rzv2h_pll_dsi_info *dsi_info;
+	u8 lvds_table[] = { 7 };
+	u64 rate_millihz;
+
+	dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance];
+	dsi_params = &dsi_info->pll_dsi_parameters;
+
+	rate_millihz = mul_u32_u32(req->rate, MILLI);
+	if (!rzv2h_get_pll_divs_pars(dsi_info->pll_dsi_limits, dsi_params,
+				     lvds_table, 1, rate_millihz)) {
+		dev_err(priv->dev, "failed to determine rate for req->rate: %lu\n",
+			req->rate);
+		return -EINVAL;
+	}
+
+	req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params->div.freq_millihz, MILLI);
+	req->best_parent_rate = req->rate;
+	dsi_info->req_pll_dsi_rate = req->best_parent_rate * dsi_params->div.divider_value;
+
+	return 0;
+}
+
+static int rzv2h_cpg_plldsi_smux_determine_rate(struct clk_hw *hw,
+						struct clk_rate_request *req)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	struct rzv2h_plldsi_mux_clk *dsi_mux = to_plldsi_clk_mux(mux);
+	struct pll_clk *pll_clk = to_pll(clk_hw_get_parent(hw));
+	struct rzv2h_cpg_priv *priv = dsi_mux->priv;
+	int ret;
+
+	/*
+	 * For LVDS output (parent_idx == 0), calculate PLL parameters with
+	 * fixed divider value of 7. For DSI/RGB output (parent_idx == 1) skip
+	 * PLL calculation here as it's handled by determine_rate of the
+	 * divider (up one level).
+	 */
+	if (!clk_mux_ops.get_parent(hw))
+		ret = rzv2h_cpg_plldsi_smux_lvds_determine_rate(priv, pll_clk, req);
+	else
+		ret = clk_mux_determine_rate_flags(hw, req, mux->flags);
+
+	return ret;
+}
+
+static const struct clk_ops rzv2h_cpg_plldsi_smux_ops = {
+	.determine_rate = rzv2h_cpg_plldsi_smux_determine_rate,
+	.get_parent = rzv2h_cpg_plldsi_smux_get_parent,
+	.set_parent = rzv2h_cpg_plldsi_smux_set_parent,
+};
+
+static struct clk * __init
+rzv2h_cpg_plldsi_smux_clk_register(const struct cpg_core_clk *core,
+				   struct rzv2h_cpg_priv *priv)
+{
+	struct rzv2h_plldsi_mux_clk *clk_hw_data;
+	struct clk_init_data init;
+	struct clk_hw *clk_hw;
+	struct smuxed smux;
+	u8 width;
+	int ret;
+
+	smux = core->cfg.smux;
+	width = fls(smux.width) - ffs(smux.width) + 1;
+
+	if (width + smux.width > 16) {
+		dev_err(priv->dev, "mux value exceeds LOWORD field\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	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;
+
+	init.name = core->name;
+	init.ops = &rzv2h_cpg_plldsi_smux_ops;
+	init.flags = core->flag;
+	init.parent_names = core->parent_names;
+	init.num_parents = core->num_parents;
+
+	clk_hw_data->mux.reg = priv->base + smux.offset;
+
+	clk_hw_data->mux.shift = smux.shift;
+	clk_hw_data->mux.mask = smux.width;
+	clk_hw_data->mux.flags = core->mux_flags;
+	clk_hw_data->mux.lock = &priv->rmw_lock;
+
+	clk_hw = &clk_hw_data->mux.hw;
+	clk_hw->init = &init;
+
+	ret = devm_clk_hw_register(priv->dev, clk_hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return clk_hw->clk;
+}
+
 static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
 {
 	struct pll_clk *pll_clk = to_pll(hw);
@@ -1085,6 +1213,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
 	case CLK_TYPE_PLLDSI_DIV:
 		clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
 		break;
+	case CLK_TYPE_PLLDSI_SMUX:
+		clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
+		break;
 	default:
 		goto fail;
 	}
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index dc957bdaf5e9..5f6e775612e7 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -203,6 +203,7 @@ enum clk_types {
 	CLK_TYPE_SMUX,		/* Static Mux */
 	CLK_TYPE_PLLDSI,	/* PLLDSI */
 	CLK_TYPE_PLLDSI_DIV,	/* PLLDSI divider */
+	CLK_TYPE_PLLDSI_SMUX,	/* PLLDSI Static Mux */
 };
 
 #define DEF_TYPE(_name, _id, _type...) \
@@ -241,6 +242,13 @@ enum clk_types {
 		 .dtable = _dtable, \
 		 .parent = _parent, \
 		 .flag = CLK_SET_RATE_PARENT)
+#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
+	DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
+		 .cfg.smux = _smux_packed, \
+		 .parent_names = _parent_names, \
+		 .num_parents = ARRAY_SIZE(_parent_names), \
+		 .flag = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, \
+		 .mux_flags = CLK_MUX_HIWORD_MASK)
 
 /**
  * struct rzv2h_mod_clk - Module Clocks definitions
-- 
2.43.0
Re: [PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Geert Uytterhoeven 3 weeks, 5 days ago
Hi Tommaso,

On Wed, 26 Nov 2025 at 15:08, Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
> Add PLLDSI clk mux support to select PLLDSI clock from different clock
> sources.
>
> Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
> them in the clock driver.
>
> Extend the determine_rate callback to calculate and propagate PLL
> parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
> using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

Thanks for your patch!

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

> +
> +static int rzv2h_cpg_plldsi_smux_lvds_determine_rate(struct rzv2h_cpg_priv *priv,
> +                                                    struct pll_clk *pll_clk,
> +                                                    struct clk_rate_request *req)
> +{
> +       struct rzv2h_pll_div_pars *dsi_params;
> +       struct rzv2h_pll_dsi_info *dsi_info;
> +       u8 lvds_table[] = { 7 };
> +       u64 rate_millihz;
> +
> +       dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance];
> +       dsi_params = &dsi_info->pll_dsi_parameters;
> +
> +       rate_millihz = mul_u32_u32(req->rate, MILLI);
> +       if (!rzv2h_get_pll_divs_pars(dsi_info->pll_dsi_limits, dsi_params,
> +                                    lvds_table, 1, rate_millihz)) {

s/1/ARRAY_SIZE(lvds_table)/

> +               dev_err(priv->dev, "failed to determine rate for req->rate: %lu\n",
> +                       req->rate);
> +               return -EINVAL;
> +       }
> +
> +       req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params->div.freq_millihz, MILLI);
> +       req->best_parent_rate = req->rate;
> +       dsi_info->req_pll_dsi_rate = req->best_parent_rate * dsi_params->div.divider_value;
> +
> +       return 0;
> +}

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
Re: [PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Geert Uytterhoeven 1 month ago
Hi Tommaso,

On Wed, 26 Nov 2025 at 15:08, Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
> Add PLLDSI clk mux support to select PLLDSI clock from different clock
> sources.
>
> Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
> them in the clock driver.
>
> Extend the determine_rate callback to calculate and propagate PLL
> parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
> using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

Thanks for your patch!

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

[...]

>  static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
>  {
>         struct pll_clk *pll_clk = to_pll(hw);
> @@ -1085,6 +1213,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
>         case CLK_TYPE_PLLDSI_DIV:
>                 clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
>                 break;
> +       case CLK_TYPE_PLLDSI_SMUX:
> +               clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
> +               break;
>         default:
>                 goto fail;
>         }
> diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
> index dc957bdaf5e9..5f6e775612e7 100644
> --- a/drivers/clk/renesas/rzv2h-cpg.h
> +++ b/drivers/clk/renesas/rzv2h-cpg.h
> @@ -203,6 +203,7 @@ enum clk_types {
>         CLK_TYPE_SMUX,          /* Static Mux */
>         CLK_TYPE_PLLDSI,        /* PLLDSI */
>         CLK_TYPE_PLLDSI_DIV,    /* PLLDSI divider */
> +       CLK_TYPE_PLLDSI_SMUX,   /* PLLDSI Static Mux */
>  };
>
>  #define DEF_TYPE(_name, _id, _type...) \
> @@ -241,6 +242,13 @@ enum clk_types {
>                  .dtable = _dtable, \
>                  .parent = _parent, \
>                  .flag = CLK_SET_RATE_PARENT)
> +#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
> +       DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
> +                .cfg.smux = _smux_packed, \
> +                .parent_names = _parent_names, \
> +                .num_parents = ARRAY_SIZE(_parent_names), \
> +                .flag = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, \
> +                .mux_flags = CLK_MUX_HIWORD_MASK)
>
>  /**
>   * struct rzv2h_mod_clk - Module Clocks definitions

Why do you need a completely new clock type, and can't you just use
the existing CLK_TYPE_SMUX?

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
Re: [PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Tommaso Merciai 4 weeks ago
Hi Geert,
Thanks for your review!

On Fri, Jan 09, 2026 at 07:27:04PM +0100, Geert Uytterhoeven wrote:
> Hi Tommaso,
> 
> On Wed, 26 Nov 2025 at 15:08, Tommaso Merciai
> <tommaso.merciai.xr@bp.renesas.com> wrote:
> > Add PLLDSI clk mux support to select PLLDSI clock from different clock
> > sources.
> >
> > Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
> > them in the clock driver.
> >
> > Extend the determine_rate callback to calculate and propagate PLL
> > parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
> > using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().
> >
> > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> 
> Thanks for your patch!
> 
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
> 
> [...]
> 
> >  static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
> >  {
> >         struct pll_clk *pll_clk = to_pll(hw);
> > @@ -1085,6 +1213,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
> >         case CLK_TYPE_PLLDSI_DIV:
> >                 clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
> >                 break;
> > +       case CLK_TYPE_PLLDSI_SMUX:
> > +               clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
> > +               break;
> >         default:
> >                 goto fail;
> >         }
> > diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
> > index dc957bdaf5e9..5f6e775612e7 100644
> > --- a/drivers/clk/renesas/rzv2h-cpg.h
> > +++ b/drivers/clk/renesas/rzv2h-cpg.h
> > @@ -203,6 +203,7 @@ enum clk_types {
> >         CLK_TYPE_SMUX,          /* Static Mux */
> >         CLK_TYPE_PLLDSI,        /* PLLDSI */
> >         CLK_TYPE_PLLDSI_DIV,    /* PLLDSI divider */
> > +       CLK_TYPE_PLLDSI_SMUX,   /* PLLDSI Static Mux */
> >  };
> >
> >  #define DEF_TYPE(_name, _id, _type...) \
> > @@ -241,6 +242,13 @@ enum clk_types {
> >                  .dtable = _dtable, \
> >                  .parent = _parent, \
> >                  .flag = CLK_SET_RATE_PARENT)
> > +#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
> > +       DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
> > +                .cfg.smux = _smux_packed, \
> > +                .parent_names = _parent_names, \
> > +                .num_parents = ARRAY_SIZE(_parent_names), \
> > +                .flag = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, \
> > +                .mux_flags = CLK_MUX_HIWORD_MASK)
> >
> >  /**
> >   * struct rzv2h_mod_clk - Module Clocks definitions
> 
> Why do you need a completely new clock type, and can't you just use
> the existing CLK_TYPE_SMUX?

From reference manual (Table 4.4-10 Specifications of the CPG_SSELm
Registers)

We have the following:

 - SMUX2_DSI0_CLK*2
	0b: CDIV7_DSI0_CLK (default)
	1b: CSDIV_2to16_PLLDSI0

 - SMUX2_DSI1_CLK*2
	0b: CDIV7_DSI1_CLK (default)
	1b: CSDIV_2to16_PLLDSI1

Note 2.If LVDS0 / LVDS1 is used, be sure to set 0b.

For this reason these clocks needs an ad hoc determine_rate function:
	- rzv2h_cpg_plldsi_smux_determine_rate()

For that CLK_TYPE_PLLDSI_SMUX has been introduced.
What do you think?

Thanks & Regards,
Tommaso


> 
> 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
Re: [PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Geert Uytterhoeven 3 weeks, 5 days ago
Hi Tommaso,

On Mon, 12 Jan 2026 at 09:13, Tommaso Merciai
<tommaso.merciai.xr@bp.renesas.com> wrote:
> On Fri, Jan 09, 2026 at 07:27:04PM +0100, Geert Uytterhoeven wrote:
> > On Wed, 26 Nov 2025 at 15:08, Tommaso Merciai
> > <tommaso.merciai.xr@bp.renesas.com> wrote:
> > > Add PLLDSI clk mux support to select PLLDSI clock from different clock
> > > sources.
> > >
> > > Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
> > > them in the clock driver.
> > >
> > > Extend the determine_rate callback to calculate and propagate PLL
> > > parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
> > > using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().
> > >
> > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> >
> > Thanks for your patch!
> >
> > > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > > +++ b/drivers/clk/renesas/rzv2h-cpg.c
> >
> > [...]
> >
> > >  static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
> > >  {
> > >         struct pll_clk *pll_clk = to_pll(hw);
> > > @@ -1085,6 +1213,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
> > >         case CLK_TYPE_PLLDSI_DIV:
> > >                 clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
> > >                 break;
> > > +       case CLK_TYPE_PLLDSI_SMUX:
> > > +               clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
> > > +               break;
> > >         default:
> > >                 goto fail;
> > >         }
> > > diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
> > > index dc957bdaf5e9..5f6e775612e7 100644
> > > --- a/drivers/clk/renesas/rzv2h-cpg.h
> > > +++ b/drivers/clk/renesas/rzv2h-cpg.h
> > > @@ -203,6 +203,7 @@ enum clk_types {
> > >         CLK_TYPE_SMUX,          /* Static Mux */
> > >         CLK_TYPE_PLLDSI,        /* PLLDSI */
> > >         CLK_TYPE_PLLDSI_DIV,    /* PLLDSI divider */
> > > +       CLK_TYPE_PLLDSI_SMUX,   /* PLLDSI Static Mux */
> > >  };
> > >
> > >  #define DEF_TYPE(_name, _id, _type...) \
> > > @@ -241,6 +242,13 @@ enum clk_types {
> > >                  .dtable = _dtable, \
> > >                  .parent = _parent, \
> > >                  .flag = CLK_SET_RATE_PARENT)
> > > +#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
> > > +       DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
> > > +                .cfg.smux = _smux_packed, \
> > > +                .parent_names = _parent_names, \
> > > +                .num_parents = ARRAY_SIZE(_parent_names), \
> > > +                .flag = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, \
> > > +                .mux_flags = CLK_MUX_HIWORD_MASK)
> > >
> > >  /**
> > >   * struct rzv2h_mod_clk - Module Clocks definitions
> >
> > Why do you need a completely new clock type, and can't you just use
> > the existing CLK_TYPE_SMUX?
>
> From reference manual (Table 4.4-10 Specifications of the CPG_SSELm
> Registers)
>
> We have the following:
>
>  - SMUX2_DSI0_CLK*2
>         0b: CDIV7_DSI0_CLK (default)
>         1b: CSDIV_2to16_PLLDSI0
>
>  - SMUX2_DSI1_CLK*2
>         0b: CDIV7_DSI1_CLK (default)
>         1b: CSDIV_2to16_PLLDSI1
>
> Note 2.If LVDS0 / LVDS1 is used, be sure to set 0b.
>
> For this reason these clocks needs an ad hoc determine_rate function:
>         - rzv2h_cpg_plldsi_smux_determine_rate()
>
> For that CLK_TYPE_PLLDSI_SMUX has been introduced.
> What do you think?

OK, your solution sounds good to me.  Still, as this is used from the
DRM driver, I would like to get some feedback from the DRM people, too.

BTW, I just noticed in the RZ/G3E clock system diagram that
CDIV7_DSI0_CLK has a duty cycle "DUTY H/L=4/3", while all other clocks
use the symmetrical 50%.  Perhaps the DRM driver can request a duty
cycle of 4/7 when using LVDS? Currently the DRM driver communicates
its requirements by explicitly setting the parent.

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
Re: [PATCH 01/22] clk: renesas: rzv2h: Add PLLDSI clk mux support
Posted by Tommaso Merciai 2 weeks, 3 days ago
Hi Geert,
Thanks for your comment.

On Wed, Jan 14, 2026 at 02:07:49PM +0100, Geert Uytterhoeven wrote:
> Hi Tommaso,
> 
> On Mon, 12 Jan 2026 at 09:13, Tommaso Merciai
> <tommaso.merciai.xr@bp.renesas.com> wrote:
> > On Fri, Jan 09, 2026 at 07:27:04PM +0100, Geert Uytterhoeven wrote:
> > > On Wed, 26 Nov 2025 at 15:08, Tommaso Merciai
> > > <tommaso.merciai.xr@bp.renesas.com> wrote:
> > > > Add PLLDSI clk mux support to select PLLDSI clock from different clock
> > > > sources.
> > > >
> > > > Introduce the DEF_PLLDSI_SMUX() macro to define these muxes and register
> > > > them in the clock driver.
> > > >
> > > > Extend the determine_rate callback to calculate and propagate PLL
> > > > parameters via rzv2h_get_pll_dtable_pars() when LVDS output is selected,
> > > > using a new helper function rzv2h_cpg_plldsi_smux_lvds_determine_rate().
> > > >
> > > > Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> > >
> > > Thanks for your patch!
> > >
> > > > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > > > +++ b/drivers/clk/renesas/rzv2h-cpg.c
> > >
> > > [...]
> > >
> > > >  static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
> > > >  {
> > > >         struct pll_clk *pll_clk = to_pll(hw);
> > > > @@ -1085,6 +1213,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
> > > >         case CLK_TYPE_PLLDSI_DIV:
> > > >                 clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
> > > >                 break;
> > > > +       case CLK_TYPE_PLLDSI_SMUX:
> > > > +               clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
> > > > +               break;
> > > >         default:
> > > >                 goto fail;
> > > >         }
> > > > diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
> > > > index dc957bdaf5e9..5f6e775612e7 100644
> > > > --- a/drivers/clk/renesas/rzv2h-cpg.h
> > > > +++ b/drivers/clk/renesas/rzv2h-cpg.h
> > > > @@ -203,6 +203,7 @@ enum clk_types {
> > > >         CLK_TYPE_SMUX,          /* Static Mux */
> > > >         CLK_TYPE_PLLDSI,        /* PLLDSI */
> > > >         CLK_TYPE_PLLDSI_DIV,    /* PLLDSI divider */
> > > > +       CLK_TYPE_PLLDSI_SMUX,   /* PLLDSI Static Mux */
> > > >  };
> > > >
> > > >  #define DEF_TYPE(_name, _id, _type...) \
> > > > @@ -241,6 +242,13 @@ enum clk_types {
> > > >                  .dtable = _dtable, \
> > > >                  .parent = _parent, \
> > > >                  .flag = CLK_SET_RATE_PARENT)
> > > > +#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
> > > > +       DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
> > > > +                .cfg.smux = _smux_packed, \
> > > > +                .parent_names = _parent_names, \
> > > > +                .num_parents = ARRAY_SIZE(_parent_names), \
> > > > +                .flag = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, \
> > > > +                .mux_flags = CLK_MUX_HIWORD_MASK)
> > > >
> > > >  /**
> > > >   * struct rzv2h_mod_clk - Module Clocks definitions
> > >
> > > Why do you need a completely new clock type, and can't you just use
> > > the existing CLK_TYPE_SMUX?
> >
> > From reference manual (Table 4.4-10 Specifications of the CPG_SSELm
> > Registers)
> >
> > We have the following:
> >
> >  - SMUX2_DSI0_CLK*2
> >         0b: CDIV7_DSI0_CLK (default)
> >         1b: CSDIV_2to16_PLLDSI0
> >
> >  - SMUX2_DSI1_CLK*2
> >         0b: CDIV7_DSI1_CLK (default)
> >         1b: CSDIV_2to16_PLLDSI1
> >
> > Note 2.If LVDS0 / LVDS1 is used, be sure to set 0b.
> >
> > For this reason these clocks needs an ad hoc determine_rate function:
> >         - rzv2h_cpg_plldsi_smux_determine_rate()
> >
> > For that CLK_TYPE_PLLDSI_SMUX has been introduced.
> > What do you think?
> 
> OK, your solution sounds good to me.  Still, as this is used from the
> DRM driver, I would like to get some feedback from the DRM people, too.
> 
> BTW, I just noticed in the RZ/G3E clock system diagram that
> CDIV7_DSI0_CLK has a duty cycle "DUTY H/L=4/3", while all other clocks
> use the symmetrical 50%.  Perhaps the DRM driver can request a duty
> cycle of 4/7 when using LVDS? Currently the DRM driver communicates
> its requirements by explicitly setting the parent.

Based on your idea we can add at cpg lvl:

	.get_duty_cycle = rzv2h_cpg_plldsi_smux_get_duty_cycle,
	.set_duty_cycle = rzv2h_cpg_plldsi_smux_set_duty_cycle,

That select parent based on requested duty cycle:

  - If duty > 50% (num/den > 1/2), select LVDS path (parent 0)
  - Otherwise, select DSI/RGB path (parent 1)

Then at DRM lvl we can go for:

	if (rzg2l_du_has(rcdu, RG2L_DU_FEATURE_SMUX2_DSI_CLK)) {
	    struct clk *clk_parent;

	    clk_parent = clk_get_parent(rcrtc->rzg2l_clocks.dclk);

	    /*
	     * Request appropriate duty cycle to let clock driver select
	     * the correct parent:
	     * - CDIV7_DSIx_CLK (LVDS path) has DUTY H/L=4/3, 4/7 duty cycle.
	     * - CSDIV_2to16_PLLDSIx (DSI/RGB path) has symmetric 50% duty cycle.
	     */
	    if (rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS0) ||
    		rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS1))
	      clk_set_duty_cycle(clk_parent, 4, 7);
	    else
	      clk_set_duty_cycle(clk_parent, 1, 2);
	  }

What do you think? Please correct me if I'm wrong.
Glad to hear from Laurent's input too.

Thank you both in advance.

Kind Regards,
Tommaso


> 
> 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
>