aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt42
-rw-r--r--drivers/gpu/drm/tegra/Makefile2
-rw-r--r--drivers/gpu/drm/tegra/dc.h1
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c544
-rw-r--r--drivers/gpu/drm/tegra/dpaux.h73
-rw-r--r--drivers/gpu/drm/tegra/drm.c19
-rw-r--r--drivers/gpu/drm/tegra/drm.h20
-rw-r--r--drivers/gpu/drm/tegra/output.c8
-rw-r--r--drivers/gpu/drm/tegra/sor.c1092
-rw-r--r--drivers/gpu/drm/tegra/sor.h278
10 files changed, 2077 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
index efaeec8961b6..efa8b8451f93 100644
--- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
@@ -190,6 +190,48 @@ of the following host1x client modules:
190 - nvidia,edid: supplies a binary EDID blob 190 - nvidia,edid: supplies a binary EDID blob
191 - nvidia,panel: phandle of a display panel 191 - nvidia,panel: phandle of a display panel
192 192
193- sor: serial output resource
194
195 Required properties:
196 - compatible: "nvidia,tegra124-sor"
197 - reg: Physical base address and length of the controller's registers.
198 - interrupts: The interrupt outputs from the controller.
199 - clocks: Must contain an entry for each entry in clock-names.
200 See ../clocks/clock-bindings.txt for details.
201 - clock-names: Must include the following entries:
202 - sor: clock input for the SOR hardware
203 - parent: input for the pixel clock
204 - dp: reference clock for the SOR clock
205 - safe: safe reference for the SOR clock during power up
206 - resets: Must contain an entry for each entry in reset-names.
207 See ../reset/reset.txt for details.
208 - reset-names: Must include the following entries:
209 - sor
210
211 Optional properties:
212 - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
213 - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
214 - nvidia,edid: supplies a binary EDID blob
215 - nvidia,panel: phandle of a display panel
216
217 Optional properties when driving an eDP output:
218 - nvidia,dpaux: phandle to a DispayPort AUX interface
219
220- dpaux: DisplayPort AUX interface
221 - compatible: "nvidia,tegra124-dpaux"
222 - reg: Physical base address and length of the controller's registers.
223 - interrupts: The interrupt outputs from the controller.
224 - clocks: Must contain an entry for each entry in clock-names.
225 See ../clocks/clock-bindings.txt for details.
226 - clock-names: Must include the following entries:
227 - dpaux: clock input for the DPAUX hardware
228 - parent: reference clock
229 - resets: Must contain an entry for each entry in reset-names.
230 See ../reset/reset.txt for details.
231 - reset-names: Must include the following entries:
232 - dpaux
233 - vdd-supply: phandle of a supply that powers the DisplayPort link
234
193Example: 235Example:
194 236
195/ { 237/ {
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index 8d220afbd85f..d43f21bb4596 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -11,6 +11,8 @@ tegra-drm-y := \
11 hdmi.o \ 11 hdmi.o \
12 mipi-phy.o \ 12 mipi-phy.o \
13 dsi.o \ 13 dsi.o \
14 sor.o \
15 dpaux.o \
14 gr2d.o \ 16 gr2d.o \
15 gr3d.o 17 gr3d.o
16 18
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 3c2c0ea1cd87..c94101494826 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -118,6 +118,7 @@
118#define DC_DISP_DISP_WIN_OPTIONS 0x402 118#define DC_DISP_DISP_WIN_OPTIONS 0x402
119#define HDMI_ENABLE (1 << 30) 119#define HDMI_ENABLE (1 << 30)
120#define DSI_ENABLE (1 << 29) 120#define DSI_ENABLE (1 << 29)
121#define SOR_ENABLE (1 << 25)
121 122
122#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 123#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
123#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) 124#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
new file mode 100644
index 000000000000..d536ed381fbd
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -0,0 +1,544 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/clk.h>
10#include <linux/delay.h>
11#include <linux/gpio.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/of_gpio.h>
15#include <linux/platform_device.h>
16#include <linux/reset.h>
17#include <linux/regulator/consumer.h>
18
19#include <drm/drm_dp_helper.h>
20#include <drm/drm_panel.h>
21
22#include "dpaux.h"
23#include "drm.h"
24
25static DEFINE_MUTEX(dpaux_lock);
26static LIST_HEAD(dpaux_list);
27
28struct tegra_dpaux {
29 struct drm_dp_aux aux;
30 struct device *dev;
31
32 void __iomem *regs;
33 int irq;
34
35 struct tegra_output *output;
36
37 struct reset_control *rst;
38 struct clk *clk_parent;
39 struct clk *clk;
40
41 struct regulator *vdd;
42
43 struct completion complete;
44 struct list_head list;
45};
46
47static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux)
48{
49 return container_of(aux, struct tegra_dpaux, aux);
50}
51
52static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux,
53 unsigned long offset)
54{
55 return readl(dpaux->regs + (offset << 2));
56}
57
58static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux,
59 unsigned long value,
60 unsigned long offset)
61{
62 writel(value, dpaux->regs + (offset << 2));
63}
64
65static void tegra_dpaux_write_fifo(struct tegra_dpaux *dpaux, const u8 *buffer,
66 size_t size)
67{
68 unsigned long offset = DPAUX_DP_AUXDATA_WRITE(0);
69 size_t i, j;
70
71 for (i = 0; i < size; i += 4) {
72 size_t num = min_t(size_t, size - i, 4);
73 unsigned long value = 0;
74
75 for (j = 0; j < num; j++)
76 value |= buffer[i + j] << (j * 8);
77
78 tegra_dpaux_writel(dpaux, value, offset++);
79 }
80}
81
82static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,
83 size_t size)
84{
85 unsigned long offset = DPAUX_DP_AUXDATA_READ(0);
86 size_t i, j;
87
88 for (i = 0; i < size; i += 4) {
89 size_t num = min_t(size_t, size - i, 4);
90 unsigned long value;
91
92 value = tegra_dpaux_readl(dpaux, offset++);
93
94 for (j = 0; j < num; j++)
95 buffer[i + j] = value >> (j * 8);
96 }
97}
98
99static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
100 struct drm_dp_aux_msg *msg)
101{
102 unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ;
103 unsigned long timeout = msecs_to_jiffies(250);
104 struct tegra_dpaux *dpaux = to_dpaux(aux);
105 unsigned long status;
106 ssize_t ret = 0;
107
108 if (msg->size < 1 || msg->size > 16)
109 return -EINVAL;
110
111 tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
112
113 switch (msg->request & ~DP_AUX_I2C_MOT) {
114 case DP_AUX_I2C_WRITE:
115 if (msg->request & DP_AUX_I2C_MOT)
116 value = DPAUX_DP_AUXCTL_CMD_MOT_WR;
117 else
118 value = DPAUX_DP_AUXCTL_CMD_I2C_WR;
119
120 break;
121
122 case DP_AUX_I2C_READ:
123 if (msg->request & DP_AUX_I2C_MOT)
124 value = DPAUX_DP_AUXCTL_CMD_MOT_RD;
125 else
126 value = DPAUX_DP_AUXCTL_CMD_I2C_RD;
127
128 break;
129
130 case DP_AUX_I2C_STATUS:
131 if (msg->request & DP_AUX_I2C_MOT)
132 value = DPAUX_DP_AUXCTL_CMD_MOT_RQ;
133 else
134 value = DPAUX_DP_AUXCTL_CMD_I2C_RQ;
135
136 break;
137
138 case DP_AUX_NATIVE_WRITE:
139 value = DPAUX_DP_AUXCTL_CMD_AUX_WR;
140 break;
141
142 case DP_AUX_NATIVE_READ:
143 value = DPAUX_DP_AUXCTL_CMD_AUX_RD;
144 break;
145
146 default:
147 return -EINVAL;
148 }
149
150 value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
151 tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
152
153 if ((msg->request & DP_AUX_I2C_READ) == 0) {
154 tegra_dpaux_write_fifo(dpaux, msg->buffer, msg->size);
155 ret = msg->size;
156 }
157
158 /* start transaction */
159 value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXCTL);
160 value |= DPAUX_DP_AUXCTL_TRANSACTREQ;
161 tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
162
163 status = wait_for_completion_timeout(&dpaux->complete, timeout);
164 if (!status)
165 return -ETIMEDOUT;
166
167 /* read status and clear errors */
168 value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
169 tegra_dpaux_writel(dpaux, 0xf00, DPAUX_DP_AUXSTAT);
170
171 if (value & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR)
172 return -ETIMEDOUT;
173
174 if ((value & DPAUX_DP_AUXSTAT_RX_ERROR) ||
175 (value & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR) ||
176 (value & DPAUX_DP_AUXSTAT_NO_STOP_ERROR))
177 return -EIO;
178
179 switch ((value & DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK) >> 16) {
180 case 0x00:
181 msg->reply = DP_AUX_NATIVE_REPLY_ACK;
182 break;
183
184 case 0x01:
185 msg->reply = DP_AUX_NATIVE_REPLY_NACK;
186 break;
187
188 case 0x02:
189 msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
190 break;
191
192 case 0x04:
193 msg->reply = DP_AUX_I2C_REPLY_NACK;
194 break;
195
196 case 0x08:
197 msg->reply = DP_AUX_I2C_REPLY_DEFER;
198 break;
199 }
200
201 if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
202 if (msg->request & DP_AUX_I2C_READ) {
203 size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK;
204
205 if (WARN_ON(count != msg->size))
206 count = min_t(size_t, count, msg->size);
207
208 tegra_dpaux_read_fifo(dpaux, msg->buffer, count);
209 ret = count;
210 }
211 }
212
213 return ret;
214}
215
216static irqreturn_t tegra_dpaux_irq(int irq, void *data)
217{
218 struct tegra_dpaux *dpaux = data;
219 irqreturn_t ret = IRQ_HANDLED;
220 unsigned long value;
221
222 /* clear interrupts */
223 value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX);
224 tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
225
226 if (value & DPAUX_INTR_PLUG_EVENT) {
227 if (dpaux->output) {
228 drm_helper_hpd_irq_event(dpaux->output->connector.dev);
229 }
230 }
231
232 if (value & DPAUX_INTR_UNPLUG_EVENT) {
233 if (dpaux->output)
234 drm_helper_hpd_irq_event(dpaux->output->connector.dev);
235 }
236
237 if (value & DPAUX_INTR_IRQ_EVENT) {
238 /* TODO: handle this */
239 }
240
241 if (value & DPAUX_INTR_AUX_DONE)
242 complete(&dpaux->complete);
243
244 return ret;
245}
246
247static int tegra_dpaux_probe(struct platform_device *pdev)
248{
249 struct tegra_dpaux *dpaux;
250 struct resource *regs;
251 unsigned long value;
252 int err;
253
254 dpaux = devm_kzalloc(&pdev->dev, sizeof(*dpaux), GFP_KERNEL);
255 if (!dpaux)
256 return -ENOMEM;
257
258 init_completion(&dpaux->complete);
259 INIT_LIST_HEAD(&dpaux->list);
260 dpaux->dev = &pdev->dev;
261
262 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
263 dpaux->regs = devm_ioremap_resource(&pdev->dev, regs);
264 if (IS_ERR(dpaux->regs))
265 return PTR_ERR(dpaux->regs);
266
267 dpaux->irq = platform_get_irq(pdev, 0);
268 if (dpaux->irq < 0) {
269 dev_err(&pdev->dev, "failed to get IRQ\n");
270 return -ENXIO;
271 }
272
273 dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
274 if (IS_ERR(dpaux->rst))
275 return PTR_ERR(dpaux->rst);
276
277 dpaux->clk = devm_clk_get(&pdev->dev, NULL);
278 if (IS_ERR(dpaux->clk))
279 return PTR_ERR(dpaux->clk);
280
281 err = clk_prepare_enable(dpaux->clk);
282 if (err < 0)
283 return err;
284
285 reset_control_deassert(dpaux->rst);
286
287 dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
288 if (IS_ERR(dpaux->clk_parent))
289 return PTR_ERR(dpaux->clk_parent);
290
291 err = clk_prepare_enable(dpaux->clk_parent);
292 if (err < 0)
293 return err;
294
295 err = clk_set_rate(dpaux->clk_parent, 270000000);
296 if (err < 0) {
297 dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n",
298 err);
299 return err;
300 }
301
302 dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
303 if (IS_ERR(dpaux->vdd))
304 return PTR_ERR(dpaux->vdd);
305
306 err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
307 dev_name(dpaux->dev), dpaux);
308 if (err < 0) {
309 dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n",
310 dpaux->irq, err);
311 return err;
312 }
313
314 dpaux->aux.transfer = tegra_dpaux_transfer;
315 dpaux->aux.dev = &pdev->dev;
316
317 err = drm_dp_aux_register_i2c_bus(&dpaux->aux);
318 if (err < 0)
319 return err;
320
321 /* enable and clear all interrupts */
322 value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
323 DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
324 tegra_dpaux_writel(dpaux, value, DPAUX_INTR_EN_AUX);
325 tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
326
327 mutex_lock(&dpaux_lock);
328 list_add_tail(&dpaux->list, &dpaux_list);
329 mutex_unlock(&dpaux_lock);
330
331 platform_set_drvdata(pdev, dpaux);
332
333 return 0;
334}
335
336static int tegra_dpaux_remove(struct platform_device *pdev)
337{
338 struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
339
340 drm_dp_aux_unregister_i2c_bus(&dpaux->aux);
341
342 mutex_lock(&dpaux_lock);
343 list_del(&dpaux->list);
344 mutex_unlock(&dpaux_lock);
345
346 clk_disable_unprepare(dpaux->clk_parent);
347 reset_control_assert(dpaux->rst);
348 clk_disable_unprepare(dpaux->clk);
349
350 return 0;
351}
352
353static const struct of_device_id tegra_dpaux_of_match[] = {
354 { .compatible = "nvidia,tegra124-dpaux", },
355 { },
356};
357
358struct platform_driver tegra_dpaux_driver = {
359 .driver = {
360 .name = "tegra-dpaux",
361 .of_match_table = tegra_dpaux_of_match,
362 },
363 .probe = tegra_dpaux_probe,
364 .remove = tegra_dpaux_remove,
365};
366
367struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np)
368{
369 struct tegra_dpaux *dpaux;
370
371 mutex_lock(&dpaux_lock);
372
373 list_for_each_entry(dpaux, &dpaux_list, list)
374 if (np == dpaux->dev->of_node) {
375 mutex_unlock(&dpaux_lock);
376 return dpaux;
377 }
378
379 mutex_unlock(&dpaux_lock);
380
381 return NULL;
382}
383
384int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
385{
386 unsigned long timeout;
387 int err;
388
389 dpaux->output = output;
390
391 err = regulator_enable(dpaux->vdd);
392 if (err < 0)
393 return err;
394
395 timeout = jiffies + msecs_to_jiffies(250);
396
397 while (time_before(jiffies, timeout)) {
398 enum drm_connector_status status;
399
400 status = tegra_dpaux_detect(dpaux);
401 if (status == connector_status_connected)
402 return 0;
403
404 usleep_range(1000, 2000);
405 }
406
407 return -ETIMEDOUT;
408}
409
410int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
411{
412 unsigned long timeout;
413 int err;
414
415 err = regulator_disable(dpaux->vdd);
416 if (err < 0)
417 return err;
418
419 timeout = jiffies + msecs_to_jiffies(250);
420
421 while (time_before(jiffies, timeout)) {
422 enum drm_connector_status status;
423
424 status = tegra_dpaux_detect(dpaux);
425 if (status == connector_status_disconnected) {
426 dpaux->output = NULL;
427 return 0;
428 }
429
430 usleep_range(1000, 2000);
431 }
432
433 return -ETIMEDOUT;
434}
435
436enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux)
437{
438 unsigned long value;
439
440 value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
441
442 if (value & DPAUX_DP_AUXSTAT_HPD_STATUS)
443 return connector_status_connected;
444
445 return connector_status_disconnected;
446}
447
448int tegra_dpaux_enable(struct tegra_dpaux *dpaux)
449{
450 unsigned long value;
451
452 value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) |
453 DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) |
454 DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) |
455 DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV |
456 DPAUX_HYBRID_PADCTL_MODE_AUX;
457 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
458
459 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
460 value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
461 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
462
463 return 0;
464}
465
466int tegra_dpaux_disable(struct tegra_dpaux *dpaux)
467{
468 unsigned long value;
469
470 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
471 value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
472 tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
473
474 return 0;
475}
476
477int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding)
478{
479 int err;
480
481 err = drm_dp_dpcd_writeb(&dpaux->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
482 encoding);
483 if (err < 0)
484 return err;
485
486 return 0;
487}
488
489int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
490 u8 pattern)
491{
492 u8 tp = pattern & DP_TRAINING_PATTERN_MASK;
493 u8 status[DP_LINK_STATUS_SIZE], values[4];
494 unsigned int i;
495 int err;
496
497 err = drm_dp_dpcd_writeb(&dpaux->aux, DP_TRAINING_PATTERN_SET, pattern);
498 if (err < 0)
499 return err;
500
501 if (tp == DP_TRAINING_PATTERN_DISABLE)
502 return 0;
503
504 for (i = 0; i < link->num_lanes; i++)
505 values[i] = DP_TRAIN_MAX_PRE_EMPHASIS_REACHED |
506 DP_TRAIN_PRE_EMPHASIS_0 |
507 DP_TRAIN_MAX_SWING_REACHED |
508 DP_TRAIN_VOLTAGE_SWING_400;
509
510 err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values,
511 link->num_lanes);
512 if (err < 0)
513 return err;
514
515 usleep_range(500, 1000);
516
517 err = drm_dp_dpcd_read_link_status(&dpaux->aux, status);
518 if (err < 0)
519 return err;
520
521 switch (tp) {
522 case DP_TRAINING_PATTERN_1:
523 if (!drm_dp_clock_recovery_ok(status, link->num_lanes))
524 return -EAGAIN;
525
526 break;
527
528 case DP_TRAINING_PATTERN_2:
529 if (!drm_dp_channel_eq_ok(status, link->num_lanes))
530 return -EAGAIN;
531
532 break;
533
534 default:
535 dev_err(dpaux->dev, "unsupported training pattern %u\n", tp);
536 return -EINVAL;
537 }
538
539 err = drm_dp_dpcd_writeb(&dpaux->aux, DP_EDP_CONFIGURATION_SET, 0);
540 if (err < 0)
541 return err;
542
543 return 0;
544}
diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h
new file mode 100644
index 000000000000..4f5bf10fdff9
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dpaux.h
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRM_TEGRA_DPAUX_H
10#define DRM_TEGRA_DPAUX_H
11
12#define DPAUX_CTXSW 0x00
13
14#define DPAUX_INTR_EN_AUX 0x01
15#define DPAUX_INTR_AUX 0x05
16#define DPAUX_INTR_AUX_DONE (1 << 3)
17#define DPAUX_INTR_IRQ_EVENT (1 << 2)
18#define DPAUX_INTR_UNPLUG_EVENT (1 << 1)
19#define DPAUX_INTR_PLUG_EVENT (1 << 0)
20
21#define DPAUX_DP_AUXDATA_WRITE(x) (0x09 + ((x) << 2))
22#define DPAUX_DP_AUXDATA_READ(x) (0x19 + ((x) << 2))
23#define DPAUX_DP_AUXADDR 0x29
24
25#define DPAUX_DP_AUXCTL 0x2d
26#define DPAUX_DP_AUXCTL_TRANSACTREQ (1 << 16)
27#define DPAUX_DP_AUXCTL_CMD_AUX_RD (9 << 12)
28#define DPAUX_DP_AUXCTL_CMD_AUX_WR (8 << 12)
29#define DPAUX_DP_AUXCTL_CMD_MOT_RQ (6 << 12)
30#define DPAUX_DP_AUXCTL_CMD_MOT_RD (5 << 12)
31#define DPAUX_DP_AUXCTL_CMD_MOT_WR (4 << 12)
32#define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12)
33#define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12)
34#define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12)
35#define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff)
36
37#define DPAUX_DP_AUXSTAT 0x31
38#define DPAUX_DP_AUXSTAT_HPD_STATUS (1 << 28)
39#define DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK (0xf0000)
40#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR (1 << 11)
41#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR (1 << 10)
42#define DPAUX_DP_AUXSTAT_RX_ERROR (1 << 9)
43#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR (1 << 8)
44#define DPAUX_DP_AUXSTAT_REPLY_MASK (0xff)
45
46#define DPAUX_DP_AUX_SINKSTAT_LO 0x35
47#define DPAUX_DP_AUX_SINKSTAT_HI 0x39
48
49#define DPAUX_HPD_CONFIG 0x3d
50#define DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME(x) (((x) & 0xffff) << 16)
51#define DPAUX_HPD_CONFIG_PLUG_MIN_TIME(x) ((x) & 0xffff)
52
53#define DPAUX_HPD_IRQ_CONFIG 0x41
54#define DPAUX_HPD_IRQ_CONFIG_MIN_LOW_TIME(x) ((x) & 0xffff)
55
56#define DPAUX_DP_AUX_CONFIG 0x45
57
58#define DPAUX_HYBRID_PADCTL 0x49
59#define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12)
60#define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8)
61#define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2)
62#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV (1 << 1)
63#define DPAUX_HYBRID_PADCTL_MODE_I2C (1 << 0)
64#define DPAUX_HYBRID_PADCTL_MODE_AUX (0 << 0)
65
66#define DPAUX_HYBRID_SPARE 0x4d
67#define DPAUX_HYBRID_SPARE_PAD_POWER_DOWN (1 << 0)
68
69#define DPAUX_SCRATCH_REG0 0x51
70#define DPAUX_SCRATCH_REG1 0x55
71#define DPAUX_SCRATCH_REG2 0x59
72
73#endif
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 88a529008ce0..4c583d58334a 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -665,6 +665,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
665 { .compatible = "nvidia,tegra114-hdmi", }, 665 { .compatible = "nvidia,tegra114-hdmi", },
666 { .compatible = "nvidia,tegra114-gr3d", }, 666 { .compatible = "nvidia,tegra114-gr3d", },
667 { .compatible = "nvidia,tegra124-dc", }, 667 { .compatible = "nvidia,tegra124-dc", },
668 { .compatible = "nvidia,tegra124-sor", },
668 { /* sentinel */ } 669 { /* sentinel */ }
669}; 670};
670 671
@@ -691,14 +692,22 @@ static int __init host1x_drm_init(void)
691 if (err < 0) 692 if (err < 0)
692 goto unregister_dc; 693 goto unregister_dc;
693 694
694 err = platform_driver_register(&tegra_hdmi_driver); 695 err = platform_driver_register(&tegra_sor_driver);
695 if (err < 0) 696 if (err < 0)
696 goto unregister_dsi; 697 goto unregister_dsi;
697 698
698 err = platform_driver_register(&tegra_gr2d_driver); 699 err = platform_driver_register(&tegra_hdmi_driver);
700 if (err < 0)
701 goto unregister_sor;
702
703 err = platform_driver_register(&tegra_dpaux_driver);
699 if (err < 0) 704 if (err < 0)
700 goto unregister_hdmi; 705 goto unregister_hdmi;
701 706
707 err = platform_driver_register(&tegra_gr2d_driver);
708 if (err < 0)
709 goto unregister_dpaux;
710
702 err = platform_driver_register(&tegra_gr3d_driver); 711 err = platform_driver_register(&tegra_gr3d_driver);
703 if (err < 0) 712 if (err < 0)
704 goto unregister_gr2d; 713 goto unregister_gr2d;
@@ -707,8 +716,12 @@ static int __init host1x_drm_init(void)
707 716
708unregister_gr2d: 717unregister_gr2d:
709 platform_driver_unregister(&tegra_gr2d_driver); 718 platform_driver_unregister(&tegra_gr2d_driver);
719unregister_dpaux:
720 platform_driver_unregister(&tegra_dpaux_driver);
710unregister_hdmi: 721unregister_hdmi:
711 platform_driver_unregister(&tegra_hdmi_driver); 722 platform_driver_unregister(&tegra_hdmi_driver);
723unregister_sor:
724 platform_driver_unregister(&tegra_sor_driver);
712unregister_dsi: 725unregister_dsi:
713 platform_driver_unregister(&tegra_dsi_driver); 726 platform_driver_unregister(&tegra_dsi_driver);
714unregister_dc: 727unregister_dc:
@@ -723,7 +736,9 @@ static void __exit host1x_drm_exit(void)
723{ 736{
724 platform_driver_unregister(&tegra_gr3d_driver); 737 platform_driver_unregister(&tegra_gr3d_driver);
725 platform_driver_unregister(&tegra_gr2d_driver); 738 platform_driver_unregister(&tegra_gr2d_driver);
739 platform_driver_unregister(&tegra_dpaux_driver);
726 platform_driver_unregister(&tegra_hdmi_driver); 740 platform_driver_unregister(&tegra_hdmi_driver);
741 platform_driver_unregister(&tegra_sor_driver);
727 platform_driver_unregister(&tegra_dsi_driver); 742 platform_driver_unregister(&tegra_dsi_driver);
728 platform_driver_unregister(&tegra_dc_driver); 743 platform_driver_unregister(&tegra_dc_driver);
729 host1x_driver_unregister(&host1x_drm_driver); 744 host1x_driver_unregister(&host1x_drm_driver);
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index bf1cac7658f8..126332c3ecbb 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -179,12 +179,14 @@ struct tegra_output_ops {
179 int (*check_mode)(struct tegra_output *output, 179 int (*check_mode)(struct tegra_output *output,
180 struct drm_display_mode *mode, 180 struct drm_display_mode *mode,
181 enum drm_mode_status *status); 181 enum drm_mode_status *status);
182 enum drm_connector_status (*detect)(struct tegra_output *output);
182}; 183};
183 184
184enum tegra_output_type { 185enum tegra_output_type {
185 TEGRA_OUTPUT_RGB, 186 TEGRA_OUTPUT_RGB,
186 TEGRA_OUTPUT_HDMI, 187 TEGRA_OUTPUT_HDMI,
187 TEGRA_OUTPUT_DSI, 188 TEGRA_OUTPUT_DSI,
189 TEGRA_OUTPUT_EDP,
188}; 190};
189 191
190struct tegra_output { 192struct tegra_output {
@@ -265,6 +267,22 @@ extern int tegra_output_remove(struct tegra_output *output);
265extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); 267extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
266extern int tegra_output_exit(struct tegra_output *output); 268extern int tegra_output_exit(struct tegra_output *output);
267 269
270/* from dpaux.c */
271
272struct tegra_dpaux;
273struct drm_dp_link;
274struct drm_dp_aux;
275
276struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np);
277enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux);
278int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output);
279int tegra_dpaux_detach(struct tegra_dpaux *dpaux);
280int tegra_dpaux_enable(struct tegra_dpaux *dpaux);
281int tegra_dpaux_disable(struct tegra_dpaux *dpaux);
282int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding);
283int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
284 u8 pattern);
285
268/* from fb.c */ 286/* from fb.c */
269struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, 287struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
270 unsigned int index); 288 unsigned int index);
@@ -278,7 +296,9 @@ extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
278 296
279extern struct platform_driver tegra_dc_driver; 297extern struct platform_driver tegra_dc_driver;
280extern struct platform_driver tegra_dsi_driver; 298extern struct platform_driver tegra_dsi_driver;
299extern struct platform_driver tegra_sor_driver;
281extern struct platform_driver tegra_hdmi_driver; 300extern struct platform_driver tegra_hdmi_driver;
301extern struct platform_driver tegra_dpaux_driver;
282extern struct platform_driver tegra_gr2d_driver; 302extern struct platform_driver tegra_gr2d_driver;
283extern struct platform_driver tegra_gr3d_driver; 303extern struct platform_driver tegra_gr3d_driver;
284 304
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 57cecbd18ca8..a3e4f1eca6f7 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -77,6 +77,9 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
77 struct tegra_output *output = connector_to_output(connector); 77 struct tegra_output *output = connector_to_output(connector);
78 enum drm_connector_status status = connector_status_unknown; 78 enum drm_connector_status status = connector_status_unknown;
79 79
80 if (output->ops->detect)
81 return output->ops->detect(output);
82
80 if (gpio_is_valid(output->hpd_gpio)) { 83 if (gpio_is_valid(output->hpd_gpio)) {
81 if (gpio_get_value(output->hpd_gpio) == 0) 84 if (gpio_get_value(output->hpd_gpio) == 0)
82 status = connector_status_disconnected; 85 status = connector_status_disconnected;
@@ -292,6 +295,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
292 encoder = DRM_MODE_ENCODER_DSI; 295 encoder = DRM_MODE_ENCODER_DSI;
293 break; 296 break;
294 297
298 case TEGRA_OUTPUT_EDP:
299 connector = DRM_MODE_CONNECTOR_eDP;
300 encoder = DRM_MODE_ENCODER_TMDS;
301 break;
302
295 default: 303 default:
296 connector = DRM_MODE_CONNECTOR_Unknown; 304 connector = DRM_MODE_CONNECTOR_Unknown;
297 encoder = DRM_MODE_ENCODER_NONE; 305 encoder = DRM_MODE_ENCODER_NONE;
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
new file mode 100644
index 000000000000..49ef5729f435
--- /dev/null
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -0,0 +1,1092 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/clk.h>
10#include <linux/io.h>
11#include <linux/platform_device.h>
12#include <linux/reset.h>
13#include <linux/tegra-powergate.h>
14
15#include <drm/drm_dp_helper.h>
16
17#include "dc.h"
18#include "drm.h"
19#include "sor.h"
20
21struct tegra_sor {
22 struct host1x_client client;
23 struct tegra_output output;
24 struct device *dev;
25
26 void __iomem *regs;
27
28 struct reset_control *rst;
29 struct clk *clk_parent;
30 struct clk *clk_safe;
31 struct clk *clk_dp;
32 struct clk *clk;
33
34 struct tegra_dpaux *dpaux;
35
36 bool enabled;
37};
38
39static inline struct tegra_sor *
40host1x_client_to_sor(struct host1x_client *client)
41{
42 return container_of(client, struct tegra_sor, client);
43}
44
45static inline struct tegra_sor *to_sor(struct tegra_output *output)
46{
47 return container_of(output, struct tegra_sor, output);
48}
49
50static inline unsigned long tegra_sor_readl(struct tegra_sor *sor,
51 unsigned long offset)
52{
53 return readl(sor->regs + (offset << 2));
54}
55
56static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
57 unsigned long offset)
58{
59 writel(value, sor->regs + (offset << 2));
60}
61
62static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
63 struct drm_dp_link *link)
64{
65 unsigned long value;
66 unsigned int i;
67 u8 pattern;
68 int err;
69
70 /* setup lane parameters */
71 value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) |
72 SOR_LANE_DRIVE_CURRENT_LANE2(0x40) |
73 SOR_LANE_DRIVE_CURRENT_LANE1(0x40) |
74 SOR_LANE_DRIVE_CURRENT_LANE0(0x40);
75 tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0);
76
77 value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) |
78 SOR_LANE_PREEMPHASIS_LANE2(0x0f) |
79 SOR_LANE_PREEMPHASIS_LANE1(0x0f) |
80 SOR_LANE_PREEMPHASIS_LANE0(0x0f);
81 tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0);
82
83 value = SOR_LANE_POST_CURSOR_LANE3(0x00) |
84 SOR_LANE_POST_CURSOR_LANE2(0x00) |
85 SOR_LANE_POST_CURSOR_LANE1(0x00) |
86 SOR_LANE_POST_CURSOR_LANE0(0x00);
87 tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0);
88
89 /* disable LVDS mode */
90 tegra_sor_writel(sor, 0, SOR_LVDS);
91
92 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
93 value |= SOR_DP_PADCTL_TX_PU_ENABLE;
94 value &= ~SOR_DP_PADCTL_TX_PU_MASK;
95 value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */
96 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
97
98 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
99 value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
100 SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0;
101 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
102
103 usleep_range(10, 100);
104
105 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
106 value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
107 SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0);
108 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
109
110 err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B);
111 if (err < 0)
112 return err;
113
114 for (i = 0, value = 0; i < link->num_lanes; i++) {
115 unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
116 SOR_DP_TPG_SCRAMBLER_NONE |
117 SOR_DP_TPG_PATTERN_TRAIN1;
118 value = (value << 8) | lane;
119 }
120
121 tegra_sor_writel(sor, value, SOR_DP_TPG);
122
123 pattern = DP_TRAINING_PATTERN_1;
124
125 err = tegra_dpaux_train(sor->dpaux, link, pattern);
126 if (err < 0)
127 return err;
128
129 value = tegra_sor_readl(sor, SOR_DP_SPARE_0);
130 value |= SOR_DP_SPARE_SEQ_ENABLE;
131 value &= ~SOR_DP_SPARE_PANEL_INTERNAL;
132 value |= SOR_DP_SPARE_MACRO_SOR_CLK;
133 tegra_sor_writel(sor, value, SOR_DP_SPARE_0);
134
135 for (i = 0, value = 0; i < link->num_lanes; i++) {
136 unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
137 SOR_DP_TPG_SCRAMBLER_NONE |
138 SOR_DP_TPG_PATTERN_TRAIN2;
139 value = (value << 8) | lane;
140 }
141
142 tegra_sor_writel(sor, value, SOR_DP_TPG);
143
144 pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2;
145
146 err = tegra_dpaux_train(sor->dpaux, link, pattern);
147 if (err < 0)
148 return err;
149
150 for (i = 0, value = 0; i < link->num_lanes; i++) {
151 unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
152 SOR_DP_TPG_SCRAMBLER_GALIOS |
153 SOR_DP_TPG_PATTERN_NONE;
154 value = (value << 8) | lane;
155 }
156
157 tegra_sor_writel(sor, value, SOR_DP_TPG);
158
159 pattern = DP_TRAINING_PATTERN_DISABLE;
160
161 err = tegra_dpaux_train(sor->dpaux, link, pattern);
162 if (err < 0)
163 return err;
164
165 return 0;
166}
167
168static void tegra_sor_super_update(struct tegra_sor *sor)
169{
170 tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
171 tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0);
172 tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
173}
174
175static void tegra_sor_update(struct tegra_sor *sor)
176{
177 tegra_sor_writel(sor, 0, SOR_STATE_0);
178 tegra_sor_writel(sor, 1, SOR_STATE_0);
179 tegra_sor_writel(sor, 0, SOR_STATE_0);
180}
181
182static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
183{
184 unsigned long value;
185
186 value = tegra_sor_readl(sor, SOR_PWM_DIV);
187 value &= ~SOR_PWM_DIV_MASK;
188 value |= 0x400; /* period */
189 tegra_sor_writel(sor, value, SOR_PWM_DIV);
190
191 value = tegra_sor_readl(sor, SOR_PWM_CTL);
192 value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK;
193 value |= 0x400; /* duty cycle */
194 value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */
195 value |= SOR_PWM_CTL_TRIGGER;
196 tegra_sor_writel(sor, value, SOR_PWM_CTL);
197
198 timeout = jiffies + msecs_to_jiffies(timeout);
199
200 while (time_before(jiffies, timeout)) {
201 value = tegra_sor_readl(sor, SOR_PWM_CTL);
202 if ((value & SOR_PWM_CTL_TRIGGER) == 0)
203 return 0;
204
205 usleep_range(25, 100);
206 }
207
208 return -ETIMEDOUT;
209}
210
211static int tegra_sor_attach(struct tegra_sor *sor)
212{
213 unsigned long value, timeout;
214
215 /* wake up in normal mode */
216 value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
217 value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE;
218 value |= SOR_SUPER_STATE_MODE_NORMAL;
219 tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
220 tegra_sor_super_update(sor);
221
222 /* attach */
223 value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
224 value |= SOR_SUPER_STATE_ATTACHED;
225 tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
226 tegra_sor_super_update(sor);
227
228 timeout = jiffies + msecs_to_jiffies(250);
229
230 while (time_before(jiffies, timeout)) {
231 value = tegra_sor_readl(sor, SOR_TEST);
232 if ((value & SOR_TEST_ATTACHED) != 0)
233 return 0;
234
235 usleep_range(25, 100);
236 }
237
238 return -ETIMEDOUT;
239}
240
241static int tegra_sor_wakeup(struct tegra_sor *sor)
242{
243 struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc);
244 unsigned long value, timeout;
245
246 /* enable display controller outputs */
247 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
248 value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
249 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
250 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
251
252 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
253 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
254
255 timeout = jiffies + msecs_to_jiffies(250);
256
257 /* wait for head to wake up */
258 while (time_before(jiffies, timeout)) {
259 value = tegra_sor_readl(sor, SOR_TEST);
260 value &= SOR_TEST_HEAD_MODE_MASK;
261
262 if (value == SOR_TEST_HEAD_MODE_AWAKE)
263 return 0;
264
265 usleep_range(25, 100);
266 }
267
268 return -ETIMEDOUT;
269}
270
271static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
272{
273 unsigned long value;
274
275 value = tegra_sor_readl(sor, SOR_PWR);
276 value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU;
277 tegra_sor_writel(sor, value, SOR_PWR);
278
279 timeout = jiffies + msecs_to_jiffies(timeout);
280
281 while (time_before(jiffies, timeout)) {
282 value = tegra_sor_readl(sor, SOR_PWR);
283 if ((value & SOR_PWR_TRIGGER) == 0)
284 return 0;
285
286 usleep_range(25, 100);
287 }
288
289 return -ETIMEDOUT;
290}
291
292static int tegra_output_sor_enable(struct tegra_output *output)
293{
294 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
295 struct drm_display_mode *mode = &dc->base.mode;
296 unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
297 struct tegra_sor *sor = to_sor(output);
298 unsigned long value;
299 int err;
300
301 if (sor->enabled)
302 return 0;
303
304 err = clk_prepare_enable(sor->clk);
305 if (err < 0)
306 return err;
307
308 reset_control_deassert(sor->rst);
309
310 if (sor->dpaux) {
311 err = tegra_dpaux_enable(sor->dpaux);
312 if (err < 0)
313 dev_err(sor->dev, "failed to enable DP: %d\n", err);
314 }
315
316 err = clk_set_parent(sor->clk, sor->clk_safe);
317 if (err < 0)
318 dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
319
320 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
321 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
322 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
323 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
324
325 value = tegra_sor_readl(sor, SOR_PLL_2);
326 value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
327 tegra_sor_writel(sor, value, SOR_PLL_2);
328 usleep_range(20, 100);
329
330 value = tegra_sor_readl(sor, SOR_PLL_3);
331 value |= SOR_PLL_3_PLL_VDD_MODE_V3_3;
332 tegra_sor_writel(sor, value, SOR_PLL_3);
333
334 value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST |
335 SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT;
336 tegra_sor_writel(sor, value, SOR_PLL_0);
337
338 value = tegra_sor_readl(sor, SOR_PLL_2);
339 value |= SOR_PLL_2_SEQ_PLLCAPPD;
340 value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
341 value |= SOR_PLL_2_LVDS_ENABLE;
342 tegra_sor_writel(sor, value, SOR_PLL_2);
343
344 value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM;
345 tegra_sor_writel(sor, value, SOR_PLL_1);
346
347 while (true) {
348 value = tegra_sor_readl(sor, SOR_PLL_2);
349 if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0)
350 break;
351
352 usleep_range(250, 1000);
353 }
354
355 value = tegra_sor_readl(sor, SOR_PLL_2);
356 value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE;
357 value &= ~SOR_PLL_2_PORT_POWERDOWN;
358 tegra_sor_writel(sor, value, SOR_PLL_2);
359
360 /*
361 * power up
362 */
363
364 /* set safe link bandwidth (1.62 Gbps) */
365 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
366 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
367 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62;
368 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
369
370 /* step 1 */
371 value = tegra_sor_readl(sor, SOR_PLL_2);
372 value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN |
373 SOR_PLL_2_BANDGAP_POWERDOWN;
374 tegra_sor_writel(sor, value, SOR_PLL_2);
375
376 value = tegra_sor_readl(sor, SOR_PLL_0);
377 value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF;
378 tegra_sor_writel(sor, value, SOR_PLL_0);
379
380 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
381 value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
382 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
383
384 /* step 2 */
385 err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
386 if (err < 0) {
387 dev_err(sor->dev, "failed to power on I/O rail: %d\n", err);
388 return err;
389 }
390
391 usleep_range(5, 100);
392
393 /* step 3 */
394 value = tegra_sor_readl(sor, SOR_PLL_2);
395 value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
396 tegra_sor_writel(sor, value, SOR_PLL_2);
397
398 usleep_range(20, 100);
399
400 /* step 4 */
401 value = tegra_sor_readl(sor, SOR_PLL_0);
402 value &= ~SOR_PLL_0_POWER_OFF;
403 value &= ~SOR_PLL_0_VCOPD;
404 tegra_sor_writel(sor, value, SOR_PLL_0);
405
406 value = tegra_sor_readl(sor, SOR_PLL_2);
407 value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
408 tegra_sor_writel(sor, value, SOR_PLL_2);
409
410 usleep_range(200, 1000);
411
412 /* step 5 */
413 value = tegra_sor_readl(sor, SOR_PLL_2);
414 value &= ~SOR_PLL_2_PORT_POWERDOWN;
415 tegra_sor_writel(sor, value, SOR_PLL_2);
416
417 /* switch to DP clock */
418 err = clk_set_parent(sor->clk, sor->clk_dp);
419 if (err < 0)
420 dev_err(sor->dev, "failed to set DP parent clock: %d\n", err);
421
422 /* power dplanes (XXX parameterize based on link?) */
423 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
424 value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
425 SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2;
426 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
427
428 value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
429 value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
430 value |= SOR_DP_LINKCTL_LANE_COUNT(4);
431 tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
432
433 /* start lane sequencer */
434 value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
435 SOR_LANE_SEQ_CTL_POWER_STATE_UP;
436 tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
437
438 while (true) {
439 value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
440 if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
441 break;
442
443 usleep_range(250, 1000);
444 }
445
446 /* set link bandwidth (2.7 GHz, XXX: parameterize based on link?) */
447 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
448 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
449 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70;
450 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
451
452 /* set linkctl */
453 value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
454 value |= SOR_DP_LINKCTL_ENABLE;
455
456 value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK;
457 value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */
458
459 value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
460 tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
461
462 for (i = 0, value = 0; i < 4; i++) {
463 unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
464 SOR_DP_TPG_SCRAMBLER_GALIOS |
465 SOR_DP_TPG_PATTERN_NONE;
466 value = (value << 8) | lane;
467 }
468
469 tegra_sor_writel(sor, value, SOR_DP_TPG);
470
471 value = tegra_sor_readl(sor, SOR_DP_CONFIG_0);
472 value &= ~SOR_DP_CONFIG_WATERMARK_MASK;
473 value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */
474
475 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK;
476 value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */
477
478 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK;
479 value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */
480
481 value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */
482
483 value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE;
484 value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */
485 tegra_sor_writel(sor, value, SOR_DP_CONFIG_0);
486
487 value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS);
488 value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK;
489 value |= 137; /* XXX: don't hardcode? */
490 tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS);
491
492 value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS);
493 value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK;
494 value |= 2368; /* XXX: don't hardcode? */
495 tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS);
496
497 /* enable pad calibration logic */
498 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
499 value |= SOR_DP_PADCTL_PAD_CAL_PD;
500 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
501
502 if (sor->dpaux) {
503 /* FIXME: properly convert to struct drm_dp_aux */
504 struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux;
505 struct drm_dp_link link;
506 u8 rate, lanes;
507
508 err = drm_dp_link_probe(aux, &link);
509 if (err < 0) {
510 dev_err(sor->dev, "failed to probe eDP link: %d\n",
511 err);
512 return err;
513 }
514
515 err = drm_dp_link_power_up(aux, &link);
516 if (err < 0) {
517 dev_err(sor->dev, "failed to power up eDP link: %d\n",
518 err);
519 return err;
520 }
521
522 err = drm_dp_link_configure(aux, &link);
523 if (err < 0) {
524 dev_err(sor->dev, "failed to configure eDP link: %d\n",
525 err);
526 return err;
527 }
528
529 rate = drm_dp_link_rate_to_bw_code(link.rate);
530 lanes = link.num_lanes;
531
532 value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
533 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
534 value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
535 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
536
537 value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
538 value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
539 value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
540
541 if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
542 value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
543
544 tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
545
546 /* disable training pattern generator */
547
548 for (i = 0; i < link.num_lanes; i++) {
549 unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
550 SOR_DP_TPG_SCRAMBLER_GALIOS |
551 SOR_DP_TPG_PATTERN_NONE;
552 value = (value << 8) | lane;
553 }
554
555 tegra_sor_writel(sor, value, SOR_DP_TPG);
556
557 err = tegra_sor_dp_train_fast(sor, &link);
558 if (err < 0) {
559 dev_err(sor->dev, "DP fast link training failed: %d\n",
560 err);
561 return err;
562 }
563
564 dev_dbg(sor->dev, "fast link training succeeded\n");
565 }
566
567 err = tegra_sor_power_up(sor, 250);
568 if (err < 0) {
569 dev_err(sor->dev, "failed to power up SOR: %d\n", err);
570 return err;
571 }
572
573 /* start display controller in continuous mode */
574 value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
575 value |= WRITE_MUX;
576 tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
577
578 tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS);
579 tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
580
581 value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
582 value &= ~WRITE_MUX;
583 tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
584
585 /*
586 * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
587 * raster, associate with display controller)
588 */
589 value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 |
590 SOR_STATE_ASY_VSYNCPOL |
591 SOR_STATE_ASY_HSYNCPOL |
592 SOR_STATE_ASY_PROTOCOL_DP_A |
593 SOR_STATE_ASY_CRC_MODE_COMPLETE |
594 SOR_STATE_ASY_OWNER(dc->pipe + 1);
595 tegra_sor_writel(sor, value, SOR_STATE_1);
596
597 /*
598 * TODO: The video timing programming below doesn't seem to match the
599 * register definitions.
600 */
601
602 value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff);
603 tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0));
604
605 vse = mode->vsync_end - mode->vsync_start - 1;
606 hse = mode->hsync_end - mode->hsync_start - 1;
607
608 value = ((vse & 0x7fff) << 16) | (hse & 0x7fff);
609 tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0));
610
611 vbe = vse + (mode->vsync_start - mode->vdisplay);
612 hbe = hse + (mode->hsync_start - mode->hdisplay);
613
614 value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff);
615 tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0));
616
617 vbs = vbe + mode->vdisplay;
618 hbs = hbe + mode->hdisplay;
619
620 value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff);
621 tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0));
622
623 /* XXX interlaced mode */
624 tegra_sor_writel(sor, 0x00000001, SOR_HEAD_STATE_5(0));
625
626 /* CSTM (LVDS, link A/B, upper) */
627 value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_B | SOR_CSTM_LINK_ACT_B |
628 SOR_CSTM_UPPER;
629 tegra_sor_writel(sor, value, SOR_CSTM);
630
631 /* PWM setup */
632 err = tegra_sor_setup_pwm(sor, 250);
633 if (err < 0) {
634 dev_err(sor->dev, "failed to setup PWM: %d\n", err);
635 return err;
636 }
637
638 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
639 value |= SOR_ENABLE;
640 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
641
642 tegra_sor_update(sor);
643
644 err = tegra_sor_attach(sor);
645 if (err < 0) {
646 dev_err(sor->dev, "failed to attach SOR: %d\n", err);
647 return err;
648 }
649
650 err = tegra_sor_wakeup(sor);
651 if (err < 0) {
652 dev_err(sor->dev, "failed to enable DC: %d\n", err);
653 return err;
654 }
655
656 sor->enabled = true;
657
658 return 0;
659}
660
661static int tegra_sor_detach(struct tegra_sor *sor)
662{
663 unsigned long value, timeout;
664
665 /* switch to safe mode */
666 value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
667 value &= ~SOR_SUPER_STATE_MODE_NORMAL;
668 tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
669 tegra_sor_super_update(sor);
670
671 timeout = jiffies + msecs_to_jiffies(250);
672
673 while (time_before(jiffies, timeout)) {
674 value = tegra_sor_readl(sor, SOR_PWR);
675 if (value & SOR_PWR_MODE_SAFE)
676 break;
677 }
678
679 if ((value & SOR_PWR_MODE_SAFE) == 0)
680 return -ETIMEDOUT;
681
682 /* go to sleep */
683 value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
684 value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
685 tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
686 tegra_sor_super_update(sor);
687
688 /* detach */
689 value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
690 value &= ~SOR_SUPER_STATE_ATTACHED;
691 tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
692 tegra_sor_super_update(sor);
693
694 timeout = jiffies + msecs_to_jiffies(250);
695
696 while (time_before(jiffies, timeout)) {
697 value = tegra_sor_readl(sor, SOR_TEST);
698 if ((value & SOR_TEST_ATTACHED) == 0)
699 break;
700
701 usleep_range(25, 100);
702 }
703
704 if ((value & SOR_TEST_ATTACHED) != 0)
705 return -ETIMEDOUT;
706
707 return 0;
708}
709
710static int tegra_sor_power_down(struct tegra_sor *sor)
711{
712 unsigned long value, timeout;
713 int err;
714
715 value = tegra_sor_readl(sor, SOR_PWR);
716 value &= ~SOR_PWR_NORMAL_STATE_PU;
717 value |= SOR_PWR_TRIGGER;
718 tegra_sor_writel(sor, value, SOR_PWR);
719
720 timeout = jiffies + msecs_to_jiffies(250);
721
722 while (time_before(jiffies, timeout)) {
723 value = tegra_sor_readl(sor, SOR_PWR);
724 if ((value & SOR_PWR_TRIGGER) == 0)
725 return 0;
726
727 usleep_range(25, 100);
728 }
729
730 if ((value & SOR_PWR_TRIGGER) != 0)
731 return -ETIMEDOUT;
732
733 err = clk_set_parent(sor->clk, sor->clk_safe);
734 if (err < 0)
735 dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
736
737 value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
738 value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
739 SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
740 tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
741
742 /* stop lane sequencer */
743 value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
744 SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
745 tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
746
747 timeout = jiffies + msecs_to_jiffies(250);
748
749 while (time_before(jiffies, timeout)) {
750 value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
751 if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
752 break;
753
754 usleep_range(25, 100);
755 }
756
757 if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
758 return -ETIMEDOUT;
759
760 value = tegra_sor_readl(sor, SOR_PLL_2);
761 value |= SOR_PLL_2_PORT_POWERDOWN;
762 tegra_sor_writel(sor, value, SOR_PLL_2);
763
764 usleep_range(20, 100);
765
766 value = tegra_sor_readl(sor, SOR_PLL_0);
767 value |= SOR_PLL_0_POWER_OFF;
768 value |= SOR_PLL_0_VCOPD;
769 tegra_sor_writel(sor, value, SOR_PLL_0);
770
771 value = tegra_sor_readl(sor, SOR_PLL_2);
772 value |= SOR_PLL_2_SEQ_PLLCAPPD;
773 value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
774 tegra_sor_writel(sor, value, SOR_PLL_2);
775
776 usleep_range(20, 100);
777
778 return 0;
779}
780
781static int tegra_output_sor_disable(struct tegra_output *output)
782{
783 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
784 struct tegra_sor *sor = to_sor(output);
785 unsigned long value;
786 int err;
787
788 if (!sor->enabled)
789 return 0;
790
791 err = tegra_sor_detach(sor);
792 if (err < 0) {
793 dev_err(sor->dev, "failed to detach SOR: %d\n", err);
794 return err;
795 }
796
797 tegra_sor_writel(sor, 0, SOR_STATE_1);
798 tegra_sor_update(sor);
799
800 /*
801 * The following accesses registers of the display controller, so make
802 * sure it's only executed when the output is attached to one.
803 */
804 if (dc) {
805 /*
806 * XXX: We can't do this here because it causes the SOR to go
807 * into an erroneous state and the output will look scrambled
808 * the next time it is enabled. Presumably this is because we
809 * should be doing this only on the next VBLANK. A possible
810 * solution would be to queue a "power-off" event to trigger
811 * this code to be run during the next VBLANK.
812 */
813 /*
814 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
815 value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
816 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
817 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
818 */
819
820 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
821 value &= ~DISP_CTRL_MODE_MASK;
822 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
823
824 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
825 value &= ~SOR_ENABLE;
826 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
827
828 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
829 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
830 }
831
832 err = tegra_sor_power_down(sor);
833 if (err < 0) {
834 dev_err(sor->dev, "failed to power down SOR: %d\n", err);
835 return err;
836 }
837
838 if (sor->dpaux) {
839 err = tegra_dpaux_disable(sor->dpaux);
840 if (err < 0) {
841 dev_err(sor->dev, "failed to disable DP: %d\n", err);
842 return err;
843 }
844 }
845
846 err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
847 if (err < 0) {
848 dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
849 return err;
850 }
851
852 reset_control_assert(sor->rst);
853 clk_disable_unprepare(sor->clk);
854
855 sor->enabled = false;
856
857 return 0;
858}
859
860static int tegra_output_sor_setup_clock(struct tegra_output *output,
861 struct clk *clk, unsigned long pclk)
862{
863 struct tegra_sor *sor = to_sor(output);
864 int err;
865
866 /* round to next MHz */
867 pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000;
868
869 err = clk_set_parent(clk, sor->clk_parent);
870 if (err < 0) {
871 dev_err(sor->dev, "failed to set parent clock: %d\n", err);
872 return err;
873 }
874
875 err = clk_set_rate(sor->clk_parent, pclk);
876 if (err < 0) {
877 dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n",
878 pclk * 2);
879 return err;
880 }
881
882 return 0;
883}
884
885static int tegra_output_sor_check_mode(struct tegra_output *output,
886 struct drm_display_mode *mode,
887 enum drm_mode_status *status)
888{
889 /*
890 * FIXME: For now, always assume that the mode is okay.
891 */
892
893 *status = MODE_OK;
894
895 return 0;
896}
897
898static enum drm_connector_status
899tegra_output_sor_detect(struct tegra_output *output)
900{
901 struct tegra_sor *sor = to_sor(output);
902
903 if (sor->dpaux)
904 return tegra_dpaux_detect(sor->dpaux);
905
906 return connector_status_unknown;
907}
908
909static const struct tegra_output_ops sor_ops = {
910 .enable = tegra_output_sor_enable,
911 .disable = tegra_output_sor_disable,
912 .setup_clock = tegra_output_sor_setup_clock,
913 .check_mode = tegra_output_sor_check_mode,
914 .detect = tegra_output_sor_detect,
915};
916
917static int tegra_sor_init(struct host1x_client *client)
918{
919 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
920 struct tegra_sor *sor = host1x_client_to_sor(client);
921 int err;
922
923 if (!sor->dpaux)
924 return -ENODEV;
925
926 sor->output.type = TEGRA_OUTPUT_EDP;
927
928 sor->output.dev = sor->dev;
929 sor->output.ops = &sor_ops;
930
931 err = tegra_output_init(tegra->drm, &sor->output);
932 if (err < 0) {
933 dev_err(sor->dev, "output setup failed: %d\n", err);
934 return err;
935 }
936
937 if (sor->dpaux) {
938 err = tegra_dpaux_attach(sor->dpaux, &sor->output);
939 if (err < 0) {
940 dev_err(sor->dev, "failed to attach DP: %d\n", err);
941 return err;
942 }
943 }
944
945 return 0;
946}
947
948static int tegra_sor_exit(struct host1x_client *client)
949{
950 struct tegra_sor *sor = host1x_client_to_sor(client);
951 int err;
952
953 err = tegra_output_disable(&sor->output);
954 if (err < 0) {
955 dev_err(sor->dev, "output failed to disable: %d\n", err);
956 return err;
957 }
958
959 if (sor->dpaux) {
960 err = tegra_dpaux_detach(sor->dpaux);
961 if (err < 0) {
962 dev_err(sor->dev, "failed to detach DP: %d\n", err);
963 return err;
964 }
965 }
966
967 err = tegra_output_exit(&sor->output);
968 if (err < 0) {
969 dev_err(sor->dev, "output cleanup failed: %d\n", err);
970 return err;
971 }
972
973 return 0;
974}
975
976static const struct host1x_client_ops sor_client_ops = {
977 .init = tegra_sor_init,
978 .exit = tegra_sor_exit,
979};
980
981static int tegra_sor_probe(struct platform_device *pdev)
982{
983 struct device_node *np;
984 struct tegra_sor *sor;
985 struct resource *regs;
986 int err;
987
988 sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL);
989 if (!sor)
990 return -ENOMEM;
991
992 sor->output.dev = sor->dev = &pdev->dev;
993
994 np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0);
995 if (np) {
996 sor->dpaux = tegra_dpaux_find_by_of_node(np);
997 of_node_put(np);
998
999 if (!sor->dpaux)
1000 return -EPROBE_DEFER;
1001 }
1002
1003 err = tegra_output_probe(&sor->output);
1004 if (err < 0)
1005 return err;
1006
1007 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1008 sor->regs = devm_ioremap_resource(&pdev->dev, regs);
1009 if (IS_ERR(sor->regs))
1010 return PTR_ERR(sor->regs);
1011
1012 sor->rst = devm_reset_control_get(&pdev->dev, "sor");
1013 if (IS_ERR(sor->rst))
1014 return PTR_ERR(sor->rst);
1015
1016 sor->clk = devm_clk_get(&pdev->dev, NULL);
1017 if (IS_ERR(sor->clk))
1018 return PTR_ERR(sor->clk);
1019
1020 sor->clk_parent = devm_clk_get(&pdev->dev, "parent");
1021 if (IS_ERR(sor->clk_parent))
1022 return PTR_ERR(sor->clk_parent);
1023
1024 err = clk_prepare_enable(sor->clk_parent);
1025 if (err < 0)
1026 return err;
1027
1028 sor->clk_safe = devm_clk_get(&pdev->dev, "safe");
1029 if (IS_ERR(sor->clk_safe))
1030 return PTR_ERR(sor->clk_safe);
1031
1032 err = clk_prepare_enable(sor->clk_safe);
1033 if (err < 0)
1034 return err;
1035
1036 sor->clk_dp = devm_clk_get(&pdev->dev, "dp");
1037 if (IS_ERR(sor->clk_dp))
1038 return PTR_ERR(sor->clk_dp);
1039
1040 err = clk_prepare_enable(sor->clk_dp);
1041 if (err < 0)
1042 return err;
1043
1044 INIT_LIST_HEAD(&sor->client.list);
1045 sor->client.ops = &sor_client_ops;
1046 sor->client.dev = &pdev->dev;
1047
1048 err = host1x_client_register(&sor->client);
1049 if (err < 0) {
1050 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1051 err);
1052 return err;
1053 }
1054
1055 platform_set_drvdata(pdev, sor);
1056
1057 return 0;
1058}
1059
1060static int tegra_sor_remove(struct platform_device *pdev)
1061{
1062 struct tegra_sor *sor = platform_get_drvdata(pdev);
1063 int err;
1064
1065 err = host1x_client_unregister(&sor->client);
1066 if (err < 0) {
1067 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1068 err);
1069 return err;
1070 }
1071
1072 clk_disable_unprepare(sor->clk_parent);
1073 clk_disable_unprepare(sor->clk_safe);
1074 clk_disable_unprepare(sor->clk_dp);
1075 clk_disable_unprepare(sor->clk);
1076
1077 return 0;
1078}
1079
1080static const struct of_device_id tegra_sor_of_match[] = {
1081 { .compatible = "nvidia,tegra124-sor", },
1082 { },
1083};
1084
1085struct platform_driver tegra_sor_driver = {
1086 .driver = {
1087 .name = "tegra-sor",
1088 .of_match_table = tegra_sor_of_match,
1089 },
1090 .probe = tegra_sor_probe,
1091 .remove = tegra_sor_remove,
1092};
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h
new file mode 100644
index 000000000000..f4156d54cd05
--- /dev/null
+++ b/drivers/gpu/drm/tegra/sor.h
@@ -0,0 +1,278 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRM_TEGRA_SOR_H
10#define DRM_TEGRA_SOR_H
11
12#define SOR_CTXSW 0x00
13
14#define SOR_SUPER_STATE_0 0x01
15
16#define SOR_SUPER_STATE_1 0x02
17#define SOR_SUPER_STATE_ATTACHED (1 << 3)
18#define SOR_SUPER_STATE_MODE_NORMAL (1 << 2)
19#define SOR_SUPER_STATE_HEAD_MODE_MASK (3 << 0)
20#define SOR_SUPER_STATE_HEAD_MODE_AWAKE (2 << 0)
21#define SOR_SUPER_STATE_HEAD_MODE_SNOOZE (1 << 0)
22#define SOR_SUPER_STATE_HEAD_MODE_SLEEP (0 << 0)
23
24#define SOR_STATE_0 0x03
25
26#define SOR_STATE_1 0x04
27#define SOR_STATE_ASY_PIXELDEPTH_MASK (0xf << 17)
28#define SOR_STATE_ASY_PIXELDEPTH_BPP_18_444 (0x2 << 17)
29#define SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 (0x5 << 17)
30#define SOR_STATE_ASY_VSYNCPOL (1 << 13)
31#define SOR_STATE_ASY_HSYNCPOL (1 << 12)
32#define SOR_STATE_ASY_PROTOCOL_MASK (0xf << 8)
33#define SOR_STATE_ASY_PROTOCOL_CUSTOM (0xf << 8)
34#define SOR_STATE_ASY_PROTOCOL_DP_A (0x8 << 8)
35#define SOR_STATE_ASY_PROTOCOL_DP_B (0x9 << 8)
36#define SOR_STATE_ASY_PROTOCOL_LVDS (0x0 << 8)
37#define SOR_STATE_ASY_CRC_MODE_MASK (0x3 << 6)
38#define SOR_STATE_ASY_CRC_MODE_NON_ACTIVE (0x2 << 6)
39#define SOR_STATE_ASY_CRC_MODE_COMPLETE (0x1 << 6)
40#define SOR_STATE_ASY_CRC_MODE_ACTIVE (0x0 << 6)
41#define SOR_STATE_ASY_OWNER(x) (((x) & 0xf) << 0)
42
43#define SOR_HEAD_STATE_0(x) (0x05 + (x))
44#define SOR_HEAD_STATE_1(x) (0x07 + (x))
45#define SOR_HEAD_STATE_2(x) (0x09 + (x))
46#define SOR_HEAD_STATE_3(x) (0x0b + (x))
47#define SOR_HEAD_STATE_4(x) (0x0d + (x))
48#define SOR_HEAD_STATE_5(x) (0x0f + (x))
49#define SOR_CRC_CNTRL 0x11
50#define SOR_DP_DEBUG_MVID 0x12
51
52#define SOR_CLK_CNTRL 0x13
53#define SOR_CLK_CNTRL_DP_LINK_SPEED_MASK (0x1f << 2)
54#define SOR_CLK_CNTRL_DP_LINK_SPEED(x) (((x) & 0x1f) << 2)
55#define SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62 (0x06 << 2)
56#define SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70 (0x0a << 2)
57#define SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40 (0x14 << 2)
58#define SOR_CLK_CNTRL_DP_CLK_SEL_MASK (3 << 0)
59#define SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK (0 << 0)
60#define SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK (1 << 0)
61#define SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK (2 << 0)
62#define SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK (3 << 0)
63
64#define SOR_CAP 0x14
65
66#define SOR_PWR 0x15
67#define SOR_PWR_TRIGGER (1 << 31)
68#define SOR_PWR_MODE_SAFE (1 << 28)
69#define SOR_PWR_NORMAL_STATE_PU (1 << 0)
70
71#define SOR_TEST 0x16
72#define SOR_TEST_ATTACHED (1 << 10)
73#define SOR_TEST_HEAD_MODE_MASK (3 << 8)
74#define SOR_TEST_HEAD_MODE_AWAKE (2 << 8)
75
76#define SOR_PLL_0 0x17
77#define SOR_PLL_0_ICHPMP_MASK (0xf << 24)
78#define SOR_PLL_0_ICHPMP(x) (((x) & 0xf) << 24)
79#define SOR_PLL_0_VCOCAP_MASK (0xf << 8)
80#define SOR_PLL_0_VCOCAP(x) (((x) & 0xf) << 8)
81#define SOR_PLL_0_VCOCAP_RST SOR_PLL_0_VCOCAP(3)
82#define SOR_PLL_0_PLLREG_MASK (0x3 << 6)
83#define SOR_PLL_0_PLLREG_LEVEL(x) (((x) & 0x3) << 6)
84#define SOR_PLL_0_PLLREG_LEVEL_V25 SOR_PLL_0_PLLREG_LEVEL(0)
85#define SOR_PLL_0_PLLREG_LEVEL_V15 SOR_PLL_0_PLLREG_LEVEL(1)
86#define SOR_PLL_0_PLLREG_LEVEL_V35 SOR_PLL_0_PLLREG_LEVEL(2)
87#define SOR_PLL_0_PLLREG_LEVEL_V45 SOR_PLL_0_PLLREG_LEVEL(3)
88#define SOR_PLL_0_PULLDOWN (1 << 5)
89#define SOR_PLL_0_RESISTOR_EXT (1 << 4)
90#define SOR_PLL_0_VCOPD (1 << 2)
91#define SOR_PLL_0_POWER_OFF (1 << 0)
92
93#define SOR_PLL_1 0x18
94/* XXX: read-only bit? */
95#define SOR_PLL_1_TERM_COMPOUT (1 << 15)
96#define SOR_PLL_1_TMDS_TERM (1 << 8)
97
98#define SOR_PLL_2 0x19
99#define SOR_PLL_2_LVDS_ENABLE (1 << 25)
100#define SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE (1 << 24)
101#define SOR_PLL_2_PORT_POWERDOWN (1 << 23)
102#define SOR_PLL_2_BANDGAP_POWERDOWN (1 << 22)
103#define SOR_PLL_2_POWERDOWN_OVERRIDE (1 << 18)
104#define SOR_PLL_2_SEQ_PLLCAPPD (1 << 17)
105
106#define SOR_PLL_3 0x1a
107#define SOR_PLL_3_PLL_VDD_MODE_V1_8 (0 << 13)
108#define SOR_PLL_3_PLL_VDD_MODE_V3_3 (1 << 13)
109
110#define SOR_CSTM 0x1b
111#define SOR_CSTM_LVDS (1 << 16)
112#define SOR_CSTM_LINK_ACT_B (1 << 15)
113#define SOR_CSTM_LINK_ACT_A (1 << 14)
114#define SOR_CSTM_UPPER (1 << 11)
115
116#define SOR_LVDS 0x1c
117#define SOR_CRC_A 0x1d
118#define SOR_CRC_B 0x1e
119#define SOR_BLANK 0x1f
120#define SOR_SEQ_CTL 0x20
121
122#define SOR_LANE_SEQ_CTL 0x21
123#define SOR_LANE_SEQ_CTL_TRIGGER (1 << 31)
124#define SOR_LANE_SEQ_CTL_SEQUENCE_UP (0 << 20)
125#define SOR_LANE_SEQ_CTL_SEQUENCE_DOWN (1 << 20)
126#define SOR_LANE_SEQ_CTL_POWER_STATE_UP (0 << 16)
127#define SOR_LANE_SEQ_CTL_POWER_STATE_DOWN (1 << 16)
128
129#define SOR_SEQ_INST(x) (0x22 + (x))
130
131#define SOR_PWM_DIV 0x32
132#define SOR_PWM_DIV_MASK 0xffffff
133
134#define SOR_PWM_CTL 0x33
135#define SOR_PWM_CTL_TRIGGER (1 << 31)
136#define SOR_PWM_CTL_CLK_SEL (1 << 30)
137#define SOR_PWM_CTL_DUTY_CYCLE_MASK 0xffffff
138
139#define SOR_VCRC_A_0 0x34
140#define SOR_VCRC_A_1 0x35
141#define SOR_VCRC_B_0 0x36
142#define SOR_VCRC_B_1 0x37
143#define SOR_CCRC_A_0 0x38
144#define SOR_CCRC_A_1 0x39
145#define SOR_CCRC_B_0 0x3a
146#define SOR_CCRC_B_1 0x3b
147#define SOR_EDATA_A_0 0x3c
148#define SOR_EDATA_A_1 0x3d
149#define SOR_EDATA_B_0 0x3e
150#define SOR_EDATA_B_1 0x3f
151#define SOR_COUNT_A_0 0x40
152#define SOR_COUNT_A_1 0x41
153#define SOR_COUNT_B_0 0x42
154#define SOR_COUNT_B_1 0x43
155#define SOR_DEBUG_A_0 0x44
156#define SOR_DEBUG_A_1 0x45
157#define SOR_DEBUG_B_0 0x46
158#define SOR_DEBUG_B_1 0x47
159#define SOR_TRIG 0x48
160#define SOR_MSCHECK 0x49
161#define SOR_XBAR_CTRL 0x4a
162#define SOR_XBAR_POL 0x4b
163
164#define SOR_DP_LINKCTL_0 0x4c
165#define SOR_DP_LINKCTL_LANE_COUNT_MASK (0x1f << 16)
166#define SOR_DP_LINKCTL_LANE_COUNT(x) (((1 << (x)) - 1) << 16)
167#define SOR_DP_LINKCTL_ENHANCED_FRAME (1 << 14)
168#define SOR_DP_LINKCTL_TU_SIZE_MASK (0x7f << 2)
169#define SOR_DP_LINKCTL_TU_SIZE(x) (((x) & 0x7f) << 2)
170#define SOR_DP_LINKCTL_ENABLE (1 << 0)
171
172#define SOR_DP_LINKCTL_1 0x4d
173
174#define SOR_LANE_DRIVE_CURRENT_0 0x4e
175#define SOR_LANE_DRIVE_CURRENT_1 0x4f
176#define SOR_LANE4_DRIVE_CURRENT_0 0x50
177#define SOR_LANE4_DRIVE_CURRENT_1 0x51
178#define SOR_LANE_DRIVE_CURRENT_LANE3(x) (((x) & 0xff) << 24)
179#define SOR_LANE_DRIVE_CURRENT_LANE2(x) (((x) & 0xff) << 16)
180#define SOR_LANE_DRIVE_CURRENT_LANE1(x) (((x) & 0xff) << 8)
181#define SOR_LANE_DRIVE_CURRENT_LANE0(x) (((x) & 0xff) << 0)
182
183#define SOR_LANE_PREEMPHASIS_0 0x52
184#define SOR_LANE_PREEMPHASIS_1 0x53
185#define SOR_LANE4_PREEMPHASIS_0 0x54
186#define SOR_LANE4_PREEMPHASIS_1 0x55
187#define SOR_LANE_PREEMPHASIS_LANE3(x) (((x) & 0xff) << 24)
188#define SOR_LANE_PREEMPHASIS_LANE2(x) (((x) & 0xff) << 16)
189#define SOR_LANE_PREEMPHASIS_LANE1(x) (((x) & 0xff) << 8)
190#define SOR_LANE_PREEMPHASIS_LANE0(x) (((x) & 0xff) << 0)
191
192#define SOR_LANE_POST_CURSOR_0 0x56
193#define SOR_LANE_POST_CURSOR_1 0x57
194#define SOR_LANE_POST_CURSOR_LANE3(x) (((x) & 0xff) << 24)
195#define SOR_LANE_POST_CURSOR_LANE2(x) (((x) & 0xff) << 16)
196#define SOR_LANE_POST_CURSOR_LANE1(x) (((x) & 0xff) << 8)
197#define SOR_LANE_POST_CURSOR_LANE0(x) (((x) & 0xff) << 0)
198
199#define SOR_DP_CONFIG_0 0x58
200#define SOR_DP_CONFIG_DISPARITY_NEGATIVE (1 << 31)
201#define SOR_DP_CONFIG_ACTIVE_SYM_ENABLE (1 << 26)
202#define SOR_DP_CONFIG_ACTIVE_SYM_POLARITY (1 << 24)
203#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK (0xf << 16)
204#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC(x) (((x) & 0xf) << 16)
205#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK (0x7f << 8)
206#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT(x) (((x) & 0x7f) << 8)
207#define SOR_DP_CONFIG_WATERMARK_MASK (0x3f << 0)
208#define SOR_DP_CONFIG_WATERMARK(x) (((x) & 0x3f) << 0)
209
210#define SOR_DP_CONFIG_1 0x59
211#define SOR_DP_MN_0 0x5a
212#define SOR_DP_MN_1 0x5b
213
214#define SOR_DP_PADCTL_0 0x5c
215#define SOR_DP_PADCTL_PAD_CAL_PD (1 << 23)
216#define SOR_DP_PADCTL_TX_PU_ENABLE (1 << 22)
217#define SOR_DP_PADCTL_TX_PU_MASK (0xff << 8)
218#define SOR_DP_PADCTL_TX_PU(x) (((x) & 0xff) << 8)
219#define SOR_DP_PADCTL_CM_TXD_3 (1 << 7)
220#define SOR_DP_PADCTL_CM_TXD_2 (1 << 6)
221#define SOR_DP_PADCTL_CM_TXD_1 (1 << 5)
222#define SOR_DP_PADCTL_CM_TXD_0 (1 << 4)
223#define SOR_DP_PADCTL_PD_TXD_3 (1 << 3)
224#define SOR_DP_PADCTL_PD_TXD_0 (1 << 2)
225#define SOR_DP_PADCTL_PD_TXD_1 (1 << 1)
226#define SOR_DP_PADCTL_PD_TXD_2 (1 << 0)
227
228#define SOR_DP_PADCTL_1 0x5d
229
230#define SOR_DP_DEBUG_0 0x5e
231#define SOR_DP_DEBUG_1 0x5f
232
233#define SOR_DP_SPARE_0 0x60
234#define SOR_DP_SPARE_MACRO_SOR_CLK (1 << 2)
235#define SOR_DP_SPARE_PANEL_INTERNAL (1 << 1)
236#define SOR_DP_SPARE_SEQ_ENABLE (1 << 0)
237
238#define SOR_DP_SPARE_1 0x61
239#define SOR_DP_AUDIO_CTRL 0x62
240
241#define SOR_DP_AUDIO_HBLANK_SYMBOLS 0x63
242#define SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK (0x01ffff << 0)
243
244#define SOR_DP_AUDIO_VBLANK_SYMBOLS 0x64
245#define SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK (0x1fffff << 0)
246
247#define SOR_DP_GENERIC_INFOFRAME_HEADER 0x65
248#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_0 0x66
249#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_1 0x67
250#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_2 0x68
251#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_3 0x69
252#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_4 0x6a
253#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_5 0x6b
254#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_6 0x6c
255
256#define SOR_DP_TPG 0x6d
257#define SOR_DP_TPG_CHANNEL_CODING (1 << 6)
258#define SOR_DP_TPG_SCRAMBLER_MASK (3 << 4)
259#define SOR_DP_TPG_SCRAMBLER_FIBONACCI (2 << 4)
260#define SOR_DP_TPG_SCRAMBLER_GALIOS (1 << 4)
261#define SOR_DP_TPG_SCRAMBLER_NONE (0 << 4)
262#define SOR_DP_TPG_PATTERN_MASK (0xf << 0)
263#define SOR_DP_TPG_PATTERN_HBR2 (0x8 << 0)
264#define SOR_DP_TPG_PATTERN_CSTM (0x7 << 0)
265#define SOR_DP_TPG_PATTERN_PRBS7 (0x6 << 0)
266#define SOR_DP_TPG_PATTERN_SBLERRRATE (0x5 << 0)
267#define SOR_DP_TPG_PATTERN_D102 (0x4 << 0)
268#define SOR_DP_TPG_PATTERN_TRAIN3 (0x3 << 0)
269#define SOR_DP_TPG_PATTERN_TRAIN2 (0x2 << 0)
270#define SOR_DP_TPG_PATTERN_TRAIN1 (0x1 << 0)
271#define SOR_DP_TPG_PATTERN_NONE (0x0 << 0)
272
273#define SOR_DP_TPG_CONFIG 0x6e
274#define SOR_DP_LQ_CSTM_0 0x6f
275#define SOR_DP_LQ_CSTM_1 0x70
276#define SOR_DP_LQ_CSTM_2 0x71
277
278#endif