blob: 8dc3df61aad14c88dce594740af221f0486478e0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Simon Glassf4f5cfa2015-04-14 21:03:40 -06002/*
3 * Copyright (c) 2011-2013, NVIDIA Corporation.
Simon Glassf4f5cfa2015-04-14 21:03:40 -06004 */
5
6#include <common.h>
Simon Glassfad72182016-01-30 16:37:50 -07007#include <dm.h>
Simon Glassf4f5cfa2015-04-14 21:03:40 -06008#include <errno.h>
Simon Glassf4f5cfa2015-04-14 21:03:40 -06009#include <malloc.h>
Simon Glassfad72182016-01-30 16:37:50 -070010#include <panel.h>
Simon Glass5eb75402017-07-25 08:30:01 -060011#include <syscon.h>
Simon Glassfad72182016-01-30 16:37:50 -070012#include <video_bridge.h>
Simon Glassf4f5cfa2015-04-14 21:03:40 -060013#include <asm/io.h>
14#include <asm/arch/clock.h>
15#include <asm/arch-tegra/dc.h>
16#include "displayport.h"
17#include "sor.h"
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glassf4f5cfa2015-04-14 21:03:40 -060019
Simon Glassf4f5cfa2015-04-14 21:03:40 -060020#define DEBUG_SOR 0
21
22#define APBDEV_PMC_DPD_SAMPLE 0x20
23#define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE 0
24#define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE 1
25#define APBDEV_PMC_SEL_DPD_TIM 0x1c8
26#define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT 0x7f
27#define APBDEV_PMC_IO_DPD2_REQ 0x1c0
28#define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT 25
29#define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF (0 << 25)
30#define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON (1 << 25)
31#define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT 30
32#define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK (0x3 << 30)
33#define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE (0 << 30)
34#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF (1 << 30)
35#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON (2 << 30)
36#define APBDEV_PMC_IO_DPD2_STATUS 0x1c4
37#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT 25
38#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25)
39#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25)
40
Simon Glassfad72182016-01-30 16:37:50 -070041struct tegra_dc_sor_data {
42 void *base;
43 void *pmc_base;
44 u8 portnum; /* 0 or 1 */
45 int power_is_up;
46 struct udevice *panel;
47};
48
Simon Glassf4f5cfa2015-04-14 21:03:40 -060049static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg)
50{
51 return readl((u32 *)sor->base + reg);
52}
53
54static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor, u32 reg,
55 u32 val)
56{
57 writel(val, (u32 *)sor->base + reg);
58}
59
60static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
61 u32 reg, u32 mask, u32 val)
62{
63 u32 reg_val = tegra_sor_readl(sor, reg);
64 reg_val &= ~mask;
65 reg_val |= val;
66 tegra_sor_writel(sor, reg, reg_val);
67}
68
Simon Glassfad72182016-01-30 16:37:50 -070069void tegra_dp_disable_tx_pu(struct udevice *dev)
Simon Glass662f2aa2015-04-14 21:03:44 -060070{
Simon Glassfad72182016-01-30 16:37:50 -070071 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
72
Simon Glass662f2aa2015-04-14 21:03:44 -060073 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
74 DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE);
75}
76
Simon Glassfad72182016-01-30 16:37:50 -070077void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg,
Simon Glass662f2aa2015-04-14 21:03:44 -060078 u32 vs_reg, u32 pc_reg, u8 pc_supported)
79{
Simon Glassfad72182016-01-30 16:37:50 -070080 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
81
Simon Glass662f2aa2015-04-14 21:03:44 -060082 tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg);
83 tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg);
84 if (pc_supported) {
85 tegra_sor_write_field(sor, POSTCURSOR(sor->portnum), mask,
86 pc_reg);
87 }
88}
89
Simon Glassf4f5cfa2015-04-14 21:03:40 -060090static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg,
91 u32 mask, u32 exp_val,
92 int poll_interval_us, int timeout_ms)
93{
94 u32 reg_val = 0;
95 ulong start;
96
97 start = get_timer(0);
98 do {
99 reg_val = tegra_sor_readl(sor, reg);
100 if (((reg_val & mask) == exp_val))
101 return 0;
102 udelay(poll_interval_us);
103 } while (get_timer(start) < timeout_ms);
104
105 debug("sor_poll_register 0x%x: timeout, (reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n",
106 reg, reg_val, mask, exp_val);
107
108 return -ETIMEDOUT;
109}
110
Simon Glassfad72182016-01-30 16:37:50 -0700111int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600112{
Simon Glassfad72182016-01-30 16:37:50 -0700113 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600114 u32 reg_val;
115 u32 orig_val;
116
117 orig_val = tegra_sor_readl(sor, PWR);
118
119 reg_val = pu_pd ? PWR_NORMAL_STATE_PU :
120 PWR_NORMAL_STATE_PD; /* normal state only */
121
122 if (reg_val == orig_val)
123 return 0; /* No update needed */
124
125 reg_val |= PWR_SETTING_NEW_TRIGGER;
126 tegra_sor_writel(sor, PWR, reg_val);
127
128 /* Poll to confirm it is done */
129 if (tegra_dc_sor_poll_register(sor, PWR,
130 PWR_SETTING_NEW_DEFAULT_MASK,
131 PWR_SETTING_NEW_DONE,
132 100, TEGRA_SOR_TIMEOUT_MS)) {
133 debug("dc timeout waiting for SOR_PWR = NEW_DONE\n");
134 return -EFAULT;
135 }
136
137 return 0;
138}
139
Simon Glassfad72182016-01-30 16:37:50 -0700140void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600141 u8 training_pattern,
142 const struct tegra_dp_link_config *link_cfg)
143{
Simon Glassfad72182016-01-30 16:37:50 -0700144 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600145 u32 reg_val;
146
147 reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum));
148
149 if (ena)
150 reg_val |= DP_LINKCTL_ENABLE_YES;
151 else
152 reg_val &= DP_LINKCTL_ENABLE_NO;
153
154 reg_val &= ~DP_LINKCTL_TUSIZE_MASK;
155 reg_val |= (link_cfg->tu_size << DP_LINKCTL_TUSIZE_SHIFT);
156
157 if (link_cfg->enhanced_framing)
158 reg_val |= DP_LINKCTL_ENHANCEDFRAME_ENABLE;
159
160 tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val);
161
162 switch (training_pattern) {
163 case training_pattern_1:
164 tegra_sor_writel(sor, DP_TPG, 0x41414141);
165 break;
166 case training_pattern_2:
167 case training_pattern_3:
168 reg_val = (link_cfg->link_bw == SOR_LINK_SPEED_G5_4) ?
169 0x43434343 : 0x42424242;
170 tegra_sor_writel(sor, DP_TPG, reg_val);
171 break;
172 default:
173 tegra_sor_writel(sor, DP_TPG, 0x50505050);
174 break;
175 }
176}
177
178static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor,
179 int pu, int is_lvds)
180{
181 u32 reg_val;
182
183 /* SOR lane sequencer */
184 if (pu) {
185 reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
186 LANE_SEQ_CTL_SEQUENCE_DOWN |
187 LANE_SEQ_CTL_NEW_POWER_STATE_PU;
188 } else {
189 reg_val = LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
190 LANE_SEQ_CTL_SEQUENCE_UP |
191 LANE_SEQ_CTL_NEW_POWER_STATE_PD;
192 }
193
194 if (is_lvds)
195 reg_val |= 15 << LANE_SEQ_CTL_DELAY_SHIFT;
196 else
197 reg_val |= 1 << LANE_SEQ_CTL_DELAY_SHIFT;
198
199 tegra_sor_writel(sor, LANE_SEQ_CTL, reg_val);
200
201 if (tegra_dc_sor_poll_register(sor, LANE_SEQ_CTL,
202 LANE_SEQ_CTL_SETTING_MASK,
203 LANE_SEQ_CTL_SETTING_NEW_DONE,
204 100, TEGRA_SOR_TIMEOUT_MS)) {
205 debug("dp: timeout while waiting for SOR lane sequencer to power down lanes\n");
206 return -1;
207 }
208
209 return 0;
210}
211
Simon Glassfad72182016-01-30 16:37:50 -0700212static int tegra_dc_sor_power_dplanes(struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600213 u32 lane_count, int pu)
214{
Simon Glassfad72182016-01-30 16:37:50 -0700215 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600216 u32 reg_val;
217
218 reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
219
220 if (pu) {
221 switch (lane_count) {
222 case 4:
223 reg_val |= (DP_PADCTL_PD_TXD_3_NO |
224 DP_PADCTL_PD_TXD_2_NO);
225 /* fall through */
226 case 2:
227 reg_val |= DP_PADCTL_PD_TXD_1_NO;
228 case 1:
229 reg_val |= DP_PADCTL_PD_TXD_0_NO;
230 break;
231 default:
232 debug("dp: invalid lane number %d\n", lane_count);
233 return -1;
234 }
235
236 tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val);
Simon Glassfad72182016-01-30 16:37:50 -0700237 tegra_dc_sor_set_lane_count(dev, lane_count);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600238 }
239
240 return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0);
241}
242
Simon Glassfad72182016-01-30 16:37:50 -0700243void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600244{
Simon Glassfad72182016-01-30 16:37:50 -0700245 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600246 u32 reg_val;
247
248 reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
249
250 if (power_up)
251 reg_val |= DP_PADCTL_PAD_CAL_PD_POWERUP;
252 else
253 reg_val &= ~DP_PADCTL_PAD_CAL_PD_POWERUP;
254
255 tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val);
256}
257
258static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div,
259 u32 pwm_dutycycle)
260{
261 tegra_sor_writel(sor, PWM_DIV, pwm_div);
262 tegra_sor_writel(sor, PWM_CTL,
263 (pwm_dutycycle & PWM_CTL_DUTY_CYCLE_MASK) |
264 PWM_CTL_SETTING_NEW_TRIGGER);
265
266 if (tegra_dc_sor_poll_register(sor, PWM_CTL,
267 PWM_CTL_SETTING_NEW_SHIFT,
268 PWM_CTL_SETTING_NEW_DONE,
269 100, TEGRA_SOR_TIMEOUT_MS)) {
270 debug("dp: timeout while waiting for SOR PWM setting\n");
271 }
272}
273
Simon Glassfad72182016-01-30 16:37:50 -0700274static void tegra_dc_sor_set_dp_mode(struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600275 const struct tegra_dp_link_config *link_cfg)
276{
Simon Glassfad72182016-01-30 16:37:50 -0700277 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600278 u32 reg_val;
279
Simon Glassfad72182016-01-30 16:37:50 -0700280 tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600281
Simon Glassfad72182016-01-30 16:37:50 -0700282 tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600283 reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum));
284 reg_val &= ~DP_CONFIG_WATERMARK_MASK;
285 reg_val |= link_cfg->watermark;
286 reg_val &= ~DP_CONFIG_ACTIVESYM_COUNT_MASK;
287 reg_val |= (link_cfg->active_count <<
288 DP_CONFIG_ACTIVESYM_COUNT_SHIFT);
289 reg_val &= ~DP_CONFIG_ACTIVESYM_FRAC_MASK;
290 reg_val |= (link_cfg->active_frac <<
291 DP_CONFIG_ACTIVESYM_FRAC_SHIFT);
292 if (link_cfg->activepolarity)
293 reg_val |= DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
294 else
295 reg_val &= ~DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
296 reg_val |= (DP_CONFIG_ACTIVESYM_CNTL_ENABLE |
297 DP_CONFIG_RD_RESET_VAL_NEGATIVE);
298
299 tegra_sor_writel(sor, DP_CONFIG(sor->portnum), reg_val);
300
301 /* program h/vblank sym */
302 tegra_sor_write_field(sor, DP_AUDIO_HBLANK_SYMBOLS,
303 DP_AUDIO_HBLANK_SYMBOLS_MASK,
304 link_cfg->hblank_sym);
305
306 tegra_sor_write_field(sor, DP_AUDIO_VBLANK_SYMBOLS,
307 DP_AUDIO_VBLANK_SYMBOLS_MASK,
308 link_cfg->vblank_sym);
309}
310
311static inline void tegra_dc_sor_super_update(struct tegra_dc_sor_data *sor)
312{
313 tegra_sor_writel(sor, SUPER_STATE0, 0);
314 tegra_sor_writel(sor, SUPER_STATE0, 1);
315 tegra_sor_writel(sor, SUPER_STATE0, 0);
316}
317
318static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor)
319{
320 tegra_sor_writel(sor, STATE0, 0);
321 tegra_sor_writel(sor, STATE0, 1);
322 tegra_sor_writel(sor, STATE0, 0);
323}
324
325static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up)
326{
327 u32 reg_val;
328 void *pmc_base = sor->pmc_base;
329
330 if (up) {
331 writel(APBDEV_PMC_DPD_SAMPLE_ON_ENABLE,
332 pmc_base + APBDEV_PMC_DPD_SAMPLE);
333 writel(10, pmc_base + APBDEV_PMC_SEL_DPD_TIM);
334 }
335
336 reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ);
337 reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON ||
338 APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK);
339
340 reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON |
341 APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF :
342 APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF |
343 APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON;
344
345 writel(reg_val, pmc_base + APBDEV_PMC_IO_DPD2_REQ);
346
347 /* Polling */
348 u32 temp = 10 * 1000;
349 do {
350 udelay(20);
351 reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_STATUS);
352 if (temp > 20)
353 temp -= 20;
354 else
355 break;
356 } while ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0);
357
358 if ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0) {
359 debug("PMC_IO_DPD2 polling failed (0x%x)\n", reg_val);
360 return -EIO;
361 }
362
363 if (up) {
364 writel(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE,
365 pmc_base + APBDEV_PMC_DPD_SAMPLE);
366 }
367
368 return 0;
369}
370
Simon Glassfad72182016-01-30 16:37:50 -0700371void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600372{
Simon Glassfad72182016-01-30 16:37:50 -0700373 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600374 u32 reg_val;
375
376 reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum));
377 if (is_int)
378 reg_val |= DP_SPARE_PANEL_INTERNAL;
379 else
380 reg_val &= ~DP_SPARE_PANEL_INTERNAL;
381
382 reg_val |= DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK |
383 DP_SPARE_SEQ_ENABLE_YES;
384 tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val);
385}
386
Simon Glassfad72182016-01-30 16:37:50 -0700387void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600388 u8 *lane_count)
389{
Simon Glassfad72182016-01-30 16:37:50 -0700390 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600391 u32 reg_val;
392
393 reg_val = tegra_sor_readl(sor, CLK_CNTRL);
394 *link_bw = (reg_val & CLK_CNTRL_DP_LINK_SPEED_MASK)
395 >> CLK_CNTRL_DP_LINK_SPEED_SHIFT;
396 reg_val = tegra_sor_readl(sor,
397 DP_LINKCTL(sor->portnum));
398
399 switch (reg_val & DP_LINKCTL_LANECOUNT_MASK) {
400 case DP_LINKCTL_LANECOUNT_ZERO:
401 *lane_count = 0;
402 break;
403 case DP_LINKCTL_LANECOUNT_ONE:
404 *lane_count = 1;
405 break;
406 case DP_LINKCTL_LANECOUNT_TWO:
407 *lane_count = 2;
408 break;
409 case DP_LINKCTL_LANECOUNT_FOUR:
410 *lane_count = 4;
411 break;
412 default:
413 printf("Unknown lane count\n");
414 }
415}
416
Simon Glassfad72182016-01-30 16:37:50 -0700417void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600418{
Simon Glassfad72182016-01-30 16:37:50 -0700419 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
420
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600421 tegra_sor_write_field(sor, CLK_CNTRL,
422 CLK_CNTRL_DP_LINK_SPEED_MASK,
423 link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT);
424}
425
Simon Glassfad72182016-01-30 16:37:50 -0700426void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600427{
Simon Glassfad72182016-01-30 16:37:50 -0700428 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600429 u32 reg_val;
430
431 reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum));
432 reg_val &= ~DP_LINKCTL_LANECOUNT_MASK;
433 switch (lane_count) {
434 case 0:
435 break;
436 case 1:
437 reg_val |= DP_LINKCTL_LANECOUNT_ONE;
438 break;
439 case 2:
440 reg_val |= DP_LINKCTL_LANECOUNT_TWO;
441 break;
442 case 4:
443 reg_val |= DP_LINKCTL_LANECOUNT_FOUR;
444 break;
445 default:
446 /* 0 should be handled earlier. */
447 printf("dp: Invalid lane count %d\n", lane_count);
448 return;
449 }
450 tegra_sor_writel(sor, DP_LINKCTL(sor->portnum), reg_val);
451}
452
453/*
454 * The SOR power sequencer does not work for t124 so SW has to
455 * go through the power sequence manually
456 * Power up steps from spec:
457 * STEP PDPORT PDPLL PDBG PLLVCOD PLLCAPD E_DPD PDCAL
458 * 1 1 1 1 1 1 1 1
459 * 2 1 1 1 1 1 0 1
460 * 3 1 1 0 1 1 0 1
461 * 4 1 0 0 0 0 0 1
462 * 5 0 0 0 0 0 0 1
463 */
Simon Glassfad72182016-01-30 16:37:50 -0700464static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds)
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600465{
Simon Glassfad72182016-01-30 16:37:50 -0700466 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassd1536e32017-05-31 17:57:20 -0600467 u32 reg;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600468 int ret;
469
470 if (sor->power_is_up)
471 return 0;
472
Simon Glassd1536e32017-05-31 17:57:20 -0600473 /*
474 * If for some reason it is already powered up, don't do it again.
475 * This can happen if U-Boot is the secondary boot loader.
476 */
477 reg = tegra_sor_readl(sor, DP_PADCTL(sor->portnum));
478 if (reg & DP_PADCTL_PD_TXD_0_NO)
479 return 0;
480
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600481 /* Set link bw */
Simon Glassfad72182016-01-30 16:37:50 -0700482 tegra_dc_sor_set_link_bandwidth(dev, is_lvds ?
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600483 CLK_CNTRL_DP_LINK_SPEED_LVDS :
484 CLK_CNTRL_DP_LINK_SPEED_G1_62);
485
486 /* step 1 */
487 tegra_sor_write_field(sor, PLL2,
488 PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */
489 PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */
490 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
491 PLL2_AUX7_PORT_POWERDOWN_ENABLE |
492 PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE |
493 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE);
494 tegra_sor_write_field(sor, PLL0, PLL0_PWR_MASK | /* PDPLL */
495 PLL0_VCOPD_MASK, /* PLLVCOPD */
496 PLL0_PWR_OFF | PLL0_VCOPD_ASSERT);
497 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
498 DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */
499 DP_PADCTL_PAD_CAL_PD_POWERDOWN);
500
501 /* step 2 */
502 ret = tegra_dc_sor_io_set_dpd(sor, 1);
503 if (ret)
504 return ret;
505 udelay(15);
506
507 /* step 3 */
508 tegra_sor_write_field(sor, PLL2,
509 PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
510 PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
511 udelay(25);
512
513 /* step 4 */
514 tegra_sor_write_field(sor, PLL0,
515 PLL0_PWR_MASK | /* PDPLL */
516 PLL0_VCOPD_MASK, /* PLLVCOPD */
517 PLL0_PWR_ON | PLL0_VCOPD_RESCIND);
518 /* PLLCAPD */
519 tegra_sor_write_field(sor, PLL2,
520 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
521 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
522 udelay(225);
523
524 /* step 5 PDPORT */
525 tegra_sor_write_field(sor, PLL2,
526 PLL2_AUX7_PORT_POWERDOWN_MASK,
527 PLL2_AUX7_PORT_POWERDOWN_DISABLE);
528
529 sor->power_is_up = 1;
530
531 return 0;
532}
533
534#if DEBUG_SOR
535static void dump_sor_reg(struct tegra_dc_sor_data *sor)
536{
Simon Glass126f0d22018-10-01 12:22:42 -0600537#define DUMP_REG(a) printk(BIOS_INFO, \
538 "%-32s %03x %08x\n", \
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600539 #a, a, tegra_sor_readl(sor, a));
540
541 DUMP_REG(SUPER_STATE0);
542 DUMP_REG(SUPER_STATE1);
543 DUMP_REG(STATE0);
544 DUMP_REG(STATE1);
545 DUMP_REG(NV_HEAD_STATE0(0));
546 DUMP_REG(NV_HEAD_STATE0(1));
547 DUMP_REG(NV_HEAD_STATE1(0));
548 DUMP_REG(NV_HEAD_STATE1(1));
549 DUMP_REG(NV_HEAD_STATE2(0));
550 DUMP_REG(NV_HEAD_STATE2(1));
551 DUMP_REG(NV_HEAD_STATE3(0));
552 DUMP_REG(NV_HEAD_STATE3(1));
553 DUMP_REG(NV_HEAD_STATE4(0));
554 DUMP_REG(NV_HEAD_STATE4(1));
555 DUMP_REG(NV_HEAD_STATE5(0));
556 DUMP_REG(NV_HEAD_STATE5(1));
557 DUMP_REG(CRC_CNTRL);
558 DUMP_REG(CLK_CNTRL);
559 DUMP_REG(CAP);
560 DUMP_REG(PWR);
561 DUMP_REG(TEST);
562 DUMP_REG(PLL0);
563 DUMP_REG(PLL1);
564 DUMP_REG(PLL2);
565 DUMP_REG(PLL3);
566 DUMP_REG(CSTM);
567 DUMP_REG(LVDS);
568 DUMP_REG(CRCA);
569 DUMP_REG(CRCB);
570 DUMP_REG(SEQ_CTL);
571 DUMP_REG(LANE_SEQ_CTL);
572 DUMP_REG(SEQ_INST(0));
573 DUMP_REG(SEQ_INST(1));
574 DUMP_REG(SEQ_INST(2));
575 DUMP_REG(SEQ_INST(3));
576 DUMP_REG(SEQ_INST(4));
577 DUMP_REG(SEQ_INST(5));
578 DUMP_REG(SEQ_INST(6));
579 DUMP_REG(SEQ_INST(7));
580 DUMP_REG(SEQ_INST(8));
581 DUMP_REG(PWM_DIV);
582 DUMP_REG(PWM_CTL);
583 DUMP_REG(MSCHECK);
584 DUMP_REG(XBAR_CTRL);
585 DUMP_REG(DP_LINKCTL(0));
586 DUMP_REG(DP_LINKCTL(1));
587 DUMP_REG(DC(0));
588 DUMP_REG(DC(1));
589 DUMP_REG(LANE_DRIVE_CURRENT(0));
590 DUMP_REG(PR(0));
591 DUMP_REG(LANE4_PREEMPHASIS(0));
592 DUMP_REG(POSTCURSOR(0));
593 DUMP_REG(DP_CONFIG(0));
594 DUMP_REG(DP_CONFIG(1));
595 DUMP_REG(DP_MN(0));
596 DUMP_REG(DP_MN(1));
597 DUMP_REG(DP_PADCTL(0));
598 DUMP_REG(DP_PADCTL(1));
599 DUMP_REG(DP_DEBUG(0));
600 DUMP_REG(DP_DEBUG(1));
601 DUMP_REG(DP_SPARE(0));
602 DUMP_REG(DP_SPARE(1));
603 DUMP_REG(DP_TPG);
604
605 return;
606}
607#endif
608
609static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
610 int is_lvds,
611 const struct tegra_dp_link_config *link_cfg,
612 const struct display_timing *timing)
613{
614 const int head_num = 0;
615 u32 reg_val = STATE1_ASY_OWNER_HEAD0 << head_num;
616 u32 vtotal, htotal;
617 u32 vsync_end, hsync_end;
618 u32 vblank_end, hblank_end;
619 u32 vblank_start, hblank_start;
620
621 reg_val |= is_lvds ? STATE1_ASY_PROTOCOL_LVDS_CUSTOM :
622 STATE1_ASY_PROTOCOL_DP_A;
623 reg_val |= STATE1_ASY_SUBOWNER_NONE |
624 STATE1_ASY_CRCMODE_COMPLETE_RASTER;
625
626 reg_val |= STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE;
627 reg_val |= STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE;
628 reg_val |= (link_cfg->bits_per_pixel > 18) ?
629 STATE1_ASY_PIXELDEPTH_BPP_24_444 :
630 STATE1_ASY_PIXELDEPTH_BPP_18_444;
631
632 tegra_sor_writel(sor, STATE1, reg_val);
633
634 /*
635 * Skipping programming NV_HEAD_STATE0, assuming:
636 * interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB
637 */
638 vtotal = timing->vsync_len.typ + timing->vback_porch.typ +
639 timing->vactive.typ + timing->vfront_porch.typ;
640 htotal = timing->hsync_len.typ + timing->hback_porch.typ +
641 timing->hactive.typ + timing->hfront_porch.typ;
642
643 tegra_sor_writel(sor, NV_HEAD_STATE1(head_num),
644 vtotal << NV_HEAD_STATE1_VTOTAL_SHIFT |
645 htotal << NV_HEAD_STATE1_HTOTAL_SHIFT);
646
647 vsync_end = timing->vsync_len.typ - 1;
648 hsync_end = timing->hsync_len.typ - 1;
649 tegra_sor_writel(sor, NV_HEAD_STATE2(head_num),
650 vsync_end << NV_HEAD_STATE2_VSYNC_END_SHIFT |
651 hsync_end << NV_HEAD_STATE2_HSYNC_END_SHIFT);
652
653 vblank_end = vsync_end + timing->vback_porch.typ;
654 hblank_end = hsync_end + timing->hback_porch.typ;
655 tegra_sor_writel(sor, NV_HEAD_STATE3(head_num),
656 vblank_end << NV_HEAD_STATE3_VBLANK_END_SHIFT |
657 hblank_end << NV_HEAD_STATE3_HBLANK_END_SHIFT);
658
659 vblank_start = vblank_end + timing->vactive.typ;
660 hblank_start = hblank_end + timing->hactive.typ;
661 tegra_sor_writel(sor, NV_HEAD_STATE4(head_num),
662 vblank_start << NV_HEAD_STATE4_VBLANK_START_SHIFT |
663 hblank_start << NV_HEAD_STATE4_HBLANK_START_SHIFT);
664
665 /* TODO: adding interlace mode support */
666 tegra_sor_writel(sor, NV_HEAD_STATE5(head_num), 0x1);
667
668 tegra_sor_write_field(sor, CSTM,
669 CSTM_ROTCLK_DEFAULT_MASK |
670 CSTM_LVDS_EN_ENABLE,
671 2 << CSTM_ROTCLK_SHIFT |
672 is_lvds ? CSTM_LVDS_EN_ENABLE :
673 CSTM_LVDS_EN_DISABLE);
674
675 tegra_dc_sor_config_pwm(sor, 1024, 1024);
676}
677
678static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl)
679{
680 u32 reg_val = readl(&disp_ctrl->cmd.state_access);
681
682 writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
683 writel(VSYNC_H_POSITION(1), &disp_ctrl->disp.disp_timing_opt);
684
685 /* Enable DC now - otherwise pure text console may not show. */
686 writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT,
687 &disp_ctrl->cmd.disp_cmd);
688 writel(reg_val, &disp_ctrl->cmd.state_access);
689}
690
Simon Glassfad72182016-01-30 16:37:50 -0700691int tegra_dc_sor_enable_dp(struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600692 const struct tegra_dp_link_config *link_cfg)
693{
Simon Glassfad72182016-01-30 16:37:50 -0700694 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600695 int ret;
696
697 tegra_sor_write_field(sor, CLK_CNTRL,
698 CLK_CNTRL_DP_CLK_SEL_MASK,
699 CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK);
700
701 tegra_sor_write_field(sor, PLL2,
702 PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
703 PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
704 udelay(25);
705
706 tegra_sor_write_field(sor, PLL3,
707 PLL3_PLLVDD_MODE_MASK,
708 PLL3_PLLVDD_MODE_V3_3);
709 tegra_sor_writel(sor, PLL0,
710 0xf << PLL0_ICHPMP_SHFIT |
711 0x3 << PLL0_VCOCAP_SHIFT |
712 PLL0_PLLREG_LEVEL_V45 |
713 PLL0_RESISTORSEL_EXT |
714 PLL0_PWR_ON | PLL0_VCOPD_RESCIND);
715 tegra_sor_write_field(sor, PLL2,
716 PLL2_AUX1_SEQ_MASK |
717 PLL2_AUX9_LVDSEN_OVERRIDE |
718 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
719 PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE |
720 PLL2_AUX9_LVDSEN_OVERRIDE |
721 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
722 tegra_sor_writel(sor, PLL1, PLL1_TERM_COMPOUT_HIGH |
723 PLL1_TMDS_TERM_ENABLE);
724
725 if (tegra_dc_sor_poll_register(sor, PLL2,
726 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
727 PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE,
728 100, TEGRA_SOR_TIMEOUT_MS)) {
729 printf("DP failed to lock PLL\n");
730 return -EIO;
731 }
732
733 tegra_sor_write_field(sor, PLL2, PLL2_AUX2_MASK |
734 PLL2_AUX7_PORT_POWERDOWN_MASK,
735 PLL2_AUX2_OVERRIDE_POWERDOWN |
736 PLL2_AUX7_PORT_POWERDOWN_DISABLE);
737
Simon Glassfad72182016-01-30 16:37:50 -0700738 ret = tegra_dc_sor_power_up(dev, 0);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600739 if (ret) {
740 debug("DP failed to power up\n");
741 return ret;
742 }
743
744 /* re-enable SOR clock */
745 clock_sor_enable_edp_clock();
746
747 /* Power up lanes */
Simon Glassfad72182016-01-30 16:37:50 -0700748 tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600749
Simon Glassfad72182016-01-30 16:37:50 -0700750 tegra_dc_sor_set_dp_mode(dev, link_cfg);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600751 debug("%s ret\n", __func__);
752
753 return 0;
754}
755
Simon Glassfad72182016-01-30 16:37:50 -0700756int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600757 const struct tegra_dp_link_config *link_cfg,
758 const struct display_timing *timing)
759{
Simon Glassfad72182016-01-30 16:37:50 -0700760 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600761 struct dc_ctlr *disp_ctrl;
762 u32 reg_val;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600763
764 /* Use the first display controller */
765 debug("%s\n", __func__);
Simon Glass5eb75402017-07-25 08:30:01 -0600766 disp_ctrl = (struct dc_ctlr *)dev_read_addr(dc_dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600767
768 tegra_dc_sor_enable_dc(disp_ctrl);
769 tegra_dc_sor_config_panel(sor, 0, link_cfg, timing);
770
771 writel(0x9f00, &disp_ctrl->cmd.state_ctrl);
772 writel(0x9f, &disp_ctrl->cmd.state_ctrl);
773
774 writel(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
775 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
776 &disp_ctrl->cmd.disp_pow_ctrl);
777
778 reg_val = tegra_sor_readl(sor, TEST);
779 if (reg_val & TEST_ATTACHED_TRUE)
780 return -EEXIST;
781
782 tegra_sor_writel(sor, SUPER_STATE1,
783 SUPER_STATE1_ATTACHED_NO);
784
785 /*
786 * Enable display2sor clock at least 2 cycles before DC start,
787 * to clear sor internal valid signal.
788 */
789 writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
790 writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
791 writel(0, &disp_ctrl->disp.disp_win_opt);
792 writel(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
793
794 /* Attach head */
795 tegra_dc_sor_update(sor);
796 tegra_sor_writel(sor, SUPER_STATE1,
797 SUPER_STATE1_ATTACHED_YES);
798 tegra_sor_writel(sor, SUPER_STATE1,
799 SUPER_STATE1_ATTACHED_YES |
800 SUPER_STATE1_ASY_HEAD_OP_AWAKE |
801 SUPER_STATE1_ASY_ORMODE_NORMAL);
802 tegra_dc_sor_super_update(sor);
803
804 /* Enable dc */
805 reg_val = readl(&disp_ctrl->cmd.state_access);
806 writel(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
807 writel(CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT,
808 &disp_ctrl->cmd.disp_cmd);
809 writel(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
810 writel(reg_val, &disp_ctrl->cmd.state_access);
811
812 if (tegra_dc_sor_poll_register(sor, TEST,
813 TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
814 TEST_ACT_HEAD_OPMODE_AWAKE,
815 100,
816 TEGRA_SOR_ATTACH_TIMEOUT_MS)) {
817 printf("dc timeout waiting for OPMOD = AWAKE\n");
818 return -ETIMEDOUT;
819 } else {
820 debug("%s: sor is attached\n", __func__);
821 }
822
823#if DEBUG_SOR
824 dump_sor_reg(sor);
825#endif
826 debug("%s: ret=%d\n", __func__, 0);
827
828 return 0;
829}
830
Simon Glassfad72182016-01-30 16:37:50 -0700831void tegra_dc_sor_set_lane_parm(struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600832 const struct tegra_dp_link_config *link_cfg)
833{
Simon Glassfad72182016-01-30 16:37:50 -0700834 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
835
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600836 tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum),
837 link_cfg->drive_current);
838 tegra_sor_writel(sor, PR(sor->portnum),
839 link_cfg->preemphasis);
840 tegra_sor_writel(sor, POSTCURSOR(sor->portnum),
841 link_cfg->postcursor);
842 tegra_sor_writel(sor, LVDS, 0);
843
Simon Glassfad72182016-01-30 16:37:50 -0700844 tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw);
845 tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600846
847 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
848 DP_PADCTL_TX_PU_ENABLE |
849 DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK,
850 DP_PADCTL_TX_PU_ENABLE |
851 2 << DP_PADCTL_TX_PU_VALUE_SHIFT);
852
853 /* Precharge */
854 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0xf0);
855 udelay(20);
856
857 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0);
858}
859
Simon Glassfad72182016-01-30 16:37:50 -0700860int tegra_dc_sor_set_voltage_swing(struct udevice *dev,
Simon Glass662f2aa2015-04-14 21:03:44 -0600861 const struct tegra_dp_link_config *link_cfg)
862{
Simon Glassfad72182016-01-30 16:37:50 -0700863 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glass662f2aa2015-04-14 21:03:44 -0600864 u32 drive_current = 0;
865 u32 pre_emphasis = 0;
866
867 /* Set to a known-good pre-calibrated setting */
868 switch (link_cfg->link_bw) {
869 case SOR_LINK_SPEED_G1_62:
870 case SOR_LINK_SPEED_G2_7:
871 drive_current = 0x13131313;
872 pre_emphasis = 0;
873 break;
874 case SOR_LINK_SPEED_G5_4:
875 debug("T124 does not support 5.4G link clock.\n");
876 default:
877 debug("Invalid sor link bandwidth: %d\n", link_cfg->link_bw);
878 return -ENOLINK;
879 }
880
881 tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), drive_current);
882 tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis);
883
884 return 0;
885}
886
Simon Glassfad72182016-01-30 16:37:50 -0700887void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev,
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600888 const struct tegra_dp_link_config *link_cfg)
889{
Simon Glassfad72182016-01-30 16:37:50 -0700890 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600891 u32 pad_ctrl = 0;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600892 int err = 0;
893
894 switch (link_cfg->lane_count) {
895 case 4:
896 pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
897 DP_PADCTL_PD_TXD_1_NO |
898 DP_PADCTL_PD_TXD_2_NO |
899 DP_PADCTL_PD_TXD_3_NO;
900 break;
901 case 2:
902 pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
903 DP_PADCTL_PD_TXD_1_NO |
904 DP_PADCTL_PD_TXD_2_YES |
905 DP_PADCTL_PD_TXD_3_YES;
906 break;
907 case 1:
908 pad_ctrl = DP_PADCTL_PD_TXD_0_NO |
909 DP_PADCTL_PD_TXD_1_YES |
910 DP_PADCTL_PD_TXD_2_YES |
911 DP_PADCTL_PD_TXD_3_YES;
912 break;
913 default:
914 printf("Invalid sor lane count: %u\n", link_cfg->lane_count);
915 return;
916 }
917
918 pad_ctrl |= DP_PADCTL_PAD_CAL_PD_POWERDOWN;
919 tegra_sor_writel(sor, DP_PADCTL(sor->portnum), pad_ctrl);
920
921 err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0);
922 if (err) {
923 debug("Wait for lane power down failed: %d\n", err);
924 return;
925 }
Simon Glass662f2aa2015-04-14 21:03:44 -0600926}
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600927
Simon Glassfad72182016-01-30 16:37:50 -0700928int tegra_sor_precharge_lanes(struct udevice *dev,
Simon Glass662f2aa2015-04-14 21:03:44 -0600929 const struct tegra_dp_link_config *cfg)
930{
Simon Glassfad72182016-01-30 16:37:50 -0700931 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glass662f2aa2015-04-14 21:03:44 -0600932 u32 val = 0;
933
934 switch (cfg->lane_count) {
935 case 4:
936 val |= (DP_PADCTL_PD_TXD_3_NO |
937 DP_PADCTL_PD_TXD_2_NO);
938 /* fall through */
939 case 2:
940 val |= DP_PADCTL_PD_TXD_1_NO;
941 /* fall through */
942 case 1:
943 val |= DP_PADCTL_PD_TXD_0_NO;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600944 break;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600945 default:
Simon Glass662f2aa2015-04-14 21:03:44 -0600946 debug("dp: invalid lane number %d\n", cfg->lane_count);
947 return -EINVAL;
Simon Glassf4f5cfa2015-04-14 21:03:40 -0600948 }
949
Simon Glass662f2aa2015-04-14 21:03:44 -0600950 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
951 (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT),
952 (val << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT));
953 udelay(100);
954 tegra_sor_write_field(sor, DP_PADCTL(sor->portnum),
955 (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT),
956 0);
957
958 return 0;
959}
960
961static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable)
962{
963 u32 reg_val = readl(&disp_ctrl->disp.disp_win_opt);
964
965 reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE;
966 writel(reg_val, &disp_ctrl->disp.disp_win_opt);
967}
968
Simon Glassfad72182016-01-30 16:37:50 -0700969int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev)
Simon Glass662f2aa2015-04-14 21:03:44 -0600970{
Simon Glassfad72182016-01-30 16:37:50 -0700971 struct tegra_dc_sor_data *sor = dev_get_priv(dev);
Simon Glass662f2aa2015-04-14 21:03:44 -0600972 int dc_reg_ctx[DC_REG_SAVE_SPACE];
Simon Glass662f2aa2015-04-14 21:03:44 -0600973 struct dc_ctlr *disp_ctrl;
974 unsigned long dc_int_mask;
Simon Glass662f2aa2015-04-14 21:03:44 -0600975 int ret;
976
977 debug("%s\n", __func__);
978 /* Use the first display controller */
Simon Glass5eb75402017-07-25 08:30:01 -0600979 disp_ctrl = (struct dc_ctlr *)dev_read_addr(dev);
Simon Glass662f2aa2015-04-14 21:03:44 -0600980
981 /* Sleep mode */
982 tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP |
983 SUPER_STATE1_ASY_ORMODE_SAFE |
984 SUPER_STATE1_ATTACHED_YES);
985 tegra_dc_sor_super_update(sor);
986
987 tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx);
988
989 if (tegra_dc_sor_poll_register(sor, TEST,
990 TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
991 TEST_ACT_HEAD_OPMODE_SLEEP, 100,
992 TEGRA_SOR_ATTACH_TIMEOUT_MS)) {
993 debug("dc timeout waiting for OPMOD = SLEEP\n");
994 ret = -ETIMEDOUT;
995 goto err;
996 }
997
998 tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP |
999 SUPER_STATE1_ASY_ORMODE_SAFE |
1000 SUPER_STATE1_ATTACHED_NO);
1001
1002 /* Mask DC interrupts during the 2 dummy frames required for detach */
1003 dc_int_mask = readl(&disp_ctrl->cmd.int_mask);
1004 writel(0, &disp_ctrl->cmd.int_mask);
1005
1006 /* Stop DC->SOR path */
1007 tegra_dc_sor_enable_sor(disp_ctrl, false);
1008 ret = tegra_dc_sor_general_act(disp_ctrl);
1009 if (ret)
1010 goto err;
1011
1012 /* Stop DC */
1013 writel(CTRL_MODE_STOP << CTRL_MODE_SHIFT, &disp_ctrl->cmd.disp_cmd);
1014 ret = tegra_dc_sor_general_act(disp_ctrl);
1015 if (ret)
1016 goto err;
1017
1018 tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx);
1019
1020 writel(dc_int_mask, &disp_ctrl->cmd.int_mask);
1021
1022 return 0;
1023err:
1024 debug("%s: ret=%d\n", __func__, ret);
1025
1026 return ret;
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001027}
1028
Simon Glassfad72182016-01-30 16:37:50 -07001029static int tegra_sor_set_backlight(struct udevice *dev, int percent)
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001030{
Simon Glassfad72182016-01-30 16:37:50 -07001031 struct tegra_dc_sor_data *priv = dev_get_priv(dev);
1032 int ret;
1033
1034 ret = panel_enable_backlight(priv->panel);
1035 if (ret) {
1036 debug("sor: Cannot enable panel backlight\n");
1037 return ret;
1038 }
1039
1040 return 0;
1041}
1042
1043static int tegra_sor_ofdata_to_platdata(struct udevice *dev)
1044{
1045 struct tegra_dc_sor_data *priv = dev_get_priv(dev);
Simon Glassfad72182016-01-30 16:37:50 -07001046 int ret;
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001047
Simon Glass5eb75402017-07-25 08:30:01 -06001048 priv->base = (void *)dev_read_addr(dev);
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001049
Simon Glass5eb75402017-07-25 08:30:01 -06001050 priv->pmc_base = (void *)syscon_get_first_range(TEGRA_SYSCON_PMC);
1051 if (IS_ERR(priv->pmc_base))
1052 return PTR_ERR(priv->pmc_base);
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001053
Simon Glassfad72182016-01-30 16:37:50 -07001054 ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel",
1055 &priv->panel);
1056 if (ret) {
1057 debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
1058 dev->name, ret);
1059 return ret;
1060 }
Simon Glassf4f5cfa2015-04-14 21:03:40 -06001061
1062 return 0;
1063}
Simon Glassfad72182016-01-30 16:37:50 -07001064
1065static const struct video_bridge_ops tegra_sor_ops = {
1066 .set_backlight = tegra_sor_set_backlight,
1067};
1068
1069static const struct udevice_id tegra_sor_ids[] = {
1070 { .compatible = "nvidia,tegra124-sor" },
1071 { }
1072};
1073
1074U_BOOT_DRIVER(sor_tegra) = {
1075 .name = "sor_tegra",
1076 .id = UCLASS_VIDEO_BRIDGE,
1077 .of_match = tegra_sor_ids,
1078 .ofdata_to_platdata = tegra_sor_ofdata_to_platdata,
1079 .ops = &tegra_sor_ops,
1080 .priv_auto_alloc_size = sizeof(struct tegra_dc_sor_data),
1081};