diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 7877058537..bc21379de2 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -2012,15 +2012,18 @@ static int dp_display_set_stream_info(struct dp_display *dp_display, static void dp_display_update_dsc_resources(struct dp_display_private *dp, struct dp_panel *panel, bool enable) { + int rc; u32 dsc_blk_cnt = 0; + struct msm_drm_private *priv = dp->priv; if (panel->pinfo.comp_info.comp_type == MSM_DISPLAY_COMPRESSION_DSC && - (panel->pinfo.comp_info.comp_ratio > 1)) { - dsc_blk_cnt = panel->pinfo.h_active / - dp->parser->max_dp_dsc_input_width_pixs; - if (panel->pinfo.h_active % - dp->parser->max_dp_dsc_input_width_pixs) - dsc_blk_cnt++; + (panel->pinfo.comp_info.comp_ratio > 1)) { + rc = msm_get_dsc_count(priv, panel->pinfo.h_active, + &dsc_blk_cnt); + if (rc) { + DP_ERR("error getting dsc count. rc:%d\n", rc); + return; + } } if (enable) { @@ -2431,10 +2434,74 @@ static int dp_display_validate_mixers(struct msm_drm_private *priv, return rc; } - if (num_lm > avail_res->num_lm || - (num_lm == 2 && !avail_res->num_3dmux)) { - DP_DEBUG("num_lm:%d, req lm:%d 3dmux:%d\n", num_lm, - avail_res->num_lm, avail_res->num_3dmux); + if (num_lm > avail_res->num_lm) { + DP_DEBUG("num lm:%d > available lm:%d\n", num_lm, + avail_res->num_lm); + return -EPERM; + } + + return 0; +} + +static int dp_display_validate_dscs(struct msm_drm_private *priv, + struct dp_panel *dp_panel, struct drm_display_mode *mode, + struct dp_display_mode *dp_mode, + const struct msm_resource_caps_info *avail_res) +{ + int rc; + u32 num_dsc = 0; + bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC; + + if (!dp_panel->dsc_en || !dsc_capable) + return 0; + + rc = msm_get_dsc_count(priv, mode->hdisplay, &num_dsc); + if (rc) { + DP_ERR("error getting dsc count. rc:%d\n", rc); + return rc; + } + + if (num_dsc > avail_res->num_dsc) { + DP_DEBUG("num dsc:%d > available dsc:%d\n", num_dsc, + avail_res->num_dsc); + return -EPERM; + } + + return 0; +} + +static int dp_display_validate_topology(struct dp_display_private *dp, + struct dp_panel *dp_panel, struct drm_display_mode *mode, + struct dp_display_mode *dp_mode, + const struct msm_resource_caps_info *avail_res) +{ + int rc; + struct msm_drm_private *priv = dp->priv; + const u32 dual_lm = 2, quad_lm = 4; + u32 num_lm = 0, num_dsc = 0, num_3dmux = 0; + bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC; + + rc = msm_get_mixer_count(priv, mode, avail_res, &num_lm); + if (rc) { + DP_ERR("error getting mixer count. rc:%d\n", rc); + return rc; + } + + num_3dmux = avail_res->num_3dmux; + + if (dp_panel->dsc_en && dsc_capable) { + rc = msm_get_dsc_count(priv, mode->hdisplay, &num_dsc); + if (rc) { + DP_ERR("error getting dsc count. rc:%d\n", rc); + return rc; + } + } + + /* filter out unsupported DP topologies */ + if ((num_lm == dual_lm && (!num_3dmux && !num_dsc)) || + (num_lm == quad_lm && (num_dsc != 4))) { + DP_DEBUG("invalid topology lm:%d dsc:%d 3dmux:%d intf:1\n", + num_lm, num_dsc, num_3dmux); return -EPERM; } @@ -2554,6 +2621,16 @@ static enum drm_mode_status dp_display_validate_mode( if (rc) goto end; + rc = dp_display_validate_dscs(dp->priv, panel, mode, &dp_mode, + avail_res); + if (rc) + goto end; + + rc = dp_display_validate_topology(dp, dp_panel, mode, + &dp_mode, avail_res); + if (rc) + goto end; + dp_display_validate_mst_connectors(debug, dp_panel, mode, &mode_status, &use_default); if (!use_default) @@ -2568,9 +2645,40 @@ static enum drm_mode_status dp_display_validate_mode( mode_status = MODE_OK; end: mutex_unlock(&dp->session_lock); + DP_DEBUG("[%s] mode is %s\n", mode->name, + (mode_status == MODE_OK) ? "valid" : "invalid"); + return mode_status; } +static int dp_display_get_available_dp_resources(struct dp_display *dp_display, + const struct msm_resource_caps_info *avail_res, + struct msm_resource_caps_info *max_dp_avail_res) +{ + if (!dp_display || !avail_res || !max_dp_avail_res) { + DP_ERR("invalid arguments\n"); + return -EINVAL; + } + + memcpy(max_dp_avail_res, avail_res, + sizeof(struct msm_resource_caps_info)); + + max_dp_avail_res->num_lm = min(avail_res->num_lm, + dp_display->max_mixer_count); + max_dp_avail_res->num_dsc = min(avail_res->num_dsc, + dp_display->max_dsc_count); + + DP_DEBUG("max_lm:%d, avail_lm:%d, dp_avail_lm:%d\n", + dp_display->max_mixer_count, avail_res->num_lm, + max_dp_avail_res->num_lm); + + DP_DEBUG("max_dsc:%d, avail_dsc:%d, dp_avail_dsc:%d\n", + dp_display->max_dsc_count, avail_res->num_dsc, + max_dp_avail_res->num_dsc); + + return 0; +} + static int dp_display_get_modes(struct dp_display *dp, void *panel, struct dp_display_mode *dp_mode) { @@ -2602,6 +2710,7 @@ static void dp_display_convert_to_dp_mode(struct dp_display *dp_display, const struct drm_display_mode *drm_mode, struct dp_display_mode *dp_mode) { + int rc; struct dp_display_private *dp; struct dp_panel *dp_panel; u32 free_dsc_blks = 0, required_dsc_blks = 0; @@ -2616,22 +2725,26 @@ static void dp_display_convert_to_dp_mode(struct dp_display *dp_display, memset(dp_mode, 0, sizeof(*dp_mode)); - free_dsc_blks = dp->parser->max_dp_dsc_blks - + free_dsc_blks = dp_display->max_dsc_count - dp->tot_dsc_blks_in_use + dp_panel->tot_dsc_blks_in_use; - required_dsc_blks = drm_mode->hdisplay / - dp->parser->max_dp_dsc_input_width_pixs; - if (drm_mode->hdisplay % dp->parser->max_dp_dsc_input_width_pixs) - required_dsc_blks++; + + rc = msm_get_dsc_count(dp->priv, drm_mode->hdisplay, + &required_dsc_blks); + if (rc) { + DP_ERR("error getting dsc count. rc:%d\n", rc); + return; + } if (free_dsc_blks >= required_dsc_blks) dp_mode->capabilities |= DP_PANEL_CAPS_DSC; if (dp_mode->capabilities & DP_PANEL_CAPS_DSC) - DP_DEBUG("in_use:%d, max:%d, free:%d, req:%d, caps:0x%x, width:%d\n", - dp->tot_dsc_blks_in_use, dp->parser->max_dp_dsc_blks, - free_dsc_blks, required_dsc_blks, dp_mode->capabilities, - dp->parser->max_dp_dsc_input_width_pixs); + DP_DEBUG("in_use:%d, max:%d, free:%d, req:%d, caps:0x%x\n", + dp->tot_dsc_blks_in_use, + dp_display->max_dsc_count, + free_dsc_blks, required_dsc_blks, + dp_mode->capabilities); dp_panel->convert_to_dp_mode(dp_panel, drm_mode, dp_mode); } @@ -3231,6 +3344,8 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->wakeup_phy_layer = dp_display_wakeup_phy_layer; g_dp_display->set_colorspace = dp_display_setup_colospace; + g_dp_display->get_available_dp_resources = + dp_display_get_available_dp_resources; 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 5bb2a74ad4..0ea71cc80f 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -127,6 +127,9 @@ struct dp_display { struct drm_connector *connector, char *pps_cmd); void (*wakeup_phy_layer)(struct dp_display *dp_display, bool wakeup); + int (*get_available_dp_resources)(struct dp_display *dp_display, + const struct msm_resource_caps_info *avail_res, + struct msm_resource_caps_info *max_dp_avail_res); }; #if IS_ENABLED(CONFIG_DRM_MSM_DP) diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index dd9b80fd76..43bd72ad68 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -383,6 +383,7 @@ int dp_connector_get_mode_info(struct drm_connector *connector, struct dp_display_mode dp_mode; struct dp_display *dp_disp = display; struct msm_drm_private *priv; + struct msm_resource_caps_info avail_dp_res; int rc = 0; if (!drm_mode || !mode_info || !avail_res || @@ -400,7 +401,14 @@ int dp_connector_get_mode_info(struct drm_connector *connector, topology = &mode_info->topology; - rc = msm_get_mixer_count(priv, drm_mode, avail_res, + rc = dp_disp->get_available_dp_resources(dp_disp, avail_res, + &avail_dp_res); + if (rc) { + DP_ERR("error getting max dp resources. rc:%d\n", rc); + return rc; + } + + rc = msm_get_mixer_count(priv, drm_mode, &avail_dp_res, &topology->num_lm); if (rc) { DP_ERR("error getting mixer count. rc:%d\n", rc); @@ -644,8 +652,10 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode, void *display, const struct msm_resource_caps_info *avail_res) { + int rc = 0; struct dp_display *dp_disp; struct sde_connector *sde_conn; + struct msm_resource_caps_info avail_dp_res; if (!mode || !display || !connector) { DP_ERR("invalid params\n"); @@ -661,8 +671,15 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, dp_disp = display; mode->vrefresh = drm_mode_vrefresh(mode); + rc = dp_disp->get_available_dp_resources(dp_disp, avail_res, + &avail_dp_res); + if (rc) { + DP_ERR("error getting max dp resources. rc:%d\n", rc); + return MODE_ERROR; + } + return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel, - mode, avail_res); + mode, &avail_dp_res); } int dp_connector_update_pps(struct drm_connector *connector, diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index 21ac2562b9..dbe11c37a0 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -722,27 +722,13 @@ static int dp_parser_mst(struct dp_parser *parser) static void dp_parser_dsc(struct dp_parser *parser) { - int rc; struct device *dev = &parser->pdev->dev; parser->dsc_feature_enable = of_property_read_bool(dev->of_node, "qcom,dsc-feature-enable"); - rc = of_property_read_u32(dev->of_node, - "qcom,max-dp-dsc-blks", &parser->max_dp_dsc_blks); - if (rc || !parser->max_dp_dsc_blks) - parser->dsc_feature_enable = false; - - rc = of_property_read_u32(dev->of_node, - "qcom,max-dp-dsc-input-width-pixs", - &parser->max_dp_dsc_input_width_pixs); - if (rc || !parser->max_dp_dsc_input_width_pixs) - parser->dsc_feature_enable = false; - - DP_DEBUG("dsc parsing successful. dsc:%d, blks:%d, width:%d\n", - parser->dsc_feature_enable, - parser->max_dp_dsc_blks, - parser->max_dp_dsc_input_width_pixs); + DP_DEBUG("dsc parsing successful. dsc:%d\n", + parser->dsc_feature_enable); } static void dp_parser_fec(struct dp_parser *parser) diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index c5d0b186a5..8ba2e5dc7e 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.h @@ -195,8 +195,6 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) * @gpio_aux_switch: presence GPIO AUX switch status * @dsc_feature_enable: DSC feature enable status * @fec_feature_enable: FEC feature enable status - * @max_dp_dsc_blks: maximum DSC blks for DP interface - * @max_dp_dsc_input_width_pixs: Maximum input width for DSC block * @has_widebus: widebus (2PPC) feature eanble status *@mst_fixed_port: mst port_num reserved for fixed topology * @parse: function to be called by client to parse device tree. @@ -225,8 +223,6 @@ struct dp_parser { bool fec_feature_enable; bool has_widebus; bool gpio_aux_switch; - u32 max_dp_dsc_blks; - u32 max_dp_dsc_input_width_pixs; bool lphw_hpd; u32 mst_fixed_port[MAX_DP_MST_STREAMS]; diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 5e725f481f..3382a4f112 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1938,6 +1938,32 @@ int msm_get_mixer_count(struct msm_drm_private *priv, return funcs->get_mixer_count(priv->kms, mode, res, num_lm); } +int msm_get_dsc_count(struct msm_drm_private *priv, + u32 hdisplay, u32 *num_dsc) +{ + struct msm_kms *kms; + const struct msm_kms_funcs *funcs; + + if (!priv) { + DRM_ERROR("invalid drm private struct\n"); + return -EINVAL; + } + + kms = priv->kms; + if (!kms) { + DRM_ERROR("invalid msm kms struct\n"); + return -EINVAL; + } + + funcs = kms->funcs; + if (!funcs || !funcs->get_dsc_count) { + DRM_ERROR("invalid function pointers\n"); + return -EINVAL; + } + + return funcs->get_dsc_count(priv->kms, hdisplay, num_dsc); +} + static int msm_drm_bind(struct device *dev) { return msm_drm_component_init(dev); diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 88990df459..5dd3a2db95 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1351,6 +1351,9 @@ int msm_get_mixer_count(struct msm_drm_private *priv, const struct drm_display_mode *mode, const struct msm_resource_caps_info *res, u32 *num_lm); +int msm_get_dsc_count(struct msm_drm_private *priv, + u32 hdisplay, u32 *num_dsc); + int msm_get_src_bpc(int chroma_format, int bpc); #endif /* __MSM_DRV_H__ */ diff --git a/msm/msm_kms.h b/msm/msm_kms.h index e05349dcb6..b4b8a0d2c5 100644 --- a/msm/msm_kms.h +++ b/msm/msm_kms.h @@ -120,10 +120,13 @@ struct msm_kms_funcs { int (*cont_splash_config)(struct msm_kms *kms); /* check for continuous splash status */ bool (*check_for_splash)(struct msm_kms *kms); - /* topology information */ + /* topology lm information */ int (*get_mixer_count)(const struct msm_kms *kms, const struct drm_display_mode *mode, const struct msm_resource_caps_info *res, u32 *num_lm); + /* topology dsc information */ + int (*get_dsc_count)(const struct msm_kms *kms, + u32 hdisplay, u32 *num_dsc); }; struct msm_kms { diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 6fbebd0051..3ff265298f 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -35,7 +35,7 @@ /* max table size for dts property lists, increase if tables grow larger */ #define MAX_SDE_DT_TABLE_SIZE 64 -/* default line width for sspp, mixer, ds (input), wb */ +/* default line width for sspp, mixer, ds (input), dsc, wb */ #define DEFAULT_SDE_LINE_WIDTH 2048 /* default output line width for ds */ @@ -101,7 +101,6 @@ #define MAX_DISPLAY_HEIGHT 5760 #define MIN_DISPLAY_HEIGHT 0 #define MIN_DISPLAY_WIDTH 0 -#define MAX_LM_PER_DISPLAY 2 /* maximum XIN halt timeout in usec */ #define VBIF_XIN_HALT_TIMEOUT 0x4000 @@ -324,6 +323,7 @@ enum { DSC_CTL, DSC_CTL_LEN, DSC_422, + DSC_LINEWIDTH, DSC_PROP_MAX, }; @@ -790,7 +790,8 @@ static struct sde_prop_type dsc_prop[] = { {DSC_ENC_LEN, "qcom,sde-dsc-enc-size", false, PROP_TYPE_U32}, {DSC_CTL, "qcom,sde-dsc-ctl", false, PROP_TYPE_U32_ARRAY}, {DSC_CTL_LEN, "qcom,sde-dsc-ctl-size", false, PROP_TYPE_U32}, - {DSC_422, "qcom,sde-dsc-native422-supp", false, PROP_TYPE_U32_ARRAY} + {DSC_422, "qcom,sde-dsc-native422-supp", false, PROP_TYPE_U32_ARRAY}, + {DSC_LINEWIDTH, "qcom,sde-dsc-linewidth", false, PROP_TYPE_U32}, }; static struct sde_prop_type vdc_prop[] = { @@ -2932,6 +2933,10 @@ static int sde_dsc_parse_dt(struct device_node *np, if (rc) goto end; + sde_cfg->max_dsc_width = prop_exists[DSC_LINEWIDTH] ? + PROP_VALUE_ACCESS(prop_value, DSC_LINEWIDTH, 0) : + DEFAULT_SDE_LINE_WIDTH; + for (i = 0; i < off_count; i++) { dsc = sde_cfg->dsc + i; @@ -4734,9 +4739,6 @@ static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg, &sde_cfg->sspp[i].features); } - /* this should be updated based on HW rev in future */ - sde_cfg->max_lm_per_display = MAX_LM_PER_DISPLAY; - if (max_horz_deci) sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth * max_horz_deci; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 33f2e49d90..063e1d262f 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1362,13 +1362,14 @@ struct sde_perf_cfg { * @vig_sspp_linewidth max vig source pipe line width support. * @scaling_linewidth max vig source pipe linewidth for scaling usecases * @max_mixer_width max layer mixer line width support. + * @max_dsc_width max dsc line width support. * @max_mixer_blendstages max layer mixer blend stages or * supported z order * @max_wb_linewidth max writeback line width support. * @max_wb_linewidth_linear max writeback line width for linear formats. * @max_display_width maximum display width support. * @max_display_height maximum display height support. - * @max_lm_per_display maximum layer mixer per display + * @min_display_width minimum display width support. * @min_display_height minimum display height support. * @qseed_type qseed2 or qseed3 support. @@ -1433,6 +1434,7 @@ struct sde_mdss_cfg { u32 vig_sspp_linewidth; u32 scaling_linewidth; u32 max_mixer_width; + u32 max_dsc_width; u32 max_mixer_blendstages; u32 max_wb_linewidth; u32 max_wb_linewidth_linear; @@ -1441,7 +1443,6 @@ struct sde_mdss_cfg { u32 max_display_height; u32 min_display_width; u32 min_display_height; - u32 max_lm_per_display; u32 qseed_type; u32 csc_type; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index c1602ab3f7..e12e2449ac 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2533,6 +2533,34 @@ error: return rc; } +static int sde_kms_get_dsc_count(const struct msm_kms *kms, + u32 hdisplay, u32 *num_dsc) +{ + struct sde_kms *sde_kms; + uint32_t max_dsc_width; + + if (!num_dsc) { + SDE_ERROR("invalid num_dsc pointer\n"); + return -EINVAL; + } + + *num_dsc = 0; + if (!kms || !hdisplay) { + SDE_ERROR("invalid input args\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + max_dsc_width = sde_kms->catalog->max_dsc_width; + *num_dsc = DIV_ROUND_UP(hdisplay, max_dsc_width); + + SDE_DEBUG("h=%d, max_dsc_width=%d, num_dsc=%d\n", + hdisplay, max_dsc_width, + *num_dsc); + + return 0; +} + static void _sde_kms_null_commit(struct drm_device *dev, struct drm_encoder *enc) { @@ -2885,6 +2913,7 @@ static const struct msm_kms_funcs kms_funcs = { .postopen = _sde_kms_post_open, .check_for_splash = sde_kms_check_for_splash, .get_mixer_count = sde_kms_get_mixer_count, + .get_dsc_count = sde_kms_get_dsc_count, }; static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms)