uboot/drivers/misc/fs_loader.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2 /*
   3 * Copyright (C) 2018-2019 Intel Corporation <www.intel.com>
   4 *
   5 */
   6#include <common.h>
   7#include <dm.h>
   8#include <env.h>
   9#include <errno.h>
  10#include <blk.h>
  11#include <fs.h>
  12#include <fs_loader.h>
  13#include <log.h>
  14#include <linux/string.h>
  15#include <mapmem.h>
  16#include <malloc.h>
  17#include <spl.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21/**
  22 * struct firmware - A place for storing firmware and its attribute data.
  23 *
  24 * This holds information about a firmware and its content.
  25 *
  26 * @size: Size of a file
  27 * @data: Buffer for file
  28 * @priv: Firmware loader private fields
  29 * @name: Filename
  30 * @offset: Offset of reading a file
  31 */
  32struct firmware {
  33        size_t size;
  34        const u8 *data;
  35        const char *name;
  36        u32 offset;
  37};
  38
  39#ifdef CONFIG_CMD_UBIFS
  40static int mount_ubifs(char *mtdpart, char *ubivol)
  41{
  42        int ret = ubi_part(mtdpart, NULL);
  43
  44        if (ret) {
  45                debug("Cannot find mtd partition %s\n", mtdpart);
  46                return ret;
  47        }
  48
  49        return cmd_ubifs_mount(ubivol);
  50}
  51
  52static int umount_ubifs(void)
  53{
  54        return cmd_ubifs_umount();
  55}
  56#else
  57static int mount_ubifs(char *mtdpart, char *ubivol)
  58{
  59        debug("Error: Cannot load image: no UBIFS support\n");
  60        return -ENOSYS;
  61}
  62#endif
  63
  64static int select_fs_dev(struct device_platdata *plat)
  65{
  66        int ret;
  67
  68        if (plat->phandlepart.phandle) {
  69                ofnode node;
  70
  71                node = ofnode_get_by_phandle(plat->phandlepart.phandle);
  72
  73                struct udevice *dev;
  74
  75                ret = device_get_global_by_ofnode(node, &dev);
  76                if (!ret) {
  77                        struct blk_desc *desc = blk_get_by_device(dev);
  78                        if (desc) {
  79                                ret = fs_set_blk_dev_with_part(desc,
  80                                        plat->phandlepart.partition);
  81                        } else {
  82                                debug("%s: No device found\n", __func__);
  83                                return -ENODEV;
  84                        }
  85                }
  86        } else if (plat->mtdpart && plat->ubivol) {
  87                ret = mount_ubifs(plat->mtdpart, plat->ubivol);
  88                if (ret)
  89                        return ret;
  90
  91                ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
  92        } else {
  93                debug("Error: unsupported storage device.\n");
  94                return -ENODEV;
  95        }
  96
  97        if (ret)
  98                debug("Error: could not access storage.\n");
  99
 100        return ret;
 101}
 102
 103/**
 104 * _request_firmware_prepare - Prepare firmware struct.
 105 *
 106 * @dev: An instance of a driver.
 107 * @name: Name of firmware file.
 108 * @dbuf: Address of buffer to load firmware into.
 109 * @size: Size of buffer.
 110 * @offset: Offset of a file for start reading into buffer.
 111 *
 112 * Return: Negative value if fail, 0 for successful.
 113 */
 114static int _request_firmware_prepare(struct udevice *dev,
 115                                    const char *name, void *dbuf,
 116                                    size_t size, u32 offset)
 117{
 118        if (!name || name[0] == '\0')
 119                return -EINVAL;
 120
 121        struct firmware *firmwarep = dev_get_priv(dev);
 122
 123        if (!firmwarep)
 124                return -ENOMEM;
 125
 126        firmwarep->name = name;
 127        firmwarep->offset = offset;
 128        firmwarep->data = dbuf;
 129        firmwarep->size = size;
 130
 131        return 0;
 132}
 133
 134/**
 135 * fw_get_filesystem_firmware - load firmware into an allocated buffer.
 136 * @dev: An instance of a driver.
 137 *
 138 * Return: Size of total read, negative value when error.
 139 */
 140static int fw_get_filesystem_firmware(struct udevice *dev)
 141{
 142        loff_t actread;
 143        char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
 144        int ret;
 145
 146        storage_interface = env_get("storage_interface");
 147        dev_part = env_get("fw_dev_part");
 148        ubi_mtdpart = env_get("fw_ubi_mtdpart");
 149        ubi_volume = env_get("fw_ubi_volume");
 150
 151        if (storage_interface && dev_part) {
 152                ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY);
 153        } else if (storage_interface && ubi_mtdpart && ubi_volume) {
 154                ret = mount_ubifs(ubi_mtdpart, ubi_volume);
 155                if (ret)
 156                        return ret;
 157
 158                if (!strcmp("ubi", storage_interface))
 159                        ret = fs_set_blk_dev(storage_interface, NULL,
 160                                FS_TYPE_UBIFS);
 161                else
 162                        ret = -ENODEV;
 163        } else {
 164                ret = select_fs_dev(dev->platdata);
 165        }
 166
 167        if (ret)
 168                goto out;
 169
 170        struct firmware *firmwarep = dev_get_priv(dev);
 171
 172        if (!firmwarep)
 173                return -ENOMEM;
 174
 175        ret = fs_read(firmwarep->name, (ulong)map_to_sysmem(firmwarep->data),
 176                        firmwarep->offset, firmwarep->size, &actread);
 177
 178        if (ret) {
 179                debug("Error: %d Failed to read %s from flash %lld != %zu.\n",
 180                      ret, firmwarep->name, actread, firmwarep->size);
 181        } else {
 182                ret = actread;
 183        }
 184
 185out:
 186#ifdef CONFIG_CMD_UBIFS
 187        umount_ubifs();
 188#endif
 189        return ret;
 190}
 191
 192/**
 193 * request_firmware_into_buf - Load firmware into a previously allocated buffer.
 194 * @dev: An instance of a driver.
 195 * @name: Name of firmware file.
 196 * @buf: Address of buffer to load firmware into.
 197 * @size: Size of buffer.
 198 * @offset: Offset of a file for start reading into buffer.
 199 *
 200 * The firmware is loaded directly into the buffer pointed to by @buf.
 201 *
 202 * Return: Size of total read, negative value when error.
 203 */
 204int request_firmware_into_buf(struct udevice *dev,
 205                              const char *name,
 206                              void *buf, size_t size, u32 offset)
 207{
 208        int ret;
 209
 210        if (!dev)
 211                return -EINVAL;
 212
 213        ret = _request_firmware_prepare(dev, name, buf, size, offset);
 214        if (ret < 0) /* error */
 215                return ret;
 216
 217        ret = fw_get_filesystem_firmware(dev);
 218
 219        return ret;
 220}
 221
 222static int fs_loader_ofdata_to_platdata(struct udevice *dev)
 223{
 224        u32 phandlepart[2];
 225
 226        ofnode fs_loader_node = dev_ofnode(dev);
 227
 228        if (ofnode_valid(fs_loader_node)) {
 229                struct device_platdata *plat;
 230
 231                plat = dev->platdata;
 232                if (!ofnode_read_u32_array(fs_loader_node,
 233                                          "phandlepart",
 234                                          phandlepart, 2)) {
 235                        plat->phandlepart.phandle = phandlepart[0];
 236                        plat->phandlepart.partition = phandlepart[1];
 237                }
 238
 239                plat->mtdpart = (char *)ofnode_read_string(
 240                                 fs_loader_node, "mtdpart");
 241
 242                plat->ubivol = (char *)ofnode_read_string(
 243                                 fs_loader_node, "ubivol");
 244        }
 245
 246        return 0;
 247}
 248
 249static int fs_loader_probe(struct udevice *dev)
 250{
 251#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(BLK)
 252        int ret;
 253        struct device_platdata *plat = dev->platdata;
 254
 255        if (plat->phandlepart.phandle) {
 256                ofnode node = ofnode_get_by_phandle(plat->phandlepart.phandle);
 257                struct udevice *parent_dev = NULL;
 258
 259                ret = device_get_global_by_ofnode(node, &parent_dev);
 260                if (!ret) {
 261                        struct udevice *dev;
 262
 263                        ret = blk_get_from_parent(parent_dev, &dev);
 264                        if (ret) {
 265                                debug("fs_loader: No block device: %d\n",
 266                                        ret);
 267
 268                                return ret;
 269                        }
 270                }
 271        }
 272#endif
 273
 274        return 0;
 275};
 276
 277static const struct udevice_id fs_loader_ids[] = {
 278        { .compatible = "u-boot,fs-loader"},
 279        { }
 280};
 281
 282U_BOOT_DRIVER(fs_loader) = {
 283        .name                   = "fs-loader",
 284        .id                     = UCLASS_FS_FIRMWARE_LOADER,
 285        .of_match               = fs_loader_ids,
 286        .probe                  = fs_loader_probe,
 287        .ofdata_to_platdata     = fs_loader_ofdata_to_platdata,
 288        .platdata_auto_alloc_size       = sizeof(struct device_platdata),
 289        .priv_auto_alloc_size   = sizeof(struct firmware),
 290};
 291
 292UCLASS_DRIVER(fs_loader) = {
 293        .id             = UCLASS_FS_FIRMWARE_LOADER,
 294        .name           = "fs-loader",
 295};
 296