*/
#include <common.h>
+#include <stdio_dev.h>
#include <linux/ctype.h>
#include <linux/types.h>
#include <asm/global_data.h>
*/
DECLARE_GLOBAL_DATA_PTR;
+/**
+ * fdt_getprop_u32_default - Find a node and return it's property or a default
+ *
+ * @fdt: ptr to device tree
+ * @path: path of node
+ * @prop: property name
+ * @dflt: default value if the property isn't found
+ *
+ * Convenience function to find a node and return it's property or a
+ * default value if it doesn't exist.
+ */
+u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop,
+ const u32 dflt)
+{
+ const u32 *val;
+ int off;
+
+ off = fdt_path_offset(fdt, path);
+ if (off < 0)
+ return dflt;
+
+ val = fdt_getprop(fdt, off, prop, NULL);
+ if (val)
+ return *val;
+ else
+ return dflt;
+}
/**
* fdt_find_and_setprop: Find a node and set it's property
}
#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;
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) {
}
#endif
-int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
+int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
{
int nodeoffset;
- int err;
- u32 tmp; /* used to set 32 bit integer properties */
- char *str; /* used to set string properties */
+ int err, j, total;
+ u32 tmp;
const char *path;
+ uint64_t addr, size;
- err = fdt_check_header(fdt);
- if (err < 0) {
- printf("fdt_chosen: %s\n", fdt_strerror(err));
- return err;
+ /* Find the "chosen" node. */
+ nodeoffset = fdt_path_offset (fdt, "/chosen");
+
+ /* If there is no "chosen" node in the blob return */
+ if (nodeoffset < 0) {
+ printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
+ return nodeoffset;
}
- if (initrd_start && initrd_end) {
- uint64_t addr, size;
- int total = fdt_num_mem_rsv(fdt);
- int j;
+ /* just return if initrd_start/end aren't valid */
+ if ((initrd_start == 0) || (initrd_end == 0))
+ return 0;
- /*
- * Look for an existing entry and update it. If we don't find
- * the entry, we will j be the next available slot.
- */
- for (j = 0; j < total; j++) {
- err = fdt_get_mem_rsv(fdt, j, &addr, &size);
- if (addr == initrd_start) {
- fdt_del_mem_rsv(fdt, j);
- break;
- }
+ total = fdt_num_mem_rsv(fdt);
+
+ /*
+ * Look for an existing entry and update it. If we don't find
+ * the entry, we will j be the next available slot.
+ */
+ for (j = 0; j < total; j++) {
+ err = fdt_get_mem_rsv(fdt, j, &addr, &size);
+ if (addr == initrd_start) {
+ fdt_del_mem_rsv(fdt, j);
+ break;
}
+ }
+
+ err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
+ if (err < 0) {
+ printf("fdt_initrd: %s\n", fdt_strerror(err));
+ return err;
+ }
- err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
+ path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
+ if ((path == NULL) || force) {
+ tmp = __cpu_to_be32(initrd_start);
+ err = fdt_setprop(fdt, nodeoffset,
+ "linux,initrd-start", &tmp, sizeof(tmp));
if (err < 0) {
- printf("fdt_chosen: %s\n", fdt_strerror(err));
+ printf("WARNING: "
+ "could not set linux,initrd-start %s.\n",
+ fdt_strerror(err));
+ return err;
+ }
+ tmp = __cpu_to_be32(initrd_end);
+ err = fdt_setprop(fdt, nodeoffset,
+ "linux,initrd-end", &tmp, sizeof(tmp));
+ if (err < 0) {
+ printf("WARNING: could not set linux,initrd-end %s.\n",
+ fdt_strerror(err));
+
return err;
}
}
+ return 0;
+}
+
+int fdt_chosen(void *fdt, int force)
+{
+ int nodeoffset;
+ int err;
+ char *str; /* used to set string properties */
+ const char *path;
+
+ err = fdt_check_header(fdt);
+ if (err < 0) {
+ printf("fdt_chosen: %s\n", fdt_strerror(err));
+ return err;
+ }
+
/*
* Find the "chosen" node.
*/
fdt_strerror(err));
}
}
- if (initrd_start && initrd_end) {
- path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
- if ((path == NULL) || force) {
- tmp = __cpu_to_be32(initrd_start);
- err = fdt_setprop(fdt, nodeoffset,
- "linux,initrd-start", &tmp, sizeof(tmp));
- if (err < 0)
- printf("WARNING: "
- "could not set linux,initrd-start %s.\n",
- fdt_strerror(err));
- tmp = __cpu_to_be32(initrd_end);
- err = fdt_setprop(fdt, nodeoffset,
- "linux,initrd-end", &tmp, sizeof(tmp));
- if (err < 0)
- printf("WARNING: could not set linux,initrd-end %s.\n",
- fdt_strerror(err));
- }
- }
#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
}
#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
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)
+{
+ int i;
+ uint64_t addr, size;
+ int total, ret;
+ uint actualsize;
+
+ if (!blob)
+ return 0;
+
+ total = fdt_num_mem_rsv(blob);
+ for (i = 0; i < total; i++) {
+ fdt_get_mem_rsv(blob, i, &addr, &size);
+ if (addr == (uint64_t)(u32)blob) {
+ fdt_del_mem_rsv(blob, i);
+ break;
+ }
+ }
+
+ /*
+ * Calculate the actual size of the fdt
+ * 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) + 2*sizeof(struct fdt_reserve_entry);
+
+ /* Make it so the fdt ends on a page boundary */
+ actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
+ actualsize = actualsize - ((uint)blob & 0xfff);
+
+ /* Change the fdt header to reflect the correct size */
+ fdt_set_totalsize(blob, actualsize);
+
+ /* Add the new reservation */
+ ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize);
+ if (ret < 0)
+ return ret;
+
+ return actualsize;
+}
+
+#ifdef CONFIG_PCI
+#define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
+
+#define FDT_PCI_PREFETCH (0x40000000)
+#define FDT_PCI_MEM32 (0x02000000)
+#define FDT_PCI_IO (0x01000000)
+#define FDT_PCI_MEM64 (0x03000000)
+
+int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
+
+ int addrcell, sizecell, len, r;
+ u32 *dma_range;
+ /* sized based on pci addr cells, size-cells, & address-cells */
+ u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
+
+ addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
+ sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
+
+ dma_range = &dma_ranges[0];
+ for (r = 0; r < hose->region_count; r++) {
+ u64 bus_start, phys_start, size;
+
+ /* skip if !PCI_REGION_SYS_MEMORY */
+ if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
+ continue;
+
+ bus_start = (u64)hose->regions[r].bus_start;
+ phys_start = (u64)hose->regions[r].phys_start;
+ size = (u64)hose->regions[r].size;
+
+ dma_range[0] = 0;
+ if (size >= 0x100000000ull)
+ dma_range[0] |= FDT_PCI_MEM64;
+ else
+ dma_range[0] |= FDT_PCI_MEM32;
+ if (hose->regions[r].flags & PCI_REGION_PREFETCH)
+ dma_range[0] |= FDT_PCI_PREFETCH;
+#ifdef CONFIG_SYS_PCI_64BIT
+ dma_range[1] = bus_start >> 32;
+#else
+ dma_range[1] = 0;
+#endif
+ dma_range[2] = bus_start & 0xffffffff;
+
+ if (addrcell == 2) {
+ dma_range[3] = phys_start >> 32;
+ dma_range[4] = phys_start & 0xffffffff;
+ } else {
+ dma_range[3] = phys_start & 0xffffffff;
+ }
+
+ if (sizecell == 2) {
+ dma_range[3 + addrcell + 0] = size >> 32;
+ dma_range[3 + addrcell + 1] = size & 0xffffffff;
+ } else {
+ dma_range[3 + addrcell + 0] = size & 0xffffffff;
+ }
+
+ dma_range += (3 + addrcell + sizecell);
+ }
+
+ len = dma_range - &dma_ranges[0];
+ if (len)
+ fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
+
+ 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