#size-cells = <1>;
compatible = "brcm,bcm6338";
+ aliases {
+ pflash = &pflash;
+ };
+
cpus {
cpu@0 {
compatible = "brcm,bmips3300", "mips,mips4Kc";
memory { device_type = "memory"; reg = <0 0>; };
+ pflash: nor@1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-witdh = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
ubus@fff00000 {
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
compatible = "brcm,bcm6345";
+ aliases {
+ pflash = &pflash;
+ };
+
cpus {
cpu@0 {
compatible = "brcm,bmips32", "mips,mips4Kc";
memory { device_type = "memory"; reg = <0 0>; };
+ pflash: nor@1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-witdh = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
ubus@fff00000 {
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
compatible = "brcm,bcm6348";
+ aliases {
+ pflash = &pflash;
+ };
+
cpus {
cpu@0 {
compatible = "brcm,bmips3300", "mips,mips4Kc";
memory { device_type = "memory"; reg = <0 0>; };
+ pflash: nor@1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-witdh = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
ubus@fff00000 {
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
compatible = "brcm,bcm6358";
+ aliases {
+ pflash = &pflash;
+ };
+
cpus {
cpu@0 {
compatible = "brcm,bmips4350", "mips,mips4Kc";
memory { device_type = "memory"; reg = <0 0>; };
+ pflash: nor@1e000000 {
+ compatible = "cfi-flash";
+ reg = <0x1e000000 0x2000000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
ubus@fff00000 {
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
compatible = "brcm,bcm6368";
+ aliases {
+ pflash = &pflash;
+ };
+
cpus {
cpu@0 {
compatible = "brcm,bmips4350", "mips,mips4Kc";
#size-cells = <1>;
compatible = "simple-bus";
};
+
+ pflash: nor@18000000 {
+ compatible = "cfi-flash";
+ reg = <0x18000000 0x2000000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ };
};
--- /dev/null
+From 0d0e02d605c5696a5076510f564fefe659127aa4 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely@linaro.org>
+Date: Thu, 22 May 2014 01:04:17 +0900
+Subject: [PATCH] of: Create unlocked version of for_each_child_of_node()
+
+When iterating over nodes, sometimes it needs to be done when the DT
+lock is already held. This patch makes an unlocked version of the
+for_each_child_of_node() macro.
+
+Signed-off-by: Grant Likely <grant.likely@linaro.org>
+---
+ drivers/of/base.c | 22 +++++++++++++++++-----
+ 1 file changed, 17 insertions(+), 5 deletions(-)
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -545,6 +545,22 @@ struct device_node *of_get_next_parent(s
+ }
+ EXPORT_SYMBOL(of_get_next_parent);
+
++static struct device_node *__of_get_next_child(const struct device_node *node,
++ struct device_node *prev)
++{
++ struct device_node *next;
++
++ next = prev ? prev->sibling : node->child;
++ for (; next; next = next->sibling)
++ if (of_node_get(next))
++ break;
++ of_node_put(prev);
++ return next;
++}
++#define __for_each_child_of_node(parent, child) \
++ for (child = __of_get_next_child(parent, NULL); child != NULL; \
++ child = __of_get_next_child(parent, child))
++
+ /**
+ * of_get_next_child - Iterate a node childs
+ * @node: parent node
+@@ -560,11 +576,7 @@ struct device_node *of_get_next_child(co
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+- next = prev ? prev->sibling : node->child;
+- for (; next; next = next->sibling)
+- if (of_node_get(next))
+- break;
+- of_node_put(prev);
++ next = __of_get_next_child(node, prev);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return next;
+ }
--- /dev/null
+From 11d200e95f3e84c1102e4cc9863a3614fd41f3ad Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely@linaro.org>
+Date: Fri, 14 Mar 2014 17:00:14 +0000
+Subject: [PATCH] lib: add glibc style strchrnul() variant
+
+The strchrnul() variant helpfully returns a the end of the string
+instead of a NULL if the requested character is not found. This can
+simplify string parsing code since it doesn't need to expicitly check
+for a NULL return. If a valid string pointer is passed in, then a valid
+null terminated string will always come back out.
+
+Signed-off-by: Grant Likely <grant.likely@linaro.org>
+---
+ include/linux/string.h | 3 +++
+ lib/string.c | 18 ++++++++++++++++++
+ 2 files changed, 21 insertions(+)
+
+--- a/include/linux/string.h
++++ b/include/linux/string.h
+@@ -52,6 +52,9 @@ extern int strncasecmp(const char *s1, c
+ #ifndef __HAVE_ARCH_STRCHR
+ extern char * strchr(const char *,int);
+ #endif
++#ifndef __HAVE_ARCH_STRCHRNUL
++extern char * strchrnul(const char *,int);
++#endif
+ #ifndef __HAVE_ARCH_STRNCHR
+ extern char * strnchr(const char *, size_t, int);
+ #endif
+--- a/lib/string.c
++++ b/lib/string.c
+@@ -301,6 +301,24 @@ char *strchr(const char *s, int c)
+ EXPORT_SYMBOL(strchr);
+ #endif
+
++#ifndef __HAVE_ARCH_STRCHRNUL
++/**
++ * strchrnul - Find and return a character in a string, or end of string
++ * @s: The string to be searched
++ * @c: The character to search for
++ *
++ * Returns pointer to first occurrence of 'c' in s. If c is not found, then
++ * return a pointer to the null byte at the end of s.
++ */
++char *strchrnul(const char *s, int c)
++{
++ while (*s && *s != (char)c)
++ s++;
++ return (char *)s;
++}
++EXPORT_SYMBOL(strchrnul);
++#endif
++
+ #ifndef __HAVE_ARCH_STRRCHR
+ /**
+ * strrchr - Find the last occurrence of a character in a string
--- /dev/null
+From c22e650e66b862babe9c00bebb20b8029c7b0362 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely@linaro.org>
+Date: Fri, 14 Mar 2014 17:07:12 +0000
+Subject: [PATCH] of: Make of_find_node_by_path() handle /aliases
+
+Make of_find_node_by_path() handle aliases as prefixes. To make this
+work the name search is refactored to search by path component instead
+of by full string. This should be a more efficient search, and it makes
+it possible to start a search at a subnode of a tree.
+
+Signed-off-by: David Daney <david.daney@cavium.com>
+Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+[grant.likely: Rework to not require allocating at runtime]
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Grant Likely <grant.likely@linaro.org>
+---
+ drivers/of/base.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 61 insertions(+), 6 deletions(-)
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -633,23 +633,78 @@ struct device_node *of_get_child_by_name
+ }
+ EXPORT_SYMBOL(of_get_child_by_name);
+
++static struct device_node *__of_find_node_by_path(struct device_node *parent,
++ const char *path)
++{
++ struct device_node *child;
++ int len = strchrnul(path, '/') - path;
++
++ if (!len)
++ return NULL;
++
++ __for_each_child_of_node(parent, child) {
++ const char *name = strrchr(child->full_name, '/');
++ if (WARN(!name, "malformed device_node %s\n", child->full_name))
++ continue;
++ name++;
++ if (strncmp(path, name, len) == 0 && (strlen(name) == len))
++ return child;
++ }
++ return NULL;
++}
++
+ /**
+ * of_find_node_by_path - Find a node matching a full OF path
+- * @path: The full path to match
++ * @path: Either the full path to match, or if the path does not
++ * start with '/', the name of a property of the /aliases
++ * node (an alias). In the case of an alias, the node
++ * matching the alias' value will be returned.
++ *
++ * Valid paths:
++ * /foo/bar Full path
++ * foo Valid alias
++ * foo/bar Valid alias + relative path
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+ struct device_node *of_find_node_by_path(const char *path)
+ {
+- struct device_node *np = of_allnodes;
++ struct device_node *np = NULL;
++ struct property *pp;
+ unsigned long flags;
+
++ if (strcmp(path, "/") == 0)
++ return of_node_get(of_allnodes);
++
++ /* The path could begin with an alias */
++ if (*path != '/') {
++ char *p = strchrnul(path, '/');
++ int len = p - path;
++
++ /* of_aliases must not be NULL */
++ if (!of_aliases)
++ return NULL;
++
++ for_each_property_of_node(of_aliases, pp) {
++ if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
++ np = of_find_node_by_path(pp->value);
++ break;
++ }
++ }
++ if (!np)
++ return NULL;
++ path = p;
++ }
++
++ /* Step down the tree matching path components */
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+- for (; np; np = np->allnext) {
+- if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+- && of_node_get(np))
+- break;
++ if (!np)
++ np = of_node_get(of_allnodes);
++ while (np && *path == '/') {
++ path++; /* Increment past '/' delimiter */
++ np = __of_find_node_by_path(np, path);
++ path = strchrnul(path, '/');
+ }
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return np;
--- /dev/null
+--- a/arch/mips/bcm63xx/boards/board_common.c
++++ b/arch/mips/bcm63xx/boards/board_common.c
+@@ -147,6 +147,18 @@ void __init device_tree_init(void)
+
+ unflatten_and_copy_device_tree();
+ }
++
++int board_of_device_present(const char *alias)
++{
++ bool present;
++ struct device_node *np;
++
++ np = of_find_node_by_path(alias);
++ present = of_device_is_available(np);
++ of_node_put(np);
++
++ return present;
++}
+ #endif
+
+ static struct gpio_led_platform_data bcm63xx_led_data;
+--- a/arch/mips/bcm63xx/boards/board_common.h
++++ b/arch/mips/bcm63xx/boards/board_common.h
+@@ -15,4 +15,13 @@ void board_bcm963xx_init(void);
+ static inline void board_bcm963xx_init(void) { }
+ #endif
+
++#if defined(CONFIG_OF)
++int board_of_device_present(const char *alias);
++#else
++static inline void board_of_device_present(const char *alias)
++{
++ return 0;
++}
++#endif
++
+ #endif /* __BOARD_COMMON_H */
--- /dev/null
+--- a/arch/mips/bcm63xx/dev-flash.c
++++ b/arch/mips/bcm63xx/dev-flash.c
+@@ -22,6 +22,8 @@
+ #include <bcm63xx_regs.h>
+ #include <bcm63xx_io.h>
+
++#include "boards/board_common.h"
++
+ static int flash_type;
+
+ static struct mtd_partition mtd_partitions[] = {
+@@ -164,6 +166,9 @@ int __init bcm63xx_flash_register(void)
+
+ switch (flash_type) {
+ case BCM63XX_FLASH_TYPE_PARALLEL:
++ /* don't register when already registered through from dtb */
++ if (board_of_device_present("pflash"))
++ return 0;
+
+ if (!mtd_resources[0].start) {
+ /* read base address of boot chip select (0) */
--- a/arch/mips/bcm63xx/dev-flash.c
+++ b/arch/mips/bcm63xx/dev-flash.c
-@@ -32,7 +32,7 @@ static struct mtd_partition mtd_partitio
+@@ -34,7 +34,7 @@ static struct mtd_partition mtd_partitio
}
};
#include <bcm63xx_regs.h>
#include <bcm63xx_io.h>
-@@ -63,6 +66,21 @@ void __init bcm63xx_flash_force_phys_bas
+@@ -65,6 +68,21 @@ void __init bcm63xx_flash_force_phys_bas
mtd_resources[0].end = end;
}
static int __init bcm63xx_detect_flash_type(void)
{
u32 val;
-@@ -70,9 +88,15 @@ static int __init bcm63xx_detect_flash_t
+@@ -72,9 +90,15 @@ static int __init bcm63xx_detect_flash_t
switch (bcm63xx_get_cpu_id()) {
case BCM6318_CPU_ID:
/* only support serial flash */
if (val & STRAPBUS_6328_BOOT_SEL_SERIAL)
return BCM63XX_FLASH_TYPE_SERIAL;
else
-@@ -91,12 +115,20 @@ static int __init bcm63xx_detect_flash_t
+@@ -93,12 +117,20 @@ static int __init bcm63xx_detect_flash_t
return BCM63XX_FLASH_TYPE_SERIAL;
case BCM6362_CPU_ID:
val = bcm_misc_readl(MISC_STRAPBUS_6362_REG);
switch (val & STRAPBUS_6368_BOOT_SEL_MASK) {
case STRAPBUS_6368_BOOT_SEL_NAND:
return BCM63XX_FLASH_TYPE_NAND;
-@@ -107,6 +139,11 @@ static int __init bcm63xx_detect_flash_t
+@@ -109,6 +141,11 @@ static int __init bcm63xx_detect_flash_t
}
case BCM63268_CPU_ID:
val = bcm_misc_readl(MISC_STRAPBUS_63268_REG);
if (val & STRAPBUS_63268_BOOT_SEL_SERIAL)
return BCM63XX_FLASH_TYPE_SERIAL;
else
-@@ -176,8 +213,15 @@ int __init bcm63xx_flash_register(void)
+@@ -181,8 +218,15 @@ int __init bcm63xx_flash_register(void)
return platform_device_register(&mtd_dev);
case BCM63XX_FLASH_TYPE_SERIAL:
#include "board_common.h"
-@@ -184,6 +185,7 @@ int __init board_register_devices(void)
+@@ -196,6 +197,7 @@ int __init board_register_devices(void)
int button_count = 0;
int led_count = 0;
int usbh_ports = 0;
#if CONFIG_OF
if (of_have_populated_dt()) {
-@@ -281,6 +283,10 @@ int __init board_register_devices(void)
+@@ -293,6 +295,10 @@ int __init board_register_devices(void)
platform_device_register(&bcm63xx_gpio_keys_device);
}
--- a/arch/mips/bcm63xx/dev-flash.c
+++ b/arch/mips/bcm63xx/dev-flash.c
-@@ -231,3 +231,8 @@ int __init bcm63xx_flash_register(void)
+@@ -236,3 +236,8 @@ int __init bcm63xx_flash_register(void)
return -ENODEV;
}
}
--- a/arch/mips/bcm63xx/boards/board_common.c
+++ b/arch/mips/bcm63xx/boards/board_common.c
-@@ -255,7 +255,7 @@ int __init board_register_devices(void)
+@@ -267,7 +267,7 @@ int __init board_register_devices(void)
if (board.num_spis)
spi_register_board_info(board.spis, board.num_spis);
while (led_count < ARRAY_SIZE(board.leds) && board.leds[led_count].name)
--- a/arch/mips/bcm63xx/dev-flash.c
+++ b/arch/mips/bcm63xx/dev-flash.c
-@@ -35,12 +35,15 @@ static struct mtd_partition mtd_partitio
+@@ -37,12 +37,15 @@ static struct mtd_partition mtd_partitio
}
};
};
static struct resource mtd_resources[] = {
-@@ -68,6 +71,7 @@ void __init bcm63xx_flash_force_phys_bas
+@@ -70,6 +73,7 @@ void __init bcm63xx_flash_force_phys_bas
static struct flash_platform_data bcm63xx_flash_data = {
.part_probe_types = bcm63xx_part_types,
};
static struct spi_board_info bcm63xx_spi_flash_info[] = {
-@@ -195,9 +199,13 @@ void __init bcm63xx_flash_detect(void)
+@@ -197,9 +201,13 @@ void __init bcm63xx_flash_detect(void)
}
}
return;
--- a/arch/mips/bcm63xx/boards/board_common.c
+++ b/arch/mips/bcm63xx/boards/board_common.c
-@@ -285,7 +285,8 @@ int __init board_register_devices(void)
+@@ -297,7 +297,8 @@ int __init board_register_devices(void)
/* register any fixups */
for (i = 0; i < board.has_caldata; i++)
--- a/arch/mips/bcm63xx/boards/board_common.c
+++ b/arch/mips/bcm63xx/boards/board_common.c
-@@ -286,7 +286,7 @@ int __init board_register_devices(void)
+@@ -298,7 +298,7 @@ int __init board_register_devices(void)
/* register any fixups */
for (i = 0; i < board.has_caldata; i++)
pci_enable_ath9k_fixup(board.caldata[i].slot, board.caldata[i].caldata_offset,
#include "board_common.h"
-@@ -284,9 +285,19 @@ int __init board_register_devices(void)
+@@ -296,9 +297,19 @@ int __init board_register_devices(void)
}
/* register any fixups */
}
--- a/arch/mips/bcm63xx/dev-flash.c
+++ b/arch/mips/bcm63xx/dev-flash.c
-@@ -199,7 +199,7 @@ void __init bcm63xx_flash_detect(void)
+@@ -201,7 +201,7 @@ void __init bcm63xx_flash_detect(void)
}
}
--- /dev/null
+--- a/drivers/mtd/bcm63xxpart.c
++++ b/drivers/mtd/bcm63xxpart.c
+@@ -32,6 +32,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of.h>
+
+ #include <asm/mach-bcm63xx/bcm63xx_nvram.h>
+ #include <linux/bcm963xx_tag.h>
+@@ -43,66 +44,35 @@
+
+ #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
+
+-static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
+- struct mtd_part_parser_data *data)
++static bool node_has_compatible(struct device_node *pp)
++{
++ return of_get_property(pp, "compatible", NULL);
++}
++
++static int parse_bcmtag(struct mtd_info *master, struct mtd_partition *pparts,
++ int next_part, size_t offset, size_t size)
+ {
+- /* CFE, NVRAM and global Linux are always present */
+- int nrparts = 3, curpart = 0;
+ struct bcm_tag *buf;
+- struct mtd_partition *parts;
++ u32 computed_crc;
+ int ret;
+ size_t retlen;
+- unsigned int rootfsaddr, kerneladdr, spareaddr, nvramaddr;
+- unsigned int rootfslen, kernellen, sparelen, totallen;
+- unsigned int cfelen, nvramlen;
+- unsigned int cfe_erasesize;
+- unsigned int caldatalen1 = 0, caldataaddr1 = 0;
+- unsigned int caldatalen2 = 0, caldataaddr2 = 0;
+- int i;
+- u32 computed_crc;
++ unsigned int rootfsaddr, kerneladdr;
++ unsigned int rootfslen, kernellen, totallen;
+ bool rootfs_first = false;
+-
+- if (!bcm63xx_is_cfe_present())
+- return -EINVAL;
+-
+- cfe_erasesize = max_t(uint32_t, master->erasesize,
+- BCM63XX_CFE_BLOCK_SIZE);
+-
+- cfelen = cfe_erasesize;
+- nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+- nvramlen = roundup(nvramlen, cfe_erasesize);
+- nvramaddr = master->size - nvramlen;
+-
+- if (data) {
+- if (data->caldata[0]) {
+- caldatalen1 = cfe_erasesize;
+- caldataaddr1 = rounddown(data->caldata[0],
+- cfe_erasesize);
+- }
+- if (data->caldata[1]) {
+- caldatalen2 = cfe_erasesize;
+- caldataaddr2 = rounddown(data->caldata[1],
+- cfe_erasesize);
+- }
+- if (caldataaddr1 == caldataaddr2) {
+- caldataaddr2 = 0;
+- caldatalen2 = 0;
+- }
+- }
++ int curr_part = next_part;
+
+ /* Allocate memory for buffer */
+- buf = vmalloc(sizeof(struct bcm_tag));
++ buf = vmalloc(sizeof(*buf));
+ if (!buf)
+ return -ENOMEM;
+
+ /* Get the tag */
+- ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen,
++ ret = mtd_read(master, offset, sizeof(*buf), &retlen,
+ (void *)buf);
+
+- if (retlen != sizeof(struct bcm_tag)) {
++ if (retlen != sizeof(*buf)) {
+ vfree(buf);
+- return -EIO;
++ return 0;
+ }
+
+ computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
+@@ -121,7 +91,6 @@ static int bcm63xx_parse_cfe_partitions(
+
+ kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
+ rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
+- spareaddr = roundup(totallen, master->erasesize) + cfelen;
+
+ if (rootfsaddr < kerneladdr) {
+ /* default Broadcom layout */
+@@ -130,8 +99,8 @@ static int bcm63xx_parse_cfe_partitions(
+ } else {
+ /* OpenWrt layout */
+ rootfsaddr = kerneladdr + kernellen;
+- rootfslen = buf->real_rootfs_length;
+- spareaddr = rootfsaddr + rootfslen;
++ rootfslen = size - kernellen -
++ sizeof(*buf);
+ }
+ } else {
+ pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
+@@ -139,16 +108,145 @@ static int bcm63xx_parse_cfe_partitions(
+ kernellen = 0;
+ rootfslen = 0;
+ rootfsaddr = 0;
+- spareaddr = cfelen;
+ }
+- sparelen = min_not_zero(nvramaddr, caldataaddr1) - spareaddr;
+
+- /* Determine number of partitions */
+- if (rootfslen > 0)
+- nrparts++;
++ if (kernellen > 0) {
++ int kernelpart = curr_part;
+
+- if (kernellen > 0)
+- nrparts++;
++ if (rootfslen > 0 && rootfs_first)
++ kernelpart++;
++ pparts[kernelpart].name = "kernel";
++ pparts[kernelpart].offset = kerneladdr;
++ pparts[kernelpart].size = kernellen;
++ curr_part++;
++ }
++
++ if (rootfslen > 0) {
++ int rootfspart = curr_part;
++
++ if (kernellen > 0 && rootfs_first)
++ rootfspart--;
++ pparts[rootfspart].name = "rootfs";
++ pparts[rootfspart].offset = rootfsaddr;
++ pparts[rootfspart].size = rootfslen;
++
++ curr_part++;
++ }
++
++ vfree(buf);
++
++ return curr_part - next_part;
++}
++
++
++static int bcm63xx_parse_cfe_partitions_of(struct mtd_info *master,
++ struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ struct device_node *dp = data->of_node;
++ struct device_node *pp;
++ int i, nr_parts = 0;
++ const char *partname;
++ int len;
++
++ for_each_child_of_node(dp, pp) {
++ if (node_has_compatible(pp))
++ continue;
++
++ nr_parts++;
++ }
++
++ *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
++ if (!*pparts)
++ return -ENOMEM;
++
++ i = 0;
++ for_each_child_of_node(dp, pp) {
++ const __be32 *reg;
++ int a_cells, s_cells;
++ size_t size, offset;
++
++ if (node_has_compatible(pp))
++ continue;
++
++ reg = of_get_property(pp, "reg", &len);
++ if (!reg) {
++ nr_parts--;
++ continue;
++ }
++
++ a_cells = of_n_addr_cells(pp);
++ s_cells = of_n_size_cells(pp);
++ offset = of_read_number(reg, a_cells);
++ size = of_read_number(reg + a_cells, s_cells);
++ partname = of_get_property(pp, "label", &len);
++ if (!partname)
++ partname = of_get_property(pp, "name", &len);
++
++ if (!strcmp(partname, "linux"))
++ i += parse_bcmtag(master, *pparts, i, offset, size);
++
++ if (of_get_property(pp, "read-only", &len))
++ (*pparts)[i].mask_flags |= MTD_WRITEABLE;
++
++ if (of_get_property(pp, "lock", &len))
++ (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
++
++ (*pparts)[i].offset = offset;
++ (*pparts)[i].size = size;
++ (*pparts)[i].name = partname;
++
++ i++;
++ }
++
++ return i;
++}
++
++static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
++ struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ /* CFE, NVRAM and global Linux are always present */
++ int nrparts = 5, curpart = 0;
++ struct mtd_partition *parts;
++ unsigned int nvramaddr;
++ unsigned int cfelen, nvramlen;
++ unsigned int cfe_erasesize;
++ unsigned int caldatalen1 = 0, caldataaddr1 = 0;
++ unsigned int caldatalen2 = 0, caldataaddr2 = 0;
++ unsigned int imageaddr, imagelen;
++ int i;
++
++ if (!bcm63xx_is_cfe_present())
++ return -EINVAL;
++
++ cfe_erasesize = max_t(uint32_t, master->erasesize,
++ BCM63XX_CFE_BLOCK_SIZE);
++
++ cfelen = cfe_erasesize;
++ nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
++ nvramlen = roundup(nvramlen, cfe_erasesize);
++ nvramaddr = master->size - nvramlen;
++
++ if (data) {
++ if (data->caldata[0]) {
++ caldatalen1 = cfe_erasesize;
++ caldataaddr1 = rounddown(data->caldata[0],
++ cfe_erasesize);
++ }
++ if (data->caldata[1]) {
++ caldatalen2 = cfe_erasesize;
++ caldataaddr2 = rounddown(data->caldata[1],
++ cfe_erasesize);
++ }
++ if (caldataaddr1 == caldataaddr2) {
++ caldataaddr2 = 0;
++ caldatalen2 = 0;
++ }
++ }
++
++ imageaddr = cfelen;
++ imagelen = min_not_zero(nvramaddr, caldataaddr1) - imageaddr;
+
+ if (caldatalen1 > 0)
+ nrparts++;
+@@ -158,10 +256,8 @@ static int bcm63xx_parse_cfe_partitions(
+
+ /* Ask kernel for more memory */
+ parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
+- if (!parts) {
+- vfree(buf);
++ if (!parts)
+ return -ENOMEM;
+- }
+
+ /* Start building partition list */
+ parts[curpart].name = "CFE";
+@@ -169,29 +265,7 @@ static int bcm63xx_parse_cfe_partitions(
+ parts[curpart].size = cfelen;
+ curpart++;
+
+- if (kernellen > 0) {
+- int kernelpart = curpart;
+-
+- if (rootfslen > 0 && rootfs_first)
+- kernelpart++;
+- parts[kernelpart].name = "kernel";
+- parts[kernelpart].offset = kerneladdr;
+- parts[kernelpart].size = kernellen;
+- curpart++;
+- }
+-
+- if (rootfslen > 0) {
+- int rootfspart = curpart;
+-
+- if (kernellen > 0 && rootfs_first)
+- rootfspart--;
+- parts[rootfspart].name = "rootfs";
+- parts[rootfspart].offset = rootfsaddr;
+- parts[rootfspart].size = rootfslen;
+- if (sparelen > 0 && !rootfs_first)
+- parts[rootfspart].size += sparelen;
+- curpart++;
+- }
++ curpart += parse_bcmtag(master, parts, curpart, imageaddr, imagelen);
+
+ if (caldatalen1 > 0) {
+ if (caldatalen2 > 0)
+@@ -217,25 +291,33 @@ static int bcm63xx_parse_cfe_partitions(
+
+ /* Global partition "linux" to make easy firmware upgrade */
+ parts[curpart].name = "linux";
+- parts[curpart].offset = cfelen;
+- parts[curpart].size = min_not_zero(nvramaddr, caldataaddr1) - cfelen;
++ parts[curpart].offset = imageaddr;
++ parts[curpart].size = imagelen;
++ curpart++;
+
+- for (i = 0; i < nrparts; i++)
++ for (i = 0; i < curpart; i++)
+ pr_info("Partition %d is %s offset %llx and length %llx\n", i,
+ parts[i].name, parts[i].offset, parts[i].size);
+
+- pr_info("Spare partition is offset %x and length %x\n", spareaddr,
+- sparelen);
+-
+ *pparts = parts;
+- vfree(buf);
+
+ return nrparts;
+ };
+
++
++static int bcm63xx_parse_partitions(struct mtd_info *master,
++ struct mtd_partition **pparts,
++ struct mtd_part_parser_data *data)
++{
++ if (data && data->of_node)
++ return bcm63xx_parse_cfe_partitions_of(master, pparts, data);
++ else
++ return bcm63xx_parse_cfe_partitions(master, pparts, data);
++}
++
+ static struct mtd_part_parser bcm63xx_cfe_parser = {
+ .owner = THIS_MODULE,
+- .parse_fn = bcm63xx_parse_cfe_partitions,
++ .parse_fn = bcm63xx_parse_partitions,
+ .name = "bcm63xxpart",
+ };
+
#include <bcm63xx_cpu.h>
#include <bcm63xx_dev_flash.h>
#include <bcm63xx_dev_hsspi.h>
-@@ -215,6 +216,13 @@ int __init bcm63xx_flash_register(int nu
+@@ -220,6 +221,13 @@ int __init bcm63xx_flash_register(int nu
val = bcm_mpi_readl(MPI_CSBASE_REG(0));
val &= MPI_CSBASE_BASE_MASK;
static int (*board_get_mac_address)(u8 mac[ETH_ALEN]);
--- a/arch/mips/bcm63xx/boards/board_common.h
+++ b/arch/mips/bcm63xx/boards/board_common.h
-@@ -15,4 +15,10 @@ void board_bcm963xx_init(void);
- static inline void board_bcm963xx_init(void) { }
+@@ -24,4 +24,10 @@ static inline void board_of_device_prese
+ }
#endif
+#if defined(CONFIG_BOARD_LIVEBOX)
--- a/drivers/mtd/bcm63xxpart.c
+++ b/drivers/mtd/bcm63xxpart.c
-@@ -70,6 +70,11 @@ static int bcm63xx_parse_cfe_partitions(
+@@ -224,6 +224,11 @@ static int bcm63xx_parse_cfe_partitions(
BCM63XX_CFE_BLOCK_SIZE);
cfelen = cfe_erasesize;