123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2018 Intel Corporation <www.intel.com>
- *
- */
- #include <common.h>
- #include <dm.h>
- #include <errno.h>
- #include <blk.h>
- #include <fs.h>
- #include <fs_loader.h>
- #include <linux/string.h>
- #include <mapmem.h>
- #include <malloc.h>
- #include <spl.h>
- DECLARE_GLOBAL_DATA_PTR;
- struct firmware_priv {
- const char *name; /* Filename */
- u32 offset; /* Offset of reading a file */
- };
- #ifdef CONFIG_CMD_UBIFS
- static int mount_ubifs(char *mtdpart, char *ubivol)
- {
- int ret = ubi_part(mtdpart, NULL);
- if (ret) {
- debug("Cannot find mtd partition %s\n", mtdpart);
- return ret;
- }
- return cmd_ubifs_mount(ubivol);
- }
- static int umount_ubifs(void)
- {
- return cmd_ubifs_umount();
- }
- #else
- static int mount_ubifs(char *mtdpart, char *ubivol)
- {
- debug("Error: Cannot load image: no UBIFS support\n");
- return -ENOSYS;
- }
- #endif
- static int select_fs_dev(struct device_platdata *plat)
- {
- int ret;
- if (plat->phandlepart.phandle) {
- ofnode node;
- node = ofnode_get_by_phandle(plat->phandlepart.phandle);
- struct udevice *dev;
- ret = device_get_global_by_ofnode(node, &dev);
- if (!ret) {
- struct blk_desc *desc = blk_get_by_device(dev);
- if (desc) {
- ret = fs_set_blk_dev_with_part(desc,
- plat->phandlepart.partition);
- } else {
- debug("%s: No device found\n", __func__);
- return -ENODEV;
- }
- }
- } else if (plat->mtdpart && plat->ubivol) {
- ret = mount_ubifs(plat->mtdpart, plat->ubivol);
- if (ret)
- return ret;
- ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
- } else {
- debug("Error: unsupported storage device.\n");
- return -ENODEV;
- }
- if (ret)
- debug("Error: could not access storage.\n");
- return ret;
- }
- /**
- * _request_firmware_prepare - Prepare firmware struct.
- *
- * @name: Name of firmware file.
- * @dbuf: Address of buffer to load firmware into.
- * @size: Size of buffer.
- * @offset: Offset of a file for start reading into buffer.
- * @firmwarep: Pointer to pointer to firmware image.
- *
- * Return: Negative value if fail, 0 for successful.
- */
- static int _request_firmware_prepare(const char *name, void *dbuf,
- size_t size, u32 offset,
- struct firmware **firmwarep)
- {
- if (!name || name[0] == '\0')
- return -EINVAL;
- /* No memory allocation is required if *firmwarep is allocated */
- if (!(*firmwarep)) {
- (*firmwarep) = calloc(1, sizeof(struct firmware));
- if (!(*firmwarep))
- return -ENOMEM;
- (*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv));
- if (!(*firmwarep)->priv) {
- free(*firmwarep);
- return -ENOMEM;
- }
- } else if (!(*firmwarep)->priv) {
- (*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv));
- if (!(*firmwarep)->priv) {
- free(*firmwarep);
- return -ENOMEM;
- }
- }
- ((struct firmware_priv *)((*firmwarep)->priv))->name = name;
- ((struct firmware_priv *)((*firmwarep)->priv))->offset = offset;
- (*firmwarep)->data = dbuf;
- (*firmwarep)->size = size;
- return 0;
- }
- /**
- * release_firmware - Release the resource associated with a firmware image
- * @firmware: Firmware resource to release
- */
- void release_firmware(struct firmware *firmware)
- {
- if (firmware) {
- if (firmware->priv) {
- free(firmware->priv);
- firmware->priv = NULL;
- }
- free(firmware);
- }
- }
- /**
- * fw_get_filesystem_firmware - load firmware into an allocated buffer.
- * @plat: Platform data such as storage and partition firmware loading from.
- * @firmware: pointer to firmware image.
- *
- * Return: Size of total read, negative value when error.
- */
- static int fw_get_filesystem_firmware(struct device_platdata *plat,
- struct firmware *firmware)
- {
- struct firmware_priv *fw_priv = NULL;
- loff_t actread;
- char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
- int ret;
- storage_interface = env_get("storage_interface");
- dev_part = env_get("fw_dev_part");
- ubi_mtdpart = env_get("fw_ubi_mtdpart");
- ubi_volume = env_get("fw_ubi_volume");
- if (storage_interface && dev_part) {
- ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY);
- } else if (storage_interface && ubi_mtdpart && ubi_volume) {
- ret = mount_ubifs(ubi_mtdpart, ubi_volume);
- if (ret)
- return ret;
- if (!strcmp("ubi", storage_interface))
- ret = fs_set_blk_dev(storage_interface, NULL,
- FS_TYPE_UBIFS);
- else
- ret = -ENODEV;
- } else {
- ret = select_fs_dev(plat);
- }
- if (ret)
- goto out;
- fw_priv = firmware->priv;
- ret = fs_read(fw_priv->name, (ulong)map_to_sysmem(firmware->data),
- fw_priv->offset, firmware->size, &actread);
- if (ret) {
- debug("Error: %d Failed to read %s from flash %lld != %zu.\n",
- ret, fw_priv->name, actread, firmware->size);
- } else {
- ret = actread;
- }
- out:
- #ifdef CONFIG_CMD_UBIFS
- umount_ubifs();
- #endif
- return ret;
- }
- /**
- * request_firmware_into_buf - Load firmware into a previously allocated buffer.
- * @plat: Platform data such as storage and partition firmware loading from.
- * @name: Name of firmware file.
- * @buf: Address of buffer to load firmware into.
- * @size: Size of buffer.
- * @offset: Offset of a file for start reading into buffer.
- * @firmwarep: Pointer to firmware image.
- *
- * The firmware is loaded directly into the buffer pointed to by @buf and
- * the @firmwarep data member is pointed at @buf.
- *
- * Return: Size of total read, negative value when error.
- */
- int request_firmware_into_buf(struct device_platdata *plat,
- const char *name,
- void *buf, size_t size, u32 offset,
- struct firmware **firmwarep)
- {
- int ret;
- if (!plat)
- return -EINVAL;
- ret = _request_firmware_prepare(name, buf, size, offset, firmwarep);
- if (ret < 0) /* error */
- return ret;
- ret = fw_get_filesystem_firmware(plat, *firmwarep);
- return ret;
- }
- static int fs_loader_ofdata_to_platdata(struct udevice *dev)
- {
- const char *fs_loader_path;
- u32 phandlepart[2];
- fs_loader_path = ofnode_get_chosen_prop("firmware-loader");
- if (fs_loader_path) {
- ofnode fs_loader_node;
- fs_loader_node = ofnode_path(fs_loader_path);
- if (ofnode_valid(fs_loader_node)) {
- struct device_platdata *plat;
- plat = dev->platdata;
- if (!ofnode_read_u32_array(fs_loader_node,
- "phandlepart",
- phandlepart, 2)) {
- plat->phandlepart.phandle = phandlepart[0];
- plat->phandlepart.partition = phandlepart[1];
- }
- plat->mtdpart = (char *)ofnode_read_string(
- fs_loader_node, "mtdpart");
- plat->ubivol = (char *)ofnode_read_string(
- fs_loader_node, "ubivol");
- }
- }
- return 0;
- }
- static int fs_loader_probe(struct udevice *dev)
- {
- return 0;
- };
- static const struct udevice_id fs_loader_ids[] = {
- { .compatible = "u-boot,fs-loader"},
- { }
- };
- U_BOOT_DRIVER(fs_loader) = {
- .name = "fs-loader",
- .id = UCLASS_FS_FIRMWARE_LOADER,
- .of_match = fs_loader_ids,
- .probe = fs_loader_probe,
- .ofdata_to_platdata = fs_loader_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct device_platdata),
- };
- UCLASS_DRIVER(fs_loader) = {
- .id = UCLASS_FS_FIRMWARE_LOADER,
- .name = "fs-loader",
- };
|