Home | History | Annotate | Line # | Download | only in algor
      1 /*	$NetBSD: algor_p6032_intr.c,v 1.24 2020/11/14 02:23:04 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      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 /*
     33  * Platform-specific interrupt support for the Algorithmics P-6032.
     34  *
     35  * The Algorithmics P-6032's interrupts are wired to GPIO pins
     36  * on the BONITO system controller.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: algor_p6032_intr.c,v 1.24 2020/11/14 02:23:04 thorpej Exp $");
     41 
     42 #include "opt_ddb.h"
     43 #define	__INTR_PRIVATE
     44 
     45 #include <sys/param.h>
     46 #include <sys/bus.h>
     47 #include <sys/cpu.h>
     48 #include <sys/device.h>
     49 #include <sys/intr.h>
     50 #include <sys/kernel.h>
     51 #include <sys/kmem.h>
     52 #include <sys/queue.h>
     53 #include <sys/systm.h>
     54 
     55 #include <algor/autoconf.h>
     56 
     57 #include <mips/locore.h>
     58 
     59 #include <dev/ic/mc146818reg.h>
     60 
     61 #include <algor/algor/algor_p6032reg.h>
     62 #include <algor/algor/algor_p6032var.h>
     63 
     64 #include <dev/pci/pcireg.h>
     65 #include <dev/pci/pcivar.h>
     66 
     67 #include <dev/isa/isavar.h>
     68 
     69 /*
     70  * The P-6032 interrupts are wired up in the following way:
     71  *
     72  *	GPIN0		ISA_NMI		(in)
     73  *	GPIN1		ISA_INTR	(in)
     74  *	GPIN2		ETH_INT~	(in)
     75  *	GPIN3		BONIDE_INT	(in)
     76  *
     77  *	GPIN4		ISA IRQ3	(in, also on piix4)
     78  *	GPIN5		ISA IRQ4	(in, also on piix4)
     79  *
     80  *	GPIO0		PIRQ A~		(in)
     81  *	GPIO1		PIRQ B~		(in)
     82  *	GPIO2		PIRQ C~		(in)
     83  *	GPIO3		PIRQ D~		(in)
     84  */
     85 
     86 #define	NIRQMAPS	10
     87 
     88 const char * const p6032_intrnames[NIRQMAPS] = {
     89 	"gpin 0",
     90 	"gpin 1",
     91 	"gpin 2",
     92 	"gpin 3",
     93 
     94 	"gpin 4",
     95 	"gpin 5",
     96 
     97 	"gpio 0",
     98 	"gpio 1",
     99 	"gpio 2",
    100 	"gpio 3",
    101 };
    102 
    103 struct p6032_irqmap {
    104 	int	irqidx;
    105 	uint32_t intbit;
    106 	uint32_t gpioiebit;
    107 	int	flags;
    108 };
    109 
    110 #define	IRQ_F_INVERT	0x01	/* invert polarity */
    111 #define	IRQ_F_EDGE	0x02	/* edge trigger */
    112 #define	IRQ_F_INT1	0x04	/* INT1, else INT0 */
    113 
    114 const struct p6032_irqmap p6032_irqmap[NIRQMAPS] = {
    115 	/* ISA NMI */
    116 	{ P6032_IRQ_GPIN0,	BONITO_ICU_GPIN(0),
    117 	  BONITO_GPIO_INR(0),	IRQ_F_INT1 },
    118 
    119 	/* ISA bridge */
    120 	{ P6032_IRQ_GPIN1,	BONITO_ICU_GPIN(1),
    121 	  BONITO_GPIO_INR(1),	IRQ_F_INT1 },
    122 
    123 	/* Ethernet */
    124 	{ P6032_IRQ_GPIN2,	BONITO_ICU_GPIN(2),
    125 	  BONITO_GPIO_INR(2),	IRQ_F_INVERT },
    126 
    127 	/* BONITO IDE */
    128 	{ P6032_IRQ_GPIN3,	BONITO_ICU_GPIN(3),
    129 	  BONITO_GPIO_INR(3),	0 },
    130 
    131 	/* ISA IRQ3 */
    132 	{ P6032_IRQ_GPIN4,	BONITO_ICU_GPIN(4),
    133 	  BONITO_GPIO_INR(4),	IRQ_F_INT1 },
    134 
    135 	/* ISA IRQ4 */
    136 	{ P6032_IRQ_GPIN5,	BONITO_ICU_GPIN(5),
    137 	  BONITO_GPIO_INR(5),	IRQ_F_INT1 },
    138 
    139 	/* PIRQ A */
    140 	{ P6032_IRQ_GPIO0,	BONITO_ICU_GPIO(0),
    141 	  BONITO_GPIO_IOW(0),	IRQ_F_INVERT },
    142 
    143 	/* PIRQ B */
    144 	{ P6032_IRQ_GPIO1,	BONITO_ICU_GPIO(1),
    145 	  BONITO_GPIO_IOW(1),	IRQ_F_INVERT },
    146 
    147 	/* PIRQ C */
    148 	{ P6032_IRQ_GPIO2,	BONITO_ICU_GPIO(2),
    149 	  BONITO_GPIO_IOW(2),	IRQ_F_INVERT },
    150 
    151 	/* PIRQ D */
    152 	{ P6032_IRQ_GPIO3,	BONITO_ICU_GPIO(3),
    153 	  BONITO_GPIO_IOW(3),	IRQ_F_INVERT },
    154 };
    155 
    156 struct p6032_intrhead {
    157 	struct evcnt intr_count;
    158 	int intr_refcnt;
    159 };
    160 struct p6032_intrhead p6032_intrtab[NIRQMAPS];
    161 
    162 #define	NINTRS			2	/* MIPS INT0 - INT1 */
    163 
    164 struct p6032_cpuintr {
    165 	LIST_HEAD(, evbmips_intrhand) cintr_list;
    166 	struct evcnt cintr_count;
    167 };
    168 
    169 struct p6032_cpuintr p6032_cpuintrs[NINTRS];
    170 const char * const p6032_cpuintrnames[NINTRS] = {
    171 	"int 0 (pci)",
    172 	"int 1 (isa)",
    173 };
    174 
    175 void	*algor_p6032_intr_establish(int, int (*)(void *), void *);
    176 void	algor_p6032_intr_disestablish(void *);
    177 
    178 int	algor_p6032_pci_intr_map(const struct pci_attach_args *,
    179 	    pci_intr_handle_t *);
    180 const char *algor_p6032_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
    181 const struct evcnt *algor_p6032_pci_intr_evcnt(void *, pci_intr_handle_t);
    182 void	*algor_p6032_pci_intr_establish(void *, pci_intr_handle_t, int,
    183 	    int (*)(void *), void *);
    184 void	algor_p6032_pci_intr_disestablish(void *, void *);
    185 void	algor_p6032_pci_conf_interrupt(void *, int, int, int, int, int *);
    186 
    187 void	algor_p6032_iointr(int, vaddr_t, uint32_t);
    188 
    189 void
    190 algor_p6032_intr_init(struct p6032_config *acp)
    191 {
    192 	struct bonito_config *bc = &acp->ac_bonito;
    193 	const struct p6032_irqmap *irqmap;
    194 	int i;
    195 
    196 	for (i = 0; i < NINTRS; i++) {
    197 		LIST_INIT(&p6032_cpuintrs[i].cintr_list);
    198 		evcnt_attach_dynamic(&p6032_cpuintrs[i].cintr_count,
    199 		    EVCNT_TYPE_INTR, NULL, "mips", p6032_cpuintrnames[i]);
    200 	}
    201 
    202 	for (i = 0; i < __arraycount(p6032_irqmap); i++) {
    203 		irqmap = &p6032_irqmap[i];
    204 
    205 		evcnt_attach_dynamic(&p6032_intrtab[i].intr_count,
    206 		    EVCNT_TYPE_INTR, NULL, "bonito", p6032_intrnames[i]);
    207 
    208 		bc->bc_gpioIE |= irqmap->gpioiebit;
    209 		if (irqmap->flags & IRQ_F_INVERT)
    210 			bc->bc_intPol |= irqmap->intbit;
    211 		if (irqmap->flags & IRQ_F_EDGE)
    212 			bc->bc_intEdge |= irqmap->intbit;
    213 		if (irqmap->flags & IRQ_F_INT1)
    214 			bc->bc_intSteer |= irqmap->intbit;
    215 
    216 		REGVAL(BONITO_INTENCLR) = irqmap->intbit;
    217 	}
    218 
    219 	REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE;
    220 	REGVAL(BONITO_INTEDGE) = bc->bc_intEdge;
    221 	REGVAL(BONITO_INTSTEER) = bc->bc_intSteer;
    222 	REGVAL(BONITO_INTPOL) = bc->bc_intPol;
    223 
    224 	acp->ac_pc.pc_intr_v = NULL;
    225 	acp->ac_pc.pc_intr_map = algor_p6032_pci_intr_map;
    226 	acp->ac_pc.pc_intr_string = algor_p6032_pci_intr_string;
    227 	acp->ac_pc.pc_intr_evcnt = algor_p6032_pci_intr_evcnt;
    228 	acp->ac_pc.pc_intr_establish = algor_p6032_pci_intr_establish;
    229 	acp->ac_pc.pc_intr_disestablish = algor_p6032_pci_intr_disestablish;
    230 	acp->ac_pc.pc_conf_interrupt = algor_p6032_pci_conf_interrupt;
    231 
    232 	/* We let the PCI-ISA bridge code handle this. */
    233 	acp->ac_pc.pc_pciide_compat_intr_establish = NULL;
    234 
    235 	algor_intr_establish = algor_p6032_intr_establish;
    236 	algor_intr_disestablish = algor_p6032_intr_disestablish;
    237 	algor_iointr = algor_p6032_iointr;
    238 }
    239 
    240 void
    241 algor_p6032_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
    242 {
    243 	u_long ctrdiff[4], startctr, endctr, cps;
    244 	uint8_t regc;
    245 	int i;
    246 
    247 	/* Disable interrupts first. */
    248 	bus_space_write_1(st, sh, 0, MC_REGB);
    249 	bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
    250 	    MC_REGB_24HR);
    251 
    252 	/* Initialize for 16Hz. */
    253 	bus_space_write_1(st, sh, 0, MC_REGA);
    254 	bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
    255 
    256 	/* Run the loop an extra time to prime the cache. */
    257 	for (i = 0; i < 4; i++) {
    258 		led_display('h', 'z', '0' + i, ' ');
    259 
    260 		/* Enable the interrupt. */
    261 		bus_space_write_1(st, sh, 0, MC_REGB);
    262 		bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
    263 		    MC_REGB_BINARY | MC_REGB_24HR);
    264 
    265 		/* Go to REGC. */
    266 		bus_space_write_1(st, sh, 0, MC_REGC);
    267 
    268 		/* Wait for it to happen. */
    269 		startctr = mips3_cp0_count_read();
    270 		do {
    271 			regc = bus_space_read_1(st, sh, 1);
    272 			endctr = mips3_cp0_count_read();
    273 		} while ((regc & MC_REGC_IRQF) == 0);
    274 
    275 		/* Already ACK'd. */
    276 
    277 		/* Disable. */
    278 		bus_space_write_1(st, sh, 0, MC_REGB);
    279 		bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
    280 		    MC_REGB_24HR);
    281 
    282 		ctrdiff[i] = endctr - startctr;
    283 	}
    284 
    285 	/* Update CPU frequency values */
    286 	cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
    287 	/* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */
    288 	curcpu()->ci_cpu_freq = cps * 2;
    289 	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
    290 	curcpu()->ci_divisor_delay =
    291 	    ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000);
    292 	/* XXX assume CPU_MIPS_DOUBLE_COUNT */
    293 	curcpu()->ci_cycles_per_hz /= 2;
    294 	curcpu()->ci_divisor_delay /= 2;
    295 
    296 	printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
    297 	    cps, ctrdiff[2], ctrdiff[3]);
    298 	printf("CPU clock speed = %lu.%02luMHz "
    299 	    "(hz cycles = %lu, delay divisor = %lu)\n",
    300 	    curcpu()->ci_cpu_freq / 1000000,
    301 	    (curcpu()->ci_cpu_freq % 1000000) / 10000,
    302 	    curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);
    303 }
    304 
    305 void *
    306 algor_p6032_intr_establish(int irq, int (*func)(void *), void *arg)
    307 {
    308 	const struct p6032_irqmap *irqmap;
    309 	struct evbmips_intrhand *ih;
    310 	int s;
    311 
    312 	irqmap = &p6032_irqmap[irq];
    313 
    314 	KASSERT(irq == irqmap->irqidx);
    315 
    316 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
    317 	ih->ih_func = func;
    318 	ih->ih_arg = arg;
    319 	ih->ih_irq = 0;
    320 	ih->ih_irqmap = irqmap;
    321 
    322 	s = splhigh();
    323 
    324 	/*
    325 	 * First, link it into the tables.
    326 	 */
    327 	if (irqmap->flags & IRQ_F_INT1)
    328 		LIST_INSERT_HEAD(&p6032_cpuintrs[1].cintr_list, ih, ih_q);
    329 	else
    330 		LIST_INSERT_HEAD(&p6032_cpuintrs[0].cintr_list, ih, ih_q);
    331 
    332 	/*
    333 	 * Now enable it.
    334 	 */
    335 	if (p6032_intrtab[irqmap->irqidx].intr_refcnt++ == 0)
    336 		REGVAL(BONITO_INTENSET) = irqmap->intbit;
    337 
    338 	splx(s);
    339 
    340 	return (ih);
    341 }
    342 
    343 void
    344 algor_p6032_intr_disestablish(void *cookie)
    345 {
    346 	const struct p6032_irqmap *irqmap;
    347 	struct evbmips_intrhand *ih = cookie;
    348 	int s;
    349 
    350 	irqmap = ih->ih_irqmap;
    351 
    352 	s = splhigh();
    353 
    354 	/*
    355 	 * First, remove it from the table.
    356 	 */
    357 	LIST_REMOVE(ih, ih_q);
    358 
    359 	/*
    360 	 * Now, disable it, if there is nothing remaining on the
    361 	 * list.
    362 	 */
    363 	if (p6032_intrtab[irqmap->irqidx].intr_refcnt-- == 1)
    364 		REGVAL(BONITO_INTENCLR) = irqmap->intbit;
    365 
    366 	splx(s);
    367 
    368 	kmem_free(ih, sizeof(*ih));
    369 }
    370 
    371 void
    372 algor_p6032_iointr(int ipl, vaddr_t pc, uint32_t ipending)
    373 {
    374 	const struct p6032_irqmap *irqmap;
    375 	struct evbmips_intrhand *ih;
    376 	int level;
    377 	uint32_t isr;
    378 
    379 	/* Check for DEBUG interrupts. */
    380 	if (ipending & MIPS_INT_MASK_3) {
    381 #ifdef DDB
    382 		printf("Debug switch -- entering debugger\n");
    383 		led_display('D','D','B',' ');
    384 		Debugger();
    385 		led_display('N','B','S','D');
    386 #else
    387 		printf("Debug switch ignored -- "
    388 		    "no debugger configured\n");
    389 #endif
    390 	}
    391 
    392 	/*
    393 	 * Read the interrupt pending registers, mask them with the
    394 	 * ones we have enabled, and service them in order of decreasing
    395 	 * priority.
    396 	 */
    397 	isr = REGVAL(BONITO_INTISR) & REGVAL(BONITO_INTEN);
    398 
    399 	for (level = 1; level >= 0; level--) {
    400 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    401 			continue;
    402 		p6032_cpuintrs[level].cintr_count.ev_count++;
    403 		for (ih = LIST_FIRST(&p6032_cpuintrs[level].cintr_list);
    404 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
    405 			irqmap = ih->ih_irqmap;
    406 			if (isr & irqmap->intbit) {
    407 				p6032_intrtab[
    408 				    irqmap->irqidx].intr_count.ev_count++;
    409 				(*ih->ih_func)(ih->ih_arg);
    410 			}
    411 		}
    412 	}
    413 }
    414 
    415 /*****************************************************************************
    416  * PCI interrupt support
    417  *****************************************************************************/
    418 
    419 int
    420 algor_p6032_pci_intr_map(const struct pci_attach_args *pa,
    421     pci_intr_handle_t *ihp)
    422 {
    423 	static const int pciirqmap[6/*device*/][4/*pin*/] = {
    424 	    { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1,
    425 	      P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 13: slot 2 (p9) */
    426 
    427 	    { P6032_IRQ_GPIO1, P6032_IRQ_GPIO2,
    428 	      P6032_IRQ_GPIO3, P6032_IRQ_GPIO0 }, /* 14: slot 3 (p10) */
    429 
    430 	    { P6032_IRQ_GPIO2, P6032_IRQ_GPIO3,
    431 	      P6032_IRQ_GPIO0, P6032_IRQ_GPIO1 }, /* 15: slot 4 (p11) */
    432 
    433 	    { P6032_IRQ_GPIN2, -1,
    434 	      -1,              -1 },              /* 16: Ethernet */
    435 
    436 	    { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1,
    437 	      P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 17: southbridge */
    438 
    439 	    { P6032_IRQ_GPIO3, P6032_IRQ_GPIO0,
    440 	      P6032_IRQ_GPIO1, P6032_IRQ_GPIO2 }, /* 18: slot 1 (p8) */
    441 	};
    442 	pcitag_t bustag = pa->pa_intrtag;
    443 	int buspin = pa->pa_intrpin;
    444 	pci_chipset_tag_t pc = pa->pa_pc;
    445 	int device, irq;
    446 
    447 	if (buspin == 0) {
    448 		/* No IRQ used. */
    449 		return (1);
    450 	}
    451 
    452 	if (buspin > 4) {
    453 		printf("algor_p6032_pci_intr_map: bad interrupt pin %d\n",
    454 		    buspin);
    455 		return (1);
    456 	}
    457 
    458 	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
    459 	if (device < 13 || device > 18) {
    460 		printf("algor_p6032_pci_intr_map: bad device %d\n",
    461 		    device);
    462 		return (1);
    463 	}
    464 
    465 	irq = pciirqmap[device - 13][buspin - 1];
    466 	if (irq == -1) {
    467 		printf("algor_p6032_pci_intr_map: no mapping for "
    468 		    "device %d pin %d\n", device, buspin);
    469 		return (1);
    470 	}
    471 
    472 	*ihp = irq;
    473 	return (0);
    474 }
    475 
    476 const char *
    477 algor_p6032_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
    478 {
    479 
    480 	if (ih >= NIRQMAPS)
    481 		panic("algor_p6032_intr_string: bogus IRQ %ld", ih);
    482 
    483 	strlcpy(buf, p6032_intrnames[ih], len);
    484 	return buf;
    485 }
    486 
    487 const struct evcnt *
    488 algor_p6032_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
    489 {
    490 
    491 	return (&p6032_intrtab[ih].intr_count);
    492 }
    493 
    494 void *
    495 algor_p6032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
    496     int (*func)(void *), void *arg)
    497 {
    498 
    499 	if (ih >= NIRQMAPS)
    500 		panic("algor_p6032_intr_establish: bogus IRQ %ld", ih);
    501 
    502 	return (algor_p6032_intr_establish(ih, func, arg));
    503 }
    504 
    505 void
    506 algor_p6032_pci_intr_disestablish(void *v, void *cookie)
    507 {
    508 
    509 	return (algor_p6032_intr_disestablish(cookie));
    510 }
    511 
    512 void
    513 algor_p6032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
    514     int *iline)
    515 {
    516 
    517 	/*
    518 	 * We actually don't need to do anything; everything is handled
    519 	 * in pci_intr_map().
    520 	 */
    521 	*iline = 0;
    522 }
    523