xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_lvds.c (revision 386f9d4cdc1bf882b1c9fda58e195f3017bf3b71)
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 <dm/device.h>
11 #include <dm/read.h>
12 #include <dm/ofnode.h>
13 #include <dm/of_access.h>
14 #include <syscon.h>
15 #include <regmap.h>
16 #include <dm/device.h>
17 #include <dm/read.h>
18 #include <linux/media-bus-format.h>
19 
20 #include "rockchip_display.h"
21 #include "rockchip_connector.h"
22 #include "rockchip_phy.h"
23 #include "rockchip_panel.h"
24 #include "drm_of.h"
25 
26 #define HIWORD_UPDATE(v, h, l)		(((v) << (l)) | (GENMASK(h, l) << 16))
27 
28 #define PX30_GRF_PD_VO_CON1		0x0438
29 #define PX30_LVDS_SELECT(x)		HIWORD_UPDATE(x, 14, 13)
30 #define PX30_LVDS_MODE_EN(x)		HIWORD_UPDATE(x, 12, 12)
31 #define PX30_LVDS_MSBSEL(x)		HIWORD_UPDATE(x, 11, 11)
32 #define PX30_LVDS_P2S_EN(x)		HIWORD_UPDATE(x,  6,  6)
33 #define PX30_LVDS_VOP_SEL(x)		HIWORD_UPDATE(x,  1,  1)
34 
35 #define RK3126_GRF_LVDS_CON0		0x0150
36 #define RK3126_LVDS_P2S_EN(x)		HIWORD_UPDATE(x,  9,  9)
37 #define RK3126_LVDS_MODE_EN(x)		HIWORD_UPDATE(x,  6,  6)
38 #define RK3126_LVDS_MSBSEL(x)		HIWORD_UPDATE(x,  3,  3)
39 #define RK3126_LVDS_SELECT(x)		HIWORD_UPDATE(x,  2,  1)
40 
41 #define RK3288_GRF_SOC_CON6		0x025c
42 #define RK3288_LVDS_LCDC_SEL(x)		HIWORD_UPDATE(x,  3,  3)
43 #define RK3288_GRF_SOC_CON7		0x0260
44 #define RK3288_LVDS_PWRDWN(x)		HIWORD_UPDATE(x, 15, 15)
45 #define RK3288_LVDS_CON_ENABLE_2(x)	HIWORD_UPDATE(x, 12, 12)
46 #define RK3288_LVDS_CON_ENABLE_1(x)	HIWORD_UPDATE(x, 11, 11)
47 #define RK3288_LVDS_CON_DEN_POL(x)	HIWORD_UPDATE(x, 10, 10)
48 #define RK3288_LVDS_CON_HS_POL(x)	HIWORD_UPDATE(x,  9,  9)
49 #define RK3288_LVDS_CON_CLKINV(x)	HIWORD_UPDATE(x,  8,  8)
50 #define RK3288_LVDS_CON_STARTPHASE(x)	HIWORD_UPDATE(x,  7,  7)
51 #define RK3288_LVDS_CON_TTL_EN(x)	HIWORD_UPDATE(x,  6,  6)
52 #define RK3288_LVDS_CON_STARTSEL(x)	HIWORD_UPDATE(x,  5,  5)
53 #define RK3288_LVDS_CON_CHASEL(x)	HIWORD_UPDATE(x,  4,  4)
54 #define RK3288_LVDS_CON_MSBSEL(x)	HIWORD_UPDATE(x,  3,  3)
55 #define RK3288_LVDS_CON_SELECT(x)	HIWORD_UPDATE(x,  2,  0)
56 
57 #define RK3368_GRF_SOC_CON7		0x041c
58 #define RK3368_LVDS_SELECT(x)		HIWORD_UPDATE(x, 14, 13)
59 #define RK3368_LVDS_MODE_EN(x)		HIWORD_UPDATE(x, 12, 12)
60 #define RK3368_LVDS_MSBSEL(x)		HIWORD_UPDATE(x, 11, 11)
61 #define RK3368_LVDS_P2S_EN(x)		HIWORD_UPDATE(x,  6,  6)
62 
63 #define RK3562_GRF_VO_CON0		0x05d0
64 #define RK3562_GRF_VO_CON1		0x05d4
65 
66 #define RK3568_GRF_VO_CON0		0x0360
67 #define RK3568_LVDS1_SELECT(x)		HIWORD_UPDATE(x, 13, 12)
68 #define RK3568_LVDS1_MSBSEL(x)		HIWORD_UPDATE(x, 11, 11)
69 #define RK3568_LVDS0_SELECT(x)		HIWORD_UPDATE(x,  5,  4)
70 #define RK3568_LVDS0_MSBSEL(x)		HIWORD_UPDATE(x,  3,  3)
71 #define RK3568_GRF_VO_CON2		0x0368
72 #define RK3568_LVDS0_DCLK_INV_SEL(x)	HIWORD_UPDATE(x,  9,  9)
73 #define RK3568_LVDS0_DCLK_DIV2_SEL(x)	HIWORD_UPDATE(x,  8,  8)
74 #define RK3568_LVDS0_MODE_EN(x)		HIWORD_UPDATE(x,  1,  1)
75 #define RK3568_LVDS0_P2S_EN(x)		HIWORD_UPDATE(x,  0,  0)
76 #define RK3568_GRF_VO_CON3		0x036c
77 #define RK3568_LVDS1_DCLK_INV_SEL(x)	HIWORD_UPDATE(x,  9,  9)
78 #define RK3568_LVDS1_DCLK_DIV2_SEL(x)	HIWORD_UPDATE(x,  8,  8)
79 #define RK3568_LVDS1_MODE_EN(x)		HIWORD_UPDATE(x,  1,  1)
80 #define RK3568_LVDS1_P2S_EN(x)		HIWORD_UPDATE(x,  0,  0)
81 
82 enum lvds_format {
83 	LVDS_8BIT_MODE_FORMAT_1,
84 	LVDS_8BIT_MODE_FORMAT_2,
85 	LVDS_8BIT_MODE_FORMAT_3,
86 	LVDS_6BIT_MODE,
87 	LVDS_10BIT_MODE_FORMAT_1,
88 	LVDS_10BIT_MODE_FORMAT_2,
89 };
90 
91 struct rockchip_lvds;
92 
93 struct rockchip_lvds_funcs {
94 	int (*probe)(struct rockchip_lvds *lvds);
95 	void (*enable)(struct rockchip_lvds *lvds, int pipe);
96 	void (*disable)(struct rockchip_lvds *lvds);
97 };
98 
99 struct rockchip_lvds {
100 	struct rockchip_connector connector;
101 	int id;
102 	struct udevice *dev;
103 	struct regmap *grf;
104 	struct rockchip_phy *phy;
105 	const struct drm_display_mode *mode;
106 	const struct rockchip_lvds_funcs *funcs;
107 	enum lvds_format format;
108 	bool data_swap;
109 	bool dual_channel;
110 	enum drm_lvds_dual_link_pixels pixel_order;
111 };
112 
113 static int rockchip_lvds_connector_init(struct rockchip_connector *conn,
114 					struct display_state *state)
115 {
116 	struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
117 	struct rockchip_lvds *primary_lvds = NULL;
118 	struct connector_state *conn_state = &state->conn_state;
119 	struct rockchip_panel *panel = conn->panel;
120 
121 	lvds->mode = &conn_state->mode;
122 	lvds->phy = conn->phy;
123 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, lvds->id);
124 
125 	if (conn_state->secondary)
126 		primary_lvds = dev_get_priv(conn_state->connector->dev);
127 
128 	switch (panel->bus_format) {
129 	case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA:	/* jeida-18 */
130 		lvds->format = LVDS_6BIT_MODE;
131 		break;
132 	case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:	/* jeida-24 */
133 		lvds->format = LVDS_8BIT_MODE_FORMAT_2;
134 		break;
135 	case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA: /* jeida-30 */
136 		lvds->format = LVDS_10BIT_MODE_FORMAT_1;
137 	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:	/* vesa-18 */
138 		lvds->format = LVDS_8BIT_MODE_FORMAT_3;
139 		break;
140 	case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG: /* vesa-30 */
141 		lvds->format = LVDS_10BIT_MODE_FORMAT_2;
142 		break;
143 	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:	/* vesa-24 */
144 	default:
145 		lvds->format = LVDS_8BIT_MODE_FORMAT_1;
146 		break;
147 	}
148 
149 	conn_state->bus_format = panel->bus_format;
150 	conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
151 
152 	if ((lvds->format == LVDS_10BIT_MODE_FORMAT_1) ||
153 		(lvds->format == LVDS_10BIT_MODE_FORMAT_2))
154 		conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
155 
156 	conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
157 	if (primary_lvds) {
158 		conn_state->output_flags = 0;
159 		conn_state->output_if = 0;
160 
161 		switch (primary_lvds->pixel_order) {
162 		case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
163 			conn_state->output_flags |=
164 				ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
165 			conn_state->output_if |=
166 				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
167 			break;
168 		case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
169 			conn_state->output_flags |=
170 				ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE;
171 			conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
172 			conn_state->output_if |=
173 				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
174 			break;
175 		case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS:
176 			conn_state->output_flags |=
177 				ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
178 			conn_state->output_if |=
179 				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
180 			break;
181 		case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS:
182 			conn_state->output_flags |=
183 				ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE;
184 			conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP;
185 			conn_state->output_if |=
186 				VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0;
187 			break;
188 		default:
189 			break;
190 		}
191 	}
192 
193 	if (lvds->id)
194 		conn_state->output_if |= VOP_OUTPUT_IF_LVDS1;
195 	else
196 		conn_state->output_if |= VOP_OUTPUT_IF_LVDS0;
197 
198 	return 0;
199 }
200 
201 static int rockchip_lvds_connector_enable(struct rockchip_connector *conn,
202 					  struct display_state *state)
203 {
204 	struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
205 	struct crtc_state *crtc_state = &state->crtc_state;
206 	int pipe = crtc_state->crtc_id;
207 	int ret;
208 
209 	if (lvds->funcs->enable)
210 		lvds->funcs->enable(lvds, pipe);
211 
212 	ret = rockchip_phy_set_mode(lvds->phy, PHY_MODE_VIDEO_LVDS);
213 	if (ret) {
214 		dev_err(lvds->dev, "failed to set phy mode: %d\n", ret);
215 		return ret;
216 	}
217 
218 	rockchip_phy_power_on(lvds->phy);
219 
220 	return 0;
221 }
222 
223 static int rockchip_lvds_connector_disable(struct rockchip_connector *conn,
224 					   struct display_state *state)
225 {
226 	struct rockchip_lvds *lvds = dev_get_priv(conn->dev);
227 
228 	rockchip_phy_power_off(lvds->phy);
229 
230 	if (lvds->funcs->disable)
231 		lvds->funcs->disable(lvds);
232 
233 	return 0;
234 }
235 
236 static const struct rockchip_connector_funcs rockchip_lvds_connector_funcs = {
237 	.init = rockchip_lvds_connector_init,
238 	.enable = rockchip_lvds_connector_enable,
239 	.disable = rockchip_lvds_connector_disable,
240 };
241 
242 static int rockchip_lvds_probe(struct udevice *dev)
243 {
244 	struct rockchip_lvds *lvds = dev_get_priv(dev);
245 
246 	lvds->dev = dev;
247 	lvds->funcs = (const struct rockchip_lvds_funcs *)dev_get_driver_data(dev);
248 	lvds->grf = syscon_get_regmap(dev_get_parent(dev));
249 	lvds->dual_channel = dev_read_bool(dev, "dual-channel");
250 	lvds->data_swap = dev_read_bool(dev, "rockchip,data-swap");
251 	lvds->id = of_alias_get_id(ofnode_to_np(dev->node), "lvds");
252 	if (lvds->id < 0)
253 		lvds->id = 0;
254 
255 	lvds->pixel_order = -1;
256 	if (lvds->funcs->probe)
257 		lvds->funcs->probe(lvds);
258 
259 	rockchip_connector_bind(&lvds->connector, dev, lvds->id, &rockchip_lvds_connector_funcs,
260 				NULL, DRM_MODE_CONNECTOR_LVDS);
261 
262 	return 0;
263 }
264 
265 static void px30_lvds_enable(struct rockchip_lvds *lvds, int pipe)
266 {
267 	regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1,
268 		     PX30_LVDS_SELECT(lvds->format) |
269 		     PX30_LVDS_MODE_EN(1) | PX30_LVDS_MSBSEL(1) |
270 		     PX30_LVDS_P2S_EN(1) | PX30_LVDS_VOP_SEL(pipe));
271 }
272 
273 static void px30_lvds_disable(struct rockchip_lvds *lvds)
274 {
275 	regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1,
276 		     PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0));
277 }
278 
279 static const struct rockchip_lvds_funcs px30_lvds_funcs = {
280 	.enable = px30_lvds_enable,
281 	.disable = px30_lvds_disable,
282 };
283 
284 static void rk3126_lvds_enable(struct rockchip_lvds *lvds, int pipe)
285 {
286 	regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0,
287 		     RK3126_LVDS_P2S_EN(1) | RK3126_LVDS_MODE_EN(1) |
288 		     RK3126_LVDS_MSBSEL(1) | RK3126_LVDS_SELECT(lvds->format));
289 }
290 
291 static void rk3126_lvds_disable(struct rockchip_lvds *lvds)
292 {
293 	regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0,
294 		     RK3126_LVDS_P2S_EN(0) | RK3126_LVDS_MODE_EN(0));
295 }
296 
297 static const struct rockchip_lvds_funcs rk3126_lvds_funcs = {
298 	.enable = rk3126_lvds_enable,
299 	.disable = rk3126_lvds_disable,
300 };
301 
302 static void rk3288_lvds_enable(struct rockchip_lvds *lvds, int pipe)
303 {
304 	const struct drm_display_mode *mode = lvds->mode;
305 	u32 val;
306 
307 	regmap_write(lvds->grf, RK3288_GRF_SOC_CON6,
308 		     RK3288_LVDS_LCDC_SEL(pipe));
309 
310 	val = RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_CLKINV(0) |
311 	      RK3288_LVDS_CON_CHASEL(lvds->dual_channel) |
312 	      RK3288_LVDS_CON_SELECT(lvds->format);
313 
314 	if (lvds->dual_channel) {
315 		u32 h_bp = mode->htotal - mode->hsync_start;
316 
317 		val |= RK3288_LVDS_CON_ENABLE_2(1) |
318 		       RK3288_LVDS_CON_ENABLE_1(1) |
319 		       RK3288_LVDS_CON_STARTSEL(lvds->data_swap);
320 
321 		if (h_bp % 2)
322 			val |= RK3288_LVDS_CON_STARTPHASE(1);
323 		else
324 			val |= RK3288_LVDS_CON_STARTPHASE(0);
325 	} else {
326 		val |= RK3288_LVDS_CON_ENABLE_2(0) |
327 		       RK3288_LVDS_CON_ENABLE_1(1);
328 	}
329 
330 	regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, val);
331 
332 	rockchip_phy_set_bus_width(lvds->phy, lvds->dual_channel ? 2 : 1);
333 }
334 
335 static void rk3288_lvds_disable(struct rockchip_lvds *lvds)
336 {
337 	regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, RK3288_LVDS_PWRDWN(1));
338 }
339 
340 static const struct rockchip_lvds_funcs rk3288_lvds_funcs = {
341 	.enable = rk3288_lvds_enable,
342 	.disable = rk3288_lvds_disable,
343 };
344 
345 static void rk3368_lvds_enable(struct rockchip_lvds *lvds, int pipe)
346 {
347 	regmap_write(lvds->grf, RK3368_GRF_SOC_CON7,
348 		     RK3368_LVDS_SELECT(lvds->format) |
349 		     RK3368_LVDS_MODE_EN(1) | RK3368_LVDS_MSBSEL(1) |
350 		     RK3368_LVDS_P2S_EN(1));
351 }
352 
353 static void rk3368_lvds_disable(struct rockchip_lvds *lvds)
354 {
355 	regmap_write(lvds->grf, RK3368_GRF_SOC_CON7,
356 		     RK3368_LVDS_MODE_EN(0) | RK3368_LVDS_P2S_EN(0));
357 }
358 
359 static const struct rockchip_lvds_funcs rk3368_lvds_funcs = {
360 	.enable = rk3368_lvds_enable,
361 	.disable = rk3368_lvds_disable,
362 };
363 
364 static void rk3562_lvds_enable(struct rockchip_lvds *lvds, int pipe)
365 {
366 	regmap_write(lvds->grf, RK3562_GRF_VO_CON1,
367 		     RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
368 		     RK3568_LVDS0_DCLK_INV_SEL(1));
369 	regmap_write(lvds->grf, RK3562_GRF_VO_CON0,
370 		     RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1));
371 }
372 
373 static void rk3562_lvds_disable(struct rockchip_lvds *lvds)
374 {
375 	regmap_write(lvds->grf, RK3562_GRF_VO_CON1, RK3568_LVDS0_MODE_EN(0));
376 }
377 
378 static const struct rockchip_lvds_funcs rk3562_lvds_funcs = {
379 	.enable = rk3562_lvds_enable,
380 	.disable = rk3562_lvds_disable,
381 };
382 
383 static int rk3568_lvds_probe(struct rockchip_lvds *lvds)
384 {
385 	if (lvds->dual_channel) {
386 		const struct device_node *port0, *port1;
387 		int pixel_order;
388 
389 		port1 = of_alias_get_dev("lvds", 1);
390 		if (!port1 || !of_device_is_available(port1)) {
391 			lvds->pixel_order = 0;
392 			return 0;
393 		}
394 
395 		port0 = rockchip_of_graph_get_port_by_id(lvds->dev->node, 1);
396 		port1 = rockchip_of_graph_get_port_by_id(np_to_ofnode(port1),
397 							 1);
398 		pixel_order =
399 			drm_of_lvds_get_dual_link_pixel_order(port0, port1);
400 
401 		lvds->pixel_order = pixel_order >= 0 ? pixel_order : 0;
402 	}
403 
404 	return 0;
405 }
406 
407 static void rk3568_lvds_enable(struct rockchip_lvds *lvds, int pipe)
408 {
409 	if (lvds->id) {
410 		regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
411 			     RK3568_LVDS1_MODE_EN(1) | RK3568_LVDS1_P2S_EN(1) |
412 				     RK3568_LVDS1_DCLK_INV_SEL(1));
413 		regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
414 			     RK3568_LVDS1_SELECT(lvds->format) |
415 				     RK3568_LVDS1_MSBSEL(1));
416 	} else {
417 		regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
418 			     RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) |
419 				     RK3568_LVDS0_DCLK_INV_SEL(1));
420 		regmap_write(lvds->grf, RK3568_GRF_VO_CON0,
421 			     RK3568_LVDS0_SELECT(lvds->format) |
422 				     RK3568_LVDS0_MSBSEL(1));
423 	}
424 }
425 
426 static void rk3568_lvds_disable(struct rockchip_lvds *lvds)
427 {
428 	if (lvds->id)
429 		regmap_write(lvds->grf, RK3568_GRF_VO_CON3,
430 			     RK3568_LVDS1_MODE_EN(0));
431 	else
432 		regmap_write(lvds->grf, RK3568_GRF_VO_CON2,
433 			     RK3568_LVDS0_MODE_EN(0));
434 }
435 
436 static const struct rockchip_lvds_funcs rk3568_lvds_funcs = {
437 	.probe = rk3568_lvds_probe,
438 	.enable = rk3568_lvds_enable,
439 	.disable = rk3568_lvds_disable,
440 };
441 
442 static const struct udevice_id rockchip_lvds_ids[] = {
443 	{
444 		.compatible = "rockchip,px30-lvds",
445 		.data = (ulong)&px30_lvds_funcs,
446 	},
447 	{
448 		.compatible = "rockchip,rk3126-lvds",
449 		.data = (ulong)&rk3126_lvds_funcs,
450 	},
451 	{
452 		.compatible = "rockchip,rk3288-lvds",
453 		.data = (ulong)&rk3288_lvds_funcs,
454 	},
455 	{
456 		.compatible = "rockchip,rk3368-lvds",
457 		.data = (ulong)&rk3368_lvds_funcs,
458 	},
459 	{
460 		.compatible = "rockchip,rk3562-lvds",
461 		.data = (ulong)&rk3562_lvds_funcs,
462 	},
463 	{
464 		.compatible = "rockchip,rk3568-lvds",
465 		.data = (ulong)&rk3568_lvds_funcs,
466 	},
467 	{}
468 };
469 
470 U_BOOT_DRIVER(rockchip_lvds) = {
471 	.name = "rockchip_lvds",
472 	.id = UCLASS_DISPLAY,
473 	.of_match = rockchip_lvds_ids,
474 	.probe = rockchip_lvds_probe,
475 	.priv_auto_alloc_size = sizeof(struct rockchip_lvds),
476 };
477