diff options
Diffstat (limited to 'drivers/mtd/spi')
-rw-r--r-- | drivers/mtd/spi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mtd/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/spi/sf-uclass.c | 11 | ||||
-rw-r--r-- | drivers/mtd/spi/sf_bootdev.c | 82 |
4 files changed, 102 insertions, 0 deletions
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 7b858a3a919..a9617c6c58c 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -80,6 +80,14 @@ config SF_DEFAULT_SPEED if SPI_FLASH +config BOOTDEV_SPI_FLASH + bool "SPI Flash bootdev support" + help + Enable a boot device for SPI flash. This allows reading a script + from SPI flash so that it can be used to boot an Operating System. + + If unsure, say N + config SPI_FLASH_SFDP_SUPPORT bool "SFDP table parsing support for SPI NOR flashes" depends on !SPI_FLASH_BAR diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 99cc4185522..409395382f5 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o +obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_SPI_FLASH) += sf_bootdev.o diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index e6e650ef8c0..df1f75390c4 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -6,6 +6,7 @@ #define LOG_CATEGORY UCLASS_SPI_FLASH #include <common.h> +#include <bootdev.h> #include <dm.h> #include <log.h> #include <malloc.h> @@ -13,6 +14,7 @@ #include <spi_flash.h> #include <asm/global_data.h> #include <dm/device-internal.h> +#include <test/test.h> #include "sf_internal.h" DECLARE_GLOBAL_DATA_PTR; @@ -86,6 +88,14 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, static int spi_flash_post_bind(struct udevice *dev) { + int ret; + + if (CONFIG_IS_ENABLED(BOOTDEV_SPI_FLASH) && test_sf_bootdev_enabled()) { + ret = bootdev_setup_for_dev(dev, "sf_bootdev"); + if (ret) + return log_msg_ret("bd", ret); + } + #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_spi_flash_ops *ops = sf_get_ops(dev); static int reloc_done; @@ -101,6 +111,7 @@ static int spi_flash_post_bind(struct udevice *dev) reloc_done++; } #endif + return 0; } diff --git a/drivers/mtd/spi/sf_bootdev.c b/drivers/mtd/spi/sf_bootdev.c new file mode 100644 index 00000000000..2272e8567ce --- /dev/null +++ b/drivers/mtd/spi/sf_bootdev.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Read a bootflow from SPI flash + * + * Copyright 2022 Google LLC + */ + +#include <common.h> +#include <bootdev.h> +#include <bootflow.h> +#include <bootmeth.h> +#include <dm.h> +#include <env.h> +#include <malloc.h> +#include <spi_flash.h> + +static int sf_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, + struct bootflow *bflow) +{ + struct udevice *sf = dev_get_parent(dev); + uint size; + char *buf; + int ret; + + /* We only support the whole device, not partitions */ + if (iter->part) + return log_msg_ret("max", -ESHUTDOWN); + + size = env_get_hex("script_size_f", 0); + if (!size) + return log_msg_ret("sz", -EINVAL); + + buf = malloc(size + 1); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + + ret = spi_flash_read_dm(sf, env_get_hex("script_offset_f", 0), + size, buf); + if (ret) + return log_msg_ret("cmd", -EINVAL); + bflow->state = BOOTFLOWST_MEDIA; + + ret = bootmeth_set_bootflow(bflow->method, bflow, buf, size); + if (ret) { + free(buf); + return log_msg_ret("method", ret); + } + + return 0; +} + +static int sf_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_2_SCAN_FAST; + + return 0; +} + +struct bootdev_ops sf_bootdev_ops = { + .get_bootflow = sf_get_bootflow, +}; + +static const struct udevice_id sf_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-sf" }, + { } +}; + +U_BOOT_DRIVER(sf_bootdev) = { + .name = "sf_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &sf_bootdev_ops, + .bind = sf_bootdev_bind, + .of_match = sf_bootdev_ids, +}; + +BOOTDEV_HUNTER(sf_bootdev_hunter) = { + .prio = BOOTDEVP_2_SCAN_FAST, + .uclass = UCLASS_SPI_FLASH, + .drv = DM_DRIVER_REF(sf_bootdev), +}; |