xref: /rk3399_rockchip-uboot/board/gdsys/common/dp501.c (revision e9cb21d0e891e95350da6ec3f8623018fd246187)
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