xref: /rk3399_rockchip-uboot/drivers/video/drm/analogix_dp.c (revision 51fee72cfce7499f818f60f8e78cc8eefaaca712)
16f920c07SWyon Bi /*
26f920c07SWyon Bi  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
36f920c07SWyon Bi  *
46f920c07SWyon Bi  * SPDX-License-Identifier:	GPL-2.0+
56f920c07SWyon Bi  */
66f920c07SWyon Bi 
76f920c07SWyon Bi #include <config.h>
86f920c07SWyon Bi #include <common.h>
96f920c07SWyon Bi #include <errno.h>
106f920c07SWyon Bi #include <malloc.h>
116f920c07SWyon Bi #include <asm/unaligned.h>
126f920c07SWyon Bi #include <asm/io.h>
136f920c07SWyon Bi #include <dm/device.h>
14cb17ca6cSSandy Huang #include <dm/of_access.h>
156f920c07SWyon Bi #include <dm/read.h>
167adc0066SWyon Bi #include <linux/bitfield.h>
176f920c07SWyon Bi #include <linux/list.h>
18d67c1260SDamon Ding #include <linux/media-bus-format.h>
196f920c07SWyon Bi #include <syscon.h>
206f920c07SWyon Bi #include <asm/arch-rockchip/clock.h>
216f920c07SWyon Bi #include <asm/gpio.h>
226f920c07SWyon Bi 
236f920c07SWyon Bi #include "rockchip_display.h"
246f920c07SWyon Bi #include "rockchip_crtc.h"
256f920c07SWyon Bi #include "rockchip_connector.h"
266f920c07SWyon Bi #include "analogix_dp.h"
276f920c07SWyon Bi 
287adc0066SWyon Bi #define RK3588_GRF_VO1_CON0	0x0000
297adc0066SWyon Bi #define EDP_MODE		BIT(0)
307adc0066SWyon Bi #define RK3588_GRF_VO1_CON1	0x0004
317adc0066SWyon Bi 
326f920c07SWyon Bi /**
336f920c07SWyon Bi  * struct rockchip_dp_chip_data - splite the grf setting of kind of chips
346f920c07SWyon Bi  * @lcdsel_grf_reg: grf register offset of lcdc select
356f920c07SWyon Bi  * @lcdsel_big: reg value of selecting vop big for eDP
366f920c07SWyon Bi  * @lcdsel_lit: reg value of selecting vop little for eDP
37699c29a5SWyon Bi  * @chip_type: specific chip type
38699c29a5SWyon Bi  * @ssc: check if SSC is supported by source
39d67c1260SDamon Ding  * @max_link_rate: max supported link rate
40d67c1260SDamon Ding  * @max_lane_count: max supported lane count
41d67c1260SDamon Ding  * @format_yuv: check if yuv color format is supported
4232035f4bSDamon Ding  * @support_dp_mode: check if dp mode is supported
43d67c1260SDamon Ding  * @max_bpc: max supported bpc which set to 8 by default
446f920c07SWyon Bi  */
456f920c07SWyon Bi struct rockchip_dp_chip_data {
466f920c07SWyon Bi 	u32	lcdsel_grf_reg;
476f920c07SWyon Bi 	u32	lcdsel_big;
486f920c07SWyon Bi 	u32	lcdsel_lit;
496f920c07SWyon Bi 	u32	chip_type;
50699c29a5SWyon Bi 	bool    ssc;
517adc0066SWyon Bi 
527adc0066SWyon Bi 	u32 max_link_rate;
537adc0066SWyon Bi 	u32 max_lane_count;
54d67c1260SDamon Ding 	bool format_yuv;
5532035f4bSDamon Ding 	bool support_dp_mode;
56d67c1260SDamon Ding 	u8 max_bpc;
576f920c07SWyon Bi };
586f920c07SWyon Bi 
59d67c1260SDamon Ding static const struct analogix_dp_output_format possible_output_fmts[] = {
60d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, 10 },
61d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, 8 },
62d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, 6 },
63d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444, 10 },
64d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444, 8},
65d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422, 10 },
66d67c1260SDamon Ding 	{ MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422, 8 },
67d67c1260SDamon Ding };
68d67c1260SDamon Ding 
analogix_dp_get_output_bpp(const struct analogix_dp_output_format * fmt)69d67c1260SDamon Ding static u8 analogix_dp_get_output_bpp(const struct analogix_dp_output_format *fmt)
70d67c1260SDamon Ding {
71d67c1260SDamon Ding 	switch (fmt->color_format) {
72d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_YCRCB422:
73d67c1260SDamon Ding 		return fmt->bpc * 2;
74d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_RGB444:
75d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_YCRCB444:
76d67c1260SDamon Ding 	default:
77d67c1260SDamon Ding 		return fmt->bpc * 3;
78d67c1260SDamon Ding 	}
79d67c1260SDamon Ding }
80d67c1260SDamon Ding 
812fcb4783SDamon Ding static int
analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device * dp,bool enable)826f920c07SWyon Bi analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
836f920c07SWyon Bi 				       bool enable)
846f920c07SWyon Bi {
856f920c07SWyon Bi 	u8 data;
862fcb4783SDamon Ding 	int ret;
876f920c07SWyon Bi 
882fcb4783SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
892fcb4783SDamon Ding 	if (ret != 1)
902fcb4783SDamon Ding 		return ret;
916f920c07SWyon Bi 
926f920c07SWyon Bi 	if (enable)
932fcb4783SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
946f920c07SWyon Bi 					 DP_LANE_COUNT_ENHANCED_FRAME_EN |
956f920c07SWyon Bi 					 DPCD_LANE_COUNT_SET(data));
966f920c07SWyon Bi 	else
972fcb4783SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
986f920c07SWyon Bi 					 DPCD_LANE_COUNT_SET(data));
992fcb4783SDamon Ding 
1002fcb4783SDamon Ding 	return ret < 0 ? ret : 0;
1016f920c07SWyon Bi }
1026f920c07SWyon Bi 
analogix_dp_set_enhanced_mode(struct analogix_dp_device * dp)1032fcb4783SDamon Ding static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
1046f920c07SWyon Bi {
1051bf3c971SDamon Ding 	bool enhanced_frame_en;
1066f920c07SWyon Bi 	u8 data;
1072fcb4783SDamon Ding 	int ret;
1086f920c07SWyon Bi 
1091bf3c971SDamon Ding 	enhanced_frame_en = drm_dp_enhanced_frame_cap(dp->dpcd);
1101bf3c971SDamon Ding 
1111bf3c971SDamon Ding 	ret = analogix_dp_enable_rx_to_enhanced_mode(dp, enhanced_frame_en);
1122fcb4783SDamon Ding 	if (ret < 0)
1132fcb4783SDamon Ding 		return ret;
1142fcb4783SDamon Ding 
1151bf3c971SDamon Ding 	if (!enhanced_frame_en) {
11606b1b28fSDamon Ding 		/*
11706b1b28fSDamon Ding 		 * As the Table 3-4 in eDP v1.2 spec:
11806b1b28fSDamon Ding 		 * DPCD 0000Dh:
11906b1b28fSDamon Ding 		 * Bit 1 = FRAMING_CHANGE_CAPABLE
12006b1b28fSDamon Ding 		 * A setting of 1 indicates that this is an eDP device that
12106b1b28fSDamon Ding 		 * uses only Enhanced Framing, independently of the setting by
12206b1b28fSDamon Ding 		 * the source of ENHANCED_FRAME_EN
12306b1b28fSDamon Ding 		 *
12406b1b28fSDamon Ding 		 * And as the Table 3-3 in eDP v1.4 spec:
12506b1b28fSDamon Ding 		 * DPCD 0000Dh:
12606b1b28fSDamon Ding 		 * Bit 1 = RESERVED for eDP
12706b1b28fSDamon Ding 		 * New to eDP v1.4.(Read all 0s)
12806b1b28fSDamon Ding 		 */
12906b1b28fSDamon Ding 		ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_CAP,
13006b1b28fSDamon Ding 					&data);
13106b1b28fSDamon Ding 		if (ret < 0)
13206b1b28fSDamon Ding 			return ret;
13306b1b28fSDamon Ding 
1341bf3c971SDamon Ding 		enhanced_frame_en = !!(data & DP_FRAMING_CHANGE_CAP);
13506b1b28fSDamon Ding 	}
13606b1b28fSDamon Ding 
1371bf3c971SDamon Ding 	analogix_dp_enable_enhanced_mode(dp, enhanced_frame_en);
1382fcb4783SDamon Ding 
1392fcb4783SDamon Ding 	return 0;
1406f920c07SWyon Bi }
1416f920c07SWyon Bi 
analogix_dp_training_pattern_dis(struct analogix_dp_device * dp)1422fcb4783SDamon Ding static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
1436f920c07SWyon Bi {
1442fcb4783SDamon Ding 	int ret;
1452fcb4783SDamon Ding 
1466f920c07SWyon Bi 	analogix_dp_set_training_pattern(dp, DP_NONE);
1476f920c07SWyon Bi 
1482fcb4783SDamon Ding 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
1496f920c07SWyon Bi 				 DP_TRAINING_PATTERN_DISABLE);
1502fcb4783SDamon Ding 
1512fcb4783SDamon Ding 	return ret < 0 ? ret : 0;
1526f920c07SWyon Bi }
1536f920c07SWyon Bi 
analogix_dp_enable_sink_to_assr_mode(struct analogix_dp_device * dp,bool enable)154fc275078SDamon Ding static int analogix_dp_enable_sink_to_assr_mode(struct analogix_dp_device *dp, bool enable)
155fc275078SDamon Ding {
156fc275078SDamon Ding 	u8 data;
157fc275078SDamon Ding 	int ret;
158fc275078SDamon Ding 
159fc275078SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_SET, &data);
160fc275078SDamon Ding 	if (ret != 1)
161fc275078SDamon Ding 		return ret;
162fc275078SDamon Ding 
163fc275078SDamon Ding 	if (enable)
164fc275078SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET,
165fc275078SDamon Ding 					 data | DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
166fc275078SDamon Ding 	else
1674e1a12d5SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET,
168fc275078SDamon Ding 					 data & ~DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
169fc275078SDamon Ding 
170fc275078SDamon Ding 	return ret < 0 ? ret : 0;
171fc275078SDamon Ding }
172fc275078SDamon Ding 
analogix_dp_set_assr_mode(struct analogix_dp_device * dp)173fc275078SDamon Ding static int analogix_dp_set_assr_mode(struct analogix_dp_device *dp)
174fc275078SDamon Ding {
175fc275078SDamon Ding 	bool assr_en;
176fc275078SDamon Ding 	int ret;
177fc275078SDamon Ding 
178fc275078SDamon Ding 	assr_en = drm_dp_alternate_scrambler_reset_cap(dp->dpcd);
179fc275078SDamon Ding 
180fc275078SDamon Ding 	ret = analogix_dp_enable_sink_to_assr_mode(dp, assr_en);
181fc275078SDamon Ding 	if (ret < 0)
182fc275078SDamon Ding 		return ret;
183fc275078SDamon Ding 
184fc275078SDamon Ding 	analogix_dp_enable_assr_mode(dp, assr_en);
185fc275078SDamon Ding 
186fc275078SDamon Ding 	return 0;
187fc275078SDamon Ding }
188fc275078SDamon Ding 
analogix_dp_link_start(struct analogix_dp_device * dp)1896f920c07SWyon Bi static int analogix_dp_link_start(struct analogix_dp_device *dp)
1906f920c07SWyon Bi {
1916f920c07SWyon Bi 	u8 buf[4];
192a6285d17SWyon Bi 	int lane, lane_count, retval;
1936f920c07SWyon Bi 
1946f920c07SWyon Bi 	lane_count = dp->link_train.lane_count;
1956f920c07SWyon Bi 
1966f920c07SWyon Bi 	dp->link_train.lt_state = CLOCK_RECOVERY;
1976f920c07SWyon Bi 	dp->link_train.eq_loop = 0;
1986f920c07SWyon Bi 
1996f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++)
2006f920c07SWyon Bi 		dp->link_train.cr_loop[lane] = 0;
2016f920c07SWyon Bi 
2026f920c07SWyon Bi 	/* Set link rate and count as you want to establish */
2036f920c07SWyon Bi 	analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
2046f920c07SWyon Bi 	analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
2056f920c07SWyon Bi 
2067477c1efSDamon Ding 	if (dp->nr_link_rate_table) {
2077477c1efSDamon Ding 		/* Setup DP_LINK_RATE_SET for eDP 1.4 and later */
2082fcb4783SDamon Ding 		drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, dp->link_train.lane_count);
2092fcb4783SDamon Ding 		drm_dp_dpcd_writeb(&dp->aux, DP_LINK_RATE_SET, dp->link_rate_select);
2107477c1efSDamon Ding 	} else {
2117477c1efSDamon Ding 		/* Setup DP_LINK_BW_SET for eDP 1.3 and earlier */
2126f920c07SWyon Bi 		buf[0] = dp->link_train.link_rate;
2136f920c07SWyon Bi 		buf[1] = dp->link_train.lane_count;
2142fcb4783SDamon Ding 		retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
2152fcb4783SDamon Ding 		if (retval < 0)
2166f920c07SWyon Bi 			return retval;
2177477c1efSDamon Ding 	}
2186f920c07SWyon Bi 
219699c29a5SWyon Bi 	/* Spread AMP if required, enable 8b/10b coding */
220699c29a5SWyon Bi 	buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0;
221699c29a5SWyon Bi 	buf[1] = DP_SET_ANSI_8B10B;
2222fcb4783SDamon Ding 	retval = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 2);
223699c29a5SWyon Bi 	if (retval < 0)
224699c29a5SWyon Bi 		return retval;
225699c29a5SWyon Bi 
226fc275078SDamon Ding 	/* set ASSR if available */
227fc275078SDamon Ding 	retval = analogix_dp_set_assr_mode(dp);
228fc275078SDamon Ding 	if (retval < 0) {
229fc275078SDamon Ding 		dev_err(dp->dev, "failed to set assr mode\n");
230fc275078SDamon Ding 		return retval;
231fc275078SDamon Ding 	}
232fc275078SDamon Ding 
233ea286ea2SDamon Ding 	/* set enhanced mode if available */
234ea286ea2SDamon Ding 	retval = analogix_dp_set_enhanced_mode(dp);
235ea286ea2SDamon Ding 	if (retval < 0) {
236ea286ea2SDamon Ding 		dev_err(dp->dev, "failed to set enhance mode\n");
237ea286ea2SDamon Ding 		return retval;
238ea286ea2SDamon Ding 	}
239ea286ea2SDamon Ding 
240253c2dc8SWyon Bi 	/* Set TX voltage-swing and pre-emphasis to minimum */
2416f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++)
242253c2dc8SWyon Bi 		dp->link_train.training_lane[lane] =
243253c2dc8SWyon Bi 				DP_TRAIN_VOLTAGE_SWING_LEVEL_0 |
244253c2dc8SWyon Bi 				DP_TRAIN_PRE_EMPH_LEVEL_0;
245253c2dc8SWyon Bi 	analogix_dp_set_lane_link_training(dp);
2466f920c07SWyon Bi 
2476f920c07SWyon Bi 	/* Set training pattern 1 */
2486f920c07SWyon Bi 	analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
2496f920c07SWyon Bi 
2506f920c07SWyon Bi 	/* Set RX training pattern */
2512fcb4783SDamon Ding 	retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
2526f920c07SWyon Bi 				    DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1);
2532fcb4783SDamon Ding 	if (retval < 0)
2546f920c07SWyon Bi 		return retval;
2556f920c07SWyon Bi 
2566f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++)
2576f920c07SWyon Bi 		buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
2586f920c07SWyon Bi 			    DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
2596f920c07SWyon Bi 
2602fcb4783SDamon Ding 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf,
2612fcb4783SDamon Ding 				   lane_count);
2622fcb4783SDamon Ding 	if (retval < 0)
2636f920c07SWyon Bi 		return retval;
2642fcb4783SDamon Ding 
2652fcb4783SDamon Ding 	return 0;
2666f920c07SWyon Bi }
2676f920c07SWyon Bi 
analogix_dp_get_lane_status(u8 link_status[2],int lane)2686f920c07SWyon Bi static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane)
2696f920c07SWyon Bi {
2706f920c07SWyon Bi 	int shift = (lane & 1) * 4;
2716f920c07SWyon Bi 	u8 link_value = link_status[lane >> 1];
2726f920c07SWyon Bi 
2736f920c07SWyon Bi 	return (link_value >> shift) & 0xf;
2746f920c07SWyon Bi }
2756f920c07SWyon Bi 
analogix_dp_clock_recovery_ok(u8 link_status[2],int lane_count)2766f920c07SWyon Bi static int analogix_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
2776f920c07SWyon Bi {
2786f920c07SWyon Bi 	int lane;
2796f920c07SWyon Bi 	u8 lane_status;
2806f920c07SWyon Bi 
2816f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++) {
2826f920c07SWyon Bi 		lane_status = analogix_dp_get_lane_status(link_status, lane);
2836f920c07SWyon Bi 		if ((lane_status & DP_LANE_CR_DONE) == 0)
2846f920c07SWyon Bi 			return -EINVAL;
2856f920c07SWyon Bi 	}
2866f920c07SWyon Bi 	return 0;
2876f920c07SWyon Bi }
2886f920c07SWyon Bi 
analogix_dp_channel_eq_ok(u8 link_status[2],u8 link_align,int lane_count)2896f920c07SWyon Bi static int analogix_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
2906f920c07SWyon Bi 				     int lane_count)
2916f920c07SWyon Bi {
2926f920c07SWyon Bi 	int lane;
2936f920c07SWyon Bi 	u8 lane_status;
2946f920c07SWyon Bi 
2956f920c07SWyon Bi 	if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0)
2966f920c07SWyon Bi 		return -EINVAL;
2976f920c07SWyon Bi 
2986f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++) {
2996f920c07SWyon Bi 		lane_status = analogix_dp_get_lane_status(link_status, lane);
3006f920c07SWyon Bi 		lane_status &= DP_CHANNEL_EQ_BITS;
3016f920c07SWyon Bi 		if (lane_status != DP_CHANNEL_EQ_BITS)
3026f920c07SWyon Bi 			return -EINVAL;
3036f920c07SWyon Bi 	}
3046f920c07SWyon Bi 
3056f920c07SWyon Bi 	return 0;
3066f920c07SWyon Bi }
3076f920c07SWyon Bi 
3086f920c07SWyon Bi static unsigned char
analogix_dp_get_adjust_request_voltage(u8 adjust_request[2],int lane)3096f920c07SWyon Bi analogix_dp_get_adjust_request_voltage(u8 adjust_request[2], int lane)
3106f920c07SWyon Bi {
3116f920c07SWyon Bi 	int shift = (lane & 1) * 4;
3126f920c07SWyon Bi 	u8 link_value = adjust_request[lane >> 1];
3136f920c07SWyon Bi 
3146f920c07SWyon Bi 	return (link_value >> shift) & 0x3;
3156f920c07SWyon Bi }
3166f920c07SWyon Bi 
analogix_dp_get_adjust_request_pre_emphasis(u8 adjust_request[2],int lane)3176f920c07SWyon Bi static unsigned char analogix_dp_get_adjust_request_pre_emphasis(
3186f920c07SWyon Bi 					u8 adjust_request[2],
3196f920c07SWyon Bi 					int lane)
3206f920c07SWyon Bi {
3216f920c07SWyon Bi 	int shift = (lane & 1) * 4;
3226f920c07SWyon Bi 	u8 link_value = adjust_request[lane >> 1];
3236f920c07SWyon Bi 
3246f920c07SWyon Bi 	return ((link_value >> shift) & 0xc) >> 2;
3256f920c07SWyon Bi }
3266f920c07SWyon Bi 
analogix_dp_reduce_link_rate(struct analogix_dp_device * dp)3276f920c07SWyon Bi static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp)
3286f920c07SWyon Bi {
3296f920c07SWyon Bi 	analogix_dp_training_pattern_dis(dp);
3306f920c07SWyon Bi 	analogix_dp_set_enhanced_mode(dp);
3316f920c07SWyon Bi 
3326f920c07SWyon Bi 	dp->link_train.lt_state = FAILED;
3336f920c07SWyon Bi }
3346f920c07SWyon Bi 
analogix_dp_get_adjust_training_lane(struct analogix_dp_device * dp,u8 adjust_request[2])3356f920c07SWyon Bi static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp,
3366f920c07SWyon Bi 						 u8 adjust_request[2])
3376f920c07SWyon Bi {
3386f920c07SWyon Bi 	int lane, lane_count;
3396f920c07SWyon Bi 	u8 voltage_swing, pre_emphasis, training_lane;
3406f920c07SWyon Bi 
3416f920c07SWyon Bi 	lane_count = dp->link_train.lane_count;
3426f920c07SWyon Bi 	for (lane = 0; lane < lane_count; lane++) {
3436f920c07SWyon Bi 		voltage_swing = analogix_dp_get_adjust_request_voltage(
3446f920c07SWyon Bi 						adjust_request, lane);
3456f920c07SWyon Bi 		pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(
3466f920c07SWyon Bi 						adjust_request, lane);
3476f920c07SWyon Bi 		training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
3486f920c07SWyon Bi 				DPCD_PRE_EMPHASIS_SET(pre_emphasis);
3496f920c07SWyon Bi 
3506f920c07SWyon Bi 		if (voltage_swing == VOLTAGE_LEVEL_3)
3516f920c07SWyon Bi 			training_lane |= DP_TRAIN_MAX_SWING_REACHED;
3526f920c07SWyon Bi 		if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
3536f920c07SWyon Bi 			training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
3546f920c07SWyon Bi 
3556f920c07SWyon Bi 		dp->link_train.training_lane[lane] = training_lane;
3566f920c07SWyon Bi 	}
3576f920c07SWyon Bi }
3586f920c07SWyon Bi 
analogix_dp_tps3_supported(struct analogix_dp_device * dp)3597adc0066SWyon Bi static bool analogix_dp_tps3_supported(struct analogix_dp_device *dp)
3607adc0066SWyon Bi {
3617adc0066SWyon Bi 	bool source_tps3_supported, sink_tps3_supported;
3627adc0066SWyon Bi 	u8 dpcd = 0;
3637adc0066SWyon Bi 
3647adc0066SWyon Bi 	source_tps3_supported =
3657adc0066SWyon Bi 		dp->video_info.max_link_rate == DP_LINK_BW_5_4;
3662fcb4783SDamon Ding 	drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &dpcd);
3677adc0066SWyon Bi 	sink_tps3_supported = dpcd & DP_TPS3_SUPPORTED;
3687adc0066SWyon Bi 
3697adc0066SWyon Bi 	return source_tps3_supported && sink_tps3_supported;
3707adc0066SWyon Bi }
3717adc0066SWyon Bi 
analogix_dp_process_clock_recovery(struct analogix_dp_device * dp)3726f920c07SWyon Bi static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
3736f920c07SWyon Bi {
3746f920c07SWyon Bi 	int lane, lane_count, retval;
3756f920c07SWyon Bi 	u8 voltage_swing, pre_emphasis, training_lane;
3766f920c07SWyon Bi 	u8 link_status[2], adjust_request[2];
3777adc0066SWyon Bi 	u8 training_pattern = TRAINING_PTN2;
3786f920c07SWyon Bi 
3791a00cf6eSWyon Bi 	drm_dp_link_train_clock_recovery_delay(dp->dpcd);
3806f920c07SWyon Bi 
3816f920c07SWyon Bi 	lane_count = dp->link_train.lane_count;
3826f920c07SWyon Bi 
3832fcb4783SDamon Ding 	retval =  drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
3842fcb4783SDamon Ding 	if (retval < 0)
3856f920c07SWyon Bi 		return retval;
3866f920c07SWyon Bi 
3876f920c07SWyon Bi 	if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) {
3887adc0066SWyon Bi 		if (analogix_dp_tps3_supported(dp))
3897adc0066SWyon Bi 			training_pattern = TRAINING_PTN3;
3907adc0066SWyon Bi 
3917adc0066SWyon Bi 		/* set training pattern for EQ */
3927adc0066SWyon Bi 		analogix_dp_set_training_pattern(dp, training_pattern);
3936f920c07SWyon Bi 
3942fcb4783SDamon Ding 		retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
3952fcb4783SDamon Ding 					    DP_LINK_SCRAMBLING_DISABLE |
3967adc0066SWyon Bi 					    (training_pattern == TRAINING_PTN3 ?
3977adc0066SWyon Bi 					     DP_TRAINING_PATTERN_3 : DP_TRAINING_PATTERN_2));
3982fcb4783SDamon Ding 		if (retval < 0)
3996f920c07SWyon Bi 			return retval;
4006f920c07SWyon Bi 
4016f920c07SWyon Bi 		dev_info(dp->dev, "Link Training Clock Recovery success\n");
4026f920c07SWyon Bi 		dp->link_train.lt_state = EQUALIZER_TRAINING;
40310d706d5SWyon Bi 
40410d706d5SWyon Bi 		return 0;
4056f920c07SWyon Bi 	} else {
4062fcb4783SDamon Ding 		retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1,
4072fcb4783SDamon Ding 					  adjust_request, 2);
4082fcb4783SDamon Ding 		if (retval < 0)
40910d706d5SWyon Bi 			return retval;
41010d706d5SWyon Bi 
4116f920c07SWyon Bi 		for (lane = 0; lane < lane_count; lane++) {
4126f920c07SWyon Bi 			training_lane = analogix_dp_get_lane_link_training(
4136f920c07SWyon Bi 							dp, lane);
4146f920c07SWyon Bi 			voltage_swing = analogix_dp_get_adjust_request_voltage(
4156f920c07SWyon Bi 							adjust_request, lane);
4166f920c07SWyon Bi 			pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(
4176f920c07SWyon Bi 							adjust_request, lane);
4186f920c07SWyon Bi 
4196f920c07SWyon Bi 			if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
4206f920c07SWyon Bi 					voltage_swing &&
4216f920c07SWyon Bi 			    DPCD_PRE_EMPHASIS_GET(training_lane) ==
4226f920c07SWyon Bi 					pre_emphasis)
4236f920c07SWyon Bi 				dp->link_train.cr_loop[lane]++;
4246f920c07SWyon Bi 
4251ee9f77bSGuochun Huang 			/*
4261ee9f77bSGuochun Huang 			 * In DP spec 1.3, Condition of CR fail are
4271ee9f77bSGuochun Huang 			 * outlined in section 3.5.1.2.2.1, figure 3-20:
4281ee9f77bSGuochun Huang 			 *
4291ee9f77bSGuochun Huang 			 * 1. Maximum Voltage Swing reached
4301ee9f77bSGuochun Huang 			 * 2. Same Voltage five times
4311ee9f77bSGuochun Huang 			 */
4326f920c07SWyon Bi 			if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
4331ee9f77bSGuochun Huang 			    DPCD_VOLTAGE_SWING_GET(training_lane) == VOLTAGE_LEVEL_3) {
4346f920c07SWyon Bi 				dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
4356f920c07SWyon Bi 					dp->link_train.cr_loop[lane],
4366f920c07SWyon Bi 					voltage_swing, pre_emphasis);
4376f920c07SWyon Bi 				analogix_dp_reduce_link_rate(dp);
4386f920c07SWyon Bi 				return -EIO;
4396f920c07SWyon Bi 			}
4406f920c07SWyon Bi 		}
4416f920c07SWyon Bi 	}
4426f920c07SWyon Bi 
4436f920c07SWyon Bi 	analogix_dp_get_adjust_training_lane(dp, adjust_request);
444253c2dc8SWyon Bi 	analogix_dp_set_lane_link_training(dp);
4456f920c07SWyon Bi 
4462fcb4783SDamon Ding 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
4472fcb4783SDamon Ding 				   dp->link_train.training_lane, lane_count);
4482fcb4783SDamon Ding 	if (retval < 0)
4496f920c07SWyon Bi 		return retval;
4506f920c07SWyon Bi 
4512fcb4783SDamon Ding 	return 0;
4526f920c07SWyon Bi }
4536f920c07SWyon Bi 
analogix_dp_process_equalizer_training(struct analogix_dp_device * dp)4546f920c07SWyon Bi static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
4556f920c07SWyon Bi {
456253c2dc8SWyon Bi 	int lane_count, retval;
4576f920c07SWyon Bi 	u32 reg;
4586f920c07SWyon Bi 	u8 link_align, link_status[2], adjust_request[2];
4596f920c07SWyon Bi 
4601a00cf6eSWyon Bi 	drm_dp_link_train_channel_eq_delay(dp->dpcd);
4616f920c07SWyon Bi 
4626f920c07SWyon Bi 	lane_count = dp->link_train.lane_count;
4636f920c07SWyon Bi 
4642fcb4783SDamon Ding 	retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2);
4652fcb4783SDamon Ding 	if (retval < 0)
4666f920c07SWyon Bi 		return retval;
4676f920c07SWyon Bi 
4686f920c07SWyon Bi 	if (analogix_dp_clock_recovery_ok(link_status, lane_count)) {
4696f920c07SWyon Bi 		analogix_dp_reduce_link_rate(dp);
4706f920c07SWyon Bi 		return -EIO;
4716f920c07SWyon Bi 	}
4726f920c07SWyon Bi 
4732fcb4783SDamon Ding 	retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, &link_align);
4742fcb4783SDamon Ding 	if (retval < 0)
4756f920c07SWyon Bi 		return retval;
4766f920c07SWyon Bi 
4776f920c07SWyon Bi 	if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) {
4786f920c07SWyon Bi 		/* traing pattern Set to Normal */
4792fcb4783SDamon Ding 		retval = analogix_dp_training_pattern_dis(dp);
4802fcb4783SDamon Ding 		if (retval < 0)
4812fcb4783SDamon Ding 			return retval;
4826f920c07SWyon Bi 
4836f920c07SWyon Bi 		printf("Link Training success!\n");
4846f920c07SWyon Bi 
4856f920c07SWyon Bi 		analogix_dp_get_link_bandwidth(dp, &reg);
4866f920c07SWyon Bi 		dp->link_train.link_rate = reg;
4876f920c07SWyon Bi 		analogix_dp_get_lane_count(dp, &reg);
4886f920c07SWyon Bi 		dp->link_train.lane_count = reg;
4896f920c07SWyon Bi 
4906f920c07SWyon Bi 		printf("final link rate = 0x%.2x, lane count = 0x%.2x\n",
4916f920c07SWyon Bi 		       dp->link_train.link_rate, dp->link_train.lane_count);
4926f920c07SWyon Bi 
4936f920c07SWyon Bi 		dp->link_train.lt_state = FINISHED;
4946f920c07SWyon Bi 
4956f920c07SWyon Bi 		return 0;
4966f920c07SWyon Bi 	}
4976f920c07SWyon Bi 
4986f920c07SWyon Bi 	/* not all locked */
4996f920c07SWyon Bi 	dp->link_train.eq_loop++;
5006f920c07SWyon Bi 
5016f920c07SWyon Bi 	if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
5026f920c07SWyon Bi 		dev_dbg(dp->dev, "EQ Max loop\n");
5036f920c07SWyon Bi 		analogix_dp_reduce_link_rate(dp);
5046f920c07SWyon Bi 		return -EIO;
5056f920c07SWyon Bi 	}
5066f920c07SWyon Bi 
5072fcb4783SDamon Ding 	retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, adjust_request, 2);
5082fcb4783SDamon Ding 	if (retval < 0)
50910d706d5SWyon Bi 		return retval;
51010d706d5SWyon Bi 
51110d706d5SWyon Bi 	analogix_dp_get_adjust_training_lane(dp, adjust_request);
512253c2dc8SWyon Bi 	analogix_dp_set_lane_link_training(dp);
5136f920c07SWyon Bi 
5142fcb4783SDamon Ding 	retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
5152fcb4783SDamon Ding 				   dp->link_train.training_lane, lane_count);
5162fcb4783SDamon Ding 	if (retval < 0)
5176f920c07SWyon Bi 		return retval;
5182fcb4783SDamon Ding 
5192fcb4783SDamon Ding 	return 0;
5206f920c07SWyon Bi }
5216f920c07SWyon Bi 
analogix_dp_bandwidth_ok(struct analogix_dp_device * dp,const struct drm_display_mode * mode,u32 bpp,unsigned int rate,unsigned int lanes)5227477c1efSDamon Ding static bool analogix_dp_bandwidth_ok(struct analogix_dp_device *dp,
523d67c1260SDamon Ding 				     const struct drm_display_mode *mode, u32 bpp,
5247477c1efSDamon Ding 				     unsigned int rate, unsigned int lanes)
5257477c1efSDamon Ding {
5267477c1efSDamon Ding 	u32 max_bw, req_bw;
5277477c1efSDamon Ding 
5287477c1efSDamon Ding 	req_bw = mode->clock * bpp / 8;
5297477c1efSDamon Ding 	max_bw = lanes * rate;
5307477c1efSDamon Ding 	if (req_bw > max_bw)
5317477c1efSDamon Ding 		return false;
5327477c1efSDamon Ding 
5337477c1efSDamon Ding 	return true;
5347477c1efSDamon Ding }
5357477c1efSDamon Ding 
analogix_dp_link_config_validate(u8 link_rate,u8 lane_count)5367477c1efSDamon Ding static bool analogix_dp_link_config_validate(u8 link_rate, u8 lane_count)
5377477c1efSDamon Ding {
5387477c1efSDamon Ding 	switch (link_rate) {
5397477c1efSDamon Ding 	case DP_LINK_BW_1_62:
5407477c1efSDamon Ding 	case DP_LINK_BW_2_7:
5417477c1efSDamon Ding 	case DP_LINK_BW_5_4:
542ead74bb6SDamon Ding 	/* Supported link rate in eDP 1.4 */
543ead74bb6SDamon Ding 	case EDP_LINK_BW_2_16:
544ead74bb6SDamon Ding 	case EDP_LINK_BW_2_43:
545ead74bb6SDamon Ding 	case EDP_LINK_BW_3_24:
546ead74bb6SDamon Ding 	case EDP_LINK_BW_4_32:
5477477c1efSDamon Ding 		break;
5487477c1efSDamon Ding 	default:
5497477c1efSDamon Ding 		return false;
5507477c1efSDamon Ding 	}
5517477c1efSDamon Ding 
5527477c1efSDamon Ding 	switch (lane_count) {
5537477c1efSDamon Ding 	case LANE_COUNT1:
5547477c1efSDamon Ding 	case LANE_COUNT2:
5557477c1efSDamon Ding 	case LANE_COUNT4:
5567477c1efSDamon Ding 		break;
5577477c1efSDamon Ding 	default:
5587477c1efSDamon Ding 		return false;
5597477c1efSDamon Ding 	}
5607477c1efSDamon Ding 
5617477c1efSDamon Ding 	return true;
5627477c1efSDamon Ding }
5637477c1efSDamon Ding 
analogix_dp_select_link_rate_from_table(struct analogix_dp_device * dp)5647477c1efSDamon Ding static int analogix_dp_select_link_rate_from_table(struct analogix_dp_device *dp)
5657477c1efSDamon Ding {
5667477c1efSDamon Ding 	int i;
5677477c1efSDamon Ding 	u8 bw_code;
5687477c1efSDamon Ding 	u32 max_link_rate = drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate);
5697477c1efSDamon Ding 
5707477c1efSDamon Ding 	for (i = 0; i < dp->nr_link_rate_table; i++) {
5717477c1efSDamon Ding 		bw_code =  drm_dp_link_rate_to_bw_code(dp->link_rate_table[i]);
5727477c1efSDamon Ding 
573d67c1260SDamon Ding 		if (!analogix_dp_bandwidth_ok(dp, &dp->video_info.mode,
574d67c1260SDamon Ding 					      analogix_dp_get_output_bpp(dp->output_fmt),
575d67c1260SDamon Ding 					      dp->link_rate_table[i], dp->link_train.lane_count))
5767477c1efSDamon Ding 			continue;
5777477c1efSDamon Ding 
5787477c1efSDamon Ding 		if (dp->link_rate_table[i] <= max_link_rate &&
5797477c1efSDamon Ding 		    analogix_dp_link_config_validate(bw_code, dp->link_train.lane_count)) {
5807477c1efSDamon Ding 			dp->link_rate_select = i;
5817477c1efSDamon Ding 			return bw_code;
5827477c1efSDamon Ding 		}
5837477c1efSDamon Ding 	}
5847477c1efSDamon Ding 
5857477c1efSDamon Ding 	return 0;
5867477c1efSDamon Ding }
5877477c1efSDamon Ding 
analogix_dp_select_rx_bandwidth(struct analogix_dp_device * dp)5887477c1efSDamon Ding static int analogix_dp_select_rx_bandwidth(struct analogix_dp_device *dp)
5897477c1efSDamon Ding {
5907477c1efSDamon Ding 	if (dp->nr_link_rate_table)
5917477c1efSDamon Ding 		/*
5927477c1efSDamon Ding 		 * Select the smallest one among link rates which meet
5937477c1efSDamon Ding 		 * the bandwidth requirement for eDP 1.4 and later.
5947477c1efSDamon Ding 		 */
5957477c1efSDamon Ding 		dp->link_train.link_rate = analogix_dp_select_link_rate_from_table(dp);
5967477c1efSDamon Ding 	else
5977477c1efSDamon Ding 		/*
5987477c1efSDamon Ding 		 * Select the smaller one between rx DP_MAX_LINK_RATE
5997477c1efSDamon Ding 		 * and the max link rate supported by the platform.
6007477c1efSDamon Ding 		 */
6017477c1efSDamon Ding 		dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate,
6027477c1efSDamon Ding 						 dp->video_info.max_link_rate);
6037477c1efSDamon Ding 	if (!dp->link_train.link_rate)
6047477c1efSDamon Ding 		return -EINVAL;
6057477c1efSDamon Ding 
6067477c1efSDamon Ding 	return 0;
6077477c1efSDamon Ding }
6087477c1efSDamon Ding 
analogix_dp_init_link_rate_table(struct analogix_dp_device * dp)6097477c1efSDamon Ding static int analogix_dp_init_link_rate_table(struct analogix_dp_device *dp)
6107477c1efSDamon Ding {
6117477c1efSDamon Ding 	u8 link_rate_table[DP_MAX_SUPPORTED_RATES * 2];
6127477c1efSDamon Ding 	int i;
6137477c1efSDamon Ding 	int ret;
6147477c1efSDamon Ding 
6152fcb4783SDamon Ding 	ret = drm_dp_dpcd_read(&dp->aux, DP_SUPPORTED_LINK_RATES, link_rate_table,
6162fcb4783SDamon Ding 			       sizeof(link_rate_table));
6172fcb4783SDamon Ding 	if (ret < 0)
6187477c1efSDamon Ding 		return ret;
6197477c1efSDamon Ding 
6207477c1efSDamon Ding 	for (i = 0; i < ARRAY_SIZE(link_rate_table) / 2; i++) {
6217477c1efSDamon Ding 		int val = link_rate_table[2 * i] | link_rate_table[2 * i + 1] << 8;
6227477c1efSDamon Ding 
6237477c1efSDamon Ding 		if (val == 0)
6247477c1efSDamon Ding 			break;
6257477c1efSDamon Ding 
6267477c1efSDamon Ding 		/* Convert to the link_rate as drm_dp_bw_code_to_link_rate() */
6277477c1efSDamon Ding 		dp->link_rate_table[i] = (val * 20);
6287477c1efSDamon Ding 	}
6297477c1efSDamon Ding 	dp->nr_link_rate_table = i;
6307477c1efSDamon Ding 
6317477c1efSDamon Ding 	return 0;
6327477c1efSDamon Ding }
6337477c1efSDamon Ding 
analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device * dp,u8 * bandwidth)6342fcb4783SDamon Ding static int analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp,
6356f920c07SWyon Bi 					    u8 *bandwidth)
6366f920c07SWyon Bi {
6376f920c07SWyon Bi 	u8 data;
6387477c1efSDamon Ding 	int ret;
6396f920c07SWyon Bi 
6402fcb4783SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_DPCD_REV, &data);
6412fcb4783SDamon Ding 	if (ret == 1 && data >= DP_EDP_14) {
6427477c1efSDamon Ding 		u32 max_link_rate;
6437477c1efSDamon Ding 
6447477c1efSDamon Ding 		/* As the Table 4-23 in eDP 1.4 spec, the link rate table is required */
6457477c1efSDamon Ding 		if (!dp->nr_link_rate_table) {
6462fcb4783SDamon Ding 			dev_info(dp->dev, "eDP version: 0x%02x supports link rate table\n",
6472fcb4783SDamon Ding 					data);
6487477c1efSDamon Ding 
6497477c1efSDamon Ding 			if (analogix_dp_init_link_rate_table(dp))
6502fcb4783SDamon Ding 				dev_err(dp->dev, "failed to read link rate table: %d\n",
6512fcb4783SDamon Ding 					ret);
6527477c1efSDamon Ding 		}
6537477c1efSDamon Ding 		max_link_rate = dp->link_rate_table[dp->nr_link_rate_table - 1];
6547477c1efSDamon Ding 		*bandwidth = drm_dp_link_rate_to_bw_code(max_link_rate);
6557477c1efSDamon Ding 	} else {
6566f920c07SWyon Bi 		/*
6576f920c07SWyon Bi 		 * For DP rev.1.1, Maximum link rate of Main Link lanes
6586f920c07SWyon Bi 		 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
6596f920c07SWyon Bi 		 * For DP rev.1.2, Maximum link rate of Main Link lanes
6606f920c07SWyon Bi 		 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps
6616f920c07SWyon Bi 		*/
6622fcb4783SDamon Ding 		ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data);
6632fcb4783SDamon Ding 		if (ret < 0)
6642fcb4783SDamon Ding 			return ret;
6652fcb4783SDamon Ding 
6666f920c07SWyon Bi 		*bandwidth = data;
6676f920c07SWyon Bi 	}
6682fcb4783SDamon Ding 
6692fcb4783SDamon Ding 	return 0;
6707477c1efSDamon Ding }
6716f920c07SWyon Bi 
analogix_dp_get_max_rx_lane_count(struct analogix_dp_device * dp,u8 * lane_count)6722fcb4783SDamon Ding static int analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp,
6736f920c07SWyon Bi 					      u8 *lane_count)
6746f920c07SWyon Bi {
6756f920c07SWyon Bi 	u8 data;
6762fcb4783SDamon Ding 	int ret;
6776f920c07SWyon Bi 
6786f920c07SWyon Bi 	/*
6796f920c07SWyon Bi 	 * For DP rev.1.1, Maximum number of Main Link lanes
6806f920c07SWyon Bi 	 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
6816f920c07SWyon Bi 	 */
6822fcb4783SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
6832fcb4783SDamon Ding 	if (ret < 0)
6842fcb4783SDamon Ding 		return ret;
6852fcb4783SDamon Ding 
6866f920c07SWyon Bi 	*lane_count = DPCD_MAX_LANE_COUNT(data);
6872fcb4783SDamon Ding 
6882fcb4783SDamon Ding 	return 0;
6896f920c07SWyon Bi }
6906f920c07SWyon Bi 
analogix_dp_init_training(struct analogix_dp_device * dp,enum link_lane_count_type max_lane,int max_rate)6916f920c07SWyon Bi static int analogix_dp_init_training(struct analogix_dp_device *dp,
6926f920c07SWyon Bi 				     enum link_lane_count_type max_lane,
6936f920c07SWyon Bi 				     int max_rate)
6946f920c07SWyon Bi {
695699c29a5SWyon Bi 	u8 dpcd;
696699c29a5SWyon Bi 
6976f920c07SWyon Bi 	/*
6986f920c07SWyon Bi 	 * MACRO_RST must be applied after the PLL_LOCK to avoid
6996f920c07SWyon Bi 	 * the DP inter pair skew issue for at least 10 us
7006f920c07SWyon Bi 	 */
7016f920c07SWyon Bi 	analogix_dp_reset_macro(dp);
7026f920c07SWyon Bi 
7037477c1efSDamon Ding 	/* Setup TX lane count */
7047477c1efSDamon Ding 	dp->link_train.lane_count = min_t(u32, dp->link_train.lane_count, max_lane);
7057477c1efSDamon Ding 
7067477c1efSDamon Ding 	/* Setup TX lane rate */
7077477c1efSDamon Ding 	if (analogix_dp_select_rx_bandwidth(dp)) {
7087477c1efSDamon Ding 		dev_err(dp->dev, "Select rx bandwidth failed\n");
7097477c1efSDamon Ding 		return -EINVAL;
7107477c1efSDamon Ding 	}
7116f920c07SWyon Bi 
7122fcb4783SDamon Ding 	drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &dpcd);
713699c29a5SWyon Bi 	dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5);
714699c29a5SWyon Bi 
7156f920c07SWyon Bi 	/* All DP analog module power up */
7166f920c07SWyon Bi 	analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
7176f920c07SWyon Bi 
7186f920c07SWyon Bi 	return 0;
7196f920c07SWyon Bi }
7206f920c07SWyon Bi 
analogix_dp_sw_link_training(struct analogix_dp_device * dp)7216f920c07SWyon Bi static int analogix_dp_sw_link_training(struct analogix_dp_device *dp)
7226f920c07SWyon Bi {
7236f920c07SWyon Bi 	int retval = 0, training_finished = 0;
7246f920c07SWyon Bi 
7256f920c07SWyon Bi 	dp->link_train.lt_state = START;
7266f920c07SWyon Bi 
7276f920c07SWyon Bi 	/* Process here */
7286f920c07SWyon Bi 	while (!retval && !training_finished) {
7296f920c07SWyon Bi 		switch (dp->link_train.lt_state) {
7306f920c07SWyon Bi 		case START:
7316f920c07SWyon Bi 			retval = analogix_dp_link_start(dp);
7326f920c07SWyon Bi 			if (retval)
7336f920c07SWyon Bi 				dev_err(dp->dev, "LT link start failed!\n");
7346f920c07SWyon Bi 			break;
7356f920c07SWyon Bi 		case CLOCK_RECOVERY:
7366f920c07SWyon Bi 			retval = analogix_dp_process_clock_recovery(dp);
7376f920c07SWyon Bi 			if (retval)
7386f920c07SWyon Bi 				dev_err(dp->dev, "LT CR failed!\n");
7396f920c07SWyon Bi 			break;
7406f920c07SWyon Bi 		case EQUALIZER_TRAINING:
7416f920c07SWyon Bi 			retval = analogix_dp_process_equalizer_training(dp);
7426f920c07SWyon Bi 			if (retval)
7436f920c07SWyon Bi 				dev_err(dp->dev, "LT EQ failed!\n");
7446f920c07SWyon Bi 			break;
7456f920c07SWyon Bi 		case FINISHED:
7466f920c07SWyon Bi 			training_finished = 1;
7476f920c07SWyon Bi 			break;
7486f920c07SWyon Bi 		case FAILED:
7496f920c07SWyon Bi 			return -EREMOTEIO;
7506f920c07SWyon Bi 		}
7516f920c07SWyon Bi 	}
7526f920c07SWyon Bi 
7536f920c07SWyon Bi 	return retval;
7546f920c07SWyon Bi }
7556f920c07SWyon Bi 
analogix_dp_set_link_train(struct analogix_dp_device * dp,u32 count,u32 bwtype)7566f920c07SWyon Bi static int analogix_dp_set_link_train(struct analogix_dp_device *dp,
7576f920c07SWyon Bi 				      u32 count, u32 bwtype)
7586f920c07SWyon Bi {
75921069358SWyon Bi 	int i, ret;
7606f920c07SWyon Bi 
76121069358SWyon Bi 	for (i = 0; i < 5; i++) {
7626f920c07SWyon Bi 		ret = analogix_dp_init_training(dp, count, bwtype);
7636f920c07SWyon Bi 		if (ret < 0) {
7646f920c07SWyon Bi 			dev_err(dp->dev, "failed to init training\n");
7656f920c07SWyon Bi 			return ret;
7666f920c07SWyon Bi 		}
7676f920c07SWyon Bi 
7686f920c07SWyon Bi 		ret = analogix_dp_sw_link_training(dp);
76921069358SWyon Bi 		if (!ret)
77021069358SWyon Bi 			break;
7716f920c07SWyon Bi 	}
7726f920c07SWyon Bi 
77321069358SWyon Bi 	return ret;
7746f920c07SWyon Bi }
7756f920c07SWyon Bi 
analogix_dp_config_video(struct analogix_dp_device * dp)7766f920c07SWyon Bi static int analogix_dp_config_video(struct analogix_dp_device *dp)
7776f920c07SWyon Bi {
7786f920c07SWyon Bi 	int timeout_loop = 0;
7796f920c07SWyon Bi 	int done_count = 0;
7806f920c07SWyon Bi 
7816f920c07SWyon Bi 	analogix_dp_config_video_slave_mode(dp);
7826f920c07SWyon Bi 
7836f920c07SWyon Bi 	analogix_dp_set_video_color_format(dp);
7846f920c07SWyon Bi 
7856f920c07SWyon Bi 	if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
7866f920c07SWyon Bi 		dev_err(dp->dev, "PLL is not locked yet.\n");
7876f920c07SWyon Bi 		return -EINVAL;
7886f920c07SWyon Bi 	}
7896f920c07SWyon Bi 
7906f920c07SWyon Bi 	for (;;) {
7916f920c07SWyon Bi 		timeout_loop++;
7926f920c07SWyon Bi 		if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0)
7936f920c07SWyon Bi 			break;
7946f920c07SWyon Bi 		if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
7956f920c07SWyon Bi 			dev_err(dp->dev, "Timeout of video streamclk ok\n");
7966f920c07SWyon Bi 			return -ETIMEDOUT;
7976f920c07SWyon Bi 		}
7986f920c07SWyon Bi 
7996f920c07SWyon Bi 		udelay(2);
8006f920c07SWyon Bi 	}
8016f920c07SWyon Bi 
8026f920c07SWyon Bi 	/* Set to use the register calculated M/N video */
8036f920c07SWyon Bi 	analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
8046f920c07SWyon Bi 
8056f920c07SWyon Bi 	/* For video bist, Video timing must be generated by register */
806e9cac7f1SWyon Bi 	analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_REGISTER);
8076f920c07SWyon Bi 
8086f920c07SWyon Bi 	/* Disable video mute */
8096f920c07SWyon Bi 	analogix_dp_enable_video_mute(dp, 0);
8106f920c07SWyon Bi 
8116f920c07SWyon Bi 	/* Configure video slave mode */
8126f920c07SWyon Bi 	analogix_dp_enable_video_master(dp, 0);
8136f920c07SWyon Bi 
8146f920c07SWyon Bi 	/* Enable video input */
8156f920c07SWyon Bi 	analogix_dp_start_video(dp);
8166f920c07SWyon Bi 
8176f920c07SWyon Bi 	timeout_loop = 0;
8186f920c07SWyon Bi 
8196f920c07SWyon Bi 	for (;;) {
8206f920c07SWyon Bi 		timeout_loop++;
8216f920c07SWyon Bi 		if (analogix_dp_is_video_stream_on(dp) == 0) {
8226f920c07SWyon Bi 			done_count++;
8236f920c07SWyon Bi 			if (done_count > 10)
8246f920c07SWyon Bi 				break;
8256f920c07SWyon Bi 		} else if (done_count) {
8266f920c07SWyon Bi 			done_count = 0;
8276f920c07SWyon Bi 		}
8286f920c07SWyon Bi 		if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
8296f920c07SWyon Bi 			dev_err(dp->dev, "Timeout of video streamclk ok\n");
8306f920c07SWyon Bi 			return -ETIMEDOUT;
8316f920c07SWyon Bi 		}
8326f920c07SWyon Bi 
8336f920c07SWyon Bi 		udelay(1001);
8346f920c07SWyon Bi 	}
8356f920c07SWyon Bi 
8366f920c07SWyon Bi 	return 0;
8376f920c07SWyon Bi }
8386f920c07SWyon Bi 
analogix_dp_enable_scramble(struct analogix_dp_device * dp,bool enable)8392fcb4783SDamon Ding static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
8406f920c07SWyon Bi 					bool enable)
8416f920c07SWyon Bi {
8426f920c07SWyon Bi 	u8 data;
8432fcb4783SDamon Ding 	int ret;
8446f920c07SWyon Bi 
8456f920c07SWyon Bi 	if (enable) {
8466f920c07SWyon Bi 		analogix_dp_enable_scrambling(dp);
8476f920c07SWyon Bi 
8482fcb4783SDamon Ding 		ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
8496f920c07SWyon Bi 					&data);
8502fcb4783SDamon Ding 		if (ret != 1)
8512fcb4783SDamon Ding 			return ret;
8522fcb4783SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
8536f920c07SWyon Bi 					 (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
8546f920c07SWyon Bi 	} else {
8556f920c07SWyon Bi 		analogix_dp_disable_scrambling(dp);
8566f920c07SWyon Bi 
8572fcb4783SDamon Ding 		ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
8586f920c07SWyon Bi 					&data);
8592fcb4783SDamon Ding 		if (ret != 1)
8602fcb4783SDamon Ding 			return ret;
8612fcb4783SDamon Ding 		ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
8626f920c07SWyon Bi 					 (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
8636f920c07SWyon Bi 	}
8642fcb4783SDamon Ding 	return ret < 0 ? ret : 0;
8656f920c07SWyon Bi }
8666f920c07SWyon Bi 
analogix_dp_init_dp(struct analogix_dp_device * dp)8676f920c07SWyon Bi static void analogix_dp_init_dp(struct analogix_dp_device *dp)
8686f920c07SWyon Bi {
8696f920c07SWyon Bi 	analogix_dp_reset(dp);
8706f920c07SWyon Bi 
8716f920c07SWyon Bi 	analogix_dp_swreset(dp);
8726f920c07SWyon Bi 
8736f920c07SWyon Bi 	analogix_dp_init_analog_param(dp);
8746f920c07SWyon Bi 	analogix_dp_init_interrupt(dp);
8756f920c07SWyon Bi 
8766f920c07SWyon Bi 	/* SW defined function Normal operation */
8776f920c07SWyon Bi 	analogix_dp_enable_sw_function(dp);
8786f920c07SWyon Bi 
8796f920c07SWyon Bi 	analogix_dp_config_interrupt(dp);
8806f920c07SWyon Bi 	analogix_dp_init_analog_func(dp);
8816f920c07SWyon Bi 
8826f920c07SWyon Bi 	analogix_dp_init_hpd(dp);
8836f920c07SWyon Bi 	analogix_dp_init_aux(dp);
8846f920c07SWyon Bi }
8856f920c07SWyon Bi 
analogix_dp_connector_init(struct rockchip_connector * conn,struct display_state * state)8860594ce39SZhang Yubing static int analogix_dp_connector_init(struct rockchip_connector *conn, struct display_state *state)
88758c17f51SSandy Huang {
88858c17f51SSandy Huang 	struct connector_state *conn_state = &state->conn_state;
8890594ce39SZhang Yubing 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
8906c0d4eb6SDamon Ding 	int submode = PHY_SUBMODE_EDP;
8916c0d4eb6SDamon Ding 
8926c0d4eb6SDamon Ding 	if (!conn->panel)
8936c0d4eb6SDamon Ding 		dp->dp_mode = true;
8946f920c07SWyon Bi 
895e29a4df2SDamon Ding 	if (dev_read_bool(conn->dev, "dp-mode"))
896e29a4df2SDamon Ding 		dp->dp_mode = true;
89794834379SDamon Ding 	else if (dev_read_bool(conn->dev, "edp-mode"))
89894834379SDamon Ding 		dp->dp_mode = false;
899e29a4df2SDamon Ding 
9007adc0066SWyon Bi 	conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_eDP1 : VOP_OUTPUT_IF_eDP0;
9016f920c07SWyon Bi 	conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
902df0a5c43SDamon Ding 	conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
903df0a5c43SDamon Ding 	conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
9046f920c07SWyon Bi 
905699c29a5SWyon Bi 	reset_assert_bulk(&dp->resets);
906dddde95bSWyon Bi 	udelay(1);
907699c29a5SWyon Bi 	reset_deassert_bulk(&dp->resets);
908dddde95bSWyon Bi 
909cb17ca6cSSandy Huang 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, dp->id);
9106c0d4eb6SDamon Ding 	if (dp->plat_data.support_dp_mode && dp->dp_mode)
9116c0d4eb6SDamon Ding 		submode = PHY_SUBMODE_DP;
9126c0d4eb6SDamon Ding 	generic_phy_set_mode_ext(&dp->phy, PHY_MODE_DP, submode);
913699c29a5SWyon Bi 	generic_phy_power_on(&dp->phy);
9146f920c07SWyon Bi 	analogix_dp_init_dp(dp);
9156f920c07SWyon Bi 
9166f920c07SWyon Bi 	return 0;
9176f920c07SWyon Bi }
9186f920c07SWyon Bi 
analogix_dp_connector_get_edid(struct rockchip_connector * conn,struct display_state * state)9190594ce39SZhang Yubing static int analogix_dp_connector_get_edid(struct rockchip_connector *conn,
9200594ce39SZhang Yubing 					  struct display_state *state)
9216f920c07SWyon Bi {
9226f920c07SWyon Bi 	struct connector_state *conn_state = &state->conn_state;
9230594ce39SZhang Yubing 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
9249c170041SAlgea Cao 	int ret = 0;
9256f920c07SWyon Bi 
9269c170041SAlgea Cao 	conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
9279c170041SAlgea Cao 	if (!conn_state->edid)
9289c170041SAlgea Cao 		ret = -EINVAL;
929eb6d4c72SDamon Ding 
9306f920c07SWyon Bi 	return ret;
9316f920c07SWyon Bi }
9326f920c07SWyon Bi 
analogix_dp_link_power_up(struct analogix_dp_device * dp)933d3e70420SWyon Bi static int analogix_dp_link_power_up(struct analogix_dp_device *dp)
934d3e70420SWyon Bi {
935d3e70420SWyon Bi 	u8 value;
936d3e70420SWyon Bi 	int ret;
937d3e70420SWyon Bi 
938d3e70420SWyon Bi 	if (dp->dpcd[DP_DPCD_REV] < 0x11)
939d3e70420SWyon Bi 		return 0;
940d3e70420SWyon Bi 
9412fcb4783SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
942d3e70420SWyon Bi 	if (ret < 0)
943d3e70420SWyon Bi 		return ret;
944d3e70420SWyon Bi 
945d3e70420SWyon Bi 	value &= ~DP_SET_POWER_MASK;
946d3e70420SWyon Bi 	value |= DP_SET_POWER_D0;
947d3e70420SWyon Bi 
9482fcb4783SDamon Ding 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
949d3e70420SWyon Bi 	if (ret < 0)
950d3e70420SWyon Bi 		return ret;
951d3e70420SWyon Bi 
952d3e70420SWyon Bi 	mdelay(1);
953d3e70420SWyon Bi 
954d3e70420SWyon Bi 	return 0;
955d3e70420SWyon Bi }
956d3e70420SWyon Bi 
analogix_dp_link_power_down(struct analogix_dp_device * dp)957d3e70420SWyon Bi static int analogix_dp_link_power_down(struct analogix_dp_device *dp)
958d3e70420SWyon Bi {
959d3e70420SWyon Bi 	u8 value;
960d3e70420SWyon Bi 	int ret;
961d3e70420SWyon Bi 
962d3e70420SWyon Bi 	if (dp->dpcd[DP_DPCD_REV] < 0x11)
963d3e70420SWyon Bi 		return 0;
964d3e70420SWyon Bi 
9652fcb4783SDamon Ding 	ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
966d3e70420SWyon Bi 	if (ret < 0)
967d3e70420SWyon Bi 		return ret;
968d3e70420SWyon Bi 
969d3e70420SWyon Bi 	value &= ~DP_SET_POWER_MASK;
970d3e70420SWyon Bi 	value |= DP_SET_POWER_D3;
971d3e70420SWyon Bi 
9722fcb4783SDamon Ding 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
973d3e70420SWyon Bi 	if (ret < 0)
974d3e70420SWyon Bi 		return ret;
975d3e70420SWyon Bi 
976d3e70420SWyon Bi 	return 0;
977d3e70420SWyon Bi }
978d3e70420SWyon Bi 
analogix_dp_get_output_format(struct analogix_dp_device * dp,u32 bus_format)979d67c1260SDamon Ding static u32 analogix_dp_get_output_format(struct analogix_dp_device *dp, u32 bus_format)
980d67c1260SDamon Ding {
981d67c1260SDamon Ding 	unsigned int i;
982d67c1260SDamon Ding 
983d67c1260SDamon Ding 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
984d67c1260SDamon Ding 		const struct analogix_dp_output_format *fmt = &possible_output_fmts[i];
985d67c1260SDamon Ding 
986d67c1260SDamon Ding 		if (fmt->bus_format == bus_format)
987d67c1260SDamon Ding 			break;
988d67c1260SDamon Ding 	}
989d67c1260SDamon Ding 
990d67c1260SDamon Ding 	if (i == ARRAY_SIZE(possible_output_fmts))
991d67c1260SDamon Ding 		return 1;
992d67c1260SDamon Ding 
993d67c1260SDamon Ding 	return i;
994d67c1260SDamon Ding }
995d67c1260SDamon Ding 
analogix_dp_get_output_format_by_edid(struct analogix_dp_device * dp,struct hdmi_edid_data * edid_data)996d67c1260SDamon Ding static u32 analogix_dp_get_output_format_by_edid(struct analogix_dp_device *dp,
997d67c1260SDamon Ding 						 struct hdmi_edid_data *edid_data)
998d67c1260SDamon Ding {
999d67c1260SDamon Ding 	unsigned int i;
1000d67c1260SDamon Ding 
1001d67c1260SDamon Ding 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
1002d67c1260SDamon Ding 		const struct analogix_dp_output_format *fmt = &possible_output_fmts[i];
1003d67c1260SDamon Ding 
1004d67c1260SDamon Ding 		if (fmt->bpc > edid_data->display_info.bpc || fmt->bpc > dp->plat_data.max_bpc)
1005d67c1260SDamon Ding 			continue;
1006d67c1260SDamon Ding 
1007d67c1260SDamon Ding 		if (!(edid_data->display_info.color_formats & fmt->color_format))
1008d67c1260SDamon Ding 			continue;
1009d67c1260SDamon Ding 
1010d67c1260SDamon Ding 		if (!analogix_dp_bandwidth_ok(dp, edid_data->preferred_mode,
1011d67c1260SDamon Ding 					      analogix_dp_get_output_bpp(fmt),
1012d67c1260SDamon Ding 					      drm_dp_bw_code_to_link_rate(dp->link_train.link_rate),
1013d67c1260SDamon Ding 					      dp->link_train.lane_count))
1014d67c1260SDamon Ding 			continue;
1015d67c1260SDamon Ding 
1016d67c1260SDamon Ding 		break;
1017d67c1260SDamon Ding 	}
1018d67c1260SDamon Ding 
1019d67c1260SDamon Ding 	if (i == ARRAY_SIZE(possible_output_fmts))
1020d67c1260SDamon Ding 		return 1;
1021d67c1260SDamon Ding 
1022d67c1260SDamon Ding 	return i;
1023d67c1260SDamon Ding }
1024d67c1260SDamon Ding 
analogix_dp_connector_enable(struct rockchip_connector * conn,struct display_state * state)10250594ce39SZhang Yubing static int analogix_dp_connector_enable(struct rockchip_connector *conn,
10260594ce39SZhang Yubing 					struct display_state *state)
10276f920c07SWyon Bi {
10286f920c07SWyon Bi 	struct connector_state *conn_state = &state->conn_state;
10296f920c07SWyon Bi 	struct crtc_state *crtc_state = &state->crtc_state;
10300594ce39SZhang Yubing 	const struct rockchip_dp_chip_data *pdata =
10310594ce39SZhang Yubing 		(const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev);
10320594ce39SZhang Yubing 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
10332a74799bSJianqun Xu 	struct video_info *video = &dp->video_info;
10346e378f44SDamon Ding 	struct drm_display_mode mode;
1035d67c1260SDamon Ding 	u32 fmt_id;
10366f920c07SWyon Bi 	u32 val;
10376f920c07SWyon Bi 	int ret;
10386f920c07SWyon Bi 
10397477c1efSDamon Ding 	drm_mode_copy(&video->mode, &conn_state->mode);
10407477c1efSDamon Ding 
1041699c29a5SWyon Bi 	if (pdata->lcdsel_grf_reg) {
10426f920c07SWyon Bi 		if (crtc_state->crtc_id)
10436f920c07SWyon Bi 			val = pdata->lcdsel_lit;
10446f920c07SWyon Bi 		else
10456f920c07SWyon Bi 			val = pdata->lcdsel_big;
10466f920c07SWyon Bi 
10477adc0066SWyon Bi 		regmap_write(dp->grf, pdata->lcdsel_grf_reg, val);
10486f920c07SWyon Bi 	}
10496f920c07SWyon Bi 
10507adc0066SWyon Bi 	if (pdata->chip_type == RK3588_EDP)
10517adc0066SWyon Bi 		regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0,
10527adc0066SWyon Bi 			     EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 1));
10537adc0066SWyon Bi 
1054d67c1260SDamon Ding 	if (!dp->output_fmt) {
1055d67c1260SDamon Ding 		fmt_id = analogix_dp_get_output_format(dp, conn_state->bus_format);
1056d67c1260SDamon Ding 		dp->output_fmt = &possible_output_fmts[fmt_id];
1057d67c1260SDamon Ding 	}
1058d67c1260SDamon Ding 
1059d67c1260SDamon Ding 	switch (dp->output_fmt->bpc) {
10602a74799bSJianqun Xu 	case 12:
10612a74799bSJianqun Xu 		video->color_depth = COLOR_12;
10622a74799bSJianqun Xu 		break;
10632a74799bSJianqun Xu 	case 10:
10642a74799bSJianqun Xu 		video->color_depth = COLOR_10;
10652a74799bSJianqun Xu 		break;
10662a74799bSJianqun Xu 	case 6:
10672a74799bSJianqun Xu 		video->color_depth = COLOR_6;
10682a74799bSJianqun Xu 		break;
10692a74799bSJianqun Xu 	case 8:
10702a74799bSJianqun Xu 	default:
10712a74799bSJianqun Xu 		video->color_depth = COLOR_8;
10722a74799bSJianqun Xu 		break;
10732a74799bSJianqun Xu 	}
1074d67c1260SDamon Ding 	if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCRCB444) {
1075d67c1260SDamon Ding 		video->color_space = COLOR_YCBCR444;
1076d67c1260SDamon Ding 		video->ycbcr_coeff = COLOR_YCBCR709;
1077d67c1260SDamon Ding 	} else if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_YCRCB422) {
1078d67c1260SDamon Ding 		video->color_space = COLOR_YCBCR422;
1079d67c1260SDamon Ding 		video->ycbcr_coeff = COLOR_YCBCR709;
1080d67c1260SDamon Ding 	} else {
1081d67c1260SDamon Ding 		video->color_space = COLOR_RGB;
1082d67c1260SDamon Ding 		video->ycbcr_coeff = COLOR_YCBCR601;
1083d67c1260SDamon Ding 	}
10842a74799bSJianqun Xu 
10852fcb4783SDamon Ding 	ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, DP_RECEIVER_CAP_SIZE);
10862fcb4783SDamon Ding 	if (ret < 0) {
10871a00cf6eSWyon Bi 		dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret);
10881a00cf6eSWyon Bi 		return ret;
10891a00cf6eSWyon Bi 	}
10901a00cf6eSWyon Bi 
1091d3e70420SWyon Bi 	ret = analogix_dp_link_power_up(dp);
1092d3e70420SWyon Bi 	if (ret) {
1093d3e70420SWyon Bi 		dev_err(dp->dev, "failed to power up link: %d\n", ret);
1094d3e70420SWyon Bi 		return ret;
1095d3e70420SWyon Bi 	}
1096d3e70420SWyon Bi 
10976f920c07SWyon Bi 	ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count,
10986f920c07SWyon Bi 					 dp->video_info.max_link_rate);
10996f920c07SWyon Bi 	if (ret) {
11006f920c07SWyon Bi 		dev_err(dp->dev, "unable to do link train\n");
11016f920c07SWyon Bi 		return ret;
11026f920c07SWyon Bi 	}
11036f920c07SWyon Bi 
11042fcb4783SDamon Ding 	ret = analogix_dp_enable_scramble(dp, 1);
11052fcb4783SDamon Ding 	if (ret < 0) {
11062fcb4783SDamon Ding 		dev_err(dp->dev, "can not enable scramble\n");
11072fcb4783SDamon Ding 		return ret;
11082fcb4783SDamon Ding 	}
11092fcb4783SDamon Ding 
11106f920c07SWyon Bi 	analogix_dp_init_video(dp);
11116e378f44SDamon Ding 
11126e378f44SDamon Ding 	drm_mode_copy(&mode, &conn_state->mode);
11136e378f44SDamon Ding 	if (conn->dual_channel_mode)
11146e378f44SDamon Ding 		drm_mode_convert_to_origin_mode(&mode);
11156e378f44SDamon Ding 	analogix_dp_set_video_format(dp, &mode);
11160b8cf90dSWyon Bi 
11170b8cf90dSWyon Bi 	if (dp->video_bist_enable)
11180b8cf90dSWyon Bi 		analogix_dp_video_bist_enable(dp);
11190b8cf90dSWyon Bi 
11206f920c07SWyon Bi 	ret = analogix_dp_config_video(dp);
11216f920c07SWyon Bi 	if (ret) {
11226f920c07SWyon Bi 		dev_err(dp->dev, "unable to config video\n");
11236f920c07SWyon Bi 		return ret;
11246f920c07SWyon Bi 	}
11256f920c07SWyon Bi 
11266f920c07SWyon Bi 	return 0;
11276f920c07SWyon Bi }
11286f920c07SWyon Bi 
analogix_dp_connector_disable(struct rockchip_connector * conn,struct display_state * state)11290594ce39SZhang Yubing static int analogix_dp_connector_disable(struct rockchip_connector *conn,
11300594ce39SZhang Yubing 					 struct display_state *state)
11316f920c07SWyon Bi {
11320594ce39SZhang Yubing 	const struct rockchip_dp_chip_data *pdata =
11330594ce39SZhang Yubing 		(const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev);
11340594ce39SZhang Yubing 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
11357adc0066SWyon Bi 
1136d3e70420SWyon Bi 	if (!analogix_dp_get_plug_in_status(dp))
1137d3e70420SWyon Bi 		analogix_dp_link_power_down(dp);
1138d3e70420SWyon Bi 
11397adc0066SWyon Bi 	if (pdata->chip_type == RK3588_EDP)
11407adc0066SWyon Bi 		regmap_write(dp->grf, dp->id ? RK3588_GRF_VO1_CON1 : RK3588_GRF_VO1_CON0,
11417adc0066SWyon Bi 			     EDP_MODE << 16 | FIELD_PREP(EDP_MODE, 0));
11426f920c07SWyon Bi 
11436f920c07SWyon Bi 	return 0;
11446f920c07SWyon Bi }
11456f920c07SWyon Bi 
analogix_dp_connector_detect(struct rockchip_connector * conn,struct display_state * state)11460594ce39SZhang Yubing static int analogix_dp_connector_detect(struct rockchip_connector *conn,
11470594ce39SZhang Yubing 					struct display_state *state)
1148d90a0d9fSWyon Bi {
11490594ce39SZhang Yubing 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
1150d67c1260SDamon Ding 	int ret;
1151d90a0d9fSWyon Bi 
1152d67c1260SDamon Ding 	if (analogix_dp_detect(dp)) {
1153d67c1260SDamon Ding 		/* Initialize by reading RX's DPCD */
1154d67c1260SDamon Ding 		ret = analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
1155d67c1260SDamon Ding 		if (ret) {
1156d67c1260SDamon Ding 			dev_err(dp->dev, "failed to read max link rate\n");
1157d67c1260SDamon Ding 			return 0;
1158d67c1260SDamon Ding 		}
1159d67c1260SDamon Ding 
1160d67c1260SDamon Ding 		ret = analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
1161d67c1260SDamon Ding 		if (ret) {
1162d67c1260SDamon Ding 			dev_err(dp->dev, "failed to read max lane count\n");
1163d67c1260SDamon Ding 			return 0;
1164d67c1260SDamon Ding 		}
1165d67c1260SDamon Ding 
1166d67c1260SDamon Ding 		return 1;
1167d67c1260SDamon Ding 	} else {
1168d67c1260SDamon Ding 		return 0;
1169d67c1260SDamon Ding 	}
1170d90a0d9fSWyon Bi }
1171d90a0d9fSWyon Bi 
analogix_dp_connector_mode_valid(struct rockchip_connector * conn,struct display_state * state)1172f38653b8SDamon Ding static int analogix_dp_connector_mode_valid(struct rockchip_connector *conn,
1173f38653b8SDamon Ding 					    struct display_state *state)
1174f38653b8SDamon Ding {
1175f38653b8SDamon Ding 	struct connector_state *conn_state = &state->conn_state;
1176f38653b8SDamon Ding 	struct videomode vm;
1177f38653b8SDamon Ding 
1178f38653b8SDamon Ding 	drm_display_mode_to_videomode(&conn_state->mode, &vm);
1179f38653b8SDamon Ding 
1180f38653b8SDamon Ding 	if (!vm.hfront_porch || !vm.hback_porch || !vm.vfront_porch || !vm.vback_porch) {
1181f38653b8SDamon Ding 		dev_err(dp->dev, "front porch or back porch can not be 0\n");
1182f38653b8SDamon Ding 		return MODE_BAD;
1183f38653b8SDamon Ding 	}
1184f38653b8SDamon Ding 
1185f38653b8SDamon Ding 	return MODE_OK;
1186f38653b8SDamon Ding }
1187f38653b8SDamon Ding 
analogix_dp_mode_valid(struct analogix_dp_device * dp,struct hdmi_edid_data * edid_data)1188d67c1260SDamon Ding static int analogix_dp_mode_valid(struct analogix_dp_device *dp, struct hdmi_edid_data *edid_data)
1189d67c1260SDamon Ding {
1190d67c1260SDamon Ding 	struct drm_display_info *di = &edid_data->display_info;
1191d67c1260SDamon Ding 	u32 max_link_rate, max_lane_count;
1192d67c1260SDamon Ding 	u32 min_bpp;
1193d67c1260SDamon Ding 	int i;
1194d67c1260SDamon Ding 
1195d67c1260SDamon Ding 	if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1196d67c1260SDamon Ding 		min_bpp = 16;
1197d67c1260SDamon Ding 	else if (di->color_formats & DRM_COLOR_FORMAT_RGB444)
1198d67c1260SDamon Ding 		min_bpp = 18;
1199d67c1260SDamon Ding 	else
1200d67c1260SDamon Ding 		min_bpp = 24;
1201d67c1260SDamon Ding 
1202d67c1260SDamon Ding 	max_link_rate = min_t(u32, dp->video_info.max_link_rate, dp->link_train.link_rate);
1203d67c1260SDamon Ding 	max_lane_count = min_t(u32, dp->video_info.max_lane_count, dp->link_train.lane_count);
1204d67c1260SDamon Ding 	for (i = 0; i < edid_data->modes; i++) {
1205d67c1260SDamon Ding 		if (!analogix_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp,
1206d67c1260SDamon Ding 					      drm_dp_bw_code_to_link_rate(max_link_rate),
1207d67c1260SDamon Ding 					      max_lane_count))
1208d67c1260SDamon Ding 			edid_data->mode_buf[i].invalid = true;
1209d67c1260SDamon Ding 	}
1210d67c1260SDamon Ding 
1211d67c1260SDamon Ding 	return 0;
1212d67c1260SDamon Ding }
1213d67c1260SDamon Ding 
analogix_dp_connector_get_timing(struct rockchip_connector * conn,struct display_state * state)1214d67c1260SDamon Ding static int analogix_dp_connector_get_timing(struct rockchip_connector *conn,
1215d67c1260SDamon Ding 					    struct display_state *state)
1216d67c1260SDamon Ding {
1217d67c1260SDamon Ding 	struct connector_state *conn_state = &state->conn_state;
1218d67c1260SDamon Ding 	const struct rockchip_dp_chip_data *pdata =
1219d67c1260SDamon Ding 		(const struct rockchip_dp_chip_data *)dev_get_driver_data(conn->dev);
1220d67c1260SDamon Ding 	struct analogix_dp_device *dp = dev_get_priv(conn->dev);
1221d67c1260SDamon Ding 	struct drm_display_mode *mode = &conn_state->mode;
1222d67c1260SDamon Ding 	struct hdmi_edid_data edid_data;
1223d67c1260SDamon Ding 	struct drm_display_mode *mode_buf;
1224d67c1260SDamon Ding 	struct vop_rect rect;
1225d67c1260SDamon Ding 	u32 yuv_fmts_mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422;
1226d67c1260SDamon Ding 	u32 fmt_id;
12279c170041SAlgea Cao 	int ret = 0, i;
1228d67c1260SDamon Ding 
1229d67c1260SDamon Ding 	mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
1230d67c1260SDamon Ding 	if (!mode_buf)
1231d67c1260SDamon Ding 		return -ENOMEM;
1232d67c1260SDamon Ding 
1233d67c1260SDamon Ding 	memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
1234d67c1260SDamon Ding 	memset(&edid_data, 0, sizeof(struct hdmi_edid_data));
1235d67c1260SDamon Ding 	edid_data.mode_buf = mode_buf;
1236d67c1260SDamon Ding 
12379c170041SAlgea Cao 	conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
12389c170041SAlgea Cao 	if (conn_state->edid)
1239d67c1260SDamon Ding 		ret = drm_add_edid_modes(&edid_data, conn_state->edid);
1240d67c1260SDamon Ding 
12419c170041SAlgea Cao 	if (ret <= 0) {
1242d67c1260SDamon Ding 		printf("failed to get edid\n");
1243d67c1260SDamon Ding 		goto err;
1244d67c1260SDamon Ding 	}
1245d67c1260SDamon Ding 
1246d67c1260SDamon Ding 	if (!pdata->format_yuv) {
1247d67c1260SDamon Ding 		if (edid_data.display_info.color_formats & yuv_fmts_mask) {
1248d67c1260SDamon Ding 			printf("Swapping display color format from YUV to RGB\n");
1249d67c1260SDamon Ding 			edid_data.display_info.color_formats &= ~yuv_fmts_mask;
1250d67c1260SDamon Ding 			edid_data.display_info.color_formats |= DRM_COLOR_FORMAT_RGB444;
1251d67c1260SDamon Ding 		}
1252d67c1260SDamon Ding 	}
1253d67c1260SDamon Ding 
1254d67c1260SDamon Ding 	if (state->conn_state.secondary) {
1255d67c1260SDamon Ding 		rect.width = state->crtc_state.max_output.width / 2;
1256d67c1260SDamon Ding 		rect.height = state->crtc_state.max_output.height / 2;
1257d67c1260SDamon Ding 	} else {
1258d67c1260SDamon Ding 		rect.width = state->crtc_state.max_output.width;
1259d67c1260SDamon Ding 		rect.height = state->crtc_state.max_output.height;
1260d67c1260SDamon Ding 	}
1261d67c1260SDamon Ding 
1262d67c1260SDamon Ding 	drm_mode_max_resolution_filter(&edid_data, &rect);
1263d67c1260SDamon Ding 	analogix_dp_mode_valid(dp, &edid_data);
1264d67c1260SDamon Ding 
1265d67c1260SDamon Ding 	if (!drm_mode_prune_invalid(&edid_data)) {
1266d67c1260SDamon Ding 		printf("can't find valid dp mode\n");
1267d67c1260SDamon Ding 		ret = -EINVAL;
1268d67c1260SDamon Ding 		goto err;
1269d67c1260SDamon Ding 	}
1270d67c1260SDamon Ding 
1271d67c1260SDamon Ding 	for (i = 0; i < edid_data.modes; i++)
1272d67c1260SDamon Ding 		edid_data.mode_buf[i].vrefresh = drm_mode_vrefresh(&edid_data.mode_buf[i]);
1273d67c1260SDamon Ding 
1274d67c1260SDamon Ding 	drm_mode_sort(&edid_data);
1275d67c1260SDamon Ding 	memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode));
1276d67c1260SDamon Ding 
1277d67c1260SDamon Ding 	fmt_id = analogix_dp_get_output_format_by_edid(dp, &edid_data);
1278d67c1260SDamon Ding 	dp->output_fmt = &possible_output_fmts[fmt_id];
1279d67c1260SDamon Ding 
1280d67c1260SDamon Ding 	switch (dp->output_fmt->color_format) {
1281d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_YCRCB422:
1282d67c1260SDamon Ding 		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV422;
1283d67c1260SDamon Ding 		break;
1284d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_RGB444:
1285d67c1260SDamon Ding 	case DRM_COLOR_FORMAT_YCRCB444:
1286d67c1260SDamon Ding 	default:
1287d67c1260SDamon Ding 		conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1288d67c1260SDamon Ding 		break;
1289d67c1260SDamon Ding 	}
1290d67c1260SDamon Ding 
1291d67c1260SDamon Ding 	conn_state->bus_format = dp->output_fmt->bus_format;
1292d67c1260SDamon Ding 	conn_state->bpc = dp->output_fmt->bpc;
1293d67c1260SDamon Ding 	conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
1294d67c1260SDamon Ding 	if (dp->output_fmt->color_format == DRM_COLOR_FORMAT_RGB444)
1295d67c1260SDamon Ding 		conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
1296d67c1260SDamon Ding 	else
1297d67c1260SDamon Ding 		conn_state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
1298d67c1260SDamon Ding 
1299d67c1260SDamon Ding err:
1300d67c1260SDamon Ding 	free(mode_buf);
1301d67c1260SDamon Ding 
1302d67c1260SDamon Ding 	return 0;
1303d67c1260SDamon Ding }
1304d67c1260SDamon Ding 
13056f920c07SWyon Bi static const struct rockchip_connector_funcs analogix_dp_connector_funcs = {
13066f920c07SWyon Bi 	.init = analogix_dp_connector_init,
13076f920c07SWyon Bi 	.get_edid = analogix_dp_connector_get_edid,
13086f920c07SWyon Bi 	.enable = analogix_dp_connector_enable,
13096f920c07SWyon Bi 	.disable = analogix_dp_connector_disable,
1310d90a0d9fSWyon Bi 	.detect = analogix_dp_connector_detect,
1311f38653b8SDamon Ding 	.mode_valid = analogix_dp_connector_mode_valid,
1312d67c1260SDamon Ding 	.get_timing = analogix_dp_connector_get_timing,
13136f920c07SWyon Bi };
13146f920c07SWyon Bi 
analogix_dp_parse_link_frequencies(struct analogix_dp_device * dp)131535c48984SWyon Bi static u32 analogix_dp_parse_link_frequencies(struct analogix_dp_device *dp)
131635c48984SWyon Bi {
131735c48984SWyon Bi 	struct udevice *dev = dp->dev;
131835c48984SWyon Bi 	const struct device_node *endpoint;
131935c48984SWyon Bi 	u64 frequency = 0;
132035c48984SWyon Bi 
132135c48984SWyon Bi 	endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0);
132235c48984SWyon Bi 	if (!endpoint)
132335c48984SWyon Bi 		return 0;
132435c48984SWyon Bi 
132535c48984SWyon Bi 	if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0)
132635c48984SWyon Bi 		return 0;
132735c48984SWyon Bi 
132835c48984SWyon Bi 	if (!frequency)
132935c48984SWyon Bi 		return 0;
133035c48984SWyon Bi 
133135c48984SWyon Bi 	do_div(frequency, 10 * 1000);	/* symbol rate kbytes */
133235c48984SWyon Bi 
133335c48984SWyon Bi 	switch (frequency) {
133435c48984SWyon Bi 	case 162000:
133535c48984SWyon Bi 	case 270000:
133635c48984SWyon Bi 	case 540000:
133735c48984SWyon Bi 		break;
133835c48984SWyon Bi 	default:
133935c48984SWyon Bi 		dev_err(dev, "invalid link frequency value: %llu\n", frequency);
134035c48984SWyon Bi 		return 0;
134135c48984SWyon Bi 	}
134235c48984SWyon Bi 
134335c48984SWyon Bi 	return frequency;
134435c48984SWyon Bi }
134535c48984SWyon Bi 
analogix_dp_parse_dt(struct analogix_dp_device * dp)13461f59ac36SWyon Bi static int analogix_dp_parse_dt(struct analogix_dp_device *dp)
13471f59ac36SWyon Bi {
13481f59ac36SWyon Bi 	struct udevice *dev = dp->dev;
13491f59ac36SWyon Bi 	int len;
13501f59ac36SWyon Bi 	u32 num_lanes;
1351e14b9f0dSWyon Bi 	u32 max_link_rate;
13521f59ac36SWyon Bi 	int ret;
13531f59ac36SWyon Bi 
13541f59ac36SWyon Bi 	dp->force_hpd = dev_read_bool(dev, "force-hpd");
13551f59ac36SWyon Bi 	dp->video_bist_enable = dev_read_bool(dev, "analogix,video-bist-enable");
1356ae5256b5SWyon Bi 	dp->video_info.force_stream_valid =
1357ae5256b5SWyon Bi 		dev_read_bool(dev, "analogix,force-stream-valid");
13581f59ac36SWyon Bi 
135935c48984SWyon Bi 	max_link_rate = analogix_dp_parse_link_frequencies(dp);
136035c48984SWyon Bi 	if (max_link_rate && max_link_rate < drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate))
136135c48984SWyon Bi 		dp->video_info.max_link_rate = drm_dp_link_rate_to_bw_code(max_link_rate);
1362e14b9f0dSWyon Bi 
13631f59ac36SWyon Bi 	if (dev_read_prop(dev, "data-lanes", &len)) {
13641f59ac36SWyon Bi 		num_lanes = len / sizeof(u32);
13651f59ac36SWyon Bi 		if (num_lanes < 1 || num_lanes > 4 || num_lanes == 3) {
13661f59ac36SWyon Bi 			dev_err(dev, "bad number of data lanes\n");
13671f59ac36SWyon Bi 			return -EINVAL;
13681f59ac36SWyon Bi 		}
13691f59ac36SWyon Bi 
13701f59ac36SWyon Bi 		ret = dev_read_u32_array(dev, "data-lanes", dp->lane_map,
13711f59ac36SWyon Bi 					 num_lanes);
13721f59ac36SWyon Bi 		if (ret)
13731f59ac36SWyon Bi 			return ret;
13741f59ac36SWyon Bi 
13751f59ac36SWyon Bi 		dp->video_info.max_lane_count = num_lanes;
13761f59ac36SWyon Bi 	} else {
13771f59ac36SWyon Bi 		dp->lane_map[0] = 0;
13781f59ac36SWyon Bi 		dp->lane_map[1] = 1;
13791f59ac36SWyon Bi 		dp->lane_map[2] = 2;
13801f59ac36SWyon Bi 		dp->lane_map[3] = 3;
13811f59ac36SWyon Bi 	}
13821f59ac36SWyon Bi 
13831f59ac36SWyon Bi 	return 0;
13841f59ac36SWyon Bi }
13851f59ac36SWyon Bi 
analogix_dp_ddc_init(struct analogix_dp_device * dp)138658df3976SDamon Ding static int analogix_dp_ddc_init(struct analogix_dp_device *dp)
138758df3976SDamon Ding {
138858df3976SDamon Ding 	dp->aux.name = "analogix-dp";
138958df3976SDamon Ding 	dp->aux.dev = dp->dev;
139058df3976SDamon Ding 	dp->aux.transfer = analogix_dp_aux_transfer;
139158df3976SDamon Ding 	dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer;
139258df3976SDamon Ding 
139358df3976SDamon Ding 	return 0;
139458df3976SDamon Ding }
139558df3976SDamon Ding 
analogix_dp_probe(struct udevice * dev)13966f920c07SWyon Bi static int analogix_dp_probe(struct udevice *dev)
13976f920c07SWyon Bi {
13986f920c07SWyon Bi 	struct analogix_dp_device *dp = dev_get_priv(dev);
13990594ce39SZhang Yubing 	const struct rockchip_dp_chip_data *pdata =
14000594ce39SZhang Yubing 		(const struct rockchip_dp_chip_data *)dev_get_driver_data(dev);
14017adc0066SWyon Bi 	struct udevice *syscon;
14026f920c07SWyon Bi 	int ret;
14036f920c07SWyon Bi 
14046f920c07SWyon Bi 	dp->reg_base = dev_read_addr_ptr(dev);
14056f920c07SWyon Bi 
1406cb17ca6cSSandy Huang 	dp->id = of_alias_get_id(ofnode_to_np(dev->node), "edp");
1407cb17ca6cSSandy Huang 	if (dp->id < 0)
1408cb17ca6cSSandy Huang 		dp->id = 0;
14097adc0066SWyon Bi 
14107adc0066SWyon Bi 	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf",
14117adc0066SWyon Bi 					   &syscon);
14127adc0066SWyon Bi 	if (!ret) {
14137adc0066SWyon Bi 		dp->grf = syscon_get_regmap(syscon);
14147adc0066SWyon Bi 		if (!dp->grf)
14157adc0066SWyon Bi 			return -ENODEV;
14167adc0066SWyon Bi 	}
14177adc0066SWyon Bi 
1418*51fee72cSFinley Xiao #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
1419*51fee72cSFinley Xiao 	ret = power_domain_get(dev, &dp->pwrdom);
1420*51fee72cSFinley Xiao 	if (ret) {
1421*51fee72cSFinley Xiao 		dev_err(dev, "failed to get pwrdom: %d\n", ret);
1422*51fee72cSFinley Xiao 		return ret;
1423*51fee72cSFinley Xiao 	}
1424*51fee72cSFinley Xiao 	ret = power_domain_on(&dp->pwrdom);
1425*51fee72cSFinley Xiao 	if (ret) {
1426*51fee72cSFinley Xiao 		dev_err(dev, "failed to power on pd: %d\n", ret);
1427*51fee72cSFinley Xiao 		return ret;
1428*51fee72cSFinley Xiao 	}
1429*51fee72cSFinley Xiao 	ret = clk_get_bulk(dev, &dp->clks);
1430*51fee72cSFinley Xiao 	if (ret) {
1431*51fee72cSFinley Xiao 		dev_err(dev, "failed to get clk: %d\n", ret);
1432*51fee72cSFinley Xiao 		return ret;
1433*51fee72cSFinley Xiao 	}
1434*51fee72cSFinley Xiao 	ret = clk_enable_bulk(&dp->clks);
1435*51fee72cSFinley Xiao 	if (ret) {
1436*51fee72cSFinley Xiao 		dev_err(dev, "failed to enable clk: %d\n", ret);
1437*51fee72cSFinley Xiao 		return ret;
1438*51fee72cSFinley Xiao 	}
1439*51fee72cSFinley Xiao #endif
1440*51fee72cSFinley Xiao 
1441699c29a5SWyon Bi 	ret = reset_get_bulk(dev, &dp->resets);
1442dddde95bSWyon Bi 	if (ret) {
1443dddde95bSWyon Bi 		dev_err(dev, "failed to get reset control: %d\n", ret);
1444dddde95bSWyon Bi 		return ret;
1445dddde95bSWyon Bi 	}
1446dddde95bSWyon Bi 
14476f920c07SWyon Bi 	ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio,
14486f920c07SWyon Bi 				   GPIOD_IS_IN);
14496f920c07SWyon Bi 	if (ret && ret != -ENOENT) {
14506f920c07SWyon Bi 		dev_err(dev, "failed to get hpd GPIO: %d\n", ret);
14516f920c07SWyon Bi 		return ret;
14526f920c07SWyon Bi 	}
14536f920c07SWyon Bi 
1454699c29a5SWyon Bi 	generic_phy_get_by_name(dev, "dp", &dp->phy);
1455699c29a5SWyon Bi 
14566f920c07SWyon Bi 	dp->plat_data.dev_type = ROCKCHIP_DP;
14576f920c07SWyon Bi 	dp->plat_data.subdev_type = pdata->chip_type;
1458699c29a5SWyon Bi 	dp->plat_data.ssc = pdata->ssc;
14596c0d4eb6SDamon Ding 	dp->plat_data.support_dp_mode = pdata->support_dp_mode;
1460d67c1260SDamon Ding 	dp->plat_data.max_bpc = pdata->max_bpc ? pdata->max_bpc : 8;
14617adc0066SWyon Bi 
14627adc0066SWyon Bi 	dp->video_info.max_link_rate = pdata->max_link_rate;
14637adc0066SWyon Bi 	dp->video_info.max_lane_count = pdata->max_lane_count;
14646f920c07SWyon Bi 
14656f920c07SWyon Bi 	dp->dev = dev;
14666f920c07SWyon Bi 
14671f59ac36SWyon Bi 	ret = analogix_dp_parse_dt(dp);
14681f59ac36SWyon Bi 	if (ret) {
14691f59ac36SWyon Bi 		dev_err(dev, "failed to parse DT: %d\n", ret);
14701f59ac36SWyon Bi 		return ret;
14711f59ac36SWyon Bi 	}
14721f59ac36SWyon Bi 
147358df3976SDamon Ding 	analogix_dp_ddc_init(dp);
147458df3976SDamon Ding 
14750594ce39SZhang Yubing 	rockchip_connector_bind(&dp->connector, dev, dp->id, &analogix_dp_connector_funcs,
14760594ce39SZhang Yubing 				NULL, DRM_MODE_CONNECTOR_eDP);
14770594ce39SZhang Yubing 
14786f920c07SWyon Bi 	return 0;
14796f920c07SWyon Bi }
14806f920c07SWyon Bi 
14816f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3288_edp_platform_data = {
14826f920c07SWyon Bi 	.lcdsel_grf_reg = 0x025c,
14836f920c07SWyon Bi 	.lcdsel_big = 0 | BIT(21),
14846f920c07SWyon Bi 	.lcdsel_lit = BIT(5) | BIT(21),
14856f920c07SWyon Bi 	.chip_type = RK3288_DP,
14867adc0066SWyon Bi 
14877adc0066SWyon Bi 	.max_link_rate = DP_LINK_BW_2_7,
14887adc0066SWyon Bi 	.max_lane_count = 4,
14896f920c07SWyon Bi };
14906f920c07SWyon Bi 
14916f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3368_edp_platform_data = {
14926f920c07SWyon Bi 	.chip_type = RK3368_EDP,
14937adc0066SWyon Bi 
14947adc0066SWyon Bi 	.max_link_rate = DP_LINK_BW_2_7,
14957adc0066SWyon Bi 	.max_lane_count = 4,
14966f920c07SWyon Bi };
14976f920c07SWyon Bi 
14986f920c07SWyon Bi static const struct rockchip_dp_chip_data rk3399_edp_platform_data = {
14996f920c07SWyon Bi 	.lcdsel_grf_reg = 0x6250,
15006f920c07SWyon Bi 	.lcdsel_big = 0 | BIT(21),
15016f920c07SWyon Bi 	.lcdsel_lit = BIT(5) | BIT(21),
15026f920c07SWyon Bi 	.chip_type = RK3399_EDP,
1503e417664aSWyon Bi 	.ssc = true,
15047adc0066SWyon Bi 
1505e417664aSWyon Bi 	.max_link_rate = DP_LINK_BW_5_4,
15067adc0066SWyon Bi 	.max_lane_count = 4,
15076f920c07SWyon Bi };
15086f920c07SWyon Bi 
1509699c29a5SWyon Bi static const struct rockchip_dp_chip_data rk3568_edp_platform_data = {
1510699c29a5SWyon Bi 	.chip_type = RK3568_EDP,
1511699c29a5SWyon Bi 	.ssc = true,
15127adc0066SWyon Bi 
15137adc0066SWyon Bi 	.max_link_rate = DP_LINK_BW_2_7,
15147adc0066SWyon Bi 	.max_lane_count = 4,
1515699c29a5SWyon Bi };
1516699c29a5SWyon Bi 
151746d49f07SDamon Ding static const struct rockchip_dp_chip_data rk3576_edp_platform_data = {
151846d49f07SDamon Ding 	.chip_type = RK3576_EDP,
151946d49f07SDamon Ding 	.ssc = true,
152046d49f07SDamon Ding 
152146d49f07SDamon Ding 	.max_link_rate = DP_LINK_BW_5_4,
152246d49f07SDamon Ding 	.max_lane_count = 4,
1523d67c1260SDamon Ding 	.format_yuv = true,
152432035f4bSDamon Ding 	.support_dp_mode = true,
1525d67c1260SDamon Ding 	.max_bpc = 10,
152646d49f07SDamon Ding };
152746d49f07SDamon Ding 
15287adc0066SWyon Bi static const struct rockchip_dp_chip_data rk3588_edp_platform_data = {
15297adc0066SWyon Bi 	.chip_type = RK3588_EDP,
15307adc0066SWyon Bi 	.ssc = true,
15317adc0066SWyon Bi 
15327adc0066SWyon Bi 	.max_link_rate = DP_LINK_BW_5_4,
15337adc0066SWyon Bi 	.max_lane_count = 4,
1534d67c1260SDamon Ding 	.format_yuv = true,
153532035f4bSDamon Ding 	.support_dp_mode = true,
1536d67c1260SDamon Ding 	.max_bpc = 10,
15377adc0066SWyon Bi };
15387adc0066SWyon Bi 
15396f920c07SWyon Bi static const struct udevice_id analogix_dp_ids[] = {
15406f920c07SWyon Bi 	{
15416f920c07SWyon Bi 		.compatible = "rockchip,rk3288-dp",
15420594ce39SZhang Yubing 		.data = (ulong)&rk3288_edp_platform_data,
15436f920c07SWyon Bi 	}, {
15446f920c07SWyon Bi 		.compatible = "rockchip,rk3368-edp",
15450594ce39SZhang Yubing 		.data = (ulong)&rk3368_edp_platform_data,
15466f920c07SWyon Bi 	}, {
15476f920c07SWyon Bi 		.compatible = "rockchip,rk3399-edp",
15480594ce39SZhang Yubing 		.data = (ulong)&rk3399_edp_platform_data,
1549699c29a5SWyon Bi 	}, {
1550699c29a5SWyon Bi 		.compatible = "rockchip,rk3568-edp",
15510594ce39SZhang Yubing 		.data = (ulong)&rk3568_edp_platform_data,
15527adc0066SWyon Bi 	}, {
155346d49f07SDamon Ding 		.compatible = "rockchip,rk3576-edp",
155446d49f07SDamon Ding 		.data = (ulong)&rk3576_edp_platform_data,
155546d49f07SDamon Ding 	}, {
15567adc0066SWyon Bi 		.compatible = "rockchip,rk3588-edp",
15570594ce39SZhang Yubing 		.data = (ulong)&rk3588_edp_platform_data,
15586f920c07SWyon Bi 	},
15596f920c07SWyon Bi 	{}
15606f920c07SWyon Bi };
15616f920c07SWyon Bi 
15626f920c07SWyon Bi U_BOOT_DRIVER(analogix_dp) = {
15636f920c07SWyon Bi 	.name = "analogix_dp",
15646f920c07SWyon Bi 	.id = UCLASS_DISPLAY,
15656f920c07SWyon Bi 	.of_match = analogix_dp_ids,
15666f920c07SWyon Bi 	.probe = analogix_dp_probe,
15676f920c07SWyon Bi 	.priv_auto_alloc_size = sizeof(struct analogix_dp_device),
15686f920c07SWyon Bi };
1569