diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_ctrl.c')
| -rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 90 | 
1 files changed, 88 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index dd26ca651a05..a7a5c7e0ab92 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -22,6 +22,7 @@  #define DP_KHZ_TO_HZ 1000  #define IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES	(30 * HZ / 1000) /* 30 ms */ +#define PSR_OPERATION_COMPLETION_TIMEOUT_JIFFIES       (300 * HZ / 1000) /* 300 ms */  #define WAIT_FOR_VIDEO_READY_TIMEOUT_JIFFIES (HZ / 2)  #define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0) @@ -80,6 +81,7 @@ struct dp_ctrl_private {  	struct dp_catalog *catalog;  	struct completion idle_comp; +	struct completion psr_op_comp;  	struct completion video_comp;  }; @@ -153,6 +155,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)  	config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;  	config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK; +	if (ctrl->panel->psr_cap.version) +		config |= DP_CONFIGURATION_CTRL_SEND_VSC; +  	dp_catalog_ctrl_config_ctrl(ctrl->catalog, config);  } @@ -1375,6 +1380,64 @@ void dp_ctrl_reset_irq_ctrl(struct dp_ctrl *dp_ctrl, bool enable)  	dp_catalog_ctrl_enable_irq(ctrl->catalog, enable);  } +void dp_ctrl_config_psr(struct dp_ctrl *dp_ctrl) +{ +	u8 cfg; +	struct dp_ctrl_private *ctrl = container_of(dp_ctrl, +			struct dp_ctrl_private, dp_ctrl); + +	if (!ctrl->panel->psr_cap.version) +		return; + +	dp_catalog_ctrl_config_psr(ctrl->catalog); + +	cfg = DP_PSR_ENABLE; +	drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1); +} + +void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool enter) +{ +	struct dp_ctrl_private *ctrl = container_of(dp_ctrl, +			struct dp_ctrl_private, dp_ctrl); + +	if (!ctrl->panel->psr_cap.version) +		return; + +	/* +	 * When entering PSR, +	 * 1. Send PSR enter SDP and wait for the PSR_UPDATE_INT +	 * 2. Turn off video +	 * 3. Disable the mainlink +	 * +	 * When exiting PSR, +	 * 1. Enable the mainlink +	 * 2. Send the PSR exit SDP +	 */ +	if (enter) { +		reinit_completion(&ctrl->psr_op_comp); +		dp_catalog_ctrl_set_psr(ctrl->catalog, true); + +		if (!wait_for_completion_timeout(&ctrl->psr_op_comp, +			PSR_OPERATION_COMPLETION_TIMEOUT_JIFFIES)) { +			DRM_ERROR("PSR_ENTRY timedout\n"); +			dp_catalog_ctrl_set_psr(ctrl->catalog, false); +			return; +		} + +		dp_ctrl_push_idle(dp_ctrl); +		dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + +		dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, false); +	} else { +		dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, true); + +		dp_catalog_ctrl_set_psr(ctrl->catalog, false); +		dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); +		dp_ctrl_wait4video_ready(ctrl); +		dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); +	} +} +  void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)  {  	struct dp_ctrl_private *ctrl; @@ -1979,27 +2042,49 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)  	return ret;  } -void dp_ctrl_isr(struct dp_ctrl *dp_ctrl) +irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl)  {  	struct dp_ctrl_private *ctrl;  	u32 isr; +	irqreturn_t ret = IRQ_NONE;  	if (!dp_ctrl) -		return; +		return IRQ_NONE;  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); +	if (ctrl->panel->psr_cap.version) { +		isr = dp_catalog_ctrl_read_psr_interrupt_status(ctrl->catalog); + +		if (isr) +			complete(&ctrl->psr_op_comp); + +		if (isr & PSR_EXIT_INT) +			drm_dbg_dp(ctrl->drm_dev, "PSR exit done\n"); + +		if (isr & PSR_UPDATE_INT) +			drm_dbg_dp(ctrl->drm_dev, "PSR frame update done\n"); + +		if (isr & PSR_CAPTURE_INT) +			drm_dbg_dp(ctrl->drm_dev, "PSR frame capture done\n"); +	} +  	isr = dp_catalog_ctrl_get_interrupt(ctrl->catalog); +  	if (isr & DP_CTRL_INTR_READY_FOR_VIDEO) {  		drm_dbg_dp(ctrl->drm_dev, "dp_video_ready\n");  		complete(&ctrl->video_comp); +		ret = IRQ_HANDLED;  	}  	if (isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) {  		drm_dbg_dp(ctrl->drm_dev, "idle_patterns_sent\n");  		complete(&ctrl->idle_comp); +		ret = IRQ_HANDLED;  	} + +	return ret;  }  struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, @@ -2035,6 +2120,7 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,  		dev_err(dev, "failed to add DP OPP table\n");  	init_completion(&ctrl->idle_comp); +	init_completion(&ctrl->psr_op_comp);  	init_completion(&ctrl->video_comp);  	/* in parameters */  |