Home | History | Annotate | Line # | Download | only in alchemy
      1  1.31   thorpej /*	$NetBSD: au_icu.c,v 1.31 2021/01/04 17:35:12 thorpej 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  *
     50   1.1    simonb  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     51   1.1    simonb  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     52   1.1    simonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     53   1.1    simonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     54   1.1    simonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     55   1.1    simonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     56   1.1    simonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     57   1.1    simonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     58   1.1    simonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     59   1.1    simonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     60   1.1    simonb  * POSSIBILITY OF SUCH DAMAGE.
     61   1.1    simonb  */
     62   1.1    simonb 
     63   1.1    simonb /*
     64   1.1    simonb  * Interrupt support for the Alchemy Semiconductor Au1x00 CPUs.
     65   1.1    simonb  *
     66   1.1    simonb  * The Alchemy Semiconductor Au1x00's interrupts are wired to two internal
     67   1.1    simonb  * interrupt controllers.
     68   1.1    simonb  */
     69   1.7     lukem 
     70   1.7     lukem #include <sys/cdefs.h>
     71  1.31   thorpej __KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.31 2021/01/04 17:35:12 thorpej Exp $");
     72   1.1    simonb 
     73   1.1    simonb #include "opt_ddb.h"
     74  1.26      matt #define __INTR_PRIVATE
     75   1.1    simonb 
     76   1.1    simonb #include <sys/param.h>
     77  1.28      matt #include <sys/bus.h>
     78  1.28      matt #include <sys/device.h>
     79  1.28      matt #include <sys/intr.h>
     80  1.28      matt #include <sys/kernel.h>
     81  1.31   thorpej #include <sys/kmem.h>
     82   1.1    simonb #include <sys/systm.h>
     83   1.1    simonb 
     84   1.1    simonb #include <mips/locore.h>
     85   1.1    simonb #include <mips/alchemy/include/aureg.h>
     86   1.1    simonb #include <mips/alchemy/include/auvar.h>
     87   1.1    simonb 
     88  1.14   gdamore #define	REGVAL(x)	*((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
     89   1.1    simonb 
     90   1.1    simonb /*
     91   1.1    simonb  * This is a mask of bits to clear in the SR when we go to a
     92   1.1    simonb  * given hardware interrupt priority level.
     93   1.1    simonb  */
     94   1.1    simonb 
     95  1.26      matt static const struct ipl_sr_map alchemy_ipl_sr_map = {
     96  1.26      matt     .sr_bits = {
     97  1.26      matt 	[IPL_NONE] =		0,
     98  1.26      matt 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
     99  1.26      matt 	[IPL_SOFTBIO] =		MIPS_SOFT_INT_MASK_0,
    100  1.26      matt 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
    101  1.26      matt 	[IPL_SOFTSERIAL] =	MIPS_SOFT_INT_MASK,
    102  1.29  kiyohara 	[IPL_VM] =		MIPS_SOFT_INT_MASK |
    103  1.29  kiyohara 				MIPS_INT_MASK_0	|
    104  1.29  kiyohara 				MIPS_INT_MASK_1	|
    105  1.29  kiyohara 				MIPS_INT_MASK_2 |
    106  1.29  kiyohara 				MIPS_INT_MASK_3,
    107  1.26      matt 	[IPL_SCHED] =		MIPS_INT_MASK,
    108  1.29  kiyohara 	[IPL_DDB] =		MIPS_INT_MASK,
    109  1.26      matt 	[IPL_HIGH] =		MIPS_INT_MASK,
    110  1.26      matt     },
    111   1.1    simonb };
    112   1.1    simonb 
    113   1.1    simonb #define	NIRQS		64
    114   1.1    simonb 
    115  1.13   gdamore struct au_icu_intrhead {
    116   1.1    simonb 	struct evcnt intr_count;
    117   1.1    simonb 	int intr_refcnt;
    118   1.1    simonb };
    119  1.13   gdamore struct au_icu_intrhead au_icu_intrtab[NIRQS];
    120   1.1    simonb 
    121   1.1    simonb #define	NINTRS			4	/* MIPS INT0 - INT3 */
    122   1.1    simonb 
    123  1.14   gdamore struct au_intrhand {
    124  1.14   gdamore 	LIST_ENTRY(au_intrhand) ih_q;
    125  1.14   gdamore 	int (*ih_func)(void *);
    126  1.14   gdamore 	void *ih_arg;
    127  1.14   gdamore 	int ih_irq;
    128  1.19   gdamore 	int ih_mask;
    129  1.14   gdamore };
    130  1.14   gdamore 
    131  1.13   gdamore struct au_cpuintr {
    132  1.14   gdamore 	LIST_HEAD(, au_intrhand) cintr_list;
    133   1.1    simonb 	struct evcnt cintr_count;
    134   1.1    simonb };
    135   1.1    simonb 
    136  1.13   gdamore struct au_cpuintr au_cpuintrs[NINTRS];
    137  1.26      matt const char * const au_cpuintrnames[NINTRS] = {
    138   1.1    simonb 	"icu 0, req 0",
    139   1.1    simonb 	"icu 0, req 1",
    140   1.1    simonb 	"icu 1, req 0",
    141   1.1    simonb 	"icu 1, req 1",
    142   1.1    simonb };
    143   1.1    simonb 
    144  1.13   gdamore static bus_addr_t ic0_base, ic1_base;
    145  1.13   gdamore 
    146   1.1    simonb void
    147   1.1    simonb au_intr_init(void)
    148   1.1    simonb {
    149  1.26      matt 	ipl_sr_map = alchemy_ipl_sr_map;
    150   1.1    simonb 
    151  1.26      matt 	for (size_t i = 0; i < NINTRS; i++) {
    152  1.13   gdamore 		LIST_INIT(&au_cpuintrs[i].cintr_list);
    153  1.13   gdamore 		evcnt_attach_dynamic(&au_cpuintrs[i].cintr_count,
    154  1.13   gdamore 		    EVCNT_TYPE_INTR, NULL, "mips", au_cpuintrnames[i]);
    155   1.1    simonb 	}
    156   1.1    simonb 
    157  1.26      matt 	struct au_chipdep * const chip = au_chipdep();
    158  1.13   gdamore 	KASSERT(chip != NULL);
    159  1.13   gdamore 
    160  1.13   gdamore 	ic0_base = chip->icus[0];
    161  1.13   gdamore 	ic1_base = chip->icus[1];
    162  1.13   gdamore 
    163  1.26      matt 	for (size_t i = 0; i < NIRQS; i++) {
    164  1.13   gdamore 		au_icu_intrtab[i].intr_refcnt = 0;
    165  1.13   gdamore 		evcnt_attach_dynamic(&au_icu_intrtab[i].intr_count,
    166  1.13   gdamore 		    EVCNT_TYPE_INTR, NULL, chip->name, chip->irqnames[i]);
    167   1.1    simonb 	}
    168  1.19   gdamore 
    169  1.19   gdamore 	/* start with all interrupts masked */
    170  1.19   gdamore 	REGVAL(ic0_base + IC_MASK_CLEAR) = 0xffffffff;
    171  1.19   gdamore 	REGVAL(ic0_base + IC_WAKEUP_CLEAR) = 0xffffffff;
    172  1.19   gdamore 	REGVAL(ic0_base + IC_SOURCE_SET) = 0xffffffff;
    173  1.19   gdamore 	REGVAL(ic0_base + IC_RISING_EDGE) = 0xffffffff;
    174  1.19   gdamore 	REGVAL(ic0_base + IC_FALLING_EDGE) = 0xffffffff;
    175  1.19   gdamore 	REGVAL(ic0_base + IC_TEST_BIT) = 0;
    176  1.19   gdamore 
    177  1.19   gdamore 	REGVAL(ic1_base + IC_MASK_CLEAR) = 0xffffffff;
    178  1.19   gdamore 	REGVAL(ic1_base + IC_WAKEUP_CLEAR) = 0xffffffff;
    179  1.19   gdamore 	REGVAL(ic1_base + IC_SOURCE_SET) = 0xffffffff;
    180  1.19   gdamore 	REGVAL(ic1_base + IC_RISING_EDGE) = 0xffffffff;
    181  1.19   gdamore 	REGVAL(ic1_base + IC_FALLING_EDGE) = 0xffffffff;
    182  1.19   gdamore 	REGVAL(ic1_base + IC_TEST_BIT) = 0;
    183   1.1    simonb }
    184   1.1    simonb 
    185   1.1    simonb void *
    186   1.1    simonb au_intr_establish(int irq, int req, int level, int type,
    187   1.1    simonb     int (*func)(void *), void *arg)
    188   1.1    simonb {
    189  1.14   gdamore 	struct au_intrhand	*ih;
    190  1.13   gdamore 	uint32_t		icu_base;
    191  1.13   gdamore 	int			cpu_int, s;
    192  1.13   gdamore 	struct au_chipdep	*chip;
    193  1.13   gdamore 
    194  1.13   gdamore 	chip = au_chipdep();
    195  1.13   gdamore 	KASSERT(chip != NULL);
    196   1.1    simonb 
    197   1.1    simonb 	if (irq >= NIRQS)
    198   1.3    provos 		panic("au_intr_establish: bogus IRQ %d", irq);
    199   1.1    simonb 	if (req > 1)
    200   1.3    provos 		panic("au_intr_establish: bogus request %d", req);
    201   1.1    simonb 
    202  1.31   thorpej 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
    203   1.1    simonb 	ih->ih_func = func;
    204   1.1    simonb 	ih->ih_arg = arg;
    205   1.1    simonb 	ih->ih_irq = irq;
    206  1.19   gdamore 	ih->ih_mask = (1 << (irq & 31));
    207   1.1    simonb 
    208   1.1    simonb 	s = splhigh();
    209   1.1    simonb 
    210   1.1    simonb 	/*
    211   1.1    simonb 	 * First, link it into the tables.
    212   1.1    simonb 	 * XXX do we want a separate list (really, should only be one item, not
    213   1.9       wiz 	 *     a list anyway) per irq, not per CPU interrupt?
    214   1.1    simonb 	 */
    215  1.20   gdamore 	cpu_int = (irq < 32 ? 0 : 2) + req;
    216  1.13   gdamore 	LIST_INSERT_HEAD(&au_cpuintrs[cpu_int].cintr_list, ih, ih_q);
    217   1.1    simonb 
    218   1.1    simonb 	/*
    219   1.1    simonb 	 * Now enable it.
    220   1.1    simonb 	 */
    221  1.13   gdamore 	if (au_icu_intrtab[irq].intr_refcnt++ == 0) {
    222  1.13   gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    223   1.1    simonb 
    224   1.1    simonb 		irq &= 31;	/* throw away high bit if set */
    225   1.1    simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    226   1.1    simonb 
    227  1.13   gdamore 		/* XXX Only level interrupts for now */
    228   1.1    simonb 		switch (type) {
    229   1.1    simonb 		case IST_NONE:
    230   1.1    simonb 		case IST_PULSE:
    231   1.1    simonb 		case IST_EDGE:
    232   1.1    simonb 			panic("unsupported irq type %d", type);
    233   1.5   hpeyerl 			/* NOTREACHED */
    234   1.1    simonb 		case IST_LEVEL:
    235   1.5   hpeyerl 		case IST_LEVEL_HIGH:
    236   1.1    simonb 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    237   1.1    simonb 			REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    238   1.1    simonb 			REGVAL(icu_base + IC_CONFIG0_SET) = irq;
    239   1.5   hpeyerl 			break;
    240   1.5   hpeyerl 		case IST_LEVEL_LOW:
    241   1.5   hpeyerl 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    242   1.5   hpeyerl 			REGVAL(icu_base + IC_CONFIG1_SET) = irq;
    243   1.5   hpeyerl 			REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    244   1.5   hpeyerl 			break;
    245   1.1    simonb 		}
    246  1.18   gdamore 		wbflush();
    247   1.1    simonb 
    248   1.1    simonb 		/* XXX handle GPIO interrupts - not done at all yet */
    249  1.10        he 		if (cpu_int & 0x1)
    250   1.1    simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
    251   1.1    simonb 		else
    252   1.1    simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
    253   1.1    simonb 
    254   1.1    simonb 		/* Associate interrupt with peripheral */
    255   1.1    simonb 		REGVAL(icu_base + IC_SOURCE_SET) = irq;
    256   1.1    simonb 
    257   1.1    simonb 		/* Actually enable the interrupt */
    258   1.1    simonb 		REGVAL(icu_base + IC_MASK_SET) = irq;
    259   1.1    simonb 
    260   1.1    simonb 		/* And allow the interrupt to interrupt idle */
    261   1.1    simonb 		REGVAL(icu_base + IC_WAKEUP_SET) = irq;
    262  1.18   gdamore 
    263  1.18   gdamore 		wbflush();
    264   1.1    simonb 	}
    265   1.1    simonb 	splx(s);
    266   1.1    simonb 
    267   1.1    simonb 	return (ih);
    268   1.1    simonb }
    269   1.1    simonb 
    270   1.1    simonb void
    271   1.1    simonb au_intr_disestablish(void *cookie)
    272   1.1    simonb {
    273  1.14   gdamore 	struct au_intrhand *ih = cookie;
    274   1.1    simonb 	uint32_t icu_base;
    275   1.1    simonb 	int irq, s;
    276   1.1    simonb 
    277   1.1    simonb 	irq = ih->ih_irq;
    278   1.1    simonb 
    279   1.1    simonb 	s = splhigh();
    280   1.1    simonb 
    281   1.1    simonb 	/*
    282   1.1    simonb 	 * First, remove it from the table.
    283   1.1    simonb 	 */
    284   1.1    simonb 	LIST_REMOVE(ih, ih_q);
    285   1.1    simonb 
    286   1.1    simonb 	/*
    287   1.1    simonb 	 * Now, disable it, if there is nothing remaining on the
    288   1.1    simonb 	 * list.
    289   1.1    simonb 	 */
    290  1.13   gdamore 	if (au_icu_intrtab[irq].intr_refcnt-- == 1) {
    291  1.13   gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    292   1.1    simonb 
    293   1.1    simonb 		irq &= 31;	/* throw away high bit if set */
    294   1.1    simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    295   1.1    simonb 
    296   1.1    simonb 		REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
    297   1.1    simonb 		REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    298   1.1    simonb 		REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    299   1.1    simonb 
    300  1.15   gdamore 		/* disable with MASK_CLEAR and WAKEUP_CLEAR */
    301  1.15   gdamore 		REGVAL(icu_base + IC_MASK_CLEAR) = irq;
    302  1.15   gdamore 		REGVAL(icu_base + IC_WAKEUP_CLEAR) = irq;
    303  1.18   gdamore 		wbflush();
    304   1.1    simonb 	}
    305   1.1    simonb 
    306   1.1    simonb 	splx(s);
    307   1.1    simonb 
    308  1.31   thorpej 	kmem_free(ih, sizeof(*ih));
    309   1.1    simonb }
    310   1.1    simonb 
    311   1.1    simonb void
    312  1.26      matt au_iointr(int ipl, vaddr_t pc, uint32_t ipending)
    313   1.1    simonb {
    314  1.14   gdamore 	struct au_intrhand *ih;
    315   1.1    simonb 	int level;
    316  1.17    simonb 	uint32_t icu_base, irqstat, irqmask;
    317  1.17    simonb 
    318  1.19   gdamore 	icu_base = irqstat = 0;
    319   1.1    simonb 
    320   1.1    simonb 	for (level = 3; level >= 0; level--) {
    321   1.1    simonb 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    322   1.1    simonb 			continue;
    323   1.1    simonb 
    324   1.1    simonb 		/*
    325   1.1    simonb 		 * XXX	the following may well be slow to execute.
    326   1.1    simonb 		 *	investigate and possibly speed up.
    327   1.1    simonb 		 *
    328   1.1    simonb 		 * is something like:
    329   1.1    simonb 		 *
    330  1.17    simonb 		 *    irqstat = REGVAL(
    331   1.1    simonb 		 *	 (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
    332   1.1    simonb 		 *	 (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
    333   1.1    simonb 		 *
    334   1.1    simonb 		 * be any better?
    335   1.1    simonb 		 *
    336   1.1    simonb 		 */
    337   1.1    simonb 		switch (level) {
    338   1.1    simonb 		case 0:
    339  1.13   gdamore 			icu_base = ic0_base;
    340  1.15   gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
    341   1.1    simonb 			break;
    342   1.1    simonb 		case 1:
    343  1.13   gdamore 			icu_base = ic0_base;
    344  1.15   gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
    345   1.1    simonb 			break;
    346   1.1    simonb 		case 2:
    347  1.13   gdamore 			icu_base = ic1_base;
    348  1.15   gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
    349   1.1    simonb 			break;
    350   1.1    simonb 		case 3:
    351  1.13   gdamore 			icu_base = ic1_base;
    352  1.15   gdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
    353   1.1    simonb 			break;
    354   1.1    simonb 		}
    355  1.15   gdamore 		irqmask = REGVAL(icu_base + IC_MASK_READ);
    356  1.13   gdamore 		au_cpuintrs[level].cintr_count.ev_count++;
    357  1.13   gdamore 		LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
    358  1.19   gdamore 			int mask = ih->ih_mask;
    359  1.15   gdamore 
    360  1.19   gdamore 			if (mask & irqmask & irqstat) {
    361  1.13   gdamore 				au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
    362   1.1    simonb 				(*ih->ih_func)(ih->ih_arg);
    363   1.1    simonb 
    364  1.19   gdamore 				if (REGVAL(icu_base + IC_MASK_READ) & mask) {
    365  1.19   gdamore 					REGVAL(icu_base + IC_MASK_CLEAR) = mask;
    366  1.19   gdamore 					REGVAL(icu_base + IC_MASK_SET) = mask;
    367  1.18   gdamore 					wbflush();
    368  1.16   gdamore 				}
    369   1.1    simonb 			}
    370   1.1    simonb 		}
    371   1.1    simonb 	}
    372   1.1    simonb }
    373  1.15   gdamore 
    374  1.15   gdamore /*
    375  1.15   gdamore  * Some devices (e.g. PCMCIA) want to be able to mask interrupts at
    376  1.15   gdamore  * the ICU, and leave them masked off until some later time
    377  1.15   gdamore  * (e.g. reenabled by a soft interrupt).
    378  1.15   gdamore  */
    379  1.15   gdamore 
    380  1.15   gdamore void
    381  1.15   gdamore au_intr_enable(int irq)
    382  1.15   gdamore {
    383  1.15   gdamore 	int		s;
    384  1.15   gdamore 	uint32_t	icu_base, mask;
    385  1.15   gdamore 
    386  1.15   gdamore 	if (irq >= NIRQS)
    387  1.15   gdamore 		panic("au_intr_enable: bogus IRQ %d", irq);
    388  1.15   gdamore 
    389  1.15   gdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
    390  1.15   gdamore 	mask = irq & 31;
    391  1.15   gdamore 	mask = 1 << mask;
    392  1.15   gdamore 
    393  1.15   gdamore 	s = splhigh();
    394  1.15   gdamore 	/* only enable the interrupt if we have a handler */
    395  1.18   gdamore 	if (au_icu_intrtab[irq].intr_refcnt) {
    396  1.15   gdamore 		REGVAL(icu_base + IC_MASK_SET) = mask;
    397  1.18   gdamore 		REGVAL(icu_base + IC_WAKEUP_SET) = mask;
    398  1.18   gdamore 		wbflush();
    399  1.18   gdamore 	}
    400  1.15   gdamore 	splx(s);
    401  1.15   gdamore }
    402  1.15   gdamore 
    403  1.15   gdamore void
    404  1.15   gdamore au_intr_disable(int irq)
    405  1.15   gdamore {
    406  1.15   gdamore 	int		s;
    407  1.15   gdamore 	uint32_t	icu_base, mask;
    408  1.15   gdamore 
    409  1.18   gdamore 	if (irq >= NIRQS)
    410  1.18   gdamore 		panic("au_intr_disable: bogus IRQ %d", irq);
    411  1.18   gdamore 
    412  1.15   gdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
    413  1.15   gdamore 	mask = irq & 31;
    414  1.15   gdamore 	mask = 1 << mask;
    415  1.15   gdamore 
    416  1.15   gdamore 	s = splhigh();
    417  1.15   gdamore 	REGVAL(icu_base + IC_MASK_CLEAR) = mask;
    418  1.18   gdamore 	REGVAL(icu_base + IC_WAKEUP_CLEAR) = mask;
    419  1.18   gdamore 	wbflush();
    420  1.15   gdamore 	splx(s);
    421  1.15   gdamore }
    422