|
@@ -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) {
|