* [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC
@ 2025-07-28 20:14 Prabhakar
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
` (6 more replies)
0 siblings, 7 replies; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Hi All,
This patch series adds DU/DSI clocks and provides support for the
MIPI DSI interface on the RZ/V2H(P) SoC. It was originally part of
series [0], but has now been split into 6 patches due to dependencies
on the clock driver, making it easier to review and merge.
[0] https://lore.kernel.org/all/20250430204112.342123-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
v6->v7:
- Renamed pllclk to pllrefclk in DT binding
- Added a new patch to add instance field to struct pll
- Renamed rzv2h_pll_div_limits to rzv2h_pll_limits
- Included fout_min and fout_max in the rzv2h_pll_limits structure
- Renamed rzv2h_plldsi_parameters to rzv2h_pll_div_pars and re-structured
for readability
- Dropped rzv2h_dsi_get_pll_parameters_values() instead added modular apis
to calculate the PLL parameters ie rzv2h_get_pll_pars/rzv2h_get_pll_div_pars/
rzv2h_get_pll_dtable_pars
- Dropped plldsi_limits from rzv2h_cpg_info structure
- Updated the DSI driver to use the new PLL APIs
- Included the LPCLK patch
- Rebased the changes on next-20250728
v5-> v6:
- Renamed CPG_PLL_STBY_SSCGEN_WEN to CPG_PLL_STBY_SSC_EN_WEN
- Updated CPG_PLL_CLK1_DIV_K, CPG_PLL_CLK1_DIV_M, and
CPG_PLL_CLK1_DIV_P macros to use GENMASK
- Updated req->rate in rzv2h_cpg_plldsi_div_determine_rate()
- Dropped the cast in rzv2h_cpg_plldsi_div_set_rate()
- Dropped rzv2h_cpg_plldsi_round_rate() and implemented
rzv2h_cpg_plldsi_determine_rate() instead
- Made use of FIELD_PREP()
- Moved CPG_CSDIV1 macro in patch 2/4
- Dropped two_pow_s in rzv2h_dsi_get_pll_parameters_values()
- Used mul_u32_u32() while calculating output_m and output_k_range
- Used div_s64() instead of div64_s64() while calculating
pll_k
- Used mul_u32_u32() while calculating fvco and fvco checks
- Rounded the final output using DIV_U64_ROUND_CLOSEST()
- Renamed CLK_DIV_PLLETH_LPCLK to CLK_CDIV4_PLLETH_LPCLK
- Renamed CLK_CSDIV_PLLETH_LPCLK to CLK_PLLETH_LPCLK_GEAR
- Renamed CLK_PLLDSI_SDIV2 to CLK_PLLDSI_GEAR
- Renamed plldsi_sdiv2 to plldsi_gear
- Preserved the sort order (by part number).
- Added reviewed tag from Geert.
- Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
PHYTCLKSETR_* and PHYTHSSETR_* macros.
- Replaced 10000000UL with 10 * MEGA
- Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
- Replaced `i -= 1;` with `i--;`
- Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
Cheers,
Prabhakar
Lad Prabhakar (6):
clk: renesas: rzv2h-cpg: Add instance field to struct pll
clk: renesas: rzv2h-cpg: Add support for DSI clocks
clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and
RZ/V2N
drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
.../bindings/display/bridge/renesas,dsi.yaml | 120 ++++--
drivers/clk/renesas/r9a09g057-cpg.c | 62 +++
drivers/clk/renesas/rzv2h-cpg.c | 309 +++++++++++++-
drivers/clk/renesas/rzv2h-cpg.h | 29 +-
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 350 ++++++++++++++++
.../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
include/linux/clk/renesas-rzv2h-cpg-pll.h | 395 ++++++++++++++++++
7 files changed, 1257 insertions(+), 42 deletions(-)
create mode 100644 include/linux/clk/renesas-rzv2h-cpg-pll.h
--
2.50.1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-08-15 5:11 ` Biju Das
2025-08-19 13:05 ` Geert Uytterhoeven
2025-07-28 20:14 ` [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
` (5 subsequent siblings)
6 siblings, 2 replies; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add a two-bit "instance" member to struct pll and extend the PLL_PACK()
macro to accept an instance parameter. Initialize all existing PLL
definitions with instance 0 to preserve legacy behavior. This change
enables support for SoCs with multiple PLL instances (for example,
RZ/G3E we have two PLL DSIs).
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v6->v7:
- New patch
---
drivers/clk/renesas/rzv2h-cpg.h | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index 840eed25aeda..e2053049c299 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -16,20 +16,23 @@
*
* @offset: STBY register offset
* @has_clkn: Flag to indicate if CLK1/2 are accessible or not
+ * @instance: PLL instance number
*/
struct pll {
unsigned int offset:9;
unsigned int has_clkn:1;
+ unsigned int instance:2;
};
-#define PLL_PACK(_offset, _has_clkn) \
+#define PLL_PACK(_offset, _has_clkn, _instance) \
((struct pll){ \
.offset = _offset, \
- .has_clkn = _has_clkn \
+ .has_clkn = _has_clkn, \
+ .instance = _instance \
})
-#define PLLCA55 PLL_PACK(0x60, 1)
-#define PLLGPU PLL_PACK(0x120, 1)
+#define PLLCA55 PLL_PACK(0x60, 1, 0)
+#define PLLGPU PLL_PACK(0x120, 1, 0)
/**
* struct ddiv - Structure for dynamic switching divider
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-08-15 5:13 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
2025-07-28 20:14 ` [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
` (4 subsequent siblings)
6 siblings, 2 replies; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add support for PLLDSI and PLLDSI divider clocks.
Introduce the `renesas-rzv2h-cpg-pll.h` header to centralize and share
PLLDSI related data structures, limits, and algorithms between the
RZ/V2H(P) CPG and DSI drivers.
The DSI PLL is functionally similar to the CPG's PLLDSI, but has slightly
different parameter limits and omits the programmable divider present in
CPG. To ensure precise frequency calculations, especially for milliHz-level
accuracy needed by the DSI driver, the shared algorithm allows both drivers
to compute PLL parameters consistently using the same logic and input
clock.
Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v6->v7:
- Made struct rzv2h_pll_limits more modular also added Ffout limits
- Made the alogirithm modular and also added apis based on the
needs for lvds and dpi
v5->v6:
- Renamed CPG_PLL_STBY_SSCGEN_WEN to CPG_PLL_STBY_SSC_EN_WEN
- Updated CPG_PLL_CLK1_DIV_K, CPG_PLL_CLK1_DIV_M, and
CPG_PLL_CLK1_DIV_P macros to use GENMASK
- Updated req->rate in rzv2h_cpg_plldsi_div_determine_rate()
- Dropped the cast in rzv2h_cpg_plldsi_div_set_rate()
- Dropped rzv2h_cpg_plldsi_round_rate() and implemented
rzv2h_cpg_plldsi_determine_rate() instead
- Made use of FIELD_PREP()
- Moved CPG_CSDIV1 macro in patch 2/4
- Dropped two_pow_s in rzv2h_dsi_get_pll_parameters_values()
- Used mul_u32_u32() while calculating output_m and output_k_range
- Used div_s64() instead of div64_s64() while calculating
pll_k
- Used mul_u32_u32() while calculating fvco and fvco checks
- Rounded the final output using DIV_U64_ROUND_CLOSEST()
v4->v5:
- No changes
v3->v4:
- Corrected parameter name in rzv2h_dsi_get_pll_parameters_values()
description freq_millihz
v2->v3:
- Update the commit message to clarify the purpose of `renesas-rzv2h-dsi.h`
header
- Used mul_u32_u32() in rzv2h_cpg_plldsi_div_determine_rate()
- Replaced *_mhz to *_millihz for clarity
- Updated u64->u32 for fvco limits
- Initialized the members in declaration order for
RZV2H_CPG_PLL_DSI_LIMITS() macro
- Used clk_div_mask() in rzv2h_cpg_plldsi_div_recalc_rate()
- Replaced `unsigned long long` with u64
- Dropped rzv2h_cpg_plldsi_clk_recalc_rate() and reused
rzv2h_cpg_pll_clk_recalc_rate() instead
- In rzv2h_cpg_plldsi_div_set_rate() followed the same style
of RMW-operation as done in the other functions
- Renamed rzv2h_cpg_plldsi_set_rate() to rzv2h_cpg_pll_set_rate()
- Dropped rzv2h_cpg_plldsi_clk_register() and reused
rzv2h_cpg_pll_clk_register() instead
- Added a gaurd in renesas-rzv2h-dsi.h header
v1->v2:
- No changes
---
drivers/clk/renesas/rzv2h-cpg.c | 309 ++++++++++++++++-
drivers/clk/renesas/rzv2h-cpg.h | 19 +-
include/linux/clk/renesas-rzv2h-cpg-pll.h | 395 ++++++++++++++++++++++
3 files changed, 712 insertions(+), 11 deletions(-)
create mode 100644 include/linux/clk/renesas-rzv2h-cpg-pll.h
diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index f468afbb54e2..2378cf92da5e 100644
--- a/drivers/clk/renesas/rzv2h-cpg.c
+++ b/drivers/clk/renesas/rzv2h-cpg.c
@@ -14,9 +14,13 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/clk/renesas-rzv2h-cpg-pll.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/iopoll.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -26,6 +30,7 @@
#include <linux/refcount.h>
#include <linux/reset-controller.h>
#include <linux/string_choices.h>
+#include <linux/units.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h>
@@ -47,13 +52,15 @@
#define CPG_PLL_STBY(x) ((x))
#define CPG_PLL_STBY_RESETB BIT(0)
+#define CPG_PLL_STBY_SSC_EN BIT(2)
#define CPG_PLL_STBY_RESETB_WEN BIT(16)
+#define CPG_PLL_STBY_SSC_EN_WEN BIT(18)
#define CPG_PLL_CLK1(x) ((x) + 0x004)
-#define CPG_PLL_CLK1_KDIV(x) ((s16)FIELD_GET(GENMASK(31, 16), (x)))
-#define CPG_PLL_CLK1_MDIV(x) FIELD_GET(GENMASK(15, 6), (x))
-#define CPG_PLL_CLK1_PDIV(x) FIELD_GET(GENMASK(5, 0), (x))
+#define CPG_PLL_CLK1_KDIV GENMASK(31, 16)
+#define CPG_PLL_CLK1_MDIV GENMASK(15, 6)
+#define CPG_PLL_CLK1_PDIV GENMASK(5, 0)
#define CPG_PLL_CLK2(x) ((x) + 0x008)
-#define CPG_PLL_CLK2_SDIV(x) FIELD_GET(GENMASK(2, 0), (x))
+#define CPG_PLL_CLK2_SDIV GENMASK(2, 0)
#define CPG_PLL_MON(x) ((x) + 0x010)
#define CPG_PLL_MON_RESETB BIT(0)
#define CPG_PLL_MON_LOCK BIT(4)
@@ -65,6 +72,22 @@
#define CPG_CLKSTATUS0 (0x700)
+/* On RZ/G3E SoC we have two DSI PLLs */
+#define MAX_CPG_DSI_PLL 2
+
+/**
+ * struct rzv2h_pll_dsi_info - PLL DSI information, holds the limits and parameters
+ *
+ * @pll_dsi_limits: PLL DSI parameters limits
+ * @pll_dsi_parameters: Calculated PLL DSI parameters
+ * @req_pll_dsi_rate: Requested PLL DSI rate
+ */
+struct rzv2h_pll_dsi_info {
+ const struct rzv2h_pll_limits *pll_dsi_limits;
+ struct rzv2h_pll_div_pars pll_dsi_parameters;
+ unsigned long req_pll_dsi_rate;
+};
+
/**
* struct rzv2h_cpg_priv - Clock Pulse Generator Private Data
*
@@ -80,6 +103,7 @@
* @ff_mod_status_ops: Fixed Factor Module Status Clock operations
* @mstop_count: Array of mstop values
* @rcdev: Reset controller entity
+ * @pll_dsi_info: Array of PLL DSI information, holds the limits and parameters
*/
struct rzv2h_cpg_priv {
struct device *dev;
@@ -98,6 +122,8 @@ struct rzv2h_cpg_priv {
atomic_t *mstop_count;
struct reset_controller_dev rcdev;
+
+ struct rzv2h_pll_dsi_info pll_dsi_info[MAX_CPG_DSI_PLL];
};
#define rcdev_to_priv(x) container_of(x, struct rzv2h_cpg_priv, rcdev)
@@ -168,6 +194,253 @@ struct rzv2h_ff_mod_status_clk {
#define to_rzv2h_ff_mod_status_clk(_hw) \
container_of(_hw, struct rzv2h_ff_mod_status_clk, fix.hw)
+/**
+ * struct rzv2h_plldsi_div_clk - PLL DSI DDIV clock
+ *
+ * @dtable: divider table
+ * @priv: CPG private data
+ * @hw: divider clk
+ * @ddiv: divider configuration
+ */
+struct rzv2h_plldsi_div_clk {
+ const struct clk_div_table *dtable;
+ struct rzv2h_cpg_priv *priv;
+ struct clk_hw hw;
+ struct ddiv ddiv;
+};
+
+#define to_plldsi_div_clk(_hw) \
+ container_of(_hw, struct rzv2h_plldsi_div_clk, hw)
+
+static unsigned long rzv2h_cpg_plldsi_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw);
+ struct rzv2h_cpg_priv *priv = dsi_div->priv;
+ struct ddiv ddiv = dsi_div->ddiv;
+ u32 div;
+
+ div = readl(priv->base + ddiv.offset);
+ div >>= ddiv.shift;
+ div &= clk_div_mask(ddiv.width);
+ div = dsi_div->dtable[div].div;
+
+ return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
+}
+
+static struct rzv2h_pll_dsi_info *rzv2h_get_pll_dsi_info(struct clk_hw *pll_dsi,
+ struct rzv2h_cpg_priv *priv)
+{
+ struct pll_clk *pll_clk = to_pll(pll_dsi);
+
+ return &priv->pll_dsi_info[pll_clk->pll.instance];
+}
+
+static int rzv2h_cpg_plldsi_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw);
+ struct rzv2h_cpg_priv *priv = dsi_div->priv;
+ struct rzv2h_pll_div_pars *dsi_params;
+ struct rzv2h_pll_dsi_info *dsi_info;
+ u64 rate_millihz;
+
+ dsi_info = rzv2h_get_pll_dsi_info(clk_hw_get_parent(hw), priv);
+ dsi_params = &dsi_info->pll_dsi_parameters;
+
+ rate_millihz = mul_u32_u32(req->rate, MILLI);
+ if (rate_millihz == dsi_params->div.error_millihz + dsi_params->div.freq_millihz)
+ goto exit_determine_rate;
+
+ if (!rzv2h_get_pll_dtable_pars(dsi_info->pll_dsi_limits, dsi_params, dsi_div->dtable,
+ rate_millihz)) {
+ dev_err(priv->dev,
+ "failed to determine rate for req->rate: %lu\n",
+ req->rate);
+ return -EINVAL;
+ }
+
+exit_determine_rate:
+ req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params->div.freq_millihz, MILLI);
+ req->best_parent_rate = req->rate * dsi_params->div.divider_value;
+ dsi_info->req_pll_dsi_rate = req->best_parent_rate;
+
+ return 0;
+};
+
+static int rzv2h_cpg_plldsi_div_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct rzv2h_plldsi_div_clk *dsi_div = to_plldsi_div_clk(hw);
+ struct rzv2h_cpg_priv *priv = dsi_div->priv;
+ struct rzv2h_pll_div_pars *dsi_params;
+ struct rzv2h_pll_dsi_info *dsi_info;
+ struct ddiv ddiv = dsi_div->ddiv;
+ const struct clk_div_table *clkt;
+ bool divider_found = false;
+ u32 val, shift;
+
+ dsi_info = rzv2h_get_pll_dsi_info(clk_hw_get_parent(hw), priv);
+ dsi_params = &dsi_info->pll_dsi_parameters;
+
+ for (clkt = dsi_div->dtable; clkt->div; clkt++) {
+ if (clkt->div == dsi_params->div.divider_value) {
+ divider_found = true;
+ break;
+ }
+ }
+
+ if (!divider_found)
+ return -EINVAL;
+
+ shift = ddiv.shift;
+ val = readl(priv->base + ddiv.offset) | DDIV_DIVCTL_WEN(shift);
+ val &= ~(clk_div_mask(ddiv.width) << shift);
+ val |= clkt->val << shift;
+ writel(val, priv->base + ddiv.offset);
+
+ return 0;
+};
+
+static const struct clk_ops rzv2h_cpg_plldsi_div_ops = {
+ .recalc_rate = rzv2h_cpg_plldsi_div_recalc_rate,
+ .determine_rate = rzv2h_cpg_plldsi_div_determine_rate,
+ .set_rate = rzv2h_cpg_plldsi_div_set_rate,
+};
+
+static struct clk * __init
+rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core,
+ struct rzv2h_cpg_priv *priv)
+{
+ struct rzv2h_plldsi_div_clk *clk_hw_data;
+ struct clk **clks = priv->clks;
+ struct clk_init_data init;
+ const struct clk *parent;
+ const char *parent_name;
+ struct clk_hw *clk_hw;
+ int ret;
+
+ parent = clks[core->parent];
+ 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;
+ clk_hw_data->ddiv = core->cfg.ddiv;
+ clk_hw_data->dtable = core->dtable;
+
+ parent_name = __clk_get_name(parent);
+ init.name = core->name;
+ init.ops = &rzv2h_cpg_plldsi_div_ops;
+ init.flags = core->flag;
+ 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;
+}
+
+static int rzv2h_cpg_plldsi_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzv2h_cpg_priv *priv = pll_clk->priv;
+ struct rzv2h_pll_dsi_info *dsi_info;
+ u64 rate_millihz;
+
+ dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance];
+ /* check if the divider has already invoked the algorithm */
+ if (req->rate == dsi_info->req_pll_dsi_rate)
+ return 0;
+
+ /* If the req->rate doesn't match we do the calculation assuming there is no divider */
+ rate_millihz = mul_u32_u32(req->rate, MILLI);
+ if (!rzv2h_get_pll_pars(dsi_info->pll_dsi_limits,
+ &dsi_info->pll_dsi_parameters.pll, 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_info->pll_dsi_parameters.pll.freq_millihz, MILLI);
+ dsi_info->req_pll_dsi_rate = req->rate;
+
+ return 0;
+}
+
+static int rzv2h_cpg_pll_set_rate(struct pll_clk *pll_clk,
+ struct rzv2h_pll_pars *params,
+ bool ssc_disable)
+{
+ struct rzv2h_cpg_priv *priv = pll_clk->priv;
+ u16 offset = pll_clk->pll.offset;
+ u32 val;
+ int ret;
+
+ /* Put PLL into standby mode */
+ writel(CPG_PLL_STBY_RESETB_WEN, priv->base + CPG_PLL_STBY(offset));
+ ret = readl_poll_timeout_atomic(priv->base + CPG_PLL_MON(offset),
+ val, !(val & CPG_PLL_MON_LOCK),
+ 100, 2000);
+ if (ret) {
+ dev_err(priv->dev, "Failed to put PLLDSI into standby mode");
+ return ret;
+ }
+
+ /* Output clock setting 1 */
+ writel(FIELD_PREP(CPG_PLL_CLK1_KDIV, (u16)params->k) |
+ FIELD_PREP(CPG_PLL_CLK1_MDIV, params->m) |
+ FIELD_PREP(CPG_PLL_CLK1_PDIV, params->p),
+ priv->base + CPG_PLL_CLK1(offset));
+
+ /* Output clock setting 2 */
+ val = readl(priv->base + CPG_PLL_CLK2(offset));
+ writel((val & ~CPG_PLL_CLK2_SDIV) | FIELD_PREP(CPG_PLL_CLK2_SDIV, params->s),
+ priv->base + CPG_PLL_CLK2(offset));
+
+ /* Put PLL to normal mode */
+ if (ssc_disable)
+ val = CPG_PLL_STBY_SSC_EN_WEN;
+ else
+ val = CPG_PLL_STBY_SSC_EN_WEN | CPG_PLL_STBY_SSC_EN;
+ writel(val | CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB,
+ priv->base + CPG_PLL_STBY(offset));
+
+ /* PLL normal mode transition, output clock stability check */
+ ret = readl_poll_timeout_atomic(priv->base + CPG_PLL_MON(offset),
+ val, (val & CPG_PLL_MON_LOCK),
+ 100, 2000);
+ if (ret) {
+ dev_err(priv->dev, "Failed to put PLLDSI into normal mode");
+ return ret;
+ }
+
+ return 0;
+};
+
+static int rzv2h_cpg_plldsi_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzv2h_pll_dsi_info *dsi_info;
+ struct rzv2h_cpg_priv *priv = pll_clk->priv;
+
+ dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance];
+
+ return rzv2h_cpg_pll_set_rate(pll_clk, &dsi_info->pll_dsi_parameters.pll, true);
+};
+
static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
{
struct pll_clk *pll_clk = to_pll(hw);
@@ -231,12 +504,19 @@ static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
clk1 = readl(priv->base + CPG_PLL_CLK1(pll.offset));
clk2 = readl(priv->base + CPG_PLL_CLK2(pll.offset));
- rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(clk1) << 16) +
- CPG_PLL_CLK1_KDIV(clk1), 16 + CPG_PLL_CLK2_SDIV(clk2));
+ rate = mul_u64_u32_shr(parent_rate, (FIELD_GET(CPG_PLL_CLK1_MDIV, clk1) << 16) +
+ (s16)FIELD_GET(CPG_PLL_CLK1_KDIV, clk1),
+ 16 + FIELD_GET(CPG_PLL_CLK2_SDIV, clk2));
- return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(clk1));
+ return DIV_ROUND_CLOSEST_ULL(rate, FIELD_GET(CPG_PLL_CLK1_PDIV, clk1));
}
+static const struct clk_ops rzv2h_cpg_plldsi_ops = {
+ .recalc_rate = rzv2h_cpg_pll_clk_recalc_rate,
+ .determine_rate = rzv2h_cpg_plldsi_determine_rate,
+ .set_rate = rzv2h_cpg_plldsi_set_rate,
+};
+
static const struct clk_ops rzv2h_cpg_pll_ops = {
.is_enabled = rzv2h_cpg_pll_clk_is_enabled,
.enable = rzv2h_cpg_pll_clk_enable,
@@ -246,7 +526,8 @@ static const struct clk_ops rzv2h_cpg_pll_ops = {
static struct clk * __init
rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
struct rzv2h_cpg_priv *priv,
- const struct clk_ops *ops)
+ const struct clk_ops *ops,
+ bool is_plldsi)
{
struct device *dev = priv->dev;
struct clk_init_data init;
@@ -263,6 +544,10 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
if (!pll_clk)
return ERR_PTR(-ENOMEM);
+ if (is_plldsi)
+ priv->pll_dsi_info[core->cfg.pll.instance].pll_dsi_limits =
+ core->cfg.pll.limits;
+
parent_name = __clk_get_name(parent);
init.name = core->name;
init.ops = ops;
@@ -589,7 +874,7 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
clk = rzv2h_cpg_fixed_mod_status_clk_register(core, priv);
break;
case CLK_TYPE_PLL:
- clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops);
+ clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops, false);
break;
case CLK_TYPE_DDIV:
clk = rzv2h_cpg_ddiv_clk_register(core, priv);
@@ -597,6 +882,12 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
case CLK_TYPE_SMUX:
clk = rzv2h_cpg_mux_clk_register(core, priv);
break;
+ case CLK_TYPE_PLLDSI:
+ clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_plldsi_ops, true);
+ break;
+ case CLK_TYPE_PLLDSI_DIV:
+ clk = rzv2h_cpg_plldsi_div_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 e2053049c299..637803bc1e89 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -22,15 +22,20 @@ struct pll {
unsigned int offset:9;
unsigned int has_clkn:1;
unsigned int instance:2;
+ const struct rzv2h_pll_limits *limits;
};
-#define PLL_PACK(_offset, _has_clkn, _instance) \
+#define PLL_PACK_LIMITS(_offset, _has_clkn, _instance, _limits) \
((struct pll){ \
.offset = _offset, \
.has_clkn = _has_clkn, \
- .instance = _instance \
+ .instance = _instance, \
+ .limits = _limits \
})
+#define PLL_PACK(_offset, _has_clkn, _instance) \
+ PLL_PACK_LIMITS(_offset, _has_clkn, _instance, NULL)
+
#define PLLCA55 PLL_PACK(0x60, 1, 0)
#define PLLGPU PLL_PACK(0x120, 1, 0)
@@ -191,6 +196,8 @@ enum clk_types {
CLK_TYPE_PLL,
CLK_TYPE_DDIV, /* Dynamic Switching Divider */
CLK_TYPE_SMUX, /* Static Mux */
+ CLK_TYPE_PLLDSI, /* PLLDSI */
+ CLK_TYPE_PLLDSI_DIV, /* PLLDSI divider */
};
#define DEF_TYPE(_name, _id, _type...) \
@@ -221,6 +228,14 @@ enum clk_types {
.num_parents = ARRAY_SIZE(_parent_names), \
.flag = CLK_SET_RATE_PARENT, \
.mux_flags = CLK_MUX_HIWORD_MASK)
+#define DEF_PLLDSI(_name, _id, _parent, _pll_packed) \
+ DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI, .parent = _parent, .cfg.pll = _pll_packed)
+#define DEF_PLLDSI_DIV(_name, _id, _parent, _ddiv_packed, _dtable) \
+ DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_DIV, \
+ .cfg.ddiv = _ddiv_packed, \
+ .dtable = _dtable, \
+ .parent = _parent, \
+ .flag = CLK_SET_RATE_PARENT)
/**
* struct rzv2h_mod_clk - Module Clocks definitions
diff --git a/include/linux/clk/renesas-rzv2h-cpg-pll.h b/include/linux/clk/renesas-rzv2h-cpg-pll.h
new file mode 100644
index 000000000000..f34904cba8de
--- /dev/null
+++ b/include/linux/clk/renesas-rzv2h-cpg-pll.h
@@ -0,0 +1,395 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Renesas RZ/V2H(P) CPG PLL helper
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+#ifndef __RENESAS_RZV2H_CPG_PLL_H__
+#define __RENESAS_RZV2H_CPG_PLL_H__
+
+#include <linux/clk-provider.h>
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/units.h>
+
+#define RZ_V2H_OSC_CLK_IN_MEGA (24 * MEGA)
+#define RZV2H_MAX_DIV_TABLES (16)
+
+/**
+ * struct rzv2h_pll_limits - PLL parameter constraints
+ *
+ * This structure defines the minimum and maximum allowed values for
+ * various parameters used to configure a PLL. These limits ensure
+ * the PLL operates within valid and stable ranges.
+ *
+ * @fout: Output frequency range (in MHz)
+ * @fout.min: Minimum allowed output frequency
+ * @fout.max: Maximum allowed output frequency
+ *
+ * @fvco: PLL oscillation frequency range (in MHz)
+ * @fvco.min: Minimum allowed VCO frequency
+ * @fvco.max: Maximum allowed VCO frequency
+ *
+ * @m: Main-divider range
+ * @m.min: Minimum main-divider value
+ * @m.max: Maximum main-divider value
+ *
+ * @p: Pre-divider range
+ * @p.min: Minimum pre-divider value
+ * @p.max: Maximum pre-divider value
+ *
+ * @s: Divider range
+ * @s.min: Minimum divider value
+ * @s.max: Maximum divider value
+ *
+ * @k: Delta-sigma modulator range (signed)
+ * @k.min: Minimum delta-sigma value
+ * @k.max: Maximum delta-sigma value
+ */
+struct rzv2h_pll_limits {
+ struct {
+ u32 min;
+ u32 max;
+ } fout;
+
+ struct {
+ u32 min;
+ u32 max;
+ } fvco;
+
+ struct {
+ u16 min;
+ u16 max;
+ } m;
+
+ struct {
+ u8 min;
+ u8 max;
+ } p;
+
+ struct {
+ u8 min;
+ u8 max;
+ } s;
+
+ struct {
+ s16 min;
+ s16 max;
+ } k;
+};
+
+/**
+ * struct rzv2h_pll_pars - PLL configuration parameters
+ *
+ * This structure contains the configuration parameters for the
+ * Phase-Locked Loop (PLL), used to achieve a specific output frequency.
+ *
+ * @m: Main divider value
+ * @p: Pre-divider value
+ * @s: Output divider value
+ * @k: Delta-sigma modulation value
+ * @freq_millihz: Calculated PLL output frequency in millihertz
+ * @error_millihz: Frequency error from target in millihertz (signed)
+ */
+struct rzv2h_pll_pars {
+ u16 m;
+ u8 p;
+ u8 s;
+ s16 k;
+ u64 freq_millihz;
+ s64 error_millihz;
+};
+
+/**
+ * struct rzv2h_pll_div_pars - PLL parameters with post-divider
+ *
+ * This structure is used for PLLs that include an additional post-divider
+ * stage after the main PLL block. It contains both the PLL configuration
+ * parameters and the resulting frequency/error values after the divider.
+ *
+ * @pll: Main PLL configuration parameters (see struct rzv2h_pll_pars)
+ *
+ * @div: Post-divider configuration and result
+ * @div.divider_value: Divider applied to the PLL output
+ * @div.freq_millihz: Output frequency after divider in millihertz
+ * @div.error_millihz: Frequency error from target in millihertz (signed)
+ */
+struct rzv2h_pll_div_pars {
+ struct rzv2h_pll_pars pll;
+ struct {
+ u8 divider_value;
+ u64 freq_millihz;
+ s64 error_millihz;
+ } div;
+};
+
+#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
+ static const struct rzv2h_pll_limits (name) = { \
+ .fout = { .min = 25 * MEGA, .max = 375 * MEGA }, \
+ .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA }, \
+ .m = { .min = 64, .max = 533 }, \
+ .p = { .min = 1, .max = 4 }, \
+ .s = { .min = 0, .max = 6 }, \
+ .k = { .min = -32768, .max = 32767 }, \
+ } \
+
+/**
+ * rzv2h_get_pll_pars - Finds the best combination of PLL parameters
+ * for a given frequency.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters values
+ * will be stored
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) to achieve
+ * the desired frequency.
+ * There is no direct formula to calculate the PLL parameters, as it's an open
+ * system of equations, therefore this function uses an iterative approach to
+ * determine the best solution. The best solution is one that minimizes the error
+ * (desired frequency - actual frequency).
+ *
+ * Return: true if a valid set of parameters values is found, false otherwise.
+ */
+static __maybe_unused bool
+rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars, u64 freq_millihz)
+{
+ u64 fout_min_millihz = mul_u32_u32(limits->fout.min, MILLI);
+ u64 fout_max_millihz = mul_u32_u32(limits->fout.max, MILLI);
+ struct rzv2h_pll_pars p, best;
+
+ if (freq_millihz > fout_max_millihz ||
+ freq_millihz < fout_min_millihz)
+ return false;
+
+ /* Initialize best error to maximum possible value */
+ best.error_millihz = S64_MAX;
+
+ for (p.p = limits->p.min; p.p <= limits->p.max; p.p++) {
+ u32 fref = RZ_V2H_OSC_CLK_IN_MEGA / p.p;
+ u16 divider;
+
+ for (divider = 1 << limits->s.min, p.s = limits->s.min;
+ p.s <= limits->s.max; p.s++, divider <<= 1) {
+ for (p.m = limits->m.min; p.m <= limits->m.max; p.m++) {
+ u64 output_m, output_k_range;
+ s64 pll_k, output_k;
+ u64 fvco, output;
+
+ /*
+ * The frequency generated by the PLL + divider
+ * is calculated as follows:
+ *
+ * With:
+ * Freq = Ffout = Ffvco / 2^(pll_s)
+ * Ffvco = (pll_m + (pll_k / 65536)) * Ffref
+ * Ffref = 24MHz / pll_p
+ *
+ * Freq can also be rewritten as:
+ * Freq = Ffvco / 2^(pll_s)
+ * = ((pll_m + (pll_k / 65536)) * Ffref) / 2^(pll_s)
+ * = (pll_m * Ffref) / 2^(pll_s) + ((pll_k / 65536) * Ffref) / 2^(pll_s)
+ * = output_m + output_k
+ *
+ * Every parameter has been determined at this
+ * point, but pll_k.
+ *
+ * Considering that:
+ * limits->k.min <= pll_k <= limits->k.max
+ * Then:
+ * -0.5 <= (pll_k / 65536) < 0.5
+ * Therefore:
+ * -Ffref / (2 * 2^(pll_s)) <= output_k < Ffref / (2 * 2^(pll_s))
+ */
+
+ /* Compute output M component (in mHz) */
+ output_m = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(p.m, fref) * MILLI,
+ divider);
+ /* Compute range for output K (in mHz) */
+ output_k_range = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(fref, MILLI),
+ 2 * divider);
+ /*
+ * No point in continuing if we can't achieve
+ * the desired frequency
+ */
+ if (freq_millihz < (output_m - output_k_range) ||
+ freq_millihz >= (output_m + output_k_range)) {
+ continue;
+ }
+
+ /*
+ * Compute the K component
+ *
+ * Since:
+ * Freq = output_m + output_k
+ * Then:
+ * output_k = Freq - output_m
+ * = ((pll_k / 65536) * Ffref) / 2^(pll_s)
+ * Therefore:
+ * pll_k = (output_k * 65536 * 2^(pll_s)) / Ffref
+ */
+ output_k = freq_millihz - output_m;
+ pll_k = div_s64(output_k * 65536ULL * divider,
+ fref);
+ pll_k = DIV_S64_ROUND_CLOSEST(pll_k, MILLI);
+
+ /* Validate K value within allowed limits */
+ if (pll_k < limits->k.min ||
+ pll_k > limits->k.max)
+ continue;
+
+ p.k = pll_k;
+
+ /* Compute (Ffvco * 65536) */
+ fvco = mul_u32_u32(p.m * 65536 + p.k, fref);
+ if (fvco < mul_u32_u32(limits->fvco.min, 65536) ||
+ fvco > mul_u32_u32(limits->fvco.max, 65536))
+ continue;
+
+ /* PLL_M component of (output * 65536 * PLL_P) */
+ output = mul_u32_u32(p.m * 65536, RZ_V2H_OSC_CLK_IN_MEGA);
+ /* PLL_K component of (output * 65536 * PLL_P) */
+ output += p.k * RZ_V2H_OSC_CLK_IN_MEGA;
+ /* Make it in mHz */
+ output *= MILLI;
+ output = DIV_U64_ROUND_CLOSEST(output, 65536 * p.p * divider);
+
+ /* Check output frequency against limits */
+ if (output < fout_min_millihz ||
+ output > fout_max_millihz)
+ continue;
+
+ 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(best.error_millihz) > abs(p.error_millihz))
+ best = p;
+ }
+ }
+ }
+
+ /* If no valid parameters were found, return false */
+ if (best.error_millihz == S64_MAX)
+ return false;
+
+ *pars = best;
+ return true;
+}
+
+/*
+ * rzv2h_get_pll_div_pars - Finds the best combination of PLL parameters
+ * and divider value for a given frequency.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters and
+ * divider values will be stored
+ * @divider: Divider value to be applied to the PLL output
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) where
+ * the divider value is already known. See rzv2h_get_pll_pars() for more details
+ * on how the PLL parameters are calculated.
+ */
+static __maybe_unused bool
+rzv2h_get_pll_div_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars, u8 divider,
+ u64 freq_millihz)
+{
+ if (!rzv2h_get_pll_pars(limits, &pars->pll, freq_millihz * divider))
+ return false;
+
+ pars->div.divider_value = divider;
+ pars->div.freq_millihz = DIV_U64_ROUND_CLOSEST(pars->pll.freq_millihz, divider);
+ pars->div.error_millihz = freq_millihz - pars->div.freq_millihz;
+
+ return true;
+}
+
+/*
+ * rzv2h_get_pll_divs_pars - Finds the best combination of PLL parameters
+ * and divider value for a given frequency.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters and
+ * divider values will be stored
+ * @table: Pointer to the array of valid divider values
+ * @table_size: Size of the divider values array
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) and divider
+ * value to achieve the desired frequency. See rzv2h_get_pll_pars() for more details
+ * on how the PLL parameters are calculated.
+ *
+ * freq_millihz is the desired frequency generated by the PLL followed by a
+ * a gear.
+ */
+static __maybe_unused bool
+rzv2h_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)
+{
+ struct rzv2h_pll_div_pars p, best;
+
+ best.div.error_millihz = S64_MAX;
+ p.div.error_millihz = S64_MAX;
+ for (unsigned int i = 0; i < table_size; i++) {
+ if (!rzv2h_get_pll_div_pars(limits, &p, table[i], freq_millihz))
+ continue;
+
+ if (p.div.error_millihz == 0) {
+ *pars = p;
+ return true;
+ }
+
+ if (abs(best.div.error_millihz) > abs(p.div.error_millihz))
+ best = p;
+ }
+
+ if (best.div.error_millihz == S64_MAX)
+ return false;
+
+ *pars = best;
+ return true;
+}
+
+/*
+ * rzv2h_get_pll_dtable_pars - Finds the best combination of PLL parameters
+ * and divider value for a given frequency using a divider table.
+ *
+ * @limits: Pointer to the structure containing the limits for the PLL parameters
+ * @pars: Pointer to the structure where the best calculated PLL parameters and
+ * divider values will be stored
+ * @dtable: Pointer to the array of valid divider values
+ * @freq_millihz: Target output frequency in millihertz
+ *
+ * See rzv2h_get_pll_divs_pars() for more details on how the PLL
+ * parameters and divider values are calculated.
+ */
+static __maybe_unused bool
+rzv2h_get_pll_dtable_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const struct clk_div_table *dtable, u64 freq_millihz)
+{
+ const struct clk_div_table *div = dtable;
+ u8 table[RZV2H_MAX_DIV_TABLES] = { 0 };
+ unsigned int i = 0;
+
+ for (; div->div; div++) {
+ if (i >= RZV2H_MAX_DIV_TABLES)
+ return false;
+ table[i++] = div->div;
+ }
+
+ return rzv2h_get_pll_divs_pars(limits, pars, table, i, freq_millihz);
+}
+
+#endif /* __RENESAS_RZV2H_CPG_PLL_H__ */
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
2025-07-28 20:14 ` [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-08-15 5:14 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
2025-07-28 20:14 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N Prabhakar
` (3 subsequent siblings)
6 siblings, 2 replies; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add clock and reset entries for the DSI and LCDC peripherals.
Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v6->v7:
- Dropped passing plldsi_limits
v5->v6:
- Renamed CLK_DIV_PLLETH_LPCLK to CLK_CDIV4_PLLETH_LPCLK
- Renamed CLK_CSDIV_PLLETH_LPCLK to CLK_PLLETH_LPCLK_GEAR
- Renamed CLK_PLLDSI_SDIV2 to CLK_PLLDSI_GEAR
- Renamed plldsi_sdiv2 to plldsi_gear
v4->v5:
- No changes
v3->v4:
- No changes
v2->v3:
- Reverted CSDIV0_DIVCTL2() to use DDIV_PACK()
- Renamed plleth_lpclk_div4 -> cdiv4_plleth_lpclk
- Renamed plleth_lpclk -> plleth_lpclk_gear
v1->v2:
- Changed CSDIV0_DIVCTL2 to the NO_RMW
---
drivers/clk/renesas/r9a09g057-cpg.c | 62 +++++++++++++++++++++++++++++
drivers/clk/renesas/rzv2h-cpg.h | 3 ++
2 files changed, 65 insertions(+)
diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c
index f7de69a93de1..f94040f9d8a3 100644
--- a/drivers/clk/renesas/r9a09g057-cpg.c
+++ b/drivers/clk/renesas/r9a09g057-cpg.c
@@ -6,6 +6,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/clk/renesas-rzv2h-cpg-pll.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -30,6 +31,7 @@ enum clk_ids {
CLK_PLLCA55,
CLK_PLLVDO,
CLK_PLLETH,
+ CLK_PLLDSI,
CLK_PLLGPU,
/* Internal Core Clocks */
@@ -63,6 +65,9 @@ enum clk_ids {
CLK_SMUX2_GBE0_RXCLK,
CLK_SMUX2_GBE1_TXCLK,
CLK_SMUX2_GBE1_RXCLK,
+ CLK_CDIV4_PLLETH_LPCLK,
+ CLK_PLLETH_LPCLK_GEAR,
+ CLK_PLLDSI_GEAR,
CLK_PLLGPU_GEAR,
/* Module Clocks */
@@ -91,6 +96,26 @@ static const struct clk_div_table dtable_2_16[] = {
{0, 0},
};
+static const struct clk_div_table dtable_2_32[] = {
+ {0, 2},
+ {1, 4},
+ {2, 6},
+ {3, 8},
+ {4, 10},
+ {5, 12},
+ {6, 14},
+ {7, 16},
+ {8, 18},
+ {9, 20},
+ {10, 22},
+ {11, 24},
+ {12, 26},
+ {13, 28},
+ {14, 30},
+ {15, 32},
+ {0, 0},
+};
+
static const struct clk_div_table dtable_2_64[] = {
{0, 2},
{1, 4},
@@ -107,6 +132,17 @@ static const struct clk_div_table dtable_2_100[] = {
{0, 0},
};
+static const struct clk_div_table dtable_16_128[] = {
+ {0, 16},
+ {1, 32},
+ {2, 64},
+ {3, 128},
+ {0, 0},
+};
+
+RZV2H_CPG_PLL_DSI_LIMITS(rzv2h_cpg_pll_dsi_limits);
+#define PLLDSI PLL_PACK_LIMITS(0xc0, 1, 0, &rzv2h_cpg_pll_dsi_limits)
+
/* Mux clock tables */
static const char * const smux2_gbe0_rxclk[] = { ".plleth_gbe0", "et0_rxclk" };
static const char * const smux2_gbe0_txclk[] = { ".plleth_gbe0", "et0_txclk" };
@@ -128,6 +164,7 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = {
DEF_PLL(".pllca55", CLK_PLLCA55, CLK_QEXTAL, PLLCA55),
DEF_FIXED(".pllvdo", CLK_PLLVDO, CLK_QEXTAL, 105, 2),
DEF_FIXED(".plleth", CLK_PLLETH, CLK_QEXTAL, 125, 3),
+ DEF_PLLDSI(".plldsi", CLK_PLLDSI, CLK_QEXTAL, PLLDSI),
DEF_PLL(".pllgpu", CLK_PLLGPU, CLK_QEXTAL, PLLGPU),
/* Internal Core Clocks */
@@ -169,6 +206,12 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = {
DEF_SMUX(".smux2_gbe0_rxclk", CLK_SMUX2_GBE0_RXCLK, SSEL0_SELCTL3, smux2_gbe0_rxclk),
DEF_SMUX(".smux2_gbe1_txclk", CLK_SMUX2_GBE1_TXCLK, SSEL1_SELCTL0, smux2_gbe1_txclk),
DEF_SMUX(".smux2_gbe1_rxclk", CLK_SMUX2_GBE1_RXCLK, SSEL1_SELCTL1, smux2_gbe1_rxclk),
+ DEF_FIXED(".cdiv4_plleth_lpclk", CLK_CDIV4_PLLETH_LPCLK, CLK_PLLETH, 1, 4),
+ DEF_CSDIV(".plleth_lpclk_gear", CLK_PLLETH_LPCLK_GEAR, CLK_CDIV4_PLLETH_LPCLK,
+ CSDIV0_DIVCTL2, dtable_16_128),
+
+ DEF_PLLDSI_DIV(".plldsi_gear", CLK_PLLDSI_GEAR, CLK_PLLDSI,
+ CSDIV1_DIVCTL2, dtable_2_32),
DEF_DDIV(".pllgpu_gear", CLK_PLLGPU_GEAR, CLK_PLLGPU, CDDIV3_DIVCTL1, dtable_2_64),
@@ -366,6 +409,22 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = {
BUS_MSTOP(9, BIT(7))),
DEF_MOD("cru_3_pclk", CLK_PLLDTY_DIV16, 13, 13, 6, 29,
BUS_MSTOP(9, BIT(7))),
+ DEF_MOD("dsi_0_pclk", CLK_PLLDTY_DIV16, 14, 8, 7, 8,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("dsi_0_aclk", CLK_PLLDTY_ACPU_DIV2, 14, 9, 7, 9,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("dsi_0_vclk1", CLK_PLLDSI_GEAR, 14, 10, 7, 10,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("dsi_0_lpclk", CLK_PLLETH_LPCLK_GEAR, 14, 11, 7, 11,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("dsi_0_pllref_clk", CLK_QEXTAL, 14, 12, 7, 12,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("lcdc_0_clk_a", CLK_PLLDTY_ACPU_DIV2, 14, 13, 7, 13,
+ BUS_MSTOP(10, BIT(1) | BIT(2) | BIT(3))),
+ DEF_MOD("lcdc_0_clk_p", CLK_PLLDTY_DIV16, 14, 14, 7, 14,
+ BUS_MSTOP(10, BIT(1) | BIT(2) | BIT(3))),
+ DEF_MOD("lcdc_0_clk_d", CLK_PLLDSI_GEAR, 14, 15, 7, 15,
+ BUS_MSTOP(10, BIT(1) | BIT(2) | BIT(3))),
DEF_MOD("gpu_0_clk", CLK_PLLGPU_GEAR, 15, 0, 7, 16,
BUS_MSTOP(3, BIT(4))),
DEF_MOD("gpu_0_axi_clk", CLK_PLLDTY_ACPU_DIV2, 15, 1, 7, 17,
@@ -435,6 +494,9 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = {
DEF_RST(12, 14, 5, 31), /* CRU_3_PRESETN */
DEF_RST(12, 15, 6, 0), /* CRU_3_ARESETN */
DEF_RST(13, 0, 6, 1), /* CRU_3_S_RESETN */
+ DEF_RST(13, 7, 6, 8), /* DSI_0_PRESETN */
+ DEF_RST(13, 8, 6, 9), /* DSI_0_ARESETN */
+ DEF_RST(13, 12, 6, 13), /* LCDC_0_RESET_N */
DEF_RST(13, 13, 6, 14), /* GPU_0_RESETN */
DEF_RST(13, 14, 6, 15), /* GPU_0_AXI_RESETN */
DEF_RST(13, 15, 6, 16), /* GPU_0_ACE_RESETN */
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index 637803bc1e89..3dceb8dc5c13 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -126,6 +126,7 @@ struct fixed_mod_conf {
#define CPG_CDDIV3 (0x40C)
#define CPG_CDDIV4 (0x410)
#define CPG_CSDIV0 (0x500)
+#define CPG_CSDIV1 (0x504)
#define CDDIV0_DIVCTL1 DDIV_PACK(CPG_CDDIV0, 4, 3, 1)
#define CDDIV0_DIVCTL2 DDIV_PACK(CPG_CDDIV0, 8, 3, 2)
@@ -142,7 +143,9 @@ struct fixed_mod_conf {
#define CSDIV0_DIVCTL0 DDIV_PACK(CPG_CSDIV0, 0, 2, CSDIV_NO_MON)
#define CSDIV0_DIVCTL1 DDIV_PACK(CPG_CSDIV0, 4, 2, CSDIV_NO_MON)
+#define CSDIV0_DIVCTL2 DDIV_PACK(CPG_CSDIV0, 8, 2, CSDIV_NO_MON)
#define CSDIV0_DIVCTL3 DDIV_PACK_NO_RMW(CPG_CSDIV0, 12, 2, CSDIV_NO_MON)
+#define CSDIV1_DIVCTL2 DDIV_PACK(CPG_CSDIV1, 8, 4, CSDIV_NO_MON)
#define SSEL0_SELCTL2 SMUX_PACK(CPG_SSEL0, 8, 1)
#define SSEL0_SELCTL3 SMUX_PACK(CPG_SSEL0, 12, 1)
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
` (2 preceding siblings ...)
2025-07-28 20:14 ` [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-07-28 20:27 ` Lad, Prabhakar
2025-08-21 8:47 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas, dsi: " Tomi Valkeinen
2025-07-28 20:14 ` [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling Prabhakar
` (2 subsequent siblings)
6 siblings, 2 replies; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Krzysztof Kozlowski
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add the compatible string "renesas,r9a09g057-mipi-dsi" for the Renesas
RZ/V2H(P) (R9A09G057) SoC. While the MIPI DSI LINK registers are shared
with the RZ/G2L SoC, the D-PHY register layout differs. Additionally, the
RZ/V2H(P) uses only two resets compared to three on RZ/G2L, and requires
five clocks instead of six.
To reflect these hardware differences, update the binding schema to
support the reduced clock and reset requirements for RZ/V2H(P).
Since the RZ/V2N (R9A09G056) SoC integrates an identical DSI IP to
RZ/V2H(P), the same "renesas,r9a09g057-mipi-dsi" compatible string is
reused for RZ/V2N.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v6->v7:
- Renamed pllclk to pllrefclk
- Preserved the reviewed by tag from Geert and Krzysztof
v5->v6:
- Preserved the sort order (by part number).
- Added reviewed tag from Geert.
v4->v5:
- No changes
v3->v4:
- No changes
v2->v3:
- Collected reviewed tag from Krzysztof
v1->v2:
- Kept the sort order for schema validation
- Added `port@1: false` for RZ/V2H(P) SoC
---
.../bindings/display/bridge/renesas,dsi.yaml | 120 +++++++++++++-----
1 file changed, 91 insertions(+), 29 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
index 5a99d9b9635e..c20625b8425e 100644
--- a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
@@ -14,16 +14,21 @@ description: |
RZ/G2L alike family of SoC's. The encoder can operate in DSI mode, with
up to four data lanes.
-allOf:
- - $ref: /schemas/display/dsi-controller.yaml#
-
properties:
compatible:
- items:
+ oneOf:
+ - items:
+ - enum:
+ - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
+ - renesas,r9a07g054-mipi-dsi # RZ/V2L
+ - const: renesas,rzg2l-mipi-dsi
+
+ - items:
+ - const: renesas,r9a09g056-mipi-dsi # RZ/V2N
+ - const: renesas,r9a09g057-mipi-dsi
+
- enum:
- - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
- - renesas,r9a07g054-mipi-dsi # RZ/V2L
- - const: renesas,rzg2l-mipi-dsi
+ - renesas,r9a09g057-mipi-dsi # RZ/V2H(P)
reg:
maxItems: 1
@@ -49,34 +54,56 @@ properties:
- const: debug
clocks:
- items:
- - description: DSI D-PHY PLL multiplied clock
- - description: DSI D-PHY system clock
- - description: DSI AXI bus clock
- - description: DSI Register access clock
- - description: DSI Video clock
- - description: DSI D-PHY Escape mode transmit clock
+ oneOf:
+ - items:
+ - description: DSI D-PHY PLL multiplied clock
+ - description: DSI D-PHY system clock
+ - description: DSI AXI bus clock
+ - description: DSI Register access clock
+ - description: DSI Video clock
+ - description: DSI D-PHY Escape mode transmit clock
+ - items:
+ - description: DSI D-PHY PLL reference clock
+ - description: DSI AXI bus clock
+ - description: DSI Register access clock
+ - description: DSI Video clock
+ - description: DSI D-PHY Escape mode transmit clock
clock-names:
- items:
- - const: pllclk
- - const: sysclk
- - const: aclk
- - const: pclk
- - const: vclk
- - const: lpclk
+ oneOf:
+ - items:
+ - const: pllclk
+ - const: sysclk
+ - const: aclk
+ - const: pclk
+ - const: vclk
+ - const: lpclk
+ - items:
+ - const: pllrefclk
+ - const: aclk
+ - const: pclk
+ - const: vclk
+ - const: lpclk
resets:
- items:
- - description: MIPI_DSI_CMN_RSTB
- - description: MIPI_DSI_ARESET_N
- - description: MIPI_DSI_PRESET_N
+ oneOf:
+ - items:
+ - description: MIPI_DSI_CMN_RSTB
+ - description: MIPI_DSI_ARESET_N
+ - description: MIPI_DSI_PRESET_N
+ - items:
+ - description: MIPI_DSI_ARESET_N
+ - description: MIPI_DSI_PRESET_N
reset-names:
- items:
- - const: rst
- - const: arst
- - const: prst
+ oneOf:
+ - items:
+ - const: rst
+ - const: arst
+ - const: prst
+ - items:
+ - const: arst
+ - const: prst
power-domains:
maxItems: 1
@@ -130,6 +157,41 @@ required:
unevaluatedProperties: false
+allOf:
+ - $ref: ../dsi-controller.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g057-mipi-dsi
+ then:
+ properties:
+ clocks:
+ maxItems: 5
+
+ clock-names:
+ maxItems: 5
+
+ resets:
+ maxItems: 2
+
+ reset-names:
+ maxItems: 2
+ else:
+ properties:
+ clocks:
+ minItems: 6
+
+ clock-names:
+ minItems: 6
+
+ resets:
+ minItems: 3
+
+ reset-names:
+ minItems: 3
+
examples:
- |
#include <dt-bindings/clock/r9a07g044-cpg.h>
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
` (3 preceding siblings ...)
2025-07-28 20:14 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-08-21 8:52 ` Tomi Valkeinen
2025-07-28 20:14 ` [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
2025-08-19 13:48 ` [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas " Geert Uytterhoeven
6 siblings, 1 reply; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add LPCLK clock support in the RZ/G2L MIPI DSI driver via the optional
clock API. This clock is required by some SoCs like RZ/V2H(P) for proper
DPHY configuration, whereas it is absent on others like RZ/G2L.
Introduce a new `lpclk` field in the `rzg2l_mipi_dsi` structure and
conditionally acquire the "lpclk" clock using `devm_clk_get_optional()`
during probe. This allows LPCLK-aware SoCs to pass the clock via device
tree without impacting existing platforms.
Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v6->v7:
- New patch
Note, this patch was previously part of series [0].
[0] https://lore.kernel.org/all/20250609225630.502888-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 5 +++++
1 file changed, 5 insertions(+)
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 f87337c3cbb5..893a90c7a886 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -68,6 +68,7 @@ struct rzg2l_mipi_dsi {
struct drm_bridge *next_bridge;
struct clk *vclk;
+ struct clk *lpclk;
enum mipi_dsi_pixel_format format;
unsigned int num_data_lanes;
@@ -979,6 +980,10 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->vclk))
return PTR_ERR(dsi->vclk);
+ dsi->lpclk = devm_clk_get_optional(dsi->dev, "lpclk");
+ if (IS_ERR(dsi->lpclk))
+ return PTR_ERR(dsi->lpclk);
+
dsi->rstc = devm_reset_control_get_optional_exclusive(dsi->dev, "rst");
if (IS_ERR(dsi->rstc))
return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
` (4 preceding siblings ...)
2025-07-28 20:14 ` [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling Prabhakar
@ 2025-07-28 20:14 ` Prabhakar
2025-08-21 9:28 ` Tomi Valkeinen
2025-08-19 13:48 ` [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas " Geert Uytterhoeven
6 siblings, 1 reply; 26+ messages in thread
From: Prabhakar @ 2025-07-28 20:14 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Prabhakar, Fabrizio Castro, Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Add DSI support for Renesas RZ/V2H(P) SoC.
Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v6->v7:
- Used the new apis for calculating the PLLDSI
parameters in the DSI driver.
v5->v6:
- Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
PHYTCLKSETR_* and PHYTHSSETR_* macros.
- Replaced 10000000UL with 10 * MEGA
- Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
- Replaced `i -= 1;` with `i--;`
- Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
v4->v5:
- No changes
v3->v4
- In rzv2h_dphy_find_ulpsexit() made the array static const.
v2->v3:
- Simplifed V2H DSI timings array to save space
- Switched to use fsleep() instead of udelay()
v1->v2:
- Dropped unused macros
- Added missing LPCLK flag to rzv2h info
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
.../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
2 files changed, 379 insertions(+)
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 893a90c7a886..3b2f77665309 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk/renesas-rzv2h-cpg-pll.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
@@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
u64 *hsfreq_millihz);
unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
unsigned long mode_freq);
+ struct {
+ const struct rzv2h_pll_limits **limits;
+ const u8 *table;
+ const u8 table_size;
+ } cpg_plldsi;
u32 phy_reg_offset;
u32 link_reg_offset;
unsigned long min_dclk;
@@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
u8 features;
};
+struct rzv2h_dsi_mode_calc {
+ unsigned long mode_freq_khz;
+ struct rzv2h_pll_pars dsi_parameters;
+};
+
struct rzg2l_mipi_dsi {
struct device *dev;
void __iomem *mmio;
@@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
unsigned int lanes;
unsigned long mode_flags;
+ struct rzv2h_dsi_mode_calc mode_calc;
+
/* DCS buffer pointers when using external memory. */
dma_addr_t dcs_buf_phys;
u8 *dcs_buf_virt;
};
+static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
+ .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
+ .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
+ .m = { .min = 64, .max = 1023 },
+ .p = { .min = 1, .max = 4 },
+ .s = { .min = 0, .max = 5 },
+ .k = { .min = -32768, .max = 32767 },
+};
+
static inline struct rzg2l_mipi_dsi *
bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
{
@@ -194,6 +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
},
};
+struct rzv2h_mipi_dsi_timings {
+ const u8 *hsfreq;
+ u8 len;
+ u8 start_index;
+};
+
+enum {
+ TCLKPRPRCTL,
+ TCLKZEROCTL,
+ TCLKPOSTCTL,
+ TCLKTRAILCTL,
+ THSPRPRCTL,
+ THSZEROCTL,
+ THSTRAILCTL,
+ TLPXCTL,
+ THSEXITCTL,
+};
+
+static const u8 tclkprprctl[] = {
+ 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150,
+};
+
+static const u8 tclkzeroctl[] = {
+ 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
+ 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
+ 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
+ 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
+ 134, 137, 139, 141, 143, 146, 148, 150,
+};
+
+static const u8 tclkpostctl[] = {
+ 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150,
+};
+
+static const u8 tclktrailctl[] = {
+ 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150,
+};
+
+static const u8 thsprprctl[] = {
+ 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150,
+};
+
+static const u8 thszeroctl[] = {
+ 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
+ 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150,
+};
+
+static const u8 thstrailctl[] = {
+ 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150,
+};
+
+static const u8 tlpxctl[] = {
+ 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
+};
+
+static const u8 thsexitctl[] = {
+ 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
+ 95, 103, 111, 119, 127, 135, 143, 150,
+};
+
+static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
+ [TCLKPRPRCTL] = {
+ .hsfreq = tclkprprctl,
+ .len = ARRAY_SIZE(tclkprprctl),
+ .start_index = 0,
+ },
+ [TCLKZEROCTL] = {
+ .hsfreq = tclkzeroctl,
+ .len = ARRAY_SIZE(tclkzeroctl),
+ .start_index = 2,
+ },
+ [TCLKPOSTCTL] = {
+ .hsfreq = tclkpostctl,
+ .len = ARRAY_SIZE(tclkpostctl),
+ .start_index = 6,
+ },
+ [TCLKTRAILCTL] = {
+ .hsfreq = tclktrailctl,
+ .len = ARRAY_SIZE(tclktrailctl),
+ .start_index = 1,
+ },
+ [THSPRPRCTL] = {
+ .hsfreq = thsprprctl,
+ .len = ARRAY_SIZE(thsprprctl),
+ .start_index = 0,
+ },
+ [THSZEROCTL] = {
+ .hsfreq = thszeroctl,
+ .len = ARRAY_SIZE(thszeroctl),
+ .start_index = 0,
+ },
+ [THSTRAILCTL] = {
+ .hsfreq = thstrailctl,
+ .len = ARRAY_SIZE(thstrailctl),
+ .start_index = 3,
+ },
+ [TLPXCTL] = {
+ .hsfreq = tlpxctl,
+ .len = ARRAY_SIZE(tlpxctl),
+ .start_index = 0,
+ },
+ [THSEXITCTL] = {
+ .hsfreq = thsexitctl,
+ .len = ARRAY_SIZE(thsexitctl),
+ .start_index = 1,
+ },
+};
+
+static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
+{
+ static const unsigned long hsfreq[] = {
+ 1953125UL,
+ 3906250UL,
+ 7812500UL,
+ 15625000UL,
+ };
+ static const u16 ulpsexit[] = {49, 98, 195, 391};
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
+ if (freq <= hsfreq[i])
+ break;
+ }
+
+ if (i == ARRAY_SIZE(hsfreq))
+ i--;
+
+ return ulpsexit[i];
+}
+
+static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
+{
+ const struct rzv2h_mipi_dsi_timings *timings;
+ u16 i;
+
+ timings = &rzv2h_dsi_timings_tables[index];
+ for (i = 0; i < timings->len; i++) {
+ unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
+
+ if (freq <= hsfreq)
+ break;
+ }
+
+ if (i == timings->len)
+ i--;
+
+ return timings->start_index + i;
+};
+
static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
{
iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
@@ -318,6 +489,150 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
return 0;
}
+static unsigned int rzv2h_dphy_mode_clk_check(struct rzg2l_mipi_dsi *dsi,
+ unsigned long mode_freq)
+{
+ u64 hsfreq_millihz, mode_freq_hz, mode_freq_millihz;
+ struct rzv2h_pll_div_pars cpg_dsi_parameters;
+ struct rzv2h_pll_pars dsi_parameters;
+ bool parameters_found;
+ unsigned int bpp;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ mode_freq_hz = mul_u32_u32(mode_freq, KILO);
+ mode_freq_millihz = mode_freq_hz * MILLI;
+ parameters_found =
+ rzv2h_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[0],
+ &cpg_dsi_parameters,
+ dsi->info->cpg_plldsi.table,
+ dsi->info->cpg_plldsi.table_size,
+ mode_freq_millihz);
+ if (!parameters_found)
+ return MODE_CLOCK_RANGE;
+
+ hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.div.freq_millihz * bpp,
+ dsi->lanes);
+ parameters_found = rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
+ &dsi_parameters, hsfreq_millihz);
+ if (!parameters_found)
+ return MODE_CLOCK_RANGE;
+
+ if (abs(dsi_parameters.error_millihz) >= 500)
+ return MODE_CLOCK_RANGE;
+
+ memcpy(&dsi->mode_calc.dsi_parameters, &dsi_parameters, sizeof(dsi_parameters));
+ dsi->mode_calc.mode_freq_khz = mode_freq;
+
+ return MODE_OK;
+}
+
+static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+ u64 *hsfreq_millihz)
+{
+ struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+ unsigned long status;
+
+ if (dsi->mode_calc.mode_freq_khz != mode_freq) {
+ status = rzv2h_dphy_mode_clk_check(dsi, mode_freq);
+ if (status != MODE_OK) {
+ dev_err(dsi->dev, "No PLL parameters found for mode clk %lu\n",
+ mode_freq);
+ return -EINVAL;
+ }
+ }
+
+ *hsfreq_millihz = dsi_parameters->freq_millihz;
+
+ return 0;
+}
+
+static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+ u64 hsfreq_millihz)
+{
+ struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+ unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
+ u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
+ struct rzg2l_mipi_dsi_timings dphy_timings;
+ u16 ulpsexit;
+ u64 hsfreq;
+
+ hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz, MILLI);
+
+ if (dsi_parameters->freq_millihz == hsfreq_millihz)
+ goto parameters_found;
+
+ if (rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
+ dsi_parameters, hsfreq_millihz))
+ goto parameters_found;
+
+ dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n", hsfreq);
+ return -EINVAL;
+
+parameters_found:
+ dphy_timings.tclk_trail =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKTRAILCTL);
+ dphy_timings.tclk_post =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL);
+ dphy_timings.tclk_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL);
+ dphy_timings.tclk_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL);
+ dphy_timings.ths_exit =
+ rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL);
+ dphy_timings.ths_trail =
+ rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL);
+ dphy_timings.ths_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL);
+ dphy_timings.ths_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL);
+ dphy_timings.tlpx =
+ rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL);
+ ulpsexit = rzv2h_dphy_find_ulpsexit(lpclk_rate);
+
+ phytclksetr = FIELD_PREP(PHYTCLKSETR_TCLKTRAILCTL, dphy_timings.tclk_trail) |
+ FIELD_PREP(PHYTCLKSETR_TCLKPOSTCTL, dphy_timings.tclk_post) |
+ FIELD_PREP(PHYTCLKSETR_TCLKZEROCTL, dphy_timings.tclk_zero) |
+ FIELD_PREP(PHYTCLKSETR_TCLKPRPRCTL, dphy_timings.tclk_prepare);
+ phythssetr = FIELD_PREP(PHYTHSSETR_THSEXITCTL, dphy_timings.ths_exit) |
+ FIELD_PREP(PHYTHSSETR_THSTRAILCTL, dphy_timings.ths_trail) |
+ FIELD_PREP(PHYTHSSETR_THSZEROCTL, dphy_timings.ths_zero) |
+ FIELD_PREP(PHYTHSSETR_THSPRPRCTL, dphy_timings.ths_prepare);
+ phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~PHYTLPXSETR_TLPXCTL;
+ phytlpxsetr |= FIELD_PREP(PHYTLPXSETR_TLPXCTL, dphy_timings.tlpx);
+ phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
+ phycr |= FIELD_PREP(PHYCR_ULPSEXIT, ulpsexit);
+
+ /* Setting all D-PHY Timings Registers */
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTCLKSETR, phytclksetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTHSSETR, phythssetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYTLPXSETR, phytlpxsetr);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYCR, phycr);
+
+ rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET0R,
+ FIELD_PREP(PLLCLKSET0R_PLL_S, dsi_parameters->s) |
+ FIELD_PREP(PLLCLKSET0R_PLL_P, dsi_parameters->p) |
+ FIELD_PREP(PLLCLKSET0R_PLL_M, dsi_parameters->m));
+ rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R,
+ FIELD_PREP(PLLCLKSET1R_PLL_K, dsi_parameters->k));
+ fsleep(20);
+
+ rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
+ fsleep(500);
+
+ return 0;
+}
+
+static void rzv2h_mipi_dsi_dphy_startup_late_init(struct rzg2l_mipi_dsi *dsi)
+{
+ fsleep(220);
+ rzg2l_mipi_dsi_phy_write(dsi, PHYRSTR, PHYRSTR_PHYMRSTN);
+}
+
+static void rzv2h_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
+{
+ rzg2l_mipi_dsi_phy_write(dsi, PLLENR, 0);
+}
+
static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
const struct drm_display_mode *mode)
{
@@ -430,6 +745,9 @@ static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
case 18:
vich1ppsetr = VICH1PPSETR_DT_RGB18;
break;
+ case 16:
+ vich1ppsetr = VICH1PPSETR_DT_RGB16;
+ break;
}
if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) &&
@@ -1056,6 +1374,32 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
+RZV2H_CPG_PLL_DSI_LIMITS(rzv2h_cpg_pll_dsi_limits);
+
+static const struct rzv2h_pll_limits *rzv2h_plldsi_limits[] = {
+ &rzv2h_cpg_pll_dsi_limits,
+};
+
+static const u8 rzv2h_cpg_div_table[] = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
+};
+
+static const struct rzg2l_mipi_dsi_hw_info rzv2h_mipi_dsi_info = {
+ .dphy_init = rzv2h_mipi_dsi_dphy_init,
+ .dphy_startup_late_init = rzv2h_mipi_dsi_dphy_startup_late_init,
+ .dphy_exit = rzv2h_mipi_dsi_dphy_exit,
+ .dphy_mode_clk_check = rzv2h_dphy_mode_clk_check,
+ .dphy_conf_clks = rzv2h_dphy_conf_clks,
+ .cpg_plldsi.limits = rzv2h_plldsi_limits,
+ .cpg_plldsi.table = rzv2h_cpg_div_table,
+ .cpg_plldsi.table_size = ARRAY_SIZE(rzv2h_cpg_div_table),
+ .phy_reg_offset = 0x10000,
+ .link_reg_offset = 0,
+ .min_dclk = 5440,
+ .max_dclk = 187500,
+ .features = RZ_MIPI_DSI_FEATURE_16BPP,
+};
+
static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
.dphy_init = rzg2l_mipi_dsi_dphy_init,
.dphy_exit = rzg2l_mipi_dsi_dphy_exit,
@@ -1066,6 +1410,7 @@ static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
};
static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
+ { .compatible = "renesas,r9a09g057-mipi-dsi", .data = &rzv2h_mipi_dsi_info, },
{ .compatible = "renesas,rzg2l-mipi-dsi", .data = &rzg2l_mipi_dsi_info, },
{ /* sentinel */ }
};
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
index d8082a87d874..2bef20566648 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
@@ -40,6 +40,39 @@
#define DSIDPHYTIM3_THS_TRAIL(x) ((x) << 8)
#define DSIDPHYTIM3_THS_ZERO(x) ((x) << 0)
+/* RZ/V2H DPHY Registers */
+#define PLLENR 0x000
+#define PLLENR_PLLEN BIT(0)
+
+#define PHYRSTR 0x004
+#define PHYRSTR_PHYMRSTN BIT(0)
+
+#define PLLCLKSET0R 0x010
+#define PLLCLKSET0R_PLL_S GENMASK(2, 0)
+#define PLLCLKSET0R_PLL_P GENMASK(13, 8)
+#define PLLCLKSET0R_PLL_M GENMASK(25, 16)
+
+#define PLLCLKSET1R 0x014
+#define PLLCLKSET1R_PLL_K GENMASK(15, 0)
+
+#define PHYTCLKSETR 0x020
+#define PHYTCLKSETR_TCLKTRAILCTL GENMASK(7, 0)
+#define PHYTCLKSETR_TCLKPOSTCTL GENMASK(15, 8)
+#define PHYTCLKSETR_TCLKZEROCTL GENMASK(23, 16)
+#define PHYTCLKSETR_TCLKPRPRCTL GENMASK(31, 24)
+
+#define PHYTHSSETR 0x024
+#define PHYTHSSETR_THSEXITCTL GENMASK(7, 0)
+#define PHYTHSSETR_THSTRAILCTL GENMASK(15, 8)
+#define PHYTHSSETR_THSZEROCTL GENMASK(23, 16)
+#define PHYTHSSETR_THSPRPRCTL GENMASK(31, 24)
+
+#define PHYTLPXSETR 0x028
+#define PHYTLPXSETR_TLPXCTL GENMASK(7, 0)
+
+#define PHYCR 0x030
+#define PHYCR_ULPSEXIT GENMASK(9, 0)
+
/* --------------------------------------------------------*/
/* Link Status Register */
@@ -130,6 +163,7 @@
/* Video-Input Channel 1 Pixel Packet Set Register */
#define VICH1PPSETR 0x420
+#define VICH1PPSETR_DT_RGB16 (0x0e << 16)
#define VICH1PPSETR_DT_RGB18 (0x1e << 16)
#define VICH1PPSETR_DT_RGB18_LS (0x2e << 16)
#define VICH1PPSETR_DT_RGB24 (0x3e << 16)
--
2.50.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N
2025-07-28 20:14 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N Prabhakar
@ 2025-07-28 20:27 ` Lad, Prabhakar
2025-08-19 10:40 ` Geert Uytterhoeven
2025-08-21 8:47 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas, dsi: " Tomi Valkeinen
1 sibling, 1 reply; 26+ messages in thread
From: Lad, Prabhakar @ 2025-07-28 20:27 UTC (permalink / raw)
To: Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Krzysztof Kozlowski
Hi All,
On Mon, Jul 28, 2025 at 9:14 PM Prabhakar <prabhakar.csengg@gmail.com> wrote:
>
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add the compatible string "renesas,r9a09g057-mipi-dsi" for the Renesas
> RZ/V2H(P) (R9A09G057) SoC. While the MIPI DSI LINK registers are shared
> with the RZ/G2L SoC, the D-PHY register layout differs. Additionally, the
> RZ/V2H(P) uses only two resets compared to three on RZ/G2L, and requires
> five clocks instead of six.
>
> To reflect these hardware differences, update the binding schema to
> support the reduced clock and reset requirements for RZ/V2H(P).
>
> Since the RZ/V2N (R9A09G056) SoC integrates an identical DSI IP to
> RZ/V2H(P), the same "renesas,r9a09g057-mipi-dsi" compatible string is
> reused for RZ/V2N.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v6->v7:
> - Renamed pllclk to pllrefclk
> - Preserved the reviewed by tag from Geert and Krzysztof
>
- Included support for RZ/V2N in the same patch
- Updated commit description.
I missed mentioning the above.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 26+ messages in thread
* RE: [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
@ 2025-08-15 5:11 ` Biju Das
2025-08-19 13:05 ` Geert Uytterhoeven
1 sibling, 0 replies; 26+ messages in thread
From: Biju Das @ 2025-08-15 5:11 UTC (permalink / raw)
To: Prabhakar, Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong,
Robert Foss, laurent.pinchart, Jonas Karlman, Jernej Skrabec,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, magnus.damm
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, Fabrizio Castro, Tommaso Merciai,
Prabhakar Mahadev Lad
> -----Original Message-----
> From: Prabhakar <prabhakar.csengg@gmail.com>
> Sent: 28 July 2025 21:15
> Subject: [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll
>
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add a two-bit "instance" member to struct pll and extend the PLL_PACK() macro to accept an instance
> parameter. Initialize all existing PLL definitions with instance 0 to preserve legacy behavior. This
> change enables support for SoCs with multiple PLL instances (for example, RZ/G3E we have two PLL DSIs).
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* RE: [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-07-28 20:14 ` [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
@ 2025-08-15 5:13 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
1 sibling, 0 replies; 26+ messages in thread
From: Biju Das @ 2025-08-15 5:13 UTC (permalink / raw)
To: Prabhakar, Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong,
Robert Foss, laurent.pinchart, Jonas Karlman, Jernej Skrabec,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, magnus.damm
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, Fabrizio Castro, Tommaso Merciai,
Prabhakar Mahadev Lad
Hi Prabhakar,
> -----Original Message-----
> From: Prabhakar <prabhakar.csengg@gmail.com>
> Sent: 28 July 2025 21:15
> Subject: [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks
>
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add support for PLLDSI and PLLDSI divider clocks.
>
> Introduce the `renesas-rzv2h-cpg-pll.h` header to centralize and share PLLDSI related data structures,
> limits, and algorithms between the
> RZ/V2H(P) CPG and DSI drivers.
>
> The DSI PLL is functionally similar to the CPG's PLLDSI, but has slightly different parameter limits
> and omits the programmable divider present in CPG. To ensure precise frequency calculations, especially
> for milliHz-level accuracy needed by the DSI driver, the shared algorithm allows both drivers to
> compute PLL parameters consistently using the same logic and input clock.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* RE: [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-07-28 20:14 ` [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
@ 2025-08-15 5:14 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
1 sibling, 0 replies; 26+ messages in thread
From: Biju Das @ 2025-08-15 5:14 UTC (permalink / raw)
To: Prabhakar, Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong,
Robert Foss, laurent.pinchart, Jonas Karlman, Jernej Skrabec,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, magnus.damm
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, Fabrizio Castro, Tommaso Merciai,
Prabhakar Mahadev Lad
Hi Prabhakar,
Thanks for the patch.
> -----Original Message-----
> From: Prabhakar <prabhakar.csengg@gmail.com>
> Sent: 28 July 2025 21:15
> Subject: [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
>
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add clock and reset entries for the DSI and LCDC peripherals.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Cheers,
Biju
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N
2025-07-28 20:27 ` Lad, Prabhakar
@ 2025-08-19 10:40 ` Geert Uytterhoeven
0 siblings, 0 replies; 26+ messages in thread
From: Geert Uytterhoeven @ 2025-08-19 10:40 UTC (permalink / raw)
To: Lad, Prabhakar
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar, Krzysztof Kozlowski
On Mon, 28 Jul 2025 at 22:28, Lad, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> On Mon, Jul 28, 2025 at 9:14 PM Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add the compatible string "renesas,r9a09g057-mipi-dsi" for the Renesas
> > RZ/V2H(P) (R9A09G057) SoC. While the MIPI DSI LINK registers are shared
> > with the RZ/G2L SoC, the D-PHY register layout differs. Additionally, the
> > RZ/V2H(P) uses only two resets compared to three on RZ/G2L, and requires
> > five clocks instead of six.
> >
> > To reflect these hardware differences, update the binding schema to
> > support the reduced clock and reset requirements for RZ/V2H(P).
> >
> > Since the RZ/V2N (R9A09G056) SoC integrates an identical DSI IP to
> > RZ/V2H(P), the same "renesas,r9a09g057-mipi-dsi" compatible string is
> > reused for RZ/V2N.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > ---
> > v6->v7:
> > - Renamed pllclk to pllrefclk
> > - Preserved the reviewed by tag from Geert and Krzysztof
> >
> - Included support for RZ/V2N in the same patch
> - Updated commit description.
>
> I missed mentioning the above.
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
2025-08-15 5:11 ` Biju Das
@ 2025-08-19 13:05 ` Geert Uytterhoeven
1 sibling, 0 replies; 26+ messages in thread
From: Geert Uytterhoeven @ 2025-08-19 13:05 UTC (permalink / raw)
To: Prabhakar
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
On Mon, 28 Jul 2025 at 22:14, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add a two-bit "instance" member to struct pll and extend the PLL_PACK()
> macro to accept an instance parameter. Initialize all existing PLL
> definitions with instance 0 to preserve legacy behavior. This change
> enables support for SoCs with multiple PLL instances (for example,
> RZ/G3E we have two PLL DSIs).
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-07-28 20:14 ` [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
2025-08-15 5:13 ` Biju Das
@ 2025-08-19 13:14 ` Geert Uytterhoeven
2025-08-20 21:10 ` Lad, Prabhakar
1 sibling, 1 reply; 26+ messages in thread
From: Geert Uytterhoeven @ 2025-08-19 13:14 UTC (permalink / raw)
To: Prabhakar
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
Hi Prabhakar,
On Mon, 28 Jul 2025 at 22:14, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add support for PLLDSI and PLLDSI divider clocks.
>
> Introduce the `renesas-rzv2h-cpg-pll.h` header to centralize and share
> PLLDSI related data structures, limits, and algorithms between the
> RZ/V2H(P) CPG and DSI drivers.
>
> The DSI PLL is functionally similar to the CPG's PLLDSI, but has slightly
> different parameter limits and omits the programmable divider present in
> CPG. To ensure precise frequency calculations, especially for milliHz-level
> accuracy needed by the DSI driver, the shared algorithm allows both drivers
> to compute PLL parameters consistently using the same logic and input
> clock.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
> v6->v7:
> - Made struct rzv2h_pll_limits more modular also added Ffout limits
> - Made the alogirithm modular and also added apis based on the
> needs for lvds and dpi
Thanks for the update!
> --- a/drivers/clk/renesas/rzv2h-cpg.c
> +++ b/drivers/clk/renesas/rzv2h-cpg.c
> +static struct rzv2h_pll_dsi_info *rzv2h_get_pll_dsi_info(struct clk_hw *pll_dsi,
> + struct rzv2h_cpg_priv *priv)
> +{
> + struct pll_clk *pll_clk = to_pll(pll_dsi);
> +
> + return &priv->pll_dsi_info[pll_clk->pll.instance];
> +}
This (very simple helper) is used twice, while there are two (almost
three) other locations where it is open-coded. Perhaps just open-code
it everywhere?
> @@ -246,7 +526,8 @@ static const struct clk_ops rzv2h_cpg_pll_ops = {
> static struct clk * __init
> rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
> struct rzv2h_cpg_priv *priv,
> - const struct clk_ops *ops)
> + const struct clk_ops *ops,
> + bool is_plldsi)
No need for this parameter...
> {
> struct device *dev = priv->dev;
> struct clk_init_data init;
> @@ -263,6 +544,10 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
> if (!pll_clk)
> return ERR_PTR(-ENOMEM);
>
> + if (is_plldsi)
... as you can just test "core->type == CLK_TYPE_PLLDSI" here.
> + priv->pll_dsi_info[core->cfg.pll.instance].pll_dsi_limits =
> + core->cfg.pll.limits;
> +
> parent_name = __clk_get_name(parent);
> init.name = core->name;
> init.ops = ops;
The rest LGTM, so
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-07-28 20:14 ` [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
2025-08-15 5:14 ` Biju Das
@ 2025-08-19 13:14 ` Geert Uytterhoeven
1 sibling, 0 replies; 26+ messages in thread
From: Geert Uytterhoeven @ 2025-08-19 13:14 UTC (permalink / raw)
To: Prabhakar
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
On Mon, 28 Jul 2025 at 22:14, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add clock and reset entries for the DSI and LCDC peripherals.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
` (5 preceding siblings ...)
2025-07-28 20:14 ` [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
@ 2025-08-19 13:48 ` Geert Uytterhoeven
2025-08-19 14:54 ` Laurent Pinchart
6 siblings, 1 reply; 26+ messages in thread
From: Geert Uytterhoeven @ 2025-08-19 13:48 UTC (permalink / raw)
To: Prabhakar
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
Hi all,
On Mon, 28 Jul 2025 at 22:14, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> This patch series adds DU/DSI clocks and provides support for the
> MIPI DSI interface on the RZ/V2H(P) SoC. It was originally part of
> series [0], but has now been split into 6 patches due to dependencies
> on the clock driver, making it easier to review and merge.
Thanks for your series!
> Lad Prabhakar (6):
> clk: renesas: rzv2h-cpg: Add instance field to struct pll
> clk: renesas: rzv2h-cpg: Add support for DSI clocks
> clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
> dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and
> RZ/V2N
> drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
> drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
On the renesas-clk side, I am (almost) totally happy with this.
Any feedback from the renesas-drm side?
The last patch depends on a header file introduced by the second patch,
so I will need to provide an immutable branch containing the first
two patches (probably/hopefully based on v8).
Thanks!
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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC
2025-08-19 13:48 ` [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas " Geert Uytterhoeven
@ 2025-08-19 14:54 ` Laurent Pinchart
2025-08-20 21:03 ` Lad, Prabhakar
0 siblings, 1 reply; 26+ messages in thread
From: Laurent Pinchart @ 2025-08-19 14:54 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Prabhakar, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
On Tue, Aug 19, 2025 at 03:48:08PM +0200, Geert Uytterhoeven wrote:
> On Mon, 28 Jul 2025 at 22:14, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > This patch series adds DU/DSI clocks and provides support for the
> > MIPI DSI interface on the RZ/V2H(P) SoC. It was originally part of
> > series [0], but has now been split into 6 patches due to dependencies
> > on the clock driver, making it easier to review and merge.
>
> Thanks for your series!
>
> > Lad Prabhakar (6):
> > clk: renesas: rzv2h-cpg: Add instance field to struct pll
> > clk: renesas: rzv2h-cpg: Add support for DSI clocks
> > clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
> > dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and
> > RZ/V2N
> > drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
> > drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
>
> On the renesas-clk side, I am (almost) totally happy with this.
> Any feedback from the renesas-drm side?
Tomi told me he added the patches on this review list.
> The last patch depends on a header file introduced by the second patch,
> so I will need to provide an immutable branch containing the first
> two patches (probably/hopefully based on v8).
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC
2025-08-19 14:54 ` Laurent Pinchart
@ 2025-08-20 21:03 ` Lad, Prabhakar
0 siblings, 0 replies; 26+ messages in thread
From: Lad, Prabhakar @ 2025-08-20 21:03 UTC (permalink / raw)
To: Laurent Pinchart, Geert Uytterhoeven, Tomi Valkeinen
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
Hi All,
On Tue, Aug 19, 2025 at 3:54 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Tue, Aug 19, 2025 at 03:48:08PM +0200, Geert Uytterhoeven wrote:
> > On Mon, 28 Jul 2025 at 22:14, Prabhakar wrote:
> > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > >
> > > This patch series adds DU/DSI clocks and provides support for the
> > > MIPI DSI interface on the RZ/V2H(P) SoC. It was originally part of
> > > series [0], but has now been split into 6 patches due to dependencies
> > > on the clock driver, making it easier to review and merge.
> >
> > Thanks for your series!
> >
> > > Lad Prabhakar (6):
> > > clk: renesas: rzv2h-cpg: Add instance field to struct pll
> > > clk: renesas: rzv2h-cpg: Add support for DSI clocks
> > > clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
> > > dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and
> > > RZ/V2N
> > > drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
> > > drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
> >
> > On the renesas-clk side, I am (almost) totally happy with this.
> > Any feedback from the renesas-drm side?
>
> Tomi told me he added the patches on this review list.
>
Shall I send a v8 fixing review comments from Geert or wait for Tomi to review?
> > The last patch depends on a header file introduced by the second patch,
> > so I will need to provide an immutable branch containing the first
> > two patches (probably/hopefully based on v8).
>
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-08-19 13:14 ` Geert Uytterhoeven
@ 2025-08-20 21:10 ` Lad, Prabhakar
0 siblings, 0 replies; 26+ messages in thread
From: Lad, Prabhakar @ 2025-08-20 21:10 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm, dri-devel, devicetree,
linux-kernel, linux-renesas-soc, linux-clk, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
Hi Geert,
Thank you for the review.
On Tue, Aug 19, 2025 at 2:14 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Prabhakar,
>
> On Mon, 28 Jul 2025 at 22:14, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add support for PLLDSI and PLLDSI divider clocks.
> >
> > Introduce the `renesas-rzv2h-cpg-pll.h` header to centralize and share
> > PLLDSI related data structures, limits, and algorithms between the
> > RZ/V2H(P) CPG and DSI drivers.
> >
> > The DSI PLL is functionally similar to the CPG's PLLDSI, but has slightly
> > different parameter limits and omits the programmable divider present in
> > CPG. To ensure precise frequency calculations, especially for milliHz-level
> > accuracy needed by the DSI driver, the shared algorithm allows both drivers
> > to compute PLL parameters consistently using the same logic and input
> > clock.
> >
> > Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > ---
> > v6->v7:
> > - Made struct rzv2h_pll_limits more modular also added Ffout limits
> > - Made the alogirithm modular and also added apis based on the
> > needs for lvds and dpi
>
> Thanks for the update!
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
>
> > +static struct rzv2h_pll_dsi_info *rzv2h_get_pll_dsi_info(struct clk_hw *pll_dsi,
> > + struct rzv2h_cpg_priv *priv)
> > +{
> > + struct pll_clk *pll_clk = to_pll(pll_dsi);
> > +
> > + return &priv->pll_dsi_info[pll_clk->pll.instance];
> > +}
>
> This (very simple helper) is used twice, while there are two (almost
> three) other locations where it is open-coded. Perhaps just open-code
> it everywhere?
>
Sure, I will open code it.
> > @@ -246,7 +526,8 @@ static const struct clk_ops rzv2h_cpg_pll_ops = {
> > static struct clk * __init
> > rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
> > struct rzv2h_cpg_priv *priv,
> > - const struct clk_ops *ops)
> > + const struct clk_ops *ops,
> > + bool is_plldsi)
>
> No need for this parameter...
>
> > {
> > struct device *dev = priv->dev;
> > struct clk_init_data init;
> > @@ -263,6 +544,10 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core,
> > if (!pll_clk)
> > return ERR_PTR(-ENOMEM);
> >
> > + if (is_plldsi)
>
> ... as you can just test "core->type == CLK_TYPE_PLLDSI" here.
>
Agreed, thanks for the pointer.
Cheers,
Prabhakar
> > + priv->pll_dsi_info[core->cfg.pll.instance].pll_dsi_limits =
> > + core->cfg.pll.limits;
> > +
> > parent_name = __clk_get_name(parent);
> > init.name = core->name;
> > init.ops = ops;
>
> The rest LGTM, so
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
> 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
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/6] dt-bindings: display: bridge: renesas, dsi: Document RZ/V2H(P) and RZ/V2N
2025-07-28 20:14 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N Prabhakar
2025-07-28 20:27 ` Lad, Prabhakar
@ 2025-08-21 8:47 ` Tomi Valkeinen
1 sibling, 0 replies; 26+ messages in thread
From: Tomi Valkeinen @ 2025-08-21 8:47 UTC (permalink / raw)
To: Prabhakar
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Krzysztof Kozlowski, Geert Uytterhoeven, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, Biju Das, Magnus Damm
Hi,
On 28/07/2025 23:14, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add the compatible string "renesas,r9a09g057-mipi-dsi" for the Renesas
> RZ/V2H(P) (R9A09G057) SoC. While the MIPI DSI LINK registers are shared
> with the RZ/G2L SoC, the D-PHY register layout differs. Additionally, the
> RZ/V2H(P) uses only two resets compared to three on RZ/G2L, and requires
> five clocks instead of six.
>
> To reflect these hardware differences, update the binding schema to
> support the reduced clock and reset requirements for RZ/V2H(P).
>
> Since the RZ/V2N (R9A09G056) SoC integrates an identical DSI IP to
> RZ/V2H(P), the same "renesas,r9a09g057-mipi-dsi" compatible string is
> reused for RZ/V2N.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v6->v7:
> - Renamed pllclk to pllrefclk
> - Preserved the reviewed by tag from Geert and Krzysztof
>
> v5->v6:
> - Preserved the sort order (by part number).
> - Added reviewed tag from Geert.
>
> v4->v5:
> - No changes
>
> v3->v4:
> - No changes
>
> v2->v3:
> - Collected reviewed tag from Krzysztof
>
> v1->v2:
> - Kept the sort order for schema validation
> - Added `port@1: false` for RZ/V2H(P) SoC
> ---
> .../bindings/display/bridge/renesas,dsi.yaml | 120 +++++++++++++-----
> 1 file changed, 91 insertions(+), 29 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
> index 5a99d9b9635e..c20625b8425e 100644
> --- a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
> +++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
> @@ -14,16 +14,21 @@ description: |
> RZ/G2L alike family of SoC's. The encoder can operate in DSI mode, with
> up to four data lanes.
>
> -allOf:
> - - $ref: /schemas/display/dsi-controller.yaml#
> -
> properties:
> compatible:
> - items:
> + oneOf:
> + - items:
> + - enum:
> + - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
> + - renesas,r9a07g054-mipi-dsi # RZ/V2L
> + - const: renesas,rzg2l-mipi-dsi
> +
> + - items:
> + - const: renesas,r9a09g056-mipi-dsi # RZ/V2N
> + - const: renesas,r9a09g057-mipi-dsi
> +
> - enum:
> - - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
> - - renesas,r9a07g054-mipi-dsi # RZ/V2L
> - - const: renesas,rzg2l-mipi-dsi
> + - renesas,r9a09g057-mipi-dsi # RZ/V2H(P)
>
> reg:
> maxItems: 1
> @@ -49,34 +54,56 @@ properties:
> - const: debug
>
> clocks:
> - items:
> - - description: DSI D-PHY PLL multiplied clock
> - - description: DSI D-PHY system clock
> - - description: DSI AXI bus clock
> - - description: DSI Register access clock
> - - description: DSI Video clock
> - - description: DSI D-PHY Escape mode transmit clock
> + oneOf:
> + - items:
> + - description: DSI D-PHY PLL multiplied clock
> + - description: DSI D-PHY system clock
> + - description: DSI AXI bus clock
> + - description: DSI Register access clock
> + - description: DSI Video clock
> + - description: DSI D-PHY Escape mode transmit clock
> + - items:
> + - description: DSI D-PHY PLL reference clock
> + - description: DSI AXI bus clock
> + - description: DSI Register access clock
> + - description: DSI Video clock
> + - description: DSI D-PHY Escape mode transmit clock
Is this style ok in the bindings? I thought it's necessary to "if" these
kind of blocks based on the compatible.
> clock-names:
> - items:
> - - const: pllclk
> - - const: sysclk
> - - const: aclk
> - - const: pclk
> - - const: vclk
> - - const: lpclk
> + oneOf:
> + - items:
> + - const: pllclk
> + - const: sysclk
> + - const: aclk
> + - const: pclk
> + - const: vclk
> + - const: lpclk
> + - items:
> + - const: pllrefclk
> + - const: aclk
> + - const: pclk
> + - const: vclk
> + - const: lpclk
>
> resets:
> - items:
> - - description: MIPI_DSI_CMN_RSTB
> - - description: MIPI_DSI_ARESET_N
> - - description: MIPI_DSI_PRESET_N
> + oneOf:
> + - items:
> + - description: MIPI_DSI_CMN_RSTB
> + - description: MIPI_DSI_ARESET_N
> + - description: MIPI_DSI_PRESET_N
> + - items:
> + - description: MIPI_DSI_ARESET_N
> + - description: MIPI_DSI_PRESET_N
>
> reset-names:
> - items:
> - - const: rst
> - - const: arst
> - - const: prst
> + oneOf:
> + - items:
> + - const: rst
> + - const: arst
> + - const: prst
> + - items:
> + - const: arst
> + - const: prst
>
> power-domains:
> maxItems: 1
> @@ -130,6 +157,41 @@ required:
>
> unevaluatedProperties: false
>
> +allOf:
> + - $ref: ../dsi-controller.yaml#
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: renesas,r9a09g057-mipi-dsi
> + then:
> + properties:
> + clocks:
> + maxItems: 5
> +
> + clock-names:
> + maxItems: 5
> +
> + resets:
> + maxItems: 2
> +
> + reset-names:
> + maxItems: 2
> + else:
> + properties:
> + clocks:
> + minItems: 6
> +
> + clock-names:
> + minItems: 6
> +
> + resets:
> + minItems: 3
> +
> + reset-names:
> + minItems: 3
> +
Oh... So this one does the selection based on the compatible. And if we
get a new SoC which doesn't fit into the above classification model,
we'll have to restructure the binding (or add a new one)?
Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Tomi
> examples:
> - |
> #include <dt-bindings/clock/r9a07g044-cpg.h>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling
2025-07-28 20:14 ` [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling Prabhakar
@ 2025-08-21 8:52 ` Tomi Valkeinen
0 siblings, 0 replies; 26+ messages in thread
From: Tomi Valkeinen @ 2025-08-21 8:52 UTC (permalink / raw)
To: Prabhakar
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Hi,
On 28/07/2025 23:14, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add LPCLK clock support in the RZ/G2L MIPI DSI driver via the optional
> clock API. This clock is required by some SoCs like RZ/V2H(P) for proper
> DPHY configuration, whereas it is absent on others like RZ/G2L.
In the DT binding lpclk is present for all SoCs. Is that an error in the
binding, then? And if I read the binding correctly, it's mandatory for
all SoCs, so why is it optional in the driver?
Tomi
> Introduce a new `lpclk` field in the `rzg2l_mipi_dsi` structure and
> conditionally acquire the "lpclk" clock using `devm_clk_get_optional()`
> during probe. This allows LPCLK-aware SoCs to pass the clock via device
> tree without impacting existing platforms.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> ---
> v6->v7:
> - New patch
> Note, this patch was previously part of series [0].
> [0] https://lore.kernel.org/all/20250609225630.502888-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
> ---
> drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> 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 f87337c3cbb5..893a90c7a886 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> @@ -68,6 +68,7 @@ struct rzg2l_mipi_dsi {
> struct drm_bridge *next_bridge;
>
> struct clk *vclk;
> + struct clk *lpclk;
>
> enum mipi_dsi_pixel_format format;
> unsigned int num_data_lanes;
> @@ -979,6 +980,10 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
> if (IS_ERR(dsi->vclk))
> return PTR_ERR(dsi->vclk);
>
> + dsi->lpclk = devm_clk_get_optional(dsi->dev, "lpclk");
> + if (IS_ERR(dsi->lpclk))
> + return PTR_ERR(dsi->lpclk);
> +
> dsi->rstc = devm_reset_control_get_optional_exclusive(dsi->dev, "rst");
> if (IS_ERR(dsi->rstc))
> return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-07-28 20:14 ` [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
@ 2025-08-21 9:28 ` Tomi Valkeinen
2025-08-22 7:01 ` Biju Das
2025-08-27 12:41 ` Lad, Prabhakar
0 siblings, 2 replies; 26+ messages in thread
From: Tomi Valkeinen @ 2025-08-21 9:28 UTC (permalink / raw)
To: Prabhakar
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Hi,
On 28/07/2025 23:14, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add DSI support for Renesas RZ/V2H(P) SoC.
I think a bit longer desc would be in order, as this is not just a "add
a new compatible string" patch, but we have new registers and functions.
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
> v6->v7:
> - Used the new apis for calculating the PLLDSI
> parameters in the DSI driver.
>
> v5->v6:
> - Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
> PHYTCLKSETR_* and PHYTHSSETR_* macros.
> - Replaced 10000000UL with 10 * MEGA
> - Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
> - Replaced `i -= 1;` with `i--;`
> - Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
> RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
>
> v4->v5:
> - No changes
>
> v3->v4
> - In rzv2h_dphy_find_ulpsexit() made the array static const.
>
> v2->v3:
> - Simplifed V2H DSI timings array to save space
> - Switched to use fsleep() instead of udelay()
>
> v1->v2:
> - Dropped unused macros
> - Added missing LPCLK flag to rzv2h info
> ---
> .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
> .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> 2 files changed, 379 insertions(+)
>
> 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 893a90c7a886..3b2f77665309 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> @@ -7,6 +7,7 @@
>
> #include <linux/bitfield.h>
> #include <linux/clk.h>
> +#include <linux/clk/renesas-rzv2h-cpg-pll.h>
> #include <linux/delay.h>
> #include <linux/dma-mapping.h>
> #include <linux/io.h>
> @@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
> u64 *hsfreq_millihz);
> unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> unsigned long mode_freq);
> + struct {
> + const struct rzv2h_pll_limits **limits;
> + const u8 *table;
> + const u8 table_size;
> + } cpg_plldsi;
> u32 phy_reg_offset;
> u32 link_reg_offset;
> unsigned long min_dclk;
> @@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
> u8 features;
> };
>
> +struct rzv2h_dsi_mode_calc {
> + unsigned long mode_freq_khz;
> + struct rzv2h_pll_pars dsi_parameters;
> +};
> +
> struct rzg2l_mipi_dsi {
> struct device *dev;
> void __iomem *mmio;
> @@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
> unsigned int lanes;
> unsigned long mode_flags;
>
> + struct rzv2h_dsi_mode_calc mode_calc;
> +
> /* DCS buffer pointers when using external memory. */
> dma_addr_t dcs_buf_phys;
> u8 *dcs_buf_virt;
> };
>
> +static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
> + .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
> + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
> + .m = { .min = 64, .max = 1023 },
> + .p = { .min = 1, .max = 4 },
> + .s = { .min = 0, .max = 5 },
> + .k = { .min = -32768, .max = 32767 },
> +};
> +
> static inline struct rzg2l_mipi_dsi *
> bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
> {
> @@ -194,6 +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> },
> };
>
> +struct rzv2h_mipi_dsi_timings {
> + const u8 *hsfreq;
> + u8 len;
> + u8 start_index;
> +};
> +
> +enum {
> + TCLKPRPRCTL,
> + TCLKZEROCTL,
> + TCLKPOSTCTL,
> + TCLKTRAILCTL,
> + THSPRPRCTL,
> + THSZEROCTL,
> + THSTRAILCTL,
> + TLPXCTL,
> + THSEXITCTL,
> +};
> +
> +static const u8 tclkprprctl[] = {
> + 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150,
> +};
> +
> +static const u8 tclkzeroctl[] = {
> + 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
> + 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
> + 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
> + 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
> + 134, 137, 139, 141, 143, 146, 148, 150,
> +};
> +
> +static const u8 tclkpostctl[] = {
> + 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150,
> +};
> +
> +static const u8 tclktrailctl[] = {
> + 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150,
> +};
> +
> +static const u8 thsprprctl[] = {
> + 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150,
> +};
> +
> +static const u8 thszeroctl[] = {
> + 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
> + 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150,
> +};
> +
> +static const u8 thstrailctl[] = {
> + 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150,
> +};
> +
> +static const u8 tlpxctl[] = {
> + 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
> +};
> +
> +static const u8 thsexitctl[] = {
> + 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
> + 95, 103, 111, 119, 127, 135, 143, 150,
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
> + [TCLKPRPRCTL] = {
> + .hsfreq = tclkprprctl,
> + .len = ARRAY_SIZE(tclkprprctl),
> + .start_index = 0,
> + },
> + [TCLKZEROCTL] = {
> + .hsfreq = tclkzeroctl,
> + .len = ARRAY_SIZE(tclkzeroctl),
> + .start_index = 2,
> + },
> + [TCLKPOSTCTL] = {
> + .hsfreq = tclkpostctl,
> + .len = ARRAY_SIZE(tclkpostctl),
> + .start_index = 6,
> + },
> + [TCLKTRAILCTL] = {
> + .hsfreq = tclktrailctl,
> + .len = ARRAY_SIZE(tclktrailctl),
> + .start_index = 1,
> + },
> + [THSPRPRCTL] = {
> + .hsfreq = thsprprctl,
> + .len = ARRAY_SIZE(thsprprctl),
> + .start_index = 0,
> + },
> + [THSZEROCTL] = {
> + .hsfreq = thszeroctl,
> + .len = ARRAY_SIZE(thszeroctl),
> + .start_index = 0,
> + },
> + [THSTRAILCTL] = {
> + .hsfreq = thstrailctl,
> + .len = ARRAY_SIZE(thstrailctl),
> + .start_index = 3,
> + },
> + [TLPXCTL] = {
> + .hsfreq = tlpxctl,
> + .len = ARRAY_SIZE(tlpxctl),
> + .start_index = 0,
> + },
> + [THSEXITCTL] = {
> + .hsfreq = thsexitctl,
> + .len = ARRAY_SIZE(thsexitctl),
> + .start_index = 1,
> + },
> +};
> +
> +static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
> +{
> + static const unsigned long hsfreq[] = {
> + 1953125UL,
> + 3906250UL,
> + 7812500UL,
> + 15625000UL,
> + };
> + static const u16 ulpsexit[] = {49, 98, 195, 391};
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
> + if (freq <= hsfreq[i])
> + break;
> + }
> +
> + if (i == ARRAY_SIZE(hsfreq))
> + i--;
> +
> + return ulpsexit[i];
> +}
> +
> +static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
> +{
> + const struct rzv2h_mipi_dsi_timings *timings;
> + u16 i;
> +
> + timings = &rzv2h_dsi_timings_tables[index];
> + for (i = 0; i < timings->len; i++) {
> + unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
> +
> + if (freq <= hsfreq)
> + break;
> + }
> +
> + if (i == timings->len)
> + i--;
> +
> + return timings->start_index + i;
> +};
I have to say I really don't like this... In the minimum, the method how
this works has to be explained in a comment. These values can't really
be calculated? If we really have to deal with hardcoded values and with
that table from the docs, I would say that just replicate the table in
the driver (i.e. a struct that represents one row of the table), instead
of the method in this driver.
Or was this method added based on earlier feedback, for v3? I see
"Simplifed V2H DSI timings array to save space" in the change log. If
so, at least document it clearly.
> +
> static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
> {
> iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
> @@ -318,6 +489,150 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
> return 0;
> }
>
> +static unsigned int rzv2h_dphy_mode_clk_check(struct rzg2l_mipi_dsi *dsi,
> + unsigned long mode_freq)
> +{
> + u64 hsfreq_millihz, mode_freq_hz, mode_freq_millihz;
> + struct rzv2h_pll_div_pars cpg_dsi_parameters;
> + struct rzv2h_pll_pars dsi_parameters;
> + bool parameters_found;
> + unsigned int bpp;
> +
> + bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> + mode_freq_hz = mul_u32_u32(mode_freq, KILO);
> + mode_freq_millihz = mode_freq_hz * MILLI;
> + parameters_found =
> + rzv2h_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[0],
> + &cpg_dsi_parameters,
> + dsi->info->cpg_plldsi.table,
> + dsi->info->cpg_plldsi.table_size,
> + mode_freq_millihz);
> + if (!parameters_found)
> + return MODE_CLOCK_RANGE;
> +
> + hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.div.freq_millihz * bpp,
> + dsi->lanes);
> + parameters_found = rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
> + &dsi_parameters, hsfreq_millihz);
> + if (!parameters_found)
> + return MODE_CLOCK_RANGE;
> +
> + if (abs(dsi_parameters.error_millihz) >= 500)
> + return MODE_CLOCK_RANGE;
> +
> + memcpy(&dsi->mode_calc.dsi_parameters, &dsi_parameters, sizeof(dsi_parameters));
> + dsi->mode_calc.mode_freq_khz = mode_freq;
> +
> + return MODE_OK;
> +}
> +
> +static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
> + u64 *hsfreq_millihz)
> +{
> + struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
> + unsigned long status;
> +
> + if (dsi->mode_calc.mode_freq_khz != mode_freq) {
> + status = rzv2h_dphy_mode_clk_check(dsi, mode_freq);
> + if (status != MODE_OK) {
> + dev_err(dsi->dev, "No PLL parameters found for mode clk %lu\n",
> + mode_freq);
> + return -EINVAL;
> + }
> + }
> +
> + *hsfreq_millihz = dsi_parameters->freq_millihz;
> +
> + return 0;
> +}
> +
> +static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
> + u64 hsfreq_millihz)
> +{
> + struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
> + unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
> + u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
> + struct rzg2l_mipi_dsi_timings dphy_timings;
> + u16 ulpsexit;
> + u64 hsfreq;
> +
> + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz, MILLI);
> +
> + if (dsi_parameters->freq_millihz == hsfreq_millihz)
> + goto parameters_found;
> +
> + if (rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
> + dsi_parameters, hsfreq_millihz))
> + goto parameters_found;
> +
> + dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n", hsfreq);
> + return -EINVAL;
> +
> +parameters_found:
Maybe:
if (dsi_parameters->freq_millihz != hsfreq_millihz &&
!rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits, dsi_parameters,
hsfreq_millihz)) {
dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n",
hsfreq);
return -EINVAL;
}
keeps the flow a bit cleaner.
> + dphy_timings.tclk_trail =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKTRAILCTL);
> + dphy_timings.tclk_post =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL);
> + dphy_timings.tclk_zero =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL);
> + dphy_timings.tclk_prepare =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL);
> + dphy_timings.ths_exit =
> + rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL);
> + dphy_timings.ths_trail =
> + rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL);
> + dphy_timings.ths_zero =
> + rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL);
> + dphy_timings.ths_prepare =
> + rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL);
> + dphy_timings.tlpx =
> + rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL);
> + ulpsexit = rzv2h_dphy_find_ulpsexit(lpclk_rate);
> +
> + phytclksetr = FIELD_PREP(PHYTCLKSETR_TCLKTRAILCTL, dphy_timings.tclk_trail) |
> + FIELD_PREP(PHYTCLKSETR_TCLKPOSTCTL, dphy_timings.tclk_post) |
> + FIELD_PREP(PHYTCLKSETR_TCLKZEROCTL, dphy_timings.tclk_zero) |
> + FIELD_PREP(PHYTCLKSETR_TCLKPRPRCTL, dphy_timings.tclk_prepare);
> + phythssetr = FIELD_PREP(PHYTHSSETR_THSEXITCTL, dphy_timings.ths_exit) |
> + FIELD_PREP(PHYTHSSETR_THSTRAILCTL, dphy_timings.ths_trail) |
> + FIELD_PREP(PHYTHSSETR_THSZEROCTL, dphy_timings.ths_zero) |
> + FIELD_PREP(PHYTHSSETR_THSPRPRCTL, dphy_timings.ths_prepare);
> + phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~PHYTLPXSETR_TLPXCTL;
> + phytlpxsetr |= FIELD_PREP(PHYTLPXSETR_TLPXCTL, dphy_timings.tlpx);
> + phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
> + phycr |= FIELD_PREP(PHYCR_ULPSEXIT, ulpsexit);
> +
> + /* Setting all D-PHY Timings Registers */
> + rzg2l_mipi_dsi_phy_write(dsi, PHYTCLKSETR, phytclksetr);
> + rzg2l_mipi_dsi_phy_write(dsi, PHYTHSSETR, phythssetr);
> + rzg2l_mipi_dsi_phy_write(dsi, PHYTLPXSETR, phytlpxsetr);
> + rzg2l_mipi_dsi_phy_write(dsi, PHYCR, phycr);
> +
> + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET0R,
> + FIELD_PREP(PLLCLKSET0R_PLL_S, dsi_parameters->s) |
> + FIELD_PREP(PLLCLKSET0R_PLL_P, dsi_parameters->p) |
> + FIELD_PREP(PLLCLKSET0R_PLL_M, dsi_parameters->m));
> + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R,
> + FIELD_PREP(PLLCLKSET1R_PLL_K, dsi_parameters->k));
> + fsleep(20);
Why sleep? Sleeps should (almost) always have a comment, explaining what
it is waiting for.
> +
> + rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
> + fsleep(500);
> +
> + return 0;
> +}
> +
> +static void rzv2h_mipi_dsi_dphy_startup_late_init(struct rzg2l_mipi_dsi *dsi)
> +{
> + fsleep(220);
Especially sleeps like this, where the upper side is "open ended".
> + rzg2l_mipi_dsi_phy_write(dsi, PHYRSTR, PHYRSTR_PHYMRSTN);
> +}
> +
Tomi
^ permalink raw reply [flat|nested] 26+ messages in thread
* RE: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-08-21 9:28 ` Tomi Valkeinen
@ 2025-08-22 7:01 ` Biju Das
2025-08-22 7:05 ` Tomi Valkeinen
2025-08-27 12:41 ` Lad, Prabhakar
1 sibling, 1 reply; 26+ messages in thread
From: Biju Das @ 2025-08-22 7:01 UTC (permalink / raw)
To: Tomi Valkeinen, Prabhakar
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, Fabrizio Castro, Tommaso Merciai,
Prabhakar Mahadev Lad, Geert Uytterhoeven, Andrzej Hajda,
Neil Armstrong, Robert Foss, laurent.pinchart, Jonas Karlman,
Jernej Skrabec, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, magnus.damm
Hi Tomi,
> -----Original Message-----
> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Tomi Valkeinen
> Sent: 21 August 2025 10:29
> Subject: Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
>
> Hi,
>
> On 28/07/2025 23:14, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add DSI support for Renesas RZ/V2H(P) SoC.
>
> I think a bit longer desc would be in order, as this is not just a "add a new compatible string" patch,
> but we have new registers and functions.
>
> > Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > ---
> > v6->v7:
> > - Used the new apis for calculating the PLLDSI
> > parameters in the DSI driver.
> >
> > v5->v6:
> > - Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
> > PHYTCLKSETR_* and PHYTHSSETR_* macros.
> > - Replaced 10000000UL with 10 * MEGA
> > - Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
> > - Replaced `i -= 1;` with `i--;`
> > - Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
> > RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
> > RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
> > RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
> >
> > v4->v5:
> > - No changes
> >
> > v3->v4
> > - In rzv2h_dphy_find_ulpsexit() made the array static const.
> >
> > v2->v3:
> > - Simplifed V2H DSI timings array to save space
> > - Switched to use fsleep() instead of udelay()
> >
> > v1->v2:
> > - Dropped unused macros
> > - Added missing LPCLK flag to rzv2h info
> > ---
> > .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
> > .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> > 2 files changed, 379 insertions(+)
> >
> > 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 893a90c7a886..3b2f77665309 100644
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -7,6 +7,7 @@
> >
> > #include <linux/bitfield.h>
> > #include <linux/clk.h>
> > +#include <linux/clk/renesas-rzv2h-cpg-pll.h>
> > #include <linux/delay.h>
> > #include <linux/dma-mapping.h>
> > #include <linux/io.h>
> > @@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
> > u64 *hsfreq_millihz);
> > unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> > unsigned long mode_freq);
> > + struct {
> > + const struct rzv2h_pll_limits **limits;
> > + const u8 *table;
> > + const u8 table_size;
> > + } cpg_plldsi;
> > u32 phy_reg_offset;
> > u32 link_reg_offset;
> > unsigned long min_dclk;
> > @@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
> > u8 features;
> > };
> >
> > +struct rzv2h_dsi_mode_calc {
> > + unsigned long mode_freq_khz;
> > + struct rzv2h_pll_pars dsi_parameters; };
> > +
> > struct rzg2l_mipi_dsi {
> > struct device *dev;
> > void __iomem *mmio;
> > @@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
> > unsigned int lanes;
> > unsigned long mode_flags;
> >
> > + struct rzv2h_dsi_mode_calc mode_calc;
> > +
> > /* DCS buffer pointers when using external memory. */
> > dma_addr_t dcs_buf_phys;
> > u8 *dcs_buf_virt;
> > };
> >
> > +static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
> > + .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
> > + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
> > + .m = { .min = 64, .max = 1023 },
> > + .p = { .min = 1, .max = 4 },
> > + .s = { .min = 0, .max = 5 },
> > + .k = { .min = -32768, .max = 32767 }, };
> > +
> > static inline struct rzg2l_mipi_dsi *
> > bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge) { @@ -194,6
> > +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> > },
> > };
> >
> > +struct rzv2h_mipi_dsi_timings {
> > + const u8 *hsfreq;
> > + u8 len;
> > + u8 start_index;
> > +};
> > +
> > +enum {
> > + TCLKPRPRCTL,
> > + TCLKZEROCTL,
> > + TCLKPOSTCTL,
> > + TCLKTRAILCTL,
> > + THSPRPRCTL,
> > + THSZEROCTL,
> > + THSTRAILCTL,
> > + TLPXCTL,
> > + THSEXITCTL,
> > +};
> > +
> > +static const u8 tclkprprctl[] = {
> > + 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150, };
> > +
> > +static const u8 tclkzeroctl[] = {
> > + 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
> > + 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
> > + 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
> > + 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
> > + 134, 137, 139, 141, 143, 146, 148, 150, };
> > +
> > +static const u8 tclkpostctl[] = {
> > + 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150, };
> > +
> > +static const u8 tclktrailctl[] = {
> > + 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150, };
> > +
> > +static const u8 thsprprctl[] = {
> > + 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150, };
> > +
> > +static const u8 thszeroctl[] = {
> > + 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
> > + 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150, };
> > +
> > +static const u8 thstrailctl[] = {
> > + 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150, };
> > +
> > +static const u8 tlpxctl[] = {
> > + 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
> > +};
> > +
> > +static const u8 thsexitctl[] = {
> > + 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
> > + 95, 103, 111, 119, 127, 135, 143, 150, };
> > +
> > +static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
> > + [TCLKPRPRCTL] = {
> > + .hsfreq = tclkprprctl,
> > + .len = ARRAY_SIZE(tclkprprctl),
> > + .start_index = 0,
> > + },
> > + [TCLKZEROCTL] = {
> > + .hsfreq = tclkzeroctl,
> > + .len = ARRAY_SIZE(tclkzeroctl),
> > + .start_index = 2,
> > + },
> > + [TCLKPOSTCTL] = {
> > + .hsfreq = tclkpostctl,
> > + .len = ARRAY_SIZE(tclkpostctl),
> > + .start_index = 6,
> > + },
> > + [TCLKTRAILCTL] = {
> > + .hsfreq = tclktrailctl,
> > + .len = ARRAY_SIZE(tclktrailctl),
> > + .start_index = 1,
> > + },
> > + [THSPRPRCTL] = {
> > + .hsfreq = thsprprctl,
> > + .len = ARRAY_SIZE(thsprprctl),
> > + .start_index = 0,
> > + },
> > + [THSZEROCTL] = {
> > + .hsfreq = thszeroctl,
> > + .len = ARRAY_SIZE(thszeroctl),
> > + .start_index = 0,
> > + },
> > + [THSTRAILCTL] = {
> > + .hsfreq = thstrailctl,
> > + .len = ARRAY_SIZE(thstrailctl),
> > + .start_index = 3,
> > + },
> > + [TLPXCTL] = {
> > + .hsfreq = tlpxctl,
> > + .len = ARRAY_SIZE(tlpxctl),
> > + .start_index = 0,
> > + },
> > + [THSEXITCTL] = {
> > + .hsfreq = thsexitctl,
> > + .len = ARRAY_SIZE(thsexitctl),
> > + .start_index = 1,
> > + },
> > +};
> > +
> > +static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq) {
> > + static const unsigned long hsfreq[] = {
> > + 1953125UL,
> > + 3906250UL,
> > + 7812500UL,
> > + 15625000UL,
> > + };
> > + static const u16 ulpsexit[] = {49, 98, 195, 391};
> > + unsigned int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
> > + if (freq <= hsfreq[i])
> > + break;
> > + }
> > +
> > + if (i == ARRAY_SIZE(hsfreq))
> > + i--;
> > +
> > + return ulpsexit[i];
> > +}
> > +
> > +static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
> > +{
> > + const struct rzv2h_mipi_dsi_timings *timings;
> > + u16 i;
> > +
> > + timings = &rzv2h_dsi_timings_tables[index];
> > + for (i = 0; i < timings->len; i++) {
> > + unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
> > +
> > + if (freq <= hsfreq)
> > + break;
> > + }
> > +
> > + if (i == timings->len)
> > + i--;
> > +
> > + return timings->start_index + i;
> > +};
>
> I have to say I really don't like this... In the minimum, the method how this works has to be explained
> in a comment. These values can't really be calculated? If we really have to deal with hardcoded values
> and with that table from the docs, I would say that just replicate the table in the driver (i.e. a
> struct that represents one row of the table), instead of the method in this driver.
>
> Or was this method added based on earlier feedback, for v3? I see "Simplifed V2H DSI timings array to
> save space" in the change log. If so, at least document it clearly.
It was added based on v3 based on my comment on v2[1].
If you see each table entries it is now just 1 byte vs 10 bytes (u8 vs (u64 + u16)).
So, it is saving considerable space by using this methos. Maybe we need to document this
[1] https://lore.kernel.org/all/TY3PR01MB113462CC30072B670E23EC7F586B12@TY3PR01MB11346.jpnprd01.prod.outlook.com/
Cheers,
Biju
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-08-22 7:01 ` Biju Das
@ 2025-08-22 7:05 ` Tomi Valkeinen
2025-08-27 12:34 ` Lad, Prabhakar
0 siblings, 1 reply; 26+ messages in thread
From: Tomi Valkeinen @ 2025-08-22 7:05 UTC (permalink / raw)
To: Biju Das, Prabhakar
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-clk@vger.kernel.org, Fabrizio Castro, Tommaso Merciai,
Prabhakar Mahadev Lad, Geert Uytterhoeven, Andrzej Hajda,
Neil Armstrong, Robert Foss, laurent.pinchart, Jonas Karlman,
Jernej Skrabec, David Airlie, Simona Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michael Turquette,
Stephen Boyd, magnus.damm
Hi,
On 22/08/2025 10:01, Biju Das wrote:
> Hi Tomi,
>
>> -----Original Message-----
>> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Tomi Valkeinen
>> Sent: 21 August 2025 10:29
>> Subject: Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
>>
>> Hi,
>>
>> On 28/07/2025 23:14, Prabhakar wrote:
>>> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>>>
>>> Add DSI support for Renesas RZ/V2H(P) SoC.
>>
>> I think a bit longer desc would be in order, as this is not just a "add a new compatible string" patch,
>> but we have new registers and functions.
>>
>>> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
>>> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
>>> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>>> ---
>>> v6->v7:
>>> - Used the new apis for calculating the PLLDSI
>>> parameters in the DSI driver.
>>>
>>> v5->v6:
>>> - Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
>>> PHYTCLKSETR_* and PHYTHSSETR_* macros.
>>> - Replaced 10000000UL with 10 * MEGA
>>> - Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
>>> - Replaced `i -= 1;` with `i--;`
>>> - Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
>>> RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
>>> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
>>> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
>>>
>>> v4->v5:
>>> - No changes
>>>
>>> v3->v4
>>> - In rzv2h_dphy_find_ulpsexit() made the array static const.
>>>
>>> v2->v3:
>>> - Simplifed V2H DSI timings array to save space
>>> - Switched to use fsleep() instead of udelay()
>>>
>>> v1->v2:
>>> - Dropped unused macros
>>> - Added missing LPCLK flag to rzv2h info
>>> ---
>>> .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
>>> .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
>>> 2 files changed, 379 insertions(+)
>>>
>>> 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 893a90c7a886..3b2f77665309 100644
>>> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
>>> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
>>> @@ -7,6 +7,7 @@
>>>
>>> #include <linux/bitfield.h>
>>> #include <linux/clk.h>
>>> +#include <linux/clk/renesas-rzv2h-cpg-pll.h>
>>> #include <linux/delay.h>
>>> #include <linux/dma-mapping.h>
>>> #include <linux/io.h>
>>> @@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
>>> u64 *hsfreq_millihz);
>>> unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
>>> unsigned long mode_freq);
>>> + struct {
>>> + const struct rzv2h_pll_limits **limits;
>>> + const u8 *table;
>>> + const u8 table_size;
>>> + } cpg_plldsi;
>>> u32 phy_reg_offset;
>>> u32 link_reg_offset;
>>> unsigned long min_dclk;
>>> @@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
>>> u8 features;
>>> };
>>>
>>> +struct rzv2h_dsi_mode_calc {
>>> + unsigned long mode_freq_khz;
>>> + struct rzv2h_pll_pars dsi_parameters; };
>>> +
>>> struct rzg2l_mipi_dsi {
>>> struct device *dev;
>>> void __iomem *mmio;
>>> @@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
>>> unsigned int lanes;
>>> unsigned long mode_flags;
>>>
>>> + struct rzv2h_dsi_mode_calc mode_calc;
>>> +
>>> /* DCS buffer pointers when using external memory. */
>>> dma_addr_t dcs_buf_phys;
>>> u8 *dcs_buf_virt;
>>> };
>>>
>>> +static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
>>> + .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
>>> + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
>>> + .m = { .min = 64, .max = 1023 },
>>> + .p = { .min = 1, .max = 4 },
>>> + .s = { .min = 0, .max = 5 },
>>> + .k = { .min = -32768, .max = 32767 }, };
>>> +
>>> static inline struct rzg2l_mipi_dsi *
>>> bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge) { @@ -194,6
>>> +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
>>> },
>>> };
>>>
>>> +struct rzv2h_mipi_dsi_timings {
>>> + const u8 *hsfreq;
>>> + u8 len;
>>> + u8 start_index;
>>> +};
>>> +
>>> +enum {
>>> + TCLKPRPRCTL,
>>> + TCLKZEROCTL,
>>> + TCLKPOSTCTL,
>>> + TCLKTRAILCTL,
>>> + THSPRPRCTL,
>>> + THSZEROCTL,
>>> + THSTRAILCTL,
>>> + TLPXCTL,
>>> + THSEXITCTL,
>>> +};
>>> +
>>> +static const u8 tclkprprctl[] = {
>>> + 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150, };
>>> +
>>> +static const u8 tclkzeroctl[] = {
>>> + 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
>>> + 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
>>> + 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
>>> + 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
>>> + 134, 137, 139, 141, 143, 146, 148, 150, };
>>> +
>>> +static const u8 tclkpostctl[] = {
>>> + 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150, };
>>> +
>>> +static const u8 tclktrailctl[] = {
>>> + 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150, };
>>> +
>>> +static const u8 thsprprctl[] = {
>>> + 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150, };
>>> +
>>> +static const u8 thszeroctl[] = {
>>> + 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
>>> + 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150, };
>>> +
>>> +static const u8 thstrailctl[] = {
>>> + 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150, };
>>> +
>>> +static const u8 tlpxctl[] = {
>>> + 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
>>> +};
>>> +
>>> +static const u8 thsexitctl[] = {
>>> + 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
>>> + 95, 103, 111, 119, 127, 135, 143, 150, };
>>> +
>>> +static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
>>> + [TCLKPRPRCTL] = {
>>> + .hsfreq = tclkprprctl,
>>> + .len = ARRAY_SIZE(tclkprprctl),
>>> + .start_index = 0,
>>> + },
>>> + [TCLKZEROCTL] = {
>>> + .hsfreq = tclkzeroctl,
>>> + .len = ARRAY_SIZE(tclkzeroctl),
>>> + .start_index = 2,
>>> + },
>>> + [TCLKPOSTCTL] = {
>>> + .hsfreq = tclkpostctl,
>>> + .len = ARRAY_SIZE(tclkpostctl),
>>> + .start_index = 6,
>>> + },
>>> + [TCLKTRAILCTL] = {
>>> + .hsfreq = tclktrailctl,
>>> + .len = ARRAY_SIZE(tclktrailctl),
>>> + .start_index = 1,
>>> + },
>>> + [THSPRPRCTL] = {
>>> + .hsfreq = thsprprctl,
>>> + .len = ARRAY_SIZE(thsprprctl),
>>> + .start_index = 0,
>>> + },
>>> + [THSZEROCTL] = {
>>> + .hsfreq = thszeroctl,
>>> + .len = ARRAY_SIZE(thszeroctl),
>>> + .start_index = 0,
>>> + },
>>> + [THSTRAILCTL] = {
>>> + .hsfreq = thstrailctl,
>>> + .len = ARRAY_SIZE(thstrailctl),
>>> + .start_index = 3,
>>> + },
>>> + [TLPXCTL] = {
>>> + .hsfreq = tlpxctl,
>>> + .len = ARRAY_SIZE(tlpxctl),
>>> + .start_index = 0,
>>> + },
>>> + [THSEXITCTL] = {
>>> + .hsfreq = thsexitctl,
>>> + .len = ARRAY_SIZE(thsexitctl),
>>> + .start_index = 1,
>>> + },
>>> +};
>>> +
>>> +static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq) {
>>> + static const unsigned long hsfreq[] = {
>>> + 1953125UL,
>>> + 3906250UL,
>>> + 7812500UL,
>>> + 15625000UL,
>>> + };
>>> + static const u16 ulpsexit[] = {49, 98, 195, 391};
>>> + unsigned int i;
>>> +
>>> + for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
>>> + if (freq <= hsfreq[i])
>>> + break;
>>> + }
>>> +
>>> + if (i == ARRAY_SIZE(hsfreq))
>>> + i--;
>>> +
>>> + return ulpsexit[i];
>>> +}
>>> +
>>> +static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
>>> +{
>>> + const struct rzv2h_mipi_dsi_timings *timings;
>>> + u16 i;
>>> +
>>> + timings = &rzv2h_dsi_timings_tables[index];
>>> + for (i = 0; i < timings->len; i++) {
>>> + unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
>>> +
>>> + if (freq <= hsfreq)
>>> + break;
>>> + }
>>> +
>>> + if (i == timings->len)
>>> + i--;
>>> +
>>> + return timings->start_index + i;
>>> +};
>>
>> I have to say I really don't like this... In the minimum, the method how this works has to be explained
>> in a comment. These values can't really be calculated? If we really have to deal with hardcoded values
>> and with that table from the docs, I would say that just replicate the table in the driver (i.e. a
>> struct that represents one row of the table), instead of the method in this driver.
>>
>> Or was this method added based on earlier feedback, for v3? I see "Simplifed V2H DSI timings array to
>> save space" in the change log. If so, at least document it clearly.
>
> It was added based on v3 based on my comment on v2[1].
>
> If you see each table entries it is now just 1 byte vs 10 bytes (u8 vs (u64 + u16)).
>
> So, it is saving considerable space by using this methos. Maybe we need to document this
>
> [1] https://lore.kernel.org/all/TY3PR01MB113462CC30072B670E23EC7F586B12@TY3PR01MB11346.jpnprd01.prod.outlook.com/
Ok. I guess it's fine if it's documented. It wasn't super hard to
reverse engineer it, but a short comment would have saved me the time =).
But still, where do the numbers come from? Is there a formula that was
used to generate the values in the doc? Maybe the Renesas HW people
know? If yes, it'd be much better to use that formula. These are normal
DSI timings, based on the hs clock, so I think they should be calculable.
Tomi
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-08-22 7:05 ` Tomi Valkeinen
@ 2025-08-27 12:34 ` Lad, Prabhakar
0 siblings, 0 replies; 26+ messages in thread
From: Lad, Prabhakar @ 2025-08-27 12:34 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Biju Das, dri-devel@lists.freedesktop.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-renesas-soc@vger.kernel.org, linux-clk@vger.kernel.org,
Fabrizio Castro, Tommaso Merciai, Prabhakar Mahadev Lad,
Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
laurent.pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, magnus.damm
Hi Tomi,
On Fri, Aug 22, 2025 at 8:05 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
>
> Hi,
>
> On 22/08/2025 10:01, Biju Das wrote:
> > Hi Tomi,
> >
> >> -----Original Message-----
> >> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Tomi Valkeinen
> >> Sent: 21 August 2025 10:29
> >> Subject: Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
> >>
> >> Hi,
> >>
> >> On 28/07/2025 23:14, Prabhakar wrote:
> >>> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >>>
> >>> Add DSI support for Renesas RZ/V2H(P) SoC.
> >>
> >> I think a bit longer desc would be in order, as this is not just a "add a new compatible string" patch,
> >> but we have new registers and functions.
> >>
> >>> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> >>> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> >>> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >>> ---
> >>> v6->v7:
> >>> - Used the new apis for calculating the PLLDSI
> >>> parameters in the DSI driver.
> >>>
> >>> v5->v6:
> >>> - Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
> >>> PHYTCLKSETR_* and PHYTHSSETR_* macros.
> >>> - Replaced 10000000UL with 10 * MEGA
> >>> - Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
> >>> - Replaced `i -= 1;` with `i--;`
> >>> - Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
> >>> RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
> >>> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
> >>> RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
> >>>
> >>> v4->v5:
> >>> - No changes
> >>>
> >>> v3->v4
> >>> - In rzv2h_dphy_find_ulpsexit() made the array static const.
> >>>
> >>> v2->v3:
> >>> - Simplifed V2H DSI timings array to save space
> >>> - Switched to use fsleep() instead of udelay()
> >>>
> >>> v1->v2:
> >>> - Dropped unused macros
> >>> - Added missing LPCLK flag to rzv2h info
> >>> ---
> >>> .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
> >>> .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> >>> 2 files changed, 379 insertions(+)
> >>>
> >>> 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 893a90c7a886..3b2f77665309 100644
> >>> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> >>> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> >>> @@ -7,6 +7,7 @@
> >>>
> >>> #include <linux/bitfield.h>
> >>> #include <linux/clk.h>
> >>> +#include <linux/clk/renesas-rzv2h-cpg-pll.h>
> >>> #include <linux/delay.h>
> >>> #include <linux/dma-mapping.h>
> >>> #include <linux/io.h>
> >>> @@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
> >>> u64 *hsfreq_millihz);
> >>> unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> >>> unsigned long mode_freq);
> >>> + struct {
> >>> + const struct rzv2h_pll_limits **limits;
> >>> + const u8 *table;
> >>> + const u8 table_size;
> >>> + } cpg_plldsi;
> >>> u32 phy_reg_offset;
> >>> u32 link_reg_offset;
> >>> unsigned long min_dclk;
> >>> @@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
> >>> u8 features;
> >>> };
> >>>
> >>> +struct rzv2h_dsi_mode_calc {
> >>> + unsigned long mode_freq_khz;
> >>> + struct rzv2h_pll_pars dsi_parameters; };
> >>> +
> >>> struct rzg2l_mipi_dsi {
> >>> struct device *dev;
> >>> void __iomem *mmio;
> >>> @@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
> >>> unsigned int lanes;
> >>> unsigned long mode_flags;
> >>>
> >>> + struct rzv2h_dsi_mode_calc mode_calc;
> >>> +
> >>> /* DCS buffer pointers when using external memory. */
> >>> dma_addr_t dcs_buf_phys;
> >>> u8 *dcs_buf_virt;
> >>> };
> >>>
> >>> +static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
> >>> + .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
> >>> + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
> >>> + .m = { .min = 64, .max = 1023 },
> >>> + .p = { .min = 1, .max = 4 },
> >>> + .s = { .min = 0, .max = 5 },
> >>> + .k = { .min = -32768, .max = 32767 }, };
> >>> +
> >>> static inline struct rzg2l_mipi_dsi *
> >>> bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge) { @@ -194,6
> >>> +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> >>> },
> >>> };
> >>>
> >>> +struct rzv2h_mipi_dsi_timings {
> >>> + const u8 *hsfreq;
> >>> + u8 len;
> >>> + u8 start_index;
> >>> +};
> >>> +
> >>> +enum {
> >>> + TCLKPRPRCTL,
> >>> + TCLKZEROCTL,
> >>> + TCLKPOSTCTL,
> >>> + TCLKTRAILCTL,
> >>> + THSPRPRCTL,
> >>> + THSZEROCTL,
> >>> + THSTRAILCTL,
> >>> + TLPXCTL,
> >>> + THSEXITCTL,
> >>> +};
> >>> +
> >>> +static const u8 tclkprprctl[] = {
> >>> + 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150, };
> >>> +
> >>> +static const u8 tclkzeroctl[] = {
> >>> + 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
> >>> + 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
> >>> + 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
> >>> + 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
> >>> + 134, 137, 139, 141, 143, 146, 148, 150, };
> >>> +
> >>> +static const u8 tclkpostctl[] = {
> >>> + 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150, };
> >>> +
> >>> +static const u8 tclktrailctl[] = {
> >>> + 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150, };
> >>> +
> >>> +static const u8 thsprprctl[] = {
> >>> + 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150, };
> >>> +
> >>> +static const u8 thszeroctl[] = {
> >>> + 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
> >>> + 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150, };
> >>> +
> >>> +static const u8 thstrailctl[] = {
> >>> + 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150, };
> >>> +
> >>> +static const u8 tlpxctl[] = {
> >>> + 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
> >>> +};
> >>> +
> >>> +static const u8 thsexitctl[] = {
> >>> + 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
> >>> + 95, 103, 111, 119, 127, 135, 143, 150, };
> >>> +
> >>> +static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
> >>> + [TCLKPRPRCTL] = {
> >>> + .hsfreq = tclkprprctl,
> >>> + .len = ARRAY_SIZE(tclkprprctl),
> >>> + .start_index = 0,
> >>> + },
> >>> + [TCLKZEROCTL] = {
> >>> + .hsfreq = tclkzeroctl,
> >>> + .len = ARRAY_SIZE(tclkzeroctl),
> >>> + .start_index = 2,
> >>> + },
> >>> + [TCLKPOSTCTL] = {
> >>> + .hsfreq = tclkpostctl,
> >>> + .len = ARRAY_SIZE(tclkpostctl),
> >>> + .start_index = 6,
> >>> + },
> >>> + [TCLKTRAILCTL] = {
> >>> + .hsfreq = tclktrailctl,
> >>> + .len = ARRAY_SIZE(tclktrailctl),
> >>> + .start_index = 1,
> >>> + },
> >>> + [THSPRPRCTL] = {
> >>> + .hsfreq = thsprprctl,
> >>> + .len = ARRAY_SIZE(thsprprctl),
> >>> + .start_index = 0,
> >>> + },
> >>> + [THSZEROCTL] = {
> >>> + .hsfreq = thszeroctl,
> >>> + .len = ARRAY_SIZE(thszeroctl),
> >>> + .start_index = 0,
> >>> + },
> >>> + [THSTRAILCTL] = {
> >>> + .hsfreq = thstrailctl,
> >>> + .len = ARRAY_SIZE(thstrailctl),
> >>> + .start_index = 3,
> >>> + },
> >>> + [TLPXCTL] = {
> >>> + .hsfreq = tlpxctl,
> >>> + .len = ARRAY_SIZE(tlpxctl),
> >>> + .start_index = 0,
> >>> + },
> >>> + [THSEXITCTL] = {
> >>> + .hsfreq = thsexitctl,
> >>> + .len = ARRAY_SIZE(thsexitctl),
> >>> + .start_index = 1,
> >>> + },
> >>> +};
> >>> +
> >>> +static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq) {
> >>> + static const unsigned long hsfreq[] = {
> >>> + 1953125UL,
> >>> + 3906250UL,
> >>> + 7812500UL,
> >>> + 15625000UL,
> >>> + };
> >>> + static const u16 ulpsexit[] = {49, 98, 195, 391};
> >>> + unsigned int i;
> >>> +
> >>> + for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
> >>> + if (freq <= hsfreq[i])
> >>> + break;
> >>> + }
> >>> +
> >>> + if (i == ARRAY_SIZE(hsfreq))
> >>> + i--;
> >>> +
> >>> + return ulpsexit[i];
> >>> +}
> >>> +
> >>> +static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
> >>> +{
> >>> + const struct rzv2h_mipi_dsi_timings *timings;
> >>> + u16 i;
> >>> +
> >>> + timings = &rzv2h_dsi_timings_tables[index];
> >>> + for (i = 0; i < timings->len; i++) {
> >>> + unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
> >>> +
> >>> + if (freq <= hsfreq)
> >>> + break;
> >>> + }
> >>> +
> >>> + if (i == timings->len)
> >>> + i--;
> >>> +
> >>> + return timings->start_index + i;
> >>> +};
> >>
> >> I have to say I really don't like this... In the minimum, the method how this works has to be explained
> >> in a comment. These values can't really be calculated? If we really have to deal with hardcoded values
> >> and with that table from the docs, I would say that just replicate the table in the driver (i.e. a
> >> struct that represents one row of the table), instead of the method in this driver.
> >>
> >> Or was this method added based on earlier feedback, for v3? I see "Simplifed V2H DSI timings array to
> >> save space" in the change log. If so, at least document it clearly.
> >
> > It was added based on v3 based on my comment on v2[1].
> >
> > If you see each table entries it is now just 1 byte vs 10 bytes (u8 vs (u64 + u16)).
> >
> > So, it is saving considerable space by using this methos. Maybe we need to document this
> >
> > [1] https://lore.kernel.org/all/TY3PR01MB113462CC30072B670E23EC7F586B12@TY3PR01MB11346.jpnprd01.prod.outlook.com/
>
> Ok. I guess it's fine if it's documented. It wasn't super hard to
> reverse engineer it, but a short comment would have saved me the time =).
>
> But still, where do the numbers come from? Is there a formula that was
> used to generate the values in the doc? Maybe the Renesas HW people
> know? If yes, it'd be much better to use that formula. These are normal
> DSI timings, based on the hs clock, so I think they should be calculable.
>
I did check this internally with the HW team, based on the feedback
the IP vendor which provides the DSI IP does not disclose any formula
so unfortunately we will have to stick with the current lookup table
implementation. I'll add some comments for the lookup table in the
next version.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-08-21 9:28 ` Tomi Valkeinen
2025-08-22 7:01 ` Biju Das
@ 2025-08-27 12:41 ` Lad, Prabhakar
1 sibling, 0 replies; 26+ messages in thread
From: Lad, Prabhakar @ 2025-08-27 12:41 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: dri-devel, devicetree, linux-kernel, linux-renesas-soc, linux-clk,
Fabrizio Castro, Tommaso Merciai, Lad Prabhakar,
Geert Uytterhoeven, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Turquette, Stephen Boyd, Biju Das, Magnus Damm
Hi Tomi,
Thank you for the review.
On Thu, Aug 21, 2025 at 10:28 AM Tomi Valkeinen
<tomi.valkeinen+renesas@ideasonboard.com> wrote:
>
> Hi,
>
> On 28/07/2025 23:14, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add DSI support for Renesas RZ/V2H(P) SoC.
>
> I think a bit longer desc would be in order, as this is not just a "add
> a new compatible string" patch, but we have new registers and functions.
>
Sure, I'll elaborate on the commit message.
> > Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > ---
> > v6->v7:
> > - Used the new apis for calculating the PLLDSI
> > parameters in the DSI driver.
> >
> > v5->v6:
> > - Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
> > PHYTCLKSETR_* and PHYTHSSETR_* macros.
> > - Replaced 10000000UL with 10 * MEGA
> > - Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
> > - Replaced `i -= 1;` with `i--;`
> > - Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
> > RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
> > RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
> > RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.
> >
> > v4->v5:
> > - No changes
> >
> > v3->v4
> > - In rzv2h_dphy_find_ulpsexit() made the array static const.
> >
> > v2->v3:
> > - Simplifed V2H DSI timings array to save space
> > - Switched to use fsleep() instead of udelay()
> >
> > v1->v2:
> > - Dropped unused macros
> > - Added missing LPCLK flag to rzv2h info
> > ---
> > .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 345 ++++++++++++++++++
> > .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> > 2 files changed, 379 insertions(+)
> >
> > 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 893a90c7a886..3b2f77665309 100644
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -7,6 +7,7 @@
> >
> > #include <linux/bitfield.h>
> > #include <linux/clk.h>
> > +#include <linux/clk/renesas-rzv2h-cpg-pll.h>
> > #include <linux/delay.h>
> > #include <linux/dma-mapping.h>
> > #include <linux/io.h>
> > @@ -46,6 +47,11 @@ struct rzg2l_mipi_dsi_hw_info {
> > u64 *hsfreq_millihz);
> > unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> > unsigned long mode_freq);
> > + struct {
> > + const struct rzv2h_pll_limits **limits;
> > + const u8 *table;
> > + const u8 table_size;
> > + } cpg_plldsi;
> > u32 phy_reg_offset;
> > u32 link_reg_offset;
> > unsigned long min_dclk;
> > @@ -53,6 +59,11 @@ struct rzg2l_mipi_dsi_hw_info {
> > u8 features;
> > };
> >
> > +struct rzv2h_dsi_mode_calc {
> > + unsigned long mode_freq_khz;
> > + struct rzv2h_pll_pars dsi_parameters;
> > +};
> > +
> > struct rzg2l_mipi_dsi {
> > struct device *dev;
> > void __iomem *mmio;
> > @@ -75,11 +86,22 @@ struct rzg2l_mipi_dsi {
> > unsigned int lanes;
> > unsigned long mode_flags;
> >
> > + struct rzv2h_dsi_mode_calc mode_calc;
> > +
> > /* DCS buffer pointers when using external memory. */
> > dma_addr_t dcs_buf_phys;
> > u8 *dcs_buf_virt;
> > };
> >
> > +static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
> > + .fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
> > + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
> > + .m = { .min = 64, .max = 1023 },
> > + .p = { .min = 1, .max = 4 },
> > + .s = { .min = 0, .max = 5 },
> > + .k = { .min = -32768, .max = 32767 },
> > +};
> > +
> > static inline struct rzg2l_mipi_dsi *
> > bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
> > {
> > @@ -194,6 +216,155 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> > },
> > };
> >
> > +struct rzv2h_mipi_dsi_timings {
> > + const u8 *hsfreq;
> > + u8 len;
> > + u8 start_index;
> > +};
> > +
> > +enum {
> > + TCLKPRPRCTL,
> > + TCLKZEROCTL,
> > + TCLKPOSTCTL,
> > + TCLKTRAILCTL,
> > + THSPRPRCTL,
> > + THSZEROCTL,
> > + THSTRAILCTL,
> > + TLPXCTL,
> > + THSEXITCTL,
> > +};
> > +
> > +static const u8 tclkprprctl[] = {
> > + 15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150,
> > +};
> > +
> > +static const u8 tclkzeroctl[] = {
> > + 9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
> > + 41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
> > + 75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
> > + 107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
> > + 134, 137, 139, 141, 143, 146, 148, 150,
> > +};
> > +
> > +static const u8 tclkpostctl[] = {
> > + 8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150,
> > +};
> > +
> > +static const u8 tclktrailctl[] = {
> > + 14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150,
> > +};
> > +
> > +static const u8 thsprprctl[] = {
> > + 11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150,
> > +};
> > +
> > +static const u8 thszeroctl[] = {
> > + 18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
> > + 95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150,
> > +};
> > +
> > +static const u8 thstrailctl[] = {
> > + 10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150,
> > +};
> > +
> > +static const u8 tlpxctl[] = {
> > + 13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146, 150,
> > +};
> > +
> > +static const u8 thsexitctl[] = {
> > + 15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
> > + 95, 103, 111, 119, 127, 135, 143, 150,
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
> > + [TCLKPRPRCTL] = {
> > + .hsfreq = tclkprprctl,
> > + .len = ARRAY_SIZE(tclkprprctl),
> > + .start_index = 0,
> > + },
> > + [TCLKZEROCTL] = {
> > + .hsfreq = tclkzeroctl,
> > + .len = ARRAY_SIZE(tclkzeroctl),
> > + .start_index = 2,
> > + },
> > + [TCLKPOSTCTL] = {
> > + .hsfreq = tclkpostctl,
> > + .len = ARRAY_SIZE(tclkpostctl),
> > + .start_index = 6,
> > + },
> > + [TCLKTRAILCTL] = {
> > + .hsfreq = tclktrailctl,
> > + .len = ARRAY_SIZE(tclktrailctl),
> > + .start_index = 1,
> > + },
> > + [THSPRPRCTL] = {
> > + .hsfreq = thsprprctl,
> > + .len = ARRAY_SIZE(thsprprctl),
> > + .start_index = 0,
> > + },
> > + [THSZEROCTL] = {
> > + .hsfreq = thszeroctl,
> > + .len = ARRAY_SIZE(thszeroctl),
> > + .start_index = 0,
> > + },
> > + [THSTRAILCTL] = {
> > + .hsfreq = thstrailctl,
> > + .len = ARRAY_SIZE(thstrailctl),
> > + .start_index = 3,
> > + },
> > + [TLPXCTL] = {
> > + .hsfreq = tlpxctl,
> > + .len = ARRAY_SIZE(tlpxctl),
> > + .start_index = 0,
> > + },
> > + [THSEXITCTL] = {
> > + .hsfreq = thsexitctl,
> > + .len = ARRAY_SIZE(thsexitctl),
> > + .start_index = 1,
> > + },
> > +};
> > +
> > +static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
> > +{
> > + static const unsigned long hsfreq[] = {
> > + 1953125UL,
> > + 3906250UL,
> > + 7812500UL,
> > + 15625000UL,
> > + };
> > + static const u16 ulpsexit[] = {49, 98, 195, 391};
> > + unsigned int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
> > + if (freq <= hsfreq[i])
> > + break;
> > + }
> > +
> > + if (i == ARRAY_SIZE(hsfreq))
> > + i--;
> > +
> > + return ulpsexit[i];
> > +}
> > +
> > +static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
> > +{
> > + const struct rzv2h_mipi_dsi_timings *timings;
> > + u16 i;
> > +
> > + timings = &rzv2h_dsi_timings_tables[index];
> > + for (i = 0; i < timings->len; i++) {
> > + unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
> > +
> > + if (freq <= hsfreq)
> > + break;
> > + }
> > +
> > + if (i == timings->len)
> > + i--;
> > +
> > + return timings->start_index + i;
> > +};
>
> I have to say I really don't like this... In the minimum, the method how
> this works has to be explained in a comment. These values can't really
> be calculated? If we really have to deal with hardcoded values and with
> that table from the docs, I would say that just replicate the table in
> the driver (i.e. a struct that represents one row of the table), instead
> of the method in this driver.
>
> Or was this method added based on earlier feedback, for v3? I see
> "Simplifed V2H DSI timings array to save space" in the change log. If
> so, at least document it clearly.
>
As mentioned in the previous thread, we will have to live with the
lookup tables. I'll add some comments for it.
> > +
> > static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
> > {
> > iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
> > @@ -318,6 +489,150 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
> > return 0;
> > }
> >
> > +static unsigned int rzv2h_dphy_mode_clk_check(struct rzg2l_mipi_dsi *dsi,
> > + unsigned long mode_freq)
> > +{
> > + u64 hsfreq_millihz, mode_freq_hz, mode_freq_millihz;
> > + struct rzv2h_pll_div_pars cpg_dsi_parameters;
> > + struct rzv2h_pll_pars dsi_parameters;
> > + bool parameters_found;
> > + unsigned int bpp;
> > +
> > + bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> > + mode_freq_hz = mul_u32_u32(mode_freq, KILO);
> > + mode_freq_millihz = mode_freq_hz * MILLI;
> > + parameters_found =
> > + rzv2h_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[0],
> > + &cpg_dsi_parameters,
> > + dsi->info->cpg_plldsi.table,
> > + dsi->info->cpg_plldsi.table_size,
> > + mode_freq_millihz);
> > + if (!parameters_found)
> > + return MODE_CLOCK_RANGE;
> > +
> > + hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.div.freq_millihz * bpp,
> > + dsi->lanes);
> > + parameters_found = rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
> > + &dsi_parameters, hsfreq_millihz);
> > + if (!parameters_found)
> > + return MODE_CLOCK_RANGE;
> > +
> > + if (abs(dsi_parameters.error_millihz) >= 500)
> > + return MODE_CLOCK_RANGE;
> > +
> > + memcpy(&dsi->mode_calc.dsi_parameters, &dsi_parameters, sizeof(dsi_parameters));
> > + dsi->mode_calc.mode_freq_khz = mode_freq;
> > +
> > + return MODE_OK;
> > +}
> > +
> > +static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
> > + u64 *hsfreq_millihz)
> > +{
> > + struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
> > + unsigned long status;
> > +
> > + if (dsi->mode_calc.mode_freq_khz != mode_freq) {
> > + status = rzv2h_dphy_mode_clk_check(dsi, mode_freq);
> > + if (status != MODE_OK) {
> > + dev_err(dsi->dev, "No PLL parameters found for mode clk %lu\n",
> > + mode_freq);
> > + return -EINVAL;
> > + }
> > + }
> > +
> > + *hsfreq_millihz = dsi_parameters->freq_millihz;
> > +
> > + return 0;
> > +}
> > +
> > +static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
> > + u64 hsfreq_millihz)
> > +{
> > + struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
> > + unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
> > + u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
> > + struct rzg2l_mipi_dsi_timings dphy_timings;
> > + u16 ulpsexit;
> > + u64 hsfreq;
> > +
> > + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz, MILLI);
> > +
> > + if (dsi_parameters->freq_millihz == hsfreq_millihz)
> > + goto parameters_found;
> > +
> > + if (rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
> > + dsi_parameters, hsfreq_millihz))
> > + goto parameters_found;
> > +
> > + dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n", hsfreq);
> > + return -EINVAL;
> > +
> > +parameters_found:
>
> Maybe:
>
> if (dsi_parameters->freq_millihz != hsfreq_millihz &&
> !rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits, dsi_parameters,
> hsfreq_millihz)) {
> dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n",
> hsfreq);
> return -EINVAL;
> }
>
> keeps the flow a bit cleaner.
>
Agreed, I will update as above.
> > + dphy_timings.tclk_trail =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKTRAILCTL);
> > + dphy_timings.tclk_post =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL);
> > + dphy_timings.tclk_zero =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL);
> > + dphy_timings.tclk_prepare =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL);
> > + dphy_timings.ths_exit =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL);
> > + dphy_timings.ths_trail =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL);
> > + dphy_timings.ths_zero =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL);
> > + dphy_timings.ths_prepare =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL);
> > + dphy_timings.tlpx =
> > + rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL);
> > + ulpsexit = rzv2h_dphy_find_ulpsexit(lpclk_rate);
> > +
> > + phytclksetr = FIELD_PREP(PHYTCLKSETR_TCLKTRAILCTL, dphy_timings.tclk_trail) |
> > + FIELD_PREP(PHYTCLKSETR_TCLKPOSTCTL, dphy_timings.tclk_post) |
> > + FIELD_PREP(PHYTCLKSETR_TCLKZEROCTL, dphy_timings.tclk_zero) |
> > + FIELD_PREP(PHYTCLKSETR_TCLKPRPRCTL, dphy_timings.tclk_prepare);
> > + phythssetr = FIELD_PREP(PHYTHSSETR_THSEXITCTL, dphy_timings.ths_exit) |
> > + FIELD_PREP(PHYTHSSETR_THSTRAILCTL, dphy_timings.ths_trail) |
> > + FIELD_PREP(PHYTHSSETR_THSZEROCTL, dphy_timings.ths_zero) |
> > + FIELD_PREP(PHYTHSSETR_THSPRPRCTL, dphy_timings.ths_prepare);
> > + phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~PHYTLPXSETR_TLPXCTL;
> > + phytlpxsetr |= FIELD_PREP(PHYTLPXSETR_TLPXCTL, dphy_timings.tlpx);
> > + phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
> > + phycr |= FIELD_PREP(PHYCR_ULPSEXIT, ulpsexit);
> > +
> > + /* Setting all D-PHY Timings Registers */
> > + rzg2l_mipi_dsi_phy_write(dsi, PHYTCLKSETR, phytclksetr);
> > + rzg2l_mipi_dsi_phy_write(dsi, PHYTHSSETR, phythssetr);
> > + rzg2l_mipi_dsi_phy_write(dsi, PHYTLPXSETR, phytlpxsetr);
> > + rzg2l_mipi_dsi_phy_write(dsi, PHYCR, phycr);
> > +
> > + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET0R,
> > + FIELD_PREP(PLLCLKSET0R_PLL_S, dsi_parameters->s) |
> > + FIELD_PREP(PLLCLKSET0R_PLL_P, dsi_parameters->p) |
> > + FIELD_PREP(PLLCLKSET0R_PLL_M, dsi_parameters->m));
> > + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R,
> > + FIELD_PREP(PLLCLKSET1R_PLL_K, dsi_parameters->k));
> > + fsleep(20);
>
> Why sleep? Sleeps should (almost) always have a comment, explaining what
> it is waiting for.
>
Sure, I will add comments here (and below).
Cheers,
Prabhakar
> > +
> > + rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
> > + fsleep(500);
> > +
> > + return 0;
> > +}
> > +
> > +static void rzv2h_mipi_dsi_dphy_startup_late_init(struct rzg2l_mipi_dsi *dsi)
> > +{
> > + fsleep(220);
>
> Especially sleeps like this, where the upper side is "open ended".
>
> > + rzg2l_mipi_dsi_phy_write(dsi, PHYRSTR, PHYRSTR_PHYMRSTN);
> > +}
> > +
>
> Tomi
>
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2025-08-27 12:41 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-28 20:14 [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas RZ/V2H(P) SoC Prabhakar
2025-07-28 20:14 ` [PATCH v7 1/6] clk: renesas: rzv2h-cpg: Add instance field to struct pll Prabhakar
2025-08-15 5:11 ` Biju Das
2025-08-19 13:05 ` Geert Uytterhoeven
2025-07-28 20:14 ` [PATCH v7 2/6] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
2025-08-15 5:13 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
2025-08-20 21:10 ` Lad, Prabhakar
2025-07-28 20:14 ` [PATCH v7 3/6] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
2025-08-15 5:14 ` Biju Das
2025-08-19 13:14 ` Geert Uytterhoeven
2025-07-28 20:14 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas,dsi: Document RZ/V2H(P) and RZ/V2N Prabhakar
2025-07-28 20:27 ` Lad, Prabhakar
2025-08-19 10:40 ` Geert Uytterhoeven
2025-08-21 8:47 ` [PATCH v7 4/6] dt-bindings: display: bridge: renesas, dsi: " Tomi Valkeinen
2025-07-28 20:14 ` [PATCH v7 5/6] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK clock handling Prabhakar
2025-08-21 8:52 ` Tomi Valkeinen
2025-07-28 20:14 ` [PATCH v7 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
2025-08-21 9:28 ` Tomi Valkeinen
2025-08-22 7:01 ` Biju Das
2025-08-22 7:05 ` Tomi Valkeinen
2025-08-27 12:34 ` Lad, Prabhakar
2025-08-27 12:41 ` Lad, Prabhakar
2025-08-19 13:48 ` [PATCH v7 0/6] Add support for DU/DSI clocks and DSI driver support for the Renesas " Geert Uytterhoeven
2025-08-19 14:54 ` Laurent Pinchart
2025-08-20 21:03 ` Lad, Prabhakar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).