2 * devtree.c - convenience functions for device tree manipulation
3 * Copyright 2007 David Gibson, IBM Corporation.
4 * Copyright (c) 2007 Freescale Semiconductor, Inc.
6 * Authors: David Gibson <david@gibson.dropbear.id.au>
7 * Scott Wood <scottwood@freescale.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
21 void dt_fixup_memory(u64 start
, u64 size
)
27 root
= finddevice("/");
28 if (getprop(root
, "#address-cells", &naddr
, sizeof(naddr
)) < 0)
30 if (naddr
< 1 || naddr
> 2)
31 fatal("Can't cope with #address-cells == %d in /\n\r", naddr
);
33 if (getprop(root
, "#size-cells", &nsize
, sizeof(nsize
)) < 0)
35 if (nsize
< 1 || nsize
> 2)
36 fatal("Can't cope with #size-cells == %d in /\n\r", nsize
);
40 memreg
[i
++] = start
>> 32;
41 memreg
[i
++] = start
& 0xffffffff;
43 memreg
[i
++] = size
>> 32;
44 memreg
[i
++] = size
& 0xffffffff;
46 memory
= finddevice("/memory");
48 memory
= create_node(NULL
, "memory");
49 setprop_str(memory
, "device_type", "memory");
52 printf("Memory <- <0x%x", memreg
[0]);
53 for (i
= 1; i
< (naddr
+ nsize
); i
++)
54 printf(" 0x%x", memreg
[i
]);
55 printf("> (%ldMB)\n\r", (unsigned long)(size
>> 20));
57 setprop(memory
, "reg", memreg
, (naddr
+ nsize
)*sizeof(u32
));
60 #define MHZ(x) ((x + 500000) / 1000000)
62 void dt_fixup_cpu_clocks(u32 cpu
, u32 tb
, u32 bus
)
66 printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu
, MHZ(cpu
));
67 printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb
, MHZ(tb
));
69 printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus
, MHZ(bus
));
71 while ((devp
= find_node_by_devtype(devp
, "cpu"))) {
72 setprop_val(devp
, "clock-frequency", cpu
);
73 setprop_val(devp
, "timebase-frequency", tb
);
75 setprop_val(devp
, "bus-frequency", bus
);
78 timebase_period_ns
= 1000000000 / tb
;
81 void dt_fixup_clock(const char *path
, u32 freq
)
83 void *devp
= finddevice(path
);
86 printf("%s: clock-frequency <- %x (%dMHz)\n\r", path
, freq
, MHZ(freq
));
87 setprop_val(devp
, "clock-frequency", freq
);
91 void dt_fixup_mac_address_by_alias(const char *alias
, const u8
*addr
)
93 void *devp
= find_node_by_alias(alias
);
96 printf("%s: local-mac-address <-"
97 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", alias
,
98 addr
[0], addr
[1], addr
[2],
99 addr
[3], addr
[4], addr
[5]);
101 setprop(devp
, "local-mac-address", addr
, 6);
105 void dt_fixup_mac_address(u32 index
, const u8
*addr
)
107 void *devp
= find_node_by_prop_value(NULL
, "linux,network-index",
108 (void*)&index
, sizeof(index
));
111 printf("ENET%d: local-mac-address <-"
112 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index
,
113 addr
[0], addr
[1], addr
[2],
114 addr
[3], addr
[4], addr
[5]);
116 setprop(devp
, "local-mac-address", addr
, 6);
120 void __dt_fixup_mac_addresses(u32 startindex
, ...)
123 u32 index
= startindex
;
126 va_start(ap
, startindex
);
128 while ((addr
= va_arg(ap
, const u8
*)))
129 dt_fixup_mac_address(index
++, addr
);
134 #define MAX_ADDR_CELLS 4
136 void dt_get_reg_format(void *node
, u32
*naddr
, u32
*nsize
)
138 if (getprop(node
, "#address-cells", naddr
, 4) != 4)
140 if (getprop(node
, "#size-cells", nsize
, 4) != 4)
144 static void copy_val(u32
*dest
, u32
*src
, int naddr
)
146 int pad
= MAX_ADDR_CELLS
- naddr
;
148 memset(dest
, 0, pad
* 4);
149 memcpy(dest
+ pad
, src
, naddr
* 4);
152 static int sub_reg(u32
*reg
, u32
*sub
)
156 for (i
= MAX_ADDR_CELLS
- 1; i
>= 0; i
--) {
157 int prev_borrow
= borrow
;
158 borrow
= reg
[i
] < sub
[i
] + prev_borrow
;
159 reg
[i
] -= sub
[i
] + prev_borrow
;
165 static int add_reg(u32
*reg
, u32
*add
, int naddr
)
169 for (i
= MAX_ADDR_CELLS
- 1; i
>= MAX_ADDR_CELLS
- naddr
; i
--) {
170 u64 tmp
= (u64
)reg
[i
] + add
[i
] + carry
;
178 /* It is assumed that if the first byte of reg fits in a
179 * range, then the whole reg block fits.
181 static int compare_reg(u32
*reg
, u32
*range
, u32
*rangesize
)
186 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
187 if (reg
[i
] < range
[i
])
189 if (reg
[i
] > range
[i
])
193 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
194 end
= range
[i
] + rangesize
[i
];
202 return reg
[i
] != end
;
205 /* reg must be MAX_ADDR_CELLS */
206 static int find_range(u32
*reg
, u32
*ranges
, int nregaddr
,
207 int naddr
, int nsize
, int buflen
)
209 int nrange
= nregaddr
+ naddr
+ nsize
;
212 for (i
= 0; i
+ nrange
<= buflen
; i
+= nrange
) {
213 u32 range_addr
[MAX_ADDR_CELLS
];
214 u32 range_size
[MAX_ADDR_CELLS
];
216 copy_val(range_addr
, ranges
+ i
, naddr
);
217 copy_val(range_size
, ranges
+ i
+ nregaddr
+ naddr
, nsize
);
219 if (compare_reg(reg
, range_addr
, range_size
))
226 /* Currently only generic buses without special encodings are supported.
227 * In particular, PCI is not supported. Also, only the beginning of the
228 * reg block is tracked; size is ignored except in ranges.
230 static u32 prop_buf
[MAX_PROP_LEN
/ 4];
232 static int dt_xlate(void *node
, int res
, int reglen
, unsigned long *addr
,
235 u32 last_addr
[MAX_ADDR_CELLS
];
236 u32 this_addr
[MAX_ADDR_CELLS
];
238 u64 ret_addr
, ret_size
;
239 u32 naddr
, nsize
, prev_naddr
, prev_nsize
;
242 parent
= get_parent(node
);
246 dt_get_reg_format(parent
, &naddr
, &nsize
);
251 offset
= (naddr
+ nsize
) * res
;
253 if (reglen
< offset
+ naddr
+ nsize
||
254 MAX_PROP_LEN
< (offset
+ naddr
+ nsize
) * 4)
257 copy_val(last_addr
, prop_buf
+ offset
, naddr
);
259 ret_size
= prop_buf
[offset
+ naddr
];
262 ret_size
|= prop_buf
[offset
+ naddr
+ 1];
270 parent
= get_parent(node
);
274 dt_get_reg_format(parent
, &naddr
, &nsize
);
276 buflen
= getprop(node
, "ranges", prop_buf
,
280 if (buflen
< 0 || buflen
> sizeof(prop_buf
))
283 offset
= find_range(last_addr
, prop_buf
, prev_naddr
,
284 naddr
, prev_nsize
, buflen
/ 4);
289 copy_val(this_addr
, prop_buf
+ offset
, prev_naddr
);
291 if (!sub_reg(last_addr
, this_addr
))
294 copy_val(this_addr
, prop_buf
+ offset
+ prev_naddr
, naddr
);
296 if (!add_reg(last_addr
, this_addr
, naddr
))
303 ret_addr
= ((u64
)last_addr
[2] << 32) | last_addr
[3];
305 if (sizeof(void *) == 4 &&
306 (ret_addr
>= 0x100000000ULL
|| ret_size
> 0x100000000ULL
||
307 ret_addr
+ ret_size
> 0x100000000ULL
))
317 int dt_xlate_reg(void *node
, int res
, unsigned long *addr
, unsigned long *size
)
321 reglen
= getprop(node
, "reg", prop_buf
, sizeof(prop_buf
)) / 4;
322 return dt_xlate(node
, res
, reglen
, addr
, size
);
325 int dt_xlate_addr(void *node
, u32
*buf
, int buflen
, unsigned long *xlated_addr
)
328 if (buflen
> sizeof(prop_buf
))
331 memcpy(prop_buf
, buf
, buflen
);
332 return dt_xlate(node
, 0, buflen
/ 4, xlated_addr
, NULL
);
335 int dt_is_compatible(void *node
, const char *compat
)
337 char *buf
= (char *)prop_buf
;
340 len
= getprop(node
, "compatible", buf
, MAX_PROP_LEN
);
344 for (pos
= 0; pos
< len
; pos
++) {
345 if (!strcmp(buf
+ pos
, compat
))
348 pos
+= strnlen(&buf
[pos
], len
- pos
);
354 int dt_get_virtual_reg(void *node
, void **addr
, int nres
)
359 n
= getprop(node
, "virtual-reg", addr
, nres
* 4);
363 for (n
= 0; n
< nres
; n
++) {
364 if (!dt_xlate_reg(node
, n
, &xaddr
, NULL
))
367 addr
[n
] = (void *)xaddr
;