[PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC

Prabhakar posted 6 patches 4 months, 1 week ago
There is a newer version of this series
[PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
Posted by Prabhakar 4 months, 1 week ago
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Add MIPI DSI support for the Renesas RZ/V2H(P) SoC. Compared to the
RZ/G2L family, the RZ/V2H(P) requires dedicated D-PHY PLL programming,
different clock configuration, and additional timing parameter handling.
The driver introduces lookup tables and helpers for D-PHY timings
(TCLK*, THS*, TLPX, and ULPS exit) as specified in the RZ/V2H(P) hardware
manual. ULPS exit timing depends on the LPCLK rate and is now handled
explicitly.

The implementation also adds support for 16 bpp RGB format, updates the
clock setup path to use the RZ/V2H PLL divider limits, and provides new
.dphy_init, .dphy_conf_clks, and .dphy_startup_late_init callbacks to
match the RZ/V2H sequence.

With these changes, the RZ/V2H(P) can operate the MIPI DSI interface in
compliance with its hardware specification while retaining support for
existing RZ/G2L platforms.

Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
---
v8->v9:
- Updated Kconfig to select CLK_RZV2H
- Updated to use renesas.h
- Added reviewed-by tag from Tomi

v7->v8:
- Updated commit message
- Simplified check in rzv2h_mipi_dsi_dphy_init() for PLL parameters
- Renamed start_index member to base_value in struct rzv2h_mipi_dsi_timings
- Added comments in the code for DSI arrays and their usage
- Added comments in the code for sleeps

v6->v7:
- Used the new apis for calculating the PLLDSI
  parameters in the DSI driver.

v5->v6:
- Made use of GENMASK() macro for PLLCLKSET0R_PLL_*,
  PHYTCLKSETR_* and PHYTHSSETR_* macros.
- Replaced 10000000UL with 10 * MEGA
- Renamed mode_freq_hz to mode_freq_khz in rzv2h_dsi_mode_calc
- Replaced `i -= 1;` with `i--;`
- Renamed RZV2H_MIPI_DPHY_FOUT_MIN_IN_MEGA to
  RZV2H_MIPI_DPHY_FOUT_MIN_IN_MHZ and
  RZV2H_MIPI_DPHY_FOUT_MAX_IN_MEGA to
  RZV2H_MIPI_DPHY_FOUT_MAX_IN_MHZ.

v4->v5:
- No changes

v3->v4
- In rzv2h_dphy_find_ulpsexit() made the array static const.

v2->v3:
- Simplifed V2H DSI timings array to save space
- Switched to use fsleep() instead of udelay()

v1->v2:
- Dropped unused macros
- Added missing LPCLK flag to rzv2h_info
---
 drivers/gpu/drm/renesas/rz-du/Kconfig         |   1 +
 .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c    | 448 ++++++++++++++++++
 .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h   |  34 ++
 3 files changed, 483 insertions(+)

diff --git a/drivers/gpu/drm/renesas/rz-du/Kconfig b/drivers/gpu/drm/renesas/rz-du/Kconfig
index e57536fd6f4d..34d515eb798b 100644
--- a/drivers/gpu/drm/renesas/rz-du/Kconfig
+++ b/drivers/gpu/drm/renesas/rz-du/Kconfig
@@ -19,6 +19,7 @@ config DRM_RZG2L_USE_MIPI_DSI
 	depends on DRM_BRIDGE && OF
 	depends on DRM_RZG2L_DU || COMPILE_TEST
 	default DRM_RZG2L_DU
+	select CLK_RZV2H
 	help
 	  Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
 
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 bb03b49b1e85..5edd45424562 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -7,6 +7,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/clk/renesas.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
@@ -32,6 +33,8 @@
 
 #include "rzg2l_mipi_dsi_regs.h"
 
+MODULE_IMPORT_NS("RZV2H_CPG");
+
 #define RZG2L_DCS_BUF_SIZE	128 /* Maximum DCS buffer size in external memory. */
 
 #define RZ_MIPI_DSI_FEATURE_16BPP	BIT(0)
@@ -46,6 +49,11 @@ struct rzg2l_mipi_dsi_hw_info {
 			      u64 *hsfreq_millihz);
 	unsigned int (*dphy_mode_clk_check)(struct rzg2l_mipi_dsi *dsi,
 					    unsigned long mode_freq);
+	struct {
+		const struct rzv2h_pll_limits **limits;
+		const u8 *table;
+		const u8 table_size;
+	} cpg_plldsi;
 	u32 phy_reg_offset;
 	u32 link_reg_offset;
 	unsigned long min_dclk;
@@ -53,6 +61,11 @@ struct rzg2l_mipi_dsi_hw_info {
 	u8 features;
 };
 
+struct rzv2h_dsi_mode_calc {
+	unsigned long mode_freq_khz;
+	struct rzv2h_pll_pars dsi_parameters;
+};
+
 struct rzg2l_mipi_dsi {
 	struct device *dev;
 	void __iomem *mmio;
@@ -75,11 +88,22 @@ struct rzg2l_mipi_dsi {
 	unsigned int lanes;
 	unsigned long mode_flags;
 
+	struct rzv2h_dsi_mode_calc mode_calc;
+
 	/* DCS buffer pointers when using external memory. */
 	dma_addr_t dcs_buf_phys;
 	u8 *dcs_buf_virt;
 };
 
+static const struct rzv2h_pll_limits rzv2h_plldsi_div_limits = {
+	.fout = { .min = 80 * MEGA, .max = 1500 * MEGA },
+	.fvco = { .min = 1050 * MEGA, .max = 2100 * MEGA },
+	.m = { .min = 64, .max = 1023 },
+	.p = { .min = 1, .max = 4 },
+	.s = { .min = 0, .max = 5 },
+	.k = { .min = -32768, .max = 32767 },
+};
+
 static inline struct rzg2l_mipi_dsi *
 bridge_to_rzg2l_mipi_dsi(struct drm_bridge *bridge)
 {
@@ -194,6 +218,237 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
 	},
 };
 
+/**
+ * struct rzv2h_mipi_dsi_timings - Timing parameter table structure
+ *
+ * @hsfreq: Pointer to frequency threshold array
+ * @len: Number of entries in the hsfreq array
+ * @base_value: Base register value offset for this timing parameter
+ *
+ * Each timing parameter (TCLK*, THS*, etc.) has its own table with
+ * frequency thresholds and corresponding base register values.
+ */
+struct rzv2h_mipi_dsi_timings {
+	const u8 *hsfreq;
+	u8 len;
+	u8 base_value;
+};
+
+/*
+ * enum rzv2h_dsi_timing_idx - MIPI DSI timing parameter indices
+ *
+ * These enums correspond to different MIPI DSI PHY timing parameters.
+ */
+enum rzv2h_dsi_timing_idx {
+	TCLKPRPRCTL,
+	TCLKZEROCTL,
+	TCLKPOSTCTL,
+	TCLKTRAILCTL,
+	THSPRPRCTL,
+	THSZEROCTL,
+	THSTRAILCTL,
+	TLPXCTL,
+	THSEXITCTL,
+};
+
+/*
+ * RZ/V2H(P) Frequency threshold lookup tables for D-PHY timing parameters
+ *
+ * - Each array contains frequency thresholds (in units of 10 Mbps),
+ *   taken directly from the table 9.5-4 hardware manual.
+ * - These thresholds define the frequency ranges for which timing
+ *   register values must be programmed.
+ * - The actual register value is calculated in
+ *   rzv2h_dphy_find_timings_val():
+ *
+ *       register_value = timings->base_value + table_index
+ *
+ * Example (TCLKPRPRCTL, from HW manual):
+ *   0-150 Mbps   -> index 0 -> register_value = base + 0 = 0 + 0 = 0
+ *   151-260 Mbps -> index 1 -> register_value = base + 1 = 0 + 1 = 1
+ *   261-370 Mbps -> index 2 -> register_value = base + 2 = 0 + 2 = 2
+ *
+ * Each of the following arrays corresponds to a specific timing
+ * parameter (TCLKPRPRCTL, TCLKZEROCTL, TCLKPOSTCTL, etc.).
+ */
+static const u8 tclkprprctl[] = {
+	15, 26, 37, 47, 58, 69, 79, 90, 101, 111, 122, 133, 143, 150,
+};
+
+static const u8 tclkzeroctl[] = {
+	9, 11, 13, 15, 18, 21, 23, 24, 25, 27, 29, 31, 34, 36, 38,
+	41, 43, 45, 47, 50, 52, 54, 57, 59, 61, 63, 66, 68, 70, 73,
+	75, 77, 79, 82, 84, 86, 89, 91, 93, 95, 98, 100, 102, 105,
+	107, 109, 111, 114, 116, 118, 121, 123, 125, 127, 130, 132,
+	134, 137, 139, 141, 143, 146, 148, 150,
+};
+
+static const u8 tclkpostctl[] = {
+	8, 21, 34, 48, 61, 74, 88, 101, 114, 128, 141, 150,
+};
+
+static const u8 tclktrailctl[] = {
+	14, 25, 37, 48, 59, 71, 82, 94, 105, 117, 128, 139, 150,
+};
+
+static const u8 thsprprctl[] = {
+	11, 19, 29, 40, 50, 61, 72, 82, 93, 103, 114, 125, 135, 146, 150,
+};
+
+static const u8 thszeroctl[] = {
+	18, 24, 29, 35, 40, 46, 51, 57, 62, 68, 73, 79, 84, 90,
+	95, 101, 106, 112, 117, 123, 128, 134, 139, 145, 150,
+};
+
+static const u8 thstrailctl[] = {
+	10, 21, 32, 42, 53, 64, 75, 85, 96, 107, 118, 128, 139, 150,
+};
+
+static const u8 tlpxctl[] = {
+	13, 26, 39, 53, 66, 79, 93, 106, 119, 133, 146,	150,
+};
+
+static const u8 thsexitctl[] = {
+	15, 23, 31, 39, 47, 55, 63, 71, 79, 87,
+	95, 103, 111, 119, 127, 135, 143, 150,
+};
+
+/*
+ * rzv2h_dsi_timings_tables - main timing parameter lookup table
+ * Maps timing parameter enum to its frequency table, array length and
+ * base register offset value.
+ */
+static const struct rzv2h_mipi_dsi_timings rzv2h_dsi_timings_tables[] = {
+	[TCLKPRPRCTL] = {
+		.hsfreq = tclkprprctl,
+		.len = ARRAY_SIZE(tclkprprctl),
+		.base_value = 0,
+	},
+	[TCLKZEROCTL] = {
+		.hsfreq = tclkzeroctl,
+		.len = ARRAY_SIZE(tclkzeroctl),
+		.base_value = 2,
+	},
+	[TCLKPOSTCTL] = {
+		.hsfreq = tclkpostctl,
+		.len = ARRAY_SIZE(tclkpostctl),
+		.base_value = 6,
+	},
+	[TCLKTRAILCTL] = {
+		.hsfreq = tclktrailctl,
+		.len = ARRAY_SIZE(tclktrailctl),
+		.base_value = 1,
+	},
+	[THSPRPRCTL] = {
+		.hsfreq = thsprprctl,
+		.len = ARRAY_SIZE(thsprprctl),
+		.base_value = 0,
+	},
+	[THSZEROCTL] = {
+		.hsfreq = thszeroctl,
+		.len = ARRAY_SIZE(thszeroctl),
+		.base_value = 0,
+	},
+	[THSTRAILCTL] = {
+		.hsfreq = thstrailctl,
+		.len = ARRAY_SIZE(thstrailctl),
+		.base_value = 3,
+	},
+	[TLPXCTL] = {
+		.hsfreq = tlpxctl,
+		.len = ARRAY_SIZE(tlpxctl),
+		.base_value = 0,
+	},
+	[THSEXITCTL] = {
+		.hsfreq = thsexitctl,
+		.len = ARRAY_SIZE(thsexitctl),
+		.base_value = 1,
+	},
+};
+
+/**
+ * rzv2h_dphy_find_ulpsexit - Find ULP Exit timing value based on frequency
+ * The function maps frequency ranges to ULP exit timing values.
+ * Thresholds in the local hsfreq[] are expressed in Hz already.
+ *
+ * @freq: Input frequency in Hz
+ *
+ * Return: ULP exit timing value
+ */
+static u16 rzv2h_dphy_find_ulpsexit(unsigned long freq)
+{
+	/* Frequency thresholds in Hz for ULP exit timing selection */
+	static const unsigned long hsfreq[] = {
+		1953125UL,
+		3906250UL,
+		7812500UL,
+		15625000UL,
+	};
+	/* Corresponding ULP exit timing values for each frequency range */
+	static const u16 ulpsexit[] = {49, 98, 195, 391};
+	unsigned int i;
+
+	/* Find the appropriate frequency range */
+	for (i = 0; i < ARRAY_SIZE(hsfreq); i++) {
+		if (freq <= hsfreq[i])
+			break;
+	}
+
+	 /* If frequency exceeds all thresholds, use the highest range */
+	if (i == ARRAY_SIZE(hsfreq))
+		i--;
+
+	return ulpsexit[i];
+}
+
+/**
+ * rzv2h_dphy_find_timings_val - Find timing parameter value from lookup tables
+ * @freq: Input frequency in Hz
+ * @index: Index to select timing parameter table (see enum rzv2h_dsi_timing_idx)
+ *
+ * Selects the timing table for the requested parameter, finds the
+ * frequency range entry and returns the register value to program:
+ *
+ *   register_value = timings->base_value + table_index
+ *
+ * Note: frequency table entries are stored as small integers (units of 10):
+ *       threshold_in_hz = (unsigned long)table_entry * 10 * MEGA
+ *
+ * Return: timing register value to be programmed into hardware
+ */
+static u16 rzv2h_dphy_find_timings_val(unsigned long freq, u8 index)
+{
+	const struct rzv2h_mipi_dsi_timings *timings;
+	u16 i;
+
+	/* Get the timing table structure for the requested parameter */
+	timings = &rzv2h_dsi_timings_tables[index];
+
+	/*
+	 * Search through frequency table to find appropriate range
+	 * timings->hsfreq[i] contains frequency values from HW manual
+	 * Convert to Hz by multiplying by 10 * MEGA.
+	 */
+	for (i = 0; i < timings->len; i++) {
+		unsigned long hsfreq = timings->hsfreq[i] * 10 * MEGA;
+
+		if (freq <= hsfreq)
+			break;
+	}
+
+	/* If frequency exceeds table range, use the last entry */
+	if (i == timings->len)
+		i--;
+
+	/*
+	 * Calculate final register value:
+	 * - timings->base_value: base value for this timing parameter
+	 * - i: index into frequency table (0-based)
+	 * Combined they give the exact register value to program
+	 */
+	return timings->base_value + i;
+};
+
 static void rzg2l_mipi_dsi_phy_write(struct rzg2l_mipi_dsi *dsi, u32 reg, u32 data)
 {
 	iowrite32(data, dsi->mmio + dsi->info->phy_reg_offset + reg);
@@ -318,6 +573,169 @@ static int rzg2l_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_f
 	return 0;
 }
 
+static unsigned int rzv2h_dphy_mode_clk_check(struct rzg2l_mipi_dsi *dsi,
+					      unsigned long mode_freq)
+{
+	u64 hsfreq_millihz, mode_freq_hz, mode_freq_millihz;
+	struct rzv2h_pll_div_pars cpg_dsi_parameters;
+	struct rzv2h_pll_pars dsi_parameters;
+	bool parameters_found;
+	unsigned int bpp;
+
+	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+	mode_freq_hz = mul_u32_u32(mode_freq, KILO);
+	mode_freq_millihz = mode_freq_hz * MILLI;
+	parameters_found =
+		rzv2h_get_pll_divs_pars(dsi->info->cpg_plldsi.limits[0],
+					&cpg_dsi_parameters,
+					dsi->info->cpg_plldsi.table,
+					dsi->info->cpg_plldsi.table_size,
+					mode_freq_millihz);
+	if (!parameters_found)
+		return MODE_CLOCK_RANGE;
+
+	hsfreq_millihz = DIV_ROUND_CLOSEST_ULL(cpg_dsi_parameters.div.freq_millihz * bpp,
+					       dsi->lanes);
+	parameters_found = rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits,
+					      &dsi_parameters, hsfreq_millihz);
+	if (!parameters_found)
+		return MODE_CLOCK_RANGE;
+
+	if (abs(dsi_parameters.error_millihz) >= 500)
+		return MODE_CLOCK_RANGE;
+
+	memcpy(&dsi->mode_calc.dsi_parameters, &dsi_parameters, sizeof(dsi_parameters));
+	dsi->mode_calc.mode_freq_khz = mode_freq;
+
+	return MODE_OK;
+}
+
+static int rzv2h_dphy_conf_clks(struct rzg2l_mipi_dsi *dsi, unsigned long mode_freq,
+				u64 *hsfreq_millihz)
+{
+	struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+	unsigned long status;
+
+	if (dsi->mode_calc.mode_freq_khz != mode_freq) {
+		status = rzv2h_dphy_mode_clk_check(dsi, mode_freq);
+		if (status != MODE_OK) {
+			dev_err(dsi->dev, "No PLL parameters found for mode clk %lu\n",
+				mode_freq);
+			return -EINVAL;
+		}
+	}
+
+	*hsfreq_millihz = dsi_parameters->freq_millihz;
+
+	return 0;
+}
+
+static int rzv2h_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
+				    u64 hsfreq_millihz)
+{
+	struct rzv2h_pll_pars *dsi_parameters = &dsi->mode_calc.dsi_parameters;
+	unsigned long lpclk_rate = clk_get_rate(dsi->lpclk);
+	u32 phytclksetr, phythssetr, phytlpxsetr, phycr;
+	struct rzg2l_mipi_dsi_timings dphy_timings;
+	u16 ulpsexit;
+	u64 hsfreq;
+
+	hsfreq = DIV_ROUND_CLOSEST_ULL(hsfreq_millihz, MILLI);
+
+	if (dsi_parameters->freq_millihz != hsfreq_millihz &&
+	    !rzv2h_get_pll_pars(&rzv2h_plldsi_div_limits, dsi_parameters,
+				hsfreq_millihz)) {
+		dev_err(dsi->dev, "No PLL parameters found for HSFREQ %lluHz\n", hsfreq);
+		return -EINVAL;
+	}
+
+	dphy_timings.tclk_trail =
+		rzv2h_dphy_find_timings_val(hsfreq, TCLKTRAILCTL);
+	dphy_timings.tclk_post =
+		rzv2h_dphy_find_timings_val(hsfreq, TCLKPOSTCTL);
+	dphy_timings.tclk_zero =
+		rzv2h_dphy_find_timings_val(hsfreq, TCLKZEROCTL);
+	dphy_timings.tclk_prepare =
+		rzv2h_dphy_find_timings_val(hsfreq, TCLKPRPRCTL);
+	dphy_timings.ths_exit =
+		rzv2h_dphy_find_timings_val(hsfreq, THSEXITCTL);
+	dphy_timings.ths_trail =
+		rzv2h_dphy_find_timings_val(hsfreq, THSTRAILCTL);
+	dphy_timings.ths_zero =
+		rzv2h_dphy_find_timings_val(hsfreq, THSZEROCTL);
+	dphy_timings.ths_prepare =
+		rzv2h_dphy_find_timings_val(hsfreq, THSPRPRCTL);
+	dphy_timings.tlpx =
+		rzv2h_dphy_find_timings_val(hsfreq, TLPXCTL);
+	ulpsexit = rzv2h_dphy_find_ulpsexit(lpclk_rate);
+
+	phytclksetr = FIELD_PREP(PHYTCLKSETR_TCLKTRAILCTL, dphy_timings.tclk_trail) |
+		      FIELD_PREP(PHYTCLKSETR_TCLKPOSTCTL, dphy_timings.tclk_post) |
+		      FIELD_PREP(PHYTCLKSETR_TCLKZEROCTL, dphy_timings.tclk_zero) |
+		      FIELD_PREP(PHYTCLKSETR_TCLKPRPRCTL, dphy_timings.tclk_prepare);
+	phythssetr = FIELD_PREP(PHYTHSSETR_THSEXITCTL, dphy_timings.ths_exit) |
+		     FIELD_PREP(PHYTHSSETR_THSTRAILCTL, dphy_timings.ths_trail) |
+		     FIELD_PREP(PHYTHSSETR_THSZEROCTL, dphy_timings.ths_zero) |
+		     FIELD_PREP(PHYTHSSETR_THSPRPRCTL, dphy_timings.ths_prepare);
+	phytlpxsetr = rzg2l_mipi_dsi_phy_read(dsi, PHYTLPXSETR) & ~PHYTLPXSETR_TLPXCTL;
+	phytlpxsetr |= FIELD_PREP(PHYTLPXSETR_TLPXCTL, dphy_timings.tlpx);
+	phycr = rzg2l_mipi_dsi_phy_read(dsi, PHYCR) & ~GENMASK(9, 0);
+	phycr |= FIELD_PREP(PHYCR_ULPSEXIT, ulpsexit);
+
+	/* Setting all D-PHY Timings Registers */
+	rzg2l_mipi_dsi_phy_write(dsi, PHYTCLKSETR, phytclksetr);
+	rzg2l_mipi_dsi_phy_write(dsi, PHYTHSSETR, phythssetr);
+	rzg2l_mipi_dsi_phy_write(dsi, PHYTLPXSETR, phytlpxsetr);
+	rzg2l_mipi_dsi_phy_write(dsi, PHYCR, phycr);
+
+	rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET0R,
+				 FIELD_PREP(PLLCLKSET0R_PLL_S, dsi_parameters->s) |
+				 FIELD_PREP(PLLCLKSET0R_PLL_P, dsi_parameters->p) |
+				 FIELD_PREP(PLLCLKSET0R_PLL_M, dsi_parameters->m));
+	rzg2l_mipi_dsi_phy_write(dsi, PLLCLKSET1R,
+				 FIELD_PREP(PLLCLKSET1R_PLL_K, dsi_parameters->k));
+
+	/*
+	 * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+	 * (C) After write to D-PHY registers we need to wait for more than 1 x tp
+	 *
+	 * tp = 1 / (PLLREFCLK / PLLCLKSET0R.PLL_P)
+	 * PLLREFCLK = 24MHz
+	 * PLLCLKSET0R.PLL_P = {1, 2, 3, 4}
+	 *
+	 * To handle all the cases lets use PLLCLKSET0R.PLL_P = 4
+	 * tp = 1 / (24MHz / 4) = 1 / 6MHz = 166.67ns
+	 */
+	ndelay(200);
+
+	rzg2l_mipi_dsi_phy_write(dsi, PLLENR, PLLENR_PLLEN);
+	/*
+	 * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+	 * (D) After write to PLLENR.PLLEN we need to wait for more than 3000 x tp
+	 *
+	 * 3000 x tp = 3000 x 0.16667 ns = 500.01 microseconds
+	 */
+	usleep_range(510, 520);
+
+	return 0;
+}
+
+static void rzv2h_mipi_dsi_dphy_startup_late_init(struct rzg2l_mipi_dsi *dsi)
+{
+	/*
+	 * From RZ/V2H HW manual (Rev.1.20) section 9.5.3 Operation,
+	 * (E) After write to TXSETR we need to wait for more than 200 microseconds
+	 * and then write to PHYRSTR
+	 */
+	usleep_range(210, 220);
+	rzg2l_mipi_dsi_phy_write(dsi, PHYRSTR, PHYRSTR_PHYMRSTN);
+}
+
+static void rzv2h_mipi_dsi_dphy_exit(struct rzg2l_mipi_dsi *dsi)
+{
+	rzg2l_mipi_dsi_phy_write(dsi, PLLENR, 0);
+}
+
 static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
 				  const struct drm_display_mode *mode)
 {
@@ -430,6 +848,9 @@ static void rzg2l_mipi_dsi_set_display_timing(struct rzg2l_mipi_dsi *dsi,
 	case 18:
 		vich1ppsetr = VICH1PPSETR_DT_RGB18;
 		break;
+	case 16:
+		vich1ppsetr = VICH1PPSETR_DT_RGB16;
+		break;
 	}
 
 	if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) &&
@@ -1056,6 +1477,32 @@ static void rzg2l_mipi_dsi_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
+RZV2H_CPG_PLL_DSI_LIMITS(rzv2h_cpg_pll_dsi_limits);
+
+static const struct rzv2h_pll_limits *rzv2h_plldsi_limits[] = {
+	&rzv2h_cpg_pll_dsi_limits,
+};
+
+static const u8 rzv2h_cpg_div_table[] = {
+	2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
+};
+
+static const struct rzg2l_mipi_dsi_hw_info rzv2h_mipi_dsi_info = {
+	.dphy_init = rzv2h_mipi_dsi_dphy_init,
+	.dphy_startup_late_init = rzv2h_mipi_dsi_dphy_startup_late_init,
+	.dphy_exit = rzv2h_mipi_dsi_dphy_exit,
+	.dphy_mode_clk_check = rzv2h_dphy_mode_clk_check,
+	.dphy_conf_clks = rzv2h_dphy_conf_clks,
+	.cpg_plldsi.limits = rzv2h_plldsi_limits,
+	.cpg_plldsi.table = rzv2h_cpg_div_table,
+	.cpg_plldsi.table_size = ARRAY_SIZE(rzv2h_cpg_div_table),
+	.phy_reg_offset = 0x10000,
+	.link_reg_offset = 0,
+	.min_dclk = 5440,
+	.max_dclk = 187500,
+	.features = RZ_MIPI_DSI_FEATURE_16BPP,
+};
+
 static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
 	.dphy_init = rzg2l_mipi_dsi_dphy_init,
 	.dphy_exit = rzg2l_mipi_dsi_dphy_exit,
@@ -1066,6 +1513,7 @@ static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
 };
 
 static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
+	{ .compatible = "renesas,r9a09g057-mipi-dsi", .data = &rzv2h_mipi_dsi_info, },
 	{ .compatible = "renesas,rzg2l-mipi-dsi", .data = &rzg2l_mipi_dsi_info, },
 	{ /* sentinel */ }
 };
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
index d8082a87d874..2bef20566648 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
@@ -40,6 +40,39 @@
 #define DSIDPHYTIM3_THS_TRAIL(x)	((x) << 8)
 #define DSIDPHYTIM3_THS_ZERO(x)		((x) << 0)
 
+/* RZ/V2H DPHY Registers */
+#define PLLENR				0x000
+#define PLLENR_PLLEN			BIT(0)
+
+#define PHYRSTR				0x004
+#define PHYRSTR_PHYMRSTN		BIT(0)
+
+#define PLLCLKSET0R			0x010
+#define PLLCLKSET0R_PLL_S		GENMASK(2, 0)
+#define PLLCLKSET0R_PLL_P		GENMASK(13, 8)
+#define PLLCLKSET0R_PLL_M		GENMASK(25, 16)
+
+#define PLLCLKSET1R			0x014
+#define PLLCLKSET1R_PLL_K		GENMASK(15, 0)
+
+#define PHYTCLKSETR			0x020
+#define PHYTCLKSETR_TCLKTRAILCTL        GENMASK(7, 0)
+#define PHYTCLKSETR_TCLKPOSTCTL         GENMASK(15, 8)
+#define PHYTCLKSETR_TCLKZEROCTL         GENMASK(23, 16)
+#define PHYTCLKSETR_TCLKPRPRCTL         GENMASK(31, 24)
+
+#define PHYTHSSETR			0x024
+#define PHYTHSSETR_THSEXITCTL           GENMASK(7, 0)
+#define PHYTHSSETR_THSTRAILCTL          GENMASK(15, 8)
+#define PHYTHSSETR_THSZEROCTL           GENMASK(23, 16)
+#define PHYTHSSETR_THSPRPRCTL           GENMASK(31, 24)
+
+#define PHYTLPXSETR			0x028
+#define PHYTLPXSETR_TLPXCTL             GENMASK(7, 0)
+
+#define PHYCR				0x030
+#define PHYCR_ULPSEXIT                  GENMASK(9, 0)
+
 /* --------------------------------------------------------*/
 
 /* Link Status Register */
@@ -130,6 +163,7 @@
 
 /* Video-Input Channel 1 Pixel Packet Set Register */
 #define VICH1PPSETR			0x420
+#define VICH1PPSETR_DT_RGB16		(0x0e << 16)
 #define VICH1PPSETR_DT_RGB18		(0x1e << 16)
 #define VICH1PPSETR_DT_RGB18_LS		(0x2e << 16)
 #define VICH1PPSETR_DT_RGB24		(0x3e << 16)
-- 
2.51.0
Re: [PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
Posted by Geert Uytterhoeven 4 months ago
Hi Prabhakar,

On Thu, 2 Oct 2025 at 18:17, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
>
> Add MIPI DSI support for the Renesas RZ/V2H(P) SoC. Compared to the
> RZ/G2L family, the RZ/V2H(P) requires dedicated D-PHY PLL programming,
> different clock configuration, and additional timing parameter handling.
> The driver introduces lookup tables and helpers for D-PHY timings
> (TCLK*, THS*, TLPX, and ULPS exit) as specified in the RZ/V2H(P) hardware
> manual. ULPS exit timing depends on the LPCLK rate and is now handled
> explicitly.
>
> The implementation also adds support for 16 bpp RGB format, updates the
> clock setup path to use the RZ/V2H PLL divider limits, and provides new
> .dphy_init, .dphy_conf_clks, and .dphy_startup_late_init callbacks to
> match the RZ/V2H sequence.
>
> With these changes, the RZ/V2H(P) can operate the MIPI DSI interface in
> compliance with its hardware specification while retaining support for
> existing RZ/G2L platforms.
>
> Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> ---
> v8->v9:
> - Updated Kconfig to select CLK_RZV2H
> - Updated to use renesas.h
> - Added reviewed-by tag from Tomi

Thanks for the update!

> --- a/drivers/gpu/drm/renesas/rz-du/Kconfig
> +++ b/drivers/gpu/drm/renesas/rz-du/Kconfig
> @@ -19,6 +19,7 @@ config DRM_RZG2L_USE_MIPI_DSI
>         depends on DRM_BRIDGE && OF
>         depends on DRM_RZG2L_DU || COMPILE_TEST
>         default DRM_RZG2L_DU
> +       select CLK_RZV2H

As the kernel test robot has already told you, this is not a good idea.
RZ/V2H support is optional, just rely on (dummy) rzv2h_get_pll_*()
helpers returning false if CLK_RZV2H is not enabled.

>         help
>           Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
>

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
Re: [PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
Posted by Lad, Prabhakar 4 months ago
Hi Geert,

Thank you for the review.

On Mon, Oct 6, 2025 at 1:49 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> Hi Prabhakar,
>
> On Thu, 2 Oct 2025 at 18:17, Prabhakar <prabhakar.csengg@gmail.com> wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Add MIPI DSI support for the Renesas RZ/V2H(P) SoC. Compared to the
> > RZ/G2L family, the RZ/V2H(P) requires dedicated D-PHY PLL programming,
> > different clock configuration, and additional timing parameter handling.
> > The driver introduces lookup tables and helpers for D-PHY timings
> > (TCLK*, THS*, TLPX, and ULPS exit) as specified in the RZ/V2H(P) hardware
> > manual. ULPS exit timing depends on the LPCLK rate and is now handled
> > explicitly.
> >
> > The implementation also adds support for 16 bpp RGB format, updates the
> > clock setup path to use the RZ/V2H PLL divider limits, and provides new
> > .dphy_init, .dphy_conf_clks, and .dphy_startup_late_init callbacks to
> > match the RZ/V2H sequence.
> >
> > With these changes, the RZ/V2H(P) can operate the MIPI DSI interface in
> > compliance with its hardware specification while retaining support for
> > existing RZ/G2L platforms.
> >
> > Co-developed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> > ---
> > v8->v9:
> > - Updated Kconfig to select CLK_RZV2H
> > - Updated to use renesas.h
> > - Added reviewed-by tag from Tomi
>
> Thanks for the update!
>
> > --- a/drivers/gpu/drm/renesas/rz-du/Kconfig
> > +++ b/drivers/gpu/drm/renesas/rz-du/Kconfig
> > @@ -19,6 +19,7 @@ config DRM_RZG2L_USE_MIPI_DSI
> >         depends on DRM_BRIDGE && OF
> >         depends on DRM_RZG2L_DU || COMPILE_TEST
> >         default DRM_RZG2L_DU
> > +       select CLK_RZV2H
>
> As the kernel test robot has already told you, this is not a good idea.
> RZ/V2H support is optional, just rely on (dummy) rzv2h_get_pll_*()
> helpers returning false if CLK_RZV2H is not enabled.
>
Agreed, I will add static inline helpers in renesas.h if !CLK_RZV2H.

Cheers,
Prabhakar

> >         help
> >           Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
> >
>
> 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
>
Re: [PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
Posted by kernel test robot 4 months, 1 week ago
Hi Prabhakar,

kernel test robot noticed the following build errors:

[auto build test ERROR on geert-renesas-drivers/renesas-clk]
[also build test ERROR on clk/clk-next robh/for-next linus/master v6.17 next-20251003]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Prabhakar/clk-renesas-rzv2h-cpg-Add-instance-field-to-struct-pll/20251003-002026
base:   https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git renesas-clk
patch link:    https://lore.kernel.org/r/20251002161728.186024-7-prabhakar.mahadev-lad.rj%40bp.renesas.com
patch subject: [PATCH v9 6/6] drm: renesas: rz-du: mipi_dsi: Add support for RZ/V2H(P) SoC
config: s390-randconfig-r131-20251003 (https://download.01.org/0day-ci/archive/20251004/202510040513.VEXSy8SM-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251004/202510040513.VEXSy8SM-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510040513.VEXSy8SM-lkp@intel.com/

All errors (new ones prefixed by >>):

   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_del_clk_provider':
>> drivers/clk/renesas/rzv2h-cpg.c:1625: undefined reference to `of_clk_del_provider'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_ddiv_determine_rate':
>> drivers/clk/renesas/rzv2h-cpg.c:842: undefined reference to `divider_determine_rate'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_plldsi_div_determine_rate':
>> drivers/clk/renesas/rzv2h-cpg.c:497: undefined reference to `clk_hw_get_parent'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_ddiv_recalc_rate':
>> drivers/clk/renesas/rzv2h-cpg.c:833: undefined reference to `divider_recalc_rate'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_plldsi_div_set_rate':
   drivers/clk/renesas/rzv2h-cpg.c:531: undefined reference to `clk_hw_get_parent'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_parent_clk_mux_to_index':
>> drivers/clk/renesas/rzv2h-cpg.c:1209: undefined reference to `clk_mux_val_to_index'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_ddiv_set_rate':
>> drivers/clk/renesas/rzv2h-cpg.c:868: undefined reference to `divider_get_val'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_pll_clk_register':
>> drivers/clk/renesas/rzv2h-cpg.c:806: undefined reference to `__clk_get_name'
>> s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:817: undefined reference to `devm_clk_hw_register'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_register_mod_clk':
   drivers/clk/renesas/rzv2h-cpg.c:1332: undefined reference to `__clk_get_name'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:1346: undefined reference to `devm_clk_hw_register'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_probe':
>> drivers/clk/renesas/rzv2h-cpg.c:1686: undefined reference to `of_clk_add_provider'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_plldsi_div_clk_register':
   drivers/clk/renesas/rzv2h-cpg.c:592: undefined reference to `__clk_get_name'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:602: undefined reference to `devm_clk_hw_register'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_mux_clk_register':
>> drivers/clk/renesas/rzv2h-cpg.c:959: undefined reference to `__devm_clk_hw_register_mux'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_ddiv_clk_register':
   drivers/clk/renesas/rzv2h-cpg.c:916: undefined reference to `__clk_get_name'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:945: undefined reference to `devm_clk_hw_register'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_fixed_mod_status_clk_register':
   drivers/clk/renesas/rzv2h-cpg.c:999: undefined reference to `__clk_get_name'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:1022: undefined reference to `devm_clk_hw_register'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_register_core_clk':
   drivers/clk/renesas/rzv2h-cpg.c:1098: undefined reference to `__clk_get_name'
>> s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.c:1099: undefined reference to `devm_clk_hw_register_fixed_factor'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_del_clk_provider':
>> drivers/clk/renesas/rzv2h-cpg.c:1625: undefined reference to `of_clk_del_provider'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_register_core_clk':
>> drivers/clk/renesas/rzv2h-cpg.c:1115: undefined reference to `clk_fixed_factor_ops'
   s390-linux-ld: drivers/clk/renesas/rzv2h-cpg.o: in function `rzv2h_cpg_ddiv_clk_register':
>> drivers/clk/renesas/rzv2h-cpg.c:927: undefined reference to `clk_divider_ops'

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for CLK_RZV2H
   Depends on [n]: COMMON_CLK [=n] && CLK_RENESAS [=n]
   Selected by [y]:
   - DRM_RZG2L_USE_MIPI_DSI [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_BRIDGE [=y] && OF [=y] && (DRM_RZG2L_DU [=n] || COMPILE_TEST [=y])


vim +1625 drivers/clk/renesas/rzv2h-cpg.c

dd22e56217495e Lad Prabhakar 2024-07-29  1622  
dd22e56217495e Lad Prabhakar 2024-07-29  1623  static void rzv2h_cpg_del_clk_provider(void *data)
dd22e56217495e Lad Prabhakar 2024-07-29  1624  {
dd22e56217495e Lad Prabhakar 2024-07-29 @1625  	of_clk_del_provider(data);
dd22e56217495e Lad Prabhakar 2024-07-29  1626  }
dd22e56217495e Lad Prabhakar 2024-07-29  1627  
dd22e56217495e Lad Prabhakar 2024-07-29  1628  static int __init rzv2h_cpg_probe(struct platform_device *pdev)
dd22e56217495e Lad Prabhakar 2024-07-29  1629  {
dd22e56217495e Lad Prabhakar 2024-07-29  1630  	struct device *dev = &pdev->dev;
dd22e56217495e Lad Prabhakar 2024-07-29  1631  	struct device_node *np = dev->of_node;
dd22e56217495e Lad Prabhakar 2024-07-29  1632  	const struct rzv2h_cpg_info *info;
dd22e56217495e Lad Prabhakar 2024-07-29  1633  	struct rzv2h_cpg_priv *priv;
dd22e56217495e Lad Prabhakar 2024-07-29  1634  	unsigned int nclks, i;
dd22e56217495e Lad Prabhakar 2024-07-29  1635  	struct clk **clks;
dd22e56217495e Lad Prabhakar 2024-07-29  1636  	int error;
dd22e56217495e Lad Prabhakar 2024-07-29  1637  
dd22e56217495e Lad Prabhakar 2024-07-29  1638  	info = of_device_get_match_data(dev);
dd22e56217495e Lad Prabhakar 2024-07-29  1639  
dd22e56217495e Lad Prabhakar 2024-07-29  1640  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
dd22e56217495e Lad Prabhakar 2024-07-29  1641  	if (!priv)
dd22e56217495e Lad Prabhakar 2024-07-29  1642  		return -ENOMEM;
dd22e56217495e Lad Prabhakar 2024-07-29  1643  
bc4d25fdfadfa8 Lad Prabhakar 2024-08-28  1644  	spin_lock_init(&priv->rmw_lock);
bc4d25fdfadfa8 Lad Prabhakar 2024-08-28  1645  
dd22e56217495e Lad Prabhakar 2024-07-29  1646  	priv->dev = dev;
dd22e56217495e Lad Prabhakar 2024-07-29  1647  
dd22e56217495e Lad Prabhakar 2024-07-29  1648  	priv->base = devm_platform_ioremap_resource(pdev, 0);
dd22e56217495e Lad Prabhakar 2024-07-29  1649  	if (IS_ERR(priv->base))
dd22e56217495e Lad Prabhakar 2024-07-29  1650  		return PTR_ERR(priv->base);
dd22e56217495e Lad Prabhakar 2024-07-29  1651  
dd22e56217495e Lad Prabhakar 2024-07-29  1652  	nclks = info->num_total_core_clks + info->num_hw_mod_clks;
dd22e56217495e Lad Prabhakar 2024-07-29  1653  	clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
dd22e56217495e Lad Prabhakar 2024-07-29  1654  	if (!clks)
dd22e56217495e Lad Prabhakar 2024-07-29  1655  		return -ENOMEM;
dd22e56217495e Lad Prabhakar 2024-07-29  1656  
9b6e63a777ea5f Biju Das      2024-12-13  1657  	priv->mstop_count = devm_kcalloc(dev, info->num_mstop_bits,
9b6e63a777ea5f Biju Das      2024-12-13  1658  					 sizeof(*priv->mstop_count), GFP_KERNEL);
9b6e63a777ea5f Biju Das      2024-12-13  1659  	if (!priv->mstop_count)
9b6e63a777ea5f Biju Das      2024-12-13  1660  		return -ENOMEM;
9b6e63a777ea5f Biju Das      2024-12-13  1661  
69ac2acd209a15 Biju Das      2025-02-22  1662  	/* Adjust for CPG_BUS_m_MSTOP starting from m = 1 */
69ac2acd209a15 Biju Das      2025-02-22  1663  	priv->mstop_count -= 16;
69ac2acd209a15 Biju Das      2025-02-22  1664  
338b505d564c1e Raag Jadav    2025-06-10  1665  	priv->resets = devm_kmemdup_array(dev, info->resets, info->num_resets,
338b505d564c1e Raag Jadav    2025-06-10  1666  					  sizeof(*info->resets), GFP_KERNEL);
dd22e56217495e Lad Prabhakar 2024-07-29  1667  	if (!priv->resets)
dd22e56217495e Lad Prabhakar 2024-07-29  1668  		return -ENOMEM;
dd22e56217495e Lad Prabhakar 2024-07-29  1669  
dd22e56217495e Lad Prabhakar 2024-07-29  1670  	dev_set_drvdata(dev, priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1671  	priv->clks = clks;
dd22e56217495e Lad Prabhakar 2024-07-29  1672  	priv->num_core_clks = info->num_total_core_clks;
dd22e56217495e Lad Prabhakar 2024-07-29  1673  	priv->num_mod_clks = info->num_hw_mod_clks;
dd22e56217495e Lad Prabhakar 2024-07-29  1674  	priv->last_dt_core_clk = info->last_dt_core_clk;
dd22e56217495e Lad Prabhakar 2024-07-29  1675  	priv->num_resets = info->num_resets;
dd22e56217495e Lad Prabhakar 2024-07-29  1676  
dd22e56217495e Lad Prabhakar 2024-07-29  1677  	for (i = 0; i < nclks; i++)
dd22e56217495e Lad Prabhakar 2024-07-29  1678  		clks[i] = ERR_PTR(-ENOENT);
dd22e56217495e Lad Prabhakar 2024-07-29  1679  
dd22e56217495e Lad Prabhakar 2024-07-29  1680  	for (i = 0; i < info->num_core_clks; i++)
dd22e56217495e Lad Prabhakar 2024-07-29  1681  		rzv2h_cpg_register_core_clk(&info->core_clks[i], priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1682  
dd22e56217495e Lad Prabhakar 2024-07-29  1683  	for (i = 0; i < info->num_mod_clks; i++)
dd22e56217495e Lad Prabhakar 2024-07-29  1684  		rzv2h_cpg_register_mod_clk(&info->mod_clks[i], priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1685  
dd22e56217495e Lad Prabhakar 2024-07-29 @1686  	error = of_clk_add_provider(np, rzv2h_cpg_clk_src_twocell_get, priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1687  	if (error)
dd22e56217495e Lad Prabhakar 2024-07-29  1688  		return error;
dd22e56217495e Lad Prabhakar 2024-07-29  1689  
dd22e56217495e Lad Prabhakar 2024-07-29  1690  	error = devm_add_action_or_reset(dev, rzv2h_cpg_del_clk_provider, np);
dd22e56217495e Lad Prabhakar 2024-07-29  1691  	if (error)
dd22e56217495e Lad Prabhakar 2024-07-29  1692  		return error;
dd22e56217495e Lad Prabhakar 2024-07-29  1693  
dd22e56217495e Lad Prabhakar 2024-07-29  1694  	error = rzv2h_cpg_add_pm_domains(priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1695  	if (error)
dd22e56217495e Lad Prabhakar 2024-07-29  1696  		return error;
dd22e56217495e Lad Prabhakar 2024-07-29  1697  
dd22e56217495e Lad Prabhakar 2024-07-29  1698  	error = rzv2h_cpg_reset_controller_register(priv);
dd22e56217495e Lad Prabhakar 2024-07-29  1699  	if (error)
dd22e56217495e Lad Prabhakar 2024-07-29  1700  		return error;
dd22e56217495e Lad Prabhakar 2024-07-29  1701  
dd22e56217495e Lad Prabhakar 2024-07-29  1702  	return 0;
dd22e56217495e Lad Prabhakar 2024-07-29  1703  }
dd22e56217495e Lad Prabhakar 2024-07-29  1704  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki