12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23424e3a4SYakir Yang /*
33424e3a4SYakir Yang * Analogix DP (Display Port) core interface driver.
43424e3a4SYakir Yang *
53424e3a4SYakir Yang * Copyright (C) 2012 Samsung Electronics Co., Ltd.
63424e3a4SYakir Yang * Author: Jingoo Han <jg1.han@samsung.com>
73424e3a4SYakir Yang */
83424e3a4SYakir Yang 
93424e3a4SYakir Yang #include <linux/clk.h>
1095b60804SSam Ravnborg #include <linux/component.h>
1195b60804SSam Ravnborg #include <linux/err.h>
125b038dcfSLinus Walleij #include <linux/gpio/consumer.h>
1395b60804SSam Ravnborg #include <linux/interrupt.h>
143424e3a4SYakir Yang #include <linux/io.h>
15f9d56805Szain wang #include <linux/iopoll.h>
1695b60804SSam Ravnborg #include <linux/module.h>
173424e3a4SYakir Yang #include <linux/of.h>
183424e3a4SYakir Yang #include <linux/phy/phy.h>
1995b60804SSam Ravnborg #include <linux/platform_device.h>
203424e3a4SYakir Yang 
213424e3a4SYakir Yang #include <drm/bridge/analogix_dp.h>
226c836d96SSean Paul #include <drm/drm_atomic.h>
2395b60804SSam Ravnborg #include <drm/drm_atomic_helper.h>
24ee68c743SBoris Brezillon #include <drm/drm_bridge.h>
2595b60804SSam Ravnborg #include <drm/drm_crtc.h>
2695b60804SSam Ravnborg #include <drm/drm_device.h>
27*255490f9SVille Syrjälä #include <drm/drm_edid.h>
2895b60804SSam Ravnborg #include <drm/drm_panel.h>
2995b60804SSam Ravnborg #include <drm/drm_print.h>
3095b60804SSam Ravnborg #include <drm/drm_probe_helper.h>
313424e3a4SYakir Yang 
323424e3a4SYakir Yang #include "analogix_dp_core.h"
330d97ad03STomeu Vizoso #include "analogix_dp_reg.h"
343424e3a4SYakir Yang 
353424e3a4SYakir Yang #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
363424e3a4SYakir Yang 
37f9d56805Szain wang static const bool verify_fast_training;
38f9d56805Szain wang 
393424e3a4SYakir Yang struct bridge_init {
403424e3a4SYakir Yang 	struct i2c_client *client;
413424e3a4SYakir Yang 	struct device_node *node;
423424e3a4SYakir Yang };
433424e3a4SYakir Yang 
analogix_dp_init_dp(struct analogix_dp_device * dp)448a335736Szain wang static int analogix_dp_init_dp(struct analogix_dp_device *dp)
453424e3a4SYakir Yang {
468a335736Szain wang 	int ret;
478a335736Szain wang 
483424e3a4SYakir Yang 	analogix_dp_reset(dp);
493424e3a4SYakir Yang 
503424e3a4SYakir Yang 	analogix_dp_swreset(dp);
513424e3a4SYakir Yang 
523424e3a4SYakir Yang 	analogix_dp_init_analog_param(dp);
533424e3a4SYakir Yang 	analogix_dp_init_interrupt(dp);
543424e3a4SYakir Yang 
553424e3a4SYakir Yang 	/* SW defined function Normal operation */
563424e3a4SYakir Yang 	analogix_dp_enable_sw_function(dp);
573424e3a4SYakir Yang 
583424e3a4SYakir Yang 	analogix_dp_config_interrupt(dp);
598a335736Szain wang 	ret = analogix_dp_init_analog_func(dp);
608a335736Szain wang 	if (ret)
618a335736Szain wang 		return ret;
623424e3a4SYakir Yang 
633424e3a4SYakir Yang 	analogix_dp_init_hpd(dp);
643424e3a4SYakir Yang 	analogix_dp_init_aux(dp);
658a335736Szain wang 	return 0;
663424e3a4SYakir Yang }
673424e3a4SYakir Yang 
analogix_dp_detect_hpd(struct analogix_dp_device * dp)683424e3a4SYakir Yang static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
693424e3a4SYakir Yang {
703424e3a4SYakir Yang 	int timeout_loop = 0;
713424e3a4SYakir Yang 
725cff007cSYakir Yang 	while (timeout_loop < DP_TIMEOUT_LOOP_COUNT) {
735cff007cSYakir Yang 		if (analogix_dp_get_plug_in_status(dp) == 0)
745cff007cSYakir Yang 			return 0;
755cff007cSYakir Yang 
763424e3a4SYakir Yang 		timeout_loop++;
77606c5e64SLin Huang 		usleep_range(1000, 1100);
783424e3a4SYakir Yang 	}
793424e3a4SYakir Yang 
805cff007cSYakir Yang 	/*
815cff007cSYakir Yang 	 * Some edp screen do not have hpd signal, so we can't just
825cff007cSYakir Yang 	 * return failed when hpd plug in detect failed, DT property
835cff007cSYakir Yang 	 * "force-hpd" would indicate whether driver need this.
845cff007cSYakir Yang 	 */
855cff007cSYakir Yang 	if (!dp->force_hpd)
865cff007cSYakir Yang 		return -ETIMEDOUT;
875cff007cSYakir Yang 
885cff007cSYakir Yang 	/*
895cff007cSYakir Yang 	 * The eDP TRM indicate that if HPD_STATUS(RO) is 0, AUX CH
905cff007cSYakir Yang 	 * will not work, so we need to give a force hpd action to
915cff007cSYakir Yang 	 * set HPD_STATUS manually.
925cff007cSYakir Yang 	 */
935cff007cSYakir Yang 	dev_dbg(dp->dev, "failed to get hpd plug status, try to force hpd\n");
945cff007cSYakir Yang 
955cff007cSYakir Yang 	analogix_dp_force_hpd(dp);
965cff007cSYakir Yang 
975cff007cSYakir Yang 	if (analogix_dp_get_plug_in_status(dp) != 0) {
985cff007cSYakir Yang 		dev_err(dp->dev, "failed to get hpd plug in status\n");
995cff007cSYakir Yang 		return -EINVAL;
1005cff007cSYakir Yang 	}
1015cff007cSYakir Yang 
1025cff007cSYakir Yang 	dev_dbg(dp->dev, "success to get plug in status after force hpd\n");
1035cff007cSYakir Yang 
1043424e3a4SYakir Yang 	return 0;
1053424e3a4SYakir Yang }
1063424e3a4SYakir Yang 
analogix_dp_detect_sink_psr(struct analogix_dp_device * dp)1076c836d96SSean Paul static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
1085b3f84f2SYakir Yang {
1095b3f84f2SYakir Yang 	unsigned char psr_version;
110ccdc578bSLin Huang 	int ret;
1115b3f84f2SYakir Yang 
112ccdc578bSLin Huang 	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
113ccdc578bSLin Huang 	if (ret != 1) {
114ccdc578bSLin Huang 		dev_err(dp->dev, "failed to get PSR version, disable it\n");
1156c836d96SSean Paul 		return false;
1165b3f84f2SYakir Yang 	}
1175b3f84f2SYakir Yang 
118ccdc578bSLin Huang 	dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
1196c836d96SSean Paul 	return psr_version & DP_PSR_IS_SUPPORTED;
120ccdc578bSLin Huang }
121ccdc578bSLin Huang 
analogix_dp_enable_sink_psr(struct analogix_dp_device * dp)122ccdc578bSLin Huang static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
1235b3f84f2SYakir Yang {
1245b3f84f2SYakir Yang 	unsigned char psr_en;
125ccdc578bSLin Huang 	int ret;
1265b3f84f2SYakir Yang 
1275b3f84f2SYakir Yang 	/* Disable psr function */
128ccdc578bSLin Huang 	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
129ccdc578bSLin Huang 	if (ret != 1) {
130ccdc578bSLin Huang 		dev_err(dp->dev, "failed to get psr config\n");
131ccdc578bSLin Huang 		goto end;
132ccdc578bSLin Huang 	}
133ccdc578bSLin Huang 
1345b3f84f2SYakir Yang 	psr_en &= ~DP_PSR_ENABLE;
135ccdc578bSLin Huang 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
136ccdc578bSLin Huang 	if (ret != 1) {
137ccdc578bSLin Huang 		dev_err(dp->dev, "failed to disable panel psr\n");
138ccdc578bSLin Huang 		goto end;
139ccdc578bSLin Huang 	}
1405b3f84f2SYakir Yang 
1415b3f84f2SYakir Yang 	/* Main-Link transmitter remains active during PSR active states */
1426c836d96SSean Paul 	psr_en = DP_PSR_CRC_VERIFICATION;
143ccdc578bSLin Huang 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
144ccdc578bSLin Huang 	if (ret != 1) {
145ccdc578bSLin Huang 		dev_err(dp->dev, "failed to set panel psr\n");
146ccdc578bSLin Huang 		goto end;
147ccdc578bSLin Huang 	}
1485b3f84f2SYakir Yang 
1495b3f84f2SYakir Yang 	/* Enable psr function */
1506c836d96SSean Paul 	psr_en = DP_PSR_ENABLE | DP_PSR_CRC_VERIFICATION;
151ccdc578bSLin Huang 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
152ccdc578bSLin Huang 	if (ret != 1) {
153ccdc578bSLin Huang 		dev_err(dp->dev, "failed to set panel psr\n");
154ccdc578bSLin Huang 		goto end;
1555b3f84f2SYakir Yang 	}
1565b3f84f2SYakir Yang 
157ccdc578bSLin Huang 	analogix_dp_enable_psr_crc(dp);
158ccdc578bSLin Huang 
1596c836d96SSean Paul 	dp->psr_supported = true;
1606c836d96SSean Paul 
161ccdc578bSLin Huang 	return 0;
162ccdc578bSLin Huang end:
163ccdc578bSLin Huang 	dev_err(dp->dev, "enable psr fail, force to disable psr\n");
164ccdc578bSLin Huang 
165ccdc578bSLin Huang 	return ret;
166ccdc578bSLin Huang }
167ccdc578bSLin Huang 
168ccdc578bSLin Huang static int
analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device * dp,bool enable)169bcbb7033SYakir Yang analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
1703424e3a4SYakir Yang 				       bool enable)
1713424e3a4SYakir Yang {
1723424e3a4SYakir Yang 	u8 data;
173ccdc578bSLin Huang 	int ret;
1743424e3a4SYakir Yang 
175ccdc578bSLin Huang 	ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
176ccdc578bSLin Huang 	if (ret != 1)
177ccdc578bSLin Huang 		return ret;
1783424e3a4SYakir Yang 
1793424e3a4SYakir Yang 	if (enable)
180ccdc578bSLin Huang 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
1813424e3a4SYakir Yang 					 DP_LANE_COUNT_ENHANCED_FRAME_EN |
1823424e3a4SYakir Yang 					 DPCD_LANE_COUNT_SET(data));
1833424e3a4SYakir Yang 	else
184ccdc578bSLin Huang 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
1853424e3a4SYakir Yang 					 DPCD_LANE_COUNT_SET(data));
186ccdc578bSLin Huang 
187ccdc578bSLin Huang 	return ret < 0 ? ret : 0;
1883424e3a4SYakir Yang }
1893424e3a4SYakir Yang 
analogix_dp_is_enhanced_mode_available(struct analogix_dp_device * dp,u8 * enhanced_mode_support)190ccdc578bSLin Huang static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp,
191ccdc578bSLin Huang 						  u8 *enhanced_mode_support)
1923424e3a4SYakir Yang {
1933424e3a4SYakir Yang 	u8 data;
194ccdc578bSLin Huang 	int ret;
1953424e3a4SYakir Yang 
196ccdc578bSLin Huang 	ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
197ccdc578bSLin Huang 	if (ret != 1) {
198ccdc578bSLin Huang 		*enhanced_mode_support = 0;
199ccdc578bSLin Huang 		return ret;
2003424e3a4SYakir Yang 	}
2013424e3a4SYakir Yang 
202ccdc578bSLin Huang 	*enhanced_mode_support = DPCD_ENHANCED_FRAME_CAP(data);
203ccdc578bSLin Huang 
204ccdc578bSLin Huang 	return 0;
205ccdc578bSLin Huang }
206ccdc578bSLin Huang 
analogix_dp_set_enhanced_mode(struct analogix_dp_device * dp)207ccdc578bSLin Huang static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
2083424e3a4SYakir Yang {
2093424e3a4SYakir Yang 	u8 data;
210ccdc578bSLin Huang 	int ret;
2113424e3a4SYakir Yang 
212ccdc578bSLin Huang 	ret = analogix_dp_is_enhanced_mode_available(dp, &data);
213ccdc578bSLin Huang 	if (ret < 0)
214ccdc578bSLin Huang 		return ret;
215ccdc578bSLin Huang 
216ccdc578bSLin Huang 	ret = analogix_dp_enable_rx_to_enhanced_mode(dp, data);
217ccdc578bSLin Huang 	if (ret < 0)
218ccdc578bSLin Huang 		return ret;
219ccdc578bSLin Huang 
2203424e3a4SYakir Yang 	analogix_dp_enable_enhanced_mode(dp, data);
221ccdc578bSLin Huang 
222ccdc578bSLin Huang 	return 0;
2233424e3a4SYakir Yang }
2243424e3a4SYakir Yang 
analogix_dp_training_pattern_dis(struct analogix_dp_device * dp)225ccdc578bSLin Huang static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
2263424e3a4SYakir Yang {
227ccdc578bSLin Huang 	int ret;
228ccdc578bSLin Huang 
2293424e3a4SYakir Yang 	analogix_dp_set_training_pattern(dp, DP_NONE);
2303424e3a4SYakir Yang 
231ccdc578bSLin Huang 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
2323424e3a4SYakir Yang 				 DP_TRAINING_PATTERN_DISABLE);
233ccdc578bSLin Huang 
234ccdc578bSLin Huang 	return ret < 0 ? ret : 0;
2353424e3a4SYakir Yang }
2363424e3a4SYakir Yang 
237bcbb7033SYakir Yang static void
analogix_dp_set_lane_lane_pre_emphasis(struct analogix_dp_device * dp,int pre_emphasis,int lane)238bcbb7033SYakir Yang analogix_dp_set_lane_lane_pre_emphasis(struct analogix_dp_device *dp,
2393424e3a4SYakir Yang 				       int pre_emphasis, int lane)
2403424e3a4SYakir Yang {
2413424e3a4SYakir Yang 	switch (lane) {
2423424e3a4SYakir Yang 	case 0:
2433424e3a4SYakir Yang 		analogix_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
2443424e3a4SYakir Yang 		break;
2453424e3a4SYakir Yang 	case 1:
2463424e3a4SYakir Yang 		analogix_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
2473424e3a4SYakir Yang 		break;
2483424e3a4SYakir Yang 
2493424e3a4SYakir Yang 	case 2:
2503424e3a4SYakir Yang 		analogix_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
2513424e3a4SYakir Yang 		break;
2523424e3a4SYakir Yang 
2533424e3a4SYakir Yang 	case 3:
2543424e3a4SYakir Yang 		analogix_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
2553424e3a4SYakir Yang 		break;
2563424e3a4SYakir Yang 	}
2573424e3a4SYakir Yang }
2583424e3a4SYakir Yang 
analogix_dp_link_start(struct analogix_dp_device * dp)2593424e3a4SYakir Yang static int analogix_dp_link_start(struct analogix_dp_device *dp)
2603424e3a4SYakir Yang {
2613424e3a4SYakir Yang 	u8 buf[4];
2623424e3a4SYakir Yang 	int lane, lane_count, pll_tries, retval;
2633424e3a4SYakir Yang 
2643424e3a4SYakir Yang 	lane_count = dp->link_train.lane_count;
2653424e3a4SYakir Yang 
2663424e3a4SYakir Yang 	dp->link_train.lt_state = CLOCK_RECOVERY;
2673424e3a4SYakir Yang 	dp->link_train.eq_loop = 0;
2683424e3a4SYakir Yang 
2693424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++)
2703424e3a4SYakir Yang 		dp->link_train.cr_loop[lane] = 0;
2713424e3a4SYakir Yang 
2723424e3a4SYakir Yang 	/* Set link rate and count as you want to establish*/
2733424e3a4SYakir Yang 	analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
2743424e3a4SYakir Yang 	analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
2753424e3a4SYakir Yang 
2763424e3a4SYakir Yang 	/* Setup RX configuration */
2773424e3a4SYakir Yang 	buf[0] = dp->link_train.link_rate;
2783424e3a4SYakir Yang 	buf[1] = dp->link_train.lane_count;
2790d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
2800d97ad03STomeu Vizoso 	if (retval < 0)
2813424e3a4SYakir Yang 		return retval;
2821932250dSzain wang 	/* set enhanced mode if available */
283ccdc578bSLin Huang 	retval = analogix_dp_set_enhanced_mode(dp);
284ccdc578bSLin Huang 	if (retval < 0) {
285ccdc578bSLin Huang 		dev_err(dp->dev, "failed to set enhance mode\n");
286ccdc578bSLin Huang 		return retval;
287ccdc578bSLin Huang 	}
2883424e3a4SYakir Yang 
2893424e3a4SYakir Yang 	/* Set TX pre-emphasis to minimum */
2903424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++)
2913424e3a4SYakir Yang 		analogix_dp_set_lane_lane_pre_emphasis(dp,
2923424e3a4SYakir Yang 			PRE_EMPHASIS_LEVEL_0, lane);
2933424e3a4SYakir Yang 
2943424e3a4SYakir Yang 	/* Wait for PLL lock */
2953424e3a4SYakir Yang 	pll_tries = 0;
2963424e3a4SYakir Yang 	while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
2973424e3a4SYakir Yang 		if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
2983424e3a4SYakir Yang 			dev_err(dp->dev, "Wait for PLL lock timed out\n");
2993424e3a4SYakir Yang 			return -ETIMEDOUT;
3003424e3a4SYakir Yang 		}
3013424e3a4SYakir Yang 
3023424e3a4SYakir Yang 		pll_tries++;
3033424e3a4SYakir Yang 		usleep_range(90, 120);
3043424e3a4SYakir Yang 	}
3053424e3a4SYakir Yang 
3063424e3a4SYakir Yang 	/* Set training pattern 1 */
3073424e3a4SYakir Yang 	analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
3083424e3a4SYakir Yang 
3093424e3a4SYakir Yang 	/* Set RX training pattern */
3100d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
3110d97ad03STomeu Vizoso 				    DP_LINK_SCRAMBLING_DISABLE |
3120d97ad03STomeu Vizoso 					DP_TRAINING_PATTERN_1);
3130d97ad03STomeu Vizoso 	if (retval < 0)
3143424e3a4SYakir Yang 		return retval;
3153424e3a4SYakir Yang 
3163424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++)
3173424e3a4SYakir Yang 		buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
3183424e3a4SYakir Yang 			    DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
3193424e3a4SYakir Yang 
3200d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf,
3210d97ad03STomeu Vizoso 				   lane_count);
3220d97ad03STomeu Vizoso 	if (retval < 0)
3233424e3a4SYakir Yang 		return retval;
3240d97ad03STomeu Vizoso 
3250d97ad03STomeu Vizoso 	return 0;
3263424e3a4SYakir Yang }
3273424e3a4SYakir Yang 
analogix_dp_get_lane_status(u8 link_status[2],int lane)3283424e3a4SYakir Yang static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane)
3293424e3a4SYakir Yang {
3303424e3a4SYakir Yang 	int shift = (lane & 1) * 4;
3313424e3a4SYakir Yang 	u8 link_value = link_status[lane >> 1];
3323424e3a4SYakir Yang 
3333424e3a4SYakir Yang 	return (link_value >> shift) & 0xf;
3343424e3a4SYakir Yang }
3353424e3a4SYakir Yang 
analogix_dp_clock_recovery_ok(u8 link_status[2],int lane_count)3363424e3a4SYakir Yang static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
3373424e3a4SYakir Yang {
3383424e3a4SYakir Yang 	int lane;
3393424e3a4SYakir Yang 	u8 lane_status;
3403424e3a4SYakir Yang 
3413424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++) {
3423424e3a4SYakir Yang 		lane_status = analogix_dp_get_lane_status(link_status, lane);
3433424e3a4SYakir Yang 		if ((lane_status & DP_LANE_CR_DONE) == 0)
3443424e3a4SYakir Yang 			return -EINVAL;
3453424e3a4SYakir Yang 	}
3463424e3a4SYakir Yang 	return 0;
3473424e3a4SYakir Yang }
3483424e3a4SYakir Yang 
analogix_dp_channel_eq_ok(u8 link_status[2],u8 link_align,int lane_count)3493424e3a4SYakir Yang static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
3503424e3a4SYakir Yang 				     int lane_count)
3513424e3a4SYakir Yang {
3523424e3a4SYakir Yang 	int lane;
3533424e3a4SYakir Yang 	u8 lane_status;
3543424e3a4SYakir Yang 
3553424e3a4SYakir Yang 	if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0)
3563424e3a4SYakir Yang 		return -EINVAL;
3573424e3a4SYakir Yang 
3583424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++) {
3593424e3a4SYakir Yang 		lane_status = analogix_dp_get_lane_status(link_status, lane);
3603424e3a4SYakir Yang 		lane_status &= DP_CHANNEL_EQ_BITS;
3613424e3a4SYakir Yang 		if (lane_status != DP_CHANNEL_EQ_BITS)
3623424e3a4SYakir Yang 			return -EINVAL;
3633424e3a4SYakir Yang 	}
3643424e3a4SYakir Yang 
3653424e3a4SYakir Yang 	return 0;
3663424e3a4SYakir Yang }
3673424e3a4SYakir Yang 
368bcbb7033SYakir Yang static unsigned char
analogix_dp_get_adjust_request_voltage(u8 adjust_request[2],int lane)369bcbb7033SYakir Yang analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane)
3703424e3a4SYakir Yang {
3713424e3a4SYakir Yang 	int shift = (lane & 1) * 4;
3723424e3a4SYakir Yang 	u8 link_value = adjust_request[lane >> 1];
3733424e3a4SYakir Yang 
3743424e3a4SYakir Yang 	return (link_value >> shift) & 0x3;
3753424e3a4SYakir Yang }
3763424e3a4SYakir Yang 
analogix_dp_get_adjust_request_pre_emphasis(u8 adjust_request[2],int lane)3773424e3a4SYakir Yang static unsigned char analogix_dp_get_adjust_request_pre_emphasis(
3783424e3a4SYakir Yang 					u8 adjust_request[2],
3793424e3a4SYakir Yang 					int lane)
3803424e3a4SYakir Yang {
3813424e3a4SYakir Yang 	int shift = (lane & 1) * 4;
3823424e3a4SYakir Yang 	u8 link_value = adjust_request[lane >> 1];
3833424e3a4SYakir Yang 
3843424e3a4SYakir Yang 	return ((link_value >> shift) & 0xc) >> 2;
3853424e3a4SYakir Yang }
3863424e3a4SYakir Yang 
analogix_dp_set_lane_link_training(struct analogix_dp_device * dp,u8 training_lane_set,int lane)3873424e3a4SYakir Yang static void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp,
3883424e3a4SYakir Yang 					       u8 training_lane_set, int lane)
3893424e3a4SYakir Yang {
3903424e3a4SYakir Yang 	switch (lane) {
3913424e3a4SYakir Yang 	case 0:
3923424e3a4SYakir Yang 		analogix_dp_set_lane0_link_training(dp, training_lane_set);
3933424e3a4SYakir Yang 		break;
3943424e3a4SYakir Yang 	case 1:
3953424e3a4SYakir Yang 		analogix_dp_set_lane1_link_training(dp, training_lane_set);
3963424e3a4SYakir Yang 		break;
3973424e3a4SYakir Yang 
3983424e3a4SYakir Yang 	case 2:
3993424e3a4SYakir Yang 		analogix_dp_set_lane2_link_training(dp, training_lane_set);
4003424e3a4SYakir Yang 		break;
4013424e3a4SYakir Yang 
4023424e3a4SYakir Yang 	case 3:
4033424e3a4SYakir Yang 		analogix_dp_set_lane3_link_training(dp, training_lane_set);
4043424e3a4SYakir Yang 		break;
4053424e3a4SYakir Yang 	}
4063424e3a4SYakir Yang }
4073424e3a4SYakir Yang 
408bcbb7033SYakir Yang static unsigned int
analogix_dp_get_lane_link_training(struct analogix_dp_device * dp,int lane)409bcbb7033SYakir Yang analogix_dp_get_lane_link_training(struct analogix_dp_device *dp,
4103424e3a4SYakir Yang 				   int lane)
4113424e3a4SYakir Yang {
4123424e3a4SYakir Yang 	u32 reg;
4133424e3a4SYakir Yang 
4143424e3a4SYakir Yang 	switch (lane) {
4153424e3a4SYakir Yang 	case 0:
4163424e3a4SYakir Yang 		reg = analogix_dp_get_lane0_link_training(dp);
4173424e3a4SYakir Yang 		break;
4183424e3a4SYakir Yang 	case 1:
4193424e3a4SYakir Yang 		reg = analogix_dp_get_lane1_link_training(dp);
4203424e3a4SYakir Yang 		break;
4213424e3a4SYakir Yang 	case 2:
4223424e3a4SYakir Yang 		reg = analogix_dp_get_lane2_link_training(dp);
4233424e3a4SYakir Yang 		break;
4243424e3a4SYakir Yang 	case 3:
4253424e3a4SYakir Yang 		reg = analogix_dp_get_lane3_link_training(dp);
4263424e3a4SYakir Yang 		break;
4273424e3a4SYakir Yang 	default:
4283424e3a4SYakir Yang 		WARN_ON(1);
4293424e3a4SYakir Yang 		return 0;
4303424e3a4SYakir Yang 	}
4313424e3a4SYakir Yang 
4323424e3a4SYakir Yang 	return reg;
4333424e3a4SYakir Yang }
4343424e3a4SYakir Yang 
analogix_dp_reduce_link_rate(struct analogix_dp_device * dp)4353424e3a4SYakir Yang static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp)
4363424e3a4SYakir Yang {
4373424e3a4SYakir Yang 	analogix_dp_training_pattern_dis(dp);
4383424e3a4SYakir Yang 	analogix_dp_set_enhanced_mode(dp);
4393424e3a4SYakir Yang 
4403424e3a4SYakir Yang 	dp->link_train.lt_state = FAILED;
4413424e3a4SYakir Yang }
4423424e3a4SYakir Yang 
analogix_dp_get_adjust_training_lane(struct analogix_dp_device * dp,u8 adjust_request[2])4433424e3a4SYakir Yang static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp,
4443424e3a4SYakir Yang 						 u8 adjust_request[2])
4453424e3a4SYakir Yang {
4463424e3a4SYakir Yang 	int lane, lane_count;
4473424e3a4SYakir Yang 	u8 voltage_swing, pre_emphasis, training_lane;
4483424e3a4SYakir Yang 
4493424e3a4SYakir Yang 	lane_count = dp->link_train.lane_count;
4503424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++) {
4513424e3a4SYakir Yang 		voltage_swing = analogix_dp_get_adjust_request_voltage(
4523424e3a4SYakir Yang 						adjust_request, lane);
4533424e3a4SYakir Yang 		pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(
4543424e3a4SYakir Yang 						adjust_request, lane);
4553424e3a4SYakir Yang 		training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
4563424e3a4SYakir Yang 				DPCD_PRE_EMPHASIS_SET(pre_emphasis);
4573424e3a4SYakir Yang 
4583424e3a4SYakir Yang 		if (voltage_swing == VOLTAGE_LEVEL_3)
4593424e3a4SYakir Yang 			training_lane |= DP_TRAIN_MAX_SWING_REACHED;
4603424e3a4SYakir Yang 		if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
4613424e3a4SYakir Yang 			training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
4623424e3a4SYakir Yang 
4633424e3a4SYakir Yang 		dp->link_train.training_lane[lane] = training_lane;
4643424e3a4SYakir Yang 	}
4653424e3a4SYakir Yang }
4663424e3a4SYakir Yang 
analogix_dp_process_clock_recovery(struct analogix_dp_device * dp)4673424e3a4SYakir Yang static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
4683424e3a4SYakir Yang {
4693424e3a4SYakir Yang 	int lane, lane_count, retval;
4703424e3a4SYakir Yang 	u8 voltage_swing, pre_emphasis, training_lane;
4713424e3a4SYakir Yang 	u8 link_status[2], adjust_request[2];
4723424e3a4SYakir Yang 
4733424e3a4SYakir Yang 	usleep_range(100, 101);
4743424e3a4SYakir Yang 
4753424e3a4SYakir Yang 	lane_count = dp->link_train.lane_count;
4763424e3a4SYakir Yang 
4770d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
4780d97ad03STomeu Vizoso 	if (retval < 0)
4793424e3a4SYakir Yang 		return retval;
4803424e3a4SYakir Yang 
4810d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1,
4820d97ad03STomeu Vizoso 				  adjust_request, 2);
4830d97ad03STomeu Vizoso 	if (retval < 0)
4843424e3a4SYakir Yang 		return retval;
4853424e3a4SYakir Yang 
4863424e3a4SYakir Yang 	if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) {
4873424e3a4SYakir Yang 		/* set training pattern 2 for EQ */
4883424e3a4SYakir Yang 		analogix_dp_set_training_pattern(dp, TRAINING_PTN2);
4893424e3a4SYakir Yang 
4900d97ad03STomeu Vizoso 		retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
4913424e3a4SYakir Yang 					    DP_LINK_SCRAMBLING_DISABLE |
4923424e3a4SYakir Yang 						DP_TRAINING_PATTERN_2);
4930d97ad03STomeu Vizoso 		if (retval < 0)
4943424e3a4SYakir Yang 			return retval;
4953424e3a4SYakir Yang 
496eb1d23d7SMarc Zyngier 		dev_dbg(dp->dev, "Link Training Clock Recovery success\n");
4973424e3a4SYakir Yang 		dp->link_train.lt_state = EQUALIZER_TRAINING;
4983424e3a4SYakir Yang 	} else {
4993424e3a4SYakir Yang 		for (lane = 0; lane < lane_count; lane++) {
5003424e3a4SYakir Yang 			training_lane = analogix_dp_get_lane_link_training(
5013424e3a4SYakir Yang 							dp, lane);
5023424e3a4SYakir Yang 			voltage_swing = analogix_dp_get_adjust_request_voltage(
5033424e3a4SYakir Yang 							adjust_request, lane);
5043424e3a4SYakir Yang 			pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(
5053424e3a4SYakir Yang 							adjust_request, lane);
5063424e3a4SYakir Yang 
5073424e3a4SYakir Yang 			if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
5083424e3a4SYakir Yang 					voltage_swing &&
5093424e3a4SYakir Yang 			    DPCD_PRE_EMPHASIS_GET(training_lane) ==
5103424e3a4SYakir Yang 					pre_emphasis)
5113424e3a4SYakir Yang 				dp->link_train.cr_loop[lane]++;
5123424e3a4SYakir Yang 
5133424e3a4SYakir Yang 			if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
5143424e3a4SYakir Yang 			    voltage_swing == VOLTAGE_LEVEL_3 ||
5153424e3a4SYakir Yang 			    pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
5163424e3a4SYakir Yang 				dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
5173424e3a4SYakir Yang 					dp->link_train.cr_loop[lane],
5183424e3a4SYakir Yang 					voltage_swing, pre_emphasis);
5193424e3a4SYakir Yang 				analogix_dp_reduce_link_rate(dp);
5203424e3a4SYakir Yang 				return -EIO;
5213424e3a4SYakir Yang 			}
5223424e3a4SYakir Yang 		}
5233424e3a4SYakir Yang 	}
5243424e3a4SYakir Yang 
5253424e3a4SYakir Yang 	analogix_dp_get_adjust_training_lane(dp, adjust_request);
5263424e3a4SYakir Yang 
5273424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++)
5283424e3a4SYakir Yang 		analogix_dp_set_lane_link_training(dp,
5293424e3a4SYakir Yang 			dp->link_train.training_lane[lane], lane);
5303424e3a4SYakir Yang 
5310d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
5320d97ad03STomeu Vizoso 				   dp->link_train.training_lane, lane_count);
5330d97ad03STomeu Vizoso 	if (retval < 0)
5343424e3a4SYakir Yang 		return retval;
5353424e3a4SYakir Yang 
5360d97ad03STomeu Vizoso 	return 0;
5373424e3a4SYakir Yang }
5383424e3a4SYakir Yang 
analogix_dp_process_equalizer_training(struct analogix_dp_device * dp)5393424e3a4SYakir Yang static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
5403424e3a4SYakir Yang {
5413424e3a4SYakir Yang 	int lane, lane_count, retval;
5423424e3a4SYakir Yang 	u32 reg;
5436f4638a1Szain wang 	u8 link_align, link_status[2], adjust_request[2];
5443424e3a4SYakir Yang 
5453424e3a4SYakir Yang 	usleep_range(400, 401);
5463424e3a4SYakir Yang 
5473424e3a4SYakir Yang 	lane_count = dp->link_train.lane_count;
5483424e3a4SYakir Yang 
5490d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
5500d97ad03STomeu Vizoso 	if (retval < 0)
5513424e3a4SYakir Yang 		return retval;
5523424e3a4SYakir Yang 
5533424e3a4SYakir Yang 	if (analogix_dp_clock_recovery_ok(link_status, lane_count)) {
5543424e3a4SYakir Yang 		analogix_dp_reduce_link_rate(dp);
5553424e3a4SYakir Yang 		return -EIO;
5563424e3a4SYakir Yang 	}
5573424e3a4SYakir Yang 
5580d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1,
5590d97ad03STomeu Vizoso 				  adjust_request, 2);
5600d97ad03STomeu Vizoso 	if (retval < 0)
5613424e3a4SYakir Yang 		return retval;
5623424e3a4SYakir Yang 
5630d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED,
5640d97ad03STomeu Vizoso 				   &link_align);
5650d97ad03STomeu Vizoso 	if (retval < 0)
5663424e3a4SYakir Yang 		return retval;
5673424e3a4SYakir Yang 
5683424e3a4SYakir Yang 	analogix_dp_get_adjust_training_lane(dp, adjust_request);
5693424e3a4SYakir Yang 
5703424e3a4SYakir Yang 	if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) {
5713424e3a4SYakir Yang 		/* traing pattern Set to Normal */
572ccdc578bSLin Huang 		retval = analogix_dp_training_pattern_dis(dp);
573ccdc578bSLin Huang 		if (retval < 0)
574ccdc578bSLin Huang 			return retval;
5753424e3a4SYakir Yang 
576eb1d23d7SMarc Zyngier 		dev_dbg(dp->dev, "Link Training success!\n");
5773424e3a4SYakir Yang 		analogix_dp_get_link_bandwidth(dp, &reg);
5783424e3a4SYakir Yang 		dp->link_train.link_rate = reg;
5793424e3a4SYakir Yang 		dev_dbg(dp->dev, "final bandwidth = %.2x\n",
5803424e3a4SYakir Yang 			dp->link_train.link_rate);
5813424e3a4SYakir Yang 
5823424e3a4SYakir Yang 		analogix_dp_get_lane_count(dp, &reg);
5833424e3a4SYakir Yang 		dp->link_train.lane_count = reg;
5843424e3a4SYakir Yang 		dev_dbg(dp->dev, "final lane count = %.2x\n",
5853424e3a4SYakir Yang 			dp->link_train.lane_count);
5863424e3a4SYakir Yang 
5873424e3a4SYakir Yang 		dp->link_train.lt_state = FINISHED;
5883424e3a4SYakir Yang 
5893424e3a4SYakir Yang 		return 0;
5903424e3a4SYakir Yang 	}
5913424e3a4SYakir Yang 
5923424e3a4SYakir Yang 	/* not all locked */
5933424e3a4SYakir Yang 	dp->link_train.eq_loop++;
5943424e3a4SYakir Yang 
5953424e3a4SYakir Yang 	if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
5963424e3a4SYakir Yang 		dev_err(dp->dev, "EQ Max loop\n");
5973424e3a4SYakir Yang 		analogix_dp_reduce_link_rate(dp);
5983424e3a4SYakir Yang 		return -EIO;
5993424e3a4SYakir Yang 	}
6003424e3a4SYakir Yang 
6013424e3a4SYakir Yang 	for (lane = 0; lane < lane_count; lane++)
6023424e3a4SYakir Yang 		analogix_dp_set_lane_link_training(dp,
6033424e3a4SYakir Yang 			dp->link_train.training_lane[lane], lane);
6043424e3a4SYakir Yang 
6050d97ad03STomeu Vizoso 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
6060d97ad03STomeu Vizoso 				   dp->link_train.training_lane, lane_count);
6070d97ad03STomeu Vizoso 	if (retval < 0)
6083424e3a4SYakir Yang 		return retval;
6090d97ad03STomeu Vizoso 
6100d97ad03STomeu Vizoso 	return 0;
6113424e3a4SYakir Yang }
6123424e3a4SYakir Yang 
analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device * dp,u8 * bandwidth)6133424e3a4SYakir Yang static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp,
6143424e3a4SYakir Yang 					     u8 *bandwidth)
6153424e3a4SYakir Yang {
6163424e3a4SYakir Yang 	u8 data;
6173424e3a4SYakir Yang 
6183424e3a4SYakir Yang 	/*
6193424e3a4SYakir Yang 	 * For DP rev.1.1, Maximum link rate of Main Link lanes
6203424e3a4SYakir Yang 	 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
62140fc7ce7SYakir Yang 	 * For DP rev.1.2, Maximum link rate of Main Link lanes
62240fc7ce7SYakir Yang 	 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps
6233424e3a4SYakir Yang 	 */
6240d97ad03STomeu Vizoso 	drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data);
6253424e3a4SYakir Yang 	*bandwidth = data;
6263424e3a4SYakir Yang }
6273424e3a4SYakir Yang 
analogix_dp_get_max_rx_lane_count(struct analogix_dp_device * dp,u8 * lane_count)6283424e3a4SYakir Yang static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp,
6293424e3a4SYakir Yang 					      u8 *lane_count)
6303424e3a4SYakir Yang {
6313424e3a4SYakir Yang 	u8 data;
6323424e3a4SYakir Yang 
6333424e3a4SYakir Yang 	/*
6343424e3a4SYakir Yang 	 * For DP rev.1.1, Maximum number of Main Link lanes
6353424e3a4SYakir Yang 	 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
6363424e3a4SYakir Yang 	 */
6370d97ad03STomeu Vizoso 	drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
6383424e3a4SYakir Yang 	*lane_count = DPCD_MAX_LANE_COUNT(data);
6393424e3a4SYakir Yang }
6403424e3a4SYakir Yang 
analogix_dp_full_link_train(struct analogix_dp_device * dp,u32 max_lanes,u32 max_rate)641f9d56805Szain wang static int analogix_dp_full_link_train(struct analogix_dp_device *dp,
642f9d56805Szain wang 				       u32 max_lanes, u32 max_rate)
6433424e3a4SYakir Yang {
644f9d56805Szain wang 	int retval = 0;
645f9d56805Szain wang 	bool training_finished = false;
646f9d56805Szain wang 
6473424e3a4SYakir Yang 	/*
6483424e3a4SYakir Yang 	 * MACRO_RST must be applied after the PLL_LOCK to avoid
6493424e3a4SYakir Yang 	 * the DP inter pair skew issue for at least 10 us
6503424e3a4SYakir Yang 	 */
6513424e3a4SYakir Yang 	analogix_dp_reset_macro(dp);
6523424e3a4SYakir Yang 
6533424e3a4SYakir Yang 	/* Initialize by reading RX's DPCD */
6543424e3a4SYakir Yang 	analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
6553424e3a4SYakir Yang 	analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
6563424e3a4SYakir Yang 
65740fc7ce7SYakir Yang 	if ((dp->link_train.link_rate != DP_LINK_BW_1_62) &&
65840fc7ce7SYakir Yang 	    (dp->link_train.link_rate != DP_LINK_BW_2_7) &&
65940fc7ce7SYakir Yang 	    (dp->link_train.link_rate != DP_LINK_BW_5_4)) {
6603424e3a4SYakir Yang 		dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
6613424e3a4SYakir Yang 			dp->link_train.link_rate);
66240fc7ce7SYakir Yang 		dp->link_train.link_rate = DP_LINK_BW_1_62;
6633424e3a4SYakir Yang 	}
6643424e3a4SYakir Yang 
6653424e3a4SYakir Yang 	if (dp->link_train.lane_count == 0) {
6663424e3a4SYakir Yang 		dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
6673424e3a4SYakir Yang 			dp->link_train.lane_count);
6683424e3a4SYakir Yang 		dp->link_train.lane_count = (u8)LANE_COUNT1;
6693424e3a4SYakir Yang 	}
6703424e3a4SYakir Yang 
6713424e3a4SYakir Yang 	/* Setup TX lane count & rate */
672f9d56805Szain wang 	if (dp->link_train.lane_count > max_lanes)
673f9d56805Szain wang 		dp->link_train.lane_count = max_lanes;
6743424e3a4SYakir Yang 	if (dp->link_train.link_rate > max_rate)
6753424e3a4SYakir Yang 		dp->link_train.link_rate = max_rate;
6763424e3a4SYakir Yang 
6773424e3a4SYakir Yang 	/* All DP analog module power up */
6783424e3a4SYakir Yang 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
6793424e3a4SYakir Yang 
6803424e3a4SYakir Yang 	dp->link_train.lt_state = START;
6813424e3a4SYakir Yang 
6823424e3a4SYakir Yang 	/* Process here */
6833424e3a4SYakir Yang 	while (!retval && !training_finished) {
6843424e3a4SYakir Yang 		switch (dp->link_train.lt_state) {
6853424e3a4SYakir Yang 		case START:
6863424e3a4SYakir Yang 			retval = analogix_dp_link_start(dp);
6873424e3a4SYakir Yang 			if (retval)
6883424e3a4SYakir Yang 				dev_err(dp->dev, "LT link start failed!\n");
6893424e3a4SYakir Yang 			break;
6903424e3a4SYakir Yang 		case CLOCK_RECOVERY:
6913424e3a4SYakir Yang 			retval = analogix_dp_process_clock_recovery(dp);
6923424e3a4SYakir Yang 			if (retval)
6933424e3a4SYakir Yang 				dev_err(dp->dev, "LT CR failed!\n");
6943424e3a4SYakir Yang 			break;
6953424e3a4SYakir Yang 		case EQUALIZER_TRAINING:
6963424e3a4SYakir Yang 			retval = analogix_dp_process_equalizer_training(dp);
6973424e3a4SYakir Yang 			if (retval)
6983424e3a4SYakir Yang 				dev_err(dp->dev, "LT EQ failed!\n");
6993424e3a4SYakir Yang 			break;
7003424e3a4SYakir Yang 		case FINISHED:
7013424e3a4SYakir Yang 			training_finished = 1;
7023424e3a4SYakir Yang 			break;
7033424e3a4SYakir Yang 		case FAILED:
7043424e3a4SYakir Yang 			return -EREMOTEIO;
7053424e3a4SYakir Yang 		}
7063424e3a4SYakir Yang 	}
7073424e3a4SYakir Yang 	if (retval)
7083424e3a4SYakir Yang 		dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
7093424e3a4SYakir Yang 
7103424e3a4SYakir Yang 	return retval;
7113424e3a4SYakir Yang }
7123424e3a4SYakir Yang 
analogix_dp_fast_link_train(struct analogix_dp_device * dp)713f9d56805Szain wang static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
7143424e3a4SYakir Yang {
715f9d56805Szain wang 	int i, ret;
716f9d56805Szain wang 	u8 link_align, link_status[2];
717f9d56805Szain wang 	enum pll_status status;
7183424e3a4SYakir Yang 
719f9d56805Szain wang 	analogix_dp_reset_macro(dp);
7203424e3a4SYakir Yang 
721f9d56805Szain wang 	analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
722f9d56805Szain wang 	analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
723f9d56805Szain wang 
724f9d56805Szain wang 	for (i = 0; i < dp->link_train.lane_count; i++) {
725f9d56805Szain wang 		analogix_dp_set_lane_link_training(dp,
726f9d56805Szain wang 			dp->link_train.training_lane[i], i);
7273424e3a4SYakir Yang 	}
7283424e3a4SYakir Yang 
729f9d56805Szain wang 	ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
730f9d56805Szain wang 				 status != PLL_UNLOCKED, 120,
731f9d56805Szain wang 				 120 * DP_TIMEOUT_LOOP_COUNT);
732f9d56805Szain wang 	if (ret) {
733f9d56805Szain wang 		DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret);
734f9d56805Szain wang 		return ret;
735f9d56805Szain wang 	}
736f9d56805Szain wang 
737f9d56805Szain wang 	/* source Set training pattern 1 */
738f9d56805Szain wang 	analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
739f9d56805Szain wang 	/* From DP spec, pattern must be on-screen for a minimum 500us */
740f9d56805Szain wang 	usleep_range(500, 600);
741f9d56805Szain wang 
742f9d56805Szain wang 	analogix_dp_set_training_pattern(dp, TRAINING_PTN2);
743f9d56805Szain wang 	/* From DP spec, pattern must be on-screen for a minimum 500us */
744f9d56805Szain wang 	usleep_range(500, 600);
745f9d56805Szain wang 
746f9d56805Szain wang 	/* TODO: enhanced_mode?*/
747f9d56805Szain wang 	analogix_dp_set_training_pattern(dp, DP_NONE);
748f9d56805Szain wang 
749f9d56805Szain wang 	/*
750f9d56805Szain wang 	 * Useful for debugging issues with fast link training, disable for more
751f9d56805Szain wang 	 * speed
752f9d56805Szain wang 	 */
753f9d56805Szain wang 	if (verify_fast_training) {
754f9d56805Szain wang 		ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED,
755f9d56805Szain wang 					&link_align);
756f9d56805Szain wang 		if (ret < 0) {
757f9d56805Szain wang 			DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n",
758f9d56805Szain wang 				      ret);
759f9d56805Szain wang 			return ret;
760f9d56805Szain wang 		}
761f9d56805Szain wang 
762f9d56805Szain wang 		ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status,
763f9d56805Szain wang 				       2);
764f9d56805Szain wang 		if (ret < 0) {
765f9d56805Szain wang 			DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n",
766f9d56805Szain wang 				      ret);
767f9d56805Szain wang 			return ret;
768f9d56805Szain wang 		}
769f9d56805Szain wang 
770f9d56805Szain wang 		if (analogix_dp_clock_recovery_ok(link_status,
771f9d56805Szain wang 						  dp->link_train.lane_count)) {
772f9d56805Szain wang 			DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n");
773f9d56805Szain wang 			analogix_dp_reduce_link_rate(dp);
774f9d56805Szain wang 			return -EIO;
775f9d56805Szain wang 		}
776f9d56805Szain wang 
777f9d56805Szain wang 		if (analogix_dp_channel_eq_ok(link_status, link_align,
778f9d56805Szain wang 					      dp->link_train.lane_count)) {
779f9d56805Szain wang 			DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n");
780f9d56805Szain wang 			analogix_dp_reduce_link_rate(dp);
781f9d56805Szain wang 			return -EIO;
782f9d56805Szain wang 		}
783f9d56805Szain wang 	}
784f9d56805Szain wang 
785f9d56805Szain wang 	return 0;
786f9d56805Szain wang }
787f9d56805Szain wang 
analogix_dp_train_link(struct analogix_dp_device * dp)788f9d56805Szain wang static int analogix_dp_train_link(struct analogix_dp_device *dp)
789f9d56805Szain wang {
7907ba8fb57Szain wang 	if (dp->fast_train_enable)
791f9d56805Szain wang 		return analogix_dp_fast_link_train(dp);
792f9d56805Szain wang 
793f9d56805Szain wang 	return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count,
794f9d56805Szain wang 					   dp->video_info.max_link_rate);
7953424e3a4SYakir Yang }
7963424e3a4SYakir Yang 
analogix_dp_config_video(struct analogix_dp_device * dp)7973424e3a4SYakir Yang static int analogix_dp_config_video(struct analogix_dp_device *dp)
7983424e3a4SYakir Yang {
7993424e3a4SYakir Yang 	int timeout_loop = 0;
8003424e3a4SYakir Yang 	int done_count = 0;
8013424e3a4SYakir Yang 
8023424e3a4SYakir Yang 	analogix_dp_config_video_slave_mode(dp);
8033424e3a4SYakir Yang 
8043424e3a4SYakir Yang 	analogix_dp_set_video_color_format(dp);
8053424e3a4SYakir Yang 
8063424e3a4SYakir Yang 	if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
8073424e3a4SYakir Yang 		dev_err(dp->dev, "PLL is not locked yet.\n");
8083424e3a4SYakir Yang 		return -EINVAL;
8093424e3a4SYakir Yang 	}
8103424e3a4SYakir Yang 
8113424e3a4SYakir Yang 	for (;;) {
8123424e3a4SYakir Yang 		timeout_loop++;
8133424e3a4SYakir Yang 		if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0)
8143424e3a4SYakir Yang 			break;
815bcbb7033SYakir Yang 		if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
81693cba9daSLin Huang 			dev_err(dp->dev, "Timeout of slave video streamclk ok\n");
8173424e3a4SYakir Yang 			return -ETIMEDOUT;
8183424e3a4SYakir Yang 		}
81993cba9daSLin Huang 		usleep_range(1000, 1001);
8203424e3a4SYakir Yang 	}
8213424e3a4SYakir Yang 
8223424e3a4SYakir Yang 	/* Set to use the register calculated M/N video */
8233424e3a4SYakir Yang 	analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
8243424e3a4SYakir Yang 
8253424e3a4SYakir Yang 	/* For video bist, Video timing must be generated by register */
8263424e3a4SYakir Yang 	analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
8273424e3a4SYakir Yang 
8283424e3a4SYakir Yang 	/* Disable video mute */
8293424e3a4SYakir Yang 	analogix_dp_enable_video_mute(dp, 0);
8303424e3a4SYakir Yang 
8313424e3a4SYakir Yang 	/* Configure video slave mode */
8323424e3a4SYakir Yang 	analogix_dp_enable_video_master(dp, 0);
8333424e3a4SYakir Yang 
83493cba9daSLin Huang 	/* Enable video */
83593cba9daSLin Huang 	analogix_dp_start_video(dp);
83693cba9daSLin Huang 
8373424e3a4SYakir Yang 	timeout_loop = 0;
8383424e3a4SYakir Yang 
8393424e3a4SYakir Yang 	for (;;) {
8403424e3a4SYakir Yang 		timeout_loop++;
8413424e3a4SYakir Yang 		if (analogix_dp_is_video_stream_on(dp) == 0) {
8423424e3a4SYakir Yang 			done_count++;
8433424e3a4SYakir Yang 			if (done_count > 10)
8443424e3a4SYakir Yang 				break;
8453424e3a4SYakir Yang 		} else if (done_count) {
8463424e3a4SYakir Yang 			done_count = 0;
8473424e3a4SYakir Yang 		}
848bcbb7033SYakir Yang 		if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
849c4d3b1a2Szain wang 			dev_warn(dp->dev,
850c4d3b1a2Szain wang 				 "Ignoring timeout of video streamclk ok\n");
851c4d3b1a2Szain wang 			break;
8523424e3a4SYakir Yang 		}
8533424e3a4SYakir Yang 
8543424e3a4SYakir Yang 		usleep_range(1000, 1001);
8553424e3a4SYakir Yang 	}
8563424e3a4SYakir Yang 
857c4712f27SSylwester Nawrocki 	return 0;
8583424e3a4SYakir Yang }
8593424e3a4SYakir Yang 
analogix_dp_enable_scramble(struct analogix_dp_device * dp,bool enable)860ccdc578bSLin Huang static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
861bcbb7033SYakir Yang 				       bool enable)
8623424e3a4SYakir Yang {
8633424e3a4SYakir Yang 	u8 data;
864ccdc578bSLin Huang 	int ret;
8653424e3a4SYakir Yang 
8663424e3a4SYakir Yang 	if (enable) {
8673424e3a4SYakir Yang 		analogix_dp_enable_scrambling(dp);
8683424e3a4SYakir Yang 
869ccdc578bSLin Huang 		ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
870ccdc578bSLin Huang 					&data);
871ccdc578bSLin Huang 		if (ret != 1)
872ccdc578bSLin Huang 			return ret;
873ccdc578bSLin Huang 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
8743424e3a4SYakir Yang 				   (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
8753424e3a4SYakir Yang 	} else {
8763424e3a4SYakir Yang 		analogix_dp_disable_scrambling(dp);
8773424e3a4SYakir Yang 
878ccdc578bSLin Huang 		ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
879ccdc578bSLin Huang 					&data);
880ccdc578bSLin Huang 		if (ret != 1)
881ccdc578bSLin Huang 			return ret;
882ccdc578bSLin Huang 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
8833424e3a4SYakir Yang 				   (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
8843424e3a4SYakir Yang 	}
885ccdc578bSLin Huang 	return ret < 0 ? ret : 0;
8863424e3a4SYakir Yang }
8873424e3a4SYakir Yang 
analogix_dp_hardirq(int irq,void * arg)8887b4b7a8dSYakir Yang static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
8893424e3a4SYakir Yang {
8903424e3a4SYakir Yang 	struct analogix_dp_device *dp = arg;
8917b4b7a8dSYakir Yang 	irqreturn_t ret = IRQ_NONE;
8923424e3a4SYakir Yang 	enum dp_irq_type irq_type;
8933424e3a4SYakir Yang 
8943424e3a4SYakir Yang 	irq_type = analogix_dp_get_irq_type(dp);
8957b4b7a8dSYakir Yang 	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
8967b4b7a8dSYakir Yang 		analogix_dp_mute_hpd_interrupt(dp);
8977b4b7a8dSYakir Yang 		ret = IRQ_WAKE_THREAD;
8983424e3a4SYakir Yang 	}
8993424e3a4SYakir Yang 
9007b4b7a8dSYakir Yang 	return ret;
9017b4b7a8dSYakir Yang }
9027b4b7a8dSYakir Yang 
analogix_dp_irq_thread(int irq,void * arg)9037b4b7a8dSYakir Yang static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
9043424e3a4SYakir Yang {
9057b4b7a8dSYakir Yang 	struct analogix_dp_device *dp = arg;
9067b4b7a8dSYakir Yang 	enum dp_irq_type irq_type;
9073424e3a4SYakir Yang 
9087b4b7a8dSYakir Yang 	irq_type = analogix_dp_get_irq_type(dp);
9097b4b7a8dSYakir Yang 	if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN ||
9107b4b7a8dSYakir Yang 	    irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) {
9117b4b7a8dSYakir Yang 		dev_dbg(dp->dev, "Detected cable status changed!\n");
9123424e3a4SYakir Yang 		if (dp->drm_dev)
9133424e3a4SYakir Yang 			drm_helper_hpd_irq_event(dp->drm_dev);
9143424e3a4SYakir Yang 	}
9153424e3a4SYakir Yang 
9167b4b7a8dSYakir Yang 	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
9177b4b7a8dSYakir Yang 		analogix_dp_clear_hotplug_interrupts(dp);
9187b4b7a8dSYakir Yang 		analogix_dp_unmute_hpd_interrupt(dp);
9197b4b7a8dSYakir Yang 	}
9207b4b7a8dSYakir Yang 
9217b4b7a8dSYakir Yang 	return IRQ_HANDLED;
9227b4b7a8dSYakir Yang }
9237b4b7a8dSYakir Yang 
analogix_dp_fast_link_train_detection(struct analogix_dp_device * dp)9246f4638a1Szain wang static int analogix_dp_fast_link_train_detection(struct analogix_dp_device *dp)
9256f4638a1Szain wang {
9266f4638a1Szain wang 	int ret;
9276f4638a1Szain wang 	u8 spread;
9286f4638a1Szain wang 
9296f4638a1Szain wang 	ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &spread);
9306f4638a1Szain wang 	if (ret != 1) {
9316f4638a1Szain wang 		dev_err(dp->dev, "failed to read downspread %d\n", ret);
9326f4638a1Szain wang 		return ret;
9336f4638a1Szain wang 	}
9346f4638a1Szain wang 	dp->fast_train_enable = !!(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING);
9356f4638a1Szain wang 	dev_dbg(dp->dev, "fast link training %s\n",
9366f4638a1Szain wang 		dp->fast_train_enable ? "supported" : "unsupported");
9376f4638a1Szain wang 	return 0;
9386f4638a1Szain wang }
9396f4638a1Szain wang 
analogix_dp_commit(struct analogix_dp_device * dp)9408a335736Szain wang static int analogix_dp_commit(struct analogix_dp_device *dp)
9413424e3a4SYakir Yang {
9423424e3a4SYakir Yang 	int ret;
9433424e3a4SYakir Yang 
9443424e3a4SYakir Yang 	/* Keep the panel disabled while we configure video */
9453424e3a4SYakir Yang 	if (dp->plat_data->panel) {
9463424e3a4SYakir Yang 		if (drm_panel_disable(dp->plat_data->panel))
9473424e3a4SYakir Yang 			DRM_ERROR("failed to disable the panel\n");
9483424e3a4SYakir Yang 	}
9493424e3a4SYakir Yang 
9508a335736Szain wang 	ret = analogix_dp_train_link(dp);
9513424e3a4SYakir Yang 	if (ret) {
952f9d56805Szain wang 		dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
9538a335736Szain wang 		return ret;
9543424e3a4SYakir Yang 	}
9553424e3a4SYakir Yang 
956ccdc578bSLin Huang 	ret = analogix_dp_enable_scramble(dp, 1);
957ccdc578bSLin Huang 	if (ret < 0) {
958ccdc578bSLin Huang 		dev_err(dp->dev, "can not enable scramble\n");
959ccdc578bSLin Huang 		return ret;
960ccdc578bSLin Huang 	}
9613424e3a4SYakir Yang 
9623424e3a4SYakir Yang 	analogix_dp_init_video(dp);
9633424e3a4SYakir Yang 	ret = analogix_dp_config_video(dp);
964ccdc578bSLin Huang 	if (ret) {
9653424e3a4SYakir Yang 		dev_err(dp->dev, "unable to config video\n");
966ccdc578bSLin Huang 		return ret;
967ccdc578bSLin Huang 	}
9683424e3a4SYakir Yang 
9693424e3a4SYakir Yang 	/* Safe to enable the panel now */
9703424e3a4SYakir Yang 	if (dp->plat_data->panel) {
971ccdc578bSLin Huang 		ret = drm_panel_enable(dp->plat_data->panel);
972ccdc578bSLin Huang 		if (ret) {
9733424e3a4SYakir Yang 			DRM_ERROR("failed to enable the panel\n");
974ccdc578bSLin Huang 			return ret;
975ccdc578bSLin Huang 		}
9763424e3a4SYakir Yang 	}
9773424e3a4SYakir Yang 
978ad309284SSean Paul 	/* Check whether panel supports fast training */
979ad309284SSean Paul 	ret = analogix_dp_fast_link_train_detection(dp);
980ad309284SSean Paul 	if (ret)
9816c836d96SSean Paul 		return ret;
982ad309284SSean Paul 
9836c836d96SSean Paul 	if (analogix_dp_detect_sink_psr(dp)) {
984ccdc578bSLin Huang 		ret = analogix_dp_enable_sink_psr(dp);
9856f4638a1Szain wang 		if (ret)
9866f4638a1Szain wang 			return ret;
9876f4638a1Szain wang 	}
9886f4638a1Szain wang 
9896c836d96SSean Paul 	return ret;
9906c836d96SSean Paul }
9916c836d96SSean Paul 
analogix_dp_enable_psr(struct analogix_dp_device * dp)9926c836d96SSean Paul static int analogix_dp_enable_psr(struct analogix_dp_device *dp)
9936c836d96SSean Paul {
9946c836d96SSean Paul 	struct dp_sdp psr_vsc;
9956c836d96SSean Paul 	int ret;
9966c836d96SSean Paul 	u8 sink;
9976c836d96SSean Paul 
9986c836d96SSean Paul 	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink);
9996c836d96SSean Paul 	if (ret != 1)
10006c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret);
10016c836d96SSean Paul 	else if (sink == DP_PSR_SINK_ACTIVE_RFB)
10026c836d96SSean Paul 		return 0;
10036c836d96SSean Paul 
10046c836d96SSean Paul 	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
10056c836d96SSean Paul 	memset(&psr_vsc, 0, sizeof(psr_vsc));
10066c836d96SSean Paul 	psr_vsc.sdp_header.HB0 = 0;
10076c836d96SSean Paul 	psr_vsc.sdp_header.HB1 = 0x7;
10086c836d96SSean Paul 	psr_vsc.sdp_header.HB2 = 0x2;
10096c836d96SSean Paul 	psr_vsc.sdp_header.HB3 = 0x8;
10106c836d96SSean Paul 	psr_vsc.db[0] = 0;
10116c836d96SSean Paul 	psr_vsc.db[1] = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
10126c836d96SSean Paul 
10136c836d96SSean Paul 	ret = analogix_dp_send_psr_spd(dp, &psr_vsc, true);
10146c836d96SSean Paul 	if (!ret)
10156c836d96SSean Paul 		analogix_dp_set_analog_power_down(dp, POWER_ALL, true);
1016ccdc578bSLin Huang 
1017ccdc578bSLin Huang 	return ret;
10183424e3a4SYakir Yang }
10193424e3a4SYakir Yang 
analogix_dp_disable_psr(struct analogix_dp_device * dp)10206c836d96SSean Paul static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
10216c836d96SSean Paul {
10226c836d96SSean Paul 	struct dp_sdp psr_vsc;
10236c836d96SSean Paul 	int ret;
10246c836d96SSean Paul 	u8 sink;
10256c836d96SSean Paul 
10266c836d96SSean Paul 	analogix_dp_set_analog_power_down(dp, POWER_ALL, false);
10276c836d96SSean Paul 
10286c836d96SSean Paul 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
10296c836d96SSean Paul 	if (ret != 1) {
10306c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "Failed to set DP Power0 %d\n", ret);
10316c836d96SSean Paul 		return ret;
10326c836d96SSean Paul 	}
10336c836d96SSean Paul 
10346c836d96SSean Paul 	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink);
10356c836d96SSean Paul 	if (ret != 1) {
10366c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret);
10376c836d96SSean Paul 		return ret;
10386c836d96SSean Paul 	} else if (sink == DP_PSR_SINK_INACTIVE) {
10396c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "sink inactive, skip disable psr");
10406c836d96SSean Paul 		return 0;
10416c836d96SSean Paul 	}
10426c836d96SSean Paul 
10436c836d96SSean Paul 	ret = analogix_dp_train_link(dp);
10446c836d96SSean Paul 	if (ret) {
10456c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "Failed to train the link %d\n", ret);
10466c836d96SSean Paul 		return ret;
10476c836d96SSean Paul 	}
10486c836d96SSean Paul 
10496c836d96SSean Paul 	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
10506c836d96SSean Paul 	memset(&psr_vsc, 0, sizeof(psr_vsc));
10516c836d96SSean Paul 	psr_vsc.sdp_header.HB0 = 0;
10526c836d96SSean Paul 	psr_vsc.sdp_header.HB1 = 0x7;
10536c836d96SSean Paul 	psr_vsc.sdp_header.HB2 = 0x2;
10546c836d96SSean Paul 	psr_vsc.sdp_header.HB3 = 0x8;
10556c836d96SSean Paul 
10566c836d96SSean Paul 	psr_vsc.db[0] = 0;
10576c836d96SSean Paul 	psr_vsc.db[1] = 0;
10586c836d96SSean Paul 
10596c836d96SSean Paul 	return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
10606c836d96SSean Paul }
10616c836d96SSean Paul 
10620b8b059aSSean Paul /*
10630b8b059aSSean Paul  * This function is a bit of a catch-all for panel preparation, hopefully
10640b8b059aSSean Paul  * simplifying the logic of functions that need to prepare/unprepare the panel
10650b8b059aSSean Paul  * below.
10660b8b059aSSean Paul  *
10670b8b059aSSean Paul  * If @prepare is true, this function will prepare the panel. Conversely, if it
10680b8b059aSSean Paul  * is false, the panel will be unprepared.
10690b8b059aSSean Paul  *
10700b8b059aSSean Paul  * If @is_modeset_prepare is true, the function will disregard the current state
10710b8b059aSSean Paul  * of the panel and either prepare/unprepare the panel based on @prepare. Once
10720b8b059aSSean Paul  * it finishes, it will update dp->panel_is_modeset to reflect the current state
10730b8b059aSSean Paul  * of the panel.
10740b8b059aSSean Paul  */
analogix_dp_prepare_panel(struct analogix_dp_device * dp,bool prepare,bool is_modeset_prepare)10750b8b059aSSean Paul static int analogix_dp_prepare_panel(struct analogix_dp_device *dp,
10760b8b059aSSean Paul 				     bool prepare, bool is_modeset_prepare)
10770b8b059aSSean Paul {
10780b8b059aSSean Paul 	int ret = 0;
10790b8b059aSSean Paul 
10800b8b059aSSean Paul 	if (!dp->plat_data->panel)
10810b8b059aSSean Paul 		return 0;
10820b8b059aSSean Paul 
10830b8b059aSSean Paul 	mutex_lock(&dp->panel_lock);
10840b8b059aSSean Paul 
10850b8b059aSSean Paul 	/*
10860b8b059aSSean Paul 	 * Exit early if this is a temporary prepare/unprepare and we're already
10870b8b059aSSean Paul 	 * modeset (since we neither want to prepare twice or unprepare early).
10880b8b059aSSean Paul 	 */
10890b8b059aSSean Paul 	if (dp->panel_is_modeset && !is_modeset_prepare)
10900b8b059aSSean Paul 		goto out;
10910b8b059aSSean Paul 
10920b8b059aSSean Paul 	if (prepare)
10930b8b059aSSean Paul 		ret = drm_panel_prepare(dp->plat_data->panel);
10940b8b059aSSean Paul 	else
10950b8b059aSSean Paul 		ret = drm_panel_unprepare(dp->plat_data->panel);
10960b8b059aSSean Paul 
10970b8b059aSSean Paul 	if (ret)
10980b8b059aSSean Paul 		goto out;
10990b8b059aSSean Paul 
11000b8b059aSSean Paul 	if (is_modeset_prepare)
11010b8b059aSSean Paul 		dp->panel_is_modeset = prepare;
11020b8b059aSSean Paul 
11030b8b059aSSean Paul out:
11040b8b059aSSean Paul 	mutex_unlock(&dp->panel_lock);
11050b8b059aSSean Paul 	return ret;
11060b8b059aSSean Paul }
11070b8b059aSSean Paul 
analogix_dp_get_modes(struct drm_connector * connector)1108089cfdd9SBaoyou Xie static int analogix_dp_get_modes(struct drm_connector *connector)
11093424e3a4SYakir Yang {
11103424e3a4SYakir Yang 	struct analogix_dp_device *dp = to_dp(connector);
11110d97ad03STomeu Vizoso 	struct edid *edid;
11120b8b059aSSean Paul 	int ret, num_modes = 0;
11130b8b059aSSean Paul 
1114f2600d08SSean Paul 	if (dp->plat_data->panel) {
111506c4a9c2SSam Ravnborg 		num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
1116f2600d08SSean Paul 	} else {
11170b8b059aSSean Paul 		ret = analogix_dp_prepare_panel(dp, true, false);
11180b8b059aSSean Paul 		if (ret) {
11190b8b059aSSean Paul 			DRM_ERROR("Failed to prepare panel (%d)\n", ret);
11200b8b059aSSean Paul 			return 0;
11210b8b059aSSean Paul 		}
11223424e3a4SYakir Yang 
11230d97ad03STomeu Vizoso 		edid = drm_get_edid(connector, &dp->aux.ddc);
11240d97ad03STomeu Vizoso 		if (edid) {
1125c555f023SDaniel Vetter 			drm_connector_update_edid_property(&dp->connector,
11268c77e2c2SSean Paul 							   edid);
1127398a3995SYakir Yang 			num_modes += drm_add_edid_modes(&dp->connector, edid);
11280d97ad03STomeu Vizoso 			kfree(edid);
1129398a3995SYakir Yang 		}
11303424e3a4SYakir Yang 
11310b8b059aSSean Paul 		ret = analogix_dp_prepare_panel(dp, false, false);
11320b8b059aSSean Paul 		if (ret)
11330b8b059aSSean Paul 			DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
1134f2600d08SSean Paul 	}
1135f2600d08SSean Paul 
1136f2600d08SSean Paul 	if (dp->plat_data->get_modes)
1137f2600d08SSean Paul 		num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
11380b8b059aSSean Paul 
11393424e3a4SYakir Yang 	return num_modes;
11403424e3a4SYakir Yang }
11413424e3a4SYakir Yang 
11423424e3a4SYakir Yang static struct drm_encoder *
analogix_dp_best_encoder(struct drm_connector * connector)11433424e3a4SYakir Yang analogix_dp_best_encoder(struct drm_connector *connector)
11443424e3a4SYakir Yang {
11453424e3a4SYakir Yang 	struct analogix_dp_device *dp = to_dp(connector);
11463424e3a4SYakir Yang 
11473424e3a4SYakir Yang 	return dp->encoder;
11483424e3a4SYakir Yang }
11493424e3a4SYakir Yang 
11506c836d96SSean Paul 
analogix_dp_atomic_check(struct drm_connector * connector,struct drm_atomic_state * state)11510486ad20SYueHaibing static int analogix_dp_atomic_check(struct drm_connector *connector,
11526c836d96SSean Paul 				    struct drm_atomic_state *state)
11536c836d96SSean Paul {
11546c836d96SSean Paul 	struct analogix_dp_device *dp = to_dp(connector);
11556c836d96SSean Paul 	struct drm_connector_state *conn_state;
11566c836d96SSean Paul 	struct drm_crtc_state *crtc_state;
11576c836d96SSean Paul 
11586c836d96SSean Paul 	conn_state = drm_atomic_get_new_connector_state(state, connector);
11596c836d96SSean Paul 	if (WARN_ON(!conn_state))
11606c836d96SSean Paul 		return -ENODEV;
11616c836d96SSean Paul 
11626c836d96SSean Paul 	conn_state->self_refresh_aware = true;
11636c836d96SSean Paul 
11646c836d96SSean Paul 	if (!conn_state->crtc)
11656c836d96SSean Paul 		return 0;
11666c836d96SSean Paul 
11676c836d96SSean Paul 	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
11686c836d96SSean Paul 	if (!crtc_state)
11696c836d96SSean Paul 		return 0;
11706c836d96SSean Paul 
11716c836d96SSean Paul 	if (crtc_state->self_refresh_active && !dp->psr_supported)
11726c836d96SSean Paul 		return -EINVAL;
11736c836d96SSean Paul 
11746c836d96SSean Paul 	return 0;
11756c836d96SSean Paul }
11766c836d96SSean Paul 
11773424e3a4SYakir Yang static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = {
11783424e3a4SYakir Yang 	.get_modes = analogix_dp_get_modes,
11793424e3a4SYakir Yang 	.best_encoder = analogix_dp_best_encoder,
11806c836d96SSean Paul 	.atomic_check = analogix_dp_atomic_check,
11813424e3a4SYakir Yang };
11823424e3a4SYakir Yang 
1183089cfdd9SBaoyou Xie static enum drm_connector_status
analogix_dp_detect(struct drm_connector * connector,bool force)11843424e3a4SYakir Yang analogix_dp_detect(struct drm_connector *connector, bool force)
11853424e3a4SYakir Yang {
11862b77a291SYakir Yang 	struct analogix_dp_device *dp = to_dp(connector);
11870b8b059aSSean Paul 	enum drm_connector_status status = connector_status_disconnected;
11880b8b059aSSean Paul 	int ret;
11892b77a291SYakir Yang 
1190f2600d08SSean Paul 	if (dp->plat_data->panel)
1191f2600d08SSean Paul 		return connector_status_connected;
1192f2600d08SSean Paul 
11930b8b059aSSean Paul 	ret = analogix_dp_prepare_panel(dp, true, false);
11940b8b059aSSean Paul 	if (ret) {
11950b8b059aSSean Paul 		DRM_ERROR("Failed to prepare panel (%d)\n", ret);
11962b77a291SYakir Yang 		return connector_status_disconnected;
11970b8b059aSSean Paul 	}
11982b77a291SYakir Yang 
11990b8b059aSSean Paul 	if (!analogix_dp_detect_hpd(dp))
12000b8b059aSSean Paul 		status = connector_status_connected;
12010b8b059aSSean Paul 
12020b8b059aSSean Paul 	ret = analogix_dp_prepare_panel(dp, false, false);
12030b8b059aSSean Paul 	if (ret)
12040b8b059aSSean Paul 		DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
12050b8b059aSSean Paul 
12060b8b059aSSean Paul 	return status;
12073424e3a4SYakir Yang }
12083424e3a4SYakir Yang 
12093424e3a4SYakir Yang static const struct drm_connector_funcs analogix_dp_connector_funcs = {
12103424e3a4SYakir Yang 	.fill_modes = drm_helper_probe_single_connector_modes,
12113424e3a4SYakir Yang 	.detect = analogix_dp_detect,
1212fdd8326aSMarek Vasut 	.destroy = drm_connector_cleanup,
12133424e3a4SYakir Yang 	.reset = drm_atomic_helper_connector_reset,
12143424e3a4SYakir Yang 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
12153424e3a4SYakir Yang 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
12163424e3a4SYakir Yang };
12173424e3a4SYakir Yang 
analogix_dp_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)1218a25b988fSLaurent Pinchart static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
1219a25b988fSLaurent Pinchart 				     enum drm_bridge_attach_flags flags)
12203424e3a4SYakir Yang {
12213424e3a4SYakir Yang 	struct analogix_dp_device *dp = bridge->driver_private;
12223424e3a4SYakir Yang 	struct drm_encoder *encoder = dp->encoder;
12232e9b3e74SMarek Szyprowski 	struct drm_connector *connector = NULL;
12242e9b3e74SMarek Szyprowski 	int ret = 0;
12253424e3a4SYakir Yang 
1226a25b988fSLaurent Pinchart 	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
1227a25b988fSLaurent Pinchart 		DRM_ERROR("Fix bridge driver to make connector optional!");
1228a25b988fSLaurent Pinchart 		return -EINVAL;
1229a25b988fSLaurent Pinchart 	}
1230a25b988fSLaurent Pinchart 
12313424e3a4SYakir Yang 	if (!bridge->encoder) {
12323424e3a4SYakir Yang 		DRM_ERROR("Parent encoder object not found");
12333424e3a4SYakir Yang 		return -ENODEV;
12343424e3a4SYakir Yang 	}
12353424e3a4SYakir Yang 
12362e9b3e74SMarek Szyprowski 	if (!dp->plat_data->skip_connector) {
12372e9b3e74SMarek Szyprowski 		connector = &dp->connector;
12383424e3a4SYakir Yang 		connector->polled = DRM_CONNECTOR_POLL_HPD;
12393424e3a4SYakir Yang 
12403424e3a4SYakir Yang 		ret = drm_connector_init(dp->drm_dev, connector,
12413424e3a4SYakir Yang 					 &analogix_dp_connector_funcs,
12423424e3a4SYakir Yang 					 DRM_MODE_CONNECTOR_eDP);
12433424e3a4SYakir Yang 		if (ret) {
12443424e3a4SYakir Yang 			DRM_ERROR("Failed to initialize connector with drm\n");
12453424e3a4SYakir Yang 			return ret;
12463424e3a4SYakir Yang 		}
12473424e3a4SYakir Yang 
12483424e3a4SYakir Yang 		drm_connector_helper_add(connector,
12493424e3a4SYakir Yang 					 &analogix_dp_connector_helper_funcs);
1250cde4c44dSDaniel Vetter 		drm_connector_attach_encoder(connector, encoder);
12512e9b3e74SMarek Szyprowski 	}
12523424e3a4SYakir Yang 
12533424e3a4SYakir Yang 	/*
12543424e3a4SYakir Yang 	 * NOTE: the connector registration is implemented in analogix
12553424e3a4SYakir Yang 	 * platform driver, that to say connector would be exist after
12563424e3a4SYakir Yang 	 * plat_data->attch return, that's why we record the connector
12573424e3a4SYakir Yang 	 * point after plat attached.
12583424e3a4SYakir Yang 	 */
12593424e3a4SYakir Yang 	if (dp->plat_data->attach) {
12603424e3a4SYakir Yang 		ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
12613424e3a4SYakir Yang 		if (ret) {
126229305d7eSEnric Balletbo i Serra 			DRM_ERROR("Failed at platform attach func\n");
12633424e3a4SYakir Yang 			return ret;
12643424e3a4SYakir Yang 		}
12653424e3a4SYakir Yang 	}
12663424e3a4SYakir Yang 
12673424e3a4SYakir Yang 	return 0;
12683424e3a4SYakir Yang }
12693424e3a4SYakir Yang 
12706c836d96SSean Paul static
analogix_dp_get_old_crtc(struct analogix_dp_device * dp,struct drm_atomic_state * state)1271ca871659SBrian Norris struct drm_crtc *analogix_dp_get_old_crtc(struct analogix_dp_device *dp,
1272ca871659SBrian Norris 					  struct drm_atomic_state *state)
1273ca871659SBrian Norris {
1274ca871659SBrian Norris 	struct drm_encoder *encoder = dp->encoder;
1275ca871659SBrian Norris 	struct drm_connector *connector;
1276ca871659SBrian Norris 	struct drm_connector_state *conn_state;
1277ca871659SBrian Norris 
1278ca871659SBrian Norris 	connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
1279ca871659SBrian Norris 	if (!connector)
1280ca871659SBrian Norris 		return NULL;
1281ca871659SBrian Norris 
1282ca871659SBrian Norris 	conn_state = drm_atomic_get_old_connector_state(state, connector);
1283ca871659SBrian Norris 	if (!conn_state)
1284ca871659SBrian Norris 		return NULL;
1285ca871659SBrian Norris 
1286ca871659SBrian Norris 	return conn_state->crtc;
1287ca871659SBrian Norris }
1288ca871659SBrian Norris 
1289ca871659SBrian Norris static
analogix_dp_get_new_crtc(struct analogix_dp_device * dp,struct drm_atomic_state * state)12906c836d96SSean Paul struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
12916c836d96SSean Paul 					  struct drm_atomic_state *state)
12926c836d96SSean Paul {
12936c836d96SSean Paul 	struct drm_encoder *encoder = dp->encoder;
12946c836d96SSean Paul 	struct drm_connector *connector;
12956c836d96SSean Paul 	struct drm_connector_state *conn_state;
12966c836d96SSean Paul 
12976c836d96SSean Paul 	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
12986c836d96SSean Paul 	if (!connector)
12996c836d96SSean Paul 		return NULL;
13006c836d96SSean Paul 
13016c836d96SSean Paul 	conn_state = drm_atomic_get_new_connector_state(state, connector);
13026c836d96SSean Paul 	if (!conn_state)
13036c836d96SSean Paul 		return NULL;
13046c836d96SSean Paul 
13056c836d96SSean Paul 	return conn_state->crtc;
13066c836d96SSean Paul }
13076c836d96SSean Paul 
130841cf5712SBoris Brezillon static void
analogix_dp_bridge_atomic_pre_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)130941cf5712SBoris Brezillon analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
131041cf5712SBoris Brezillon 				     struct drm_bridge_state *old_bridge_state)
13110b8b059aSSean Paul {
131241cf5712SBoris Brezillon 	struct drm_atomic_state *old_state = old_bridge_state->base.state;
13130b8b059aSSean Paul 	struct analogix_dp_device *dp = bridge->driver_private;
13146c836d96SSean Paul 	struct drm_crtc *crtc;
13156c836d96SSean Paul 	struct drm_crtc_state *old_crtc_state;
13160b8b059aSSean Paul 	int ret;
13170b8b059aSSean Paul 
131841cf5712SBoris Brezillon 	crtc = analogix_dp_get_new_crtc(dp, old_state);
13196c836d96SSean Paul 	if (!crtc)
13206c836d96SSean Paul 		return;
13216c836d96SSean Paul 
132241cf5712SBoris Brezillon 	old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
13236c836d96SSean Paul 	/* Don't touch the panel if we're coming back from PSR */
13246c836d96SSean Paul 	if (old_crtc_state && old_crtc_state->self_refresh_active)
13256c836d96SSean Paul 		return;
13266c836d96SSean Paul 
13270b8b059aSSean Paul 	ret = analogix_dp_prepare_panel(dp, true, true);
13280b8b059aSSean Paul 	if (ret)
13290b8b059aSSean Paul 		DRM_ERROR("failed to setup the panel ret = %d\n", ret);
13300b8b059aSSean Paul }
13310b8b059aSSean Paul 
analogix_dp_set_bridge(struct analogix_dp_device * dp)13328a335736Szain wang static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
13333424e3a4SYakir Yang {
13348a335736Szain wang 	int ret;
13353424e3a4SYakir Yang 
13363424e3a4SYakir Yang 	pm_runtime_get_sync(dp->dev);
13373424e3a4SYakir Yang 
133863872659SLin Huang 	ret = clk_prepare_enable(dp->clock);
133963872659SLin Huang 	if (ret < 0) {
134063872659SLin Huang 		DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
134163872659SLin Huang 		goto out_dp_clk_pre;
134263872659SLin Huang 	}
134363872659SLin Huang 
13447bb3bb4dSDouglas Anderson 	if (dp->plat_data->power_on_start)
13457bb3bb4dSDouglas Anderson 		dp->plat_data->power_on_start(dp->plat_data);
13463424e3a4SYakir Yang 
13473424e3a4SYakir Yang 	phy_power_on(dp->phy);
13483424e3a4SYakir Yang 
13498a335736Szain wang 	ret = analogix_dp_init_dp(dp);
13508a335736Szain wang 	if (ret)
13518a335736Szain wang 		goto out_dp_init;
13528a335736Szain wang 
13537f641414Szain wang 	/*
13547f641414Szain wang 	 * According to DP spec v1.3 chap 3.5.1.2 Link Training,
13557f641414Szain wang 	 * We should first make sure the HPD signal is asserted high by device
13567f641414Szain wang 	 * when we want to establish a link with it.
13577f641414Szain wang 	 */
13587f641414Szain wang 	ret = analogix_dp_detect_hpd(dp);
13597f641414Szain wang 	if (ret) {
13607f641414Szain wang 		DRM_ERROR("failed to get hpd single ret = %d\n", ret);
13617f641414Szain wang 		goto out_dp_init;
13627f641414Szain wang 	}
13637f641414Szain wang 
13648a335736Szain wang 	ret = analogix_dp_commit(dp);
1365ccdc578bSLin Huang 	if (ret) {
1366ccdc578bSLin Huang 		DRM_ERROR("dp commit error, ret = %d\n", ret);
13678a335736Szain wang 		goto out_dp_init;
1368ccdc578bSLin Huang 	}
13698a335736Szain wang 
13707bb3bb4dSDouglas Anderson 	if (dp->plat_data->power_on_end)
13717bb3bb4dSDouglas Anderson 		dp->plat_data->power_on_end(dp->plat_data);
13727bb3bb4dSDouglas Anderson 
13738a335736Szain wang 	enable_irq(dp->irq);
13748a335736Szain wang 	return 0;
13758a335736Szain wang 
13768a335736Szain wang out_dp_init:
13778a335736Szain wang 	phy_power_off(dp->phy);
13788a335736Szain wang 	if (dp->plat_data->power_off)
13798a335736Szain wang 		dp->plat_data->power_off(dp->plat_data);
138063872659SLin Huang 	clk_disable_unprepare(dp->clock);
138163872659SLin Huang out_dp_clk_pre:
13828a335736Szain wang 	pm_runtime_put_sync(dp->dev);
13838a335736Szain wang 
13848a335736Szain wang 	return ret;
13858a335736Szain wang }
13868a335736Szain wang 
138741cf5712SBoris Brezillon static void
analogix_dp_bridge_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)138841cf5712SBoris Brezillon analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
138941cf5712SBoris Brezillon 				 struct drm_bridge_state *old_bridge_state)
13908a335736Szain wang {
139141cf5712SBoris Brezillon 	struct drm_atomic_state *old_state = old_bridge_state->base.state;
13928a335736Szain wang 	struct analogix_dp_device *dp = bridge->driver_private;
13936c836d96SSean Paul 	struct drm_crtc *crtc;
13946c836d96SSean Paul 	struct drm_crtc_state *old_crtc_state;
13958a335736Szain wang 	int timeout_loop = 0;
13966c836d96SSean Paul 	int ret;
13976c836d96SSean Paul 
139841cf5712SBoris Brezillon 	crtc = analogix_dp_get_new_crtc(dp, old_state);
13996c836d96SSean Paul 	if (!crtc)
14006c836d96SSean Paul 		return;
14016c836d96SSean Paul 
140241cf5712SBoris Brezillon 	old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
14036c836d96SSean Paul 	/* Not a full enable, just disable PSR and continue */
14046c836d96SSean Paul 	if (old_crtc_state && old_crtc_state->self_refresh_active) {
14056c836d96SSean Paul 		ret = analogix_dp_disable_psr(dp);
14066c836d96SSean Paul 		if (ret)
14076c836d96SSean Paul 			DRM_ERROR("Failed to disable psr %d\n", ret);
14086c836d96SSean Paul 		return;
14096c836d96SSean Paul 	}
14108a335736Szain wang 
14118a335736Szain wang 	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
14128a335736Szain wang 		return;
14138a335736Szain wang 
14148a335736Szain wang 	while (timeout_loop < MAX_PLL_LOCK_LOOP) {
14158a335736Szain wang 		if (analogix_dp_set_bridge(dp) == 0) {
14163424e3a4SYakir Yang 			dp->dpms_mode = DRM_MODE_DPMS_ON;
14178a335736Szain wang 			return;
14188a335736Szain wang 		}
14198a335736Szain wang 		dev_err(dp->dev, "failed to set bridge, retry: %d\n",
14208a335736Szain wang 			timeout_loop);
14218a335736Szain wang 		timeout_loop++;
14228a335736Szain wang 		usleep_range(10, 11);
14238a335736Szain wang 	}
14248a335736Szain wang 	dev_err(dp->dev, "too many times retry set bridge, give it up\n");
14253424e3a4SYakir Yang }
14263424e3a4SYakir Yang 
analogix_dp_bridge_disable(struct drm_bridge * bridge)14273424e3a4SYakir Yang static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
14283424e3a4SYakir Yang {
14293424e3a4SYakir Yang 	struct analogix_dp_device *dp = bridge->driver_private;
14300b8b059aSSean Paul 	int ret;
14313424e3a4SYakir Yang 
14323424e3a4SYakir Yang 	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
14333424e3a4SYakir Yang 		return;
14343424e3a4SYakir Yang 
14353424e3a4SYakir Yang 	if (dp->plat_data->panel) {
14363424e3a4SYakir Yang 		if (drm_panel_disable(dp->plat_data->panel)) {
14373424e3a4SYakir Yang 			DRM_ERROR("failed to disable the panel\n");
14383424e3a4SYakir Yang 			return;
14393424e3a4SYakir Yang 		}
14403424e3a4SYakir Yang 	}
14413424e3a4SYakir Yang 
14423424e3a4SYakir Yang 	disable_irq(dp->irq);
14433424e3a4SYakir Yang 
14443424e3a4SYakir Yang 	if (dp->plat_data->power_off)
14453424e3a4SYakir Yang 		dp->plat_data->power_off(dp->plat_data);
14463424e3a4SYakir Yang 
14472f8d2160SDouglas Anderson 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
14482f8d2160SDouglas Anderson 	phy_power_off(dp->phy);
14492f8d2160SDouglas Anderson 
145063872659SLin Huang 	clk_disable_unprepare(dp->clock);
145163872659SLin Huang 
14523424e3a4SYakir Yang 	pm_runtime_put_sync(dp->dev);
14533424e3a4SYakir Yang 
14540b8b059aSSean Paul 	ret = analogix_dp_prepare_panel(dp, false, true);
14550b8b059aSSean Paul 	if (ret)
14560b8b059aSSean Paul 		DRM_ERROR("failed to setup the panel ret = %d\n", ret);
14570b8b059aSSean Paul 
14587ba8fb57Szain wang 	dp->fast_train_enable = false;
14596c836d96SSean Paul 	dp->psr_supported = false;
14603424e3a4SYakir Yang 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
14613424e3a4SYakir Yang }
14623424e3a4SYakir Yang 
146341cf5712SBoris Brezillon static void
analogix_dp_bridge_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)146441cf5712SBoris Brezillon analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
146541cf5712SBoris Brezillon 				  struct drm_bridge_state *old_bridge_state)
14666c836d96SSean Paul {
146741cf5712SBoris Brezillon 	struct drm_atomic_state *old_state = old_bridge_state->base.state;
14686c836d96SSean Paul 	struct analogix_dp_device *dp = bridge->driver_private;
1469ca871659SBrian Norris 	struct drm_crtc *old_crtc, *new_crtc;
1470ca871659SBrian Norris 	struct drm_crtc_state *old_crtc_state = NULL;
14716c836d96SSean Paul 	struct drm_crtc_state *new_crtc_state = NULL;
1472ca871659SBrian Norris 	int ret;
14736c836d96SSean Paul 
1474ca871659SBrian Norris 	new_crtc = analogix_dp_get_new_crtc(dp, old_state);
1475ca871659SBrian Norris 	if (!new_crtc)
14766c836d96SSean Paul 		goto out;
14776c836d96SSean Paul 
1478ca871659SBrian Norris 	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, new_crtc);
14796c836d96SSean Paul 	if (!new_crtc_state)
14806c836d96SSean Paul 		goto out;
14816c836d96SSean Paul 
14826c836d96SSean Paul 	/* Don't do a full disable on PSR transitions */
14836c836d96SSean Paul 	if (new_crtc_state->self_refresh_active)
14846c836d96SSean Paul 		return;
14856c836d96SSean Paul 
14866c836d96SSean Paul out:
1487ca871659SBrian Norris 	old_crtc = analogix_dp_get_old_crtc(dp, old_state);
1488ca871659SBrian Norris 	if (old_crtc) {
1489ca871659SBrian Norris 		old_crtc_state = drm_atomic_get_old_crtc_state(old_state,
1490ca871659SBrian Norris 							       old_crtc);
1491ca871659SBrian Norris 
1492ca871659SBrian Norris 		/* When moving from PSR to fully disabled, exit PSR first. */
1493ca871659SBrian Norris 		if (old_crtc_state && old_crtc_state->self_refresh_active) {
1494ca871659SBrian Norris 			ret = analogix_dp_disable_psr(dp);
1495ca871659SBrian Norris 			if (ret)
1496ca871659SBrian Norris 				DRM_ERROR("Failed to disable psr (%d)\n", ret);
1497ca871659SBrian Norris 		}
1498ca871659SBrian Norris 	}
1499ca871659SBrian Norris 
15006c836d96SSean Paul 	analogix_dp_bridge_disable(bridge);
15016c836d96SSean Paul }
15026c836d96SSean Paul 
150341cf5712SBoris Brezillon static void
analogix_dp_bridge_atomic_post_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)150441cf5712SBoris Brezillon analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
150541cf5712SBoris Brezillon 				struct drm_bridge_state *old_bridge_state)
15066c836d96SSean Paul {
150741cf5712SBoris Brezillon 	struct drm_atomic_state *old_state = old_bridge_state->base.state;
15086c836d96SSean Paul 	struct analogix_dp_device *dp = bridge->driver_private;
15096c836d96SSean Paul 	struct drm_crtc *crtc;
15106c836d96SSean Paul 	struct drm_crtc_state *new_crtc_state;
15116c836d96SSean Paul 	int ret;
15126c836d96SSean Paul 
151341cf5712SBoris Brezillon 	crtc = analogix_dp_get_new_crtc(dp, old_state);
15146c836d96SSean Paul 	if (!crtc)
15156c836d96SSean Paul 		return;
15166c836d96SSean Paul 
151741cf5712SBoris Brezillon 	new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
15186c836d96SSean Paul 	if (!new_crtc_state || !new_crtc_state->self_refresh_active)
15196c836d96SSean Paul 		return;
15206c836d96SSean Paul 
15216c836d96SSean Paul 	ret = analogix_dp_enable_psr(dp);
15226c836d96SSean Paul 	if (ret)
15236c836d96SSean Paul 		DRM_ERROR("Failed to enable psr (%d)\n", ret);
15246c836d96SSean Paul }
15256c836d96SSean Paul 
analogix_dp_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * orig_mode,const struct drm_display_mode * mode)1526793ce4ebSYakir Yang static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
152763f8f3baSLaurent Pinchart 				const struct drm_display_mode *orig_mode,
152863f8f3baSLaurent Pinchart 				const struct drm_display_mode *mode)
1529793ce4ebSYakir Yang {
1530793ce4ebSYakir Yang 	struct analogix_dp_device *dp = bridge->driver_private;
1531793ce4ebSYakir Yang 	struct drm_display_info *display_info = &dp->connector.display_info;
1532793ce4ebSYakir Yang 	struct video_info *video = &dp->video_info;
1533793ce4ebSYakir Yang 	struct device_node *dp_node = dp->dev->of_node;
1534793ce4ebSYakir Yang 	int vic;
1535793ce4ebSYakir Yang 
1536793ce4ebSYakir Yang 	/* Input video interlaces & hsync pol & vsync pol */
1537793ce4ebSYakir Yang 	video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
1538793ce4ebSYakir Yang 	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
1539793ce4ebSYakir Yang 	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
1540793ce4ebSYakir Yang 
1541793ce4ebSYakir Yang 	/* Input video dynamic_range & colorimetry */
1542793ce4ebSYakir Yang 	vic = drm_match_cea_mode(mode);
1543793ce4ebSYakir Yang 	if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
1544793ce4ebSYakir Yang 	    (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) {
1545793ce4ebSYakir Yang 		video->dynamic_range = CEA;
1546793ce4ebSYakir Yang 		video->ycbcr_coeff = COLOR_YCBCR601;
1547793ce4ebSYakir Yang 	} else if (vic) {
1548793ce4ebSYakir Yang 		video->dynamic_range = CEA;
1549793ce4ebSYakir Yang 		video->ycbcr_coeff = COLOR_YCBCR709;
1550793ce4ebSYakir Yang 	} else {
1551793ce4ebSYakir Yang 		video->dynamic_range = VESA;
1552793ce4ebSYakir Yang 		video->ycbcr_coeff = COLOR_YCBCR709;
1553793ce4ebSYakir Yang 	}
1554793ce4ebSYakir Yang 
1555793ce4ebSYakir Yang 	/* Input vide bpc and color_formats */
1556793ce4ebSYakir Yang 	switch (display_info->bpc) {
1557793ce4ebSYakir Yang 	case 12:
1558793ce4ebSYakir Yang 		video->color_depth = COLOR_12;
1559793ce4ebSYakir Yang 		break;
1560793ce4ebSYakir Yang 	case 10:
1561793ce4ebSYakir Yang 		video->color_depth = COLOR_10;
1562793ce4ebSYakir Yang 		break;
1563793ce4ebSYakir Yang 	case 8:
1564793ce4ebSYakir Yang 		video->color_depth = COLOR_8;
1565793ce4ebSYakir Yang 		break;
1566793ce4ebSYakir Yang 	case 6:
1567793ce4ebSYakir Yang 		video->color_depth = COLOR_6;
1568793ce4ebSYakir Yang 		break;
1569793ce4ebSYakir Yang 	default:
1570793ce4ebSYakir Yang 		video->color_depth = COLOR_8;
1571793ce4ebSYakir Yang 		break;
1572793ce4ebSYakir Yang 	}
1573c03d0b52SMaxime Ripard 	if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
1574793ce4ebSYakir Yang 		video->color_space = COLOR_YCBCR444;
1575c03d0b52SMaxime Ripard 	else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
1576793ce4ebSYakir Yang 		video->color_space = COLOR_YCBCR422;
1577793ce4ebSYakir Yang 	else
1578793ce4ebSYakir Yang 		video->color_space = COLOR_RGB;
1579793ce4ebSYakir Yang 
1580793ce4ebSYakir Yang 	/*
1581793ce4ebSYakir Yang 	 * NOTE: those property parsing code is used for providing backward
1582793ce4ebSYakir Yang 	 * compatibility for samsung platform.
1583793ce4ebSYakir Yang 	 * Due to we used the "of_property_read_u32" interfaces, when this
1584793ce4ebSYakir Yang 	 * property isn't present, the "video_info" can keep the original
1585793ce4ebSYakir Yang 	 * values and wouldn't be modified.
1586793ce4ebSYakir Yang 	 */
1587793ce4ebSYakir Yang 	of_property_read_u32(dp_node, "samsung,color-space",
1588793ce4ebSYakir Yang 			     &video->color_space);
1589793ce4ebSYakir Yang 	of_property_read_u32(dp_node, "samsung,dynamic-range",
1590793ce4ebSYakir Yang 			     &video->dynamic_range);
1591793ce4ebSYakir Yang 	of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
1592793ce4ebSYakir Yang 			     &video->ycbcr_coeff);
1593793ce4ebSYakir Yang 	of_property_read_u32(dp_node, "samsung,color-depth",
1594793ce4ebSYakir Yang 			     &video->color_depth);
1595793ce4ebSYakir Yang 	if (of_property_read_bool(dp_node, "hsync-active-high"))
1596793ce4ebSYakir Yang 		video->h_sync_polarity = true;
1597793ce4ebSYakir Yang 	if (of_property_read_bool(dp_node, "vsync-active-high"))
1598793ce4ebSYakir Yang 		video->v_sync_polarity = true;
1599793ce4ebSYakir Yang 	if (of_property_read_bool(dp_node, "interlaced"))
1600793ce4ebSYakir Yang 		video->interlaced = true;
1601793ce4ebSYakir Yang }
1602793ce4ebSYakir Yang 
16033424e3a4SYakir Yang static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
1604d9aad8c2SBoris Brezillon 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
1605d9aad8c2SBoris Brezillon 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
1606d9aad8c2SBoris Brezillon 	.atomic_reset = drm_atomic_helper_bridge_reset,
16076c836d96SSean Paul 	.atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable,
16086c836d96SSean Paul 	.atomic_enable = analogix_dp_bridge_atomic_enable,
16096c836d96SSean Paul 	.atomic_disable = analogix_dp_bridge_atomic_disable,
16106c836d96SSean Paul 	.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
1611793ce4ebSYakir Yang 	.mode_set = analogix_dp_bridge_mode_set,
16123424e3a4SYakir Yang 	.attach = analogix_dp_bridge_attach,
16133424e3a4SYakir Yang };
16143424e3a4SYakir Yang 
analogix_dp_create_bridge(struct drm_device * drm_dev,struct analogix_dp_device * dp)16153424e3a4SYakir Yang static int analogix_dp_create_bridge(struct drm_device *drm_dev,
16163424e3a4SYakir Yang 				     struct analogix_dp_device *dp)
16173424e3a4SYakir Yang {
16183424e3a4SYakir Yang 	struct drm_bridge *bridge;
16193424e3a4SYakir Yang 
16203424e3a4SYakir Yang 	bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL);
16213424e3a4SYakir Yang 	if (!bridge) {
16223424e3a4SYakir Yang 		DRM_ERROR("failed to allocate for drm bridge\n");
16233424e3a4SYakir Yang 		return -ENOMEM;
16243424e3a4SYakir Yang 	}
16253424e3a4SYakir Yang 
16263424e3a4SYakir Yang 	dp->bridge = bridge;
16273424e3a4SYakir Yang 
16283424e3a4SYakir Yang 	bridge->driver_private = dp;
16293424e3a4SYakir Yang 	bridge->funcs = &analogix_dp_bridge_funcs;
16303424e3a4SYakir Yang 
1631fb8d617fSLaurent Pinchart 	return drm_bridge_attach(dp->encoder, bridge, NULL, 0);
16323424e3a4SYakir Yang }
16333424e3a4SYakir Yang 
analogix_dp_dt_parse_pdata(struct analogix_dp_device * dp)1634793ce4ebSYakir Yang static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
16353424e3a4SYakir Yang {
1636793ce4ebSYakir Yang 	struct device_node *dp_node = dp->dev->of_node;
1637793ce4ebSYakir Yang 	struct video_info *video_info = &dp->video_info;
16383424e3a4SYakir Yang 
16390d0abd89SYakir Yang 	switch (dp->plat_data->dev_type) {
16400d0abd89SYakir Yang 	case RK3288_DP:
164182872e42SYakir Yang 	case RK3399_EDP:
16420d0abd89SYakir Yang 		/*
16430d0abd89SYakir Yang 		 * Like Rk3288 DisplayPort TRM indicate that "Main link
16440d0abd89SYakir Yang 		 * containing 4 physical lanes of 2.7/1.62 Gbps/lane".
16450d0abd89SYakir Yang 		 */
16460d0abd89SYakir Yang 		video_info->max_link_rate = 0x0A;
16470d0abd89SYakir Yang 		video_info->max_lane_count = 0x04;
16480d0abd89SYakir Yang 		break;
16490d0abd89SYakir Yang 	case EXYNOS_DP:
16500d0abd89SYakir Yang 		/*
16510d0abd89SYakir Yang 		 * NOTE: those property parseing code is used for
16520d0abd89SYakir Yang 		 * providing backward compatibility for samsung platform.
16530d0abd89SYakir Yang 		 */
16540d0abd89SYakir Yang 		of_property_read_u32(dp_node, "samsung,link-rate",
16550d0abd89SYakir Yang 				     &video_info->max_link_rate);
16560d0abd89SYakir Yang 		of_property_read_u32(dp_node, "samsung,lane-count",
16570d0abd89SYakir Yang 				     &video_info->max_lane_count);
16580d0abd89SYakir Yang 		break;
16593424e3a4SYakir Yang 	}
16603424e3a4SYakir Yang 
1661793ce4ebSYakir Yang 	return 0;
16623424e3a4SYakir Yang }
16633424e3a4SYakir Yang 
analogix_dpaux_transfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)16640d97ad03STomeu Vizoso static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
16650d97ad03STomeu Vizoso 				       struct drm_dp_aux_msg *msg)
16660d97ad03STomeu Vizoso {
16670d97ad03STomeu Vizoso 	struct analogix_dp_device *dp = to_dp(aux);
16688fb6c44fSBrian Norris 	int ret;
16690d97ad03STomeu Vizoso 
16708fb6c44fSBrian Norris 	pm_runtime_get_sync(dp->dev);
16718fb6c44fSBrian Norris 
16728fb6c44fSBrian Norris 	ret = analogix_dp_detect_hpd(dp);
16738fb6c44fSBrian Norris 	if (ret)
16748fb6c44fSBrian Norris 		goto out;
16758fb6c44fSBrian Norris 
16768fb6c44fSBrian Norris 	ret = analogix_dp_transfer(dp, msg);
16778fb6c44fSBrian Norris out:
1678f28dd507SBrian Norris 	pm_runtime_mark_last_busy(dp->dev);
1679f28dd507SBrian Norris 	pm_runtime_put_autosuspend(dp->dev);
16808fb6c44fSBrian Norris 
16818fb6c44fSBrian Norris 	return ret;
16820d97ad03STomeu Vizoso }
16830d97ad03STomeu Vizoso 
16846b2d8fd9SJeffy Chen struct analogix_dp_device *
analogix_dp_probe(struct device * dev,struct analogix_dp_plat_data * plat_data)1685152cce00SMarek Szyprowski analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
16863424e3a4SYakir Yang {
16873424e3a4SYakir Yang 	struct platform_device *pdev = to_platform_device(dev);
16883424e3a4SYakir Yang 	struct analogix_dp_device *dp;
16893424e3a4SYakir Yang 	struct resource *res;
16903424e3a4SYakir Yang 	unsigned int irq_flags;
16913424e3a4SYakir Yang 	int ret;
16923424e3a4SYakir Yang 
16933424e3a4SYakir Yang 	if (!plat_data) {
16943424e3a4SYakir Yang 		dev_err(dev, "Invalided input plat_data\n");
16956b2d8fd9SJeffy Chen 		return ERR_PTR(-EINVAL);
16963424e3a4SYakir Yang 	}
16973424e3a4SYakir Yang 
16983424e3a4SYakir Yang 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
16993424e3a4SYakir Yang 	if (!dp)
17006b2d8fd9SJeffy Chen 		return ERR_PTR(-ENOMEM);
17013424e3a4SYakir Yang 
17023424e3a4SYakir Yang 	dp->dev = &pdev->dev;
17033424e3a4SYakir Yang 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
17043424e3a4SYakir Yang 
17050b8b059aSSean Paul 	mutex_init(&dp->panel_lock);
17060b8b059aSSean Paul 	dp->panel_is_modeset = false;
17070b8b059aSSean Paul 
17083424e3a4SYakir Yang 	/*
17093424e3a4SYakir Yang 	 * platform dp driver need containor_of the plat_data to get
17103424e3a4SYakir Yang 	 * the driver private data, so we need to store the point of
17113424e3a4SYakir Yang 	 * plat_data, not the context of plat_data.
17123424e3a4SYakir Yang 	 */
17133424e3a4SYakir Yang 	dp->plat_data = plat_data;
17143424e3a4SYakir Yang 
1715793ce4ebSYakir Yang 	ret = analogix_dp_dt_parse_pdata(dp);
1716793ce4ebSYakir Yang 	if (ret)
17176b2d8fd9SJeffy Chen 		return ERR_PTR(ret);
17183424e3a4SYakir Yang 
17193424e3a4SYakir Yang 	dp->phy = devm_phy_get(dp->dev, "dp");
17203424e3a4SYakir Yang 	if (IS_ERR(dp->phy)) {
17213424e3a4SYakir Yang 		dev_err(dp->dev, "no DP phy configured\n");
17223424e3a4SYakir Yang 		ret = PTR_ERR(dp->phy);
17233424e3a4SYakir Yang 		if (ret) {
17243424e3a4SYakir Yang 			/*
17253424e3a4SYakir Yang 			 * phy itself is not enabled, so we can move forward
17263424e3a4SYakir Yang 			 * assigning NULL to phy pointer.
17273424e3a4SYakir Yang 			 */
17283424e3a4SYakir Yang 			if (ret == -ENOSYS || ret == -ENODEV)
17293424e3a4SYakir Yang 				dp->phy = NULL;
17303424e3a4SYakir Yang 			else
17316b2d8fd9SJeffy Chen 				return ERR_PTR(ret);
17323424e3a4SYakir Yang 		}
17333424e3a4SYakir Yang 	}
17343424e3a4SYakir Yang 
17353424e3a4SYakir Yang 	dp->clock = devm_clk_get(&pdev->dev, "dp");
17363424e3a4SYakir Yang 	if (IS_ERR(dp->clock)) {
17373424e3a4SYakir Yang 		dev_err(&pdev->dev, "failed to get clock\n");
17386b2d8fd9SJeffy Chen 		return ERR_CAST(dp->clock);
17393424e3a4SYakir Yang 	}
17403424e3a4SYakir Yang 
17413424e3a4SYakir Yang 	clk_prepare_enable(dp->clock);
17423424e3a4SYakir Yang 
17433424e3a4SYakir Yang 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
17443424e3a4SYakir Yang 
17453424e3a4SYakir Yang 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
17469f15930bSMiaoqian Lin 	if (IS_ERR(dp->reg_base)) {
17479f15930bSMiaoqian Lin 		ret = PTR_ERR(dp->reg_base);
17489f15930bSMiaoqian Lin 		goto err_disable_clk;
17499f15930bSMiaoqian Lin 	}
17503424e3a4SYakir Yang 
17515cff007cSYakir Yang 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
17525cff007cSYakir Yang 
17535b038dcfSLinus Walleij 	/* Try two different names */
17545b038dcfSLinus Walleij 	dp->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
17555b038dcfSLinus Walleij 	if (!dp->hpd_gpiod)
17565b038dcfSLinus Walleij 		dp->hpd_gpiod = devm_gpiod_get_optional(dev, "samsung,hpd",
17575b038dcfSLinus Walleij 							GPIOD_IN);
17585b038dcfSLinus Walleij 	if (IS_ERR(dp->hpd_gpiod)) {
17595b038dcfSLinus Walleij 		dev_err(dev, "error getting HDP GPIO: %ld\n",
17605b038dcfSLinus Walleij 			PTR_ERR(dp->hpd_gpiod));
17619f15930bSMiaoqian Lin 		ret = PTR_ERR(dp->hpd_gpiod);
17629f15930bSMiaoqian Lin 		goto err_disable_clk;
17635b038dcfSLinus Walleij 	}
17643424e3a4SYakir Yang 
17655b038dcfSLinus Walleij 	if (dp->hpd_gpiod) {
17663424e3a4SYakir Yang 		/*
17673424e3a4SYakir Yang 		 * Set up the hotplug GPIO from the device tree as an interrupt.
17683424e3a4SYakir Yang 		 * Simply specifying a different interrupt in the device tree
17693424e3a4SYakir Yang 		 * doesn't work since we handle hotplug rather differently when
17703424e3a4SYakir Yang 		 * using a GPIO.  We also need the actual GPIO specifier so
17713424e3a4SYakir Yang 		 * that we can get the current state of the GPIO.
17723424e3a4SYakir Yang 		 */
17735b038dcfSLinus Walleij 		dp->irq = gpiod_to_irq(dp->hpd_gpiod);
17743424e3a4SYakir Yang 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
17753424e3a4SYakir Yang 	} else {
17763424e3a4SYakir Yang 		dp->irq = platform_get_irq(pdev, 0);
17773424e3a4SYakir Yang 		irq_flags = 0;
17783424e3a4SYakir Yang 	}
17793424e3a4SYakir Yang 
17803424e3a4SYakir Yang 	if (dp->irq == -ENXIO) {
17813424e3a4SYakir Yang 		dev_err(&pdev->dev, "failed to get irq\n");
17829f15930bSMiaoqian Lin 		ret = -ENODEV;
17839f15930bSMiaoqian Lin 		goto err_disable_clk;
17843424e3a4SYakir Yang 	}
17853424e3a4SYakir Yang 
17867b4b7a8dSYakir Yang 	ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
17877b4b7a8dSYakir Yang 					analogix_dp_hardirq,
17887b4b7a8dSYakir Yang 					analogix_dp_irq_thread,
17893424e3a4SYakir Yang 					irq_flags, "analogix-dp", dp);
17903424e3a4SYakir Yang 	if (ret) {
17913424e3a4SYakir Yang 		dev_err(&pdev->dev, "failed to request irq\n");
17929f15930bSMiaoqian Lin 		goto err_disable_clk;
17933424e3a4SYakir Yang 	}
17943424e3a4SYakir Yang 	disable_irq(dp->irq);
17953424e3a4SYakir Yang 
1796152cce00SMarek Szyprowski 	return dp;
17979f15930bSMiaoqian Lin 
17989f15930bSMiaoqian Lin err_disable_clk:
17999f15930bSMiaoqian Lin 	clk_disable_unprepare(dp->clock);
18009f15930bSMiaoqian Lin 	return ERR_PTR(ret);
1801152cce00SMarek Szyprowski }
1802152cce00SMarek Szyprowski EXPORT_SYMBOL_GPL(analogix_dp_probe);
1803152cce00SMarek Szyprowski 
analogix_dp_bind(struct analogix_dp_device * dp,struct drm_device * drm_dev)1804152cce00SMarek Szyprowski int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
1805152cce00SMarek Szyprowski {
1806152cce00SMarek Szyprowski 	int ret;
1807152cce00SMarek Szyprowski 
18083424e3a4SYakir Yang 	dp->drm_dev = drm_dev;
18093424e3a4SYakir Yang 	dp->encoder = dp->plat_data->encoder;
18103424e3a4SYakir Yang 
18110d97ad03STomeu Vizoso 	dp->aux.name = "DP-AUX";
18120d97ad03STomeu Vizoso 	dp->aux.transfer = analogix_dpaux_transfer;
1813152cce00SMarek Szyprowski 	dp->aux.dev = dp->dev;
18146cba3fe4SLyude Paul 	dp->aux.drm_dev = drm_dev;
18150d97ad03STomeu Vizoso 
18160d97ad03STomeu Vizoso 	ret = drm_dp_aux_register(&dp->aux);
18170d97ad03STomeu Vizoso 	if (ret)
1818152cce00SMarek Szyprowski 		return ret;
1819f25c8358SMarek Szyprowski 
1820f28dd507SBrian Norris 	pm_runtime_use_autosuspend(dp->dev);
1821f28dd507SBrian Norris 	pm_runtime_set_autosuspend_delay(dp->dev, 100);
1822152cce00SMarek Szyprowski 	pm_runtime_enable(dp->dev);
18230d97ad03STomeu Vizoso 
18243424e3a4SYakir Yang 	ret = analogix_dp_create_bridge(drm_dev, dp);
18253424e3a4SYakir Yang 	if (ret) {
18263424e3a4SYakir Yang 		DRM_ERROR("failed to create bridge (%d)\n", ret);
18273424e3a4SYakir Yang 		goto err_disable_pm_runtime;
18283424e3a4SYakir Yang 	}
18293424e3a4SYakir Yang 
1830152cce00SMarek Szyprowski 	return 0;
18313424e3a4SYakir Yang 
18323424e3a4SYakir Yang err_disable_pm_runtime:
1833f28dd507SBrian Norris 	pm_runtime_dont_use_autosuspend(dp->dev);
1834152cce00SMarek Szyprowski 	pm_runtime_disable(dp->dev);
1835b3bdf89cSLyude Paul 	drm_dp_aux_unregister(&dp->aux);
1836f0a8b49cSMarek Szyprowski 
1837152cce00SMarek Szyprowski 	return ret;
18383424e3a4SYakir Yang }
18393424e3a4SYakir Yang EXPORT_SYMBOL_GPL(analogix_dp_bind);
18403424e3a4SYakir Yang 
analogix_dp_unbind(struct analogix_dp_device * dp)18416b2d8fd9SJeffy Chen void analogix_dp_unbind(struct analogix_dp_device *dp)
18423424e3a4SYakir Yang {
18433424e3a4SYakir Yang 	analogix_dp_bridge_disable(dp->bridge);
184437e04877SJeffy Chen 	dp->connector.funcs->destroy(&dp->connector);
18452b77a291SYakir Yang 
18462b77a291SYakir Yang 	if (dp->plat_data->panel) {
18472b77a291SYakir Yang 		if (drm_panel_unprepare(dp->plat_data->panel))
18482b77a291SYakir Yang 			DRM_ERROR("failed to turnoff the panel\n");
18492b77a291SYakir Yang 	}
18502b77a291SYakir Yang 
18517b017a58SJeffy Chen 	drm_dp_aux_unregister(&dp->aux);
1852f28dd507SBrian Norris 	pm_runtime_dont_use_autosuspend(dp->dev);
18536b2d8fd9SJeffy Chen 	pm_runtime_disable(dp->dev);
18543424e3a4SYakir Yang }
18553424e3a4SYakir Yang EXPORT_SYMBOL_GPL(analogix_dp_unbind);
18563424e3a4SYakir Yang 
analogix_dp_remove(struct analogix_dp_device * dp)1857152cce00SMarek Szyprowski void analogix_dp_remove(struct analogix_dp_device *dp)
1858152cce00SMarek Szyprowski {
1859152cce00SMarek Szyprowski 	clk_disable_unprepare(dp->clock);
1860152cce00SMarek Szyprowski }
1861152cce00SMarek Szyprowski EXPORT_SYMBOL_GPL(analogix_dp_remove);
1862152cce00SMarek Szyprowski 
18633424e3a4SYakir Yang #ifdef CONFIG_PM
analogix_dp_suspend(struct analogix_dp_device * dp)18646b2d8fd9SJeffy Chen int analogix_dp_suspend(struct analogix_dp_device *dp)
18653424e3a4SYakir Yang {
18663424e3a4SYakir Yang 	clk_disable_unprepare(dp->clock);
18673424e3a4SYakir Yang 	return 0;
18683424e3a4SYakir Yang }
18693424e3a4SYakir Yang EXPORT_SYMBOL_GPL(analogix_dp_suspend);
18703424e3a4SYakir Yang 
analogix_dp_resume(struct analogix_dp_device * dp)18716b2d8fd9SJeffy Chen int analogix_dp_resume(struct analogix_dp_device *dp)
18723424e3a4SYakir Yang {
18733424e3a4SYakir Yang 	int ret;
18743424e3a4SYakir Yang 
18753424e3a4SYakir Yang 	ret = clk_prepare_enable(dp->clock);
18763424e3a4SYakir Yang 	if (ret < 0) {
18773424e3a4SYakir Yang 		DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
18783424e3a4SYakir Yang 		return ret;
18793424e3a4SYakir Yang 	}
18803424e3a4SYakir Yang 
18813424e3a4SYakir Yang 	return 0;
18823424e3a4SYakir Yang }
18833424e3a4SYakir Yang EXPORT_SYMBOL_GPL(analogix_dp_resume);
18843424e3a4SYakir Yang #endif
18853424e3a4SYakir Yang 
analogix_dp_start_crc(struct drm_connector * connector)1886737d6e33STomeu Vizoso int analogix_dp_start_crc(struct drm_connector *connector)
1887737d6e33STomeu Vizoso {
1888737d6e33STomeu Vizoso 	struct analogix_dp_device *dp = to_dp(connector);
1889737d6e33STomeu Vizoso 
1890737d6e33STomeu Vizoso 	if (!connector->state->crtc) {
1891737d6e33STomeu Vizoso 		DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
1892737d6e33STomeu Vizoso 			  connector->name);
1893737d6e33STomeu Vizoso 		return -EINVAL;
1894737d6e33STomeu Vizoso 	}
1895737d6e33STomeu Vizoso 
1896737d6e33STomeu Vizoso 	return drm_dp_start_crc(&dp->aux, connector->state->crtc);
1897737d6e33STomeu Vizoso }
1898737d6e33STomeu Vizoso EXPORT_SYMBOL_GPL(analogix_dp_start_crc);
1899737d6e33STomeu Vizoso 
analogix_dp_stop_crc(struct drm_connector * connector)1900737d6e33STomeu Vizoso int analogix_dp_stop_crc(struct drm_connector *connector)
1901737d6e33STomeu Vizoso {
1902737d6e33STomeu Vizoso 	struct analogix_dp_device *dp = to_dp(connector);
1903737d6e33STomeu Vizoso 
1904737d6e33STomeu Vizoso 	return drm_dp_stop_crc(&dp->aux);
1905737d6e33STomeu Vizoso }
1906737d6e33STomeu Vizoso EXPORT_SYMBOL_GPL(analogix_dp_stop_crc);
1907737d6e33STomeu Vizoso 
19083424e3a4SYakir Yang MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
19093424e3a4SYakir Yang MODULE_DESCRIPTION("Analogix DP Core Driver");
19103424e3a4SYakir Yang MODULE_LICENSE("GPL v2");
1911