From c79760ba9747244cc5ad5c8791c840be6ed62ae6 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 28 May 2019 17:16:04 -0700 Subject: [PATCH 1/3] disp: msm: dp: populate supported colorspace property for DP Populate the supported colorspaces property for DP as part of getting the display modes. This will expose the supported colorspaces of the sink to userspace and in-turn the userspace shall pick the colorspace suitable for the use-case. Change-Id: I70408c719610bc63f9c06dad8cd50f7fa5d94908 Signed-off-by: Abhinav Kumar --- msm/dp/dp_display.c | 10 ++++++++++ msm/msm_drv.h | 1 + msm/sde/sde_connector.c | 23 +++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 8fa0dc81fde2..68b26d4cf76e 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1676,6 +1676,14 @@ end: return 0; } +static void dp_display_clear_colorspaces(struct dp_display *dp_display) +{ + struct drm_connector *connector; + + connector = dp_display->base_connector; + connector->color_enc_fmt = 0; +} + static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) { struct dp_display_private *dp; @@ -1732,6 +1740,8 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) } } + dp_display_clear_colorspaces(dp_display); + clean: if (dp_panel->audio_supported) dp_panel->audio->off(dp_panel->audio); diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 264c69f001f7..a99a64a8da08 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -190,6 +190,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_ROI_V1, CONNECTOR_PROP_BL_SCALE, CONNECTOR_PROP_SV_BL_SCALE, + CONNECTOR_PROP_SUPPORTED_COLORSPACES, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 844d2b859016..99550b67a61b 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1480,6 +1480,20 @@ static void sde_connector_update_hdr_props(struct drm_connector *connector) &hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO); } +static void sde_connector_update_colorspace(struct drm_connector *connector) +{ + int ret; + + ret = msm_property_set_property( + sde_connector_get_propinfo(connector), + sde_connector_get_property_state(connector->state), + CONNECTOR_PROP_SUPPORTED_COLORSPACES, + connector->color_enc_fmt); + + if (ret) + SDE_ERROR("failed to set colorspace property for connector\n"); +} + static enum drm_connector_status sde_connector_detect(struct drm_connector *connector, bool force) { @@ -1919,6 +1933,9 @@ static int sde_connector_get_modes(struct drm_connector *connector) if (c_conn->hdr_capable) sde_connector_update_hdr_props(connector); + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + sde_connector_update_colorspace(connector); + return mode_count; } @@ -2388,6 +2405,12 @@ static int _sde_connector_install_properties(struct drm_device *dev, c_conn->bl_scale = MAX_BL_SCALE_LEVEL; c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) + msm_property_install_range(&c_conn->property_info, + "supported_colorspaces", + DRM_MODE_PROP_IMMUTABLE, 0, 0xffff, 0, + CONNECTOR_PROP_SUPPORTED_COLORSPACES); + /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, From 7f5f73ff4104f74825ffcf2ae0a420794976f80d Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 4 Jun 2019 17:32:01 -0700 Subject: [PATCH 2/3] disp: msm: dp: separate hdr data into individual packets Currently a lot of information is packed into the HDR data structure of the catalog panel making it difficult to individually control the parameters like colorimetry and other information sent using VSC SDP packets. Break up the structure into individual VSC SDP colorimetry, HDR infoframe and DHDR VSIF packets. This makes it easier to control each of these parameters independently. For example, when only the colorspace is changed its sufficient to update only the VSC SDP colorimetry packets. Also align these packets with the upstream DP helper header defines. Change-Id: Ia208f30a480fd203192624fe4f3d99c1c89350dc Signed-off-by: Abhinav Kumar --- msm/dp/dp_catalog.c | 54 +++++++------------ msm/dp/dp_catalog.h | 35 +++--------- msm/dp/dp_panel.c | 127 +++++++++++++++++++++++++++++++------------- 3 files changed, 118 insertions(+), 98 deletions(-) diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index 339580c5cd3a..d6f25d70d507 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -6,7 +6,6 @@ #include #include -#include #include "dp_catalog.h" #include "dp_reg.h" @@ -496,11 +495,11 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp( mst_offset = MMSS_DP1_VSCEXT_0 - MMSS_DP_VSCEXT_0; catalog = dp_catalog_get_priv(panel); - hdr = &panel->hdr_data.hdr_meta; + hdr = &panel->hdr_meta; io_data = catalog->io.dp_link; /* HEADER BYTE 1 */ - header = panel->hdr_data.vscext_header_byte1; + header = panel->dhdr_vsif_sdp.HB1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); @@ -510,7 +509,7 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp( off += sizeof(data); /* HEADER BYTE 2 */ - header = panel->hdr_data.vscext_header_byte2; + header = panel->dhdr_vsif_sdp.HB2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); @@ -518,7 +517,7 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp( data); /* HEADER BYTE 3 */ - header = panel->hdr_data.vscext_header_byte3; + header = panel->dhdr_vsif_sdp.HB3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); @@ -541,6 +540,8 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp( struct dp_io_data *io_data; u32 header, parity, data, mst_offset = 0; u8 buf[SZ_64], off = 0; + u32 const version = 0x01; + u32 const length = 0x1a; if (panel->stream_id >= DP_STREAM_MAX) { DP_ERR("invalid stream_id:%d\n", panel->stream_id); @@ -551,11 +552,11 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp( mst_offset = MMSS_DP1_GENERIC2_0 - MMSS_DP_GENERIC2_0; catalog = dp_catalog_get_priv(panel); - hdr = &panel->hdr_data.hdr_meta; + hdr = &panel->hdr_meta; io_data = catalog->io.dp_link; /* HEADER BYTE 1 */ - header = panel->hdr_data.shdr_header_byte1; + header = panel->shdr_if_sdp.HB1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); @@ -565,7 +566,7 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp( off += sizeof(data); /* HEADER BYTE 2 */ - header = panel->hdr_data.shdr_header_byte2; + header = panel->shdr_if_sdp.HB2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); @@ -573,7 +574,7 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp( data); /* HEADER BYTE 3 */ - header = panel->hdr_data.shdr_header_byte3; + header = panel->shdr_if_sdp.HB3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); @@ -584,8 +585,8 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp( memcpy(buf + off, &data, sizeof(data)); off += sizeof(data); - data = panel->hdr_data.version; - data |= panel->hdr_data.length << 8; + data = version; + data |= length << 8; data |= hdr->eotf << 16; dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC2_2 + mst_offset, data); @@ -661,7 +662,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) struct dp_catalog_private *catalog; struct dp_io_data *io_data; u32 header, parity, data, mst_offset = 0; - u8 bpc, off = 0; + u8 off = 0; u8 buf[SZ_128]; if (!panel) { @@ -681,7 +682,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) io_data = catalog->io.dp_link; /* HEADER BYTE 1 */ - header = panel->hdr_data.vsc_header_byte1; + header = panel->vsc_colorimetry.header.HB1; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_1_BIT) | (parity << PARITY_BYTE_1_BIT)); @@ -691,7 +692,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) off += sizeof(data); /* HEADER BYTE 2 */ - header = panel->hdr_data.vsc_header_byte2; + header = panel->vsc_colorimetry.header.HB2; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_2_BIT) | (parity << PARITY_BYTE_2_BIT)); @@ -699,7 +700,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) data); /* HEADER BYTE 3 */ - header = panel->hdr_data.vsc_header_byte3; + header = panel->vsc_colorimetry.header.HB3; parity = dp_header_get_parity(header); data = ((header << HEADER_BYTE_3_BIT) | (parity << PARITY_BYTE_3_BIT)); @@ -731,24 +732,9 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) memcpy(buf + off, &data, sizeof(data)); off += sizeof(data); - switch (panel->hdr_data.bpc) { - default: - case 10: - bpc = BIT(1); - break; - case 8: - bpc = BIT(0); - break; - case 6: - bpc = 0; - break; - } - - data = (panel->hdr_data.colorimetry & 0xF) | - ((panel->hdr_data.pixel_encoding & 0xF) << 4) | - (bpc << 8) | - ((panel->hdr_data.dynamic_range & 0x1) << 15) | - ((panel->hdr_data.content_type & 0x7) << 16); + data = (panel->vsc_colorimetry.data[16] & 0xFF) | + ((panel->vsc_colorimetry.data[17] & 0xFF) << 8) | + ((panel->vsc_colorimetry.data[18] & 0x7) << 16); dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC0_6 + mst_offset, data); @@ -842,7 +828,7 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, /* indicates presence of VSC (BIT(6) of MISC1) */ misc |= BIT(14); - if (panel->hdr_data.hdr_meta.eotf) + if (panel->hdr_meta.eotf) DP_DEBUG("Enabled\n"); else DP_DEBUG("Reset\n"); diff --git a/msm/dp/dp_catalog.h b/msm/dp/dp_catalog.h index d1bf8760bfa7..58f4e3a7f30c 100644 --- a/msm/dp/dp_catalog.h +++ b/msm/dp/dp_catalog.h @@ -6,6 +6,7 @@ #ifndef _DP_CATALOG_H_ #define _DP_CATALOG_H_ +#include #include #include "dp_parser.h" @@ -39,32 +40,9 @@ enum dp_stream_id { DP_STREAM_MAX, }; -struct dp_catalog_hdr_data { - u32 vsc_header_byte0; - u32 vsc_header_byte1; - u32 vsc_header_byte2; - u32 vsc_header_byte3; - - u32 vscext_header_byte0; - u32 vscext_header_byte1; - u32 vscext_header_byte2; - u32 vscext_header_byte3; - - u32 shdr_header_byte0; - u32 shdr_header_byte1; - u32 shdr_header_byte2; - u32 shdr_header_byte3; - - u32 bpc; - - u32 version; - u32 length; - u32 pixel_encoding; - u32 colorimetry; - u32 dynamic_range; - u32 content_type; - - struct drm_msm_ext_hdr_metadata hdr_meta; +struct dp_catalog_vsc_sdp_colorimetry { + struct dp_sdp_header header; + u8 data[32]; }; struct dp_catalog_aux { @@ -197,7 +175,10 @@ struct dp_catalog_panel { u8 *spd_vendor_name; u8 *spd_product_description; - struct dp_catalog_hdr_data hdr_data; + struct dp_catalog_vsc_sdp_colorimetry vsc_colorimetry; + struct dp_sdp_header dhdr_vsif_sdp; + struct dp_sdp_header shdr_if_sdp; + struct drm_msm_ext_hdr_metadata hdr_meta; /* TPG */ u32 hsync_period; diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 23b381835419..a0757a5db540 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -2480,7 +2480,10 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) { int rc = 0; struct dp_panel_private *panel; - struct dp_catalog_hdr_data *hdr; + struct drm_msm_ext_hdr_metadata *hdr_meta; + struct dp_sdp_header *dhdr_vsif_sdp; + struct dp_sdp_header *shdr_if_sdp; + struct dp_catalog_vsc_sdp_colorimetry *vsc_colorimetry; struct drm_connector *connector; struct sde_connector_state *c_state; @@ -2495,14 +2498,22 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) } panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - hdr = &panel->catalog->hdr_data; + hdr_meta = &panel->catalog->hdr_meta; + dhdr_vsif_sdp = &panel->catalog->dhdr_vsif_sdp; + shdr_if_sdp = &panel->catalog->shdr_if_sdp; + vsc_colorimetry = &panel->catalog->vsc_colorimetry; if (!panel->custom_edid && dp_panel->edid_ctrl->edid) sde_free_edid((void **)&dp_panel->edid_ctrl); dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0, 0); memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo)); - memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); + memset(hdr_meta, 0, sizeof(struct drm_msm_ext_hdr_metadata)); + memset(dhdr_vsif_sdp, 0, sizeof(struct dp_sdp_header)); + memset(shdr_if_sdp, 0, sizeof(struct dp_sdp_header)); + memset(vsc_colorimetry, 0, + sizeof(struct dp_catalog_vsc_sdp_colorimetry)); + panel->panel_on = false; connector = dp_panel->connector; @@ -2646,14 +2657,76 @@ static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel, return calc_pkt_limit; } +static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_catalog_vsc_sdp_colorimetry *hdr_colorimetry; + u8 bpc; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + hdr_colorimetry = &panel->catalog->vsc_colorimetry; + + hdr_colorimetry->header.HB0 = 0x00; + hdr_colorimetry->header.HB1 = 0x07; + hdr_colorimetry->header.HB2 = 0x05; + hdr_colorimetry->header.HB3 = 0x13; + + /* VSC SDP Payload for DB16 */ + hdr_colorimetry->data[16] = (RGB << 4) | ITU_R_BT_2020_RGB; + + /* VSC SDP Payload for DB17 */ + hdr_colorimetry->data[17] = (CEA << 7); + bpc = (dp_panel->pinfo.bpp / 3); + + switch (bpc) { + default: + case 10: + hdr_colorimetry->data[17] |= BIT(1); + break; + case 8: + hdr_colorimetry->data[17] |= BIT(0); + break; + case 6: + hdr_colorimetry->data[17] |= 0; + break; + } + + /* VSC SDP Payload for DB18 */ + hdr_colorimetry->data[18] = GRAPHICS; +} + +static void dp_panel_setup_hdr_if(struct dp_panel_private *panel) +{ + struct dp_sdp_header *shdr_if; + + shdr_if = &panel->catalog->shdr_if_sdp; + + shdr_if->HB0 = 0x00; + shdr_if->HB1 = 0x87; + shdr_if->HB2 = 0x1D; + shdr_if->HB3 = 0x13 << 2; +} + +static void dp_panel_setup_dhdr_vsif(struct dp_panel_private *panel) +{ + struct dp_sdp_header *dhdr_vsif; + + dhdr_vsif = &panel->catalog->dhdr_vsif_sdp; + + dhdr_vsif->HB0 = 0x00; + dhdr_vsif->HB1 = 0x81; + dhdr_vsif->HB2 = 0x1D; + dhdr_vsif->HB3 = 0x13 << 2; +} + static int dp_panel_setup_hdr(struct dp_panel *dp_panel, struct drm_msm_ext_hdr_metadata *hdr_meta, bool dhdr_update, u64 core_clk_rate) { int rc = 0, max_pkts = 0; struct dp_panel_private *panel; - struct dp_catalog_hdr_data *hdr; struct dp_dhdr_maxpkt_calc_input input; + struct drm_msm_ext_hdr_metadata *catalog_hdr_meta; if (!dp_panel) { DP_ERR("invalid input\n"); @@ -2662,11 +2735,12 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel, } panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - hdr = &panel->catalog->hdr_data; + + catalog_hdr_meta = &panel->catalog->hdr_meta; /* use cached meta data in case meta data not provided */ if (!hdr_meta) { - if (hdr->hdr_meta.hdr_state) + if (catalog_hdr_meta->hdr_state) goto cached; else goto end; @@ -2674,41 +2748,20 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel, panel->hdr_state = hdr_meta->hdr_state; - hdr->vsc_header_byte0 = 0x00; - hdr->vsc_header_byte1 = 0x07; - hdr->vsc_header_byte2 = 0x05; - hdr->vsc_header_byte3 = 0x13; + dp_panel_setup_colorimetry_sdp(dp_panel); - hdr->shdr_header_byte0 = 0x00; - hdr->shdr_header_byte1 = 0x87; - hdr->shdr_header_byte2 = 0x1D; - hdr->shdr_header_byte3 = 0x13 << 2; + dp_panel_setup_hdr_if(panel); - /* VSC SDP Payload for DB16 */ - hdr->pixel_encoding = RGB; - hdr->colorimetry = ITU_R_BT_2020_RGB; - - /* VSC SDP Payload for DB17 */ - hdr->dynamic_range = CEA; - - /* VSC SDP Payload for DB18 */ - hdr->content_type = GRAPHICS; - - hdr->bpc = dp_panel->pinfo.bpp / 3; - - hdr->version = 0x01; - hdr->length = 0x1A; - - if (panel->hdr_state) - memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta)); - else - memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); + if (panel->hdr_state) { + memcpy(catalog_hdr_meta, hdr_meta, + sizeof(struct drm_msm_ext_hdr_metadata)); + } else { + memset(catalog_hdr_meta, 0, + sizeof(struct drm_msm_ext_hdr_metadata)); + } cached: if (dhdr_update) { - hdr->vscext_header_byte0 = 0x00; - hdr->vscext_header_byte1 = 0x81; - hdr->vscext_header_byte2 = 0x1D; - hdr->vscext_header_byte3 = 0x13 << 2; + dp_panel_setup_dhdr_vsif(panel); input.mdp_clk = core_clk_rate; input.lclk = dp_panel->link_info.rate; From 14e02e4b02716e58d14b84dd6fe54a849a5fc6c8 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Fri, 7 Jun 2019 19:13:41 -0700 Subject: [PATCH 3/3] disp: msm: dp: add colorspace property for MSM DP Add the colorspace property for DP controller for MSM. Also, change the default method to send the colorimetry information to the sink from MISC bits of MSA to VSC SDP packets if the sink supports it. This helps to avoid dynamic switches between the packet types for sending the colorimetry information during BT2020 and DCI-P3 use-cases. Change-Id: I7ddf879a187b023fcf7404d64028e4d19b031119 Signed-off-by: Abhinav Kumar --- msm/dp/dp_catalog.c | 206 +++++++++++++++++++++++++++++----------- msm/dp/dp_catalog.h | 5 +- msm/dp/dp_display.c | 37 +++++++- msm/dp/dp_display.h | 2 + msm/dp/dp_drm.c | 45 +++++++++ msm/dp/dp_drm.h | 21 ++++ msm/dp/dp_link.c | 2 +- msm/dp/dp_panel.c | 200 ++++++++++++++++++++++++++++++++++++-- msm/dp/dp_panel.h | 4 +- msm/sde/sde_connector.c | 28 ++++++ msm/sde/sde_connector.h | 11 +++ msm/sde/sde_kms.c | 2 + 12 files changed, 492 insertions(+), 71 deletions(-) diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index d6f25d70d507..8ec37ceffe09 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -477,6 +477,29 @@ static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl) return dp_read(catalog->exe_mode, io_data, DP_HDCP_STATUS); } +static void dp_catalog_panel_sdp_update(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 sdp_cfg3_off = 0; + + if (panel->stream_id >= DP_STREAM_MAX) { + pr_err("invalid stream_id:%d\n", panel->stream_id); + return; + } + + if (panel->stream_id == DP_STREAM_1) + sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3; + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, + 0x01); + dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, + 0x00); +} + static void dp_catalog_panel_setup_vsif_infoframe_sdp( struct dp_catalog_panel *panel) { @@ -761,15 +784,125 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) DUMP_PREFIX_NONE, 16, 4, buf, off, false); } +static void dp_catalog_panel_config_sdp(struct dp_catalog_panel *panel, + bool en) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 cfg, cfg2; + u32 sdp_cfg_off = 0; + u32 sdp_cfg2_off = 0; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) { + sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } + + cfg = dp_read(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG + sdp_cfg_off); + cfg2 = dp_read(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG2 + sdp_cfg2_off); + + if (en) { + /* GEN0_SDP_EN */ + cfg |= BIT(17); + dp_write(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC0_SDPSIZE */ + cfg2 |= BIT(16); + dp_write(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + + /* setup the GENERIC0 in case of en = true */ + dp_catalog_panel_setup_vsc_sdp(panel); + + } else { + /* GEN0_SDP_EN */ + cfg &= ~BIT(17); + dp_write(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC0_SDPSIZE */ + cfg2 &= ~BIT(16); + dp_write(catalog->exe_mode, io_data, + MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + } + + dp_catalog_panel_sdp_update(panel); +} + +static void dp_catalog_panel_config_misc(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 reg_offset = 0; + + if (!panel) { + pr_err("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + pr_err("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + reg_offset = DP1_MISC1_MISC0 - DP_MISC1_MISC0; + + DP_DEBUG("misc settings = 0x%x\n", panel->misc_val); + dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + reg_offset, + panel->misc_val); +} + +static int dp_catalog_panel_set_colorspace(struct dp_catalog_panel *panel, +bool vsc_supported) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + pr_err("invalid stream_id:%d\n", panel->stream_id); + return -EINVAL; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (vsc_supported) { + dp_catalog_panel_setup_vsc_sdp(panel); + dp_catalog_panel_sdp_update(panel); + } else + dp_catalog_panel_config_misc(panel); + + return 0; +} + static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, - u32 dhdr_max_pkts) + u32 dhdr_max_pkts, bool flush) { struct dp_catalog_private *catalog; struct dp_io_data *io_data; u32 cfg, cfg2, cfg4, misc; u32 sdp_cfg_off = 0; u32 sdp_cfg2_off = 0; - u32 sdp_cfg3_off = 0; u32 sdp_cfg4_off = 0; u32 misc1_misc0_off = 0; @@ -789,7 +922,6 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, if (panel->stream_id == DP_STREAM_1) { sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; - sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3; sdp_cfg4_off = MMSS_DP1_SDP_CFG4 - MMSS_DP_SDP_CFG4; misc1_misc0_off = DP1_MISC1_MISC0 - DP_MISC1_MISC0; } @@ -812,34 +944,30 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, dp_catalog_panel_setup_vsif_infoframe_sdp(panel); } - /* GEN0_SDP_EN, GEN2_SDP_EN */ - cfg |= BIT(17) | BIT(19); + /* GEN2_SDP_EN */ + cfg |= BIT(19); dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); - /* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */ - cfg2 |= BIT(16) | BIT(20); + /* GENERIC2_SDPSIZE */ + cfg2 |= BIT(20); dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); - dp_catalog_panel_setup_vsc_sdp(panel); dp_catalog_panel_setup_hdr_infoframe_sdp(panel); - /* indicates presence of VSC (BIT(6) of MISC1) */ - misc |= BIT(14); - if (panel->hdr_meta.eotf) DP_DEBUG("Enabled\n"); else DP_DEBUG("Reset\n"); } else { - /* VSCEXT_SDP_EN, GEN0_SDP_EN */ - cfg &= ~BIT(16) & ~BIT(17) & ~BIT(19); + /* VSCEXT_SDP_ENG */ + cfg &= ~BIT(16) & ~BIT(19); dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); /* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */ - cfg2 &= ~BIT(16) & ~BIT(20); + cfg2 &= ~BIT(20); dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); @@ -848,19 +976,13 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG4 + sdp_cfg4_off, cfg4); - /* switch back to MSA */ - misc &= ~BIT(14); - DP_DEBUG("Disabled\n"); } - dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + misc1_misc0_off, - misc); - - dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, - 0x01); - dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, - 0x00); + if (flush) { + DP_DEBUG("flushing HDR metadata\n"); + dp_catalog_panel_sdp_update(panel); + } } static void dp_catalog_panel_update_transfer_unit( @@ -1095,33 +1217,6 @@ static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl, } } -static void dp_catalog_panel_config_misc(struct dp_catalog_panel *panel) -{ - struct dp_catalog_private *catalog; - struct dp_io_data *io_data; - u32 reg_offset = 0; - - if (!panel) { - DP_ERR("invalid input\n"); - return; - } - - if (panel->stream_id >= DP_STREAM_MAX) { - DP_ERR("invalid stream_id:%d\n", panel->stream_id); - return; - } - - catalog = dp_catalog_get_priv(panel); - io_data = catalog->io.dp_link; - - if (panel->stream_id == DP_STREAM_1) - reg_offset = DP1_MISC1_MISC0 - DP_MISC1_MISC0; - - DP_DEBUG("misc settings = 0x%x\n", panel->misc_val); - dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + reg_offset, - panel->misc_val); -} - static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel, u32 rate, u32 stream_rate_khz) { @@ -2468,7 +2563,6 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) u32 offset = 0; u32 sdp_cfg_off = 0; u32 sdp_cfg2_off = 0; - u32 sdp_cfg3_off = 0; /* * Source Device Information @@ -2541,7 +2635,6 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) if (panel->stream_id == DP_STREAM_1) { sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; - sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3; } spd_cfg = dp_read(catalog->exe_mode, io_data, @@ -2558,10 +2651,7 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg2_off, spd_cfg2); - dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, - 0x1); - dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, - 0x0); + dp_catalog_panel_sdp_update(panel); } static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog) @@ -2719,9 +2809,11 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser) struct dp_catalog_panel panel = { .timing_cfg = dp_catalog_panel_timing_cfg, .config_hdr = dp_catalog_panel_config_hdr, + .config_sdp = dp_catalog_panel_config_sdp, .tpg_config = dp_catalog_panel_tpg_cfg, .config_spd = dp_catalog_panel_config_spd, .config_misc = dp_catalog_panel_config_misc, + .set_colorspace = dp_catalog_panel_set_colorspace, .config_msa = dp_catalog_panel_config_msa, .update_transfer_unit = dp_catalog_panel_update_transfer_unit, .config_ctrl = dp_catalog_panel_config_ctrl, diff --git a/msm/dp/dp_catalog.h b/msm/dp/dp_catalog.h index 58f4e3a7f30c..a1235b529463 100644 --- a/msm/dp/dp_catalog.h +++ b/msm/dp/dp_catalog.h @@ -203,7 +203,10 @@ struct dp_catalog_panel { int (*timing_cfg)(struct dp_catalog_panel *panel); void (*config_hdr)(struct dp_catalog_panel *panel, bool en, - u32 dhdr_max_pkts); + u32 dhdr_max_pkts, bool flush); + void (*config_sdp)(struct dp_catalog_panel *panel, bool en); + int (*set_colorspace)(struct dp_catalog_panel *panel, + bool vsc_supported); void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); void (*config_spd)(struct dp_catalog_panel *panel); void (*config_misc)(struct dp_catalog_panel *panel); diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 68b26d4cf76e..c8720f23f164 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1627,7 +1627,7 @@ static void dp_display_stream_post_enable(struct dp_display_private *dp, struct dp_panel *dp_panel) { dp_panel->spd_config(dp_panel); - dp_panel->setup_hdr(dp_panel, NULL, false, 0); + dp_panel->setup_hdr(dp_panel, NULL, false, 0, true); } static int dp_display_post_enable(struct dp_display *dp_display, void *panel) @@ -2092,8 +2092,10 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel, struct drm_msm_ext_hdr_metadata *hdr, bool dhdr_update) { struct dp_panel *dp_panel; + struct sde_connector *sde_conn; struct dp_display_private *dp; u64 core_clk_rate; + bool flush_hdr; if (!dp_display || !panel) { DP_ERR("invalid input\n"); @@ -2102,6 +2104,7 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel, dp_panel = panel; dp = container_of(dp_display, struct dp_display_private, dp_display); + sde_conn = to_sde_connector(dp_panel->connector); core_clk_rate = dp->power->clk_get_rate(dp->power, "core_clk"); if (!core_clk_rate) { @@ -2109,7 +2112,36 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel, return -EINVAL; } - return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update, core_clk_rate); + /* + * In rare cases where HDR metadata is updated independently + * flush the HDR metadata immediately instead of relying on + * the colorspace + */ + flush_hdr = !sde_conn->colorspace_updated; + + if (flush_hdr) + DP_DEBUG("flushing the HDR metadata\n"); + else + DP_DEBUG("piggy-backing with colorspace\n"); + + return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update, + core_clk_rate, flush_hdr); +} + +static int dp_display_setup_colospace(struct dp_display *dp_display, + void *panel, + u32 colorspace) +{ + struct dp_panel *dp_panel; + + if (!dp_display || !panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp_panel = panel; + + return dp_panel->set_colorspace(dp_panel, colorspace); } static int dp_display_create_workqueue(struct dp_display_private *dp) @@ -2633,6 +2665,7 @@ static int dp_display_probe(struct platform_device *pdev) dp_display_mst_get_fixed_topology_port; g_dp_display->wakeup_phy_layer = dp_display_wakeup_phy_layer; + g_dp_display->set_colorspace = dp_display_setup_colospace; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 8b5f730bcd20..6091c709179a 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -93,6 +93,8 @@ struct dp_display { int (*config_hdr)(struct dp_display *dp_display, void *panel, struct drm_msm_ext_hdr_metadata *hdr_meta, bool dhdr_update); + int (*set_colorspace)(struct dp_display *dp_display, void *panel, + u32 colorspace); int (*post_init)(struct dp_display *dp_display); int (*mst_install)(struct dp_display *dp_display, struct dp_mst_drm_install_info *mst_install_info); diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index b1adf287078e..7439338aaa22 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -326,6 +326,25 @@ int dp_connector_config_hdr(struct drm_connector *connector, void *display, c_state->dyn_hdr_meta.dynamic_hdr_update); } +int dp_connector_set_colorspace(struct drm_connector *connector, + void *display) +{ + struct dp_display *dp_display = display; + struct sde_connector *sde_conn; + + if (!dp_display || !connector) + return -EINVAL; + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + pr_err("invalid dp panel\n"); + return -EINVAL; + } + + return dp_display->set_colorspace(dp_display, + sde_conn->drv_panel, connector->state->colorspace); +} + int dp_connector_post_init(struct drm_connector *connector, void *display) { int rc; @@ -469,6 +488,32 @@ void dp_connector_post_open(struct drm_connector *connector, void *display) dp->post_open(dp); } +int dp_connector_atomic_check(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state) +{ + struct sde_connector *sde_conn; + struct drm_connector_state *old_state = + drm_atomic_get_old_connector_state(c_state->state, connector); + + if (!connector || !display) + return -EINVAL; + + sde_conn = to_sde_connector(connector); + + /* + * Marking the colorspace has been changed + * the flag shall be checked in the pre_kickoff + * to configure the new colorspace in HW + */ + if (c_state->colorspace != old_state->colorspace) { + DP_DEBUG("colorspace has been updated\n"); + sde_conn->colorspace_updated = true; + } + + return 0; +} + int dp_connector_get_modes(struct drm_connector *connector, void *display, const struct msm_resource_caps_info *avail_res) { diff --git a/msm/dp/dp_drm.h b/msm/dp/dp_drm.h index 13c1a059b33d..0056857ff7b3 100644 --- a/msm/dp/dp_drm.h +++ b/msm/dp/dp_drm.h @@ -37,6 +37,27 @@ int dp_connector_config_hdr(struct drm_connector *connector, void *display, struct sde_connector_state *c_state); +/** + * dp_connector_atomic_check - callback to perform atomic + * check for DP + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: connect state data + * Returns: Zero on success + */ +int dp_connector_atomic_check(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state); + +/** + * dp_connector_set_colorspace - callback to set new colorspace + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ +int dp_connector_set_colorspace(struct drm_connector *connector, + void *display); + /** * dp_connector_post_init - callback to perform additional initialization steps * @connector: Pointer to drm connector structure diff --git a/msm/dp/dp_link.c b/msm/dp/dp_link.c index b8980c40fd74..eb2f872597d2 100644 --- a/msm/dp/dp_link.c +++ b/msm/dp/dp_link.c @@ -1352,7 +1352,7 @@ static int dp_link_get_colorimetry_config(struct dp_link *dp_link) /* Only RGB_VESA nd RGB_CEA supported for now */ switch (dr) { case DP_DYNAMIC_RANGE_RGB_CEA: - cc = BIT(3); + cc = BIT(2); break; case DP_DYNAMIC_RANGE_RGB_VESA: default: diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index a0757a5db540..65a036230e21 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -189,6 +189,98 @@ struct tu_algo_data { s64 ratio; }; +/** + * Mapper function which outputs colorimetry and dynamic range + * to be used for a given colorspace value when the vsc sdp + * packets are used to change the colorimetry. + */ +static void get_sdp_colorimetry_range(struct dp_panel_private *panel, + u32 colorspace, u32 *colorimetry, u32 *dynamic_range) +{ + + u32 cc; + + /* + * Some rules being used for assignment of dynamic + * range for colorimetry using SDP: + * + * 1) If compliance test is ongoing return sRGB with + * CEA primaries + * 2) For BT2020 cases, dynamic range shall be CEA + * 3) For DCI-P3 cases, as per HW team dynamic range + * shall be VESA for RGB and CEA for YUV content + * Hence defaulting to RGB and picking VESA + * 4) Default shall be sRGB with VESA + */ + + cc = panel->link->get_colorimetry_config(panel->link); + + if (cc) { + *colorimetry = sRGB; + *dynamic_range = CEA; + return; + } + + switch (colorspace) { + case DRM_MODE_COLORIMETRY_BT2020_RGB: + *colorimetry = ITU_R_BT_2020_RGB; + *dynamic_range = CEA; + break; + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + *colorimetry = DCI_P3; + *dynamic_range = VESA; + break; + default: + *colorimetry = sRGB; + *dynamic_range = VESA; + } +} + +/** + * Mapper function which outputs colorimetry to be used for a + * given colorspace value when misc field of MSA is used to + * change the colorimetry. Currently only RGB formats have been + * added. This API will be extended to YUV once its supported on DP. + */ +static u8 get_misc_colorimetry_val(struct dp_panel_private *panel, + u32 colorspace) +{ + u8 colorimetry; + u32 cc; + + cc = panel->link->get_colorimetry_config(panel->link); + /* + * If there is a non-zero value then compliance test-case + * is going on, otherwise we can honor the colorspace setting + */ + if (cc) + return cc; + + switch (colorspace) { + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + colorimetry = 0x7; + break; + case DRM_MODE_DP_COLORIMETRY_SRGB: + colorimetry = 0x4; + break; + case DRM_MODE_DP_COLORIMETRY_RGB_WIDE_GAMUT: + colorimetry = 0x3; + break; + case DRM_MODE_DP_COLORIMETRY_SCRGB: + colorimetry = 0xb; + break; + case DRM_MODE_COLORIMETRY_OPRGB: + colorimetry = 0xc; + break; + default: + colorimetry = 0; + } + + return colorimetry; +} + static int _tu_param_compare(s64 a, s64 b) { u32 a_int, a_frac, a_sign; @@ -2482,6 +2574,7 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) struct dp_panel_private *panel; struct drm_msm_ext_hdr_metadata *hdr_meta; struct dp_sdp_header *dhdr_vsif_sdp; + struct sde_connector *sde_conn; struct dp_sdp_header *shdr_if_sdp; struct dp_catalog_vsc_sdp_colorimetry *vsc_colorimetry; struct drm_connector *connector; @@ -2517,6 +2610,7 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) panel->panel_on = false; connector = dp_panel->connector; + sde_conn = to_sde_connector(connector); c_state = to_sde_connector_state(connector->state); connector->hdr_eotf = 0; @@ -2527,6 +2621,8 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) connector->hdr_supported = false; connector->hdr_plus_app_ver = 0; + sde_conn->colorspace_updated = false; + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta)); @@ -2657,11 +2753,14 @@ static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel, return calc_pkt_limit; } -static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel) +static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel, + u32 cspace) { struct dp_panel_private *panel; struct dp_catalog_vsc_sdp_colorimetry *hdr_colorimetry; u8 bpc; + u32 colorimetry = 0; + u32 dynamic_range = 0; panel = container_of(dp_panel, struct dp_panel_private, dp_panel); hdr_colorimetry = &panel->catalog->vsc_colorimetry; @@ -2671,11 +2770,14 @@ static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel) hdr_colorimetry->header.HB2 = 0x05; hdr_colorimetry->header.HB3 = 0x13; + get_sdp_colorimetry_range(panel, cspace, &colorimetry, + &dynamic_range); + /* VSC SDP Payload for DB16 */ - hdr_colorimetry->data[16] = (RGB << 4) | ITU_R_BT_2020_RGB; + hdr_colorimetry->data[16] = (RGB << 4) | colorimetry; /* VSC SDP Payload for DB17 */ - hdr_colorimetry->data[17] = (CEA << 7); + hdr_colorimetry->data[17] = (dynamic_range << 7); bpc = (dp_panel->pinfo.bpp / 3); switch (bpc) { @@ -2719,9 +2821,60 @@ static void dp_panel_setup_dhdr_vsif(struct dp_panel_private *panel) dhdr_vsif->HB3 = 0x13 << 2; } +static void dp_panel_setup_misc_colorimetry(struct dp_panel *dp_panel, + u32 colorspace) +{ + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + + catalog->misc_val &= ~0x1e; + + catalog->misc_val |= (get_misc_colorimetry_val(panel, + colorspace) << 1); +} + +static int dp_panel_set_colorspace(struct dp_panel *dp_panel, + u32 colorspace) +{ + int rc = 0; + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->vsc_supported) + dp_panel_setup_colorimetry_sdp(dp_panel, + colorspace); + else + dp_panel_setup_misc_colorimetry(dp_panel, + colorspace); + + /* + * During the first frame update panel_on will be false and + * the colorspace will be cached in the connector's state which + * shall be used in the dp_panel_hw_cfg + */ + if (panel->panel_on) { + DP_DEBUG("panel is ON programming colorspace\n"); + rc = panel->catalog->set_colorspace(panel->catalog, + panel->vsc_supported); + } + +end: + return rc; +} + static int dp_panel_setup_hdr(struct dp_panel *dp_panel, struct drm_msm_ext_hdr_metadata *hdr_meta, - bool dhdr_update, u64 core_clk_rate) + bool dhdr_update, u64 core_clk_rate, bool flush) { int rc = 0, max_pkts = 0; struct dp_panel_private *panel; @@ -2748,8 +2901,6 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel, panel->hdr_state = hdr_meta->hdr_state; - dp_panel_setup_colorimetry_sdp(dp_panel); - dp_panel_setup_hdr_if(panel); if (panel->hdr_state) { @@ -2777,7 +2928,7 @@ cached: if (panel->panel_on) { panel->catalog->stream_id = dp_panel->stream_id; panel->catalog->config_hdr(panel->catalog, panel->hdr_state, - max_pkts); + max_pkts, flush); if (dhdr_update) panel->catalog->dhdr_flush(panel->catalog); } @@ -2856,19 +3007,29 @@ static void dp_panel_config_misc(struct dp_panel *dp_panel) { struct dp_panel_private *panel; struct dp_catalog_panel *catalog; + struct drm_connector *connector; u32 misc_val; - u32 tb, cc; + u32 tb, cc, colorspace; panel = container_of(dp_panel, struct dp_panel_private, dp_panel); catalog = panel->catalog; + connector = dp_panel->connector; + cc = 0; tb = panel->link->get_test_bits_depth(panel->link, dp_panel->pinfo.bpp); - cc = panel->link->get_colorimetry_config(panel->link); + colorspace = connector->state->colorspace; + + + cc = (get_misc_colorimetry_val(panel, colorspace) << 1); misc_val = cc; misc_val |= (tb << 5); misc_val |= BIT(0); /* Configure clock to synchronous mode */ + /* if VSC is supported then set bit 6 of MISC1 */ + if (panel->vsc_supported) + misc_val |= BIT(14); + catalog->misc_val = misc_val; catalog->config_misc(catalog); } @@ -2910,9 +3071,21 @@ static void dp_panel_resolution_info(struct dp_panel_private *panel) panel->link->link_params.lane_count); } +static void dp_panel_config_sdp(struct dp_panel *dp_panel, + bool en) +{ + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel->catalog->stream_id = dp_panel->stream_id; + + panel->catalog->config_sdp(panel->catalog, en); +} + static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable) { struct dp_panel_private *panel; + struct drm_connector *connector; if (!dp_panel) { DP_ERR("invalid input\n"); @@ -2926,15 +3099,23 @@ static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable) panel = container_of(dp_panel, struct dp_panel_private, dp_panel); panel->catalog->stream_id = dp_panel->stream_id; + connector = dp_panel->connector; if (enable) { dp_panel_config_ctrl(dp_panel); dp_panel_config_misc(dp_panel); dp_panel_config_msa(dp_panel); + if (panel->vsc_supported) { + dp_panel_setup_colorimetry_sdp(dp_panel, + connector->state->colorspace); + dp_panel_config_sdp(dp_panel, true); + } dp_panel_config_dsc(dp_panel, enable); dp_panel_config_tr_unit(dp_panel); dp_panel_config_timing(dp_panel); dp_panel_resolution_info(panel); + } else { + dp_panel_config_sdp(dp_panel, false); } panel->catalog->config_dto(panel->catalog, !enable); @@ -3148,6 +3329,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->tpg_config = dp_panel_tpg_config; dp_panel->spd_config = dp_panel_spd_config; dp_panel->setup_hdr = dp_panel_setup_hdr; + dp_panel->set_colorspace = dp_panel_set_colorspace; dp_panel->hdr_supported = dp_panel_hdr_supported; dp_panel->set_stream_info = dp_panel_set_stream_info; dp_panel->read_sink_status = dp_panel_read_sink_sts; diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index dc96090ba5c5..9738de259d9c 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -148,7 +148,9 @@ struct dp_panel { int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd); int (*setup_hdr)(struct dp_panel *dp_panel, struct drm_msm_ext_hdr_metadata *hdr_meta, - bool dhdr_update, u64 core_clk_rate); + bool dhdr_update, u64 core_clk_rate, bool flush); + int (*set_colorspace)(struct dp_panel *dp_panel, + u32 colorspace); void (*tpg_config)(struct dp_panel *dp_panel, bool enable); int (*spd_config)(struct dp_panel *dp_panel); bool (*hdr_supported)(struct dp_panel *dp_panel); diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 99550b67a61b..7ba7c93f03eb 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -606,6 +606,19 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) return rc; } +void sde_connector_set_colorspace(struct sde_connector *c_conn) +{ + int rc = 0; + + if (c_conn->ops.set_colorspace) + rc = c_conn->ops.set_colorspace(&c_conn->base, + c_conn->display); + + if (rc) + SDE_ERROR_CONN(c_conn, "cannot apply new colorspace %d\n", rc); + +} + void sde_connector_set_qsync_params(struct drm_connector *connector) { struct sde_connector *c_conn = to_sde_connector(connector); @@ -680,6 +693,12 @@ static int _sde_connector_update_dirty_properties( } } + /* if colorspace needs to be updated do it first */ + if (c_conn->colorspace_updated) { + c_conn->colorspace_updated = false; + sde_connector_set_colorspace(c_conn); + } + /* * Special handling for postproc properties and * for updating backlight if any unset backlight level is present @@ -2134,6 +2153,7 @@ static const struct drm_connector_helper_funcs sde_connector_helper_ops = { .get_modes = sde_connector_get_modes, .mode_valid = sde_connector_mode_valid, .best_encoder = sde_connector_best_encoder, + .atomic_check = sde_connector_atomic_check, }; static const struct drm_connector_helper_funcs sde_connector_helper_ops_v2 = { @@ -2311,6 +2331,7 @@ static int _sde_connector_install_properties(struct drm_device *dev, { struct dsi_display *dsi_display; int rc; + struct drm_connector *connector; msm_property_install_blob(&c_conn->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); @@ -2323,6 +2344,8 @@ static int _sde_connector_install_properties(struct drm_device *dev, return rc; } + connector = &c_conn->base; + msm_property_install_blob(&c_conn->property_info, "mode_properties", DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_MODE_INFO); @@ -2366,6 +2389,11 @@ static int _sde_connector_install_properties(struct drm_device *dev, &hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO); + + /* create and attach colorspace property for DP */ + if (!drm_mode_create_colorspace_property(connector)) + drm_object_attach_property(&connector->base, + connector->colorspace_property, 0); } msm_property_install_volatile_range(&c_conn->property_info, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 08386421e7af..117cc236ebca 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -168,6 +168,14 @@ struct sde_connector_ops { int (*set_backlight)(struct drm_connector *connector, void *display, u32 bl_lvl); + /** + * set_colorspace - set colorspace for connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + */ + int (*set_colorspace)(struct drm_connector *connector, + void *display); + /** * soft_reset - perform a soft reset on the connector * @display: Pointer to private display structure @@ -400,6 +408,7 @@ struct sde_connector_dyn_hdr_metadata { * @allow_bl_update: Flag to indicate if BL update is allowed currently or not * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode * @qsync_updated: Qsync settings were updated + * @colorspace_updated: Colorspace property was updated * last_cmd_tx_sts: status of the last command transfer * @hdr_capable: external hdr support present * @core_clk_rate: MDP core clk rate used for dynamic HDR packet calculation @@ -452,6 +461,8 @@ struct sde_connector { u32 qsync_mode; bool qsync_updated; + bool colorspace_updated; + bool last_cmd_tx_sts; bool hdr_capable; }; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index cddf8220a363..ff10e8fe8003 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1222,11 +1222,13 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .post_init = dp_connector_post_init, .detect = dp_connector_detect, .get_modes = dp_connector_get_modes, + .atomic_check = dp_connector_atomic_check, .mode_valid = dp_connector_mode_valid, .get_info = dp_connector_get_info, .get_mode_info = dp_connector_get_mode_info, .post_open = dp_connector_post_open, .check_status = NULL, + .set_colorspace = dp_connector_set_colorspace, .config_hdr = dp_connector_config_hdr, .cmd_transfer = NULL, .cont_splash_config = NULL,