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