xref: /rk3399_rockchip-uboot/drivers/video/drm/rk628/rk628.c (revision ab3bc87339b1566ceabcfb54995e11928492c356)
1*ab3bc873SGuochun Huang // SPDX-License-Identifier: GPL-2.0+
2*ab3bc873SGuochun Huang /*
3*ab3bc873SGuochun Huang  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4*ab3bc873SGuochun Huang  */
5*ab3bc873SGuochun Huang 
6*ab3bc873SGuochun Huang #include <clk.h>
7*ab3bc873SGuochun Huang #include "rk628.h"
8*ab3bc873SGuochun Huang #include "rk628_cru.h"
9*ab3bc873SGuochun Huang #include "rk628_dsi.h"
10*ab3bc873SGuochun Huang #include "rk628_gvi.h"
11*ab3bc873SGuochun Huang #include "rk628_hdmirx.h"
12*ab3bc873SGuochun Huang #include "rk628_hdmitx.h"
13*ab3bc873SGuochun Huang #include "rk628_lvds.h"
14*ab3bc873SGuochun Huang #include "rk628_post_process.h"
15*ab3bc873SGuochun Huang #include "rk628_rgb.h"
16*ab3bc873SGuochun Huang 
rk628_power_on(struct rk628 * rk628)17*ab3bc873SGuochun Huang static int rk628_power_on(struct rk628 *rk628)
18*ab3bc873SGuochun Huang {
19*ab3bc873SGuochun Huang 	if (rk628->power_supply)
20*ab3bc873SGuochun Huang 		regulator_set_enable(rk628->power_supply, 1);
21*ab3bc873SGuochun Huang 
22*ab3bc873SGuochun Huang 	if (dm_gpio_is_valid(&rk628->enable_gpio)) {
23*ab3bc873SGuochun Huang 		dm_gpio_set_value(&rk628->enable_gpio, 1);
24*ab3bc873SGuochun Huang 		mdelay(10);
25*ab3bc873SGuochun Huang 	}
26*ab3bc873SGuochun Huang 
27*ab3bc873SGuochun Huang 	if (dm_gpio_is_valid(&rk628->reset_gpio)) {
28*ab3bc873SGuochun Huang 		dm_gpio_set_value(&rk628->reset_gpio, 0);
29*ab3bc873SGuochun Huang 		mdelay(10);
30*ab3bc873SGuochun Huang 		dm_gpio_set_value(&rk628->reset_gpio, 1);
31*ab3bc873SGuochun Huang 		mdelay(10);
32*ab3bc873SGuochun Huang 		dm_gpio_set_value(&rk628->reset_gpio, 0);
33*ab3bc873SGuochun Huang 		mdelay(10);
34*ab3bc873SGuochun Huang 	}
35*ab3bc873SGuochun Huang 
36*ab3bc873SGuochun Huang 	/* selete int io function */
37*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x30002000);
38*ab3bc873SGuochun Huang 
39*ab3bc873SGuochun Huang 	return 0;
40*ab3bc873SGuochun Huang }
41*ab3bc873SGuochun Huang 
rk628_version_info(struct rk628 * rk628)42*ab3bc873SGuochun Huang static int rk628_version_info(struct rk628 *rk628)
43*ab3bc873SGuochun Huang {
44*ab3bc873SGuochun Huang 	int ret;
45*ab3bc873SGuochun Huang 	char *version;
46*ab3bc873SGuochun Huang 
47*ab3bc873SGuochun Huang 	ret = rk628_i2c_read(rk628, GRF_SOC_VERSION, &rk628->version);
48*ab3bc873SGuochun Huang 	if (ret < 0) {
49*ab3bc873SGuochun Huang 		printf("failed to access rk628 register: %d\n", ret);
50*ab3bc873SGuochun Huang 		return ret;
51*ab3bc873SGuochun Huang 	}
52*ab3bc873SGuochun Huang 
53*ab3bc873SGuochun Huang 	switch (rk628->version) {
54*ab3bc873SGuochun Huang 	case RK628D_VERSION:
55*ab3bc873SGuochun Huang 		version = "D/E";
56*ab3bc873SGuochun Huang 		break;
57*ab3bc873SGuochun Huang 	case RK628F_VERSION:
58*ab3bc873SGuochun Huang 		version = "F/H";
59*ab3bc873SGuochun Huang 		break;
60*ab3bc873SGuochun Huang 	default:
61*ab3bc873SGuochun Huang 		version = "unknown";
62*ab3bc873SGuochun Huang 		ret = -EINVAL;
63*ab3bc873SGuochun Huang 	}
64*ab3bc873SGuochun Huang 
65*ab3bc873SGuochun Huang 	printf("the IC version is: RK628-%s\n", version);
66*ab3bc873SGuochun Huang 
67*ab3bc873SGuochun Huang 	return ret;
68*ab3bc873SGuochun Huang }
69*ab3bc873SGuochun Huang 
rk628_display_route_info_parse(struct rk628 * rk628)70*ab3bc873SGuochun Huang static int rk628_display_route_info_parse(struct rk628 *rk628)
71*ab3bc873SGuochun Huang {
72*ab3bc873SGuochun Huang 	int ret = 0;
73*ab3bc873SGuochun Huang 	ofnode np;
74*ab3bc873SGuochun Huang 	u32 val;
75*ab3bc873SGuochun Huang 
76*ab3bc873SGuochun Huang 	if (dev_read_bool(rk628->dev, "rk628-hdmi-in") ||
77*ab3bc873SGuochun Huang 	    dev_read_bool(rk628->dev, "rk628,hdmi-in")) {
78*ab3bc873SGuochun Huang 		rk628->input_mode = BIT(INPUT_MODE_HDMI);
79*ab3bc873SGuochun Huang 	} else if (dev_read_bool(rk628->dev, "rk628-rgb-in") ||
80*ab3bc873SGuochun Huang 		   dev_read_bool(rk628->dev, "rk628,rgb-in")) {
81*ab3bc873SGuochun Huang 		rk628->input_mode = BIT(INPUT_MODE_RGB);
82*ab3bc873SGuochun Huang 		ret = rk628_rgbrx_parse(rk628);
83*ab3bc873SGuochun Huang 	} else if (dev_read_bool(rk628->dev, "rk628-bt1120-in") ||
84*ab3bc873SGuochun Huang 		   dev_read_bool(rk628->dev, "rk628,bt1120-in")) {
85*ab3bc873SGuochun Huang 		rk628->input_mode = BIT(INPUT_MODE_BT1120);
86*ab3bc873SGuochun Huang 		ret = rk628_rgbrx_parse(rk628);
87*ab3bc873SGuochun Huang 	} else {
88*ab3bc873SGuochun Huang 		rk628->input_mode = BIT(INPUT_MODE_RGB);
89*ab3bc873SGuochun Huang 	}
90*ab3bc873SGuochun Huang 
91*ab3bc873SGuochun Huang 	if (ofnode_valid(dev_read_subnode(rk628->dev, "rk628-gvi-out")) ||
92*ab3bc873SGuochun Huang 	    ofnode_valid(dev_read_subnode(rk628->dev, "rk628-gvi"))) {
93*ab3bc873SGuochun Huang 		np = dev_read_subnode(rk628->dev, "rk628-gvi-out");
94*ab3bc873SGuochun Huang 		if (!ofnode_valid(np))
95*ab3bc873SGuochun Huang 			np = dev_read_subnode(rk628->dev, "rk628-gvi");
96*ab3bc873SGuochun Huang 
97*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_GVI);
98*ab3bc873SGuochun Huang 		ret = rk628_gvi_parse(rk628, np);
99*ab3bc873SGuochun Huang 	} else if (ofnode_valid(dev_read_subnode(rk628->dev, "rk628-lvds-out")) ||
100*ab3bc873SGuochun Huang 		   ofnode_valid(dev_read_subnode(rk628->dev, "rk628-lvds"))) {
101*ab3bc873SGuochun Huang 		np = dev_read_subnode(rk628->dev, "rk628-lvds-out");
102*ab3bc873SGuochun Huang 		if (!ofnode_valid(np))
103*ab3bc873SGuochun Huang 			np = dev_read_subnode(rk628->dev, "rk628-lvds");
104*ab3bc873SGuochun Huang 
105*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_LVDS);
106*ab3bc873SGuochun Huang 		ret = rk628_lvds_parse(rk628, np);
107*ab3bc873SGuochun Huang 	} else if (ofnode_valid(dev_read_subnode(rk628->dev, "rk628-dsi-out")) ||
108*ab3bc873SGuochun Huang 		   ofnode_valid(dev_read_subnode(rk628->dev, "rk628-dsi"))) {
109*ab3bc873SGuochun Huang 		np = dev_read_subnode(rk628->dev, "rk628-dsi-out");
110*ab3bc873SGuochun Huang 		if (!ofnode_valid(np))
111*ab3bc873SGuochun Huang 			np = dev_read_subnode(rk628->dev, "rk628-dsi");
112*ab3bc873SGuochun Huang 
113*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_DSI);
114*ab3bc873SGuochun Huang 		ret = rk628_dsi_parse(rk628, np);
115*ab3bc873SGuochun Huang 	} else if (dev_read_bool(rk628->dev, "rk628-csi-out") ||
116*ab3bc873SGuochun Huang 		   dev_read_bool(rk628->dev, "rk628,csi-out")) {
117*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_CSI);
118*ab3bc873SGuochun Huang 	}
119*ab3bc873SGuochun Huang 
120*ab3bc873SGuochun Huang 	if (dev_read_bool(rk628->dev, "rk628-hdmi-out") ||
121*ab3bc873SGuochun Huang 	    dev_read_bool(rk628->dev, "rk628,hdmi-out"))
122*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_HDMI);
123*ab3bc873SGuochun Huang 
124*ab3bc873SGuochun Huang 	if (dev_read_bool(rk628->dev, "rk628-rgb-out") ||
125*ab3bc873SGuochun Huang 	    dev_read_bool(rk628->dev, "rk628-rgb")) {
126*ab3bc873SGuochun Huang 		np = dev_read_subnode(rk628->dev, "rk628-rgb-out");
127*ab3bc873SGuochun Huang 		if (!ofnode_valid(np))
128*ab3bc873SGuochun Huang 			np = dev_read_subnode(rk628->dev, "rk628-rgb");
129*ab3bc873SGuochun Huang 
130*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_RGB);
131*ab3bc873SGuochun Huang 		ret = rk628_rgbtx_parse(rk628, np);
132*ab3bc873SGuochun Huang 	} else if (dev_read_bool(rk628->dev, "rk628-bt1120-out") ||
133*ab3bc873SGuochun Huang 		   dev_read_bool(rk628->dev, "rk628-bt1120")) {
134*ab3bc873SGuochun Huang 		np = dev_read_subnode(rk628->dev, "rk628-bt1120-out");
135*ab3bc873SGuochun Huang 		if (!ofnode_valid(np))
136*ab3bc873SGuochun Huang 			np = dev_read_subnode(rk628->dev, "rk628-bt1120");
137*ab3bc873SGuochun Huang 
138*ab3bc873SGuochun Huang 		rk628->output_mode |= BIT(OUTPUT_MODE_BT1120);
139*ab3bc873SGuochun Huang 		ret = rk628_rgbtx_parse(rk628, np);
140*ab3bc873SGuochun Huang 	}
141*ab3bc873SGuochun Huang 
142*ab3bc873SGuochun Huang 	val = dev_read_u32_default(rk628->dev, "mode-sync-pol", 1);
143*ab3bc873SGuochun Huang 	rk628->sync_pol = (!val ? MODE_FLAG_NSYNC : MODE_FLAG_PSYNC);
144*ab3bc873SGuochun Huang 
145*ab3bc873SGuochun Huang 	return ret;
146*ab3bc873SGuochun Huang }
147*ab3bc873SGuochun Huang 
rk628_display_route_check(struct rk628 * rk628)148*ab3bc873SGuochun Huang static bool rk628_display_route_check(struct rk628 *rk628)
149*ab3bc873SGuochun Huang {
150*ab3bc873SGuochun Huang 	if (!hweight32(rk628->input_mode) || !hweight32(rk628->output_mode))
151*ab3bc873SGuochun Huang 		return false;
152*ab3bc873SGuochun Huang 
153*ab3bc873SGuochun Huang 	/*
154*ab3bc873SGuochun Huang 	 * the RGB/BT1120 RX and RGB/BT1120 TX are the same shared IP
155*ab3bc873SGuochun Huang 	 * and cannot be used as both input and output simultaneously.
156*ab3bc873SGuochun Huang 	 */
157*ab3bc873SGuochun Huang 	if ((rk628_input_is_rgb(rk628) || rk628_input_is_bt1120(rk628)) &&
158*ab3bc873SGuochun Huang 	    (rk628_output_is_rgb(rk628) || rk628_output_is_bt1120(rk628)))
159*ab3bc873SGuochun Huang 		return false;
160*ab3bc873SGuochun Huang 
161*ab3bc873SGuochun Huang 	if (rk628->version == RK628F_VERSION)
162*ab3bc873SGuochun Huang 		return true;
163*ab3bc873SGuochun Huang 
164*ab3bc873SGuochun Huang 	/* rk628d only support rgb and hdmi output simultaneously */
165*ab3bc873SGuochun Huang 	if (hweight32(rk628->output_mode) > 2)
166*ab3bc873SGuochun Huang 		return false;
167*ab3bc873SGuochun Huang 
168*ab3bc873SGuochun Huang 	if (hweight32(rk628->output_mode) == 2 &&
169*ab3bc873SGuochun Huang 	    !(rk628_output_is_rgb(rk628) && rk628_output_is_hdmi(rk628)))
170*ab3bc873SGuochun Huang 		return false;
171*ab3bc873SGuochun Huang 
172*ab3bc873SGuochun Huang 	return true;
173*ab3bc873SGuochun Huang }
174*ab3bc873SGuochun Huang 
strlcat(char * dest,const char * src,size_t n)175*ab3bc873SGuochun Huang static inline size_t strlcat(char *dest, const char *src, size_t n)
176*ab3bc873SGuochun Huang {
177*ab3bc873SGuochun Huang 	strcat(dest, src);
178*ab3bc873SGuochun Huang 	return strlen(dest) + strlen(src);
179*ab3bc873SGuochun Huang }
180*ab3bc873SGuochun Huang 
rk628_current_display_route(struct rk628 * rk628,char * input_s,int input_s_len,char * output_s,int output_s_len)181*ab3bc873SGuochun Huang static void rk628_current_display_route(struct rk628 *rk628, char *input_s,
182*ab3bc873SGuochun Huang 					int input_s_len, char *output_s,
183*ab3bc873SGuochun Huang 					int output_s_len)
184*ab3bc873SGuochun Huang {
185*ab3bc873SGuochun Huang 	*input_s = '\0';
186*ab3bc873SGuochun Huang 	*output_s = '\0';
187*ab3bc873SGuochun Huang 
188*ab3bc873SGuochun Huang 	if (rk628_input_is_rgb(rk628))
189*ab3bc873SGuochun Huang 		strlcat(input_s, "RGB", input_s_len);
190*ab3bc873SGuochun Huang 	else if (rk628_input_is_bt1120(rk628))
191*ab3bc873SGuochun Huang 		strlcat(input_s, "BT1120", input_s_len);
192*ab3bc873SGuochun Huang 	else if (rk628_input_is_hdmi(rk628))
193*ab3bc873SGuochun Huang 		strlcat(input_s, "HDMI", input_s_len);
194*ab3bc873SGuochun Huang 	else
195*ab3bc873SGuochun Huang 		strlcat(input_s, "unknown", input_s_len);
196*ab3bc873SGuochun Huang 
197*ab3bc873SGuochun Huang 	if (rk628_output_is_rgb(rk628))
198*ab3bc873SGuochun Huang 		strlcat(output_s, "RGB ", output_s_len);
199*ab3bc873SGuochun Huang 
200*ab3bc873SGuochun Huang 	if (rk628_output_is_bt1120(rk628))
201*ab3bc873SGuochun Huang 		strlcat(output_s, "BT1120 ", output_s_len);
202*ab3bc873SGuochun Huang 
203*ab3bc873SGuochun Huang 	if (rk628_output_is_gvi(rk628))
204*ab3bc873SGuochun Huang 		strlcat(output_s, "GVI ", output_s_len);
205*ab3bc873SGuochun Huang 
206*ab3bc873SGuochun Huang 	if (rk628_output_is_lvds(rk628))
207*ab3bc873SGuochun Huang 		strncat(output_s, "LVDS ", output_s_len);
208*ab3bc873SGuochun Huang 
209*ab3bc873SGuochun Huang 	if (rk628_output_is_dsi(rk628))
210*ab3bc873SGuochun Huang 		strlcat(output_s, "DSI ", output_s_len);
211*ab3bc873SGuochun Huang 
212*ab3bc873SGuochun Huang 	if (rk628_output_is_csi(rk628))
213*ab3bc873SGuochun Huang 		strlcat(output_s, "CSI ", output_s_len);
214*ab3bc873SGuochun Huang 
215*ab3bc873SGuochun Huang 	if (rk628_output_is_hdmi(rk628))
216*ab3bc873SGuochun Huang 		strlcat(output_s, "HDMI ", output_s_len);
217*ab3bc873SGuochun Huang 
218*ab3bc873SGuochun Huang 	if (!strlen(output_s))
219*ab3bc873SGuochun Huang 		strlcat(output_s, "unknown", output_s_len);
220*ab3bc873SGuochun Huang }
221*ab3bc873SGuochun Huang 
rk628_show_current_display_route(struct rk628 * rk628)222*ab3bc873SGuochun Huang static void rk628_show_current_display_route(struct rk628 *rk628)
223*ab3bc873SGuochun Huang {
224*ab3bc873SGuochun Huang 	char input_s[10], output_s[30];
225*ab3bc873SGuochun Huang 
226*ab3bc873SGuochun Huang 	rk628_current_display_route(rk628, input_s, sizeof(input_s),
227*ab3bc873SGuochun Huang 				    output_s, sizeof(output_s));
228*ab3bc873SGuochun Huang 
229*ab3bc873SGuochun Huang 	printf("rk628 input_mode: %s, output_mode: %s\n", input_s, output_s);
230*ab3bc873SGuochun Huang }
231*ab3bc873SGuochun Huang 
rk628_pwr_consumption_init(struct rk628 * rk628)232*ab3bc873SGuochun Huang static void rk628_pwr_consumption_init(struct rk628 *rk628)
233*ab3bc873SGuochun Huang {
234*ab3bc873SGuochun Huang 	/* set pin as int function to allow output interrupt */
235*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x30002000);
236*ab3bc873SGuochun Huang 
237*ab3bc873SGuochun Huang 	/*
238*ab3bc873SGuochun Huang 	 * set unuse pin as GPIO input and
239*ab3bc873SGuochun Huang 	 * pull down to reduce power consumption
240*ab3bc873SGuochun Huang 	 */
241*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffff0000);
242*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff0000);
243*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b0000);
244*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO2C_P_CON, 0x3f0015);
245*ab3bc873SGuochun Huang 	rk628_i2c_write(rk628, GRF_GPIO3A_P_CON, 0xcc0044);
246*ab3bc873SGuochun Huang 
247*ab3bc873SGuochun Huang 	if (!rk628_output_is_hdmi(rk628)) {
248*ab3bc873SGuochun Huang 		u32 mask = SW_OUTPUT_MODE_MASK;
249*ab3bc873SGuochun Huang 		u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_HDMI);
250*ab3bc873SGuochun Huang 
251*ab3bc873SGuochun Huang 		if (rk628->version == RK628F_VERSION) {
252*ab3bc873SGuochun Huang 			mask = SW_HDMITX_EN_MASK;
253*ab3bc873SGuochun Huang 			val = SW_HDMITX_EN(1);
254*ab3bc873SGuochun Huang 		}
255*ab3bc873SGuochun Huang 
256*ab3bc873SGuochun Huang 		/* disable clock/data channel and band gap when hdmitx not work */
257*ab3bc873SGuochun Huang 		rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
258*ab3bc873SGuochun Huang 		rk628_i2c_write(rk628, HDMI_PHY_SYS_CTL, 0x17);
259*ab3bc873SGuochun Huang 		rk628_i2c_write(rk628, HDMI_PHY_CHG_PWR, 0x0);
260*ab3bc873SGuochun Huang 		rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, 0);
261*ab3bc873SGuochun Huang 	}
262*ab3bc873SGuochun Huang }
263*ab3bc873SGuochun Huang 
rk628_display_enable(struct rk628 * rk628)264*ab3bc873SGuochun Huang static void rk628_display_enable(struct rk628 *rk628)
265*ab3bc873SGuochun Huang {
266*ab3bc873SGuochun Huang 	if (rk628_input_is_rgb(rk628))
267*ab3bc873SGuochun Huang 		rk628_rgb_rx_enable(rk628);
268*ab3bc873SGuochun Huang 
269*ab3bc873SGuochun Huang 	/*
270*ab3bc873SGuochun Huang 	 * bt1120 needs to configure the timing register, but hdmitx will modify
271*ab3bc873SGuochun Huang 	 * the timing as needed, so the bt1120 enable process is moved to the
272*ab3bc873SGuochun Huang 	 * configuration of post_process (function rk628_post_process_enable in
273*ab3bc873SGuochun Huang 	 * rk628_post_process.c)
274*ab3bc873SGuochun Huang 	 */
275*ab3bc873SGuochun Huang 
276*ab3bc873SGuochun Huang 	if (rk628_output_is_rgb(rk628))
277*ab3bc873SGuochun Huang 		rk628_rgb_tx_enable(rk628);
278*ab3bc873SGuochun Huang 
279*ab3bc873SGuochun Huang 	if (rk628_input_is_hdmi(rk628))
280*ab3bc873SGuochun Huang 		rk628_hdmirx_enable(rk628);
281*ab3bc873SGuochun Huang 
282*ab3bc873SGuochun Huang 	if (rk628_output_is_dsi(rk628)) {
283*ab3bc873SGuochun Huang 		rk628_mipi_dsi_pre_enable(rk628);
284*ab3bc873SGuochun Huang 		rk628_mipi_dsi_enable(rk628);
285*ab3bc873SGuochun Huang 	}
286*ab3bc873SGuochun Huang 
287*ab3bc873SGuochun Huang 
288*ab3bc873SGuochun Huang 	if (rk628_output_is_bt1120(rk628))
289*ab3bc873SGuochun Huang 		rk628_bt1120_tx_enable(rk628);
290*ab3bc873SGuochun Huang 
291*ab3bc873SGuochun Huang 	if (!rk628_output_is_hdmi(rk628)) {
292*ab3bc873SGuochun Huang 		rk628_post_process_init(rk628);
293*ab3bc873SGuochun Huang 		rk628_post_process_enable(rk628);
294*ab3bc873SGuochun Huang 	}
295*ab3bc873SGuochun Huang 
296*ab3bc873SGuochun Huang 	if (rk628_output_is_lvds(rk628))
297*ab3bc873SGuochun Huang 		rk628_lvds_enable(rk628);
298*ab3bc873SGuochun Huang 
299*ab3bc873SGuochun Huang 	if (rk628_output_is_gvi(rk628))
300*ab3bc873SGuochun Huang 		rk628_gvi_enable(rk628);
301*ab3bc873SGuochun Huang }
302*ab3bc873SGuochun Huang 
303*ab3bc873SGuochun Huang static void
of_parse_rk628_display_timing(ofnode np,struct rk628_videomode * vm)304*ab3bc873SGuochun Huang of_parse_rk628_display_timing( ofnode np, struct rk628_videomode *vm)
305*ab3bc873SGuochun Huang {
306*ab3bc873SGuochun Huang 	u32 val = 0;
307*ab3bc873SGuochun Huang 
308*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "clock-frequency", &vm->pixelclock);
309*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "hactive", &vm->hactive);
310*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "hfront-porch", &vm->hfront_porch);
311*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "hback-porch", &vm->hback_porch);
312*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "hsync-len", &vm->hsync_len);
313*ab3bc873SGuochun Huang 
314*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "vactive", &vm->vactive);
315*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "vfront-porch", &vm->vfront_porch);
316*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "vback-porch", &vm->vback_porch);
317*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "vsync-len", &vm->vsync_len);
318*ab3bc873SGuochun Huang 
319*ab3bc873SGuochun Huang 	vm->flags = 0;
320*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "hsync-active", &val);
321*ab3bc873SGuochun Huang 	vm->flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
322*ab3bc873SGuochun Huang 
323*ab3bc873SGuochun Huang 	ofnode_read_u32(np, "vsync-active", &val);
324*ab3bc873SGuochun Huang 	vm->flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
325*ab3bc873SGuochun Huang }
326*ab3bc873SGuochun Huang 
327*ab3bc873SGuochun Huang static void
rk628_display_mode_from_videomode(const struct rk628_videomode * vm,struct drm_display_mode * dmode)328*ab3bc873SGuochun Huang rk628_display_mode_from_videomode(const struct rk628_videomode *vm,
329*ab3bc873SGuochun Huang 				  struct drm_display_mode *dmode)
330*ab3bc873SGuochun Huang {
331*ab3bc873SGuochun Huang 	dmode->hdisplay = vm->hactive;
332*ab3bc873SGuochun Huang 	dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
333*ab3bc873SGuochun Huang 	dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
334*ab3bc873SGuochun Huang 	dmode->htotal = dmode->hsync_end + vm->hback_porch;
335*ab3bc873SGuochun Huang 
336*ab3bc873SGuochun Huang 	dmode->vdisplay = vm->vactive;
337*ab3bc873SGuochun Huang 	dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
338*ab3bc873SGuochun Huang 	dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
339*ab3bc873SGuochun Huang 	dmode->vtotal = dmode->vsync_end + vm->vback_porch;
340*ab3bc873SGuochun Huang 
341*ab3bc873SGuochun Huang 	dmode->clock = vm->pixelclock / 1000;
342*ab3bc873SGuochun Huang 	dmode->flags = vm->flags;
343*ab3bc873SGuochun Huang }
344*ab3bc873SGuochun Huang 
rk628_get_video_mode(struct rk628 * rk628)345*ab3bc873SGuochun Huang static int rk628_get_video_mode(struct rk628 *rk628)
346*ab3bc873SGuochun Huang {
347*ab3bc873SGuochun Huang 	ofnode timings_np, src_np, dst_np;
348*ab3bc873SGuochun Huang 	struct rk628_videomode vm;
349*ab3bc873SGuochun Huang 
350*ab3bc873SGuochun Huang 	timings_np = ofnode_find_subnode(dev_ofnode(rk628->dev), "display-timings");
351*ab3bc873SGuochun Huang 	if (!ofnode_valid(timings_np))
352*ab3bc873SGuochun Huang 		return -EINVAL;
353*ab3bc873SGuochun Huang 
354*ab3bc873SGuochun Huang 	src_np = ofnode_find_subnode(timings_np, "src-timing");
355*ab3bc873SGuochun Huang 	if (!ofnode_valid(src_np)) {
356*ab3bc873SGuochun Huang 		printf("rk628 failed to found src timing\n");
357*ab3bc873SGuochun Huang 		return -EINVAL;
358*ab3bc873SGuochun Huang 	}
359*ab3bc873SGuochun Huang 
360*ab3bc873SGuochun Huang 	of_parse_rk628_display_timing(src_np, &vm);
361*ab3bc873SGuochun Huang 	rk628_display_mode_from_videomode(&vm, &rk628->src_mode);
362*ab3bc873SGuochun Huang 	printf("rk628 src mode: %d %d %d %d %d %d %d %d %d 0x%x\n",
363*ab3bc873SGuochun Huang 		rk628->src_mode.clock, rk628->src_mode.hdisplay, rk628->src_mode.hsync_start,
364*ab3bc873SGuochun Huang 		rk628->src_mode.hsync_end, rk628->src_mode.htotal, rk628->src_mode.vdisplay,
365*ab3bc873SGuochun Huang 		rk628->src_mode.vsync_start, rk628->src_mode.vsync_end, rk628->src_mode.vtotal,
366*ab3bc873SGuochun Huang 		rk628->src_mode.flags);
367*ab3bc873SGuochun Huang 
368*ab3bc873SGuochun Huang 	dst_np = ofnode_find_subnode(timings_np, "dst-timing");
369*ab3bc873SGuochun Huang 	if (!ofnode_valid(dst_np)) {
370*ab3bc873SGuochun Huang 		printf("rk628 failed to found dst timing\n");
371*ab3bc873SGuochun Huang 		return -EINVAL;
372*ab3bc873SGuochun Huang 	}
373*ab3bc873SGuochun Huang 
374*ab3bc873SGuochun Huang 	of_parse_rk628_display_timing(dst_np, &vm);
375*ab3bc873SGuochun Huang 	rk628_display_mode_from_videomode(&vm, &rk628->dst_mode);
376*ab3bc873SGuochun Huang 	printf("rk628 dst mode: %d %d %d %d %d %d %d %d %d 0x%x\n",
377*ab3bc873SGuochun Huang 		rk628->dst_mode.clock, rk628->dst_mode.hdisplay, rk628->dst_mode.hsync_start,
378*ab3bc873SGuochun Huang 		rk628->dst_mode.hsync_end, rk628->dst_mode.htotal, rk628->dst_mode.vdisplay,
379*ab3bc873SGuochun Huang 		rk628->dst_mode.vsync_start, rk628->dst_mode.vsync_end, rk628->dst_mode.vtotal,
380*ab3bc873SGuochun Huang 		rk628->dst_mode.flags);
381*ab3bc873SGuochun Huang 
382*ab3bc873SGuochun Huang 	return 0;
383*ab3bc873SGuochun Huang }
384*ab3bc873SGuochun Huang 
rk628_display_timings_get(struct rk628 * rk628)385*ab3bc873SGuochun Huang static int rk628_display_timings_get(struct rk628 *rk628)
386*ab3bc873SGuochun Huang {
387*ab3bc873SGuochun Huang 	int ret;
388*ab3bc873SGuochun Huang 
389*ab3bc873SGuochun Huang 	ret = rk628_get_video_mode(rk628);
390*ab3bc873SGuochun Huang 
391*ab3bc873SGuochun Huang 	return ret;
392*ab3bc873SGuochun Huang 
393*ab3bc873SGuochun Huang }
394*ab3bc873SGuochun Huang 
rk628_probe(struct udevice * dev)395*ab3bc873SGuochun Huang static int rk628_probe(struct udevice *dev)
396*ab3bc873SGuochun Huang {
397*ab3bc873SGuochun Huang 	struct rk628 *rk628 = dev_get_priv(dev);
398*ab3bc873SGuochun Huang 	int ret;
399*ab3bc873SGuochun Huang 
400*ab3bc873SGuochun Huang 	ret = i2c_set_chip_offset_len(dev, 4);
401*ab3bc873SGuochun Huang 	if (ret)
402*ab3bc873SGuochun Huang 		return ret;
403*ab3bc873SGuochun Huang 
404*ab3bc873SGuochun Huang 	rk628->dev = dev;
405*ab3bc873SGuochun Huang 
406*ab3bc873SGuochun Huang 	ret = rk628_display_route_info_parse(rk628);
407*ab3bc873SGuochun Huang 	if (ret) {
408*ab3bc873SGuochun Huang 		printf("display route parse err\n");
409*ab3bc873SGuochun Huang 		return ret;
410*ab3bc873SGuochun Huang 	}
411*ab3bc873SGuochun Huang 
412*ab3bc873SGuochun Huang 	if (!rk628_output_is_csi(rk628) && !rk628_output_is_hdmi(rk628)) {
413*ab3bc873SGuochun Huang 		ret = rk628_display_timings_get(rk628);
414*ab3bc873SGuochun Huang 		if (ret) {
415*ab3bc873SGuochun Huang 			printf("rk628 display timings err\n");
416*ab3bc873SGuochun Huang 			return ret;
417*ab3bc873SGuochun Huang 		}
418*ab3bc873SGuochun Huang 	}
419*ab3bc873SGuochun Huang 
420*ab3bc873SGuochun Huang 	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
421*ab3bc873SGuochun Huang 					   "power-supply",
422*ab3bc873SGuochun Huang 					   &rk628->power_supply);
423*ab3bc873SGuochun Huang 	if (ret && ret != -ENOENT) {
424*ab3bc873SGuochun Huang 		dev_err(dev, "Cannot get power supply: %d\n", ret);
425*ab3bc873SGuochun Huang 		return ret;
426*ab3bc873SGuochun Huang 	}
427*ab3bc873SGuochun Huang 
428*ab3bc873SGuochun Huang 	ret = gpio_request_by_name(dev, "enable-gpios", 0,
429*ab3bc873SGuochun Huang 				   &rk628->enable_gpio, GPIOD_IS_OUT);
430*ab3bc873SGuochun Huang 	if (ret && ret != -ENOENT) {
431*ab3bc873SGuochun Huang 		dev_err(dev, "%s: failed to get enable GPIO: %d\n", __func__, ret);
432*ab3bc873SGuochun Huang 		return ret;
433*ab3bc873SGuochun Huang 	}
434*ab3bc873SGuochun Huang 
435*ab3bc873SGuochun Huang 	ret = gpio_request_by_name(dev, "reset-gpios", 0,
436*ab3bc873SGuochun Huang 				   &rk628->reset_gpio, GPIOD_IS_OUT);
437*ab3bc873SGuochun Huang 	if (ret && ret != -ENOENT) {
438*ab3bc873SGuochun Huang 		dev_err(dev, "%s: failed to get reset GPIO: %d\n", __func__, ret);
439*ab3bc873SGuochun Huang 		return ret;
440*ab3bc873SGuochun Huang 	}
441*ab3bc873SGuochun Huang 
442*ab3bc873SGuochun Huang 	/*
443*ab3bc873SGuochun Huang 	 * Process 'assigned-{clocks/clock-parents/clock-rates}'
444*ab3bc873SGuochun Huang 	 * properties for ref clock from soc
445*ab3bc873SGuochun Huang 	 */
446*ab3bc873SGuochun Huang 	ret = clk_set_defaults(dev);
447*ab3bc873SGuochun Huang 	if (ret)
448*ab3bc873SGuochun Huang 		dev_err(dev, "%s clk_set_defaults failed %d\n", __func__, ret);
449*ab3bc873SGuochun Huang 
450*ab3bc873SGuochun Huang 	rk628_power_on(rk628);
451*ab3bc873SGuochun Huang 	rk628_version_info(rk628);
452*ab3bc873SGuochun Huang 
453*ab3bc873SGuochun Huang 	rk628_show_current_display_route(rk628);
454*ab3bc873SGuochun Huang 
455*ab3bc873SGuochun Huang 	if (!rk628_display_route_check(rk628)) {
456*ab3bc873SGuochun Huang 		printf("rk628 display route check err\n");
457*ab3bc873SGuochun Huang 		return -EINVAL;
458*ab3bc873SGuochun Huang 	}
459*ab3bc873SGuochun Huang 
460*ab3bc873SGuochun Huang 	rk628_pwr_consumption_init(rk628);
461*ab3bc873SGuochun Huang 	rk628_cru_init(rk628);
462*ab3bc873SGuochun Huang 	rk628_display_enable(rk628);
463*ab3bc873SGuochun Huang 
464*ab3bc873SGuochun Huang 	return 0;
465*ab3bc873SGuochun Huang }
466*ab3bc873SGuochun Huang 
467*ab3bc873SGuochun Huang static const struct udevice_id rk628_of_match[] = {
468*ab3bc873SGuochun Huang 	{ .compatible = "rockchip,rk628" },
469*ab3bc873SGuochun Huang 	{}
470*ab3bc873SGuochun Huang };
471*ab3bc873SGuochun Huang 
472*ab3bc873SGuochun Huang U_BOOT_DRIVER(rk628) = {
473*ab3bc873SGuochun Huang 	.name = "rk628",
474*ab3bc873SGuochun Huang 	.id = UCLASS_I2C_GENERIC,
475*ab3bc873SGuochun Huang 	.of_match = rk628_of_match,
476*ab3bc873SGuochun Huang 	.bind = dm_scan_fdt_dev,
477*ab3bc873SGuochun Huang 	.probe = rk628_probe,
478*ab3bc873SGuochun Huang 	.priv_auto_alloc_size = sizeof(struct rk628),
479*ab3bc873SGuochun Huang };
480