xref: /rk3399_rockchip-uboot/drivers/video/drm/dw-dp.c (revision 9c170041dcf97ed3fe5bbd76e70cda2ed3fcbd92)
1fb43630cSZhang Yubing // SPDX-License-Identifier: GPL-2.0-or-later
2fb43630cSZhang Yubing /*
3fb43630cSZhang Yubing  * Rockchip USBDP Combo PHY with Samsung IP block driver
4fb43630cSZhang Yubing  *
5fb43630cSZhang Yubing  * Copyright (C) 2021 Rockchip Electronics Co., Ltd
6fb43630cSZhang Yubing  */
7fb43630cSZhang Yubing 
8fb43630cSZhang Yubing #include <config.h>
9fb43630cSZhang Yubing #include <common.h>
10fb43630cSZhang Yubing #include <errno.h>
11fb43630cSZhang Yubing #include <malloc.h>
12fb43630cSZhang Yubing #include <asm/unaligned.h>
13fb43630cSZhang Yubing #include <asm/io.h>
14fb43630cSZhang Yubing #include <clk.h>
15fb43630cSZhang Yubing #include <dm/device.h>
16fb43630cSZhang Yubing #include <dm/of_access.h>
177ac3c934SZhang Yubing #include <dm/lists.h>
18fb43630cSZhang Yubing #include <dm/read.h>
19fb43630cSZhang Yubing #include <generic-phy.h>
20fb43630cSZhang Yubing #include <linux/bitfield.h>
21fb43630cSZhang Yubing #include <linux/hdmi.h>
22fb43630cSZhang Yubing #include <linux/media-bus-format.h>
23fb43630cSZhang Yubing #include <linux/list.h>
24fb43630cSZhang Yubing #include <asm/gpio.h>
25fb43630cSZhang Yubing #include <generic-phy.h>
26fb43630cSZhang Yubing #include <regmap.h>
27fb43630cSZhang Yubing #include <reset.h>
28fb43630cSZhang Yubing #include <drm/drm_dp_helper.h>
29fb43630cSZhang Yubing 
30fb43630cSZhang Yubing #include "rockchip_display.h"
31fb43630cSZhang Yubing #include "rockchip_crtc.h"
32fb43630cSZhang Yubing #include "rockchip_connector.h"
33fb43630cSZhang Yubing 
34fb43630cSZhang Yubing #define DPTX_VERSION_NUMBER			0x0000
35fb43630cSZhang Yubing #define DPTX_VERSION_TYPE			0x0004
36fb43630cSZhang Yubing #define DPTX_ID					0x0008
37fb43630cSZhang Yubing 
38fb43630cSZhang Yubing #define DPTX_CONFIG_REG1			0x0100
39fb43630cSZhang Yubing #define DPTX_CONFIG_REG2			0x0104
40fb43630cSZhang Yubing #define DPTX_CONFIG_REG3			0x0108
41fb43630cSZhang Yubing 
42fb43630cSZhang Yubing #define DPTX_CCTL				0x0200
43fb43630cSZhang Yubing #define FORCE_HPD				BIT(4)
44fb43630cSZhang Yubing #define DEFAULT_FAST_LINK_TRAIN_EN		BIT(2)
45fb43630cSZhang Yubing #define ENHANCE_FRAMING_EN			BIT(1)
46fb43630cSZhang Yubing #define SCRAMBLE_DIS				BIT(0)
47fb43630cSZhang Yubing #define DPTX_SOFT_RESET_CTRL			0x0204
48fb43630cSZhang Yubing #define VIDEO_RESET				BIT(5)
49fb43630cSZhang Yubing #define AUX_RESET				BIT(4)
50fb43630cSZhang Yubing #define AUDIO_SAMPLER_RESET			BIT(3)
51fb43630cSZhang Yubing #define PHY_SOFT_RESET				BIT(1)
52fb43630cSZhang Yubing #define CONTROLLER_RESET			BIT(0)
53fb43630cSZhang Yubing 
54fb43630cSZhang Yubing #define DPTX_VSAMPLE_CTRL			0x0300
55fb43630cSZhang Yubing #define PIXEL_MODE_SELECT			GENMASK(22, 21)
56fb43630cSZhang Yubing #define VIDEO_MAPPING				GENMASK(20, 16)
57fb43630cSZhang Yubing #define VIDEO_STREAM_ENABLE			BIT(5)
58fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL1		0x0304
59fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL2		0x0308
60fb43630cSZhang Yubing #define DPTX_VINPUT_POLARITY_CTRL		0x030c
61fb43630cSZhang Yubing #define DE_IN_POLARITY				BIT(2)
62fb43630cSZhang Yubing #define HSYNC_IN_POLARITY			BIT(1)
63fb43630cSZhang Yubing #define VSYNC_IN_POLARITY			BIT(0)
64fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG1			0x0310
65fb43630cSZhang Yubing #define HACTIVE					GENMASK(31, 16)
66fb43630cSZhang Yubing #define HBLANK					GENMASK(15, 2)
67fb43630cSZhang Yubing #define I_P					BIT(1)
68fb43630cSZhang Yubing #define R_V_BLANK_IN_OSC			BIT(0)
69fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG2			0x0314
70fb43630cSZhang Yubing #define VBLANK					GENMASK(31, 16)
71fb43630cSZhang Yubing #define VACTIVE					GENMASK(15, 0)
72fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG3			0x0318
73fb43630cSZhang Yubing #define H_SYNC_WIDTH				GENMASK(31, 16)
74fb43630cSZhang Yubing #define H_FRONT_PORCH				GENMASK(15, 0)
75fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG4			0x031c
76fb43630cSZhang Yubing #define V_SYNC_WIDTH				GENMASK(31, 16)
77fb43630cSZhang Yubing #define V_FRONT_PORCH				GENMASK(15, 0)
78fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG5			0x0320
79fb43630cSZhang Yubing #define INIT_THRESHOLD_HI			GENMASK(22, 21)
80fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU_FRAC		GENMASK(19, 16)
81fb43630cSZhang Yubing #define INIT_THRESHOLD				GENMASK(13, 7)
82fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU			GENMASK(6, 0)
83fb43630cSZhang Yubing #define DPTX_VIDEO_MSA1				0x0324
84fb43630cSZhang Yubing #define VSTART					GENMASK(31, 16)
85fb43630cSZhang Yubing #define HSTART					GENMASK(15, 0)
86fb43630cSZhang Yubing #define DPTX_VIDEO_MSA2				0x0328
87fb43630cSZhang Yubing #define MISC0					GENMASK(31, 24)
88fb43630cSZhang Yubing #define DPTX_VIDEO_MSA3				0x032c
89fb43630cSZhang Yubing #define MISC1					GENMASK(31, 24)
90fb43630cSZhang Yubing #define DPTX_VIDEO_HBLANK_INTERVAL		0x0330
91fb43630cSZhang Yubing #define HBLANK_INTERVAL_EN			BIT(16)
92fb43630cSZhang Yubing #define HBLANK_INTERVAL				GENMASK(15, 0)
93fb43630cSZhang Yubing 
94fb43630cSZhang Yubing #define DPTX_AUD_CONFIG1			0x0400
95fb43630cSZhang Yubing #define AUDIO_TIMESTAMP_VERSION_NUM		GENMASK(29, 24)
96fb43630cSZhang Yubing #define AUDIO_PACKET_ID				GENMASK(23, 16)
97fb43630cSZhang Yubing #define AUDIO_MUTE				BIT(15)
98fb43630cSZhang Yubing #define NUM_CHANNELS				GENMASK(14, 12)
99fb43630cSZhang Yubing #define HBR_MODE_ENABLE				BIT(10)
100fb43630cSZhang Yubing #define AUDIO_DATA_WIDTH			GENMASK(9, 5)
101fb43630cSZhang Yubing #define AUDIO_DATA_IN_EN			GENMASK(4, 1)
102fb43630cSZhang Yubing #define AUDIO_INF_SELECT			BIT(0)
103fb43630cSZhang Yubing 
104fb43630cSZhang Yubing #define DPTX_SDP_VERTICAL_CTRL			0x0500
105fb43630cSZhang Yubing #define EN_VERTICAL_SDP				BIT(2)
106fb43630cSZhang Yubing #define EN_AUDIO_STREAM_SDP			BIT(1)
107fb43630cSZhang Yubing #define EN_AUDIO_TIMESTAMP_SDP			BIT(0)
108fb43630cSZhang Yubing #define DPTX_SDP_HORIZONTAL_CTRL		0x0504
109fb43630cSZhang Yubing #define EN_HORIZONTAL_SDP			BIT(2)
110fb43630cSZhang Yubing #define DPTX_SDP_STATUS_REGISTER		0x0508
111fb43630cSZhang Yubing #define DPTX_SDP_MANUAL_CTRL			0x050c
112fb43630cSZhang Yubing #define DPTX_SDP_STATUS_EN			0x0510
113fb43630cSZhang Yubing 
114fb43630cSZhang Yubing #define DPTX_SDP_REGISTER_BANK			0x0600
115fb43630cSZhang Yubing #define SDP_REGS				GENMASK(31, 0)
116fb43630cSZhang Yubing 
117fb43630cSZhang Yubing #define DPTX_PHYIF_CTRL				0x0a00
118fb43630cSZhang Yubing #define PHY_WIDTH				BIT(25)
119fb43630cSZhang Yubing #define PHY_POWERDOWN				GENMASK(20, 17)
120fb43630cSZhang Yubing #define PHY_BUSY				GENMASK(15, 12)
121fb43630cSZhang Yubing #define SSC_DIS					BIT(16)
122fb43630cSZhang Yubing #define XMIT_ENABLE				GENMASK(11, 8)
123fb43630cSZhang Yubing #define PHY_LANES				GENMASK(7, 6)
124fb43630cSZhang Yubing #define PHY_RATE				GENMASK(5, 4)
125fb43630cSZhang Yubing #define TPS_SEL					GENMASK(3, 0)
126fb43630cSZhang Yubing #define DPTX_PHY_TX_EQ				0x0a04
127fb43630cSZhang Yubing #define DPTX_CUSTOMPAT0				0x0a08
128fb43630cSZhang Yubing #define DPTX_CUSTOMPAT1				0x0a0c
129fb43630cSZhang Yubing #define DPTX_CUSTOMPAT2				0x0a10
130fb43630cSZhang Yubing #define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET	0x0a14
131fb43630cSZhang Yubing #define DPTX_PHYIF_PWRDOWN_CTRL			0x0a18
132fb43630cSZhang Yubing 
133fb43630cSZhang Yubing #define DPTX_AUX_CMD				0x0b00
134fb43630cSZhang Yubing #define AUX_CMD_TYPE				GENMASK(31, 28)
135fb43630cSZhang Yubing #define AUX_ADDR				GENMASK(27, 8)
136fb43630cSZhang Yubing #define I2C_ADDR_ONLY				BIT(4)
137fb43630cSZhang Yubing #define AUX_LEN_REQ				GENMASK(3, 0)
138fb43630cSZhang Yubing #define DPTX_AUX_STATUS				0x0b04
139fb43630cSZhang Yubing #define AUX_TIMEOUT				BIT(17)
140fb43630cSZhang Yubing #define AUX_BYTES_READ				GENMASK(23, 19)
141fb43630cSZhang Yubing #define AUX_STATUS				GENMASK(7, 4)
142fb43630cSZhang Yubing #define DPTX_AUX_DATA0				0x0b08
143fb43630cSZhang Yubing #define DPTX_AUX_DATA1				0x0b0c
144fb43630cSZhang Yubing #define DPTX_AUX_DATA2				0x0b10
145fb43630cSZhang Yubing #define DPTX_AUX_DATA3				0x0b14
146fb43630cSZhang Yubing 
147fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT			0x0d00
148fb43630cSZhang Yubing #define VIDEO_FIFO_OVERFLOW_STREAM0		BIT(6)
149fb43630cSZhang Yubing #define AUDIO_FIFO_OVERFLOW_STREAM0		BIT(5)
150fb43630cSZhang Yubing #define SDP_EVENT_STREAM0			BIT(4)
151fb43630cSZhang Yubing #define AUX_CMD_INVALID				BIT(3)
152fb43630cSZhang Yubing #define AUX_REPLY_EVENT				BIT(1)
153fb43630cSZhang Yubing #define HPD_EVENT				BIT(0)
154fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT_ENABLE		0x0d04
155fb43630cSZhang Yubing #define AUX_REPLY_EVENT_EN			BIT(1)
156fb43630cSZhang Yubing #define HPD_EVENT_EN				BIT(0)
157fb43630cSZhang Yubing #define DPTX_HPD_STATUS				0x0d08
158fb43630cSZhang Yubing #define HPD_STATE				GENMASK(11, 9)
159fb43630cSZhang Yubing #define HPD_STATUS				BIT(8)
160fb43630cSZhang Yubing #define HPD_HOT_UNPLUG				BIT(2)
161fb43630cSZhang Yubing #define HPD_HOT_PLUG				BIT(1)
162fb43630cSZhang Yubing #define HPD_IRQ					BIT(0)
163fb43630cSZhang Yubing #define DPTX_HPD_INTERRUPT_ENABLE		0x0d0c
164fb43630cSZhang Yubing #define HPD_UNPLUG_ERR_EN			BIT(3)
165fb43630cSZhang Yubing #define HPD_UNPLUG_EN				BIT(2)
166fb43630cSZhang Yubing #define HPD_PLUG_EN				BIT(1)
167fb43630cSZhang Yubing #define HPD_IRQ_EN				BIT(0)
168fb43630cSZhang Yubing 
169fb43630cSZhang Yubing #define DPTX_MAX_REGISTER			DPTX_HPD_INTERRUPT_ENABLE
170fb43630cSZhang Yubing 
171fb43630cSZhang Yubing #define SDP_REG_BANK_SIZE			16
172fb43630cSZhang Yubing 
173fb43630cSZhang Yubing struct drm_dp_link_caps {
174fb43630cSZhang Yubing 	bool enhanced_framing;
175fb43630cSZhang Yubing 	bool tps3_supported;
176fb43630cSZhang Yubing 	bool tps4_supported;
177fb43630cSZhang Yubing 	bool channel_coding;
178fb43630cSZhang Yubing 	bool ssc;
179fb43630cSZhang Yubing };
180fb43630cSZhang Yubing 
181fb43630cSZhang Yubing struct drm_dp_link_train_set {
182fb43630cSZhang Yubing 	unsigned int voltage_swing[4];
183fb43630cSZhang Yubing 	unsigned int pre_emphasis[4];
184fb43630cSZhang Yubing };
185fb43630cSZhang Yubing 
186fb43630cSZhang Yubing struct drm_dp_link_train {
187fb43630cSZhang Yubing 	struct drm_dp_link_train_set request;
188fb43630cSZhang Yubing 	struct drm_dp_link_train_set adjust;
189fb43630cSZhang Yubing 	bool clock_recovered;
190fb43630cSZhang Yubing 	bool channel_equalized;
191fb43630cSZhang Yubing };
192fb43630cSZhang Yubing 
193fb43630cSZhang Yubing struct dw_dp_link {
194fb43630cSZhang Yubing 	u8 dpcd[DP_RECEIVER_CAP_SIZE];
195fb43630cSZhang Yubing 	unsigned char revision;
196fb43630cSZhang Yubing 	unsigned int rate;
197fb43630cSZhang Yubing 	unsigned int lanes;
198fb43630cSZhang Yubing 	struct drm_dp_link_caps caps;
199fb43630cSZhang Yubing 	struct drm_dp_link_train train;
200fb43630cSZhang Yubing 	u8 sink_count;
201fb43630cSZhang Yubing 	u8 vsc_sdp_extension_for_colorimetry_supported;
202fb43630cSZhang Yubing };
203fb43630cSZhang Yubing 
204fb43630cSZhang Yubing struct dw_dp_video {
205fb43630cSZhang Yubing 	struct drm_display_mode mode;
206fb43630cSZhang Yubing 	u32 bus_format;
207fb43630cSZhang Yubing 	u8 video_mapping;
208fb43630cSZhang Yubing 	u8 pixel_mode;
209fb43630cSZhang Yubing 	u8 color_format;
210fb43630cSZhang Yubing 	u8 bpc;
211fb43630cSZhang Yubing 	u8 bpp;
212fb43630cSZhang Yubing };
213fb43630cSZhang Yubing 
214fb43630cSZhang Yubing struct dw_dp_sdp {
215fb43630cSZhang Yubing 	struct dp_sdp_header header;
216fb43630cSZhang Yubing 	u8 db[32];
217fb43630cSZhang Yubing 	unsigned long flags;
218fb43630cSZhang Yubing };
219fb43630cSZhang Yubing 
2205fc83b1eSZhang Yubing struct dw_dp_chip_data {
2215fc83b1eSZhang Yubing 	int pixel_mode;
2225fc83b1eSZhang Yubing };
2235fc83b1eSZhang Yubing 
224fb43630cSZhang Yubing struct dw_dp {
2250594ce39SZhang Yubing 	struct rockchip_connector connector;
226fb43630cSZhang Yubing 	struct udevice *dev;
227fb43630cSZhang Yubing 	struct regmap *regmap;
228fb43630cSZhang Yubing 	struct phy phy;
229fb43630cSZhang Yubing 	struct reset_ctl reset;
230fb43630cSZhang Yubing 	int id;
231fb43630cSZhang Yubing 
232fb43630cSZhang Yubing 	struct gpio_desc hpd_gpio;
233fb43630cSZhang Yubing 	struct drm_dp_aux aux;
234fb43630cSZhang Yubing 	struct dw_dp_link link;
235fb43630cSZhang Yubing 	struct dw_dp_video video;
2365efdd3e2SZhang Yubing 
2375fbef17aSZhang Yubing 	bool force_hpd;
2385efdd3e2SZhang Yubing 	bool force_output;
239549d42b6SWyon Bi 	u32 max_link_rate;
240fb43630cSZhang Yubing };
241fb43630cSZhang Yubing 
242fb43630cSZhang Yubing enum {
243fb43630cSZhang Yubing 	SOURCE_STATE_IDLE,
244fb43630cSZhang Yubing 	SOURCE_STATE_UNPLUG,
245fb43630cSZhang Yubing 	SOURCE_STATE_HPD_TIMEOUT = 4,
246fb43630cSZhang Yubing 	SOURCE_STATE_PLUG = 7
247fb43630cSZhang Yubing };
248fb43630cSZhang Yubing 
249fb43630cSZhang Yubing enum {
250fb43630cSZhang Yubing 	DPTX_VM_RGB_6BIT,
251fb43630cSZhang Yubing 	DPTX_VM_RGB_8BIT,
252fb43630cSZhang Yubing 	DPTX_VM_RGB_10BIT,
253fb43630cSZhang Yubing 	DPTX_VM_RGB_12BIT,
254fb43630cSZhang Yubing 	DPTX_VM_RGB_16BIT,
255fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_8BIT,
256fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_10BIT,
257fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_12BIT,
258fb43630cSZhang Yubing 	DPTX_VM_YCBCR444_16BIT,
259fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_8BIT,
260fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_10BIT,
261fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_12BIT,
262fb43630cSZhang Yubing 	DPTX_VM_YCBCR422_16BIT,
263fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_8BIT,
264fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_10BIT,
265fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_12BIT,
266fb43630cSZhang Yubing 	DPTX_VM_YCBCR420_16BIT,
267fb43630cSZhang Yubing };
268fb43630cSZhang Yubing 
269fb43630cSZhang Yubing enum {
270fb43630cSZhang Yubing 	DPTX_MP_SINGLE_PIXEL,
271fb43630cSZhang Yubing 	DPTX_MP_DUAL_PIXEL,
272fb43630cSZhang Yubing 	DPTX_MP_QUAD_PIXEL,
273fb43630cSZhang Yubing };
274fb43630cSZhang Yubing 
275fb43630cSZhang Yubing enum {
276fb43630cSZhang Yubing 	DPTX_SDP_VERTICAL_INTERVAL = BIT(0),
277fb43630cSZhang Yubing 	DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1),
278fb43630cSZhang Yubing };
279fb43630cSZhang Yubing 
280fb43630cSZhang Yubing enum {
281fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_NONE,
282fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_1,
283fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_2,
284fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_3,
285fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_TPS_4,
286fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_SERM,
287fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_PBRS7,
288fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CUSTOM_80BIT,
289fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CP2520_1,
290fb43630cSZhang Yubing 	DPTX_PHY_PATTERN_CP2520_2,
291fb43630cSZhang Yubing };
292fb43630cSZhang Yubing 
2935efdd3e2SZhang Yubing enum {
2945efdd3e2SZhang Yubing 	DPTX_PHYRATE_RBR,
2955efdd3e2SZhang Yubing 	DPTX_PHYRATE_HBR,
2965efdd3e2SZhang Yubing 	DPTX_PHYRATE_HBR2,
2975efdd3e2SZhang Yubing 	DPTX_PHYRATE_HBR3,
2985efdd3e2SZhang Yubing };
2995efdd3e2SZhang Yubing 
300fb43630cSZhang Yubing struct dw_dp_output_format {
301fb43630cSZhang Yubing 	u32 bus_format;
302fb43630cSZhang Yubing 	u32 color_format;
303fb43630cSZhang Yubing 	u8 video_mapping;
304fb43630cSZhang Yubing 	u8 bpc;
305fb43630cSZhang Yubing 	u8 bpp;
306fb43630cSZhang Yubing };
307fb43630cSZhang Yubing 
308fb43630cSZhang Yubing static const struct dw_dp_output_format possible_output_fmts[] = {
309fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444,
310fb43630cSZhang Yubing 	  DPTX_VM_RGB_10BIT, 10, 30 },
311fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444,
312fb43630cSZhang Yubing 	  DPTX_VM_RGB_8BIT, 8, 24 },
313fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444,
314fb43630cSZhang Yubing 	  DPTX_VM_YCBCR444_10BIT, 10, 30 },
315fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444,
316fb43630cSZhang Yubing 	  DPTX_VM_YCBCR444_8BIT, 8, 24},
317fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422,
318fb43630cSZhang Yubing 	  DPTX_VM_YCBCR422_10BIT, 10, 20 },
319fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422,
320fb43630cSZhang Yubing 	  DPTX_VM_YCBCR422_8BIT, 8, 16 },
321fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420,
322fb43630cSZhang Yubing 	  DPTX_VM_YCBCR420_10BIT, 10, 15 },
323fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420,
324fb43630cSZhang Yubing 	  DPTX_VM_YCBCR420_8BIT, 8, 12 },
325fb43630cSZhang Yubing 	{ MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444,
326fb43630cSZhang Yubing 	  DPTX_VM_RGB_6BIT, 6, 18 },
327fb43630cSZhang Yubing };
328fb43630cSZhang Yubing 
329fb43630cSZhang Yubing static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size)
330fb43630cSZhang Yubing {
331fb43630cSZhang Yubing 	size_t i, j;
332fb43630cSZhang Yubing 
333fb43630cSZhang Yubing 	for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
334fb43630cSZhang Yubing 		size_t num = min_t(size_t, size - i * 4, 4);
335fb43630cSZhang Yubing 		u32 value = 0;
336fb43630cSZhang Yubing 
337fb43630cSZhang Yubing 		for (j = 0; j < num; j++)
338fb43630cSZhang Yubing 			value |= buffer[i * 4 + j] << (j * 8);
339fb43630cSZhang Yubing 
340fb43630cSZhang Yubing 		regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value);
341fb43630cSZhang Yubing 	}
342fb43630cSZhang Yubing 
343fb43630cSZhang Yubing 	return size;
344fb43630cSZhang Yubing }
345fb43630cSZhang Yubing 
346fb43630cSZhang Yubing static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size)
347fb43630cSZhang Yubing {
348fb43630cSZhang Yubing 	size_t i, j;
349fb43630cSZhang Yubing 
350fb43630cSZhang Yubing 	for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
351fb43630cSZhang Yubing 		size_t num = min_t(size_t, size - i * 4, 4);
352fb43630cSZhang Yubing 		u32 value;
353fb43630cSZhang Yubing 
354fb43630cSZhang Yubing 		regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value);
355fb43630cSZhang Yubing 
356fb43630cSZhang Yubing 		for (j = 0; j < num; j++)
357fb43630cSZhang Yubing 			buffer[i * 4 + j] = value >> (j * 8);
358fb43630cSZhang Yubing 	}
359fb43630cSZhang Yubing 
360fb43630cSZhang Yubing 	return size;
361fb43630cSZhang Yubing }
362fb43630cSZhang Yubing 
363fb43630cSZhang Yubing static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
364fb43630cSZhang Yubing 				  struct drm_dp_aux_msg *msg)
365fb43630cSZhang Yubing {
366fb43630cSZhang Yubing 	u32 status, value;
367fb43630cSZhang Yubing 	ssize_t ret = 0;
368fb43630cSZhang Yubing 	int timeout = 0;
369fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(aux->dev);
370fb43630cSZhang Yubing 
371fb43630cSZhang Yubing 	if (WARN_ON(msg->size > 16))
372fb43630cSZhang Yubing 		return -E2BIG;
373fb43630cSZhang Yubing 
374fb43630cSZhang Yubing 	switch (msg->request & ~DP_AUX_I2C_MOT) {
375fb43630cSZhang Yubing 	case DP_AUX_NATIVE_WRITE:
376fb43630cSZhang Yubing 	case DP_AUX_I2C_WRITE:
377fb43630cSZhang Yubing 	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
378fb43630cSZhang Yubing 		ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size);
379fb43630cSZhang Yubing 		if (ret < 0)
380fb43630cSZhang Yubing 			return ret;
381fb43630cSZhang Yubing 		break;
382fb43630cSZhang Yubing 	case DP_AUX_NATIVE_READ:
383fb43630cSZhang Yubing 	case DP_AUX_I2C_READ:
384fb43630cSZhang Yubing 		break;
385fb43630cSZhang Yubing 	default:
386fb43630cSZhang Yubing 		return -EINVAL;
387fb43630cSZhang Yubing 	}
388fb43630cSZhang Yubing 
389fb43630cSZhang Yubing 	if (msg->size > 0)
390fb43630cSZhang Yubing 		value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1);
391fb43630cSZhang Yubing 	else
392fb43630cSZhang Yubing 		value = FIELD_PREP(I2C_ADDR_ONLY, 1);
393fb43630cSZhang Yubing 
394fb43630cSZhang Yubing 	value |= FIELD_PREP(AUX_CMD_TYPE, msg->request);
395fb43630cSZhang Yubing 	value |= FIELD_PREP(AUX_ADDR, msg->address);
396fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_AUX_CMD, value);
397fb43630cSZhang Yubing 
398fb43630cSZhang Yubing 	timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT,
399fb43630cSZhang Yubing 					   status, status & AUX_REPLY_EVENT,
400fb43630cSZhang Yubing 					   200, 10);
401fb43630cSZhang Yubing 
402fb43630cSZhang Yubing 	if (timeout) {
403fb43630cSZhang Yubing 		printf("timeout waiting for AUX reply\n");
404fb43630cSZhang Yubing 		return -ETIMEDOUT;
405fb43630cSZhang Yubing 	}
406fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT);
407fb43630cSZhang Yubing 
408fb43630cSZhang Yubing 	regmap_read(dp->regmap, DPTX_AUX_STATUS, &value);
409fb43630cSZhang Yubing 	if (value & AUX_TIMEOUT) {
410fb43630cSZhang Yubing 		printf("aux timeout\n");
411fb43630cSZhang Yubing 		return -ETIMEDOUT;
412fb43630cSZhang Yubing 	}
413fb43630cSZhang Yubing 
414fb43630cSZhang Yubing 	msg->reply = FIELD_GET(AUX_STATUS, value);
415fb43630cSZhang Yubing 
416fb43630cSZhang Yubing 	if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
417fb43630cSZhang Yubing 		if (msg->request & DP_AUX_I2C_READ) {
418fb43630cSZhang Yubing 			size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1;
419fb43630cSZhang Yubing 
420fb43630cSZhang Yubing 			if (count != msg->size) {
421fb43630cSZhang Yubing 				printf("aux fail to read %lu bytes\n", count);
422fb43630cSZhang Yubing 				return -EBUSY;
423fb43630cSZhang Yubing 			}
424fb43630cSZhang Yubing 
425fb43630cSZhang Yubing 			ret = dw_dp_aux_read_data(dp, msg->buffer, count);
426fb43630cSZhang Yubing 			if (ret < 0)
427fb43630cSZhang Yubing 				return ret;
428fb43630cSZhang Yubing 		}
429fb43630cSZhang Yubing 	}
430fb43630cSZhang Yubing 
431fb43630cSZhang Yubing 	return ret;
432fb43630cSZhang Yubing }
433fb43630cSZhang Yubing 
434fb43630cSZhang Yubing static bool dw_dp_bandwidth_ok(struct dw_dp *dp,
435fb43630cSZhang Yubing 			       const struct drm_display_mode *mode, u32 bpp,
436fb43630cSZhang Yubing 			       unsigned int lanes, unsigned int rate)
437fb43630cSZhang Yubing {
438fb43630cSZhang Yubing 	u32 max_bw, req_bw;
439fb43630cSZhang Yubing 
440fb43630cSZhang Yubing 	req_bw = mode->clock * bpp / 8;
441fb43630cSZhang Yubing 	max_bw = lanes * rate;
442fb43630cSZhang Yubing 	if (req_bw > max_bw)
443fb43630cSZhang Yubing 		return false;
444fb43630cSZhang Yubing 
445fb43630cSZhang Yubing 	return true;
446fb43630cSZhang Yubing }
447fb43630cSZhang Yubing 
448fb43630cSZhang Yubing static void dw_dp_hpd_init(struct dw_dp *dp)
449fb43630cSZhang Yubing {
4505fbef17aSZhang Yubing 	if (dm_gpio_is_valid(&dp->hpd_gpio) || dp->force_hpd) {
451fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD,
452fb43630cSZhang Yubing 				   FIELD_PREP(FORCE_HPD, 1));
453fb43630cSZhang Yubing 		return;
454fb43630cSZhang Yubing 	}
455fb43630cSZhang Yubing 
456fb43630cSZhang Yubing 	/* Enable all HPD interrupts */
457fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE,
458fb43630cSZhang Yubing 			   HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN,
459fb43630cSZhang Yubing 			   FIELD_PREP(HPD_UNPLUG_EN, 1) |
460fb43630cSZhang Yubing 			   FIELD_PREP(HPD_PLUG_EN, 1) |
461fb43630cSZhang Yubing 			   FIELD_PREP(HPD_IRQ_EN, 1));
462fb43630cSZhang Yubing 
463fb43630cSZhang Yubing 	/* Enable all top-level interrupts */
464fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
465fb43630cSZhang Yubing 			   HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1));
466fb43630cSZhang Yubing }
467fb43630cSZhang Yubing 
468fb43630cSZhang Yubing static void dw_dp_aux_init(struct dw_dp *dp)
469fb43630cSZhang Yubing {
470fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
471fb43630cSZhang Yubing 			   FIELD_PREP(AUX_RESET, 1));
472fb43630cSZhang Yubing 	udelay(10);
473fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
474fb43630cSZhang Yubing 			   FIELD_PREP(AUX_RESET, 0));
475fb43630cSZhang Yubing 
476fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
477fb43630cSZhang Yubing 			   AUX_REPLY_EVENT_EN,
478fb43630cSZhang Yubing 			   FIELD_PREP(AUX_REPLY_EVENT_EN, 1));
479fb43630cSZhang Yubing }
480fb43630cSZhang Yubing 
481fb43630cSZhang Yubing static void dw_dp_init(struct dw_dp *dp)
482fb43630cSZhang Yubing {
483fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
484fb43630cSZhang Yubing 			   FIELD_PREP(CONTROLLER_RESET, 1));
485fb43630cSZhang Yubing 	udelay(10);
486fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
487fb43630cSZhang Yubing 			   FIELD_PREP(CONTROLLER_RESET, 0));
488fb43630cSZhang Yubing 
489fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
490fb43630cSZhang Yubing 			   FIELD_PREP(PHY_SOFT_RESET, 1));
491fb43630cSZhang Yubing 	udelay(10);
492fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
493fb43630cSZhang Yubing 			   FIELD_PREP(PHY_SOFT_RESET, 0));
494fb43630cSZhang Yubing 
495fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN,
496fb43630cSZhang Yubing 			   FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0));
497fb43630cSZhang Yubing 
498fb43630cSZhang Yubing 	dw_dp_hpd_init(dp);
499fb43630cSZhang Yubing 	dw_dp_aux_init(dp);
500fb43630cSZhang Yubing }
501fb43630cSZhang Yubing 
502fb43630cSZhang Yubing static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern)
503fb43630cSZhang Yubing {
504fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL,
505fb43630cSZhang Yubing 			   FIELD_PREP(TPS_SEL, pattern));
506fb43630cSZhang Yubing }
507fb43630cSZhang Yubing 
508fb43630cSZhang Yubing static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes)
509fb43630cSZhang Yubing {
510fb43630cSZhang Yubing 	u32 xmit_enable;
511fb43630cSZhang Yubing 
512fb43630cSZhang Yubing 	switch (lanes) {
513fb43630cSZhang Yubing 	case 4:
514fb43630cSZhang Yubing 	case 2:
515fb43630cSZhang Yubing 	case 1:
516fb43630cSZhang Yubing 		xmit_enable = GENMASK(lanes - 1, 0);
517fb43630cSZhang Yubing 		break;
518fb43630cSZhang Yubing 	case 0:
519fb43630cSZhang Yubing 	default:
520fb43630cSZhang Yubing 		xmit_enable = 0;
521fb43630cSZhang Yubing 		break;
522fb43630cSZhang Yubing 	}
523fb43630cSZhang Yubing 
524fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE,
525fb43630cSZhang Yubing 			   FIELD_PREP(XMIT_ENABLE, xmit_enable));
526fb43630cSZhang Yubing }
527fb43630cSZhang Yubing 
528fb43630cSZhang Yubing static int dw_dp_link_power_up(struct dw_dp *dp)
529fb43630cSZhang Yubing {
530fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
531fb43630cSZhang Yubing 	u8 value;
532fb43630cSZhang Yubing 	int ret;
533fb43630cSZhang Yubing 
534fb43630cSZhang Yubing 	if (link->revision < 0x11)
535fb43630cSZhang Yubing 		return 0;
536fb43630cSZhang Yubing 
537fb43630cSZhang Yubing 	ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
538fb43630cSZhang Yubing 	if (ret < 0)
539fb43630cSZhang Yubing 		return ret;
540fb43630cSZhang Yubing 
541fb43630cSZhang Yubing 	value &= ~DP_SET_POWER_MASK;
542fb43630cSZhang Yubing 	value |= DP_SET_POWER_D0;
543fb43630cSZhang Yubing 
544fb43630cSZhang Yubing 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
545fb43630cSZhang Yubing 	if (ret < 0)
546fb43630cSZhang Yubing 		return ret;
547fb43630cSZhang Yubing 
548fb43630cSZhang Yubing 	udelay(1000);
549fb43630cSZhang Yubing 	return 0;
550fb43630cSZhang Yubing }
551fb43630cSZhang Yubing 
552fb43630cSZhang Yubing static int dw_dp_link_probe(struct dw_dp *dp)
553fb43630cSZhang Yubing {
554fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
555fb43630cSZhang Yubing 	u8 dpcd;
556fb43630cSZhang Yubing 	int ret;
557fb43630cSZhang Yubing 
5582493a680SZhang Yubing 	drm_dp_dpcd_writeb(&dp->aux, DP_MSTM_CTRL, 0);
559fb43630cSZhang Yubing 	ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd);
560fb43630cSZhang Yubing 	if (ret < 0)
561fb43630cSZhang Yubing 		return ret;
562fb43630cSZhang Yubing 
563fb43630cSZhang Yubing 	ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
564fb43630cSZhang Yubing 				&dpcd);
565fb43630cSZhang Yubing 	if (ret < 0)
566fb43630cSZhang Yubing 		return ret;
567fb43630cSZhang Yubing 
568fb43630cSZhang Yubing 	link->vsc_sdp_extension_for_colorimetry_supported =
569fb43630cSZhang Yubing 		!!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED);
570fb43630cSZhang Yubing 
571fb43630cSZhang Yubing 	link->revision = link->dpcd[DP_DPCD_REV];
572549d42b6SWyon Bi 	link->rate = min_t(u32, min(dp->max_link_rate, dp->phy.attrs.max_link_rate * 100),
573ca4b9d14SWyon Bi 			   drm_dp_max_link_rate(link->dpcd));
574fb43630cSZhang Yubing 	link->lanes = min_t(u8, dp->phy.attrs.bus_width,
575fb43630cSZhang Yubing 			    drm_dp_max_lane_count(link->dpcd));
576fb43630cSZhang Yubing 
577fb43630cSZhang Yubing 	link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd);
578fb43630cSZhang Yubing 	link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd);
579fb43630cSZhang Yubing 	link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd);
580fb43630cSZhang Yubing 	link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd);
581fb43630cSZhang Yubing 	link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] &
582fb43630cSZhang Yubing 			    DP_MAX_DOWNSPREAD_0_5);
583fb43630cSZhang Yubing 
584fb43630cSZhang Yubing 	return 0;
585fb43630cSZhang Yubing }
586fb43630cSZhang Yubing 
587fb43630cSZhang Yubing static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp)
588fb43630cSZhang Yubing {
589fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
590fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &link->train.request;
591fb43630cSZhang Yubing 	union phy_configure_opts phy_cfg;
592fb43630cSZhang Yubing 	unsigned int lanes = link->lanes, *vs, *pe;
593fb43630cSZhang Yubing 	u8 buf[4];
594fb43630cSZhang Yubing 	int i, ret;
595fb43630cSZhang Yubing 
596fb43630cSZhang Yubing 	vs = request->voltage_swing;
597fb43630cSZhang Yubing 	pe = request->pre_emphasis;
598fb43630cSZhang Yubing 
599fb43630cSZhang Yubing 	for (i = 0; i < lanes; i++) {
600fb43630cSZhang Yubing 		phy_cfg.dp.voltage[i] = vs[i];
601fb43630cSZhang Yubing 		phy_cfg.dp.pre[i] = pe[i];
602fb43630cSZhang Yubing 	}
603fb43630cSZhang Yubing 	phy_cfg.dp.lanes = lanes;
604fb43630cSZhang Yubing 	phy_cfg.dp.link_rate = link->rate / 100;
605fb43630cSZhang Yubing 	phy_cfg.dp.set_lanes = false;
606fb43630cSZhang Yubing 	phy_cfg.dp.set_rate = false;
607fb43630cSZhang Yubing 	phy_cfg.dp.set_voltages = true;
608fb43630cSZhang Yubing 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
609fb43630cSZhang Yubing 	if (ret)
610fb43630cSZhang Yubing 		return ret;
611fb43630cSZhang Yubing 
612fb43630cSZhang Yubing 	for (i = 0; i < lanes; i++)
613fb43630cSZhang Yubing 		buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) |
614fb43630cSZhang Yubing 			 (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT);
615fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes);
616fb43630cSZhang Yubing 	if (ret < 0)
617fb43630cSZhang Yubing 		return ret;
618fb43630cSZhang Yubing 
619fb43630cSZhang Yubing 	return 0;
620fb43630cSZhang Yubing }
621fb43630cSZhang Yubing 
622fb43630cSZhang Yubing static int dw_dp_link_configure(struct dw_dp *dp)
623fb43630cSZhang Yubing {
624fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
625fb43630cSZhang Yubing 	union phy_configure_opts phy_cfg;
626fb43630cSZhang Yubing 	u8 buf[2];
6275efdd3e2SZhang Yubing 	int ret, phy_rate;
628fb43630cSZhang Yubing 
629fb43630cSZhang Yubing 	/* Move PHY to P3 */
630fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
631fb43630cSZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x3));
632fb43630cSZhang Yubing 
633fb43630cSZhang Yubing 	phy_cfg.dp.lanes = link->lanes;
634fb43630cSZhang Yubing 	phy_cfg.dp.link_rate = link->rate / 100;
635fb43630cSZhang Yubing 	phy_cfg.dp.ssc = link->caps.ssc;
636fb43630cSZhang Yubing 	phy_cfg.dp.set_lanes = true;
637fb43630cSZhang Yubing 	phy_cfg.dp.set_rate = true;
638fb43630cSZhang Yubing 	phy_cfg.dp.set_voltages = false;
639fb43630cSZhang Yubing 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
640fb43630cSZhang Yubing 	if (ret)
641fb43630cSZhang Yubing 		return ret;
642fb43630cSZhang Yubing 
643fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES,
644fb43630cSZhang Yubing 			   FIELD_PREP(PHY_LANES, link->lanes / 2));
645fb43630cSZhang Yubing 
6465efdd3e2SZhang Yubing 	switch (link->rate) {
6475efdd3e2SZhang Yubing 	case 810000:
6485efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR3;
6495efdd3e2SZhang Yubing 		break;
6505efdd3e2SZhang Yubing 	case 540000:
6515efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR2;
6525efdd3e2SZhang Yubing 		break;
6535efdd3e2SZhang Yubing 	case 270000:
6545efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR;
6555efdd3e2SZhang Yubing 		break;
6565efdd3e2SZhang Yubing 	case 162000:
6575efdd3e2SZhang Yubing 	default:
6585efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_RBR;
6595efdd3e2SZhang Yubing 		break;
6605efdd3e2SZhang Yubing 	}
6615efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE,
6625efdd3e2SZhang Yubing 			   FIELD_PREP(PHY_RATE, phy_rate));
6635efdd3e2SZhang Yubing 
664fb43630cSZhang Yubing 	/* Move PHY to P0 */
665fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
666fb43630cSZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x0));
667fb43630cSZhang Yubing 
668fb43630cSZhang Yubing 	dw_dp_phy_xmit_enable(dp, link->lanes);
669fb43630cSZhang Yubing 
670fb43630cSZhang Yubing 	buf[0] = drm_dp_link_rate_to_bw_code(link->rate);
671fb43630cSZhang Yubing 	buf[1] = link->lanes;
672fb43630cSZhang Yubing 
673fb43630cSZhang Yubing 	if (link->caps.enhanced_framing) {
674fb43630cSZhang Yubing 		buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
675fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
676fb43630cSZhang Yubing 				   FIELD_PREP(ENHANCE_FRAMING_EN, 1));
677fb43630cSZhang Yubing 	} else {
678fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
679fb43630cSZhang Yubing 				   FIELD_PREP(ENHANCE_FRAMING_EN, 0));
680fb43630cSZhang Yubing 	}
681fb43630cSZhang Yubing 
682fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf));
683fb43630cSZhang Yubing 	if (ret < 0)
684fb43630cSZhang Yubing 		return ret;
685fb43630cSZhang Yubing 
686fb43630cSZhang Yubing 	buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0;
687fb43630cSZhang Yubing 	buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0;
688fb43630cSZhang Yubing 
689fb43630cSZhang Yubing 	ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf,
690fb43630cSZhang Yubing 				sizeof(buf));
691fb43630cSZhang Yubing 	if (ret < 0)
692fb43630cSZhang Yubing 		return ret;
693fb43630cSZhang Yubing 
694fb43630cSZhang Yubing 	return 0;
695fb43630cSZhang Yubing }
696fb43630cSZhang Yubing 
697fb43630cSZhang Yubing static void dw_dp_link_train_init(struct drm_dp_link_train *train)
698fb43630cSZhang Yubing {
699fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &train->request;
700fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &train->adjust;
701fb43630cSZhang Yubing 	unsigned int i;
702fb43630cSZhang Yubing 
703fb43630cSZhang Yubing 	for (i = 0; i < 4; i++) {
704fb43630cSZhang Yubing 		request->voltage_swing[i] = 0;
705fb43630cSZhang Yubing 		adjust->voltage_swing[i] = 0;
706fb43630cSZhang Yubing 
707fb43630cSZhang Yubing 		request->pre_emphasis[i] = 0;
708fb43630cSZhang Yubing 		adjust->pre_emphasis[i] = 0;
709fb43630cSZhang Yubing 	}
710fb43630cSZhang Yubing 
711fb43630cSZhang Yubing 	train->clock_recovered = false;
712fb43630cSZhang Yubing 	train->channel_equalized = false;
713fb43630cSZhang Yubing }
714fb43630cSZhang Yubing 
715fb43630cSZhang Yubing static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern)
716fb43630cSZhang Yubing {
717fb43630cSZhang Yubing 	u8 buf = 0;
718fb43630cSZhang Yubing 	int ret;
719fb43630cSZhang Yubing 
720fb43630cSZhang Yubing 	if (pattern && pattern != DP_TRAINING_PATTERN_4) {
721fb43630cSZhang Yubing 		buf |= DP_LINK_SCRAMBLING_DISABLE;
722fb43630cSZhang Yubing 
723fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
724fb43630cSZhang Yubing 				   FIELD_PREP(SCRAMBLE_DIS, 1));
725fb43630cSZhang Yubing 	} else {
726fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
727fb43630cSZhang Yubing 				   FIELD_PREP(SCRAMBLE_DIS, 0));
728fb43630cSZhang Yubing 	}
729fb43630cSZhang Yubing 
730fb43630cSZhang Yubing 	switch (pattern) {
731fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_DISABLE:
732fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE);
733fb43630cSZhang Yubing 		break;
734fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_1:
735fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1);
736fb43630cSZhang Yubing 		break;
737fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_2:
738fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2);
739fb43630cSZhang Yubing 		break;
740fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_3:
741fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3);
742fb43630cSZhang Yubing 		break;
743fb43630cSZhang Yubing 	case DP_TRAINING_PATTERN_4:
744fb43630cSZhang Yubing 		dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4);
745fb43630cSZhang Yubing 		break;
746fb43630cSZhang Yubing 	default:
747fb43630cSZhang Yubing 		return -EINVAL;
748fb43630cSZhang Yubing 	}
749fb43630cSZhang Yubing 
750fb43630cSZhang Yubing 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
751fb43630cSZhang Yubing 				 buf | pattern);
752fb43630cSZhang Yubing 	if (ret < 0)
753fb43630cSZhang Yubing 		return ret;
754fb43630cSZhang Yubing 
755fb43630cSZhang Yubing 	return 0;
756fb43630cSZhang Yubing }
757fb43630cSZhang Yubing 
758fb43630cSZhang Yubing static void dw_dp_link_get_adjustments(struct dw_dp_link *link,
759fb43630cSZhang Yubing 				       u8 status[DP_LINK_STATUS_SIZE])
760fb43630cSZhang Yubing {
761fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &link->train.adjust;
762fb43630cSZhang Yubing 	unsigned int i;
763fb43630cSZhang Yubing 
764fb43630cSZhang Yubing 	for (i = 0; i < link->lanes; i++) {
765fb43630cSZhang Yubing 		adjust->voltage_swing[i] =
766fb43630cSZhang Yubing 			drm_dp_get_adjust_request_voltage(status, i) >>
767fb43630cSZhang Yubing 				DP_TRAIN_VOLTAGE_SWING_SHIFT;
768fb43630cSZhang Yubing 
769fb43630cSZhang Yubing 		adjust->pre_emphasis[i] =
770fb43630cSZhang Yubing 			drm_dp_get_adjust_request_pre_emphasis(status, i) >>
771fb43630cSZhang Yubing 				DP_TRAIN_PRE_EMPHASIS_SHIFT;
772fb43630cSZhang Yubing 	}
773fb43630cSZhang Yubing }
774fb43630cSZhang Yubing 
775fb43630cSZhang Yubing static void dw_dp_link_train_adjust(struct drm_dp_link_train *train)
776fb43630cSZhang Yubing {
777fb43630cSZhang Yubing 	struct drm_dp_link_train_set *request = &train->request;
778fb43630cSZhang Yubing 	struct drm_dp_link_train_set *adjust = &train->adjust;
779fb43630cSZhang Yubing 	unsigned int i;
780fb43630cSZhang Yubing 
781fb43630cSZhang Yubing 	for (i = 0; i < 4; i++)
782fb43630cSZhang Yubing 		if (request->voltage_swing[i] != adjust->voltage_swing[i])
783fb43630cSZhang Yubing 			request->voltage_swing[i] = adjust->voltage_swing[i];
784fb43630cSZhang Yubing 
785fb43630cSZhang Yubing 	for (i = 0; i < 4; i++)
786fb43630cSZhang Yubing 		if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
787fb43630cSZhang Yubing 			request->pre_emphasis[i] = adjust->pre_emphasis[i];
788fb43630cSZhang Yubing }
789fb43630cSZhang Yubing 
790fb43630cSZhang Yubing static int dw_dp_link_clock_recovery(struct dw_dp *dp)
791fb43630cSZhang Yubing {
792fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
793fb43630cSZhang Yubing 	u8 status[DP_LINK_STATUS_SIZE];
794fb43630cSZhang Yubing 	unsigned int tries = 0;
795fb43630cSZhang Yubing 	int ret;
796fb43630cSZhang Yubing 
797fb43630cSZhang Yubing 	ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);
798fb43630cSZhang Yubing 	if (ret)
799fb43630cSZhang Yubing 		return ret;
800fb43630cSZhang Yubing 
801fb43630cSZhang Yubing 	for (;;) {
802fb43630cSZhang Yubing 		ret = dw_dp_link_train_update_vs_emph(dp);
803fb43630cSZhang Yubing 		if (ret)
804fb43630cSZhang Yubing 			return ret;
805fb43630cSZhang Yubing 
806fb43630cSZhang Yubing 		drm_dp_link_train_clock_recovery_delay(link->dpcd);
807fb43630cSZhang Yubing 
808fb43630cSZhang Yubing 		ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
809fb43630cSZhang Yubing 		if (ret < 0) {
810fb43630cSZhang Yubing 			dev_err(dp->dev, "failed to read link status: %d\n",
811fb43630cSZhang Yubing 				ret);
812fb43630cSZhang Yubing 			return ret;
813fb43630cSZhang Yubing 		}
814fb43630cSZhang Yubing 
815fb43630cSZhang Yubing 		if (drm_dp_clock_recovery_ok(status, link->lanes)) {
816fb43630cSZhang Yubing 			link->train.clock_recovered = true;
817fb43630cSZhang Yubing 			break;
818fb43630cSZhang Yubing 		}
819fb43630cSZhang Yubing 
820fb43630cSZhang Yubing 		dw_dp_link_get_adjustments(link, status);
821fb43630cSZhang Yubing 
822fb43630cSZhang Yubing 		if (link->train.request.voltage_swing[0] ==
823fb43630cSZhang Yubing 		    link->train.adjust.voltage_swing[0])
824fb43630cSZhang Yubing 			tries++;
825fb43630cSZhang Yubing 		else
826fb43630cSZhang Yubing 			tries = 0;
827fb43630cSZhang Yubing 
828fb43630cSZhang Yubing 		if (tries == 5)
829fb43630cSZhang Yubing 			break;
830fb43630cSZhang Yubing 
831fb43630cSZhang Yubing 		dw_dp_link_train_adjust(&link->train);
832fb43630cSZhang Yubing 	}
833fb43630cSZhang Yubing 
834fb43630cSZhang Yubing 	return 0;
835fb43630cSZhang Yubing }
836fb43630cSZhang Yubing 
837fb43630cSZhang Yubing static int dw_dp_link_channel_equalization(struct dw_dp *dp)
838fb43630cSZhang Yubing {
839fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
840fb43630cSZhang Yubing 	u8 status[DP_LINK_STATUS_SIZE], pattern;
841fb43630cSZhang Yubing 	unsigned int tries;
842fb43630cSZhang Yubing 	int ret;
843fb43630cSZhang Yubing 
844fb43630cSZhang Yubing 	if (link->caps.tps4_supported)
845fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_4;
846fb43630cSZhang Yubing 	else if (link->caps.tps3_supported)
847fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_3;
848fb43630cSZhang Yubing 	else
849fb43630cSZhang Yubing 		pattern = DP_TRAINING_PATTERN_2;
850fb43630cSZhang Yubing 	ret = dw_dp_link_train_set_pattern(dp, pattern);
851fb43630cSZhang Yubing 	if (ret)
852fb43630cSZhang Yubing 		return ret;
853fb43630cSZhang Yubing 
854fb43630cSZhang Yubing 	for (tries = 1; tries < 5; tries++) {
855fb43630cSZhang Yubing 		ret = dw_dp_link_train_update_vs_emph(dp);
856fb43630cSZhang Yubing 		if (ret)
857fb43630cSZhang Yubing 			return ret;
858fb43630cSZhang Yubing 
859fb43630cSZhang Yubing 		drm_dp_link_train_channel_eq_delay(link->dpcd);
860fb43630cSZhang Yubing 
861fb43630cSZhang Yubing 		ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
862fb43630cSZhang Yubing 		if (ret < 0)
863fb43630cSZhang Yubing 			return ret;
864fb43630cSZhang Yubing 
865fb43630cSZhang Yubing 		if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
866fb43630cSZhang Yubing 			dev_err(dp->dev,
867fb43630cSZhang Yubing 				"clock recovery lost while eq\n");
868fb43630cSZhang Yubing 			link->train.clock_recovered = false;
869fb43630cSZhang Yubing 			break;
870fb43630cSZhang Yubing 		}
871fb43630cSZhang Yubing 
872fb43630cSZhang Yubing 		if (drm_dp_channel_eq_ok(status, link->lanes)) {
873fb43630cSZhang Yubing 			link->train.channel_equalized = true;
874fb43630cSZhang Yubing 			break;
875fb43630cSZhang Yubing 		}
876fb43630cSZhang Yubing 
877fb43630cSZhang Yubing 		dw_dp_link_get_adjustments(link, status);
878fb43630cSZhang Yubing 		dw_dp_link_train_adjust(&link->train);
879fb43630cSZhang Yubing 	}
880fb43630cSZhang Yubing 
881fb43630cSZhang Yubing 	return 0;
882fb43630cSZhang Yubing }
883fb43630cSZhang Yubing 
884fb43630cSZhang Yubing static int dw_dp_link_downgrade(struct dw_dp *dp)
885fb43630cSZhang Yubing {
886fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
887fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
888fb43630cSZhang Yubing 
889fb43630cSZhang Yubing 	switch (link->rate) {
890fb43630cSZhang Yubing 	case 162000:
891fb43630cSZhang Yubing 		return -EINVAL;
892fb43630cSZhang Yubing 	case 270000:
893fb43630cSZhang Yubing 		link->rate = 162000;
894fb43630cSZhang Yubing 		break;
895fb43630cSZhang Yubing 	case 540000:
896fb43630cSZhang Yubing 		link->rate = 270000;
897fb43630cSZhang Yubing 		break;
898fb43630cSZhang Yubing 	case 810000:
899fb43630cSZhang Yubing 		link->rate = 540000;
900fb43630cSZhang Yubing 		break;
901fb43630cSZhang Yubing 	}
902fb43630cSZhang Yubing 
903fb43630cSZhang Yubing 	if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes,
904fb43630cSZhang Yubing 				link->rate))
905fb43630cSZhang Yubing 		return -E2BIG;
906fb43630cSZhang Yubing 
907fb43630cSZhang Yubing 	return 0;
908fb43630cSZhang Yubing }
909fb43630cSZhang Yubing 
910fb43630cSZhang Yubing static int dw_dp_link_train(struct dw_dp *dp)
911fb43630cSZhang Yubing {
912fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
913fb43630cSZhang Yubing 	int ret;
914fb43630cSZhang Yubing 
915fb43630cSZhang Yubing retry:
916fb43630cSZhang Yubing 	dw_dp_link_train_init(&link->train);
917fb43630cSZhang Yubing 
918fb43630cSZhang Yubing 	printf("training link: %u lane%s at %u MHz\n",
919fb43630cSZhang Yubing 	       link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100);
920fb43630cSZhang Yubing 
921fb43630cSZhang Yubing 	ret = dw_dp_link_configure(dp);
922fb43630cSZhang Yubing 	if (ret < 0) {
923fb43630cSZhang Yubing 		dev_err(dp->dev, "failed to configure DP link: %d\n", ret);
924fb43630cSZhang Yubing 		return ret;
925fb43630cSZhang Yubing 	}
926fb43630cSZhang Yubing 
927fb43630cSZhang Yubing 	ret = dw_dp_link_clock_recovery(dp);
928fb43630cSZhang Yubing 	if (ret < 0) {
929fb43630cSZhang Yubing 		dev_err(dp->dev, "clock recovery failed: %d\n", ret);
930fb43630cSZhang Yubing 		goto out;
931fb43630cSZhang Yubing 	}
932fb43630cSZhang Yubing 
933fb43630cSZhang Yubing 	if (!link->train.clock_recovered) {
934fb43630cSZhang Yubing 		dev_err(dp->dev, "clock recovery failed, downgrading link\n");
935fb43630cSZhang Yubing 
936fb43630cSZhang Yubing 		ret = dw_dp_link_downgrade(dp);
937fb43630cSZhang Yubing 		if (ret < 0)
938fb43630cSZhang Yubing 			goto out;
939fb43630cSZhang Yubing 		else
940fb43630cSZhang Yubing 			goto retry;
941fb43630cSZhang Yubing 	}
942fb43630cSZhang Yubing 
943fb43630cSZhang Yubing 	printf("clock recovery succeeded\n");
944fb43630cSZhang Yubing 
945fb43630cSZhang Yubing 	ret = dw_dp_link_channel_equalization(dp);
946fb43630cSZhang Yubing 	if (ret < 0) {
947fb43630cSZhang Yubing 		dev_err(dp->dev, "channel equalization failed: %d\n", ret);
948fb43630cSZhang Yubing 		goto out;
949fb43630cSZhang Yubing 	}
950fb43630cSZhang Yubing 
951fb43630cSZhang Yubing 	if (!link->train.channel_equalized) {
952fb43630cSZhang Yubing 		dev_err(dp->dev,
953fb43630cSZhang Yubing 			"channel equalization failed, downgrading link\n");
954fb43630cSZhang Yubing 
955fb43630cSZhang Yubing 		ret = dw_dp_link_downgrade(dp);
956fb43630cSZhang Yubing 		if (ret < 0)
957fb43630cSZhang Yubing 			goto out;
958fb43630cSZhang Yubing 		else
959fb43630cSZhang Yubing 			goto retry;
960fb43630cSZhang Yubing 	}
961fb43630cSZhang Yubing 
962fb43630cSZhang Yubing 	printf("channel equalization succeeded\n");
963fb43630cSZhang Yubing 
964fb43630cSZhang Yubing out:
965fb43630cSZhang Yubing 	dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
966fb43630cSZhang Yubing 	return ret;
967fb43630cSZhang Yubing }
968fb43630cSZhang Yubing 
969fb43630cSZhang Yubing static int dw_dp_link_enable(struct dw_dp *dp)
970fb43630cSZhang Yubing {
971fb43630cSZhang Yubing 	int ret;
972fb43630cSZhang Yubing 
973fb43630cSZhang Yubing 	ret = dw_dp_link_power_up(dp);
974fb43630cSZhang Yubing 	if (ret < 0)
975fb43630cSZhang Yubing 		return ret;
976fb43630cSZhang Yubing 
977fb43630cSZhang Yubing 	ret = dw_dp_link_train(dp);
978fb43630cSZhang Yubing 	if (ret < 0) {
979fb43630cSZhang Yubing 		dev_err(dp->dev, "link training failed: %d\n", ret);
980fb43630cSZhang Yubing 		return ret;
981fb43630cSZhang Yubing 	}
982fb43630cSZhang Yubing 
983fb43630cSZhang Yubing 	return 0;
984fb43630cSZhang Yubing }
985fb43630cSZhang Yubing 
9865efdd3e2SZhang Yubing static int dw_dp_set_phy_default_config(struct dw_dp *dp)
9875efdd3e2SZhang Yubing {
9885efdd3e2SZhang Yubing 	struct dw_dp_link *link = &dp->link;
9895efdd3e2SZhang Yubing 	union phy_configure_opts phy_cfg;
9905efdd3e2SZhang Yubing 	int ret, i, phy_rate;
9915efdd3e2SZhang Yubing 
9925efdd3e2SZhang Yubing 	link->vsc_sdp_extension_for_colorimetry_supported = false;
9935efdd3e2SZhang Yubing 	link->rate = 270000;
9945efdd3e2SZhang Yubing 	link->lanes = dp->phy.attrs.bus_width;
9955efdd3e2SZhang Yubing 
9965efdd3e2SZhang Yubing 	link->caps.enhanced_framing = true;
9975efdd3e2SZhang Yubing 	link->caps.channel_coding = true;
9985efdd3e2SZhang Yubing 	link->caps.ssc = true;
9995efdd3e2SZhang Yubing 
10005efdd3e2SZhang Yubing 	/* Move PHY to P3 */
10015efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
10025efdd3e2SZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x3));
10035efdd3e2SZhang Yubing 
10045efdd3e2SZhang Yubing 	for (i = 0; i < link->lanes; i++) {
10055efdd3e2SZhang Yubing 		phy_cfg.dp.voltage[i] = 3;
10065efdd3e2SZhang Yubing 		phy_cfg.dp.pre[i] = 0;
10075efdd3e2SZhang Yubing 	}
10085efdd3e2SZhang Yubing 	phy_cfg.dp.lanes = link->lanes;
10095efdd3e2SZhang Yubing 	phy_cfg.dp.link_rate = link->rate / 100;
10105efdd3e2SZhang Yubing 	phy_cfg.dp.ssc = link->caps.ssc;
10115efdd3e2SZhang Yubing 	phy_cfg.dp.set_lanes = true;
10125efdd3e2SZhang Yubing 	phy_cfg.dp.set_rate = true;
10135efdd3e2SZhang Yubing 	phy_cfg.dp.set_voltages = true;
10145efdd3e2SZhang Yubing 	ret = generic_phy_configure(&dp->phy, &phy_cfg);
10155efdd3e2SZhang Yubing 	if (ret)
10165efdd3e2SZhang Yubing 		return ret;
10175efdd3e2SZhang Yubing 
10185efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES,
10195efdd3e2SZhang Yubing 			   FIELD_PREP(PHY_LANES, link->lanes / 2));
10205efdd3e2SZhang Yubing 
10215efdd3e2SZhang Yubing 	switch (link->rate) {
10225efdd3e2SZhang Yubing 	case 810000:
10235efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR3;
10245efdd3e2SZhang Yubing 		break;
10255efdd3e2SZhang Yubing 	case 540000:
10265efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR2;
10275efdd3e2SZhang Yubing 		break;
10285efdd3e2SZhang Yubing 	case 270000:
10295efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_HBR;
10305efdd3e2SZhang Yubing 		break;
10315efdd3e2SZhang Yubing 	case 162000:
10325efdd3e2SZhang Yubing 	default:
10335efdd3e2SZhang Yubing 		phy_rate = DPTX_PHYRATE_RBR;
10345efdd3e2SZhang Yubing 		break;
10355efdd3e2SZhang Yubing 	}
10365efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE,
10375efdd3e2SZhang Yubing 			   FIELD_PREP(PHY_RATE, phy_rate));
10385efdd3e2SZhang Yubing 
10395efdd3e2SZhang Yubing 	/* Move PHY to P0 */
10405efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
10415efdd3e2SZhang Yubing 			   FIELD_PREP(PHY_POWERDOWN, 0x0));
10425efdd3e2SZhang Yubing 
10435efdd3e2SZhang Yubing 	dw_dp_phy_xmit_enable(dp, link->lanes);
10445efdd3e2SZhang Yubing 
10455efdd3e2SZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
10465efdd3e2SZhang Yubing 			   FIELD_PREP(ENHANCE_FRAMING_EN, 1));
10475efdd3e2SZhang Yubing 
10485efdd3e2SZhang Yubing 	dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE);
10495efdd3e2SZhang Yubing 	return 0;
10505efdd3e2SZhang Yubing }
10515efdd3e2SZhang Yubing 
1052fb43630cSZhang Yubing static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp)
1053fb43630cSZhang Yubing {
1054fb43630cSZhang Yubing 	const u8 *payload = sdp->db;
1055fb43630cSZhang Yubing 	u32 reg;
1056fb43630cSZhang Yubing 	int i, nr = 0;
1057fb43630cSZhang Yubing 
1058fb43630cSZhang Yubing 	reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4;
1059fb43630cSZhang Yubing 
1060fb43630cSZhang Yubing 	/* SDP header */
1061fb43630cSZhang Yubing 	regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header));
1062fb43630cSZhang Yubing 
1063fb43630cSZhang Yubing 	/* SDP data payload */
1064fb43630cSZhang Yubing 	for (i = 1; i < 9; i++, payload += 4)
1065fb43630cSZhang Yubing 		regmap_write(dp->regmap, reg + i * 4,
1066fb43630cSZhang Yubing 			     FIELD_PREP(SDP_REGS, get_unaligned_le32(payload)));
1067fb43630cSZhang Yubing 
1068fb43630cSZhang Yubing 	if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL)
1069fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL,
1070fb43630cSZhang Yubing 				   EN_VERTICAL_SDP << nr,
1071fb43630cSZhang Yubing 				   EN_VERTICAL_SDP << nr);
1072fb43630cSZhang Yubing 
1073fb43630cSZhang Yubing 	if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL)
1074fb43630cSZhang Yubing 		regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL,
1075fb43630cSZhang Yubing 				   EN_HORIZONTAL_SDP << nr,
1076fb43630cSZhang Yubing 				   EN_HORIZONTAL_SDP << nr);
1077fb43630cSZhang Yubing 
1078fb43630cSZhang Yubing 	return 0;
1079fb43630cSZhang Yubing }
1080fb43630cSZhang Yubing 
1081fb43630cSZhang Yubing static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
1082fb43630cSZhang Yubing 			       struct dw_dp_sdp *sdp)
1083fb43630cSZhang Yubing {
1084fb43630cSZhang Yubing 	sdp->header.HB0 = 0;
1085fb43630cSZhang Yubing 	sdp->header.HB1 = DP_SDP_VSC;
1086fb43630cSZhang Yubing 	sdp->header.HB2 = vsc->revision;
1087fb43630cSZhang Yubing 	sdp->header.HB3 = vsc->length;
1088fb43630cSZhang Yubing 
1089fb43630cSZhang Yubing 	sdp->db[16] = (vsc->pixelformat & 0xf) << 4;
1090fb43630cSZhang Yubing 	sdp->db[16] |= vsc->colorimetry & 0xf;
1091fb43630cSZhang Yubing 
1092fb43630cSZhang Yubing 	switch (vsc->bpc) {
1093fb43630cSZhang Yubing 	case 8:
1094fb43630cSZhang Yubing 		sdp->db[17] = 0x1;
1095fb43630cSZhang Yubing 		break;
1096fb43630cSZhang Yubing 	case 10:
1097fb43630cSZhang Yubing 		sdp->db[17] = 0x2;
1098fb43630cSZhang Yubing 		break;
1099fb43630cSZhang Yubing 	case 12:
1100fb43630cSZhang Yubing 		sdp->db[17] = 0x3;
1101fb43630cSZhang Yubing 		break;
1102fb43630cSZhang Yubing 	case 16:
1103fb43630cSZhang Yubing 		sdp->db[17] = 0x4;
1104fb43630cSZhang Yubing 		break;
1105fb43630cSZhang Yubing 	case 6:
1106fb43630cSZhang Yubing 	default:
1107fb43630cSZhang Yubing 		break;
1108fb43630cSZhang Yubing 	}
1109fb43630cSZhang Yubing 
1110fb43630cSZhang Yubing 	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
1111fb43630cSZhang Yubing 		sdp->db[17] |= 0x80;
1112fb43630cSZhang Yubing 
1113fb43630cSZhang Yubing 	sdp->db[18] = vsc->content_type & 0x7;
1114fb43630cSZhang Yubing 
1115fb43630cSZhang Yubing 	sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL;
1116fb43630cSZhang Yubing }
1117fb43630cSZhang Yubing 
1118fb43630cSZhang Yubing static int dw_dp_send_vsc_sdp(struct dw_dp *dp)
1119fb43630cSZhang Yubing {
1120fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1121fb43630cSZhang Yubing 	struct drm_dp_vsc_sdp vsc = {};
1122fb43630cSZhang Yubing 	struct dw_dp_sdp sdp = {};
1123fb43630cSZhang Yubing 
1124fb43630cSZhang Yubing 	vsc.revision = 0x5;
1125fb43630cSZhang Yubing 	vsc.length = 0x13;
1126fb43630cSZhang Yubing 
1127fb43630cSZhang Yubing 	switch (video->color_format) {
1128fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1129fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV444;
1130fb43630cSZhang Yubing 		break;
1131fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1132fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV420;
1133fb43630cSZhang Yubing 		break;
1134fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1135fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_YUV422;
1136fb43630cSZhang Yubing 		break;
1137fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1138fb43630cSZhang Yubing 	default:
1139fb43630cSZhang Yubing 		vsc.pixelformat = DP_PIXELFORMAT_RGB;
1140fb43630cSZhang Yubing 		break;
1141fb43630cSZhang Yubing 	}
1142fb43630cSZhang Yubing 
1143fb43630cSZhang Yubing 	if (video->color_format == DRM_COLOR_FORMAT_RGB444)
1144fb43630cSZhang Yubing 		vsc.colorimetry = DP_COLORIMETRY_DEFAULT;
1145fb43630cSZhang Yubing 	else
1146fb43630cSZhang Yubing 		vsc.colorimetry = DP_COLORIMETRY_BT709_YCC;
1147fb43630cSZhang Yubing 
1148fb43630cSZhang Yubing 	vsc.bpc = video->bpc;
1149fb43630cSZhang Yubing 	vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA;
1150fb43630cSZhang Yubing 	vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED;
1151fb43630cSZhang Yubing 
1152fb43630cSZhang Yubing 	dw_dp_vsc_sdp_pack(&vsc, &sdp);
1153fb43630cSZhang Yubing 
1154fb43630cSZhang Yubing 	return dw_dp_send_sdp(dp, &sdp);
1155fb43630cSZhang Yubing }
1156fb43630cSZhang Yubing 
1157fb43630cSZhang Yubing static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode)
1158fb43630cSZhang Yubing {
1159fb43630cSZhang Yubing 	switch (pixel_mode) {
1160fb43630cSZhang Yubing 	case DPTX_MP_SINGLE_PIXEL:
1161fb43630cSZhang Yubing 	case DPTX_MP_DUAL_PIXEL:
1162fb43630cSZhang Yubing 	case DPTX_MP_QUAD_PIXEL:
1163fb43630cSZhang Yubing 		break;
1164fb43630cSZhang Yubing 	default:
1165fb43630cSZhang Yubing 		return -EINVAL;
1166fb43630cSZhang Yubing 	}
1167fb43630cSZhang Yubing 
1168fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT,
1169fb43630cSZhang Yubing 			   FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode));
1170fb43630cSZhang Yubing 
1171fb43630cSZhang Yubing 	return 0;
1172fb43630cSZhang Yubing }
1173fb43630cSZhang Yubing 
1174fb43630cSZhang Yubing static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc,
1175fb43630cSZhang Yubing 			       u16 vstart, u16 hstart)
1176fb43630cSZhang Yubing {
1177fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1178fb43630cSZhang Yubing 	u16 misc = 0;
1179fb43630cSZhang Yubing 
1180fb43630cSZhang Yubing 	if (link->vsc_sdp_extension_for_colorimetry_supported)
1181fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_VSC_SDP;
1182fb43630cSZhang Yubing 
1183fb43630cSZhang Yubing 	switch (color_format) {
1184fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1185fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_RGB;
1186fb43630cSZhang Yubing 		break;
1187fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1188fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709;
1189fb43630cSZhang Yubing 		break;
1190fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1191fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709;
1192fb43630cSZhang Yubing 		break;
1193fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1194fb43630cSZhang Yubing 		break;
1195fb43630cSZhang Yubing 	default:
1196fb43630cSZhang Yubing 		return -EINVAL;
1197fb43630cSZhang Yubing 	}
1198fb43630cSZhang Yubing 
1199fb43630cSZhang Yubing 	switch (bpc) {
1200fb43630cSZhang Yubing 	case 6:
1201fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_6_BPC;
1202fb43630cSZhang Yubing 		break;
1203fb43630cSZhang Yubing 	case 8:
1204fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_8_BPC;
1205fb43630cSZhang Yubing 		break;
1206fb43630cSZhang Yubing 	case 10:
1207fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_10_BPC;
1208fb43630cSZhang Yubing 		break;
1209fb43630cSZhang Yubing 	case 12:
1210fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_12_BPC;
1211fb43630cSZhang Yubing 		break;
1212fb43630cSZhang Yubing 	case 16:
1213fb43630cSZhang Yubing 		misc |= DP_MSA_MISC_16_BPC;
1214fb43630cSZhang Yubing 		break;
1215fb43630cSZhang Yubing 	default:
1216fb43630cSZhang Yubing 		return -EINVAL;
1217fb43630cSZhang Yubing 	}
1218fb43630cSZhang Yubing 
1219fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA1,
1220fb43630cSZhang Yubing 		     FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart));
1221fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc));
1222fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8));
1223fb43630cSZhang Yubing 
1224fb43630cSZhang Yubing 	return 0;
1225fb43630cSZhang Yubing }
1226fb43630cSZhang Yubing 
1227fb43630cSZhang Yubing static int dw_dp_video_enable(struct dw_dp *dp)
1228fb43630cSZhang Yubing {
1229fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1230fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1231fb43630cSZhang Yubing 	struct drm_display_mode *mode = &video->mode;
1232fb43630cSZhang Yubing 	u8 color_format = video->color_format;
1233fb43630cSZhang Yubing 	u8 bpc = video->bpc;
1234fb43630cSZhang Yubing 	u8 pixel_mode = video->pixel_mode;
1235fb43630cSZhang Yubing 	u8 bpp = video->bpp, init_threshold, vic;
1236fb43630cSZhang Yubing 	u32 hactive, hblank, h_sync_width, h_front_porch;
1237fb43630cSZhang Yubing 	u32 vactive, vblank, v_sync_width, v_front_porch;
1238fb43630cSZhang Yubing 	u32 vstart = mode->vtotal - mode->vsync_start;
1239fb43630cSZhang Yubing 	u32 hstart = mode->htotal - mode->hsync_start;
1240fb43630cSZhang Yubing 	u32 peak_stream_bandwidth, link_bandwidth;
1241fb43630cSZhang Yubing 	u32 average_bytes_per_tu, average_bytes_per_tu_frac;
1242fb43630cSZhang Yubing 	u32 ts, hblank_interval;
1243fb43630cSZhang Yubing 	u32 value;
1244fb43630cSZhang Yubing 	int ret;
1245fb43630cSZhang Yubing 
1246fb43630cSZhang Yubing 	ret = dw_dp_video_set_pixel_mode(dp, pixel_mode);
1247fb43630cSZhang Yubing 	if (ret)
1248fb43630cSZhang Yubing 		return ret;
1249fb43630cSZhang Yubing 
1250fb43630cSZhang Yubing 	ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart);
1251fb43630cSZhang Yubing 	if (ret)
1252fb43630cSZhang Yubing 		return ret;
1253fb43630cSZhang Yubing 
1254fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING,
1255fb43630cSZhang Yubing 			   FIELD_PREP(VIDEO_MAPPING, video->video_mapping));
1256fb43630cSZhang Yubing 
1257fb43630cSZhang Yubing 	/* Configure DPTX_VINPUT_POLARITY_CTRL register */
1258fb43630cSZhang Yubing 	value = 0;
1259fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1260fb43630cSZhang Yubing 		value |= FIELD_PREP(HSYNC_IN_POLARITY, 1);
1261fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1262fb43630cSZhang Yubing 		value |= FIELD_PREP(VSYNC_IN_POLARITY, 1);
1263fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value);
1264fb43630cSZhang Yubing 
1265fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG1 register */
1266fb43630cSZhang Yubing 	hactive = mode->hdisplay;
1267fb43630cSZhang Yubing 	hblank = mode->htotal - mode->hdisplay;
1268fb43630cSZhang Yubing 	value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank);
1269fb43630cSZhang Yubing 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1270fb43630cSZhang Yubing 		value |= FIELD_PREP(I_P, 1);
1271fb43630cSZhang Yubing 	vic = drm_match_cea_mode(mode);
1272fb43630cSZhang Yubing 	if (vic == 5 || vic == 6 || vic == 7 ||
1273fb43630cSZhang Yubing 	    vic == 10 || vic == 11 || vic == 20 ||
1274fb43630cSZhang Yubing 	    vic == 21 || vic == 22 || vic == 39 ||
1275fb43630cSZhang Yubing 	    vic == 25 || vic == 26 || vic == 40 ||
1276fb43630cSZhang Yubing 	    vic == 44 || vic == 45 || vic == 46 ||
1277fb43630cSZhang Yubing 	    vic == 50 || vic == 51 || vic == 54 ||
1278fb43630cSZhang Yubing 	    vic == 55 || vic == 58 || vic  == 59)
1279fb43630cSZhang Yubing 		value |= R_V_BLANK_IN_OSC;
1280fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value);
1281fb43630cSZhang Yubing 
1282fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG2 register */
1283fb43630cSZhang Yubing 	vblank = mode->vtotal - mode->vdisplay;
1284fb43630cSZhang Yubing 	vactive = mode->vdisplay;
1285fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2,
1286fb43630cSZhang Yubing 		     FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive));
1287fb43630cSZhang Yubing 
1288fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG3 register */
1289fb43630cSZhang Yubing 	h_sync_width = mode->hsync_end - mode->hsync_start;
1290fb43630cSZhang Yubing 	h_front_porch = mode->hsync_start - mode->hdisplay;
1291fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3,
1292fb43630cSZhang Yubing 		     FIELD_PREP(H_SYNC_WIDTH, h_sync_width) |
1293fb43630cSZhang Yubing 		     FIELD_PREP(H_FRONT_PORCH, h_front_porch));
1294fb43630cSZhang Yubing 
1295fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG4 register */
1296fb43630cSZhang Yubing 	v_sync_width = mode->vsync_end - mode->vsync_start;
1297fb43630cSZhang Yubing 	v_front_porch = mode->vsync_start - mode->vdisplay;
1298fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4,
1299fb43630cSZhang Yubing 		     FIELD_PREP(V_SYNC_WIDTH, v_sync_width) |
1300fb43630cSZhang Yubing 		     FIELD_PREP(V_FRONT_PORCH, v_front_porch));
1301fb43630cSZhang Yubing 
1302fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_CONFIG5 register */
1303fb43630cSZhang Yubing 	peak_stream_bandwidth = mode->clock * bpp / 8;
1304fb43630cSZhang Yubing 	link_bandwidth = (link->rate / 1000) * link->lanes;
1305fb43630cSZhang Yubing 	ts = peak_stream_bandwidth * 64 / link_bandwidth;
1306fb43630cSZhang Yubing 	average_bytes_per_tu = ts / 1000;
1307fb43630cSZhang Yubing 	average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10;
1308fb43630cSZhang Yubing 	if (pixel_mode == DPTX_MP_SINGLE_PIXEL) {
1309fb43630cSZhang Yubing 		if (average_bytes_per_tu < 6)
1310fb43630cSZhang Yubing 			init_threshold = 32;
1311fb43630cSZhang Yubing 		else if (hblank <= 80 &&
1312fb43630cSZhang Yubing 			 color_format != DRM_COLOR_FORMAT_YCRCB420)
1313fb43630cSZhang Yubing 			init_threshold = 12;
1314fb43630cSZhang Yubing 		else if (hblank <= 40 &&
1315fb43630cSZhang Yubing 			 color_format == DRM_COLOR_FORMAT_YCRCB420)
1316fb43630cSZhang Yubing 			init_threshold = 3;
1317fb43630cSZhang Yubing 		else
1318fb43630cSZhang Yubing 			init_threshold = 16;
1319fb43630cSZhang Yubing 	} else {
1320fb43630cSZhang Yubing 		u32 t1 = 0, t2 = 0, t3 = 0;
1321fb43630cSZhang Yubing 
1322fb43630cSZhang Yubing 		switch (bpc) {
1323fb43630cSZhang Yubing 		case 6:
1324fb43630cSZhang Yubing 			t1 = (4 * 1000 / 9) * link->lanes;
1325fb43630cSZhang Yubing 			break;
1326fb43630cSZhang Yubing 		case 8:
1327fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1328fb43630cSZhang Yubing 				t1 = (1000 / 2) * link->lanes;
1329fb43630cSZhang Yubing 			} else {
1330fb43630cSZhang Yubing 				if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1331fb43630cSZhang Yubing 					t1 = (1000 / 3) * link->lanes;
1332fb43630cSZhang Yubing 				else
1333fb43630cSZhang Yubing 					t1 = (3000 / 16) * link->lanes;
1334fb43630cSZhang Yubing 			}
1335fb43630cSZhang Yubing 			break;
1336fb43630cSZhang Yubing 		case 10:
1337fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422)
1338fb43630cSZhang Yubing 				t1 = (2000 / 5) * link->lanes;
1339fb43630cSZhang Yubing 			else
1340fb43630cSZhang Yubing 				t1 = (4000 / 15) * link->lanes;
1341fb43630cSZhang Yubing 			break;
1342fb43630cSZhang Yubing 		case 12:
1343fb43630cSZhang Yubing 			if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1344fb43630cSZhang Yubing 				if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1345fb43630cSZhang Yubing 					t1 = (1000 / 6) * link->lanes;
1346fb43630cSZhang Yubing 				else
1347fb43630cSZhang Yubing 					t1 = (1000 / 3) * link->lanes;
1348fb43630cSZhang Yubing 			} else {
1349fb43630cSZhang Yubing 				t1 = (2000 / 9) * link->lanes;
1350fb43630cSZhang Yubing 			}
1351fb43630cSZhang Yubing 			break;
1352fb43630cSZhang Yubing 		case 16:
1353fb43630cSZhang Yubing 			if (color_format != DRM_COLOR_FORMAT_YCRCB422 &&
1354fb43630cSZhang Yubing 			    pixel_mode == DPTX_MP_DUAL_PIXEL)
1355fb43630cSZhang Yubing 				t1 = (1000 / 6) * link->lanes;
1356fb43630cSZhang Yubing 			else
1357fb43630cSZhang Yubing 				t1 = (1000 / 4) * link->lanes;
1358fb43630cSZhang Yubing 			break;
1359fb43630cSZhang Yubing 		default:
1360fb43630cSZhang Yubing 			return -EINVAL;
1361fb43630cSZhang Yubing 		}
1362fb43630cSZhang Yubing 
1363fb43630cSZhang Yubing 		if (color_format == DRM_COLOR_FORMAT_YCRCB420)
1364fb43630cSZhang Yubing 			t2 = (link->rate / 4) * 1000 / (mode->clock / 2);
1365fb43630cSZhang Yubing 		else
1366fb43630cSZhang Yubing 			t2 = (link->rate / 4) * 1000 / mode->clock;
1367fb43630cSZhang Yubing 
1368fb43630cSZhang Yubing 		if (average_bytes_per_tu_frac)
1369fb43630cSZhang Yubing 			t3 = average_bytes_per_tu + 1;
1370fb43630cSZhang Yubing 		else
1371fb43630cSZhang Yubing 			t3 = average_bytes_per_tu;
1372fb43630cSZhang Yubing 		init_threshold = t1 * t2 * t3 / (1000 * 1000);
1373fb43630cSZhang Yubing 		if (init_threshold <= 16 || average_bytes_per_tu < 10)
1374fb43630cSZhang Yubing 			init_threshold = 40;
1375fb43630cSZhang Yubing 	}
1376fb43630cSZhang Yubing 
1377fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5,
1378fb43630cSZhang Yubing 		     FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) |
1379fb43630cSZhang Yubing 		     FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC,
1380fb43630cSZhang Yubing 				average_bytes_per_tu_frac) |
1381fb43630cSZhang Yubing 		     FIELD_PREP(INIT_THRESHOLD, init_threshold) |
1382fb43630cSZhang Yubing 		     FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu));
1383fb43630cSZhang Yubing 
1384fb43630cSZhang Yubing 	/* Configure DPTX_VIDEO_HBLANK_INTERVAL register */
1385fb43630cSZhang Yubing 	hblank_interval = hblank * (link->rate / 4) / mode->clock;
1386fb43630cSZhang Yubing 	regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL,
1387fb43630cSZhang Yubing 		     FIELD_PREP(HBLANK_INTERVAL_EN, 1) |
1388fb43630cSZhang Yubing 		     FIELD_PREP(HBLANK_INTERVAL, hblank_interval));
1389fb43630cSZhang Yubing 
1390fb43630cSZhang Yubing 	/* Video stream enable */
1391fb43630cSZhang Yubing 	regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,
1392fb43630cSZhang Yubing 			   FIELD_PREP(VIDEO_STREAM_ENABLE, 1));
1393fb43630cSZhang Yubing 
1394fb43630cSZhang Yubing 	if (link->vsc_sdp_extension_for_colorimetry_supported)
1395fb43630cSZhang Yubing 		dw_dp_send_vsc_sdp(dp);
1396fb43630cSZhang Yubing 
1397fb43630cSZhang Yubing 	return 0;
1398fb43630cSZhang Yubing }
1399fb43630cSZhang Yubing 
1400fb43630cSZhang Yubing static bool dw_dp_detect(struct dw_dp *dp)
1401fb43630cSZhang Yubing {
1402fb43630cSZhang Yubing 	u32 value;
1403fb43630cSZhang Yubing 
1404fb43630cSZhang Yubing 	if (dm_gpio_is_valid(&dp->hpd_gpio))
1405fb43630cSZhang Yubing 		return dm_gpio_get_value(&dp->hpd_gpio);
1406fb43630cSZhang Yubing 
1407fb43630cSZhang Yubing 	regmap_read(dp->regmap, DPTX_HPD_STATUS, &value);
14085fbef17aSZhang Yubing 	if (FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG) {
1409fb43630cSZhang Yubing 		regmap_write(dp->regmap, DPTX_HPD_STATUS, HPD_HOT_PLUG);
1410fb43630cSZhang Yubing 		return true;
1411fb43630cSZhang Yubing 	}
1412fb43630cSZhang Yubing 
1413fb43630cSZhang Yubing 	return false;
1414fb43630cSZhang Yubing }
1415fb43630cSZhang Yubing 
14167ac3c934SZhang Yubing static struct dw_dp *connector_to_dw_dp(struct rockchip_connector *conn)
14177ac3c934SZhang Yubing {
14187ac3c934SZhang Yubing 	struct dw_dp *dp;
14197ac3c934SZhang Yubing 
14207ac3c934SZhang Yubing 	if (dev_get_priv(conn->dev))
14217ac3c934SZhang Yubing 		dp = dev_get_priv(conn->dev);
14227ac3c934SZhang Yubing 	else
14237ac3c934SZhang Yubing 		dp = dev_get_priv(conn->dev->parent);
14247ac3c934SZhang Yubing 
14257ac3c934SZhang Yubing 	return dp;
14267ac3c934SZhang Yubing }
14277ac3c934SZhang Yubing 
14280594ce39SZhang Yubing static int dw_dp_connector_init(struct rockchip_connector *conn, struct display_state *state)
1429fb43630cSZhang Yubing {
1430fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
14317ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
1432fb43630cSZhang Yubing 	int ret;
1433fb43630cSZhang Yubing 
14347ac3c934SZhang Yubing 	if (dev_get_priv(conn->dev))
14357ac3c934SZhang Yubing 		dp  = dev_get_priv(conn->dev);
14367ac3c934SZhang Yubing 	else
14377ac3c934SZhang Yubing 		dp = dev_get_priv(conn->dev->parent);
1438fb43630cSZhang Yubing 	conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0;
1439fb43630cSZhang Yubing 	conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1440df0a5c43SDamon Ding 	conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
1441fb43630cSZhang Yubing 
1442fb43630cSZhang Yubing 	clk_set_defaults(dp->dev);
1443fb43630cSZhang Yubing 
1444fb43630cSZhang Yubing 	reset_assert(&dp->reset);
1445fb43630cSZhang Yubing 	udelay(20);
1446fb43630cSZhang Yubing 	reset_deassert(&dp->reset);
1447fb43630cSZhang Yubing 
1448fb43630cSZhang Yubing 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type,
1449fb43630cSZhang Yubing 							dp->id);
1450fb43630cSZhang Yubing 	dw_dp_init(dp);
1451fb43630cSZhang Yubing 	ret = generic_phy_power_on(&dp->phy);
1452fb43630cSZhang Yubing 
1453fb43630cSZhang Yubing 	return ret;
1454fb43630cSZhang Yubing }
1455fb43630cSZhang Yubing 
14560594ce39SZhang Yubing static int dw_dp_connector_get_edid(struct rockchip_connector *conn, struct display_state *state)
1457fb43630cSZhang Yubing {
1458fb43630cSZhang Yubing 	int ret;
1459fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
14607ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
1461fb43630cSZhang Yubing 
1462*9c170041SAlgea Cao 	conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
1463*9c170041SAlgea Cao 	if (!conn_state->edid)
1464*9c170041SAlgea Cao 		ret = -EINVAL;
1465fb43630cSZhang Yubing 
1466fb43630cSZhang Yubing 	return ret;
1467fb43630cSZhang Yubing }
1468fb43630cSZhang Yubing 
14691cf3aaecSZhang Yubing static int dw_dp_get_output_fmts_index(u32 bus_format)
14701cf3aaecSZhang Yubing {
14711cf3aaecSZhang Yubing 	int i;
14721cf3aaecSZhang Yubing 
14731cf3aaecSZhang Yubing 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
14741cf3aaecSZhang Yubing 		const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
14751cf3aaecSZhang Yubing 
14761cf3aaecSZhang Yubing 		if (fmt->bus_format == bus_format)
14771cf3aaecSZhang Yubing 			break;
14781cf3aaecSZhang Yubing 	}
14791cf3aaecSZhang Yubing 
14801cf3aaecSZhang Yubing 	if (i == ARRAY_SIZE(possible_output_fmts))
14811cf3aaecSZhang Yubing 		return 1;
14821cf3aaecSZhang Yubing 
14831cf3aaecSZhang Yubing 	return i;
14841cf3aaecSZhang Yubing }
14851cf3aaecSZhang Yubing 
14860594ce39SZhang Yubing static int dw_dp_connector_prepare(struct rockchip_connector *conn, struct display_state *state)
14871cf3aaecSZhang Yubing {
14881cf3aaecSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
14897ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
14901cf3aaecSZhang Yubing 	struct dw_dp_video *video = &dp->video;
14911cf3aaecSZhang Yubing 	int bus_fmt;
14921cf3aaecSZhang Yubing 
14931cf3aaecSZhang Yubing 	bus_fmt = dw_dp_get_output_fmts_index(conn_state->bus_format);
14941cf3aaecSZhang Yubing 	video->video_mapping = possible_output_fmts[bus_fmt].video_mapping;
14951cf3aaecSZhang Yubing 	video->color_format = possible_output_fmts[bus_fmt].color_format;
14961cf3aaecSZhang Yubing 	video->bus_format = possible_output_fmts[bus_fmt].bus_format;
14971cf3aaecSZhang Yubing 	video->bpc = possible_output_fmts[bus_fmt].bpc;
14981cf3aaecSZhang Yubing 	video->bpp = possible_output_fmts[bus_fmt].bpp;
14991cf3aaecSZhang Yubing 
15001cf3aaecSZhang Yubing 	return 0;
15011cf3aaecSZhang Yubing }
15021cf3aaecSZhang Yubing 
15030594ce39SZhang Yubing static int dw_dp_connector_enable(struct rockchip_connector *conn, struct display_state *state)
1504fb43630cSZhang Yubing {
1505fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
1506fb43630cSZhang Yubing 	struct drm_display_mode *mode = &conn_state->mode;
15077ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
1508fb43630cSZhang Yubing 	struct dw_dp_video *video = &dp->video;
1509fb43630cSZhang Yubing 	int ret;
1510fb43630cSZhang Yubing 
1511fb43630cSZhang Yubing 	memcpy(&video->mode, mode, sizeof(video->mode));
1512fb43630cSZhang Yubing 
15135efdd3e2SZhang Yubing 	if (dp->force_output) {
15145efdd3e2SZhang Yubing 		ret = dw_dp_set_phy_default_config(dp);
15155efdd3e2SZhang Yubing 		if (ret < 0)
15165efdd3e2SZhang Yubing 			printf("failed to set phy_default config: %d\n", ret);
15175efdd3e2SZhang Yubing 	} else {
1518fb43630cSZhang Yubing 		ret = dw_dp_link_enable(dp);
1519fb43630cSZhang Yubing 		if (ret < 0) {
15205efdd3e2SZhang Yubing 			printf("failed to enable link: %d\n", ret);
1521fb43630cSZhang Yubing 			return ret;
1522fb43630cSZhang Yubing 		}
15235efdd3e2SZhang Yubing 	}
1524fb43630cSZhang Yubing 
1525fb43630cSZhang Yubing 	ret = dw_dp_video_enable(dp);
1526fb43630cSZhang Yubing 	if (ret < 0) {
15275efdd3e2SZhang Yubing 		printf("failed to enable video: %d\n", ret);
1528fb43630cSZhang Yubing 		return ret;
1529fb43630cSZhang Yubing 	}
1530fb43630cSZhang Yubing 
1531fb43630cSZhang Yubing 	return 0;
1532fb43630cSZhang Yubing }
1533fb43630cSZhang Yubing 
15340594ce39SZhang Yubing static int dw_dp_connector_disable(struct rockchip_connector *conn, struct display_state *state)
1535fb43630cSZhang Yubing {
1536fb43630cSZhang Yubing 	/* TODO */
1537fb43630cSZhang Yubing 
1538fb43630cSZhang Yubing 	return 0;
1539fb43630cSZhang Yubing }
1540fb43630cSZhang Yubing 
15410594ce39SZhang Yubing static int dw_dp_connector_detect(struct rockchip_connector *conn, struct display_state *state)
1542fb43630cSZhang Yubing {
15437ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
15441cf3aaecSZhang Yubing 	int status, tries, ret;
1545fb43630cSZhang Yubing 
1546a66bd69eSZhang Yubing 	for (tries = 0; tries < 200; tries++) {
1547fb43630cSZhang Yubing 		status = dw_dp_detect(dp);
1548fb43630cSZhang Yubing 		if (status)
1549fb43630cSZhang Yubing 			break;
1550fb43630cSZhang Yubing 		mdelay(2);
1551fb43630cSZhang Yubing 	}
1552fb43630cSZhang Yubing 
15535efdd3e2SZhang Yubing 	if (state->force_output && !status)
15545efdd3e2SZhang Yubing 		dp->force_output = true;
15555efdd3e2SZhang Yubing 
15565efdd3e2SZhang Yubing 	if (!status && !dp->force_output)
1557fb43630cSZhang Yubing 		generic_phy_power_off(&dp->phy);
1558fb43630cSZhang Yubing 
15591cf3aaecSZhang Yubing 	if (status && !dp->force_output) {
15601cf3aaecSZhang Yubing 		ret = dw_dp_link_probe(dp);
15611cf3aaecSZhang Yubing 		if (ret)
15621cf3aaecSZhang Yubing 			printf("failed to probe DP link: %d\n", ret);
15631cf3aaecSZhang Yubing 	}
15641cf3aaecSZhang Yubing 
1565fb43630cSZhang Yubing 	return status;
1566fb43630cSZhang Yubing }
1567fb43630cSZhang Yubing 
1568fb43630cSZhang Yubing static int dw_dp_mode_valid(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1569fb43630cSZhang Yubing {
1570fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1571fb43630cSZhang Yubing 	struct drm_display_info *di = &edid_data->display_info;
1572fb43630cSZhang Yubing 	u32 min_bpp;
1573fb43630cSZhang Yubing 	int i;
1574fb43630cSZhang Yubing 
1575fb43630cSZhang Yubing 	if (di->color_formats & DRM_COLOR_FORMAT_YCRCB420 &&
1576fb43630cSZhang Yubing 	    link->vsc_sdp_extension_for_colorimetry_supported)
1577fb43630cSZhang Yubing 		min_bpp = 12;
1578fb43630cSZhang Yubing 	else if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1579fb43630cSZhang Yubing 		min_bpp = 16;
1580fb43630cSZhang Yubing 	else if (di->color_formats & DRM_COLOR_FORMAT_RGB444)
1581fb43630cSZhang Yubing 		min_bpp = 18;
1582fb43630cSZhang Yubing 	else
1583fb43630cSZhang Yubing 		min_bpp = 24;
1584fb43630cSZhang Yubing 
1585fb43630cSZhang Yubing 	for (i = 0; i < edid_data->modes; i++) {
1586fb43630cSZhang Yubing 		if (!dw_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, link->lanes,
1587fb43630cSZhang Yubing 					link->rate))
1588fb43630cSZhang Yubing 			edid_data->mode_buf[i].invalid = true;
1589fb43630cSZhang Yubing 	}
1590fb43630cSZhang Yubing 
1591fb43630cSZhang Yubing 	return 0;
1592fb43630cSZhang Yubing }
1593fb43630cSZhang Yubing 
1594fb43630cSZhang Yubing static u32 dw_dp_get_output_bus_fmts(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1595fb43630cSZhang Yubing {
1596fb43630cSZhang Yubing 	struct dw_dp_link *link = &dp->link;
1597fb43630cSZhang Yubing 	unsigned int i;
1598fb43630cSZhang Yubing 
1599fb43630cSZhang Yubing 	for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
1600fb43630cSZhang Yubing 		const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
1601fb43630cSZhang Yubing 
1602fb43630cSZhang Yubing 		if (fmt->bpc > edid_data->display_info.bpc)
1603fb43630cSZhang Yubing 			continue;
1604fb43630cSZhang Yubing 
1605fb43630cSZhang Yubing 		if (!(edid_data->display_info.color_formats & fmt->color_format))
1606fb43630cSZhang Yubing 			continue;
1607fb43630cSZhang Yubing 
1608fb43630cSZhang Yubing 		if (fmt->color_format == DRM_COLOR_FORMAT_YCRCB420 &&
1609fb43630cSZhang Yubing 		    !link->vsc_sdp_extension_for_colorimetry_supported)
1610fb43630cSZhang Yubing 			continue;
1611fb43630cSZhang Yubing 
1612fb43630cSZhang Yubing 		if (drm_mode_is_420(&edid_data->display_info, edid_data->preferred_mode) &&
1613fb43630cSZhang Yubing 		    fmt->color_format != DRM_COLOR_FORMAT_YCRCB420)
1614fb43630cSZhang Yubing 			continue;
1615fb43630cSZhang Yubing 
1616fb43630cSZhang Yubing 		if (!dw_dp_bandwidth_ok(dp, edid_data->preferred_mode, fmt->bpp, link->lanes,
1617fb43630cSZhang Yubing 					link->rate))
1618fb43630cSZhang Yubing 			continue;
1619fb43630cSZhang Yubing 
1620fb43630cSZhang Yubing 		break;
1621fb43630cSZhang Yubing 	}
1622fb43630cSZhang Yubing 
1623fb43630cSZhang Yubing 	if (i == ARRAY_SIZE(possible_output_fmts))
1624fb43630cSZhang Yubing 		return 1;
1625fb43630cSZhang Yubing 
1626fb43630cSZhang Yubing 	return i;
1627fb43630cSZhang Yubing }
1628fb43630cSZhang Yubing 
16290594ce39SZhang Yubing static int dw_dp_connector_get_timing(struct rockchip_connector *conn, struct display_state *state)
1630fb43630cSZhang Yubing {
1631*9c170041SAlgea Cao 	int ret = 0, i;
1632fb43630cSZhang Yubing 	struct connector_state *conn_state = &state->conn_state;
16337ac3c934SZhang Yubing 	struct dw_dp *dp = connector_to_dw_dp(conn);
1634fb43630cSZhang Yubing 	struct drm_display_mode *mode = &conn_state->mode;
1635fb43630cSZhang Yubing 	struct hdmi_edid_data edid_data;
1636fb43630cSZhang Yubing 	struct drm_display_mode *mode_buf;
1637364352d1SZhang Yubing 	struct vop_rect rect;
1638fb43630cSZhang Yubing 	u32 bus_fmt;
1639fb43630cSZhang Yubing 
1640fb43630cSZhang Yubing 	mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
1641fb43630cSZhang Yubing 	if (!mode_buf)
1642fb43630cSZhang Yubing 		return -ENOMEM;
1643fb43630cSZhang Yubing 
1644fb43630cSZhang Yubing 	memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
1645fb43630cSZhang Yubing 	memset(&edid_data, 0, sizeof(struct hdmi_edid_data));
1646fb43630cSZhang Yubing 	edid_data.mode_buf = mode_buf;
1647fb43630cSZhang Yubing 
16485efdd3e2SZhang Yubing 	if (!dp->force_output) {
1649*9c170041SAlgea Cao 		conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
1650*9c170041SAlgea Cao 		if (conn_state->edid)
1651fb43630cSZhang Yubing 			ret = drm_add_edid_modes(&edid_data, conn_state->edid);
1652fb43630cSZhang Yubing 
1653*9c170041SAlgea Cao 		if (ret <= 0) {
1654fb43630cSZhang Yubing 			printf("failed to get edid\n");
1655fb43630cSZhang Yubing 			goto err;
1656fb43630cSZhang Yubing 		}
1657fb43630cSZhang Yubing 
16587ac3c934SZhang Yubing 		//drm_rk_filter_whitelist(&edid_data);
1659364352d1SZhang Yubing 		if (state->conn_state.secondary) {
1660364352d1SZhang Yubing 			rect.width = state->crtc_state.max_output.width / 2;
1661364352d1SZhang Yubing 			rect.height = state->crtc_state.max_output.height / 2;
1662364352d1SZhang Yubing 		} else {
1663364352d1SZhang Yubing 			rect.width = state->crtc_state.max_output.width;
1664364352d1SZhang Yubing 			rect.height = state->crtc_state.max_output.height;
1665364352d1SZhang Yubing 		}
1666364352d1SZhang Yubing 
1667364352d1SZhang Yubing 		drm_mode_max_resolution_filter(&edid_data, &rect);
1668fb43630cSZhang Yubing 		dw_dp_mode_valid(dp, &edid_data);
1669fb43630cSZhang Yubing 
1670fb43630cSZhang Yubing 		if (!drm_mode_prune_invalid(&edid_data)) {
16714f1d0c46SZhang Yubing 			printf("can't find valid dp mode\n");
1672fb43630cSZhang Yubing 			ret = -EINVAL;
1673fb43630cSZhang Yubing 			goto err;
1674fb43630cSZhang Yubing 		}
1675fb43630cSZhang Yubing 
1676fb43630cSZhang Yubing 		for (i = 0; i < edid_data.modes; i++)
1677fb43630cSZhang Yubing 			edid_data.mode_buf[i].vrefresh =
1678fb43630cSZhang Yubing 				drm_mode_vrefresh(&edid_data.mode_buf[i]);
1679fb43630cSZhang Yubing 
1680fb43630cSZhang Yubing 		drm_mode_sort(&edid_data);
1681fb43630cSZhang Yubing 		memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode));
16825efdd3e2SZhang Yubing 	}
1683fb43630cSZhang Yubing 
1684fb43630cSZhang Yubing 	if (state->force_output)
16851cf3aaecSZhang Yubing 		bus_fmt = dw_dp_get_output_fmts_index(state->force_bus_format);
1686fb43630cSZhang Yubing 	else
1687fb43630cSZhang Yubing 		bus_fmt = dw_dp_get_output_bus_fmts(dp, &edid_data);
1688fb43630cSZhang Yubing 
16891cf3aaecSZhang Yubing 	conn_state->bus_format = possible_output_fmts[bus_fmt].bus_format;
1690fb43630cSZhang Yubing 
16911cf3aaecSZhang Yubing 	switch (possible_output_fmts[bus_fmt].color_format) {
1692fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB420:
1693fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
1694fb43630cSZhang Yubing 		break;
1695fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB422:
1696fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
1697fb43630cSZhang Yubing 		break;
1698fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_RGB444:
1699fb43630cSZhang Yubing 	case DRM_COLOR_FORMAT_YCRCB444:
1700fb43630cSZhang Yubing 	default:
1701fb43630cSZhang Yubing 		conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1702fb43630cSZhang Yubing 		break;
1703fb43630cSZhang Yubing 	}
1704fb43630cSZhang Yubing 
1705fb43630cSZhang Yubing err:
1706fb43630cSZhang Yubing 	free(mode_buf);
1707fb43630cSZhang Yubing 
1708fb43630cSZhang Yubing 	return 0;
1709fb43630cSZhang Yubing }
1710fb43630cSZhang Yubing 
1711fb43630cSZhang Yubing static const struct rockchip_connector_funcs dw_dp_connector_funcs = {
1712fb43630cSZhang Yubing 	.init = dw_dp_connector_init,
1713fb43630cSZhang Yubing 	.get_edid = dw_dp_connector_get_edid,
17141cf3aaecSZhang Yubing 	.prepare = dw_dp_connector_prepare,
1715fb43630cSZhang Yubing 	.enable = dw_dp_connector_enable,
1716fb43630cSZhang Yubing 	.disable = dw_dp_connector_disable,
1717fb43630cSZhang Yubing 	.detect = dw_dp_connector_detect,
1718fb43630cSZhang Yubing 	.get_timing = dw_dp_connector_get_timing,
1719fb43630cSZhang Yubing };
1720fb43630cSZhang Yubing 
1721fb43630cSZhang Yubing static int dw_dp_ddc_init(struct dw_dp *dp)
1722fb43630cSZhang Yubing {
1723fb43630cSZhang Yubing 	dp->aux.name = "dw-dp";
1724fb43630cSZhang Yubing 	dp->aux.dev = dp->dev;
1725fb43630cSZhang Yubing 	dp->aux.transfer = dw_dp_aux_transfer;
1726fb43630cSZhang Yubing 	dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer;
1727fb43630cSZhang Yubing 
1728fb43630cSZhang Yubing 	return 0;
1729fb43630cSZhang Yubing }
1730fb43630cSZhang Yubing 
1731549d42b6SWyon Bi static u32 dw_dp_parse_link_frequencies(struct dw_dp *dp)
1732549d42b6SWyon Bi {
1733549d42b6SWyon Bi 	struct udevice *dev = dp->dev;
1734549d42b6SWyon Bi 	const struct device_node *endpoint;
1735549d42b6SWyon Bi 	u64 frequency = 0;
1736549d42b6SWyon Bi 
1737549d42b6SWyon Bi 	endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0);
1738549d42b6SWyon Bi 	if (!endpoint)
1739549d42b6SWyon Bi 		return 0;
1740549d42b6SWyon Bi 
1741549d42b6SWyon Bi 	if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0)
1742549d42b6SWyon Bi 		return 0;
1743549d42b6SWyon Bi 
1744549d42b6SWyon Bi 	if (!frequency)
1745549d42b6SWyon Bi 		return 0;
1746549d42b6SWyon Bi 
1747549d42b6SWyon Bi 	do_div(frequency, 10 * 1000);	/* symbol rate kbytes */
1748549d42b6SWyon Bi 
1749549d42b6SWyon Bi 	switch (frequency) {
1750549d42b6SWyon Bi 	case 162000:
1751549d42b6SWyon Bi 	case 270000:
1752549d42b6SWyon Bi 	case 540000:
1753549d42b6SWyon Bi 	case 810000:
1754549d42b6SWyon Bi 		break;
1755549d42b6SWyon Bi 	default:
1756549d42b6SWyon Bi 		dev_err(dev, "invalid link frequency value: %llu\n", frequency);
1757549d42b6SWyon Bi 		return 0;
1758549d42b6SWyon Bi 	}
1759549d42b6SWyon Bi 
1760549d42b6SWyon Bi 	return frequency;
1761549d42b6SWyon Bi }
1762549d42b6SWyon Bi 
1763549d42b6SWyon Bi static int dw_dp_parse_dt(struct dw_dp *dp)
1764549d42b6SWyon Bi {
1765549d42b6SWyon Bi 	dp->force_hpd = dev_read_bool(dp->dev, "force-hpd");
1766549d42b6SWyon Bi 
1767549d42b6SWyon Bi 	dp->max_link_rate = dw_dp_parse_link_frequencies(dp);
1768549d42b6SWyon Bi 	if (!dp->max_link_rate)
1769549d42b6SWyon Bi 		dp->max_link_rate = 810000;
1770549d42b6SWyon Bi 
1771549d42b6SWyon Bi 	return 0;
1772549d42b6SWyon Bi }
1773549d42b6SWyon Bi 
1774fb43630cSZhang Yubing static int dw_dp_probe(struct udevice *dev)
1775fb43630cSZhang Yubing {
1776fb43630cSZhang Yubing 	struct dw_dp *dp = dev_get_priv(dev);
17775fc83b1eSZhang Yubing 	const struct dw_dp_chip_data *pdata =
17785fc83b1eSZhang Yubing 		(const struct dw_dp_chip_data *)dev_get_driver_data(dev);
1779fb43630cSZhang Yubing 	int ret;
1780fb43630cSZhang Yubing 
1781fb43630cSZhang Yubing 	ret = regmap_init_mem(dev, &dp->regmap);
1782fb43630cSZhang Yubing 	if (ret)
1783fb43630cSZhang Yubing 		return ret;
1784fb43630cSZhang Yubing 
1785fb43630cSZhang Yubing 	dp->id = of_alias_get_id(ofnode_to_np(dev->node), "dp");
1786fb43630cSZhang Yubing 	if (dp->id < 0)
1787fb43630cSZhang Yubing 		dp->id = 0;
1788fb43630cSZhang Yubing 
17895fc83b1eSZhang Yubing 	dp->video.pixel_mode = pdata->pixel_mode;
17905fc83b1eSZhang Yubing 
1791fb43630cSZhang Yubing 	ret = reset_get_by_index(dev, 0, &dp->reset);
1792fb43630cSZhang Yubing 	if (ret) {
1793fb43630cSZhang Yubing 		dev_err(dev, "failed to get reset control: %d\n", ret);
1794fb43630cSZhang Yubing 		return ret;
1795fb43630cSZhang Yubing 	}
1796fb43630cSZhang Yubing 
1797fb43630cSZhang Yubing 	ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio,
1798fb43630cSZhang Yubing 				   GPIOD_IS_IN);
1799fb43630cSZhang Yubing 	if (ret && ret != -ENOENT) {
1800fb43630cSZhang Yubing 		dev_err(dev, "failed to get hpd GPIO: %d\n", ret);
1801fb43630cSZhang Yubing 		return ret;
1802fb43630cSZhang Yubing 	}
1803fb43630cSZhang Yubing 
1804fb43630cSZhang Yubing 	generic_phy_get_by_index(dev, 0, &dp->phy);
1805fb43630cSZhang Yubing 
1806fb43630cSZhang Yubing 	dp->dev = dev;
1807fb43630cSZhang Yubing 
1808549d42b6SWyon Bi 	ret = dw_dp_parse_dt(dp);
1809549d42b6SWyon Bi 	if (ret) {
1810549d42b6SWyon Bi 		dev_err(dev, "failed to parse DT\n");
1811549d42b6SWyon Bi 		return ret;
1812549d42b6SWyon Bi 	}
1813549d42b6SWyon Bi 
1814fb43630cSZhang Yubing 	dw_dp_ddc_init(dp);
1815fb43630cSZhang Yubing 
18160594ce39SZhang Yubing 	rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL,
18170594ce39SZhang Yubing 				DRM_MODE_CONNECTOR_DisplayPort);
18180594ce39SZhang Yubing 
1819fb43630cSZhang Yubing 	return 0;
1820fb43630cSZhang Yubing }
1821fb43630cSZhang Yubing 
18227ac3c934SZhang Yubing static int dw_dp_bind(struct udevice *parent)
18237ac3c934SZhang Yubing {
18247ac3c934SZhang Yubing 	struct udevice *child;
18257ac3c934SZhang Yubing 	ofnode subnode;
18267ac3c934SZhang Yubing 	const char *node_name;
18277ac3c934SZhang Yubing 	int ret;
18287ac3c934SZhang Yubing 
18297ac3c934SZhang Yubing 	dev_for_each_subnode(subnode, parent) {
18307ac3c934SZhang Yubing 		if (!ofnode_valid(subnode)) {
18317ac3c934SZhang Yubing 			printf("%s: no subnode for %s\n", __func__, parent->name);
18327ac3c934SZhang Yubing 			return -ENXIO;
18337ac3c934SZhang Yubing 		}
18347ac3c934SZhang Yubing 
18357ac3c934SZhang Yubing 		node_name = ofnode_get_name(subnode);
18367ac3c934SZhang Yubing 		debug("%s: subnode %s\n", __func__, node_name);
18377ac3c934SZhang Yubing 
18387ac3c934SZhang Yubing 		if (!strcasecmp(node_name, "dp0")) {
18397ac3c934SZhang Yubing 			ret = device_bind_driver_to_node(parent,
18407ac3c934SZhang Yubing 							 "dw_dp_port0",
18417ac3c934SZhang Yubing 							 node_name, subnode, &child);
18427ac3c934SZhang Yubing 			if (ret) {
18437ac3c934SZhang Yubing 				printf("%s: '%s' cannot bind its driver\n",
18447ac3c934SZhang Yubing 				       __func__, node_name);
18457ac3c934SZhang Yubing 				return ret;
18467ac3c934SZhang Yubing 			}
18477ac3c934SZhang Yubing 		}
18487ac3c934SZhang Yubing 	}
18497ac3c934SZhang Yubing 
18507ac3c934SZhang Yubing 	return 0;
18517ac3c934SZhang Yubing }
18527ac3c934SZhang Yubing 
18537ac3c934SZhang Yubing static int dw_dp_port_probe(struct udevice *dev)
18547ac3c934SZhang Yubing {
18557ac3c934SZhang Yubing 	struct dw_dp *dp = dev_get_priv(dev->parent);
18567ac3c934SZhang Yubing 
18577ac3c934SZhang Yubing 	rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL,
18587ac3c934SZhang Yubing 				DRM_MODE_CONNECTOR_DisplayPort);
18597ac3c934SZhang Yubing 
18607ac3c934SZhang Yubing 	return 0;
18617ac3c934SZhang Yubing }
18627ac3c934SZhang Yubing 
18635fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3588_dp = {
18645fc83b1eSZhang Yubing 	.pixel_mode = DPTX_MP_QUAD_PIXEL,
18655fc83b1eSZhang Yubing };
18665fc83b1eSZhang Yubing 
18675fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3576_dp = {
18685fc83b1eSZhang Yubing 	.pixel_mode = DPTX_MP_DUAL_PIXEL,
18695fc83b1eSZhang Yubing };
18705fc83b1eSZhang Yubing 
1871fb43630cSZhang Yubing static const struct udevice_id dw_dp_ids[] = {
1872fb43630cSZhang Yubing 	{
18735fc83b1eSZhang Yubing 		.compatible = "rockchip,rk3576-dp",
18745fc83b1eSZhang Yubing 		.data = (ulong)&rk3576_dp,
18755fc83b1eSZhang Yubing 	},
18765fc83b1eSZhang Yubing 	{
1877fb43630cSZhang Yubing 		.compatible = "rockchip,rk3588-dp",
18785fc83b1eSZhang Yubing 		.data = (ulong)&rk3588_dp,
1879fb43630cSZhang Yubing 	},
1880fb43630cSZhang Yubing 	{}
1881fb43630cSZhang Yubing };
1882fb43630cSZhang Yubing 
18837ac3c934SZhang Yubing U_BOOT_DRIVER(dw_dp_port) = {
18847ac3c934SZhang Yubing 	.name		= "dw_dp_port0",
18857ac3c934SZhang Yubing 	.id		= UCLASS_DISPLAY,
18867ac3c934SZhang Yubing 	.probe		= dw_dp_port_probe,
18877ac3c934SZhang Yubing };
18887ac3c934SZhang Yubing 
1889fb43630cSZhang Yubing U_BOOT_DRIVER(dw_dp) = {
1890fb43630cSZhang Yubing 	.name = "dw_dp",
1891fb43630cSZhang Yubing 	.id = UCLASS_DISPLAY,
1892fb43630cSZhang Yubing 	.of_match = dw_dp_ids,
1893fb43630cSZhang Yubing 	.probe = dw_dp_probe,
18947ac3c934SZhang Yubing 	.bind = dw_dp_bind,
1895fb43630cSZhang Yubing 	.priv_auto_alloc_size = sizeof(struct dw_dp),
1896fb43630cSZhang Yubing };
1897fb43630cSZhang Yubing 
1898