1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2014 CompuLab, Ltd. <www.compulab.co.il>
4  *
5  * Authors: Igor Grinberg <grinberg@compulab.co.il>
6  */
7 
8 #include <common.h>
9 #include <bmp_layout.h>
10 #include <command.h>
11 #include <env.h>
12 #include <errno.h>
13 #include <fs.h>
14 #include <fdt_support.h>
15 #include <image.h>
16 #include <log.h>
17 #include <nand.h>
18 #include <sata.h>
19 #include <spi.h>
20 #include <spi_flash.h>
21 #include <splash.h>
22 #include <usb.h>
23 #include <asm/global_data.h>
24 
25 DECLARE_GLOBAL_DATA_PTR;
26 
27 #ifdef CONFIG_SPI_FLASH
28 static struct spi_flash *sf;
splash_sf_read_raw(u32 bmp_load_addr,int offset,size_t read_size)29 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
30 {
31 	if (!sf) {
32 		sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
33 				     CONFIG_SF_DEFAULT_CS,
34 				     CONFIG_SF_DEFAULT_SPEED,
35 				     CONFIG_SF_DEFAULT_MODE);
36 		if (!sf)
37 			return -ENODEV;
38 	}
39 
40 	return spi_flash_read(sf, offset, read_size, (void *)(uintptr_t)bmp_load_addr);
41 }
42 #else
splash_sf_read_raw(u32 bmp_load_addr,int offset,size_t read_size)43 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
44 {
45 	debug("%s: sf support not available\n", __func__);
46 	return -ENOSYS;
47 }
48 #endif
49 
50 #ifdef CONFIG_CMD_NAND
splash_nand_read_raw(u32 bmp_load_addr,int offset,size_t read_size)51 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
52 {
53 	struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
54 	return nand_read_skip_bad(mtd, offset,
55 				  &read_size, NULL,
56 				  mtd->size,
57 				  (u_char *)bmp_load_addr);
58 }
59 #else
splash_nand_read_raw(u32 bmp_load_addr,int offset,size_t read_size)60 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
61 {
62 	debug("%s: nand support not available\n", __func__);
63 	return -ENOSYS;
64 }
65 #endif
66 
splash_storage_read_raw(struct splash_location * location,u32 bmp_load_addr,size_t read_size)67 static int splash_storage_read_raw(struct splash_location *location,
68 			       u32 bmp_load_addr, size_t read_size)
69 {
70 	u32 offset;
71 
72 	if (!location)
73 		return -EINVAL;
74 
75 	offset = location->offset;
76 	switch (location->storage) {
77 	case SPLASH_STORAGE_NAND:
78 		return splash_nand_read_raw(bmp_load_addr, offset, read_size);
79 	case SPLASH_STORAGE_SF:
80 		return splash_sf_read_raw(bmp_load_addr, offset, read_size);
81 	default:
82 		printf("Unknown splash location\n");
83 	}
84 
85 	return -EINVAL;
86 }
87 
splash_load_raw(struct splash_location * location,u32 bmp_load_addr)88 static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
89 {
90 	struct bmp_header *bmp_hdr;
91 	int res;
92 	size_t bmp_size, bmp_header_size = sizeof(struct bmp_header);
93 
94 	if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp)
95 		goto splash_address_too_high;
96 
97 	res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
98 	if (res < 0)
99 		return res;
100 
101 	bmp_hdr = (struct bmp_header *)(uintptr_t)bmp_load_addr;
102 	bmp_size = le32_to_cpu(bmp_hdr->file_size);
103 
104 	if (bmp_load_addr + bmp_size >= gd->start_addr_sp)
105 		goto splash_address_too_high;
106 
107 	return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
108 
109 splash_address_too_high:
110 	printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
111 
112 	return -EFAULT;
113 }
114 
splash_select_fs_dev(struct splash_location * location)115 static int splash_select_fs_dev(struct splash_location *location)
116 {
117 	int res;
118 
119 	switch (location->storage) {
120 	case SPLASH_STORAGE_MMC:
121 		res = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY);
122 		break;
123 	case SPLASH_STORAGE_USB:
124 		res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
125 		break;
126 	case SPLASH_STORAGE_SATA:
127 		res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
128 		break;
129 	case SPLASH_STORAGE_NAND:
130 		if (location->ubivol != NULL)
131 			res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
132 		else
133 			res = -ENODEV;
134 		break;
135 	default:
136 		printf("Error: unsupported location storage.\n");
137 		return -ENODEV;
138 	}
139 
140 	if (res)
141 		printf("Error: could not access storage.\n");
142 
143 	return res;
144 }
145 
146 #ifdef CONFIG_USB_STORAGE
splash_init_usb(void)147 static int splash_init_usb(void)
148 {
149 	int err;
150 
151 	err = usb_init();
152 	if (err)
153 		return err;
154 
155 #ifndef CONFIG_DM_USB
156 	err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
157 #endif
158 
159 	return err;
160 }
161 #else
splash_init_usb(void)162 static inline int splash_init_usb(void)
163 {
164 	printf("Cannot load splash image: no USB support\n");
165 	return -ENOSYS;
166 }
167 #endif
168 
169 #ifdef CONFIG_SATA
splash_init_sata(void)170 static int splash_init_sata(void)
171 {
172 	return sata_probe(0);
173 }
174 #else
splash_init_sata(void)175 static inline int splash_init_sata(void)
176 {
177 	printf("Cannot load splash image: no SATA support\n");
178 	return -ENOSYS;
179 }
180 #endif
181 
182 #ifdef CONFIG_CMD_UBIFS
splash_mount_ubifs(struct splash_location * location)183 static int splash_mount_ubifs(struct splash_location *location)
184 {
185 	int res;
186 	char cmd[32];
187 
188 	sprintf(cmd, "ubi part %s", location->mtdpart);
189 	res = run_command(cmd, 0);
190 	if (res)
191 		return res;
192 
193 	sprintf(cmd, "ubifsmount %s", location->ubivol);
194 	res = run_command(cmd, 0);
195 
196 	return res;
197 }
198 
splash_umount_ubifs(void)199 static inline int splash_umount_ubifs(void)
200 {
201 	return run_command("ubifsumount", 0);
202 }
203 #else
splash_mount_ubifs(struct splash_location * location)204 static inline int splash_mount_ubifs(struct splash_location *location)
205 {
206 	printf("Cannot load splash image: no UBIFS support\n");
207 	return -ENOSYS;
208 }
209 
splash_umount_ubifs(void)210 static inline int splash_umount_ubifs(void)
211 {
212 	printf("Cannot unmount UBIFS: no UBIFS support\n");
213 	return -ENOSYS;
214 }
215 #endif
216 
217 #define SPLASH_SOURCE_DEFAULT_FILE_NAME		"splash.bmp"
218 
splash_load_fs(struct splash_location * location,u32 bmp_load_addr)219 static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
220 {
221 	int res = 0;
222 	loff_t bmp_size;
223 	loff_t actread;
224 	char *splash_file;
225 
226 	splash_file = env_get("splashfile");
227 	if (!splash_file)
228 		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
229 
230 	if (location->storage == SPLASH_STORAGE_USB)
231 		res = splash_init_usb();
232 
233 	if (location->storage == SPLASH_STORAGE_SATA)
234 		res = splash_init_sata();
235 
236 	if (location->ubivol != NULL)
237 		res = splash_mount_ubifs(location);
238 
239 	if (res)
240 		return res;
241 
242 	res = splash_select_fs_dev(location);
243 	if (res)
244 		goto out;
245 
246 	res = fs_size(splash_file, &bmp_size);
247 	if (res) {
248 		printf("Error (%d): cannot determine file size\n", res);
249 		goto out;
250 	}
251 
252 	if (bmp_load_addr + bmp_size >= gd->start_addr_sp) {
253 		printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
254 		res = -EFAULT;
255 		goto out;
256 	}
257 
258 	splash_select_fs_dev(location);
259 	res = fs_read(splash_file, bmp_load_addr, 0, 0, &actread);
260 
261 out:
262 	if (location->ubivol != NULL)
263 		splash_umount_ubifs();
264 
265 	return res;
266 }
267 
268 /**
269  * select_splash_location - return the splash location based on board support
270  *			    and env variable "splashsource".
271  *
272  * @locations:		An array of supported splash locations.
273  * @size:		Size of splash_locations array.
274  *
275  * @return: If a null set of splash locations is given, or
276  *	    splashsource env variable is set to unsupported value
277  *			return NULL.
278  *	    If splashsource env variable is not defined
279  *			return the first entry in splash_locations as default.
280  *	    If splashsource env variable contains a supported value
281  *			return the location selected by splashsource.
282  */
select_splash_location(struct splash_location * locations,uint size)283 static struct splash_location *select_splash_location(
284 			    struct splash_location *locations, uint size)
285 {
286 	int i;
287 	char *env_splashsource;
288 
289 	if (!locations || size == 0)
290 		return NULL;
291 
292 	env_splashsource = env_get("splashsource");
293 	if (env_splashsource == NULL)
294 		return &locations[0];
295 
296 	for (i = 0; i < size; i++) {
297 		if (!strcmp(locations[i].name, env_splashsource))
298 			return &locations[i];
299 	}
300 
301 	printf("splashsource env variable set to unsupported value\n");
302 	return NULL;
303 }
304 
305 #ifdef CONFIG_FIT
splash_load_fit(struct splash_location * location,u32 bmp_load_addr)306 static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
307 {
308 	int res;
309 	int node_offset;
310 	const char *splash_file;
311 	const void *internal_splash_data;
312 	size_t internal_splash_size;
313 	int external_splash_addr;
314 	int external_splash_size;
315 	bool is_splash_external = false;
316 	struct image_header *img_header;
317 	const u32 *fit_header;
318 	u32 fit_size;
319 	const size_t header_size = sizeof(struct image_header);
320 
321 	/* Read in image header */
322 	res = splash_storage_read_raw(location, bmp_load_addr, header_size);
323 	if (res < 0)
324 		return res;
325 
326 	img_header = (struct image_header *)bmp_load_addr;
327 	if (image_get_magic(img_header) != FDT_MAGIC) {
328 		printf("Could not find FDT magic\n");
329 		return -EINVAL;
330 	}
331 
332 	fit_size = fdt_totalsize(img_header);
333 
334 	/* Read in entire FIT */
335 	fit_header = (const u32 *)(bmp_load_addr + header_size);
336 	res = splash_storage_read_raw(location, (u32)fit_header, fit_size);
337 	if (res < 0)
338 		return res;
339 
340 	res = fit_check_format(fit_header, IMAGE_SIZE_INVAL);
341 	if (res) {
342 		debug("Could not find valid FIT image\n");
343 		return res;
344 	}
345 
346 	/* Get the splash image node */
347 	splash_file = env_get("splashfile");
348 	if (!splash_file)
349 		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
350 
351 	node_offset = fit_image_get_node(fit_header, splash_file);
352 	if (node_offset < 0) {
353 		debug("Could not find splash image '%s' in FIT\n",
354 		      splash_file);
355 		return -ENOENT;
356 	}
357 
358 	/* Extract the splash data from FIT */
359 	/* 1. Test if splash is in FIT internal data. */
360 	if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size))
361 		memmove((void *)bmp_load_addr, internal_splash_data, internal_splash_size);
362 	/* 2. Test if splash is in FIT external data with fixed position. */
363 	else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr))
364 		is_splash_external = true;
365 	/* 3. Test if splash is in FIT external data with offset. */
366 	else if (!fit_image_get_data_offset(fit_header, node_offset, &external_splash_addr)) {
367 		/* Align data offset to 4-byte boundary */
368 		fit_size = ALIGN(fdt_totalsize(fit_header), 4);
369 		/* External splash offset means the offset by end of FIT header */
370 		external_splash_addr += location->offset + fit_size;
371 		is_splash_external = true;
372 	} else {
373 		printf("Failed to get splash image from FIT\n");
374 		return -ENODATA;
375 	}
376 
377 	if (is_splash_external) {
378 		res = fit_image_get_data_size(fit_header, node_offset, &external_splash_size);
379 		if (res < 0) {
380 			printf("Failed to get size of splash image (err=%d)\n", res);
381 			return res;
382 		}
383 
384 		/* Read in the splash data */
385 		location->offset = external_splash_addr;
386 		res = splash_storage_read_raw(location, bmp_load_addr, external_splash_size);
387 		if (res < 0)
388 			return res;
389 	}
390 
391 	return 0;
392 }
393 #endif /* CONFIG_FIT */
394 
395 /**
396  * splash_source_load - load splash image from a supported location.
397  *
398  * Select a splash image location based on the value of splashsource environment
399  * variable and the board supported splash source locations, and load a
400  * splashimage to the address pointed to by splashimage environment variable.
401  *
402  * @locations:		An array of supported splash locations.
403  * @size:		Size of splash_locations array.
404  *
405  * @return: 0 on success, negative value on failure.
406  */
splash_source_load(struct splash_location * locations,uint size)407 int splash_source_load(struct splash_location *locations, uint size)
408 {
409 	struct splash_location *splash_location;
410 	char *env_splashimage_value;
411 	u32 bmp_load_addr;
412 
413 	env_splashimage_value = env_get("splashimage");
414 	if (env_splashimage_value == NULL)
415 		return -ENOENT;
416 
417 	bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
418 	if (bmp_load_addr == 0) {
419 		printf("Error: bad splashimage address specified\n");
420 		return -EFAULT;
421 	}
422 
423 	splash_location = select_splash_location(locations, size);
424 	if (!splash_location)
425 		return -EINVAL;
426 
427 	if (splash_location->flags == SPLASH_STORAGE_RAW)
428 		return splash_load_raw(splash_location, bmp_load_addr);
429 	else if (splash_location->flags == SPLASH_STORAGE_FS)
430 		return splash_load_fs(splash_location, bmp_load_addr);
431 #ifdef CONFIG_FIT
432 	else if (splash_location->flags == SPLASH_STORAGE_FIT)
433 		return splash_load_fit(splash_location, bmp_load_addr);
434 #endif
435 	return -EINVAL;
436 }
437