164dbbd40SGerald Van Baren /* 264dbbd40SGerald Van Baren * (C) Copyright 2007 364dbbd40SGerald Van Baren * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 464dbbd40SGerald Van Baren * 564dbbd40SGerald Van Baren * See file CREDITS for list of people who contributed to this 664dbbd40SGerald Van Baren * project. 764dbbd40SGerald Van Baren * 864dbbd40SGerald Van Baren * This program is free software; you can redistribute it and/or 964dbbd40SGerald Van Baren * modify it under the terms of the GNU General Public License as 1064dbbd40SGerald Van Baren * published by the Free Software Foundation; either version 2 of 1164dbbd40SGerald Van Baren * the License, or (at your option) any later version. 1264dbbd40SGerald Van Baren * 1364dbbd40SGerald Van Baren * This program is distributed in the hope that it will be useful, 1464dbbd40SGerald Van Baren * but WITHOUT ANY WARRANTY; without even the implied warranty of 1564dbbd40SGerald Van Baren * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1664dbbd40SGerald Van Baren * GNU General Public License for more details. 1764dbbd40SGerald Van Baren * 1864dbbd40SGerald Van Baren * You should have received a copy of the GNU General Public License 1964dbbd40SGerald Van Baren * along with this program; if not, write to the Free Software 2064dbbd40SGerald Van Baren * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 2164dbbd40SGerald Van Baren * MA 02111-1307 USA 2264dbbd40SGerald Van Baren */ 2364dbbd40SGerald Van Baren 2464dbbd40SGerald Van Baren #include <common.h> 2564dbbd40SGerald Van Baren #include <linux/ctype.h> 2664dbbd40SGerald Van Baren #include <linux/types.h> 2764dbbd40SGerald Van Baren #include <asm/global_data.h> 2864dbbd40SGerald Van Baren #include <fdt.h> 2964dbbd40SGerald Van Baren #include <libfdt.h> 3064dbbd40SGerald Van Baren #include <fdt_support.h> 31151c8b09SKumar Gala #include <exports.h> 3264dbbd40SGerald Van Baren 3364dbbd40SGerald Van Baren /* 3464dbbd40SGerald Van Baren * Global data (for the gd->bd) 3564dbbd40SGerald Van Baren */ 3664dbbd40SGerald Van Baren DECLARE_GLOBAL_DATA_PTR; 3764dbbd40SGerald Van Baren 383bed2aafSKumar Gala /** 393bed2aafSKumar Gala * fdt_getprop_u32_default - Find a node and return it's property or a default 403bed2aafSKumar Gala * 413bed2aafSKumar Gala * @fdt: ptr to device tree 423bed2aafSKumar Gala * @path: path of node 433bed2aafSKumar Gala * @prop: property name 443bed2aafSKumar Gala * @dflt: default value if the property isn't found 453bed2aafSKumar Gala * 463bed2aafSKumar Gala * Convenience function to find a node and return it's property or a 473bed2aafSKumar Gala * default value if it doesn't exist. 483bed2aafSKumar Gala */ 493bed2aafSKumar Gala u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop, 503bed2aafSKumar Gala const u32 dflt) 513bed2aafSKumar Gala { 523bed2aafSKumar Gala const u32 *val; 533bed2aafSKumar Gala int off; 543bed2aafSKumar Gala 553bed2aafSKumar Gala off = fdt_path_offset(fdt, path); 563bed2aafSKumar Gala if (off < 0) 573bed2aafSKumar Gala return dflt; 583bed2aafSKumar Gala 593bed2aafSKumar Gala val = fdt_getprop(fdt, off, prop, NULL); 603bed2aafSKumar Gala if (val) 613bed2aafSKumar Gala return *val; 623bed2aafSKumar Gala else 633bed2aafSKumar Gala return dflt; 643bed2aafSKumar Gala } 6564dbbd40SGerald Van Baren 66a3c2933eSKumar Gala /** 67a3c2933eSKumar Gala * fdt_find_and_setprop: Find a node and set it's property 68a3c2933eSKumar Gala * 69a3c2933eSKumar Gala * @fdt: ptr to device tree 70a3c2933eSKumar Gala * @node: path of node 71a3c2933eSKumar Gala * @prop: property name 72a3c2933eSKumar Gala * @val: ptr to new value 73a3c2933eSKumar Gala * @len: length of new property value 74a3c2933eSKumar Gala * @create: flag to create the property if it doesn't exist 75a3c2933eSKumar Gala * 76a3c2933eSKumar Gala * Convenience function to directly set a property given the path to the node. 77a3c2933eSKumar Gala */ 78a3c2933eSKumar Gala int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, 79a3c2933eSKumar Gala const void *val, int len, int create) 80a3c2933eSKumar Gala { 818d04f02fSKumar Gala int nodeoff = fdt_path_offset(fdt, node); 82a3c2933eSKumar Gala 83a3c2933eSKumar Gala if (nodeoff < 0) 84a3c2933eSKumar Gala return nodeoff; 85a3c2933eSKumar Gala 86a3c2933eSKumar Gala if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL)) 87a3c2933eSKumar Gala return 0; /* create flag not set; so exit quietly */ 88a3c2933eSKumar Gala 89a3c2933eSKumar Gala return fdt_setprop(fdt, nodeoff, prop, val, len); 90a3c2933eSKumar Gala } 91a3c2933eSKumar Gala 92151c8b09SKumar Gala #ifdef CONFIG_OF_STDOUT_VIA_ALIAS 9340777812SDetlev Zundel static int fdt_fixup_stdout(void *fdt, int chosenoff) 94151c8b09SKumar Gala { 95151c8b09SKumar Gala int err = 0; 96151c8b09SKumar Gala #ifdef CONFIG_CONS_INDEX 97151c8b09SKumar Gala int node; 98151c8b09SKumar Gala char sername[9] = { 0 }; 99151c8b09SKumar Gala const char *path; 100151c8b09SKumar Gala 101151c8b09SKumar Gala sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); 102151c8b09SKumar Gala 103151c8b09SKumar Gala err = node = fdt_path_offset(fdt, "/aliases"); 104151c8b09SKumar Gala if (node >= 0) { 105151c8b09SKumar Gala int len; 106151c8b09SKumar Gala path = fdt_getprop(fdt, node, sername, &len); 107151c8b09SKumar Gala if (path) { 108151c8b09SKumar Gala char *p = malloc(len); 109151c8b09SKumar Gala err = -FDT_ERR_NOSPACE; 110151c8b09SKumar Gala if (p) { 111151c8b09SKumar Gala memcpy(p, path, len); 11240777812SDetlev Zundel err = fdt_setprop(fdt, chosenoff, 113151c8b09SKumar Gala "linux,stdout-path", p, len); 114151c8b09SKumar Gala free(p); 115151c8b09SKumar Gala } 116151c8b09SKumar Gala } else { 117151c8b09SKumar Gala err = len; 118151c8b09SKumar Gala } 119151c8b09SKumar Gala } 120151c8b09SKumar Gala #endif 121151c8b09SKumar Gala if (err < 0) 122151c8b09SKumar Gala printf("WARNING: could not set linux,stdout-path %s.\n", 123151c8b09SKumar Gala fdt_strerror(err)); 124151c8b09SKumar Gala 125151c8b09SKumar Gala return err; 126151c8b09SKumar Gala } 127151c8b09SKumar Gala #endif 128151c8b09SKumar Gala 1292a1a2cb6SKumar Gala int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force) 13064dbbd40SGerald Van Baren { 13164dbbd40SGerald Van Baren int nodeoffset; 1322a1a2cb6SKumar Gala int err, j, total; 1332a1a2cb6SKumar Gala u32 tmp; 134b60af3d4SGerald Van Baren const char *path; 1352a1a2cb6SKumar Gala uint64_t addr, size; 13664dbbd40SGerald Van Baren 1372a1a2cb6SKumar Gala /* Find the "chosen" node. */ 1382a1a2cb6SKumar Gala nodeoffset = fdt_path_offset (fdt, "/chosen"); 1392a1a2cb6SKumar Gala 1402a1a2cb6SKumar Gala /* If there is no "chosen" node in the blob return */ 1412a1a2cb6SKumar Gala if (nodeoffset < 0) { 1422a1a2cb6SKumar Gala printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset)); 1432a1a2cb6SKumar Gala return nodeoffset; 14464dbbd40SGerald Van Baren } 14564dbbd40SGerald Van Baren 1462a1a2cb6SKumar Gala /* just return if initrd_start/end aren't valid */ 1472a1a2cb6SKumar Gala if ((initrd_start == 0) || (initrd_end == 0)) 1482a1a2cb6SKumar Gala return 0; 1492a1a2cb6SKumar Gala 1502a1a2cb6SKumar Gala total = fdt_num_mem_rsv(fdt); 151c28abb9cSGerald Van Baren 152c28abb9cSGerald Van Baren /* 153c28abb9cSGerald Van Baren * Look for an existing entry and update it. If we don't find 154c28abb9cSGerald Van Baren * the entry, we will j be the next available slot. 155c28abb9cSGerald Van Baren */ 1568d04f02fSKumar Gala for (j = 0; j < total; j++) { 1578d04f02fSKumar Gala err = fdt_get_mem_rsv(fdt, j, &addr, &size); 1588d04f02fSKumar Gala if (addr == initrd_start) { 1598d04f02fSKumar Gala fdt_del_mem_rsv(fdt, j); 160c28abb9cSGerald Van Baren break; 161c28abb9cSGerald Van Baren } 162c28abb9cSGerald Van Baren } 1638d04f02fSKumar Gala 1648d04f02fSKumar Gala err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1); 16564dbbd40SGerald Van Baren if (err < 0) { 1662a1a2cb6SKumar Gala printf("fdt_initrd: %s\n", fdt_strerror(err)); 16764dbbd40SGerald Van Baren return err; 16864dbbd40SGerald Van Baren } 1692a1a2cb6SKumar Gala 1702a1a2cb6SKumar Gala path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL); 1712a1a2cb6SKumar Gala if ((path == NULL) || force) { 1722a1a2cb6SKumar Gala tmp = __cpu_to_be32(initrd_start); 1732a1a2cb6SKumar Gala err = fdt_setprop(fdt, nodeoffset, 1742a1a2cb6SKumar Gala "linux,initrd-start", &tmp, sizeof(tmp)); 1752a1a2cb6SKumar Gala if (err < 0) { 1762a1a2cb6SKumar Gala printf("WARNING: " 1772a1a2cb6SKumar Gala "could not set linux,initrd-start %s.\n", 1782a1a2cb6SKumar Gala fdt_strerror(err)); 1792a1a2cb6SKumar Gala return err; 1802a1a2cb6SKumar Gala } 1812a1a2cb6SKumar Gala tmp = __cpu_to_be32(initrd_end); 1822a1a2cb6SKumar Gala err = fdt_setprop(fdt, nodeoffset, 1832a1a2cb6SKumar Gala "linux,initrd-end", &tmp, sizeof(tmp)); 1842a1a2cb6SKumar Gala if (err < 0) { 1852a1a2cb6SKumar Gala printf("WARNING: could not set linux,initrd-end %s.\n", 1862a1a2cb6SKumar Gala fdt_strerror(err)); 1872a1a2cb6SKumar Gala 1882a1a2cb6SKumar Gala return err; 1892a1a2cb6SKumar Gala } 1902a1a2cb6SKumar Gala } 1912a1a2cb6SKumar Gala 1922a1a2cb6SKumar Gala return 0; 1932a1a2cb6SKumar Gala } 1942a1a2cb6SKumar Gala 19556844a22SHeiko Schocher int fdt_chosen(void *fdt, int force) 1962a1a2cb6SKumar Gala { 1972a1a2cb6SKumar Gala int nodeoffset; 1982a1a2cb6SKumar Gala int err; 1992a1a2cb6SKumar Gala char *str; /* used to set string properties */ 2002a1a2cb6SKumar Gala const char *path; 2012a1a2cb6SKumar Gala 2022a1a2cb6SKumar Gala err = fdt_check_header(fdt); 2032a1a2cb6SKumar Gala if (err < 0) { 2042a1a2cb6SKumar Gala printf("fdt_chosen: %s\n", fdt_strerror(err)); 2052a1a2cb6SKumar Gala return err; 20664dbbd40SGerald Van Baren } 20764dbbd40SGerald Van Baren 20864dbbd40SGerald Van Baren /* 20964dbbd40SGerald Van Baren * Find the "chosen" node. 21064dbbd40SGerald Van Baren */ 2118d04f02fSKumar Gala nodeoffset = fdt_path_offset (fdt, "/chosen"); 21264dbbd40SGerald Van Baren 21364dbbd40SGerald Van Baren /* 214b60af3d4SGerald Van Baren * If there is no "chosen" node in the blob, create it. 21564dbbd40SGerald Van Baren */ 21664dbbd40SGerald Van Baren if (nodeoffset < 0) { 21764dbbd40SGerald Van Baren /* 21864dbbd40SGerald Van Baren * Create a new node "/chosen" (offset 0 is root level) 21964dbbd40SGerald Van Baren */ 22064dbbd40SGerald Van Baren nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); 22164dbbd40SGerald Van Baren if (nodeoffset < 0) { 2225fe6be62SGerald Van Baren printf("WARNING: could not create /chosen %s.\n", 22335ec398fSGerald Van Baren fdt_strerror(nodeoffset)); 22464dbbd40SGerald Van Baren return nodeoffset; 22564dbbd40SGerald Van Baren } 22664dbbd40SGerald Van Baren } 22764dbbd40SGerald Van Baren 22864dbbd40SGerald Van Baren /* 229b60af3d4SGerald Van Baren * Create /chosen properites that don't exist in the fdt. 230b60af3d4SGerald Van Baren * If the property exists, update it only if the "force" parameter 231b60af3d4SGerald Van Baren * is true. 23264dbbd40SGerald Van Baren */ 23364dbbd40SGerald Van Baren str = getenv("bootargs"); 23464dbbd40SGerald Van Baren if (str != NULL) { 235b60af3d4SGerald Van Baren path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL); 236b60af3d4SGerald Van Baren if ((path == NULL) || force) { 23735ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 23835ec398fSGerald Van Baren "bootargs", str, strlen(str)+1); 23964dbbd40SGerald Van Baren if (err < 0) 2405fe6be62SGerald Van Baren printf("WARNING: could not set bootargs %s.\n", 24135ec398fSGerald Van Baren fdt_strerror(err)); 24264dbbd40SGerald Van Baren } 243b60af3d4SGerald Van Baren } 2442a1a2cb6SKumar Gala 245151c8b09SKumar Gala #ifdef CONFIG_OF_STDOUT_VIA_ALIAS 246b60af3d4SGerald Van Baren path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL); 247b60af3d4SGerald Van Baren if ((path == NULL) || force) 248151c8b09SKumar Gala err = fdt_fixup_stdout(fdt, nodeoffset); 249151c8b09SKumar Gala #endif 250151c8b09SKumar Gala 25164dbbd40SGerald Van Baren #ifdef OF_STDOUT_PATH 252b60af3d4SGerald Van Baren path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL); 253b60af3d4SGerald Van Baren if ((path == NULL) || force) { 25435ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 25535ec398fSGerald Van Baren "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); 25664dbbd40SGerald Van Baren if (err < 0) 2575fe6be62SGerald Van Baren printf("WARNING: could not set linux,stdout-path %s.\n", 25835ec398fSGerald Van Baren fdt_strerror(err)); 259b60af3d4SGerald Van Baren } 26064dbbd40SGerald Van Baren #endif 26164dbbd40SGerald Van Baren 26264dbbd40SGerald Van Baren return err; 26364dbbd40SGerald Van Baren } 26464dbbd40SGerald Van Baren 265e93becf8SKumar Gala void do_fixup_by_path(void *fdt, const char *path, const char *prop, 266e93becf8SKumar Gala const void *val, int len, int create) 267e93becf8SKumar Gala { 268e93becf8SKumar Gala #if defined(DEBUG) 269e93becf8SKumar Gala int i; 270d9ad115bSKumar Gala debug("Updating property '%s/%s' = ", path, prop); 271e93becf8SKumar Gala for (i = 0; i < len; i++) 272e93becf8SKumar Gala debug(" %.2x", *(u8*)(val+i)); 273e93becf8SKumar Gala debug("\n"); 274e93becf8SKumar Gala #endif 275e93becf8SKumar Gala int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); 276e93becf8SKumar Gala if (rc) 277e93becf8SKumar Gala printf("Unable to update property %s:%s, err=%s\n", 278e93becf8SKumar Gala path, prop, fdt_strerror(rc)); 279e93becf8SKumar Gala } 280e93becf8SKumar Gala 281e93becf8SKumar Gala void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, 282e93becf8SKumar Gala u32 val, int create) 283e93becf8SKumar Gala { 284e93becf8SKumar Gala val = cpu_to_fdt32(val); 285e93becf8SKumar Gala do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create); 286e93becf8SKumar Gala } 287e93becf8SKumar Gala 2889eb77ceaSKumar Gala void do_fixup_by_prop(void *fdt, 2899eb77ceaSKumar Gala const char *pname, const void *pval, int plen, 2909eb77ceaSKumar Gala const char *prop, const void *val, int len, 2919eb77ceaSKumar Gala int create) 2929eb77ceaSKumar Gala { 2939eb77ceaSKumar Gala int off; 2949eb77ceaSKumar Gala #if defined(DEBUG) 2959eb77ceaSKumar Gala int i; 296d9ad115bSKumar Gala debug("Updating property '%s' = ", prop); 2979eb77ceaSKumar Gala for (i = 0; i < len; i++) 2989eb77ceaSKumar Gala debug(" %.2x", *(u8*)(val+i)); 2999eb77ceaSKumar Gala debug("\n"); 3009eb77ceaSKumar Gala #endif 3019eb77ceaSKumar Gala off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); 3029eb77ceaSKumar Gala while (off != -FDT_ERR_NOTFOUND) { 3039eb77ceaSKumar Gala if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) 3049eb77ceaSKumar Gala fdt_setprop(fdt, off, prop, val, len); 3059eb77ceaSKumar Gala off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); 3069eb77ceaSKumar Gala } 3079eb77ceaSKumar Gala } 3089eb77ceaSKumar Gala 3099eb77ceaSKumar Gala void do_fixup_by_prop_u32(void *fdt, 3109eb77ceaSKumar Gala const char *pname, const void *pval, int plen, 3119eb77ceaSKumar Gala const char *prop, u32 val, int create) 3129eb77ceaSKumar Gala { 3139eb77ceaSKumar Gala val = cpu_to_fdt32(val); 3149eb77ceaSKumar Gala do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create); 3159eb77ceaSKumar Gala } 3169eb77ceaSKumar Gala 3179eb77ceaSKumar Gala void do_fixup_by_compat(void *fdt, const char *compat, 3189eb77ceaSKumar Gala const char *prop, const void *val, int len, int create) 3199eb77ceaSKumar Gala { 3209eb77ceaSKumar Gala int off = -1; 3219eb77ceaSKumar Gala #if defined(DEBUG) 3229eb77ceaSKumar Gala int i; 323d9ad115bSKumar Gala debug("Updating property '%s' = ", prop); 3249eb77ceaSKumar Gala for (i = 0; i < len; i++) 3259eb77ceaSKumar Gala debug(" %.2x", *(u8*)(val+i)); 3269eb77ceaSKumar Gala debug("\n"); 3279eb77ceaSKumar Gala #endif 3289eb77ceaSKumar Gala off = fdt_node_offset_by_compatible(fdt, -1, compat); 3299eb77ceaSKumar Gala while (off != -FDT_ERR_NOTFOUND) { 3309eb77ceaSKumar Gala if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) 3319eb77ceaSKumar Gala fdt_setprop(fdt, off, prop, val, len); 3329eb77ceaSKumar Gala off = fdt_node_offset_by_compatible(fdt, off, compat); 3339eb77ceaSKumar Gala } 3349eb77ceaSKumar Gala } 3359eb77ceaSKumar Gala 3369eb77ceaSKumar Gala void do_fixup_by_compat_u32(void *fdt, const char *compat, 3379eb77ceaSKumar Gala const char *prop, u32 val, int create) 3389eb77ceaSKumar Gala { 3399eb77ceaSKumar Gala val = cpu_to_fdt32(val); 3409eb77ceaSKumar Gala do_fixup_by_compat(fdt, compat, prop, &val, 4, create); 3419eb77ceaSKumar Gala } 3429eb77ceaSKumar Gala 3433c927281SKumar Gala int fdt_fixup_memory(void *blob, u64 start, u64 size) 3443c927281SKumar Gala { 3453c927281SKumar Gala int err, nodeoffset, len = 0; 3463c927281SKumar Gala u8 tmp[16]; 3473c927281SKumar Gala const u32 *addrcell, *sizecell; 3483c927281SKumar Gala 3493c927281SKumar Gala err = fdt_check_header(blob); 3503c927281SKumar Gala if (err < 0) { 3513c927281SKumar Gala printf("%s: %s\n", __FUNCTION__, fdt_strerror(err)); 3523c927281SKumar Gala return err; 3533c927281SKumar Gala } 3543c927281SKumar Gala 3553c927281SKumar Gala /* update, or add and update /memory node */ 3563c927281SKumar Gala nodeoffset = fdt_path_offset(blob, "/memory"); 3573c927281SKumar Gala if (nodeoffset < 0) { 3583c927281SKumar Gala nodeoffset = fdt_add_subnode(blob, 0, "memory"); 3593c927281SKumar Gala if (nodeoffset < 0) 3603c927281SKumar Gala printf("WARNING: could not create /memory: %s.\n", 3613c927281SKumar Gala fdt_strerror(nodeoffset)); 3623c927281SKumar Gala return nodeoffset; 3633c927281SKumar Gala } 3643c927281SKumar Gala err = fdt_setprop(blob, nodeoffset, "device_type", "memory", 3653c927281SKumar Gala sizeof("memory")); 3663c927281SKumar Gala if (err < 0) { 3673c927281SKumar Gala printf("WARNING: could not set %s %s.\n", "device_type", 3683c927281SKumar Gala fdt_strerror(err)); 3693c927281SKumar Gala return err; 3703c927281SKumar Gala } 3713c927281SKumar Gala 3723c927281SKumar Gala addrcell = fdt_getprop(blob, 0, "#address-cells", NULL); 3733c927281SKumar Gala /* use shifts and mask to ensure endianness */ 3743c927281SKumar Gala if ((addrcell) && (*addrcell == 2)) { 3753c927281SKumar Gala tmp[0] = (start >> 56) & 0xff; 3763c927281SKumar Gala tmp[1] = (start >> 48) & 0xff; 3773c927281SKumar Gala tmp[2] = (start >> 40) & 0xff; 3783c927281SKumar Gala tmp[3] = (start >> 32) & 0xff; 3793c927281SKumar Gala tmp[4] = (start >> 24) & 0xff; 3803c927281SKumar Gala tmp[5] = (start >> 16) & 0xff; 3813c927281SKumar Gala tmp[6] = (start >> 8) & 0xff; 3823c927281SKumar Gala tmp[7] = (start ) & 0xff; 3833c927281SKumar Gala len = 8; 3843c927281SKumar Gala } else { 3853c927281SKumar Gala tmp[0] = (start >> 24) & 0xff; 3863c927281SKumar Gala tmp[1] = (start >> 16) & 0xff; 3873c927281SKumar Gala tmp[2] = (start >> 8) & 0xff; 3883c927281SKumar Gala tmp[3] = (start ) & 0xff; 3893c927281SKumar Gala len = 4; 3903c927281SKumar Gala } 3913c927281SKumar Gala 3923c927281SKumar Gala sizecell = fdt_getprop(blob, 0, "#size-cells", NULL); 3933c927281SKumar Gala /* use shifts and mask to ensure endianness */ 3943c927281SKumar Gala if ((sizecell) && (*sizecell == 2)) { 3953c927281SKumar Gala tmp[0+len] = (size >> 56) & 0xff; 3963c927281SKumar Gala tmp[1+len] = (size >> 48) & 0xff; 3973c927281SKumar Gala tmp[2+len] = (size >> 40) & 0xff; 3983c927281SKumar Gala tmp[3+len] = (size >> 32) & 0xff; 3993c927281SKumar Gala tmp[4+len] = (size >> 24) & 0xff; 4003c927281SKumar Gala tmp[5+len] = (size >> 16) & 0xff; 4013c927281SKumar Gala tmp[6+len] = (size >> 8) & 0xff; 4023c927281SKumar Gala tmp[7+len] = (size ) & 0xff; 4033c927281SKumar Gala len += 8; 4043c927281SKumar Gala } else { 4053c927281SKumar Gala tmp[0+len] = (size >> 24) & 0xff; 4063c927281SKumar Gala tmp[1+len] = (size >> 16) & 0xff; 4073c927281SKumar Gala tmp[2+len] = (size >> 8) & 0xff; 4083c927281SKumar Gala tmp[3+len] = (size ) & 0xff; 4093c927281SKumar Gala len += 4; 4103c927281SKumar Gala } 4113c927281SKumar Gala 4123c927281SKumar Gala err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); 4133c927281SKumar Gala if (err < 0) { 4143c927281SKumar Gala printf("WARNING: could not set %s %s.\n", 4153c927281SKumar Gala "reg", fdt_strerror(err)); 4163c927281SKumar Gala return err; 4173c927281SKumar Gala } 4183c927281SKumar Gala return 0; 4193c927281SKumar Gala } 4203c927281SKumar Gala 421ba37aa03SKumar Gala void fdt_fixup_ethernet(void *fdt) 422ab544633SKumar Gala { 423ba37aa03SKumar Gala int node, i, j; 424ba37aa03SKumar Gala char enet[16], *tmp, *end; 425ba37aa03SKumar Gala char mac[16] = "ethaddr"; 426ab544633SKumar Gala const char *path; 427ba37aa03SKumar Gala unsigned char mac_addr[6]; 428ab544633SKumar Gala 429ab544633SKumar Gala node = fdt_path_offset(fdt, "/aliases"); 430ba37aa03SKumar Gala if (node < 0) 431ba37aa03SKumar Gala return; 432ba37aa03SKumar Gala 433ba37aa03SKumar Gala i = 0; 434ba37aa03SKumar Gala while ((tmp = getenv(mac)) != NULL) { 435ba37aa03SKumar Gala sprintf(enet, "ethernet%d", i); 436ba37aa03SKumar Gala path = fdt_getprop(fdt, node, enet, NULL); 437ba37aa03SKumar Gala if (!path) { 438ba37aa03SKumar Gala debug("No alias for %s\n", enet); 439ba37aa03SKumar Gala sprintf(mac, "eth%daddr", ++i); 440ba37aa03SKumar Gala continue; 441ba37aa03SKumar Gala } 442ba37aa03SKumar Gala 443ba37aa03SKumar Gala for (j = 0; j < 6; j++) { 444ba37aa03SKumar Gala mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0; 445ba37aa03SKumar Gala if (tmp) 446ba37aa03SKumar Gala tmp = (*end) ? end+1 : end; 447ba37aa03SKumar Gala } 448ba37aa03SKumar Gala 449ba37aa03SKumar Gala do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0); 450ab544633SKumar Gala do_fixup_by_path(fdt, path, "local-mac-address", 451ba37aa03SKumar Gala &mac_addr, 6, 1); 452ba37aa03SKumar Gala 453ba37aa03SKumar Gala sprintf(mac, "eth%daddr", ++i); 454ab544633SKumar Gala } 455ab544633SKumar Gala } 45618e69a35SAnton Vorontsov 45718e69a35SAnton Vorontsov #ifdef CONFIG_HAS_FSL_DR_USB 45818e69a35SAnton Vorontsov void fdt_fixup_dr_usb(void *blob, bd_t *bd) 45918e69a35SAnton Vorontsov { 46018e69a35SAnton Vorontsov char *mode; 461015b27b9SAnton Vorontsov char *type; 46218e69a35SAnton Vorontsov const char *compat = "fsl-usb2-dr"; 463015b27b9SAnton Vorontsov const char *prop_mode = "dr_mode"; 464015b27b9SAnton Vorontsov const char *prop_type = "phy_type"; 46518e69a35SAnton Vorontsov int node_offset; 46618e69a35SAnton Vorontsov int err; 46718e69a35SAnton Vorontsov 46818e69a35SAnton Vorontsov mode = getenv("usb_dr_mode"); 469015b27b9SAnton Vorontsov type = getenv("usb_phy_type"); 470015b27b9SAnton Vorontsov if (!mode && !type) 47118e69a35SAnton Vorontsov return; 47218e69a35SAnton Vorontsov 47318e69a35SAnton Vorontsov node_offset = fdt_node_offset_by_compatible(blob, 0, compat); 474015b27b9SAnton Vorontsov if (node_offset < 0) { 47518e69a35SAnton Vorontsov printf("WARNING: could not find compatible node %s: %s.\n", 47618e69a35SAnton Vorontsov compat, fdt_strerror(node_offset)); 477015b27b9SAnton Vorontsov return; 478015b27b9SAnton Vorontsov } 47918e69a35SAnton Vorontsov 480015b27b9SAnton Vorontsov if (mode) { 481015b27b9SAnton Vorontsov err = fdt_setprop(blob, node_offset, prop_mode, mode, 482015b27b9SAnton Vorontsov strlen(mode) + 1); 48318e69a35SAnton Vorontsov if (err < 0) 48418e69a35SAnton Vorontsov printf("WARNING: could not set %s for %s: %s.\n", 485015b27b9SAnton Vorontsov prop_mode, compat, fdt_strerror(err)); 486015b27b9SAnton Vorontsov } 487015b27b9SAnton Vorontsov 488015b27b9SAnton Vorontsov if (type) { 489015b27b9SAnton Vorontsov err = fdt_setprop(blob, node_offset, prop_type, type, 490015b27b9SAnton Vorontsov strlen(type) + 1); 491015b27b9SAnton Vorontsov if (err < 0) 492015b27b9SAnton Vorontsov printf("WARNING: could not set %s for %s: %s.\n", 493015b27b9SAnton Vorontsov prop_type, compat, fdt_strerror(err)); 494015b27b9SAnton Vorontsov } 49518e69a35SAnton Vorontsov } 49618e69a35SAnton Vorontsov #endif /* CONFIG_HAS_FSL_DR_USB */ 4976b70ffb9SKim Phillips 4986b70ffb9SKim Phillips #if defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx) 4996b70ffb9SKim Phillips /* 5006b70ffb9SKim Phillips * update crypto node properties to a specified revision of the SEC 5016b70ffb9SKim Phillips * called with sec_rev == 0 if not on an mpc8xxxE processor 5026b70ffb9SKim Phillips */ 5036b70ffb9SKim Phillips void fdt_fixup_crypto_node(void *blob, int sec_rev) 5046b70ffb9SKim Phillips { 5056b70ffb9SKim Phillips const struct sec_rev_prop { 5066b70ffb9SKim Phillips u32 sec_rev; 5076b70ffb9SKim Phillips u32 num_channels; 5086b70ffb9SKim Phillips u32 channel_fifo_len; 5096b70ffb9SKim Phillips u32 exec_units_mask; 5106b70ffb9SKim Phillips u32 descriptor_types_mask; 5116b70ffb9SKim Phillips } sec_rev_prop_list [] = { 5126b70ffb9SKim Phillips { 0x0200, 4, 24, 0x07e, 0x01010ebf }, /* SEC 2.0 */ 5136b70ffb9SKim Phillips { 0x0201, 4, 24, 0x0fe, 0x012b0ebf }, /* SEC 2.1 */ 5146b70ffb9SKim Phillips { 0x0202, 1, 24, 0x04c, 0x0122003f }, /* SEC 2.2 */ 5156b70ffb9SKim Phillips { 0x0204, 4, 24, 0x07e, 0x012b0ebf }, /* SEC 2.4 */ 5166b70ffb9SKim Phillips { 0x0300, 4, 24, 0x9fe, 0x03ab0ebf }, /* SEC 3.0 */ 5176b70ffb9SKim Phillips { 0x0303, 4, 24, 0x97c, 0x03ab0abf }, /* SEC 3.3 */ 5186b70ffb9SKim Phillips }; 5196b70ffb9SKim Phillips char compat_strlist[ARRAY_SIZE(sec_rev_prop_list) * 5206b70ffb9SKim Phillips sizeof("fsl,secX.Y")]; 5216b70ffb9SKim Phillips int crypto_node, sec_idx, err; 5226b70ffb9SKim Phillips char *p; 5236b70ffb9SKim Phillips u32 val; 5246b70ffb9SKim Phillips 5256b70ffb9SKim Phillips /* locate crypto node based on lowest common compatible */ 5266b70ffb9SKim Phillips crypto_node = fdt_node_offset_by_compatible(blob, -1, "fsl,sec2.0"); 5276b70ffb9SKim Phillips if (crypto_node == -FDT_ERR_NOTFOUND) 5286b70ffb9SKim Phillips return; 5296b70ffb9SKim Phillips 5306b70ffb9SKim Phillips /* delete it if not on an E-processor */ 5316b70ffb9SKim Phillips if (crypto_node > 0 && !sec_rev) { 5326b70ffb9SKim Phillips fdt_del_node(blob, crypto_node); 5336b70ffb9SKim Phillips return; 5346b70ffb9SKim Phillips } 5356b70ffb9SKim Phillips 5366b70ffb9SKim Phillips /* else we got called for possible uprev */ 5376b70ffb9SKim Phillips for (sec_idx = 0; sec_idx < ARRAY_SIZE(sec_rev_prop_list); sec_idx++) 5386b70ffb9SKim Phillips if (sec_rev_prop_list[sec_idx].sec_rev == sec_rev) 5396b70ffb9SKim Phillips break; 5406b70ffb9SKim Phillips 5416b70ffb9SKim Phillips if (sec_idx == ARRAY_SIZE(sec_rev_prop_list)) { 5426b70ffb9SKim Phillips puts("warning: unknown SEC revision number\n"); 5436b70ffb9SKim Phillips return; 5446b70ffb9SKim Phillips } 5456b70ffb9SKim Phillips 5466b70ffb9SKim Phillips val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].num_channels); 5476b70ffb9SKim Phillips err = fdt_setprop(blob, crypto_node, "fsl,num-channels", &val, 4); 5486b70ffb9SKim Phillips if (err < 0) 5496b70ffb9SKim Phillips printf("WARNING: could not set crypto property: %s\n", 5506b70ffb9SKim Phillips fdt_strerror(err)); 5516b70ffb9SKim Phillips 5526b70ffb9SKim Phillips val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].descriptor_types_mask); 5536b70ffb9SKim Phillips err = fdt_setprop(blob, crypto_node, "fsl,descriptor-types-mask", &val, 4); 5546b70ffb9SKim Phillips if (err < 0) 5556b70ffb9SKim Phillips printf("WARNING: could not set crypto property: %s\n", 5566b70ffb9SKim Phillips fdt_strerror(err)); 5576b70ffb9SKim Phillips 5586b70ffb9SKim Phillips val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].exec_units_mask); 5596b70ffb9SKim Phillips err = fdt_setprop(blob, crypto_node, "fsl,exec-units-mask", &val, 4); 5606b70ffb9SKim Phillips if (err < 0) 5616b70ffb9SKim Phillips printf("WARNING: could not set crypto property: %s\n", 5626b70ffb9SKim Phillips fdt_strerror(err)); 5636b70ffb9SKim Phillips 5646b70ffb9SKim Phillips val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].channel_fifo_len); 5656b70ffb9SKim Phillips err = fdt_setprop(blob, crypto_node, "fsl,channel-fifo-len", &val, 4); 5666b70ffb9SKim Phillips if (err < 0) 5676b70ffb9SKim Phillips printf("WARNING: could not set crypto property: %s\n", 5686b70ffb9SKim Phillips fdt_strerror(err)); 5696b70ffb9SKim Phillips 5706b70ffb9SKim Phillips val = 0; 5716b70ffb9SKim Phillips while (sec_idx >= 0) { 5726b70ffb9SKim Phillips p = compat_strlist + val; 5736b70ffb9SKim Phillips val += sprintf(p, "fsl,sec%d.%d", 5746b70ffb9SKim Phillips (sec_rev_prop_list[sec_idx].sec_rev & 0xff00) >> 8, 5756b70ffb9SKim Phillips sec_rev_prop_list[sec_idx].sec_rev & 0x00ff) + 1; 5766b70ffb9SKim Phillips sec_idx--; 5776b70ffb9SKim Phillips } 5786b70ffb9SKim Phillips err = fdt_setprop(blob, crypto_node, "compatible", &compat_strlist, val); 5796b70ffb9SKim Phillips if (err < 0) 5806b70ffb9SKim Phillips printf("WARNING: could not set crypto property: %s\n", 5816b70ffb9SKim Phillips fdt_strerror(err)); 5826b70ffb9SKim Phillips } 5836b70ffb9SKim Phillips #endif /* defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx) */ 5843082d234SKumar Gala 5853082d234SKumar Gala /* Resize the fdt to its actual size + a bit of padding */ 5863082d234SKumar Gala int fdt_resize(void *blob) 5873082d234SKumar Gala { 5883082d234SKumar Gala int i; 5893082d234SKumar Gala uint64_t addr, size; 5903082d234SKumar Gala int total, ret; 5913082d234SKumar Gala uint actualsize; 5923082d234SKumar Gala 5933082d234SKumar Gala if (!blob) 5943082d234SKumar Gala return 0; 5953082d234SKumar Gala 5963082d234SKumar Gala total = fdt_num_mem_rsv(blob); 5973082d234SKumar Gala for (i = 0; i < total; i++) { 5983082d234SKumar Gala fdt_get_mem_rsv(blob, i, &addr, &size); 5993082d234SKumar Gala if (addr == (uint64_t)(u32)blob) { 6003082d234SKumar Gala fdt_del_mem_rsv(blob, i); 6013082d234SKumar Gala break; 6023082d234SKumar Gala } 6033082d234SKumar Gala } 6043082d234SKumar Gala 605f242a088SPeter Korsgaard /* 606f242a088SPeter Korsgaard * Calculate the actual size of the fdt 607f242a088SPeter Korsgaard * plus the size needed for fdt_add_mem_rsv 608f242a088SPeter Korsgaard */ 6093082d234SKumar Gala actualsize = fdt_off_dt_strings(blob) + 610f242a088SPeter Korsgaard fdt_size_dt_strings(blob) + sizeof(struct fdt_reserve_entry); 6113082d234SKumar Gala 6123082d234SKumar Gala /* Make it so the fdt ends on a page boundary */ 613c088a108SPeter Korsgaard actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000); 6143082d234SKumar Gala actualsize = actualsize - ((uint)blob & 0xfff); 6153082d234SKumar Gala 6163082d234SKumar Gala /* Change the fdt header to reflect the correct size */ 6173082d234SKumar Gala fdt_set_totalsize(blob, actualsize); 6183082d234SKumar Gala 6193082d234SKumar Gala /* Add the new reservation */ 6203082d234SKumar Gala ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize); 6213082d234SKumar Gala if (ret < 0) 6223082d234SKumar Gala return ret; 6233082d234SKumar Gala 6243082d234SKumar Gala return actualsize; 6253082d234SKumar Gala } 6268ab451c4SKumar Gala 6278ab451c4SKumar Gala #ifdef CONFIG_PCI 6288ab451c4SKumar Gala #define CONFIG_SYS_PCI_NR_INBOUND_WIN 3 6298ab451c4SKumar Gala 6308ab451c4SKumar Gala #define FDT_PCI_PREFETCH (0x40000000) 6318ab451c4SKumar Gala #define FDT_PCI_MEM32 (0x02000000) 6328ab451c4SKumar Gala #define FDT_PCI_IO (0x01000000) 6338ab451c4SKumar Gala #define FDT_PCI_MEM64 (0x03000000) 6348ab451c4SKumar Gala 6358ab451c4SKumar Gala int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) { 6368ab451c4SKumar Gala 6378ab451c4SKumar Gala int addrcell, sizecell, len, r; 6388ab451c4SKumar Gala u32 *dma_range; 6398ab451c4SKumar Gala /* sized based on pci addr cells, size-cells, & address-cells */ 6408ab451c4SKumar Gala u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN]; 6418ab451c4SKumar Gala 6428ab451c4SKumar Gala addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1); 6438ab451c4SKumar Gala sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1); 6448ab451c4SKumar Gala 6458ab451c4SKumar Gala dma_range = &dma_ranges[0]; 6468ab451c4SKumar Gala for (r = 0; r < hose->region_count; r++) { 6478ab451c4SKumar Gala u64 bus_start, phys_start, size; 6488ab451c4SKumar Gala 649*ff4e66e9SKumar Gala /* skip if !PCI_REGION_SYS_MEMORY */ 650*ff4e66e9SKumar Gala if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY)) 6518ab451c4SKumar Gala continue; 6528ab451c4SKumar Gala 6538ab451c4SKumar Gala bus_start = (u64)hose->regions[r].bus_start; 6548ab451c4SKumar Gala phys_start = (u64)hose->regions[r].phys_start; 6558ab451c4SKumar Gala size = (u64)hose->regions[r].size; 6568ab451c4SKumar Gala 6578ab451c4SKumar Gala dma_range[0] = 0; 6588ab451c4SKumar Gala if (size > 0x100000000ull) 6598ab451c4SKumar Gala dma_range[0] |= FDT_PCI_MEM64; 6608ab451c4SKumar Gala else 6618ab451c4SKumar Gala dma_range[0] |= FDT_PCI_MEM32; 6628ab451c4SKumar Gala if (hose->regions[r].flags & PCI_REGION_PREFETCH) 6638ab451c4SKumar Gala dma_range[0] |= FDT_PCI_PREFETCH; 6648ab451c4SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 6658ab451c4SKumar Gala dma_range[1] = bus_start >> 32; 6668ab451c4SKumar Gala #else 6678ab451c4SKumar Gala dma_range[1] = 0; 6688ab451c4SKumar Gala #endif 6698ab451c4SKumar Gala dma_range[2] = bus_start & 0xffffffff; 6708ab451c4SKumar Gala 6718ab451c4SKumar Gala if (addrcell == 2) { 6728ab451c4SKumar Gala dma_range[3] = phys_start >> 32; 6738ab451c4SKumar Gala dma_range[4] = phys_start & 0xffffffff; 6748ab451c4SKumar Gala } else { 6758ab451c4SKumar Gala dma_range[3] = phys_start & 0xffffffff; 6768ab451c4SKumar Gala } 6778ab451c4SKumar Gala 6788ab451c4SKumar Gala if (sizecell == 2) { 6798ab451c4SKumar Gala dma_range[3 + addrcell + 0] = size >> 32; 6808ab451c4SKumar Gala dma_range[3 + addrcell + 1] = size & 0xffffffff; 6818ab451c4SKumar Gala } else { 6828ab451c4SKumar Gala dma_range[3 + addrcell + 0] = size & 0xffffffff; 6838ab451c4SKumar Gala } 6848ab451c4SKumar Gala 6858ab451c4SKumar Gala dma_range += (3 + addrcell + sizecell); 6868ab451c4SKumar Gala } 6878ab451c4SKumar Gala 6888ab451c4SKumar Gala len = dma_range - &dma_ranges[0]; 6898ab451c4SKumar Gala if (len) 6908ab451c4SKumar Gala fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4); 6918ab451c4SKumar Gala 6928ab451c4SKumar Gala return 0; 6938ab451c4SKumar Gala } 6948ab451c4SKumar Gala #endif 695