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

Commit 8a44bd9e authored by Tatenda Chipeperekwa's avatar Tatenda Chipeperekwa
Browse files

drm/msm/dp: update mode validation



Use the maximum pixel clock supported on the platform as the
clock rate to validate display modes. Furthermore, once a mode
has been validated and selected, update the bits per pixel for
that mode to ensure that the mode does not exceed the maximum
allowable throughput for the chosen link configuration.

CRs-Fixed: 2119709
Change-Id: I018d4ec23436d6fac9abf9472126e0b1b70037df
Signed-off-by: default avatarTatenda Chipeperekwa <tatendac@codeaurora.org>
parent db328a8e
Loading
Loading
Loading
Loading
+35 −40
Original line number Diff line number Diff line
@@ -512,7 +512,6 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
static int dp_display_process_hpd_high(struct dp_display_private *dp)
{
	int rc = 0;
	u32 max_pclk_from_edid = 0;
	struct edid *edid;

	dp->aux->init(dp->aux, dp->parser->aux_cfg);
@@ -538,11 +537,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)

	dp->panel->handle_sink_request(dp->panel);

	max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);

	dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
		dp->parser->max_pclk_khz);

	dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz;
notify:
	dp_display_send_hpd_notification(dp, true);

@@ -909,6 +904,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
static int dp_display_set_mode(struct dp_display *dp_display,
		struct dp_display_mode *mode)
{
	const u32 num_components = 3, default_bpp = 24;
	struct dp_display_private *dp;

	if (!dp_display) {
@@ -918,6 +914,14 @@ static int dp_display_set_mode(struct dp_display *dp_display,
	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->session_lock);
	mode->timing.bpp =
		dp_display->connector->display_info.bpc * num_components;
	if (!mode->timing.bpp)
		mode->timing.bpp = default_bpp;

	mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel,
			mode->timing.bpp, mode->timing.pixel_clk_khz);

	dp->panel->pinfo = mode->timing;
	dp->panel->init_info(dp->panel);
	mutex_unlock(&dp->session_lock);
@@ -1113,52 +1117,42 @@ static int dp_display_unprepare(struct dp_display *dp)
	return 0;
}

static int dp_display_validate_mode(struct dp_display *dp,
	struct dp_display_mode *mode)
{
	return 0;
}

static int dp_display_get_modes(struct dp_display *dp,
	struct dp_display_mode *dp_mode)
static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz)
{
	const u32 num_components = 3, default_bpp = 24;
	struct dp_display_private *dp_display;
	int ret = 0;
	struct drm_dp_link *link_info;
	u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;

	if (!dp) {
	if (!dp || !mode_pclk_khz) {
		pr_err("invalid params\n");
		return 0;
		return -EINVAL;
	}

	dp_display = container_of(dp, struct dp_display_private, dp_display);
	link_info = &dp_display->panel->link_info;

	ret = dp_display->panel->get_modes(dp_display->panel,
		dp->connector, dp_mode);
	if (dp_mode->timing.pixel_clk_khz)
		dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
	return ret;
}

static bool dp_display_check_video_test(struct dp_display *dp)
{
	struct dp_display_private *dp_display;
	mode_bpp = dp->connector->display_info.bpc * num_components;
	if (!mode_bpp)
		mode_bpp = default_bpp;

	if (!dp) {
		pr_err("invalid params\n");
		return false;
	}
	mode_bpp = dp_display->panel->get_mode_bpp(dp_display->panel,
			mode_bpp, mode_pclk_khz);

	dp_display = container_of(dp, struct dp_display_private, dp_display);
	mode_rate_khz = mode_pclk_khz * mode_bpp;
	supported_rate_khz = link_info->num_lanes * link_info->rate * 8;

	if (dp_display->panel->video_test)
		return true;
	if (mode_rate_khz > supported_rate_khz)
		return MODE_BAD;

	return false;
	return MODE_OK;
}

static int dp_display_get_test_bpp(struct dp_display *dp)
static int dp_display_get_modes(struct dp_display *dp,
	struct dp_display_mode *dp_mode)
{
	struct dp_display_private *dp_display;
	int ret = 0;

	if (!dp) {
		pr_err("invalid params\n");
@@ -1167,8 +1161,11 @@ static int dp_display_get_test_bpp(struct dp_display *dp)

	dp_display = container_of(dp, struct dp_display_private, dp_display);

	return dp_link_bit_depth_to_bpp(
		dp_display->link->test_video.test_bit_depth);
	ret = dp_display->panel->get_modes(dp_display->panel,
		dp->connector, dp_mode);
	if (dp_mode->timing.pixel_clk_khz)
		dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
	return ret;
}

static int dp_display_probe(struct platform_device *pdev)
@@ -1212,8 +1209,6 @@ static int dp_display_probe(struct platform_device *pdev)
	g_dp_display->request_irq   = dp_request_irq;
	g_dp_display->get_debug     = dp_get_debug;
	g_dp_display->send_hpd_event    = dp_display_send_hpd_event;
	g_dp_display->is_video_test = dp_display_check_video_test;
	g_dp_display->get_test_bpp = dp_display_get_test_bpp;

	rc = component_add(&pdev->dev, &dp_display_comp_ops);
	if (rc) {
+1 −4
Original line number Diff line number Diff line
@@ -34,8 +34,7 @@ struct dp_display {

	int (*set_mode)(struct dp_display *dp_display,
			struct dp_display_mode *mode);
	int (*validate_mode)(struct dp_display *dp_display,
			struct dp_display_mode *mode);
	int (*validate_mode)(struct dp_display *dp_display, u32 mode_pclk_khz);
	int (*get_modes)(struct dp_display *dp_display,
		struct dp_display_mode *dp_mode);
	int (*prepare)(struct dp_display *dp_display);
@@ -43,8 +42,6 @@ struct dp_display {
	int (*request_irq)(struct dp_display *dp_display);
	struct dp_debug *(*get_debug)(struct dp_display *dp_display);
	void (*send_hpd_event)(struct dp_display *dp_display);
	bool (*is_video_test)(struct dp_display *dp_display);
	int (*get_test_bpp)(struct dp_display *dp_display);
};

int dp_display_get_num_of_displays(void);
+2 −21
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@
static void convert_to_dp_mode(const struct drm_display_mode *drm_mode,
			struct dp_display_mode *dp_mode, struct dp_display *dp)
{
	const u32 num_components = 3;

	memset(dp_mode, 0, sizeof(*dp_mode));

	dp_mode->timing.h_active = drm_mode->hdisplay;
@@ -49,15 +47,6 @@ static void convert_to_dp_mode(const struct drm_display_mode *drm_mode,
	dp_mode->timing.v_front_porch = drm_mode->vsync_start -
					 drm_mode->vdisplay;

	if (dp->is_video_test(dp))
		dp_mode->timing.bpp = dp->get_test_bpp(dp);
	else
		dp_mode->timing.bpp = dp->connector->display_info.bpc *
		num_components;

	if (!dp_mode->timing.bpp)
		dp_mode->timing.bpp = 24;

	dp_mode->timing.refresh_rate = drm_mode->vrefresh;

	dp_mode->timing.pixel_clk_khz = drm_mode->clock;
@@ -254,7 +243,6 @@ static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
				  const struct drm_display_mode *mode,
				  struct drm_display_mode *adjusted_mode)
{
	int rc = 0;
	bool ret = true;
	struct dp_display_mode dp_mode;
	struct dp_bridge *bridge;
@@ -270,14 +258,7 @@ static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
	dp = bridge->display;

	convert_to_dp_mode(mode, &dp_mode, dp);

	rc = dp->validate_mode(dp, &dp_mode);
	if (rc) {
		pr_err("[%d] mode is not valid, rc=%d\n", bridge->id, rc);
		ret = false;
	} else {
	convert_to_drm_mode(&dp_mode, adjusted_mode);
	}
end:
	return ret;
}
@@ -528,5 +509,5 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
			mode->picture_aspect_ratio != debug->aspect_ratio))
		return MODE_BAD;

	return MODE_OK;
	return dp_disp->validate_mode(dp_disp, mode->clock);
}
+34 −21
Original line number Diff line number Diff line
@@ -204,32 +204,48 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
	return 0;
}

static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel)
static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
		u32 mode_edid_bpp, u32 mode_pclk_khz)
{
	struct drm_dp_link *link_info;
	const u8 num_components = 3;
	u32 bpc = 0, bpp = 0, max_data_rate_khz = 0, max_pclk_rate_khz = 0;
	const u32 max_supported_bpp = 30, min_supported_bpp = 18;
	u32 bpp = 0, data_rate_khz = 0;

	if (!dp_panel) {
		pr_err("invalid input\n");
		return 0;
	}
	bpp = min_t(u32, mode_edid_bpp, max_supported_bpp);

	link_info = &dp_panel->link_info;
	data_rate_khz = link_info->num_lanes * link_info->rate * 8;

	bpc = sde_get_sink_bpc(dp_panel->edid_ctrl);
	bpp = bpc * num_components;
	if (!bpp)
		bpp = DP_PANEL_DEFAULT_BPP;
	while (bpp > min_supported_bpp) {
		if (mode_pclk_khz * bpp <= data_rate_khz)
			break;
		bpp -= 6;
	}

	max_data_rate_khz = (link_info->num_lanes * link_info->rate * 8);
	max_pclk_rate_khz = max_data_rate_khz / bpp;
	return bpp;
}

	pr_debug("bpp=%d, max_lane_cnt=%d\n", bpp, link_info->num_lanes);
	pr_debug("max_data_rate=%dKHz, max_pclk_rate=%dKHz\n",
		max_data_rate_khz, max_pclk_rate_khz);
static u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel,
		u32 mode_edid_bpp, u32 mode_pclk_khz)
{
	struct dp_panel_private *panel;
	u32 bpp = mode_edid_bpp;

	return max_pclk_rate_khz;
	if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) {
		pr_err("invalid input\n");
		return 0;
	}

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

	if (dp_panel->video_test)
		bpp = dp_link_bit_depth_to_bpp(
				panel->link->test_video.test_bit_depth);
	else
		bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp,
				mode_pclk_khz);

	return bpp;
}

static void dp_panel_set_test_mode(struct dp_panel_private *panel,
@@ -445,9 +461,6 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
	pr_info("bpp = %d\n", pinfo->bpp);
	pr_info("active low (h|v)=(%d|%d)\n", pinfo->h_active_low,
		pinfo->v_active_low);

	pinfo->bpp = max_t(u32, 18, min_t(u32, pinfo->bpp, 30));
	pr_info("updated bpp = %d\n", pinfo->bpp);
end:
	return rc;
}
@@ -511,7 +524,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	dp_panel->timing_cfg = dp_panel_timing_cfg;
	dp_panel->read_sink_caps = dp_panel_read_sink_caps;
	dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate;
	dp_panel->get_max_pclk = dp_panel_get_max_pclk;
	dp_panel->get_mode_bpp = dp_panel_get_mode_bpp;
	dp_panel->get_modes = dp_panel_get_modes;
	dp_panel->handle_sink_request = dp_panel_handle_sink_request;

+2 −1
Original line number Diff line number Diff line
@@ -81,7 +81,8 @@ struct dp_panel {
	int (*read_sink_caps)(struct dp_panel *dp_panel,
		struct drm_connector *connector);
	u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel);
	u32 (*get_max_pclk)(struct dp_panel *dp_panel);
	u32 (*get_mode_bpp)(struct dp_panel *dp_panel, u32 mode_max_bpp,
			u32 mode_pclk_khz);
	int (*get_modes)(struct dp_panel *dp_panel,
		struct drm_connector *connector, struct dp_display_mode *mode);
	void (*handle_sink_request)(struct dp_panel *dp_panel);
Loading