kernel: add the latest mtd patch extending ofpart parser
authorRafał Miłecki <rafal@milecki.pl>
Mon, 1 Mar 2021 17:12:48 +0000 (18:12 +0100)
committerRafał Miłecki <rafal@milecki.pl>
Mon, 1 Mar 2021 17:18:38 +0000 (18:18 +0100)
This adds the latest version of ofpart commit. It hopefully
1. Doesn't break compilation
2. Doesn't break partitioning
(this time).

It's required to implement fixed partitioning with some quirks. It's
required by bcm53xx, bcm4908, kirkwood, lantiq and mvebu.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
15 files changed:
target/linux/ath79/patches-5.10/404-mtd-cybertan-trx-parser.patch
target/linux/ath79/patches-5.4/404-mtd-cybertan-trx-parser.patch
target/linux/bcm4908/patches-5.4/400-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch [deleted file]
target/linux/generic/pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch [new file with mode: 0644]
target/linux/generic/pending-5.10/430-mtd-add-myloader-partition-parser.patch
target/linux/generic/pending-5.10/435-mtd-add-routerbootpart-parser-config.patch
target/linux/generic/pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/430-mtd-add-myloader-partition-parser.patch
target/linux/generic/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch
target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch
target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch
target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch
target/linux/lantiq/patches-5.4/0101-find_active_root.patch
target/linux/mvebu/patches-5.10/400-find_active_root.patch
target/linux/mvebu/patches-5.4/400-find_active_root.patch

index 1ebf87c61045aea1a54460f4539d538329bbe24a..59ee57d277b95877d95a3ac9bdd329da65f0b5f7 100644 (file)
@@ -1,18 +1,18 @@
 --- a/drivers/mtd/parsers/Makefile
 +++ b/drivers/mtd/parsers/Makefile
-@@ -5,6 +5,7 @@ obj-$(CONFIG_MTD_BCM63XX_PARTS)                += bcm6
- obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
- obj-$(CONFIG_MTD_MYLOADER_PARTS)              += myloader.o
+@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_MYLOADER_PARTS)               += myl
  obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
+ ofpart-y                              += ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
 +obj-$(CONFIG_MTD_PARSER_CYBERTAN)     += parser_cybertan.o
  obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
  obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
  obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
 --- a/drivers/mtd/parsers/Kconfig
 +++ b/drivers/mtd/parsers/Kconfig
-@@ -83,6 +83,14 @@ config MTD_OF_PARTS
-         flash memory node, as described in
-         Documentation/devicetree/bindings/mtd/partition.txt.
+@@ -92,6 +92,14 @@ config MTD_OF_PARTS_BCM4908
+         that can have multiple "firmware" partitions. It takes care of
+         finding currently used one and backup ones.
  
 +config MTD_PARSER_CYBERTAN
 +      tristate "Parser for Cybertan format partitions"
index 1ebf87c61045aea1a54460f4539d538329bbe24a..59ee57d277b95877d95a3ac9bdd329da65f0b5f7 100644 (file)
@@ -1,18 +1,18 @@
 --- a/drivers/mtd/parsers/Makefile
 +++ b/drivers/mtd/parsers/Makefile
-@@ -5,6 +5,7 @@ obj-$(CONFIG_MTD_BCM63XX_PARTS)                += bcm6
- obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
- obj-$(CONFIG_MTD_MYLOADER_PARTS)              += myloader.o
+@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_MYLOADER_PARTS)               += myl
  obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
+ ofpart-y                              += ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
 +obj-$(CONFIG_MTD_PARSER_CYBERTAN)     += parser_cybertan.o
  obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
  obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
  obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
 --- a/drivers/mtd/parsers/Kconfig
 +++ b/drivers/mtd/parsers/Kconfig
-@@ -83,6 +83,14 @@ config MTD_OF_PARTS
-         flash memory node, as described in
-         Documentation/devicetree/bindings/mtd/partition.txt.
+@@ -92,6 +92,14 @@ config MTD_OF_PARTS_BCM4908
+         that can have multiple "firmware" partitions. It takes care of
+         finding currently used one and backup ones.
  
 +config MTD_PARSER_CYBERTAN
 +      tristate "Parser for Cybertan format partitions"
diff --git a/target/linux/bcm4908/patches-5.4/400-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/target/linux/bcm4908/patches-5.4/400-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch
deleted file mode 100644 (file)
index ace0c77..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-From 3924b0384a0cd20245e2ffb55c45c2ace737a061 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Thu, 11 Feb 2021 23:04:27 +0100
-Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some devices use fixed partitioning with some partitions requiring some
-extra logic. E.g. BCM4908 may have multiple firmware partitions but
-detecting currently used one requires checking bootloader parameters.
-
-To support such cases without duplicating a lot of code (without copying
-most of the ofpart.c code) support for post-parsing callback was added.
-
-BCM4908 support in ofpart can be enabled using config option and results
-in compiling & executing a specific callback. It simply reads offset of
-currently used firmware partition from the DT. Bootloader specifies it
-using the "brcm_blparms" property.
-
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
----
- drivers/mtd/parsers/Kconfig                   |  9 +++
- drivers/mtd/parsers/Makefile                  |  2 +
- drivers/mtd/parsers/ofpart_bcm4908.c          | 66 +++++++++++++++++++
- drivers/mtd/parsers/ofpart_bcm4908.h          | 15 +++++
- .../mtd/parsers/{ofpart.c => ofpart_core.c}   | 28 +++++++-
- 5 files changed, 118 insertions(+), 2 deletions(-)
- create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c
- create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h
- rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%)
-
---- a/drivers/mtd/parsers/Kconfig
-+++ b/drivers/mtd/parsers/Kconfig
-@@ -83,6 +83,15 @@ config MTD_OF_PARTS
-         flash memory node, as described in
-         Documentation/devicetree/bindings/mtd/partition.txt.
-+config MTD_OF_PARTS_BCM4908
-+      bool "BCM4908 partitioning support"
-+      depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
-+      default ARCH_BCM4908
-+      help
-+        This provides partitions parser for BCM4908 family devices
-+        that can have multiple "firmware" partitions. It takes care of
-+        finding currently used one and backup ones.
-+
- config MTD_PARSER_IMAGETAG
-       tristate "Parser for BCM963XX Image Tag format partitions"
-       depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
---- a/drivers/mtd/parsers/Makefile
-+++ b/drivers/mtd/parsers/Makefile
-@@ -5,6 +5,8 @@ obj-$(CONFIG_MTD_BCM63XX_PARTS)                += bcm6
- obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
- obj-$(CONFIG_MTD_MYLOADER_PARTS)              += myloader.o
- obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
-+ofpart-y                              += ofpart_core.o
-+ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
- obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
- obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
- obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
---- /dev/null
-+++ b/drivers/mtd/parsers/ofpart_bcm4908.c
-@@ -0,0 +1,66 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/of.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include "ofpart_bcm4908.h"
-+
-+#define BLPARAMS_FW_OFFSET            "NAND_RFS_OFS"
-+
-+static long long bcm4908_partitions_fw_offset(void)
-+{
-+      struct device_node *root;
-+      struct property *prop;
-+      const char *s;
-+
-+      root = of_find_node_by_path("/");
-+      if (!root)
-+              return -ENOENT;
-+
-+      of_property_for_each_string(root, "brcm_blparms", prop, s) {
-+              size_t len = strlen(BLPARAMS_FW_OFFSET);
-+              unsigned long offset;
-+              int err;
-+
-+              if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
-+                      continue;
-+
-+              err = kstrtoul(s + len + 1, 0, &offset);
-+              if (err) {
-+                      pr_err("failed to parse %s\n", s + len + 1);
-+                      return err;
-+              }
-+
-+              return offset << 10;
-+      }
-+
-+      return -ENOENT;
-+}
-+
-+int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
-+{
-+      long long fw_offset;
-+      int i;
-+
-+      fw_offset = bcm4908_partitions_fw_offset();
-+
-+      for (i = 0; i < nr_parts; i++) {
-+              if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
-+                      if (fw_offset < 0 || parts[i].offset == fw_offset)
-+                              parts[i].name = "firmware";
-+                      else
-+                              parts[i].name = "backup";
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/mtd/parsers/ofpart_bcm4908.h
-@@ -0,0 +1,15 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+#ifndef __BCM4908_PARTITIONS_H
-+#define __BCM4908_PARTITIONS_H
-+
-+#ifdef CONFIG_MTD_OF_PARTS_BCM4908
-+int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
-+#else
-+static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
-+                                              int nr_parts)
-+{
-+      return -EOPNOTSUPP;
-+}
-+#endif
-+
-+#endif
---- a/drivers/mtd/parsers/ofpart.c
-+++ /dev/null
-@@ -1,236 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Flash partitions described by the OF (or flattened) device tree
-- *
-- * Copyright © 2006 MontaVista Software Inc.
-- * Author: Vitaly Wool <vwool@ru.mvista.com>
-- *
-- * Revised to handle newer style flash binding by:
-- *   Copyright © 2007 David Gibson, IBM Corporation.
-- */
--
--#include <linux/module.h>
--#include <linux/init.h>
--#include <linux/of.h>
--#include <linux/mtd/mtd.h>
--#include <linux/slab.h>
--#include <linux/mtd/partitions.h>
--
--static bool node_has_compatible(struct device_node *pp)
--{
--      return of_get_property(pp, "compatible", NULL);
--}
--
--static int parse_fixed_partitions(struct mtd_info *master,
--                                const struct mtd_partition **pparts,
--                                struct mtd_part_parser_data *data)
--{
--      struct mtd_partition *parts;
--      struct device_node *mtd_node;
--      struct device_node *ofpart_node;
--      const char *partname;
--      struct device_node *pp;
--      int nr_parts, i, ret = 0;
--      bool dedicated = true;
--
--
--      /* Pull of_node from the master device node */
--      mtd_node = mtd_get_of_node(master);
--      if (!mtd_node)
--              return 0;
--
--      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
--      if (!ofpart_node) {
--              /*
--               * We might get here even when ofpart isn't used at all (e.g.,
--               * when using another parser), so don't be louder than
--               * KERN_DEBUG
--               */
--              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
--                       master->name, mtd_node);
--              ofpart_node = mtd_node;
--              dedicated = false;
--      } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
--              /* The 'partitions' subnode might be used by another parser */
--              return 0;
--      }
--
--      /* First count the subnodes */
--      nr_parts = 0;
--      for_each_child_of_node(ofpart_node,  pp) {
--              if (!dedicated && node_has_compatible(pp))
--                      continue;
--
--              nr_parts++;
--      }
--
--      if (nr_parts == 0)
--              return 0;
--
--      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
--      if (!parts)
--              return -ENOMEM;
--
--      i = 0;
--      for_each_child_of_node(ofpart_node,  pp) {
--              const __be32 *reg;
--              int len;
--              int a_cells, s_cells;
--
--              if (!dedicated && node_has_compatible(pp))
--                      continue;
--
--              reg = of_get_property(pp, "reg", &len);
--              if (!reg) {
--                      if (dedicated) {
--                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
--                                       master->name, pp,
--                                       mtd_node);
--                              goto ofpart_fail;
--                      } else {
--                              nr_parts--;
--                              continue;
--                      }
--              }
--
--              a_cells = of_n_addr_cells(pp);
--              s_cells = of_n_size_cells(pp);
--              if (len / 4 != a_cells + s_cells) {
--                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
--                               master->name, pp,
--                               mtd_node);
--                      goto ofpart_fail;
--              }
--
--              parts[i].offset = of_read_number(reg, a_cells);
--              parts[i].size = of_read_number(reg + a_cells, s_cells);
--              parts[i].of_node = pp;
--
--              partname = of_get_property(pp, "label", &len);
--              if (!partname)
--                      partname = of_get_property(pp, "name", &len);
--              parts[i].name = partname;
--
--              if (of_get_property(pp, "read-only", &len))
--                      parts[i].mask_flags |= MTD_WRITEABLE;
--
--              if (of_get_property(pp, "lock", &len))
--                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
--
--              i++;
--      }
--
--      if (!nr_parts)
--              goto ofpart_none;
--
--      *pparts = parts;
--      return nr_parts;
--
--ofpart_fail:
--      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
--             master->name, pp, mtd_node);
--      ret = -EINVAL;
--ofpart_none:
--      of_node_put(pp);
--      kfree(parts);
--      return ret;
--}
--
--static const struct of_device_id parse_ofpart_match_table[] = {
--      { .compatible = "fixed-partitions" },
--      {},
--};
--MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
--
--static struct mtd_part_parser ofpart_parser = {
--      .parse_fn = parse_fixed_partitions,
--      .name = "fixed-partitions",
--      .of_match_table = parse_ofpart_match_table,
--};
--
--static int parse_ofoldpart_partitions(struct mtd_info *master,
--                                    const struct mtd_partition **pparts,
--                                    struct mtd_part_parser_data *data)
--{
--      struct mtd_partition *parts;
--      struct device_node *dp;
--      int i, plen, nr_parts;
--      const struct {
--              __be32 offset, len;
--      } *part;
--      const char *names;
--
--      /* Pull of_node from the master device node */
--      dp = mtd_get_of_node(master);
--      if (!dp)
--              return 0;
--
--      part = of_get_property(dp, "partitions", &plen);
--      if (!part)
--              return 0; /* No partitions found */
--
--      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
--
--      nr_parts = plen / sizeof(part[0]);
--
--      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
--      if (!parts)
--              return -ENOMEM;
--
--      names = of_get_property(dp, "partition-names", &plen);
--
--      for (i = 0; i < nr_parts; i++) {
--              parts[i].offset = be32_to_cpu(part->offset);
--              parts[i].size   = be32_to_cpu(part->len) & ~1;
--              /* bit 0 set signifies read only partition */
--              if (be32_to_cpu(part->len) & 1)
--                      parts[i].mask_flags = MTD_WRITEABLE;
--
--              if (names && (plen > 0)) {
--                      int len = strlen(names) + 1;
--
--                      parts[i].name = names;
--                      plen -= len;
--                      names += len;
--              } else {
--                      parts[i].name = "unnamed";
--              }
--
--              part++;
--      }
--
--      *pparts = parts;
--      return nr_parts;
--}
--
--static struct mtd_part_parser ofoldpart_parser = {
--      .parse_fn = parse_ofoldpart_partitions,
--      .name = "ofoldpart",
--};
--
--static int __init ofpart_parser_init(void)
--{
--      register_mtd_parser(&ofpart_parser);
--      register_mtd_parser(&ofoldpart_parser);
--      return 0;
--}
--
--static void __exit ofpart_parser_exit(void)
--{
--      deregister_mtd_parser(&ofpart_parser);
--      deregister_mtd_parser(&ofoldpart_parser);
--}
--
--module_init(ofpart_parser_init);
--module_exit(ofpart_parser_exit);
--
--MODULE_LICENSE("GPL");
--MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
--MODULE_AUTHOR("Vitaly Wool, David Gibson");
--/*
-- * When MTD core cannot find the requested parser, it tries to load the module
-- * with the same name. Since we provide the ofoldpart parser, we should have
-- * the corresponding alias.
-- */
--MODULE_ALIAS("fixed-partitions");
--MODULE_ALIAS("ofoldpart");
---- /dev/null
-+++ b/drivers/mtd/parsers/ofpart_core.c
-@@ -0,0 +1,260 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Flash partitions described by the OF (or flattened) device tree
-+ *
-+ * Copyright © 2006 MontaVista Software Inc.
-+ * Author: Vitaly Wool <vwool@ru.mvista.com>
-+ *
-+ * Revised to handle newer style flash binding by:
-+ *   Copyright © 2007 David Gibson, IBM Corporation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/of.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/slab.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include "ofpart_bcm4908.h"
-+
-+struct fixed_partitions_quirks {
-+      int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
-+};
-+
-+struct fixed_partitions_quirks bcm4908_partitions_quirks = {
-+      .post_parse = bcm4908_partitions_post_parse,
-+};
-+
-+static const struct of_device_id parse_ofpart_match_table[];
-+
-+static bool node_has_compatible(struct device_node *pp)
-+{
-+      return of_get_property(pp, "compatible", NULL);
-+}
-+
-+static int parse_fixed_partitions(struct mtd_info *master,
-+                                const struct mtd_partition **pparts,
-+                                struct mtd_part_parser_data *data)
-+{
-+      const struct fixed_partitions_quirks *quirks;
-+      const struct of_device_id *of_id;
-+      struct mtd_partition *parts;
-+      struct device_node *mtd_node;
-+      struct device_node *ofpart_node;
-+      const char *partname;
-+      struct device_node *pp;
-+      int nr_parts, i, ret = 0;
-+      bool dedicated = true;
-+
-+      /* Pull of_node from the master device node */
-+      mtd_node = mtd_get_of_node(master);
-+      if (!mtd_node)
-+              return 0;
-+
-+      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
-+      if (!ofpart_node) {
-+              /*
-+               * We might get here even when ofpart isn't used at all (e.g.,
-+               * when using another parser), so don't be louder than
-+               * KERN_DEBUG
-+               */
-+              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
-+                       master->name, mtd_node);
-+              ofpart_node = mtd_node;
-+              dedicated = false;
-+      }
-+
-+      of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
-+      if (dedicated && !of_id) {
-+              /* The 'partitions' subnode might be used by another parser */
-+              return 0;
-+      }
-+
-+      quirks = of_id ? of_id->data : NULL;
-+
-+      /* First count the subnodes */
-+      nr_parts = 0;
-+      for_each_child_of_node(ofpart_node,  pp) {
-+              if (!dedicated && node_has_compatible(pp))
-+                      continue;
-+
-+              nr_parts++;
-+      }
-+
-+      if (nr_parts == 0)
-+              return 0;
-+
-+      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
-+      if (!parts)
-+              return -ENOMEM;
-+
-+      i = 0;
-+      for_each_child_of_node(ofpart_node,  pp) {
-+              const __be32 *reg;
-+              int len;
-+              int a_cells, s_cells;
-+
-+              if (!dedicated && node_has_compatible(pp))
-+                      continue;
-+
-+              reg = of_get_property(pp, "reg", &len);
-+              if (!reg) {
-+                      if (dedicated) {
-+                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
-+                                       master->name, pp,
-+                                       mtd_node);
-+                              goto ofpart_fail;
-+                      } else {
-+                              nr_parts--;
-+                              continue;
-+                      }
-+              }
-+
-+              a_cells = of_n_addr_cells(pp);
-+              s_cells = of_n_size_cells(pp);
-+              if (len / 4 != a_cells + s_cells) {
-+                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
-+                               master->name, pp,
-+                               mtd_node);
-+                      goto ofpart_fail;
-+              }
-+
-+              parts[i].offset = of_read_number(reg, a_cells);
-+              parts[i].size = of_read_number(reg + a_cells, s_cells);
-+              parts[i].of_node = pp;
-+
-+              partname = of_get_property(pp, "label", &len);
-+              if (!partname)
-+                      partname = of_get_property(pp, "name", &len);
-+              parts[i].name = partname;
-+
-+              if (of_get_property(pp, "read-only", &len))
-+                      parts[i].mask_flags |= MTD_WRITEABLE;
-+
-+              if (of_get_property(pp, "lock", &len))
-+                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
-+
-+              i++;
-+      }
-+
-+      if (!nr_parts)
-+              goto ofpart_none;
-+
-+      if (quirks && quirks->post_parse)
-+              quirks->post_parse(master, parts, nr_parts);
-+
-+      *pparts = parts;
-+      return nr_parts;
-+
-+ofpart_fail:
-+      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
-+             master->name, pp, mtd_node);
-+      ret = -EINVAL;
-+ofpart_none:
-+      of_node_put(pp);
-+      kfree(parts);
-+      return ret;
-+}
-+
-+static const struct of_device_id parse_ofpart_match_table[] = {
-+      /* Generic */
-+      { .compatible = "fixed-partitions" },
-+      /* Customized */
-+      { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
-+
-+static struct mtd_part_parser ofpart_parser = {
-+      .parse_fn = parse_fixed_partitions,
-+      .name = "fixed-partitions",
-+      .of_match_table = parse_ofpart_match_table,
-+};
-+
-+static int parse_ofoldpart_partitions(struct mtd_info *master,
-+                                    const struct mtd_partition **pparts,
-+                                    struct mtd_part_parser_data *data)
-+{
-+      struct mtd_partition *parts;
-+      struct device_node *dp;
-+      int i, plen, nr_parts;
-+      const struct {
-+              __be32 offset, len;
-+      } *part;
-+      const char *names;
-+
-+      /* Pull of_node from the master device node */
-+      dp = mtd_get_of_node(master);
-+      if (!dp)
-+              return 0;
-+
-+      part = of_get_property(dp, "partitions", &plen);
-+      if (!part)
-+              return 0; /* No partitions found */
-+
-+      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
-+
-+      nr_parts = plen / sizeof(part[0]);
-+
-+      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
-+      if (!parts)
-+              return -ENOMEM;
-+
-+      names = of_get_property(dp, "partition-names", &plen);
-+
-+      for (i = 0; i < nr_parts; i++) {
-+              parts[i].offset = be32_to_cpu(part->offset);
-+              parts[i].size   = be32_to_cpu(part->len) & ~1;
-+              /* bit 0 set signifies read only partition */
-+              if (be32_to_cpu(part->len) & 1)
-+                      parts[i].mask_flags = MTD_WRITEABLE;
-+
-+              if (names && (plen > 0)) {
-+                      int len = strlen(names) + 1;
-+
-+                      parts[i].name = names;
-+                      plen -= len;
-+                      names += len;
-+              } else {
-+                      parts[i].name = "unnamed";
-+              }
-+
-+              part++;
-+      }
-+
-+      *pparts = parts;
-+      return nr_parts;
-+}
-+
-+static struct mtd_part_parser ofoldpart_parser = {
-+      .parse_fn = parse_ofoldpart_partitions,
-+      .name = "ofoldpart",
-+};
-+
-+static int __init ofpart_parser_init(void)
-+{
-+      register_mtd_parser(&ofpart_parser);
-+      register_mtd_parser(&ofoldpart_parser);
-+      return 0;
-+}
-+
-+static void __exit ofpart_parser_exit(void)
-+{
-+      deregister_mtd_parser(&ofpart_parser);
-+      deregister_mtd_parser(&ofoldpart_parser);
-+}
-+
-+module_init(ofpart_parser_init);
-+module_exit(ofpart_parser_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
-+MODULE_AUTHOR("Vitaly Wool, David Gibson");
-+/*
-+ * When MTD core cannot find the requested parser, it tries to load the module
-+ * with the same name. Since we provide the ofoldpart parser, we should have
-+ * the corresponding alias.
-+ */
-+MODULE_ALIAS("fixed-partitions");
-+MODULE_ALIAS("ofoldpart");
diff --git a/target/linux/generic/pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/target/linux/generic/pending-5.10/401-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch
new file mode 100644 (file)
index 0000000..d389122
--- /dev/null
@@ -0,0 +1,654 @@
+From afbef8efb591792579c633a7c545f914c6165f82 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 11 Feb 2021 23:04:27 +0100
+Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some devices use fixed partitioning with some partitions requiring some
+extra logic. E.g. BCM4908 may have multiple firmware partitions but
+detecting currently used one requires checking bootloader parameters.
+
+To support such cases without duplicating a lot of code (without copying
+most of the ofpart.c code) support for post-parsing callback was added.
+
+BCM4908 support in ofpart can be enabled using config option and results
+in compiling & executing a specific callback. It simply reads offset of
+currently used firmware partition from the DT. Bootloader specifies it
+using the "brcm_blparms" property.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/mtd/parsers/Kconfig                   |  9 +++
+ drivers/mtd/parsers/Makefile                  |  2 +
+ drivers/mtd/parsers/ofpart_bcm4908.c          | 64 +++++++++++++++++++
+ drivers/mtd/parsers/ofpart_bcm4908.h          | 15 +++++
+ .../mtd/parsers/{ofpart.c => ofpart_core.c}   | 28 +++++++-
+ 5 files changed, 116 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h
+ rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%)
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -67,6 +67,15 @@ config MTD_OF_PARTS
+         flash memory node, as described in
+         Documentation/devicetree/bindings/mtd/partition.txt.
++config MTD_OF_PARTS_BCM4908
++      bool "BCM4908 partitioning support"
++      depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
++      default ARCH_BCM4908
++      help
++        This provides partitions parser for BCM4908 family devices
++        that can have multiple "firmware" partitions. It takes care of
++        finding currently used one and backup ones.
++
+ config MTD_PARSER_IMAGETAG
+       tristate "Parser for BCM963XX Image Tag format partitions"
+       depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -4,6 +4,8 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS)                += bcm4
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)               += bcm63xxpart.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
+ obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
++ofpart-y                              += ofpart_core.o
++ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.c
+@@ -0,0 +1,64 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++#define BLPARAMS_FW_OFFSET            "NAND_RFS_OFS"
++
++static long long bcm4908_partitions_fw_offset(void)
++{
++      struct device_node *root;
++      struct property *prop;
++      const char *s;
++
++      root = of_find_node_by_path("/");
++      if (!root)
++              return -ENOENT;
++
++      of_property_for_each_string(root, "brcm_blparms", prop, s) {
++              size_t len = strlen(BLPARAMS_FW_OFFSET);
++              unsigned long offset;
++              int err;
++
++              if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
++                      continue;
++
++              err = kstrtoul(s + len + 1, 0, &offset);
++              if (err) {
++                      pr_err("failed to parse %s\n", s + len + 1);
++                      return err;
++              }
++
++              return offset << 10;
++      }
++
++      return -ENOENT;
++}
++
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
++{
++      long long fw_offset;
++      int i;
++
++      fw_offset = bcm4908_partitions_fw_offset();
++
++      for (i = 0; i < nr_parts; i++) {
++              if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
++                      if (fw_offset < 0 || parts[i].offset == fw_offset)
++                              parts[i].name = "firmware";
++                      else
++                              parts[i].name = "backup";
++              }
++      }
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __BCM4908_PARTITIONS_H
++#define __BCM4908_PARTITIONS_H
++
++#ifdef CONFIG_MTD_OF_PARTS_BCM4908
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++#else
++static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
++                                              int nr_parts)
++{
++      return -EOPNOTSUPP;
++}
++#endif
++
++#endif
+--- a/drivers/mtd/parsers/ofpart.c
++++ /dev/null
+@@ -1,239 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Flash partitions described by the OF (or flattened) device tree
+- *
+- * Copyright © 2006 MontaVista Software Inc.
+- * Author: Vitaly Wool <vwool@ru.mvista.com>
+- *
+- * Revised to handle newer style flash binding by:
+- *   Copyright © 2007 David Gibson, IBM Corporation.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/of.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/partitions.h>
+-
+-static bool node_has_compatible(struct device_node *pp)
+-{
+-      return of_get_property(pp, "compatible", NULL);
+-}
+-
+-static int parse_fixed_partitions(struct mtd_info *master,
+-                                const struct mtd_partition **pparts,
+-                                struct mtd_part_parser_data *data)
+-{
+-      struct mtd_partition *parts;
+-      struct device_node *mtd_node;
+-      struct device_node *ofpart_node;
+-      const char *partname;
+-      struct device_node *pp;
+-      int nr_parts, i, ret = 0;
+-      bool dedicated = true;
+-
+-
+-      /* Pull of_node from the master device node */
+-      mtd_node = mtd_get_of_node(master);
+-      if (!mtd_node)
+-              return 0;
+-
+-      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+-      if (!ofpart_node) {
+-              /*
+-               * We might get here even when ofpart isn't used at all (e.g.,
+-               * when using another parser), so don't be louder than
+-               * KERN_DEBUG
+-               */
+-              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
+-                       master->name, mtd_node);
+-              ofpart_node = mtd_node;
+-              dedicated = false;
+-      } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
+-              /* The 'partitions' subnode might be used by another parser */
+-              return 0;
+-      }
+-
+-      /* First count the subnodes */
+-      nr_parts = 0;
+-      for_each_child_of_node(ofpart_node,  pp) {
+-              if (!dedicated && node_has_compatible(pp))
+-                      continue;
+-
+-              nr_parts++;
+-      }
+-
+-      if (nr_parts == 0)
+-              return 0;
+-
+-      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-      if (!parts)
+-              return -ENOMEM;
+-
+-      i = 0;
+-      for_each_child_of_node(ofpart_node,  pp) {
+-              const __be32 *reg;
+-              int len;
+-              int a_cells, s_cells;
+-
+-              if (!dedicated && node_has_compatible(pp))
+-                      continue;
+-
+-              reg = of_get_property(pp, "reg", &len);
+-              if (!reg) {
+-                      if (dedicated) {
+-                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
+-                                       master->name, pp,
+-                                       mtd_node);
+-                              goto ofpart_fail;
+-                      } else {
+-                              nr_parts--;
+-                              continue;
+-                      }
+-              }
+-
+-              a_cells = of_n_addr_cells(pp);
+-              s_cells = of_n_size_cells(pp);
+-              if (len / 4 != a_cells + s_cells) {
+-                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
+-                               master->name, pp,
+-                               mtd_node);
+-                      goto ofpart_fail;
+-              }
+-
+-              parts[i].offset = of_read_number(reg, a_cells);
+-              parts[i].size = of_read_number(reg + a_cells, s_cells);
+-              parts[i].of_node = pp;
+-
+-              partname = of_get_property(pp, "label", &len);
+-              if (!partname)
+-                      partname = of_get_property(pp, "name", &len);
+-              parts[i].name = partname;
+-
+-              if (of_get_property(pp, "read-only", &len))
+-                      parts[i].mask_flags |= MTD_WRITEABLE;
+-
+-              if (of_get_property(pp, "lock", &len))
+-                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
+-
+-              if (of_property_read_bool(pp, "slc-mode"))
+-                      parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION;
+-
+-              i++;
+-      }
+-
+-      if (!nr_parts)
+-              goto ofpart_none;
+-
+-      *pparts = parts;
+-      return nr_parts;
+-
+-ofpart_fail:
+-      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
+-             master->name, pp, mtd_node);
+-      ret = -EINVAL;
+-ofpart_none:
+-      of_node_put(pp);
+-      kfree(parts);
+-      return ret;
+-}
+-
+-static const struct of_device_id parse_ofpart_match_table[] = {
+-      { .compatible = "fixed-partitions" },
+-      {},
+-};
+-MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
+-
+-static struct mtd_part_parser ofpart_parser = {
+-      .parse_fn = parse_fixed_partitions,
+-      .name = "fixed-partitions",
+-      .of_match_table = parse_ofpart_match_table,
+-};
+-
+-static int parse_ofoldpart_partitions(struct mtd_info *master,
+-                                    const struct mtd_partition **pparts,
+-                                    struct mtd_part_parser_data *data)
+-{
+-      struct mtd_partition *parts;
+-      struct device_node *dp;
+-      int i, plen, nr_parts;
+-      const struct {
+-              __be32 offset, len;
+-      } *part;
+-      const char *names;
+-
+-      /* Pull of_node from the master device node */
+-      dp = mtd_get_of_node(master);
+-      if (!dp)
+-              return 0;
+-
+-      part = of_get_property(dp, "partitions", &plen);
+-      if (!part)
+-              return 0; /* No partitions found */
+-
+-      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
+-
+-      nr_parts = plen / sizeof(part[0]);
+-
+-      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-      if (!parts)
+-              return -ENOMEM;
+-
+-      names = of_get_property(dp, "partition-names", &plen);
+-
+-      for (i = 0; i < nr_parts; i++) {
+-              parts[i].offset = be32_to_cpu(part->offset);
+-              parts[i].size   = be32_to_cpu(part->len) & ~1;
+-              /* bit 0 set signifies read only partition */
+-              if (be32_to_cpu(part->len) & 1)
+-                      parts[i].mask_flags = MTD_WRITEABLE;
+-
+-              if (names && (plen > 0)) {
+-                      int len = strlen(names) + 1;
+-
+-                      parts[i].name = names;
+-                      plen -= len;
+-                      names += len;
+-              } else {
+-                      parts[i].name = "unnamed";
+-              }
+-
+-              part++;
+-      }
+-
+-      *pparts = parts;
+-      return nr_parts;
+-}
+-
+-static struct mtd_part_parser ofoldpart_parser = {
+-      .parse_fn = parse_ofoldpart_partitions,
+-      .name = "ofoldpart",
+-};
+-
+-static int __init ofpart_parser_init(void)
+-{
+-      register_mtd_parser(&ofpart_parser);
+-      register_mtd_parser(&ofoldpart_parser);
+-      return 0;
+-}
+-
+-static void __exit ofpart_parser_exit(void)
+-{
+-      deregister_mtd_parser(&ofpart_parser);
+-      deregister_mtd_parser(&ofoldpart_parser);
+-}
+-
+-module_init(ofpart_parser_init);
+-module_exit(ofpart_parser_exit);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
+-MODULE_AUTHOR("Vitaly Wool, David Gibson");
+-/*
+- * When MTD core cannot find the requested parser, it tries to load the module
+- * with the same name. Since we provide the ofoldpart parser, we should have
+- * the corresponding alias.
+- */
+-MODULE_ALIAS("fixed-partitions");
+-MODULE_ALIAS("ofoldpart");
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -0,0 +1,263 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Flash partitions described by the OF (or flattened) device tree
++ *
++ * Copyright © 2006 MontaVista Software Inc.
++ * Author: Vitaly Wool <vwool@ru.mvista.com>
++ *
++ * Revised to handle newer style flash binding by:
++ *   Copyright © 2007 David Gibson, IBM Corporation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++struct fixed_partitions_quirks {
++      int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++};
++
++struct fixed_partitions_quirks bcm4908_partitions_quirks = {
++      .post_parse = bcm4908_partitions_post_parse,
++};
++
++static const struct of_device_id parse_ofpart_match_table[];
++
++static bool node_has_compatible(struct device_node *pp)
++{
++      return of_get_property(pp, "compatible", NULL);
++}
++
++static int parse_fixed_partitions(struct mtd_info *master,
++                                const struct mtd_partition **pparts,
++                                struct mtd_part_parser_data *data)
++{
++      const struct fixed_partitions_quirks *quirks;
++      const struct of_device_id *of_id;
++      struct mtd_partition *parts;
++      struct device_node *mtd_node;
++      struct device_node *ofpart_node;
++      const char *partname;
++      struct device_node *pp;
++      int nr_parts, i, ret = 0;
++      bool dedicated = true;
++
++      /* Pull of_node from the master device node */
++      mtd_node = mtd_get_of_node(master);
++      if (!mtd_node)
++              return 0;
++
++      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++      if (!ofpart_node) {
++              /*
++               * We might get here even when ofpart isn't used at all (e.g.,
++               * when using another parser), so don't be louder than
++               * KERN_DEBUG
++               */
++              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
++                       master->name, mtd_node);
++              ofpart_node = mtd_node;
++              dedicated = false;
++      }
++
++      of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
++      if (dedicated && !of_id) {
++              /* The 'partitions' subnode might be used by another parser */
++              return 0;
++      }
++
++      quirks = of_id ? of_id->data : NULL;
++
++      /* First count the subnodes */
++      nr_parts = 0;
++      for_each_child_of_node(ofpart_node,  pp) {
++              if (!dedicated && node_has_compatible(pp))
++                      continue;
++
++              nr_parts++;
++      }
++
++      if (nr_parts == 0)
++              return 0;
++
++      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++      if (!parts)
++              return -ENOMEM;
++
++      i = 0;
++      for_each_child_of_node(ofpart_node,  pp) {
++              const __be32 *reg;
++              int len;
++              int a_cells, s_cells;
++
++              if (!dedicated && node_has_compatible(pp))
++                      continue;
++
++              reg = of_get_property(pp, "reg", &len);
++              if (!reg) {
++                      if (dedicated) {
++                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
++                                       master->name, pp,
++                                       mtd_node);
++                              goto ofpart_fail;
++                      } else {
++                              nr_parts--;
++                              continue;
++                      }
++              }
++
++              a_cells = of_n_addr_cells(pp);
++              s_cells = of_n_size_cells(pp);
++              if (len / 4 != a_cells + s_cells) {
++                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
++                               master->name, pp,
++                               mtd_node);
++                      goto ofpart_fail;
++              }
++
++              parts[i].offset = of_read_number(reg, a_cells);
++              parts[i].size = of_read_number(reg + a_cells, s_cells);
++              parts[i].of_node = pp;
++
++              partname = of_get_property(pp, "label", &len);
++              if (!partname)
++                      partname = of_get_property(pp, "name", &len);
++              parts[i].name = partname;
++
++              if (of_get_property(pp, "read-only", &len))
++                      parts[i].mask_flags |= MTD_WRITEABLE;
++
++              if (of_get_property(pp, "lock", &len))
++                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
++
++              if (of_property_read_bool(pp, "slc-mode"))
++                      parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION;
++
++              i++;
++      }
++
++      if (!nr_parts)
++              goto ofpart_none;
++
++      if (quirks && quirks->post_parse)
++              quirks->post_parse(master, parts, nr_parts);
++
++      *pparts = parts;
++      return nr_parts;
++
++ofpart_fail:
++      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
++             master->name, pp, mtd_node);
++      ret = -EINVAL;
++ofpart_none:
++      of_node_put(pp);
++      kfree(parts);
++      return ret;
++}
++
++static const struct of_device_id parse_ofpart_match_table[] = {
++      /* Generic */
++      { .compatible = "fixed-partitions" },
++      /* Customized */
++      { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
++      {},
++};
++MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
++
++static struct mtd_part_parser ofpart_parser = {
++      .parse_fn = parse_fixed_partitions,
++      .name = "fixed-partitions",
++      .of_match_table = parse_ofpart_match_table,
++};
++
++static int parse_ofoldpart_partitions(struct mtd_info *master,
++                                    const struct mtd_partition **pparts,
++                                    struct mtd_part_parser_data *data)
++{
++      struct mtd_partition *parts;
++      struct device_node *dp;
++      int i, plen, nr_parts;
++      const struct {
++              __be32 offset, len;
++      } *part;
++      const char *names;
++
++      /* Pull of_node from the master device node */
++      dp = mtd_get_of_node(master);
++      if (!dp)
++              return 0;
++
++      part = of_get_property(dp, "partitions", &plen);
++      if (!part)
++              return 0; /* No partitions found */
++
++      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
++
++      nr_parts = plen / sizeof(part[0]);
++
++      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++      if (!parts)
++              return -ENOMEM;
++
++      names = of_get_property(dp, "partition-names", &plen);
++
++      for (i = 0; i < nr_parts; i++) {
++              parts[i].offset = be32_to_cpu(part->offset);
++              parts[i].size   = be32_to_cpu(part->len) & ~1;
++              /* bit 0 set signifies read only partition */
++              if (be32_to_cpu(part->len) & 1)
++                      parts[i].mask_flags = MTD_WRITEABLE;
++
++              if (names && (plen > 0)) {
++                      int len = strlen(names) + 1;
++
++                      parts[i].name = names;
++                      plen -= len;
++                      names += len;
++              } else {
++                      parts[i].name = "unnamed";
++              }
++
++              part++;
++      }
++
++      *pparts = parts;
++      return nr_parts;
++}
++
++static struct mtd_part_parser ofoldpart_parser = {
++      .parse_fn = parse_ofoldpart_partitions,
++      .name = "ofoldpart",
++};
++
++static int __init ofpart_parser_init(void)
++{
++      register_mtd_parser(&ofpart_parser);
++      register_mtd_parser(&ofoldpart_parser);
++      return 0;
++}
++
++static void __exit ofpart_parser_exit(void)
++{
++      deregister_mtd_parser(&ofpart_parser);
++      deregister_mtd_parser(&ofoldpart_parser);
++}
++
++module_init(ofpart_parser_init);
++module_exit(ofpart_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
++MODULE_AUTHOR("Vitaly Wool, David Gibson");
++/*
++ * When MTD core cannot find the requested parser, it tries to load the module
++ * with the same name. Since we provide the ofoldpart parser, we should have
++ * the corresponding alias.
++ */
++MODULE_ALIAS("fixed-partitions");
++MODULE_ALIAS("ofoldpart");
index 5c00612d03c6563b64d7c3a5616588b66984378d..0889c9a343411082cbbba74db7d27b2d34fab93b 100644 (file)
@@ -41,8 +41,8 @@ Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
  obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
 +obj-$(CONFIG_MTD_MYLOADER_PARTS)              += myloader.o
  obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
- obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
- obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
+ ofpart-y                              += ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
 --- /dev/null
 +++ b/drivers/mtd/parsers/myloader.c
 @@ -0,0 +1,181 @@
index 1523e757c70aca723bd80d11d4c5bf3f50d48b02..7853cae3257e1ba5898b3fae4dd2885465e0681e 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
 
 --- a/drivers/mtd/parsers/Kconfig
 +++ b/drivers/mtd/parsers/Kconfig
-@@ -176,3 +176,12 @@ config MTD_REDBOOT_PARTS_READONLY
+@@ -185,3 +185,12 @@ config MTD_REDBOOT_PARTS_READONLY
          'FIS directory' images, enable this option.
  
  endif # MTD_REDBOOT_PARTS
@@ -31,7 +31,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
 +       formatted DTS.
 --- a/drivers/mtd/parsers/Makefile
 +++ b/drivers/mtd/parsers/Makefile
-@@ -10,3 +10,4 @@ obj-$(CONFIG_MTD_AFS_PARTS)          += afs.o
+@@ -12,3 +12,4 @@ obj-$(CONFIG_MTD_AFS_PARTS)          += afs.o
  obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
  obj-$(CONFIG_MTD_SHARPSL_PARTS)               += sharpslpart.o
  obj-$(CONFIG_MTD_REDBOOT_PARTS)               += redboot.o
diff --git a/target/linux/generic/pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/target/linux/generic/pending-5.4/404-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch
new file mode 100644 (file)
index 0000000..8f292bd
--- /dev/null
@@ -0,0 +1,648 @@
+From afbef8efb591792579c633a7c545f914c6165f82 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 11 Feb 2021 23:04:27 +0100
+Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some devices use fixed partitioning with some partitions requiring some
+extra logic. E.g. BCM4908 may have multiple firmware partitions but
+detecting currently used one requires checking bootloader parameters.
+
+To support such cases without duplicating a lot of code (without copying
+most of the ofpart.c code) support for post-parsing callback was added.
+
+BCM4908 support in ofpart can be enabled using config option and results
+in compiling & executing a specific callback. It simply reads offset of
+currently used firmware partition from the DT. Bootloader specifies it
+using the "brcm_blparms" property.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/mtd/parsers/Kconfig                   |  9 +++
+ drivers/mtd/parsers/Makefile                  |  2 +
+ drivers/mtd/parsers/ofpart_bcm4908.c          | 64 +++++++++++++++++++
+ drivers/mtd/parsers/ofpart_bcm4908.h          | 15 +++++
+ .../mtd/parsers/{ofpart.c => ofpart_core.c}   | 28 +++++++-
+ 5 files changed, 116 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h
+ rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%)
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -67,6 +67,15 @@ config MTD_OF_PARTS
+         flash memory node, as described in
+         Documentation/devicetree/bindings/mtd/partition.txt.
++config MTD_OF_PARTS_BCM4908
++      bool "BCM4908 partitioning support"
++      depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
++      default ARCH_BCM4908
++      help
++        This provides partitions parser for BCM4908 family devices
++        that can have multiple "firmware" partitions. It takes care of
++        finding currently used one and backup ones.
++
+ config MTD_PARSER_IMAGETAG
+       tristate "Parser for BCM963XX Image Tag format partitions"
+       depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -4,6 +4,8 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS)                += bcm4
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)               += bcm63xxpart.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
+ obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
++ofpart-y                              += ofpart_core.o
++ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.c
+@@ -0,0 +1,64 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++#define BLPARAMS_FW_OFFSET            "NAND_RFS_OFS"
++
++static long long bcm4908_partitions_fw_offset(void)
++{
++      struct device_node *root;
++      struct property *prop;
++      const char *s;
++
++      root = of_find_node_by_path("/");
++      if (!root)
++              return -ENOENT;
++
++      of_property_for_each_string(root, "brcm_blparms", prop, s) {
++              size_t len = strlen(BLPARAMS_FW_OFFSET);
++              unsigned long offset;
++              int err;
++
++              if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
++                      continue;
++
++              err = kstrtoul(s + len + 1, 0, &offset);
++              if (err) {
++                      pr_err("failed to parse %s\n", s + len + 1);
++                      return err;
++              }
++
++              return offset << 10;
++      }
++
++      return -ENOENT;
++}
++
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
++{
++      long long fw_offset;
++      int i;
++
++      fw_offset = bcm4908_partitions_fw_offset();
++
++      for (i = 0; i < nr_parts; i++) {
++              if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
++                      if (fw_offset < 0 || parts[i].offset == fw_offset)
++                              parts[i].name = "firmware";
++                      else
++                              parts[i].name = "backup";
++              }
++      }
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __BCM4908_PARTITIONS_H
++#define __BCM4908_PARTITIONS_H
++
++#ifdef CONFIG_MTD_OF_PARTS_BCM4908
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++#else
++static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
++                                              int nr_parts)
++{
++      return -EOPNOTSUPP;
++}
++#endif
++
++#endif
+--- a/drivers/mtd/parsers/ofpart.c
++++ /dev/null
+@@ -1,236 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Flash partitions described by the OF (or flattened) device tree
+- *
+- * Copyright © 2006 MontaVista Software Inc.
+- * Author: Vitaly Wool <vwool@ru.mvista.com>
+- *
+- * Revised to handle newer style flash binding by:
+- *   Copyright © 2007 David Gibson, IBM Corporation.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/of.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/partitions.h>
+-
+-static bool node_has_compatible(struct device_node *pp)
+-{
+-      return of_get_property(pp, "compatible", NULL);
+-}
+-
+-static int parse_fixed_partitions(struct mtd_info *master,
+-                                const struct mtd_partition **pparts,
+-                                struct mtd_part_parser_data *data)
+-{
+-      struct mtd_partition *parts;
+-      struct device_node *mtd_node;
+-      struct device_node *ofpart_node;
+-      const char *partname;
+-      struct device_node *pp;
+-      int nr_parts, i, ret = 0;
+-      bool dedicated = true;
+-
+-
+-      /* Pull of_node from the master device node */
+-      mtd_node = mtd_get_of_node(master);
+-      if (!mtd_node)
+-              return 0;
+-
+-      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+-      if (!ofpart_node) {
+-              /*
+-               * We might get here even when ofpart isn't used at all (e.g.,
+-               * when using another parser), so don't be louder than
+-               * KERN_DEBUG
+-               */
+-              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
+-                       master->name, mtd_node);
+-              ofpart_node = mtd_node;
+-              dedicated = false;
+-      } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
+-              /* The 'partitions' subnode might be used by another parser */
+-              return 0;
+-      }
+-
+-      /* First count the subnodes */
+-      nr_parts = 0;
+-      for_each_child_of_node(ofpart_node,  pp) {
+-              if (!dedicated && node_has_compatible(pp))
+-                      continue;
+-
+-              nr_parts++;
+-      }
+-
+-      if (nr_parts == 0)
+-              return 0;
+-
+-      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-      if (!parts)
+-              return -ENOMEM;
+-
+-      i = 0;
+-      for_each_child_of_node(ofpart_node,  pp) {
+-              const __be32 *reg;
+-              int len;
+-              int a_cells, s_cells;
+-
+-              if (!dedicated && node_has_compatible(pp))
+-                      continue;
+-
+-              reg = of_get_property(pp, "reg", &len);
+-              if (!reg) {
+-                      if (dedicated) {
+-                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
+-                                       master->name, pp,
+-                                       mtd_node);
+-                              goto ofpart_fail;
+-                      } else {
+-                              nr_parts--;
+-                              continue;
+-                      }
+-              }
+-
+-              a_cells = of_n_addr_cells(pp);
+-              s_cells = of_n_size_cells(pp);
+-              if (len / 4 != a_cells + s_cells) {
+-                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
+-                               master->name, pp,
+-                               mtd_node);
+-                      goto ofpart_fail;
+-              }
+-
+-              parts[i].offset = of_read_number(reg, a_cells);
+-              parts[i].size = of_read_number(reg + a_cells, s_cells);
+-              parts[i].of_node = pp;
+-
+-              partname = of_get_property(pp, "label", &len);
+-              if (!partname)
+-                      partname = of_get_property(pp, "name", &len);
+-              parts[i].name = partname;
+-
+-              if (of_get_property(pp, "read-only", &len))
+-                      parts[i].mask_flags |= MTD_WRITEABLE;
+-
+-              if (of_get_property(pp, "lock", &len))
+-                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
+-
+-              i++;
+-      }
+-
+-      if (!nr_parts)
+-              goto ofpart_none;
+-
+-      *pparts = parts;
+-      return nr_parts;
+-
+-ofpart_fail:
+-      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
+-             master->name, pp, mtd_node);
+-      ret = -EINVAL;
+-ofpart_none:
+-      of_node_put(pp);
+-      kfree(parts);
+-      return ret;
+-}
+-
+-static const struct of_device_id parse_ofpart_match_table[] = {
+-      { .compatible = "fixed-partitions" },
+-      {},
+-};
+-MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
+-
+-static struct mtd_part_parser ofpart_parser = {
+-      .parse_fn = parse_fixed_partitions,
+-      .name = "fixed-partitions",
+-      .of_match_table = parse_ofpart_match_table,
+-};
+-
+-static int parse_ofoldpart_partitions(struct mtd_info *master,
+-                                    const struct mtd_partition **pparts,
+-                                    struct mtd_part_parser_data *data)
+-{
+-      struct mtd_partition *parts;
+-      struct device_node *dp;
+-      int i, plen, nr_parts;
+-      const struct {
+-              __be32 offset, len;
+-      } *part;
+-      const char *names;
+-
+-      /* Pull of_node from the master device node */
+-      dp = mtd_get_of_node(master);
+-      if (!dp)
+-              return 0;
+-
+-      part = of_get_property(dp, "partitions", &plen);
+-      if (!part)
+-              return 0; /* No partitions found */
+-
+-      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
+-
+-      nr_parts = plen / sizeof(part[0]);
+-
+-      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-      if (!parts)
+-              return -ENOMEM;
+-
+-      names = of_get_property(dp, "partition-names", &plen);
+-
+-      for (i = 0; i < nr_parts; i++) {
+-              parts[i].offset = be32_to_cpu(part->offset);
+-              parts[i].size   = be32_to_cpu(part->len) & ~1;
+-              /* bit 0 set signifies read only partition */
+-              if (be32_to_cpu(part->len) & 1)
+-                      parts[i].mask_flags = MTD_WRITEABLE;
+-
+-              if (names && (plen > 0)) {
+-                      int len = strlen(names) + 1;
+-
+-                      parts[i].name = names;
+-                      plen -= len;
+-                      names += len;
+-              } else {
+-                      parts[i].name = "unnamed";
+-              }
+-
+-              part++;
+-      }
+-
+-      *pparts = parts;
+-      return nr_parts;
+-}
+-
+-static struct mtd_part_parser ofoldpart_parser = {
+-      .parse_fn = parse_ofoldpart_partitions,
+-      .name = "ofoldpart",
+-};
+-
+-static int __init ofpart_parser_init(void)
+-{
+-      register_mtd_parser(&ofpart_parser);
+-      register_mtd_parser(&ofoldpart_parser);
+-      return 0;
+-}
+-
+-static void __exit ofpart_parser_exit(void)
+-{
+-      deregister_mtd_parser(&ofpart_parser);
+-      deregister_mtd_parser(&ofoldpart_parser);
+-}
+-
+-module_init(ofpart_parser_init);
+-module_exit(ofpart_parser_exit);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
+-MODULE_AUTHOR("Vitaly Wool, David Gibson");
+-/*
+- * When MTD core cannot find the requested parser, it tries to load the module
+- * with the same name. Since we provide the ofoldpart parser, we should have
+- * the corresponding alias.
+- */
+-MODULE_ALIAS("fixed-partitions");
+-MODULE_ALIAS("ofoldpart");
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -0,0 +1,260 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Flash partitions described by the OF (or flattened) device tree
++ *
++ * Copyright © 2006 MontaVista Software Inc.
++ * Author: Vitaly Wool <vwool@ru.mvista.com>
++ *
++ * Revised to handle newer style flash binding by:
++ *   Copyright © 2007 David Gibson, IBM Corporation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++struct fixed_partitions_quirks {
++      int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++};
++
++struct fixed_partitions_quirks bcm4908_partitions_quirks = {
++      .post_parse = bcm4908_partitions_post_parse,
++};
++
++static const struct of_device_id parse_ofpart_match_table[];
++
++static bool node_has_compatible(struct device_node *pp)
++{
++      return of_get_property(pp, "compatible", NULL);
++}
++
++static int parse_fixed_partitions(struct mtd_info *master,
++                                const struct mtd_partition **pparts,
++                                struct mtd_part_parser_data *data)
++{
++      const struct fixed_partitions_quirks *quirks;
++      const struct of_device_id *of_id;
++      struct mtd_partition *parts;
++      struct device_node *mtd_node;
++      struct device_node *ofpart_node;
++      const char *partname;
++      struct device_node *pp;
++      int nr_parts, i, ret = 0;
++      bool dedicated = true;
++
++      /* Pull of_node from the master device node */
++      mtd_node = mtd_get_of_node(master);
++      if (!mtd_node)
++              return 0;
++
++      ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++      if (!ofpart_node) {
++              /*
++               * We might get here even when ofpart isn't used at all (e.g.,
++               * when using another parser), so don't be louder than
++               * KERN_DEBUG
++               */
++              pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
++                       master->name, mtd_node);
++              ofpart_node = mtd_node;
++              dedicated = false;
++      }
++
++      of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
++      if (dedicated && !of_id) {
++              /* The 'partitions' subnode might be used by another parser */
++              return 0;
++      }
++
++      quirks = of_id ? of_id->data : NULL;
++
++      /* First count the subnodes */
++      nr_parts = 0;
++      for_each_child_of_node(ofpart_node,  pp) {
++              if (!dedicated && node_has_compatible(pp))
++                      continue;
++
++              nr_parts++;
++      }
++
++      if (nr_parts == 0)
++              return 0;
++
++      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++      if (!parts)
++              return -ENOMEM;
++
++      i = 0;
++      for_each_child_of_node(ofpart_node,  pp) {
++              const __be32 *reg;
++              int len;
++              int a_cells, s_cells;
++
++              if (!dedicated && node_has_compatible(pp))
++                      continue;
++
++              reg = of_get_property(pp, "reg", &len);
++              if (!reg) {
++                      if (dedicated) {
++                              pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
++                                       master->name, pp,
++                                       mtd_node);
++                              goto ofpart_fail;
++                      } else {
++                              nr_parts--;
++                              continue;
++                      }
++              }
++
++              a_cells = of_n_addr_cells(pp);
++              s_cells = of_n_size_cells(pp);
++              if (len / 4 != a_cells + s_cells) {
++                      pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
++                               master->name, pp,
++                               mtd_node);
++                      goto ofpart_fail;
++              }
++
++              parts[i].offset = of_read_number(reg, a_cells);
++              parts[i].size = of_read_number(reg + a_cells, s_cells);
++              parts[i].of_node = pp;
++
++              partname = of_get_property(pp, "label", &len);
++              if (!partname)
++                      partname = of_get_property(pp, "name", &len);
++              parts[i].name = partname;
++
++              if (of_get_property(pp, "read-only", &len))
++                      parts[i].mask_flags |= MTD_WRITEABLE;
++
++              if (of_get_property(pp, "lock", &len))
++                      parts[i].mask_flags |= MTD_POWERUP_LOCK;
++
++              i++;
++      }
++
++      if (!nr_parts)
++              goto ofpart_none;
++
++      if (quirks && quirks->post_parse)
++              quirks->post_parse(master, parts, nr_parts);
++
++      *pparts = parts;
++      return nr_parts;
++
++ofpart_fail:
++      pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
++             master->name, pp, mtd_node);
++      ret = -EINVAL;
++ofpart_none:
++      of_node_put(pp);
++      kfree(parts);
++      return ret;
++}
++
++static const struct of_device_id parse_ofpart_match_table[] = {
++      /* Generic */
++      { .compatible = "fixed-partitions" },
++      /* Customized */
++      { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
++      {},
++};
++MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
++
++static struct mtd_part_parser ofpart_parser = {
++      .parse_fn = parse_fixed_partitions,
++      .name = "fixed-partitions",
++      .of_match_table = parse_ofpart_match_table,
++};
++
++static int parse_ofoldpart_partitions(struct mtd_info *master,
++                                    const struct mtd_partition **pparts,
++                                    struct mtd_part_parser_data *data)
++{
++      struct mtd_partition *parts;
++      struct device_node *dp;
++      int i, plen, nr_parts;
++      const struct {
++              __be32 offset, len;
++      } *part;
++      const char *names;
++
++      /* Pull of_node from the master device node */
++      dp = mtd_get_of_node(master);
++      if (!dp)
++              return 0;
++
++      part = of_get_property(dp, "partitions", &plen);
++      if (!part)
++              return 0; /* No partitions found */
++
++      pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
++
++      nr_parts = plen / sizeof(part[0]);
++
++      parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++      if (!parts)
++              return -ENOMEM;
++
++      names = of_get_property(dp, "partition-names", &plen);
++
++      for (i = 0; i < nr_parts; i++) {
++              parts[i].offset = be32_to_cpu(part->offset);
++              parts[i].size   = be32_to_cpu(part->len) & ~1;
++              /* bit 0 set signifies read only partition */
++              if (be32_to_cpu(part->len) & 1)
++                      parts[i].mask_flags = MTD_WRITEABLE;
++
++              if (names && (plen > 0)) {
++                      int len = strlen(names) + 1;
++
++                      parts[i].name = names;
++                      plen -= len;
++                      names += len;
++              } else {
++                      parts[i].name = "unnamed";
++              }
++
++              part++;
++      }
++
++      *pparts = parts;
++      return nr_parts;
++}
++
++static struct mtd_part_parser ofoldpart_parser = {
++      .parse_fn = parse_ofoldpart_partitions,
++      .name = "ofoldpart",
++};
++
++static int __init ofpart_parser_init(void)
++{
++      register_mtd_parser(&ofpart_parser);
++      register_mtd_parser(&ofoldpart_parser);
++      return 0;
++}
++
++static void __exit ofpart_parser_exit(void)
++{
++      deregister_mtd_parser(&ofpart_parser);
++      deregister_mtd_parser(&ofoldpart_parser);
++}
++
++module_init(ofpart_parser_init);
++module_exit(ofpart_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
++MODULE_AUTHOR("Vitaly Wool, David Gibson");
++/*
++ * When MTD core cannot find the requested parser, it tries to load the module
++ * with the same name. Since we provide the ofoldpart parser, we should have
++ * the corresponding alias.
++ */
++MODULE_ALIAS("fixed-partitions");
++MODULE_ALIAS("ofoldpart");
index 9600dfc67acf1a48d595a6585a1e04e63b3a1172..3319ed94c2d885c54d23fd2f1e725e18e1dbb64b 100644 (file)
@@ -41,8 +41,8 @@ Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
  obj-$(CONFIG_MTD_CMDLINE_PARTS)               += cmdlinepart.o
 +obj-$(CONFIG_MTD_MYLOADER_PARTS)              += myloader.o
  obj-$(CONFIG_MTD_OF_PARTS)            += ofpart.o
- obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
- obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
+ ofpart-y                              += ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
 --- /dev/null
 +++ b/drivers/mtd/parsers/myloader.c
 @@ -0,0 +1,181 @@
index 1523e757c70aca723bd80d11d4c5bf3f50d48b02..7853cae3257e1ba5898b3fae4dd2885465e0681e 100644 (file)
@@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
 
 --- a/drivers/mtd/parsers/Kconfig
 +++ b/drivers/mtd/parsers/Kconfig
-@@ -176,3 +176,12 @@ config MTD_REDBOOT_PARTS_READONLY
+@@ -185,3 +185,12 @@ config MTD_REDBOOT_PARTS_READONLY
          'FIS directory' images, enable this option.
  
  endif # MTD_REDBOOT_PARTS
@@ -31,7 +31,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
 +       formatted DTS.
 --- a/drivers/mtd/parsers/Makefile
 +++ b/drivers/mtd/parsers/Makefile
-@@ -10,3 +10,4 @@ obj-$(CONFIG_MTD_AFS_PARTS)          += afs.o
+@@ -12,3 +12,4 @@ obj-$(CONFIG_MTD_AFS_PARTS)          += afs.o
  obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
  obj-$(CONFIG_MTD_SHARPSL_PARTS)               += sharpslpart.o
  obj-$(CONFIG_MTD_REDBOOT_PARTS)               += redboot.o
index 6aa404c8c5a37ad7adbf12af3ec12d8010a80b1b..0b54e0772e99f431e80004881ff31283e616ae31 100644 (file)
@@ -18,7 +18,7 @@ Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
 
 --- a/drivers/mtd/parsers/Kconfig
 +++ b/drivers/mtd/parsers/Kconfig
-@@ -119,6 +119,13 @@ config MTD_PARSER_TRX
+@@ -128,6 +128,13 @@ config MTD_PARSER_TRX
          This driver will parse TRX header and report at least two partitions:
          kernel and rootfs.
  
@@ -34,7 +34,7 @@ Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
        depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST
 --- a/drivers/mtd/parsers/Makefile
 +++ b/drivers/mtd/parsers/Makefile
-@@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_OF_PARTS)             += ofpart.o
+@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)        +=
  obj-$(CONFIG_MTD_PARSER_IMAGETAG)     += parser_imagetag.o
  obj-$(CONFIG_MTD_AFS_PARTS)           += afs.o
  obj-$(CONFIG_MTD_PARSER_TRX)          += parser_trx.o
index 18c03efa8f43ebb46c5939b4e94e340ac73384d3..2d1f769e968ff842f7870c214aae78f5470c926f 100644 (file)
@@ -3,9 +3,9 @@ Dynamically rename the active partition to "ubi".
 
 Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
 ---
---- a/drivers/mtd/parsers/ofpart.c
-+++ b/drivers/mtd/parsers/ofpart.c
-@@ -21,6 +21,8 @@ static bool node_has_compatible(struct d
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
        return of_get_property(pp, "compatible", NULL);
  }
  
@@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
  static int parse_fixed_partitions(struct mtd_info *master,
                                  const struct mtd_partition **pparts,
                                  struct mtd_part_parser_data *data)
-@@ -28,6 +30,7 @@ static int parse_fixed_partitions(struct
+@@ -42,6 +44,7 @@ static int parse_fixed_partitions(struct
        struct mtd_partition *parts;
        struct device_node *mtd_node;
        struct device_node *ofpart_node;
@@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
        const char *partname;
        struct device_node *pp;
        int nr_parts, i, ret = 0;
-@@ -106,9 +109,15 @@ static int parse_fixed_partitions(struct
+@@ -124,9 +127,15 @@ static int parse_fixed_partitions(struct
                parts[i].size = of_read_number(reg + a_cells, s_cells);
                parts[i].of_node = pp;
  
@@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
                parts[i].name = partname;
  
                if (of_get_property(pp, "read-only", &len))
-@@ -218,6 +227,18 @@ static int __init ofpart_parser_init(voi
+@@ -242,6 +251,18 @@ static int __init ofpart_parser_init(voi
        return 0;
  }
  
index b7e7f50271fefc7a905fb23b87395a815b98159f..cc35583b984ec3ebb739d38661b8d22d7e7a61d3 100644 (file)
@@ -3,9 +3,9 @@ Dynamically rename the active partition to "ubi".
 
 Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
 ---
---- a/drivers/mtd/parsers/ofpart.c
-+++ b/drivers/mtd/parsers/ofpart.c
-@@ -21,6 +21,8 @@ static bool node_has_compatible(struct d
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
        return of_get_property(pp, "compatible", NULL);
  }
  
@@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
  static int parse_fixed_partitions(struct mtd_info *master,
                                  const struct mtd_partition **pparts,
                                  struct mtd_part_parser_data *data)
-@@ -28,6 +30,7 @@ static int parse_fixed_partitions(struct
+@@ -42,6 +44,7 @@ static int parse_fixed_partitions(struct
        struct mtd_partition *parts;
        struct device_node *mtd_node;
        struct device_node *ofpart_node;
@@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
        const char *partname;
        struct device_node *pp;
        int nr_parts, i, ret = 0;
-@@ -106,9 +109,15 @@ static int parse_fixed_partitions(struct
+@@ -124,9 +127,15 @@ static int parse_fixed_partitions(struct
                parts[i].size = of_read_number(reg + a_cells, s_cells);
                parts[i].of_node = pp;
  
@@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
                parts[i].name = partname;
  
                if (of_get_property(pp, "read-only", &len))
-@@ -215,6 +224,18 @@ static int __init ofpart_parser_init(voi
+@@ -239,6 +248,18 @@ static int __init ofpart_parser_init(voi
        return 0;
  }
  
index b6b4ab7409fde6cf005909d43c45fdf85a89f06b..d541cc247cb08f07a10d70e785dd07f34f02f460 100644 (file)
@@ -1,6 +1,6 @@
---- a/drivers/mtd/parsers/ofpart.c
-+++ b/drivers/mtd/parsers/ofpart.c
-@@ -21,6 +21,38 @@ static bool node_has_compatible(struct d
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -33,6 +33,38 @@ static bool node_has_compatible(struct d
        return of_get_property(pp, "compatible", NULL);
  }
  
  static int parse_fixed_partitions(struct mtd_info *master,
                                  const struct mtd_partition **pparts,
                                  struct mtd_part_parser_data *data)
-@@ -32,7 +64,8 @@ static int parse_fixed_partitions(struct
+@@ -46,6 +78,8 @@ static int parse_fixed_partitions(struct
        struct device_node *pp;
        int nr_parts, i, ret = 0;
        bool dedicated = true;
--
 +      uint8_t *proot_id = NULL;
 +      struct device_node **part_nodes;
  
        /* Pull of_node from the master device node */
        mtd_node = mtd_get_of_node(master);
-@@ -68,7 +101,9 @@ static int parse_fixed_partitions(struct
+@@ -86,7 +120,9 @@ static int parse_fixed_partitions(struct
                return 0;
  
        parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
@@ -60,7 +59,7 @@
                return -ENOMEM;
  
        i = 0;
-@@ -117,12 +152,22 @@ static int parse_fixed_partitions(struct
+@@ -135,6 +171,11 @@ static int parse_fixed_partitions(struct
                if (of_get_property(pp, "lock", &len))
                        parts[i].mask_flags |= MTD_POWERUP_LOCK;
  
@@ -72,8 +71,9 @@
                i++;
        }
  
-       if (!nr_parts)
-               goto ofpart_none;
+@@ -144,6 +185,11 @@ static int parse_fixed_partitions(struct
+       if (quirks && quirks->post_parse)
+               quirks->post_parse(master, parts, nr_parts);
  
 +      if (proot_id)
 +              brnboot_set_active_root_part(parts, part_nodes, nr_parts, proot_id);
@@ -83,7 +83,7 @@
        *pparts = parts;
        return nr_parts;
  
-@@ -133,6 +178,7 @@ ofpart_fail:
+@@ -154,6 +200,7 @@ ofpart_fail:
  ofpart_none:
        of_node_put(pp);
        kfree(parts);
index f61d85bc05b494095cc800dea19031e0982a5af9..9df99d69ae678c1ea265806d41906d5943494a9f 100644 (file)
@@ -3,9 +3,9 @@ Dynamically rename the active partition to "ubi".
 
 Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
 
---- a/drivers/mtd/parsers/ofpart.c
-+++ b/drivers/mtd/parsers/ofpart.c
-@@ -21,6 +21,8 @@ static bool node_has_compatible(struct d
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
        return of_get_property(pp, "compatible", NULL);
  }
  
@@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
  static int parse_fixed_partitions(struct mtd_info *master,
                                  const struct mtd_partition **pparts,
                                  struct mtd_part_parser_data *data)
-@@ -29,6 +31,7 @@ static int parse_fixed_partitions(struct
+@@ -43,6 +45,7 @@ static int parse_fixed_partitions(struct
        struct device_node *mtd_node;
        struct device_node *ofpart_node;
        const char *partname;
@@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
        struct device_node *pp;
        int nr_parts, i, ret = 0;
        bool dedicated = true;
-@@ -106,9 +109,13 @@ static int parse_fixed_partitions(struct
+@@ -124,9 +127,13 @@ static int parse_fixed_partitions(struct
                parts[i].size = of_read_number(reg + a_cells, s_cells);
                parts[i].of_node = pp;
  
@@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
                parts[i].name = partname;
  
                if (of_get_property(pp, "read-only", &len))
-@@ -218,6 +225,18 @@ static int __init ofpart_parser_init(voi
+@@ -242,6 +249,18 @@ static int __init ofpart_parser_init(voi
        return 0;
  }
  
index 854031b0d51a37d199856941a42cde0d5f237fe1..8475bec925cc40fb97bd5ce567613154a6a1f052 100644 (file)
@@ -3,9 +3,9 @@ Dynamically rename the active partition to "ubi".
 
 Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
 
---- a/drivers/mtd/parsers/ofpart.c
-+++ b/drivers/mtd/parsers/ofpart.c
-@@ -21,6 +21,8 @@ static bool node_has_compatible(struct d
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
        return of_get_property(pp, "compatible", NULL);
  }
  
@@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
  static int parse_fixed_partitions(struct mtd_info *master,
                                  const struct mtd_partition **pparts,
                                  struct mtd_part_parser_data *data)
-@@ -29,6 +31,7 @@ static int parse_fixed_partitions(struct
+@@ -43,6 +45,7 @@ static int parse_fixed_partitions(struct
        struct device_node *mtd_node;
        struct device_node *ofpart_node;
        const char *partname;
@@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
        struct device_node *pp;
        int nr_parts, i, ret = 0;
        bool dedicated = true;
-@@ -106,9 +109,13 @@ static int parse_fixed_partitions(struct
+@@ -124,9 +127,13 @@ static int parse_fixed_partitions(struct
                parts[i].size = of_read_number(reg + a_cells, s_cells);
                parts[i].of_node = pp;
  
@@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
                parts[i].name = partname;
  
                if (of_get_property(pp, "read-only", &len))
-@@ -215,6 +222,18 @@ static int __init ofpart_parser_init(voi
+@@ -239,6 +246,18 @@ static int __init ofpart_parser_init(voi
        return 0;
  }