coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
sn65dsi86bridge.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <endian.h>
5 #include <device/i2c_simple.h>
6 #include <dp_aux.h>
7 #include <edid.h>
8 #include <timer.h>
9 #include <types.h>
10 #include <soc/addressmap.h>
11 #include "sn65dsi86bridge.h"
12 
13 #define BRIDGE_GETHIGHERBYTE(x) ((uint8_t)((x & 0xff00) >> 8))
14 #define BRIDGE_GETLOWERBYTE(x) ((uint8_t)(x & 0x00ff))
15 
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 
107 };
108 
109 enum {
110  HPD_ENABLE = 0x0,
111  HPD_DISABLE = 0x1,
112 };
113 
114 enum {
120 };
121 
125 };
126 
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 
137  NORMAL_MODE = 0x1,
138  TPS1 = 0x2,
139  TPS2 = 0x3,
140  TPS3 = 0x4,
141  PRBS7 = 0x5,
148 };
149 
150 /*
151  * LUT index corresponds to register value and LUT values corresponds
152  * to dp data rate supported by the bridge in Mbps unit.
153  */
154 static const unsigned int sn65dsi86_bridge_dp_rate_lut[] = {
155  0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
156 };
157 
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;
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. */
173 
174  while (total_size) {
175  length = MIN(total_size, DP_AUX_MAX_PAYLOAD_BYTES);
176  total_size -= length;
177 
178  enum i2c_over_aux cmd = dp_get_aux_cmd(request, total_size);
179  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) ||
184  return CB_ERR;
185 
186  if (dp_aux_request_is_write(request)) {
187  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))) {
197  printk(BIOS_ERR, "AUX_CMD_SEND not acknowledged\n");
198  return CB_ERR;
199  }
201  return CB_ERR;
203  printk(BIOS_ERR, "AUX command failed, status = %#x\n", buf);
204  return CB_ERR;
205  }
206 
207  if (!dp_aux_request_is_write(request)) {
208  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 
221 {
222  enum cb_err err;
223  u8 edid[EDID_LENGTH * 2];
224  int edid_size = EDID_LENGTH;
225 
226  uint8_t reg_addr = 0;
228  I2C_RAW_WRITE, &reg_addr);
229  if (!err)
232  if (err) {
233  printk(BIOS_ERR, "Failed to read EDID.\n");
234  return err;
235  }
236 
237  if (edid[EDID_EXTENSION_FLAG]) {
238  edid_size += EDID_LENGTH;
239  reg_addr = EDID_LENGTH;
241  I2C_RAW_WRITE, &reg_addr);
242  if (!err)
245  if (err) {
246  printk(BIOS_ERR, "Failed to read EDID ext block.\n");
247  return err;
248  }
249  }
250 
251  if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
252  printk(BIOS_ERR, "Failed to decode EDID.\n");
253  return CB_ERR;
254  }
255 
256  return CB_SUCCESS;
257 }
258 
259 static 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 
266  DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
267  if (dpcd_val >= DP_BRIDGE_14) {
268  /* eDP 1.4 devices must provide a custom table */
269  uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};
270 
272  sizeof(sink_rates),
273  DPCD_READ, (void *)sink_rates);
274  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;
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 */
299 
300  switch (dpcd_val) {
301  default:
302  printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
303  (int)dpcd_val);
305  case DP_LINK_BW_5_4:
306  rate_valid[7] = 1;
308  case DP_LINK_BW_2_7:
309  rate_valid[4] = 1;
311  case DP_LINK_BW_1_62:
312  rate_valid[1] = 1;
313  break;
314  }
315 }
316 
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 
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 
356 
357  /* Train until we run out of rates */
358  for (dp_rate_idx = i;
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
367  printk(BIOS_ERR, "valid dp rate not found");
368 }
369 
371  uint8_t chip,
372  struct edid *edid)
373 {
391  edid->mode.hbl - edid->mode.hso - edid->mode.hspw);
393  edid->mode.vbl - edid->mode.vso - edid->mode.vspw);
395  edid->mode.hso);
397  edid->mode.vso);
398 }
399 
401 {
402  uint8_t buf;
403 
404  /* enable pll lock */
406 
407  if (!wait_ms(500,
409  (buf & BIT(7)))) {
410  printk(BIOS_ERR, "PLL lock failure\n");
411  }
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;
422 
423  int i; /* Kernel driver suggests to retry this up to 10 times if it fails. */
424  for (i = 0; i < 10; i++) {
426 
427  if (!wait_ms(500, !(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
428  (buf == NORMAL_MODE || buf == MAIN_LINK_OFF))) {
429  printk(BIOS_ERR, "unexpected link training state: %#x\n", buf);
430  return;
431  }
432  if (buf == NORMAL_MODE)
433  return;
434  }
435 
436  printk(BIOS_ERR, "Link training failed 10 times\n");
437 }
438 
440 {
443 
444  val = 0xff;
446  DPCD_WRITE, &val);
447 
450  DPCD_WRITE, &val);
451 }
452 
454 {
455  if (enable)
457  else
459 }
460 
462 {
463  uint8_t lane_count;
464 
466  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 
473 {
474  /* disable HPD */
476 
477  /* set refclk to 19.2 MHZ */
478  i2c_write_field(bus, chip, SN_DPPLL_SRC_REG, ref_clk, 7, 1);
479 }
480 
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 */
492 
493  sn65dsi86_bridge_set_dsi_clock_range(bus, chip, edid, num_of_lanes, dsi_bpp);
494 
496 
497  /* Disable vstream */
501 
502  /* DP BPP config */
504 
505  /* color bar disabled */
507 
508  /* Enable vstream */
510 }
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define MIN(a, b)
Definition: helpers.h:37
#define MHz
Definition: helpers.h:80
#define KHz
Definition: helpers.h:79
#define MAX(a, b)
Definition: helpers.h:40
#define DIV_ROUND_UP(x, y)
Definition: helpers.h:60
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_ERR
Generic error code.
Definition: cb_err.h:17
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
#define printk(level,...)
Definition: stdlib.h:16
#define __fallthrough
Definition: compiler.h:39
int i2c_write_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t data, uint8_t mask, uint8_t shift)
Definition: i2c.c:20
#define DP_BACKLIGHT_MODE_SET
Definition: dp_aux.h:35
#define DP_AUX_MAX_PAYLOAD_BYTES
Definition: dp_aux.h:42
#define DP_DISPLAY_CONTROL_REGISTER
Definition: dp_aux.h:38
bool dp_aux_request_is_write(enum aux_request request)
Definition: dp_aux.c:5
#define DP_BACKLIGHT_BRIGHTNESS_MSB
Definition: dp_aux.h:40
aux_request
Definition: dp_aux.h:25
@ I2C_RAW_WRITE
Definition: dp_aux.h:29
@ DPCD_READ
Definition: dp_aux.h:26
@ I2C_RAW_READ_AND_STOP
Definition: dp_aux.h:30
@ DPCD_WRITE
Definition: dp_aux.h:27
enum i2c_over_aux dp_get_aux_cmd(enum aux_request request, uint32_t remaining_after_this)
Definition: dp_aux.c:17
#define DP_BACKLIGHT_ENABLE
Definition: dp_aux.h:39
i2c_over_aux
Definition: dp_aux.h:14
#define DP_BACKLIGHT_CONTROL_MODE_DPCD
Definition: dp_aux.h:37
@ EDID_EXTENSION_FLAG
Definition: dp_aux.h:11
@ EDID_I2C_ADDR
Definition: dp_aux.h:10
@ EDID_LENGTH
Definition: dp_aux.h:9
#define BIT(nr)
Definition: ec_commands.h:45
uint64_t length
Definition: fw_cfg_if.h:1
static struct tpm_chip chip
Definition: tis.c:17
static int i2c_writeb(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t data)
Write a byte with one segment in one frame.
Definition: i2c_simple.h:131
static int i2c_readb(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t *data)
Read a byte with two segments in one frame.
Definition: i2c_simple.h:109
@ EDID_CONFORMANT
Definition: edid.h:90
int decode_edid(unsigned char *edid, int size, struct edid *out)
Definition: edid.c:1104
#define wait_ms(timeout_ms, condition)
Definition: timer.h:215
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static uint8_t * buf
Definition: uart.c:7
static void sn65dsi86_bridge_set_dp_clock_range(uint8_t bus, uint8_t chip, struct edid *edid, uint32_t num_of_lanes)
#define DP_MAX_LINK_RATE
#define BRIDGE_GETLOWERBYTE(x)
#define DP_LANE_COUNT_MASK
static void sn65dsi86_bridge_assr_config(uint8_t bus, uint8_t chip, int enable)
static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate_valid[])
ml_tx_mode
@ CUTSOM_PATTERN
@ SYMBOL_ERR_RATE_MEASUREMENT_PATTERN
@ FAST_LINK_TRAINING
@ HBR2_COMPLIANCE_EYE_PATTERN
@ SEMI_AUTO_LINK_TRAINING
@ TPS2
@ TPS1
@ NORMAL_MODE
@ TPS3
@ PRBS7
@ MAIN_LINK_OFF
@ REDRIVER_SEMI_AUTO_LINK_TRAINING
void sn65dsi86_backlight_enable(uint8_t bus, uint8_t chip)
static const unsigned int sn65dsi86_bridge_dp_rate_lut[]
vstream_config
@ VSTREAM_DISABLE
@ VSTREAM_ENABLE
#define DP_BRIDGE_DPCD_REV
static void sn65dsi86_bridge_link_training(uint8_t bus, uint8_t chip)
#define DP_BRIDGE_14
#define DP_LINK_BW_5_4
bridge_regs
@ SN_AUX_LENGTH_REG
@ SN_AUX_WDATA_REG_10
@ SN_AUX_WDATA_REG_4
@ SN_AUX_RDATA_REG_8
@ SN_AUX_WDATA_REG_2
@ SN_DPPLL_SRC_REG
@ SN_AUX_WDATA_REG_0
@ SN_DSI_LANES_REG
@ SN_AUX_RDATA_REG_6
@ SN_AUX_WDATA_REG_9
@ SN_CHA_VERTICAL_FRONT_PORCH_REG
@ SN_AUX_RDATA_REG_3
@ SN_ML_TX_MODE_REG
@ SN_DSIA_CLK_FREQ_REG
@ SN_CHA_HORIZONTAL_FRONT_PORCH_REG
@ SN_AUX_RDATA_REG_11
@ SN_CHA_VSYNC_PULSE_WIDTH_HIGH_REG
@ SN_AUX_RDATA_REG_0
@ SN_AUX_ADDR_15_8_REG
@ SN_AUX_WDATA_REG_11
@ SN_AUX_RDATA_REG_4
@ SN_CHA_HORIZONTAL_BACK_PORCH_REG
@ SN_DATA_FORMAT_REG
@ SN_AUX_WDATA_REG_6
@ SN_AUX_WDATA_REG_5
@ SN_COLOR_BAR_REG
@ SN_AUX_RDATA_REG_9
@ SN_SSC_CONFIG_REG
@ SN_AUX_WDATA_REG_12
@ SN_AUX_CMD_REG
@ SN_AUX_WDATA_REG_3
@ SN_AUX_WDATA_REG_14
@ SN_AUX_RDATA_REG_14
@ SN_AUX_RDATA_REG_12
@ SN_HPD_DISABLE_REG
@ SN_AUX_RDATA_REG_15
@ SN_AUX_ADDR_7_0_REG
@ SN_AUX_WDATA_REG_7
@ SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG
@ SN_AUX_WDATA_REG_15
@ SN_AUX_RDATA_REG_13
@ SN_AUX_ADDR_19_16_REG
@ SN_AUX_WDATA_REG_8
@ SN_I2C_CLAIM_ADDR_EN1
@ SN_AUX_RDATA_REG_1
@ SN_AUX_RDATA_REG_10
@ SN_AUX_WDATA_REG_1
@ SN_ENH_FRAME_REG
@ SN_AUX_RDATA_REG_7
@ SN_CHA_HSYNC_PULSE_WIDTH_HIGH_REG
@ SN_CHA_ACTIVE_LINE_LENGTH_HIGH_REG
@ SN_CHA_VERTICAL_DISPLAY_SIZE_LOW_REG
@ SN_AUX_WDATA_REG_13
@ SN_AUX_RDATA_REG_5
@ SN_CHA_VERTICAL_BACK_PORCH_REG
@ SN_CHA_VSYNC_PULSE_WIDTH_LOW_REG
@ SN_AUX_RDATA_REG_2
@ SN_CHA_HSYNC_PULSE_WIDTH_LOW_REG
@ SN_PLL_ENABLE_REG
@ SN_CHA_VERTICAL_DISPLAY_SIZE_HIGH_REG
@ SN_DATARATE_CONFIG_REG
@ SN_AUX_CMD_STATUS_REG
#define DP_SUPPORTED_LINK_RATES
static enum cb_err sn65dsi86_bridge_aux_request(uint8_t bus, uint8_t chip, unsigned int target_reg, unsigned int total_size, enum aux_request request, uint8_t *data)
#define DP_BRIDGE_CONFIGURATION_SET
@ LEFT_RIGHT_PIXELS
@ CHA_DSI_LANES
@ CHB_DSI_LANES
@ SOT_ERR_TOL_DSI
@ DSI_CHANNEL_MODE
@ HPD_ENABLE
@ HPD_DISABLE
void sn65dsi86_bridge_init(uint8_t bus, uint8_t chip, enum dp_pll_clk_src ref_clk)
#define DP_CLK_FUDGE_NUM
void sn65dsi86_bridge_configure(uint8_t bus, uint8_t chip, struct edid *edid, uint32_t num_of_lanes, uint32_t dsi_bpp)
#define DP_MAX_SUPPORTED_RATES
aux_cmd_status
@ SEND_INT
@ AUX_RPLY_TOUT
@ NAT_I2C_FAIL
@ AUX_DFER
@ AUX_SHORT
#define DP_LINK_BW_2_7
static void sn65dsi86_bridge_set_dsi_clock_range(uint8_t bus, uint8_t chip, struct edid *edid, uint32_t num_of_lanes, uint32_t bpp)
static void sn65dsi86_bridge_set_bridge_active_timing(uint8_t bus, uint8_t chip, struct edid *edid)
#define DP_LINK_BW_1_62
enum cb_err sn65dsi86_bridge_read_edid(uint8_t bus, uint8_t chip, struct edid *out)
#define MIN_DSI_CLK_FREQ_MHZ
#define DP_MAX_LANE_COUNT
#define MAX_DSI_CLK_FREQ_MHZ
static int sn65dsi86_bridge_dp_lane_config(uint8_t bus, uint8_t chip)
#define BRIDGE_GETHIGHERBYTE(x)
#define AUX_CMD_SEND
#define DP_CLK_FUDGE_DEN
dp_pll_clk_src
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned long long uint64_t
Definition: stdint.h:17
uint8_t u8
Definition: stdint.h:45
unsigned char uint8_t
Definition: stdint.h:8
Definition: device.h:76
unsigned int hbl
Definition: edid.h:26
unsigned int va
Definition: edid.h:30
unsigned int vspw
Definition: edid.h:33
unsigned int ha
Definition: edid.h:25
unsigned int vso
Definition: edid.h:32
unsigned int hso
Definition: edid.h:27
unsigned int pixel_clock
Definition: edid.h:22
unsigned int hspw
Definition: edid.h:28
unsigned int vbl
Definition: edid.h:31
Definition: edid.h:49
struct edid_mode mode
Definition: edid.h:72
u8 val
Definition: sys.c:300