xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_display.c (revision 8e2bab3fc592f2c222a220d894a033e964c97a7a)
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/hdmi.h>
15 #include <linux/list.h>
16 #include <linux/compat.h>
17 #include <linux/media-bus-format.h>
18 #include <malloc.h>
19 #include <video.h>
20 #include <video_rockchip.h>
21 #include <dm/device.h>
22 #include <dm/uclass-internal.h>
23 #include <asm/arch-rockchip/resource_img.h>
24 
25 #include "bmp_helper.h"
26 #include "rockchip_display.h"
27 #include "rockchip_crtc.h"
28 #include "rockchip_connector.h"
29 #include "rockchip_phy.h"
30 #include "rockchip_panel.h"
31 #include <dm.h>
32 #include <dm/of_access.h>
33 #include <dm/ofnode.h>
34 
35 #define DRIVER_VERSION	"v1.0.0"
36 
37 /***********************************************************************
38  *  Rockchip UBOOT DRM driver version
39  *
40  *  v1.0.0	: add basic version for rockchip drm driver(hjc)
41  *
42  **********************************************************************/
43 
44 #define RK_BLK_SIZE 512
45 
46 DECLARE_GLOBAL_DATA_PTR;
47 static LIST_HEAD(rockchip_display_list);
48 static LIST_HEAD(logo_cache_list);
49 
50 static unsigned long memory_start;
51 static unsigned long memory_end;
52 
53 static void init_display_buffer(ulong base)
54 {
55 	memory_start = base + DRM_ROCKCHIP_FB_SIZE;
56 	memory_end = memory_start;
57 }
58 
59 static void *get_display_buffer(int size)
60 {
61 	unsigned long roundup_memory = roundup(memory_end, PAGE_SIZE);
62 	void *buf;
63 
64 	if (roundup_memory + size > memory_start + MEMORY_POOL_SIZE) {
65 		printf("failed to alloc %dbyte memory to display\n", size);
66 		return NULL;
67 	}
68 	buf = (void *)roundup_memory;
69 
70 	memory_end = roundup_memory + size;
71 
72 	return buf;
73 }
74 
75 static unsigned long get_display_size(void)
76 {
77 	return memory_end - memory_start;
78 }
79 
80 static bool can_direct_logo(int bpp)
81 {
82 	return bpp == 24 || bpp == 32;
83 }
84 
85 
86 static struct udevice *get_panel_device(struct display_state *state, ofnode conn_node)
87 {
88 	struct panel_state *panel_state = &state->panel_state;
89 	struct udevice *dev;
90 	struct connector_state *conn_state = &state->conn_state;
91 	ofnode node, ports_node, port_node;
92 	struct device_node *port, *panel, *ep;
93 	int ph;
94 	int ret;
95 
96 	node = dev_read_subnode(conn_state->dev, "panel");
97 	if (ofnode_valid(node) &&
98 	    of_device_is_available(ofnode_to_np(node))) {
99 		ret = uclass_get_device_by_ofnode(UCLASS_PANEL, node, &dev);
100 		if (!ret) {
101 			panel_state->node = node;
102 			return dev;
103 		}
104 	}
105 
106 	/* TODO: this path not tested */
107 	ports_node = dev_read_subnode(conn_state->dev, "ports");
108 	if (!ofnode_valid(ports_node))
109 		return NULL;
110 
111 	ofnode_for_each_subnode(port_node, ports_node) {
112 		ofnode_for_each_subnode(node, port_node) {
113 			ph = ofnode_read_u32_default(node, "remote-endpoint", -1);
114 			if (!ph)
115 				continue;
116 			ep = of_find_node_by_phandle(ph);
117 			if (!ofnode_valid(np_to_ofnode(ep))) {
118 				printf("Warn: can't find endpoint from phdl\n");
119 				continue;
120 			}
121 			port = of_get_parent(ep);
122 			if (!ofnode_valid(np_to_ofnode(port))) {
123 				printf("Warn: can't find port node\n");
124 				continue;
125 			}
126 			panel = of_get_parent(port);
127 			if (!ofnode_valid(np_to_ofnode(panel))) {
128 				printf("Warn: can't find panel node\n");
129 				continue;
130 			}
131 			ret = uclass_get_device_by_ofnode(UCLASS_PANEL,
132 							  np_to_ofnode(panel),
133 							  &dev);
134 			if (!ret) {
135 				panel_state->node = np_to_ofnode(panel);
136 				return dev;
137 			}
138 		}
139 	}
140 
141 	return NULL;
142 }
143 
144 static int connector_phy_init(struct display_state *state)
145 {
146 	struct connector_state *conn_state = &state->conn_state;
147 	const struct rockchip_phy *phy;
148 	struct udevice *dev;
149 	int ret;
150 
151 	ret = uclass_get_device_by_phandle(UCLASS_PHY, conn_state->dev, "phys",
152 					   &dev);
153 	if (ret) {
154 		printf("Warn: can't find phy driver\n");
155 		return 0;
156 	}
157 
158 	phy = (const struct rockchip_phy *)dev_get_driver_data(dev);
159 	if (!phy) {
160 		printf("failed to find phy driver\n");
161 		return 0;
162 	}
163 
164 	conn_state->phy_dev = dev;
165 	conn_state->phy_node = dev->node;
166 
167 	if (!phy->funcs || !phy->funcs->init ||
168 	    phy->funcs->init(state)) {
169 		printf("failed to init phy driver\n");
170 		return -EINVAL;
171 	}
172 	conn_state->phy = phy;
173 	return 0;
174 }
175 
176 static int connector_panel_init(struct display_state *state)
177 {
178 	struct connector_state *conn_state = &state->conn_state;
179 	struct panel_state *panel_state = &state->panel_state;
180 	struct udevice *dev;
181 	ofnode conn_node = conn_state->node;
182 	const struct rockchip_panel *panel;
183 	ofnode dsp_lut_node;
184 	int ret, len;
185 
186 	dm_scan_fdt_dev(conn_state->dev);
187 
188 	dev = get_panel_device(state, conn_node);
189 	if (!dev) {
190 		return 0;
191 	}
192 
193 	panel = (const struct rockchip_panel *)dev_get_driver_data(dev);
194 	if (!panel) {
195 		printf("failed to find panel driver\n");
196 		return 0;
197 	}
198 
199 	panel_state->dev = dev;
200 	panel_state->panel = panel;
201 
202 	if (panel->funcs && panel->funcs->init) {
203 		ret = panel->funcs->init(state);
204 		if (ret) {
205 			printf("failed to init panel driver\n");
206 			return ret;
207 		}
208 	}
209 
210 	dsp_lut_node = dev_read_subnode(dev, "dsp-lut");
211 	if (!ofnode_valid(dsp_lut_node)) {
212 		debug("%s can not find dsp-lut node\n", __func__);
213 		return 0;
214 	}
215 
216 	ofnode_get_property(dsp_lut_node, "gamma-lut", &len);
217 	if (len > 0) {
218 		conn_state->gamma.size = len / sizeof(u32);
219 		conn_state->gamma.lut = malloc(len);
220 		if (!conn_state->gamma.lut) {
221 			printf("malloc gamma lut failed\n");
222 			return -ENOMEM;
223 		}
224 		ret = ofnode_read_u32_array(dsp_lut_node, "gamma-lut",
225 					    conn_state->gamma.lut,
226 					    conn_state->gamma.size);
227 		if (ret) {
228 			printf("Cannot decode gamma_lut\n");
229 			conn_state->gamma.lut = NULL;
230 			return -EINVAL;
231 		}
232 		panel_state->dsp_lut_node = dsp_lut_node;
233 	}
234 
235 	return 0;
236 }
237 
238 int drm_mode_vrefresh(const struct drm_display_mode *mode)
239 {
240 	int refresh = 0;
241 	unsigned int calc_val;
242 
243 	if (mode->vrefresh > 0) {
244 		refresh = mode->vrefresh;
245 	} else if (mode->htotal > 0 && mode->vtotal > 0) {
246 		int vtotal;
247 
248 		vtotal = mode->vtotal;
249 		/* work out vrefresh the value will be x1000 */
250 		calc_val = (mode->clock * 1000);
251 		calc_val /= mode->htotal;
252 		refresh = (calc_val + vtotal / 2) / vtotal;
253 
254 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
255 			refresh *= 2;
256 		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
257 			refresh /= 2;
258 		if (mode->vscan > 1)
259 			refresh /= mode->vscan;
260 	}
261 	return refresh;
262 }
263 
264 static int display_get_timing_from_dts(struct panel_state *panel_state,
265 				       struct drm_display_mode *mode)
266 {
267 	int phandle;
268 	int hactive, vactive, pixelclock;
269 	int hfront_porch, hback_porch, hsync_len;
270 	int vfront_porch, vback_porch, vsync_len;
271 	int val, flags = 0;
272 	ofnode timing, native_mode;
273 
274 	timing = dev_read_subnode(panel_state->dev, "display-timings");
275 	if (!ofnode_valid(timing))
276 		return -ENODEV;
277 
278 	native_mode = ofnode_find_subnode(timing, "timing");
279 	if (!ofnode_valid(native_mode)) {
280 		phandle = ofnode_read_u32_default(timing, "native-mode", -1);
281 		native_mode = np_to_ofnode(of_find_node_by_phandle(phandle));
282 		if (!ofnode_valid(native_mode)) {
283 			printf("failed to get display timings from DT\n");
284 			return -ENXIO;
285 		}
286 	}
287 
288 #define FDT_GET_INT(val, name) \
289 	val = ofnode_read_s32_default(native_mode, name, -1); \
290 	if (val < 0) { \
291 		printf("Can't get %s\n", name); \
292 		return -ENXIO; \
293 	}
294 
295 	FDT_GET_INT(hactive, "hactive");
296 	FDT_GET_INT(vactive, "vactive");
297 	FDT_GET_INT(pixelclock, "clock-frequency");
298 	FDT_GET_INT(hsync_len, "hsync-len");
299 	FDT_GET_INT(hfront_porch, "hfront-porch");
300 	FDT_GET_INT(hback_porch, "hback-porch");
301 	FDT_GET_INT(vsync_len, "vsync-len");
302 	FDT_GET_INT(vfront_porch, "vfront-porch");
303 	FDT_GET_INT(vback_porch, "vback-porch");
304 	FDT_GET_INT(val, "hsync-active");
305 	flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
306 	FDT_GET_INT(val, "vsync-active");
307 	flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
308 	FDT_GET_INT(val, "pixelclk-active");
309 	flags |= val ? DRM_MODE_FLAG_PPIXDATA : 0;
310 
311 	mode->hdisplay = hactive;
312 	mode->hsync_start = mode->hdisplay + hfront_porch;
313 	mode->hsync_end = mode->hsync_start + hsync_len;
314 	mode->htotal = mode->hsync_end + hback_porch;
315 
316 	mode->vdisplay = vactive;
317 	mode->vsync_start = mode->vdisplay + vfront_porch;
318 	mode->vsync_end = mode->vsync_start + vsync_len;
319 	mode->vtotal = mode->vsync_end + vback_porch;
320 
321 	mode->clock = pixelclock / 1000;
322 	mode->flags = flags;
323 
324 	return 0;
325 }
326 
327 /**
328  * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
329  * @p: mode
330  * @adjust_flags: a combination of adjustment flags
331  *
332  * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
333  *
334  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
335  *   interlaced modes.
336  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
337  *   buffers containing two eyes (only adjust the timings when needed, eg. for
338  *   "frame packing" or "side by side full").
339  * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
340  *   be performed for doublescan and vscan > 1 modes respectively.
341  */
342 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
343 {
344 	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
345 		return;
346 
347 	if (p->flags & DRM_MODE_FLAG_DBLCLK)
348 		p->crtc_clock = 2 * p->clock;
349 	else
350 		p->crtc_clock = p->clock;
351 	p->crtc_hdisplay = p->hdisplay;
352 	p->crtc_hsync_start = p->hsync_start;
353 	p->crtc_hsync_end = p->hsync_end;
354 	p->crtc_htotal = p->htotal;
355 	p->crtc_hskew = p->hskew;
356 	p->crtc_vdisplay = p->vdisplay;
357 	p->crtc_vsync_start = p->vsync_start;
358 	p->crtc_vsync_end = p->vsync_end;
359 	p->crtc_vtotal = p->vtotal;
360 
361 	if (p->flags & DRM_MODE_FLAG_INTERLACE) {
362 		if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
363 			p->crtc_vdisplay /= 2;
364 			p->crtc_vsync_start /= 2;
365 			p->crtc_vsync_end /= 2;
366 			p->crtc_vtotal /= 2;
367 		}
368 	}
369 
370 	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
371 		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
372 			p->crtc_vdisplay *= 2;
373 			p->crtc_vsync_start *= 2;
374 			p->crtc_vsync_end *= 2;
375 			p->crtc_vtotal *= 2;
376 		}
377 	}
378 
379 	if (!(adjust_flags & CRTC_NO_VSCAN)) {
380 		if (p->vscan > 1) {
381 			p->crtc_vdisplay *= p->vscan;
382 			p->crtc_vsync_start *= p->vscan;
383 			p->crtc_vsync_end *= p->vscan;
384 			p->crtc_vtotal *= p->vscan;
385 		}
386 	}
387 
388 	if (adjust_flags & CRTC_STEREO_DOUBLE) {
389 		unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
390 
391 		switch (layout) {
392 		case DRM_MODE_FLAG_3D_FRAME_PACKING:
393 			p->crtc_clock *= 2;
394 			p->crtc_vdisplay += p->crtc_vtotal;
395 			p->crtc_vsync_start += p->crtc_vtotal;
396 			p->crtc_vsync_end += p->crtc_vtotal;
397 			p->crtc_vtotal += p->crtc_vtotal;
398 			break;
399 		}
400 	}
401 
402 	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
403 	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
404 	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
405 	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
406 }
407 
408 /**
409  * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
410  * output format
411  *
412  * @connector: drm connector under action.
413  * @mode: video mode to be tested.
414  *
415  * Returns:
416  * true if the mode can be supported in YCBCR420 format
417  * false if not.
418  */
419 bool drm_mode_is_420_only(const struct drm_display_info *display,
420 			  struct drm_display_mode *mode)
421 {
422 	u8 vic = drm_match_cea_mode(mode);
423 
424 	return test_bit(vic, display->hdmi.y420_vdb_modes);
425 }
426 
427 /**
428  * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
429  * output format also (along with RGB/YCBCR444/422)
430  *
431  * @display: display under action.
432  * @mode: video mode to be tested.
433  *
434  * Returns:
435  * true if the mode can be support YCBCR420 format
436  * false if not.
437  */
438 bool drm_mode_is_420_also(const struct drm_display_info *display,
439 			  struct drm_display_mode *mode)
440 {
441 	u8 vic = drm_match_cea_mode(mode);
442 
443 	return test_bit(vic, display->hdmi.y420_cmdb_modes);
444 }
445 
446 /**
447  * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
448  * output format
449  *
450  * @display: display under action.
451  * @mode: video mode to be tested.
452  *
453  * Returns:
454  * true if the mode can be supported in YCBCR420 format
455  * false if not.
456  */
457 bool drm_mode_is_420(const struct drm_display_info *display,
458 		     struct drm_display_mode *mode)
459 {
460 	return drm_mode_is_420_only(display, mode) ||
461 		drm_mode_is_420_also(display, mode);
462 }
463 
464 static int display_get_timing(struct display_state *state)
465 {
466 	struct connector_state *conn_state = &state->conn_state;
467 	const struct rockchip_connector *conn = conn_state->connector;
468 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
469 	struct drm_display_mode *mode = &conn_state->mode;
470 	const struct drm_display_mode *m;
471 	struct panel_state *panel_state = &state->panel_state;
472 	const struct rockchip_panel *panel = panel_state->panel;
473 	const struct rockchip_panel_funcs *panel_funcs = panel->funcs;
474 	ofnode panel_node = panel_state->node;
475 	int ret;
476 
477 	if (ofnode_valid(panel_node) && !display_get_timing_from_dts(panel_state, mode)) {
478 		printf("Using display timing dts\n");
479 		goto done;
480 	}
481 
482 	if (panel->data) {
483 		m = (const struct drm_display_mode *)panel->data;
484 		memcpy(mode, m, sizeof(*m));
485 		printf("Using display timing from compatible panel driver\n");
486 		goto done;
487 	}
488 
489 	if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) {
490 		int panel_bits_per_colourp;
491 
492 		/* In order to read EDID, the panel needs to be powered on */
493 		if (panel_funcs->prepare) {
494 			ret = panel_funcs->prepare(state);
495 			if (ret) {
496 				printf("failed to prepare panel\n");
497 				return ret;
498 			}
499 		}
500 
501 		if (!edid_get_drm_mode((void *)&conn_state->edid,
502 				     sizeof(conn_state->edid), mode,
503 				     &panel_bits_per_colourp)) {
504 			printf("Using display timing from edid\n");
505 			edid_print_info((void *)&conn_state->edid);
506 			goto done;
507 		} else {
508 			if (panel_funcs->unprepare)
509 				panel_funcs->unprepare(state);
510 		}
511 	}
512 
513 	printf("failed to find display timing\n");
514 	return -ENODEV;
515 done:
516 	printf("Detailed mode clock %u kHz, flags[%x]\n"
517 	       "    H: %04d %04d %04d %04d\n"
518 	       "    V: %04d %04d %04d %04d\n"
519 	       "bus_format: %x\n",
520 	       mode->clock, mode->flags,
521 	       mode->hdisplay, mode->hsync_start,
522 	       mode->hsync_end, mode->htotal,
523 	       mode->vdisplay, mode->vsync_start,
524 	       mode->vsync_end, mode->vtotal,
525 	       conn_state->bus_format);
526 
527 	return 0;
528 }
529 
530 static int display_init(struct display_state *state)
531 {
532 	struct connector_state *conn_state = &state->conn_state;
533 	const struct rockchip_connector *conn = conn_state->connector;
534 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
535 	struct crtc_state *crtc_state = &state->crtc_state;
536 	const struct rockchip_crtc *crtc = crtc_state->crtc;
537 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
538 	struct drm_display_mode *mode = &conn_state->mode;
539 	int ret = 0;
540 	static bool __print_once = false;
541 
542 	if (!__print_once) {
543 		__print_once = true;
544 		printf("Rockchip UBOOT DRM driver version: %s\n", DRIVER_VERSION);
545 	}
546 
547 	if (state->is_init)
548 		return 0;
549 
550 	if (!conn_funcs || !crtc_funcs) {
551 		printf("failed to find connector or crtc functions\n");
552 		return -ENXIO;
553 	}
554 
555 	if (conn_funcs->init) {
556 		ret = conn_funcs->init(state);
557 		if (ret)
558 			goto deinit;
559 	}
560 	/*
561 	 * support hotplug, but not connect;
562 	 */
563 	if (conn_funcs->detect) {
564 		ret = conn_funcs->detect(state);
565 		if (!ret)
566 			goto deinit;
567 	}
568 
569 	if (conn_funcs->get_timing) {
570 		ret = conn_funcs->get_timing(state);
571 		if (ret)
572 			goto deinit;
573 	} else {
574 		ret = display_get_timing(state);
575 		if (ret)
576 			goto deinit;
577 	}
578 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
579 
580 	if (crtc_funcs->init) {
581 		ret = crtc_funcs->init(state);
582 		if (ret)
583 			goto deinit;
584 	}
585 	state->is_init = 1;
586 
587 	return 0;
588 
589 deinit:
590 	if (conn_funcs->deinit)
591 		conn_funcs->deinit(state);
592 	return ret;
593 }
594 
595 int display_send_mcu_cmd(struct display_state *state, u32 type, u32 val)
596 {
597 	struct crtc_state *crtc_state = &state->crtc_state;
598 	const struct rockchip_crtc *crtc = crtc_state->crtc;
599 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
600 	int ret;
601 
602 	if (!state->is_init)
603 		return -EINVAL;
604 
605 	if (crtc_funcs->send_mcu_cmd) {
606 		ret = crtc_funcs->send_mcu_cmd(state, type, val);
607 		if (ret)
608 			return ret;
609 	}
610 
611 	return 0;
612 }
613 
614 static int display_set_plane(struct display_state *state)
615 {
616 	struct crtc_state *crtc_state = &state->crtc_state;
617 	const struct rockchip_crtc *crtc = crtc_state->crtc;
618 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
619 	int ret;
620 
621 	if (!state->is_init)
622 		return -EINVAL;
623 
624 	if (crtc_funcs->set_plane) {
625 		ret = crtc_funcs->set_plane(state);
626 		if (ret)
627 			return ret;
628 	}
629 
630 	return 0;
631 }
632 
633 static int display_panel_prepare(struct display_state *state)
634 {
635 	struct panel_state *panel_state = &state->panel_state;
636 	const struct rockchip_panel *panel = panel_state->panel;
637 
638 	if (!panel || !panel->funcs || !panel->funcs->prepare) {
639 		printf("%s: failed to find panel prepare funcs\n", __func__);
640 		return -ENODEV;
641 	}
642 
643 	return panel->funcs->prepare(state);
644 }
645 
646 static int display_panel_enable(struct display_state *state)
647 {
648 	struct panel_state *panel_state = &state->panel_state;
649 	const struct rockchip_panel *panel = panel_state->panel;
650 
651 	if (!panel || !panel->funcs || !panel->funcs->enable) {
652 		printf("%s: failed to find panel enable funcs\n", __func__);
653 		return -ENODEV;
654 	}
655 
656 	return panel->funcs->enable(state);
657 }
658 
659 static void display_panel_unprepare(struct display_state *state)
660 {
661 	struct panel_state *panel_state = &state->panel_state;
662 	const struct rockchip_panel *panel = panel_state->panel;
663 
664 	if (!panel || !panel->funcs || !panel->funcs->unprepare) {
665 		printf("%s: failed to find panel unprepare funcs\n", __func__);
666 		return;
667 	}
668 
669 	panel->funcs->unprepare(state);
670 }
671 
672 static void display_panel_disable(struct display_state *state)
673 {
674 	struct panel_state *panel_state = &state->panel_state;
675 	const struct rockchip_panel *panel = panel_state->panel;
676 
677 	if (!panel || !panel->funcs || !panel->funcs->disable) {
678 		printf("%s: failed to find panel disable funcs\n", __func__);
679 		return;
680 	}
681 
682 	panel->funcs->disable(state);
683 }
684 
685 static int display_enable(struct display_state *state)
686 {
687 	struct connector_state *conn_state = &state->conn_state;
688 	const struct rockchip_connector *conn = conn_state->connector;
689 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
690 	struct crtc_state *crtc_state = &state->crtc_state;
691 	const struct rockchip_crtc *crtc = crtc_state->crtc;
692 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
693 	int ret = 0;
694 
695 	display_init(state);
696 
697 	if (!state->is_init)
698 		return -EINVAL;
699 
700 	if (state->is_enable)
701 		return 0;
702 
703 	if (crtc_funcs->prepare) {
704 		ret = crtc_funcs->prepare(state);
705 		if (ret)
706 			return ret;
707 	}
708 
709 	if (conn_funcs->prepare) {
710 		ret = conn_funcs->prepare(state);
711 		if (ret)
712 			goto unprepare_crtc;
713 	}
714 
715 	display_panel_prepare(state);
716 
717 	if (crtc_funcs->enable) {
718 		ret = crtc_funcs->enable(state);
719 		if (ret)
720 			goto unprepare_conn;
721 	}
722 
723 	if (conn_funcs->enable) {
724 		ret = conn_funcs->enable(state);
725 		if (ret)
726 			goto disable_crtc;
727 	}
728 
729 	display_panel_enable(state);
730 
731 	state->is_enable = true;
732 	return 0;
733 
734 disable_crtc:
735 	if (crtc_funcs->disable)
736 		crtc_funcs->disable(state);
737 unprepare_conn:
738 	if (conn_funcs->unprepare)
739 		conn_funcs->unprepare(state);
740 unprepare_crtc:
741 	if (crtc_funcs->unprepare)
742 		crtc_funcs->unprepare(state);
743 	return ret;
744 }
745 
746 static int display_disable(struct display_state *state)
747 {
748 	struct connector_state *conn_state = &state->conn_state;
749 	const struct rockchip_connector *conn = conn_state->connector;
750 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
751 	struct crtc_state *crtc_state = &state->crtc_state;
752 	const struct rockchip_crtc *crtc = crtc_state->crtc;
753 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
754 
755 	if (!state->is_init)
756 		return 0;
757 
758 	if (!state->is_enable)
759 		return 0;
760 
761 	display_panel_disable(state);
762 
763 	if (crtc_funcs->disable)
764 		crtc_funcs->disable(state);
765 
766 	if (conn_funcs->disable)
767 		conn_funcs->disable(state);
768 
769 	display_panel_unprepare(state);
770 
771 	if (conn_funcs->unprepare)
772 		conn_funcs->unprepare(state);
773 
774 	state->is_enable = 0;
775 	state->is_init = 0;
776 
777 	return 0;
778 }
779 
780 static int display_logo(struct display_state *state)
781 {
782 	struct crtc_state *crtc_state = &state->crtc_state;
783 	struct connector_state *conn_state = &state->conn_state;
784 	struct logo_info *logo = &state->logo;
785 	int hdisplay, vdisplay;
786 
787 	display_init(state);
788 	if (!state->is_init)
789 		return -ENODEV;
790 
791 	switch (logo->bpp) {
792 	case 16:
793 		crtc_state->format = ROCKCHIP_FMT_RGB565;
794 		break;
795 	case 24:
796 		crtc_state->format = ROCKCHIP_FMT_RGB888;
797 		break;
798 	case 32:
799 		crtc_state->format = ROCKCHIP_FMT_ARGB8888;
800 		break;
801 	default:
802 		printf("can't support bmp bits[%d]\n", logo->bpp);
803 		return -EINVAL;
804 	}
805 	crtc_state->rb_swap = logo->bpp != 32;
806 	hdisplay = conn_state->mode.hdisplay;
807 	vdisplay = conn_state->mode.vdisplay;
808 	crtc_state->src_w = logo->width;
809 	crtc_state->src_h = logo->height;
810 	crtc_state->src_x = 0;
811 	crtc_state->src_y = 0;
812 	crtc_state->ymirror = logo->ymirror;
813 
814 	crtc_state->dma_addr = (u32)(unsigned long)logo->mem + logo->offset;
815 	crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5;
816 
817 	if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) {
818 		crtc_state->crtc_x = 0;
819 		crtc_state->crtc_y = 0;
820 		crtc_state->crtc_w = hdisplay;
821 		crtc_state->crtc_h = vdisplay;
822 	} else {
823 		if (crtc_state->src_w >= hdisplay) {
824 			crtc_state->crtc_x = 0;
825 			crtc_state->crtc_w = hdisplay;
826 		} else {
827 			crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2;
828 			crtc_state->crtc_w = crtc_state->src_w;
829 		}
830 
831 		if (crtc_state->src_h >= vdisplay) {
832 			crtc_state->crtc_y = 0;
833 			crtc_state->crtc_h = vdisplay;
834 		} else {
835 			crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2;
836 			crtc_state->crtc_h = crtc_state->src_h;
837 		}
838 	}
839 
840 	display_set_plane(state);
841 	display_enable(state);
842 
843 	return 0;
844 }
845 
846 static int get_crtc_id(ofnode connect)
847 {
848 	int phandle;
849 	struct device_node *remote;
850 	int val;
851 
852 	phandle = ofnode_read_u32_default(connect, "remote-endpoint", -1);
853 	if (phandle < 0)
854 		goto err;
855 	remote = of_find_node_by_phandle(phandle);
856 	val = ofnode_read_u32_default(np_to_ofnode(remote), "reg", -1);
857 	if (val < 0)
858 		goto err;
859 
860 	return val;
861 err:
862 	printf("Can't get crtc id, default set to id = 0\n");
863 	return 0;
864 }
865 
866 static int get_crtc_mcu_mode(struct crtc_state *crtc_state)
867 {
868 	ofnode mcu_node;
869 	int total_pixel, cs_pst, cs_pend, rw_pst, rw_pend;
870 
871 	mcu_node = dev_read_subnode(crtc_state->dev, "mcu-timing");
872 
873 #define FDT_GET_MCU_INT(val, name) \
874 	do { \
875 		val = ofnode_read_s32_default(mcu_node, name, -1); \
876 		if (val < 0) { \
877 			printf("Can't get %s\n", name); \
878 			return -ENXIO; \
879 		} \
880 	} while (0)
881 
882 	FDT_GET_MCU_INT(total_pixel, "mcu-pix-total");
883 	FDT_GET_MCU_INT(cs_pst, "mcu-cs-pst");
884 	FDT_GET_MCU_INT(cs_pend, "mcu-cs-pend");
885 	FDT_GET_MCU_INT(rw_pst, "mcu-rw-pst");
886 	FDT_GET_MCU_INT(rw_pend, "mcu-rw-pend");
887 
888 	crtc_state->mcu_timing.mcu_pix_total = total_pixel;
889 	crtc_state->mcu_timing.mcu_cs_pst = cs_pst;
890 	crtc_state->mcu_timing.mcu_cs_pend = cs_pend;
891 	crtc_state->mcu_timing.mcu_rw_pst = rw_pst;
892 	crtc_state->mcu_timing.mcu_rw_pend = rw_pend;
893 
894 	return 0;
895 }
896 
897 struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp)
898 {
899 	struct rockchip_logo_cache *tmp, *logo_cache = NULL;
900 
901 	list_for_each_entry(tmp, &logo_cache_list, head) {
902 		if (!strcmp(tmp->name, bmp)) {
903 			logo_cache = tmp;
904 			break;
905 		}
906 	}
907 
908 	if (!logo_cache) {
909 		logo_cache = malloc(sizeof(*logo_cache));
910 		if (!logo_cache) {
911 			printf("failed to alloc memory for logo cache\n");
912 			return NULL;
913 		}
914 		memset(logo_cache, 0, sizeof(*logo_cache));
915 		strcpy(logo_cache->name, bmp);
916 		INIT_LIST_HEAD(&logo_cache->head);
917 		list_add_tail(&logo_cache->head, &logo_cache_list);
918 	}
919 
920 	return logo_cache;
921 }
922 
923 /* Note: used only for rkfb kernel driver */
924 static int load_kernel_bmp_logo(struct logo_info *logo, const char *bmp_name)
925 {
926 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
927 	void *dst = NULL;
928 	int len, size;
929 	struct bmp_header *header;
930 
931 	if (!logo || !bmp_name)
932 		return -EINVAL;
933 
934 	header = malloc(RK_BLK_SIZE);
935 	if (!header)
936 		return -ENOMEM;
937 
938 	len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
939 	if (len != RK_BLK_SIZE) {
940 		free(header);
941 		return -EINVAL;
942 	}
943 	size = get_unaligned_le32(&header->file_size);
944 	dst = (void *)(memory_start + MEMORY_POOL_SIZE / 2);
945 	len = rockchip_read_resource_file(dst, bmp_name, 0, size);
946 	if (len != size) {
947 		printf("failed to load bmp %s\n", bmp_name);
948 		free(header);
949 		return -ENOENT;
950 	}
951 
952 	logo->mem = dst;
953 
954 	return 0;
955 #endif
956 }
957 
958 static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
959 {
960 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
961 	struct rockchip_logo_cache *logo_cache;
962 	struct bmp_header *header;
963 	void *dst = NULL, *pdst;
964 	int size, len;
965 	int ret = 0;
966 
967 	if (!logo || !bmp_name)
968 		return -EINVAL;
969 	logo_cache = find_or_alloc_logo_cache(bmp_name);
970 	if (!logo_cache)
971 		return -ENOMEM;
972 
973 	if (logo_cache->logo.mem) {
974 		memcpy(logo, &logo_cache->logo, sizeof(*logo));
975 		return 0;
976 	}
977 
978 	header = malloc(RK_BLK_SIZE);
979 	if (!header)
980 		return -ENOMEM;
981 
982 	len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
983 	if (len != RK_BLK_SIZE) {
984 		ret = -EINVAL;
985 		goto free_header;
986 	}
987 
988 	logo->bpp = get_unaligned_le16(&header->bit_count);
989 	logo->width = get_unaligned_le32(&header->width);
990 	logo->height = get_unaligned_le32(&header->height);
991 	size = get_unaligned_le32(&header->file_size);
992 	if (!can_direct_logo(logo->bpp)) {
993 		if (size > MEMORY_POOL_SIZE) {
994 			printf("failed to use boot buf as temp bmp buffer\n");
995 			ret = -ENOMEM;
996 			goto free_header;
997 		}
998 		pdst = get_display_buffer(size);
999 
1000 	} else {
1001 		pdst = get_display_buffer(size);
1002 		dst = pdst;
1003 	}
1004 
1005 	len = rockchip_read_resource_file(pdst, bmp_name, 0, size);
1006 	if (len != size) {
1007 		printf("failed to load bmp %s\n", bmp_name);
1008 		ret = -ENOENT;
1009 		goto free_header;
1010 	}
1011 
1012 	if (!can_direct_logo(logo->bpp)) {
1013 		int dst_size;
1014 		/*
1015 		 * TODO: force use 16bpp if bpp less than 16;
1016 		 */
1017 		logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp;
1018 		dst_size = logo->width * logo->height * logo->bpp >> 3;
1019 
1020 		dst = get_display_buffer(dst_size);
1021 		if (!dst) {
1022 			ret = -ENOMEM;
1023 			goto free_header;
1024 		}
1025 		if (bmpdecoder(pdst, dst, logo->bpp)) {
1026 			printf("failed to decode bmp %s\n", bmp_name);
1027 			ret = -EINVAL;
1028 			goto free_header;
1029 		}
1030 		flush_dcache_range((ulong)dst,
1031 				   ALIGN((ulong)dst + dst_size,
1032 					 CONFIG_SYS_CACHELINE_SIZE));
1033 
1034 		logo->offset = 0;
1035 		logo->ymirror = 0;
1036 	} else {
1037 		logo->offset = get_unaligned_le32(&header->data_offset);
1038 		logo->ymirror = 1;
1039 	}
1040 	logo->mem = dst;
1041 
1042 	memcpy(&logo_cache->logo, logo, sizeof(*logo));
1043 
1044 free_header:
1045 
1046 	free(header);
1047 
1048 	return ret;
1049 #else
1050 	return -EINVAL;
1051 #endif
1052 }
1053 
1054 void rockchip_show_fbbase(ulong fbbase)
1055 {
1056 	struct display_state *s;
1057 
1058 	list_for_each_entry(s, &rockchip_display_list, head) {
1059 		s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN;
1060 		s->logo.mem = (char *)fbbase;
1061 		s->logo.width = DRM_ROCKCHIP_FB_WIDTH;
1062 		s->logo.height = DRM_ROCKCHIP_FB_HEIGHT;
1063 		s->logo.bpp = 32;
1064 		s->logo.ymirror = 0;
1065 
1066 		display_logo(s);
1067 	}
1068 }
1069 
1070 void rockchip_show_bmp(const char *bmp)
1071 {
1072 	struct display_state *s;
1073 
1074 	if (!bmp) {
1075 		list_for_each_entry(s, &rockchip_display_list, head)
1076 			display_disable(s);
1077 		return;
1078 	}
1079 
1080 	list_for_each_entry(s, &rockchip_display_list, head) {
1081 		s->logo.mode = s->charge_logo_mode;
1082 		if (load_bmp_logo(&s->logo, bmp))
1083 			continue;
1084 		display_logo(s);
1085 	}
1086 }
1087 
1088 void rockchip_show_logo(void)
1089 {
1090 	struct display_state *s;
1091 
1092 	list_for_each_entry(s, &rockchip_display_list, head) {
1093 		s->logo.mode = s->logo_mode;
1094 		if (load_bmp_logo(&s->logo, s->ulogo_name))
1095 			printf("failed to display uboot logo\n");
1096 		else
1097 			display_logo(s);
1098 
1099 		/* Load kernel bmp in rockchip_display_fixup() later */
1100 	}
1101 }
1102 
1103 static int rockchip_display_probe(struct udevice *dev)
1104 {
1105 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1106 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
1107 	const void *blob = gd->fdt_blob;
1108 	int phandle;
1109 	struct udevice *crtc_dev, *conn_dev;
1110 	const struct rockchip_crtc *crtc;
1111 	const struct rockchip_connector *conn;
1112 	struct display_state *s;
1113 	const char *name;
1114 	int ret;
1115 	ofnode node, route_node;
1116 	struct device_node *port_node, *vop_node, *ep_node;
1117 	struct device_node *cnt_node, *p;
1118 
1119 	/* Before relocation we don't need to do anything */
1120 	if (!(gd->flags & GD_FLG_RELOC))
1121 		return 0;
1122 	init_display_buffer(plat->base);
1123 
1124 	route_node = dev_read_subnode(dev, "route");
1125 	if (!ofnode_valid(route_node))
1126 		return -ENODEV;
1127 
1128 	ofnode_for_each_subnode(node, route_node) {
1129 		if (!ofnode_is_available(node))
1130 			continue;
1131 		phandle = ofnode_read_u32_default(node, "connect", -1);
1132 		if (phandle < 0) {
1133 			printf("Warn: can't find connect node's handle\n");
1134 			continue;
1135 		}
1136 		ep_node = of_find_node_by_phandle(phandle);
1137 		if (!ofnode_valid(np_to_ofnode(ep_node))) {
1138 			printf("Warn: can't find endpoint node from phandle\n");
1139 			continue;
1140 		}
1141 		port_node = of_get_parent(ep_node);
1142 		if (!ofnode_valid(np_to_ofnode(port_node))) {
1143 			printf("Warn: can't find port node from phandle\n");
1144 			continue;
1145 		}
1146 		vop_node = of_get_parent(port_node);
1147 		if (!ofnode_valid(np_to_ofnode(vop_node))) {
1148 			printf("Warn: can't find crtc node from phandle\n");
1149 			continue;
1150 		}
1151 		ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC,
1152 						  np_to_ofnode(vop_node),
1153 						  &crtc_dev);
1154 		if (ret) {
1155 			printf("Warn: can't find crtc driver %d\n", ret);
1156 			continue;
1157 		}
1158 		crtc = (const struct rockchip_crtc *)dev_get_driver_data(crtc_dev);
1159 
1160 		phandle = ofnode_read_u32_default(np_to_ofnode(ep_node),
1161 						  "remote-endpoint", -1);
1162 		cnt_node = of_find_node_by_phandle(phandle);
1163 		if (phandle < 0) {
1164 			printf("Warn: can't find remote-endpoint's handle\n");
1165 			continue;
1166 		}
1167 		while (cnt_node->parent){
1168 			p = of_get_parent(cnt_node);
1169 			if (!strcmp(p->full_name, "/"))
1170 				break;
1171 			cnt_node = p;
1172 		}
1173 		if (!of_device_is_available(cnt_node))
1174 			continue;
1175 		ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY,
1176 						  np_to_ofnode(cnt_node),
1177 						  &conn_dev);
1178 		if (ret) {
1179 			printf("Warn: can't find connect driver\n");
1180 			continue;
1181 		}
1182 		conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev);
1183 
1184 		s = malloc(sizeof(*s));
1185 		if (!s)
1186 			continue;
1187 
1188 		memset(s, 0, sizeof(*s));
1189 
1190 		INIT_LIST_HEAD(&s->head);
1191 		ret = ofnode_read_string_index(node, "logo,uboot", 0, &s->ulogo_name);
1192 		ret = ofnode_read_string_index(node, "logo,kernel", 0, &s->klogo_name);
1193 		ret = ofnode_read_string_index(node, "logo,mode", 0, &name);
1194 		if (!strcmp(name, "fullscreen"))
1195 			s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
1196 		else
1197 			s->logo_mode = ROCKCHIP_DISPLAY_CENTER;
1198 		ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name);
1199 		if (!strcmp(name, "fullscreen"))
1200 			s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
1201 		else
1202 			s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER;
1203 
1204 		s->blob = blob;
1205 		s->conn_state.node = np_to_ofnode(cnt_node);
1206 		s->conn_state.dev = conn_dev;
1207 		s->conn_state.connector = conn;
1208 		s->conn_state.overscan.left_margin = 100;
1209 		s->conn_state.overscan.right_margin = 100;
1210 		s->conn_state.overscan.top_margin = 100;
1211 		s->conn_state.overscan.bottom_margin = 100;
1212 		s->crtc_state.node = np_to_ofnode(vop_node);
1213 		s->crtc_state.dev = crtc_dev;
1214 		s->crtc_state.crtc = crtc;
1215 		s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node));
1216 		s->node = node;
1217 		get_crtc_mcu_mode(&s->crtc_state);
1218 
1219 		if (connector_panel_init(s)) {
1220 			printf("Warn: Failed to init panel drivers\n");
1221 			free(s);
1222 			continue;
1223 		}
1224 
1225 		if (connector_phy_init(s)) {
1226 			printf("Warn: Failed to init phy drivers\n");
1227 			free(s);
1228 			continue;
1229 		}
1230 		list_add_tail(&s->head, &rockchip_display_list);
1231 	}
1232 
1233 	if (list_empty(&rockchip_display_list)) {
1234 		printf("Failed to found available display route\n");
1235 		return -ENODEV;
1236 	}
1237 
1238 	uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH;
1239 	uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT;
1240 	uc_priv->bpix = VIDEO_BPP32;
1241 
1242 	#ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER
1243 	rockchip_show_fbbase(plat->base);
1244 	video_set_flush_dcache(dev, true);
1245 	#endif
1246 
1247 	return 0;
1248 }
1249 
1250 void rockchip_display_fixup(void *blob)
1251 {
1252 	const struct rockchip_connector_funcs *conn_funcs;
1253 	const struct rockchip_crtc_funcs *crtc_funcs;
1254 	const struct rockchip_connector *conn;
1255 	const struct rockchip_crtc *crtc;
1256 	struct display_state *s;
1257 	int offset;
1258 	const struct device_node *np;
1259 	const char *path;
1260 
1261 	if (!get_display_size())
1262 		return;
1263 
1264 	if (fdt_node_offset_by_compatible(blob, 0, "rockchip,drm-logo") >= 0) {
1265 		list_for_each_entry(s, &rockchip_display_list, head)
1266 			load_bmp_logo(&s->logo, s->klogo_name);
1267 		offset = fdt_update_reserved_memory(blob, "rockchip,drm-logo",
1268 						    (u64)memory_start,
1269 						    (u64)get_display_size());
1270 		if (offset < 0)
1271 			printf("failed to reserve drm-loader-logo memory\n");
1272 	} else {
1273 		printf("can't found rockchip,drm-logo, use rockchip,fb-logo\n");
1274 		/* Compatible with rkfb display, only need reserve memory */
1275 		offset = fdt_update_reserved_memory(blob, "rockchip,fb-logo",
1276 						    (u64)memory_start,
1277 						    MEMORY_POOL_SIZE);
1278 		if (offset < 0)
1279 			printf("failed to reserve fb-loader-logo memory\n");
1280 		else
1281 			list_for_each_entry(s, &rockchip_display_list, head)
1282 				load_kernel_bmp_logo(&s->logo, s->klogo_name);
1283 		return;
1284 	}
1285 
1286 	list_for_each_entry(s, &rockchip_display_list, head) {
1287 		conn = s->conn_state.connector;
1288 		if (!conn)
1289 			continue;
1290 		conn_funcs = conn->funcs;
1291 		if (!conn_funcs) {
1292 			printf("failed to get exist connector\n");
1293 			continue;
1294 		}
1295 
1296 		crtc = s->crtc_state.crtc;
1297 		if (!crtc)
1298 			continue;
1299 
1300 		crtc_funcs = crtc->funcs;
1301 		if (!crtc_funcs) {
1302 			printf("failed to get exist crtc\n");
1303 			continue;
1304 		}
1305 
1306 		if (crtc_funcs->fixup_dts)
1307 			crtc_funcs->fixup_dts(s, blob);
1308 
1309 		if (conn_funcs->fixup_dts)
1310 			conn_funcs->fixup_dts(s, blob);
1311 
1312 		np = ofnode_to_np(s->node);
1313 		path = np->full_name;
1314 		fdt_increase_size(blob, 0x400);
1315 #define FDT_SET_U32(name, val) \
1316 		do_fixup_by_path_u32(blob, path, name, val, 1);
1317 
1318 		offset = s->logo.offset + (u32)(unsigned long)s->logo.mem
1319 			 - memory_start;
1320 		FDT_SET_U32("logo,offset", offset);
1321 		FDT_SET_U32("logo,width", s->logo.width);
1322 		FDT_SET_U32("logo,height", s->logo.height);
1323 		FDT_SET_U32("logo,bpp", s->logo.bpp);
1324 		FDT_SET_U32("logo,ymirror", s->logo.ymirror);
1325 		FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay);
1326 		FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay);
1327 		FDT_SET_U32("video,crtc_hsync_end", s->conn_state.mode.crtc_hsync_end);
1328 		FDT_SET_U32("video,crtc_vsync_end", s->conn_state.mode.crtc_vsync_end);
1329 		FDT_SET_U32("video,vrefresh",
1330 			    drm_mode_vrefresh(&s->conn_state.mode));
1331 		FDT_SET_U32("video,flags", s->conn_state.mode.flags);
1332 		FDT_SET_U32("overscan,left_margin", s->conn_state.overscan.left_margin);
1333 		FDT_SET_U32("overscan,right_margin", s->conn_state.overscan.right_margin);
1334 		FDT_SET_U32("overscan,top_margin", s->conn_state.overscan.top_margin);
1335 		FDT_SET_U32("overscan,bottom_margin", s->conn_state.overscan.bottom_margin);
1336 #undef FDT_SET_U32
1337 	}
1338 }
1339 
1340 int rockchip_display_bind(struct udevice *dev)
1341 {
1342 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
1343 
1344 	plat->size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE;
1345 
1346 	return 0;
1347 }
1348 
1349 static const struct udevice_id rockchip_display_ids[] = {
1350 	{ .compatible = "rockchip,display-subsystem" },
1351 	{ }
1352 };
1353 
1354 U_BOOT_DRIVER(rockchip_display) = {
1355 	.name	= "rockchip_display",
1356 	.id	= UCLASS_VIDEO,
1357 	.of_match = rockchip_display_ids,
1358 	.bind	= rockchip_display_bind,
1359 	.probe	= rockchip_display_probe,
1360 };
1361 
1362 static int do_rockchip_logo_show(cmd_tbl_t *cmdtp, int flag, int argc,
1363 			char *const argv[])
1364 {
1365 	if (argc != 1)
1366 		return CMD_RET_USAGE;
1367 
1368 	rockchip_show_logo();
1369 
1370 	return 0;
1371 }
1372 
1373 static int do_rockchip_show_bmp(cmd_tbl_t *cmdtp, int flag, int argc,
1374 				char *const argv[])
1375 {
1376 	if (argc != 2)
1377 		return CMD_RET_USAGE;
1378 
1379 	rockchip_show_bmp(argv[1]);
1380 
1381 	return 0;
1382 }
1383 
1384 U_BOOT_CMD(
1385 	rockchip_show_logo, 1, 1, do_rockchip_logo_show,
1386 	"load and display log from resource partition",
1387 	NULL
1388 );
1389 
1390 U_BOOT_CMD(
1391 	rockchip_show_bmp, 2, 1, do_rockchip_show_bmp,
1392 	"load and display bmp from resource partition",
1393 	"    <bmp_name>"
1394 );
1395