diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index 07ce6eac79..cf3f89005f 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" @@ -478,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) { @@ -496,11 +518,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 +532,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 +540,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 +563,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 +575,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 +589,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 +597,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 +608,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 +685,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 +705,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 +715,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 +723,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 +755,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); @@ -775,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; @@ -803,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; } @@ -826,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_data.hdr_meta.eotf) + 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); @@ -862,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( @@ -1109,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) { @@ -2494,7 +2575,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 @@ -2567,7 +2647,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, @@ -2584,10 +2663,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) @@ -2745,9 +2821,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 d1bf8760bf..a1235b5294 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; @@ -222,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 8fa0dc81fd..c8720f23f1 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) @@ -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); @@ -2082,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"); @@ -2092,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) { @@ -2099,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) @@ -2623,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 8b5f730bcd..6091c70917 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 b1adf28707..7439338aaa 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 13c1a059b3..0056857ff7 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 b8980c40fd..eb2f872597 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 9ce7266a7c..8d8d6bf2bc 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; @@ -2485,7 +2577,11 @@ 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 sde_connector *sde_conn; + 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; @@ -2500,17 +2596,26 @@ 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; + sde_conn = to_sde_connector(connector); c_state = to_sde_connector_state(connector->state); connector->hdr_eotf = 0; @@ -2521,6 +2626,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)); @@ -2651,14 +2758,133 @@ 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, + 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; + + hdr_colorimetry->header.HB0 = 0x00; + hdr_colorimetry->header.HB1 = 0x07; + 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) | colorimetry; + + /* VSC SDP Payload for DB17 */ + hdr_colorimetry->data[17] = (dynamic_range << 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 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; - 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"); @@ -2667,11 +2893,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; @@ -2679,41 +2906,18 @@ 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_hdr_if(panel); - hdr->shdr_header_byte0 = 0x00; - hdr->shdr_header_byte1 = 0x87; - hdr->shdr_header_byte2 = 0x1D; - hdr->shdr_header_byte3 = 0x13 << 2; - - /* 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; @@ -2729,7 +2933,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); } @@ -2808,19 +3012,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); } @@ -2862,9 +3076,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"); @@ -2878,15 +3104,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); @@ -3100,6 +3334,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 5b7fb9a582..649e588370 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -150,7 +150,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/msm_drv.h b/msm/msm_drv.h index 264c69f001..a99a64a8da 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 ed477f2233..c45dc8ca52 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 @@ -1480,6 +1499,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) { @@ -1920,6 +1953,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; } @@ -2118,6 +2154,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 = { @@ -2295,6 +2332,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); @@ -2307,6 +2345,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); @@ -2350,6 +2390,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, @@ -2389,6 +2434,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, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 08386421e7..117cc236eb 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 88984b6f4a..b244245c14 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,