Blame view

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

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

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