From ff7af21e33065dda99b8753f0e1611fe0450a9f5 Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Wed, 20 Nov 2024 14:35:30 +0800 Subject: [PATCH] drm/rockchip: dw_hdmi: Support get hdr10 plus vsdb Add drm property HDR10_PLUS_VSDB that hdr10 plus data in edid: struct hdr10_plus_vsdb { u8 application_version; u8 full_frame_peak_luminance_index; u8 peak_luminance_index; }; Change-Id: I464cb67e0d9784df905bf34fd8472f80a6b98296 Signed-off-by: Algea Cao --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 2 + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 49 ++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 44 ++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + include/drm/bridge/dw_hdmi.h | 8 ++++ 5 files changed, 104 insertions(+) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 8dbe50439f84..398079e53c72 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -2770,6 +2770,8 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->plat_data->get_colorimetry(data, edid); if (hdmi->plat_data->get_yuv422_format) hdmi->plat_data->get_yuv422_format(connector, edid); + if (hdmi->plat_data->get_hdr10_plus_vsdb) + hdmi->plat_data->get_hdr10_plus_vsdb(data, edid, connector); dw_hdmi_update_hdr_property(connector); if (ret > 0 && hdmi->plat_data->split_mode) { struct dw_hdmi_qp *secondary = NULL; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 1d4d8d07bf49..640c998efff6 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -314,11 +314,13 @@ struct rockchip_hdmi { struct drm_property *mode_color_capacity; struct drm_property *hdr_panel_dovi_vsdb; struct drm_property *vsif_data; + struct drm_property *hdr10_plus_vsdb; struct drm_property_blob *mode_color_caps_ptr; struct drm_property_blob *hdr_panel_blob_ptr; struct drm_property_blob *hdr_panel_dovi_vsdb_ptr; struct drm_property_blob *vsif_data_ptr; + struct drm_property_blob *hdr10_plus_vsdb_ptr; unsigned int colordepth; unsigned int colorimetry; @@ -335,6 +337,7 @@ struct rockchip_hdmi { u8 edid_colorimetry; u8 hdcp_status; u8 dovi_vsdb[DOVI_VSDB_LEN]; + struct hdr10_plus_vsdb hdr10_plus_data; struct rockchip_drm_dsc_cap dsc_cap; struct dw_hdmi_link_config link_cfg; struct gpio_desc *enable_gpio; @@ -2867,6 +2870,31 @@ dw_hdmi_rockchip_get_edid_dsc_info(void *data, const struct edid *edid) &hdmi->max_lanes, &hdmi->add_func, edid); } +static int +dw_hdmi_rockchip_get_hdr10_plus_vsdb(void *data, const struct edid *edid, + struct drm_connector *connector) +{ + int ret; + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + struct drm_property *property = hdmi->hdr10_plus_vsdb; + u8 hdr10_plus; + + if (!edid || !connector) + return -ENOMEM; + + hdr10_plus = rockchip_drm_parse_hdr10_plus_vsdb(edid); + + hdmi->hdr10_plus_data.application_version = hdr10_plus & 0x3; + hdmi->hdr10_plus_data.full_frame_peak_luminance_index = hdr10_plus & 0xc; + hdmi->hdr10_plus_data.peak_luminance_index = hdr10_plus & 0xf0; + + ret = drm_property_replace_global_blob(connector->dev, &hdmi->hdr10_plus_vsdb_ptr, + 3, &hdmi->hdr10_plus_data, &connector->base, + property); + + return ret; +} + static int dw_hdmi_rockchip_get_dovi_data(void *data, const struct edid *edid, struct drm_connector *connector) @@ -3418,6 +3446,15 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector, drm_object_attach_property(&connector->base, prop, 0); } hdmi->enable_allm = allm_en; + + prop = drm_property_create(connector->dev, + DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_IMMUTABLE, + "HDR10_PLUS_VSDB", 0); + if (prop) { + hdmi->hdr10_plus_vsdb = prop; + drm_object_attach_property(&connector->base, prop, 0); + } } prop = drm_property_create_enum(connector->dev, 0, @@ -3572,6 +3609,11 @@ dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector, drm_property_destroy(connector->dev, hdmi->vsif_data); hdmi->vsif_data = NULL; } + + if (hdmi->hdr10_plus_vsdb) { + drm_property_destroy(connector->dev, hdmi->hdr10_plus_vsdb); + hdmi->hdr10_plus_vsdb = NULL; + } } static int @@ -3652,6 +3694,8 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector, &hdmi->vsif_data_ptr, val, -1, -1, &replaced); return ret; + } else if (property == hdmi->hdr10_plus_vsdb) { + return 0; } DRM_ERROR("Unknown property [PROP:%d:%s]\n", @@ -3744,6 +3788,9 @@ dw_hdmi_rockchip_get_property(struct drm_connector *connector, } else if (property == hdmi->vsif_data) { *val = (hdmi->vsif_data_ptr) ? hdmi->vsif_data_ptr->base.id : 0; return 0; + } else if (property == hdmi->hdr10_plus_vsdb) { + *val = (hdmi->hdr10_plus_vsdb_ptr) ? hdmi->hdr10_plus_vsdb_ptr->base.id : 0; + return 0; } DRM_ERROR("Unknown property [PROP:%d:%s]\n", @@ -4445,6 +4492,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, dw_hdmi_rockchip_get_colorimetry; plat_data->get_dovi_vsif = dw_hdmi_rockchip_get_vsif_data; + plat_data->get_hdr10_plus_vsdb = + dw_hdmi_rockchip_get_hdr10_plus_vsdb; plat_data->get_link_cfg = dw_hdmi_rockchip_get_link_cfg; plat_data->set_hdcp2_enable = rockchip_set_hdcp2_enable; plat_data->set_hdcp_status = rockchip_set_hdcp_status; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d525319a612f..9a8c2c5a6ac2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1179,6 +1179,50 @@ rockchip_drm_parse_colorimetry_data_block(u8 *colorimetry, const struct edid *ed } EXPORT_SYMBOL(rockchip_drm_parse_colorimetry_data_block); +#define HDR10_PLUS_OUI 0x90848b + +static bool cea_db_is_hdr10_plus_block(const u8 *db) +{ + unsigned int oui; + + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) + return false; + + if (cea_db_payload_len(db) < 5) + return false; + + oui = db[4] << 16 | db[3] << 8 | db[2]; + return oui == HDR10_PLUS_OUI; +} + +u8 rockchip_drm_parse_hdr10_plus_vsdb(const struct edid *edid) +{ + const u8 *edid_ext; + int i, start, end; + u8 hdr10_plus = 0; + + if (!edid) + return 0; + + edid_ext = find_cea_extension(edid); + if (!edid_ext) + return 0; + + if (cea_db_offsets(edid_ext, &start, &end)) + return 0; + + for_each_cea_db(edid_ext, i, start, end) { + const u8 *db = &edid_ext[i]; + + if (cea_db_is_hdr10_plus_block(db)) + /* As per CEA 861-G spec */ + hdr10_plus = db[5]; + } + + return hdr10_plus; +} +EXPORT_SYMBOL(rockchip_drm_parse_hdr10_plus_vsdb); + /* * Attach a (component) device to the shared drm dma mapping from master drm * device. This is used by the VOPs to map GEM buffers to a common DMA diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 90e2c4ffd43b..b6d11095992f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -669,6 +669,7 @@ int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, const struct edid *edid); int rockchip_drm_parse_dovi(u8 *sink_data, const struct edid *edid); int rockchip_drm_parse_colorimetry_data_block(u8 *colorimetry, const struct edid *edid); +u8 rockchip_drm_parse_hdr10_plus_vsdb(const struct edid *edid); struct dma_buf *rockchip_drm_gem_prime_export(struct drm_gem_object *obj, int flags); long rockchip_drm_dclk_round_rate(u32 version, struct clk *dclk, unsigned long rate); int rockchip_drm_dclk_set_rate(u32 version, struct clk *dclk, unsigned long rate); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 9580f6e43d3c..c674866b5ef8 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -148,6 +148,12 @@ struct dovi_vsif_data { u8 pb[28]; }; +struct hdr10_plus_vsdb { + u8 application_version; + u8 full_frame_peak_luminance_index; + u8 peak_luminance_index; +}; + struct dw_hdmi_phy_ops { int (*init)(struct dw_hdmi *hdmi, void *data, const struct drm_display_info *display, @@ -286,6 +292,8 @@ struct dw_hdmi_plat_data { void *data); void (*crtc_pre_disable)(void *data, struct drm_crtc *crtc); void (*crtc_post_enable)(void *data, struct drm_crtc *crtc); + int (*get_hdr10_plus_vsdb)(void *data, const struct edid *edid, + struct drm_connector *connector); /* Vendor Property support */ const struct dw_hdmi_property_ops *property_ops;