1b9944a77SDirk Eibach /*
2b9944a77SDirk Eibach * (C) Copyright 2012
3b9944a77SDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
4b9944a77SDirk Eibach *
59fab4bf4STom Rini * SPDX-License-Identifier: GPL-2.0+
6b9944a77SDirk Eibach */
7b9944a77SDirk Eibach
8b9944a77SDirk Eibach /* Parade Technologies Inc. DP501 DisplayPort DVI/HDMI Transmitter */
9b9944a77SDirk Eibach
10b9944a77SDirk Eibach #include <common.h>
11b9944a77SDirk Eibach #include <asm/io.h>
12b9944a77SDirk Eibach #include <errno.h>
13b9944a77SDirk Eibach #include <i2c.h>
14b9944a77SDirk Eibach
15*e9cb21d0SDirk Eibach #define DP501_I2C_ADDR 0x08
16*e9cb21d0SDirk Eibach
17*e9cb21d0SDirk Eibach #ifdef CONFIG_SYS_DP501_I2C
18*e9cb21d0SDirk Eibach int dp501_i2c[] = CONFIG_SYS_DP501_I2C;
19*e9cb21d0SDirk Eibach #endif
20*e9cb21d0SDirk Eibach
21*e9cb21d0SDirk Eibach #ifdef CONFIG_SYS_DP501_BASE
22*e9cb21d0SDirk Eibach int dp501_base[] = CONFIG_SYS_DP501_BASE;
23*e9cb21d0SDirk Eibach #endif
24*e9cb21d0SDirk Eibach
dp501_setbits(u8 addr,u8 reg,u8 mask)25b9944a77SDirk Eibach static void dp501_setbits(u8 addr, u8 reg, u8 mask)
26b9944a77SDirk Eibach {
27b9944a77SDirk Eibach u8 val;
28b9944a77SDirk Eibach
29b9944a77SDirk Eibach val = i2c_reg_read(addr, reg);
30b9944a77SDirk Eibach setbits_8(&val, mask);
31b9944a77SDirk Eibach i2c_reg_write(addr, reg, val);
32b9944a77SDirk Eibach }
33b9944a77SDirk Eibach
dp501_clrbits(u8 addr,u8 reg,u8 mask)34b9944a77SDirk Eibach static void dp501_clrbits(u8 addr, u8 reg, u8 mask)
35b9944a77SDirk Eibach {
36b9944a77SDirk Eibach u8 val;
37b9944a77SDirk Eibach
38b9944a77SDirk Eibach val = i2c_reg_read(addr, reg);
39b9944a77SDirk Eibach clrbits_8(&val, mask);
40b9944a77SDirk Eibach i2c_reg_write(addr, reg, val);
41b9944a77SDirk Eibach }
42b9944a77SDirk Eibach
dp501_detect_cable_adapter(u8 addr)43b9944a77SDirk Eibach static int dp501_detect_cable_adapter(u8 addr)
44b9944a77SDirk Eibach {
45b9944a77SDirk Eibach u8 val = i2c_reg_read(addr, 0x00);
46b9944a77SDirk Eibach
47b9944a77SDirk Eibach return !(val & 0x04);
48b9944a77SDirk Eibach }
49b9944a77SDirk Eibach
dp501_link_training(u8 addr)50b9944a77SDirk Eibach static void dp501_link_training(u8 addr)
51b9944a77SDirk Eibach {
52b9944a77SDirk Eibach u8 val;
53d054c2f8SDirk Eibach u8 link_bw;
54d054c2f8SDirk Eibach u8 max_lane_cnt;
55d054c2f8SDirk Eibach u8 lane_cnt;
56b9944a77SDirk Eibach
57b9944a77SDirk Eibach val = i2c_reg_read(addr, 0x51);
58d054c2f8SDirk Eibach if (val >= 0x0a)
59d054c2f8SDirk Eibach link_bw = 0x0a;
60d054c2f8SDirk Eibach else
61d054c2f8SDirk Eibach link_bw = 0x06;
62d054c2f8SDirk Eibach if (link_bw != val)
63d054c2f8SDirk Eibach printf("DP sink supports %d Mbps link rate, set to %d Mbps\n",
64d054c2f8SDirk Eibach val * 270, link_bw * 270);
65d054c2f8SDirk Eibach i2c_reg_write(addr, 0x5d, link_bw); /* set link_bw */
66b9944a77SDirk Eibach val = i2c_reg_read(addr, 0x52);
67d054c2f8SDirk Eibach max_lane_cnt = val & 0x1f;
68d054c2f8SDirk Eibach if (max_lane_cnt >= 4)
69d054c2f8SDirk Eibach lane_cnt = 4;
70d054c2f8SDirk Eibach else
71d054c2f8SDirk Eibach lane_cnt = max_lane_cnt;
72d054c2f8SDirk Eibach if (lane_cnt != max_lane_cnt)
73d054c2f8SDirk Eibach printf("DP sink supports %d lanes, set to %d lanes\n",
74d054c2f8SDirk Eibach max_lane_cnt, lane_cnt);
75d054c2f8SDirk Eibach i2c_reg_write(addr, 0x5e, lane_cnt | (val & 0x80)); /* set lane_cnt */
76b9944a77SDirk Eibach val = i2c_reg_read(addr, 0x53);
77b9944a77SDirk Eibach i2c_reg_write(addr, 0x5c, val); /* set downspread_ctl */
78b9944a77SDirk Eibach
79b9944a77SDirk Eibach i2c_reg_write(addr, 0x5f, 0x0d); /* start training */
80b9944a77SDirk Eibach }
81b9944a77SDirk Eibach
dp501_powerup(u8 addr)82b9944a77SDirk Eibach void dp501_powerup(u8 addr)
83b9944a77SDirk Eibach {
84b9944a77SDirk Eibach dp501_clrbits(addr, 0x0a, 0x30); /* power on encoder */
855568fb44SDirk Eibach dp501_setbits(addr, 0x0a, 0x0e); /* block HDCP and MCCS on I2C bride*/
86b9944a77SDirk Eibach i2c_reg_write(addr, 0x27, 0x30); /* Hardware auto detect DVO timing */
87b9944a77SDirk Eibach dp501_setbits(addr, 0x72, 0x80); /* DPCD read enable */
88b9944a77SDirk Eibach dp501_setbits(addr, 0x30, 0x20); /* RS polynomial select */
89b9944a77SDirk Eibach i2c_reg_write(addr, 0x71, 0x20); /* Enable Aux burst write */
90b9944a77SDirk Eibach dp501_setbits(addr, 0x78, 0x30); /* Disable HPD2 IRQ */
91b9944a77SDirk Eibach dp501_clrbits(addr, 0x2f, 0x40); /* Link FIFO reset selection */
92b415fec6SDirk Eibach dp501_clrbits(addr, 0x60, 0x20); /* Enable scrambling */
93b9944a77SDirk Eibach
94edfe9feaSDirk Eibach #ifdef CONFIG_SYS_DP501_VCAPCTRL0
95edfe9feaSDirk Eibach i2c_reg_write(addr, 0x24, CONFIG_SYS_DP501_VCAPCTRL0);
96edfe9feaSDirk Eibach #else
97edfe9feaSDirk Eibach i2c_reg_write(addr, 0x24, 0xc0); /* SDR mode 0, ext. H/VSYNC */
98edfe9feaSDirk Eibach #endif
99edfe9feaSDirk Eibach
100edfe9feaSDirk Eibach #ifdef CONFIG_SYS_DP501_DIFFERENTIAL
101edfe9feaSDirk Eibach i2c_reg_write(addr + 2, 0x24, 0x10); /* clock input differential */
102edfe9feaSDirk Eibach i2c_reg_write(addr + 2, 0x25, 0x04);
103edfe9feaSDirk Eibach i2c_reg_write(addr + 2, 0x26, 0x10);
104edfe9feaSDirk Eibach #else
105edfe9feaSDirk Eibach i2c_reg_write(addr + 2, 0x24, 0x02); /* clock input single ended */
106edfe9feaSDirk Eibach #endif
107edfe9feaSDirk Eibach
1080caad193SDirk Eibach i2c_reg_write(addr + 2, 0x1a, 0x04); /* SPDIF input method TTL */
1090caad193SDirk Eibach
110b9944a77SDirk Eibach i2c_reg_write(addr + 2, 0x00, 0x18); /* driving strength */
111b9944a77SDirk Eibach i2c_reg_write(addr + 2, 0x03, 0x06); /* driving strength */
112b9944a77SDirk Eibach i2c_reg_write(addr, 0x2c, 0x00); /* configure N value */
113b9944a77SDirk Eibach i2c_reg_write(addr, 0x2d, 0x00); /* configure N value */
114b9944a77SDirk Eibach i2c_reg_write(addr, 0x2e, 0x0c); /* configure N value */
115b9944a77SDirk Eibach i2c_reg_write(addr, 0x76, 0xff); /* clear all interrupt */
116b9944a77SDirk Eibach dp501_setbits(addr, 0x78, 0x03); /* clear all interrupt */
117b9944a77SDirk Eibach i2c_reg_write(addr, 0x75, 0xf8); /* aux channel reset */
118b9944a77SDirk Eibach i2c_reg_write(addr, 0x75, 0x00); /* clear aux channel reset */
1192302fd32SDirk Eibach i2c_reg_write(addr, 0x87, 0x7f); /* set retry counter as 7
1202302fd32SDirk Eibach retry interval 400us */
121edfe9feaSDirk Eibach
122edfe9feaSDirk Eibach if (dp501_detect_cable_adapter(addr)) {
123edfe9feaSDirk Eibach printf("DVI/HDMI cable adapter detected\n");
124edfe9feaSDirk Eibach i2c_reg_write(addr, 0x5e, 0x04); /* enable 4 channel */
125edfe9feaSDirk Eibach dp501_clrbits(addr, 0x00, 0x08); /* DVI/HDMI HDCP operation */
126edfe9feaSDirk Eibach } else {
127edfe9feaSDirk Eibach printf("no DVI/HDMI cable adapter detected\n");
128b9944a77SDirk Eibach dp501_setbits(addr, 0x00, 0x08); /* for DP HDCP operation */
129b9944a77SDirk Eibach
130b9944a77SDirk Eibach dp501_link_training(addr);
131b9944a77SDirk Eibach }
132b9944a77SDirk Eibach }
133b9944a77SDirk Eibach
dp501_powerdown(u8 addr)134b9944a77SDirk Eibach void dp501_powerdown(u8 addr)
135b9944a77SDirk Eibach {
136b9944a77SDirk Eibach dp501_setbits(addr, 0x0a, 0x30); /* power down encoder, standby mode */
137b9944a77SDirk Eibach }
138*e9cb21d0SDirk Eibach
139*e9cb21d0SDirk Eibach
dp501_probe(unsigned screen,bool power)140*e9cb21d0SDirk Eibach int dp501_probe(unsigned screen, bool power)
141*e9cb21d0SDirk Eibach {
142*e9cb21d0SDirk Eibach #ifdef CONFIG_SYS_DP501_BASE
143*e9cb21d0SDirk Eibach uint8_t dp501_addr = dp501_base[screen];
144*e9cb21d0SDirk Eibach #else
145*e9cb21d0SDirk Eibach uint8_t dp501_addr = DP501_I2C_ADDR;
146*e9cb21d0SDirk Eibach #endif
147*e9cb21d0SDirk Eibach
148*e9cb21d0SDirk Eibach #ifdef CONFIG_SYS_DP501_I2C
149*e9cb21d0SDirk Eibach i2c_set_bus_num(dp501_i2c[screen]);
150*e9cb21d0SDirk Eibach #endif
151*e9cb21d0SDirk Eibach
152*e9cb21d0SDirk Eibach if (i2c_probe(dp501_addr))
153*e9cb21d0SDirk Eibach return -1;
154*e9cb21d0SDirk Eibach
155*e9cb21d0SDirk Eibach dp501_powerup(dp501_addr);
156*e9cb21d0SDirk Eibach
157*e9cb21d0SDirk Eibach return 0;
158*e9cb21d0SDirk Eibach }
159