Introduce a framework that allows loading the System Firmware (SYSFW) binary as well as the associated configuration data from an image tree blob named "sysfw.itb" from an FS-based boot media using the FS loader framework.
Signed-off-by: Andreas Dannenberg <dannenb...@ti.com> --- arch/arm/mach-k3/Kconfig | 22 ++ arch/arm/mach-k3/Makefile | 3 + arch/arm/mach-k3/include/mach/sysfw-loader.h | 12 + arch/arm/mach-k3/sysfw-loader.c | 296 +++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 arch/arm/mach-k3/include/mach/sysfw-loader.h create mode 100644 arch/arm/mach-k3/sysfw-loader.c diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig index e677a2e01b..fd28593cec 100644 --- a/arch/arm/mach-k3/Kconfig +++ b/arch/arm/mach-k3/Kconfig @@ -58,6 +58,28 @@ config SYS_K3_BOOT_CORE_ID int default 16 +config K3_LOAD_SYSFW + bool + depends on SPL + +config K3_SYSFW_IMAGE_NAME + string "File name of SYSFW firmware and configuration blob" + depends on K3_LOAD_SYSFW + default "sysfw.itb" + help + Filename of the combined System Firmware and configuration image tree + blob to be loaded when booting from a filesystem. + +config K3_SYSFW_IMAGE_SIZE_MAX + int "Amount of memory dynamically allocated for loading SYSFW blob" + depends on K3_LOAD_SYSFW + default 269000 + help + Amount of memory (in bytes) reserved through dynamic allocation at + runtime for loading the combined System Firmware and configuration image + tree blob. Keep it as tight as possible, as this directly affects the + overall SPL memory footprint. + config SYS_K3_SPL_ATF bool "Start Cortex-A from SPL" depends on SPL && CPU_V7R diff --git a/arch/arm/mach-k3/Makefile b/arch/arm/mach-k3/Makefile index 0c3a4f7db1..3af7f2ec96 100644 --- a/arch/arm/mach-k3/Makefile +++ b/arch/arm/mach-k3/Makefile @@ -7,4 +7,7 @@ obj-$(CONFIG_SOC_K3_AM6) += am6_init.o obj-$(CONFIG_ARM64) += arm64-mmu.o obj-$(CONFIG_CPU_V7R) += r5_mpu.o lowlevel_init.o obj-$(CONFIG_TI_SECURE_DEVICE) += security.o +ifeq ($(CONFIG_SPL_BUILD),y) +obj-$(CONFIG_K3_LOAD_SYSFW) += sysfw-loader.o +endif obj-y += common.o diff --git a/arch/arm/mach-k3/include/mach/sysfw-loader.h b/arch/arm/mach-k3/include/mach/sysfw-loader.h new file mode 100644 index 0000000000..c335c7ed92 --- /dev/null +++ b/arch/arm/mach-k3/include/mach/sysfw-loader.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Andreas Dannenberg <dannenb...@ti.com> + */ + +#ifndef _SYSFW_LOADER_H_ +#define _SYSFW_LOADER_H_ + +void k3_sysfw_loader(void (*config_pm_done_callback)(void)); + +#endif diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c new file mode 100644 index 0000000000..1191640acd --- /dev/null +++ b/arch/arm/mach-k3/sysfw-loader.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * K3: System Firmware Loader + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * Andreas Dannenberg <dannenb...@ti.com> + */ + +#include <common.h> +#include <spl.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/pinctrl.h> +#include <remoteproc.h> +#include <linux/libfdt.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <image.h> +#include <malloc.h> +#include <fs_loader.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/spl.h> +#include <asm/sections.h> +#include <asm/armv7_mpu.h> +#include <asm/arch/hardware.h> + +/* Name of the FIT image nodes for SYSFW and its config data */ +#define SYSFW_FIRMWARE "sysfw.bin" +#define SYSFW_CFG_BOARD "board-cfg.bin" +#define SYSFW_CFG_PM "pm-cfg.bin" +#define SYSFW_CFG_RM "rm-cfg.bin" +#define SYSFW_CFG_SEC "sec-cfg.bin" + +static int fit_get_data_by_name(const void *fit, int images, const char *name, + const void **addr, size_t *size) +{ + int node_offset; + + node_offset = fdt_subnode_offset(fit, images, name); + if (node_offset < 0) + return -ENOENT; + + return fit_image_get_data(fit, node_offset, addr, size); +} + +static void k3_sysfw_load_using_fit(void *fit, struct ti_sci_handle **ti_sci) +{ + int images; + const void *sysfw_addr; + size_t sysfw_size; + struct udevice *dev; + int ret; + + /* Find the node holding the images information */ + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) + panic("Cannot find /images node (%d)\n", images); + + /* Extract System Firmware (SYSFW) image from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE, + &sysfw_addr, &sysfw_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE, + ret); + + /* + * Start up system controller firmware + * + * It is assumed that remoteproc device 0 is the corresponding + * system-controller that runs SYSFW. Make sure DT reflects the same. + */ + ret = rproc_dev_init(0); + if (ret) + panic("rproc failed to be initialized (%d)\n", ret); + + ret = rproc_load(0, (ulong)sysfw_addr, (ulong)sysfw_size); + if (ret) + panic("Firmware failed to start on rproc (%d)\n", ret); + + ret = rproc_start(0); + if (ret) + panic("Firmware init failed on rproc (%d)\n", ret); + + /* Bring up the Device Management and Security Controller (SYSFW) */ + ret = uclass_get_device_by_name(UCLASS_FIRMWARE, "dmsc", &dev); + if (ret) + panic("Failed to initialize SYSFW (%d)\n", ret); + + /* Establish handle for easier access */ + *ti_sci = (struct ti_sci_handle *)(ti_sci_get_handle_from_sysfw(dev)); +} + +static void k3_sysfw_configure_using_fit(void *fit, + struct ti_sci_handle *ti_sci, + void (*config_pm_done_callback)(void)) +{ + struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops; + int images; + const void *cfg_fragment_addr; + size_t cfg_fragment_size; + int ret; + + /* Find the node holding the images information */ + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) + panic("Cannot find /images node (%d)\n", images); + + /* Extract board configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD, + ret); + + /* Apply board configuration to SYSFW */ + ret = board_ops->board_config(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board configuration (%d)\n", ret); + + /* Extract power/clock (PM) specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM, + ret); + + /* Apply power/clock (PM) specific configuration to SYSFW */ + ret = board_ops->board_config_pm(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board PM configuration (%d)\n", ret); + + /* Extract resource management (RM) specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM, + ret); + + /* Apply resource management (RM) configuration to SYSFW */ + ret = board_ops->board_config_rm(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board RM configuration (%d)\n", ret); + + /* Extract security specific configuration from FIT */ + ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC, + &cfg_fragment_addr, &cfg_fragment_size); + if (ret < 0) + panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC, + ret); + + /* Apply security configuration to SYSFW */ + ret = board_ops->board_config_security(ti_sci, + (u64)(u32)cfg_fragment_addr, + (u32)cfg_fragment_size); + if (ret) + panic("Failed to set board security configuration (%d)\n", + ret); + + /* + * Now that all clocks and PM aspects are setup, invoke a user- + * provided callback function. Usually this callback would be used + * to setup or re-configure the U-Boot console UART. + */ + if (config_pm_done_callback) + config_pm_done_callback(); +} + +static int k3_sysfw_load_mmc_fs(const char *filename, void *buf, size_t max_size) +{ + int mmc_dev; + struct udevice *mmcdev; + struct mmc *mmc; + struct udevice *fsdev; + struct device_platdata *plat; + int ret; + + /* Bring up the MMC boot device */ + + mmc_dev = spl_mmc_get_device_index(spl_boot_device()); + if (mmc_dev < 0) { + pr_err("%s: Getting MMC device index failed (%d)\n", __func__, + mmc_dev); + return mmc_dev; + } + + ret = uclass_get_device(UCLASS_MMC, mmc_dev, &mmcdev); + if (ret < 0) { + pr_err("%s: Getting MMC device failed (%d)\n", __func__, ret); + return ret; + } + + ret = mmc_initialize(NULL); + if (ret < 0) { + pr_err("%s: Initializing MMC device failed (%d)\n", __func__, + ret); + return ret; + } + + mmc = mmc_get_mmc_dev(mmcdev); + if (!mmc) { + pr_err("%s: Getting underlying MMC device failed\n", __func__); + return -ENODEV; + } + + ret = mmc_init(mmc); + if (ret) { + printf("%s: mmc init failed with error: %d\n", __func__, ret); + return ret; + } + + /* Use the FS loader framework to perform the actual FW loading */ + + ret = uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &fsdev); + if (ret < 0) { + pr_err("%s: Getting FW loader device failed (%d)\n", __func__, + ret); + return ret; + } + + plat = fsdev->platdata; + plat->blkdev = mmcdev; + plat->blkpart = CONFIG_SYS_MMCSD_FS_BOOT_PARTITION; + + return request_firmware_into_buf(fsdev, filename, buf, max_size, 0); +} + +void k3_sysfw_loader(void (*config_pm_done_callback)(void)) +{ + void *addr; + struct spl_boot_device bootdev = { 0 }; + struct ti_sci_handle *ti_sci; + u32 boot_mode; + int ret; + + addr = memalign(ARCH_DMA_MINALIGN, CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); + if (!addr) + panic("Error allocating %u bytes of memory for SYSFW image\n", + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); + + debug("%s: allocated %u bytes at 0x%p\n", __func__, + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, addr); + + bootdev.boot_device = spl_boot_device(); + boot_mode = spl_boot_mode(bootdev.boot_device); + + /* Load combined System Controller firmware and config data image */ + switch (bootdev.boot_device) { +#if CONFIG_IS_ENABLED(MMC_SUPPORT) + case BOOT_DEVICE_MMC1: + case BOOT_DEVICE_MMC2: + case BOOT_DEVICE_MMC2_2: +#ifdef CONFIG_K3_SYSFW_IMAGE_NAME + if (boot_mode == MMCSD_MODE_FS) { + ret = k3_sysfw_load_mmc_fs(CONFIG_K3_SYSFW_IMAGE_NAME, + addr, + CONFIG_K3_SYSFW_IMAGE_SIZE_MAX); + } else +#endif + { + panic("Non-FS load of SYSFW image from device %u not supported!\n", + bootdev.boot_device); + } + break; +#endif + default: + panic("Loading SYSFW image from device %u not supported!\n", + bootdev.boot_device); + } + + if (ret < 0) + panic("Error %d occurred during loading SYSFW image!\n", ret); + + /* Ensure the SYSFW image is in FIT format */ + if (image_get_magic((const image_header_t *)addr) != FDT_MAGIC) + panic("SYSFW image not in FIT format!\n"); + + /* Extract and start SYSFW */ + k3_sysfw_load_using_fit(addr, &ti_sci); + + /* Parse and apply the different SYSFW configuration fragments */ + k3_sysfw_configure_using_fit(addr, ti_sci, config_pm_done_callback); + + /* Output System Firmware version info */ + printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%.*s')\n", + ti_sci->version.abi_major, ti_sci->version.abi_minor, + ti_sci->version.firmware_revision, + sizeof(ti_sci->version.firmware_description), + ti_sci->version.firmware_description); +} -- 2.17.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot