Home | History | Annotate | Line # | Download | only in ews4800mips
      1 /*	$NetBSD: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by UCHIYAMA Yasushi.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $");
     34 
     35 #define __INTR_PRIVATE
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/evcnt.h>
     40 #include <sys/lwp.h>
     41 #include <sys/cpu.h>
     42 #include <sys/intr.h>
     43 
     44 #include <machine/locore.h>	/* mips3_cp0* */
     45 #include <machine/sbdvar.h>
     46 #define	_SBD_TR2A_PRIVATE
     47 #include <machine/sbd_tr2a.h>
     48 
     49 SBD_DECL(tr2a);
     50 
     51 const struct ipl_sr_map tr2a_ipl_sr_map = {
     52     .sr_bits = {
     53 	[IPL_NONE] = 0,
     54 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
     55 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
     56 	[IPL_VM] =		MIPS_INT_MASK & ~MIPS_INT_MASK_5,
     57 	[IPL_SCHED] =		MIPS_INT_MASK,
     58 	[IPL_DDB] =		MIPS_INT_MASK,
     59 	[IPL_HIGH] =		MIPS_INT_MASK,
     60     },
     61 };
     62 
     63 #define	NIRQ		16
     64 enum bustype {
     65 	ASOBUS,
     66 	APBUS,
     67 };
     68 
     69 /* ASO + APbus interrupt */
     70 struct tr2a_intr_handler {
     71 	int (*func)(void *);
     72 	void *arg;
     73 	enum bustype bustype;
     74 	uint32_t cpu_int;
     75 	uint32_t aso_mask;
     76 	struct evcnt evcnt;
     77 	char evname[32];
     78 } tr2a_intr_handler[NIRQ] = {
     79 	[0]  = { NULL, NULL, ASOBUS, 2, 0x00000001 },	/* AM79C90 */
     80 	[4]  = { NULL, NULL, ASOBUS, 4, 0x00300010 },	/* Z85230 (SIO) */
     81 	[6]  = { NULL, NULL, ASOBUS, 2, 0x00000200 },	/* 53C710 SCSI-A */
     82 	[9]  = { NULL, NULL, ASOBUS, 4, 0x00000040 },	/* Z85230 (KBMS) */
     83 	[10] = { NULL, NULL, ASOBUS, 2, 0x00000100 },	/* 53C710 SCSI-B */
     84 };
     85 
     86 /* CPU interrupt */
     87 struct tr2a_intc_handler {
     88 	int ref_cnt;
     89 	uint32_t mask;
     90 } tr2a_intc_handler[6] = {
     91 	[0] = { 0, 0x00000020 },
     92 	[1] = { 0, 0x00000800 },
     93 	[2] = { 0, 0x00010000 },
     94 	[3] = { 0, 0x00200000 },
     95 	[4] = { 0, 0x04000000 },
     96 	[5] = { 0, 0x80000000 }
     97 };
     98 
     99 struct evcnt timer_tr2a_ev =
    100     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "intc", "timer");
    101 
    102 void
    103 tr2a_intr_init(void)
    104 {
    105 
    106 	/* Disable all ASObus interrupt */
    107 #if 1
    108 	*ASO_INT_MASK_REG &= ~TR2A_ASO_INTMASK_ALL;
    109 #else
    110 	/* open all interrupt for development. */
    111 	*ASO_INT_MASK_REG |= TR2A_ASO_INTMASK_ALL;
    112 #endif
    113 	tr2a_wbflush();
    114 
    115 	/* set up interval timer clock */
    116 	*INTC_MASK_REG = 0;
    117 	*CLOCK_REG = 0x80;
    118 	tr2a_wbflush();
    119 	if ((*CLOCK_REG & 0x80) != 0)
    120 		*ASO_INT_MASK_REG |= 0x8000;	/* NMI (what UX does.) -uch */
    121 	tr2a_wbflush();
    122 
    123 	evcnt_attach_static(&timer_tr2a_ev);
    124 }
    125 
    126 void *
    127 tr2a_intr_establish(int irq, int (*func)(void *), void *arg)
    128 {
    129 	struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq];
    130 	struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int];
    131 	int s;
    132 
    133 	s = splhigh();
    134 	ih->func = func;
    135 	ih->arg  = arg;
    136 	snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq);
    137 	evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR,
    138 	    NULL, "intc", ih->evname);
    139 
    140 	if (ih->bustype == ASOBUS)
    141 		*ASO_INT_MASK_REG |= ih->aso_mask;
    142 
    143 	if (ic->ref_cnt++ == 0)
    144 		*INTC_MASK_REG |= ic->mask;
    145 
    146 	tr2a_wbflush();
    147 	splx(s);
    148 
    149 	return (void *)irq;
    150 }
    151 
    152 void
    153 tr2a_intr_disestablish(void *arg)
    154 {
    155 	int s, irq = (int)arg;
    156 	struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq];
    157 	struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int];
    158 
    159 	s = splhigh();
    160 	if (ih->bustype == ASOBUS)
    161 		*ASO_INT_MASK_REG &= ~ih->aso_mask;
    162 
    163 	if (--ic->ref_cnt == 0)
    164 		*INTC_MASK_REG &= ~ic->mask;
    165 
    166 	ih->func = NULL;
    167 	ih->arg = NULL;
    168 	evcnt_detach(&ih->evcnt);
    169 	splx(s);
    170 }
    171 
    172 void
    173 tr2a_intr(int ppl, vaddr_t pc, uint32_t status)
    174 {
    175 	struct tr2a_intr_handler *ih;
    176 	struct clockframe cf;
    177 	uint32_t r, intc_cause, ipending;
    178 	int ipl;
    179 
    180 	intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG;
    181 
    182 	while (ppl < (ipl = splintr(&ipending))) {
    183 		if ((ipending & MIPS_INT_MASK_5) && (intc_cause & INTC_INT5)) {
    184 			cf.pc = pc;
    185 			cf.sr = status;
    186 			cf.intr = (curcpu()->ci_idepth > 1);
    187 			tr2a_wbflush();
    188 			*INTC_CLEAR_REG = 0x7c;
    189 			*INTC_STATUS_REG;
    190 
    191 			hardclock(&cf);
    192 			timer_tr2a_ev.ev_count++;
    193 		}
    194 
    195 		if ((ipending & MIPS_INT_MASK_4) && (intc_cause & INTC_INT4)) {
    196 			/* KBD, MOUSE, SERIAL */
    197 			r = *ASO_INT_STATUS_REG;
    198 			if (r & 0x300010) {
    199 				ih = &tr2a_intr_handler[4];
    200 				if (ih->func) {
    201 					ih->func(ih->arg);
    202 					ih->evcnt.ev_count++;
    203 				}
    204 			} else if (r & 0x40) {
    205 				/* kbms */
    206 				ih = &tr2a_intr_handler[9];
    207 				if (ih->func) {
    208 					ih->func(ih->arg);
    209 					ih->evcnt.ev_count++;
    210 				}
    211 			} else if (r & 0x20) {
    212 				printf("INT4 (1)\n");
    213 			} else if (r & 0x00800000) {
    214 				printf("INT4 (2)\n");
    215 			} else if (r & 0x00400000) {
    216 				printf("INT4 (3)\n");
    217 			} else if (r != 0) {
    218 				printf("not for INT4 %x\n", r);
    219 			}
    220 
    221 			tr2a_wbflush();
    222 			*INTC_CLEAR_REG = 0x68;
    223 			*INTC_STATUS_REG;
    224 		}
    225 
    226 		if ((ipending & MIPS_INT_MASK_3) && (intc_cause & INTC_INT3)) {
    227 			/* APbus HI */
    228 			printf("APbus HI\n");
    229 			tr2a_wbflush();
    230 			*INTC_CLEAR_REG = 0x54;
    231 			*INTC_STATUS_REG;
    232 		}
    233 
    234 		if ((ipending & MIPS_INT_MASK_2) && (intc_cause & INTC_INT2)) {
    235 			/* SCSI, ETHER */
    236 			r = *ASO_INT_STATUS_REG;
    237 			if (r & 0x100) {	/* SCSI-A */
    238 				ih = &tr2a_intr_handler[6];
    239 				if (ih->func) {
    240 					ih->func(ih->arg);
    241 					ih->evcnt.ev_count++;
    242 				}
    243 			} else if (r & 0x200) {	/* SCSI-B */
    244 				ih = &tr2a_intr_handler[10];
    245 				if (ih->func) {
    246 					ih->func(ih->arg);
    247 					ih->evcnt.ev_count++;
    248 				}
    249 			} else if (r & 0x1) {	/* LANCE */
    250 				ih = &tr2a_intr_handler[0];
    251 				if (ih->func) {
    252 					ih->func(ih->arg);
    253 					ih->evcnt.ev_count++;
    254 				}
    255 			} else if (r != 0) {
    256 				printf("not for INT2 %x %x\n", r,
    257 				    *ASO_DMAINT_STATUS_REG);
    258 			}
    259 
    260 			tr2a_wbflush();
    261 			*INTC_CLEAR_REG = 0x40;
    262 			*INTC_STATUS_REG;
    263 		}
    264 
    265 		if ((ipending & MIPS_INT_MASK_1) && (intc_cause & INTC_INT1)) {
    266 			/* APbus LO */
    267 			printf("APbus LO\n");
    268 			tr2a_wbflush();
    269 			*INTC_CLEAR_REG = 0x2c;
    270 			*INTC_STATUS_REG;
    271 		}
    272 
    273 		if ((ipending & MIPS_INT_MASK_0) && (intc_cause & INTC_INT0)) {
    274 			/* NMI etc. */
    275 			r = *ASO_INT_STATUS_REG;
    276 			printf("INT0 %08x\n", r);
    277 			if (r & 0x8000) {
    278 				printf("INT0(1) NMI\n");
    279 			} else if (r & 0x8) {
    280 				printf("INT0(2)\n");
    281 			} else if (r & 0x4) {
    282 				printf("INT0(3)\n");
    283 			} else if (r != 0) {
    284 				printf("not for INT0 %x\n", r);
    285 			}
    286 			tr2a_wbflush();
    287 			*INTC_CLEAR_REG = 0x14;
    288 			*INTC_STATUS_REG;
    289 		}
    290 		intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG;
    291 	}
    292 }
    293 
    294 void
    295 tr2a_initclocks(void)
    296 {
    297 
    298 	/* Enable INT5 */
    299 	*INTC_MASK_REG |= INTC_INT5;
    300 	tr2a_wbflush();
    301 }
    302