drm/rockchip: dw_hdmi: Do not enable DSC when the DSC compression ratio is below 0.375.

If the DSC mode with a compression rate lower than 0.375 is to
be supported, the dclk clock source of the VOP bound to HDMI must
be a CRU PLL that supports fractional frequency division.
However, in most scenarios, HDMI is unable to be assigned such a
PLL. So in this scenario, instead of enabling DSC, we switch to
YUV420 format.

Change-Id: I450cdd5857e4384894651ed063fac152a8d9bb0f
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2025-07-28 11:14:29 +08:00
parent 9f6237f086
commit dbcc3c130c

View File

@@ -1036,23 +1036,36 @@ rockchip_hdmi_find_by_id(struct device_driver *drv, unsigned int id)
return dev_get_drvdata(dev); return dev_get_drvdata(dev);
} }
static bool rockchip_hdmi_check_dsc_rate_supported(struct rockchip_hdmi *hdmi,
u64 tmdsclk, u8 bpp)
{
u64 data_rate, dsc_rate;
u64 frl_rate, dsc_frl_rate;
frl_rate = (u64)hdmi->hdmi21_data.max_lanes *
hdmi->hdmi21_data.max_frl_rate_per_lane * 1000000000;
dsc_frl_rate = (u64)hdmi->hdmi21_data.dsc_cap.max_lanes *
hdmi->hdmi21_data.dsc_cap.max_frl_rate_per_lane * 1000000000;
data_rate = (u64)tmdsclk * bpp;
data_rate = DIV_ROUND_UP_ULL(data_rate * 18, 16);
/* compression ratio needs to be greater than 0.375. */
dsc_rate = DIV_ROUND_UP_ULL(data_rate * 9, 24);
if ((data_rate > frl_rate) && (dsc_rate > dsc_frl_rate))
return true;
return false;
}
static bool rockchip_hdmi_if_dsc_enable(struct rockchip_hdmi *hdmi, unsigned int tmdsclk) static bool rockchip_hdmi_if_dsc_enable(struct rockchip_hdmi *hdmi, unsigned int tmdsclk)
{ {
u64 data_rate;
u64 frl_rate = (u64)hdmi->link_cfg.frl_lanes * hdmi->link_cfg.rate_per_lane * 1000000;
u8 bpp = hdmi_bus_fmt_color_depth(hdmi->bus_format) * 3; u8 bpp = hdmi_bus_fmt_color_depth(hdmi->bus_format) * 3;
/* rk3588 dsc can't support yuv420/422 dsc */ /* rk3588 dsc can't support yuv420/422 dsc */
if (hdmi_bus_fmt_is_yuv420(hdmi->bus_format) || hdmi_bus_fmt_is_yuv422(hdmi->bus_format)) if (hdmi_bus_fmt_is_yuv420(hdmi->bus_format) || hdmi_bus_fmt_is_yuv422(hdmi->bus_format))
return false; return false;
data_rate = (u64)tmdsclk * bpp; return rockchip_hdmi_check_dsc_rate_supported(hdmi, tmdsclk, bpp);
data_rate = DIV_ROUND_UP_ULL(data_rate * 18, 16);
if (data_rate > frl_rate)
return true;
return false;
} }
static void hdmi_select_link_config(struct rockchip_hdmi *hdmi, static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
@@ -1092,7 +1105,7 @@ static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
max_dsc_rate_per_lane = max_dsc_rate_per_lane =
hdmi->hdmi21_data.dsc_cap.max_frl_rate_per_lane; hdmi->hdmi21_data.dsc_cap.max_frl_rate_per_lane;
if (rockchip_hdmi_if_dsc_enable(hdmi, tmdsclk)) { if (rockchip_hdmi_if_dsc_enable(hdmi, tmdsclk * 1000)) {
hdmi->link_cfg.dsc_mode = true; hdmi->link_cfg.dsc_mode = true;
hdmi->link_cfg.frl_lanes = max_dsc_lanes; hdmi->link_cfg.frl_lanes = max_dsc_lanes;
hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane; hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane;
@@ -2419,6 +2432,7 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
bool support_dc = false; bool support_dc = false;
bool sink_is_hdmi = true; bool sink_is_hdmi = true;
bool yuv422_out = false; bool yuv422_out = false;
bool dsc_rate_supported;
u32 max_tmds_clock = info->max_tmds_clock; u32 max_tmds_clock = info->max_tmds_clock;
int output_eotf; int output_eotf;
@@ -2537,9 +2551,14 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
DRM_MODE_FLAG_3D_FRAME_PACKING) DRM_MODE_FLAG_3D_FRAME_PACKING)
pixclock *= 2; pixclock *= 2;
tmdsclock = hdmi_get_tmdsclock(hdmi, mode.clock * 1000);
dsc_rate_supported =
rockchip_hdmi_check_dsc_rate_supported(hdmi, tmdsclock, color_depth * 3);
if (drm_mode_is_420_only(info, &mode) || if (drm_mode_is_420_only(info, &mode) ||
(hdmi->is_hdmi_qp && mode.clock > 1188000 && (hdmi->is_hdmi_qp && mode.clock > 1188000 &&
(*color_format == RK_IF_FORMAT_YCBCR422 || hdmi->force_disable_dsc))) (*color_format == RK_IF_FORMAT_YCBCR422 || hdmi->force_disable_dsc ||
!dsc_rate_supported)))
*color_format = RK_IF_FORMAT_YCBCR420; *color_format = RK_IF_FORMAT_YCBCR420;
if (!sink_is_hdmi) { if (!sink_is_hdmi) {