2021-12-22 19:23:31

by Rafał Miłecki

[permalink] [raw]
Subject: [PATCH 1/3] mtd: core: call devm_of_platform_populate() for MTD devices

From: Rafał Miłecki <[email protected]>

This adds support for bindings present in MTD devices (applies to
partitions too) nodes. The purpose of this change is to allow drivers
handle MTD device (partition) data. Some partitions may contain info
that requires parsing & processing.

An example can be U-Boot partition that contains block with environment
variables somehwere in a middle. That block should be described in DT
and parsed by a specific driver.

Signed-off-by: Rafał Miłecki <[email protected]>
---
drivers/mtd/mtdcore.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 70f492dce158..07b75e6ca111 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -19,6 +19,7 @@
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/proc_fs.h>
#include <linux/idr.h>
#include <linux/backing-dev.h>
@@ -690,6 +691,9 @@ int add_mtd_device(struct mtd_info *mtd)
not->add(mtd);

mutex_unlock(&mtd_table_mutex);
+
+ devm_of_platform_populate(&mtd->dev);
+
/* We _know_ we aren't being removed, because
our caller is still holding us here. So none
of this try_ nonsense, and no bitching about it
--
2.31.1



2021-12-22 19:23:34

by Rafał Miłecki

[permalink] [raw]
Subject: [PATCH 2/3] dt-bindings: nvmem: add U-Boot environment variables binding

From: Rafał Miłecki <[email protected]>

This binding allows describing a (part of) MTD device (partition) that
contains a block with environment variables. Operating system usually
needs to parse that block to read variables values that may affect
booting process & device configuration.

Signed-off-by: Rafał Miłecki <[email protected]>
---
.../devicetree/bindings/nvmem/u-boot,env.yaml | 56 +++++++++++++++++++
MAINTAINERS | 5 ++
2 files changed, 61 insertions(+)
create mode 100644 Documentation/devicetree/bindings/nvmem/u-boot,env.yaml

diff --git a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
new file mode 100644
index 000000000000..0f808868fff3
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/u-boot,env.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: U-Boot environment variables
+
+description: |
+ U-Boot uses environment variables to store device parameters and
+ configuration. They may be used for booting process, setup or keeping end user
+ interesting info.
+
+ Data is stored on flash partition in a U-Boot specific format (CRC32 and NUL
+ separated key-value pairs).
+
+ This binding allows specifying data location and format (default one or vendor
+ specific).
+
+maintainers:
+ - Rafał Miłecki <[email protected]>
+
+allOf:
+ - $ref: nvmem.yaml#
+
+properties:
+ compatible:
+ enum:
+ - u,boot,env
+ - brcm,env
+
+ reg:
+ maxItems: 1
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "uboot";
+ reg = <0x0 0x100000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nvmem@10000 {
+ compatible = "u,boot,env";
+ reg = <0x10000 0x10000>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 67558097bb66..271c29c84c7d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19624,6 +19624,11 @@ W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/pci/tw686x/

+U-BOOT ENVIRONMENT VARIABLES
+M: Rafał Miłecki <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
+
UACCE ACCELERATOR FRAMEWORK
M: Zhangfei Gao <[email protected]>
M: Zhou Wang <[email protected]>
--
2.31.1


2021-12-22 19:23:36

by Rafał Miłecki

[permalink] [raw]
Subject: [PATCH 3/3] nvmem: add driver handling U-Boot environment variables

From: Rafał Miłecki <[email protected]>

U-Boot binary contains a block of environment variables (NVMEM) that
should be parsed and exposed as NVMEM cells.

Signed-off-by: Rafał Miłecki <[email protected]>
---
MAINTAINERS | 1 +
drivers/nvmem/Kconfig | 10 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/u-boot-env.c | 236 +++++++++++++++++++++++++++++++++++++
4 files changed, 249 insertions(+)
create mode 100644 drivers/nvmem/u-boot-env.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 271c29c84c7d..cc9bdeb33b64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19628,6 +19628,7 @@ U-BOOT ENVIRONMENT VARIABLES
M: Rafał Miłecki <[email protected]>
S: Maintained
F: Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
+F: drivers/nvmem/u-boot-env.c

UACCE ACCELERATOR FRAMEWORK
M: Zhangfei Gao <[email protected]>
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index da414617a54d..af9115852412 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -300,4 +300,14 @@ 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 ARCH_BCM4908 || COMPILE_TEST
+ depends on OF
+ help
+ This driver adds support for parsing U-Boot environment variables
+ stored on flash partition.
+
+ If compiled as module it will be called nvmem_u-boot-env.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index dcbbde35b6a8..772904cdebdb 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -61,3 +61,5 @@ 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
+obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o
+nvmem_u-boot-env-y := u-boot-env.o
diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c
new file mode 100644
index 000000000000..a932b3d3c63b
--- /dev/null
+++ b/drivers/nvmem/u-boot-env.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <[email protected]>
+ */
+
+#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_DEFAULT,
+ U_BOOT_FORMAT_BRCM,
+};
+
+struct u_boot_env {
+ struct device *dev;
+ enum u_boot_env_format format;
+ struct mtd_info *mtd;
+ size_t offset;
+ size_t size;
+ struct nvmem_cell_info *cells;
+ int ncells;
+};
+
+struct u_boot_env_image {
+ __le32 crc32;
+ uint8_t data[0];
+} __packed;
+
+struct u_boot_brcm_header {
+ __le32 unk;
+ __le32 len;
+} __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, priv->offset + 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 %zd bytes\n", bytes);
+ return err;
+ }
+
+ return 0;
+}
+
+static int u_boot_env_add_cells(struct u_boot_env *priv, size_t data_offset,
+ uint8_t *data, size_t len)
+{
+ struct device *dev = priv->dev;
+ char *var, *value, *eq;
+ int idx;
+
+ priv->ncells = 0;
+ for (var = data; var < (char *)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 < (char *)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 - (char *)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;
+ struct u_boot_env_image *image;
+ size_t image_offset;
+ size_t image_len;
+ uint32_t crc32;
+ size_t bytes;
+ uint8_t *buf;
+ int err;
+
+ image_offset = 0;
+ image_len = priv->size;
+ if (priv->format == U_BOOT_FORMAT_BRCM) {
+ struct u_boot_brcm_header header;
+
+ err = mtd_read(priv->mtd, priv->offset, sizeof(header), &bytes,
+ (uint8_t *)&header);
+ if (err && !mtd_is_bitflip(err)) {
+ dev_err(dev, "Failed to read from mtd: %d\n", err);
+ return err;
+ }
+
+ image_offset = sizeof(header);
+ image_len = le32_to_cpu(header.len);
+ }
+ dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len);
+
+ buf = kcalloc(1, image_len, GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ image = (struct u_boot_env_image *)buf;
+
+ err = mtd_read(priv->mtd, priv->offset + image_offset, image_len, &bytes, buf);
+ if (err && !mtd_is_bitflip(err)) {
+ dev_err(dev, "Failed to read from mtd: %d\n", err);
+ goto err_kfree;
+ }
+
+ crc32 = crc32(~0, buf + 4, image_len - 4) ^ ~0L;
+ if (crc32 != le32_to_cpu(image->crc32)) {
+ dev_err(dev, "Invalid calculated CRC32: 0x%08x\n", crc32);
+ err = -EINVAL;
+ goto err_kfree;
+ }
+
+ buf[image_len - 1] = '\0';
+ err = u_boot_env_add_cells(priv, image_offset + sizeof(*image),
+ buf + sizeof(*image),
+ image_len - sizeof(*image));
+ if (err)
+ dev_err(dev, "Failed to add cells: %d\n", err);
+
+err_kfree:
+ kfree(buf);
+err_out:
+ return err;
+}
+
+static const struct of_device_id u_boot_env_of_match_table[] = {
+ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_DEFAULT, },
+ { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BRCM, },
+ {},
+};
+
+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;
+ const struct of_device_id *of_id;
+ struct u_boot_env *priv;
+ const char *label;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->dev = dev;
+
+ of_id = of_match_device(u_boot_env_of_match_table, dev);
+ if (!of_id)
+ return -EINVAL;
+ priv->format = (uintptr_t)of_id->data;
+
+ if (of_property_read_u32(np, "reg", &priv->offset) ||
+ of_property_read_u32_index(np, "reg", 1, &priv->size)) {
+ dev_err(dev, "Failed to read \"reg\" property\n");
+ return -EINVAL;
+ }
+
+ label = of_get_property(np->parent, "label", NULL);
+ if (!label)
+ label = np->parent->name;
+
+ priv->mtd = get_mtd_device_nm(label);
+ if (IS_ERR(priv->mtd)) {
+ dev_err(dev, "Failed to find \"%s\" MTD device: %ld\n", label, PTR_ERR(priv->mtd));
+ 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->size;
+
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
+}
+
+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,
+ },
+};
+
+static int __init u_boot_env_init(void)
+{
+ return platform_driver_register(&u_boot_env_driver);
+}
+
+subsys_initcall_sync(u_boot_env_init);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);
--
2.31.1


2021-12-23 16:24:36

by Pratyush Yadav

[permalink] [raw]
Subject: Re: [PATCH 2/3] dt-bindings: nvmem: add U-Boot environment variables binding

On 22/12/21 08:23PM, Rafał Miłecki wrote:
> From: Rafał Miłecki <[email protected]>
>
> This binding allows describing a (part of) MTD device (partition) that
> contains a block with environment variables. Operating system usually
> needs to parse that block to read variables values that may affect
> booting process & device configuration.
>
> Signed-off-by: Rafał Miłecki <[email protected]>
> ---
> .../devicetree/bindings/nvmem/u-boot,env.yaml | 56 +++++++++++++++++++
> MAINTAINERS | 5 ++
> 2 files changed, 61 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
>
> diff --git a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
> new file mode 100644
> index 000000000000..0f808868fff3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml
> +
> +properties:
> + compatible:
> + enum:
> + - u,boot,env

Typo? In patch 3 you match u-boot,env.

--
Regards,
Pratyush Yadav
Texas Instruments Inc.

2021-12-27 05:14:17

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 3/3] nvmem: add driver handling U-Boot environment variables

Hi "Rafał,

I love your patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on mtd/mtd/next mtd/mtd/fixes linus/master v5.16-rc7 next-20211224]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Rafa-Mi-ecki/mtd-core-call-devm_of_platform_populate-for-MTD-devices/20211223-032456
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: riscv-randconfig-c006-20211227 (https://download.01.org/0day-ci/archive/20211227/[email protected]/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 511726c64d3b6cca66f7c54d457d586aa3129f67)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/43acf8c3e5ac48785826453744a925ff149b1d60
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Rafa-Mi-ecki/mtd-core-call-devm_of_platform_populate-for-MTD-devices/20211223-032456
git checkout 43acf8c3e5ac48785826453744a925ff149b1d60
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash drivers/nvmem/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All error/warnings (new ones prefixed by >>):

>> drivers/nvmem/u-boot-env.c:126:46: warning: format specifies type 'unsigned int' but the argument has type 'size_t' (aka 'unsigned long') [-Wformat]
dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len);
~~~~ ^~~~~~~~~~~~
%08lx
include/linux/dev_printk.h:150:67: note: expanded from macro 'dev_info'
dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
_p_func(dev, fmt, ##__VA_ARGS__); \
~~~ ^~~~~~~~~~~
drivers/nvmem/u-boot-env.c:126:60: warning: format specifies type 'unsigned int' but the argument has type 'size_t' (aka 'unsigned long') [-Wformat]
dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len);
~~~~ ^~~~~~~~~
%08lx
include/linux/dev_printk.h:150:67: note: expanded from macro 'dev_info'
dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
~~~ ^~~~~~~~~~~
include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
_p_func(dev, fmt, ##__VA_ARGS__); \
~~~ ^~~~~~~~~~~
>> drivers/nvmem/u-boot-env.c:190:38: error: incompatible pointer types passing 'size_t *' (aka 'unsigned long *') to parameter of type 'u32 *' (aka 'unsigned int *') [-Werror,-Wincompatible-pointer-types]
if (of_property_read_u32(np, "reg", &priv->offset) ||
^~~~~~~~~~~~~
include/linux/of.h:1255:17: note: passing argument to parameter 'out_value' here
u32 *out_value)
^
drivers/nvmem/u-boot-env.c:191:47: error: incompatible pointer types passing 'size_t *' (aka 'unsigned long *') to parameter of type 'u32 *' (aka 'unsigned int *') [-Werror,-Wincompatible-pointer-types]
of_property_read_u32_index(np, "reg", 1, &priv->size)) {
^~~~~~~~~~~
include/linux/of.h:311:28: note: passing argument to parameter 'out_value' here
u32 index, u32 *out_value);
^
2 warnings and 2 errors generated.


vim +190 drivers/nvmem/u-boot-env.c

99
100 static int u_boot_env_parse(struct u_boot_env *priv)
101 {
102 struct device *dev = priv->dev;
103 struct u_boot_env_image *image;
104 size_t image_offset;
105 size_t image_len;
106 uint32_t crc32;
107 size_t bytes;
108 uint8_t *buf;
109 int err;
110
111 image_offset = 0;
112 image_len = priv->size;
113 if (priv->format == U_BOOT_FORMAT_BRCM) {
114 struct u_boot_brcm_header header;
115
116 err = mtd_read(priv->mtd, priv->offset, sizeof(header), &bytes,
117 (uint8_t *)&header);
118 if (err && !mtd_is_bitflip(err)) {
119 dev_err(dev, "Failed to read from mtd: %d\n", err);
120 return err;
121 }
122
123 image_offset = sizeof(header);
124 image_len = le32_to_cpu(header.len);
125 }
> 126 dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len);
127
128 buf = kcalloc(1, image_len, GFP_KERNEL);
129 if (!buf) {
130 err = -ENOMEM;
131 goto err_out;
132 }
133 image = (struct u_boot_env_image *)buf;
134
135 err = mtd_read(priv->mtd, priv->offset + image_offset, image_len, &bytes, buf);
136 if (err && !mtd_is_bitflip(err)) {
137 dev_err(dev, "Failed to read from mtd: %d\n", err);
138 goto err_kfree;
139 }
140
141 crc32 = crc32(~0, buf + 4, image_len - 4) ^ ~0L;
142 if (crc32 != le32_to_cpu(image->crc32)) {
143 dev_err(dev, "Invalid calculated CRC32: 0x%08x\n", crc32);
144 err = -EINVAL;
145 goto err_kfree;
146 }
147
148 buf[image_len - 1] = '\0';
149 err = u_boot_env_add_cells(priv, image_offset + sizeof(*image),
150 buf + sizeof(*image),
151 image_len - sizeof(*image));
152 if (err)
153 dev_err(dev, "Failed to add cells: %d\n", err);
154
155 err_kfree:
156 kfree(buf);
157 err_out:
158 return err;
159 }
160
161 static const struct of_device_id u_boot_env_of_match_table[] = {
162 { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_DEFAULT, },
163 { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BRCM, },
164 {},
165 };
166
167 static int u_boot_env_probe(struct platform_device *pdev)
168 {
169 struct nvmem_config config = {
170 .name = "u-boot-env",
171 .reg_read = u_boot_env_read,
172 };
173 struct device *dev = &pdev->dev;
174 struct device_node *np = dev->of_node;
175 const struct of_device_id *of_id;
176 struct u_boot_env *priv;
177 const char *label;
178 int err;
179
180 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
181 if (!priv)
182 return -ENOMEM;
183 priv->dev = dev;
184
185 of_id = of_match_device(u_boot_env_of_match_table, dev);
186 if (!of_id)
187 return -EINVAL;
188 priv->format = (uintptr_t)of_id->data;
189
> 190 if (of_property_read_u32(np, "reg", &priv->offset) ||
191 of_property_read_u32_index(np, "reg", 1, &priv->size)) {
192 dev_err(dev, "Failed to read \"reg\" property\n");
193 return -EINVAL;
194 }
195
196 label = of_get_property(np->parent, "label", NULL);
197 if (!label)
198 label = np->parent->name;
199
200 priv->mtd = get_mtd_device_nm(label);
201 if (IS_ERR(priv->mtd)) {
202 dev_err(dev, "Failed to find \"%s\" MTD device: %ld\n", label, PTR_ERR(priv->mtd));
203 return PTR_ERR(priv->mtd);
204 }
205
206 err = u_boot_env_parse(priv);
207 if (err)
208 return err;
209
210 config.dev = dev;
211 config.cells = priv->cells;
212 config.ncells = priv->ncells;
213 config.priv = priv;
214 config.size = priv->size;
215
216 return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
217 }
218

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]