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