summaryrefslogtreecommitdiffstats
path: root/sys/sparc64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2003-09-02 20:32:12 +0000
committermarcel <marcel@FreeBSD.org>2003-09-02 20:32:12 +0000
commit2432ffe7fb7e8c66deef64402e25c458e2132707 (patch)
tree2e06204ca3d740714bdb022c5d067c677892e266 /sys/sparc64
parent3a5e34ed9ea402d643342c93f0c33d054db0ab56 (diff)
downloadFreeBSD-src-2432ffe7fb7e8c66deef64402e25c458e2132707.zip
FreeBSD-src-2432ffe7fb7e8c66deef64402e25c458e2132707.tar.gz
Add function OF_decode_addr(). This function obtains the physical
address of the device identified by its phandle_t by traversing OFW's device tree. The space and address returned by this function can subsequently be passed to sparc64_fake_bustag() to construct a valid tag and handle for use by the newbus I/O functions. Use of this function is expected to be limited to pre-newbus access to devices, such as consoles and keyboards. Partially obtained from: tmm Reviewed by: jake, jmg, tmm SBus testing made possible by: jake Tested with: LINT
Diffstat (limited to 'sys/sparc64')
-rw-r--r--sys/sparc64/include/ofw_machdep.h3
-rw-r--r--sys/sparc64/sparc64/ofw_machdep.c110
2 files changed, 112 insertions, 1 deletions
diff --git a/sys/sparc64/include/ofw_machdep.h b/sys/sparc64/include/ofw_machdep.h
index 64c7d56..f7062f7 100644
--- a/sys/sparc64/include/ofw_machdep.h
+++ b/sys/sparc64/include/ofw_machdep.h
@@ -30,7 +30,8 @@
#include <sys/bus.h>
-void OF_getetheraddr(device_t dev, u_char *addr);
+int OF_decode_addr(phandle_t, int *, bus_addr_t *);
+void OF_getetheraddr(device_t, u_char *);
void cpu_shutdown(void *);
void openfirmware_exit(void *);
diff --git a/sys/sparc64/sparc64/ofw_machdep.c b/sys/sparc64/sparc64/ofw_machdep.c
index 9cd4c02..404eeaf 100644
--- a/sys/sparc64/sparc64/ofw_machdep.c
+++ b/sys/sparc64/sparc64/ofw_machdep.c
@@ -36,8 +36,15 @@
#include <dev/ofw/openfirm.h>
+#include <machine/bus.h>
#include <machine/idprom.h>
#include <machine/ofw_machdep.h>
+#include <machine/ofw_upa.h>
+#include <machine/resource.h>
+
+#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/isa/ofw_isa.h>
+#include <sparc64/sbus/ofw_sbus.h>
void
OF_getetheraddr(device_t dev, u_char *addr)
@@ -50,3 +57,106 @@ OF_getetheraddr(device_t dev, u_char *addr)
panic("Could not determine the machine ethernet address");
bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN);
}
+
+int
+OF_decode_addr(phandle_t node, int *space, bus_addr_t *addr)
+{
+ char name[32];
+ union {
+ struct isa_ranges isa[4];
+ struct sbus_ranges sbus[8];
+ struct upa_ranges upa[4];
+ } range;
+ union {
+ struct isa_regs isa;
+ struct sbus_regs sbus;
+ } reg;
+ phandle_t bus, pbus;
+ u_long child, dummy, phys;
+ int cs, i, rsz, type;
+
+ bus = OF_parent(node);
+ if (bus == NULL)
+ return (ENXIO);
+ if (OF_getprop(bus, "name", name, sizeof(name)) == -1)
+ return (ENXIO);
+ name[sizeof(name) - 1] = '\0';
+ if (strcmp(name, "ebus") == 0) {
+ if (OF_getprop(node, "reg", &reg.isa, sizeof(reg.isa)) == -1)
+ return (ENXIO);
+ rsz = OF_getprop(bus, "ranges", range.isa, sizeof(range.isa));
+ if (rsz == -1)
+ return (ENXIO);
+ phys = ISA_REG_PHYS(&reg.isa);
+ dummy = phys + 1;
+ type = ofw_isa_map_iorange(range.isa, rsz / sizeof(*range.isa),
+ &phys, &dummy);
+ if (type == SYS_RES_MEMORY) {
+ cs = PCI_CS_MEM32;
+ *space = PCI_MEMORY_BUS_SPACE;
+ } else {
+ cs = PCI_CS_IO;
+ *space = PCI_IO_BUS_SPACE;
+ }
+
+ /* Find the topmost PCI node (the host bridge) */
+ while (1) {
+ pbus = OF_parent(bus);
+ if (pbus == NULL)
+ return (ENXIO);
+ if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
+ return (ENXIO);
+ name[sizeof(name) - 1] = '\0';
+ if (strcmp(name, "pci") != 0)
+ break;
+ bus = pbus;
+ }
+
+ /* There wasn't a PCI bridge. */
+ if (bus == OF_parent(node))
+ return (ENXIO);
+
+ /* Make sure we reached the UPA/PCI node. */
+ if (OF_getprop(pbus, "device_type", name, sizeof(name)) == -1)
+ return (ENXIO);
+ name[sizeof(name) - 1] = '\0';
+ if (strcmp(name, "upa") != 0)
+ return (ENXIO);
+
+ rsz = OF_getprop(bus, "ranges", range.upa, sizeof(range.upa));
+ if (rsz == -1)
+ return (ENXIO);
+ for (i = 0; i < (rsz / sizeof(range.upa[0])); i++) {
+ child = UPA_RANGE_CHILD(&range.upa[i]);
+ if (UPA_RANGE_CS(&range.upa[i]) == cs &&
+ phys >= child &&
+ phys - child < UPA_RANGE_SIZE(&range.upa[i])) {
+ *addr = UPA_RANGE_PHYS(&range.upa[i]) + phys;
+ return (0);
+ }
+ }
+ } else if (strcmp(name, "sbus") == 0) {
+ if (OF_getprop(node, "reg", &reg.sbus, sizeof(reg.sbus)) == -1)
+ return (ENXIO);
+ rsz = OF_getprop(bus, "ranges", range.sbus,
+ sizeof(range.sbus));
+ if (rsz == -1)
+ return (ENXIO);
+ for (i = 0; i < (rsz / sizeof(range.sbus[0])); i++) {
+ if (reg.sbus.sbr_slot != range.sbus[i].cspace)
+ continue;
+ if (reg.sbus.sbr_offset < range.sbus[i].coffset ||
+ reg.sbus.sbr_offset >= range.sbus[i].coffset +
+ range.sbus[i].size)
+ continue;
+ /* Found it... */
+ phys = range.sbus[i].poffset |
+ ((bus_addr_t)range.sbus[i].pspace << 32);
+ phys += reg.sbus.sbr_offset - range.sbus[i].coffset;
+ *addr = phys;
+ *space = SBUS_BUS_SPACE;
+ return (0);
+ }
+ }
+ return (ENXIO);
+}
OpenPOWER on IntegriCloud