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(u32 index
, const u8
*addr
)
93 void *devp
= find_node_by_prop_value(NULL
, "linux,network-index",
94 (void*)&index
, sizeof(index
));
97 printf("ENET%d: local-mac-address <-"
98 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index
,
99 addr
[0], addr
[1], addr
[2],
100 addr
[3], addr
[4], addr
[5]);
102 setprop(devp
, "local-mac-address", addr
, 6);
106 void __dt_fixup_mac_addresses(u32 startindex
, ...)
109 u32 index
= startindex
;
112 va_start(ap
, startindex
);
114 while ((addr
= va_arg(ap
, const u8
*)))
115 dt_fixup_mac_address(index
++, addr
);
120 #define MAX_ADDR_CELLS 4
122 void dt_get_reg_format(void *node
, u32
*naddr
, u32
*nsize
)
124 if (getprop(node
, "#address-cells", naddr
, 4) != 4)
126 if (getprop(node
, "#size-cells", nsize
, 4) != 4)
130 static void copy_val(u32
*dest
, u32
*src
, int naddr
)
132 int pad
= MAX_ADDR_CELLS
- naddr
;
134 memset(dest
, 0, pad
* 4);
135 memcpy(dest
+ pad
, src
, naddr
* 4);
138 static int sub_reg(u32
*reg
, u32
*sub
)
142 for (i
= MAX_ADDR_CELLS
- 1; i
>= 0; i
--) {
143 int prev_borrow
= borrow
;
144 borrow
= reg
[i
] < sub
[i
] + prev_borrow
;
145 reg
[i
] -= sub
[i
] + prev_borrow
;
151 static int add_reg(u32
*reg
, u32
*add
, int naddr
)
155 for (i
= MAX_ADDR_CELLS
- 1; i
>= MAX_ADDR_CELLS
- naddr
; i
--) {
156 u64 tmp
= (u64
)reg
[i
] + add
[i
] + carry
;
164 /* It is assumed that if the first byte of reg fits in a
165 * range, then the whole reg block fits.
167 static int compare_reg(u32
*reg
, u32
*range
, u32
*rangesize
)
172 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
173 if (reg
[i
] < range
[i
])
175 if (reg
[i
] > range
[i
])
179 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
180 end
= range
[i
] + rangesize
[i
];
188 return reg
[i
] != end
;
191 /* reg must be MAX_ADDR_CELLS */
192 static int find_range(u32
*reg
, u32
*ranges
, int nregaddr
,
193 int naddr
, int nsize
, int buflen
)
195 int nrange
= nregaddr
+ naddr
+ nsize
;
198 for (i
= 0; i
+ nrange
<= buflen
; i
+= nrange
) {
199 u32 range_addr
[MAX_ADDR_CELLS
];
200 u32 range_size
[MAX_ADDR_CELLS
];
202 copy_val(range_addr
, ranges
+ i
, naddr
);
203 copy_val(range_size
, ranges
+ i
+ nregaddr
+ naddr
, nsize
);
205 if (compare_reg(reg
, range_addr
, range_size
))
212 /* Currently only generic buses without special encodings are supported.
213 * In particular, PCI is not supported. Also, only the beginning of the
214 * reg block is tracked; size is ignored except in ranges.
216 static u32 prop_buf
[MAX_PROP_LEN
/ 4];
218 static int dt_xlate(void *node
, int res
, int reglen
, unsigned long *addr
,
221 u32 last_addr
[MAX_ADDR_CELLS
];
222 u32 this_addr
[MAX_ADDR_CELLS
];
224 u64 ret_addr
, ret_size
;
225 u32 naddr
, nsize
, prev_naddr
, prev_nsize
;
228 parent
= get_parent(node
);
232 dt_get_reg_format(parent
, &naddr
, &nsize
);
237 offset
= (naddr
+ nsize
) * res
;
239 if (reglen
< offset
+ naddr
+ nsize
||
240 MAX_PROP_LEN
< (offset
+ naddr
+ nsize
) * 4)
243 copy_val(last_addr
, prop_buf
+ offset
, naddr
);
245 ret_size
= prop_buf
[offset
+ naddr
];
248 ret_size
|= prop_buf
[offset
+ naddr
+ 1];
256 parent
= get_parent(node
);
260 dt_get_reg_format(parent
, &naddr
, &nsize
);
262 buflen
= getprop(node
, "ranges", prop_buf
,
266 if (buflen
< 0 || buflen
> sizeof(prop_buf
))
269 offset
= find_range(last_addr
, prop_buf
, prev_naddr
,
270 naddr
, prev_nsize
, buflen
/ 4);
275 copy_val(this_addr
, prop_buf
+ offset
, prev_naddr
);
277 if (!sub_reg(last_addr
, this_addr
))
280 copy_val(this_addr
, prop_buf
+ offset
+ prev_naddr
, naddr
);
282 if (!add_reg(last_addr
, this_addr
, naddr
))
289 ret_addr
= ((u64
)last_addr
[2] << 32) | last_addr
[3];
291 if (sizeof(void *) == 4 &&
292 (ret_addr
>= 0x100000000ULL
|| ret_size
> 0x100000000ULL
||
293 ret_addr
+ ret_size
> 0x100000000ULL
))
303 int dt_xlate_reg(void *node
, int res
, unsigned long *addr
, unsigned long *size
)
307 reglen
= getprop(node
, "reg", prop_buf
, sizeof(prop_buf
)) / 4;
308 return dt_xlate(node
, res
, reglen
, addr
, size
);
311 int dt_xlate_addr(void *node
, u32
*buf
, int buflen
, unsigned long *xlated_addr
)
314 if (buflen
> sizeof(prop_buf
))
317 memcpy(prop_buf
, buf
, buflen
);
318 return dt_xlate(node
, 0, buflen
/ 4, xlated_addr
, NULL
);
321 int dt_is_compatible(void *node
, const char *compat
)
323 char *buf
= (char *)prop_buf
;
326 len
= getprop(node
, "compatible", buf
, MAX_PROP_LEN
);
330 for (pos
= 0; pos
< len
; pos
++) {
331 if (!strcmp(buf
+ pos
, compat
))
334 pos
+= strnlen(&buf
[pos
], len
- pos
);