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