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