lantiq: handle the dual-firmware layout of brnboot
[openwrt.git] / target / linux / lantiq / patches-4.4 / 0101-find_active_root.patch
diff --git a/target/linux/lantiq/patches-4.4/0101-find_active_root.patch b/target/linux/lantiq/patches-4.4/0101-find_active_root.patch
new file mode 100644 (file)
index 0000000..978def3
--- /dev/null
@@ -0,0 +1,93 @@
+--- a/drivers/mtd/ofpart.c
++++ b/drivers/mtd/ofpart.c
+@@ -25,6 +25,38 @@ static bool node_has_compatible(struct d
+       return of_get_property(pp, "compatible", NULL);
+ }
++static uint8_t * brnboot_get_selected_root_part(struct mtd_info *master,
++                                              loff_t offset)
++{
++      static uint8_t root_id;
++      int err, len;
++
++      err = mtd_read(master, offset, 0x01, &len, &root_id);
++
++      if (mtd_is_bitflip(err) || !err)
++              return &root_id;
++
++      return NULL;
++}
++
++static void brnboot_set_active_root_part(struct mtd_partition *pparts,
++                                       struct device_node **part_nodes,
++                                       int nr_parts,
++                                       uint8_t *root_id)
++{
++      int i;
++
++      for (i = 0; i < nr_parts; i++) {
++              int part_root_id;
++
++              if (!of_property_read_u32(part_nodes[i], "brnboot,root-id", &part_root_id)
++                  && part_root_id == *root_id) {
++                      pparts[i].name = "firmware";
++                      break;
++              }
++      }
++}
++
+ static int parse_ofpart_partitions(struct mtd_info *master,
+                                  struct mtd_partition **pparts,
+                                  struct mtd_part_parser_data *data)
+@@ -35,7 +67,8 @@ static int parse_ofpart_partitions(struc
+       struct device_node *pp;
+       int nr_parts, i, ret = 0;
+       bool dedicated = true;
+-
++      uint8_t *proot_id = NULL;
++      struct device_node **part_nodes;
+       if (!data)
+               return 0;
+@@ -73,7 +106,9 @@ static int parse_ofpart_partitions(struc
+               return 0;
+       *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+-      if (!*pparts)
++      part_nodes = kzalloc(nr_parts * sizeof(*part_nodes), GFP_KERNEL);
++
++      if (!*pparts || !part_nodes)
+               return -ENOMEM;
+       i = 0;
+@@ -121,12 +156,22 @@ static int parse_ofpart_partitions(struc
+               if (of_get_property(pp, "lock", &len))
+                       (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
++              if (!proot_id && of_device_is_compatible(pp, "brnboot,root-selector"))
++                      proot_id = brnboot_get_selected_root_part(master, (*pparts)[i].offset);
++
++              part_nodes[i] = pp;
++
+               i++;
+       }
+       if (!nr_parts)
+               goto ofpart_none;
++      if (proot_id)
++              brnboot_set_active_root_part(*pparts, part_nodes, nr_parts, proot_id);
++
++      kfree(part_nodes);
++
+       return nr_parts;
+ ofpart_fail:
+@@ -136,6 +181,7 @@ ofpart_fail:
+ ofpart_none:
+       of_node_put(pp);
+       kfree(*pparts);
++      kfree(part_nodes);
+       *pparts = NULL;
+       return ret;
+ }