/* $OpenBSD: ofobio.c,v 1.1 2009/03/01 22:08:13 miod Exp $ */ /* * Copyright (c) 2009 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. */ /* * MVME141 On-board resources (One-Four-One OBIO) * * Unlike other MVME boards supported under OpenBSD/mvme68k, there is no * specific ASIC (lrc, mc2, pcc, pcc2...) providing a solid base to which * all other devices are related. * * Instead, we have four registers, and no timers. The onboard devices * (MC6861 providing serial ports and the clock, VMEchip, VSBchip and * NVRAM) may as well attach to mainbus. We nevertheless attach them at * ofobio to make things simpler in the kernel. */ #include #include #include #include #include #include #include #include #include struct ofobioreg *sys_ofobio; struct ofobiosoftc { struct device sc_dev; struct ofobioreg *sc_regs; struct intrhand sc_abortih; }; int ofobioabort(void *); void ofobioattach(struct device *, struct device *, void *); int ofobiomatch(struct device *, void *, void *); int ofobioprint(void *, const char *); int ofobioscan(struct device *, void *, void *); struct cfattach ofobio_ca = { sizeof(struct ofobiosoftc), ofobiomatch, ofobioattach }; struct cfdriver ofobio_cd = { NULL, "ofobio", DV_DULL }; int ofobiomatch(struct device *parent, void *cf, void *aux) { if (cputyp != CPU_141 || sys_ofobio != NULL) return (0); return (1); } void ofobioattach(struct device *parent, struct device *self, void *aux) { #if 0 struct confargs *ca = aux; #endif struct ofobiosoftc *sc = (struct ofobiosoftc *)self; sys_ofobio = sc->sc_regs = (struct ofobioreg *)IIOV(OFOBIO_CSR_ADDR); /* disable VSB and timer interrupts */ sc->sc_regs->csr_b |= OFO_CSRB_VSB_INTDIS | OFO_CSRB_TIMER_INTDIS; /* enable A32 addressing and device interrupts */ sc->sc_regs->csr_b &= ~(OFO_CSRB_GLOBAL_INTDIS | OFO_CSRB_DISABLE_A24); /* * A note regarding the board cache: the on-board 32KB are used * during early BUG bootstrap, until off-board memory is found, * and is intended to be used by the operating system as cache * memory (in addition to the small instruction cache internal to * the 68030). * * The cache flush and cache invalidation routines in locore * are not modified to invalidate the board cache as well, * since its snooping appears to be good enough to make it * completely transparent (the fact that vsbic(4) works, relying * to proper invalidate behaviour, is a good omen). */ /* clear board cache, then enable it */ sc->sc_regs->csr_a |= OFO_CSRA_CACHE_WDIS | OFO_CSRA_CACHE_RDIS; sc->sc_regs->csr_a |= OFO_CSRA_CACHE_CLEAR; sc->sc_regs->csr_a = OFO_CSRA_CACHE_MONITOR; printf(": board cache enabled\n"); sc->sc_abortih.ih_fn = ofobioabort; sc->sc_abortih.ih_ipl = IPL_HIGH; sc->sc_abortih.ih_wantframe = 1; intr_establish(OFOBIOVEC_ABORT, &sc->sc_abortih, self->dv_xname); config_search(ofobioscan, self, aux); } int ofobioprint(void *aux, const char *pnp) { struct confargs *ca = aux; if (ca->ca_offset != -1) printf(" offset 0x%x", ca->ca_offset); if (ca->ca_ipl > 0) printf(" ipl %d", ca->ca_ipl); return (UNCONF); } int ofobioscan(struct device *parent, void *self, void *aux) { struct cfdata *cf = self; #if 0 struct ofobiosoftc *sc = (struct ofobiosoftc *)parent; #endif struct confargs *ca = aux; struct confargs oca; bzero(&oca, sizeof oca); oca.ca_iot = ca->ca_iot; oca.ca_dmat = ca->ca_dmat; oca.ca_offset = cf->cf_loc[0]; oca.ca_ipl = cf->cf_loc[1]; if (oca.ca_offset != -1) { oca.ca_paddr = ca->ca_paddr + oca.ca_offset; oca.ca_vaddr = IIOV(oca.ca_paddr); } else { oca.ca_vaddr = (vaddr_t)-1; oca.ca_paddr = (paddr_t)-1; } oca.ca_bustype = BUS_OFOBIO; oca.ca_name = cf->cf_driver->cd_name; if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) return (0); config_attach(parent, cf, &oca, ofobioprint); return (1); } int ofobioabort(void *frame) { /* * Latch the condition; this will debounce the interrupt, * acknowledge it, and both the CSRD_ABORT and CRSD_ABORT_LATCH * bits will clear. */ sys_ofobio->csr_d |= OFO_CSRD_ABORT_LATCH; nmihand(frame); return (1); } void ofobio_clocksetup() { volatile uint8_t *dartregs = (volatile uint8_t *)IIOV(MVME141_DART_BASE); uint limit; uint8_t dummy; /* * Note that the dart(4) driver already may have programmed the * OPCR register during attachment. * It is very unfortunate that we have to override this. However * since dart(4) never needs to change the setting of this register, * ve'll simply keep the serial-related bits and add our own. */ /* disable timer output during programming */ dartregs[DART_OPCR] = OPSET; /* * The DUART runs at 3.6864 MHz; by using the second waveform * generator we'll get a CLK/32 master rate. */ limit = (3686400 / 32) / hz; dartregs[DART_CTUR] = limit >> 8; dartregs[DART_CTLR] = limit & 0xff; dartregs[DART_ACR] = BDSET2 | CCLK1 | IPDCDB | IPDCDA; dartregs[DART_OPCR] = OPSETTO; /* start counter */ dummy = dartregs[DART_CTSTART]; /* enable timer interrupts */ sys_ofobio->csr_b &= ~OFO_CSRB_TIMER_INTDIS; }