[openwrt/openwrt] kernel: import pending patches adding support for NVMEM on UBI and MMC

LEDE Commits lede-commits at lists.infradead.org
Thu Feb 15 11:34:50 PST 2024


dangole pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/fc153aa8d94ffe09d5ff50e2a73a6dfc209d8545

commit fc153aa8d94ffe09d5ff50e2a73a6dfc209d8545
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Mon Dec 4 23:48:40 2023 +0000

    kernel: import pending patches adding support for NVMEM on UBI and MMC
    
    Similar to supporting nvmem-layouts on MTD devices, also allow referencing
    UBI and MMC devices in DT.
    
    Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
 ...950-0111-MMC-added-alternative-MMC-driver.patch |   6 +-
 target/linux/generic/config-6.1                    |   2 +
 ...t-bindings-mtd-add-basic-bindings-for-UBI.patch | 121 ++++++++++
 ...-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch |  48 ++++
 ...ck-use-notifier-to-create-ubiblock-from-p.patch | 225 ++++++++++++++++++
 .../450-04-mtd-ubi-attach-from-device-tree.patch   | 264 +++++++++++++++++++++
 ...roduce-pre-removal-notification-for-UBI-v.patch | 226 ++++++++++++++++++
 ...450-06-mtd-ubi-populate-ubi-volume-fwnode.patch |  65 +++++
 ...-ubi-provide-NVMEM-layer-over-UBI-volumes.patch | 243 +++++++++++++++++++
 ...-block-add-basic-bindings-for-block-devic.patch | 120 ++++++++++
 .../450-09-block-partitions-populate-fwnode.patch  |  77 ++++++
 ...0-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch |  29 +++
 .../450-11-block-implement-NVMEM-provider.patch    | 235 ++++++++++++++++++
 ...dings-mmc-mmc-card-add-block-device-nodes.patch |  74 ++++++
 .../450-13-mmc-core-set-card-fwnode_handle.patch   |  23 ++
 ...0-14-mmc-block-set-fwnode-of-disk-devices.patch |  38 +++
 .../450-15-mmc-block-set-GENHD_FL_NVMEM.patch      |  22 ++
 ...tach-mtd-device-named-ubi-or-data-on-boot.patch |  17 +-
 ...bi-auto-create-ubiblock-device-for-rootfs.patch |  76 +++---
 ...-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch |   4 +-
 .../494-mtd-ubi-add-EOF-marker-support.patch       |   2 +-
 .../041-block-fit-partition-parser.patch           |  15 +-
 22 files changed, 1876 insertions(+), 56 deletions(-)

diff --git a/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch b/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch
index 476a3caf3c..693ed2b6d1 100644
--- a/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch
+++ b/target/linux/bcm27xx/patches-6.1/950-0111-MMC-added-alternative-MMC-driver.patch
@@ -266,7 +266,7 @@ Signed-off-by: Phil Elwell <phil at raspberrypi.com>
  static inline int mmc_blk_part_switch(struct mmc_card *card,
  				      unsigned int part_type);
  static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
-@@ -3040,6 +3047,8 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3049,6 +3056,8 @@ static int mmc_blk_probe(struct mmc_card
  {
  	struct mmc_blk_data *md;
  	int ret = 0;
@@ -275,7 +275,7 @@ Signed-off-by: Phil Elwell <phil at raspberrypi.com>
  
  	/*
  	 * Check that the card supports the command class(es) we need.
-@@ -3047,7 +3056,16 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3056,7 +3065,16 @@ static int mmc_blk_probe(struct mmc_card
  	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
  		return -ENODEV;
  
@@ -293,7 +293,7 @@ Signed-off-by: Phil Elwell <phil at raspberrypi.com>
  
  	card->complete_wq = alloc_workqueue("mmc_complete",
  					WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
-@@ -3062,6 +3080,17 @@ static int mmc_blk_probe(struct mmc_card
+@@ -3071,6 +3089,17 @@ static int mmc_blk_probe(struct mmc_card
  		goto out_free;
  	}
  
diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1
index 30bda17d17..ce1bfcd5bf 100644
--- a/target/linux/generic/config-6.1
+++ b/target/linux/generic/config-6.1
@@ -730,6 +730,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_ZONED is not set
 # CONFIG_BLK_INLINE_ENCRYPTION is not set
+# CONFIG_BLK_NVMEM is not set
 # CONFIG_BLK_SED_OPAL is not set
 # CONFIG_BLK_WBT is not set
 CONFIG_BLOCK=y
@@ -4037,6 +4038,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y
 # CONFIG_MTD_UBI is not set
 # CONFIG_MTD_UBI_FASTMAP is not set
 # CONFIG_MTD_UBI_GLUEBI is not set
+# CONFIG_MTD_UBI_NVMEM is not set
 # CONFIG_MTD_UIMAGE_SPLIT is not set
 # CONFIG_MTD_VIRT_CONCAT is not set
 # CONFIG_MTK_DEVAPC is not set
diff --git a/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch b/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch
new file mode 100644
index 0000000000..063d3fa79c
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-01-dt-bindings-mtd-add-basic-bindings-for-UBI.patch
@@ -0,0 +1,121 @@
+From ffbbe7d66872ff8957dad2136133e28a1fd5d437 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 7 Aug 2023 22:51:05 +0100
+Subject: [PATCH 01/15] dt-bindings: mtd: add basic bindings for UBI
+
+Add basic bindings for UBI devices and volumes.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ .../bindings/mtd/partitions/linux,ubi.yaml    | 65 +++++++++++++++++++
+ .../bindings/mtd/partitions/ubi-volume.yaml   | 35 ++++++++++
+ 2 files changed, 100 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+@@ -0,0 +1,65 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Unsorted Block Images
++
++description: |
++  UBI ("Unsorted Block Images") is a volume management system for raw
++  flash devices which manages multiple logical volumes on a single
++  physical flash device and spreads the I/O load (i.e wear-leveling)
++  across the whole flash chip.
++
++maintainers:
++  - Daniel Golle <daniel at makrotopia.org>
++
++allOf:
++  - $ref: partition.yaml#
++
++properties:
++  compatible:
++    const: linux,ubi
++
++  volumes:
++    type: object
++    description: UBI Volumes
++
++    patternProperties:
++      "^ubi-volume-.*$":
++        $ref: /schemas/mtd/partitions/ubi-volume.yaml#
++
++    unevaluatedProperties: false
++
++required:
++  - compatible
++
++unevaluatedProperties: false
++
++examples:
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition at 0 {
++            reg = <0x0 0x100000>;
++            label = "bootloader";
++            read-only;
++        };
++
++        partition at 100000 {
++            reg = <0x100000 0x1ff00000>;
++            label = "ubi";
++            compatible = "linux,ubi";
++
++            volumes {
++                ubi-volume-caldata {
++                    volid = <2>;
++                    volname = "rf";
++                };
++            };
++        };
++    };
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+@@ -0,0 +1,35 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: UBI volume
++
++description: |
++  This binding describes a single UBI volume. Volumes can be matches either
++  by their ID or their name, or both.
++
++maintainers:
++  - Daniel Golle <daniel at makrotopia.org>
++
++properties:
++  volid:
++    $ref: "/schemas/types.yaml#/definitions/uint32"
++    description:
++      Match UBI volume ID
++
++  volname:
++    $ref: "/schemas/types.yaml#/definitions/string"
++    description:
++      Match UBI volume ID
++
++anyOf:
++  - required:
++    - volid
++
++  - required:
++    - volname
++
++# This is a generic file other binding inherit from and extend
++additionalProperties: true
diff --git a/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch b/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch
new file mode 100644
index 0000000000..823c8e83b7
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-02-dt-bindings-mtd-ubi-volume-allow-UBI-volumes-to-prov.patch
@@ -0,0 +1,48 @@
+From e4dad3aa5c3ab9c553555dd23c0b85f725f2eb51 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 7 Aug 2023 22:53:01 +0100
+Subject: [PATCH 02/15] dt-bindings: mtd: ubi-volume: allow UBI volumes to
+ provide NVMEM
+
+UBI volumes may be used to contain NVMEM bits, typically device MAC
+addresses or wireless radio calibration data.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ .../devicetree/bindings/mtd/partitions/linux,ubi.yaml  | 10 ++++++++++
+ .../devicetree/bindings/mtd/partitions/ubi-volume.yaml |  5 +++++
+ 2 files changed, 15 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
++++ b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
+@@ -59,6 +59,16 @@ examples:
+                 ubi-volume-caldata {
+                     volid = <2>;
+                     volname = "rf";
++
++                    nvmem-layout {
++                        compatible = "fixed-layout";
++                        #address-cells = <1>;
++                        #size-cells = <1>;
++
++                        eeprom at 0 {
++                            reg = <0x0 0x1000>;
++                        };
++                    };
+                 };
+             };
+         };
+--- a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
++++ b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
+@@ -24,6 +24,11 @@ properties:
+     description:
+       Match UBI volume ID
+ 
++  nvmem-layout:
++    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++    description:
++      This container may reference an NVMEM layout parser.
++
+ anyOf:
+   - required:
+     - volid
diff --git a/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch b/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch
new file mode 100644
index 0000000000..eda3b108da
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-03-mtd-ubi-block-use-notifier-to-create-ubiblock-from-p.patch
@@ -0,0 +1,225 @@
+From e5cf19bd8204925f3bd2067df9e867313eac388b Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 1 May 2023 11:57:51 +0100
+Subject: [PATCH 03/15] mtd: ubi: block: use notifier to create ubiblock from
+ parameter
+
+Use UBI_VOLUME_ADDED notification to create ubiblock device specified
+on kernel cmdline or module parameter.
+This makes thing more simple and has the advantage that ubiblock devices
+on volumes which are not present at the time the ubi module is probed
+will still be created.
+
+Suggested-by: Zhihao Cheng <chengzhihao1 at huawei.com>
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 154 ++++++++++++++++++++++------------------
+ 1 file changed, 85 insertions(+), 69 deletions(-)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -33,6 +33,7 @@
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/mutex.h>
++#include <linux/namei.h>
+ #include <linux/slab.h>
+ #include <linux/mtd/ubi.h>
+ #include <linux/workqueue.h>
+@@ -67,10 +68,10 @@ struct ubiblock_pdu {
+ };
+ 
+ /* Numbers of elements set in the @ubiblock_param array */
+-static int ubiblock_devs __initdata;
++static int ubiblock_devs;
+ 
+ /* MTD devices specification parameters */
+-static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
++static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
+ 
+ struct ubiblock {
+ 	struct ubi_volume_desc *desc;
+@@ -504,7 +505,7 @@ int ubiblock_remove(struct ubi_volume_in
+ 	}
+ 
+ 	/* Found a device, let's lock it so we can check if it's busy */
+-	mutex_lock(&dev->dev_mutex);
++	mutex_lock_nested(&dev->dev_mutex, SINGLE_DEPTH_NESTING);
+ 	if (dev->refcnt > 0) {
+ 		ret = -EBUSY;
+ 		goto out_unlock_dev;
+@@ -567,6 +568,85 @@ static int ubiblock_resize(struct ubi_vo
+ 	return 0;
+ }
+ 
++static bool
++match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
++{
++	int err, len;
++	struct path path;
++	struct kstat stat;
++
++	if (ubi_num == -1) {
++		/* No ubi num, name must be a vol device path */
++		err = kern_path(name, LOOKUP_FOLLOW, &path);
++		if (err)
++			return false;
++
++		err = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
++		path_put(&path);
++		if (err)
++			return false;
++
++		if (!S_ISCHR(stat.mode))
++			return false;
++
++		if (vi->ubi_num != ubi_major2num(MAJOR(stat.rdev)))
++			return false;
++
++		if (vi->vol_id != MINOR(stat.rdev) - 1)
++			return false;
++
++		return true;
++	}
++
++	if (vol_id == -1) {
++		if (vi->ubi_num != ubi_num)
++			return false;
++
++		len = strnlen(name, UBI_VOL_NAME_MAX + 1);
++		if (len < 1 || vi->name_len != len)
++			return false;
++
++		if (strcmp(name, vi->name))
++			return false;
++
++		return true;
++	}
++
++	if (vi->ubi_num != ubi_num)
++		return false;
++
++	if (vi->vol_id != vol_id)
++		return false;
++
++	return true;
++}
++
++static void
++ubiblock_create_from_param(struct ubi_volume_info *vi)
++{
++	int i, ret = 0;
++	struct ubiblock_param *p;
++
++	/*
++	 * Iterate over ubiblock cmdline parameters. If a parameter matches the
++	 * newly added volume create the ubiblock device for it.
++	 */
++	for (i = 0; i < ubiblock_devs; i++) {
++		p = &ubiblock_param[i];
++
++		if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
++			continue;
++
++		ret = ubiblock_create(vi);
++		if (ret) {
++			pr_err(
++			       "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
++			       vi->name, p->ubi_num, p->vol_id, ret);
++		}
++		break;
++	}
++}
++
+ static int ubiblock_notify(struct notifier_block *nb,
+ 			 unsigned long notification_type, void *ns_ptr)
+ {
+@@ -574,10 +654,7 @@ static int ubiblock_notify(struct notifi
+ 
+ 	switch (notification_type) {
+ 	case UBI_VOLUME_ADDED:
+-		/*
+-		 * We want to enforce explicit block device creation for
+-		 * volumes, so when a volume is added we do nothing.
+-		 */
++		ubiblock_create_from_param(&nt->vi);
+ 		break;
+ 	case UBI_VOLUME_REMOVED:
+ 		ubiblock_remove(&nt->vi);
+@@ -603,56 +680,6 @@ static struct notifier_block ubiblock_no
+ 	.notifier_call = ubiblock_notify,
+ };
+ 
+-static struct ubi_volume_desc * __init
+-open_volume_desc(const char *name, int ubi_num, int vol_id)
+-{
+-	if (ubi_num == -1)
+-		/* No ubi num, name must be a vol device path */
+-		return ubi_open_volume_path(name, UBI_READONLY);
+-	else if (vol_id == -1)
+-		/* No vol_id, must be vol_name */
+-		return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
+-	else
+-		return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
+-}
+-
+-static void __init ubiblock_create_from_param(void)
+-{
+-	int i, ret = 0;
+-	struct ubiblock_param *p;
+-	struct ubi_volume_desc *desc;
+-	struct ubi_volume_info vi;
+-
+-	/*
+-	 * If there is an error creating one of the ubiblocks, continue on to
+-	 * create the following ubiblocks. This helps in a circumstance where
+-	 * the kernel command-line specifies multiple block devices and some
+-	 * may be broken, but we still want the working ones to come up.
+-	 */
+-	for (i = 0; i < ubiblock_devs; i++) {
+-		p = &ubiblock_param[i];
+-
+-		desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
+-		if (IS_ERR(desc)) {
+-			pr_err(
+-			       "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
+-			       p->ubi_num, p->vol_id, PTR_ERR(desc));
+-			continue;
+-		}
+-
+-		ubi_get_volume_info(desc, &vi);
+-		ubi_close_volume(desc);
+-
+-		ret = ubiblock_create(&vi);
+-		if (ret) {
+-			pr_err(
+-			       "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
+-			       vi.name, p->ubi_num, p->vol_id, ret);
+-			continue;
+-		}
+-	}
+-}
+-
+ static void ubiblock_remove_all(void)
+ {
+ 	struct ubiblock *next;
+@@ -678,18 +705,7 @@ int __init ubiblock_init(void)
+ 	if (ubiblock_major < 0)
+ 		return ubiblock_major;
+ 
+-	/*
+-	 * Attach block devices from 'block=' module param.
+-	 * Even if one block device in the param list fails to come up,
+-	 * still allow the module to load and leave any others up.
+-	 */
+-	ubiblock_create_from_param();
+-
+-	/*
+-	 * Block devices are only created upon user requests, so we ignore
+-	 * existing volumes.
+-	 */
+-	ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
++	ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
+ 	if (ret)
+ 		goto err_unreg;
+ 	return 0;
diff --git a/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch b/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch
new file mode 100644
index 0000000000..6e10e5ebed
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-04-mtd-ubi-attach-from-device-tree.patch
@@ -0,0 +1,264 @@
+From 471a17d8d1b838092d1a76e48cdce8b5b67ff809 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 27 Nov 2023 01:54:28 +0000
+Subject: [PATCH 04/15] mtd: ubi: attach from device tree
+
+Introduce device tree compatible 'linux,ubi' and attach compatible MTD
+devices using the MTD add notifier. This is needed for a UBI device to
+be available early at boot (and not only after late_initcall), so
+volumes on them can be used eg. as NVMEM providers for other drivers.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 146 ++++++++++++++++++++++++++++------------
+ drivers/mtd/ubi/cdev.c  |   2 +-
+ drivers/mtd/ubi/ubi.h   |   2 +-
+ 3 files changed, 106 insertions(+), 44 deletions(-)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -27,6 +27,7 @@
+ #include <linux/log2.h>
+ #include <linux/kthread.h>
+ #include <linux/kernel.h>
++#include <linux/of.h>
+ #include <linux/slab.h>
+ #include <linux/major.h>
+ #include "ubi.h"
+@@ -1071,6 +1072,7 @@ out_free:
+  * ubi_detach_mtd_dev - detach an MTD device.
+  * @ubi_num: UBI device number to detach from
+  * @anyway: detach MTD even if device reference count is not zero
++ * @have_lock: called by MTD notifier holding mtd_table_mutex
+  *
+  * This function destroys an UBI device number @ubi_num and detaches the
+  * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+@@ -1080,7 +1082,7 @@ out_free:
+  * Note, the invocations of this function has to be serialized by the
+  * @ubi_devices_mutex.
+  */
+-int ubi_detach_mtd_dev(int ubi_num, int anyway)
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock)
+ {
+ 	struct ubi_device *ubi;
+ 
+@@ -1136,7 +1138,11 @@ int ubi_detach_mtd_dev(int ubi_num, int
+ 	vfree(ubi->peb_buf);
+ 	vfree(ubi->fm_buf);
+ 	ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
+-	put_mtd_device(ubi->mtd);
++	if (have_lock)
++		__put_mtd_device(ubi->mtd);
++	else
++		put_mtd_device(ubi->mtd);
++
+ 	put_device(&ubi->dev);
+ 	return 0;
+ }
+@@ -1213,43 +1219,43 @@ static struct mtd_info * __init open_mtd
+ 	return mtd;
+ }
+ 
+-static int __init ubi_init(void)
++static void ubi_notify_add(struct mtd_info *mtd)
+ {
+-	int err, i, k;
++	struct device_node *np = mtd_get_of_node(mtd);
++	int err;
+ 
+-	/* Ensure that EC and VID headers have correct size */
+-	BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+-	BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
++	if (!of_device_is_compatible(np, "linux,ubi"))
++		return;
+ 
+-	if (mtd_devs > UBI_MAX_DEVICES) {
+-		pr_err("UBI error: too many MTD devices, maximum is %d\n",
+-		       UBI_MAX_DEVICES);
+-		return -EINVAL;
+-	}
++	/*
++	 * we are already holding &mtd_table_mutex, but still need
++	 * to bump refcount
++	 */
++	err = __get_mtd_device(mtd);
++	if (err)
++		return;
+ 
+-	/* Create base sysfs directory and sysfs files */
+-	err = class_register(&ubi_class);
++	/* called while holding mtd_table_mutex */
++	mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
++	err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false);
++	mutex_unlock(&ubi_devices_mutex);
+ 	if (err < 0)
+-		return err;
+-
+-	err = misc_register(&ubi_ctrl_cdev);
+-	if (err) {
+-		pr_err("UBI error: cannot register device\n");
+-		goto out;
+-	}
++		__put_mtd_device(mtd);
++}
+ 
+-	ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+-					      sizeof(struct ubi_wl_entry),
+-					      0, 0, NULL);
+-	if (!ubi_wl_entry_slab) {
+-		err = -ENOMEM;
+-		goto out_dev_unreg;
+-	}
++static void ubi_notify_remove(struct mtd_info *mtd)
++{
++	WARN(1, "mtd%d removed despite UBI still being attached", mtd->index);
++}
+ 
+-	err = ubi_debugfs_init();
+-	if (err)
+-		goto out_slab;
++static struct mtd_notifier ubi_mtd_notifier = {
++	.add = ubi_notify_add,
++	.remove = ubi_notify_remove,
++};
+ 
++static int __init ubi_init_attach(void)
++{
++	int err, i, k;
+ 
+ 	/* Attach MTD devices */
+ 	for (i = 0; i < mtd_devs; i++) {
+@@ -1297,25 +1303,79 @@ static int __init ubi_init(void)
+ 		}
+ 	}
+ 
++	return 0;
++
++out_detach:
++	for (k = 0; k < i; k++)
++		if (ubi_devices[k]) {
++			mutex_lock(&ubi_devices_mutex);
++			ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1, false);
++			mutex_unlock(&ubi_devices_mutex);
++		}
++	return err;
++}
++#ifndef CONFIG_MTD_UBI_MODULE
++late_initcall(ubi_init_attach);
++#endif
++
++static int __init ubi_init(void)
++{
++	int err;
++
++	/* Ensure that EC and VID headers have correct size */
++	BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
++	BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
++
++	if (mtd_devs > UBI_MAX_DEVICES) {
++		pr_err("UBI error: too many MTD devices, maximum is %d\n",
++		       UBI_MAX_DEVICES);
++		return -EINVAL;
++	}
++
++	/* Create base sysfs directory and sysfs files */
++	err = class_register(&ubi_class);
++	if (err < 0)
++		return err;
++
++	err = misc_register(&ubi_ctrl_cdev);
++	if (err) {
++		pr_err("UBI error: cannot register device\n");
++		goto out;
++	}
++
++	ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
++					      sizeof(struct ubi_wl_entry),
++					      0, 0, NULL);
++	if (!ubi_wl_entry_slab) {
++		err = -ENOMEM;
++		goto out_dev_unreg;
++	}
++
++	err = ubi_debugfs_init();
++	if (err)
++		goto out_slab;
++
+ 	err = ubiblock_init();
+ 	if (err) {
+ 		pr_err("UBI error: block: cannot initialize, error %d\n", err);
+ 
+ 		/* See comment above re-ubi_is_module(). */
+ 		if (ubi_is_module())
+-			goto out_detach;
++			goto out_slab;
++	}
++
++	register_mtd_user(&ubi_mtd_notifier);
++
++	if (ubi_is_module()) {
++		err = ubi_init_attach();
++		if (err)
++			goto out_mtd_notifier;
+ 	}
+ 
+ 	return 0;
+ 
+-out_detach:
+-	for (k = 0; k < i; k++)
+-		if (ubi_devices[k]) {
+-			mutex_lock(&ubi_devices_mutex);
+-			ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+-			mutex_unlock(&ubi_devices_mutex);
+-		}
+-	ubi_debugfs_exit();
++out_mtd_notifier:
++	unregister_mtd_user(&ubi_mtd_notifier);
+ out_slab:
+ 	kmem_cache_destroy(ubi_wl_entry_slab);
+ out_dev_unreg:
+@@ -1325,18 +1385,20 @@ out:
+ 	pr_err("UBI error: cannot initialize UBI, error %d\n", err);
+ 	return err;
+ }
+-late_initcall(ubi_init);
++device_initcall(ubi_init);
++
+ 
+ static void __exit ubi_exit(void)
+ {
+ 	int i;
+ 
+ 	ubiblock_exit();
++	unregister_mtd_user(&ubi_mtd_notifier);
+ 
+ 	for (i = 0; i < UBI_MAX_DEVICES; i++)
+ 		if (ubi_devices[i]) {
+ 			mutex_lock(&ubi_devices_mutex);
+-			ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
++			ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1, false);
+ 			mutex_unlock(&ubi_devices_mutex);
+ 		}
+ 	ubi_debugfs_exit();
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -1065,7 +1065,7 @@ static long ctrl_cdev_ioctl(struct file
+ 		}
+ 
+ 		mutex_lock(&ubi_devices_mutex);
+-		err = ubi_detach_mtd_dev(ubi_num, 0);
++		err = ubi_detach_mtd_dev(ubi_num, 0, false);
+ 		mutex_unlock(&ubi_devices_mutex);
+ 		break;
+ 	}
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -939,7 +939,7 @@ int ubi_io_write_vid_hdr(struct ubi_devi
+ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
+ 		       int vid_hdr_offset, int max_beb_per1024,
+ 		       bool disable_fm);
+-int ubi_detach_mtd_dev(int ubi_num, int anyway);
++int ubi_detach_mtd_dev(int ubi_num, int anyway, bool have_lock);
+ struct ubi_device *ubi_get_device(int ubi_num);
+ void ubi_put_device(struct ubi_device *ubi);
+ struct ubi_device *ubi_get_by_major(int major);
diff --git a/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch b/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch
new file mode 100644
index 0000000000..d5da37b856
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-05-mtd-ubi-introduce-pre-removal-notification-for-UBI-v.patch
@@ -0,0 +1,226 @@
+From 2d664266cfdd114cc7a1fa28dd64275e99222455 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 8 Jun 2023 17:18:09 +0100
+Subject: [PATCH 05/15] mtd: ubi: introduce pre-removal notification for UBI
+ volumes
+
+Introduce a new notification type UBI_VOLUME_SHUTDOWN to inform users
+that a volume is just about to be removed.
+This is needed because users (such as the NVMEM subsystem) expect that
+at the time their removal function is called, the parenting device is
+still available (for removal of sysfs nodes, for example, in case of
+NVMEM which otherwise WARNs on volume removal).
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 26 ++++++++++++++++++++++++++
+ drivers/mtd/ubi/build.c | 20 +++++++++++++++-----
+ drivers/mtd/ubi/kapi.c  |  2 +-
+ drivers/mtd/ubi/ubi.h   |  2 ++
+ drivers/mtd/ubi/vmt.c   | 17 +++++++++++++++--
+ include/linux/mtd/ubi.h |  2 ++
+ 6 files changed, 61 insertions(+), 8 deletions(-)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -568,6 +568,29 @@ static int ubiblock_resize(struct ubi_vo
+ 	return 0;
+ }
+ 
++static int ubiblock_shutdown(struct ubi_volume_info *vi)
++{
++	struct ubiblock *dev;
++	struct gendisk *disk;
++	int ret = 0;
++
++	mutex_lock(&devices_mutex);
++	dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
++	if (!dev) {
++		ret = -ENODEV;
++		goto out_unlock;
++	}
++	disk = dev->gd;
++
++out_unlock:
++	mutex_unlock(&devices_mutex);
++
++	if (!ret)
++		blk_mark_disk_dead(disk);
++
++	return ret;
++};
++
+ static bool
+ match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
+ {
+@@ -659,6 +682,9 @@ static int ubiblock_notify(struct notifi
+ 	case UBI_VOLUME_REMOVED:
+ 		ubiblock_remove(&nt->vi);
+ 		break;
++	case UBI_VOLUME_SHUTDOWN:
++		ubiblock_shutdown(&nt->vi);
++		break;
+ 	case UBI_VOLUME_RESIZED:
+ 		ubiblock_resize(&nt->vi);
+ 		break;
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -89,7 +89,7 @@ static struct ubi_device *ubi_devices[UB
+ /* Serializes UBI devices creations and removals */
+ DEFINE_MUTEX(ubi_devices_mutex);
+ 
+-/* Protects @ubi_devices and @ubi->ref_count */
++/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
+ static DEFINE_SPINLOCK(ubi_devices_lock);
+ 
+ /* "Show" method for files in '/<sysfs>/class/ubi/' */
+@@ -258,6 +258,9 @@ struct ubi_device *ubi_get_device(int ub
+ 
+ 	spin_lock(&ubi_devices_lock);
+ 	ubi = ubi_devices[ubi_num];
++	if (ubi && ubi->is_dead)
++		ubi = NULL;
++
+ 	if (ubi) {
+ 		ubi_assert(ubi->ref_count >= 0);
+ 		ubi->ref_count += 1;
+@@ -295,7 +298,7 @@ struct ubi_device *ubi_get_by_major(int
+ 	spin_lock(&ubi_devices_lock);
+ 	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+ 		ubi = ubi_devices[i];
+-		if (ubi && MAJOR(ubi->cdev.dev) == major) {
++		if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
+ 			ubi_assert(ubi->ref_count >= 0);
+ 			ubi->ref_count += 1;
+ 			get_device(&ubi->dev);
+@@ -324,7 +327,7 @@ int ubi_major2num(int major)
+ 	for (i = 0; i < UBI_MAX_DEVICES; i++) {
+ 		struct ubi_device *ubi = ubi_devices[i];
+ 
+-		if (ubi && MAJOR(ubi->cdev.dev) == major) {
++		if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
+ 			ubi_num = ubi->ubi_num;
+ 			break;
+ 		}
+@@ -511,7 +514,7 @@ static void ubi_free_volumes_from(struct
+ 	int i;
+ 
+ 	for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+-		if (!ubi->volumes[i])
++		if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
+ 			continue;
+ 		ubi_eba_replace_table(ubi->volumes[i], NULL);
+ 		ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
+@@ -1094,10 +1097,10 @@ int ubi_detach_mtd_dev(int ubi_num, int
+ 		return -EINVAL;
+ 
+ 	spin_lock(&ubi_devices_lock);
+-	put_device(&ubi->dev);
+ 	ubi->ref_count -= 1;
+ 	if (ubi->ref_count) {
+ 		if (!anyway) {
++			ubi->ref_count += 1;
+ 			spin_unlock(&ubi_devices_lock);
+ 			return -EBUSY;
+ 		}
+@@ -1105,6 +1108,13 @@ int ubi_detach_mtd_dev(int ubi_num, int
+ 		ubi_err(ubi, "%s reference count %d, destroy anyway",
+ 			ubi->ubi_name, ubi->ref_count);
+ 	}
++	ubi->is_dead = true;
++	spin_unlock(&ubi_devices_lock);
++
++	ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
++
++	spin_lock(&ubi_devices_lock);
++	put_device(&ubi->dev);
+ 	ubi_devices[ubi_num] = NULL;
+ 	spin_unlock(&ubi_devices_lock);
+ 
+--- a/drivers/mtd/ubi/kapi.c
++++ b/drivers/mtd/ubi/kapi.c
+@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(
+ 
+ 	spin_lock(&ubi->volumes_lock);
+ 	vol = ubi->volumes[vol_id];
+-	if (!vol)
++	if (!vol || vol->is_dead)
+ 		goto out_unlock;
+ 
+ 	err = -EBUSY;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -345,6 +345,7 @@ struct ubi_volume {
+ 	int writers;
+ 	int exclusive;
+ 	int metaonly;
++	bool is_dead;
+ 
+ 	int reserved_pebs;
+ 	int vol_type;
+@@ -564,6 +565,7 @@ struct ubi_device {
+ 	spinlock_t volumes_lock;
+ 	int ref_count;
+ 	int image_seq;
++	bool is_dead;
+ 
+ 	int rsvd_pebs;
+ 	int avail_pebs;
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct
+ 	struct ubi_device *ubi = vol->ubi;
+ 
+ 	spin_lock(&ubi->volumes_lock);
+-	if (!ubi->volumes[vol->vol_id]) {
++	if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
+ 		spin_unlock(&ubi->volumes_lock);
+ 		return -ENODEV;
+ 	}
+@@ -189,7 +189,7 @@ int ubi_create_volume(struct ubi_device
+ 
+ 	/* Ensure that the name is unique */
+ 	for (i = 0; i < ubi->vtbl_slots; i++)
+-		if (ubi->volumes[i] &&
++		if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
+ 		    ubi->volumes[i]->name_len == req->name_len &&
+ 		    !strcmp(ubi->volumes[i]->name, req->name)) {
+ 			ubi_err(ubi, "volume \"%s\" exists (ID %d)",
+@@ -352,6 +352,19 @@ int ubi_remove_volume(struct ubi_volume_
+ 		err = -EBUSY;
+ 		goto out_unlock;
+ 	}
++
++	/*
++	 * Mark volume as dead at this point to prevent that anyone
++	 * can take a reference to the volume from now on.
++	 * This is necessary as we have to release the spinlock before
++	 * calling ubi_volume_notify.
++	 */
++	vol->is_dead = true;
++	spin_unlock(&ubi->volumes_lock);
++
++	ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
++
++	spin_lock(&ubi->volumes_lock);
+ 	ubi->volumes[vol_id] = NULL;
+ 	spin_unlock(&ubi->volumes_lock);
+ 
+--- a/include/linux/mtd/ubi.h
++++ b/include/linux/mtd/ubi.h
+@@ -192,6 +192,7 @@ struct ubi_device_info {
+  *			or a volume was removed)
+  * @UBI_VOLUME_RESIZED: a volume has been re-sized
+  * @UBI_VOLUME_RENAMED: a volume has been re-named
++ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
+  * @UBI_VOLUME_UPDATED: data has been written to a volume
+  *
+  * These constants define which type of event has happened when a volume
+@@ -202,6 +203,7 @@ enum {
+ 	UBI_VOLUME_REMOVED,
+ 	UBI_VOLUME_RESIZED,
+ 	UBI_VOLUME_RENAMED,
++	UBI_VOLUME_SHUTDOWN,
+ 	UBI_VOLUME_UPDATED,
+ };
+ 
diff --git a/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch b/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch
new file mode 100644
index 0000000000..1322766965
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-06-mtd-ubi-populate-ubi-volume-fwnode.patch
@@ -0,0 +1,65 @@
+From 3a041ee543cdf2e707a1dd72946cd6a583509b28 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Fri, 21 Jul 2023 19:26:37 +0100
+Subject: [PATCH 06/15] mtd: ubi: populate ubi volume fwnode
+
+Look for the 'volumes' subnode of an MTD partition attached to a UBI
+device and attach matching child nodes to UBI volumes.
+This allows UBI volumes to be referenced in device tree, e.g. for use
+as NVMEM providers.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mtd/ubi/vmt.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -124,6 +124,31 @@ static void vol_release(struct device *d
+ 	kfree(vol);
+ }
+ 
++static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
++{
++	struct fwnode_handle *fw_vols, *fw_vol;
++	const char *volname;
++	u32 volid;
++
++	fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
++	if (!fw_vols)
++		return NULL;
++
++	fwnode_for_each_child_node(fw_vols, fw_vol) {
++		if (!fwnode_property_read_string(fw_vol, "volname", &volname) &&
++		    strncmp(volname, vol->name, vol->name_len))
++			continue;
++
++		if (!fwnode_property_read_u32(fw_vol, "volid", &volid) &&
++		    vol->vol_id != volid)
++			continue;
++
++		return fw_vol;
++	}
++
++	return NULL;
++}
++
+ /**
+  * ubi_create_volume - create volume.
+  * @ubi: UBI device description object
+@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device
+ 	vol->name_len  = req->name_len;
+ 	memcpy(vol->name, req->name, vol->name_len);
+ 	vol->ubi = ubi;
++	device_set_node(&vol->dev, find_volume_fwnode(vol));
+ 
+ 	/*
+ 	 * Finish all pending erases because there may be some LEBs belonging
+@@ -605,6 +631,7 @@ int ubi_add_volume(struct ubi_device *ub
+ 	vol->dev.class = &ubi_class;
+ 	vol->dev.groups = volume_dev_groups;
+ 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
++	device_set_node(&vol->dev, find_volume_fwnode(vol));
+ 	err = device_register(&vol->dev);
+ 	if (err) {
+ 		cdev_del(&vol->cdev);
diff --git a/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch b/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch
new file mode 100644
index 0000000000..9e6fbea38c
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-07-mtd-ubi-provide-NVMEM-layer-over-UBI-volumes.patch
@@ -0,0 +1,243 @@
+From 7eb6666348f3f2d1f7308c712fa5903cbe189401 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 8 Jun 2023 17:22:04 +0100
+Subject: [PATCH 07/15] mtd: ubi: provide NVMEM layer over UBI volumes
+
+In an ideal world we would like UBI to be used where ever possible on a
+NAND chip. And with UBI support in ARM Trusted Firmware and U-Boot it
+is possible to achieve an (almost-)all-UBI flash layout. Hence the need
+for a way to also use UBI volumes to store board-level constants, such
+as MAC addresses and calibration data of wireless interfaces.
+
+Add UBI volume NVMEM driver module exposing UBI volumes as NVMEM
+providers. Allow UBI devices to have a "volumes" firmware subnode with
+volumes which may be compatible with "nvmem-cells".
+Access to UBI volumes via the NVMEM interface at this point is
+read-only, and it is slow, opening and closing the UBI volume for each
+access due to limitations of the NVMEM provider API.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mtd/ubi/Kconfig  |  12 +++
+ drivers/mtd/ubi/Makefile |   1 +
+ drivers/mtd/ubi/nvmem.c  | 188 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 201 insertions(+)
+ create mode 100644 drivers/mtd/ubi/nvmem.c
+
+--- a/drivers/mtd/ubi/Kconfig
++++ b/drivers/mtd/ubi/Kconfig
+@@ -104,4 +104,16 @@ config MTD_UBI_BLOCK
+ 
+ 	   If in doubt, say "N".
+ 
++config MTD_UBI_NVMEM
++	tristate "UBI virtual NVMEM"
++	default n
++	depends on NVMEM
++	help
++	   This option enabled an additional driver exposing UBI volumes as NVMEM
++	   providers, intended for platforms where UBI is part of the firmware
++	   specification and used to store also e.g. MAC addresses or board-
++	   specific Wi-Fi calibration data.
++
++	   If in doubt, say "N".
++
+ endif # MTD_UBI
+--- a/drivers/mtd/ubi/Makefile
++++ b/drivers/mtd/ubi/Makefile
+@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap
+ ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
+ 
+ obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
++obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
+--- /dev/null
++++ b/drivers/mtd/ubi/nvmem.c
+@@ -0,0 +1,188 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Copyright (c) 2023 Daniel Golle <daniel at makrotopia.org>
++ */
++
++/* UBI NVMEM provider */
++#include "ubi.h"
++#include <linux/nvmem-provider.h>
++#include <asm/div64.h>
++
++/* List of all NVMEM devices */
++static LIST_HEAD(nvmem_devices);
++static DEFINE_MUTEX(devices_mutex);
++
++struct ubi_nvmem {
++	struct nvmem_device *nvmem;
++	int ubi_num;
++	int vol_id;
++	int usable_leb_size;
++	struct list_head list;
++};
++
++static int ubi_nvmem_reg_read(void *priv, unsigned int from,
++			      void *val, size_t bytes)
++{
++	int err = 0, lnum = from, offs, bytes_left = bytes, to_read;
++	struct ubi_nvmem *unv = priv;
++	struct ubi_volume_desc *desc;
++
++	desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
++	if (IS_ERR(desc))
++		return PTR_ERR(desc);
++
++	offs = do_div(lnum, unv->usable_leb_size);
++	while (bytes_left) {
++		to_read = unv->usable_leb_size - offs;
++
++		if (to_read > bytes_left)
++			to_read = bytes_left;
++
++		err = ubi_read(desc, lnum, val, offs, to_read);
++		if (err)
++			break;
++
++		lnum += 1;
++		offs = 0;
++		bytes_left -= to_read;
++		val += to_read;
++	}
++	ubi_close_volume(desc);
++
++	if (err)
++		return err;
++
++	return bytes_left == 0 ? 0 : -EIO;
++}
++
++static int ubi_nvmem_add(struct ubi_volume_info *vi)
++{
++	struct device_node *np = dev_of_node(vi->dev);
++	struct nvmem_config config = {};
++	struct ubi_nvmem *unv;
++	int ret;
++
++	if (!np)
++		return 0;
++
++	if (!of_get_child_by_name(np, "nvmem-layout"))
++		return 0;
++
++	if (WARN_ON_ONCE(vi->usable_leb_size <= 0) ||
++	    WARN_ON_ONCE(vi->size <= 0))
++		return -EINVAL;
++
++	unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
++	if (!unv)
++		return -ENOMEM;
++
++	config.id = NVMEM_DEVID_NONE;
++	config.dev = vi->dev;
++	config.name = dev_name(vi->dev);
++	config.owner = THIS_MODULE;
++	config.priv = unv;
++	config.reg_read = ubi_nvmem_reg_read;
++	config.size = vi->usable_leb_size * vi->size;
++	config.word_size = 1;
++	config.stride = 1;
++	config.read_only = true;
++	config.root_only = true;
++	config.ignore_wp = true;
++	config.of_node = np;
++
++	unv->ubi_num = vi->ubi_num;
++	unv->vol_id = vi->vol_id;
++	unv->usable_leb_size = vi->usable_leb_size;
++	unv->nvmem = nvmem_register(&config);
++	if (IS_ERR(unv->nvmem)) {
++		ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
++				    "Failed to register NVMEM device\n");
++		kfree(unv);
++		return ret;
++	}
++
++	mutex_lock(&devices_mutex);
++	list_add_tail(&unv->list, &nvmem_devices);
++	mutex_unlock(&devices_mutex);
++
++	return 0;
++}
++
++static void ubi_nvmem_remove(struct ubi_volume_info *vi)
++{
++	struct ubi_nvmem *unv_c, *unv = NULL;
++
++	mutex_lock(&devices_mutex);
++	list_for_each_entry(unv_c, &nvmem_devices, list)
++		if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
++			unv = unv_c;
++			break;
++		}
++
++	if (!unv) {
++		mutex_unlock(&devices_mutex);
++		return;
++	}
++
++	list_del(&unv->list);
++	mutex_unlock(&devices_mutex);
++	nvmem_unregister(unv->nvmem);
++	kfree(unv);
++}
++
++/**
++ * nvmem_notify - UBI notification handler.
++ * @nb: registered notifier block
++ * @l: notification type
++ * @ns_ptr: pointer to the &struct ubi_notification object
++ */
++static int nvmem_notify(struct notifier_block *nb, unsigned long l,
++			 void *ns_ptr)
++{
++	struct ubi_notification *nt = ns_ptr;
++
++	switch (l) {
++	case UBI_VOLUME_RESIZED:
++		ubi_nvmem_remove(&nt->vi);
++		fallthrough;
++	case UBI_VOLUME_ADDED:
++		ubi_nvmem_add(&nt->vi);
++		break;
++	case UBI_VOLUME_SHUTDOWN:
++		ubi_nvmem_remove(&nt->vi);
++		break;
++	default:
++		break;
++	}
++	return NOTIFY_OK;
++}
++
++static struct notifier_block nvmem_notifier = {
++	.notifier_call = nvmem_notify,
++};
++
++static int __init ubi_nvmem_init(void)
++{
++	return ubi_register_volume_notifier(&nvmem_notifier, 0);
++}
++
++static void __exit ubi_nvmem_exit(void)
++{
++	struct ubi_nvmem *unv, *tmp;
++
++	mutex_lock(&devices_mutex);
++	list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
++		nvmem_unregister(unv->nvmem);
++		list_del(&unv->list);
++		kfree(unv);
++	}
++	mutex_unlock(&devices_mutex);
++
++	ubi_unregister_volume_notifier(&nvmem_notifier);
++}
++
++module_init(ubi_nvmem_init);
++module_exit(ubi_nvmem_exit);
++MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
++MODULE_AUTHOR("Daniel Golle");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch b/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch
new file mode 100644
index 0000000000..d0727faf3d
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-08-dt-bindings-block-add-basic-bindings-for-block-devic.patch
@@ -0,0 +1,120 @@
+From 9ffc1d7d73609a89eb264d6066340f8b7b3b0ebe Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 7 Aug 2023 21:19:45 +0100
+Subject: [PATCH 08/15] dt-bindings: block: add basic bindings for block
+ devices
+
+Add bindings for block devices which are used to allow referencing
+nvmem bits on them.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ .../bindings/block/block-device.yaml          | 22 ++++++++
+ .../devicetree/bindings/block/partition.yaml  | 50 +++++++++++++++++++
+ .../devicetree/bindings/block/partitions.yaml | 20 ++++++++
+ 3 files changed, 92 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
+ create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
+ create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/block-device.yaml
+@@ -0,0 +1,22 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/block-device.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: block storage device
++
++description: |
++  This binding is generic and describes a block-oriented storage device.
++
++maintainers:
++  - Daniel Golle <daniel at makrotopia.org>
++
++properties:
++  partitions:
++    $ref: /schemas/block/partitions.yaml
++
++  nvmem-layout:
++    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++
++unevaluatedProperties: false
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/partition.yaml
+@@ -0,0 +1,50 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/partition.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Partition on a block device
++
++description: |
++  This binding describes a partition on a block device.
++  Partitions may be matched by a combination of partition number, name,
++  and UUID.
++
++maintainers:
++  - Daniel Golle <daniel at makrotopia.org>
++
++properties:
++  $nodename:
++    pattern: '^block-partition-.+$'
++
++  partnum:
++    description:
++      Matches partition by number if present.
++
++  partname:
++    "$ref": "/schemas/types.yaml#/definitions/string"
++    description:
++      Matches partition by PARTNAME if present.
++
++  uuid:
++    "$ref": "/schemas/types.yaml#/definitions/string"
++    description:
++      Matches partition by PARTUUID if present.
++
++  nvmem-layout:
++    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
++    description:
++      This container may reference an NVMEM layout parser.
++
++anyOf:
++  - required:
++    - partnum
++
++  - required:
++    - partname
++
++  - required:
++    - uuid
++
++unevaluatedProperties: false
+--- /dev/null
++++ b/Documentation/devicetree/bindings/block/partitions.yaml
+@@ -0,0 +1,20 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/block/partitions.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Partitions on block devices
++
++description: |
++  This binding is generic and describes the content of the partitions container
++  node.
++
++maintainers:
++  - Daniel Golle <daniel at makrotopia.org>
++
++patternProperties:
++  "^block-partition-.+$":
++    $ref: partition.yaml
++
++unevaluatedProperties: false
diff --git a/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch b/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch
new file mode 100644
index 0000000000..8aa5cba678
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-09-block-partitions-populate-fwnode.patch
@@ -0,0 +1,77 @@
+From 614f4f6fdda09e30ecf7ef6c8091579db15018cb Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Fri, 21 Jul 2023 17:51:03 +0100
+Subject: [PATCH 09/15] block: partitions: populate fwnode
+
+Let block partitions to be represented by a firmware node and hence
+allow them to being referenced e.g. for use with blk-nvmem.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+--- a/block/partitions/core.c
++++ b/block/partitions/core.c
+@@ -10,6 +10,8 @@
+ #include <linux/ctype.h>
+ #include <linux/vmalloc.h>
+ #include <linux/raid/detect.h>
++#include <linux/property.h>
++
+ #include "check.h"
+ 
+ static int (*check_part[])(struct parsed_partitions *) = {
+@@ -298,6 +300,43 @@ static ssize_t whole_disk_show(struct de
+ }
+ static DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
+ 
++static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
++{
++	struct fwnode_handle *fw_parts, *fw_part;
++	struct device *ddev = disk_to_dev(bdev->bd_disk);
++	const char *partname, *uuid;
++	u32 partno;
++
++	fw_parts = device_get_named_child_node(ddev, "partitions");
++	if (!fw_parts)
++		fw_parts = device_get_named_child_node(ddev->parent, "partitions");
++
++	if (!fw_parts)
++		return NULL;
++
++	fwnode_for_each_child_node(fw_parts, fw_part) {
++		if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
++		    (!bdev->bd_meta_info || strncmp(uuid,
++						    bdev->bd_meta_info->uuid,
++						    PARTITION_META_INFO_UUIDLTH)))
++			continue;
++
++		if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
++		    (!bdev->bd_meta_info || strncmp(partname,
++						    bdev->bd_meta_info->volname,
++						    PARTITION_META_INFO_VOLNAMELTH)))
++			continue;
++
++		if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
++		    bdev->bd_partno != partno)
++			continue;
++
++		return fw_part;
++	}
++
++	return NULL;
++}
++
+ /*
+  * Must be called either with open_mutex held, before a disk can be opened or
+  * after all disk users are gone.
+@@ -380,6 +419,8 @@ static struct block_device *add_partitio
+ 			goto out_put;
+ 	}
+ 
++	device_set_node(pdev, find_partition_fwnode(bdev));
++
+ 	/* delay uevent until 'holders' subdir is created */
+ 	dev_set_uevent_suppress(pdev, 1);
+ 	err = device_add(pdev);
diff --git a/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch b/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch
new file mode 100644
index 0000000000..4cbec14f5c
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-10-block-add-new-genhd-flag-GENHD_FL_NVMEM.patch
@@ -0,0 +1,29 @@
+From 65f3ff9672ccd5ee78937047e7a2fc696eee1c8f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 13 Jul 2023 04:07:16 +0100
+Subject: [PATCH 10/15] block: add new genhd flag GENHD_FL_NVMEM
+
+Add new flag to destinguish block devices which may act as an NVMEM
+provider.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ include/linux/blkdev.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -87,11 +87,13 @@ struct partition_meta_info {
+  * ``GENHD_FL_NO_PART``: partition support is disabled.  The kernel will not
+  * scan for partitions from add_disk, and users can't add partitions manually.
+  *
++ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
+  */
+ enum {
+ 	GENHD_FL_REMOVABLE			= 1 << 0,
+ 	GENHD_FL_HIDDEN				= 1 << 1,
+ 	GENHD_FL_NO_PART			= 1 << 2,
++	GENHD_FL_NVMEM				= 1 << 3,
+ };
+ 
+ enum {
diff --git a/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch b/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch
new file mode 100644
index 0000000000..e18b0c3a5c
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-11-block-implement-NVMEM-provider.patch
@@ -0,0 +1,235 @@
+From b9936aa8a3775c2027f655d91a206d0e6e1c7ec0 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Tue, 11 Jul 2023 00:17:31 +0100
+Subject: [PATCH 11/15] block: implement NVMEM provider
+
+On embedded devices using an eMMC it is common that one or more partitions
+on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
+data. Allow referencing the partition in device tree for the kernel and
+Wi-Fi drivers accessing it via the NVMEM layer.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ block/Kconfig     |   9 +++
+ block/Makefile    |   1 +
+ block/blk-nvmem.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 196 insertions(+)
+ create mode 100644 block/blk-nvmem.c
+
+--- a/block/Kconfig
++++ b/block/Kconfig
+@@ -203,6 +203,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
+ 	  by falling back to the kernel crypto API when inline
+ 	  encryption hardware is not present.
+ 
++config BLK_NVMEM
++	bool "Block device NVMEM provider"
++	depends on OF
++	depends on NVMEM
++	help
++	  Allow block devices (or partitions) to act as NVMEM prodivers,
++	  typically used with eMMC to store MAC addresses or Wi-Fi
++	  calibration data on embedded devices.
++
+ source "block/partitions/Kconfig"
+ 
+ config BLOCK_COMPAT
+--- a/block/Makefile
++++ b/block/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)	+= blk-zoned
+ obj-$(CONFIG_BLK_WBT)		+= blk-wbt.o
+ obj-$(CONFIG_BLK_DEBUG_FS)	+= blk-mq-debugfs.o
+ obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
++obj-$(CONFIG_BLK_NVMEM)		+= blk-nvmem.o
+ obj-$(CONFIG_BLK_SED_OPAL)	+= sed-opal.o
+ obj-$(CONFIG_BLK_PM)		+= blk-pm.o
+ obj-$(CONFIG_BLK_INLINE_ENCRYPTION)	+= blk-crypto.o blk-crypto-profile.o \
+--- /dev/null
++++ b/block/blk-nvmem.c
+@@ -0,0 +1,186 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * block device NVMEM provider
++ *
++ * Copyright (c) 2023 Daniel Golle <daniel at makrotopia.org>
++ *
++ * Useful on devices using a partition on an eMMC for MAC addresses or
++ * Wi-Fi calibration EEPROM data.
++ */
++
++#include "blk.h"
++#include <linux/nvmem-provider.h>
++#include <linux/of.h>
++#include <linux/pagemap.h>
++#include <linux/property.h>
++
++/* List of all NVMEM devices */
++static LIST_HEAD(nvmem_devices);
++static DEFINE_MUTEX(devices_mutex);
++
++struct blk_nvmem {
++	struct nvmem_device *nvmem;
++	struct block_device *bdev;
++	struct list_head list;
++};
++
++static int blk_nvmem_reg_read(void *priv, unsigned int from,
++			      void *val, size_t bytes)
++{
++	unsigned long offs = from & ~PAGE_MASK, to_read;
++	pgoff_t f_index = from >> PAGE_SHIFT;
++	struct address_space *mapping;
++	struct blk_nvmem *bnv = priv;
++	size_t bytes_left = bytes;
++	struct folio *folio;
++	void *p;
++	int ret;
++
++	if (!bnv->bdev)
++		return -ENODEV;
++
++	if (!bnv->bdev->bd_disk)
++		return -EINVAL;
++
++	if (!bnv->bdev->bd_disk->fops)
++		return -EIO;
++
++	if (!bnv->bdev->bd_disk->fops->open)
++		return -EIO;
++
++	ret = bnv->bdev->bd_disk->fops->open(bnv->bdev, FMODE_READ);
++	if (ret)
++		return ret;
++
++	mapping = bnv->bdev->bd_inode->i_mapping;
++
++	while (bytes_left) {
++		folio = read_mapping_folio(mapping, f_index++, NULL);
++		if (IS_ERR(folio)) {
++			ret = PTR_ERR(folio);
++			goto err_release_bdev;
++		}
++		to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs);
++		p = folio_address(folio) + offset_in_folio(folio, offs);
++		memcpy(val, p, to_read);
++		offs = 0;
++		bytes_left -= to_read;
++		val += to_read;
++		folio_put(folio);
++	}
++
++err_release_bdev:
++	bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk, FMODE_READ);
++
++	return ret;
++}
++
++static int blk_nvmem_register(struct device *dev, struct class_interface *iface)
++{
++	struct device_node *np = dev_of_node(dev);
++	struct block_device *bdev = dev_to_bdev(dev);
++	struct nvmem_config config = {};
++	struct blk_nvmem *bnv;
++
++	/* skip devices which do not have a device tree node */
++	if (!np)
++		return 0;
++
++	/* skip devices without an nvmem layout defined */
++	if (!of_get_child_by_name(np, "nvmem-layout"))
++		return 0;
++
++	/*
++	 * skip devices which don't have GENHD_FL_NVMEM set
++	 *
++	 * This flag is used for mtdblock and ubiblock devices because
++	 * both, MTD and UBI already implement their own NVMEM provider.
++	 * To avoid registering multiple NVMEM providers for the same
++	 * device node, don't register the block NVMEM provider for them.
++	 */
++	if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM))
++		return 0;
++
++	/*
++	 * skip block device too large to be represented as NVMEM devices
++	 * which are using an 'int' as address
++	 */
++	if (bdev_nr_bytes(bdev) > INT_MAX)
++		return -EFBIG;
++
++	bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL);
++	if (!bnv)
++		return -ENOMEM;
++
++	config.id = NVMEM_DEVID_NONE;
++	config.dev = &bdev->bd_device;
++	config.name = dev_name(&bdev->bd_device);
++	config.owner = THIS_MODULE;
++	config.priv = bnv;
++	config.reg_read = blk_nvmem_reg_read;
++	config.size = bdev_nr_bytes(bdev);
++	config.word_size = 1;
++	config.stride = 1;
++	config.read_only = true;
++	config.root_only = true;
++	config.ignore_wp = true;
++	config.of_node = to_of_node(dev->fwnode);
++
++	bnv->bdev = bdev;
++	bnv->nvmem = nvmem_register(&config);
++	if (IS_ERR(bnv->nvmem)) {
++		dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
++			      "Failed to register NVMEM device\n");
++
++		kfree(bnv);
++		return PTR_ERR(bnv->nvmem);
++	}
++
++	mutex_lock(&devices_mutex);
++	list_add_tail(&bnv->list, &nvmem_devices);
++	mutex_unlock(&devices_mutex);
++
++	return 0;
++}
++
++static void blk_nvmem_unregister(struct device *dev, struct class_interface *iface)
++{
++	struct block_device *bdev = dev_to_bdev(dev);
++	struct blk_nvmem *bnv_c, *bnv = NULL;
++
++	mutex_lock(&devices_mutex);
++	list_for_each_entry(bnv_c, &nvmem_devices, list) {
++		if (bnv_c->bdev == bdev) {
++			bnv = bnv_c;
++			break;
++		}
++	}
++
++	if (!bnv) {
++		mutex_unlock(&devices_mutex);
++		return;
++	}
++
++	list_del(&bnv->list);
++	mutex_unlock(&devices_mutex);
++	nvmem_unregister(bnv->nvmem);
++	kfree(bnv);
++}
++
++static struct class_interface blk_nvmem_bus_interface __refdata = {
++	.class = &block_class,
++	.add_dev = &blk_nvmem_register,
++	.remove_dev = &blk_nvmem_unregister,
++};
++
++static int __init blk_nvmem_init(void)
++{
++	int ret;
++
++	ret = class_interface_register(&blk_nvmem_bus_interface);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++device_initcall(blk_nvmem_init);
diff --git a/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch b/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch
new file mode 100644
index 0000000000..77c9bf91a5
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-12-dt-bindings-mmc-mmc-card-add-block-device-nodes.patch
@@ -0,0 +1,74 @@
+From 86864bf8f40e84dc881c197ef470a88668329dbf Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Mon, 7 Aug 2023 21:21:45 +0100
+Subject: [PATCH 12/15] dt-bindings: mmc: mmc-card: add block device nodes
+
+Add nodes representing the block devices exposed by an MMC device
+including an example involving nvmem-cells.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ .../devicetree/bindings/mmc/mmc-card.yaml     | 45 +++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
++++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+@@ -26,6 +26,18 @@ properties:
+       Use this to indicate that the mmc-card has a broken hpi
+       implementation, and that hpi should not be used.
+ 
++  block:
++    $ref: /schemas/block/block-device.yaml#
++    description:
++      Represents the block storage provided by an SD card or the
++      main hardware partition of an eMMC.
++
++patternProperties:
++  '^boot[0-9]+':
++    $ref: /schemas/block/block-device.yaml#
++    description:
++      Represents a boot hardware partition on an eMMC.
++
+ required:
+   - compatible
+   - reg
+@@ -42,6 +54,39 @@ examples:
+             compatible = "mmc-card";
+             reg = <0>;
+             broken-hpi;
++
++            block {
++                partitions {
++                    cal_data: block-partition-rf {
++                        partnum = <3>;
++                        partname = "rf";
++
++                        nvmem-layout {
++                            compatible = "fixed-layout";
++                            #address-cells = <1>;
++                            #size-cells = <1>;
++
++                            eeprom at 0 {
++                                reg = <0x0 0x1000>;
++                            };
++                        };
++                    };
++                };
++            };
++
++            boot1 {
++                nvmem-layout {
++                    compatible = "fixed-layout";
++                    #address-cells = <1>;
++                    #size-cells = <1>;
++
++                    macaddr: macaddr at a {
++                        compatible = "mac-base";
++                        reg = <0xa 0x6>;
++                        #nvmem-cell-cells = <1>;
++                    };
++                };
++            };
+         };
+     };
+ 
diff --git a/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch b/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch
new file mode 100644
index 0000000000..fada280437
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-13-mmc-core-set-card-fwnode_handle.patch
@@ -0,0 +1,23 @@
+From 644942a31719de674e2aa68f83d66bd8ae7e4fb7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 13 Jul 2023 04:12:21 +0100
+Subject: [PATCH 13/15] mmc: core: set card fwnode_handle
+
+Set fwnode in case it isn't set yet and of_node is present.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mmc/core/bus.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/mmc/core/bus.c
++++ b/drivers/mmc/core/bus.c
+@@ -363,6 +363,8 @@ int mmc_add_card(struct mmc_card *card)
+ 	mmc_add_card_debugfs(card);
+ #endif
+ 	card->dev.of_node = mmc_of_find_child_device(card->host, 0);
++	if (card->dev.of_node && !card->dev.fwnode)
++		card->dev.fwnode = &card->dev.of_node->fwnode;
+ 
+ 	device_enable_async_suspend(&card->dev);
+ 
diff --git a/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch b/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch
new file mode 100644
index 0000000000..d033abb70d
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-14-mmc-block-set-fwnode-of-disk-devices.patch
@@ -0,0 +1,38 @@
+From d9143f86330dd038fc48878558dd287ceee5d3d4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 13 Jul 2023 04:13:04 +0100
+Subject: [PATCH 14/15] mmc: block: set fwnode of disk devices
+
+Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
+the mmc-card. This is done in preparation for having the eMMC act as
+NVMEM provider.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mmc/core/block.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2484,6 +2484,8 @@ static struct mmc_blk_data *mmc_blk_allo
+ 					      int area_type,
+ 					      unsigned int part_type)
+ {
++	struct fwnode_handle *fwnode;
++	struct device *ddev;
+ 	struct mmc_blk_data *md;
+ 	int devidx, ret;
+ 	char cap_str[10];
+@@ -2580,6 +2582,12 @@ static struct mmc_blk_data *mmc_blk_allo
+ 
+ 	blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled);
+ 
++	ddev = disk_to_dev(md->disk);
++	fwnode = device_get_named_child_node(subname ? md->parent->parent :
++						       md->parent,
++					     subname ? subname : "block");
++	ddev->fwnode = fwnode;
++
+ 	string_get_size((u64)size, 512, STRING_UNITS_2,
+ 			cap_str, sizeof(cap_str));
+ 	pr_info("%s: %s %s %s %s\n",
diff --git a/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch b/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch
new file mode 100644
index 0000000000..d76e7b2fe5
--- /dev/null
+++ b/target/linux/generic/pending-6.1/450-15-mmc-block-set-GENHD_FL_NVMEM.patch
@@ -0,0 +1,22 @@
+From 322035ab2b0113d98b6c0ea788d971e0df2952a4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel at makrotopia.org>
+Date: Thu, 20 Jul 2023 17:36:44 +0100
+Subject: [PATCH 15/15] mmc: block: set GENHD_FL_NVMEM
+
+Set flag to consider MMC block devices as NVMEM providers.
+
+Signed-off-by: Daniel Golle <daniel at makrotopia.org>
+---
+ drivers/mmc/core/block.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2538,6 +2538,7 @@ static struct mmc_blk_data *mmc_blk_allo
+ 	md->disk->major	= MMC_BLOCK_MAJOR;
+ 	md->disk->minors = perdev_minors;
+ 	md->disk->first_minor = devidx * perdev_minors;
++	md->disk->flags = GENHD_FL_NVMEM;
+ 	md->disk->fops = &mmc_bdops;
+ 	md->disk->private_data = md;
+ 	md->parent = parent;
diff --git a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
index 2601281bf7..2eccb9d3bb 100644
--- a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
+++ b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -8,10 +8,11 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 
 --- a/drivers/mtd/ubi/build.c
 +++ b/drivers/mtd/ubi/build.c
-@@ -1213,6 +1213,73 @@ static struct mtd_info * __init open_mtd
- 	return mtd;
- }
+@@ -1263,6 +1263,74 @@ static struct mtd_notifier ubi_mtd_notif
+ 	.remove = ubi_notify_remove,
+ };
  
++
 +/*
 + * This function tries attaching mtd partitions named either "ubi" or "data"
 + * during boot.
@@ -79,10 +80,10 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 +	put_mtd_device(mtd);
 +}
 +
- static int __init ubi_init(void)
+ static int __init ubi_init_attach(void)
  {
  	int err, i, k;
-@@ -1297,6 +1364,12 @@ static int __init ubi_init(void)
+@@ -1313,6 +1381,12 @@ static int __init ubi_init_attach(void)
  		}
  	}
  
@@ -92,6 +93,6 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 +	    !ubi_is_module() && !mtd_devs)
 +		ubi_auto_attach();
 +
- 	err = ubiblock_init();
- 	if (err) {
- 		pr_err("UBI error: block: cannot initialize, error %d\n", err);
+ 	return 0;
+ 
+ out_detach:
diff --git a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
index 17e8d8bedb..a43da2a572 100644
--- a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
+++ b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
@@ -8,8 +8,8 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -653,6 +653,47 @@ static void __init ubiblock_create_from_
- 	}
+@@ -644,10 +644,47 @@ match_volume_desc(struct ubi_volume_info
+ 	return true;
  }
  
 +#define UBIFS_NODE_MAGIC  0x06101831
@@ -24,46 +24,54 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 +	return magic == UBIFS_NODE_MAGIC;
 +}
 +
-+static void __init ubiblock_create_auto_rootfs(void)
++static void __init ubiblock_create_auto_rootfs(struct ubi_volume_info *vi)
 +{
-+	int ubi_num, ret, is_ubifs;
++	int ret, is_ubifs;
 +	struct ubi_volume_desc *desc;
-+	struct ubi_volume_info vi;
 +
-+	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
-+		desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
-+		if (IS_ERR(desc))
-+			desc = ubi_open_volume_nm(ubi_num, "fit", UBI_READONLY);;
++	if (strcmp(vi->name, "rootfs") &&
++	    strcmp(vi->name, "fit"))
++		return;
 +
-+		if (IS_ERR(desc))
-+			continue;
++	desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY);
++	if (IS_ERR(desc))
++		return;
 +
-+		ubi_get_volume_info(desc, &vi);
-+		is_ubifs = ubi_vol_is_ubifs(desc);
-+		ubi_close_volume(desc);
-+		if (is_ubifs)
-+			break;
++	is_ubifs = ubi_vol_is_ubifs(desc);
++	ubi_close_volume(desc);
++	if (is_ubifs)
++		return;
 +
-+		ret = ubiblock_create(&vi);
-+		if (ret)
-+			pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
-+				vi.name, ret);
-+		/* always break if we get here */
-+		break;
-+	}
++	ret = ubiblock_create(vi);
++	if (ret)
++		pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
++			vi->name, ret);
 +}
 +
- static void ubiblock_remove_all(void)
+ static void
+ ubiblock_create_from_param(struct ubi_volume_info *vi)
  {
- 	struct ubiblock *next;
-@@ -685,6 +726,10 @@ int __init ubiblock_init(void)
- 	 */
- 	ubiblock_create_from_param();
+ 	int i, ret = 0;
++	bool got_param = false;
+ 	struct ubiblock_param *p;
  
-+	/* auto-attach "rootfs" volume if existing and non-ubifs */
-+	if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
-+		ubiblock_create_auto_rootfs();
-+
  	/*
- 	 * Block devices are only created upon user requests, so we ignore
- 	 * existing volumes.
+@@ -660,6 +697,7 @@ ubiblock_create_from_param(struct ubi_vo
+ 		if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
+ 			continue;
+ 
++		got_param = true;
+ 		ret = ubiblock_create(vi);
+ 		if (ret) {
+ 			pr_err(
+@@ -668,6 +706,10 @@ ubiblock_create_from_param(struct ubi_vo
+ 		}
+ 		break;
+ 	}
++
++	/* auto-attach "rootfs" volume if existing and non-ubifs */
++	if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
++		ubiblock_create_auto_rootfs(vi);
+ }
+ 
+ static int ubiblock_notify(struct notifier_block *nb,
diff --git a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
index e3493ef19e..5357c7e15d 100644
--- a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
+++ b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
@@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
 
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -42,6 +42,7 @@
+@@ -43,6 +43,7 @@
  #include <linux/scatterlist.h>
  #include <linux/idr.h>
  #include <asm/div64.h>
@@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle <daniel at makrotopia.org>
  
  #include "ubi-media.h"
  #include "ubi.h"
-@@ -459,6 +460,15 @@ int ubiblock_create(struct ubi_volume_in
+@@ -460,6 +461,15 @@ int ubiblock_create(struct ubi_volume_in
  	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
  		 dev->ubi_num, dev->vol_id, vi->name);
  	mutex_unlock(&devices_mutex);
diff --git a/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch
index 413431755f..fc48146221 100644
--- a/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch
+++ b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch
@@ -50,7 +50,7 @@ Signed-off-by: Gabor Juhos <juhosg at openwrt.org>
  		break;
 --- a/drivers/mtd/ubi/ubi.h
 +++ b/drivers/mtd/ubi/ubi.h
-@@ -778,6 +778,7 @@ struct ubi_attach_info {
+@@ -780,6 +780,7 @@ struct ubi_attach_info {
  	int mean_ec;
  	uint64_t ec_sum;
  	int ec_count;
diff --git a/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch b/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch
index 3e45646fdb..bb87c20a91 100644
--- a/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch
+++ b/target/linux/mediatek/patches-6.1/041-block-fit-partition-parser.patch
@@ -72,18 +72,17 @@ Subject: [PATCH] kernel: add block fit partition parser
 +int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain);
 --- a/block/partitions/core.c
 +++ b/block/partitions/core.c
-@@ -10,6 +10,10 @@
- #include <linux/ctype.h>
+@@ -11,6 +11,9 @@
  #include <linux/vmalloc.h>
  #include <linux/raid/detect.h>
+ #include <linux/property.h>
 +#ifdef CONFIG_FIT_PARTITION
 +#include <linux/root_dev.h>
 +#endif
-+
+ 
  #include "check.h"
  
- static int (*check_part[])(struct parsed_partitions *) = {
-@@ -46,6 +50,9 @@ static int (*check_part[])(struct parsed
+@@ -48,6 +51,9 @@ static int (*check_part[])(struct parsed
  #ifdef CONFIG_EFI_PARTITION
  	efi_partition,		/* this must come before msdos */
  #endif
@@ -93,7 +92,7 @@ Subject: [PATCH] kernel: add block fit partition parser
  #ifdef CONFIG_SGI_PARTITION
  	sgi_partition,
  #endif
-@@ -398,6 +405,11 @@ static struct block_device *add_partitio
+@@ -439,6 +445,11 @@ static struct block_device *add_partitio
  			goto out_del;
  	}
  
@@ -105,7 +104,7 @@ Subject: [PATCH] kernel: add block fit partition parser
  	/* everything is up and running, commence */
  	err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
  	if (err)
-@@ -590,6 +602,11 @@ static bool blk_add_partition(struct gen
+@@ -631,6 +642,11 @@ static bool blk_add_partition(struct gen
  	    (state->parts[p].flags & ADDPART_FLAG_RAID))
  		md_autodetect_dev(part->bd_dev);
  
@@ -194,7 +193,7 @@ Subject: [PATCH] kernel: add block fit partition parser
  	set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
 --- a/drivers/mtd/ubi/block.c
 +++ b/drivers/mtd/ubi/block.c
-@@ -431,7 +431,9 @@ int ubiblock_create(struct ubi_volume_in
+@@ -432,7 +432,9 @@ int ubiblock_create(struct ubi_volume_in
  		ret = -ENODEV;
  		goto out_cleanup_disk;
  	}




More information about the lede-commits mailing list