Newer
Older
/*
* (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>
#include <fdt_support.h>
#include <image.h>
#include <nand.h>
#include <sata.h>
#include <spi_flash.h>
#include <splash.h>
#include <usb.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SPI_FLASH
static struct spi_flash *sf;
static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
{
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
static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
{
debug("%s: sf support not available\n", __func__);
return -ENOSYS;
}
#endif
static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
return nand_read_skip_bad(mtd, offset,
(u_char *)bmp_load_addr);
}
#else
static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size)
{
debug("%s: nand support not available\n", __func__);
return -ENOSYS;
}
#endif
static int splash_storage_read_raw(struct splash_location *location,
u32 bmp_load_addr, size_t read_size)
u32 offset;
if (!location)
return -EINVAL;
offset = location->offset;
switch (location->storage) {
case SPLASH_STORAGE_NAND:
return splash_nand_read_raw(bmp_load_addr, offset, read_size);
case SPLASH_STORAGE_SF:
return splash_sf_read_raw(bmp_load_addr, offset, read_size);
default:
printf("Unknown splash location\n");
}
return -EINVAL;
static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr)
{
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;
res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size);
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;
return splash_storage_read_raw(location, bmp_load_addr, bmp_size);
splash_address_too_high:
printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n");
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;
case SPLASH_STORAGE_USB:
res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY);
break;
case SPLASH_STORAGE_SATA:
res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY);
break;
case SPLASH_STORAGE_NAND:
if (location->ubivol != NULL)
res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
else
res = -ENODEV;
break;
default:
printf("Error: unsupported location storage.\n");
return -ENODEV;
}
if (res)
printf("Error: could not access storage.\n");
return res;
}
#ifdef CONFIG_USB_STORAGE
static int splash_init_usb(void)
{
int err;
err = usb_init();
if (err)
return err;
#ifndef CONFIG_DM_USB
err = usb_stor_scan(1) < 0 ? -ENODEV : 0;
#endif
return err;
}
#else
static inline int splash_init_usb(void)
{
printf("Cannot load splash image: no USB support\n");
return -ENOSYS;
}
#endif
static int splash_init_sata(void)
{
return sata_probe(0);
}
#else
static inline int splash_init_sata(void)
{
printf("Cannot load splash image: no SATA support\n");
return -ENOSYS;
}
#endif
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\n");
return -ENOSYS;
}
static inline int splash_umount_ubifs(void)
{
printf("Cannot unmount UBIFS: no UBIFS support\n");
return -ENOSYS;
}
#endif
#define SPLASH_SOURCE_DEFAULT_FILE_NAME "splash.bmp"
static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr)
{
loff_t bmp_size;
char *splash_file;
if (!splash_file)
splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME;
if (location->storage == SPLASH_STORAGE_USB)
res = splash_init_usb();
if (location->storage == SPLASH_STORAGE_SATA)
res = splash_init_sata();
if (location->ubivol != NULL)
res = splash_mount_ubifs(location);
if (res)
return res;
res = splash_select_fs_dev(location);
if (res)
res = fs_size(splash_file, &bmp_size);
if (res) {
printf("Error (%d): cannot determine file size\n", res);
}
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.\n");
res = -EFAULT;
goto out;
}
splash_select_fs_dev(location);
res = fs_read(splash_file, bmp_load_addr, 0, 0, &actread);
out:
if (location->ubivol != NULL)
splash_umount_ubifs();
return res;
/**
* 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;
env_splashsource = env_get("splashsource");
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\n");
return NULL;
}
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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
#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;
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\n");
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\n",
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)\n", 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)\n", 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 */
/**
* 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)
struct splash_location *splash_location;
char *env_splashimage_value;
u32 bmp_load_addr;
env_splashimage_value = env_get("splashimage");
if (env_splashimage_value == NULL)
bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16);
if (bmp_load_addr == 0) {
printf("Error: bad splashimage address specified\n");
splash_location = select_splash_location(locations, size);
if (!splash_location)
return -EINVAL;
if (splash_location->flags == SPLASH_STORAGE_RAW)
return splash_load_raw(splash_location, bmp_load_addr);
else if (splash_location->flags == SPLASH_STORAGE_FS)
return splash_load_fs(splash_location, bmp_load_addr);
#ifdef CONFIG_FIT
else if (splash_location->flags == SPLASH_STORAGE_FIT)
return splash_load_fit(splash_location, bmp_load_addr);
#endif
return -EINVAL;