X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Ffdt_support.c;h=9a6f6b7d8b16c822496c53a62df26d3850081b29;hb=dfdb3d37dd0fa8bdabdf7b5ffb597af470e74621;hp=aef4fe23e058c0294a714bc1313725d7c1ddeea3;hpb=f91506e28387fece392b5dd3bb3aa309e4ce7e4d;p=karo-tx-uboot.git diff --git a/common/fdt_support.c b/common/fdt_support.c index aef4fe23e0..9a6f6b7d8b 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -2,7 +2,7 @@ * (C) Copyright 2007 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com * - * Copyright 2010 Freescale Semiconductor, Inc. + * Copyright 2010-2011 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -49,10 +48,10 @@ DECLARE_GLOBAL_DATA_PTR; * 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) +u32 fdt_getprop_u32_default(const void *fdt, const char *path, + const char *prop, const u32 dflt) { - const u32 *val; + const fdt32_t *val; int off; off = fdt_path_offset(fdt, path); @@ -61,7 +60,7 @@ u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop, val = fdt_getprop(fdt, off, prop, NULL); if (val) - return *val; + return fdt32_to_cpu(*val); else return dflt; } @@ -86,7 +85,7 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, if (nodeoff < 0) return nodeoff; - if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL)) + if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL)) return 0; /* create flag not set; so exit quietly */ return fdt_setprop(fdt, nodeoff, prop, val, len); @@ -94,7 +93,7 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, #ifdef CONFIG_OF_STDOUT_VIA_ALIAS -#ifdef CONFIG_SERIAL_MULTI +#ifdef CONFIG_CONS_INDEX static void fdt_fill_multisername(char *sername, size_t maxlen) { const char *outname = stdio_devices[stdout]->name; @@ -106,9 +105,7 @@ static void fdt_fill_multisername(char *sername, size_t maxlen) 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 */ +#endif static int fdt_fixup_stdout(void *fdt, int chosenoff) { @@ -152,7 +149,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force) { int nodeoffset; int err, j, total; - u32 tmp; + fdt32_t tmp; const char *path; uint64_t addr, size; @@ -183,7 +180,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force) } } - err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1); + err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start); if (err < 0) { printf("fdt_initrd: %s\n", fdt_strerror(err)); return err; @@ -191,7 +188,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force) path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL); if ((path == NULL) || force) { - tmp = __cpu_to_be32(initrd_start); + tmp = cpu_to_fdt32(initrd_start); err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp)); if (err < 0) { @@ -200,7 +197,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force) fdt_strerror(err)); return err; } - tmp = __cpu_to_be32(initrd_end); + tmp = cpu_to_fdt32(initrd_end); err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp)); if (err < 0) { @@ -303,8 +300,8 @@ void do_fixup_by_path(void *fdt, const char *path, const char *prop, void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, u32 val, int create) { - val = cpu_to_fdt32(val); - do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create); + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create); } void do_fixup_by_prop(void *fdt, @@ -322,7 +319,7 @@ void do_fixup_by_prop(void *fdt, #endif off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); while (off != -FDT_ERR_NOTFOUND) { - if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) fdt_setprop(fdt, off, prop, val, len); off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); } @@ -332,8 +329,8 @@ void do_fixup_by_prop_u32(void *fdt, const char *pname, const void *pval, int plen, const char *prop, u32 val, int create) { - val = cpu_to_fdt32(val); - do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create); + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create); } void do_fixup_by_compat(void *fdt, const char *compat, @@ -349,7 +346,7 @@ void do_fixup_by_compat(void *fdt, const char *compat, #endif off = fdt_node_offset_by_compatible(fdt, -1, compat); while (off != -FDT_ERR_NOTFOUND) { - if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) + if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL)) fdt_setprop(fdt, off, prop, val, len); off = fdt_node_offset_by_compatible(fdt, off, compat); } @@ -358,15 +355,56 @@ void do_fixup_by_compat(void *fdt, const char *compat, void do_fixup_by_compat_u32(void *fdt, const char *compat, const char *prop, u32 val, int create) { - val = cpu_to_fdt32(val); - do_fixup_by_compat(fdt, compat, prop, &val, 4, create); + fdt32_t tmp = cpu_to_fdt32(val); + do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create); } -int fdt_fixup_memory(void *blob, u64 start, u64 size) +/* + * Get cells len in bytes + * if #NNNN-cells property is 2 then len is 8 + * otherwise len is 4 + */ +static int get_cells_len(void *blob, char *nr_cells_name) { - int err, nodeoffset, len = 0; - u8 tmp[16]; - const u32 *addrcell, *sizecell; + const fdt32_t *cell; + + cell = fdt_getprop(blob, 0, nr_cells_name, NULL); + if (cell && fdt32_to_cpu(*cell) == 2) + return 8; + + return 4; +} + +/* + * Write a 4 or 8 byte big endian cell + */ +static void write_cell(u8 *addr, u64 val, int size) +{ + int shift = (size - 1) * 8; + while (size-- > 0) { + *addr++ = (val >> shift) & 0xff; + shift -= 8; + } +} + +#ifdef CONFIG_NR_DRAM_BANKS +#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS +#else +#define MEMORY_BANKS_MAX 4 +#endif +int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) +{ + int err, nodeoffset; + int addr_cell_len, size_cell_len, len; + u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */ + int bank; + + if (banks > MEMORY_BANKS_MAX) { + printf("%s: num banks %d exceeds hardcoded limit %d." + " Recompile with higher MEMORY_BANKS_MAX?\n", + __FUNCTION__, banks, MEMORY_BANKS_MAX); + return -1; + } err = fdt_check_header(blob); if (err < 0) { @@ -391,44 +429,15 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size) return err; } - addrcell = fdt_getprop(blob, 0, "#address-cells", NULL); - /* use shifts and mask to ensure endianness */ - if ((addrcell) && (*addrcell == 2)) { - tmp[0] = (start >> 56) & 0xff; - tmp[1] = (start >> 48) & 0xff; - tmp[2] = (start >> 40) & 0xff; - tmp[3] = (start >> 32) & 0xff; - tmp[4] = (start >> 24) & 0xff; - tmp[5] = (start >> 16) & 0xff; - tmp[6] = (start >> 8) & 0xff; - tmp[7] = (start ) & 0xff; - len = 8; - } else { - tmp[0] = (start >> 24) & 0xff; - tmp[1] = (start >> 16) & 0xff; - tmp[2] = (start >> 8) & 0xff; - tmp[3] = (start ) & 0xff; - len = 4; - } + addr_cell_len = get_cells_len(blob, "#address-cells"); + size_cell_len = get_cells_len(blob, "#size-cells"); - sizecell = fdt_getprop(blob, 0, "#size-cells", NULL); - /* use shifts and mask to ensure endianness */ - if ((sizecell) && (*sizecell == 2)) { - tmp[0+len] = (size >> 56) & 0xff; - tmp[1+len] = (size >> 48) & 0xff; - tmp[2+len] = (size >> 40) & 0xff; - tmp[3+len] = (size >> 32) & 0xff; - tmp[4+len] = (size >> 24) & 0xff; - tmp[5+len] = (size >> 16) & 0xff; - tmp[6+len] = (size >> 8) & 0xff; - tmp[7+len] = (size ) & 0xff; - len += 8; - } else { - tmp[0+len] = (size >> 24) & 0xff; - tmp[1+len] = (size >> 16) & 0xff; - tmp[2+len] = (size >> 8) & 0xff; - tmp[3+len] = (size ) & 0xff; - len += 4; + for (bank = 0, len = 0; bank < banks; bank++) { + write_cell(tmp + len, start[bank], addr_cell_len); + len += addr_cell_len; + + write_cell(tmp + len, size[bank], size_cell_len); + len += size_cell_len; } err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); @@ -440,11 +449,16 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size) return 0; } +int fdt_fixup_memory(void *blob, u64 start, u64 size) +{ + return fdt_fixup_memory_banks(blob, &start, &size, 1); +} + void fdt_fixup_ethernet(void *fdt) { int node, i, j; char enet[16], *tmp, *end; - char mac[16] = "ethaddr"; + char mac[16]; const char *path; unsigned char mac_addr[6]; @@ -453,6 +467,7 @@ void fdt_fixup_ethernet(void *fdt) return; i = 0; + strcpy(mac, "ethaddr"); while ((tmp = getenv(mac)) != NULL) { sprintf(enet, "ethernet%d", i); path = fdt_getprop(fdt, node, enet, NULL); @@ -490,7 +505,7 @@ int fdt_resize(void *blob) 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) { + if (addr == (uintptr_t)blob) { fdt_del_mem_rsv(blob, i); break; } @@ -506,14 +521,14 @@ int fdt_resize(void *blob) fdt_size_dt_strings(blob) + 5 * 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); + actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000); + actualsize = actualsize - ((uintptr_t)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); + ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize); if (ret < 0) return ret; @@ -590,37 +605,71 @@ int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { #endif #ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE +/* + * Provide a weak default function to return the flash bank size. + * There might be multiple non-identical flash chips connected to one + * chip-select, so we need to pass an index as well. + */ +u32 __flash_get_bank_size(int cs, int idx) +{ + extern flash_info_t flash_info[]; + + /* + * As default, a simple 1:1 mapping is provided. Boards with + * a different mapping need to supply a board specific mapping + * routine. + */ + return flash_info[cs].size; +} +u32 flash_get_bank_size(int cs, int idx) + __attribute__((weak, alias("__flash_get_bank_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 + * of all 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) +int fdt_fixup_nor_flash_size(void *blob) { char compat[][16] = { "cfi-flash", "jedec-flash" }; int off; int len; struct fdt_property *prop; - u32 *reg; + u32 *reg, *reg2; int i; for (i = 0; i < 2; i++) { off = fdt_node_offset_by_compatible(blob, -1, compat[i]); while (off != -FDT_ERR_NOTFOUND) { + int idx; + /* - * Found one compatible node, now check if this one - * has the correct CS + * Found one compatible node, so fixup the size + * int its reg properties */ 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; + int tuple_size = 3 * sizeof(reg); + + /* + * There might be multiple reg-tuples, + * so loop through them all + */ + reg = reg2 = (u32 *)&prop->data[0]; + for (idx = 0; idx < (len / tuple_size); idx++) { + /* + * Update size in reg property + */ + reg[2] = flash_get_bank_size(reg[0], + idx); + + /* + * Point to next reg tuple + */ + reg += 3; } + + fdt_setprop(blob, off, "reg", reg2, len); } /* Move to next compatible node */ @@ -629,10 +678,20 @@ int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size) } } - return -1; + return 0; } #endif +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); +} + #ifdef CONFIG_FDT_FIXUP_PARTITIONS #include #include @@ -667,16 +726,6 @@ int fdt_del_subnodes(const void *blob, int 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; @@ -866,11 +915,11 @@ void fdt_del_node_and_alias(void *blob, const char *alias) } /* Helper to read a big number; size is in cells (not bytes) */ -static inline u64 of_read_number(const __be32 *cell, int size) +static inline u64 of_read_number(const fdt32_t *cell, int size) { u64 r = 0; while (size--) - r = (r << 32) | be32_to_cpu(*(cell++)); + r = (r << 32) | fdt32_to_cpu(*(cell++)); return r; } @@ -884,7 +933,7 @@ static inline u64 of_read_number(const __be32 *cell, int size) /* Debug utility */ #ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { printf("%s", s); while(na--) @@ -892,7 +941,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na) printf("\n"); } #else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } +static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } #endif /* Callbacks for bus specific translators */ @@ -901,16 +950,16 @@ struct of_bus { const char *addresses; void (*count_cells)(void *blob, int parentoffset, int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, + u64 (*map)(fdt32_t *addr, const fdt32_t *range, int na, int ns, int pna); - int (*translate)(u32 *addr, u64 offset, int na); + int (*translate)(fdt32_t *addr, u64 offset, int na); }; /* Default translator (generic bus) */ static void of_bus_default_count_cells(void *blob, int parentoffset, int *addrc, int *sizec) { - const u32 *prop; + const fdt32_t *prop; if (addrc) { prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL); @@ -929,7 +978,7 @@ static void of_bus_default_count_cells(void *blob, int parentoffset, } } -static u64 of_bus_default_map(u32 *addr, const u32 *range, +static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, int na, int ns, int pna) { u64 cp, s, da; @@ -946,14 +995,14 @@ static u64 of_bus_default_map(u32 *addr, const u32 *range, return da - cp; } -static int of_bus_default_translate(u32 *addr, u64 offset, int na) +static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) { u64 a = of_read_number(addr, na); memset(addr, 0, na * 4); a += offset; if (na > 1) - addr[na - 2] = a >> 32; - addr[na - 1] = a & 0xffffffffu; + addr[na - 2] = cpu_to_fdt32(a >> 32); + addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); return 0; } @@ -971,10 +1020,10 @@ static struct of_bus of_busses[] = { }; static int of_translate_one(void * blob, int parent, struct of_bus *bus, - struct of_bus *pbus, u32 *addr, + struct of_bus *pbus, fdt32_t *addr, int na, int ns, int pna, const char *rprop) { - const u32 *ranges; + const fdt32_t *ranges; int rlen; int rone; u64 offset = OF_BAD_ADDR; @@ -991,7 +1040,7 @@ static int of_translate_one(void * blob, int parent, struct of_bus *bus, * to translate addresses that aren't supposed to be translated in * the first place. --BenH. */ - ranges = (u32 *)fdt_getprop(blob, parent, rprop, &rlen); + ranges = fdt_getprop(blob, parent, rprop, &rlen); if (ranges == NULL || rlen == 0) { offset = of_read_number(addr, na); memset(addr, 0, pna * 4); @@ -1033,12 +1082,12 @@ static int of_translate_one(void * blob, int parent, struct of_bus *bus, * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things */ -u64 __of_translate_address(void *blob, int node_offset, const u32 *in_addr, - const char *rprop) +static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in_addr, + const char *rprop) { int parent; struct of_bus *bus, *pbus; - u32 addr[OF_MAX_ADDR_CELLS]; + fdt32_t addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns; u64 result = OF_BAD_ADDR; @@ -1106,7 +1155,7 @@ u64 __of_translate_address(void *blob, int node_offset, const u32 *in_addr, return result; } -u64 fdt_translate_address(void *blob, int node_offset, const u32 *in_addr) +u64 fdt_translate_address(void *blob, int node_offset, const fdt32_t *in_addr) { return __of_translate_address(blob, node_offset, in_addr, "ranges"); } @@ -1125,7 +1174,7 @@ int fdt_node_offset_by_compat_reg(void *blob, const char *compat, { int len, off = fdt_node_offset_by_compatible(blob, -1, compat); while (off != -FDT_ERR_NOTFOUND) { - u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", &len); + const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len); if (reg) { if (compat_off == fdt_translate_address(blob, off, reg)) return off; @@ -1143,15 +1192,233 @@ int fdt_node_offset_by_compat_reg(void *blob, const char *compat, */ int fdt_alloc_phandle(void *blob) { - int offset, len, phandle = 0; - const u32 *val; + int offset, phandle = 0; for (offset = fdt_next_node(blob, -1, NULL); offset >= 0; offset = fdt_next_node(blob, offset, NULL)) { - val = fdt_getprop(blob, offset, "linux,phandle", &len); - if (val) - phandle = max(*val, phandle); + phandle = max(phandle, fdt_get_phandle(blob, offset)); } return phandle + 1; } + +/* + * fdt_set_phandle: Create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @phandle: phandle value to set (must be unique) + */ +int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle) +{ + int ret; + +#ifdef DEBUG + int off = fdt_node_offset_by_phandle(fdt, phandle); + + if ((off >= 0) && (off != nodeoffset)) { + char buf[64]; + + fdt_get_path(fdt, nodeoffset, buf, sizeof(buf)); + printf("Trying to update node %s with phandle %u ", + buf, phandle); + + fdt_get_path(fdt, off, buf, sizeof(buf)); + printf("that already exists in node %s.\n", buf); + return -FDT_ERR_BADPHANDLE; + } +#endif + + ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle); + if (ret < 0) + return ret; + + /* + * For now, also set the deprecated "linux,phandle" property, so that we + * don't break older kernels. + */ + ret = fdt_setprop_cell(fdt, nodeoffset, "linux,phandle", phandle); + + return ret; +} + +/* + * fdt_create_phandle: Create a phandle property for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + */ +unsigned int fdt_create_phandle(void *fdt, int nodeoffset) +{ + /* see if there is a phandle already */ + int phandle = fdt_get_phandle(fdt, nodeoffset); + + /* if we got 0, means no phandle so create one */ + if (phandle == 0) { + int ret; + + phandle = fdt_alloc_phandle(fdt); + ret = fdt_set_phandle(fdt, nodeoffset, phandle); + if (ret < 0) { + printf("Can't set phandle %u: %s\n", phandle, + fdt_strerror(ret)); + return 0; + } + } + + return phandle; +} + +/* + * fdt_set_node_status: Set status for the given node + * + * @fdt: ptr to device tree + * @nodeoffset: node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, + * FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE + * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE + */ +int fdt_set_node_status(void *fdt, int nodeoffset, + enum fdt_status status, unsigned int error_code) +{ + char buf[16]; + int ret = 0; + + if (nodeoffset < 0) + return nodeoffset; + + switch (status) { + case FDT_STATUS_OKAY: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay"); + break; + case FDT_STATUS_DISABLED: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled"); + break; + case FDT_STATUS_FAIL: + ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail"); + break; + case FDT_STATUS_FAIL_ERROR_CODE: + sprintf(buf, "fail-%d", error_code); + ret = fdt_setprop_string(fdt, nodeoffset, "status", buf); + break; + default: + printf("Invalid fdt status: %x\n", status); + ret = -1; + break; + } + + return ret; +} + +/* + * fdt_set_status_by_alias: Set status for the given node given an alias + * + * @fdt: ptr to device tree + * @alias: alias of node to update + * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, + * FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE + * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE + */ +int fdt_set_status_by_alias(void *fdt, const char* alias, + enum fdt_status status, unsigned int error_code) +{ + int offset = fdt_path_offset(fdt, alias); + + return fdt_set_node_status(fdt, offset, status, error_code); +} + +#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD) +int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf) +{ + int noff; + int ret; + + noff = fdt_node_offset_by_compatible(blob, -1, compat); + if (noff != -FDT_ERR_NOTFOUND) { + debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat); +add_edid: + ret = fdt_setprop(blob, noff, "edid", edid_buf, 128); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (!ret) + goto add_edid; + else + goto err_size; + } else if (ret < 0) { + printf("Can't add property: %s\n", fdt_strerror(ret)); + return ret; + } + } + return 0; +err_size: + printf("Can't increase blob size: %s\n", fdt_strerror(ret)); + return ret; +} +#endif + +/* + * Verify the physical address of device tree node for a given alias + * + * This function locates the device tree node of a given alias, and then + * verifies that the physical address of that device matches the given + * parameter. It displays a message if there is a mismatch. + * + * Returns 1 on success, 0 on failure + */ +int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) +{ + const char *path; + const fdt32_t *reg; + int node, len; + u64 dt_addr; + + path = fdt_getprop(fdt, anode, alias, NULL); + if (!path) { + /* If there's no such alias, then it's not a failure */ + return 1; + } + + node = fdt_path_offset(fdt, path); + if (node < 0) { + printf("Warning: device tree alias '%s' points to invalid " + "node %s.\n", alias, path); + return 0; + } + + reg = fdt_getprop(fdt, node, "reg", &len); + if (!reg) { + printf("Warning: device tree node '%s' has no address.\n", + path); + return 0; + } + + dt_addr = fdt_translate_address(fdt, node, reg); + if (addr != dt_addr) { + printf("Warning: U-Boot configured device %s at address %llx,\n" + " but the device tree has it address %llx.\n", + alias, addr, dt_addr); + return 0; + } + + return 1; +} + +/* + * Returns the base address of an SOC or PCI node + */ +u64 fdt_get_base_address(void *fdt, int node) +{ + int size; + u32 naddr; + const fdt32_t *prop; + + prop = fdt_getprop(fdt, node, "#address-cells", &size); + if (prop && size == 4) + naddr = be32_to_cpup(prop); + else + naddr = 2; + + prop = fdt_getprop(fdt, node, "ranges", &size); + + return prop ? fdt_translate_address(fdt, node, prop + naddr) : 0; +}