RE: [PATCH 2/6] clk: renesas: rzg2l: Add PLL7 DSI clock support for RZ/G3L
Biju Das <[email protected]> Mon, 27 Jul 2026 19:05:18 +0000
| Newsgroups | org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-clk,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <TY3PR01MB11346D51CFA3114C1F336D9B286CC2@TY3PR01MB11346.jpnprd01.prod.outlook.com> |
Hi Geert, Thanks for the feedback. > -----Original Message----- > From: Geert Uytterhoeven <[email protected]> > Sent: 10 July 2026 16:39 > Subject: Re: [PATCH 2/6] clk: renesas: rzg2l: Add PLL7 DSI clock support for RZ/G3L > > Hi Biju, > > On Fri, 19 Jun 2026 at 18:40, Biju <[email protected]> wrote: > > From: Biju Das <[email protected]> > > > > Add a new fractional PLL clock type (CLK_TYPE_G3L_PLLDSI) for the > > RZ/G3L SoC's PLL7, which drives the DSI interface and requires a > > dedicated parameter calculation and programming sequence distinct from > > other PLLs in the RZ/G2L family. > > > > PLL7 output frequency is determined by the formula: > > > > Ffdco = (NIR + NFR / 4096) * (Fosc / MR) > > Ffout = Ffdco / (1 << PR) > > > > where: > > - Fosc = 24 MHz (oscillator input) > > - PR in [0, 4] (post divider, power-of-two) > > - MR in [1, 12] (input pre-divider) > > - NIR in [56, 375], NFR in [0, 4095] (integer and fractional parts) > > > > The FDCO must fall within one of two valid ranges: 900–2000 MHz > > (rangesel=0) or 2000–3000 MHz (rangesel=1). > > > > The parameter search in rzg3l_dsi_get_pll_parameters_values() iterates > > over all valid (MR, PR) combinations, filtering by the required FPFD > > range of 8–16 MHz, then delegates to > > rzg3l_dsi_compute_pll_parameters() to find the NIR/NFR pair that best > > approximates the requested rate. An exact match returns immediately; > > otherwise the combination with the smallest absolute frequency error is used. > > > > Computed parameters are cached in pll7_dsi_params within pll_clk to > > avoid redundant recalculation in determine_rate() when the requested > > rate has not changed. > > > > Signed-off-by: Biju Das <[email protected]> > > Thanks for your patch! > > > > --- a/drivers/clk/renesas/rzg2l-cpg.c > > +++ b/drivers/clk/renesas/rzg2l-cpg.c > > @@ -67,6 +67,10 @@ > > #define CPG_PLL_MON_OFFSET(x) (CPG_PLL_STBY_OFFSET(x) + 0xc) > > #define CPG_PLL_MON_LOCK BIT(4) > > #define CPG_PLL_MON_RESETB BIT(0) > > +#define CPG_PLL_CLK1_VAL(p, m, ni, nf, sel) (FIELD_PREP(GENMASK(28, 26), p) | \ > > + FIELD_PREP(GENMASK(25, 22), m) | \ > > + FIELD_PREP(GENMASK(21, 13), ni) | \ > > + > > +FIELD_PREP(GENMASK(12, 1), nf) | (sel)) > > What about dropping CPG_PLL_CLK1_VAL(), defining > > #define CPG_PLL_CLK1_DIV_NF GENMASK(12, 1) > #define CPG_PLL_CLK1_DIV_NI GENMASK(21, 13) > ... > > and using FIELD_PREP(CPG_PLL_CLK1_DIV_NF, ...) | ..." at all callsites? OK. > > > > > #define RZG3L_SDIV_DIV_DSI_A_WEN BIT(16) > > #define RZG3L_SDIV_DIV_DSI_B_WEN BIT(20) > > @@ -96,6 +100,26 @@ > > #define PLL5_HSCLK_MIN 10000000 > > #define PLL5_HSCLK_MAX 187500000 > > > > +#define RZG3L_OSC_CLK (24 * MEGA) > > This is the clock rate of the external crystal. > As this must be 24 MHz on RZ/G3L, I guess it is OK to use a define for that. > > > +#define RZG3L_PLL7_FDCO_RANGE_0_MIN (900 * MEGA) > > +#define RZG3L_PLL7_FDCO_RANGE_0_MAX (2000 * MEGA) > > +#define RZG3L_PLL7_FDCO_RANGE_1_MIN (2000 * MEGA) > > +#define RZG3L_PLL7_FDCO_RANGE_1_MAX (3000ULL * MEGA) > > I didn't check the ranges yet. > Do you need the 87 MHz upper limit of LVDS somewhere? Not here. I believe 87MHz upper limit is to be taken care in LVDS bridge driver(mode_valid), same case for DSI and DPI. > > > +#define RZG3L_PLL7_PR_MIN (0) > > +#define RZG3L_PLL7_PR_MAX (4) > > +#define RZG3L_PLL7_MR_MIN (0) > > +#define RZG3L_PLL7_MR_MAX (11) > > +#define RZG3L_PLL7_NIR_MIN (55) > > +#define RZG3L_PLL7_NIR_MAX (374) > > +#define RZG3L_PLL7_NFR_MIN (0) > > +#define RZG3L_PLL7_NFR_MAX (4095) > > +#define RZG3L_PLL7_NR_MIN (56250) /* Multiplied value 56.25 * 1000 */ > > +#define RZG3L_PLL7_NR_MAX (375000) /* Multiplied value 375 * 1000 */ > > +#define RZG3L_PLL7_MULT_MIN (293) /* Multiplied value 0.293 * 1000 */ > > +#define RZG3L_PLL7_MULT_MAX (375000) /* Multiplied value 375 * 1000 */ > > +#define RZG3L_PLL7_FSTD_DIV_MR_MIN (8 * MEGA) > > +#define RZG3L_PLL7_FSTD_DIV_MR_MAX (16 * MEGA) > > + > > /** > > * struct clk_hw_data - clock hardware data > > * @hw: clock hw > > > @@ -1368,6 +1402,196 @@ static const struct clk_ops rzg3l_cpg_pll_ops = { > > .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, }; > > > > +static inline bool > > +rzg3l_dsi_compute_pll_parameters(struct rzg3l_plldsi_parameters *pars, > > + struct rzg3l_plldsi_parameters *p, > > + struct rzg3l_plldsi_parameters *best, > > + u64 freq_millihz, u32 fpfd, u32 pr) { > > + for (p->nir = RZG3L_PLL7_NIR_MIN; p->nir <= RZG3L_PLL7_NIR_MAX; p->nir++) { > > + u64 output_nir, output_nfr_range; > > + s64 nfr, output_nfr; > > + u64 fdco, output; > > + u64 nr_div_mr_pr; > > + > > + /* > > + * The frequency generated by the PLL is calculated as follows: > > + * > > + * With: > > + * Freq = Ffout = Ffdco / pr > > + * input frequency(fstd) = 24MHz > > + * fpfd = fstd / mr > > + * nr = nir + nfr / 4096 > > + * Ffdco = nr * fpfd > > + * Ffdco = (nir + (nfr / 4096)) * fpfd > > + * > > + * Freq can also be rewritten as: > > + * Freq = Ffdco / pr > > + * = (nir * fpfd) / pr + ((nfr / 4096) * fpfd) / pr > > + * = output_nir + output_nfr > > + * > > + * Every parameter has been determined at this point, but nfr. > > + * Considering that: > > + * 0 <= nfr <= 4095 > > + * Then: > > + * 0 <= (nfr / 4096) < 1 > > + * Therefore: > > + * 0 <= output_nfr < fpfd / pr > > + */ > > + > > + /* Compute output nir component (in mHz) */ > > + output_nir = DIV_ROUND_CLOSEST_ULL((p->nir + 1) * 1ULL > > + * fpfd * MILLI, pr); > > The multiplication with 1ULL to force 64-bit looks a bit odd. > As p->nir is small, perhaps mul_u32_u32((p->nir + 1) * MILLI, fpfd)? Agreed. > > > + /* Compute range for output nfr (in mHz) */ > > + output_nfr_range = DIV_ROUND_CLOSEST_ULL(fpfd * 1ULL * > > + MILLI, pr); > > mul_u32_u32(fpfd, MILLI) Agreed. > > > + /* No point in continuing if we can't achieve the desired frequency */ > > + if (freq_millihz < output_nir || freq_millihz >= (output_nir + output_nfr_range)) > > + continue; > > + > > + /* > > + * Compute the nfr component > > + * > > + * Since: > > + * Freq = output_nir + output_nfr > > + * Then: > > + * output_nfr = Freq - output_nir > > + * = ((nfr / 4096) * fpfd) / pr > > + * Therefore: > > + * nfr = (output_nfr * 4096 * pr) / fpfd > > + */ > > + output_nfr = freq_millihz - output_nir; > > + nfr = div64_s64(output_nfr * 4096ULL * pr, fpfd); > > No need for the ULL > fpfd is u32, so div_s64 is overkill, and div_s64 is sufficient. Agreed will use div_s64. > > > + nfr = DIV_S64_ROUND_CLOSEST(nfr, 1000); > > + > > + /* Validate nfr value within allowed limits */ > > + if (nfr < RZG3L_PLL7_NFR_MIN || nfr > RZG3L_PLL7_NFR_MAX) > > + continue; > > + > > + p->nfr = nfr; > > + > > + /* Compute (Ffdco * 4096) */ > > + fdco = (((p->nir + 1) * 4096ULL) + p->nfr) * fpfd; > > mul_u32_u32(p->nir + 1, 4096) Ok. > > > + if (fdco < (RZG3L_PLL7_FDCO_RANGE_0_MIN * 4096ULL) || > > + fdco > (RZG3L_PLL7_FDCO_RANGE_1_MAX * 4096ULL)) > > + continue; > > + > > + if (fdco <= (RZG3L_PLL7_FDCO_RANGE_0_MAX * 4096ULL)) > > + p->rangesel = 0; > > + else > > + p->rangesel = 1; > > + > > + /* compute the nr and magnify by 1000 */ > > + output = mul_u32_u32((p->nir + 1), 4096); > > Please move this up, and use it in the calculation of fdco above. Agreed. > > > + output += p->nfr; > > + output *= 1000; > > + nr_div_mr_pr = output / 4096; > > Open-coded 64-by-32 division, please use div_u64() instead. > Or >> 12. Ok will use div_u64(). > > mul_u64_add_u64_div_u64 (multiply, add, and divide) and mul_u64_u32_shr (multiply and shift) might also > be handy, somewhere... If you agree, will do this optimization later. > > > + if (nr_div_mr_pr < RZG3L_PLL7_NR_MIN || nr_div_mr_pr > RZG3L_PLL7_NR_MAX) > > + continue; > > + > > + /* compute the magnified multipier = nr(magnified)/(mr *pr) */ > > + nr_div_mr_pr /= (p->mr + 1) * pr; > > Open-coded 64-by-32 division, please use div_u64() instead. OK. Will use div_u64(). > > > + if (nr_div_mr_pr < RZG3L_PLL7_MULT_MIN || nr_div_mr_pr > RZG3L_PLL7_MULT_MAX) > > + continue; > > + > > + output *= RZG3L_OSC_CLK; > > + output /= (p->mr + 1) * pr * 4096; > > Open-coded 64-by-32 division. Or perhaps even 64-by-64? OK. Will use div_u64(). > > > + > > + p->error_millihz = freq_millihz - output; > > + p->freq_millihz = output; > > + > > + /* If an exact match is found, return immediately */ > > + if (p->error_millihz == 0) { > > + *pars = *p; > > + return true; > > + } > > + > > + /* Update best match if error is smaller */ > > + if (abs(p->error_millihz) < abs(best->error_millihz)) > > + *best = *p; > > + } > > + > > + return false; > > +} > > + > > > +static const struct clk_ops rzg3l_cpg_plldsi_ops = { > > + .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, > > + .determine_rate = rzg3l_cpg_plldsi_determine_rate, > > + .set_rate = rzg3l_cpg_plldsi_set_rate, > > + .is_enabled = rzg3l_cpg_pll_clk_is_enabled, > > + .enable = rzg3l_cpg_pll_clk_enable, }; > > Basically this is rzg3l_cpg_pll_ops with .determine_rate() and > .set_rate() added. Why can't you just add them to the existing rzg3l_cpg_pll_ops, and use that for all > PLLs? PLL7 doesn't seem that different to me. As per Figure 4.4-6 Block Diagram of the Deformed Clock System (5), Only PLL7 is variable one. PLL registers (1, 4, 6, 7), PLL1-CA55, PLL4-DDR, PLL6- GBETH are fixed frequency PLL's and I believe we need to use dividers for changing the rate for this PLL's. where as for PLL7, as the divider is fixed (eg: DSI: for a given bpp and num_lanes fixed. LVDS: 1/7 divider, same case for DPI). So, we need to generate variable frequencies at run time using PLL7 registers. Cheers, Biju