diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index d6f25d70d5..8ec37ceffe 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 58f4e3a7f3..a1235b5294 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 68b26d4cf7..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) @@ -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 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 a0757a5db5..65a036230e 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 dc96090ba5..9738de259d 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 99550b67a6..7ba7c93f03 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 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 cddf8220a3..ff10e8fe80 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,