ofw_machdep.c revision 141753
186229Stmm/*- 286229Stmm * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. 3141753Smarius * Copyright (c) 2005 by Marius Strobl <marius@FreeBSD.org>. 486229Stmm * All rights reserved. 586229Stmm * 686229Stmm * Redistribution and use in source and binary forms, with or without 786229Stmm * modification, are permitted provided that the following conditions 886229Stmm * are met: 986229Stmm * 1. Redistributions of source code must retain the above copyright 1086229Stmm * notice, this list of conditions and the following disclaimer. 1186229Stmm * 2. Redistributions in binary form must reproduce the above copyright 1286229Stmm * notice, this list of conditions and the following disclaimer in the 1386229Stmm * documentation and/or other materials provided with the distribution. 1486229Stmm * 1586229Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1686229Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1786229Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1886229Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 1986229Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2086229Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2186229Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2286229Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2386229Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 2486229Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2586229Stmm * 2686229Stmm * $FreeBSD: head/sys/sparc64/sparc64/ofw_machdep.c 141753 2005-02-12 19:13:51Z marius $ 2786229Stmm */ 2886229Stmm 2986229Stmm/* 30133862Smarius * Some Open Firmware helper functions that are likely machine dependent. 3186229Stmm */ 3286229Stmm 3386229Stmm#include <sys/param.h> 34133589Smarius#include <sys/bus.h> 3586229Stmm#include <sys/systm.h> 3686229Stmm 3788370Stmm#include <net/ethernet.h> 3888370Stmm 39133589Smarius#include <dev/ofw/ofw_bus.h> 40141753Smarius#include <dev/ofw/ofw_pci.h> 41119338Simp#include <dev/ofw/openfirm.h> 4286229Stmm 43119697Smarcel#include <machine/bus.h> 4486229Stmm#include <machine/idprom.h> 45141753Smarius#include <machine/ofw_bus.h> 4686229Stmm#include <machine/ofw_machdep.h> 4786229Stmm 4886229Stmmvoid 4986229StmmOF_getetheraddr(device_t dev, u_char *addr) 5086229Stmm{ 51133728Smarius char buf[sizeof("true")]; 5286229Stmm phandle_t node; 5386229Stmm struct idprom idp; 5486229Stmm 55133728Smarius if ((node = OF_finddevice("/options")) > 0 && 56133728Smarius OF_getprop(node, "local-mac-address?", buf, sizeof(buf)) > 0) { 57133728Smarius buf[sizeof(buf) - 1] = '\0'; 58133728Smarius if (strcmp(buf, "true") == 0 && 59133728Smarius (node = ofw_bus_get_node(dev)) > 0 && 60133728Smarius OF_getprop(node, "local-mac-address", addr, 61133728Smarius ETHER_ADDR_LEN) == ETHER_ADDR_LEN) 62133728Smarius return; 63133728Smarius } 64133728Smarius 6586229Stmm node = OF_peer(0); 6686229Stmm if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1) 6786229Stmm panic("Could not determine the machine ethernet address"); 6888370Stmm bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN); 6986229Stmm} 70119697Smarcel 71141753Smariusstatic __inline uint32_t 72141753Smariusphys_hi_mask_space(const char *bus, uint32_t phys_hi) 73141753Smarius{ 74141753Smarius uint32_t space; 75141753Smarius 76141753Smarius space = phys_hi; 77141753Smarius if (strcmp(bus, "ebus") == 0 || strcmp(bus, "isa") == 0) 78141753Smarius space &= 0x1; 79141753Smarius else if (strcmp(bus, "pci") == 0) 80141753Smarius space &= OFW_PCI_PHYS_HI_SPACEMASK; 81141753Smarius /* The phys.hi cells of the other busses only contain space bits. */ 82141753Smarius return (space); 83141753Smarius} 84141753Smarius 85141753Smarius/* 86141753Smarius * Return the physical address and the bus space to use for a node 87141753Smarius * referenced by its package handle and the index of the register bank 88141753Smarius * to decode. Intended to be used to together with sparc64_fake_bustag() 89141753Smarius * by console drivers in early boot only. 90141753Smarius * Works by mapping the address of the node's bank given in the address 91141753Smarius * space of its parent upward in the device tree at each bridge along the 92141753Smarius * path. 93141753Smarius * Currently only really deals with max. 64-bit addresses, i.e. addresses 94141753Smarius * consisting of max. 2 phys cells (phys.hi and phys.lo). If we encounter 95141753Smarius * a 3 phys cells address (as with PCI addresses) we assume phys.hi can 96141753Smarius * be ignored except for the space bits (generally contained in phys.hi) 97141753Smarius * and treat phys.mid as phys.hi. 98141753Smarius */ 99119697Smarcelint 100141753SmariusOF_decode_addr(phandle_t node, int bank, int *space, bus_addr_t *addr) 101119697Smarcel{ 102119697Smarcel char name[32]; 103141753Smarius uint64_t cend, cstart, end, phys, sz, start; 104141753Smarius pcell_t addrc, szc, paddrc; 105141753Smarius phandle_t bus, lbus, pbus; 106141753Smarius uint32_t banks[10 * 5]; /* 10 PCI banks */ 107141753Smarius uint32_t cspace, spc; 108141753Smarius int i, j, nbank; 109119697Smarcel 110141753Smarius /* 111141753Smarius * In general the addresses are contained in the "reg" property 112141753Smarius * of a node. The first address in the "reg" property of a PCI 113141753Smarius * node however is the address of its configuration registers in 114141753Smarius * the configuration space of the host bridge. Additional entries 115141753Smarius * denote the memory and I/O addresses. For relocatable addresses 116141753Smarius * the "reg" property contains the BAR, for non-relocatable 117141753Smarius * addresses it contains the absolute PCI address. The PCI-only 118141753Smarius * "assigned-addresses" property however always contains the 119141753Smarius * absolute PCI addresses. 120141753Smarius * The "assigned-addresses" and "reg" properties are arrays of 121141753Smarius * address structures consisting of #address-cells 32-bit phys 122141753Smarius * cells and #size-cells 32-bit size cells. If a parent lacks 123141753Smarius * the "#address-cells" or "#size-cells" property the default 124141753Smarius * for #address-cells to use is 2 and for #size-cells 1. 125141753Smarius */ 126119697Smarcel bus = OF_parent(node); 127123866Sobrien if (bus == 0) 128119697Smarcel return (ENXIO); 129119697Smarcel if (OF_getprop(bus, "name", name, sizeof(name)) == -1) 130119697Smarcel return (ENXIO); 131119697Smarcel name[sizeof(name) - 1] = '\0'; 132141753Smarius if (OF_getprop(bus, "#address-cells", &addrc, sizeof(addrc)) == -1) 133141753Smarius addrc = 2; 134141753Smarius if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1) 135141753Smarius szc = 1; 136141753Smarius if (szc > 2) 137141753Smarius return (ENXIO); 138141753Smarius if (strcmp(name, "pci") == 0) { 139141753Smarius if (addrc > 3) 140119697Smarcel return (ENXIO); 141141753Smarius nbank = OF_getprop(node, "assigned-addresses", &banks, 142141753Smarius sizeof(banks)); 143141753Smarius } else { 144141753Smarius if (addrc > 2) 145119697Smarcel return (ENXIO); 146141753Smarius nbank = OF_getprop(node, "reg", &banks, sizeof(banks)); 147141753Smarius } 148141753Smarius if (nbank == -1) 149141753Smarius return (ENXIO); 150141753Smarius nbank /= sizeof(banks[0]) * (addrc + szc); 151141753Smarius if (bank < 0 || bank > nbank - 1) 152141753Smarius return (ENXIO); 153141753Smarius phys = 0; 154141753Smarius for (i = 0; i < MIN(2, addrc); i++) 155141753Smarius phys |= (uint64_t)banks[(addrc + szc) * bank + addrc - 2 + i] << 156141753Smarius 32 * (MIN(2, addrc) - i - 1); 157141753Smarius sz = 0; 158141753Smarius for (i = 0; i < szc; i++) 159141753Smarius sz |= (uint64_t)banks[(addrc + szc) * bank + addrc + i] << 160141753Smarius 32 * (szc - i - 1); 161141753Smarius start = phys; 162141753Smarius end = phys + sz - 1; 163141753Smarius spc = phys_hi_mask_space(name, banks[(addrc + szc) * bank]); 164119697Smarcel 165141753Smarius /* 166141753Smarius * Map upward in the device tree at every bridge we encounter 167141753Smarius * using their "ranges" properties. 168141753Smarius * The "ranges" property of a bridge is an array of a structure 169141753Smarius * consisting of that bridge's #address-cells 32-bit child-phys 170141753Smarius * cells, its parent bridge #address-cells 32-bit parent-phys 171141753Smarius * cells and that bridge's #size-cells 32-bit size cells. 172141753Smarius * If a bridge doesn't have a "ranges" property no mapping is 173141753Smarius * necessary at that bridge. 174141753Smarius */ 175141753Smarius cspace = 0; 176141753Smarius lbus = bus; 177141753Smarius while ((pbus = OF_parent(bus)) != 0) { 178141753Smarius if (OF_getprop(pbus, "#address-cells", &paddrc, 179141753Smarius sizeof(paddrc)) == -1) 180141753Smarius paddrc = 2; 181141753Smarius if (paddrc > 3) 182141753Smarius return (ENXIO); 183141753Smarius nbank = OF_getprop(bus, "ranges", &banks, sizeof(banks)); 184141753Smarius if (nbank == -1) { 185141753Smarius if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 186119697Smarcel return (ENXIO); 187141753Smarius name[sizeof(name) - 1] = '\0'; 188141753Smarius goto skip; 189141753Smarius } 190141753Smarius if (lbus != bus) { 191141753Smarius if (OF_getprop(bus, "#size-cells", &szc, 192141753Smarius sizeof(szc)) == -1) 193141753Smarius szc = 1; 194141753Smarius if (szc > 2) 195141753Smarius return (ENXIO); 196141753Smarius } 197141753Smarius nbank /= sizeof(banks[0]) * (addrc + paddrc + szc); 198141753Smarius for (i = 0; i < nbank; i++) { 199141753Smarius cspace = phys_hi_mask_space(name, 200141753Smarius banks[(addrc + paddrc + szc) * i]); 201141753Smarius if (cspace != spc) 202141753Smarius continue; 203141753Smarius phys = 0; 204141753Smarius for (j = 0; j < MIN(2, addrc); j++) 205141753Smarius phys |= (uint64_t)banks[ 206141753Smarius (addrc + paddrc + szc) * i + 207141753Smarius addrc - 2 + j] << 208141753Smarius 32 * (MIN(2, addrc) - j - 1); 209141753Smarius sz = 0; 210141753Smarius for (j = 0; j < szc; j++) 211141753Smarius sz |= (uint64_t)banks[ 212141753Smarius (addrc + paddrc + szc) * i + addrc + 213141753Smarius paddrc + j] << 214141753Smarius 32 * (szc - j - 1); 215141753Smarius cstart = phys; 216141753Smarius cend = phys + sz - 1; 217141753Smarius if (start < cstart || start > cend) 218141753Smarius continue; 219141753Smarius if (end < cstart || end > cend) 220141753Smarius return (ENXIO); 221141753Smarius phys = 0; 222141753Smarius for (j = 0; j < MIN(2, paddrc); j++) 223141753Smarius phys |= (uint64_t)banks[ 224141753Smarius (addrc + paddrc + szc) * i + addrc + 225141753Smarius paddrc - 2 + j] << 226141753Smarius 32 * (MIN(2, paddrc) - j - 1); 227141753Smarius start += phys - cstart; 228141753Smarius end += phys - cstart; 229119697Smarcel if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 230119697Smarcel return (ENXIO); 231119697Smarcel name[sizeof(name) - 1] = '\0'; 232141753Smarius spc = phys_hi_mask_space(name, 233141753Smarius banks[(addrc + paddrc + szc) * i + addrc]); 234141753Smarius break; 235119697Smarcel } 236141753Smarius if (i == nbank) 237119697Smarcel return (ENXIO); 238141753Smarius skip: 239141753Smarius addrc = paddrc; 240141753Smarius lbus = bus; 241141753Smarius bus = pbus; 242141753Smarius } 243119697Smarcel 244141753Smarius /* Done with mapping. Return the bus space as used by FreeBSD. */ 245141753Smarius *addr = start; 246141753Smarius if (OF_getprop(lbus, "name", name, sizeof(name)) == -1) 247141753Smarius return (ENXIO); 248141753Smarius name[sizeof(name) - 1] = '\0'; 249141753Smarius if (strcmp(name, "central") == 0) { 250141753Smarius *space = UPA_BUS_SPACE; 251141753Smarius return (0); 252141753Smarius } else if (strcmp(name, "pci") == 0) { 253141753Smarius switch (cspace) { 254141753Smarius case OFW_PCI_PHYS_HI_SPACE_IO: 255141753Smarius *space = PCI_IO_BUS_SPACE; 256141753Smarius return (0); 257141753Smarius case OFW_PCI_PHYS_HI_SPACE_MEM32: 258141753Smarius *space = PCI_MEMORY_BUS_SPACE; 259141753Smarius return (0); 260119697Smarcel } 261119697Smarcel } else if (strcmp(name, "sbus") == 0) { 262141753Smarius *space = SBUS_BUS_SPACE; 263141753Smarius return (0); 264119697Smarcel } 265119697Smarcel return (ENXIO); 266119697Smarcel} 267