Home | History | Annotate | Line # | Download | only in algor
      1 /*	$NetBSD: algor_p4032_intr.c,v 1.27 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-4032.
     34  *
     35  * The Algorithmics P-4032 has an interrupt controller that is pretty
     36  * flexible -- it can take an interrupt source and route it to an
     37  * arbitrary MIPS CPU hardware interrupt pin.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: algor_p4032_intr.c,v 1.27 2020/11/14 02:23:04 thorpej Exp $");
     42 
     43 #include "opt_ddb.h"
     44 #define	__INTR_PRIVATE
     45 
     46 #include <sys/param.h>
     47 #include <sys/bus.h>
     48 #include <sys/cpu.h>
     49 #include <sys/device.h>
     50 #include <sys/intr.h>
     51 #include <sys/kernel.h>
     52 #include <sys/kmem.h>
     53 #include <sys/queue.h>
     54 #include <sys/systm.h>
     55 
     56 #include <algor/autoconf.h>
     57 
     58 #include <mips/locore.h>
     59 
     60 #include <dev/ic/mc146818reg.h>
     61 
     62 #include <algor/algor/algor_p4032reg.h>
     63 #include <algor/algor/algor_p4032var.h>
     64 
     65 #include <dev/pci/pcireg.h>
     66 #include <dev/pci/pcivar.h>
     67 
     68 #define	REGVAL(x)	*((volatile u_int32_t *)(MIPS_PHYS_TO_KSEG1((x))))
     69 
     70 struct p4032_irqreg {
     71 	bus_addr_t	addr;
     72 	u_int32_t	val;
     73 };
     74 
     75 #define	IRQREG_8BIT		0
     76 #define	IRQREG_ERROR		1
     77 #define	IRQREG_PCI		2
     78 #define	NIRQREG			3
     79 
     80 struct p4032_irqreg p4032_irqregs[NIRQREG] = {
     81 	{ P4032_IRR0,		0 },
     82 	{ P4032_IRR1,		0 },
     83 	{ P4032_IRR2,		0 },
     84 };
     85 
     86 #define	NSTEERREG		3
     87 
     88 struct p4032_irqreg p4032_irqsteer[NSTEERREG] = {
     89 	{ P4032_XBAR0,		0 },
     90 	{ P4032_XBAR1,		0 },
     91 	{ P4032_XBAR2,		0 },
     92 };
     93 
     94 #define	NPCIIRQS		4
     95 
     96 /* See algor_p4032var.h */
     97 #define	N8BITIRQS		8
     98 
     99 #define	IRQMAP_PCIBASE		0
    100 #define	IRQMAP_8BITBASE		NPCIIRQS
    101 #define	NIRQMAPS		(IRQMAP_8BITBASE + N8BITIRQS)
    102 
    103 const char * const p4032_intrnames[NIRQMAPS] = {
    104 	/*
    105 	 * PCI INTERRUPTS
    106 	 */
    107 	"PCIIRQ 0",
    108 	"PCIIRQ 1",
    109 	"PCIIRQ 2",
    110 	"PCIIRQ 3",
    111 
    112 	/*
    113 	 * 8-BIT DEVICE INTERRUPTS
    114 	 */
    115 	"PCI ctlr",
    116 	"floppy",
    117 	"pckbc",
    118 	"com 1",
    119 	"com 2",
    120 	"centronics",
    121 	"gpio",
    122 	"mcclock",
    123 };
    124 
    125 struct p4032_irqmap {
    126 	int	irqidx;
    127 	int	cpuintr;
    128 	int	irqreg;
    129 	int	irqbit;
    130 	int	xbarreg;
    131 	int	xbarshift;
    132 };
    133 
    134 const struct p4032_irqmap p4032_irqmap[NIRQMAPS] = {
    135 	/*
    136 	 * PCI INTERRUPTS
    137 	 */
    138 	/* PCIIRQ 0 */
    139 	{ 0,			0,
    140 	  IRQREG_PCI,		IRR2_PCIIRQ0,
    141 	  2,			0 },
    142 
    143 	/* PCIIRQ 1 */
    144 	{ 1,			0,
    145 	  IRQREG_PCI,		IRR2_PCIIRQ1,
    146 	  2,			2 },
    147 
    148 	/* PCIIRQ 2 */
    149 	{ 2,			0,
    150 	  IRQREG_PCI,		IRR2_PCIIRQ2,
    151 	  2,			4 },
    152 
    153 	/* PCIIRQ 3 */
    154 	{ 3,			0,
    155 	  IRQREG_PCI,		IRR2_PCIIRQ3,
    156 	  2,			6 },
    157 
    158 	/*
    159 	 * 8-BIT DEVICE INTERRUPTS
    160 	 */
    161 	{ P4032_IRQ_PCICTLR,	1,
    162 	  IRQREG_8BIT,		IRR0_PCICTLR,
    163 	  0,			0 },
    164 
    165 	{ P4032_IRQ_FLOPPY,	1,
    166 	  IRQREG_8BIT,		IRR0_FLOPPY,
    167 	  0,			2 },
    168 
    169 	{ P4032_IRQ_PCKBC,	1,
    170 	  IRQREG_8BIT,		IRR0_PCKBC,
    171 	  0,			4 },
    172 
    173 	{ P4032_IRQ_COM1,	1,
    174 	  IRQREG_8BIT,		IRR0_COM1,
    175 	  0,			6 },
    176 
    177 	{ P4032_IRQ_COM2,	1,
    178 	  IRQREG_8BIT,		IRR0_COM2,
    179 	  1,			0 },
    180 
    181 	{ P4032_IRQ_LPT,	1,
    182 	  IRQREG_8BIT,		IRR0_LPT,
    183 	  1,			2 },
    184 
    185 	{ P4032_IRQ_GPIO,	1,
    186 	  IRQREG_8BIT,		IRR0_GPIO,
    187 	  1,			4 },
    188 
    189 	{ P4032_IRQ_RTC,	1,
    190 	  IRQREG_8BIT,		IRR0_RTC,
    191 	  1,			6 },
    192 };
    193 
    194 struct p4032_intrhead {
    195 	struct evcnt intr_count;
    196 	int intr_refcnt;
    197 };
    198 struct p4032_intrhead p4032_intrtab[NIRQMAPS];
    199 
    200 #define	NINTRS			2	/* MIPS INT0 - INT1 */
    201 
    202 
    203 struct p4032_cpuintr {
    204 	LIST_HEAD(, evbmips_intrhand) cintr_list;
    205 	struct evcnt cintr_count;
    206 };
    207 
    208 struct p4032_cpuintr p4032_cpuintrs[NINTRS];
    209 const char * const p4032_cpuintrnames[NINTRS] = {
    210 	"int 0 (pci)",
    211 	"int 1 (8-bit)",
    212 };
    213 
    214 const char * const p4032_intrgroups[NINTRS] = {
    215 	"pci",
    216 	"8-bit",
    217 };
    218 
    219 void	*algor_p4032_intr_establish(int, int (*)(void *), void *);
    220 void	algor_p4032_intr_disestablish(void *);
    221 
    222 int	algor_p4032_pci_intr_map(const struct pci_attach_args *,
    223 	    pci_intr_handle_t *);
    224 const char *algor_p4032_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
    225 const struct evcnt *algor_p4032_pci_intr_evcnt(void *, pci_intr_handle_t);
    226 void	*algor_p4032_pci_intr_establish(void *, pci_intr_handle_t, int,
    227 	    int (*)(void *), void *);
    228 void	algor_p4032_pci_intr_disestablish(void *, void *);
    229 void	algor_p4032_pci_conf_interrupt(void *, int, int, int, int, int *);
    230 
    231 void	algor_p4032_iointr(int, vaddr_t, uint32_t);
    232 
    233 void
    234 algor_p4032_intr_init(struct p4032_config *acp)
    235 {
    236 	const struct p4032_irqmap *irqmap;
    237 	int i;
    238 
    239 	for (i = 0; i < NIRQREG; i++)
    240 		REGVAL(p4032_irqregs[i].addr) = p4032_irqregs[i].val;
    241 
    242 	for (i = 0; i < NINTRS; i++) {
    243 		LIST_INIT(&p4032_cpuintrs[i].cintr_list);
    244 		evcnt_attach_dynamic(&p4032_cpuintrs[i].cintr_count,
    245 		    EVCNT_TYPE_INTR, NULL, "mips", p4032_cpuintrnames[i]);
    246 	}
    247 
    248 	for (i = 0; i < NIRQMAPS; i++) {
    249 		irqmap = &p4032_irqmap[i];
    250 
    251 		p4032_irqsteer[irqmap->xbarreg].val |=
    252 		    irqmap->cpuintr << irqmap->xbarshift;
    253 
    254 		evcnt_attach_dynamic(&p4032_intrtab[i].intr_count,
    255 		    EVCNT_TYPE_INTR, NULL, p4032_intrgroups[irqmap->cpuintr],
    256 		    p4032_intrnames[i]);
    257 	}
    258 
    259 	for (i = 0; i < NSTEERREG; i++)
    260 		REGVAL(p4032_irqsteer[i].addr) = p4032_irqsteer[i].val;
    261 
    262 	acp->ac_pc.pc_intr_v = NULL;
    263 	acp->ac_pc.pc_intr_map = algor_p4032_pci_intr_map;
    264 	acp->ac_pc.pc_intr_string = algor_p4032_pci_intr_string;
    265 	acp->ac_pc.pc_intr_evcnt = algor_p4032_pci_intr_evcnt;
    266 	acp->ac_pc.pc_intr_establish = algor_p4032_pci_intr_establish;
    267 	acp->ac_pc.pc_intr_disestablish = algor_p4032_pci_intr_disestablish;
    268 	acp->ac_pc.pc_conf_interrupt = algor_p4032_pci_conf_interrupt;
    269 	acp->ac_pc.pc_pciide_compat_intr_establish = NULL;
    270 
    271 	algor_intr_establish = algor_p4032_intr_establish;
    272 	algor_intr_disestablish = algor_p4032_intr_disestablish;
    273 	algor_iointr = algor_p4032_iointr;
    274 }
    275 
    276 void
    277 algor_p4032_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
    278 {
    279 	u_long ctrdiff[4], startctr, endctr, cps;
    280 	u_int32_t irr;
    281 	int i;
    282 
    283 	/* Disable interrupts first. */
    284 	bus_space_write_1(st, sh, 0, MC_REGB);
    285 	bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
    286 	    MC_REGB_24HR);
    287 
    288 	/* Initialize for 16Hz. */
    289 	bus_space_write_1(st, sh, 0, MC_REGA);
    290 	bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
    291 
    292 	REGVAL(P4032_IRR0) = IRR0_RTC;
    293 
    294 	/* Run the loop an extra time to prime the cache. */
    295 	for (i = 0; i < 4; i++) {
    296 		led_display('h', 'z', '0' + i, ' ');
    297 
    298 		/* Enable the interrupt. */
    299 		bus_space_write_1(st, sh, 0, MC_REGB);
    300 		bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
    301 		    MC_REGB_BINARY | MC_REGB_24HR);
    302 
    303 		/* Wait for it to happen. */
    304 		startctr = mips3_cp0_count_read();
    305 		do {
    306 			irr = REGVAL(P4032_IRR0);
    307 			endctr = mips3_cp0_count_read();
    308 		} while ((irr & IRR0_RTC) == 0);
    309 
    310 		/* ACK. */
    311 		bus_space_write_1(st, sh, 0, MC_REGC);
    312 		(void) bus_space_read_1(st, sh, 1);
    313 
    314 		/* Disable. */
    315 		bus_space_write_1(st, sh, 0, MC_REGB);
    316 		bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
    317 		    MC_REGB_24HR);
    318 
    319 		ctrdiff[i] = endctr - startctr;
    320 	}
    321 
    322 	REGVAL(P4032_IRR0) = 0;
    323 
    324 	/* Update CPU frequency values */
    325 	cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
    326 	/* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */
    327 	curcpu()->ci_cpu_freq = cps * 2;
    328 	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
    329 	curcpu()->ci_divisor_delay =
    330 	    ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000);
    331 	/* XXX assume CPU_MIPS_DOUBLE_COUNT */
    332 	curcpu()->ci_cycles_per_hz /= 2;
    333 	curcpu()->ci_divisor_delay /= 2;
    334 
    335 	printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
    336 	    cps, ctrdiff[2], ctrdiff[3]);
    337 	printf("CPU clock speed = %lu.%02luMHz "
    338 	    "(hz cycles = %lu, delay divisor = %lu)\n",
    339 	    curcpu()->ci_cpu_freq / 1000000,
    340 	    (curcpu()->ci_cpu_freq % 1000000) / 10000,
    341 	    curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);
    342 }
    343 
    344 void *
    345 algor_p4032_intr_establish(int irq, int (*func)(void *), void *arg)
    346 {
    347 	const struct p4032_irqmap *irqmap;
    348 	struct evbmips_intrhand *ih;
    349 	int s;
    350 
    351 	irqmap = &p4032_irqmap[irq];
    352 
    353 	KASSERT(irq == irqmap->irqidx);
    354 
    355 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
    356 	ih->ih_func = func;
    357 	ih->ih_arg = arg;
    358 	ih->ih_irq = 0;
    359 	ih->ih_irqmap = irqmap;
    360 
    361 	s = splhigh();
    362 
    363 	/*
    364 	 * First, link it into the tables.
    365 	 */
    366 	LIST_INSERT_HEAD(&p4032_cpuintrs[irqmap->cpuintr].cintr_list,
    367 	    ih, ih_q);
    368 
    369 	/*
    370 	 * Now enable it.
    371 	 */
    372 	if (p4032_intrtab[irqmap->irqidx].intr_refcnt++ == 0) {
    373 		p4032_irqregs[irqmap->irqreg].val |= irqmap->irqbit;
    374 		REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
    375 		    p4032_irqregs[irqmap->irqreg].val;
    376 	}
    377 
    378 	splx(s);
    379 
    380 	return (ih);
    381 }
    382 
    383 void
    384 algor_p4032_intr_disestablish(void *cookie)
    385 {
    386 	const struct p4032_irqmap *irqmap;
    387 	struct evbmips_intrhand *ih = cookie;
    388 	int s;
    389 
    390 	irqmap = ih->ih_irqmap;
    391 
    392 	s = splhigh();
    393 
    394 	/*
    395 	 * First, remove it from the table.
    396 	 */
    397 	LIST_REMOVE(ih, ih_q);
    398 
    399 	/*
    400 	 * Now, disable it, if there is nothing remaining on the
    401 	 * list.
    402 	 */
    403 	if (p4032_intrtab[irqmap->irqidx].intr_refcnt-- == 1) {
    404 		p4032_irqregs[irqmap->irqreg].val &= ~irqmap->irqbit;
    405 		REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
    406 		    p4032_irqregs[irqmap->irqreg].val;
    407 	}
    408 
    409 	splx(s);
    410 
    411 	kmem_free(ih, sizeof(*ih));
    412 }
    413 
    414 void
    415 algor_p4032_iointr(int ipl, vaddr_t pc, u_int32_t ipending)
    416 {
    417 	const struct p4032_irqmap *irqmap;
    418 	struct evbmips_intrhand *ih;
    419 	int level, i;
    420 	u_int32_t irr[NIRQREG];
    421 
    422 	/* Check for ERROR interrupts. */
    423 	if (ipending & MIPS_INT_MASK_4) {
    424 		irr[IRQREG_ERROR] = REGVAL(p4032_irqregs[IRQREG_ERROR].addr);
    425 		if (irr[IRQREG_ERROR] & IRR1_BUSERR)
    426 			printf("WARNING: Bus error\n");
    427 		if (irr[IRQREG_ERROR] & IRR1_POWERFAIL)
    428 			printf("WARNING: Power failure\n");
    429 		if (irr[IRQREG_ERROR] & IRR1_DEBUG) {
    430 #ifdef DDB
    431 			printf("Debug switch -- entering debugger\n");
    432 			led_display('D','D','B',' ');
    433 			Debugger();
    434 			led_display('N','B','S','D');
    435 #else
    436 			printf("Debug switch ignored -- "
    437 			    "no debugger configured\n");
    438 #endif
    439 		}
    440 
    441 		/* Clear them. */
    442 		REGVAL(p4032_irqregs[IRQREG_ERROR].addr) = irr[IRQREG_ERROR];
    443 	}
    444 
    445 	/* Do floppy DMA request interrupts. */
    446 	if (ipending & MIPS_INT_MASK_3) {
    447 		/*
    448 		 * XXX Hi, um, yah, we need to deal with
    449 		 * XXX the floppy interrupt here.
    450 		 */
    451 
    452 	}
    453 
    454 	/*
    455 	 * Read the interrupt pending registers, mask them with the
    456 	 * ones we have enabled, and service them in order of decreasing
    457 	 * priority.
    458 	 */
    459 	for (i = 0; i < NIRQREG; i++) {
    460 		if (i == IRQREG_ERROR)
    461 			continue;
    462 		irr[i] = REGVAL(p4032_irqregs[i].addr) & p4032_irqregs[i].val;
    463 	}
    464 
    465 	for (level = (NINTRS - 1); level >= 0; level--) {
    466 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    467 			continue;
    468 		p4032_cpuintrs[level].cintr_count.ev_count++;
    469 		for (ih = LIST_FIRST(&p4032_cpuintrs[level].cintr_list);
    470 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
    471 			irqmap = ih->ih_irqmap;
    472 			if (irr[irqmap->irqreg] & irqmap->irqbit) {
    473 				p4032_intrtab[
    474 				    irqmap->irqidx].intr_count.ev_count++;
    475 				(*ih->ih_func)(ih->ih_arg);
    476 			}
    477 		}
    478 	}
    479 }
    480 
    481 /*****************************************************************************
    482  * PCI interrupt support
    483  *****************************************************************************/
    484 
    485 int
    486 algor_p4032_pci_intr_map(const struct pci_attach_args *pa,
    487     pci_intr_handle_t *ihp)
    488 {
    489 	static const int pciirqmap[6/*device*/][4/*pin*/] = {
    490 		{ 1, -1, -1, -1 },		/* 5: Ethernet */
    491 		{ 2, 3, 0, 1 },			/* 6: PCI slot 1 */
    492 		{ 3, 0, 1, 2 },			/* 7: PCI slot 2 */
    493 		{ 0, -1, -1, -1 },		/* 8: SCSI */
    494 		{ -1, -1, -1, -1 },		/* 9: not used */
    495 		{ 0, 1, 2, 3 },			/* 10: custom connector */
    496 	};
    497 	pcitag_t bustag = pa->pa_intrtag;
    498 	int buspin = pa->pa_intrpin;
    499 	pci_chipset_tag_t pc = pa->pa_pc;
    500 	int device, irq;
    501 
    502 	if (buspin == 0) {
    503 		/* No IRQ used. */
    504 		return (1);
    505 	}
    506 
    507 	if (buspin > 4) {
    508 		printf("algor_p4032_pci_intr_map: bad interrupt pin %d\n",
    509 		    buspin);
    510 		return (1);
    511 	}
    512 
    513 	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
    514 	if (device < 5 || device > 10) {
    515 		printf("algor_p4032_pci_intr_map: bad device %d\n",
    516 		    device);
    517 		return (1);
    518 	}
    519 
    520 	irq = pciirqmap[device - 5][buspin - 1];
    521 	if (irq == -1) {
    522 		printf("algor_p4032_pci_intr_map: no mapping for "
    523 		    "device %d pin %d\n", device, buspin);
    524 		return (1);
    525 	}
    526 
    527 	*ihp = irq;
    528 	return (0);
    529 }
    530 
    531 const char *
    532 algor_p4032_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
    533 {
    534 
    535 	if (ih >= NPCIIRQS)
    536 		panic("algor_p4032_intr_string: bogus IRQ %ld", ih);
    537 
    538 	strlcpy(buf, p4032_intrnames[ih], len);
    539 	return buf;
    540 }
    541 
    542 const struct evcnt *
    543 algor_p4032_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
    544 {
    545 
    546 	return (&p4032_intrtab[ih].intr_count);
    547 }
    548 
    549 void *
    550 algor_p4032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
    551     int (*func)(void *), void *arg)
    552 {
    553 
    554 	if (ih >= NPCIIRQS)
    555 		panic("algor_p4032_intr_establish: bogus IRQ %ld", ih);
    556 
    557 	return (algor_p4032_intr_establish(ih, func, arg));
    558 }
    559 
    560 void
    561 algor_p4032_pci_intr_disestablish(void *v, void *cookie)
    562 {
    563 
    564 	return (algor_p4032_intr_disestablish(cookie));
    565 }
    566 
    567 void
    568 algor_p4032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
    569     int *iline)
    570 {
    571 
    572 	/*
    573 	 * We actually don't need to do anything; everything is handled
    574 	 * in pci_intr_map().
    575 	 */
    576 	*iline = 0;
    577 }
    578