Skip to content

Commit 5a4326f

Browse files
seebegeertu
authored andcommitted
clk: renesas: rzg2l: Remove DSI clock rate restrictions
Convert the limited MIPI clock calculations to a full range of settings based on math including H/W limitation validation. Since the required DSI division setting must be specified from external sources before calculations, expose a new API to set it. Signed-off-by: Chris Brandt <chris.brandt@renesas.com> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com> Tested-by: Biju Das <biju.das.jz@bp.renesas.com> Reviewed-by: Hugo Villeneuve <hvilleneuve@dimonoff.com> Tested-by: Hugo Villeneuve <hvilleneuve@dimonoff.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://patch.msgid.link/20251124131003.992554-2-chris.brandt@renesas.com Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
1 parent 879e9fc commit 5a4326f

2 files changed

Lines changed: 154 additions & 31 deletions

File tree

drivers/clk/renesas/rzg2l-cpg.c

Lines changed: 143 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/device.h>
2323
#include <linux/init.h>
2424
#include <linux/iopoll.h>
25+
#include <linux/math64.h>
2526
#include <linux/mod_devicetable.h>
2627
#include <linux/module.h>
2728
#include <linux/of.h>
@@ -74,6 +75,17 @@
7475
#define MSTOP_OFF(conf) FIELD_GET(GENMASK(31, 16), (conf))
7576
#define MSTOP_MASK(conf) FIELD_GET(GENMASK(15, 0), (conf))
7677

78+
#define PLL5_FOUTVCO_MIN 800000000
79+
#define PLL5_FOUTVCO_MAX 3000000000
80+
#define PLL5_POSTDIV_MIN 1
81+
#define PLL5_POSTDIV_MAX 7
82+
#define PLL5_REFDIV_MIN 1
83+
#define PLL5_REFDIV_MAX 2
84+
#define PLL5_INTIN_MIN 20
85+
#define PLL5_INTIN_MAX 320
86+
#define PLL5_HSCLK_MIN 10000000
87+
#define PLL5_HSCLK_MAX 187500000
88+
7789
/**
7890
* struct clk_hw_data - clock hardware data
7991
* @hw: clock hw
@@ -129,6 +141,12 @@ struct rzg2l_pll5_param {
129141
u8 pl5_spread;
130142
};
131143

144+
/* PLL5 output will be used for DPI or MIPI-DSI */
145+
static int dsi_div_target = PLL5_TARGET_DPI;
146+
147+
/* Required division ratio for MIPI D-PHY clock depending on number of lanes and bpp. */
148+
static u8 dsi_div_ab_desired;
149+
132150
struct rzg2l_pll5_mux_dsi_div_param {
133151
u8 clksrc;
134152
u8 dsi_div_a;
@@ -170,6 +188,11 @@ struct rzg2l_cpg_priv {
170188
struct rzg2l_pll5_mux_dsi_div_param mux_dsi_div_params;
171189
};
172190

191+
static inline u8 rzg2l_cpg_div_ab(u8 a, u8 b)
192+
{
193+
return (b + 1) << a;
194+
}
195+
173196
static void rzg2l_cpg_del_clk_provider(void *data)
174197
{
175198
of_clk_del_provider(data);
@@ -556,24 +579,121 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core,
556579
return clk_hw->clk;
557580
}
558581

582+
/*
583+
* VCO-->[POSTDIV1,2]--FOUTPOSTDIV--------------->|
584+
* | |-->[1/(DSI DIV A * B)]--> MIPI_DSI_VCLK
585+
* |-->[1/2]--FOUT1PH0-->|
586+
* |
587+
* |------->[1/16]--------------------------------> hsclk (MIPI-PHY)
588+
*/
559589
static unsigned long
560-
rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params,
590+
rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_cpg_priv *priv,
591+
struct rzg2l_pll5_param *params,
561592
unsigned long rate)
562593
{
563-
unsigned long foutpostdiv_rate, foutvco_rate;
594+
const u32 extal_hz = EXTAL_FREQ_IN_MEGA_HZ * MEGA;
595+
unsigned long foutpostdiv_rate;
596+
unsigned int a, b, odd;
597+
unsigned long hsclk;
598+
u8 dsi_div_ab_calc;
599+
u64 foutvco_rate;
600+
601+
if (dsi_div_target == PLL5_TARGET_DSI) {
602+
/* Check hsclk */
603+
hsclk = rate * dsi_div_ab_desired / 16;
604+
if (hsclk < PLL5_HSCLK_MIN || hsclk > PLL5_HSCLK_MAX) {
605+
dev_err(priv->dev, "hsclk out of range\n");
606+
return 0;
607+
}
608+
609+
/* Determine the correct clock source based on even/odd of the divider */
610+
odd = dsi_div_ab_desired & 1;
611+
if (odd) {
612+
priv->mux_dsi_div_params.clksrc = 0; /* FOUTPOSTDIV */
613+
dsi_div_ab_calc = dsi_div_ab_desired;
614+
} else {
615+
priv->mux_dsi_div_params.clksrc = 1; /* FOUT1PH0 */
616+
dsi_div_ab_calc = dsi_div_ab_desired / 2;
617+
}
618+
619+
/* Calculate the DIV_DSI_A and DIV_DSI_B based on the desired divider */
620+
for (a = 0; a < 4; a++) {
621+
/* FOUT1PH0: Max output of DIV_DSI_A is 750MHz so at least 1/2 to be safe */
622+
if (!odd && a == 0)
623+
continue;
624+
625+
/* FOUTPOSTDIV: DIV_DSI_A must always be 1/1 */
626+
if (odd && a != 0)
627+
break;
628+
629+
for (b = 0; b < 16; b++) {
630+
/* FOUTPOSTDIV: DIV_DSI_B must always be odd divider 1/(b+1) */
631+
if (odd && b & 1)
632+
continue;
633+
634+
if (rzg2l_cpg_div_ab(a, b) == dsi_div_ab_calc) {
635+
priv->mux_dsi_div_params.dsi_div_a = a;
636+
priv->mux_dsi_div_params.dsi_div_b = b;
637+
goto calc_pll_clk;
638+
}
639+
}
640+
}
641+
642+
dev_err(priv->dev, "Failed to calculate DIV_DSI_A,B\n");
643+
644+
return 0;
645+
} else if (dsi_div_target == PLL5_TARGET_DPI) {
646+
/* Fixed settings for DPI */
647+
priv->mux_dsi_div_params.clksrc = 0;
648+
priv->mux_dsi_div_params.dsi_div_a = 3; /* Divided by 8 */
649+
priv->mux_dsi_div_params.dsi_div_b = 0; /* Divided by 1 */
650+
dsi_div_ab_desired = rzg2l_cpg_div_ab(priv->mux_dsi_div_params.dsi_div_a,
651+
priv->mux_dsi_div_params.dsi_div_b);
652+
}
564653

565-
params->pl5_intin = rate / MEGA;
566-
params->pl5_fracin = div_u64(((u64)rate % MEGA) << 24, MEGA);
567-
params->pl5_refdiv = 2;
568-
params->pl5_postdiv1 = 1;
569-
params->pl5_postdiv2 = 1;
654+
calc_pll_clk:
655+
/* PLL5 (MIPI_DSI_PLLCLK) = VCO / POSTDIV1 / POSTDIV2 */
656+
for (params->pl5_postdiv1 = PLL5_POSTDIV_MIN;
657+
params->pl5_postdiv1 <= PLL5_POSTDIV_MAX;
658+
params->pl5_postdiv1++) {
659+
for (params->pl5_postdiv2 = PLL5_POSTDIV_MIN;
660+
params->pl5_postdiv2 <= PLL5_POSTDIV_MAX;
661+
params->pl5_postdiv2++) {
662+
foutvco_rate = rate * params->pl5_postdiv1 * params->pl5_postdiv2 *
663+
dsi_div_ab_desired;
664+
if (foutvco_rate <= PLL5_FOUTVCO_MIN || foutvco_rate >= PLL5_FOUTVCO_MAX)
665+
continue;
666+
667+
for (params->pl5_refdiv = PLL5_REFDIV_MIN;
668+
params->pl5_refdiv <= PLL5_REFDIV_MAX;
669+
params->pl5_refdiv++) {
670+
u32 rem;
671+
672+
params->pl5_intin = div_u64_rem(foutvco_rate * params->pl5_refdiv,
673+
extal_hz, &rem);
674+
675+
if (params->pl5_intin < PLL5_INTIN_MIN ||
676+
params->pl5_intin > PLL5_INTIN_MAX)
677+
continue;
678+
679+
params->pl5_fracin = div_u64((u64)rem << 24, extal_hz);
680+
681+
goto clk_valid;
682+
}
683+
}
684+
}
685+
686+
dev_err(priv->dev, "Failed to calculate PLL5 settings\n");
687+
return 0;
688+
689+
clk_valid:
570690
params->pl5_spread = 0x16;
571691

572692
foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA,
573693
(params->pl5_intin << 24) + params->pl5_fracin),
574694
params->pl5_refdiv) >> 24;
575-
foutpostdiv_rate = DIV_ROUND_CLOSEST(foutvco_rate,
576-
params->pl5_postdiv1 * params->pl5_postdiv2);
695+
foutpostdiv_rate = DIV_U64_ROUND_CLOSEST(foutvco_rate,
696+
params->pl5_postdiv1 * params->pl5_postdiv2);
577697

578698
return foutpostdiv_rate;
579699
}
@@ -607,7 +727,7 @@ static unsigned long rzg2l_cpg_get_vclk_parent_rate(struct clk_hw *hw,
607727
struct rzg2l_pll5_param params;
608728
unsigned long parent_rate;
609729

610-
parent_rate = rzg2l_cpg_get_foutpostdiv_rate(&params, rate);
730+
parent_rate = rzg2l_cpg_get_foutpostdiv_rate(priv, &params, rate);
611731

612732
if (priv->mux_dsi_div_params.clksrc)
613733
parent_rate /= 2;
@@ -623,9 +743,19 @@ static int rzg2l_cpg_dsi_div_determine_rate(struct clk_hw *hw,
623743

624744
req->best_parent_rate = rzg2l_cpg_get_vclk_parent_rate(hw, req->rate);
625745

746+
if (!req->best_parent_rate)
747+
return -EINVAL;
748+
626749
return 0;
627750
}
628751

752+
void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target)
753+
{
754+
dsi_div_ab_desired = divider;
755+
dsi_div_target = target;
756+
}
757+
EXPORT_SYMBOL_GPL(rzg2l_cpg_dsi_div_set_divider);
758+
629759
static int rzg2l_cpg_dsi_div_set_rate(struct clk_hw *hw,
630760
unsigned long rate,
631761
unsigned long parent_rate)
@@ -796,22 +926,6 @@ struct sipll5 {
796926

797927
#define to_sipll5(_hw) container_of(_hw, struct sipll5, hw)
798928

799-
static unsigned long rzg2l_cpg_get_vclk_rate(struct clk_hw *hw,
800-
unsigned long rate)
801-
{
802-
struct sipll5 *sipll5 = to_sipll5(hw);
803-
struct rzg2l_cpg_priv *priv = sipll5->priv;
804-
unsigned long vclk;
805-
806-
vclk = rate / ((1 << priv->mux_dsi_div_params.dsi_div_a) *
807-
(priv->mux_dsi_div_params.dsi_div_b + 1));
808-
809-
if (priv->mux_dsi_div_params.clksrc)
810-
vclk /= 2;
811-
812-
return vclk;
813-
}
814-
815929
static unsigned long rzg2l_cpg_sipll5_recalc_rate(struct clk_hw *hw,
816930
unsigned long parent_rate)
817931
{
@@ -856,9 +970,9 @@ static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw,
856970
if (!rate)
857971
return -EINVAL;
858972

859-
vclk_rate = rzg2l_cpg_get_vclk_rate(hw, rate);
973+
vclk_rate = rate / dsi_div_ab_desired;
860974
sipll5->foutpostdiv_rate =
861-
rzg2l_cpg_get_foutpostdiv_rate(&params, vclk_rate);
975+
rzg2l_cpg_get_foutpostdiv_rate(priv, &params, vclk_rate);
862976

863977
/* Put PLL5 into standby mode */
864978
writel(CPG_SIPLL5_STBY_RESETB_WEN, priv->base + CPG_SIPLL5_STBY);
@@ -945,9 +1059,7 @@ rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core,
9451059
if (ret)
9461060
return ERR_PTR(ret);
9471061

948-
priv->mux_dsi_div_params.clksrc = 1; /* Use clk src 1 for DSI */
949-
priv->mux_dsi_div_params.dsi_div_a = 1; /* Divided by 2 */
950-
priv->mux_dsi_div_params.dsi_div_b = 2; /* Divided by 3 */
1062+
rzg2l_cpg_dsi_div_set_divider(8, PLL5_TARGET_DPI);
9511063

9521064
return clk_hw->clk;
9531065
}

include/linux/clk/renesas.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev);
3535
#define cpg_mssr_detach_dev NULL
3636
#endif
3737

38+
enum {
39+
PLL5_TARGET_DPI,
40+
PLL5_TARGET_DSI
41+
};
42+
43+
#ifdef CONFIG_CLK_RZG2L
44+
void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target);
45+
#else
46+
static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { }
47+
#endif
48+
3849
/**
3950
* struct rzv2h_pll_limits - PLL parameter constraints
4051
*

0 commit comments

Comments
 (0)