0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <stdarg.h>
0011 #include <stddef.h>
0012 #include "types.h"
0013 #include "string.h"
0014 #include "stdio.h"
0015 #include "ops.h"
0016 #include "of.h"
0017
0018 void dt_fixup_memory(u64 start, u64 size)
0019 {
0020 void *root, *memory;
0021 int naddr, nsize, i;
0022 u32 memreg[4];
0023
0024 root = finddevice("/");
0025 if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
0026 naddr = 2;
0027 else
0028 naddr = be32_to_cpu(naddr);
0029 if (naddr < 1 || naddr > 2)
0030 fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
0031
0032 if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
0033 nsize = 1;
0034 else
0035 nsize = be32_to_cpu(nsize);
0036 if (nsize < 1 || nsize > 2)
0037 fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
0038
0039 i = 0;
0040 if (naddr == 2)
0041 memreg[i++] = cpu_to_be32(start >> 32);
0042 memreg[i++] = cpu_to_be32(start & 0xffffffff);
0043 if (nsize == 2)
0044 memreg[i++] = cpu_to_be32(size >> 32);
0045 memreg[i++] = cpu_to_be32(size & 0xffffffff);
0046
0047 memory = finddevice("/memory");
0048 if (! memory) {
0049 memory = create_node(NULL, "memory");
0050 setprop_str(memory, "device_type", "memory");
0051 }
0052
0053 printf("Memory <- <0x%x", be32_to_cpu(memreg[0]));
0054 for (i = 1; i < (naddr + nsize); i++)
0055 printf(" 0x%x", be32_to_cpu(memreg[i]));
0056 printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
0057
0058 setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
0059 }
0060
0061 #define MHZ(x) ((x + 500000) / 1000000)
0062
0063 void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus)
0064 {
0065 void *devp = NULL;
0066
0067 printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu));
0068 printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb));
0069 if (bus > 0)
0070 printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
0071
0072 while ((devp = find_node_by_devtype(devp, "cpu"))) {
0073 setprop_val(devp, "clock-frequency", cpu_to_be32(cpu));
0074 setprop_val(devp, "timebase-frequency", cpu_to_be32(tb));
0075 if (bus > 0)
0076 setprop_val(devp, "bus-frequency", cpu_to_be32(bus));
0077 }
0078
0079 timebase_period_ns = 1000000000 / tb;
0080 }
0081
0082 void dt_fixup_clock(const char *path, u32 freq)
0083 {
0084 void *devp = finddevice(path);
0085
0086 if (devp) {
0087 printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
0088 setprop_val(devp, "clock-frequency", cpu_to_be32(freq));
0089 }
0090 }
0091
0092 void dt_fixup_mac_address_by_alias(const char *alias, const u8 *addr)
0093 {
0094 void *devp = find_node_by_alias(alias);
0095
0096 if (devp) {
0097 printf("%s: local-mac-address <-"
0098 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", alias,
0099 addr[0], addr[1], addr[2],
0100 addr[3], addr[4], addr[5]);
0101
0102 setprop(devp, "local-mac-address", addr, 6);
0103 }
0104 }
0105
0106 void dt_fixup_mac_address(u32 index, const u8 *addr)
0107 {
0108 void *devp = find_node_by_prop_value(NULL, "linux,network-index",
0109 (void*)&index, sizeof(index));
0110
0111 if (devp) {
0112 printf("ENET%d: local-mac-address <-"
0113 " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
0114 addr[0], addr[1], addr[2],
0115 addr[3], addr[4], addr[5]);
0116
0117 setprop(devp, "local-mac-address", addr, 6);
0118 }
0119 }
0120
0121 void __dt_fixup_mac_addresses(u32 startindex, ...)
0122 {
0123 va_list ap;
0124 u32 index = startindex;
0125 const u8 *addr;
0126
0127 va_start(ap, startindex);
0128
0129 while ((addr = va_arg(ap, const u8 *)))
0130 dt_fixup_mac_address(index++, addr);
0131
0132 va_end(ap);
0133 }
0134
0135 #define MAX_ADDR_CELLS 4
0136
0137 void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize)
0138 {
0139 if (getprop(node, "#address-cells", naddr, 4) != 4)
0140 *naddr = 2;
0141 else
0142 *naddr = be32_to_cpu(*naddr);
0143 if (getprop(node, "#size-cells", nsize, 4) != 4)
0144 *nsize = 1;
0145 else
0146 *nsize = be32_to_cpu(*nsize);
0147 }
0148
0149 static void copy_val(u32 *dest, u32 *src, int naddr)
0150 {
0151 int pad = MAX_ADDR_CELLS - naddr;
0152
0153 memset(dest, 0, pad * 4);
0154 memcpy(dest + pad, src, naddr * 4);
0155 }
0156
0157 static int sub_reg(u32 *reg, u32 *sub)
0158 {
0159 int i, borrow = 0;
0160
0161 for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
0162 int prev_borrow = borrow;
0163 borrow = reg[i] < sub[i] + prev_borrow;
0164 reg[i] -= sub[i] + prev_borrow;
0165 }
0166
0167 return !borrow;
0168 }
0169
0170 static int add_reg(u32 *reg, u32 *add, int naddr)
0171 {
0172 int i, carry = 0;
0173
0174 for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
0175 u64 tmp = (u64)be32_to_cpu(reg[i]) + be32_to_cpu(add[i]) + carry;
0176 carry = tmp >> 32;
0177 reg[i] = cpu_to_be32((u32)tmp);
0178 }
0179
0180 return !carry;
0181 }
0182
0183
0184
0185
0186 static int compare_reg(u32 *reg, u32 *range, u32 *rangesize)
0187 {
0188 int i;
0189 u32 end;
0190
0191 for (i = 0; i < MAX_ADDR_CELLS; i++) {
0192 if (be32_to_cpu(reg[i]) < be32_to_cpu(range[i]))
0193 return 0;
0194 if (be32_to_cpu(reg[i]) > be32_to_cpu(range[i]))
0195 break;
0196 }
0197
0198 for (i = 0; i < MAX_ADDR_CELLS; i++) {
0199 end = be32_to_cpu(range[i]) + be32_to_cpu(rangesize[i]);
0200
0201 if (be32_to_cpu(reg[i]) < end)
0202 break;
0203 if (be32_to_cpu(reg[i]) > end)
0204 return 0;
0205 }
0206
0207 return reg[i] != end;
0208 }
0209
0210
0211 static int find_range(u32 *reg, u32 *ranges, int nregaddr,
0212 int naddr, int nsize, int buflen)
0213 {
0214 int nrange = nregaddr + naddr + nsize;
0215 int i;
0216
0217 for (i = 0; i + nrange <= buflen; i += nrange) {
0218 u32 range_addr[MAX_ADDR_CELLS];
0219 u32 range_size[MAX_ADDR_CELLS];
0220
0221 copy_val(range_addr, ranges + i, nregaddr);
0222 copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
0223
0224 if (compare_reg(reg, range_addr, range_size))
0225 return i;
0226 }
0227
0228 return -1;
0229 }
0230
0231
0232
0233
0234
0235 static u32 prop_buf[MAX_PROP_LEN / 4];
0236
0237 static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
0238 unsigned long *size)
0239 {
0240 u32 last_addr[MAX_ADDR_CELLS];
0241 u32 this_addr[MAX_ADDR_CELLS];
0242 void *parent;
0243 u64 ret_addr, ret_size;
0244 u32 naddr, nsize, prev_naddr, prev_nsize;
0245 int buflen, offset;
0246
0247 parent = get_parent(node);
0248 if (!parent)
0249 return 0;
0250
0251 dt_get_reg_format(parent, &naddr, &nsize);
0252 if (nsize > 2)
0253 return 0;
0254
0255 offset = (naddr + nsize) * res;
0256
0257 if (reglen < offset + naddr + nsize ||
0258 MAX_PROP_LEN < (offset + naddr + nsize) * 4)
0259 return 0;
0260
0261 copy_val(last_addr, prop_buf + offset, naddr);
0262
0263 ret_size = be32_to_cpu(prop_buf[offset + naddr]);
0264 if (nsize == 2) {
0265 ret_size <<= 32;
0266 ret_size |= be32_to_cpu(prop_buf[offset + naddr + 1]);
0267 }
0268
0269 for (;;) {
0270 prev_naddr = naddr;
0271 prev_nsize = nsize;
0272 node = parent;
0273
0274 parent = get_parent(node);
0275 if (!parent)
0276 break;
0277
0278 dt_get_reg_format(parent, &naddr, &nsize);
0279
0280 buflen = getprop(node, "ranges", prop_buf,
0281 sizeof(prop_buf));
0282 if (buflen == 0)
0283 continue;
0284 if (buflen < 0 || buflen > sizeof(prop_buf))
0285 return 0;
0286
0287 offset = find_range(last_addr, prop_buf, prev_naddr,
0288 naddr, prev_nsize, buflen / 4);
0289 if (offset < 0)
0290 return 0;
0291
0292 copy_val(this_addr, prop_buf + offset, prev_naddr);
0293
0294 if (!sub_reg(last_addr, this_addr))
0295 return 0;
0296
0297 copy_val(this_addr, prop_buf + offset + prev_naddr, naddr);
0298
0299 if (!add_reg(last_addr, this_addr, naddr))
0300 return 0;
0301 }
0302
0303 if (naddr > 2)
0304 return 0;
0305
0306 ret_addr = ((u64)be32_to_cpu(last_addr[2]) << 32) | be32_to_cpu(last_addr[3]);
0307 if (sizeof(void *) == 4 &&
0308 (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
0309 ret_addr + ret_size > 0x100000000ULL))
0310 return 0;
0311
0312 *addr = ret_addr;
0313 if (size)
0314 *size = ret_size;
0315
0316 return 1;
0317 }
0318
0319 int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
0320 {
0321 int reglen;
0322
0323 reglen = getprop(node, "reg", prop_buf, sizeof(prop_buf)) / 4;
0324 return dt_xlate(node, res, reglen, addr, size);
0325 }
0326
0327 int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
0328 {
0329
0330 if (buflen > sizeof(prop_buf))
0331 return 0;
0332
0333 memcpy(prop_buf, buf, buflen);
0334 return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
0335 }
0336
0337 int dt_is_compatible(void *node, const char *compat)
0338 {
0339 char *buf = (char *)prop_buf;
0340 int len, pos;
0341
0342 len = getprop(node, "compatible", buf, MAX_PROP_LEN);
0343 if (len < 0)
0344 return 0;
0345
0346 for (pos = 0; pos < len; pos++) {
0347 if (!strcmp(buf + pos, compat))
0348 return 1;
0349
0350 pos += strnlen(&buf[pos], len - pos);
0351 }
0352
0353 return 0;
0354 }
0355
0356 int dt_get_virtual_reg(void *node, void **addr, int nres)
0357 {
0358 unsigned long xaddr;
0359 int n, i;
0360
0361 n = getprop(node, "virtual-reg", addr, nres * 4);
0362 if (n > 0) {
0363 for (i = 0; i < n/4; i ++)
0364 ((u32 *)addr)[i] = be32_to_cpu(((u32 *)addr)[i]);
0365 return n / 4;
0366 }
0367
0368 for (n = 0; n < nres; n++) {
0369 if (!dt_xlate_reg(node, n, &xaddr, NULL))
0370 break;
0371
0372 addr[n] = (void *)xaddr;
0373 }
0374
0375 return n;
0376 }
0377