1 /* 2 * devtree.c - convenience functions for device tree manipulation 3 * Copyright 2007 David Gibson, IBM Corporation. 4 * Copyright (c) 2007 Freescale Semiconductor, Inc. 5 * 6 * Authors: David Gibson <david@gibson.dropbear.id.au> 7 * Scott Wood <scottwood@freescale.com> 8 * 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. 13 */ 14 #include <stdarg.h> 15 #include <stddef.h> 16 #include "types.h" 17 #include "string.h" 18 #include "stdio.h" 19 #include "ops.h" 20 21 void dt_fixup_memory(u64 start, u64 size) 22 { 23 void *root, *memory; 24 int naddr, nsize, i; 25 u32 memreg[4]; 26 27 root = finddevice("/"); 28 if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0) 29 naddr = 2; 30 if (naddr < 1 || naddr > 2) 31 fatal("Can't cope with #address-cells == %d in /\n\r", naddr); 32 33 if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0) 34 nsize = 1; 35 if (nsize < 1 || nsize > 2) 36 fatal("Can't cope with #size-cells == %d in /\n\r", nsize); 37 38 i = 0; 39 if (naddr == 2) 40 memreg[i++] = start >> 32; 41 memreg[i++] = start & 0xffffffff; 42 if (nsize == 2) 43 memreg[i++] = size >> 32; 44 memreg[i++] = size & 0xffffffff; 45 46 memory = finddevice("/memory"); 47 if (! memory) { 48 memory = create_node(NULL, "memory"); 49 setprop_str(memory, "device_type", "memory"); 50 } 51 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)); 56 57 setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32)); 58 } 59 60 #define MHZ(x) ((x + 500000) / 1000000) 61 62 void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus) 63 { 64 void *devp = NULL; 65 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)); 68 if (bus > 0) 69 printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus)); 70 71 while ((devp = find_node_by_devtype(devp, "cpu"))) { 72 setprop_val(devp, "clock-frequency", cpu); 73 setprop_val(devp, "timebase-frequency", tb); 74 if (bus > 0) 75 setprop_val(devp, "bus-frequency", bus); 76 } 77 } 78 79 void dt_fixup_clock(const char *path, u32 freq) 80 { 81 void *devp = finddevice(path); 82 83 if (devp) { 84 printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq)); 85 setprop_val(devp, "clock-frequency", freq); 86 } 87 } 88 89 void __dt_fixup_mac_addresses(u32 startindex, ...) 90 { 91 va_list ap; 92 u32 index = startindex; 93 void *devp; 94 const u8 *addr; 95 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)); 100 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]); 104 105 if (devp) 106 setprop(devp, "local-mac-address", addr, 6); 107 108 index++; 109 } 110 va_end(ap); 111 } 112 113 #define MAX_ADDR_CELLS 4 114 #define MAX_RANGES 8 115 116 static void get_reg_format(void *node, u32 *naddr, u32 *nsize) 117 { 118 if (getprop(node, "#address-cells", naddr, 4) != 4) 119 *naddr = 2; 120 if (getprop(node, "#size-cells", nsize, 4) != 4) 121 *nsize = 1; 122 } 123 124 static void copy_val(u32 *dest, u32 *src, int naddr) 125 { 126 int pad = MAX_ADDR_CELLS - naddr; 127 128 memset(dest, 0, pad * 4); 129 memcpy(dest + pad, src, naddr * 4); 130 } 131 132 static int sub_reg(u32 *reg, u32 *sub) 133 { 134 int i, borrow = 0; 135 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; 140 } 141 142 return !borrow; 143 } 144 145 static int add_reg(u32 *reg, u32 *add, int naddr) 146 { 147 int i, carry = 0; 148 149 for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) { 150 u64 tmp = (u64)reg[i] + add[i] + carry; 151 carry = tmp >> 32; 152 reg[i] = (u32)tmp; 153 } 154 155 return !carry; 156 } 157 158 /* It is assumed that if the first byte of reg fits in a 159 * range, then the whole reg block fits. 160 */ 161 static int compare_reg(u32 *reg, u32 *range, u32 *rangesize) 162 { 163 int i; 164 u32 end; 165 166 for (i = 0; i < MAX_ADDR_CELLS; i++) { 167 if (reg[i] < range[i]) 168 return 0; 169 if (reg[i] > range[i]) 170 break; 171 } 172 173 for (i = 0; i < MAX_ADDR_CELLS; i++) { 174 end = range[i] + rangesize[i]; 175 176 if (reg[i] < end) 177 break; 178 if (reg[i] > end) 179 return 0; 180 } 181 182 return reg[i] != end; 183 } 184 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) 188 { 189 int nrange = nregaddr + naddr + nsize; 190 int i; 191 192 for (i = 0; i + nrange <= buflen; i += nrange) { 193 u32 range_addr[MAX_ADDR_CELLS]; 194 u32 range_size[MAX_ADDR_CELLS]; 195 196 copy_val(range_addr, ranges + i, naddr); 197 copy_val(range_size, ranges + i + nregaddr + naddr, nsize); 198 199 if (compare_reg(reg, range_addr, range_size)) 200 return i; 201 } 202 203 return -1; 204 } 205 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. 209 */ 210 static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3]; 211 212 static int dt_xlate(void *node, int res, int reglen, unsigned long *addr, 213 unsigned long *size) 214 { 215 u32 last_addr[MAX_ADDR_CELLS]; 216 u32 this_addr[MAX_ADDR_CELLS]; 217 void *parent; 218 u64 ret_addr, ret_size; 219 u32 naddr, nsize, prev_naddr; 220 int buflen, offset; 221 222 parent = get_parent(node); 223 if (!parent) 224 return 0; 225 226 get_reg_format(parent, &naddr, &nsize); 227 228 if (nsize > 2) 229 return 0; 230 231 offset = (naddr + nsize) * res; 232 233 if (reglen < offset + naddr + nsize || 234 sizeof(dt_xlate_buf) < offset + naddr + nsize) 235 return 0; 236 237 copy_val(last_addr, dt_xlate_buf + offset, naddr); 238 239 ret_size = dt_xlate_buf[offset + naddr]; 240 if (nsize == 2) { 241 ret_size <<= 32; 242 ret_size |= dt_xlate_buf[offset + naddr + 1]; 243 } 244 245 while ((node = get_parent(node))) { 246 prev_naddr = naddr; 247 248 get_reg_format(node, &naddr, &nsize); 249 250 buflen = getprop(node, "ranges", dt_xlate_buf, 251 sizeof(dt_xlate_buf)); 252 if (buflen < 0) 253 continue; 254 if (buflen > sizeof(dt_xlate_buf)) 255 return 0; 256 257 offset = find_range(last_addr, dt_xlate_buf, prev_naddr, 258 naddr, nsize, buflen / 4); 259 260 if (offset < 0) 261 return 0; 262 263 copy_val(this_addr, dt_xlate_buf + offset, prev_naddr); 264 265 if (!sub_reg(last_addr, this_addr)) 266 return 0; 267 268 copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr); 269 270 if (!add_reg(last_addr, this_addr, naddr)) 271 return 0; 272 } 273 274 if (naddr > 2) 275 return 0; 276 277 ret_addr = ((u64)last_addr[2] << 32) | last_addr[3]; 278 279 if (sizeof(void *) == 4 && 280 (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL || 281 ret_addr + ret_size > 0x100000000ULL)) 282 return 0; 283 284 *addr = ret_addr; 285 if (size) 286 *size = ret_size; 287 288 return 1; 289 } 290 291 int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size) 292 { 293 int reglen; 294 295 reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4; 296 return dt_xlate(node, res, reglen, addr, size); 297 } 298 299 int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr) 300 { 301 302 if (buflen > sizeof(dt_xlate_buf)) 303 return 0; 304 305 memcpy(dt_xlate_buf, buf, buflen); 306 return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL); 307 } 308