+++ /dev/null
-From b152bbeb0282bfcf6f91d0d5befd7582c1c3fc23 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Fri, 5 Mar 2021 19:32:36 +0100
-Subject: [PATCH] nvmem: brcm_nvram: new driver exposing Broadcom's NVRAM
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This driver provides access to Broadcom's NVRAM.
-
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
- drivers/nvmem/Kconfig | 9 +++++
- drivers/nvmem/Makefile | 2 +
- drivers/nvmem/brcm_nvram.c | 78 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 89 insertions(+)
- create mode 100644 drivers/nvmem/brcm_nvram.c
-
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -283,4 +283,13 @@ config NVMEM_U_BOOT_ENV
-
- If compiled as module it will be called nvmem_u-boot-env.
-
-+
-+config NVMEM_BRCM_NVRAM
-+ tristate "Broadcom's NVRAM support"
-+ depends on ARCH_BCM_5301X || COMPILE_TEST
-+ depends on HAS_IOMEM
-+ help
-+ This driver provides support for Broadcom's NVRAM that can be accessed
-+ using I/O mapping.
-+
- endif
---- a/drivers/nvmem/Makefile
-+++ b/drivers/nvmem/Makefile
-@@ -57,3 +57,5 @@ obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_e
- nvmem_sprd_efuse-y := sprd-efuse.o
- obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o
- nvmem_u-boot-env-y := u-boot-env.o
-+obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
-+nvmem_brcm_nvram-y := brcm_nvram.o
---- /dev/null
-+++ b/drivers/nvmem/brcm_nvram.c
-@@ -0,0 +1,78 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/mod_devicetable.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/platform_device.h>
-+
-+struct brcm_nvram {
-+ struct device *dev;
-+ void __iomem *base;
-+};
-+
-+static int brcm_nvram_read(void *context, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ struct brcm_nvram *priv = context;
-+ u8 *dst = val;
-+
-+ while (bytes--)
-+ *dst++ = readb(priv->base + offset++);
-+
-+ return 0;
-+}
-+
-+static int brcm_nvram_probe(struct platform_device *pdev)
-+{
-+ struct nvmem_config config = {
-+ .name = "brcm-nvram",
-+ .reg_read = brcm_nvram_read,
-+ };
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ struct brcm_nvram *priv;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+ priv->dev = dev;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ priv->base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(priv->base))
-+ return PTR_ERR(priv->base);
-+
-+ config.dev = dev;
-+ config.priv = priv;
-+ config.size = resource_size(res);
-+
-+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
-+}
-+
-+static const struct of_device_id brcm_nvram_of_match_table[] = {
-+ { .compatible = "brcm,nvram", },
-+ {},
-+};
-+
-+static struct platform_driver brcm_nvram_driver = {
-+ .probe = brcm_nvram_probe,
-+ .driver = {
-+ .name = "brcm_nvram",
-+ .of_match_table = brcm_nvram_of_match_table,
-+ },
-+};
-+
-+static int __init brcm_nvram_init(void)
-+{
-+ return platform_driver_register(&brcm_nvram_driver);
-+}
-+
-+subsys_initcall_sync(brcm_nvram_init);
-+
-+MODULE_AUTHOR("Rafał Miłecki");
-+MODULE_LICENSE("GPL");
-+MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table);
--- /dev/null
+From fd3bb8f54a88107570334c156efb0c724a261003 Mon Sep 17 00:00:00 2001
+From: Evan Green <evgreen@chromium.org>
+Date: Fri, 27 Nov 2020 10:28:34 +0000
+Subject: [PATCH] nvmem: core: Add support for keepout regions
+
+Introduce support into the nvmem core for arrays of register ranges
+that should not result in actual device access. For these regions a
+constant byte (repeated) is returned instead on read, and writes are
+quietly ignored and returned as successful.
+
+This is useful for instance if certain efuse regions are protected
+from access by Linux because they contain secret info to another part
+of the system (like an integrated modem).
+
+Signed-off-by: Evan Green <evgreen@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20201127102837.19366-3-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 153 ++++++++++++++++++++++++++++++++-
+ include/linux/nvmem-provider.h | 17 ++++
+ 2 files changed, 166 insertions(+), 4 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -34,6 +34,8 @@ struct nvmem_device {
+ struct bin_attribute eeprom;
+ struct device *base_dev;
+ struct list_head cells;
++ const struct nvmem_keepout *keepout;
++ unsigned int nkeepout;
+ nvmem_reg_read_t reg_read;
+ nvmem_reg_write_t reg_write;
+ struct gpio_desc *wp_gpio;
+@@ -66,8 +68,8 @@ static LIST_HEAD(nvmem_lookup_list);
+
+ static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
+
+-static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
+- void *val, size_t bytes)
++static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
++ void *val, size_t bytes)
+ {
+ if (nvmem->reg_read)
+ return nvmem->reg_read(nvmem->priv, offset, val, bytes);
+@@ -75,8 +77,8 @@ static int nvmem_reg_read(struct nvmem_d
+ return -EINVAL;
+ }
+
+-static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
+- void *val, size_t bytes)
++static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
++ void *val, size_t bytes)
+ {
+ int ret;
+
+@@ -90,6 +92,88 @@ static int nvmem_reg_write(struct nvmem_
+ return -EINVAL;
+ }
+
++static int nvmem_access_with_keepouts(struct nvmem_device *nvmem,
++ unsigned int offset, void *val,
++ size_t bytes, int write)
++{
++
++ unsigned int end = offset + bytes;
++ unsigned int kend, ksize;
++ const struct nvmem_keepout *keepout = nvmem->keepout;
++ const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout;
++ int rc;
++
++ /*
++ * Skip all keepouts before the range being accessed.
++ * Keepouts are sorted.
++ */
++ while ((keepout < keepoutend) && (keepout->end <= offset))
++ keepout++;
++
++ while ((offset < end) && (keepout < keepoutend)) {
++ /* Access the valid portion before the keepout. */
++ if (offset < keepout->start) {
++ kend = min(end, keepout->start);
++ ksize = kend - offset;
++ if (write)
++ rc = __nvmem_reg_write(nvmem, offset, val, ksize);
++ else
++ rc = __nvmem_reg_read(nvmem, offset, val, ksize);
++
++ if (rc)
++ return rc;
++
++ offset += ksize;
++ val += ksize;
++ }
++
++ /*
++ * Now we're aligned to the start of this keepout zone. Go
++ * through it.
++ */
++ kend = min(end, keepout->end);
++ ksize = kend - offset;
++ if (!write)
++ memset(val, keepout->value, ksize);
++
++ val += ksize;
++ offset += ksize;
++ keepout++;
++ }
++
++ /*
++ * If we ran out of keepouts but there's still stuff to do, send it
++ * down directly
++ */
++ if (offset < end) {
++ ksize = end - offset;
++ if (write)
++ return __nvmem_reg_write(nvmem, offset, val, ksize);
++ else
++ return __nvmem_reg_read(nvmem, offset, val, ksize);
++ }
++
++ return 0;
++}
++
++static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
++ void *val, size_t bytes)
++{
++ if (!nvmem->nkeepout)
++ return __nvmem_reg_read(nvmem, offset, val, bytes);
++
++ return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false);
++}
++
++static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
++ void *val, size_t bytes)
++{
++ if (!nvmem->nkeepout)
++ return __nvmem_reg_write(nvmem, offset, val, bytes);
++
++ return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true);
++}
++
+ #ifdef CONFIG_NVMEM_SYSFS
+ static const char * const nvmem_type_str[] = {
+ [NVMEM_TYPE_UNKNOWN] = "Unknown",
+@@ -535,6 +619,59 @@ nvmem_find_cell_by_name(struct nvmem_dev
+ return cell;
+ }
+
++static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
++{
++ unsigned int cur = 0;
++ const struct nvmem_keepout *keepout = nvmem->keepout;
++ const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout;
++
++ while (keepout < keepoutend) {
++ /* Ensure keepouts are sorted and don't overlap. */
++ if (keepout->start < cur) {
++ dev_err(&nvmem->dev,
++ "Keepout regions aren't sorted or overlap.\n");
++
++ return -ERANGE;
++ }
++
++ if (keepout->end < keepout->start) {
++ dev_err(&nvmem->dev,
++ "Invalid keepout region.\n");
++
++ return -EINVAL;
++ }
++
++ /*
++ * Validate keepouts (and holes between) don't violate
++ * word_size constraints.
++ */
++ if ((keepout->end - keepout->start < nvmem->word_size) ||
++ ((keepout->start != cur) &&
++ (keepout->start - cur < nvmem->word_size))) {
++
++ dev_err(&nvmem->dev,
++ "Keepout regions violate word_size constraints.\n");
++
++ return -ERANGE;
++ }
++
++ /* Validate keepouts don't violate stride (alignment). */
++ if (!IS_ALIGNED(keepout->start, nvmem->stride) ||
++ !IS_ALIGNED(keepout->end, nvmem->stride)) {
++
++ dev_err(&nvmem->dev,
++ "Keepout regions violate stride.\n");
++
++ return -EINVAL;
++ }
++
++ cur = keepout->end;
++ keepout++;
++ }
++
++ return 0;
++}
++
+ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
+ {
+ struct device_node *parent, *child;
+@@ -655,6 +792,8 @@ struct nvmem_device *nvmem_register(cons
+ nvmem->type = config->type;
+ nvmem->reg_read = config->reg_read;
+ nvmem->reg_write = config->reg_write;
++ nvmem->keepout = config->keepout;
++ nvmem->nkeepout = config->nkeepout;
+ if (!config->no_of_node)
+ nvmem->dev.of_node = config->dev->of_node;
+
+@@ -679,6 +818,12 @@ struct nvmem_device *nvmem_register(cons
+ nvmem->dev.groups = nvmem_dev_groups;
+ #endif
+
++ if (nvmem->nkeepout) {
++ rval = nvmem_validate_keepouts(nvmem);
++ if (rval)
++ goto err_put_device;
++ }
++
+ dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
+
+ rval = device_register(&nvmem->dev);
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -31,6 +31,19 @@ enum nvmem_type {
+ #define NVMEM_DEVID_AUTO (-2)
+
+ /**
++ * struct nvmem_keepout - NVMEM register keepout range.
++ *
++ * @start: The first byte offset to avoid.
++ * @end: One beyond the last byte offset to avoid.
++ * @value: The byte to fill reads with for this region.
++ */
++struct nvmem_keepout {
++ unsigned int start;
++ unsigned int end;
++ unsigned char value;
++};
++
++/**
+ * struct nvmem_config - NVMEM device configuration
+ *
+ * @dev: Parent device.
+@@ -39,6 +52,8 @@ enum nvmem_type {
+ * @owner: Pointer to exporter module. Used for refcounting.
+ * @cells: Optional array of pre-defined NVMEM cells.
+ * @ncells: Number of elements in cells.
++ * @keepout: Optional array of keepout ranges (sorted ascending by start).
++ * @nkeepout: Number of elements in the keepout array.
+ * @type: Type of the nvmem storage
+ * @read_only: Device is read-only.
+ * @root_only: Device is accessibly to root only.
+@@ -66,6 +81,8 @@ struct nvmem_config {
+ struct gpio_desc *wp_gpio;
+ const struct nvmem_cell_info *cells;
+ int ncells;
++ const struct nvmem_keepout *keepout;
++ unsigned int nkeepout;
+ enum nvmem_type type;
+ bool read_only;
+ bool root_only;
--- /dev/null
+From 044ee8f85267599a9b0112911f5c16d4548b4289 Mon Sep 17 00:00:00 2001
+From: Evan Green <evgreen@chromium.org>
+Date: Fri, 27 Nov 2020 10:28:36 +0000
+Subject: [PATCH] nvmem: qfprom: Don't touch certain fuses
+
+Some fuse ranges are protected by the XPU such that the AP cannot
+access them. Attempting to do so causes an SError. Use the newly
+introduced per-soc compatible string, and the newly introduced
+nvmem keepout support to attach the set of regions
+we should not access.
+
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Evan Green <evgreen@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20201127102837.19366-5-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qfprom.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -12,6 +12,7 @@
+ #include <linux/mod_devicetable.h>
+ #include <linux/nvmem-provider.h>
+ #include <linux/platform_device.h>
++#include <linux/property.h>
+ #include <linux/regulator/consumer.h>
+
+ /* Blow timer clock frequency in Mhz */
+@@ -89,6 +90,28 @@ struct qfprom_touched_values {
+ };
+
+ /**
++ * struct qfprom_soc_compatible_data - Data matched against the SoC
++ * compatible string.
++ *
++ * @keepout: Array of keepout regions for this SoC.
++ * @nkeepout: Number of elements in the keepout array.
++ */
++struct qfprom_soc_compatible_data {
++ const struct nvmem_keepout *keepout;
++ unsigned int nkeepout;
++};
++
++static const struct nvmem_keepout sc7180_qfprom_keepout[] = {
++ {.start = 0x128, .end = 0x148},
++ {.start = 0x220, .end = 0x228}
++};
++
++static const struct qfprom_soc_compatible_data sc7180_qfprom = {
++ .keepout = sc7180_qfprom_keepout,
++ .nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout)
++};
++
++/**
+ * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
+ * @priv: Our driver data.
+ * @old: The data that was stashed from before fuse blowing.
+@@ -302,6 +325,7 @@ static int qfprom_probe(struct platform_
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nvmem_device *nvmem;
++ const struct qfprom_soc_compatible_data *soc_data;
+ struct qfprom_priv *priv;
+ int ret;
+
+@@ -320,6 +344,11 @@ static int qfprom_probe(struct platform_
+ econfig.priv = priv;
+
+ priv->dev = dev;
++ soc_data = device_get_match_data(dev);
++ if (soc_data) {
++ econfig.keepout = soc_data->keepout;
++ econfig.nkeepout = soc_data->nkeepout;
++ }
+
+ /*
+ * If more than one region is provided then the OS has the ability
+@@ -375,6 +404,7 @@ static int qfprom_probe(struct platform_
+
+ static const struct of_device_id qfprom_of_match[] = {
+ { .compatible = "qcom,qfprom",},
++ { .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom},
+ {/* sentinel */},
+ };
+ MODULE_DEVICE_TABLE(of, qfprom_of_match);
--- /dev/null
+From 3311bf18467272388039922a5e29c4925b291f73 Mon Sep 17 00:00:00 2001
+From: Peng Fan <peng.fan@nxp.com>
+Date: Fri, 27 Nov 2020 10:28:37 +0000
+Subject: [PATCH] nvmem: imx-ocotp: add support for the unaliged word count
+
+When offset is not 4 bytes aligned, directly shift righty by 2 bits
+will cause reading out wrong data. Since imx ocotp only supports
+4 bytes reading once, we need handle offset is not 4 bytes aligned
+and enlarge the bytes to 4 bytes aligned. After reading finished,
+copy the needed data from buffer to caller and free buffer.
+
+Signed-off-by: Peng Fan <peng.fan@nxp.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20201127102837.19366-6-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/imx-ocotp.c | 30 ++++++++++++++++++++++++------
+ 1 file changed, 24 insertions(+), 6 deletions(-)
+
+--- a/drivers/nvmem/imx-ocotp.c
++++ b/drivers/nvmem/imx-ocotp.c
+@@ -4,6 +4,8 @@
+ *
+ * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
+ *
++ * Copyright 2019 NXP
++ *
+ * Based on the barebox ocotp driver,
+ * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
+ * Orex Computed Radiography
+@@ -158,22 +160,30 @@ static int imx_ocotp_read(void *context,
+ {
+ struct ocotp_priv *priv = context;
+ unsigned int count;
+- u32 *buf = val;
++ u8 *buf, *p;
+ int i, ret;
+- u32 index;
++ u32 index, num_bytes;
+
+ index = offset >> 2;
+- count = bytes >> 2;
++ num_bytes = round_up((offset % 4) + bytes, 4);
++ count = num_bytes >> 2;
+
+ if (count > (priv->params->nregs - index))
+ count = priv->params->nregs - index;
+
++ p = kzalloc(num_bytes, GFP_KERNEL);
++ if (!p)
++ return -ENOMEM;
++
+ mutex_lock(&ocotp_mutex);
+
++ buf = p;
++
+ ret = clk_prepare_enable(priv->clk);
+ if (ret < 0) {
+ mutex_unlock(&ocotp_mutex);
+ dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
++ kfree(p);
+ return ret;
+ }
+
+@@ -184,7 +194,7 @@ static int imx_ocotp_read(void *context,
+ }
+
+ for (i = index; i < (index + count); i++) {
+- *buf++ = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 +
++ *(u32 *)buf = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 +
+ i * IMX_OCOTP_OFFSET_PER_WORD);
+
+ /* 47.3.1.2
+@@ -193,13 +203,21 @@ static int imx_ocotp_read(void *context,
+ * software before any new write, read or reload access can be
+ * issued
+ */
+- if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
++ if (*((u32 *)buf) == IMX_OCOTP_READ_LOCKED_VAL)
+ imx_ocotp_clr_err_if_set(priv);
++
++ buf += 4;
+ }
+
++ index = offset % 4;
++ memcpy(val, &p[index], bytes);
++
+ read_end:
+ clk_disable_unprepare(priv->clk);
+ mutex_unlock(&ocotp_mutex);
++
++ kfree(p);
++
+ return ret;
+ }
+
+@@ -447,7 +465,7 @@ static struct nvmem_config imx_ocotp_nvm
+ .name = "imx-ocotp",
+ .read_only = false,
+ .word_size = 4,
+- .stride = 4,
++ .stride = 1,
+ .reg_read = imx_ocotp_read,
+ .reg_write = imx_ocotp_write,
+ };
+++ /dev/null
-From f955dc14450695564926711cf9fa8e1d5d854302 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Wed, 15 Jun 2022 21:43:00 +0200
-Subject: [PATCH] nvmem: add driver handling U-Boot environment variables
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-U-Boot stores its setup as environment variables. It's a list of
-key-value pairs stored on flash device with a custom header.
-
-This commit adds an NVMEM driver that:
-1. Provides NVMEM access to environment vars binary data
-2. Extracts variables as NVMEM cells
-
-Current Linux's NVMEM sysfs API allows reading whole NVMEM data block.
-It can be used by user-space tools for reading U-Boot env vars block
-without the hassle of finding its location. Parsing will still need to
-be re-done there.
-
-Kernel-parsed NVMEM cells can be read however by Linux drivers. This may
-be useful for Ethernet drivers for reading device MAC address which is
-often stored as U-Boot env variable.
-
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
-
---- a/drivers/nvmem/Kconfig
-+++ b/drivers/nvmem/Kconfig
-@@ -270,4 +270,17 @@ config SPRD_EFUSE
- This driver can also be built as a module. If so, the module
- will be called nvmem-sprd-efuse.
-
-+config NVMEM_U_BOOT_ENV
-+ tristate "U-Boot environment variables support"
-+ depends on OF && MTD
-+ select CRC32
-+ help
-+ U-Boot stores its setup as environment variables. This driver adds
-+ support for verifying & exporting such data. It also exposes variables
-+ as NVMEM cells so they can be referenced by other drivers.
-+
-+ Currently this drivers works only with env variables on top of MTD.
-+
-+ If compiled as module it will be called nvmem_u-boot-env.
-+
- endif
---- a/drivers/nvmem/Makefile
-+++ b/drivers/nvmem/Makefile
-@@ -55,3 +55,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynq
- nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o
- obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o
- nvmem_sprd_efuse-y := sprd-efuse.o
-+obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o
-+nvmem_u-boot-env-y := u-boot-env.o
---- /dev/null
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -0,0 +1,218 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2022 Rafał Miłecki <rafal@milecki.pl>
-+ */
-+
-+#include <linux/crc32.h>
-+#include <linux/mod_devicetable.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/nvmem-provider.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+enum u_boot_env_format {
-+ U_BOOT_FORMAT_SINGLE,
-+ U_BOOT_FORMAT_REDUNDANT,
-+};
-+
-+struct u_boot_env {
-+ struct device *dev;
-+ enum u_boot_env_format format;
-+
-+ struct mtd_info *mtd;
-+
-+ /* Cells */
-+ struct nvmem_cell_info *cells;
-+ int ncells;
-+};
-+
-+struct u_boot_env_image_single {
-+ __le32 crc32;
-+ uint8_t data[];
-+} __packed;
-+
-+struct u_boot_env_image_redundant {
-+ __le32 crc32;
-+ u8 mark;
-+ uint8_t data[];
-+} __packed;
-+
-+static int u_boot_env_read(void *context, unsigned int offset, void *val,
-+ size_t bytes)
-+{
-+ struct u_boot_env *priv = context;
-+ struct device *dev = priv->dev;
-+ size_t bytes_read;
-+ int err;
-+
-+ err = mtd_read(priv->mtd, offset, bytes, &bytes_read, val);
-+ if (err && !mtd_is_bitflip(err)) {
-+ dev_err(dev, "Failed to read from mtd: %d\n", err);
-+ return err;
-+ }
-+
-+ if (bytes_read != bytes) {
-+ dev_err(dev, "Failed to read %zu bytes\n", bytes);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf,
-+ size_t data_offset, size_t data_len)
-+{
-+ struct device *dev = priv->dev;
-+ char *data = buf + data_offset;
-+ char *var, *value, *eq;
-+ int idx;
-+
-+ priv->ncells = 0;
-+ for (var = data; var < data + data_len && *var; var += strlen(var) + 1)
-+ priv->ncells++;
-+
-+ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL);
-+ if (!priv->cells)
-+ return -ENOMEM;
-+
-+ for (var = data, idx = 0;
-+ var < data + data_len && *var;
-+ var = value + strlen(value) + 1, idx++) {
-+ eq = strchr(var, '=');
-+ if (!eq)
-+ break;
-+ *eq = '\0';
-+ value = eq + 1;
-+
-+ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL);
-+ if (!priv->cells[idx].name)
-+ return -ENOMEM;
-+ priv->cells[idx].offset = data_offset + value - data;
-+ priv->cells[idx].bytes = strlen(value);
-+ }
-+
-+ if (WARN_ON(idx != priv->ncells))
-+ priv->ncells = idx;
-+
-+ return 0;
-+}
-+
-+static int u_boot_env_parse(struct u_boot_env *priv)
-+{
-+ struct device *dev = priv->dev;
-+ size_t crc32_data_offset;
-+ size_t crc32_data_len;
-+ size_t crc32_offset;
-+ size_t data_offset;
-+ size_t data_len;
-+ uint32_t crc32;
-+ uint32_t calc;
-+ size_t bytes;
-+ uint8_t *buf;
-+ int err;
-+
-+ buf = kcalloc(1, priv->mtd->size, GFP_KERNEL);
-+ if (!buf) {
-+ err = -ENOMEM;
-+ goto err_out;
-+ }
-+
-+ err = mtd_read(priv->mtd, 0, priv->mtd->size, &bytes, buf);
-+ if ((err && !mtd_is_bitflip(err)) || bytes != priv->mtd->size) {
-+ dev_err(dev, "Failed to read from mtd: %d\n", err);
-+ goto err_kfree;
-+ }
-+
-+ switch (priv->format) {
-+ case U_BOOT_FORMAT_SINGLE:
-+ crc32_offset = offsetof(struct u_boot_env_image_single, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_single, data);
-+ data_offset = offsetof(struct u_boot_env_image_single, data);
-+ break;
-+ case U_BOOT_FORMAT_REDUNDANT:
-+ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark);
-+ data_offset = offsetof(struct u_boot_env_image_redundant, data);
-+ break;
-+ }
-+ crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset));
-+ crc32_data_len = priv->mtd->size - crc32_data_offset;
-+ data_len = priv->mtd->size - data_offset;
-+
-+ calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
-+ if (calc != crc32) {
-+ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
-+ err = -EINVAL;
-+ goto err_kfree;
-+ }
-+
-+ buf[priv->mtd->size - 1] = '\0';
-+ err = u_boot_env_add_cells(priv, buf, data_offset, data_len);
-+ if (err)
-+ dev_err(dev, "Failed to add cells: %d\n", err);
-+
-+err_kfree:
-+ kfree(buf);
-+err_out:
-+ return err;
-+}
-+
-+static int u_boot_env_probe(struct platform_device *pdev)
-+{
-+ struct nvmem_config config = {
-+ .name = "u-boot-env",
-+ .reg_read = u_boot_env_read,
-+ };
-+ struct device *dev = &pdev->dev;
-+ struct device_node *np = dev->of_node;
-+ struct u_boot_env *priv;
-+ int err;
-+
-+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+ priv->dev = dev;
-+
-+ priv->format = (uintptr_t)of_device_get_match_data(dev);
-+
-+ priv->mtd = of_get_mtd_device_by_node(np);
-+ if (IS_ERR(priv->mtd)) {
-+ dev_err_probe(dev, PTR_ERR(priv->mtd), "Failed to get %pOF MTD\n", np);
-+ return PTR_ERR(priv->mtd);
-+ }
-+
-+ err = u_boot_env_parse(priv);
-+ if (err)
-+ return err;
-+
-+ config.dev = dev;
-+ config.cells = priv->cells;
-+ config.ncells = priv->ncells;
-+ config.priv = priv;
-+ config.size = priv->mtd->size;
-+
-+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
-+}
-+
-+static const struct of_device_id u_boot_env_of_match_table[] = {
-+ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
-+ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
-+ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
-+ {},
-+};
-+
-+static struct platform_driver u_boot_env_driver = {
-+ .probe = u_boot_env_probe,
-+ .driver = {
-+ .name = "u_boot_env",
-+ .of_match_table = u_boot_env_of_match_table,
-+ },
-+};
-+module_platform_driver(u_boot_env_driver);
-+
-+MODULE_AUTHOR("Rafał Miłecki");
-+MODULE_LICENSE("GPL");
-+MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);
+++ /dev/null
-From d69efcf951df4dcc74a0e1554969c533aec8aa9b Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Thu, 15 Sep 2022 22:06:29 +0200
-Subject: [PATCH] nvmem: u-boot-env: find Device Tree nodes for NVMEM cells
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-DT binding allows specifying NVMEM cells as NVMEM device (provider)
-subnodes. Looks for such subnodes when building NVMEM cells.
-
-This allows NVMEM consumers to use U-Boot environment variables.
-
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
- drivers/nvmem/u-boot-env.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -92,6 +92,7 @@ static int u_boot_env_add_cells(struct u
- return -ENOMEM;
- priv->cells[idx].offset = data_offset + value - data;
- priv->cells[idx].bytes = strlen(value);
-+ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name);
- }
-
- if (WARN_ON(idx != priv->ncells))
+++ /dev/null
-From 60bbaad38109684b156e21112322e0a922f92cde Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Thu, 18 Aug 2022 06:38:37 +0200
-Subject: [PATCH] nvmem: u-boot-env: fix crc32 casting type
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This fixes:
-drivers/nvmem/u-boot-env.c:141:17: sparse: sparse: cast to restricted __le32
-
-Reported-by: kernel test robot <lkp@intel.com>
-Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables")
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
- drivers/nvmem/u-boot-env.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -139,7 +139,7 @@ static int u_boot_env_parse(struct u_boo
- data_offset = offsetof(struct u_boot_env_image_redundant, data);
- break;
- }
-- crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset));
-+ crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
- crc32_data_len = priv->mtd->size - crc32_data_offset;
- data_len = priv->mtd->size - data_offset;
-
--- /dev/null
+From 579db09c6106977c0496f2cca48606b289df4bdf Mon Sep 17 00:00:00 2001
+From: Fabio Estevam <festevam@gmail.com>
+Date: Fri, 29 Jan 2021 17:14:27 +0000
+Subject: [PATCH] nvmem: imx-iim: Use of_device_get_match_data()
+
+The retrieval of driver data via of_device_get_match_data() can make
+the code simpler.
+
+Use of_device_get_match_data() to simplify the code.
+
+Signed-off-by: Fabio Estevam <festevam@gmail.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210129171430.11328-3-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/imx-iim.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/nvmem/imx-iim.c
++++ b/drivers/nvmem/imx-iim.c
+@@ -96,7 +96,6 @@ MODULE_DEVICE_TABLE(of, imx_iim_dt_ids);
+
+ static int imx_iim_probe(struct platform_device *pdev)
+ {
+- const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct iim_priv *iim;
+ struct nvmem_device *nvmem;
+@@ -111,11 +110,7 @@ static int imx_iim_probe(struct platform
+ if (IS_ERR(iim->base))
+ return PTR_ERR(iim->base);
+
+- of_id = of_match_device(imx_iim_dt_ids, dev);
+- if (!of_id)
+- return -ENODEV;
+-
+- drvdata = of_id->data;
++ drvdata = of_device_get_match_data(&pdev->dev);
+
+ iim->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(iim->clk))
--- /dev/null
+From 5a3fa75a4d9cb6bcfc9081ef224a4cdcd4b3eafe Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Fri, 29 Jan 2021 17:14:29 +0000
+Subject: [PATCH] nvmem: Add driver to expose reserved memory as nvmem
+
+Firmware/co-processors might use reserved memory areas in order to pass
+data stemming from an nvmem device otherwise non accessible to Linux.
+For example an EEPROM memory only physically accessible to firmware, or
+data only accessible early at boot time.
+
+In order to expose this data to other drivers and user-space, the driver
+models the reserved memory area as an nvmem device.
+
+Tested-by: Tim Gover <tim.gover@raspberrypi.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210129171430.11328-5-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 8 ++++
+ drivers/nvmem/Makefile | 2 +
+ drivers/nvmem/rmem.c | 97 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/of/platform.c | 1 +
+ 4 files changed, 108 insertions(+)
+ create mode 100644 drivers/nvmem/rmem.c
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -270,4 +270,12 @@ config SPRD_EFUSE
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-sprd-efuse.
+
++config NVMEM_RMEM
++ tristate "Reserved Memory Based Driver Support"
++ help
++ This drivers maps reserved memory into an nvmem device. It might be
++ useful to expose information left by firmware in memory.
++
++ This driver can also be built as a module. If so, the module
++ will be called nvmem-rmem.
+ endif
+--- a/drivers/nvmem/Makefile
++++ b/drivers/nvmem/Makefile
+@@ -55,3 +55,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynq
+ nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o
+ obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o
+ nvmem_sprd_efuse-y := sprd-efuse.o
++obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o
++nvmem-rmem-y := rmem.o
+--- /dev/null
++++ b/drivers/nvmem/rmem.c
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
++ */
++
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/nvmem-provider.h>
++#include <linux/of_reserved_mem.h>
++#include <linux/platform_device.h>
++
++struct rmem {
++ struct device *dev;
++ struct nvmem_device *nvmem;
++ struct reserved_mem *mem;
++
++ phys_addr_t size;
++};
++
++static int rmem_read(void *context, unsigned int offset,
++ void *val, size_t bytes)
++{
++ struct rmem *priv = context;
++ size_t available = priv->mem->size;
++ loff_t off = offset;
++ void *addr;
++ int count;
++
++ /*
++ * Only map the reserved memory at this point to avoid potential rogue
++ * kernel threads inadvertently modifying it. Based on the current
++ * uses-cases for this driver, the performance hit isn't a concern.
++ * Nor is likely to be, given the nature of the subsystem. Most nvmem
++ * devices operate over slow buses to begin with.
++ *
++ * An alternative would be setting the memory as RO, set_memory_ro(),
++ * but as of Dec 2020 this isn't possible on arm64.
++ */
++ addr = memremap(priv->mem->base, available, MEMREMAP_WB);
++ if (IS_ERR(addr)) {
++ dev_err(priv->dev, "Failed to remap memory region\n");
++ return PTR_ERR(addr);
++ }
++
++ count = memory_read_from_buffer(val, bytes, &off, addr, available);
++
++ memunmap(addr);
++
++ return count;
++}
++
++static int rmem_probe(struct platform_device *pdev)
++{
++ struct nvmem_config config = { };
++ struct device *dev = &pdev->dev;
++ struct reserved_mem *mem;
++ struct rmem *priv;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++ priv->dev = dev;
++
++ mem = of_reserved_mem_lookup(dev->of_node);
++ if (!mem) {
++ dev_err(dev, "Failed to lookup reserved memory\n");
++ return -EINVAL;
++ }
++ priv->mem = mem;
++
++ config.dev = dev;
++ config.priv = priv;
++ config.name = "rmem";
++ config.size = mem->size;
++ config.reg_read = rmem_read;
++
++ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
++}
++
++static const struct of_device_id rmem_match[] = {
++ { .compatible = "nvmem-rmem", },
++ { /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, rmem_match);
++
++static struct platform_driver rmem_driver = {
++ .probe = rmem_probe,
++ .driver = {
++ .name = "rmem",
++ .of_match_table = rmem_match,
++ },
++};
++module_platform_driver(rmem_driver);
++
++MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>");
++MODULE_DESCRIPTION("Reserved Memory Based nvmem Driver");
++MODULE_LICENSE("GPL");
+--- a/drivers/of/platform.c
++++ b/drivers/of/platform.c
+@@ -511,6 +511,7 @@ static const struct of_device_id reserve
+ { .compatible = "qcom,rmtfs-mem" },
+ { .compatible = "qcom,cmd-db" },
+ { .compatible = "ramoops" },
++ { .compatible = "nvmem-rmem" },
+ {}
+ };
+
--- /dev/null
+From b31f1eb41c140d7979f855df73064b3a3ae8055a Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Fri, 5 Feb 2021 10:08:52 +0000
+Subject: [PATCH] nvmem: Kconfig: Correct typo in NVMEM_RMEM
+
+s/drivers/driver/ as the configuration selects a single driver.
+
+Suggested-by: Randy Dunlap <rdunlap@infradead.org>
+Acked-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210205100853.32372-2-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -273,7 +273,7 @@ config SPRD_EFUSE
+ config NVMEM_RMEM
+ tristate "Reserved Memory Based Driver Support"
+ help
+- This drivers maps reserved memory into an nvmem device. It might be
++ This driver maps reserved memory into an nvmem device. It might be
+ useful to expose information left by firmware in memory.
+
+ This driver can also be built as a module. If so, the module
+++ /dev/null
-From dbc2f62061c6bfba0aee93161ee3194dcee84bd0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Fri, 29 Apr 2022 17:26:46 +0100
-Subject: [PATCH] nvmem: core: support passing DT node in cell info
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some hardware may have NVMEM cells described in Device Tree using
-individual nodes. Let drivers pass such nodes to the NVMEM subsystem so
-they can be later used by NVMEM consumers.
-
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-Link: https://lore.kernel.org/r/20220429162701.2222-2-srinivas.kandagatla@linaro.org
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/nvmem/core.c | 1 +
- include/linux/nvmem-consumer.h | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/nvmem/core.c
-+++ b/drivers/nvmem/core.c
-@@ -374,6 +374,7 @@ static int nvmem_cell_info_to_nvmem_cell
-
- cell->bit_offset = info->bit_offset;
- cell->nbits = info->nbits;
-+ cell->np = info->np;
-
- if (cell->nbits)
- cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
---- a/include/linux/nvmem-consumer.h
-+++ b/include/linux/nvmem-consumer.h
-@@ -25,6 +25,7 @@ struct nvmem_cell_info {
- unsigned int bytes;
- unsigned int bit_offset;
- unsigned int nbits;
-+ struct device_node *np;
- };
-
- /**
--- /dev/null
+From e050f160d4832ce5227fb6ca934969cec0fc48be Mon Sep 17 00:00:00 2001
+From: Zheng Yongjun <zhengyongjun3@huawei.com>
+Date: Tue, 30 Mar 2021 12:12:33 +0100
+Subject: [PATCH] nvmem: convert comma to semicolon
+
+Replace a comma between expression statements by a semicolon.
+
+Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Signed-off-by: Zheng Yongjun <zhengyongjun3@huawei.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-3-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qcom-spmi-sdam.c | 2 +-
+ drivers/nvmem/snvs_lpgpr.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvmem/qcom-spmi-sdam.c
++++ b/drivers/nvmem/qcom-spmi-sdam.c
+@@ -141,7 +141,7 @@ static int sdam_probe(struct platform_de
+ sdam->sdam_config.dev = &pdev->dev;
+ sdam->sdam_config.name = "spmi_sdam";
+ sdam->sdam_config.id = NVMEM_DEVID_AUTO;
+- sdam->sdam_config.owner = THIS_MODULE,
++ sdam->sdam_config.owner = THIS_MODULE;
+ sdam->sdam_config.stride = 1;
+ sdam->sdam_config.word_size = 1;
+ sdam->sdam_config.reg_read = sdam_read;
+--- a/drivers/nvmem/snvs_lpgpr.c
++++ b/drivers/nvmem/snvs_lpgpr.c
+@@ -123,7 +123,7 @@ static int snvs_lpgpr_probe(struct platf
+ cfg->dev = dev;
+ cfg->stride = 4;
+ cfg->word_size = 4;
+- cfg->size = dcfg->size,
++ cfg->size = dcfg->size;
+ cfg->owner = THIS_MODULE;
+ cfg->reg_read = snvs_lpgpr_read;
+ cfg->reg_write = snvs_lpgpr_write;
--- /dev/null
+From 3fef9ed0627af30753a2404b8bd59d92cdb4c0ce Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 30 Mar 2021 12:12:36 +0100
+Subject: [PATCH] nvmem: brcm_nvram: new driver exposing Broadcom's NVRAM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This driver provides access to Broadcom's NVRAM.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-6-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 9 +++++
+ drivers/nvmem/Makefile | 2 +
+ drivers/nvmem/brcm_nvram.c | 78 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 89 insertions(+)
+ create mode 100644 drivers/nvmem/brcm_nvram.c
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -278,4 +278,13 @@ config NVMEM_RMEM
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-rmem.
++
++config NVMEM_BRCM_NVRAM
++ tristate "Broadcom's NVRAM support"
++ depends on ARCH_BCM_5301X || COMPILE_TEST
++ depends on HAS_IOMEM
++ help
++ This driver provides support for Broadcom's NVRAM that can be accessed
++ using I/O mapping.
++
+ endif
+--- a/drivers/nvmem/Makefile
++++ b/drivers/nvmem/Makefile
+@@ -57,3 +57,5 @@ obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_e
+ nvmem_sprd_efuse-y := sprd-efuse.o
+ obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o
+ nvmem-rmem-y := rmem.o
++obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
++nvmem_brcm_nvram-y := brcm_nvram.o
+--- /dev/null
++++ b/drivers/nvmem/brcm_nvram.c
+@@ -0,0 +1,78 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/io.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/nvmem-provider.h>
++#include <linux/platform_device.h>
++
++struct brcm_nvram {
++ struct device *dev;
++ void __iomem *base;
++};
++
++static int brcm_nvram_read(void *context, unsigned int offset, void *val,
++ size_t bytes)
++{
++ struct brcm_nvram *priv = context;
++ u8 *dst = val;
++
++ while (bytes--)
++ *dst++ = readb(priv->base + offset++);
++
++ return 0;
++}
++
++static int brcm_nvram_probe(struct platform_device *pdev)
++{
++ struct nvmem_config config = {
++ .name = "brcm-nvram",
++ .reg_read = brcm_nvram_read,
++ };
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ struct brcm_nvram *priv;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++ priv->dev = dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->base))
++ return PTR_ERR(priv->base);
++
++ config.dev = dev;
++ config.priv = priv;
++ config.size = resource_size(res);
++
++ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
++}
++
++static const struct of_device_id brcm_nvram_of_match_table[] = {
++ { .compatible = "brcm,nvram", },
++ {},
++};
++
++static struct platform_driver brcm_nvram_driver = {
++ .probe = brcm_nvram_probe,
++ .driver = {
++ .name = "brcm_nvram",
++ .of_match_table = brcm_nvram_of_match_table,
++ },
++};
++
++static int __init brcm_nvram_init(void)
++{
++ return platform_driver_register(&brcm_nvram_driver);
++}
++
++subsys_initcall_sync(brcm_nvram_init);
++
++MODULE_AUTHOR("Rafał Miłecki");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table);
--- /dev/null
+From a28e824fb8270eda43fd0f65c2a5fdf33f55c5eb Mon Sep 17 00:00:00 2001
+From: Douglas Anderson <dianders@chromium.org>
+Date: Tue, 30 Mar 2021 12:12:37 +0100
+Subject: [PATCH] nvmem: core: Add functions to make number reading easy
+
+Sometimes the clients of nvmem just want to get a number out of
+nvmem. They don't want to think about exactly how many bytes the nvmem
+cell took up. They just want the number. Let's make it easy.
+
+In general this concept is useful because nvmem space is precious and
+usually the fewest bits are allocated that will hold a given value on
+a given system. However, even though small numbers might be fine on
+one system that doesn't mean that logically the number couldn't be
+bigger. Imagine nvmem containing a max frequency for a component. On
+one system perhaps that fits in 16 bits. On another system it might
+fit in 32 bits. The code reading this number doesn't care--it just
+wants the number.
+
+We'll provide two functions: nvmem_cell_read_variable_le_u32() and
+nvmem_cell_read_variable_le_u64().
+
+Comparing these to the existing functions like nvmem_cell_read_u32():
+* These new functions have no problems if the value was stored in
+ nvmem in fewer bytes. It's OK to use these function as long as the
+ value stored will fit in 32-bits (or 64-bits).
+* These functions avoid problems that the earlier APIs had with bit
+ offsets. For instance, you can't use nvmem_cell_read_u32() to read a
+ value has nbits=32 and bit_offset=4 because the nvmem cell must be
+ at least 5 bytes big to hold this value. The new API accounts for
+ this and works fine.
+* These functions make it very explicit that they assume that the
+ number was stored in little endian format. The old functions made
+ this assumption whenever bit_offset was non-zero (see
+ nvmem_shift_read_buffer_in_place()) but didn't whenever the
+ bit_offset was zero.
+
+NOTE: it's assumed that we don't need an 8-bit or 16-bit version of
+this function. The 32-bit version of the function can be used to read
+8-bit or 16-bit data.
+
+At the moment, I'm only adding the "unsigned" versions of these
+functions, but if it ends up being useful someone could add a "signed"
+version that did 2's complement sign extension.
+
+At the moment, I'm only adding the "little endian" versions of these
+functions. Adding the "big endian" version would require adding "big
+endian" support to nvmem_shift_read_buffer_in_place().
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-7-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 95 ++++++++++++++++++++++++++++++++++
+ include/linux/nvmem-consumer.h | 4 ++
+ 2 files changed, 99 insertions(+)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1612,6 +1612,101 @@ int nvmem_cell_read_u64(struct device *d
+ }
+ EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
+
++static void *nvmem_cell_read_variable_common(struct device *dev,
++ const char *cell_id,
++ size_t max_len, size_t *len)
++{
++ struct nvmem_cell *cell;
++ int nbits;
++ void *buf;
++
++ cell = nvmem_cell_get(dev, cell_id);
++ if (IS_ERR(cell))
++ return cell;
++
++ nbits = cell->nbits;
++ buf = nvmem_cell_read(cell, len);
++ nvmem_cell_put(cell);
++ if (IS_ERR(buf))
++ return buf;
++
++ /*
++ * If nbits is set then nvmem_cell_read() can significantly exaggerate
++ * the length of the real data. Throw away the extra junk.
++ */
++ if (nbits)
++ *len = DIV_ROUND_UP(nbits, 8);
++
++ if (*len > max_len) {
++ kfree(buf);
++ return ERR_PTR(-ERANGE);
++ }
++
++ return buf;
++}
++
++/**
++ * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++ u32 *val)
++{
++ size_t len;
++ u8 *buf;
++ int i;
++
++ buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++
++ /* Copy w/ implicit endian conversion */
++ *val = 0;
++ for (i = 0; i < len; i++)
++ *val |= buf[i] << (8 * i);
++
++ kfree(buf);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
++
++/**
++ * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++ u64 *val)
++{
++ size_t len;
++ u8 *buf;
++ int i;
++
++ buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++ if (IS_ERR(buf))
++ return PTR_ERR(buf);
++
++ /* Copy w/ implicit endian conversion */
++ *val = 0;
++ for (i = 0; i < len; i++)
++ *val |= buf[i] << (8 * i);
++
++ kfree(buf);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64);
++
+ /**
+ * nvmem_device_cell_read() - Read a given nvmem device and cell
+ *
+--- a/include/linux/nvmem-consumer.h
++++ b/include/linux/nvmem-consumer.h
+@@ -65,6 +65,10 @@ int nvmem_cell_read_u8(struct device *de
+ int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
+ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
+ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val);
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++ u32 *val);
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++ u64 *val);
+
+ /* direct nvmem device read/write interface */
+ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
--- /dev/null
+From 55022fdeace8e432f008787ce03703bdcc9c3ca9 Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.king@canonical.com>
+Date: Tue, 30 Mar 2021 12:12:38 +0100
+Subject: [PATCH] nvmem: core: Fix unintentional sign extension issue
+
+The shifting of the u8 integer buf[3] by 24 bits to the left will
+be promoted to a 32 bit signed int and then sign-extended to a
+u64. In the event that the top bit of buf[3] is set then all
+then all the upper 32 bits of the u64 end up as also being set
+because of the sign-extension. Fix this by casting buf[i] to
+a u64 before the shift.
+
+Fixes: a28e824fb827 ("nvmem: core: Add functions to make number reading easy")
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Addresses-Coverity: ("Unintended sign extension")
+Link: https://lore.kernel.org/r/20210330111241.19401-8-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1699,7 +1699,7 @@ int nvmem_cell_read_variable_le_u64(stru
+ /* Copy w/ implicit endian conversion */
+ *val = 0;
+ for (i = 0; i < len; i++)
+- *val |= buf[i] << (8 * i);
++ *val |= (uint64_t)buf[i] << (8 * i);
+
+ kfree(buf);
+
--- /dev/null
+From cc1bc56fdc76a55bb8fae9a145a2e60bf22fb129 Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Date: Tue, 30 Mar 2021 12:12:39 +0100
+Subject: [PATCH] nvmem: rmem: fix undefined reference to memremap
+
+Fix below error reporte by kernel test robot
+rmem.c:(.text+0x14e): undefined reference to memremap
+s390x-linux-gnu-ld: rmem.c:(.text+0x1b6): undefined reference to memunmap
+
+Fixes: 5a3fa75a4d9c ("nvmem: Add driver to expose reserved memory as nvmem")
+Reported-by: kernel test robot <lkp@intel.com>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-9-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -272,6 +272,7 @@ config SPRD_EFUSE
+
+ config NVMEM_RMEM
+ tristate "Reserved Memory Based Driver Support"
++ depends on HAS_IOMEM
+ help
+ This driver maps reserved memory into an nvmem device. It might be
+ useful to expose information left by firmware in memory.
--- /dev/null
+From 5a1bea2a2572ce5eb4bdcf432a6929681ee381f2 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Tue, 30 Mar 2021 12:12:41 +0100
+Subject: [PATCH] nvmem: qfprom: Add support for fuse blowing on sc7280
+
+Handle the differences across LDO voltage needed for blowing fuses,
+and the blow timer value, identified using a minor version of 15
+on sc7280.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Ravi Kumar Bokka <rbokka@codeaurora.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-11-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qfprom.c | 27 +++++++++++++++++++++++++--
+ 1 file changed, 25 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -45,11 +45,13 @@ MODULE_PARM_DESC(read_raw_data, "Read ra
+ * @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow.
+ * @qfprom_blow_set_freq: The frequency required to set when we start the
+ * fuse blowing.
++ * @qfprom_blow_uV: LDO voltage to be set when doing efuse blow
+ */
+ struct qfprom_soc_data {
+ u32 accel_value;
+ u32 qfprom_blow_timer_value;
+ u32 qfprom_blow_set_freq;
++ int qfprom_blow_uV;
+ };
+
+ /**
+@@ -111,6 +113,15 @@ static const struct qfprom_soc_compatibl
+ .nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout)
+ };
+
++static const struct nvmem_keepout sc7280_qfprom_keepout[] = {
++ {.start = 0x128, .end = 0x148},
++ {.start = 0x238, .end = 0x248}
++};
++
++static const struct qfprom_soc_compatible_data sc7280_qfprom = {
++ .keepout = sc7280_qfprom_keepout,
++ .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout)
++};
+ /**
+ * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
+ * @priv: Our driver data.
+@@ -168,6 +179,7 @@ static int qfprom_enable_fuse_blowing(co
+ struct qfprom_touched_values *old)
+ {
+ int ret;
++ int qfprom_blow_uV = priv->soc_data->qfprom_blow_uV;
+
+ ret = clk_prepare_enable(priv->secclk);
+ if (ret) {
+@@ -187,9 +199,9 @@ static int qfprom_enable_fuse_blowing(co
+ * a rail shared do don't specify a max--regulator constraints
+ * will handle.
+ */
+- ret = regulator_set_voltage(priv->vcc, 1800000, INT_MAX);
++ ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX);
+ if (ret) {
+- dev_err(priv->dev, "Failed to set 1.8 voltage\n");
++ dev_err(priv->dev, "Failed to set %duV\n", qfprom_blow_uV);
+ goto err_clk_rate_set;
+ }
+
+@@ -311,6 +323,14 @@ static const struct qfprom_soc_data qfpr
+ .accel_value = 0xD10,
+ .qfprom_blow_timer_value = 25,
+ .qfprom_blow_set_freq = 4800000,
++ .qfprom_blow_uV = 1800000,
++};
++
++static const struct qfprom_soc_data qfprom_7_15_data = {
++ .accel_value = 0xD08,
++ .qfprom_blow_timer_value = 24,
++ .qfprom_blow_set_freq = 4800000,
++ .qfprom_blow_uV = 1900000,
+ };
+
+ static int qfprom_probe(struct platform_device *pdev)
+@@ -379,6 +399,8 @@ static int qfprom_probe(struct platform_
+
+ if (major_version == 7 && minor_version == 8)
+ priv->soc_data = &qfprom_7_8_data;
++ if (major_version == 7 && minor_version == 15)
++ priv->soc_data = &qfprom_7_15_data;
+
+ priv->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(priv->vcc))
+@@ -405,6 +427,7 @@ static int qfprom_probe(struct platform_
+ static const struct of_device_id qfprom_of_match[] = {
+ { .compatible = "qcom,qfprom",},
+ { .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom},
++ { .compatible = "qcom,sc7280-qfprom", .data = &sc7280_qfprom},
+ {/* sentinel */},
+ };
+ MODULE_DEVICE_TABLE(of, qfprom_of_match);
+++ /dev/null
-From 7a69ff9c9bde03a690ea783970f664782fc303d8 Mon Sep 17 00:00:00 2001
-From: Christian Lamparter <chunkeey@gmail.com>
-Date: Fri, 4 Nov 2022 17:52:03 +0100
-Subject: [PATCH] nvmem: u-boot-env: fix crc32_data_offset on redundant
- u-boot-env
-
-The Western Digital MyBook Live (PowerPC 464/APM82181)
-has a set of redundant u-boot-env. Loading up the driver
-the following error:
-
-| u_boot_env: Invalid calculated CRC32: 0x4f8f2c86 (expected: 0x98b14514)
-| u_boot_env: probe of partition@1e000 failed with error -22
-
-Looking up the userspace libubootenv utilities source [0],
-it looks like the "mark" or "flag" is not part of the
-crc32 sum... which is unfortunate :(
-
-|static int libuboot_load(struct uboot_ctx *ctx)
-|{
-|[...]
-| if (ctx->redundant) {
-| [...]
-| offsetdata = offsetof(struct uboot_env_redund, data);
-| [...] //-----^^
-| }
-| usable_envsize = ctx->size - offsetdata;
-| buf[0] = malloc(bufsize);
-|[...]
-| for (i = 0; i < copies; i++) {
-| data = (uint8_t *)(buf[i] + offsetdata);
-| uint32_t crc;
-|
-| ret = devread(ctx, i, buf[i]);
-| [...]
-| crc = *(uint32_t *)(buf[i] + offsetcrc);
-| dev->crc = crc32(0, (uint8_t *)data, usable_envsize);
-|
-
-[0] https://github.com/sbabic/libubootenv/blob/master/src/uboot_env.c#L951
-Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables")
-Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
----
- drivers/nvmem/u-boot-env.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -135,7 +135,7 @@ static int u_boot_env_parse(struct u_boo
- break;
- case U_BOOT_FORMAT_REDUNDANT:
- crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
-- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
- data_offset = offsetof(struct u_boot_env_image_redundant, data);
- break;
- }
+++ /dev/null
-From 0e71cac033bb7689c4dfa2e6814191337ef770f5 Mon Sep 17 00:00:00 2001
-From: INAGAKI Hiroshi <musashino.open@gmail.com>
-Date: Thu, 13 Oct 2022 00:51:33 +0900
-Subject: [PATCH] nvmem: u-boot-env: align endianness of crc32 values
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch fixes crc32 error on Big-Endianness system by conversion of
-calculated crc32 value.
-
-Little-Endianness system:
-
- obtained crc32: Little
-calculated crc32: Little
-
-Big-Endianness system:
-
- obtained crc32: Little
-calculated crc32: Big
-
-log (APRESIA ApresiaLightGS120GT-SS, RTL8382M, Big-Endianness):
-
-[ 8.570000] u_boot_env 18001200.spi:flash@0:partitions:partition@c0000: Invalid calculated CRC32: 0x88cd6f09 (expected: 0x096fcd88)
-[ 8.580000] u_boot_env: probe of 18001200.spi:flash@0:partitions:partition@c0000 failed with error -22
-
-Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables")
-
-Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
-Acked-by: Rafał Miłecki <rafal@milecki.pl>
-Tested-by: Christian Lamparter <chunkeey@gmail.com>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
- drivers/nvmem/u-boot-env.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -143,7 +143,7 @@ static int u_boot_env_parse(struct u_boo
- crc32_data_len = priv->mtd->size - crc32_data_offset;
- data_len = priv->mtd->size - data_offset;
-
-- calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
-+ calc = le32_to_cpu((__le32)crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L);
- if (calc != crc32) {
- dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
- err = -EINVAL;
+++ /dev/null
-From 5b4eaafbeac472fc19049152f18e88aecb2b2829 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Mon, 17 Oct 2022 09:17:22 +0200
-Subject: [PATCH] nvmem: u-boot-env: add Broadcom format support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Broadcom uses U-Boot for a lot of their bcmbca familiy chipsets. They
-decided to store U-Boot environment data inside U-Boot partition and to
-use a custom header (with "uEnv" magic and env data length).
-
-Add support for Broadcom's specific binding and their custom format.
-
-Ref: 6b0584c19d87 ("dt-bindings: nvmem: u-boot,env: add Broadcom's variant binding")
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
-Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
----
- drivers/nvmem/u-boot-env.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
---- a/drivers/nvmem/u-boot-env.c
-+++ b/drivers/nvmem/u-boot-env.c
-@@ -16,6 +16,7 @@
- enum u_boot_env_format {
- U_BOOT_FORMAT_SINGLE,
- U_BOOT_FORMAT_REDUNDANT,
-+ U_BOOT_FORMAT_BROADCOM,
- };
-
- struct u_boot_env {
-@@ -40,6 +41,13 @@ struct u_boot_env_image_redundant {
- uint8_t data[];
- } __packed;
-
-+struct u_boot_env_image_broadcom {
-+ __le32 magic;
-+ __le32 len;
-+ __le32 crc32;
-+ uint8_t data[0];
-+} __packed;
-+
- static int u_boot_env_read(void *context, unsigned int offset, void *val,
- size_t bytes)
- {
-@@ -138,6 +146,11 @@ static int u_boot_env_parse(struct u_boo
- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
- data_offset = offsetof(struct u_boot_env_image_redundant, data);
- break;
-+ case U_BOOT_FORMAT_BROADCOM:
-+ crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32);
-+ crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-+ data_offset = offsetof(struct u_boot_env_image_broadcom, data);
-+ break;
- }
- crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
- crc32_data_len = priv->mtd->size - crc32_data_offset;
-@@ -202,6 +215,7 @@ static const struct of_device_id u_boot_
- { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
- { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
- { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
-+ { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BROADCOM, },
- {},
- };
-
--- /dev/null
+From 1333a6779501f4cc662ff5c8b36b0a22f3a7ddc6 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Sat, 24 Apr 2021 13:06:04 +0200
+Subject: [PATCH] nvmem: core: allow specifying of_node
+
+Until now, the of_node of the parent device is used. Some devices
+provide more than just the nvmem provider. To avoid name space clashes,
+add a way to allow specifying the nvmem cells in subnodes. Consider the
+following example:
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ reg = <0x000000 0x010000>;
+ };
+ };
+
+ otp {
+ compatible = "user-otp";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ serial-number@0 {
+ reg = <0x0 0x8>;
+ };
+ };
+ };
+
+There the nvmem provider might be the MTD partition or the OTP region of
+the flash.
+
+Add a new config->of_node parameter, which if set, will be used instead
+of the parent's of_node.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210424110608.15748-2-michael@walle.cc
+---
+ drivers/nvmem/core.c | 4 +++-
+ include/linux/nvmem-provider.h | 2 ++
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -794,7 +794,9 @@ struct nvmem_device *nvmem_register(cons
+ nvmem->reg_write = config->reg_write;
+ nvmem->keepout = config->keepout;
+ nvmem->nkeepout = config->nkeepout;
+- if (!config->no_of_node)
++ if (config->of_node)
++ nvmem->dev.of_node = config->of_node;
++ else if (!config->no_of_node)
+ nvmem->dev.of_node = config->dev->of_node;
+
+ switch (config->id) {
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -57,6 +57,7 @@ struct nvmem_keepout {
+ * @type: Type of the nvmem storage
+ * @read_only: Device is read-only.
+ * @root_only: Device is accessibly to root only.
++ * @of_node: If given, this will be used instead of the parent's of_node.
+ * @no_of_node: Device should not use the parent's of_node even if it's !NULL.
+ * @reg_read: Callback to read data.
+ * @reg_write: Callback to write data.
+@@ -86,6 +87,7 @@ struct nvmem_config {
+ enum nvmem_type type;
+ bool read_only;
+ bool root_only;
++ struct device_node *of_node;
+ bool no_of_node;
+ nvmem_reg_read_t reg_read;
+ nvmem_reg_write_t reg_write;
--- /dev/null
+From 20be064ec864086bca7a4eb62c772a397b44afb7 Mon Sep 17 00:00:00 2001
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Date: Fri, 7 May 2021 19:02:48 +0200
+Subject: [PATCH] nvmem: sprd: Fix an error message
+
+'ret' is known to be 0 here.
+The expected error status is stored in 'status', so use it instead.
+
+Also change %d in %u, because status is an u32, not a int.
+
+Fixes: 096030e7f449 ("nvmem: sprd: Add Spreadtrum SoCs eFuse support")
+Acked-by: Chunyan Zhang <zhang.lyra@gmail.com>
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Link: https://lore.kernel.org/r/5bc44aace2fe7e1c91d8b35c8fe31e7134ceab2c.1620406852.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/sprd-efuse.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/sprd-efuse.c
++++ b/drivers/nvmem/sprd-efuse.c
+@@ -234,7 +234,7 @@ static int sprd_efuse_raw_prog(struct sp
+ status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG);
+ if (status) {
+ dev_err(efuse->dev,
+- "write error status %d of block %d\n", ret, blk);
++ "write error status %u of block %d\n", status, blk);
+
+ writel(SPRD_EFUSE_ERR_CLR_MASK,
+ efuse->base + SPRD_EFUSE_ERR_CLR);
--- /dev/null
+From 78a005a22d5608b266eafa011b093a33284c52ce Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 11 Jun 2021 09:33:45 +0100
+Subject: [PATCH] nvmem: sunxi_sid: Set type to OTP
+
+This device currently reports an "Unknown" type in sysfs.
+Since it is an eFuse hardware device, set its type to OTP.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Acked-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210611083348.20170-7-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/sunxi_sid.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/nvmem/sunxi_sid.c
++++ b/drivers/nvmem/sunxi_sid.c
+@@ -142,6 +142,7 @@ static int sunxi_sid_probe(struct platfo
+
+ nvmem_cfg->dev = dev;
+ nvmem_cfg->name = "sunxi-sid";
++ nvmem_cfg->type = NVMEM_TYPE_OTP;
+ nvmem_cfg->read_only = true;
+ nvmem_cfg->size = cfg->size;
+ nvmem_cfg->word_size = 1;
--- /dev/null
+From c813bb37bd32cb967060a2c573fae4ea518d32eb Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Fri, 11 Jun 2021 09:33:46 +0100
+Subject: [PATCH] nvmem: qfprom: minor nit fixes
+
+Fix a missed newline, change an 'if' to 'else if' and update
+a comment which is stale after the merge of '5a1bea2a: nvmem:
+qfprom: Add support for fuseblowing on sc7280'
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210611083348.20170-8-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qfprom.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -122,6 +122,7 @@ static const struct qfprom_soc_compatibl
+ .keepout = sc7280_qfprom_keepout,
+ .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout)
+ };
++
+ /**
+ * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
+ * @priv: Our driver data.
+@@ -195,7 +196,7 @@ static int qfprom_enable_fuse_blowing(co
+ }
+
+ /*
+- * Hardware requires 1.8V min for fuse blowing; this may be
++ * Hardware requires a min voltage for fuse blowing; this may be
+ * a rail shared do don't specify a max--regulator constraints
+ * will handle.
+ */
+@@ -399,7 +400,7 @@ static int qfprom_probe(struct platform_
+
+ if (major_version == 7 && minor_version == 8)
+ priv->soc_data = &qfprom_7_8_data;
+- if (major_version == 7 && minor_version == 15)
++ else if (major_version == 7 && minor_version == 15)
+ priv->soc_data = &qfprom_7_15_data;
+
+ priv->vcc = devm_regulator_get(&pdev->dev, "vcc");
--- /dev/null
+From 1f7b4d87874624f4beb25253900a25306a193b8b Mon Sep 17 00:00:00 2001
+From: Douglas Anderson <dianders@chromium.org>
+Date: Fri, 11 Jun 2021 09:33:47 +0100
+Subject: [PATCH] nvmem: core: constify nvmem_cell_read_variable_common()
+ return value
+
+The caller doesn't modify the memory pointed to by the pointer so it
+can be const.
+
+Suggested-by: Stephen Boyd <swboyd@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Stephen Boyd <swboyd@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210611083348.20170-9-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1614,9 +1614,9 @@ int nvmem_cell_read_u64(struct device *d
+ }
+ EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
+
+-static void *nvmem_cell_read_variable_common(struct device *dev,
+- const char *cell_id,
+- size_t max_len, size_t *len)
++static const void *nvmem_cell_read_variable_common(struct device *dev,
++ const char *cell_id,
++ size_t max_len, size_t *len)
+ {
+ struct nvmem_cell *cell;
+ int nbits;
+@@ -1660,7 +1660,7 @@ int nvmem_cell_read_variable_le_u32(stru
+ u32 *val)
+ {
+ size_t len;
+- u8 *buf;
++ const u8 *buf;
+ int i;
+
+ buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
+@@ -1691,7 +1691,7 @@ int nvmem_cell_read_variable_le_u64(stru
+ u64 *val)
+ {
+ size_t len;
+- u8 *buf;
++ const u8 *buf;
+ int i;
+
+ buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
--- /dev/null
+From 989f77e3fdee2e8f414dd1da9b6397d8763d414e Mon Sep 17 00:00:00 2001
+From: Douglas Anderson <dianders@chromium.org>
+Date: Fri, 11 Jun 2021 09:33:48 +0100
+Subject: [PATCH] nvmem: qfprom: Improve the comment about regulator setting
+
+In review feedback Joe Perches found the existing comment
+confusing. Let's use something based on the wording proposed by Joe.
+
+Suggested-by: Joe Perches <joe@perches.com>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Stephen Boyd <swboyd@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210611083348.20170-10-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qfprom.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -196,9 +196,9 @@ static int qfprom_enable_fuse_blowing(co
+ }
+
+ /*
+- * Hardware requires a min voltage for fuse blowing; this may be
+- * a rail shared do don't specify a max--regulator constraints
+- * will handle.
++ * Hardware requires a minimum voltage for fuse blowing.
++ * This may be a shared rail so don't specify a maximum.
++ * Regulator constraints will cap to the actual maximum.
+ */
+ ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX);
+ if (ret) {
--- /dev/null
+From: Rafał Miłecki <rafal@milecki.pl>
+Subject: [PATCH] nvmem: add NVMEM_TYPE_FRAM
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -180,6 +180,7 @@ static const char * const nvmem_type_str
+ [NVMEM_TYPE_EEPROM] = "EEPROM",
+ [NVMEM_TYPE_OTP] = "OTP",
+ [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
++ [NVMEM_TYPE_FRAM] = "FRAM",
+ };
+
+ #ifdef CONFIG_DEBUG_LOCK_ALLOC
+@@ -361,6 +362,9 @@ static int nvmem_sysfs_setup_compat(stru
+ if (!config->base_dev)
+ return -EINVAL;
+
++ if (config->type == NVMEM_TYPE_FRAM)
++ bin_attr_nvmem_eeprom_compat.attr.name = "fram";
++
+ nvmem->eeprom = bin_attr_nvmem_eeprom_compat;
+ nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem);
+ nvmem->eeprom.size = nvmem->size;
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -25,6 +25,7 @@ enum nvmem_type {
+ NVMEM_TYPE_EEPROM,
+ NVMEM_TYPE_OTP,
+ NVMEM_TYPE_BATTERY_BACKED,
++ NVMEM_TYPE_FRAM,
+ };
+
+ #define NVMEM_DEVID_NONE (-1)
--- /dev/null
+From 7b808449f572d07bee840cd9da7e2fe6a1b8f4b5 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Fri, 6 Aug 2021 09:59:46 +0100
+Subject: [PATCH] nvmem: qfprom: sc7280: Handle the additional power-domains
+ vote
+
+On sc7280, to reliably blow fuses, we need an additional vote
+on max performance state of 'MX' power-domain.
+Add support for power-domain performance state voting in the
+driver.
+
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210806085947.22682-4-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/qfprom.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/drivers/nvmem/qfprom.c
++++ b/drivers/nvmem/qfprom.c
+@@ -12,6 +12,8 @@
+ #include <linux/mod_devicetable.h>
+ #include <linux/nvmem-provider.h>
+ #include <linux/platform_device.h>
++#include <linux/pm_domain.h>
++#include <linux/pm_runtime.h>
+ #include <linux/property.h>
+ #include <linux/regulator/consumer.h>
+
+@@ -142,6 +144,9 @@ static void qfprom_disable_fuse_blowing(
+ writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET);
+ writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET);
+
++ dev_pm_genpd_set_performance_state(priv->dev, 0);
++ pm_runtime_put(priv->dev);
++
+ /*
+ * This may be a shared rail and may be able to run at a lower rate
+ * when we're not blowing fuses. At the moment, the regulator framework
+@@ -212,6 +217,14 @@ static int qfprom_enable_fuse_blowing(co
+ goto err_clk_rate_set;
+ }
+
++ ret = pm_runtime_get_sync(priv->dev);
++ if (ret < 0) {
++ pm_runtime_put_noidle(priv->dev);
++ dev_err(priv->dev, "Failed to enable power-domain\n");
++ goto err_reg_enable;
++ }
++ dev_pm_genpd_set_performance_state(priv->dev, INT_MAX);
++
+ old->timer_val = readl(priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET);
+ old->accel_val = readl(priv->qfpconf + QFPROM_ACCEL_OFFSET);
+ writel(priv->soc_data->qfprom_blow_timer_value,
+@@ -221,6 +234,8 @@ static int qfprom_enable_fuse_blowing(co
+
+ return 0;
+
++err_reg_enable:
++ regulator_disable(priv->vcc);
+ err_clk_rate_set:
+ clk_set_rate(priv->secclk, old->clk_rate);
+ err_clk_prepared:
+@@ -320,6 +335,11 @@ static int qfprom_reg_read(void *context
+ return 0;
+ }
+
++static void qfprom_runtime_disable(void *data)
++{
++ pm_runtime_disable(data);
++}
++
+ static const struct qfprom_soc_data qfprom_7_8_data = {
+ .accel_value = 0xD10,
+ .qfprom_blow_timer_value = 25,
+@@ -420,6 +440,11 @@ static int qfprom_probe(struct platform_
+ econfig.reg_write = qfprom_reg_write;
+ }
+
++ pm_runtime_enable(dev);
++ ret = devm_add_action_or_reset(dev, qfprom_runtime_disable, dev);
++ if (ret)
++ return ret;
++
+ nvmem = devm_nvmem_register(dev, &econfig);
+
+ return PTR_ERR_OR_ZERO(nvmem);
--- /dev/null
+From de0534df93474f268486c486ea7e01b44a478026 Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Date: Fri, 6 Aug 2021 09:59:47 +0100
+Subject: [PATCH] nvmem: core: fix error handling while validating keepout
+ regions
+
+Current error path on failure of validating keepout regions is calling
+put_device, eventhough the device is not even registered at that point.
+
+Fix this by adding proper error handling of freeing ida and nvmem.
+
+Fixes: fd3bb8f54a88 ("nvmem: core: Add support for keepout regions")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210806085947.22682-5-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -826,8 +826,11 @@ struct nvmem_device *nvmem_register(cons
+
+ if (nvmem->nkeepout) {
+ rval = nvmem_validate_keepouts(nvmem);
+- if (rval)
+- goto err_put_device;
++ if (rval) {
++ ida_free(&nvmem_ida, nvmem->id);
++ kfree(nvmem);
++ return ERR_PTR(rval);
++ }
+ }
+
+ dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
--- /dev/null
+From 3683b761fe3a10ad18515acd5368dd601268cfe5 Mon Sep 17 00:00:00 2001
+From: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+Date: Tue, 10 Aug 2021 16:30:36 +0100
+Subject: [PATCH] nvmem: nintendo-otp: Add new driver for the Wii and Wii U OTP
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This OTP is read-only and contains various keys used by the console to
+decrypt, encrypt or verify various pieces of storage.
+
+Its size depends on the console, it is 128 bytes on the Wii and
+1024 bytes on the Wii U (split into eight 128 bytes banks).
+
+It can be used directly by writing into one register and reading from
+the other one, without any additional synchronisation.
+
+This driver was written based on reversed documentation, see:
+https://wiiubrew.org/wiki/Hardware/OTP
+
+Tested-by: Jonathan Neuschäfer <j.ne@posteo.net> # on Wii
+Tested-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> # on Wii U
+Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210810153036.1494-3-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 11 ++++
+ drivers/nvmem/Makefile | 2 +
+ drivers/nvmem/nintendo-otp.c | 124 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 137 insertions(+)
+ create mode 100644 drivers/nvmem/nintendo-otp.c
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -107,6 +107,17 @@ config MTK_EFUSE
+ This driver can also be built as a module. If so, the module
+ will be called efuse-mtk.
+
++config NVMEM_NINTENDO_OTP
++ tristate "Nintendo Wii and Wii U OTP Support"
++ help
++ This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
++
++ This memory contains common and per-console keys, signatures and
++ related data required to access peripherals.
++
++ This driver can also be built as a module. If so, the module
++ will be called nvmem-nintendo-otp.
++
+ config QCOM_QFPROM
+ tristate "QCOM QFPROM Support"
+ depends on ARCH_QCOM || COMPILE_TEST
+--- a/drivers/nvmem/Makefile
++++ b/drivers/nvmem/Makefile
+@@ -23,6 +23,8 @@ obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem
+ nvmem_lpc18xx_otp-y := lpc18xx_otp.o
+ obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o
+ nvmem-mxs-ocotp-y := mxs-ocotp.o
++obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o
++nvmem-nintendo-otp-y := nintendo-otp.o
+ obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o
+ nvmem_mtk-efuse-y := mtk-efuse.o
+ obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
+--- /dev/null
++++ b/drivers/nvmem/nintendo-otp.c
+@@ -0,0 +1,124 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Nintendo Wii and Wii U OTP driver
++ *
++ * This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
++ *
++ * This memory contains common and per-console keys, signatures and
++ * related data required to access peripherals.
++ *
++ * Based on reversed documentation from https://wiiubrew.org/wiki/Hardware/OTP
++ *
++ * Copyright (C) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
++ */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/nvmem-provider.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++
++#define HW_OTPCMD 0
++#define HW_OTPDATA 4
++#define OTP_READ 0x80000000
++#define BANK_SIZE 128
++#define WORD_SIZE 4
++
++struct nintendo_otp_priv {
++ void __iomem *regs;
++};
++
++struct nintendo_otp_devtype_data {
++ const char *name;
++ unsigned int num_banks;
++};
++
++static const struct nintendo_otp_devtype_data hollywood_otp_data = {
++ .name = "wii-otp",
++ .num_banks = 1,
++};
++
++static const struct nintendo_otp_devtype_data latte_otp_data = {
++ .name = "wiiu-otp",
++ .num_banks = 8,
++};
++
++static int nintendo_otp_reg_read(void *context,
++ unsigned int reg, void *_val, size_t bytes)
++{
++ struct nintendo_otp_priv *priv = context;
++ u32 *val = _val;
++ int words = bytes / WORD_SIZE;
++ u32 bank, addr;
++
++ while (words--) {
++ bank = (reg / BANK_SIZE) << 8;
++ addr = (reg / WORD_SIZE) % (BANK_SIZE / WORD_SIZE);
++ iowrite32be(OTP_READ | bank | addr, priv->regs + HW_OTPCMD);
++ *val++ = ioread32be(priv->regs + HW_OTPDATA);
++ reg += WORD_SIZE;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id nintendo_otp_of_table[] = {
++ { .compatible = "nintendo,hollywood-otp", .data = &hollywood_otp_data },
++ { .compatible = "nintendo,latte-otp", .data = &latte_otp_data },
++ {/* sentinel */},
++};
++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);
++ struct resource *res;
++ struct nvmem_device *nvmem;
++ struct nintendo_otp_priv *priv;
++
++ struct nvmem_config config = {
++ .stride = WORD_SIZE,
++ .word_size = WORD_SIZE,
++ .reg_read = nintendo_otp_reg_read,
++ .read_only = true,
++ .root_only = true,
++ };
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->regs))
++ return PTR_ERR(priv->regs);
++
++ if (of_id->data) {
++ const struct nintendo_otp_devtype_data *data = of_id->data;
++ config.name = data->name;
++ config.size = data->num_banks * BANK_SIZE;
++ }
++
++ config.dev = dev;
++ config.priv = priv;
++
++ nvmem = devm_nvmem_register(dev, &config);
++
++ return PTR_ERR_OR_ZERO(nvmem);
++}
++
++static struct platform_driver nintendo_otp_driver = {
++ .probe = nintendo_otp_probe,
++ .driver = {
++ .name = "nintendo-otp",
++ .of_match_table = nintendo_otp_of_table,
++ },
++};
++module_platform_driver(nintendo_otp_driver);
++MODULE_AUTHOR("Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>");
++MODULE_DESCRIPTION("Nintendo Wii and Wii U OTP driver");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 7af526c740bdbd5b4dcebba04ace5b3b0c07801f Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Tue, 14 Sep 2021 11:29:49 +0200
+Subject: [PATCH] nvmem: NVMEM_NINTENDO_OTP should depend on WII
+
+The Nintendo Wii and Wii U OTP is only present on Nintendo Wii and Wii U
+consoles. Hence add a dependency on WII, to prevent asking the user
+about this driver when configuring a kernel without Nintendo Wii and Wii
+U console support.
+
+Fixes: 3683b761fe3a10ad ("nvmem: nintendo-otp: Add new driver for the Wii and Wii U OTP")
+Reviewed-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/r/01318920709dddc4d85fe895e2083ca0eee234d8.1631611652.git.geert+renesas@glider.be
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -109,6 +109,7 @@ config MTK_EFUSE
+
+ config NVMEM_NINTENDO_OTP
+ tristate "Nintendo Wii and Wii U OTP Support"
++ depends on WII || COMPILE_TEST
+ help
+ This is a driver exposing the OTP of a Nintendo Wii or Wii U console.
+
--- /dev/null
+From f955dc14450695564926711cf9fa8e1d5d854302 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 15 Jun 2022 21:43:00 +0200
+Subject: [PATCH] nvmem: add driver handling U-Boot environment variables
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+U-Boot stores its setup as environment variables. It's a list of
+key-value pairs stored on flash device with a custom header.
+
+This commit adds an NVMEM driver that:
+1. Provides NVMEM access to environment vars binary data
+2. Extracts variables as NVMEM cells
+
+Current Linux's NVMEM sysfs API allows reading whole NVMEM data block.
+It can be used by user-space tools for reading U-Boot env vars block
+without the hassle of finding its location. Parsing will still need to
+be re-done there.
+
+Kernel-parsed NVMEM cells can be read however by Linux drivers. This may
+be useful for Ethernet drivers for reading device MAC address which is
+often stored as U-Boot env variable.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+---
+
+--- a/drivers/nvmem/Kconfig
++++ b/drivers/nvmem/Kconfig
+@@ -300,4 +300,17 @@ config NVMEM_BRCM_NVRAM
+ This driver provides support for Broadcom's NVRAM that can be accessed
+ using I/O mapping.
+
++config NVMEM_U_BOOT_ENV
++ tristate "U-Boot environment variables support"
++ depends on OF && MTD
++ select CRC32
++ help
++ U-Boot stores its setup as environment variables. This driver adds
++ support for verifying & exporting such data. It also exposes variables
++ as NVMEM cells so they can be referenced by other drivers.
++
++ Currently this drivers works only with env variables on top of MTD.
++
++ If compiled as module it will be called nvmem_u-boot-env.
++
+ endif
+--- a/drivers/nvmem/Makefile
++++ b/drivers/nvmem/Makefile
+@@ -61,3 +61,5 @@ obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.
+ nvmem-rmem-y := rmem.o
+ obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
+ nvmem_brcm_nvram-y := brcm_nvram.o
++obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o
++nvmem_u-boot-env-y := u-boot-env.o
+--- /dev/null
++++ b/drivers/nvmem/u-boot-env.c
+@@ -0,0 +1,218 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (C) 2022 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/crc32.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/nvmem-provider.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++enum u_boot_env_format {
++ U_BOOT_FORMAT_SINGLE,
++ U_BOOT_FORMAT_REDUNDANT,
++};
++
++struct u_boot_env {
++ struct device *dev;
++ enum u_boot_env_format format;
++
++ struct mtd_info *mtd;
++
++ /* Cells */
++ struct nvmem_cell_info *cells;
++ int ncells;
++};
++
++struct u_boot_env_image_single {
++ __le32 crc32;
++ uint8_t data[];
++} __packed;
++
++struct u_boot_env_image_redundant {
++ __le32 crc32;
++ u8 mark;
++ uint8_t data[];
++} __packed;
++
++static int u_boot_env_read(void *context, unsigned int offset, void *val,
++ size_t bytes)
++{
++ struct u_boot_env *priv = context;
++ struct device *dev = priv->dev;
++ size_t bytes_read;
++ int err;
++
++ err = mtd_read(priv->mtd, offset, bytes, &bytes_read, val);
++ if (err && !mtd_is_bitflip(err)) {
++ dev_err(dev, "Failed to read from mtd: %d\n", err);
++ return err;
++ }
++
++ if (bytes_read != bytes) {
++ dev_err(dev, "Failed to read %zu bytes\n", bytes);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf,
++ size_t data_offset, size_t data_len)
++{
++ struct device *dev = priv->dev;
++ char *data = buf + data_offset;
++ char *var, *value, *eq;
++ int idx;
++
++ priv->ncells = 0;
++ for (var = data; var < data + data_len && *var; var += strlen(var) + 1)
++ priv->ncells++;
++
++ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL);
++ if (!priv->cells)
++ return -ENOMEM;
++
++ for (var = data, idx = 0;
++ var < data + data_len && *var;
++ var = value + strlen(value) + 1, idx++) {
++ eq = strchr(var, '=');
++ if (!eq)
++ break;
++ *eq = '\0';
++ value = eq + 1;
++
++ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL);
++ if (!priv->cells[idx].name)
++ return -ENOMEM;
++ priv->cells[idx].offset = data_offset + value - data;
++ priv->cells[idx].bytes = strlen(value);
++ }
++
++ if (WARN_ON(idx != priv->ncells))
++ priv->ncells = idx;
++
++ return 0;
++}
++
++static int u_boot_env_parse(struct u_boot_env *priv)
++{
++ struct device *dev = priv->dev;
++ size_t crc32_data_offset;
++ size_t crc32_data_len;
++ size_t crc32_offset;
++ size_t data_offset;
++ size_t data_len;
++ uint32_t crc32;
++ uint32_t calc;
++ size_t bytes;
++ uint8_t *buf;
++ int err;
++
++ buf = kcalloc(1, priv->mtd->size, GFP_KERNEL);
++ if (!buf) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ err = mtd_read(priv->mtd, 0, priv->mtd->size, &bytes, buf);
++ if ((err && !mtd_is_bitflip(err)) || bytes != priv->mtd->size) {
++ dev_err(dev, "Failed to read from mtd: %d\n", err);
++ goto err_kfree;
++ }
++
++ switch (priv->format) {
++ case U_BOOT_FORMAT_SINGLE:
++ crc32_offset = offsetof(struct u_boot_env_image_single, crc32);
++ crc32_data_offset = offsetof(struct u_boot_env_image_single, data);
++ data_offset = offsetof(struct u_boot_env_image_single, data);
++ break;
++ case U_BOOT_FORMAT_REDUNDANT:
++ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
++ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark);
++ data_offset = offsetof(struct u_boot_env_image_redundant, data);
++ break;
++ }
++ crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset));
++ crc32_data_len = priv->mtd->size - crc32_data_offset;
++ data_len = priv->mtd->size - data_offset;
++
++ calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
++ if (calc != crc32) {
++ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
++ err = -EINVAL;
++ goto err_kfree;
++ }
++
++ buf[priv->mtd->size - 1] = '\0';
++ err = u_boot_env_add_cells(priv, buf, data_offset, data_len);
++ if (err)
++ dev_err(dev, "Failed to add cells: %d\n", err);
++
++err_kfree:
++ kfree(buf);
++err_out:
++ return err;
++}
++
++static int u_boot_env_probe(struct platform_device *pdev)
++{
++ struct nvmem_config config = {
++ .name = "u-boot-env",
++ .reg_read = u_boot_env_read,
++ };
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct u_boot_env *priv;
++ int err;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++ priv->dev = dev;
++
++ priv->format = (uintptr_t)of_device_get_match_data(dev);
++
++ priv->mtd = of_get_mtd_device_by_node(np);
++ if (IS_ERR(priv->mtd)) {
++ dev_err_probe(dev, PTR_ERR(priv->mtd), "Failed to get %pOF MTD\n", np);
++ return PTR_ERR(priv->mtd);
++ }
++
++ err = u_boot_env_parse(priv);
++ if (err)
++ return err;
++
++ config.dev = dev;
++ config.cells = priv->cells;
++ config.ncells = priv->ncells;
++ config.priv = priv;
++ config.size = priv->mtd->size;
++
++ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
++}
++
++static const struct of_device_id u_boot_env_of_match_table[] = {
++ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
++ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
++ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
++ {},
++};
++
++static struct platform_driver u_boot_env_driver = {
++ .probe = u_boot_env_probe,
++ .driver = {
++ .name = "u_boot_env",
++ .of_match_table = u_boot_env_of_match_table,
++ },
++};
++module_platform_driver(u_boot_env_driver);
++
++MODULE_AUTHOR("Rafał Miłecki");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);
--- /dev/null
+From d69efcf951df4dcc74a0e1554969c533aec8aa9b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 15 Sep 2022 22:06:29 +0200
+Subject: [PATCH] nvmem: u-boot-env: find Device Tree nodes for NVMEM cells
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+DT binding allows specifying NVMEM cells as NVMEM device (provider)
+subnodes. Looks for such subnodes when building NVMEM cells.
+
+This allows NVMEM consumers to use U-Boot environment variables.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+---
+ drivers/nvmem/u-boot-env.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/nvmem/u-boot-env.c
++++ b/drivers/nvmem/u-boot-env.c
+@@ -92,6 +92,7 @@ static int u_boot_env_add_cells(struct u
+ return -ENOMEM;
+ priv->cells[idx].offset = data_offset + value - data;
+ priv->cells[idx].bytes = strlen(value);
++ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name);
+ }
+
+ if (WARN_ON(idx != priv->ncells))
--- /dev/null
+From 60bbaad38109684b156e21112322e0a922f92cde Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 18 Aug 2022 06:38:37 +0200
+Subject: [PATCH] nvmem: u-boot-env: fix crc32 casting type
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes:
+drivers/nvmem/u-boot-env.c:141:17: sparse: sparse: cast to restricted __le32
+
+Reported-by: kernel test robot <lkp@intel.com>
+Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables")
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+---
+ drivers/nvmem/u-boot-env.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/u-boot-env.c
++++ b/drivers/nvmem/u-boot-env.c
+@@ -139,7 +139,7 @@ static int u_boot_env_parse(struct u_boo
+ data_offset = offsetof(struct u_boot_env_image_redundant, data);
+ break;
+ }
+- crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset));
++ crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
+ crc32_data_len = priv->mtd->size - crc32_data_offset;
+ data_len = priv->mtd->size - data_offset;
+
--- /dev/null
+From dbc2f62061c6bfba0aee93161ee3194dcee84bd0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 29 Apr 2022 17:26:46 +0100
+Subject: [PATCH] nvmem: core: support passing DT node in cell info
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some hardware may have NVMEM cells described in Device Tree using
+individual nodes. Let drivers pass such nodes to the NVMEM subsystem so
+they can be later used by NVMEM consumers.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20220429162701.2222-2-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 1 +
+ include/linux/nvmem-consumer.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -462,6 +462,7 @@ static int nvmem_cell_info_to_nvmem_cell
+
+ cell->bit_offset = info->bit_offset;
+ cell->nbits = info->nbits;
++ cell->np = info->np;
+
+ if (cell->nbits)
+ cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+--- a/include/linux/nvmem-consumer.h
++++ b/include/linux/nvmem-consumer.h
+@@ -25,6 +25,7 @@ struct nvmem_cell_info {
+ unsigned int bytes;
+ unsigned int bit_offset;
+ unsigned int nbits;
++ struct device_node *np;
+ };
+
+ /**
--- /dev/null
+From 7a69ff9c9bde03a690ea783970f664782fc303d8 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Fri, 4 Nov 2022 17:52:03 +0100
+Subject: [PATCH] nvmem: u-boot-env: fix crc32_data_offset on redundant
+ u-boot-env
+
+The Western Digital MyBook Live (PowerPC 464/APM82181)
+has a set of redundant u-boot-env. Loading up the driver
+the following error:
+
+| u_boot_env: Invalid calculated CRC32: 0x4f8f2c86 (expected: 0x98b14514)
+| u_boot_env: probe of partition@1e000 failed with error -22
+
+Looking up the userspace libubootenv utilities source [0],
+it looks like the "mark" or "flag" is not part of the
+crc32 sum... which is unfortunate :(
+
+|static int libuboot_load(struct uboot_ctx *ctx)
+|{
+|[...]
+| if (ctx->redundant) {
+| [...]
+| offsetdata = offsetof(struct uboot_env_redund, data);
+| [...] //-----^^
+| }
+| usable_envsize = ctx->size - offsetdata;
+| buf[0] = malloc(bufsize);
+|[...]
+| for (i = 0; i < copies; i++) {
+| data = (uint8_t *)(buf[i] + offsetdata);
+| uint32_t crc;
+|
+| ret = devread(ctx, i, buf[i]);
+| [...]
+| crc = *(uint32_t *)(buf[i] + offsetcrc);
+| dev->crc = crc32(0, (uint8_t *)data, usable_envsize);
+|
+
+[0] https://github.com/sbabic/libubootenv/blob/master/src/uboot_env.c#L951
+Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables")
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+---
+ drivers/nvmem/u-boot-env.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/u-boot-env.c
++++ b/drivers/nvmem/u-boot-env.c
+@@ -135,7 +135,7 @@ static int u_boot_env_parse(struct u_boo
+ break;
+ case U_BOOT_FORMAT_REDUNDANT:
+ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32);
+- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark);
++ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
+ data_offset = offsetof(struct u_boot_env_image_redundant, data);
+ break;
+ }
--- /dev/null
+From 0e71cac033bb7689c4dfa2e6814191337ef770f5 Mon Sep 17 00:00:00 2001
+From: INAGAKI Hiroshi <musashino.open@gmail.com>
+Date: Thu, 13 Oct 2022 00:51:33 +0900
+Subject: [PATCH] nvmem: u-boot-env: align endianness of crc32 values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch fixes crc32 error on Big-Endianness system by conversion of
+calculated crc32 value.
+
+Little-Endianness system:
+
+ obtained crc32: Little
+calculated crc32: Little
+
+Big-Endianness system:
+
+ obtained crc32: Little
+calculated crc32: Big
+
+log (APRESIA ApresiaLightGS120GT-SS, RTL8382M, Big-Endianness):
+
+[ 8.570000] u_boot_env 18001200.spi:flash@0:partitions:partition@c0000: Invalid calculated CRC32: 0x88cd6f09 (expected: 0x096fcd88)
+[ 8.580000] u_boot_env: probe of 18001200.spi:flash@0:partitions:partition@c0000 failed with error -22
+
+Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables")
+
+Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
+Acked-by: Rafał Miłecki <rafal@milecki.pl>
+Tested-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+---
+ drivers/nvmem/u-boot-env.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvmem/u-boot-env.c
++++ b/drivers/nvmem/u-boot-env.c
+@@ -143,7 +143,7 @@ static int u_boot_env_parse(struct u_boo
+ crc32_data_len = priv->mtd->size - crc32_data_offset;
+ data_len = priv->mtd->size - data_offset;
+
+- calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
++ calc = le32_to_cpu((__le32)crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L);
+ if (calc != crc32) {
+ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32);
+ err = -EINVAL;
--- /dev/null
+From 5b4eaafbeac472fc19049152f18e88aecb2b2829 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 17 Oct 2022 09:17:22 +0200
+Subject: [PATCH] nvmem: u-boot-env: add Broadcom format support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Broadcom uses U-Boot for a lot of their bcmbca familiy chipsets. They
+decided to store U-Boot environment data inside U-Boot partition and to
+use a custom header (with "uEnv" magic and env data length).
+
+Add support for Broadcom's specific binding and their custom format.
+
+Ref: 6b0584c19d87 ("dt-bindings: nvmem: u-boot,env: add Broadcom's variant binding")
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+---
+ drivers/nvmem/u-boot-env.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/nvmem/u-boot-env.c
++++ b/drivers/nvmem/u-boot-env.c
+@@ -16,6 +16,7 @@
+ enum u_boot_env_format {
+ U_BOOT_FORMAT_SINGLE,
+ U_BOOT_FORMAT_REDUNDANT,
++ U_BOOT_FORMAT_BROADCOM,
+ };
+
+ struct u_boot_env {
+@@ -40,6 +41,13 @@ struct u_boot_env_image_redundant {
+ uint8_t data[];
+ } __packed;
+
++struct u_boot_env_image_broadcom {
++ __le32 magic;
++ __le32 len;
++ __le32 crc32;
++ uint8_t data[0];
++} __packed;
++
+ static int u_boot_env_read(void *context, unsigned int offset, void *val,
+ size_t bytes)
+ {
+@@ -138,6 +146,11 @@ static int u_boot_env_parse(struct u_boo
+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data);
+ data_offset = offsetof(struct u_boot_env_image_redundant, data);
+ break;
++ case U_BOOT_FORMAT_BROADCOM:
++ crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32);
++ crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data);
++ data_offset = offsetof(struct u_boot_env_image_broadcom, data);
++ break;
+ }
+ crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
+ crc32_data_len = priv->mtd->size - crc32_data_offset;
+@@ -202,6 +215,7 @@ static const struct of_device_id u_boot_
+ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, },
+ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
+ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, },
++ { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BROADCOM, },
+ {},
+ };
+
# CONFIG_NVMEM_BCM_OCOTP is not set
# CONFIG_NVMEM_IMX_OCOTP is not set
# CONFIG_NVMEM_REBOOT_MODE is not set
+# CONFIG_NVMEM_RMEM is not set
# CONFIG_NVMEM_SYSFS is not set
# CONFIG_NVMEM_U_BOOT_ENV is not set
# CONFIG_NVME_FC is not set