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
);
79 void dt_fixup_clock(const char *path
, u32 freq
)
81 void *devp
= finddevice(path
);
84 printf("%s: clock-frequency <- %x (%dMHz)\n\r", path
, freq
, MHZ(freq
));
85 setprop_val(devp
, "clock-frequency", freq
);
89 void __dt_fixup_mac_addresses(u32 startindex
, ...)
92 u32 index
= startindex
;
96 va_start(ap
, startindex
);
97 while ((addr
= va_arg(ap
, const u8
*))) {
98 devp
= find_node_by_prop_value(NULL
, "linux,network-index",
99 (void*)&index
, sizeof(index
));
101 printf("ENET%d: local-mac-address <-"
102 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index
,
103 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
106 setprop(devp
, "local-mac-address", addr
, 6);
113 #define MAX_ADDR_CELLS 4
116 static void get_reg_format(void *node
, u32
*naddr
, u32
*nsize
)
118 if (getprop(node
, "#address-cells", naddr
, 4) != 4)
120 if (getprop(node
, "#size-cells", nsize
, 4) != 4)
124 static void copy_val(u32
*dest
, u32
*src
, int naddr
)
126 int pad
= MAX_ADDR_CELLS
- naddr
;
128 memset(dest
, 0, pad
* 4);
129 memcpy(dest
+ pad
, src
, naddr
* 4);
132 static int sub_reg(u32
*reg
, u32
*sub
)
136 for (i
= MAX_ADDR_CELLS
- 1; i
>= 0; i
--) {
137 int prev_borrow
= borrow
;
138 borrow
= reg
[i
] < sub
[i
] + prev_borrow
;
139 reg
[i
] -= sub
[i
] + prev_borrow
;
145 static int add_reg(u32
*reg
, u32
*add
, int naddr
)
149 for (i
= MAX_ADDR_CELLS
- 1; i
>= MAX_ADDR_CELLS
- naddr
; i
--) {
150 u64 tmp
= (u64
)reg
[i
] + add
[i
] + carry
;
158 /* It is assumed that if the first byte of reg fits in a
159 * range, then the whole reg block fits.
161 static int compare_reg(u32
*reg
, u32
*range
, u32
*rangesize
)
166 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
167 if (reg
[i
] < range
[i
])
169 if (reg
[i
] > range
[i
])
173 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
174 end
= range
[i
] + rangesize
[i
];
182 return reg
[i
] != end
;
185 /* reg must be MAX_ADDR_CELLS */
186 static int find_range(u32
*reg
, u32
*ranges
, int nregaddr
,
187 int naddr
, int nsize
, int buflen
)
189 int nrange
= nregaddr
+ naddr
+ nsize
;
192 for (i
= 0; i
+ nrange
<= buflen
; i
+= nrange
) {
193 u32 range_addr
[MAX_ADDR_CELLS
];
194 u32 range_size
[MAX_ADDR_CELLS
];
196 copy_val(range_addr
, ranges
+ i
, naddr
);
197 copy_val(range_size
, ranges
+ i
+ nregaddr
+ naddr
, nsize
);
199 if (compare_reg(reg
, range_addr
, range_size
))
206 /* Currently only generic buses without special encodings are supported.
207 * In particular, PCI is not supported. Also, only the beginning of the
208 * reg block is tracked; size is ignored except in ranges.
210 static u32 dt_xlate_buf
[MAX_ADDR_CELLS
* MAX_RANGES
* 3];
212 static int dt_xlate(void *node
, int res
, int reglen
, unsigned long *addr
,
215 u32 last_addr
[MAX_ADDR_CELLS
];
216 u32 this_addr
[MAX_ADDR_CELLS
];
218 u64 ret_addr
, ret_size
;
219 u32 naddr
, nsize
, prev_naddr
;
222 parent
= get_parent(node
);
226 get_reg_format(parent
, &naddr
, &nsize
);
231 offset
= (naddr
+ nsize
) * res
;
233 if (reglen
< offset
+ naddr
+ nsize
||
234 sizeof(dt_xlate_buf
) < offset
+ naddr
+ nsize
)
237 copy_val(last_addr
, dt_xlate_buf
+ offset
, naddr
);
239 ret_size
= dt_xlate_buf
[offset
+ naddr
];
242 ret_size
|= dt_xlate_buf
[offset
+ naddr
+ 1];
245 while ((node
= get_parent(node
))) {
248 get_reg_format(node
, &naddr
, &nsize
);
250 buflen
= getprop(node
, "ranges", dt_xlate_buf
,
251 sizeof(dt_xlate_buf
));
254 if (buflen
> sizeof(dt_xlate_buf
))
257 offset
= find_range(last_addr
, dt_xlate_buf
, prev_naddr
,
258 naddr
, nsize
, buflen
/ 4);
263 copy_val(this_addr
, dt_xlate_buf
+ offset
, prev_naddr
);
265 if (!sub_reg(last_addr
, this_addr
))
268 copy_val(this_addr
, dt_xlate_buf
+ offset
+ prev_naddr
, naddr
);
270 if (!add_reg(last_addr
, this_addr
, naddr
))
277 ret_addr
= ((u64
)last_addr
[2] << 32) | last_addr
[3];
279 if (sizeof(void *) == 4 &&
280 (ret_addr
>= 0x100000000ULL
|| ret_size
> 0x100000000ULL
||
281 ret_addr
+ ret_size
> 0x100000000ULL
))
291 int dt_xlate_reg(void *node
, int res
, unsigned long *addr
, unsigned long *size
)
295 reglen
= getprop(node
, "reg", dt_xlate_buf
, sizeof(dt_xlate_buf
)) / 4;
296 return dt_xlate(node
, res
, reglen
, addr
, size
);
299 int dt_xlate_addr(void *node
, u32
*buf
, int buflen
, unsigned long *xlated_addr
)
302 if (buflen
> sizeof(dt_xlate_buf
))
305 memcpy(dt_xlate_buf
, buf
, buflen
);
306 return dt_xlate(node
, 0, buflen
/ 4, xlated_addr
, NULL
);