xref: /rk3399_rockchip-uboot/drivers/video/drm/dw-dp.c (revision fb43630c0dcb46eb77fcbd5d2add597b7db06162)
1*fb43630cSZhang Yubing // SPDX-License-Identifier: GPL-2.0-or-later
2*fb43630cSZhang Yubing /*
3*fb43630cSZhang Yubing  * Rockchip USBDP Combo PHY with Samsung IP block driver
4*fb43630cSZhang Yubing  *
5*fb43630cSZhang Yubing  * Copyright (C) 2021 Rockchip Electronics Co., Ltd
6*fb43630cSZhang Yubing  */
7*fb43630cSZhang Yubing 
8*fb43630cSZhang Yubing #include <config.h>
9*fb43630cSZhang Yubing #include <common.h>
10*fb43630cSZhang Yubing #include <errno.h>
11*fb43630cSZhang Yubing #include <malloc.h>
12*fb43630cSZhang Yubing #include <asm/unaligned.h>
13*fb43630cSZhang Yubing #include <asm/io.h>
14*fb43630cSZhang Yubing #include <clk.h>
15*fb43630cSZhang Yubing #include <dm/device.h>
16*fb43630cSZhang Yubing #include <dm/of_access.h>
17*fb43630cSZhang Yubing #include <dm/read.h>
18*fb43630cSZhang Yubing #include <generic-phy.h>
19*fb43630cSZhang Yubing #include <linux/bitfield.h>
20*fb43630cSZhang Yubing #include <linux/hdmi.h>
21*fb43630cSZhang Yubing #include <linux/media-bus-format.h>
22*fb43630cSZhang Yubing #include <linux/list.h>
23*fb43630cSZhang Yubing #include <asm/gpio.h>
24*fb43630cSZhang Yubing #include <generic-phy.h>
25*fb43630cSZhang Yubing #include <regmap.h>
26*fb43630cSZhang Yubing #include <reset.h>
27*fb43630cSZhang Yubing #include <drm/drm_dp_helper.h>
28*fb43630cSZhang Yubing 
29*fb43630cSZhang Yubing #include "rockchip_display.h"
30*fb43630cSZhang Yubing #include "rockchip_crtc.h"
31*fb43630cSZhang Yubing #include "rockchip_connector.h"
32*fb43630cSZhang Yubing 
33*fb43630cSZhang Yubing #define DPTX_VERSION_NUMBER			0x0000
34*fb43630cSZhang Yubing #define DPTX_VERSION_TYPE			0x0004
35*fb43630cSZhang Yubing #define DPTX_ID					0x0008
36*fb43630cSZhang Yubing 
37*fb43630cSZhang Yubing #define DPTX_CONFIG_REG1			0x0100
38*fb43630cSZhang Yubing #define DPTX_CONFIG_REG2			0x0104
39*fb43630cSZhang Yubing #define DPTX_CONFIG_REG3			0x0108
40*fb43630cSZhang Yubing 
41*fb43630cSZhang Yubing #define DPTX_CCTL				0x0200
42*fb43630cSZhang Yubing #define FORCE_HPD				BIT(4)
43*fb43630cSZhang Yubing #define DEFAULT_FAST_LINK_TRAIN_EN		BIT(2)
44*fb43630cSZhang Yubing #define ENHANCE_FRAMING_EN			BIT(1)
45*fb43630cSZhang Yubing #define SCRAMBLE_DIS				BIT(0)
46*fb43630cSZhang Yubing #define DPTX_SOFT_RESET_CTRL			0x0204
47*fb43630cSZhang Yubing #define VIDEO_RESET				BIT(5)
48*fb43630cSZhang Yubing #define AUX_RESET				BIT(4)
49*fb43630cSZhang Yubing #define AUDIO_SAMPLER_RESET			BIT(3)
50*fb43630cSZhang Yubing #define PHY_SOFT_RESET				BIT(1)
51*fb43630cSZhang Yubing #define CONTROLLER_RESET			BIT(0)
52*fb43630cSZhang Yubing 
53*fb43630cSZhang Yubing #define DPTX_VSAMPLE_CTRL			0x0300
54*fb43630cSZhang Yubing #define PIXEL_MODE_SELECT			GENMASK(22, 21)
55*fb43630cSZhang Yubing #define VIDEO_MAPPING				GENMASK(20, 16)
56*fb43630cSZhang Yubing #define VIDEO_STREAM_ENABLE			BIT(5)
57*fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL1		0x0304
58*fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL2		0x0308
59*fb43630cSZhang Yubing #define DPTX_VINPUT_POLARITY_CTRL		0x030c
60*fb43630cSZhang Yubing #define DE_IN_POLARITY				BIT(2)
61*fb43630cSZhang Yubing #define HSYNC_IN_POLARITY			BIT(1)
62*fb43630cSZhang Yubing #define VSYNC_IN_POLARITY			BIT(0)
63*fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG1			0x0310
64*fb43630cSZhang Yubing #define HACTIVE					GENMASK(31, 16)
65*fb43630cSZhang Yubing #define HBLANK					GENMASK(15, 2)
66*fb43630cSZhang Yubing #define I_P					BIT(1)
67*fb43630cSZhang Yubing #define R_V_BLANK_IN_OSC			BIT(0)
68*fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG2			0x0314
69*fb43630cSZhang Yubing #define VBLANK					GENMASK(31, 16)
70*fb43630cSZhang Yubing #define VACTIVE					GENMASK(15, 0)
71*fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG3			0x0318
72*fb43630cSZhang Yubing #define H_SYNC_WIDTH				GENMASK(31, 16)
73*fb43630cSZhang Yubing #define H_FRONT_PORCH				GENMASK(15, 0)
74*fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG4			0x031c
75*fb43630cSZhang Yubing #define V_SYNC_WIDTH				GENMASK(31, 16)
76*fb43630cSZhang Yubing #define V_FRONT_PORCH				GENMASK(15, 0)
77*fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG5			0x0320
78*fb43630cSZhang Yubing #define INIT_THRESHOLD_HI			GENMASK(22, 21)
79*fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU_FRAC		GENMASK(19, 16)
80*fb43630cSZhang Yubing #define INIT_THRESHOLD				GENMASK(13, 7)
81*fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU			GENMASK(6, 0)
82*fb43630cSZhang Yubing #define DPTX_VIDEO_MSA1				0x0324
83*fb43630cSZhang Yubing #define VSTART					GENMASK(31, 16)
84*fb43630cSZhang Yubing #define HSTART					GENMASK(15, 0)
85*fb43630cSZhang Yubing #define DPTX_VIDEO_MSA2				0x0328
86*fb43630cSZhang Yubing #define MISC0					GENMASK(31, 24)
87*fb43630cSZhang Yubing #define DPTX_VIDEO_MSA3				0x032c
88*fb43630cSZhang Yubing #define MISC1					GENMASK(31, 24)
89*fb43630cSZhang Yubing #define DPTX_VIDEO_HBLANK_INTERVAL		0x0330
90*fb43630cSZhang Yubing #define HBLANK_INTERVAL_EN			BIT(16)
91*fb43630cSZhang Yubing #define HBLANK_INTERVAL				GENMASK(15, 0)
92*fb43630cSZhang Yubing 
93*fb43630cSZhang Yubing #define DPTX_AUD_CONFIG1			0x0400
94*fb43630cSZhang Yubing #define AUDIO_TIMESTAMP_VERSION_NUM		GENMASK(29, 24)
95*fb43630cSZhang Yubing #define AUDIO_PACKET_ID				GENMASK(23, 16)
96*fb43630cSZhang Yubing #define AUDIO_MUTE				BIT(15)
97*fb43630cSZhang Yubing #define NUM_CHANNELS				GENMASK(14, 12)
98*fb43630cSZhang Yubing #define HBR_MODE_ENABLE				BIT(10)
99*fb43630cSZhang Yubing #define AUDIO_DATA_WIDTH			GENMASK(9, 5)
100*fb43630cSZhang Yubing #define AUDIO_DATA_IN_EN			GENMASK(4, 1)
101*fb43630cSZhang Yubing #define AUDIO_INF_SELECT			BIT(0)
102*fb43630cSZhang Yubing 
103*fb43630cSZhang Yubing #define DPTX_SDP_VERTICAL_CTRL			0x0500
104*fb43630cSZhang Yubing #define EN_VERTICAL_SDP				BIT(2)
105*fb43630cSZhang Yubing #define EN_AUDIO_STREAM_SDP			BIT(1)
106*fb43630cSZhang Yubing #define EN_AUDIO_TIMESTAMP_SDP			BIT(0)
107*fb43630cSZhang Yubing #define DPTX_SDP_HORIZONTAL_CTRL		0x0504
108*fb43630cSZhang Yubing #define EN_HORIZONTAL_SDP			BIT(2)
109*fb43630cSZhang Yubing #define DPTX_SDP_STATUS_REGISTER		0x0508
110*fb43630cSZhang Yubing #define DPTX_SDP_MANUAL_CTRL			0x050c
111*fb43630cSZhang Yubing #define DPTX_SDP_STATUS_EN			0x0510
112*fb43630cSZhang Yubing 
113*fb43630cSZhang Yubing #define DPTX_SDP_REGISTER_BANK			0x0600
114*fb43630cSZhang Yubing #define SDP_REGS				GENMASK(31, 0)
115*fb43630cSZhang Yubing 
116*fb43630cSZhang Yubing #define DPTX_PHYIF_CTRL				0x0a00
117*fb43630cSZhang Yubing #define PHY_WIDTH				BIT(25)
118*fb43630cSZhang Yubing #define PHY_POWERDOWN				GENMASK(20, 17)
119*fb43630cSZhang Yubing #define PHY_BUSY				GENMASK(15, 12)
120*fb43630cSZhang Yubing #define SSC_DIS					BIT(16)
121*fb43630cSZhang Yubing #define XMIT_ENABLE				GENMASK(11, 8)
122*fb43630cSZhang Yubing #define PHY_LANES				GENMASK(7, 6)
123*fb43630cSZhang Yubing #define PHY_RATE				GENMASK(5, 4)
124*fb43630cSZhang Yubing #define TPS_SEL					GENMASK(3, 0)
125*fb43630cSZhang Yubing #define DPTX_PHY_TX_EQ				0x0a04
126*fb43630cSZhang Yubing #define DPTX_CUSTOMPAT0				0x0a08
127*fb43630cSZhang Yubing #define DPTX_CUSTOMPAT1				0x0a0c
128*fb43630cSZhang Yubing #define DPTX_CUSTOMPAT2				0x0a10
129*fb43630cSZhang Yubing #define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET	0x0a14
130*fb43630cSZhang Yubing #define DPTX_PHYIF_PWRDOWN_CTRL			0x0a18
131*fb43630cSZhang Yubing 
132*fb43630cSZhang Yubing #define DPTX_AUX_CMD				0x0b00
133*fb43630cSZhang Yubing #define AUX_CMD_TYPE				GENMASK(31, 28)
134*fb43630cSZhang Yubing #define AUX_ADDR				GENMASK(27, 8)
135*fb43630cSZhang Yubing #define I2C_ADDR_ONLY				BIT(4)
136*fb43630cSZhang Yubing #define AUX_LEN_REQ				GENMASK(3, 0)
137*fb43630cSZhang Yubing #define DPTX_AUX_STATUS				0x0b04
138*fb43630cSZhang Yubing #define AUX_TIMEOUT				BIT(17)
139*fb43630cSZhang Yubing #define AUX_BYTES_READ				GENMASK(23, 19)
140*fb43630cSZhang Yubing #define AUX_STATUS				GENMASK(7, 4)
141*fb43630cSZhang Yubing #define DPTX_AUX_DATA0				0x0b08
142*fb43630cSZhang Yubing #define DPTX_AUX_DATA1				0x0b0c
143*fb43630cSZhang Yubing #define DPTX_AUX_DATA2				0x0b10
144*fb43630cSZhang Yubing #define DPTX_AUX_DATA3				0x0b14
145*fb43630cSZhang Yubing 
146*fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT			0x0d00
147*fb43630cSZhang Yubing #define VIDEO_FIFO_OVERFLOW_STREAM0		BIT(6)
148*fb43630cSZhang Yubing #define AUDIO_FIFO_OVERFLOW_STREAM0		BIT(5)
149*fb43630cSZhang Yubing #define SDP_EVENT_STREAM0			BIT(4)
150*fb43630cSZhang Yubing #define AUX_CMD_INVALID				BIT(3)
151*fb43630cSZhang Yubing #define AUX_REPLY_EVENT				BIT(1)
152*fb43630cSZhang Yubing #define HPD_EVENT				BIT(0)
153*fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT_ENABLE		0x0d04
154*fb43630cSZhang Yubing #define AUX_REPLY_EVENT_EN			BIT(1)
155*fb43630cSZhang Yubing #define HPD_EVENT_EN				BIT(0)
156*fb43630cSZhang Yubing #define DPTX_HPD_STATUS				0x0d08
157*fb43630cSZhang Yubing #define HPD_STATE				GENMASK(11, 9)
158*fb43630cSZhang Yubing #define HPD_STATUS				BIT(8)
159*fb43630cSZhang Yubing #define HPD_HOT_UNPLUG				BIT(2)
160*fb43630cSZhang Yubing #define HPD_HOT_PLUG				BIT(1)
161*fb43630cSZhang Yubing #define HPD_IRQ					BIT(0)
162*fb43630cSZhang Yubing #define DPTX_HPD_INTERRUPT_ENABLE		0x0d0c
163*fb43630cSZhang Yubing #define HPD_UNPLUG_ERR_EN			BIT(3)
164*fb43630cSZhang Yubing #define HPD_UNPLUG_EN				BIT(2)
165*fb43630cSZhang Yubing #define HPD_PLUG_EN				BIT(1)
166*fb43630cSZhang Yubing #define HPD_IRQ_EN				BIT(0)
167*fb43630cSZhang Yubing 
168*fb43630cSZhang Yubing #define DPTX_MAX_REGISTER			DPTX_HPD_INTERRUPT_ENABLE
169*fb43630cSZhang Yubing 
170*fb43630cSZhang Yubing #define SDP_REG_BANK_SIZE			16
171*fb43630cSZhang Yubing 
172*fb43630cSZhang Yubing struct drm_dp_link_caps {
173*fb43630cSZhang Yubing 	bool enhanced_framing;
174*fb43630cSZhang Yubing 	bool tps3_supported;
175*fb43630cSZhang Yubing 	bool tps4_supported;
176*fb43630cSZhang Yubing 	bool channel_coding;
177*fb43630cSZhang Yubing 	bool ssc;
178*fb43630cSZhang Yubing };
179*fb43630cSZhang Yubing 
180*fb43630cSZhang Yubing struct drm_dp_link_train_set {
181*fb43630cSZhang Yubing 	unsigned int voltage_swing[4];
182*fb43630cSZhang Yubing 	unsigned int pre_emphasis[4];
183*fb43630cSZhang Yubing };
184*fb43630cSZhang Yubing 
185*fb43630cSZhang Yubing struct drm_dp_link_train {
186*fb43630cSZhang Yubing 	struct drm_dp_link_train_set request;
187*fb43630cSZhang Yubing 	struct drm_dp_link_train_set adjust;
188*fb43630cSZhang Yubing 	bool clock_recovered;
189*fb43630cSZhang Yubing 	bool channel_equalized;
190*fb43630cSZhang Yubing };
191*fb43630cSZhang Yubing 
192*fb43630cSZhang Yubing struct dw_dp_link {
193*fb43630cSZhang Yubing 	u8 dpcd[DP_RECEIVER_CAP_SIZE];
194*fb43630cSZhang Yubing 	unsigned char revision;
195*fb43630cSZhang Yubing 	unsigned int rate;
196*fb43630cSZhang Yubing 	unsigned int lanes;
197*fb43630cSZhang Yubing 	struct drm_dp_link_caps caps;
198*fb43630cSZhang Yubing 	struct drm_dp_link_train train;
199*fb43630cSZhang Yubing 	u8 sink_count;
200*fb43630cSZhang Yubing 	u8 vsc_sdp_extension_for_colorimetry_supported;
201*fb43630cSZhang Yubing };
202*fb43630cSZhang Yubing 
203*fb43630cSZhang Yubing struct dw_dp_video {
204*fb43630cSZhang Yubing 	struct drm_display_mode mode;
205*fb43630cSZhang Yubing 	u32 bus_format;
206*fb43630cSZhang Yubing 	u8 video_mapping;
207*fb43630cSZhang Yubing 	u8 pixel_mode;
208*fb43630cSZhang Yubing 	u8 color_format;
209*fb43630cSZhang Yubing 	u8 bpc;
210*fb43630cSZhang Yubing 	u8 bpp;
211*fb43630cSZhang Yubing };
212*fb43630cSZhang Yubing 
213*fb43630cSZhang Yubing struct dw_dp_sdp {
214*fb43630cSZhang Yubing 	struct dp_sdp_header header;
215*fb43630cSZhang Yubing 	u8 db[32];
216*fb43630cSZhang Yubing 	unsigned long flags;
217*fb43630cSZhang Yubing };
218*fb43630cSZhang Yubing 
219*fb43630cSZhang Yubing struct dw_dp {
220*fb43630cSZhang Yubing 	struct udevice *dev;
221*fb43630cSZhang Yubing 	struct regmap *regmap;
222*fb43630cSZhang Yubing 	struct phy phy;
223*fb43630cSZhang Yubing 	struct reset_ctl reset;
224*fb43630cSZhang Yubing 	int id;
225*fb43630cSZhang Yubing 
226*fb43630cSZhang Yubing 	struct gpio_desc hpd_gpio;
227*fb43630cSZhang Yubing 	struct drm_dp_aux aux;
228*fb43630cSZhang Yubing 	struct dw_dp_link link;
229*fb43630cSZhang Yubing 	struct dw_dp_video video;
230*fb43630cSZhang Yubing };
231*fb43630cSZhang Yubing 
232*fb43630cSZhang Yubing enum {
233*fb43630cSZhang Yubing 	SOURCE_STATE_IDLE,
234*fb43630cSZhang Yubing 	SOURCE_STATE_UNPLUG,
235*fb43630cSZhang Yubing 	SOURCE_STATE_HPD_TIMEOUT = 4,
236*fb43630cSZhang Yubing 	SOURCE_STATE_PLUG = 7
237*fb43630cSZhang Yubing };
238*fb43630cSZhang Yubing 
239*fb43630cSZhang Yubing enum {
240*fb43630cSZhang Yubing 	DPTX_VM_RGB_6BIT,
241*fb43630cSZhang Yubing 	DPTX_VM_RGB_8BIT,
242*fb43630cSZhang Yubing 	DPTX_VM_RGB_10BIT,
243*fb43630cSZhang Yubing 	DPTX_VM_RGB_12BIT,
244*fb43630cSZhang Yubing 	DPTX_VM_RGB_16BIT,
245*fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_8BIT,
246*fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_10BIT,
247*fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_12BIT,
248*fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_16BIT,
249*fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_8BIT,
250*fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_10BIT,
251*fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_12BIT,
252*fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_16BIT,
253*fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_8BIT,
254*fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_10BIT,
255*fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_12BIT,
256*fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_16BIT,
257*fb43630cSZhang Yubing };
258*fb43630cSZhang Yubing 
259*fb43630cSZhang Yubing enum {
260*fb43630cSZhang Yubing 	DPTX_MP_SINGLE_PIXEL,
261*fb43630cSZhang Yubing 	DPTX_MP_DUAL_PIXEL,
262*fb43630cSZhang Yubing 	DPTX_MP_QUAD_PIXEL,
263*fb43630cSZhang Yubing };
264*fb43630cSZhang Yubing 
265*fb43630cSZhang Yubing enum {
266*fb43630cSZhang Yubing 	DPTX_SDP_VERTICAL_INTERVAL = BIT(0),
267*fb43630cSZhang Yubing 	DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1),
268*fb43630cSZhang Yubing };
269*fb43630cSZhang Yubing 
270*fb43630cSZhang Yubing enum {
271*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_NONE,
272*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_1,
273*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_2,
274*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_3,
275*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_4,
276*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_SERM,
277*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_PBRS7,
278*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CUSTOM_80BIT,
279*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CP2520_1,
280*fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CP2520_2,
281*fb43630cSZhang Yubing };
282*fb43630cSZhang Yubing 
283*fb43630cSZhang Yubing struct dw_dp_output_format {
284*fb43630cSZhang Yubing 	u32 bus_format;
285*fb43630cSZhang Yubing 	u32 color_format;
286*fb43630cSZhang Yubing 	u8 video_mapping;
287*fb43630cSZhang Yubing 	u8 bpc;
288*fb43630cSZhang Yubing 	u8 bpp;
289*fb43630cSZhang Yubing };
290*fb43630cSZhang Yubing 
291*fb43630cSZhang Yubing static const struct dw_dp_output_format possible_output_fmts[] = {
292*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444,
293*fb43630cSZhang Yubing 	  DPTX_VM_RGB_10BIT, 10, 30 },
294*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444,
295*fb43630cSZhang Yubing 	  DPTX_VM_RGB_8BIT, 8, 24 },
296*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444,
297*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR444_10BIT, 10, 30 },
298*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444,
299*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR444_8BIT, 8, 24},
300*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422,
301*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR422_10BIT, 10, 20 },
302*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422,
303*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR422_8BIT, 8, 16 },
304*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420,
305*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR420_10BIT, 10, 15 },
306*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420,
307*fb43630cSZhang Yubing 	  DPTX_VM_YCBCR420_8BIT, 8, 12 },
308*fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444,
309*fb43630cSZhang Yubing 	  DPTX_VM_RGB_6BIT, 6, 18 },
310*fb43630cSZhang Yubing };
311*fb43630cSZhang Yubing 
312*fb43630cSZhang Yubing static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size)
313*fb43630cSZhang Yubing {
314*fb43630cSZhang Yubing 	size_t i, j;
315*fb43630cSZhang Yubing 
316*fb43630cSZhang Yubing 	for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
317*fb43630cSZhang Yubing 		size_t num = min_t(size_t, size - i * 4, 4);
318*fb43630cSZhang Yubing 		u32 value = 0;
319*fb43630cSZhang Yubing 
320*fb43630cSZhang Yubing 		for (j = 0; j < num; j++)
321*fb43630cSZhang Yubing 			value |= buffer[i * 4 + j] << (j * 8);
322*fb43630cSZhang Yubing 
323*fb43630cSZhang Yubing 		regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value);
324*fb43630cSZhang Yubing 	}
325*fb43630cSZhang Yubing 
326*fb43630cSZhang Yubing 	return size;
327*fb43630cSZhang Yubing }
328*fb43630cSZhang Yubing 
329*fb43630cSZhang Yubing static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size)
330*fb43630cSZhang Yubing {
331*fb43630cSZhang Yubing 	size_t i, j;
332*fb43630cSZhang Yubing 
333*fb43630cSZhang Yubing 	for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
334*fb43630cSZhang Yubing 		size_t num = min_t(size_t, size - i * 4, 4);
335*fb43630cSZhang Yubing 		u32 value;
336*fb43630cSZhang Yubing 
337*fb43630cSZhang Yubing 		regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value);
338*fb43630cSZhang Yubing 
339*fb43630cSZhang Yubing 		for (j = 0; j < num; j++)
340*fb43630cSZhang Yubing 			buffer[i * 4 + j] = value >> (j * 8);
341*fb43630cSZhang Yubing 	}
342*fb43630cSZhang Yubing 
343*fb43630cSZhang Yubing 	return size;
344*fb43630cSZhang Yubing }
345*fb43630cSZhang Yubing 
346*fb43630cSZhang Yubing static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
347*fb43630cSZhang Yubing 				  struct drm_dp_aux_msg *msg)
348*fb43630cSZhang Yubing {
349*fb43630cSZhang Yubing 	u32 status, value;
350*fb43630cSZhang Yubing 	ssize_t ret = 0;
351*fb43630cSZhang Yubing 	int timeout = 0;
352*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(aux->dev);
353*fb43630cSZhang Yubing 
354*fb43630cSZhang Yubing 	if (WARN_ON(msg->size > 16))
355*fb43630cSZhang Yubing 		return -E2BIG;
356*fb43630cSZhang Yubing 
357*fb43630cSZhang Yubing 	switch (msg->request & ~DP_AUX_I2C_MOT) {
358*fb43630cSZhang Yubing 	case DP_AUX_NATIVE_WRITE:
359*fb43630cSZhang Yubing 	case DP_AUX_I2C_WRITE:
360*fb43630cSZhang Yubing 	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
361*fb43630cSZhang Yubing 		ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size);
362*fb43630cSZhang Yubing 		if (ret < 0)
363*fb43630cSZhang Yubing 			return ret;
364*fb43630cSZhang Yubing 		break;
365*fb43630cSZhang Yubing 	case DP_AUX_NATIVE_READ:
366*fb43630cSZhang Yubing 	case DP_AUX_I2C_READ:
367*fb43630cSZhang Yubing 		break;
368*fb43630cSZhang Yubing 	default:
369*fb43630cSZhang Yubing 		return -EINVAL;
370*fb43630cSZhang Yubing 	}
371*fb43630cSZhang Yubing 
372*fb43630cSZhang Yubing 	if (msg->size > 0)
373*fb43630cSZhang Yubing 		value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1);
374*fb43630cSZhang Yubing 	else
375*fb43630cSZhang Yubing 		value = FIELD_PREP(I2C_ADDR_ONLY, 1);
376*fb43630cSZhang Yubing 
377*fb43630cSZhang Yubing 	value |= FIELD_PREP(AUX_CMD_TYPE, msg->request);
378*fb43630cSZhang Yubing 	value |= FIELD_PREP(AUX_ADDR, msg->address);
379*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_AUX_CMD, value);
380*fb43630cSZhang Yubing 
381*fb43630cSZhang Yubing 	timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT,
382*fb43630cSZhang Yubing 					   status, status & AUX_REPLY_EVENT,
383*fb43630cSZhang Yubing 					   200, 10);
384*fb43630cSZhang Yubing 
385*fb43630cSZhang Yubing 	if (timeout) {
386*fb43630cSZhang Yubing 		printf("timeout waiting for AUX reply\n");
387*fb43630cSZhang Yubing 		return -ETIMEDOUT;
388*fb43630cSZhang Yubing 	}
389*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT);
390*fb43630cSZhang Yubing 
391*fb43630cSZhang Yubing 	regmap_read(dp->regmap, DPTX_AUX_STATUS, &value);
392*fb43630cSZhang Yubing 	if (value & AUX_TIMEOUT) {
393*fb43630cSZhang Yubing 		printf("aux timeout\n");
394*fb43630cSZhang Yubing 		return -ETIMEDOUT;
395*fb43630cSZhang Yubing 	}
396*fb43630cSZhang Yubing 
397*fb43630cSZhang Yubing 	msg->reply = FIELD_GET(AUX_STATUS, value);
398*fb43630cSZhang Yubing 
399*fb43630cSZhang Yubing 	if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
400*fb43630cSZhang Yubing 		if (msg->request & DP_AUX_I2C_READ) {
401*fb43630cSZhang Yubing 			size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1;
402*fb43630cSZhang Yubing 
403*fb43630cSZhang Yubing 			if (count != msg->size) {
404*fb43630cSZhang Yubing 				printf("aux fail to read %lu bytes\n", count);
405*fb43630cSZhang Yubing 				return -EBUSY;
406*fb43630cSZhang Yubing 			}
407*fb43630cSZhang Yubing 
408*fb43630cSZhang Yubing 			ret = dw_dp_aux_read_data(dp, msg->buffer, count);
409*fb43630cSZhang Yubing 			if (ret < 0)
410*fb43630cSZhang Yubing 				return ret;
411*fb43630cSZhang Yubing 		}
412*fb43630cSZhang Yubing 	}
413*fb43630cSZhang Yubing 
414*fb43630cSZhang Yubing 	return ret;
415*fb43630cSZhang Yubing }
416*fb43630cSZhang Yubing 
417*fb43630cSZhang Yubing static bool dw_dp_bandwidth_ok(struct dw_dp *dp,
418*fb43630cSZhang Yubing 			       const struct drm_display_mode *mode, u32 bpp,
419*fb43630cSZhang Yubing 			       unsigned int lanes, unsigned int rate)
420*fb43630cSZhang Yubing {
421*fb43630cSZhang Yubing 	u32 max_bw, req_bw;
422*fb43630cSZhang Yubing 
423*fb43630cSZhang Yubing 	req_bw = mode->clock * bpp / 8;
424*fb43630cSZhang Yubing 	max_bw = lanes * rate;
425*fb43630cSZhang Yubing 	if (req_bw > max_bw)
426*fb43630cSZhang Yubing 		return false;
427*fb43630cSZhang Yubing 
428*fb43630cSZhang Yubing 	return true;
429*fb43630cSZhang Yubing }
430*fb43630cSZhang Yubing 
431*fb43630cSZhang Yubing static void dw_dp_hpd_init(struct dw_dp *dp)
432*fb43630cSZhang Yubing {
433*fb43630cSZhang Yubing 	if (dm_gpio_is_valid(&dp->hpd_gpio)) {
434*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD,
435*fb43630cSZhang Yubing 				   FIELD_PREP(FORCE_HPD, 1));
436*fb43630cSZhang Yubing 		return;
437*fb43630cSZhang Yubing 	}
438*fb43630cSZhang Yubing 
439*fb43630cSZhang Yubing 	/* Enable all HPD interrupts */
440*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE,
441*fb43630cSZhang Yubing 			   HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN,
442*fb43630cSZhang Yubing 			   FIELD_PREP(HPD_UNPLUG_EN, 1) |
443*fb43630cSZhang Yubing 			   FIELD_PREP(HPD_PLUG_EN, 1) |
444*fb43630cSZhang Yubing 			   FIELD_PREP(HPD_IRQ_EN, 1));
445*fb43630cSZhang Yubing 
446*fb43630cSZhang Yubing 	/* Enable all top-level interrupts */
447*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
448*fb43630cSZhang Yubing 			   HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1));
449*fb43630cSZhang Yubing }
450*fb43630cSZhang Yubing 
451*fb43630cSZhang Yubing static void dw_dp_aux_init(struct dw_dp *dp)
452*fb43630cSZhang Yubing {
453*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
454*fb43630cSZhang Yubing 			   FIELD_PREP(AUX_RESET, 1));
455*fb43630cSZhang Yubing 	udelay(10);
456*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
457*fb43630cSZhang Yubing 			   FIELD_PREP(AUX_RESET, 0));
458*fb43630cSZhang Yubing 
459*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
460*fb43630cSZhang Yubing 			   AUX_REPLY_EVENT_EN,
461*fb43630cSZhang Yubing 			   FIELD_PREP(AUX_REPLY_EVENT_EN, 1));
462*fb43630cSZhang Yubing }
463*fb43630cSZhang Yubing 
464*fb43630cSZhang Yubing static void dw_dp_init(struct dw_dp *dp)
465*fb43630cSZhang Yubing {
466*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
467*fb43630cSZhang Yubing 			   FIELD_PREP(CONTROLLER_RESET, 1));
468*fb43630cSZhang Yubing 	udelay(10);
469*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
470*fb43630cSZhang Yubing 			   FIELD_PREP(CONTROLLER_RESET, 0));
471*fb43630cSZhang Yubing 
472*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
473*fb43630cSZhang Yubing 			   FIELD_PREP(PHY_SOFT_RESET, 1));
474*fb43630cSZhang Yubing 	udelay(10);
475*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
476*fb43630cSZhang Yubing 			   FIELD_PREP(PHY_SOFT_RESET, 0));
477*fb43630cSZhang Yubing 
478*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN,
479*fb43630cSZhang Yubing 			   FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0));
480*fb43630cSZhang Yubing 
481*fb43630cSZhang Yubing 	dw_dp_hpd_init(dp);
482*fb43630cSZhang Yubing 	dw_dp_aux_init(dp);
483*fb43630cSZhang Yubing }
484*fb43630cSZhang Yubing 
485*fb43630cSZhang Yubing static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern)
486*fb43630cSZhang Yubing {
487*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL,
488*fb43630cSZhang Yubing 			   FIELD_PREP(TPS_SEL, pattern));
489*fb43630cSZhang Yubing }
490*fb43630cSZhang Yubing 
491*fb43630cSZhang Yubing static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes)
492*fb43630cSZhang Yubing {
493*fb43630cSZhang Yubing 	u32 xmit_enable;
494*fb43630cSZhang Yubing 
495*fb43630cSZhang Yubing 	switch (lanes) {
496*fb43630cSZhang Yubing 	case 4:
497*fb43630cSZhang Yubing 	case 2:
498*fb43630cSZhang Yubing 	case 1:
499*fb43630cSZhang Yubing 		xmit_enable = GENMASK(lanes - 1, 0);
500*fb43630cSZhang Yubing 		break;
501*fb43630cSZhang Yubing 	case 0:
502*fb43630cSZhang Yubing 	default:
503*fb43630cSZhang Yubing 		xmit_enable = 0;
504*fb43630cSZhang Yubing 		break;
505*fb43630cSZhang Yubing 	}
506*fb43630cSZhang Yubing 
507*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE,
508*fb43630cSZhang Yubing 			   FIELD_PREP(XMIT_ENABLE, xmit_enable));
509*fb43630cSZhang Yubing }
510*fb43630cSZhang Yubing 
511*fb43630cSZhang Yubing static int dw_dp_link_power_up(struct dw_dp *dp)
512*fb43630cSZhang Yubing {
513*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
514*fb43630cSZhang Yubing 	u8 value;
515*fb43630cSZhang Yubing 	int ret;
516*fb43630cSZhang Yubing 
517*fb43630cSZhang Yubing 	if (link->revision < 0x11)
518*fb43630cSZhang Yubing 		return 0;
519*fb43630cSZhang Yubing 
520*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
521*fb43630cSZhang Yubing 	if (ret < 0)
522*fb43630cSZhang Yubing 		return ret;
523*fb43630cSZhang Yubing 
524*fb43630cSZhang Yubing 	value &= ~DP_SET_POWER_MASK;
525*fb43630cSZhang Yubing 	value |= DP_SET_POWER_D0;
526*fb43630cSZhang Yubing 
527*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
528*fb43630cSZhang Yubing 	if (ret < 0)
529*fb43630cSZhang Yubing 		return ret;
530*fb43630cSZhang Yubing 
531*fb43630cSZhang Yubing 	udelay(1000);
532*fb43630cSZhang Yubing 	return 0;
533*fb43630cSZhang Yubing }
534*fb43630cSZhang Yubing 
535*fb43630cSZhang Yubing static int dw_dp_link_probe(struct dw_dp *dp)
536*fb43630cSZhang Yubing {
537*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
538*fb43630cSZhang Yubing 	u8 dpcd;
539*fb43630cSZhang Yubing 	int ret;
540*fb43630cSZhang Yubing 
541*fb43630cSZhang Yubing 	ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd);
542*fb43630cSZhang Yubing 	if (ret < 0)
543*fb43630cSZhang Yubing 		return ret;
544*fb43630cSZhang Yubing 
545*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
546*fb43630cSZhang Yubing 				&dpcd);
547*fb43630cSZhang Yubing 	if (ret < 0)
548*fb43630cSZhang Yubing 		return ret;
549*fb43630cSZhang Yubing 
550*fb43630cSZhang Yubing 	link->vsc_sdp_extension_for_colorimetry_supported =
551*fb43630cSZhang Yubing 		!!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED);
552*fb43630cSZhang Yubing 
553*fb43630cSZhang Yubing 	link->revision = link->dpcd[DP_DPCD_REV];
554*fb43630cSZhang Yubing 	link->rate = drm_dp_max_link_rate(link->dpcd);
555*fb43630cSZhang Yubing 	link->lanes = min_t(u8, dp->phy.attrs.bus_width,
556*fb43630cSZhang Yubing 			    drm_dp_max_lane_count(link->dpcd));
557*fb43630cSZhang Yubing 
558*fb43630cSZhang Yubing 	link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd);
559*fb43630cSZhang Yubing 	link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd);
560*fb43630cSZhang Yubing 	link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd);
561*fb43630cSZhang Yubing 	link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd);
562*fb43630cSZhang Yubing 	link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] &
563*fb43630cSZhang Yubing 			    DP_MAX_DOWNSPREAD_0_5);
564*fb43630cSZhang Yubing 
565*fb43630cSZhang Yubing 	return 0;
566*fb43630cSZhang Yubing }
567*fb43630cSZhang Yubing 
568*fb43630cSZhang Yubing static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp)
569*fb43630cSZhang Yubing {
570*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
571*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &link->train.request;
572*fb43630cSZhang Yubing 	union phy_configure_opts phy_cfg;
573*fb43630cSZhang Yubing 	unsigned int lanes = link->lanes, *vs, *pe;
574*fb43630cSZhang Yubing 	u8 buf[4];
575*fb43630cSZhang Yubing 	int i, ret;
576*fb43630cSZhang Yubing 
577*fb43630cSZhang Yubing 	vs = request->voltage_swing;
578*fb43630cSZhang Yubing 	pe = request->pre_emphasis;
579*fb43630cSZhang Yubing 
580*fb43630cSZhang Yubing 	for (i = 0; i < lanes; i++) {
581*fb43630cSZhang Yubing 		phy_cfg.dp.voltage[i] = vs[i];
582*fb43630cSZhang Yubing 		phy_cfg.dp.pre[i] = pe[i];
583*fb43630cSZhang Yubing 	}
584*fb43630cSZhang Yubing 	phy_cfg.dp.lanes = lanes;
585*fb43630cSZhang Yubing 	phy_cfg.dp.link_rate = link->rate / 100;
586*fb43630cSZhang Yubing 	phy_cfg.dp.set_lanes = false;
587*fb43630cSZhang Yubing 	phy_cfg.dp.set_rate = false;
588*fb43630cSZhang Yubing 	phy_cfg.dp.set_voltages = true;
589*fb43630cSZhang Yubing 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
590*fb43630cSZhang Yubing 	if (ret)
591*fb43630cSZhang Yubing 		return ret;
592*fb43630cSZhang Yubing 
593*fb43630cSZhang Yubing 	for (i = 0; i < lanes; i++)
594*fb43630cSZhang Yubing 		buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) |
595*fb43630cSZhang Yubing 			 (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT);
596*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes);
597*fb43630cSZhang Yubing 	if (ret < 0)
598*fb43630cSZhang Yubing 		return ret;
599*fb43630cSZhang Yubing 
600*fb43630cSZhang Yubing 	return 0;
601*fb43630cSZhang Yubing }
602*fb43630cSZhang Yubing 
603*fb43630cSZhang Yubing static int dw_dp_link_configure(struct dw_dp *dp)
604*fb43630cSZhang Yubing {
605*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
606*fb43630cSZhang Yubing 	union phy_configure_opts phy_cfg;
607*fb43630cSZhang Yubing 	u8 buf[2];
608*fb43630cSZhang Yubing 	int ret;
609*fb43630cSZhang Yubing 
610*fb43630cSZhang Yubing 	/* Move PHY to P3 */
611*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
612*fb43630cSZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x3));
613*fb43630cSZhang Yubing 
614*fb43630cSZhang Yubing 	phy_cfg.dp.lanes = link->lanes;
615*fb43630cSZhang Yubing 	phy_cfg.dp.link_rate = link->rate / 100;
616*fb43630cSZhang Yubing 	phy_cfg.dp.ssc = link->caps.ssc;
617*fb43630cSZhang Yubing 	phy_cfg.dp.set_lanes = true;
618*fb43630cSZhang Yubing 	phy_cfg.dp.set_rate = true;
619*fb43630cSZhang Yubing 	phy_cfg.dp.set_voltages = false;
620*fb43630cSZhang Yubing 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
621*fb43630cSZhang Yubing 	if (ret)
622*fb43630cSZhang Yubing 		return ret;
623*fb43630cSZhang Yubing 
624*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES,
625*fb43630cSZhang Yubing 			   FIELD_PREP(PHY_LANES, link->lanes / 2));
626*fb43630cSZhang Yubing 
627*fb43630cSZhang Yubing 	/* Move PHY to P0 */
628*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
629*fb43630cSZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x0));
630*fb43630cSZhang Yubing 
631*fb43630cSZhang Yubing 	dw_dp_phy_xmit_enable(dp, link->lanes);
632*fb43630cSZhang Yubing 
633*fb43630cSZhang Yubing 	buf[0] = drm_dp_link_rate_to_bw_code(link->rate);
634*fb43630cSZhang Yubing 	buf[1] = link->lanes;
635*fb43630cSZhang Yubing 
636*fb43630cSZhang Yubing 	if (link->caps.enhanced_framing) {
637*fb43630cSZhang Yubing 		buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
638*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
639*fb43630cSZhang Yubing 				   FIELD_PREP(ENHANCE_FRAMING_EN, 1));
640*fb43630cSZhang Yubing 	} else {
641*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
642*fb43630cSZhang Yubing 				   FIELD_PREP(ENHANCE_FRAMING_EN, 0));
643*fb43630cSZhang Yubing 	}
644*fb43630cSZhang Yubing 
645*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf));
646*fb43630cSZhang Yubing 	if (ret < 0)
647*fb43630cSZhang Yubing 		return ret;
648*fb43630cSZhang Yubing 
649*fb43630cSZhang Yubing 	buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0;
650*fb43630cSZhang Yubing 	buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0;
651*fb43630cSZhang Yubing 
652*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf,
653*fb43630cSZhang Yubing 				sizeof(buf));
654*fb43630cSZhang Yubing 	if (ret < 0)
655*fb43630cSZhang Yubing 		return ret;
656*fb43630cSZhang Yubing 
657*fb43630cSZhang Yubing 	return 0;
658*fb43630cSZhang Yubing }
659*fb43630cSZhang Yubing 
660*fb43630cSZhang Yubing static void dw_dp_link_train_init(struct drm_dp_link_train *train)
661*fb43630cSZhang Yubing {
662*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &train->request;
663*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &train->adjust;
664*fb43630cSZhang Yubing 	unsigned int i;
665*fb43630cSZhang Yubing 
666*fb43630cSZhang Yubing 	for (i = 0; i < 4; i++) {
667*fb43630cSZhang Yubing 		request->voltage_swing[i] = 0;
668*fb43630cSZhang Yubing 		adjust->voltage_swing[i] = 0;
669*fb43630cSZhang Yubing 
670*fb43630cSZhang Yubing 		request->pre_emphasis[i] = 0;
671*fb43630cSZhang Yubing 		adjust->pre_emphasis[i] = 0;
672*fb43630cSZhang Yubing 	}
673*fb43630cSZhang Yubing 
674*fb43630cSZhang Yubing 	train->clock_recovered = false;
675*fb43630cSZhang Yubing 	train->channel_equalized = false;
676*fb43630cSZhang Yubing }
677*fb43630cSZhang Yubing 
678*fb43630cSZhang Yubing static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern)
679*fb43630cSZhang Yubing {
680*fb43630cSZhang Yubing 	u8 buf = 0;
681*fb43630cSZhang Yubing 	int ret;
682*fb43630cSZhang Yubing 
683*fb43630cSZhang Yubing 	if (pattern && pattern != DP_TRAINING_PATTERN_4) {
684*fb43630cSZhang Yubing 		buf |= DP_LINK_SCRAMBLING_DISABLE;
685*fb43630cSZhang Yubing 
686*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
687*fb43630cSZhang Yubing 				   FIELD_PREP(SCRAMBLE_DIS, 1));
688*fb43630cSZhang Yubing 	} else {
689*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
690*fb43630cSZhang Yubing 				   FIELD_PREP(SCRAMBLE_DIS, 0));
691*fb43630cSZhang Yubing 	}
692*fb43630cSZhang Yubing 
693*fb43630cSZhang Yubing 	switch (pattern) {
694*fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_DISABLE:
695*fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE);
696*fb43630cSZhang Yubing 		break;
697*fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_1:
698*fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1);
699*fb43630cSZhang Yubing 		break;
700*fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_2:
701*fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2);
702*fb43630cSZhang Yubing 		break;
703*fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_3:
704*fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3);
705*fb43630cSZhang Yubing 		break;
706*fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_4:
707*fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4);
708*fb43630cSZhang Yubing 		break;
709*fb43630cSZhang Yubing 	default:
710*fb43630cSZhang Yubing 		return -EINVAL;
711*fb43630cSZhang Yubing 	}
712*fb43630cSZhang Yubing 
713*fb43630cSZhang Yubing 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
714*fb43630cSZhang Yubing 				 buf | pattern);
715*fb43630cSZhang Yubing 	if (ret < 0)
716*fb43630cSZhang Yubing 		return ret;
717*fb43630cSZhang Yubing 
718*fb43630cSZhang Yubing 	return 0;
719*fb43630cSZhang Yubing }
720*fb43630cSZhang Yubing 
721*fb43630cSZhang Yubing static void dw_dp_link_get_adjustments(struct dw_dp_link *link,
722*fb43630cSZhang Yubing 				       u8 status[DP_LINK_STATUS_SIZE])
723*fb43630cSZhang Yubing {
724*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &link->train.adjust;
725*fb43630cSZhang Yubing 	unsigned int i;
726*fb43630cSZhang Yubing 
727*fb43630cSZhang Yubing 	for (i = 0; i < link->lanes; i++) {
728*fb43630cSZhang Yubing 		adjust->voltage_swing[i] =
729*fb43630cSZhang Yubing 			drm_dp_get_adjust_request_voltage(status, i) >>
730*fb43630cSZhang Yubing 				DP_TRAIN_VOLTAGE_SWING_SHIFT;
731*fb43630cSZhang Yubing 
732*fb43630cSZhang Yubing 		adjust->pre_emphasis[i] =
733*fb43630cSZhang Yubing 			drm_dp_get_adjust_request_pre_emphasis(status, i) >>
734*fb43630cSZhang Yubing 				DP_TRAIN_PRE_EMPHASIS_SHIFT;
735*fb43630cSZhang Yubing 	}
736*fb43630cSZhang Yubing }
737*fb43630cSZhang Yubing 
738*fb43630cSZhang Yubing static void dw_dp_link_train_adjust(struct drm_dp_link_train *train)
739*fb43630cSZhang Yubing {
740*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &train->request;
741*fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &train->adjust;
742*fb43630cSZhang Yubing 	unsigned int i;
743*fb43630cSZhang Yubing 
744*fb43630cSZhang Yubing 	for (i = 0; i < 4; i++)
745*fb43630cSZhang Yubing 		if (request->voltage_swing[i] != adjust->voltage_swing[i])
746*fb43630cSZhang Yubing 			request->voltage_swing[i] = adjust->voltage_swing[i];
747*fb43630cSZhang Yubing 
748*fb43630cSZhang Yubing 	for (i = 0; i < 4; i++)
749*fb43630cSZhang Yubing 		if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
750*fb43630cSZhang Yubing 			request->pre_emphasis[i] = adjust->pre_emphasis[i];
751*fb43630cSZhang Yubing }
752*fb43630cSZhang Yubing 
753*fb43630cSZhang Yubing static int dw_dp_link_clock_recovery(struct dw_dp *dp)
754*fb43630cSZhang Yubing {
755*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
756*fb43630cSZhang Yubing 	u8 status[DP_LINK_STATUS_SIZE];
757*fb43630cSZhang Yubing 	unsigned int tries = 0;
758*fb43630cSZhang Yubing 	int ret;
759*fb43630cSZhang Yubing 
760*fb43630cSZhang Yubing 	ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);
761*fb43630cSZhang Yubing 	if (ret)
762*fb43630cSZhang Yubing 		return ret;
763*fb43630cSZhang Yubing 
764*fb43630cSZhang Yubing 	for (;;) {
765*fb43630cSZhang Yubing 		ret = dw_dp_link_train_update_vs_emph(dp);
766*fb43630cSZhang Yubing 		if (ret)
767*fb43630cSZhang Yubing 			return ret;
768*fb43630cSZhang Yubing 
769*fb43630cSZhang Yubing 		drm_dp_link_train_clock_recovery_delay(link->dpcd);
770*fb43630cSZhang Yubing 
771*fb43630cSZhang Yubing 		ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
772*fb43630cSZhang Yubing 		if (ret < 0) {
773*fb43630cSZhang Yubing 			dev_err(dp->dev, "failed to read link status: %d\n",
774*fb43630cSZhang Yubing 				ret);
775*fb43630cSZhang Yubing 			return ret;
776*fb43630cSZhang Yubing 		}
777*fb43630cSZhang Yubing 
778*fb43630cSZhang Yubing 		if (drm_dp_clock_recovery_ok(status, link->lanes)) {
779*fb43630cSZhang Yubing 			link->train.clock_recovered = true;
780*fb43630cSZhang Yubing 			break;
781*fb43630cSZhang Yubing 		}
782*fb43630cSZhang Yubing 
783*fb43630cSZhang Yubing 		dw_dp_link_get_adjustments(link, status);
784*fb43630cSZhang Yubing 
785*fb43630cSZhang Yubing 		if (link->train.request.voltage_swing[0] ==
786*fb43630cSZhang Yubing 		    link->train.adjust.voltage_swing[0])
787*fb43630cSZhang Yubing 			tries++;
788*fb43630cSZhang Yubing 		else
789*fb43630cSZhang Yubing 			tries = 0;
790*fb43630cSZhang Yubing 
791*fb43630cSZhang Yubing 		if (tries == 5)
792*fb43630cSZhang Yubing 			break;
793*fb43630cSZhang Yubing 
794*fb43630cSZhang Yubing 		dw_dp_link_train_adjust(&link->train);
795*fb43630cSZhang Yubing 	}
796*fb43630cSZhang Yubing 
797*fb43630cSZhang Yubing 	return 0;
798*fb43630cSZhang Yubing }
799*fb43630cSZhang Yubing 
800*fb43630cSZhang Yubing static int dw_dp_link_channel_equalization(struct dw_dp *dp)
801*fb43630cSZhang Yubing {
802*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
803*fb43630cSZhang Yubing 	u8 status[DP_LINK_STATUS_SIZE], pattern;
804*fb43630cSZhang Yubing 	unsigned int tries;
805*fb43630cSZhang Yubing 	int ret;
806*fb43630cSZhang Yubing 
807*fb43630cSZhang Yubing 	if (link->caps.tps4_supported)
808*fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_4;
809*fb43630cSZhang Yubing 	else if (link->caps.tps3_supported)
810*fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_3;
811*fb43630cSZhang Yubing 	else
812*fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_2;
813*fb43630cSZhang Yubing 	ret = dw_dp_link_train_set_pattern(dp, pattern);
814*fb43630cSZhang Yubing 	if (ret)
815*fb43630cSZhang Yubing 		return ret;
816*fb43630cSZhang Yubing 
817*fb43630cSZhang Yubing 	for (tries = 1; tries < 5; tries++) {
818*fb43630cSZhang Yubing 		ret = dw_dp_link_train_update_vs_emph(dp);
819*fb43630cSZhang Yubing 		if (ret)
820*fb43630cSZhang Yubing 			return ret;
821*fb43630cSZhang Yubing 
822*fb43630cSZhang Yubing 		drm_dp_link_train_channel_eq_delay(link->dpcd);
823*fb43630cSZhang Yubing 
824*fb43630cSZhang Yubing 		ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
825*fb43630cSZhang Yubing 		if (ret < 0)
826*fb43630cSZhang Yubing 			return ret;
827*fb43630cSZhang Yubing 
828*fb43630cSZhang Yubing 		if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
829*fb43630cSZhang Yubing 			dev_err(dp->dev,
830*fb43630cSZhang Yubing 				"clock recovery lost while eq\n");
831*fb43630cSZhang Yubing 			link->train.clock_recovered = false;
832*fb43630cSZhang Yubing 			break;
833*fb43630cSZhang Yubing 		}
834*fb43630cSZhang Yubing 
835*fb43630cSZhang Yubing 		if (drm_dp_channel_eq_ok(status, link->lanes)) {
836*fb43630cSZhang Yubing 			link->train.channel_equalized = true;
837*fb43630cSZhang Yubing 			break;
838*fb43630cSZhang Yubing 		}
839*fb43630cSZhang Yubing 
840*fb43630cSZhang Yubing 		dw_dp_link_get_adjustments(link, status);
841*fb43630cSZhang Yubing 		dw_dp_link_train_adjust(&link->train);
842*fb43630cSZhang Yubing 	}
843*fb43630cSZhang Yubing 
844*fb43630cSZhang Yubing 	return 0;
845*fb43630cSZhang Yubing }
846*fb43630cSZhang Yubing 
847*fb43630cSZhang Yubing static int dw_dp_link_downgrade(struct dw_dp *dp)
848*fb43630cSZhang Yubing {
849*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
850*fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
851*fb43630cSZhang Yubing 
852*fb43630cSZhang Yubing 	switch (link->rate) {
853*fb43630cSZhang Yubing 	case 162000:
854*fb43630cSZhang Yubing 		return -EINVAL;
855*fb43630cSZhang Yubing 	case 270000:
856*fb43630cSZhang Yubing 		link->rate = 162000;
857*fb43630cSZhang Yubing 		break;
858*fb43630cSZhang Yubing 	case 540000:
859*fb43630cSZhang Yubing 		link->rate = 270000;
860*fb43630cSZhang Yubing 		break;
861*fb43630cSZhang Yubing 	case 810000:
862*fb43630cSZhang Yubing 		link->rate = 540000;
863*fb43630cSZhang Yubing 		break;
864*fb43630cSZhang Yubing 	}
865*fb43630cSZhang Yubing 
866*fb43630cSZhang Yubing 	if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes,
867*fb43630cSZhang Yubing 				link->rate))
868*fb43630cSZhang Yubing 		return -E2BIG;
869*fb43630cSZhang Yubing 
870*fb43630cSZhang Yubing 	return 0;
871*fb43630cSZhang Yubing }
872*fb43630cSZhang Yubing 
873*fb43630cSZhang Yubing static int dw_dp_link_train(struct dw_dp *dp)
874*fb43630cSZhang Yubing {
875*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
876*fb43630cSZhang Yubing 	int ret;
877*fb43630cSZhang Yubing 
878*fb43630cSZhang Yubing retry:
879*fb43630cSZhang Yubing 	dw_dp_link_train_init(&link->train);
880*fb43630cSZhang Yubing 
881*fb43630cSZhang Yubing 	printf("training link: %u lane%s at %u MHz\n",
882*fb43630cSZhang Yubing 	       link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100);
883*fb43630cSZhang Yubing 
884*fb43630cSZhang Yubing 	ret = dw_dp_link_configure(dp);
885*fb43630cSZhang Yubing 	if (ret < 0) {
886*fb43630cSZhang Yubing 		dev_err(dp->dev, "failed to configure DP link: %d\n", ret);
887*fb43630cSZhang Yubing 		return ret;
888*fb43630cSZhang Yubing 	}
889*fb43630cSZhang Yubing 
890*fb43630cSZhang Yubing 	ret = dw_dp_link_clock_recovery(dp);
891*fb43630cSZhang Yubing 	if (ret < 0) {
892*fb43630cSZhang Yubing 		dev_err(dp->dev, "clock recovery failed: %d\n", ret);
893*fb43630cSZhang Yubing 		goto out;
894*fb43630cSZhang Yubing 	}
895*fb43630cSZhang Yubing 
896*fb43630cSZhang Yubing 	if (!link->train.clock_recovered) {
897*fb43630cSZhang Yubing 		dev_err(dp->dev, "clock recovery failed, downgrading link\n");
898*fb43630cSZhang Yubing 
899*fb43630cSZhang Yubing 		ret = dw_dp_link_downgrade(dp);
900*fb43630cSZhang Yubing 		if (ret < 0)
901*fb43630cSZhang Yubing 			goto out;
902*fb43630cSZhang Yubing 		else
903*fb43630cSZhang Yubing 			goto retry;
904*fb43630cSZhang Yubing 	}
905*fb43630cSZhang Yubing 
906*fb43630cSZhang Yubing 	printf("clock recovery succeeded\n");
907*fb43630cSZhang Yubing 
908*fb43630cSZhang Yubing 	ret = dw_dp_link_channel_equalization(dp);
909*fb43630cSZhang Yubing 	if (ret < 0) {
910*fb43630cSZhang Yubing 		dev_err(dp->dev, "channel equalization failed: %d\n", ret);
911*fb43630cSZhang Yubing 		goto out;
912*fb43630cSZhang Yubing 	}
913*fb43630cSZhang Yubing 
914*fb43630cSZhang Yubing 	if (!link->train.channel_equalized) {
915*fb43630cSZhang Yubing 		dev_err(dp->dev,
916*fb43630cSZhang Yubing 			"channel equalization failed, downgrading link\n");
917*fb43630cSZhang Yubing 
918*fb43630cSZhang Yubing 		ret = dw_dp_link_downgrade(dp);
919*fb43630cSZhang Yubing 		if (ret < 0)
920*fb43630cSZhang Yubing 			goto out;
921*fb43630cSZhang Yubing 		else
922*fb43630cSZhang Yubing 			goto retry;
923*fb43630cSZhang Yubing 	}
924*fb43630cSZhang Yubing 
925*fb43630cSZhang Yubing 	printf("channel equalization succeeded\n");
926*fb43630cSZhang Yubing 
927*fb43630cSZhang Yubing out:
928*fb43630cSZhang Yubing 	dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
929*fb43630cSZhang Yubing 	return ret;
930*fb43630cSZhang Yubing }
931*fb43630cSZhang Yubing 
932*fb43630cSZhang Yubing static int dw_dp_link_enable(struct dw_dp *dp)
933*fb43630cSZhang Yubing {
934*fb43630cSZhang Yubing 	int ret;
935*fb43630cSZhang Yubing 
936*fb43630cSZhang Yubing 	ret = dw_dp_link_power_up(dp);
937*fb43630cSZhang Yubing 	if (ret < 0)
938*fb43630cSZhang Yubing 		return ret;
939*fb43630cSZhang Yubing 
940*fb43630cSZhang Yubing 	ret = dw_dp_link_train(dp);
941*fb43630cSZhang Yubing 	if (ret < 0) {
942*fb43630cSZhang Yubing 		dev_err(dp->dev, "link training failed: %d\n", ret);
943*fb43630cSZhang Yubing 		return ret;
944*fb43630cSZhang Yubing 	}
945*fb43630cSZhang Yubing 
946*fb43630cSZhang Yubing 	return 0;
947*fb43630cSZhang Yubing }
948*fb43630cSZhang Yubing 
949*fb43630cSZhang Yubing static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp)
950*fb43630cSZhang Yubing {
951*fb43630cSZhang Yubing 	const u8 *payload = sdp->db;
952*fb43630cSZhang Yubing 	u32 reg;
953*fb43630cSZhang Yubing 	int i, nr = 0;
954*fb43630cSZhang Yubing 
955*fb43630cSZhang Yubing 	reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4;
956*fb43630cSZhang Yubing 
957*fb43630cSZhang Yubing 	/* SDP header */
958*fb43630cSZhang Yubing 	regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header));
959*fb43630cSZhang Yubing 
960*fb43630cSZhang Yubing 	/* SDP data payload */
961*fb43630cSZhang Yubing 	for (i = 1; i < 9; i++, payload += 4)
962*fb43630cSZhang Yubing 		regmap_write(dp->regmap, reg + i * 4,
963*fb43630cSZhang Yubing 			     FIELD_PREP(SDP_REGS, get_unaligned_le32(payload)));
964*fb43630cSZhang Yubing 
965*fb43630cSZhang Yubing 	if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL)
966*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL,
967*fb43630cSZhang Yubing 				   EN_VERTICAL_SDP << nr,
968*fb43630cSZhang Yubing 				   EN_VERTICAL_SDP << nr);
969*fb43630cSZhang Yubing 
970*fb43630cSZhang Yubing 	if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL)
971*fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL,
972*fb43630cSZhang Yubing 				   EN_HORIZONTAL_SDP << nr,
973*fb43630cSZhang Yubing 				   EN_HORIZONTAL_SDP << nr);
974*fb43630cSZhang Yubing 
975*fb43630cSZhang Yubing 	return 0;
976*fb43630cSZhang Yubing }
977*fb43630cSZhang Yubing 
978*fb43630cSZhang Yubing static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
979*fb43630cSZhang Yubing 			       struct dw_dp_sdp *sdp)
980*fb43630cSZhang Yubing {
981*fb43630cSZhang Yubing 	sdp->header.HB0 = 0;
982*fb43630cSZhang Yubing 	sdp->header.HB1 = DP_SDP_VSC;
983*fb43630cSZhang Yubing 	sdp->header.HB2 = vsc->revision;
984*fb43630cSZhang Yubing 	sdp->header.HB3 = vsc->length;
985*fb43630cSZhang Yubing 
986*fb43630cSZhang Yubing 	sdp->db[16] = (vsc->pixelformat & 0xf) << 4;
987*fb43630cSZhang Yubing 	sdp->db[16] |= vsc->colorimetry & 0xf;
988*fb43630cSZhang Yubing 
989*fb43630cSZhang Yubing 	switch (vsc->bpc) {
990*fb43630cSZhang Yubing 	case 8:
991*fb43630cSZhang Yubing 		sdp->db[17] = 0x1;
992*fb43630cSZhang Yubing 		break;
993*fb43630cSZhang Yubing 	case 10:
994*fb43630cSZhang Yubing 		sdp->db[17] = 0x2;
995*fb43630cSZhang Yubing 		break;
996*fb43630cSZhang Yubing 	case 12:
997*fb43630cSZhang Yubing 		sdp->db[17] = 0x3;
998*fb43630cSZhang Yubing 		break;
999*fb43630cSZhang Yubing 	case 16:
1000*fb43630cSZhang Yubing 		sdp->db[17] = 0x4;
1001*fb43630cSZhang Yubing 		break;
1002*fb43630cSZhang Yubing 	case 6:
1003*fb43630cSZhang Yubing 	default:
1004*fb43630cSZhang Yubing 		break;
1005*fb43630cSZhang Yubing 	}
1006*fb43630cSZhang Yubing 
1007*fb43630cSZhang Yubing 	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
1008*fb43630cSZhang Yubing 		sdp->db[17] |= 0x80;
1009*fb43630cSZhang Yubing 
1010*fb43630cSZhang Yubing 	sdp->db[18] = vsc->content_type & 0x7;
1011*fb43630cSZhang Yubing 
1012*fb43630cSZhang Yubing 	sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL;
1013*fb43630cSZhang Yubing }
1014*fb43630cSZhang Yubing 
1015*fb43630cSZhang Yubing static int dw_dp_send_vsc_sdp(struct dw_dp *dp)
1016*fb43630cSZhang Yubing {
1017*fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1018*fb43630cSZhang Yubing 	struct drm_dp_vsc_sdp vsc = {};
1019*fb43630cSZhang Yubing 	struct dw_dp_sdp sdp = {};
1020*fb43630cSZhang Yubing 
1021*fb43630cSZhang Yubing 	vsc.revision = 0x5;
1022*fb43630cSZhang Yubing 	vsc.length = 0x13;
1023*fb43630cSZhang Yubing 
1024*fb43630cSZhang Yubing 	switch (video->color_format) {
1025*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1026*fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV444;
1027*fb43630cSZhang Yubing 		break;
1028*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1029*fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV420;
1030*fb43630cSZhang Yubing 		break;
1031*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1032*fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV422;
1033*fb43630cSZhang Yubing 		break;
1034*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1035*fb43630cSZhang Yubing 	default:
1036*fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_RGB;
1037*fb43630cSZhang Yubing 		break;
1038*fb43630cSZhang Yubing 	}
1039*fb43630cSZhang Yubing 
1040*fb43630cSZhang Yubing 	if (video->color_format == DRM_COLOR_FORMAT_RGB444)
1041*fb43630cSZhang Yubing 		vsc.colorimetry = DP_COLORIMETRY_DEFAULT;
1042*fb43630cSZhang Yubing 	else
1043*fb43630cSZhang Yubing 		vsc.colorimetry = DP_COLORIMETRY_BT709_YCC;
1044*fb43630cSZhang Yubing 
1045*fb43630cSZhang Yubing 	vsc.bpc = video->bpc;
1046*fb43630cSZhang Yubing 	vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA;
1047*fb43630cSZhang Yubing 	vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED;
1048*fb43630cSZhang Yubing 
1049*fb43630cSZhang Yubing 	dw_dp_vsc_sdp_pack(&vsc, &sdp);
1050*fb43630cSZhang Yubing 
1051*fb43630cSZhang Yubing 	return dw_dp_send_sdp(dp, &sdp);
1052*fb43630cSZhang Yubing }
1053*fb43630cSZhang Yubing 
1054*fb43630cSZhang Yubing static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode)
1055*fb43630cSZhang Yubing {
1056*fb43630cSZhang Yubing 	switch (pixel_mode) {
1057*fb43630cSZhang Yubing 	case DPTX_MP_SINGLE_PIXEL:
1058*fb43630cSZhang Yubing 	case DPTX_MP_DUAL_PIXEL:
1059*fb43630cSZhang Yubing 	case DPTX_MP_QUAD_PIXEL:
1060*fb43630cSZhang Yubing 		break;
1061*fb43630cSZhang Yubing 	default:
1062*fb43630cSZhang Yubing 		return -EINVAL;
1063*fb43630cSZhang Yubing 	}
1064*fb43630cSZhang Yubing 
1065*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT,
1066*fb43630cSZhang Yubing 			   FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode));
1067*fb43630cSZhang Yubing 
1068*fb43630cSZhang Yubing 	return 0;
1069*fb43630cSZhang Yubing }
1070*fb43630cSZhang Yubing 
1071*fb43630cSZhang Yubing static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc,
1072*fb43630cSZhang Yubing 			       u16 vstart, u16 hstart)
1073*fb43630cSZhang Yubing {
1074*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1075*fb43630cSZhang Yubing 	u16 misc = 0;
1076*fb43630cSZhang Yubing 
1077*fb43630cSZhang Yubing 	if (link->vsc_sdp_extension_for_colorimetry_supported)
1078*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_VSC_SDP;
1079*fb43630cSZhang Yubing 
1080*fb43630cSZhang Yubing 	switch (color_format) {
1081*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1082*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_RGB;
1083*fb43630cSZhang Yubing 		break;
1084*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1085*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709;
1086*fb43630cSZhang Yubing 		break;
1087*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1088*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709;
1089*fb43630cSZhang Yubing 		break;
1090*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1091*fb43630cSZhang Yubing 		break;
1092*fb43630cSZhang Yubing 	default:
1093*fb43630cSZhang Yubing 		return -EINVAL;
1094*fb43630cSZhang Yubing 	}
1095*fb43630cSZhang Yubing 
1096*fb43630cSZhang Yubing 	switch (bpc) {
1097*fb43630cSZhang Yubing 	case 6:
1098*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_6_BPC;
1099*fb43630cSZhang Yubing 		break;
1100*fb43630cSZhang Yubing 	case 8:
1101*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_8_BPC;
1102*fb43630cSZhang Yubing 		break;
1103*fb43630cSZhang Yubing 	case 10:
1104*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_10_BPC;
1105*fb43630cSZhang Yubing 		break;
1106*fb43630cSZhang Yubing 	case 12:
1107*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_12_BPC;
1108*fb43630cSZhang Yubing 		break;
1109*fb43630cSZhang Yubing 	case 16:
1110*fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_16_BPC;
1111*fb43630cSZhang Yubing 		break;
1112*fb43630cSZhang Yubing 	default:
1113*fb43630cSZhang Yubing 		return -EINVAL;
1114*fb43630cSZhang Yubing 	}
1115*fb43630cSZhang Yubing 
1116*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA1,
1117*fb43630cSZhang Yubing 		     FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart));
1118*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc));
1119*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8));
1120*fb43630cSZhang Yubing 
1121*fb43630cSZhang Yubing 	return 0;
1122*fb43630cSZhang Yubing }
1123*fb43630cSZhang Yubing 
1124*fb43630cSZhang Yubing static int dw_dp_video_enable(struct dw_dp *dp)
1125*fb43630cSZhang Yubing {
1126*fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1127*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1128*fb43630cSZhang Yubing 	struct drm_display_mode *mode = &video->mode;
1129*fb43630cSZhang Yubing 	u8 color_format = video->color_format;
1130*fb43630cSZhang Yubing 	u8 bpc = video->bpc;
1131*fb43630cSZhang Yubing 	u8 pixel_mode = video->pixel_mode;
1132*fb43630cSZhang Yubing 	u8 bpp = video->bpp, init_threshold, vic;
1133*fb43630cSZhang Yubing 	u32 hactive, hblank, h_sync_width, h_front_porch;
1134*fb43630cSZhang Yubing 	u32 vactive, vblank, v_sync_width, v_front_porch;
1135*fb43630cSZhang Yubing 	u32 vstart = mode->vtotal - mode->vsync_start;
1136*fb43630cSZhang Yubing 	u32 hstart = mode->htotal - mode->hsync_start;
1137*fb43630cSZhang Yubing 	u32 peak_stream_bandwidth, link_bandwidth;
1138*fb43630cSZhang Yubing 	u32 average_bytes_per_tu, average_bytes_per_tu_frac;
1139*fb43630cSZhang Yubing 	u32 ts, hblank_interval;
1140*fb43630cSZhang Yubing 	u32 value;
1141*fb43630cSZhang Yubing 	int ret;
1142*fb43630cSZhang Yubing 
1143*fb43630cSZhang Yubing 	ret = dw_dp_video_set_pixel_mode(dp, pixel_mode);
1144*fb43630cSZhang Yubing 	if (ret)
1145*fb43630cSZhang Yubing 		return ret;
1146*fb43630cSZhang Yubing 
1147*fb43630cSZhang Yubing 	ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart);
1148*fb43630cSZhang Yubing 	if (ret)
1149*fb43630cSZhang Yubing 		return ret;
1150*fb43630cSZhang Yubing 
1151*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING,
1152*fb43630cSZhang Yubing 			   FIELD_PREP(VIDEO_MAPPING, video->video_mapping));
1153*fb43630cSZhang Yubing 
1154*fb43630cSZhang Yubing 	/* Configure DPTX_VINPUT_POLARITY_CTRL register */
1155*fb43630cSZhang Yubing 	value = 0;
1156*fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1157*fb43630cSZhang Yubing 		value |= FIELD_PREP(HSYNC_IN_POLARITY, 1);
1158*fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1159*fb43630cSZhang Yubing 		value |= FIELD_PREP(VSYNC_IN_POLARITY, 1);
1160*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value);
1161*fb43630cSZhang Yubing 
1162*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG1 register */
1163*fb43630cSZhang Yubing 	hactive = mode->hdisplay;
1164*fb43630cSZhang Yubing 	hblank = mode->htotal - mode->hdisplay;
1165*fb43630cSZhang Yubing 	value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank);
1166*fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1167*fb43630cSZhang Yubing 		value |= FIELD_PREP(I_P, 1);
1168*fb43630cSZhang Yubing 	vic = drm_match_cea_mode(mode);
1169*fb43630cSZhang Yubing 	if (vic == 5 || vic == 6 || vic == 7 ||
1170*fb43630cSZhang Yubing 	    vic == 10 || vic == 11 || vic == 20 ||
1171*fb43630cSZhang Yubing 	    vic == 21 || vic == 22 || vic == 39 ||
1172*fb43630cSZhang Yubing 	    vic == 25 || vic == 26 || vic == 40 ||
1173*fb43630cSZhang Yubing 	    vic == 44 || vic == 45 || vic == 46 ||
1174*fb43630cSZhang Yubing 	    vic == 50 || vic == 51 || vic == 54 ||
1175*fb43630cSZhang Yubing 	    vic == 55 || vic == 58 || vic  == 59)
1176*fb43630cSZhang Yubing 		value |= R_V_BLANK_IN_OSC;
1177*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value);
1178*fb43630cSZhang Yubing 
1179*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG2 register */
1180*fb43630cSZhang Yubing 	vblank = mode->vtotal - mode->vdisplay;
1181*fb43630cSZhang Yubing 	vactive = mode->vdisplay;
1182*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2,
1183*fb43630cSZhang Yubing 		     FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive));
1184*fb43630cSZhang Yubing 
1185*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG3 register */
1186*fb43630cSZhang Yubing 	h_sync_width = mode->hsync_end - mode->hsync_start;
1187*fb43630cSZhang Yubing 	h_front_porch = mode->hsync_start - mode->hdisplay;
1188*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3,
1189*fb43630cSZhang Yubing 		     FIELD_PREP(H_SYNC_WIDTH, h_sync_width) |
1190*fb43630cSZhang Yubing 		     FIELD_PREP(H_FRONT_PORCH, h_front_porch));
1191*fb43630cSZhang Yubing 
1192*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG4 register */
1193*fb43630cSZhang Yubing 	v_sync_width = mode->vsync_end - mode->vsync_start;
1194*fb43630cSZhang Yubing 	v_front_porch = mode->vsync_start - mode->vdisplay;
1195*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4,
1196*fb43630cSZhang Yubing 		     FIELD_PREP(V_SYNC_WIDTH, v_sync_width) |
1197*fb43630cSZhang Yubing 		     FIELD_PREP(V_FRONT_PORCH, v_front_porch));
1198*fb43630cSZhang Yubing 
1199*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG5 register */
1200*fb43630cSZhang Yubing 	peak_stream_bandwidth = mode->clock * bpp / 8;
1201*fb43630cSZhang Yubing 	link_bandwidth = (link->rate / 1000) * link->lanes;
1202*fb43630cSZhang Yubing 	ts = peak_stream_bandwidth * 64 / link_bandwidth;
1203*fb43630cSZhang Yubing 	average_bytes_per_tu = ts / 1000;
1204*fb43630cSZhang Yubing 	average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10;
1205*fb43630cSZhang Yubing 	if (pixel_mode == DPTX_MP_SINGLE_PIXEL) {
1206*fb43630cSZhang Yubing 		if (average_bytes_per_tu < 6)
1207*fb43630cSZhang Yubing 			init_threshold = 32;
1208*fb43630cSZhang Yubing 		else if (hblank <= 80 &&
1209*fb43630cSZhang Yubing 			 color_format != DRM_COLOR_FORMAT_YCRCB420)
1210*fb43630cSZhang Yubing 			init_threshold = 12;
1211*fb43630cSZhang Yubing 		else if (hblank <= 40 &&
1212*fb43630cSZhang Yubing 			 color_format == DRM_COLOR_FORMAT_YCRCB420)
1213*fb43630cSZhang Yubing 			init_threshold = 3;
1214*fb43630cSZhang Yubing 		else
1215*fb43630cSZhang Yubing 			init_threshold = 16;
1216*fb43630cSZhang Yubing 	} else {
1217*fb43630cSZhang Yubing 		u32 t1 = 0, t2 = 0, t3 = 0;
1218*fb43630cSZhang Yubing 
1219*fb43630cSZhang Yubing 		switch (bpc) {
1220*fb43630cSZhang Yubing 		case 6:
1221*fb43630cSZhang Yubing 			t1 = (4 * 1000 / 9) * link->lanes;
1222*fb43630cSZhang Yubing 			break;
1223*fb43630cSZhang Yubing 		case 8:
1224*fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1225*fb43630cSZhang Yubing 				t1 = (1000 / 2) * link->lanes;
1226*fb43630cSZhang Yubing 			} else {
1227*fb43630cSZhang Yubing 				if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1228*fb43630cSZhang Yubing 					t1 = (1000 / 3) * link->lanes;
1229*fb43630cSZhang Yubing 				else
1230*fb43630cSZhang Yubing 					t1 = (3000 / 16) * link->lanes;
1231*fb43630cSZhang Yubing 			}
1232*fb43630cSZhang Yubing 			break;
1233*fb43630cSZhang Yubing 		case 10:
1234*fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422)
1235*fb43630cSZhang Yubing 				t1 = (2000 / 5) * link->lanes;
1236*fb43630cSZhang Yubing 			else
1237*fb43630cSZhang Yubing 				t1 = (4000 / 15) * link->lanes;
1238*fb43630cSZhang Yubing 			break;
1239*fb43630cSZhang Yubing 		case 12:
1240*fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1241*fb43630cSZhang Yubing 				if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1242*fb43630cSZhang Yubing 					t1 = (1000 / 6) * link->lanes;
1243*fb43630cSZhang Yubing 				else
1244*fb43630cSZhang Yubing 					t1 = (1000 / 3) * link->lanes;
1245*fb43630cSZhang Yubing 			} else {
1246*fb43630cSZhang Yubing 				t1 = (2000 / 9) * link->lanes;
1247*fb43630cSZhang Yubing 			}
1248*fb43630cSZhang Yubing 			break;
1249*fb43630cSZhang Yubing 		case 16:
1250*fb43630cSZhang Yubing 			if (color_format != DRM_COLOR_FORMAT_YCRCB422 &&
1251*fb43630cSZhang Yubing 			    pixel_mode == DPTX_MP_DUAL_PIXEL)
1252*fb43630cSZhang Yubing 				t1 = (1000 / 6) * link->lanes;
1253*fb43630cSZhang Yubing 			else
1254*fb43630cSZhang Yubing 				t1 = (1000 / 4) * link->lanes;
1255*fb43630cSZhang Yubing 			break;
1256*fb43630cSZhang Yubing 		default:
1257*fb43630cSZhang Yubing 			return -EINVAL;
1258*fb43630cSZhang Yubing 		}
1259*fb43630cSZhang Yubing 
1260*fb43630cSZhang Yubing 		if (color_format == DRM_COLOR_FORMAT_YCRCB420)
1261*fb43630cSZhang Yubing 			t2 = (link->rate / 4) * 1000 / (mode->clock / 2);
1262*fb43630cSZhang Yubing 		else
1263*fb43630cSZhang Yubing 			t2 = (link->rate / 4) * 1000 / mode->clock;
1264*fb43630cSZhang Yubing 
1265*fb43630cSZhang Yubing 		if (average_bytes_per_tu_frac)
1266*fb43630cSZhang Yubing 			t3 = average_bytes_per_tu + 1;
1267*fb43630cSZhang Yubing 		else
1268*fb43630cSZhang Yubing 			t3 = average_bytes_per_tu;
1269*fb43630cSZhang Yubing 		init_threshold = t1 * t2 * t3 / (1000 * 1000);
1270*fb43630cSZhang Yubing 		if (init_threshold <= 16 || average_bytes_per_tu < 10)
1271*fb43630cSZhang Yubing 			init_threshold = 40;
1272*fb43630cSZhang Yubing 	}
1273*fb43630cSZhang Yubing 
1274*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5,
1275*fb43630cSZhang Yubing 		     FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) |
1276*fb43630cSZhang Yubing 		     FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC,
1277*fb43630cSZhang Yubing 				average_bytes_per_tu_frac) |
1278*fb43630cSZhang Yubing 		     FIELD_PREP(INIT_THRESHOLD, init_threshold) |
1279*fb43630cSZhang Yubing 		     FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu));
1280*fb43630cSZhang Yubing 
1281*fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_HBLANK_INTERVAL register */
1282*fb43630cSZhang Yubing 	hblank_interval = hblank * (link->rate / 4) / mode->clock;
1283*fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL,
1284*fb43630cSZhang Yubing 		     FIELD_PREP(HBLANK_INTERVAL_EN, 1) |
1285*fb43630cSZhang Yubing 		     FIELD_PREP(HBLANK_INTERVAL, hblank_interval));
1286*fb43630cSZhang Yubing 
1287*fb43630cSZhang Yubing 	/* Video stream enable */
1288*fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,
1289*fb43630cSZhang Yubing 			   FIELD_PREP(VIDEO_STREAM_ENABLE, 1));
1290*fb43630cSZhang Yubing 
1291*fb43630cSZhang Yubing 	if (link->vsc_sdp_extension_for_colorimetry_supported)
1292*fb43630cSZhang Yubing 		dw_dp_send_vsc_sdp(dp);
1293*fb43630cSZhang Yubing 
1294*fb43630cSZhang Yubing 	return 0;
1295*fb43630cSZhang Yubing }
1296*fb43630cSZhang Yubing 
1297*fb43630cSZhang Yubing static bool dw_dp_detect(struct dw_dp *dp)
1298*fb43630cSZhang Yubing {
1299*fb43630cSZhang Yubing 	u32 value;
1300*fb43630cSZhang Yubing 
1301*fb43630cSZhang Yubing 	if (dm_gpio_is_valid(&dp->hpd_gpio))
1302*fb43630cSZhang Yubing 		return dm_gpio_get_value(&dp->hpd_gpio);
1303*fb43630cSZhang Yubing 
1304*fb43630cSZhang Yubing 	regmap_read(dp->regmap, DPTX_GENERAL_INTERRUPT, &value);
1305*fb43630cSZhang Yubing 	if (value & HPD_EVENT) {
1306*fb43630cSZhang Yubing 		regmap_read(dp->regmap, DPTX_HPD_STATUS, &value);
1307*fb43630cSZhang Yubing 		if ((value & HPD_HOT_PLUG) &&
1308*fb43630cSZhang Yubing 		    (FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG)) {
1309*fb43630cSZhang Yubing 			regmap_write(dp->regmap, DPTX_HPD_STATUS, HPD_HOT_PLUG);
1310*fb43630cSZhang Yubing 			return true;
1311*fb43630cSZhang Yubing 		}
1312*fb43630cSZhang Yubing 	}
1313*fb43630cSZhang Yubing 
1314*fb43630cSZhang Yubing 	return false;
1315*fb43630cSZhang Yubing }
1316*fb43630cSZhang Yubing 
1317*fb43630cSZhang Yubing static int dw_dp_connector_pre_init(struct display_state *state)
1318*fb43630cSZhang Yubing {
1319*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1320*fb43630cSZhang Yubing 
1321*fb43630cSZhang Yubing 	conn_state->type = DRM_MODE_CONNECTOR_DisplayPort;
1322*fb43630cSZhang Yubing 
1323*fb43630cSZhang Yubing 	return 0;
1324*fb43630cSZhang Yubing }
1325*fb43630cSZhang Yubing 
1326*fb43630cSZhang Yubing static int dw_dp_connector_init(struct display_state *state)
1327*fb43630cSZhang Yubing {
1328*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1329*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(conn_state->dev);
1330*fb43630cSZhang Yubing 	int ret;
1331*fb43630cSZhang Yubing 
1332*fb43630cSZhang Yubing 	conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0;
1333*fb43630cSZhang Yubing 	conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1334*fb43630cSZhang Yubing 	conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
1335*fb43630cSZhang Yubing 
1336*fb43630cSZhang Yubing 	clk_set_defaults(dp->dev);
1337*fb43630cSZhang Yubing 
1338*fb43630cSZhang Yubing 	reset_assert(&dp->reset);
1339*fb43630cSZhang Yubing 	udelay(20);
1340*fb43630cSZhang Yubing 	reset_deassert(&dp->reset);
1341*fb43630cSZhang Yubing 
1342*fb43630cSZhang Yubing 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type,
1343*fb43630cSZhang Yubing 							dp->id);
1344*fb43630cSZhang Yubing 	dw_dp_init(dp);
1345*fb43630cSZhang Yubing 	ret = generic_phy_power_on(&dp->phy);
1346*fb43630cSZhang Yubing 
1347*fb43630cSZhang Yubing 	return ret;
1348*fb43630cSZhang Yubing }
1349*fb43630cSZhang Yubing 
1350*fb43630cSZhang Yubing static int dw_dp_connector_get_edid(struct display_state *state)
1351*fb43630cSZhang Yubing {
1352*fb43630cSZhang Yubing 	int ret;
1353*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1354*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(conn_state->dev);
1355*fb43630cSZhang Yubing 
1356*fb43630cSZhang Yubing 	ret = drm_do_get_edid(&dp->aux.ddc, conn_state->edid);
1357*fb43630cSZhang Yubing 
1358*fb43630cSZhang Yubing 	return ret;
1359*fb43630cSZhang Yubing }
1360*fb43630cSZhang Yubing 
1361*fb43630cSZhang Yubing static int dw_dp_connector_enable(struct display_state *state)
1362*fb43630cSZhang Yubing {
1363*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1364*fb43630cSZhang Yubing 	struct drm_display_mode *mode = &conn_state->mode;
1365*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(conn_state->dev);
1366*fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1367*fb43630cSZhang Yubing 	int ret;
1368*fb43630cSZhang Yubing 
1369*fb43630cSZhang Yubing 	memcpy(&video->mode, mode, sizeof(video->mode));
1370*fb43630cSZhang Yubing 	video->pixel_mode = DPTX_MP_QUAD_PIXEL;
1371*fb43630cSZhang Yubing 
1372*fb43630cSZhang Yubing 	ret = dw_dp_link_enable(dp);
1373*fb43630cSZhang Yubing 	if (ret < 0) {
1374*fb43630cSZhang Yubing 		dev_err(dp->dev, "failed to enable link: %d\n", ret);
1375*fb43630cSZhang Yubing 		return ret;
1376*fb43630cSZhang Yubing 	}
1377*fb43630cSZhang Yubing 
1378*fb43630cSZhang Yubing 	ret = dw_dp_video_enable(dp);
1379*fb43630cSZhang Yubing 	if (ret < 0) {
1380*fb43630cSZhang Yubing 		dev_err(dp->dev, "failed to enable video: %d\n", ret);
1381*fb43630cSZhang Yubing 		return ret;
1382*fb43630cSZhang Yubing 	}
1383*fb43630cSZhang Yubing 
1384*fb43630cSZhang Yubing 	return 0;
1385*fb43630cSZhang Yubing }
1386*fb43630cSZhang Yubing 
1387*fb43630cSZhang Yubing static int dw_dp_connector_disable(struct display_state *state)
1388*fb43630cSZhang Yubing {
1389*fb43630cSZhang Yubing 	/* TODO */
1390*fb43630cSZhang Yubing 
1391*fb43630cSZhang Yubing 	return 0;
1392*fb43630cSZhang Yubing }
1393*fb43630cSZhang Yubing 
1394*fb43630cSZhang Yubing static int dw_dp_connector_detect(struct display_state *state)
1395*fb43630cSZhang Yubing {
1396*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1397*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(conn_state->dev);
1398*fb43630cSZhang Yubing 	int status, tries;
1399*fb43630cSZhang Yubing 
1400*fb43630cSZhang Yubing 	for (tries = 0; tries < 100; tries++) {
1401*fb43630cSZhang Yubing 		status = dw_dp_detect(dp);
1402*fb43630cSZhang Yubing 		if (status)
1403*fb43630cSZhang Yubing 			break;
1404*fb43630cSZhang Yubing 		mdelay(2);
1405*fb43630cSZhang Yubing 	}
1406*fb43630cSZhang Yubing 
1407*fb43630cSZhang Yubing 	if (!status)
1408*fb43630cSZhang Yubing 		generic_phy_power_off(&dp->phy);
1409*fb43630cSZhang Yubing 
1410*fb43630cSZhang Yubing 	return status;
1411*fb43630cSZhang Yubing }
1412*fb43630cSZhang Yubing 
1413*fb43630cSZhang Yubing static int dw_dp_mode_valid(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1414*fb43630cSZhang Yubing {
1415*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1416*fb43630cSZhang Yubing 	struct drm_display_info *di = &edid_data->display_info;
1417*fb43630cSZhang Yubing 	u32 min_bpp;
1418*fb43630cSZhang Yubing 	int i;
1419*fb43630cSZhang Yubing 
1420*fb43630cSZhang Yubing 	if (di->color_formats & DRM_COLOR_FORMAT_YCRCB420 &&
1421*fb43630cSZhang Yubing 	    link->vsc_sdp_extension_for_colorimetry_supported)
1422*fb43630cSZhang Yubing 		min_bpp = 12;
1423*fb43630cSZhang Yubing 	else if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1424*fb43630cSZhang Yubing 		min_bpp = 16;
1425*fb43630cSZhang Yubing 	else if (di->color_formats & DRM_COLOR_FORMAT_RGB444)
1426*fb43630cSZhang Yubing 		min_bpp = 18;
1427*fb43630cSZhang Yubing 	else
1428*fb43630cSZhang Yubing 		min_bpp = 24;
1429*fb43630cSZhang Yubing 
1430*fb43630cSZhang Yubing 	for (i = 0; i < edid_data->modes; i++) {
1431*fb43630cSZhang Yubing 		if (!dw_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, link->lanes,
1432*fb43630cSZhang Yubing 					link->rate))
1433*fb43630cSZhang Yubing 			edid_data->mode_buf[i].invalid = true;
1434*fb43630cSZhang Yubing 	}
1435*fb43630cSZhang Yubing 
1436*fb43630cSZhang Yubing 	return 0;
1437*fb43630cSZhang Yubing }
1438*fb43630cSZhang Yubing 
1439*fb43630cSZhang Yubing static u32 dw_dp_get_output_bus_fmts(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1440*fb43630cSZhang Yubing {
1441*fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1442*fb43630cSZhang Yubing 	unsigned int i;
1443*fb43630cSZhang Yubing 
1444*fb43630cSZhang Yubing 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
1445*fb43630cSZhang Yubing 		const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
1446*fb43630cSZhang Yubing 
1447*fb43630cSZhang Yubing 		if (fmt->bpc > edid_data->display_info.bpc)
1448*fb43630cSZhang Yubing 			continue;
1449*fb43630cSZhang Yubing 
1450*fb43630cSZhang Yubing 		if (!(edid_data->display_info.color_formats & fmt->color_format))
1451*fb43630cSZhang Yubing 			continue;
1452*fb43630cSZhang Yubing 
1453*fb43630cSZhang Yubing 		if (fmt->color_format == DRM_COLOR_FORMAT_YCRCB420 &&
1454*fb43630cSZhang Yubing 		    !link->vsc_sdp_extension_for_colorimetry_supported)
1455*fb43630cSZhang Yubing 			continue;
1456*fb43630cSZhang Yubing 
1457*fb43630cSZhang Yubing 		if (drm_mode_is_420(&edid_data->display_info, edid_data->preferred_mode) &&
1458*fb43630cSZhang Yubing 		    fmt->color_format != DRM_COLOR_FORMAT_YCRCB420)
1459*fb43630cSZhang Yubing 			continue;
1460*fb43630cSZhang Yubing 
1461*fb43630cSZhang Yubing 		if (!dw_dp_bandwidth_ok(dp, edid_data->preferred_mode, fmt->bpp, link->lanes,
1462*fb43630cSZhang Yubing 					link->rate))
1463*fb43630cSZhang Yubing 			continue;
1464*fb43630cSZhang Yubing 
1465*fb43630cSZhang Yubing 		break;
1466*fb43630cSZhang Yubing 	}
1467*fb43630cSZhang Yubing 
1468*fb43630cSZhang Yubing 	if (i == ARRAY_SIZE(possible_output_fmts))
1469*fb43630cSZhang Yubing 		return 1;
1470*fb43630cSZhang Yubing 
1471*fb43630cSZhang Yubing 	return i;
1472*fb43630cSZhang Yubing }
1473*fb43630cSZhang Yubing 
1474*fb43630cSZhang Yubing static int dw_dp_get_force_output_fmts(struct display_state *state)
1475*fb43630cSZhang Yubing {
1476*fb43630cSZhang Yubing 	int i;
1477*fb43630cSZhang Yubing 
1478*fb43630cSZhang Yubing 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
1479*fb43630cSZhang Yubing 		const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
1480*fb43630cSZhang Yubing 
1481*fb43630cSZhang Yubing 		if (fmt->bus_format == state->force_bus_format)
1482*fb43630cSZhang Yubing 			break;
1483*fb43630cSZhang Yubing 	}
1484*fb43630cSZhang Yubing 
1485*fb43630cSZhang Yubing 	if (i == ARRAY_SIZE(possible_output_fmts))
1486*fb43630cSZhang Yubing 		return 1;
1487*fb43630cSZhang Yubing 
1488*fb43630cSZhang Yubing 	return i;
1489*fb43630cSZhang Yubing }
1490*fb43630cSZhang Yubing 
1491*fb43630cSZhang Yubing static int dw_dp_connector_get_timing(struct display_state *state)
1492*fb43630cSZhang Yubing {
1493*fb43630cSZhang Yubing 	int ret, i;
1494*fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1495*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(conn_state->dev);
1496*fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1497*fb43630cSZhang Yubing 	struct drm_display_mode *mode = &conn_state->mode;
1498*fb43630cSZhang Yubing 	struct hdmi_edid_data edid_data;
1499*fb43630cSZhang Yubing 	struct drm_display_mode *mode_buf;
1500*fb43630cSZhang Yubing 	u32 bus_fmt;
1501*fb43630cSZhang Yubing 
1502*fb43630cSZhang Yubing 	mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
1503*fb43630cSZhang Yubing 	if (!mode_buf)
1504*fb43630cSZhang Yubing 		return -ENOMEM;
1505*fb43630cSZhang Yubing 
1506*fb43630cSZhang Yubing 	memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
1507*fb43630cSZhang Yubing 	memset(&edid_data, 0, sizeof(struct hdmi_edid_data));
1508*fb43630cSZhang Yubing 	edid_data.mode_buf = mode_buf;
1509*fb43630cSZhang Yubing 
1510*fb43630cSZhang Yubing 	ret = drm_do_get_edid(&dp->aux.ddc, conn_state->edid);
1511*fb43630cSZhang Yubing 	if (!ret)
1512*fb43630cSZhang Yubing 		ret = drm_add_edid_modes(&edid_data, conn_state->edid);
1513*fb43630cSZhang Yubing 
1514*fb43630cSZhang Yubing 	if (ret < 0) {
1515*fb43630cSZhang Yubing 		printf("failed to get edid\n");
1516*fb43630cSZhang Yubing 		goto err;
1517*fb43630cSZhang Yubing 	}
1518*fb43630cSZhang Yubing 
1519*fb43630cSZhang Yubing 	ret = dw_dp_link_probe(dp);
1520*fb43630cSZhang Yubing 	if (ret) {
1521*fb43630cSZhang Yubing 		printf("failed to probe DP link: %d\n", ret);
1522*fb43630cSZhang Yubing 		ret = -EINVAL;
1523*fb43630cSZhang Yubing 		goto err;
1524*fb43630cSZhang Yubing 	}
1525*fb43630cSZhang Yubing 
1526*fb43630cSZhang Yubing 	drm_rk_filter_whitelist(&edid_data);
1527*fb43630cSZhang Yubing 	drm_mode_max_resolution_filter(&edid_data,
1528*fb43630cSZhang Yubing 				       &state->crtc_state.max_output);
1529*fb43630cSZhang Yubing 	dw_dp_mode_valid(dp, &edid_data);
1530*fb43630cSZhang Yubing 
1531*fb43630cSZhang Yubing 	if (!drm_mode_prune_invalid(&edid_data)) {
1532*fb43630cSZhang Yubing 		printf("can't find valid hdmi mode\n");
1533*fb43630cSZhang Yubing 		ret = -EINVAL;
1534*fb43630cSZhang Yubing 		goto err;
1535*fb43630cSZhang Yubing 	}
1536*fb43630cSZhang Yubing 
1537*fb43630cSZhang Yubing 	for (i = 0; i < edid_data.modes; i++)
1538*fb43630cSZhang Yubing 		edid_data.mode_buf[i].vrefresh =
1539*fb43630cSZhang Yubing 			drm_mode_vrefresh(&edid_data.mode_buf[i]);
1540*fb43630cSZhang Yubing 
1541*fb43630cSZhang Yubing 	drm_mode_sort(&edid_data);
1542*fb43630cSZhang Yubing 	memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode));
1543*fb43630cSZhang Yubing 
1544*fb43630cSZhang Yubing 	if (state->force_output)
1545*fb43630cSZhang Yubing 		bus_fmt = dw_dp_get_force_output_fmts(state);
1546*fb43630cSZhang Yubing 	else
1547*fb43630cSZhang Yubing 		bus_fmt = dw_dp_get_output_bus_fmts(dp, &edid_data);
1548*fb43630cSZhang Yubing 
1549*fb43630cSZhang Yubing 	video->video_mapping = possible_output_fmts[bus_fmt].video_mapping;
1550*fb43630cSZhang Yubing 	video->color_format = possible_output_fmts[bus_fmt].color_format;
1551*fb43630cSZhang Yubing 	video->bus_format = possible_output_fmts[bus_fmt].bus_format;
1552*fb43630cSZhang Yubing 	video->bpc = possible_output_fmts[bus_fmt].bpc;
1553*fb43630cSZhang Yubing 	video->bpp = possible_output_fmts[bus_fmt].bpp;
1554*fb43630cSZhang Yubing 
1555*fb43630cSZhang Yubing 	switch (video->color_format) {
1556*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1557*fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
1558*fb43630cSZhang Yubing 		break;
1559*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1560*fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
1561*fb43630cSZhang Yubing 		break;
1562*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1563*fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1564*fb43630cSZhang Yubing 	default:
1565*fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1566*fb43630cSZhang Yubing 		break;
1567*fb43630cSZhang Yubing 	}
1568*fb43630cSZhang Yubing 
1569*fb43630cSZhang Yubing 	conn_state->bus_format = video->bus_format;
1570*fb43630cSZhang Yubing err:
1571*fb43630cSZhang Yubing 	free(mode_buf);
1572*fb43630cSZhang Yubing 
1573*fb43630cSZhang Yubing 	return 0;
1574*fb43630cSZhang Yubing }
1575*fb43630cSZhang Yubing 
1576*fb43630cSZhang Yubing static const struct rockchip_connector_funcs dw_dp_connector_funcs = {
1577*fb43630cSZhang Yubing 	.pre_init = dw_dp_connector_pre_init,
1578*fb43630cSZhang Yubing 	.init = dw_dp_connector_init,
1579*fb43630cSZhang Yubing 	.get_edid = dw_dp_connector_get_edid,
1580*fb43630cSZhang Yubing 	.enable = dw_dp_connector_enable,
1581*fb43630cSZhang Yubing 	.disable = dw_dp_connector_disable,
1582*fb43630cSZhang Yubing 	.detect = dw_dp_connector_detect,
1583*fb43630cSZhang Yubing 	.get_timing = dw_dp_connector_get_timing,
1584*fb43630cSZhang Yubing };
1585*fb43630cSZhang Yubing 
1586*fb43630cSZhang Yubing static int dw_dp_ddc_init(struct dw_dp *dp)
1587*fb43630cSZhang Yubing {
1588*fb43630cSZhang Yubing 	dp->aux.name = "dw-dp";
1589*fb43630cSZhang Yubing 	dp->aux.dev = dp->dev;
1590*fb43630cSZhang Yubing 	dp->aux.transfer = dw_dp_aux_transfer;
1591*fb43630cSZhang Yubing 	dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer;
1592*fb43630cSZhang Yubing 
1593*fb43630cSZhang Yubing 	return 0;
1594*fb43630cSZhang Yubing }
1595*fb43630cSZhang Yubing 
1596*fb43630cSZhang Yubing static int dw_dp_probe(struct udevice *dev)
1597*fb43630cSZhang Yubing {
1598*fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(dev);
1599*fb43630cSZhang Yubing 	int ret;
1600*fb43630cSZhang Yubing 
1601*fb43630cSZhang Yubing 	ret = regmap_init_mem(dev, &dp->regmap);
1602*fb43630cSZhang Yubing 	if (ret)
1603*fb43630cSZhang Yubing 		return ret;
1604*fb43630cSZhang Yubing 
1605*fb43630cSZhang Yubing 	dp->id = of_alias_get_id(ofnode_to_np(dev->node), "dp");
1606*fb43630cSZhang Yubing 	if (dp->id < 0)
1607*fb43630cSZhang Yubing 		dp->id = 0;
1608*fb43630cSZhang Yubing 
1609*fb43630cSZhang Yubing 	ret = reset_get_by_index(dev, 0, &dp->reset);
1610*fb43630cSZhang Yubing 	if (ret) {
1611*fb43630cSZhang Yubing 		dev_err(dev, "failed to get reset control: %d\n", ret);
1612*fb43630cSZhang Yubing 		return ret;
1613*fb43630cSZhang Yubing 	}
1614*fb43630cSZhang Yubing 
1615*fb43630cSZhang Yubing 	ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio,
1616*fb43630cSZhang Yubing 				   GPIOD_IS_IN);
1617*fb43630cSZhang Yubing 	if (ret && ret != -ENOENT) {
1618*fb43630cSZhang Yubing 		dev_err(dev, "failed to get hpd GPIO: %d\n", ret);
1619*fb43630cSZhang Yubing 		return ret;
1620*fb43630cSZhang Yubing 	}
1621*fb43630cSZhang Yubing 
1622*fb43630cSZhang Yubing 	generic_phy_get_by_index(dev, 0, &dp->phy);
1623*fb43630cSZhang Yubing 
1624*fb43630cSZhang Yubing 	dp->dev = dev;
1625*fb43630cSZhang Yubing 
1626*fb43630cSZhang Yubing 	dw_dp_ddc_init(dp);
1627*fb43630cSZhang Yubing 
1628*fb43630cSZhang Yubing 	return 0;
1629*fb43630cSZhang Yubing }
1630*fb43630cSZhang Yubing 
1631*fb43630cSZhang Yubing static const struct rockchip_connector rk3588_dp_driver_data = {
1632*fb43630cSZhang Yubing 	.funcs = &dw_dp_connector_funcs,
1633*fb43630cSZhang Yubing };
1634*fb43630cSZhang Yubing 
1635*fb43630cSZhang Yubing static const struct udevice_id dw_dp_ids[] = {
1636*fb43630cSZhang Yubing 	{
1637*fb43630cSZhang Yubing 		.compatible = "rockchip,rk3588-dp",
1638*fb43630cSZhang Yubing 		.data = (ulong)&rk3588_dp_driver_data
1639*fb43630cSZhang Yubing 	},
1640*fb43630cSZhang Yubing 	{}
1641*fb43630cSZhang Yubing };
1642*fb43630cSZhang Yubing 
1643*fb43630cSZhang Yubing U_BOOT_DRIVER(dw_dp) = {
1644*fb43630cSZhang Yubing 	.name = "dw_dp",
1645*fb43630cSZhang Yubing 	.id = UCLASS_DISPLAY,
1646*fb43630cSZhang Yubing 	.of_match = dw_dp_ids,
1647*fb43630cSZhang Yubing 	.probe = dw_dp_probe,
1648*fb43630cSZhang Yubing 	.priv_auto_alloc_size = sizeof(struct dw_dp),
1649*fb43630cSZhang Yubing };
1650*fb43630cSZhang Yubing 
1651