xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_spl_display.c (revision 690e9ed17aeae22edefd790be3aa69d5fb401bae)
1*690e9ed1SSandy Huang /*
2*690e9ed1SSandy Huang  * (C) Copyright 2023 Rockchip Electronics Co., Ltd
3*690e9ed1SSandy Huang  *
4*690e9ed1SSandy Huang  * SPDX-License-Identifier:	GPL-2.0+
5*690e9ed1SSandy Huang  */
6*690e9ed1SSandy Huang 
7*690e9ed1SSandy Huang #include <common.h>
8*690e9ed1SSandy Huang #include <asm/io.h>
9*690e9ed1SSandy Huang #include <malloc.h>
10*690e9ed1SSandy Huang #include <mp_boot.h>
11*690e9ed1SSandy Huang #include <spl.h>
12*690e9ed1SSandy Huang #include <part.h>
13*690e9ed1SSandy Huang #include <drm_modes.h>
14*690e9ed1SSandy Huang #include <spl_display.h>
15*690e9ed1SSandy Huang #include <linux/hdmi.h>
16*690e9ed1SSandy Huang 
17*690e9ed1SSandy Huang #include "rockchip_display.h"
18*690e9ed1SSandy Huang #include "rockchip_crtc.h"
19*690e9ed1SSandy Huang #include "rockchip_connector.h"
20*690e9ed1SSandy Huang #include "rockchip_phy.h"
21*690e9ed1SSandy Huang 
22*690e9ed1SSandy Huang static struct base2_info base_parameter;
23*690e9ed1SSandy Huang 
24*690e9ed1SSandy Huang struct display_state *rockchip_spl_display_drv_probe(void)
25*690e9ed1SSandy Huang {
26*690e9ed1SSandy Huang 	struct display_state *state = malloc(sizeof(struct display_state));
27*690e9ed1SSandy Huang 	if (!state)
28*690e9ed1SSandy Huang 		return NULL;
29*690e9ed1SSandy Huang 
30*690e9ed1SSandy Huang 	memset(state, 0, sizeof(*state));
31*690e9ed1SSandy Huang 
32*690e9ed1SSandy Huang 	rockchip_spl_vop_probe(&state->crtc_state);
33*690e9ed1SSandy Huang 	rockchip_spl_dw_hdmi_probe(&state->conn_state);
34*690e9ed1SSandy Huang 	inno_spl_hdmi_phy_probe(state);
35*690e9ed1SSandy Huang 
36*690e9ed1SSandy Huang 	return state;
37*690e9ed1SSandy Huang }
38*690e9ed1SSandy Huang 
39*690e9ed1SSandy Huang static int rockchip_spl_display_init(struct display_state *state)
40*690e9ed1SSandy Huang {
41*690e9ed1SSandy Huang 	struct crtc_state *crtc_state = &state->crtc_state;
42*690e9ed1SSandy Huang 	struct connector_state *conn_state = &state->conn_state;
43*690e9ed1SSandy Huang 	struct rockchip_connector *conn = conn_state->connector;
44*690e9ed1SSandy Huang 	const struct rockchip_crtc *crtc = crtc_state->crtc;
45*690e9ed1SSandy Huang 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
46*690e9ed1SSandy Huang 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
47*690e9ed1SSandy Huang 	struct drm_display_mode *mode = &state->conn_state.mode;
48*690e9ed1SSandy Huang 	int ret = 0;
49*690e9ed1SSandy Huang 
50*690e9ed1SSandy Huang 	if (!crtc_funcs) {
51*690e9ed1SSandy Huang 		printf("failed to find crtc functions\n");
52*690e9ed1SSandy Huang 		return -ENXIO;
53*690e9ed1SSandy Huang 	}
54*690e9ed1SSandy Huang 
55*690e9ed1SSandy Huang 	if (crtc_funcs->preinit) {
56*690e9ed1SSandy Huang 		ret = crtc_funcs->preinit(state);
57*690e9ed1SSandy Huang 		if (ret)
58*690e9ed1SSandy Huang 			return ret;
59*690e9ed1SSandy Huang 	}
60*690e9ed1SSandy Huang 
61*690e9ed1SSandy Huang 	rockchip_display_make_crc32_table();
62*690e9ed1SSandy Huang 	if (conn_funcs->pre_init) {
63*690e9ed1SSandy Huang 		ret = conn_funcs->pre_init(conn, state);
64*690e9ed1SSandy Huang 		if (ret)
65*690e9ed1SSandy Huang 			return ret;
66*690e9ed1SSandy Huang 	}
67*690e9ed1SSandy Huang 
68*690e9ed1SSandy Huang 	if (conn_funcs->init) {
69*690e9ed1SSandy Huang 		ret = conn_funcs->init(conn, state);
70*690e9ed1SSandy Huang 		if (ret)
71*690e9ed1SSandy Huang 			goto deinit;
72*690e9ed1SSandy Huang 	}
73*690e9ed1SSandy Huang 
74*690e9ed1SSandy Huang 	if (conn->phy)
75*690e9ed1SSandy Huang 		rockchip_phy_init(conn->phy);
76*690e9ed1SSandy Huang 
77*690e9ed1SSandy Huang 	if (conn_funcs->detect) {
78*690e9ed1SSandy Huang 		conn->hpd = conn_funcs->detect(conn, state);
79*690e9ed1SSandy Huang 		if (!conn->hpd)
80*690e9ed1SSandy Huang 			goto deinit;
81*690e9ed1SSandy Huang 	}
82*690e9ed1SSandy Huang 
83*690e9ed1SSandy Huang 	if (conn_funcs->get_timing) {
84*690e9ed1SSandy Huang 		ret = conn_funcs->get_timing(conn, state);
85*690e9ed1SSandy Huang 		if (ret)
86*690e9ed1SSandy Huang 			goto deinit;
87*690e9ed1SSandy Huang 	}
88*690e9ed1SSandy Huang 
89*690e9ed1SSandy Huang 	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
90*690e9ed1SSandy Huang 	if (crtc_funcs->init) {
91*690e9ed1SSandy Huang 		ret = crtc_funcs->init(state);
92*690e9ed1SSandy Huang 		if (ret)
93*690e9ed1SSandy Huang 			goto deinit;
94*690e9ed1SSandy Huang 	}
95*690e9ed1SSandy Huang 
96*690e9ed1SSandy Huang 	return 0;
97*690e9ed1SSandy Huang 
98*690e9ed1SSandy Huang deinit:
99*690e9ed1SSandy Huang 	rockchip_connector_deinit(state);
100*690e9ed1SSandy Huang 	return ret;
101*690e9ed1SSandy Huang }
102*690e9ed1SSandy Huang 
103*690e9ed1SSandy Huang static int rockchip_spl_display_post_enable(struct display_state *state)
104*690e9ed1SSandy Huang {
105*690e9ed1SSandy Huang 	struct crtc_state *crtc_state = &state->crtc_state;
106*690e9ed1SSandy Huang 	struct connector_state *conn_state = &state->conn_state;
107*690e9ed1SSandy Huang 	struct rockchip_connector *conn = conn_state->connector;
108*690e9ed1SSandy Huang 	const struct rockchip_crtc *crtc = crtc_state->crtc;
109*690e9ed1SSandy Huang 	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
110*690e9ed1SSandy Huang 	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
111*690e9ed1SSandy Huang 
112*690e9ed1SSandy Huang 	if (crtc_funcs->enable)
113*690e9ed1SSandy Huang 		crtc_funcs->enable(state);
114*690e9ed1SSandy Huang 	state->crtc_state.crtc->active = true;
115*690e9ed1SSandy Huang 
116*690e9ed1SSandy Huang 	if (conn_funcs->enable)
117*690e9ed1SSandy Huang 		conn_funcs->enable(conn, state);
118*690e9ed1SSandy Huang 
119*690e9ed1SSandy Huang 	return 0;
120*690e9ed1SSandy Huang }
121*690e9ed1SSandy Huang 
122*690e9ed1SSandy Huang static void rockchip_spl_display_transmit_info_to_uboot(struct display_state *state)
123*690e9ed1SSandy Huang {
124*690e9ed1SSandy Huang 	struct connector_state *conn_state = &state->conn_state;
125*690e9ed1SSandy Huang 	struct spl_display_info *spl_disp_info = (struct spl_display_info *)CONFIG_SPL_VIDEO_BUF;
126*690e9ed1SSandy Huang 
127*690e9ed1SSandy Huang 	/* transmit mode and bus_format to uboot */
128*690e9ed1SSandy Huang 	memcpy(&spl_disp_info->mode, &conn_state->mode, sizeof(conn_state->mode));
129*690e9ed1SSandy Huang 	spl_disp_info->bus_format = state->conn_state.bus_format;
130*690e9ed1SSandy Huang 	spl_disp_info->enabled = 1;
131*690e9ed1SSandy Huang 	flush_dcache_all();
132*690e9ed1SSandy Huang }
133*690e9ed1SSandy Huang 
134*690e9ed1SSandy Huang int spl_init_display(struct task_data *data)
135*690e9ed1SSandy Huang {
136*690e9ed1SSandy Huang 	struct display_state *state = NULL;
137*690e9ed1SSandy Huang 	struct drm_display_mode *mode;
138*690e9ed1SSandy Huang 	int ret = 0;
139*690e9ed1SSandy Huang 
140*690e9ed1SSandy Huang 	state = rockchip_spl_display_drv_probe();
141*690e9ed1SSandy Huang 	if (!state) {
142*690e9ed1SSandy Huang 		printf("rockchip_spl_display_drv_probe failed\n");
143*690e9ed1SSandy Huang 		return -1;
144*690e9ed1SSandy Huang 	}
145*690e9ed1SSandy Huang 
146*690e9ed1SSandy Huang 	ret = rockchip_spl_display_init(state);
147*690e9ed1SSandy Huang 	if (ret) {
148*690e9ed1SSandy Huang 		printf("rockchip_spl_display_init failed ret:%d\n", ret);
149*690e9ed1SSandy Huang 		return  -1;
150*690e9ed1SSandy Huang 	}
151*690e9ed1SSandy Huang 
152*690e9ed1SSandy Huang 	if (!state->conn_state.connector->hpd) {
153*690e9ed1SSandy Huang 		printf("HDMI is unplug and exit\n");
154*690e9ed1SSandy Huang 		return 0;
155*690e9ed1SSandy Huang 	}
156*690e9ed1SSandy Huang 
157*690e9ed1SSandy Huang 	ret = rockchip_spl_display_post_enable(state);
158*690e9ed1SSandy Huang 	if (ret) {
159*690e9ed1SSandy Huang 		printf("rockchip_spl_display_post_enable failed ret:%d\n", ret);
160*690e9ed1SSandy Huang 		return -1;
161*690e9ed1SSandy Huang 	}
162*690e9ed1SSandy Huang 
163*690e9ed1SSandy Huang 	rockchip_spl_display_transmit_info_to_uboot(state);
164*690e9ed1SSandy Huang 
165*690e9ed1SSandy Huang 	mode = &state->conn_state.mode;
166*690e9ed1SSandy Huang 	printf("SPL enable hdmi, detailed mode clock %u kHz, flags[%x]\n"
167*690e9ed1SSandy Huang 	       "    H: %04d %04d %04d %04d\n"
168*690e9ed1SSandy Huang 	       "    V: %04d %04d %04d %04d\n"
169*690e9ed1SSandy Huang 	       "bus_format: %x\n",
170*690e9ed1SSandy Huang 	       mode->clock, mode->flags,
171*690e9ed1SSandy Huang 	       mode->hdisplay, mode->hsync_start,
172*690e9ed1SSandy Huang 	       mode->hsync_end, mode->htotal,
173*690e9ed1SSandy Huang 	       mode->vdisplay, mode->vsync_start,
174*690e9ed1SSandy Huang 	       mode->vsync_end, mode->vtotal,
175*690e9ed1SSandy Huang 	       state->conn_state.bus_format);
176*690e9ed1SSandy Huang 
177*690e9ed1SSandy Huang 	return ret;
178*690e9ed1SSandy Huang }
179*690e9ed1SSandy Huang 
180*690e9ed1SSandy Huang struct base2_disp_info *rockchip_get_disp_info(int type, int id)
181*690e9ed1SSandy Huang {
182*690e9ed1SSandy Huang 	struct base2_disp_info *disp_info;
183*690e9ed1SSandy Huang 	struct base2_disp_header *disp_header;
184*690e9ed1SSandy Huang 	int i = 0, offset = -1;
185*690e9ed1SSandy Huang 	u32 crc_val;
186*690e9ed1SSandy Huang 	u32 base2_length;
187*690e9ed1SSandy Huang 	void *base_parameter_addr = (void *)&base_parameter;
188*690e9ed1SSandy Huang #ifdef CONFIG_MP_BOOT
189*690e9ed1SSandy Huang 	void *bp_addr = (void *)CONFIG_SPL_VIDEO_BUF;
190*690e9ed1SSandy Huang 	ulong ret;
191*690e9ed1SSandy Huang 
192*690e9ed1SSandy Huang 	/* make sure the baseparameter is ready */
193*690e9ed1SSandy Huang 	ret = mpb_post(6);
194*690e9ed1SSandy Huang 	printf("SPL read baseparameter %s\n", ret < 0 ? "failed" : "success");
195*690e9ed1SSandy Huang 	memcpy(&base_parameter, bp_addr, sizeof(base_parameter));
196*690e9ed1SSandy Huang #endif
197*690e9ed1SSandy Huang 	for (i = 0; i < 8; i++) {
198*690e9ed1SSandy Huang 		disp_header = &base_parameter.disp_header[i];
199*690e9ed1SSandy Huang 		if (disp_header->connector_type == type &&
200*690e9ed1SSandy Huang 		    disp_header->connector_id == id) {
201*690e9ed1SSandy Huang 			printf("disp info %d, type:%d, id:%d\n", i, type, id);
202*690e9ed1SSandy Huang 			offset = disp_header->offset;
203*690e9ed1SSandy Huang 			break;
204*690e9ed1SSandy Huang 		}
205*690e9ed1SSandy Huang 	}
206*690e9ed1SSandy Huang 
207*690e9ed1SSandy Huang 	if (offset < 0)
208*690e9ed1SSandy Huang 		return NULL;
209*690e9ed1SSandy Huang 	disp_info = base_parameter_addr + offset;
210*690e9ed1SSandy Huang 	if (disp_info->screen_info[0].type != type ||
211*690e9ed1SSandy Huang 	    disp_info->screen_info[0].id != id) {
212*690e9ed1SSandy Huang 		printf("base2_disp_info couldn't be found, screen_info type[%d] or id[%d] mismatched\n",
213*690e9ed1SSandy Huang 		       disp_info->screen_info[0].type,
214*690e9ed1SSandy Huang 		       disp_info->screen_info[0].id);
215*690e9ed1SSandy Huang 		return NULL;
216*690e9ed1SSandy Huang 	}
217*690e9ed1SSandy Huang 
218*690e9ed1SSandy Huang 	if (strncasecmp(disp_info->disp_head_flag, "DISP", 4))
219*690e9ed1SSandy Huang 		return NULL;
220*690e9ed1SSandy Huang 
221*690e9ed1SSandy Huang 	if (base_parameter.major_version == 3 && base_parameter.minor_version == 0) {
222*690e9ed1SSandy Huang 		crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info,
223*690e9ed1SSandy Huang 						      sizeof(struct base2_disp_info) - 4);
224*690e9ed1SSandy Huang 		if (crc_val != disp_info->crc2) {
225*690e9ed1SSandy Huang 			printf("error: connector type[%d], id[%d] disp info crc2 check error\n",
226*690e9ed1SSandy Huang 			       type, id);
227*690e9ed1SSandy Huang 			return NULL;
228*690e9ed1SSandy Huang 		}
229*690e9ed1SSandy Huang 	} else {
230*690e9ed1SSandy Huang 		base2_length = sizeof(struct base2_disp_info) - sizeof(struct csc_info) -
231*690e9ed1SSandy Huang 			       sizeof(struct acm_data) - 10 * 1024 - 4;
232*690e9ed1SSandy Huang 		crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info, base2_length - 4);
233*690e9ed1SSandy Huang 		if (crc_val != disp_info->crc) {
234*690e9ed1SSandy Huang 			printf("error: connector type[%d], id[%d] disp info crc check error\n",
235*690e9ed1SSandy Huang 			       type, id);
236*690e9ed1SSandy Huang 			return NULL;
237*690e9ed1SSandy Huang 		}
238*690e9ed1SSandy Huang 	}
239*690e9ed1SSandy Huang 
240*690e9ed1SSandy Huang 	return disp_info;
241*690e9ed1SSandy Huang }
242*690e9ed1SSandy Huang 
243*690e9ed1SSandy Huang int spl_load_baseparamter(struct task_data *data)
244*690e9ed1SSandy Huang {
245*690e9ed1SSandy Huang 	struct spl_load_info *info = &data->info;
246*690e9ed1SSandy Huang 	ulong addr = CONFIG_SPL_VIDEO_BUF;
247*690e9ed1SSandy Huang 	disk_partition_t part;
248*690e9ed1SSandy Huang 
249*690e9ed1SSandy Huang 	debug("== Baseparam: start\n");
250*690e9ed1SSandy Huang 
251*690e9ed1SSandy Huang 	if (part_get_info_by_name(info->dev, "baseparameter", &part) < 0) {
252*690e9ed1SSandy Huang 		printf("No baseparameter partition\n");
253*690e9ed1SSandy Huang 		return -ENOENT;
254*690e9ed1SSandy Huang 	} else {
255*690e9ed1SSandy Huang 		if (info->read(info, part.start, part.size, (void *)addr) != part.size)
256*690e9ed1SSandy Huang 			return -EIO;
257*690e9ed1SSandy Huang 		else
258*690e9ed1SSandy Huang 			flush_dcache_range(addr, addr + part.size * info->bl_len);
259*690e9ed1SSandy Huang 	}
260*690e9ed1SSandy Huang 
261*690e9ed1SSandy Huang 	debug("== Baseparam: load OK\n");
262*690e9ed1SSandy Huang 
263*690e9ed1SSandy Huang 	return 0;
264*690e9ed1SSandy Huang }
265*690e9ed1SSandy Huang 
266