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