]> Gentwo Git Trees - linux/.git/commitdiff
drm/rockchip: dw_hdmi_qp: Add high color depth support
authorCristian Ciocaltea <cristian.ciocaltea@collabora.com>
Tue, 21 Oct 2025 10:19:18 +0000 (13:19 +0300)
committerHeiko Stuebner <heiko@sntech.de>
Fri, 14 Nov 2025 22:10:38 +0000 (23:10 +0100)
Since both RK3576 and RK3588 SoCs are capable of handling 10 bpc color
depth, introduce a pair of new helpers to program the necessary
registers, as well as passing bpc at PHY configuration level.

Note max_bpc is unconditionally set to 10 before initializing the QP
bridge library, as there is no need to adjust it dynamically, i.e. per
SoC variant, for now.

While setting up .enc_init() callbacks of rockchip_hdmi_qp_ctrl_ops,
also replace the unnecessary whitespace chars before .irq_callback()
assignments.

Acked-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20251021-rk3588-10bpc-v3-5-3d3eed00a6db@collabora.com
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c

index 2480f5efd3282db2d1eb581bf9e8083161023705..c9fe6aa3e3e3606086b1cedf38dc1318eb3daf26 100644 (file)
 #define RK3588_HDMI1_LEVEL_INT         BIT(24)
 #define RK3588_GRF_VO1_CON3            0x000c
 #define RK3588_GRF_VO1_CON6            0x0018
+#define RK3588_COLOR_DEPTH_MASK                GENMASK(7, 4)
+#define RK3588_8BPC                    0x0
+#define RK3588_10BPC                   0x6
+#define RK3588_COLOR_FORMAT_MASK       GENMASK(3, 0)
+#define RK3588_RGB                     0x0
+#define RK3588_YUV420                  0x3
 #define RK3588_SCLIN_MASK              BIT(9)
 #define RK3588_SDAIN_MASK              BIT(10)
 #define RK3588_MODE_MASK               BIT(11)
@@ -97,6 +103,7 @@ struct rockchip_hdmi_qp {
 
 struct rockchip_hdmi_qp_ctrl_ops {
        void (*io_init)(struct rockchip_hdmi_qp *hdmi);
+       void (*enc_init)(struct rockchip_hdmi_qp *hdmi, struct rockchip_crtc_state *state);
        irqreturn_t (*irq_callback)(int irq, void *dev_id);
        irqreturn_t (*hardirq_callback)(int irq, void *dev_id);
 };
@@ -111,9 +118,16 @@ static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *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;
 
        /* Unconditionally switch to TMDS as FRL is not yet supported */
        gpiod_set_value(hdmi->frl_enable_gpio, 0);
+
+       if (!crtc || !crtc->state)
+               return;
+
+       if (hdmi->ctrl_ops->enc_init)
+               hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state));
 }
 
 static int
@@ -126,16 +140,19 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
        union phy_configure_opts phy_cfg = {};
        int ret;
 
-       if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate)
+       if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
+           s->output_bpc == conn_state->hdmi.output_bpc)
                return 0;
 
        phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+       phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc;
 
        ret = phy_configure(hdmi->phy, &phy_cfg);
        if (!ret) {
                hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
                s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
                s->output_type = DRM_MODE_CONNECTOR_HDMIA;
+               s->output_bpc = conn_state->hdmi.output_bpc;
        } else {
                dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret);
        }
@@ -371,15 +388,45 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
        regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
 }
 
+static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
+                                      struct rockchip_crtc_state *state)
+{
+       u32 val;
+
+       if (state->output_bpc == 10)
+               val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_10BPC);
+       else
+               val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC);
+
+       regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val);
+}
+
+static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
+                                      struct rockchip_crtc_state *state)
+{
+       u32 val;
+
+       if (state->output_bpc == 10)
+               val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_10BPC);
+       else
+               val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC);
+
+       regmap_write(hdmi->vo_regmap,
+                    hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
+                    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,
+       .enc_init               = dw_hdmi_qp_rk3576_enc_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,
+       .enc_init               = dw_hdmi_qp_rk3588_enc_init,
+       .irq_callback           = dw_hdmi_qp_rk3588_irq,
        .hardirq_callback       = dw_hdmi_qp_rk3588_hardirq,
 };
 
@@ -472,6 +519,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 
        plat_data.phy_ops = cfg->phy_ops;
        plat_data.phy_data = hdmi;
+       plat_data.max_bpc = 10;
 
        encoder = &hdmi->encoder.encoder;
        encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);