File: [local] / sys / arch / sparc64 / dev / ebus_mainbus.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:08:32 2008 UTC (16 years, 4 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: ebus_mainbus.c,v 1.3 2007/04/07 20:15:54 kettenis Exp $ */
/*
* Copyright (c) 2007 Mark Kettenis
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef DEBUG
#define EDB_PROM 0x01
#define EDB_CHILD 0x02
#define EDB_INTRMAP 0x04
#define EDB_BUSMAP 0x08
#define EDB_BUSDMA 0x10
#define EDB_INTR 0x20
extern int ebus_debug;
#define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0)
#else
#define DPRINTF(l, s)
#endif
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/time.h>
#define _SPARC_BUS_DMA_PRIVATE
#include <machine/bus.h>
#include <machine/autoconf.h>
#include <machine/openfirm.h>
#include <dev/pci/pcivar.h>
#include <sparc64/dev/iommureg.h>
#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>
#include <sparc64/dev/pyrovar.h>
extern struct cfdriver pyro_cd;
int ebus_mainbus_match(struct device *, void *, void *);
void ebus_mainbus_attach(struct device *, struct device *, void *);
struct cfattach ebus_mainbus_ca = {
sizeof(struct ebus_softc), ebus_mainbus_match, ebus_mainbus_attach
};
int _ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
bus_addr_t, bus_size_t, int, bus_space_handle_t *);
void *_ebus_mainbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
int, int, int, int (*)(void *), void *, const char *);
bus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t);
int
ebus_mainbus_match(struct device *parent, void *match, void *aux)
{
struct mainbus_attach_args *ma = aux;
if (strcmp(ma->ma_name, "ebus") == 0)
return (1);
return (0);
}
void
ebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
{
struct ebus_softc *sc = (struct ebus_softc *)self;
struct mainbus_attach_args *ma = aux;
struct ebus_attach_args eba;
struct ebus_interrupt_map_mask *immp;
int node, nmapmask, error;
struct pyro_softc *psc;
int i;
sc->sc_node = node = ma->ma_node;
sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
printf(": ign %x", sc->sc_ign);
for (i = 0; i < pyro_cd.cd_ndevs; i++) {
psc = pyro_cd.cd_devs[i];
if (psc && psc->sc_ign == sc->sc_ign) {
sc->sc_bust = psc->sc_bust;
sc->sc_csr = psc->sc_csr;
sc->sc_csrh = psc->sc_csrh;
break;
}
}
if (sc->sc_csr == 0) {
printf(": can't find matching host bridge leaf\n");
return;
}
printf("\n");
sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
/*
* fill in our softc with information from the prom
*/
sc->sc_intmap = NULL;
sc->sc_range = NULL;
error = getprop(node, "interrupt-map",
sizeof(struct ebus_interrupt_map),
&sc->sc_nintmap, (void **)&sc->sc_intmap);
switch (error) {
case 0:
immp = &sc->sc_intmapmask;
error = getprop(node, "interrupt-map-mask",
sizeof(struct ebus_interrupt_map_mask), &nmapmask,
(void **)&immp);
if (error)
panic("could not get ebus interrupt-map-mask");
if (nmapmask != 1)
panic("ebus interrupt-map-mask is broken");
break;
case ENOENT:
break;
default:
panic("ebus interrupt-map: error %d", error);
break;
}
error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
&sc->sc_nrange, (void **)&sc->sc_range);
if (error)
panic("ebus ranges: error %d", error);
/*
* now attach all our children
*/
DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
for (node = firstchild(node); node; node = nextsibling(node)) {
if (ebus_setup_attach_args(sc, node, &eba) != 0) {
DPRINTF(EDB_CHILD,
("ebus_mainbus_attach: %s: incomplete\n",
getpropstring(node, "name")));
continue;
} else {
DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
eba.ea_name));
(void)config_found(self, &eba, ebus_print);
}
ebus_destroy_attach_args(&eba);
}
}
bus_space_tag_t
ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
{
struct sparc_bus_space_tag *bt;
bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
if (bt == NULL)
panic("could not allocate ebus bus tag");
bzero(bt, sizeof *bt);
snprintf(bt->name, sizeof(bt->name), "%s", sc->sc_dev.dv_xname);
bt->cookie = sc;
bt->parent = parent;
bt->asi = parent->asi;
bt->sasi = parent->sasi;
bt->sparc_bus_map = _ebus_mainbus_bus_map;
bt->sparc_intr_establish = _ebus_mainbus_intr_establish;
return (bt);
}
int
_ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
bus_size_t size, int flags, bus_space_handle_t *hp)
{
struct ebus_softc *sc = t->cookie;
struct ebus_mainbus_ranges *range;
bus_addr_t hi, lo;
int i;
DPRINTF(EDB_BUSMAP,
("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
(unsigned long long)offset, (int)size, (int)flags));
if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
printf("\n_ebus_mainbus_bus_map: invalid parent");
return (EINVAL);
}
t = t->parent;
if (flags & BUS_SPACE_MAP_PROMADDRESS) {
return ((*t->sparc_bus_map)
(t, t0, offset, size, flags, hp));
}
hi = offset >> 32UL;
lo = offset & 0xffffffff;
range = (struct ebus_mainbus_ranges *)sc->sc_range;
DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
for (i = 0; i < sc->sc_nrange; i++) {
bus_addr_t addr;
if (hi != range[i].child_hi)
continue;
if (lo < range[i].child_lo ||
(lo + size) > (range[i].child_lo + range[i].size))
continue;
addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
range[i].phys_lo;
addr += lo;
DPRINTF(EDB_BUSMAP,
("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
(unsigned long long)offset, (unsigned long long)addr));
return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
}
DPRINTF(EDB_BUSMAP, (": FAILED\n"));
return (EINVAL);
}
void *
_ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
int level, int flags, int (*handler)(void *), void *arg, const char *what)
{
struct ebus_softc *sc = t->cookie;
struct intrhand *ih = NULL;
volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
int ino;
ihandle |= sc->sc_ign;
ino = INTINO(ihandle);
if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
u_int64_t *imap, *iclr;
/* XXX */
imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
intrmapptr = &imap[ino];
intrclrptr = &iclr[ino];
ino |= INTVEC(ihandle);
}
ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
intrclrptr, what);
if (ih == NULL)
return (NULL);
intr_establish(ih->ih_pil, ih);
if (intrmapptr != NULL) {
u_int64_t intrmap;
intrmap = *intrmapptr;
intrmap |= (1LL << 6);
intrmap |= INTMAP_V;
*intrmapptr = intrmap;
intrmap = *intrmapptr;
ih->ih_number |= intrmap & INTMAP_INR;
}
return (ih);
}