ofw_machdep.c revision 133589
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 133589 2004-08-12 17:41:33Z marius $ 2686229Stmm */ 2786229Stmm 2886229Stmm/* 2986229Stmm * Some OpenFirmware helper functions that are likely machine dependent. 3086229Stmm */ 3186229Stmm 3286229Stmm#include <sys/param.h> 33133589Smarius#include <sys/bus.h> 3486229Stmm#include <sys/systm.h> 3586229Stmm 3688370Stmm#include <net/ethernet.h> 3788370Stmm 38133589Smarius#include <dev/ofw/ofw_bus.h> 39119338Simp#include <dev/ofw/openfirm.h> 4086229Stmm 41119697Smarcel#include <machine/bus.h> 4286229Stmm#include <machine/idprom.h> 4386229Stmm#include <machine/ofw_machdep.h> 44119697Smarcel#include <machine/ofw_upa.h> 45119697Smarcel#include <machine/resource.h> 4686229Stmm 47119697Smarcel#include <sparc64/pci/ofw_pci.h> 48119697Smarcel#include <sparc64/isa/ofw_isa.h> 49119697Smarcel#include <sparc64/sbus/ofw_sbus.h> 50119697Smarcel 5186229Stmmvoid 5286229StmmOF_getetheraddr(device_t dev, u_char *addr) 5386229Stmm{ 5486229Stmm phandle_t node; 5586229Stmm struct idprom idp; 5686229Stmm 5786229Stmm node = OF_peer(0); 5886229Stmm if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1) 5986229Stmm panic("Could not determine the machine ethernet address"); 6088370Stmm bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN); 6186229Stmm} 62119697Smarcel 63119697Smarcelint 64124259SmuxOF_getetheraddr2(device_t dev, u_char *addr) 65124259Smux{ 66124259Smux phandle_t node; 67124259Smux 68133589Smarius node = ofw_bus_get_node(dev); 69124259Smux if (node <= 0) 70124259Smux return (-1); 71124259Smux return (OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN)); 72124259Smux} 73124259Smux 74124259Smuxint 75119697SmarcelOF_decode_addr(phandle_t node, int *space, bus_addr_t *addr) 76119697Smarcel{ 77119697Smarcel char name[32]; 78119697Smarcel union { 79119697Smarcel struct isa_ranges isa[4]; 80119697Smarcel struct sbus_ranges sbus[8]; 81119697Smarcel struct upa_ranges upa[4]; 82119697Smarcel } range; 83119697Smarcel union { 84119697Smarcel struct isa_regs isa; 85119697Smarcel struct sbus_regs sbus; 86119697Smarcel } reg; 87119697Smarcel phandle_t bus, pbus; 88119697Smarcel u_long child, dummy, phys; 89119697Smarcel int cs, i, rsz, type; 90119697Smarcel 91119697Smarcel bus = OF_parent(node); 92123866Sobrien if (bus == 0) 93119697Smarcel return (ENXIO); 94119697Smarcel if (OF_getprop(bus, "name", name, sizeof(name)) == -1) 95119697Smarcel return (ENXIO); 96119697Smarcel name[sizeof(name) - 1] = '\0'; 97120008Stmm if (strcmp(name, "ebus") == 0 || strcmp(name, "isa") == 0) { 98119697Smarcel if (OF_getprop(node, "reg", ®.isa, sizeof(reg.isa)) == -1) 99119697Smarcel return (ENXIO); 100119697Smarcel rsz = OF_getprop(bus, "ranges", range.isa, sizeof(range.isa)); 101119697Smarcel if (rsz == -1) 102119697Smarcel return (ENXIO); 103119697Smarcel phys = ISA_REG_PHYS(®.isa); 104119697Smarcel dummy = phys + 1; 105128712Stmm type = ofw_isa_range_map(range.isa, rsz / sizeof(*range.isa), 106128712Stmm &phys, &dummy, NULL); 107119697Smarcel if (type == SYS_RES_MEMORY) { 108119697Smarcel cs = PCI_CS_MEM32; 109119697Smarcel *space = PCI_MEMORY_BUS_SPACE; 110119697Smarcel } else { 111119697Smarcel cs = PCI_CS_IO; 112119697Smarcel *space = PCI_IO_BUS_SPACE; 113119697Smarcel } 114119697Smarcel 115119697Smarcel /* Find the topmost PCI node (the host bridge) */ 116119697Smarcel while (1) { 117119697Smarcel pbus = OF_parent(bus); 118123866Sobrien if (pbus == 0) 119119697Smarcel return (ENXIO); 120119697Smarcel if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 121119697Smarcel return (ENXIO); 122119697Smarcel name[sizeof(name) - 1] = '\0'; 123119697Smarcel if (strcmp(name, "pci") != 0) 124119697Smarcel break; 125119697Smarcel bus = pbus; 126119697Smarcel } 127119697Smarcel 128119697Smarcel /* There wasn't a PCI bridge. */ 129119697Smarcel if (bus == OF_parent(node)) 130119697Smarcel return (ENXIO); 131119697Smarcel 132119697Smarcel /* Make sure we reached the UPA/PCI node. */ 133119697Smarcel if (OF_getprop(pbus, "device_type", name, sizeof(name)) == -1) 134119697Smarcel return (ENXIO); 135119697Smarcel name[sizeof(name) - 1] = '\0'; 136119697Smarcel if (strcmp(name, "upa") != 0) 137119697Smarcel return (ENXIO); 138119697Smarcel 139119697Smarcel rsz = OF_getprop(bus, "ranges", range.upa, sizeof(range.upa)); 140119697Smarcel if (rsz == -1) 141119697Smarcel return (ENXIO); 142119697Smarcel for (i = 0; i < (rsz / sizeof(range.upa[0])); i++) { 143119697Smarcel child = UPA_RANGE_CHILD(&range.upa[i]); 144119697Smarcel if (UPA_RANGE_CS(&range.upa[i]) == cs && 145119697Smarcel phys >= child && 146119697Smarcel phys - child < UPA_RANGE_SIZE(&range.upa[i])) { 147119697Smarcel *addr = UPA_RANGE_PHYS(&range.upa[i]) + phys; 148119697Smarcel return (0); 149119697Smarcel } 150119697Smarcel } 151119697Smarcel } else if (strcmp(name, "sbus") == 0) { 152119697Smarcel if (OF_getprop(node, "reg", ®.sbus, sizeof(reg.sbus)) == -1) 153119697Smarcel return (ENXIO); 154119697Smarcel rsz = OF_getprop(bus, "ranges", range.sbus, 155119697Smarcel sizeof(range.sbus)); 156119697Smarcel if (rsz == -1) 157119697Smarcel return (ENXIO); 158119697Smarcel for (i = 0; i < (rsz / sizeof(range.sbus[0])); i++) { 159119697Smarcel if (reg.sbus.sbr_slot != range.sbus[i].cspace) 160119697Smarcel continue; 161119697Smarcel if (reg.sbus.sbr_offset < range.sbus[i].coffset || 162119697Smarcel reg.sbus.sbr_offset >= range.sbus[i].coffset + 163119697Smarcel range.sbus[i].size) 164119697Smarcel continue; 165119697Smarcel /* Found it... */ 166119697Smarcel phys = range.sbus[i].poffset | 167119697Smarcel ((bus_addr_t)range.sbus[i].pspace << 32); 168119697Smarcel phys += reg.sbus.sbr_offset - range.sbus[i].coffset; 169119697Smarcel *addr = phys; 170119697Smarcel *space = SBUS_BUS_SPACE; 171119697Smarcel return (0); 172119697Smarcel } 173119697Smarcel } 174119697Smarcel return (ENXIO); 175119697Smarcel} 176