186229Stmm/*- 286229Stmm * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. 3207243Smarius * Copyright (c) 2005 - 2010 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 */ 26200924Smarius 27146473Smarius#include <sys/cdefs.h> 28146473Smarius__FBSDID("$FreeBSD$"); 2986229Stmm 3086229Stmm/* 31133862Smarius * Some Open Firmware helper functions that are likely machine dependent. 3286229Stmm */ 3386229Stmm 3486229Stmm#include <sys/param.h> 35133589Smarius#include <sys/bus.h> 3686229Stmm#include <sys/systm.h> 3786229Stmm 3888370Stmm#include <net/ethernet.h> 3988370Stmm 40133589Smarius#include <dev/ofw/ofw_bus.h> 41141753Smarius#include <dev/ofw/ofw_pci.h> 42119338Simp#include <dev/ofw/openfirm.h> 4386229Stmm 44119697Smarcel#include <machine/bus.h> 4586229Stmm#include <machine/idprom.h> 4686229Stmm#include <machine/ofw_machdep.h> 47230632Smarius#include <machine/stdarg.h> 4886229Stmm 4986229Stmmvoid 5086229StmmOF_getetheraddr(device_t dev, u_char *addr) 5186229Stmm{ 52133728Smarius char buf[sizeof("true")]; 5386229Stmm phandle_t node; 5486229Stmm struct idprom idp; 5586229Stmm 56228201Sjchandra if ((node = OF_finddevice("/options")) != -1 && 57133728Smarius OF_getprop(node, "local-mac-address?", buf, sizeof(buf)) > 0) { 58133728Smarius buf[sizeof(buf) - 1] = '\0'; 59133728Smarius if (strcmp(buf, "true") == 0 && 60133728Smarius (node = ofw_bus_get_node(dev)) > 0 && 61133728Smarius OF_getprop(node, "local-mac-address", addr, 62133728Smarius ETHER_ADDR_LEN) == ETHER_ADDR_LEN) 63133728Smarius return; 64133728Smarius } 65133728Smarius 6686229Stmm node = OF_peer(0); 6786229Stmm if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1) 68200924Smarius panic("Could not determine the machine Ethernet address"); 6988370Stmm bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN); 7086229Stmm} 71119697Smarcel 72207243Smariusu_int 73207243SmariusOF_getscsinitid(device_t dev) 74207243Smarius{ 75207243Smarius phandle_t node; 76207243Smarius uint32_t id; 77207243Smarius 78207243Smarius for (node = ofw_bus_get_node(dev); node != 0; node = OF_parent(node)) 79207243Smarius if (OF_getprop(node, "scsi-initiator-id", &id, 80207243Smarius sizeof(id)) > 0) 81207243Smarius return (id); 82207243Smarius return (7); 83207243Smarius} 84207243Smarius 85230632Smariusvoid 86230632SmariusOF_panic(const char *fmt, ...) 87230632Smarius{ 88230632Smarius char buf[256]; 89230632Smarius va_list ap; 90230632Smarius 91230632Smarius va_start(ap, fmt); 92230632Smarius (void)vsnprintf(buf, sizeof(buf), fmt, ap); 93230632Smarius OF_printf("OF_panic: %s\n", buf); 94230632Smarius va_end(ap); 95230632Smarius OF_exit(); 96230632Smarius} 97230632Smarius 98141753Smariusstatic __inline uint32_t 99141753Smariusphys_hi_mask_space(const char *bus, uint32_t phys_hi) 100141753Smarius{ 101141753Smarius 102141753Smarius if (strcmp(bus, "ebus") == 0 || strcmp(bus, "isa") == 0) 103200924Smarius phys_hi &= 0x1; 104141753Smarius else if (strcmp(bus, "pci") == 0) 105200924Smarius phys_hi &= OFW_PCI_PHYS_HI_SPACEMASK; 106141753Smarius /* The phys.hi cells of the other busses only contain space bits. */ 107200924Smarius return (phys_hi); 108141753Smarius} 109141753Smarius 110141753Smarius/* 111141753Smarius * Return the physical address and the bus space to use for a node 112141753Smarius * referenced by its package handle and the index of the register bank 113200924Smarius * to decode. Intended to be used to together with sparc64_fake_bustag() 114141753Smarius * by console drivers in early boot only. 115141753Smarius * Works by mapping the address of the node's bank given in the address 116141753Smarius * space of its parent upward in the device tree at each bridge along the 117141753Smarius * path. 118141753Smarius * Currently only really deals with max. 64-bit addresses, i.e. addresses 119200924Smarius * consisting of max. 2 phys cells (phys.hi and phys.lo). If we encounter 120141753Smarius * a 3 phys cells address (as with PCI addresses) we assume phys.hi can 121141753Smarius * be ignored except for the space bits (generally contained in phys.hi) 122141753Smarius * and treat phys.mid as phys.hi. 123141753Smarius */ 124119697Smarcelint 125141753SmariusOF_decode_addr(phandle_t node, int bank, int *space, bus_addr_t *addr) 126119697Smarcel{ 127119697Smarcel char name[32]; 128200925Smarius uint64_t cend, cstart, end, phys, pphys, sz, start; 129141753Smarius pcell_t addrc, szc, paddrc; 130141753Smarius phandle_t bus, lbus, pbus; 131141753Smarius uint32_t banks[10 * 5]; /* 10 PCI banks */ 132200925Smarius uint32_t cspc, pspc, spc; 133141753Smarius int i, j, nbank; 134119697Smarcel 135141753Smarius /* 136141753Smarius * In general the addresses are contained in the "reg" property 137200924Smarius * of a node. The first address in the "reg" property of a PCI 138141753Smarius * node however is the address of its configuration registers in 139200924Smarius * the configuration space of the host bridge. Additional entries 140200924Smarius * denote the memory and I/O addresses. For relocatable addresses 141141753Smarius * the "reg" property contains the BAR, for non-relocatable 142200924Smarius * addresses it contains the absolute PCI address. The PCI-only 143141753Smarius * "assigned-addresses" property however always contains the 144141753Smarius * absolute PCI addresses. 145141753Smarius * The "assigned-addresses" and "reg" properties are arrays of 146141753Smarius * address structures consisting of #address-cells 32-bit phys 147200924Smarius * cells and #size-cells 32-bit size cells. If a parent lacks 148141753Smarius * the "#address-cells" or "#size-cells" property the default 149141753Smarius * for #address-cells to use is 2 and for #size-cells 1. 150141753Smarius */ 151119697Smarcel bus = OF_parent(node); 152123866Sobrien if (bus == 0) 153119697Smarcel return (ENXIO); 154119697Smarcel if (OF_getprop(bus, "name", name, sizeof(name)) == -1) 155119697Smarcel return (ENXIO); 156119697Smarcel name[sizeof(name) - 1] = '\0'; 157141753Smarius if (OF_getprop(bus, "#address-cells", &addrc, sizeof(addrc)) == -1) 158141753Smarius addrc = 2; 159141753Smarius if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1) 160141753Smarius szc = 1; 161146473Smarius if (addrc < 2 || addrc > 3 || szc < 1 || szc > 2) 162141753Smarius return (ENXIO); 163141753Smarius if (strcmp(name, "pci") == 0) { 164141753Smarius if (addrc > 3) 165119697Smarcel return (ENXIO); 166141753Smarius nbank = OF_getprop(node, "assigned-addresses", &banks, 167141753Smarius sizeof(banks)); 168141753Smarius } else { 169141753Smarius if (addrc > 2) 170119697Smarcel return (ENXIO); 171141753Smarius nbank = OF_getprop(node, "reg", &banks, sizeof(banks)); 172141753Smarius } 173141753Smarius if (nbank == -1) 174141753Smarius return (ENXIO); 175141753Smarius nbank /= sizeof(banks[0]) * (addrc + szc); 176141753Smarius if (bank < 0 || bank > nbank - 1) 177141753Smarius return (ENXIO); 178200925Smarius bank *= addrc + szc; 179200925Smarius spc = phys_hi_mask_space(name, banks[bank]); 180200925Smarius /* Skip the high cell for 3-cell addresses. */ 181200925Smarius bank += addrc - 2; 182141753Smarius phys = 0; 183141753Smarius for (i = 0; i < MIN(2, addrc); i++) 184200925Smarius phys = ((uint64_t)phys << 32) | banks[bank++]; 185141753Smarius sz = 0; 186141753Smarius for (i = 0; i < szc; i++) 187200925Smarius sz = ((uint64_t)sz << 32) | banks[bank++]; 188141753Smarius start = phys; 189141753Smarius end = phys + sz - 1; 190119697Smarcel 191141753Smarius /* 192141753Smarius * Map upward in the device tree at every bridge we encounter 193141753Smarius * using their "ranges" properties. 194141753Smarius * The "ranges" property of a bridge is an array of a structure 195141753Smarius * consisting of that bridge's #address-cells 32-bit child-phys 196141753Smarius * cells, its parent bridge #address-cells 32-bit parent-phys 197141753Smarius * cells and that bridge's #size-cells 32-bit size cells. 198141753Smarius * If a bridge doesn't have a "ranges" property no mapping is 199141753Smarius * necessary at that bridge. 200141753Smarius */ 201200925Smarius cspc = 0; 202141753Smarius lbus = bus; 203141753Smarius while ((pbus = OF_parent(bus)) != 0) { 204141753Smarius if (OF_getprop(pbus, "#address-cells", &paddrc, 205141753Smarius sizeof(paddrc)) == -1) 206141753Smarius paddrc = 2; 207146473Smarius if (paddrc < 2 || paddrc > 3) 208141753Smarius return (ENXIO); 209141753Smarius nbank = OF_getprop(bus, "ranges", &banks, sizeof(banks)); 210141753Smarius if (nbank == -1) { 211141753Smarius if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 212119697Smarcel return (ENXIO); 213141753Smarius name[sizeof(name) - 1] = '\0'; 214141753Smarius goto skip; 215141753Smarius } 216206448Smarius if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1) 217206448Smarius szc = 1; 218206448Smarius if (szc < 1 || szc > 2) 219206448Smarius return (ENXIO); 220141753Smarius nbank /= sizeof(banks[0]) * (addrc + paddrc + szc); 221200925Smarius bank = 0; 222141753Smarius for (i = 0; i < nbank; i++) { 223200925Smarius cspc = phys_hi_mask_space(name, banks[bank]); 224200925Smarius if (cspc != spc) { 225200925Smarius bank += addrc + paddrc + szc; 226141753Smarius continue; 227200925Smarius } 228200925Smarius /* Skip the high cell for 3-cell addresses. */ 229200925Smarius bank += addrc - 2; 230141753Smarius phys = 0; 231141753Smarius for (j = 0; j < MIN(2, addrc); j++) 232200925Smarius phys = ((uint64_t)phys << 32) | banks[bank++]; 233200925Smarius pspc = banks[bank]; 234200925Smarius /* Skip the high cell for 3-cell addresses. */ 235200925Smarius bank += paddrc - 2; 236200925Smarius pphys = 0; 237200925Smarius for (j = 0; j < MIN(2, paddrc); j++) 238200925Smarius pphys = 239200925Smarius ((uint64_t)pphys << 32) | banks[bank++]; 240141753Smarius sz = 0; 241141753Smarius for (j = 0; j < szc; j++) 242200925Smarius sz = ((uint64_t)sz << 32) | banks[bank++]; 243141753Smarius cstart = phys; 244141753Smarius cend = phys + sz - 1; 245141753Smarius if (start < cstart || start > cend) 246141753Smarius continue; 247141753Smarius if (end < cstart || end > cend) 248141753Smarius return (ENXIO); 249119697Smarcel if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 250119697Smarcel return (ENXIO); 251119697Smarcel name[sizeof(name) - 1] = '\0'; 252200925Smarius spc = phys_hi_mask_space(name, pspc); 253200925Smarius start += pphys - cstart; 254200925Smarius end += pphys - cstart; 255141753Smarius break; 256119697Smarcel } 257141753Smarius if (i == nbank) 258119697Smarcel return (ENXIO); 259206448Smarius lbus = bus; 260141753Smarius skip: 261141753Smarius addrc = paddrc; 262141753Smarius bus = pbus; 263141753Smarius } 264119697Smarcel 265141753Smarius *addr = start; 266200925Smarius /* Determine the bus space based on the last bus we mapped. */ 267166058Smarius if (OF_parent(lbus) == 0) { 268166096Smarius *space = NEXUS_BUS_SPACE; 269166058Smarius return (0); 270166058Smarius } 271141753Smarius if (OF_getprop(lbus, "name", name, sizeof(name)) == -1) 272141753Smarius return (ENXIO); 273141753Smarius name[sizeof(name) - 1] = '\0'; 274200925Smarius if (strcmp(name, "central") == 0 || strcmp(name, "ebus") == 0 || 275200925Smarius strcmp(name, "upa") == 0) { 276166096Smarius *space = NEXUS_BUS_SPACE; 277141753Smarius return (0); 278141753Smarius } else if (strcmp(name, "pci") == 0) { 279200925Smarius switch (cspc) { 280141753Smarius case OFW_PCI_PHYS_HI_SPACE_IO: 281141753Smarius *space = PCI_IO_BUS_SPACE; 282141753Smarius return (0); 283141753Smarius case OFW_PCI_PHYS_HI_SPACE_MEM32: 284141753Smarius *space = PCI_MEMORY_BUS_SPACE; 285141753Smarius return (0); 286119697Smarcel } 287119697Smarcel } else if (strcmp(name, "sbus") == 0) { 288141753Smarius *space = SBUS_BUS_SPACE; 289141753Smarius return (0); 290119697Smarcel } 291119697Smarcel return (ENXIO); 292119697Smarcel} 293