/* $OpenBSD: clock.c,v 1.19 2002/03/14 01:26:39 millert Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. * Copyright (c) 1995 Theo de Raadt * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Theo de Raadt for Willowglen Singapore. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * Copyright (c) 1995 Nivas Madhur * Copyright (c) 1994 Gordon W. Ross * Copyright (c) 1993 Adam Glass * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)clock.c 8.1 (Berkeley) 6/11/93 */ /* * interval clock driver. */ #include #include #include #include #include #ifdef GPROF #include #endif #include #include /* for stack_pointer() */ #include /* for register defines */ #include #include #include #include #include /* DMA_CACHE_SYNC, etc... */ #include "pcctwo.h" #if NPCCTWO > 0 #include #include #include "bugtty.h" #if NBUGTTY > 0 #include #endif #endif #include "syscon.h" #if NSYSCON > 0 #include #include #endif #include extern struct vme2reg *sys_vme2; int timerok = 0; u_long delay_factor = 1; static int clockmatch(struct device *, void *, void *); static void clockattach(struct device *, struct device *, void *); void sbc_initclock(void); void m188_initclock(void); void m188_timer_init(unsigned); struct clocksoftc { struct device sc_dev; struct intrhand sc_profih; struct intrhand sc_statih; }; struct cfattach clock_ca = { sizeof(struct clocksoftc), clockmatch, clockattach }; struct cfdriver clock_cd = { NULL, "clock", DV_DULL, 0 }; int sbc_clockintr(void *); int m188_clockintr(void *); int clockbus; u_char prof_reset; /* * Every machine must have a clock tick device of some sort; for this * platform this file manages it, no matter what form it takes. */ int clockmatch(parent, vcf, args) struct device *parent; void *vcf, *args; { register struct confargs *ca = args; register struct cfdata *cf = vcf; if (strcmp(cf->cf_driver->cd_name, "clock")) { return (0); } /* * clock has to be at ipl 5 * We return the ipl here so that the parent can print * a message if it is different from what ioconf.c says. */ ca->ca_ipl = IPL_CLOCK; /* set size to 0 - see pcctwo.c:match for details */ ca->ca_len = 0; return (1); } void clockattach(parent, self, args) struct device *parent, *self; void *args; { struct confargs *ca = args; struct clocksoftc *sc = (struct clocksoftc *)self; clockbus = ca->ca_bustype; switch (clockbus) { #if NPCCTWO > 0 case BUS_PCCTWO: sc->sc_profih.ih_fn = sbc_clockintr; sc->sc_profih.ih_arg = 0; sc->sc_profih.ih_wantframe = 1; sc->sc_profih.ih_ipl = ca->ca_ipl; prof_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR; pcctwointr_establish(PCC2V_TIMER1, &sc->sc_profih); md.clock_init_func = sbc_initclock; printf(": VME1x7"); break; #endif /* NPCCTWO */ #if NSYSCON > 0 && defined(MVME188) case BUS_SYSCON: sc->sc_profih.ih_fn = m188_clockintr; sc->sc_profih.ih_arg = 0; sc->sc_profih.ih_wantframe = 1; sc->sc_profih.ih_ipl = ca->ca_ipl; sysconintr_establish(SYSCV_TIMER1, &sc->sc_profih); md.clock_init_func = m188_initclock; printf(": VME188"); break; #endif /* NSYSCON */ } printf("\n"); } #if NPCCTWO > 0 void sbc_initclock(void) { #ifdef CLOCK_DEBUG printf("SBC clock init\n"); #endif if (1000000 % hz) { printf("cannot get %d Hz clock; using 100 Hz\n", hz); hz = 100; tick = 1000000 / hz; } /* profclock */ sys_pcc2->pcc2_t1ctl = 0; sys_pcc2->pcc2_t1cmp = pcc2_timer_us2lim(tick); sys_pcc2->pcc2_t1count = 0; sys_pcc2->pcc2_t1ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC | PCC2_TCTL_COVF; sys_pcc2->pcc2_t1irq = prof_reset; } /* * clockintr: ack intr and call hardclock */ int sbc_clockintr(eframe) void *eframe; { sys_pcc2->pcc2_t1irq = prof_reset; /* increment intr counter */ intrcnt[M88K_CLK_IRQ]++; hardclock(eframe); #if NBUGTTY > 0 bugtty_chkinput(); #endif /* NBUGTTY */ timerok = 1; return (1); } #endif /* NPCCTWO */ int delay(us) register int us; { volatile register int c; /* * We use the vme system controller for the delay clock. * Do not go to the real timer until vme device is present. * Or, in the case of MVME188, not at all. */ if (sys_vme2 == NULL || brdtyp == BRD_188) { c = 3 * us; while (--c > 0); return (0); } sys_vme2->vme2_irql1 |= (0 << VME2_IRQL1_TIC1SHIFT); sys_vme2->vme2_t1count = 0; sys_vme2->vme2_tctl |= (VME2_TCTL1_CEN | VME2_TCTL1_COVF); while (sys_vme2->vme2_t1count < us) ; sys_vme2->vme2_tctl &= ~(VME2_TCTL1_CEN | VME2_TCTL1_COVF); return (0); } #if NSYSCON > 0 int counter = 0; #define IST int m188_clockintr(eframe) void *eframe; { volatile int tmp; int *volatile dti_stop = (int *volatile)DART_STOPC; int *volatile dti_start = (int *volatile)DART_STARTC; int *volatile ist = (int *volatile)MVME188_IST; #ifdef DEBUG register unsigned long sp; #endif /* increment intr counter */ intrcnt[M88K_CLK_IRQ]++; /* acknowledge the timer interrupt */ dma_cachectl(0xFFF82000, 0x1000, DMA_CACHE_SYNC_INVAL); tmp = *dti_stop; #ifdef DEBUG /* check kernel stack for overflow */ sp = stack_pointer(); if (sp < UADDR + NBPG && sp > UADDR) { if (*ist & DTI_BIT) { printf("DTI not clearing!\n"); } printf("kernel stack @ 0x%8x\n", sp); panic("stack overflow imminent!"); } #endif #if 0 /* clear the counter/timer output OP3 while we program the DART */ *((int *volatile) DART_OPCR) = 0x00; /* do the stop counter/timer command */ tmp = *((int *volatile) DART_STOPC); /* set counter/timer to counter mode, clock/16 */ *((int *volatile) DART_ACR) = 0x30; *((int *volatile) DART_CTUR) = counter / 256; /* set counter MSB */ *((int *volatile) DART_CTLR) = counter % 256; /* set counter LSB */ *((int *volatile) DART_IVR) = SYSCV_TIMER1; /* set interrupt vec */ #endif hardclock(eframe); #if NBUGTTY > 0 bugtty_chkinput(); #endif /* NBUGTTY */ /* give the start counter/timer command */ tmp = *dti_start; #if 0 *((int *volatile) DART_OPCR) = 0x04; #endif if (*ist & DTI_BIT) { printf("DTI not clearing!\n"); } return (1); } void m188_initclock(void) { #ifdef CLOCK_DEBUG printf("VME188 clock init\n"); #endif if (1000000 % hz) { printf("cannot get %d Hz clock; using 100 Hz\n", hz); hz = 100; tick = 1000000 / hz; } m188_timer_init(tick); } void m188_timer_init(unsigned period) { int imr; dma_cachectl(0xFFF82000, 0x1000, DMA_CACHE_SYNC_INVAL); /* make sure the counter range is proper. */ if ( period < 9 ) counter = 2; else if ( period > 284421 ) counter = 65535; else counter = period / 4.34; #ifdef CLOCK_DEBUG printf("tick == %d, period == %d\n", tick, period); printf("timer will interrupt every %d usec\n", (int) (counter * 4.34)); #endif /* clear the counter/timer output OP3 while we program the DART */ *((int *volatile) DART_OPCR) = 0x00; /* do the stop counter/timer command */ imr = *((int *volatile) DART_STOPC); /* set counter/timer to counter mode, clock/16 */ *((int *volatile) DART_ACR) = 0x30; *((int *volatile) DART_CTUR) = counter / 256; /* set counter MSB */ *((int *volatile) DART_CTLR) = counter % 256; /* set counter LSB */ *((int *volatile) DART_IVR) = SYSCV_TIMER1; /* set interrupt vec */ /* give the start counter/timer command */ /* (yes, this is supposed to be a read) */ imr = *((int *volatile) DART_STARTC); /* set the counter/timer output OP3 */ *((int *volatile) DART_OPCR) = 0x04; } #endif /* NSYSCON */