1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * devtree.c - convenience functions for device tree manipulation
4 * Copyright 2007 David Gibson, IBM Corporation.
5 * Copyright (c) 2007 Freescale Semiconductor, Inc.
7 * Authors: David Gibson <david@gibson.dropbear.id.au>
8 * Scott Wood <scottwood@freescale.com>
17 void dt_fixup_memory(u64 start
, u64 size
)
23 root
= finddevice("/");
24 if (getprop(root
, "#address-cells", &naddr
, sizeof(naddr
)) < 0)
26 if (naddr
< 1 || naddr
> 2)
27 fatal("Can't cope with #address-cells == %d in /\n\r", naddr
);
29 if (getprop(root
, "#size-cells", &nsize
, sizeof(nsize
)) < 0)
31 if (nsize
< 1 || nsize
> 2)
32 fatal("Can't cope with #size-cells == %d in /\n\r", nsize
);
36 memreg
[i
++] = start
>> 32;
37 memreg
[i
++] = start
& 0xffffffff;
39 memreg
[i
++] = size
>> 32;
40 memreg
[i
++] = size
& 0xffffffff;
42 memory
= finddevice("/memory");
44 memory
= create_node(NULL
, "memory");
45 setprop_str(memory
, "device_type", "memory");
48 printf("Memory <- <0x%x", memreg
[0]);
49 for (i
= 1; i
< (naddr
+ nsize
); i
++)
50 printf(" 0x%x", memreg
[i
]);
51 printf("> (%ldMB)\n\r", (unsigned long)(size
>> 20));
53 setprop(memory
, "reg", memreg
, (naddr
+ nsize
)*sizeof(u32
));
56 #define MHZ(x) ((x + 500000) / 1000000)
58 void dt_fixup_cpu_clocks(u32 cpu
, u32 tb
, u32 bus
)
62 printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu
, MHZ(cpu
));
63 printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb
, MHZ(tb
));
65 printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus
, MHZ(bus
));
67 while ((devp
= find_node_by_devtype(devp
, "cpu"))) {
68 setprop_val(devp
, "clock-frequency", cpu
);
69 setprop_val(devp
, "timebase-frequency", tb
);
71 setprop_val(devp
, "bus-frequency", bus
);
74 timebase_period_ns
= 1000000000 / tb
;
77 void dt_fixup_clock(const char *path
, u32 freq
)
79 void *devp
= finddevice(path
);
82 printf("%s: clock-frequency <- %x (%dMHz)\n\r", path
, freq
, MHZ(freq
));
83 setprop_val(devp
, "clock-frequency", freq
);
87 void dt_fixup_mac_address_by_alias(const char *alias
, const u8
*addr
)
89 void *devp
= find_node_by_alias(alias
);
92 printf("%s: local-mac-address <-"
93 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", alias
,
94 addr
[0], addr
[1], addr
[2],
95 addr
[3], addr
[4], addr
[5]);
97 setprop(devp
, "local-mac-address", addr
, 6);
101 void dt_fixup_mac_address(u32 index
, const u8
*addr
)
103 void *devp
= find_node_by_prop_value(NULL
, "linux,network-index",
104 (void*)&index
, sizeof(index
));
107 printf("ENET%d: local-mac-address <-"
108 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index
,
109 addr
[0], addr
[1], addr
[2],
110 addr
[3], addr
[4], addr
[5]);
112 setprop(devp
, "local-mac-address", addr
, 6);
116 void __dt_fixup_mac_addresses(u32 startindex
, ...)
119 u32 index
= startindex
;
122 va_start(ap
, startindex
);
124 while ((addr
= va_arg(ap
, const u8
*)))
125 dt_fixup_mac_address(index
++, addr
);
130 #define MAX_ADDR_CELLS 4
132 void dt_get_reg_format(void *node
, u32
*naddr
, u32
*nsize
)
134 if (getprop(node
, "#address-cells", naddr
, 4) != 4)
136 if (getprop(node
, "#size-cells", nsize
, 4) != 4)
140 static void copy_val(u32
*dest
, u32
*src
, int naddr
)
142 int pad
= MAX_ADDR_CELLS
- naddr
;
144 memset(dest
, 0, pad
* 4);
145 memcpy(dest
+ pad
, src
, naddr
* 4);
148 static int sub_reg(u32
*reg
, u32
*sub
)
152 for (i
= MAX_ADDR_CELLS
- 1; i
>= 0; i
--) {
153 int prev_borrow
= borrow
;
154 borrow
= reg
[i
] < sub
[i
] + prev_borrow
;
155 reg
[i
] -= sub
[i
] + prev_borrow
;
161 static int add_reg(u32
*reg
, u32
*add
, int naddr
)
165 for (i
= MAX_ADDR_CELLS
- 1; i
>= MAX_ADDR_CELLS
- naddr
; i
--) {
166 u64 tmp
= (u64
)reg
[i
] + add
[i
] + carry
;
174 /* It is assumed that if the first byte of reg fits in a
175 * range, then the whole reg block fits.
177 static int compare_reg(u32
*reg
, u32
*range
, u32
*rangesize
)
182 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
183 if (reg
[i
] < range
[i
])
185 if (reg
[i
] > range
[i
])
189 for (i
= 0; i
< MAX_ADDR_CELLS
; i
++) {
190 end
= range
[i
] + rangesize
[i
];
198 return reg
[i
] != end
;
201 /* reg must be MAX_ADDR_CELLS */
202 static int find_range(u32
*reg
, u32
*ranges
, int nregaddr
,
203 int naddr
, int nsize
, int buflen
)
205 int nrange
= nregaddr
+ naddr
+ nsize
;
208 for (i
= 0; i
+ nrange
<= buflen
; i
+= nrange
) {
209 u32 range_addr
[MAX_ADDR_CELLS
];
210 u32 range_size
[MAX_ADDR_CELLS
];
212 copy_val(range_addr
, ranges
+ i
, nregaddr
);
213 copy_val(range_size
, ranges
+ i
+ nregaddr
+ naddr
, nsize
);
215 if (compare_reg(reg
, range_addr
, range_size
))
222 /* Currently only generic buses without special encodings are supported.
223 * In particular, PCI is not supported. Also, only the beginning of the
224 * reg block is tracked; size is ignored except in ranges.
226 static u32 prop_buf
[MAX_PROP_LEN
/ 4];
228 static int dt_xlate(void *node
, int res
, int reglen
, unsigned long *addr
,
231 u32 last_addr
[MAX_ADDR_CELLS
];
232 u32 this_addr
[MAX_ADDR_CELLS
];
234 u64 ret_addr
, ret_size
;
235 u32 naddr
, nsize
, prev_naddr
, prev_nsize
;
238 parent
= get_parent(node
);
242 dt_get_reg_format(parent
, &naddr
, &nsize
);
247 offset
= (naddr
+ nsize
) * res
;
249 if (reglen
< offset
+ naddr
+ nsize
||
250 MAX_PROP_LEN
< (offset
+ naddr
+ nsize
) * 4)
253 copy_val(last_addr
, prop_buf
+ offset
, naddr
);
255 ret_size
= prop_buf
[offset
+ naddr
];
258 ret_size
|= prop_buf
[offset
+ naddr
+ 1];
266 parent
= get_parent(node
);
270 dt_get_reg_format(parent
, &naddr
, &nsize
);
272 buflen
= getprop(node
, "ranges", prop_buf
,
276 if (buflen
< 0 || buflen
> sizeof(prop_buf
))
279 offset
= find_range(last_addr
, prop_buf
, prev_naddr
,
280 naddr
, prev_nsize
, buflen
/ 4);
285 copy_val(this_addr
, prop_buf
+ offset
, prev_naddr
);
287 if (!sub_reg(last_addr
, this_addr
))
290 copy_val(this_addr
, prop_buf
+ offset
+ prev_naddr
, naddr
);
292 if (!add_reg(last_addr
, this_addr
, naddr
))
299 ret_addr
= ((u64
)last_addr
[2] << 32) | last_addr
[3];
301 if (sizeof(void *) == 4 &&
302 (ret_addr
>= 0x100000000ULL
|| ret_size
> 0x100000000ULL
||
303 ret_addr
+ ret_size
> 0x100000000ULL
))
313 int dt_xlate_reg(void *node
, int res
, unsigned long *addr
, unsigned long *size
)
317 reglen
= getprop(node
, "reg", prop_buf
, sizeof(prop_buf
)) / 4;
318 return dt_xlate(node
, res
, reglen
, addr
, size
);
321 int dt_xlate_addr(void *node
, u32
*buf
, int buflen
, unsigned long *xlated_addr
)
324 if (buflen
> sizeof(prop_buf
))
327 memcpy(prop_buf
, buf
, buflen
);
328 return dt_xlate(node
, 0, buflen
/ 4, xlated_addr
, NULL
);
331 int dt_is_compatible(void *node
, const char *compat
)
333 char *buf
= (char *)prop_buf
;
336 len
= getprop(node
, "compatible", buf
, MAX_PROP_LEN
);
340 for (pos
= 0; pos
< len
; pos
++) {
341 if (!strcmp(buf
+ pos
, compat
))
344 pos
+= strnlen(&buf
[pos
], len
- pos
);
350 int dt_get_virtual_reg(void *node
, void **addr
, int nres
)
355 n
= getprop(node
, "virtual-reg", addr
, nres
* 4);
359 for (n
= 0; n
< nres
; n
++) {
360 if (!dt_xlate_reg(node
, n
, &xaddr
, NULL
))
363 addr
[n
] = (void *)xaddr
;