xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_display.c (revision 75eb6fceb584d246c2b7cfac79b4fe43d0ec0ecd)
1186f8572SMark Yao /*
2186f8572SMark Yao  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3186f8572SMark Yao  *
4186f8572SMark Yao  * SPDX-License-Identifier:	GPL-2.0+
5186f8572SMark Yao  */
6186f8572SMark Yao 
7186f8572SMark Yao #include <asm/unaligned.h>
8186f8572SMark Yao #include <config.h>
9186f8572SMark Yao #include <common.h>
10186f8572SMark Yao #include <errno.h>
110e00a84cSMasahiro Yamada #include <linux/libfdt.h>
12186f8572SMark Yao #include <fdtdec.h>
13186f8572SMark Yao #include <fdt_support.h>
148e2bab3fSAlgea Cao #include <linux/hdmi.h>
15186f8572SMark Yao #include <linux/list.h>
16186f8572SMark Yao #include <linux/compat.h>
17186f8572SMark Yao #include <linux/media-bus-format.h>
18186f8572SMark Yao #include <malloc.h>
19186f8572SMark Yao #include <video.h>
20f8a3e587SJoseph Chen #include <video_rockchip.h>
211a8d717cSWyon Bi #include <video_bridge.h>
22186f8572SMark Yao #include <dm/device.h>
23186f8572SMark Yao #include <dm/uclass-internal.h>
244b8c2ef1SMark Yao #include <asm/arch-rockchip/resource_img.h>
25186f8572SMark Yao 
26186f8572SMark Yao #include "bmp_helper.h"
27186f8572SMark Yao #include "rockchip_display.h"
28186f8572SMark Yao #include "rockchip_crtc.h"
29186f8572SMark Yao #include "rockchip_connector.h"
301a8d717cSWyon Bi #include "rockchip_bridge.h"
31186f8572SMark Yao #include "rockchip_phy.h"
32186f8572SMark Yao #include "rockchip_panel.h"
33e2bce6e4SKever Yang #include <dm.h>
34e2bce6e4SKever Yang #include <dm/of_access.h>
35e2bce6e4SKever Yang #include <dm/ofnode.h>
36186f8572SMark Yao 
371e4c51caSSandy Huang #define DRIVER_VERSION	"v1.0.1"
38e559407dSSandy Huang 
39e559407dSSandy Huang /***********************************************************************
40e559407dSSandy Huang  *  Rockchip UBOOT DRM driver version
41e559407dSSandy Huang  *
42e559407dSSandy Huang  *  v1.0.0	: add basic version for rockchip drm driver(hjc)
431e4c51caSSandy Huang  *  v1.0.1	: add much dsi update(hjc)
44e559407dSSandy Huang  *
45e559407dSSandy Huang  **********************************************************************/
46e559407dSSandy Huang 
474b8c2ef1SMark Yao #define RK_BLK_SIZE 512
487e72214dSShixiang Zheng #define BMP_PROCESSED_FLAG 8399
494b8c2ef1SMark Yao 
50186f8572SMark Yao DECLARE_GLOBAL_DATA_PTR;
51186f8572SMark Yao static LIST_HEAD(rockchip_display_list);
52186f8572SMark Yao static LIST_HEAD(logo_cache_list);
53186f8572SMark Yao 
54186f8572SMark Yao static unsigned long memory_start;
55186f8572SMark Yao static unsigned long memory_end;
56186f8572SMark Yao 
572a48727aSAlgea Cao /*
582a48727aSAlgea Cao  * the phy types are used by different connectors in public.
592a48727aSAlgea Cao  * The current version only has inno hdmi phy for hdmi and tve.
602a48727aSAlgea Cao  */
612a48727aSAlgea Cao enum public_use_phy {
622a48727aSAlgea Cao 	NONE,
632a48727aSAlgea Cao 	INNO_HDMI_PHY
642a48727aSAlgea Cao };
652a48727aSAlgea Cao 
662a48727aSAlgea Cao /* save public phy data */
672a48727aSAlgea Cao struct public_phy_data {
682a48727aSAlgea Cao 	const struct rockchip_phy *phy_drv;
692a48727aSAlgea Cao 	int phy_node;
702a48727aSAlgea Cao 	int public_phy_type;
712a48727aSAlgea Cao 	bool phy_init;
722a48727aSAlgea Cao };
732a48727aSAlgea Cao 
742a48727aSAlgea Cao /* check which kind of public phy does connector use */
752a48727aSAlgea Cao static int check_public_use_phy(struct display_state *state)
762a48727aSAlgea Cao {
772a48727aSAlgea Cao 	int ret = NONE;
782a48727aSAlgea Cao #ifdef CONFIG_ROCKCHIP_INNO_HDMI_PHY
792a48727aSAlgea Cao 	struct connector_state *conn_state = &state->conn_state;
802a48727aSAlgea Cao 
812a48727aSAlgea Cao 	if (!strncmp(dev_read_name(conn_state->dev), "tve", 3) ||
822a48727aSAlgea Cao 	    !strncmp(dev_read_name(conn_state->dev), "hdmi", 4))
832a48727aSAlgea Cao 		ret = INNO_HDMI_PHY;
842a48727aSAlgea Cao #endif
852a48727aSAlgea Cao 
862a48727aSAlgea Cao 	return ret;
872a48727aSAlgea Cao }
882a48727aSAlgea Cao 
892a48727aSAlgea Cao /*
902a48727aSAlgea Cao  * get public phy driver and initialize it.
912a48727aSAlgea Cao  * The current version only has inno hdmi phy for hdmi and tve.
922a48727aSAlgea Cao  */
932a48727aSAlgea Cao static int get_public_phy(struct display_state *state,
942a48727aSAlgea Cao 			  struct public_phy_data *data)
952a48727aSAlgea Cao {
962a48727aSAlgea Cao 	struct connector_state *conn_state = &state->conn_state;
9715081c50SWyon Bi 	struct rockchip_phy *phy;
982a48727aSAlgea Cao 	struct udevice *dev;
992a48727aSAlgea Cao 	int ret = 0;
1002a48727aSAlgea Cao 
1012a48727aSAlgea Cao 	switch (data->public_phy_type) {
1022a48727aSAlgea Cao 	case INNO_HDMI_PHY:
1032a48727aSAlgea Cao #if defined(CONFIG_ROCKCHIP_RK3328)
10415081c50SWyon Bi 		ret = uclass_get_device_by_name(UCLASS_PHY,
1052a48727aSAlgea Cao 						"hdmiphy@ff430000", &dev);
1062a48727aSAlgea Cao #elif defined(CONFIG_ROCKCHIP_RK322X)
10715081c50SWyon Bi 		ret = uclass_get_device_by_name(UCLASS_PHY,
1082a48727aSAlgea Cao 						"hdmi-phy@12030000", &dev);
1092a48727aSAlgea Cao #else
1102a48727aSAlgea Cao 		ret = -EINVAL;
1112a48727aSAlgea Cao #endif
1122a48727aSAlgea Cao 		if (ret) {
1132a48727aSAlgea Cao 			printf("Warn: can't find phy driver\n");
1142a48727aSAlgea Cao 			return 0;
1152a48727aSAlgea Cao 		}
1162a48727aSAlgea Cao 
11715081c50SWyon Bi 		phy = (struct rockchip_phy *)dev_get_driver_data(dev);
1182a48727aSAlgea Cao 		if (!phy) {
1192a48727aSAlgea Cao 			printf("failed to get phy driver\n");
1202a48727aSAlgea Cao 			return 0;
1212a48727aSAlgea Cao 		}
1222a48727aSAlgea Cao 
12315081c50SWyon Bi 		ret = rockchip_phy_init(phy);
12415081c50SWyon Bi 		if (ret) {
1252a48727aSAlgea Cao 			printf("failed to init phy driver\n");
12615081c50SWyon Bi 			return ret;
1272a48727aSAlgea Cao 		}
1282a48727aSAlgea Cao 		conn_state->phy = phy;
1292a48727aSAlgea Cao 
1304ba1647cSKever Yang 		debug("inno hdmi phy init success, save it\n");
1312a48727aSAlgea Cao 		data->phy_drv = conn_state->phy;
1322a48727aSAlgea Cao 		data->phy_init = true;
1332a48727aSAlgea Cao 		return 0;
1342a48727aSAlgea Cao 	default:
1352a48727aSAlgea Cao 		return -EINVAL;
1362a48727aSAlgea Cao 	}
1372a48727aSAlgea Cao }
1382a48727aSAlgea Cao 
1394b8c2ef1SMark Yao static void init_display_buffer(ulong base)
140186f8572SMark Yao {
1414b8c2ef1SMark Yao 	memory_start = base + DRM_ROCKCHIP_FB_SIZE;
142186f8572SMark Yao 	memory_end = memory_start;
143186f8572SMark Yao }
144186f8572SMark Yao 
145186f8572SMark Yao static void *get_display_buffer(int size)
146186f8572SMark Yao {
147186f8572SMark Yao 	unsigned long roundup_memory = roundup(memory_end, PAGE_SIZE);
148186f8572SMark Yao 	void *buf;
149186f8572SMark Yao 
150186f8572SMark Yao 	if (roundup_memory + size > memory_start + MEMORY_POOL_SIZE) {
151186f8572SMark Yao 		printf("failed to alloc %dbyte memory to display\n", size);
152186f8572SMark Yao 		return NULL;
153186f8572SMark Yao 	}
154186f8572SMark Yao 	buf = (void *)roundup_memory;
155186f8572SMark Yao 
156186f8572SMark Yao 	memory_end = roundup_memory + size;
157186f8572SMark Yao 
158186f8572SMark Yao 	return buf;
159186f8572SMark Yao }
160186f8572SMark Yao 
161186f8572SMark Yao static unsigned long get_display_size(void)
162186f8572SMark Yao {
163186f8572SMark Yao 	return memory_end - memory_start;
164186f8572SMark Yao }
165186f8572SMark Yao 
166861ce1a0SSandy Huang static bool can_direct_logo(int bpp)
167186f8572SMark Yao {
168861ce1a0SSandy Huang 	return bpp == 24 || bpp == 32;
169186f8572SMark Yao }
170186f8572SMark Yao 
1712a48727aSAlgea Cao static int connector_phy_init(struct display_state *state,
1722a48727aSAlgea Cao 			      struct public_phy_data *data)
173186f8572SMark Yao {
174186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
1757cacd0a8SWyon Bi 	int type;
176186f8572SMark Yao 
1772a48727aSAlgea Cao 	/* does this connector use public phy with others */
1782a48727aSAlgea Cao 	type = check_public_use_phy(state);
1792a48727aSAlgea Cao 	if (type == INNO_HDMI_PHY) {
1802a48727aSAlgea Cao 		/* there is no public phy was initialized */
1812a48727aSAlgea Cao 		if (!data->phy_init) {
1824ba1647cSKever Yang 			debug("start get public phy\n");
1832a48727aSAlgea Cao 			data->public_phy_type = type;
1842a48727aSAlgea Cao 			if (get_public_phy(state, data)) {
1852a48727aSAlgea Cao 				printf("can't find correct public phy type\n");
1862a48727aSAlgea Cao 				free(data);
1872a48727aSAlgea Cao 				return -EINVAL;
1882a48727aSAlgea Cao 			}
1892a48727aSAlgea Cao 			return 0;
1902a48727aSAlgea Cao 		}
1912a48727aSAlgea Cao 
1922a48727aSAlgea Cao 		/* if this phy has been initialized, get it directly */
19315081c50SWyon Bi 		conn_state->phy = (struct rockchip_phy *)data->phy_drv;
1942a48727aSAlgea Cao 		return 0;
1952a48727aSAlgea Cao 	}
1962a48727aSAlgea Cao 
197186f8572SMark Yao 	return 0;
198186f8572SMark Yao }
199186f8572SMark Yao 
200186f8572SMark Yao static int connector_panel_init(struct display_state *state)
201186f8572SMark Yao {
202186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
203186f8572SMark Yao 	struct panel_state *panel_state = &state->panel_state;
2041a8d717cSWyon Bi 	const struct rockchip_panel *panel = panel_state->panel;
205e2bce6e4SKever Yang 	ofnode dsp_lut_node;
206186f8572SMark Yao 	int ret, len;
207186f8572SMark Yao 
2081a8d717cSWyon Bi 	if (!panel)
2094b8c2ef1SMark Yao 		return 0;
210186f8572SMark Yao 
2111a8d717cSWyon Bi 	dsp_lut_node = dev_read_subnode(panel->dev, "dsp-lut");
212e2bce6e4SKever Yang 	if (!ofnode_valid(dsp_lut_node)) {
213861ce1a0SSandy Huang 		debug("%s can not find dsp-lut node\n", __func__);
2141e44acfcSWyon Bi 		return 0;
215e2bce6e4SKever Yang 	}
2161e44acfcSWyon Bi 
217e2bce6e4SKever Yang 	ofnode_get_property(dsp_lut_node, "gamma-lut", &len);
218186f8572SMark Yao 	if (len > 0) {
219186f8572SMark Yao 		conn_state->gamma.size = len / sizeof(u32);
220186f8572SMark Yao 		conn_state->gamma.lut = malloc(len);
221186f8572SMark Yao 		if (!conn_state->gamma.lut) {
222186f8572SMark Yao 			printf("malloc gamma lut failed\n");
223186f8572SMark Yao 			return -ENOMEM;
224186f8572SMark Yao 		}
225e2bce6e4SKever Yang 		ret = ofnode_read_u32_array(dsp_lut_node, "gamma-lut",
226186f8572SMark Yao 					    conn_state->gamma.lut,
227e2bce6e4SKever Yang 					    conn_state->gamma.size);
228e2bce6e4SKever Yang 		if (ret) {
229186f8572SMark Yao 			printf("Cannot decode gamma_lut\n");
230186f8572SMark Yao 			conn_state->gamma.lut = NULL;
231186f8572SMark Yao 			return -EINVAL;
232186f8572SMark Yao 		}
233186f8572SMark Yao 		panel_state->dsp_lut_node = dsp_lut_node;
234186f8572SMark Yao 	}
235186f8572SMark Yao 
236186f8572SMark Yao 	return 0;
237186f8572SMark Yao }
238186f8572SMark Yao 
239186f8572SMark Yao int drm_mode_vrefresh(const struct drm_display_mode *mode)
240186f8572SMark Yao {
241186f8572SMark Yao 	int refresh = 0;
242186f8572SMark Yao 	unsigned int calc_val;
243186f8572SMark Yao 
244186f8572SMark Yao 	if (mode->vrefresh > 0) {
245186f8572SMark Yao 		refresh = mode->vrefresh;
246186f8572SMark Yao 	} else if (mode->htotal > 0 && mode->vtotal > 0) {
247186f8572SMark Yao 		int vtotal;
248186f8572SMark Yao 
249186f8572SMark Yao 		vtotal = mode->vtotal;
250186f8572SMark Yao 		/* work out vrefresh the value will be x1000 */
251186f8572SMark Yao 		calc_val = (mode->clock * 1000);
252186f8572SMark Yao 		calc_val /= mode->htotal;
253186f8572SMark Yao 		refresh = (calc_val + vtotal / 2) / vtotal;
254186f8572SMark Yao 
255186f8572SMark Yao 		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
256186f8572SMark Yao 			refresh *= 2;
257186f8572SMark Yao 		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
258186f8572SMark Yao 			refresh /= 2;
259186f8572SMark Yao 		if (mode->vscan > 1)
260186f8572SMark Yao 			refresh /= mode->vscan;
261186f8572SMark Yao 	}
262186f8572SMark Yao 	return refresh;
263186f8572SMark Yao }
264186f8572SMark Yao 
265e2bce6e4SKever Yang static int display_get_timing_from_dts(struct panel_state *panel_state,
266186f8572SMark Yao 				       struct drm_display_mode *mode)
267186f8572SMark Yao {
2681a8d717cSWyon Bi 	struct rockchip_panel *panel = panel_state->panel;
269e2bce6e4SKever Yang 	int phandle;
270186f8572SMark Yao 	int hactive, vactive, pixelclock;
271186f8572SMark Yao 	int hfront_porch, hback_porch, hsync_len;
272186f8572SMark Yao 	int vfront_porch, vback_porch, vsync_len;
273186f8572SMark Yao 	int val, flags = 0;
274e2bce6e4SKever Yang 	ofnode timing, native_mode;
275186f8572SMark Yao 
2761a8d717cSWyon Bi 	timing = dev_read_subnode(panel->dev, "display-timings");
277e2bce6e4SKever Yang 	if (!ofnode_valid(timing))
278186f8572SMark Yao 		return -ENODEV;
279186f8572SMark Yao 
280e2bce6e4SKever Yang 	native_mode = ofnode_find_subnode(timing, "timing");
281e2bce6e4SKever Yang 	if (!ofnode_valid(native_mode)) {
282e2bce6e4SKever Yang 		phandle = ofnode_read_u32_default(timing, "native-mode", -1);
283e2bce6e4SKever Yang 		native_mode = np_to_ofnode(of_find_node_by_phandle(phandle));
284e2bce6e4SKever Yang 		if (!ofnode_valid(native_mode)) {
285186f8572SMark Yao 			printf("failed to get display timings from DT\n");
286186f8572SMark Yao 			return -ENXIO;
287186f8572SMark Yao 		}
288186f8572SMark Yao 	}
289186f8572SMark Yao 
290186f8572SMark Yao #define FDT_GET_INT(val, name) \
291e2bce6e4SKever Yang 	val = ofnode_read_s32_default(native_mode, name, -1); \
292186f8572SMark Yao 	if (val < 0) { \
293186f8572SMark Yao 		printf("Can't get %s\n", name); \
294186f8572SMark Yao 		return -ENXIO; \
295186f8572SMark Yao 	}
296186f8572SMark Yao 
297ffa55e18SShixiang Zheng #define FDT_GET_INT_DEFAULT(val, name, default) \
298ffa55e18SShixiang Zheng 	val = ofnode_read_s32_default(native_mode, name, default);
299ffa55e18SShixiang Zheng 
300186f8572SMark Yao 	FDT_GET_INT(hactive, "hactive");
301186f8572SMark Yao 	FDT_GET_INT(vactive, "vactive");
302186f8572SMark Yao 	FDT_GET_INT(pixelclock, "clock-frequency");
303186f8572SMark Yao 	FDT_GET_INT(hsync_len, "hsync-len");
304186f8572SMark Yao 	FDT_GET_INT(hfront_porch, "hfront-porch");
305186f8572SMark Yao 	FDT_GET_INT(hback_porch, "hback-porch");
306186f8572SMark Yao 	FDT_GET_INT(vsync_len, "vsync-len");
307186f8572SMark Yao 	FDT_GET_INT(vfront_porch, "vfront-porch");
308186f8572SMark Yao 	FDT_GET_INT(vback_porch, "vback-porch");
309186f8572SMark Yao 	FDT_GET_INT(val, "hsync-active");
310186f8572SMark Yao 	flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
311186f8572SMark Yao 	FDT_GET_INT(val, "vsync-active");
312186f8572SMark Yao 	flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
3133a06149eSSandy Huang 	FDT_GET_INT(val, "pixelclk-active");
3143a06149eSSandy Huang 	flags |= val ? DRM_MODE_FLAG_PPIXDATA : 0;
315186f8572SMark Yao 
316ffa55e18SShixiang Zheng 	FDT_GET_INT_DEFAULT(val, "screen-rotate", 0);
317ffa55e18SShixiang Zheng 	if (val == DRM_MODE_FLAG_XMIRROR) {
318ffa55e18SShixiang Zheng 		flags |= DRM_MODE_FLAG_XMIRROR;
319ffa55e18SShixiang Zheng 	} else if (val == DRM_MODE_FLAG_YMIRROR) {
320ffa55e18SShixiang Zheng 		flags |= DRM_MODE_FLAG_YMIRROR;
321ffa55e18SShixiang Zheng 	} else if (val == DRM_MODE_FLAG_XYMIRROR) {
322ffa55e18SShixiang Zheng 		flags |= DRM_MODE_FLAG_XMIRROR;
323ffa55e18SShixiang Zheng 		flags |= DRM_MODE_FLAG_YMIRROR;
324ffa55e18SShixiang Zheng 	}
325186f8572SMark Yao 	mode->hdisplay = hactive;
326186f8572SMark Yao 	mode->hsync_start = mode->hdisplay + hfront_porch;
327186f8572SMark Yao 	mode->hsync_end = mode->hsync_start + hsync_len;
328186f8572SMark Yao 	mode->htotal = mode->hsync_end + hback_porch;
329186f8572SMark Yao 
330186f8572SMark Yao 	mode->vdisplay = vactive;
331186f8572SMark Yao 	mode->vsync_start = mode->vdisplay + vfront_porch;
332186f8572SMark Yao 	mode->vsync_end = mode->vsync_start + vsync_len;
333186f8572SMark Yao 	mode->vtotal = mode->vsync_end + vback_porch;
334186f8572SMark Yao 
335186f8572SMark Yao 	mode->clock = pixelclock / 1000;
336186f8572SMark Yao 	mode->flags = flags;
337186f8572SMark Yao 
338186f8572SMark Yao 	return 0;
339186f8572SMark Yao }
340186f8572SMark Yao 
341ccd843b9SSandy Huang /**
342ccd843b9SSandy Huang  * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
343ccd843b9SSandy Huang  * @p: mode
344ccd843b9SSandy Huang  * @adjust_flags: a combination of adjustment flags
345ccd843b9SSandy Huang  *
346ccd843b9SSandy Huang  * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
347ccd843b9SSandy Huang  *
348ccd843b9SSandy Huang  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
349ccd843b9SSandy Huang  *   interlaced modes.
350ccd843b9SSandy Huang  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
351ccd843b9SSandy Huang  *   buffers containing two eyes (only adjust the timings when needed, eg. for
352ccd843b9SSandy Huang  *   "frame packing" or "side by side full").
353ccd843b9SSandy Huang  * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
354ccd843b9SSandy Huang  *   be performed for doublescan and vscan > 1 modes respectively.
355ccd843b9SSandy Huang  */
356ccd843b9SSandy Huang void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
357ccd843b9SSandy Huang {
358ccd843b9SSandy Huang 	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
359ccd843b9SSandy Huang 		return;
360ccd843b9SSandy Huang 
361ccd843b9SSandy Huang 	if (p->flags & DRM_MODE_FLAG_DBLCLK)
362ccd843b9SSandy Huang 		p->crtc_clock = 2 * p->clock;
363ccd843b9SSandy Huang 	else
364ccd843b9SSandy Huang 		p->crtc_clock = p->clock;
365ccd843b9SSandy Huang 	p->crtc_hdisplay = p->hdisplay;
366ccd843b9SSandy Huang 	p->crtc_hsync_start = p->hsync_start;
367ccd843b9SSandy Huang 	p->crtc_hsync_end = p->hsync_end;
368ccd843b9SSandy Huang 	p->crtc_htotal = p->htotal;
369ccd843b9SSandy Huang 	p->crtc_hskew = p->hskew;
370ccd843b9SSandy Huang 	p->crtc_vdisplay = p->vdisplay;
371ccd843b9SSandy Huang 	p->crtc_vsync_start = p->vsync_start;
372ccd843b9SSandy Huang 	p->crtc_vsync_end = p->vsync_end;
373ccd843b9SSandy Huang 	p->crtc_vtotal = p->vtotal;
374ccd843b9SSandy Huang 
375ccd843b9SSandy Huang 	if (p->flags & DRM_MODE_FLAG_INTERLACE) {
376ccd843b9SSandy Huang 		if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
377ccd843b9SSandy Huang 			p->crtc_vdisplay /= 2;
378ccd843b9SSandy Huang 			p->crtc_vsync_start /= 2;
379ccd843b9SSandy Huang 			p->crtc_vsync_end /= 2;
380ccd843b9SSandy Huang 			p->crtc_vtotal /= 2;
381ccd843b9SSandy Huang 		}
382ccd843b9SSandy Huang 	}
383ccd843b9SSandy Huang 
384ccd843b9SSandy Huang 	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
385ccd843b9SSandy Huang 		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
386ccd843b9SSandy Huang 			p->crtc_vdisplay *= 2;
387ccd843b9SSandy Huang 			p->crtc_vsync_start *= 2;
388ccd843b9SSandy Huang 			p->crtc_vsync_end *= 2;
389ccd843b9SSandy Huang 			p->crtc_vtotal *= 2;
390ccd843b9SSandy Huang 		}
391ccd843b9SSandy Huang 	}
392ccd843b9SSandy Huang 
393ccd843b9SSandy Huang 	if (!(adjust_flags & CRTC_NO_VSCAN)) {
394ccd843b9SSandy Huang 		if (p->vscan > 1) {
395ccd843b9SSandy Huang 			p->crtc_vdisplay *= p->vscan;
396ccd843b9SSandy Huang 			p->crtc_vsync_start *= p->vscan;
397ccd843b9SSandy Huang 			p->crtc_vsync_end *= p->vscan;
398ccd843b9SSandy Huang 			p->crtc_vtotal *= p->vscan;
399ccd843b9SSandy Huang 		}
400ccd843b9SSandy Huang 	}
401ccd843b9SSandy Huang 
402ccd843b9SSandy Huang 	if (adjust_flags & CRTC_STEREO_DOUBLE) {
403ccd843b9SSandy Huang 		unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
404ccd843b9SSandy Huang 
405ccd843b9SSandy Huang 		switch (layout) {
406ccd843b9SSandy Huang 		case DRM_MODE_FLAG_3D_FRAME_PACKING:
407ccd843b9SSandy Huang 			p->crtc_clock *= 2;
408ccd843b9SSandy Huang 			p->crtc_vdisplay += p->crtc_vtotal;
409ccd843b9SSandy Huang 			p->crtc_vsync_start += p->crtc_vtotal;
410ccd843b9SSandy Huang 			p->crtc_vsync_end += p->crtc_vtotal;
411ccd843b9SSandy Huang 			p->crtc_vtotal += p->crtc_vtotal;
412ccd843b9SSandy Huang 			break;
413ccd843b9SSandy Huang 		}
414ccd843b9SSandy Huang 	}
415ccd843b9SSandy Huang 
416ccd843b9SSandy Huang 	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
417ccd843b9SSandy Huang 	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
418ccd843b9SSandy Huang 	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
419ccd843b9SSandy Huang 	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
420ccd843b9SSandy Huang }
421ccd843b9SSandy Huang 
4228e2bab3fSAlgea Cao /**
4238e2bab3fSAlgea Cao  * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
4248e2bab3fSAlgea Cao  * output format
4258e2bab3fSAlgea Cao  *
4268e2bab3fSAlgea Cao  * @connector: drm connector under action.
4278e2bab3fSAlgea Cao  * @mode: video mode to be tested.
4288e2bab3fSAlgea Cao  *
4298e2bab3fSAlgea Cao  * Returns:
4308e2bab3fSAlgea Cao  * true if the mode can be supported in YCBCR420 format
4318e2bab3fSAlgea Cao  * false if not.
4328e2bab3fSAlgea Cao  */
4338e2bab3fSAlgea Cao bool drm_mode_is_420_only(const struct drm_display_info *display,
4348e2bab3fSAlgea Cao 			  struct drm_display_mode *mode)
4358e2bab3fSAlgea Cao {
4368e2bab3fSAlgea Cao 	u8 vic = drm_match_cea_mode(mode);
4378e2bab3fSAlgea Cao 
4388e2bab3fSAlgea Cao 	return test_bit(vic, display->hdmi.y420_vdb_modes);
4398e2bab3fSAlgea Cao }
4408e2bab3fSAlgea Cao 
4418e2bab3fSAlgea Cao /**
4428e2bab3fSAlgea Cao  * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
4438e2bab3fSAlgea Cao  * output format also (along with RGB/YCBCR444/422)
4448e2bab3fSAlgea Cao  *
4458e2bab3fSAlgea Cao  * @display: display under action.
4468e2bab3fSAlgea Cao  * @mode: video mode to be tested.
4478e2bab3fSAlgea Cao  *
4488e2bab3fSAlgea Cao  * Returns:
4498e2bab3fSAlgea Cao  * true if the mode can be support YCBCR420 format
4508e2bab3fSAlgea Cao  * false if not.
4518e2bab3fSAlgea Cao  */
4528e2bab3fSAlgea Cao bool drm_mode_is_420_also(const struct drm_display_info *display,
4538e2bab3fSAlgea Cao 			  struct drm_display_mode *mode)
4548e2bab3fSAlgea Cao {
4558e2bab3fSAlgea Cao 	u8 vic = drm_match_cea_mode(mode);
4568e2bab3fSAlgea Cao 
4578e2bab3fSAlgea Cao 	return test_bit(vic, display->hdmi.y420_cmdb_modes);
4588e2bab3fSAlgea Cao }
4598e2bab3fSAlgea Cao 
4608e2bab3fSAlgea Cao /**
4618e2bab3fSAlgea Cao  * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
4628e2bab3fSAlgea Cao  * output format
4638e2bab3fSAlgea Cao  *
4648e2bab3fSAlgea Cao  * @display: display under action.
4658e2bab3fSAlgea Cao  * @mode: video mode to be tested.
4668e2bab3fSAlgea Cao  *
4678e2bab3fSAlgea Cao  * Returns:
4688e2bab3fSAlgea Cao  * true if the mode can be supported in YCBCR420 format
4698e2bab3fSAlgea Cao  * false if not.
4708e2bab3fSAlgea Cao  */
4718e2bab3fSAlgea Cao bool drm_mode_is_420(const struct drm_display_info *display,
4728e2bab3fSAlgea Cao 		     struct drm_display_mode *mode)
4738e2bab3fSAlgea Cao {
4748e2bab3fSAlgea Cao 	return drm_mode_is_420_only(display, mode) ||
4758e2bab3fSAlgea Cao 		drm_mode_is_420_also(display, mode);
4768e2bab3fSAlgea Cao }
4778e2bab3fSAlgea Cao 
478186f8572SMark Yao static int display_get_timing(struct display_state *state)
479186f8572SMark Yao {
480186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
481186f8572SMark Yao 	struct drm_display_mode *mode = &conn_state->mode;
482186f8572SMark Yao 	const struct drm_display_mode *m;
4834b8c2ef1SMark Yao 	struct panel_state *panel_state = &state->panel_state;
484c493d00eSWyon Bi 	const struct rockchip_panel *panel = panel_state->panel;
485186f8572SMark Yao 
4861a8d717cSWyon Bi 	if (dev_of_valid(panel->dev) &&
4871a8d717cSWyon Bi 	    !display_get_timing_from_dts(panel_state, mode)) {
488186f8572SMark Yao 		printf("Using display timing dts\n");
489186f8572SMark Yao 		goto done;
490186f8572SMark Yao 	}
491186f8572SMark Yao 
492c493d00eSWyon Bi 	if (panel->data) {
493c493d00eSWyon Bi 		m = (const struct drm_display_mode *)panel->data;
494186f8572SMark Yao 		memcpy(mode, m, sizeof(*m));
495c493d00eSWyon Bi 		printf("Using display timing from compatible panel driver\n");
496186f8572SMark Yao 		goto done;
497186f8572SMark Yao 	}
498186f8572SMark Yao 
499186f8572SMark Yao 	printf("failed to find display timing\n");
500186f8572SMark Yao 	return -ENODEV;
501186f8572SMark Yao done:
502186f8572SMark Yao 	printf("Detailed mode clock %u kHz, flags[%x]\n"
503186f8572SMark Yao 	       "    H: %04d %04d %04d %04d\n"
504186f8572SMark Yao 	       "    V: %04d %04d %04d %04d\n"
505186f8572SMark Yao 	       "bus_format: %x\n",
506186f8572SMark Yao 	       mode->clock, mode->flags,
507186f8572SMark Yao 	       mode->hdisplay, mode->hsync_start,
508186f8572SMark Yao 	       mode->hsync_end, mode->htotal,
509186f8572SMark Yao 	       mode->vdisplay, mode->vsync_start,
510186f8572SMark Yao 	       mode->vsync_end, mode->vtotal,
511186f8572SMark Yao 	       conn_state->bus_format);
512186f8572SMark Yao 
513186f8572SMark Yao 	return 0;
514186f8572SMark Yao }
515186f8572SMark Yao 
516186f8572SMark Yao static int display_init(struct display_state *state)
517186f8572SMark Yao {
518186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
5191a8d717cSWyon Bi 	struct panel_state *panel_state = &state->panel_state;
520186f8572SMark Yao 	const struct rockchip_connector *conn = conn_state->connector;
521186f8572SMark Yao 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
522186f8572SMark Yao 	struct crtc_state *crtc_state = &state->crtc_state;
5232a48727aSAlgea Cao 	struct rockchip_crtc *crtc = crtc_state->crtc;
524186f8572SMark Yao 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
525ccd843b9SSandy Huang 	struct drm_display_mode *mode = &conn_state->mode;
526005d29a7SWyon Bi 	int bpc;
527186f8572SMark Yao 	int ret = 0;
52852015e97SSandy Huang 	static bool __print_once = false;
529186f8572SMark Yao 
53052015e97SSandy Huang 	if (!__print_once) {
53152015e97SSandy Huang 		__print_once = true;
532e559407dSSandy Huang 		printf("Rockchip UBOOT DRM driver version: %s\n", DRIVER_VERSION);
53352015e97SSandy Huang 	}
534e559407dSSandy Huang 
535186f8572SMark Yao 	if (state->is_init)
536186f8572SMark Yao 		return 0;
537186f8572SMark Yao 
538186f8572SMark Yao 	if (!conn_funcs || !crtc_funcs) {
539186f8572SMark Yao 		printf("failed to find connector or crtc functions\n");
540186f8572SMark Yao 		return -ENXIO;
541186f8572SMark Yao 	}
542186f8572SMark Yao 
5437cacd0a8SWyon Bi 	if (panel_state->panel)
5447cacd0a8SWyon Bi 		rockchip_panel_init(panel_state->panel);
5457cacd0a8SWyon Bi 
546186f8572SMark Yao 	if (conn_funcs->init) {
547186f8572SMark Yao 		ret = conn_funcs->init(state);
548186f8572SMark Yao 		if (ret)
5494b8c2ef1SMark Yao 			goto deinit;
550186f8572SMark Yao 	}
5517cacd0a8SWyon Bi 
5527cacd0a8SWyon Bi 	if (conn_state->phy)
5537cacd0a8SWyon Bi 		rockchip_phy_init(conn_state->phy);
5547cacd0a8SWyon Bi 
555186f8572SMark Yao 	/*
556186f8572SMark Yao 	 * support hotplug, but not connect;
557186f8572SMark Yao 	 */
5582a48727aSAlgea Cao #ifdef CONFIG_ROCKCHIP_DRM_TVE
5592a48727aSAlgea Cao 	if (crtc->hdmi_hpd && conn_state->type == DRM_MODE_CONNECTOR_TV) {
5602a48727aSAlgea Cao 		printf("hdmi plugin ,skip tve\n");
5612a48727aSAlgea Cao 		goto deinit;
5622a48727aSAlgea Cao 	}
5632a48727aSAlgea Cao #elif defined(CONFIG_ROCKCHIP_DRM_RK1000)
5642a48727aSAlgea Cao 	if (crtc->hdmi_hpd && conn_state->type == DRM_MODE_CONNECTOR_LVDS) {
5652a48727aSAlgea Cao 		printf("hdmi plugin ,skip tve\n");
5662a48727aSAlgea Cao 		goto deinit;
5672a48727aSAlgea Cao 	}
5682a48727aSAlgea Cao #endif
569186f8572SMark Yao 	if (conn_funcs->detect) {
570186f8572SMark Yao 		ret = conn_funcs->detect(state);
5712a48727aSAlgea Cao #if defined(CONFIG_ROCKCHIP_DRM_TVE) || defined(CONFIG_ROCKCHIP_DRM_RK1000)
5722a48727aSAlgea Cao 		if (conn_state->type == DRM_MODE_CONNECTOR_HDMIA)
5732a48727aSAlgea Cao 			crtc->hdmi_hpd = ret;
5742a48727aSAlgea Cao #endif
575186f8572SMark Yao 		if (!ret)
576186f8572SMark Yao 			goto deinit;
577186f8572SMark Yao 	}
578186f8572SMark Yao 
579005d29a7SWyon Bi 	if (panel_state->panel) {
580186f8572SMark Yao 		ret = display_get_timing(state);
5811a8d717cSWyon Bi 	} else if (conn_state->bridge) {
5821a8d717cSWyon Bi 		ret = video_bridge_read_edid(conn_state->bridge->dev,
5831a8d717cSWyon Bi 					     conn_state->edid, EDID_SIZE);
5841a8d717cSWyon Bi 		if (ret > 0) {
5851a8d717cSWyon Bi 			ret = edid_get_drm_mode(conn_state->edid, ret, mode,
5861a8d717cSWyon Bi 						&bpc);
5871a8d717cSWyon Bi 			if (!ret)
5881a8d717cSWyon Bi 				edid_print_info((void *)&conn_state->edid);
589*75eb6fceSAlgea Cao 		} else {
590*75eb6fceSAlgea Cao 			ret = video_bridge_get_timing(conn_state->bridge->dev);
5911a8d717cSWyon Bi 		}
592005d29a7SWyon Bi 	} else if (conn_funcs->get_timing) {
593005d29a7SWyon Bi 		ret = conn_funcs->get_timing(state);
594005d29a7SWyon Bi 	} else if (conn_funcs->get_edid) {
595005d29a7SWyon Bi 		ret = conn_funcs->get_edid(state);
596005d29a7SWyon Bi 		if (!ret) {
597005d29a7SWyon Bi 			ret = edid_get_drm_mode((void *)&conn_state->edid,
598005d29a7SWyon Bi 						sizeof(conn_state->edid), mode,
599005d29a7SWyon Bi 						&bpc);
600005d29a7SWyon Bi 			if (!ret)
601005d29a7SWyon Bi 				edid_print_info((void *)&conn_state->edid);
602005d29a7SWyon Bi 		}
6031a8d717cSWyon Bi 	}
6041a8d717cSWyon Bi 
605186f8572SMark Yao 	if (ret)
606186f8572SMark Yao 		goto deinit;
6071a8d717cSWyon Bi 
608ccd843b9SSandy Huang 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
609186f8572SMark Yao 
610186f8572SMark Yao 	if (crtc_funcs->init) {
611186f8572SMark Yao 		ret = crtc_funcs->init(state);
612186f8572SMark Yao 		if (ret)
613186f8572SMark Yao 			goto deinit;
614186f8572SMark Yao 	}
615186f8572SMark Yao 	state->is_init = 1;
616186f8572SMark Yao 
617186f8572SMark Yao 	return 0;
618186f8572SMark Yao 
619186f8572SMark Yao deinit:
620186f8572SMark Yao 	if (conn_funcs->deinit)
621186f8572SMark Yao 		conn_funcs->deinit(state);
622186f8572SMark Yao 	return ret;
623186f8572SMark Yao }
624186f8572SMark Yao 
62567b9012cSSandy Huang int display_send_mcu_cmd(struct display_state *state, u32 type, u32 val)
62667b9012cSSandy Huang {
62767b9012cSSandy Huang 	struct crtc_state *crtc_state = &state->crtc_state;
62867b9012cSSandy Huang 	const struct rockchip_crtc *crtc = crtc_state->crtc;
62967b9012cSSandy Huang 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
63067b9012cSSandy Huang 	int ret;
63167b9012cSSandy Huang 
63267b9012cSSandy Huang 	if (!state->is_init)
63367b9012cSSandy Huang 		return -EINVAL;
63467b9012cSSandy Huang 
63567b9012cSSandy Huang 	if (crtc_funcs->send_mcu_cmd) {
63667b9012cSSandy Huang 		ret = crtc_funcs->send_mcu_cmd(state, type, val);
63767b9012cSSandy Huang 		if (ret)
63867b9012cSSandy Huang 			return ret;
63967b9012cSSandy Huang 	}
64067b9012cSSandy Huang 
64167b9012cSSandy Huang 	return 0;
64267b9012cSSandy Huang }
64367b9012cSSandy Huang 
644186f8572SMark Yao static int display_set_plane(struct display_state *state)
645186f8572SMark Yao {
646186f8572SMark Yao 	struct crtc_state *crtc_state = &state->crtc_state;
647186f8572SMark Yao 	const struct rockchip_crtc *crtc = crtc_state->crtc;
648186f8572SMark Yao 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
649186f8572SMark Yao 	int ret;
650186f8572SMark Yao 
651186f8572SMark Yao 	if (!state->is_init)
652186f8572SMark Yao 		return -EINVAL;
653186f8572SMark Yao 
654186f8572SMark Yao 	if (crtc_funcs->set_plane) {
655186f8572SMark Yao 		ret = crtc_funcs->set_plane(state);
656186f8572SMark Yao 		if (ret)
657186f8572SMark Yao 			return ret;
658186f8572SMark Yao 	}
659186f8572SMark Yao 
660186f8572SMark Yao 	return 0;
661186f8572SMark Yao }
662186f8572SMark Yao 
663186f8572SMark Yao static int display_enable(struct display_state *state)
664186f8572SMark Yao {
665186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
666186f8572SMark Yao 	const struct rockchip_connector *conn = conn_state->connector;
667186f8572SMark Yao 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
668186f8572SMark Yao 	struct crtc_state *crtc_state = &state->crtc_state;
669186f8572SMark Yao 	const struct rockchip_crtc *crtc = crtc_state->crtc;
670186f8572SMark Yao 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
6717cacd0a8SWyon Bi 	struct panel_state *panel_state = &state->panel_state;
672186f8572SMark Yao 
673186f8572SMark Yao 	display_init(state);
674186f8572SMark Yao 
675186f8572SMark Yao 	if (!state->is_init)
676186f8572SMark Yao 		return -EINVAL;
677186f8572SMark Yao 
678186f8572SMark Yao 	if (state->is_enable)
679186f8572SMark Yao 		return 0;
680186f8572SMark Yao 
68149ae8667SWyon Bi 	if (crtc_funcs->prepare)
68249ae8667SWyon Bi 		crtc_funcs->prepare(state);
683186f8572SMark Yao 
68449ae8667SWyon Bi 	if (conn_funcs->prepare)
68549ae8667SWyon Bi 		conn_funcs->prepare(state);
686186f8572SMark Yao 
6871a8d717cSWyon Bi 	if (conn_state->bridge)
6881a8d717cSWyon Bi 		rockchip_bridge_pre_enable(conn_state->bridge);
6891a8d717cSWyon Bi 
6907cacd0a8SWyon Bi 	if (panel_state->panel)
6917cacd0a8SWyon Bi 		rockchip_panel_prepare(panel_state->panel);
692186f8572SMark Yao 
69349ae8667SWyon Bi 	if (crtc_funcs->enable)
69449ae8667SWyon Bi 		crtc_funcs->enable(state);
695186f8572SMark Yao 
69649ae8667SWyon Bi 	if (conn_funcs->enable)
69749ae8667SWyon Bi 		conn_funcs->enable(state);
698186f8572SMark Yao 
6991a8d717cSWyon Bi 	if (conn_state->bridge)
7001a8d717cSWyon Bi 		rockchip_bridge_enable(conn_state->bridge);
7011a8d717cSWyon Bi 
7027cacd0a8SWyon Bi 	if (panel_state->panel)
7037cacd0a8SWyon Bi 		rockchip_panel_enable(panel_state->panel);
704186f8572SMark Yao 
705186f8572SMark Yao 	state->is_enable = true;
706c493d00eSWyon Bi 
70749ae8667SWyon Bi 	return 0;
708186f8572SMark Yao }
709186f8572SMark Yao 
710186f8572SMark Yao static int display_disable(struct display_state *state)
711186f8572SMark Yao {
712186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
713186f8572SMark Yao 	const struct rockchip_connector *conn = conn_state->connector;
714186f8572SMark Yao 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
715186f8572SMark Yao 	struct crtc_state *crtc_state = &state->crtc_state;
716186f8572SMark Yao 	const struct rockchip_crtc *crtc = crtc_state->crtc;
717186f8572SMark Yao 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
7187cacd0a8SWyon Bi 	struct panel_state *panel_state = &state->panel_state;
719186f8572SMark Yao 
720186f8572SMark Yao 	if (!state->is_init)
721186f8572SMark Yao 		return 0;
722186f8572SMark Yao 
723186f8572SMark Yao 	if (!state->is_enable)
724186f8572SMark Yao 		return 0;
725186f8572SMark Yao 
7267cacd0a8SWyon Bi 	if (panel_state->panel)
7277cacd0a8SWyon Bi 		rockchip_panel_disable(panel_state->panel);
728186f8572SMark Yao 
7291a8d717cSWyon Bi 	if (conn_state->bridge)
7301a8d717cSWyon Bi 		rockchip_bridge_disable(conn_state->bridge);
731186f8572SMark Yao 
732186f8572SMark Yao 	if (conn_funcs->disable)
733186f8572SMark Yao 		conn_funcs->disable(state);
734186f8572SMark Yao 
7351a8d717cSWyon Bi 	if (crtc_funcs->disable)
7361a8d717cSWyon Bi 		crtc_funcs->disable(state);
7371a8d717cSWyon Bi 
7387cacd0a8SWyon Bi 	if (panel_state->panel)
7397cacd0a8SWyon Bi 		rockchip_panel_unprepare(panel_state->panel);
740186f8572SMark Yao 
7411a8d717cSWyon Bi 	if (conn_state->bridge)
7421a8d717cSWyon Bi 		rockchip_bridge_post_disable(conn_state->bridge);
7431a8d717cSWyon Bi 
744186f8572SMark Yao 	if (conn_funcs->unprepare)
745186f8572SMark Yao 		conn_funcs->unprepare(state);
746186f8572SMark Yao 
747186f8572SMark Yao 	state->is_enable = 0;
748186f8572SMark Yao 	state->is_init = 0;
749186f8572SMark Yao 
750186f8572SMark Yao 	return 0;
751186f8572SMark Yao }
752186f8572SMark Yao 
753186f8572SMark Yao static int display_logo(struct display_state *state)
754186f8572SMark Yao {
755186f8572SMark Yao 	struct crtc_state *crtc_state = &state->crtc_state;
756186f8572SMark Yao 	struct connector_state *conn_state = &state->conn_state;
757186f8572SMark Yao 	struct logo_info *logo = &state->logo;
758186f8572SMark Yao 	int hdisplay, vdisplay;
759186f8572SMark Yao 
760186f8572SMark Yao 	display_init(state);
761186f8572SMark Yao 	if (!state->is_init)
762186f8572SMark Yao 		return -ENODEV;
763186f8572SMark Yao 
764186f8572SMark Yao 	switch (logo->bpp) {
765186f8572SMark Yao 	case 16:
766186f8572SMark Yao 		crtc_state->format = ROCKCHIP_FMT_RGB565;
767186f8572SMark Yao 		break;
768186f8572SMark Yao 	case 24:
769186f8572SMark Yao 		crtc_state->format = ROCKCHIP_FMT_RGB888;
770186f8572SMark Yao 		break;
771186f8572SMark Yao 	case 32:
772186f8572SMark Yao 		crtc_state->format = ROCKCHIP_FMT_ARGB8888;
773186f8572SMark Yao 		break;
774186f8572SMark Yao 	default:
775186f8572SMark Yao 		printf("can't support bmp bits[%d]\n", logo->bpp);
776186f8572SMark Yao 		return -EINVAL;
777186f8572SMark Yao 	}
778861ce1a0SSandy Huang 	crtc_state->rb_swap = logo->bpp != 32;
779186f8572SMark Yao 	hdisplay = conn_state->mode.hdisplay;
780186f8572SMark Yao 	vdisplay = conn_state->mode.vdisplay;
781186f8572SMark Yao 	crtc_state->src_w = logo->width;
782186f8572SMark Yao 	crtc_state->src_h = logo->height;
783186f8572SMark Yao 	crtc_state->src_x = 0;
784186f8572SMark Yao 	crtc_state->src_y = 0;
785186f8572SMark Yao 	crtc_state->ymirror = logo->ymirror;
786186f8572SMark Yao 
7874b8c2ef1SMark Yao 	crtc_state->dma_addr = (u32)(unsigned long)logo->mem + logo->offset;
788186f8572SMark Yao 	crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5;
789186f8572SMark Yao 
790186f8572SMark Yao 	if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) {
791186f8572SMark Yao 		crtc_state->crtc_x = 0;
792186f8572SMark Yao 		crtc_state->crtc_y = 0;
793186f8572SMark Yao 		crtc_state->crtc_w = hdisplay;
794186f8572SMark Yao 		crtc_state->crtc_h = vdisplay;
795186f8572SMark Yao 	} else {
796186f8572SMark Yao 		if (crtc_state->src_w >= hdisplay) {
797186f8572SMark Yao 			crtc_state->crtc_x = 0;
798186f8572SMark Yao 			crtc_state->crtc_w = hdisplay;
799186f8572SMark Yao 		} else {
800186f8572SMark Yao 			crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2;
801186f8572SMark Yao 			crtc_state->crtc_w = crtc_state->src_w;
802186f8572SMark Yao 		}
803186f8572SMark Yao 
804186f8572SMark Yao 		if (crtc_state->src_h >= vdisplay) {
805186f8572SMark Yao 			crtc_state->crtc_y = 0;
806186f8572SMark Yao 			crtc_state->crtc_h = vdisplay;
807186f8572SMark Yao 		} else {
808186f8572SMark Yao 			crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2;
809186f8572SMark Yao 			crtc_state->crtc_h = crtc_state->src_h;
810186f8572SMark Yao 		}
811186f8572SMark Yao 	}
812186f8572SMark Yao 
813186f8572SMark Yao 	display_set_plane(state);
814186f8572SMark Yao 	display_enable(state);
815186f8572SMark Yao 
816186f8572SMark Yao 	return 0;
817186f8572SMark Yao }
818186f8572SMark Yao 
819e2bce6e4SKever Yang static int get_crtc_id(ofnode connect)
820186f8572SMark Yao {
821e2bce6e4SKever Yang 	int phandle;
822e2bce6e4SKever Yang 	struct device_node *remote;
823186f8572SMark Yao 	int val;
824186f8572SMark Yao 
825e2bce6e4SKever Yang 	phandle = ofnode_read_u32_default(connect, "remote-endpoint", -1);
826186f8572SMark Yao 	if (phandle < 0)
827186f8572SMark Yao 		goto err;
828e2bce6e4SKever Yang 	remote = of_find_node_by_phandle(phandle);
829e2bce6e4SKever Yang 	val = ofnode_read_u32_default(np_to_ofnode(remote), "reg", -1);
830186f8572SMark Yao 	if (val < 0)
831186f8572SMark Yao 		goto err;
832186f8572SMark Yao 
833186f8572SMark Yao 	return val;
834186f8572SMark Yao err:
835186f8572SMark Yao 	printf("Can't get crtc id, default set to id = 0\n");
836186f8572SMark Yao 	return 0;
837186f8572SMark Yao }
838186f8572SMark Yao 
83967b9012cSSandy Huang static int get_crtc_mcu_mode(struct crtc_state *crtc_state)
84067b9012cSSandy Huang {
84167b9012cSSandy Huang 	ofnode mcu_node;
84267b9012cSSandy Huang 	int total_pixel, cs_pst, cs_pend, rw_pst, rw_pend;
84367b9012cSSandy Huang 
84467b9012cSSandy Huang 	mcu_node = dev_read_subnode(crtc_state->dev, "mcu-timing");
845a196d7fcSKever Yang 	if (!ofnode_valid(mcu_node))
846a196d7fcSKever Yang 		return -ENODEV;
84767b9012cSSandy Huang 
84867b9012cSSandy Huang #define FDT_GET_MCU_INT(val, name) \
84967b9012cSSandy Huang 	do { \
85067b9012cSSandy Huang 		val = ofnode_read_s32_default(mcu_node, name, -1); \
85167b9012cSSandy Huang 		if (val < 0) { \
85267b9012cSSandy Huang 			printf("Can't get %s\n", name); \
85367b9012cSSandy Huang 			return -ENXIO; \
85467b9012cSSandy Huang 		} \
85567b9012cSSandy Huang 	} while (0)
85667b9012cSSandy Huang 
85767b9012cSSandy Huang 	FDT_GET_MCU_INT(total_pixel, "mcu-pix-total");
85867b9012cSSandy Huang 	FDT_GET_MCU_INT(cs_pst, "mcu-cs-pst");
85967b9012cSSandy Huang 	FDT_GET_MCU_INT(cs_pend, "mcu-cs-pend");
86067b9012cSSandy Huang 	FDT_GET_MCU_INT(rw_pst, "mcu-rw-pst");
86167b9012cSSandy Huang 	FDT_GET_MCU_INT(rw_pend, "mcu-rw-pend");
86267b9012cSSandy Huang 
86367b9012cSSandy Huang 	crtc_state->mcu_timing.mcu_pix_total = total_pixel;
86467b9012cSSandy Huang 	crtc_state->mcu_timing.mcu_cs_pst = cs_pst;
86567b9012cSSandy Huang 	crtc_state->mcu_timing.mcu_cs_pend = cs_pend;
86667b9012cSSandy Huang 	crtc_state->mcu_timing.mcu_rw_pst = rw_pst;
86767b9012cSSandy Huang 	crtc_state->mcu_timing.mcu_rw_pend = rw_pend;
86867b9012cSSandy Huang 
86967b9012cSSandy Huang 	return 0;
87067b9012cSSandy Huang }
87167b9012cSSandy Huang 
872186f8572SMark Yao struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp)
873186f8572SMark Yao {
874186f8572SMark Yao 	struct rockchip_logo_cache *tmp, *logo_cache = NULL;
875186f8572SMark Yao 
876186f8572SMark Yao 	list_for_each_entry(tmp, &logo_cache_list, head) {
877186f8572SMark Yao 		if (!strcmp(tmp->name, bmp)) {
878186f8572SMark Yao 			logo_cache = tmp;
879186f8572SMark Yao 			break;
880186f8572SMark Yao 		}
881186f8572SMark Yao 	}
882186f8572SMark Yao 
883186f8572SMark Yao 	if (!logo_cache) {
884186f8572SMark Yao 		logo_cache = malloc(sizeof(*logo_cache));
885186f8572SMark Yao 		if (!logo_cache) {
886186f8572SMark Yao 			printf("failed to alloc memory for logo cache\n");
887186f8572SMark Yao 			return NULL;
888186f8572SMark Yao 		}
889186f8572SMark Yao 		memset(logo_cache, 0, sizeof(*logo_cache));
890186f8572SMark Yao 		strcpy(logo_cache->name, bmp);
891186f8572SMark Yao 		INIT_LIST_HEAD(&logo_cache->head);
892186f8572SMark Yao 		list_add_tail(&logo_cache->head, &logo_cache_list);
893186f8572SMark Yao 	}
894186f8572SMark Yao 
895186f8572SMark Yao 	return logo_cache;
896186f8572SMark Yao }
897186f8572SMark Yao 
8985eb61944SSandy Huang /* Note: used only for rkfb kernel driver */
8995eb61944SSandy Huang static int load_kernel_bmp_logo(struct logo_info *logo, const char *bmp_name)
9005eb61944SSandy Huang {
9015eb61944SSandy Huang #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
9025eb61944SSandy Huang 	void *dst = NULL;
9035eb61944SSandy Huang 	int len, size;
9045eb61944SSandy Huang 	struct bmp_header *header;
9055eb61944SSandy Huang 
9065eb61944SSandy Huang 	if (!logo || !bmp_name)
9075eb61944SSandy Huang 		return -EINVAL;
9085eb61944SSandy Huang 
9095eb61944SSandy Huang 	header = malloc(RK_BLK_SIZE);
9105eb61944SSandy Huang 	if (!header)
9115eb61944SSandy Huang 		return -ENOMEM;
9125eb61944SSandy Huang 
9135eb61944SSandy Huang 	len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
9145eb61944SSandy Huang 	if (len != RK_BLK_SIZE) {
9155eb61944SSandy Huang 		free(header);
9165eb61944SSandy Huang 		return -EINVAL;
9175eb61944SSandy Huang 	}
9185eb61944SSandy Huang 	size = get_unaligned_le32(&header->file_size);
9195eb61944SSandy Huang 	dst = (void *)(memory_start + MEMORY_POOL_SIZE / 2);
9205eb61944SSandy Huang 	len = rockchip_read_resource_file(dst, bmp_name, 0, size);
9215eb61944SSandy Huang 	if (len != size) {
9225eb61944SSandy Huang 		printf("failed to load bmp %s\n", bmp_name);
9235eb61944SSandy Huang 		free(header);
9245eb61944SSandy Huang 		return -ENOENT;
9255eb61944SSandy Huang 	}
9265eb61944SSandy Huang 
9275eb61944SSandy Huang 	logo->mem = dst;
9285eb61944SSandy Huang 
9295eb61944SSandy Huang 	return 0;
9305eb61944SSandy Huang #endif
9315eb61944SSandy Huang }
9325eb61944SSandy Huang 
933186f8572SMark Yao static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
934186f8572SMark Yao {
9354b8c2ef1SMark Yao #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
936186f8572SMark Yao 	struct rockchip_logo_cache *logo_cache;
937186f8572SMark Yao 	struct bmp_header *header;
938186f8572SMark Yao 	void *dst = NULL, *pdst;
9394b8c2ef1SMark Yao 	int size, len;
9404b8c2ef1SMark Yao 	int ret = 0;
9417e72214dSShixiang Zheng 	int reserved = 0;
942186f8572SMark Yao 
943186f8572SMark Yao 	if (!logo || !bmp_name)
944186f8572SMark Yao 		return -EINVAL;
945186f8572SMark Yao 	logo_cache = find_or_alloc_logo_cache(bmp_name);
946186f8572SMark Yao 	if (!logo_cache)
947186f8572SMark Yao 		return -ENOMEM;
948186f8572SMark Yao 
949186f8572SMark Yao 	if (logo_cache->logo.mem) {
950186f8572SMark Yao 		memcpy(logo, &logo_cache->logo, sizeof(*logo));
951186f8572SMark Yao 		return 0;
952186f8572SMark Yao 	}
953186f8572SMark Yao 
9544b8c2ef1SMark Yao 	header = malloc(RK_BLK_SIZE);
955186f8572SMark Yao 	if (!header)
9564b8c2ef1SMark Yao 		return -ENOMEM;
9574b8c2ef1SMark Yao 
9584b8c2ef1SMark Yao 	len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
9594b8c2ef1SMark Yao 	if (len != RK_BLK_SIZE) {
9604b8c2ef1SMark Yao 		ret = -EINVAL;
9614b8c2ef1SMark Yao 		goto free_header;
9624b8c2ef1SMark Yao 	}
963186f8572SMark Yao 
964186f8572SMark Yao 	logo->bpp = get_unaligned_le16(&header->bit_count);
965186f8572SMark Yao 	logo->width = get_unaligned_le32(&header->width);
966186f8572SMark Yao 	logo->height = get_unaligned_le32(&header->height);
9677e72214dSShixiang Zheng 	reserved = get_unaligned_le32(&header->reserved);
9687e72214dSShixiang Zheng 	if (logo->height < 0)
9697e72214dSShixiang Zheng 	    logo->height = -logo->height;
970186f8572SMark Yao 	size = get_unaligned_le32(&header->file_size);
971861ce1a0SSandy Huang 	if (!can_direct_logo(logo->bpp)) {
972186f8572SMark Yao 		if (size > MEMORY_POOL_SIZE) {
973186f8572SMark Yao 			printf("failed to use boot buf as temp bmp buffer\n");
9744b8c2ef1SMark Yao 			ret = -ENOMEM;
9754b8c2ef1SMark Yao 			goto free_header;
976186f8572SMark Yao 		}
977861ce1a0SSandy Huang 		pdst = get_display_buffer(size);
978186f8572SMark Yao 
979861ce1a0SSandy Huang 	} else {
980186f8572SMark Yao 		pdst = get_display_buffer(size);
981186f8572SMark Yao 		dst = pdst;
982861ce1a0SSandy Huang 	}
983186f8572SMark Yao 
9844b8c2ef1SMark Yao 	len = rockchip_read_resource_file(pdst, bmp_name, 0, size);
9854b8c2ef1SMark Yao 	if (len != size) {
986186f8572SMark Yao 		printf("failed to load bmp %s\n", bmp_name);
9874b8c2ef1SMark Yao 		ret = -ENOENT;
9884b8c2ef1SMark Yao 		goto free_header;
989186f8572SMark Yao 	}
99055e2f86dSSandy Huang 
991861ce1a0SSandy Huang 	if (!can_direct_logo(logo->bpp)) {
992186f8572SMark Yao 		int dst_size;
993186f8572SMark Yao 		/*
994186f8572SMark Yao 		 * TODO: force use 16bpp if bpp less than 16;
995186f8572SMark Yao 		 */
996186f8572SMark Yao 		logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp;
997186f8572SMark Yao 		dst_size = logo->width * logo->height * logo->bpp >> 3;
99855e2f86dSSandy Huang 
999186f8572SMark Yao 		dst = get_display_buffer(dst_size);
10004b8c2ef1SMark Yao 		if (!dst) {
10014b8c2ef1SMark Yao 			ret = -ENOMEM;
10024b8c2ef1SMark Yao 			goto free_header;
10034b8c2ef1SMark Yao 		}
100455e2f86dSSandy Huang 		if (bmpdecoder(pdst, dst, logo->bpp)) {
1005186f8572SMark Yao 			printf("failed to decode bmp %s\n", bmp_name);
10064b8c2ef1SMark Yao 			ret = -EINVAL;
10074b8c2ef1SMark Yao 			goto free_header;
1008186f8572SMark Yao 		}
10094b8c2ef1SMark Yao 		flush_dcache_range((ulong)dst,
10104b8c2ef1SMark Yao 				   ALIGN((ulong)dst + dst_size,
10114b8c2ef1SMark Yao 					 CONFIG_SYS_CACHELINE_SIZE));
101255e2f86dSSandy Huang 
1013186f8572SMark Yao 		logo->offset = 0;
101455e2f86dSSandy Huang 		logo->ymirror = 0;
1015186f8572SMark Yao 	} else {
1016186f8572SMark Yao 		logo->offset = get_unaligned_le32(&header->data_offset);
10177e72214dSShixiang Zheng 		if (reserved == BMP_PROCESSED_FLAG)
10187e72214dSShixiang Zheng 			logo->ymirror = 0;
10197e72214dSShixiang Zheng 		else
102055e2f86dSSandy Huang 			logo->ymirror = 1;
1021186f8572SMark Yao 	}
10224b8c2ef1SMark Yao 	logo->mem = dst;
1023186f8572SMark Yao 
1024186f8572SMark Yao 	memcpy(&logo_cache->logo, logo, sizeof(*logo));
1025186f8572SMark Yao 
10264b8c2ef1SMark Yao free_header:
10274b8c2ef1SMark Yao 
10284b8c2ef1SMark Yao 	free(header);
10294b8c2ef1SMark Yao 
10304b8c2ef1SMark Yao 	return ret;
10314b8c2ef1SMark Yao #else
10324b8c2ef1SMark Yao 	return -EINVAL;
10334b8c2ef1SMark Yao #endif
1034186f8572SMark Yao }
1035186f8572SMark Yao 
1036186f8572SMark Yao void rockchip_show_fbbase(ulong fbbase)
1037186f8572SMark Yao {
1038186f8572SMark Yao 	struct display_state *s;
1039186f8572SMark Yao 
1040186f8572SMark Yao 	list_for_each_entry(s, &rockchip_display_list, head) {
1041186f8572SMark Yao 		s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN;
10424b8c2ef1SMark Yao 		s->logo.mem = (char *)fbbase;
1043186f8572SMark Yao 		s->logo.width = DRM_ROCKCHIP_FB_WIDTH;
1044186f8572SMark Yao 		s->logo.height = DRM_ROCKCHIP_FB_HEIGHT;
1045186f8572SMark Yao 		s->logo.bpp = 32;
1046186f8572SMark Yao 		s->logo.ymirror = 0;
1047186f8572SMark Yao 
1048186f8572SMark Yao 		display_logo(s);
1049186f8572SMark Yao 	}
1050186f8572SMark Yao }
1051186f8572SMark Yao 
1052a2d2b88eSSandy Huang int rockchip_show_bmp(const char *bmp)
1053186f8572SMark Yao {
1054186f8572SMark Yao 	struct display_state *s;
1055a2d2b88eSSandy Huang 	int ret = 0;
1056186f8572SMark Yao 
1057186f8572SMark Yao 	if (!bmp) {
1058186f8572SMark Yao 		list_for_each_entry(s, &rockchip_display_list, head)
1059186f8572SMark Yao 			display_disable(s);
1060a2d2b88eSSandy Huang 		return -ENOENT;
1061186f8572SMark Yao 	}
1062186f8572SMark Yao 
1063186f8572SMark Yao 	list_for_each_entry(s, &rockchip_display_list, head) {
1064186f8572SMark Yao 		s->logo.mode = s->charge_logo_mode;
1065186f8572SMark Yao 		if (load_bmp_logo(&s->logo, bmp))
1066186f8572SMark Yao 			continue;
1067a2d2b88eSSandy Huang 		ret = display_logo(s);
1068186f8572SMark Yao 	}
1069186f8572SMark Yao 
1070a2d2b88eSSandy Huang 	return ret;
1071a2d2b88eSSandy Huang }
1072a2d2b88eSSandy Huang 
1073a2d2b88eSSandy Huang int rockchip_show_logo(void)
1074186f8572SMark Yao {
1075186f8572SMark Yao 	struct display_state *s;
1076a2d2b88eSSandy Huang 	int ret = 0;
1077186f8572SMark Yao 
1078186f8572SMark Yao 	list_for_each_entry(s, &rockchip_display_list, head) {
1079186f8572SMark Yao 		s->logo.mode = s->logo_mode;
1080186f8572SMark Yao 		if (load_bmp_logo(&s->logo, s->ulogo_name))
1081186f8572SMark Yao 			printf("failed to display uboot logo\n");
1082186f8572SMark Yao 		else
1083a2d2b88eSSandy Huang 			ret = display_logo(s);
10845eb61944SSandy Huang 
10855eb61944SSandy Huang 		/* Load kernel bmp in rockchip_display_fixup() later */
1086186f8572SMark Yao 	}
1087a2d2b88eSSandy Huang 
1088a2d2b88eSSandy Huang 	return ret;
1089186f8572SMark Yao }
1090186f8572SMark Yao 
10911a8d717cSWyon Bi enum {
10921a8d717cSWyon Bi 	PORT_DIR_IN,
10931a8d717cSWyon Bi 	PORT_DIR_OUT,
10941a8d717cSWyon Bi };
10951a8d717cSWyon Bi 
10961a8d717cSWyon Bi static struct rockchip_panel *rockchip_of_find_panel(struct udevice *dev)
10971a8d717cSWyon Bi {
10981a8d717cSWyon Bi 	ofnode panel_node, ports, port, ep;
10991a8d717cSWyon Bi 	struct udevice *panel_dev;
11001a8d717cSWyon Bi 	int ret;
11011a8d717cSWyon Bi 
11021a8d717cSWyon Bi 	panel_node = dev_read_subnode(dev, "panel");
11031a8d717cSWyon Bi 	if (ofnode_valid(panel_node) && ofnode_is_available(panel_node)) {
11041a8d717cSWyon Bi 		ret = uclass_get_device_by_ofnode(UCLASS_PANEL, panel_node,
11051a8d717cSWyon Bi 						  &panel_dev);
11061a8d717cSWyon Bi 		if (!ret)
11071a8d717cSWyon Bi 			goto found;
11081a8d717cSWyon Bi 	}
11091a8d717cSWyon Bi 
11101a8d717cSWyon Bi 	ports = dev_read_subnode(dev, "ports");
11111a8d717cSWyon Bi 	if (!ofnode_valid(ports))
11121a8d717cSWyon Bi 		return NULL;
11131a8d717cSWyon Bi 
11141a8d717cSWyon Bi 	ofnode_for_each_subnode(port, ports) {
11151a8d717cSWyon Bi 		u32 reg;
11161a8d717cSWyon Bi 
11171a8d717cSWyon Bi 		if (ofnode_read_u32(port, "reg", &reg))
11181a8d717cSWyon Bi 			continue;
11191a8d717cSWyon Bi 
11201a8d717cSWyon Bi 		if (reg != PORT_DIR_OUT)
11211a8d717cSWyon Bi 			continue;
11221a8d717cSWyon Bi 
11231a8d717cSWyon Bi 		ofnode_for_each_subnode(ep, port) {
11241a8d717cSWyon Bi 			ofnode _ep, _port;
11251a8d717cSWyon Bi 			uint phandle;
11261a8d717cSWyon Bi 
11271a8d717cSWyon Bi 			if (ofnode_read_u32(ep, "remote-endpoint", &phandle))
11281a8d717cSWyon Bi 				continue;
11291a8d717cSWyon Bi 
11301a8d717cSWyon Bi 			_ep = ofnode_get_by_phandle(phandle);
11311a8d717cSWyon Bi 			if (!ofnode_valid(_ep))
11321a8d717cSWyon Bi 				continue;
11331a8d717cSWyon Bi 
11341a8d717cSWyon Bi 			_port = ofnode_get_parent(_ep);
11351a8d717cSWyon Bi 			if (!ofnode_valid(_port))
11361a8d717cSWyon Bi 				continue;
11371a8d717cSWyon Bi 
11381a8d717cSWyon Bi 			panel_node = ofnode_get_parent(_port);
11391a8d717cSWyon Bi 			if (!ofnode_valid(panel_node))
11401a8d717cSWyon Bi 				continue;
11411a8d717cSWyon Bi 
11421a8d717cSWyon Bi 			ret = uclass_get_device_by_ofnode(UCLASS_PANEL,
11431a8d717cSWyon Bi 							  panel_node,
11441a8d717cSWyon Bi 							  &panel_dev);
11451a8d717cSWyon Bi 			if (!ret)
11461a8d717cSWyon Bi 				goto found;
11471a8d717cSWyon Bi 		}
11481a8d717cSWyon Bi 	}
11491a8d717cSWyon Bi 
11501a8d717cSWyon Bi 	return NULL;
11511a8d717cSWyon Bi 
11521a8d717cSWyon Bi found:
11531a8d717cSWyon Bi 	return (struct rockchip_panel *)dev_get_driver_data(panel_dev);
11541a8d717cSWyon Bi }
11551a8d717cSWyon Bi 
11561a8d717cSWyon Bi static struct rockchip_bridge *rockchip_of_find_bridge(struct udevice *conn_dev)
11571a8d717cSWyon Bi {
11581a8d717cSWyon Bi 	ofnode node, ports, port, ep;
11591a8d717cSWyon Bi 	struct udevice *dev;
11601a8d717cSWyon Bi 	int ret;
11611a8d717cSWyon Bi 
11621a8d717cSWyon Bi 	ports = dev_read_subnode(conn_dev, "ports");
11631a8d717cSWyon Bi 	if (!ofnode_valid(ports))
11641a8d717cSWyon Bi 		return NULL;
11651a8d717cSWyon Bi 
11661a8d717cSWyon Bi 	ofnode_for_each_subnode(port, ports) {
11671a8d717cSWyon Bi 		u32 reg;
11681a8d717cSWyon Bi 
11691a8d717cSWyon Bi 		if (ofnode_read_u32(port, "reg", &reg))
11701a8d717cSWyon Bi 			continue;
11711a8d717cSWyon Bi 
11721a8d717cSWyon Bi 		if (reg != PORT_DIR_OUT)
11731a8d717cSWyon Bi 			continue;
11741a8d717cSWyon Bi 
11751a8d717cSWyon Bi 		ofnode_for_each_subnode(ep, port) {
11761a8d717cSWyon Bi 			ofnode _ep, _port, _ports;
11771a8d717cSWyon Bi 			uint phandle;
11781a8d717cSWyon Bi 
11791a8d717cSWyon Bi 			if (ofnode_read_u32(ep, "remote-endpoint", &phandle))
11801a8d717cSWyon Bi 				continue;
11811a8d717cSWyon Bi 
11821a8d717cSWyon Bi 			_ep = ofnode_get_by_phandle(phandle);
11831a8d717cSWyon Bi 			if (!ofnode_valid(_ep))
11841a8d717cSWyon Bi 				continue;
11851a8d717cSWyon Bi 
11861a8d717cSWyon Bi 			_port = ofnode_get_parent(_ep);
11871a8d717cSWyon Bi 			if (!ofnode_valid(_port))
11881a8d717cSWyon Bi 				continue;
11891a8d717cSWyon Bi 
11901a8d717cSWyon Bi 			_ports = ofnode_get_parent(_port);
11911a8d717cSWyon Bi 			if (!ofnode_valid(_ports))
11921a8d717cSWyon Bi 				continue;
11931a8d717cSWyon Bi 
11941a8d717cSWyon Bi 			node = ofnode_get_parent(_ports);
11951a8d717cSWyon Bi 			if (!ofnode_valid(node))
11961a8d717cSWyon Bi 				continue;
11971a8d717cSWyon Bi 
11981a8d717cSWyon Bi 			ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_BRIDGE,
11991a8d717cSWyon Bi 							  node, &dev);
12001a8d717cSWyon Bi 			if (!ret)
12011a8d717cSWyon Bi 				goto found;
12021a8d717cSWyon Bi 		}
12031a8d717cSWyon Bi 	}
12041a8d717cSWyon Bi 
12051a8d717cSWyon Bi 	return NULL;
12061a8d717cSWyon Bi 
12071a8d717cSWyon Bi found:
12081a8d717cSWyon Bi 	return (struct rockchip_bridge *)dev_get_driver_data(dev);
12091a8d717cSWyon Bi }
12101a8d717cSWyon Bi 
1211f8281ef0SWyon Bi static struct udevice *rockchip_of_find_connector(ofnode endpoint)
1212747dfc26SWyon Bi {
1213f8281ef0SWyon Bi 	ofnode ep, port, ports, conn;
1214f8281ef0SWyon Bi 	uint phandle;
1215f8281ef0SWyon Bi 	struct udevice *dev;
1216747dfc26SWyon Bi 	int ret;
1217747dfc26SWyon Bi 
1218f8281ef0SWyon Bi 	if (ofnode_read_u32(endpoint, "remote-endpoint", &phandle))
1219f8281ef0SWyon Bi 		return NULL;
1220f8281ef0SWyon Bi 
1221f8281ef0SWyon Bi 	ep = ofnode_get_by_phandle(phandle);
1222f8281ef0SWyon Bi 	if (!ofnode_valid(ep) || !ofnode_is_available(ep))
1223f8281ef0SWyon Bi 		return NULL;
1224f8281ef0SWyon Bi 
1225f8281ef0SWyon Bi 	port = ofnode_get_parent(ep);
1226747dfc26SWyon Bi 	if (!ofnode_valid(port))
1227747dfc26SWyon Bi 		return NULL;
1228747dfc26SWyon Bi 
1229f8281ef0SWyon Bi 	ports = ofnode_get_parent(port);
1230f8281ef0SWyon Bi 	if (!ofnode_valid(ports))
1231747dfc26SWyon Bi 		return NULL;
1232f8281ef0SWyon Bi 
1233f8281ef0SWyon Bi 	conn = ofnode_get_parent(ports);
1234f8281ef0SWyon Bi 	if (!ofnode_valid(conn) || !ofnode_is_available(conn))
1235f8281ef0SWyon Bi 		return NULL;
1236f8281ef0SWyon Bi 
1237f8281ef0SWyon Bi 	ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY, conn, &dev);
1238f8281ef0SWyon Bi 	if (ret)
1239f8281ef0SWyon Bi 		return NULL;
1240f8281ef0SWyon Bi 
1241f8281ef0SWyon Bi 	return dev;
1242747dfc26SWyon Bi }
1243747dfc26SWyon Bi 
12447cacd0a8SWyon Bi static struct rockchip_phy *rockchip_of_find_phy(struct udevice *dev)
12457cacd0a8SWyon Bi {
12467cacd0a8SWyon Bi 	struct udevice *phy_dev;
12477cacd0a8SWyon Bi 	int ret;
12487cacd0a8SWyon Bi 
12497cacd0a8SWyon Bi 	ret = uclass_get_device_by_phandle(UCLASS_PHY, dev, "phys", &phy_dev);
12507cacd0a8SWyon Bi 	if (ret)
12517cacd0a8SWyon Bi 		return NULL;
12527cacd0a8SWyon Bi 
12537cacd0a8SWyon Bi 	return (struct rockchip_phy *)dev_get_driver_data(phy_dev);
12547cacd0a8SWyon Bi }
12557cacd0a8SWyon Bi 
1256186f8572SMark Yao static int rockchip_display_probe(struct udevice *dev)
1257186f8572SMark Yao {
1258186f8572SMark Yao 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1259186f8572SMark Yao 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
1260186f8572SMark Yao 	const void *blob = gd->fdt_blob;
1261e2bce6e4SKever Yang 	int phandle;
1262186f8572SMark Yao 	struct udevice *crtc_dev, *conn_dev;
12632a48727aSAlgea Cao 	struct rockchip_crtc *crtc;
1264186f8572SMark Yao 	const struct rockchip_connector *conn;
12651a8d717cSWyon Bi 	struct rockchip_panel *panel = NULL;
12661a8d717cSWyon Bi 	struct rockchip_bridge *bridge = NULL;
12677cacd0a8SWyon Bi 	struct rockchip_phy *phy = NULL;
1268186f8572SMark Yao 	struct display_state *s;
1269186f8572SMark Yao 	const char *name;
1270186f8572SMark Yao 	int ret;
1271e2bce6e4SKever Yang 	ofnode node, route_node;
1272e2bce6e4SKever Yang 	struct device_node *port_node, *vop_node, *ep_node;
12732a48727aSAlgea Cao 	struct public_phy_data *data;
1274186f8572SMark Yao 
1275186f8572SMark Yao 	/* Before relocation we don't need to do anything */
1276186f8572SMark Yao 	if (!(gd->flags & GD_FLG_RELOC))
1277186f8572SMark Yao 		return 0;
12782a48727aSAlgea Cao 
12792a48727aSAlgea Cao 	data = malloc(sizeof(struct public_phy_data));
12802a48727aSAlgea Cao 	if (!data) {
12812a48727aSAlgea Cao 		printf("failed to alloc phy data\n");
12822a48727aSAlgea Cao 		return -ENOMEM;
12832a48727aSAlgea Cao 	}
12842a48727aSAlgea Cao 	data->phy_init = false;
12852a48727aSAlgea Cao 
12864b8c2ef1SMark Yao 	init_display_buffer(plat->base);
1287186f8572SMark Yao 
1288e2bce6e4SKever Yang 	route_node = dev_read_subnode(dev, "route");
1289e2bce6e4SKever Yang 	if (!ofnode_valid(route_node))
1290e2bce6e4SKever Yang 		return -ENODEV;
1291186f8572SMark Yao 
1292e2bce6e4SKever Yang 	ofnode_for_each_subnode(node, route_node) {
12931e44acfcSWyon Bi 		if (!ofnode_is_available(node))
12941e44acfcSWyon Bi 			continue;
1295e2bce6e4SKever Yang 		phandle = ofnode_read_u32_default(node, "connect", -1);
1296186f8572SMark Yao 		if (phandle < 0) {
1297e2bce6e4SKever Yang 			printf("Warn: can't find connect node's handle\n");
1298186f8572SMark Yao 			continue;
1299186f8572SMark Yao 		}
1300e2bce6e4SKever Yang 		ep_node = of_find_node_by_phandle(phandle);
1301e2bce6e4SKever Yang 		if (!ofnode_valid(np_to_ofnode(ep_node))) {
1302e2bce6e4SKever Yang 			printf("Warn: can't find endpoint node from phandle\n");
1303186f8572SMark Yao 			continue;
1304186f8572SMark Yao 		}
1305e2bce6e4SKever Yang 		port_node = of_get_parent(ep_node);
1306e2bce6e4SKever Yang 		if (!ofnode_valid(np_to_ofnode(port_node))) {
1307e2bce6e4SKever Yang 			printf("Warn: can't find port node from phandle\n");
1308186f8572SMark Yao 			continue;
1309186f8572SMark Yao 		}
1310e2bce6e4SKever Yang 		vop_node = of_get_parent(port_node);
1311e2bce6e4SKever Yang 		if (!ofnode_valid(np_to_ofnode(vop_node))) {
1312e2bce6e4SKever Yang 			printf("Warn: can't find crtc node from phandle\n");
1313e2bce6e4SKever Yang 			continue;
1314e2bce6e4SKever Yang 		}
1315e2bce6e4SKever Yang 		ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC,
1316e2bce6e4SKever Yang 						  np_to_ofnode(vop_node),
1317e2bce6e4SKever Yang 						  &crtc_dev);
1318186f8572SMark Yao 		if (ret) {
1319335adcb5SKever Yang 			printf("Warn: can't find crtc driver %d\n", ret);
1320186f8572SMark Yao 			continue;
1321186f8572SMark Yao 		}
13222a48727aSAlgea Cao 		crtc = (struct rockchip_crtc *)dev_get_driver_data(crtc_dev);
1323186f8572SMark Yao 
1324f8281ef0SWyon Bi 		conn_dev = rockchip_of_find_connector(np_to_ofnode(ep_node));
1325747dfc26SWyon Bi 		if (!conn_dev) {
1326e2bce6e4SKever Yang 			printf("Warn: can't find connect driver\n");
1327186f8572SMark Yao 			continue;
1328186f8572SMark Yao 		}
1329747dfc26SWyon Bi 
1330186f8572SMark Yao 		conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev);
1331186f8572SMark Yao 
13327cacd0a8SWyon Bi 		phy = rockchip_of_find_phy(conn_dev);
13337cacd0a8SWyon Bi 
13341a8d717cSWyon Bi 		bridge = rockchip_of_find_bridge(conn_dev);
13351a8d717cSWyon Bi 		if (bridge)
13361a8d717cSWyon Bi 			panel = rockchip_of_find_panel(bridge->dev);
13371a8d717cSWyon Bi 		else
13381a8d717cSWyon Bi 			panel = rockchip_of_find_panel(conn_dev);
13391a8d717cSWyon Bi 
1340186f8572SMark Yao 		s = malloc(sizeof(*s));
1341186f8572SMark Yao 		if (!s)
13424b8c2ef1SMark Yao 			continue;
1343186f8572SMark Yao 
1344186f8572SMark Yao 		memset(s, 0, sizeof(*s));
1345186f8572SMark Yao 
1346186f8572SMark Yao 		INIT_LIST_HEAD(&s->head);
134754fc9addSSandy Huang 		ret = ofnode_read_string_index(node, "logo,uboot", 0, &name);
134854fc9addSSandy Huang 		if (!ret)
134954fc9addSSandy Huang 			memcpy(s->ulogo_name, name, strlen(name));
135054fc9addSSandy Huang 		ret = ofnode_read_string_index(node, "logo,kernel", 0, &name);
135154fc9addSSandy Huang 		if (!ret)
135254fc9addSSandy Huang 			memcpy(s->klogo_name, name, strlen(name));
1353e2bce6e4SKever Yang 		ret = ofnode_read_string_index(node, "logo,mode", 0, &name);
1354186f8572SMark Yao 		if (!strcmp(name, "fullscreen"))
1355186f8572SMark Yao 			s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
1356186f8572SMark Yao 		else
1357186f8572SMark Yao 			s->logo_mode = ROCKCHIP_DISPLAY_CENTER;
1358e2bce6e4SKever Yang 		ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name);
1359186f8572SMark Yao 		if (!strcmp(name, "fullscreen"))
1360186f8572SMark Yao 			s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
1361186f8572SMark Yao 		else
1362186f8572SMark Yao 			s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER;
1363186f8572SMark Yao 
1364186f8572SMark Yao 		s->blob = blob;
13651a8d717cSWyon Bi 		s->panel_state.panel = panel;
1366747dfc26SWyon Bi 		s->conn_state.node = conn_dev->node;
1367186f8572SMark Yao 		s->conn_state.dev = conn_dev;
1368186f8572SMark Yao 		s->conn_state.connector = conn;
13697cacd0a8SWyon Bi 		s->conn_state.phy = phy;
13701a8d717cSWyon Bi 		s->conn_state.bridge = bridge;
13718a2a3a29SSandy Huang 		s->conn_state.overscan.left_margin = 100;
13728a2a3a29SSandy Huang 		s->conn_state.overscan.right_margin = 100;
13738a2a3a29SSandy Huang 		s->conn_state.overscan.top_margin = 100;
13748a2a3a29SSandy Huang 		s->conn_state.overscan.bottom_margin = 100;
1375e2bce6e4SKever Yang 		s->crtc_state.node = np_to_ofnode(vop_node);
1376186f8572SMark Yao 		s->crtc_state.dev = crtc_dev;
1377186f8572SMark Yao 		s->crtc_state.crtc = crtc;
1378e2bce6e4SKever Yang 		s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node));
1379e2bce6e4SKever Yang 		s->node = node;
13801a8d717cSWyon Bi 
13811a8d717cSWyon Bi 		if (bridge)
13821a8d717cSWyon Bi 			bridge->state = s;
13831a8d717cSWyon Bi 
13847cacd0a8SWyon Bi 		if (panel)
13857cacd0a8SWyon Bi 			panel->state = s;
13867cacd0a8SWyon Bi 
138767b9012cSSandy Huang 		get_crtc_mcu_mode(&s->crtc_state);
1388186f8572SMark Yao 
1389e2bce6e4SKever Yang 		if (connector_panel_init(s)) {
1390e2bce6e4SKever Yang 			printf("Warn: Failed to init panel drivers\n");
13914b8c2ef1SMark Yao 			free(s);
13924b8c2ef1SMark Yao 			continue;
13934b8c2ef1SMark Yao 		}
13944b8c2ef1SMark Yao 
13952a48727aSAlgea Cao 		if (connector_phy_init(s, data)) {
1396e2bce6e4SKever Yang 			printf("Warn: Failed to init phy drivers\n");
13974b8c2ef1SMark Yao 			free(s);
13984b8c2ef1SMark Yao 			continue;
13994b8c2ef1SMark Yao 		}
1400186f8572SMark Yao 		list_add_tail(&s->head, &rockchip_display_list);
1401186f8572SMark Yao 	}
1402186f8572SMark Yao 
14034b8c2ef1SMark Yao 	if (list_empty(&rockchip_display_list)) {
14044b8c2ef1SMark Yao 		printf("Failed to found available display route\n");
14054b8c2ef1SMark Yao 		return -ENODEV;
14064b8c2ef1SMark Yao 	}
14074b8c2ef1SMark Yao 
1408186f8572SMark Yao 	uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH;
1409186f8572SMark Yao 	uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT;
1410186f8572SMark Yao 	uc_priv->bpix = VIDEO_BPP32;
1411186f8572SMark Yao 
14124b8c2ef1SMark Yao 	#ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER
1413186f8572SMark Yao 	rockchip_show_fbbase(plat->base);
1414186f8572SMark Yao 	video_set_flush_dcache(dev, true);
14154b8c2ef1SMark Yao 	#endif
1416186f8572SMark Yao 
1417186f8572SMark Yao 	return 0;
14184b8c2ef1SMark Yao }
1419186f8572SMark Yao 
1420186f8572SMark Yao void rockchip_display_fixup(void *blob)
1421186f8572SMark Yao {
1422186f8572SMark Yao 	const struct rockchip_connector_funcs *conn_funcs;
1423186f8572SMark Yao 	const struct rockchip_crtc_funcs *crtc_funcs;
1424186f8572SMark Yao 	const struct rockchip_connector *conn;
1425186f8572SMark Yao 	const struct rockchip_crtc *crtc;
1426186f8572SMark Yao 	struct display_state *s;
1427694afdc8SKever Yang 	int offset;
142851619d03SKever Yang 	const struct device_node *np;
142951619d03SKever Yang 	const char *path;
1430186f8572SMark Yao 
1431186f8572SMark Yao 	if (!get_display_size())
1432186f8572SMark Yao 		return;
1433186f8572SMark Yao 
14345eb61944SSandy Huang 	if (fdt_node_offset_by_compatible(blob, 0, "rockchip,drm-logo") >= 0) {
14355eb61944SSandy Huang 		list_for_each_entry(s, &rockchip_display_list, head)
14365eb61944SSandy Huang 			load_bmp_logo(&s->logo, s->klogo_name);
143751619d03SKever Yang 		offset = fdt_update_reserved_memory(blob, "rockchip,drm-logo",
1438186f8572SMark Yao 						    (u64)memory_start,
1439186f8572SMark Yao 						    (u64)get_display_size());
14405eb61944SSandy Huang 		if (offset < 0)
14415eb61944SSandy Huang 			printf("failed to reserve drm-loader-logo memory\n");
14425eb61944SSandy Huang 	} else {
14435eb61944SSandy Huang 		printf("can't found rockchip,drm-logo, use rockchip,fb-logo\n");
1444694afdc8SKever Yang 		/* Compatible with rkfb display, only need reserve memory */
1445694afdc8SKever Yang 		offset = fdt_update_reserved_memory(blob, "rockchip,fb-logo",
1446694afdc8SKever Yang 						    (u64)memory_start,
14475eb61944SSandy Huang 						    MEMORY_POOL_SIZE);
1448694afdc8SKever Yang 		if (offset < 0)
14495eb61944SSandy Huang 			printf("failed to reserve fb-loader-logo memory\n");
14505eb61944SSandy Huang 		else
14515eb61944SSandy Huang 			list_for_each_entry(s, &rockchip_display_list, head)
14525eb61944SSandy Huang 				load_kernel_bmp_logo(&s->logo, s->klogo_name);
1453186f8572SMark Yao 		return;
1454186f8572SMark Yao 	}
1455186f8572SMark Yao 
1456186f8572SMark Yao 	list_for_each_entry(s, &rockchip_display_list, head) {
1457186f8572SMark Yao 		conn = s->conn_state.connector;
1458186f8572SMark Yao 		if (!conn)
1459186f8572SMark Yao 			continue;
1460186f8572SMark Yao 		conn_funcs = conn->funcs;
1461186f8572SMark Yao 		if (!conn_funcs) {
1462186f8572SMark Yao 			printf("failed to get exist connector\n");
1463186f8572SMark Yao 			continue;
1464186f8572SMark Yao 		}
1465186f8572SMark Yao 
1466186f8572SMark Yao 		crtc = s->crtc_state.crtc;
1467186f8572SMark Yao 		if (!crtc)
1468186f8572SMark Yao 			continue;
1469186f8572SMark Yao 
1470186f8572SMark Yao 		crtc_funcs = crtc->funcs;
1471186f8572SMark Yao 		if (!crtc_funcs) {
1472186f8572SMark Yao 			printf("failed to get exist crtc\n");
1473186f8572SMark Yao 			continue;
1474186f8572SMark Yao 		}
1475186f8572SMark Yao 
1476186f8572SMark Yao 		if (crtc_funcs->fixup_dts)
1477186f8572SMark Yao 			crtc_funcs->fixup_dts(s, blob);
1478186f8572SMark Yao 
1479186f8572SMark Yao 		if (conn_funcs->fixup_dts)
1480186f8572SMark Yao 			conn_funcs->fixup_dts(s, blob);
1481186f8572SMark Yao 
148251619d03SKever Yang 		np = ofnode_to_np(s->node);
148351619d03SKever Yang 		path = np->full_name;
148451619d03SKever Yang 		fdt_increase_size(blob, 0x400);
1485186f8572SMark Yao #define FDT_SET_U32(name, val) \
1486186f8572SMark Yao 		do_fixup_by_path_u32(blob, path, name, val, 1);
1487186f8572SMark Yao 
148851619d03SKever Yang 		offset = s->logo.offset + (u32)(unsigned long)s->logo.mem
148951619d03SKever Yang 			 - memory_start;
1490186f8572SMark Yao 		FDT_SET_U32("logo,offset", offset);
1491186f8572SMark Yao 		FDT_SET_U32("logo,width", s->logo.width);
1492186f8572SMark Yao 		FDT_SET_U32("logo,height", s->logo.height);
1493186f8572SMark Yao 		FDT_SET_U32("logo,bpp", s->logo.bpp);
1494186f8572SMark Yao 		FDT_SET_U32("logo,ymirror", s->logo.ymirror);
1495186f8572SMark Yao 		FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay);
1496186f8572SMark Yao 		FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay);
1497f11b858fSSandy Huang 		FDT_SET_U32("video,crtc_hsync_end", s->conn_state.mode.crtc_hsync_end);
1498f11b858fSSandy Huang 		FDT_SET_U32("video,crtc_vsync_end", s->conn_state.mode.crtc_vsync_end);
1499186f8572SMark Yao 		FDT_SET_U32("video,vrefresh",
1500186f8572SMark Yao 			    drm_mode_vrefresh(&s->conn_state.mode));
15018a2a3a29SSandy Huang 		FDT_SET_U32("video,flags", s->conn_state.mode.flags);
150294d85f7bSSandy Huang 		FDT_SET_U32("video,aspect_ratio", s->conn_state.mode.picture_aspect_ratio);
15038a2a3a29SSandy Huang 		FDT_SET_U32("overscan,left_margin", s->conn_state.overscan.left_margin);
15048a2a3a29SSandy Huang 		FDT_SET_U32("overscan,right_margin", s->conn_state.overscan.right_margin);
15058a2a3a29SSandy Huang 		FDT_SET_U32("overscan,top_margin", s->conn_state.overscan.top_margin);
15068a2a3a29SSandy Huang 		FDT_SET_U32("overscan,bottom_margin", s->conn_state.overscan.bottom_margin);
1507186f8572SMark Yao #undef FDT_SET_U32
1508186f8572SMark Yao 	}
1509186f8572SMark Yao }
1510186f8572SMark Yao 
1511186f8572SMark Yao int rockchip_display_bind(struct udevice *dev)
1512186f8572SMark Yao {
1513186f8572SMark Yao 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
1514186f8572SMark Yao 
15154b8c2ef1SMark Yao 	plat->size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE;
1516186f8572SMark Yao 
1517186f8572SMark Yao 	return 0;
1518186f8572SMark Yao }
1519186f8572SMark Yao 
1520186f8572SMark Yao static const struct udevice_id rockchip_display_ids[] = {
1521186f8572SMark Yao 	{ .compatible = "rockchip,display-subsystem" },
1522186f8572SMark Yao 	{ }
1523186f8572SMark Yao };
1524186f8572SMark Yao 
1525186f8572SMark Yao U_BOOT_DRIVER(rockchip_display) = {
1526186f8572SMark Yao 	.name	= "rockchip_display",
1527186f8572SMark Yao 	.id	= UCLASS_VIDEO,
1528186f8572SMark Yao 	.of_match = rockchip_display_ids,
1529186f8572SMark Yao 	.bind	= rockchip_display_bind,
1530186f8572SMark Yao 	.probe	= rockchip_display_probe,
1531186f8572SMark Yao };
15324b8c2ef1SMark Yao 
15334b8c2ef1SMark Yao static int do_rockchip_logo_show(cmd_tbl_t *cmdtp, int flag, int argc,
15344b8c2ef1SMark Yao 			char *const argv[])
15354b8c2ef1SMark Yao {
15364b8c2ef1SMark Yao 	if (argc != 1)
15374b8c2ef1SMark Yao 		return CMD_RET_USAGE;
15384b8c2ef1SMark Yao 
15394b8c2ef1SMark Yao 	rockchip_show_logo();
15404b8c2ef1SMark Yao 
15414b8c2ef1SMark Yao 	return 0;
15424b8c2ef1SMark Yao }
15434b8c2ef1SMark Yao 
15444b8c2ef1SMark Yao static int do_rockchip_show_bmp(cmd_tbl_t *cmdtp, int flag, int argc,
15454b8c2ef1SMark Yao 				char *const argv[])
15464b8c2ef1SMark Yao {
15474b8c2ef1SMark Yao 	if (argc != 2)
15484b8c2ef1SMark Yao 		return CMD_RET_USAGE;
15494b8c2ef1SMark Yao 
15504b8c2ef1SMark Yao 	rockchip_show_bmp(argv[1]);
15514b8c2ef1SMark Yao 
15524b8c2ef1SMark Yao 	return 0;
15534b8c2ef1SMark Yao }
15544b8c2ef1SMark Yao 
15554b8c2ef1SMark Yao U_BOOT_CMD(
15564b8c2ef1SMark Yao 	rockchip_show_logo, 1, 1, do_rockchip_logo_show,
15574b8c2ef1SMark Yao 	"load and display log from resource partition",
15584b8c2ef1SMark Yao 	NULL
15594b8c2ef1SMark Yao );
15604b8c2ef1SMark Yao 
15614b8c2ef1SMark Yao U_BOOT_CMD(
15624b8c2ef1SMark Yao 	rockchip_show_bmp, 2, 1, do_rockchip_show_bmp,
15634b8c2ef1SMark Yao 	"load and display bmp from resource partition",
15644b8c2ef1SMark Yao 	"    <bmp_name>"
15654b8c2ef1SMark Yao );
1566