1e169cfbeSGrant Likely /* 2e169cfbeSGrant Likely * Functions for working with the Flattened Device Tree data format 3e169cfbeSGrant Likely * 4e169cfbeSGrant Likely * Copyright 2009 Benjamin Herrenschmidt, IBM Corp 5e169cfbeSGrant Likely * benh@kernel.crashing.org 6e169cfbeSGrant Likely * 7e169cfbeSGrant Likely * This program is free software; you can redistribute it and/or 8e169cfbeSGrant Likely * modify it under the terms of the GNU General Public License 9e169cfbeSGrant Likely * version 2 as published by the Free Software Foundation. 10e169cfbeSGrant Likely */ 11e169cfbeSGrant Likely 12e169cfbeSGrant Likely #include <linux/of.h> 13e169cfbeSGrant Likely #include <linux/of_fdt.h> 14e169cfbeSGrant Likely 15e169cfbeSGrant Likely struct boot_param_header *initial_boot_params; 16e169cfbeSGrant Likely 17e169cfbeSGrant Likely char *find_flat_dt_string(u32 offset) 18e169cfbeSGrant Likely { 19e169cfbeSGrant Likely return ((char *)initial_boot_params) + 20e169cfbeSGrant Likely initial_boot_params->off_dt_strings + offset; 21e169cfbeSGrant Likely } 22c8cb7a59SGrant Likely 23c8cb7a59SGrant Likely /** 24c8cb7a59SGrant Likely * of_scan_flat_dt - scan flattened tree blob and call callback on each. 25c8cb7a59SGrant Likely * @it: callback function 26c8cb7a59SGrant Likely * @data: context data pointer 27c8cb7a59SGrant Likely * 28c8cb7a59SGrant Likely * This function is used to scan the flattened device-tree, it is 29c8cb7a59SGrant Likely * used to extract the memory information at boot before we can 30c8cb7a59SGrant Likely * unflatten the tree 31c8cb7a59SGrant Likely */ 32c8cb7a59SGrant Likely int __init of_scan_flat_dt(int (*it)(unsigned long node, 33c8cb7a59SGrant Likely const char *uname, int depth, 34c8cb7a59SGrant Likely void *data), 35c8cb7a59SGrant Likely void *data) 36c8cb7a59SGrant Likely { 37c8cb7a59SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 38c8cb7a59SGrant Likely initial_boot_params->off_dt_struct; 39c8cb7a59SGrant Likely int rc = 0; 40c8cb7a59SGrant Likely int depth = -1; 41c8cb7a59SGrant Likely 42c8cb7a59SGrant Likely do { 43c8cb7a59SGrant Likely u32 tag = *((u32 *)p); 44c8cb7a59SGrant Likely char *pathp; 45c8cb7a59SGrant Likely 46c8cb7a59SGrant Likely p += 4; 47c8cb7a59SGrant Likely if (tag == OF_DT_END_NODE) { 48c8cb7a59SGrant Likely depth--; 49c8cb7a59SGrant Likely continue; 50c8cb7a59SGrant Likely } 51c8cb7a59SGrant Likely if (tag == OF_DT_NOP) 52c8cb7a59SGrant Likely continue; 53c8cb7a59SGrant Likely if (tag == OF_DT_END) 54c8cb7a59SGrant Likely break; 55c8cb7a59SGrant Likely if (tag == OF_DT_PROP) { 56c8cb7a59SGrant Likely u32 sz = *((u32 *)p); 57c8cb7a59SGrant Likely p += 8; 58c8cb7a59SGrant Likely if (initial_boot_params->version < 0x10) 59c8cb7a59SGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 60c8cb7a59SGrant Likely p += sz; 61c8cb7a59SGrant Likely p = _ALIGN(p, 4); 62c8cb7a59SGrant Likely continue; 63c8cb7a59SGrant Likely } 64c8cb7a59SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 65c8cb7a59SGrant Likely pr_err("Invalid tag %x in flat device tree!\n", tag); 66c8cb7a59SGrant Likely return -EINVAL; 67c8cb7a59SGrant Likely } 68c8cb7a59SGrant Likely depth++; 69c8cb7a59SGrant Likely pathp = (char *)p; 70c8cb7a59SGrant Likely p = _ALIGN(p + strlen(pathp) + 1, 4); 71c8cb7a59SGrant Likely if ((*pathp) == '/') { 72c8cb7a59SGrant Likely char *lp, *np; 73c8cb7a59SGrant Likely for (lp = NULL, np = pathp; *np; np++) 74c8cb7a59SGrant Likely if ((*np) == '/') 75c8cb7a59SGrant Likely lp = np+1; 76c8cb7a59SGrant Likely if (lp != NULL) 77c8cb7a59SGrant Likely pathp = lp; 78c8cb7a59SGrant Likely } 79c8cb7a59SGrant Likely rc = it(p, pathp, depth, data); 80c8cb7a59SGrant Likely if (rc != 0) 81c8cb7a59SGrant Likely break; 82c8cb7a59SGrant Likely } while (1); 83c8cb7a59SGrant Likely 84c8cb7a59SGrant Likely return rc; 85c8cb7a59SGrant Likely } 86819d2819SGrant Likely 87819d2819SGrant Likely /** 88819d2819SGrant Likely * of_get_flat_dt_root - find the root node in the flat blob 89819d2819SGrant Likely */ 90819d2819SGrant Likely unsigned long __init of_get_flat_dt_root(void) 91819d2819SGrant Likely { 92819d2819SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 93819d2819SGrant Likely initial_boot_params->off_dt_struct; 94819d2819SGrant Likely 95819d2819SGrant Likely while (*((u32 *)p) == OF_DT_NOP) 96819d2819SGrant Likely p += 4; 97819d2819SGrant Likely BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); 98819d2819SGrant Likely p += 4; 99819d2819SGrant Likely return _ALIGN(p + strlen((char *)p) + 1, 4); 100819d2819SGrant Likely } 101819d2819SGrant Likely 102ca900cfaSGrant Likely /** 103ca900cfaSGrant Likely * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 104ca900cfaSGrant Likely * 105ca900cfaSGrant Likely * This function can be used within scan_flattened_dt callback to get 106ca900cfaSGrant Likely * access to properties 107ca900cfaSGrant Likely */ 108ca900cfaSGrant Likely void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 109ca900cfaSGrant Likely unsigned long *size) 110ca900cfaSGrant Likely { 111ca900cfaSGrant Likely unsigned long p = node; 112ca900cfaSGrant Likely 113ca900cfaSGrant Likely do { 114ca900cfaSGrant Likely u32 tag = *((u32 *)p); 115ca900cfaSGrant Likely u32 sz, noff; 116ca900cfaSGrant Likely const char *nstr; 117ca900cfaSGrant Likely 118ca900cfaSGrant Likely p += 4; 119ca900cfaSGrant Likely if (tag == OF_DT_NOP) 120ca900cfaSGrant Likely continue; 121ca900cfaSGrant Likely if (tag != OF_DT_PROP) 122ca900cfaSGrant Likely return NULL; 123ca900cfaSGrant Likely 124ca900cfaSGrant Likely sz = *((u32 *)p); 125ca900cfaSGrant Likely noff = *((u32 *)(p + 4)); 126ca900cfaSGrant Likely p += 8; 127ca900cfaSGrant Likely if (initial_boot_params->version < 0x10) 128ca900cfaSGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 129ca900cfaSGrant Likely 130ca900cfaSGrant Likely nstr = find_flat_dt_string(noff); 131ca900cfaSGrant Likely if (nstr == NULL) { 132ca900cfaSGrant Likely pr_warning("Can't find property index name !\n"); 133ca900cfaSGrant Likely return NULL; 134ca900cfaSGrant Likely } 135ca900cfaSGrant Likely if (strcmp(name, nstr) == 0) { 136ca900cfaSGrant Likely if (size) 137ca900cfaSGrant Likely *size = sz; 138ca900cfaSGrant Likely return (void *)p; 139ca900cfaSGrant Likely } 140ca900cfaSGrant Likely p += sz; 141ca900cfaSGrant Likely p = _ALIGN(p, 4); 142ca900cfaSGrant Likely } while (1); 143ca900cfaSGrant Likely } 144ca900cfaSGrant Likely 145