]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nvmem: layouts: Add fixed-layout driver
authorMathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Fri, 24 Jul 2026 22:34:04 +0000 (23:34 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 31 Jul 2026 09:00:13 +0000 (11:00 +0200)
Current implementation isn't working well when device tree nodes have a
phandle on a fixed-layout nvmem node. As the fixed layout is handled in
nvmem core, no driver is ever associated with the layout, and the device
consumer driver probe is deferred indefinitely.

Remove the specific handling of fixed-layout and add a layout driver.
This makes the fixed-layout similar to all other layouts, fixing the
whole issue.

Fixes: fc29fd821d9a ("nvmem: core: Rework layouts to become regular devices")
Cc: stable@vger.kernel.org
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Srinivas Kandagatla <srini@kernel.org>
Link: https://patch.msgid.link/20260724223404.629248-3-srini@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
MAINTAINERS
drivers/nvmem/core.c
drivers/nvmem/internals.h
drivers/nvmem/layouts.c
drivers/nvmem/layouts/Makefile
drivers/nvmem/layouts/fixed-layout.c [new file with mode: 0644]
include/linux/nvmem-provider.h

index 716acfc3d7c1b817e242487c8435c581e7ef3359..1b044ddc68f983ff733276bcfceb870b6ead08d9 100644 (file)
@@ -10134,6 +10134,11 @@ F:     drivers/base/firmware_loader/
 F:     rust/kernel/firmware.rs
 F:     include/linux/firmware.h
 
+FIXED-LAYOUT NVMEM LAYOUT DRIVER
+M:     Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
+S:     Maintained
+F:     drivers/nvmem/layouts/fixed-layout.c
+
 FLEXTIMER FTM-QUADDEC DRIVER
 M:     Patrick Havelange <patrick.havelange@essensium.com>
 L:     linux-iio@vger.kernel.org
index e871181751f3c2739154b3cff27ef9b90032e607..2f971b059704fe726dac1c996167000710a5c184 100644 (file)
@@ -786,7 +786,7 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
        return 0;
 }
 
-static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
+int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
 {
        struct device *dev = &nvmem->dev;
        const __be32 *addr;
@@ -834,29 +834,13 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nvmem_add_cells_from_dt);
 
 static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem)
 {
        return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node);
 }
 
-static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem)
-{
-       struct device_node *layout_np;
-       int err = 0;
-
-       layout_np = of_nvmem_layout_get_container(nvmem);
-       if (!layout_np)
-               return 0;
-
-       if (of_device_is_compatible(layout_np, "fixed-layout"))
-               err = nvmem_add_cells_from_dt(nvmem, layout_np);
-
-       of_node_put(layout_np);
-
-       return err;
-}
-
 int nvmem_layout_register(struct nvmem_layout *layout)
 {
        int ret;
@@ -1005,10 +989,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
                        goto err_remove_cells;
        }
 
-       rval = nvmem_add_cells_from_fixed_layout(nvmem);
-       if (rval)
-               goto err_remove_cells;
-
        dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
 
        rval = device_add(&nvmem->dev);
index 18fed57270e5e3391cf24d5e49836121a53a8cd6..f6d452b6a28f1593cd1cb70843037cae603c4dd8 100644 (file)
@@ -35,6 +35,8 @@ struct nvmem_device {
        bool                    sysfs_cells_populated;
 };
 
+int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np);
+
 #if IS_ENABLED(CONFIG_OF)
 int nvmem_layout_bus_register(void);
 void nvmem_layout_bus_unregister(void);
index b90584e1b99eab4217cbe7ec48373e18a7caf0dc..07a34be9669ca1e924cb2f34e6dbc560cef06ce7 100644 (file)
@@ -125,11 +125,6 @@ static int nvmem_layout_create_device(struct nvmem_device *nvmem,
        return 0;
 }
 
-static const struct of_device_id of_nvmem_layout_skip_table[] = {
-       { .compatible = "fixed-layout", },
-       {}
-};
-
 static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
                                     struct device_node *layout_dn)
 {
@@ -142,12 +137,6 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
                return 0;
        }
 
-       /* Fixed layouts are parsed manually somewhere else for now */
-       if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
-               pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
-               return 0;
-       }
-
        if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
                pr_debug("%s() - skipping %pOF, already populated\n",
                         __func__, layout_dn);
index 4940c9db0665643de8363b404090eb279a32860e..dd6c6c70b1a92ce497a3d3bc2c7dbfb2dba71f67 100644 (file)
@@ -3,6 +3,7 @@
 # Makefile for nvmem layouts.
 #
 
+obj-$(CONFIG_NVMEM_LAYOUTS) += fixed-layout.o
 obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o
 obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o
 obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o
diff --git a/drivers/nvmem/layouts/fixed-layout.c b/drivers/nvmem/layouts/fixed-layout.c
new file mode 100644 (file)
index 0000000..635d448
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2026 Bootlin
+ *
+ * Authors: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
+ */
+
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+
+#include "../internals.h"
+
+static int fixed_layout_add_cells(struct nvmem_layout *layout)
+{
+       struct device_node *np;
+       int ret;
+
+       np = of_nvmem_layout_get_container(layout->nvmem);
+       if (!np)
+               return -ENOENT;
+
+       ret = nvmem_add_cells_from_dt(layout->nvmem, np);
+       of_node_put(np);
+
+       return ret;
+}
+
+static int fixed_layout_probe(struct nvmem_layout *layout)
+{
+       layout->add_cells = fixed_layout_add_cells;
+
+       return nvmem_layout_register(layout);
+}
+
+static void fixed_layout_remove(struct nvmem_layout *layout)
+{
+       nvmem_layout_unregister(layout);
+}
+
+static const struct of_device_id fixed_layout_of_match_table[] = {
+       { .compatible = "fixed-layout", },
+       {},
+};
+
+static struct nvmem_layout_driver fixed_layout_layout = {
+       .driver = {
+               .name = "fixed-layout",
+               .of_match_table = fixed_layout_of_match_table,
+       },
+       .probe = fixed_layout_probe,
+       .remove = fixed_layout_remove,
+};
+module_nvmem_layout_driver(fixed_layout_layout);
+
+MODULE_AUTHOR("Mathieu Dubois-Briand");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, fixed_layout_of_match_table);
+MODULE_DESCRIPTION("NVMEM fixed-layout driver");
index f3b13da78aac94fb259652e5441c0e59d75fcc4a..6063fe5b7784ac9239c9450414a829ef5fc46172 100644 (file)
@@ -214,6 +214,12 @@ static inline int nvmem_layout_register(struct nvmem_layout *layout)
 
 static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {}
 
+static inline int nvmem_add_cells_from_dt(struct nvmem_device *nvmem,
+                                         struct device_node *np)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_NVMEM */
 
 #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)