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);