blob: 5da2c066f55a3a9b73735812577935ccfae4dc6d [file] [log] [blame]
Angel Ponsa2ee7612020-04-04 18:51:15 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Angel Ponsa2ee7612020-04-04 18:51:15 +02002
Julius Werneredf6b572013-10-25 17:49:26 -07003/*
4 * drivers/video/tegra/dc/dp.c
Julius Werneredf6b572013-10-25 17:49:26 -07005 */
6
Julius Werneredf6b572013-10-25 17:49:26 -07007#include <console/console.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -07008#include <delay.h>
Julius Werneredf6b572013-10-25 17:49:26 -07009#include <device/device.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +020010#include <device/i2c_simple.h>
Hung-Te Lin3af0d312014-04-02 21:57:40 +080011#include <edid.h>
Julius Werneredf6b572013-10-25 17:49:26 -070012#include <soc/addressmap.h>
13#include <soc/nvidia/tegra/i2c.h>
14#include <soc/nvidia/tegra/dc.h>
Julius Werneredf6b572013-10-25 17:49:26 -070015#include <soc/nvidia/tegra/displayport.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -070016#include <soc/sor.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -070017#include <string.h>
Elyes HAOUAS30818552019-06-23 07:03:59 +020018#include <types.h>
Julius Wernerf0d21ff32014-10-20 13:24:14 -070019
20#include "chip.h"
Julius Werneredf6b572013-10-25 17:49:26 -070021
Neil Chen8c440a62014-09-23 17:41:59 +080022enum {
23 DP_LT_SUCCESS = 0,
24 DP_LT_FAILED = -1,
25};
26
Jimmy Zhangbd5925a2014-03-10 12:42:05 -070027struct tegra_dc_dp_data dp_data;
Julius Werneredf6b572013-10-25 17:49:26 -070028
29static inline u32 tegra_dpaux_readl(struct tegra_dc_dp_data *dp, u32 reg)
30{
31 void *addr = dp->aux_base + (u32) (reg << 2);
32 u32 reg_val = READL(addr);
33 return reg_val;
34}
35
36static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080037 u32 reg, u32 val)
Julius Werneredf6b572013-10-25 17:49:26 -070038{
39 void *addr = dp->aux_base + (u32) (reg << 2);
40 WRITEL(val, addr);
41}
42
43static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080044 u32 reg, u32 mask, u32 exp_val,
45 u32 poll_interval_us,
46 u32 timeout_us)
Julius Werneredf6b572013-10-25 17:49:26 -070047{
48 u32 reg_val = 0;
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080049 u32 temp = timeout_us;
Julius Werneredf6b572013-10-25 17:49:26 -070050
Julius Werneredf6b572013-10-25 17:49:26 -070051 do {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080052 udelay(poll_interval_us);
Julius Werneredf6b572013-10-25 17:49:26 -070053 reg_val = tegra_dpaux_readl(dp, reg);
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080054 if (timeout_us > poll_interval_us)
55 timeout_us -= poll_interval_us;
56 else
57 break;
58 } while ((reg_val & mask) != exp_val);
Julius Werneredf6b572013-10-25 17:49:26 -070059
60 if ((reg_val & mask) == exp_val)
61 return 0; /* success */
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080062 printk(BIOS_ERR,
Julius Werneredf6b572013-10-25 17:49:26 -070063 "dpaux_poll_register 0x%x: timeout: "
64 "(reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n",
65 reg, reg_val, mask, exp_val);
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080066 return temp;
Julius Werneredf6b572013-10-25 17:49:26 -070067}
68
69static inline int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp)
70{
71 /* According to DP spec, each aux transaction needs to finish
72 within 40ms. */
73 if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080074 DPAUX_DP_AUXCTL_TRANSACTREQ_MASK,
75 DPAUX_DP_AUXCTL_TRANSACTREQ_DONE,
76 100, DP_AUX_TIMEOUT_MS * 1000) != 0) {
77 printk(BIOS_INFO, "dp: DPAUX transaction timeout\n");
Julius Werneredf6b572013-10-25 17:49:26 -070078 return -1;
79 }
80 return 0;
81}
82
83static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -080084 u32 addr, u8 *data, u32 *size,
85 u32 *aux_stat)
Julius Werneredf6b572013-10-25 17:49:26 -070086{
87 int i;
88 u32 reg_val;
89 u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
90 u32 defer_retries = DP_AUX_DEFER_MAX_TRIES;
91 u32 temp_data;
92
93 if (*size > DP_AUX_MAX_BYTES)
94 return -1; /* only write one chunk of data */
95
96 /* Make sure the command is write command */
97 switch (cmd) {
98 case DPAUX_DP_AUXCTL_CMD_I2CWR:
99 case DPAUX_DP_AUXCTL_CMD_MOTWR:
100 case DPAUX_DP_AUXCTL_CMD_AUXWR:
101 break;
102 default:
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800103 printk(BIOS_ERR, "dp: aux write cmd 0x%x is invalid\n",
104 cmd);
Julius Werneredf6b572013-10-25 17:49:26 -0700105 return -1;
106 }
107
Julius Werneredf6b572013-10-25 17:49:26 -0700108 tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
109 for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) {
110 memcpy(&temp_data, data, 4);
111 tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), temp_data);
112 data += 4;
113 }
114
115 reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
116 reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
117 reg_val |= cmd;
118 reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
119 reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
120
121 while ((timeout_retries > 0) && (defer_retries > 0)) {
122 if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
123 (defer_retries != DP_AUX_DEFER_MAX_TRIES))
124 udelay(1);
125
126 reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
127 tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
128
129 if (tegra_dpaux_wait_transaction(dp))
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800130 printk(BIOS_ERR, "dp: aux write transaction timeout\n");
Julius Werneredf6b572013-10-25 17:49:26 -0700131
132 *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
133
134 if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
135 (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
136 (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
137 (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
138 if (timeout_retries-- > 0) {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800139 printk(BIOS_INFO, "dp: aux write retry (0x%x) -- %d\n",
Julius Werneredf6b572013-10-25 17:49:26 -0700140 *aux_stat, timeout_retries);
141 /* clear the error bits */
142 tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, *aux_stat);
143 continue;
144 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800145 printk(BIOS_ERR, "dp: aux write got error (0x%x)\n",
Julius Werneredf6b572013-10-25 17:49:26 -0700146 *aux_stat);
147 return -1;
148 }
149 }
150
151 if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
152 (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
153 if (defer_retries-- > 0) {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800154 printk(BIOS_INFO, "dp: aux write defer (0x%x) -- %d\n",
Julius Werneredf6b572013-10-25 17:49:26 -0700155 *aux_stat, defer_retries);
156 /* clear the error bits */
157 tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, *aux_stat);
158 continue;
159 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800160 printk(BIOS_ERR, "dp: aux write defer exceeds max retries "
Julius Werneredf6b572013-10-25 17:49:26 -0700161 "(0x%x)\n", *aux_stat);
162 return -1;
163 }
164 }
165
166 if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
167 DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
168 *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
169 return 0;
170 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800171 printk(BIOS_ERR, "dp: aux write failed (0x%x)\n",
172 *aux_stat);
Julius Werneredf6b572013-10-25 17:49:26 -0700173 return -1;
174 }
175 }
176 /* Should never come to here */
177 return -1;
178}
179
Julius Werneredf6b572013-10-25 17:49:26 -0700180static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800181 u32 addr, u8 *data, u32 *size,
182 u32 *aux_stat)
Julius Werneredf6b572013-10-25 17:49:26 -0700183{
184 u32 reg_val;
185 u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
186 u32 defer_retries = DP_AUX_DEFER_MAX_TRIES;
187
188 if (*size > DP_AUX_MAX_BYTES)
189 return -1; /* only read one chunk */
190
191 /* Check to make sure the command is read command */
192 switch (cmd) {
193 case DPAUX_DP_AUXCTL_CMD_I2CRD:
194 case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT:
195 case DPAUX_DP_AUXCTL_CMD_MOTRD:
196 case DPAUX_DP_AUXCTL_CMD_AUXRD:
197 break;
198 default:
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800199 printk(BIOS_ERR, "dp: aux read cmd 0x%x is invalid\n",
200 cmd);
Julius Werneredf6b572013-10-25 17:49:26 -0700201 return -1;
202 }
203
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700204 *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
205 if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
206 printk(BIOS_SPEW, "dp: HPD is not detected\n");
207 return -1;
Julius Werneredf6b572013-10-25 17:49:26 -0700208 }
209
210 tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
211
212 reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
213 reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
214 reg_val |= cmd;
Julius Werneredf6b572013-10-25 17:49:26 -0700215 reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
216 reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
Julius Werneredf6b572013-10-25 17:49:26 -0700217 while ((timeout_retries > 0) && (defer_retries > 0)) {
218 if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
219 (defer_retries != DP_AUX_DEFER_MAX_TRIES))
220 udelay(DP_DPCP_RETRY_SLEEP_NS * 2);
221
222 reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
Julius Werneredf6b572013-10-25 17:49:26 -0700223 tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
224
225 if (tegra_dpaux_wait_transaction(dp))
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800226 printk(BIOS_INFO, "dp: aux read transaction timeout\n");
Julius Werneredf6b572013-10-25 17:49:26 -0700227
228 *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
Julius Werneredf6b572013-10-25 17:49:26 -0700229
230 if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
231 (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
232 (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
233 (*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
234 if (timeout_retries-- > 0) {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800235 printk(BIOS_INFO, "dp: aux read retry (0x%x)"
236 " -- %d\n", *aux_stat,
237 timeout_retries);
Julius Werneredf6b572013-10-25 17:49:26 -0700238 /* clear the error bits */
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800239 tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT,
240 *aux_stat);
Julius Werneredf6b572013-10-25 17:49:26 -0700241 continue; /* retry */
242 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800243 printk(BIOS_ERR, "dp: aux read got error"
244 " (0x%x)\n", *aux_stat);
Julius Werneredf6b572013-10-25 17:49:26 -0700245 return -1;
246 }
247 }
248
249 if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
250 (*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
251 if (defer_retries-- > 0) {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800252 printk(BIOS_INFO, "dp: aux read defer (0x%x) -- %d\n",
Julius Werneredf6b572013-10-25 17:49:26 -0700253 *aux_stat, defer_retries);
254 /* clear the error bits */
255 tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, *aux_stat);
256 continue;
257 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800258 printk(BIOS_INFO, "dp: aux read defer exceeds max retries "
Julius Werneredf6b572013-10-25 17:49:26 -0700259 "(0x%x)\n", *aux_stat);
260 return -1;
261 }
262 }
263
264 if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
265 DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
266 int i;
267 u32 temp_data[4];
268
269 for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i)
270 temp_data[i] = tegra_dpaux_readl(dp,
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800271 DPAUX_DP_AUXDATA_READ_W(i));
Julius Werneredf6b572013-10-25 17:49:26 -0700272
273 *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
Julius Werneredf6b572013-10-25 17:49:26 -0700274 memcpy(data, temp_data, *size);
275
276 return 0;
277 } else {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800278 printk(BIOS_ERR, "dp: aux read failed (0x%x\n",
279 *aux_stat);
Julius Werneredf6b572013-10-25 17:49:26 -0700280 return -1;
281 }
282 }
283 /* Should never come to here */
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800284 printk(BIOS_ERR, "%s: can't\n", __func__);
Julius Werneredf6b572013-10-25 17:49:26 -0700285 return -1;
286}
287
Jimmy Zhang75f701792014-04-21 15:58:45 -0700288static int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
289 u8 *data, u32 *size, u32 *aux_stat)
290{
291 u32 finished = 0;
292 u32 cur_size;
293 int ret = 0;
294
295 do {
296 cur_size = *size - finished;
297 if (cur_size > DP_AUX_MAX_BYTES)
298 cur_size = DP_AUX_MAX_BYTES;
299
300 ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr,
301 data, &cur_size, aux_stat);
302 if (ret)
303 break;
304
305 /* cur_size should be the real size returned */
306 addr += cur_size;
307 data += cur_size;
308 finished += cur_size;
309
310 } while (*size > finished);
311
312 *size = finished;
313 return ret;
314}
315
Julius Werneredf6b572013-10-25 17:49:26 -0700316static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd,
Elyes HAOUAS39303d52018-07-08 12:40:45 +0200317 u8 *data_ptr)
Julius Werneredf6b572013-10-25 17:49:26 -0700318{
319 u32 size = 1;
320 u32 status = 0;
321 int ret;
322
323 ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700324 cmd, data_ptr, &size, &status);
Julius Werneredf6b572013-10-25 17:49:26 -0700325 if (ret)
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -0800326 printk(BIOS_ERR,
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700327 "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n",
328 cmd, status);
Julius Werneredf6b572013-10-25 17:49:26 -0700329
330 return ret;
331}
332
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700333static int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd,
334 u8 data)
335{
336 u32 size = 1;
337 u32 status = 0;
338 int ret;
339
340 ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
341 cmd, &data, &size, &status);
342 if (ret)
343 printk(BIOS_ERR,
344 "dp: Failed to write DPCD data. CMD 0x%x, Status 0x%x\n",
345 cmd, status);
346 return ret;
347}
348
Hung-Te Lin3af0d312014-04-02 21:57:40 +0800349static int tegra_dc_i2c_aux_read(struct tegra_dc_dp_data *dp, u32 i2c_addr,
350 u8 addr, u8 *data, u32 *size, u32 *aux_stat)
Hung-Te Linc04d3dd72014-03-05 21:09:58 +0800351{
352 u32 finished = 0;
353 int ret = 0;
354
355 do {
356 u32 cur_size = MIN(DP_AUX_MAX_BYTES, *size - finished);
357
358 u32 len = 1;
359 ret = tegra_dc_dpaux_write_chunk(
Ken Chang2d43a482014-04-15 17:00:17 +0800360 dp, DPAUX_DP_AUXCTL_CMD_MOTWR, i2c_addr,
Hung-Te Linc04d3dd72014-03-05 21:09:58 +0800361 &addr, &len, aux_stat);
362 if (ret) {
363 printk(BIOS_ERR, "%s: error sending address to read.\n",
364 __func__);
365 break;
366 }
367
368 ret = tegra_dc_dpaux_read_chunk(
369 dp, DPAUX_DP_AUXCTL_CMD_I2CRD, i2c_addr,
370 data, &cur_size, aux_stat);
371 if (ret) {
372 printk(BIOS_ERR, "%s: error reading data.\n", __func__);
373 break;
374 }
375
376 /* cur_size should be the real size returned */
377 addr += cur_size;
378 data += cur_size;
379 finished += cur_size;
380 } while (*size > finished);
381
382 *size = finished;
383 return ret;
384}
385
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700386static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp)
387{
388 /* clear interrupt */
389 tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff);
390 /* do not enable interrupt for now. Enable them when Isr in place */
391 tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0);
392
393 tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL,
394 DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 |
395 DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 |
396 0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT |
397 DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE);
398
399 tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE,
400 DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP);
401}
402
403static void tegra_dc_dp_dump_link_cfg(struct tegra_dc_dp_data *dp,
404 const struct tegra_dc_dp_link_config *link_cfg)
405{
406 printk(BIOS_INFO, "DP config: cfg_name "
407 "cfg_value\n");
408 printk(BIOS_INFO, " Lane Count %d\n",
409 link_cfg->max_lane_count);
410 printk(BIOS_INFO, " SupportEnhancedFraming %s\n",
411 link_cfg->support_enhanced_framing ? "Y" : "N");
412 printk(BIOS_INFO, " Bandwidth %d\n",
413 link_cfg->max_link_bw);
414 printk(BIOS_INFO, " bpp %d\n",
415 link_cfg->bits_per_pixel);
416 printk(BIOS_INFO, " EnhancedFraming %s\n",
417 link_cfg->enhanced_framing ? "Y" : "N");
418 printk(BIOS_INFO, " Scramble_enabled %s\n",
419 link_cfg->scramble_ena ? "Y" : "N");
420 printk(BIOS_INFO, " LinkBW %d\n",
421 link_cfg->link_bw);
422 printk(BIOS_INFO, " lane_count %d\n",
423 link_cfg->lane_count);
424 printk(BIOS_INFO, " activespolarity %d\n",
425 link_cfg->activepolarity);
426 printk(BIOS_INFO, " active_count %d\n",
427 link_cfg->active_count);
428 printk(BIOS_INFO, " tu_size %d\n",
429 link_cfg->tu_size);
430 printk(BIOS_INFO, " active_frac %d\n",
431 link_cfg->active_frac);
432 printk(BIOS_INFO, " watermark %d\n",
433 link_cfg->watermark);
434 printk(BIOS_INFO, " hblank_sym %d\n",
435 link_cfg->hblank_sym);
436 printk(BIOS_INFO, " vblank_sym %d\n",
437 link_cfg->vblank_sym);
Jimmy Zhang75f701792014-04-21 15:58:45 -0700438}
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700439
Neil Chen8c440a62014-09-23 17:41:59 +0800440static int _tegra_dp_lower_link_config(struct tegra_dc_dp_data *dp,
441 struct tegra_dc_dp_link_config *cfg)
442{
443
444 switch (cfg->link_bw){
445 case SOR_LINK_SPEED_G1_62:
446 if (cfg->max_link_bw > SOR_LINK_SPEED_G1_62)
447 cfg->link_bw = SOR_LINK_SPEED_G2_7;
448 cfg->lane_count /= 2;
449 break;
450 case SOR_LINK_SPEED_G2_7:
451 cfg->link_bw = SOR_LINK_SPEED_G1_62;
452 break;
453 case SOR_LINK_SPEED_G5_4:
454 if (cfg->lane_count == 1) {
455 cfg->link_bw = SOR_LINK_SPEED_G2_7;
456 cfg->lane_count = cfg->max_lane_count;
457 } else
458 cfg->lane_count /= 2;
459 break;
460 default:
461 printk(BIOS_ERR,"dp: Error link rate %d\n", cfg->link_bw);
462 return DP_LT_FAILED;
463 }
464
465 return (cfg->lane_count > 0) ? DP_LT_SUCCESS : DP_LT_FAILED;
466}
467
Martin Roth26f97f92021-10-01 14:53:22 -0600468/* Calculate if given cfg can meet the mode request. */
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700469/* Return true if mode is possible, false otherwise. */
470static int tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp,
471 const struct soc_nvidia_tegra124_config *config,
472 struct tegra_dc_dp_link_config *link_cfg)
473{
474 const u32 link_rate = 27 * link_cfg->link_bw * 1000 * 1000;
475 const u64 f = 100000; /* precision factor */
476
477 u32 num_linkclk_line; /* Number of link clocks per line */
478 u64 ratio_f; /* Ratio of incoming to outgoing data rate */
479
480 u64 frac_f;
481 u64 activesym_f; /* Activesym per TU */
482 u64 activecount_f;
483 u32 activecount;
484 u32 activepolarity;
485 u64 approx_value_f;
486 u32 activefrac = 0;
487 u64 accumulated_error_f = 0;
488 u32 lowest_neg_activecount = 0;
489 u32 lowest_neg_activepolarity = 0;
490 u32 lowest_neg_tusize = 64;
491 u32 num_symbols_per_line;
492 u64 lowest_neg_activefrac = 0;
493 u64 lowest_neg_error_f = 64 * f;
494 u64 watermark_f;
495
496 int i;
497 int neg;
498
499 if (!link_rate || !link_cfg->lane_count || !config->pixel_clock ||
500 !link_cfg->bits_per_pixel)
501 return -1;
502
503 if ((u64)config->pixel_clock * link_cfg->bits_per_pixel >=
504 (u64)link_rate * 8 * link_cfg->lane_count)
505 return -1;
506
507 num_linkclk_line = (u32)((u64)link_rate * (u64)config->xres / config->pixel_clock);
508
509 ratio_f = (u64)config->pixel_clock * link_cfg->bits_per_pixel * f;
510 ratio_f /= 8;
511 ratio_f = (u64)(ratio_f / (link_rate * link_cfg->lane_count));
512
513 for (i = 64; i >= 32; --i) {
514 activesym_f = ratio_f * i;
515 activecount_f = (u64)(activesym_f / (u32)f) * f;
516 frac_f = activesym_f - activecount_f;
517 activecount = (u32)((u64)(activecount_f / (u32)f));
518
519 if (frac_f < (f / 2)) /* fraction < 0.5 */
520 activepolarity = 0;
521 else {
522 activepolarity = 1;
523 frac_f = f - frac_f;
524 }
525
526 if (frac_f != 0) {
527 frac_f = (u64)((f * f) / frac_f); /* 1/fraction */
528 if (frac_f > (15 * f))
529 activefrac = activepolarity ? 1 : 15;
530 else
531 activefrac = activepolarity ?
532 (u32)((u64)(frac_f / (u32)f)) + 1 :
533 (u32)((u64)(frac_f / (u32)f));
534 }
535
536 if (activefrac == 1)
537 activepolarity = 0;
538
539 if (activepolarity == 1)
540 approx_value_f = activefrac ? (u64)(
541 (activecount_f + (activefrac * f - f) * f) /
542 (activefrac * f)) :
543 activecount_f + f;
544 else
545 approx_value_f = activefrac ?
546 activecount_f + (u64)(f / activefrac) :
547 activecount_f;
548
549 if (activesym_f < approx_value_f) {
550 accumulated_error_f = num_linkclk_line *
551 (u64)((approx_value_f - activesym_f) / i);
552 neg = 1;
553 } else {
554 accumulated_error_f = num_linkclk_line *
555 (u64)((activesym_f - approx_value_f) / i);
556 neg = 0;
557 }
558
559 if ((neg && (lowest_neg_error_f > accumulated_error_f)) ||
560 (accumulated_error_f == 0)) {
561 lowest_neg_error_f = accumulated_error_f;
562 lowest_neg_tusize = i;
563 lowest_neg_activecount = activecount;
564 lowest_neg_activepolarity = activepolarity;
565 lowest_neg_activefrac = activefrac;
566
567 if (accumulated_error_f == 0)
568 break;
569 }
570 }
571
572 if (lowest_neg_activefrac == 0) {
573 link_cfg->activepolarity = 0;
574 link_cfg->active_count = lowest_neg_activepolarity ?
575 lowest_neg_activecount : lowest_neg_activecount - 1;
576 link_cfg->tu_size = lowest_neg_tusize;
577 link_cfg->active_frac = 1;
578 } else {
579 link_cfg->activepolarity = lowest_neg_activepolarity;
580 link_cfg->active_count = (u32)lowest_neg_activecount;
581 link_cfg->tu_size = lowest_neg_tusize;
582 link_cfg->active_frac = (u32)lowest_neg_activefrac;
583 }
584
585 watermark_f = (u64)((ratio_f * link_cfg->tu_size * (f - ratio_f)) / f);
586 link_cfg->watermark = (u32)((u64)((watermark_f + lowest_neg_error_f) /
587 f)) + link_cfg->bits_per_pixel / 4 - 1;
588 num_symbols_per_line = (config->xres * link_cfg->bits_per_pixel) /
589 (8 * link_cfg->lane_count);
590
591 if (link_cfg->watermark > 30) {
592 printk(BIOS_INFO,
593 "dp: sor setting: unable to get a good tusize, "
594 "force watermark to 30.\n");
595 link_cfg->watermark = 30;
596 return -1;
597 } else if (link_cfg->watermark > num_symbols_per_line) {
598 printk(BIOS_INFO,
599 "dp: sor setting: force watermark to the number "
600 "of symbols in the line.\n");
601 link_cfg->watermark = num_symbols_per_line;
602 return -1;
603 }
604
605 /* Refer to dev_disp.ref for more information. */
606 /* # symbols/hblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - */
607 /* SetRasterBlankStart.X - 7) * link_clk / pclk) */
608 /* - 3 * enhanced_framing - Y */
609 /* where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 */
610 link_cfg->hblank_sym = (int)((u64)(((u64)(config->hback_porch +
611 config->hfront_porch + config->hsync_width - 7) *
612 link_rate) / config->pixel_clock)) -
613 3 * link_cfg->enhanced_framing -
614 (12 / link_cfg->lane_count);
615
616 if (link_cfg->hblank_sym < 0)
617 link_cfg->hblank_sym = 0;
618
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700619 /* Refer to dev_disp.ref for more information. */
620 /* # symbols/vblank = ((SetRasterBlankStart.X - */
621 /* SetRasterBlankEen.X - 25) * link_clk / pclk) */
622 /* - Y - 1; */
623 /* where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 */
624 link_cfg->vblank_sym = (int)((u64)((u64)(config->xres - 25)
625 * link_rate / config->pixel_clock)) - (36 /
626 link_cfg->lane_count) - 4;
627
628 if (link_cfg->vblank_sym < 0)
629 link_cfg->vblank_sym = 0;
630
631 link_cfg->is_valid = 1;
632 tegra_dc_dp_dump_link_cfg(dp, link_cfg);
633
634 return 0;
635}
636
Jimmy Zhang75f701792014-04-21 15:58:45 -0700637static int tegra_dc_dp_init_max_link_cfg(
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700638 struct soc_nvidia_tegra124_config *config,
639 struct tegra_dc_dp_data *dp,
640 struct tegra_dc_dp_link_config *link_cfg)
Julius Werneredf6b572013-10-25 17:49:26 -0700641{
642 u8 dpcd_data;
643 int ret;
644
Jimmy Zhang75f701792014-04-21 15:58:45 -0700645 CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT,
646 &dpcd_data));
647 link_cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK;
Neil Chen8c440a62014-09-23 17:41:59 +0800648 link_cfg->tps3_supported = (dpcd_data &
649 NV_DPCD_MAX_LANE_COUNT_TPS3_SUPPORTED_YES) ? 1 : 0;
Jimmy Zhang75f701792014-04-21 15:58:45 -0700650
651 link_cfg->support_enhanced_framing =
652 (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ?
653 1 : 0;
654
655 CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD,
656 &dpcd_data));
657 link_cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT)?
658 1 : 0;
659
Neil Chen8c440a62014-09-23 17:41:59 +0800660 CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_AUX_RD_INTERVAL,
661 &link_cfg->aux_rd_interval));
662
Jimmy Zhang75f701792014-04-21 15:58:45 -0700663 CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH,
664 &link_cfg->max_link_bw));
665
666 link_cfg->bits_per_pixel = config->panel_bits_per_pixel;
667
668 /*
669 * Set to a high value for link training and attach.
670 * Will be re-programmed when dp is enabled.
671 */
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700672 link_cfg->drive_current = config->drive_current;
673 link_cfg->preemphasis = config->preemphasis;
674 link_cfg->postcursor = config->postcursor;
Julius Werneredf6b572013-10-25 17:49:26 -0700675
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700676 CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP,
677 &dpcd_data));
678 link_cfg->alt_scramber_reset_cap =
679 (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ?
680 1 : 0;
681 link_cfg->only_enhanced_framing =
682 (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ?
683 1 : 0;
Julius Werneredf6b572013-10-25 17:49:26 -0700684
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700685 link_cfg->lane_count = link_cfg->max_lane_count;
686 link_cfg->link_bw = link_cfg->max_link_bw;
687 link_cfg->enhanced_framing = link_cfg->support_enhanced_framing;
Julius Werneredf6b572013-10-25 17:49:26 -0700688
Jimmy Zhangbd5925a2014-03-10 12:42:05 -0700689 tegra_dc_dp_calc_config(dp, config, link_cfg);
Julius Werneredf6b572013-10-25 17:49:26 -0700690 return 0;
691}
692
Jimmy Zhangd712ec42014-04-14 12:47:37 -0700693static int tegra_dc_dp_set_assr(struct tegra_dc_dp_data *dp, int ena)
694{
695 int ret;
696
697 u8 dpcd_data = ena ?
698 NV_DPCD_EDP_CONFIG_SET_ASC_RESET_ENABLE :
699 NV_DPCD_EDP_CONFIG_SET_ASC_RESET_DISABLE;
700
701 CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_EDP_CONFIG_SET,
702 dpcd_data));
703
704 /* Also reset the scrambler to 0xfffe */
705 tegra_dc_sor_set_internal_panel(&dp->sor, ena);
706 return 0;
707}
708
Jimmy Zhang75f701792014-04-21 15:58:45 -0700709static int tegra_dp_set_link_bandwidth(struct tegra_dc_dp_data *dp, u8 link_bw)
710{
711 tegra_dc_sor_set_link_bandwidth(&dp->sor, link_bw);
712
713 /* Sink side */
714 return tegra_dc_dp_dpcd_write(dp, NV_DPCD_LINK_BANDWIDTH_SET, link_bw);
715}
716
717static int tegra_dp_set_lane_count(struct tegra_dc_dp_data *dp,
718 const struct tegra_dc_dp_link_config *link_cfg)
719{
720 u8 dpcd_data;
721 int ret;
722
723 /* check if panel support enhanched_framing */
724 dpcd_data = link_cfg->lane_count;
725 if (link_cfg->enhanced_framing)
726 dpcd_data |= NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_T;
727 CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_LANE_COUNT_SET,
728 dpcd_data));
729
730 tegra_dc_sor_set_lane_count(&dp->sor, link_cfg->lane_count);
731
732 /* Also power down lanes that will not be used */
733 return 0;
734}
735
736static int tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp,
737 const struct tegra_dc_dp_link_config *cfg)
738{
739 u32 lane;
740 u8 mask;
741 u8 data;
742 int ret;
743
744 for (lane = 0; lane < cfg->lane_count; ++lane) {
745 CHECK_RET(tegra_dc_dp_dpcd_read(dp, (lane/2) ?
746 NV_DPCD_LANE2_3_STATUS : NV_DPCD_LANE0_1_STATUS,
747 &data));
748 mask = (lane & 1) ?
749 NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES |
750 NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES |
751 NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES :
752 NV_DPCD_STATUS_LANEX_CR_DONE_YES |
753 NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES |
754 NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES;
755 if ((data & mask) != mask)
756 return -1;
757 }
758 return 0;
759}
760
Neil Chen8c440a62014-09-23 17:41:59 +0800761static int tegra_dp_channel_eq_status(struct tegra_dc_dp_data *dp)
762{
763 u32 cnt;
764 u32 n_lanes = dp->link_cfg.lane_count;
765 u8 data;
766 u8 ce_done = 1;
767
768 for (cnt = 0; cnt < n_lanes / 2; cnt++) {
769 tegra_dc_dp_dpcd_read(dp, (NV_DPCD_LANE0_1_STATUS + cnt), &data);
770
771 if (n_lanes == 1) {
772 ce_done = (data &
773 (0x1 << NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) &&
774 (data & (0x1 << NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT));
775 break;
776 } else if (!(data & (0x1 << NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) ||
777 !(data & (0x1 << NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)) ||
778 !(data & (0x1 << NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT)) ||
779 !(data & (0x1 << NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT)))
780 return 0;
781 }
782
783 if (ce_done) {
784 tegra_dc_dp_dpcd_read(dp, NV_DPCD_LANE_ALIGN_STATUS_UPDATED, &data);
785 if (!(data & NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES))
786 ce_done = 0;
787 }
788
789 return ce_done;
790}
791
792static u8 tegra_dp_clock_recovery_status(struct tegra_dc_dp_data *dp)
793{
794 u32 cnt;
795 u32 n_lanes = dp->link_cfg.lane_count;
796 u8 data_ptr;
797
798 for (cnt = 0; cnt < n_lanes / 2; cnt++) {
799 tegra_dc_dp_dpcd_read(dp,
800 (NV_DPCD_LANE0_1_STATUS + cnt), &data_ptr);
801
802 if (n_lanes == 1)
803 return (data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ? 1 : 0;
804 else if (!(data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ||
805 !(data_ptr &
806 (NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES)))
807 return 0;
808 }
809
810 return 1;
811}
812
813static void tegra_dp_lt_adjust(struct tegra_dc_dp_data *dp,
814 u32 pe[4], u32 vs[4], u32 pc[4],
815 u8 pc_supported)
816{
817 size_t cnt;
818 u8 data_ptr;
819 u32 n_lanes = dp->link_cfg.lane_count;
820
821 for (cnt = 0; cnt < n_lanes / 2; cnt++) {
822 tegra_dc_dp_dpcd_read(dp,
823 (NV_DPCD_LANE0_1_ADJUST_REQ + cnt), &data_ptr);
824 pe[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_PE_MASK) >>
825 NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT;
826 vs[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_DC_MASK) >>
827 NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT;
828 pe[1 + 2 * cnt] =
829 (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK) >>
830 NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT;
831 vs[1 + 2 * cnt] =
832 (data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK) >>
833 NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT;
834 }
835 if (pc_supported) {
836 tegra_dc_dp_dpcd_read(dp,
837 NV_DPCD_ADJUST_REQ_POST_CURSOR2, &data_ptr);
838 for (cnt = 0; cnt < n_lanes; cnt++) {
839 pc[cnt] = (data_ptr >>
840 NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(cnt)) &
841 NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK;
842 }
843 }
844}
845
846static inline u32 tegra_dp_wait_aux_training(struct tegra_dc_dp_data *dp,
847 u8 is_clk_recovery)
848{
849 if (!dp->link_cfg.aux_rd_interval)
850 is_clk_recovery ? udelay(200) :
851 udelay(500);
852 else
853 mdelay(dp->link_cfg.aux_rd_interval * 4);
854
855 return dp->link_cfg.aux_rd_interval;
856}
857
858static void tegra_dp_tpg(struct tegra_dc_dp_data *dp, u32 tp, u32 n_lanes)
859{
860 u8 data = (tp == training_pattern_disabled)
861 ? (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F)
862 : (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T);
863
864 tegra_dc_sor_set_dp_linkctl(&dp->sor, 1, tp, &dp->link_cfg);
865 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET, data);
866}
867
868static int tegra_dp_link_config(struct tegra_dc_dp_data *dp,
869 const struct tegra_dc_dp_link_config *link_cfg)
870{
871 u8 dpcd_data;
872 u32 retry;
873
874 if (link_cfg->lane_count == 0) {
875 printk(BIOS_ERR, "dp: error: lane count is 0. "
876 "Can not set link config.\n");
877 return DP_LT_FAILED;
878 }
879
880 /* Set power state if it is not in normal level */
Elyes HAOUAS4a83f1c2016-08-25 21:07:59 +0200881 if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_SET_POWER, &dpcd_data))
Neil Chen8c440a62014-09-23 17:41:59 +0800882 return DP_LT_FAILED;
883
884 if (dpcd_data == NV_DPCD_SET_POWER_VAL_D3_PWRDWN) {
885 dpcd_data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
886
887 /* DP spec requires 3 retries */
888 for (retry = 3; retry > 0; --retry){
889 if (tegra_dc_dp_dpcd_write(dp, NV_DPCD_SET_POWER, dpcd_data))
890 break;
891 if (retry == 1){
892 printk(BIOS_ERR, "dp: Failed to set DP panel power\n");
893 return DP_LT_FAILED;
894 }
895 }
896 }
897
898 /* Enable ASSR if possible */
899 if (link_cfg->alt_scramber_reset_cap)
Elyes HAOUAS4a83f1c2016-08-25 21:07:59 +0200900 if (tegra_dc_dp_set_assr(dp, 1))
Neil Chen8c440a62014-09-23 17:41:59 +0800901 return DP_LT_FAILED;
902
903 if (tegra_dp_set_link_bandwidth(dp, link_cfg->link_bw)) {
904 printk(BIOS_ERR, "dp: Failed to set link bandwidth\n");
905 return DP_LT_FAILED;
906 }
907 if (tegra_dp_set_lane_count(dp, link_cfg)) {
908 printk(BIOS_ERR, "dp: Failed to set lane count\n");
909 return DP_LT_FAILED;
910 }
911 tegra_dc_sor_set_dp_linkctl(&dp->sor, 1, training_pattern_none,
912 link_cfg);
913 return DP_LT_SUCCESS;
914}
915
916static int tegra_dp_lower_link_config(struct tegra_dc_dp_data *dp,
917 struct tegra_dc_dp_link_config *cfg)
918{
919 struct tegra_dc_dp_link_config tmp_cfg;
920
921 tmp_cfg = dp->link_cfg;
922 cfg->is_valid = 0;
923
924 if (_tegra_dp_lower_link_config(dp, cfg))
925 goto fail;
926
927 if (tegra_dc_dp_calc_config(dp, dp->dc->config, cfg))
928 goto fail;
929 tegra_dp_link_config(dp, cfg);
930
931 return DP_LT_SUCCESS;
932fail:
933 dp->link_cfg = tmp_cfg;
934 tegra_dp_link_config(dp, &tmp_cfg);
935 return DP_LT_FAILED;
936}
937
938static void tegra_dp_lt_config(struct tegra_dc_dp_data *dp,
939 u32 pe[4], u32 vs[4], u32 pc[4])
940{
941 struct tegra_dc_sor_data *sor = &dp->sor;
942 u32 n_lanes = dp->link_cfg.lane_count;
943 u8 pc_supported = dp->link_cfg.tps3_supported;
944 u32 cnt;
945 u32 val;
946
947 for (cnt = 0; cnt < n_lanes; cnt++) {
948 u32 mask = 0;
949 u32 pe_reg, vs_reg, pc_reg;
950 u32 shift = 0;
951
952 switch (cnt) {
953 case 0:
954 mask = NV_SOR_PR_LANE2_DP_LANE0_MASK;
955 shift = NV_SOR_PR_LANE2_DP_LANE0_SHIFT;
956 break;
957 case 1:
958 mask = NV_SOR_PR_LANE1_DP_LANE1_MASK;
959 shift = NV_SOR_PR_LANE1_DP_LANE1_SHIFT;
960 break;
961 case 2:
962 mask = NV_SOR_PR_LANE0_DP_LANE2_MASK;
963 shift = NV_SOR_PR_LANE0_DP_LANE2_SHIFT;
964 break;
965 case 3:
966 mask = NV_SOR_PR_LANE3_DP_LANE3_MASK;
967 shift = NV_SOR_PR_LANE3_DP_LANE3_SHIFT;
968 break;
969 default:
970 printk(BIOS_ERR,
971 "dp: incorrect lane cnt\n");
972 }
973
974 pe_reg = tegra_dp_pe_regs[pc[cnt]][vs[cnt]][pe[cnt]];
975 vs_reg = tegra_dp_vs_regs[pc[cnt]][vs[cnt]][pe[cnt]];
976 pc_reg = tegra_dp_pc_regs[pc[cnt]][vs[cnt]][pe[cnt]];
977
978 tegra_dp_set_pe_vs_pc(sor, mask, pe_reg << shift,
979 vs_reg << shift, pc_reg << shift, pc_supported);
980 }
981
982 tegra_dp_disable_tx_pu(&dp->sor);
983 udelay(20);
984
985 for (cnt = 0; cnt < n_lanes; cnt++) {
986 u32 max_vs_flag = tegra_dp_is_max_vs(pe[cnt], vs[cnt]);
987 u32 max_pe_flag = tegra_dp_is_max_pe(pe[cnt], vs[cnt]);
988
989 val = (vs[cnt] << NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT) |
990 (max_vs_flag ?
991 NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T :
992 NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F) |
993 (pe[cnt] << NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT) |
994 (max_pe_flag ?
995 NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T :
996 NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F);
997 tegra_dc_dp_dpcd_write(dp,
998 (NV_DPCD_TRAINING_LANE0_SET + cnt), val);
999 }
1000
1001 if (pc_supported) {
1002 for (cnt = 0; cnt < n_lanes / 2; cnt++) {
1003 u32 max_pc_flag0 = tegra_dp_is_max_pc(pc[cnt]);
1004 u32 max_pc_flag1 = tegra_dp_is_max_pc(pc[cnt + 1]);
1005 val = (pc[cnt] << NV_DPCD_LANEX_SET2_PC2_SHIFT) |
1006 (max_pc_flag0 ?
1007 NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T :
1008 NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F) |
1009 (pc[cnt + 1] <<
1010 NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT) |
1011 (max_pc_flag1 ?
1012 NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T :
1013 NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F);
1014 tegra_dc_dp_dpcd_write(dp,
1015 (NV_DPCD_TRAINING_LANE0_1_SET2 + cnt), val);
1016 }
1017 }
1018}
1019
1020static int _tegra_dp_channel_eq(struct tegra_dc_dp_data *dp, u32 pe[4],
1021 u32 vs[4], u32 pc[4], u8 pc_supported,
1022 u32 n_lanes)
1023{
1024 u32 retry_cnt;
1025
1026 for (retry_cnt = 0; retry_cnt < 4; retry_cnt++) {
1027 if (retry_cnt){
1028 tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported);
1029 tegra_dp_lt_config(dp, pe, vs, pc);
1030 }
1031
1032 tegra_dp_wait_aux_training(dp, 0);
1033
1034 if (!tegra_dp_clock_recovery_status(dp)) {
1035 printk(BIOS_ERR,"dp: CR failed in channel EQ sequence!\n");
1036 break;
1037 }
1038
1039 if (tegra_dp_channel_eq_status(dp))
1040 return DP_LT_SUCCESS;
1041 }
1042
1043 return DP_LT_FAILED;
1044}
1045
1046static int tegra_dp_channel_eq(struct tegra_dc_dp_data *dp,
1047 u32 pe[4], u32 vs[4], u32 pc[4])
1048{
1049 u32 n_lanes = dp->link_cfg.lane_count;
1050 u8 pc_supported = dp->link_cfg.tps3_supported;
1051 int err;
1052 u32 tp_src = training_pattern_2;
1053
1054 if (pc_supported)
1055 tp_src = training_pattern_3;
1056
1057 tegra_dp_tpg(dp, tp_src, n_lanes);
1058
1059 err = _tegra_dp_channel_eq(dp, pe, vs, pc, pc_supported, n_lanes);
1060
1061 tegra_dp_tpg(dp, training_pattern_disabled, n_lanes);
1062
1063 return err;
1064}
1065
1066static int _tegra_dp_clk_recovery(struct tegra_dc_dp_data *dp, u32 pe[4],
1067 u32 vs[4], u32 pc[4], u8 pc_supported,
1068 u32 n_lanes)
1069{
1070 u32 vs_temp[4];
1071 u32 retry_cnt = 0;
1072
1073 do {
1074 tegra_dp_lt_config(dp, pe, vs, pc);
1075 tegra_dp_wait_aux_training(dp, 1);
1076
1077 if (tegra_dp_clock_recovery_status(dp))
1078 return DP_LT_SUCCESS;
1079
1080 memcpy(vs_temp, vs, sizeof(vs_temp));
1081 tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported);
1082
1083 if (memcmp(vs_temp, vs, sizeof(vs_temp)))
1084 retry_cnt = 0;
1085 else
1086 ++retry_cnt;
1087 } while (retry_cnt < 5);
1088
1089 return DP_LT_FAILED;
1090}
1091
1092static int tegra_dp_clk_recovery(struct tegra_dc_dp_data *dp,
1093 u32 pe[4], u32 vs[4], u32 pc[4])
1094{
1095 u32 n_lanes = dp->link_cfg.lane_count;
1096 u8 pc_supported = dp->link_cfg.tps3_supported;
1097 int err;
1098
1099 tegra_dp_tpg(dp, training_pattern_1, n_lanes);
1100
1101 err = _tegra_dp_clk_recovery(dp, pe, vs, pc, pc_supported, n_lanes);
1102 if (err < 0)
1103 tegra_dp_tpg(dp, training_pattern_disabled, n_lanes);
1104
1105 return err;
1106}
1107
1108static int tegra_dc_dp_full_link_training(struct tegra_dc_dp_data *dp)
1109{
1110 struct tegra_dc_sor_data *sor = &dp->sor;
1111 int err;
1112 u32 pe[4], vs[4], pc[4];
1113
1114 tegra_sor_precharge_lanes(sor);
1115
1116retry_cr:
1117 memset(pe, preEmphasis_Disabled, sizeof(pe));
1118 memset(vs, driveCurrent_Level0, sizeof(vs));
1119 memset(pc, postCursor2_Level0, sizeof(pc));
1120
1121 err = tegra_dp_clk_recovery(dp, pe, vs, pc);
1122 if (err != DP_LT_SUCCESS) {
1123 if (!tegra_dp_lower_link_config(dp, &dp->link_cfg))
1124 goto retry_cr;
1125
1126 printk(BIOS_ERR, "dp: clk recovery failed\n");
1127 goto fail;
1128 }
1129
1130 err = tegra_dp_channel_eq(dp, pe, vs, pc);
1131 if (err != DP_LT_SUCCESS) {
1132 if (!tegra_dp_lower_link_config(dp, &dp->link_cfg))
1133 goto retry_cr;
1134
1135 printk(BIOS_ERR,
1136 "dp: channel equalization failed\n");
1137 goto fail;
1138 }
1139
1140 tegra_dc_dp_dump_link_cfg(dp, &dp->link_cfg);
1141
1142 return 0;
1143
1144fail:
1145 return err;
1146}
Jimmy Zhang75f701792014-04-21 15:58:45 -07001147/*
1148 * All link training functions are ported from kernel dc driver.
1149 * See more details at drivers/video/tegra/dc/dp.c
1150 */
1151static int tegra_dc_dp_fast_link_training(struct tegra_dc_dp_data *dp,
1152 const struct tegra_dc_dp_link_config *link_cfg)
1153{
1154 struct tegra_dc_sor_data *sor = &dp->sor;
1155 u8 link_bw;
1156 u8 lane_count;
1157 u16 data16;
1158 u32 data32;
1159 u32 size;
1160 u32 status;
1161 int j;
1162 u32 mask = 0xffff >> ((4 - link_cfg->lane_count) * 4);
1163
1164 tegra_dc_sor_set_lane_parm(sor, link_cfg);
1165 tegra_dc_dp_dpcd_write(dp, NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET,
1166 NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET_ANSI_8B10B);
1167
1168 /* Send TP1 */
1169 tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_1, link_cfg);
1170 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET,
1171 NV_DPCD_TRAINING_PATTERN_SET_TPS_TP1);
1172
1173 for (j = 0; j < link_cfg->lane_count; ++j)
1174 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_LANE0_SET + j,
1175 0x24);
1176 udelay(520);
1177
1178 size = sizeof(data16);
1179 tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
1180 NV_DPCD_LANE0_1_STATUS, (u8 *)&data16, &size, &status);
1181 status = mask & 0x1111;
1182 if ((data16 & status) != status) {
1183 printk(BIOS_ERR,
1184 "dp: Link training error for TP1 (%#x)\n", data16);
1185 return -EFAULT;
1186 }
1187
1188 /* enable ASSR */
1189 tegra_dc_dp_set_assr(dp, link_cfg->scramble_ena);
1190 tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_3, link_cfg);
1191
1192 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET,
1193 link_cfg->link_bw == 20 ? 0x23 : 0x22);
1194 for (j = 0; j < link_cfg->lane_count; ++j)
1195 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_LANE0_SET + j,
1196 0x24);
1197 udelay(520);
1198
1199 size = sizeof(data32);
1200 tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
1201 NV_DPCD_LANE0_1_STATUS, (u8 *)&data32, &size, &status);
1202 if ((data32 & mask) != (0x7777 & mask)) {
1203 printk(BIOS_ERR,
1204 "dp: Link training error for TP2/3 (0x%x)\n", data32);
1205 return -EFAULT;
1206 }
1207
1208 tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_disabled,
1209 link_cfg);
1210 tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET, 0);
1211
1212 if (tegra_dc_dp_link_trained(dp, link_cfg)) {
1213 tegra_dc_sor_read_link_config(&dp->sor, &link_bw,
1214 &lane_count);
1215 printk(BIOS_ERR,
1216 "Fast link trainging failed, link bw %d, lane # %d\n",
1217 link_bw, lane_count);
1218 return -EFAULT;
1219 }
1220
1221 printk(BIOS_INFO,
1222 "Fast link trainging succeeded, link bw %d, lane %d\n",
1223 link_cfg->link_bw, link_cfg->lane_count);
1224
1225 return 0;
1226}
1227
Neil Chen8c440a62014-09-23 17:41:59 +08001228static int tegra_dp_do_link_training(struct tegra_dc_dp_data *dp,
Jimmy Zhang75f701792014-04-21 15:58:45 -07001229 const struct tegra_dc_dp_link_config *link_cfg)
1230{
Jimmy Zhang75f701792014-04-21 15:58:45 -07001231 u8 link_bw;
1232 u8 lane_count;
Jimmy Zhang75f701792014-04-21 15:58:45 -07001233 int ret;
1234
Jimmy Zhang75f701792014-04-21 15:58:45 -07001235 /* Now do the fast link training for eDP */
1236 ret = tegra_dc_dp_fast_link_training(dp, link_cfg);
1237 if (ret) {
1238 printk(BIOS_ERR, "dp: fast link training failed\n");
Neil Chen8c440a62014-09-23 17:41:59 +08001239
1240 /* Try full link training then */
1241 if (tegra_dc_dp_full_link_training(dp)){
1242 printk(BIOS_ERR, "dp: full link training failed\n");
1243 return ret;
1244 }
Neil Chenac4fef82014-09-24 10:41:08 +08001245 } else {
1246 /* set to a known-good drive setting if fast link succeeded */
1247 tegra_dc_sor_set_voltage_swing(&dp->sor);
Jimmy Zhang75f701792014-04-21 15:58:45 -07001248 }
1249
1250 /* Everything goes well, double check the link config */
1251 /* TODO: record edc/c2 data for debugging */
1252 tegra_dc_sor_read_link_config(&dp->sor, &link_bw, &lane_count);
1253
1254 if ((link_cfg->link_bw == link_bw) &&
1255 (link_cfg->lane_count == lane_count))
1256 return 0;
1257 else
1258 return -EFAULT;
1259}
1260
1261static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp,
1262 struct tegra_dc_dp_link_config *link_cfg,
1263 const struct soc_nvidia_tegra124_config *config)
1264{
1265 struct tegra_dc_dp_link_config temp_cfg;
1266
1267 if (!config->pixel_clock || !config->xres || !config->yres) {
1268 printk(BIOS_ERR,
1269 "dp: error mode configuration");
1270 return -EINVAL;
1271 }
1272 if (!link_cfg->max_link_bw || !link_cfg->max_lane_count) {
1273 printk(BIOS_ERR,
1274 "dp: error link configuration");
1275 return -EINVAL;
1276 }
1277
1278 link_cfg->is_valid = 0;
1279
1280 memcpy(&temp_cfg, link_cfg, sizeof(temp_cfg));
1281
1282 temp_cfg.link_bw = temp_cfg.max_link_bw;
1283 temp_cfg.lane_count = temp_cfg.max_lane_count;
1284
1285 /*
1286 * set to max link config
1287 */
1288 if ((!tegra_dc_dp_calc_config(dp, config, &temp_cfg)) &&
Neil Chen8c440a62014-09-23 17:41:59 +08001289 (!tegra_dp_link_config(dp, &temp_cfg)) &&
1290 (!tegra_dp_do_link_training(dp, &temp_cfg)))
Jimmy Zhang75f701792014-04-21 15:58:45 -07001291 /* the max link cfg is doable */
1292 memcpy(link_cfg, &temp_cfg, sizeof(temp_cfg));
1293
1294 return link_cfg->is_valid ? 0 : -EFAULT;
1295}
1296
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001297static void tegra_dp_update_config(struct tegra_dc_dp_data *dp,
1298 struct soc_nvidia_tegra124_config *config)
1299{
1300 struct edid edid;
1301 u8 buf[128] = {0};
1302 u32 size = sizeof(buf), aux_stat = 0;
1303
1304 tegra_dc_dpaux_enable(dp);
1305 if (tegra_dc_i2c_aux_read(dp, TEGRA_EDID_I2C_ADDRESS, 0, buf, &size,
1306 &aux_stat)) {
1307 printk(BIOS_ERR, "%s: Failed to read EDID. Use defaults.\n",
1308 __func__);
1309 return;
1310 }
1311
Arthur Heymans8c5884e2017-04-30 08:28:05 +02001312 if (decode_edid(buf, sizeof(buf), &edid) != EDID_CONFORMANT) {
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001313 printk(BIOS_ERR, "%s: Failed to decode EDID. Use defaults.\n",
1314 __func__);
1315 return;
1316 }
1317
David Hendricks7dbf9c62015-07-30 18:49:48 -07001318 config->xres = edid.mode.ha;
1319 config->yres = edid.mode.va;
1320 config->pixel_clock = edid.mode.pixel_clock * 1000;
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001321
David Hendricks7dbf9c62015-07-30 18:49:48 -07001322 config->hfront_porch = edid.mode.hso;
1323 config->hsync_width = edid.mode.hspw;
1324 config->hback_porch = edid.mode.hbl - edid.mode.hso - edid.mode.hspw;
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001325
David Hendricks7dbf9c62015-07-30 18:49:48 -07001326 config->vfront_porch = edid.mode.vso;
1327 config->vsync_width = edid.mode.vspw;
1328 config->vback_porch = edid.mode.vbl - edid.mode.vso - edid.mode.vspw;
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001329
1330 /**
1331 * Note edid->framebuffer_bits_per_pixel is currently hard-coded as 32,
1332 * so we should keep the default value in device config.
1333 *
1334 * EDID v1.3 panels may not have color depth info, so we need to check
1335 * if these values are zero before updating config.
1336 */
1337 if (edid.panel_bits_per_pixel)
1338 config->panel_bits_per_pixel = edid.panel_bits_per_pixel;
1339 if (edid.panel_bits_per_color)
1340 config->color_depth = edid.panel_bits_per_color;
1341 printk(BIOS_SPEW, "%s: configuration updated by EDID.\n", __func__);
1342}
1343
Elyes HAOUAS39303d52018-07-08 12:40:45 +02001344void dp_init(void *_config)
Julius Werneredf6b572013-10-25 17:49:26 -07001345{
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001346 struct soc_nvidia_tegra124_config *config = (void *)_config;
1347 struct tegra_dc *dc = config->dc_data;
Julius Werneredf6b572013-10-25 17:49:26 -07001348 struct tegra_dc_dp_data *dp = &dp_data;
1349
Elyes HAOUAS88607a42018-10-05 10:36:45 +02001350 // set up links among config, dc, dp and sor
1351 dp->dc = dc;
1352 dc->out = dp;
1353 dp->sor.dc = dc;
Julius Werneredf6b572013-10-25 17:49:26 -07001354
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001355 dp->sor.power_is_up = 0;
Julius Werneredf6b572013-10-25 17:49:26 -07001356 dp->sor.base = (void *)TEGRA_ARM_SOR;
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001357 dp->sor.pmc_base = (void *)TEGRA_PMC_BASE;
Julius Werneredf6b572013-10-25 17:49:26 -07001358 dp->sor.portnum = 0;
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001359 dp->sor.link_cfg = &dp->link_cfg;
Julius Werneredf6b572013-10-25 17:49:26 -07001360 dp->aux_base = (void *)TEGRA_ARM_DPAUX;
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001361 dp->link_cfg.is_valid = 0;
1362 dp->enabled = 0;
Hung-Te Lin3af0d312014-04-02 21:57:40 +08001363
1364 tegra_dp_update_config(dp, config);
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001365}
Julius Werneredf6b572013-10-25 17:49:26 -07001366
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001367static void tegra_dp_hpd_config(struct tegra_dc_dp_data *dp,
1368 struct soc_nvidia_tegra124_config *config)
1369{
1370 u32 val;
1371
1372 val = config->hpd_plug_min_us |
1373 (config->hpd_unplug_min_us <<
1374 DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME_SHIFT);
1375 tegra_dpaux_writel(dp, DPAUX_HPD_CONFIG, val);
1376
1377 tegra_dpaux_writel(dp, DPAUX_HPD_IRQ_CONFIG, config->hpd_irq_min_us);
1378}
1379
1380static int tegra_dp_hpd_plug(struct tegra_dc_dp_data *dp, int timeout_ms)
1381{
1382 u32 val;
1383 u32 timeout = timeout_ms * 1000;
1384 do {
1385 val = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
1386 if (val & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)
1387 return 0;
1388 udelay(100);
1389 timeout -= 100;
1390 } while (timeout > 0);
1391 return -1;
1392}
1393
Elyes HAOUAS39303d52018-07-08 12:40:45 +02001394void dp_enable(void *_dp)
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001395{
1396 struct tegra_dc_dp_data *dp = _dp;
1397 struct tegra_dc *dc = dp->dc;
1398 struct soc_nvidia_tegra124_config *config = dc->config;
1399
1400 u8 data;
1401 u32 retry;
1402 int ret;
1403
1404 tegra_dc_dpaux_enable(dp);
1405
1406 tegra_dp_hpd_config(dp, config);
1407 if (tegra_dp_hpd_plug(dp, config->vdd_to_hpd_delay_ms) < 0) {
1408 printk(BIOS_ERR, "dp: hpd plug failed\n");
1409 goto error_enable;
Julius Werneredf6b572013-10-25 17:49:26 -07001410 }
1411
Jimmy Zhang75f701792014-04-21 15:58:45 -07001412 if (tegra_dc_dp_init_max_link_cfg(config, dp, &dp->link_cfg)) {
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -08001413 printk(BIOS_ERR, "dp: failed to init link configuration\n");
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001414 goto error_enable;
Elyes HAOUAS88607a42018-10-05 10:36:45 +02001415 }
Julius Werneredf6b572013-10-25 17:49:26 -07001416
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001417 tegra_dc_sor_enable_dp(&dp->sor);
Julius Werneredf6b572013-10-25 17:49:26 -07001418
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001419 tegra_dc_sor_set_panel_power(&dp->sor, 1);
Julius Werneredf6b572013-10-25 17:49:26 -07001420
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001421 /* Write power on to DPCD */
1422 data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
1423 retry = 0;
1424 do {
1425 ret = tegra_dc_dp_dpcd_write(dp,
1426 NV_DPCD_SET_POWER, data);
1427 } while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret);
Andrew Bresticker24d4f7f2013-12-18 22:41:34 -08001428
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001429 if (ret || retry >= DP_POWER_ON_MAX_TRIES) {
1430 printk(BIOS_ERR,
1431 "dp: failed to power on panel (0x%x)\n", ret);
1432 goto error_enable;
Julius Werneredf6b572013-10-25 17:49:26 -07001433 }
1434
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001435 /* Confirm DP is plugging status */
1436 if (!(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) &
1437 DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
1438 printk(BIOS_ERR, "dp: could not detect HPD\n");
1439 goto error_enable;
Julius Werneredf6b572013-10-25 17:49:26 -07001440 }
1441
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001442 /* Check DP version */
1443 if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision))
1444 printk(BIOS_ERR,
1445 "dp: failed to read the revision number from sink\n");
Julius Werneredf6b572013-10-25 17:49:26 -07001446
Jimmy Zhang75f701792014-04-21 15:58:45 -07001447 if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, config)) {
1448 printk(BIOS_ERR, "dp: error to configure link\n");
1449 goto error_enable;
1450 }
1451
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001452 tegra_dc_sor_set_power_state(&dp->sor, 1);
1453 tegra_dc_sor_attach(&dp->sor);
Julius Werneredf6b572013-10-25 17:49:26 -07001454
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001455 /*
1456 * Power down the unused lanes to save power
1457 * (about hundreds milli-watts, varies from boards).
1458 */
1459 tegra_dc_sor_power_down_unused_lanes(&dp->sor);
Julius Werneredf6b572013-10-25 17:49:26 -07001460
Jimmy Zhangbd5925a2014-03-10 12:42:05 -07001461 dp->enabled = 1;
1462error_enable:
1463 return;
Julius Werneredf6b572013-10-25 17:49:26 -07001464}