From db27b299b7778d1732a11d4cdcde9311b1e75ce4 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Mon, 31 Mar 2025 15:07:37 +0800 Subject: [PATCH] drm/bridge: synopsys: dw-hdmi-qp: Get uboot color format from avi regs in dsc mode RK3588/RK3576 hdmi color format setting and dsc mode setting are the same mask in the same register. If dsc is enabled for hdmi in uboot, what color is hdmi output in uboot that cannot be obtained from this register in kernel. Since hdmi in dsc mode always sends avi infoframe, color format of hdmi output in uboot can be read from the avi register. Change-Id: I68157455342302338370feb9176b46e2051b4f01 Signed-off-by: Algea Cao --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 103 ++++++++++++++++++- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 40 ------- include/drm/bridge/dw_hdmi.h | 1 - 3 files changed, 100 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 8ca8bff2e68c..95f6b8611dc9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -73,6 +73,15 @@ #define HDMI_CTRL_CLK_EN 0x15 +#define DW_HDMI_QP_RGB 0 +#define DW_HDMI_QP_YUV422 0x1 +#define DW_HDMI_QP_YUV444 0x2 +#define DW_HDMI_QP_YUV420 0x3 +#define DW_HDMI_QP_DSC 0xb + +#define IPI_FORMAT_MASK 0xf +#define IPI_COLOR_DEPTH_MASK 0xf0 + static const unsigned int dw_hdmi_cable[] = { EXTCON_DISP_HDMI, EXTCON_NONE, @@ -2990,20 +2999,107 @@ dw_hdmi_connector_set_property(struct drm_connector *connector, property, val); } +static u64 dw_hdmi_qp_get_avi_color_fmt(struct dw_hdmi_qp *hdmi, u32 depth) +{ + u32 fmt; + u64 bus_format; + + fmt = (hdmi_readl(hdmi, PKT_AVI_CONTENTS1) >> 13) & 0x3; + + switch (fmt) { + case DW_HDMI_QP_YUV444: + if (!depth) + bus_format = MEDIA_BUS_FMT_YUV8_1X24; + else + bus_format = MEDIA_BUS_FMT_YUV10_1X30; + break; + case DW_HDMI_QP_YUV422: + bus_format = MEDIA_BUS_FMT_YUYV10_1X20; + break; + case DW_HDMI_QP_YUV420: + if (!depth) + bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + else + bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30; + break; + case DW_HDMI_QP_RGB: + if (!depth) + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + else + bus_format = MEDIA_BUS_FMT_RGB101010_1X30; + break; + default: + dev_err(hdmi->dev, "can't get correct color format\n"); + bus_format = MEDIA_BUS_FMT_YUV8_1X24; + break; + } + + return bus_format; +} + +static u64 dw_hdmi_qp_get_color_fmt(struct dw_hdmi_qp *hdmi) +{ + u32 fmt, depth; + u64 bus_format; + + fmt = hdmi_readl(hdmi, VIDEO_INTERFACE_STATUS0); + depth = fmt & IPI_COLOR_DEPTH_MASK; + fmt = fmt & IPI_FORMAT_MASK; + + switch (fmt) { + case DW_HDMI_QP_YUV444: + if (!depth) + bus_format = MEDIA_BUS_FMT_YUV8_1X24; + else + bus_format = MEDIA_BUS_FMT_YUV10_1X30; + break; + case DW_HDMI_QP_YUV422: + bus_format = MEDIA_BUS_FMT_YUYV10_1X20; + break; + case DW_HDMI_QP_YUV420: + if (!depth) + bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + else + bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30; + break; + case DW_HDMI_QP_RGB: + if (!depth) + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + else + bus_format = MEDIA_BUS_FMT_RGB101010_1X30; + break; + /* + * RK3588/RK3576 hdmi color format setting and dsc mode setting are + * the same mask in the same register. If dsc is enabled for hdmi in + * uboot, what color is hdmi output in uboot that cannot be obtained + * from this register in kernel. + * Since hdmi in dsc mode always sends avi infoframe, color format + * of hdmi output in uboot can be read from the avi register. + */ + case DW_HDMI_QP_DSC: + bus_format = dw_hdmi_qp_get_avi_color_fmt(hdmi, depth); + break; + default: + dev_err(hdmi->dev, "can't get correct color format\n"); + bus_format = MEDIA_BUS_FMT_YUV8_1X24; + break; + } + + return bus_format; +} + static void dw_hdmi_attach_properties(struct dw_hdmi_qp *hdmi) { u32 val; u64 color = MEDIA_BUS_FMT_YUV8_1X24; const struct dw_hdmi_property_ops *ops = hdmi->plat_data->property_ops; - void *data = hdmi->plat_data->phy_data; enum drm_connector_status connect_status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); if ((connect_status == connector_status_connected) && hdmi->initialized) { - if (hdmi->plat_data->get_grf_color_fmt) - color = hdmi->plat_data->get_grf_color_fmt(data); + color = dw_hdmi_qp_get_color_fmt(hdmi); val = (hdmi_readl(hdmi, PKT_VSI_CONTENTS1) >> 8) & 0xffffff; if (val == HDMI_FORUM_OUI) @@ -3613,6 +3709,7 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, cancel_work_sync(&hdmi->flt_work); flush_workqueue(hdmi->workqueue); + dw_hdmi_qp_flt_ltsl(hdmi); if (hdmi->panel) drm_panel_unprepare(hdmi->panel); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 5eabbbd03eee..c29caa36b004 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -2399,45 +2399,6 @@ static void rk3588_get_grf_color_fmt(struct rockchip_hdmi *hdmi, u32 *fmt, u32 * *fmt = *fmt & RK3588_COLOR_FORMAT_MASK; } -static u64 rockchip_get_grf_color_fmt(void *data) -{ - struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; - u32 fmt, depth; - u64 bus_format; - - hdmi->chip_data->ops->get_grf_color_fmt(hdmi, &fmt, &depth); - - switch (fmt) { - case RK3588_YUV444: - if (!depth) - bus_format = MEDIA_BUS_FMT_YUV8_1X24; - else - bus_format = MEDIA_BUS_FMT_YUV10_1X30; - break; - case RK3588_YUV422: - bus_format = MEDIA_BUS_FMT_YUYV10_1X20; - break; - case RK3588_YUV420: - if (!depth) - bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; - else - bus_format = MEDIA_BUS_FMT_UYYVYY10_0_5X30; - break; - case RK3588_RGB: - if (!depth) - bus_format = MEDIA_BUS_FMT_RGB888_1X24; - else - bus_format = MEDIA_BUS_FMT_RGB101010_1X30; - break; - default: - dev_err(hdmi->dev, "can't get correct color format\n"); - bus_format = MEDIA_BUS_FMT_YUV8_1X24; - break; - } - - return bus_format; -} - static void dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state, struct drm_crtc_state *crtc_state, @@ -4603,7 +4564,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, plat_data->set_hdcp2_enable = rockchip_set_hdcp2_enable; plat_data->set_hdcp_status = rockchip_set_hdcp_status; plat_data->set_grf_cfg = rockchip_set_grf_cfg; - plat_data->get_grf_color_fmt = rockchip_get_grf_color_fmt; plat_data->convert_to_split_mode = drm_mode_convert_to_split_mode; plat_data->convert_to_origin_mode = drm_mode_convert_to_origin_mode; plat_data->dclk_set = dw_hdmi_dclk_set; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index a9b8700f17d6..796c146c2555 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -273,7 +273,6 @@ struct dw_hdmi_plat_data { void (*set_hdcp_status)(void *data, u8 status); void (*set_hdcp2_enable)(void *data, bool enable); void (*set_grf_cfg)(void *data); - u64 (*get_grf_color_fmt)(void *data); void (*convert_to_split_mode)(struct drm_display_mode *mode); void (*convert_to_origin_mode)(struct drm_display_mode *mode); int (*dclk_set)(void *data, bool enable, int vp_id);