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