xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_display.c (revision ac1dc0c37a5bde2bf6a399028a52c0fbe3f99d65)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <asm/unaligned.h>
8 #include <config.h>
9 #include <common.h>
10 #include <errno.h>
11 #include <libfdt.h>
12 #include <fdtdec.h>
13 #include <fdt_support.h>
14 #include <linux/list.h>
15 #include <linux/compat.h>
16 #include <linux/media-bus-format.h>
17 #include <malloc.h>
18 #include <video.h>
19 #include <video_rockchip.h>
20 #include <dm/device.h>
21 #include <dm/uclass-internal.h>
22 #include <asm/arch-rockchip/resource_img.h>
23 
24 #include "bmp_helper.h"
25 #include "rockchip_display.h"
26 #include "rockchip_crtc.h"
27 #include "rockchip_connector.h"
28 #include "rockchip_phy.h"
29 #include "rockchip_panel.h"
30 #include <dm.h>
31 #include <dm/of_access.h>
32 #include <dm/ofnode.h>
33 
34 #define RK_BLK_SIZE 512
35 
36 DECLARE_GLOBAL_DATA_PTR;
37 static LIST_HEAD(rockchip_display_list);
38 static LIST_HEAD(logo_cache_list);
39 
40 static unsigned long memory_start;
41 static unsigned long memory_end;
42 
43 static void init_display_buffer(ulong base)
44 {
45 	memory_start = base + DRM_ROCKCHIP_FB_SIZE;
46 	memory_end = memory_start;
47 }
48 
49 static void *get_display_buffer(int size)
50 {
51 	unsigned long roundup_memory = roundup(memory_end, PAGE_SIZE);
52 	void *buf;
53 
54 	if (roundup_memory + size > memory_start + MEMORY_POOL_SIZE) {
55 		printf("failed to alloc %dbyte memory to display\n", size);
56 		return NULL;
57 	}
58 	buf = (void *)roundup_memory;
59 
60 	memory_end = roundup_memory + size;
61 
62 	return buf;
63 }
64 
65 #if 0
66 static unsigned long get_display_size(void)
67 {
68 	return memory_end - memory_start;
69 }
70 #endif
71 
72 static bool can_direct_logo(int bpp)
73 {
74 	return bpp == 24 || bpp == 32;
75 }
76 
77 
78 static struct udevice *get_panel_device(struct display_state *state, ofnode conn_node)
79 {
80 	struct panel_state *panel_state = &state->panel_state;
81 	struct udevice *dev;
82 	struct connector_state *conn_state = &state->conn_state;
83 	ofnode node, ports_node, port_node;
84 	struct device_node *port, *panel, *ep;
85 	int ph;
86 	int ret;
87 
88 	node = dev_read_subnode(conn_state->dev, "panel");
89 	if (ofnode_valid(node) &&
90 	    of_device_is_available(ofnode_to_np(node))){
91 		ret = uclass_get_device_by_ofnode(UCLASS_PANEL, node, &dev);
92 		if(!ret) {
93 			printf("%s get panel dev\n", __func__);
94 			panel_state->node = node;
95 			return dev;
96 		}
97 	}
98 
99 	/* TODO: this path not tested */
100 	ports_node = dev_read_subnode(conn_state->dev, "ports");
101 	if (!ofnode_valid(ports_node))
102 		return NULL;
103 
104 	ofnode_for_each_subnode(port_node, ports_node) {
105 		ofnode_for_each_subnode(node, port_node) {
106 			ph = ofnode_read_u32_default(node, "remote-endpoint", -1);
107 			if (!ph)
108 				continue;
109 			ep = of_find_node_by_phandle(ph);
110 			if (!ofnode_valid(np_to_ofnode(ep))) {
111 				printf("Warn: can't find endpoint from phdl\n");
112 				continue;
113 			}
114 			port = of_get_parent(ep);
115 			if (!ofnode_valid(np_to_ofnode(port))) {
116 				printf("Warn: can't find port node\n");
117 				continue;
118 			}
119 			panel = of_get_parent(port);
120 			if (!ofnode_valid(np_to_ofnode(panel))) {
121 				printf("Warn: can't find panel node\n");
122 				continue;
123 			}
124 			ret = uclass_get_device_by_ofnode(UCLASS_PANEL,
125 							  np_to_ofnode(panel),
126 							  &dev);
127 			if (ret) {
128 				printf("Warn: can't find crtc driver\n");
129 				continue;
130 			}
131 			return dev;
132 		}
133 	}
134 
135 	return NULL;
136 }
137 
138 static int connector_phy_init(struct display_state *state)
139 {
140 	struct connector_state *conn_state = &state->conn_state;
141 	const struct rockchip_phy *phy;
142 	struct udevice *dev;
143 	int ret;
144 
145 	ret = uclass_get_device_by_phandle(UCLASS_PHY, conn_state->dev, "phys",
146 					   &dev);
147 	if (ret) {
148 		printf("Warn: can't find phy driver\n");
149 		return ret;
150 	}
151 	phy = (const struct rockchip_phy *)dev_get_driver_data(dev);
152 	if (!phy) {
153 		printf("failed to find phy driver\n");
154 		return 0;
155 	}
156 
157 	conn_state->phy_dev = dev;
158 	conn_state->phy_node = dev->node;
159 
160 	if (!phy->funcs || !phy->funcs->init ||
161 	    phy->funcs->init(state)) {
162 		printf("failed to init phy driver\n");
163 		return -EINVAL;
164 	}
165 
166 	conn_state->phy = phy;
167 	return 0;
168 }
169 
170 static int connector_panel_init(struct display_state *state)
171 {
172 	struct connector_state *conn_state = &state->conn_state;
173 	struct panel_state *panel_state = &state->panel_state;
174 	struct udevice *dev;
175 	ofnode conn_node = conn_state->node;
176 	const struct rockchip_panel *panel;
177 	ofnode dsp_lut_node;
178 	int ret, len;
179 
180 	dm_scan_fdt_dev(conn_state->dev);
181 
182 	dev = get_panel_device(state, conn_node);
183 	if (!dev) {
184 		return 0;
185 	}
186 
187 	panel = (const struct rockchip_panel *)dev_get_driver_data(dev);
188 	if (!panel) {
189 		printf("failed to find panel driver\n");
190 		return 0;
191 	}
192 
193 	panel_state->dev = dev;
194 	panel_state->panel = panel;
195 
196 	ret = rockchip_panel_init(state);
197 	if (ret) {
198 		printf("failed to init panel driver\n");
199 		return ret;
200 	}
201 	dsp_lut_node = dev_read_subnode(dev, "dsp-lut");
202 	if (!ofnode_valid(dsp_lut_node)) {
203 		printf("%s can not find dsp-lut node\n", __func__);
204 	}
205 	ofnode_get_property(dsp_lut_node, "gamma-lut", &len);
206 	if (len > 0) {
207 		conn_state->gamma.size = len / sizeof(u32);
208 		conn_state->gamma.lut = malloc(len);
209 		if (!conn_state->gamma.lut) {
210 			printf("malloc gamma lut failed\n");
211 			return -ENOMEM;
212 		}
213 		ret = ofnode_read_u32_array(dsp_lut_node, "gamma-lut",
214 					    conn_state->gamma.lut,
215 					    conn_state->gamma.size);
216 		if (ret) {
217 			printf("Cannot decode gamma_lut\n");
218 			conn_state->gamma.lut = NULL;
219 			return -EINVAL;
220 		}
221 		panel_state->dsp_lut_node = dsp_lut_node;
222 	}
223 
224 	return 0;
225 }
226 
227 int drm_mode_vrefresh(const struct drm_display_mode *mode)
228 {
229 	int refresh = 0;
230 	unsigned int calc_val;
231 
232 	if (mode->vrefresh > 0) {
233 		refresh = mode->vrefresh;
234 	} else if (mode->htotal > 0 && mode->vtotal > 0) {
235 		int vtotal;
236 
237 		vtotal = mode->vtotal;
238 		/* work out vrefresh the value will be x1000 */
239 		calc_val = (mode->clock * 1000);
240 		calc_val /= mode->htotal;
241 		refresh = (calc_val + vtotal / 2) / vtotal;
242 
243 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
244 			refresh *= 2;
245 		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
246 			refresh /= 2;
247 		if (mode->vscan > 1)
248 			refresh /= mode->vscan;
249 	}
250 	return refresh;
251 }
252 
253 static int display_get_timing_from_dts(struct panel_state *panel_state,
254 				       struct drm_display_mode *mode)
255 {
256 	int phandle;
257 	int hactive, vactive, pixelclock;
258 	int hfront_porch, hback_porch, hsync_len;
259 	int vfront_porch, vback_porch, vsync_len;
260 	int val, flags = 0;
261 	ofnode timing, native_mode;
262 
263 	timing = dev_read_subnode(panel_state->dev, "display-timings");
264 	if (!ofnode_valid(timing))
265 		return -ENODEV;
266 
267 	native_mode = ofnode_find_subnode(timing, "timing");
268 	if (!ofnode_valid(native_mode)) {
269 		phandle = ofnode_read_u32_default(timing, "native-mode", -1);
270 		native_mode = np_to_ofnode(of_find_node_by_phandle(phandle));
271 		if (!ofnode_valid(native_mode)) {
272 			printf("failed to get display timings from DT\n");
273 			return -ENXIO;
274 		}
275 	}
276 
277 #define FDT_GET_INT(val, name) \
278 	val = ofnode_read_s32_default(native_mode, name, -1); \
279 	if (val < 0) { \
280 		printf("Can't get %s\n", name); \
281 		return -ENXIO; \
282 	}
283 
284 	FDT_GET_INT(hactive, "hactive");
285 	FDT_GET_INT(vactive, "vactive");
286 	FDT_GET_INT(pixelclock, "clock-frequency");
287 	FDT_GET_INT(hsync_len, "hsync-len");
288 	FDT_GET_INT(hfront_porch, "hfront-porch");
289 	FDT_GET_INT(hback_porch, "hback-porch");
290 	FDT_GET_INT(vsync_len, "vsync-len");
291 	FDT_GET_INT(vfront_porch, "vfront-porch");
292 	FDT_GET_INT(vback_porch, "vback-porch");
293 	FDT_GET_INT(val, "hsync-active");
294 	flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
295 	FDT_GET_INT(val, "vsync-active");
296 	flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
297 
298 	mode->hdisplay = hactive;
299 	mode->hsync_start = mode->hdisplay + hfront_porch;
300 	mode->hsync_end = mode->hsync_start + hsync_len;
301 	mode->htotal = mode->hsync_end + hback_porch;
302 
303 	mode->vdisplay = vactive;
304 	mode->vsync_start = mode->vdisplay + vfront_porch;
305 	mode->vsync_end = mode->vsync_start + vsync_len;
306 	mode->vtotal = mode->vsync_end + vback_porch;
307 
308 	mode->clock = pixelclock / 1000;
309 	mode->flags = flags;
310 
311 	return 0;
312 }
313 
314 static int display_get_timing(struct display_state *state)
315 {
316 	struct connector_state *conn_state = &state->conn_state;
317 	const struct rockchip_connector *conn = conn_state->connector;
318 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
319 	struct drm_display_mode *mode = &conn_state->mode;
320 	const struct drm_display_mode *m;
321 	struct panel_state *panel_state = &state->panel_state;
322 	ofnode panel = panel_state->node;
323 
324 	if (ofnode_valid(panel) && !display_get_timing_from_dts(panel_state, mode)) {
325 		printf("Using display timing dts\n");
326 		goto done;
327 	}
328 
329 	m = rockchip_get_display_mode_from_panel(state);
330 	if (m) {
331 		printf("Using display timing from compatible panel driver\n");
332 		memcpy(mode, m, sizeof(*m));
333 		goto done;
334 	}
335 
336 	rockchip_panel_prepare(state);
337 
338 	if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) {
339 		int panel_bits_per_colourp;
340 
341 		if (!edid_get_drm_mode((void *)&conn_state->edid,
342 				     sizeof(conn_state->edid), mode,
343 				     &panel_bits_per_colourp)) {
344 			printf("Using display timing from edid\n");
345 			edid_print_info((void *)&conn_state->edid);
346 			goto done;
347 		}
348 	}
349 
350 	printf("failed to find display timing\n");
351 	return -ENODEV;
352 done:
353 	printf("Detailed mode clock %u kHz, flags[%x]\n"
354 	       "    H: %04d %04d %04d %04d\n"
355 	       "    V: %04d %04d %04d %04d\n"
356 	       "bus_format: %x\n",
357 	       mode->clock, mode->flags,
358 	       mode->hdisplay, mode->hsync_start,
359 	       mode->hsync_end, mode->htotal,
360 	       mode->vdisplay, mode->vsync_start,
361 	       mode->vsync_end, mode->vtotal,
362 	       conn_state->bus_format);
363 
364 	return 0;
365 }
366 
367 static int display_init(struct display_state *state)
368 {
369 	struct connector_state *conn_state = &state->conn_state;
370 	const struct rockchip_connector *conn = conn_state->connector;
371 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
372 	struct crtc_state *crtc_state = &state->crtc_state;
373 	const struct rockchip_crtc *crtc = crtc_state->crtc;
374 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
375 	int ret = 0;
376 
377 	if (state->is_init)
378 		return 0;
379 
380 	if (!conn_funcs || !crtc_funcs) {
381 		printf("failed to find connector or crtc functions\n");
382 		return -ENXIO;
383 	}
384 
385 	if (conn_funcs->init) {
386 		ret = conn_funcs->init(state);
387 		if (ret)
388 			goto deinit;
389 	}
390 	/*
391 	 * support hotplug, but not connect;
392 	 */
393 	if (conn_funcs->detect) {
394 		ret = conn_funcs->detect(state);
395 		if (!ret)
396 			goto deinit;
397 	}
398 
399 	if (conn_funcs->get_timing) {
400 		ret = conn_funcs->get_timing(state);
401 		if (ret)
402 			goto deinit;
403 	} else {
404 		ret = display_get_timing(state);
405 		if (ret)
406 			goto deinit;
407 	}
408 
409 	if (crtc_funcs->init) {
410 		ret = crtc_funcs->init(state);
411 		if (ret)
412 			goto deinit;
413 	}
414 
415 	state->is_init = 1;
416 
417 	return 0;
418 
419 deinit:
420 	if (conn_funcs->deinit)
421 		conn_funcs->deinit(state);
422 	return ret;
423 }
424 
425 static int display_set_plane(struct display_state *state)
426 {
427 	struct crtc_state *crtc_state = &state->crtc_state;
428 	const struct rockchip_crtc *crtc = crtc_state->crtc;
429 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
430 	int ret;
431 
432 	if (!state->is_init)
433 		return -EINVAL;
434 
435 	if (crtc_funcs->set_plane) {
436 		ret = crtc_funcs->set_plane(state);
437 		if (ret)
438 			return ret;
439 	}
440 
441 	return 0;
442 }
443 
444 static int display_enable(struct display_state *state)
445 {
446 	struct connector_state *conn_state = &state->conn_state;
447 	const struct rockchip_connector *conn = conn_state->connector;
448 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
449 	struct crtc_state *crtc_state = &state->crtc_state;
450 	const struct rockchip_crtc *crtc = crtc_state->crtc;
451 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
452 	int ret = 0;
453 
454 	display_init(state);
455 
456 	if (!state->is_init)
457 		return -EINVAL;
458 
459 	if (state->is_enable)
460 		return 0;
461 
462 	if (crtc_funcs->prepare) {
463 		ret = crtc_funcs->prepare(state);
464 		if (ret)
465 			return ret;
466 	}
467 
468 	if (conn_funcs->prepare) {
469 		ret = conn_funcs->prepare(state);
470 		if (ret)
471 			goto unprepare_crtc;
472 	}
473 
474 	rockchip_panel_prepare(state);
475 
476 	if (crtc_funcs->enable) {
477 		ret = crtc_funcs->enable(state);
478 		if (ret)
479 			goto unprepare_conn;
480 	}
481 
482 	if (conn_funcs->enable) {
483 		ret = conn_funcs->enable(state);
484 		if (ret)
485 			goto disable_crtc;
486 	}
487 
488 	rockchip_panel_enable(state);
489 
490 	state->is_enable = true;
491 
492 	return 0;
493 unprepare_crtc:
494 	if (crtc_funcs->unprepare)
495 		crtc_funcs->unprepare(state);
496 unprepare_conn:
497 	if (conn_funcs->unprepare)
498 		conn_funcs->unprepare(state);
499 disable_crtc:
500 	if (crtc_funcs->disable)
501 		crtc_funcs->disable(state);
502 	return ret;
503 }
504 
505 static int display_disable(struct display_state *state)
506 {
507 	struct connector_state *conn_state = &state->conn_state;
508 	const struct rockchip_connector *conn = conn_state->connector;
509 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
510 	struct crtc_state *crtc_state = &state->crtc_state;
511 	const struct rockchip_crtc *crtc = crtc_state->crtc;
512 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
513 
514 	if (!state->is_init)
515 		return 0;
516 
517 	if (!state->is_enable)
518 		return 0;
519 
520 	rockchip_panel_disable(state);
521 
522 	if (crtc_funcs->disable)
523 		crtc_funcs->disable(state);
524 
525 	if (conn_funcs->disable)
526 		conn_funcs->disable(state);
527 
528 	rockchip_panel_unprepare(state);
529 
530 	if (conn_funcs->unprepare)
531 		conn_funcs->unprepare(state);
532 
533 	state->is_enable = 0;
534 	state->is_init = 0;
535 
536 	return 0;
537 }
538 
539 static int display_logo(struct display_state *state)
540 {
541 	struct crtc_state *crtc_state = &state->crtc_state;
542 	struct connector_state *conn_state = &state->conn_state;
543 	struct logo_info *logo = &state->logo;
544 	int hdisplay, vdisplay;
545 
546 	display_init(state);
547 	if (!state->is_init)
548 		return -ENODEV;
549 
550 	switch (logo->bpp) {
551 	case 16:
552 		crtc_state->format = ROCKCHIP_FMT_RGB565;
553 		break;
554 	case 24:
555 		crtc_state->format = ROCKCHIP_FMT_RGB888;
556 		break;
557 	case 32:
558 		crtc_state->format = ROCKCHIP_FMT_ARGB8888;
559 		break;
560 	default:
561 		printf("can't support bmp bits[%d]\n", logo->bpp);
562 		return -EINVAL;
563 	}
564 	crtc_state->rb_swap = logo->bpp != 32;
565 	hdisplay = conn_state->mode.hdisplay;
566 	vdisplay = conn_state->mode.vdisplay;
567 	crtc_state->src_w = logo->width;
568 	crtc_state->src_h = logo->height;
569 	crtc_state->src_x = 0;
570 	crtc_state->src_y = 0;
571 	crtc_state->ymirror = logo->ymirror;
572 
573 	crtc_state->dma_addr = (u32)(unsigned long)logo->mem + logo->offset;
574 	crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5;
575 
576 	if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) {
577 		crtc_state->crtc_x = 0;
578 		crtc_state->crtc_y = 0;
579 		crtc_state->crtc_w = hdisplay;
580 		crtc_state->crtc_h = vdisplay;
581 	} else {
582 		if (crtc_state->src_w >= hdisplay) {
583 			crtc_state->crtc_x = 0;
584 			crtc_state->crtc_w = hdisplay;
585 		} else {
586 			crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2;
587 			crtc_state->crtc_w = crtc_state->src_w;
588 		}
589 
590 		if (crtc_state->src_h >= vdisplay) {
591 			crtc_state->crtc_y = 0;
592 			crtc_state->crtc_h = vdisplay;
593 		} else {
594 			crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2;
595 			crtc_state->crtc_h = crtc_state->src_h;
596 		}
597 	}
598 
599 	display_set_plane(state);
600 	display_enable(state);
601 
602 	return 0;
603 }
604 
605 static int get_crtc_id(ofnode connect)
606 {
607 	int phandle;
608 	struct device_node *remote;
609 	int val;
610 
611 	phandle = ofnode_read_u32_default(connect, "remote-endpoint", -1);
612 	if (phandle < 0)
613 		goto err;
614 	remote = of_find_node_by_phandle(phandle);
615 	val = ofnode_read_u32_default(np_to_ofnode(remote), "reg", -1);
616 	if (val < 0)
617 		goto err;
618 
619 	return val;
620 err:
621 	printf("Can't get crtc id, default set to id = 0\n");
622 	return 0;
623 }
624 
625 struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp)
626 {
627 	struct rockchip_logo_cache *tmp, *logo_cache = NULL;
628 
629 	list_for_each_entry(tmp, &logo_cache_list, head) {
630 		if (!strcmp(tmp->name, bmp)) {
631 			logo_cache = tmp;
632 			break;
633 		}
634 	}
635 
636 	if (!logo_cache) {
637 		logo_cache = malloc(sizeof(*logo_cache));
638 		if (!logo_cache) {
639 			printf("failed to alloc memory for logo cache\n");
640 			return NULL;
641 		}
642 		memset(logo_cache, 0, sizeof(*logo_cache));
643 		strcpy(logo_cache->name, bmp);
644 		INIT_LIST_HEAD(&logo_cache->head);
645 		list_add_tail(&logo_cache->head, &logo_cache_list);
646 	}
647 
648 	return logo_cache;
649 }
650 
651 static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
652 {
653 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
654 	struct rockchip_logo_cache *logo_cache;
655 	struct bmp_header *header;
656 	void *dst = NULL, *pdst;
657 	int size, len;
658 	int ret = 0;
659 
660 	if (!logo || !bmp_name)
661 		return -EINVAL;
662 	logo_cache = find_or_alloc_logo_cache(bmp_name);
663 	if (!logo_cache)
664 		return -ENOMEM;
665 
666 	if (logo_cache->logo.mem) {
667 		memcpy(logo, &logo_cache->logo, sizeof(*logo));
668 		return 0;
669 	}
670 
671 	header = malloc(RK_BLK_SIZE);
672 	if (!header)
673 		return -ENOMEM;
674 
675 	len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
676 	if (len != RK_BLK_SIZE) {
677 		ret = -EINVAL;
678 		goto free_header;
679 	}
680 
681 	logo->bpp = get_unaligned_le16(&header->bit_count);
682 	logo->width = get_unaligned_le32(&header->width);
683 	logo->height = get_unaligned_le32(&header->height);
684 	size = get_unaligned_le32(&header->file_size);
685 	if (!can_direct_logo(logo->bpp)) {
686 		if (size > MEMORY_POOL_SIZE) {
687 			printf("failed to use boot buf as temp bmp buffer\n");
688 			ret = -ENOMEM;
689 			goto free_header;
690 		}
691 		pdst = get_display_buffer(size);
692 
693 	} else {
694 		pdst = get_display_buffer(size);
695 		dst = pdst;
696 	}
697 
698 	len = rockchip_read_resource_file(pdst, bmp_name, 0, size);
699 	if (len != size) {
700 		printf("failed to load bmp %s\n", bmp_name);
701 		ret = -ENOENT;
702 		goto free_header;
703 	}
704 
705 	if (!can_direct_logo(logo->bpp)) {
706 		int dst_size;
707 		/*
708 		 * TODO: force use 16bpp if bpp less than 16;
709 		 */
710 		logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp;
711 		dst_size = logo->width * logo->height * logo->bpp >> 3;
712 
713 		dst = get_display_buffer(dst_size);
714 		if (!dst) {
715 			ret = -ENOMEM;
716 			goto free_header;
717 		}
718 		if (bmpdecoder(pdst, dst, logo->bpp)) {
719 			printf("failed to decode bmp %s\n", bmp_name);
720 			ret = -EINVAL;
721 			goto free_header;
722 		}
723 		flush_dcache_range((ulong)dst,
724 				   ALIGN((ulong)dst + dst_size,
725 					 CONFIG_SYS_CACHELINE_SIZE));
726 
727 		logo->offset = 0;
728 		logo->ymirror = 0;
729 	} else {
730 		logo->offset = get_unaligned_le32(&header->data_offset);
731 		logo->ymirror = 1;
732 	}
733 	logo->mem = dst;
734 
735 	memcpy(&logo_cache->logo, logo, sizeof(*logo));
736 
737 free_header:
738 
739 	free(header);
740 
741 	return ret;
742 #else
743 	return -EINVAL;
744 #endif
745 }
746 
747 void rockchip_show_fbbase(ulong fbbase)
748 {
749 	struct display_state *s;
750 
751 	list_for_each_entry(s, &rockchip_display_list, head) {
752 		s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN;
753 		s->logo.mem = (char *)fbbase;
754 		s->logo.width = DRM_ROCKCHIP_FB_WIDTH;
755 		s->logo.height = DRM_ROCKCHIP_FB_HEIGHT;
756 		s->logo.bpp = 32;
757 		s->logo.ymirror = 0;
758 
759 		display_logo(s);
760 	}
761 }
762 
763 void rockchip_show_bmp(const char *bmp)
764 {
765 	struct display_state *s;
766 
767 	if (!bmp) {
768 		list_for_each_entry(s, &rockchip_display_list, head)
769 			display_disable(s);
770 		return;
771 	}
772 
773 	list_for_each_entry(s, &rockchip_display_list, head) {
774 		s->logo.mode = s->charge_logo_mode;
775 		if (load_bmp_logo(&s->logo, bmp))
776 			continue;
777 		display_logo(s);
778 	}
779 }
780 
781 void rockchip_show_logo(void)
782 {
783 	struct display_state *s;
784 
785 	list_for_each_entry(s, &rockchip_display_list, head) {
786 		s->logo.mode = s->logo_mode;
787 		if (load_bmp_logo(&s->logo, s->ulogo_name))
788 			printf("failed to display uboot logo\n");
789 		else
790 			display_logo(s);
791 		if (load_bmp_logo(&s->logo, s->klogo_name))
792 			printf("failed to display kernel logo\n");
793 	}
794 }
795 
796 static int rockchip_display_probe(struct udevice *dev)
797 {
798 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
799 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
800 	const void *blob = gd->fdt_blob;
801 	int phandle;
802 	struct udevice *crtc_dev, *conn_dev;
803 	const struct rockchip_crtc *crtc;
804 	const struct rockchip_connector *conn;
805 	struct display_state *s;
806 	const char *name;
807 	int ret;
808 	ofnode node, route_node;
809 	struct device_node *port_node, *vop_node, *ep_node;
810 	struct device_node *cnt_node, *p;
811 
812 	/* Before relocation we don't need to do anything */
813 	if (!(gd->flags & GD_FLG_RELOC))
814 		return 0;
815 	init_display_buffer(plat->base);
816 
817 	route_node = dev_read_subnode(dev, "route");
818 	if (!ofnode_valid(route_node))
819 		return -ENODEV;
820 
821 	ofnode_for_each_subnode(node, route_node){
822 		phandle = ofnode_read_u32_default(node, "connect", -1);
823 		if (phandle < 0) {
824 			printf("Warn: can't find connect node's handle\n");
825 			continue;
826 		}
827 		ep_node = of_find_node_by_phandle(phandle);
828 		if (!ofnode_valid(np_to_ofnode(ep_node))) {
829 			printf("Warn: can't find endpoint node from phandle\n");
830 			continue;
831 		}
832 		port_node = of_get_parent(ep_node);
833 		if (!ofnode_valid(np_to_ofnode(port_node))) {
834 			printf("Warn: can't find port node from phandle\n");
835 			continue;
836 		}
837 		vop_node = of_get_parent(port_node);
838 		if (!ofnode_valid(np_to_ofnode(vop_node))) {
839 			printf("Warn: can't find crtc node from phandle\n");
840 			continue;
841 		}
842 		ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC,
843 						  np_to_ofnode(vop_node),
844 						  &crtc_dev);
845 		if (ret) {
846 			printf("Warn: can't find crtc driver\n");
847 			continue;
848 		}
849 		crtc = (const struct rockchip_crtc *)dev_get_driver_data(crtc_dev);
850 
851 		phandle = ofnode_read_u32_default(np_to_ofnode(ep_node),
852 						  "remote-endpoint", -1);
853 		cnt_node = of_find_node_by_phandle(phandle);
854 		if (phandle < 0) {
855 			printf("Warn: can't find remote-endpoint's handle\n");
856 			continue;
857 		}
858 		while (cnt_node->parent){
859 			p = of_get_parent(cnt_node);
860 			if (!strcmp(p->full_name, "/"))
861 				break;
862 			cnt_node = p;
863 		}
864 		if (!of_device_is_available(cnt_node))
865 			continue;
866 		ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY,
867 						  np_to_ofnode(cnt_node),
868 						  &conn_dev);
869 		if (ret) {
870 			printf("Warn: can't find connect driver\n");
871 			continue;
872 		}
873 		conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev);
874 
875 		s = malloc(sizeof(*s));
876 		if (!s)
877 			continue;
878 
879 		memset(s, 0, sizeof(*s));
880 
881 		INIT_LIST_HEAD(&s->head);
882 		ret = ofnode_read_string_index(node, "logo,uboot", 0, &s->ulogo_name);
883 		ret = ofnode_read_string_index(node, "logo,kernel", 0, &s->klogo_name);
884 		ret = ofnode_read_string_index(node, "logo,mode", 0, &name);
885 		if (!strcmp(name, "fullscreen"))
886 			s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
887 		else
888 			s->logo_mode = ROCKCHIP_DISPLAY_CENTER;
889 		ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name);
890 		if (!strcmp(name, "fullscreen"))
891 			s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
892 		else
893 			s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER;
894 
895 		s->blob = blob;
896 		s->conn_state.node = np_to_ofnode(cnt_node);
897 		s->conn_state.dev = conn_dev;
898 		s->conn_state.connector = conn;
899 		s->crtc_state.node = np_to_ofnode(vop_node);
900 		s->crtc_state.dev = crtc_dev;
901 		s->crtc_state.crtc = crtc;
902 		s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node));
903 		s->node = node;
904 
905 		if (connector_panel_init(s)) {
906 			printf("Warn: Failed to init panel drivers\n");
907 			free(s);
908 			continue;
909 		}
910 
911 		if (connector_phy_init(s)) {
912 			printf("Warn: Failed to init phy drivers\n");
913 			free(s);
914 			continue;
915 		}
916 		list_add_tail(&s->head, &rockchip_display_list);
917 
918 	}
919 
920 	if (list_empty(&rockchip_display_list)) {
921 		printf("Failed to found available display route\n");
922 		return -ENODEV;
923 	}
924 
925 	uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH;
926 	uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT;
927 	uc_priv->bpix = VIDEO_BPP32;
928 
929 	#ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER
930 	rockchip_show_fbbase(plat->base);
931 	video_set_flush_dcache(dev, true);
932 	#endif
933 
934 	return 0;
935 }
936 
937 #if 0
938 void rockchip_display_fixup(void *blob)
939 {
940 	const struct rockchip_connector_funcs *conn_funcs;
941 	const struct rockchip_crtc_funcs *crtc_funcs;
942 	const struct rockchip_connector *conn;
943 	const struct rockchip_crtc *crtc;
944 	struct display_state *s;
945 	u32 offset;
946 	int node;
947 	char path[100];
948 	int ret;
949 
950 	if (!get_display_size())
951 		return;
952 
953 	node = fdt_update_reserved_memory(blob, "rockchip,drm-logo",
954 					       (u64)memory_start,
955 					       (u64)get_display_size());
956 	if (node < 0) {
957 		printf("failed to add drm-loader-logo memory\n");
958 		return;
959 	}
960 
961 	list_for_each_entry(s, &rockchip_display_list, head) {
962 		conn = s->conn_state.connector;
963 		if (!conn)
964 			continue;
965 		conn_funcs = conn->funcs;
966 		if (!conn_funcs) {
967 			printf("failed to get exist connector\n");
968 			continue;
969 		}
970 
971 		crtc = s->crtc_state.crtc;
972 		if (!crtc)
973 			continue;
974 
975 		crtc_funcs = crtc->funcs;
976 		if (!crtc_funcs) {
977 			printf("failed to get exist crtc\n");
978 			continue;
979 		}
980 
981 		if (crtc_funcs->fixup_dts)
982 			crtc_funcs->fixup_dts(s, blob);
983 
984 		if (conn_funcs->fixup_dts)
985 			conn_funcs->fixup_dts(s, blob);
986 
987 		ret = fdt_get_path(s->blob, s->node, path, sizeof(path));
988 		if (ret < 0) {
989 			printf("failed to get route path[%s], ret=%d\n",
990 			       path, ret);
991 			continue;
992 		}
993 
994 #define FDT_SET_U32(name, val) \
995 		do_fixup_by_path_u32(blob, path, name, val, 1);
996 
997 		offset = s->logo.offset + s->logo.mem - memory_start;
998 		FDT_SET_U32("logo,offset", offset);
999 		FDT_SET_U32("logo,width", s->logo.width);
1000 		FDT_SET_U32("logo,height", s->logo.height);
1001 		FDT_SET_U32("logo,bpp", s->logo.bpp);
1002 		FDT_SET_U32("logo,ymirror", s->logo.ymirror);
1003 		FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay);
1004 		FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay);
1005 		FDT_SET_U32("video,vrefresh",
1006 			    drm_mode_vrefresh(&s->conn_state.mode));
1007 #undef FDT_SET_U32
1008 	}
1009 }
1010 #endif
1011 
1012 int rockchip_display_bind(struct udevice *dev)
1013 {
1014 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
1015 
1016 	plat->size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE;
1017 
1018 	return 0;
1019 }
1020 
1021 static const struct udevice_id rockchip_display_ids[] = {
1022 	{ .compatible = "rockchip,display-subsystem" },
1023 	{ }
1024 };
1025 
1026 U_BOOT_DRIVER(rockchip_display) = {
1027 	.name	= "rockchip_display",
1028 	.id	= UCLASS_VIDEO,
1029 	.of_match = rockchip_display_ids,
1030 	.bind	= rockchip_display_bind,
1031 	.probe	= rockchip_display_probe,
1032 };
1033 
1034 static int do_rockchip_logo_show(cmd_tbl_t *cmdtp, int flag, int argc,
1035 			char *const argv[])
1036 {
1037 	if (argc != 1)
1038 		return CMD_RET_USAGE;
1039 
1040 	rockchip_show_logo();
1041 
1042 	return 0;
1043 }
1044 
1045 static int do_rockchip_show_bmp(cmd_tbl_t *cmdtp, int flag, int argc,
1046 				char *const argv[])
1047 {
1048 	if (argc != 2)
1049 		return CMD_RET_USAGE;
1050 
1051 	rockchip_show_bmp(argv[1]);
1052 
1053 	return 0;
1054 }
1055 
1056 U_BOOT_CMD(
1057 	rockchip_show_logo, 1, 1, do_rockchip_logo_show,
1058 	"load and display log from resource partition",
1059 	NULL
1060 );
1061 
1062 U_BOOT_CMD(
1063 	rockchip_show_bmp, 2, 1, do_rockchip_show_bmp,
1064 	"load and display bmp from resource partition",
1065 	"    <bmp_name>"
1066 );
1067