summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorgene <gene@cvs.openbsd.org>1998-05-08 22:13:03 +0000
committergene <gene@cvs.openbsd.org>1998-05-08 22:13:03 +0000
commit5371b0dd050231a8b55459b4c87bd4693c1b1072 (patch)
tree0b60fae959035f03afb7c7d6d4fb99a7cc78f3ae /sys
parent56edc1944d991304daa71bf275fd0c3c700bafc6 (diff)
New and much smarter handling of the PSC chip.
Based on briggs' work with some by me.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/mac68k/include/psc.h21
-rw-r--r--sys/arch/mac68k/mac68k/psc.c335
2 files changed, 347 insertions, 9 deletions
diff --git a/sys/arch/mac68k/include/psc.h b/sys/arch/mac68k/include/psc.h
index 523b342ae71..f6793bc3d1b 100644
--- a/sys/arch/mac68k/include/psc.h
+++ b/sys/arch/mac68k/include/psc.h
@@ -1,4 +1,5 @@
-/* $NetBSD: psc.h,v 1.2 1997/11/07 13:31:21 briggs Exp $ */
+/* $OpenBSD: psc.h,v 1.2 1998/05/08 22:13:02 gene Exp $ */
+/* $NetBSD: psc.h,v 1.3 1998/04/24 05:27:24 scottr Exp $ */
/*-
* Copyright (c) 1997 David Huang <khym@bga.com>
@@ -36,15 +37,17 @@ extern volatile u_int8_t *PSCBase;
#define psc_reg2(r) (*((volatile u_int16_t *)(PSCBase+r)))
#define psc_reg4(r) (*((volatile u_int32_t *)(PSCBase+r)))
-int add_psc_lev3_intr __P((void (*)(void *), void *));
-int add_psc_lev4_intr __P((int, int (*)(void *), void *));
-int add_psc_lev5_intr __P((int, void (*)(void *), void *));
-int add_psc_lev6_intr __P((int, void (*)(void *), void *));
+void psc_init __P((void));
-int remove_psc_lev3_intr __P((void));
-int remove_psc_lev4_intr __P((int));
-int remove_psc_lev5_intr __P((int));
-int remove_psc_lev6_intr __P((int));
+int add_psc_lev3_intr __P((void (*)(void *), void *));
+int add_psc_lev4_intr __P((int, int (*)(void *), void *));
+int add_psc_lev5_intr __P((int, void (*)(void *), void *));
+int add_psc_lev6_intr __P((int, void (*)(void *), void *));
+
+int remove_psc_lev3_intr __P((void));
+int remove_psc_lev4_intr __P((int));
+int remove_psc_lev5_intr __P((int));
+int remove_psc_lev6_intr __P((int));
/*
* Reading an interrupt status register returns a mask of the
diff --git a/sys/arch/mac68k/mac68k/psc.c b/sys/arch/mac68k/mac68k/psc.c
new file mode 100644
index 00000000000..63912d49467
--- /dev/null
+++ b/sys/arch/mac68k/mac68k/psc.c
@@ -0,0 +1,335 @@
+/* $OpenBSD: psc.c,v 1.1 1998/05/08 22:13:02 gene Exp $ */
+/* $NetBSD: psc.c,v 1.4 1998/04/24 05:27:26 scottr Exp $ */
+
+/*-
+ * Copyright (c) 1997 David Huang <khym@bga.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This handles registration/unregistration of PSC (Peripheral
+ * Subsystem Controller) interrupts. The PSC is used only on the
+ * Centris/Quadra 660av and the Quadra 840av.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/psc.h>
+
+void psc_lev3_intr __P((struct frame *));
+static void psc_lev3_noint __P((void *));
+int psc_lev4_intr __P((struct frame *));
+static int psc_lev4_noint __P((void *));
+void psc_lev5_intr __P((struct frame *));
+static void psc_lev5_noint __P((void *));
+void psc_lev6_intr __P((struct frame *));
+static void psc_lev6_noint __P((void *));
+void psc_spurintr __P((struct frame *));
+
+void (*lev3_intrvec) __P((struct frame *));
+int (*lev4_intrvec) __P((struct frame *));
+void (*lev5_intrvec) __P((struct frame *));
+void (*lev6_intrvec) __P((struct frame *));
+
+extern int zshard __P((void *)); /* from zs.c */
+
+void (*psc3_ihandler) __P((void *)) = psc_lev3_noint;
+void *psc3_iarg;
+
+int (*psc4_itab[4]) __P((void *)) = {
+ psc_lev4_noint, /* 0 */
+ zshard, /* 1 */
+ zshard, /* 2 */
+ psc_lev4_noint /* 3 */
+};
+
+void *psc4_iarg[4] = {
+ (void *)0, (void *)1, (void *)2, (void *)3
+};
+
+void (*psc5_itab[2]) __P((void *)) = {
+ psc_lev5_noint, /* 0 */
+ psc_lev5_noint /* 1 */
+};
+
+void *psc5_iarg[2] = {
+ (void *)0, (void *)1
+};
+
+void (*psc6_itab[3]) __P((void *)) = {
+ psc_lev6_noint, /* 0 */
+ psc_lev6_noint, /* 1 */
+ psc_lev6_noint /* 2 */
+};
+
+void *psc6_iarg[3] = {
+ (void *)0, (void *)1, (void *)2
+};
+
+/*
+ * Setup the interrupt vectors and disable most of the PSC interrupts
+ */
+void
+psc_init()
+{
+ /*
+ * Only Quadra AVs have a PSC. On other machines, point the
+ * level 4 interrupt to zshard(), and levels 3, 5, and 6 to
+ * psc_spurintr().
+ */
+ if (current_mac_model->class == MACH_CLASSAV) {
+ lev3_intrvec = psc_lev3_intr;
+ lev4_intrvec = psc_lev4_intr;
+ lev5_intrvec = psc_lev5_intr;
+ lev6_intrvec = psc_lev6_intr;
+ psc_reg1(PSC_LEV3_IER) = 0x01; /* disable level 3 interrupts */
+ psc_reg1(PSC_LEV4_IER) = 0x09; /* disable level 4 interrupts */
+ psc_reg1(PSC_LEV4_IER) = 0x86; /* except for SCC */
+ psc_reg1(PSC_LEV5_IER) = 0x03; /* disable level 5 interrupts */
+ psc_reg1(PSC_LEV6_IER) = 0x07; /* disable level 6 interrupts */
+ } else {
+ lev3_intrvec = lev5_intrvec = lev6_intrvec = psc_spurintr;
+ lev4_intrvec = (int (*)(struct frame *))zshard;
+ }
+}
+
+void
+psc_spurintr(fp)
+ struct frame *fp;
+{
+}
+
+int
+add_psc_lev3_intr(handler, arg)
+ void (*handler)(void *);
+ void *arg;
+{
+ int s;
+
+ s = splhigh();
+
+ psc3_ihandler = handler;
+ psc3_iarg = arg;
+
+ splx(s);
+
+ return 1;
+}
+
+int
+remove_psc_lev3_intr()
+{
+ return add_psc_lev3_intr(psc_lev3_noint, (void *)0);
+}
+
+void
+psc_lev3_intr(fp)
+ struct frame *fp;
+{
+ u_int8_t intbits;
+
+ while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR))
+ ;
+ intbits &= 0x1 & psc_reg1(PSC_LEV3_IER);
+
+ if (intbits)
+ psc3_ihandler(psc3_iarg);
+}
+
+static void
+psc_lev3_noint(arg)
+ void *arg;
+{
+ printf("psc_lev3_noint\n");
+}
+
+int
+psc_lev4_intr(fp)
+ struct frame *fp;
+{
+ u_int8_t intbits, bitnum;
+ u_int mask;
+
+ while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR))
+ ;
+ intbits &= 0xf & psc_reg1(PSC_LEV4_IER);
+
+ mask = 1;
+ bitnum = 0;
+ do {
+ if (intbits & mask)
+ psc4_itab[bitnum](psc4_iarg[bitnum]);
+ mask <<= 1;
+ } while (intbits >= mask && ++bitnum);
+
+ return 0;
+}
+
+int
+add_psc_lev4_intr(dev, handler, arg)
+ int dev;
+ int (*handler)(void *);
+ void *arg;
+{
+ int s;
+
+ if ((dev < 0) || (dev > 3))
+ return 0;
+
+ s = splhigh();
+
+ psc4_itab[dev] = handler;
+ psc4_iarg[dev] = arg;
+
+ splx(s);
+
+ return 1;
+}
+
+int
+remove_psc_lev4_intr(dev)
+ int dev;
+{
+ return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev);
+}
+
+int
+psc_lev4_noint(arg)
+ void *arg;
+{
+ printf("psc_lev4_noint: device %d\n", (int)arg);
+ return 0;
+}
+
+void
+psc_lev5_intr(fp)
+ struct frame *fp;
+{
+ u_int8_t intbits, bitnum;
+ u_int mask;
+
+ while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR))
+ ;
+ intbits &= 0x3 & psc_reg1(PSC_LEV5_IER);
+
+ mask = 1;
+ bitnum = 0;
+ do {
+ if (intbits & mask)
+ psc5_itab[bitnum](psc5_iarg[bitnum]);
+ mask <<= 1;
+ } while (intbits >= mask && ++bitnum);
+}
+
+int
+add_psc_lev5_intr(dev, handler, arg)
+ int dev;
+ void (*handler)(void *);
+ void *arg;
+{
+ int s;
+
+ if ((dev < 0) || (dev > 1))
+ return 0;
+
+ s = splhigh();
+
+ psc5_itab[dev] = handler;
+ psc5_iarg[dev] = arg;
+
+ splx(s);
+
+ return 1;
+}
+
+int
+remove_psc_lev5_intr(dev)
+ int dev;
+{
+ return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev);
+}
+
+void
+psc_lev5_noint(arg)
+ void *arg;
+{
+ printf("psc_lev5_noint: device %d\n", (int)arg);
+}
+
+void
+psc_lev6_intr(fp)
+ struct frame *fp;
+{
+ u_int8_t intbits, bitnum;
+ u_int mask;
+
+ while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR))
+ ;
+ intbits &= 0x7 & psc_reg1(PSC_LEV6_IER);
+
+ mask = 1;
+ bitnum = 0;
+ do {
+ if (intbits & mask)
+ psc6_itab[bitnum](psc6_iarg[bitnum]);
+ mask <<= 1;
+ } while (intbits >= mask && ++bitnum);
+}
+
+int
+add_psc_lev6_intr(dev, handler, arg)
+ int dev;
+ void (*handler)(void *);
+ void *arg;
+{
+ int s;
+
+ if ((dev < 0) || (dev > 2))
+ return 0;
+
+ s = splhigh();
+
+ psc6_itab[dev] = handler;
+ psc6_iarg[dev] = arg;
+
+ splx(s);
+
+ return 1;
+}
+
+int
+remove_psc_lev6_intr(dev)
+ int dev;
+{
+ return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev);
+}
+
+void
+psc_lev6_noint(arg)
+ void *arg;
+{
+ printf("psc_lev6_noint: device %d\n", (int)arg);
+}