blob: 806e9b20abf08678f2182d5e1a69f36a599eba9c [file] [log] [blame]
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +05301/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +05304#include <endian.h>
5#include <device/i2c_simple.h>
xuxinxiongcb3745c2021-10-26 20:16:21 +08006#include <dp_aux.h>
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +05307#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
Julius Wernere0dbeee2021-05-05 17:41:10 -0700127enum aux_cmd_status {
128 NAT_I2C_FAIL = 1 << 6,
129 AUX_SHORT = 1 << 5,
130 AUX_DFER = 1 << 4,
131 AUX_RPLY_TOUT = 1 << 3,
132 SEND_INT = 1 << 0,
133};
134
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530135enum ml_tx_mode {
136 MAIN_LINK_OFF = 0x0,
137 NORMAL_MODE = 0x1,
138 TPS1 = 0x2,
139 TPS2 = 0x3,
140 TPS3 = 0x4,
141 PRBS7 = 0x5,
142 HBR2_COMPLIANCE_EYE_PATTERN = 0x6,
143 SYMBOL_ERR_RATE_MEASUREMENT_PATTERN = 0x7,
144 CUTSOM_PATTERN = 0x8,
145 FAST_LINK_TRAINING = 0x9,
146 SEMI_AUTO_LINK_TRAINING = 0xa,
147 REDRIVER_SEMI_AUTO_LINK_TRAINING = 0xb,
148};
149
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530150/*
151 * LUT index corresponds to register value and LUT values corresponds
152 * to dp data rate supported by the bridge in Mbps unit.
153 */
154static const unsigned int sn65dsi86_bridge_dp_rate_lut[] = {
155 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
156};
157
Julius Wernere0dbeee2021-05-05 17:41:10 -0700158static cb_err_t sn65dsi86_bridge_aux_request(uint8_t bus,
159 uint8_t chip,
160 unsigned int target_reg,
161 unsigned int total_size,
162 enum aux_request request,
163 uint8_t *data)
164{
165 int i;
166 uint32_t length;
167 uint8_t buf;
168 uint8_t reg;
169
170 /* Clear old status flags just in case they're left over from a previous transfer. */
171 i2c_writeb(bus, chip, SN_AUX_CMD_STATUS_REG,
172 NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT | SEND_INT);
173
174 while (total_size) {
xuxinxiongcb3745c2021-10-26 20:16:21 +0800175 length = MIN(total_size, DP_AUX_MAX_PAYLOAD_BYTES);
Julius Wernere0dbeee2021-05-05 17:41:10 -0700176 total_size -= length;
177
xuxinxiongcb3745c2021-10-26 20:16:21 +0800178 enum i2c_over_aux cmd = dp_get_aux_cmd(request, total_size);
Julius Wernere0dbeee2021-05-05 17:41:10 -0700179 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, (cmd << 4)) ||
180 i2c_writeb(bus, chip, SN_AUX_ADDR_19_16_REG, (target_reg >> 16) & 0xF) ||
181 i2c_writeb(bus, chip, SN_AUX_ADDR_15_8_REG, (target_reg >> 8) & 0xFF) ||
182 i2c_writeb(bus, chip, SN_AUX_ADDR_7_0_REG, (target_reg) & 0xFF) ||
183 i2c_writeb(bus, chip, SN_AUX_LENGTH_REG, length))
184 return CB_ERR;
185
xuxinxiongcb3745c2021-10-26 20:16:21 +0800186 if (dp_aux_request_is_write(request)) {
Julius Wernere0dbeee2021-05-05 17:41:10 -0700187 reg = SN_AUX_WDATA_REG_0;
188 for (i = 0; i < length; i++)
189 if (i2c_writeb(bus, chip, reg++, *data++))
190 return CB_ERR;
191 }
192
193 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, AUX_CMD_SEND | (cmd << 4)))
194 return CB_ERR;
195 if (!wait_ms(100, !i2c_readb(bus, chip, SN_AUX_CMD_REG, &buf) &&
196 !(buf & AUX_CMD_SEND))) {
Julius Wernere9665952022-01-21 17:06:20 -0800197 printk(BIOS_ERR, "AUX_CMD_SEND not acknowledged\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700198 return CB_ERR;
199 }
200 if (i2c_readb(bus, chip, SN_AUX_CMD_STATUS_REG, &buf))
201 return CB_ERR;
202 if (buf & (NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT)) {
Julius Wernere9665952022-01-21 17:06:20 -0800203 printk(BIOS_ERR, "AUX command failed, status = %#x\n", buf);
Julius Wernere0dbeee2021-05-05 17:41:10 -0700204 return CB_ERR;
205 }
206
xuxinxiongcb3745c2021-10-26 20:16:21 +0800207 if (!dp_aux_request_is_write(request)) {
Julius Wernere0dbeee2021-05-05 17:41:10 -0700208 reg = SN_AUX_RDATA_REG_0;
209 for (i = 0; i < length; i++) {
210 if (i2c_readb(bus, chip, reg++, &buf))
211 return CB_ERR;
212 *data++ = buf;
213 }
214 }
215 }
216
217 return CB_SUCCESS;
218}
219
220cb_err_t sn65dsi86_bridge_read_edid(uint8_t bus, uint8_t chip, struct edid *out)
221{
222 cb_err_t err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530223 u8 edid[EDID_LENGTH * 2];
224 int edid_size = EDID_LENGTH;
225
Julius Wernere0dbeee2021-05-05 17:41:10 -0700226 uint8_t reg_addr = 0;
227 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
228 I2C_RAW_WRITE, &reg_addr);
229 if (!err)
230 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, EDID_LENGTH,
231 I2C_RAW_READ_AND_STOP, edid);
232 if (err) {
Julius Wernere9665952022-01-21 17:06:20 -0800233 printk(BIOS_ERR, "Failed to read EDID.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700234 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530235 }
236
237 if (edid[EDID_EXTENSION_FLAG]) {
238 edid_size += EDID_LENGTH;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700239 reg_addr = EDID_LENGTH;
240 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
241 I2C_RAW_WRITE, &reg_addr);
242 if (!err)
243 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR,
244 EDID_LENGTH, I2C_RAW_READ_AND_STOP, &edid[EDID_LENGTH]);
245 if (err) {
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530246 printk(BIOS_ERR, "Failed to read EDID ext block.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700247 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530248 }
249 }
250
251 if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
Julius Wernere9665952022-01-21 17:06:20 -0800252 printk(BIOS_ERR, "Failed to decode EDID.\n");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530253 return CB_ERR;
254 }
255
256 return CB_SUCCESS;
257}
258
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530259static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate_valid[])
260{
261 unsigned int rate_per_200khz;
262 uint8_t dpcd_val;
263 int i, j;
264
Julius Wernere0dbeee2021-05-05 17:41:10 -0700265 sn65dsi86_bridge_aux_request(bus, chip,
266 DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530267 if (dpcd_val >= DP_BRIDGE_14) {
268 /* eDP 1.4 devices must provide a custom table */
Julius Werner6b8305d2020-10-12 15:32:52 -0700269 uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530270
Julius Wernere0dbeee2021-05-05 17:41:10 -0700271 sn65dsi86_bridge_aux_request(bus, chip, DP_SUPPORTED_LINK_RATES,
272 sizeof(sink_rates),
273 DPCD_READ, (void *)sink_rates);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530274 for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
275 rate_per_200khz = le16_to_cpu(sink_rates[i]);
276
277 if (!rate_per_200khz)
278 break;
279
280 for (j = 0;
281 j < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
282 j++) {
283 if (sn65dsi86_bridge_dp_rate_lut[j] * (MHz / KHz) ==
284 rate_per_200khz * 200)
285 rate_valid[j] = true;
286 }
287 }
288
289 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut); i++) {
290 if (rate_valid[i])
291 return;
292 }
293
294 printk(BIOS_ERR, "No matching eDP rates in table; falling back\n");
295 }
296
297 /* On older versions best we can do is use DP_MAX_LINK_RATE */
Julius Wernere0dbeee2021-05-05 17:41:10 -0700298 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530299
300 switch (dpcd_val) {
301 default:
Julius Werner6b8305d2020-10-12 15:32:52 -0700302 printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
303 (int)dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530304 /* fall through */
305 case DP_LINK_BW_5_4:
306 rate_valid[7] = 1;
307 /* fall through */
308 case DP_LINK_BW_2_7:
309 rate_valid[4] = 1;
310 /* fall through */
311 case DP_LINK_BW_1_62:
312 rate_valid[1] = 1;
313 break;
314 }
315}
316
317static void sn65dsi86_bridge_set_dsi_clock_range(uint8_t bus, uint8_t chip,
318 struct edid *edid,
319 uint32_t num_of_lanes, uint32_t bpp)
320{
321 uint64_t pixel_clk_hz;
322 uint64_t stream_bit_rate_mhz;
323 uint64_t min_req_dsi_clk;
324
325 pixel_clk_hz = edid->mode.pixel_clock * KHz;
326 stream_bit_rate_mhz = (pixel_clk_hz * bpp) / MHz;
327
328 /* For TI the clock frequencies are half the bit rates */
329 min_req_dsi_clk = stream_bit_rate_mhz / (num_of_lanes * 2);
330
331 /* for each increment in val, frequency increases by 5MHz */
332 min_req_dsi_clk = MAX(MIN_DSI_CLK_FREQ_MHZ,
333 MIN(MAX_DSI_CLK_FREQ_MHZ, min_req_dsi_clk)) / 5;
334 i2c_writeb(bus, chip, SN_DSIA_CLK_FREQ_REG, min_req_dsi_clk);
335}
336
337static void sn65dsi86_bridge_set_dp_clock_range(uint8_t bus, uint8_t chip,
338 struct edid *edid, uint32_t num_of_lanes)
339{
340 uint64_t stream_bit_rate_khz;
341 bool rate_valid[ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut)] = { };
342 uint64_t dp_rate_mhz;
343 int dp_rate_idx, i;
344
345 stream_bit_rate_khz = edid->mode.pixel_clock * 18;
346
347 /* Calculate minimum DP data rate, taking 80% as per DP spec */
348 dp_rate_mhz = DIV_ROUND_UP(stream_bit_rate_khz * DP_CLK_FUDGE_NUM,
349 KHz * num_of_lanes * DP_CLK_FUDGE_DEN);
350
351 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut) - 1; i++)
352 if (sn65dsi86_bridge_dp_rate_lut[i] > dp_rate_mhz)
353 break;
354
355 sn65dsi86_bridge_valid_dp_rates(bus, chip, rate_valid);
356
357 /* Train until we run out of rates */
358 for (dp_rate_idx = i;
359 dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
360 dp_rate_idx++)
361 if (rate_valid[dp_rate_idx])
362 break;
363
364 if (dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut))
365 i2c_write_field(bus, chip, SN_DATARATE_CONFIG_REG, dp_rate_idx, 8, 5);
366 else
Julius Wernere9665952022-01-21 17:06:20 -0800367 printk(BIOS_ERR, "valid dp rate not found");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530368}
369
370static void sn65dsi86_bridge_set_bridge_active_timing(uint8_t bus,
371 uint8_t chip,
372 struct edid *edid)
373{
374 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
375 BRIDGE_GETLOWERBYTE(edid->mode.ha));
376 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG,
377 BRIDGE_GETHIGHERBYTE(edid->mode.ha));
378 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG,
379 BRIDGE_GETLOWERBYTE(edid->mode.va));
380 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG,
381 BRIDGE_GETHIGHERBYTE(edid->mode.va));
382 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG,
383 BRIDGE_GETLOWERBYTE(edid->mode.hspw));
384 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG,
385 BRIDGE_GETHIGHERBYTE(edid->mode.hspw));
386 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG,
387 BRIDGE_GETLOWERBYTE(edid->mode.vspw));
388 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG,
389 BRIDGE_GETHIGHERBYTE(edid->mode.vspw));
390 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_BACK_PORCH_REG,
391 edid->mode.hbl - edid->mode.hso - edid->mode.hspw);
392 i2c_writeb(bus, chip, SN_CHA_VERTICAL_BACK_PORCH_REG,
393 edid->mode.vbl - edid->mode.vso - edid->mode.vspw);
394 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_FRONT_PORCH_REG,
395 edid->mode.hso);
396 i2c_writeb(bus, chip, SN_CHA_VERTICAL_FRONT_PORCH_REG,
397 edid->mode.vso);
398}
399
400static void sn65dsi86_bridge_link_training(uint8_t bus, uint8_t chip)
401{
402 uint8_t buf;
403
404 /* enable pll lock */
405 i2c_writeb(bus, chip, SN_PLL_ENABLE_REG, 0x1);
406
407 if (!wait_ms(500,
408 !(i2c_readb(bus, chip, SN_DPPLL_SRC_REG, &buf)) &&
409 (buf & BIT(7)))) {
Julius Wernere9665952022-01-21 17:06:20 -0800410 printk(BIOS_ERR, "PLL lock failure\n");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530411 }
412
413 /*
414 * The SN65DSI86 only supports ASSR Display Authentication method and
415 * this method is enabled by default. An eDP panel must support this
416 * authentication method. We need to enable this method in the eDP panel
417 * at DisplayPort address 0x0010A prior to link training.
418 */
419 buf = 0x1;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700420 sn65dsi86_bridge_aux_request(bus, chip,
421 DP_BRIDGE_CONFIGURATION_SET, 1, DPCD_WRITE, &buf);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530422
Julius Werner411e7602020-09-30 15:23:46 -0700423 int i; /* Kernel driver suggests to retry this up to 10 times if it fails. */
424 for (i = 0; i < 10; i++) {
425 i2c_writeb(bus, chip, SN_ML_TX_MODE_REG, SEMI_AUTO_LINK_TRAINING);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530426
Julius Werner411e7602020-09-30 15:23:46 -0700427 if (!wait_ms(500, !(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
428 (buf == NORMAL_MODE || buf == MAIN_LINK_OFF))) {
Julius Wernere9665952022-01-21 17:06:20 -0800429 printk(BIOS_ERR, "unexpected link training state: %#x\n", buf);
Julius Werner411e7602020-09-30 15:23:46 -0700430 return;
431 }
432 if (buf == NORMAL_MODE)
433 return;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530434 }
435
Julius Wernere9665952022-01-21 17:06:20 -0800436 printk(BIOS_ERR, "Link training failed 10 times\n");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530437}
438
Vinod Polimera6ea80332021-03-17 16:11:12 +0530439void sn65dsi86_backlight_enable(uint8_t bus, uint8_t chip)
440{
441 uint8_t val = DP_BACKLIGHT_CONTROL_MODE_DPCD;
442 sn65dsi86_bridge_aux_request(bus, chip, DP_BACKLIGHT_MODE_SET, 1, DPCD_WRITE, &val);
443
444 val = 0xff;
445 sn65dsi86_bridge_aux_request(bus, chip, DP_BACKLIGHT_BRIGHTNESS_MSB, 1,
446 DPCD_WRITE, &val);
447
448 val = DP_BACKLIGHT_ENABLE;
449 sn65dsi86_bridge_aux_request(bus, chip, DP_DISPLAY_CONTROL_REGISTER, 1,
450 DPCD_WRITE, &val);
451}
452
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530453static void sn65dsi86_bridge_assr_config(uint8_t bus, uint8_t chip, int enable)
454{
455 if (enable)
456 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 1, 3);
457 else
458 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_DISABLE, 1, 3);
459}
460
461static int sn65dsi86_bridge_dp_lane_config(uint8_t bus, uint8_t chip)
462{
463 uint8_t lane_count;
464
Julius Wernere0dbeee2021-05-05 17:41:10 -0700465 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LANE_COUNT, 1, DPCD_READ, &lane_count);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530466 lane_count &= DP_LANE_COUNT_MASK;
467 i2c_write_field(bus, chip, SN_SSC_CONFIG_REG, MIN(lane_count, 3), 3, 4);
468
469 return lane_count;
470}
471
472void sn65dsi86_bridge_init(uint8_t bus, uint8_t chip, enum dp_pll_clk_src ref_clk)
473{
Vinod Polimerab9a7d772020-09-21 08:55:16 +0530474 /* disable HPD */
475 i2c_write_field(bus, chip, SN_HPD_DISABLE_REG, HPD_DISABLE, 1, 0);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530476
477 /* set refclk to 19.2 MHZ */
478 i2c_write_field(bus, chip, SN_DPPLL_SRC_REG, ref_clk, 7, 1);
479}
480
481void sn65dsi86_bridge_configure(uint8_t bus, uint8_t chip,
482 struct edid *edid, uint32_t num_of_lanes,
483 uint32_t dsi_bpp)
484{
485 int dp_lanes;
486
487 /* DSI Lanes config */
488 i2c_write_field(bus, chip, SN_DSI_LANES_REG, (4 - num_of_lanes), 3, 3);
489
490 /* DP Lane config */
491 dp_lanes = sn65dsi86_bridge_dp_lane_config(bus, chip);
492
493 sn65dsi86_bridge_set_dsi_clock_range(bus, chip, edid, num_of_lanes, dsi_bpp);
494
495 sn65dsi86_bridge_set_dp_clock_range(bus, chip, edid, dp_lanes);
496
497 /* Disable vstream */
498 sn65dsi86_bridge_assr_config(bus, chip, 0);
499 sn65dsi86_bridge_link_training(bus, chip);
500 sn65dsi86_bridge_set_bridge_active_timing(bus, chip, edid);
501
502 /* DP BPP config */
503 i2c_writeb(bus, chip, SN_DATA_FORMAT_REG, 0x1);
504
505 /* color bar disabled */
506 i2c_writeb(bus, chip, SN_COLOR_BAR_REG, 0x5);
507
508 /* Enable vstream */
509 sn65dsi86_bridge_assr_config(bus, chip, 1);
510}