summaryrefslogtreecommitdiff
path: root/sys/arch/amiga/isa/ggbus.c
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1996-04-27 18:39:08 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1996-04-27 18:39:08 +0000
commit61aa6f7b30e536382606a49e9a65374b125db338 (patch)
treebe587186b2f38f6fce1900c5bb71acadd3120a8f /sys/arch/amiga/isa/ggbus.c
parent8d6a67b28c750bb5eb69cca28d6e787b1f57336f (diff)
Bring forward the Amiga ISA support, and resolve a conflict with if_ed
Diffstat (limited to 'sys/arch/amiga/isa/ggbus.c')
-rw-r--r--sys/arch/amiga/isa/ggbus.c487
1 files changed, 352 insertions, 135 deletions
diff --git a/sys/arch/amiga/isa/ggbus.c b/sys/arch/amiga/isa/ggbus.c
index 7faeb895c85..03f546e88de 100644
--- a/sys/arch/amiga/isa/ggbus.c
+++ b/sys/arch/amiga/isa/ggbus.c
@@ -1,8 +1,7 @@
-/* $OpenBSD: ggbus.c,v 1.2 1996/02/27 15:40:56 niklas Exp $ */
-/* $NetBSD: ggbus.c,v 1.1 1994/07/08 23:32:17 niklas Exp $ */
+/* $OpenBSD: ggbus.c,v 1.3 1996/04/27 18:38:58 niklas Exp $ */
/*
- * Copyright (c) 1994, 1995 Niklas Hallqvist
+ * Copyright (c) 1994, 1995, 1996 Niklas Hallqvist
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,14 +29,16 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
+#include <machine/bus.h>
#include <machine/cpu.h>
-#include <machine/pio.h>
+#include <machine/intr.h>
#include <dev/isa/isavar.h>
@@ -46,36 +47,120 @@
#include <amiga/amiga/isr.h>
#include <amiga/dev/zbusvar.h>
#include <amiga/isa/isa_machdep.h>
-#include <amiga/isa/isa_intr.h>
#include <amiga/isa/ggbusvar.h>
#include <amiga/isa/ggbusreg.h>
+extern int cold;
+
int ggdebug = 0;
int ggstrayints = 0;
-/* This is OK because we only allow one ISA bus. */
-struct ggbus_device *ggbusp;
-
void ggbusattach __P((struct device *, struct device *, void *));
int ggbusmatch __P((struct device *, void *, void *));
-int ggbusprint __P((void *auxp, char *));
-void ggbusstb __P((struct device *, int, u_char));
-u_char ggbusldb __P((struct device *, int));
-void ggbusstw __P((struct device *, int, u_short));
-u_short ggbusldw __P((struct device *, int));
-void *ggbus_establish_intr __P((int intr, int type, int level,
- int (*ih_fun) (void *), void *ih_arg,
- char *ih_what));
-void ggbus_disestablish_intr __P((void *handler));
-
-struct isa_intr_fcns ggbus_intr_fcns = {
- 0 /* ggbus_intr_setup */, ggbus_establish_intr,
- ggbus_disestablish_intr, 0 /* ggbus_iointr */
+int ggbusprint __P((void *, char *));
+
+int ggbus_io_map(bus_chipset_tag_t, bus_io_addr_t, bus_io_size_t,
+ bus_io_handle_t *);
+int ggbus_mem_map(bus_chipset_tag_t, bus_mem_addr_t, bus_mem_size_t, int,
+ bus_mem_handle_t *);
+
+void ggbus_io_read_multi_1(bus_io_handle_t, bus_io_size_t, u_int8_t *,
+ bus_io_size_t);
+void ggbus_io_read_multi_2(bus_io_handle_t, bus_io_size_t, u_int16_t *,
+ bus_io_size_t);
+
+void ggbus_io_write_multi_1(bus_io_handle_t, bus_io_size_t,
+ const u_int8_t *, bus_io_size_t);
+void ggbus_io_write_multi_2(bus_io_handle_t, bus_io_size_t,
+ const u_int16_t *, bus_io_size_t);
+
+/*
+ * Note that the following unified access functions are prototyped for the
+ * I/O access case. We use casts to get type correctness.
+ */
+int ggbus_unmap(bus_io_handle_t, bus_io_size_t);
+
+__inline u_int8_t ggbus_read_1(bus_io_handle_t, bus_io_size_t);
+__inline u_int16_t ggbus_read_2(bus_io_handle_t, bus_io_size_t);
+
+__inline void ggbus_write_1(bus_io_handle_t, bus_io_size_t, u_int8_t);
+__inline void ggbus_write_2(bus_io_handle_t, bus_io_size_t, u_int16_t);
+
+/*
+ * In order to share the access function implementations for I/O and memory
+ * access we cast the functions for the memory access case. These typedefs
+ * make that casting look nicer.
+ */
+typedef int (*bus_mem_unmap_t)(bus_mem_handle_t, bus_mem_size_t);
+typedef u_int8_t (*bus_mem_read_1_t)(bus_mem_handle_t, bus_mem_size_t);
+typedef u_int16_t (*bus_mem_read_2_t)(bus_mem_handle_t, bus_mem_size_t);
+typedef void (*bus_mem_write_1_t)(bus_mem_handle_t, bus_mem_size_t, u_int8_t);
+typedef void (*bus_mem_write_2_t)(bus_mem_handle_t, bus_mem_size_t, u_int16_t);
+
+void ggbus_attach_hook(struct device *, struct device *,
+ struct isabus_attach_args *);
+void *ggbus_intr_establish __P((void *, int, int, int, int (*)(void *),
+ void *, char *));
+void ggbus_intr_disestablish __P((void *, void *));
+
+static u_int16_t swap __P((u_int16_t));
+
+/* Golden Gate I. */
+struct amiga_bus_chipset ggbus1_chipset = {
+ 0 /* bc_data */,
+
+ ggbus_io_map, ggbus_unmap,
+ ggbus_read_1, ggbus_read_2,
+ 0 /* bc_io_read_4 */, 0 /* bc_io_read_8 */,
+ ggbus_io_read_multi_1, ggbus_io_read_multi_2,
+ 0 /* bc_io_multi_4 */, 0 /* bc_io_multi_8 */,
+ ggbus_write_1, ggbus_write_2,
+ 0 /* bc_io_write_4 */, 0 /* bc_io_write_8 */,
+ ggbus_io_write_multi_1, ggbus_io_write_multi_2,
+ 0 /* bc_io_write_multi_4 */, 0 /* bc_io_write_multi_8 */,
+
+ 0 /* bc_mem_map */, 0 /* bc_mem_unmap */,
+ 0 /* bc_mem_read_1 */, 0 /* bc_mem_read_2 */,
+ 0 /* bc_mem_read_4 */, 0 /* bc_mem_read_8 */,
+ 0 /* bc_mem_write_1 */, 0 /* bc_mem_write_2 */,
+ 0 /* bc_mem_write_4 */, 0 /* bc_mem_write_8 */,
+
+ /* These are extensions to the general NetBSD bus interface. */
+ swap, 0 /* bc_to_host_4 */, 0 /* bc_to_host_8 */,
+ swap, 0 /* bc_from_host_4 */, 0 /* bc_from_host_8 */,
+};
+
+/* Golden Gate II. */
+struct amiga_bus_chipset ggbus2_chipset = {
+ 0 /* bc_data */,
+
+ ggbus_io_map, ggbus_unmap,
+ ggbus_read_1, ggbus_read_2,
+ 0 /* bc_io_read_4 */, 0 /* bc_io_read_8 */,
+ ggbus_io_read_multi_1, ggbus_io_read_multi_2,
+ 0 /* bc_io_multi_4 */, 0 /* bc_io_multi_8 */,
+ ggbus_write_1, ggbus_write_2,
+ 0 /* bc_io_write_4 */, 0 /* bc_io_write_8 */,
+ ggbus_io_write_multi_1, ggbus_io_write_multi_2,
+ 0 /* bc_io_write_multi_4 */, 0 /* bc_io_write_multi_8 */,
+
+ ggbus_mem_map, (bus_mem_unmap_t)ggbus_unmap,
+ (bus_mem_read_1_t)ggbus_read_1, (bus_mem_read_2_t)ggbus_read_2,
+ 0 /* bc_mem_read_4 */, 0 /* bc_mem_read_8 */,
+ (bus_mem_write_1_t)ggbus_write_1, (bus_mem_write_2_t)ggbus_write_2,
+ 0 /* bc_mem_write_4 */, 0 /* bc_mem_write_8 */,
+
+ /* These are extensions to the general NetBSD bus interface. */
+ swap, 0 /* bc_to_host_4 */, 0 /* bc_to_host_8 */,
+ swap, 0 /* bc_from_host_4 */, 0 /* bc_from_host_8 */,
+};
+
+struct cfattach ggbus_ca = {
+ sizeof(struct ggbus_softc), ggbusmatch, ggbusattach
};
-struct cfdriver ggbuscd = {
- NULL, "ggbus", ggbusmatch, ggbusattach,
- DV_DULL, sizeof(struct ggbus_device), 0
+struct cfdriver ggbus_cd = {
+ NULL, "ggbus", DV_DULL, 0
};
int
@@ -94,48 +179,39 @@ ggbusmatch(parent, match, aux)
}
void
-ggbusattach(pdp, dp, auxp)
- struct device *pdp, *dp;
- void *auxp;
+ggbusattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
{
- struct zbus_args *zap = auxp;
- struct ggbus_device *gdp = (struct ggbus_device *)dp;
-
- ggbusp = gdp;
- bcopy(zap, &gdp->gd_zargs, sizeof(struct zbus_args));
- gdp->gd_link.il_dev = dp;
- if (gdp->gd_zargs.serno >= 2)
- {
- gdp->gd_link.il_ldb = ggbusldb;
- gdp->gd_link.il_stb = ggbusstb;
- gdp->gd_link.il_ldw = ggbusldw;
- gdp->gd_link.il_stw = ggbusstw;
- }
- else
- {
- gdp->gd_link.il_ldb = 0;
- gdp->gd_link.il_stb = 0;
- gdp->gd_link.il_ldw = 0;
- gdp->gd_link.il_stw = 0;
- }
- gdp->gd_imask = 0;
-
- isa_intr_fcns = &ggbus_intr_fcns;
- isa_pio_fcns = &ggbus_pio_fcns;
-
- if (gdp->gd_zargs.serno >= 2)
- {
- /* XXX turn on wait states unconditionally for now. */
- GG2_ENABLE_WAIT(zap->va);
- GG2_ENABLE_INTS(zap->va);
- }
-
- printf(": pa 0x%08x va 0x%08x size 0x%x\n", zap->pa, zap->va, zap->size);
+ struct ggbus_softc *sc = (struct ggbus_softc *)self;
+ struct zbus_args *zap = aux;
+ struct isabus_attach_args iba;
+
+ bcopy(zap, &sc->sc_zargs, sizeof(struct zbus_args));
+ /* XXX Is serno reliable? */
+ bcopy(zap->serno < 2 ? &ggbus1_chipset : &ggbus2_chipset,
+ &sc->sc_bc, sizeof(struct amiga_bus_chipset));
+ sc->sc_bc.bc_data = sc;
+ sc->sc_status = GG2_STATUS_ADDR(sc->sc_zargs.va);
+
+ if (sc->sc_zargs.serno >= 2) {
+ /* XXX turn on wait states unconditionally for now. */
+ GG2_ENABLE_WAIT(zap->va);
+ GG2_ENABLE_INTS(zap->va);
+ }
- /*
- * attempt to configure the board.
- */
- config_found(dp, &gdp->gd_link, ggbusprint);
+ printf(": pa 0x%08x va 0x%08x size 0x%x\n", zap->pa, zap->va,
+ zap->size);
+
+ sc->sc_ic.ic_data = sc;
+ sc->sc_ic.ic_attach_hook = ggbus_attach_hook;
+ sc->sc_ic.ic_intr_establish = ggbus_intr_establish;
+ sc->sc_ic.ic_intr_disestablish = ggbus_intr_disestablish;
+
+ iba.iba_busname = "isa";
+ iba.iba_bc = &sc->sc_bc;
+ iba.iba_ic = &sc->sc_ic;
+ config_found(self, &iba, ggbusprint);
}
int
@@ -148,59 +224,130 @@ ggbusprint(auxp, pnp)
return(UNCONF);
}
+int
+ggbus_io_map(bct, addr, sz, handle)
+ bus_chipset_tag_t bct;
+ bus_io_addr_t addr;
+ bus_io_size_t sz;
+ bus_io_handle_t *handle;
+{
+ *handle = (bus_io_handle_t)
+ ((struct ggbus_softc *)bct->bc_data)->sc_zargs.va + 2 * addr;
+#if 0
+ printf("io_map %x %d -> %x\n", addr, sz, *handle);
+#endif
+ return 0;
+}
-void
-ggbusstb(dev, ia, b)
- struct device *dev;
- int ia;
- u_char b;
+int
+ggbus_mem_map(bct, addr, sz, cacheable, handle)
+ bus_chipset_tag_t bct;
+ bus_mem_addr_t addr;
+ bus_mem_size_t sz;
+ int cacheable;
+ bus_mem_handle_t *handle;
{
- struct ggbus_device *gd = (struct ggbus_device *)dev;
+ *handle = (bus_mem_handle_t)
+ ((struct ggbus_softc *)bct->bc_data)->sc_zargs.va + 2 * addr +
+ GG2_MEMORY_OFFSET;
+#if 0
+ printf("mem_map %x %d -> %x\n", addr, sz, *handle);
+#endif
+ return 0;
+}
- *(volatile u_char *)(gd->gd_zargs.va + GG2_MEMORY_OFFSET + 2 * ia + 1) = b;
+int
+ggbus_unmap(handle, sz)
+ bus_io_handle_t handle;
+ bus_io_size_t sz;
+{
+ return 0;
}
-u_char
-ggbusldb(dev, ia)
- struct device *dev;
- int ia;
+__inline u_int8_t
+ggbus_read_1(handle, addr)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
{
- struct ggbus_device *gd = (struct ggbus_device *)dev;
- u_char retval =
- *(volatile u_char *)(gd->gd_zargs.va + GG2_MEMORY_OFFSET + 2 * ia + 1);
+ u_int8_t val = *(volatile u_int8_t *)(handle + 2 * addr + 1);
-#ifdef DEBUG
- if (ggdebug)
- printf("ldb 0x%x => 0x%x\n", ia, retval);
+#if 0
+ printf("read_1 @%x handle %x -> %d\n", addr, handle, val);
#endif
- return retval;
+ return val;
}
-void
-ggbusstw(dev, ia, w)
- struct device *dev;
- int ia;
- u_short w;
+__inline u_int16_t
+ggbus_read_2(handle, addr)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
{
- struct ggbus_device *gd = (struct ggbus_device *)dev;
+ return swap(*(volatile u_int16_t *)(handle + 2 * addr));
+}
- *(volatile u_short *)(gd->gd_zargs.va + GG2_MEMORY_OFFSET + 2 * ia) = swap(w);
+void
+ggbus_io_read_multi_1(handle, addr, buf, cnt)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ u_int8_t *buf;
+ bus_io_size_t cnt;
+{
+ while (cnt--)
+ *buf++ = ggbus_read_1(handle, addr);
}
-u_short
-ggbusldw(dev, ia)
- struct device *dev;
- int ia;
+void
+ggbus_io_read_multi_2(handle, addr, buf, cnt)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ u_int16_t *buf;
+ bus_io_size_t cnt;
{
- struct ggbus_device *gd = (struct ggbus_device *)dev;
- u_short retval =
- swap(*(volatile u_short *)(gd->gd_zargs.va + GG2_MEMORY_OFFSET + 2 * ia));
+ while (cnt--)
+ *buf++ = ggbus_read_2(handle, addr);
+}
-#ifdef DEBUG
- if (ggdebug)
- printf("ldw 0x%x => 0x%x\n", ia, retval);
+__inline void
+ggbus_write_1(handle, addr, val)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ u_int8_t val;
+{
+#if 0
+ printf("write_1 @%x handle %x: %d\n", addr, handle, val);
#endif
- return retval;
+ *(volatile u_int8_t *)(handle + 2 * addr + 1) = val;
+}
+
+__inline void
+ggbus_write_2(handle, addr, val)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ u_int16_t val;
+{
+ *(volatile u_int16_t *)(handle + 2 * addr) = swap(val);
+}
+
+void
+ggbus_io_write_multi_1(handle, addr, buf, cnt)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ const u_int8_t *buf;
+ bus_io_size_t cnt;
+{
+ while (cnt--)
+ ggbus_write_1(handle, addr, *buf++);
+}
+
+void
+ggbus_io_write_multi_2(handle, addr, buf, cnt)
+ bus_io_handle_t handle;
+ bus_io_size_t addr;
+ const u_int16_t *buf;
+ bus_io_size_t cnt;
+{
+ while (cnt--)
+ ggbus_write_2(handle, addr, *buf++);
}
static ggbus_int_map[] = {
@@ -208,56 +355,126 @@ static ggbus_int_map[] = {
GG2_IRQ9, GG2_IRQ10, GG2_IRQ11, GG2_IRQ12, 0, GG2_IRQ14, GG2_IRQ15
};
-struct ggintr_desc {
- struct isr gid_isr;
- int gid_mask;
- int (*gid_fun)(void *);
- void *gid_arg;
-};
+int
+ggbusintr(v)
+ void *v;
+{
+ struct intrhand *ih = (struct intrhand *)v;
+ int handled;
-static struct ggintr_desc *ggid[16]; /* XXX */
+ if (!(*ih->ih_status & ih->ih_mask))
+ return 0;
+ for (handled = 0; ih; ih = ih->ih_next)
+ if ((*ih->ih_fun)(ih->ih_arg))
+ handled = 1;
+ return handled;
+}
-int
-ggbusintr(gid)
- struct ggintr_desc *gid;
+void
+ggbus_attach_hook(parent, self, iba)
+ struct device *parent, *self;
+ struct isabus_attach_args *iba;
{
- return (GG2_GET_STATUS (ggbusp->gd_zargs.va) & gid->gid_mask) ?
- (*gid->gid_fun)(gid->gid_arg) : 0;
}
void *
-ggbus_establish_intr(intr, type, level, ih_fun, ih_arg, ih_what)
- int intr;
+ggbus_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what)
+ void *ic;
+ int irq;
int type;
int level;
int (*ih_fun)(void *);
void *ih_arg;
char *ih_what;
{
- if (ggid[intr]) {
- log(LOG_WARNING, "ISA interrupt %d already handled\n", intr);
- return 0;
- }
- MALLOC(ggid[intr], struct ggintr_desc *, sizeof(struct ggintr_desc),
- M_DEVBUF, M_WAITOK);
- ggid[intr]->gid_isr.isr_intr = ggbusintr;
- ggid[intr]->gid_isr.isr_arg = ggid[intr];
- ggid[intr]->gid_isr.isr_ipl = 6;
- ggid[intr]->gid_isr.isr_mapped_ipl = level;
- ggid[intr]->gid_mask = 1 << ggbus_int_map[intr + 1];
- ggid[intr]->gid_fun = ih_fun;
- ggid[intr]->gid_arg = ih_arg;
- add_isr(&ggid[intr]->gid_isr);
- return &ggid[intr];
+ struct intrhand **p, *c, *ih;
+ struct ggbus_softc *sc = (struct ggbus_softc *)ic;
+
+ /* no point in sleeping unless someone can free memory. */
+ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+ if (ih == NULL)
+ panic("ggbus_intr_establish: can't malloc handler info");
+
+ if (irq > ICU_LEN || type == IST_NONE)
+ panic("ggbus_intr_establish: bogus irq or type");
+
+ switch (sc->sc_intrsharetype[irq]) {
+ case IST_EDGE:
+ case IST_LEVEL:
+ if (type == sc->sc_intrsharetype[irq])
+ break;
+ case IST_PULSE:
+ if (type != IST_NONE)
+ panic("ggbus_intr_establish: can't share %s with %s",
+ isa_intr_typename(sc->sc_intrsharetype[irq]),
+ isa_intr_typename(type));
+ break;
+ }
+
+ /*
+ * Figure out where to put the handler.
+ * This is O(N^2), but we want to preserve the order, and N is
+ * generally small.
+ */
+ for (p = &sc->sc_ih[irq]; (c = *p) != NULL; p = &c->ih_next)
+ ;
+
+ /*
+ * Poke the real handler in now.
+ */
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_count = 0;
+ ih->ih_next = NULL;
+ ih->ih_irq = irq;
+ ih->ih_what = ih_what;
+ ih->ih_mask = 1 << ggbus_int_map[irq + 1];
+ ih->ih_status = sc->sc_status;
+ ih->ih_isr.isr_intr = ggbusintr;
+ ih->ih_isr.isr_arg = ih;
+ ih->ih_isr.isr_ipl = 6;
+ ih->ih_isr.isr_mapped_ipl = level;
+ *p = ih;
+
+ add_isr(&ih->ih_isr);
+ return ih;
}
void
-ggbus_disestablish_intr(handler)
- void *handler;
+ggbus_intr_disestablish(ic, arg)
+ void *ic;
+ void *arg;
{
- struct ggintr_desc **gid = handler;
+ struct intrhand *ih = arg;
+ struct ggbus_softc *sc = (struct ggbus_softc *)ic;
+ int irq = ih->ih_irq;
+ struct intrhand **p, *q;
- remove_isr(&(*gid)->gid_isr);
- FREE(*gid, M_DEVBUF);
- *gid = 0;
+ if (irq > ICU_LEN)
+ panic("ggbus_intr_establish: bogus irq");
+
+ remove_isr(&ih->ih_isr);
+
+ /*
+ * Remove the handler from the chain.
+ * This is O(n^2), too.
+ */
+ for (p = &sc->sc_ih[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
+ ;
+ if (q)
+ *p = q->ih_next;
+ else
+ panic("ggbus_intr_disestablish: handler not registered");
+ free(ih, M_DEVBUF);
+
+ if (sc->sc_intrsharetype[irq] == NULL)
+ sc->sc_intrsharetype[irq] = IST_NONE;
+}
+
+/* Swap bytes in a short word. */
+static u_int16_t
+swap(u_int16_t x)
+{
+ __asm("rolw #8,%0" : "=r" (x) : "0" (x));
+ return x;
}