ofw_machdep.c revision 123866
186229Stmm/*- 286229Stmm * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. 386229Stmm * All rights reserved. 486229Stmm * 586229Stmm * Redistribution and use in source and binary forms, with or without 686229Stmm * modification, are permitted provided that the following conditions 786229Stmm * are met: 886229Stmm * 1. Redistributions of source code must retain the above copyright 986229Stmm * notice, this list of conditions and the following disclaimer. 1086229Stmm * 2. Redistributions in binary form must reproduce the above copyright 1186229Stmm * notice, this list of conditions and the following disclaimer in the 1286229Stmm * documentation and/or other materials provided with the distribution. 1386229Stmm * 1486229Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1586229Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1686229Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1786229Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 1886229Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 1986229Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2086229Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2186229Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2286229Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 2386229Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2486229Stmm * 2586229Stmm * $FreeBSD: head/sys/sparc64/sparc64/ofw_machdep.c 123866 2003-12-26 14:30:19Z obrien $ 2686229Stmm */ 2786229Stmm 2886229Stmm/* 2986229Stmm * Some OpenFirmware helper functions that are likely machine dependent. 3086229Stmm */ 3186229Stmm 3286229Stmm#include <sys/param.h> 3386229Stmm#include <sys/systm.h> 3486229Stmm 3588370Stmm#include <net/ethernet.h> 3688370Stmm 37119338Simp#include <dev/ofw/openfirm.h> 3886229Stmm 39119697Smarcel#include <machine/bus.h> 4086229Stmm#include <machine/idprom.h> 4186229Stmm#include <machine/ofw_machdep.h> 42119697Smarcel#include <machine/ofw_upa.h> 43119697Smarcel#include <machine/resource.h> 4486229Stmm 45119697Smarcel#include <sparc64/pci/ofw_pci.h> 46119697Smarcel#include <sparc64/isa/ofw_isa.h> 47119697Smarcel#include <sparc64/sbus/ofw_sbus.h> 48119697Smarcel 4986229Stmmvoid 5086229StmmOF_getetheraddr(device_t dev, u_char *addr) 5186229Stmm{ 5286229Stmm phandle_t node; 5386229Stmm struct idprom idp; 5486229Stmm 5586229Stmm node = OF_peer(0); 5686229Stmm if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1) 5786229Stmm panic("Could not determine the machine ethernet address"); 5888370Stmm bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN); 5986229Stmm} 60119697Smarcel 61119697Smarcelint 62119697SmarcelOF_decode_addr(phandle_t node, int *space, bus_addr_t *addr) 63119697Smarcel{ 64119697Smarcel char name[32]; 65119697Smarcel union { 66119697Smarcel struct isa_ranges isa[4]; 67119697Smarcel struct sbus_ranges sbus[8]; 68119697Smarcel struct upa_ranges upa[4]; 69119697Smarcel } range; 70119697Smarcel union { 71119697Smarcel struct isa_regs isa; 72119697Smarcel struct sbus_regs sbus; 73119697Smarcel } reg; 74119697Smarcel phandle_t bus, pbus; 75119697Smarcel u_long child, dummy, phys; 76119697Smarcel int cs, i, rsz, type; 77119697Smarcel 78119697Smarcel bus = OF_parent(node); 79123866Sobrien if (bus == 0) 80119697Smarcel return (ENXIO); 81119697Smarcel if (OF_getprop(bus, "name", name, sizeof(name)) == -1) 82119697Smarcel return (ENXIO); 83119697Smarcel name[sizeof(name) - 1] = '\0'; 84120008Stmm if (strcmp(name, "ebus") == 0 || strcmp(name, "isa") == 0) { 85119697Smarcel if (OF_getprop(node, "reg", ®.isa, sizeof(reg.isa)) == -1) 86119697Smarcel return (ENXIO); 87119697Smarcel rsz = OF_getprop(bus, "ranges", range.isa, sizeof(range.isa)); 88119697Smarcel if (rsz == -1) 89119697Smarcel return (ENXIO); 90119697Smarcel phys = ISA_REG_PHYS(®.isa); 91119697Smarcel dummy = phys + 1; 92119697Smarcel type = ofw_isa_map_iorange(range.isa, rsz / sizeof(*range.isa), 93119697Smarcel &phys, &dummy); 94119697Smarcel if (type == SYS_RES_MEMORY) { 95119697Smarcel cs = PCI_CS_MEM32; 96119697Smarcel *space = PCI_MEMORY_BUS_SPACE; 97119697Smarcel } else { 98119697Smarcel cs = PCI_CS_IO; 99119697Smarcel *space = PCI_IO_BUS_SPACE; 100119697Smarcel } 101119697Smarcel 102119697Smarcel /* Find the topmost PCI node (the host bridge) */ 103119697Smarcel while (1) { 104119697Smarcel pbus = OF_parent(bus); 105123866Sobrien if (pbus == 0) 106119697Smarcel return (ENXIO); 107119697Smarcel if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 108119697Smarcel return (ENXIO); 109119697Smarcel name[sizeof(name) - 1] = '\0'; 110119697Smarcel if (strcmp(name, "pci") != 0) 111119697Smarcel break; 112119697Smarcel bus = pbus; 113119697Smarcel } 114119697Smarcel 115119697Smarcel /* There wasn't a PCI bridge. */ 116119697Smarcel if (bus == OF_parent(node)) 117119697Smarcel return (ENXIO); 118119697Smarcel 119119697Smarcel /* Make sure we reached the UPA/PCI node. */ 120119697Smarcel if (OF_getprop(pbus, "device_type", name, sizeof(name)) == -1) 121119697Smarcel return (ENXIO); 122119697Smarcel name[sizeof(name) - 1] = '\0'; 123119697Smarcel if (strcmp(name, "upa") != 0) 124119697Smarcel return (ENXIO); 125119697Smarcel 126119697Smarcel rsz = OF_getprop(bus, "ranges", range.upa, sizeof(range.upa)); 127119697Smarcel if (rsz == -1) 128119697Smarcel return (ENXIO); 129119697Smarcel for (i = 0; i < (rsz / sizeof(range.upa[0])); i++) { 130119697Smarcel child = UPA_RANGE_CHILD(&range.upa[i]); 131119697Smarcel if (UPA_RANGE_CS(&range.upa[i]) == cs && 132119697Smarcel phys >= child && 133119697Smarcel phys - child < UPA_RANGE_SIZE(&range.upa[i])) { 134119697Smarcel *addr = UPA_RANGE_PHYS(&range.upa[i]) + phys; 135119697Smarcel return (0); 136119697Smarcel } 137119697Smarcel } 138119697Smarcel } else if (strcmp(name, "sbus") == 0) { 139119697Smarcel if (OF_getprop(node, "reg", ®.sbus, sizeof(reg.sbus)) == -1) 140119697Smarcel return (ENXIO); 141119697Smarcel rsz = OF_getprop(bus, "ranges", range.sbus, 142119697Smarcel sizeof(range.sbus)); 143119697Smarcel if (rsz == -1) 144119697Smarcel return (ENXIO); 145119697Smarcel for (i = 0; i < (rsz / sizeof(range.sbus[0])); i++) { 146119697Smarcel if (reg.sbus.sbr_slot != range.sbus[i].cspace) 147119697Smarcel continue; 148119697Smarcel if (reg.sbus.sbr_offset < range.sbus[i].coffset || 149119697Smarcel reg.sbus.sbr_offset >= range.sbus[i].coffset + 150119697Smarcel range.sbus[i].size) 151119697Smarcel continue; 152119697Smarcel /* Found it... */ 153119697Smarcel phys = range.sbus[i].poffset | 154119697Smarcel ((bus_addr_t)range.sbus[i].pspace << 32); 155119697Smarcel phys += reg.sbus.sbr_offset - range.sbus[i].coffset; 156119697Smarcel *addr = phys; 157119697Smarcel *space = SBUS_BUS_SPACE; 158119697Smarcel return (0); 159119697Smarcel } 160119697Smarcel } 161119697Smarcel return (ENXIO); 162119697Smarcel} 163