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