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