diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/root.c | 12 | ||||
-rw-r--r-- | drivers/crypto/fsl/Kconfig | 10 | ||||
-rw-r--r-- | drivers/crypto/fsl/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/fsl/dcp_rng.c | 182 | ||||
-rw-r--r-- | drivers/fpga/socfpga_arria10.c | 28 | ||||
-rw-r--r-- | drivers/gpio/gpio-uclass.c | 31 | ||||
-rw-r--r-- | drivers/misc/fs_loader.c | 27 | ||||
-rw-r--r-- | drivers/net/fm/fm.c | 40 | ||||
-rw-r--r-- | drivers/net/fm/fm.h | 2 | ||||
-rw-r--r-- | drivers/qe/Kconfig | 4 |
10 files changed, 279 insertions, 58 deletions
diff --git a/drivers/core/root.c b/drivers/core/root.c index f24ddfa5218..c4fb48548bb 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -363,20 +363,22 @@ void *dm_priv_to_rw(void *priv) static int dm_probe_devices(struct udevice *dev, bool pre_reloc_only) { - u32 mask = DM_FLAG_PROBE_AFTER_BIND; - u32 flags = dev_get_flags(dev); + ofnode node = dev_ofnode(dev); struct udevice *child; int ret; - if (pre_reloc_only) - mask |= DM_FLAG_PRE_RELOC; + if (pre_reloc_only && + (!ofnode_valid(node) || !ofnode_pre_reloc(node)) && + !(dev->driver->flags & DM_FLAG_PRE_RELOC)) + goto probe_children; - if ((flags & mask) == mask) { + if (dev_get_flags(dev) & DM_FLAG_PROBE_AFTER_BIND) { ret = device_probe(dev); if (ret) return ret; } +probe_children: list_for_each_entry(child, &dev->child_head, sibling_node) dm_probe_devices(child, pre_reloc_only); diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig index b04c70183d2..91a51cc5fe7 100644 --- a/drivers/crypto/fsl/Kconfig +++ b/drivers/crypto/fsl/Kconfig @@ -73,3 +73,13 @@ config FSL_CAAM_RNG reseeded from the TRNG every time random data is generated. endif + +config FSL_DCP_RNG + bool "Enable Random Number Generator support" + depends on DM_RNG + default n + help + Enable support for the hardware based random number generator + module of the DCP. It uses the True Random Number Generator (TRNG) + and a Pseudo-Random Number Generator (PRNG) to achieve a true + randomness and cryptographic strength. diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile index f9c3ccecfc2..7a2543e16cc 100644 --- a/drivers/crypto/fsl/Makefile +++ b/drivers/crypto/fsl/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o obj-$(CONFIG_CMD_BLOB)$(CONFIG_IMX_CAAM_DEK_ENCAP) += fsl_blob.o obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o obj-$(CONFIG_FSL_CAAM_RNG) += rng.o +obj-$(CONFIG_FSL_DCP_RNG) += dcp_rng.o obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o diff --git a/drivers/crypto/fsl/dcp_rng.c b/drivers/crypto/fsl/dcp_rng.c new file mode 100644 index 00000000000..31706960157 --- /dev/null +++ b/drivers/crypto/fsl/dcp_rng.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RNG driver for Freescale RNGC + * + * Copyright 2022 NXP + * + * Based on RNGC driver in drivers/char/hw_random/imx-rngc.c in Linux + */ + +#include <common.h> +#include <cpu_func.h> +#include <dm.h> +#include <rng.h> +#include <asm/cache.h> +#include <asm/io.h> +#include <dm/root.h> +#include <linux/delay.h> +#include <linux/kernel.h> + +#define DCP_RNG_MAX_FIFO_STORE_SIZE 4 +#define RNGC_VER_ID 0x0 +#define RNGC_COMMAND 0x4 +#define RNGC_CONTROL 0x8 +#define RNGC_STATUS 0xC +#define RNGC_ERROR 0x10 +#define RNGC_FIFO 0x14 + +/* the fields in the ver id register */ +#define RNGC_TYPE_SHIFT 28 + +/* the rng_type field */ +#define RNGC_TYPE_RNGB 0x1 +#define RNGC_TYPE_RNGC 0x2 + +#define RNGC_CMD_CLR_ERR 0x20 +#define RNGC_CMD_SEED 0x2 + +#define RNGC_CTRL_AUTO_SEED 0x10 + +#define RNGC_STATUS_ERROR 0x10000 +#define RNGC_STATUS_FIFO_LEVEL_MASK 0xf00 +#define RNGC_STATUS_FIFO_LEVEL_SHIFT 8 +#define RNGC_STATUS_SEED_DONE 0x20 +#define RNGC_STATUS_ST_DONE 0x10 + +#define RNGC_ERROR_STATUS_STAT_ERR 0x8 + +#define RNGC_TIMEOUT 3000000U /* 3 sec */ + +struct imx_rngc_priv { + unsigned long base; +}; + +static int rngc_read(struct udevice *dev, void *data, size_t len) +{ + struct imx_rngc_priv *priv = dev_get_priv(dev); + u8 buffer[DCP_RNG_MAX_FIFO_STORE_SIZE]; + u32 status, level; + size_t size; + + while (len) { + status = readl(priv->base + RNGC_STATUS); + + /* is there some error while reading this random number? */ + if (status & RNGC_STATUS_ERROR) + break; + /* how many random numbers are in FIFO? [0-16] */ + level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >> + RNGC_STATUS_FIFO_LEVEL_SHIFT; + + if (level) { + /* retrieve a random number from FIFO */ + *(u32 *)buffer = readl(priv->base + RNGC_FIFO); + size = min(len, sizeof(u32)); + memcpy(data, buffer, size); + data += size; + len -= size; + } + } + + return len ? -EIO : 0; +} + +static int rngc_init(struct imx_rngc_priv *priv) +{ + u32 cmd, ctrl, status, err_reg = 0; + unsigned long long timeval = 0; + unsigned long long timeout = RNGC_TIMEOUT; + + /* clear error */ + cmd = readl(priv->base + RNGC_COMMAND); + writel(cmd | RNGC_CMD_CLR_ERR, priv->base + RNGC_COMMAND); + + /* create seed, repeat while there is some statistical error */ + do { + /* seed creation */ + cmd = readl(priv->base + RNGC_COMMAND); + writel(cmd | RNGC_CMD_SEED, priv->base + RNGC_COMMAND); + + udelay(1); + timeval += 1; + + status = readl(priv->base + RNGC_STATUS); + err_reg = readl(priv->base + RNGC_ERROR); + + if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE)) + break; + + if (timeval > timeout) { + debug("rngc timed out\n"); + return -ETIMEDOUT; + } + } while (err_reg == RNGC_ERROR_STATUS_STAT_ERR); + + if (err_reg) + return -EIO; + + /* + * enable automatic seeding, the rngc creates a new seed automatically + * after serving 2^20 random 160-bit words + */ + ctrl = readl(priv->base + RNGC_CONTROL); + ctrl |= RNGC_CTRL_AUTO_SEED; + writel(ctrl, priv->base + RNGC_CONTROL); + return 0; +} + +static int rngc_probe(struct udevice *dev) +{ + struct imx_rngc_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + u32 ver_id; + u8 rng_type; + int ret; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) { + ret = -EINVAL; + goto err; + } + + priv->base = addr; + ver_id = readl(priv->base + RNGC_VER_ID); + rng_type = ver_id >> RNGC_TYPE_SHIFT; + /* + * This driver supports only RNGC and RNGB. (There's a different + * driver for RNGA.) + */ + if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) { + ret = -ENODEV; + goto err; + } + + ret = rngc_init(priv); + if (ret) + goto err; + + return 0; + +err: + printf("%s error = %d\n", __func__, ret); + return ret; +} + +static const struct dm_rng_ops rngc_ops = { + .read = rngc_read, +}; + +static const struct udevice_id rngc_dt_ids[] = { + { .compatible = "fsl,imx25-rngb" }, + { } +}; + +U_BOOT_DRIVER(dcp_rng) = { + .name = "dcp_rng", + .id = UCLASS_RNG, + .of_match = rngc_dt_ids, + .ops = &rngc_ops, + .probe = rngc_probe, + .priv_auto = sizeof(struct imx_rngc_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index 3b785e67d0b..96b195063e0 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -777,42 +777,20 @@ int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize, { struct fpga_loadfs_info fpga_loadfs; struct udevice *dev; - int status, ret, size; + int status, ret; u32 buffer = (uintptr_t)buf; size_t buffer_sizebytes = bsize; size_t buffer_sizebytes_ori = bsize; size_t total_sizeof_image = 0; ofnode node; - const fdt32_t *phandle_p; - u32 phandle; node = get_fpga_mgr_ofnode(ofnode_null()); - - if (ofnode_valid(node)) { - phandle_p = ofnode_get_property(node, "firmware-loader", &size); - if (!phandle_p) { - node = ofnode_path("/chosen"); - if (!ofnode_valid(node)) { - debug("FPGA: /chosen node was not found.\n"); - return -ENOENT; - } - - phandle_p = ofnode_get_property(node, "firmware-loader", - &size); - if (!phandle_p) { - debug("FPGA: firmware-loader property was not"); - debug(" found.\n"); - return -ENOENT; - } - } - } else { + if (!ofnode_valid(node)) { debug("FPGA: FPGA manager node was not found.\n"); return -ENOENT; } - phandle = fdt32_to_cpu(*phandle_p); - ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER, - phandle, &dev); + ret = get_fs_loader(&dev); if (ret) return ret; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 3a6ef3b01d5..dbebf3a53eb 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -311,34 +311,11 @@ static int gpio_hog_probe(struct udevice *dev) return 0; } -int gpio_hog_probe_all(void) -{ - struct udevice *dev; - int ret; - int retval = 0; - - for (uclass_first_device(UCLASS_NOP, &dev); - dev; - uclass_find_next_device(&dev)) { - if (dev->driver == DM_DRIVER_GET(gpio_hog)) { - ret = device_probe(dev); - if (ret) { - printf("Failed to probe device %s err: %d\n", - dev->name, ret); - retval = ret; - } - } - } - - return retval; -} - int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc) { struct udevice *dev; *desc = NULL; - gpio_hog_probe_all(); if (!uclass_get_device_by_name(UCLASS_NOP, name, &dev)) { struct gpio_hog_priv *priv = dev_get_priv(dev); @@ -1505,9 +1482,17 @@ static int gpio_post_bind(struct udevice *dev) &child); if (ret) return ret; + + /* + * Make sure gpio-hogs are probed after bind + * since hogs can be essential to the hardware + * system. + */ + dev_or_flags(child, DM_FLAG_PROBE_AFTER_BIND); } } } + return 0; } diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c index 5b4d03639c3..ccf5c7a8037 100644 --- a/drivers/misc/fs_loader.c +++ b/drivers/misc/fs_loader.c @@ -15,6 +15,8 @@ #include <fs_loader.h> #include <log.h> #include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/root.h> #include <linux/string.h> #include <mapmem.h> #include <malloc.h> @@ -297,6 +299,31 @@ U_BOOT_DRIVER(fs_loader) = { .priv_auto = sizeof(struct firmware), }; +static struct device_plat default_plat = { 0 }; + +int get_fs_loader(struct udevice **dev) +{ + int ret; + ofnode node = ofnode_get_chosen_node("firmware-loader"); + + if (ofnode_valid(node)) + return uclass_get_device_by_ofnode(UCLASS_FS_FIRMWARE_LOADER, + node, dev); + + /* Try the first device if none was chosen */ + ret = uclass_first_device_err(UCLASS_FS_FIRMWARE_LOADER, dev); + if (ret != -ENODEV) + return ret; + + /* Just create a new device */ + ret = device_bind(dm_root(), DM_DRIVER_GET(fs_loader), "default-loader", + &default_plat, ofnode_null(), dev); + if (ret) + return ret; + + return device_probe(*dev); +} + UCLASS_DRIVER(fs_loader) = { .id = UCLASS_FS_FIRMWARE_LOADER, .name = "fs-loader", diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index 055dd61fbe5..e1fba24471c 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -5,9 +5,11 @@ */ #include <common.h> #include <env.h> +#include <fs_loader.h> #include <image.h> #include <malloc.h> #include <asm/io.h> +#include <dm/device_compat.h> #include <linux/errno.h> #include <u-boot/crc.h> #include <dm.h> @@ -353,7 +355,7 @@ static void fm_init_qmi(struct fm_qmi_common *qmi) /* Init common part of FM, index is fm num# like fm as above */ #ifdef CONFIG_TFABOOT -int fm_init_common(int index, struct ccsr_fman *reg) +int fm_init_common(int index, struct ccsr_fman *reg, const char *firmware_name) { int rc; void *addr = NULL; @@ -448,10 +450,32 @@ int fm_init_common(int index, struct ccsr_fman *reg) return fm_init_bmi(index, ®->fm_bmi_common); } #else -int fm_init_common(int index, struct ccsr_fman *reg) +int fm_init_common(int index, struct ccsr_fman *reg, const char *firmware_name) { int rc; -#if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR) +#if defined(CONFIG_SYS_QE_FMAN_FW_IN_FS) + struct udevice *fs_loader; + void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); + + if (!addr) + return -ENOMEM; + + rc = get_fs_loader(&fs_loader); + if (rc) { + debug("could not get fs loader: %d\n", rc); + return rc; + } + + if (!firmware_name) + firmware_name = "fman.itb"; + + rc = request_firmware_into_buf(fs_loader, firmware_name, addr, + CONFIG_SYS_QE_FMAN_FW_LENGTH, 0); + if (rc < 0) { + debug("could not request %s: %d\n", firmware_name, rc); + return rc; + } +#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR) void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR; #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND) size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH; @@ -561,6 +585,8 @@ static const struct udevice_id fman_ids[] = { static int fman_probe(struct udevice *dev) { + const char *firmware_name = NULL; + int ret; struct fman_priv *priv = dev_get_priv(dev); priv->reg = (struct ccsr_fman *)(uintptr_t)dev_read_addr(dev); @@ -570,7 +596,13 @@ static int fman_probe(struct udevice *dev) return -EINVAL; } - return fm_init_common(priv->fman_id, priv->reg); + ret = dev_read_string_index(dev, "firmware-name", 0, &firmware_name); + if (ret && ret != -EINVAL) { + dev_dbg(dev, "Could not read firmware-name\n"); + return ret; + } + + return fm_init_common(priv->fman_id, priv->reg, firmware_name); } static int fman_remove(struct udevice *dev) diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h index ba858cc24b0..a2d5b03429a 100644 --- a/drivers/net/fm/fm.h +++ b/drivers/net/fm/fm.h @@ -106,7 +106,7 @@ struct fm_port_global_pram { void *fm_muram_alloc(int fm_idx, size_t size, ulong align); void *fm_muram_base(int fm_idx); -int fm_init_common(int index, struct ccsr_fman *reg); +int fm_init_common(int index, struct ccsr_fman *reg, const char *firmware_name); int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info); phy_interface_t fman_port_enet_if(enum fm_port port); void fman_disable_port(enum fm_port port); diff --git a/drivers/qe/Kconfig b/drivers/qe/Kconfig index c44a81f69a5..89a75c175b0 100644 --- a/drivers/qe/Kconfig +++ b/drivers/qe/Kconfig @@ -27,6 +27,10 @@ choice depends on FMAN_ENET || QE default SYS_QE_FMAN_FW_IN_ROM +config SYS_QE_FMAN_FW_IN_FS + depends on FS_LOADER && FMAN_ENET + bool "Filesystem" + config SYS_QE_FMAN_FW_IN_NOR bool "NOR flash" |