Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed868466 authored by Amine Najahi's avatar Amine Najahi
Browse files

disp: msm: dp: Extend mode filtering to support 8K



Currently DP driver determines if a mode is DSC capable
based on a DTSI entry and the required number of DSC
to support it. This approach does not scale when there
is an overlap in DSC requirement between DSI displays
and external DP display, thus causing one of the display to
report modes that cannot be supported.

This change compares the resources reserved for DP driver
calculated at initialization time and the currently available
ones to determine the correct number of resources that DP driver
can use. It also adds DSC and topology filtering logic and moves
DSC hardware specific from DP driver to SDE driver.

Change-Id: I8e601de33422b7c6d786826f7bfe152c4af8a6b5
Signed-off-by: default avatarAmine Najahi <anajahi@codeaurora.org>
parent 83860f06
Loading
Loading
Loading
Loading
+134 −19
Original line number Diff line number Diff line
@@ -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++;
		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) {
+3 −0
Original line number Diff line number Diff line
@@ -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)
+19 −2
Original line number Diff line number Diff line
@@ -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,
+2 −16
Original line number Diff line number Diff line
@@ -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)
+0 −4
Original line number Diff line number Diff line
@@ -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];

Loading