Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/rockchip: dw_hdmi_qp: Add high color depth support

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

authored by

Cristian Ciocaltea and committed by
Heiko Stuebner
e95b9ff6 97ffefaa

+51 -3
+51 -3
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
··· 70 70 #define RK3588_HDMI1_LEVEL_INT BIT(24) 71 71 #define RK3588_GRF_VO1_CON3 0x000c 72 72 #define RK3588_GRF_VO1_CON6 0x0018 73 + #define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4) 74 + #define RK3588_8BPC 0x0 75 + #define RK3588_10BPC 0x6 76 + #define RK3588_COLOR_FORMAT_MASK GENMASK(3, 0) 77 + #define RK3588_RGB 0x0 78 + #define RK3588_YUV420 0x3 73 79 #define RK3588_SCLIN_MASK BIT(9) 74 80 #define RK3588_SDAIN_MASK BIT(10) 75 81 #define RK3588_MODE_MASK BIT(11) ··· 103 97 104 98 struct rockchip_hdmi_qp_ctrl_ops { 105 99 void (*io_init)(struct rockchip_hdmi_qp *hdmi); 100 + void (*enc_init)(struct rockchip_hdmi_qp *hdmi, struct rockchip_crtc_state *state); 106 101 irqreturn_t (*irq_callback)(int irq, void *dev_id); 107 102 irqreturn_t (*hardirq_callback)(int irq, void *dev_id); 108 103 }; ··· 118 111 static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) 119 112 { 120 113 struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); 114 + struct drm_crtc *crtc = encoder->crtc; 121 115 122 116 /* Unconditionally switch to TMDS as FRL is not yet supported */ 123 117 gpiod_set_value(hdmi->frl_enable_gpio, 0); 118 + 119 + if (!crtc || !crtc->state) 120 + return; 121 + 122 + if (hdmi->ctrl_ops->enc_init) 123 + hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state)); 124 124 } 125 125 126 126 static int ··· 140 126 union phy_configure_opts phy_cfg = {}; 141 127 int ret; 142 128 143 - if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate) 129 + if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate && 130 + s->output_bpc == conn_state->hdmi.output_bpc) 144 131 return 0; 145 132 146 133 phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate; 134 + phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc; 147 135 148 136 ret = phy_configure(hdmi->phy, &phy_cfg); 149 137 if (!ret) { 150 138 hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; 151 139 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 152 140 s->output_type = DRM_MODE_CONNECTOR_HDMIA; 141 + s->output_bpc = conn_state->hdmi.output_bpc; 153 142 } else { 154 143 dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret); 155 144 } ··· 388 371 regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); 389 372 } 390 373 374 + static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi, 375 + struct rockchip_crtc_state *state) 376 + { 377 + u32 val; 378 + 379 + if (state->output_bpc == 10) 380 + val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_10BPC); 381 + else 382 + val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC); 383 + 384 + regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val); 385 + } 386 + 387 + static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi, 388 + struct rockchip_crtc_state *state) 389 + { 390 + u32 val; 391 + 392 + if (state->output_bpc == 10) 393 + val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_10BPC); 394 + else 395 + val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC); 396 + 397 + regmap_write(hdmi->vo_regmap, 398 + hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3, 399 + val); 400 + } 401 + 391 402 static const struct rockchip_hdmi_qp_ctrl_ops rk3576_hdmi_ctrl_ops = { 392 403 .io_init = dw_hdmi_qp_rk3576_io_init, 393 - .irq_callback = dw_hdmi_qp_rk3576_irq, 404 + .enc_init = dw_hdmi_qp_rk3576_enc_init, 405 + .irq_callback = dw_hdmi_qp_rk3576_irq, 394 406 .hardirq_callback = dw_hdmi_qp_rk3576_hardirq, 395 407 }; 396 408 397 409 static const struct rockchip_hdmi_qp_ctrl_ops rk3588_hdmi_ctrl_ops = { 398 410 .io_init = dw_hdmi_qp_rk3588_io_init, 399 - .irq_callback = dw_hdmi_qp_rk3588_irq, 411 + .enc_init = dw_hdmi_qp_rk3588_enc_init, 412 + .irq_callback = dw_hdmi_qp_rk3588_irq, 400 413 .hardirq_callback = dw_hdmi_qp_rk3588_hardirq, 401 414 }; 402 415 ··· 519 472 520 473 plat_data.phy_ops = cfg->phy_ops; 521 474 plat_data.phy_data = hdmi; 475 + plat_data.max_bpc = 10; 522 476 523 477 encoder = &hdmi->encoder.encoder; 524 478 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);