Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * devtree.c - convenience functions for device tree manipulation
0004  * Copyright 2007 David Gibson, IBM Corporation.
0005  * Copyright (c) 2007 Freescale Semiconductor, Inc.
0006  *
0007  * Authors: David Gibson <david@gibson.dropbear.id.au>
0008  *      Scott Wood <scottwood@freescale.com>
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 /* It is assumed that if the first byte of reg fits in a
0184  * range, then the whole reg block fits.
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 /* reg must be MAX_ADDR_CELLS */
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 /* Currently only generic buses without special encodings are supported.
0232  * In particular, PCI is not supported.  Also, only the beginning of the
0233  * reg block is tracked; size is ignored except in ranges.
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