blob: c4c40880237e9efd3b9e601469f6560825ef7bf1 [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>
xuxinxiongcb3745c2021-10-26 20:16:21 +08007#include <dp_aux.h>
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +05308#include <edid.h>
9#include <timer.h>
10#include <types.h>
11#include <soc/addressmap.h>
12#include "sn65dsi86bridge.h"
13
Elyes HAOUAS2826cdc2021-01-16 13:57:58 +010014#define BRIDGE_GETHIGHERBYTE(x) ((uint8_t)((x & 0xff00) >> 8))
15#define BRIDGE_GETLOWERBYTE(x) ((uint8_t)(x & 0x00ff))
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +053016
17/* fudge factor required to account for 8b/10b encoding */
18#define DP_CLK_FUDGE_NUM 10
19#define DP_CLK_FUDGE_DEN 8
20
21/* DPCD */
22#define DP_BRIDGE_DPCD_REV 0x700
23#define DP_BRIDGE_11 0x00
24#define DP_BRIDGE_12 0x01
25#define DP_BRIDGE_13 0x02
26#define DP_BRIDGE_14 0x03
27#define DP_BRIDGE_CONFIGURATION_SET 0x10a
28#define DP_MAX_LINK_RATE 0x001
29#define DP_MAX_LANE_COUNT 0x002
30#define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */
31#define DP_MAX_LINK_RATE 0x001
32#define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */
33#define DP_LANE_COUNT_MASK 0xf
34
35/* link configuration */
36#define DP_LINK_BW_SET 0x100
37#define DP_LINK_BW_1_62 0x06
38#define DP_LINK_BW_2_7 0x0a
39#define DP_LINK_BW_5_4 0x14
40
41#define AUX_CMD_SEND 0x1
42#define MIN_DSI_CLK_FREQ_MHZ 40
43#define MAX_DSI_CLK_FREQ_MHZ 750
44
45enum bridge_regs {
46 SN_DPPLL_SRC_REG = 0x0A,
47 SN_PLL_ENABLE_REG = 0x0D,
48 SN_DSI_LANES_REG = 0x10,
49 SN_DSIA_CLK_FREQ_REG = 0x12,
50 SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG = 0x20,
51 SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG = 0x21,
52 SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG = 0x24,
53 SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG = 0x25,
54 SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG = 0x2C,
55 SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG = 0x2D,
56 SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG = 0x30,
57 SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG = 0x31,
58 SN_CHA_HORIZONTAL_BACK_PORCH_REG = 0x34,
59 SN_CHA_VERTICAL_BACK_PORCH_REG = 0x36,
60 SN_CHA_HORIZONTAL_FRONT_PORCH_REG = 0x38,
61 SN_CHA_VERTICAL_FRONT_PORCH_REG = 0x3A,
62 SN_COLOR_BAR_REG = 0x3C,
63 SN_ENH_FRAME_REG = 0x5A,
64 SN_DATA_FORMAT_REG = 0x5B,
65 SN_HPD_DISABLE_REG = 0x5C,
66 SN_I2C_CLAIM_ADDR_EN1 = 0x60,
67 SN_AUX_WDATA_REG_0 = 0x64,
68 SN_AUX_WDATA_REG_1 = 0x65,
69 SN_AUX_WDATA_REG_2 = 0x66,
70 SN_AUX_WDATA_REG_3 = 0x67,
71 SN_AUX_WDATA_REG_4 = 0x68,
72 SN_AUX_WDATA_REG_5 = 0x69,
73 SN_AUX_WDATA_REG_6 = 0x6A,
74 SN_AUX_WDATA_REG_7 = 0x6B,
75 SN_AUX_WDATA_REG_8 = 0x6C,
76 SN_AUX_WDATA_REG_9 = 0x6D,
77 SN_AUX_WDATA_REG_10 = 0x6E,
78 SN_AUX_WDATA_REG_11 = 0x6F,
79 SN_AUX_WDATA_REG_12 = 0x70,
80 SN_AUX_WDATA_REG_13 = 0x71,
81 SN_AUX_WDATA_REG_14 = 0x72,
82 SN_AUX_WDATA_REG_15 = 0x73,
83 SN_AUX_ADDR_19_16_REG = 0x74,
84 SN_AUX_ADDR_15_8_REG = 0x75,
85 SN_AUX_ADDR_7_0_REG = 0x76,
86 SN_AUX_LENGTH_REG = 0x77,
87 SN_AUX_CMD_REG = 0x78,
88 SN_AUX_RDATA_REG_0 = 0x79,
89 SN_AUX_RDATA_REG_1 = 0x7A,
90 SN_AUX_RDATA_REG_2 = 0x7B,
91 SN_AUX_RDATA_REG_3 = 0x7C,
92 SN_AUX_RDATA_REG_4 = 0x7D,
93 SN_AUX_RDATA_REG_5 = 0x7E,
94 SN_AUX_RDATA_REG_6 = 0x7F,
95 SN_AUX_RDATA_REG_7 = 0x80,
96 SN_AUX_RDATA_REG_8 = 0x81,
97 SN_AUX_RDATA_REG_9 = 0x82,
98 SN_AUX_RDATA_REG_10 = 0x83,
99 SN_AUX_RDATA_REG_11 = 0x84,
100 SN_AUX_RDATA_REG_12 = 0x85,
101 SN_AUX_RDATA_REG_13 = 0x86,
102 SN_AUX_RDATA_REG_14 = 0x87,
103 SN_AUX_RDATA_REG_15 = 0x88,
104 SN_SSC_CONFIG_REG = 0x93,
105 SN_DATARATE_CONFIG_REG = 0x94,
106 SN_ML_TX_MODE_REG = 0x96,
107 SN_AUX_CMD_STATUS_REG = 0xF4,
108};
109
110enum {
111 HPD_ENABLE = 0x0,
112 HPD_DISABLE = 0x1,
113};
114
115enum {
116 SOT_ERR_TOL_DSI = 0x0,
117 CHB_DSI_LANES = 0x1,
118 CHA_DSI_LANES = 0x2,
119 DSI_CHANNEL_MODE = 0x3,
120 LEFT_RIGHT_PIXELS = 0x4,
121};
122
123enum vstream_config {
124 VSTREAM_DISABLE = 0,
125 VSTREAM_ENABLE = 1,
126};
127
Julius Wernere0dbeee2021-05-05 17:41:10 -0700128enum aux_cmd_status {
129 NAT_I2C_FAIL = 1 << 6,
130 AUX_SHORT = 1 << 5,
131 AUX_DFER = 1 << 4,
132 AUX_RPLY_TOUT = 1 << 3,
133 SEND_INT = 1 << 0,
134};
135
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530136enum ml_tx_mode {
137 MAIN_LINK_OFF = 0x0,
138 NORMAL_MODE = 0x1,
139 TPS1 = 0x2,
140 TPS2 = 0x3,
141 TPS3 = 0x4,
142 PRBS7 = 0x5,
143 HBR2_COMPLIANCE_EYE_PATTERN = 0x6,
144 SYMBOL_ERR_RATE_MEASUREMENT_PATTERN = 0x7,
145 CUTSOM_PATTERN = 0x8,
146 FAST_LINK_TRAINING = 0x9,
147 SEMI_AUTO_LINK_TRAINING = 0xa,
148 REDRIVER_SEMI_AUTO_LINK_TRAINING = 0xb,
149};
150
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530151/*
152 * LUT index corresponds to register value and LUT values corresponds
153 * to dp data rate supported by the bridge in Mbps unit.
154 */
155static const unsigned int sn65dsi86_bridge_dp_rate_lut[] = {
156 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
157};
158
Julius Wernere0dbeee2021-05-05 17:41:10 -0700159static cb_err_t sn65dsi86_bridge_aux_request(uint8_t bus,
160 uint8_t chip,
161 unsigned int target_reg,
162 unsigned int total_size,
163 enum aux_request request,
164 uint8_t *data)
165{
166 int i;
167 uint32_t length;
168 uint8_t buf;
169 uint8_t reg;
170
171 /* Clear old status flags just in case they're left over from a previous transfer. */
172 i2c_writeb(bus, chip, SN_AUX_CMD_STATUS_REG,
173 NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT | SEND_INT);
174
175 while (total_size) {
xuxinxiongcb3745c2021-10-26 20:16:21 +0800176 length = MIN(total_size, DP_AUX_MAX_PAYLOAD_BYTES);
Julius Wernere0dbeee2021-05-05 17:41:10 -0700177 total_size -= length;
178
xuxinxiongcb3745c2021-10-26 20:16:21 +0800179 enum i2c_over_aux cmd = dp_get_aux_cmd(request, total_size);
Julius Wernere0dbeee2021-05-05 17:41:10 -0700180 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, (cmd << 4)) ||
181 i2c_writeb(bus, chip, SN_AUX_ADDR_19_16_REG, (target_reg >> 16) & 0xF) ||
182 i2c_writeb(bus, chip, SN_AUX_ADDR_15_8_REG, (target_reg >> 8) & 0xFF) ||
183 i2c_writeb(bus, chip, SN_AUX_ADDR_7_0_REG, (target_reg) & 0xFF) ||
184 i2c_writeb(bus, chip, SN_AUX_LENGTH_REG, length))
185 return CB_ERR;
186
xuxinxiongcb3745c2021-10-26 20:16:21 +0800187 if (dp_aux_request_is_write(request)) {
Julius Wernere0dbeee2021-05-05 17:41:10 -0700188 reg = SN_AUX_WDATA_REG_0;
189 for (i = 0; i < length; i++)
190 if (i2c_writeb(bus, chip, reg++, *data++))
191 return CB_ERR;
192 }
193
194 if (i2c_writeb(bus, chip, SN_AUX_CMD_REG, AUX_CMD_SEND | (cmd << 4)))
195 return CB_ERR;
196 if (!wait_ms(100, !i2c_readb(bus, chip, SN_AUX_CMD_REG, &buf) &&
197 !(buf & AUX_CMD_SEND))) {
198 printk(BIOS_ERR, "ERROR: AUX_CMD_SEND not acknowledged\n");
199 return CB_ERR;
200 }
201 if (i2c_readb(bus, chip, SN_AUX_CMD_STATUS_REG, &buf))
202 return CB_ERR;
203 if (buf & (NAT_I2C_FAIL | AUX_SHORT | AUX_DFER | AUX_RPLY_TOUT)) {
204 printk(BIOS_ERR, "ERROR: AUX command failed, status = %#x\n", buf);
205 return CB_ERR;
206 }
207
xuxinxiongcb3745c2021-10-26 20:16:21 +0800208 if (!dp_aux_request_is_write(request)) {
Julius Wernere0dbeee2021-05-05 17:41:10 -0700209 reg = SN_AUX_RDATA_REG_0;
210 for (i = 0; i < length; i++) {
211 if (i2c_readb(bus, chip, reg++, &buf))
212 return CB_ERR;
213 *data++ = buf;
214 }
215 }
216 }
217
218 return CB_SUCCESS;
219}
220
221cb_err_t sn65dsi86_bridge_read_edid(uint8_t bus, uint8_t chip, struct edid *out)
222{
223 cb_err_t err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530224 u8 edid[EDID_LENGTH * 2];
225 int edid_size = EDID_LENGTH;
226
Julius Wernere0dbeee2021-05-05 17:41:10 -0700227 uint8_t reg_addr = 0;
228 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
229 I2C_RAW_WRITE, &reg_addr);
230 if (!err)
231 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, EDID_LENGTH,
232 I2C_RAW_READ_AND_STOP, edid);
233 if (err) {
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530234 printk(BIOS_ERR, "ERROR: Failed to read EDID.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700235 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530236 }
237
238 if (edid[EDID_EXTENSION_FLAG]) {
239 edid_size += EDID_LENGTH;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700240 reg_addr = EDID_LENGTH;
241 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR, 1,
242 I2C_RAW_WRITE, &reg_addr);
243 if (!err)
244 err = sn65dsi86_bridge_aux_request(bus, chip, EDID_I2C_ADDR,
245 EDID_LENGTH, I2C_RAW_READ_AND_STOP, &edid[EDID_LENGTH]);
246 if (err) {
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530247 printk(BIOS_ERR, "Failed to read EDID ext block.\n");
Julius Wernere0dbeee2021-05-05 17:41:10 -0700248 return err;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530249 }
250 }
251
252 if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
253 printk(BIOS_ERR, "ERROR: Failed to decode EDID.\n");
254 return CB_ERR;
255 }
256
257 return CB_SUCCESS;
258}
259
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530260static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate_valid[])
261{
262 unsigned int rate_per_200khz;
263 uint8_t dpcd_val;
264 int i, j;
265
Julius Wernere0dbeee2021-05-05 17:41:10 -0700266 sn65dsi86_bridge_aux_request(bus, chip,
267 DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530268 if (dpcd_val >= DP_BRIDGE_14) {
269 /* eDP 1.4 devices must provide a custom table */
Julius Werner6b8305d2020-10-12 15:32:52 -0700270 uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530271
Julius Wernere0dbeee2021-05-05 17:41:10 -0700272 sn65dsi86_bridge_aux_request(bus, chip, DP_SUPPORTED_LINK_RATES,
273 sizeof(sink_rates),
274 DPCD_READ, (void *)sink_rates);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530275 for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
276 rate_per_200khz = le16_to_cpu(sink_rates[i]);
277
278 if (!rate_per_200khz)
279 break;
280
281 for (j = 0;
282 j < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
283 j++) {
284 if (sn65dsi86_bridge_dp_rate_lut[j] * (MHz / KHz) ==
285 rate_per_200khz * 200)
286 rate_valid[j] = true;
287 }
288 }
289
290 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut); i++) {
291 if (rate_valid[i])
292 return;
293 }
294
295 printk(BIOS_ERR, "No matching eDP rates in table; falling back\n");
296 }
297
298 /* On older versions best we can do is use DP_MAX_LINK_RATE */
Julius Wernere0dbeee2021-05-05 17:41:10 -0700299 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530300
301 switch (dpcd_val) {
302 default:
Julius Werner6b8305d2020-10-12 15:32:52 -0700303 printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
304 (int)dpcd_val);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530305 /* fall through */
306 case DP_LINK_BW_5_4:
307 rate_valid[7] = 1;
308 /* fall through */
309 case DP_LINK_BW_2_7:
310 rate_valid[4] = 1;
311 /* fall through */
312 case DP_LINK_BW_1_62:
313 rate_valid[1] = 1;
314 break;
315 }
316}
317
318static void sn65dsi86_bridge_set_dsi_clock_range(uint8_t bus, uint8_t chip,
319 struct edid *edid,
320 uint32_t num_of_lanes, uint32_t bpp)
321{
322 uint64_t pixel_clk_hz;
323 uint64_t stream_bit_rate_mhz;
324 uint64_t min_req_dsi_clk;
325
326 pixel_clk_hz = edid->mode.pixel_clock * KHz;
327 stream_bit_rate_mhz = (pixel_clk_hz * bpp) / MHz;
328
329 /* For TI the clock frequencies are half the bit rates */
330 min_req_dsi_clk = stream_bit_rate_mhz / (num_of_lanes * 2);
331
332 /* for each increment in val, frequency increases by 5MHz */
333 min_req_dsi_clk = MAX(MIN_DSI_CLK_FREQ_MHZ,
334 MIN(MAX_DSI_CLK_FREQ_MHZ, min_req_dsi_clk)) / 5;
335 i2c_writeb(bus, chip, SN_DSIA_CLK_FREQ_REG, min_req_dsi_clk);
336}
337
338static void sn65dsi86_bridge_set_dp_clock_range(uint8_t bus, uint8_t chip,
339 struct edid *edid, uint32_t num_of_lanes)
340{
341 uint64_t stream_bit_rate_khz;
342 bool rate_valid[ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut)] = { };
343 uint64_t dp_rate_mhz;
344 int dp_rate_idx, i;
345
346 stream_bit_rate_khz = edid->mode.pixel_clock * 18;
347
348 /* Calculate minimum DP data rate, taking 80% as per DP spec */
349 dp_rate_mhz = DIV_ROUND_UP(stream_bit_rate_khz * DP_CLK_FUDGE_NUM,
350 KHz * num_of_lanes * DP_CLK_FUDGE_DEN);
351
352 for (i = 0; i < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut) - 1; i++)
353 if (sn65dsi86_bridge_dp_rate_lut[i] > dp_rate_mhz)
354 break;
355
356 sn65dsi86_bridge_valid_dp_rates(bus, chip, rate_valid);
357
358 /* Train until we run out of rates */
359 for (dp_rate_idx = i;
360 dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut);
361 dp_rate_idx++)
362 if (rate_valid[dp_rate_idx])
363 break;
364
365 if (dp_rate_idx < ARRAY_SIZE(sn65dsi86_bridge_dp_rate_lut))
366 i2c_write_field(bus, chip, SN_DATARATE_CONFIG_REG, dp_rate_idx, 8, 5);
367 else
368 printk(BIOS_ERR, "ERROR: valid dp rate not found");
369}
370
371static void sn65dsi86_bridge_set_bridge_active_timing(uint8_t bus,
372 uint8_t chip,
373 struct edid *edid)
374{
375 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG,
376 BRIDGE_GETLOWERBYTE(edid->mode.ha));
377 i2c_writeb(bus, chip, SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG,
378 BRIDGE_GETHIGHERBYTE(edid->mode.ha));
379 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG,
380 BRIDGE_GETLOWERBYTE(edid->mode.va));
381 i2c_writeb(bus, chip, SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG,
382 BRIDGE_GETHIGHERBYTE(edid->mode.va));
383 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG,
384 BRIDGE_GETLOWERBYTE(edid->mode.hspw));
385 i2c_writeb(bus, chip, SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG,
386 BRIDGE_GETHIGHERBYTE(edid->mode.hspw));
387 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG,
388 BRIDGE_GETLOWERBYTE(edid->mode.vspw));
389 i2c_writeb(bus, chip, SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG,
390 BRIDGE_GETHIGHERBYTE(edid->mode.vspw));
391 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_BACK_PORCH_REG,
392 edid->mode.hbl - edid->mode.hso - edid->mode.hspw);
393 i2c_writeb(bus, chip, SN_CHA_VERTICAL_BACK_PORCH_REG,
394 edid->mode.vbl - edid->mode.vso - edid->mode.vspw);
395 i2c_writeb(bus, chip, SN_CHA_HORIZONTAL_FRONT_PORCH_REG,
396 edid->mode.hso);
397 i2c_writeb(bus, chip, SN_CHA_VERTICAL_FRONT_PORCH_REG,
398 edid->mode.vso);
399}
400
401static void sn65dsi86_bridge_link_training(uint8_t bus, uint8_t chip)
402{
403 uint8_t buf;
404
405 /* enable pll lock */
406 i2c_writeb(bus, chip, SN_PLL_ENABLE_REG, 0x1);
407
408 if (!wait_ms(500,
409 !(i2c_readb(bus, chip, SN_DPPLL_SRC_REG, &buf)) &&
410 (buf & BIT(7)))) {
411 printk(BIOS_ERR, "ERROR: PLL lock failure\n");
412 }
413
414 /*
415 * The SN65DSI86 only supports ASSR Display Authentication method and
416 * this method is enabled by default. An eDP panel must support this
417 * authentication method. We need to enable this method in the eDP panel
418 * at DisplayPort address 0x0010A prior to link training.
419 */
420 buf = 0x1;
Julius Wernere0dbeee2021-05-05 17:41:10 -0700421 sn65dsi86_bridge_aux_request(bus, chip,
422 DP_BRIDGE_CONFIGURATION_SET, 1, DPCD_WRITE, &buf);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530423
Julius Werner411e7602020-09-30 15:23:46 -0700424 int i; /* Kernel driver suggests to retry this up to 10 times if it fails. */
425 for (i = 0; i < 10; i++) {
426 i2c_writeb(bus, chip, SN_ML_TX_MODE_REG, SEMI_AUTO_LINK_TRAINING);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530427
Julius Werner411e7602020-09-30 15:23:46 -0700428 if (!wait_ms(500, !(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
429 (buf == NORMAL_MODE || buf == MAIN_LINK_OFF))) {
430 printk(BIOS_ERR, "ERROR: unexpected link training state: %#x\n", buf);
431 return;
432 }
433 if (buf == NORMAL_MODE)
434 return;
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530435 }
436
Julius Werner411e7602020-09-30 15:23:46 -0700437 printk(BIOS_ERR, "ERROR: Link training failed 10 times\n");
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530438}
439
Vinod Polimera6ea80332021-03-17 16:11:12 +0530440void sn65dsi86_backlight_enable(uint8_t bus, uint8_t chip)
441{
442 uint8_t val = DP_BACKLIGHT_CONTROL_MODE_DPCD;
443 sn65dsi86_bridge_aux_request(bus, chip, DP_BACKLIGHT_MODE_SET, 1, DPCD_WRITE, &val);
444
445 val = 0xff;
446 sn65dsi86_bridge_aux_request(bus, chip, DP_BACKLIGHT_BRIGHTNESS_MSB, 1,
447 DPCD_WRITE, &val);
448
449 val = DP_BACKLIGHT_ENABLE;
450 sn65dsi86_bridge_aux_request(bus, chip, DP_DISPLAY_CONTROL_REGISTER, 1,
451 DPCD_WRITE, &val);
452}
453
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530454static void sn65dsi86_bridge_assr_config(uint8_t bus, uint8_t chip, int enable)
455{
456 if (enable)
457 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 1, 3);
458 else
459 i2c_write_field(bus, chip, SN_ENH_FRAME_REG, VSTREAM_DISABLE, 1, 3);
460}
461
462static int sn65dsi86_bridge_dp_lane_config(uint8_t bus, uint8_t chip)
463{
464 uint8_t lane_count;
465
Julius Wernere0dbeee2021-05-05 17:41:10 -0700466 sn65dsi86_bridge_aux_request(bus, chip, DP_MAX_LANE_COUNT, 1, DPCD_READ, &lane_count);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530467 lane_count &= DP_LANE_COUNT_MASK;
468 i2c_write_field(bus, chip, SN_SSC_CONFIG_REG, MIN(lane_count, 3), 3, 4);
469
470 return lane_count;
471}
472
473void sn65dsi86_bridge_init(uint8_t bus, uint8_t chip, enum dp_pll_clk_src ref_clk)
474{
Vinod Polimerab9a7d772020-09-21 08:55:16 +0530475 /* disable HPD */
476 i2c_write_field(bus, chip, SN_HPD_DISABLE_REG, HPD_DISABLE, 1, 0);
Vinod Polimerac4e0b0a2020-06-23 16:23:06 +0530477
478 /* set refclk to 19.2 MHZ */
479 i2c_write_field(bus, chip, SN_DPPLL_SRC_REG, ref_clk, 7, 1);
480}
481
482void sn65dsi86_bridge_configure(uint8_t bus, uint8_t chip,
483 struct edid *edid, uint32_t num_of_lanes,
484 uint32_t dsi_bpp)
485{
486 int dp_lanes;
487
488 /* DSI Lanes config */
489 i2c_write_field(bus, chip, SN_DSI_LANES_REG, (4 - num_of_lanes), 3, 3);
490
491 /* DP Lane config */
492 dp_lanes = sn65dsi86_bridge_dp_lane_config(bus, chip);
493
494 sn65dsi86_bridge_set_dsi_clock_range(bus, chip, edid, num_of_lanes, dsi_bpp);
495
496 sn65dsi86_bridge_set_dp_clock_range(bus, chip, edid, dp_lanes);
497
498 /* Disable vstream */
499 sn65dsi86_bridge_assr_config(bus, chip, 0);
500 sn65dsi86_bridge_link_training(bus, chip);
501 sn65dsi86_bridge_set_bridge_active_timing(bus, chip, edid);
502
503 /* DP BPP config */
504 i2c_writeb(bus, chip, SN_DATA_FORMAT_REG, 0x1);
505
506 /* color bar disabled */
507 i2c_writeb(bus, chip, SN_COLOR_BAR_REG, 0x5);
508
509 /* Enable vstream */
510 sn65dsi86_bridge_assr_config(bus, chip, 1);
511}