diff --git a/include/uapi/display/drm/sde_drm.h b/include/uapi/display/drm/sde_drm.h index a6f31b54b8..81dce23242 100644 --- a/include/uapi/display/drm/sde_drm.h +++ b/include/uapi/display/drm/sde_drm.h @@ -453,6 +453,9 @@ struct sde_drm_color { /* Color fill outside of the rect, excluding border */ #define SDE_DRM_DIM_LAYER_EXCLUSIVE 0x2 + /* bitmask for allowed_dsc_reservation_switch property */ +#define SDE_DP_DSC_RESERVATION_SWITCH (1 << 0) + /** * struct sde_drm_dim_layer - dim layer cfg struct * @flags: Refer SDE_DRM_DIM_LAYER_CONFIG_FLAG for possible values diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index c6e1455193..327814b15d 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6447,6 +6447,16 @@ struct drm_panel *dsi_display_get_drm_panel(struct dsi_display *display) return &display->panel->drm_panel; } +bool dsi_display_has_dsc_switch_support(struct dsi_display *display) +{ + if (!display || !display->panel) { + pr_err("invalid param(s)\n"); + return false; + } + + return display->panel->dsc_switch_supported; +} + int dsi_display_drm_ext_bridge_init(struct dsi_display *display, struct drm_encoder *encoder, struct drm_connector *connector) { @@ -6846,6 +6856,7 @@ int dsi_display_get_modes(struct dsi_display *display, u32 sublinks_count, mode_idx, array_idx = 0; struct dsi_dyn_clk_caps *dyn_clk_caps; int i, start, end, rc = -EINVAL; + int dsc_modes = 0, nondsc_modes = 0; if (!display || !out_modes) { DSI_ERR("Invalid params\n"); @@ -6910,6 +6921,11 @@ int dsi_display_get_modes(struct dsi_display *display, support_cmd_mode = display_mode.panel_mode_caps & DSI_OP_CMD_MODE; support_video_mode = display_mode.panel_mode_caps & DSI_OP_VIDEO_MODE; + if (display_mode.priv_info->dsc_enabled) + dsc_modes++; + else + nondsc_modes++; + /* Setup widebus support */ display_mode.priv_info->widebus_support = ctrl->ctrl->hw.widebus_support; @@ -6987,6 +7003,9 @@ int dsi_display_get_modes(struct dsi_display *display, } } + if (dsc_modes && nondsc_modes) + display->panel->dsc_switch_supported = true; + exit: *out_modes = display->modes; rc = 0; diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 86a51412a1..e9445945c2 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -648,6 +648,14 @@ int dsi_dispaly_static_frame(struct dsi_display *display, bool enable); */ struct drm_panel *dsi_display_get_drm_panel(struct dsi_display *display); +/** + * dsi_display_has_dsc_switch_support() - check if dsc switch is supported. + * @display: Handle to display. + * + * Return: True of panel supports both dsc and non-dsc modes. + */ +bool dsi_display_has_dsc_switch_support(struct dsi_display *display); + /** * dsi_display_enable_event() - enable interrupt based connector event * @connector: Pointer to drm connector structure diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 5ce3c9da25..191cc2ac8a 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -3025,6 +3025,14 @@ static int dsi_panel_parse_topology( goto parse_fail; } + if (!(priv_info->dsc_enabled || priv_info->vdc_enabled) != + !topology[top_sel].num_enc) { + DSI_ERR("topology and compression info mismatch dsc:%d vdc:%d num_enc:%d\n", + priv_info->dsc_enabled, priv_info->vdc_enabled, + topology[top_sel].num_enc); + goto parse_fail; + } + if (priv_info->dsc_enabled) topology[top_sel].comp_type = MSM_DISPLAY_COMPRESSION_DSC; else if (priv_info->vdc_enabled) diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 4a88b4fa0e..e4407b6008 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -228,6 +228,7 @@ struct dsi_panel { struct dsi_dfps_capabilities dfps_caps; struct dsi_dyn_clk_caps dyn_clk_caps; struct dsi_panel_phy_props phy_props; + bool dsc_switch_supported; struct dsi_display_mode *cur_mode; u32 num_timing_nodes; diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index d6cfa940e9..1c96bc248f 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -411,6 +411,7 @@ static void sde_connector_get_avail_res_info(struct drm_connector *conn, { struct sde_kms *sde_kms; struct drm_encoder *drm_enc = NULL; + struct sde_connector *sde_conn; sde_kms = _sde_connector_get_kms(conn); if (!sde_kms) { @@ -418,12 +419,17 @@ static void sde_connector_get_avail_res_info(struct drm_connector *conn, return; } + sde_conn = to_sde_connector(conn); if (conn->state && conn->state->best_encoder) drm_enc = conn->state->best_encoder; else drm_enc = conn->encoder; sde_rm_get_resource_info(&sde_kms->rm, drm_enc, avail_res); + if ((sde_kms->catalog->allowed_dsc_reservation_switch & + SDE_DP_DSC_RESERVATION_SWITCH) && + sde_conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + avail_res->num_dsc = sde_kms->catalog->dsc_count; avail_res->max_mixer_width = sde_kms->catalog->max_mixer_width; } diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index ca0bf301a0..01fc75b88e 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -5628,6 +5628,10 @@ static void sde_crtc_setup_capabilities_blob(struct sde_kms_info *info, sde_kms_info_add_keyint(info, "skip_inline_rot_threshold", catalog->skip_inline_rot_threshold); + if (catalog->allowed_dsc_reservation_switch) + sde_kms_info_add_keyint(info, "allowed_dsc_reservation_switch", + catalog->allowed_dsc_reservation_switch); + if (catalog->uidle_cfg.uidle_rev) sde_kms_info_add_keyint(info, "has_uidle", true); @@ -5816,6 +5820,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, catalog->demura_count); } + sde_kms_info_add_keyint(info, "dsc_block_count", catalog->dsc_count); + msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); @@ -7137,6 +7143,11 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) return ERR_PTR(rc); } + if (kms->catalog->allowed_dsc_reservation_switch && !kms->dsc_switch_support) { + SDE_DEBUG("dsc switch not supported\n"); + kms->catalog->allowed_dsc_reservation_switch = 0; + } + /* create CRTC properties */ msm_property_init(&sde_crtc->property_info, &crtc->base, dev, priv->crtc_property, sde_crtc->property_data, diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index a41a9cbcd5..aaf5ad43fa 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1500,6 +1500,7 @@ struct sde_perf_cfg { * @ubwc_bw_calc_version indicate how UBWC BW has to be calculated * @skip_inline_rot_thresh Skip inline rotation threshold * @has_idle_pc indicate if idle power collapse feature is supported + * @allowed_dsc_reservation_switch intf to which dsc reservation switch is supported * @wakeup_with_touch indicate early wake up display with input touch event * @has_hdr HDR feature support * @has_hdr_plus HDR10+ feature support @@ -1590,6 +1591,7 @@ struct sde_mdss_cfg { u32 ubwc_bw_calc_version; bool skip_inline_rot_threshold; bool has_idle_pc; + u32 allowed_dsc_reservation_switch; bool wakeup_with_touch; u32 vbif_qos_nlvl; u32 ts_prefill_rev; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 31fbf6c206..3fa909657f 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1932,6 +1932,9 @@ static int _sde_kms_setup_displays(struct drm_device *dev, dsc_count += info.dsc_count; mixer_count += info.lm_count; + + if (dsi_display_has_dsc_switch_support(display)) + sde_kms->dsc_switch_support = true; } max_dp_mixer_count = sde_kms->catalog->mixer_count > mixer_count ? @@ -1939,6 +1942,9 @@ static int _sde_kms_setup_displays(struct drm_device *dev, max_dp_dsc_count = sde_kms->catalog->dsc_count > dsc_count ? sde_kms->catalog->dsc_count - dsc_count : 0; + if (sde_kms->catalog->allowed_dsc_reservation_switch & + SDE_DP_DSC_RESERVATION_SWITCH) + max_dp_dsc_count = sde_kms->catalog->dsc_count; /* dp */ for (i = 0; i < sde_kms->dp_display_count && priv->num_encoders < max_encoders; ++i) { diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index 904656126a..fe78d4c727 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -294,6 +294,7 @@ struct sde_kms { int dp_display_count; void **dp_displays; int dp_stream_count; + bool dsc_switch_support; bool has_danger_ctrl;