[PATCH 5/5] drm/rockchip: Add basic RK3576 HDMI output support
Andy Yan
andyshrk at 163.com
Tue Aug 27 03:32:11 PDT 2024
From: Andy Yan <andy.yan at rock-chips.com>
The HDMI on rk3576 is share the same IP block (PHY and Controller)
with rk3588.
It depends on the WIP patch from Cristian[0]:
[0]https://lore.kernel.org/lkml/20240819-b4-rk3588-bridge-upstream-v4-0-6417c72a2749@collabora.com/
Signed-off-by: Andy Yan <andy.yan at rock-chips.com>
---
.../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 174 ++++++++++++++----
1 file changed, 143 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 3ad5e62a1a85..67b84bf24e5b 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -23,6 +23,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)
@@ -161,6 +196,37 @@ static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.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,
@@ -181,13 +247,26 @@ 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 (of_device_is_compatible(hdmi->dev->of_node, "rockchip,rk3576-dw-hdmi-qp")) {
+ regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &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;
+ 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;
+ }
+ } else {
+
+ 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;
@@ -199,27 +278,48 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
u32 intr_stat, val;
int debounce_ms;
- regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
- if (!intr_stat)
- return IRQ_NONE;
+ if (of_device_is_compatible(hdmi->dev->of_node, "rockchip,rk3576-dw-hdmi-qp")) {
+ regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
+
+ val = HIWORD_UPDATE(RK3576_HDMI_HPD_INT_CLR,
+ RK3576_HDMI_HPD_INT_CLR);
- val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR,
- RK3588_HDMI0_HPD_INT_CLR);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- debounce_ms = intr_stat & RK3588_HDMI0_LEVEL_INT ? 150 : 20;
- mod_delayed_work(system_wq, &hdmi->hpd_work,
- msecs_to_jiffies(debounce_ms));
+ debounce_ms = intr_stat & RK3576_HDMI_LEVEL_INT ? 150 : 20;
+ mod_delayed_work(system_wq, &hdmi->hpd_work,
+ msecs_to_jiffies(debounce_ms));
- val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK);
+
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ } else {
+ 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);
+
+ debounce_ms = intr_stat & RK3588_HDMI0_LEVEL_INT ? 150 : 20;
+ mod_delayed_work(system_wq, &hdmi->hpd_work,
+ msecs_to_jiffies(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 },
+ .data = &rk3588_hdmi_phy_ops
+ }, {
+ .compatible = "rockchip,rk3576-dw-hdmi-qp",
+ .data = &rk3576_hdmi_phy_ops
+ },
{},
};
MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids);
@@ -308,22 +408,34 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
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->vo1_regmap, RK3588_GRF_VO1_CON3, val);
+ if (of_device_is_compatible(dev->of_node, "rockchip,rk3576-dw-hdmi-qp")) {
+ 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);
- val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
- RK3588_SET_HPD_PATH_MASK);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val);
+ regmap_write(hdmi->vo1_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
- RK3588_HDMI0_GRANT_SEL);
- regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON9, val);
+ val = HIWORD_UPDATE(0, RK3576_HDMI_HPD_INT_MSK);
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ } else {
+ 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->vo1_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_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
+ RK3588_HDMI0_GRANT_SEL);
+ regmap_write(hdmi->vo1_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);
--
2.34.1
More information about the Linux-rockchip
mailing list