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