xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_lvds.c (revision f05ce84792cbd2e5573a414010d421eb8fbb7689)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <config.h>
8 #include <common.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <asm/unaligned.h>
12 #include <linux/list.h>
13 #include <linux/ioport.h>
14 #include <asm/io.h>
15 #include <asm/hardware.h>
16 #include <dm/device.h>
17 #include <dm/read.h>
18 #include <dm/ofnode.h>
19 #include <syscon.h>
20 #include <asm/arch-rockchip/clock.h>
21 #include <asm/gpio.h>
22 
23 #include "rockchip_display.h"
24 #include "rockchip_crtc.h"
25 #include "rockchip_connector.h"
26 #include "rockchip_lvds.h"
27 
28 enum rockchip_lvds_sub_devtype {
29 	PX30_LVDS,
30 	RK3126_LVDS,
31 	RK3288_LVDS,
32 	RK3368_LVDS,
33 };
34 
35 struct rockchip_lvds_chip_data {
36 	u32	chip_type;
37 	bool	has_vop_sel;
38 	u32	grf_soc_con5;
39 	u32	grf_soc_con6;
40 	u32	grf_soc_con7;
41 	u32	grf_soc_con15;
42 	u32	grf_gpio1d_iomux;
43 };
44 
45 struct rockchip_lvds_device {
46 	void	*regbase;
47 	void	*grf;
48 	void	*ctrl_reg;
49 	u32	channel;
50 	u32	output;
51 	u32	format;
52 	struct drm_display_mode *mode;
53 	const struct rockchip_lvds_chip_data *pdata;
54 };
55 
56 static inline int lvds_name_to_format(const char *s)
57 {
58 	if (!s)
59 		return -EINVAL;
60 
61 	if (strncmp(s, "jeida", 6) == 0)
62 		return LVDS_FORMAT_JEIDA;
63 	else if (strncmp(s, "vesa", 5) == 0)
64 		return LVDS_FORMAT_VESA;
65 
66 	return -EINVAL;
67 }
68 
69 static inline int lvds_name_to_output(const char *s)
70 {
71 	if (!s)
72 		return -EINVAL;
73 
74 	if (strncmp(s, "rgb", 3) == 0)
75 		return DISPLAY_OUTPUT_RGB;
76 	else if (strncmp(s, "lvds", 4) == 0)
77 		return DISPLAY_OUTPUT_LVDS;
78 	else if (strncmp(s, "duallvds", 8) == 0)
79 		return DISPLAY_OUTPUT_DUAL_LVDS;
80 
81 	return -EINVAL;
82 }
83 
84 static inline void lvds_writel(struct rockchip_lvds_device *lvds,
85 			      u32 offset, u32 val)
86 {
87 	writel(val, lvds->regbase + offset);
88 
89 	if ((lvds->pdata->chip_type == RK3288_LVDS) &&
90 	    ((lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) ||
91 	     (lvds->output == DISPLAY_OUTPUT_RGB)))
92 		writel(val, lvds->regbase + offset + 0x100);
93 }
94 
95 static inline void lvds_msk_reg(struct rockchip_lvds_device *lvds, u32 offset,
96 			       u32 msk, u32 val)
97 {
98 	u32 temp;
99 
100 	temp = readl(lvds->regbase + offset) & (0xFF - (msk));
101 	writel(temp | ((val) & (msk)), lvds->regbase + offset);
102 }
103 
104 static inline u32 lvds_readl(struct rockchip_lvds_device *lvds, u32 offset)
105 {
106 	return readl(lvds->regbase + offset);
107 }
108 
109 static inline void lvds_ctrl_writel(struct rockchip_lvds_device *lvds,
110 				   u32 offset, u32 val)
111 {
112 	writel(val, lvds->ctrl_reg + offset);
113 }
114 
115 static inline u32 lvds_pmugrf_readl(u32 offset)
116 {
117 	return readl((void *)LVDS_PMUGRF_BASE + offset);
118 }
119 
120 static inline void lvds_pmugrf_writel(u32 offset, u32 val)
121 {
122 	writel(val, (void *)LVDS_PMUGRF_BASE + offset);
123 }
124 
125 static inline u32 lvds_phy_lock(struct rockchip_lvds_device *lvds)
126 {
127 	u32 val = 0;
128 	val = readl(lvds->ctrl_reg + MIPIC_PHY_STATUS);
129 	return (val & m_PHY_LOCK_STATUS) ? 1 : 0;
130 }
131 
132 static int rockchip_lvds_clk_enable(struct rockchip_lvds_device *lvds)
133 {
134 	return 0;
135 }
136 
137 static int rk336x_lvds_pwr_off(struct display_state *state)
138 {
139 	struct connector_state *conn_state = &state->conn_state;
140 	struct rockchip_lvds_device *lvds = conn_state->private;
141 
142 	/* disable lvds lane and power off pll */
143 	lvds_writel(lvds, MIPIPHY_REGEB,
144 		    v_LANE0_EN(0) | v_LANE1_EN(0) | v_LANE2_EN(0) |
145 		    v_LANE3_EN(0) | v_LANECLK_EN(0) | v_PLL_PWR_OFF(1) |
146 		    v_LVDS_BGPD(1));
147 
148 	/* power down lvds pll and bandgap */
149 	lvds_msk_reg(lvds, MIPIPHY_REG1,
150 		     m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
151 		     v_SYNC_RST(1) | v_LDO_PWR_DOWN(1) | v_PLL_PWR_DOWN(1));
152 
153 	/* disable lvds */
154 	lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN,
155 		     v_LVDS_EN(0) | v_TTL_EN(0));
156 
157 	return 0;
158 }
159 
160 static int rk3288_lvds_pwr_off(struct display_state *state)
161 {
162 	struct connector_state *conn_state = &state->conn_state;
163 	struct rockchip_lvds_device *lvds = conn_state->private;
164 
165 	lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_DISABLE);
166 	lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_DISABLE);
167 
168 	writel(0xffff8000, lvds->grf + lvds->pdata->grf_soc_con7);
169 
170 	return 0;
171 }
172 
173 static int rk336x_lvds_pwr_on(struct display_state *state)
174 {
175 	struct connector_state *conn_state = &state->conn_state;
176 	struct rockchip_lvds_device *lvds = conn_state->private;
177 	u32 delay_times = 20;
178 
179 	if (lvds->output == DISPLAY_OUTPUT_LVDS) {
180 		/* set VOCM 900 mv and V-DIFF 350 mv */
181 		lvds_msk_reg(lvds, MIPIPHY_REGE4, m_VOCM | m_DIFF_V,
182 			     v_VOCM(0) | v_DIFF_V(2));
183 		/* power up lvds pll and ldo */
184 		lvds_msk_reg(lvds, MIPIPHY_REG1,
185 			     m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
186 			     v_SYNC_RST(0) | v_LDO_PWR_DOWN(0) |
187 			     v_PLL_PWR_DOWN(0));
188 		/* enable lvds lane and power on pll */
189 		lvds_writel(lvds, MIPIPHY_REGEB,
190 			    v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) |
191 			    v_LANE3_EN(1) | v_LANECLK_EN(1) | v_PLL_PWR_OFF(0) |
192 			    v_LVDS_BGPD(0));
193 
194 		/* enable lvds */
195 		lvds_msk_reg(lvds, MIPIPHY_REGE3,
196 			     m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
197 			     v_MIPI_EN(0) | v_LVDS_EN(1) | v_TTL_EN(0));
198 	} else {
199 		lvds_msk_reg(lvds, MIPIPHY_REGE3,
200 			     m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
201 			     v_MIPI_EN(0) | v_LVDS_EN(0) | v_TTL_EN(1));
202 
203 		/* set clock lane enable */
204 		lvds_ctrl_writel(lvds, 0xa0, 0x4);
205 	}
206 	/* delay for waitting pll lock on */
207 	while (delay_times--) {
208 		if (lvds_phy_lock(lvds))
209 			break;
210 		udelay(100);
211 	}
212 
213 	if (delay_times <= 0)
214 		printf("wait lvds phy lock failed, please check the hardware!\n");
215 
216 	return 0;
217 }
218 
219 static void px30_output_ttl(struct display_state *state)
220 {
221 	struct connector_state *conn_state = &state->conn_state;
222 	struct rockchip_lvds_device *lvds = conn_state->private;
223 	u32 val = 0;
224 
225 	/* enable lvds mode */
226 	val = PX30_RGB_SYNC_BYPASS(1) | PX30_DPHY_FORCERXMODE(1);
227 	writel(val, lvds->grf + PX30_GRF_PD_VO_CON1);
228 
229 	/* enable lane */
230 	lvds_msk_reg(lvds, MIPIPHY_REG0, 0x7c, 0x7c);
231 	val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
232 		v_LANECLK_EN(1) | v_PLL_PWR_OFF(1) | v_LVDS_BGPD(0);
233 	lvds_writel(lvds, MIPIPHY_REGEB, val);
234 	/* set ttl mode and reset phy config */
235 	val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
236 		v_MSB_SEL(1) | v_DIG_INTER_RST(1);
237 	lvds_writel(lvds, MIPIPHY_REGE0, val);
238 	rk336x_lvds_pwr_on(state);
239 }
240 
241 static void rk3126_output_ttl(struct display_state *state)
242 {
243 	struct connector_state *conn_state = &state->conn_state;
244 	struct rockchip_lvds_device *lvds = conn_state->private;
245 	u32 val = 0;
246 
247 	/* enable lvds mode */
248 	val = v_RK3126_LVDSMODE_EN(0) |
249 		v_RK3126_MIPIPHY_TTL_EN(1) |
250 		v_RK3126_MIPIPHY_LANE0_EN(1) |
251 		v_RK3126_MIPIDPI_FORCEX_EN(1);
252 	writel(val, lvds->grf + lvds->pdata->grf_soc_con7);
253 	val = v_RK3126_MIPITTL_CLK_EN(1) |
254 		v_RK3126_MIPITTL_LANE0_EN(1) |
255 		v_RK3126_MIPITTL_LANE1_EN(1) |
256 		v_RK3126_MIPITTL_LANE2_EN(1) |
257 		v_RK3126_MIPITTL_LANE3_EN(1);
258 	writel(val, lvds->grf + lvds->pdata->grf_soc_con15);
259 	/* enable lane */
260 	lvds_msk_reg(lvds, MIPIPHY_REG0, 0x7c, 0x7c);
261 	val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
262 		v_LANECLK_EN(1) | v_PLL_PWR_OFF(1) | v_LVDS_BGPD(0);
263 	lvds_writel(lvds, MIPIPHY_REGEB, val);
264 	/* set ttl mode and reset phy config */
265 	val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
266 		v_MSB_SEL(1) | v_DIG_INTER_RST(1);
267 	lvds_writel(lvds, MIPIPHY_REGE0, val);
268 	rk336x_lvds_pwr_on(state);
269 }
270 
271 static void rk336x_output_ttl(struct display_state *state)
272 {
273 	struct connector_state *conn_state = &state->conn_state;
274 	struct rockchip_lvds_device *lvds = conn_state->private;
275 	u32 val = 0;
276 
277 	/* enable lvds mode */
278 	val = v_RK336X_LVDSMODE_EN(0) | v_RK336X_MIPIPHY_TTL_EN(1) |
279 		v_RK336X_MIPIPHY_LANE0_EN(1) |
280 		v_RK336X_MIPIDPI_FORCEX_EN(1);
281 	writel(val, lvds->grf + lvds->pdata->grf_soc_con7);
282 	val = v_RK336X_FORCE_JETAG(0);
283 	writel(val, lvds->grf + lvds->pdata->grf_soc_con15);
284 
285 	/* enable lane */
286 	lvds_msk_reg(lvds, MIPIPHY_REG0, 0x7c, 0x7c);
287 	val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
288 		v_LANECLK_EN(1) | v_PLL_PWR_OFF(1) | v_LVDS_BGPD(0);
289 	lvds_writel(lvds, MIPIPHY_REGEB, val);
290 
291 	/* set ttl mode and reset phy config */
292 	val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
293 		v_MSB_SEL(1) | v_DIG_INTER_RST(1);
294 	lvds_writel(lvds, MIPIPHY_REGE0, val);
295 
296 	rk336x_lvds_pwr_on(state);
297 }
298 
299 static void px30_output_lvds(struct display_state *state)
300 {
301 	struct connector_state *conn_state = &state->conn_state;
302 	struct rockchip_lvds_device *lvds = conn_state->private;
303 	u32 val = 0;
304 
305 	lvds_writel(lvds, MIPIPHY_REG0, 0x01);
306 
307 	/* enable lvds mode */
308 	val = PX30_LVDS_PHY_MODE(1) | PX30_DPHY_FORCERXMODE(1);
309 	/* config lvds_format */
310 	val |= PX30_LVDS_OUTPUT_FORMAT(lvds->format);
311 	/* LSB receive mode */
312 	val |= PX30_LVDS_MSBSEL(LVDS_MSB_D7);
313 	writel(val, lvds->grf + PX30_GRF_PD_VO_CON1);
314 
315 	/* digital internal disable */
316 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0));
317 
318 	/* set pll prediv and fbdiv */
319 	lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0));
320 	lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28));
321 
322 	lvds_writel(lvds, MIPIPHY_REGE8, 0xfc);
323 
324 	lvds_msk_reg(lvds, MIPIPHY_REG8,
325 		     m_SAMPLE_CLK_DIR, v_SAMPLE_CLK_DIR_REVERSE);
326 
327 	/* set lvds mode and reset phy config */
328 	lvds_msk_reg(lvds, MIPIPHY_REGE0,
329 		     m_MSB_SEL | m_DIG_INTER_RST,
330 		     v_MSB_SEL(1) | v_DIG_INTER_RST(1));
331 
332 	rk336x_lvds_pwr_on(state);
333 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1));
334 }
335 
336 static void rk3126_output_lvds(struct display_state *state)
337 {
338 	struct connector_state *conn_state = &state->conn_state;
339 	struct rockchip_lvds_device *lvds = conn_state->private;
340 	u32 val = 0;
341 
342 	/* enable lvds mode */
343 	val = v_RK3126_LVDSMODE_EN(1) |
344 	      v_RK3126_MIPIPHY_TTL_EN(0);
345 	/* config lvds_format */
346 	val |= v_RK3126_LVDS_OUTPUT_FORMAT(lvds->format);
347 	/* LSB receive mode */
348 	val |= v_RK3126_LVDS_MSBSEL(LVDS_MSB_D7);
349 	val |= v_RK3126_MIPIPHY_LANE0_EN(1) |
350 	       v_RK3126_MIPIDPI_FORCEX_EN(1);
351 	writel(val, lvds->grf + lvds->pdata->grf_soc_con7);
352 
353 	/* digital internal disable */
354 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0));
355 
356 	/* set pll prediv and fbdiv */
357 	lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0));
358 	lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28));
359 
360 	lvds_writel(lvds, MIPIPHY_REGE8, 0xfc);
361 
362 	/* set lvds mode and reset phy config */
363 	lvds_msk_reg(lvds, MIPIPHY_REGE0,
364 		     m_MSB_SEL | m_DIG_INTER_RST,
365 		     v_MSB_SEL(1) | v_DIG_INTER_RST(1));
366 
367 	rk336x_lvds_pwr_on(state);
368 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1));
369 }
370 
371 static void rk336x_output_lvds(struct display_state *state)
372 {
373 	struct connector_state *conn_state = &state->conn_state;
374 	struct rockchip_lvds_device *lvds = conn_state->private;
375 	u32 val = 0;
376 
377 	/* enable lvds mode */
378 	val |= v_RK336X_LVDSMODE_EN(1) | v_RK336X_MIPIPHY_TTL_EN(0);
379 	/* config lvds_format */
380 	val |= v_RK336X_LVDS_OUTPUT_FORMAT(lvds->format);
381 	/* LSB receive mode */
382 	val |= v_RK336X_LVDS_MSBSEL(LVDS_MSB_D7);
383 	val |= v_RK336X_MIPIPHY_LANE0_EN(1) |
384 	       v_RK336X_MIPIDPI_FORCEX_EN(1);
385 	writel(val, lvds->grf + lvds->pdata->grf_soc_con7);
386 	/* digital internal disable */
387 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0));
388 
389 	/* set pll prediv and fbdiv */
390 	lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0));
391 	lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28));
392 
393 	lvds_writel(lvds, MIPIPHY_REGE8, 0xfc);
394 
395 	/* set lvds mode and reset phy config */
396 	lvds_msk_reg(lvds, MIPIPHY_REGE0,
397 		     m_MSB_SEL | m_DIG_INTER_RST,
398 		     v_MSB_SEL(1) | v_DIG_INTER_RST(1));
399 
400 	rk336x_lvds_pwr_on(state);
401 	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1));
402 }
403 
404 static int rk3288_lvds_pwr_on(struct display_state *state)
405 {
406 	struct connector_state *conn_state = &state->conn_state;
407 	struct rockchip_lvds_device *lvds = conn_state->private;
408 	struct drm_display_mode *mode = &conn_state->mode;
409 	u32 val;
410 	u32 h_bp = mode->htotal - mode->hsync_start;
411 	u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0;
412 	u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0;
413 
414 	val = lvds->format;
415 	if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
416 		val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
417 	else if (lvds->output == DISPLAY_OUTPUT_LVDS)
418 		val |= LVDS_CH0_EN;
419 	else if (lvds->output == DISPLAY_OUTPUT_RGB)
420 		val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
421 
422 	if (h_bp & 0x01)
423 		val |= LVDS_START_PHASE_RST_1;
424 
425 	val |= (pin_dclk << 8) | (pin_hsync << 9);
426 	val |= (0xffff << 16);
427 	writel(val, lvds->grf + lvds->pdata->grf_soc_con7);
428 
429 	return 0;
430 }
431 
432 static void rk3288_output_ttl(struct display_state *state)
433 {
434 	struct connector_state *conn_state = &state->conn_state;
435 	struct rockchip_lvds_device *lvds = conn_state->private;
436 
437 	rk3288_lvds_pwr_on(state);
438 	lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
439 		    RK3288_LVDS_CH0_REG0_TTL_EN |
440 		    RK3288_LVDS_CH0_REG0_LANECK_EN |
441 		    RK3288_LVDS_CH0_REG0_LANE4_EN |
442 		    RK3288_LVDS_CH0_REG0_LANE3_EN |
443 		    RK3288_LVDS_CH0_REG0_LANE2_EN |
444 		    RK3288_LVDS_CH0_REG0_LANE1_EN |
445 		    RK3288_LVDS_CH0_REG0_LANE0_EN);
446 	lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
447 		    RK3288_LVDS_PLL_FBDIV_REG2(0x46));
448 
449 	lvds_writel(lvds, RK3288_LVDS_CH0_REG3,
450 		    RK3288_LVDS_PLL_FBDIV_REG3(0x46));
451 	lvds_writel(lvds, RK3288_LVDS_CH0_REG4,
452 		    RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
453 		    RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
454 		    RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
455 		    RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
456 		    RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
457 		    RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
458 	lvds_writel(lvds, RK3288_LVDS_CH0_REG5,
459 		    RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
460 		    RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
461 		    RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
462 		    RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
463 		    RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
464 		    RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
465 	lvds_writel(lvds, RK3288_LVDS_CH0_REGD,
466 		    RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
467 	lvds_writel(lvds, RK3288_LVDS_CH0_REG20,
468 		    RK3288_LVDS_CH0_REG20_LSB);
469 
470 	lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE);
471 	lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE);
472 }
473 
474 static void rk3288_output_lvds(struct display_state *state)
475 {
476 	struct connector_state *conn_state = &state->conn_state;
477 	struct rockchip_lvds_device *lvds = conn_state->private;
478 
479 	rk3288_lvds_pwr_on(state);
480 
481 	lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
482 		    RK3288_LVDS_CH0_REG0_LVDS_EN |
483 		    RK3288_LVDS_CH0_REG0_LANECK_EN |
484 		    RK3288_LVDS_CH0_REG0_LANE4_EN |
485 		    RK3288_LVDS_CH0_REG0_LANE3_EN |
486 		    RK3288_LVDS_CH0_REG0_LANE2_EN |
487 		    RK3288_LVDS_CH0_REG0_LANE1_EN |
488 		    RK3288_LVDS_CH0_REG0_LANE0_EN);
489 	lvds_writel(lvds, RK3288_LVDS_CH0_REG1,
490 		    RK3288_LVDS_CH0_REG1_LANECK_BIAS |
491 		    RK3288_LVDS_CH0_REG1_LANE4_BIAS |
492 		    RK3288_LVDS_CH0_REG1_LANE3_BIAS |
493 		    RK3288_LVDS_CH0_REG1_LANE2_BIAS |
494 		    RK3288_LVDS_CH0_REG1_LANE1_BIAS |
495 		    RK3288_LVDS_CH0_REG1_LANE0_BIAS);
496 	lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
497 		    RK3288_LVDS_CH0_REG2_RESERVE_ON |
498 		    RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
499 		    RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
500 		    RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
501 		    RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
502 		    RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
503 		    RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
504 		    RK3288_LVDS_PLL_FBDIV_REG2(0x46));
505 	lvds_writel(lvds, RK3288_LVDS_CH0_REG3,
506 		    RK3288_LVDS_PLL_FBDIV_REG3(0x46));
507 	lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
508 	lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
509 	lvds_writel(lvds, RK3288_LVDS_CH0_REGD,
510 		    RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
511 	lvds_writel(lvds, RK3288_LVDS_CH0_REG20,
512 		    RK3288_LVDS_CH0_REG20_LSB);
513 
514 	lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE);
515 	lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE);
516 }
517 
518 static int rockchip_lvds_init(struct display_state *state)
519 {
520 	struct connector_state *conn_state = &state->conn_state;
521 	const struct rockchip_connector *connector = conn_state->connector;
522 	const struct rockchip_lvds_chip_data *pdata = connector->data;
523 	struct rockchip_lvds_device *lvds;
524 	const char *name;
525 	int i, width;
526 	struct resource lvds_phy, lvds_ctrl;
527 	struct panel_state *panel_state = &state->panel_state;
528 	ofnode panel_node = panel_state->node;
529 	int ret;
530 
531 	lvds = malloc(sizeof(*lvds));
532 	if (!lvds)
533 		return -ENOMEM;
534 	lvds->pdata = pdata;
535 
536 	if (pdata->chip_type == RK3288_LVDS) {
537 		lvds->regbase = dev_read_addr_ptr(conn_state->dev);
538 	} else {
539 		i = dev_read_resource(conn_state->dev, 0, &lvds_phy);
540 		if (i) {
541 			printf("can't get regs lvds_phy addresses!\n");
542 			free(lvds);
543 			return -ENOMEM;
544 		}
545 
546 		i = dev_read_resource(conn_state->dev, 1, &lvds_ctrl);
547 		if (i) {
548 			printf("can't get regs lvds_ctrl addresses!\n");
549 			free(lvds);
550 			return -ENOMEM;
551 		}
552 
553 		lvds->regbase = (void *)lvds_phy.start;
554 		lvds->ctrl_reg = (void *)lvds_ctrl.start;
555 	}
556 
557 	lvds->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
558 	if (lvds->grf <= 0) {
559 		printf("%s: Get syscon grf failed (ret=%p)\n",
560 		      __func__, lvds->grf);
561 		return  -ENXIO;
562 	}
563 
564 	ret = dev_read_string_index(panel_state->dev, "rockchip,output", 0, &name);
565 	if (ret)
566 		/* default set it as output rgb */
567 		lvds->output = DISPLAY_OUTPUT_RGB;
568 	else
569 		lvds->output = lvds_name_to_output(name);
570 	if (lvds->output < 0) {
571 		printf("invalid output type [%s]\n", name);
572 		free(lvds);
573 		return lvds->output;
574 	}
575 	ret = dev_read_string_index(panel_state->dev, "rockchip,data-mapping", 0, &name);
576 	if (ret)
577 		/* default set it as format jeida */
578 		lvds->format = LVDS_FORMAT_JEIDA;
579 	else
580 		lvds->format = lvds_name_to_format(name);
581 
582 	if (lvds->format < 0) {
583 		printf("invalid data-mapping format [%s]\n", name);
584 		free(lvds);
585 		return lvds->format;
586 	}
587 	width = ofnode_read_u32_default(panel_node, "rockchip,data-width", 24);
588 	if (width == 24) {
589 		lvds->format |= LVDS_24BIT;
590 	} else if (width == 18) {
591 		lvds->format |= LVDS_18BIT;
592 	} else {
593 		printf("rockchip-lvds unsupport data-width[%d]\n", width);
594 		free(lvds);
595 		return -EINVAL;
596 	}
597 
598 	printf("LVDS: data mapping: %s, data-width:%d, format:%d,\n",
599 		name, width, lvds->format);
600 	conn_state->private = lvds;
601 	conn_state->type = DRM_MODE_CONNECTOR_LVDS;
602 
603 	if ((lvds->output == DISPLAY_OUTPUT_RGB) && (width == 18))
604 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P666;
605 	else
606 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
607 	conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
608 
609 	return 0;
610 }
611 
612 static void rockchip_lvds_deinit(struct display_state *state)
613 {
614 	struct connector_state *conn_state = &state->conn_state;
615 	struct rockchip_lvds_device *lvds = conn_state->private;
616 
617 	free(lvds);
618 }
619 
620 static int rockchip_lvds_prepare(struct display_state *state)
621 {
622 	struct connector_state *conn_state = &state->conn_state;
623 	struct rockchip_lvds_device *lvds = conn_state->private;
624 	lvds->mode = &conn_state->mode;
625 
626 	rockchip_lvds_clk_enable(lvds);
627 
628 	return 0;
629 }
630 
631 static void rockchip_lvds_vop_routing(struct rockchip_lvds_device *lvds, int pipe)
632 {
633 	u32 val;
634 
635 	if (lvds->pdata->chip_type == RK3288_LVDS) {
636 		if (pipe)
637 			val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
638 				(RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
639 		else
640 			val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
641 		writel(val, lvds->grf + lvds->pdata->grf_soc_con6);
642 	} else if (lvds->pdata->chip_type == PX30_LVDS) {
643 		if (lvds->output == DISPLAY_OUTPUT_RGB)
644 			writel(PX30_RGB_VOP_SEL(pipe),
645 			       lvds->grf + PX30_GRF_PD_VO_CON1);
646 		else if (lvds->output == DISPLAY_OUTPUT_LVDS)
647 			writel(PX30_LVDS_VOP_SEL(pipe),
648 			       lvds->grf + PX30_GRF_PD_VO_CON1);
649 	}
650 }
651 
652 static int rockchip_lvds_enable(struct display_state *state)
653 {
654 	struct connector_state *conn_state = &state->conn_state;
655 	struct rockchip_lvds_device *lvds = conn_state->private;
656 	struct crtc_state *crtc_state = &state->crtc_state;
657 
658 	if (lvds->pdata->has_vop_sel)
659 		rockchip_lvds_vop_routing(lvds, crtc_state->crtc_id);
660 
661 	if ((lvds->output == DISPLAY_OUTPUT_LVDS) ||
662 	    (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)) {
663 		if (lvds->pdata->chip_type == RK3288_LVDS)
664 			rk3288_output_lvds(state);
665 		else if (lvds->pdata->chip_type == RK3126_LVDS)
666 			rk3126_output_lvds(state);
667 		else if (lvds->pdata->chip_type == PX30_LVDS)
668 			px30_output_lvds(state);
669 		else
670 			rk336x_output_lvds(state);
671 	} else {
672 		if (lvds->pdata->chip_type == RK3288_LVDS)
673 			rk3288_output_ttl(state);
674 		else if (lvds->pdata->chip_type == RK3126_LVDS)
675 			rk3126_output_ttl(state);
676 		else if (lvds->pdata->chip_type == PX30_LVDS)
677 			px30_output_ttl(state);
678 		else
679 			rk336x_output_ttl(state);
680 	}
681 
682 	return 0;
683 }
684 
685 static int rockchip_lvds_disable(struct display_state *state)
686 {
687 	struct connector_state *conn_state = &state->conn_state;
688 	struct rockchip_lvds_device *lvds = conn_state->private;
689 
690 	if (lvds->pdata->chip_type == RK3288_LVDS)
691 		rk3288_lvds_pwr_off(state);
692 	else
693 		rk336x_lvds_pwr_off(state);
694 
695 	return 0;
696 }
697 
698 const struct rockchip_connector_funcs rockchip_lvds_funcs = {
699 	.init = rockchip_lvds_init,
700 	.deinit = rockchip_lvds_deinit,
701 	.prepare = rockchip_lvds_prepare,
702 	.enable = rockchip_lvds_enable,
703 	.disable = rockchip_lvds_disable,
704 };
705 
706 static const struct rockchip_lvds_chip_data px30_lvds_drv_data = {
707 	.chip_type = PX30_LVDS,
708 	.has_vop_sel = true,
709 };
710 
711 static const struct rockchip_connector px30_lvds_data = {
712 	 .funcs = &rockchip_lvds_funcs,
713 	 .data = &px30_lvds_drv_data,
714 };
715 
716 static const struct rockchip_lvds_chip_data rk3126_lvds_drv_data = {
717 	.chip_type = RK3126_LVDS,
718 	.grf_soc_con7  = RK3126_GRF_LVDS_CON0,
719 	.grf_soc_con15 = RK3126_GRF_CON1,
720 	.has_vop_sel = true,
721 };
722 
723 static const struct rockchip_connector rk3126_lvds_data = {
724 	 .funcs = &rockchip_lvds_funcs,
725 	 .data = &rk3126_lvds_drv_data,
726 };
727 
728 static const struct rockchip_lvds_chip_data rk3288_lvds_drv_data = {
729 	.chip_type = RK3288_LVDS,
730 	.has_vop_sel = true,
731 	.grf_soc_con6 = 0x025c,
732 	.grf_soc_con7 = 0x0260,
733 	.grf_gpio1d_iomux = 0x000c,
734 };
735 
736 static const struct rockchip_connector rk3288_lvds_data = {
737 	 .funcs = &rockchip_lvds_funcs,
738 	 .data = &rk3288_lvds_drv_data,
739 };
740 
741 static const struct rockchip_lvds_chip_data rk3368_lvds_drv_data = {
742 	.chip_type = RK3368_LVDS,
743 	.grf_soc_con7  = RK3368_GRF_SOC_CON7,
744 	.grf_soc_con15 = RK3368_GRF_SOC_CON15,
745 	.has_vop_sel = false,
746 };
747 
748 static const struct rockchip_connector rk3368_lvds_data = {
749 	 .funcs = &rockchip_lvds_funcs,
750 	 .data = &rk3368_lvds_drv_data,
751 };
752 
753 static const struct udevice_id rockchip_lvds_ids[] = {
754 	{
755 		.compatible = "rockchip,px30-lvds",
756 		.data = (ulong)&px30_lvds_data,
757 	},
758 	{
759 		.compatible = "rockchip,rk3126-lvds",
760 		.data = (ulong)&rk3126_lvds_data,
761 	},
762 	{
763 		.compatible = "rockchip,rk3288-lvds",
764 		.data = (ulong)&rk3288_lvds_data,
765 	},
766 	{
767 		.compatible = "rockchip,rk3368-lvds",
768 		.data = (ulong)&rk3368_lvds_data,
769 	},
770 	{}
771 };
772 
773 U_BOOT_DRIVER(rockchip_lvds) = {
774 	.name = "rockchip_lvds",
775 	.id = UCLASS_DISPLAY,
776 	.of_match = rockchip_lvds_ids,
777 };
778