public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH 0/5] Rockchip RK3368 drivers improve
@ 2025-08-14 13:12 WeiHao Li
  2025-08-14 13:12 ` [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set WeiHao Li
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

RK3368 clock and VOP drivers are incomplete, some function is missing.

This patchset improved clk and vop driver to make emmc, i2c, vop and
mipi-dsi working normally.

These patches already tested on a RK3368-based board and it works good,
you can review my test log follow the link blow [1].

This patchset with additional board support already submit to my github
repository, you can find it follow the link blow [2].

Link [1]: https://ieiao.github.io/wiki/embedded-dev/rockchip/rk3368/
Link [2]: https://github.com/ieiao/u-boot/tree/ymd8_mb

WeiHao Li (5):
  clk: rockchip: rk3368: Add bus clk get/set
  clk: rockchip: rk3368: add SCLK for mmc clock get/set
  clk: rockchip: rk3368: Add VOP clock get/set
  video: rockchip: Add bridge support for VOP
  video: rockchip: add RK3368 VOP support

 .../include/asm/arch-rockchip/cru_rk3368.h    |  34 ++
 drivers/clk/rockchip/clk_rk3368.c             | 342 +++++++++++++++++-
 drivers/video/rockchip/Makefile               |   1 +
 drivers/video/rockchip/dw_mipi_dsi_rockchip.c |  20 +
 drivers/video/rockchip/rk3368_vop.c           |  79 ++++
 drivers/video/rockchip/rk_vop.c               |  92 +++--
 6 files changed, 542 insertions(+), 26 deletions(-)
 create mode 100644 drivers/video/rockchip/rk3368_vop.c

-- 
2.39.5


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set
  2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
@ 2025-08-14 13:12 ` WeiHao Li
  2025-11-02  0:50   ` Kever Yang
  2025-08-14 13:12 ` [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set WeiHao Li
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

Some of board need operate PMIC like RK808-B for power supply. It's
depends on I2C peripheral, this patch add bus clock get/set function
which include I2C clock support.

This patch get form Rockchip downstream uboot repository.

Link: https://github.com/rockchip-linux/u-boot

Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
---
 .../include/asm/arch-rockchip/cru_rk3368.h    | 12 +++
 drivers/clk/rockchip/clk_rk3368.c             | 94 +++++++++++++++++++
 2 files changed, 106 insertions(+)

diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
index ed2a61218..845113f13 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
@@ -80,6 +80,18 @@ enum {
 	PLL_RESET			= 1,
 	PLL_RESET_MASK			= GENMASK(5, 5),
 
+	/* CLKSEL8CON */
+	PCLK_BUS_DIV_CON_SHIFT		= 12,
+	PCLK_BUS_DIV_CON_MASK		= 0x7 << PCLK_BUS_DIV_CON_SHIFT,
+	HCLK_BUS_DIV_CON_SHIFT		= 8,
+	HCLK_BUS_DIV_CON_MASK		= 0x3 << HCLK_BUS_DIV_CON_SHIFT,
+	CLK_BUS_PLL_SEL_CPLL		= 0,
+	CLK_BUS_PLL_SEL_GPLL		= 1,
+	CLK_BUS_PLL_SEL_SHIFT		= 7,
+	CLK_BUS_PLL_SEL_MASK		= 1 << CLK_BUS_PLL_SEL_SHIFT,
+	ACLK_BUS_DIV_CON_SHIFT		= 0,
+	ACLK_BUS_DIV_CON_MASK		= 0x1f << ACLK_BUS_DIV_CON_SHIFT,
+
 	/* CLKSEL12_CON */
 	MCU_STCLK_DIV_SHIFT		= 8,
 	MCU_STCLK_DIV_MASK		= GENMASK(10, 8),
diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index 630253fbb..994330162 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -453,6 +453,82 @@ static ulong rk3368_saradc_set_clk(struct rk3368_cru *cru, uint hz)
 	return rk3368_saradc_get_clk(cru);
 }
 
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+static ulong rk3368_bus_get_clk(struct rk3368_cru *cru, ulong clk_id)
+{
+	u32 div, con, parent;
+
+	switch (clk_id) {
+	case ACLK_BUS:
+		con = readl(&cru->clksel_con[8]);
+		div = (con & ACLK_BUS_DIV_CON_MASK) >> ACLK_BUS_DIV_CON_SHIFT;
+		parent = rkclk_pll_get_rate(cru, GPLL);
+		break;
+	case HCLK_BUS:
+		con = readl(&cru->clksel_con[8]);
+		div = (con & HCLK_BUS_DIV_CON_MASK) >> HCLK_BUS_DIV_CON_SHIFT;
+		parent = rk3368_bus_get_clk(cru, ACLK_BUS);
+		break;
+	case PCLK_BUS:
+	case PCLK_PWM0:
+	case PCLK_PWM1:
+	case PCLK_I2C0:
+	case PCLK_I2C1:
+		con = readl(&cru->clksel_con[8]);
+		div = (con & PCLK_BUS_DIV_CON_MASK) >> PCLK_BUS_DIV_CON_SHIFT;
+		parent = rk3368_bus_get_clk(cru, ACLK_BUS);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3368_bus_set_clk(struct rk3368_cru *cru,
+				ulong clk_id, ulong hz)
+{
+	int src_clk_div;
+
+	/*
+	 * select gpll as pd_bus bus clock source and
+	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+	 */
+	switch (clk_id) {
+	case ACLK_BUS:
+		src_clk_div = DIV_ROUND_UP(rkclk_pll_get_rate(cru, GPLL), hz);
+		assert(src_clk_div - 1 < 31);
+		rk_clrsetreg(&cru->clksel_con[8],
+			     CLK_BUS_PLL_SEL_MASK | ACLK_BUS_DIV_CON_MASK,
+			     CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT |
+			     (src_clk_div - 1) << ACLK_BUS_DIV_CON_SHIFT);
+		break;
+	case HCLK_BUS:
+		src_clk_div = DIV_ROUND_UP(rk3368_bus_get_clk(cru,
+							      ACLK_BUS),
+					   hz);
+		assert(src_clk_div - 1 < 3);
+		rk_clrsetreg(&cru->clksel_con[8],
+			     HCLK_BUS_DIV_CON_MASK,
+			     (src_clk_div - 1) << HCLK_BUS_DIV_CON_SHIFT);
+		break;
+	case PCLK_BUS:
+		src_clk_div = DIV_ROUND_UP(rk3368_bus_get_clk(cru,
+							      ACLK_BUS),
+					   hz);
+		assert(src_clk_div - 1 < 3);
+		rk_clrsetreg(&cru->clksel_con[8],
+			     PCLK_BUS_DIV_CON_MASK,
+			     (src_clk_div - 1) << PCLK_BUS_DIV_CON_SHIFT);
+		break;
+	default:
+		printf("do not support this bus freq\n");
+		return -EINVAL;
+	}
+	return rk3368_bus_get_clk(cru, clk_id);
+}
+#endif
+
 static ulong rk3368_clk_get_rate(struct clk *clk)
 {
 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
@@ -469,6 +545,17 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
 	case SCLK_SPI0 ... SCLK_SPI2:
 		rate = rk3368_spi_get_clk(priv->cru, clk->id);
 		break;
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+	case ACLK_BUS:
+	case HCLK_BUS:
+	case PCLK_BUS:
+	case PCLK_PWM0:
+	case PCLK_PWM1:
+	case PCLK_I2C0:
+	case PCLK_I2C1:
+		rate = rk3368_bus_get_clk(priv->cru, clk->id);
+		break;
+#endif
 #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
 	case HCLK_SDMMC:
 	case HCLK_EMMC:
@@ -500,6 +587,13 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
 		ret = rk3368_ddr_set_clk(priv->cru, rate);
 		break;
 #endif
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+	case ACLK_BUS:
+	case HCLK_BUS:
+	case PCLK_BUS:
+		rate = rk3368_bus_set_clk(priv->cru, clk->id, rate);
+		break;
+#endif
 #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
 	case HCLK_SDMMC:
 	case HCLK_EMMC:
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set
  2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
  2025-08-14 13:12 ` [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set WeiHao Li
@ 2025-08-14 13:12 ` WeiHao Li
  2025-11-02  0:50   ` Kever Yang
  2025-08-14 13:12 ` [PATCH 3/5] clk: rockchip: rk3368: Add VOP " WeiHao Li
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

Because of dwmmc driver get clk form a fixed index 1, so must add
SCLK_SDMMC and SCLK_EMMC support to make emmc work.

Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
---
 drivers/clk/rockchip/clk_rk3368.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index 994330162..f9936fb40 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -165,9 +165,11 @@ static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id)
 
 	switch (clk_id) {
 	case HCLK_SDMMC:
+	case SCLK_SDMMC:
 		con_id = 50;
 		break;
 	case HCLK_EMMC:
+	case SCLK_EMMC:
 		con_id = 51;
 		break;
 	case SCLK_SDIO0:
@@ -262,9 +264,11 @@ static ulong rk3368_mmc_set_clk(struct clk *clk, ulong rate)
 
 	switch (clk_id) {
 	case HCLK_SDMMC:
+	case SCLK_SDMMC:
 		con_id = 50;
 		break;
 	case HCLK_EMMC:
+	case SCLK_EMMC:
 		con_id = 51;
 		break;
 	case SCLK_SDIO0:
@@ -559,6 +563,8 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
 #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
 	case HCLK_SDMMC:
 	case HCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_EMMC:
 		rate = rk3368_mmc_get_clk(priv->cru, clk->id);
 		break;
 #endif
@@ -597,6 +603,8 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
 #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
 	case HCLK_SDMMC:
 	case HCLK_EMMC:
+	case SCLK_SDMMC:
+	case SCLK_EMMC:
 		ret = rk3368_mmc_set_clk(clk, rate);
 		break;
 #endif
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/5] clk: rockchip: rk3368: Add VOP clock get/set
  2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
  2025-08-14 13:12 ` [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set WeiHao Li
  2025-08-14 13:12 ` [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set WeiHao Li
@ 2025-08-14 13:12 ` WeiHao Li
  2025-11-02  0:51   ` Kever Yang
  2025-08-14 13:12 ` [PATCH 4/5] video: rockchip: Add bridge support for VOP WeiHao Li
  2025-08-14 13:12 ` [PATCH 5/5] video: rockchip: add RK3368 VOP support WeiHao Li
  4 siblings, 1 reply; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

Clock driver need provide VOP related clocks support if we need display
support, this patch add VOP clock support for rk3368.

This patch get form Rockchip downstream uboot repository.

Link: https://github.com/rockchip-linux/u-boot

Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
---
 .../include/asm/arch-rockchip/cru_rk3368.h    |  22 ++
 drivers/clk/rockchip/clk_rk3368.c             | 240 +++++++++++++++++-
 2 files changed, 257 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
index 845113f13..4e2def4dd 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
@@ -102,6 +102,28 @@ enum {
 	MCU_CLK_DIV_SHIFT		= 0,
 	MCU_CLK_DIV_MASK		= GENMASK(4, 0),
 
+	/* CLKSEL19_CON */
+	ACLK_VOP_PLL_SEL_SHIFT		= 6,
+	ACLK_VOP_PLL_SEL_MASK		= GENMASK(7, 6),
+	ACLK_VOP_PLL_SEL_CPLL		= 0,
+	ACLK_VOP_PLL_SEL_GPLL		= 1,
+	ACLK_VOP_DIV_SHIFT		= 0,
+	ACLK_VOP_DIV_MASK		= GENMASK(4, 0),
+
+	/* CLKSEL20_CON */
+	DCLK_VOP_PLL_SEL_SHIFT		= 8,
+	DCLK_VOP_PLL_SEL_MASK		= GENMASK(9, 8),
+	DCLK_VOP_PLL_SEL_CPLL		= 0,
+	DCLK_VOP_PLL_SEL_GPLL		= 1,
+	DCLK_VOP_PLL_SEL_NPLL		= 2,
+	DCLK_VOP_DIV_SHIFT		= 0,
+	DCLK_VOP_DIV_MASK		= GENMASK(7, 0),
+
+	/* CLKSEL21_CON */
+	HCLK_VOP_DIV_SHIFT		= 0,
+	HCLK_VOP_DIV_MASK		= GENMASK(5, 0),
+	HCLK_VOP_DIV_WIDTH		= 5,
+
 	/* CLKSEL_CON25 */
 	CLK_SARADC_DIV_CON_SHIFT	= 8,
 	CLK_SARADC_DIV_CON_MASK		= GENMASK(15, 8),
diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index f9936fb40..b260391ad 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -31,9 +31,27 @@ struct rk3368_clk_plat {
 #endif
 
 struct pll_div {
+	ulong rate;
 	u32 nr;
 	u32 nf;
 	u32 no;
+	u32 nb;
+};
+
+#define RK3368_PLL_RATE(_rate, _nr, _nf, _no, _nb)	\
+{							\
+	.rate	= _rate##U,				\
+	.nr = _nr,					\
+	.nf = _nf,					\
+	.no = _no,					\
+	.nb = _nb,					\
+}
+
+static struct pll_div rk3368_pll_rates[] = {
+	/* _mhz,  _nr, _nf, _no, _nb */
+	RK3368_PLL_RATE(594000000, 1, 99, 4, 16),
+	RK3368_PLL_RATE(424200000, 5, 707, 8, 0),
+	RK3368_PLL_RATE(410000000, 3, 205, 4, 16),
 };
 
 #define OSC_HZ		(24 * 1000 * 1000)
@@ -41,6 +59,7 @@ struct pll_div {
 #define APLL_B_HZ	(816 * 1000 * 1000)
 #define GPLL_HZ		(576 * 1000 * 1000)
 #define CPLL_HZ		(400 * 1000 * 1000)
+#define NPLL_HZ		(594 * 1000 * 1000)
 
 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
 
@@ -61,6 +80,105 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6);
 
 static ulong rk3368_clk_get_rate(struct clk *clk);
 
+#define VCO_MAX_KHZ	2200000
+#define VCO_MIN_KHZ	440000
+#define FREF_MAX_KHZ	2200000
+#define FREF_MIN_KHZ	269
+#define PLL_LIMIT_FREQ	400000000
+
+struct pll_div *rkclk_get_pll_config(ulong freq_hz)
+{
+	unsigned int rate_count = ARRAY_SIZE(rk3368_pll_rates);
+	int i;
+
+	for (i = 0; i < rate_count; i++) {
+		if (freq_hz == rk3368_pll_rates[i].rate)
+			return &rk3368_pll_rates[i];
+	}
+	return NULL;
+}
+
+static int pll_para_config(ulong freq_hz, struct pll_div *div, uint *ext_div)
+{
+	struct pll_div *best_div = NULL;
+	uint ref_khz = OSC_HZ / 1000, nr, nf = 0;
+	uint fref_khz;
+	uint diff_khz, best_diff_khz;
+	const uint max_nr = 1 << 6, max_nf = 1 << 12, max_no = 1 << 4;
+	uint vco_khz;
+	uint no = 1;
+	uint freq_khz = freq_hz / 1000;
+
+	if (!freq_hz) {
+		printf("%s: the frequency can not be 0 Hz\n", __func__);
+		return -EINVAL;
+	}
+
+	no = DIV_ROUND_UP(VCO_MIN_KHZ, freq_khz);
+	if (ext_div) {
+		*ext_div = DIV_ROUND_UP(PLL_LIMIT_FREQ, freq_hz);
+		no = DIV_ROUND_UP(no, *ext_div);
+	}
+
+	best_div = rkclk_get_pll_config(freq_hz * (*ext_div));
+	if (best_div) {
+		div->nr = best_div->nr;
+		div->nf = best_div->nf;
+		div->no = best_div->no;
+		div->nb = best_div->nb;
+		return 0;
+	}
+
+	/* only even divisors (and 1) are supported */
+	if (no > 1)
+		no = DIV_ROUND_UP(no, 2) * 2;
+
+	vco_khz = freq_khz * no;
+	if (ext_div)
+		vco_khz *= *ext_div;
+
+	if (vco_khz < VCO_MIN_KHZ || vco_khz > VCO_MAX_KHZ || no > max_no) {
+		printf("%s: Cannot find out VCO for Frequency (%luHz).\n",
+		       __func__, freq_hz);
+		return -1;
+	}
+
+	div->no = no;
+
+	best_diff_khz = vco_khz;
+	for (nr = 1; nr < max_nr && best_diff_khz; nr++) {
+		fref_khz = ref_khz / nr;
+		if (fref_khz < FREF_MIN_KHZ)
+			break;
+		if (fref_khz > FREF_MAX_KHZ)
+			continue;
+
+		nf = vco_khz / fref_khz;
+		if (nf >= max_nf)
+			continue;
+		diff_khz = vco_khz - nf * fref_khz;
+		if (nf + 1 < max_nf && diff_khz > fref_khz / 2) {
+			nf++;
+			diff_khz = fref_khz - diff_khz;
+		}
+
+		if (diff_khz >= best_diff_khz)
+			continue;
+
+		best_diff_khz = diff_khz;
+		div->nr = nr;
+		div->nf = nf;
+	}
+
+	if (best_diff_khz > 4 * 1000) {
+		printf("%s:Fail to match output freq %lu,best_is %u Hz\n",
+		       __func__, freq_hz, best_diff_khz * 1000);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /* Get pll rate by id */
 static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
 				   enum rk3368_pll_id pll_id)
@@ -88,7 +206,6 @@ static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
 	}
 }
 
-#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
 static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
 			 const struct pll_div *div)
 {
@@ -128,7 +245,6 @@ static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
 
 	return 0;
 }
-#endif
 
 #if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
 static void rkclk_init(struct rk3368_cru *cru)
@@ -531,6 +647,104 @@ static ulong rk3368_bus_set_clk(struct rk3368_cru *cru,
 	}
 	return rk3368_bus_get_clk(cru, clk_id);
 }
+
+static ulong rk3368_vop_get_clk(struct rk3368_cru *cru,  int clk_id)
+{
+	u32 div, con, parent, sel;
+
+	switch (clk_id) {
+	case DCLK_VOP:
+		con = readl(&cru->clksel_con[20]);
+		div = con & DCLK_VOP_DIV_MASK;
+		parent = rkclk_pll_get_rate(cru, NPLL);
+		break;
+	case ACLK_VOP:
+		con = readl(&cru->clksel_con[19]);
+		div = con & ACLK_VOP_DIV_MASK;
+		sel =  (con & (ACLK_VOP_PLL_SEL_MASK <<
+			ACLK_VOP_PLL_SEL_SHIFT)) >>
+			ACLK_VOP_PLL_SEL_SHIFT;
+		if (sel == ACLK_VOP_PLL_SEL_CPLL)
+			parent = rkclk_pll_get_rate(cru, CPLL);
+		else if (ACLK_VOP_PLL_SEL_GPLL)
+			parent = rkclk_pll_get_rate(cru, GPLL);
+		else
+			parent = 480000000;
+		break;
+	case HCLK_VOP:
+		parent = rk3368_vop_get_clk(cru, ACLK_VOP);
+		con = readl(&cru->clksel_con[21]);
+		div = con & HCLK_VOP_DIV_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return DIV_TO_RATE(parent, div);
+}
+
+static ulong rk3368_vop_set_clk(struct rk3368_cru *cru, int clk_id, uint hz)
+{
+	struct pll_div npll_config = {0};
+	u32 lcdc_div;
+	int ret;
+
+	switch (clk_id) {
+	case DCLK_VOP:
+		if (!(NPLL_HZ % hz)) {
+			rkclk_set_pll(cru, NPLL, rkclk_get_pll_config(NPLL_HZ));
+			lcdc_div = NPLL_HZ / hz;
+		} else {
+			ret = pll_para_config(hz, &npll_config, &lcdc_div);
+			if (ret)
+				return ret;
+
+			rkclk_set_pll(cru, NPLL, &npll_config);
+		}
+		/* vop dclk source clk: npll,dclk_div: 1 */
+		rk_clrsetreg(&cru->clksel_con[20],
+			     (DCLK_VOP_PLL_SEL_MASK << DCLK_VOP_PLL_SEL_SHIFT) |
+			     (DCLK_VOP_DIV_MASK << DCLK_VOP_DIV_SHIFT),
+			     (DCLK_VOP_PLL_SEL_NPLL << DCLK_VOP_PLL_SEL_SHIFT) |
+			     (lcdc_div - 1) << DCLK_VOP_DIV_SHIFT);
+		break;
+	case ACLK_VOP:
+		if ((rkclk_pll_get_rate(cru, CPLL) % hz) == 0) {
+			lcdc_div = rkclk_pll_get_rate(cru, CPLL) / hz;
+			rk_clrsetreg(&cru->clksel_con[19],
+				     (ACLK_VOP_PLL_SEL_MASK <<
+				     ACLK_VOP_PLL_SEL_SHIFT) |
+				     (ACLK_VOP_DIV_MASK <<
+				     ACLK_VOP_DIV_SHIFT),
+				     (ACLK_VOP_PLL_SEL_CPLL <<
+				     ACLK_VOP_PLL_SEL_SHIFT) |
+				     (lcdc_div - 1) <<
+				     ACLK_VOP_DIV_SHIFT);
+		} else {
+			lcdc_div = rkclk_pll_get_rate(cru, GPLL) / hz;
+			rk_clrsetreg(&cru->clksel_con[19],
+				     (ACLK_VOP_PLL_SEL_MASK <<
+				     ACLK_VOP_PLL_SEL_SHIFT) |
+				     (ACLK_VOP_DIV_MASK <<
+				     ACLK_VOP_DIV_SHIFT),
+				     (ACLK_VOP_PLL_SEL_GPLL <<
+				     ACLK_VOP_PLL_SEL_SHIFT) |
+				     (lcdc_div - 1) <<
+				     ACLK_VOP_DIV_SHIFT);
+		}
+		break;
+	case HCLK_VOP:
+		lcdc_div = rk3368_vop_get_clk(cru, ACLK_VOP) / hz;
+		rk_clrsetreg(&cru->clksel_con[21],
+			     HCLK_VOP_DIV_MASK,
+			     (lcdc_div - 1) << HCLK_VOP_DIV_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rk3368_vop_get_clk(cru, clk_id);
+}
 #endif
 
 static ulong rk3368_clk_get_rate(struct clk *clk)
@@ -540,11 +754,13 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
 
 	debug("%s: id %ld\n", __func__, clk->id);
 	switch (clk->id) {
+	case PLL_APLLB:
+	case PLL_APLLL:
+	case PLL_DPLL:
 	case PLL_CPLL:
-		rate = rkclk_pll_get_rate(priv->cru, CPLL);
-		break;
 	case PLL_GPLL:
-		rate = rkclk_pll_get_rate(priv->cru, GPLL);
+	case PLL_NPLL:
+		rate = rkclk_pll_get_rate(priv->cru, clk->id - 1);
 		break;
 	case SCLK_SPI0 ... SCLK_SPI2:
 		rate = rk3368_spi_get_clk(priv->cru, clk->id);
@@ -571,6 +787,13 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
 	case SCLK_SARADC:
 		rate = rk3368_saradc_get_clk(priv->cru);
 		break;
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+	case ACLK_VOP:
+	case DCLK_VOP:
+	case HCLK_VOP:
+		rate = rk3368_vop_get_clk(priv->cru, clk->id);
+		break;
+#endif
 	default:
 		return -ENOENT;
 	}
@@ -617,6 +840,13 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
 	case SCLK_SARADC:
 		ret =  rk3368_saradc_set_clk(priv->cru, rate);
 		break;
+#if !defined(CONFIG_XPL_BUILD)
+	case ACLK_VOP:
+	case DCLK_VOP:
+	case HCLK_VOP:
+		ret = rk3368_vop_set_clk(priv->cru, clk->id, rate);
+		break;
+#endif
 	default:
 		return -ENOENT;
 	}
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/5] video: rockchip: Add bridge support for VOP
  2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
                   ` (2 preceding siblings ...)
  2025-08-14 13:12 ` [PATCH 3/5] clk: rockchip: rk3368: Add VOP " WeiHao Li
@ 2025-08-14 13:12 ` WeiHao Li
  2025-11-03  3:27   ` Chaoyi Chen
  2025-08-14 13:12 ` [PATCH 5/5] video: rockchip: add RK3368 VOP support WeiHao Li
  4 siblings, 1 reply; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

Rockchip VOP driver only support UCLASS_DISPLAY for now, It can't work
if SOC use dw-mipi with inno-dphy like RK3368.

This patch try to add UCLASS_VIDEO_BRIDGE support to let it support
dw-mipi-dsi-rockchip driver, will support SOC use dw-mipi with inno-dphy.

This patch basic same as muratdemirtas's github repository, just adjust
some code style.

Link: https://github.com/muratdemirtas/rockchip-rk3399-uboot-mipi-dsi

Signed-off-by: muratdemirtas <muratdemirtaseu@outlook.com>
Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
---
 drivers/video/rockchip/rk_vop.c | 92 +++++++++++++++++++++++++--------
 1 file changed, 71 insertions(+), 21 deletions(-)

diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index 17dfe62c9..71786da77 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -14,6 +14,8 @@
 #include <reset.h>
 #include <syscon.h>
 #include <video.h>
+#include <video_bridge.h>
+#include <panel.h>
 #include <asm/global_data.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
@@ -257,6 +259,8 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 	ofnode remote;
 	const char *compat;
 	struct reset_ctl dclk_rst;
+	struct udevice *bridge;
+	struct udevice *panel;
 
 	debug("%s(%s, 0x%lx, %s)\n", __func__,
 	      dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
@@ -298,6 +302,10 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 			return -EINVAL;
 		}
 
+		uclass_find_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote, &bridge);
+		if (bridge)
+			break;
+
 		uclass_find_device_by_ofnode(UCLASS_DISPLAY, remote, &disp);
 		if (disp)
 			break;
@@ -326,27 +334,60 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 	}
 	debug("vop_id=%d\n", vop_id);
 
-	disp_uc_plat = dev_get_uclass_plat(disp);
-	debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
-	if (display_in_use(disp)) {
-		debug("   - device in use\n");
-		return -EBUSY;
-	}
+	if (bridge) {
+		/* video bridge detected, probe it */
+		ret = device_probe(bridge);
+		if (ret) {
+			debug("%s: device '%s' bridge won't probe (ret=%d)\n",
+			      __func__, dev->name, ret);
+			return ret;
+		}
 
-	disp_uc_plat->source_id = remote_vop_id;
-	disp_uc_plat->src_dev = dev;
+		/* Attach the DSI controller and the display to the bridge. */
+		ret = video_bridge_attach(bridge);
+		if (ret) {
+			debug("Failed to attach video bridge: %d\n", ret);
+			return ret;
+		}
 
-	ret = device_probe(disp);
-	if (ret) {
-		debug("%s: device '%s' display won't probe (ret=%d)\n",
-		      __func__, dev->name, ret);
-		return ret;
-	}
+		/*
+		 * Get the panel device
+		 * TODO: Maybe fetch it from the bridge private data.
+		 */
+		ret = uclass_first_device_err(UCLASS_PANEL, &panel);
+		if (ret) {
+			debug("Panel device error: %d\n", ret);
+			return ret;
+		}
 
-	ret = display_read_timing(disp, &timing);
-	if (ret) {
-		debug("%s: Failed to read timings\n", __func__);
-		return ret;
+		ret = panel_get_display_timing(panel, &timing);
+		if (ret) {
+			debug("%s: Failed to read timings\n", __func__);
+			return ret;
+		}
+	} else {
+		disp_uc_plat = dev_get_uclass_plat(disp);
+		debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
+		if (display_in_use(disp)) {
+			debug("   - device in use\n");
+			return -EBUSY;
+		}
+
+		disp_uc_plat->source_id = remote_vop_id;
+		disp_uc_plat->src_dev = dev;
+
+		ret = device_probe(disp);
+		if (ret) {
+			debug("%s: device '%s' display won't probe (ret=%d)\n",
+			      __func__, dev->name, ret);
+			return ret;
+		}
+
+		ret = display_read_timing(disp, &timing);
+		if (ret) {
+			debug("%s: Failed to read timings\n", __func__);
+			return ret;
+		}
 	}
 
 	ret = clk_get_by_index(dev, 1, &clk);
@@ -383,9 +424,18 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 
 	rkvop_enable(dev, fbbase, 1 << l2bpp, &timing, &dclk_rst);
 
-	ret = display_enable(disp, 1 << l2bpp, &timing);
-	if (ret)
-		return ret;
+	if (bridge) {
+		/* Attach the DSI controller and the display to the bridge. */
+		ret = video_bridge_set_backlight(bridge, 80);
+		if (ret) {
+			printf("Failed to start the video bridge: %d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = display_enable(disp, 1 << l2bpp, &timing);
+		if (ret)
+			return ret;
+	}
 
 	uc_priv->xsize = timing.hactive.typ;
 	uc_priv->ysize = timing.vactive.typ;
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/5] video: rockchip: add RK3368 VOP support
  2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
                   ` (3 preceding siblings ...)
  2025-08-14 13:12 ` [PATCH 4/5] video: rockchip: Add bridge support for VOP WeiHao Li
@ 2025-08-14 13:12 ` WeiHao Li
  4 siblings, 0 replies; 10+ messages in thread
From: WeiHao Li @ 2025-08-14 13:12 UTC (permalink / raw)
  To: u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, WeiHao Li

This patch adds RK3368 VOP driver based on RK3288. I got its GRF register
user manual from a online forum.

Link: https://github.com/ieiao/wiki/blob/master/docs/embedded-dev/rockchip/rk3368/Rockchip_RK3368_GRF.pdf

Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
---
 drivers/video/rockchip/Makefile               |  1 +
 drivers/video/rockchip/dw_mipi_dsi_rockchip.c | 20 +++++
 drivers/video/rockchip/rk3368_vop.c           | 79 +++++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 drivers/video/rockchip/rk3368_vop.c

diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile
index f55beceeb..83c0b7aef 100644
--- a/drivers/video/rockchip/Makefile
+++ b/drivers/video/rockchip/Makefile
@@ -7,6 +7,7 @@ ifdef CONFIG_VIDEO_ROCKCHIP
 obj-y += rk_vop.o
 obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o
 obj-$(CONFIG_ROCKCHIP_RK3328) += rk3328_vop.o
+obj-$(CONFIG_ROCKCHIP_RK3368) += rk3368_vop.o
 obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o
 obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o
 obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o
diff --git a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
index fa5121735..122974d60 100644
--- a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
+++ b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
@@ -134,6 +134,11 @@
 #define DW_MIPI_NEEDS_PHY_CFG_CLK	BIT(0)
 #define DW_MIPI_NEEDS_GRF_CLK		BIT(1)
 
+#define RK3368_GRF_SOC_CON7		0x41c
+#define RK3368_DSI_FORCETXSTOPMODE	(0xf << 7)
+#define RK3368_DSI_FORCERXMODE		(0x1 << 6)
+#define RK3368_DSI_TURNDISABLE		(0x1 << 5)
+
 #define RK3399_GRF_SOC_CON20		0x6250
 #define RK3399_DSI0_LCDC_SEL		BIT(0)
 #define RK3399_DSI1_LCDC_SEL		BIT(4)
@@ -911,6 +916,18 @@ struct video_bridge_ops dw_mipi_dsi_rockchip_ops = {
 	.set_backlight = dw_mipi_dsi_rockchip_set_bl,
 };
 
+static const struct rockchip_dw_dsi_chip_data rk3368_chip_data[] = {
+	{
+		.reg = 0xff960000,
+		.lanecfg1_grf_reg = RK3368_GRF_SOC_CON7,
+		.lanecfg1 = HIWORD_UPDATE(0, RK3368_DSI_TURNDISABLE |
+					     RK3368_DSI_FORCETXSTOPMODE |
+					     RK3368_DSI_FORCERXMODE),
+		.max_data_lanes = 4,
+	},
+	{ /* sentinel */ }
+};
+
 static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
 	{
 		.reg = 0xff960000,
@@ -980,6 +997,9 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
 };
 
 static const struct udevice_id dw_mipi_dsi_rockchip_dt_ids[] = {
+	{ .compatible = "rockchip,rk3368-mipi-dsi",
+	  .data = (long)&rk3368_chip_data,
+	},
 	{ .compatible = "rockchip,rk3399-mipi-dsi",
 	  .data = (long)&rk3399_chip_data,
 	},
diff --git a/drivers/video/rockchip/rk3368_vop.c b/drivers/video/rockchip/rk3368_vop.c
new file mode 100644
index 000000000..b4aac51c5
--- /dev/null
+++ b/drivers/video/rockchip/rk3368_vop.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author(s): WeiHao Li <cn.liweihao@gmail.com>
+ */
+
+#include <display.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <video.h>
+#include <asm/global_data.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <linux/delay.h>
+#include "rk_vop.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void rk3368_set_pin_polarity(struct udevice *dev,
+				    enum vop_modes mode, u32 polarity)
+{
+	struct rk_vop_priv *priv = dev_get_priv(dev);
+	struct rk3288_vop *regs = priv->regs;
+
+	/* The RK3368 VOP (v3.2) has its polarity configuration in ctrl0 */
+	clrsetbits_le32(&regs->dsp_ctrl0,
+			M_DSP_DCLK_POL | M_DSP_DEN_POL |
+			M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
+			V_DSP_PIN_POL(polarity));
+}
+
+/*
+ * Try some common regulators. We should really get these from the
+ * device tree somehow.
+ */
+static const char * const rk3368_regulator_names[] = {
+	"vcc18_lcd",
+	"VCC18_LCD",
+	"vdd10_lcd_pwren_h",
+	"vdd10_lcd",
+	"VDD10_LCD",
+	"vcc33_lcd"
+};
+
+static int rk3368_vop_probe(struct udevice *dev)
+{
+	/* Before relocation we don't need to do anything */
+	if (!(gd->flags & GD_FLG_RELOC))
+		return 0;
+
+	/* Probe regulators required for the RK3368 VOP */
+	rk_vop_probe_regulators(dev, rk3368_regulator_names,
+				ARRAY_SIZE(rk3368_regulator_names));
+
+	return rk_vop_probe(dev);
+}
+
+struct rkvop_driverdata rk3368_driverdata = {
+	.set_pin_polarity = rk3368_set_pin_polarity,
+};
+
+static const struct udevice_id rk3368_vop_ids[] = {
+	{ .compatible = "rockchip,rk3368-vop",
+	  .data = (ulong)&rk3368_driverdata },
+	{ }
+};
+
+static const struct video_ops rk3368_vop_ops = {
+};
+
+U_BOOT_DRIVER(rockchip_rk3368_vop) = {
+	.name		= "rockchip_rk3368_vop",
+	.id		= UCLASS_VIDEO,
+	.of_match 	= rk3368_vop_ids,
+	.ops		= &rk3368_vop_ops,
+	.bind		= rk_vop_bind,
+	.probe		= rk3368_vop_probe,
+	.priv_auto	= sizeof(struct rk_vop_priv),
+};
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set
  2025-08-14 13:12 ` [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set WeiHao Li
@ 2025-11-02  0:50   ` Kever Yang
  0 siblings, 0 replies; 10+ messages in thread
From: Kever Yang @ 2025-11-02  0:50 UTC (permalink / raw)
  To: WeiHao Li, u-boot
  Cc: trini, sjg, philipp.tomsich, lukma, seanga2, ag.dev.uboot,
	muratdemirtaseu


On 2025/8/14 21:12, WeiHao Li wrote:
> Some of board need operate PMIC like RK808-B for power supply. It's
> depends on I2C peripheral, this patch add bus clock get/set function
> which include I2C clock support.
>
> This patch get form Rockchip downstream uboot repository.
>
> Link: https://github.com/rockchip-linux/u-boot
>
> Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>

Thanks,
- Kever
> ---
>   .../include/asm/arch-rockchip/cru_rk3368.h    | 12 +++
>   drivers/clk/rockchip/clk_rk3368.c             | 94 +++++++++++++++++++
>   2 files changed, 106 insertions(+)
>
> diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> index ed2a61218..845113f13 100644
> --- a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> @@ -80,6 +80,18 @@ enum {
>   	PLL_RESET			= 1,
>   	PLL_RESET_MASK			= GENMASK(5, 5),
>   
> +	/* CLKSEL8CON */
> +	PCLK_BUS_DIV_CON_SHIFT		= 12,
> +	PCLK_BUS_DIV_CON_MASK		= 0x7 << PCLK_BUS_DIV_CON_SHIFT,
> +	HCLK_BUS_DIV_CON_SHIFT		= 8,
> +	HCLK_BUS_DIV_CON_MASK		= 0x3 << HCLK_BUS_DIV_CON_SHIFT,
> +	CLK_BUS_PLL_SEL_CPLL		= 0,
> +	CLK_BUS_PLL_SEL_GPLL		= 1,
> +	CLK_BUS_PLL_SEL_SHIFT		= 7,
> +	CLK_BUS_PLL_SEL_MASK		= 1 << CLK_BUS_PLL_SEL_SHIFT,
> +	ACLK_BUS_DIV_CON_SHIFT		= 0,
> +	ACLK_BUS_DIV_CON_MASK		= 0x1f << ACLK_BUS_DIV_CON_SHIFT,
> +
>   	/* CLKSEL12_CON */
>   	MCU_STCLK_DIV_SHIFT		= 8,
>   	MCU_STCLK_DIV_MASK		= GENMASK(10, 8),
> diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
> index 630253fbb..994330162 100644
> --- a/drivers/clk/rockchip/clk_rk3368.c
> +++ b/drivers/clk/rockchip/clk_rk3368.c
> @@ -453,6 +453,82 @@ static ulong rk3368_saradc_set_clk(struct rk3368_cru *cru, uint hz)
>   	return rk3368_saradc_get_clk(cru);
>   }
>   
> +#if !IS_ENABLED(CONFIG_XPL_BUILD)
> +static ulong rk3368_bus_get_clk(struct rk3368_cru *cru, ulong clk_id)
> +{
> +	u32 div, con, parent;
> +
> +	switch (clk_id) {
> +	case ACLK_BUS:
> +		con = readl(&cru->clksel_con[8]);
> +		div = (con & ACLK_BUS_DIV_CON_MASK) >> ACLK_BUS_DIV_CON_SHIFT;
> +		parent = rkclk_pll_get_rate(cru, GPLL);
> +		break;
> +	case HCLK_BUS:
> +		con = readl(&cru->clksel_con[8]);
> +		div = (con & HCLK_BUS_DIV_CON_MASK) >> HCLK_BUS_DIV_CON_SHIFT;
> +		parent = rk3368_bus_get_clk(cru, ACLK_BUS);
> +		break;
> +	case PCLK_BUS:
> +	case PCLK_PWM0:
> +	case PCLK_PWM1:
> +	case PCLK_I2C0:
> +	case PCLK_I2C1:
> +		con = readl(&cru->clksel_con[8]);
> +		div = (con & PCLK_BUS_DIV_CON_MASK) >> PCLK_BUS_DIV_CON_SHIFT;
> +		parent = rk3368_bus_get_clk(cru, ACLK_BUS);
> +		break;
> +	default:
> +		return -ENOENT;
> +	}
> +
> +	return DIV_TO_RATE(parent, div);
> +}
> +
> +static ulong rk3368_bus_set_clk(struct rk3368_cru *cru,
> +				ulong clk_id, ulong hz)
> +{
> +	int src_clk_div;
> +
> +	/*
> +	 * select gpll as pd_bus bus clock source and
> +	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
> +	 */
> +	switch (clk_id) {
> +	case ACLK_BUS:
> +		src_clk_div = DIV_ROUND_UP(rkclk_pll_get_rate(cru, GPLL), hz);
> +		assert(src_clk_div - 1 < 31);
> +		rk_clrsetreg(&cru->clksel_con[8],
> +			     CLK_BUS_PLL_SEL_MASK | ACLK_BUS_DIV_CON_MASK,
> +			     CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT |
> +			     (src_clk_div - 1) << ACLK_BUS_DIV_CON_SHIFT);
> +		break;
> +	case HCLK_BUS:
> +		src_clk_div = DIV_ROUND_UP(rk3368_bus_get_clk(cru,
> +							      ACLK_BUS),
> +					   hz);
> +		assert(src_clk_div - 1 < 3);
> +		rk_clrsetreg(&cru->clksel_con[8],
> +			     HCLK_BUS_DIV_CON_MASK,
> +			     (src_clk_div - 1) << HCLK_BUS_DIV_CON_SHIFT);
> +		break;
> +	case PCLK_BUS:
> +		src_clk_div = DIV_ROUND_UP(rk3368_bus_get_clk(cru,
> +							      ACLK_BUS),
> +					   hz);
> +		assert(src_clk_div - 1 < 3);
> +		rk_clrsetreg(&cru->clksel_con[8],
> +			     PCLK_BUS_DIV_CON_MASK,
> +			     (src_clk_div - 1) << PCLK_BUS_DIV_CON_SHIFT);
> +		break;
> +	default:
> +		printf("do not support this bus freq\n");
> +		return -EINVAL;
> +	}
> +	return rk3368_bus_get_clk(cru, clk_id);
> +}
> +#endif
> +
>   static ulong rk3368_clk_get_rate(struct clk *clk)
>   {
>   	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
> @@ -469,6 +545,17 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
>   	case SCLK_SPI0 ... SCLK_SPI2:
>   		rate = rk3368_spi_get_clk(priv->cru, clk->id);
>   		break;
> +#if !IS_ENABLED(CONFIG_XPL_BUILD)
> +	case ACLK_BUS:
> +	case HCLK_BUS:
> +	case PCLK_BUS:
> +	case PCLK_PWM0:
> +	case PCLK_PWM1:
> +	case PCLK_I2C0:
> +	case PCLK_I2C1:
> +		rate = rk3368_bus_get_clk(priv->cru, clk->id);
> +		break;
> +#endif
>   #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
>   	case HCLK_SDMMC:
>   	case HCLK_EMMC:
> @@ -500,6 +587,13 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
>   		ret = rk3368_ddr_set_clk(priv->cru, rate);
>   		break;
>   #endif
> +#if !IS_ENABLED(CONFIG_XPL_BUILD)
> +	case ACLK_BUS:
> +	case HCLK_BUS:
> +	case PCLK_BUS:
> +		rate = rk3368_bus_set_clk(priv->cru, clk->id, rate);
> +		break;
> +#endif
>   #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
>   	case HCLK_SDMMC:
>   	case HCLK_EMMC:

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set
  2025-08-14 13:12 ` [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set WeiHao Li
@ 2025-11-02  0:50   ` Kever Yang
  0 siblings, 0 replies; 10+ messages in thread
From: Kever Yang @ 2025-11-02  0:50 UTC (permalink / raw)
  To: WeiHao Li, u-boot
  Cc: trini, sjg, philipp.tomsich, lukma, seanga2, ag.dev.uboot,
	muratdemirtaseu


On 2025/8/14 21:12, WeiHao Li wrote:
> Because of dwmmc driver get clk form a fixed index 1, so must add
> SCLK_SDMMC and SCLK_EMMC support to make emmc work.
>
> Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>

Thanks,
- Kever
> ---
>   drivers/clk/rockchip/clk_rk3368.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
>
> diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
> index 994330162..f9936fb40 100644
> --- a/drivers/clk/rockchip/clk_rk3368.c
> +++ b/drivers/clk/rockchip/clk_rk3368.c
> @@ -165,9 +165,11 @@ static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id)
>   
>   	switch (clk_id) {
>   	case HCLK_SDMMC:
> +	case SCLK_SDMMC:
>   		con_id = 50;
>   		break;
>   	case HCLK_EMMC:
> +	case SCLK_EMMC:
>   		con_id = 51;
>   		break;
>   	case SCLK_SDIO0:
> @@ -262,9 +264,11 @@ static ulong rk3368_mmc_set_clk(struct clk *clk, ulong rate)
>   
>   	switch (clk_id) {
>   	case HCLK_SDMMC:
> +	case SCLK_SDMMC:
>   		con_id = 50;
>   		break;
>   	case HCLK_EMMC:
> +	case SCLK_EMMC:
>   		con_id = 51;
>   		break;
>   	case SCLK_SDIO0:
> @@ -559,6 +563,8 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
>   #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
>   	case HCLK_SDMMC:
>   	case HCLK_EMMC:
> +	case SCLK_SDMMC:
> +	case SCLK_EMMC:
>   		rate = rk3368_mmc_get_clk(priv->cru, clk->id);
>   		break;
>   #endif
> @@ -597,6 +603,8 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
>   #if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC)
>   	case HCLK_SDMMC:
>   	case HCLK_EMMC:
> +	case SCLK_SDMMC:
> +	case SCLK_EMMC:
>   		ret = rk3368_mmc_set_clk(clk, rate);
>   		break;
>   #endif

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/5] clk: rockchip: rk3368: Add VOP clock get/set
  2025-08-14 13:12 ` [PATCH 3/5] clk: rockchip: rk3368: Add VOP " WeiHao Li
@ 2025-11-02  0:51   ` Kever Yang
  0 siblings, 0 replies; 10+ messages in thread
From: Kever Yang @ 2025-11-02  0:51 UTC (permalink / raw)
  To: WeiHao Li, u-boot
  Cc: trini, sjg, philipp.tomsich, lukma, seanga2, ag.dev.uboot,
	muratdemirtaseu


On 2025/8/14 21:12, WeiHao Li wrote:
> Clock driver need provide VOP related clocks support if we need display
> support, this patch add VOP clock support for rk3368.
>
> This patch get form Rockchip downstream uboot repository.
>
> Link: https://github.com/rockchip-linux/u-boot
>
> Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>

Thanks,
- Kever
> ---
>   .../include/asm/arch-rockchip/cru_rk3368.h    |  22 ++
>   drivers/clk/rockchip/clk_rk3368.c             | 240 +++++++++++++++++-
>   2 files changed, 257 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> index 845113f13..4e2def4dd 100644
> --- a/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3368.h
> @@ -102,6 +102,28 @@ enum {
>   	MCU_CLK_DIV_SHIFT		= 0,
>   	MCU_CLK_DIV_MASK		= GENMASK(4, 0),
>   
> +	/* CLKSEL19_CON */
> +	ACLK_VOP_PLL_SEL_SHIFT		= 6,
> +	ACLK_VOP_PLL_SEL_MASK		= GENMASK(7, 6),
> +	ACLK_VOP_PLL_SEL_CPLL		= 0,
> +	ACLK_VOP_PLL_SEL_GPLL		= 1,
> +	ACLK_VOP_DIV_SHIFT		= 0,
> +	ACLK_VOP_DIV_MASK		= GENMASK(4, 0),
> +
> +	/* CLKSEL20_CON */
> +	DCLK_VOP_PLL_SEL_SHIFT		= 8,
> +	DCLK_VOP_PLL_SEL_MASK		= GENMASK(9, 8),
> +	DCLK_VOP_PLL_SEL_CPLL		= 0,
> +	DCLK_VOP_PLL_SEL_GPLL		= 1,
> +	DCLK_VOP_PLL_SEL_NPLL		= 2,
> +	DCLK_VOP_DIV_SHIFT		= 0,
> +	DCLK_VOP_DIV_MASK		= GENMASK(7, 0),
> +
> +	/* CLKSEL21_CON */
> +	HCLK_VOP_DIV_SHIFT		= 0,
> +	HCLK_VOP_DIV_MASK		= GENMASK(5, 0),
> +	HCLK_VOP_DIV_WIDTH		= 5,
> +
>   	/* CLKSEL_CON25 */
>   	CLK_SARADC_DIV_CON_SHIFT	= 8,
>   	CLK_SARADC_DIV_CON_MASK		= GENMASK(15, 8),
> diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
> index f9936fb40..b260391ad 100644
> --- a/drivers/clk/rockchip/clk_rk3368.c
> +++ b/drivers/clk/rockchip/clk_rk3368.c
> @@ -31,9 +31,27 @@ struct rk3368_clk_plat {
>   #endif
>   
>   struct pll_div {
> +	ulong rate;
>   	u32 nr;
>   	u32 nf;
>   	u32 no;
> +	u32 nb;
> +};
> +
> +#define RK3368_PLL_RATE(_rate, _nr, _nf, _no, _nb)	\
> +{							\
> +	.rate	= _rate##U,				\
> +	.nr = _nr,					\
> +	.nf = _nf,					\
> +	.no = _no,					\
> +	.nb = _nb,					\
> +}
> +
> +static struct pll_div rk3368_pll_rates[] = {
> +	/* _mhz,  _nr, _nf, _no, _nb */
> +	RK3368_PLL_RATE(594000000, 1, 99, 4, 16),
> +	RK3368_PLL_RATE(424200000, 5, 707, 8, 0),
> +	RK3368_PLL_RATE(410000000, 3, 205, 4, 16),
>   };
>   
>   #define OSC_HZ		(24 * 1000 * 1000)
> @@ -41,6 +59,7 @@ struct pll_div {
>   #define APLL_B_HZ	(816 * 1000 * 1000)
>   #define GPLL_HZ		(576 * 1000 * 1000)
>   #define CPLL_HZ		(400 * 1000 * 1000)
> +#define NPLL_HZ		(594 * 1000 * 1000)
>   
>   #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
>   
> @@ -61,6 +80,105 @@ static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6);
>   
>   static ulong rk3368_clk_get_rate(struct clk *clk);
>   
> +#define VCO_MAX_KHZ	2200000
> +#define VCO_MIN_KHZ	440000
> +#define FREF_MAX_KHZ	2200000
> +#define FREF_MIN_KHZ	269
> +#define PLL_LIMIT_FREQ	400000000
> +
> +struct pll_div *rkclk_get_pll_config(ulong freq_hz)
> +{
> +	unsigned int rate_count = ARRAY_SIZE(rk3368_pll_rates);
> +	int i;
> +
> +	for (i = 0; i < rate_count; i++) {
> +		if (freq_hz == rk3368_pll_rates[i].rate)
> +			return &rk3368_pll_rates[i];
> +	}
> +	return NULL;
> +}
> +
> +static int pll_para_config(ulong freq_hz, struct pll_div *div, uint *ext_div)
> +{
> +	struct pll_div *best_div = NULL;
> +	uint ref_khz = OSC_HZ / 1000, nr, nf = 0;
> +	uint fref_khz;
> +	uint diff_khz, best_diff_khz;
> +	const uint max_nr = 1 << 6, max_nf = 1 << 12, max_no = 1 << 4;
> +	uint vco_khz;
> +	uint no = 1;
> +	uint freq_khz = freq_hz / 1000;
> +
> +	if (!freq_hz) {
> +		printf("%s: the frequency can not be 0 Hz\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	no = DIV_ROUND_UP(VCO_MIN_KHZ, freq_khz);
> +	if (ext_div) {
> +		*ext_div = DIV_ROUND_UP(PLL_LIMIT_FREQ, freq_hz);
> +		no = DIV_ROUND_UP(no, *ext_div);
> +	}
> +
> +	best_div = rkclk_get_pll_config(freq_hz * (*ext_div));
> +	if (best_div) {
> +		div->nr = best_div->nr;
> +		div->nf = best_div->nf;
> +		div->no = best_div->no;
> +		div->nb = best_div->nb;
> +		return 0;
> +	}
> +
> +	/* only even divisors (and 1) are supported */
> +	if (no > 1)
> +		no = DIV_ROUND_UP(no, 2) * 2;
> +
> +	vco_khz = freq_khz * no;
> +	if (ext_div)
> +		vco_khz *= *ext_div;
> +
> +	if (vco_khz < VCO_MIN_KHZ || vco_khz > VCO_MAX_KHZ || no > max_no) {
> +		printf("%s: Cannot find out VCO for Frequency (%luHz).\n",
> +		       __func__, freq_hz);
> +		return -1;
> +	}
> +
> +	div->no = no;
> +
> +	best_diff_khz = vco_khz;
> +	for (nr = 1; nr < max_nr && best_diff_khz; nr++) {
> +		fref_khz = ref_khz / nr;
> +		if (fref_khz < FREF_MIN_KHZ)
> +			break;
> +		if (fref_khz > FREF_MAX_KHZ)
> +			continue;
> +
> +		nf = vco_khz / fref_khz;
> +		if (nf >= max_nf)
> +			continue;
> +		diff_khz = vco_khz - nf * fref_khz;
> +		if (nf + 1 < max_nf && diff_khz > fref_khz / 2) {
> +			nf++;
> +			diff_khz = fref_khz - diff_khz;
> +		}
> +
> +		if (diff_khz >= best_diff_khz)
> +			continue;
> +
> +		best_diff_khz = diff_khz;
> +		div->nr = nr;
> +		div->nf = nf;
> +	}
> +
> +	if (best_diff_khz > 4 * 1000) {
> +		printf("%s:Fail to match output freq %lu,best_is %u Hz\n",
> +		       __func__, freq_hz, best_diff_khz * 1000);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>   /* Get pll rate by id */
>   static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
>   				   enum rk3368_pll_id pll_id)
> @@ -88,7 +206,6 @@ static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
>   	}
>   }
>   
> -#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
>   static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
>   			 const struct pll_div *div)
>   {
> @@ -128,7 +245,6 @@ static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
>   
>   	return 0;
>   }
> -#endif
>   
>   #if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
>   static void rkclk_init(struct rk3368_cru *cru)
> @@ -531,6 +647,104 @@ static ulong rk3368_bus_set_clk(struct rk3368_cru *cru,
>   	}
>   	return rk3368_bus_get_clk(cru, clk_id);
>   }
> +
> +static ulong rk3368_vop_get_clk(struct rk3368_cru *cru,  int clk_id)
> +{
> +	u32 div, con, parent, sel;
> +
> +	switch (clk_id) {
> +	case DCLK_VOP:
> +		con = readl(&cru->clksel_con[20]);
> +		div = con & DCLK_VOP_DIV_MASK;
> +		parent = rkclk_pll_get_rate(cru, NPLL);
> +		break;
> +	case ACLK_VOP:
> +		con = readl(&cru->clksel_con[19]);
> +		div = con & ACLK_VOP_DIV_MASK;
> +		sel =  (con & (ACLK_VOP_PLL_SEL_MASK <<
> +			ACLK_VOP_PLL_SEL_SHIFT)) >>
> +			ACLK_VOP_PLL_SEL_SHIFT;
> +		if (sel == ACLK_VOP_PLL_SEL_CPLL)
> +			parent = rkclk_pll_get_rate(cru, CPLL);
> +		else if (ACLK_VOP_PLL_SEL_GPLL)
> +			parent = rkclk_pll_get_rate(cru, GPLL);
> +		else
> +			parent = 480000000;
> +		break;
> +	case HCLK_VOP:
> +		parent = rk3368_vop_get_clk(cru, ACLK_VOP);
> +		con = readl(&cru->clksel_con[21]);
> +		div = con & HCLK_VOP_DIV_MASK;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return DIV_TO_RATE(parent, div);
> +}
> +
> +static ulong rk3368_vop_set_clk(struct rk3368_cru *cru, int clk_id, uint hz)
> +{
> +	struct pll_div npll_config = {0};
> +	u32 lcdc_div;
> +	int ret;
> +
> +	switch (clk_id) {
> +	case DCLK_VOP:
> +		if (!(NPLL_HZ % hz)) {
> +			rkclk_set_pll(cru, NPLL, rkclk_get_pll_config(NPLL_HZ));
> +			lcdc_div = NPLL_HZ / hz;
> +		} else {
> +			ret = pll_para_config(hz, &npll_config, &lcdc_div);
> +			if (ret)
> +				return ret;
> +
> +			rkclk_set_pll(cru, NPLL, &npll_config);
> +		}
> +		/* vop dclk source clk: npll,dclk_div: 1 */
> +		rk_clrsetreg(&cru->clksel_con[20],
> +			     (DCLK_VOP_PLL_SEL_MASK << DCLK_VOP_PLL_SEL_SHIFT) |
> +			     (DCLK_VOP_DIV_MASK << DCLK_VOP_DIV_SHIFT),
> +			     (DCLK_VOP_PLL_SEL_NPLL << DCLK_VOP_PLL_SEL_SHIFT) |
> +			     (lcdc_div - 1) << DCLK_VOP_DIV_SHIFT);
> +		break;
> +	case ACLK_VOP:
> +		if ((rkclk_pll_get_rate(cru, CPLL) % hz) == 0) {
> +			lcdc_div = rkclk_pll_get_rate(cru, CPLL) / hz;
> +			rk_clrsetreg(&cru->clksel_con[19],
> +				     (ACLK_VOP_PLL_SEL_MASK <<
> +				     ACLK_VOP_PLL_SEL_SHIFT) |
> +				     (ACLK_VOP_DIV_MASK <<
> +				     ACLK_VOP_DIV_SHIFT),
> +				     (ACLK_VOP_PLL_SEL_CPLL <<
> +				     ACLK_VOP_PLL_SEL_SHIFT) |
> +				     (lcdc_div - 1) <<
> +				     ACLK_VOP_DIV_SHIFT);
> +		} else {
> +			lcdc_div = rkclk_pll_get_rate(cru, GPLL) / hz;
> +			rk_clrsetreg(&cru->clksel_con[19],
> +				     (ACLK_VOP_PLL_SEL_MASK <<
> +				     ACLK_VOP_PLL_SEL_SHIFT) |
> +				     (ACLK_VOP_DIV_MASK <<
> +				     ACLK_VOP_DIV_SHIFT),
> +				     (ACLK_VOP_PLL_SEL_GPLL <<
> +				     ACLK_VOP_PLL_SEL_SHIFT) |
> +				     (lcdc_div - 1) <<
> +				     ACLK_VOP_DIV_SHIFT);
> +		}
> +		break;
> +	case HCLK_VOP:
> +		lcdc_div = rk3368_vop_get_clk(cru, ACLK_VOP) / hz;
> +		rk_clrsetreg(&cru->clksel_con[21],
> +			     HCLK_VOP_DIV_MASK,
> +			     (lcdc_div - 1) << HCLK_VOP_DIV_SHIFT);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return rk3368_vop_get_clk(cru, clk_id);
> +}
>   #endif
>   
>   static ulong rk3368_clk_get_rate(struct clk *clk)
> @@ -540,11 +754,13 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
>   
>   	debug("%s: id %ld\n", __func__, clk->id);
>   	switch (clk->id) {
> +	case PLL_APLLB:
> +	case PLL_APLLL:
> +	case PLL_DPLL:
>   	case PLL_CPLL:
> -		rate = rkclk_pll_get_rate(priv->cru, CPLL);
> -		break;
>   	case PLL_GPLL:
> -		rate = rkclk_pll_get_rate(priv->cru, GPLL);
> +	case PLL_NPLL:
> +		rate = rkclk_pll_get_rate(priv->cru, clk->id - 1);
>   		break;
>   	case SCLK_SPI0 ... SCLK_SPI2:
>   		rate = rk3368_spi_get_clk(priv->cru, clk->id);
> @@ -571,6 +787,13 @@ static ulong rk3368_clk_get_rate(struct clk *clk)
>   	case SCLK_SARADC:
>   		rate = rk3368_saradc_get_clk(priv->cru);
>   		break;
> +#if !IS_ENABLED(CONFIG_XPL_BUILD)
> +	case ACLK_VOP:
> +	case DCLK_VOP:
> +	case HCLK_VOP:
> +		rate = rk3368_vop_get_clk(priv->cru, clk->id);
> +		break;
> +#endif
>   	default:
>   		return -ENOENT;
>   	}
> @@ -617,6 +840,13 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
>   	case SCLK_SARADC:
>   		ret =  rk3368_saradc_set_clk(priv->cru, rate);
>   		break;
> +#if !defined(CONFIG_XPL_BUILD)
> +	case ACLK_VOP:
> +	case DCLK_VOP:
> +	case HCLK_VOP:
> +		ret = rk3368_vop_set_clk(priv->cru, clk->id, rate);
> +		break;
> +#endif
>   	default:
>   		return -ENOENT;
>   	}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/5] video: rockchip: Add bridge support for VOP
  2025-08-14 13:12 ` [PATCH 4/5] video: rockchip: Add bridge support for VOP WeiHao Li
@ 2025-11-03  3:27   ` Chaoyi Chen
  0 siblings, 0 replies; 10+ messages in thread
From: Chaoyi Chen @ 2025-11-03  3:27 UTC (permalink / raw)
  To: WeiHao Li, u-boot
  Cc: trini, sjg, philipp.tomsich, kever.yang, lukma, seanga2,
	ag.dev.uboot, muratdemirtaseu, Andy Yan, Sandy Huang

Hi WeiHao,

On 8/14/2025 9:12 PM, WeiHao Li wrote:
> Rockchip VOP driver only support UCLASS_DISPLAY for now, It can't work
> if SOC use dw-mipi with inno-dphy like RK3368.
>
> This patch try to add UCLASS_VIDEO_BRIDGE support to let it support
> dw-mipi-dsi-rockchip driver, will support SOC use dw-mipi with inno-dphy.
>
> This patch basic same as muratdemirtas's github repository, just adjust
> some code style.
>
> Link: https://github.com/muratdemirtas/rockchip-rk3399-uboot-mipi-dsi
>
> Signed-off-by: muratdemirtas <muratdemirtaseu@outlook.com>
> Signed-off-by: WeiHao Li <cn.liweihao@gmail.com>

The rk_vop.c should implement code related to the VOP controller.  And anything related to panel/backlight should not appear here.

Please refer to rk3288_mipi.c or rk3399_mipi.c.  You can implement a UCLASS_DISPLAY device to access the UCLASS_VIDEO_BRIDGE device.


> ---
>   drivers/video/rockchip/rk_vop.c | 92 +++++++++++++++++++++++++--------
>   1 file changed, 71 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
> index 17dfe62c9..71786da77 100644
> --- a/drivers/video/rockchip/rk_vop.c
> +++ b/drivers/video/rockchip/rk_vop.c
> @@ -14,6 +14,8 @@
>   #include <reset.h>
>   #include <syscon.h>
>   #include <video.h>
> +#include <video_bridge.h>
> +#include <panel.h>
>   #include <asm/global_data.h>
>   #include <asm/gpio.h>
>   #include <asm/io.h>
> @@ -257,6 +259,8 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
>   	ofnode remote;
>   	const char *compat;
>   	struct reset_ctl dclk_rst;
> +	struct udevice *bridge;
> +	struct udevice *panel;
>   
>   	debug("%s(%s, 0x%lx, %s)\n", __func__,
>   	      dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
> @@ -298,6 +302,10 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
>   			return -EINVAL;
>   		}
>   
> +		uclass_find_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote, &bridge);
> +		if (bridge)
> +			break;
> +
>   		uclass_find_device_by_ofnode(UCLASS_DISPLAY, remote, &disp);
>   		if (disp)
>   			break;
> @@ -326,27 +334,60 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
>   	}
>   	debug("vop_id=%d\n", vop_id);
>   
> -	disp_uc_plat = dev_get_uclass_plat(disp);
> -	debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
> -	if (display_in_use(disp)) {
> -		debug("   - device in use\n");
> -		return -EBUSY;
> -	}
> +	if (bridge) {
> +		/* video bridge detected, probe it */
> +		ret = device_probe(bridge);
> +		if (ret) {
> +			debug("%s: device '%s' bridge won't probe (ret=%d)\n",
> +			      __func__, dev->name, ret);
> +			return ret;
> +		}
>   
> -	disp_uc_plat->source_id = remote_vop_id;
> -	disp_uc_plat->src_dev = dev;
> +		/* Attach the DSI controller and the display to the bridge. */
> +		ret = video_bridge_attach(bridge);
> +		if (ret) {
> +			debug("Failed to attach video bridge: %d\n", ret);
> +			return ret;
> +		}
>   
> -	ret = device_probe(disp);
> -	if (ret) {
> -		debug("%s: device '%s' display won't probe (ret=%d)\n",
> -		      __func__, dev->name, ret);
> -		return ret;
> -	}
> +		/*
> +		 * Get the panel device
> +		 * TODO: Maybe fetch it from the bridge private data.
> +		 */
> +		ret = uclass_first_device_err(UCLASS_PANEL, &panel);
> +		if (ret) {
> +			debug("Panel device error: %d\n", ret);
> +			return ret;
> +		}
>   
> -	ret = display_read_timing(disp, &timing);
> -	if (ret) {
> -		debug("%s: Failed to read timings\n", __func__);
> -		return ret;
> +		ret = panel_get_display_timing(panel, &timing);
> +		if (ret) {
> +			debug("%s: Failed to read timings\n", __func__);
> +			return ret;
> +		}
> +	} else {
> +		disp_uc_plat = dev_get_uclass_plat(disp);
> +		debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
> +		if (display_in_use(disp)) {
> +			debug("   - device in use\n");
> +			return -EBUSY;
> +		}
> +
> +		disp_uc_plat->source_id = remote_vop_id;
> +		disp_uc_plat->src_dev = dev;
> +
> +		ret = device_probe(disp);
> +		if (ret) {
> +			debug("%s: device '%s' display won't probe (ret=%d)\n",
> +			      __func__, dev->name, ret);
> +			return ret;
> +		}
> +
> +		ret = display_read_timing(disp, &timing);
> +		if (ret) {
> +			debug("%s: Failed to read timings\n", __func__);
> +			return ret;
> +		}
>   	}
>   
>   	ret = clk_get_by_index(dev, 1, &clk);
> @@ -383,9 +424,18 @@ static int rk_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
>   
>   	rkvop_enable(dev, fbbase, 1 << l2bpp, &timing, &dclk_rst);
>   
> -	ret = display_enable(disp, 1 << l2bpp, &timing);
> -	if (ret)
> -		return ret;
> +	if (bridge) {
> +		/* Attach the DSI controller and the display to the bridge. */
> +		ret = video_bridge_set_backlight(bridge, 80);
> +		if (ret) {
> +			printf("Failed to start the video bridge: %d\n", ret);
> +			return ret;
> +		}
> +	} else {
> +		ret = display_enable(disp, 1 << l2bpp, &timing);
> +		if (ret)
> +			return ret;
> +	}
>   
>   	uc_priv->xsize = timing.hactive.typ;
>   	uc_priv->ysize = timing.vactive.typ;

-- 
Best,
Chaoyi


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-11-03 13:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 13:12 [PATCH 0/5] Rockchip RK3368 drivers improve WeiHao Li
2025-08-14 13:12 ` [PATCH 1/5] clk: rockchip: rk3368: Add bus clk get/set WeiHao Li
2025-11-02  0:50   ` Kever Yang
2025-08-14 13:12 ` [PATCH 2/5] clk: rockchip: rk3368: add SCLK for mmc clock get/set WeiHao Li
2025-11-02  0:50   ` Kever Yang
2025-08-14 13:12 ` [PATCH 3/5] clk: rockchip: rk3368: Add VOP " WeiHao Li
2025-11-02  0:51   ` Kever Yang
2025-08-14 13:12 ` [PATCH 4/5] video: rockchip: Add bridge support for VOP WeiHao Li
2025-11-03  3:27   ` Chaoyi Chen
2025-08-14 13:12 ` [PATCH 5/5] video: rockchip: add RK3368 VOP support WeiHao Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox