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