* [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
@ 2025-04-08 20:08 ` Prabhakar
2025-04-15 15:57 ` Geert Uytterhoeven
2025-04-16 9:27 ` Geert Uytterhoeven
2025-04-08 20:08 ` [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
` (13 subsequent siblings)
14 siblings, 2 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:08 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, 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.
The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
algorithm between the CPG and DSI drivers.
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>
---
v1->v2:
- No changes
---
drivers/clk/renesas/rzv2h-cpg.c | 284 ++++++++++++++++++++++++++
drivers/clk/renesas/rzv2h-cpg.h | 14 ++
include/linux/clk/renesas-rzv2h-dsi.h | 207 +++++++++++++++++++
3 files changed, 505 insertions(+)
create mode 100644 include/linux/clk/renesas-rzv2h-dsi.h
diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index dca0940b3df9..3b4f520df627 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-dsi.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>
@@ -48,6 +53,7 @@
#define CPG_PLL_STBY(x) ((x))
#define CPG_PLL_STBY_RESETB BIT(0)
#define CPG_PLL_STBY_RESETB_WEN BIT(16)
+#define CPG_PLL_STBY_SSCGEN_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))
@@ -79,6 +85,8 @@
* @last_dt_core_clk: ID of the last Core Clock exported to DT
* @mstop_count: Array of mstop values
* @rcdev: Reset controller entity
+ * @dsi_limits: PLL DSI parameters limits
+ * @plldsi_div_parameters: PLL DSI and divider parameters configuration
*/
struct rzv2h_cpg_priv {
struct device *dev;
@@ -95,6 +103,9 @@ struct rzv2h_cpg_priv {
atomic_t *mstop_count;
struct reset_controller_dev rcdev;
+
+ const struct rzv2h_plldsi_div_limits *dsi_limits;
+ struct rzv2h_plldsi_parameters plldsi_div_parameters;
};
#define rcdev_to_priv(x) container_of(x, struct rzv2h_cpg_priv, rcdev)
@@ -148,6 +159,24 @@ struct ddiv_clk {
#define to_ddiv_clock(_div) container_of(_div, struct ddiv_clk, div)
+/**
+ * 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 int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
{
struct pll_clk *pll_clk = to_pll(hw);
@@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
return ret;
}
+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 &= ((2 << ddiv.width) - 1);
+
+ div = dsi_div->dtable[div].div;
+
+ return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
+}
+
+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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
+ unsigned long long rate_mhz;
+
+ /*
+ * Adjust the requested clock rate (`req->rate`) to ensure it falls within
+ * the supported range of 5.44 MHz to 187.5 MHz.
+ */
+ req->rate = clamp(req->rate, 5440000UL, 187500000UL);
+
+ rate_mhz = req->rate * MILLI * 1ULL;
+ if (rate_mhz == dsi_dividers->error_mhz + dsi_dividers->freq_mhz)
+ goto exit_determine_rate;
+
+ if (!rzv2h_dsi_get_pll_parameters_values(priv->dsi_limits,
+ dsi_dividers, rate_mhz)) {
+ dev_err(priv->dev,
+ "failed to determine rate for req->rate: %lu\n",
+ req->rate);
+ return -EINVAL;
+ }
+
+exit_determine_rate:
+ req->best_parent_rate = req->rate * dsi_dividers->csdiv;
+
+ 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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
+ struct ddiv ddiv = dsi_div->ddiv;
+ const struct clk_div_table *clkt;
+ u32 reg, shift, div;
+
+ div = dsi_dividers->csdiv;
+ for (clkt = dsi_div->dtable; clkt->div; clkt++) {
+ if (clkt->div == div)
+ break;
+ }
+
+ if (!clkt->div && !clkt->val)
+ return -EINVAL;
+
+ shift = ddiv.shift;
+ reg = readl(priv->base + ddiv.offset);
+ reg &= ~(GENMASK(shift + ddiv.width, shift));
+
+ writel(reg | (clkt->val << shift) |
+ DDIV_DIVCTL_WEN(shift), 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 long rzv2h_cpg_plldsi_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return clamp(rate, 25000000UL, 375000000UL);
+}
+
+static unsigned long rzv2h_cpg_plldsi_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzv2h_cpg_priv *priv = pll_clk->priv;
+ unsigned int val1, val2;
+ u64 rate;
+
+ val1 = readl(priv->base + CPG_PLL_CLK1(pll_clk->pll.offset));
+ val2 = readl(priv->base + CPG_PLL_CLK2(pll_clk->pll.offset));
+
+ rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(val1) << 16) +
+ CPG_PLL_CLK1_KDIV(val1), 16 + CPG_PLL_CLK2_SDIV(val2));
+
+ return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(val1));
+}
+
+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_cpg_priv *priv = pll_clk->priv;
+ struct rzv2h_plldsi_parameters *dsi_dividers;
+ struct pll pll = pll_clk->pll;
+ u16 offset = 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;
+ }
+
+ dsi_dividers = &priv->plldsi_div_parameters;
+ /* Output clock setting 1 */
+ writel((dsi_dividers->k << 16) | (dsi_dividers->m << 6) | (dsi_dividers->p),
+ priv->base + CPG_PLL_CLK1(offset));
+
+ /* Output clock setting 2 */
+ val = readl(priv->base + CPG_PLL_CLK2(offset));
+ writel((val & ~GENMASK(2, 0)) | dsi_dividers->s,
+ priv->base + CPG_PLL_CLK2(offset));
+
+ /* Put PLL to normal mode */
+ writel(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 const struct clk_ops rzv2h_cpg_plldsi_ops = {
+ .recalc_rate = rzv2h_cpg_plldsi_clk_recalc_rate,
+ .round_rate = rzv2h_cpg_plldsi_round_rate,
+ .set_rate = rzv2h_cpg_plldsi_set_rate,
+};
+
+static struct clk * __init
+rzv2h_cpg_plldsi_clk_register(const struct cpg_core_clk *core,
+ struct rzv2h_cpg_priv *priv)
+{
+ void __iomem *base = priv->base;
+ struct device *dev = priv->dev;
+ struct clk_init_data init;
+ const struct clk *parent;
+ const char *parent_name;
+ struct pll_clk *pll_clk;
+ int ret;
+
+ parent = priv->clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+ if (!pll_clk)
+ return ERR_PTR(-ENOMEM);
+
+ parent_name = __clk_get_name(parent);
+ init.name = core->name;
+ init.ops = &rzv2h_cpg_plldsi_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll_clk->hw.init = &init;
+ pll_clk->pll = core->cfg.pll;
+ pll_clk->base = base;
+ pll_clk->priv = priv;
+
+ /* Disable SSC and turn on PLL clock when init */
+ writel(CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB |
+ CPG_PLL_STBY_SSCGEN_WEN, base + CPG_PLL_STBY(pll_clk->pll.offset));
+
+ ret = devm_clk_hw_register(dev, &pll_clk->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return pll_clk->hw.clk;
+}
+
static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -511,6 +787,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_plldsi_clk_register(core, priv);
+ break;
+ case CLK_TYPE_PLLDSI_DIV:
+ clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
+ break;
default:
goto fail;
}
@@ -1050,6 +1332,8 @@ static int __init rzv2h_cpg_probe(struct platform_device *pdev)
priv->last_dt_core_clk = info->last_dt_core_clk;
priv->num_resets = info->num_resets;
+ priv->dsi_limits = info->plldsi_limits;
+
for (i = 0; i < nclks; i++)
clks[i] = ERR_PTR(-ENOENT);
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index e730179d92aa..c4b67a56b805 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -100,6 +100,7 @@ struct smuxed {
#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)
@@ -163,6 +164,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...) \
@@ -190,6 +193,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
@@ -301,6 +312,7 @@ struct rzv2h_reset {
*
* @num_mstop_bits: Maximum number of MSTOP bits supported, equivalent to the
* number of CPG_BUS_m_MSTOP registers multiplied by 16.
+ * @plldsi_limits: PLL DSI parameters limits
*/
struct rzv2h_cpg_info {
/* Core Clocks */
@@ -319,6 +331,8 @@ struct rzv2h_cpg_info {
unsigned int num_resets;
unsigned int num_mstop_bits;
+
+ const struct rzv2h_plldsi_div_limits *plldsi_limits;
};
extern const struct rzv2h_cpg_info r9a09g047_cpg_info;
diff --git a/include/linux/clk/renesas-rzv2h-dsi.h b/include/linux/clk/renesas-rzv2h-dsi.h
new file mode 100644
index 000000000000..ee8bae8b7375
--- /dev/null
+++ b/include/linux/clk/renesas-rzv2h-dsi.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Renesas RZ/V2H(P) DSI CPG helper
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/units.h>
+
+#define OSC_CLK_IN_MEGA (24 * MEGA)
+
+struct rzv2h_plldsi_div_limits {
+ struct {
+ u64 min;
+ u64 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 {
+ u8 min;
+ u8 max;
+ } csdiv;
+};
+
+struct rzv2h_plldsi_parameters {
+ u64 freq_mhz;
+ s64 error_mhz;
+ u16 m;
+ s16 k;
+ u8 csdiv;
+ u8 p;
+ u8 s;
+};
+
+#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
+ static const struct rzv2h_plldsi_div_limits (name) = { \
+ .m = { .min = 64, .max = 533 }, \
+ .p = { .min = 1, .max = 4 }, \
+ .s = { .min = 0, .max = 6 }, \
+ .k = { .min = -32768, .max = 32767 }, \
+ .csdiv = { .min = 2, .max = 32 }, \
+ .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA } \
+ } \
+
+/**
+ * rzv2h_dsi_get_pll_parameters_values - 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 and
+ * divider values
+ * @pars: Pointer to the structure where the best calculated PLL parameters and divider
+ * values will be stored
+ * @freq: Target output frequency (in mHz)
+ *
+ * This function calculates the best set of PLL parameters (M, K, P, S) and divider
+ * value (CSDIV) to achieve the desired frequency.
+ * There is no direct formula to calculate the PLL parameters and the divider value,
+ * 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 divider values is found, false otherwise.
+ */
+static __maybe_unused bool
+rzv2h_dsi_get_pll_parameters_values(const struct rzv2h_plldsi_div_limits *limits,
+ struct rzv2h_plldsi_parameters *pars,
+ u64 freq_mhz)
+{
+ struct rzv2h_plldsi_parameters p, best;
+
+ /* Initialize best error to maximum possible value */
+ best.error_mhz = S64_MAX;
+
+ for (p.csdiv = limits->csdiv.min; p.csdiv <= limits->csdiv.max; p.csdiv += 2) {
+ for (p.p = limits->p.min; p.p <= limits->p.max; p.p++) {
+ u32 fref = OSC_CLK_IN_MEGA / p.p;
+
+ for (p.s = limits->s.min; p.s <= limits->s.max; p.s++) {
+ u16 two_pow_s = 1 << p.s;
+ u16 divider = two_pow_s * p.csdiv;
+
+ 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 combination of the
+ * PLL + divider is calculated as follows:
+ *
+ * Freq = Ffout / csdiv
+ *
+ * With:
+ * 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) * csdiv))
+ * = Ffvco / divider
+ * = (pll_m * Ffref) / divider + ((pll_k / 65536) * Ffref) / divider
+ * = output_m + output_k
+ *
+ * Every parameter has been determined at this point, but pll_k.
+ * Considering that:
+ * -32768 <= pll_k <= 32767
+ * Then:
+ * -0.5 <= (pll_k / 65536) < 0.5
+ * Therefore:
+ * -Ffref / (2 * divider) <= output_k < Ffref / (2 * divider)
+ */
+
+ /* Compute output M component (in mHz) */
+ output_m = DIV_ROUND_CLOSEST_ULL(p.m * fref * 1000ULL,
+ divider);
+ /* Compute range for output K (in mHz) */
+ output_k_range = DIV_ROUND_CLOSEST_ULL(fref * 1000ULL,
+ divider * 2);
+ /*
+ * No point in continuing if we can't achieve the
+ * desired frequency
+ */
+ if (freq_mhz < (output_m - output_k_range) ||
+ freq_mhz >= (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) / divider
+ * Therefore:
+ * pll_k = (output_k * 65536 * divider) / Ffref
+ */
+ output_k = freq_mhz - output_m;
+ pll_k = div64_s64(output_k * 65536ULL * divider, fref);
+ pll_k = DIV_S64_ROUND_CLOSEST(pll_k, 1000);
+
+ /* 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 = ((p.m * 65536ULL) + p.k) * fref;
+ if ((fvco < (limits->fvco.min * 65536ULL)) ||
+ (fvco > (limits->fvco.max * 65536ULL)))
+ continue;
+
+ /* PLL_M component of (output * 65536 * PLL_P) */
+ output = p.m * 65536ULL * OSC_CLK_IN_MEGA;
+ /* PLL_K component of (output * 65536 * PLL_P) */
+ output += p.k * OSC_CLK_IN_MEGA;
+ /* Make it in mHz */
+ output *= 1000ULL;
+ output /= 65536ULL * p.p * divider;
+
+ p.error_mhz = freq_mhz - output;
+ p.freq_mhz = output;
+
+ /* If an exact match is found, return immediately */
+ if (p.error_mhz == 0) {
+ *pars = p;
+ return true;
+ }
+
+ /* Update best match if error is smaller */
+ if (abs(best.error_mhz) > abs(p.error_mhz))
+ best = p;
+ }
+ }
+ }
+ }
+
+ /* If no valid parameters were found, return false */
+ if (best.error_mhz == S64_MAX)
+ return false;
+
+ *pars = best;
+ return true;
+}
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-08 20:08 ` [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
@ 2025-04-15 15:57 ` Geert Uytterhoeven
2025-04-18 9:51 ` Lad, Prabhakar
2025-04-16 9:27 ` Geert Uytterhoeven
1 sibling, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-04-15 15:57 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Prabhakar,
On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add support for PLLDSI and PLLDSI divider clocks.
>
> The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> algorithm between the CPG and DSI drivers.
>
> 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>
Thanks for your patch!
> --- a/drivers/clk/renesas/rzv2h-cpg.c
> +++ b/drivers/clk/renesas/rzv2h-cpg.c
> @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> return ret;
> }
>
> +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 &= ((2 << ddiv.width) - 1);
> +
> + div = dsi_div->dtable[div].div;
> +
> + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> +}
> +
> +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> + unsigned long long rate_mhz;
> +
> + /*
> + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> + * the supported range of 5.44 MHz to 187.5 MHz.
> + */
> + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> +
> + rate_mhz = req->rate * MILLI * 1ULL;
The first multiplication overflows on 32-bit systems.
Probably you wanted to use mul_u32_u32() instead?
More review later, I fell too deep in the wrong rabbit hole ("mhz !=
megaHertz"), again...
> --- /dev/null
> +++ b/include/linux/clk/renesas-rzv2h-dsi.h
> @@ -0,0 +1,207 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Renesas RZ/V2H(P) DSI CPG helper
> + *
> + * Copyright (C) 2025 Renesas Electronics Corp.
> + */
> +
> +#include <linux/limits.h>
> +#include <linux/math.h>
> +#include <linux/math64.h>
> +#include <linux/units.h>
> +
> +#define OSC_CLK_IN_MEGA (24 * MEGA)
> +
> +struct rzv2h_plldsi_div_limits {
> + struct {
> + u64 min;
> + u64 max;
u32 should be sufficient?
> + } 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 {
> + u8 min;
> + u8 max;
> + } csdiv;
> +};
> +
> +struct rzv2h_plldsi_parameters {
> + u64 freq_mhz;
> + s64 error_mhz;
> + u16 m;
> + s16 k;
> + u8 csdiv;
> + u8 p;
> + u8 s;
> +};
> +
> +#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
> + static const struct rzv2h_plldsi_div_limits (name) = { \
> + .m = { .min = 64, .max = 533 }, \
> + .p = { .min = 1, .max = 4 }, \
> + .s = { .min = 0, .max = 6 }, \
> + .k = { .min = -32768, .max = 32767 }, \
> + .csdiv = { .min = 2, .max = 32 }, \
> + .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA } \
Please initialize the members in declaration order.
> + } \
> +
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] 31+ messages in thread* Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-15 15:57 ` Geert Uytterhoeven
@ 2025-04-18 9:51 ` Lad, Prabhakar
0 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 9:51 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Geert,
Thank you for the review.
On Tue, Apr 15, 2025 at 4:57 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Prabhakar,
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add support for PLLDSI and PLLDSI divider clocks.
> >
> > The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> > algorithm between the CPG and DSI drivers.
> >
> > 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>
>
> Thanks for your patch!
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
> > @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> > return ret;
> > }
> >
> > +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 &= ((2 << ddiv.width) - 1);
> > +
> > + div = dsi_div->dtable[div].div;
> > +
> > + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> > +}
> > +
> > +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + unsigned long long rate_mhz;
> > +
> > + /*
> > + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> > + * the supported range of 5.44 MHz to 187.5 MHz.
> > + */
> > + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> > +
> > + rate_mhz = req->rate * MILLI * 1ULL;
>
> The first multiplication overflows on 32-bit systems.
> Probably you wanted to use mul_u32_u32() instead?
>
Ok, I'll switch to mul_u32_u32() .
> More review later, I fell too deep in the wrong rabbit hole ("mhz !=
> megaHertz"), again...
>
After fixing the review comments on this I'll send out a v3 with this
change, so that its easier to review.
> > --- /dev/null
> > +++ b/include/linux/clk/renesas-rzv2h-dsi.h
> > @@ -0,0 +1,207 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Renesas RZ/V2H(P) DSI CPG helper
> > + *
> > + * Copyright (C) 2025 Renesas Electronics Corp.
> > + */
> > +
> > +#include <linux/limits.h>
> > +#include <linux/math.h>
> > +#include <linux/math64.h>
> > +#include <linux/units.h>
> > +
> > +#define OSC_CLK_IN_MEGA (24 * MEGA)
> > +
> > +struct rzv2h_plldsi_div_limits {
> > + struct {
> > + u64 min;
> > + u64 max;
>
> u32 should be sufficient?
>
Agreed.
> > + } 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 {
> > + u8 min;
> > + u8 max;
> > + } csdiv;
> > +};
> > +
> > +struct rzv2h_plldsi_parameters {
> > + u64 freq_mhz;
> > + s64 error_mhz;
> > + u16 m;
> > + s16 k;
> > + u8 csdiv;
> > + u8 p;
> > + u8 s;
> > +};
> > +
> > +#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
> > + static const struct rzv2h_plldsi_div_limits (name) = { \
> > + .m = { .min = 64, .max = 533 }, \
> > + .p = { .min = 1, .max = 4 }, \
> > + .s = { .min = 0, .max = 6 }, \
> > + .k = { .min = -32768, .max = 32767 }, \
> > + .csdiv = { .min = 2, .max = 32 }, \
> > + .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA } \
>
> Please initialize the members in declaration order.
>
Ok.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-08 20:08 ` [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
2025-04-15 15:57 ` Geert Uytterhoeven
@ 2025-04-16 9:27 ` Geert Uytterhoeven
2025-04-17 15:12 ` Fabrizio Castro
` (2 more replies)
1 sibling, 3 replies; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-04-16 9:27 UTC (permalink / raw)
To: Prabhakar, Fabrizio Castro
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, Biju Das, Tomi Valkeinen,
Michael Turquette, Stephen Boyd, Philipp Zabel, Magnus Damm,
dri-devel, devicetree, linux-clk, linux-renesas-soc, linux-kernel,
Tommaso Merciai, Lad Prabhakar
Hi Prabhakar, Fabrizio,
Thanks for your patch!
On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add support for PLLDSI and PLLDSI divider clocks.
>
> The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> algorithm between the CPG and DSI drivers.
Please explain here why the DSI driver needs access to this algorithm.
> 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>
> --- a/drivers/clk/renesas/rzv2h-cpg.c
> +++ b/drivers/clk/renesas/rzv2h-cpg.c
> @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> return ret;
> }
>
> +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 &= ((2 << ddiv.width) - 1);
Shouldn't that "2" be "1"?
GENMASK(ddiv.width - 1, 0), or even better: clk_div_mask(ddiv.width).
> +
> + div = dsi_div->dtable[div].div;
> +
> + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> +}
> +
> +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> + unsigned long long rate_mhz;
u64?
Please use "millihz" instead of "mhz" everywhere, so it becomes very
clear this is really "mHz" and not "MHz".
> +
> + /*
> + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> + * the supported range of 5.44 MHz to 187.5 MHz.
> + */
> + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> +
> + rate_mhz = req->rate * MILLI * 1ULL;
> + if (rate_mhz == dsi_dividers->error_mhz + dsi_dividers->freq_mhz)
> + goto exit_determine_rate;
> +
> + if (!rzv2h_dsi_get_pll_parameters_values(priv->dsi_limits,
> + dsi_dividers, rate_mhz)) {
> + dev_err(priv->dev,
> + "failed to determine rate for req->rate: %lu\n",
> + req->rate);
> + return -EINVAL;
> + }
> +
> +exit_determine_rate:
> + req->best_parent_rate = req->rate * dsi_dividers->csdiv;
> +
> + 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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> + struct ddiv ddiv = dsi_div->ddiv;
> + const struct clk_div_table *clkt;
> + u32 reg, shift, div;
> +
> + div = dsi_dividers->csdiv;
> + for (clkt = dsi_div->dtable; clkt->div; clkt++) {
> + if (clkt->div == div)
> + break;
> + }
> +
> + if (!clkt->div && !clkt->val)
> + return -EINVAL;
No need to check clkt->dev.
> +
> + shift = ddiv.shift;
> + reg = readl(priv->base + ddiv.offset);
> + reg &= ~(GENMASK(shift + ddiv.width, shift));
> +
> + writel(reg | (clkt->val << shift) |
> + DDIV_DIVCTL_WEN(shift), priv->base + ddiv.offset);
> +
> + return 0;
This function is very similar to the existing rzv2h_ddiv_set_rate().
If you can't re-use it as-is, please consider factoring out the common
part, or at least follow the same style of RMW-operation.
> +};
> +static long rzv2h_cpg_plldsi_round_rate(struct clk_hw *hw,
> + unsigned long rate,
> + unsigned long *parent_rate)
> +{
> + return clamp(rate, 25000000UL, 375000000UL);
This only rounds rates outside the range from 25 to 375 MHz.
What about rates between 25 and 375 MHz?
> +}
> +
> +static unsigned long rzv2h_cpg_plldsi_clk_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct pll_clk *pll_clk = to_pll(hw);
> + struct rzv2h_cpg_priv *priv = pll_clk->priv;
> + unsigned int val1, val2;
> + u64 rate;
> +
> + val1 = readl(priv->base + CPG_PLL_CLK1(pll_clk->pll.offset));
> + val2 = readl(priv->base + CPG_PLL_CLK2(pll_clk->pll.offset));
> +
> + rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(val1) << 16) +
> + CPG_PLL_CLK1_KDIV(val1), 16 + CPG_PLL_CLK2_SDIV(val2));
> +
> + return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(val1));
Can't you just reuse the existing rzv2h_cpg_pll_clk_recalc_rate()?
> +}
> +
> +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_cpg_priv *priv = pll_clk->priv;
> + struct rzv2h_plldsi_parameters *dsi_dividers;
> + struct pll pll = pll_clk->pll;
> + u16 offset = 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;
> + }
> +
> + dsi_dividers = &priv->plldsi_div_parameters;
> + /* Output clock setting 1 */
> + writel((dsi_dividers->k << 16) | (dsi_dividers->m << 6) | (dsi_dividers->p),
> + priv->base + CPG_PLL_CLK1(offset));
> +
> + /* Output clock setting 2 */
> + val = readl(priv->base + CPG_PLL_CLK2(offset));
> + writel((val & ~GENMASK(2, 0)) | dsi_dividers->s,
> + priv->base + CPG_PLL_CLK2(offset));
> +
> + /* Put PLL to normal mode */
> + writel(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;
This function could be reused for non-DSI PLLs?
> +};
> +
> +static const struct clk_ops rzv2h_cpg_plldsi_ops = {
> + .recalc_rate = rzv2h_cpg_plldsi_clk_recalc_rate,
> + .round_rate = rzv2h_cpg_plldsi_round_rate,
> + .set_rate = rzv2h_cpg_plldsi_set_rate,
> +};
> +
> +static struct clk * __init
> +rzv2h_cpg_plldsi_clk_register(const struct cpg_core_clk *core,
> + struct rzv2h_cpg_priv *priv)
> +{
> + void __iomem *base = priv->base;
> + struct device *dev = priv->dev;
> + struct clk_init_data init;
> + const struct clk *parent;
> + const char *parent_name;
> + struct pll_clk *pll_clk;
> + int ret;
> +
> + parent = priv->clks[core->parent];
> + if (IS_ERR(parent))
> + return ERR_CAST(parent);
> +
> + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return ERR_PTR(-ENOMEM);
> +
> + parent_name = __clk_get_name(parent);
> + init.name = core->name;
> + init.ops = &rzv2h_cpg_plldsi_ops;
> + init.flags = 0;
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> +
> + pll_clk->hw.init = &init;
> + pll_clk->pll = core->cfg.pll;
> + pll_clk->base = base;
> + pll_clk->priv = priv;
> +
> + /* Disable SSC and turn on PLL clock when init */
> + writel(CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB |
> + CPG_PLL_STBY_SSCGEN_WEN, base + CPG_PLL_STBY(pll_clk->pll.offset));
Apart from the three lines above, this function does the same as the
existing rzv2h_cpg_pll_clk_register(). Merge/reuse?
> +
> + ret = devm_clk_hw_register(dev, &pll_clk->hw);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + return pll_clk->hw.clk;
> +}
> +
> static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
> unsigned long parent_rate)
> {
> --- /dev/null
> +++ b/include/linux/clk/renesas-rzv2h-dsi.h
> @@ -0,0 +1,207 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Renesas RZ/V2H(P) DSI CPG helper
> + *
> + * Copyright (C) 2025 Renesas Electronics Corp.
> + */
Missing include guard.
> +
> +#include <linux/limits.h>
> +#include <linux/math.h>
> +#include <linux/math64.h>
> +#include <linux/units.h>
> +
> +#define OSC_CLK_IN_MEGA (24 * MEGA)
> +
> +struct rzv2h_plldsi_div_limits {
This structure looks applicable to all RZ/V2H PLLs, so perhaps drop the
"dsi" part from the name?
> + struct {
> + u64 min;
> + u64 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 {
> + u8 min;
> + u8 max;
> + } csdiv;
> +};
> +
> +struct rzv2h_plldsi_parameters {
> + u64 freq_mhz;
> + s64 error_mhz;
> + u16 m;
> + s16 k;
> + u8 csdiv;
> + u8 p;
> + u8 s;
> +};
> +
> +#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
> + static const struct rzv2h_plldsi_div_limits (name) = { \
> + .m = { .min = 64, .max = 533 }, \
> + .p = { .min = 1, .max = 4 }, \
> + .s = { .min = 0, .max = 6 }, \
> + .k = { .min = -32768, .max = 32767 }, \
> + .csdiv = { .min = 2, .max = 32 }, \
> + .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA } \
> + } \
> +
> +/**
> + * rzv2h_dsi_get_pll_parameters_values - 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 and
> + * divider values
> + * @pars: Pointer to the structure where the best calculated PLL parameters and divider
> + * values will be stored
> + * @freq: Target output frequency (in mHz)
> + *
> + * This function calculates the best set of PLL parameters (M, K, P, S) and divider
> + * value (CSDIV) to achieve the desired frequency.
> + * There is no direct formula to calculate the PLL parameters and the divider value,
> + * 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 divider values is found, false otherwise.
> + */
> +static __maybe_unused bool
> +rzv2h_dsi_get_pll_parameters_values(const struct rzv2h_plldsi_div_limits *limits,
> + struct rzv2h_plldsi_parameters *pars,
> + u64 freq_mhz)
> +{
I haven't reviewed the heavy calculations yet.
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] 31+ messages in thread* RE: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-16 9:27 ` Geert Uytterhoeven
@ 2025-04-17 15:12 ` Fabrizio Castro
2025-04-18 14:10 ` Lad, Prabhakar
2025-04-18 16:19 ` Lad, Prabhakar
2 siblings, 0 replies; 31+ messages in thread
From: Fabrizio Castro @ 2025-04-17 15:12 UTC (permalink / raw)
To: Geert Uytterhoeven, 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, Biju Das, Tomi Valkeinen,
Michael Turquette, Stephen Boyd, Philipp Zabel, Magnus Damm,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-clk@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
linux-kernel@vger.kernel.org, Tommaso Merciai,
Prabhakar Mahadev Lad
Hi Geert,
Thanks for your feedback!
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Sent: 16 April 2025 10:27
> Subject: Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
>
> Hi Prabhakar, Fabrizio,
>
> Thanks for your patch!
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add support for PLLDSI and PLLDSI divider clocks.
> >
> > The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> > algorithm between the CPG and DSI drivers.
>
> Please explain here why the DSI driver needs access to this algorithm.
Perhaps something like the below could fully explain the reason, although
it's an eyeful:
"The PLL found inside the DSI IP is very similar to the PLLDSI found in the
CPG IP block, although the limits for some of the parameters are different.
Also, the PLLDSI is followed by a programmable divider, whereas there is no
such thing in the DSI PLL IP.
The limits for the PLL found within the DSI IP are:
1 <= PLL_P <= 4
64 <= PLL_M <= 1023
0 <= PLL_S <= 5
−32768 <= PLL_K <= 32767
The limits for PLLDSI (found in CPG) are:
1 <= PLL_P <= 4
64 <= PLL_M <= 533
0 <= PLL_S <= 6
−32768 <= PLL_K <= 32767
The limits for the PLLDSI related divider are:
CSDIV = 1/(2 + 2 * n), with n=0,...,15
Header file `renesas-rzv2h-dsi.h` is added so that both the CPG and DSI drivers
can reuse exactly the same data structures and algorithm, although
they'll drive rzv2h_dsi_get_pll_parameters_values() with different limits.
While the CPG driver only needs visibility of the limits for the PLLDSI,
the DSI driver is going to need visibility of the limits for both PLLDSI and
for the PLL inside the DSI IP.
The DSI driver requires a resolution higher than Hz (which is what the clock
subsystem currently supports), namely: mHz. This is vital to allow the DSI driver
to keep the error between the calculated value of HSFREQ and the generated value
of HSFREQ below a certain threshold.
The difficulty in achieving a small error is down to the accuracy of the VCLK
representation.
Since the clock subsystem only allows for Hz, a 1/2 Hz error on the representation of
VCLK (down to the selection of frequencies that cannot be precisely achieved and
related rounding errors) may lead to a very big error in the calculation
of HSFREQ, which uses the below formula:
HSFREQ = (VCLK * bpp) / num_lanes
In the worst case scenario (1 lane and 24 bpp), a 1/2 Hz error on the representation
of VCLK will lead to an error of 12Hz(!) on the calculation of HSFREQ, leading
to a non working video output.
By granting the DSI driver access to the PLL calculations and PLLDSI (CPG) limits,
the DSI driver can work out the best solution for VCLK independently from the CPG
driver, and it can set VCLK accordingly (knowing that the CPG driver will
use exactly the same parameters determined by the DSI driver, as it will be using
the same input frequency and the same algorithm for the calculations).
For convenience, macro RZV2H_CPG_PLL_DSI_LIMITS() is added to avoid replicating
the declaration of the PLLDSI limits and therefore it can be used in both the
CPG driver and in the DSI driver.
Make use of the data structures and algorithm defined in header file
`renesas-rzv2h-dsi.h` to add PLLDSI support, including its divider.
Since we need to make sure that the DSI driver knows exactly which frequency
the PLLDSI + divider combo is going to generate, the CPG driver is instructed
to calculate the parameters for the PLLDSI + divider combo (by calling into
rzv2h_dsi_get_pll_parameters_values()) only from
rzv2h_cpg_plldsi_div_determine_rate(). rzv2h_cpg_plldsi_set_rate() will simply
reuse the pre-calculated parameter values."
What do you think? Too much?
Cheers,
Fab
>
> > 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>
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
>
> > @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> > return ret;
> > }
> >
> > +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 &= ((2 << ddiv.width) - 1);
>
> Shouldn't that "2" be "1"?
> GENMASK(ddiv.width - 1, 0), or even better: clk_div_mask(ddiv.width).
>
> > +
> > + div = dsi_div->dtable[div].div;
> > +
> > + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> > +}
> > +
> > +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + unsigned long long rate_mhz;
>
> u64?
> Please use "millihz" instead of "mhz" everywhere, so it becomes very
> clear this is really "mHz" and not "MHz".
>
> > +
> > + /*
> > + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> > + * the supported range of 5.44 MHz to 187.5 MHz.
> > + */
> > + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> > +
> > + rate_mhz = req->rate * MILLI * 1ULL;
> > + if (rate_mhz == dsi_dividers->error_mhz + dsi_dividers->freq_mhz)
> > + goto exit_determine_rate;
> > +
> > + if (!rzv2h_dsi_get_pll_parameters_values(priv->dsi_limits,
> > + dsi_dividers, rate_mhz)) {
> > + dev_err(priv->dev,
> > + "failed to determine rate for req->rate: %lu\n",
> > + req->rate);
> > + return -EINVAL;
> > + }
> > +
> > +exit_determine_rate:
> > + req->best_parent_rate = req->rate * dsi_dividers->csdiv;
> > +
> > + 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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + struct ddiv ddiv = dsi_div->ddiv;
> > + const struct clk_div_table *clkt;
> > + u32 reg, shift, div;
> > +
> > + div = dsi_dividers->csdiv;
> > + for (clkt = dsi_div->dtable; clkt->div; clkt++) {
> > + if (clkt->div == div)
> > + break;
> > + }
> > +
> > + if (!clkt->div && !clkt->val)
> > + return -EINVAL;
>
> No need to check clkt->dev.
>
> > +
> > + shift = ddiv.shift;
> > + reg = readl(priv->base + ddiv.offset);
> > + reg &= ~(GENMASK(shift + ddiv.width, shift));
> > +
> > + writel(reg | (clkt->val << shift) |
> > + DDIV_DIVCTL_WEN(shift), priv->base + ddiv.offset);
> > +
> > + return 0;
>
> This function is very similar to the existing rzv2h_ddiv_set_rate().
> If you can't re-use it as-is, please consider factoring out the common
> part, or at least follow the same style of RMW-operation.
>
> > +};
>
>
> > +static long rzv2h_cpg_plldsi_round_rate(struct clk_hw *hw,
> > + unsigned long rate,
> > + unsigned long *parent_rate)
> > +{
> > + return clamp(rate, 25000000UL, 375000000UL);
>
> This only rounds rates outside the range from 25 to 375 MHz.
> What about rates between 25 and 375 MHz?
>
> > +}
> > +
> > +static unsigned long rzv2h_cpg_plldsi_clk_recalc_rate(struct clk_hw *hw,
> > + unsigned long parent_rate)
> > +{
> > + struct pll_clk *pll_clk = to_pll(hw);
> > + struct rzv2h_cpg_priv *priv = pll_clk->priv;
> > + unsigned int val1, val2;
> > + u64 rate;
> > +
> > + val1 = readl(priv->base + CPG_PLL_CLK1(pll_clk->pll.offset));
> > + val2 = readl(priv->base + CPG_PLL_CLK2(pll_clk->pll.offset));
> > +
> > + rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(val1) << 16) +
> > + CPG_PLL_CLK1_KDIV(val1), 16 + CPG_PLL_CLK2_SDIV(val2));
> > +
> > + return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(val1));
>
> Can't you just reuse the existing rzv2h_cpg_pll_clk_recalc_rate()?
>
> > +}
> > +
> > +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_cpg_priv *priv = pll_clk->priv;
> > + struct rzv2h_plldsi_parameters *dsi_dividers;
> > + struct pll pll = pll_clk->pll;
> > + u16 offset = 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;
> > + }
> > +
> > + dsi_dividers = &priv->plldsi_div_parameters;
> > + /* Output clock setting 1 */
> > + writel((dsi_dividers->k << 16) | (dsi_dividers->m << 6) | (dsi_dividers->p),
> > + priv->base + CPG_PLL_CLK1(offset));
> > +
> > + /* Output clock setting 2 */
> > + val = readl(priv->base + CPG_PLL_CLK2(offset));
> > + writel((val & ~GENMASK(2, 0)) | dsi_dividers->s,
> > + priv->base + CPG_PLL_CLK2(offset));
> > +
> > + /* Put PLL to normal mode */
> > + writel(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;
>
> This function could be reused for non-DSI PLLs?
>
> > +};
> > +
> > +static const struct clk_ops rzv2h_cpg_plldsi_ops = {
> > + .recalc_rate = rzv2h_cpg_plldsi_clk_recalc_rate,
> > + .round_rate = rzv2h_cpg_plldsi_round_rate,
> > + .set_rate = rzv2h_cpg_plldsi_set_rate,
> > +};
> > +
> > +static struct clk * __init
> > +rzv2h_cpg_plldsi_clk_register(const struct cpg_core_clk *core,
> > + struct rzv2h_cpg_priv *priv)
> > +{
> > + void __iomem *base = priv->base;
> > + struct device *dev = priv->dev;
> > + struct clk_init_data init;
> > + const struct clk *parent;
> > + const char *parent_name;
> > + struct pll_clk *pll_clk;
> > + int ret;
> > +
> > + parent = priv->clks[core->parent];
> > + if (IS_ERR(parent))
> > + return ERR_CAST(parent);
> > +
> > + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> > + if (!pll_clk)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + parent_name = __clk_get_name(parent);
> > + init.name = core->name;
> > + init.ops = &rzv2h_cpg_plldsi_ops;
> > + init.flags = 0;
> > + init.parent_names = &parent_name;
> > + init.num_parents = 1;
> > +
> > + pll_clk->hw.init = &init;
> > + pll_clk->pll = core->cfg.pll;
> > + pll_clk->base = base;
> > + pll_clk->priv = priv;
> > +
> > + /* Disable SSC and turn on PLL clock when init */
> > + writel(CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB |
> > + CPG_PLL_STBY_SSCGEN_WEN, base + CPG_PLL_STBY(pll_clk->pll.offset));
>
> Apart from the three lines above, this function does the same as the
> existing rzv2h_cpg_pll_clk_register(). Merge/reuse?
>
> > +
> > + ret = devm_clk_hw_register(dev, &pll_clk->hw);
> > + if (ret)
> > + return ERR_PTR(ret);
> > +
> > + return pll_clk->hw.clk;
> > +}
> > +
> > static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
> > unsigned long parent_rate)
> > {
>
> > --- /dev/null
> > +++ b/include/linux/clk/renesas-rzv2h-dsi.h
> > @@ -0,0 +1,207 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Renesas RZ/V2H(P) DSI CPG helper
> > + *
> > + * Copyright (C) 2025 Renesas Electronics Corp.
> > + */
>
> Missing include guard.
>
> > +
> > +#include <linux/limits.h>
> > +#include <linux/math.h>
> > +#include <linux/math64.h>
> > +#include <linux/units.h>
> > +
> > +#define OSC_CLK_IN_MEGA (24 * MEGA)
> > +
> > +struct rzv2h_plldsi_div_limits {
>
> This structure looks applicable to all RZ/V2H PLLs, so perhaps drop the
> "dsi" part from the name?
>
> > + struct {
> > + u64 min;
> > + u64 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 {
> > + u8 min;
> > + u8 max;
> > + } csdiv;
> > +};
> > +
> > +struct rzv2h_plldsi_parameters {
> > + u64 freq_mhz;
> > + s64 error_mhz;
> > + u16 m;
> > + s16 k;
> > + u8 csdiv;
> > + u8 p;
> > + u8 s;
> > +};
> > +
> > +#define RZV2H_CPG_PLL_DSI_LIMITS(name) \
> > + static const struct rzv2h_plldsi_div_limits (name) = { \
> > + .m = { .min = 64, .max = 533 }, \
> > + .p = { .min = 1, .max = 4 }, \
> > + .s = { .min = 0, .max = 6 }, \
> > + .k = { .min = -32768, .max = 32767 }, \
> > + .csdiv = { .min = 2, .max = 32 }, \
> > + .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA } \
> > + } \
> > +
> > +/**
> > + * rzv2h_dsi_get_pll_parameters_values - 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 and
> > + * divider values
> > + * @pars: Pointer to the structure where the best calculated PLL parameters and divider
> > + * values will be stored
> > + * @freq: Target output frequency (in mHz)
> > + *
> > + * This function calculates the best set of PLL parameters (M, K, P, S) and divider
> > + * value (CSDIV) to achieve the desired frequency.
> > + * There is no direct formula to calculate the PLL parameters and the divider value,
> > + * 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 divider values is found, false otherwise.
> > + */
> > +static __maybe_unused bool
> > +rzv2h_dsi_get_pll_parameters_values(const struct rzv2h_plldsi_div_limits *limits,
> > + struct rzv2h_plldsi_parameters *pars,
> > + u64 freq_mhz)
> > +{
>
> I haven't reviewed the heavy calculations yet.
>
> 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] 31+ messages in thread* Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-16 9:27 ` Geert Uytterhoeven
2025-04-17 15:12 ` Fabrizio Castro
@ 2025-04-18 14:10 ` Lad, Prabhakar
2025-04-18 16:19 ` Lad, Prabhakar
2 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 14:10 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Fabrizio Castro, 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,
Biju Das, Tomi Valkeinen, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Tommaso Merciai, Lad Prabhakar
Hi Geert,
Thank you for the review.
On Wed, Apr 16, 2025 at 10:27 AM Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
>
> Hi Prabhakar, Fabrizio,
>
> Thanks for your patch!
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add support for PLLDSI and PLLDSI divider clocks.
> >
> > The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> > algorithm between the CPG and DSI drivers.
>
> Please explain here why the DSI driver needs access to this algorithm.
>
> > 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>
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
>
> > @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> > return ret;
> > }
> >
> > +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 &= ((2 << ddiv.width) - 1);
>
> Shouldn't that "2" be "1"?
> GENMASK(ddiv.width - 1, 0), or even better: clk_div_mask(ddiv.width).
>
Agreed, I'll switch to clk_div_mask(ddiv.width)
> > +
> > + div = dsi_div->dtable[div].div;
> > +
> > + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> > +}
> > +
> > +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + unsigned long long rate_mhz;
>
> u64?
OK.
> Please use "millihz" instead of "mhz" everywhere, so it becomes very
> clear this is really "mHz" and not "MHz".
>
OK.
> > +
> > + /*
> > + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> > + * the supported range of 5.44 MHz to 187.5 MHz.
> > + */
> > + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> > +
> > + rate_mhz = req->rate * MILLI * 1ULL;
> > + if (rate_mhz == dsi_dividers->error_mhz + dsi_dividers->freq_mhz)
> > + goto exit_determine_rate;
> > +
> > + if (!rzv2h_dsi_get_pll_parameters_values(priv->dsi_limits,
> > + dsi_dividers, rate_mhz)) {
> > + dev_err(priv->dev,
> > + "failed to determine rate for req->rate: %lu\n",
> > + req->rate);
> > + return -EINVAL;
> > + }
> > +
> > +exit_determine_rate:
> > + req->best_parent_rate = req->rate * dsi_dividers->csdiv;
> > +
> > + 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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + struct ddiv ddiv = dsi_div->ddiv;
> > + const struct clk_div_table *clkt;
> > + u32 reg, shift, div;
> > +
> > + div = dsi_dividers->csdiv;
> > + for (clkt = dsi_div->dtable; clkt->div; clkt++) {
> > + if (clkt->div == div)
> > + break;
> > + }
> > +
> > + if (!clkt->div && !clkt->val)
> > + return -EINVAL;
>
> No need to check clkt->dev.
>
I'll drop this check and use a bool flag to determine if a div is found.
> > +
> > + shift = ddiv.shift;
> > + reg = readl(priv->base + ddiv.offset);
> > + reg &= ~(GENMASK(shift + ddiv.width, shift));
> > +
> > + writel(reg | (clkt->val << shift) |
> > + DDIV_DIVCTL_WEN(shift), priv->base + ddiv.offset);
> > +
> > + return 0;
>
> This function is very similar to the existing rzv2h_ddiv_set_rate().
> If you can't re-use it as-is, please consider factoring out the common
> part, or at least follow the same style of RMW-operation.
>
Ok, I'll follow the same RMW operation.
> > +};
>
>
> > +static long rzv2h_cpg_plldsi_round_rate(struct clk_hw *hw,
> > + unsigned long rate,
> > + unsigned long *parent_rate)
> > +{
> > + return clamp(rate, 25000000UL, 375000000UL);
>
> This only rounds rates outside the range from 25 to 375 MHz.
> What about rates between 25 and 375 MHz?
>
> > +}
> > +
> > +static unsigned long rzv2h_cpg_plldsi_clk_recalc_rate(struct clk_hw *hw,
> > + unsigned long parent_rate)
> > +{
> > + struct pll_clk *pll_clk = to_pll(hw);
> > + struct rzv2h_cpg_priv *priv = pll_clk->priv;
> > + unsigned int val1, val2;
> > + u64 rate;
> > +
> > + val1 = readl(priv->base + CPG_PLL_CLK1(pll_clk->pll.offset));
> > + val2 = readl(priv->base + CPG_PLL_CLK2(pll_clk->pll.offset));
> > +
> > + rate = mul_u64_u32_shr(parent_rate, (CPG_PLL_CLK1_MDIV(val1) << 16) +
> > + CPG_PLL_CLK1_KDIV(val1), 16 + CPG_PLL_CLK2_SDIV(val2));
> > +
> > + return DIV_ROUND_CLOSEST_ULL(rate, CPG_PLL_CLK1_PDIV(val1));
>
> Can't you just reuse the existing rzv2h_cpg_pll_clk_recalc_rate()?
>
Agreed.
> > +}
> > +
> > +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_cpg_priv *priv = pll_clk->priv;
> > + struct rzv2h_plldsi_parameters *dsi_dividers;
> > + struct pll pll = pll_clk->pll;
> > + u16 offset = 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;
> > + }
> > +
> > + dsi_dividers = &priv->plldsi_div_parameters;
> > + /* Output clock setting 1 */
> > + writel((dsi_dividers->k << 16) | (dsi_dividers->m << 6) | (dsi_dividers->p),
> > + priv->base + CPG_PLL_CLK1(offset));
> > +
> > + /* Output clock setting 2 */
> > + val = readl(priv->base + CPG_PLL_CLK2(offset));
> > + writel((val & ~GENMASK(2, 0)) | dsi_dividers->s,
> > + priv->base + CPG_PLL_CLK2(offset));
> > +
> > + /* Put PLL to normal mode */
> > + writel(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;
>
> This function could be reused for non-DSI PLLs?
>
Yes it could be reused, I'll rename this to rzv2h_cpg_pll_set_rate().
> > +};
> > +
> > +static const struct clk_ops rzv2h_cpg_plldsi_ops = {
> > + .recalc_rate = rzv2h_cpg_plldsi_clk_recalc_rate,
> > + .round_rate = rzv2h_cpg_plldsi_round_rate,
> > + .set_rate = rzv2h_cpg_plldsi_set_rate,
> > +};
> > +
> > +static struct clk * __init
> > +rzv2h_cpg_plldsi_clk_register(const struct cpg_core_clk *core,
> > + struct rzv2h_cpg_priv *priv)
> > +{
> > + void __iomem *base = priv->base;
> > + struct device *dev = priv->dev;
> > + struct clk_init_data init;
> > + const struct clk *parent;
> > + const char *parent_name;
> > + struct pll_clk *pll_clk;
> > + int ret;
> > +
> > + parent = priv->clks[core->parent];
> > + if (IS_ERR(parent))
> > + return ERR_CAST(parent);
> > +
> > + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> > + if (!pll_clk)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + parent_name = __clk_get_name(parent);
> > + init.name = core->name;
> > + init.ops = &rzv2h_cpg_plldsi_ops;
> > + init.flags = 0;
> > + init.parent_names = &parent_name;
> > + init.num_parents = 1;
> > +
> > + pll_clk->hw.init = &init;
> > + pll_clk->pll = core->cfg.pll;
> > + pll_clk->base = base;
> > + pll_clk->priv = priv;
> > +
> > + /* Disable SSC and turn on PLL clock when init */
> > + writel(CPG_PLL_STBY_RESETB_WEN | CPG_PLL_STBY_RESETB |
> > + CPG_PLL_STBY_SSCGEN_WEN, base + CPG_PLL_STBY(pll_clk->pll.offset));
>
> Apart from the three lines above, this function does the same as the
> existing rzv2h_cpg_pll_clk_register(). Merge/reuse?
>
Agreed, I'll reuse this function and introduce a bool flag to turn on the PLL.
> > +
> > + ret = devm_clk_hw_register(dev, &pll_clk->hw);
> > + if (ret)
> > + return ERR_PTR(ret);
> > +
> > + return pll_clk->hw.clk;
> > +}
> > +
> > static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
> > unsigned long parent_rate)
> > {
>
> > --- /dev/null
> > +++ b/include/linux/clk/renesas-rzv2h-dsi.h
> > @@ -0,0 +1,207 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Renesas RZ/V2H(P) DSI CPG helper
> > + *
> > + * Copyright (C) 2025 Renesas Electronics Corp.
> > + */
>
> Missing include guard.
>
Ouch, Ill add one.
> > +
> > +#include <linux/limits.h>
> > +#include <linux/math.h>
> > +#include <linux/math64.h>
> > +#include <linux/units.h>
> > +
> > +#define OSC_CLK_IN_MEGA (24 * MEGA)
> > +
> > +struct rzv2h_plldsi_div_limits {
>
> This structure looks applicable to all RZ/V2H PLLs, so perhaps drop the
> "dsi" part from the name?
>
Agreed.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks
2025-04-16 9:27 ` Geert Uytterhoeven
2025-04-17 15:12 ` Fabrizio Castro
2025-04-18 14:10 ` Lad, Prabhakar
@ 2025-04-18 16:19 ` Lad, Prabhakar
2 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 16:19 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Fabrizio Castro, 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,
Biju Das, Tomi Valkeinen, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Tommaso Merciai, Lad Prabhakar
Hi Geert,
On Wed, Apr 16, 2025 at 10:27 AM Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
>
> Hi Prabhakar, Fabrizio,
>
> Thanks for your patch!
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add support for PLLDSI and PLLDSI divider clocks.
> >
> > The `renesas-rzv2h-dsi.h` header file is added to share the PLL divider
> > algorithm between the CPG and DSI drivers.
>
> Please explain here why the DSI driver needs access to this algorithm.
>
> > 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>
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.c
> > +++ b/drivers/clk/renesas/rzv2h-cpg.c
>
> > @@ -196,6 +225,253 @@ static int rzv2h_cpg_pll_clk_enable(struct clk_hw *hw)
> > return ret;
> > }
> >
> > +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 &= ((2 << ddiv.width) - 1);
>
> Shouldn't that "2" be "1"?
> GENMASK(ddiv.width - 1, 0), or even better: clk_div_mask(ddiv.width).
>
> > +
> > + div = dsi_div->dtable[div].div;
> > +
> > + return DIV_ROUND_CLOSEST_ULL(parent_rate, div);
> > +}
> > +
> > +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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + unsigned long long rate_mhz;
>
> u64?
> Please use "millihz" instead of "mhz" everywhere, so it becomes very
> clear this is really "mHz" and not "MHz".
>
> > +
> > + /*
> > + * Adjust the requested clock rate (`req->rate`) to ensure it falls within
> > + * the supported range of 5.44 MHz to 187.5 MHz.
> > + */
> > + req->rate = clamp(req->rate, 5440000UL, 187500000UL);
> > +
> > + rate_mhz = req->rate * MILLI * 1ULL;
> > + if (rate_mhz == dsi_dividers->error_mhz + dsi_dividers->freq_mhz)
> > + goto exit_determine_rate;
> > +
> > + if (!rzv2h_dsi_get_pll_parameters_values(priv->dsi_limits,
> > + dsi_dividers, rate_mhz)) {
> > + dev_err(priv->dev,
> > + "failed to determine rate for req->rate: %lu\n",
> > + req->rate);
> > + return -EINVAL;
> > + }
> > +
> > +exit_determine_rate:
> > + req->best_parent_rate = req->rate * dsi_dividers->csdiv;
> > +
> > + 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_plldsi_parameters *dsi_dividers = &priv->plldsi_div_parameters;
> > + struct ddiv ddiv = dsi_div->ddiv;
> > + const struct clk_div_table *clkt;
> > + u32 reg, shift, div;
> > +
> > + div = dsi_dividers->csdiv;
> > + for (clkt = dsi_div->dtable; clkt->div; clkt++) {
> > + if (clkt->div == div)
> > + break;
> > + }
> > +
> > + if (!clkt->div && !clkt->val)
> > + return -EINVAL;
>
> No need to check clkt->dev.
>
> > +
> > + shift = ddiv.shift;
> > + reg = readl(priv->base + ddiv.offset);
> > + reg &= ~(GENMASK(shift + ddiv.width, shift));
> > +
> > + writel(reg | (clkt->val << shift) |
> > + DDIV_DIVCTL_WEN(shift), priv->base + ddiv.offset);
> > +
> > + return 0;
>
> This function is very similar to the existing rzv2h_ddiv_set_rate().
> If you can't re-use it as-is, please consider factoring out the common
> part, or at least follow the same style of RMW-operation.
>
> > +};
>
>
> > +static long rzv2h_cpg_plldsi_round_rate(struct clk_hw *hw,
> > + unsigned long rate,
> > + unsigned long *parent_rate)
> > +{
> > + return clamp(rate, 25000000UL, 375000000UL);
>
> This only rounds rates outside the range from 25 to 375 MHz.
> What about rates between 25 and 375 MHz?
>
My intention was to clamp it and let the PLL DSI DIV determine_rate
handle rejecting the rates if they dont get best dividers. Let's take
this discussion to v3.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
2025-04-08 20:08 ` [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
@ 2025-04-08 20:08 ` Prabhakar
2025-04-15 15:50 ` Geert Uytterhoeven
2025-04-08 20:09 ` [PATCH v2 03/15] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/V2H(P) SoC Prabhakar
` (12 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:08 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, 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>
---
v1->v2:
- No changes
---
drivers/clk/renesas/r9a09g057-cpg.c | 63 +++++++++++++++++++++++++++++
drivers/clk/renesas/rzv2h-cpg.h | 3 ++
2 files changed, 66 insertions(+)
diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c
index 057bfa0e2a57..94c959577f03 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-dsi.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 */
@@ -58,6 +60,9 @@ enum clk_ids {
CLK_SMUX2_GBE0_RXCLK,
CLK_SMUX2_GBE1_TXCLK,
CLK_SMUX2_GBE1_RXCLK,
+ CLK_DIV_PLLETH_LPCLK,
+ CLK_CSDIV_PLLETH_LPCLK,
+ CLK_PLLDSI_SDIV2,
CLK_PLLGPU_GEAR,
/* Module Clocks */
@@ -78,6 +83,26 @@ static const struct clk_div_table dtable_2_4[] = {
{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},
@@ -94,6 +119,14 @@ 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},
+};
+
/* Mux clock tables */
static const char * const smux2_gbe0_rxclk[] = { ".plleth_gbe0", "et0-rxc-rxclk" };
static const char * const smux2_gbe0_txclk[] = { ".plleth_gbe0", "et0-txc-txclk" };
@@ -113,6 +146,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 */
@@ -148,6 +182,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(".plleth_lpclk_div4", CLK_DIV_PLLETH_LPCLK, CLK_PLLETH, 1, 4),
+ DEF_CSDIV(".plleth_lpclk", CLK_CSDIV_PLLETH_LPCLK, CLK_DIV_PLLETH_LPCLK,
+ CSDIV0_DIVCTL2, dtable_16_128),
+
+ DEF_PLLDSI_DIV(".plldsi_sdiv2", CLK_PLLDSI_SDIV2, CLK_PLLDSI,
+ CSDIV1_DIVCTL2, dtable_2_32),
DEF_DDIV(".pllgpu_gear", CLK_PLLGPU_GEAR, CLK_PLLGPU, CDDIV3_DIVCTL1, dtable_2_64),
@@ -327,6 +367,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_SDIV2, 14, 10, 7, 10,
+ BUS_MSTOP(9, BIT(14) | BIT(15))),
+ DEF_MOD("dsi_0_lpclk", CLK_CSDIV_PLLETH_LPCLK, 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_SDIV2, 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,
@@ -388,11 +444,16 @@ 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 */
};
+RZV2H_CPG_PLL_DSI_LIMITS(rzv2h_cpg_pll_dsi_limits);
+
const struct rzv2h_cpg_info r9a09g057_cpg_info __initconst = {
/* Core Clocks */
.core_clks = r9a09g057_core_clks,
@@ -410,4 +471,6 @@ const struct rzv2h_cpg_info r9a09g057_cpg_info __initconst = {
.num_resets = ARRAY_SIZE(r9a09g057_resets),
.num_mstop_bits = 192,
+
+ .plldsi_limits = &rzv2h_cpg_pll_dsi_limits,
};
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index c4b67a56b805..d0678ff1c7cb 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -28,6 +28,7 @@ struct pll {
})
#define PLLCA55 PLL_PACK(0x60, 1)
+#define PLLDSI PLL_PACK(0xc0, 1)
#define PLLGPU PLL_PACK(0x120, 1)
/**
@@ -117,6 +118,8 @@ struct smuxed {
#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_NO_RMW(CPG_CSDIV0, 8, 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.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-04-08 20:08 ` [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
@ 2025-04-15 15:50 ` Geert Uytterhoeven
2025-04-18 14:30 ` Lad, Prabhakar
0 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-04-15 15:50 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Prabhakar,
On Tue, 8 Apr 2025 at 22:09, 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>
> ---
> v1->v2:
> - No changes
You did change CSDIV0_DIVCTL2 to the NO_RMW-variant...
> --- a/drivers/clk/renesas/r9a09g057-cpg.c
> +++ b/drivers/clk/renesas/r9a09g057-cpg.c
> @@ -148,6 +182,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(".plleth_lpclk_div4", CLK_DIV_PLLETH_LPCLK, CLK_PLLETH, 1, 4),
> + DEF_CSDIV(".plleth_lpclk", CLK_CSDIV_PLLETH_LPCLK, CLK_DIV_PLLETH_LPCLK,
> + CSDIV0_DIVCTL2, dtable_16_128),
The clock names look strange to me: "plleth_lpclk_div4" sounds like it is
"plleth_lpclk" divided by four, but that is not the case here.
> +
> + DEF_PLLDSI_DIV(".plldsi_sdiv2", CLK_PLLDSI_SDIV2, CLK_PLLDSI,
> + CSDIV1_DIVCTL2, dtable_2_32),
>
> DEF_DDIV(".pllgpu_gear", CLK_PLLGPU_GEAR, CLK_PLLGPU, CDDIV3_DIVCTL1, dtable_2_64),
>
> --- a/drivers/clk/renesas/rzv2h-cpg.h
> +++ b/drivers/clk/renesas/rzv2h-cpg.h
> @@ -117,6 +118,8 @@ struct smuxed {
>
> #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_NO_RMW(CPG_CSDIV0, 8, 2, CSDIV_NO_MON)
The documentation says:
DIVCTL2[3:2] is reserved.
When writing, read modify write is needed.
So the NO_RMW-logic seems to be inverted?
> +#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)
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] 31+ messages in thread* Re: [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC
2025-04-15 15:50 ` Geert Uytterhoeven
@ 2025-04-18 14:30 ` Lad, Prabhakar
0 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 14:30 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Geert,
Thank you for the review.
On Tue, Apr 15, 2025 at 4:51 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Prabhakar,
>
> On Tue, 8 Apr 2025 at 22:09, 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>
> > ---
> > v1->v2:
> > - No changes
>
> You did change CSDIV0_DIVCTL2 to the NO_RMW-variant...
>
Ouch missed that.
> > --- a/drivers/clk/renesas/r9a09g057-cpg.c
> > +++ b/drivers/clk/renesas/r9a09g057-cpg.c
>
> > @@ -148,6 +182,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(".plleth_lpclk_div4", CLK_DIV_PLLETH_LPCLK, CLK_PLLETH, 1, 4),
> > + DEF_CSDIV(".plleth_lpclk", CLK_CSDIV_PLLETH_LPCLK, CLK_DIV_PLLETH_LPCLK,
> > + CSDIV0_DIVCTL2, dtable_16_128),
>
> The clock names look strange to me: "plleth_lpclk_div4" sounds like it is
> "plleth_lpclk" divided by four, but that is not the case here.
>
Maybe ".cdiv4_plleth_lpclk" and ".plleth_lpclk_gear"?
> > +
> > + DEF_PLLDSI_DIV(".plldsi_sdiv2", CLK_PLLDSI_SDIV2, CLK_PLLDSI,
> > + CSDIV1_DIVCTL2, dtable_2_32),
> >
> > DEF_DDIV(".pllgpu_gear", CLK_PLLGPU_GEAR, CLK_PLLGPU, CDDIV3_DIVCTL1, dtable_2_64),
> >
>
> > --- a/drivers/clk/renesas/rzv2h-cpg.h
> > +++ b/drivers/clk/renesas/rzv2h-cpg.h
>
> > @@ -117,6 +118,8 @@ struct smuxed {
> >
> > #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_NO_RMW(CPG_CSDIV0, 8, 2, CSDIV_NO_MON)
>
> The documentation says:
>
> DIVCTL2[3:2] is reserved.
> When writing, read modify write is needed.
>
> So the NO_RMW-logic seems to be inverted?
>
Yes.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 03/15] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/V2H(P) SoC
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
2025-04-08 20:08 ` [PATCH v2 01/15] clk: renesas: rzv2h-cpg: Add support for DSI clocks Prabhakar
2025-04-08 20:08 ` [PATCH v2 02/15] clk: renesas: r9a09g057: Add clock and reset entries for DSI and LCDC Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-09 6:44 ` Krzysztof Kozlowski
2025-04-08 20:09 ` [PATCH v2 04/15] dt-bindings: display: bridge: renesas,dsi: " Prabhakar
` (11 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
The DU block on the RZ/V2H(P) SoC is identical to the one found on the
RZ/G2L SoC. However, it only supports the DSI interface, whereas the
RZ/G2L supports both DSI and DPI interfaces.
Due to this difference, a SoC-specific compatible string
'renesas,r9a09g057-du' is added for the RZ/V2H(P) SoC.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v1->v2:
- Kept the sort order for schema validation
- Added `port@1: false` for RZ/V2H(P) SoC
---
.../bindings/display/renesas,rzg2l-du.yaml | 23 ++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml b/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
index 95e3d5e74b87..1e32d14b6edb 100644
--- a/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
+++ b/Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml
@@ -20,6 +20,7 @@ properties:
- enum:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
+ - renesas,r9a09g057-du # RZ/V2H(P)
- items:
- enum:
- renesas,r9a07g054-du # RZ/V2L
@@ -101,7 +102,12 @@ allOf:
required:
- port@0
- else:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a07g044-du
+ then:
properties:
ports:
properties:
@@ -113,6 +119,21 @@ allOf:
required:
- port@0
- port@1
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g057-du
+ then:
+ properties:
+ ports:
+ properties:
+ port@0:
+ description: DSI
+ port@1: false
+
+ required:
+ - port@0
examples:
# RZ/G2L DU
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 03/15] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/V2H(P) SoC
2025-04-08 20:09 ` [PATCH v2 03/15] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/V2H(P) SoC Prabhakar
@ 2025-04-09 6:44 ` Krzysztof Kozlowski
0 siblings, 0 replies; 31+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-09 6:44 UTC (permalink / raw)
To: Prabhakar, 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,
Biju Das, Tomi Valkeinen, Geert Uytterhoeven, Michael Turquette,
Stephen Boyd, Philipp Zabel, Magnus Damm, dri-devel, devicetree,
linux-clk
Cc: linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
On 08/04/2025 22:09, Prabhakar wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> The DU block on the RZ/V2H(P) SoC is identical to the one found on the
> RZ/G2L SoC. However, it only supports the DSI interface, whereas the
> RZ/G2L supports both DSI and DPI interfaces.
>
> Due to this difference, a SoC-specific compatible string
> 'renesas,r9a09g057-du' is added for the RZ/V2H(P) SoC.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 04/15] dt-bindings: display: bridge: renesas,dsi: Add support for RZ/V2H(P) SoC
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (2 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 03/15] dt-bindings: display: renesas,rzg2l-du: Add support for RZ/V2H(P) SoC Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 05/15] drm: renesas: rz-du: " Prabhakar
` (10 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar, Krzysztof Kozlowski
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
The MIPI DSI interface on the RZ/V2H(P) SoC is nearly identical to that of
the RZ/G2L SoC. While the LINK registers are the same for both SoCs, the
D-PHY registers differ. Additionally, the number of resets for DSI on
RZ/V2H(P) is two compared to three on the RZ/G2L.
To accommodate these differences, a SoC-specific
`renesas,r9a09g057-mipi-dsi` compatible string has been added for the
RZ/V2H(P) SoC.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
v1->v2:
- Added enum for RZ/V2H as suggested by Krzysztof as the list
will grow in the future (while adding RZ/G3E SoC).
- Added Reviewed-by tag from Krzysztof.
---
.../bindings/display/bridge/renesas,dsi.yaml | 116 +++++++++++++-----
1 file changed, 87 insertions(+), 29 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
index e08c24633926..5980df2b389b 100644
--- a/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi.yaml
@@ -14,16 +14,17 @@ 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:
- 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)
+
+ - items:
+ - enum:
+ - renesas,r9a07g044-mipi-dsi # RZ/G2{L,LC}
+ - renesas,r9a07g054-mipi-dsi # RZ/V2L
+ - const: renesas,rzg2l-mipi-dsi
reg:
maxItems: 1
@@ -49,34 +50,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 multiplied 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: pllclk
+ - 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 +153,41 @@ required:
additionalProperties: 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.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 05/15] drm: renesas: rz-du: Add support for RZ/V2H(P) SoC
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (3 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 04/15] dt-bindings: display: bridge: renesas,dsi: " Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 06/15] drm: renesas: rz-du: mipi_dsi: Add min check for VCLK range Prabhakar
` (9 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
The LCD controller (LCDC) on the RZ/V2H(P) SoC is composed of Frame
Compression Processor (FCPVD), Video Signal Processor (VSPD), and
Display Unit (DU).
There is one LCDC unit available on the RZ/V2H(P) SoC which is connected
to the DSI.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
v1->v2:
- No changes
---
drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
index 5e40f0c1e7b0..e1aa6a719529 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
@@ -50,9 +50,20 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
}
};
+static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
+ .channels_mask = BIT(0),
+ .routes = {
+ [RZG2L_DU_OUTPUT_DSI0] = {
+ .possible_outputs = BIT(0),
+ .port = 0,
+ },
+ },
+};
+
static const struct of_device_id rzg2l_du_of_table[] = {
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
+ { .compatible = "renesas,r9a09g057-du", .data = &rzg2l_du_r9a09g057_info },
{ /* sentinel */ }
};
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 06/15] drm: renesas: rz-du: mipi_dsi: Add min check for VCLK range
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (4 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 05/15] drm: renesas: rz-du: " Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 07/15] drm: renesas: rz-du: mipi_dsi: Simplify HSFREQ calculation Prabhakar
` (8 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
The VCLK range for Renesas RZ/G2L SoC is 148.5 MHz to 5.803 MHz. Add a
minimum clock check in the mode_valid callback to ensure that the clock
value does not fall below the valid range.
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>
---
v1->v2:
- Added Reviewed-by tag from Biju
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 3 +++
1 file changed, 3 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 4550c6d84796..ec8baecb9ba5 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -584,6 +584,9 @@ rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
if (mode->clock > 148500)
return MODE_CLOCK_HIGH;
+ if (mode->clock < 5803)
+ return MODE_CLOCK_LOW;
+
return MODE_OK;
}
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 07/15] drm: renesas: rz-du: mipi_dsi: Simplify HSFREQ calculation
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (5 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 06/15] drm: renesas: rz-du: mipi_dsi: Add min check for VCLK range Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 08/15] drm: renesas: rz-du: mipi_dsi: Use VCLK for " Prabhakar
` (7 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Simplify the high-speed clock frequency (HSFREQ) calculation by removing
the redundant multiplication and division by 8. The updated equation:
hsfreq = (mode->clock * bpp) / (dsi->lanes);
produces the same result while improving readability and clarity.
Additionally, update the comment to clarify the relationship between HS
clock bit frequency, HS byte clock frequency, and HSFREQ.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v1->v2:
- Added Reviewed-by tag from Biju
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index ec8baecb9ba5..c5f698cd74f1 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -277,10 +277,10 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
* hsclk: DSI HS Byte clock frequency (Hz)
* lanes: number of data lanes
*
- * hsclk(bit) = hsclk(byte) * 8
+ * hsclk(bit) = hsclk(byte) * 8 = hsfreq
*/
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
- hsfreq = (mode->clock * bpp * 8) / (8 * dsi->lanes);
+ hsfreq = (mode->clock * bpp) / dsi->lanes;
ret = pm_runtime_resume_and_get(dsi->dev);
if (ret < 0)
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 08/15] drm: renesas: rz-du: mipi_dsi: Use VCLK for HSFREQ calculation
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (6 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 07/15] drm: renesas: rz-du: mipi_dsi: Simplify HSFREQ calculation Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 09/15] drm: renesas: rz-du: mipi_dsi: Add OF data support Prabhakar
` (6 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Update the RZ/G2L MIPI DSI driver to calculate HSFREQ using the actual
VCLK rate instead of the mode clock. The relationship between HSCLK and
VCLK is:
vclk * bpp <= hsclk * 8 * lanes
Retrieve the VCLK rate using `clk_get_rate(dsi->vclk)`, ensuring that
HSFREQ accurately reflects the clock rate set in hardware, leading to
better precision in data transmission.
Additionally, use `DIV_ROUND_CLOSEST_ULL` for a more precise division
when computing `hsfreq`. Also, update unit conversions to use correct
scaling factors for better clarity and correctness.
Since `clk_get_rate()` returns the clock rate in Hz, update the HSFREQ
threshold comparisons to use Hz instead of kHz to ensure correct behavior.
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>
---
v1->v2:
- No changes
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 27 ++++++++++---------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index c5f698cd74f1..8fa86ae07fd2 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
@@ -15,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include <linux/units.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -199,7 +201,7 @@ static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
/* All DSI global operation timings are set with recommended setting */
for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) {
dphy_timings = &rzg2l_mipi_dsi_global_timings[i];
- if (hsfreq <= dphy_timings->hsfreq_max)
+ if (hsfreq <= (dphy_timings->hsfreq_max * KILO))
break;
}
@@ -258,7 +260,7 @@ static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
const struct drm_display_mode *mode)
{
- unsigned long hsfreq;
+ unsigned long hsfreq, vclk_rate;
unsigned int bpp;
u32 txsetr;
u32 clstptsetr;
@@ -269,6 +271,12 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
u32 golpbkt;
int ret;
+ ret = pm_runtime_resume_and_get(dsi->dev);
+ if (ret < 0)
+ return ret;
+
+ clk_set_rate(dsi->vclk, mode->clock * KILO);
+
/*
* Relationship between hsclk and vclk must follow
* vclk * bpp = hsclk * 8 * lanes
@@ -280,13 +288,8 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
* hsclk(bit) = hsclk(byte) * 8 = hsfreq
*/
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
- hsfreq = (mode->clock * bpp) / dsi->lanes;
-
- ret = pm_runtime_resume_and_get(dsi->dev);
- if (ret < 0)
- return ret;
-
- clk_set_rate(dsi->vclk, mode->clock * 1000);
+ vclk_rate = clk_get_rate(dsi->vclk);
+ hsfreq = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp, dsi->lanes);
ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq);
if (ret < 0)
@@ -304,12 +307,12 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
* - data lanes: maximum 4 lanes
* Therefore maximum hsclk will be 891 Mbps.
*/
- if (hsfreq > 445500) {
+ if (hsfreq > 445500000) {
clkkpt = 12;
clkbfht = 15;
clkstpt = 48;
golpbkt = 75;
- } else if (hsfreq > 250000) {
+ } else if (hsfreq > 250000000) {
clkkpt = 7;
clkbfht = 8;
clkstpt = 27;
@@ -753,7 +756,7 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
* mode->clock and format are not available. So initialize DPHY with
* timing parameters for 80Mbps.
*/
- ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000);
+ ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000000);
if (ret < 0)
goto err_phy;
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 09/15] drm: renesas: rz-du: mipi_dsi: Add OF data support
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (7 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 08/15] drm: renesas: rz-du: mipi_dsi: Use VCLK for " Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations Prabhakar
` (5 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
In preparation for adding support for the Renesas RZ/V2H(P) SoC, this patch
introduces a mechanism to pass SoC-specific information via OF data in the
DSI driver. This enables the driver to adapt dynamically to various
SoC-specific requirements without hardcoding configurations.
The MIPI DSI interface on the RZ/V2H(P) SoC is nearly identical to the one
on the RZ/G2L SoC. While the LINK registers are shared between the two
SoCs, the D-PHY registers differ. Also the VCLK range differs on both these
SoCs. To accommodate these differences `struct rzg2l_mipi_dsi_hw_info` is
introduced and as now passed as OF data.
These changes lay the groundwork for the upcoming RZ/V2H(P) SoC support by
allowing SoC-specific data to be passed through OF.
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>
---
v1->v2:
- Added DPHY_RST as feature flag
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 68 ++++++++++++++-----
.../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 2 -
2 files changed, 51 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 8fa86ae07fd2..07457a57cf3b 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -28,10 +28,26 @@
#include "rzg2l_mipi_dsi_regs.h"
+#define RZ_MIPI_DSI_FEATURE_DPHY_RST BIT(0)
+
+struct rzg2l_mipi_dsi;
+
+struct rzg2l_mipi_dsi_hw_info {
+ int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long hsfreq);
+ void (*dphy_exit)(struct rzg2l_mipi_dsi *dsi);
+ u32 phy_reg_offset;
+ u32 link_reg_offset;
+ unsigned long max_dclk;
+ unsigned long min_dclk;
+ u8 features;
+};
+
struct rzg2l_mipi_dsi {
struct device *dev;
void __iomem *mmio;
+ const struct rzg2l_mipi_dsi_hw_info *info;
+
struct reset_control *rstc;
struct reset_control *arstc;
struct reset_control *prstc;
@@ -164,22 +180,22 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
{
- iowrite32(data, dsi->mmio + reg);
+ iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
}
static void rzg2l_mipi_dsi_link_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
{
- iowrite32(data, dsi->mmio + LINK_REG_OFFSET + reg);
+ iowrite32(data, dsi->mmio + dsi->info->link_reg_offset + reg);
}
static u32 rzg2l_mipi_dsi_phy_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
{
- return ioread32(dsi->mmio + reg);
+ return ioread32(dsi->mmio + dsi->info->phy_reg_offset + reg);
}
static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
{
- return ioread32(dsi->mmio + LINK_REG_OFFSET + reg);
+ return ioread32(dsi->mmio + dsi->info->link_reg_offset + reg);
}
/* -----------------------------------------------------------------------------
@@ -291,7 +307,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
vclk_rate = clk_get_rate(dsi->vclk);
hsfreq = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp, dsi->lanes);
- ret = rzg2l_mipi_dsi_dphy_init(dsi, hsfreq);
+ ret = dsi->info->dphy_init(dsi, hsfreq);
if (ret < 0)
goto err_phy;
@@ -334,7 +350,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
return 0;
err_phy:
- rzg2l_mipi_dsi_dphy_exit(dsi);
+ dsi->info->dphy_exit(dsi);
pm_runtime_put(dsi->dev);
return ret;
@@ -342,7 +358,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
static void rzg2l_mipi_dsi_stop(struct rzg2l_mipi_dsi *dsi)
{
- rzg2l_mipi_dsi_dphy_exit(dsi);
+ dsi->info->dphy_exit(dsi);
pm_runtime_put(dsi->dev);
}
@@ -584,10 +600,12 @@ rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
- if (mode->clock > 148500)
+ struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+
+ if (mode->clock > dsi->info->max_dclk)
return MODE_CLOCK_HIGH;
- if (mode->clock < 5803)
+ if (mode->clock < dsi->info->min_dclk)
return MODE_CLOCK_LOW;
return MODE_OK;
@@ -713,6 +731,11 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dsi);
dsi->dev = &pdev->dev;
+ dsi->info = of_device_get_match_data(&pdev->dev);
+ if (!dsi->info)
+ return dev_err_probe(dsi->dev, -ENODEV,
+ "missing data info\n");
+
ret = drm_of_get_data_lanes_count_ep(dsi->dev->of_node, 1, 0, 1, 4);
if (ret < 0)
return dev_err_probe(dsi->dev, ret,
@@ -728,10 +751,12 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->vclk))
return PTR_ERR(dsi->vclk);
- dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst");
- if (IS_ERR(dsi->rstc))
- return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
- "failed to get rst\n");
+ if (dsi->info->features & RZ_MIPI_DSI_FEATURE_DPHY_RST) {
+ dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst");
+ if (IS_ERR(dsi->rstc))
+ return dev_err_probe(dsi->dev, PTR_ERR(dsi->rstc),
+ "failed to get rst\n");
+ }
dsi->arstc = devm_reset_control_get_exclusive(dsi->dev, "arst");
if (IS_ERR(dsi->arstc))
@@ -756,13 +781,13 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
* mode->clock and format are not available. So initialize DPHY with
* timing parameters for 80Mbps.
*/
- ret = rzg2l_mipi_dsi_dphy_init(dsi, 80000000);
+ ret = dsi->info->dphy_init(dsi, 80000000);
if (ret < 0)
goto err_phy;
txsetr = rzg2l_mipi_dsi_link_read(dsi, TXSETR);
dsi->num_data_lanes = min(((txsetr >> 16) & 3) + 1, num_data_lanes);
- rzg2l_mipi_dsi_dphy_exit(dsi);
+ dsi->info->dphy_exit(dsi);
pm_runtime_put(dsi->dev);
/* Initialize the DRM bridge. */
@@ -779,7 +804,7 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
return 0;
err_phy:
- rzg2l_mipi_dsi_dphy_exit(dsi);
+ dsi->info->dphy_exit(dsi);
pm_runtime_put(dsi->dev);
err_pm_disable:
pm_runtime_disable(dsi->dev);
@@ -794,8 +819,17 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
+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,
+ .link_reg_offset = 0x10000,
+ .max_dclk = 148500,
+ .min_dclk = 5803,
+ .features = RZ_MIPI_DSI_FEATURE_DPHY_RST,
+};
+
static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
- { .compatible = "renesas,rzg2l-mipi-dsi" },
+ { .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 1dbc16ec64a4..16efe4dc59f4 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
@@ -41,8 +41,6 @@
#define DSIDPHYTIM3_THS_ZERO(x) ((x) << 0)
/* --------------------------------------------------------*/
-/* Link Registers */
-#define LINK_REG_OFFSET 0x10000
/* Link Status Register */
#define LINKSR 0x10
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (8 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 09/15] drm: renesas: rz-du: mipi_dsi: Add OF data support Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-09 8:15 ` Geert Uytterhoeven
2025-04-08 20:09 ` [PATCH v2 11/15] drm: renesas: rz-du: mipi_dsi: Add feature flag for 16BPP support Prabhakar
` (4 subsequent siblings)
14 siblings, 1 reply; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Pass the HSFREQ in milli-Hz to the `dphy_init()` callback to improve
precision, especially for the RZ/V2H(P) SoC, where PLL dividers require
high accuracy.
These changes prepare the driver for upcoming RZ/V2H(P) SoC support.
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>
---
v1->v2:
- No changes
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 07457a57cf3b..4a8fe52e9752 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -33,7 +33,7 @@
struct rzg2l_mipi_dsi;
struct rzg2l_mipi_dsi_hw_info {
- int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long hsfreq);
+ int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long long hsfreq_mhz);
void (*dphy_exit)(struct rzg2l_mipi_dsi *dsi);
u32 phy_reg_offset;
u32 link_reg_offset;
@@ -203,8 +203,9 @@ static u32 rzg2l_mipi_dsi_link_read(struct rzg2l_mipi_dsi *dsi, u32 reg)
*/
static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
- unsigned long hsfreq)
+ unsigned long long hsfreq_mhz)
{
+ unsigned long hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
const struct rzg2l_mipi_dsi_timings *dphy_timings;
unsigned int i;
u32 dphyctrl0;
@@ -277,6 +278,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
const struct drm_display_mode *mode)
{
unsigned long hsfreq, vclk_rate;
+ unsigned long long hsfreq_mhz;
unsigned int bpp;
u32 txsetr;
u32 clstptsetr;
@@ -305,9 +307,9 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
*/
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
vclk_rate = clk_get_rate(dsi->vclk);
- hsfreq = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp, dsi->lanes);
+ hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp * KILO * 1ULL, dsi->lanes);
- ret = dsi->info->dphy_init(dsi, hsfreq);
+ ret = dsi->info->dphy_init(dsi, hsfreq_mhz);
if (ret < 0)
goto err_phy;
@@ -315,6 +317,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN;
rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr);
+ hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
/*
* Global timings characteristic depends on high speed Clock Frequency
* Currently MIPI DSI-IF just supports maximum FHD@60 with:
@@ -781,7 +784,7 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
* mode->clock and format are not available. So initialize DPHY with
* timing parameters for 80Mbps.
*/
- ret = dsi->info->dphy_init(dsi, 80000000);
+ ret = dsi->info->dphy_init(dsi, 80000000ULL * KILO);
if (ret < 0)
goto err_phy;
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations
2025-04-08 20:09 ` [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations Prabhakar
@ 2025-04-09 8:15 ` Geert Uytterhoeven
2025-04-09 8:55 ` Lad, Prabhakar
0 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-04-09 8:15 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Prabhakar,
On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Pass the HSFREQ in milli-Hz to the `dphy_init()` callback to improve
> precision, especially for the RZ/V2H(P) SoC, where PLL dividers require
> high accuracy.
>
> These changes prepare the driver for upcoming RZ/V2H(P) SoC support.
>
> 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>
Thanks for your patch!
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> @@ -33,7 +33,7 @@
> struct rzg2l_mipi_dsi;
>
> struct rzg2l_mipi_dsi_hw_info {
> - int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long hsfreq);
> + int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long long hsfreq_mhz);
Due to the lack of capitalization of the "hz" part, it is not clear
that the "m" stands for "milli" instead of "mega".
Perhaps hsfreq_mHz or hsfreq_millihz?
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] 31+ messages in thread* Re: [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations
2025-04-09 8:15 ` Geert Uytterhoeven
@ 2025-04-09 8:55 ` Lad, Prabhakar
0 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-09 8:55 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Fabrizio Castro, Tommaso Merciai,
Lad Prabhakar
Hi Geert,
Thank you for the review.
On Wed, Apr 9, 2025 at 9:16 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Prabhakar,
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Pass the HSFREQ in milli-Hz to the `dphy_init()` callback to improve
> > precision, especially for the RZ/V2H(P) SoC, where PLL dividers require
> > high accuracy.
> >
> > These changes prepare the driver for upcoming RZ/V2H(P) SoC support.
> >
> > 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>
>
> Thanks for your patch!
>
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -33,7 +33,7 @@
> > struct rzg2l_mipi_dsi;
> >
> > struct rzg2l_mipi_dsi_hw_info {
> > - int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long hsfreq);
> > + int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long long hsfreq_mhz);
>
> Due to the lack of capitalization of the "hz" part, it is not clear
> that the "m" stands for "milli" instead of "mega".
> Perhaps hsfreq_mHz or hsfreq_millihz?
>
Agreed, I will use `hsfreq_millihz`. Shall I respin a new version as
the initial patches do the same (i.e. use mhz).
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 11/15] drm: renesas: rz-du: mipi_dsi: Add feature flag for 16BPP support
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (9 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 10/15] drm: renesas: rz-du: mipi_dsi: Use mHz for D-PHY frequency calculations Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 12/15] drm: renesas: rz-du: mipi_dsi: Add dphy_late_init() callback for RZ/V2H(P) Prabhakar
` (3 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Introduce the `RZ_MIPI_DSI_FEATURE_16BPP` flag in `rzg2l_mipi_dsi_hw_info`
to indicate support for 16BPP pixel formats. The RZ/V2H(P) SoC supports
16BPP, whereas this feature is missing on the RZ/G2L SoC.
Update the `mipi_dsi_host_attach()` function to check this flag before
allowing 16BPP formats. If the SoC does not support 16BPP, return an error
to prevent incorrect format selection.
This change enables finer-grained format support control for different
SoC variants.
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>
---
v1->v2:
- Renamed RZ_MIPI_DSI_FEATURE_16BPP
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 9 +++++++++
1 file changed, 9 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 4a8fe52e9752..c8be7428c4d7 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -29,6 +29,7 @@
#include "rzg2l_mipi_dsi_regs.h"
#define RZ_MIPI_DSI_FEATURE_DPHY_RST BIT(0)
+#define RZ_MIPI_DSI_FEATURE_16BPP BIT(1)
struct rzg2l_mipi_dsi;
@@ -643,8 +644,16 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
switch (mipi_dsi_pixel_format_to_bpp(device->format)) {
case 24:
+ break;
case 18:
break;
+ case 16:
+ if (!(dsi->info->features & RZ_MIPI_DSI_FEATURE_16BPP)) {
+ dev_err(dsi->dev, "Unsupported format 0x%04x\n",
+ device->format);
+ return -EINVAL;
+ }
+ break;
default:
dev_err(dsi->dev, "Unsupported format 0x%04x\n", device->format);
return -EINVAL;
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 12/15] drm: renesas: rz-du: mipi_dsi: Add dphy_late_init() callback for RZ/V2H(P)
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (10 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 11/15] drm: renesas: rz-du: mipi_dsi: Add feature flag for 16BPP support Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 13/15] drm: renesas: rz-du: mipi_dsi: Add function pointers for configuring VCLK and mode validation Prabhakar
` (2 subsequent siblings)
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Introduce the `dphy_late_init` callback in `rzg2l_mipi_dsi_hw_info` to
allow additional D-PHY register configurations after enabling data and
clock lanes. This is required for the RZ/V2H(P) SoC but not for the
RZ/G2L SoC.
Modify `rzg2l_mipi_dsi_startup()` to invoke `dphy_late_init` if defined,
ensuring SoC-specific initialization is performed only when necessary.
This change prepares for RZ/V2H(P) SoC support while maintaining
compatibility with 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>
---
v1->v2:
- No changes
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 4 ++++
1 file changed, 4 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 c8be7428c4d7..85f23a41911e 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -35,6 +35,7 @@ struct rzg2l_mipi_dsi;
struct rzg2l_mipi_dsi_hw_info {
int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long long hsfreq_mhz);
+ void (*dphy_late_init)(struct rzg2l_mipi_dsi *dsi);
void (*dphy_exit)(struct rzg2l_mipi_dsi *dsi);
u32 phy_reg_offset;
u32 link_reg_offset;
@@ -318,6 +319,9 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
txsetr = TXSETR_DLEN | TXSETR_NUMLANEUSE(dsi->lanes - 1) | TXSETR_CLEN;
rzg2l_mipi_dsi_link_write(dsi, TXSETR, txsetr);
+ if (dsi->info->dphy_late_init)
+ dsi->info->dphy_late_init(dsi);
+
hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
/*
* Global timings characteristic depends on high speed Clock Frequency
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 13/15] drm: renesas: rz-du: mipi_dsi: Add function pointers for configuring VCLK and mode validation
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (11 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 12/15] drm: renesas: rz-du: mipi_dsi: Add dphy_late_init() callback for RZ/V2H(P) Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 14/15] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK handling Prabhakar
2025-04-08 20:09 ` [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Introduce `dphy_conf_clks` and `dphy_mode_clk_check` callbacks in
`rzg2l_mipi_dsi_hw_info` to configure the VCLK and validate
supported display modes.
On the RZ/V2H(P) SoC, the DSI PLL dividers need to be as accurate as
possible. To ensure compatibility with both RZ/G2L and RZ/V2H(P) SoCs,
function pointers are introduced.
Modify `rzg2l_mipi_dsi_startup()` to use `dphy_conf_clks` for clock
configuration and `rzg2l_mipi_dsi_bridge_mode_valid()` to invoke
`dphy_mode_clk_check` for mode validation.
This change ensures proper operation across different SoC variants
by allowing fine-grained control over clock configuration and mode
validation.
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>
---
v1->v2:
- No changes
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 59 +++++++++++++------
1 file changed, 42 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 85f23a41911e..a9dad3b1974f 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -37,6 +37,10 @@ struct rzg2l_mipi_dsi_hw_info {
int (*dphy_init)(struct rzg2l_mipi_dsi *dsi, unsigned long long hsfreq_mhz);
void (*dphy_late_init)(struct rzg2l_mipi_dsi *dsi);
void (*dphy_exit)(struct rzg2l_mipi_dsi *dsi);
+ int (*dphy_conf_clks)(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+ unsigned long long *hsfreq_mhz);
+ unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
+ unsigned long mode_freq);
u32 phy_reg_offset;
u32 link_reg_offset;
unsigned long max_dclk;
@@ -276,12 +280,36 @@ static void rzg2l_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
reset_control_assert(dsi->rstc);
}
+static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+ unsigned long long *hsfreq_mhz)
+{
+ unsigned long vclk_rate;
+ unsigned int bpp;
+
+ clk_set_rate(dsi->vclk, mode_freq * KILO);
+ /*
+ * Relationship between hsclk and vclk must follow
+ * vclk * bpp = hsclk * 8 * lanes
+ * where vclk: video clock (Hz)
+ * bpp: video pixel bit depth
+ * hsclk: DSI HS Byte clock frequency (Hz)
+ * lanes: number of data lanes
+ *
+ * hsclk(bit) = hsclk(byte) * 8 = hsfreq
+ */
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ vclk_rate = clk_get_rate(dsi->vclk);
+ *hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp * KILO * 1ULL,
+ dsi->lanes);
+
+ return 0;
+}
+
static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
const struct drm_display_mode *mode)
{
- unsigned long hsfreq, vclk_rate;
unsigned long long hsfreq_mhz;
- unsigned int bpp;
+ unsigned long hsfreq;
u32 txsetr;
u32 clstptsetr;
u32 lptrnstsetr;
@@ -295,21 +323,9 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
if (ret < 0)
return ret;
- clk_set_rate(dsi->vclk, mode->clock * KILO);
-
- /*
- * Relationship between hsclk and vclk must follow
- * vclk * bpp = hsclk * 8 * lanes
- * where vclk: video clock (Hz)
- * bpp: video pixel bit depth
- * hsclk: DSI HS Byte clock frequency (Hz)
- * lanes: number of data lanes
- *
- * hsclk(bit) = hsclk(byte) * 8 = hsfreq
- */
- bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
- vclk_rate = clk_get_rate(dsi->vclk);
- hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(vclk_rate * bpp * KILO * 1ULL, dsi->lanes);
+ ret = dsi->info->dphy_conf_clks(dsi, mode->clock, &hsfreq_mhz);
+ if (ret < 0)
+ goto err_phy;
ret = dsi->info->dphy_init(dsi, hsfreq_mhz);
if (ret < 0)
@@ -616,6 +632,14 @@ rzg2l_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
if (mode->clock < dsi->info->min_dclk)
return MODE_CLOCK_LOW;
+ if (dsi->info->dphy_mode_clk_check) {
+ enum drm_mode_status status;
+
+ status = dsi->info->dphy_mode_clk_check(dsi, mode->clock);
+ if (status != MODE_OK)
+ return status;
+ }
+
return MODE_OK;
}
@@ -838,6 +862,7 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
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,
+ .dphy_conf_clks = rzg2l_dphy_conf_clks,
.link_reg_offset = 0x10000,
.max_dclk = 148500,
.min_dclk = 5803,
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 14/15] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK handling
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (12 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 13/15] drm: renesas: rz-du: mipi_dsi: Add function pointers for configuring VCLK and mode validation Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-08 20:09 ` [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
14 siblings, 0 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, Prabhakar, Fabrizio Castro,
Tommaso Merciai, Lad Prabhakar
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Introduce the `RZ_MIPI_DSI_FEATURE_LPCLK` feature flag in
`rzg2l_mipi_dsi_hw_info` to indicate the need for LPCLK configuration.
On the RZ/V2H(P) SoC, the LPCLK clock rate influences the required
DPHY register configuration, whereas on the RZ/G2L SoC, this clock
is not present. To accommodate this difference, add an `lpclk`
clock handle in `rzg2l_mipi_dsi` and update the probe function to
conditionally acquire LPCLK if the SoC supports it.
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>
---
v1->v2:
- Added LPCLK as feature flag
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 8 ++++++++
1 file changed, 8 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 a9dad3b1974f..6c6bc59eabbc 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -30,6 +30,7 @@
#define RZ_MIPI_DSI_FEATURE_DPHY_RST BIT(0)
#define RZ_MIPI_DSI_FEATURE_16BPP BIT(1)
+#define RZ_MIPI_DSI_FEATURE_LPCLK BIT(2)
struct rzg2l_mipi_dsi;
@@ -63,6 +64,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;
@@ -791,6 +793,12 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->vclk))
return PTR_ERR(dsi->vclk);
+ if (dsi->info->features & RZ_MIPI_DSI_FEATURE_LPCLK) {
+ dsi->lpclk = devm_clk_get(dsi->dev, "lpclk");
+ if (IS_ERR(dsi->lpclk))
+ return PTR_ERR(dsi->lpclk);
+ }
+
if (dsi->info->features & RZ_MIPI_DSI_FEATURE_DPHY_RST) {
dsi->rstc = devm_reset_control_get_exclusive(dsi->dev, "rst");
if (IS_ERR(dsi->rstc))
--
2.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-04-08 20:08 [PATCH v2 00/15] Add support for DU and DSI on the Renesas RZ/V2H(P) SoC Prabhakar
` (13 preceding siblings ...)
2025-04-08 20:09 ` [PATCH v2 14/15] drm: renesas: rz-du: mipi_dsi: Add support for LPCLK handling Prabhakar
@ 2025-04-08 20:09 ` Prabhakar
2025-04-12 8:00 ` Biju Das
2025-04-16 9:28 ` Geert Uytterhoeven
14 siblings, 2 replies; 31+ messages in thread
From: Prabhakar @ 2025-04-08 20:09 UTC (permalink / raw)
To: 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, Biju Das, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk
Cc: linux-renesas-soc, linux-kernel, 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>
---
v1->v2:
- Dropped unused macros
- Added missing LPCLK flag to rzvv2h info
---
.../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 451 ++++++++++++++++++
.../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
2 files changed, 485 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 6c6bc59eabbc..e260e2ed03c1 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -5,6 +5,7 @@
* Copyright (C) 2022 Renesas Electronics Corporation
*/
#include <linux/clk.h>
+#include <linux/clk/renesas-rzv2h-dsi.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -32,6 +33,9 @@
#define RZ_MIPI_DSI_FEATURE_16BPP BIT(1)
#define RZ_MIPI_DSI_FEATURE_LPCLK BIT(2)
+#define RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA (80 * MEGA)
+#define RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA (1500 * MEGA)
+
struct rzg2l_mipi_dsi;
struct rzg2l_mipi_dsi_hw_info {
@@ -42,6 +46,7 @@ struct rzg2l_mipi_dsi_hw_info {
unsigned long long *hsfreq_mhz);
unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
unsigned long mode_freq);
+ const struct rzv2h_plldsi_div_limits *cpg_dsi_limits;
u32 phy_reg_offset;
u32 link_reg_offset;
unsigned long max_dclk;
@@ -49,6 +54,11 @@ struct rzg2l_mipi_dsi_hw_info {
u8 features;
};
+struct rzv2h_dsi_mode_calc {
+ unsigned long mode_freq;
+ unsigned long long mode_freq_hz;
+};
+
struct rzg2l_mipi_dsi {
struct device *dev;
void __iomem *mmio;
@@ -70,6 +80,18 @@ struct rzg2l_mipi_dsi {
unsigned int num_data_lanes;
unsigned int lanes;
unsigned long mode_flags;
+
+ struct rzv2h_dsi_mode_calc mode_calc;
+ struct rzv2h_plldsi_parameters dsi_parameters;
+};
+
+static const struct rzv2h_plldsi_div_limits rzv2h_plldsi_div_limits = {
+ .m = { .min = 64, .max = 1023 },
+ .p = { .min = 1, .max = 4 },
+ .s = { .min = 0, .max = 5 },
+ .k = { .min = -32768, .max = 32767 },
+ .csdiv = { .min = 1, .max = 1 },
+ .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA }
};
static inline struct rzg2l_mipi_dsi *
@@ -186,6 +208,249 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
},
};
+struct rzv2h_mipi_dsi_timings {
+ unsigned long hsfreq;
+ u16 value;
+};
+
+static const struct rzv2h_mipi_dsi_timings TCLKPRPRCTL[] = {
+ {150000000UL, 0},
+ {260000000UL, 1},
+ {370000000UL, 2},
+ {470000000UL, 3},
+ {580000000UL, 4},
+ {690000000UL, 5},
+ {790000000UL, 6},
+ {900000000UL, 7},
+ {1010000000UL, 8},
+ {1110000000UL, 9},
+ {1220000000UL, 10},
+ {1330000000UL, 11},
+ {1430000000UL, 12},
+ {1500000000UL, 13},
+};
+
+static const struct rzv2h_mipi_dsi_timings TCLKZEROCTL[] = {
+ {90000000UL, 2},
+ {110000000UL, 3},
+ {130000000UL, 4},
+ {150000000UL, 5},
+ {180000000UL, 6},
+ {210000000UL, 7},
+ {230000000UL, 8},
+ {240000000UL, 9},
+ {250000000UL, 10},
+ {270000000UL, 11},
+ {290000000UL, 12},
+ {310000000UL, 13},
+ {340000000UL, 14},
+ {360000000UL, 15},
+ {380000000UL, 16},
+ {410000000UL, 17},
+ {430000000UL, 18},
+ {450000000UL, 19},
+ {470000000UL, 20},
+ {500000000UL, 21},
+ {520000000UL, 22},
+ {540000000UL, 23},
+ {570000000UL, 24},
+ {590000000UL, 25},
+ {610000000UL, 26},
+ {630000000UL, 27},
+ {660000000UL, 28},
+ {680000000UL, 29},
+ {700000000UL, 30},
+ {730000000UL, 31},
+ {750000000UL, 32},
+ {770000000UL, 33},
+ {790000000UL, 34},
+ {820000000UL, 35},
+ {840000000UL, 36},
+ {860000000UL, 37},
+ {890000000UL, 38},
+ {910000000UL, 39},
+ {930000000UL, 40},
+ {950000000UL, 41},
+ {980000000UL, 42},
+ {1000000000UL, 43},
+ {1020000000UL, 44},
+ {1050000000UL, 45},
+ {1070000000UL, 46},
+ {1090000000UL, 47},
+ {1110000000UL, 48},
+ {1140000000UL, 49},
+ {1160000000UL, 50},
+ {1180000000UL, 51},
+ {1210000000UL, 52},
+ {1230000000UL, 53},
+ {1250000000UL, 54},
+ {1270000000UL, 55},
+ {1300000000UL, 56},
+ {1320000000UL, 57},
+ {1340000000UL, 58},
+ {1370000000UL, 59},
+ {1390000000UL, 60},
+ {1410000000UL, 61},
+ {1430000000UL, 62},
+ {1460000000UL, 63},
+ {1480000000UL, 64},
+ {1500000000UL, 65},
+};
+
+static const struct rzv2h_mipi_dsi_timings TCLKPOSTCTL[] = {
+ {80000000UL, 6},
+ {210000000UL, 7},
+ {340000000UL, 8},
+ {480000000UL, 9},
+ {610000000UL, 10},
+ {740000000UL, 11},
+ {880000000UL, 12},
+ {1010000000UL, 13},
+ {1140000000UL, 14},
+ {1280000000UL, 15},
+ {1410000000UL, 16},
+ {1500000000UL, 17},
+};
+
+static const struct rzv2h_mipi_dsi_timings TCLKTRAILCTL[] = {
+ {140000000UL, 1},
+ {250000000UL, 2},
+ {370000000UL, 3},
+ {480000000UL, 4},
+ {590000000UL, 5},
+ {710000000UL, 6},
+ {820000000UL, 7},
+ {940000000UL, 8},
+ {1050000000UL, 9},
+ {1170000000UL, 10},
+ {1280000000UL, 11},
+ {1390000000UL, 12},
+ {1500000000UL, 13},
+};
+
+static const struct rzv2h_mipi_dsi_timings THSPRPRCTL[] = {
+ {110000000UL, 0},
+ {190000000UL, 1},
+ {290000000UL, 2},
+ {400000000UL, 3},
+ {500000000UL, 4},
+ {610000000UL, 5},
+ {720000000UL, 6},
+ {820000000UL, 7},
+ {930000000UL, 8},
+ {1030000000UL, 9},
+ {1140000000UL, 10},
+ {1250000000UL, 11},
+ {1350000000UL, 12},
+ {1460000000UL, 13},
+ {1500000000UL, 14},
+};
+
+static const struct rzv2h_mipi_dsi_timings THSZEROCTL[] = {
+ {180000000UL, 0},
+ {240000000UL, 1},
+ {290000000UL, 2},
+ {350000000UL, 3},
+ {400000000UL, 4},
+ {460000000UL, 5},
+ {510000000UL, 6},
+ {570000000UL, 7},
+ {620000000UL, 8},
+ {680000000UL, 9},
+ {730000000UL, 10},
+ {790000000UL, 11},
+ {840000000UL, 12},
+ {900000000UL, 13},
+ {950000000UL, 14},
+ {1010000000UL, 15},
+ {1060000000UL, 16},
+ {1120000000UL, 17},
+ {1170000000UL, 18},
+ {1230000000UL, 19},
+ {1280000000UL, 20},
+ {1340000000UL, 21},
+ {1390000000UL, 22},
+ {1450000000UL, 23},
+ {1500000000UL, 24},
+};
+
+static const struct rzv2h_mipi_dsi_timings THSTRAILCTL[] = {
+ {100000000UL, 3},
+ {210000000UL, 4},
+ {320000000UL, 5},
+ {420000000UL, 6},
+ {530000000UL, 7},
+ {640000000UL, 8},
+ {750000000UL, 9},
+ {850000000UL, 10},
+ {960000000UL, 11},
+ {1070000000UL, 12},
+ {1180000000UL, 13},
+ {1280000000UL, 14},
+ {1390000000UL, 15},
+ {1500000000UL, 16},
+};
+
+static const struct rzv2h_mipi_dsi_timings TLPXCTL[] = {
+ {130000000UL, 0},
+ {260000000UL, 1},
+ {390000000UL, 2},
+ {530000000UL, 3},
+ {660000000UL, 4},
+ {790000000UL, 5},
+ {930000000UL, 6},
+ {1060000000UL, 7},
+ {1190000000UL, 8},
+ {1330000000UL, 9},
+ {1460000000UL, 10},
+ {1500000000UL, 11},
+};
+
+static const struct rzv2h_mipi_dsi_timings THSEXITCTL[] = {
+ {150000000UL, 1},
+ {230000000UL, 2},
+ {310000000UL, 3},
+ {390000000UL, 4},
+ {470000000UL, 5},
+ {550000000UL, 6},
+ {630000000UL, 7},
+ {710000000UL, 8},
+ {790000000UL, 9},
+ {870000000UL, 10},
+ {950000000UL, 11},
+ {1030000000UL, 12},
+ {1110000000UL, 13},
+ {1190000000UL, 14},
+ {1270000000UL, 15},
+ {1350000000UL, 16},
+ {1430000000UL, 17},
+ {1500000000UL, 18},
+};
+
+static const struct rzv2h_mipi_dsi_timings ULPSEXIT[] = {
+ {1953125UL, 49},
+ {3906250UL, 98},
+ {7812500UL, 195},
+ {15625000UL, 391},
+};
+
+static int rzv2h_dphy_find_timings_val(unsigned long freq,
+ const struct rzv2h_mipi_dsi_timings timings[],
+ unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (freq <= timings[i].hsfreq)
+ break;
+ }
+
+ if (i == size)
+ i -= 1;
+
+ return timings[i].value;
+};
+
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);
@@ -307,6 +572,168 @@ 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)
+{
+ struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
+ unsigned long long hsfreq_mhz, mode_freq_hz, mode_freq_mhz;
+ struct rzv2h_plldsi_parameters cpg_dsi_parameters;
+ unsigned int bpp, i;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+
+ for (i = 0; i < 10; i += 1) {
+ unsigned long hsfreq;
+ bool parameters_found;
+
+ mode_freq_hz = mode_freq * KILO + i;
+ mode_freq_mhz = mode_freq_hz * KILO * 1ULL;
+ parameters_found = rzv2h_dsi_get_pll_parameters_values(dsi->info->cpg_dsi_limits,
+ &cpg_dsi_parameters,
+ mode_freq_mhz);
+ if (!parameters_found)
+ continue;
+
+ hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.freq_mhz * bpp, dsi->lanes);
+ parameters_found = rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
+ dsi_parameters,
+ hsfreq_mhz);
+ if (!parameters_found)
+ continue;
+
+ if (abs(dsi_parameters->error_mhz) >= 500)
+ continue;
+
+ hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
+ if (hsfreq >= RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA &&
+ hsfreq <= RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA) {
+ dsi->mode_calc.mode_freq_hz = mode_freq_hz;
+ dsi->mode_calc.mode_freq = mode_freq;
+ return MODE_OK;
+ }
+ }
+
+ return MODE_CLOCK_RANGE;
+}
+
+static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+ unsigned long long *hsfreq_mhz)
+{
+ struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
+ unsigned long status;
+
+ if (dsi->mode_calc.mode_freq != 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;
+ }
+ }
+
+ clk_set_rate(dsi->vclk, dsi->mode_calc.mode_freq_hz);
+ *hsfreq_mhz = dsi_parameters->freq_mhz;
+
+ return 0;
+}
+
+static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+ unsigned long long hsfreq_mhz)
+{
+ struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
+ unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
+ u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
+ struct rzg2l_mipi_dsi_timings dphy_timings;
+ unsigned long long hsfreq;
+ u32 ulpsexit;
+
+ hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
+
+ if (dsi_parameters->freq_mhz == hsfreq_mhz)
+ goto parameters_found;
+
+ if (rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
+ dsi_parameters, hsfreq_mhz))
+ 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,
+ ARRAY_SIZE(TCLKTRAILCTL));
+ dphy_timings.tclk_post =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL,
+ ARRAY_SIZE(TCLKPOSTCTL));
+ dphy_timings.tclk_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL,
+ ARRAY_SIZE(TCLKZEROCTL));
+ dphy_timings.tclk_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL,
+ ARRAY_SIZE(TCLKPRPRCTL));
+ dphy_timings.ths_exit =
+ rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL,
+ ARRAY_SIZE(THSEXITCTL));
+ dphy_timings.ths_trail =
+ rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL,
+ ARRAY_SIZE(THSTRAILCTL));
+ dphy_timings.ths_zero =
+ rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL,
+ ARRAY_SIZE(THSZEROCTL));
+ dphy_timings.ths_prepare =
+ rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL,
+ ARRAY_SIZE(THSPRPRCTL));
+ dphy_timings.tlpx =
+ rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL,
+ ARRAY_SIZE(TLPXCTL));
+ ulpsexit =
+ rzv2h_dphy_find_timings_val(lpclk_rate, ULPSEXIT,
+ ARRAY_SIZE(ULPSEXIT));
+
+ phytclksetr = PHYTCLKSETR_TCLKTRAILCTL(dphy_timings.tclk_trail) |
+ PHYTCLKSETR_TCLKPOSTCTL(dphy_timings.tclk_post) |
+ PHYTCLKSETR_TCLKZEROCTL(dphy_timings.tclk_zero) |
+ PHYTCLKSETR_TCLKPRPRCTL(dphy_timings.tclk_prepare);
+ phythssetr = PHYTHSSETR_THSEXITCTL(dphy_timings.ths_exit) |
+ PHYTHSSETR_THSTRAILCTL(dphy_timings.ths_trail) |
+ PHYTHSSETR_THSZEROCTL(dphy_timings.ths_zero) |
+ PHYTHSSETR_THSPRPRCTL(dphy_timings.ths_prepare);
+ phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~GENMASK(7, 0);
+ phytlpxsetr |= PHYTLPXSETR_TLPXCTL(dphy_timings.tlpx);
+ phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
+ phycr |= 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,
+ PLLCLKSET0R_PLL_S(dsi_parameters->s) |
+ PLLCLKSET0R_PLL_P(dsi_parameters->p) |
+ PLLCLKSET0R_PLL_M(dsi_parameters->m));
+ rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R, PLLCLKSET1R_PLL_K(dsi_parameters->k));
+ udelay(20);
+
+ rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
+ udelay(500);
+
+ return 0;
+}
+
+static void rzv2h_mipi_dsi_dphy_late_init(struct rzg2l_mipi_dsi *dsi)
+{
+ udelay(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)
{
@@ -409,6 +836,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) &&
@@ -439,6 +869,9 @@ static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
rzg2l_mipi_dsi_link_write(dsi, VICH1HSSETR, vich1hssetr);
rzg2l_mipi_dsi_link_write(dsi, VICH1HPSETR, vich1hpsetr);
+ if (dsi->info->dphy_late_init)
+ dsi->info->dphy_late_init(dsi);
+
/*
* Configuration for Delay Value
* Delay value based on 2 ranges of video clock.
@@ -867,6 +1300,23 @@ 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 rzg2l_mipi_dsi_hw_info rzv2h_mipi_dsi_info = {
+ .dphy_init = rzv2h_mipi_dsi_dphy_init,
+ .dphy_late_init = rzv2h_mipi_dsi_dphy_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_dsi_limits = &rzv2h_cpg_pll_dsi_limits,
+ .phy_reg_offset = 0x10000,
+ .link_reg_offset = 0,
+ .max_dclk = 187500,
+ .min_dclk = 5440,
+ .features = RZ_MIPI_DSI_FEATURE_16BPP |
+ RZ_MIPI_DSI_FEATURE_LPCLK,
+};
+
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,
@@ -878,6 +1328,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 16efe4dc59f4..68165395d61c 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(x) ((x) << 0)
+#define PLLCLKSET0R_PLL_P(x) ((x) << 8)
+#define PLLCLKSET0R_PLL_M(x) ((x) << 16)
+
+#define PLLCLKSET1R 0x014
+#define PLLCLKSET1R_PLL_K(x) ((x) << 0)
+
+#define PHYTCLKSETR 0x020
+#define PHYTCLKSETR_TCLKTRAILCTL(x) ((x) << 0)
+#define PHYTCLKSETR_TCLKPOSTCTL(x) ((x) << 8)
+#define PHYTCLKSETR_TCLKZEROCTL(x) ((x) << 16)
+#define PHYTCLKSETR_TCLKPRPRCTL(x) ((x) << 24)
+
+#define PHYTHSSETR 0x024
+#define PHYTHSSETR_THSEXITCTL(x) ((x) << 0)
+#define PHYTHSSETR_THSTRAILCTL(x) ((x) << 8)
+#define PHYTHSSETR_THSZEROCTL(x) ((x) << 16)
+#define PHYTHSSETR_THSPRPRCTL(x) ((x) << 24)
+
+#define PHYTLPXSETR 0x028
+#define PHYTLPXSETR_TLPXCTL(x) ((x) << 0)
+
+#define PHYCR 0x030
+#define PHYCR_ULPSEXIT(x) ((x) << 0)
+
/* --------------------------------------------------------*/
/* Link Status Register */
@@ -116,6 +149,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.49.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* RE: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-04-08 20:09 ` [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
@ 2025-04-12 8:00 ` Biju Das
2025-04-18 9:24 ` Lad, Prabhakar
2025-04-16 9:28 ` Geert Uytterhoeven
1 sibling, 1 reply; 31+ messages in thread
From: Biju Das @ 2025-04-12 8:00 UTC (permalink / raw)
To: Prabhakar, 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,
Tomi Valkeinen, Geert Uytterhoeven, Michael Turquette,
Stephen Boyd, Philipp Zabel, Magnus Damm,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-clk@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org, linux-kernel@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: 08 April 2025 21:09
> Subject: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
>
> 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>
> ---
> v1->v2:
> - Dropped unused macros
> - Added missing LPCLK flag to rzvv2h info
> ---
> .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 451 ++++++++++++++++++
> .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> 2 files changed, 485 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 6c6bc59eabbc..e260e2ed03c1 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> @@ -5,6 +5,7 @@
> * Copyright (C) 2022 Renesas Electronics Corporation
> */
> #include <linux/clk.h>
> +#include <linux/clk/renesas-rzv2h-dsi.h>
This patch has hard dependency on clk driver.
> #include <linux/delay.h>
> #include <linux/io.h>
> #include <linux/iopoll.h>
> @@ -32,6 +33,9 @@
> #define RZ_MIPI_DSI_FEATURE_16BPP BIT(1)
> #define RZ_MIPI_DSI_FEATURE_LPCLK BIT(2)
>
> +#define RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA (80 * MEGA)
> +#define RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA (1500 * MEGA)
> +
> struct rzg2l_mipi_dsi;
>
> struct rzg2l_mipi_dsi_hw_info {
> @@ -42,6 +46,7 @@ struct rzg2l_mipi_dsi_hw_info {
> unsigned long long *hsfreq_mhz);
> unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> unsigned long mode_freq);
> + const struct rzv2h_plldsi_div_limits *cpg_dsi_limits;
> u32 phy_reg_offset;
> u32 link_reg_offset;
> unsigned long max_dclk;
> @@ -49,6 +54,11 @@ struct rzg2l_mipi_dsi_hw_info {
> u8 features;
> };
>
> +struct rzv2h_dsi_mode_calc {
> + unsigned long mode_freq;
> + unsigned long long mode_freq_hz;
> +};
> +
> struct rzg2l_mipi_dsi {
> struct device *dev;
> void __iomem *mmio;
> @@ -70,6 +80,18 @@ struct rzg2l_mipi_dsi {
> unsigned int num_data_lanes;
> unsigned int lanes;
> unsigned long mode_flags;
> +
> + struct rzv2h_dsi_mode_calc mode_calc;
> + struct rzv2h_plldsi_parameters dsi_parameters; };
> +
> +static const struct rzv2h_plldsi_div_limits rzv2h_plldsi_div_limits = {
> + .m = { .min = 64, .max = 1023 },
> + .p = { .min = 1, .max = 4 },
> + .s = { .min = 0, .max = 5 },
> + .k = { .min = -32768, .max = 32767 },
> + .csdiv = { .min = 1, .max = 1 },
> + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA }
> };
>
> static inline struct rzg2l_mipi_dsi *
> @@ -186,6 +208,249 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> },
> };
>
> +struct rzv2h_mipi_dsi_timings {
> + unsigned long hsfreq;
> + u16 value;
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings TCLKPRPRCTL[] = {
> + {150000000UL, 0},
> + {260000000UL, 1},
> + {370000000UL, 2},
> + {470000000UL, 3},
> + {580000000UL, 4},
> + {690000000UL, 5},
> + {790000000UL, 6},
> + {900000000UL, 7},
> + {1010000000UL, 8},
> + {1110000000UL, 9},
> + {1220000000UL, 10},
> + {1330000000UL, 11},
> + {1430000000UL, 12},
> + {1500000000UL, 13},
> +};
Not sure, Is it right approach to optimize this table as the second entry is sequential
with a fixed number for all tables except last one?
28 bytes can be saved, if we use a variable holding start_index.
> +
> +static const struct rzv2h_mipi_dsi_timings TCLKZEROCTL[] = {
> + {90000000UL, 2},
> + {110000000UL, 3},
> + {130000000UL, 4},
> + {150000000UL, 5},
> + {180000000UL, 6},
> + {210000000UL, 7},
> + {230000000UL, 8},
> + {240000000UL, 9},
> + {250000000UL, 10},
> + {270000000UL, 11},
> + {290000000UL, 12},
> + {310000000UL, 13},
> + {340000000UL, 14},
> + {360000000UL, 15},
> + {380000000UL, 16},
> + {410000000UL, 17},
> + {430000000UL, 18},
> + {450000000UL, 19},
> + {470000000UL, 20},
> + {500000000UL, 21},
> + {520000000UL, 22},
> + {540000000UL, 23},
> + {570000000UL, 24},
> + {590000000UL, 25},
> + {610000000UL, 26},
> + {630000000UL, 27},
> + {660000000UL, 28},
> + {680000000UL, 29},
> + {700000000UL, 30},
> + {730000000UL, 31},
> + {750000000UL, 32},
> + {770000000UL, 33},
> + {790000000UL, 34},
> + {820000000UL, 35},
> + {840000000UL, 36},
> + {860000000UL, 37},
> + {890000000UL, 38},
> + {910000000UL, 39},
> + {930000000UL, 40},
> + {950000000UL, 41},
> + {980000000UL, 42},
> + {1000000000UL, 43},
> + {1020000000UL, 44},
> + {1050000000UL, 45},
> + {1070000000UL, 46},
> + {1090000000UL, 47},
> + {1110000000UL, 48},
> + {1140000000UL, 49},
> + {1160000000UL, 50},
> + {1180000000UL, 51},
> + {1210000000UL, 52},
> + {1230000000UL, 53},
> + {1250000000UL, 54},
> + {1270000000UL, 55},
> + {1300000000UL, 56},
> + {1320000000UL, 57},
> + {1340000000UL, 58},
> + {1370000000UL, 59},
> + {1390000000UL, 60},
> + {1410000000UL, 61},
> + {1430000000UL, 62},
> + {1460000000UL, 63},
> + {1480000000UL, 64},
> + {1500000000UL, 65},
Same. Here 128 bytes
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings TCLKPOSTCTL[] = {
> + {80000000UL, 6},
> + {210000000UL, 7},
> + {340000000UL, 8},
> + {480000000UL, 9},
> + {610000000UL, 10},
> + {740000000UL, 11},
> + {880000000UL, 12},
> + {1010000000UL, 13},
> + {1140000000UL, 14},
> + {1280000000UL, 15},
> + {1410000000UL, 16},
> + {1500000000UL, 17},
Same. Here 24 bytes
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings TCLKTRAILCTL[] = {
> + {140000000UL, 1},
> + {250000000UL, 2},
> + {370000000UL, 3},
> + {480000000UL, 4},
> + {590000000UL, 5},
> + {710000000UL, 6},
> + {820000000UL, 7},
> + {940000000UL, 8},
> + {1050000000UL, 9},
> + {1170000000UL, 10},
> + {1280000000UL, 11},
> + {1390000000UL, 12},
> + {1500000000UL, 13},
Same. Here 26 bytes
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings THSPRPRCTL[] = {
> + {110000000UL, 0},
> + {190000000UL, 1},
> + {290000000UL, 2},
> + {400000000UL, 3},
> + {500000000UL, 4},
> + {610000000UL, 5},
> + {720000000UL, 6},
> + {820000000UL, 7},
> + {930000000UL, 8},
> + {1030000000UL, 9},
> + {1140000000UL, 10},
> + {1250000000UL, 11},
> + {1350000000UL, 12},
> + {1460000000UL, 13},
> + {1500000000UL, 14},
Same. Here 30 bytes
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings THSZEROCTL[] = {
> + {180000000UL, 0},
> + {240000000UL, 1},
> + {290000000UL, 2},
> + {350000000UL, 3},
> + {400000000UL, 4},
> + {460000000UL, 5},
> + {510000000UL, 6},
> + {570000000UL, 7},
> + {620000000UL, 8},
> + {680000000UL, 9},
> + {730000000UL, 10},
> + {790000000UL, 11},
> + {840000000UL, 12},
> + {900000000UL, 13},
> + {950000000UL, 14},
> + {1010000000UL, 15},
> + {1060000000UL, 16},
> + {1120000000UL, 17},
> + {1170000000UL, 18},
> + {1230000000UL, 19},
> + {1280000000UL, 20},
> + {1340000000UL, 21},
> + {1390000000UL, 22},
> + {1450000000UL, 23},
> + {1500000000UL, 24},
Same. Here 50 bytes.
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings THSTRAILCTL[] = {
> + {100000000UL, 3},
> + {210000000UL, 4},
> + {320000000UL, 5},
> + {420000000UL, 6},
> + {530000000UL, 7},
> + {640000000UL, 8},
> + {750000000UL, 9},
> + {850000000UL, 10},
> + {960000000UL, 11},
> + {1070000000UL, 12},
> + {1180000000UL, 13},
> + {1280000000UL, 14},
> + {1390000000UL, 15},
> + {1500000000UL, 16},
Same. Here 28 bytes?
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings TLPXCTL[] = {
> + {130000000UL, 0},
> + {260000000UL, 1},
> + {390000000UL, 2},
> + {530000000UL, 3},
> + {660000000UL, 4},
> + {790000000UL, 5},
> + {930000000UL, 6},
> + {1060000000UL, 7},
> + {1190000000UL, 8},
> + {1330000000UL, 9},
> + {1460000000UL, 10},
> + {1500000000UL, 11},
Same. Here 24 bytes
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings THSEXITCTL[] = {
> + {150000000UL, 1},
> + {230000000UL, 2},
> + {310000000UL, 3},
> + {390000000UL, 4},
> + {470000000UL, 5},
> + {550000000UL, 6},
> + {630000000UL, 7},
> + {710000000UL, 8},
> + {790000000UL, 9},
> + {870000000UL, 10},
> + {950000000UL, 11},
> + {1030000000UL, 12},
> + {1110000000UL, 13},
> + {1190000000UL, 14},
> + {1270000000UL, 15},
> + {1350000000UL, 16},
> + {1430000000UL, 17},
> + {1500000000UL, 18},
Same. Here 36 bytes.
> +};
> +
> +static const struct rzv2h_mipi_dsi_timings ULPSEXIT[] = {
> + {1953125UL, 49},
> + {3906250UL, 98},
> + {7812500UL, 195},
> + {15625000UL, 391},
Here we have problem as it is non-sequential and only has 4 entries?
Since it is ULPS EXIT Counter values compared to DPHY timings
This can have its own structure?
> +};
> +
> +static int rzv2h_dphy_find_timings_val(unsigned long freq,
> + const struct rzv2h_mipi_dsi_timings timings[],
> + unsigned int size)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < size; i++) {
> + if (freq <= timings[i].hsfreq)
> + break;
> + }
> +
> + if (i == size)
> + i -= 1;
> +
> + return timings[i].value;
This will be then start_index + i for all DPHY timing parmeter table.
And
Maybe use another function to find ULPS EXIT Counter values??
> +};
> +
> 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); @@ -307,6 +572,168 @@ 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)
> +{
> + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> + unsigned long long hsfreq_mhz, mode_freq_hz, mode_freq_mhz;
> + struct rzv2h_plldsi_parameters cpg_dsi_parameters;
> + unsigned int bpp, i;
> +
> + bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> +
> + for (i = 0; i < 10; i += 1) {
> + unsigned long hsfreq;
> + bool parameters_found;
> +
> + mode_freq_hz = mode_freq * KILO + i;
> + mode_freq_mhz = mode_freq_hz * KILO * 1ULL;
> + parameters_found = rzv2h_dsi_get_pll_parameters_values(dsi->info->cpg_dsi_limits,
> + &cpg_dsi_parameters,
> + mode_freq_mhz);
> + if (!parameters_found)
> + continue;
> +
> + hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.freq_mhz * bpp, dsi->lanes);
> + parameters_found = rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
> + dsi_parameters,
> + hsfreq_mhz);
> + if (!parameters_found)
> + continue;
> +
> + if (abs(dsi_parameters->error_mhz) >= 500)
> + continue;
> +
> + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
> + if (hsfreq >= RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA &&
> + hsfreq <= RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA) {
> + dsi->mode_calc.mode_freq_hz = mode_freq_hz;
> + dsi->mode_calc.mode_freq = mode_freq;
> + return MODE_OK;
> + }
> + }
> +
> + return MODE_CLOCK_RANGE;
> +}
> +
> +static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
> + unsigned long long *hsfreq_mhz)
> +{
> + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> + unsigned long status;
> +
> + if (dsi->mode_calc.mode_freq != 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;
> + }
> + }
> +
> + clk_set_rate(dsi->vclk, dsi->mode_calc.mode_freq_hz);
> + *hsfreq_mhz = dsi_parameters->freq_mhz;
> +
> + return 0;
> +}
> +
> +static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
> + unsigned long long hsfreq_mhz)
> +{
> + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> + unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
> + u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
> + struct rzg2l_mipi_dsi_timings dphy_timings;
> + unsigned long long hsfreq;
> + u32 ulpsexit;
> +
> + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
> +
> + if (dsi_parameters->freq_mhz == hsfreq_mhz)
> + goto parameters_found;
> +
> + if (rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
> + dsi_parameters, hsfreq_mhz))
> + 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,
> + ARRAY_SIZE(TCLKTRAILCTL));
> + dphy_timings.tclk_post =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL,
> + ARRAY_SIZE(TCLKPOSTCTL));
> + dphy_timings.tclk_zero =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL,
> + ARRAY_SIZE(TCLKZEROCTL));
> + dphy_timings.tclk_prepare =
> + rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL,
> + ARRAY_SIZE(TCLKPRPRCTL));
> + dphy_timings.ths_exit =
> + rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL,
> + ARRAY_SIZE(THSEXITCTL));
> + dphy_timings.ths_trail =
> + rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL,
> + ARRAY_SIZE(THSTRAILCTL));
> + dphy_timings.ths_zero =
> + rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL,
> + ARRAY_SIZE(THSZEROCTL));
> + dphy_timings.ths_prepare =
> + rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL,
> + ARRAY_SIZE(THSPRPRCTL));
> + dphy_timings.tlpx =
> + rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL,
> + ARRAY_SIZE(TLPXCTL));
> + ulpsexit =
> + rzv2h_dphy_find_timings_val(lpclk_rate, ULPSEXIT,
> + ARRAY_SIZE(ULPSEXIT));
> +
> + phytclksetr = PHYTCLKSETR_TCLKTRAILCTL(dphy_timings.tclk_trail) |
> + PHYTCLKSETR_TCLKPOSTCTL(dphy_timings.tclk_post) |
> + PHYTCLKSETR_TCLKZEROCTL(dphy_timings.tclk_zero) |
> + PHYTCLKSETR_TCLKPRPRCTL(dphy_timings.tclk_prepare);
> + phythssetr = PHYTHSSETR_THSEXITCTL(dphy_timings.ths_exit) |
> + PHYTHSSETR_THSTRAILCTL(dphy_timings.ths_trail) |
> + PHYTHSSETR_THSZEROCTL(dphy_timings.ths_zero) |
> + PHYTHSSETR_THSPRPRCTL(dphy_timings.ths_prepare);
> + phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~GENMASK(7, 0);
> + phytlpxsetr |= PHYTLPXSETR_TLPXCTL(dphy_timings.tlpx);
> + phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
> + phycr |= 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,
> + PLLCLKSET0R_PLL_S(dsi_parameters->s) |
> + PLLCLKSET0R_PLL_P(dsi_parameters->p) |
> + PLLCLKSET0R_PLL_M(dsi_parameters->m));
> + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R, PLLCLKSET1R_PLL_K(dsi_parameters->k));
> + udelay(20);
> +
> + rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
> + udelay(500);
Checkpatch warnings, maybe use fsleep()?
CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
#475: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:718:
+ udelay(20);
CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
#478: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:721:
+ udelay(500);
CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
#485: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:728:
+ udelay(220);
Cheers,
Biju
> +
> + return 0;
> +}
> +
> +static void rzv2h_mipi_dsi_dphy_late_init(struct rzg2l_mipi_dsi *dsi) {
> + udelay(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) { @@ -409,6 +836,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) && @@ -439,6 +869,9 @@ static void
> rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
> rzg2l_mipi_dsi_link_write(dsi, VICH1HSSETR, vich1hssetr);
> rzg2l_mipi_dsi_link_write(dsi, VICH1HPSETR, vich1hpsetr);
>
> + if (dsi->info->dphy_late_init)
> + dsi->info->dphy_late_init(dsi);
> +
> /*
> * Configuration for Delay Value
> * Delay value based on 2 ranges of video clock.
> @@ -867,6 +1300,23 @@ 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 rzg2l_mipi_dsi_hw_info rzv2h_mipi_dsi_info = {
> + .dphy_init = rzv2h_mipi_dsi_dphy_init,
> + .dphy_late_init = rzv2h_mipi_dsi_dphy_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_dsi_limits = &rzv2h_cpg_pll_dsi_limits,
> + .phy_reg_offset = 0x10000,
> + .link_reg_offset = 0,
> + .max_dclk = 187500,
> + .min_dclk = 5440,
> + .features = RZ_MIPI_DSI_FEATURE_16BPP |
> + RZ_MIPI_DSI_FEATURE_LPCLK,
> +};
> +
> 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, @@ -878,6 +1328,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 16efe4dc59f4..68165395d61c 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(x) ((x) << 0)
> +#define PLLCLKSET0R_PLL_P(x) ((x) << 8)
> +#define PLLCLKSET0R_PLL_M(x) ((x) << 16)
> +
> +#define PLLCLKSET1R 0x014
> +#define PLLCLKSET1R_PLL_K(x) ((x) << 0)
> +
> +#define PHYTCLKSETR 0x020
> +#define PHYTCLKSETR_TCLKTRAILCTL(x) ((x) << 0)
> +#define PHYTCLKSETR_TCLKPOSTCTL(x) ((x) << 8)
> +#define PHYTCLKSETR_TCLKZEROCTL(x) ((x) << 16)
> +#define PHYTCLKSETR_TCLKPRPRCTL(x) ((x) << 24)
> +
> +#define PHYTHSSETR 0x024
> +#define PHYTHSSETR_THSEXITCTL(x) ((x) << 0)
> +#define PHYTHSSETR_THSTRAILCTL(x) ((x) << 8)
> +#define PHYTHSSETR_THSZEROCTL(x) ((x) << 16)
> +#define PHYTHSSETR_THSPRPRCTL(x) ((x) << 24)
> +
> +#define PHYTLPXSETR 0x028
> +#define PHYTLPXSETR_TLPXCTL(x) ((x) << 0)
> +
> +#define PHYCR 0x030
> +#define PHYCR_ULPSEXIT(x) ((x) << 0)
> +
> /* --------------------------------------------------------*/
>
> /* Link Status Register */
> @@ -116,6 +149,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.49.0
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-04-12 8:00 ` Biju Das
@ 2025-04-18 9:24 ` Lad, Prabhakar
0 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 9:24 UTC (permalink / raw)
To: Biju Das
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, Tomi Valkeinen,
Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel@lists.freedesktop.org,
devicetree@vger.kernel.org, linux-clk@vger.kernel.org,
linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
Fabrizio Castro, Tommaso Merciai, Prabhakar Mahadev Lad
Hi Biju,
Thank you for the review.
On Sat, Apr 12, 2025 at 9:01 AM Biju Das <biju.das.jz@bp.renesas.com> wrote:
>
> Hi Prabhakar,
>
> Thanks for the patch.
>
> > -----Original Message-----
> > From: Prabhakar <prabhakar.csengg@gmail.com>
> > Sent: 08 April 2025 21:09
> > Subject: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
> >
> > 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>
> > ---
> > v1->v2:
> > - Dropped unused macros
> > - Added missing LPCLK flag to rzvv2h info
> > ---
> > .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 451 ++++++++++++++++++
> > .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h | 34 ++
> > 2 files changed, 485 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 6c6bc59eabbc..e260e2ed03c1 100644
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -5,6 +5,7 @@
> > * Copyright (C) 2022 Renesas Electronics Corporation
> > */
> > #include <linux/clk.h>
> > +#include <linux/clk/renesas-rzv2h-dsi.h>
>
> This patch has hard dependency on clk driver.
>
> > #include <linux/delay.h>
> > #include <linux/io.h>
> > #include <linux/iopoll.h>
> > @@ -32,6 +33,9 @@
> > #define RZ_MIPI_DSI_FEATURE_16BPP BIT(1)
> > #define RZ_MIPI_DSI_FEATURE_LPCLK BIT(2)
> >
> > +#define RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA (80 * MEGA)
> > +#define RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA (1500 * MEGA)
> > +
> > struct rzg2l_mipi_dsi;
> >
> > struct rzg2l_mipi_dsi_hw_info {
> > @@ -42,6 +46,7 @@ struct rzg2l_mipi_dsi_hw_info {
> > unsigned long long *hsfreq_mhz);
> > unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
> > unsigned long mode_freq);
> > + const struct rzv2h_plldsi_div_limits *cpg_dsi_limits;
> > u32 phy_reg_offset;
> > u32 link_reg_offset;
> > unsigned long max_dclk;
> > @@ -49,6 +54,11 @@ struct rzg2l_mipi_dsi_hw_info {
> > u8 features;
> > };
> >
> > +struct rzv2h_dsi_mode_calc {
> > + unsigned long mode_freq;
> > + unsigned long long mode_freq_hz;
> > +};
> > +
> > struct rzg2l_mipi_dsi {
> > struct device *dev;
> > void __iomem *mmio;
> > @@ -70,6 +80,18 @@ struct rzg2l_mipi_dsi {
> > unsigned int num_data_lanes;
> > unsigned int lanes;
> > unsigned long mode_flags;
> > +
> > + struct rzv2h_dsi_mode_calc mode_calc;
> > + struct rzv2h_plldsi_parameters dsi_parameters; };
> > +
> > +static const struct rzv2h_plldsi_div_limits rzv2h_plldsi_div_limits = {
> > + .m = { .min = 64, .max = 1023 },
> > + .p = { .min = 1, .max = 4 },
> > + .s = { .min = 0, .max = 5 },
> > + .k = { .min = -32768, .max = 32767 },
> > + .csdiv = { .min = 1, .max = 1 },
> > + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA }
> > };
> >
> > static inline struct rzg2l_mipi_dsi *
> > @@ -186,6 +208,249 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
> > },
> > };
> >
> > +struct rzv2h_mipi_dsi_timings {
> > + unsigned long hsfreq;
> > + u16 value;
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings TCLKPRPRCTL[] = {
> > + {150000000UL, 0},
> > + {260000000UL, 1},
> > + {370000000UL, 2},
> > + {470000000UL, 3},
> > + {580000000UL, 4},
> > + {690000000UL, 5},
> > + {790000000UL, 6},
> > + {900000000UL, 7},
> > + {1010000000UL, 8},
> > + {1110000000UL, 9},
> > + {1220000000UL, 10},
> > + {1330000000UL, 11},
> > + {1430000000UL, 12},
> > + {1500000000UL, 13},
> > +};
>
> Not sure, Is it right approach to optimize this table as the second entry is sequential
> with a fixed number for all tables except last one?
>
Agreed, I'll simplify this.
> 28 bytes can be saved, if we use a variable holding start_index.
>
> > +
> > +static const struct rzv2h_mipi_dsi_timings TCLKZEROCTL[] = {
> > + {90000000UL, 2},
> > + {110000000UL, 3},
> > + {130000000UL, 4},
> > + {150000000UL, 5},
> > + {180000000UL, 6},
> > + {210000000UL, 7},
> > + {230000000UL, 8},
> > + {240000000UL, 9},
> > + {250000000UL, 10},
> > + {270000000UL, 11},
> > + {290000000UL, 12},
> > + {310000000UL, 13},
> > + {340000000UL, 14},
> > + {360000000UL, 15},
> > + {380000000UL, 16},
> > + {410000000UL, 17},
> > + {430000000UL, 18},
> > + {450000000UL, 19},
> > + {470000000UL, 20},
> > + {500000000UL, 21},
> > + {520000000UL, 22},
> > + {540000000UL, 23},
> > + {570000000UL, 24},
> > + {590000000UL, 25},
> > + {610000000UL, 26},
> > + {630000000UL, 27},
> > + {660000000UL, 28},
> > + {680000000UL, 29},
> > + {700000000UL, 30},
> > + {730000000UL, 31},
> > + {750000000UL, 32},
> > + {770000000UL, 33},
> > + {790000000UL, 34},
> > + {820000000UL, 35},
> > + {840000000UL, 36},
> > + {860000000UL, 37},
> > + {890000000UL, 38},
> > + {910000000UL, 39},
> > + {930000000UL, 40},
> > + {950000000UL, 41},
> > + {980000000UL, 42},
> > + {1000000000UL, 43},
> > + {1020000000UL, 44},
> > + {1050000000UL, 45},
> > + {1070000000UL, 46},
> > + {1090000000UL, 47},
> > + {1110000000UL, 48},
> > + {1140000000UL, 49},
> > + {1160000000UL, 50},
> > + {1180000000UL, 51},
> > + {1210000000UL, 52},
> > + {1230000000UL, 53},
> > + {1250000000UL, 54},
> > + {1270000000UL, 55},
> > + {1300000000UL, 56},
> > + {1320000000UL, 57},
> > + {1340000000UL, 58},
> > + {1370000000UL, 59},
> > + {1390000000UL, 60},
> > + {1410000000UL, 61},
> > + {1430000000UL, 62},
> > + {1460000000UL, 63},
> > + {1480000000UL, 64},
> > + {1500000000UL, 65},
>
> Same. Here 128 bytes
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings TCLKPOSTCTL[] = {
> > + {80000000UL, 6},
> > + {210000000UL, 7},
> > + {340000000UL, 8},
> > + {480000000UL, 9},
> > + {610000000UL, 10},
> > + {740000000UL, 11},
> > + {880000000UL, 12},
> > + {1010000000UL, 13},
> > + {1140000000UL, 14},
> > + {1280000000UL, 15},
> > + {1410000000UL, 16},
> > + {1500000000UL, 17},
>
> Same. Here 24 bytes
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings TCLKTRAILCTL[] = {
> > + {140000000UL, 1},
> > + {250000000UL, 2},
> > + {370000000UL, 3},
> > + {480000000UL, 4},
> > + {590000000UL, 5},
> > + {710000000UL, 6},
> > + {820000000UL, 7},
> > + {940000000UL, 8},
> > + {1050000000UL, 9},
> > + {1170000000UL, 10},
> > + {1280000000UL, 11},
> > + {1390000000UL, 12},
> > + {1500000000UL, 13},
> Same. Here 26 bytes
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings THSPRPRCTL[] = {
> > + {110000000UL, 0},
> > + {190000000UL, 1},
> > + {290000000UL, 2},
> > + {400000000UL, 3},
> > + {500000000UL, 4},
> > + {610000000UL, 5},
> > + {720000000UL, 6},
> > + {820000000UL, 7},
> > + {930000000UL, 8},
> > + {1030000000UL, 9},
> > + {1140000000UL, 10},
> > + {1250000000UL, 11},
> > + {1350000000UL, 12},
> > + {1460000000UL, 13},
> > + {1500000000UL, 14},
>
> Same. Here 30 bytes
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings THSZEROCTL[] = {
> > + {180000000UL, 0},
> > + {240000000UL, 1},
> > + {290000000UL, 2},
> > + {350000000UL, 3},
> > + {400000000UL, 4},
> > + {460000000UL, 5},
> > + {510000000UL, 6},
> > + {570000000UL, 7},
> > + {620000000UL, 8},
> > + {680000000UL, 9},
> > + {730000000UL, 10},
> > + {790000000UL, 11},
> > + {840000000UL, 12},
> > + {900000000UL, 13},
> > + {950000000UL, 14},
> > + {1010000000UL, 15},
> > + {1060000000UL, 16},
> > + {1120000000UL, 17},
> > + {1170000000UL, 18},
> > + {1230000000UL, 19},
> > + {1280000000UL, 20},
> > + {1340000000UL, 21},
> > + {1390000000UL, 22},
> > + {1450000000UL, 23},
> > + {1500000000UL, 24},
>
> Same. Here 50 bytes.
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings THSTRAILCTL[] = {
> > + {100000000UL, 3},
> > + {210000000UL, 4},
> > + {320000000UL, 5},
> > + {420000000UL, 6},
> > + {530000000UL, 7},
> > + {640000000UL, 8},
> > + {750000000UL, 9},
> > + {850000000UL, 10},
> > + {960000000UL, 11},
> > + {1070000000UL, 12},
> > + {1180000000UL, 13},
> > + {1280000000UL, 14},
> > + {1390000000UL, 15},
> > + {1500000000UL, 16},
>
> Same. Here 28 bytes?
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings TLPXCTL[] = {
> > + {130000000UL, 0},
> > + {260000000UL, 1},
> > + {390000000UL, 2},
> > + {530000000UL, 3},
> > + {660000000UL, 4},
> > + {790000000UL, 5},
> > + {930000000UL, 6},
> > + {1060000000UL, 7},
> > + {1190000000UL, 8},
> > + {1330000000UL, 9},
> > + {1460000000UL, 10},
> > + {1500000000UL, 11},
>
> Same. Here 24 bytes
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings THSEXITCTL[] = {
> > + {150000000UL, 1},
> > + {230000000UL, 2},
> > + {310000000UL, 3},
> > + {390000000UL, 4},
> > + {470000000UL, 5},
> > + {550000000UL, 6},
> > + {630000000UL, 7},
> > + {710000000UL, 8},
> > + {790000000UL, 9},
> > + {870000000UL, 10},
> > + {950000000UL, 11},
> > + {1030000000UL, 12},
> > + {1110000000UL, 13},
> > + {1190000000UL, 14},
> > + {1270000000UL, 15},
> > + {1350000000UL, 16},
> > + {1430000000UL, 17},
> > + {1500000000UL, 18},
>
> Same. Here 36 bytes.
>
> > +};
> > +
> > +static const struct rzv2h_mipi_dsi_timings ULPSEXIT[] = {
> > + {1953125UL, 49},
> > + {3906250UL, 98},
> > + {7812500UL, 195},
> > + {15625000UL, 391},
>
> Here we have problem as it is non-sequential and only has 4 entries?
>
> Since it is ULPS EXIT Counter values compared to DPHY timings
> This can have its own structure?
>
Agreed as this will have a separate function of its own no need for a
new struct, I'll have something like below:
static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
{
const unsigned long hsfreq[] = {
1953125UL,
3906250UL,
7812500UL,
15625000UL,
};
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 -= 1;
return ulpsexit[i];
}
> > +};
> > +
> > +static int rzv2h_dphy_find_timings_val(unsigned long freq,
> > + const struct rzv2h_mipi_dsi_timings timings[],
> > + unsigned int size)
> > +{
> > + unsigned int i;
> > +
> > + for (i = 0; i < size; i++) {
> > + if (freq <= timings[i].hsfreq)
> > + break;
> > + }
> > +
> > + if (i == size)
> > + i -= 1;
> > +
> > + return timings[i].value;
>
> This will be then start_index + i for all DPHY timing parmeter table.
>
Agreed.
> And
>
> Maybe use another function to find ULPS EXIT Counter values??
>
>
> > +};
> > +
> > 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); @@ -307,6 +572,168 @@ 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)
> > +{
> > + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> > + unsigned long long hsfreq_mhz, mode_freq_hz, mode_freq_mhz;
> > + struct rzv2h_plldsi_parameters cpg_dsi_parameters;
> > + unsigned int bpp, i;
> > +
> > + bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> > +
> > + for (i = 0; i < 10; i += 1) {
> > + unsigned long hsfreq;
> > + bool parameters_found;
> > +
> > + mode_freq_hz = mode_freq * KILO + i;
> > + mode_freq_mhz = mode_freq_hz * KILO * 1ULL;
> > + parameters_found = rzv2h_dsi_get_pll_parameters_values(dsi->info->cpg_dsi_limits,
> > + &cpg_dsi_parameters,
> > + mode_freq_mhz);
> > + if (!parameters_found)
> > + continue;
> > +
> > + hsfreq_mhz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.freq_mhz * bpp, dsi->lanes);
> > + parameters_found = rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
> > + dsi_parameters,
> > + hsfreq_mhz);
> > + if (!parameters_found)
> > + continue;
> > +
> > + if (abs(dsi_parameters->error_mhz) >= 500)
> > + continue;
> > +
> > + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
> > + if (hsfreq >= RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA &&
> > + hsfreq <= RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA) {
> > + dsi->mode_calc.mode_freq_hz = mode_freq_hz;
> > + dsi->mode_calc.mode_freq = mode_freq;
> > + return MODE_OK;
> > + }
> > + }
> > +
> > + return MODE_CLOCK_RANGE;
> > +}
> > +
> > +static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
> > + unsigned long long *hsfreq_mhz)
> > +{
> > + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> > + unsigned long status;
> > +
> > + if (dsi->mode_calc.mode_freq != 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;
> > + }
> > + }
> > +
> > + clk_set_rate(dsi->vclk, dsi->mode_calc.mode_freq_hz);
> > + *hsfreq_mhz = dsi_parameters->freq_mhz;
> > +
> > + return 0;
> > +}
> > +
> > +static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
> > + unsigned long long hsfreq_mhz)
> > +{
> > + struct rzv2h_plldsi_parameters *dsi_parameters = &dsi->dsi_parameters;
> > + unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
> > + u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
> > + struct rzg2l_mipi_dsi_timings dphy_timings;
> > + unsigned long long hsfreq;
> > + u32 ulpsexit;
> > +
> > + hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_mhz, KILO);
> > +
> > + if (dsi_parameters->freq_mhz == hsfreq_mhz)
> > + goto parameters_found;
> > +
> > + if (rzv2h_dsi_get_pll_parameters_values(&rzv2h_plldsi_div_limits,
> > + dsi_parameters, hsfreq_mhz))
> > + 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,
> > + ARRAY_SIZE(TCLKTRAILCTL));
> > + dphy_timings.tclk_post =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL,
> > + ARRAY_SIZE(TCLKPOSTCTL));
> > + dphy_timings.tclk_zero =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL,
> > + ARRAY_SIZE(TCLKZEROCTL));
> > + dphy_timings.tclk_prepare =
> > + rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL,
> > + ARRAY_SIZE(TCLKPRPRCTL));
> > + dphy_timings.ths_exit =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL,
> > + ARRAY_SIZE(THSEXITCTL));
> > + dphy_timings.ths_trail =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL,
> > + ARRAY_SIZE(THSTRAILCTL));
> > + dphy_timings.ths_zero =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL,
> > + ARRAY_SIZE(THSZEROCTL));
> > + dphy_timings.ths_prepare =
> > + rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL,
> > + ARRAY_SIZE(THSPRPRCTL));
> > + dphy_timings.tlpx =
> > + rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL,
> > + ARRAY_SIZE(TLPXCTL));
> > + ulpsexit =
> > + rzv2h_dphy_find_timings_val(lpclk_rate, ULPSEXIT,
> > + ARRAY_SIZE(ULPSEXIT));
> > +
> > + phytclksetr = PHYTCLKSETR_TCLKTRAILCTL(dphy_timings.tclk_trail) |
> > + PHYTCLKSETR_TCLKPOSTCTL(dphy_timings.tclk_post) |
> > + PHYTCLKSETR_TCLKZEROCTL(dphy_timings.tclk_zero) |
> > + PHYTCLKSETR_TCLKPRPRCTL(dphy_timings.tclk_prepare);
> > + phythssetr = PHYTHSSETR_THSEXITCTL(dphy_timings.ths_exit) |
> > + PHYTHSSETR_THSTRAILCTL(dphy_timings.ths_trail) |
> > + PHYTHSSETR_THSZEROCTL(dphy_timings.ths_zero) |
> > + PHYTHSSETR_THSPRPRCTL(dphy_timings.ths_prepare);
> > + phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~GENMASK(7, 0);
> > + phytlpxsetr |= PHYTLPXSETR_TLPXCTL(dphy_timings.tlpx);
> > + phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
> > + phycr |= 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,
> > + PLLCLKSET0R_PLL_S(dsi_parameters->s) |
> > + PLLCLKSET0R_PLL_P(dsi_parameters->p) |
> > + PLLCLKSET0R_PLL_M(dsi_parameters->m));
> > + rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R, PLLCLKSET1R_PLL_K(dsi_parameters->k));
> > + udelay(20);
> > +
> > + rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
> > + udelay(500);
>
> Checkpatch warnings, maybe use fsleep()?
>
> CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
> #475: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:718:
> + udelay(20);
> CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
> #478: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:721:
> + udelay(500);
> CHECK: usleep_range is preferred over udelay; see function description of usleep_range() and udelay().
> #485: FILE: drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:728:
> + udelay(220);
>
Ok, I will switch to fsleep().
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-04-08 20:09 ` [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC Prabhakar
2025-04-12 8:00 ` Biju Das
@ 2025-04-16 9:28 ` Geert Uytterhoeven
2025-04-18 15:15 ` Lad, Prabhakar
1 sibling, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2025-04-16 9:28 UTC (permalink / raw)
To: Prabhakar, Fabrizio Castro
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, Biju Das, Tomi Valkeinen,
Michael Turquette, Stephen Boyd, Philipp Zabel, Magnus Damm,
dri-devel, devicetree, linux-clk, linux-renesas-soc, linux-kernel,
Tommaso Merciai, Lad Prabhakar
Hi Prabhakar, Fabrizio,
On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> 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>
Thanks for your patch!
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> @@ -70,6 +80,18 @@ struct rzg2l_mipi_dsi {
> unsigned int num_data_lanes;
> unsigned int lanes;
> unsigned long mode_flags;
> +
> + struct rzv2h_dsi_mode_calc mode_calc;
> + struct rzv2h_plldsi_parameters dsi_parameters;
> +};
> +
> +static const struct rzv2h_plldsi_div_limits rzv2h_plldsi_div_limits = {
> + .m = { .min = 64, .max = 1023 },
.max = 533?
> + .p = { .min = 1, .max = 4 },
> + .s = { .min = 0, .max = 5 },
.max = 6?
> + .k = { .min = -32768, .max = 32767 },
> + .csdiv = { .min = 1, .max = 1 },
> + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA }
> };
Summarized: why do these values differ from the ones in the declaration
macro RZV2H_CPG_PLL_DSI_LIMITS(), i.e. why can't you use the latter?
>
> static inline struct rzg2l_mipi_dsi *
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] 31+ messages in thread* Re: [PATCH v2 15/15] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
2025-04-16 9:28 ` Geert Uytterhoeven
@ 2025-04-18 15:15 ` Lad, Prabhakar
0 siblings, 0 replies; 31+ messages in thread
From: Lad, Prabhakar @ 2025-04-18 15:15 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Fabrizio Castro, 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,
Biju Das, Tomi Valkeinen, Michael Turquette, Stephen Boyd,
Philipp Zabel, Magnus Damm, dri-devel, devicetree, linux-clk,
linux-renesas-soc, linux-kernel, Tommaso Merciai, Lad Prabhakar
Hi Geert,
Thank you for the review.
On Wed, Apr 16, 2025 at 10:35 AM Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
>
> Hi Prabhakar, Fabrizio,
>
> On Tue, 8 Apr 2025 at 22:09, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > 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>
>
> Thanks for your patch!
>
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -70,6 +80,18 @@ struct rzg2l_mipi_dsi {
> > unsigned int num_data_lanes;
> > unsigned int lanes;
> > unsigned long mode_flags;
> > +
> > + struct rzv2h_dsi_mode_calc mode_calc;
> > + struct rzv2h_plldsi_parameters dsi_parameters;
> > +};
> > +
> > +static const struct rzv2h_plldsi_div_limits rzv2h_plldsi_div_limits = {
> > + .m = { .min = 64, .max = 1023 },
>
> .max = 533?
>
> > + .p = { .min = 1, .max = 4 },
> > + .s = { .min = 0, .max = 5 },
>
> .max = 6?
>
> > + .k = { .min = -32768, .max = 32767 },
> > + .csdiv = { .min = 1, .max = 1 },
> > + .fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA }
> > };
>
> Summarized: why do these values differ from the ones in the declaration
> macro RZV2H_CPG_PLL_DSI_LIMITS(), i.e. why can't you use the latter?
>
There is a divider inside the DSI IP which is almost similar to PLL in
the CPG. The divider limits for the DSI IP vary as compared to one in
the CPG IP.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 31+ messages in thread