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

Commit 04e88e68 authored by Aravind Venkateswaran's avatar Aravind Venkateswaran Committed by Padmanabhan Komanduru
Browse files

msm: mdss: dp: fix handling of device shutdown with cable connected



When the source is powered off with an external sink connected, it
will result in a call to blank and power off the source. In the
current implementation, sink is not transitioned to D3 power mode
prior to turning off the source. This can result in the sink
reporting signal lock failures as the source if powered off,
resulting in an HPD IRQ interrupt. If this interrupt is handled
after the DP controller is powered off, it can lead to unclocked
register accesses. Fix this by ensuring that sink is powered off
prior to powering off the source. In addition, ensure that no more
attention events are handled once the DP controller is powered off.

Change-Id: I08558229f7c3e603904527de58a39039b3d7615e
Signed-off-by: default avatarAravind Venkateswaran <aravindh@codeaurora.org>
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
parent 22b400ed
Loading
Loading
Loading
Loading
+27 −21
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ static int mdss_dp_process_phy_test_pattern_request(
		struct mdss_dp_drv_pdata *dp);
static int mdss_dp_send_audio_notification(
	struct mdss_dp_drv_pdata *dp, int val);
static void mdss_dp_reset_sw_state(struct mdss_dp_drv_pdata *dp);

static inline void mdss_dp_reset_sink_count(struct mdss_dp_drv_pdata *dp)
{
@@ -1489,7 +1490,12 @@ static int mdss_dp_setup_main_link(struct mdss_dp_drv_pdata *dp, bool train)

	pr_debug("enter\n");
	mdss_dp_mainlink_ctrl(&dp->ctrl_io, true);
	mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON);
	ret = mdss_dp_aux_send_psm_request(dp, false);
	if (ret) {
		pr_err("Failed to exit low power mode, rc=%d\n", ret);
		goto end;
	}

	reinit_completion(&dp->video_comp);

	if (mdss_dp_is_phy_test_pattern_requested(dp))
@@ -1576,15 +1582,6 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv, bool lt_needed)

		dp_drv->power_on = true;

		if (dp_drv->psm_enabled) {
			ret = mdss_dp_aux_send_psm_request(dp_drv, false);
			if (ret) {
				pr_err("Failed to exit low power mode, rc=%d\n",
					ret);
				goto exit_loop;
			}
		}

		ret = mdss_dp_setup_main_link(dp_drv, lt_needed);

exit_loop:
@@ -1653,15 +1650,6 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)

	mdss_dp_configure_source_params(dp_drv, ln_map);

	if (dp_drv->psm_enabled) {
		ret = mdss_dp_aux_send_psm_request(dp_drv, false);
		if (ret) {
			pr_err("Failed to exit low power mode, rc=%d\n", ret);
			goto exit;
		}
	}


link_training:
	dp_drv->power_on = true;

@@ -2989,6 +2977,7 @@ static int mdss_dp_sysfs_create(struct mdss_dp_drv_pdata *dp,

static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata)
{
	bool cable_connected;
	struct mdss_dp_drv_pdata *dp_drv = NULL;
	const int idle_pattern_completion_timeout_ms = 3 * HZ / 100;

@@ -3009,6 +2998,14 @@ static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata)
		return;
	}

	/* power down the sink if cable is still connected */
	mutex_lock(&dp_drv->attention_lock);
	cable_connected = dp_drv->cable_connected;
	mutex_unlock(&dp_drv->attention_lock);
	if (cable_connected && dp_drv->alt_mode.dp_status.hpd_high) {
		if (mdss_dp_aux_send_psm_request(dp_drv, true))
			pr_err("Failed to enter low power mode\n");
	}
	reinit_completion(&dp_drv->idle_comp);
	mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE);
	if (!wait_for_completion_timeout(&dp_drv->idle_comp,
@@ -3129,6 +3126,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
			pr_err("DP Controller not powered on\n");
			break;
		}
		if (!atomic_read(&dp->notification_pending)) {
			pr_debug("blank when cable is connected\n");
			kthread_park(dp->ev_thread);
		}
		if (dp_is_hdcp_enabled(dp)) {
			dp->hdcp_status = HDCP_STATE_INACTIVE;

@@ -3168,8 +3169,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
		 * when you connect DP sink while the
		 * device is in suspend state.
		 */
		if ((!dp->power_on) && (dp->dp_initialized))
		if ((!dp->power_on) && (dp->dp_initialized)) {
			rc = mdss_dp_host_deinit(dp);
			kthread_park(dp->ev_thread);
		}

		/*
		 * For DP suspend/resume use case, CHECK_PARAMS is
@@ -3181,8 +3184,11 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
			dp->suspend_vic = dp->vic;
		break;
	case MDSS_EVENT_RESUME:
		if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN)
		if (dp->suspend_vic != HDMI_VFRMT_UNKNOWN) {
			dp_init_panel_info(dp, dp->suspend_vic);
			mdss_dp_reset_sw_state(dp);
			kthread_unpark(dp->ev_thread);
		}
		break;
	default:
		pr_debug("unhandled event=%d\n", event);
+0 −6
Original line number Diff line number Diff line
@@ -218,10 +218,6 @@ struct dp_alt_mode {
#define ST_SEND_VIDEO			BIT(7)
#define ST_PUSH_IDLE			BIT(8)

/* sink power state  */
#define SINK_POWER_ON		1
#define SINK_POWER_OFF		2

#define DP_LINK_RATE_162	6	/* 1.62G = 270M * 6 */
#define DP_LINK_RATE_270	10	/* 2.70G = 270M * 10 */
#define DP_LINK_RATE_540	20	/* 5.40G = 270M * 20 */
@@ -1181,11 +1177,9 @@ void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr);
void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep);

void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep);
void mdss_dp_sink_power_down(struct mdss_dp_drv_pdata *ep);
void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up);
void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep);
char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
+0 −9
Original line number Diff line number Diff line
@@ -2556,15 +2556,6 @@ static int dp_link_rate_down_shift(struct mdss_dp_drv_pdata *ep)
	return ret;
}

int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state)
{
	int ret;

	ret = dp_aux_write_buf(ep, 0x600, &state, 1, 0);
	pr_debug("state=%d ret=%d\n", state, ret);
	return ret;
}

static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep)
{
	int usleep_time;