blob: 1cbf6fd97d65e6fbc1d2a04f036f454f7b4cd21f [file] [log] [blame]
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +05301/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
4#include <delay.h>
5#include <endian.h>
6#include <device/i2c_simple.h>
7#include <edid.h>
8#include <timer.h>
9#include <types.h>
10#include <soc/addressmap.h>
11#include "sn65dsi86bridge.h"
12
Elyes HAOUAS2826cdc2021-01-16 13:57:58 +010013#define BRIDGE_GETHIGHERBYTE(x) ((uint8_t)((x & 0xff00) >> 8))
14#define BRIDGE_GETLOWERBYTE(x) ((uint8_t)(x & 0x00ff))
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +053015
16/* fudge factor required to account for 8b/10b encoding */
17#define DP_CLK_FUDGE_NUM 10
18#define DP_CLK_FUDGE_DEN 8
19
20/* DPCD */
21#define DP_BRIDGE_DPCD_REV 0x700
22#define DP_BRIDGE_11 0x00
23#define DP_BRIDGE_12 0x01
24#define DP_BRIDGE_13 0x02
25#define DP_BRIDGE_14 0x03
26#define DP_BRIDGE_CONFIGURATION_SET 0x10a
27#define DP_MAX_LINK_RATE 0x001
28#define DP_MAX_LANE_COUNT 0x002
29#define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */
30#define DP_MAX_LINK_RATE 0x001
31#define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */
32#define DP_LANE_COUNT_MASK 0xf
33
34/* link configuration */
35#define DP_LINK_BW_SET 0x100
36#define DP_LINK_BW_1_62 0x06
37#define DP_LINK_BW_2_7 0x0a
38#define DP_LINK_BW_5_4 0x14
39
40#define AUX_CMD_SEND 0x1
41#define MIN_DSI_CLK_FREQ_MHZ 40
42#define MAX_DSI_CLK_FREQ_MHZ 750
43
44enum bridge_regs {
45 SN_DPPLL_SRC_REG = 0x0A,
46 SN_PLL_ENABLE_REG = 0x0D,
47 SN_DSI_LANES_REG = 0x10,
48 SN_DSIA_CLK_FREQ_REG = 0x12,
49 SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG = 0x20,
50 SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG = 0x21,
51 SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG = 0x24,
52 SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG = 0x25,
53 SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG = 0x2C,
54 SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG = 0x2D,
55 SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG = 0x30,
56 SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG = 0x31,
57 SN_CHA_HORIZONTAL_BACK_PORCH_REG = 0x34,
58 SN_CHA_VERTICAL_BACK_PORCH_REG = 0x36,
59 SN_CHA_HORIZONTAL_FRONT_PORCH_REG = 0x38,
60 SN_CHA_VERTICAL_FRONT_PORCH_REG = 0x3A,
61 SN_COLOR_BAR_REG = 0x3C,
62 SN_ENH_FRAME_REG = 0x5A,
63 SN_DATA_FORMAT_REG = 0x5B,
64 SN_HPD_DISABLE_REG = 0x5C,
65 SN_I2C_CLAIM_ADDR_EN1 = 0x60,
66 SN_AUX_WDATA_REG_0 = 0x64,
67 SN_AUX_WDATA_REG_1 = 0x65,
68 SN_AUX_WDATA_REG_2 = 0x66,
69 SN_AUX_WDATA_REG_3 = 0x67,
70 SN_AUX_WDATA_REG_4 = 0x68,
71 SN_AUX_WDATA_REG_5 = 0x69,
72 SN_AUX_WDATA_REG_6 = 0x6A,
73 SN_AUX_WDATA_REG_7 = 0x6B,
74 SN_AUX_WDATA_REG_8 = 0x6C,
75 SN_AUX_WDATA_REG_9 = 0x6D,
76 SN_AUX_WDATA_REG_10 = 0x6E,
77 SN_AUX_WDATA_REG_11 = 0x6F,
78 SN_AUX_WDATA_REG_12 = 0x70,
79 SN_AUX_WDATA_REG_13 = 0x71,
80 SN_AUX_WDATA_REG_14 = 0x72,
81 SN_AUX_WDATA_REG_15 = 0x73,
82 SN_AUX_ADDR_19_16_REG = 0x74,
83 SN_AUX_ADDR_15_8_REG = 0x75,
84 SN_AUX_ADDR_7_0_REG = 0x76,
85 SN_AUX_LENGTH_REG = 0x77,
86 SN_AUX_CMD_REG = 0x78,
87 SN_AUX_RDATA_REG_0 = 0x79,
88 SN_AUX_RDATA_REG_1 = 0x7A,
89 SN_AUX_RDATA_REG_2 = 0x7B,
90 SN_AUX_RDATA_REG_3 = 0x7C,
91 SN_AUX_RDATA_REG_4 = 0x7D,
92 SN_AUX_RDATA_REG_5 = 0x7E,
93 SN_AUX_RDATA_REG_6 = 0x7F,
94 SN_AUX_RDATA_REG_7 = 0x80,
95 SN_AUX_RDATA_REG_8 = 0x81,
96 SN_AUX_RDATA_REG_9 = 0x82,
97 SN_AUX_RDATA_REG_10 = 0x83,
98 SN_AUX_RDATA_REG_11 = 0x84,
99 SN_AUX_RDATA_REG_12 = 0x85,
100 SN_AUX_RDATA_REG_13 = 0x86,
101 SN_AUX_RDATA_REG_14 = 0x87,
102 SN_AUX_RDATA_REG_15 = 0x88,
103 SN_SSC_CONFIG_REG = 0x93,
104 SN_DATARATE_CONFIG_REG = 0x94,
105 SN_ML_TX_MODE_REG = 0x96,
106 SN_AUX_CMD_STATUS_REG = 0xF4,
107};
108
109enum {
110 HPD_ENABLE = 0x0,
111 HPD_DISABLE = 0x1,
112};
113
114enum {
115 SOT_ERR_TOL_DSI = 0x0,
116 CHB_DSI_LANES = 0x1,
117 CHA_DSI_LANES = 0x2,
118 DSI_CHANNEL_MODE = 0x3,
119 LEFT_RIGHT_PIXELS = 0x4,
120};
121
122enum vstream_config {
123 VSTREAM_DISABLE = 0,
124 VSTREAM_ENABLE = 1,
125};
126
127enum i2c_over_aux {
128 I2C_OVER_AUX_WRITE_MOT_0 = 0x0,
129 I2C_OVER_AUX_READ_MOT_0 = 0x1,
Julius Wernere0dbeee2021-05-05 17:41:10 -0700130 I2C_OVER_AUX_WRITE_STATUS_UPDATE_0 = 0x2,
131 I2C_OVER_AUX_WRITE_MOT_1 = 0x4,
132 I2C_OVER_AUX_READ_MOT_1 = 0x5,
133 I2C_OVER_AUX_WRITE_STATUS_UPDATE_1 = 0x6,
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530134 NATIVE_AUX_WRITE = 0x8,
135 NATIVE_AUX_READ = 0x9,
136};
137
Julius Wernere0dbeee2021-05-05 17:41:10 -0700138enum aux_cmd_status {
139 NAT_I2C_FAIL = 1 << 6,
140 AUX_SHORT = 1 << 5,
141 AUX_DFER = 1 << 4,
142 AUX_RPLY_TOUT = 1 << 3,
143 SEND_INT = 1 << 0,
144};
145
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530146enum ml_tx_mode {
147 MAIN_LINK_OFF = 0x0,
148 NORMAL_MODE = 0x1,
149 TPS1 = 0x2,
150 TPS2 = 0x3,
151 TPS3 = 0x4,
152 PRBS7 = 0x5,
153 HBR2_COMPLIANCE_EYE_PATTERN = 0x6,
154 SYMBOL_ERR_RATE_MEASUREMENT_PATTERN = 0x7,
155 CUTSOM_PATTERN = 0x8,
156 FAST_LINK_TRAINING = 0x9,
157 SEMI_AUTO_LINK_TRAINING = 0xa,
158 REDRIVER_SEMI_AUTO_LINK_TRAINING = 0xb,
159};
160
Julius Wernere0dbeee2021-05-05 17:41:10 -0700161enum aux_request {
162 DPCD_READ,
163 DPCD_WRITE,
164 I2C_RAW_READ,
165 I2C_RAW_WRITE,
166 I2C_RAW_READ_AND_STOP,
167 I2C_RAW_WRITE_AND_STOP,
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530168};
169
170enum {
171 EDID_LENGTH = 128,
172 EDID_I2C_ADDR = 0x50,
173 EDID_EXTENSION_FLAG = 0x7e,
174};
175
176/*
177 * LUT index corresponds to register value and LUT values corresponds
178 * to dp data rate supported by the bridge in Mbps unit.
179 */
180static const unsigned int sn65dsi86_bridge_dp_rate_lut[] = {
181 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
182};
183
Julius Wernere0dbeee2021-05-05 17:41:10 -0700184static bool request_is_write(enum aux_request request)
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530185{
Julius Wernere0dbeee2021-05-05 17:41:10 -0700186 switch (request) {
187 case I2C_RAW_WRITE_AND_STOP:
188 case I2C_RAW_WRITE:
189 case DPCD_WRITE:
190 return true;
191 default:
192 return false;
193 }
194}
195
196static enum i2c_over_aux get_aux_cmd(enum aux_request request, uint32_t remaining_after_this)
197{
198 switch (request) {
199 case I2C_RAW_WRITE_AND_STOP:
200 if (!remaining_after_this)
201 return I2C_OVER_AUX_WRITE_MOT_0;
202 /* fallthrough */
203 case I2C_RAW_WRITE:
204 return I2C_OVER_AUX_WRITE_MOT_1;
205 case I2C_RAW_READ_AND_STOP:
206 if (!remaining_after_this)
207 return I2C_OVER_AUX_READ_MOT_0;
208 /* fallthrough */
209 case I2C_RAW_READ:
210 return I2C_OVER_AUX_READ_MOT_1;
211 case DPCD_WRITE:
212 return NATIVE_AUX_WRITE;
213 case DPCD_READ:
214 default:
215 return NATIVE_AUX_READ;
216 }
217}
218
219static cb_err_t sn65dsi86_bridge_aux_request(uint8_t bus,
220 uint8_t chip,
221 unsigned int target_reg,
222 unsigned int total_size,
223 enum aux_request request,
224 uint8_t *data)
225{
226 int i;
227 uint32_t length;
228 uint8_t buf;
229 uint8_t reg;
230
231 /* Clear old status flags just in case they're left over from a previous transfer. */
232 i2c_writeb(bus, chip, SN_AUX_CMD_STATUS_REG,
233 NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT | SEND_INT);
234
235 while (total_size) {
236 length = MIN(total_size, 16);
237 total_size -= length;
238
239 enum i2c_over_aux cmd = get_aux_cmd(request, total_size);
240 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, (cmd << 4)) ||
241 i2c_writeb(bus, chip, SN_AUX_ADDR_19_16_REG, (target_reg >> 16) & 0xF) ||
242 i2c_writeb(bus, chip, SN_AUX_ADDR_15_8_REG, (target_reg >> 8) & 0xFF) ||
243 i2c_writeb(bus, chip, SN_AUX_ADDR_7_0_REG, (target_reg) & 0xFF) ||
244 i2c_writeb(bus, chip, SN_AUX_LENGTH_REG, length))
245 return CB_ERR;
246
247 if (request_is_write(request)) {
248 reg = SN_AUX_WDATA_REG_0;
249 for (i = 0; i < length; i++)
250 if (i2c_writeb(bus, chip, reg++, *data++))
251 return CB_ERR;
252 }
253
254 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, AUX_CMD_SEND | (cmd << 4)))
255 return CB_ERR;
256 if (!wait_ms(100, !i2c_readb(bus, chip, SN_AUX_CMD_REG, &buf) &&
257 !(buf & AUX_CMD_SEND))) {
258 printk(BIOS_ERR, "ERROR: AUX_CMD_SEND not acknowledged\n");
259 return CB_ERR;
260 }
261 if (i2c_readb(bus, chip, SN_AUX_CMD_STATUS_REG, &buf))
262 return CB_ERR;
263 if (buf & (NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT)) {
264 printk(BIOS_ERR, "ERROR: AUX command failed, status = %#x\n", buf);
265 return CB_ERR;
266 }
267
268 if (!request_is_write(request)) {
269 reg = SN_AUX_RDATA_REG_0;
270 for (i = 0; i < length; i++) {
271 if (i2c_readb(bus, chip, reg++, &buf))
272 return CB_ERR;
273 *data++ = buf;
274 }
275 }
276 }
277
278 return CB_SUCCESS;
279}
280
281cb_err_t sn65dsi86_bridge_read_edid(uint8_t bus, uint8_t chip, struct edid *out)
282{
283 cb_err_t err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530284 u8 edid[EDID_LENGTH * 2];
285 int edid_size = EDID_LENGTH;
286
Julius Wernere0dbeee2021-05-05 17:41:10 -0700287 uint8_t reg_addr = 0;
288 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
289 I2C_RAW_WRITE, &reg_addr);
290 if (!err)
291 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, EDID_LENGTH,
292 I2C_RAW_READ_AND_STOP, edid);
293 if (err) {
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530294 printk(BIOS_ERR, "ERROR: Failed to read EDID.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700295 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530296 }
297
298 if (edid[EDID_EXTENSION_FLAG]) {
299 edid_size += EDID_LENGTH;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700300 reg_addr = EDID_LENGTH;
301 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
302 I2C_RAW_WRITE, &reg_addr);
303 if (!err)
304 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR,
305 EDID_LENGTH, I2C_RAW_READ_AND_STOP, &edid[EDID_LENGTH]);
306 if (err) {
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530307 printk(BIOS_ERR, "Failed to read EDID ext block.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700308 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530309 }
310 }
311
312 if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
313 printk(BIOS_ERR, "ERROR: Failed to decode EDID.\n");
314 return CB_ERR;
315 }
316
317 return CB_SUCCESS;
318}
319
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530320static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate_valid[])
321{
322 unsigned int rate_per_200khz;
323 uint8_t dpcd_val;
324 int i, j;
325
Julius Wernere0dbeee2021-05-05 17:41:10 -0700326 sn65dsi86_bridge_aux_request(bus, chip,
327 DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530328 if (dpcd_val >= DP_BRIDGE_14) {
329 /* eDP 1.4 devices must provide a custom table */
Julius Werner6b8305d2020-10-12 15:32:52 -0700330 uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530331
Julius Wernere0dbeee2021-05-05 17:41:10 -0700332 sn65dsi86_bridge_aux_request(bus, chip, DP_SUPPORTED_LINK_RATES,
333 sizeof(sink_rates),
334 DPCD_READ, (void *)sink_rates);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530335 for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
336 rate_per_200khz = le16_to_cpu(sink_rates[i]);
337
338 if (!rate_per_200khz)
339 break;
340
341 for (j = 0;
342 j < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
343 j++) {
344 if (sn65dsi86_bridge_dp_rate_lut[j] * (MHz / KHz) ==
345 rate_per_200khz * 200)
346 rate_valid[j] = true;
347 }
348 }
349
350 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut); i++) {
351 if (rate_valid[i])
352 return;
353 }
354
355 printk(BIOS_ERR, "No matching eDP rates in table; falling back\n");
356 }
357
358 /* On older versions best we can do is use DP_MAX_LINK_RATE */
Julius Wernere0dbeee2021-05-05 17:41:10 -0700359 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530360
361 switch (dpcd_val) {
362 default:
Julius Werner6b8305d2020-10-12 15:32:52 -0700363 printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
364 (int)dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530365 /* fall through */
366 case DP_LINK_BW_5_4:
367 rate_valid[7] = 1;
368 /* fall through */
369 case DP_LINK_BW_2_7:
370 rate_valid[4] = 1;
371 /* fall through */
372 case DP_LINK_BW_1_62:
373 rate_valid[1] = 1;
374 break;
375 }
376}
377
378static void sn65dsi86_bridge_set_dsi_clock_range(uint8_t bus, uint8_t chip,
379 struct edid *edid,
380 uint32_t num_of_lanes, uint32_t bpp)
381{
382 uint64_t pixel_clk_hz;
383 uint64_t stream_bit_rate_mhz;
384 uint64_t min_req_dsi_clk;
385
386 pixel_clk_hz = edid->mode.pixel_clock * KHz;
387 stream_bit_rate_mhz = (pixel_clk_hz * bpp) / MHz;
388
389 /* For TI the clock frequencies are half the bit rates */
390 min_req_dsi_clk = stream_bit_rate_mhz / (num_of_lanes * 2);
391
392 /* for each increment in val, frequency increases by 5MHz */
393 min_req_dsi_clk = MAX(MIN_DSI_CLK_FREQ_MHZ,
394 MIN(MAX_DSI_CLK_FREQ_MHZ, min_req_dsi_clk)) / 5;
395 i2c_writeb(bus, chip, SN_DSIA_CLK_FREQ_REG, min_req_dsi_clk);
396}
397
398static void sn65dsi86_bridge_set_dp_clock_range(uint8_t bus, uint8_t chip,
399 struct edid *edid, uint32_t num_of_lanes)
400{
401 uint64_t stream_bit_rate_khz;
402 bool rate_valid[ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut)] = { };
403 uint64_t dp_rate_mhz;
404 int dp_rate_idx, i;
405
406 stream_bit_rate_khz = edid->mode.pixel_clock * 18;
407
408 /* Calculate minimum DP data rate, taking 80% as per DP spec */
409 dp_rate_mhz = DIV_ROUND_UP(stream_bit_rate_khz * DP_CLK_FUDGE_NUM,
410 KHz * num_of_lanes * DP_CLK_FUDGE_DEN);
411
412 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut) - 1; i++)
413 if (sn65dsi86_bridge_dp_rate_lut[i] > dp_rate_mhz)
414 break;
415
416 sn65dsi86_bridge_valid_dp_rates(bus, chip, rate_valid);
417
418 /* Train until we run out of rates */
419 for (dp_rate_idx = i;
420 dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
421 dp_rate_idx++)
422 if (rate_valid[dp_rate_idx])
423 break;
424
425 if (dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut))
426 i2c_write_field(bus, chip, SN_DATARATE_CONFIG_REG, dp_rate_idx, 8, 5);
427 else
428 printk(BIOS_ERR, "ERROR: valid dp rate not found");
429}
430
431static void sn65dsi86_bridge_set_bridge_active_timing(uint8_t bus,
432 uint8_t chip,
433 struct edid *edid)
434{
435 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
436 BRIDGE_GETLOWERBYTE(edid->mode.ha));
437 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG,
438 BRIDGE_GETHIGHERBYTE(edid->mode.ha));
439 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG,
440 BRIDGE_GETLOWERBYTE(edid->mode.va));
441 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG,
442 BRIDGE_GETHIGHERBYTE(edid->mode.va));
443 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG,
444 BRIDGE_GETLOWERBYTE(edid->mode.hspw));
445 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG,
446 BRIDGE_GETHIGHERBYTE(edid->mode.hspw));
447 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG,
448 BRIDGE_GETLOWERBYTE(edid->mode.vspw));
449 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG,
450 BRIDGE_GETHIGHERBYTE(edid->mode.vspw));
451 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_BACK_PORCH_REG,
452 edid->mode.hbl - edid->mode.hso - edid->mode.hspw);
453 i2c_writeb(bus, chip, SN_CHA_VERTICAL_BACK_PORCH_REG,
454 edid->mode.vbl - edid->mode.vso - edid->mode.vspw);
455 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_FRONT_PORCH_REG,
456 edid->mode.hso);
457 i2c_writeb(bus, chip, SN_CHA_VERTICAL_FRONT_PORCH_REG,
458 edid->mode.vso);
459}
460
461static void sn65dsi86_bridge_link_training(uint8_t bus, uint8_t chip)
462{
463 uint8_t buf;
464
465 /* enable pll lock */
466 i2c_writeb(bus, chip, SN_PLL_ENABLE_REG, 0x1);
467
468 if (!wait_ms(500,
469 !(i2c_readb(bus, chip, SN_DPPLL_SRC_REG, &buf)) &&
470 (buf & BIT(7)))) {
471 printk(BIOS_ERR, "ERROR: PLL lock failure\n");
472 }
473
474 /*
475 * The SN65DSI86 only supports ASSR Display Authentication method and
476 * this method is enabled by default. An eDP panel must support this
477 * authentication method. We need to enable this method in the eDP panel
478 * at DisplayPort address 0x0010A prior to link training.
479 */
480 buf = 0x1;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700481 sn65dsi86_bridge_aux_request(bus, chip,
482 DP_BRIDGE_CONFIGURATION_SET, 1, DPCD_WRITE, &buf);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530483
Julius Werner411e7602020-09-30 15:23:46 -0700484 int i; /* Kernel driver suggests to retry this up to 10 times if it fails. */
485 for (i = 0; i < 10; i++) {
486 i2c_writeb(bus, chip, SN_ML_TX_MODE_REG, SEMI_AUTO_LINK_TRAINING);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530487
Julius Werner411e7602020-09-30 15:23:46 -0700488 if (!wait_ms(500, !(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
489 (buf == NORMAL_MODE || buf == MAIN_LINK_OFF))) {
490 printk(BIOS_ERR, "ERROR: unexpected link training state: %#x\n", buf);
491 return;
492 }
493 if (buf == NORMAL_MODE)
494 return;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530495 }
496
Julius Werner411e7602020-09-30 15:23:46 -0700497 printk(BIOS_ERR, "ERROR: Link training failed 10 times\n");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530498}
499
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530500static void sn65dsi86_bridge_assr_config(uint8_t bus, uint8_t chip, int enable)
501{
502 if (enable)
503 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 1, 3);
504 else
505 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_DISABLE, 1, 3);
506}
507
508static int sn65dsi86_bridge_dp_lane_config(uint8_t bus, uint8_t chip)
509{
510 uint8_t lane_count;
511
Julius Wernere0dbeee2021-05-05 17:41:10 -0700512 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LANE_COUNT, 1, DPCD_READ, &lane_count);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530513 lane_count &= DP_LANE_COUNT_MASK;
514 i2c_write_field(bus, chip, SN_SSC_CONFIG_REG, MIN(lane_count, 3), 3, 4);
515
516 return lane_count;
517}
518
519void sn65dsi86_bridge_init(uint8_t bus, uint8_t chip, enum dp_pll_clk_src ref_clk)
520{
Vinod Polimerab9a7d772020-09-21 08:55:16 +0530521 /* disable HPD */
522 i2c_write_field(bus, chip, SN_HPD_DISABLE_REG, HPD_DISABLE, 1, 0);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530523
524 /* set refclk to 19.2 MHZ */
525 i2c_write_field(bus, chip, SN_DPPLL_SRC_REG, ref_clk, 7, 1);
526}
527
528void sn65dsi86_bridge_configure(uint8_t bus, uint8_t chip,
529 struct edid *edid, uint32_t num_of_lanes,
530 uint32_t dsi_bpp)
531{
532 int dp_lanes;
533
534 /* DSI Lanes config */
535 i2c_write_field(bus, chip, SN_DSI_LANES_REG, (4 - num_of_lanes), 3, 3);
536
537 /* DP Lane config */
538 dp_lanes = sn65dsi86_bridge_dp_lane_config(bus, chip);
539
540 sn65dsi86_bridge_set_dsi_clock_range(bus, chip, edid, num_of_lanes, dsi_bpp);
541
542 sn65dsi86_bridge_set_dp_clock_range(bus, chip, edid, dp_lanes);
543
544 /* Disable vstream */
545 sn65dsi86_bridge_assr_config(bus, chip, 0);
546 sn65dsi86_bridge_link_training(bus, chip);
547 sn65dsi86_bridge_set_bridge_active_timing(bus, chip, edid);
548
549 /* DP BPP config */
550 i2c_writeb(bus, chip, SN_DATA_FORMAT_REG, 0x1);
551
552 /* color bar disabled */
553 i2c_writeb(bus, chip, SN_COLOR_BAR_REG, 0x5);
554
555 /* Enable vstream */
556 sn65dsi86_bridge_assr_config(bus, chip, 1);
557}