Blame view

common/splash_source.c 9.79 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>
6947e3f56   Nikita Kiryanov   compulab: splash:...
10
  #include <errno.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
11
  #include <fs.h>
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
12
  #include <fdt_support.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
13
14
15
  #include <image.h>
  #include <nand.h>
  #include <sata.h>
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
16
  #include <spi.h>
7583f1f57   tomas.melin@vaisala.com   splash: sort incl...
17
18
  #include <spi_flash.h>
  #include <splash.h>
9bb4e9474   Nikita Kiryanov   splash_source: ad...
19
  #include <usb.h>
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
20
21
  
  DECLARE_GLOBAL_DATA_PTR;
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
22
23
  #ifdef CONFIG_SPI_FLASH
  static struct spi_flash *sf;
bcbb6448b   Nikita Kiryanov   splash_source: re...
24
  static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
25
26
27
28
29
30
31
32
33
34
35
36
37
  {
  	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...
38
  static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
39
40
41
42
43
44
  {
  	debug("%s: sf support not available
  ", __func__);
  	return -ENOSYS;
  }
  #endif
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
45
  #ifdef CONFIG_CMD_NAND
bcbb6448b   Nikita Kiryanov   splash_source: re...
46
  static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
47
  {
edba8cc4f   Grygorii Strashko   common: use get_n...
48
49
  	struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
  	return nand_read_skip_bad(mtd, offset,
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
50
  				  &read_size, NULL,
edba8cc4f   Grygorii Strashko   common: use get_n...
51
  				  mtd->size,
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
52
53
54
  				  (u_char *)bmp_load_addr);
  }
  #else
bcbb6448b   Nikita Kiryanov   splash_source: re...
55
  static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
56
57
58
59
60
61
  {
  	debug("%s: nand support not available
  ", __func__);
  	return -ENOSYS;
  }
  #endif
bcbb6448b   Nikita Kiryanov   splash_source: re...
62
  static int splash_storage_read_raw(struct splash_location *location,
fd29dd554   Nikita Kiryanov   compulab: splash:...
63
  			       u32 bmp_load_addr, size_t read_size)
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
64
  {
fd29dd554   Nikita Kiryanov   compulab: splash:...
65
66
67
68
69
70
71
72
  	u32 offset;
  
  	if (!location)
  		return -EINVAL;
  
  	offset = location->offset;
  	switch (location->storage) {
  	case SPLASH_STORAGE_NAND:
bcbb6448b   Nikita Kiryanov   splash_source: re...
73
  		return splash_nand_read_raw(bmp_load_addr, offset, read_size);
7e8d7f2ac   Nikita Kiryanov   compulab: splash:...
74
  	case SPLASH_STORAGE_SF:
bcbb6448b   Nikita Kiryanov   splash_source: re...
75
  		return splash_sf_read_raw(bmp_load_addr, offset, read_size);
fd29dd554   Nikita Kiryanov   compulab: splash:...
76
77
78
79
80
81
  	default:
  		printf("Unknown splash location
  ");
  	}
  
  	return -EINVAL;
7be4cd2cc   Nikita Kiryanov   compulab: splash:...
82
  }
fd29dd554   Nikita Kiryanov   compulab: splash:...
83
  static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
84
85
86
87
88
89
90
  {
  	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...
91
  	res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
92
93
94
95
96
97
98
99
  	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...
100
  	return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
101
102
  
  splash_address_too_high:
f82eb2fa5   Nikita Kiryanov   common: convert c...
103
104
  	printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.
  ");
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
105

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

870dd3095   Nikita Kiryanov   splash_source: ad...
109
110
111
112
113
114
115
116
  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...
117
118
119
  	case SPLASH_STORAGE_USB:
  		res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
  		break;
50c2d2e12   Nikita Kiryanov   splash_source: ad...
120
121
122
  	case SPLASH_STORAGE_SATA:
  		res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
  		break;
1cb075c6c   Eran Matityahu   splash_source: ad...
123
124
125
126
127
128
  	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...
129
130
131
132
133
134
135
136
137
138
139
140
  	default:
  		printf("Error: unsupported location storage.
  ");
  		return -ENODEV;
  	}
  
  	if (res)
  		printf("Error: could not access storage.
  ");
  
  	return res;
  }
9bb4e9474   Nikita Kiryanov   splash_source: ad...
141
142
143
144
145
146
147
148
  #ifdef CONFIG_USB_STORAGE
  static int splash_init_usb(void)
  {
  	int err;
  
  	err = usb_init();
  	if (err)
  		return err;
d7b60fbfa   Alexey Brodkin   splash: Accommoda...
149
150
151
152
153
  #ifndef CONFIG_DM_USB
  	err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
  #endif
  
  	return err;
9bb4e9474   Nikita Kiryanov   splash_source: ad...
154
155
156
157
158
159
160
161
162
  }
  #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...
163
  #ifdef CONFIG_SATA
50c2d2e12   Nikita Kiryanov   splash_source: ad...
164
165
  static int splash_init_sata(void)
  {
f19f1ecb6   Simon Glass   dm: sata: Support...
166
  	return sata_probe(0);
50c2d2e12   Nikita Kiryanov   splash_source: ad...
167
168
169
170
171
172
173
174
175
  }
  #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...
176
177
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
  #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...
212
213
214
215
  #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...
216
  	int res = 0;
870dd3095   Nikita Kiryanov   splash_source: ad...
217
  	loff_t bmp_size;
3cc6e7070   Jonathan Golder   splash: Prevent s...
218
  	loff_t actread;
870dd3095   Nikita Kiryanov   splash_source: ad...
219
  	char *splash_file;
00caae6d4   Simon Glass   env: Rename geten...
220
  	splash_file = env_get("splashfile");
870dd3095   Nikita Kiryanov   splash_source: ad...
221
222
  	if (!splash_file)
  		splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
9bb4e9474   Nikita Kiryanov   splash_source: ad...
223
224
  	if (location->storage == SPLASH_STORAGE_USB)
  		res = splash_init_usb();
50c2d2e12   Nikita Kiryanov   splash_source: ad...
225
226
  	if (location->storage == SPLASH_STORAGE_SATA)
  		res = splash_init_sata();
1cb075c6c   Eran Matityahu   splash_source: ad...
227
228
  	if (location->ubivol != NULL)
  		res = splash_mount_ubifs(location);
9bb4e9474   Nikita Kiryanov   splash_source: ad...
229
230
  	if (res)
  		return res;
870dd3095   Nikita Kiryanov   splash_source: ad...
231
232
  	res = splash_select_fs_dev(location);
  	if (res)
1cb075c6c   Eran Matityahu   splash_source: ad...
233
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
234
235
236
237
238
  
  	res = fs_size(splash_file, &bmp_size);
  	if (res) {
  		printf("Error (%d): cannot determine file size
  ", res);
1cb075c6c   Eran Matityahu   splash_source: ad...
239
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
240
241
242
243
244
  	}
  
  	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...
245
246
  		res = -EFAULT;
  		goto out;
870dd3095   Nikita Kiryanov   splash_source: ad...
247
248
249
  	}
  
  	splash_select_fs_dev(location);
3cc6e7070   Jonathan Golder   splash: Prevent s...
250
  	res = fs_read(splash_file, bmp_load_addr, 0, 0, &actread);
1cb075c6c   Eran Matityahu   splash_source: ad...
251
252
253
254
255
256
  
  out:
  	if (location->ubivol != NULL)
  		splash_umount_ubifs();
  
  	return res;
870dd3095   Nikita Kiryanov   splash_source: ad...
257
  }
fd29dd554   Nikita Kiryanov   compulab: splash:...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  /**
   * 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...
281
  	env_splashsource = env_get("splashsource");
fd29dd554   Nikita Kiryanov   compulab: splash:...
282
283
284
285
286
287
288
289
290
291
292
293
  	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...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  #ifdef CONFIG_FIT
  static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
  {
  	int res;
  	int node_offset;
  	int splash_offset;
  	int splash_size;
  	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...
312
313
314
315
316
  	if (image_get_magic(img_header) != FDT_MAGIC) {
  		printf("Could not find FDT magic
  ");
  		return -EINVAL;
  	}
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  	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;
  	}
  
  	node_offset = fit_image_get_node(fit_header, location->name);
  	if (node_offset < 0) {
  		debug("Could not find splash image '%s' in FIT
  ",
  		      location->name);
  		return -ENOENT;
  	}
  
  	res = fit_image_get_data_offset(fit_header, node_offset,
  					&splash_offset);
  	if (res < 0) {
  		printf("Failed to load splash image (err=%d)
  ", res);
  		return res;
  	}
  
  	res = fit_image_get_data_size(fit_header, node_offset, &splash_size);
  	if (res < 0) {
  		printf("Failed to load splash image (err=%d)
  ", res);
  		return res;
  	}
  
  	/* Align data offset to 4-byte boundrary */
  	fit_size = fdt_totalsize(fit_header);
  	fit_size = (fit_size + 3) & ~3;
  
  	/* Read in the splash data */
  	location->offset = (location->offset + fit_size + splash_offset);
  	res = splash_storage_read_raw(location, bmp_load_addr , splash_size);
  	if (res < 0)
  		return res;
  
  	return 0;
  }
  #endif /* CONFIG_FIT */
f82eb2fa5   Nikita Kiryanov   common: convert c...
368
369
370
371
372
373
374
375
376
377
378
379
380
  /**
   * 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...
381
  {
fd29dd554   Nikita Kiryanov   compulab: splash:...
382
  	struct splash_location *splash_location;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
383
384
  	char *env_splashimage_value;
  	u32 bmp_load_addr;
00caae6d4   Simon Glass   env: Rename geten...
385
  	env_splashimage_value = env_get("splashimage");
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
386
  	if (env_splashimage_value == NULL)
6947e3f56   Nikita Kiryanov   compulab: splash:...
387
  		return -ENOENT;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
388
389
390
391
392
  
  	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:...
393
  		return -EFAULT;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
394
  	}
fd29dd554   Nikita Kiryanov   compulab: splash:...
395
396
397
  	splash_location = select_splash_location(locations, size);
  	if (!splash_location)
  		return -EINVAL;
3b593f903   tomas.melin@vaisala.com   splash: fix splas...
398
  	if (splash_location->flags == SPLASH_STORAGE_RAW)
870dd3095   Nikita Kiryanov   splash_source: ad...
399
  		return splash_load_raw(splash_location, bmp_load_addr);
3b593f903   tomas.melin@vaisala.com   splash: fix splas...
400
  	else if (splash_location->flags == SPLASH_STORAGE_FS)
870dd3095   Nikita Kiryanov   splash_source: ad...
401
  		return splash_load_fs(splash_location, bmp_load_addr);
db1b79b88   tomas.melin@vaisala.com   splash: add suppo...
402
403
404
405
  #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...
406
  	return -EINVAL;
f4a40f05f   Igor Grinberg   omap3: cm-t35: ex...
407
  }