#include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/err.h>
+#include <linux/of.h>
 
 #include "mtdcore.h"
 
        return ret;
 }
 
+/**
+ * mtd_part_get_compatible_parser - find MTD parser by a compatible string
+ *
+ * @compat: compatible string describing partitions in a device tree
+ *
+ * MTD parsers can specify supported partitions by providing a table of
+ * compatibility strings. This function finds a parser that advertises support
+ * for a passed value of "compatible".
+ */
+static struct mtd_part_parser *mtd_part_get_compatible_parser(const char *compat)
+{
+       struct mtd_part_parser *p, *ret = NULL;
+
+       spin_lock(&part_parser_lock);
+
+       list_for_each_entry(p, &part_parsers, list) {
+               const struct of_device_id *matches;
+
+               matches = p->of_match_table;
+               if (!matches)
+                       continue;
+
+               for (; matches->compatible[0]; matches++) {
+                       if (!strcmp(matches->compatible, compat) &&
+                           try_module_get(p->owner)) {
+                               ret = p;
+                               break;
+                       }
+               }
+
+               if (ret)
+                       break;
+       }
+
+       spin_unlock(&part_parser_lock);
+
+       return ret;
+}
+
+static int mtd_part_of_parse(struct mtd_info *master,
+                            struct mtd_partitions *pparts)
+{
+       struct mtd_part_parser *parser;
+       struct device_node *np;
+       struct property *prop;
+       const char *compat;
+       const char *fixed = "ofpart";
+       int ret, err = 0;
+
+       np = of_get_child_by_name(mtd_get_of_node(master), "partitions");
+       of_property_for_each_string(np, "compatible", prop, compat) {
+               parser = mtd_part_get_compatible_parser(compat);
+               if (!parser)
+                       continue;
+               ret = mtd_part_do_parse(parser, master, pparts, NULL);
+               if (ret > 0) {
+                       of_node_put(np);
+                       return ret;
+               }
+               mtd_part_parser_put(parser);
+               if (ret < 0 && !err)
+                       err = ret;
+       }
+       of_node_put(np);
+
+       /*
+        * For backward compatibility we have to try the "ofpart"
+        * parser. It supports old DT format with partitions specified as a
+        * direct subnodes of a flash device DT node without any compatibility
+        * specified we could match.
+        */
+       parser = mtd_part_parser_get(fixed);
+       if (!parser && !request_module("%s", fixed))
+               parser = mtd_part_parser_get(fixed);
+       if (parser) {
+               ret = mtd_part_do_parse(parser, master, pparts, NULL);
+               if (ret > 0)
+                       return ret;
+               mtd_part_parser_put(parser);
+               if (ret < 0 && !err)
+                       err = ret;
+       }
+
+       return err;
+}
+
 /**
  * parse_mtd_partitions - parse MTD partitions
  * @master: the master partition (describes whole MTD device)
                types = default_mtd_part_types;
 
        for ( ; *types; types++) {
-               pr_debug("%s: parsing partitions %s\n", master->name, *types);
-               parser = mtd_part_parser_get(*types);
-               if (!parser && !request_module("%s", *types))
+               /*
+                * ofpart is a special type that means OF partitioning info
+                * should be used. It requires a bit different logic so it is
+                * handled in a separated function.
+                */
+               if (!strcmp(*types, "ofpart")) {
+                       ret = mtd_part_of_parse(master, pparts);
+               } else {
+                       pr_debug("%s: parsing partitions %s\n", master->name,
+                                *types);
                        parser = mtd_part_parser_get(*types);
-               pr_debug("%s: got parser %s\n", master->name,
-                        parser ? parser->name : NULL);
-               if (!parser)
-                       continue;
-               ret = mtd_part_do_parse(parser, master, pparts, data);
+                       if (!parser && !request_module("%s", *types))
+                               parser = mtd_part_parser_get(*types);
+                       pr_debug("%s: got parser %s\n", master->name,
+                               parser ? parser->name : NULL);
+                       if (!parser)
+                               continue;
+                       ret = mtd_part_do_parse(parser, master, pparts, data);
+                       if (ret <= 0)
+                               mtd_part_parser_put(parser);
+               }
                /* Found partitions! */
                if (ret > 0)
                        return 0;
-               mtd_part_parser_put(parser);
                /*
                 * Stash the first error we see; only report it if no parser
                 * succeeds