aboutsummaryrefslogtreecommitdiffstats
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 23:14:22 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 23:14:22 +0100
commita7a99e76d203e7f6621804f33148cb7afa7818f2 (patch)
tree5e41a013924da155246aa2f87ec14f53733dcf5e
parent375761e00da5ebaa9940bea5c7349ba9c52bd9a5 (diff)
parent69679101cc8935b9f4032678c12612ea584a573a (diff)
downloadlinux-next-history-a7a99e76d203e7f6621804f33148cb7afa7818f2.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git
-rw-r--r--Documentation/devicetree/bindings/nvmem/airoha,smc-efuses.yaml67
-rw-r--r--Documentation/devicetree/bindings/nvmem/microchip,lan9662-otpc.yaml1
-rw-r--r--Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml4
-rw-r--r--drivers/nvmem/Kconfig22
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/airoha-smc-efuses.c125
-rw-r--r--drivers/nvmem/core.c4
-rw-r--r--drivers/nvmem/lan9662-otpc.c12
-rw-r--r--drivers/nvmem/layouts/onie-tlv.c3
-rw-r--r--drivers/nvmem/layouts/u-boot-env.c5
-rw-r--r--drivers/nvmem/nintendo-otp.c9
-rw-r--r--drivers/nvmem/rockchip-otp.c9
12 files changed, 238 insertions, 25 deletions
diff --git a/Documentation/devicetree/bindings/nvmem/airoha,smc-efuses.yaml b/Documentation/devicetree/bindings/nvmem/airoha,smc-efuses.yaml
new file mode 100644
index 0000000000000..c52f8d4bec392
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/airoha,smc-efuses.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/airoha,smc-efuses.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha SMC eFuses
+
+description: |
+ Airoha new SoC AN7581 expose banks of eFuse accessible
+ via specific SMC commands.
+
+ 2 different bank of eFuse or 64 cells of 32 bit are exposed
+ read-only used to give information on HW Revision, PHY Calibration,
+ Device Model, Private Key...
+
+maintainers:
+ - Christian Marangi <ansuelsmth@gmail.com>
+
+properties:
+ compatible:
+ enum:
+ - airoha,an7581-efuses
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ '^efuse-bank@[0-1]$':
+ type: object
+
+ allOf:
+ - $ref: nvmem.yaml#
+
+ properties:
+ reg:
+ description: Identify the eFuse bank.
+ enum: [0, 1]
+
+ required:
+ - reg
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - '#address-cells'
+ - '#size-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ efuse {
+ compatible = "airoha,an7581-efuses";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ efuse-bank@0 {
+ reg = <0>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/nvmem/microchip,lan9662-otpc.yaml b/Documentation/devicetree/bindings/nvmem/microchip,lan9662-otpc.yaml
index f97c6beb4766a..c03e96afe5641 100644
--- a/Documentation/devicetree/bindings/nvmem/microchip,lan9662-otpc.yaml
+++ b/Documentation/devicetree/bindings/nvmem/microchip,lan9662-otpc.yaml
@@ -25,6 +25,7 @@ properties:
- const: microchip,lan9662-otpc
- enum:
- microchip,lan9662-otpc
+ - microchip,lan9691-otpc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 2ab047f2bb69d..8134ddb54e130 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -19,6 +19,8 @@ properties:
- enum:
- qcom,apq8064-qfprom
- qcom,apq8084-qfprom
+ - qcom,glymur-qfprom
+ - qcom,hawi-qfprom
- qcom,ipq5018-qfprom
- qcom,ipq5332-qfprom
- qcom,ipq5424-qfprom
@@ -27,6 +29,7 @@ properties:
- qcom,ipq8074-qfprom
- qcom,ipq9574-qfprom
- qcom,kaanapali-qfprom
+ - qcom,milos-qfprom
- qcom,msm8226-qfprom
- qcom,msm8916-qfprom
- qcom,msm8917-qfprom
@@ -48,6 +51,7 @@ properties:
- qcom,sdm630-qfprom
- qcom,sdm670-qfprom
- qcom,sdm845-qfprom
+ - qcom,shikra-qfprom
- qcom,sm6115-qfprom
- qcom,sm6350-qfprom
- qcom,sm6375-qfprom
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 74ddbd0f79b0e..e10f7ff725ff9 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -28,6 +28,19 @@ source "drivers/nvmem/layouts/Kconfig"
# Devices
+config NVMEM_AIROHA_SMC_EFUSES
+ tristate "Airoha SMC eFuse support"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on HAVE_ARM_SMCCC
+ default ARCH_AIROHA
+ help
+ Say y here to enable support for reading eFuses on Airoha AN7581
+ SoCs. These are e.g. used to store factory programmed
+ calibration data required for the PCIe or the USB-C PHY or Thermal.
+
+ This driver can also be built as a module. If so, the module will
+ be called nvmem-airoha-smc-efuses.
+
config NVMEM_AN8855_EFUSE
tristate "Airoha AN8855 eFuse support"
depends on COMPILE_TEST
@@ -138,7 +151,7 @@ config NVMEM_JZ4780_EFUSE
config NVMEM_LAN9662_OTPC
tristate "Microchip LAN9662 OTP controller support"
- depends on SOC_LAN966 || COMPILE_TEST
+ depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST
depends on HAS_IOMEM
help
This driver enables the OTP controller available on Microchip LAN9662
@@ -262,7 +275,7 @@ config NVMEM_S32G_OCOTP
Programmable memory pages.
config NVMEM_QCOM_QFPROM
- tristate "QCOM QFPROM Support"
+ tristate "Qualcomm QFPROM Support"
depends on ARCH_QCOM || COMPILE_TEST
depends on HAS_IOMEM
help
@@ -273,7 +286,7 @@ config NVMEM_QCOM_QFPROM
will be called nvmem_qfprom.
config NVMEM_QCOM_SEC_QFPROM
- tristate "QCOM SECURE QFPROM Support"
+ tristate "Qualcomm SECURE QFPROM Support"
depends on ARCH_QCOM || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
@@ -303,7 +316,6 @@ config NVMEM_RAVE_SP_EEPROM
config NVMEM_RCAR_EFUSE
tristate "Renesas R-Car Gen4 E-FUSE support"
depends on (ARCH_RENESAS && ARM64) || COMPILE_TEST
- depends on NVMEM
help
Enable support for reading the fuses in the E-FUSE or OTP
non-volatile memory block on Renesas R-Car Gen4 SoCs.
@@ -483,4 +495,4 @@ config NVMEM_QORIQ_EFUSE
This driver can also be built as a module. If so, the module
will be called nvmem_qoriq_efuse.
-endif
+endif # NVMEM
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 7252b8ec88d46..f6f2bc51dee19 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -10,6 +10,8 @@ nvmem_layouts-y := layouts.o
obj-y += layouts/
# Devices
+obj-$(CONFIG_NVMEM_AIROHA_SMC_EFUSES) += nvmem-airoha-smc-efuses.o
+nvmem-airoha-smc-efuses-y := airoha-smc-efuses.o
obj-$(CONFIG_NVMEM_AN8855_EFUSE) += nvmem-an8855-efuse.o
nvmem-an8855-efuse-y := an8855-efuse.o
obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o
diff --git a/drivers/nvmem/airoha-smc-efuses.c b/drivers/nvmem/airoha-smc-efuses.c
new file mode 100644
index 0000000000000..e56a99f4aa1f9
--- /dev/null
+++ b/drivers/nvmem/airoha-smc-efuses.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define AIROHA_SMC_EFUSE_FID 0x82000001
+#define AIROHA_SMC_EFUSE_SUB_ID_READ 0x44414552
+
+#define AIROHA_EFUSE_CELLS 64
+
+struct airoha_efuse_bank_priv {
+ u32 bank_index;
+};
+
+static int airoha_efuse_read(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct regmap *regmap = context;
+
+ return regmap_bulk_read(regmap, offset,
+ val, bytes / sizeof(u32));
+}
+
+static int airoha_efuse_reg_read(void *context, unsigned int offset,
+ unsigned int *val)
+{
+ struct airoha_efuse_bank_priv *priv = context;
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_invoke(AIROHA_SMC_EFUSE_FID,
+ AIROHA_SMC_EFUSE_SUB_ID_READ,
+ priv->bank_index, offset, 0, 0, 0, 0, &res);
+
+ /* check if SMC reported an error */
+ if (res.a0)
+ return -EIO;
+
+ *val = res.a1;
+ return 0;
+}
+
+static int airoha_efuse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ struct nvmem_config nvmem_config = {
+ .size = AIROHA_EFUSE_CELLS * sizeof(u32),
+ .stride = sizeof(u32),
+ .word_size = sizeof(u32),
+ .reg_read = airoha_efuse_read,
+ };
+ struct regmap_config regmap_config = {
+ .reg_read = airoha_efuse_reg_read,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ };
+ struct airoha_efuse_bank_priv *priv;
+ struct nvmem_device *nvmem;
+ struct regmap *regmap;
+ const char *name;
+ u32 bank;
+
+ ret = of_property_read_u32(child, "reg", &bank);
+ if (ret)
+ return ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "airoha-efuse-%u",
+ bank);
+ if (!name)
+ return -ENOMEM;
+
+ priv->bank_index = bank;
+
+ regmap_config.name = name;
+ regmap = devm_regmap_init(dev, NULL, priv,
+ &regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ nvmem_config.name = name;
+ nvmem_config.priv = regmap;
+ nvmem_config.dev = dev;
+ nvmem_config.id = bank;
+ nvmem_config.of_node = child;
+ nvmem = devm_nvmem_register(dev, &nvmem_config);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id airoha_efuse_of_match[] = {
+ { .compatible = "airoha,an7581-efuses", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, airoha_efuse_of_match);
+
+static struct platform_driver airoha_efuse_driver = {
+ .probe = airoha_efuse_probe,
+ .driver = {
+ .name = "airoha-efuse",
+ .of_match_table = airoha_efuse_of_match,
+ },
+};
+module_platform_driver(airoha_efuse_driver);
+
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Driver for Airoha SMC eFUSEs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 311cb2e5a5c02..be28a366f6031 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1019,6 +1019,10 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (rval)
goto err_remove_dev;
+ /* If the device has WP GPIO, default to read-only */
+ if (nvmem->wp_gpio)
+ nvmem->read_only = true;
+
#ifdef CONFIG_NVMEM_SYSFS
rval = nvmem_populate_sysfs_cells(nvmem);
if (rval)
diff --git a/drivers/nvmem/lan9662-otpc.c b/drivers/nvmem/lan9662-otpc.c
index 56fc19f092a7f..62d1d6381bf88 100644
--- a/drivers/nvmem/lan9662-otpc.c
+++ b/drivers/nvmem/lan9662-otpc.c
@@ -27,7 +27,6 @@
#define OTP_OTP_STATUS_OTP_CPUMPEN BIT(1)
#define OTP_OTP_STATUS_OTP_BUSY BIT(0)
-#define OTP_MEM_SIZE 8192
#define OTP_SLEEP_US 10
#define OTP_TIMEOUT_US 500000
@@ -176,7 +175,6 @@ static struct nvmem_config otp_config = {
.word_size = 1,
.reg_read = lan9662_otp_read,
.reg_write = lan9662_otp_write,
- .size = OTP_MEM_SIZE,
};
static int lan9662_otp_probe(struct platform_device *pdev)
@@ -196,6 +194,7 @@ static int lan9662_otp_probe(struct platform_device *pdev)
otp_config.priv = otp;
otp_config.dev = dev;
+ otp_config.size = (uintptr_t) device_get_match_data(dev);
nvmem = devm_nvmem_register(dev, &otp_config);
@@ -203,7 +202,14 @@ static int lan9662_otp_probe(struct platform_device *pdev)
}
static const struct of_device_id lan9662_otp_match[] = {
- { .compatible = "microchip,lan9662-otpc", },
+ {
+ .compatible = "microchip,lan9662-otpc",
+ .data = (const void *) SZ_8K,
+ },
+ {
+ .compatible = "microchip,lan9691-otpc",
+ .data = (const void *) SZ_16K,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, lan9662_otp_match);
diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c
index 0967a32319a28..8b0f3c1b8a0e9 100644
--- a/drivers/nvmem/layouts/onie-tlv.c
+++ b/drivers/nvmem/layouts/onie-tlv.c
@@ -119,7 +119,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem,
cell.name = onie_tlv_cell_name(tlv.type);
if (!cell.name)
- continue;
+ goto next;
cell.offset = hdr_len + offset + sizeof(tlv.type) + sizeof(tlv.len);
cell.bytes = tlv.len;
@@ -132,6 +132,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem,
return ret;
}
+next:
offset += sizeof(tlv) + tlv.len;
}
diff --git a/drivers/nvmem/layouts/u-boot-env.c b/drivers/nvmem/layouts/u-boot-env.c
index f27f387bb52af..33ec2350386f5 100644
--- a/drivers/nvmem/layouts/u-boot-env.c
+++ b/drivers/nvmem/layouts/u-boot-env.c
@@ -38,9 +38,6 @@ static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, i
{
u8 mac[ETH_ALEN];
- if (bytes != MAC_ADDR_STR_LEN)
- return -EINVAL;
-
if (!mac_pton(buf, mac))
return -EINVAL;
@@ -75,7 +72,7 @@ static int u_boot_env_parse_cells(struct device *dev, struct nvmem_device *nvmem
info.offset = data_offset + value - data;
info.bytes = strlen(value);
info.np = of_get_child_by_name(dev->of_node, info.name);
- if (!strcmp(var, "ethaddr")) {
+ if (!strcmp(var, "ethaddr") && info.bytes == MAC_ADDR_STR_LEN) {
info.raw_len = strlen(value);
info.bytes = ETH_ALEN;
info.read_post_process = u_boot_env_read_post_process_ethaddr;
diff --git a/drivers/nvmem/nintendo-otp.c b/drivers/nvmem/nintendo-otp.c
index 355e7f1fc6d54..e45a8a3a9774a 100644
--- a/drivers/nvmem/nintendo-otp.c
+++ b/drivers/nvmem/nintendo-otp.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/nvmem-provider.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#define HW_OTPCMD 0
@@ -74,8 +74,7 @@ MODULE_DEVICE_TABLE(of, nintendo_otp_of_table);
static int nintendo_otp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct of_device_id *of_id =
- of_match_device(nintendo_otp_of_table, dev);
+ const struct nintendo_otp_devtype_data *data;
struct nvmem_device *nvmem;
struct nintendo_otp_priv *priv;
@@ -95,8 +94,8 @@ static int nintendo_otp_probe(struct platform_device *pdev)
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
- if (of_id->data) {
- const struct nintendo_otp_devtype_data *data = of_id->data;
+ data = of_device_get_match_data(dev);
+ if (data) {
config.name = data->name;
config.size = data->num_banks * BANK_SIZE;
}
diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c
index 0ec78b5e19e7d..2c0feb036f3fd 100644
--- a/drivers/nvmem/rockchip-otp.c
+++ b/drivers/nvmem/rockchip-otp.c
@@ -78,9 +78,9 @@ struct rockchip_data {
struct rockchip_otp {
struct device *dev;
void __iomem *base;
- struct clk_bulk_data *clks;
struct reset_control *rst;
const struct rockchip_data *data;
+ struct clk_bulk_data clks[];
};
static int rockchip_otp_reset(struct rockchip_otp *otp)
@@ -424,7 +424,7 @@ static int rockchip_otp_probe(struct platform_device *pdev)
if (!data)
return dev_err_probe(dev, -EINVAL, "failed to get match data\n");
- otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
+ otp = devm_kzalloc(&pdev->dev, struct_size(otp, clks, data->num_clks),
GFP_KERNEL);
if (!otp)
return -ENOMEM;
@@ -436,11 +436,6 @@ static int rockchip_otp_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(otp->base),
"failed to ioremap resource\n");
- otp->clks = devm_kcalloc(dev, data->num_clks, sizeof(*otp->clks),
- GFP_KERNEL);
- if (!otp->clks)
- return -ENOMEM;
-
for (i = 0; i < data->num_clks; ++i)
otp->clks[i].id = data->clks[i];