Rockchip DW HDMI QP encoder supports YUV 4:2:2 output through ROCKCHIP_OUT_MODE_YUV422, but was limited to 8-bit depth via MEDIA_BUS_FMT_UYVY8_1X16. Add support for its 10-bit counterpart MEDIA_BUS_FMT_UYVY10_1X20, which carries two 10-bit components per clock cycle on a 20-bit wide bus.
The HDMI PHY scales its PLL output by 8/bpc to undo the deep color packing, such that it matches the DCLK rate expected by VOP2. However, YUV 4:2:2 is never deep color packed, as it always transmits two 12-bit components per pixel, regardless of the color depth. From a clock-rate perspective this is equivalent to three 8-bit RGB components, so configure the HDMI PHY with 8 bpc when YUV 4:2:2 is in use to keep its output clock aligned with the TMDS character rate. Tested-by: Igor Paunovic <[email protected]> Signed-off-by: Cristian Ciocaltea <[email protected]> --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index db1933d75ced..7f05d26f8d76 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -190,6 +190,25 @@ static int dw_hdmi_qp_rockchip_get_vop_format(struct drm_encoder *encoder, return bstate->output_bus_cfg.format; } +/* + * The HDMI PHY scales its PLL output by 8/bpc to undo the deep color packing, + * such that it matches the DCLK rate expected by VOP2. + * + * YUV422 is never deep color packed, as it always transmits two 12-bit + * components per clock cycle, regardless of the color depth. Hence, as for + * drm_hdmi_compute_mode_clock(), use 8 bpc to keep the PHY PLL output aligned + * with the TMDS character rate. + */ +static unsigned int +dw_hdmi_qp_rockchip_phy_bpc(const struct rockchip_crtc_state *s, + const struct drm_connector_state *conn_state) +{ + if (s->output_mode == ROCKCHIP_OUT_MODE_YUV422) + return 8; + + return conn_state->hdmi.output_bpc; +} + static int dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -218,6 +237,7 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, s->output_mode = ROCKCHIP_OUT_MODE_AAAA; break; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY10_1X20: s->output_mode = ROCKCHIP_OUT_MODE_YUV422; break; case MEDIA_BUS_FMT_UYYVYY8_0_5X24: @@ -229,7 +249,7 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, } phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate; - phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc; + phy_cfg.hdmi.bpc = dw_hdmi_qp_rockchip_phy_bpc(s, conn_state); ret = phy_configure(hdmi->phy, &phy_cfg); if (!ret) { -- 2.55.0
