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>
26638855e8SFinley Xiao #include <power-domain.h>
27fb43630cSZhang Yubing #include <regmap.h>
28fb43630cSZhang Yubing #include <reset.h>
29fb43630cSZhang Yubing #include <drm/drm_dp_helper.h>
30fb43630cSZhang Yubing
31fb43630cSZhang Yubing #include "rockchip_display.h"
32fb43630cSZhang Yubing #include "rockchip_crtc.h"
33fb43630cSZhang Yubing #include "rockchip_connector.h"
34fb43630cSZhang Yubing
35fb43630cSZhang Yubing #define DPTX_VERSION_NUMBER 0x0000
36fb43630cSZhang Yubing #define DPTX_VERSION_TYPE 0x0004
37fb43630cSZhang Yubing #define DPTX_ID 0x0008
38fb43630cSZhang Yubing
39fb43630cSZhang Yubing #define DPTX_CONFIG_REG1 0x0100
40fb43630cSZhang Yubing #define DPTX_CONFIG_REG2 0x0104
41fb43630cSZhang Yubing #define DPTX_CONFIG_REG3 0x0108
42fb43630cSZhang Yubing
43fb43630cSZhang Yubing #define DPTX_CCTL 0x0200
44fb43630cSZhang Yubing #define FORCE_HPD BIT(4)
45fb43630cSZhang Yubing #define DEFAULT_FAST_LINK_TRAIN_EN BIT(2)
46fb43630cSZhang Yubing #define ENHANCE_FRAMING_EN BIT(1)
47fb43630cSZhang Yubing #define SCRAMBLE_DIS BIT(0)
48fb43630cSZhang Yubing #define DPTX_SOFT_RESET_CTRL 0x0204
49fb43630cSZhang Yubing #define VIDEO_RESET BIT(5)
50fb43630cSZhang Yubing #define AUX_RESET BIT(4)
51fb43630cSZhang Yubing #define AUDIO_SAMPLER_RESET BIT(3)
52fb43630cSZhang Yubing #define PHY_SOFT_RESET BIT(1)
53fb43630cSZhang Yubing #define CONTROLLER_RESET BIT(0)
54fb43630cSZhang Yubing
55fb43630cSZhang Yubing #define DPTX_VSAMPLE_CTRL 0x0300
56fb43630cSZhang Yubing #define PIXEL_MODE_SELECT GENMASK(22, 21)
57fb43630cSZhang Yubing #define VIDEO_MAPPING GENMASK(20, 16)
58fb43630cSZhang Yubing #define VIDEO_STREAM_ENABLE BIT(5)
59fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL1 0x0304
60fb43630cSZhang Yubing #define DPTX_VSAMPLE_STUFF_CTRL2 0x0308
61fb43630cSZhang Yubing #define DPTX_VINPUT_POLARITY_CTRL 0x030c
62fb43630cSZhang Yubing #define DE_IN_POLARITY BIT(2)
63fb43630cSZhang Yubing #define HSYNC_IN_POLARITY BIT(1)
64fb43630cSZhang Yubing #define VSYNC_IN_POLARITY BIT(0)
65fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG1 0x0310
66fb43630cSZhang Yubing #define HACTIVE GENMASK(31, 16)
67fb43630cSZhang Yubing #define HBLANK GENMASK(15, 2)
68fb43630cSZhang Yubing #define I_P BIT(1)
69fb43630cSZhang Yubing #define R_V_BLANK_IN_OSC BIT(0)
70fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG2 0x0314
71fb43630cSZhang Yubing #define VBLANK GENMASK(31, 16)
72fb43630cSZhang Yubing #define VACTIVE GENMASK(15, 0)
73fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG3 0x0318
74fb43630cSZhang Yubing #define H_SYNC_WIDTH GENMASK(31, 16)
75fb43630cSZhang Yubing #define H_FRONT_PORCH GENMASK(15, 0)
76fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG4 0x031c
77fb43630cSZhang Yubing #define V_SYNC_WIDTH GENMASK(31, 16)
78fb43630cSZhang Yubing #define V_FRONT_PORCH GENMASK(15, 0)
79fb43630cSZhang Yubing #define DPTX_VIDEO_CONFIG5 0x0320
80fb43630cSZhang Yubing #define INIT_THRESHOLD_HI GENMASK(22, 21)
81fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16)
82fb43630cSZhang Yubing #define INIT_THRESHOLD GENMASK(13, 7)
83fb43630cSZhang Yubing #define AVERAGE_BYTES_PER_TU GENMASK(6, 0)
84fb43630cSZhang Yubing #define DPTX_VIDEO_MSA1 0x0324
85fb43630cSZhang Yubing #define VSTART GENMASK(31, 16)
86fb43630cSZhang Yubing #define HSTART GENMASK(15, 0)
87fb43630cSZhang Yubing #define DPTX_VIDEO_MSA2 0x0328
88fb43630cSZhang Yubing #define MISC0 GENMASK(31, 24)
89fb43630cSZhang Yubing #define DPTX_VIDEO_MSA3 0x032c
90fb43630cSZhang Yubing #define MISC1 GENMASK(31, 24)
91fb43630cSZhang Yubing #define DPTX_VIDEO_HBLANK_INTERVAL 0x0330
92fb43630cSZhang Yubing #define HBLANK_INTERVAL_EN BIT(16)
93fb43630cSZhang Yubing #define HBLANK_INTERVAL GENMASK(15, 0)
94fb43630cSZhang Yubing
95fb43630cSZhang Yubing #define DPTX_AUD_CONFIG1 0x0400
96fb43630cSZhang Yubing #define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24)
97fb43630cSZhang Yubing #define AUDIO_PACKET_ID GENMASK(23, 16)
98fb43630cSZhang Yubing #define AUDIO_MUTE BIT(15)
99fb43630cSZhang Yubing #define NUM_CHANNELS GENMASK(14, 12)
100fb43630cSZhang Yubing #define HBR_MODE_ENABLE BIT(10)
101fb43630cSZhang Yubing #define AUDIO_DATA_WIDTH GENMASK(9, 5)
102fb43630cSZhang Yubing #define AUDIO_DATA_IN_EN GENMASK(4, 1)
103fb43630cSZhang Yubing #define AUDIO_INF_SELECT BIT(0)
104fb43630cSZhang Yubing
105fb43630cSZhang Yubing #define DPTX_SDP_VERTICAL_CTRL 0x0500
106fb43630cSZhang Yubing #define EN_VERTICAL_SDP BIT(2)
107fb43630cSZhang Yubing #define EN_AUDIO_STREAM_SDP BIT(1)
108fb43630cSZhang Yubing #define EN_AUDIO_TIMESTAMP_SDP BIT(0)
109fb43630cSZhang Yubing #define DPTX_SDP_HORIZONTAL_CTRL 0x0504
110fb43630cSZhang Yubing #define EN_HORIZONTAL_SDP BIT(2)
111fb43630cSZhang Yubing #define DPTX_SDP_STATUS_REGISTER 0x0508
112fb43630cSZhang Yubing #define DPTX_SDP_MANUAL_CTRL 0x050c
113fb43630cSZhang Yubing #define DPTX_SDP_STATUS_EN 0x0510
114fb43630cSZhang Yubing
115fb43630cSZhang Yubing #define DPTX_SDP_REGISTER_BANK 0x0600
116fb43630cSZhang Yubing #define SDP_REGS GENMASK(31, 0)
117fb43630cSZhang Yubing
118fb43630cSZhang Yubing #define DPTX_PHYIF_CTRL 0x0a00
119fb43630cSZhang Yubing #define PHY_WIDTH BIT(25)
120fb43630cSZhang Yubing #define PHY_POWERDOWN GENMASK(20, 17)
121fb43630cSZhang Yubing #define PHY_BUSY GENMASK(15, 12)
122fb43630cSZhang Yubing #define SSC_DIS BIT(16)
123fb43630cSZhang Yubing #define XMIT_ENABLE GENMASK(11, 8)
124fb43630cSZhang Yubing #define PHY_LANES GENMASK(7, 6)
125fb43630cSZhang Yubing #define PHY_RATE GENMASK(5, 4)
126fb43630cSZhang Yubing #define TPS_SEL GENMASK(3, 0)
127fb43630cSZhang Yubing #define DPTX_PHY_TX_EQ 0x0a04
128fb43630cSZhang Yubing #define DPTX_CUSTOMPAT0 0x0a08
129fb43630cSZhang Yubing #define DPTX_CUSTOMPAT1 0x0a0c
130fb43630cSZhang Yubing #define DPTX_CUSTOMPAT2 0x0a10
131fb43630cSZhang Yubing #define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14
132fb43630cSZhang Yubing #define DPTX_PHYIF_PWRDOWN_CTRL 0x0a18
133fb43630cSZhang Yubing
134fb43630cSZhang Yubing #define DPTX_AUX_CMD 0x0b00
135fb43630cSZhang Yubing #define AUX_CMD_TYPE GENMASK(31, 28)
136fb43630cSZhang Yubing #define AUX_ADDR GENMASK(27, 8)
137fb43630cSZhang Yubing #define I2C_ADDR_ONLY BIT(4)
138fb43630cSZhang Yubing #define AUX_LEN_REQ GENMASK(3, 0)
139fb43630cSZhang Yubing #define DPTX_AUX_STATUS 0x0b04
140fb43630cSZhang Yubing #define AUX_TIMEOUT BIT(17)
141fb43630cSZhang Yubing #define AUX_BYTES_READ GENMASK(23, 19)
142fb43630cSZhang Yubing #define AUX_STATUS GENMASK(7, 4)
143fb43630cSZhang Yubing #define DPTX_AUX_DATA0 0x0b08
144fb43630cSZhang Yubing #define DPTX_AUX_DATA1 0x0b0c
145fb43630cSZhang Yubing #define DPTX_AUX_DATA2 0x0b10
146fb43630cSZhang Yubing #define DPTX_AUX_DATA3 0x0b14
147fb43630cSZhang Yubing
148fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT 0x0d00
149fb43630cSZhang Yubing #define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6)
150fb43630cSZhang Yubing #define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5)
151fb43630cSZhang Yubing #define SDP_EVENT_STREAM0 BIT(4)
152fb43630cSZhang Yubing #define AUX_CMD_INVALID BIT(3)
153fb43630cSZhang Yubing #define AUX_REPLY_EVENT BIT(1)
154fb43630cSZhang Yubing #define HPD_EVENT BIT(0)
155fb43630cSZhang Yubing #define DPTX_GENERAL_INTERRUPT_ENABLE 0x0d04
156fb43630cSZhang Yubing #define AUX_REPLY_EVENT_EN BIT(1)
157fb43630cSZhang Yubing #define HPD_EVENT_EN BIT(0)
158fb43630cSZhang Yubing #define DPTX_HPD_STATUS 0x0d08
159fb43630cSZhang Yubing #define HPD_STATE GENMASK(11, 9)
160fb43630cSZhang Yubing #define HPD_STATUS BIT(8)
161fb43630cSZhang Yubing #define HPD_HOT_UNPLUG BIT(2)
162fb43630cSZhang Yubing #define HPD_HOT_PLUG BIT(1)
163fb43630cSZhang Yubing #define HPD_IRQ BIT(0)
164fb43630cSZhang Yubing #define DPTX_HPD_INTERRUPT_ENABLE 0x0d0c
165fb43630cSZhang Yubing #define HPD_UNPLUG_ERR_EN BIT(3)
166fb43630cSZhang Yubing #define HPD_UNPLUG_EN BIT(2)
167fb43630cSZhang Yubing #define HPD_PLUG_EN BIT(1)
168fb43630cSZhang Yubing #define HPD_IRQ_EN BIT(0)
169fb43630cSZhang Yubing
170fb43630cSZhang Yubing #define DPTX_MAX_REGISTER DPTX_HPD_INTERRUPT_ENABLE
171fb43630cSZhang Yubing
172fb43630cSZhang Yubing #define SDP_REG_BANK_SIZE 16
173fb43630cSZhang Yubing
174fb43630cSZhang Yubing struct drm_dp_link_caps {
175fb43630cSZhang Yubing bool enhanced_framing;
176fb43630cSZhang Yubing bool tps3_supported;
177fb43630cSZhang Yubing bool tps4_supported;
178fb43630cSZhang Yubing bool channel_coding;
179fb43630cSZhang Yubing bool ssc;
180fb43630cSZhang Yubing };
181fb43630cSZhang Yubing
182fb43630cSZhang Yubing struct drm_dp_link_train_set {
183fb43630cSZhang Yubing unsigned int voltage_swing[4];
184fb43630cSZhang Yubing unsigned int pre_emphasis[4];
185fb43630cSZhang Yubing };
186fb43630cSZhang Yubing
187fb43630cSZhang Yubing struct drm_dp_link_train {
188fb43630cSZhang Yubing struct drm_dp_link_train_set request;
189fb43630cSZhang Yubing struct drm_dp_link_train_set adjust;
190fb43630cSZhang Yubing bool clock_recovered;
191fb43630cSZhang Yubing bool channel_equalized;
192fb43630cSZhang Yubing };
193fb43630cSZhang Yubing
194fb43630cSZhang Yubing struct dw_dp_link {
195fb43630cSZhang Yubing u8 dpcd[DP_RECEIVER_CAP_SIZE];
196fb43630cSZhang Yubing unsigned char revision;
197fb43630cSZhang Yubing unsigned int rate;
198fb43630cSZhang Yubing unsigned int lanes;
199fb43630cSZhang Yubing struct drm_dp_link_caps caps;
200fb43630cSZhang Yubing struct drm_dp_link_train train;
201fb43630cSZhang Yubing u8 sink_count;
202fb43630cSZhang Yubing u8 vsc_sdp_extension_for_colorimetry_supported;
203fb43630cSZhang Yubing };
204fb43630cSZhang Yubing
205fb43630cSZhang Yubing struct dw_dp_video {
206fb43630cSZhang Yubing struct drm_display_mode mode;
207fb43630cSZhang Yubing u32 bus_format;
208fb43630cSZhang Yubing u8 video_mapping;
209fb43630cSZhang Yubing u8 pixel_mode;
210fb43630cSZhang Yubing u8 color_format;
211fb43630cSZhang Yubing u8 bpc;
212fb43630cSZhang Yubing u8 bpp;
213fb43630cSZhang Yubing };
214fb43630cSZhang Yubing
215fb43630cSZhang Yubing struct dw_dp_sdp {
216fb43630cSZhang Yubing struct dp_sdp_header header;
217fb43630cSZhang Yubing u8 db[32];
218fb43630cSZhang Yubing unsigned long flags;
219fb43630cSZhang Yubing };
220fb43630cSZhang Yubing
2215fc83b1eSZhang Yubing struct dw_dp_chip_data {
2225fc83b1eSZhang Yubing int pixel_mode;
2235fc83b1eSZhang Yubing };
2245fc83b1eSZhang Yubing
225fb43630cSZhang Yubing struct dw_dp {
2260594ce39SZhang Yubing struct rockchip_connector connector;
227fb43630cSZhang Yubing struct udevice *dev;
228fb43630cSZhang Yubing struct regmap *regmap;
229fb43630cSZhang Yubing struct phy phy;
230638855e8SFinley Xiao #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
231638855e8SFinley Xiao struct power_domain pwrdom;
232638855e8SFinley Xiao struct clk_bulk clks;
233638855e8SFinley Xiao #endif
234fb43630cSZhang Yubing struct reset_ctl reset;
235fb43630cSZhang Yubing int id;
236fb43630cSZhang Yubing
237fb43630cSZhang Yubing struct gpio_desc hpd_gpio;
238fb43630cSZhang Yubing struct drm_dp_aux aux;
239fb43630cSZhang Yubing struct dw_dp_link link;
240fb43630cSZhang Yubing struct dw_dp_video video;
2415efdd3e2SZhang Yubing
2425fbef17aSZhang Yubing bool force_hpd;
2435efdd3e2SZhang Yubing bool force_output;
244549d42b6SWyon Bi u32 max_link_rate;
245fb43630cSZhang Yubing };
246fb43630cSZhang Yubing
247fb43630cSZhang Yubing enum {
248fb43630cSZhang Yubing SOURCE_STATE_IDLE,
249fb43630cSZhang Yubing SOURCE_STATE_UNPLUG,
250fb43630cSZhang Yubing SOURCE_STATE_HPD_TIMEOUT = 4,
251fb43630cSZhang Yubing SOURCE_STATE_PLUG = 7
252fb43630cSZhang Yubing };
253fb43630cSZhang Yubing
254fb43630cSZhang Yubing enum {
255fb43630cSZhang Yubing DPTX_VM_RGB_6BIT,
256fb43630cSZhang Yubing DPTX_VM_RGB_8BIT,
257fb43630cSZhang Yubing DPTX_VM_RGB_10BIT,
258fb43630cSZhang Yubing DPTX_VM_RGB_12BIT,
259fb43630cSZhang Yubing DPTX_VM_RGB_16BIT,
260fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT,
261fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT,
262fb43630cSZhang Yubing DPTX_VM_YCBCR444_12BIT,
263fb43630cSZhang Yubing DPTX_VM_YCBCR444_16BIT,
264fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT,
265fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT,
266fb43630cSZhang Yubing DPTX_VM_YCBCR422_12BIT,
267fb43630cSZhang Yubing DPTX_VM_YCBCR422_16BIT,
268fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT,
269fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT,
270fb43630cSZhang Yubing DPTX_VM_YCBCR420_12BIT,
271fb43630cSZhang Yubing DPTX_VM_YCBCR420_16BIT,
272fb43630cSZhang Yubing };
273fb43630cSZhang Yubing
274fb43630cSZhang Yubing enum {
275fb43630cSZhang Yubing DPTX_MP_SINGLE_PIXEL,
276fb43630cSZhang Yubing DPTX_MP_DUAL_PIXEL,
277fb43630cSZhang Yubing DPTX_MP_QUAD_PIXEL,
278fb43630cSZhang Yubing };
279fb43630cSZhang Yubing
280fb43630cSZhang Yubing enum {
281fb43630cSZhang Yubing DPTX_SDP_VERTICAL_INTERVAL = BIT(0),
282fb43630cSZhang Yubing DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1),
283fb43630cSZhang Yubing };
284fb43630cSZhang Yubing
285fb43630cSZhang Yubing enum {
286fb43630cSZhang Yubing DPTX_PHY_PATTERN_NONE,
287fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_1,
288fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_2,
289fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_3,
290fb43630cSZhang Yubing DPTX_PHY_PATTERN_TPS_4,
291fb43630cSZhang Yubing DPTX_PHY_PATTERN_SERM,
292fb43630cSZhang Yubing DPTX_PHY_PATTERN_PBRS7,
293fb43630cSZhang Yubing DPTX_PHY_PATTERN_CUSTOM_80BIT,
294fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_1,
295fb43630cSZhang Yubing DPTX_PHY_PATTERN_CP2520_2,
296fb43630cSZhang Yubing };
297fb43630cSZhang Yubing
2985efdd3e2SZhang Yubing enum {
2995efdd3e2SZhang Yubing DPTX_PHYRATE_RBR,
3005efdd3e2SZhang Yubing DPTX_PHYRATE_HBR,
3015efdd3e2SZhang Yubing DPTX_PHYRATE_HBR2,
3025efdd3e2SZhang Yubing DPTX_PHYRATE_HBR3,
3035efdd3e2SZhang Yubing };
3045efdd3e2SZhang Yubing
305fb43630cSZhang Yubing struct dw_dp_output_format {
306fb43630cSZhang Yubing u32 bus_format;
307fb43630cSZhang Yubing u32 color_format;
308fb43630cSZhang Yubing u8 video_mapping;
309fb43630cSZhang Yubing u8 bpc;
310fb43630cSZhang Yubing u8 bpp;
311fb43630cSZhang Yubing };
312fb43630cSZhang Yubing
313fb43630cSZhang Yubing static const struct dw_dp_output_format possible_output_fmts[] = {
314fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444,
315fb43630cSZhang Yubing DPTX_VM_RGB_10BIT, 10, 30 },
316fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444,
317fb43630cSZhang Yubing DPTX_VM_RGB_8BIT, 8, 24 },
318fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444,
319fb43630cSZhang Yubing DPTX_VM_YCBCR444_10BIT, 10, 30 },
320fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444,
321fb43630cSZhang Yubing DPTX_VM_YCBCR444_8BIT, 8, 24},
322fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422,
323fb43630cSZhang Yubing DPTX_VM_YCBCR422_10BIT, 10, 20 },
324fb43630cSZhang Yubing { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422,
325fb43630cSZhang Yubing DPTX_VM_YCBCR422_8BIT, 8, 16 },
326fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420,
327fb43630cSZhang Yubing DPTX_VM_YCBCR420_10BIT, 10, 15 },
328fb43630cSZhang Yubing { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420,
329fb43630cSZhang Yubing DPTX_VM_YCBCR420_8BIT, 8, 12 },
330fb43630cSZhang Yubing { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444,
331fb43630cSZhang Yubing DPTX_VM_RGB_6BIT, 6, 18 },
332fb43630cSZhang Yubing };
333fb43630cSZhang Yubing
dw_dp_aux_write_data(struct dw_dp * dp,const u8 * buffer,size_t size)334fb43630cSZhang Yubing static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size)
335fb43630cSZhang Yubing {
336fb43630cSZhang Yubing size_t i, j;
337fb43630cSZhang Yubing
338fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
339fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4);
340fb43630cSZhang Yubing u32 value = 0;
341fb43630cSZhang Yubing
342fb43630cSZhang Yubing for (j = 0; j < num; j++)
343fb43630cSZhang Yubing value |= buffer[i * 4 + j] << (j * 8);
344fb43630cSZhang Yubing
345fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value);
346fb43630cSZhang Yubing }
347fb43630cSZhang Yubing
348fb43630cSZhang Yubing return size;
349fb43630cSZhang Yubing }
350fb43630cSZhang Yubing
dw_dp_aux_read_data(struct dw_dp * dp,u8 * buffer,size_t size)351fb43630cSZhang Yubing static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size)
352fb43630cSZhang Yubing {
353fb43630cSZhang Yubing size_t i, j;
354fb43630cSZhang Yubing
355fb43630cSZhang Yubing for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
356fb43630cSZhang Yubing size_t num = min_t(size_t, size - i * 4, 4);
357fb43630cSZhang Yubing u32 value;
358fb43630cSZhang Yubing
359fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value);
360fb43630cSZhang Yubing
361fb43630cSZhang Yubing for (j = 0; j < num; j++)
362fb43630cSZhang Yubing buffer[i * 4 + j] = value >> (j * 8);
363fb43630cSZhang Yubing }
364fb43630cSZhang Yubing
365fb43630cSZhang Yubing return size;
366fb43630cSZhang Yubing }
367fb43630cSZhang Yubing
dw_dp_aux_transfer(struct drm_dp_aux * aux,struct drm_dp_aux_msg * msg)368fb43630cSZhang Yubing static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
369fb43630cSZhang Yubing struct drm_dp_aux_msg *msg)
370fb43630cSZhang Yubing {
371fb43630cSZhang Yubing u32 status, value;
372fb43630cSZhang Yubing ssize_t ret = 0;
373fb43630cSZhang Yubing int timeout = 0;
374fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(aux->dev);
375fb43630cSZhang Yubing
376fb43630cSZhang Yubing if (WARN_ON(msg->size > 16))
377fb43630cSZhang Yubing return -E2BIG;
378fb43630cSZhang Yubing
379fb43630cSZhang Yubing switch (msg->request & ~DP_AUX_I2C_MOT) {
380fb43630cSZhang Yubing case DP_AUX_NATIVE_WRITE:
381fb43630cSZhang Yubing case DP_AUX_I2C_WRITE:
382fb43630cSZhang Yubing case DP_AUX_I2C_WRITE_STATUS_UPDATE:
383fb43630cSZhang Yubing ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size);
384fb43630cSZhang Yubing if (ret < 0)
385fb43630cSZhang Yubing return ret;
386fb43630cSZhang Yubing break;
387fb43630cSZhang Yubing case DP_AUX_NATIVE_READ:
388fb43630cSZhang Yubing case DP_AUX_I2C_READ:
389fb43630cSZhang Yubing break;
390fb43630cSZhang Yubing default:
391fb43630cSZhang Yubing return -EINVAL;
392fb43630cSZhang Yubing }
393fb43630cSZhang Yubing
394fb43630cSZhang Yubing if (msg->size > 0)
395fb43630cSZhang Yubing value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1);
396fb43630cSZhang Yubing else
397fb43630cSZhang Yubing value = FIELD_PREP(I2C_ADDR_ONLY, 1);
398fb43630cSZhang Yubing
399fb43630cSZhang Yubing value |= FIELD_PREP(AUX_CMD_TYPE, msg->request);
400fb43630cSZhang Yubing value |= FIELD_PREP(AUX_ADDR, msg->address);
401fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_AUX_CMD, value);
402fb43630cSZhang Yubing
403fb43630cSZhang Yubing timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT,
404fb43630cSZhang Yubing status, status & AUX_REPLY_EVENT,
405fb43630cSZhang Yubing 200, 10);
406fb43630cSZhang Yubing
407fb43630cSZhang Yubing if (timeout) {
408fb43630cSZhang Yubing printf("timeout waiting for AUX reply\n");
409fb43630cSZhang Yubing return -ETIMEDOUT;
410fb43630cSZhang Yubing }
411fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT);
412fb43630cSZhang Yubing
413fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_AUX_STATUS, &value);
414fb43630cSZhang Yubing if (value & AUX_TIMEOUT) {
415fb43630cSZhang Yubing printf("aux timeout\n");
416fb43630cSZhang Yubing return -ETIMEDOUT;
417fb43630cSZhang Yubing }
418fb43630cSZhang Yubing
419fb43630cSZhang Yubing msg->reply = FIELD_GET(AUX_STATUS, value);
420fb43630cSZhang Yubing
421fb43630cSZhang Yubing if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
422fb43630cSZhang Yubing if (msg->request & DP_AUX_I2C_READ) {
423fb43630cSZhang Yubing size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1;
424fb43630cSZhang Yubing
425fb43630cSZhang Yubing if (count != msg->size) {
426fb43630cSZhang Yubing printf("aux fail to read %lu bytes\n", count);
427fb43630cSZhang Yubing return -EBUSY;
428fb43630cSZhang Yubing }
429fb43630cSZhang Yubing
430fb43630cSZhang Yubing ret = dw_dp_aux_read_data(dp, msg->buffer, count);
431fb43630cSZhang Yubing if (ret < 0)
432fb43630cSZhang Yubing return ret;
433fb43630cSZhang Yubing }
434fb43630cSZhang Yubing }
435fb43630cSZhang Yubing
436fb43630cSZhang Yubing return ret;
437fb43630cSZhang Yubing }
438fb43630cSZhang Yubing
dw_dp_bandwidth_ok(struct dw_dp * dp,const struct drm_display_mode * mode,u32 bpp,unsigned int lanes,unsigned int rate)439fb43630cSZhang Yubing static bool dw_dp_bandwidth_ok(struct dw_dp *dp,
440fb43630cSZhang Yubing const struct drm_display_mode *mode, u32 bpp,
441fb43630cSZhang Yubing unsigned int lanes, unsigned int rate)
442fb43630cSZhang Yubing {
443fb43630cSZhang Yubing u32 max_bw, req_bw;
444fb43630cSZhang Yubing
445fb43630cSZhang Yubing req_bw = mode->clock * bpp / 8;
446fb43630cSZhang Yubing max_bw = lanes * rate;
447fb43630cSZhang Yubing if (req_bw > max_bw)
448fb43630cSZhang Yubing return false;
449fb43630cSZhang Yubing
450fb43630cSZhang Yubing return true;
451fb43630cSZhang Yubing }
452fb43630cSZhang Yubing
dw_dp_hpd_init(struct dw_dp * dp)453fb43630cSZhang Yubing static void dw_dp_hpd_init(struct dw_dp *dp)
454fb43630cSZhang Yubing {
4555fbef17aSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio) || dp->force_hpd) {
456fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD,
457fb43630cSZhang Yubing FIELD_PREP(FORCE_HPD, 1));
458fb43630cSZhang Yubing return;
459fb43630cSZhang Yubing }
460fb43630cSZhang Yubing
461fb43630cSZhang Yubing /* Enable all HPD interrupts */
462fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE,
463fb43630cSZhang Yubing HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN,
464fb43630cSZhang Yubing FIELD_PREP(HPD_UNPLUG_EN, 1) |
465fb43630cSZhang Yubing FIELD_PREP(HPD_PLUG_EN, 1) |
466fb43630cSZhang Yubing FIELD_PREP(HPD_IRQ_EN, 1));
467fb43630cSZhang Yubing
468fb43630cSZhang Yubing /* Enable all top-level interrupts */
469fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
470fb43630cSZhang Yubing HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1));
471fb43630cSZhang Yubing }
472fb43630cSZhang Yubing
dw_dp_aux_init(struct dw_dp * dp)473fb43630cSZhang Yubing static void dw_dp_aux_init(struct dw_dp *dp)
474fb43630cSZhang Yubing {
475fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
476fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 1));
477fb43630cSZhang Yubing udelay(10);
478fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET,
479fb43630cSZhang Yubing FIELD_PREP(AUX_RESET, 0));
480fb43630cSZhang Yubing
481fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE,
482fb43630cSZhang Yubing AUX_REPLY_EVENT_EN,
483fb43630cSZhang Yubing FIELD_PREP(AUX_REPLY_EVENT_EN, 1));
484fb43630cSZhang Yubing }
485fb43630cSZhang Yubing
dw_dp_init(struct dw_dp * dp)486fb43630cSZhang Yubing static void dw_dp_init(struct dw_dp *dp)
487fb43630cSZhang Yubing {
488fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
489fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 1));
490fb43630cSZhang Yubing udelay(10);
491fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET,
492fb43630cSZhang Yubing FIELD_PREP(CONTROLLER_RESET, 0));
493fb43630cSZhang Yubing
494fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
495fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 1));
496fb43630cSZhang Yubing udelay(10);
497fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET,
498fb43630cSZhang Yubing FIELD_PREP(PHY_SOFT_RESET, 0));
499fb43630cSZhang Yubing
500fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN,
501fb43630cSZhang Yubing FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0));
502fb43630cSZhang Yubing
503fb43630cSZhang Yubing dw_dp_hpd_init(dp);
504fb43630cSZhang Yubing dw_dp_aux_init(dp);
505fb43630cSZhang Yubing }
506fb43630cSZhang Yubing
dw_dp_phy_set_pattern(struct dw_dp * dp,u32 pattern)507fb43630cSZhang Yubing static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern)
508fb43630cSZhang Yubing {
509fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL,
510fb43630cSZhang Yubing FIELD_PREP(TPS_SEL, pattern));
511fb43630cSZhang Yubing }
512fb43630cSZhang Yubing
dw_dp_phy_xmit_enable(struct dw_dp * dp,u32 lanes)513fb43630cSZhang Yubing static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes)
514fb43630cSZhang Yubing {
515fb43630cSZhang Yubing u32 xmit_enable;
516fb43630cSZhang Yubing
517fb43630cSZhang Yubing switch (lanes) {
518fb43630cSZhang Yubing case 4:
519fb43630cSZhang Yubing case 2:
520fb43630cSZhang Yubing case 1:
521fb43630cSZhang Yubing xmit_enable = GENMASK(lanes - 1, 0);
522fb43630cSZhang Yubing break;
523fb43630cSZhang Yubing case 0:
524fb43630cSZhang Yubing default:
525fb43630cSZhang Yubing xmit_enable = 0;
526fb43630cSZhang Yubing break;
527fb43630cSZhang Yubing }
528fb43630cSZhang Yubing
529fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE,
530fb43630cSZhang Yubing FIELD_PREP(XMIT_ENABLE, xmit_enable));
531fb43630cSZhang Yubing }
532fb43630cSZhang Yubing
dw_dp_link_power_up(struct dw_dp * dp)533fb43630cSZhang Yubing static int dw_dp_link_power_up(struct dw_dp *dp)
534fb43630cSZhang Yubing {
535fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
536fb43630cSZhang Yubing u8 value;
537fb43630cSZhang Yubing int ret;
538fb43630cSZhang Yubing
539fb43630cSZhang Yubing if (link->revision < 0x11)
540fb43630cSZhang Yubing return 0;
541fb43630cSZhang Yubing
542fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value);
543fb43630cSZhang Yubing if (ret < 0)
544fb43630cSZhang Yubing return ret;
545fb43630cSZhang Yubing
546fb43630cSZhang Yubing value &= ~DP_SET_POWER_MASK;
547fb43630cSZhang Yubing value |= DP_SET_POWER_D0;
548fb43630cSZhang Yubing
549fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value);
550fb43630cSZhang Yubing if (ret < 0)
551fb43630cSZhang Yubing return ret;
552fb43630cSZhang Yubing
553fb43630cSZhang Yubing udelay(1000);
554fb43630cSZhang Yubing return 0;
555fb43630cSZhang Yubing }
556fb43630cSZhang Yubing
dw_dp_link_probe(struct dw_dp * dp)557fb43630cSZhang Yubing static int dw_dp_link_probe(struct dw_dp *dp)
558fb43630cSZhang Yubing {
559fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
560fb43630cSZhang Yubing u8 dpcd;
561fb43630cSZhang Yubing int ret;
562fb43630cSZhang Yubing
5632493a680SZhang Yubing drm_dp_dpcd_writeb(&dp->aux, DP_MSTM_CTRL, 0);
564fb43630cSZhang Yubing ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd);
565fb43630cSZhang Yubing if (ret < 0)
566fb43630cSZhang Yubing return ret;
567fb43630cSZhang Yubing
568fb43630cSZhang Yubing ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
569fb43630cSZhang Yubing &dpcd);
570fb43630cSZhang Yubing if (ret < 0)
571fb43630cSZhang Yubing return ret;
572fb43630cSZhang Yubing
573fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported =
574fb43630cSZhang Yubing !!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED);
575fb43630cSZhang Yubing
576fb43630cSZhang Yubing link->revision = link->dpcd[DP_DPCD_REV];
577549d42b6SWyon Bi link->rate = min_t(u32, min(dp->max_link_rate, dp->phy.attrs.max_link_rate * 100),
578ca4b9d14SWyon Bi drm_dp_max_link_rate(link->dpcd));
579fb43630cSZhang Yubing link->lanes = min_t(u8, dp->phy.attrs.bus_width,
580fb43630cSZhang Yubing drm_dp_max_lane_count(link->dpcd));
581fb43630cSZhang Yubing
582fb43630cSZhang Yubing link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd);
583fb43630cSZhang Yubing link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd);
584fb43630cSZhang Yubing link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd);
585fb43630cSZhang Yubing link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd);
586fb43630cSZhang Yubing link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] &
587fb43630cSZhang Yubing DP_MAX_DOWNSPREAD_0_5);
588fb43630cSZhang Yubing
589fb43630cSZhang Yubing return 0;
590fb43630cSZhang Yubing }
591fb43630cSZhang Yubing
dw_dp_link_train_update_vs_emph(struct dw_dp * dp)592fb43630cSZhang Yubing static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp)
593fb43630cSZhang Yubing {
594fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
595fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &link->train.request;
596fb43630cSZhang Yubing union phy_configure_opts phy_cfg;
597fb43630cSZhang Yubing unsigned int lanes = link->lanes, *vs, *pe;
598fb43630cSZhang Yubing u8 buf[4];
599fb43630cSZhang Yubing int i, ret;
600fb43630cSZhang Yubing
601fb43630cSZhang Yubing vs = request->voltage_swing;
602fb43630cSZhang Yubing pe = request->pre_emphasis;
603fb43630cSZhang Yubing
604fb43630cSZhang Yubing for (i = 0; i < lanes; i++) {
605fb43630cSZhang Yubing phy_cfg.dp.voltage[i] = vs[i];
606fb43630cSZhang Yubing phy_cfg.dp.pre[i] = pe[i];
607fb43630cSZhang Yubing }
608fb43630cSZhang Yubing phy_cfg.dp.lanes = lanes;
609fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100;
610fb43630cSZhang Yubing phy_cfg.dp.set_lanes = false;
611fb43630cSZhang Yubing phy_cfg.dp.set_rate = false;
612fb43630cSZhang Yubing phy_cfg.dp.set_voltages = true;
613fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg);
614fb43630cSZhang Yubing if (ret)
615fb43630cSZhang Yubing return ret;
616fb43630cSZhang Yubing
617fb43630cSZhang Yubing for (i = 0; i < lanes; i++)
618fb43630cSZhang Yubing buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) |
619fb43630cSZhang Yubing (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT);
620fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes);
621fb43630cSZhang Yubing if (ret < 0)
622fb43630cSZhang Yubing return ret;
623fb43630cSZhang Yubing
624fb43630cSZhang Yubing return 0;
625fb43630cSZhang Yubing }
626fb43630cSZhang Yubing
dw_dp_link_configure(struct dw_dp * dp)627fb43630cSZhang Yubing static int dw_dp_link_configure(struct dw_dp *dp)
628fb43630cSZhang Yubing {
629fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
630fb43630cSZhang Yubing union phy_configure_opts phy_cfg;
631fb43630cSZhang Yubing u8 buf[2];
6325efdd3e2SZhang Yubing int ret, phy_rate;
633fb43630cSZhang Yubing
634fb43630cSZhang Yubing /* Move PHY to P3 */
635fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
636fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3));
637fb43630cSZhang Yubing
638fb43630cSZhang Yubing phy_cfg.dp.lanes = link->lanes;
639fb43630cSZhang Yubing phy_cfg.dp.link_rate = link->rate / 100;
640fb43630cSZhang Yubing phy_cfg.dp.ssc = link->caps.ssc;
641fb43630cSZhang Yubing phy_cfg.dp.set_lanes = true;
642fb43630cSZhang Yubing phy_cfg.dp.set_rate = true;
643fb43630cSZhang Yubing phy_cfg.dp.set_voltages = false;
644fb43630cSZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg);
645fb43630cSZhang Yubing if (ret)
646fb43630cSZhang Yubing return ret;
647fb43630cSZhang Yubing
648fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES,
649fb43630cSZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2));
650fb43630cSZhang Yubing
6515efdd3e2SZhang Yubing switch (link->rate) {
6525efdd3e2SZhang Yubing case 810000:
6535efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3;
6545efdd3e2SZhang Yubing break;
6555efdd3e2SZhang Yubing case 540000:
6565efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2;
6575efdd3e2SZhang Yubing break;
6585efdd3e2SZhang Yubing case 270000:
6595efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR;
6605efdd3e2SZhang Yubing break;
6615efdd3e2SZhang Yubing case 162000:
6625efdd3e2SZhang Yubing default:
6635efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR;
6645efdd3e2SZhang Yubing break;
6655efdd3e2SZhang Yubing }
6665efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE,
6675efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate));
6685efdd3e2SZhang Yubing
669fb43630cSZhang Yubing /* Move PHY to P0 */
670fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
671fb43630cSZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0));
672fb43630cSZhang Yubing
673fb43630cSZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes);
674fb43630cSZhang Yubing
675fb43630cSZhang Yubing buf[0] = drm_dp_link_rate_to_bw_code(link->rate);
676fb43630cSZhang Yubing buf[1] = link->lanes;
677fb43630cSZhang Yubing
678fb43630cSZhang Yubing if (link->caps.enhanced_framing) {
679fb43630cSZhang Yubing buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
680fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
681fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1));
682fb43630cSZhang Yubing } else {
683fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
684fb43630cSZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 0));
685fb43630cSZhang Yubing }
686fb43630cSZhang Yubing
687fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf));
688fb43630cSZhang Yubing if (ret < 0)
689fb43630cSZhang Yubing return ret;
690fb43630cSZhang Yubing
691fb43630cSZhang Yubing buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0;
692fb43630cSZhang Yubing buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0;
693fb43630cSZhang Yubing
694fb43630cSZhang Yubing ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf,
695fb43630cSZhang Yubing sizeof(buf));
696fb43630cSZhang Yubing if (ret < 0)
697fb43630cSZhang Yubing return ret;
698fb43630cSZhang Yubing
699fb43630cSZhang Yubing return 0;
700fb43630cSZhang Yubing }
701fb43630cSZhang Yubing
dw_dp_link_train_init(struct drm_dp_link_train * train)702fb43630cSZhang Yubing static void dw_dp_link_train_init(struct drm_dp_link_train *train)
703fb43630cSZhang Yubing {
704fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request;
705fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust;
706fb43630cSZhang Yubing unsigned int i;
707fb43630cSZhang Yubing
708fb43630cSZhang Yubing for (i = 0; i < 4; i++) {
709fb43630cSZhang Yubing request->voltage_swing[i] = 0;
710fb43630cSZhang Yubing adjust->voltage_swing[i] = 0;
711fb43630cSZhang Yubing
712fb43630cSZhang Yubing request->pre_emphasis[i] = 0;
713fb43630cSZhang Yubing adjust->pre_emphasis[i] = 0;
714fb43630cSZhang Yubing }
715fb43630cSZhang Yubing
716fb43630cSZhang Yubing train->clock_recovered = false;
717fb43630cSZhang Yubing train->channel_equalized = false;
718fb43630cSZhang Yubing }
719fb43630cSZhang Yubing
dw_dp_link_train_set_pattern(struct dw_dp * dp,u32 pattern)720fb43630cSZhang Yubing static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern)
721fb43630cSZhang Yubing {
722fb43630cSZhang Yubing u8 buf = 0;
723fb43630cSZhang Yubing int ret;
724fb43630cSZhang Yubing
725fb43630cSZhang Yubing if (pattern && pattern != DP_TRAINING_PATTERN_4) {
726fb43630cSZhang Yubing buf |= DP_LINK_SCRAMBLING_DISABLE;
727fb43630cSZhang Yubing
728fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
729fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 1));
730fb43630cSZhang Yubing } else {
731fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS,
732fb43630cSZhang Yubing FIELD_PREP(SCRAMBLE_DIS, 0));
733fb43630cSZhang Yubing }
734fb43630cSZhang Yubing
735fb43630cSZhang Yubing switch (pattern) {
736fb43630cSZhang Yubing case DP_TRAINING_PATTERN_DISABLE:
737fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE);
738fb43630cSZhang Yubing break;
739fb43630cSZhang Yubing case DP_TRAINING_PATTERN_1:
740fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1);
741fb43630cSZhang Yubing break;
742fb43630cSZhang Yubing case DP_TRAINING_PATTERN_2:
743fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2);
744fb43630cSZhang Yubing break;
745fb43630cSZhang Yubing case DP_TRAINING_PATTERN_3:
746fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3);
747fb43630cSZhang Yubing break;
748fb43630cSZhang Yubing case DP_TRAINING_PATTERN_4:
749fb43630cSZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4);
750fb43630cSZhang Yubing break;
751fb43630cSZhang Yubing default:
752fb43630cSZhang Yubing return -EINVAL;
753fb43630cSZhang Yubing }
754fb43630cSZhang Yubing
755fb43630cSZhang Yubing ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
756fb43630cSZhang Yubing buf | pattern);
757fb43630cSZhang Yubing if (ret < 0)
758fb43630cSZhang Yubing return ret;
759fb43630cSZhang Yubing
760fb43630cSZhang Yubing return 0;
761fb43630cSZhang Yubing }
762fb43630cSZhang Yubing
dw_dp_link_get_adjustments(struct dw_dp_link * link,u8 status[DP_LINK_STATUS_SIZE])763fb43630cSZhang Yubing static void dw_dp_link_get_adjustments(struct dw_dp_link *link,
764fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE])
765fb43630cSZhang Yubing {
766fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &link->train.adjust;
767fb43630cSZhang Yubing unsigned int i;
768fb43630cSZhang Yubing
769fb43630cSZhang Yubing for (i = 0; i < link->lanes; i++) {
770fb43630cSZhang Yubing adjust->voltage_swing[i] =
771fb43630cSZhang Yubing drm_dp_get_adjust_request_voltage(status, i) >>
772fb43630cSZhang Yubing DP_TRAIN_VOLTAGE_SWING_SHIFT;
773fb43630cSZhang Yubing
774fb43630cSZhang Yubing adjust->pre_emphasis[i] =
775fb43630cSZhang Yubing drm_dp_get_adjust_request_pre_emphasis(status, i) >>
776fb43630cSZhang Yubing DP_TRAIN_PRE_EMPHASIS_SHIFT;
777fb43630cSZhang Yubing }
778fb43630cSZhang Yubing }
779fb43630cSZhang Yubing
dw_dp_link_train_adjust(struct drm_dp_link_train * train)780fb43630cSZhang Yubing static void dw_dp_link_train_adjust(struct drm_dp_link_train *train)
781fb43630cSZhang Yubing {
782fb43630cSZhang Yubing struct drm_dp_link_train_set *request = &train->request;
783fb43630cSZhang Yubing struct drm_dp_link_train_set *adjust = &train->adjust;
784fb43630cSZhang Yubing unsigned int i;
785fb43630cSZhang Yubing
786fb43630cSZhang Yubing for (i = 0; i < 4; i++)
787fb43630cSZhang Yubing if (request->voltage_swing[i] != adjust->voltage_swing[i])
788fb43630cSZhang Yubing request->voltage_swing[i] = adjust->voltage_swing[i];
789fb43630cSZhang Yubing
790fb43630cSZhang Yubing for (i = 0; i < 4; i++)
791fb43630cSZhang Yubing if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
792fb43630cSZhang Yubing request->pre_emphasis[i] = adjust->pre_emphasis[i];
793fb43630cSZhang Yubing }
794fb43630cSZhang Yubing
dw_dp_link_clock_recovery(struct dw_dp * dp)795fb43630cSZhang Yubing static int dw_dp_link_clock_recovery(struct dw_dp *dp)
796fb43630cSZhang Yubing {
797fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
798fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE];
799fb43630cSZhang Yubing unsigned int tries = 0;
800fb43630cSZhang Yubing int ret;
801fb43630cSZhang Yubing
802fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);
803fb43630cSZhang Yubing if (ret)
804fb43630cSZhang Yubing return ret;
805fb43630cSZhang Yubing
806fb43630cSZhang Yubing for (;;) {
807fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp);
808fb43630cSZhang Yubing if (ret)
809fb43630cSZhang Yubing return ret;
810fb43630cSZhang Yubing
811fb43630cSZhang Yubing drm_dp_link_train_clock_recovery_delay(link->dpcd);
812fb43630cSZhang Yubing
813fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
814fb43630cSZhang Yubing if (ret < 0) {
815fb43630cSZhang Yubing dev_err(dp->dev, "failed to read link status: %d\n",
816fb43630cSZhang Yubing ret);
817fb43630cSZhang Yubing return ret;
818fb43630cSZhang Yubing }
819fb43630cSZhang Yubing
820fb43630cSZhang Yubing if (drm_dp_clock_recovery_ok(status, link->lanes)) {
821fb43630cSZhang Yubing link->train.clock_recovered = true;
822fb43630cSZhang Yubing break;
823fb43630cSZhang Yubing }
824fb43630cSZhang Yubing
825fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status);
826fb43630cSZhang Yubing
827fb43630cSZhang Yubing if (link->train.request.voltage_swing[0] ==
828fb43630cSZhang Yubing link->train.adjust.voltage_swing[0])
829fb43630cSZhang Yubing tries++;
830fb43630cSZhang Yubing else
831fb43630cSZhang Yubing tries = 0;
832fb43630cSZhang Yubing
833fb43630cSZhang Yubing if (tries == 5)
834fb43630cSZhang Yubing break;
835fb43630cSZhang Yubing
836fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train);
837fb43630cSZhang Yubing }
838fb43630cSZhang Yubing
839fb43630cSZhang Yubing return 0;
840fb43630cSZhang Yubing }
841fb43630cSZhang Yubing
dw_dp_link_channel_equalization(struct dw_dp * dp)842fb43630cSZhang Yubing static int dw_dp_link_channel_equalization(struct dw_dp *dp)
843fb43630cSZhang Yubing {
844fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
845fb43630cSZhang Yubing u8 status[DP_LINK_STATUS_SIZE], pattern;
846fb43630cSZhang Yubing unsigned int tries;
847fb43630cSZhang Yubing int ret;
848fb43630cSZhang Yubing
849fb43630cSZhang Yubing if (link->caps.tps4_supported)
850fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_4;
851fb43630cSZhang Yubing else if (link->caps.tps3_supported)
852fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_3;
853fb43630cSZhang Yubing else
854fb43630cSZhang Yubing pattern = DP_TRAINING_PATTERN_2;
855fb43630cSZhang Yubing ret = dw_dp_link_train_set_pattern(dp, pattern);
856fb43630cSZhang Yubing if (ret)
857fb43630cSZhang Yubing return ret;
858fb43630cSZhang Yubing
859fb43630cSZhang Yubing for (tries = 1; tries < 5; tries++) {
860fb43630cSZhang Yubing ret = dw_dp_link_train_update_vs_emph(dp);
861fb43630cSZhang Yubing if (ret)
862fb43630cSZhang Yubing return ret;
863fb43630cSZhang Yubing
864fb43630cSZhang Yubing drm_dp_link_train_channel_eq_delay(link->dpcd);
865fb43630cSZhang Yubing
866fb43630cSZhang Yubing ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
867fb43630cSZhang Yubing if (ret < 0)
868fb43630cSZhang Yubing return ret;
869fb43630cSZhang Yubing
870fb43630cSZhang Yubing if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
871fb43630cSZhang Yubing dev_err(dp->dev,
872fb43630cSZhang Yubing "clock recovery lost while eq\n");
873fb43630cSZhang Yubing link->train.clock_recovered = false;
874fb43630cSZhang Yubing break;
875fb43630cSZhang Yubing }
876fb43630cSZhang Yubing
877fb43630cSZhang Yubing if (drm_dp_channel_eq_ok(status, link->lanes)) {
878fb43630cSZhang Yubing link->train.channel_equalized = true;
879fb43630cSZhang Yubing break;
880fb43630cSZhang Yubing }
881fb43630cSZhang Yubing
882fb43630cSZhang Yubing dw_dp_link_get_adjustments(link, status);
883fb43630cSZhang Yubing dw_dp_link_train_adjust(&link->train);
884fb43630cSZhang Yubing }
885fb43630cSZhang Yubing
886fb43630cSZhang Yubing return 0;
887fb43630cSZhang Yubing }
888fb43630cSZhang Yubing
dw_dp_link_downgrade(struct dw_dp * dp)889fb43630cSZhang Yubing static int dw_dp_link_downgrade(struct dw_dp *dp)
890fb43630cSZhang Yubing {
891fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
892fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video;
893fb43630cSZhang Yubing
894fb43630cSZhang Yubing switch (link->rate) {
895fb43630cSZhang Yubing case 162000:
896fb43630cSZhang Yubing return -EINVAL;
897fb43630cSZhang Yubing case 270000:
898fb43630cSZhang Yubing link->rate = 162000;
899fb43630cSZhang Yubing break;
900fb43630cSZhang Yubing case 540000:
901fb43630cSZhang Yubing link->rate = 270000;
902fb43630cSZhang Yubing break;
903fb43630cSZhang Yubing case 810000:
904fb43630cSZhang Yubing link->rate = 540000;
905fb43630cSZhang Yubing break;
906fb43630cSZhang Yubing }
907fb43630cSZhang Yubing
908fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes,
909fb43630cSZhang Yubing link->rate))
910fb43630cSZhang Yubing return -E2BIG;
911fb43630cSZhang Yubing
912fb43630cSZhang Yubing return 0;
913fb43630cSZhang Yubing }
914fb43630cSZhang Yubing
dw_dp_link_train(struct dw_dp * dp)915fb43630cSZhang Yubing static int dw_dp_link_train(struct dw_dp *dp)
916fb43630cSZhang Yubing {
917fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
918fb43630cSZhang Yubing int ret;
919fb43630cSZhang Yubing
920fb43630cSZhang Yubing retry:
921fb43630cSZhang Yubing dw_dp_link_train_init(&link->train);
922fb43630cSZhang Yubing
923fb43630cSZhang Yubing printf("training link: %u lane%s at %u MHz\n",
924fb43630cSZhang Yubing link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100);
925fb43630cSZhang Yubing
926fb43630cSZhang Yubing ret = dw_dp_link_configure(dp);
927fb43630cSZhang Yubing if (ret < 0) {
928fb43630cSZhang Yubing dev_err(dp->dev, "failed to configure DP link: %d\n", ret);
929fb43630cSZhang Yubing return ret;
930fb43630cSZhang Yubing }
931fb43630cSZhang Yubing
932fb43630cSZhang Yubing ret = dw_dp_link_clock_recovery(dp);
933fb43630cSZhang Yubing if (ret < 0) {
934fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed: %d\n", ret);
935fb43630cSZhang Yubing goto out;
936fb43630cSZhang Yubing }
937fb43630cSZhang Yubing
938fb43630cSZhang Yubing if (!link->train.clock_recovered) {
939fb43630cSZhang Yubing dev_err(dp->dev, "clock recovery failed, downgrading link\n");
940fb43630cSZhang Yubing
941fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp);
942fb43630cSZhang Yubing if (ret < 0)
943fb43630cSZhang Yubing goto out;
944fb43630cSZhang Yubing else
945fb43630cSZhang Yubing goto retry;
946fb43630cSZhang Yubing }
947fb43630cSZhang Yubing
948fb43630cSZhang Yubing printf("clock recovery succeeded\n");
949fb43630cSZhang Yubing
950fb43630cSZhang Yubing ret = dw_dp_link_channel_equalization(dp);
951fb43630cSZhang Yubing if (ret < 0) {
952fb43630cSZhang Yubing dev_err(dp->dev, "channel equalization failed: %d\n", ret);
953fb43630cSZhang Yubing goto out;
954fb43630cSZhang Yubing }
955fb43630cSZhang Yubing
956fb43630cSZhang Yubing if (!link->train.channel_equalized) {
957fb43630cSZhang Yubing dev_err(dp->dev,
958fb43630cSZhang Yubing "channel equalization failed, downgrading link\n");
959fb43630cSZhang Yubing
960fb43630cSZhang Yubing ret = dw_dp_link_downgrade(dp);
961fb43630cSZhang Yubing if (ret < 0)
962fb43630cSZhang Yubing goto out;
963fb43630cSZhang Yubing else
964fb43630cSZhang Yubing goto retry;
965fb43630cSZhang Yubing }
966fb43630cSZhang Yubing
967fb43630cSZhang Yubing printf("channel equalization succeeded\n");
968fb43630cSZhang Yubing
969fb43630cSZhang Yubing out:
970fb43630cSZhang Yubing dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);
971fb43630cSZhang Yubing return ret;
972fb43630cSZhang Yubing }
973fb43630cSZhang Yubing
dw_dp_link_enable(struct dw_dp * dp)974fb43630cSZhang Yubing static int dw_dp_link_enable(struct dw_dp *dp)
975fb43630cSZhang Yubing {
976fb43630cSZhang Yubing int ret;
977fb43630cSZhang Yubing
978fb43630cSZhang Yubing ret = dw_dp_link_power_up(dp);
979fb43630cSZhang Yubing if (ret < 0)
980fb43630cSZhang Yubing return ret;
981fb43630cSZhang Yubing
982fb43630cSZhang Yubing ret = dw_dp_link_train(dp);
983fb43630cSZhang Yubing if (ret < 0) {
984fb43630cSZhang Yubing dev_err(dp->dev, "link training failed: %d\n", ret);
985fb43630cSZhang Yubing return ret;
986fb43630cSZhang Yubing }
987fb43630cSZhang Yubing
988fb43630cSZhang Yubing return 0;
989fb43630cSZhang Yubing }
990fb43630cSZhang Yubing
dw_dp_set_phy_default_config(struct dw_dp * dp)9915efdd3e2SZhang Yubing static int dw_dp_set_phy_default_config(struct dw_dp *dp)
9925efdd3e2SZhang Yubing {
9935efdd3e2SZhang Yubing struct dw_dp_link *link = &dp->link;
9945efdd3e2SZhang Yubing union phy_configure_opts phy_cfg;
9955efdd3e2SZhang Yubing int ret, i, phy_rate;
9965efdd3e2SZhang Yubing
9975efdd3e2SZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported = false;
9985efdd3e2SZhang Yubing link->rate = 270000;
9995efdd3e2SZhang Yubing link->lanes = dp->phy.attrs.bus_width;
10005efdd3e2SZhang Yubing
10015efdd3e2SZhang Yubing link->caps.enhanced_framing = true;
10025efdd3e2SZhang Yubing link->caps.channel_coding = true;
10035efdd3e2SZhang Yubing link->caps.ssc = true;
10045efdd3e2SZhang Yubing
10055efdd3e2SZhang Yubing /* Move PHY to P3 */
10065efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
10075efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x3));
10085efdd3e2SZhang Yubing
10095efdd3e2SZhang Yubing for (i = 0; i < link->lanes; i++) {
10105efdd3e2SZhang Yubing phy_cfg.dp.voltage[i] = 3;
10115efdd3e2SZhang Yubing phy_cfg.dp.pre[i] = 0;
10125efdd3e2SZhang Yubing }
10135efdd3e2SZhang Yubing phy_cfg.dp.lanes = link->lanes;
10145efdd3e2SZhang Yubing phy_cfg.dp.link_rate = link->rate / 100;
10155efdd3e2SZhang Yubing phy_cfg.dp.ssc = link->caps.ssc;
10165efdd3e2SZhang Yubing phy_cfg.dp.set_lanes = true;
10175efdd3e2SZhang Yubing phy_cfg.dp.set_rate = true;
10185efdd3e2SZhang Yubing phy_cfg.dp.set_voltages = true;
10195efdd3e2SZhang Yubing ret = generic_phy_configure(&dp->phy, &phy_cfg);
10205efdd3e2SZhang Yubing if (ret)
10215efdd3e2SZhang Yubing return ret;
10225efdd3e2SZhang Yubing
10235efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES,
10245efdd3e2SZhang Yubing FIELD_PREP(PHY_LANES, link->lanes / 2));
10255efdd3e2SZhang Yubing
10265efdd3e2SZhang Yubing switch (link->rate) {
10275efdd3e2SZhang Yubing case 810000:
10285efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR3;
10295efdd3e2SZhang Yubing break;
10305efdd3e2SZhang Yubing case 540000:
10315efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR2;
10325efdd3e2SZhang Yubing break;
10335efdd3e2SZhang Yubing case 270000:
10345efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_HBR;
10355efdd3e2SZhang Yubing break;
10365efdd3e2SZhang Yubing case 162000:
10375efdd3e2SZhang Yubing default:
10385efdd3e2SZhang Yubing phy_rate = DPTX_PHYRATE_RBR;
10395efdd3e2SZhang Yubing break;
10405efdd3e2SZhang Yubing }
10415efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE,
10425efdd3e2SZhang Yubing FIELD_PREP(PHY_RATE, phy_rate));
10435efdd3e2SZhang Yubing
10445efdd3e2SZhang Yubing /* Move PHY to P0 */
10455efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN,
10465efdd3e2SZhang Yubing FIELD_PREP(PHY_POWERDOWN, 0x0));
10475efdd3e2SZhang Yubing
10485efdd3e2SZhang Yubing dw_dp_phy_xmit_enable(dp, link->lanes);
10495efdd3e2SZhang Yubing
10505efdd3e2SZhang Yubing regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN,
10515efdd3e2SZhang Yubing FIELD_PREP(ENHANCE_FRAMING_EN, 1));
10525efdd3e2SZhang Yubing
10535efdd3e2SZhang Yubing dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE);
10545efdd3e2SZhang Yubing return 0;
10555efdd3e2SZhang Yubing }
10565efdd3e2SZhang Yubing
dw_dp_send_sdp(struct dw_dp * dp,struct dw_dp_sdp * sdp)1057fb43630cSZhang Yubing static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp)
1058fb43630cSZhang Yubing {
1059fb43630cSZhang Yubing const u8 *payload = sdp->db;
1060fb43630cSZhang Yubing u32 reg;
1061fb43630cSZhang Yubing int i, nr = 0;
1062fb43630cSZhang Yubing
1063fb43630cSZhang Yubing reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4;
1064fb43630cSZhang Yubing
1065fb43630cSZhang Yubing /* SDP header */
1066fb43630cSZhang Yubing regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header));
1067fb43630cSZhang Yubing
1068fb43630cSZhang Yubing /* SDP data payload */
1069fb43630cSZhang Yubing for (i = 1; i < 9; i++, payload += 4)
1070fb43630cSZhang Yubing regmap_write(dp->regmap, reg + i * 4,
1071fb43630cSZhang Yubing FIELD_PREP(SDP_REGS, get_unaligned_le32(payload)));
1072fb43630cSZhang Yubing
1073fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL)
1074fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL,
1075fb43630cSZhang Yubing EN_VERTICAL_SDP << nr,
1076fb43630cSZhang Yubing EN_VERTICAL_SDP << nr);
1077fb43630cSZhang Yubing
1078fb43630cSZhang Yubing if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL)
1079fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL,
1080fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr,
1081fb43630cSZhang Yubing EN_HORIZONTAL_SDP << nr);
1082fb43630cSZhang Yubing
1083fb43630cSZhang Yubing return 0;
1084fb43630cSZhang Yubing }
1085fb43630cSZhang Yubing
dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp * vsc,struct dw_dp_sdp * sdp)1086fb43630cSZhang Yubing static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
1087fb43630cSZhang Yubing struct dw_dp_sdp *sdp)
1088fb43630cSZhang Yubing {
1089fb43630cSZhang Yubing sdp->header.HB0 = 0;
1090fb43630cSZhang Yubing sdp->header.HB1 = DP_SDP_VSC;
1091fb43630cSZhang Yubing sdp->header.HB2 = vsc->revision;
1092fb43630cSZhang Yubing sdp->header.HB3 = vsc->length;
1093fb43630cSZhang Yubing
1094fb43630cSZhang Yubing sdp->db[16] = (vsc->pixelformat & 0xf) << 4;
1095fb43630cSZhang Yubing sdp->db[16] |= vsc->colorimetry & 0xf;
1096fb43630cSZhang Yubing
1097fb43630cSZhang Yubing switch (vsc->bpc) {
1098fb43630cSZhang Yubing case 8:
1099fb43630cSZhang Yubing sdp->db[17] = 0x1;
1100fb43630cSZhang Yubing break;
1101fb43630cSZhang Yubing case 10:
1102fb43630cSZhang Yubing sdp->db[17] = 0x2;
1103fb43630cSZhang Yubing break;
1104fb43630cSZhang Yubing case 12:
1105fb43630cSZhang Yubing sdp->db[17] = 0x3;
1106fb43630cSZhang Yubing break;
1107fb43630cSZhang Yubing case 16:
1108fb43630cSZhang Yubing sdp->db[17] = 0x4;
1109fb43630cSZhang Yubing break;
1110fb43630cSZhang Yubing case 6:
1111fb43630cSZhang Yubing default:
1112fb43630cSZhang Yubing break;
1113fb43630cSZhang Yubing }
1114fb43630cSZhang Yubing
1115fb43630cSZhang Yubing if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
1116fb43630cSZhang Yubing sdp->db[17] |= 0x80;
1117fb43630cSZhang Yubing
1118fb43630cSZhang Yubing sdp->db[18] = vsc->content_type & 0x7;
1119fb43630cSZhang Yubing
1120fb43630cSZhang Yubing sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL;
1121fb43630cSZhang Yubing }
1122fb43630cSZhang Yubing
dw_dp_send_vsc_sdp(struct dw_dp * dp)1123fb43630cSZhang Yubing static int dw_dp_send_vsc_sdp(struct dw_dp *dp)
1124fb43630cSZhang Yubing {
1125fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video;
1126fb43630cSZhang Yubing struct drm_dp_vsc_sdp vsc = {};
1127fb43630cSZhang Yubing struct dw_dp_sdp sdp = {};
1128fb43630cSZhang Yubing
1129fb43630cSZhang Yubing vsc.revision = 0x5;
1130fb43630cSZhang Yubing vsc.length = 0x13;
1131fb43630cSZhang Yubing
1132fb43630cSZhang Yubing switch (video->color_format) {
1133fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444:
1134fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV444;
1135fb43630cSZhang Yubing break;
1136fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420:
1137fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV420;
1138fb43630cSZhang Yubing break;
1139fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422:
1140fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_YUV422;
1141fb43630cSZhang Yubing break;
1142fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444:
1143fb43630cSZhang Yubing default:
1144fb43630cSZhang Yubing vsc.pixelformat = DP_PIXELFORMAT_RGB;
1145fb43630cSZhang Yubing break;
1146fb43630cSZhang Yubing }
1147fb43630cSZhang Yubing
1148fb43630cSZhang Yubing if (video->color_format == DRM_COLOR_FORMAT_RGB444)
1149fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_DEFAULT;
1150fb43630cSZhang Yubing else
1151fb43630cSZhang Yubing vsc.colorimetry = DP_COLORIMETRY_BT709_YCC;
1152fb43630cSZhang Yubing
1153fb43630cSZhang Yubing vsc.bpc = video->bpc;
1154fb43630cSZhang Yubing vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA;
1155fb43630cSZhang Yubing vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED;
1156fb43630cSZhang Yubing
1157fb43630cSZhang Yubing dw_dp_vsc_sdp_pack(&vsc, &sdp);
1158fb43630cSZhang Yubing
1159fb43630cSZhang Yubing return dw_dp_send_sdp(dp, &sdp);
1160fb43630cSZhang Yubing }
1161fb43630cSZhang Yubing
dw_dp_video_set_pixel_mode(struct dw_dp * dp,u8 pixel_mode)1162fb43630cSZhang Yubing static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode)
1163fb43630cSZhang Yubing {
1164fb43630cSZhang Yubing switch (pixel_mode) {
1165fb43630cSZhang Yubing case DPTX_MP_SINGLE_PIXEL:
1166fb43630cSZhang Yubing case DPTX_MP_DUAL_PIXEL:
1167fb43630cSZhang Yubing case DPTX_MP_QUAD_PIXEL:
1168fb43630cSZhang Yubing break;
1169fb43630cSZhang Yubing default:
1170fb43630cSZhang Yubing return -EINVAL;
1171fb43630cSZhang Yubing }
1172fb43630cSZhang Yubing
1173fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT,
1174fb43630cSZhang Yubing FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode));
1175fb43630cSZhang Yubing
1176fb43630cSZhang Yubing return 0;
1177fb43630cSZhang Yubing }
1178fb43630cSZhang Yubing
dw_dp_video_set_msa(struct dw_dp * dp,u8 color_format,u8 bpc,u16 vstart,u16 hstart)1179fb43630cSZhang Yubing static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc,
1180fb43630cSZhang Yubing u16 vstart, u16 hstart)
1181fb43630cSZhang Yubing {
1182fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
1183fb43630cSZhang Yubing u16 misc = 0;
1184fb43630cSZhang Yubing
1185fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported)
1186fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_VSC_SDP;
1187fb43630cSZhang Yubing
1188fb43630cSZhang Yubing switch (color_format) {
1189fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444:
1190fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_RGB;
1191fb43630cSZhang Yubing break;
1192fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444:
1193fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709;
1194fb43630cSZhang Yubing break;
1195fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422:
1196fb43630cSZhang Yubing misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709;
1197fb43630cSZhang Yubing break;
1198fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420:
1199fb43630cSZhang Yubing break;
1200fb43630cSZhang Yubing default:
1201fb43630cSZhang Yubing return -EINVAL;
1202fb43630cSZhang Yubing }
1203fb43630cSZhang Yubing
1204fb43630cSZhang Yubing switch (bpc) {
1205fb43630cSZhang Yubing case 6:
1206fb43630cSZhang Yubing misc |= DP_MSA_MISC_6_BPC;
1207fb43630cSZhang Yubing break;
1208fb43630cSZhang Yubing case 8:
1209fb43630cSZhang Yubing misc |= DP_MSA_MISC_8_BPC;
1210fb43630cSZhang Yubing break;
1211fb43630cSZhang Yubing case 10:
1212fb43630cSZhang Yubing misc |= DP_MSA_MISC_10_BPC;
1213fb43630cSZhang Yubing break;
1214fb43630cSZhang Yubing case 12:
1215fb43630cSZhang Yubing misc |= DP_MSA_MISC_12_BPC;
1216fb43630cSZhang Yubing break;
1217fb43630cSZhang Yubing case 16:
1218fb43630cSZhang Yubing misc |= DP_MSA_MISC_16_BPC;
1219fb43630cSZhang Yubing break;
1220fb43630cSZhang Yubing default:
1221fb43630cSZhang Yubing return -EINVAL;
1222fb43630cSZhang Yubing }
1223fb43630cSZhang Yubing
1224fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA1,
1225fb43630cSZhang Yubing FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart));
1226fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc));
1227fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8));
1228fb43630cSZhang Yubing
1229fb43630cSZhang Yubing return 0;
1230fb43630cSZhang Yubing }
1231fb43630cSZhang Yubing
dw_dp_video_enable(struct dw_dp * dp)1232fb43630cSZhang Yubing static int dw_dp_video_enable(struct dw_dp *dp)
1233fb43630cSZhang Yubing {
1234fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video;
1235fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
1236fb43630cSZhang Yubing struct drm_display_mode *mode = &video->mode;
1237fb43630cSZhang Yubing u8 color_format = video->color_format;
1238fb43630cSZhang Yubing u8 bpc = video->bpc;
1239fb43630cSZhang Yubing u8 pixel_mode = video->pixel_mode;
1240fb43630cSZhang Yubing u8 bpp = video->bpp, init_threshold, vic;
1241fb43630cSZhang Yubing u32 hactive, hblank, h_sync_width, h_front_porch;
1242fb43630cSZhang Yubing u32 vactive, vblank, v_sync_width, v_front_porch;
1243fb43630cSZhang Yubing u32 vstart = mode->vtotal - mode->vsync_start;
1244fb43630cSZhang Yubing u32 hstart = mode->htotal - mode->hsync_start;
1245fb43630cSZhang Yubing u32 peak_stream_bandwidth, link_bandwidth;
1246fb43630cSZhang Yubing u32 average_bytes_per_tu, average_bytes_per_tu_frac;
1247fb43630cSZhang Yubing u32 ts, hblank_interval;
1248fb43630cSZhang Yubing u32 value;
1249fb43630cSZhang Yubing int ret;
1250fb43630cSZhang Yubing
1251fb43630cSZhang Yubing ret = dw_dp_video_set_pixel_mode(dp, pixel_mode);
1252fb43630cSZhang Yubing if (ret)
1253fb43630cSZhang Yubing return ret;
1254fb43630cSZhang Yubing
1255fb43630cSZhang Yubing ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart);
1256fb43630cSZhang Yubing if (ret)
1257fb43630cSZhang Yubing return ret;
1258fb43630cSZhang Yubing
1259fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING,
1260fb43630cSZhang Yubing FIELD_PREP(VIDEO_MAPPING, video->video_mapping));
1261fb43630cSZhang Yubing
1262fb43630cSZhang Yubing /* Configure DPTX_VINPUT_POLARITY_CTRL register */
1263fb43630cSZhang Yubing value = 0;
1264fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1265fb43630cSZhang Yubing value |= FIELD_PREP(HSYNC_IN_POLARITY, 1);
1266fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1267fb43630cSZhang Yubing value |= FIELD_PREP(VSYNC_IN_POLARITY, 1);
1268fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value);
1269fb43630cSZhang Yubing
1270fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG1 register */
1271fb43630cSZhang Yubing hactive = mode->hdisplay;
1272fb43630cSZhang Yubing hblank = mode->htotal - mode->hdisplay;
1273fb43630cSZhang Yubing value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank);
1274fb43630cSZhang Yubing if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1275fb43630cSZhang Yubing value |= FIELD_PREP(I_P, 1);
1276fb43630cSZhang Yubing vic = drm_match_cea_mode(mode);
1277fb43630cSZhang Yubing if (vic == 5 || vic == 6 || vic == 7 ||
1278fb43630cSZhang Yubing vic == 10 || vic == 11 || vic == 20 ||
1279fb43630cSZhang Yubing vic == 21 || vic == 22 || vic == 39 ||
1280fb43630cSZhang Yubing vic == 25 || vic == 26 || vic == 40 ||
1281fb43630cSZhang Yubing vic == 44 || vic == 45 || vic == 46 ||
1282fb43630cSZhang Yubing vic == 50 || vic == 51 || vic == 54 ||
1283fb43630cSZhang Yubing vic == 55 || vic == 58 || vic == 59)
1284fb43630cSZhang Yubing value |= R_V_BLANK_IN_OSC;
1285fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value);
1286fb43630cSZhang Yubing
1287fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG2 register */
1288fb43630cSZhang Yubing vblank = mode->vtotal - mode->vdisplay;
1289fb43630cSZhang Yubing vactive = mode->vdisplay;
1290fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2,
1291fb43630cSZhang Yubing FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive));
1292fb43630cSZhang Yubing
1293fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG3 register */
1294fb43630cSZhang Yubing h_sync_width = mode->hsync_end - mode->hsync_start;
1295fb43630cSZhang Yubing h_front_porch = mode->hsync_start - mode->hdisplay;
1296fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3,
1297fb43630cSZhang Yubing FIELD_PREP(H_SYNC_WIDTH, h_sync_width) |
1298fb43630cSZhang Yubing FIELD_PREP(H_FRONT_PORCH, h_front_porch));
1299fb43630cSZhang Yubing
1300fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG4 register */
1301fb43630cSZhang Yubing v_sync_width = mode->vsync_end - mode->vsync_start;
1302fb43630cSZhang Yubing v_front_porch = mode->vsync_start - mode->vdisplay;
1303fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4,
1304fb43630cSZhang Yubing FIELD_PREP(V_SYNC_WIDTH, v_sync_width) |
1305fb43630cSZhang Yubing FIELD_PREP(V_FRONT_PORCH, v_front_porch));
1306fb43630cSZhang Yubing
1307fb43630cSZhang Yubing /* Configure DPTX_VIDEO_CONFIG5 register */
1308fb43630cSZhang Yubing peak_stream_bandwidth = mode->clock * bpp / 8;
1309fb43630cSZhang Yubing link_bandwidth = (link->rate / 1000) * link->lanes;
1310fb43630cSZhang Yubing ts = peak_stream_bandwidth * 64 / link_bandwidth;
1311fb43630cSZhang Yubing average_bytes_per_tu = ts / 1000;
1312fb43630cSZhang Yubing average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10;
1313fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_SINGLE_PIXEL) {
1314fb43630cSZhang Yubing if (average_bytes_per_tu < 6)
1315fb43630cSZhang Yubing init_threshold = 32;
1316fb43630cSZhang Yubing else if (hblank <= 80 &&
1317fb43630cSZhang Yubing color_format != DRM_COLOR_FORMAT_YCRCB420)
1318fb43630cSZhang Yubing init_threshold = 12;
1319fb43630cSZhang Yubing else if (hblank <= 40 &&
1320fb43630cSZhang Yubing color_format == DRM_COLOR_FORMAT_YCRCB420)
1321fb43630cSZhang Yubing init_threshold = 3;
1322fb43630cSZhang Yubing else
1323fb43630cSZhang Yubing init_threshold = 16;
1324fb43630cSZhang Yubing } else {
1325fb43630cSZhang Yubing u32 t1 = 0, t2 = 0, t3 = 0;
1326fb43630cSZhang Yubing
1327fb43630cSZhang Yubing switch (bpc) {
1328fb43630cSZhang Yubing case 6:
1329fb43630cSZhang Yubing t1 = (4 * 1000 / 9) * link->lanes;
1330fb43630cSZhang Yubing break;
1331fb43630cSZhang Yubing case 8:
1332fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1333fb43630cSZhang Yubing t1 = (1000 / 2) * link->lanes;
1334fb43630cSZhang Yubing } else {
1335fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1336fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes;
1337fb43630cSZhang Yubing else
1338fb43630cSZhang Yubing t1 = (3000 / 16) * link->lanes;
1339fb43630cSZhang Yubing }
1340fb43630cSZhang Yubing break;
1341fb43630cSZhang Yubing case 10:
1342fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422)
1343fb43630cSZhang Yubing t1 = (2000 / 5) * link->lanes;
1344fb43630cSZhang Yubing else
1345fb43630cSZhang Yubing t1 = (4000 / 15) * link->lanes;
1346fb43630cSZhang Yubing break;
1347fb43630cSZhang Yubing case 12:
1348fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB422) {
1349fb43630cSZhang Yubing if (pixel_mode == DPTX_MP_DUAL_PIXEL)
1350fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes;
1351fb43630cSZhang Yubing else
1352fb43630cSZhang Yubing t1 = (1000 / 3) * link->lanes;
1353fb43630cSZhang Yubing } else {
1354fb43630cSZhang Yubing t1 = (2000 / 9) * link->lanes;
1355fb43630cSZhang Yubing }
1356fb43630cSZhang Yubing break;
1357fb43630cSZhang Yubing case 16:
1358fb43630cSZhang Yubing if (color_format != DRM_COLOR_FORMAT_YCRCB422 &&
1359fb43630cSZhang Yubing pixel_mode == DPTX_MP_DUAL_PIXEL)
1360fb43630cSZhang Yubing t1 = (1000 / 6) * link->lanes;
1361fb43630cSZhang Yubing else
1362fb43630cSZhang Yubing t1 = (1000 / 4) * link->lanes;
1363fb43630cSZhang Yubing break;
1364fb43630cSZhang Yubing default:
1365fb43630cSZhang Yubing return -EINVAL;
1366fb43630cSZhang Yubing }
1367fb43630cSZhang Yubing
1368fb43630cSZhang Yubing if (color_format == DRM_COLOR_FORMAT_YCRCB420)
1369fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / (mode->clock / 2);
1370fb43630cSZhang Yubing else
1371fb43630cSZhang Yubing t2 = (link->rate / 4) * 1000 / mode->clock;
1372fb43630cSZhang Yubing
1373fb43630cSZhang Yubing if (average_bytes_per_tu_frac)
1374fb43630cSZhang Yubing t3 = average_bytes_per_tu + 1;
1375fb43630cSZhang Yubing else
1376fb43630cSZhang Yubing t3 = average_bytes_per_tu;
1377fb43630cSZhang Yubing init_threshold = t1 * t2 * t3 / (1000 * 1000);
1378fb43630cSZhang Yubing if (init_threshold <= 16 || average_bytes_per_tu < 10)
1379fb43630cSZhang Yubing init_threshold = 40;
1380fb43630cSZhang Yubing }
1381fb43630cSZhang Yubing
1382fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5,
1383fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) |
1384fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC,
1385fb43630cSZhang Yubing average_bytes_per_tu_frac) |
1386fb43630cSZhang Yubing FIELD_PREP(INIT_THRESHOLD, init_threshold) |
1387fb43630cSZhang Yubing FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu));
1388fb43630cSZhang Yubing
1389fb43630cSZhang Yubing /* Configure DPTX_VIDEO_HBLANK_INTERVAL register */
1390fb43630cSZhang Yubing hblank_interval = hblank * (link->rate / 4) / mode->clock;
1391fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL,
1392fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL_EN, 1) |
1393fb43630cSZhang Yubing FIELD_PREP(HBLANK_INTERVAL, hblank_interval));
1394fb43630cSZhang Yubing
1395fb43630cSZhang Yubing /* Video stream enable */
1396fb43630cSZhang Yubing regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE,
1397fb43630cSZhang Yubing FIELD_PREP(VIDEO_STREAM_ENABLE, 1));
1398fb43630cSZhang Yubing
1399fb43630cSZhang Yubing if (link->vsc_sdp_extension_for_colorimetry_supported)
1400fb43630cSZhang Yubing dw_dp_send_vsc_sdp(dp);
1401fb43630cSZhang Yubing
1402fb43630cSZhang Yubing return 0;
1403fb43630cSZhang Yubing }
1404fb43630cSZhang Yubing
dw_dp_detect(struct dw_dp * dp)1405fb43630cSZhang Yubing static bool dw_dp_detect(struct dw_dp *dp)
1406fb43630cSZhang Yubing {
1407fb43630cSZhang Yubing u32 value;
1408fb43630cSZhang Yubing
1409fb43630cSZhang Yubing if (dm_gpio_is_valid(&dp->hpd_gpio))
1410fb43630cSZhang Yubing return dm_gpio_get_value(&dp->hpd_gpio);
1411fb43630cSZhang Yubing
1412fb43630cSZhang Yubing regmap_read(dp->regmap, DPTX_HPD_STATUS, &value);
14135fbef17aSZhang Yubing if (FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG) {
1414fb43630cSZhang Yubing regmap_write(dp->regmap, DPTX_HPD_STATUS, HPD_HOT_PLUG);
1415fb43630cSZhang Yubing return true;
1416fb43630cSZhang Yubing }
1417fb43630cSZhang Yubing
1418fb43630cSZhang Yubing return false;
1419fb43630cSZhang Yubing }
1420fb43630cSZhang Yubing
connector_to_dw_dp(struct rockchip_connector * conn)14217ac3c934SZhang Yubing static struct dw_dp *connector_to_dw_dp(struct rockchip_connector *conn)
14227ac3c934SZhang Yubing {
14237ac3c934SZhang Yubing struct dw_dp *dp;
14247ac3c934SZhang Yubing
14257ac3c934SZhang Yubing if (dev_get_priv(conn->dev))
14267ac3c934SZhang Yubing dp = dev_get_priv(conn->dev);
14277ac3c934SZhang Yubing else
14287ac3c934SZhang Yubing dp = dev_get_priv(conn->dev->parent);
14297ac3c934SZhang Yubing
14307ac3c934SZhang Yubing return dp;
14317ac3c934SZhang Yubing }
14327ac3c934SZhang Yubing
dw_dp_connector_init(struct rockchip_connector * conn,struct display_state * state)14330594ce39SZhang Yubing static int dw_dp_connector_init(struct rockchip_connector *conn, struct display_state *state)
1434fb43630cSZhang Yubing {
1435fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state;
14367ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
1437fb43630cSZhang Yubing int ret;
1438fb43630cSZhang Yubing
14397ac3c934SZhang Yubing if (dev_get_priv(conn->dev))
14407ac3c934SZhang Yubing dp = dev_get_priv(conn->dev);
14417ac3c934SZhang Yubing else
14427ac3c934SZhang Yubing dp = dev_get_priv(conn->dev->parent);
1443fb43630cSZhang Yubing conn_state->output_if |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0;
1444fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1445df0a5c43SDamon Ding conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
1446fb43630cSZhang Yubing
1447fb43630cSZhang Yubing clk_set_defaults(dp->dev);
1448fb43630cSZhang Yubing
1449fb43630cSZhang Yubing reset_assert(&dp->reset);
1450fb43630cSZhang Yubing udelay(20);
1451fb43630cSZhang Yubing reset_deassert(&dp->reset);
1452fb43630cSZhang Yubing
1453fb43630cSZhang Yubing conn_state->disp_info = rockchip_get_disp_info(conn_state->type,
1454fb43630cSZhang Yubing dp->id);
1455fb43630cSZhang Yubing dw_dp_init(dp);
1456fb43630cSZhang Yubing ret = generic_phy_power_on(&dp->phy);
1457fb43630cSZhang Yubing
1458fb43630cSZhang Yubing return ret;
1459fb43630cSZhang Yubing }
1460fb43630cSZhang Yubing
dw_dp_connector_get_edid(struct rockchip_connector * conn,struct display_state * state)14610594ce39SZhang Yubing static int dw_dp_connector_get_edid(struct rockchip_connector *conn, struct display_state *state)
1462fb43630cSZhang Yubing {
1463fb43630cSZhang Yubing int ret;
1464fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state;
14657ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
1466fb43630cSZhang Yubing
14679c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
14689c170041SAlgea Cao if (!conn_state->edid)
14699c170041SAlgea Cao ret = -EINVAL;
1470fb43630cSZhang Yubing
1471fb43630cSZhang Yubing return ret;
1472fb43630cSZhang Yubing }
1473fb43630cSZhang Yubing
dw_dp_get_output_fmts_index(u32 bus_format)14741cf3aaecSZhang Yubing static int dw_dp_get_output_fmts_index(u32 bus_format)
14751cf3aaecSZhang Yubing {
14761cf3aaecSZhang Yubing int i;
14771cf3aaecSZhang Yubing
14781cf3aaecSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
14791cf3aaecSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
14801cf3aaecSZhang Yubing
14811cf3aaecSZhang Yubing if (fmt->bus_format == bus_format)
14821cf3aaecSZhang Yubing break;
14831cf3aaecSZhang Yubing }
14841cf3aaecSZhang Yubing
14851cf3aaecSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts))
14861cf3aaecSZhang Yubing return 1;
14871cf3aaecSZhang Yubing
14881cf3aaecSZhang Yubing return i;
14891cf3aaecSZhang Yubing }
14901cf3aaecSZhang Yubing
dw_dp_connector_prepare(struct rockchip_connector * conn,struct display_state * state)14910594ce39SZhang Yubing static int dw_dp_connector_prepare(struct rockchip_connector *conn, struct display_state *state)
14921cf3aaecSZhang Yubing {
14931cf3aaecSZhang Yubing struct connector_state *conn_state = &state->conn_state;
14947ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
14951cf3aaecSZhang Yubing struct dw_dp_video *video = &dp->video;
14961cf3aaecSZhang Yubing int bus_fmt;
14971cf3aaecSZhang Yubing
14981cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(conn_state->bus_format);
14991cf3aaecSZhang Yubing video->video_mapping = possible_output_fmts[bus_fmt].video_mapping;
15001cf3aaecSZhang Yubing video->color_format = possible_output_fmts[bus_fmt].color_format;
15011cf3aaecSZhang Yubing video->bus_format = possible_output_fmts[bus_fmt].bus_format;
15021cf3aaecSZhang Yubing video->bpc = possible_output_fmts[bus_fmt].bpc;
15031cf3aaecSZhang Yubing video->bpp = possible_output_fmts[bus_fmt].bpp;
15041cf3aaecSZhang Yubing
15051cf3aaecSZhang Yubing return 0;
15061cf3aaecSZhang Yubing }
15071cf3aaecSZhang Yubing
dw_dp_connector_enable(struct rockchip_connector * conn,struct display_state * state)15080594ce39SZhang Yubing static int dw_dp_connector_enable(struct rockchip_connector *conn, struct display_state *state)
1509fb43630cSZhang Yubing {
1510fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state;
1511fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode;
15127ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
1513fb43630cSZhang Yubing struct dw_dp_video *video = &dp->video;
1514fb43630cSZhang Yubing int ret;
1515fb43630cSZhang Yubing
1516fb43630cSZhang Yubing memcpy(&video->mode, mode, sizeof(video->mode));
1517fb43630cSZhang Yubing
15185efdd3e2SZhang Yubing if (dp->force_output) {
15195efdd3e2SZhang Yubing ret = dw_dp_set_phy_default_config(dp);
15205efdd3e2SZhang Yubing if (ret < 0)
15215efdd3e2SZhang Yubing printf("failed to set phy_default config: %d\n", ret);
15225efdd3e2SZhang Yubing } else {
1523fb43630cSZhang Yubing ret = dw_dp_link_enable(dp);
1524fb43630cSZhang Yubing if (ret < 0) {
15255efdd3e2SZhang Yubing printf("failed to enable link: %d\n", ret);
1526fb43630cSZhang Yubing return ret;
1527fb43630cSZhang Yubing }
15285efdd3e2SZhang Yubing }
1529fb43630cSZhang Yubing
1530fb43630cSZhang Yubing ret = dw_dp_video_enable(dp);
1531fb43630cSZhang Yubing if (ret < 0) {
15325efdd3e2SZhang Yubing printf("failed to enable video: %d\n", ret);
1533fb43630cSZhang Yubing return ret;
1534fb43630cSZhang Yubing }
1535fb43630cSZhang Yubing
1536fb43630cSZhang Yubing return 0;
1537fb43630cSZhang Yubing }
1538fb43630cSZhang Yubing
dw_dp_connector_disable(struct rockchip_connector * conn,struct display_state * state)15390594ce39SZhang Yubing static int dw_dp_connector_disable(struct rockchip_connector *conn, struct display_state *state)
1540fb43630cSZhang Yubing {
1541fb43630cSZhang Yubing /* TODO */
1542fb43630cSZhang Yubing
1543fb43630cSZhang Yubing return 0;
1544fb43630cSZhang Yubing }
1545fb43630cSZhang Yubing
dw_dp_connector_detect(struct rockchip_connector * conn,struct display_state * state)15460594ce39SZhang Yubing static int dw_dp_connector_detect(struct rockchip_connector *conn, struct display_state *state)
1547fb43630cSZhang Yubing {
15487ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
15491cf3aaecSZhang Yubing int status, tries, ret;
1550fb43630cSZhang Yubing
1551a66bd69eSZhang Yubing for (tries = 0; tries < 200; tries++) {
1552fb43630cSZhang Yubing status = dw_dp_detect(dp);
1553fb43630cSZhang Yubing if (status)
1554fb43630cSZhang Yubing break;
1555fb43630cSZhang Yubing mdelay(2);
1556fb43630cSZhang Yubing }
1557fb43630cSZhang Yubing
15585efdd3e2SZhang Yubing if (state->force_output && !status)
15595efdd3e2SZhang Yubing dp->force_output = true;
15605efdd3e2SZhang Yubing
15615efdd3e2SZhang Yubing if (!status && !dp->force_output)
1562fb43630cSZhang Yubing generic_phy_power_off(&dp->phy);
1563fb43630cSZhang Yubing
15641cf3aaecSZhang Yubing if (status && !dp->force_output) {
15651cf3aaecSZhang Yubing ret = dw_dp_link_probe(dp);
15661cf3aaecSZhang Yubing if (ret)
15671cf3aaecSZhang Yubing printf("failed to probe DP link: %d\n", ret);
15681cf3aaecSZhang Yubing }
15691cf3aaecSZhang Yubing
1570fb43630cSZhang Yubing return status;
1571fb43630cSZhang Yubing }
1572fb43630cSZhang Yubing
dw_dp_mode_valid(struct dw_dp * dp,struct hdmi_edid_data * edid_data)1573fb43630cSZhang Yubing static int dw_dp_mode_valid(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1574fb43630cSZhang Yubing {
1575fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
1576fb43630cSZhang Yubing struct drm_display_info *di = &edid_data->display_info;
1577fb43630cSZhang Yubing u32 min_bpp;
1578fb43630cSZhang Yubing int i;
1579fb43630cSZhang Yubing
1580fb43630cSZhang Yubing if (di->color_formats & DRM_COLOR_FORMAT_YCRCB420 &&
1581fb43630cSZhang Yubing link->vsc_sdp_extension_for_colorimetry_supported)
1582fb43630cSZhang Yubing min_bpp = 12;
1583fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_YCRCB422)
1584fb43630cSZhang Yubing min_bpp = 16;
1585fb43630cSZhang Yubing else if (di->color_formats & DRM_COLOR_FORMAT_RGB444)
1586fb43630cSZhang Yubing min_bpp = 18;
1587fb43630cSZhang Yubing else
1588fb43630cSZhang Yubing min_bpp = 24;
1589fb43630cSZhang Yubing
1590fb43630cSZhang Yubing for (i = 0; i < edid_data->modes; i++) {
1591fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, &edid_data->mode_buf[i], min_bpp, link->lanes,
1592fb43630cSZhang Yubing link->rate))
1593fb43630cSZhang Yubing edid_data->mode_buf[i].invalid = true;
1594fb43630cSZhang Yubing }
1595fb43630cSZhang Yubing
1596fb43630cSZhang Yubing return 0;
1597fb43630cSZhang Yubing }
1598fb43630cSZhang Yubing
dw_dp_get_output_bus_fmts(struct dw_dp * dp,struct hdmi_edid_data * edid_data)1599fb43630cSZhang Yubing static u32 dw_dp_get_output_bus_fmts(struct dw_dp *dp, struct hdmi_edid_data *edid_data)
1600fb43630cSZhang Yubing {
1601fb43630cSZhang Yubing struct dw_dp_link *link = &dp->link;
1602fb43630cSZhang Yubing unsigned int i;
1603fb43630cSZhang Yubing
1604fb43630cSZhang Yubing for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) {
1605fb43630cSZhang Yubing const struct dw_dp_output_format *fmt = &possible_output_fmts[i];
1606fb43630cSZhang Yubing
1607fb43630cSZhang Yubing if (fmt->bpc > edid_data->display_info.bpc)
1608fb43630cSZhang Yubing continue;
1609fb43630cSZhang Yubing
1610fb43630cSZhang Yubing if (!(edid_data->display_info.color_formats & fmt->color_format))
1611fb43630cSZhang Yubing continue;
1612fb43630cSZhang Yubing
1613fb43630cSZhang Yubing if (fmt->color_format == DRM_COLOR_FORMAT_YCRCB420 &&
1614fb43630cSZhang Yubing !link->vsc_sdp_extension_for_colorimetry_supported)
1615fb43630cSZhang Yubing continue;
1616fb43630cSZhang Yubing
1617*80cb0596SZhang Yubing if (drm_mode_is_420_only(&edid_data->display_info, edid_data->preferred_mode) &&
1618fb43630cSZhang Yubing fmt->color_format != DRM_COLOR_FORMAT_YCRCB420)
1619fb43630cSZhang Yubing continue;
1620fb43630cSZhang Yubing
1621fb43630cSZhang Yubing if (!dw_dp_bandwidth_ok(dp, edid_data->preferred_mode, fmt->bpp, link->lanes,
1622fb43630cSZhang Yubing link->rate))
1623fb43630cSZhang Yubing continue;
1624fb43630cSZhang Yubing
1625fb43630cSZhang Yubing break;
1626fb43630cSZhang Yubing }
1627fb43630cSZhang Yubing
1628fb43630cSZhang Yubing if (i == ARRAY_SIZE(possible_output_fmts))
1629fb43630cSZhang Yubing return 1;
1630fb43630cSZhang Yubing
1631fb43630cSZhang Yubing return i;
1632fb43630cSZhang Yubing }
1633fb43630cSZhang Yubing
dw_dp_connector_get_timing(struct rockchip_connector * conn,struct display_state * state)16340594ce39SZhang Yubing static int dw_dp_connector_get_timing(struct rockchip_connector *conn, struct display_state *state)
1635fb43630cSZhang Yubing {
16369c170041SAlgea Cao int ret = 0, i;
1637fb43630cSZhang Yubing struct connector_state *conn_state = &state->conn_state;
16387ac3c934SZhang Yubing struct dw_dp *dp = connector_to_dw_dp(conn);
1639fb43630cSZhang Yubing struct drm_display_mode *mode = &conn_state->mode;
1640fb43630cSZhang Yubing struct hdmi_edid_data edid_data;
1641fb43630cSZhang Yubing struct drm_display_mode *mode_buf;
1642364352d1SZhang Yubing struct vop_rect rect;
1643fb43630cSZhang Yubing u32 bus_fmt;
1644fb43630cSZhang Yubing
1645fb43630cSZhang Yubing mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
1646fb43630cSZhang Yubing if (!mode_buf)
1647fb43630cSZhang Yubing return -ENOMEM;
1648fb43630cSZhang Yubing
1649fb43630cSZhang Yubing memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
1650fb43630cSZhang Yubing memset(&edid_data, 0, sizeof(struct hdmi_edid_data));
1651fb43630cSZhang Yubing edid_data.mode_buf = mode_buf;
1652fb43630cSZhang Yubing
16535efdd3e2SZhang Yubing if (!dp->force_output) {
16549c170041SAlgea Cao conn_state->edid = drm_do_get_edid(&dp->aux.ddc);
16559c170041SAlgea Cao if (conn_state->edid)
1656fb43630cSZhang Yubing ret = drm_add_edid_modes(&edid_data, conn_state->edid);
1657fb43630cSZhang Yubing
16589c170041SAlgea Cao if (ret <= 0) {
1659fb43630cSZhang Yubing printf("failed to get edid\n");
1660fb43630cSZhang Yubing goto err;
1661fb43630cSZhang Yubing }
1662fb43630cSZhang Yubing
16637ac3c934SZhang Yubing //drm_rk_filter_whitelist(&edid_data);
1664364352d1SZhang Yubing if (state->conn_state.secondary) {
1665364352d1SZhang Yubing rect.width = state->crtc_state.max_output.width / 2;
1666364352d1SZhang Yubing rect.height = state->crtc_state.max_output.height / 2;
1667364352d1SZhang Yubing } else {
1668364352d1SZhang Yubing rect.width = state->crtc_state.max_output.width;
1669364352d1SZhang Yubing rect.height = state->crtc_state.max_output.height;
1670364352d1SZhang Yubing }
1671364352d1SZhang Yubing
1672364352d1SZhang Yubing drm_mode_max_resolution_filter(&edid_data, &rect);
1673fb43630cSZhang Yubing dw_dp_mode_valid(dp, &edid_data);
1674fb43630cSZhang Yubing
1675fb43630cSZhang Yubing if (!drm_mode_prune_invalid(&edid_data)) {
16764f1d0c46SZhang Yubing printf("can't find valid dp mode\n");
1677fb43630cSZhang Yubing ret = -EINVAL;
1678fb43630cSZhang Yubing goto err;
1679fb43630cSZhang Yubing }
1680fb43630cSZhang Yubing
1681fb43630cSZhang Yubing for (i = 0; i < edid_data.modes; i++)
1682fb43630cSZhang Yubing edid_data.mode_buf[i].vrefresh =
1683fb43630cSZhang Yubing drm_mode_vrefresh(&edid_data.mode_buf[i]);
1684fb43630cSZhang Yubing
1685fb43630cSZhang Yubing drm_mode_sort(&edid_data);
1686fb43630cSZhang Yubing memcpy(mode, edid_data.preferred_mode, sizeof(struct drm_display_mode));
16875efdd3e2SZhang Yubing }
1688fb43630cSZhang Yubing
1689fb43630cSZhang Yubing if (state->force_output)
16901cf3aaecSZhang Yubing bus_fmt = dw_dp_get_output_fmts_index(state->force_bus_format);
1691fb43630cSZhang Yubing else
1692fb43630cSZhang Yubing bus_fmt = dw_dp_get_output_bus_fmts(dp, &edid_data);
1693fb43630cSZhang Yubing
16941cf3aaecSZhang Yubing conn_state->bus_format = possible_output_fmts[bus_fmt].bus_format;
1695fb43630cSZhang Yubing
16961cf3aaecSZhang Yubing switch (possible_output_fmts[bus_fmt].color_format) {
1697fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB420:
1698fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_YUV420;
1699fb43630cSZhang Yubing break;
1700fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB422:
1701fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
1702fb43630cSZhang Yubing break;
1703fb43630cSZhang Yubing case DRM_COLOR_FORMAT_RGB444:
1704fb43630cSZhang Yubing case DRM_COLOR_FORMAT_YCRCB444:
1705fb43630cSZhang Yubing default:
1706fb43630cSZhang Yubing conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
1707fb43630cSZhang Yubing break;
1708fb43630cSZhang Yubing }
1709fb43630cSZhang Yubing
1710fb43630cSZhang Yubing err:
1711fb43630cSZhang Yubing free(mode_buf);
1712fb43630cSZhang Yubing
1713fb43630cSZhang Yubing return 0;
1714fb43630cSZhang Yubing }
1715fb43630cSZhang Yubing
1716fb43630cSZhang Yubing static const struct rockchip_connector_funcs dw_dp_connector_funcs = {
1717fb43630cSZhang Yubing .init = dw_dp_connector_init,
1718fb43630cSZhang Yubing .get_edid = dw_dp_connector_get_edid,
17191cf3aaecSZhang Yubing .prepare = dw_dp_connector_prepare,
1720fb43630cSZhang Yubing .enable = dw_dp_connector_enable,
1721fb43630cSZhang Yubing .disable = dw_dp_connector_disable,
1722fb43630cSZhang Yubing .detect = dw_dp_connector_detect,
1723fb43630cSZhang Yubing .get_timing = dw_dp_connector_get_timing,
1724fb43630cSZhang Yubing };
1725fb43630cSZhang Yubing
dw_dp_ddc_init(struct dw_dp * dp)1726fb43630cSZhang Yubing static int dw_dp_ddc_init(struct dw_dp *dp)
1727fb43630cSZhang Yubing {
1728fb43630cSZhang Yubing dp->aux.name = "dw-dp";
1729fb43630cSZhang Yubing dp->aux.dev = dp->dev;
1730fb43630cSZhang Yubing dp->aux.transfer = dw_dp_aux_transfer;
1731fb43630cSZhang Yubing dp->aux.ddc.ddc_xfer = drm_dp_i2c_xfer;
1732fb43630cSZhang Yubing
1733fb43630cSZhang Yubing return 0;
1734fb43630cSZhang Yubing }
1735fb43630cSZhang Yubing
dw_dp_parse_link_frequencies(struct dw_dp * dp)1736549d42b6SWyon Bi static u32 dw_dp_parse_link_frequencies(struct dw_dp *dp)
1737549d42b6SWyon Bi {
1738549d42b6SWyon Bi struct udevice *dev = dp->dev;
1739549d42b6SWyon Bi const struct device_node *endpoint;
1740549d42b6SWyon Bi u64 frequency = 0;
1741549d42b6SWyon Bi
1742549d42b6SWyon Bi endpoint = rockchip_of_graph_get_endpoint_by_regs(dev->node, 1, 0);
1743549d42b6SWyon Bi if (!endpoint)
1744549d42b6SWyon Bi return 0;
1745549d42b6SWyon Bi
1746549d42b6SWyon Bi if (of_property_read_u64(endpoint, "link-frequencies", &frequency) < 0)
1747549d42b6SWyon Bi return 0;
1748549d42b6SWyon Bi
1749549d42b6SWyon Bi if (!frequency)
1750549d42b6SWyon Bi return 0;
1751549d42b6SWyon Bi
1752549d42b6SWyon Bi do_div(frequency, 10 * 1000); /* symbol rate kbytes */
1753549d42b6SWyon Bi
1754549d42b6SWyon Bi switch (frequency) {
1755549d42b6SWyon Bi case 162000:
1756549d42b6SWyon Bi case 270000:
1757549d42b6SWyon Bi case 540000:
1758549d42b6SWyon Bi case 810000:
1759549d42b6SWyon Bi break;
1760549d42b6SWyon Bi default:
1761549d42b6SWyon Bi dev_err(dev, "invalid link frequency value: %llu\n", frequency);
1762549d42b6SWyon Bi return 0;
1763549d42b6SWyon Bi }
1764549d42b6SWyon Bi
1765549d42b6SWyon Bi return frequency;
1766549d42b6SWyon Bi }
1767549d42b6SWyon Bi
dw_dp_parse_dt(struct dw_dp * dp)1768549d42b6SWyon Bi static int dw_dp_parse_dt(struct dw_dp *dp)
1769549d42b6SWyon Bi {
1770549d42b6SWyon Bi dp->force_hpd = dev_read_bool(dp->dev, "force-hpd");
1771549d42b6SWyon Bi
1772549d42b6SWyon Bi dp->max_link_rate = dw_dp_parse_link_frequencies(dp);
1773549d42b6SWyon Bi if (!dp->max_link_rate)
1774549d42b6SWyon Bi dp->max_link_rate = 810000;
1775549d42b6SWyon Bi
1776549d42b6SWyon Bi return 0;
1777549d42b6SWyon Bi }
1778549d42b6SWyon Bi
dw_dp_probe(struct udevice * dev)1779fb43630cSZhang Yubing static int dw_dp_probe(struct udevice *dev)
1780fb43630cSZhang Yubing {
1781fb43630cSZhang Yubing struct dw_dp *dp = dev_get_priv(dev);
17825fc83b1eSZhang Yubing const struct dw_dp_chip_data *pdata =
17835fc83b1eSZhang Yubing (const struct dw_dp_chip_data *)dev_get_driver_data(dev);
1784fb43630cSZhang Yubing int ret;
1785fb43630cSZhang Yubing
1786fb43630cSZhang Yubing ret = regmap_init_mem(dev, &dp->regmap);
1787fb43630cSZhang Yubing if (ret)
1788fb43630cSZhang Yubing return ret;
1789fb43630cSZhang Yubing
1790fb43630cSZhang Yubing dp->id = of_alias_get_id(ofnode_to_np(dev->node), "dp");
1791fb43630cSZhang Yubing if (dp->id < 0)
1792fb43630cSZhang Yubing dp->id = 0;
1793fb43630cSZhang Yubing
17945fc83b1eSZhang Yubing dp->video.pixel_mode = pdata->pixel_mode;
17955fc83b1eSZhang Yubing
1796638855e8SFinley Xiao #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD)
1797638855e8SFinley Xiao ret = power_domain_get(dev, &dp->pwrdom);
1798638855e8SFinley Xiao if (ret) {
1799638855e8SFinley Xiao dev_err(dev, "failed to get pwrdom: %d\n", ret);
1800638855e8SFinley Xiao return ret;
1801638855e8SFinley Xiao }
1802638855e8SFinley Xiao ret = power_domain_on(&dp->pwrdom);
1803638855e8SFinley Xiao if (ret) {
1804638855e8SFinley Xiao dev_err(dev, "failed to power on pd: %d\n", ret);
1805638855e8SFinley Xiao return ret;
1806638855e8SFinley Xiao }
1807638855e8SFinley Xiao ret = clk_get_bulk(dev, &dp->clks);
1808638855e8SFinley Xiao if (ret) {
1809638855e8SFinley Xiao dev_err(dev, "failed to get clk: %d\n", ret);
1810638855e8SFinley Xiao return ret;
1811638855e8SFinley Xiao }
1812638855e8SFinley Xiao ret = clk_enable_bulk(&dp->clks);
1813638855e8SFinley Xiao if (ret) {
1814638855e8SFinley Xiao dev_err(dev, "failed to enable clk: %d\n", ret);
1815638855e8SFinley Xiao return ret;
1816638855e8SFinley Xiao }
1817638855e8SFinley Xiao #endif
1818638855e8SFinley Xiao
1819fb43630cSZhang Yubing ret = reset_get_by_index(dev, 0, &dp->reset);
1820fb43630cSZhang Yubing if (ret) {
1821fb43630cSZhang Yubing dev_err(dev, "failed to get reset control: %d\n", ret);
1822fb43630cSZhang Yubing return ret;
1823fb43630cSZhang Yubing }
1824fb43630cSZhang Yubing
1825fb43630cSZhang Yubing ret = gpio_request_by_name(dev, "hpd-gpios", 0, &dp->hpd_gpio,
1826fb43630cSZhang Yubing GPIOD_IS_IN);
1827fb43630cSZhang Yubing if (ret && ret != -ENOENT) {
1828fb43630cSZhang Yubing dev_err(dev, "failed to get hpd GPIO: %d\n", ret);
1829fb43630cSZhang Yubing return ret;
1830fb43630cSZhang Yubing }
1831fb43630cSZhang Yubing
1832fb43630cSZhang Yubing generic_phy_get_by_index(dev, 0, &dp->phy);
1833fb43630cSZhang Yubing
1834fb43630cSZhang Yubing dp->dev = dev;
1835fb43630cSZhang Yubing
1836549d42b6SWyon Bi ret = dw_dp_parse_dt(dp);
1837549d42b6SWyon Bi if (ret) {
1838549d42b6SWyon Bi dev_err(dev, "failed to parse DT\n");
1839549d42b6SWyon Bi return ret;
1840549d42b6SWyon Bi }
1841549d42b6SWyon Bi
1842fb43630cSZhang Yubing dw_dp_ddc_init(dp);
1843fb43630cSZhang Yubing
18440594ce39SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL,
18450594ce39SZhang Yubing DRM_MODE_CONNECTOR_DisplayPort);
18460594ce39SZhang Yubing
1847fb43630cSZhang Yubing return 0;
1848fb43630cSZhang Yubing }
1849fb43630cSZhang Yubing
dw_dp_bind(struct udevice * parent)18507ac3c934SZhang Yubing static int dw_dp_bind(struct udevice *parent)
18517ac3c934SZhang Yubing {
18527ac3c934SZhang Yubing struct udevice *child;
18537ac3c934SZhang Yubing ofnode subnode;
18547ac3c934SZhang Yubing const char *node_name;
18557ac3c934SZhang Yubing int ret;
18567ac3c934SZhang Yubing
18577ac3c934SZhang Yubing dev_for_each_subnode(subnode, parent) {
18587ac3c934SZhang Yubing if (!ofnode_valid(subnode)) {
18597ac3c934SZhang Yubing printf("%s: no subnode for %s\n", __func__, parent->name);
18607ac3c934SZhang Yubing return -ENXIO;
18617ac3c934SZhang Yubing }
18627ac3c934SZhang Yubing
18637ac3c934SZhang Yubing node_name = ofnode_get_name(subnode);
18647ac3c934SZhang Yubing debug("%s: subnode %s\n", __func__, node_name);
18657ac3c934SZhang Yubing
18667ac3c934SZhang Yubing if (!strcasecmp(node_name, "dp0")) {
18677ac3c934SZhang Yubing ret = device_bind_driver_to_node(parent,
18687ac3c934SZhang Yubing "dw_dp_port0",
18697ac3c934SZhang Yubing node_name, subnode, &child);
18707ac3c934SZhang Yubing if (ret) {
18717ac3c934SZhang Yubing printf("%s: '%s' cannot bind its driver\n",
18727ac3c934SZhang Yubing __func__, node_name);
18737ac3c934SZhang Yubing return ret;
18747ac3c934SZhang Yubing }
18757ac3c934SZhang Yubing }
18767ac3c934SZhang Yubing }
18777ac3c934SZhang Yubing
18787ac3c934SZhang Yubing return 0;
18797ac3c934SZhang Yubing }
18807ac3c934SZhang Yubing
dw_dp_port_probe(struct udevice * dev)18817ac3c934SZhang Yubing static int dw_dp_port_probe(struct udevice *dev)
18827ac3c934SZhang Yubing {
18837ac3c934SZhang Yubing struct dw_dp *dp = dev_get_priv(dev->parent);
18847ac3c934SZhang Yubing
18857ac3c934SZhang Yubing rockchip_connector_bind(&dp->connector, dev, dp->id, &dw_dp_connector_funcs, NULL,
18867ac3c934SZhang Yubing DRM_MODE_CONNECTOR_DisplayPort);
18877ac3c934SZhang Yubing
18887ac3c934SZhang Yubing return 0;
18897ac3c934SZhang Yubing }
18907ac3c934SZhang Yubing
18915fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3588_dp = {
18925fc83b1eSZhang Yubing .pixel_mode = DPTX_MP_QUAD_PIXEL,
18935fc83b1eSZhang Yubing };
18945fc83b1eSZhang Yubing
18955fc83b1eSZhang Yubing static const struct dw_dp_chip_data rk3576_dp = {
18965fc83b1eSZhang Yubing .pixel_mode = DPTX_MP_DUAL_PIXEL,
18975fc83b1eSZhang Yubing };
18985fc83b1eSZhang Yubing
1899fb43630cSZhang Yubing static const struct udevice_id dw_dp_ids[] = {
1900fb43630cSZhang Yubing {
19015fc83b1eSZhang Yubing .compatible = "rockchip,rk3576-dp",
19025fc83b1eSZhang Yubing .data = (ulong)&rk3576_dp,
19035fc83b1eSZhang Yubing },
19045fc83b1eSZhang Yubing {
1905fb43630cSZhang Yubing .compatible = "rockchip,rk3588-dp",
19065fc83b1eSZhang Yubing .data = (ulong)&rk3588_dp,
1907fb43630cSZhang Yubing },
1908fb43630cSZhang Yubing {}
1909fb43630cSZhang Yubing };
1910fb43630cSZhang Yubing
19117ac3c934SZhang Yubing U_BOOT_DRIVER(dw_dp_port) = {
19127ac3c934SZhang Yubing .name = "dw_dp_port0",
19137ac3c934SZhang Yubing .id = UCLASS_DISPLAY,
19147ac3c934SZhang Yubing .probe = dw_dp_port_probe,
19157ac3c934SZhang Yubing };
19167ac3c934SZhang Yubing
1917fb43630cSZhang Yubing U_BOOT_DRIVER(dw_dp) = {
1918fb43630cSZhang Yubing .name = "dw_dp",
1919fb43630cSZhang Yubing .id = UCLASS_DISPLAY,
1920fb43630cSZhang Yubing .of_match = dw_dp_ids,
1921fb43630cSZhang Yubing .probe = dw_dp_probe,
19227ac3c934SZhang Yubing .bind = dw_dp_bind,
1923fb43630cSZhang Yubing .priv_auto_alloc_size = sizeof(struct dw_dp),
1924fb43630cSZhang Yubing };
1925fb43630cSZhang Yubing
1926