diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2010-05-08 21:59:57 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2010-05-08 21:59:57 +0000 |
commit | c60925a8da6f5ba6b3c5a172c87f11377364205e (patch) | |
tree | 95f9bb1dd0b2b987e34b70d89d19f31684265de3 /sys/arch/loongson | |
parent | 82e9f80967a1e3668ead006f748d60ca2293f5b9 (diff) |
Huge work-in-progress commit to support Loongson 2E-based evaluation boards
with a VIA 686 southbridge.
Features:
- 686 setup code (no thanks to PMON for not initializing the beast).
- work in progress ISA interrupt handling code.
- support for vga(4) compatible devices as console, in PC-compatible text mode.
- move legacy (ISA) support code out of bonito(4) to make things clearer.
- support more than 256MB on 2E-based systems.
Tested on a generic 2E-based evaluation board by someone who wishes to remain
anonymous; you know who you are, thank you very much for testing.
Diffstat (limited to 'sys/arch/loongson')
22 files changed, 1430 insertions, 447 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC index 9054d9bf57f..4c829bcd639 100644 --- a/sys/arch/loongson/conf/GENERIC +++ b/sys/arch/loongson/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.21 2010/03/03 20:57:28 mk Exp $ +# $OpenBSD: GENERIC,v 1.22 2010/05/08 21:59:53 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -71,6 +71,15 @@ ohci* at voyager? smfb* at voyager? wsdisplay* at smfb? +# Generic 2E systems (in addition to the Fuloong devices) +pcib* at pci? +isa0 at pcib? +vga* at pci? +wsdisplay* at vga? +auvia* at pci? +audio* at auvia? +viaenv* at pci? + # USB Controllers ohci* at pci? uhci* at pci? diff --git a/sys/arch/loongson/conf/RAMDISK b/sys/arch/loongson/conf/RAMDISK index eea22315c1c..dafdb4dcb40 100644 --- a/sys/arch/loongson/conf/RAMDISK +++ b/sys/arch/loongson/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.11 2010/03/02 20:54:51 miod Exp $ +# $OpenBSD: RAMDISK,v 1.12 2010/05/08 21:59:53 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -75,6 +75,12 @@ ohci* at voyager? smfb* at voyager? wsdisplay* at smfb? +# Generic 2E systems (in addition to the Fuloong devices) +pcib* at pci? +isa0 at pcib? +vga* at pci? +wsdisplay* at vga? + # USB Controllers ohci* at pci? uhci* at pci? diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 0efef75c2bb..1fb209cdc08 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.10 2010/03/03 13:33:27 jasper Exp $ +# $OpenBSD: files.loongson,v 1.11 2010/05/08 21:59:53 miod Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -18,6 +18,8 @@ file arch/loongson/loongson/bus_space.c file arch/loongson/loongson/conf.c file arch/loongson/loongson/disksubr.c disk file arch/loongson/loongson/gdium_machdep.c +file arch/loongson/loongson/generic2e_machdep.c +file arch/loongson/loongson/isa_machdep.c isa file arch/loongson/loongson/loongson2_machdep.c file arch/loongson/loongson/machdep.c file arch/loongson/loongson/mutex.c @@ -36,6 +38,7 @@ include "dev/isa/files.isa" include "dev/isa/files.isapnp" include "dev/mii/files.mii" include "dev/pci/files.pci" +include "dev/pci/files.agp" include "dev/pckbc/files.pckbc" include "dev/usb/files.usb" include "dev/bluetooth/files.bluetooth" @@ -66,7 +69,11 @@ file arch/loongson/dev/glx.c bonito & pci device glxpcib: isabus, gpiobus attach glxpcib at pci file arch/loongson/dev/glxpcib.c glxpcib -file arch/loongson/dev/pcib.c glxpcib + +# Other PCI-ISA bridges +device pcib: isabus +attach pcib at pci +file arch/loongson/dev/pcib.c pcib | glxpcib # Lemote Yeeloong RTC device mcclock diff --git a/sys/arch/loongson/dev/apm.c b/sys/arch/loongson/dev/apm.c index 919c6120e75..e5822bf861e 100644 --- a/sys/arch/loongson/dev/apm.c +++ b/sys/arch/loongson/dev/apm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apm.c,v 1.2 2010/02/28 09:37:28 otto Exp $ */ +/* $OpenBSD: apm.c,v 1.3 2010/05/08 21:59:56 miod Exp $ */ /*- * Copyright (c) 2001 Alexander Guy. All rights reserved. @@ -111,7 +111,12 @@ apmmatch(struct device *parent, void *match, void *aux) { struct mainbus_attach_args *maa = aux; - if (strcmp(maa->maa_name, apm_cd.cd_name) == 0) + /* + * It only makes sense to attach on a 2F system, since 2E do not + * feature speed throttling, and we do not support 2E-based + * notebooks yet (assuming there are any). + */ + if (strcmp(maa->maa_name, apm_cd.cd_name) == 0 && loongson_ver == 0x2f) return (1); return (0); } diff --git a/sys/arch/loongson/dev/bonito.c b/sys/arch/loongson/dev/bonito.c index 58c716b5eed..df9d2b7e211 100644 --- a/sys/arch/loongson/dev/bonito.c +++ b/sys/arch/loongson/dev/bonito.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bonito.c,v 1.13 2010/03/02 20:53:12 miod Exp $ */ +/* $OpenBSD: bonito.c,v 1.14 2010/05/08 21:59:56 miod Exp $ */ /* $NetBSD: bonito_mainbus.c,v 1.11 2008/04/28 20:23:10 martin Exp $ */ /* $NetBSD: bonito_pci.c,v 1.5 2008/04/28 20:23:28 martin Exp $ */ @@ -50,10 +50,6 @@ * PCI configuration space support for the Loongson PCI and memory controller * chip, which is derived from the Algorithmics BONITO chip. */ -/* - * XXX The legacy interrupt scheme is entangled and as many parts as - * XXX possible should move to pcib.c... - */ #include <sys/param.h> #include <sys/systm.h> @@ -61,8 +57,6 @@ #include <sys/extent.h> #include <sys/malloc.h> -#include <mips64/archtype.h> - #include <machine/autoconf.h> #include <machine/bus.h> #include <machine/intr.h> @@ -72,13 +66,12 @@ #include <dev/pci/pcivar.h> #include <dev/pci/ppbreg.h> -#include <dev/isa/isareg.h> -#include <dev/isa/isavar.h> - #include <loongson/dev/bonitoreg.h> #include <loongson/dev/bonitovar.h> #include <loongson/dev/bonito_irq.h> +#include <uvm/uvm_extern.h> + #if 0 #define BONITO_DEBUG #endif @@ -87,8 +80,7 @@ int bonito_match(struct device *, void *, void *); void bonito_attach(struct device *, struct device *, void *); const struct cfattach bonito_ca = { - sizeof(struct bonito_softc), - bonito_match, bonito_attach + sizeof(struct bonito_softc), bonito_match, bonito_attach }; struct cfdriver bonito_cd = { @@ -101,7 +93,9 @@ bus_addr_t bonito_pa_to_device(paddr_t); paddr_t bonito_device_to_pa(bus_addr_t); void bonito_intr_makemasks(void); -uint32_t bonito_intr(uint32_t, struct trap_frame *); +uint32_t bonito_intr_2e(uint32_t, struct trap_frame *); +uint32_t bonito_intr_2f(uint32_t, struct trap_frame *); +void bonito_intr_dispatch(uint64_t, int, struct trap_frame *); void bonito_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); @@ -122,15 +116,6 @@ int bonito_conf_addr(const struct bonito_config *, pcitag_t, int, u_int32_t *, u_int32_t *); void bonito_splx(int); -void bonito_setintrmask(int); - -uint loongson_get_isa_imr(void); -uint loongson_get_isa_isr(void); -void loongson_set_isa_imr(uint); -void loongson_isa_specific_eoi(int); -uint32_t loongson_isa_intr(uint32_t, struct trap_frame *); -void loongson_isa_splx(int); -void loongson_isa_setintrmask(int); /* * Bonito interrupt handling declarations. @@ -140,8 +125,6 @@ struct intrhand *bonito_intrhand[BONITO_NINTS]; uint64_t bonito_intem; uint64_t bonito_imask[NIPLS]; -uint loongson_isaimr; - struct machine_bus_dma_tag bonito_bus_dma_tag = { ._dmamap_create = _dmamap_create, ._dmamap_destroy = _dmamap_destroy, @@ -238,8 +221,7 @@ bonito_attach(struct device *parent, struct device *self, void *aux) * We need to make sure we never try to access an unimplemented * register... */ - if (curcpu()->ci_hw.type == MIPS_LOONGSON2 && - (curcpu()->ci_hw.c0prid & 0xff) == 0x2f - 0x2c) + if (loongson_ver == 0x2f) sc->sc_compatible = 0; else sc->sc_compatible = 1; @@ -324,16 +306,16 @@ bonito_attach(struct device *parent, struct device *self, void *aux) REGVAL(BONITO_INTENCLR) = 0xffffffff; (void)REGVAL(BONITO_INTENCLR); - if (bc->bc_legacy_pic) { - set_intr(INTPRI_BONITO, CR_INT_4, bonito_intr); - set_intr(INTPRI_ISA, CR_INT_0, loongson_isa_intr); - loongson_isaimr = loongson_get_isa_imr(); - register_splx_handler(loongson_isa_splx); - } else { - set_intr(INTPRI_BONITO, CR_INT_4, bonito_intr); - register_splx_handler(bonito_splx); + if (sc->sc_compatible) { + bonito_intem |= BONITO_INTRMASK_MASTERERR; } + if (loongson_ver == 0x2f) + set_intr(INTPRI_BONITO, CR_INT_4, bonito_intr_2f); + else + set_intr(INTPRI_BONITO, CR_INT_0, bonito_intr_2e); + register_splx_handler(bonito_splx); + /* * Attach PCI bus. */ @@ -439,10 +421,45 @@ bonito_intr_establish(int irq, int type, int level, int (*handler)(void *), } void -bonito_intr_disestablish(void *ih) +bonito_intr_disestablish(void *vih) { - /* XXX */ - panic("%s not implemented", __func__); + struct intrhand *ih = (struct intrhand *)vih; + struct intrhand **p, *q; + int irq = ih->ih_irq; + int s; + +#ifdef DIAGNOSTIC + if (irq >= BONITO_NINTS || irq == BONITO_ISA_IRQ(2) || irq < 0) + panic("bonito_intr_disestablish: illegal irq %d", irq); +#endif + + s = splhigh(); + + evcount_detach(&ih->ih_count); + + for (p = &bonito_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + if (q == ih) + break; +#ifdef DIAGNOSTIC + if (q == NULL) + panic("bonito_intr_disestablish: never registered"); +#endif + *p = ih->ih_next; + + if (ih->ih_next == NULL && p == &bonito_intrhand[irq]) { + bonito_intem &= ~(1UL << irq); + bonito_intr_makemasks(); + /* + * No need to clear a bit in INTEN through INTCLR, + * splhigh() took care of disabling everything and + * splx() will not reenable this source after the + * mask update. + */ + } + + splx(s); + + free(ih, M_DEVBUF); } /* @@ -472,17 +489,20 @@ bonito_setintrmask(int level) uint32_t sr; active = bonito_intem & ~bonito_imask[level]; - /* don't bother masking high bits, there are no isa interrupt sources */ - clear = bonito_imask[level]; - set = active; + /* be sure to mask high bits, there may be other interrupt sources */ + clear = BONITO_DIRECT_MASK(bonito_imask[level]); + set = BONITO_DIRECT_MASK(active); sr = disableintr(); - if (clear != 0) + if (clear != 0) { REGVAL(BONITO_INTENCLR) = clear; - if (set != 0) + (void)REGVAL(BONITO_INTENCLR); + } + if (set != 0) { REGVAL(BONITO_INTENSET) = set; - (void)REGVAL(BONITO_INTENSET); + (void)REGVAL(BONITO_INTENSET); + } setsr(sr); } @@ -543,12 +563,66 @@ bonito_intr_makemasks() */ uint32_t -bonito_intr(uint32_t hwpend, struct trap_frame *frame) +bonito_intr_2e(uint32_t hwpend, struct trap_frame *frame) +{ + uint64_t imr, isr, mask; + + isr = REGVAL(BONITO_INTISR); + + /* + * According to Linux code, Bonito64 - at least on Loongson + * systems - triggers an interrupt during DMA, which is to be + * ignored. Smells like a chip errata to me. + */ + while (ISSET(isr, BONITO_INTRMASK_MASTERERR)) { + delay(1); + isr = REGVAL(BONITO_INTISR); + } + + isr &= BONITO_INTRMASK_GPIN; + imr = REGVAL(BONITO_INTEN); + isr &= imr; +#ifdef DEBUG + printf("pci interrupt: imr %04x isr %04x\n", imr, isr); +#endif + if (isr == 0) + return 0; /* not for us */ + + /* + * Mask all pending interrupts. + */ + REGVAL(BONITO_INTENCLR) = isr; + (void)REGVAL(BONITO_INTENCLR); + + /* + * If interrupts are spl-masked, mask them and wait for splx() + * to reenable them when necessary. + */ + if ((mask = isr & bonito_imask[frame->ipl]) != 0) { + isr &= ~mask; + imr &= ~mask; + } + + /* + * Now process allowed interrupts. + */ + if (isr != 0) { + bonito_intr_dispatch(isr, 30, frame); + + /* + * Reenable interrupts which have been serviced. + */ + REGVAL(BONITO_INTENSET) = imr; + (void)REGVAL(BONITO_INTENSET); + } + + return hwpend; +} + +uint32_t +bonito_intr_2f(uint32_t hwpend, struct trap_frame *frame) { uint64_t imr, isr, mask; - int bit; - struct intrhand *ih; - int rc; isr = REGVAL(BONITO_INTISR) & LOONGSON_INTRMASK_LVL4; imr = REGVAL(BONITO_INTEN); @@ -578,39 +652,9 @@ bonito_intr(uint32_t hwpend, struct trap_frame *frame) * Now process allowed interrupts. */ if (isr != 0) { - int lvl, bitno; - uint64_t tmpisr; - - /* Service higher level interrupts first */ - bit = LOONGSON_INTR_DRAM_PARERR; /* skip non-pci interrupts */ - for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) { - tmpisr = isr & (bonito_imask[lvl] ^ bonito_imask[lvl - 1]); - if (tmpisr == 0) - continue; - for (bitno = bit, mask = 1UL << bitno; mask != 0; - bitno--, mask >>= 1) { - if ((tmpisr & mask) == 0) - continue; - - rc = 0; - for (ih = bonito_intrhand[bitno]; ih != NULL; - ih = ih->ih_next) { - if ((*ih->ih_fun)(ih->ih_arg) != 0) { - rc = 1; - ih->ih_count.ec_count++; - } - } - if (rc == 0) - printf("spurious interrupt %d\n", - bitno); - - if ((isr ^= mask) == 0) - goto done; - if ((tmpisr ^= mask) == 0) - break; - } - } -done: + bonito_intr_dispatch(isr, + LOONGSON_INTR_DRAM_PARERR /* skip non-pci interrupts */, + frame); /* * Reenable interrupts which have been serviced. @@ -622,6 +666,56 @@ done: return hwpend; } +void +bonito_intr_dispatch(uint64_t isr, int startbit, struct trap_frame *frame) +{ + int lvl, bitno; + uint64_t tmpisr, mask; + struct intrhand *ih; + int rc; + + /* Service higher level interrupts first */ + for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) { + tmpisr = isr & (bonito_imask[lvl] ^ bonito_imask[lvl - 1]); + if (tmpisr == 0) + continue; + for (bitno = startbit, mask = 1UL << bitno; mask != 0; + bitno--, mask >>= 1) { + if ((tmpisr & mask) == 0) + continue; + + rc = 0; + for (ih = bonito_intrhand[bitno]; ih != NULL; + ih = ih->ih_next) { + splraise(ih->ih_level); + if ((*ih->ih_fun)(ih->ih_arg) != 0) { + rc = 1; + ih->ih_count.ec_count++; + } + __asm__ (".set noreorder\n"); + curcpu()->ci_ipl = frame->ipl; + __asm__ ("sync\n\t.set reorder\n"); + } + if (rc == 0) { + printf("spurious interrupt %d\n", bitno); +#ifdef DEBUG + printf("ISR %08x IMR %08x ipl %d mask %08x\n", + REGVAL(BONITO_INTISR), REGVAL(BONITO_INTEN), + frame->ipl, bonito_imask[frame->ipl]); +#ifdef DDB + Debugger(); +#endif +#endif + } + + if ((isr ^= mask) == 0) + return; + if ((tmpisr ^= mask) == 0) + break; + } + } +} + /* * various PCI helpers */ @@ -832,7 +926,7 @@ bonito_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) const struct bonito_config *bc = sc->sc_bonito; int bus, dev, fn, pin; - *ihp = -1; + *ihp = (pci_intr_handle_t)-1; if (pa->pa_intrpin == 0) /* no interrupt needed */ return 1; @@ -852,7 +946,7 @@ bonito_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) if (bus == 0) *ihp = (*bc->bc_intr_map)(dev, fn, pa->pa_intrpin); - if (*ihp < 0) + if (*ihp == (pci_intr_handle_t)-1) return 1; } @@ -866,7 +960,7 @@ bonito_pci_intr_string(void *cookie, pci_intr_handle_t ih) if (BONITO_IRQ_IS_ISA(ih)) snprintf(irqstr, sizeof irqstr, "isa irq %d", - ih - BONITO_NDIRECT); + BONITO_IRQ_TO_ISA(ih)); else snprintf(irqstr, sizeof irqstr, "irq %d", ih); return irqstr; @@ -886,230 +980,9 @@ bonito_pci_intr_disestablish(void *cookie, void *ihp) } /* - * Legacy (ISA) interrupt handling - */ - -/* - * Process legacy interrupts. - * - * XXX ISA interrupts only occur on LOONGSON_INTR_INT0, but since the other - * XXX LOONGSON_INTR_INT# are unmaskable, bad things will happen if they - * XXX are triggered... - */ - -/* - * Interrupt dispatcher. - */ -uint32_t -loongson_isa_intr(uint32_t hwpend, struct trap_frame *frame) -{ - uint64_t imr, isr, mask; - int bit; - struct intrhand *ih; - int rc; - - isr = loongson_get_isa_isr(); - imr = loongson_get_isa_imr(); - - isr &= imr; - isr &= ~(1 << 2); /* cascade */ -#ifdef DEBUG - printf("isa interrupt: imr %04x isr %04x\n", imr, isr); -#endif - if (isr == 0) - return 0; /* not for us */ - - /* - * Mask all pending interrupts. - */ - - loongson_set_isa_imr(imr & ~isr); - - /* - * If interrupts are spl-masked, mask them and wait for splx() - * to reenable them when necessary. - */ - if ((mask = isr & (BONITO_ISA_MASK(bonito_imask[frame->ipl]))) != 0) { - isr &= ~mask; - imr &= ~mask; - } - - /* - * Now process allowed interrupts. - */ - if (isr != 0) { - int lvl, bitno; - uint64_t tmpisr; - - /* Service higher level interrupts first */ - bit = BONITO_NISA - 1; - for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) { - tmpisr = isr & BONITO_ISA_MASK(bonito_imask[lvl] ^ - bonito_imask[lvl - 1]); - if (tmpisr == 0) - continue; - for (bitno = bit, mask = 1UL << bitno; mask != 0; - bitno--, mask >>= 1) { - if ((tmpisr & mask) == 0) - continue; - - rc = 0; - for (ih = bonito_intrhand[BONITO_ISA_IRQ(bitno)]; - ih != NULL; ih = ih->ih_next) { - if ((*ih->ih_fun)(ih->ih_arg) != 0) { - rc = 1; - ih->ih_count.ec_count++; - } - } - if (rc == 0) - printf("spurious isa interrupt %d\n", - bitno); - - loongson_isa_specific_eoi(bitno); - - if ((isr ^= mask) == 0) - goto done; - if ((tmpisr ^= mask) == 0) - break; - } - } -done: - - /* - * Reenable interrupts which have been serviced. - */ - loongson_set_isa_imr(imr); - } - - return hwpend; -} - -#define REGVAL8(x) *((volatile u_int8_t *)PHYS_TO_XKPHYS(x, CCA_NC)) - -uint -loongson_get_isa_imr() -{ - uint imr1, imr2; - - imr1 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1); - imr1 &= ~(1 << 2); /* hide cascade */ - imr2 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1); - - return (imr2 << 8) | imr1; -} - -uint -loongson_get_isa_isr() -{ - uint isr1, isr2; - - isr1 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU1); - isr2 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU2); - - return (isr2 << 8) | isr1; -} - -void -loongson_set_isa_imr(uint newimr) -{ - uint imr1, imr2; - - imr1 = 0xff & ~newimr; - imr1 &= ~(1 << 2); /* enable cascade */ - imr2 = 0xff & ~(newimr >> 8); - - /* - * For some reason, trying to write the same value to the PIC - * registers causes an immediate system freeze, so we only do - * this if the value changes. - * Note that interrupts have been disabled by the caller. - */ - if ((newimr ^ loongson_isaimr) & 0xff00) { - REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) = imr2; - (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1); - } - if ((newimr ^ loongson_isaimr) & 0x00ff) { - REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1) = imr1; - (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1); - } - loongson_isaimr = newimr; -} - -void -loongson_isa_specific_eoi(int bit) -{ - if (bit & 8) { - REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 0) = 0x60 | (bit & 7); - (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 0); - bit = 2; - } - REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 0) = 0x60 | bit; - (void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 0); -} - -/* - * Update interrupt masks. This is for designs with legacy PIC. + * bus_space mapping routines. */ -void -loongson_isa_splx(int newipl) -{ - struct cpu_info *ci = curcpu(); - - /* Update masks to new ipl. Order highly important! */ - __asm__ (".set noreorder\n"); - ci->ci_ipl = newipl; - __asm__ ("sync\n\t.set reorder\n"); - loongson_isa_setintrmask(newipl); - /* If we still have softints pending trigger processing. */ - if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT) - setsoftintr0(); -} - -void -loongson_isa_setintrmask(int level) -{ - uint64_t active; - uint32_t clear, set; - uint32_t sr; - - active = bonito_intem & ~bonito_imask[level]; - clear = BONITO_DIRECT_MASK(bonito_imask[level]); - set = BONITO_DIRECT_MASK(active); - - sr = disableintr(); - - if (clear != 0) - REGVAL(BONITO_INTENCLR) = clear; - if (set != 0) - REGVAL(BONITO_INTENSET) = set; - (void)REGVAL(BONITO_INTENSET); - - loongson_set_isa_imr(BONITO_ISA_MASK(active)); - - setsr(sr); -} - -void -isa_attach_hook(struct device *parent, struct device *self, - struct isabus_attach_args *iba) -{ -} - -void * -isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level, - int (*handler)(void *), void *arg, char *name) -{ - return bonito_intr_establish(BONITO_ISA_IRQ(irq), type, level, - handler, arg, name); -} - -void -isa_intr_disestablish(void *v, void *ih) -{ - bonito_intr_disestablish(ih); -} - /* * Legacy I/O access protection. * Since MI ISA code does not expect bus access to cause any failure when @@ -1129,7 +1002,7 @@ bonito_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, if (offs >= r->start && offs + size <= r->end) break; - if (r->start == 0) + if (r->end == 0) return ENXIO; } @@ -1154,36 +1027,35 @@ bonito_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, bus_addr_t pcilo_w[3]; bus_addr_t ws, we, w; bus_addr_t end = offs + size - 1; - int is2f, pcilo_window; + int pcilo_window; /* * Try a PCIHI mapping first. */ - /* may be used before curcpu() points to valid data */ - if ((cp0_get_prid() & 0xffff) == - ((MIPS_LOONGSON2 << 8) | (0x2f - 0x2c))) - is2f = 1; - else - is2f = 0; - - if (is2f) { + if (loongson_ver == 0x2f) { if (offs >= LS2F_PCIHI_BASE && end <= LS2F_PCIHI_TOP) { *bshp = t->bus_base + offs; return 0; } } else { - /* PCI1.5 */ - if (offs >= BONITO_PCIHI_BASE && end <= BONITO_PCIHI_TOP) { - *bshp = t->bus_base + offs; - return 0; - } + /* + * Only try HI space if we do not have memory setup there. + */ + if (physmem <= atop(BONITO_PCILO_BASE)) { + /* PCI1.5 */ + if (offs >= BONITO_PCIHI_BASE && + end <= BONITO_PCIHI_TOP) { + *bshp = t->bus_base + offs; + return 0; + } - /* PCI2 */ - w = pcimap & BONITO_PCIMAP_PCIMAP_2 ? 0x80000000UL : 0; - if (offs >= w && end < (w + 0x80000000UL)) { - *bshp = t->bus_base + 0x80000000UL + (offs - w); - return 0; + /* PCI2 */ + w = pcimap & BONITO_PCIMAP_PCIMAP_2 ? 0x80000000UL : 0; + if (offs >= w && end < (w + 0x80000000UL)) { + *bshp = t->bus_base + 0x80000000UL + (offs - w); + return 0; + } } } diff --git a/sys/arch/loongson/dev/bonito_irq.h b/sys/arch/loongson/dev/bonito_irq.h index 667a2b991ac..43dcd347d59 100644 --- a/sys/arch/loongson/dev/bonito_irq.h +++ b/sys/arch/loongson/dev/bonito_irq.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bonito_irq.h,v 1.1 2010/02/05 20:51:22 miod Exp $ */ +/* $OpenBSD: bonito_irq.h,v 1.2 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -20,6 +20,10 @@ * Bonito interrupt assignments */ +/* + * Loongson 2F assignments + */ + #define LOONGSON_INTR_GPIO0 0 #define LOONGSON_INTR_GPIO1 1 #define LOONGSON_INTR_GPIO2 2 @@ -68,25 +72,51 @@ #define LOONGSON_INTRMASK_LVL4 0x000007ff /* + * Loongson 2E (Bonito64) assignments + */ + +#define BONITO_INTRMASK_MBOX 0x0000000f +#define BONITO_INTR_MBOX 0 +#define BONITO_INTRMASK_DMARDY 0x00000010 +#define BONITO_INTRMASK_DMAEMPTY 0x00000020 +#define BONITO_INTRMASK_COPYRDY 0x00000040 +#define BONITO_INTRMASK_COPYEMPTY 0x00000080 +#define BONITO_INTRMASK_COPYERR 0x00000100 +#define BONITO_INTRMASK_PCIIRQ 0x00000200 +#define BONITO_INTRMASK_MASTERERR 0x00000400 +#define BONITO_INTRMASK_SYSTEMERR 0x00000800 +#define BONITO_INTRMASK_DRAMPERR 0x00001000 +#define BONITO_INTRMASK_RETRYERR 0x00002000 +#define BONITO_INTRMASK_GPIO 0x01ff0000 +#define BONITO_INTR_GPIO 16 +#define BONITO_INTRMASK_GPIN 0x7e000000 +#define BONITO_INTR_GPIN 25 + +/* * Bonito interrupt handling recipes: - * - we have 14 interrupts on Bonito - * - on the Yeeloong, there are also 16 (well, 15) ISA interrupts with the + * - we have up to 32 interrupts at the Bonito level. + * - systems with ISA devices also have 16 (well, 15) ISA interrupts with the * usual 8259 pair. Bonito and ISA interrupts happen on two different levels. * - * For simplicity we allocate 16 vectors for direct interrupts, and 16 - * vectors for ISA interrupts as well (which will only be used if we are - * running on a Yeeloong). + * These arbitrary values may be changed as long as interrupt mask variables + * use large enough integer types and always use the following macros to + * handle interrupt masks. */ #define INTPRI_BONITO (INTPRI_CLOCK + 1) #define INTPRI_ISA (INTPRI_BONITO + 1) -#define BONITO_NDIRECT 16 +#define BONITO_NDIRECT 32 #define BONITO_NISA 16 #define BONITO_NINTS (BONITO_NDIRECT + BONITO_NISA) #define BONITO_ISA_IRQ(i) ((i) + BONITO_NDIRECT) #define BONITO_DIRECT_IRQ(i) (i) #define BONITO_IRQ_IS_ISA(i) ((i) >= BONITO_NDIRECT) +#define BONITO_IRQ_TO_ISA(i) ((i) - BONITO_NDIRECT) -#define BONITO_DIRECT_MASK(imask) ((imask) & ((1 << BONITO_NDIRECT) - 1)) +#define BONITO_DIRECT_MASK(imask) ((imask) & ((1L << BONITO_NDIRECT) - 1)) #define BONITO_ISA_MASK(imask) ((imask) >> BONITO_NDIRECT) + +extern struct intrhand *bonito_intrhand[BONITO_NINTS]; +extern uint64_t bonito_intem; +extern uint64_t bonito_imask[NIPLS]; diff --git a/sys/arch/loongson/dev/bonitoreg.h b/sys/arch/loongson/dev/bonitoreg.h index d542523f9d5..26c0a4ba09a 100644 --- a/sys/arch/loongson/dev/bonitoreg.h +++ b/sys/arch/loongson/dev/bonitoreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bonitoreg.h,v 1.6 2010/02/28 21:35:41 miod Exp $ */ +/* $OpenBSD: bonitoreg.h,v 1.7 2010/05/08 21:59:56 miod Exp $ */ /* $NetBSD: bonitoreg.h,v 1.6 2005/12/24 20:07:19 perry Exp $ */ /* @@ -33,6 +33,7 @@ #define BONITO(x) (BONITO_REG_BASE + (x)) #define REGVAL(x) *((volatile u_int32_t *)PHYS_TO_XKPHYS(x, CCA_NC)) +#define REGVAL8(x) *((volatile u_int8_t *)PHYS_TO_XKPHYS(x, CCA_NC)) #define BONITO_FLASH_BASE 0x1c000000UL #define BONITO_FLASH_SIZE 0x02000000UL @@ -139,7 +140,9 @@ /* gencfg */ -#define BONITO_GENCFG_OV_EN 0x00000001 /* video accel enable */ +#define LOONGSON_GENCFG_OV_EN 0x00000001 /* video accel enable */ + +#define BONITO_GENCFG_CPUSELFRESET 0x00000004 /* reset system */ /* pcimap */ diff --git a/sys/arch/loongson/dev/bonitovar.h b/sys/arch/loongson/dev/bonitovar.h index 1d181be1c77..82147f180ac 100644 --- a/sys/arch/loongson/dev/bonitovar.h +++ b/sys/arch/loongson/dev/bonitovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bonitovar.h,v 1.4 2010/02/12 08:14:02 miod Exp $ */ +/* $OpenBSD: bonitovar.h,v 1.5 2010/05/08 21:59:56 miod Exp $ */ /* $NetBSD: bonitovar.h,v 1.4 2008/04/28 20:23:28 martin Exp $ */ /*- @@ -33,8 +33,6 @@ #ifndef _LOONGSON_DEV_BONITOVAR_H_ #define _LOONGSON_DEV_BONITOVAR_H_ -#include <dev/pci/pcivar.h> - struct bonito_cfg_hook; struct extent; @@ -47,8 +45,6 @@ struct bonito_config { uint32_t bc_intSteer; uint32_t bc_intPol; - int bc_legacy_pic; /* nonzero if legacy PIC */ - /* PCI Attach hook for the first bus */ void (*bc_attach_hook)(pci_chipset_tag_t); @@ -76,6 +72,7 @@ int bonito_pci_hook(pci_chipset_tag_t, void *, int bonito_print(void *, const char *); struct extent *bonito_get_resource_extent(pci_chipset_tag_t, int); +void bonito_setintrmask(int); #endif /* _KERNEL */ #endif /* _LOONGSON_DEV_BONITOVAR_H_ */ diff --git a/sys/arch/loongson/dev/glxpcib.c b/sys/arch/loongson/dev/glxpcib.c index a11de01827d..9b7d3bdeaf3 100644 --- a/sys/arch/loongson/dev/glxpcib.c +++ b/sys/arch/loongson/dev/glxpcib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: glxpcib.c,v 1.5 2010/04/21 03:03:26 deraadt Exp $ */ +/* $OpenBSD: glxpcib.c,v 1.6 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> @@ -171,8 +171,10 @@ int glxpcib_match(struct device *parent, void *match, void *aux) { if (pci_matchbyid((struct pci_attach_args *)aux, glxpcib_devices, - sizeof(glxpcib_devices) / sizeof(glxpcib_devices[0]))) + nitems(glxpcib_devices))) { + /* needs to win over pcib */ return 2; + } return 0; } diff --git a/sys/arch/loongson/dev/kb3310.c b/sys/arch/loongson/dev/kb3310.c index 2749bb4648f..ef3d4c10e1c 100644 --- a/sys/arch/loongson/dev/kb3310.c +++ b/sys/arch/loongson/dev/kb3310.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kb3310.c,v 1.9 2010/03/02 17:49:38 otto Exp $ */ +/* $OpenBSD: kb3310.c,v 1.10 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2010 Otto Moerbeek <otto@drijf.net> * @@ -22,7 +22,9 @@ #include <sys/sensors.h> #include <sys/timeout.h> +#include <mips64/archtype.h> #include <machine/apmvar.h> +#include <machine/autoconf.h> #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -114,6 +116,9 @@ ykbec_match(struct device *parent, void *match, void *aux) struct isa_attach_args *ia = aux; bus_space_handle_t ioh; + if (sys_platform->system_type != LOONGSON_YEELOONG) + return (0); + if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_YKBEC) || /* (ia->ia_iosize != 0 && ia->ia_iosize != IO_YKBECSIZE) || XXX isa.c */ ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || diff --git a/sys/arch/loongson/dev/pcib.c b/sys/arch/loongson/dev/pcib.c index 82707b43219..f6a2b72e8f2 100644 --- a/sys/arch/loongson/dev/pcib.c +++ b/sys/arch/loongson/dev/pcib.c @@ -1,29 +1,44 @@ -/* $OpenBSD: pcib.c,v 1.1 2009/12/25 21:04:34 miod Exp $ */ +/* $OpenBSD: pcib.c,v 1.2 2010/05/08 21:59:56 miod Exp $ */ -/* - * Copyright (c) 2009 Miodrag Vallat. +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <machine/autoconf.h> #include <machine/bus.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> #include <dev/isa/isavar.h> @@ -32,30 +47,104 @@ #include "isa.h" +int pcibmatch(struct device *, void *, void *); void pcibattach(struct device *, struct device *, void *); +void pcib_callback(struct device *); int pcib_print(void *, const char *); +struct pcib_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; + bus_dma_tag_t sc_dmat; +}; + +const struct cfattach pcib_ca = { + sizeof(struct pcib_softc), pcibmatch, pcibattach +}; + +struct cfdriver pcib_cd = { + NULL, "pcib", DV_DULL +}; + +int +pcibmatch(struct device *parent, void *match, void *aux) +{ + struct pci_attach_args *pa = aux; + + switch (PCI_VENDOR(pa->pa_id)) { + case PCI_VENDOR_INTEL: + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_INTEL_SIO: + case PCI_PRODUCT_INTEL_82371MX: + case PCI_PRODUCT_INTEL_82371AB_ISA: + case PCI_PRODUCT_INTEL_82440MX_ISA: + /* The above bridges mis-identify themselves */ + return (1); + } + break; + case PCI_VENDOR_SIS: + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_SIS_85C503: + /* mis-identifies itself as a miscellaneous prehistoric */ + return (1); + } + break; + case PCI_VENDOR_VIATECH: + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_VIATECH_VT82C686A_SMB: + /* mis-identifies itself as a ISA bridge */ + return (0); + } + break; + } + + if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && + PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) + return (1); + + return (0); +} + void pcibattach(struct device *parent, struct device *self, void *aux) { - struct pci_attach_args *pa = aux; - struct isabus_attach_args iba; + struct pcib_softc *sc = (struct pcib_softc *)self; + struct pci_attach_args *pa = (struct pci_attach_args *)aux; printf("\n"); /* + * Wait until all PCI devices are attached before attaching isa; + * otherwise this might mess the interrupt setup on some systems. + */ + sc->sc_iot = pa->pa_iot; + sc->sc_memt = pa->pa_memt; + sc->sc_dmat = pa->pa_dmat; + config_defer(self, pcib_callback); +} + +void +pcib_callback(struct device *self) +{ + struct pcib_softc *sc = (struct pcib_softc *)self; + struct isabus_attach_args iba; + + /* * Attach the ISA bus behind this bridge. * Note that, since we only have a few legacy I/O devices and * no ISA slots, we can attach immediately. */ memset(&iba, 0, sizeof(iba)); iba.iba_busname = "isa"; - iba.iba_iot = pa->pa_iot; - iba.iba_memt = pa->pa_memt; + iba.iba_iot = sc->sc_iot; + iba.iba_memt = sc->sc_memt; #if NISADMA > 0 - iba.iba_dmat = pa->pa_dmat; + iba.iba_dmat = sc->sc_dmat; #endif - config_found(self, &iba, pcib_print); + iba.iba_ic = sys_platform->isa_chipset; + if (iba.iba_ic != NULL) + config_found(self, &iba, pcib_print); } int diff --git a/sys/arch/loongson/include/autoconf.h b/sys/arch/loongson/include/autoconf.h index f4b61339d84..0a347e49020 100644 --- a/sys/arch/loongson/include/autoconf.h +++ b/sys/arch/loongson/include/autoconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.h,v 1.6 2010/02/16 21:31:35 miod Exp $ */ +/* $OpenBSD: autoconf.h,v 1.7 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -36,6 +36,7 @@ #include <machine/bus.h> struct bonito_config; +struct mips_isa_chipset; /* * List of legacy I/O ranges. @@ -54,6 +55,7 @@ struct platform { char *product; const struct bonito_config *bonito_config; + struct mips_isa_chipset *isa_chipset; const struct legacy_io_range *legacy_io_ranges; void (*setup)(void); @@ -65,6 +67,7 @@ struct platform { }; extern const struct platform *sys_platform; +extern uint loongson_ver; struct mainbus_attach_args { const char *maa_name; diff --git a/sys/arch/loongson/include/bus.h b/sys/arch/loongson/include/bus.h index 49b347af863..d9f15ef1ac3 100644 --- a/sys/arch/loongson/include/bus.h +++ b/sys/arch/loongson/include/bus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bus.h,v 1.2 2010/04/04 11:24:27 miod Exp $ */ +/* $OpenBSD: bus.h,v 1.3 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB Sweden. All rights reserved. @@ -43,7 +43,6 @@ typedef u_long bus_addr_t; typedef u_long bus_size_t; typedef u_long bus_space_handle_t; typedef struct mips_bus_space *bus_space_tag_t; -typedef struct mips_bus_space bus_space_t; struct mips_bus_space { bus_addr_t bus_base; diff --git a/sys/arch/loongson/include/isa_machdep.h b/sys/arch/loongson/include/isa_machdep.h index 0f2e25023ef..9bfaa58d01e 100644 --- a/sys/arch/loongson/include/isa_machdep.h +++ b/sys/arch/loongson/include/isa_machdep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: isa_machdep.h,v 1.1 2009/11/25 19:44:27 miod Exp $ */ +/* $OpenBSD: isa_machdep.h,v 1.2 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2007 Miodrag Vallat. @@ -24,12 +24,28 @@ #define __NO_ISA_INTR_CHECK -typedef void *isa_chipset_tag_t; +typedef struct mips_isa_chipset *isa_chipset_tag_t; -void isa_attach_hook(struct device *, struct device *, +struct mips_isa_chipset { + void *ic_v; + + void (*ic_attach_hook)(struct device *, struct device *, + struct isabus_attach_args *); + void *(*ic_intr_establish)(void *, int, int, int, int (*)(void *), + void *, char *); + void (*ic_intr_disestablish)(void *, void *); +}; + +#define isa_attach_hook(p, s, iba) \ + (*(iba)->iba_ic->ic_attach_hook)((p), (s), (iba)) +#define isa_intr_establish(c, i, t, l, f, a, n) \ + (*(c)->ic_intr_establish)((c)->ic_v, (i), (t), (l), (f), (a), (n)) +#define isa_intr_disestablish(c, h) \ + (*(c)->ic_intr_disestablish)((c)->ic_v, (h)) + +void loongson_generic_isa_attach_hook(struct device *, struct device *, struct isabus_attach_args *); -void *isa_intr_establish(void *, int, int, int, int (*)(void *), void *, - char *); -void isa_intr_disestablish(void *, void *); +void loongson_isa_specific_eoi(int); +void loongson_set_isa_imr(uint); #endif diff --git a/sys/arch/loongson/loongson/gdium_machdep.c b/sys/arch/loongson/loongson/gdium_machdep.c index acde4ca1ea7..05274690f3c 100644 --- a/sys/arch/loongson/loongson/gdium_machdep.c +++ b/sys/arch/loongson/loongson/gdium_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdium_machdep.c,v 1.5 2010/02/16 21:31:36 miod Exp $ */ +/* $OpenBSD: gdium_machdep.c,v 1.6 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. @@ -28,6 +28,7 @@ #include <machine/autoconf.h> #include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> #include <loongson/dev/bonitoreg.h> @@ -52,8 +53,6 @@ const struct bonito_config gdium_bonito = { .bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR | LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR, - .bc_legacy_pic = 0, - .bc_attach_hook = gdium_attach_hook, .bc_intr_map = gdium_intr_map }; @@ -64,6 +63,7 @@ const struct platform gdium_platform = { .product = "Gdium", .bonito_config = &gdium_bonito, + .isa_chipset = NULL, .legacy_io_ranges = NULL, .setup = NULL, diff --git a/sys/arch/loongson/loongson/generic2e_machdep.c b/sys/arch/loongson/loongson/generic2e_machdep.c new file mode 100644 index 00000000000..e08ccb1b260 --- /dev/null +++ b/sys/arch/loongson/loongson/generic2e_machdep.c @@ -0,0 +1,586 @@ +/* $OpenBSD: generic2e_machdep.c,v 1.1 2010/05/08 21:59:56 miod Exp $ */ + +/* + * Copyright (c) 2010 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/*- + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Generic Loongson 2E code and configuration data. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <mips64/archtype.h> +#include <machine/autoconf.h> +#include <machine/pmon.h> + +#include <dev/ic/i8259reg.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <loongson/dev/bonitoreg.h> +#include <loongson/dev/bonitovar.h> +#include <loongson/dev/bonito_irq.h> + +#include "com.h" + +#if NCOM > 0 +#include <sys/termios.h> +#include <dev/ic/comvar.h> +extern struct mips_bus_space bonito_pci_io_space_tag; +#endif + +void generic2e_device_register(struct device *, void *); +void generic2e_reset(void); + +void generic2e_setup(void); + +void generic2e_pci_attach_hook(pci_chipset_tag_t); +int generic2e_intr_map(int, int, int); + +void generic2e_isa_attach_hook(struct device *, struct device *, + struct isabus_attach_args *); +void *generic2e_isa_intr_establish(void *, int, int, int, int (*)(void *), + void *, char *); +void generic2e_isa_intr_disestablish(void *, void *); + +uint32_t generic2e_isa_intr(uint32_t, struct trap_frame *); + +void via686sb_setup(pci_chipset_tag_t, int); + +/* PnP IRQ assignment for VIA686 SuperIO components */ +#define VIA686_IRQ_PCIA 9 +#define VIA686_IRQ_PCIB 10 +#define VIA686_IRQ_PCIC 11 +#define VIA686_IRQ_PCID 13 + +static int generic2e_via686sb_dev = -1; + +const struct bonito_config generic2e_bonito = { + .bc_adbase = 11, + + .bc_gpioIE = 0xffffffff, + .bc_intEdge = BONITO_INTRMASK_SYSTEMERR | BONITO_INTRMASK_MASTERERR | + BONITO_INTRMASK_RETRYERR | BONITO_INTRMASK_MBOX, + .bc_intSteer = 0, + .bc_intPol = 0, + + .bc_attach_hook = generic2e_pci_attach_hook, + .bc_intr_map = generic2e_intr_map +}; + +const struct legacy_io_range generic2e_legacy_ranges[] = { + /* no isa space access restrictions */ + { 0, BONITO_PCIIO_LEGACY }, + + { 0 } +}; + +struct mips_isa_chipset generic2e_isa_chipset = { + .ic_v = NULL, + + .ic_attach_hook = generic2e_isa_attach_hook, + .ic_intr_establish = generic2e_isa_intr_establish, + .ic_intr_disestablish = generic2e_isa_intr_disestablish +}; + +const struct platform generic2e_platform = { + .system_type = LOONGSON_2E, + .vendor = "Generic", + .product = "Loongson2E", + + .bonito_config = &generic2e_bonito, + .isa_chipset = &generic2e_isa_chipset, + .legacy_io_ranges = generic2e_legacy_ranges, + + .setup = generic2e_setup, + .device_register = generic2e_device_register, + + .powerdown = NULL, + .reset = generic2e_reset +}; + +/* + * PCI model specific routines + */ + +void +generic2e_pci_attach_hook(pci_chipset_tag_t pc) +{ + pcireg_t id; + pcitag_t tag; + int dev; + + /* + * Check for a VIA 686 southbridge; if one is found, remember + * its location, needed by generic2e_intr_map(). + */ + + for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) { + tag = pci_make_tag(pc, 0, dev, 0); + id = pci_conf_read(pc, tag, PCI_ID_REG); + if (id == PCI_ID_CODE(PCI_VENDOR_VIATECH, + PCI_PRODUCT_VIATECH_VT82C686A_ISA)) { + generic2e_via686sb_dev = dev; + break; + } + } + + if (generic2e_via686sb_dev != 0) + via686sb_setup(pc, generic2e_via686sb_dev); +} + +int +generic2e_intr_map(int dev, int fn, int pin) +{ + if (dev == generic2e_via686sb_dev) { + switch (fn) { + case 1: /* PCIIDE */ + /* will use compat interrupt */ + break; + case 2: /* USB */ + return BONITO_ISA_IRQ(VIA686_IRQ_PCIB); + case 3: /* USB */ + return BONITO_ISA_IRQ(VIA686_IRQ_PCIC); + case 4: /* power management, SMBus */ + break; + case 5: /* Audio */ + return BONITO_ISA_IRQ(VIA686_IRQ_PCIA); + case 6: /* Modem */ + break; + default: + break; + } + } else { + return BONITO_DIRECT_IRQ(BONITO_INTR_GPIN + + pin - PCI_INTERRUPT_PIN_A); + } + + return -1; +} + +/* + * ISA model specific routines + */ + +void +generic2e_isa_attach_hook(struct device *parent, struct device *self, + struct isabus_attach_args *iba) +{ + set_intr(INTPRI_ISA, CR_INT_3, generic2e_isa_intr); + loongson_generic_isa_attach_hook(parent, self, iba); +} + +void * +generic2e_isa_intr_establish(void *v, int irq, int type, int level, + int (*handler)(void *), void *arg, char *name) +{ + /* XXX check type, update elcr */ + return bonito_intr_establish(BONITO_ISA_IRQ(irq), type, level, + handler, arg, name); +} + +void +generic2e_isa_intr_disestablish(void *v, void *ih) +{ + /* XXX update elcr */ + bonito_intr_disestablish(ih); +} + +uint32_t +generic2e_isa_intr(uint32_t hwpend, struct trap_frame *frame) +{ + struct intrhand *ih; + uint64_t isr, mask = 0; + int rc, irq; + uint8_t ocw1, ocw2; + extern uint loongson_isaimr; + + for (;;) { + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = + OCW3_SELECT | OCW3_POLL; + ocw1 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3); + if ((ocw1 & OCW3_POLL_PENDING) == 0) + break; + + irq = OCW3_POLL_IRQ(ocw1); + + if (irq == 2) /* cascade */ { + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = + OCW3_SELECT | OCW3_POLL; + ocw2 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3); + if (ocw2 & OCW3_POLL_PENDING) + irq = OCW3_POLL_IRQ(ocw2); + else + irq = 2; + } else + ocw2 = 0; + + /* + * Mask the interrupt before servicing it. + */ + isr = 1UL << irq; + loongson_set_isa_imr(loongson_isaimr & ~isr); + + /* + * If interrupt is spl-masked, wait for splx() + * to reenable it when necessary. + */ + if ((isr & BONITO_ISA_MASK(bonito_imask[frame->ipl])) != 0) + continue; + else + mask |= isr; + + rc = 0; + for (ih = bonito_intrhand[BONITO_ISA_IRQ(irq)]; ih != NULL; + ih = ih->ih_next) { + splraise(ih->ih_level); + + if ((*ih->ih_fun)(ih->ih_arg) != 0) { + rc = 1; + ih->ih_count.ec_count++; + } + + __asm__ (".set noreorder\n"); + curcpu()->ci_ipl = frame->ipl; + __asm__ ("sync\n\t.set reorder\n"); + } + + /* Send a specific EOI to the 8259. */ + loongson_isa_specific_eoi(irq); + + if (rc == 0) { + printf("spurious isa interrupt %d\n", irq); +#ifdef DEBUG + printf("ICU1 %02x ICU2 %02x ipl %d mask %08x" + " isaimr %08x\n", ocw1, ocw2, frame->ipl, + bonito_imask[frame->ipl], loongson_isaimr); +#ifdef DDB + Debugger(); +#endif +#endif + } + } + + /* + * Reenable interrupts which have been serviced. + */ + if (mask != 0) + loongson_set_isa_imr(loongson_isaimr | mask); + + return mask == 0 ? 0 : hwpend; +} + +/* + * Other model specific routines + */ + +void +generic2e_reset() +{ + REGVAL(LOONGSON_GENCFG) &= ~BONITO_GENCFG_CPUSELFRESET; + REGVAL(LOONGSON_GENCFG) |= BONITO_GENCFG_CPUSELFRESET; + delay(1000000); +} + +void +generic2e_setup(void) +{ +#if NCOM > 0 + const char *envvar; + int serial; + + envvar = pmon_getenv("nokbd"); + serial = envvar != NULL; + envvar = pmon_getenv("novga"); + serial = serial && envvar != NULL; + + if (serial) { + comconsiot = &bonito_pci_io_space_tag; + comconsaddr = 0x3f8; + comconsrate = 115200; /* default PMON console speed */ + } +#endif +} + +void +generic2e_device_register(struct device *dev, void *aux) +{ + const char *drvrname = dev->dv_cfdata->cf_driver->cd_name; + const char *name = dev->dv_xname; + + if (dev->dv_class != bootdev_class) + return; + + /* + * The device numbering must match. There's no way + * pmon tells us more info. Depending on the usb slot + * and hubs used you may be lucky. Also, assume umass/sd for usb + * attached devices. + */ + switch (bootdev_class) { + case DV_DISK: + if (strcmp(drvrname, "wd") == 0 && strcmp(name, bootdev) == 0) + bootdv = dev; + else { + /* XXX this really only works safely for usb0... */ + if ((strcmp(drvrname, "sd") == 0 || + strcmp(drvrname, "cd") == 0) && + strncmp(bootdev, "usb", 3) == 0 && + strcmp(name + 2, bootdev + 3) == 0) + bootdv = dev; + } + break; + case DV_IFNET: + /* + * This relies on the onboard Ethernet interface being + * attached before any other (usb) interface. + */ + bootdv = dev; + break; + default: + break; + } +} + +/* + * Initialize a VIA686 south bridge. + * + * PMON apparently does not perform enough initialization; one may argue this + * could be done with a specific pcib(4) driver, but then no other system + * will hopefully need this, so keep it local to the 2E setup code. + */ + +#define VIA686_ISA_ROM_CONTROL 0x40 +#define VIA686_ROM_WRITE_ENABLE 0x00000001 +#define VIA686_NO_ROM_WAIT_STATE 0x00000002 +#define VIA686_EXTEND_ALE 0x00000004 +#define VIA686_IO_RECOVERY_TIME 0x00000008 +#define VIA686_CHIPSET_EXTRA_WAIT_STATES 0x00000010 +#define VIA686_ISA_EXTRA_WAIT_STATES 0x00000020 +#define VIA686_ISA_EXTENDED_BUS_READY 0x00000040 +#define VIA686_ISA_EXTRA_COMMAND_DELAY 0x00000080 +#define VIA686_ISA_REFRESH 0x00000100 +#define VIA686_DOUBLE_DMA_CLOCK 0x00000800 +#define VIA686_PORT_92_FAST_RESET 0x00002000 +#define VIA686_IO_MEDIUM_RECOVERY_TIME 0x00004000 +#define VIA686_KBC_DMA_MISC12 0x44 +#define VIA686_ISA_MASTER_TO_LINE_BUFFER 0x00008000 +#define VIA686_POSTED_MEMORY_WRITE_ENABLE 0x00010000 +#define VIA686_PCI_BURST_INTERRUPTABLE 0x00020000 +#define VIA686_FLUSH_LINE_BUFFER_ON_INTR 0x00200000 +#define VIA686_GATE_INTR 0x00400000 +#define VIA686_PCI_MASTER_WRITE_WAIT_STATE 0x00800000 +#define VIA686_PCI_RESET 0x01000000 +#define VIA686_PCI_READ_DELAY_TRANSACTION_TMO 0x02000000 +#define VIA686_PCI_WRITE_DELAY_TRANSACTION_TMO 0x04000000 +#define VIA686_ICR_SHADOW_ENABLE 0x10000000 +#define VIA686_EISA_PORT_4D0_4D1_ENABLE 0x20000000 +#define VIA686_PCI_DELAY_TRANSACTION_ENABLE 0x40000000 +#define VIA686_CPU_RESET_SOURCE_INIT 0x80000000 +#define VIA686_MISC3_IDE_INTR 0x48 +#define VIA686_IDE_PRIMARY_CHAN_MASK 0x00030000 +#define VIA686_IDE_PRIMARY_CHAN_SHIFT 16 +#define VIA686_IDE_SECONDARY_CHAN_MASK 0x000c0000 +#define VIA686_IDE_SECONDARY_CHAN_SHIFT 18 +#define VIA686_IDE_IRQ14 00 +#define VIA686_IDE_IRQ15 01 +#define VIA686_IDE_IRQ10 02 +#define VIA686_IDE_IRQ11 03 +#define VIA686_IDE_PGNT 0x00800000 +#define VIA686_PNP_DMA_IRQ 0x50 +#define VIA686_DMA_FDC_MASK 0x00000003 +#define VIA686_DMA_FDC_SHIFT 0 +#define VIA686_DMA_LPT_MASK 0x0000000c +#define VIA686_DMA_LPT_SHIFT 2 +#define VIA686_IRQ_FDC_MASK 0x00000f00 +#define VIA686_IRQ_FDC_SHIFT 8 +#define VIA686_IRQ_LPT_MASK 0x0000f000 +#define VIA686_IRQ_LPT_SHIFT 12 +#define VIA686_IRQ_COM0_MASK 0x000f0000 +#define VIA686_IRQ_COM0_SHIFT 16 +#define VIA686_IRQ_COM1_MASK 0x00f00000 +#define VIA686_IRQ_COM1_SHIFT 20 +#define VIA686_PCI_LEVEL_PNP_IRQ2 0x54 +#define VIA686_PCI_IRQD_EDGE 0x00000001 +#define VIA686_PCI_IRQC_EDGE 0x00000002 +#define VIA686_PCI_IRQB_EDGE 0x00000004 +#define VIA686_PCI_IRQA_EDGE 0x00000008 +#define VIA686_IRQ_PCIA_MASK 0x0000f000 +#define VIA686_IRQ_PCIA_SHIFT 12 +#define VIA686_IRQ_PCIB_MASK 0x000f0000 +#define VIA686_IRQ_PCIB_SHIFT 16 +#define VIA686_IRQ_PCIC_MASK 0x00f00000 +#define VIA686_IRQ_PCIC_SHIFT 20 +#define VIA686_IRQ_PCID_MASK 0xf0000000 +#define VIA686_IRQ_PCID_SHIFT 28 + +void +via686sb_setup(pci_chipset_tag_t pc, int dev) +{ + pcitag_t tag; + pcireg_t reg; + uint elcr; + + tag = pci_make_tag(pc, 0, dev, 0); + + /* + * Generic ISA bus initialization. + */ + + reg = pci_conf_read(pc, tag, VIA686_ISA_ROM_CONTROL); + reg |= VIA686_IO_RECOVERY_TIME | VIA686_ISA_REFRESH; + pci_conf_write(pc, tag, VIA686_ISA_ROM_CONTROL, reg); + + reg = pci_conf_read(pc, tag, VIA686_KBC_DMA_MISC12); + reg |= VIA686_CPU_RESET_SOURCE_INIT | + VIA686_PCI_DELAY_TRANSACTION_ENABLE | + VIA686_EISA_PORT_4D0_4D1_ENABLE | + VIA686_PCI_WRITE_DELAY_TRANSACTION_TMO | + VIA686_PCI_READ_DELAY_TRANSACTION_TMO | + VIA686_PCI_MASTER_WRITE_WAIT_STATE | VIA686_GATE_INTR | + VIA686_FLUSH_LINE_BUFFER_ON_INTR; + reg &= ~VIA686_ISA_MASTER_TO_LINE_BUFFER; + pci_conf_write(pc, tag, VIA686_KBC_DMA_MISC12, reg); + + /* + * SuperIO devices interrupt and DMA setup. + */ + + reg = pci_conf_read(pc, tag, VIA686_MISC3_IDE_INTR); + reg &= ~(VIA686_IDE_PRIMARY_CHAN_MASK | VIA686_IDE_SECONDARY_CHAN_MASK); + reg |= (VIA686_IDE_IRQ14 << VIA686_IDE_PRIMARY_CHAN_SHIFT); + reg |= (VIA686_IDE_IRQ15 << VIA686_IDE_SECONDARY_CHAN_SHIFT); + reg |= VIA686_IDE_PGNT; + pci_conf_write(pc, tag, VIA686_MISC3_IDE_INTR, reg); + + reg = pci_conf_read(pc, tag, VIA686_PNP_DMA_IRQ); + reg &= ~(VIA686_DMA_FDC_MASK | VIA686_DMA_LPT_MASK); + reg |= (2 << VIA686_DMA_FDC_SHIFT) | (3 << VIA686_DMA_LPT_SHIFT); + reg &= ~(VIA686_IRQ_FDC_MASK | VIA686_IRQ_LPT_MASK); + reg |= (6 << VIA686_IRQ_FDC_SHIFT) | (7 << VIA686_IRQ_LPT_SHIFT); + reg &= ~(VIA686_IRQ_COM0_MASK | VIA686_IRQ_COM1_MASK); + reg |= (4 << VIA686_IRQ_COM0_SHIFT) | (3 << VIA686_IRQ_COM1_SHIFT); + + reg = pci_conf_read(pc, tag, VIA686_PCI_LEVEL_PNP_IRQ2); + reg &= ~(VIA686_PCI_IRQA_EDGE | VIA686_PCI_IRQB_EDGE | + VIA686_PCI_IRQB_EDGE | VIA686_PCI_IRQD_EDGE); + reg &= ~(VIA686_IRQ_PCIA_MASK | VIA686_IRQ_PCIB_MASK | + VIA686_IRQ_PCIC_MASK | VIA686_IRQ_PCID_MASK); + reg |= (VIA686_IRQ_PCIA << VIA686_IRQ_PCIA_SHIFT) | + (VIA686_IRQ_PCIB << VIA686_IRQ_PCIB_SHIFT) | + (VIA686_IRQ_PCIC << VIA686_IRQ_PCIC_SHIFT) | + (VIA686_IRQ_PCID << VIA686_IRQ_PCID_SHIFT); + + /* + * Interrupt controller setup. + */ + + /* reset; program device, four bytes */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW1) = + ICW1_SELECT | ICW1_IC4; + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW2) = ICW2_VECTOR(0); + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW3) = ICW3_CASCADE(2); + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW4) = ICW4_8086; + /* leave interrupts masked */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff; + /* special mask mode (if available) */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = + OCW3_SELECT | OCW3_SSMM | OCW3_SMM; + /* read IRR by default. */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = OCW3_SELECT | OCW3_RR; + + /* reset; program device, four bytes */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW1) = + ICW1_SELECT | ICW1_IC4; + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW2) = ICW2_VECTOR(8); + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW3) = ICW3_SIC(2); + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW4) = ICW4_8086; + /* leave interrupts masked */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff; + /* special mask mode (if available) */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = + OCW3_SELECT | OCW3_SSMM | OCW3_SMM; + /* read IRR by default. */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = OCW3_SELECT | OCW3_RR; + + /* setup ELCR: PCI interrupts are level-triggered. */ + elcr = (1 << VIA686_IRQ_PCIA) | (1 << VIA686_IRQ_PCIB) | + (1 << VIA686_IRQ_PCIC) | (1 << VIA686_IRQ_PCID); + REGVAL8(BONITO_PCIIO_BASE + 0x4d0) = (elcr >> 0) & 0xff; + REGVAL8(BONITO_PCIIO_BASE + 0x4d1) = (elcr >> 8) & 0xff; + + __asm__ __volatile__ ("sync" ::: "memory"); + + /* + * Update interrupt information for secondary functions. + * Although this information is not used by pci_intr_establish() + * because of generic2e_intr_map() behaviour, it seems to be + * required to complete proper interrupt routing. + */ + + tag = pci_make_tag(pc, 0, dev, 2); + reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); + reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); + reg |= VIA686_IRQ_PCIB << PCI_INTERRUPT_LINE_SHIFT; + pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg); + + tag = pci_make_tag(pc, 0, dev, 3); + reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); + reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); + reg |= VIA686_IRQ_PCIC << PCI_INTERRUPT_LINE_SHIFT; + pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg); + + tag = pci_make_tag(pc, 0, dev, 5); + reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); + reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); + reg |= VIA686_IRQ_PCIA << PCI_INTERRUPT_LINE_SHIFT; + pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg); +} diff --git a/sys/arch/loongson/loongson/isa_machdep.c b/sys/arch/loongson/loongson/isa_machdep.c new file mode 100644 index 00000000000..389dac292fc --- /dev/null +++ b/sys/arch/loongson/loongson/isa_machdep.c @@ -0,0 +1,118 @@ +/* $OpenBSD: isa_machdep.c,v 1.1 2010/05/08 21:59:56 miod Exp $ */ + +/* + * Copyright (c) 2009, 2010 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Legacy device support. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/intr.h> + +#include <dev/ic/i8259reg.h> + +#include <dev/pci/pcivar.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <loongson/dev/bonitoreg.h> +#include <loongson/dev/bonitovar.h> +#include <loongson/dev/bonito_irq.h> + +void loongson_set_isa_imr(uint); +void loongson_isa_splx(int); +void loongson_isa_setintrmask(int); + +uint loongson_isaimr; + +void +loongson_set_isa_imr(uint newimr) +{ + uint imr1, imr2; + + imr1 = 0xff & ~newimr; + imr1 &= ~(1 << 2); /* enable cascade */ + imr2 = 0xff & ~(newimr >> 8); + + /* + * For some reason, trying to write the same value to the PIC + * registers causes an immediate system freeze (at least on the + * 2F and CS5536 based Lemote Yeeloong), so we only do this if + * the value changes. + * Note that interrupts have been disabled by the caller. + */ + if ((newimr ^ loongson_isaimr) & 0xff00) + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) = imr2; + if ((newimr ^ loongson_isaimr) & 0x00ff) + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1) = imr1; + loongson_isaimr = newimr; +} + +void +loongson_isa_specific_eoi(int bit) +{ + if (bit & 8) { + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW2) = + OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(bit & 7); + bit = 2; + } + REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW2) = + OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(bit); +} + +void +loongson_isa_splx(int newipl) +{ + struct cpu_info *ci = curcpu(); + + /* Update masks to new ipl. Order highly important! */ + __asm__ (".set noreorder\n"); + ci->ci_ipl = newipl; + __asm__ ("sync\n\t.set reorder\n"); + loongson_isa_setintrmask(newipl); + /* If we still have softints pending trigger processing. */ + if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT) + setsoftintr0(); +} + +void +loongson_isa_setintrmask(int level) +{ + uint64_t active; + uint32_t sr; + + active = bonito_intem & ~bonito_imask[level]; + + sr = disableintr(); + bonito_setintrmask(level); + loongson_set_isa_imr(BONITO_ISA_MASK(active)); + setsr(sr); +} + +void +loongson_generic_isa_attach_hook(struct device *parent, struct device *self, + struct isabus_attach_args *iba) +{ + loongson_isaimr = 0; + /* overrides bonito callback */ + register_splx_handler(loongson_isa_splx); +} diff --git a/sys/arch/loongson/loongson/loongson2_machdep.c b/sys/arch/loongson/loongson/loongson2_machdep.c index 5b5b623c90d..37eb3734e1d 100644 --- a/sys/arch/loongson/loongson/loongson2_machdep.c +++ b/sys/arch/loongson/loongson/loongson2_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loongson2_machdep.c,v 1.9 2010/04/21 03:03:26 deraadt Exp $ */ +/* $OpenBSD: loongson2_machdep.c,v 1.10 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -74,20 +74,26 @@ paddr_t loongson_dma_base = 0; void loongson2e_setup(u_long memlo, u_long memhi) { + if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) { + pmon_printf("WARNING! %d MB of memory will not be used", + memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)); + memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20; + } + memlo = atop(memlo << 20); memhi = atop(memhi << 20); physmem = memlo + memhi; - /* - * Only register the first 256MB of memory. - * This will be hopefully be revisited once we get our hands - * on Loongson 2E-based hardware... - */ - /* do NOT stomp on exception area */ mem_layout[0].mem_first_page = atop(DDR_PHYSICAL_BASE) + 1; mem_layout[0].mem_last_page = atop(DDR_PHYSICAL_BASE) + memlo; + if (memhi != 0) { + mem_layout[1].mem_first_page = atop(BONITO_PCIHI_BASE); + mem_layout[1].mem_last_page = atop(BONITO_PCIHI_BASE) + + memhi; + } + loongson_dma_base = PCI_DDR_BASE ^ DDR_PHYSICAL_BASE; } @@ -124,7 +130,7 @@ loongson2f_setup(u_long memlo, u_long memhi) memlo = atop(memlo << 20); memhi = atop(memhi << 20); - physmem = atop((vsize_t)physmem << 20); + physmem = memlo + memhi; /* * PMON configures the system with only the low 256MB of memory @@ -251,7 +257,7 @@ is_memory_range(paddr_t pa, psize_t len, psize_t limit) * Allow access to the low 256MB aliased region on 2F systems, * if we are accessing memory at 2GB onwards. */ - if (pa < 0x10000000) { + if (pa < 0x10000000 && loongson_ver == 0x2f) { fp += mem_layout[0].mem_first_page - 1; lp += mem_layout[0].mem_first_page - 1; } diff --git a/sys/arch/loongson/loongson/machdep.c b/sys/arch/loongson/loongson/machdep.c index 49e987af86a..46ac7d6e155 100644 --- a/sys/arch/loongson/loongson/machdep.c +++ b/sys/arch/loongson/loongson/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.18 2010/04/27 04:26:20 miod Exp $ */ +/* $OpenBSD: machdep.c,v 1.19 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -77,9 +77,6 @@ #include <mips64/archtype.h> -#include <loongson/dev/bonitoreg.h> -#include <loongson/dev/bonitovar.h> - /* The following is used externally (sysctl_hw) */ char machine[] = MACHINE; /* Machine "architecture" */ char cpu_model[30]; @@ -110,6 +107,7 @@ int kbd_reset; const struct platform *sys_platform; struct cpu_hwinfo bootcpu_hwinfo; +uint loongson_ver; /* Pointers to the start and end of the symbol table. */ caddr_t ssym; @@ -155,6 +153,7 @@ struct bonito_flavour { extern const struct platform fuloong_platform; extern const struct platform gdium_platform; +extern const struct platform generic2e_platform; extern const struct platform lynloong_platform; extern const struct platform yeeloong_platform; @@ -183,7 +182,7 @@ vaddr_t mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv, char *boot_esym) { - uint prid, loongson_ver; + uint prid; u_long memlo, memhi, cpuspeed; vaddr_t xtlb_handler; const char *envvar; @@ -280,20 +279,29 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv, envvar = pmon_getenv("Version"); if (envvar == NULL) { - pmon_printf("Unable to figure out model!\n"); - goto unsupported; - } - - for (f = bonito_flavours; f->prefix != NULL; f++) - if (strncmp(envvar, f->prefix, strlen(f->prefix)) == 0) { - sys_platform = f->platform; - break; + /* + * If this is a 2E system, use the generic code and hope + * for the best. + */ + if (loongson_ver == 0x2e) { + sys_platform = &generic2e_platform; + } else { + pmon_printf("Unable to figure out model!\n"); + goto unsupported; } + } else { + for (f = bonito_flavours; f->prefix != NULL; f++) + if (strncmp(envvar, f->prefix, strlen(f->prefix)) == + 0) { + sys_platform = f->platform; + break; + } - if (sys_platform == NULL) { - pmon_printf("This kernel doesn't support model \"%s\".\n", - envvar); - goto unsupported; + if (sys_platform == NULL) { + pmon_printf("This kernel doesn't support model \"%s\"." + "\n", envvar); + goto unsupported; + } } hw_vendor = sys_platform->vendor; diff --git a/sys/arch/loongson/loongson/pciide_machdep.c b/sys/arch/loongson/loongson/pciide_machdep.c index 267b44f1941..6aa05b32427 100644 --- a/sys/arch/loongson/loongson/pciide_machdep.c +++ b/sys/arch/loongson/loongson/pciide_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide_machdep.c,v 1.1 2009/11/25 18:56:34 miod Exp $ */ +/* $OpenBSD: pciide_machdep.c,v 1.2 2010/05/08 21:59:56 miod Exp $ */ /* $NetBSD: pciide_machdep.c,v 1.2 1999/02/19 18:01:27 mycroft Exp $ */ /* @@ -50,6 +50,8 @@ #include <dev/pci/pciidereg.h> #include <dev/pci/pciidevar.h> +#include <machine/autoconf.h> + #include <dev/isa/isavar.h> void * @@ -59,9 +61,12 @@ pciide_machdep_compat_intr_establish(struct device *dev, int irq; void *cookie; - irq = PCIIDE_COMPAT_IRQ(chan); - cookie = isa_intr_establish(NULL, irq, IST_EDGE, IPL_BIO, func, arg, - dev->dv_xname); + if (sys_platform->isa_chipset != NULL) { + irq = PCIIDE_COMPAT_IRQ(chan); + cookie = isa_intr_establish(sys_platform->isa_chipset, + irq, IST_EDGE, IPL_BIO, func, arg, dev->dv_xname); + } else + cookie = NULL; return (cookie); } @@ -69,5 +74,6 @@ pciide_machdep_compat_intr_establish(struct device *dev, void pciide_machdep_compat_intr_disestablish(pci_chipset_tag_t pc, void *cookie) { - isa_intr_disestablish(NULL, cookie); + if (sys_platform->isa_chipset != NULL) + isa_intr_disestablish(sys_platform->isa_chipset, cookie); } diff --git a/sys/arch/loongson/loongson/wscons_machdep.c b/sys/arch/loongson/loongson/wscons_machdep.c index a28b2f89d52..219c93f34a3 100644 --- a/sys/arch/loongson/loongson/wscons_machdep.c +++ b/sys/arch/loongson/loongson/wscons_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wscons_machdep.c,v 1.6 2010/02/28 22:32:50 miod Exp $ */ +/* $OpenBSD: wscons_machdep.c,v 1.7 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. @@ -58,6 +58,7 @@ #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> +#include <dev/pci/vga_pcivar.h> #include "wsdisplay.h" #if NWSDISPLAY > 0 @@ -67,6 +68,7 @@ extern int sisfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t); #include "smfb.h" extern int smfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t); +#include "vga.h" #include "pckbc.h" #if NPCKBC > 0 @@ -88,7 +90,11 @@ cons_decl(ws); void wscnprobe(struct consdev *cp) { - int maj; + pcitag_t tag; + pcireg_t id, class; + int maj, dev; + + cp->cn_pri = CN_DEAD; /* Locate the major number. */ for (maj = 0; maj < nchrdev; maj++) { @@ -98,11 +104,27 @@ wscnprobe(struct consdev *cp) if (maj == nchrdev) { /* We are not in cdevsw[], give up. */ - panic("wsdisplay is not in cdevsw[]"); + return; } - cp->cn_dev = makedev(maj, 0); - cp->cn_pri = CN_MIDPRI; + /* + * Look for a suitable video device. + */ + + for (dev = 0; dev < 32; dev++) { + tag = pci_make_tag_early(0, dev, 0); + id = pci_conf_read_early(tag, PCI_ID_REG); + if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + + class = pci_conf_read_early(tag, PCI_CLASS_REG); + if (!DEVICE_IS_VGA_PCI(class)) + continue; + + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_MIDPRI; + break; + } } void @@ -114,12 +136,15 @@ static int initted; int dev, rc; extern struct mips_bus_space bonito_pci_io_space_tag; extern struct mips_bus_space bonito_pci_mem_space_tag; + extern struct consdev pmoncons; if (initted) return; initted = 1; + cn_tab = &pmoncons; /* to be able to panic */ + /* * Look for a suitable video device. */ @@ -131,7 +156,7 @@ static int initted; continue; class = pci_conf_read_early(tag, PCI_CLASS_REG); - if (PCI_CLASS(class) != PCI_CLASS_DISPLAY) + if (!DEVICE_IS_VGA_PCI(class)) continue; /* @@ -139,20 +164,33 @@ static int initted; */ rc = ENXIO; + + /* bitmapped frame buffer won't be of PREHISTORIC class */ + if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) { #if NSISFB > 0 - if (rc != 0) - rc = sisfb_cnattach(&bonito_pci_mem_space_tag, - &bonito_pci_io_space_tag, tag, id); + if (rc != 0) + rc = sisfb_cnattach(&bonito_pci_mem_space_tag, + &bonito_pci_io_space_tag, tag, id); #endif #if NSMFB > 0 - if (rc != 0) - rc = smfb_cnattach(&bonito_pci_mem_space_tag, - &bonito_pci_io_space_tag, tag, id); + if (rc != 0) + rc = smfb_cnattach(&bonito_pci_mem_space_tag, + &bonito_pci_io_space_tag, tag, id); +#endif + } +#if NVGA > 0 + if (rc != 0) { + /* thanks $DEITY the pci_chipset_tag_t arg is ignored */ + rc = vga_pci_cnattach(&bonito_pci_io_space_tag, + &bonito_pci_mem_space_tag, NULL, 0, dev, 0); + } #endif if (rc == 0) goto setup_kbd; } + cn_tab = cp; + /* no glass console... */ return; @@ -165,21 +203,16 @@ setup_kbd: rc = ENXIO; #if NPCKBC > 0 - switch (sys_platform->system_type) { - default: - /* no pckbc or no legacy hardware */ - break; - case LOONGSON_YEELOONG: - if (rc != 0) - rc = pckbc_cnattach(&bonito_pci_io_space_tag, IO_KBD, - KBCMDP, PCKBC_KBD_SLOT, 0); - break; - } + if (rc != 0) + rc = pckbc_cnattach(&bonito_pci_io_space_tag, IO_KBD, + KBCMDP, PCKBC_KBD_SLOT, 0); #endif #if NUKBD > 0 if (rc != 0) rc = ukbd_cnattach(); #endif + + cn_tab = cp; } void @@ -193,7 +226,7 @@ wscnputc(dev_t dev, int i) int wscngetc(dev_t dev) { -#if NPCKBD > 0 +#if NPCKBD > 0 || NUKBD > 0 int c; wskbd_cnpollc(dev, 1); @@ -209,7 +242,7 @@ wscngetc(dev_t dev) void wscnpollc(dev_t dev, int on) { -#if NPCKBD > 0 +#if NPCKBD > 0 || NUKBD > 0 wskbd_cnpollc(dev, on); #endif } diff --git a/sys/arch/loongson/loongson/yeeloong_machdep.c b/sys/arch/loongson/loongson/yeeloong_machdep.c index 5d25381f039..cf99f774400 100644 --- a/sys/arch/loongson/loongson/yeeloong_machdep.c +++ b/sys/arch/loongson/loongson/yeeloong_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yeeloong_machdep.c,v 1.11 2010/03/02 20:54:51 miod Exp $ */ +/* $OpenBSD: yeeloong_machdep.c,v 1.12 2010/05/08 21:59:56 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -30,8 +30,10 @@ #include <machine/pmon.h> #include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> #include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> #include <loongson/dev/bonitoreg.h> @@ -48,15 +50,26 @@ extern struct mips_bus_space bonito_pci_io_space_tag; #endif -void lemote_attach_hook(pci_chipset_tag_t); -void lemote_device_register(struct device *, void *); -int lemote_intr_map(int, int, int); -void lemote_reset(void); +void lemote_device_register(struct device *, void *); +void lemote_reset(void); -void fuloong_powerdown(void); -void fuloong_setup(void); +void fuloong_powerdown(void); +void fuloong_setup(void); -void yeeloong_powerdown(void); +void yeeloong_powerdown(void); + +void lemote_pci_attach_hook(pci_chipset_tag_t); +int lemote_intr_map(int, int, int); + +void lemote_isa_attach_hook(struct device *, struct device *, + struct isabus_attach_args *); +void *lemote_isa_intr_establish(void *, int, int, int, int (*)(void *), + void *, char *); +void lemote_isa_intr_disestablish(void *, void *); + +uint lemote_get_isa_imr(void); +uint lemote_get_isa_isr(void); +uint32_t lemote_isa_intr(uint32_t, struct trap_frame *); const struct bonito_config lemote_bonito = { .bc_adbase = 11, @@ -69,9 +82,7 @@ const struct bonito_config lemote_bonito = { LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR | LOONGSON_INTRMASK_INT0 | LOONGSON_INTRMASK_INT1, - .bc_legacy_pic = 1, - - .bc_attach_hook = lemote_attach_hook, + .bc_attach_hook = lemote_pci_attach_hook, .bc_intr_map = lemote_intr_map }; @@ -129,12 +140,21 @@ const struct legacy_io_range yeeloong_legacy_ranges[] = { { 0 } }; +struct mips_isa_chipset lemote_isa_chipset = { + .ic_v = NULL, + + .ic_attach_hook = lemote_isa_attach_hook, + .ic_intr_establish = lemote_isa_intr_establish, + .ic_intr_disestablish = lemote_isa_intr_disestablish +}; + const struct platform fuloong_platform = { .system_type = LOONGSON_FULOONG, .vendor = "Lemote", .product = "Fuloong", .bonito_config = &lemote_bonito, + .isa_chipset = &lemote_isa_chipset, .legacy_io_ranges = fuloong_legacy_ranges, .setup = fuloong_setup, @@ -150,6 +170,7 @@ const struct platform lynloong_platform = { .product = "Lynloong", .bonito_config = &lemote_bonito, + .isa_chipset = &lemote_isa_chipset, .legacy_io_ranges = lynloong_legacy_ranges, .setup = fuloong_setup, @@ -165,6 +186,7 @@ const struct platform yeeloong_platform = { .product = "Yeeloong", .bonito_config = &lemote_bonito, + .isa_chipset = &lemote_isa_chipset, .legacy_io_ranges = yeeloong_legacy_ranges, .setup = NULL, @@ -174,8 +196,12 @@ const struct platform yeeloong_platform = { .reset = lemote_reset }; +/* + * PCI model specific routines + */ + void -lemote_attach_hook(pci_chipset_tag_t pc) +lemote_pci_attach_hook(pci_chipset_tag_t pc) { pcireg_t id; pcitag_t tag; @@ -233,6 +259,163 @@ lemote_intr_map(int dev, int fn, int pin) return -1; } +/* + * ISA model specific routines + */ + +void +lemote_isa_attach_hook(struct device *parent, struct device *self, + struct isabus_attach_args *iba) +{ + set_intr(INTPRI_ISA, CR_INT_0, lemote_isa_intr); + + /* disable all isa interrupt sources */ + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) = 0xff; + REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 2) = 0xff; + + loongson_generic_isa_attach_hook(parent, self, iba); +} + +void * +lemote_isa_intr_establish(void *v, int irq, int type, int level, + int (*handler)(void *), void *arg, char *name) +{ + return bonito_intr_establish(BONITO_ISA_IRQ(irq), type, level, + handler, arg, name); +} + +void +lemote_isa_intr_disestablish(void *v, void *ih) +{ + bonito_intr_disestablish(ih); +} + +/* + * Legacy (ISA) interrupt handling + */ + +/* + * Process legacy interrupts. + * + * XXX On 2F, ISA interrupts only occur on LOONGSON_INTR_INT0, but since + * XXX the other LOONGSON_INTR_INT# are unmaskable, bad things will happen + * XXX if they ever are triggered... + */ +uint32_t +lemote_isa_intr(uint32_t hwpend, struct trap_frame *frame) +{ + uint64_t imr, isr, mask; + int bit; + struct intrhand *ih; + int rc; + + isr = lemote_get_isa_isr(); + imr = lemote_get_isa_imr(); + + isr &= imr; + isr &= ~(1 << 2); /* cascade */ +#ifdef DEBUG + printf("isa interrupt: imr %04x isr %04x\n", imr, isr); +#endif + if (isr == 0) + return 0; /* not for us */ + + /* + * Mask all pending interrupts. + */ + + loongson_set_isa_imr(imr & ~isr); + + /* + * If interrupts are spl-masked, mask them and wait for splx() + * to reenable them when necessary. + */ + if ((mask = isr & (BONITO_ISA_MASK(bonito_imask[frame->ipl]))) != 0) { + isr &= ~mask; + imr &= ~mask; + } + + /* + * Now process allowed interrupts. + */ + if (isr != 0) { + int lvl, bitno; + uint64_t tmpisr; + + /* Service higher level interrupts first */ + bit = BONITO_NISA - 1; + for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) { + tmpisr = isr & BONITO_ISA_MASK(bonito_imask[lvl] ^ + bonito_imask[lvl - 1]); + if (tmpisr == 0) + continue; + for (bitno = bit, mask = 1UL << bitno; mask != 0; + bitno--, mask >>= 1) { + if ((tmpisr & mask) == 0) + continue; + + rc = 0; + for (ih = bonito_intrhand[BONITO_ISA_IRQ(bitno)]; + ih != NULL; ih = ih->ih_next) { + splraise(ih->ih_level); + if ((*ih->ih_fun)(ih->ih_arg) != 0) { + rc = 1; + ih->ih_count.ec_count++; + } + __asm__ (".set noreorder\n"); + curcpu()->ci_ipl = frame->ipl; + __asm__ ("sync\n\t.set reorder\n"); + } + if (rc == 0) + printf("spurious isa interrupt %d\n", + bitno); + + loongson_isa_specific_eoi(bitno); + + if ((isr ^= mask) == 0) + goto done; + if ((tmpisr ^= mask) == 0) + break; + } + } +done: + + /* + * Reenable interrupts which have been serviced. + */ + loongson_set_isa_imr(imr); + } + + return hwpend; +} + +uint +lemote_get_isa_imr() +{ + uint imr1, imr2; + + imr1 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1); + imr1 &= ~(1 << 2); /* hide cascade */ + imr2 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1); + + return (imr2 << 8) | imr1; +} + +uint +lemote_get_isa_isr() +{ + uint isr1, isr2; + + isr1 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU1); + isr2 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU2); + + return (isr2 << 8) | isr1; +} + +/* + * Other model specific routines + */ + void fuloong_powerdown() { |