xref: /openbmc/linux/drivers/of/fdt.c (revision ca900cfa)
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