[PATCH 4/4] drm: renesas: rz-du: mipi_dsi: Add fallback CPG PLLDSI parameter search
From: Prabhakar
Date: Tue Nov 03 2026 - 12:22:05 EST
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
For each PLLDSI divider, rzv2h_dphy_check_instance() only considers the
CPG PLLDSI parameters with the smallest frequency error. If they do not
lead to a DSI PLL setting less than 0.5 Hz off the required HS clock,
the divider is skipped, even though a CPG setting with a slightly larger
error could work. Modes such as <mode, lanes, format> are therefore
rejected on RZ/V2H(P), RZ/V2N and RZ/G3E.
If no divider gives a usable pair, search again with
rzv2h_cpg_get_pll_pars_validate(), accepting CPG candidates up to 50 Hz
off the target whose DSI PLL setting is less than 0.5 Hz off the HS clock.
The first accepted pair is used, so the pixel clock may be slightly less
accurate, but the mode can be driven.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@xxxxxxxxxxxxxx>
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 85 ++++++++++++++++++-
1 file changed, 83 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 682bbb339bef..c23c7f43a560 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -42,6 +42,9 @@ MODULE_IMPORT_NS("RZV2H_CPG");
#define RZ_MIPI_DSI_FEATURE_16BPP BIT(0)
#define RZ_MIPI_DSI_FEATURE_PWRRDY BIT(1)
+#define RZV2H_DSI_PLL_MAX_ERR_MILLIHZ 500
+#define RZV2H_CPG_PLLDSI_MAX_ERR_MILLIHZ (50 * MILLI)
+
struct rzg2l_mipi_dsi;
struct rzg2l_mipi_dsi_hw_info {
@@ -76,6 +79,13 @@ struct rzv2h_dsi_mode_calc {
struct rzv2h_pll_div_pars cpg_dsi_div_parameters;
};
+struct rzv2h_dsi_validator_context {
+ struct rzv2h_pll_pars *dsi_pars;
+ unsigned int lanes;
+ unsigned int bpp;
+ u8 base_divider;
+};
+
struct rzg2l_mipi_dsi {
struct device *dev;
void __iomem *mmio;
@@ -675,6 +685,67 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
return 0;
}
+static bool rzv2h_dsi_validate_pll_pars(const struct rzv2h_pll_pars *pars, void *context)
+{
+ struct rzv2h_dsi_validator_context *ctx = context;
+ u64 hsfreq_millihz;
+
+ /* Check error threshold for CPG PLL DSI */
+ if (abs(pars->error_millihz) > RZV2H_CPG_PLLDSI_MAX_ERR_MILLIHZ)
+ return false;
+
+ /* Calculate the required DSI frequency */
+ hsfreq_millihz = DIV_U64_ROUND_CLOSEST(pars->freq_millihz, ctx->base_divider);
+ hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz * ctx->bpp, ctx->lanes);
+
+ /* Find DSI PLL parameters */
+ if (!rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits, ctx->dsi_pars, hsfreq_millihz))
+ return false;
+
+ /* Check DSI error threshold */
+ if (abs(ctx->dsi_pars->error_millihz) >= RZV2H_DSI_PLL_MAX_ERR_MILLIHZ)
+ return false;
+
+ return true;
+}
+
+static bool rzv2h_dsi_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size, u64 freq_millihz,
+ unsigned int bpp, unsigned int lanes,
+ struct rzv2h_pll_pars *dsi_pars)
+{
+ struct rzv2h_pll_pars temp_dsi_pars;
+ struct rzv2h_dsi_validator_context ctx = {
+ .dsi_pars = &temp_dsi_pars,
+ .lanes = lanes,
+ .bpp = bpp,
+ };
+ struct rzv2h_pll_validator validator = {
+ .validate = rzv2h_dsi_validate_pll_pars,
+ .context = &ctx,
+ };
+ struct rzv2h_pll_div_pars p;
+
+ for (unsigned int i = 0; i < table_size; i++) {
+ ctx.base_divider = table[i];
+
+ if (!rzv2h_cpg_get_pll_pars_validate(limits, &p.pll,
+ freq_millihz * table[i], &validator))
+ continue;
+
+ p.div.divider_value = table[i];
+ p.div.freq_millihz = DIV_U64_ROUND_CLOSEST(p.pll.freq_millihz, table[i]);
+ p.div.error_millihz = freq_millihz - p.div.freq_millihz;
+
+ *dsi_pars = temp_dsi_pars;
+ *pars = p;
+ return true;
+ }
+
+ return false;
+}
+
static unsigned int rzv2h_dphy_check_instance(struct rzg2l_mipi_dsi *dsi,
unsigned long mode_freq,
unsigned int pll_instance)
@@ -718,8 +789,18 @@ static unsigned int rzv2h_dphy_check_instance(struct rzg2l_mipi_dsi *dsi,
}
}
- if (!found_valid_parameters)
- return MODE_CLOCK_RANGE;
+ if (!found_valid_parameters) {
+ parameters_found =
+ rzv2h_dsi_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[pll_instance],
+ &best_cpg_dsi_parameters,
+ dsi->info->cpg_plldsi.table,
+ dsi->info->cpg_plldsi.table_size,
+ mode_freq_millihz,
+ bpp, dsi->lanes,
+ &best_dsi_parameters);
+ if (!parameters_found)
+ return MODE_CLOCK_RANGE;
+ }
memcpy(&dsi->mode_calc.dsi_parameters, &best_dsi_parameters,
sizeof(best_dsi_parameters));
--
2.56.0