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

Commit 4f238911 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: wait for vsync before rsc amc mode"

parents 3659d47c 8bfd3d1f
Loading
Loading
Loading
Loading
+122 −71
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct dp_display_private {
	struct dp_usbpd_cb usbpd_cb;
	struct dp_display_mode mode;
	struct dp_display dp_display;
	struct msm_drm_private *priv;

	struct workqueue_struct *wq;
	struct delayed_work hdcp_cb_work;
@@ -299,7 +300,12 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp)
	pr_debug("HDCP 1.3 initialized\n");

	dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data);
	if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2))
	if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) {
		pr_err("Error initializing HDCP 2.x\n");
		rc = -EINVAL;
		goto error;
	}

	pr_debug("HDCP 2.2 initialized\n");

	dp->hdcp.feature_enabled = true;
@@ -316,7 +322,6 @@ static int dp_display_bind(struct device *dev, struct device *master,
	int rc = 0;
	struct dp_display_private *dp;
	struct drm_device *drm;
	struct msm_drm_private *priv;
	struct platform_device *pdev = to_platform_device(dev);

	if (!dev || !pdev || !master) {
@@ -336,25 +341,7 @@ static int dp_display_bind(struct device *dev, struct device *master,
	}

	dp->dp_display.drm_dev = drm;
	priv = drm->dev_private;

	rc = dp->aux->drm_aux_register(dp->aux);
	if (rc) {
		pr_err("DRM DP AUX register failed\n");
		goto end;
	}

	rc = dp->power->power_client_init(dp->power, &priv->phandle);
	if (rc) {
		pr_err("Power client create failed\n");
		goto end;
	}

	rc = dp_display_initialize_hdcp(dp);
	if (rc) {
		pr_err("HDCP initialization failed\n");
		goto end;
	}
	dp->priv = drm->dev_private;
end:
	return rc;
}
@@ -398,32 +385,25 @@ static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
		(dp->link->sink_count.count == 0);
}

static void dp_display_send_hpd_event(struct dp_display *dp_display)
static void dp_display_send_hpd_event(struct dp_display_private *dp)
{
	struct drm_device *dev = NULL;
	struct dp_display_private *dp;
	struct drm_connector *connector;
	char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE],
		bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE];
	char *envp[5];

	if (!dp_display) {
		pr_err("invalid input\n");
		return;
	}
	connector = dp->dp_display.connector;

	dp = container_of(dp_display, struct dp_display_private, dp_display);
	if (!dp) {
		pr_err("invalid params\n");
	if (!connector) {
		pr_err("connector not set\n");
		return;
	}
	connector = dp->dp_display.connector;
	dev = dp_display->connector->dev;

	connector->status = connector->funcs->detect(connector, false);
	pr_debug("[%s] status updated to %s\n",
			      connector->name,
			      drm_get_connector_status_name(connector->status));

	dev = dp->dp_display.connector->dev;

	snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name);
	snprintf(status, HPD_STRING_SIZE, "status=%s",
		drm_get_connector_status_name(connector->status));
@@ -433,8 +413,7 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display)
	snprintf(pattern, HPD_STRING_SIZE, "pattern=%d",
		dp->link->test_video.test_video_pattern);

	pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n",
		name, status, bpp, pattern);
	pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern);
	envp[0] = name;
	envp[1] = status;
	envp[2] = bpp;
@@ -444,12 +423,48 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display)
			envp);
}

static void dp_display_post_open(struct dp_display *dp_display)
{
	struct drm_connector *connector;
	struct dp_display_private *dp;

	if (!dp_display) {
		pr_err("invalid input\n");
		return;
	}

	dp = container_of(dp_display, struct dp_display_private, dp_display);
	if (IS_ERR_OR_NULL(dp)) {
		pr_err("invalid params\n");
		return;
	}

	connector = dp->dp_display.connector;

	if (!connector) {
		pr_err("connector not set\n");
		return;
	}

	/* if cable is already connected, send notification */
	if (dp_display->is_connected)
		dp_display_send_hpd_event(dp);
	else
		dp_display->post_open = NULL;

}

static int dp_display_send_hpd_notification(struct dp_display_private *dp,
		bool hpd)
{
	dp->dp_display.is_connected = hpd;

	/* in case, framework is not yet up, don't notify hpd */
	if (dp->dp_display.post_open)
		return 0;

	reinit_completion(&dp->notification_comp);
	dp_display_send_hpd_event(&dp->dp_display);
	dp_display_send_hpd_event(dp);

	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) {
		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
@@ -475,6 +490,9 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
		dp->debug->psm_enabled = false;
	}

	if (!dp->dp_display.connector)
		return 0;

	rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
	if (rc) {
		if (rc == -ETIMEDOUT) {
@@ -792,18 +810,6 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		.dev = dev,
	};

	cb->configure  = dp_display_usbpd_configure_cb;
	cb->disconnect = dp_display_usbpd_disconnect_cb;
	cb->attention  = dp_display_usbpd_attention_cb;

	dp->usbpd = dp_usbpd_get(dev, cb);
	if (IS_ERR(dp->usbpd)) {
		rc = PTR_ERR(dp->usbpd);
		pr_err("failed to initialize usbpd, rc = %d\n", rc);
		dp->usbpd = NULL;
		goto error;
	}

	mutex_init(&dp->session_lock);

	dp->parser = dp_parser_get(dp->pdev);
@@ -811,7 +817,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		rc = PTR_ERR(dp->parser);
		pr_err("failed to initialize parser, rc = %d\n", rc);
		dp->parser = NULL;
		goto error_parser;
		goto error;
	}

	rc = dp->parser->parse(dp->parser);
@@ -836,6 +842,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		goto error_power;
	}

	rc = dp->power->power_client_init(dp->power, &dp->priv->phandle);
	if (rc) {
		pr_err("Power client create failed\n");
		goto error_aux;
	}

	dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
	if (IS_ERR(dp->aux)) {
		rc = PTR_ERR(dp->aux);
@@ -844,6 +856,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		goto error_aux;
	}

	rc = dp->aux->drm_aux_register(dp->aux);
	if (rc) {
		pr_err("DRM DP AUX register failed\n");
		goto error_link;
	}

	dp->link = dp_link_get(dev, dp->aux);
	if (IS_ERR(dp->link)) {
		rc = PTR_ERR(dp->link);
@@ -887,6 +905,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
		goto error_audio;
	}

	cb->configure  = dp_display_usbpd_configure_cb;
	cb->disconnect = dp_display_usbpd_disconnect_cb;
	cb->attention  = dp_display_usbpd_attention_cb;

	dp->usbpd = dp_usbpd_get(dev, cb);
	if (IS_ERR(dp->usbpd)) {
		rc = PTR_ERR(dp->usbpd);
		pr_err("failed to initialize usbpd, rc = %d\n", rc);
		dp->usbpd = NULL;
		goto error_usbpd;
	}

	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
				dp->link, &dp->dp_display.connector);
	if (IS_ERR(dp->debug)) {
@@ -898,6 +928,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp)

	return rc;
error_debug:
	dp_usbpd_put(dp->usbpd);
error_usbpd:
	dp_audio_put(dp->audio);
error_audio:
	dp_ctrl_put(dp->ctrl);
@@ -913,13 +945,40 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
	dp_catalog_put(dp->catalog);
error_catalog:
	dp_parser_put(dp->parser);
error_parser:
	dp_usbpd_put(dp->usbpd);
	mutex_destroy(&dp->session_lock);
error:
	mutex_destroy(&dp->session_lock);
	return rc;
}

static void dp_display_post_init(struct dp_display *dp_display)
{
	int rc = 0;
	struct dp_display_private *dp;

	if (!dp_display) {
		pr_err("invalid input\n");
		rc = -EINVAL;
		goto end;
	}

	dp = container_of(dp_display, struct dp_display_private, dp_display);
	if (IS_ERR_OR_NULL(dp)) {
		pr_err("invalid params\n");
		rc = -EINVAL;
		goto end;
	}

	rc = dp_init_sub_modules(dp);
	if (rc)
		goto end;

	dp_display_initialize_hdcp(dp);

	dp_display->post_init = NULL;
end:
	pr_debug("%s\n", rc ? "failed" : "success");
}

static int dp_display_set_mode(struct dp_display *dp_display,
		struct dp_display_mode *mode)
{
@@ -1022,7 +1081,7 @@ static int dp_display_post_enable(struct dp_display *dp_display)
	}
end:
	/* clear framework event notifier */
	dp_display->send_hpd_event = NULL;
	dp_display->post_open = NULL;

	complete_all(&dp->notification_comp);
	mutex_unlock(&dp->session_lock);
@@ -1147,7 +1206,7 @@ static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz)
	struct drm_dp_link *link_info;
	u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;

	if (!dp || !mode_pclk_khz) {
	if (!dp || !mode_pclk_khz || !dp->connector) {
		pr_err("invalid params\n");
		return -EINVAL;
	}
@@ -1177,7 +1236,7 @@ static int dp_display_get_modes(struct dp_display *dp,
	struct dp_display_private *dp_display;
	int ret = 0;

	if (!dp) {
	if (!dp || !dp->connector) {
		pr_err("invalid params\n");
		return 0;
	}
@@ -1248,16 +1307,10 @@ static int dp_display_probe(struct platform_device *pdev)
	dp->pdev = pdev;
	dp->name = "drm_dp";

	rc = dp_init_sub_modules(dp);
	if (rc) {
		rc = -EPROBE_DEFER;
		goto err_dev;
	}

	rc = dp_display_create_workqueue(dp);
	if (rc) {
		pr_err("Failed to create workqueue\n");
		goto err_sub_mod;
		goto error;
	}

	platform_set_drvdata(pdev, dp);
@@ -1275,20 +1328,18 @@ static int dp_display_probe(struct platform_device *pdev)
	g_dp_display->unprepare     = dp_display_unprepare;
	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->post_open     = dp_display_post_open;
	g_dp_display->post_init     = dp_display_post_init;
	g_dp_display->pre_kickoff   = dp_display_pre_kickoff;

	rc = component_add(&pdev->dev, &dp_display_comp_ops);
	if (rc) {
		pr_err("component add failed, rc=%d\n", rc);
		goto err_sub_mod;
		goto error;
	}

	return 0;

err_sub_mod:
	dp_display_deinit_sub_modules(dp);
err_dev:
error:
	devm_kfree(&pdev->dev, dp);
bail:
	return rc;
+2 −1
Original line number Diff line number Diff line
@@ -42,9 +42,10 @@ struct dp_display {
	int (*unprepare)(struct dp_display *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);
	void (*post_open)(struct dp_display *dp_display);
	int (*pre_kickoff)(struct dp_display *dp_display,
				struct drm_msm_ext_hdr_metadata *hdr_meta);
	void (*post_init)(struct dp_display *dp_display);
};

int dp_display_get_num_of_displays(void);
+10 −3
Original line number Diff line number Diff line
@@ -184,6 +184,9 @@ static void dp_bridge_disable(struct drm_bridge *drm_bridge)
	bridge = to_dp_bridge(drm_bridge);
	dp = bridge->display;

	if (dp && dp->connector)
		sde_connector_helper_bridge_disable(dp->connector);

	rc = dp->pre_disable(dp);
	if (rc) {
		pr_err("[%d] DP display pre disable failed, rc=%d\n",
@@ -295,6 +298,10 @@ int dp_connector_post_init(struct drm_connector *connector, void *display)
		return -EINVAL;

	dp_display->connector = connector;

	if (dp_display->post_init)
		dp_display->post_init(dp_display);

	return 0;
}

@@ -376,7 +383,7 @@ enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
	return status;
}

void dp_connector_send_hpd_event(void *display)
void dp_connector_post_open(void *display)
{
	struct dp_display *dp;

@@ -387,8 +394,8 @@ void dp_connector_send_hpd_event(void *display)

	dp = display;

	if (dp->send_hpd_event)
		dp->send_hpd_event(dp);
	if (dp->post_open)
		dp->post_open(dp);
}

int dp_connector_get_modes(struct drm_connector *connector,
+5 −1
Original line number Diff line number Diff line
@@ -95,7 +95,11 @@ int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode,

int dp_connector_get_info(struct msm_display_info *info, void *display);

void dp_connector_send_hpd_event(void *display);
/**
 * dp_connector_post_open - handle the post open functionalites
 * @display: Pointer to private display structure
 */
void dp_connector_post_open(void *display);

int dp_drm_bridge_init(void *display,
	struct drm_encoder *encoder);
+149 −36
Original line number Diff line number Diff line
@@ -790,6 +790,20 @@ static int dsi_display_debugfs_init(struct dsi_display *display)
		}
	}

	if (!debugfs_create_bool("ulps_enable", 0600, dir,
			&display->panel->ulps_enabled)) {
		pr_err("[%s] debugfs create ulps enable file failed\n",
		       display->name);
		goto error_remove_dir;
	}

	if (!debugfs_create_bool("ulps_suspend_enable", 0600, dir,
			&display->panel->ulps_suspend_enabled)) {
		pr_err("[%s] debugfs create ulps-suspend enable file failed\n",
		       display->name);
		goto error_remove_dir;
	}

	display->root = dir;
	return rc;
error_remove_dir:
@@ -826,12 +840,17 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display,

	pr_debug("checking ulps req validity\n");

	if (!dsi_panel_ulps_feature_enabled(display->panel))
	if (!dsi_panel_ulps_feature_enabled(display->panel) &&
			!display->panel->ulps_suspend_enabled) {
		pr_debug("%s: ULPS feature is not enabled\n", __func__);
		return false;
	}

	/* TODO: ULPS during suspend */
	if (!dsi_panel_initialized(display->panel))
	if (!dsi_panel_initialized(display->panel) &&
			!display->panel->ulps_suspend_enabled) {
		pr_debug("%s: panel not yet initialized\n", __func__);
		return false;
	}

	if (enable && display->ulps_enabled) {
		pr_debug("ULPS already enabled\n");
@@ -2335,22 +2354,27 @@ int dsi_pre_clkoff_cb(void *priv,
	if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) {
		/*
		 * If ULPS feature is enabled, enter ULPS first.
		 * However, when blanking the panel, we should enter ULPS
		 * only if ULPS during suspend feature is enabled.
		 */
		if (dsi_panel_initialized(display->panel) &&
			dsi_panel_ulps_feature_enabled(display->panel)) {
		if (!dsi_panel_initialized(display->panel)) {
			if (display->panel->ulps_suspend_enabled)
				rc = dsi_display_set_ulps(display, true);
			if (rc) {
		} else if (dsi_panel_ulps_feature_enabled(display->panel)) {
			rc = dsi_display_set_ulps(display, true);
		}
		if (rc)
			pr_err("%s: failed enable ulps, rc = %d\n",
			       __func__, rc);
	}
		}
	}

	if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) {
		/*
		 * Enable DSI clamps only if entering idle power collapse.
		 * Enable DSI clamps only if entering idle power collapse or
		 * when ULPS during suspend is enabled..
		 */
		if (dsi_panel_initialized(display->panel)) {
		if (dsi_panel_initialized(display->panel) ||
			display->panel->ulps_suspend_enabled) {
			dsi_display_phy_idle_off(display);
			rc = dsi_display_set_clamp(display, true);
			if (rc)
@@ -3954,7 +3978,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
	return rc;
}

int dsi_display_get_mode_count(struct dsi_display *display,
static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
			u32 *count)
{
	struct dsi_dfps_capabilities dfps_caps;
@@ -3966,15 +3990,13 @@ int dsi_display_get_mode_count(struct dsi_display *display,
		return -EINVAL;
	}

	mutex_lock(&display->display_lock);

	*count = display->panel->num_timing_nodes;

	rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
	if (rc) {
		pr_err("[%s] failed to get dfps caps from panel\n",
				display->name);
		goto done;
		return rc;
	}

	num_dfps_rates = !dfps_caps.dfps_support ? 1 :
@@ -3984,7 +4006,22 @@ int dsi_display_get_mode_count(struct dsi_display *display,
	/* Inflate num_of_modes by fps in dfps */
	*count = display->panel->num_timing_nodes * num_dfps_rates;

done:
	return 0;
}

int dsi_display_get_mode_count(struct dsi_display *display,
			u32 *count)
{
	int rc;

	if (!display || !display->panel) {
		pr_err("invalid display:%d panel:%d\n", display != NULL,
				display ? display->panel != NULL : 0);
		return -EINVAL;
	}

	mutex_lock(&display->display_lock);
	rc = dsi_display_get_mode_count_no_lock(display, count);
	mutex_unlock(&display->display_lock);

	return 0;
@@ -3997,20 +4034,36 @@ void dsi_display_put_mode(struct dsi_display *display,
}

int dsi_display_get_modes(struct dsi_display *display,
			  struct dsi_display_mode *modes)
			  struct dsi_display_mode **out_modes)
{
	struct dsi_dfps_capabilities dfps_caps;
	u32 num_dfps_rates, panel_mode_count;
	u32 num_dfps_rates, panel_mode_count, total_mode_count;
	u32 mode_idx, array_idx = 0;
	int i, rc = 0;
	int i, rc = -EINVAL;

	if (!display || !modes) {
	if (!display || !out_modes) {
		pr_err("Invalid params\n");
		return -EINVAL;
	}

	*out_modes = NULL;

	mutex_lock(&display->display_lock);

	rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count);
	if (rc)
		goto error;

	/* free any previously probed modes */
	kfree(display->modes);

	display->modes = kcalloc(total_mode_count, sizeof(*display->modes),
			GFP_KERNEL);
	if (!display->modes) {
		rc = -ENOMEM;
		goto error;
	}

	rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
	if (rc) {
		pr_err("[%s] failed to get dfps caps from panel\n",
@@ -4051,12 +4104,14 @@ int dsi_display_get_modes(struct dsi_display *display,
		}

		for (i = 0; i < num_dfps_rates; i++) {
			struct dsi_display_mode *sub_mode = &modes[array_idx];
			struct dsi_display_mode *sub_mode =
					&display->modes[array_idx];
			u32 curr_refresh_rate;

			if (!sub_mode) {
				pr_err("invalid mode data\n");
				return -EFAULT;
				rc = -EFAULT;
				goto error;
			}

			memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
@@ -4080,8 +4135,54 @@ int dsi_display_get_modes(struct dsi_display *display,
		}
	}

	*out_modes = display->modes;
	rc = 0;

error:
	if (rc)
		kfree(display->modes);

	mutex_unlock(&display->display_lock);
	return rc;
}

int dsi_display_find_mode(struct dsi_display *display,
		const struct dsi_display_mode *cmp,
		struct dsi_display_mode **out_mode)
{
	u32 count, i;
	int rc;

	if (!display || !out_mode)
		return -EINVAL;

	*out_mode = NULL;

	rc = dsi_display_get_mode_count(display, &count);
	if (rc)
		return rc;

	mutex_lock(&display->display_lock);
	for (i = 0; i < count; i++) {
		struct dsi_display_mode *m = &display->modes[i];

		if (cmp->timing.v_active == m->timing.v_active &&
			cmp->timing.h_active == m->timing.h_active &&
			cmp->timing.refresh_rate == m->timing.refresh_rate) {
			*out_mode = m;
			rc = 0;
			break;
		}
	}
	mutex_unlock(&display->display_lock);

	if (!*out_mode) {
		pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n",
				display->name, cmp->timing.v_active,
				cmp->timing.h_active, cmp->timing.refresh_rate);
		rc = -ENOENT;
	}

	return rc;
}

@@ -4632,9 +4733,18 @@ int dsi_display_prepare(struct dsi_display *display)
		goto error_panel_post_unprep;
	}

	/*
	 * If ULPS during suspend feature is enabled, then DSI PHY was
	 * left on during suspend. In this case, we do not need to reset/init
	 * PHY. This would have already been done when the CORE clocks are
	 * turned on. However, if cont splash is disabled, the first time DSI
	 * is powered on, phy init needs to be done unconditionally.
	 */
	if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) {
		rc = dsi_display_phy_sw_reset(display);
		if (rc) {
		pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
			pr_err("[%s] failed to reset phy, rc=%d\n",
				display->name, rc);
			goto error_ctrl_clk_off;
		}

@@ -4644,6 +4754,7 @@ int dsi_display_prepare(struct dsi_display *display)
			       display->name, rc);
			goto error_ctrl_clk_off;
		}
	}

	rc = dsi_display_set_clk_src(display);
	if (rc) {
@@ -5129,10 +5240,12 @@ int dsi_display_unprepare(struct dsi_display *display)
		pr_err("[%s] failed to deinit controller, rc=%d\n",
		       display->name, rc);

	if (!display->panel->ulps_suspend_enabled) {
		rc = dsi_display_phy_disable(display);
		if (rc)
			pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
			       display->name, rc);
	}

	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
			DSI_CORE_CLK, DSI_CLK_OFF);
Loading