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