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