summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2022-07-11 10:18:13 -0400
committerTom Rini <[email protected]>2022-07-11 14:58:57 -0400
commit36b661dc919da318c163a45f4a220d2e3d9db608 (patch)
tree268703050f58280feb3287d48eb0cedc974730e1 /drivers/misc
parente092e3250270a1016c877da7bdd9384f14b1321e (diff)
parent05a4859637567b13219efd6f1707fb236648b1b7 (diff)
Merge branch 'next'
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig82
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/i2c_eeprom.c11
-rw-r--r--drivers/misc/i2c_eeprom_emul.c4
-rw-r--r--drivers/misc/ls2_sfp.c350
-rw-r--r--drivers/misc/misc_sandbox.c3
-rw-r--r--drivers/misc/npcm_host_intf.c110
-rw-r--r--drivers/misc/npcm_otp.c512
-rw-r--r--drivers/misc/nvmem.c142
-rw-r--r--drivers/misc/qfw_sandbox.c2
-rw-r--r--drivers/misc/stm32_rcc.c6
-rw-r--r--drivers/misc/test_drv.c6
12 files changed, 1209 insertions, 23 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 007c72819fb..e839c08c191 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -43,6 +43,22 @@ config VPL_MISC
set of generic read, write and ioctl methods may be used to
access the device.
+config NVMEM
+ bool "NVMEM support"
+ help
+ This adds support for a common interface to different types of
+ non-volatile memory. Consumers can use nvmem-cells properties to look
+ up hardware configuration data such as MAC addresses and calibration
+ settings.
+
+config SPL_NVMEM
+ bool "NVMEM support in SPL"
+ help
+ This adds support for a common interface to different types of
+ non-volatile memory. Consumers can use nvmem-cells properties to look
+ up hardware configuration data such as MAC addresses and calibration
+ settings.
+
config ALTERA_SYSID
bool "Altera Sysid support"
depends on MISC
@@ -125,7 +141,7 @@ config CROS_EC
config SPL_CROS_EC
bool "Enable Chrome OS EC in SPL"
- depends on SPL
+ depends on SPL_MISC
help
Enable access to the Chrome OS EC in SPL. This is a separate
microcontroller typically available on a SPI bus on Chromebooks. It
@@ -135,7 +151,7 @@ config SPL_CROS_EC
config TPL_CROS_EC
bool "Enable Chrome OS EC in TPL"
- depends on TPL
+ depends on TPL_MISC
help
Enable access to the Chrome OS EC in TPL. This is a separate
microcontroller typically available on a SPI bus on Chromebooks. It
@@ -145,7 +161,7 @@ config TPL_CROS_EC
config VPL_CROS_EC
bool "Enable Chrome OS EC in VPL"
- depends on VPL
+ depends on VPL_MISC
help
Enable access to the Chrome OS EC in VPL. This is a separate
microcontroller typically available on a SPI bus on Chromebooks. It
@@ -173,7 +189,7 @@ config CROS_EC_LPC
config SPL_CROS_EC_LPC
bool "Enable Chrome OS EC LPC driver in SPL"
- depends on CROS_EC
+ depends on CROS_EC && SPL_MISC
help
Enable I2C access to the Chrome OS EC. This is used on x86
Chromebooks such as link and falco. The keyboard is provided
@@ -182,7 +198,7 @@ config SPL_CROS_EC_LPC
config TPL_CROS_EC_LPC
bool "Enable Chrome OS EC LPC driver in TPL"
- depends on CROS_EC
+ depends on CROS_EC && TPL_MISC
help
Enable I2C access to the Chrome OS EC. This is used on x86
Chromebooks such as link and falco. The keyboard is provided
@@ -191,7 +207,7 @@ config TPL_CROS_EC_LPC
config VPL_CROS_EC_LPC
bool "Enable Chrome OS EC LPC driver in VPL"
- depends on CROS_EC
+ depends on CROS_EC && VPL_MISC
help
Enable I2C access to the Chrome OS EC. This is used on x86
Chromebooks such as link and falco. The keyboard is provided
@@ -259,6 +275,20 @@ config FSL_SEC_MON
Security Monitor can be transitioned on any security failures,
like software violations or hardware security violations.
+choice
+ prompt "Security monitor interaction endianess"
+ depends on FSL_SEC_MON
+ default SYS_FSL_SEC_MON_BE if PPC
+ default SYS_FSL_SEC_MON_LE
+
+config SYS_FSL_SEC_MON_LE
+ bool "Security monitor interactions are little endian"
+
+config SYS_FSL_SEC_MON_BE
+ bool "Security monitor interactions are big endian"
+
+endchoice
+
config IRQ
bool "Interrupt controller"
help
@@ -273,6 +303,20 @@ config JZ4780_EFUSE
help
This selects support for the eFUSE on Ingenic JZ4780 SoCs.
+config LS2_SFP
+ bool "Layerscape Security Fuse Processor"
+ depends on FSL_LSCH2 || ARCH_LS1021A
+ depends on MISC
+ imply DM_REGULATOR
+ help
+ This adds support for the Security Fuse Processor found on Layerscape
+ SoCs. It contains various fuses related to secure boot, including the
+ Super Root Key hash, One-Time-Programmable Master Key, Debug
+ Challenge/Response values, and others. Fuses are numbered according
+ to their four-byte offset from the start of the bank.
+
+ If you don't need to read/program fuses, say 'n'.
+
config MXC_OCOTP
bool "Enable MXC OCOTP Driver"
depends on ARCH_IMX8M || ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_VF610
@@ -282,15 +326,30 @@ config MXC_OCOTP
Programmable memory pages that are stored on the some
Freescale i.MX processors.
+config NPCM_HOST
+ bool "Enable support espi or LPC for Host"
+ depends on REGMAP && SYSCON
+ help
+ Enable NPCM BMC espi or LPC support for Host reading and writing.
+
config SPL_MXC_OCOTP
bool "Enable MXC OCOTP driver in SPL"
- depends on SPL && (ARCH_IMX8M || ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_VF610)
+ depends on SPL_MISC && (ARCH_IMX8M || ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_VF610)
default y
help
If you say Y here, you will get support for the One Time
Programmable memory pages, that are stored on some
Freescale i.MX processors, in SPL.
+config NPCM_OTP
+ bool "Nnvoton NPCM BMC On-Chip OTP Memory Support"
+ depends on (ARM && ARCH_NPCM)
+ default n
+ help
+ Support NPCM BMC OTP memory (fuse).
+ To compile this driver as a module, choose M here: the module
+ will be called npcm_otp.
+
config NUVOTON_NCT6102D
bool "Enable Nuvoton NCT6102D Super I/O driver"
help
@@ -314,7 +373,7 @@ config P2SB
config SPL_P2SB
bool "Intel Primary to Sideband Bridge in SPL"
- depends on SPL && (X86 || SANDBOX)
+ depends on SPL_MISC && (X86 || SANDBOX)
help
The Primary to Sideband Bridge is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
@@ -324,7 +383,7 @@ config SPL_P2SB
config TPL_P2SB
bool "Intel Primary to Sideband Bridge in TPL"
- depends on TPL && (X86 || SANDBOX)
+ depends on TPL_MISC && (X86 || SANDBOX)
help
The Primary to Sideband Bridge is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
@@ -343,7 +402,7 @@ config PWRSEQ
config SPL_PWRSEQ
bool "Enable power-sequencing drivers for SPL"
- depends on PWRSEQ
+ depends on SPL_MISC && PWRSEQ
help
Power-sequencing drivers provide support for controlling power for
devices. They are typically referenced by a phandle from another
@@ -460,7 +519,7 @@ config I2C_EEPROM
config SPL_I2C_EEPROM
bool "Enable driver for generic I2C-attached EEPROMs for SPL"
- depends on MISC && SPL && SPL_DM
+ depends on SPL_MISC
help
This option is an SPL-variant of the I2C_EEPROM option.
See the help of I2C_EEPROM for details.
@@ -513,6 +572,7 @@ config FS_LOADER
config SPL_FS_LOADER
bool "Enable loader driver for file system"
+ depends on SPL
help
This is file system generic loader which can be used to load
the file image from the storage into target such as memory.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b9c54bdd99b..022e54e0650 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,6 +4,7 @@
# Wolfgang Denk, DENX Software Engineering, [email protected].
obj-$(CONFIG_$(SPL_TPL_)MISC) += misc-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)NVMEM) += nvmem.o
obj-$(CONFIG_$(SPL_TPL_)CROS_EC) += cros_ec.o
obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o
@@ -52,8 +53,11 @@ obj-$(CONFIG_IMX8ULP) += imx8ulp/
obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
+obj-$(CONFIG_$(SPL_TPL_)LS2_SFP) += ls2_sfp.o
obj-$(CONFIG_$(SPL_)MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
+obj-$(CONFIG_NPCM_OTP) += npcm_otp.o
+obj-$(CONFIG_NPCM_HOST) += npcm_host_intf.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index 89a450d0f8d..bdd7e018cc6 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -33,7 +33,8 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
return ops->read(dev, offset, buf, size);
}
-int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
+int i2c_eeprom_write(struct udevice *dev, int offset, const uint8_t *buf,
+ int size)
{
const struct i2c_eeprom_ops *ops = device_get_ops(dev);
@@ -169,13 +170,6 @@ static const struct i2c_eeprom_drv_data eeprom_data = {
.offset_len = 1,
};
-static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
- .size = 256,
- .pagesize = 8,
- .addr_offset_mask = 0,
- .offset_len = 1,
-};
-
static const struct i2c_eeprom_drv_data atmel24c01a_data = {
.size = 128,
.pagesize = 8,
@@ -263,7 +257,6 @@ static const struct i2c_eeprom_drv_data atmel24c512_data = {
static const struct udevice_id i2c_eeprom_std_ids[] = {
{ .compatible = "i2c-eeprom", (ulong)&eeprom_data },
- { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
{ .compatible = "atmel,24c01", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c
index 85b127c406c..6f32087ede5 100644
--- a/drivers/misc/i2c_eeprom_emul.c
+++ b/drivers/misc/i2c_eeprom_emul.c
@@ -171,11 +171,15 @@ static int sandbox_i2c_eeprom_probe(struct udevice *dev)
{
struct sandbox_i2c_flash_plat_data *plat = dev_get_plat(dev);
struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+ /* For eth3 */
+ const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x45 };
priv->data = calloc(1, plat->size);
if (!priv->data)
return -ENOMEM;
+ memcpy(&priv->data[24], mac, sizeof(mac));
+
return 0;
}
diff --git a/drivers/misc/ls2_sfp.c b/drivers/misc/ls2_sfp.c
new file mode 100644
index 00000000000..dd104962c28
--- /dev/null
+++ b/drivers/misc/ls2_sfp.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Sean Anderson <[email protected]>
+ *
+ * This driver supports the Security Fuse Processor device found on some
+ * Layerscape processors. At the moment, we only support a few processors.
+ * This driver was written with reference to the Layerscape SDK User
+ * Guide [1] and the ATF SFP driver [2].
+ *
+ * [1] https://docs.nxp.com/bundle/GUID-487B2E69-BB19-42CB-AC38-7EF18C0FE3AE/page/GUID-27FC40AD-3321-4A82-B29E-7BB49EE94F23.html
+ * [2] https://source.codeaurora.org/external/qoriq/qoriq-components/atf/tree/drivers/nxp/sfp?h=github.com/master
+ */
+
+#define LOG_CATEGORY UCLASS_MISC
+#include <common.h>
+#include <clk.h>
+#include <fuse.h>
+#include <misc.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <linux/bitfield.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SFP_INGR 0x20
+#define SFP_SVHESR 0x24
+#define SFP_SFPCR 0x28
+
+#define SFP_START 0x200
+#define SFP_END 0x284
+#define SFP_SIZE (SFP_END - SFP_START + 4)
+
+#define SFP_INGR_ERR BIT(8)
+#define SFP_INGR_INST GENMASK(7, 0)
+
+#define SFP_INGR_READFB 0x01
+#define SFP_INGR_PROGFB 0x02
+
+#define SFP_SFPCR_PPW GENMASK(15, 0)
+
+enum ls2_sfp_ioctl {
+ LS2_SFP_IOCTL_READ,
+ LS2_SFP_IOCTL_PROG,
+};
+
+/**
+ * struct ls2_sfp_priv - private data for LS2 SFP
+ * @base: Base address of SFP
+ * @supply: The (optional) supply for TA_PROG_SFP
+ * @programmed: Whether we've already programmed the fuses since the last
+ * reset. The SFP has a *very* limited amount of programming
+ * cycles (two to six, depending on the model), so we try and
+ * prevent accidentally performing additional programming
+ * cycles.
+ * @dirty: Whether the mirror registers have been written to (overridden)
+ * since we've last read the fuses (either as part of the reset
+ * process or using a READFB instruction). There is a much larger,
+ * but still finite, limit on the number of SFP read cycles (around
+ * 300,000), so we try and minimize reads as well.
+ */
+struct ls2_sfp_priv {
+ void __iomem *base;
+ struct udevice *supply;
+ bool programmed, dirty;
+};
+
+static u32 ls2_sfp_readl(struct ls2_sfp_priv *priv, ulong off)
+{
+ u32 val = be32_to_cpu(readl(priv->base + off));
+
+ log_debug("%08x = readl(%p)\n", val, priv->base + off);
+ return val;
+}
+
+static void ls2_sfp_writel(struct ls2_sfp_priv *priv, ulong val, ulong off)
+{
+ log_debug("writel(%08lx, %p)\n", val, priv->base + off);
+ writel(cpu_to_be32(val), priv->base + off);
+}
+
+static bool ls2_sfp_validate(struct udevice *dev, int offset, int size)
+{
+ if (offset < 0 || size < 0) {
+ dev_notice(dev, "size and offset must be positive\n");
+ return false;
+ }
+
+ if (offset & 3 || size & 3) {
+ dev_notice(dev, "size and offset must be multiples of 4\n");
+ return false;
+ }
+
+ if (offset + size > SFP_SIZE) {
+ dev_notice(dev, "size + offset must be <= %#x\n", SFP_SIZE);
+ return false;
+ }
+
+ return true;
+}
+
+static int ls2_sfp_read(struct udevice *dev, int offset, void *buf_bytes,
+ int size)
+{
+ int i;
+ struct ls2_sfp_priv *priv = dev_get_priv(dev);
+ u32 *buf = buf_bytes;
+
+ if (!ls2_sfp_validate(dev, offset, size))
+ return -EINVAL;
+
+ for (i = 0; i < size; i += 4)
+ buf[i >> 2] = ls2_sfp_readl(priv, SFP_START + offset + i);
+
+ return size;
+}
+
+static int ls2_sfp_write(struct udevice *dev, int offset,
+ const void *buf_bytes, int size)
+{
+ int i;
+ struct ls2_sfp_priv *priv = dev_get_priv(dev);
+ const u32 *buf = buf_bytes;
+
+ if (!ls2_sfp_validate(dev, offset, size))
+ return -EINVAL;
+
+ for (i = 0; i < size; i += 4)
+ ls2_sfp_writel(priv, buf[i >> 2], SFP_START + offset + i);
+
+ priv->dirty = true;
+ return size;
+}
+
+static int ls2_sfp_check_secret(struct udevice *dev)
+{
+ struct ls2_sfp_priv *priv = dev_get_priv(dev);
+ u32 svhesr = ls2_sfp_readl(priv, SFP_SVHESR);
+
+ if (svhesr) {
+ dev_warn(dev, "secret value hamming error not zero: %08x\n",
+ svhesr);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int ls2_sfp_transaction(struct ls2_sfp_priv *priv, ulong inst)
+{
+ u32 ingr;
+
+ ls2_sfp_writel(priv, inst, SFP_INGR);
+
+ do {
+ ingr = ls2_sfp_readl(priv, SFP_INGR);
+ } while (FIELD_GET(SFP_INGR_INST, ingr));
+
+ return FIELD_GET(SFP_INGR_ERR, ingr) ? -EIO : 0;
+}
+
+static int ls2_sfp_ioctl(struct udevice *dev, unsigned long request, void *buf)
+{
+ int ret;
+ struct ls2_sfp_priv *priv = dev_get_priv(dev);
+
+ switch (request) {
+ case LS2_SFP_IOCTL_READ:
+ if (!priv->dirty) {
+ dev_dbg(dev, "ignoring read request, since fuses are not dirty\n");
+ return 0;
+ }
+
+ ret = ls2_sfp_transaction(priv, SFP_INGR_READFB);
+ if (ret) {
+ dev_err(dev, "error reading fuses\n");
+ return ret;
+ }
+
+ ls2_sfp_check_secret(dev);
+ priv->dirty = false;
+ return 0;
+ case LS2_SFP_IOCTL_PROG:
+ if (priv->programmed) {
+ dev_warn(dev, "fuses already programmed\n");
+ return -EPERM;
+ }
+
+ ret = ls2_sfp_check_secret(dev);
+ if (ret)
+ return ret;
+
+ if (priv->supply) {
+ ret = regulator_set_enable(priv->supply, true);
+ if (ret)
+ return ret;
+ }
+
+ ret = ls2_sfp_transaction(priv, SFP_INGR_PROGFB);
+ priv->programmed = true;
+ if (priv->supply)
+ regulator_set_enable(priv->supply, false);
+
+ if (ret)
+ dev_err(dev, "error programming fuses\n");
+ return ret;
+ default:
+ dev_dbg(dev, "unknown ioctl %lu\n", request);
+ return -EINVAL;
+ }
+}
+
+static const struct misc_ops ls2_sfp_ops = {
+ .read = ls2_sfp_read,
+ .write = ls2_sfp_write,
+ .ioctl = ls2_sfp_ioctl,
+};
+
+static int ls2_sfp_probe(struct udevice *dev)
+{
+ int ret;
+ struct clk clk;
+ struct ls2_sfp_priv *priv = dev_get_priv(dev);
+ ulong rate;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base) {
+ dev_dbg(dev, "could not read register base\n");
+ return -EINVAL;
+ }
+
+ ret = device_get_supply_regulator(dev, "ta-sfp-prog", &priv->supply);
+ if (ret && ret != -ENODEV && ret != -ENOSYS) {
+ dev_dbg(dev, "problem getting supply (err %d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "sfp", &clk);
+ if (ret == -ENOSYS) {
+ rate = gd->bus_clk / 4;
+ } else if (ret) {
+ dev_dbg(dev, "could not get clock (err %d)\n", ret);
+ return ret;
+ } else {
+ ret = clk_enable(&clk);
+ if (ret) {
+ dev_dbg(dev, "could not enable clock (err %d)\n", ret);
+ return ret;
+ }
+
+ rate = clk_get_rate(&clk);
+ clk_free(&clk);
+ if (!rate || IS_ERR_VALUE(rate)) {
+ ret = rate ? rate : -ENOENT;
+ dev_dbg(dev, "could not get clock rate (err %d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /* sfp clock in MHz * 12 */
+ ls2_sfp_writel(priv, FIELD_PREP(SFP_SFPCR_PPW, rate * 12 / 1000000),
+ SFP_SFPCR);
+
+ ls2_sfp_check_secret(dev);
+ return 0;
+}
+
+static const struct udevice_id ls2_sfp_ids[] = {
+ { .compatible = "fsl,ls1021a-sfp" },
+ { }
+};
+
+U_BOOT_DRIVER(ls2_sfp) = {
+ .name = "ls2_sfp",
+ .id = UCLASS_MISC,
+ .of_match = ls2_sfp_ids,
+ .probe = ls2_sfp_probe,
+ .ops = &ls2_sfp_ops,
+ .priv_auto = sizeof(struct ls2_sfp_priv),
+};
+
+static int ls2_sfp_device(struct udevice **dev)
+{
+ int ret = uclass_get_device_by_driver(UCLASS_MISC,
+ DM_DRIVER_GET(ls2_sfp), dev);
+
+ if (ret)
+ log_debug("device not found (err %d)\n", ret);
+ return ret;
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ int ret;
+ struct udevice *dev;
+
+ ret = ls2_sfp_device(&dev);
+ if (ret)
+ return ret;
+
+ ret = misc_ioctl(dev, LS2_SFP_IOCTL_READ, NULL);
+ if (ret)
+ return ret;
+
+ ret = misc_read(dev, word << 2, val, sizeof(*val));
+ return ret < 0 ? ret : 0;
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ int ret;
+ struct udevice *dev;
+
+ ret = ls2_sfp_device(&dev);
+ if (ret)
+ return ret;
+
+ ret = misc_read(dev, word << 2, val, sizeof(*val));
+ return ret < 0 ? ret : 0;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int ret;
+ struct udevice *dev;
+
+ ret = ls2_sfp_device(&dev);
+ if (ret)
+ return ret;
+
+ ret = misc_write(dev, word << 2, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ return misc_ioctl(dev, LS2_SFP_IOCTL_PROG, NULL);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ int ret;
+ struct udevice *dev;
+
+ ret = ls2_sfp_device(&dev);
+ if (ret)
+ return ret;
+
+ ret = misc_write(dev, word << 2, &val, sizeof(val));
+ return ret < 0 ? ret : 0;
+}
diff --git a/drivers/misc/misc_sandbox.c b/drivers/misc/misc_sandbox.c
index 0e4292fd0aa..31cde2dbac0 100644
--- a/drivers/misc/misc_sandbox.c
+++ b/drivers/misc/misc_sandbox.c
@@ -112,8 +112,11 @@ static const struct misc_ops misc_sandbox_ops = {
int misc_sandbox_probe(struct udevice *dev)
{
struct misc_sandbox_priv *priv = dev_get_priv(dev);
+ /* For eth5 */
+ const u8 mac[] = { 0x02, 0x00, 0x11, 0x22, 0x33, 0x46 };
priv->enabled = true;
+ memcpy(&priv->mem[16], mac, sizeof(mac));
return 0;
}
diff --git a/drivers/misc/npcm_host_intf.c b/drivers/misc/npcm_host_intf.c
new file mode 100644
index 00000000000..0244e404570
--- /dev/null
+++ b/drivers/misc/npcm_host_intf.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Host interface (LPC or eSPI) configuration on Nuvoton BMC
+ * Copyright (c) 2022 Nuvoton Technology Corp.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+
+#define SMC_CTL_REG_ADDR 0xc0001001
+#define SMC_CTL_HOSTWAIT 0x80
+
+/* GCR Register Offsets */
+#define HIFCR 0x50
+#define MFSEL1 0x260
+#define MFSEL4 0x26c
+
+/* ESPI Register offsets */
+#define ESPICFG 0x4
+#define ESPIHINDP 0x80
+
+/* MFSEL bit fileds */
+#define MFSEL1_LPCSEL BIT(26)
+#define MFSEL4_ESPISEL BIT(8)
+
+/* ESPICFG bit fileds */
+#define CHSUPP_MASK GENMASK(27, 24)
+#define IOMODE_MASK GENMASK(9, 8)
+#define IOMODE_SDQ FIELD_PREP(IOMODE_MASK, 3)
+#define MAXFREQ_MASK GENMASK(12, 10)
+#define MAXFREQ_33MHZ FIELD_PREP(MAXFREQ_MASK, 2)
+
+/* ESPIHINDP bit fileds */
+#define AUTO_SBLD BIT(4)
+#define AUTO_HS1 BIT(8)
+#define AUTO_HS2 BIT(12)
+#define AUTO_HS3 BIT(16)
+
+static int npcm_host_intf_bind(struct udevice *dev)
+{
+ struct regmap *syscon;
+ void __iomem *base;
+ u32 ch_supp, val;
+ u32 ioaddr;
+ const char *type;
+ int ret;
+
+ /* Release host wait */
+ setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT);
+
+ syscon = syscon_regmap_lookup_by_phandle(dev, "syscon");
+ if (IS_ERR(syscon)) {
+ dev_err(dev, "%s: unable to get syscon, dev %s\n", __func__, dev->name);
+ return PTR_ERR(syscon);
+ }
+
+ ioaddr = dev_read_u32_default(dev, "ioaddr", 0);
+ if (ioaddr)
+ regmap_write(syscon, HIFCR, ioaddr);
+
+ type = dev_read_string(dev, "type");
+ if (!type)
+ return -EINVAL;
+
+ if (!strcmp(type, "espi")) {
+ base = dev_read_addr_ptr(dev);
+ if (!base)
+ return -EINVAL;
+
+ ret = dev_read_u32(dev, "channel-support", &ch_supp);
+ if (ret)
+ return ret;
+
+ /* Select eSPI pins function */
+ regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, 0);
+ regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, MFSEL4_ESPISEL);
+
+ val = AUTO_SBLD | AUTO_HS1 | AUTO_HS2 | AUTO_HS3 | ch_supp;
+ writel(val, base + ESPIHINDP);
+
+ val = readl(base + ESPICFG);
+ val &= ~(CHSUPP_MASK | IOMODE_MASK | MAXFREQ_MASK);
+ val |= IOMODE_SDQ | MAXFREQ_33MHZ | FIELD_PREP(CHSUPP_MASK, ch_supp);
+ writel(val, base + ESPICFG);
+ } else if (!strcmp(type, "lpc")) {
+ /* Select LPC pin function */
+ regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, 0);
+ regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, MFSEL1_LPCSEL);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id npcm_hostintf_ids[] = {
+ { .compatible = "nuvoton,npcm750-host-intf" },
+ { .compatible = "nuvoton,npcm845-host-intf" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_host_intf) = {
+ .name = "npcm_host_intf",
+ .id = UCLASS_MISC,
+ .of_match = npcm_hostintf_ids,
+ .bind = npcm_host_intf_bind,
+};
diff --git a/drivers/misc/npcm_otp.c b/drivers/misc/npcm_otp.c
new file mode 100644
index 00000000000..304910888bb
--- /dev/null
+++ b/drivers/misc/npcm_otp.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Nuvoton Technology Corp.
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fuse.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/arch/otp.h>
+
+struct npcm_otp_priv {
+ struct npcm_otp_regs *regs[2];
+};
+
+static struct npcm_otp_priv *otp_priv;
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_check_inputs */
+/* */
+/* Parameters: arr - fuse array number to check */
+/* word - fuse word (offset) to check */
+/* Returns: int */
+/* Side effects: */
+/* Description: Checks is arr and word are illegal and do not exceed */
+/* their range. Return 0 if they are legal, -1 if not */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_check_inputs(u32 arr, u32 word)
+{
+ if (arr >= NPCM_NUM_OF_SA) {
+ if (IS_ENABLED(CONFIG_ARCH_NPCM8XX))
+ printf("\nError: npcm8XX otp includs only one bank: 0\n");
+ if (IS_ENABLED(CONFIG_ARCH_NPCM7XX))
+ printf("\nError: npcm7XX otp includs only two banks: 0 and 1\n");
+ return -1;
+ }
+
+ if (word >= NPCM_OTP_ARR_BYTE_SIZE) {
+ printf("\nError: npcm otp array comprises only %d bytes, numbered from 0 to %d\n",
+ NPCM_OTP_ARR_BYTE_SIZE, NPCM_OTP_ARR_BYTE_SIZE - 1);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_wait_for_otp_ready */
+/* */
+/* Parameters: array - fuse array to wait for */
+/* Returns: int */
+/* Side effects: */
+/* Description: Initialize the Fuse HW module. */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_wait_for_otp_ready(u32 arr, u32 timeout)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+ u32 time = timeout;
+
+ /*------------------------------------------------------------------------*/
+ /* check parameters validity */
+ /*------------------------------------------------------------------------*/
+ if (arr > NPCM_FUSE_SA)
+ return -EINVAL;
+
+ while (--time > 1) {
+ if (readl(&regs->fst) & FST_RDY) {
+ /* fuse is ready, clear the status. */
+ writel(readl(&regs->fst) | FST_RDST, &regs->fst);
+ return 0;
+ }
+ }
+
+ /* try to clear the status in case it was set */
+ writel(readl(&regs->fst) | FST_RDST, &regs->fst);
+
+ return -EINVAL;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_read_byte */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* addr - Byte-address to read from [input]. */
+/* data - Pointer to result [output]. */
+/* Returns: none */
+/* Side effects: */
+/* Description: Read 8-bit data from an OTP storage array. */
+/*----------------------------------------------------------------------------*/
+static void npcm_otp_read_byte(u32 arr, u32 addr, u8 *data)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Configure the byte address in the fuse array for read operation */
+ writel(FADDR_VAL(addr, 0), &regs->faddr);
+
+ /* Initiate a read cycle */
+ writel(READ_INIT, &regs->fctl);
+
+ /* Wait for read operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the result */
+ *data = readl(&regs->fdata) & FDATA_MASK;
+
+ /* Clean FDATA contents to prevent unauthorized software from reading
+ * sensitive information
+ */
+ writel(FDATA_CLEAN_VALUE, &regs->fdata);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_bit_is_programmed */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte_offset - Byte offset in array [input]. */
+/* bit_offset - Bit offset in byte [input]. */
+/* Returns: Nonzero if bit is programmed, zero otherwise. */
+/* Side effects: */
+/* Description: Check if a bit is programmed in an OTP storage array. */
+/*----------------------------------------------------------------------------*/
+static bool npcm_otp_bit_is_programmed(u32 arr,
+ u32 byte_offset, u8 bit_offset)
+{
+ u32 data = 0;
+
+ /* Read the entire byte you wish to program */
+ npcm_otp_read_byte(arr, byte_offset, (u8 *)&data);
+
+ /* Check whether the bit is already programmed */
+ if (data & (1 << bit_offset))
+ return true;
+
+ return false;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_program_bit */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte)offset - Byte offset in array [input]. */
+/* bit_offset - Bit offset in byte [input]. */
+/* Returns: int */
+/* Side effects: */
+/* Description: Program (set to 1) a bit in an OTP storage array. */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_program_bit(u32 arr, u32 byte_offset,
+ u8 bit_offset)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+ int count;
+ u8 read_data;
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Make sure the bit is not already programmed */
+ if (npcm_otp_bit_is_programmed(arr, byte_offset, bit_offset))
+ return 0;
+
+ /* Configure the bit address in the fuse array for program operation */
+ writel(FADDR_VAL(byte_offset, bit_offset), &regs->faddr);
+ writel(readl(&regs->faddr) | FADDR_IN_PROG, &regs->faddr);
+
+ // program up to MAX_PROGRAM_PULSES
+ for (count = 1; count <= MAX_PROGRAM_PULSES; count++) {
+ /* Initiate a program cycle */
+ writel(PROGRAM_ARM, &regs->fctl);
+ writel(PROGRAM_INIT, &regs->fctl);
+
+ /* Wait for program operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ // after MIN_PROGRAM_PULSES start verifying the result
+ if (count >= MIN_PROGRAM_PULSES) {
+ /* Initiate a read cycle */
+ writel(READ_INIT, &regs->fctl);
+
+ /* Wait for read operation completion */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the result */
+ read_data = readl(&regs->fdata) & FDATA_MASK;
+
+ /* If the bit is set the sequence ended correctly */
+ if (read_data & (1 << bit_offset))
+ break;
+ }
+ }
+
+ // check if programmking failed
+ if (count > MAX_PROGRAM_PULSES) {
+ printf("program fail\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Clean FDATA contents to prevent unauthorized software from reading
+ * sensitive information
+ */
+ writel(FDATA_CLEAN_VALUE, &regs->fdata);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_program_byte */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* byte_offset - Byte offset in array [input]. */
+/* value - Byte to program [input]. */
+/* Returns: int */
+/* Side effects: */
+/* Description: Program (set to 1) a given byte's relevant bits in an */
+/* OTP storage array. */
+/*----------------------------------------------------------------------------*/
+static int npcm_otp_program_byte(u32 arr, u32 byte_offset,
+ u8 value)
+{
+ int status = 0;
+ unsigned int i;
+ u8 data = 0;
+ int rc;
+
+ rc = npcm_otp_check_inputs(arr, byte_offset);
+ if (rc != 0)
+ return rc;
+
+ /* Wait for the Fuse Box Idle */
+ npcm_otp_wait_for_otp_ready(arr, 0xDEADBEEF);
+
+ /* Read the entire byte you wish to program */
+ npcm_otp_read_byte(arr, byte_offset, &data);
+
+ /* In case all relevant bits are already programmed - nothing to do */
+ if ((~data & value) == 0)
+ return status;
+
+ /* Program unprogrammed bits. */
+ for (i = 0; i < 8; i++) {
+ if (value & (1 << i)) {
+ /* Program (set to 1) the relevant bit */
+ int last_status = npcm_otp_program_bit(arr, byte_offset, (u8)i);
+
+ if (last_status != 0)
+ status = last_status;
+ }
+ }
+ return status;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_is_fuse_array_disabled */
+/* */
+/* Parameters: arr - Storage Array type [input]. */
+/* Returns: bool */
+/* Side effects: */
+/* Description: Return true if access to the first 2048 bits of the */
+/* specified fuse array is disabled, false if not */
+/*----------------------------------------------------------------------------*/
+bool npcm_otp_is_fuse_array_disabled(u32 arr)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[arr];
+
+ return (readl(&regs->fcfg) & FCFG_FDIS) != 0;
+}
+
+int npcm_otp_select_key(u8 key_index)
+{
+ struct npcm_otp_regs *regs = otp_priv->regs[NPCM_KEY_SA];
+ u32 idx = 0;
+ u32 time = 0xDAEDBEEF;
+
+ if (key_index >= 4)
+ return -1;
+
+ /* Do not destroy ECCDIS bit */
+ idx = readl(&regs->fustrap_fkeyind);
+
+ /* Configure the key size */
+ idx &= ~FKEYIND_KSIZE_MASK;
+ idx |= FKEYIND_KSIZE_256;
+
+ /* Configure the key index (0 to 3) */
+ idx &= ~FKEYIND_KIND_MASK;
+ idx |= FKEYIND_KIND_KEY(key_index);
+
+ writel(idx, &regs->fustrap_fkeyind);
+
+ /* Wait for selection completetion */
+ while (--time > 1) {
+ if (readl(&regs->fustrap_fkeyind) & FKEYIND_KVAL)
+ return 0;
+ udelay(1);
+ }
+
+ return -1;
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_nibble_parity_ecc_encode */
+/* */
+/* Parameters: datain - pointer to decoded data buffer */
+/* dataout - pointer to encoded data buffer (buffer size */
+/* should be 2 x dataout) */
+/* size - size of encoded data (decoded data x 2) */
+/* Returns: none */
+/* Side effects: */
+/* Description: Decodes the data according to nibble parity ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*----------------------------------------------------------------------------*/
+void npcm_otp_nibble_parity_ecc_encode(u8 *datain, u8 *dataout, u32 size)
+{
+ u32 i, idx;
+ u8 E0, E1, E2, E3;
+
+ for (i = 0; i < (size / 2); i++) {
+ E0 = (datain[i] >> 0) & 0x01;
+ E1 = (datain[i] >> 1) & 0x01;
+ E2 = (datain[i] >> 2) & 0x01;
+ E3 = (datain[i] >> 3) & 0x01;
+
+ idx = i * 2;
+ dataout[idx] = datain[i] & 0x0f;
+ dataout[idx] |= (E0 ^ E1) << 4;
+ dataout[idx] |= (E2 ^ E3) << 5;
+ dataout[idx] |= (E0 ^ E2) << 6;
+ dataout[idx] |= (E1 ^ E3) << 7;
+
+ E0 = (datain[i] >> 4) & 0x01;
+ E1 = (datain[i] >> 5) & 0x01;
+ E2 = (datain[i] >> 6) & 0x01;
+ E3 = (datain[i] >> 7) & 0x01;
+
+ idx = i * 2 + 1;
+ dataout[idx] = (datain[i] & 0xf0) >> 4;
+ dataout[idx] |= (E0 ^ E1) << 4;
+ dataout[idx] |= (E2 ^ E3) << 5;
+ dataout[idx] |= (E0 ^ E2) << 6;
+ dataout[idx] |= (E1 ^ E3) << 7;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: npcm_otp_majority_rule_ecc_encode */
+/* */
+/* Parameters: datain - pointer to decoded data buffer */
+/* dataout - pointer to encoded data buffer (buffer size */
+/* should be 3 x dataout) */
+/* size - size of encoded data (decoded data x 3) */
+/* Returns: none */
+/* Side effects: */
+/* Description: Decodes the data according to Major Rule ECC scheme. */
+/* Size specifies the encoded data size. */
+/* Decodes whole bytes only */
+/*----------------------------------------------------------------------------*/
+void npcm_otp_majority_rule_ecc_encode(u8 *datain, u8 *dataout, u32 size)
+{
+ u32 byte;
+ u32 bit;
+ u8 bit_val;
+ u32 decoded_size = size / 3;
+
+ for (byte = 0; byte < decoded_size; byte++) {
+ for (bit = 0; bit < 8; bit++) {
+ bit_val = (datain[byte] >> bit) & 0x01;
+
+ if (bit_val) {
+ dataout[byte] |= (1 << bit);
+ dataout[decoded_size + byte] |= (1 << bit);
+ dataout[decoded_size * 2 + byte] |= (1 << bit);
+ } else {
+ dataout[byte] &= ~(1 << bit);
+ dataout[decoded_size + byte] &= ~(1 << bit);
+ dataout[decoded_size * 2 + byte] &= ~(1 << bit);
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/* Function: fuse_program_data */
+/* */
+/* Parameters: bank - Storage Array type [input]. */
+/* word - Byte offset in array [input]. */
+/* data - Pointer to data buffer to program. */
+/* size - Number of bytes to program. */
+/* Returns: none */
+/* Side effects: */
+/* Description: Programs the given byte array (size bytes) to the given */
+/* OTP storage array, starting from offset word. */
+/*----------------------------------------------------------------------------*/
+int fuse_program_data(u32 bank, u32 word, u8 *data, u32 size)
+{
+ u32 arr = (u32)bank;
+ u32 byte;
+ int rc;
+
+ rc = npcm_otp_check_inputs(bank, word + size - 1);
+ if (rc != 0)
+ return rc;
+
+ for (byte = 0; byte < size; byte++) {
+ u8 val;
+
+ val = data[byte];
+ if (val == 0) // optimization
+ continue;
+
+ rc = npcm_otp_program_byte(arr, word + byte, data[byte]);
+ if (rc != 0)
+ return rc;
+
+ // verify programming of every '1' bit
+ val = 0;
+ npcm_otp_read_byte((u32)bank, byte, &val);
+ if ((data[byte] & ~val) != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int fuse_prog_image(u32 bank, uintptr_t address)
+{
+ return fuse_program_data(bank, 0, (u8 *)address, NPCM_OTP_ARR_BYTE_SIZE);
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ int rc = npcm_otp_check_inputs(bank, word);
+
+ if (rc != 0)
+ return rc;
+
+ *val = 0;
+ npcm_otp_read_byte((u32)bank, word, (u8 *)val);
+
+ return 0;
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ /* We do not support overriding */
+ return -EINVAL;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int rc;
+
+ rc = npcm_otp_check_inputs(bank, word);
+ if (rc != 0)
+ return rc;
+
+ return npcm_otp_program_byte(bank, word, (u8)val);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ /* We do not support overriding */
+ return -EINVAL;
+}
+
+static int npcm_otp_bind(struct udevice *dev)
+{
+ struct npcm_otp_regs *regs;
+
+ otp_priv = calloc(1, sizeof(struct npcm_otp_priv));
+ if (!otp_priv)
+ return -ENOMEM;
+
+ regs = dev_remap_addr_index(dev, 0);
+ if (!regs) {
+ printf("Cannot find reg address (arr #0), binding failed\n");
+ return -EINVAL;
+ }
+ otp_priv->regs[0] = regs;
+
+ if (IS_ENABLED(CONFIG_ARCH_NPCM7xx)) {
+ regs = dev_remap_addr_index(dev, 1);
+ if (!regs) {
+ printf("Cannot find reg address (arr #1), binding failed\n");
+ return -EINVAL;
+ }
+ otp_priv->regs[1] = regs;
+ }
+ printf("OTP: NPCM OTP module bind OK\n");
+
+ return 0;
+}
+
+static const struct udevice_id npcm_otp_ids[] = {
+ { .compatible = "nuvoton,npcm845-otp" },
+ { .compatible = "nuvoton,npcm750-otp" },
+ { }
+};
+
+U_BOOT_DRIVER(npcm_otp) = {
+ .name = "npcm_otp",
+ .id = UCLASS_MISC,
+ .of_match = npcm_otp_ids,
+ .priv_auto = sizeof(struct npcm_otp_priv),
+ .bind = npcm_otp_bind,
+};
diff --git a/drivers/misc/nvmem.c b/drivers/misc/nvmem.c
new file mode 100644
index 00000000000..5a2bd1f9f72
--- /dev/null
+++ b/drivers/misc/nvmem.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Sean Anderson <[email protected]>
+ */
+
+#include <common.h>
+#include <i2c_eeprom.h>
+#include <linker_lists.h>
+#include <misc.h>
+#include <nvmem.h>
+#include <rtc.h>
+#include <dm/device_compat.h>
+#include <dm/ofnode.h>
+#include <dm/read.h>
+#include <dm/uclass.h>
+
+int nvmem_cell_read(struct nvmem_cell *cell, void *buf, size_t size)
+{
+ dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size);
+ if (size != cell->size)
+ return -EINVAL;
+
+ switch (cell->nvmem->driver->id) {
+ case UCLASS_I2C_EEPROM:
+ return i2c_eeprom_read(cell->nvmem, cell->offset, buf, size);
+ case UCLASS_MISC: {
+ int ret = misc_read(cell->nvmem, cell->offset, buf, size);
+
+ if (ret < 0)
+ return ret;
+ if (ret != size)
+ return -EIO;
+ return 0;
+ }
+ case UCLASS_RTC:
+ return dm_rtc_read(cell->nvmem, cell->offset, buf, size);
+ default:
+ return -ENOSYS;
+ }
+}
+
+int nvmem_cell_write(struct nvmem_cell *cell, const void *buf, size_t size)
+{
+ dev_dbg(cell->nvmem, "%s: off=%u size=%zu\n", __func__, cell->offset, size);
+ if (size != cell->size)
+ return -EINVAL;
+
+ switch (cell->nvmem->driver->id) {
+ case UCLASS_I2C_EEPROM:
+ return i2c_eeprom_write(cell->nvmem, cell->offset, buf, size);
+ case UCLASS_MISC: {
+ int ret = misc_write(cell->nvmem, cell->offset, buf, size);
+
+ if (ret < 0)
+ return ret;
+ if (ret != size)
+ return -EIO;
+ return 0;
+ }
+ case UCLASS_RTC:
+ return dm_rtc_write(cell->nvmem, cell->offset, buf, size);
+ default:
+ return -ENOSYS;
+ }
+}
+
+/**
+ * nvmem_get_device() - Get an nvmem device for a cell
+ * @node: ofnode of the nvmem device
+ * @cell: Cell to look up
+ *
+ * Try to find a nvmem-compatible device by going through the nvmem interfaces.
+ *
+ * Return:
+ * * 0 on success
+ * * -ENODEV if we didn't find anything
+ * * A negative error if there was a problem looking up the device
+ */
+static int nvmem_get_device(ofnode node, struct nvmem_cell *cell)
+{
+ int i, ret;
+ enum uclass_id ids[] = {
+ UCLASS_I2C_EEPROM,
+ UCLASS_MISC,
+ UCLASS_RTC,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ids); i++) {
+ ret = uclass_get_device_by_ofnode(ids[i], node, &cell->nvmem);
+ if (!ret)
+ return 0;
+ if (ret != -ENODEV && ret != -EPFNOSUPPORT)
+ return ret;
+ }
+
+ return -ENODEV;
+}
+
+int nvmem_cell_get_by_index(struct udevice *dev, int index,
+ struct nvmem_cell *cell)
+{
+ fdt_addr_t offset;
+ fdt_size_t size = FDT_SIZE_T_NONE;
+ int ret;
+ struct ofnode_phandle_args args;
+
+ dev_dbg(dev, "%s: index=%d\n", __func__, index);
+
+ ret = dev_read_phandle_with_args(dev, "nvmem-cells", NULL, 0, index,
+ &args);
+ if (ret)
+ return ret;
+
+ ret = nvmem_get_device(ofnode_get_parent(args.node), cell);
+ if (ret)
+ return ret;
+
+ offset = ofnode_get_addr_size_index_notrans(args.node, 0, &size);
+ if (offset == FDT_ADDR_T_NONE || size == FDT_SIZE_T_NONE) {
+ dev_dbg(cell->nvmem, "missing address or size for %s\n",
+ ofnode_get_name(args.node));
+ return -EINVAL;
+ }
+
+ cell->offset = offset;
+ cell->size = size;
+ return 0;
+}
+
+int nvmem_cell_get_by_name(struct udevice *dev, const char *name,
+ struct nvmem_cell *cell)
+{
+ int index;
+
+ dev_dbg(dev, "%s, name=%s\n", __func__, name);
+
+ index = dev_read_stringlist_search(dev, "nvmem-cell-names", name);
+ if (index < 0)
+ return index;
+
+ return nvmem_cell_get_by_index(dev, index, cell);
+}
diff --git a/drivers/misc/qfw_sandbox.c b/drivers/misc/qfw_sandbox.c
index b09974d33bd..1002df75339 100644
--- a/drivers/misc/qfw_sandbox.c
+++ b/drivers/misc/qfw_sandbox.c
@@ -48,7 +48,7 @@ static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
{
u16 entry;
u32 control = be32_to_cpu(dma->control);
- void *address = (void *)be64_to_cpu(dma->address);
+ void *address = (void *)(uintptr_t)be64_to_cpu(dma->address);
u32 length = be32_to_cpu(dma->length);
struct qfw_sandbox_plat *plat = dev_get_plat(dev);
struct fw_cfg_file *file;
diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c
index f14d6e26d9c..b816503bfa2 100644
--- a/drivers/misc/stm32_rcc.c
+++ b/drivers/misc/stm32_rcc.c
@@ -39,6 +39,11 @@ struct stm32_rcc_clk stm32_rcc_clk_mp1 = {
.soc = STM32MP1,
};
+struct stm32_rcc_clk stm32_rcc_clk_mp13 = {
+ .drv_name = "stm32mp13_clk",
+ .soc = STM32MP1,
+};
+
static int stm32_rcc_bind(struct udevice *dev)
{
struct udevice *child;
@@ -79,6 +84,7 @@ static const struct udevice_id stm32_rcc_ids[] = {
{.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 },
{.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 },
{.compatible = "st,stm32mp1-rcc", .data = (ulong)&stm32_rcc_clk_mp1 },
+ {.compatible = "st,stm32mp13-rcc", .data = (ulong)&stm32_rcc_clk_mp13 },
{ }
};
diff --git a/drivers/misc/test_drv.c b/drivers/misc/test_drv.c
index 5d72982f258..927618256f0 100644
--- a/drivers/misc/test_drv.c
+++ b/drivers/misc/test_drv.c
@@ -108,8 +108,10 @@ UCLASS_DRIVER(testbus) = {
.child_pre_probe = testbus_child_pre_probe_uclass,
.child_post_probe = testbus_child_post_probe_uclass,
- /* This is for dtoc testing only */
- .per_device_plat_auto = sizeof(struct dm_test_uclass_priv),
+ .per_device_auto = sizeof(struct dm_test_uclass_priv),
+
+ /* Note: this is for dtoc testing as well as tags*/
+ .per_device_plat_auto = sizeof(struct dm_test_uclass_plat),
};
static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)