]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - common/fdt_support.c
mips: Move cpu/mips/* to arch/mips/cpu/*
[karo-tx-uboot.git] / common / fdt_support.c
index 5a83bca48177d738f6d493283214ac6ca099167e..b6f252a87b0c9de15ec7ac02eca1990565392b43 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <stdio_dev.h>
 #include <linux/ctype.h>
 #include <linux/types.h>
 #include <asm/global_data.h>
@@ -90,6 +91,23 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 }
 
 #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
+
+#ifdef CONFIG_SERIAL_MULTI
+static void fdt_fill_multisername(char *sername, size_t maxlen)
+{
+       const char *outname = stdio_devices[stdout]->name;
+
+       if (strcmp(outname, "serial") > 0)
+               strncpy(sername, outname, maxlen);
+
+       /* eserial? */
+       if (strcmp(outname + 1, "serial") > 0)
+               strncpy(sername, outname + 1, maxlen);
+}
+#else
+static inline void fdt_fill_multisername(char *sername, size_t maxlen) {}
+#endif /* CONFIG_SERIAL_MULTI */
+
 static int fdt_fixup_stdout(void *fdt, int chosenoff)
 {
        int err = 0;
@@ -98,7 +116,9 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff)
        char sername[9] = { 0 };
        const char *path;
 
-       sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
+       fdt_fill_multisername(sername, sizeof(sername) - 1);
+       if (!sername[0])
+               sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
 
        err = node = fdt_path_offset(fdt, "/aliases");
        if (node >= 0) {
@@ -495,7 +515,7 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd)
 }
 #endif /* CONFIG_HAS_FSL_DR_USB */
 
-#if defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx)
+#if defined(CONFIG_MPC83xx) || defined(CONFIG_MPC85xx)
 /*
  * update crypto node properties to a specified revision of the SEC
  * called with sec_rev == 0 if not on an mpc8xxxE processor
@@ -580,7 +600,7 @@ void fdt_fixup_crypto_node(void *blob, int sec_rev)
                printf("WARNING: could not set crypto property: %s\n",
                       fdt_strerror(err));
 }
-#endif /* defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx) */
+#endif /* defined(CONFIG_MPC83xx) || defined(CONFIG_MPC85xx) */
 
 /* Resize the fdt to its actual size + a bit of padding */
 int fdt_resize(void *blob)
@@ -604,13 +624,14 @@ int fdt_resize(void *blob)
 
        /*
         * Calculate the actual size of the fdt
-        * plus the size needed for fdt_add_mem_rsv
+        * plus the size needed for two fdt_add_mem_rsv, one
+        * for the fdt itself and one for a possible initrd
         */
        actualsize = fdt_off_dt_strings(blob) +
-               fdt_size_dt_strings(blob) + sizeof(struct fdt_reserve_entry);
+               fdt_size_dt_strings(blob) + 2*sizeof(struct fdt_reserve_entry);
 
        /* Make it so the fdt ends on a page boundary */
-       actualsize = ALIGN(actualsize, 0x1000);
+       actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
        actualsize = actualsize - ((uint)blob & 0xfff);
 
        /* Change the fdt header to reflect the correct size */
@@ -625,7 +646,7 @@ int fdt_resize(void *blob)
 }
 
 #ifdef CONFIG_PCI
-#define CONFIG_SYS_PCI_NR_INBOUND_WIN 3
+#define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
 
 #define FDT_PCI_PREFETCH       (0x40000000)
 #define FDT_PCI_MEM32          (0x02000000)
@@ -646,8 +667,8 @@ int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
        for (r = 0; r < hose->region_count; r++) {
                u64 bus_start, phys_start, size;
 
-               /* skip if !PCI_REGION_MEMORY */
-               if (!(hose->regions[r].flags & PCI_REGION_MEMORY))
+               /* skip if !PCI_REGION_SYS_MEMORY */
+               if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
                        continue;
 
                bus_start = (u64)hose->regions[r].bus_start;
@@ -655,7 +676,7 @@ int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
                size = (u64)hose->regions[r].size;
 
                dma_range[0] = 0;
-               if (size > 0x100000000ull)
+               if (size >= 0x100000000ull)
                        dma_range[0] |= FDT_PCI_MEM64;
                else
                        dma_range[0] |= FDT_PCI_MEM32;
@@ -692,3 +713,279 @@ int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
        return 0;
 }
 #endif
+
+#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
+/*
+ * This function can be used to update the size in the "reg" property
+ * of the NOR FLASH device nodes. This is necessary for boards with
+ * non-fixed NOR FLASH sizes.
+ */
+int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size)
+{
+       char compat[][16] = { "cfi-flash", "jedec-flash" };
+       int off;
+       int len;
+       struct fdt_property *prop;
+       u32 *reg;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               off = fdt_node_offset_by_compatible(blob, -1, compat[i]);
+               while (off != -FDT_ERR_NOTFOUND) {
+                       /*
+                        * Found one compatible node, now check if this one
+                        * has the correct CS
+                        */
+                       prop = fdt_get_property_w(blob, off, "reg", &len);
+                       if (prop) {
+                               reg = (u32 *)&prop->data[0];
+                               if (reg[0] == cs) {
+                                       reg[2] = size;
+                                       fdt_setprop(blob, off, "reg", reg,
+                                                   3 * sizeof(u32));
+
+                                       return 0;
+                               }
+                       }
+
+                       /* Move to next compatible node */
+                       off = fdt_node_offset_by_compatible(blob, off,
+                                                           compat[i]);
+               }
+       }
+
+       return -1;
+}
+#endif
+
+#ifdef CONFIG_FDT_FIXUP_PARTITIONS
+#include <jffs2/load_kernel.h>
+#include <mtd_node.h>
+
+struct reg_cell {
+       unsigned int r0;
+       unsigned int r1;
+};
+
+int fdt_del_subnodes(const void *blob, int parent_offset)
+{
+       int off, ndepth;
+       int ret;
+
+       for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
+            (off >= 0) && (ndepth > 0);
+            off = fdt_next_node(blob, off, &ndepth)) {
+               if (ndepth == 1) {
+                       debug("delete %s: offset: %x\n",
+                               fdt_get_name(blob, off, 0), off);
+                       ret = fdt_del_node((void *)blob, off);
+                       if (ret < 0) {
+                               printf("Can't delete node: %s\n",
+                                       fdt_strerror(ret));
+                               return ret;
+                       } else {
+                               ndepth = 0;
+                               off = parent_offset;
+                       }
+               }
+       }
+       return 0;
+}
+
+int fdt_increase_size(void *fdt, int add_len)
+{
+       int newlen;
+
+       newlen = fdt_totalsize(fdt) + add_len;
+
+       /* Open in place with a new len */
+       return fdt_open_into(fdt, fdt, newlen);
+}
+
+int fdt_del_partitions(void *blob, int parent_offset)
+{
+       const void *prop;
+       int ndepth = 0;
+       int off;
+       int ret;
+
+       off = fdt_next_node(blob, parent_offset, &ndepth);
+       if (off > 0 && ndepth == 1) {
+               prop = fdt_getprop(blob, off, "label", NULL);
+               if (prop == NULL) {
+                       /*
+                        * Could not find label property, nand {}; node?
+                        * Check subnode, delete partitions there if any.
+                        */
+                       return fdt_del_partitions(blob, off);
+               } else {
+                       ret = fdt_del_subnodes(blob, parent_offset);
+                       if (ret < 0) {
+                               printf("Can't remove subnodes: %s\n",
+                                       fdt_strerror(ret));
+                               return ret;
+                       }
+               }
+       }
+       return 0;
+}
+
+int fdt_node_set_part_info(void *blob, int parent_offset,
+                          struct mtd_device *dev)
+{
+       struct list_head *pentry;
+       struct part_info *part;
+       struct reg_cell cell;
+       int off, ndepth = 0;
+       int part_num, ret;
+       char buf[64];
+
+       ret = fdt_del_partitions(blob, parent_offset);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Check if it is nand {}; subnode, adjust
+        * the offset in this case
+        */
+       off = fdt_next_node(blob, parent_offset, &ndepth);
+       if (off > 0 && ndepth == 1)
+               parent_offset = off;
+
+       part_num = 0;
+       list_for_each_prev(pentry, &dev->parts) {
+               int newoff;
+
+               part = list_entry(pentry, struct part_info, link);
+
+               debug("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+                       part_num, part->name, part->size,
+                       part->offset, part->mask_flags);
+
+               sprintf(buf, "partition@%x", part->offset);
+add_sub:
+               ret = fdt_add_subnode(blob, parent_offset, buf);
+               if (ret == -FDT_ERR_NOSPACE) {
+                       ret = fdt_increase_size(blob, 512);
+                       if (!ret)
+                               goto add_sub;
+                       else
+                               goto err_size;
+               } else if (ret < 0) {
+                       printf("Can't add partition node: %s\n",
+                               fdt_strerror(ret));
+                       return ret;
+               }
+               newoff = ret;
+
+               /* Check MTD_WRITEABLE_CMD flag */
+               if (part->mask_flags & 1) {
+add_ro:
+                       ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
+                       if (ret == -FDT_ERR_NOSPACE) {
+                               ret = fdt_increase_size(blob, 512);
+                               if (!ret)
+                                       goto add_ro;
+                               else
+                                       goto err_size;
+                       } else if (ret < 0)
+                               goto err_prop;
+               }
+
+               cell.r0 = cpu_to_fdt32(part->offset);
+               cell.r1 = cpu_to_fdt32(part->size);
+add_reg:
+               ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
+               if (ret == -FDT_ERR_NOSPACE) {
+                       ret = fdt_increase_size(blob, 512);
+                       if (!ret)
+                               goto add_reg;
+                       else
+                               goto err_size;
+               } else if (ret < 0)
+                       goto err_prop;
+
+add_label:
+               ret = fdt_setprop_string(blob, newoff, "label", part->name);
+               if (ret == -FDT_ERR_NOSPACE) {
+                       ret = fdt_increase_size(blob, 512);
+                       if (!ret)
+                               goto add_label;
+                       else
+                               goto err_size;
+               } else if (ret < 0)
+                       goto err_prop;
+
+               part_num++;
+       }
+       return 0;
+err_size:
+       printf("Can't increase blob size: %s\n", fdt_strerror(ret));
+       return ret;
+err_prop:
+       printf("Can't add property: %s\n", fdt_strerror(ret));
+       return ret;
+}
+
+/*
+ * Update partitions in nor/nand nodes using info from
+ * mtdparts environment variable. The nodes to update are
+ * specified by node_info structure which contains mtd device
+ * type and compatible string: E. g. the board code in
+ * ft_board_setup() could use:
+ *
+ *     struct node_info nodes[] = {
+ *             { "fsl,mpc5121-nfc",    MTD_DEV_TYPE_NAND, },
+ *             { "cfi-flash",          MTD_DEV_TYPE_NOR,  },
+ *     };
+ *
+ *     fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+ */
+void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
+{
+       struct node_info *ni = node_info;
+       struct mtd_device *dev;
+       char *parts;
+       int i, idx;
+       int noff;
+
+       parts = getenv("mtdparts");
+       if (!parts)
+               return;
+
+       if (mtdparts_init() != 0)
+               return;
+
+       for (i = 0; i < node_info_size; i++) {
+               idx = 0;
+               noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
+               while (noff != -FDT_ERR_NOTFOUND) {
+                       debug("%s: %s, mtd dev type %d\n",
+                               fdt_get_name(blob, noff, 0),
+                               ni[i].compat, ni[i].type);
+                       dev = device_find(ni[i].type, idx++);
+                       if (dev) {
+                               if (fdt_node_set_part_info(blob, noff, dev))
+                                       return; /* return on error */
+                       }
+
+                       /* Jump to next flash node */
+                       noff = fdt_node_offset_by_compatible(blob, noff,
+                                                            ni[i].compat);
+               }
+       }
+}
+#endif
+
+void fdt_del_node_and_alias(void *blob, const char *alias)
+{
+       int off = fdt_path_offset(blob, alias);
+
+       if (off < 0)
+               return;
+
+       fdt_del_node(blob, off);
+
+       off = fdt_path_offset(blob, "/aliases");
+       fdt_delprop(blob, off, alias);
+}