xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_rgb.c (revision 0fd9ded2d2bcf40bfefc48cde35176ea51e29e7e)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm/of_access.h>
9 #include <errno.h>
10 #include <syscon.h>
11 #include <regmap.h>
12 #include <dm/device.h>
13 #include <dm/read.h>
14 #include <dm/pinctrl.h>
15 #include <linux/media-bus-format.h>
16 #include <asm/gpio.h>
17 #include <backlight.h>
18 
19 #include "rockchip_display.h"
20 #include "rockchip_crtc.h"
21 #include "rockchip_connector.h"
22 #include "rockchip_phy.h"
23 #include "rockchip_panel.h"
24 
25 #define HIWORD_UPDATE(v, h, l)		(((v) << (l)) | (GENMASK(h, l) << 16))
26 
27 #define PX30_GRF_PD_VO_CON1		0x0438
28 #define PX30_RGB_DATA_SYNC_BYPASS(v)	HIWORD_UPDATE(v, 3, 3)
29 #define PX30_RGB_VOP_SEL(v)		HIWORD_UPDATE(v, 2, 2)
30 
31 #define RK1808_GRF_PD_VO_CON1		0x0444
32 #define RK1808_RGB_DATA_SYNC_BYPASS(v)	HIWORD_UPDATE(v, 3, 3)
33 
34 #define RV1106_VENC_GRF_VOP_IO_WRAPPER	0x1000c
35 #define RV1106_IO_BYPASS_SEL(v)		HIWORD_UPDATE(v, 0, 1)
36 #define RV1106_VOGRF_VOP_PIPE_BYPASS	0x60034
37 #define RV1106_VOP_PIPE_BYPASS(v)	HIWORD_UPDATE(v, 0, 1)
38 
39 #define RV1126_GRF_IOFUNC_CON3          0x1026c
40 #define RV1126_LCDC_IO_BYPASS(v)        HIWORD_UPDATE(v, 0, 0)
41 
42 #define RK3288_GRF_SOC_CON6		0x025c
43 #define RK3288_LVDS_LCDC_SEL(v)		HIWORD_UPDATE(v,  3,  3)
44 #define RK3288_GRF_SOC_CON7		0x0260
45 #define RK3288_LVDS_PWRDWN(v)		HIWORD_UPDATE(v, 15, 15)
46 #define RK3288_LVDS_CON_ENABLE_2(v)	HIWORD_UPDATE(v, 12, 12)
47 #define RK3288_LVDS_CON_ENABLE_1(v)	HIWORD_UPDATE(v, 11, 11)
48 #define RK3288_LVDS_CON_CLKINV(v)	HIWORD_UPDATE(v,  8,  8)
49 #define RK3288_LVDS_CON_TTL_EN(v)	HIWORD_UPDATE(v,  6,  6)
50 
51 #define RK3368_GRF_SOC_CON15		0x043c
52 #define RK3368_FORCE_JETAG(v)		HIWORD_UPDATE(v,  13,  13)
53 
54 #define RK3562_GRF_IOC_VO_IO_CON	0x10500
55 #define RK3562_RGB_DATA_BYPASS(v)	HIWORD_UPDATE(v, 6, 6)
56 
57 #define RK3568_GRF_VO_CON1		0X0364
58 #define RK3568_RGB_DATA_BYPASS(v)	HIWORD_UPDATE(v, 6, 6)
59 
60 #define RK3576_VCCIO_IOC_MISC_CON8	0x6420
61 #define RK3576_VOP_MCU_SEL(v)		HIWORD_UPDATE(v, 10, 10)
62 #define RK3576_VOP_DLL_SEL(v)		HIWORD_UPDATE(v, 8, 8)
63 #define RK3576_VOP_DCLK_DELAYLINE(v)	HIWORD_UPDATE(v, 0, 6)
64 
65 struct rockchip_rgb;
66 
67 struct rockchip_rgb_funcs {
68 	void (*prepare)(struct rockchip_rgb *rgb, int pipe);
69 	void (*unprepare)(struct rockchip_rgb *rgb);
70 };
71 
72 struct rockchip_rgb_data {
73 	u32 rgb_max_dclk_rate;
74 	u32 mcu_max_dclk_rate;
75 	u32 dclk_delayline;
76 	const struct rockchip_rgb_funcs *funcs;
77 };
78 
79 struct rockchip_rgb {
80 	struct rockchip_connector connector;
81 	int id;
82 	struct udevice *dev;
83 	struct regmap *grf;
84 	bool data_sync_bypass;
85 	struct rockchip_phy *phy;
86 	const struct rockchip_rgb_funcs *funcs;
87 	u32 max_dclk_rate;
88 	u32 dclk_delayline;
89 };
90 
91 struct mcu_cmd_header {
92 	u8 data_type;
93 	u8 delay;
94 	u8 payload_length;
95 } __packed;
96 
97 struct mcu_cmd_desc {
98 	struct mcu_cmd_header header;
99 	const u8 *payload;
100 };
101 
102 struct mcu_cmd_seq {
103 	struct mcu_cmd_desc *cmds;
104 	unsigned int cmd_cnt;
105 };
106 
107 struct rockchip_mcu_panel_desc {
108 	struct mcu_cmd_seq *init_seq;
109 	struct mcu_cmd_seq *exit_seq;
110 
111 	struct {
112 		unsigned int width;
113 		unsigned int height;
114 	} size;
115 
116 	struct {
117 		unsigned int prepare;
118 		unsigned int enable;
119 		unsigned int disable;
120 		unsigned int unprepare;
121 		unsigned int reset;
122 		unsigned int init;
123 	} delay;
124 
125 	unsigned int bpc;
126 	u32 bus_format;
127 	u32 bus_flags;
128 	bool power_invert;
129 };
130 
131 struct rockchip_mcu_panel {
132 	struct rockchip_panel base;
133 	struct rockchip_mcu_panel_desc *desc;
134 	struct udevice *power_supply;
135 	struct udevice *backlight;
136 
137 	struct gpio_desc enable_gpio;
138 	struct gpio_desc reset_gpio;
139 
140 	bool prepared;
141 	bool enabled;
142 };
143 
144 static inline struct rockchip_mcu_panel *to_rockchip_mcu_panel(struct rockchip_panel *panel)
145 {
146 	return container_of(panel, struct rockchip_mcu_panel, base);
147 }
148 
149 static int rockchip_rgb_connector_prepare(struct rockchip_connector *conn,
150 					  struct display_state *state)
151 {
152 	struct rockchip_rgb *rgb = dev_get_priv(conn->dev);
153 	struct crtc_state *crtc_state = &state->crtc_state;
154 	int pipe = crtc_state->crtc_id;
155 	int ret;
156 
157 	pinctrl_select_state(rgb->dev, "default");
158 
159 	if (rgb->funcs && rgb->funcs->prepare)
160 		rgb->funcs->prepare(rgb, pipe);
161 
162 	if (rgb->phy) {
163 		ret = rockchip_phy_set_mode(rgb->phy, PHY_MODE_VIDEO_TTL);
164 		if (ret) {
165 			dev_err(rgb->dev, "failed to set phy mode: %d\n", ret);
166 			return ret;
167 		}
168 
169 		rockchip_phy_power_on(rgb->phy);
170 	}
171 
172 	return 0;
173 }
174 
175 static void rockchip_rgb_connector_unprepare(struct rockchip_connector *conn,
176 					     struct display_state *state)
177 {
178 	struct rockchip_rgb *rgb = dev_get_priv(conn->dev);
179 
180 	if (rgb->phy)
181 		rockchip_phy_power_off(rgb->phy);
182 
183 	if (rgb->funcs && rgb->funcs->unprepare)
184 		rgb->funcs->unprepare(rgb);
185 
186 	pinctrl_select_state(rgb->dev, "sleep");
187 }
188 
189 static int rockchip_rgb_connector_init(struct rockchip_connector *conn, struct display_state *state)
190 {
191 	struct rockchip_rgb *rgb = dev_get_priv(conn->dev);
192 	struct connector_state *conn_state = &state->conn_state;
193 
194 	rgb->phy = conn->phy;
195 
196 	conn_state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
197 	conn_state->color_encoding = DRM_COLOR_YCBCR_BT709;
198 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, rgb->id);
199 
200 	switch (conn_state->bus_format) {
201 	case MEDIA_BUS_FMT_RGB666_1X18:
202 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P666;
203 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
204 		break;
205 	case MEDIA_BUS_FMT_RGB565_1X16:
206 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P565;
207 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
208 		break;
209 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
210 	case MEDIA_BUS_FMT_BGR565_2X8_LE:
211 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S565;
212 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
213 		break;
214 	case MEDIA_BUS_FMT_RGB666_3X6:
215 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S666;
216 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
217 		break;
218 	case MEDIA_BUS_FMT_RGB888_3X8:
219 	case MEDIA_BUS_FMT_BGR888_3X8:
220 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888;
221 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
222 		break;
223 	case MEDIA_BUS_FMT_RGB888_DUMMY_4X8:
224 	case MEDIA_BUS_FMT_BGR888_DUMMY_4X8:
225 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
226 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
227 		break;
228 	case MEDIA_BUS_FMT_YUYV8_2X8:
229 	case MEDIA_BUS_FMT_YVYU8_2X8:
230 	case MEDIA_BUS_FMT_UYVY8_2X8:
231 	case MEDIA_BUS_FMT_VYUY8_2X8:
232 		conn_state->output_mode = ROCKCHIP_OUT_MODE_BT656;
233 		conn_state->output_if = VOP_OUTPUT_IF_BT656;
234 		conn_state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
235 		conn_state->color_encoding = DRM_COLOR_YCBCR_BT601;
236 		break;
237 	case MEDIA_BUS_FMT_YUYV8_1X16:
238 	case MEDIA_BUS_FMT_YVYU8_1X16:
239 	case MEDIA_BUS_FMT_UYVY8_1X16:
240 	case MEDIA_BUS_FMT_VYUY8_1X16:
241 		conn_state->output_mode = ROCKCHIP_OUT_MODE_BT1120;
242 		conn_state->output_if = VOP_OUTPUT_IF_BT1120;
243 		conn_state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
244 		break;
245 	case MEDIA_BUS_FMT_RGB888_1X24:
246 	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
247 	default:
248 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
249 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
250 		break;
251 	}
252 
253 	return 0;
254 }
255 
256 static int rockchip_rgb_connector_mode_valid(struct rockchip_connector *conn,
257 					     struct display_state *state)
258 {
259 	struct rockchip_rgb *rgb = dev_get_priv(conn->dev);
260 	struct connector_state *conn_state = &state->conn_state;
261 	struct crtc_state *crtc_state = &state->crtc_state;
262 	struct drm_display_mode *mode = &conn_state->mode;
263 	u32 request_clock = mode->clock;
264 	u32 max_clock = rgb->max_dclk_rate;
265 
266 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
267 		request_clock *= 2;
268 
269 	if (rgb->data_sync_bypass)
270 		request_clock *= rockchip_drm_get_cycles_per_pixel(conn_state->bus_format) *
271 				 (crtc_state->mcu_timing.mcu_pix_total + 1);
272 
273 	if (max_clock != 0 && request_clock > max_clock) {
274 		printf("mode [%dx%d] clock %d is higher than max_clock %d\n",
275 		       mode->hdisplay, mode->vdisplay, request_clock, max_clock);
276 		return -EINVAL;
277 	}
278 
279 	return 0;
280 }
281 
282 static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = {
283 	.init = rockchip_rgb_connector_init,
284 	.prepare = rockchip_rgb_connector_prepare,
285 	.unprepare = rockchip_rgb_connector_unprepare,
286 	.mode_valid = rockchip_rgb_connector_mode_valid,
287 };
288 
289 static int rockchip_mcu_panel_send_cmds(struct display_state *state,
290 					struct mcu_cmd_seq *cmds)
291 {
292 	int i;
293 
294 	if (!cmds)
295 		return -EINVAL;
296 
297 	display_send_mcu_cmd(state, MCU_SETBYPASS, 1);
298 	for (i = 0; i < cmds->cmd_cnt; i++) {
299 		struct mcu_cmd_desc *desc = &cmds->cmds[i];
300 		int value = 0;
301 
302 		value = desc->payload[0];
303 		display_send_mcu_cmd(state, desc->header.data_type, value);
304 
305 		if (desc->header.delay)
306 			mdelay(desc->header.delay);
307 	}
308 	display_send_mcu_cmd(state, MCU_SETBYPASS, 0);
309 
310 	return 0;
311 }
312 
313 static void rockchip_mcu_panel_prepare(struct rockchip_panel *panel)
314 {
315 	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
316 	int ret;
317 
318 	if (mcu_panel->prepared)
319 		return;
320 
321 	if (dm_gpio_is_valid(&mcu_panel->enable_gpio))
322 		dm_gpio_set_value(&mcu_panel->enable_gpio, 1);
323 
324 	if (mcu_panel->desc->delay.prepare)
325 		mdelay(mcu_panel->desc->delay.prepare);
326 
327 	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
328 		dm_gpio_set_value(&mcu_panel->reset_gpio, 1);
329 
330 	if (mcu_panel->desc->delay.reset)
331 		mdelay(mcu_panel->desc->delay.reset);
332 
333 	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
334 		dm_gpio_set_value(&mcu_panel->reset_gpio, 0);
335 
336 	if (mcu_panel->desc->delay.init)
337 		mdelay(mcu_panel->desc->delay.init);
338 
339 	if (mcu_panel->desc->init_seq) {
340 		ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->init_seq);
341 		if (ret)
342 			printf("failed to send mcu panel init cmds: %d\n", ret);
343 	}
344 
345 	mcu_panel->prepared = true;
346 }
347 
348 static void rockchip_mcu_panel_unprepare(struct rockchip_panel *panel)
349 {
350 	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
351 	int ret;
352 
353 	if (!mcu_panel->prepared)
354 		return;
355 
356 	if (mcu_panel->desc->exit_seq) {
357 		ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->exit_seq);
358 		if (ret)
359 			printf("failed to send mcu panel exit cmds: %d\n", ret);
360 	}
361 
362 	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
363 		dm_gpio_set_value(&mcu_panel->reset_gpio, 1);
364 
365 	if (dm_gpio_is_valid(&mcu_panel->enable_gpio))
366 		dm_gpio_set_value(&mcu_panel->enable_gpio, 0);
367 
368 	if (mcu_panel->desc->delay.unprepare)
369 		mdelay(mcu_panel->desc->delay.unprepare);
370 
371 	mcu_panel->prepared = false;
372 }
373 
374 static void rockchip_mcu_panel_enable(struct rockchip_panel *panel)
375 {
376 	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
377 
378 	if (mcu_panel->enabled)
379 		return;
380 
381 	if (mcu_panel->desc->delay.enable)
382 		mdelay(mcu_panel->desc->delay.enable);
383 
384 	if (mcu_panel->backlight)
385 		backlight_enable(mcu_panel->backlight);
386 
387 	mcu_panel->enabled = true;
388 }
389 
390 static void rockchip_mcu_panel_disable(struct rockchip_panel *panel)
391 {
392 	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
393 
394 	if (!mcu_panel->enabled)
395 		return;
396 
397 	if (mcu_panel->backlight)
398 		backlight_disable(mcu_panel->backlight);
399 
400 	if (mcu_panel->desc->delay.disable)
401 		mdelay(mcu_panel->desc->delay.disable);
402 
403 	mcu_panel->enabled = false;
404 }
405 
406 static const struct rockchip_panel_funcs rockchip_mcu_panel_funcs = {
407 	.prepare = rockchip_mcu_panel_prepare,
408 	.unprepare = rockchip_mcu_panel_unprepare,
409 	.enable = rockchip_mcu_panel_enable,
410 	.disable = rockchip_mcu_panel_disable,
411 };
412 
413 static int rockchip_mcu_panel_parse_cmds(const u8 *data, int length,
414 					 struct mcu_cmd_seq *pcmds)
415 {
416 	int len;
417 	const u8 *buf;
418 	const struct mcu_cmd_header *header;
419 	int i, cnt = 0;
420 
421 	/* scan commands */
422 	cnt = 0;
423 	buf = data;
424 	len = length;
425 	while (len > sizeof(*header)) {
426 		header = (const struct mcu_cmd_header *)buf;
427 		buf += sizeof(*header) + header->payload_length;
428 		len -= sizeof(*header) + header->payload_length;
429 		cnt++;
430 	}
431 
432 	pcmds->cmds = calloc(cnt, sizeof(struct mcu_cmd_desc));
433 	if (!pcmds->cmds)
434 		return -ENOMEM;
435 
436 	pcmds->cmd_cnt = cnt;
437 
438 	buf = data;
439 	len = length;
440 	for (i = 0; i < cnt; i++) {
441 		struct mcu_cmd_desc *desc = &pcmds->cmds[i];
442 
443 		header = (const struct mcu_cmd_header *)buf;
444 		length -= sizeof(*header);
445 		buf += sizeof(*header);
446 		desc->header.data_type = header->data_type;
447 		desc->header.delay = header->delay;
448 		desc->header.payload_length = header->payload_length;
449 		desc->payload = buf;
450 		buf += header->payload_length;
451 		length -= header->payload_length;
452 	}
453 
454 	return 0;
455 }
456 
457 static int rockchip_mcu_panel_init(struct rockchip_mcu_panel *mcu_panel, ofnode mcu_panel_node)
458 {
459 	const void *data;
460 	int len;
461 	int ret;
462 
463 	ret = gpio_request_by_name_nodev(mcu_panel_node, "enable-gpios", 0,
464 					 &mcu_panel->enable_gpio, GPIOD_IS_OUT);
465 	if (ret && ret != -ENOENT) {
466 		printf("%s: Cannot get mcu panel enable GPIO: %d\n", __func__, ret);
467 		return ret;
468 	}
469 
470 	ret = gpio_request_by_name_nodev(mcu_panel_node, "reset-gpios", 0,
471 					 &mcu_panel->reset_gpio, GPIOD_IS_OUT);
472 	if (ret && ret != -ENOENT) {
473 		printf("%s: Cannot get mcu panel reset GPIO: %d\n", __func__, ret);
474 		return ret;
475 	}
476 
477 	mcu_panel->desc = malloc(sizeof(struct rockchip_mcu_panel_desc));
478 	if (!mcu_panel->desc)
479 		return -ENOMEM;
480 
481 	mcu_panel->desc->power_invert = ofnode_read_bool(mcu_panel_node, "power-invert");
482 
483 	mcu_panel->desc->delay.prepare = ofnode_read_u32_default(mcu_panel_node, "prepare-delay-ms", 0);
484 	mcu_panel->desc->delay.unprepare = ofnode_read_u32_default(mcu_panel_node, "unprepare-delay-ms", 0);
485 	mcu_panel->desc->delay.enable = ofnode_read_u32_default(mcu_panel_node, "enable-delay-ms", 0);
486 	mcu_panel->desc->delay.disable = ofnode_read_u32_default(mcu_panel_node, "disable-delay-ms", 0);
487 	mcu_panel->desc->delay.init = ofnode_read_u32_default(mcu_panel_node, "init-delay-ms", 0);
488 	mcu_panel->desc->delay.reset = ofnode_read_u32_default(mcu_panel_node, "reset-delay-ms", 0);
489 
490 	mcu_panel->desc->bus_format = ofnode_read_u32_default(mcu_panel_node, "bus-format",
491 							      MEDIA_BUS_FMT_RBG888_1X24);
492 	mcu_panel->desc->bpc = ofnode_read_u32_default(mcu_panel_node, "bpc", 8);
493 
494 	data = ofnode_get_property(mcu_panel_node, "panel-init-sequence", &len);
495 	if (data) {
496 		mcu_panel->desc->init_seq = calloc(1, sizeof(*mcu_panel->desc->init_seq));
497 		if (!mcu_panel->desc->init_seq)
498 			return -ENOMEM;
499 
500 		ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->init_seq);
501 		if (ret) {
502 			printf("failed to parse panel init sequence\n");
503 			goto free_on_cmds;
504 		}
505 	}
506 
507 	data = ofnode_get_property(mcu_panel_node, "panel-exit-sequence", &len);
508 	if (data) {
509 		mcu_panel->desc->exit_seq = calloc(1, sizeof(*mcu_panel->desc->exit_seq));
510 		if (!mcu_panel->desc->exit_seq) {
511 			ret = -ENOMEM;
512 			goto free_on_cmds;
513 		}
514 
515 		ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->exit_seq);
516 		if (ret) {
517 			printf("failed to parse panel exit sequence\n");
518 			goto free_cmds;
519 		}
520 	}
521 
522 	return 0;
523 
524 free_cmds:
525 	free(mcu_panel->desc->exit_seq);
526 free_on_cmds:
527 	free(mcu_panel->desc->init_seq);
528 	return ret;
529 }
530 
531 static int rockchip_rgb_probe(struct udevice *dev)
532 {
533 	struct rockchip_rgb *rgb = dev_get_priv(dev);
534 	const struct rockchip_rgb_data *rgb_data;
535 	ofnode mcu_panel_node;
536 	int phandle;
537 	int ret;
538 
539 	rgb->data_sync_bypass = dev_read_bool(dev, "rockchip,data-sync-bypass");
540 	rgb_data = (const struct rockchip_rgb_data *)dev_get_driver_data(dev);
541 	if (rgb_data) {
542 		rgb->funcs = rgb_data->funcs;
543 		if (rgb->data_sync_bypass)
544 			rgb->max_dclk_rate = rgb_data->mcu_max_dclk_rate;
545 		else
546 			rgb->max_dclk_rate = rgb_data->rgb_max_dclk_rate;
547 		rgb->dclk_delayline = rgb_data->dclk_delayline;
548 	}
549 	rgb->dev = dev;
550 	rgb->grf = syscon_get_regmap(dev_get_parent(dev));
551 	rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb");
552 	if (rgb->id < 0)
553 		rgb->id = 0;
554 
555 	mcu_panel_node = dev_read_subnode(dev, "mcu-panel");
556 	if (ofnode_valid(mcu_panel_node) && ofnode_is_available(mcu_panel_node)) {
557 		struct rockchip_mcu_panel *mcu_panel;
558 
559 		mcu_panel = malloc(sizeof(struct rockchip_mcu_panel));
560 		if (!mcu_panel) {
561 			printf("failed to alloc mcu_panel data\n");
562 			return -ENOMEM;
563 		}
564 
565 		ret = rockchip_mcu_panel_init(mcu_panel, mcu_panel_node);
566 		if (ret < 0) {
567 			printf("failed to init mcu_panel: %d\n", ret);
568 			return ret;
569 		}
570 
571 		phandle = ofnode_read_u32_default(mcu_panel_node, "backlight", -1);
572 		if (phandle < 0) {
573 			printf("failed to find backlight phandle\n");
574 			return -EINVAL;
575 		}
576 
577 		ret = uclass_get_device_by_phandle_id(UCLASS_PANEL_BACKLIGHT, phandle,
578 						      &mcu_panel->backlight);
579 		if (ret && ret != -ENOENT) {
580 			printf("%s: failed to get backlight device: %d\n", __func__, ret);
581 			return ret;
582 		}
583 
584 		mcu_panel->base.dev = dev;
585 		mcu_panel->base.bus_format = mcu_panel->desc->bus_format;
586 		mcu_panel->base.bpc = mcu_panel->desc->bpc;
587 		mcu_panel->base.funcs = &rockchip_mcu_panel_funcs;
588 		mcu_panel->enabled = false;
589 		mcu_panel->prepared = false;
590 
591 		rgb->connector.panel = &mcu_panel->base;
592 	}
593 
594 	rockchip_connector_bind(&rgb->connector, dev, rgb->id, &rockchip_rgb_connector_funcs,
595 				NULL, DRM_MODE_CONNECTOR_LVDS);
596 
597 	return 0;
598 }
599 
600 static void rv1106_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
601 {
602 	regmap_write(rgb->grf, RV1106_VENC_GRF_VOP_IO_WRAPPER,
603 		     RV1106_IO_BYPASS_SEL(rgb->data_sync_bypass ? 0x3 : 0x0));
604 	regmap_write(rgb->grf, RV1106_VOGRF_VOP_PIPE_BYPASS,
605 		     RV1106_VOP_PIPE_BYPASS(rgb->data_sync_bypass ? 0x3 : 0x0));
606 }
607 
608 static const struct rockchip_rgb_funcs rv1106_rgb_funcs = {
609 	.prepare = rv1106_rgb_prepare,
610 };
611 
612 static const struct rockchip_rgb_data rv1106_rgb = {
613 	.rgb_max_dclk_rate = 74250,
614 	.mcu_max_dclk_rate = 150000,
615 	.funcs = &rv1106_rgb_funcs,
616 };
617 
618 static void rv1126_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
619 {
620 	regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3,
621 		     RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass));
622 }
623 
624 static const struct rockchip_rgb_funcs rv1126_rgb_funcs = {
625 	.prepare = rv1126_rgb_prepare,
626 };
627 
628 static const struct rockchip_rgb_data rv1126_rgb = {
629 	.funcs = &rv1126_rgb_funcs,
630 };
631 
632 static void px30_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
633 {
634 	regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) |
635 		     PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
636 }
637 
638 static const struct rockchip_rgb_funcs px30_rgb_funcs = {
639 	.prepare = px30_rgb_prepare,
640 };
641 
642 static const struct rockchip_rgb_data px30_rgb = {
643 	.funcs = &px30_rgb_funcs,
644 };
645 
646 static void rk1808_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
647 {
648 	regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1,
649 		     RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
650 }
651 
652 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = {
653 	.prepare = rk1808_rgb_prepare,
654 };
655 
656 static const struct rockchip_rgb_data rk1808_rgb = {
657 	.funcs = &rk1808_rgb_funcs,
658 };
659 
660 static void rk3288_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
661 {
662 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe));
663 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
664 		     RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) |
665 		     RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) |
666 		     RK3288_LVDS_CON_TTL_EN(1));
667 }
668 
669 static void rk3288_rgb_unprepare(struct rockchip_rgb *rgb)
670 {
671 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
672 		     RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) |
673 		     RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0));
674 }
675 
676 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = {
677 	.prepare = rk3288_rgb_prepare,
678 	.unprepare = rk3288_rgb_unprepare,
679 };
680 
681 static const struct rockchip_rgb_data rk3288_rgb = {
682 	.funcs = &rk3288_rgb_funcs,
683 };
684 
685 static void rk3368_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
686 {
687 	regmap_write(rgb->grf, RK3368_GRF_SOC_CON15, RK3368_FORCE_JETAG(0));
688 }
689 
690 static const struct rockchip_rgb_funcs rk3368_rgb_funcs = {
691 	.prepare = rk3368_rgb_prepare,
692 };
693 
694 static const struct rockchip_rgb_data rk3368_rgb = {
695 	.funcs = &rk3368_rgb_funcs,
696 };
697 
698 static void rk3562_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
699 {
700 	regmap_write(rgb->grf, RK3562_GRF_IOC_VO_IO_CON,
701 		     RK3562_RGB_DATA_BYPASS(rgb->data_sync_bypass));
702 }
703 
704 static const struct rockchip_rgb_funcs rk3562_rgb_funcs = {
705 	.prepare = rk3562_rgb_prepare,
706 };
707 
708 static const struct rockchip_rgb_data rk3562_rgb = {
709 	.funcs = &rk3562_rgb_funcs,
710 };
711 
712 static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
713 {
714 	regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass));
715 }
716 
717 static const struct rockchip_rgb_funcs rk3568_rgb_funcs = {
718 	.prepare = rk3568_rgb_prepare,
719 };
720 
721 static const struct rockchip_rgb_data rk3568_rgb = {
722 	.funcs = &rk3568_rgb_funcs,
723 };
724 
725 static void rk3576_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
726 {
727 	regmap_write(rgb->grf, RK3576_VCCIO_IOC_MISC_CON8,
728 		     RK3576_VOP_MCU_SEL(rgb->data_sync_bypass));
729 	regmap_write(rgb->grf, RK3576_VCCIO_IOC_MISC_CON8,
730 		     RK3576_VOP_DLL_SEL(true));
731 	regmap_write(rgb->grf, RK3576_VCCIO_IOC_MISC_CON8,
732 		     RK3576_VOP_DCLK_DELAYLINE(rgb->dclk_delayline));
733 }
734 
735 static const struct rockchip_rgb_funcs rk3576_rgb_funcs = {
736 	.prepare = rk3576_rgb_prepare,
737 };
738 
739 static const struct rockchip_rgb_data rk3576_rgb = {
740 	.dclk_delayline = 5,
741 	.funcs = &rk3576_rgb_funcs,
742 };
743 
744 static const struct udevice_id rockchip_rgb_ids[] = {
745 	{
746 		.compatible = "rockchip,px30-rgb",
747 		.data = (ulong)&px30_rgb,
748 	},
749 	{
750 		.compatible = "rockchip,rk1808-rgb",
751 		.data = (ulong)&rk1808_rgb,
752 	},
753 	{
754 		.compatible = "rockchip,rk3066-rgb",
755 	},
756 	{
757 		.compatible = "rockchip,rk3128-rgb",
758 	},
759 	{
760 		.compatible = "rockchip,rk3288-rgb",
761 		.data = (ulong)&rk3288_rgb,
762 	},
763 	{
764 		.compatible = "rockchip,rk3308-rgb",
765 	},
766 	{
767 		.compatible = "rockchip,rk3368-rgb",
768 		.data = (ulong)&rk3368_rgb,
769 	},
770 	{
771 		.compatible = "rockchip,rk3562-rgb",
772 		.data = (ulong)&rk3562_rgb,
773 	},
774 	{
775 		.compatible = "rockchip,rk3568-rgb",
776 		.data = (ulong)&rk3568_rgb,
777 	},
778 	{
779 		.compatible = "rockchip,rk3576-rgb",
780 		.data = (ulong)&rk3576_rgb,
781 	},
782 	{
783 		.compatible = "rockchip,rk3588-rgb",
784 	},
785 	{
786 		.compatible = "rockchip,rv1106-rgb",
787 		.data = (ulong)&rv1106_rgb,
788 	},
789 	{
790 		.compatible = "rockchip,rv1108-rgb",
791 	},
792 	{
793 		.compatible = "rockchip,rv1126-rgb",
794 		.data = (ulong)&rv1126_rgb,
795 	},
796 	{}
797 };
798 
799 U_BOOT_DRIVER(rockchip_rgb) = {
800 	.name = "rockchip_rgb",
801 	.id = UCLASS_DISPLAY,
802 	.of_match = rockchip_rgb_ids,
803 	.probe = rockchip_rgb_probe,
804 	.priv_auto_alloc_size = sizeof(struct rockchip_rgb),
805 };
806