Blame view

common/splash_source.c 10.8 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
2
3
4
5
  /*
   * (C) Copyright 2014 CompuLab, Ltd. <www.compulab.co.il>
   *
   * Authors: Igor Grinberg <grinberg@compulab.co.il>
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
6
7
8
   */
  
  #include <common.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
9
  #include <bmp_layout.h>
288b29e44   Simon Glass   common: Move comm...
10
  #include <command.h>
7b51b576d   Simon Glass   env: Move env_get...
11
  #include <env.h>
6947e3f56   Nikita Kiryanov   compulab: splash:...
12
  #include <errno.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
13
  #include <fs.h>
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
14
  #include <fdt_support.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
15
16
17
  #include <image.h>
  #include <nand.h>
  #include <sata.h>
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
18
  #include <spi.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
19
20
  #include <spi_flash.h>
  #include <splash.h>
9bb4e9474   Nikita Kiryanov   splash_source: ad...
21
  #include <usb.h>
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
22
23
  
  DECLARE_GLOBAL_DATA_PTR;
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
24
25
  #ifdef CONFIG_SPI_FLASH
  static struct spi_flash *sf;
bcbb6448b   Nikita Kiryanov   splash_source: re...
26
  static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
27
28
29
30
31
32
33
34
35
36
37
38
39
  {
  	if (!sf) {
  		sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
  				     CONFIG_SF_DEFAULT_CS,
  				     CONFIG_SF_DEFAULT_SPEED,
  				     CONFIG_SF_DEFAULT_MODE);
  		if (!sf)
  			return -ENODEV;
  	}
  
  	return spi_flash_read(sf, offset, read_size, (void *)bmp_load_addr);
  }
  #else
bcbb6448b   Nikita Kiryanov   splash_source: re...
40
  static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
41
42
43
44
45
46
  {
  	debug("%s: sf support not available
  ", __func__);
  	return -ENOSYS;
  }
  #endif
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
47
  #ifdef CONFIG_CMD_NAND
bcbb6448b   Nikita Kiryanov   splash_source: re...
48
  static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
49
  {
edba8cc4f   Grygorii Strashko   common: use get_n...
50
51
  	struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
  	return nand_read_skip_bad(mtd, offset,
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
52
  				  &read_size, NULL,
edba8cc4f   Grygorii Strashko   common: use get_n...
53
  				  mtd->size,
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
54
55
56
  				  (u_char *)bmp_load_addr);
  }
  #else
bcbb6448b   Nikita Kiryanov   splash_source: re...
57
  static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
58
59
60
61
62
63
  {
  	debug("%s: nand support not available
  ", __func__);
  	return -ENOSYS;
  }
  #endif
bcbb6448b   Nikita Kiryanov   splash_source: re...
64
  static int splash_storage_read_raw(struct splash_location *location,
fd29dd554   Nikita Kiryanov   compulab: splash:...
65
  			       u32 bmp_load_addr, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
66
  {
fd29dd554   Nikita Kiryanov   compulab: splash:...
67
68
69
70
71
72
73
74
  	u32 offset;
  
  	if (!location)
  		return -EINVAL;
  
  	offset = location->offset;
  	switch (location->storage) {
  	case SPLASH_STORAGE_NAND:
bcbb6448b   Nikita Kiryanov   splash_source: re...
75
  		return splash_nand_read_raw(bmp_load_addr, offset, read_size);
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
76
  	case SPLASH_STORAGE_SF:
bcbb6448b   Nikita Kiryanov   splash_source: re...
77
  		return splash_sf_read_raw(bmp_load_addr, offset, read_size);
fd29dd554   Nikita Kiryanov   compulab: splash:...
78
79
80
81
82
83
  	default:
  		printf("Unknown splash location
  ");
  	}
  
  	return -EINVAL;
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
84
  }
fd29dd554   Nikita Kiryanov   compulab: splash:...
85
  static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
86
87
88
89
90
91
92
  {
  	struct bmp_header *bmp_hdr;
  	int res;
  	size_t bmp_size, bmp_header_size = sizeof(struct bmp_header);
  
  	if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp)
  		goto splash_address_too_high;
bcbb6448b   Nikita Kiryanov   splash_source: re...
93
  	res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
94
95
96
97
98
99
100
101
  	if (res < 0)
  		return res;
  
  	bmp_hdr = (struct bmp_header *)bmp_load_addr;
  	bmp_size = le32_to_cpu(bmp_hdr->file_size);
  
  	if (bmp_load_addr + bmp_size >= gd->start_addr_sp)
  		goto splash_address_too_high;
bcbb6448b   Nikita Kiryanov   splash_source: re...
102
  	return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
103
104
  
  splash_address_too_high:
f82eb2fa5   Nikita Kiryanov   common: convert c...
105
106
  	printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.
  ");
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
107

6947e3f56   Nikita Kiryanov   compulab: splash:...
108
  	return -EFAULT;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
109
  }
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
110

870dd3095   Nikita Kiryanov   splash_source: ad...
111
112
113
114
115
116
117
118
  static int splash_select_fs_dev(struct splash_location *location)
  {
  	int res;
  
  	switch (location->storage) {
  	case SPLASH_STORAGE_MMC:
  		res = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY);
  		break;
9bb4e9474   Nikita Kiryanov   splash_source: ad...
119
120
121
  	case SPLASH_STORAGE_USB:
  		res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
  		break;
50c2d2e12   Nikita Kiryanov   splash_source: ad...
122
123
124
  	case SPLASH_STORAGE_SATA:
  		res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
  		break;
1cb075c6c   Eran Matityahu   splash_source: ad...
125
126
127
128
129
130
  	case SPLASH_STORAGE_NAND:
  		if (location->ubivol != NULL)
  			res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
  		else
  			res = -ENODEV;
  		break;
870dd3095   Nikita Kiryanov   splash_source: ad...
131
132
133
134
135
136
137
138
139
140
141
142
  	default:
  		printf("Error: unsupported location storage.
  ");
  		return -ENODEV;
  	}
  
  	if (res)
  		printf("Error: could not access storage.
  ");
  
  	return res;
  }
9bb4e9474   Nikita Kiryanov   splash_source: ad...
143
144
145
146
147
148
149
150
  #ifdef CONFIG_USB_STORAGE
  static int splash_init_usb(void)
  {
  	int err;
  
  	err = usb_init();
  	if (err)
  		return err;
d7b60fbfa   Alexey Brodkin   splash: Accommoda...
151
152
153
154
155
  #ifndef CONFIG_DM_USB
  	err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
  #endif
  
  	return err;
9bb4e9474   Nikita Kiryanov   splash_source: ad...
156
157
158
159
160
161
162
163
164
  }
  #else
  static inline int splash_init_usb(void)
  {
  	printf("Cannot load splash image: no USB support
  ");
  	return -ENOSYS;
  }
  #endif
10e40d54b   Simon Glass   Kconfig: Add CONF...
165
  #ifdef CONFIG_SATA
50c2d2e12   Nikita Kiryanov   splash_source: ad...
166
167
  static int splash_init_sata(void)
  {
f19f1ecb6   Simon Glass   dm: sata: Support...
168
  	return sata_probe(0);
50c2d2e12   Nikita Kiryanov   splash_source: ad...
169
170
171
172
173
174
175
176
177
  }
  #else
  static inline int splash_init_sata(void)
  {
  	printf("Cannot load splash image: no SATA support
  ");
  	return -ENOSYS;
  }
  #endif
1cb075c6c   Eran Matityahu   splash_source: ad...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  #ifdef CONFIG_CMD_UBIFS
  static int splash_mount_ubifs(struct splash_location *location)
  {
  	int res;
  	char cmd[32];
  
  	sprintf(cmd, "ubi part %s", location->mtdpart);
  	res = run_command(cmd, 0);
  	if (res)
  		return res;
  
  	sprintf(cmd, "ubifsmount %s", location->ubivol);
  	res = run_command(cmd, 0);
  
  	return res;
  }
  
  static inline int splash_umount_ubifs(void)
  {
  	return run_command("ubifsumount", 0);
  }
  #else
  static inline int splash_mount_ubifs(struct splash_location *location)
  {
  	printf("Cannot load splash image: no UBIFS support
  ");
  	return -ENOSYS;
  }
  
  static inline int splash_umount_ubifs(void)
  {
  	printf("Cannot unmount UBIFS: no UBIFS support
  ");
  	return -ENOSYS;
  }
  #endif
870dd3095   Nikita Kiryanov   splash_source: ad...
214
215
216
217
  #define SPLASH_SOURCE_DEFAULT_FILE_NAME		"splash.bmp"
  
  static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
  {
9bb4e9474   Nikita Kiryanov   splash_source: ad...
218
  	int res = 0;
870dd3095   Nikita Kiryanov   splash_source: ad...
219
  	loff_t bmp_size;
3cc6e7070   Jonathan Golder   splash: Prevent s...
220
  	loff_t actread;
870dd3095   Nikita Kiryanov   splash_source: ad...
221
  	char *splash_file;
00caae6d4   Simon Glass   env: Rename geten...
222
  	splash_file = env_get("splashfile");
870dd3095   Nikita Kiryanov   splash_source: ad...
223
224
  	if (!splash_file)
  		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
9bb4e9474   Nikita Kiryanov   splash_source: ad...
225
226
  	if (location->storage == SPLASH_STORAGE_USB)
  		res = splash_init_usb();
50c2d2e12   Nikita Kiryanov   splash_source: ad...
227
228
  	if (location->storage == SPLASH_STORAGE_SATA)
  		res = splash_init_sata();
1cb075c6c   Eran Matityahu   splash_source: ad...
229
230
  	if (location->ubivol != NULL)
  		res = splash_mount_ubifs(location);
9bb4e9474   Nikita Kiryanov   splash_source: ad...
231
232
  	if (res)
  		return res;
870dd3095   Nikita Kiryanov   splash_source: ad...
233
234
  	res = splash_select_fs_dev(location);
  	if (res)
1cb075c6c   Eran Matityahu   splash_source: ad...
235
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
236
237
238
239
240
  
  	res = fs_size(splash_file, &bmp_size);
  	if (res) {
  		printf("Error (%d): cannot determine file size
  ", res);
1cb075c6c   Eran Matityahu   splash_source: ad...
241
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
242
243
244
245
246
  	}
  
  	if (bmp_load_addr + bmp_size >= gd->start_addr_sp) {
  		printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.
  ");
1cb075c6c   Eran Matityahu   splash_source: ad...
247
248
  		res = -EFAULT;
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
249
250
251
  	}
  
  	splash_select_fs_dev(location);
3cc6e7070   Jonathan Golder   splash: Prevent s...
252
  	res = fs_read(splash_file, bmp_load_addr, 0, 0, &actread);
1cb075c6c   Eran Matityahu   splash_source: ad...
253
254
255
256
257
258
  
  out:
  	if (location->ubivol != NULL)
  		splash_umount_ubifs();
  
  	return res;
870dd3095   Nikita Kiryanov   splash_source: ad...
259
  }
fd29dd554   Nikita Kiryanov   compulab: splash:...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  /**
   * select_splash_location - return the splash location based on board support
   *			    and env variable "splashsource".
   *
   * @locations:		An array of supported splash locations.
   * @size:		Size of splash_locations array.
   *
   * @return: If a null set of splash locations is given, or
   *	    splashsource env variable is set to unsupported value
   *			return NULL.
   *	    If splashsource env variable is not defined
   *			return the first entry in splash_locations as default.
   *	    If splashsource env variable contains a supported value
   *			return the location selected by splashsource.
   */
  static struct splash_location *select_splash_location(
  			    struct splash_location *locations, uint size)
  {
  	int i;
  	char *env_splashsource;
  
  	if (!locations || size == 0)
  		return NULL;
00caae6d4   Simon Glass   env: Rename geten...
283
  	env_splashsource = env_get("splashsource");
fd29dd554   Nikita Kiryanov   compulab: splash:...
284
285
286
287
288
289
290
291
292
293
294
295
  	if (env_splashsource == NULL)
  		return &locations[0];
  
  	for (i = 0; i < size; i++) {
  		if (!strcmp(locations[i].name, env_splashsource))
  			return &locations[i];
  	}
  
  	printf("splashsource env variable set to unsupported value
  ");
  	return NULL;
  }
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
296
297
298
299
300
  #ifdef CONFIG_FIT
  static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
  {
  	int res;
  	int node_offset;
3d92f3176   Leo Ruan   splash: Use splas...
301
  	const char *splash_file;
d50068369   Leo Ruan   splash: Load inte...
302
303
304
305
306
  	const void *internal_splash_data;
  	size_t internal_splash_size;
  	int external_splash_addr;
  	int external_splash_size;
  	bool is_splash_external = false;
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
307
308
309
310
311
312
313
314
315
316
317
  	struct image_header *img_header;
  	const u32 *fit_header;
  	u32 fit_size;
  	const size_t header_size = sizeof(struct image_header);
  
  	/* Read in image header */
  	res = splash_storage_read_raw(location, bmp_load_addr, header_size);
  	if (res < 0)
  		return res;
  
  	img_header = (struct image_header *)bmp_load_addr;
a7126edcb   Niko Mauno   splash_source: Ve...
318
319
320
321
322
  	if (image_get_magic(img_header) != FDT_MAGIC) {
  		printf("Could not find FDT magic
  ");
  		return -EINVAL;
  	}
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  	fit_size = fdt_totalsize(img_header);
  
  	/* Read in entire FIT */
  	fit_header = (const u32 *)(bmp_load_addr + header_size);
  	res = splash_storage_read_raw(location, (u32)fit_header, fit_size);
  	if (res < 0)
  		return res;
  
  	res = fit_check_format(fit_header);
  	if (!res) {
  		debug("Could not find valid FIT image
  ");
  		return -EINVAL;
  	}
3d92f3176   Leo Ruan   splash: Use splas...
337
338
339
340
341
342
  	/* Get the splash image node */
  	splash_file = env_get("splashfile");
  	if (!splash_file)
  		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
  
  	node_offset = fit_image_get_node(fit_header, splash_file);
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
343
344
345
  	if (node_offset < 0) {
  		debug("Could not find splash image '%s' in FIT
  ",
3d92f3176   Leo Ruan   splash: Use splas...
346
  		      splash_file);
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
347
348
  		return -ENOENT;
  	}
d50068369   Leo Ruan   splash: Load inte...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  	/* Extract the splash data from FIT */
  	/* 1. Test if splash is in FIT internal data. */
  	if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size))
  		memmove((void *)bmp_load_addr, internal_splash_data, internal_splash_size);
  	/* 2. Test if splash is in FIT external data with fixed position. */
  	else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr))
  		is_splash_external = true;
  	/* 3. Test if splash is in FIT external data with offset. */
  	else if (!fit_image_get_data_offset(fit_header, node_offset, &external_splash_addr)) {
  		/* Align data offset to 4-byte boundary */
  		fit_size = ALIGN(fdt_totalsize(fit_header), 4);
  		/* External splash offset means the offset by end of FIT header */
  		external_splash_addr += location->offset + fit_size;
  		is_splash_external = true;
  	} else {
  		printf("Failed to get splash image from FIT
  ");
  		return -ENODATA;
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
367
  	}
d50068369   Leo Ruan   splash: Load inte...
368
369
370
371
372
373
374
375
376
377
378
379
380
  	if (is_splash_external) {
  		res = fit_image_get_data_size(fit_header, node_offset, &external_splash_size);
  		if (res < 0) {
  			printf("Failed to get size of splash image (err=%d)
  ", res);
  			return res;
  		}
  
  		/* Read in the splash data */
  		location->offset = external_splash_addr;
  		res = splash_storage_read_raw(location, bmp_load_addr, external_splash_size);
  		if (res < 0)
  			return res;
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
381
  	}
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
382
383
384
  	return 0;
  }
  #endif /* CONFIG_FIT */
f82eb2fa5   Nikita Kiryanov   common: convert c...
385
386
387
388
389
390
391
392
393
394
395
396
397
  /**
   * splash_source_load - load splash image from a supported location.
   *
   * Select a splash image location based on the value of splashsource environment
   * variable and the board supported splash source locations, and load a
   * splashimage to the address pointed to by splashimage environment variable.
   *
   * @locations:		An array of supported splash locations.
   * @size:		Size of splash_locations array.
   *
   * @return: 0 on success, negative value on failure.
   */
  int splash_source_load(struct splash_location *locations, uint size)
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
398
  {
fd29dd554   Nikita Kiryanov   compulab: splash:...
399
  	struct splash_location *splash_location;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
400
401
  	char *env_splashimage_value;
  	u32 bmp_load_addr;
00caae6d4   Simon Glass   env: Rename geten...
402
  	env_splashimage_value = env_get("splashimage");
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
403
  	if (env_splashimage_value == NULL)
6947e3f56   Nikita Kiryanov   compulab: splash:...
404
  		return -ENOENT;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
405
406
407
408
409
  
  	bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
  	if (bmp_load_addr == 0) {
  		printf("Error: bad splashimage address specified
  ");
6947e3f56   Nikita Kiryanov   compulab: splash:...
410
  		return -EFAULT;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
411
  	}
fd29dd554   Nikita Kiryanov   compulab: splash:...
412
413
414
  	splash_location = select_splash_location(locations, size);
  	if (!splash_location)
  		return -EINVAL;
3b593f903   tomas.melin@vaisala.com   splash: fix splas...
415
  	if (splash_location->flags == SPLASH_STORAGE_RAW)
870dd3095   Nikita Kiryanov   splash_source: ad...
416
  		return splash_load_raw(splash_location, bmp_load_addr);
3b593f903   tomas.melin@vaisala.com   splash: fix splas...
417
  	else if (splash_location->flags == SPLASH_STORAGE_FS)
870dd3095   Nikita Kiryanov   splash_source: ad...
418
  		return splash_load_fs(splash_location, bmp_load_addr);
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
419
420
421
422
  #ifdef CONFIG_FIT
  	else if (splash_location->flags == SPLASH_STORAGE_FIT)
  		return splash_load_fit(splash_location, bmp_load_addr);
  #endif
870dd3095   Nikita Kiryanov   splash_source: ad...
423
  	return -EINVAL;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
424
  }