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

Commit 6b837d21 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

drm/msm/dp: optimize link rate selection



Currently the maximum supported link rate is selected
for any given resolution. This may result in higher
system level power consumption.

Optimize this by checking the data clock of the preferred
resolution. Calculate the minimum link rate required for
this data clock and setup the link with that rate.

In case, user-space decides to go with a different resolution
which requires a different link rate, tear down the current
link session and setup the link again with the new rate.

CRs-Fixed: 2393144d
Change-Id: I4c2f7e540416328d8ec9c2be9de07ad0537c0b94
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent f5f31790
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1161,7 +1161,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,

	ctrl->mst_mode = mst_mode;
	ctrl->fec_mode = fec_mode;
	rate = ctrl->panel->link_info.rate;
	rate = ctrl->panel->get_optimal_link_rate(ctrl->panel);

	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
		pr_debug("using phy test link parameters\n");
+9 −1
Original line number Diff line number Diff line
@@ -1310,6 +1310,7 @@ static int dp_display_set_mode(struct dp_display *dp_display, void *panel,
	const u32 num_components = 3, default_bpp = 24;
	struct dp_display_private *dp;
	struct dp_panel *dp_panel;
	u32 rc;

	if (!dp_display || !panel) {
		pr_err("invalid input\n");
@@ -1334,7 +1335,14 @@ static int dp_display_set_mode(struct dp_display *dp_display, void *panel,
			mode->timing.bpp, mode->timing.pixel_clk_khz);

	dp_panel->pinfo = mode->timing;
	dp_panel->init(dp_panel);
	rc = dp_panel->init(dp_panel);

	if (rc == -EAGAIN) {
		dp->ctrl->off(dp->ctrl);
		dp->ctrl->on(dp->ctrl, dp->mst.mst_active,
			dp->panel->fec_en, false);
	}

	mutex_unlock(&dp->session_lock);

	return 0;
+74 −15
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ struct dp_panel_private {
	u8 spd_product_description[16];
	u8 major;
	u8 minor;
	u32 bpp;
	u32 active_pclk;
	u32 optimal_link_rate;
};

static const struct dp_panel_info fail_safe = {
@@ -1764,12 +1767,50 @@ static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd)
	return 0;
}

static u32 dp_panel_get_optimal_link_rate(struct dp_panel *dp_panel)
{
	struct dp_panel_private *panel;
	u32 lrate, rate = 0;

	if (!dp_panel) {
		pr_err("invalid input\n");
		goto end;
	}

	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);

	/*
	 * As MST can support multiple streams,
	 * do not optimize the link rate for MST.
	 */
	if (panel->dp_panel.mst_state) {
		rate = panel->dp_panel.link_info.rate;
		goto end;
	}

	lrate = ((panel->active_pclk / panel->dp_panel.link_info.num_lanes) *
			panel->bpp) / 8;

	if (lrate <= DP_LINK_RATE_RBR)
		rate = DP_LINK_RATE_RBR;
	else if (lrate <= DP_LINK_RATE_HBR)
		rate = DP_LINK_RATE_HBR;
	else if (lrate <= DP_LINK_RATE_HBR2)
		rate = DP_LINK_RATE_HBR2;
	else
		rate = DP_LINK_RATE_HBR3;
end:
	panel->optimal_link_rate = rate;
	return rate;
}

static int dp_panel_read_edid(struct dp_panel *dp_panel,
	struct drm_connector *connector)
{
	int ret = 0;
	struct dp_panel_private *panel;
	struct edid *edid;
	struct drm_display_mode *mode;

	if (!dp_panel) {
		pr_err("invalid input\n");
@@ -1790,6 +1831,16 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel,
		ret = -EINVAL;
		goto end;
	}

	mutex_lock(&connector->dev->mode_config.mutex);
	_sde_edid_update_modes(connector, dp_panel->edid_ctrl);
	mutex_unlock(&connector->dev->mode_config.mutex);

	mode = list_first_entry(&connector->probed_modes,
				 struct drm_display_mode, head);

	panel->bpp = connector->display_info.bpc * 3;
	panel->active_pclk = mode->clock;
end:
	edid = dp_panel->edid_ctrl->edid;
	dp_panel->audio_supported = drm_detect_monitor_audio(edid);
@@ -2325,6 +2376,7 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
	int rc = 0;
	struct dp_panel_private *panel;
	struct dp_panel_info *pinfo;
	u32 current_link_rate;

	if (!dp_panel) {
		pr_err("invalid input\n");
@@ -2348,6 +2400,13 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
		pinfo->refresh_rate, pinfo->bpp, pinfo->pixel_clk_khz,
		panel->link->link_params.bw_code,
		panel->link->link_params.lane_count);

	panel->active_pclk = pinfo->pixel_clk_khz;
	current_link_rate = panel->optimal_link_rate;
	dp_panel_get_optimal_link_rate(dp_panel);

	if (panel->optimal_link_rate != current_link_rate)
		rc = -EAGAIN;
end:
	return rc;
}
@@ -2937,34 +2996,32 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
		goto error;
	}

	dp_panel = &panel->dp_panel;

	if (in->base_panel) {
		struct dp_panel_private *base_panel_priv =
			container_of(in->base_panel,
				struct dp_panel_private, dp_panel);

		memcpy(panel, base_panel_priv, sizeof(*panel));

		goto update;
	}

	panel->dev = in->dev;
	panel->aux = in->aux;
	panel->catalog = in->catalog;
	panel->link = in->link;
	panel->parser = in->parser;

	dp_panel = &panel->dp_panel;
	dp_panel->max_bw_code = DP_LINK_BW_8_1;
	dp_panel->spd_enabled = true;
	memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8));
	memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16));
	dp_panel->connector = in->connector;

	dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable;
	dp_panel->fec_feature_enable = panel->parser->fec_feature_enable;

	if (in->base_panel) {
		memcpy(dp_panel->dpcd, in->base_panel->dpcd,
				DP_RECEIVER_CAP_SIZE + 1);
		memcpy(&dp_panel->link_info, &in->base_panel->link_info,
				sizeof(dp_panel->link_info));
		dp_panel->mst_state = in->base_panel->mst_state;
		dp_panel->widebus_en = in->base_panel->widebus_en;
		dp_panel->fec_en = in->base_panel->fec_en;
		dp_panel->dsc_en = in->base_panel->dsc_en;
		dp_panel->fec_overhead_fp = in->base_panel->fec_overhead_fp;
	}

	dp_panel->init = dp_panel_init_panel_info;
	dp_panel->deinit = dp_panel_deinit_panel_info;
	dp_panel->hw_cfg = dp_panel_hw_cfg;
@@ -2985,7 +3042,9 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	dp_panel->read_mst_cap = dp_panel_read_mst_cap;
	dp_panel->convert_to_dp_mode = dp_panel_convert_to_dp_mode;
	dp_panel->update_pps = dp_panel_update_pps;

	dp_panel->get_optimal_link_rate = dp_panel_get_optimal_link_rate;
update:
	dp_panel->connector = in->connector;
	sde_conn = to_sde_connector(dp_panel->connector);
	sde_conn->drv_panel = dp_panel;

+6 −0
Original line number Diff line number Diff line
@@ -18,6 +18,11 @@
#define DP_RECEIVER_DSC_CAP_SIZE    15
#define DP_RECEIVER_FEC_STATUS_SIZE 3

#define DP_LINK_RATE_RBR  162000
#define DP_LINK_RATE_HBR  270000
#define DP_LINK_RATE_HBR2 540000
#define DP_LINK_RATE_HBR3 810000

/*
 * A source initiated power down flag is set
 * when the DP is powered off while physical
@@ -163,6 +168,7 @@ struct dp_panel {
		const struct drm_display_mode *drm_mode,
		struct dp_display_mode *dp_mode);
	void (*update_pps)(struct dp_panel *dp_panel, char *pps_cmd);
	u32 (*get_optimal_link_rate)(struct dp_panel *dp_panel);
};

struct dp_tu_calc_input {