From 31d7cfd41ec4eff0058624f8c828ce75361ed44d Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Fri, 29 Oct 2021 15:29:44 +0800 Subject: [PATCH] drm/rockchip: drv: Parse edid next hdr info in rockchip driver To be compatible with GKI, we parse the edid next hdr information in rockchup-drm driver. Signed-off-by: Algea Cao Change-Id: Id6fd8f2d8429b07472c6562c223ae84262952e8d --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 192 ++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 79 ++++++++ 2 files changed, 271 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index e5b7460be2b8..266544119ffb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -267,6 +267,23 @@ cea_db_payload_len(const u8 *db) (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); \ (i) += cea_db_payload_len(&(cea)[(i)]) + 1) +#define HDMI_NEXT_HDR_VSDB_OUI 0xd04601 + +static bool cea_db_is_hdmi_next_hdr_block(const u8 *db) +{ + unsigned int oui; + + if (cea_db_tag(db) != 0x07) + return false; + + if (cea_db_payload_len(db) < 11) + return false; + + oui = db[3] << 16 | db[2] << 8 | db[1]; + + return oui == HDMI_NEXT_HDR_VSDB_OUI; +} + static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) { unsigned int oui; @@ -578,6 +595,152 @@ void parse_edid_forum_vsdb(struct rockchip_drm_dsc_cap *dsc_cap, } } +enum { + VER_26_BYTE_V0, + VER_15_BYTE_V1, + VER_12_BYTE_V1, + VER_12_BYTE_V2, +}; + +static int check_next_hdr_version(const u8 *next_hdr_db) +{ + u16 ver; + + ver = (next_hdr_db[5] & 0xf0) << 8 | next_hdr_db[0]; + + switch (ver) { + case 0x00f9: + return VER_26_BYTE_V0; + case 0x20ee: + return VER_15_BYTE_V1; + case 0x20eb: + return VER_12_BYTE_V1; + case 0x40eb: + return VER_12_BYTE_V2; + default: + return -ENOENT; + } +} + +static void parse_ver_26_v0_data(struct ver_26_v0 *hdr, const u8 *data) +{ + hdr->yuv422_12bit = data[5] & BIT(0); + hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; + hdr->global_dimming = (data[5] & BIT(2)) >> 2; + + hdr->dm_major_ver = (data[21] & 0xf0) >> 4; + hdr->dm_minor_ver = data[21] & 0xf; + + hdr->t_min_pq = (data[19] << 4) | ((data[18] & 0xf0) >> 4); + hdr->t_max_pq = (data[20] << 4) | (data[18] & 0xf); + + hdr->rx = (data[7] << 4) | ((data[6] & 0xf0) >> 4); + hdr->ry = (data[8] << 4) | (data[6] & 0xf); + hdr->gx = (data[10] << 4) | ((data[9] & 0xf0) >> 4); + hdr->gy = (data[11] << 4) | (data[9] & 0xf); + hdr->bx = (data[13] << 4) | ((data[12] & 0xf0) >> 4); + hdr->by = (data[14] << 4) | (data[12] & 0xf); + hdr->wx = (data[16] << 4) | ((data[15] & 0xf0) >> 4); + hdr->wy = (data[17] << 4) | (data[15] & 0xf); +} + +static void parse_ver_15_v1_data(struct ver_15_v1 *hdr, const u8 *data) +{ + hdr->yuv422_12bit = data[5] & BIT(0); + hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; + hdr->global_dimming = data[6] & BIT(0); + + hdr->dm_version = (data[5] & 0x1c) >> 2; + + hdr->colorimetry = data[7] & BIT(0); + + hdr->t_max_lum = (data[6] & 0xfe) >> 1; + hdr->t_min_lum = (data[7] & 0xfe) >> 1; + + hdr->rx = data[9]; + hdr->ry = data[10]; + hdr->gx = data[11]; + hdr->gy = data[12]; + hdr->bx = data[13]; + hdr->by = data[14]; +} + +static void parse_ver_12_v1_data(struct ver_12_v1 *hdr, const u8 *data) +{ + hdr->yuv422_12bit = data[5] & BIT(0); + hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1; + hdr->global_dimming = data[6] & BIT(0); + + hdr->dm_version = (data[5] & 0x1c) >> 2; + + hdr->colorimetry = data[7] & BIT(0); + + hdr->t_max_lum = (data[6] & 0xfe) >> 1; + hdr->t_min_lum = (data[7] & 0xfe) >> 1; + + hdr->low_latency = data[8] & 0x3; + + hdr->unique_rx = (data[11] & 0xf8) >> 3; + hdr->unique_ry = (data[11] & 0x7) << 2 | (data[10] & BIT(0)) << 1 | + (data[9] & BIT(0)); + hdr->unique_gx = (data[9] & 0xfe) >> 1; + hdr->unique_gy = (data[10] & 0xfe) >> 1; + hdr->unique_bx = (data[8] & 0xe0) >> 5; + hdr->unique_by = (data[8] & 0x1c) >> 2; +} + +static void parse_ver_12_v2_data(struct ver_12_v2 *hdr, const u8 *data) +{ + hdr->yuv422_12bit = data[5] & BIT(0); + hdr->backlt_ctrl = (data[5] & BIT(1)) >> 1; + hdr->global_dimming = (data[6] & BIT(2)) >> 2; + + hdr->dm_version = (data[5] & 0x1c) >> 2; + hdr->backlt_min_luma = data[6] & 0x3; + hdr->interface = data[7] & 0x3; + hdr->yuv444_10b_12b = (data[8] & BIT(0)) << 1 | (data[9] & BIT(0)); + + hdr->t_min_pq_v2 = (data[6] & 0xf8) >> 3; + hdr->t_max_pq_v2 = (data[7] & 0xf8) >> 3; + + hdr->unique_rx = (data[10] & 0xf8) >> 3; + hdr->unique_ry = (data[11] & 0xf8) >> 3; + hdr->unique_gx = (data[8] & 0xfe) >> 1; + hdr->unique_gy = (data[9] & 0xfe) >> 1; + hdr->unique_bx = data[10] & 0x7; + hdr->unique_by = data[11] & 0x7; +} + +static +void parse_next_hdr_block(struct next_hdr_sink_data *sink_data, + const u8 *next_hdr_db) +{ + int version; + + version = check_next_hdr_version(next_hdr_db); + if (version < 0) + return; + + sink_data->version = version; + + switch (version) { + case VER_26_BYTE_V0: + parse_ver_26_v0_data(&sink_data->ver_26_v0, next_hdr_db); + break; + case VER_15_BYTE_V1: + parse_ver_15_v1_data(&sink_data->ver_15_v1, next_hdr_db); + break; + case VER_12_BYTE_V1: + parse_ver_12_v1_data(&sink_data->ver_12_v1, next_hdr_db); + break; + case VER_12_BYTE_V2: + parse_ver_12_v2_data(&sink_data->ver_12_v2, next_hdr_db); + break; + default: + break; + } +} + int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, u8 *max_frl_rate_per_lane, u8 *max_lanes, const struct edid *edid) @@ -607,6 +770,35 @@ int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, } EXPORT_SYMBOL(rockchip_drm_parse_cea_ext); +int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data, + const struct edid *edid) +{ + const u8 *edid_ext; + int i, start, end; + + if (!sink_data || !edid) + return -EINVAL; + + memset(sink_data, 0, sizeof(struct next_hdr_sink_data)); + + edid_ext = find_cea_extension(edid); + if (!edid_ext) + return -EINVAL; + + if (cea_db_offsets(edid_ext, &start, &end)) + return -EINVAL; + + for_each_cea_db(edid_ext, i, start, end) { + const u8 *db = &edid_ext[i]; + + if (cea_db_is_hdmi_next_hdr_block(db)) + parse_next_hdr_block(sink_data, db); + } + + return 0; +} +EXPORT_SYMBOL(rockchip_drm_parse_next_hdr); + /* * 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 5454f845b086..f220458b6fc6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -221,6 +221,83 @@ struct rockchip_drm_dsc_cap { int clk_per_slice; }; +struct ver_26_v0 { + u8 yuv422_12bit; + u8 support_2160p_60; + u8 global_dimming; + u8 dm_major_ver; + u8 dm_minor_ver; + u16 t_min_pq; + u16 t_max_pq; + u16 rx; + u16 ry; + u16 gx; + u16 gy; + u16 bx; + u16 by; + u16 wx; + u16 wy; +} __packed; + +struct ver_15_v1 { + u8 yuv422_12bit; + u8 support_2160p_60; + u8 global_dimming; + u8 dm_version; + u8 colorimetry; + u8 t_max_lum; + u8 t_min_lum; + u8 rx; + u8 ry; + u8 gx; + u8 gy; + u8 bx; + u8 by; +} __packed; + +struct ver_12_v1 { + u8 yuv422_12bit; + u8 support_2160p_60; + u8 global_dimming; + u8 dm_version; + u8 colorimetry; + u8 low_latency; + u8 t_max_lum; + u8 t_min_lum; + u8 unique_rx; + u8 unique_ry; + u8 unique_gx; + u8 unique_gy; + u8 unique_bx; + u8 unique_by; +} __packed; + +struct ver_12_v2 { + u8 yuv422_12bit; + u8 backlt_ctrl; + u8 global_dimming; + u8 dm_version; + u8 backlt_min_luma; + u8 interface; + u8 yuv444_10b_12b; + u8 t_min_pq_v2; + u8 t_max_pq_v2; + u8 unique_rx; + u8 unique_ry; + u8 unique_gx; + u8 unique_gy; + u8 unique_bx; + u8 unique_by; +} __packed; + +struct next_hdr_sink_data { + u8 version; + struct ver_26_v0 ver_26_v0; + struct ver_15_v1 ver_15_v1; + struct ver_12_v1 ver_12_v1; + struct ver_12_v2 ver_12_v2; +} __packed; + /* * Rockchip drm private crtc funcs. * @loader_protect: protect loader logo crtc's power @@ -341,6 +418,8 @@ int rockchip_drm_get_yuv422_format(struct drm_connector *connector, int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap, u8 *max_frl_rate_per_lane, u8 *max_lanes, const struct edid *edid); +int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data, + const struct edid *edid); extern struct platform_driver cdn_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;