blob: 9937cfe095bc0289ba8cacc6fde9f5e8d486d2f7 [file] [log] [blame]
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2024 Jonas Schwöbel <jonasschwoebel@yahoo.de>
4 * Copyright (C) 2024 Svyatoslav Ryhel <clamor95@gmail.com>
5 */
6
7#include <dm.h>
8#include <i2c.h>
9#include <log.h>
10#include <backlight.h>
11#include <panel.h>
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +020012#include <video_bridge.h>
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +020013#include <linux/delay.h>
14#include <linux/err.h>
15#include <power/regulator.h>
16
17#include <asm/gpio.h>
18
19/* TOP */
20#define TOPCFG0 0x00
21#define ROMI2C_PRESCALE 0x01
22#define HDCPI2C_PRESCALE 0x02
23#define GPIO 0x03
24#define GPIO_OUT_ENB 0x04
25#define TESTI2C_CTL 0x05
26#define I2CMTIMEOUT 0x06
27#define TOPCFG1 0x07
28#define TOPCFG2 0x08
29#define TOPCFG3 0x09
30#define TOPCFG4 0x0A
31#define CLKSWRST 0x0B
32#define CADETB_CTL 0x0C
33
34/* Video Attribute */
35#define HTOTAL_L 0x10
36#define HTOTAL_H 0x11
37#define HSTART_L 0x12
38#define HSTART_H 0x13
39#define HWIDTH_L 0x14
40#define HWIDTH_H 0x15
41#define VTOTAL_L 0x16
42#define VTOTAL_H 0x17
43#define VSTART_L 0x18
44#define VSTART_H 0x19
45#define VHEIGHT_L 0x1A
46#define VHEIGHT_H 0x1B
47#define HSPHSW_L 0x1C
48#define HSPHSW_H 0x1D
49#define VSPVSW_L 0x1E
50#define VSPVSW_H 0x1F
51#define MISC0 0x20
52#define MISC1 0x21
53
54/* Video Capture */
55#define VCAPCTRL0 0x24
56#define VCAPCTRL1 0x25
57#define VCAPCTRL2 0x26
58#define VCAPCTRL3 0x27
59#define VCAPCTRL4 0x28
60#define VCAP_MEASURE 0x29
61
62/* Main Link Control */
63#define NVID_L 0x2C
64#define NVID_M 0x2D
65#define NVID_H 0x2E
66#define LINK_CTRL0 0x2F
67#define LINK_CTRL1 0x30
68#define LINK_DEBUG 0x31
69#define ERR_POS 0x32
70#define ERR_PAT 0x33
71#define LINK_DEB_SEL 0x34
72#define IDLE_PATTERN 0x35
73#define TU_SIZE 0x36
74#define CRC_CTRL 0x37
75#define CRC_OUT 0x38
76
77/* AVI-2 InfoFrame */
78#define SD_CTRL0 0x3A
79#define SD_CTRL1 0x3B
80#define SD_HB0 0x3C
81#define SD_HB1 0x3D
82#define SD_HB2 0x3E
83#define SD_HB3 0x3F
84#define SD_DB0 0x40
85#define SD_DB1 0x41
86#define SD_DB2 0x42
87#define SD_DB3 0x43
88#define SD_DB4 0x44
89#define SD_DB5 0x45
90#define SD_DB6 0x46
91#define SD_DB7 0x47
92#define SD_DB8 0x48
93#define SD_DB9 0x49
94#define SD_DB10 0x4A
95#define SD_DB11 0x4B
96#define SD_DB12 0x4C
97#define SD_DB13 0x4D
98#define SD_DB14 0x4E
99#define SD_DB15 0x4F
100
101/* Aux Channel and PCS */
102#define DPCD_REV 0X50
103#define MAX_LINK_RATE 0x51
104#define MAX_LANE_COUNT 0x52
105#define MAX_DOWNSPREAD 0x53
106#define NORP 0x54
107#define DOWNSTRMPORT_PRE 0x55
108#define MLINK_CH_CODING 0x56
109#define RCV_P0_CAP0 0x58
110#define RCV_P0_CAP1 0x59
111#define RCV_P1_CAP0 0x5A
112#define RCV_P1_CAP1 0x5B
113#define DOWNSPREAD_CTL 0x5C
114#define LINK_BW 0x5D
115#define LANE_CNT 0x5E
116#define TRAINING_CTL 0x5F
117#define QUALTEST_CTL 0x60
118#define SINK_COUNT 0x61
119#define DEV_SERVICE_IRQ 0x62
120#define LANE01_STATUS 0x63
121#define LANE23_STATUS 0x64
122#define LANE_STATUS_UPDATE 0x65
123#define SINK_STATUS 0x66
124#define AUX_NOISE 0x67
125#define TEST_MODE 0x69
126#define TEST_PATTERN0 0x6A
127#define TEST_PATTERN1 0x6B
128#define TEST_PATTERN2 0x6C
129#define SIGNATURE 0x6D
130#define PCSCFG 0x6E
131#define AUXCTRL0 0x6f
132#define AUXCTRL2 0x70
133#define AUXCTRL1 0x71
134#define HPDCTL0 0x72
135#define HPDCTL1 0x73
136#define LINK_STATE_CTRL 0x74
137#define SWRST 0x75
138#define LINK_IRQ 0x76
139#define AUXIRQ_CTRL 0x77
140#define HPD2_IRQ_CTRL 0x78
141#define SW_TRAIN_CTRL 0x79
142#define SW_DRV_SET 0x7A
143#define SW_PRE_SET 0x7B
144#define DPCD_ADDR_L 0x7D
145#define DPCD_ADDR_M 0x7E
146#define DPCD_ADDR_H 0x7F
147#define DPCD_LENGTH 0x80
148#define DPCD_WDATA 0x81
149#define DPCD_RDATA 0x82
150#define DPCD_CTL 0x83
151#define DPCD_STATUS 0x84
152#define AUX_STATUS 0x85
153#define I2CTOAUX_RELENGTH 0x86
154#define AUX_RETRY_CTRL 0x87
155#define TIMEOUT_CTRL 0x88
156#define I2CCMD_OPT1 0x89
157#define AUXCMD_ERR_IRQ 0x8A
158#define AUXCMD_OPT2 0x8B
159#define HDCP_Reserved 0x8C
160
161/* Audio InfoFrame */
162#define TX_MVID0 0x90
163#define TX_MVID1 0x91
164#define TX_MVID2 0x92
165#define TX_MVID_OFF 0x93
166#define TX_MAUD0 0x94
167#define TX_MAUD1 0x95
168#define TX_MAUD2 0x96
169#define TX_MAUD_OFF 0x97
170#define MN_CTRL 0x98
171#define MOUT0 0x99
172#define MOUT1 0x9A
173#define MOUT2 0x9B
174
175/* Audio Control */
176#define NAUD_L 0x9F
177#define NAUD_M 0xA0
178#define NAUD_H 0xA1
179#define AUD_CTRL0 0xA2
180#define AUD_CTRL1 0xA3
181#define LANE_POL 0xAA
182#define LANE_EN 0xAB
183#define LANE_MAP 0xAC
184#define SCR_POLY0 0xAD
185#define SCR_POLY1 0xAE
186#define PRBS7_POLY 0xAF
187
188/* Video Pre-process */
189#define MISC_SHDOW 0xB0
190#define VCAPCPCTL0 0xB1
191#define VCAPCPCTL1 0xB2
192#define VCAPCPCTL2 0xB3
193#define CSCPAR 0xB4
194#define I2CTODPCDSTATUS2 0xBA
195#define AUXCTL_REG 0xBB
196
197/* Page 2 */
198#define SEL_PIO1 0x24
199#define SEL_PIO2 0x25
200#define SEL_PIO3 0x26
201#define CHIP_VER_L 0x82
202
203struct dp501_priv {
204 struct udevice *panel;
205 struct display_timing timing;
206
207 struct udevice *chip2;
208
209 struct udevice *vdd;
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200210 struct gpio_desc enable_gpio;
211};
212
213static int dp501_sw_init(struct udevice *dev)
214{
215 struct dp501_priv *priv = dev_get_priv(dev);
216 int i;
217 u8 val;
218
219 dm_i2c_reg_write(dev, TOPCFG4, 0x30);
220 udelay(200);
221 dm_i2c_reg_write(dev, TOPCFG4, 0x0c);
222 dm_i2c_reg_write(dev, 0x8f, 0x02);
223
224 /* check for connected panel during 1 msec */
225 for (i = 0; i < 5; i++) {
226 val = dm_i2c_reg_read(dev, 0x8d);
227 val &= BIT(2);
228 if (val)
229 break;
230
231 udelay(200);
232 }
233
234 if (!val) {
235 log_debug("%s: panel is not connected!\n", __func__);
236 return -ENODEV;
237 }
238
239 dm_i2c_reg_write(priv->chip2, SEL_PIO1, 0x02);
240 dm_i2c_reg_write(priv->chip2, SEL_PIO2, 0x04);
241 dm_i2c_reg_write(priv->chip2, SEL_PIO3, 0x10);
242
243 dm_i2c_reg_write(dev, LINK_STATE_CTRL, 0xa0);
244 dm_i2c_reg_write(dev, 0x8f, 0x02);
245 dm_i2c_reg_write(dev, TOPCFG1, 0x16);
246 dm_i2c_reg_write(dev, TOPCFG0, 0x24);
247 dm_i2c_reg_write(dev, HPD2_IRQ_CTRL, 0x30);
248 dm_i2c_reg_write(dev, AUXIRQ_CTRL, 0xff);
249 dm_i2c_reg_write(dev, LINK_IRQ, 0xff);
250
251 /* auto detect DVO timing */
252 dm_i2c_reg_write(dev, VCAPCTRL3, 0x30);
253
254 /* reset tpfifo at v blank */
255 dm_i2c_reg_write(dev, LINK_CTRL0, 0x82);
256
257 dm_i2c_reg_write(dev, VCAPCTRL4, 0x07);
258 dm_i2c_reg_write(dev, AUX_RETRY_CTRL, 0x7f);
259 dm_i2c_reg_write(dev, TIMEOUT_CTRL, 0x1e);
260 dm_i2c_reg_write(dev, AUXCTL_REG, 0x06);
261
262 /* DPCD readable */
263 dm_i2c_reg_write(dev, HPDCTL0, 0xa9);
264
265 /* Scramble on */
266 dm_i2c_reg_write(dev, QUALTEST_CTL, 0x00);
267
268 dm_i2c_reg_write(dev, 0x8f, 0x02);
269
270 dm_i2c_reg_write(dev, VCAPCTRL0, 0xc4);
271
272 /* set color depth 8bit (0x00: 6bit; 0x20: 8bit; 0x40: 10bit) */
273 dm_i2c_reg_write(dev, MISC0, 0x20);
274
275 dm_i2c_reg_write(dev, VCAPCPCTL2, 0x01);
276
277 /* check if bridge returns ready status */
278 for (i = 0; i < 5; i++) {
279 val = dm_i2c_reg_read(dev, LINK_IRQ);
280 val &= BIT(0);
281 if (val)
282 break;
283
284 udelay(200);
285 }
286
287 if (!val) {
288 log_debug("%s: bridge is not ready\n", __func__);
289 return -ENODEV;
290 }
291
292 return 0;
293}
294
295static void dpcd_configure(struct udevice *dev, u32 config, bool write)
296{
297 dm_i2c_reg_write(dev, DPCD_ADDR_L, (u8)(config >> 8));
298 dm_i2c_reg_write(dev, DPCD_ADDR_M, (u8)(config >> 16));
299 dm_i2c_reg_write(dev, DPCD_ADDR_H, (u8)((config >> 24) | BIT(7)));
300 dm_i2c_reg_write(dev, DPCD_LENGTH, 0x00);
301 dm_i2c_reg_write(dev, LINK_IRQ, 0x20);
302
303 if (write)
304 dm_i2c_reg_write(dev, DPCD_WDATA, (u8)(config & 0xff));
305
306 dm_i2c_reg_write(dev, DPCD_CTL, 0x01);
307
308 udelay(10);
309}
310
311static int dump_dpcd_data(struct udevice *dev, u32 config, u8 *data)
312{
313 int i;
314 u8 value;
315
316 dpcd_configure(dev, config, false);
317
318 value = dm_i2c_reg_read(dev, DPCD_CTL);
319 if (value)
320 return -ENODATA;
321
322 for (i = 0; i < 5; i++) {
323 value = dm_i2c_reg_read(dev, LINK_IRQ);
324 value &= BIT(5);
325 if (value)
326 break;
327
328 udelay(100);
329 }
330
331 if (!value)
332 return -ENODATA;
333
334 value = dm_i2c_reg_read(dev, DPCD_STATUS);
335 if (!(value & 0xe0))
336 *data = dm_i2c_reg_read(dev, DPCD_RDATA);
337 else
338 return -ENODATA;
339
340 return 0;
341}
342
343static int dp501_dpcd_dump(struct udevice *dev, u32 config, u8 *data)
344{
345 int i, ret;
346
347 for (i = 0; i < 5; i++) {
348 ret = dump_dpcd_data(dev, config, data);
349 if (!ret)
350 break;
351
352 udelay(100);
353 }
354
355 return ret;
356}
357
358static int dp501_reset_link(struct udevice *dev)
359{
360 dm_i2c_reg_write(dev, TRAINING_CTL, 0x00);
361 dm_i2c_reg_write(dev, SWRST, 0xf8);
362 dm_i2c_reg_write(dev, SWRST, 0x00);
363
364 return -ENODEV;
365}
366
367static int dp501_link_training(struct udevice *dev)
368{
369 int i, ret;
370 u8 lane, link, link_out;
371 u8 lane_cnt, lane01, lane23;
372
373 dpcd_configure(dev, 0x030000, true);
374 dpcd_configure(dev, 0x03011c, true);
375 dpcd_configure(dev, 0x0301f8, true);
376
377 ret = dp501_dpcd_dump(dev, 0x90000100, &link);
378 if (ret) {
379 log_debug("%s: link dump failed %d\n", __func__, ret);
380 return dp501_reset_link(dev);
381 }
382
383 ret = dp501_dpcd_dump(dev, 0x90000200, &lane);
384 if (ret) {
385 log_debug("%s: lane dump failed %d\n", __func__, ret);
386 return dp501_reset_link(dev);
387 }
388
389 /* Software trainig */
390 for (i = 10; i > 0; i--) {
391 dm_i2c_reg_write(dev, LINK_BW, link);
392 dm_i2c_reg_write(dev, LANE_CNT, lane | BIT(7));
393
394 link_out = dm_i2c_reg_read(dev, LINK_BW);
395 lane_cnt = dm_i2c_reg_read(dev, LANE_CNT);
396
397 if (link_out == link &&
398 (lane_cnt == (lane | BIT(7))))
399 break;
400
401 udelay(500);
402 }
403
404 if (!i)
405 return dp501_reset_link(dev);
406
407 dm_i2c_reg_write(dev, LINK_STATE_CTRL, 0x00);
408 dm_i2c_reg_write(dev, TRAINING_CTL, 0x0d);
409
410 /* check if bridge returns link ready status */
411 for (i = 0; i < 100; i++) {
412 link_out = dm_i2c_reg_read(dev, LINK_IRQ);
413 link_out &= BIT(1);
414 if (link_out) {
415 dm_i2c_reg_write(dev, LINK_IRQ, 0xff);
416 break;
417 }
418
419 udelay(100);
420 }
421
422 if (!link_out) {
423 log_debug("%s: link prepare failed %d\n",
424 __func__, link_out);
425 return dp501_reset_link(dev);
426 }
427
428 lane01 = dm_i2c_reg_read(dev, LANE01_STATUS);
429 lane23 = dm_i2c_reg_read(dev, LANE23_STATUS);
430
431 switch (lane_cnt & 0xf) {
432 case 4:
433 if (lane01 == 0x77 &&
434 lane23 == 0x77)
435 return 0;
436 break;
437
438 case 2:
439 if (lane01 == 0x77)
440 return 0;
441 break;
442
443 default:
444 if ((lane01 & 7) == 7)
445 return 0;
446 break;
447 }
448
449 return dp501_reset_link(dev);
450}
451
452static int dp501_attach(struct udevice *dev)
453{
454 struct dp501_priv *priv = dev_get_priv(dev);
455 int ret;
456
457 ret = dp501_sw_init(dev);
458 if (ret)
459 return ret;
460
461 mdelay(90);
462
463 ret = dp501_link_training(dev);
464 if (ret)
465 return ret;
466
467 /* Perform panel HW setup */
468 return panel_enable_backlight(priv->panel);
469}
470
471static int dp501_set_backlight(struct udevice *dev, int percent)
472{
473 struct dp501_priv *priv = dev_get_priv(dev);
474
475 return panel_set_backlight(priv->panel, percent);
476}
477
478static int dp501_panel_timings(struct udevice *dev,
479 struct display_timing *timing)
480{
481 struct dp501_priv *priv = dev_get_priv(dev);
482
483 memcpy(timing, &priv->timing, sizeof(*timing));
484 return 0;
485}
486
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200487static void dp501_hw_init(struct udevice *dev)
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200488{
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200489 struct dp501_priv *priv = dev_get_priv(dev);
490 struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
491
492 dm_gpio_set_value(&uc_priv->reset, 1);
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200493
494 regulator_set_enable_if_allowed(priv->vdd, 1);
495 dm_gpio_set_value(&priv->enable_gpio, 1);
496
497 udelay(100);
498
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200499 dm_gpio_set_value(&uc_priv->reset, 0);
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200500 mdelay(80);
501}
502
503static int dp501_setup(struct udevice *dev)
504{
505 struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
506 struct dp501_priv *priv = dev_get_priv(dev);
507 struct udevice *bus = dev_get_parent(dev);
508 int ret;
509
510 /* get panel */
511 ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
512 "panel", &priv->panel);
513 if (ret) {
514 log_debug("%s: Cannot get panel: ret=%d\n", __func__, ret);
515 return log_ret(ret);
516 }
517
518 /* get regulators */
519 ret = device_get_supply_regulator(dev, "power-supply", &priv->vdd);
520 if (ret) {
521 log_debug("%s: vddc regulator error: %d\n", __func__, ret);
522 if (ret != -ENOENT)
523 return log_ret(ret);
524 }
525
526 /* get gpios */
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200527 ret = gpio_request_by_name(dev, "enable-gpios", 0,
528 &priv->enable_gpio, GPIOD_IS_OUT);
529 if (ret) {
530 log_debug("%s: Could not decode enable-gpios (%d)\n",
531 __func__, ret);
532 return ret;
533 }
534
535 ret = i2c_get_chip(bus, chip->chip_addr + 2, 1, &priv->chip2);
536 if (ret) {
537 log_debug("%s: cannot get second PMIC I2C chip (err %d)\n",
538 __func__, ret);
539 return ret;
540 }
541
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200542 dp501_hw_init(dev);
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200543
544 /* get EDID */
545 return panel_get_display_timing(priv->panel, &priv->timing);
546}
547
548static int dp501_probe(struct udevice *dev)
549{
550 if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
551 return -EPROTONOSUPPORT;
552
553 return dp501_setup(dev);
554}
555
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200556static const struct video_bridge_ops dp501_ops = {
557 .attach = dp501_attach,
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200558 .set_backlight = dp501_set_backlight,
559 .get_display_timing = dp501_panel_timings,
560};
561
562static const struct udevice_id dp501_ids[] = {
563 { .compatible = "parade,dp501" },
564 { }
565};
566
567U_BOOT_DRIVER(dp501) = {
568 .name = "dp501",
Svyatoslav Ryhel76600db2025-02-14 15:29:19 +0200569 .id = UCLASS_VIDEO_BRIDGE,
Jonas Schwöbel74ba48f2024-01-31 08:57:18 +0200570 .of_match = dp501_ids,
571 .ops = &dp501_ops,
572 .probe = dp501_probe,
573 .priv_auto = sizeof(struct dp501_priv),
574};