diff mbox series

[v4] drm/msm/dp: do not initialize phy until plugin interrupt received

Message ID 1636493893-7600-1-git-send-email-quic_khsieh@quicinc.com (mailing list archive)
State Superseded
Headers show
Series [v4] drm/msm/dp: do not initialize phy until plugin interrupt received | expand

Commit Message

Kuogee Hsieh Nov. 9, 2021, 9:38 p.m. UTC
From: Kuogee Hsieh <khsieh@codeaurora.org>

Current DP drivers have regulators, clocks, irq and phy are grouped
together within a function and executed not in a symmetric manner.
This increase difficulty of code maintenance and limited code scalability.
This patch divided the driver life cycle of operation into four states,
resume (including booting up), dongle plugin, dongle unplugged and suspend.
Regulators, core clocks and irq are grouped together and enabled at resume
(or booting up) so that the DP controller is armed and ready to receive HPD
plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
into DUT (device under test). Once HPD plugin interrupt is received, DP
controller will initialize phy so that dpcd read/write will function and
following link training can be proceeded successfully. DP phy will be
disabled after main link is teared down at end of unplugged HPD interrupt
handle triggered by dongle unplugged out of DUT. Finally regulators, code
clocks and irq are disabled at corresponding suspension.

Changes in V2:
-- removed unnecessary dp_ctrl NULL check
-- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
-- remove flip parameter out of dp_ctrl_irq_enable()
-- add fixes tag

Changes in V3:
-- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
	dp_display_host_init() for eDP

Changes in V4:
-- rewording commit text to match this commit changes

Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c    | 87 ++++++++++++++++---------------------
 drivers/gpu/drm/msm/dp/dp_ctrl.h    |  9 ++--
 drivers/gpu/drm/msm/dp/dp_display.c | 83 ++++++++++++++++++++++++++---------
 3 files changed, 105 insertions(+), 74 deletions(-)

Comments

Kuogee Hsieh Nov. 15, 2021, 8:23 p.m. UTC | #1
On 2021-11-09 13:38, Kuogee Hsieh wrote:
> From: Kuogee Hsieh <khsieh@codeaurora.org>
> 
> Current DP drivers have regulators, clocks, irq and phy are grouped
> together within a function and executed not in a symmetric manner.
> This increase difficulty of code maintenance and limited code 
> scalability.
> This patch divided the driver life cycle of operation into four states,
> resume (including booting up), dongle plugin, dongle unplugged and 
> suspend.
> Regulators, core clocks and irq are grouped together and enabled at 
> resume
> (or booting up) so that the DP controller is armed and ready to receive 
> HPD
> plugin interrupts. HPD plugin interrupt is generated when a dongle 
> plugs
> into DUT (device under test). Once HPD plugin interrupt is received, DP
> controller will initialize phy so that dpcd read/write will function 
> and
> following link training can be proceeded successfully. DP phy will be
> disabled after main link is teared down at end of unplugged HPD 
> interrupt
> handle triggered by dongle unplugged out of DUT. Finally regulators, 
> code
> clocks and irq are disabled at corresponding suspension.
> 
> Changes in V2:
> -- removed unnecessary dp_ctrl NULL check
> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
> -- remove flip parameter out of dp_ctrl_irq_enable()
> -- add fixes tag
> 
> Changes in V3:
> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
> 	dp_display_host_init() for eDP
> 
> Changes in V4:
> -- rewording commit text to match this commit changes
> 
> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on
> Snapdragon Chipsets")
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---

any more comments?

>  drivers/gpu/drm/msm/dp/dp_ctrl.c    | 87 
> ++++++++++++++++---------------------
>  drivers/gpu/drm/msm/dp/dp_ctrl.h    |  9 ++--
>  drivers/gpu/drm/msm/dp/dp_display.c | 83 
> ++++++++++++++++++++++++++---------
>  3 files changed, 105 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c 
> b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index 7ec155d..4788e8c 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -1364,60 +1364,54 @@ static int dp_ctrl_enable_stream_clocks(struct
> dp_ctrl_private *ctrl)
>  	return ret;
>  }
> 
> -int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
> +void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl)
> +{
> +	struct dp_ctrl_private *ctrl;
> +
> +	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
> +
> +	dp_catalog_ctrl_reset(ctrl->catalog);
> +
> +	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
> +}
> +
> +void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl)
> +{
> +	struct dp_ctrl_private *ctrl;
> +
> +	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
> +
> +	dp_catalog_ctrl_reset(ctrl->catalog);
> +
> +	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
> +}
> +
> +void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
>  {
>  	struct dp_ctrl_private *ctrl;
>  	struct dp_io *dp_io;
>  	struct phy *phy;
> 
> -	if (!dp_ctrl) {
> -		DRM_ERROR("Invalid input data\n");
> -		return -EINVAL;
> -	}
> -
>  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>  	dp_io = &ctrl->parser->io;
>  	phy = dp_io->phy;
> 
> -	ctrl->dp_ctrl.orientation = flip;
> -
> -	if (reset)
> -		dp_catalog_ctrl_reset(ctrl->catalog);
> -
> -	DRM_DEBUG_DP("flip=%d\n", flip);
>  	dp_catalog_ctrl_phy_reset(ctrl->catalog);
>  	phy_init(phy);
> -	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
> -
> -	return 0;
>  }
> 
> -/**
> - * dp_ctrl_host_deinit() - Uninitialize DP controller
> - * @dp_ctrl: Display Port Driver data
> - *
> - * Perform required steps to uninitialize DP controller
> - * and its resources.
> - */
> -void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
> +void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
>  {
>  	struct dp_ctrl_private *ctrl;
>  	struct dp_io *dp_io;
>  	struct phy *phy;
> 
> -	if (!dp_ctrl) {
> -		DRM_ERROR("Invalid input data\n");
> -		return;
> -	}
> -
>  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>  	dp_io = &ctrl->parser->io;
>  	phy = dp_io->phy;
> 
> -	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
> +	dp_catalog_ctrl_phy_reset(ctrl->catalog);
>  	phy_exit(phy);
> -
> -	DRM_DEBUG_DP("Host deinitialized successfully\n");
>  }
> 
>  static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
> @@ -1895,8 +1889,14 @@ int dp_ctrl_off_link_stream(struct dp_ctrl 
> *dp_ctrl)
>  		return ret;
>  	}
> 
> +	DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
> +		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
> +
>  	phy_power_off(phy);
> 
> +	DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
> +		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
> +
>  	/* aux channel down, reinit phy */
>  	phy_exit(phy);
>  	phy_init(phy);
> @@ -1905,23 +1905,6 @@ int dp_ctrl_off_link_stream(struct dp_ctrl 
> *dp_ctrl)
>  	return ret;
>  }
> 
> -void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl)
> -{
> -	struct dp_ctrl_private *ctrl;
> -	struct dp_io *dp_io;
> -	struct phy *phy;
> -
> -	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
> -	dp_io = &ctrl->parser->io;
> -	phy = dp_io->phy;
> -
> -	dp_catalog_ctrl_reset(ctrl->catalog);
> -
> -	phy_exit(phy);
> -
> -	DRM_DEBUG_DP("DP off phy done\n");
> -}
> -
>  int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
>  {
>  	struct dp_ctrl_private *ctrl;
> @@ -1949,10 +1932,14 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
>  		DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
>  	}
> 
> +	DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
> +		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
> +
>  	phy_power_off(phy);
> -	phy_exit(phy);
> 
> -	DRM_DEBUG_DP("DP off done\n");
> +	DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
> +		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
> +
>  	return ret;
>  }
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h 
> b/drivers/gpu/drm/msm/dp/dp_ctrl.h
> index 2363a2d..30f9414 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
> @@ -19,12 +19,9 @@ struct dp_ctrl {
>  	u32 pixel_rate;
>  };
> 
> -int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
> -void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl);
>  int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
>  int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
>  int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
> -void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl);
>  int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
>  void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
>  void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
> @@ -34,4 +31,10 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev,
> struct dp_link *link,
>  			struct dp_power *power, struct dp_catalog *catalog,
>  			struct dp_parser *parser);
> 
> +void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl);
> +void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl);
> +void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl);
> +void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl);
> +void dp_ctrl_irq_phy_exit(struct dp_ctrl *dp_ctrl);
> +
>  #endif /* _DP_CTRL_H_ */
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c
> b/drivers/gpu/drm/msm/dp/dp_display.c
> index e41dd40..2f113ff 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -84,6 +84,7 @@ struct dp_display_private {
> 
>  	/* state variables */
>  	bool core_initialized;
> +	bool phy_initialized;
>  	bool hpd_irq_on;
>  	bool audio_supported;
> 
> @@ -387,7 +388,29 @@ static int dp_display_process_hpd_high(struct
> dp_display_private *dp)
>  	return rc;
>  }
> 
> -static void dp_display_host_init(struct dp_display_private *dp, int 
> reset)
> +static void dp_display_host_phy_init(struct dp_display_private *dp)
> +{
> +	DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
> +			dp->core_initialized, dp->phy_initialized);
> +
> +	if (!dp->phy_initialized) {
> +		dp_ctrl_phy_init(dp->ctrl);
> +		dp->phy_initialized = true;
> +	}
> +}
> +
> +static void dp_display_host_phy_exit(struct dp_display_private *dp)
> +{
> +	DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
> +			dp->core_initialized, dp->phy_initialized);
> +
> +	if (dp->phy_initialized) {
> +		dp_ctrl_phy_exit(dp->ctrl);
> +		dp->phy_initialized = false;
> +	}
> +}
> +
> +static void dp_display_host_init(struct dp_display_private *dp)
>  {
>  	bool flip = false;
> 
> @@ -400,8 +423,16 @@ static void dp_display_host_init(struct
> dp_display_private *dp, int reset)
>  	if (dp->usbpd->orientation == ORIENTATION_CC2)
>  		flip = true;
> 
> -	dp_power_init(dp->power, flip);
> -	dp_ctrl_host_init(dp->ctrl, flip, reset);
> +	dp_power_init(dp->power, false);
> +	dp_ctrl_irq_enable(dp->ctrl);
> +
> +	/*
> +	 * eDP is the embedded primary display and has its own phy
> +	 * initialize phy immediately
> +	 */
> +	if (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP)
> +		dp_display_host_phy_init(dp);
> +
>  	dp_aux_init(dp->aux);
>  	dp->core_initialized = true;
>  }
> @@ -413,7 +444,7 @@ static void dp_display_host_deinit(struct
> dp_display_private *dp)
>  		return;
>  	}
> 
> -	dp_ctrl_host_deinit(dp->ctrl);
> +	dp_ctrl_irq_disable(dp->ctrl);
>  	dp_aux_deinit(dp->aux);
>  	dp_power_deinit(dp->power);
> 
> @@ -424,7 +455,7 @@ static int dp_display_usbpd_configure_cb(struct 
> device *dev)
>  {
>  	struct dp_display_private *dp = dev_get_dp_display_private(dev);
> 
> -	dp_display_host_init(dp, true);
> +	dp_display_host_phy_init(dp);
> 
>  	return dp_display_process_hpd_high(dp);
>  }
> @@ -551,7 +582,7 @@ static int dp_hpd_plug_handle(struct
> dp_display_private *dp, u32 data)
>  		dp->hpd_state = ST_DISCONNECTED;
> 
>  		if (ret == -ECONNRESET) { /* cable unplugged */
> -			dp->core_initialized = false;
> +			dp->phy_initialized = false;
>  		}
> 
>  	} else {
> @@ -623,9 +654,8 @@ static int dp_hpd_unplug_handle(struct
> dp_display_private *dp, u32 data)
>  	if (state == ST_DISCONNECTED) {
>  		/* triggered by irq_hdp with sink_count = 0 */
>  		if (dp->link->sink_count == 0) {
> -			dp_ctrl_off_phy(dp->ctrl);
> +			dp_display_host_phy_exit(dp);
>  			hpd->hpd_high = 0;
> -			dp->core_initialized = false;
>  		}
>  		mutex_unlock(&dp->event_mutex);
>  		return 0;
> @@ -716,7 +746,7 @@ static int dp_irq_hpd_handle(struct
> dp_display_private *dp, u32 data)
> 
>  	ret = dp_display_usbpd_attention_cb(&dp->pdev->dev);
>  	if (ret == -ECONNRESET) { /* cable unplugged */
> -		dp->core_initialized = false;
> +		dp->phy_initialized = false;
>  	}
>  	DRM_DEBUG_DP("hpd_state=%d\n", state);
> 
> @@ -918,12 +948,19 @@ static int dp_display_disable(struct
> dp_display_private *dp, u32 data)
> 
>  	dp_display->audio_enabled = false;
> 
> -	/* triggered by irq_hpd with sink_count = 0 */
>  	if (dp->link->sink_count == 0) {
> +		/*
> +		 * irq_hpd with sink_count = 0
> +		 * hdmi unplugged out of dongle
> +		 */
>  		dp_ctrl_off_link_stream(dp->ctrl);
>  	} else {
> +		/*
> +		 * unplugged interrupt
> +		 * dongle unplugged out of DUT
> +		 */
>  		dp_ctrl_off(dp->ctrl);
> -		dp->core_initialized = false;
> +		dp_display_host_phy_exit(dp);
>  	}
> 
>  	dp_power_panel_on(dp->power, false);
> @@ -1059,7 +1096,7 @@ void msm_dp_snapshot(struct msm_disp_state
> *disp_state, struct msm_dp *dp)
>  static void dp_display_config_hpd(struct dp_display_private *dp)
>  {
> 
> -	dp_display_host_init(dp, true);
> +	dp_display_host_init(dp);
>  	dp_catalog_ctrl_hpd_config(dp->catalog);
> 
>  	/* Enable interrupt first time
> @@ -1338,20 +1375,22 @@ static int dp_pm_resume(struct device *dev)
>  	dp->hpd_state = ST_DISCONNECTED;
> 
>  	/* turn on dp ctrl/phy */
> -	dp_display_host_init(dp, true);
> +	dp_display_host_init(dp);
> 
>  	dp_catalog_ctrl_hpd_config(dp->catalog);
> 
> -	/*
> -	 * set sink to normal operation mode -- D0
> -	 * before dpcd read
> -	 */
> -	dp_link_psm_config(dp->link, &dp->panel->link_info, false);
> -
>  	if (dp_catalog_link_is_connected(dp->catalog)) {
> +		/*
> +		 * set sink to normal operation mode -- D0
> +		 * before dpcd read
> +		 */
> +		dp_display_host_phy_init(dp);
> +		dp_link_psm_config(dp->link, &dp->panel->link_info, false);
>  		sink_count = drm_dp_read_sink_count(dp->aux);
>  		if (sink_count < 0)
>  			sink_count = 0;
> +
> +		dp_display_host_phy_exit(dp);
>  	}
> 
>  	dp->link->sink_count = sink_count;
> @@ -1399,6 +1438,8 @@ static int dp_pm_suspend(struct device *dev)
>  		dp_display_host_deinit(dp);
>  	}
> 
> +	dp_display_host_phy_exit(dp);
> +
>  	dp->hpd_state = ST_SUSPENDED;
> 
>  	/* host_init will be called at pm_resume */
> @@ -1473,7 +1514,7 @@ void msm_dp_irq_postinstall(struct msm_dp 
> *dp_display)
>  		enable_irq(dp->irq);
>  		dp_hpd_connect(dp->usbpd, true);
>  	} else {
> -		dp_add_event(dp, EV_HPD_INIT_SETUP, 0, dp->id * 10);
> +		dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0);
>  	}
>  }
> 
> @@ -1567,7 +1608,7 @@ int msm_dp_display_enable(struct msm_dp *dp,
> struct drm_encoder *encoder)
>  	state =  dp_display->hpd_state;
> 
>  	if (state == ST_DISPLAY_OFF)
> -		dp_display_host_init(dp_display, true);
> +		dp_display_host_phy_init(dp_display);
> 
>  	dp_display_enable(dp_display, 0);
Kuogee Hsieh Nov. 16, 2021, 9:58 p.m. UTC | #2
On 11/15/2021 12:23 PM, khsieh@codeaurora.org wrote:
> On 2021-11-09 13:38, Kuogee Hsieh wrote:
>> From: Kuogee Hsieh <khsieh@codeaurora.org>
>>
>> Current DP drivers have regulators, clocks, irq and phy are grouped
>> together within a function and executed not in a symmetric manner.
>> This increase difficulty of code maintenance and limited code 
>> scalability.
>> This patch divided the driver life cycle of operation into four states,
>> resume (including booting up), dongle plugin, dongle unplugged and 
>> suspend.
>> Regulators, core clocks and irq are grouped together and enabled at 
>> resume
>> (or booting up) so that the DP controller is armed and ready to 
>> receive HPD
>> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
>> into DUT (device under test). Once HPD plugin interrupt is received, DP
>> controller will initialize phy so that dpcd read/write will function and
>> following link training can be proceeded successfully. DP phy will be
>> disabled after main link is teared down at end of unplugged HPD 
>> interrupt
>> handle triggered by dongle unplugged out of DUT. Finally regulators, 
>> code
>> clocks and irq are disabled at corresponding suspension.
>>
>> Changes in V2:
>> -- removed unnecessary dp_ctrl NULL check
>> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
>> -- remove flip parameter out of dp_ctrl_irq_enable()
>> -- add fixes tag
>>
>> Changes in V3:
>> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
>>     dp_display_host_init() for eDP
>>
>> Changes in V4:
>> -- rewording commit text to match this commit changes
>>
>> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on
>> Snapdragon Chipsets")
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
>
> any more comments?
>
Hi Stephen/Bjorn,

Any more comments?

We like to merge this patch by the end of this month.

Would you please give me your comments asap.

Thanks,

>>  drivers/gpu/drm/msm/dp/dp_ctrl.c    | 87 
>> ++++++++++++++++---------------------
>>  drivers/gpu/drm/msm/dp/dp_ctrl.h    |  9 ++--
>>  drivers/gpu/drm/msm/dp/dp_display.c | 83 
>> ++++++++++++++++++++++++++---------
>>  3 files changed, 105 insertions(+), 74 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c 
>> b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> index 7ec155d..4788e8c 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
>> @@ -1364,60 +1364,54 @@ static int dp_ctrl_enable_stream_clocks(struct
>> dp_ctrl_private *ctrl)
>>      return ret;
>>  }
>>
>> -int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
>> +void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl)
>> +{
>> +    struct dp_ctrl_private *ctrl;
>> +
>> +    ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>> +
>> +    dp_catalog_ctrl_reset(ctrl->catalog);
>> +
>> +    dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
>> +}
>> +
>> +void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl)
>> +{
>> +    struct dp_ctrl_private *ctrl;
>> +
>> +    ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>> +
>> +    dp_catalog_ctrl_reset(ctrl->catalog);
>> +
>> +    dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
>> +}
>> +
>> +void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
>>  {
>>      struct dp_ctrl_private *ctrl;
>>      struct dp_io *dp_io;
>>      struct phy *phy;
>>
>> -    if (!dp_ctrl) {
>> -        DRM_ERROR("Invalid input data\n");
>> -        return -EINVAL;
>> -    }
>> -
>>      ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>>      dp_io = &ctrl->parser->io;
>>      phy = dp_io->phy;
>>
>> -    ctrl->dp_ctrl.orientation = flip;
>> -
>> -    if (reset)
>> -        dp_catalog_ctrl_reset(ctrl->catalog);
>> -
>> -    DRM_DEBUG_DP("flip=%d\n", flip);
>>      dp_catalog_ctrl_phy_reset(ctrl->catalog);
>>      phy_init(phy);
>> -    dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
>> -
>> -    return 0;
>>  }
>>
>> -/**
>> - * dp_ctrl_host_deinit() - Uninitialize DP controller
>> - * @dp_ctrl: Display Port Driver data
>> - *
>> - * Perform required steps to uninitialize DP controller
>> - * and its resources.
>> - */
>> -void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
>> +void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
>>  {
>>      struct dp_ctrl_private *ctrl;
>>      struct dp_io *dp_io;
>>      struct phy *phy;
>>
>> -    if (!dp_ctrl) {
>> -        DRM_ERROR("Invalid input data\n");
>> -        return;
>> -    }
>> -
>>      ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>>      dp_io = &ctrl->parser->io;
>>      phy = dp_io->phy;
>>
>> -    dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
>> +    dp_catalog_ctrl_phy_reset(ctrl->catalog);
>>      phy_exit(phy);
>> -
>> -    DRM_DEBUG_DP("Host deinitialized successfully\n");
>>  }
>>
>>  static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
>> @@ -1895,8 +1889,14 @@ int dp_ctrl_off_link_stream(struct dp_ctrl 
>> *dp_ctrl)
>>          return ret;
>>      }
>>
>> +    DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
>> +        (u32)(uintptr_t)phy, phy->init_count, phy->power_count);
>> +
>>      phy_power_off(phy);
>>
>> +    DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
>> +        (u32)(uintptr_t)phy, phy->init_count, phy->power_count);
>> +
>>      /* aux channel down, reinit phy */
>>      phy_exit(phy);
>>      phy_init(phy);
>> @@ -1905,23 +1905,6 @@ int dp_ctrl_off_link_stream(struct dp_ctrl 
>> *dp_ctrl)
>>      return ret;
>>  }
>>
>> -void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl)
>> -{
>> -    struct dp_ctrl_private *ctrl;
>> -    struct dp_io *dp_io;
>> -    struct phy *phy;
>> -
>> -    ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
>> -    dp_io = &ctrl->parser->io;
>> -    phy = dp_io->phy;
>> -
>> -    dp_catalog_ctrl_reset(ctrl->catalog);
>> -
>> -    phy_exit(phy);
>> -
>> -    DRM_DEBUG_DP("DP off phy done\n");
>> -}
>> -
>>  int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
>>  {
>>      struct dp_ctrl_private *ctrl;
>> @@ -1949,10 +1932,14 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
>>          DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
>>      }
>>
>> +    DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
>> +        (u32)(uintptr_t)phy, phy->init_count, phy->power_count);
>> +
>>      phy_power_off(phy);
>> -    phy_exit(phy);
>>
>> -    DRM_DEBUG_DP("DP off done\n");
>> +    DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
>> +        (u32)(uintptr_t)phy, phy->init_count, phy->power_count);
>> +
>>      return ret;
>>  }
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h 
>> b/drivers/gpu/drm/msm/dp/dp_ctrl.h
>> index 2363a2d..30f9414 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
>> @@ -19,12 +19,9 @@ struct dp_ctrl {
>>      u32 pixel_rate;
>>  };
>>
>> -int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
>> -void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl);
>>  int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
>>  int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
>>  int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
>> -void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl);
>>  int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
>>  void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
>>  void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
>> @@ -34,4 +31,10 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev,
>> struct dp_link *link,
>>              struct dp_power *power, struct dp_catalog *catalog,
>>              struct dp_parser *parser);
>>
>> +void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl);
>> +void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl);
>> +void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl);
>> +void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl);
>> +void dp_ctrl_irq_phy_exit(struct dp_ctrl *dp_ctrl);
>> +
>>  #endif /* _DP_CTRL_H_ */
>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c
>> b/drivers/gpu/drm/msm/dp/dp_display.c
>> index e41dd40..2f113ff 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>> @@ -84,6 +84,7 @@ struct dp_display_private {
>>
>>      /* state variables */
>>      bool core_initialized;
>> +    bool phy_initialized;
>>      bool hpd_irq_on;
>>      bool audio_supported;
>>
>> @@ -387,7 +388,29 @@ static int dp_display_process_hpd_high(struct
>> dp_display_private *dp)
>>      return rc;
>>  }
>>
>> -static void dp_display_host_init(struct dp_display_private *dp, int 
>> reset)
>> +static void dp_display_host_phy_init(struct dp_display_private *dp)
>> +{
>> +    DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
>> +            dp->core_initialized, dp->phy_initialized);
>> +
>> +    if (!dp->phy_initialized) {
>> +        dp_ctrl_phy_init(dp->ctrl);
>> +        dp->phy_initialized = true;
>> +    }
>> +}
>> +
>> +static void dp_display_host_phy_exit(struct dp_display_private *dp)
>> +{
>> +    DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
>> +            dp->core_initialized, dp->phy_initialized);
>> +
>> +    if (dp->phy_initialized) {
>> +        dp_ctrl_phy_exit(dp->ctrl);
>> +        dp->phy_initialized = false;
>> +    }
>> +}
>> +
>> +static void dp_display_host_init(struct dp_display_private *dp)
>>  {
>>      bool flip = false;
>>
>> @@ -400,8 +423,16 @@ static void dp_display_host_init(struct
>> dp_display_private *dp, int reset)
>>      if (dp->usbpd->orientation == ORIENTATION_CC2)
>>          flip = true;
>>
>> -    dp_power_init(dp->power, flip);
>> -    dp_ctrl_host_init(dp->ctrl, flip, reset);
>> +    dp_power_init(dp->power, false);
>> +    dp_ctrl_irq_enable(dp->ctrl);
>> +
>> +    /*
>> +     * eDP is the embedded primary display and has its own phy
>> +     * initialize phy immediately
>> +     */
>> +    if (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP)
>> +        dp_display_host_phy_init(dp);
>> +
>>      dp_aux_init(dp->aux);
>>      dp->core_initialized = true;
>>  }
>> @@ -413,7 +444,7 @@ static void dp_display_host_deinit(struct
>> dp_display_private *dp)
>>          return;
>>      }
>>
>> -    dp_ctrl_host_deinit(dp->ctrl);
>> +    dp_ctrl_irq_disable(dp->ctrl);
>>      dp_aux_deinit(dp->aux);
>>      dp_power_deinit(dp->power);
>>
>> @@ -424,7 +455,7 @@ static int dp_display_usbpd_configure_cb(struct 
>> device *dev)
>>  {
>>      struct dp_display_private *dp = dev_get_dp_display_private(dev);
>>
>> -    dp_display_host_init(dp, true);
>> +    dp_display_host_phy_init(dp);
>>
>>      return dp_display_process_hpd_high(dp);
>>  }
>> @@ -551,7 +582,7 @@ static int dp_hpd_plug_handle(struct
>> dp_display_private *dp, u32 data)
>>          dp->hpd_state = ST_DISCONNECTED;
>>
>>          if (ret == -ECONNRESET) { /* cable unplugged */
>> -            dp->core_initialized = false;
>> +            dp->phy_initialized = false;
>>          }
>>
>>      } else {
>> @@ -623,9 +654,8 @@ static int dp_hpd_unplug_handle(struct
>> dp_display_private *dp, u32 data)
>>      if (state == ST_DISCONNECTED) {
>>          /* triggered by irq_hdp with sink_count = 0 */
>>          if (dp->link->sink_count == 0) {
>> -            dp_ctrl_off_phy(dp->ctrl);
>> +            dp_display_host_phy_exit(dp);
>>              hpd->hpd_high = 0;
>> -            dp->core_initialized = false;
>>          }
>>          mutex_unlock(&dp->event_mutex);
>>          return 0;
>> @@ -716,7 +746,7 @@ static int dp_irq_hpd_handle(struct
>> dp_display_private *dp, u32 data)
>>
>>      ret = dp_display_usbpd_attention_cb(&dp->pdev->dev);
>>      if (ret == -ECONNRESET) { /* cable unplugged */
>> -        dp->core_initialized = false;
>> +        dp->phy_initialized = false;
>>      }
>>      DRM_DEBUG_DP("hpd_state=%d\n", state);
>>
>> @@ -918,12 +948,19 @@ static int dp_display_disable(struct
>> dp_display_private *dp, u32 data)
>>
>>      dp_display->audio_enabled = false;
>>
>> -    /* triggered by irq_hpd with sink_count = 0 */
>>      if (dp->link->sink_count == 0) {
>> +        /*
>> +         * irq_hpd with sink_count = 0
>> +         * hdmi unplugged out of dongle
>> +         */
>>          dp_ctrl_off_link_stream(dp->ctrl);
>>      } else {
>> +        /*
>> +         * unplugged interrupt
>> +         * dongle unplugged out of DUT
>> +         */
>>          dp_ctrl_off(dp->ctrl);
>> -        dp->core_initialized = false;
>> +        dp_display_host_phy_exit(dp);
>>      }
>>
>>      dp_power_panel_on(dp->power, false);
>> @@ -1059,7 +1096,7 @@ void msm_dp_snapshot(struct msm_disp_state
>> *disp_state, struct msm_dp *dp)
>>  static void dp_display_config_hpd(struct dp_display_private *dp)
>>  {
>>
>> -    dp_display_host_init(dp, true);
>> +    dp_display_host_init(dp);
>>      dp_catalog_ctrl_hpd_config(dp->catalog);
>>
>>      /* Enable interrupt first time
>> @@ -1338,20 +1375,22 @@ static int dp_pm_resume(struct device *dev)
>>      dp->hpd_state = ST_DISCONNECTED;
>>
>>      /* turn on dp ctrl/phy */
>> -    dp_display_host_init(dp, true);
>> +    dp_display_host_init(dp);
>>
>>      dp_catalog_ctrl_hpd_config(dp->catalog);
>>
>> -    /*
>> -     * set sink to normal operation mode -- D0
>> -     * before dpcd read
>> -     */
>> -    dp_link_psm_config(dp->link, &dp->panel->link_info, false);
>> -
>>      if (dp_catalog_link_is_connected(dp->catalog)) {
>> +        /*
>> +         * set sink to normal operation mode -- D0
>> +         * before dpcd read
>> +         */
>> +        dp_display_host_phy_init(dp);
>> +        dp_link_psm_config(dp->link, &dp->panel->link_info, false);
>>          sink_count = drm_dp_read_sink_count(dp->aux);
>>          if (sink_count < 0)
>>              sink_count = 0;
>> +
>> +        dp_display_host_phy_exit(dp);
>>      }
>>
>>      dp->link->sink_count = sink_count;
>> @@ -1399,6 +1438,8 @@ static int dp_pm_suspend(struct device *dev)
>>          dp_display_host_deinit(dp);
>>      }
>>
>> +    dp_display_host_phy_exit(dp);
>> +
>>      dp->hpd_state = ST_SUSPENDED;
>>
>>      /* host_init will be called at pm_resume */
>> @@ -1473,7 +1514,7 @@ void msm_dp_irq_postinstall(struct msm_dp 
>> *dp_display)
>>          enable_irq(dp->irq);
>>          dp_hpd_connect(dp->usbpd, true);
>>      } else {
>> -        dp_add_event(dp, EV_HPD_INIT_SETUP, 0, dp->id * 10);
>> +        dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0);
>>      }
>>  }
>>
>> @@ -1567,7 +1608,7 @@ int msm_dp_display_enable(struct msm_dp *dp,
>> struct drm_encoder *encoder)
>>      state =  dp_display->hpd_state;
>>
>>      if (state == ST_DISPLAY_OFF)
>> -        dp_display_host_init(dp_display, true);
>> +        dp_display_host_phy_init(dp_display);
>>
>>      dp_display_enable(dp_display, 0);
Stephen Boyd Nov. 19, 2021, 1:20 a.m. UTC | #3
Quoting Kuogee Hsieh (2021-11-09 13:38:13)
> From: Kuogee Hsieh <khsieh@codeaurora.org>
>
> Current DP drivers have regulators, clocks, irq and phy are grouped
> together within a function and executed not in a symmetric manner.
> This increase difficulty of code maintenance and limited code scalability.
> This patch divided the driver life cycle of operation into four states,
> resume (including booting up), dongle plugin, dongle unplugged and suspend.
> Regulators, core clocks and irq are grouped together and enabled at resume
> (or booting up) so that the DP controller is armed and ready to receive HPD
> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
> into DUT (device under test). Once HPD plugin interrupt is received, DP
> controller will initialize phy so that dpcd read/write will function and
> following link training can be proceeded successfully. DP phy will be
> disabled after main link is teared down at end of unplugged HPD interrupt
> handle triggered by dongle unplugged out of DUT. Finally regulators, code
> clocks and irq are disabled at corresponding suspension.
>
> Changes in V2:
> -- removed unnecessary dp_ctrl NULL check
> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
> -- remove flip parameter out of dp_ctrl_irq_enable()
> -- add fixes tag
>
> Changes in V3:
> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
>         dp_display_host_init() for eDP
>
> Changes in V4:
> -- rewording commit text to match this commit changes
>
> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")
>
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---

What commit is this patch based on?
Kuogee Hsieh Nov. 19, 2021, 4:54 p.m. UTC | #4
On 11/18/2021 5:20 PM, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2021-11-09 13:38:13)
>> From: Kuogee Hsieh <khsieh@codeaurora.org>
>>
>> Current DP drivers have regulators, clocks, irq and phy are grouped
>> together within a function and executed not in a symmetric manner.
>> This increase difficulty of code maintenance and limited code scalability.
>> This patch divided the driver life cycle of operation into four states,
>> resume (including booting up), dongle plugin, dongle unplugged and suspend.
>> Regulators, core clocks and irq are grouped together and enabled at resume
>> (or booting up) so that the DP controller is armed and ready to receive HPD
>> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
>> into DUT (device under test). Once HPD plugin interrupt is received, DP
>> controller will initialize phy so that dpcd read/write will function and
>> following link training can be proceeded successfully. DP phy will be
>> disabled after main link is teared down at end of unplugged HPD interrupt
>> handle triggered by dongle unplugged out of DUT. Finally regulators, code
>> clocks and irq are disabled at corresponding suspension.
>>
>> Changes in V2:
>> -- removed unnecessary dp_ctrl NULL check
>> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
>> -- remove flip parameter out of dp_ctrl_irq_enable()
>> -- add fixes tag
>>
>> Changes in V3:
>> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
>>          dp_display_host_init() for eDP
>>
>> Changes in V4:
>> -- rewording commit text to match this commit changes
>>
>> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
> What commit is this patch based on?

It base on Bjorn's patch,

https://patchwork.freedesktop.org/series/92992/
Stephen Boyd Dec. 3, 2021, 2:41 a.m. UTC | #5
Quoting Kuogee Hsieh (2021-11-09 13:38:13)
> From: Kuogee Hsieh <khsieh@codeaurora.org>
>
> Current DP drivers have regulators, clocks, irq and phy are grouped
> together within a function and executed not in a symmetric manner.
> This increase difficulty of code maintenance and limited code scalability.
> This patch divided the driver life cycle of operation into four states,
> resume (including booting up), dongle plugin, dongle unplugged and suspend.
> Regulators, core clocks and irq are grouped together and enabled at resume
> (or booting up) so that the DP controller is armed and ready to receive HPD
> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
> into DUT (device under test). Once HPD plugin interrupt is received, DP
> controller will initialize phy so that dpcd read/write will function and
> following link training can be proceeded successfully. DP phy will be
> disabled after main link is teared down at end of unplugged HPD interrupt
> handle triggered by dongle unplugged out of DUT. Finally regulators, code
> clocks and irq are disabled at corresponding suspension.
>
> Changes in V2:
> -- removed unnecessary dp_ctrl NULL check
> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
> -- remove flip parameter out of dp_ctrl_irq_enable()
> -- add fixes tag
>
> Changes in V3:
> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
>         dp_display_host_init() for eDP
>
> Changes in V4:
> -- rewording commit text to match this commit changes
>
> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")
>
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---

Can you please resend this based on the msm-next branch[1]? It doesn't
apply now that other patches have been applied.

[1] https://gitlab.freedesktop.org/drm/msm.git msm-next

>  drivers/gpu/drm/msm/dp/dp_ctrl.c    | 87 ++++++++++++++++---------------------
>  drivers/gpu/drm/msm/dp/dp_ctrl.h    |  9 ++--
>  drivers/gpu/drm/msm/dp/dp_display.c | 83 ++++++++++++++++++++++++++---------
>  3 files changed, 105 insertions(+), 74 deletions(-)
>
Kuogee Hsieh Dec. 3, 2021, 10:53 p.m. UTC | #6
On 12/2/2021 6:41 PM, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2021-11-09 13:38:13)
>> From: Kuogee Hsieh <khsieh@codeaurora.org>
>>
>> Current DP drivers have regulators, clocks, irq and phy are grouped
>> together within a function and executed not in a symmetric manner.
>> This increase difficulty of code maintenance and limited code scalability.
>> This patch divided the driver life cycle of operation into four states,
>> resume (including booting up), dongle plugin, dongle unplugged and suspend.
>> Regulators, core clocks and irq are grouped together and enabled at resume
>> (or booting up) so that the DP controller is armed and ready to receive HPD
>> plugin interrupts. HPD plugin interrupt is generated when a dongle plugs
>> into DUT (device under test). Once HPD plugin interrupt is received, DP
>> controller will initialize phy so that dpcd read/write will function and
>> following link training can be proceeded successfully. DP phy will be
>> disabled after main link is teared down at end of unplugged HPD interrupt
>> handle triggered by dongle unplugged out of DUT. Finally regulators, code
>> clocks and irq are disabled at corresponding suspension.
>>
>> Changes in V2:
>> -- removed unnecessary dp_ctrl NULL check
>> -- removed unnecessary phy init_count and power_count DRM_DEBUG_DP logs
>> -- remove flip parameter out of dp_ctrl_irq_enable()
>> -- add fixes tag
>>
>> Changes in V3:
>> -- call dp_display_host_phy_init() instead of dp_ctrl_phy_init() at
>>          dp_display_host_init() for eDP
>>
>> Changes in V4:
>> -- rewording commit text to match this commit changes
>>
>> Fixes: e91e3065a806 ("drm/msm/dp: Add DP compliance tests on Snapdragon Chipsets")
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
> Can you please resend this based on the msm-next branch[1]? It doesn't
> apply now that other patches have been applied.
>
> [1] https://gitlab.freedesktop.org/drm/msm.git msm-next

Stephen, below patches  missed at msm-next branch. Are there merged soon?

1) WIP: drm/msm/dp: Detect the connector type based on reg property

2) WIP: handle no-hpd property in DP driver


>>   drivers/gpu/drm/msm/dp/dp_ctrl.c    | 87 ++++++++++++++++---------------------
>>   drivers/gpu/drm/msm/dp/dp_ctrl.h    |  9 ++--
>>   drivers/gpu/drm/msm/dp/dp_display.c | 83 ++++++++++++++++++++++++++---------
>>   3 files changed, 105 insertions(+), 74 deletions(-)
>>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 7ec155d..4788e8c 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1364,60 +1364,54 @@  static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl)
 	return ret;
 }
 
-int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
+void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+	dp_catalog_ctrl_reset(ctrl->catalog);
+
+	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
+}
+
+void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+	dp_catalog_ctrl_reset(ctrl->catalog);
+
+	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
+}
+
+void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
 {
 	struct dp_ctrl_private *ctrl;
 	struct dp_io *dp_io;
 	struct phy *phy;
 
-	if (!dp_ctrl) {
-		DRM_ERROR("Invalid input data\n");
-		return -EINVAL;
-	}
-
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 	dp_io = &ctrl->parser->io;
 	phy = dp_io->phy;
 
-	ctrl->dp_ctrl.orientation = flip;
-
-	if (reset)
-		dp_catalog_ctrl_reset(ctrl->catalog);
-
-	DRM_DEBUG_DP("flip=%d\n", flip);
 	dp_catalog_ctrl_phy_reset(ctrl->catalog);
 	phy_init(phy);
-	dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
-
-	return 0;
 }
 
-/**
- * dp_ctrl_host_deinit() - Uninitialize DP controller
- * @dp_ctrl: Display Port Driver data
- *
- * Perform required steps to uninitialize DP controller
- * and its resources.
- */
-void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
+void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
 {
 	struct dp_ctrl_private *ctrl;
 	struct dp_io *dp_io;
 	struct phy *phy;
 
-	if (!dp_ctrl) {
-		DRM_ERROR("Invalid input data\n");
-		return;
-	}
-
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 	dp_io = &ctrl->parser->io;
 	phy = dp_io->phy;
 
-	dp_catalog_ctrl_enable_irq(ctrl->catalog, false);
+	dp_catalog_ctrl_phy_reset(ctrl->catalog);
 	phy_exit(phy);
-
-	DRM_DEBUG_DP("Host deinitialized successfully\n");
 }
 
 static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
@@ -1895,8 +1889,14 @@  int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
 		return ret;
 	}
 
+	DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
+		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
+
 	phy_power_off(phy);
 
+	DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
+		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
+
 	/* aux channel down, reinit phy */
 	phy_exit(phy);
 	phy_init(phy);
@@ -1905,23 +1905,6 @@  int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
 	return ret;
 }
 
-void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl)
-{
-	struct dp_ctrl_private *ctrl;
-	struct dp_io *dp_io;
-	struct phy *phy;
-
-	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-	dp_io = &ctrl->parser->io;
-	phy = dp_io->phy;
-
-	dp_catalog_ctrl_reset(ctrl->catalog);
-
-	phy_exit(phy);
-
-	DRM_DEBUG_DP("DP off phy done\n");
-}
-
 int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
 {
 	struct dp_ctrl_private *ctrl;
@@ -1949,10 +1932,14 @@  int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
 		DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
 	}
 
+	DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
+		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
+
 	phy_power_off(phy);
-	phy_exit(phy);
 
-	DRM_DEBUG_DP("DP off done\n");
+	DRM_DEBUG_DP("After, phy=%x init_count=%d power_on=%d\n",
+		(u32)(uintptr_t)phy, phy->init_count, phy->power_count);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 2363a2d..30f9414 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -19,12 +19,9 @@  struct dp_ctrl {
 	u32 pixel_rate;
 };
 
-int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
-void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl);
 int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
 int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
 int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
-void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl);
 int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
 void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
 void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
@@ -34,4 +31,10 @@  struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
 			struct dp_power *power, struct dp_catalog *catalog,
 			struct dp_parser *parser);
 
+void dp_ctrl_irq_enable(struct dp_ctrl *dp_ctrl);
+void dp_ctrl_irq_disable(struct dp_ctrl *dp_ctrl);
+void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl);
+void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl);
+void dp_ctrl_irq_phy_exit(struct dp_ctrl *dp_ctrl);
+
 #endif /* _DP_CTRL_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index e41dd40..2f113ff 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -84,6 +84,7 @@  struct dp_display_private {
 
 	/* state variables */
 	bool core_initialized;
+	bool phy_initialized;
 	bool hpd_irq_on;
 	bool audio_supported;
 
@@ -387,7 +388,29 @@  static int dp_display_process_hpd_high(struct dp_display_private *dp)
 	return rc;
 }
 
-static void dp_display_host_init(struct dp_display_private *dp, int reset)
+static void dp_display_host_phy_init(struct dp_display_private *dp)
+{
+	DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
+			dp->core_initialized, dp->phy_initialized);
+
+	if (!dp->phy_initialized) {
+		dp_ctrl_phy_init(dp->ctrl);
+		dp->phy_initialized = true;
+	}
+}
+
+static void dp_display_host_phy_exit(struct dp_display_private *dp)
+{
+	DRM_DEBUG_DP("core_init=%d phy_init=%d\n",
+			dp->core_initialized, dp->phy_initialized);
+
+	if (dp->phy_initialized) {
+		dp_ctrl_phy_exit(dp->ctrl);
+		dp->phy_initialized = false;
+	}
+}
+
+static void dp_display_host_init(struct dp_display_private *dp)
 {
 	bool flip = false;
 
@@ -400,8 +423,16 @@  static void dp_display_host_init(struct dp_display_private *dp, int reset)
 	if (dp->usbpd->orientation == ORIENTATION_CC2)
 		flip = true;
 
-	dp_power_init(dp->power, flip);
-	dp_ctrl_host_init(dp->ctrl, flip, reset);
+	dp_power_init(dp->power, false);
+	dp_ctrl_irq_enable(dp->ctrl);
+
+	/*
+	 * eDP is the embedded primary display and has its own phy
+	 * initialize phy immediately
+	 */
+	if (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP)
+		dp_display_host_phy_init(dp);
+
 	dp_aux_init(dp->aux);
 	dp->core_initialized = true;
 }
@@ -413,7 +444,7 @@  static void dp_display_host_deinit(struct dp_display_private *dp)
 		return;
 	}
 
-	dp_ctrl_host_deinit(dp->ctrl);
+	dp_ctrl_irq_disable(dp->ctrl);
 	dp_aux_deinit(dp->aux);
 	dp_power_deinit(dp->power);
 
@@ -424,7 +455,7 @@  static int dp_display_usbpd_configure_cb(struct device *dev)
 {
 	struct dp_display_private *dp = dev_get_dp_display_private(dev);
 
-	dp_display_host_init(dp, true);
+	dp_display_host_phy_init(dp);
 
 	return dp_display_process_hpd_high(dp);
 }
@@ -551,7 +582,7 @@  static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
 		dp->hpd_state = ST_DISCONNECTED;
 
 		if (ret == -ECONNRESET) { /* cable unplugged */
-			dp->core_initialized = false;
+			dp->phy_initialized = false;
 		}
 
 	} else {
@@ -623,9 +654,8 @@  static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
 	if (state == ST_DISCONNECTED) {
 		/* triggered by irq_hdp with sink_count = 0 */
 		if (dp->link->sink_count == 0) {
-			dp_ctrl_off_phy(dp->ctrl);
+			dp_display_host_phy_exit(dp);
 			hpd->hpd_high = 0;
-			dp->core_initialized = false;
 		}
 		mutex_unlock(&dp->event_mutex);
 		return 0;
@@ -716,7 +746,7 @@  static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
 
 	ret = dp_display_usbpd_attention_cb(&dp->pdev->dev);
 	if (ret == -ECONNRESET) { /* cable unplugged */
-		dp->core_initialized = false;
+		dp->phy_initialized = false;
 	}
 	DRM_DEBUG_DP("hpd_state=%d\n", state);
 
@@ -918,12 +948,19 @@  static int dp_display_disable(struct dp_display_private *dp, u32 data)
 
 	dp_display->audio_enabled = false;
 
-	/* triggered by irq_hpd with sink_count = 0 */
 	if (dp->link->sink_count == 0) {
+		/*
+		 * irq_hpd with sink_count = 0
+		 * hdmi unplugged out of dongle
+		 */
 		dp_ctrl_off_link_stream(dp->ctrl);
 	} else {
+		/*
+		 * unplugged interrupt
+		 * dongle unplugged out of DUT
+		 */
 		dp_ctrl_off(dp->ctrl);
-		dp->core_initialized = false;
+		dp_display_host_phy_exit(dp);
 	}
 
 	dp_power_panel_on(dp->power, false);
@@ -1059,7 +1096,7 @@  void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp)
 static void dp_display_config_hpd(struct dp_display_private *dp)
 {
 
-	dp_display_host_init(dp, true);
+	dp_display_host_init(dp);
 	dp_catalog_ctrl_hpd_config(dp->catalog);
 
 	/* Enable interrupt first time
@@ -1338,20 +1375,22 @@  static int dp_pm_resume(struct device *dev)
 	dp->hpd_state = ST_DISCONNECTED;
 
 	/* turn on dp ctrl/phy */
-	dp_display_host_init(dp, true);
+	dp_display_host_init(dp);
 
 	dp_catalog_ctrl_hpd_config(dp->catalog);
 
-	/*
-	 * set sink to normal operation mode -- D0
-	 * before dpcd read
-	 */
-	dp_link_psm_config(dp->link, &dp->panel->link_info, false);
-
 	if (dp_catalog_link_is_connected(dp->catalog)) {
+		/*
+		 * set sink to normal operation mode -- D0
+		 * before dpcd read
+		 */
+		dp_display_host_phy_init(dp);
+		dp_link_psm_config(dp->link, &dp->panel->link_info, false);
 		sink_count = drm_dp_read_sink_count(dp->aux);
 		if (sink_count < 0)
 			sink_count = 0;
+
+		dp_display_host_phy_exit(dp);
 	}
 
 	dp->link->sink_count = sink_count;
@@ -1399,6 +1438,8 @@  static int dp_pm_suspend(struct device *dev)
 		dp_display_host_deinit(dp);
 	}
 
+	dp_display_host_phy_exit(dp);
+
 	dp->hpd_state = ST_SUSPENDED;
 
 	/* host_init will be called at pm_resume */
@@ -1473,7 +1514,7 @@  void msm_dp_irq_postinstall(struct msm_dp *dp_display)
 		enable_irq(dp->irq);
 		dp_hpd_connect(dp->usbpd, true);
 	} else {
-		dp_add_event(dp, EV_HPD_INIT_SETUP, 0, dp->id * 10);
+		dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0);
 	}
 }
 
@@ -1567,7 +1608,7 @@  int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
 	state =  dp_display->hpd_state;
 
 	if (state == ST_DISPLAY_OFF)
-		dp_display_host_init(dp_display, true);
+		dp_display_host_phy_init(dp_display);
 
 	dp_display_enable(dp_display, 0);