Home | History | Annotate | Line # | Download | only in alchemy
au_icu.c revision 1.19
      1  1.19  gdamore /*	$NetBSD: au_icu.c,v 1.19 2006/03/25 07:23:05 gdamore Exp $	*/
      2  1.13  gdamore 
      3  1.13  gdamore /*-
      4  1.13  gdamore  * Copyright (c) 2006 Itronix Inc.
      5  1.13  gdamore  * All rights reserved.
      6  1.13  gdamore  *
      7  1.13  gdamore  * Written by Garrett D'Amore for Itronix Inc.
      8  1.13  gdamore  *
      9  1.13  gdamore  * Redistribution and use in source and binary forms, with or without
     10  1.13  gdamore  * modification, are permitted provided that the following conditions
     11  1.13  gdamore  * are met:
     12  1.13  gdamore  * 1. Redistributions of source code must retain the above copyright
     13  1.13  gdamore  *    notice, this list of conditions and the following disclaimer.
     14  1.13  gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.13  gdamore  *    notice, this list of conditions and the following disclaimer in the
     16  1.13  gdamore  *    documentation and/or other materials provided with the distribution.
     17  1.13  gdamore  * 3. The name of Itronix Inc. may not be used to endorse
     18  1.13  gdamore  *    or promote products derived from this software without specific
     19  1.13  gdamore  *    prior written permission.
     20  1.13  gdamore  *
     21  1.13  gdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     22  1.13  gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  1.13  gdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  1.13  gdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     25  1.13  gdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     26  1.13  gdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     27  1.13  gdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     28  1.13  gdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
     29  1.13  gdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  1.13  gdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  1.13  gdamore  * POSSIBILITY OF SUCH DAMAGE.
     32  1.13  gdamore  */
     33   1.1   simonb 
     34   1.1   simonb /*-
     35   1.1   simonb  * Copyright (c) 2001 The NetBSD Foundation, Inc.
     36   1.1   simonb  * All rights reserved.
     37   1.1   simonb  *
     38   1.1   simonb  * This code is derived from software contributed to The NetBSD Foundation
     39   1.1   simonb  * by Jason R. Thorpe.
     40   1.1   simonb  *
     41   1.1   simonb  * Redistribution and use in source and binary forms, with or without
     42   1.1   simonb  * modification, are permitted provided that the following conditions
     43   1.1   simonb  * are met:
     44   1.1   simonb  * 1. Redistributions of source code must retain the above copyright
     45   1.1   simonb  *    notice, this list of conditions and the following disclaimer.
     46   1.1   simonb  * 2. Redistributions in binary form must reproduce the above copyright
     47   1.1   simonb  *    notice, this list of conditions and the following disclaimer in the
     48   1.1   simonb  *    documentation and/or other materials provided with the distribution.
     49   1.1   simonb  * 3. All advertising materials mentioning features or use of this software
     50   1.1   simonb  *    must display the following acknowledgement:
     51   1.1   simonb  *	This product includes software developed by the NetBSD
     52   1.1   simonb  *	Foundation, Inc. and its contributors.
     53   1.1   simonb  * 4. Neither the name of The NetBSD Foundation nor the names of its
     54   1.1   simonb  *    contributors may be used to endorse or promote products derived
     55   1.1   simonb  *    from this software without specific prior written permission.
     56   1.1   simonb  *
     57   1.1   simonb  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     58   1.1   simonb  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     59   1.1   simonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     60   1.1   simonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     61   1.1   simonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     62   1.1   simonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     63   1.1   simonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     64   1.1   simonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     65   1.1   simonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     66   1.1   simonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     67   1.1   simonb  * POSSIBILITY OF SUCH DAMAGE.
     68   1.1   simonb  */
     69   1.1   simonb 
     70   1.1   simonb /*
     71   1.1   simonb  * Interrupt support for the Alchemy Semiconductor Au1x00 CPUs.
     72   1.1   simonb  *
     73   1.1   simonb  * The Alchemy Semiconductor Au1x00's interrupts are wired to two internal
     74   1.1   simonb  * interrupt controllers.
     75   1.1   simonb  */
     76   1.7    lukem 
     77   1.7    lukem #include <sys/cdefs.h>
     78  1.19  gdamore __KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.19 2006/03/25 07:23:05 gdamore Exp $");
     79   1.1   simonb 
     80   1.1   simonb #include "opt_ddb.h"
     81   1.1   simonb 
     82   1.1   simonb #include <sys/param.h>
     83   1.1   simonb #include <sys/queue.h>
     84   1.1   simonb #include <sys/malloc.h>
     85   1.1   simonb #include <sys/systm.h>
     86   1.1   simonb #include <sys/device.h>
     87   1.1   simonb #include <sys/kernel.h>
     88   1.1   simonb 
     89   1.1   simonb #include <machine/bus.h>
     90   1.1   simonb #include <machine/intr.h>
     91   1.1   simonb 
     92   1.1   simonb #include <mips/locore.h>
     93   1.1   simonb #include <mips/alchemy/include/aureg.h>
     94   1.1   simonb #include <mips/alchemy/include/auvar.h>
     95   1.1   simonb 
     96  1.14  gdamore #define	REGVAL(x)	*((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
     97   1.1   simonb 
     98   1.1   simonb /*
     99   1.1   simonb  * This is a mask of bits to clear in the SR when we go to a
    100   1.1   simonb  * given hardware interrupt priority level.
    101   1.1   simonb  */
    102   1.1   simonb 
    103  1.14  gdamore const uint32_t ipl_sr_bits[_IPL_N] = {
    104   1.1   simonb 	0,					/*  0: IPL_NONE */
    105   1.1   simonb 
    106   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/*  1: IPL_SOFT */
    107   1.1   simonb 
    108   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/*  2: IPL_SOFTCLOCK */
    109   1.1   simonb 
    110   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/*  3: IPL_SOFTNET */
    111   1.1   simonb 
    112   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/*  4: IPL_SOFTSERIAL */
    113   1.1   simonb 
    114   1.1   simonb 	MIPS_SOFT_INT_MASK_0|
    115   1.1   simonb 		MIPS_SOFT_INT_MASK_1|
    116   1.1   simonb 		MIPS_INT_MASK_0,		/*  5: IPL_BIO */
    117   1.1   simonb 
    118   1.1   simonb 	MIPS_SOFT_INT_MASK_0|
    119   1.1   simonb 		MIPS_SOFT_INT_MASK_1|
    120   1.1   simonb 		MIPS_INT_MASK_0,		/*  6: IPL_NET */
    121   1.1   simonb 
    122   1.1   simonb 	MIPS_SOFT_INT_MASK_0|
    123   1.1   simonb 		MIPS_SOFT_INT_MASK_1|
    124   1.2   simonb 		MIPS_INT_MASK_0,		/*  7: IPL_{SERIAL,TTY} */
    125   1.1   simonb 
    126   1.1   simonb 	MIPS_SOFT_INT_MASK_0|
    127   1.1   simonb 		MIPS_SOFT_INT_MASK_1|
    128   1.1   simonb 		MIPS_INT_MASK_0|
    129   1.1   simonb 		MIPS_INT_MASK_1|
    130   1.1   simonb 		MIPS_INT_MASK_2|
    131   1.1   simonb 		MIPS_INT_MASK_3|
    132   1.1   simonb 		MIPS_INT_MASK_4|
    133   1.2   simonb 		MIPS_INT_MASK_5,		/*  8: IPL_{CLOCK,HIGH} */
    134   1.1   simonb };
    135   1.1   simonb 
    136   1.1   simonb /*
    137   1.1   simonb  * This is a mask of bits to clear in the SR when we go to a
    138   1.1   simonb  * given software interrupt priority level.
    139   1.1   simonb  * Hardware ipls are port/board specific.
    140   1.1   simonb  */
    141  1.14  gdamore const uint32_t mips_ipl_si_to_sr[_IPL_NSOFT] = {
    142   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
    143   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
    144   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTNET */
    145   1.1   simonb 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTSERIAL */
    146   1.1   simonb };
    147   1.1   simonb 
    148   1.1   simonb #define	NIRQS		64
    149   1.1   simonb 
    150  1.13  gdamore struct au_icu_intrhead {
    151   1.1   simonb 	struct evcnt intr_count;
    152   1.1   simonb 	int intr_refcnt;
    153   1.1   simonb };
    154  1.13  gdamore struct au_icu_intrhead au_icu_intrtab[NIRQS];
    155   1.1   simonb 
    156   1.1   simonb #define	NINTRS			4	/* MIPS INT0 - INT3 */
    157   1.1   simonb 
    158  1.14  gdamore struct au_intrhand {
    159  1.14  gdamore 	LIST_ENTRY(au_intrhand) ih_q;
    160  1.14  gdamore 	int (*ih_func)(void *);
    161  1.14  gdamore 	void *ih_arg;
    162  1.14  gdamore 	int ih_irq;
    163  1.19  gdamore 	int ih_mask;
    164  1.14  gdamore };
    165  1.14  gdamore 
    166  1.13  gdamore struct au_cpuintr {
    167  1.14  gdamore 	LIST_HEAD(, au_intrhand) cintr_list;
    168   1.1   simonb 	struct evcnt cintr_count;
    169   1.1   simonb };
    170   1.1   simonb 
    171  1.13  gdamore struct au_cpuintr au_cpuintrs[NINTRS];
    172  1.13  gdamore const char *au_cpuintrnames[NINTRS] = {
    173   1.1   simonb 	"icu 0, req 0",
    174   1.1   simonb 	"icu 0, req 1",
    175   1.1   simonb 	"icu 1, req 0",
    176   1.1   simonb 	"icu 1, req 1",
    177   1.1   simonb };
    178   1.1   simonb 
    179  1.13  gdamore static bus_addr_t ic0_base, ic1_base;
    180  1.13  gdamore 
    181   1.1   simonb void
    182   1.1   simonb au_intr_init(void)
    183   1.1   simonb {
    184  1.13  gdamore 	int			i;
    185  1.13  gdamore 	struct au_chipdep	*chip;
    186   1.1   simonb 
    187   1.1   simonb 	for (i = 0; i < NINTRS; i++) {
    188  1.13  gdamore 		LIST_INIT(&au_cpuintrs[i].cintr_list);
    189  1.13  gdamore 		evcnt_attach_dynamic(&au_cpuintrs[i].cintr_count,
    190  1.13  gdamore 		    EVCNT_TYPE_INTR, NULL, "mips", au_cpuintrnames[i]);
    191   1.1   simonb 	}
    192   1.1   simonb 
    193  1.13  gdamore 	chip = au_chipdep();
    194  1.13  gdamore 	KASSERT(chip != NULL);
    195  1.13  gdamore 
    196  1.13  gdamore 	ic0_base = chip->icus[0];
    197  1.13  gdamore 	ic1_base = chip->icus[1];
    198  1.13  gdamore 
    199   1.1   simonb 	for (i = 0; i < NIRQS; i++) {
    200  1.13  gdamore 		au_icu_intrtab[i].intr_refcnt = 0;
    201  1.13  gdamore 		evcnt_attach_dynamic(&au_icu_intrtab[i].intr_count,
    202  1.13  gdamore 		    EVCNT_TYPE_INTR, NULL, chip->name, chip->irqnames[i]);
    203   1.1   simonb 	}
    204  1.19  gdamore 
    205  1.19  gdamore 	/* start with all interrupts masked */
    206  1.19  gdamore 	REGVAL(ic0_base + IC_MASK_CLEAR) = 0xffffffff;
    207  1.19  gdamore 	REGVAL(ic0_base + IC_WAKEUP_CLEAR) = 0xffffffff;
    208  1.19  gdamore 	REGVAL(ic0_base + IC_SOURCE_SET) = 0xffffffff;
    209  1.19  gdamore 	REGVAL(ic0_base + IC_RISING_EDGE) = 0xffffffff;
    210  1.19  gdamore 	REGVAL(ic0_base + IC_FALLING_EDGE) = 0xffffffff;
    211  1.19  gdamore 	REGVAL(ic0_base + IC_TEST_BIT) = 0;
    212  1.19  gdamore 
    213  1.19  gdamore 	REGVAL(ic1_base + IC_MASK_CLEAR) = 0xffffffff;
    214  1.19  gdamore 	REGVAL(ic1_base + IC_WAKEUP_CLEAR) = 0xffffffff;
    215  1.19  gdamore 	REGVAL(ic1_base + IC_SOURCE_SET) = 0xffffffff;
    216  1.19  gdamore 	REGVAL(ic1_base + IC_RISING_EDGE) = 0xffffffff;
    217  1.19  gdamore 	REGVAL(ic1_base + IC_FALLING_EDGE) = 0xffffffff;
    218  1.19  gdamore 	REGVAL(ic1_base + IC_TEST_BIT) = 0;
    219   1.1   simonb }
    220   1.1   simonb 
    221   1.1   simonb void *
    222   1.1   simonb au_intr_establish(int irq, int req, int level, int type,
    223   1.1   simonb     int (*func)(void *), void *arg)
    224   1.1   simonb {
    225  1.14  gdamore 	struct au_intrhand	*ih;
    226  1.13  gdamore 	uint32_t		icu_base;
    227  1.13  gdamore 	int			cpu_int, s;
    228  1.13  gdamore 	struct au_chipdep	*chip;
    229  1.13  gdamore 
    230  1.13  gdamore 	chip = au_chipdep();
    231  1.13  gdamore 	KASSERT(chip != NULL);
    232   1.1   simonb 
    233   1.1   simonb 	if (irq >= NIRQS)
    234   1.3   provos 		panic("au_intr_establish: bogus IRQ %d", irq);
    235   1.1   simonb 	if (req > 1)
    236   1.3   provos 		panic("au_intr_establish: bogus request %d", req);
    237   1.1   simonb 
    238   1.1   simonb 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    239   1.1   simonb 	if (ih == NULL)
    240   1.1   simonb 		return (NULL);
    241   1.1   simonb 
    242   1.1   simonb 	ih->ih_func = func;
    243   1.1   simonb 	ih->ih_arg = arg;
    244   1.1   simonb 	ih->ih_irq = irq;
    245  1.19  gdamore 	ih->ih_mask = (1 << (irq & 31));
    246   1.1   simonb 
    247   1.1   simonb 	s = splhigh();
    248   1.1   simonb 
    249   1.1   simonb 	/*
    250   1.1   simonb 	 * First, link it into the tables.
    251   1.1   simonb 	 * XXX do we want a separate list (really, should only be one item, not
    252   1.9      wiz 	 *     a list anyway) per irq, not per CPU interrupt?
    253   1.1   simonb 	 */
    254  1.10       he 	cpu_int = (irq < 32 ? 0 : 2);
    255  1.13  gdamore 	LIST_INSERT_HEAD(&au_cpuintrs[cpu_int].cintr_list, ih, ih_q);
    256   1.1   simonb 
    257   1.1   simonb 	/*
    258   1.1   simonb 	 * Now enable it.
    259   1.1   simonb 	 */
    260  1.13  gdamore 	if (au_icu_intrtab[irq].intr_refcnt++ == 0) {
    261  1.13  gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    262   1.1   simonb 
    263   1.1   simonb 		irq &= 31;	/* throw away high bit if set */
    264   1.1   simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    265   1.1   simonb 
    266  1.13  gdamore 		/* XXX Only level interrupts for now */
    267   1.1   simonb 		switch (type) {
    268   1.1   simonb 		case IST_NONE:
    269   1.1   simonb 		case IST_PULSE:
    270   1.1   simonb 		case IST_EDGE:
    271   1.1   simonb 			panic("unsupported irq type %d", type);
    272   1.5  hpeyerl 			/* NOTREACHED */
    273   1.1   simonb 		case IST_LEVEL:
    274   1.5  hpeyerl 		case IST_LEVEL_HIGH:
    275   1.1   simonb 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    276   1.1   simonb 			REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    277   1.1   simonb 			REGVAL(icu_base + IC_CONFIG0_SET) = irq;
    278   1.5  hpeyerl 			break;
    279   1.5  hpeyerl 		case IST_LEVEL_LOW:
    280   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    281   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG1_SET) = irq;
    282   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    283   1.5  hpeyerl 			break;
    284   1.1   simonb 		}
    285  1.18  gdamore 		wbflush();
    286   1.1   simonb 
    287   1.1   simonb 		/* XXX handle GPIO interrupts - not done at all yet */
    288  1.10       he 		if (cpu_int & 0x1)
    289   1.1   simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
    290   1.1   simonb 		else
    291   1.1   simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
    292   1.1   simonb 
    293   1.1   simonb 		/* Associate interrupt with peripheral */
    294   1.1   simonb 		REGVAL(icu_base + IC_SOURCE_SET) = irq;
    295   1.1   simonb 
    296   1.1   simonb 		/* Actually enable the interrupt */
    297   1.1   simonb 		REGVAL(icu_base + IC_MASK_SET) = irq;
    298   1.1   simonb 
    299   1.1   simonb 		/* And allow the interrupt to interrupt idle */
    300   1.1   simonb 		REGVAL(icu_base + IC_WAKEUP_SET) = irq;
    301  1.18  gdamore 
    302  1.18  gdamore 		wbflush();
    303   1.1   simonb 	}
    304   1.1   simonb 	splx(s);
    305   1.1   simonb 
    306   1.1   simonb 	return (ih);
    307   1.1   simonb }
    308   1.1   simonb 
    309   1.1   simonb void
    310   1.1   simonb au_intr_disestablish(void *cookie)
    311   1.1   simonb {
    312  1.14  gdamore 	struct au_intrhand *ih = cookie;
    313   1.1   simonb 	uint32_t icu_base;
    314   1.1   simonb 	int irq, s;
    315   1.1   simonb 
    316   1.1   simonb 	irq = ih->ih_irq;
    317   1.1   simonb 
    318   1.1   simonb 	s = splhigh();
    319   1.1   simonb 
    320   1.1   simonb 	/*
    321   1.1   simonb 	 * First, remove it from the table.
    322   1.1   simonb 	 */
    323   1.1   simonb 	LIST_REMOVE(ih, ih_q);
    324   1.1   simonb 
    325   1.1   simonb 	/*
    326   1.1   simonb 	 * Now, disable it, if there is nothing remaining on the
    327   1.1   simonb 	 * list.
    328   1.1   simonb 	 */
    329  1.13  gdamore 	if (au_icu_intrtab[irq].intr_refcnt-- == 1) {
    330  1.13  gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    331   1.1   simonb 
    332   1.1   simonb 		irq &= 31;	/* throw away high bit if set */
    333   1.1   simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    334   1.1   simonb 
    335   1.1   simonb 		REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
    336   1.1   simonb 		REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    337   1.1   simonb 		REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    338   1.1   simonb 
    339  1.15  gdamore 		/* disable with MASK_CLEAR and WAKEUP_CLEAR */
    340  1.15  gdamore 		REGVAL(icu_base + IC_MASK_CLEAR) = irq;
    341  1.15  gdamore 		REGVAL(icu_base + IC_WAKEUP_CLEAR) = irq;
    342  1.18  gdamore 		wbflush();
    343   1.1   simonb 	}
    344   1.1   simonb 
    345   1.1   simonb 	splx(s);
    346   1.1   simonb 
    347   1.1   simonb 	free(ih, M_DEVBUF);
    348   1.1   simonb }
    349   1.1   simonb 
    350   1.1   simonb void
    351  1.14  gdamore au_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
    352   1.1   simonb {
    353  1.14  gdamore 	struct au_intrhand *ih;
    354   1.1   simonb 	int level;
    355  1.17   simonb 	uint32_t icu_base, irqstat, irqmask;
    356  1.17   simonb 
    357  1.19  gdamore 	icu_base = irqstat = 0;
    358   1.1   simonb 
    359   1.1   simonb 	for (level = 3; level >= 0; level--) {
    360   1.1   simonb 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    361   1.1   simonb 			continue;
    362   1.1   simonb 
    363   1.1   simonb 		/*
    364   1.1   simonb 		 * XXX	the following may well be slow to execute.
    365   1.1   simonb 		 *	investigate and possibly speed up.
    366   1.1   simonb 		 *
    367   1.1   simonb 		 * is something like:
    368   1.1   simonb 		 *
    369  1.17   simonb 		 *    irqstat = REGVAL(
    370   1.1   simonb 		 *	 (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
    371   1.1   simonb 		 *	 (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
    372   1.1   simonb 		 *
    373   1.1   simonb 		 * be any better?
    374   1.1   simonb 		 *
    375   1.1   simonb 		 */
    376   1.1   simonb 		switch (level) {
    377   1.1   simonb 		case 0:
    378  1.13  gdamore 			icu_base = ic0_base;
    379  1.15  gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
    380   1.1   simonb 			break;
    381   1.1   simonb 		case 1:
    382  1.13  gdamore 			icu_base = ic0_base;
    383  1.15  gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
    384   1.1   simonb 			break;
    385   1.1   simonb 		case 2:
    386  1.13  gdamore 			icu_base = ic1_base;
    387  1.15  gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
    388   1.1   simonb 			break;
    389   1.1   simonb 		case 3:
    390  1.13  gdamore 			icu_base = ic1_base;
    391  1.15  gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
    392   1.1   simonb 			break;
    393   1.1   simonb 		}
    394  1.15  gdamore 		irqmask = REGVAL(icu_base + IC_MASK_READ);
    395  1.13  gdamore 		au_cpuintrs[level].cintr_count.ev_count++;
    396  1.13  gdamore 		LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
    397  1.19  gdamore 			int mask = ih->ih_mask;
    398  1.15  gdamore 
    399  1.19  gdamore 			if (mask & irqmask & irqstat) {
    400  1.13  gdamore 				au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
    401   1.1   simonb 				(*ih->ih_func)(ih->ih_arg);
    402   1.1   simonb 
    403  1.19  gdamore 				if (REGVAL(icu_base + IC_MASK_READ) & mask) {
    404  1.19  gdamore 					REGVAL(icu_base + IC_MASK_CLEAR) = mask;
    405  1.19  gdamore 					REGVAL(icu_base + IC_MASK_SET) = mask;
    406  1.18  gdamore 					wbflush();
    407  1.16  gdamore 				}
    408   1.1   simonb 			}
    409   1.1   simonb 		}
    410   1.1   simonb 		cause &= ~(MIPS_INT_MASK_0 << level);
    411   1.1   simonb 	}
    412   1.1   simonb 
    413   1.1   simonb 	/* Re-enable anything that we have processed. */
    414   1.1   simonb 	_splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
    415   1.1   simonb }
    416  1.15  gdamore 
    417  1.15  gdamore /*
    418  1.15  gdamore  * Some devices (e.g. PCMCIA) want to be able to mask interrupts at
    419  1.15  gdamore  * the ICU, and leave them masked off until some later time
    420  1.15  gdamore  * (e.g. reenabled by a soft interrupt).
    421  1.15  gdamore  */
    422  1.15  gdamore 
    423  1.15  gdamore void
    424  1.15  gdamore au_intr_enable(int irq)
    425  1.15  gdamore {
    426  1.15  gdamore 	int		s;
    427  1.15  gdamore 	uint32_t	icu_base, mask;
    428  1.15  gdamore 
    429  1.15  gdamore 	if (irq >= NIRQS)
    430  1.15  gdamore 		panic("au_intr_enable: bogus IRQ %d", irq);
    431  1.15  gdamore 
    432  1.15  gdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
    433  1.15  gdamore 	mask = irq & 31;
    434  1.15  gdamore 	mask = 1 << mask;
    435  1.15  gdamore 
    436  1.15  gdamore 	s = splhigh();
    437  1.15  gdamore 	/* only enable the interrupt if we have a handler */
    438  1.18  gdamore 	if (au_icu_intrtab[irq].intr_refcnt) {
    439  1.15  gdamore 		REGVAL(icu_base + IC_MASK_SET) = mask;
    440  1.18  gdamore 		REGVAL(icu_base + IC_WAKEUP_SET) = mask;
    441  1.18  gdamore 		wbflush();
    442  1.18  gdamore 	}
    443  1.15  gdamore 	splx(s);
    444  1.15  gdamore }
    445  1.15  gdamore 
    446  1.15  gdamore void
    447  1.15  gdamore au_intr_disable(int irq)
    448  1.15  gdamore {
    449  1.15  gdamore 	int		s;
    450  1.15  gdamore 	uint32_t	icu_base, mask;
    451  1.15  gdamore 
    452  1.18  gdamore 	if (irq >= NIRQS)
    453  1.18  gdamore 		panic("au_intr_disable: bogus IRQ %d", irq);
    454  1.18  gdamore 
    455  1.15  gdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
    456  1.15  gdamore 	mask = irq & 31;
    457  1.15  gdamore 	mask = 1 << mask;
    458  1.15  gdamore 
    459  1.15  gdamore 	s = splhigh();
    460  1.15  gdamore 	REGVAL(icu_base + IC_MASK_CLEAR) = mask;
    461  1.18  gdamore 	REGVAL(icu_base + IC_WAKEUP_CLEAR) = mask;
    462  1.18  gdamore 	wbflush();
    463  1.15  gdamore 	splx(s);
    464  1.15  gdamore }
    465