aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch')
-rw-r--r--target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch357
1 files changed, 357 insertions, 0 deletions
diff --git a/target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch b/target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch
new file mode 100644
index 0000000..53fc4c5
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.1/425-bcm63xxpart_parse_paritions_from_dt.patch
@@ -0,0 +1,357 @@
+--- 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 <asm/mach-bcm63xx/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,153 @@ 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;
++
++ if (!of_get_property(pp, "reg", &len))
++ continue;
++
++ partname = of_get_property(pp, "label", &len);
++ if (!partname)
++ partname = of_get_property(pp, "name", &len);
++
++ if (!strcmp(partname, "linux"))
++ nr_parts += 2;
++
++ 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)
++ 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 +264,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 +273,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 +299,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",
+ };
+