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