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