mirror of
https://github.com/Heleguo/lede.git
synced 2025-12-16 19:01:32 +00:00
rockchip: backport RK3576/RK3588 drm/vop2 support for 6.12
This commit is contained in:
parent
2cac64c0bc
commit
e9fd6ec3f6
@ -0,0 +1,69 @@
|
||||
From a6ba2dad0aa4f623ab0def8b6e6888ac00639055 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko@sntech.de>
|
||||
Date: Fri, 21 Feb 2025 00:41:40 +0100
|
||||
Subject: [PATCH] drivers: base: component: add function to query the bound
|
||||
status
|
||||
|
||||
The component helpers already expose the bound status in debugfs, but at
|
||||
times it might be necessary to also check that state in the kernel and
|
||||
act differently depending on the result.
|
||||
|
||||
For example the shutdown handler of a drm-driver might need to stop
|
||||
a whole output pipeline if the drm device is up and running, but may
|
||||
run into problems if that drm-device has never been set up before,
|
||||
for example because the binding deferred.
|
||||
|
||||
So add a little helper that returns the bound status for a componet
|
||||
device.
|
||||
|
||||
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250220234141.2788785-2-heiko@sntech.de
|
||||
---
|
||||
drivers/base/component.c | 14 ++++++++++++++
|
||||
include/linux/component.h | 4 +++-
|
||||
2 files changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/base/component.c
|
||||
+++ b/drivers/base/component.c
|
||||
@@ -569,6 +569,20 @@ void component_master_del(struct device
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(component_master_del);
|
||||
|
||||
+bool component_master_is_bound(struct device *parent,
|
||||
+ const struct component_master_ops *ops)
|
||||
+{
|
||||
+ struct aggregate_device *adev;
|
||||
+
|
||||
+ guard(mutex)(&component_mutex);
|
||||
+ adev = __aggregate_find(parent, ops);
|
||||
+ if (!adev)
|
||||
+ return 0;
|
||||
+
|
||||
+ return adev->bound;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(component_master_is_bound);
|
||||
+
|
||||
static void component_unbind(struct component *component,
|
||||
struct aggregate_device *adev, void *data)
|
||||
{
|
||||
--- a/include/linux/component.h
|
||||
+++ b/include/linux/component.h
|
||||
@@ -3,7 +3,7 @@
|
||||
#define COMPONENT_H
|
||||
|
||||
#include <linux/stddef.h>
|
||||
-
|
||||
+#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
|
||||
@@ -90,6 +90,8 @@ int component_compare_dev_name(struct de
|
||||
|
||||
void component_master_del(struct device *,
|
||||
const struct component_master_ops *);
|
||||
+bool component_master_is_bound(struct device *parent,
|
||||
+ const struct component_master_ops *ops);
|
||||
|
||||
struct component_match;
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
From f2dbca169790ea1e436ffdd9ef37d7c3a4401c46 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Fri, 20 Sep 2024 17:36:28 +0800
|
||||
Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Don't request
|
||||
RST_PHY/RST_ROPLL/RST_LCPLL
|
||||
|
||||
RST_PHY/RST_ROPLL/RST_LCPLL are used for debug only on rk3588,
|
||||
and they are not exported on rk3576, no need to request it in
|
||||
driver.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20240920093629.7410-1-andyshrk@163.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 17 +----------------
|
||||
1 file changed, 1 insertion(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -257,13 +257,10 @@ struct ropll_config {
|
||||
};
|
||||
|
||||
enum rk_hdptx_reset {
|
||||
- RST_PHY = 0,
|
||||
- RST_APB,
|
||||
+ RST_APB = 0,
|
||||
RST_INIT,
|
||||
RST_CMN,
|
||||
RST_LANE,
|
||||
- RST_ROPLL,
|
||||
- RST_LCPLL,
|
||||
RST_MAX
|
||||
};
|
||||
|
||||
@@ -679,11 +676,6 @@ static void rk_hdptx_phy_disable(struct
|
||||
{
|
||||
u32 val;
|
||||
|
||||
- /* reset phy and apb, or phy locked flag may keep 1 */
|
||||
- reset_control_assert(hdptx->rsts[RST_PHY].rstc);
|
||||
- usleep_range(20, 30);
|
||||
- reset_control_deassert(hdptx->rsts[RST_PHY].rstc);
|
||||
-
|
||||
reset_control_assert(hdptx->rsts[RST_APB].rstc);
|
||||
usleep_range(20, 30);
|
||||
reset_control_deassert(hdptx->rsts[RST_APB].rstc);
|
||||
@@ -804,10 +796,6 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
|
||||
rk_hdptx_pre_power_up(hdptx);
|
||||
|
||||
- reset_control_assert(hdptx->rsts[RST_ROPLL].rstc);
|
||||
- usleep_range(20, 30);
|
||||
- reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc);
|
||||
-
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq);
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq);
|
||||
|
||||
@@ -1130,13 +1118,10 @@ static int rk_hdptx_phy_probe(struct pla
|
||||
return dev_err_probe(dev, PTR_ERR(hdptx->regmap),
|
||||
"Failed to init regmap\n");
|
||||
|
||||
- hdptx->rsts[RST_PHY].id = "phy";
|
||||
hdptx->rsts[RST_APB].id = "apb";
|
||||
hdptx->rsts[RST_INIT].id = "init";
|
||||
hdptx->rsts[RST_CMN].id = "cmn";
|
||||
hdptx->rsts[RST_LANE].id = "lane";
|
||||
- hdptx->rsts[RST_ROPLL].id = "ropll";
|
||||
- hdptx->rsts[RST_LCPLL].id = "lcpll";
|
||||
|
||||
ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts);
|
||||
if (ret)
|
||||
@ -0,0 +1,42 @@
|
||||
From c8f7d65cac565cacf0420acf8b54c855dd7b4484 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Date: Fri, 6 Dec 2024 11:34:00 +0100
|
||||
Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: annotate regmap
|
||||
register-callback
|
||||
|
||||
The variant of the driver in the vendor-tree contained those handy
|
||||
comments in the regmap register callback. Having the different ranges
|
||||
describe what they are looks helpful.
|
||||
|
||||
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20241206103401.1780416-2-heiko@sntech.de
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -574,13 +574,13 @@ static const struct reg_sequence rk_hdtp
|
||||
static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
- case 0x0000 ... 0x029c:
|
||||
- case 0x0400 ... 0x04a4:
|
||||
- case 0x0800 ... 0x08a4:
|
||||
- case 0x0c00 ... 0x0cb4:
|
||||
- case 0x1000 ... 0x10b4:
|
||||
- case 0x1400 ... 0x14b4:
|
||||
- case 0x1800 ... 0x18b4:
|
||||
+ case 0x0000 ... 0x029c: /* CMN Register */
|
||||
+ case 0x0400 ... 0x04a4: /* Sideband Register */
|
||||
+ case 0x0800 ... 0x08a4: /* Lane Top Register */
|
||||
+ case 0x0c00 ... 0x0cb4: /* Lane 0 Register */
|
||||
+ case 0x1000 ... 0x10b4: /* Lane 1 Register */
|
||||
+ case 0x1400 ... 0x14b4: /* Lane 2 Register */
|
||||
+ case 0x1800 ... 0x18b4: /* Lane 3 Register */
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
From f706024107204cb0b640bac35ea47e7b91b8c71f Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 18:51:55 +0800
|
||||
Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Supplement some register
|
||||
names with their full version
|
||||
|
||||
Complete the register names of CMN_REG(0081) and CMN_REG(0087) to their
|
||||
full version, and it can help to better match the datasheet.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Link: https://lore.kernel.org/r/20250205105157.580060-3-damon.ding@rock-chips.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -82,14 +82,14 @@
|
||||
#define ROPLL_SSC_EN BIT(0)
|
||||
/* CMN_REG(0081) */
|
||||
#define OVRD_PLL_CD_CLK_EN BIT(8)
|
||||
-#define PLL_CD_HSCLK_EAST_EN BIT(0)
|
||||
+#define ANA_PLL_CD_HSCLK_EAST_EN BIT(0)
|
||||
/* CMN_REG(0086) */
|
||||
#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4)
|
||||
#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1)
|
||||
#define PLL_PCG_CLK_EN BIT(0)
|
||||
/* CMN_REG(0087) */
|
||||
-#define PLL_FRL_MODE_EN BIT(3)
|
||||
-#define PLL_TX_HS_CLK_EN BIT(2)
|
||||
+#define ANA_PLL_FRL_MODE_EN BIT(3)
|
||||
+#define ANA_PLL_TX_HS_CLK_EN BIT(2)
|
||||
/* CMN_REG(0089) */
|
||||
#define LCPLL_ALONE_MODE BIT(1)
|
||||
/* CMN_REG(0097) */
|
||||
@ -0,0 +1,170 @@
|
||||
From 2dc8224e3758c5d6387786ea1d74d2d510149b1a Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Wed, 5 Feb 2025 18:51:56 +0800
|
||||
Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Add the '_MASK' suffix to
|
||||
all registers
|
||||
|
||||
Adding the '_MASK' suffix to all registers in order to ensures consistency
|
||||
in the naming convention for register macros throughout the file.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Link: https://lore.kernel.org/r/20250205105157.580060-4-damon.ding@rock-chips.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 88 +++++++++----------
|
||||
1 file changed, 44 insertions(+), 44 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -50,60 +50,60 @@
|
||||
#define LCPLL_PI_EN_MASK BIT(5)
|
||||
#define LCPLL_100M_CLK_EN_MASK BIT(0)
|
||||
/* CMN_REG(0025) */
|
||||
-#define LCPLL_PMS_IQDIV_RSTN BIT(4)
|
||||
+#define LCPLL_PMS_IQDIV_RSTN_MASK BIT(4)
|
||||
/* CMN_REG(0028) */
|
||||
-#define LCPLL_SDC_FRAC_EN BIT(2)
|
||||
-#define LCPLL_SDC_FRAC_RSTN BIT(0)
|
||||
+#define LCPLL_SDC_FRAC_EN_MASK BIT(2)
|
||||
+#define LCPLL_SDC_FRAC_RSTN_MASK BIT(0)
|
||||
/* CMN_REG(002d) */
|
||||
#define LCPLL_SDC_N_MASK GENMASK(3, 1)
|
||||
/* CMN_REG(002e) */
|
||||
#define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0)
|
||||
/* CMN_REG(002f) */
|
||||
#define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2)
|
||||
-#define LCPLL_SDC_NDIV_RSTN BIT(0)
|
||||
+#define LCPLL_SDC_NDIV_RSTN_MASK BIT(0)
|
||||
/* CMN_REG(003d) */
|
||||
-#define ROPLL_LCVCO_EN BIT(4)
|
||||
+#define ROPLL_LCVCO_EN_MASK BIT(4)
|
||||
/* CMN_REG(004e) */
|
||||
-#define ROPLL_PI_EN BIT(5)
|
||||
+#define ROPLL_PI_EN_MASK BIT(5)
|
||||
/* CMN_REG(005c) */
|
||||
-#define ROPLL_PMS_IQDIV_RSTN BIT(5)
|
||||
+#define ROPLL_PMS_IQDIV_RSTN_MASK BIT(5)
|
||||
/* CMN_REG(005e) */
|
||||
#define ROPLL_SDM_EN_MASK BIT(6)
|
||||
-#define ROPLL_SDM_FRAC_EN_RBR BIT(3)
|
||||
-#define ROPLL_SDM_FRAC_EN_HBR BIT(2)
|
||||
-#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1)
|
||||
-#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0)
|
||||
+#define ROPLL_SDC_FRAC_EN_RBR_MASK BIT(3)
|
||||
+#define ROPLL_SDC_FRAC_EN_HBR_MASK BIT(2)
|
||||
+#define ROPLL_SDC_FRAC_EN_HBR2_MASK BIT(1)
|
||||
+#define ROPLL_SDM_FRAC_EN_HBR3_MASK BIT(0)
|
||||
/* CMN_REG(0064) */
|
||||
#define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3)
|
||||
/* CMN_REG(0069) */
|
||||
#define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0)
|
||||
/* CMN_REG(0074) */
|
||||
-#define ROPLL_SDC_NDIV_RSTN BIT(2)
|
||||
-#define ROPLL_SSC_EN BIT(0)
|
||||
+#define ROPLL_SDC_NDIV_RSTN_MASK BIT(2)
|
||||
+#define ROPLL_SSC_EN_MASK BIT(0)
|
||||
/* CMN_REG(0081) */
|
||||
-#define OVRD_PLL_CD_CLK_EN BIT(8)
|
||||
-#define ANA_PLL_CD_HSCLK_EAST_EN BIT(0)
|
||||
+#define OVRD_PLL_CD_CLK_EN_MASK BIT(8)
|
||||
+#define ANA_PLL_CD_HSCLK_EAST_EN_MASK BIT(0)
|
||||
/* CMN_REG(0086) */
|
||||
#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4)
|
||||
#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1)
|
||||
-#define PLL_PCG_CLK_EN BIT(0)
|
||||
+#define PLL_PCG_CLK_EN_MASK BIT(0)
|
||||
/* CMN_REG(0087) */
|
||||
-#define ANA_PLL_FRL_MODE_EN BIT(3)
|
||||
-#define ANA_PLL_TX_HS_CLK_EN BIT(2)
|
||||
+#define ANA_PLL_FRL_MODE_EN_MASK BIT(3)
|
||||
+#define ANA_PLL_TX_HS_CLK_EN_MASK BIT(2)
|
||||
/* CMN_REG(0089) */
|
||||
-#define LCPLL_ALONE_MODE BIT(1)
|
||||
+#define LCPLL_ALONE_MODE_MASK BIT(1)
|
||||
/* CMN_REG(0097) */
|
||||
-#define DIG_CLK_SEL BIT(1)
|
||||
+#define DIG_CLK_SEL_MASK BIT(1)
|
||||
#define LCPLL_REF BIT(1)
|
||||
#define ROPLL_REF 0
|
||||
/* CMN_REG(0099) */
|
||||
-#define CMN_ROPLL_ALONE_MODE BIT(2)
|
||||
+#define CMN_ROPLL_ALONE_MODE_MASK BIT(2)
|
||||
#define ROPLL_ALONE_MODE BIT(2)
|
||||
/* CMN_REG(009a) */
|
||||
-#define HS_SPEED_SEL BIT(0)
|
||||
+#define HS_SPEED_SEL_MASK BIT(0)
|
||||
#define DIV_10_CLOCK BIT(0)
|
||||
/* CMN_REG(009b) */
|
||||
-#define IS_SPEED_SEL BIT(4)
|
||||
+#define LS_SPEED_SEL_MASK BIT(4)
|
||||
#define LINK_SYMBOL_CLOCK BIT(4)
|
||||
#define LINK_SYMBOL_CLOCK1_2 0
|
||||
|
||||
@@ -161,36 +161,36 @@
|
||||
#define SB_READY_MASK BIT(4)
|
||||
|
||||
/* LNTOP_REG(0200) */
|
||||
-#define PROTOCOL_SEL BIT(2)
|
||||
+#define PROTOCOL_SEL_MASK BIT(2)
|
||||
#define HDMI_MODE BIT(2)
|
||||
#define HDMI_TMDS_FRL_SEL BIT(1)
|
||||
/* LNTOP_REG(0206) */
|
||||
-#define DATA_BUS_SEL BIT(0)
|
||||
+#define DATA_BUS_WIDTH_SEL_MASK BIT(0)
|
||||
#define DATA_BUS_36_40 BIT(0)
|
||||
/* LNTOP_REG(0207) */
|
||||
-#define LANE_EN 0xf
|
||||
+#define LANE_EN_MASK 0xf
|
||||
#define ALL_LANE_EN 0xf
|
||||
|
||||
/* LANE_REG(0312) */
|
||||
-#define LN0_TX_SER_RATE_SEL_RBR BIT(5)
|
||||
-#define LN0_TX_SER_RATE_SEL_HBR BIT(4)
|
||||
-#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3)
|
||||
-#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2)
|
||||
+#define LN0_TX_SER_RATE_SEL_RBR_MASK BIT(5)
|
||||
+#define LN0_TX_SER_RATE_SEL_HBR_MASK BIT(4)
|
||||
+#define LN0_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
|
||||
+#define LN0_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
|
||||
/* LANE_REG(0412) */
|
||||
-#define LN1_TX_SER_RATE_SEL_RBR BIT(5)
|
||||
-#define LN1_TX_SER_RATE_SEL_HBR BIT(4)
|
||||
-#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3)
|
||||
-#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2)
|
||||
+#define LN1_TX_SER_RATE_SEL_RBR_MASK BIT(5)
|
||||
+#define LN1_TX_SER_RATE_SEL_HBR_MASK BIT(4)
|
||||
+#define LN1_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
|
||||
+#define LN1_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
|
||||
/* LANE_REG(0512) */
|
||||
-#define LN2_TX_SER_RATE_SEL_RBR BIT(5)
|
||||
-#define LN2_TX_SER_RATE_SEL_HBR BIT(4)
|
||||
-#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3)
|
||||
-#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2)
|
||||
+#define LN2_TX_SER_RATE_SEL_RBR_MASK BIT(5)
|
||||
+#define LN2_TX_SER_RATE_SEL_HBR_MASK BIT(4)
|
||||
+#define LN2_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
|
||||
+#define LN2_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
|
||||
/* LANE_REG(0612) */
|
||||
-#define LN3_TX_SER_RATE_SEL_RBR BIT(5)
|
||||
-#define LN3_TX_SER_RATE_SEL_HBR BIT(4)
|
||||
-#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3)
|
||||
-#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2)
|
||||
+#define LN3_TX_SER_RATE_SEL_RBR_MASK BIT(5)
|
||||
+#define LN3_TX_SER_RATE_SEL_HBR_MASK BIT(4)
|
||||
+#define LN3_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
|
||||
+#define LN3_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
|
||||
|
||||
#define HDMI14_MAX_RATE 340000000
|
||||
#define HDMI20_MAX_RATE 600000000
|
||||
@@ -825,8 +825,8 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
|
||||
FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
|
||||
|
||||
- regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN,
|
||||
- PLL_PCG_CLK_EN);
|
||||
+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
|
||||
+ FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
|
||||
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
From 4a8463ae8d871ccd491d48a371a6789eb7378243 Mon Sep 17 00:00:00 2001
|
||||
From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Date: Thu, 6 Mar 2025 20:29:23 +0100
|
||||
Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Add support for RK3576
|
||||
|
||||
Despite the compatible already being listed in the bindings, the PHY
|
||||
driver never gained explicit support for it. This is especially a
|
||||
problem because the explicitly listed PHY addresses need to be specified
|
||||
for each SoC.
|
||||
|
||||
To solve this, add the compatible, and a PHY config, with the address
|
||||
gleaned from rk3576.dtsi.
|
||||
|
||||
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250306-rk3576-hdptx-phy-v1-1-288cc4b0611a@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -2022,6 +2022,13 @@ static const struct dev_pm_ops rk_hdptx_
|
||||
rk_hdptx_phy_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
+static const struct rk_hdptx_phy_cfg rk3576_hdptx_phy_cfgs = {
|
||||
+ .num_phys = 1,
|
||||
+ .phy_ids = {
|
||||
+ 0x2b000000,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct rk_hdptx_phy_cfg rk3588_hdptx_phy_cfgs = {
|
||||
.num_phys = 2,
|
||||
.phy_ids = {
|
||||
@@ -2032,6 +2039,10 @@ static const struct rk_hdptx_phy_cfg rk3
|
||||
|
||||
static const struct of_device_id rk_hdptx_phy_of_match[] = {
|
||||
{
|
||||
+ .compatible = "rockchip,rk3576-hdptx-phy",
|
||||
+ .data = &rk3576_hdptx_phy_cfgs
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "rockchip,rk3588-hdptx-phy",
|
||||
.data = &rk3588_hdptx_phy_cfgs
|
||||
},
|
||||
@ -0,0 +1,83 @@
|
||||
From 10ed34d6eaaf86e301a8f2dd190d26dfbc9799bd Mon Sep 17 00:00:00 2001
|
||||
From: Sandor Yu <Sandor.yu@nxp.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:35 +0200
|
||||
Subject: [PATCH] phy: Add HDMI configuration options
|
||||
|
||||
Allow HDMI PHYs to be configured through the generic
|
||||
functions through a custom structure added to the generic union.
|
||||
|
||||
The parameters added here are based on HDMI PHY
|
||||
implementation practices. The current set of parameters
|
||||
should cover the potential users.
|
||||
|
||||
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Reviewed-by: Maxime Ripard <mripard@kernel.org>
|
||||
Acked-by: Vinod Koul <vkoul@kernel.org>
|
||||
Link: https://lore.kernel.org/r/d1cff6c03ec3732d2244022029245ab2d954d997.1734340233.git.Sandor.yu@nxp.com
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-1-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
include/linux/phy/phy-hdmi.h | 19 +++++++++++++++++++
|
||||
include/linux/phy/phy.h | 7 ++++++-
|
||||
2 files changed, 25 insertions(+), 1 deletion(-)
|
||||
create mode 100644 include/linux/phy/phy-hdmi.h
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/linux/phy/phy-hdmi.h
|
||||
@@ -0,0 +1,19 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+/*
|
||||
+ * Copyright 2022,2024 NXP
|
||||
+ */
|
||||
+
|
||||
+#ifndef __PHY_HDMI_H_
|
||||
+#define __PHY_HDMI_H_
|
||||
+
|
||||
+/**
|
||||
+ * struct phy_configure_opts_hdmi - HDMI configuration set
|
||||
+ * @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
|
||||
+ *
|
||||
+ * This structure is used to represent the configuration state of a HDMI phy.
|
||||
+ */
|
||||
+struct phy_configure_opts_hdmi {
|
||||
+ unsigned long long tmds_char_rate;
|
||||
+};
|
||||
+
|
||||
+#endif /* __PHY_HDMI_H_ */
|
||||
--- a/include/linux/phy/phy.h
|
||||
+++ b/include/linux/phy/phy.h
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/phy/phy-dp.h>
|
||||
+#include <linux/phy/phy-hdmi.h>
|
||||
#include <linux/phy/phy-lvds.h>
|
||||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
|
||||
@@ -42,7 +43,8 @@ enum phy_mode {
|
||||
PHY_MODE_MIPI_DPHY,
|
||||
PHY_MODE_SATA,
|
||||
PHY_MODE_LVDS,
|
||||
- PHY_MODE_DP
|
||||
+ PHY_MODE_DP,
|
||||
+ PHY_MODE_HDMI,
|
||||
};
|
||||
|
||||
enum phy_media {
|
||||
@@ -60,11 +62,14 @@ enum phy_media {
|
||||
* the DisplayPort protocol.
|
||||
* @lvds: Configuration set applicable for phys supporting
|
||||
* the LVDS phy mode.
|
||||
+ * @hdmi: Configuration set applicable for phys supporting
|
||||
+ * the HDMI phy mode.
|
||||
*/
|
||||
union phy_configure_opts {
|
||||
struct phy_configure_opts_mipi_dphy mipi_dphy;
|
||||
struct phy_configure_opts_dp dp;
|
||||
struct phy_configure_opts_lvds lvds;
|
||||
+ struct phy_configure_opts_hdmi hdmi;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -0,0 +1,33 @@
|
||||
From 3bb9286f4ece6acbc1fbaa9f192a82645d30efbf Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:36 +0200
|
||||
Subject: [PATCH] phy: hdmi: Add color depth configuration
|
||||
|
||||
Extend the HDMI configuration options to allow managing bits per color
|
||||
channel. This is required by some PHY drivers such as
|
||||
rockchip-samsung-hdptx.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-2-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
include/linux/phy/phy-hdmi.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/include/linux/phy/phy-hdmi.h
|
||||
+++ b/include/linux/phy/phy-hdmi.h
|
||||
@@ -9,11 +9,13 @@
|
||||
/**
|
||||
* struct phy_configure_opts_hdmi - HDMI configuration set
|
||||
* @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
|
||||
+ * @bpc: Bits per color channel.
|
||||
*
|
||||
* This structure is used to represent the configuration state of a HDMI phy.
|
||||
*/
|
||||
struct phy_configure_opts_hdmi {
|
||||
unsigned long long tmds_char_rate;
|
||||
+ unsigned int bpc;
|
||||
};
|
||||
|
||||
#endif /* __PHY_HDMI_H_ */
|
||||
@ -0,0 +1,56 @@
|
||||
From 6218c3fd6702a5bc4ab323fed25714cde127684c Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:39 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop unused struct lcpll_config
|
||||
|
||||
This is just a leftover from downstream support for HDMI 2.1.
|
||||
Remove the unused struct for now.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-5-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 31 -------------------
|
||||
1 file changed, 31 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -329,37 +329,6 @@ enum dp_link_rate {
|
||||
DP_BW_HBR2,
|
||||
};
|
||||
|
||||
-struct lcpll_config {
|
||||
- u32 bit_rate;
|
||||
- u8 lcvco_mode_en;
|
||||
- u8 pi_en;
|
||||
- u8 clk_en_100m;
|
||||
- u8 pms_mdiv;
|
||||
- u8 pms_mdiv_afc;
|
||||
- u8 pms_pdiv;
|
||||
- u8 pms_refdiv;
|
||||
- u8 pms_sdiv;
|
||||
- u8 pi_cdiv_rstn;
|
||||
- u8 pi_cdiv_sel;
|
||||
- u8 sdm_en;
|
||||
- u8 sdm_rstn;
|
||||
- u8 sdc_frac_en;
|
||||
- u8 sdc_rstn;
|
||||
- u8 sdm_deno;
|
||||
- u8 sdm_num_sign;
|
||||
- u8 sdm_num;
|
||||
- u8 sdc_n;
|
||||
- u8 sdc_n2;
|
||||
- u8 sdc_num;
|
||||
- u8 sdc_deno;
|
||||
- u8 sdc_ndiv_rstn;
|
||||
- u8 ssc_en;
|
||||
- u8 ssc_fm_dev;
|
||||
- u8 ssc_fm_freq;
|
||||
- u8 ssc_clk_div_sel;
|
||||
- u8 cd_tx_ser_rate_sel;
|
||||
-};
|
||||
-
|
||||
struct ropll_config {
|
||||
u32 bit_rate;
|
||||
u8 pms_mdiv;
|
||||
@ -0,0 +1,26 @@
|
||||
From bcd61d182618c6a77d0841fcdc3333e125725360 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:40 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop unused phy_cfg driver data
|
||||
|
||||
There is no usage of phy_cfg in the upstream driver data, nor in the
|
||||
downstream one, hence remove it.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-6-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -397,7 +397,6 @@ struct rk_hdptx_phy {
|
||||
int phy_id;
|
||||
|
||||
struct phy *phy;
|
||||
- struct phy_config *phy_cfg;
|
||||
struct clk_bulk_data *clks;
|
||||
int nr_clks;
|
||||
struct reset_control_bulk_data rsts[RST_MAX];
|
||||
@ -0,0 +1,61 @@
|
||||
From bacf2fe750dab6bc7ed50556aaadd3ab107fc643 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:41 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop superfluous cfgs driver
|
||||
data
|
||||
|
||||
The ->cfgs member has been introduced via commit f08d1c085638 ("phy:
|
||||
phy-rockchip-samsung-hdptx: Don't use dt aliases to determine phy-id"),
|
||||
but it is only used during probe() in order to setup ->phy_id.
|
||||
|
||||
Use a probe() local variable to store device match data and remove the
|
||||
now unnecessary member from struct rk_hdptx_phy.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-7-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 12 +++++-------
|
||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -392,10 +392,7 @@ struct rk_hdptx_phy {
|
||||
struct regmap *regmap;
|
||||
struct regmap *grf;
|
||||
|
||||
- /* PHY const config */
|
||||
- const struct rk_hdptx_phy_cfg *cfgs;
|
||||
int phy_id;
|
||||
-
|
||||
struct phy *phy;
|
||||
struct clk_bulk_data *clks;
|
||||
int nr_clks;
|
||||
@@ -1896,6 +1893,7 @@ static int rk_hdptx_phy_runtime_resume(s
|
||||
|
||||
static int rk_hdptx_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
+ const struct rk_hdptx_phy_cfg *cfgs;
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk_hdptx_phy *hdptx;
|
||||
@@ -1914,14 +1912,14 @@ static int rk_hdptx_phy_probe(struct pla
|
||||
return dev_err_probe(dev, PTR_ERR(regs),
|
||||
"Failed to ioremap resource\n");
|
||||
|
||||
- hdptx->cfgs = device_get_match_data(dev);
|
||||
- if (!hdptx->cfgs)
|
||||
+ cfgs = device_get_match_data(dev);
|
||||
+ if (!cfgs)
|
||||
return dev_err_probe(dev, -EINVAL, "missing match data\n");
|
||||
|
||||
/* find the phy-id from the io address */
|
||||
hdptx->phy_id = -ENODEV;
|
||||
- for (id = 0; id < hdptx->cfgs->num_phys; id++) {
|
||||
- if (res->start == hdptx->cfgs->phy_ids[id]) {
|
||||
+ for (id = 0; id < cfgs->num_phys; id++) {
|
||||
+ if (res->start == cfgs->phy_ids[id]) {
|
||||
hdptx->phy_id = id;
|
||||
break;
|
||||
}
|
||||
@ -0,0 +1,240 @@
|
||||
From 0edf9d2bb9b4ba7566dfdc7605883e04575129d9 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:42 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Avoid Hz<->hHz unit conversion
|
||||
overhead
|
||||
|
||||
The ropll_tmds_cfg table used to identify the configuration params for
|
||||
the supported rates expects the search key, i.e. bit_rate member of
|
||||
struct ropll_config, to be provided in hHz rather than Hz (1 hHz = 100
|
||||
Hz). This requires multiple conversions between these units being
|
||||
performed at runtime.
|
||||
|
||||
Improve implementation clarity and efficiency by consistently using the
|
||||
Hz unit throughout driver's internal data structures and functions.
|
||||
Also rename the rather misleading struct member.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-8-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 79 +++++++++----------
|
||||
1 file changed, 39 insertions(+), 40 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -330,7 +330,7 @@ enum dp_link_rate {
|
||||
};
|
||||
|
||||
struct ropll_config {
|
||||
- u32 bit_rate;
|
||||
+ unsigned long long rate;
|
||||
u8 pms_mdiv;
|
||||
u8 pms_mdiv_afc;
|
||||
u8 pms_pdiv;
|
||||
@@ -410,47 +410,47 @@ struct rk_hdptx_phy {
|
||||
};
|
||||
|
||||
static const struct ropll_config ropll_tmds_cfg[] = {
|
||||
- { 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
|
||||
+ { 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1540000, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
|
||||
+ { 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
|
||||
+ { 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
|
||||
0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1462500, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
|
||||
+ { 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1190000, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
|
||||
+ { 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
|
||||
+ { 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
+ { 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 855000, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
|
||||
+ { 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
|
||||
+ { 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
+ { 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
|
||||
+ { 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 502500, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
|
||||
+ { 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
|
||||
4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
|
||||
+ { 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
|
||||
1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
+ { 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
+ { 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
- { 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
|
||||
+ { 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
};
|
||||
|
||||
@@ -896,10 +896,10 @@ static void rk_hdptx_phy_disable(struct
|
||||
regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
|
||||
}
|
||||
|
||||
-static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate,
|
||||
+static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate,
|
||||
struct ropll_config *cfg)
|
||||
{
|
||||
- const unsigned int fout = data_rate / 2, fref = 24000;
|
||||
+ const unsigned int fout = div_u64(rate, 200), fref = 24000;
|
||||
unsigned long k = 0, lc, k_sub, lc_sub;
|
||||
unsigned int fvco, sdc;
|
||||
u32 mdiv, sdiv, n = 8;
|
||||
@@ -969,14 +969,14 @@ static bool rk_hdptx_phy_clk_pll_calc(un
|
||||
}
|
||||
|
||||
static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned int rate)
|
||||
+ unsigned long long rate)
|
||||
{
|
||||
const struct ropll_config *cfg = NULL;
|
||||
struct ropll_config rc = {0};
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
- if (rate == ropll_tmds_cfg[i].bit_rate) {
|
||||
+ if (rate == ropll_tmds_cfg[i].rate) {
|
||||
cfg = &ropll_tmds_cfg[i];
|
||||
break;
|
||||
}
|
||||
@@ -990,8 +990,8 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
}
|
||||
}
|
||||
|
||||
- dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u, sdm_en=%u, k_sign=%u, k=%u, lc=%u\n",
|
||||
- cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en,
|
||||
+ dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n",
|
||||
+ __func__, rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en,
|
||||
cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
|
||||
|
||||
rk_hdptx_pre_power_up(hdptx);
|
||||
@@ -1030,19 +1030,19 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
- hdptx->rate = rate * 100;
|
||||
+ hdptx->rate = rate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned int rate)
|
||||
+ unsigned long long rate)
|
||||
{
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
|
||||
|
||||
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
|
||||
|
||||
- if (rate > HDMI14_MAX_RATE / 100) {
|
||||
+ if (rate > HDMI14_MAX_RATE) {
|
||||
/* For 1/40 bitrate clk */
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
|
||||
} else {
|
||||
@@ -1095,7 +1095,7 @@ static void rk_hdptx_dp_reset(struct rk_
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned int rate)
|
||||
+ unsigned long long rate)
|
||||
{
|
||||
enum phy_mode mode = phy_get_mode(hdptx->phy);
|
||||
u32 status;
|
||||
@@ -1413,8 +1413,8 @@ static int rk_hdptx_dp_aux_init(struct r
|
||||
static int rk_hdptx_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
|
||||
- int bus_width = phy_get_bus_width(hdptx->phy);
|
||||
enum phy_mode mode = phy_get_mode(phy);
|
||||
+ unsigned long long rate;
|
||||
int ret, lane;
|
||||
|
||||
/*
|
||||
@@ -1422,10 +1422,10 @@ static int rk_hdptx_phy_power_on(struct
|
||||
* from the HDMI bridge driver until phy_configure_opts_hdmi
|
||||
* becomes available in the PHY API.
|
||||
*/
|
||||
- unsigned int rate = bus_width & 0xfffffff;
|
||||
+ rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
|
||||
+ rate *= 100;
|
||||
|
||||
- dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n",
|
||||
- __func__, bus_width, rate);
|
||||
+ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, rate);
|
||||
|
||||
ret = rk_hdptx_phy_consumer_get(hdptx, rate);
|
||||
if (ret)
|
||||
@@ -1787,7 +1787,7 @@ static int rk_hdptx_phy_clk_prepare(stru
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100);
|
||||
+ return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate);
|
||||
}
|
||||
|
||||
static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
|
||||
@@ -1808,18 +1808,17 @@ static unsigned long rk_hdptx_phy_clk_re
|
||||
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
- u32 bit_rate = rate / 100;
|
||||
int i;
|
||||
|
||||
if (rate > HDMI20_MAX_RATE)
|
||||
return rate;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
- if (bit_rate == ropll_tmds_cfg[i].bit_rate)
|
||||
+ if (rate == ropll_tmds_cfg[i].rate)
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
|
||||
- !rk_hdptx_phy_clk_pll_calc(bit_rate, NULL))
|
||||
+ !rk_hdptx_phy_clk_pll_calc(rate, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
return rate;
|
||||
@@ -1830,7 +1829,7 @@ static int rk_hdptx_phy_clk_set_rate(str
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100);
|
||||
+ return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops hdptx_phy_clk_ops = {
|
||||
@ -0,0 +1,131 @@
|
||||
From c871a311edf0ebb1b934946a84a6c532cac0c035 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:43 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Setup TMDS char rate via
|
||||
phy_configure_opts_hdmi
|
||||
|
||||
The current workaround to setup the TMDS character rate relies on the
|
||||
unconventional usage of phy_set_bus_width().
|
||||
|
||||
Make use of the recently introduced HDMI PHY configuration API to
|
||||
properly handle the setup. The workaround will be dropped as soon as
|
||||
the switch has been completed on both ends.
|
||||
|
||||
Rename rk_hdptx_phy_verify_config() to rk_hdptx_phy_verify_dp_config()
|
||||
and introduce the rk_hdptx_phy_verify_hdmi_config() helper to check the
|
||||
HDMI parameters during phy_configure().
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-9-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 64 ++++++++++++++-----
|
||||
1 file changed, 47 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -394,6 +394,7 @@ struct rk_hdptx_phy {
|
||||
|
||||
int phy_id;
|
||||
struct phy *phy;
|
||||
+ struct phy_configure_opts_hdmi hdmi_cfg;
|
||||
struct clk_bulk_data *clks;
|
||||
int nr_clks;
|
||||
struct reset_control_bulk_data rsts[RST_MAX];
|
||||
@@ -1414,20 +1415,24 @@ static int rk_hdptx_phy_power_on(struct
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
|
||||
enum phy_mode mode = phy_get_mode(phy);
|
||||
- unsigned long long rate;
|
||||
int ret, lane;
|
||||
|
||||
- /*
|
||||
- * FIXME: Temporary workaround to pass pixel_clk_rate
|
||||
- * from the HDMI bridge driver until phy_configure_opts_hdmi
|
||||
- * becomes available in the PHY API.
|
||||
- */
|
||||
- rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
|
||||
- rate *= 100;
|
||||
+ if (mode != PHY_MODE_DP) {
|
||||
+ if (!hdptx->hdmi_cfg.tmds_char_rate) {
|
||||
+ /*
|
||||
+ * FIXME: Temporary workaround to setup TMDS char rate
|
||||
+ * from the RK DW HDMI QP bridge driver.
|
||||
+ * Will be removed as soon the switch to the HDMI PHY
|
||||
+ * configuration API has been completed on both ends.
|
||||
+ */
|
||||
+ hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
|
||||
+ hdptx->hdmi_cfg.tmds_char_rate *= 100;
|
||||
+ }
|
||||
|
||||
- dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, rate);
|
||||
+ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
+ }
|
||||
|
||||
- ret = rk_hdptx_phy_consumer_get(hdptx, rate);
|
||||
+ ret = rk_hdptx_phy_consumer_get(hdptx, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1458,7 +1463,7 @@ static int rk_hdptx_phy_power_on(struct
|
||||
regmap_write(hdptx->grf, GRF_HDPTX_CON0,
|
||||
HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
|
||||
|
||||
- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
|
||||
+ ret = rk_hdptx_ropll_tmds_mode_config(hdptx, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
if (ret)
|
||||
rk_hdptx_phy_consumer_put(hdptx, true);
|
||||
}
|
||||
@@ -1473,8 +1478,27 @@ static int rk_hdptx_phy_power_off(struct
|
||||
return rk_hdptx_phy_consumer_put(hdptx, false);
|
||||
}
|
||||
|
||||
-static int rk_hdptx_phy_verify_config(struct rk_hdptx_phy *hdptx,
|
||||
- struct phy_configure_opts_dp *dp)
|
||||
+static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
|
||||
+ struct phy_configure_opts_hdmi *hdmi)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
+ if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate)
|
||||
+ break;
|
||||
+
|
||||
+ if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
|
||||
+ !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rk_hdptx_phy_verify_dp_config(struct rk_hdptx_phy *hdptx,
|
||||
+ struct phy_configure_opts_dp *dp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1734,12 +1758,18 @@ static int rk_hdptx_phy_configure(struct
|
||||
enum phy_mode mode = phy_get_mode(phy);
|
||||
int ret;
|
||||
|
||||
- if (mode != PHY_MODE_DP)
|
||||
- return 0;
|
||||
+ if (mode != PHY_MODE_DP) {
|
||||
+ ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
|
||||
+ if (ret)
|
||||
+ dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
|
||||
+ else
|
||||
+ hdptx->hdmi_cfg = opts->hdmi;
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
- ret = rk_hdptx_phy_verify_config(hdptx, &opts->dp);
|
||||
+ ret = rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
|
||||
if (ret) {
|
||||
- dev_err(hdptx->dev, "invalid params for phy configure\n");
|
||||
+ dev_err(hdptx->dev, "invalid dp params for phy configure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
From 2392050a2cb94ff3397949e109e4b9f0285ee085 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:44 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Provide config params
|
||||
validation support
|
||||
|
||||
Implement the phy_ops.validate() callback to allow checking the PHY
|
||||
configuration parameters without actually applying them.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-10-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -1801,10 +1801,22 @@ static int rk_hdptx_phy_configure(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
|
||||
+ int submode, union phy_configure_opts *opts)
|
||||
+{
|
||||
+ struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
|
||||
+
|
||||
+ if (mode != PHY_MODE_DP)
|
||||
+ return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
|
||||
+
|
||||
+ return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
|
||||
+}
|
||||
+
|
||||
static const struct phy_ops rk_hdptx_phy_ops = {
|
||||
.power_on = rk_hdptx_phy_power_on,
|
||||
.power_off = rk_hdptx_phy_power_off,
|
||||
.configure = rk_hdptx_phy_configure,
|
||||
+ .validate = rk_hdptx_phy_validate,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
From 6efbd0f46dd8ae1d2b91b41d98c2800c60ab1f5e Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:45 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Restrict altering TMDS char
|
||||
rate via CCF
|
||||
|
||||
Although, in theory, the clock provider functionality could be enabled
|
||||
as a standalone driver feature, in practice it is unlikely that it would
|
||||
be ever needed separately from the common PHY related features, i.e.
|
||||
making use of the PHY PLL as an alternative and more accurate clock
|
||||
source for display modes handling. Which means the PLL will be always
|
||||
programmed according to the TMDS char rate set via the HDMI PHY
|
||||
configuration API.
|
||||
|
||||
Currently it's possible to freely adjust the rate via the clock API as
|
||||
well, that is through clk_set_rate(). Making the clock read-only is not
|
||||
feasible since we need to ensure any rate update done via the PHY
|
||||
configuration API has been actually programmed into the hardware before
|
||||
CCF accesses it. This would be normally done during phy_ops.power_on()
|
||||
or clk_ops.prepare() callbacks, but it might happen that the former gets
|
||||
fired too late and the latter only once, hence we need to keep handle it
|
||||
via clk_ops.set_rate() as a fallback approach.
|
||||
|
||||
Prevent changing the TMDS character rate via CCF by letting
|
||||
rk_hdptx_phy_clk_round_rate() always return the value set via
|
||||
phy_configure(). To avoid breaking existing users, i.e. RK DW HDMI QP
|
||||
bridge driver, until the switch to the HDMI PHY config based approach is
|
||||
completed, introduce a temporary exception to the rule, toggled via the
|
||||
new ->restrict_rate_change flag, which indicates whether phy_configure()
|
||||
has been called or not.
|
||||
|
||||
Additionally, revert any unlikely rate change that might have occurred
|
||||
between the calls to ->round_rate() and ->set_rate().
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-11-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 52 ++++++++++++++-----
|
||||
1 file changed, 40 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -402,6 +402,7 @@ struct rk_hdptx_phy {
|
||||
/* clk provider */
|
||||
struct clk_hw hw;
|
||||
unsigned long rate;
|
||||
+ bool restrict_rate_change;
|
||||
|
||||
atomic_t usage_count;
|
||||
|
||||
@@ -1760,10 +1761,12 @@ static int rk_hdptx_phy_configure(struct
|
||||
|
||||
if (mode != PHY_MODE_DP) {
|
||||
ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
|
||||
- if (ret)
|
||||
+ if (ret) {
|
||||
dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
|
||||
- else
|
||||
+ } else {
|
||||
hdptx->hdmi_cfg = opts->hdmi;
|
||||
+ hdptx->restrict_rate_change = true;
|
||||
+ }
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1850,20 +1853,31 @@ static unsigned long rk_hdptx_phy_clk_re
|
||||
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
- int i;
|
||||
+ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- if (rate > HDMI20_MAX_RATE)
|
||||
- return rate;
|
||||
+ /*
|
||||
+ * FIXME: Temporarily allow altering TMDS char rate via CCF.
|
||||
+ * To be dropped as soon as the RK DW HDMI QP bridge driver
|
||||
+ * switches to make use of phy_configure().
|
||||
+ */
|
||||
+ if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
|
||||
+ struct phy_configure_opts_hdmi hdmi = {
|
||||
+ .tmds_char_rate = rate,
|
||||
+ };
|
||||
+ int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
- if (rate == ropll_tmds_cfg[i].rate)
|
||||
- break;
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
- if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
|
||||
- !rk_hdptx_phy_clk_pll_calc(rate, NULL))
|
||||
- return -EINVAL;
|
||||
+ hdptx->hdmi_cfg = hdmi;
|
||||
+ }
|
||||
|
||||
- return rate;
|
||||
+ /*
|
||||
+ * The TMDS char rate shall be adjusted via phy_configure() only,
|
||||
+ * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
|
||||
+ * a different rate argument.
|
||||
+ */
|
||||
+ return hdptx->hdmi_cfg.tmds_char_rate;
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -1871,6 +1885,20 @@ static int rk_hdptx_phy_clk_set_rate(str
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
+ /* Revert any unlikely TMDS char rate change since round_rate() */
|
||||
+ if (hdptx->hdmi_cfg.tmds_char_rate != rate) {
|
||||
+ dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n",
|
||||
+ rate, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
+ hdptx->hdmi_cfg.tmds_char_rate = rate;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The TMDS char rate would be normally programmed in HW during
|
||||
+ * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might
|
||||
+ * happen that the former gets fired too late, i.e. after this call,
|
||||
+ * while the latter being executed only once, i.e. when clock remains
|
||||
+ * in the prepared state during rate changes.
|
||||
+ */
|
||||
return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
From 37f335dbfd028c008d0a7940ca5a270d1e2f6b81 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:46 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Rename ambiguous
|
||||
rk_hdptx_phy->rate
|
||||
|
||||
The main purpose of the ->rate member of struct rk_hdptx_phy is to
|
||||
implement rk_hdptx_phy_clk_recalc_rate() by providing the actual rate
|
||||
programmed in hardware. Hence the current naming is too generic and
|
||||
rather ambiguous.
|
||||
|
||||
Improve clarity by renaming ->rate to ->hw_rate.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-12-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -401,7 +401,7 @@ struct rk_hdptx_phy {
|
||||
|
||||
/* clk provider */
|
||||
struct clk_hw hw;
|
||||
- unsigned long rate;
|
||||
+ unsigned long hw_rate;
|
||||
bool restrict_rate_change;
|
||||
|
||||
atomic_t usage_count;
|
||||
@@ -1032,7 +1032,7 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
- hdptx->rate = rate;
|
||||
+ hdptx->hw_rate = rate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1832,7 +1832,7 @@ static int rk_hdptx_phy_clk_prepare(stru
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate);
|
||||
+ return rk_hdptx_phy_consumer_get(hdptx, hdptx->hw_rate);
|
||||
}
|
||||
|
||||
static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
|
||||
@@ -1847,7 +1847,7 @@ static unsigned long rk_hdptx_phy_clk_re
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- return hdptx->rate;
|
||||
+ return hdptx->hw_rate;
|
||||
}
|
||||
|
||||
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@ -0,0 +1,147 @@
|
||||
From 45b14bdcf4acfd483d9890396197c35c23821124 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:47 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Optimize internal rate handling
|
||||
|
||||
Drop the rate parameter from a bunch of internal helpers and, instead,
|
||||
make better use of the newly introduced ->hdmi_cfg.tmds_char_rate driver
|
||||
data.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Acked-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-13-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 47 +++++++++----------
|
||||
1 file changed, 23 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -970,31 +970,34 @@ static bool rk_hdptx_phy_clk_pll_calc(un
|
||||
return true;
|
||||
}
|
||||
|
||||
-static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned long long rate)
|
||||
+static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
const struct ropll_config *cfg = NULL;
|
||||
struct ropll_config rc = {0};
|
||||
int ret, i;
|
||||
|
||||
+ if (!hdptx->hdmi_cfg.tmds_char_rate)
|
||||
+ return 0;
|
||||
+
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
- if (rate == ropll_tmds_cfg[i].rate) {
|
||||
+ if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) {
|
||||
cfg = &ropll_tmds_cfg[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cfg) {
|
||||
- if (rk_hdptx_phy_clk_pll_calc(rate, &rc)) {
|
||||
- cfg = &rc;
|
||||
- } else {
|
||||
- dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__);
|
||||
+ if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) {
|
||||
+ dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
|
||||
+ __func__, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
+
|
||||
+ cfg = &rc;
|
||||
}
|
||||
|
||||
dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n",
|
||||
- __func__, rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en,
|
||||
- cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
|
||||
+ __func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
|
||||
+ cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
|
||||
|
||||
rk_hdptx_pre_power_up(hdptx);
|
||||
|
||||
@@ -1032,19 +1035,18 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
- hdptx->hw_rate = rate;
|
||||
+ hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned long long rate)
|
||||
+static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
|
||||
|
||||
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
|
||||
|
||||
- if (rate > HDMI14_MAX_RATE) {
|
||||
+ if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) {
|
||||
/* For 1/40 bitrate clk */
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
|
||||
} else {
|
||||
@@ -1096,8 +1098,7 @@ static void rk_hdptx_dp_reset(struct rk_
|
||||
HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0));
|
||||
}
|
||||
|
||||
-static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
|
||||
- unsigned long long rate)
|
||||
+static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
enum phy_mode mode = phy_get_mode(hdptx->phy);
|
||||
u32 status;
|
||||
@@ -1116,11 +1117,9 @@ static int rk_hdptx_phy_consumer_get(str
|
||||
if (mode == PHY_MODE_DP) {
|
||||
rk_hdptx_dp_reset(hdptx);
|
||||
} else {
|
||||
- if (rate) {
|
||||
- ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
|
||||
- if (ret)
|
||||
- goto dec_usage;
|
||||
- }
|
||||
+ ret = rk_hdptx_ropll_tmds_cmn_config(hdptx);
|
||||
+ if (ret)
|
||||
+ goto dec_usage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1433,7 +1432,7 @@ static int rk_hdptx_phy_power_on(struct
|
||||
dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
}
|
||||
|
||||
- ret = rk_hdptx_phy_consumer_get(hdptx, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
+ ret = rk_hdptx_phy_consumer_get(hdptx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1464,7 +1463,7 @@ static int rk_hdptx_phy_power_on(struct
|
||||
regmap_write(hdptx->grf, GRF_HDPTX_CON0,
|
||||
HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
|
||||
|
||||
- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
+ ret = rk_hdptx_ropll_tmds_mode_config(hdptx);
|
||||
if (ret)
|
||||
rk_hdptx_phy_consumer_put(hdptx, true);
|
||||
}
|
||||
@@ -1832,7 +1831,7 @@ static int rk_hdptx_phy_clk_prepare(stru
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
- return rk_hdptx_phy_consumer_get(hdptx, hdptx->hw_rate);
|
||||
+ return rk_hdptx_phy_consumer_get(hdptx);
|
||||
}
|
||||
|
||||
static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
|
||||
@@ -1899,7 +1898,7 @@ static int rk_hdptx_phy_clk_set_rate(str
|
||||
* while the latter being executed only once, i.e. when clock remains
|
||||
* in the prepared state during rate changes.
|
||||
*/
|
||||
- return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
|
||||
+ return rk_hdptx_ropll_tmds_cmn_config(hdptx);
|
||||
}
|
||||
|
||||
static const struct clk_ops hdptx_phy_clk_ops = {
|
||||
@ -0,0 +1,76 @@
|
||||
From 9d0ec51d7c227c3ae837e22832eaed219e25f126 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 18 Mar 2025 14:35:48 +0200
|
||||
Subject: [PATCH] phy: rockchip: samsung-hdptx: Add high color depth management
|
||||
|
||||
Add support for 8-bit, 10-bit, 12-bit and 16-bit color depth setup.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmtiry.baryshkov@linaro.org>
|
||||
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-14-8cb1678e7663@collabora.com
|
||||
Signed-off-by: Vinod Koul <vkoul@kernel.org>
|
||||
---
|
||||
.../phy/rockchip/phy-rockchip-samsung-hdptx.c | 23 ++++++++++++++++++-
|
||||
1 file changed, 22 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
@@ -1030,6 +1030,9 @@ static int rk_hdptx_ropll_tmds_cmn_confi
|
||||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
|
||||
FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
|
||||
|
||||
+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK,
|
||||
+ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1));
|
||||
+
|
||||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
|
||||
FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
|
||||
|
||||
@@ -1429,7 +1432,8 @@ static int rk_hdptx_phy_power_on(struct
|
||||
hdptx->hdmi_cfg.tmds_char_rate *= 100;
|
||||
}
|
||||
|
||||
- dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
+ dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
|
||||
+ hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
|
||||
}
|
||||
|
||||
ret = rk_hdptx_phy_consumer_get(hdptx);
|
||||
@@ -1494,6 +1498,19 @@ static int rk_hdptx_phy_verify_hdmi_conf
|
||||
!rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
+ if (!hdmi->bpc)
|
||||
+ hdmi->bpc = 8;
|
||||
+
|
||||
+ switch (hdmi->bpc) {
|
||||
+ case 8:
|
||||
+ case 10:
|
||||
+ case 12:
|
||||
+ case 16:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ };
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1766,6 +1783,9 @@ static int rk_hdptx_phy_configure(struct
|
||||
hdptx->hdmi_cfg = opts->hdmi;
|
||||
hdptx->restrict_rate_change = true;
|
||||
}
|
||||
+
|
||||
+ dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
|
||||
+ hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1974,6 +1994,7 @@ static int rk_hdptx_phy_probe(struct pla
|
||||
return -ENOMEM;
|
||||
|
||||
hdptx->dev = dev;
|
||||
+ hdptx->hdmi_cfg.bpc = 8;
|
||||
|
||||
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(regs))
|
||||
@ -0,0 +1,68 @@
|
||||
From f855146263b14abadd8d5bd0e280e54fbab3bd18 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:10 +0800
|
||||
Subject: [PATCH] dt-bindings: display: rockchip: analogix-dp: Add support for
|
||||
RK3588
|
||||
|
||||
Compared with RK3288/RK3399, the HBR2 link rate support is the main
|
||||
improvement of RK3588 eDP TX controller, and there are also two
|
||||
independent eDP display interfaces on RK3588 Soc.
|
||||
|
||||
The newly added 'apb' reset is to ensure the APB bus of eDP controller
|
||||
works well on the RK3588 SoC.
|
||||
|
||||
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-10-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../rockchip/rockchip,analogix-dp.yaml | 22 +++++++++++++++++--
|
||||
1 file changed, 20 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
|
||||
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
|
||||
@@ -15,6 +15,7 @@ properties:
|
||||
enum:
|
||||
- rockchip,rk3288-dp
|
||||
- rockchip,rk3399-edp
|
||||
+ - rockchip,rk3588-edp
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
@@ -31,10 +32,14 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
- maxItems: 1
|
||||
+ minItems: 1
|
||||
+ maxItems: 2
|
||||
|
||||
reset-names:
|
||||
- const: dp
|
||||
+ minItems: 1
|
||||
+ items:
|
||||
+ - const: dp
|
||||
+ - const: apb
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
@@ -52,6 +57,19 @@ required:
|
||||
allOf:
|
||||
- $ref: /schemas/display/bridge/analogix,dp.yaml#
|
||||
|
||||
+ - if:
|
||||
+ properties:
|
||||
+ compatible:
|
||||
+ contains:
|
||||
+ enum:
|
||||
+ - rockchip,rk3588-edp
|
||||
+ then:
|
||||
+ properties:
|
||||
+ resets:
|
||||
+ minItems: 2
|
||||
+ reset-names:
|
||||
+ minItems: 2
|
||||
+
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@ -0,0 +1,92 @@
|
||||
From 3303a206ae7474b2f8a5d17d8df9de08bac16ca5 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 8 Sep 2024 14:54:58 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Filter modes based on hdmiphy_clk
|
||||
|
||||
RK3228 and RK3328 clock rate is being validated against a mpll config
|
||||
table intended for a Synopsys phy, and not the used inno-hdmi-phy.
|
||||
|
||||
Instead get a reference to the hdmiphy clk and validate rates against
|
||||
it to enable use of HDMI2.0 modes, e.g. 4K@60Hz, on RK3228 and RK3328.
|
||||
|
||||
For Synopsis phy the max_tmds_clock validation is sufficient.
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Tested-by: Diederik de Haas <didi.debian@cknow.org> # Rock64
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-2-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 35 ++++++++++-----------
|
||||
1 file changed, 17 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -76,6 +76,7 @@ struct rockchip_hdmi {
|
||||
struct rockchip_encoder encoder;
|
||||
const struct rockchip_hdmi_chip_data *chip_data;
|
||||
const struct dw_hdmi_plat_data *plat_data;
|
||||
+ struct clk *hdmiphy_clk;
|
||||
struct clk *ref_clk;
|
||||
struct clk *grf_clk;
|
||||
struct dw_hdmi *hdmi;
|
||||
@@ -251,10 +252,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hd
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = data;
|
||||
- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
|
||||
int pclk = mode->clock * 1000;
|
||||
- bool exact_match = hdmi->plat_data->phy_force_vendor;
|
||||
- int i;
|
||||
|
||||
if (hdmi->chip_data->max_tmds_clock &&
|
||||
mode->clock > hdmi->chip_data->max_tmds_clock)
|
||||
@@ -263,26 +261,18 @@ dw_hdmi_rockchip_mode_valid(struct dw_hd
|
||||
if (hdmi->ref_clk) {
|
||||
int rpclk = clk_round_rate(hdmi->ref_clk, pclk);
|
||||
|
||||
- if (abs(rpclk - pclk) > pclk / 1000)
|
||||
+ if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
|
||||
return MODE_NOCLOCK;
|
||||
}
|
||||
|
||||
- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
|
||||
- /*
|
||||
- * For vendor specific phys force an exact match of the pixelclock
|
||||
- * to preserve the original behaviour of the driver.
|
||||
- */
|
||||
- if (exact_match && pclk == mpll_cfg[i].mpixelclock)
|
||||
- return MODE_OK;
|
||||
- /*
|
||||
- * The Synopsys phy can work with pixelclocks up to the value given
|
||||
- * in the corresponding mpll_cfg entry.
|
||||
- */
|
||||
- if (!exact_match && pclk <= mpll_cfg[i].mpixelclock)
|
||||
- return MODE_OK;
|
||||
+ if (hdmi->hdmiphy_clk) {
|
||||
+ int rpclk = clk_round_rate(hdmi->hdmiphy_clk, pclk);
|
||||
+
|
||||
+ if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000)
|
||||
+ return MODE_NOCLOCK;
|
||||
}
|
||||
|
||||
- return MODE_BAD;
|
||||
+ return MODE_OK;
|
||||
}
|
||||
|
||||
static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
|
||||
@@ -607,6 +597,15 @@ static int dw_hdmi_rockchip_bind(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (hdmi->phy) {
|
||||
+ struct of_phandle_args clkspec;
|
||||
+
|
||||
+ clkspec.np = hdmi->phy->dev.of_node;
|
||||
+ hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec);
|
||||
+ if (IS_ERR(hdmi->hdmiphy_clk))
|
||||
+ hdmi->hdmiphy_clk = NULL;
|
||||
+ }
|
||||
+
|
||||
if (hdmi->chip_data == &rk3568_chip_data) {
|
||||
regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
|
||||
HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
|
||||
@ -0,0 +1,53 @@
|
||||
From 6e94e2871eb706a17692acf7ef85ecf2789f6433 Mon Sep 17 00:00:00 2001
|
||||
From: Yakir Yang <ykk@rock-chips.com>
|
||||
Date: Sun, 8 Sep 2024 14:54:59 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Adjust cklvl & txlvl for RF/EMI
|
||||
|
||||
Dut to the high HDMI signal voltage driver, Mickey have meet
|
||||
a serious RF/EMI problem, so we decided to reduce HDMI signal
|
||||
voltage to a proper value.
|
||||
|
||||
The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed)
|
||||
ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43
|
||||
tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35
|
||||
|
||||
1. We decided to reduce voltage value to lower, but VSwing still
|
||||
keep high, RF/EMI have been improved but still failed.
|
||||
ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50
|
||||
tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50
|
||||
|
||||
2. We try to keep voltage value and vswing both lower, then RF/EMI
|
||||
test all passed ;)
|
||||
ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40
|
||||
tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40
|
||||
When we back to run HDMI different test and single-end test, we see
|
||||
different test passed, but signle-end test failed. The oscilloscope
|
||||
show that simgle-end clock's VL value is 1.78v (which remind LowLimit
|
||||
should not lower then 2.6v).
|
||||
|
||||
3. That's to say there are some different between PHY document and
|
||||
measure value. And according to experiment 2 results, we need to
|
||||
higher clock voltage and lower data voltage, then we can keep RF/EMI
|
||||
satisfied and single-end & differen test passed.
|
||||
ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47
|
||||
tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39
|
||||
|
||||
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-3-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -202,7 +202,7 @@ static const struct dw_hdmi_curr_ctrl ro
|
||||
static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
|
||||
/*pixelclk symbol term vlev*/
|
||||
{ 74250000, 0x8009, 0x0004, 0x0272},
|
||||
- { 148500000, 0x802b, 0x0004, 0x028d},
|
||||
+ { 165000000, 0x802b, 0x0004, 0x0209},
|
||||
{ 297000000, 0x8039, 0x0005, 0x028d},
|
||||
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
From b60c86d305f46483d3ed0743e9ec97a76addcabc Mon Sep 17 00:00:00 2001
|
||||
From: Nickey Yang <nickey.yang@rock-chips.com>
|
||||
Date: Sun, 8 Sep 2024 14:55:00 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Add phy_config for 594Mhz pixel clock
|
||||
|
||||
Add phy_config for 594Mhz pixel clock used for HDMI2.0 display modes.
|
||||
|
||||
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-4-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -204,6 +204,7 @@ static const struct dw_hdmi_phy_config r
|
||||
{ 74250000, 0x8009, 0x0004, 0x0272},
|
||||
{ 165000000, 0x802b, 0x0004, 0x0209},
|
||||
{ 297000000, 0x8039, 0x0005, 0x028d},
|
||||
+ { 594000000, 0x8039, 0x0000, 0x019d},
|
||||
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
||||
};
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
From 7d324630f3515bd6e11cadeb1d748bd74ecc9664 Mon Sep 17 00:00:00 2001
|
||||
From: Douglas Anderson <dianders@chromium.org>
|
||||
Date: Sun, 8 Sep 2024 14:55:01 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always
|
||||
|
||||
Jitter was improved by lowering the MPLL bandwidth to account for high
|
||||
frequency noise in the rk3288 PLL. In each case MPLL bandwidth was
|
||||
lowered only enough to get us a comfortable margin. We believe that
|
||||
lowering the bandwidth like this is safe given sufficient testing.
|
||||
|
||||
Signed-off-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-5-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 +---------------
|
||||
1 file changed, 1 insertion(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -179,23 +179,9 @@ static const struct dw_hdmi_mpll_config
|
||||
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
||||
/* pixelclk bpp8 bpp10 bpp12 */
|
||||
{
|
||||
- 40000000, { 0x0018, 0x0018, 0x0018 },
|
||||
- }, {
|
||||
- 65000000, { 0x0028, 0x0028, 0x0028 },
|
||||
- }, {
|
||||
- 66000000, { 0x0038, 0x0038, 0x0038 },
|
||||
- }, {
|
||||
- 74250000, { 0x0028, 0x0038, 0x0038 },
|
||||
- }, {
|
||||
- 83500000, { 0x0028, 0x0038, 0x0038 },
|
||||
- }, {
|
||||
- 146250000, { 0x0038, 0x0038, 0x0038 },
|
||||
- }, {
|
||||
- 148500000, { 0x0000, 0x0038, 0x0038 },
|
||||
- }, {
|
||||
600000000, { 0x0000, 0x0000, 0x0000 },
|
||||
}, {
|
||||
- ~0UL, { 0x0000, 0x0000, 0x0000},
|
||||
+ ~0UL, { 0x0000, 0x0000, 0x0000 },
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,173 @@
|
||||
From 7595c7ef17ffe70d0f4fdda01f87f105a12de66b Mon Sep 17 00:00:00 2001
|
||||
From: Douglas Anderson <dianders@chromium.org>
|
||||
Date: Sun, 8 Sep 2024 14:55:02 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables
|
||||
|
||||
The previous tables for mpll_cfg and curr_ctrl were created using the
|
||||
20-pages of example settings provided by the PHY vendor. Those
|
||||
example settings weren't particularly dense, so there were places
|
||||
where we were guessing what the settings would be for 10-bit and
|
||||
12-bit (not that we use those anyway). It was also always a lot of
|
||||
extra work every time we wanted to add a new clock rate since we had
|
||||
to cross-reference several tables.
|
||||
|
||||
In <https://crrev.com/c/285855> I've gone through the work to figure
|
||||
out how to generate this table automatically. Let's now use the
|
||||
automatically generated table and then we'll never need to look at it
|
||||
again.
|
||||
|
||||
We only support 8-bit mode right now and only support a small number
|
||||
of clock rates and I've verified that the only 8-bit rate that was
|
||||
affected was 148.5. That mode appears to have been wrong in the old
|
||||
table.
|
||||
|
||||
Signed-off-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-6-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 104 ++++++++++----------
|
||||
1 file changed, 53 insertions(+), 51 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -92,74 +92,70 @@ static struct rockchip_hdmi *to_rockchip
|
||||
|
||||
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
||||
{
|
||||
- 27000000, {
|
||||
- { 0x00b3, 0x0000},
|
||||
- { 0x2153, 0x0000},
|
||||
- { 0x40f3, 0x0000}
|
||||
+ 30666000, {
|
||||
+ { 0x00b3, 0x0000 },
|
||||
+ { 0x2153, 0x0000 },
|
||||
+ { 0x40f3, 0x0000 },
|
||||
},
|
||||
}, {
|
||||
- 36000000, {
|
||||
- { 0x00b3, 0x0000},
|
||||
- { 0x2153, 0x0000},
|
||||
- { 0x40f3, 0x0000}
|
||||
+ 36800000, {
|
||||
+ { 0x00b3, 0x0000 },
|
||||
+ { 0x2153, 0x0000 },
|
||||
+ { 0x40a2, 0x0001 },
|
||||
},
|
||||
}, {
|
||||
- 40000000, {
|
||||
- { 0x00b3, 0x0000},
|
||||
- { 0x2153, 0x0000},
|
||||
- { 0x40f3, 0x0000}
|
||||
+ 46000000, {
|
||||
+ { 0x00b3, 0x0000 },
|
||||
+ { 0x2142, 0x0001 },
|
||||
+ { 0x40a2, 0x0001 },
|
||||
},
|
||||
}, {
|
||||
- 54000000, {
|
||||
- { 0x0072, 0x0001},
|
||||
- { 0x2142, 0x0001},
|
||||
- { 0x40a2, 0x0001},
|
||||
+ 61333000, {
|
||||
+ { 0x0072, 0x0001 },
|
||||
+ { 0x2142, 0x0001 },
|
||||
+ { 0x40a2, 0x0001 },
|
||||
},
|
||||
}, {
|
||||
- 65000000, {
|
||||
- { 0x0072, 0x0001},
|
||||
- { 0x2142, 0x0001},
|
||||
- { 0x40a2, 0x0001},
|
||||
+ 73600000, {
|
||||
+ { 0x0072, 0x0001 },
|
||||
+ { 0x2142, 0x0001 },
|
||||
+ { 0x4061, 0x0002 },
|
||||
},
|
||||
}, {
|
||||
- 66000000, {
|
||||
- { 0x013e, 0x0003},
|
||||
- { 0x217e, 0x0002},
|
||||
- { 0x4061, 0x0002}
|
||||
+ 92000000, {
|
||||
+ { 0x0072, 0x0001 },
|
||||
+ { 0x2145, 0x0002 },
|
||||
+ { 0x4061, 0x0002 },
|
||||
},
|
||||
}, {
|
||||
- 74250000, {
|
||||
- { 0x0072, 0x0001},
|
||||
- { 0x2145, 0x0002},
|
||||
- { 0x4061, 0x0002}
|
||||
+ 122666000, {
|
||||
+ { 0x0051, 0x0002 },
|
||||
+ { 0x2145, 0x0002 },
|
||||
+ { 0x4061, 0x0002 },
|
||||
},
|
||||
}, {
|
||||
- 83500000, {
|
||||
- { 0x0072, 0x0001},
|
||||
+ 147200000, {
|
||||
+ { 0x0051, 0x0002 },
|
||||
+ { 0x2145, 0x0002 },
|
||||
+ { 0x4064, 0x0003 },
|
||||
},
|
||||
}, {
|
||||
- 108000000, {
|
||||
- { 0x0051, 0x0002},
|
||||
- { 0x2145, 0x0002},
|
||||
- { 0x4061, 0x0002}
|
||||
+ 184000000, {
|
||||
+ { 0x0051, 0x0002 },
|
||||
+ { 0x214c, 0x0003 },
|
||||
+ { 0x4064, 0x0003 },
|
||||
},
|
||||
}, {
|
||||
- 106500000, {
|
||||
- { 0x0051, 0x0002},
|
||||
- { 0x2145, 0x0002},
|
||||
- { 0x4061, 0x0002}
|
||||
- },
|
||||
- }, {
|
||||
- 146250000, {
|
||||
- { 0x0051, 0x0002},
|
||||
- { 0x2145, 0x0002},
|
||||
- { 0x4061, 0x0002}
|
||||
+ 226666000, {
|
||||
+ { 0x0040, 0x0003 },
|
||||
+ { 0x214c, 0x0003 },
|
||||
+ { 0x4064, 0x0003 },
|
||||
},
|
||||
}, {
|
||||
- 148500000, {
|
||||
- { 0x0051, 0x0003},
|
||||
- { 0x214c, 0x0003},
|
||||
- { 0x4064, 0x0003}
|
||||
+ 272000000, {
|
||||
+ { 0x0040, 0x0003 },
|
||||
+ { 0x214c, 0x0003 },
|
||||
+ { 0x5a64, 0x0003 },
|
||||
},
|
||||
}, {
|
||||
340000000, {
|
||||
@@ -168,10 +164,16 @@ static const struct dw_hdmi_mpll_config
|
||||
{ 0x5a64, 0x0003 },
|
||||
},
|
||||
}, {
|
||||
+ 600000000, {
|
||||
+ { 0x1a40, 0x0003 },
|
||||
+ { 0x3b4c, 0x0003 },
|
||||
+ { 0x5a64, 0x0003 },
|
||||
+ },
|
||||
+ }, {
|
||||
~0UL, {
|
||||
- { 0x00a0, 0x000a },
|
||||
- { 0x2001, 0x000f },
|
||||
- { 0x4002, 0x000f },
|
||||
+ { 0x0000, 0x0000 },
|
||||
+ { 0x0000, 0x0000 },
|
||||
+ { 0x0000, 0x0000 },
|
||||
},
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,37 @@
|
||||
From 28f0ae48e7fdbd6cdcf3972c8d8686a529ae1ede Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 8 Sep 2024 14:55:03 +0000
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi: Enable 4K@60Hz mode on RK3399 and
|
||||
RK356x
|
||||
|
||||
Use a maximum TMDS clock rate limit of 594MHz to enable use of HDMI2.0
|
||||
modes, e.g. 4K@60Hz, on RK3399 and RK3568.
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Tested-by: Diederik de Haas <didi.debian@cknow.org> # Quartz64 Model B
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-7-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -481,7 +481,7 @@ static struct rockchip_hdmi_chip_data rk
|
||||
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
|
||||
.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
|
||||
.lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),
|
||||
- .max_tmds_clock = 340000,
|
||||
+ .max_tmds_clock = 594000,
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
|
||||
@@ -495,7 +495,7 @@ static const struct dw_hdmi_plat_data rk
|
||||
|
||||
static struct rockchip_hdmi_chip_data rk3568_chip_data = {
|
||||
.lcdsel_grf_reg = -1,
|
||||
- .max_tmds_clock = 340000,
|
||||
+ .max_tmds_clock = 594000,
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
|
||||
@ -0,0 +1,59 @@
|
||||
From 0c4558a1bc2df9b6e6fb311de9cab192b0943426 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 8 Sep 2024 14:55:04 +0000
|
||||
Subject: [PATCH] drm/rockchip: Load crtc devices in preferred order
|
||||
|
||||
On RK3399 the VOPL is loaded before VOPB and get registered as crtc-0.
|
||||
However, on RK3288 and PX30 VOPB is gets registered as crtc-0 instead of
|
||||
VOPL.
|
||||
|
||||
With VOPL registered as crtc-0 the kernel kms client is not able to
|
||||
enable 4K display modes for console use on RK3399.
|
||||
|
||||
Load VOPB before VOPL to help kernel kms client make use of 4K display
|
||||
modes for console use on RK3399.
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-8-jonas@kwiboo.se
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 23 +++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -358,11 +358,34 @@ static void rockchip_drm_match_remove(st
|
||||
device_link_del(link);
|
||||
}
|
||||
|
||||
+/* list of preferred vop devices */
|
||||
+static const char *const rockchip_drm_match_preferred[] = {
|
||||
+ "rockchip,rk3399-vop-big",
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
static struct component_match *rockchip_drm_match_add(struct device *dev)
|
||||
{
|
||||
struct component_match *match = NULL;
|
||||
+ struct device_node *port;
|
||||
int i;
|
||||
|
||||
+ /* add preferred vop device match before adding driver device matches */
|
||||
+ for (i = 0; ; i++) {
|
||||
+ port = of_parse_phandle(dev->of_node, "ports", i);
|
||||
+ if (!port)
|
||||
+ break;
|
||||
+
|
||||
+ if (of_device_is_available(port->parent) &&
|
||||
+ of_device_compatible_match(port->parent,
|
||||
+ rockchip_drm_match_preferred))
|
||||
+ drm_of_component_match_add(dev, &match,
|
||||
+ component_compare_of,
|
||||
+ port->parent);
|
||||
+
|
||||
+ of_node_put(port);
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < num_rockchip_sub_drivers; i++) {
|
||||
struct platform_driver *drv = rockchip_sub_drivers[i];
|
||||
struct device *p = NULL, *d;
|
||||
@ -0,0 +1,63 @@
|
||||
From 905df8f19e1a7042ddeae1e39d0920b60dfe8c0d Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
Date: Tue, 24 Sep 2024 09:12:35 +0200
|
||||
Subject: [PATCH] drm/rockchip: Run DRM default client setup
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Call drm_client_setup() to run the kernel's default client setup
|
||||
for DRM. Set fbdev_probe in struct drm_driver, so that the client
|
||||
setup can start the common fbdev client.
|
||||
|
||||
v5:
|
||||
- select DRM_CLIENT_SELECTION
|
||||
|
||||
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
Cc: Sandy Huang <hjc@rock-chips.com>
|
||||
Cc: "Heiko St¡§1bner" <heiko@sntech.de>
|
||||
Cc: Andy Yan <andy.yan@rock-chips.com>
|
||||
Acked-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240924071734.98201-38-tzimmermann@suse.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/Kconfig | 1 +
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 +++-
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/Kconfig
|
||||
+++ b/drivers/gpu/drm/rockchip/Kconfig
|
||||
@@ -2,6 +2,7 @@
|
||||
config DRM_ROCKCHIP
|
||||
tristate "DRM Support for Rockchip"
|
||||
depends on DRM && ROCKCHIP_IOMMU
|
||||
+ select DRM_CLIENT_SELECTION
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include <drm/drm_aperture.h>
|
||||
+#include <drm/drm_client_setup.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fbdev_dma.h>
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
@@ -195,7 +196,7 @@ static int rockchip_drm_bind(struct devi
|
||||
if (ret)
|
||||
goto err_kms_helper_poll_fini;
|
||||
|
||||
- drm_fbdev_dma_setup(drm_dev, 0);
|
||||
+ drm_client_setup(drm_dev, NULL);
|
||||
|
||||
return 0;
|
||||
err_kms_helper_poll_fini:
|
||||
@@ -230,6 +231,7 @@ static const struct drm_driver rockchip_
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
|
||||
.dumb_create = rockchip_gem_dumb_create,
|
||||
.gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table,
|
||||
+ DRM_FBDEV_DMA_DRIVER_OPS,
|
||||
.fops = &rockchip_drm_driver_fops,
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,511 @@
|
||||
From 128a9bf8ace290d86d2805c06f3b0e4cfab75de0 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Wed, 16 Oct 2024 23:06:53 +0300
|
||||
Subject: [PATCH] drm/rockchip: Add basic RK3588 HDMI output support
|
||||
|
||||
The RK3588 SoC family integrates the newer Synopsys DesignWare HDMI 2.1
|
||||
Quad-Pixel (QP) TX controller IP and a HDMI/eDP TX Combo PHY based on a
|
||||
Samsung IP block.
|
||||
|
||||
Add just the basic support for now, i.e. RGB output up to 4K@60Hz,
|
||||
without audio, CEC or any of the HDMI 2.1 specific features.
|
||||
|
||||
Co-developed-by: Algea Cao <algea.cao@rock-chips.com>
|
||||
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
|
||||
Tested-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Reviewed-by: Maxime Ripard <mripard@kernel.org>
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241016-b4-rk3588-bridge-upstream-v10-3-87ef92a6d14e@collabora.com
|
||||
Signed-off-by: Maxime Ripard <mripard@kernel.org>
|
||||
---
|
||||
drivers/gpu/drm/rockchip/Kconfig | 9 +
|
||||
drivers/gpu/drm/rockchip/Makefile | 1 +
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 424 ++++++++++++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
|
||||
5 files changed, 437 insertions(+)
|
||||
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/Kconfig
|
||||
+++ b/drivers/gpu/drm/rockchip/Kconfig
|
||||
@@ -9,6 +9,7 @@ config DRM_ROCKCHIP
|
||||
select VIDEOMODE_HELPERS
|
||||
select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
|
||||
select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
|
||||
+ select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP
|
||||
select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
|
||||
select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI
|
||||
select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI
|
||||
@@ -64,6 +65,14 @@ config ROCKCHIP_DW_HDMI
|
||||
enable HDMI on RK3288 or RK3399 based SoC, you should select
|
||||
this option.
|
||||
|
||||
+config ROCKCHIP_DW_HDMI_QP
|
||||
+ bool "Rockchip specific extensions for Synopsys DW HDMI QP"
|
||||
+ select DRM_BRIDGE_CONNECTOR
|
||||
+ help
|
||||
+ This selects support for Rockchip SoC specific extensions
|
||||
+ for the Synopsys DesignWare HDMI QP driver. If you want to
|
||||
+ enable HDMI on RK3588 based SoC, you should select this option.
|
||||
+
|
||||
config ROCKCHIP_DW_MIPI_DSI
|
||||
bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
|
||||
select GENERIC_PHY_MIPI_DPHY
|
||||
--- a/drivers/gpu/drm/rockchip/Makefile
|
||||
+++ b/drivers/gpu/drm/rockchip/Makefile
|
||||
@@ -11,6 +11,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += ro
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
|
||||
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -0,0 +1,424 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
|
||||
+ * Copyright (c) 2024 Collabora Ltd.
|
||||
+ *
|
||||
+ * Author: Algea Cao <algea.cao@rock-chips.com>
|
||||
+ * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#include <drm/bridge/dw_hdmi_qp.h>
|
||||
+#include <drm/display/drm_hdmi_helper.h>
|
||||
+#include <drm/drm_bridge_connector.h>
|
||||
+#include <drm/drm_of.h>
|
||||
+#include <drm/drm_probe_helper.h>
|
||||
+#include <drm/drm_simple_kms_helper.h>
|
||||
+
|
||||
+#include "rockchip_drm_drv.h"
|
||||
+
|
||||
+#define RK3588_GRF_SOC_CON2 0x0308
|
||||
+#define RK3588_HDMI0_HPD_INT_MSK BIT(13)
|
||||
+#define RK3588_HDMI0_HPD_INT_CLR BIT(12)
|
||||
+#define RK3588_GRF_SOC_CON7 0x031c
|
||||
+#define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12)
|
||||
+#define RK3588_GRF_SOC_STATUS1 0x0384
|
||||
+#define RK3588_HDMI0_LEVEL_INT BIT(16)
|
||||
+#define RK3588_GRF_VO1_CON3 0x000c
|
||||
+#define RK3588_SCLIN_MASK BIT(9)
|
||||
+#define RK3588_SDAIN_MASK BIT(10)
|
||||
+#define RK3588_MODE_MASK BIT(11)
|
||||
+#define RK3588_I2S_SEL_MASK BIT(13)
|
||||
+#define RK3588_GRF_VO1_CON9 0x0024
|
||||
+#define RK3588_HDMI0_GRANT_SEL BIT(10)
|
||||
+
|
||||
+#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16)
|
||||
+#define HOTPLUG_DEBOUNCE_MS 150
|
||||
+
|
||||
+struct rockchip_hdmi_qp {
|
||||
+ struct device *dev;
|
||||
+ struct regmap *regmap;
|
||||
+ struct regmap *vo_regmap;
|
||||
+ struct rockchip_encoder encoder;
|
||||
+ struct clk *ref_clk;
|
||||
+ struct dw_hdmi_qp *hdmi;
|
||||
+ struct phy *phy;
|
||||
+ struct gpio_desc *enable_gpio;
|
||||
+ struct delayed_work hpd_work;
|
||||
+};
|
||||
+
|
||||
+static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
||||
+
|
||||
+ return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
|
||||
+ struct drm_crtc *crtc = encoder->crtc;
|
||||
+ unsigned long long rate;
|
||||
+
|
||||
+ /* Unconditionally switch to TMDS as FRL is not yet supported */
|
||||
+ gpiod_set_value(hdmi->enable_gpio, 1);
|
||||
+
|
||||
+ if (crtc && crtc->state) {
|
||||
+ rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode,
|
||||
+ 8, HDMI_COLORSPACE_RGB);
|
||||
+ clk_set_rate(hdmi->ref_clk, rate);
|
||||
+ /*
|
||||
+ * FIXME: Temporary workaround to pass pixel clock rate
|
||||
+ * to the PHY driver until phy_configure_opts_hdmi
|
||||
+ * becomes available in the PHY API. See also the related
|
||||
+ * comment in rk_hdptx_phy_power_on() from
|
||||
+ * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
+ */
|
||||
+ phy_set_bus_width(hdmi->phy, rate / 100);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
+
|
||||
+ s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
|
||||
+ s->output_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct
|
||||
+drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = {
|
||||
+ .enable = dw_hdmi_qp_rockchip_encoder_enable,
|
||||
+ .atomic_check = dw_hdmi_qp_rockchip_encoder_atomic_check,
|
||||
+};
|
||||
+
|
||||
+static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+
|
||||
+ return phy_power_on(hdmi->phy);
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+
|
||||
+ phy_power_off(hdmi->phy);
|
||||
+}
|
||||
+
|
||||
+static enum drm_connector_status
|
||||
+dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+ u32 val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
|
||||
+
|
||||
+ return val & RK3588_HDMI0_LEVEL_INT ?
|
||||
+ connector_status_connected : connector_status_disconnected;
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+
|
||||
+ regmap_write(hdmi->regmap,
|
||||
+ RK3588_GRF_SOC_CON2,
|
||||
+ HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
+ RK3588_HDMI0_HPD_INT_CLR |
|
||||
+ RK3588_HDMI0_HPD_INT_MSK));
|
||||
+}
|
||||
+
|
||||
+static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
|
||||
+ .init = dw_hdmi_qp_rk3588_phy_init,
|
||||
+ .disable = dw_hdmi_qp_rk3588_phy_disable,
|
||||
+ .read_hpd = dw_hdmi_qp_rk3588_read_hpd,
|
||||
+ .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
|
||||
+};
|
||||
+
|
||||
+static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = container_of(work,
|
||||
+ struct rockchip_hdmi_qp,
|
||||
+ hpd_work.work);
|
||||
+ struct drm_device *drm = hdmi->encoder.encoder.dev;
|
||||
+ bool changed;
|
||||
+
|
||||
+ if (drm) {
|
||||
+ changed = drm_helper_hpd_irq_event(drm);
|
||||
+ if (changed)
|
||||
+ drm_dbg(hdmi, "connector status changed\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
+ u32 intr_stat, val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
|
||||
+
|
||||
+ if (intr_stat) {
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK,
|
||||
+ RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+ return IRQ_WAKE_THREAD;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_NONE;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
+ u32 intr_stat, val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
|
||||
+ if (!intr_stat)
|
||||
+ return IRQ_NONE;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
+ RK3588_HDMI0_HPD_INT_CLR);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+
|
||||
+ mod_delayed_work(system_wq, &hdmi->hpd_work,
|
||||
+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
|
||||
+
|
||||
+ val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
|
||||
+ { .compatible = "rockchip,rk3588-dw-hdmi-qp",
|
||||
+ .data = &rk3588_hdmi_phy_ops },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
|
||||
+
|
||||
+static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
||||
+ void *data)
|
||||
+{
|
||||
+ static const char * const clk_names[] = {
|
||||
+ "pclk", "earc", "aud", "hdp", "hclk_vo1",
|
||||
+ "ref" /* keep "ref" last */
|
||||
+ };
|
||||
+ struct platform_device *pdev = to_platform_device(dev);
|
||||
+ struct dw_hdmi_qp_plat_data plat_data;
|
||||
+ struct drm_device *drm = data;
|
||||
+ struct drm_connector *connector;
|
||||
+ struct drm_encoder *encoder;
|
||||
+ struct rockchip_hdmi_qp *hdmi;
|
||||
+ struct clk *clk;
|
||||
+ int ret, irq, i;
|
||||
+ u32 val;
|
||||
+
|
||||
+ if (!pdev->dev.of_node)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
+ if (!hdmi)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ plat_data.phy_ops = of_device_get_match_data(dev);
|
||||
+ if (!plat_data.phy_ops)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ plat_data.phy_data = hdmi;
|
||||
+ hdmi->dev = &pdev->dev;
|
||||
+
|
||||
+ encoder = &hdmi->encoder.encoder;
|
||||
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
+
|
||||
+ rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
|
||||
+ dev->of_node, 0, 0);
|
||||
+ /*
|
||||
+ * If we failed to find the CRTC(s) which this encoder is
|
||||
+ * supposed to be connected to, it's because the CRTC has
|
||||
+ * not been registered yet. Defer probing, and hope that
|
||||
+ * the required CRTC is added later.
|
||||
+ */
|
||||
+ if (encoder->possible_crtcs == 0)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
+ "rockchip,grf");
|
||||
+ if (IS_ERR(hdmi->regmap)) {
|
||||
+ drm_err(hdmi, "Unable to get rockchip,grf\n");
|
||||
+ return PTR_ERR(hdmi->regmap);
|
||||
+ }
|
||||
+
|
||||
+ hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
+ "rockchip,vo-grf");
|
||||
+ if (IS_ERR(hdmi->vo_regmap)) {
|
||||
+ drm_err(hdmi, "Unable to get rockchip,vo-grf\n");
|
||||
+ return PTR_ERR(hdmi->vo_regmap);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(clk_names); i++) {
|
||||
+ clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]);
|
||||
+
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ ret = PTR_ERR(clk);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ drm_err(hdmi, "Failed to get %s clock: %d\n",
|
||||
+ clk_names[i], ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+ hdmi->ref_clk = clk;
|
||||
+
|
||||
+ hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
|
||||
+ GPIOD_OUT_HIGH);
|
||||
+ if (IS_ERR(hdmi->enable_gpio)) {
|
||||
+ ret = PTR_ERR(hdmi->enable_gpio);
|
||||
+ drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
|
||||
+ if (IS_ERR(hdmi->phy)) {
|
||||
+ ret = PTR_ERR(hdmi->phy);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ drm_err(hdmi, "failed to get phy: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
+ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
+ RK3588_SET_HPD_PATH_MASK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
+ RK3588_HDMI0_GRANT_SEL);
|
||||
+ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+
|
||||
+ INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
|
||||
+
|
||||
+ plat_data.main_irq = platform_get_irq_byname(pdev, "main");
|
||||
+ if (plat_data.main_irq < 0)
|
||||
+ return plat_data.main_irq;
|
||||
+
|
||||
+ irq = platform_get_irq_byname(pdev, "hpd");
|
||||
+ if (irq < 0)
|
||||
+ return irq;
|
||||
+
|
||||
+ ret = devm_request_threaded_irq(hdmi->dev, irq,
|
||||
+ dw_hdmi_qp_rk3588_hardirq,
|
||||
+ dw_hdmi_qp_rk3588_irq,
|
||||
+ IRQF_SHARED, "dw-hdmi-qp-hpd",
|
||||
+ hdmi);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
|
||||
+ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, hdmi);
|
||||
+
|
||||
+ hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
|
||||
+ if (IS_ERR(hdmi->hdmi)) {
|
||||
+ ret = PTR_ERR(hdmi->hdmi);
|
||||
+ drm_encoder_cleanup(encoder);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ connector = drm_bridge_connector_init(drm, encoder);
|
||||
+ if (IS_ERR(connector)) {
|
||||
+ ret = PTR_ERR(connector);
|
||||
+ drm_err(hdmi, "failed to init bridge connector: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return drm_connector_attach_encoder(connector, encoder);
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
|
||||
+ struct device *master,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
+
|
||||
+ cancel_delayed_work_sync(&hdmi->hpd_work);
|
||||
+
|
||||
+ drm_encoder_cleanup(&hdmi->encoder.encoder);
|
||||
+}
|
||||
+
|
||||
+static const struct component_ops dw_hdmi_qp_rockchip_ops = {
|
||||
+ .bind = dw_hdmi_qp_rockchip_bind,
|
||||
+ .unbind = dw_hdmi_qp_rockchip_unbind,
|
||||
+};
|
||||
+
|
||||
+static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
|
||||
+}
|
||||
+
|
||||
+static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
+ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
+ RK3588_SET_HPD_PATH_MASK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
+ RK3588_HDMI0_GRANT_SEL);
|
||||
+ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
+
|
||||
+ dw_hdmi_qp_resume(dev, hdmi->hdmi);
|
||||
+
|
||||
+ if (hdmi->encoder.encoder.dev)
|
||||
+ drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
|
||||
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume)
|
||||
+};
|
||||
+
|
||||
+struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {
|
||||
+ .probe = dw_hdmi_qp_rockchip_probe,
|
||||
+ .remove = dw_hdmi_qp_rockchip_remove,
|
||||
+ .driver = {
|
||||
+ .name = "dwhdmiqp-rockchip",
|
||||
+ .pm = &dw_hdmi_qp_rockchip_pm,
|
||||
+ .of_match_table = dw_hdmi_qp_rockchip_dt_ids,
|
||||
+ },
|
||||
+};
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -532,6 +532,8 @@ static int __init rockchip_drm_init(void
|
||||
ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
|
||||
CONFIG_ROCKCHIP_DW_HDMI);
|
||||
+ ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver,
|
||||
+ CONFIG_ROCKCHIP_DW_HDMI_QP);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
|
||||
CONFIG_ROCKCHIP_DW_MIPI_DSI);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
||||
@@ -88,6 +88,7 @@ int rockchip_drm_encoder_set_crtc_endpoi
|
||||
int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
|
||||
extern struct platform_driver cdn_dp_driver;
|
||||
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
|
||||
+extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver;
|
||||
extern struct platform_driver dw_mipi_dsi_rockchip_driver;
|
||||
extern struct platform_driver inno_hdmi_driver;
|
||||
extern struct platform_driver rockchip_dp_driver;
|
||||
@ -0,0 +1,334 @@
|
||||
From 4f537776340dab2b680a4d8554567f6884240d0b Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Date: Fri, 1 Nov 2024 19:01:17 +0000
|
||||
Subject: [PATCH] rockchip/drm: vop2: add support for gamma LUT
|
||||
|
||||
Add support for gamma LUT in VOP2 driver. The implementation was inspired
|
||||
by one found in VOP1 driver. Blue and red channels in gamma LUT register
|
||||
write were swapped with respect to how gamma LUT values are written in
|
||||
VOP1. Gamma LUT port selection was added before the write of new gamma LUT
|
||||
table.
|
||||
|
||||
If the current SoC is rk356x, check if no other CRTC has gamma LUT enabled
|
||||
in atomic_check (only one video port can use gamma LUT at a time) and
|
||||
disable gamma LUT before the LUT table write.
|
||||
|
||||
If the current SoC isn't rk356x, "seamless" gamma lut update is performed
|
||||
similarly to how it was done in the case of RK3399 in VOP1[1]. In seamless
|
||||
update gamma LUT disable before the write isn't necessary, check if no
|
||||
other CRTC has gamma LUT enabled is also not necessary, different register
|
||||
is being used to select gamma LUT port[2] and after setting DSP_LUT_EN bit,
|
||||
GAMMA_UPDATE_EN bit is set[3].
|
||||
|
||||
Gamma size is set and drm color management is enabled for each video port's
|
||||
CRTC except ones which have no associated device.
|
||||
|
||||
Patch was tested on RK3566 (Pinetab2). When using userspace tools
|
||||
which set eg. constant color temperature no issues were noticed. When
|
||||
using userspace tools which adjust eg. color temperature the slight screen
|
||||
flicker is visible probably because of gamma LUT disable needed in the
|
||||
case of RK356x before gamma LUT write.
|
||||
|
||||
Compare behaviour of eg.:
|
||||
```
|
||||
gammastep -O 3000
|
||||
```
|
||||
|
||||
To eg.:
|
||||
```
|
||||
gammastep -l 53:23 -t 6000:3000
|
||||
```
|
||||
|
||||
In latter case color temperature is slowly adjusted at the beginning which
|
||||
causes screen to slighly flicker. Then it adjusts every few seconds which
|
||||
also causes slight screen flicker.
|
||||
|
||||
[1] https://lists.infradead.org/pipermail/linux-rockchip/2021-October/028132.html
|
||||
[2] https://lore.kernel.org/linux-rockchip/48249708-8c05-40d2-a5d8-23de960c5a77@rock-chips.com/
|
||||
[3] https://github.com/radxa/kernel/blob/linux-6.1-stan-rkr1/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c#L3437
|
||||
|
||||
Helped-by: Daniel Stone <daniel@fooishbar.org>
|
||||
Helped-by: Dragan Simic <dsimic@manjaro.org>
|
||||
Helped-by: Diederik de Haas <didi.debian@cknow.org>
|
||||
Helped-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Reviewed-by: Andy Yan <andyshrk@163.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241101185545.559090-3-pZ010001011111@proton.me
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 186 +++++++++++++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 5 +
|
||||
2 files changed, 191 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -281,6 +281,15 @@ static u32 vop2_readl(struct vop2 *vop2,
|
||||
return val;
|
||||
}
|
||||
|
||||
+static u32 vop2_vp_read(struct vop2_video_port *vp, u32 offset)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ regmap_read(vp->vop2->map, vp->data->offset + offset, &val);
|
||||
+
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v)
|
||||
{
|
||||
regmap_field_write(win->reg[reg], v);
|
||||
@@ -1020,6 +1029,67 @@ static void vop2_disable(struct vop2 *vo
|
||||
clk_disable_unprepare(vop2->hclk);
|
||||
}
|
||||
|
||||
+static bool vop2_vp_dsp_lut_is_enabled(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
|
||||
+
|
||||
+ return dsp_ctrl & RK3568_VP_DSP_CTRL__DSP_LUT_EN;
|
||||
+}
|
||||
+
|
||||
+static void vop2_vp_dsp_lut_disable(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
|
||||
+
|
||||
+ dsp_ctrl &= ~RK3568_VP_DSP_CTRL__DSP_LUT_EN;
|
||||
+ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
|
||||
+}
|
||||
+
|
||||
+static bool vop2_vp_dsp_lut_poll_disabled(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ u32 dsp_ctrl;
|
||||
+ int ret = readx_poll_timeout(vop2_vp_dsp_lut_is_enabled, vp, dsp_ctrl,
|
||||
+ !dsp_ctrl, 5, 30 * 1000);
|
||||
+ if (ret) {
|
||||
+ drm_err(vp->vop2->drm, "display LUT RAM enable timeout!\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static void vop2_vp_dsp_lut_enable(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
|
||||
+
|
||||
+ dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_LUT_EN;
|
||||
+ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
|
||||
+}
|
||||
+
|
||||
+static void vop2_vp_dsp_lut_update_enable(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);
|
||||
+
|
||||
+ dsp_ctrl |= RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN;
|
||||
+ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
|
||||
+}
|
||||
+
|
||||
+static inline bool vop2_supports_seamless_gamma_lut_update(struct vop2 *vop2)
|
||||
+{
|
||||
+ return (vop2->data->soc_id != 3566 && vop2->data->soc_id != 3568);
|
||||
+}
|
||||
+
|
||||
+static bool vop2_gamma_lut_in_use(struct vop2 *vop2, struct vop2_video_port *vp)
|
||||
+{
|
||||
+ const int nr_vps = vop2->data->nr_vps;
|
||||
+ int gamma_en_vp_id;
|
||||
+
|
||||
+ for (gamma_en_vp_id = 0; gamma_en_vp_id < nr_vps; gamma_en_vp_id++)
|
||||
+ if (vop2_vp_dsp_lut_is_enabled(&vop2->vps[gamma_en_vp_id]))
|
||||
+ break;
|
||||
+
|
||||
+ return gamma_en_vp_id != nr_vps && gamma_en_vp_id != vp->id;
|
||||
+}
|
||||
+
|
||||
static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
@@ -1511,6 +1581,77 @@ static bool vop2_crtc_mode_fixup(struct
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void vop2_crtc_write_gamma_lut(struct vop2 *vop2, struct drm_crtc *crtc)
|
||||
+{
|
||||
+ const struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
+ const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id];
|
||||
+ struct drm_color_lut *lut = crtc->state->gamma_lut->data;
|
||||
+ unsigned int i, bpc = ilog2(vp_data->gamma_lut_len);
|
||||
+ u32 word;
|
||||
+
|
||||
+ for (i = 0; i < crtc->gamma_size; i++) {
|
||||
+ word = (drm_color_lut_extract(lut[i].blue, bpc) << (2 * bpc)) |
|
||||
+ (drm_color_lut_extract(lut[i].green, bpc) << bpc) |
|
||||
+ drm_color_lut_extract(lut[i].red, bpc);
|
||||
+
|
||||
+ writel(word, vop2->lut_regs + i * 4);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vop2_crtc_atomic_set_gamma_seamless(struct vop2 *vop2,
|
||||
+ struct vop2_video_port *vp,
|
||||
+ struct drm_crtc *crtc)
|
||||
+{
|
||||
+ vop2_writel(vop2, RK3568_LUT_PORT_SEL,
|
||||
+ FIELD_PREP(RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL, vp->id));
|
||||
+ vop2_vp_dsp_lut_enable(vp);
|
||||
+ vop2_crtc_write_gamma_lut(vop2, crtc);
|
||||
+ vop2_vp_dsp_lut_update_enable(vp);
|
||||
+}
|
||||
+
|
||||
+static void vop2_crtc_atomic_set_gamma_rk356x(struct vop2 *vop2,
|
||||
+ struct vop2_video_port *vp,
|
||||
+ struct drm_crtc *crtc)
|
||||
+{
|
||||
+ vop2_vp_dsp_lut_disable(vp);
|
||||
+ vop2_cfg_done(vp);
|
||||
+ if (!vop2_vp_dsp_lut_poll_disabled(vp))
|
||||
+ return;
|
||||
+
|
||||
+ vop2_writel(vop2, RK3568_LUT_PORT_SEL, vp->id);
|
||||
+ vop2_crtc_write_gamma_lut(vop2, crtc);
|
||||
+ vop2_vp_dsp_lut_enable(vp);
|
||||
+}
|
||||
+
|
||||
+static void vop2_crtc_atomic_try_set_gamma(struct vop2 *vop2,
|
||||
+ struct vop2_video_port *vp,
|
||||
+ struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *crtc_state)
|
||||
+{
|
||||
+ if (!vop2->lut_regs || !crtc_state->color_mgmt_changed)
|
||||
+ return;
|
||||
+
|
||||
+ if (!crtc_state->gamma_lut) {
|
||||
+ vop2_vp_dsp_lut_disable(vp);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (vop2_supports_seamless_gamma_lut_update(vop2))
|
||||
+ vop2_crtc_atomic_set_gamma_seamless(vop2, vp, crtc);
|
||||
+ else
|
||||
+ vop2_crtc_atomic_set_gamma_rk356x(vop2, vp, crtc);
|
||||
+}
|
||||
+
|
||||
+static inline void vop2_crtc_atomic_try_set_gamma_locked(struct vop2 *vop2,
|
||||
+ struct vop2_video_port *vp,
|
||||
+ struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *crtc_state)
|
||||
+{
|
||||
+ vop2_lock(vop2);
|
||||
+ vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state);
|
||||
+ vop2_unlock(vop2);
|
||||
+}
|
||||
+
|
||||
static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
@@ -2107,11 +2248,40 @@ static void vop2_crtc_atomic_enable(stru
|
||||
|
||||
vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
|
||||
|
||||
+ vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state);
|
||||
+
|
||||
drm_crtc_vblank_on(crtc);
|
||||
|
||||
vop2_unlock(vop2);
|
||||
}
|
||||
|
||||
+static int vop2_crtc_atomic_check_gamma(struct vop2_video_port *vp,
|
||||
+ struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state,
|
||||
+ struct drm_crtc_state *crtc_state)
|
||||
+{
|
||||
+ struct vop2 *vop2 = vp->vop2;
|
||||
+ unsigned int len;
|
||||
+
|
||||
+ if (!vp->vop2->lut_regs || !crtc_state->color_mgmt_changed ||
|
||||
+ !crtc_state->gamma_lut)
|
||||
+ return 0;
|
||||
+
|
||||
+ len = drm_color_lut_size(crtc_state->gamma_lut);
|
||||
+ if (len != crtc->gamma_size) {
|
||||
+ drm_dbg(vop2->drm, "Invalid LUT size; got %d, expected %d\n",
|
||||
+ len, crtc->gamma_size);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!vop2_supports_seamless_gamma_lut_update(vop2) && vop2_gamma_lut_in_use(vop2, vp)) {
|
||||
+ drm_info(vop2->drm, "Gamma LUT can be enabled for only one CRTC at a time\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
@@ -2119,6 +2289,11 @@ static int vop2_crtc_atomic_check(struct
|
||||
struct drm_plane *plane;
|
||||
int nplanes = 0;
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = vop2_crtc_atomic_check_gamma(vp, crtc, state, crtc_state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
|
||||
nplanes++;
|
||||
@@ -2582,7 +2757,13 @@ static void vop2_crtc_atomic_begin(struc
|
||||
static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
+ struct vop2 *vop2 = vp->vop2;
|
||||
+
|
||||
+ /* In case of modeset, gamma lut update already happened in atomic enable */
|
||||
+ if (!drm_atomic_crtc_needs_modeset(crtc_state))
|
||||
+ vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state);
|
||||
|
||||
vop2_post_config(crtc);
|
||||
|
||||
@@ -2885,7 +3066,12 @@ static int vop2_create_crtcs(struct vop2
|
||||
}
|
||||
|
||||
drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
|
||||
+ if (vop2->lut_regs) {
|
||||
+ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
|
||||
|
||||
+ drm_mode_crtc_set_gamma_size(&vp->crtc, vp_data->gamma_lut_len);
|
||||
+ drm_crtc_enable_color_mgmt(&vp->crtc, 0, false, vp_data->gamma_lut_len);
|
||||
+ }
|
||||
init_completion(&vp->dsp_hold_completion);
|
||||
}
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -404,6 +404,7 @@ enum dst_factor_mode {
|
||||
#define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN BIT(15)
|
||||
|
||||
#define RK3568_VP_DSP_CTRL__STANDBY BIT(31)
|
||||
+#define RK3568_VP_DSP_CTRL__DSP_LUT_EN BIT(28)
|
||||
#define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE BIT(20)
|
||||
#define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL GENMASK(19, 18)
|
||||
#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN BIT(17)
|
||||
@@ -418,6 +419,8 @@ enum dst_factor_mode {
|
||||
#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV BIT(4)
|
||||
#define RK3568_VP_DSP_CTRL__OUT_MODE GENMASK(3, 0)
|
||||
|
||||
+#define RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN BIT(22)
|
||||
+
|
||||
#define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2)
|
||||
#define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0)
|
||||
|
||||
@@ -470,6 +473,8 @@ enum dst_factor_mode {
|
||||
#define RK3588_DSP_IF_POL__DP1_PIN_POL GENMASK(14, 12)
|
||||
#define RK3588_DSP_IF_POL__DP0_PIN_POL GENMASK(10, 8)
|
||||
|
||||
+#define RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL GENMASK(13, 12)
|
||||
+
|
||||
#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK BIT(5)
|
||||
#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2 BIT(4)
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
From 86caee745e4506528801d9542db54e7b4c4d834b Mon Sep 17 00:00:00 2001
|
||||
From: Lucas Stach <l.stach@pengutronix.de>
|
||||
Date: Fri, 21 Jun 2024 22:17:55 +0200
|
||||
Subject: [PATCH] drm/rockchip: analogix_dp: allow to work without panel
|
||||
|
||||
When the DP output is routed to a external connector there is no
|
||||
need for a fixed panel, as the panel may be detected via EDID on
|
||||
the AUX channel. Allow to continue probing if no panel reference
|
||||
is present.
|
||||
|
||||
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20240621201755.500271-1-l.stach@pengutronix.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
@@ -386,7 +386,7 @@ static int rockchip_dp_probe(struct plat
|
||||
return -ENODEV;
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
|
||||
- if (ret < 0)
|
||||
+ if (ret < 0 && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
|
||||
@ -0,0 +1,32 @@
|
||||
From 4b64b4a81fcd51f570c046cf904aef19ec756d45 Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Fri, 18 Oct 2024 15:10:10 +0000
|
||||
Subject: [PATCH] drm/rockchip: avoid 64-bit division
|
||||
|
||||
Dividing a 64-bit integer prevents building this for 32-bit targets:
|
||||
|
||||
ERROR: modpost: "__aeabi_uldivmod" [drivers/gpu/drm/rockchip/rockchipdrm.ko] undefined!
|
||||
|
||||
As this function is not performance criticial, just Use the div_u64() helper.
|
||||
|
||||
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20241018151016.3496613-1-arnd@kernel.org
|
||||
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -82,7 +82,7 @@ static void dw_hdmi_qp_rockchip_encoder_
|
||||
* comment in rk_hdptx_phy_power_on() from
|
||||
* drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
|
||||
*/
|
||||
- phy_set_bus_width(hdmi->phy, rate / 100);
|
||||
+ phy_set_bus_width(hdmi->phy, div_u64(rate, 100));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,574 @@
|
||||
From 9f1e1e14f59de8e5a62226840abecbcdbd50221a Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Date: Tue, 10 Dec 2024 00:10:21 +0100
|
||||
Subject: [PATCH] drm/rockchip: Add MIPI DSI2 glue driver for RK3588
|
||||
|
||||
This adds the glue code for the MIPI DSI2 bridge on Rockchip SoCs and
|
||||
enables its use on the RK3588.
|
||||
|
||||
Right now the DSI2 controller is always paired with a DC-phy based on a
|
||||
Samsung IP, so the interface values are set statically for now.
|
||||
This stays true for the upcoming RK3576 as well.
|
||||
|
||||
Tested-by: Daniel Semkowicz <dse@thaumatec.com>
|
||||
Tested-by: Dmitry Yashin <dmt.yashin@gmail.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241209231021.2180582-4-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/Kconfig | 10 +
|
||||
drivers/gpu/drm/rockchip/Makefile | 1 +
|
||||
.../gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 487 ++++++++++++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
|
||||
5 files changed, 501 insertions(+)
|
||||
create mode 100644 drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/Kconfig
|
||||
+++ b/drivers/gpu/drm/rockchip/Kconfig
|
||||
@@ -11,6 +11,7 @@ config DRM_ROCKCHIP
|
||||
select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
|
||||
select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP
|
||||
select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
|
||||
+ select DRM_DW_MIPI_DSI2 if ROCKCHIP_DW_MIPI_DSI2
|
||||
select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI
|
||||
select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI
|
||||
select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
|
||||
@@ -82,6 +83,15 @@ config ROCKCHIP_DW_MIPI_DSI
|
||||
enable MIPI DSI on RK3288 or RK3399 based SoC, you should
|
||||
select this option.
|
||||
|
||||
+config ROCKCHIP_DW_MIPI_DSI2
|
||||
+ bool "Rockchip specific extensions for Synopsys DW MIPI DSI2"
|
||||
+ select GENERIC_PHY_MIPI_DPHY
|
||||
+ help
|
||||
+ This selects support for Rockchip SoC specific extensions
|
||||
+ for the Synopsys DesignWare DSI2 driver. If you want to
|
||||
+ enable MIPI DSI on RK3576 or RK3588 based SoC, you should
|
||||
+ select this option.
|
||||
+
|
||||
config ROCKCHIP_INNO_HDMI
|
||||
bool "Rockchip specific extensions for Innosilicon HDMI"
|
||||
select DRM_DISPLAY_HDMI_HELPER
|
||||
--- a/drivers/gpu/drm/rockchip/Makefile
|
||||
+++ b/drivers/gpu/drm/rockchip/Makefile
|
||||
@@ -13,6 +13,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) +=
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
|
||||
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi2-rockchip.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
|
||||
@@ -0,0 +1,487 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2024 Rockchip Electronics Co., Ltd.
|
||||
+ * Author:
|
||||
+ * Guochun Huang <hero.huang@rock-chips.com>
|
||||
+ * Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/component.h>
|
||||
+#include <linux/media-bus-format.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+
|
||||
+#include <drm/bridge/dw_mipi_dsi2.h>
|
||||
+#include <drm/drm_mipi_dsi.h>
|
||||
+#include <drm/drm_of.h>
|
||||
+#include <drm/drm_simple_kms_helper.h>
|
||||
+
|
||||
+#include <uapi/linux/videodev2.h>
|
||||
+
|
||||
+#include "rockchip_drm_drv.h"
|
||||
+
|
||||
+#define PSEC_PER_SEC 1000000000000LL
|
||||
+
|
||||
+struct dsigrf_reg {
|
||||
+ u16 offset;
|
||||
+ u16 lsb;
|
||||
+ u16 msb;
|
||||
+};
|
||||
+
|
||||
+enum grf_reg_fields {
|
||||
+ TXREQCLKHS_EN,
|
||||
+ GATING_EN,
|
||||
+ IPI_SHUTDN,
|
||||
+ IPI_COLORM,
|
||||
+ IPI_COLOR_DEPTH,
|
||||
+ IPI_FORMAT,
|
||||
+ MAX_FIELDS,
|
||||
+};
|
||||
+
|
||||
+#define IPI_DEPTH_5_6_5_BITS 0x02
|
||||
+#define IPI_DEPTH_6_BITS 0x03
|
||||
+#define IPI_DEPTH_8_BITS 0x05
|
||||
+#define IPI_DEPTH_10_BITS 0x06
|
||||
+
|
||||
+struct rockchip_dw_dsi2_chip_data {
|
||||
+ u32 reg;
|
||||
+ const struct dsigrf_reg *grf_regs;
|
||||
+ unsigned long long max_bit_rate_per_lane;
|
||||
+};
|
||||
+
|
||||
+struct dw_mipi_dsi2_rockchip {
|
||||
+ struct device *dev;
|
||||
+ struct rockchip_encoder encoder;
|
||||
+ struct regmap *regmap;
|
||||
+
|
||||
+ unsigned int lane_mbps; /* per lane */
|
||||
+ u32 format;
|
||||
+
|
||||
+ struct regmap *grf_regmap;
|
||||
+ struct phy *phy;
|
||||
+ union phy_configure_opts phy_opts;
|
||||
+
|
||||
+ struct dw_mipi_dsi2 *dmd;
|
||||
+ struct dw_mipi_dsi2_plat_data pdata;
|
||||
+ const struct rockchip_dw_dsi2_chip_data *cdata;
|
||||
+};
|
||||
+
|
||||
+static inline struct dw_mipi_dsi2_rockchip *to_dsi2(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
||||
+
|
||||
+ return container_of(rkencoder, struct dw_mipi_dsi2_rockchip, encoder);
|
||||
+}
|
||||
+
|
||||
+static void grf_field_write(struct dw_mipi_dsi2_rockchip *dsi2, enum grf_reg_fields index,
|
||||
+ unsigned int val)
|
||||
+{
|
||||
+ const struct dsigrf_reg *field = &dsi2->cdata->grf_regs[index];
|
||||
+
|
||||
+ if (!field)
|
||||
+ return;
|
||||
+
|
||||
+ regmap_write(dsi2->grf_regmap, field->offset,
|
||||
+ (val << field->lsb) | (GENMASK(field->msb, field->lsb) << 16));
|
||||
+}
|
||||
+
|
||||
+static int dw_mipi_dsi2_phy_init(void *priv_data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void dw_mipi_dsi2_phy_power_on(void *priv_data)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = phy_set_mode(dsi2->phy, PHY_MODE_MIPI_DPHY);
|
||||
+ if (ret) {
|
||||
+ dev_err(dsi2->dev, "Failed to set phy mode: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ phy_configure(dsi2->phy, &dsi2->phy_opts);
|
||||
+ phy_power_on(dsi2->phy);
|
||||
+}
|
||||
+
|
||||
+static void dw_mipi_dsi2_phy_power_off(void *priv_data)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+
|
||||
+ phy_power_off(dsi2->phy);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dw_mipi_dsi2_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
|
||||
+ unsigned long mode_flags, u32 lanes, u32 format,
|
||||
+ unsigned int *lane_mbps)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+ u64 max_lane_rate, target_phyclk;
|
||||
+ unsigned int lane_rate_kbps;
|
||||
+ int bpp;
|
||||
+
|
||||
+ max_lane_rate = dsi2->cdata->max_bit_rate_per_lane;
|
||||
+
|
||||
+ dsi2->format = format;
|
||||
+ bpp = mipi_dsi_pixel_format_to_bpp(format);
|
||||
+ if (bpp < 0) {
|
||||
+ dev_err(dsi2->dev, "failed to get bpp for pixel format %d\n", format);
|
||||
+ return bpp;
|
||||
+ }
|
||||
+
|
||||
+ lane_rate_kbps = mode->clock * bpp / lanes;
|
||||
+
|
||||
+ /*
|
||||
+ * Set BW a little larger only in video burst mode in
|
||||
+ * consideration of the protocol overhead and HS mode
|
||||
+ * switching to BLLP mode, take 1 / 0.9, since Mbps must
|
||||
+ * big than bandwidth of RGB
|
||||
+ */
|
||||
+ if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
|
||||
+ lane_rate_kbps = (lane_rate_kbps * 10) / 9;
|
||||
+
|
||||
+ if (lane_rate_kbps > max_lane_rate) {
|
||||
+ dev_err(dsi2->dev, "DPHY clock frequency is out of range\n");
|
||||
+ return -ERANGE;
|
||||
+ }
|
||||
+
|
||||
+ dsi2->lane_mbps = lane_rate_kbps / 1000;
|
||||
+ *lane_mbps = dsi2->lane_mbps;
|
||||
+
|
||||
+ if (dsi2->phy) {
|
||||
+ target_phyclk = DIV_ROUND_CLOSEST_ULL(lane_rate_kbps * lanes * 1000, bpp);
|
||||
+ phy_mipi_dphy_get_default_config(target_phyclk, bpp, lanes,
|
||||
+ &dsi2->phy_opts.mipi_dphy);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void dw_mipi_dsi2_phy_get_iface(void *priv_data, struct dw_mipi_dsi2_phy_iface *iface)
|
||||
+{
|
||||
+ /* PPI width is fixed to 16 bits in DCPHY */
|
||||
+ iface->ppi_width = 16;
|
||||
+ iface->phy_type = DW_MIPI_DSI2_DPHY;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dw_mipi_dsi2_phy_get_timing(void *priv_data, unsigned int lane_mbps,
|
||||
+ struct dw_mipi_dsi2_phy_timing *timing)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+ struct phy_configure_opts_mipi_dphy *cfg = &dsi2->phy_opts.mipi_dphy;
|
||||
+ unsigned long long tmp, ui;
|
||||
+ unsigned long long hstx_clk;
|
||||
+
|
||||
+ hstx_clk = DIV_ROUND_CLOSEST_ULL(dsi2->lane_mbps * USEC_PER_SEC, 16);
|
||||
+
|
||||
+ ui = ALIGN(PSEC_PER_SEC, hstx_clk);
|
||||
+ do_div(ui, hstx_clk);
|
||||
+
|
||||
+ /* PHY_LP2HS_TIME = (TLPX + THS-PREPARE + THS-ZERO) / Tphy_hstx_clk */
|
||||
+ tmp = cfg->lpx + cfg->hs_prepare + cfg->hs_zero;
|
||||
+ tmp = DIV_ROUND_CLOSEST_ULL(tmp << 16, ui);
|
||||
+ timing->data_lp2hs = tmp;
|
||||
+
|
||||
+ /* PHY_HS2LP_TIME = (THS-TRAIL + THS-EXIT) / Tphy_hstx_clk */
|
||||
+ tmp = cfg->hs_trail + cfg->hs_exit;
|
||||
+ tmp = DIV_ROUND_CLOSEST_ULL(tmp << 16, ui);
|
||||
+ timing->data_hs2lp = tmp;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct dw_mipi_dsi2_phy_ops dw_mipi_dsi2_rockchip_phy_ops = {
|
||||
+ .init = dw_mipi_dsi2_phy_init,
|
||||
+ .power_on = dw_mipi_dsi2_phy_power_on,
|
||||
+ .power_off = dw_mipi_dsi2_phy_power_off,
|
||||
+ .get_interface = dw_mipi_dsi2_phy_get_iface,
|
||||
+ .get_lane_mbps = dw_mipi_dsi2_get_lane_mbps,
|
||||
+ .get_timing = dw_mipi_dsi2_phy_get_timing,
|
||||
+};
|
||||
+
|
||||
+static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = to_dsi2(encoder);
|
||||
+ u32 color_depth;
|
||||
+
|
||||
+ switch (dsi2->format) {
|
||||
+ case MIPI_DSI_FMT_RGB666:
|
||||
+ case MIPI_DSI_FMT_RGB666_PACKED:
|
||||
+ color_depth = IPI_DEPTH_6_BITS;
|
||||
+ break;
|
||||
+ case MIPI_DSI_FMT_RGB565:
|
||||
+ color_depth = IPI_DEPTH_5_6_5_BITS;
|
||||
+ break;
|
||||
+ case MIPI_DSI_FMT_RGB888:
|
||||
+ color_depth = IPI_DEPTH_8_BITS;
|
||||
+ break;
|
||||
+ default:
|
||||
+ /* Should've been caught by atomic_check */
|
||||
+ WARN_ON(1);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ grf_field_write(dsi2, IPI_COLOR_DEPTH, color_depth);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = to_dsi2(encoder);
|
||||
+ struct drm_connector *connector = conn_state->connector;
|
||||
+ struct drm_display_info *info = &connector->display_info;
|
||||
+
|
||||
+ switch (dsi2->format) {
|
||||
+ case MIPI_DSI_FMT_RGB666:
|
||||
+ case MIPI_DSI_FMT_RGB666_PACKED:
|
||||
+ s->output_mode = ROCKCHIP_OUT_MODE_P666;
|
||||
+ break;
|
||||
+ case MIPI_DSI_FMT_RGB565:
|
||||
+ s->output_mode = ROCKCHIP_OUT_MODE_P565;
|
||||
+ break;
|
||||
+ case MIPI_DSI_FMT_RGB888:
|
||||
+ s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN_ON(1);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (info->num_bus_formats)
|
||||
+ s->bus_format = info->bus_formats[0];
|
||||
+ else
|
||||
+ s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+
|
||||
+ s->output_type = DRM_MODE_CONNECTOR_DSI;
|
||||
+ s->bus_flags = info->bus_flags;
|
||||
+ s->color_space = V4L2_COLORSPACE_DEFAULT;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct drm_encoder_helper_funcs
|
||||
+dw_mipi_dsi2_encoder_helper_funcs = {
|
||||
+ .atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
|
||||
+ .atomic_check = dw_mipi_dsi2_encoder_atomic_check,
|
||||
+};
|
||||
+
|
||||
+static int rockchip_dsi2_drm_create_encoder(struct dw_mipi_dsi2_rockchip *dsi2,
|
||||
+ struct drm_device *drm_dev)
|
||||
+{
|
||||
+ struct drm_encoder *encoder = &dsi2->encoder.encoder;
|
||||
+ int ret;
|
||||
+
|
||||
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
|
||||
+ dsi2->dev->of_node);
|
||||
+
|
||||
+ ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
|
||||
+ if (ret) {
|
||||
+ dev_err(dsi2->dev, "Failed to initialize encoder with drm\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ drm_encoder_helper_add(encoder, &dw_mipi_dsi2_encoder_helper_funcs);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dw_mipi_dsi2_rockchip_bind(struct device *dev, struct device *master,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = dev_get_drvdata(dev);
|
||||
+ struct drm_device *drm_dev = data;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = rockchip_dsi2_drm_create_encoder(dsi2, drm_dev);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Failed to create drm encoder\n");
|
||||
+
|
||||
+ rockchip_drm_encoder_set_crtc_endpoint_id(&dsi2->encoder,
|
||||
+ dev->of_node, 0, 0);
|
||||
+
|
||||
+ ret = dw_mipi_dsi2_bind(dsi2->dmd, &dsi2->encoder.encoder);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Failed to bind\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void dw_mipi_dsi2_rockchip_unbind(struct device *dev, struct device *master,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = dev_get_drvdata(dev);
|
||||
+
|
||||
+ dw_mipi_dsi2_unbind(dsi2->dmd);
|
||||
+}
|
||||
+
|
||||
+static const struct component_ops dw_mipi_dsi2_rockchip_ops = {
|
||||
+ .bind = dw_mipi_dsi2_rockchip_bind,
|
||||
+ .unbind = dw_mipi_dsi2_rockchip_unbind,
|
||||
+};
|
||||
+
|
||||
+static int dw_mipi_dsi2_rockchip_host_attach(void *priv_data,
|
||||
+ struct mipi_dsi_device *device)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = component_add(dsi2->dev, &dw_mipi_dsi2_rockchip_ops);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dsi2->dev, ret, "Failed to register component\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dw_mipi_dsi2_rockchip_host_detach(void *priv_data,
|
||||
+ struct mipi_dsi_device *device)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
|
||||
+
|
||||
+ component_del(dsi2->dev, &dw_mipi_dsi2_rockchip_ops);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct dw_mipi_dsi2_host_ops dw_mipi_dsi2_rockchip_host_ops = {
|
||||
+ .attach = dw_mipi_dsi2_rockchip_host_attach,
|
||||
+ .detach = dw_mipi_dsi2_rockchip_host_detach,
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config dw_mipi_dsi2_rockchip_regmap_config = {
|
||||
+ .name = "dsi2-host",
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .fast_io = true,
|
||||
+};
|
||||
+
|
||||
+static int dw_mipi_dsi2_rockchip_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ const struct rockchip_dw_dsi2_chip_data *cdata =
|
||||
+ of_device_get_match_data(dev);
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2;
|
||||
+ struct resource *res;
|
||||
+ void __iomem *base;
|
||||
+ int i;
|
||||
+
|
||||
+ dsi2 = devm_kzalloc(dev, sizeof(*dsi2), GFP_KERNEL);
|
||||
+ if (!dsi2)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
+ if (IS_ERR(base))
|
||||
+ return dev_err_probe(dev, PTR_ERR(base), "Unable to get dsi registers\n");
|
||||
+
|
||||
+ dsi2->regmap = devm_regmap_init_mmio(dev, base, &dw_mipi_dsi2_rockchip_regmap_config);
|
||||
+ if (IS_ERR(dsi2->regmap))
|
||||
+ return dev_err_probe(dev, PTR_ERR(dsi2->regmap), "failed to init register map\n");
|
||||
+
|
||||
+ i = 0;
|
||||
+ while (cdata[i].reg) {
|
||||
+ if (cdata[i].reg == res->start) {
|
||||
+ dsi2->cdata = &cdata[i];
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (!dsi2->cdata)
|
||||
+ return dev_err_probe(dev, -EINVAL, "No dsi-config for %s node\n", np->name);
|
||||
+
|
||||
+ dsi2->grf_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
||||
+ if (IS_ERR(dsi2->grf_regmap))
|
||||
+ return dev_err_probe(dsi2->dev, PTR_ERR(dsi2->grf_regmap), "Unable to get grf\n");
|
||||
+
|
||||
+ dsi2->phy = devm_phy_optional_get(dev, "dcphy");
|
||||
+ if (IS_ERR(dsi2->phy))
|
||||
+ return dev_err_probe(dev, PTR_ERR(dsi2->phy), "failed to get mipi phy\n");
|
||||
+
|
||||
+ dsi2->dev = dev;
|
||||
+ dsi2->pdata.regmap = dsi2->regmap;
|
||||
+ dsi2->pdata.max_data_lanes = 4;
|
||||
+ dsi2->pdata.phy_ops = &dw_mipi_dsi2_rockchip_phy_ops;
|
||||
+ dsi2->pdata.host_ops = &dw_mipi_dsi2_rockchip_host_ops;
|
||||
+ dsi2->pdata.priv_data = dsi2;
|
||||
+ platform_set_drvdata(pdev, dsi2);
|
||||
+
|
||||
+ dsi2->dmd = dw_mipi_dsi2_probe(pdev, &dsi2->pdata);
|
||||
+ if (IS_ERR(dsi2->dmd))
|
||||
+ return dev_err_probe(dev, PTR_ERR(dsi2->dmd), "Failed to probe dw_mipi_dsi2\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void dw_mipi_dsi2_rockchip_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct dw_mipi_dsi2_rockchip *dsi2 = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ dw_mipi_dsi2_remove(dsi2->dmd);
|
||||
+}
|
||||
+
|
||||
+static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = {
|
||||
+ [TXREQCLKHS_EN] = { 0x0000, 11, 11 },
|
||||
+ [GATING_EN] = { 0x0000, 10, 10 },
|
||||
+ [IPI_SHUTDN] = { 0x0000, 9, 9 },
|
||||
+ [IPI_COLORM] = { 0x0000, 8, 8 },
|
||||
+ [IPI_COLOR_DEPTH] = { 0x0000, 4, 7 },
|
||||
+ [IPI_FORMAT] = { 0x0000, 0, 3 },
|
||||
+};
|
||||
+
|
||||
+static const struct dsigrf_reg rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = {
|
||||
+ [TXREQCLKHS_EN] = { 0x0004, 11, 11 },
|
||||
+ [GATING_EN] = { 0x0004, 10, 10 },
|
||||
+ [IPI_SHUTDN] = { 0x0004, 9, 9 },
|
||||
+ [IPI_COLORM] = { 0x0004, 8, 8 },
|
||||
+ [IPI_COLOR_DEPTH] = { 0x0004, 4, 7 },
|
||||
+ [IPI_FORMAT] = { 0x0004, 0, 3 },
|
||||
+};
|
||||
+
|
||||
+static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = {
|
||||
+ {
|
||||
+ .reg = 0xfde20000,
|
||||
+ .grf_regs = rk3588_dsi0_grf_reg_fields,
|
||||
+ .max_bit_rate_per_lane = 4500000ULL,
|
||||
+ },
|
||||
+ {
|
||||
+ .reg = 0xfde30000,
|
||||
+ .grf_regs = rk3588_dsi1_grf_reg_fields,
|
||||
+ .max_bit_rate_per_lane = 4500000ULL,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = {
|
||||
+ {
|
||||
+ .compatible = "rockchip,rk3588-mipi-dsi2",
|
||||
+ .data = &rk3588_chip_data,
|
||||
+ },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, dw_mipi_dsi2_rockchip_dt_ids);
|
||||
+
|
||||
+struct platform_driver dw_mipi_dsi2_rockchip_driver = {
|
||||
+ .probe = dw_mipi_dsi2_rockchip_probe,
|
||||
+ .remove_new = dw_mipi_dsi2_rockchip_remove,
|
||||
+ .driver = {
|
||||
+ .of_match_table = dw_mipi_dsi2_rockchip_dt_ids,
|
||||
+ .name = "dw-mipi-dsi2",
|
||||
+ },
|
||||
+};
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -536,6 +536,8 @@ static int __init rockchip_drm_init(void
|
||||
CONFIG_ROCKCHIP_DW_HDMI_QP);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
|
||||
CONFIG_ROCKCHIP_DW_MIPI_DSI);
|
||||
+ ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi2_rockchip_driver,
|
||||
+ CONFIG_ROCKCHIP_DW_MIPI_DSI2);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
|
||||
ADD_ROCKCHIP_SUB_DRIVER(rk3066_hdmi_driver,
|
||||
CONFIG_ROCKCHIP_RK3066_HDMI);
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
|
||||
@@ -90,6 +90,7 @@ extern struct platform_driver cdn_dp_dri
|
||||
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
|
||||
extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver;
|
||||
extern struct platform_driver dw_mipi_dsi_rockchip_driver;
|
||||
+extern struct platform_driver dw_mipi_dsi2_rockchip_driver;
|
||||
extern struct platform_driver inno_hdmi_driver;
|
||||
extern struct platform_driver rockchip_dp_driver;
|
||||
extern struct platform_driver rockchip_lvds_driver;
|
||||
@ -0,0 +1,254 @@
|
||||
From 0f818db20c77506ddd870761785740f8230a4207 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Wed, 11 Dec 2024 01:06:14 +0200
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi_qp: Add support for RK3588 HDMI1 output
|
||||
|
||||
Provide the basic support required to enable the second HDMI TX port
|
||||
found on RK3588 SoC.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Tested-by: Alexandre ARNOUD <aarnoud@me.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241211-rk3588-hdmi1-v2-1-02cdca22ff68@collabora.com
|
||||
---
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 119 ++++++++++++++----
|
||||
1 file changed, 96 insertions(+), 23 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -28,20 +28,26 @@
|
||||
#define RK3588_GRF_SOC_CON2 0x0308
|
||||
#define RK3588_HDMI0_HPD_INT_MSK BIT(13)
|
||||
#define RK3588_HDMI0_HPD_INT_CLR BIT(12)
|
||||
+#define RK3588_HDMI1_HPD_INT_MSK BIT(15)
|
||||
+#define RK3588_HDMI1_HPD_INT_CLR BIT(14)
|
||||
#define RK3588_GRF_SOC_CON7 0x031c
|
||||
#define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12)
|
||||
#define RK3588_GRF_SOC_STATUS1 0x0384
|
||||
#define RK3588_HDMI0_LEVEL_INT BIT(16)
|
||||
+#define RK3588_HDMI1_LEVEL_INT BIT(24)
|
||||
#define RK3588_GRF_VO1_CON3 0x000c
|
||||
+#define RK3588_GRF_VO1_CON6 0x0018
|
||||
#define RK3588_SCLIN_MASK BIT(9)
|
||||
#define RK3588_SDAIN_MASK BIT(10)
|
||||
#define RK3588_MODE_MASK BIT(11)
|
||||
#define RK3588_I2S_SEL_MASK BIT(13)
|
||||
#define RK3588_GRF_VO1_CON9 0x0024
|
||||
#define RK3588_HDMI0_GRANT_SEL BIT(10)
|
||||
+#define RK3588_HDMI1_GRANT_SEL BIT(12)
|
||||
|
||||
#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16)
|
||||
#define HOTPLUG_DEBOUNCE_MS 150
|
||||
+#define MAX_HDMI_PORT_NUM 2
|
||||
|
||||
struct rockchip_hdmi_qp {
|
||||
struct device *dev;
|
||||
@@ -53,6 +59,7 @@ struct rockchip_hdmi_qp {
|
||||
struct phy *phy;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct delayed_work hpd_work;
|
||||
+ int port_id;
|
||||
};
|
||||
|
||||
static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
|
||||
@@ -127,20 +134,24 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdm
|
||||
u32 val;
|
||||
|
||||
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val);
|
||||
+ val &= hdmi->port_id ? RK3588_HDMI1_LEVEL_INT : RK3588_HDMI0_LEVEL_INT;
|
||||
|
||||
- return val & RK3588_HDMI0_LEVEL_INT ?
|
||||
- connector_status_connected : connector_status_disconnected;
|
||||
+ return val ? connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+ u32 val;
|
||||
+
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR,
|
||||
+ RK3588_HDMI1_HPD_INT_CLR | RK3588_HDMI1_HPD_INT_MSK);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
+ RK3588_HDMI0_HPD_INT_CLR | RK3588_HDMI0_HPD_INT_MSK);
|
||||
|
||||
- regmap_write(hdmi->regmap,
|
||||
- RK3588_GRF_SOC_CON2,
|
||||
- HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
- RK3588_HDMI0_HPD_INT_CLR |
|
||||
- RK3588_HDMI0_HPD_INT_MSK));
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
|
||||
@@ -173,8 +184,12 @@ static irqreturn_t dw_hdmi_qp_rk3588_har
|
||||
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
|
||||
|
||||
if (intr_stat) {
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK,
|
||||
- RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK,
|
||||
+ RK3588_HDMI1_HPD_INT_MSK);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK,
|
||||
+ RK3588_HDMI0_HPD_INT_MSK);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
@@ -191,22 +206,44 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq
|
||||
if (!intr_stat)
|
||||
return IRQ_NONE;
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
- RK3588_HDMI0_HPD_INT_CLR);
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_CLR,
|
||||
+ RK3588_HDMI1_HPD_INT_CLR);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
|
||||
+ RK3588_HDMI0_HPD_INT_CLR);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
|
||||
mod_delayed_work(system_wq, &hdmi->hpd_work,
|
||||
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
|
||||
|
||||
- val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ if (hdmi->port_id)
|
||||
+ val |= HIWORD_UPDATE(0, RK3588_HDMI1_HPD_INT_MSK);
|
||||
+ else
|
||||
+ val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+struct rockchip_hdmi_qp_cfg {
|
||||
+ unsigned int num_ports;
|
||||
+ unsigned int port_ids[MAX_HDMI_PORT_NUM];
|
||||
+ const struct dw_hdmi_qp_phy_ops *phy_ops;
|
||||
+};
|
||||
+
|
||||
+static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cfg = {
|
||||
+ .num_ports = 2,
|
||||
+ .port_ids = {
|
||||
+ 0xfde80000,
|
||||
+ 0xfdea0000,
|
||||
+ },
|
||||
+ .phy_ops = &rk3588_hdmi_phy_ops,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
|
||||
{ .compatible = "rockchip,rk3588-dw-hdmi-qp",
|
||||
- .data = &rk3588_hdmi_phy_ops },
|
||||
+ .data = &rk3588_hdmi_cfg },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
|
||||
@@ -219,11 +256,13 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
"ref" /* keep "ref" last */
|
||||
};
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
+ const struct rockchip_hdmi_qp_cfg *cfg;
|
||||
struct dw_hdmi_qp_plat_data plat_data;
|
||||
struct drm_device *drm = data;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_hdmi_qp *hdmi;
|
||||
+ struct resource *res;
|
||||
struct clk *clk;
|
||||
int ret, irq, i;
|
||||
u32 val;
|
||||
@@ -235,12 +274,31 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
- plat_data.phy_ops = of_device_get_match_data(dev);
|
||||
- if (!plat_data.phy_ops)
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ cfg = of_device_get_match_data(dev);
|
||||
+ if (!cfg)
|
||||
return -ENODEV;
|
||||
|
||||
- plat_data.phy_data = hdmi;
|
||||
hdmi->dev = &pdev->dev;
|
||||
+ hdmi->port_id = -ENODEV;
|
||||
+
|
||||
+ /* Identify port ID by matching base IO address */
|
||||
+ for (i = 0; i < cfg->num_ports; i++) {
|
||||
+ if (res->start == cfg->port_ids[i]) {
|
||||
+ hdmi->port_id = i;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (hdmi->port_id < 0) {
|
||||
+ drm_err(hdmi, "Failed to match HDMI port ID\n");
|
||||
+ return hdmi->port_id;
|
||||
+ }
|
||||
+
|
||||
+ plat_data.phy_ops = cfg->phy_ops;
|
||||
+ plat_data.phy_data = hdmi;
|
||||
|
||||
encoder = &hdmi->encoder.encoder;
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
@@ -303,17 +361,26 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
- regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
|
||||
+ regmap_write(hdmi->vo_regmap,
|
||||
+ hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
|
||||
+ val);
|
||||
|
||||
val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
RK3588_SET_HPD_PATH_MASK);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
- RK3588_HDMI0_GRANT_SEL);
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
|
||||
+ RK3588_HDMI1_GRANT_SEL);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
+ RK3588_HDMI0_GRANT_SEL);
|
||||
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
|
||||
INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
|
||||
@@ -391,14 +458,20 @@ static int __maybe_unused dw_hdmi_qp_roc
|
||||
HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
- regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val);
|
||||
+ regmap_write(hdmi->vo_regmap,
|
||||
+ hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
|
||||
+ val);
|
||||
|
||||
val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
RK3588_SET_HPD_PATH_MASK);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
- RK3588_HDMI0_GRANT_SEL);
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
|
||||
+ RK3588_HDMI1_GRANT_SEL);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
+ RK3588_HDMI0_GRANT_SEL);
|
||||
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
|
||||
dw_hdmi_qp_resume(dev, hdmi->hdmi);
|
||||
@ -0,0 +1,27 @@
|
||||
From 8ddc8dfb8329349d5efb0418c9f20025333e2d98 Mon Sep 17 00:00:00 2001
|
||||
From: Guoqing Jiang <guoqing.jiang@canonical.com>
|
||||
Date: Fri, 6 Dec 2024 19:42:33 +0800
|
||||
Subject: [PATCH] drm/rockchip: Remove unnecessary checking
|
||||
|
||||
It is not needed since drm_atomic_helper_shutdown checks it.
|
||||
|
||||
Signed-off-by: Guoqing Jiang <guoqing.jiang@canonical.com>
|
||||
Acked-by: Andy Yan <andyshrk@163.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241206114233.1270989-1-guoqing.jiang@canonical.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -488,8 +488,7 @@ static void rockchip_drm_platform_shutdo
|
||||
{
|
||||
struct drm_device *drm = platform_get_drvdata(pdev);
|
||||
|
||||
- if (drm)
|
||||
- drm_atomic_helper_shutdown(drm);
|
||||
+ drm_atomic_helper_shutdown(drm);
|
||||
}
|
||||
|
||||
static const struct of_device_id rockchip_drm_dt_ids[] = {
|
||||
@ -0,0 +1,42 @@
|
||||
From 9c22b6ece2e5c2308f41ba4bec27cfa158397fa7 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Date: Fri, 6 Dec 2024 19:26:10 +0000
|
||||
Subject: [PATCH] drm/rockchip: vop2: don't check color_mgmt_changed in
|
||||
atomic_enable
|
||||
|
||||
Remove color_mgmt_changed check from vop2_crtc_atomic_try_set_gamma to
|
||||
allow gamma LUT rewrite during modeset when coming out of suspend. Add
|
||||
a check for color_mgmt_changed directly in vop2_crtc_atomic_flush.
|
||||
|
||||
This patch fixes the patch adding gamma LUT support for vop2 [1].
|
||||
|
||||
[1] https://lore.kernel.org/linux-rockchip/20241101185545.559090-3-pZ010001011111@proton.me/
|
||||
|
||||
Suggested-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241206192013.342692-3-pZ010001011111@proton.me
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -1628,7 +1628,7 @@ static void vop2_crtc_atomic_try_set_gam
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
- if (!vop2->lut_regs || !crtc_state->color_mgmt_changed)
|
||||
+ if (!vop2->lut_regs)
|
||||
return;
|
||||
|
||||
if (!crtc_state->gamma_lut) {
|
||||
@@ -2762,7 +2762,7 @@ static void vop2_crtc_atomic_flush(struc
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
|
||||
/* In case of modeset, gamma lut update already happened in atomic enable */
|
||||
- if (!drm_atomic_crtc_needs_modeset(crtc_state))
|
||||
+ if (!drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->color_mgmt_changed)
|
||||
vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state);
|
||||
|
||||
vop2_post_config(crtc);
|
||||
@ -0,0 +1,69 @@
|
||||
From 19851fa2ba9824bede16f55234f63d9423897c3d Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Mon, 2 Dec 2024 22:27:34 +0200
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi_qp: Simplify clock handling
|
||||
|
||||
Make use of the recently introduced devm_clk_bulk_get_all_enabled()
|
||||
helper to simplify the code a bit.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241202-dw-hdmi-qp-rk-clk-bulk-v1-1-60a7cc9cd74e@collabora.com
|
||||
---
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 28 +++++++++----------
|
||||
1 file changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -251,10 +251,6 @@ MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockc
|
||||
static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
- static const char * const clk_names[] = {
|
||||
- "pclk", "earc", "aud", "hdp", "hclk_vo1",
|
||||
- "ref" /* keep "ref" last */
|
||||
- };
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const struct rockchip_hdmi_qp_cfg *cfg;
|
||||
struct dw_hdmi_qp_plat_data plat_data;
|
||||
@@ -263,7 +259,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_hdmi_qp *hdmi;
|
||||
struct resource *res;
|
||||
- struct clk *clk;
|
||||
+ struct clk_bulk_data *clks;
|
||||
int ret, irq, i;
|
||||
u32 val;
|
||||
|
||||
@@ -328,18 +324,22 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
return PTR_ERR(hdmi->vo_regmap);
|
||||
}
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(clk_names); i++) {
|
||||
- clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]);
|
||||
+ ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
|
||||
+ if (ret < 0) {
|
||||
+ drm_err(hdmi, "Failed to get clocks: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
- if (IS_ERR(clk)) {
|
||||
- ret = PTR_ERR(clk);
|
||||
- if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "Failed to get %s clock: %d\n",
|
||||
- clk_names[i], ret);
|
||||
- return ret;
|
||||
+ for (i = 0; i < ret; i++) {
|
||||
+ if (!strcmp(clks[i].id, "ref")) {
|
||||
+ hdmi->ref_clk = clks[1].clk;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
- hdmi->ref_clk = clk;
|
||||
+ if (!hdmi->ref_clk) {
|
||||
+ drm_err(hdmi, "Missing ref clock\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
|
||||
GPIOD_OUT_HIGH);
|
||||
@ -0,0 +1,586 @@
|
||||
From 779964556c64cd3d76ddfeb34738ef78020fae84 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Sat, 14 Dec 2024 16:17:00 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Add debugfs support
|
||||
|
||||
/sys/kernel/debug/dri/vop2/summary: dump vop display state
|
||||
/sys/kernel/debug/dri/vop2/regs: dump whole vop registers
|
||||
/sys/kernel/debug/dri/vop2/active_regs: only dump the registers of
|
||||
activated modules
|
||||
|
||||
Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de>
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241214081719.3330518-2-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 258 +++++++++++++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 11 +
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 191 ++++++++++++++
|
||||
3 files changed, 460 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -24,9 +24,11 @@
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
+#include <linux/debugfs.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_flip_work.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
+#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
@@ -186,6 +188,7 @@ struct vop2 {
|
||||
*/
|
||||
u32 registered_num_wins;
|
||||
|
||||
+ struct resource *res;
|
||||
void __iomem *regs;
|
||||
struct regmap *map;
|
||||
|
||||
@@ -240,6 +243,37 @@ struct vop2 {
|
||||
|
||||
#define vop2_output_if_is_dpi(x) ((x) == ROCKCHIP_VOP2_EP_RGB0)
|
||||
|
||||
+/*
|
||||
+ * bus-format types.
|
||||
+ */
|
||||
+struct drm_bus_format_enum_list {
|
||||
+ int type;
|
||||
+ const char *name;
|
||||
+};
|
||||
+
|
||||
+static const struct drm_bus_format_enum_list drm_bus_format_enum_list[] = {
|
||||
+ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
|
||||
+ { MEDIA_BUS_FMT_RGB565_1X16, "RGB565_1X16" },
|
||||
+ { MEDIA_BUS_FMT_RGB666_1X18, "RGB666_1X18" },
|
||||
+ { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, "RGB666_1X24_CPADHI" },
|
||||
+ { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, "RGB666_1X7X3_SPWG" },
|
||||
+ { MEDIA_BUS_FMT_YUV8_1X24, "YUV8_1X24" },
|
||||
+ { MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24" },
|
||||
+ { MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30" },
|
||||
+ { MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30" },
|
||||
+ { MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8" },
|
||||
+ { MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24" },
|
||||
+ { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, "RGB888_1X7X4_SPWG" },
|
||||
+ { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, "RGB888_1X7X4_JEIDA" },
|
||||
+ { MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" },
|
||||
+ { MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" },
|
||||
+ { MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" },
|
||||
+ { MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1X30" },
|
||||
+ { MEDIA_BUS_FMT_YUYV10_1X20, "YUYV10_1X20" },
|
||||
+};
|
||||
+
|
||||
+static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list)
|
||||
+
|
||||
static const struct regmap_config vop2_regmap_config;
|
||||
|
||||
static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
|
||||
@@ -2789,6 +2823,228 @@ static const struct drm_crtc_helper_func
|
||||
.atomic_disable = vop2_crtc_atomic_disable,
|
||||
};
|
||||
|
||||
+static void vop2_dump_connector_on_crtc(struct drm_crtc *crtc, struct seq_file *s)
|
||||
+{
|
||||
+ struct drm_connector_list_iter conn_iter;
|
||||
+ struct drm_connector *connector;
|
||||
+
|
||||
+ drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
||||
+ drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
+ if (crtc->state->connector_mask & drm_connector_mask(connector))
|
||||
+ seq_printf(s, " Connector: %s\n", connector->name);
|
||||
+ }
|
||||
+ drm_connector_list_iter_end(&conn_iter);
|
||||
+}
|
||||
+
|
||||
+static int vop2_plane_state_dump(struct seq_file *s, struct drm_plane *plane)
|
||||
+{
|
||||
+ struct vop2_win *win = to_vop2_win(plane);
|
||||
+ struct drm_plane_state *pstate = plane->state;
|
||||
+ struct drm_rect *src, *dst;
|
||||
+ struct drm_framebuffer *fb;
|
||||
+ struct drm_gem_object *obj;
|
||||
+ struct rockchip_gem_object *rk_obj;
|
||||
+ bool xmirror;
|
||||
+ bool ymirror;
|
||||
+ bool rotate_270;
|
||||
+ bool rotate_90;
|
||||
+ dma_addr_t fb_addr;
|
||||
+ int i;
|
||||
+
|
||||
+ seq_printf(s, " %s: %s\n", win->data->name, !pstate ?
|
||||
+ "DISABLED" : pstate->crtc ? "ACTIVE" : "DISABLED");
|
||||
+
|
||||
+ if (!pstate || !pstate->fb)
|
||||
+ return 0;
|
||||
+
|
||||
+ fb = pstate->fb;
|
||||
+ src = &pstate->src;
|
||||
+ dst = &pstate->dst;
|
||||
+ xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false;
|
||||
+ ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false;
|
||||
+ rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270;
|
||||
+ rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90;
|
||||
+
|
||||
+ seq_printf(s, "\twin_id: %d\n", win->win_id);
|
||||
+
|
||||
+ seq_printf(s, "\tformat: %p4cc%s glb_alpha[0x%x]\n",
|
||||
+ &fb->format->format,
|
||||
+ drm_is_afbc(fb->modifier) ? "[AFBC]" : "",
|
||||
+ pstate->alpha >> 8);
|
||||
+ seq_printf(s, "\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n",
|
||||
+ xmirror, ymirror, rotate_90, rotate_270);
|
||||
+ seq_printf(s, "\tzpos: %d\n", pstate->normalized_zpos);
|
||||
+ seq_printf(s, "\tsrc: pos[%d, %d] rect[%d x %d]\n", src->x1 >> 16,
|
||||
+ src->y1 >> 16, drm_rect_width(src) >> 16,
|
||||
+ drm_rect_height(src) >> 16);
|
||||
+ seq_printf(s, "\tdst: pos[%d, %d] rect[%d x %d]\n", dst->x1, dst->y1,
|
||||
+ drm_rect_width(dst), drm_rect_height(dst));
|
||||
+
|
||||
+ for (i = 0; i < fb->format->num_planes; i++) {
|
||||
+ obj = fb->obj[i];
|
||||
+ rk_obj = to_rockchip_obj(obj);
|
||||
+ fb_addr = rk_obj->dma_addr + fb->offsets[i];
|
||||
+
|
||||
+ seq_printf(s, "\tbuf[%d]: addr: %pad pitch: %d offset: %d\n",
|
||||
+ i, &fb_addr, fb->pitches[i], fb->offsets[i]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s)
|
||||
+{
|
||||
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
+ struct drm_crtc_state *cstate = crtc->state;
|
||||
+ struct rockchip_crtc_state *vcstate;
|
||||
+ struct drm_display_mode *mode;
|
||||
+ struct drm_plane *plane;
|
||||
+ bool interlaced;
|
||||
+
|
||||
+ seq_printf(s, "Video Port%d: %s\n", vp->id, !cstate ?
|
||||
+ "DISABLED" : cstate->active ? "ACTIVE" : "DISABLED");
|
||||
+
|
||||
+ if (!cstate || !cstate->active)
|
||||
+ return 0;
|
||||
+
|
||||
+ mode = &crtc->state->adjusted_mode;
|
||||
+ vcstate = to_rockchip_crtc_state(cstate);
|
||||
+ interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
+
|
||||
+ vop2_dump_connector_on_crtc(crtc, s);
|
||||
+ seq_printf(s, "\tbus_format[%x]: %s\n", vcstate->bus_format,
|
||||
+ drm_get_bus_format_name(vcstate->bus_format));
|
||||
+ seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode);
|
||||
+ seq_printf(s, " color_space[%d]\n", vcstate->color_space);
|
||||
+ seq_printf(s, " Display mode: %dx%d%s%d\n",
|
||||
+ mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p",
|
||||
+ drm_mode_vrefresh(mode));
|
||||
+ seq_printf(s, "\tclk[%d] real_clk[%d] type[%x] flag[%x]\n",
|
||||
+ mode->clock, mode->crtc_clock, mode->type, mode->flags);
|
||||
+ seq_printf(s, "\tH: %d %d %d %d\n", mode->hdisplay, mode->hsync_start,
|
||||
+ mode->hsync_end, mode->htotal);
|
||||
+ seq_printf(s, "\tV: %d %d %d %d\n", mode->vdisplay, mode->vsync_start,
|
||||
+ mode->vsync_end, mode->vtotal);
|
||||
+
|
||||
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
|
||||
+ vop2_plane_state_dump(s, plane);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vop2_summary_show(struct seq_file *s, void *data)
|
||||
+{
|
||||
+ struct drm_info_node *node = s->private;
|
||||
+ struct drm_minor *minor = node->minor;
|
||||
+ struct drm_device *drm_dev = minor->dev;
|
||||
+ struct drm_crtc *crtc;
|
||||
+
|
||||
+ drm_modeset_lock_all(drm_dev);
|
||||
+ drm_for_each_crtc(crtc, drm_dev) {
|
||||
+ vop2_crtc_state_dump(crtc, s);
|
||||
+ }
|
||||
+ drm_modeset_unlock_all(drm_dev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void vop2_regs_print(struct vop2 *vop2, struct seq_file *s,
|
||||
+ const struct vop2_regs_dump *dump, bool active_only)
|
||||
+{
|
||||
+ resource_size_t start;
|
||||
+ u32 val;
|
||||
+ int i;
|
||||
+
|
||||
+ if (dump->en_mask && active_only) {
|
||||
+ val = vop2_readl(vop2, dump->base + dump->en_reg);
|
||||
+ if ((val & dump->en_mask) != dump->en_val)
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ seq_printf(s, "\n%s:\n", dump->name);
|
||||
+
|
||||
+ start = vop2->res->start + dump->base;
|
||||
+ for (i = 0; i < dump->size >> 2; i += 4) {
|
||||
+ seq_printf(s, "%08x: %08x %08x %08x %08x\n", (u32)start + i * 4,
|
||||
+ vop2_readl(vop2, dump->base + (4 * i)),
|
||||
+ vop2_readl(vop2, dump->base + (4 * (i + 1))),
|
||||
+ vop2_readl(vop2, dump->base + (4 * (i + 2))),
|
||||
+ vop2_readl(vop2, dump->base + (4 * (i + 3))));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void __vop2_regs_dump(struct seq_file *s, bool active_only)
|
||||
+{
|
||||
+ struct drm_info_node *node = s->private;
|
||||
+ struct vop2 *vop2 = node->info_ent->data;
|
||||
+ struct drm_minor *minor = node->minor;
|
||||
+ struct drm_device *drm_dev = minor->dev;
|
||||
+ const struct vop2_regs_dump *dump;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ drm_modeset_lock_all(drm_dev);
|
||||
+
|
||||
+ regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register);
|
||||
+
|
||||
+ if (vop2->enable_count) {
|
||||
+ for (i = 0; i < vop2->data->regs_dump_size; i++) {
|
||||
+ dump = &vop2->data->regs_dump[i];
|
||||
+ vop2_regs_print(vop2, s, dump, active_only);
|
||||
+ }
|
||||
+ } else {
|
||||
+ seq_puts(s, "VOP disabled\n");
|
||||
+ }
|
||||
+ drm_modeset_unlock_all(drm_dev);
|
||||
+}
|
||||
+
|
||||
+static int vop2_regs_show(struct seq_file *s, void *arg)
|
||||
+{
|
||||
+ __vop2_regs_dump(s, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vop2_active_regs_show(struct seq_file *s, void *data)
|
||||
+{
|
||||
+ __vop2_regs_dump(s, true);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct drm_info_list vop2_debugfs_list[] = {
|
||||
+ { "summary", vop2_summary_show, 0, NULL },
|
||||
+ { "active_regs", vop2_active_regs_show, 0, NULL },
|
||||
+ { "regs", vop2_regs_show, 0, NULL },
|
||||
+};
|
||||
+
|
||||
+static void vop2_debugfs_init(struct vop2 *vop2, struct drm_minor *minor)
|
||||
+{
|
||||
+ struct dentry *root;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ root = debugfs_create_dir("vop2", minor->debugfs_root);
|
||||
+ if (!IS_ERR(root)) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(vop2_debugfs_list); i++)
|
||||
+ vop2_debugfs_list[i].data = vop2;
|
||||
+
|
||||
+ drm_debugfs_create_files(vop2_debugfs_list,
|
||||
+ ARRAY_SIZE(vop2_debugfs_list),
|
||||
+ root, minor);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int vop2_crtc_late_register(struct drm_crtc *crtc)
|
||||
+{
|
||||
+ struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
+ struct vop2 *vop2 = vp->vop2;
|
||||
+
|
||||
+ if (drm_crtc_index(crtc) == 0)
|
||||
+ vop2_debugfs_init(vop2, crtc->dev->primary);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate;
|
||||
@@ -2838,6 +3094,7 @@ static const struct drm_crtc_funcs vop2_
|
||||
.atomic_destroy_state = vop2_crtc_destroy_state,
|
||||
.enable_vblank = vop2_crtc_enable_vblank,
|
||||
.disable_vblank = vop2_crtc_disable_vblank,
|
||||
+ .late_register = vop2_crtc_late_register,
|
||||
};
|
||||
|
||||
static irqreturn_t vop2_isr(int irq, void *data)
|
||||
@@ -3395,6 +3652,7 @@ static int vop2_bind(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ vop2->res = res;
|
||||
vop2->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(vop2->regs))
|
||||
return PTR_ERR(vop2->regs);
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -126,6 +126,15 @@ enum vop2_win_regs {
|
||||
VOP2_WIN_MAX_REG,
|
||||
};
|
||||
|
||||
+struct vop2_regs_dump {
|
||||
+ const char *name;
|
||||
+ u32 base;
|
||||
+ u32 size;
|
||||
+ u32 en_reg;
|
||||
+ u32 en_val;
|
||||
+ u32 en_mask;
|
||||
+};
|
||||
+
|
||||
struct vop2_win_data {
|
||||
const char *name;
|
||||
unsigned int phys_id;
|
||||
@@ -168,10 +177,12 @@ struct vop2_data {
|
||||
u64 feature;
|
||||
const struct vop2_win_data *win;
|
||||
const struct vop2_video_port_data *vp;
|
||||
+ const struct vop2_regs_dump *regs_dump;
|
||||
struct vop_rect max_input;
|
||||
struct vop_rect max_output;
|
||||
|
||||
unsigned int win_size;
|
||||
+ unsigned int regs_dump_size;
|
||||
unsigned int soc_id;
|
||||
};
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -258,6 +258,88 @@ static const struct vop2_win_data rk3568
|
||||
},
|
||||
};
|
||||
|
||||
+static const struct vop2_regs_dump rk3568_regs_dump[] = {
|
||||
+ {
|
||||
+ .name = "SYS",
|
||||
+ .base = RK3568_REG_CFG_DONE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = 0,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = 0
|
||||
+ }, {
|
||||
+ .name = "OVL",
|
||||
+ .base = RK3568_OVL_CTRL,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = 0,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = 0,
|
||||
+ }, {
|
||||
+ .name = "VP0",
|
||||
+ .base = RK3568_VP0_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+ }, {
|
||||
+ .name = "VP1",
|
||||
+ .base = RK3568_VP1_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+ }, {
|
||||
+ .name = "VP2",
|
||||
+ .base = RK3568_VP2_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+
|
||||
+ }, {
|
||||
+ .name = "Cluster0",
|
||||
+ .base = RK3568_CLUSTER0_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Cluster1",
|
||||
+ .base = RK3568_CLUSTER1_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart0",
|
||||
+ .base = RK3568_ESMART0_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart1",
|
||||
+ .base = RK3568_ESMART1_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Smart0",
|
||||
+ .base = RK3568_SMART0_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Smart1",
|
||||
+ .base = RK3568_SMART1_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
|
||||
{
|
||||
.id = 0,
|
||||
@@ -462,6 +544,109 @@ static const struct vop2_win_data rk3588
|
||||
},
|
||||
};
|
||||
|
||||
+static const struct vop2_regs_dump rk3588_regs_dump[] = {
|
||||
+ {
|
||||
+ .name = "SYS",
|
||||
+ .base = RK3568_REG_CFG_DONE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = 0,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = 0
|
||||
+ }, {
|
||||
+ .name = "OVL",
|
||||
+ .base = RK3568_OVL_CTRL,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = 0,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = 0,
|
||||
+ }, {
|
||||
+ .name = "VP0",
|
||||
+ .base = RK3568_VP0_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+ }, {
|
||||
+ .name = "VP1",
|
||||
+ .base = RK3568_VP1_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+ }, {
|
||||
+ .name = "VP2",
|
||||
+ .base = RK3568_VP2_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+
|
||||
+ }, {
|
||||
+ .name = "VP3",
|
||||
+ .base = RK3588_VP3_CTRL_BASE,
|
||||
+ .size = 0x100,
|
||||
+ .en_reg = RK3568_VP_DSP_CTRL,
|
||||
+ .en_val = 0,
|
||||
+ .en_mask = RK3568_VP_DSP_CTRL__STANDBY,
|
||||
+ }, {
|
||||
+ .name = "Cluster0",
|
||||
+ .base = RK3568_CLUSTER0_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Cluster1",
|
||||
+ .base = RK3568_CLUSTER1_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Cluster2",
|
||||
+ .base = RK3588_CLUSTER2_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Cluster3",
|
||||
+ .base = RK3588_CLUSTER3_CTRL_BASE,
|
||||
+ .size = 0x110,
|
||||
+ .en_reg = RK3568_CLUSTER_WIN_CTRL0,
|
||||
+ .en_val = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ .en_mask = RK3568_CLUSTER_WIN_CTRL0__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart0",
|
||||
+ .base = RK3568_ESMART0_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart1",
|
||||
+ .base = RK3568_ESMART1_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart2",
|
||||
+ .base = RK3588_ESMART2_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ }, {
|
||||
+ .name = "Esmart3",
|
||||
+ .base = RK3588_ESMART3_CTRL_BASE,
|
||||
+ .size = 0xf0,
|
||||
+ .en_reg = RK3568_SMART_REGION0_CTRL,
|
||||
+ .en_val = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ .en_mask = RK3568_SMART_REGION0_CTRL__WIN0_EN,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct vop2_data rk3566_vop = {
|
||||
.feature = VOP2_FEATURE_HAS_SYS_GRF,
|
||||
.nr_vps = 3,
|
||||
@@ -470,6 +655,8 @@ static const struct vop2_data rk3566_vop
|
||||
.vp = rk3568_vop_video_ports,
|
||||
.win = rk3568_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3568_vop_win_data),
|
||||
+ .regs_dump = rk3568_regs_dump,
|
||||
+ .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump),
|
||||
.soc_id = 3566,
|
||||
};
|
||||
|
||||
@@ -481,6 +668,8 @@ static const struct vop2_data rk3568_vop
|
||||
.vp = rk3568_vop_video_ports,
|
||||
.win = rk3568_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3568_vop_win_data),
|
||||
+ .regs_dump = rk3568_regs_dump,
|
||||
+ .regs_dump_size = ARRAY_SIZE(rk3568_regs_dump),
|
||||
.soc_id = 3568,
|
||||
};
|
||||
|
||||
@@ -493,6 +682,8 @@ static const struct vop2_data rk3588_vop
|
||||
.vp = rk3588_vop_video_ports,
|
||||
.win = rk3588_vop_win_data,
|
||||
.win_size = ARRAY_SIZE(rk3588_vop_win_data),
|
||||
+ .regs_dump = rk3588_regs_dump,
|
||||
+ .regs_dump_size = ARRAY_SIZE(rk3588_regs_dump),
|
||||
.soc_id = 3588,
|
||||
};
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
From 938fbb16aba8f7b88e0fdcf56f315a5bbad41aad Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 31 Dec 2024 17:07:44 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Support 32x8 superblock afbc
|
||||
|
||||
This is the only afbc format supported by the upcoming
|
||||
VOP for rk3576.
|
||||
|
||||
Add support for it.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241231090802.251787-2-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 17 +++++++++++++----
|
||||
1 file changed, 13 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -1459,16 +1459,18 @@ static void vop2_plane_atomic_update(str
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en);
|
||||
|
||||
if (afbc_en) {
|
||||
- u32 stride;
|
||||
+ u32 stride, block_w;
|
||||
+
|
||||
+ /* the afbc superblock is 16 x 16 or 32 x 8 */
|
||||
+ block_w = fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 ? 32 : 16;
|
||||
|
||||
- /* the afbc superblock is 16 x 16 */
|
||||
afbc_format = vop2_convert_afbc_format(fb->format->format);
|
||||
|
||||
/* Enable color transform for YTR */
|
||||
if (fb->modifier & AFBC_FORMAT_MOD_YTR)
|
||||
afbc_format |= (1 << 4);
|
||||
|
||||
- afbc_tile_num = ALIGN(actual_w, 16) >> 4;
|
||||
+ afbc_tile_num = ALIGN(actual_w, block_w) / block_w;
|
||||
|
||||
/*
|
||||
* AFBC pic_vir_width is count by pixel, this is different
|
||||
@@ -1479,6 +1481,9 @@ static void vop2_plane_atomic_update(str
|
||||
drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n",
|
||||
vp->id, win->data->name, stride);
|
||||
|
||||
+ /* It's for head stride, each head size is 16 byte */
|
||||
+ stride = ALIGN(stride, block_w) / block_w * 16;
|
||||
+
|
||||
uv_swap = vop2_afbc_uv_swap(fb->format->format);
|
||||
/*
|
||||
* This is a workaround for crazy IC design, Cluster
|
||||
@@ -1509,7 +1514,11 @@ static void vop2_plane_atomic_update(str
|
||||
else
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);
|
||||
|
||||
- vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
|
||||
+ if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
|
||||
+ vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 1);
|
||||
+ else
|
||||
+ vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
|
||||
+
|
||||
transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);
|
||||
@ -0,0 +1,150 @@
|
||||
From 3f60dbd40d3f7aca312d1aa1131e204eb97a68b3 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 31 Dec 2024 17:44:17 +0800
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi_qp: Add platform ctrl callback
|
||||
|
||||
There are some control bits for IO and interrupts status scattered
|
||||
across different GRF on differt SOC.
|
||||
Add platform callback for this IO setting and interrupts status
|
||||
handling.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241231094425.253398-2-andyshrk@163.com
|
||||
---
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 79 ++++++++++++-------
|
||||
1 file changed, 51 insertions(+), 28 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -62,6 +62,12 @@ struct rockchip_hdmi_qp {
|
||||
int port_id;
|
||||
};
|
||||
|
||||
+struct rockchip_hdmi_qp_ctrl_ops {
|
||||
+ void (*io_init)(struct rockchip_hdmi_qp *hdmi);
|
||||
+ irqreturn_t (*irq_callback)(int irq, void *dev_id);
|
||||
+ irqreturn_t (*hardirq_callback)(int irq, void *dev_id);
|
||||
+};
|
||||
+
|
||||
static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
||||
@@ -226,9 +232,44 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
+ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
+ regmap_write(hdmi->vo_regmap,
|
||||
+ hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
|
||||
+ val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, RK3588_SET_HPD_PATH_MASK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
+
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL, RK3588_HDMI1_GRANT_SEL);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, RK3588_HDMI0_GRANT_SEL);
|
||||
+ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
+
|
||||
+ if (hdmi->port_id)
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK);
|
||||
+ else
|
||||
+ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+}
|
||||
+
|
||||
+static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = {
|
||||
+ .io_init = dw_hdmi_qp_rk3588_io_init,
|
||||
+ .irq_callback = dw_hdmi_qp_rk3588_irq,
|
||||
+ .hardirq_callback = dw_hdmi_qp_rk3588_hardirq,
|
||||
+};
|
||||
+
|
||||
struct rockchip_hdmi_qp_cfg {
|
||||
unsigned int num_ports;
|
||||
unsigned int port_ids[MAX_HDMI_PORT_NUM];
|
||||
+ const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
|
||||
const struct dw_hdmi_qp_phy_ops *phy_ops;
|
||||
};
|
||||
|
||||
@@ -238,6 +279,7 @@ static const struct rockchip_hdmi_qp_cfg
|
||||
0xfde80000,
|
||||
0xfdea0000,
|
||||
},
|
||||
+ .ctrl_ops = &rk3588_hdmi_ctrl_ops,
|
||||
.phy_ops = &rk3588_hdmi_phy_ops,
|
||||
};
|
||||
|
||||
@@ -261,7 +303,6 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
struct resource *res;
|
||||
struct clk_bulk_data *clks;
|
||||
int ret, irq, i;
|
||||
- u32 val;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
@@ -278,6 +319,12 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
if (!cfg)
|
||||
return -ENODEV;
|
||||
|
||||
+ if (!cfg->ctrl_ops || !cfg->ctrl_ops->io_init ||
|
||||
+ !cfg->ctrl_ops->irq_callback || !cfg->ctrl_ops->hardirq_callback) {
|
||||
+ dev_err(dev, "Missing platform ctrl ops\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
hdmi->dev = &pdev->dev;
|
||||
hdmi->port_id = -ENODEV;
|
||||
|
||||
@@ -357,31 +404,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
return ret;
|
||||
}
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
- regmap_write(hdmi->vo_regmap,
|
||||
- hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
|
||||
- val);
|
||||
-
|
||||
- val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
- RK3588_SET_HPD_PATH_MASK);
|
||||
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
-
|
||||
- if (hdmi->port_id)
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
|
||||
- RK3588_HDMI1_GRANT_SEL);
|
||||
- else
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
- RK3588_HDMI0_GRANT_SEL);
|
||||
- regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
-
|
||||
- if (hdmi->port_id)
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI1_HPD_INT_MSK, RK3588_HDMI1_HPD_INT_MSK);
|
||||
- else
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
|
||||
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
+ cfg->ctrl_ops->io_init(hdmi);
|
||||
|
||||
INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work);
|
||||
|
||||
@@ -394,8 +417,8 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
return irq;
|
||||
|
||||
ret = devm_request_threaded_irq(hdmi->dev, irq,
|
||||
- dw_hdmi_qp_rk3588_hardirq,
|
||||
- dw_hdmi_qp_rk3588_irq,
|
||||
+ cfg->ctrl_ops->hardirq_callback,
|
||||
+ cfg->ctrl_ops->irq_callback,
|
||||
IRQF_SHARED, "dw-hdmi-qp-hpd",
|
||||
hdmi);
|
||||
if (ret)
|
||||
@ -0,0 +1,211 @@
|
||||
From 36439120efbdc62e2f47053e7ddfcc4e34364640 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 31 Dec 2024 17:44:19 +0800
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi_qp: Add basic RK3576 HDMI output
|
||||
support
|
||||
|
||||
The HDMI on RK3576 shares the same IP block (PHY and Controller)
|
||||
with rk3588.
|
||||
However, there are some control bits scattered in different GRF.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241231094425.253398-4-andyshrk@163.com
|
||||
---
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 142 +++++++++++++++++-
|
||||
1 file changed, 140 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -25,6 +25,41 @@
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
|
||||
+#define RK3576_IOC_MISC_CON0 0xa400
|
||||
+#define RK3576_HDMI_HPD_INT_MSK BIT(2)
|
||||
+#define RK3576_HDMI_HPD_INT_CLR BIT(1)
|
||||
+
|
||||
+#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
|
||||
+#define RK3576_HDMI_LEVEL_INT BIT(3)
|
||||
+
|
||||
+#define RK3576_VO0_GRF_SOC_CON1 0x0004
|
||||
+#define RK3576_HDMI_FRL_MOD BIT(0)
|
||||
+#define RK3576_HDMI_HDCP14_MEM_EN BIT(15)
|
||||
+
|
||||
+#define RK3576_VO0_GRF_SOC_CON8 0x0020
|
||||
+#define RK3576_COLOR_FORMAT_MASK (0xf << 4)
|
||||
+#define RK3576_COLOR_DEPTH_MASK (0xf << 8)
|
||||
+#define RK3576_RGB (0 << 4)
|
||||
+#define RK3576_YUV422 (0x1 << 4)
|
||||
+#define RK3576_YUV444 (0x2 << 4)
|
||||
+#define RK3576_YUV420 (0x3 << 4)
|
||||
+#define RK3576_8BPC (0x0 << 8)
|
||||
+#define RK3576_10BPC (0x6 << 8)
|
||||
+#define RK3576_CECIN_MASK BIT(3)
|
||||
+
|
||||
+#define RK3576_VO0_GRF_SOC_CON12 0x0030
|
||||
+#define RK3576_GRF_OSDA_DLYN (0xf << 12)
|
||||
+#define RK3576_GRF_OSDA_DIV (0x7f << 1)
|
||||
+#define RK3576_GRF_OSDA_DLY_EN BIT(0)
|
||||
+
|
||||
+#define RK3576_VO0_GRF_SOC_CON14 0x0038
|
||||
+#define RK3576_I2S_SEL_MASK BIT(0)
|
||||
+#define RK3576_SPDIF_SEL_MASK BIT(1)
|
||||
+#define HDCP0_P1_GPIO_IN BIT(2)
|
||||
+#define RK3576_SCLIN_MASK BIT(4)
|
||||
+#define RK3576_SDAIN_MASK BIT(5)
|
||||
+#define RK3576_HDMI_GRANT_SEL BIT(6)
|
||||
+
|
||||
#define RK3588_GRF_SOC_CON2 0x0308
|
||||
#define RK3588_HDMI0_HPD_INT_MSK BIT(13)
|
||||
#define RK3588_HDMI0_HPD_INT_CLR BIT(12)
|
||||
@@ -167,6 +202,37 @@ static const struct dw_hdmi_qp_phy_ops r
|
||||
.setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
|
||||
};
|
||||
|
||||
+static enum drm_connector_status
|
||||
+dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+ u32 val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &val);
|
||||
+
|
||||
+ return val & RK3576_HDMI_LEVEL_INT ?
|
||||
+ connector_status_connected : connector_status_disconnected;
|
||||
+}
|
||||
+
|
||||
+static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_CLR,
|
||||
+ RK3576_HDMI_HPD_INT_CLR | RK3576_HDMI_HPD_INT_MSK);
|
||||
+
|
||||
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
|
||||
+}
|
||||
+
|
||||
+static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
|
||||
+ .init = dw_hdmi_qp_rk3588_phy_init,
|
||||
+ .disable = dw_hdmi_qp_rk3588_phy_disable,
|
||||
+ .read_hpd = dw_hdmi_qp_rk3576_read_hpd,
|
||||
+ .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
|
||||
+};
|
||||
+
|
||||
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = container_of(work,
|
||||
@@ -182,6 +248,43 @@ static void dw_hdmi_qp_rk3588_hpd_work(s
|
||||
}
|
||||
}
|
||||
|
||||
+static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
+ u32 intr_stat, val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
|
||||
+ if (intr_stat) {
|
||||
+ val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_MSK, RK3576_HDMI_HPD_INT_MSK);
|
||||
+
|
||||
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
+ return IRQ_WAKE_THREAD;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_NONE;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
+ u32 intr_stat, val;
|
||||
+
|
||||
+ regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
|
||||
+
|
||||
+ if (!intr_stat)
|
||||
+ return IRQ_NONE;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_CLR, RK3576_HDMI_HPD_INT_CLR);
|
||||
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
+ mod_delayed_work(system_wq, &hdmi->hpd_work,
|
||||
+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
|
||||
+
|
||||
+ val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
@@ -232,6 +335,21 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = HIWORD_UPDATE(RK3576_SCLIN_MASK, RK3576_SCLIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3576_SDAIN_MASK, RK3576_SDAIN_MASK) |
|
||||
+ HIWORD_UPDATE(RK3576_HDMI_GRANT_SEL, RK3576_HDMI_GRANT_SEL) |
|
||||
+ HIWORD_UPDATE(RK3576_I2S_SEL_MASK, RK3576_I2S_SEL_MASK);
|
||||
+
|
||||
+ regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
|
||||
+
|
||||
+ val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK);
|
||||
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
+}
|
||||
+
|
||||
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
|
||||
{
|
||||
u32 val;
|
||||
@@ -260,6 +378,12 @@ static void dw_hdmi_qp_rk3588_io_init(st
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
}
|
||||
|
||||
+static const struct rockchip_hdmi_qp_ctrl_ops rk3576_hdmi_ctrl_ops = {
|
||||
+ .io_init = dw_hdmi_qp_rk3576_io_init,
|
||||
+ .irq_callback = dw_hdmi_qp_rk3576_irq,
|
||||
+ .hardirq_callback = dw_hdmi_qp_rk3576_hardirq,
|
||||
+};
|
||||
+
|
||||
static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = {
|
||||
.io_init = dw_hdmi_qp_rk3588_io_init,
|
||||
.irq_callback = dw_hdmi_qp_rk3588_irq,
|
||||
@@ -273,6 +397,15 @@ struct rockchip_hdmi_qp_cfg {
|
||||
const struct dw_hdmi_qp_phy_ops *phy_ops;
|
||||
};
|
||||
|
||||
+static const struct rockchip_hdmi_qp_cfg rk3576_hdmi_cfg = {
|
||||
+ .num_ports = 1,
|
||||
+ .port_ids = {
|
||||
+ 0x27da0000,
|
||||
+ },
|
||||
+ .ctrl_ops = &rk3576_hdmi_ctrl_ops,
|
||||
+ .phy_ops = &rk3576_hdmi_phy_ops,
|
||||
+};
|
||||
+
|
||||
static const struct rockchip_hdmi_qp_cfg rk3588_hdmi_cfg = {
|
||||
.num_ports = 2,
|
||||
.port_ids = {
|
||||
@@ -284,8 +417,13 @@ static const struct rockchip_hdmi_qp_cfg
|
||||
};
|
||||
|
||||
static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = {
|
||||
- { .compatible = "rockchip,rk3588-dw-hdmi-qp",
|
||||
- .data = &rk3588_hdmi_cfg },
|
||||
+ {
|
||||
+ .compatible = "rockchip,rk3576-dw-hdmi-qp",
|
||||
+ .data = &rk3576_hdmi_cfg
|
||||
+ }, {
|
||||
+ .compatible = "rockchip,rk3588-dw-hdmi-qp",
|
||||
+ .data = &rk3588_hdmi_cfg
|
||||
+ },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
|
||||
@ -0,0 +1,60 @@
|
||||
From 1854df7087be70ad54e24b2e308d7558ebea9f27 Mon Sep 17 00:00:00 2001
|
||||
From: Derek Foreman <derek.foreman@collabora.com>
|
||||
Date: Tue, 17 Dec 2024 14:17:07 -0600
|
||||
Subject: [PATCH] drm/rockchip: Don't change hdmi reference clock rate
|
||||
|
||||
The code that changes hdmi->ref_clk was accidentally copied from
|
||||
downstream code that sets a different clock. We don't actually
|
||||
want to set any clock here at all.
|
||||
|
||||
Setting this clock incorrectly leads to incorrect timings for
|
||||
DDC, CEC, and HDCP signal generation.
|
||||
|
||||
No Fixes listed, as the theoretical timing error in DDC appears to
|
||||
still be within tolerances and harmless - and HDCP and CEC are not
|
||||
yet supported.
|
||||
|
||||
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
|
||||
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20241217201708.3320673-1-derek.foreman@collabora.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 13 -------------
|
||||
1 file changed, 13 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -89,7 +89,6 @@ struct rockchip_hdmi_qp {
|
||||
struct regmap *regmap;
|
||||
struct regmap *vo_regmap;
|
||||
struct rockchip_encoder encoder;
|
||||
- struct clk *ref_clk;
|
||||
struct dw_hdmi_qp *hdmi;
|
||||
struct phy *phy;
|
||||
struct gpio_desc *enable_gpio;
|
||||
@@ -122,7 +121,6 @@ static void dw_hdmi_qp_rockchip_encoder_
|
||||
if (crtc && crtc->state) {
|
||||
rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode,
|
||||
8, HDMI_COLORSPACE_RGB);
|
||||
- clk_set_rate(hdmi->ref_clk, rate);
|
||||
/*
|
||||
* FIXME: Temporary workaround to pass pixel clock rate
|
||||
* to the PHY driver until phy_configure_opts_hdmi
|
||||
@@ -515,17 +513,6 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
return ret;
|
||||
}
|
||||
|
||||
- for (i = 0; i < ret; i++) {
|
||||
- if (!strcmp(clks[i].id, "ref")) {
|
||||
- hdmi->ref_clk = clks[1].clk;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
- if (!hdmi->ref_clk) {
|
||||
- drm_err(hdmi, "Missing ref clock\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(hdmi->enable_gpio)) {
|
||||
@ -0,0 +1,30 @@
|
||||
From 9f40d7a94427a503e303b2a2d8db227d615e32c1 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Tue, 4 Feb 2025 14:40:05 +0200
|
||||
Subject: [PATCH] drm/rockchip: vop2: Drop unnecessary if_pixclk_rate
|
||||
computation
|
||||
|
||||
The if_pixclk_rate variable is not being used outside of the if-block in
|
||||
rk3588_calc_cru_cfg(), hence move the superfluous assignment from the
|
||||
first branch to the inner comment-block.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Tested-by: FUKAUMI Naoki <naoki@radxa.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250204-vop2-hdmi0-disp-modes-v3-2-d71c6a196e58@collabora.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -1908,8 +1908,8 @@ static unsigned long rk3588_calc_cru_cfg
|
||||
K = 2;
|
||||
}
|
||||
|
||||
- if_pixclk_rate = (dclk_core_rate << 1) / K;
|
||||
/*
|
||||
+ * if_pixclk_rate = (dclk_core_rate << 1) / K;
|
||||
* if_dclk_rate = dclk_core_rate / K;
|
||||
* *if_pixclk_div = dclk_rate / if_pixclk_rate;
|
||||
* *if_dclk_div = dclk_rate / if_dclk_rate;
|
||||
@ -0,0 +1,147 @@
|
||||
From 2bf9f610494d75cfaf3c8a0cef93135ce83f7254 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 24 Feb 2025 16:13:11 +0800
|
||||
Subject: [PATCH] drm/rockchip: analogix_dp: Use formalized struct definition
|
||||
for grf field
|
||||
|
||||
The formalized struct definition will makes grf field operations more
|
||||
concise and easier to extend.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250224081325.96724-2-damon.ding@rock-chips.com
|
||||
---
|
||||
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 77 +++++++++++--------
|
||||
1 file changed, 45 insertions(+), 32 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
@@ -32,26 +32,29 @@
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
|
||||
-#define RK3288_GRF_SOC_CON6 0x25c
|
||||
-#define RK3288_EDP_LCDC_SEL BIT(5)
|
||||
-#define RK3399_GRF_SOC_CON20 0x6250
|
||||
-#define RK3399_EDP_LCDC_SEL BIT(5)
|
||||
-
|
||||
-#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
|
||||
-
|
||||
#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100
|
||||
|
||||
+#define GRF_REG_FIELD(_reg, _lsb, _msb) { \
|
||||
+ .reg = _reg, \
|
||||
+ .lsb = _lsb, \
|
||||
+ .msb = _msb, \
|
||||
+ .valid = true, \
|
||||
+ }
|
||||
+
|
||||
+struct rockchip_grf_reg_field {
|
||||
+ u32 reg;
|
||||
+ u32 lsb;
|
||||
+ u32 msb;
|
||||
+ bool valid;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct rockchip_dp_chip_data - splite the grf setting of kind of chips
|
||||
- * @lcdsel_grf_reg: grf register offset of lcdc select
|
||||
- * @lcdsel_big: reg value of selecting vop big for eDP
|
||||
- * @lcdsel_lit: reg value of selecting vop little for eDP
|
||||
+ * @lcdc_sel: grf register field of lcdc_sel
|
||||
* @chip_type: specific chip type
|
||||
*/
|
||||
struct rockchip_dp_chip_data {
|
||||
- u32 lcdsel_grf_reg;
|
||||
- u32 lcdsel_big;
|
||||
- u32 lcdsel_lit;
|
||||
+ const struct rockchip_grf_reg_field lcdc_sel;
|
||||
u32 chip_type;
|
||||
};
|
||||
|
||||
@@ -84,6 +87,26 @@ static struct rockchip_dp_device *pdata_
|
||||
return container_of(plat_data, struct rockchip_dp_device, plat_data);
|
||||
}
|
||||
|
||||
+static int rockchip_grf_write(struct regmap *grf, u32 reg, u32 mask, u32 val)
|
||||
+{
|
||||
+ return regmap_write(grf, reg, (mask << 16) | (val & mask));
|
||||
+}
|
||||
+
|
||||
+static int rockchip_grf_field_write(struct regmap *grf,
|
||||
+ const struct rockchip_grf_reg_field *field,
|
||||
+ u32 val)
|
||||
+{
|
||||
+ u32 mask;
|
||||
+
|
||||
+ if (!field->valid)
|
||||
+ return 0;
|
||||
+
|
||||
+ mask = GENMASK(field->msb, field->lsb);
|
||||
+ val <<= field->lsb;
|
||||
+
|
||||
+ return rockchip_grf_write(grf, field->reg, mask, val);
|
||||
+}
|
||||
+
|
||||
static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
|
||||
{
|
||||
reset_control_assert(dp->rst);
|
||||
@@ -181,7 +204,6 @@ static void rockchip_dp_drm_encoder_enab
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int ret;
|
||||
- u32 val;
|
||||
|
||||
crtc = rockchip_dp_drm_get_new_crtc(encoder, state);
|
||||
if (!crtc)
|
||||
@@ -192,24 +214,19 @@ static void rockchip_dp_drm_encoder_enab
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
- ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
|
||||
- if (ret < 0)
|
||||
- return;
|
||||
-
|
||||
- if (ret)
|
||||
- val = dp->data->lcdsel_lit;
|
||||
- else
|
||||
- val = dp->data->lcdsel_big;
|
||||
-
|
||||
- DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
|
||||
-
|
||||
ret = clk_prepare_enable(dp->grfclk);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val);
|
||||
+ ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
|
||||
+ if (ret < 0)
|
||||
+ return;
|
||||
+
|
||||
+ DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
|
||||
+
|
||||
+ ret = rockchip_grf_field_write(dp->grf, &dp->data->lcdc_sel, ret);
|
||||
if (ret != 0)
|
||||
DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
|
||||
|
||||
@@ -448,16 +465,12 @@ static DEFINE_RUNTIME_DEV_PM_OPS(rockchi
|
||||
rockchip_dp_resume, NULL);
|
||||
|
||||
static const struct rockchip_dp_chip_data rk3399_edp = {
|
||||
- .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
|
||||
- .lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL),
|
||||
- .lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL),
|
||||
+ .lcdc_sel = GRF_REG_FIELD(0x6250, 5, 5),
|
||||
.chip_type = RK3399_EDP,
|
||||
};
|
||||
|
||||
static const struct rockchip_dp_chip_data rk3288_dp = {
|
||||
- .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
|
||||
- .lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL),
|
||||
- .lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL),
|
||||
+ .lcdc_sel = GRF_REG_FIELD(0x025c, 5, 5),
|
||||
.chip_type = RK3288_DP,
|
||||
};
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
From 718b3bb9c0ab87bc90914799e6999bf4b1ecc67b Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 24 Feb 2025 16:13:12 +0800
|
||||
Subject: [PATCH] drm/rockchip: analogix_dp: Expand device data to support
|
||||
multiple edp display
|
||||
|
||||
There are two main modifications: one is expanding struct
|
||||
rockchip_dp_chip_data to an array, and the other is adding
|
||||
&rockchip_dp_chip_data.reg to separate different edp devices.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250224081325.96724-3-damon.ding@rock-chips.com
|
||||
---
|
||||
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 41 +++++++++++++++----
|
||||
1 file changed, 34 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
@@ -52,10 +52,12 @@ struct rockchip_grf_reg_field {
|
||||
* struct rockchip_dp_chip_data - splite the grf setting of kind of chips
|
||||
* @lcdc_sel: grf register field of lcdc_sel
|
||||
* @chip_type: specific chip type
|
||||
+ * @reg: register base address
|
||||
*/
|
||||
struct rockchip_dp_chip_data {
|
||||
const struct rockchip_grf_reg_field lcdc_sel;
|
||||
u32 chip_type;
|
||||
+ u32 reg;
|
||||
};
|
||||
|
||||
struct rockchip_dp_device {
|
||||
@@ -396,6 +398,8 @@ static int rockchip_dp_probe(struct plat
|
||||
const struct rockchip_dp_chip_data *dp_data;
|
||||
struct drm_panel *panel = NULL;
|
||||
struct rockchip_dp_device *dp;
|
||||
+ struct resource *res;
|
||||
+ int i;
|
||||
int ret;
|
||||
|
||||
dp_data = of_device_get_match_data(dev);
|
||||
@@ -410,9 +414,24 @@ static int rockchip_dp_probe(struct plat
|
||||
if (!dp)
|
||||
return -ENOMEM;
|
||||
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+
|
||||
+ i = 0;
|
||||
+ while (dp_data[i].reg) {
|
||||
+ if (dp_data[i].reg == res->start) {
|
||||
+ dp->data = &dp_data[i];
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (!dp->data)
|
||||
+ return dev_err_probe(dev, -EINVAL, "no chip-data for %s node\n",
|
||||
+ dev->of_node->name);
|
||||
+
|
||||
dp->dev = dev;
|
||||
dp->adp = ERR_PTR(-ENODEV);
|
||||
- dp->data = dp_data;
|
||||
dp->plat_data.panel = panel;
|
||||
dp->plat_data.dev_type = dp->data->chip_type;
|
||||
dp->plat_data.power_on = rockchip_dp_poweron;
|
||||
@@ -464,14 +483,22 @@ static int rockchip_dp_resume(struct dev
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(rockchip_dp_pm_ops, rockchip_dp_suspend,
|
||||
rockchip_dp_resume, NULL);
|
||||
|
||||
-static const struct rockchip_dp_chip_data rk3399_edp = {
|
||||
- .lcdc_sel = GRF_REG_FIELD(0x6250, 5, 5),
|
||||
- .chip_type = RK3399_EDP,
|
||||
+static const struct rockchip_dp_chip_data rk3399_edp[] = {
|
||||
+ {
|
||||
+ .lcdc_sel = GRF_REG_FIELD(0x6250, 5, 5),
|
||||
+ .chip_type = RK3399_EDP,
|
||||
+ .reg = 0xff970000,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
};
|
||||
|
||||
-static const struct rockchip_dp_chip_data rk3288_dp = {
|
||||
- .lcdc_sel = GRF_REG_FIELD(0x025c, 5, 5),
|
||||
- .chip_type = RK3288_DP,
|
||||
+static const struct rockchip_dp_chip_data rk3288_dp[] = {
|
||||
+ {
|
||||
+ .lcdc_sel = GRF_REG_FIELD(0x025c, 5, 5),
|
||||
+ .chip_type = RK3288_DP,
|
||||
+ .reg = 0xff970000,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_dp_dt_ids[] = {
|
||||
@ -0,0 +1,83 @@
|
||||
From f8dd7fc9ba88bc4a6ea85269287a51fb756440e2 Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Sun, 23 Feb 2025 11:31:37 +0200
|
||||
Subject: [PATCH] drm/rockchip: vop2: Improve display modes handling on RK3588
|
||||
HDMI1
|
||||
|
||||
The RK3588 specific implementation is currently quite limited in terms
|
||||
of handling the full range of display modes supported by the connected
|
||||
screens, e.g. 2560x1440@75Hz, 2048x1152@60Hz, 1024x768@60Hz are just a
|
||||
few of them.
|
||||
|
||||
Additionally, it doesn't cope well with non-integer refresh rates like
|
||||
59.94, 29.97, 23.98, etc.
|
||||
|
||||
Make use of HDMI1 PHY PLL as a more accurate DCLK source to handle
|
||||
all display modes up to 4K@60Hz.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250223-vop2-hdmi1-disp-modes-v2-1-f4cec5e06fbe@collabora.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 25 +++++++++++++++++++-
|
||||
1 file changed, 24 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -216,6 +216,7 @@ struct vop2 {
|
||||
struct clk *aclk;
|
||||
struct clk *pclk;
|
||||
struct clk *pll_hdmiphy0;
|
||||
+ struct clk *pll_hdmiphy1;
|
||||
|
||||
/* optional internal rgb encoder */
|
||||
struct rockchip_rgb *rgb;
|
||||
@@ -2266,11 +2267,14 @@ static void vop2_crtc_atomic_enable(stru
|
||||
* Switch to HDMI PHY PLL as DCLK source for display modes up
|
||||
* to 4K@60Hz, if available, otherwise keep using the system CRU.
|
||||
*/
|
||||
- if (vop2->pll_hdmiphy0 && clock <= VOP2_MAX_DCLK_RATE) {
|
||||
+ if ((vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) && clock <= VOP2_MAX_DCLK_RATE) {
|
||||
drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
|
||||
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
|
||||
|
||||
if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) {
|
||||
+ if (!vop2->pll_hdmiphy0)
|
||||
+ break;
|
||||
+
|
||||
if (!vp->dclk_src)
|
||||
vp->dclk_src = clk_get_parent(vp->dclk);
|
||||
|
||||
@@ -2280,6 +2284,20 @@ static void vop2_crtc_atomic_enable(stru
|
||||
"Could not switch to HDMI0 PHY PLL: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) {
|
||||
+ if (!vop2->pll_hdmiphy1)
|
||||
+ break;
|
||||
+
|
||||
+ if (!vp->dclk_src)
|
||||
+ vp->dclk_src = clk_get_parent(vp->dclk);
|
||||
+
|
||||
+ ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1);
|
||||
+ if (ret < 0)
|
||||
+ drm_warn(vop2->drm,
|
||||
+ "Could not switch to HDMI1 PHY PLL: %d\n", ret);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3729,6 +3747,11 @@ static int vop2_bind(struct device *dev,
|
||||
return PTR_ERR(vop2->pll_hdmiphy0);
|
||||
}
|
||||
|
||||
+ vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1");
|
||||
+ if (IS_ERR(vop2->pll_hdmiphy1))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy1),
|
||||
+ "failed to get pll_hdmiphy1\n");
|
||||
+
|
||||
vop2->irq = platform_get_irq(pdev, 0);
|
||||
if (vop2->irq < 0) {
|
||||
drm_err(vop2->drm, "cannot find irq for vop2\n");
|
||||
@ -0,0 +1,183 @@
|
||||
From b06d1ef3355571383cdb463cf0195b7a02efdfbf Mon Sep 17 00:00:00 2001
|
||||
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Date: Sun, 23 Feb 2025 11:31:38 +0200
|
||||
Subject: [PATCH] drm/rockchip: vop2: Consistently use dev_err_probe()
|
||||
|
||||
Replace drm_err() calls in vop2_bind() and vop2_create_crtcs() with
|
||||
dev_err_probe(), to simplify error handling and improve consistency.
|
||||
|
||||
Additionally, ensure the already existing dev_err_probe() invocations
|
||||
pass drm->dev instead of dev as their first argument, so that we get the
|
||||
actual reason in case of -EPROBE_DEFER errors:
|
||||
|
||||
platform display-subsystem: deferred probe pending: (reason unknown)
|
||||
vs.
|
||||
platform display-subsystem: deferred probe pending: rockchip-drm: <actual reason>
|
||||
|
||||
While at it, add the missing '\n' to some of the message strings.
|
||||
|
||||
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250223-vop2-hdmi1-disp-modes-v2-2-f4cec5e06fbe@collabora.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 83 +++++++++-----------
|
||||
1 file changed, 37 insertions(+), 46 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -3269,10 +3269,9 @@ static int vop2_create_crtcs(struct vop2
|
||||
|
||||
snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
|
||||
vp->dclk = devm_clk_get(vop2->dev, dclk_name);
|
||||
- if (IS_ERR(vp->dclk)) {
|
||||
- drm_err(vop2->drm, "failed to get %s\n", dclk_name);
|
||||
- return PTR_ERR(vp->dclk);
|
||||
- }
|
||||
+ if (IS_ERR(vp->dclk))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vp->dclk),
|
||||
+ "failed to get %s\n", dclk_name);
|
||||
|
||||
np = of_graph_get_remote_node(dev->of_node, i, -1);
|
||||
if (!np) {
|
||||
@@ -3282,11 +3281,9 @@ static int vop2_create_crtcs(struct vop2
|
||||
of_node_put(np);
|
||||
|
||||
port = of_graph_get_port_by_id(dev->of_node, i);
|
||||
- if (!port) {
|
||||
- drm_err(vop2->drm, "no port node found for video_port%d\n", i);
|
||||
- return -ENOENT;
|
||||
- }
|
||||
-
|
||||
+ if (!port)
|
||||
+ return dev_err_probe(drm->dev, -ENOENT,
|
||||
+ "no port node found for video_port%d\n", i);
|
||||
vp->crtc.port = port;
|
||||
nvps++;
|
||||
}
|
||||
@@ -3326,11 +3323,9 @@ static int vop2_create_crtcs(struct vop2
|
||||
possible_crtcs = (1 << nvps) - 1;
|
||||
|
||||
ret = vop2_plane_init(vop2, win, possible_crtcs);
|
||||
- if (ret) {
|
||||
- drm_err(vop2->drm, "failed to init plane %s: %d\n",
|
||||
- win->data->name, ret);
|
||||
- return ret;
|
||||
- }
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(drm->dev, ret, "failed to init plane %s\n",
|
||||
+ win->data->name);
|
||||
}
|
||||
|
||||
for (i = 0; i < vop2_data->nr_vps; i++) {
|
||||
@@ -3344,10 +3339,9 @@ static int vop2_create_crtcs(struct vop2
|
||||
ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,
|
||||
&vop2_crtc_funcs,
|
||||
"video_port%d", vp->id);
|
||||
- if (ret) {
|
||||
- drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
|
||||
- return ret;
|
||||
- }
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(drm->dev, ret,
|
||||
+ "crtc init for video_port%d failed\n", i);
|
||||
|
||||
drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
|
||||
if (vop2->lut_regs) {
|
||||
@@ -3674,10 +3668,9 @@ static int vop2_bind(struct device *dev,
|
||||
dev_set_drvdata(dev, vop2);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop");
|
||||
- if (!res) {
|
||||
- drm_err(vop2->drm, "failed to get vop2 register byname\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ if (!res)
|
||||
+ return dev_err_probe(drm->dev, -EINVAL,
|
||||
+ "failed to get vop2 register byname\n");
|
||||
|
||||
vop2->res = res;
|
||||
vop2->regs = devm_ioremap_resource(dev, res);
|
||||
@@ -3702,50 +3695,50 @@ static int vop2_bind(struct device *dev,
|
||||
if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) {
|
||||
vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
||||
if (IS_ERR(vop2->sys_grf))
|
||||
- return dev_err_probe(dev, PTR_ERR(vop2->sys_grf), "cannot get sys_grf");
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_grf),
|
||||
+ "cannot get sys_grf\n");
|
||||
}
|
||||
|
||||
if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) {
|
||||
vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");
|
||||
if (IS_ERR(vop2->vop_grf))
|
||||
- return dev_err_probe(dev, PTR_ERR(vop2->vop_grf), "cannot get vop_grf");
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->vop_grf),
|
||||
+ "cannot get vop_grf\n");
|
||||
}
|
||||
|
||||
if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) {
|
||||
vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");
|
||||
if (IS_ERR(vop2->vo1_grf))
|
||||
- return dev_err_probe(dev, PTR_ERR(vop2->vo1_grf), "cannot get vo1_grf");
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->vo1_grf),
|
||||
+ "cannot get vo1_grf\n");
|
||||
}
|
||||
|
||||
if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) {
|
||||
vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
|
||||
if (IS_ERR(vop2->sys_pmu))
|
||||
- return dev_err_probe(dev, PTR_ERR(vop2->sys_pmu), "cannot get sys_pmu");
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_pmu),
|
||||
+ "cannot get sys_pmu\n");
|
||||
}
|
||||
|
||||
vop2->hclk = devm_clk_get(vop2->dev, "hclk");
|
||||
- if (IS_ERR(vop2->hclk)) {
|
||||
- drm_err(vop2->drm, "failed to get hclk source\n");
|
||||
- return PTR_ERR(vop2->hclk);
|
||||
- }
|
||||
+ if (IS_ERR(vop2->hclk))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->hclk),
|
||||
+ "failed to get hclk source\n");
|
||||
|
||||
vop2->aclk = devm_clk_get(vop2->dev, "aclk");
|
||||
- if (IS_ERR(vop2->aclk)) {
|
||||
- drm_err(vop2->drm, "failed to get aclk source\n");
|
||||
- return PTR_ERR(vop2->aclk);
|
||||
- }
|
||||
+ if (IS_ERR(vop2->aclk))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->aclk),
|
||||
+ "failed to get aclk source\n");
|
||||
|
||||
vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");
|
||||
- if (IS_ERR(vop2->pclk)) {
|
||||
- drm_err(vop2->drm, "failed to get pclk source\n");
|
||||
- return PTR_ERR(vop2->pclk);
|
||||
- }
|
||||
+ if (IS_ERR(vop2->pclk))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->pclk),
|
||||
+ "failed to get pclk source\n");
|
||||
|
||||
vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0");
|
||||
- if (IS_ERR(vop2->pll_hdmiphy0)) {
|
||||
- drm_err(vop2->drm, "failed to get pll_hdmiphy0\n");
|
||||
- return PTR_ERR(vop2->pll_hdmiphy0);
|
||||
- }
|
||||
+ if (IS_ERR(vop2->pll_hdmiphy0))
|
||||
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy0),
|
||||
+ "failed to get pll_hdmiphy0\n");
|
||||
|
||||
vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1");
|
||||
if (IS_ERR(vop2->pll_hdmiphy1))
|
||||
@@ -3753,10 +3746,8 @@ static int vop2_bind(struct device *dev,
|
||||
"failed to get pll_hdmiphy1\n");
|
||||
|
||||
vop2->irq = platform_get_irq(pdev, 0);
|
||||
- if (vop2->irq < 0) {
|
||||
- drm_err(vop2->drm, "cannot find irq for vop2\n");
|
||||
- return vop2->irq;
|
||||
- }
|
||||
+ if (vop2->irq < 0)
|
||||
+ return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
|
||||
|
||||
mutex_init(&vop2->vop2_lock);
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
From 4444e4d789d64f053435713e5984f0ef31a7633b Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko@sntech.de>
|
||||
Date: Fri, 21 Feb 2025 00:41:41 +0100
|
||||
Subject: [PATCH] drm/rockchip: Fix shutdown when no drm-device is set up
|
||||
|
||||
When the drm-driver probes, it mainly creates the component device, where
|
||||
all the sub-drivers (vops, hdmi, etc) hook into.
|
||||
|
||||
This will cause the shutdown handler to get called on shutdown, even
|
||||
though the drm-device might not have been set up, or the component bind
|
||||
might have failed.
|
||||
|
||||
So use the new component helper to check whether the drm-device is up
|
||||
and only then call the drm-atomic helper to release all the drm magic.
|
||||
|
||||
This prevents failures when the drm-device is never set, or has been
|
||||
freed up already for example by a probe-defer during the component bind.
|
||||
|
||||
Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Tested-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250220234141.2788785-3-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
|
||||
@@ -486,9 +486,11 @@ static void rockchip_drm_platform_remove
|
||||
|
||||
static void rockchip_drm_platform_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
- struct drm_device *drm = platform_get_drvdata(pdev);
|
||||
+ if (component_master_is_bound(&pdev->dev, &rockchip_drm_ops)) {
|
||||
+ struct drm_device *drm = platform_get_drvdata(pdev);
|
||||
|
||||
- drm_atomic_helper_shutdown(drm);
|
||||
+ drm_atomic_helper_shutdown(drm);
|
||||
+ }
|
||||
}
|
||||
|
||||
static const struct of_device_id rockchip_drm_dt_ids[] = {
|
||||
@ -0,0 +1,126 @@
|
||||
From ff0b6c031ed3ed31024618340c795523a86e6688 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Feb 2025 19:27:28 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: use devm_regmap_field_alloc for
|
||||
cluster-regs
|
||||
|
||||
Right now vop2_cluster_init() copies the base vop2_cluster_regs
|
||||
and adapts the reg value with the current window's offset before
|
||||
adding the fields to the regmap.
|
||||
|
||||
This conflicts with the notion of reg_fields being const, see
|
||||
https://lore.kernel.org/all/20240706-regmap-const-structs-v1-1-d08c776da787@weissschuh.net/
|
||||
for reference, which now causes checkpatch to actually warn about that.
|
||||
|
||||
So instead of creating one big copy and changing it afterwards,
|
||||
add the reg_fields individually using devm_regmap_field_alloc().
|
||||
|
||||
Functional it is the same, just that the reg_field we're handling
|
||||
can stay const.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250218112744.34433-2-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 66 +++++++++-----------
|
||||
1 file changed, 31 insertions(+), 35 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -3408,7 +3408,7 @@ static int vop2_find_rgb_encoder(struct
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
-static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = {
|
||||
+static const struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = {
|
||||
[VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0),
|
||||
[VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5),
|
||||
[VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14),
|
||||
@@ -3479,28 +3479,26 @@ static struct reg_field vop2_cluster_reg
|
||||
static int vop2_cluster_init(struct vop2_win *win)
|
||||
{
|
||||
struct vop2 *vop2 = win->vop2;
|
||||
- struct reg_field *cluster_regs;
|
||||
- int ret, i;
|
||||
+ int i;
|
||||
|
||||
- cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs),
|
||||
- GFP_KERNEL);
|
||||
- if (!cluster_regs)
|
||||
- return -ENOMEM;
|
||||
+ for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++) {
|
||||
+ const struct reg_field field = {
|
||||
+ .reg = (vop2_cluster_regs[i].reg != 0xffffffff) ?
|
||||
+ vop2_cluster_regs[i].reg + win->offset :
|
||||
+ vop2_cluster_regs[i].reg,
|
||||
+ .lsb = vop2_cluster_regs[i].lsb,
|
||||
+ .msb = vop2_cluster_regs[i].msb
|
||||
+ };
|
||||
+
|
||||
+ win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field);
|
||||
+ if (IS_ERR(win->reg[i]))
|
||||
+ return PTR_ERR(win->reg[i]);
|
||||
+ }
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++)
|
||||
- if (cluster_regs[i].reg != 0xffffffff)
|
||||
- cluster_regs[i].reg += win->offset;
|
||||
-
|
||||
- ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
|
||||
- cluster_regs,
|
||||
- ARRAY_SIZE(vop2_cluster_regs));
|
||||
-
|
||||
- kfree(cluster_regs);
|
||||
-
|
||||
- return ret;
|
||||
+ return 0;
|
||||
};
|
||||
|
||||
-static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = {
|
||||
+static const struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = {
|
||||
[VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0),
|
||||
[VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5),
|
||||
[VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12),
|
||||
@@ -3567,26 +3565,24 @@ static struct reg_field vop2_esmart_regs
|
||||
static int vop2_esmart_init(struct vop2_win *win)
|
||||
{
|
||||
struct vop2 *vop2 = win->vop2;
|
||||
- struct reg_field *esmart_regs;
|
||||
- int ret, i;
|
||||
-
|
||||
- esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs),
|
||||
- GFP_KERNEL);
|
||||
- if (!esmart_regs)
|
||||
- return -ENOMEM;
|
||||
+ int i;
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++)
|
||||
- if (esmart_regs[i].reg != 0xffffffff)
|
||||
- esmart_regs[i].reg += win->offset;
|
||||
+ for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++) {
|
||||
+ const struct reg_field field = {
|
||||
+ .reg = (vop2_esmart_regs[i].reg != 0xffffffff) ?
|
||||
+ vop2_esmart_regs[i].reg + win->offset :
|
||||
+ vop2_esmart_regs[i].reg,
|
||||
+ .lsb = vop2_esmart_regs[i].lsb,
|
||||
+ .msb = vop2_esmart_regs[i].msb
|
||||
+ };
|
||||
+
|
||||
+ win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field);
|
||||
+ if (IS_ERR(win->reg[i]))
|
||||
+ return PTR_ERR(win->reg[i]);
|
||||
+ }
|
||||
|
||||
- ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
|
||||
- esmart_regs,
|
||||
- ARRAY_SIZE(vop2_esmart_regs));
|
||||
-
|
||||
- kfree(esmart_regs);
|
||||
-
|
||||
- return ret;
|
||||
-};
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
static int vop2_win_init(struct vop2 *vop2)
|
||||
{
|
||||
@ -0,0 +1,77 @@
|
||||
From 838a871a4d51b59fe56ac0422b97443203bfa55c Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Feb 2025 19:27:29 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Remove AFBC from TRANSFORM_OFFSET
|
||||
register macro
|
||||
|
||||
This TRANSFORM_OFFSET register needs to be configured not only in
|
||||
AFBC mode, but also in tile mode, so remove the AFBC/AFBCD prefix.
|
||||
|
||||
This also help avoid "exceeds 100 columns" warning from checkpatch.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250218112744.34433-3-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 8 ++++----
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 4 ++--
|
||||
2 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -1523,7 +1523,7 @@ static void vop2_plane_atomic_update(str
|
||||
transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info);
|
||||
- vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset);
|
||||
+ vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, transform_offset);
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1));
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16)));
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride);
|
||||
@@ -1534,7 +1534,7 @@ static void vop2_plane_atomic_update(str
|
||||
} else {
|
||||
if (vop2_cluster_window(win)) {
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0);
|
||||
- vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, 0);
|
||||
+ vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, 0);
|
||||
}
|
||||
|
||||
vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4));
|
||||
@@ -3456,7 +3456,7 @@ static const struct reg_field vop2_clust
|
||||
[VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31),
|
||||
[VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31),
|
||||
[VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31),
|
||||
- [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31),
|
||||
+ [VOP2_WIN_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_TRANSFORM_OFFSET, 0, 31),
|
||||
[VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0),
|
||||
[VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1),
|
||||
[VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2),
|
||||
@@ -3555,7 +3555,7 @@ static const struct reg_field vop2_esmar
|
||||
[VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff },
|
||||
[VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff },
|
||||
[VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff },
|
||||
- [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff },
|
||||
+ [VOP2_WIN_TRANSFORM_OFFSET] = { .reg = 0xffffffff },
|
||||
[VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff },
|
||||
[VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff },
|
||||
[VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff },
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -118,7 +118,7 @@ enum vop2_win_regs {
|
||||
VOP2_WIN_AFBC_PIC_OFFSET,
|
||||
VOP2_WIN_AFBC_PIC_SIZE,
|
||||
VOP2_WIN_AFBC_DSP_OFFSET,
|
||||
- VOP2_WIN_AFBC_TRANSFORM_OFFSET,
|
||||
+ VOP2_WIN_TRANSFORM_OFFSET,
|
||||
VOP2_WIN_AFBC_HDR_PTR,
|
||||
VOP2_WIN_AFBC_HALF_BLOCK_EN,
|
||||
VOP2_WIN_AFBC_ROTATE_270,
|
||||
@@ -335,7 +335,7 @@ enum dst_factor_mode {
|
||||
#define RK3568_CLUSTER_WIN_DSP_INFO 0x24
|
||||
#define RK3568_CLUSTER_WIN_DSP_ST 0x28
|
||||
#define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB 0x30
|
||||
-#define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET 0x3C
|
||||
+#define RK3568_CLUSTER_WIN_TRANSFORM_OFFSET 0x3C
|
||||
#define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL 0x50
|
||||
#define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE 0x54
|
||||
#define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR 0x58
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,86 @@
|
||||
From 145c9b36892a07bf5e2525b4938e1a6cc9b41b7a Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Feb 2025 19:27:31 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Merge vop2_cluster/esmart_init function
|
||||
|
||||
Now these two function share the same logic, they can
|
||||
be merged as one.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250218112744.34433-5-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 42 +++++---------------
|
||||
1 file changed, 11 insertions(+), 31 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -2430,18 +2430,18 @@ static int vop2_find_rgb_encoder(struct
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
-static int vop2_cluster_init(struct vop2_win *win)
|
||||
+static int vop2_regmap_init(struct vop2_win *win, const struct reg_field *regs,
|
||||
+ int nr_regs)
|
||||
{
|
||||
struct vop2 *vop2 = win->vop2;
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < vop2->data->nr_cluster_regs; i++) {
|
||||
+ for (i = 0; i < nr_regs; i++) {
|
||||
const struct reg_field field = {
|
||||
- .reg = (vop2->data->cluster_reg[i].reg != 0xffffffff) ?
|
||||
- vop2->data->cluster_reg[i].reg + win->offset :
|
||||
- vop2->data->cluster_reg[i].reg,
|
||||
- .lsb = vop2->data->cluster_reg[i].lsb,
|
||||
- .msb = vop2->data->cluster_reg[i].msb
|
||||
+ .reg = (regs[i].reg != 0xffffffff) ?
|
||||
+ regs[i].reg + win->offset : regs[i].reg,
|
||||
+ .lsb = regs[i].lsb,
|
||||
+ .msb = regs[i].msb
|
||||
};
|
||||
|
||||
win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field);
|
||||
@@ -2452,28 +2452,6 @@ static int vop2_cluster_init(struct vop2
|
||||
return 0;
|
||||
};
|
||||
|
||||
-static int vop2_esmart_init(struct vop2_win *win)
|
||||
-{
|
||||
- struct vop2 *vop2 = win->vop2;
|
||||
- int i;
|
||||
-
|
||||
- for (i = 0; i < vop2->data->nr_smart_regs; i++) {
|
||||
- const struct reg_field field = {
|
||||
- .reg = (vop2->data->smart_reg[i].reg != 0xffffffff) ?
|
||||
- vop2->data->smart_reg[i].reg + win->offset :
|
||||
- vop2->data->smart_reg[i].reg,
|
||||
- .lsb = vop2->data->smart_reg[i].lsb,
|
||||
- .msb = vop2->data->smart_reg[i].msb
|
||||
- };
|
||||
-
|
||||
- win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field);
|
||||
- if (IS_ERR(win->reg[i]))
|
||||
- return PTR_ERR(win->reg[i]);
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int vop2_win_init(struct vop2 *vop2)
|
||||
{
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
@@ -2490,9 +2468,11 @@ static int vop2_win_init(struct vop2 *vo
|
||||
win->win_id = i;
|
||||
win->vop2 = vop2;
|
||||
if (vop2_cluster_window(win))
|
||||
- ret = vop2_cluster_init(win);
|
||||
+ ret = vop2_regmap_init(win, vop2->data->cluster_reg,
|
||||
+ vop2->data->nr_cluster_regs);
|
||||
else
|
||||
- ret = vop2_esmart_init(win);
|
||||
+ ret = vop2_regmap_init(win, vop2->data->smart_reg,
|
||||
+ vop2->data->nr_smart_regs);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -0,0 +1,200 @@
|
||||
From 5439c4f3cb0ec11a3f3cb70be2b019770f6d183c Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Feb 2025 19:27:32 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Support for different layer select
|
||||
configuration between VPs
|
||||
|
||||
In the upcoming VOP for rk3576, every VP has it's own LAYER_SEL
|
||||
register, and the configuration value of each VP for the same
|
||||
window maybe different, so extend the layer_sel_id to array,
|
||||
let it can descption the layer select configuration value for
|
||||
different VP.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250218112744.34433-6-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 4 +--
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 38 ++++++++++----------
|
||||
2 files changed, 22 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -166,9 +166,9 @@ struct vop2_win_data {
|
||||
const unsigned int supported_rotations;
|
||||
|
||||
/**
|
||||
- * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2
|
||||
+ * @layer_sel_id: defined by register OVERLAY_LAYER_SEL or PORTn_LAYER_SEL
|
||||
*/
|
||||
- unsigned int layer_sel_id;
|
||||
+ unsigned int layer_sel_id[ROCKCHIP_MAX_CRTC];
|
||||
uint64_t feature;
|
||||
|
||||
uint8_t axi_bus_id;
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -350,7 +350,8 @@ static const struct vop2_win_data rk3568
|
||||
.formats = formats_smart,
|
||||
.nformats = ARRAY_SIZE(formats_smart),
|
||||
.format_modifiers = format_modifiers,
|
||||
- .layer_sel_id = 3,
|
||||
+ /* 0xf means this layer can't attached to this VP */
|
||||
+ .layer_sel_id = { 3, 3, 3, 0xf },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
.max_upscale_factor = 8,
|
||||
@@ -363,7 +364,7 @@ static const struct vop2_win_data rk3568
|
||||
.nformats = ARRAY_SIZE(formats_smart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1e00,
|
||||
- .layer_sel_id = 7,
|
||||
+ .layer_sel_id = { 7, 7, 7, 0xf },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
.max_upscale_factor = 8,
|
||||
@@ -376,7 +377,7 @@ static const struct vop2_win_data rk3568
|
||||
.nformats = ARRAY_SIZE(formats_rk356x_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1a00,
|
||||
- .layer_sel_id = 6,
|
||||
+ .layer_sel_id = { 6, 6, 6, 0xf },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
.max_upscale_factor = 8,
|
||||
@@ -389,7 +390,7 @@ static const struct vop2_win_data rk3568
|
||||
.nformats = ARRAY_SIZE(formats_rk356x_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1800,
|
||||
- .layer_sel_id = 2,
|
||||
+ .layer_sel_id = { 2, 2, 2, 0xf },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
.max_upscale_factor = 8,
|
||||
@@ -402,7 +403,7 @@ static const struct vop2_win_data rk3568
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 0,
|
||||
+ .layer_sel_id = { 0, 0, 0, 0xf },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.max_upscale_factor = 4,
|
||||
@@ -417,7 +418,7 @@ static const struct vop2_win_data rk3568
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 1,
|
||||
+ .layer_sel_id = { 1, 1, 1, 0xf },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
@@ -582,7 +583,7 @@ static const struct vop2_win_data rk3588
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 0,
|
||||
+ .layer_sel_id = { 0, 0, 0, 0 },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.axi_bus_id = 0,
|
||||
@@ -600,7 +601,7 @@ static const struct vop2_win_data rk3588
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 1,
|
||||
+ .layer_sel_id = { 1, 1, 1, 1 },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
@@ -618,7 +619,7 @@ static const struct vop2_win_data rk3588
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 4,
|
||||
+ .layer_sel_id = { 4, 4, 4, 4 },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
@@ -636,7 +637,7 @@ static const struct vop2_win_data rk3588
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
- .layer_sel_id = 5,
|
||||
+ .layer_sel_id = { 5, 5, 5, 5 },
|
||||
.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
|
||||
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
@@ -654,7 +655,7 @@ static const struct vop2_win_data rk3588
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1800,
|
||||
- .layer_sel_id = 2,
|
||||
+ .layer_sel_id = { 2, 2, 2, 2 },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.axi_bus_id = 0,
|
||||
@@ -670,7 +671,7 @@ static const struct vop2_win_data rk3588
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1a00,
|
||||
- .layer_sel_id = 3,
|
||||
+ .layer_sel_id = { 3, 3, 3, 3 },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.axi_bus_id = 0,
|
||||
@@ -686,7 +687,7 @@ static const struct vop2_win_data rk3588
|
||||
.formats = formats_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
- .layer_sel_id = 6,
|
||||
+ .layer_sel_id = { 6, 6, 6, 6 },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.axi_bus_id = 1,
|
||||
@@ -702,7 +703,7 @@ static const struct vop2_win_data rk3588
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
.base = 0x1e00,
|
||||
- .layer_sel_id = 7,
|
||||
+ .layer_sel_id = { 7, 7, 7, 7 },
|
||||
.supported_rotations = DRM_MODE_REFLECT_Y,
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.axi_bus_id = 1,
|
||||
@@ -1454,7 +1455,7 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
*/
|
||||
for (old_layer_id = 0; old_layer_id < vop2->data->win_size; old_layer_id++) {
|
||||
layer_sel_id = (layer_sel >> (4 * old_layer_id)) & 0xf;
|
||||
- if (layer_sel_id == win->data->layer_sel_id)
|
||||
+ if (layer_sel_id == win->data->layer_sel_id[vp->id])
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1464,7 +1465,7 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
for (i = 0; i < vop2->data->win_size; i++) {
|
||||
old_win = &vop2->win[i];
|
||||
layer_sel_id = (layer_sel >> (4 * layer_id)) & 0xf;
|
||||
- if (layer_sel_id == old_win->data->layer_sel_id)
|
||||
+ if (layer_sel_id == old_win->data->layer_sel_id[vp->id])
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1512,13 +1513,14 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
}
|
||||
|
||||
layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(layer_id, 0x7);
|
||||
- layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(layer_id, win->data->layer_sel_id);
|
||||
+ layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(layer_id, win->data->layer_sel_id[vp->id]);
|
||||
/*
|
||||
* When we bind a window from layerM to layerN, we also need to move the old
|
||||
* window on layerN to layerM to avoid one window selected by two or more layers.
|
||||
*/
|
||||
layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, 0x7);
|
||||
- layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id, old_win->data->layer_sel_id);
|
||||
+ layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(old_layer_id,
|
||||
+ old_win->data->layer_sel_id[vp->id]);
|
||||
}
|
||||
|
||||
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
|
||||
@ -0,0 +1,177 @@
|
||||
From 301618ed1d8ab7cfaec39b107eded9f263da2299 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Feb 2025 19:27:33 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Introduce vop hardware version
|
||||
|
||||
There is a version number hardcoded in the VOP VERSION_INFO
|
||||
register, and the version number increments sequentially based
|
||||
on the production order of the SoC.
|
||||
|
||||
So using this version number to distinguish different VOP features
|
||||
will simplify the code.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250218112744.34433-7-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 26 ++++++++++++++------
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 11 +++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 3 +++
|
||||
3 files changed, 33 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -355,7 +355,7 @@ static bool vop2_output_uv_swap(u32 bus_
|
||||
|
||||
static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
|
||||
{
|
||||
- if (vop2->data->soc_id == 3588) {
|
||||
+ if (vop2->version == VOP_VERSION_RK3588) {
|
||||
if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
|
||||
bus_format == MEDIA_BUS_FMT_YUV10_1X30)
|
||||
return true;
|
||||
@@ -408,7 +408,7 @@ static bool rockchip_vop2_mod_supported(
|
||||
if (modifier == DRM_FORMAT_MOD_INVALID)
|
||||
return false;
|
||||
|
||||
- if (vop2->data->soc_id == 3568 || vop2->data->soc_id == 3566) {
|
||||
+ if (vop2->version == VOP_VERSION_RK3568) {
|
||||
if (vop2_cluster_window(win)) {
|
||||
if (modifier == DRM_FORMAT_MOD_LINEAR) {
|
||||
drm_dbg_kms(vop2->drm,
|
||||
@@ -419,7 +419,7 @@ static bool rockchip_vop2_mod_supported(
|
||||
}
|
||||
|
||||
if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) {
|
||||
- if (vop2->data->soc_id == 3588) {
|
||||
+ if (vop2->version == VOP_VERSION_RK3588) {
|
||||
if (!rockchip_afbc(plane, modifier)) {
|
||||
drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n");
|
||||
return false;
|
||||
@@ -818,6 +818,7 @@ static void rk3588_vop2_power_domain_ena
|
||||
static void vop2_enable(struct vop2 *vop2)
|
||||
{
|
||||
int ret;
|
||||
+ u32 version;
|
||||
|
||||
ret = pm_runtime_resume_and_get(vop2->dev);
|
||||
if (ret < 0) {
|
||||
@@ -837,10 +838,20 @@ static void vop2_enable(struct vop2 *vop
|
||||
return;
|
||||
}
|
||||
|
||||
+ version = vop2_readl(vop2, RK3568_VERSION_INFO);
|
||||
+ if (version != vop2->version) {
|
||||
+ drm_err(vop2->drm, "Hardware version(0x%08x) mismatch\n", version);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * rk3566 share the same vop version with rk3568, so
|
||||
+ * we need to use soc_id for identification here.
|
||||
+ */
|
||||
if (vop2->data->soc_id == 3566)
|
||||
vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);
|
||||
|
||||
- if (vop2->data->soc_id == 3588)
|
||||
+ if (vop2->version == VOP_VERSION_RK3588)
|
||||
rk3588_vop2_power_domain_enable_all(vop2);
|
||||
|
||||
vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
|
||||
@@ -921,7 +932,7 @@ static void vop2_vp_dsp_lut_update_enabl
|
||||
|
||||
static inline bool vop2_supports_seamless_gamma_lut_update(struct vop2 *vop2)
|
||||
{
|
||||
- return (vop2->data->soc_id != 3566 && vop2->data->soc_id != 3568);
|
||||
+ return vop2->version != VOP_VERSION_RK3568;
|
||||
}
|
||||
|
||||
static bool vop2_gamma_lut_in_use(struct vop2 *vop2, struct vop2_video_port *vp)
|
||||
@@ -1261,7 +1272,7 @@ static void vop2_plane_atomic_update(str
|
||||
&fb->format->format,
|
||||
afbc_en ? "AFBC" : "", &yrgb_mst);
|
||||
|
||||
- if (vop2->data->soc_id > 3568) {
|
||||
+ if (vop2->version > VOP_VERSION_RK3568) {
|
||||
vop2_win_write(win, VOP2_WIN_AXI_BUS_ID, win->data->axi_bus_id);
|
||||
vop2_win_write(win, VOP2_WIN_AXI_YRGB_R_ID, win->data->axi_yrgb_r_id);
|
||||
vop2_win_write(win, VOP2_WIN_AXI_UV_R_ID, win->data->axi_uv_r_id);
|
||||
@@ -1321,7 +1332,7 @@ static void vop2_plane_atomic_update(str
|
||||
* this bit is gating disable, we should write 1 to
|
||||
* disable gating when enable afbc.
|
||||
*/
|
||||
- if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
|
||||
+ if (vop2->version == VOP_VERSION_RK3568)
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
|
||||
else
|
||||
vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);
|
||||
@@ -2530,6 +2541,7 @@ static int vop2_bind(struct device *dev,
|
||||
vop2->dev = dev;
|
||||
vop2->data = vop2_data;
|
||||
vop2->ops = vop2_data->ops;
|
||||
+ vop2->version = vop2_data->version;
|
||||
vop2->drm = drm;
|
||||
|
||||
dev_set_drvdata(dev, vop2);
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -13,6 +13,15 @@
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_vop.h"
|
||||
|
||||
+#define VOP2_VERSION(major, minor, build) ((major) << 24 | (minor) << 16 | (build))
|
||||
+
|
||||
+/* The VOP version of new SoC is bigger than the old */
|
||||
+#define VOP_VERSION_RK3568 VOP2_VERSION(0x40, 0x15, 0x8023)
|
||||
+#define VOP_VERSION_RK3588 VOP2_VERSION(0x40, 0x17, 0x6786)
|
||||
+#define VOP_VERSION_RK3528 VOP2_VERSION(0x50, 0x17, 0x1263)
|
||||
+#define VOP_VERSION_RK3562 VOP2_VERSION(0x50, 0x17, 0x4350)
|
||||
+#define VOP_VERSION_RK3576 VOP2_VERSION(0x50, 0x19, 0x9765)
|
||||
+
|
||||
#define VOP2_VP_FEATURE_OUTPUT_10BIT BIT(0)
|
||||
|
||||
#define VOP2_FEATURE_HAS_SYS_GRF BIT(0)
|
||||
@@ -243,6 +252,7 @@ struct vop2_ops {
|
||||
struct vop2_data {
|
||||
u8 nr_vps;
|
||||
u64 feature;
|
||||
+ u32 version;
|
||||
const struct vop2_ops *ops;
|
||||
const struct vop2_win_data *win;
|
||||
const struct vop2_video_port_data *vp;
|
||||
@@ -260,6 +270,7 @@ struct vop2_data {
|
||||
};
|
||||
|
||||
struct vop2 {
|
||||
+ u32 version;
|
||||
struct device *dev;
|
||||
struct drm_device *drm;
|
||||
struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -1627,6 +1627,7 @@ static const struct vop2_ops rk3588_vop_
|
||||
};
|
||||
|
||||
static const struct vop2_data rk3566_vop = {
|
||||
+ .version = VOP_VERSION_RK3568,
|
||||
.feature = VOP2_FEATURE_HAS_SYS_GRF,
|
||||
.nr_vps = 3,
|
||||
.max_input = { 4096, 2304 },
|
||||
@@ -1645,6 +1646,7 @@ static const struct vop2_data rk3566_vop
|
||||
};
|
||||
|
||||
static const struct vop2_data rk3568_vop = {
|
||||
+ .version = VOP_VERSION_RK3568,
|
||||
.feature = VOP2_FEATURE_HAS_SYS_GRF,
|
||||
.nr_vps = 3,
|
||||
.max_input = { 4096, 2304 },
|
||||
@@ -1663,6 +1665,7 @@ static const struct vop2_data rk3568_vop
|
||||
};
|
||||
|
||||
static const struct vop2_data rk3588_vop = {
|
||||
+ .version = VOP_VERSION_RK3588,
|
||||
.feature = VOP2_FEATURE_HAS_SYS_GRF | VOP2_FEATURE_HAS_VO1_GRF |
|
||||
VOP2_FEATURE_HAS_VOP_GRF | VOP2_FEATURE_HAS_SYS_PMU,
|
||||
.nr_vps = 4,
|
||||
@ -0,0 +1,154 @@
|
||||
From 6fd4f8a26a21dd2075cfcc7eae3b9d440d886571 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Mon, 3 Mar 2025 11:44:15 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Register the primary plane and overlay
|
||||
plane separately
|
||||
|
||||
In the upcoming VOP of rk3576, a Window cannot attach to all Video Ports,
|
||||
so make sure all VP find it's suitable primary plane, then register the
|
||||
remain windows as overlay plane will make code easier.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250303034436.192400-2-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 99 ++++++++++++--------
|
||||
1 file changed, 60 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -2260,22 +2260,29 @@ static int vop2_plane_init(struct vop2 *
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)
|
||||
+/*
|
||||
+ * On RK3566 these windows don't have an independent
|
||||
+ * framebuffer. They can only share/mirror the framebuffer
|
||||
+ * with smart0, esmart0 and cluster0 respectively.
|
||||
+ * And RK3566 share the same vop version with Rk3568, so we
|
||||
+ * need to use soc_id for identification here.
|
||||
+ */
|
||||
+static bool vop2_is_mirror_win(struct vop2_win *win)
|
||||
{
|
||||
- int i;
|
||||
+ struct vop2 *vop2 = win->vop2;
|
||||
|
||||
- for (i = 0; i < vop2->data->nr_vps; i++) {
|
||||
- struct vop2_video_port *vp = &vop2->vps[i];
|
||||
-
|
||||
- if (!vp->crtc.port)
|
||||
- continue;
|
||||
- if (vp->primary_plane)
|
||||
- continue;
|
||||
-
|
||||
- return vp;
|
||||
+ if (vop2->data->soc_id == 3566) {
|
||||
+ switch (win->data->phys_id) {
|
||||
+ case ROCKCHIP_VOP2_SMART1:
|
||||
+ case ROCKCHIP_VOP2_ESMART1:
|
||||
+ case ROCKCHIP_VOP2_CLUSTER1:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return false;
|
||||
}
|
||||
-
|
||||
- return NULL;
|
||||
}
|
||||
|
||||
static int vop2_create_crtcs(struct vop2 *vop2)
|
||||
@@ -2286,7 +2293,9 @@ static int vop2_create_crtcs(struct vop2
|
||||
struct drm_plane *plane;
|
||||
struct device_node *port;
|
||||
struct vop2_video_port *vp;
|
||||
- int i, nvp, nvps = 0;
|
||||
+ struct vop2_win *win;
|
||||
+ u32 possible_crtcs;
|
||||
+ int i, j, nvp, nvps = 0;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < vop2_data->nr_vps; i++) {
|
||||
@@ -2322,42 +2331,54 @@ static int vop2_create_crtcs(struct vop2
|
||||
}
|
||||
|
||||
nvp = 0;
|
||||
- for (i = 0; i < vop2->registered_num_wins; i++) {
|
||||
- struct vop2_win *win = &vop2->win[i];
|
||||
- u32 possible_crtcs = 0;
|
||||
+ /* Register a primary plane for every crtc */
|
||||
+ for (i = 0; i < vop2_data->nr_vps; i++) {
|
||||
+ vp = &vop2->vps[i];
|
||||
+
|
||||
+ if (!vp->crtc.port)
|
||||
+ continue;
|
||||
|
||||
- if (vop2->data->soc_id == 3566) {
|
||||
- /*
|
||||
- * On RK3566 these windows don't have an independent
|
||||
- * framebuffer. They share the framebuffer with smart0,
|
||||
- * esmart0 and cluster0 respectively.
|
||||
- */
|
||||
- switch (win->data->phys_id) {
|
||||
- case ROCKCHIP_VOP2_SMART1:
|
||||
- case ROCKCHIP_VOP2_ESMART1:
|
||||
- case ROCKCHIP_VOP2_CLUSTER1:
|
||||
+ for (j = 0; j < vop2->registered_num_wins; j++) {
|
||||
+ win = &vop2->win[j];
|
||||
+
|
||||
+ /* Aready registered as primary plane */
|
||||
+ if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
- }
|
||||
- }
|
||||
|
||||
- if (win->type == DRM_PLANE_TYPE_PRIMARY) {
|
||||
- vp = find_vp_without_primary(vop2);
|
||||
- if (vp) {
|
||||
+ if (vop2_is_mirror_win(win))
|
||||
+ continue;
|
||||
+
|
||||
+ if (win->type == DRM_PLANE_TYPE_PRIMARY) {
|
||||
possible_crtcs = BIT(nvp);
|
||||
vp->primary_plane = win;
|
||||
+ ret = vop2_plane_init(vop2, win, possible_crtcs);
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(drm->dev, ret,
|
||||
+ "failed to init primary plane %s\n",
|
||||
+ win->data->name);
|
||||
nvp++;
|
||||
- } else {
|
||||
- /* change the unused primary window to overlay window */
|
||||
- win->type = DRM_PLANE_TYPE_OVERLAY;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ /* Register all unused window as overlay plane */
|
||||
+ for (i = 0; i < vop2->registered_num_wins; i++) {
|
||||
+ win = &vop2->win[i];
|
||||
+
|
||||
+ /* Aready registered as primary plane */
|
||||
+ if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
|
||||
+ continue;
|
||||
+
|
||||
+ if (vop2_is_mirror_win(win))
|
||||
+ continue;
|
||||
|
||||
- if (win->type == DRM_PLANE_TYPE_OVERLAY)
|
||||
- possible_crtcs = (1 << nvps) - 1;
|
||||
+ win->type = DRM_PLANE_TYPE_OVERLAY;
|
||||
|
||||
+ possible_crtcs = (1 << nvps) - 1;
|
||||
ret = vop2_plane_init(vop2, win, possible_crtcs);
|
||||
if (ret)
|
||||
- return dev_err_probe(drm->dev, ret, "failed to init plane %s\n",
|
||||
+ return dev_err_probe(drm->dev, ret, "failed to init overlay plane %s\n",
|
||||
win->data->name);
|
||||
}
|
||||
|
||||
@ -0,0 +1,179 @@
|
||||
From b90fa71a11600276c993e620abea8ca9f2045401 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Mon, 3 Mar 2025 11:44:16 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Set plane possible crtcs by possible vp
|
||||
mask
|
||||
|
||||
In the upcoming VOP of rk3576, a window cannot attach to all Video
|
||||
Ports, we introduce a possible_vp_mask for every window to indicate
|
||||
which Video Ports this window can attach to.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
|
||||
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250303034436.192400-3-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 18 +++++++++++++++++-
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 +
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 14 ++++++++++++++
|
||||
3 files changed, 32 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -2345,6 +2345,10 @@ static int vop2_create_crtcs(struct vop2
|
||||
if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
+ /* If this win can not attached to this VP */
|
||||
+ if (!(win->data->possible_vp_mask & BIT(vp->id)))
|
||||
+ continue;
|
||||
+
|
||||
if (vop2_is_mirror_win(win))
|
||||
continue;
|
||||
|
||||
@@ -2375,7 +2379,19 @@ static int vop2_create_crtcs(struct vop2
|
||||
|
||||
win->type = DRM_PLANE_TYPE_OVERLAY;
|
||||
|
||||
- possible_crtcs = (1 << nvps) - 1;
|
||||
+ possible_crtcs = 0;
|
||||
+ nvp = 0;
|
||||
+ for (j = 0; j < vop2_data->nr_vps; j++) {
|
||||
+ vp = &vop2->vps[j];
|
||||
+
|
||||
+ if (!vp->crtc.port)
|
||||
+ continue;
|
||||
+
|
||||
+ if (win->data->possible_vp_mask & BIT(vp->id))
|
||||
+ possible_crtcs |= BIT(nvp);
|
||||
+ nvp++;
|
||||
+ }
|
||||
+
|
||||
ret = vop2_plane_init(vop2, win, possible_crtcs);
|
||||
if (ret)
|
||||
return dev_err_probe(drm->dev, ret, "failed to init overlay plane %s\n",
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -167,6 +167,7 @@ struct vop2_win_data {
|
||||
unsigned int phys_id;
|
||||
|
||||
u32 base;
|
||||
+ u32 possible_vp_mask;
|
||||
enum drm_plane_type type;
|
||||
|
||||
u32 nformats;
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -347,6 +347,7 @@ static const struct vop2_win_data rk3568
|
||||
.name = "Smart0-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_SMART0,
|
||||
.base = 0x1c00,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_smart,
|
||||
.nformats = ARRAY_SIZE(formats_smart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -360,6 +361,7 @@ static const struct vop2_win_data rk3568
|
||||
}, {
|
||||
.name = "Smart1-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_SMART1,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_smart,
|
||||
.nformats = ARRAY_SIZE(formats_smart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -373,6 +375,7 @@ static const struct vop2_win_data rk3568
|
||||
}, {
|
||||
.name = "Esmart1-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART1,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_rk356x_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_rk356x_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -386,6 +389,7 @@ static const struct vop2_win_data rk3568
|
||||
}, {
|
||||
.name = "Esmart0-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART0,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_rk356x_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_rk356x_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -400,6 +404,7 @@ static const struct vop2_win_data rk3568
|
||||
.name = "Cluster0-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER0,
|
||||
.base = 0x1000,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -415,6 +420,7 @@ static const struct vop2_win_data rk3568
|
||||
.name = "Cluster1-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER1,
|
||||
.base = 0x1200,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -580,6 +586,7 @@ static const struct vop2_win_data rk3588
|
||||
.name = "Cluster0-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER0,
|
||||
.base = 0x1000,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -598,6 +605,7 @@ static const struct vop2_win_data rk3588
|
||||
.name = "Cluster1-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER1,
|
||||
.base = 0x1200,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -616,6 +624,7 @@ static const struct vop2_win_data rk3588
|
||||
.name = "Cluster2-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER2,
|
||||
.base = 0x1400,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -634,6 +643,7 @@ static const struct vop2_win_data rk3588
|
||||
.name = "Cluster3-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_CLUSTER3,
|
||||
.base = 0x1600,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_cluster,
|
||||
.nformats = ARRAY_SIZE(formats_cluster),
|
||||
.format_modifiers = format_modifiers_afbc,
|
||||
@@ -651,6 +661,7 @@ static const struct vop2_win_data rk3588
|
||||
}, {
|
||||
.name = "Esmart0-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART0,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -667,6 +678,7 @@ static const struct vop2_win_data rk3588
|
||||
}, {
|
||||
.name = "Esmart1-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART1,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -684,6 +696,7 @@ static const struct vop2_win_data rk3588
|
||||
.name = "Esmart2-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART2,
|
||||
.base = 0x1c00,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
@@ -699,6 +712,7 @@ static const struct vop2_win_data rk3588
|
||||
}, {
|
||||
.name = "Esmart3-win0",
|
||||
.phys_id = ROCKCHIP_VOP2_ESMART3,
|
||||
+ .possible_vp_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
|
||||
.formats = formats_esmart,
|
||||
.nformats = ARRAY_SIZE(formats_esmart),
|
||||
.format_modifiers = format_modifiers,
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
||||
From 95a5c9d197bb22a506913acb330a926d4e51aa95 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko@sntech.de>
|
||||
Date: Mon, 3 Mar 2025 19:22:56 +0100
|
||||
Subject: [PATCH] drm/rockchip: vop2: add missing bitfield.h include
|
||||
|
||||
Commit 328e6885996c ("drm/rockchip: vop2: Add platform specific callback")
|
||||
moved per soc configuration code to the other per-soc data into
|
||||
rockchip_vop2_reg.c, but forgot to also include bitfield.h for the used
|
||||
FIELD_PREP macro. Add this missing include.
|
||||
|
||||
Fixes: 328e6885996c ("drm/rockchip: vop2: Add platform specific callback")
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Closes: https://lore.kernel.org/oe-kbuild-all/202503040135.fgoyWdLB-lkp@intel.com/
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250303182256.1727178-1-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -4,6 +4,7 @@
|
||||
* Author: Andy Yan <andy.yan@rock-chips.com>
|
||||
*/
|
||||
|
||||
+#include <linux/bitfield.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@ -0,0 +1,160 @@
|
||||
From abeef1f9eaf9301cc98a6841dab5f72de5c95360 Mon Sep 17 00:00:00 2001
|
||||
From: Jani Nikula <jani.nikula@intel.com>
|
||||
Date: Thu, 23 Jan 2025 17:09:09 +0200
|
||||
Subject: [PATCH] drm/rockchip: stop passing non struct drm_device to drm_err()
|
||||
and friends
|
||||
|
||||
The expectation is that the struct drm_device based logging helpers get
|
||||
passed an actual struct drm_device pointer rather than some random
|
||||
struct pointer where you can dereference the ->dev member.
|
||||
|
||||
Convert drm_err(hdmi, ...) to dev_err(hdmi->dev, ...). This matches
|
||||
current usage, but drops "[drm] *ERROR*" prefix from logging.
|
||||
|
||||
Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch>
|
||||
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
|
||||
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/f42da4c9943a2f2a9de4272b7849e72236d4c3f9.1737644530.git.jani.nikula@intel.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++++++++--------
|
||||
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++--------
|
||||
2 files changed, 16 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
|
||||
@@ -203,7 +203,7 @@ static int rockchip_hdmi_parse_dt(struct
|
||||
|
||||
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(hdmi->regmap)) {
|
||||
- drm_err(hdmi, "Unable to get rockchip,grf\n");
|
||||
+ dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
|
||||
return PTR_ERR(hdmi->regmap);
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ static int rockchip_hdmi_parse_dt(struct
|
||||
if (IS_ERR(hdmi->ref_clk)) {
|
||||
ret = PTR_ERR(hdmi->ref_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "failed to get reference clock\n");
|
||||
+ dev_err(hdmi->dev, "failed to get reference clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ static int rockchip_hdmi_parse_dt(struct
|
||||
if (IS_ERR(hdmi->grf_clk)) {
|
||||
ret = PTR_ERR(hdmi->grf_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "failed to get grf clock\n");
|
||||
+ dev_err(hdmi->dev, "failed to get grf clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -302,16 +302,16 @@ static void dw_hdmi_rockchip_encoder_ena
|
||||
|
||||
ret = clk_prepare_enable(hdmi->grf_clk);
|
||||
if (ret < 0) {
|
||||
- drm_err(hdmi, "failed to enable grfclk %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);
|
||||
if (ret != 0)
|
||||
- drm_err(hdmi, "Could not write to GRF: %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "Could not write to GRF: %d\n", ret);
|
||||
|
||||
clk_disable_unprepare(hdmi->grf_clk);
|
||||
- drm_dbg(hdmi, "vop %s output to hdmi\n", ret ? "LIT" : "BIG");
|
||||
+ dev_dbg(hdmi->dev, "vop %s output to hdmi\n", ret ? "LIT" : "BIG");
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -574,7 +574,7 @@ static int dw_hdmi_rockchip_bind(struct
|
||||
ret = rockchip_hdmi_parse_dt(hdmi);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "Unable to parse OF data\n");
|
||||
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ static int dw_hdmi_rockchip_bind(struct
|
||||
if (IS_ERR(hdmi->phy)) {
|
||||
ret = PTR_ERR(hdmi->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "failed to get phy\n");
|
||||
+ dev_err(hdmi->dev, "failed to get phy\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -242,7 +242,7 @@ static void dw_hdmi_qp_rk3588_hpd_work(s
|
||||
if (drm) {
|
||||
changed = drm_helper_hpd_irq_event(drm);
|
||||
if (changed)
|
||||
- drm_dbg(hdmi, "connector status changed\n");
|
||||
+ dev_dbg(hdmi->dev, "connector status changed\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
}
|
||||
}
|
||||
if (hdmi->port_id < 0) {
|
||||
- drm_err(hdmi, "Failed to match HDMI port ID\n");
|
||||
+ dev_err(hdmi->dev, "Failed to match HDMI port ID\n");
|
||||
return hdmi->port_id;
|
||||
}
|
||||
|
||||
@@ -496,20 +496,20 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,grf");
|
||||
if (IS_ERR(hdmi->regmap)) {
|
||||
- drm_err(hdmi, "Unable to get rockchip,grf\n");
|
||||
+ dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
|
||||
return PTR_ERR(hdmi->regmap);
|
||||
}
|
||||
|
||||
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,vo-grf");
|
||||
if (IS_ERR(hdmi->vo_regmap)) {
|
||||
- drm_err(hdmi, "Unable to get rockchip,vo-grf\n");
|
||||
+ dev_err(hdmi->dev, "Unable to get rockchip,vo-grf\n");
|
||||
return PTR_ERR(hdmi->vo_regmap);
|
||||
}
|
||||
|
||||
ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
|
||||
if (ret < 0) {
|
||||
- drm_err(hdmi, "Failed to get clocks: %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "Failed to get clocks: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -517,7 +517,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(hdmi->enable_gpio)) {
|
||||
ret = PTR_ERR(hdmi->enable_gpio);
|
||||
- drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "Failed to request enable GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -525,7 +525,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
if (IS_ERR(hdmi->phy)) {
|
||||
ret = PTR_ERR(hdmi->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
- drm_err(hdmi, "failed to get phy: %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "failed to get phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
connector = drm_bridge_connector_init(drm, encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
ret = PTR_ERR(connector);
|
||||
- drm_err(hdmi, "failed to init bridge connector: %d\n", ret);
|
||||
+ dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
From d4f5efb9139cad34823f265053c57baf6af3c70c Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Date: Tue, 4 Mar 2025 13:44:16 +0100
|
||||
Subject: [PATCH] drm/rockchip: lvds: move pclk preparation in with clk_get
|
||||
|
||||
The LVDS block needs a separate pclk only on some socs, so currently
|
||||
requests and prepares it in the soc-specific probe function, but common
|
||||
code is required to unprepare it in the error path or on driver remove.
|
||||
|
||||
While this works because clk_unprepare just does nothing if clk is NULL,
|
||||
this mismatch of who is responsible still is not very nice.
|
||||
The clock-framework already has a helper for clk-get-and-prepare even
|
||||
with devres support in devm_clk_get_prepared().
|
||||
|
||||
This will get and prepare the clock and also unprepare it on driver
|
||||
removal, saving the driver from having to handle it "manually".
|
||||
|
||||
Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>
|
||||
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250304124418.111061-2-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_lvds.c | 19 +++----------------
|
||||
1 file changed, 3 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
@@ -448,15 +448,13 @@ struct drm_encoder_helper_funcs px30_lvd
|
||||
static int rk3288_lvds_probe(struct platform_device *pdev,
|
||||
struct rockchip_lvds *lvds)
|
||||
{
|
||||
- int ret;
|
||||
-
|
||||
lvds->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(lvds->regs))
|
||||
return PTR_ERR(lvds->regs);
|
||||
|
||||
- lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds");
|
||||
+ lvds->pclk = devm_clk_get_prepared(lvds->dev, "pclk_lvds");
|
||||
if (IS_ERR(lvds->pclk)) {
|
||||
- DRM_DEV_ERROR(lvds->dev, "could not get pclk_lvds\n");
|
||||
+ DRM_DEV_ERROR(lvds->dev, "could not get or prepare pclk_lvds\n");
|
||||
return PTR_ERR(lvds->pclk);
|
||||
}
|
||||
|
||||
@@ -480,12 +478,6 @@ static int rk3288_lvds_probe(struct plat
|
||||
}
|
||||
}
|
||||
|
||||
- ret = clk_prepare(lvds->pclk);
|
||||
- if (ret < 0) {
|
||||
- DRM_DEV_ERROR(lvds->dev, "failed to prepare pclk_lvds\n");
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -728,20 +720,15 @@ static int rockchip_lvds_probe(struct pl
|
||||
dev_set_drvdata(dev, lvds);
|
||||
|
||||
ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
|
||||
- if (ret < 0) {
|
||||
+ if (ret < 0)
|
||||
DRM_DEV_ERROR(dev, "failed to add component\n");
|
||||
- clk_unprepare(lvds->pclk);
|
||||
- }
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_lvds_remove(struct platform_device *pdev)
|
||||
{
|
||||
- struct rockchip_lvds *lvds = platform_get_drvdata(pdev);
|
||||
-
|
||||
component_del(&pdev->dev, &rockchip_lvds_component_ops);
|
||||
- clk_unprepare(lvds->pclk);
|
||||
}
|
||||
|
||||
struct platform_driver rockchip_lvds_driver = {
|
||||
@ -0,0 +1,184 @@
|
||||
From 37c18639504aacbd31371f562fabafdb890bcd2e Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Date: Tue, 4 Mar 2025 13:44:17 +0100
|
||||
Subject: [PATCH] drm/rockchip: lvds: Hide scary error messages on probe
|
||||
deferral
|
||||
|
||||
Commit 52d11c863ac9 ("drm/rockchip: lvds: do not print scary message when
|
||||
probing defer") already started hiding scary messages that are not relevant
|
||||
if the requested supply just returned EPROBE_DEFER, but there are more
|
||||
possible sources - like the phy.
|
||||
|
||||
So modernize the whole logging in the probe path by replacing the
|
||||
remaining deprecated DRM_DEV_ERROR with appropriate dev_err(_probe)
|
||||
and drm_err calls.
|
||||
|
||||
The distinction here is that all messages talking about mishaps of the
|
||||
lvds element use dev_err(_probe) while messages caused by interaction
|
||||
with the main Rockchip drm-device use drm_err.
|
||||
|
||||
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250304124418.111061-3-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_lvds.c | 63 ++++++++++--------------
|
||||
1 file changed, 27 insertions(+), 36 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
@@ -453,10 +453,9 @@ static int rk3288_lvds_probe(struct plat
|
||||
return PTR_ERR(lvds->regs);
|
||||
|
||||
lvds->pclk = devm_clk_get_prepared(lvds->dev, "pclk_lvds");
|
||||
- if (IS_ERR(lvds->pclk)) {
|
||||
- DRM_DEV_ERROR(lvds->dev, "could not get or prepare pclk_lvds\n");
|
||||
- return PTR_ERR(lvds->pclk);
|
||||
- }
|
||||
+ if (IS_ERR(lvds->pclk))
|
||||
+ return dev_err_probe(lvds->dev, PTR_ERR(lvds->pclk),
|
||||
+ "could not get or prepare pclk_lvds\n");
|
||||
|
||||
lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins),
|
||||
GFP_KERNEL);
|
||||
@@ -465,14 +464,14 @@ static int rk3288_lvds_probe(struct plat
|
||||
|
||||
lvds->pins->p = devm_pinctrl_get(lvds->dev);
|
||||
if (IS_ERR(lvds->pins->p)) {
|
||||
- DRM_DEV_ERROR(lvds->dev, "no pinctrl handle\n");
|
||||
+ dev_err(lvds->dev, "no pinctrl handle\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
} else {
|
||||
lvds->pins->default_state =
|
||||
pinctrl_lookup_state(lvds->pins->p, "lcdc");
|
||||
if (IS_ERR(lvds->pins->default_state)) {
|
||||
- DRM_DEV_ERROR(lvds->dev, "no default pinctrl state\n");
|
||||
+ dev_err(lvds->dev, "no default pinctrl state\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
}
|
||||
@@ -547,11 +546,10 @@ static int rockchip_lvds_bind(struct dev
|
||||
|
||||
lvds->drm_dev = drm_dev;
|
||||
port = of_graph_get_port_by_id(dev->of_node, 1);
|
||||
- if (!port) {
|
||||
- DRM_DEV_ERROR(dev,
|
||||
- "can't found port point, please init lvds panel port!\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ if (!port)
|
||||
+ return dev_err_probe(dev, -EINVAL,
|
||||
+ "can't found port point, please init lvds panel port!\n");
|
||||
+
|
||||
for_each_child_of_node(port, endpoint) {
|
||||
child_count++;
|
||||
of_property_read_u32(endpoint, "reg", &endpoint_id);
|
||||
@@ -563,8 +561,7 @@ static int rockchip_lvds_bind(struct dev
|
||||
}
|
||||
}
|
||||
if (!child_count) {
|
||||
- DRM_DEV_ERROR(dev, "lvds port does not have any children\n");
|
||||
- ret = -EINVAL;
|
||||
+ ret = dev_err_probe(dev, -EINVAL, "lvds port does not have any children\n");
|
||||
goto err_put_port;
|
||||
} else if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to find panel and bridge node\n");
|
||||
@@ -581,8 +578,7 @@ static int rockchip_lvds_bind(struct dev
|
||||
lvds->output = rockchip_lvds_name_to_output(name);
|
||||
|
||||
if (lvds->output < 0) {
|
||||
- DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name);
|
||||
- ret = lvds->output;
|
||||
+ ret = dev_err_probe(dev, lvds->output, "invalid output type [%s]\n", name);
|
||||
goto err_put_remote;
|
||||
}
|
||||
|
||||
@@ -593,8 +589,8 @@ static int rockchip_lvds_bind(struct dev
|
||||
lvds->format = rockchip_lvds_name_to_format(name);
|
||||
|
||||
if (lvds->format < 0) {
|
||||
- DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name);
|
||||
- ret = lvds->format;
|
||||
+ ret = dev_err_probe(dev, lvds->format,
|
||||
+ "invalid data-mapping format [%s]\n", name);
|
||||
goto err_put_remote;
|
||||
}
|
||||
|
||||
@@ -604,8 +600,8 @@ static int rockchip_lvds_bind(struct dev
|
||||
|
||||
ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
|
||||
if (ret < 0) {
|
||||
- DRM_DEV_ERROR(drm_dev->dev,
|
||||
- "failed to initialize encoder: %d\n", ret);
|
||||
+ drm_err(drm_dev,
|
||||
+ "failed to initialize encoder: %d\n", ret);
|
||||
goto err_put_remote;
|
||||
}
|
||||
|
||||
@@ -618,8 +614,8 @@ static int rockchip_lvds_bind(struct dev
|
||||
&rockchip_lvds_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret < 0) {
|
||||
- DRM_DEV_ERROR(drm_dev->dev,
|
||||
- "failed to initialize connector: %d\n", ret);
|
||||
+ drm_err(drm_dev,
|
||||
+ "failed to initialize connector: %d\n", ret);
|
||||
goto err_free_encoder;
|
||||
}
|
||||
|
||||
@@ -633,9 +629,9 @@ static int rockchip_lvds_bind(struct dev
|
||||
|
||||
connector = drm_bridge_connector_init(lvds->drm_dev, encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
- DRM_DEV_ERROR(drm_dev->dev,
|
||||
- "failed to initialize bridge connector: %pe\n",
|
||||
- connector);
|
||||
+ drm_err(drm_dev,
|
||||
+ "failed to initialize bridge connector: %pe\n",
|
||||
+ connector);
|
||||
ret = PTR_ERR(connector);
|
||||
goto err_free_encoder;
|
||||
}
|
||||
@@ -643,8 +639,7 @@ static int rockchip_lvds_bind(struct dev
|
||||
|
||||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
if (ret < 0) {
|
||||
- DRM_DEV_ERROR(drm_dev->dev,
|
||||
- "failed to attach encoder: %d\n", ret);
|
||||
+ drm_err(drm_dev, "failed to attach encoder: %d\n", ret);
|
||||
goto err_free_connector;
|
||||
}
|
||||
|
||||
@@ -706,24 +701,20 @@ static int rockchip_lvds_probe(struct pl
|
||||
|
||||
lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,grf");
|
||||
- if (IS_ERR(lvds->grf)) {
|
||||
- DRM_DEV_ERROR(dev, "missing rockchip,grf property\n");
|
||||
- return PTR_ERR(lvds->grf);
|
||||
- }
|
||||
+ if (IS_ERR(lvds->grf))
|
||||
+ return dev_err_probe(dev, PTR_ERR(lvds->grf), "missing rockchip,grf property\n");
|
||||
|
||||
ret = lvds->soc_data->probe(pdev, lvds);
|
||||
- if (ret) {
|
||||
- DRM_DEV_ERROR(dev, "Platform initialization failed\n");
|
||||
- return ret;
|
||||
- }
|
||||
+ if (ret)
|
||||
+ return dev_err_probe(dev, ret, "Platform initialization failed\n");
|
||||
|
||||
dev_set_drvdata(dev, lvds);
|
||||
|
||||
ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
|
||||
if (ret < 0)
|
||||
- DRM_DEV_ERROR(dev, "failed to add component\n");
|
||||
+ return dev_err_probe(dev, ret, "failed to add component\n");
|
||||
|
||||
- return ret;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void rockchip_lvds_remove(struct platform_device *pdev)
|
||||
@ -0,0 +1,39 @@
|
||||
From 4006be2f77cd26d065133b338dc51f59857d20f0 Mon Sep 17 00:00:00 2001
|
||||
From: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Date: Tue, 4 Mar 2025 13:44:18 +0100
|
||||
Subject: [PATCH] drm/rockchip: lvds: lower log severity for missing pinctrl
|
||||
settings
|
||||
|
||||
While missing lvds pinctrl is unexpected and is reported, we nevertheless
|
||||
don't fail setting up the device and instead continue without explicit
|
||||
pinctrl handling. So lower the log-level from error to warning to reflect
|
||||
that.
|
||||
|
||||
Suggested-by: Quentin Schulz <quentin.schulz@cherry.de>
|
||||
Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
|
||||
Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20250304124418.111061-4-heiko@sntech.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_lvds.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
|
||||
@@ -464,14 +464,14 @@ static int rk3288_lvds_probe(struct plat
|
||||
|
||||
lvds->pins->p = devm_pinctrl_get(lvds->dev);
|
||||
if (IS_ERR(lvds->pins->p)) {
|
||||
- dev_err(lvds->dev, "no pinctrl handle\n");
|
||||
+ dev_warn(lvds->dev, "no pinctrl handle\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
} else {
|
||||
lvds->pins->default_state =
|
||||
pinctrl_lookup_state(lvds->pins->p, "lcdc");
|
||||
if (IS_ERR(lvds->pins->default_state)) {
|
||||
- dev_err(lvds->dev, "no default pinctrl state\n");
|
||||
+ dev_warn(lvds->dev, "no default pinctrl state\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
From bcdc354a0a545e0e78c6f068e5a11c0285e06eeb Mon Sep 17 00:00:00 2001
|
||||
From: Lucas Stach <l.stach@pengutronix.de>
|
||||
Date: Fri, 7 Feb 2025 19:22:46 +0100
|
||||
Subject: [PATCH] drm/rockchip: vop: remove redundant condition check
|
||||
|
||||
Instead of checking the same thing twice in a row, fold the second
|
||||
condition into the first clause.
|
||||
|
||||
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
|
||||
Reviewed-by: Andy Yan <andyshrk@163.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250207182247.215537-1-l.stach@pengutronix.de
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 ++---
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
|
||||
@@ -733,11 +733,10 @@ static void vop_crtc_atomic_disable(stru
|
||||
|
||||
WARN_ON(vop->event);
|
||||
|
||||
- if (crtc->state->self_refresh_active)
|
||||
+ if (crtc->state->self_refresh_active) {
|
||||
rockchip_drm_set_win_enabled(crtc, false);
|
||||
-
|
||||
- if (crtc->state->self_refresh_active)
|
||||
goto out;
|
||||
+ }
|
||||
|
||||
mutex_lock(&vop->vop_lock);
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From c5996e4ab109c8bb5541453b20647eaaf9350f41 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Tue, 18 Mar 2025 14:20:17 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Make overlay layer select register
|
||||
configuration take effect by vsync
|
||||
|
||||
Because the layer/window enable/disable is take effect by vsync, if the
|
||||
overlay configuration of these layers does not follow vsync and
|
||||
takes effect immediately instead, when multiple layers are dynamically
|
||||
enable/disable, inconsistent display contents may be seen on the screen.
|
||||
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250318062024.4555-1-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 +
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 5 ++++-
|
||||
2 files changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -710,6 +710,7 @@ enum dst_factor_mode {
|
||||
|
||||
#define VOP2_COLOR_KEY_MASK BIT(31)
|
||||
|
||||
+#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL GENMASK(31, 30)
|
||||
#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28)
|
||||
#define RK3568_OVL_CTRL__YUV_MODE(vp) BIT(vp)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -2070,7 +2070,10 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
|
||||
|
||||
ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
|
||||
- ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
|
||||
+ ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
|
||||
+ ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL;
|
||||
+ ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
|
||||
+
|
||||
if (vcstate->yuv_overlay)
|
||||
ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);
|
||||
else
|
||||
@ -0,0 +1,31 @@
|
||||
From 210db264cf87da8908c395b44170f04469009035 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Wed, 12 Mar 2025 14:42:10 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Fix interface enable/mux setting of DP1
|
||||
on rk3588
|
||||
|
||||
This is a copy-paste error, which affects DP1 usage.
|
||||
|
||||
Fixes: 328e6885996c ("drm/rockchip: vop2: Add platform specific callback")
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250312064218.524143-1-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -1754,9 +1754,9 @@ static unsigned long rk3588_set_intf_mux
|
||||
dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP0_PIN_POL, polflags);
|
||||
break;
|
||||
case ROCKCHIP_VOP2_EP_DP1:
|
||||
- die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;
|
||||
- die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |
|
||||
- FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
|
||||
+ die &= ~RK3588_SYS_DSP_INFACE_EN_DP1_MUX;
|
||||
+ die |= RK3588_SYS_DSP_INFACE_EN_DP1 |
|
||||
+ FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_DP1_MUX, vp->id);
|
||||
dip &= ~RK3588_DSP_IF_POL__DP1_PIN_POL;
|
||||
dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP1_PIN_POL, polflags);
|
||||
break;
|
||||
@ -0,0 +1,65 @@
|
||||
From 1d34597a1e23004c7dd0ab5f58ba1ef95fd9ded5 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Mon, 17 Mar 2025 18:27:53 +0800
|
||||
Subject: [PATCH] drm/rockchip: dw_hdmi_qp: Fix io init for
|
||||
dw_hdmi_qp_rockchip_resume
|
||||
|
||||
Use cfg->ctrl_ops->io_init callback make it work for all platform.
|
||||
And it's also gets rid of code duplication
|
||||
|
||||
Fixes: 3f60dbd40d3f ("drm/rockchip: dw_hdmi_qp: Add platform ctrl callback")
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250317102757.565679-1-andyshrk@163.com
|
||||
---
|
||||
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 23 +++----------------
|
||||
1 file changed, 3 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
|
||||
@@ -94,6 +94,7 @@ struct rockchip_hdmi_qp {
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct delayed_work hpd_work;
|
||||
int port_id;
|
||||
+ const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
|
||||
};
|
||||
|
||||
struct rockchip_hdmi_qp_ctrl_ops {
|
||||
@@ -461,6 +462,7 @@ static int dw_hdmi_qp_rockchip_bind(stru
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
+ hdmi->ctrl_ops = cfg->ctrl_ops;
|
||||
hdmi->dev = &pdev->dev;
|
||||
hdmi->port_id = -ENODEV;
|
||||
|
||||
@@ -600,27 +602,8 @@ static void dw_hdmi_qp_rockchip_remove(s
|
||||
static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
- u32 val;
|
||||
|
||||
- val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
|
||||
- HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
|
||||
- regmap_write(hdmi->vo_regmap,
|
||||
- hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
|
||||
- val);
|
||||
-
|
||||
- val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
|
||||
- RK3588_SET_HPD_PATH_MASK);
|
||||
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
|
||||
-
|
||||
- if (hdmi->port_id)
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
|
||||
- RK3588_HDMI1_GRANT_SEL);
|
||||
- else
|
||||
- val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
|
||||
- RK3588_HDMI0_GRANT_SEL);
|
||||
- regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
+ hdmi->ctrl_ops->io_init(hdmi);
|
||||
|
||||
dw_hdmi_qp_resume(dev, hdmi->hdmi);
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
From efab13e7d13a641a22c7508cde6e1a5285161944 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:02 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Add irq flag IRQF_NO_AUTOEN instead
|
||||
of calling disable_irq()
|
||||
|
||||
The IRQF_NO_AUTOEN can be used for the drivers that don't want
|
||||
interrupts to be enabled automatically via devm_request_threaded_irq().
|
||||
Using this flag can provide be more robust compared to the way of
|
||||
calling disable_irq() after devm_request_threaded_irq() without the
|
||||
IRQF_NO_AUTOEN flag.
|
||||
|
||||
Suggested-by: Douglas Anderson <dianders@chromium.org>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-2-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 5 ++---
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1636,10 +1636,10 @@ analogix_dp_probe(struct device *dev, st
|
||||
* that we can get the current state of the GPIO.
|
||||
*/
|
||||
dp->irq = gpiod_to_irq(dp->hpd_gpiod);
|
||||
- irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
|
||||
+ irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN;
|
||||
} else {
|
||||
dp->irq = platform_get_irq(pdev, 0);
|
||||
- irq_flags = 0;
|
||||
+ irq_flags = IRQF_NO_AUTOEN;
|
||||
}
|
||||
|
||||
if (dp->irq == -ENXIO) {
|
||||
@@ -1656,7 +1656,6 @@ analogix_dp_probe(struct device *dev, st
|
||||
dev_err(&pdev->dev, "failed to request irq\n");
|
||||
goto err_disable_clk;
|
||||
}
|
||||
- disable_irq(dp->irq);
|
||||
|
||||
return dp;
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
From c71db051142a74b255cb61b84d8fedae3b70952f Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:03 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Remove CONFIG_PM related check in
|
||||
analogix_dp_bind()/analogix_dp_unbind()
|
||||
|
||||
Remove the check related to CONFIG_PM in order to make the code more
|
||||
concise, as the CONFIG_PM should be a required option for many drivers.
|
||||
|
||||
In addition, it is preferable to use devm_pm_runtime_enable() instead of
|
||||
manually invoking pm_runtime_enable() followed by pm_runtime_disable().
|
||||
|
||||
Suggested-by: Douglas Anderson <dianders@chromium.org>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-3-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../drm/bridge/analogix/analogix_dp_core.c | 30 ++++---------------
|
||||
1 file changed, 6 insertions(+), 24 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1706,15 +1706,11 @@ int analogix_dp_bind(struct analogix_dp_
|
||||
dp->drm_dev = drm_dev;
|
||||
dp->encoder = dp->plat_data->encoder;
|
||||
|
||||
- if (IS_ENABLED(CONFIG_PM)) {
|
||||
- pm_runtime_use_autosuspend(dp->dev);
|
||||
- pm_runtime_set_autosuspend_delay(dp->dev, 100);
|
||||
- pm_runtime_enable(dp->dev);
|
||||
- } else {
|
||||
- ret = analogix_dp_resume(dp);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- }
|
||||
+ pm_runtime_use_autosuspend(dp->dev);
|
||||
+ pm_runtime_set_autosuspend_delay(dp->dev, 100);
|
||||
+ ret = devm_pm_runtime_enable(dp->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
dp->aux.name = "DP-AUX";
|
||||
dp->aux.transfer = analogix_dpaux_transfer;
|
||||
@@ -1724,7 +1720,7 @@ int analogix_dp_bind(struct analogix_dp_
|
||||
ret = drm_dp_aux_register(&dp->aux);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to register AUX (%d)\n", ret);
|
||||
- goto err_disable_pm_runtime;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
ret = analogix_dp_create_bridge(drm_dev, dp);
|
||||
@@ -1737,13 +1733,6 @@ int analogix_dp_bind(struct analogix_dp_
|
||||
|
||||
err_unregister_aux:
|
||||
drm_dp_aux_unregister(&dp->aux);
|
||||
-err_disable_pm_runtime:
|
||||
- if (IS_ENABLED(CONFIG_PM)) {
|
||||
- pm_runtime_dont_use_autosuspend(dp->dev);
|
||||
- pm_runtime_disable(dp->dev);
|
||||
- } else {
|
||||
- analogix_dp_suspend(dp);
|
||||
- }
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1760,13 +1749,6 @@ void analogix_dp_unbind(struct analogix_
|
||||
}
|
||||
|
||||
drm_dp_aux_unregister(&dp->aux);
|
||||
-
|
||||
- if (IS_ENABLED(CONFIG_PM)) {
|
||||
- pm_runtime_dont_use_autosuspend(dp->dev);
|
||||
- pm_runtime_disable(dp->dev);
|
||||
- } else {
|
||||
- analogix_dp_suspend(dp);
|
||||
- }
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
|
||||
|
||||
@ -0,0 +1,121 @@
|
||||
From 2c0883459ed62ac65784289e9236d673102eee68 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:04 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Add support for phy configuration.
|
||||
|
||||
Add support to configurate link rate, lane count, voltage swing and
|
||||
pre-emphasis with phy_configure(). It is helpful in application scenarios
|
||||
where analogix controller is mixed with the phy of other vendors.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-4-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../drm/bridge/analogix/analogix_dp_core.c | 1 +
|
||||
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 52 +++++++++++++++++++
|
||||
2 files changed, 53 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1691,6 +1691,7 @@ int analogix_dp_resume(struct analogix_d
|
||||
if (dp->plat_data->power_on)
|
||||
dp->plat_data->power_on(dp->plat_data);
|
||||
|
||||
+ phy_set_mode(dp->phy, PHY_MODE_DP);
|
||||
phy_power_on(dp->phy);
|
||||
|
||||
analogix_dp_init_dp(dp);
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
|
||||
#include <drm/bridge/analogix_dp.h>
|
||||
|
||||
@@ -513,10 +514,24 @@ void analogix_dp_enable_sw_function(stru
|
||||
void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
|
||||
{
|
||||
u32 reg;
|
||||
+ int ret;
|
||||
|
||||
reg = bwtype;
|
||||
if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62))
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET);
|
||||
+
|
||||
+ if (dp->phy) {
|
||||
+ union phy_configure_opts phy_cfg = {0};
|
||||
+
|
||||
+ phy_cfg.dp.link_rate =
|
||||
+ drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
|
||||
+ phy_cfg.dp.set_rate = true;
|
||||
+ ret = phy_configure(dp->phy, &phy_cfg);
|
||||
+ if (ret && ret != -EOPNOTSUPP) {
|
||||
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)
|
||||
@@ -530,9 +545,22 @@ void analogix_dp_get_link_bandwidth(stru
|
||||
void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)
|
||||
{
|
||||
u32 reg;
|
||||
+ int ret;
|
||||
|
||||
reg = count;
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);
|
||||
+
|
||||
+ if (dp->phy) {
|
||||
+ union phy_configure_opts phy_cfg = {0};
|
||||
+
|
||||
+ phy_cfg.dp.lanes = dp->link_train.lane_count;
|
||||
+ phy_cfg.dp.set_lanes = true;
|
||||
+ ret = phy_configure(dp->phy, &phy_cfg);
|
||||
+ if (ret && ret != -EOPNOTSUPP) {
|
||||
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count)
|
||||
@@ -546,10 +574,34 @@ void analogix_dp_get_lane_count(struct a
|
||||
void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp)
|
||||
{
|
||||
u8 lane;
|
||||
+ int ret;
|
||||
|
||||
for (lane = 0; lane < dp->link_train.lane_count; lane++)
|
||||
writel(dp->link_train.training_lane[lane],
|
||||
dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane);
|
||||
+
|
||||
+ if (dp->phy) {
|
||||
+ union phy_configure_opts phy_cfg = {0};
|
||||
+
|
||||
+ for (lane = 0; lane < dp->link_train.lane_count; lane++) {
|
||||
+ u8 training_lane = dp->link_train.training_lane[lane];
|
||||
+ u8 vs, pe;
|
||||
+
|
||||
+ vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >>
|
||||
+ DP_TRAIN_VOLTAGE_SWING_SHIFT;
|
||||
+ pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >>
|
||||
+ DP_TRAIN_PRE_EMPHASIS_SHIFT;
|
||||
+ phy_cfg.dp.voltage[lane] = vs;
|
||||
+ phy_cfg.dp.pre[lane] = pe;
|
||||
+ }
|
||||
+
|
||||
+ phy_cfg.dp.set_voltages = true;
|
||||
+ ret = phy_configure(dp->phy, &phy_cfg);
|
||||
+ if (ret && ret != -EOPNOTSUPP) {
|
||||
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane)
|
||||
@ -0,0 +1,61 @@
|
||||
From fd073dffef041d6a2d11f00cd6cbd8ff46083396 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:06 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Support to get
|
||||
&analogix_dp_device.plat_data and &analogix_dp_device.aux
|
||||
|
||||
Add two new functions: one to find &analogix_dp_device.plat_data via
|
||||
&drm_dp_aux, and the other to get &analogix_dp_device.aux. Both of them
|
||||
serve for the function of getting panel from DP AUX bus, which is why
|
||||
they are included in a single commit.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-6-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 14 ++++++++++++++
|
||||
include/drm/bridge/analogix_dp.h | 4 ++++
|
||||
2 files changed, 18 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1775,6 +1775,20 @@ int analogix_dp_stop_crc(struct drm_conn
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(analogix_dp_stop_crc);
|
||||
|
||||
+struct analogix_dp_plat_data *analogix_dp_aux_to_plat_data(struct drm_dp_aux *aux)
|
||||
+{
|
||||
+ struct analogix_dp_device *dp = to_dp(aux);
|
||||
+
|
||||
+ return dp->plat_data;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(analogix_dp_aux_to_plat_data);
|
||||
+
|
||||
+struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
|
||||
+{
|
||||
+ return &dp->aux;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
|
||||
+
|
||||
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
|
||||
MODULE_DESCRIPTION("Analogix DP Core Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
--- a/include/drm/bridge/analogix_dp.h
|
||||
+++ b/include/drm/bridge/analogix_dp.h
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
struct analogix_dp_device;
|
||||
+struct drm_dp_aux;
|
||||
|
||||
enum analogix_dp_devtype {
|
||||
EXYNOS_DP,
|
||||
@@ -48,4 +49,7 @@ void analogix_dp_unbind(struct analogix_
|
||||
int analogix_dp_start_crc(struct drm_connector *connector);
|
||||
int analogix_dp_stop_crc(struct drm_connector *connector);
|
||||
|
||||
+struct analogix_dp_plat_data *analogix_dp_aux_to_plat_data(struct drm_dp_aux *aux);
|
||||
+struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp);
|
||||
+
|
||||
#endif /* _ANALOGIX_DP_H_ */
|
||||
@ -0,0 +1,56 @@
|
||||
From e5e9fa9f7aad4ad7eedb6359baea9193531bf4ac Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:07 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Add support to get panel from the DP
|
||||
AUX bus
|
||||
|
||||
The main modification is moving the DP AUX initialization from function
|
||||
analogix_dp_bind() to analogix_dp_probe(). In order to get the EDID of
|
||||
eDP panel during probing, it is also needed to advance PM operations to
|
||||
ensure that eDP controller and phy are prepared for AUX transmission.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-7-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../drm/bridge/analogix/analogix_dp_core.c | 20 ++++++++++---------
|
||||
1 file changed, 11 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1657,6 +1657,17 @@ analogix_dp_probe(struct device *dev, st
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
+ dp->aux.name = "DP-AUX";
|
||||
+ dp->aux.transfer = analogix_dpaux_transfer;
|
||||
+ dp->aux.dev = dp->dev;
|
||||
+ drm_dp_aux_init(&dp->aux);
|
||||
+
|
||||
+ pm_runtime_use_autosuspend(dp->dev);
|
||||
+ pm_runtime_set_autosuspend_delay(dp->dev, 100);
|
||||
+ ret = devm_pm_runtime_enable(dp->dev);
|
||||
+ if (ret)
|
||||
+ goto err_disable_clk;
|
||||
+
|
||||
return dp;
|
||||
|
||||
err_disable_clk:
|
||||
@@ -1707,15 +1718,6 @@ int analogix_dp_bind(struct analogix_dp_
|
||||
dp->drm_dev = drm_dev;
|
||||
dp->encoder = dp->plat_data->encoder;
|
||||
|
||||
- pm_runtime_use_autosuspend(dp->dev);
|
||||
- pm_runtime_set_autosuspend_delay(dp->dev, 100);
|
||||
- ret = devm_pm_runtime_enable(dp->dev);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- dp->aux.name = "DP-AUX";
|
||||
- dp->aux.transfer = analogix_dpaux_transfer;
|
||||
- dp->aux.dev = dp->dev;
|
||||
dp->aux.drm_dev = drm_dev;
|
||||
|
||||
ret = drm_dp_aux_register(&dp->aux);
|
||||
@ -0,0 +1,55 @@
|
||||
From c8f0b7cb01eadef03558b21245357683409da438 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:08 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Add support for
|
||||
&drm_dp_aux.wait_hpd_asserted()
|
||||
|
||||
Add analogix_dpaux_wait_hpd_asserted() to help confirm the HPD state
|
||||
before doing AUX transfers.
|
||||
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-8-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../drm/bridge/analogix/analogix_dp_core.c | 21 +++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1548,6 +1548,26 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int analogix_dpaux_wait_hpd_asserted(struct drm_dp_aux *aux, unsigned long wait_us)
|
||||
+{
|
||||
+ struct analogix_dp_device *dp = to_dp(aux);
|
||||
+ int val;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (dp->force_hpd)
|
||||
+ return 0;
|
||||
+
|
||||
+ pm_runtime_get_sync(dp->dev);
|
||||
+
|
||||
+ ret = readx_poll_timeout(analogix_dp_get_plug_in_status, dp, val, !val,
|
||||
+ wait_us / 100, wait_us);
|
||||
+
|
||||
+ pm_runtime_mark_last_busy(dp->dev);
|
||||
+ pm_runtime_put_autosuspend(dp->dev);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
struct analogix_dp_device *
|
||||
analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
|
||||
{
|
||||
@@ -1659,6 +1679,7 @@ analogix_dp_probe(struct device *dev, st
|
||||
|
||||
dp->aux.name = "DP-AUX";
|
||||
dp->aux.transfer = analogix_dpaux_transfer;
|
||||
+ dp->aux.wait_hpd_asserted = analogix_dpaux_wait_hpd_asserted;
|
||||
dp->aux.dev = dp->dev;
|
||||
drm_dp_aux_init(&dp->aux);
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
From d7b4936b2bc0987ccea125d9653381a1a0038d6d Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:09 +0800
|
||||
Subject: [PATCH] drm/rockchip: analogix_dp: Add support to get panel from the
|
||||
DP AUX bus
|
||||
|
||||
Move drm_of_find_panel_or_bridge() a little later and combine it with
|
||||
component_add() into a new function rockchip_dp_link_panel(). The function
|
||||
will serve as done_probing() callback of devm_of_dp_aux_populate_bus(),
|
||||
aiding to support for obtaining the eDP panel via the DP AUX bus.
|
||||
|
||||
If failed to get the panel from the DP AUX bus, it will then try the other
|
||||
way to get panel information through the platform bus.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Reviewed-by: Douglas Anderson <dianders@chromium.org>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-9-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
drivers/gpu/drm/rockchip/Kconfig | 1 +
|
||||
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 42 +++++++++++++++----
|
||||
2 files changed, 34 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/Kconfig
|
||||
+++ b/drivers/gpu/drm/rockchip/Kconfig
|
||||
@@ -8,6 +8,7 @@ config DRM_ROCKCHIP
|
||||
select DRM_PANEL
|
||||
select VIDEOMODE_HELPERS
|
||||
select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
|
||||
+ select DRM_DISPLAY_DP_AUX_BUS if ROCKCHIP_ANALOGIX_DP
|
||||
select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
|
||||
select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP
|
||||
select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
|
||||
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
+#include <drm/display/drm_dp_aux_bus.h>
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
@@ -392,11 +393,28 @@ static const struct component_ops rockch
|
||||
.unbind = rockchip_dp_unbind,
|
||||
};
|
||||
|
||||
+static int rockchip_dp_link_panel(struct drm_dp_aux *aux)
|
||||
+{
|
||||
+ struct analogix_dp_plat_data *plat_data = analogix_dp_aux_to_plat_data(aux);
|
||||
+ struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
|
||||
+ * or bridge nodes. The driver should go on for the driver-free bridge or the DP
|
||||
+ * mode applications.
|
||||
+ */
|
||||
+ ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 1, 0, &plat_data->panel, NULL);
|
||||
+ if (ret && ret != -ENODEV)
|
||||
+ return ret;
|
||||
+
|
||||
+ return component_add(dp->dev, &rockchip_dp_component_ops);
|
||||
+}
|
||||
+
|
||||
static int rockchip_dp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct rockchip_dp_chip_data *dp_data;
|
||||
- struct drm_panel *panel = NULL;
|
||||
struct rockchip_dp_device *dp;
|
||||
struct resource *res;
|
||||
int i;
|
||||
@@ -406,10 +424,6 @@ static int rockchip_dp_probe(struct plat
|
||||
if (!dp_data)
|
||||
return -ENODEV;
|
||||
|
||||
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
|
||||
- if (ret < 0 && ret != -ENODEV)
|
||||
- return ret;
|
||||
-
|
||||
dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
|
||||
if (!dp)
|
||||
return -ENOMEM;
|
||||
@@ -432,7 +446,6 @@ static int rockchip_dp_probe(struct plat
|
||||
|
||||
dp->dev = dev;
|
||||
dp->adp = ERR_PTR(-ENODEV);
|
||||
- dp->plat_data.panel = panel;
|
||||
dp->plat_data.dev_type = dp->data->chip_type;
|
||||
dp->plat_data.power_on = rockchip_dp_poweron;
|
||||
dp->plat_data.power_off = rockchip_dp_powerdown;
|
||||
@@ -448,9 +461,20 @@ static int rockchip_dp_probe(struct plat
|
||||
if (IS_ERR(dp->adp))
|
||||
return PTR_ERR(dp->adp);
|
||||
|
||||
- ret = component_add(dev, &rockchip_dp_component_ops);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ ret = devm_of_dp_aux_populate_bus(analogix_dp_get_aux(dp->adp), rockchip_dp_link_panel);
|
||||
+ if (ret) {
|
||||
+ /*
|
||||
+ * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will not
|
||||
+ * be called because there are no EP devices. Then the rockchip_dp_link_panel()
|
||||
+ * will be called directly in order to support the other valid DT configurations.
|
||||
+ *
|
||||
+ * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER.
|
||||
+ */
|
||||
+ if (ret != -ENODEV)
|
||||
+ return dev_err_probe(dp->dev, ret, "failed to populate aux bus\n");
|
||||
+
|
||||
+ return rockchip_dp_link_panel(analogix_dp_get_aux(dp->adp));
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
From 0e8b86b6df143662c631dee8bb3b1fff368aa18a Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:11 +0800
|
||||
Subject: [PATCH] drm/bridge: analogix_dp: Add support for RK3588
|
||||
|
||||
Expand enum analogix_dp_devtype with RK3588_EDP, and add max_link_rate
|
||||
and max_lane_count configs for it.
|
||||
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-11-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++++
|
||||
include/drm/bridge/analogix_dp.h | 3 ++-
|
||||
2 files changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1513,6 +1513,10 @@ static int analogix_dp_dt_parse_pdata(st
|
||||
video_info->max_link_rate = 0x0A;
|
||||
video_info->max_lane_count = 0x04;
|
||||
break;
|
||||
+ case RK3588_EDP:
|
||||
+ video_info->max_link_rate = 0x14;
|
||||
+ video_info->max_lane_count = 0x04;
|
||||
+ break;
|
||||
case EXYNOS_DP:
|
||||
/*
|
||||
* NOTE: those property parseing code is used for
|
||||
--- a/include/drm/bridge/analogix_dp.h
|
||||
+++ b/include/drm/bridge/analogix_dp.h
|
||||
@@ -16,11 +16,12 @@ enum analogix_dp_devtype {
|
||||
EXYNOS_DP,
|
||||
RK3288_DP,
|
||||
RK3399_EDP,
|
||||
+ RK3588_EDP,
|
||||
};
|
||||
|
||||
static inline bool is_rockchip(enum analogix_dp_devtype type)
|
||||
{
|
||||
- return type == RK3288_DP || type == RK3399_EDP;
|
||||
+ return type == RK3288_DP || type == RK3399_EDP || type == RK3588_EDP;
|
||||
}
|
||||
|
||||
struct analogix_dp_plat_data {
|
||||
@ -0,0 +1,164 @@
|
||||
From 729f8eefdcadaff98606931e691910f17d8d59d6 Mon Sep 17 00:00:00 2001
|
||||
From: Damon Ding <damon.ding@rock-chips.com>
|
||||
Date: Mon, 10 Mar 2025 18:41:12 +0800
|
||||
Subject: [PATCH] drm/rockchip: analogix_dp: Add support for RK3588
|
||||
|
||||
RK3588 integrates the Analogix eDP 1.3 TX controller IP and the HDMI/eDP
|
||||
TX Combo PHY based on a Samsung IP block. There are also two independent
|
||||
eDP display interface with different address on RK3588 Soc.
|
||||
|
||||
The patch currently adds only the basic support, specifically RGB output
|
||||
up to 4K@60Hz, without the tests for audio, PSR and other eDP 1.3 specific
|
||||
features.
|
||||
|
||||
In additon, the above Analogix IP has always been utilized as eDP on
|
||||
Rockchip platform, despite its capability to also support the DP v1.2.
|
||||
Therefore, the newly added logs will contain the term 'edp' rather than
|
||||
'dp'. And the newly added 'apb' reset control is to ensure the APB bus
|
||||
of eDP controller works well on the RK3588 SoC.
|
||||
|
||||
Acked-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
|
||||
Link: https://lore.kernel.org/r/20250310104114.2608063-12-damon.ding@rock-chips.com
|
||||
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
---
|
||||
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 61 ++++++++++++++++++-
|
||||
1 file changed, 58 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
|
||||
@@ -52,11 +52,13 @@ struct rockchip_grf_reg_field {
|
||||
/**
|
||||
* struct rockchip_dp_chip_data - splite the grf setting of kind of chips
|
||||
* @lcdc_sel: grf register field of lcdc_sel
|
||||
+ * @edp_mode: grf register field of edp_mode
|
||||
* @chip_type: specific chip type
|
||||
* @reg: register base address
|
||||
*/
|
||||
struct rockchip_dp_chip_data {
|
||||
const struct rockchip_grf_reg_field lcdc_sel;
|
||||
+ const struct rockchip_grf_reg_field edp_mode;
|
||||
u32 chip_type;
|
||||
u32 reg;
|
||||
};
|
||||
@@ -71,6 +73,7 @@ struct rockchip_dp_device {
|
||||
struct clk *grfclk;
|
||||
struct regmap *grf;
|
||||
struct reset_control *rst;
|
||||
+ struct reset_control *apbrst;
|
||||
|
||||
const struct rockchip_dp_chip_data *data;
|
||||
|
||||
@@ -116,6 +119,10 @@ static int rockchip_dp_pre_init(struct r
|
||||
usleep_range(10, 20);
|
||||
reset_control_deassert(dp->rst);
|
||||
|
||||
+ reset_control_assert(dp->apbrst);
|
||||
+ usleep_range(10, 20);
|
||||
+ reset_control_deassert(dp->apbrst);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -137,12 +144,21 @@ static int rockchip_dp_poweron(struct an
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ ret = rockchip_grf_field_write(dp->grf, &dp->data->edp_mode, 1);
|
||||
+ if (ret != 0)
|
||||
+ DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
|
||||
{
|
||||
struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = rockchip_grf_field_write(dp->grf, &dp->data->edp_mode, 0);
|
||||
+ if (ret != 0)
|
||||
+ DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret);
|
||||
|
||||
clk_disable_unprepare(dp->pclk);
|
||||
|
||||
@@ -206,6 +222,10 @@ static void rockchip_dp_drm_encoder_enab
|
||||
struct rockchip_dp_device *dp = encoder_to_dp(encoder);
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
+ struct of_endpoint endpoint;
|
||||
+ struct device_node *remote_port, *remote_port_parent;
|
||||
+ char name[32];
|
||||
+ u32 port_id;
|
||||
int ret;
|
||||
|
||||
crtc = rockchip_dp_drm_get_new_crtc(encoder, state);
|
||||
@@ -223,13 +243,27 @@ static void rockchip_dp_drm_encoder_enab
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
|
||||
+ ret = drm_of_encoder_active_endpoint(dp->dev->of_node, encoder, &endpoint);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
- DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
|
||||
+ remote_port_parent = of_graph_get_remote_port_parent(endpoint.local_node);
|
||||
+ if (remote_port_parent) {
|
||||
+ if (of_get_child_by_name(remote_port_parent, "ports")) {
|
||||
+ remote_port = of_graph_get_remote_port(endpoint.local_node);
|
||||
+ of_property_read_u32(remote_port, "reg", &port_id);
|
||||
+ of_node_put(remote_port);
|
||||
+ sprintf(name, "%s vp%d", remote_port_parent->full_name, port_id);
|
||||
+ } else {
|
||||
+ sprintf(name, "%s %s",
|
||||
+ remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb");
|
||||
+ }
|
||||
+ of_node_put(remote_port_parent);
|
||||
+
|
||||
+ DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
|
||||
+ }
|
||||
|
||||
- ret = rockchip_grf_field_write(dp->grf, &dp->data->lcdc_sel, ret);
|
||||
+ ret = rockchip_grf_field_write(dp->grf, &dp->data->lcdc_sel, endpoint.id);
|
||||
if (ret != 0)
|
||||
DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
|
||||
|
||||
@@ -323,6 +357,12 @@ static int rockchip_dp_of_probe(struct r
|
||||
return PTR_ERR(dp->rst);
|
||||
}
|
||||
|
||||
+ dp->apbrst = devm_reset_control_get_optional(dev, "apb");
|
||||
+ if (IS_ERR(dp->apbrst)) {
|
||||
+ DRM_DEV_ERROR(dev, "failed to get apb reset control\n");
|
||||
+ return PTR_ERR(dp->apbrst);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -525,9 +565,24 @@ static const struct rockchip_dp_chip_dat
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
+static const struct rockchip_dp_chip_data rk3588_edp[] = {
|
||||
+ {
|
||||
+ .edp_mode = GRF_REG_FIELD(0x0000, 0, 0),
|
||||
+ .chip_type = RK3588_EDP,
|
||||
+ .reg = 0xfdec0000,
|
||||
+ },
|
||||
+ {
|
||||
+ .edp_mode = GRF_REG_FIELD(0x0004, 0, 0),
|
||||
+ .chip_type = RK3588_EDP,
|
||||
+ .reg = 0xfded0000,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id rockchip_dp_dt_ids[] = {
|
||||
{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
|
||||
{.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp },
|
||||
+ {.compatible = "rockchip,rk3588-edp", .data = &rk3588_edp },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
|
||||
@ -0,0 +1,35 @@
|
||||
From 4f1a965d592a0ca7d4ee2125f54d19ba8292295a Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Wed, 23 Apr 2025 18:44:16 +0200
|
||||
Subject: [PATCH] drm/rockchip: add CONFIG_OF dependency
|
||||
|
||||
DRM_DISPLAY_DP_AUX_BUS cannot be selected when CONFIG_OF is disabled:
|
||||
|
||||
WARNING: unmet direct dependencies detected for DRM_DISPLAY_DP_AUX_BUS
|
||||
Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && OF [=n]
|
||||
Selected by [y]:
|
||||
- DRM_ROCKCHIP [=y] && HAS_IOMEM [=y] && DRM [=y] && ROCKCHIP_IOMMU [=y] && ROCKCHIP_ANALOGIX_DP [=y]
|
||||
|
||||
Rockchip platforms all depend on OF anyway, so add the dependency here
|
||||
for compile testing.
|
||||
|
||||
Fixes: d7b4936b2bc0 ("drm/rockchip: analogix_dp: Add support to get panel from the DP AUX bus")
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
Acked-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250423164422.2793634-1-arnd@kernel.org
|
||||
---
|
||||
drivers/gpu/drm/rockchip/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/Kconfig
|
||||
+++ b/drivers/gpu/drm/rockchip/Kconfig
|
||||
@@ -2,6 +2,7 @@
|
||||
config DRM_ROCKCHIP
|
||||
tristate "DRM Support for Rockchip"
|
||||
depends on DRM && ROCKCHIP_IOMMU
|
||||
+ depends on OF
|
||||
select DRM_CLIENT_SELECTION
|
||||
select DRM_GEM_DMA_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
@ -0,0 +1,283 @@
|
||||
From 3e89a8c6835476aa782da80585dee9ddae651eea Mon Sep 17 00:00:00 2001
|
||||
From: Andy Yan <andy.yan@rock-chips.com>
|
||||
Date: Mon, 21 Apr 2025 18:21:54 +0800
|
||||
Subject: [PATCH] drm/rockchip: vop2: Fix the update of LAYER/PORT select
|
||||
registers when there are multi display output on rk3588/rk3568
|
||||
|
||||
The all video ports of rk3568/rk3588 share the same OVL_LAYER_SEL
|
||||
and OVL_PORT_SEL registers, and the configuration of these two registers
|
||||
can be set to take effect when the vsync signal arrives at a certain Video
|
||||
Port.
|
||||
|
||||
If two threads for two display output choose to update these two registers
|
||||
simultaneously to meet their own plane adjustment requirements(change plane
|
||||
zpos or switch plane from one crtc to another), then no matter which Video
|
||||
Port'svsync signal we choose to follow for these two registers, the display
|
||||
output of the other Video Port will be abnormal.
|
||||
This is because the configuration of this Video Port does not take
|
||||
effect at the right time (its configuration should take effect when its
|
||||
VSYNC signal arrives).
|
||||
|
||||
In order to solve this problem, when performing plane migration or
|
||||
change the zpos of planes, there are two things to be observed and
|
||||
followed:
|
||||
|
||||
1. When a plane is migrated from one VP to another, the configuration of
|
||||
the layer can only take effect after the Port mux configuration is
|
||||
enabled.
|
||||
|
||||
2. When change the zpos of planes, we must ensure that the change for
|
||||
the previous VP takes effect before we proceed to change the next VP.
|
||||
Otherwise, the new configuration might overwrite the previous one for
|
||||
the previous VP, or it could lead to the configuration of the previous
|
||||
VP being take effect along with the VSYNC of the new VP.
|
||||
|
||||
This issue only occurs in scenarios where multi-display output is enabled.
|
||||
|
||||
Fixes: c5996e4ab109 ("drm/rockchip: vop2: Make overlay layer select register configuration take effect by vsync")
|
||||
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250421102156.424480-1-andyshrk@163.com
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 25 ++----
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 33 ++++++++
|
||||
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 89 ++++++++++++++++++--
|
||||
3 files changed, 122 insertions(+), 25 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -146,25 +146,6 @@ static void vop2_unlock(struct vop2 *vop
|
||||
mutex_unlock(&vop2->vop2_lock);
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Note:
|
||||
- * The write mask function is documented but missing on rk3566/8, writes
|
||||
- * to these bits have no effect. For newer soc(rk3588 and following) the
|
||||
- * write mask is needed for register writes.
|
||||
- *
|
||||
- * GLB_CFG_DONE_EN has no write mask bit.
|
||||
- *
|
||||
- */
|
||||
-static void vop2_cfg_done(struct vop2_video_port *vp)
|
||||
-{
|
||||
- struct vop2 *vop2 = vp->vop2;
|
||||
- u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
|
||||
-
|
||||
- val |= BIT(vp->id) | (BIT(vp->id) << 16);
|
||||
-
|
||||
- regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
|
||||
-}
|
||||
-
|
||||
static void vop2_win_disable(struct vop2_win *win)
|
||||
{
|
||||
vop2_win_write(win, VOP2_WIN_ENABLE, 0);
|
||||
@@ -854,6 +835,11 @@ static void vop2_enable(struct vop2 *vop
|
||||
if (vop2->version == VOP_VERSION_RK3588)
|
||||
rk3588_vop2_power_domain_enable_all(vop2);
|
||||
|
||||
+ if (vop2->version <= VOP_VERSION_RK3588) {
|
||||
+ vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
+ vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
+ }
|
||||
+
|
||||
vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
|
||||
|
||||
/*
|
||||
@@ -2722,6 +2708,7 @@ static int vop2_bind(struct device *dev,
|
||||
return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
|
||||
|
||||
mutex_init(&vop2->vop2_lock);
|
||||
+ mutex_init(&vop2->ovl_lock);
|
||||
|
||||
ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
|
||||
if (ret)
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
|
||||
@@ -334,6 +334,19 @@ struct vop2 {
|
||||
/* optional internal rgb encoder */
|
||||
struct rockchip_rgb *rgb;
|
||||
|
||||
+ /*
|
||||
+ * Used to record layer selection configuration on rk356x/rk3588
|
||||
+ * as register RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are
|
||||
+ * shared for all the Video Ports.
|
||||
+ */
|
||||
+ u32 old_layer_sel;
|
||||
+ u32 old_port_sel;
|
||||
+ /*
|
||||
+ * Ensure that the updates to these two registers(RKK3568_OVL_LAYER_SEL/RK3568_OVL_PORT_SEL)
|
||||
+ * take effect in sequence.
|
||||
+ */
|
||||
+ struct mutex ovl_lock;
|
||||
+
|
||||
/* must be put at the end of the struct */
|
||||
struct vop2_win win[];
|
||||
};
|
||||
@@ -727,6 +740,7 @@ enum dst_factor_mode {
|
||||
#define RK3588_OVL_PORT_SEL__CLUSTER2 GENMASK(21, 20)
|
||||
#define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18)
|
||||
#define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16)
|
||||
+#define RK3588_OVL_PORT_SET__PORT3_MUX GENMASK(15, 12)
|
||||
#define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8)
|
||||
#define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4)
|
||||
#define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0)
|
||||
@@ -831,4 +845,23 @@ static inline struct vop2_win *to_vop2_w
|
||||
return container_of(p, struct vop2_win, base);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Note:
|
||||
+ * The write mask function is documented but missing on rk3566/8, writes
|
||||
+ * to these bits have no effect. For newer soc(rk3588 and following) the
|
||||
+ * write mask is needed for register writes.
|
||||
+ *
|
||||
+ * GLB_CFG_DONE_EN has no write mask bit.
|
||||
+ *
|
||||
+ */
|
||||
+static inline void vop2_cfg_done(struct vop2_video_port *vp)
|
||||
+{
|
||||
+ struct vop2 *vop2 = vp->vop2;
|
||||
+ u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
|
||||
+
|
||||
+ val |= BIT(vp->id) | (BIT(vp->id) << 16);
|
||||
+
|
||||
+ regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
|
||||
+}
|
||||
+
|
||||
#endif /* _ROCKCHIP_DRM_VOP2_H */
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
|
||||
@@ -2052,12 +2052,55 @@ static void vop2_setup_alpha(struct vop2
|
||||
}
|
||||
}
|
||||
|
||||
+static u32 rk3568_vop2_read_port_mux(struct vop2 *vop2)
|
||||
+{
|
||||
+ return vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
+}
|
||||
+
|
||||
+static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2)
|
||||
+{
|
||||
+ u32 port_mux_sel;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Spin until the previous port_mux figuration is done.
|
||||
+ */
|
||||
+ ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel,
|
||||
+ port_mux_sel == vop2->old_port_sel, 0, 50 * 1000);
|
||||
+ if (ret)
|
||||
+ DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n",
|
||||
+ port_mux_sel, vop2->old_port_sel);
|
||||
+}
|
||||
+
|
||||
+static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2)
|
||||
+{
|
||||
+ return vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
+}
|
||||
+
|
||||
+static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
|
||||
+{
|
||||
+ u32 atv_layer_cfg;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Spin until the previous layer configuration is done.
|
||||
+ */
|
||||
+ ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
|
||||
+ atv_layer_cfg == cfg, 0, 50 * 1000);
|
||||
+ if (ret)
|
||||
+ DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n",
|
||||
+ atv_layer_cfg, cfg);
|
||||
+}
|
||||
+
|
||||
static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct drm_plane *plane;
|
||||
u32 layer_sel = 0;
|
||||
u32 port_sel;
|
||||
+ u32 old_layer_sel = 0;
|
||||
+ u32 atv_layer_sel = 0;
|
||||
+ u32 old_port_sel = 0;
|
||||
u8 layer_id;
|
||||
u8 old_layer_id;
|
||||
u8 layer_sel_id;
|
||||
@@ -2069,19 +2112,18 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
struct vop2_video_port *vp2 = &vop2->vps[2];
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
|
||||
|
||||
+ mutex_lock(&vop2->ovl_lock);
|
||||
ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL;
|
||||
- ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
|
||||
|
||||
if (vcstate->yuv_overlay)
|
||||
ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);
|
||||
else
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);
|
||||
|
||||
- vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
||||
-
|
||||
- port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
+ old_port_sel = vop2->old_port_sel;
|
||||
+ port_sel = old_port_sel;
|
||||
port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
|
||||
|
||||
if (vp0->nlayers)
|
||||
@@ -2102,7 +2144,13 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
else
|
||||
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8);
|
||||
|
||||
- layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
+ /* Fixed value for rk3588 */
|
||||
+ if (vop2->version == VOP_VERSION_RK3588)
|
||||
+ port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7);
|
||||
+
|
||||
+ atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
+ old_layer_sel = vop2->old_layer_sel;
|
||||
+ layer_sel = old_layer_sel;
|
||||
|
||||
ofs = 0;
|
||||
for (i = 0; i < vp->id; i++)
|
||||
@@ -2186,8 +2234,37 @@ static void rk3568_vop2_setup_layer_mixe
|
||||
old_win->data->layer_sel_id[vp->id]);
|
||||
}
|
||||
|
||||
+ vop2->old_layer_sel = layer_sel;
|
||||
+ vop2->old_port_sel = port_sel;
|
||||
+ /*
|
||||
+ * As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports,
|
||||
+ * and the configuration take effect by one Video Port's vsync.
|
||||
+ * When performing layer migration or change the zpos of layers, there are two things
|
||||
+ * to be observed and followed:
|
||||
+ * 1. When a layer is migrated from one VP to another, the configuration of the layer
|
||||
+ * can only take effect after the Port mux configuration is enabled.
|
||||
+ *
|
||||
+ * 2. When we change the zpos of layers, we must ensure that the change for the previous
|
||||
+ * VP takes effect before we proceed to change the next VP. Otherwise, the new
|
||||
+ * configuration might overwrite the previous one for the previous VP, or it could
|
||||
+ * lead to the configuration of the previous VP being take effect along with the VSYNC
|
||||
+ * of the new VP.
|
||||
+ */
|
||||
+ if (layer_sel != old_layer_sel || port_sel != old_port_sel)
|
||||
+ ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
|
||||
+ vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
||||
+
|
||||
+ if (port_sel != old_port_sel) {
|
||||
+ vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
|
||||
+ vop2_cfg_done(vp);
|
||||
+ rk3568_vop2_wait_for_port_mux_done(vop2);
|
||||
+ }
|
||||
+
|
||||
+ if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel)
|
||||
+ rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
|
||||
+
|
||||
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
|
||||
- vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
|
||||
+ mutex_unlock(&vop2->ovl_lock);
|
||||
}
|
||||
|
||||
static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp)
|
||||
@ -0,0 +1,52 @@
|
||||
From a52dffaa46c2c5ff0b311c4dc1288581f7b9109e Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Date: Sun, 6 Jul 2025 08:36:58 +0000
|
||||
Subject: [PATCH] drm/rockchip: vop2: make vp registers nonvolatile
|
||||
|
||||
Make video port registers nonvolatile. As DSP_CTRL register is written
|
||||
to twice due to gamma LUT enable bit which is set outside of the main
|
||||
DSP_CTRL initialization within atomic_enable (for rk356x case it is also
|
||||
necessary to always disable gamma LUT before writing a new LUT) there is
|
||||
a chance that DSP_CTRL value read-out in gamma LUT init/update code is
|
||||
not the one which was written by the preceding DSP_CTRL initialization
|
||||
code within atomic_enable. This might result in misconfigured DSP_CTRL
|
||||
which leads to no visual output[1]. Since DSP_CTRL write takes effect
|
||||
after VSYNC[1] the issue is not always present. When tested on Pinetab2
|
||||
with kernel 6.14 it happenes only when DRM is compiled as a module[1].
|
||||
In order to confirm that it is a timing issue I inserted 18ms udelay
|
||||
before vop2_crtc_atomic_try_set_gamma in atomic enable and compiled DRM
|
||||
as module - this has also fixed the issue.
|
||||
|
||||
[1] https://lore.kernel.org/linux-rockchip/562b38e5.a496.1975f09f983.Coremail.andyshrk@163.com/
|
||||
|
||||
Reported-by: Diederik de Haas <didi.debian@cknow.org>
|
||||
Closes: https://lore.kernel.org/linux-rockchip/DAEVDSTMWI1E.J454VZN0R9MA@cknow.org/
|
||||
Suggested-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Piotr Zalewski <pZ010001011111@proton.me>
|
||||
Tested-by: Diederik de Haas <didi.debian@cknow.org>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250706083629.140332-2-pZ010001011111@proton.me
|
||||
---
|
||||
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
|
||||
@@ -2573,12 +2573,13 @@ static int vop2_win_init(struct vop2 *vo
|
||||
}
|
||||
|
||||
/*
|
||||
- * The window registers are only updated when config done is written.
|
||||
- * Until that they read back the old value. As we read-modify-write
|
||||
- * these registers mark them as non-volatile. This makes sure we read
|
||||
- * the new values from the regmap register cache.
|
||||
+ * The window and video port registers are only updated when config
|
||||
+ * done is written. Until that they read back the old value. As we
|
||||
+ * read-modify-write these registers mark them as non-volatile. This
|
||||
+ * makes sure we read the new values from the regmap register cache.
|
||||
*/
|
||||
static const struct regmap_range vop2_nonvolatile_range[] = {
|
||||
+ regmap_reg_range(RK3568_VP0_CTRL_BASE, RK3588_VP3_CTRL_BASE + 255),
|
||||
regmap_reg_range(0x1000, 0x23ff),
|
||||
};
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
From b6f11f114759a088acf44e86b5cd72f24de85d44 Mon Sep 17 00:00:00 2001
|
||||
From: Guochun Huang <hero.huang@rock-chips.com>
|
||||
Date: Mon, 7 Jul 2025 18:49:02 +0200
|
||||
Subject: [PATCH] drm/rockchip: dsi2: add support rk3576
|
||||
|
||||
Add the necessary specific bits to support the rk3576-variant of the
|
||||
DW-DSI2 controller.
|
||||
|
||||
Signed-off-by: Guochun Huang <hero.huang@rock-chips.com>
|
||||
[adapted from the vendor-kernel for mainline]
|
||||
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
|
||||
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||
Link: https://lore.kernel.org/r/20250707164906.1445288-10-heiko@sntech.de
|
||||
---
|
||||
.../gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 21 +++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
|
||||
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
|
||||
@@ -437,6 +437,15 @@ static void dw_mipi_dsi2_rockchip_remove
|
||||
dw_mipi_dsi2_remove(dsi2->dmd);
|
||||
}
|
||||
|
||||
+static const struct dsigrf_reg rk3576_dsi_grf_reg_fields[MAX_FIELDS] = {
|
||||
+ [TXREQCLKHS_EN] = { 0x0028, 1, 1 },
|
||||
+ [GATING_EN] = { 0x0028, 0, 0 },
|
||||
+ [IPI_SHUTDN] = { 0x0028, 3, 3 },
|
||||
+ [IPI_COLORM] = { 0x0028, 2, 2 },
|
||||
+ [IPI_COLOR_DEPTH] = { 0x0028, 8, 11 },
|
||||
+ [IPI_FORMAT] = { 0x0028, 4, 7 },
|
||||
+};
|
||||
+
|
||||
static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = {
|
||||
[TXREQCLKHS_EN] = { 0x0000, 11, 11 },
|
||||
[GATING_EN] = { 0x0000, 10, 10 },
|
||||
@@ -455,6 +464,15 @@ static const struct dsigrf_reg rk3588_ds
|
||||
[IPI_FORMAT] = { 0x0004, 0, 3 },
|
||||
};
|
||||
|
||||
+static const struct rockchip_dw_dsi2_chip_data rk3576_chip_data[] = {
|
||||
+ {
|
||||
+ .reg = 0x27d80000,
|
||||
+ .grf_regs = rk3576_dsi_grf_reg_fields,
|
||||
+ .max_bit_rate_per_lane = 2500000ULL,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = {
|
||||
{
|
||||
.reg = 0xfde20000,
|
||||
@@ -470,6 +488,9 @@ static const struct rockchip_dw_dsi2_chi
|
||||
|
||||
static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = {
|
||||
{
|
||||
+ .compatible = "rockchip,rk3576-mipi-dsi2",
|
||||
+ .data = &rk3576_chip_data,
|
||||
+ }, {
|
||||
.compatible = "rockchip,rk3588-mipi-dsi2",
|
||||
.data = &rk3588_chip_data,
|
||||
},
|
||||
Loading…
Reference in New Issue
Block a user