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