mtd: add support for parsing partitions defined in OF

Add support for parsing partitions defined in device-trees via the
`partitions` node with `fixed-partitions` compatible.

The `mtdparts`/`mtdids` mechanism takes precedence. If some partitions
are defined for a MTD device via this mechanism, the code won't register
partitions for that MTD device from OF, even if they are defined.

Signed-off-by: Marek BehĂșn <marek.behun@nic.cz>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Tested-by: Patrice Chotard <patrice.chotard@foss.st.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>
Cc: Patrick Delaunay <patrick.delaunay@st.com>
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index d064ac3..aa58f72 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -892,6 +892,69 @@
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL)
+int add_mtd_partitions_of(struct mtd_info *master)
+{
+	ofnode parts, child;
+	int i = 0;
+
+	if (!master->dev)
+		return 0;
+
+	parts = ofnode_find_subnode(mtd_get_ofnode(master), "partitions");
+	if (!ofnode_valid(parts) || !ofnode_is_available(parts) ||
+	    !ofnode_device_is_compatible(parts, "fixed-partitions"))
+		return 0;
+
+	ofnode_for_each_subnode(child, parts) {
+		struct mtd_partition part = { 0 };
+		struct mtd_info *slave;
+		fdt_addr_t offset, size;
+
+		if (!ofnode_is_available(child))
+			continue;
+
+		offset = ofnode_get_addr_size_index_notrans(child, 0, &size);
+		if (offset == FDT_ADDR_T_NONE || !size) {
+			debug("Missing partition offset/size on \"%s\" partition\n",
+			      master->name);
+			continue;
+		}
+
+		part.name = ofnode_read_string(child, "label");
+		if (!part.name)
+			part.name = ofnode_read_string(child, "name");
+
+		/*
+		 * .mask_flags is used to remove flags in allocate_partition(),
+		 * so when "read-only" is present, we add MTD_WRITABLE to the
+		 * mask, and so MTD_WRITABLE will be removed on partition
+		 * allocation
+		 */
+		if (ofnode_read_bool(child, "read-only"))
+			part.mask_flags |= MTD_WRITEABLE;
+		if (ofnode_read_bool(child, "lock"))
+			part.mask_flags |= MTD_POWERUP_LOCK;
+
+		part.offset = offset;
+		part.size = size;
+		part.ecclayout = master->ecclayout;
+
+		slave = allocate_partition(master, &part, i++, 0);
+		if (IS_ERR(slave))
+			return PTR_ERR(slave);
+
+		mutex_lock(&mtd_partitions_mutex);
+		list_add_tail(&slave->node, &master->partitions);
+		mutex_unlock(&mtd_partitions_mutex);
+
+		add_mtd_device(slave);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) */
+
 #ifndef __UBOOT__
 static DEFINE_SPINLOCK(part_parser_lock);
 static LIST_HEAD(part_parsers);