The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mvme/clock_pcctwo.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: clock_pcctwo.c,v 1.13 2008/04/28 20:23:53 martin Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Steve C. Woodford.
    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  * Glue for the Peripheral Channel Controller Two (PCCChip2) timers,
   34  * the Memory Controller ASIC (MCchip, and the Mostek clock chip found
   35  * on the MVME-1[67]7, MVME-1[67]2 and MVME-187 series of boards.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: clock_pcctwo.c,v 1.13 2008/04/28 20:23:53 martin Exp $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/kernel.h>
   43 #include <sys/systm.h>
   44 #include <sys/device.h>
   45 #include <sys/timetc.h>
   46 
   47 #include <machine/psl.h>
   48 #include <sys/bus.h>
   49 
   50 #include <dev/mvme/clockvar.h>
   51 #include <dev/mvme/pcctwovar.h>
   52 #include <dev/mvme/pcctworeg.h>
   53 
   54 
   55 int clock_pcctwo_match(struct device *, struct cfdata *, void *);
   56 void clock_pcctwo_attach(struct device *, struct device *, void *);
   57 
   58 struct clock_pcctwo_softc {
   59         struct device sc_dev;
   60         struct clock_attach_args sc_clock_args;
   61         u_char sc_clock_lvl;
   62         struct timecounter sc_tc;
   63 };
   64 
   65 CFATTACH_DECL(clock_pcctwo, sizeof(struct clock_pcctwo_softc),
   66     clock_pcctwo_match, clock_pcctwo_attach, NULL, NULL);
   67 
   68 extern struct cfdriver clock_cd;
   69 
   70 static int clock_pcctwo_profintr(void *);
   71 static int clock_pcctwo_statintr(void *);
   72 static void clock_pcctwo_initclocks(void *, int, int);
   73 static u_int clock_pcctwo_getcount(struct timecounter *);
   74 static void clock_pcctwo_shutdown(void *);
   75 
   76 static struct clock_pcctwo_softc *clock_pcctwo_sc;
   77 static uint32_t clock_pcctwo_count;
   78 
   79 /* ARGSUSED */
   80 int
   81 clock_pcctwo_match(parent, cf, aux)
   82         struct device *parent;
   83         struct cfdata *cf;
   84         void *aux;
   85 {
   86         struct pcctwo_attach_args *pa = aux;
   87 
   88         /* Only one clock, please. */
   89         if (clock_pcctwo_sc)
   90                 return (0);
   91 
   92         if (strcmp(pa->pa_name, clock_cd.cd_name))
   93                 return (0);
   94 
   95         pa->pa_ipl = cf->pcctwocf_ipl;
   96 
   97         return (1);
   98 }
   99 
  100 /* ARGSUSED */
  101 void
  102 clock_pcctwo_attach(parent, self, aux)
  103         struct device *parent;
  104         struct device *self;
  105         void *aux;
  106 {
  107         struct clock_pcctwo_softc *sc;
  108         struct pcctwo_attach_args *pa;
  109 
  110         sc = clock_pcctwo_sc = device_private(self);
  111         pa = aux;
  112 
  113         if (pa->pa_ipl != CLOCK_LEVEL)
  114                 panic("clock_pcctwo_attach: wrong interrupt level");
  115 
  116         sc->sc_clock_args.ca_arg = sc;
  117         sc->sc_clock_args.ca_initfunc = clock_pcctwo_initclocks;
  118 
  119         /* Do common portions of clock config. */
  120         clock_config(self, &sc->sc_clock_args, pcctwointr_evcnt(pa->pa_ipl));
  121 
  122         /* Ensure our interrupts get disabled at shutdown time. */
  123         (void) shutdownhook_establish(clock_pcctwo_shutdown, NULL);
  124 
  125         sc->sc_clock_lvl = (pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK) |
  126             PCCTWO_ICR_ICLR | PCCTWO_ICR_IEN;
  127 
  128         /* Attach the interrupt handlers. */
  129         pcctwointr_establish(PCCTWOV_TIMER1, clock_pcctwo_profintr,
  130             pa->pa_ipl, NULL, &clock_profcnt);
  131         pcctwointr_establish(PCCTWOV_TIMER2, clock_pcctwo_statintr,
  132             pa->pa_ipl, NULL, &clock_statcnt);
  133 }
  134 
  135 void
  136 clock_pcctwo_initclocks(arg, prof_us, stat_us)
  137         void *arg;
  138         int prof_us;
  139         int stat_us;
  140 {
  141         struct clock_pcctwo_softc *sc;
  142 
  143         sc = arg;
  144 
  145         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
  146         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COUNTER, 0);
  147         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COMPARE,
  148             PCCTWO_US2LIM(prof_us));
  149         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
  150             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  151         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, sc->sc_clock_lvl);
  152 
  153         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  154         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
  155         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
  156             PCCTWO_US2LIM(stat_us));
  157         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
  158             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  159         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, sc->sc_clock_lvl);
  160 
  161         sc->sc_tc.tc_get_timecount = clock_pcctwo_getcount;
  162         sc->sc_tc.tc_name = "pcctwo_count";
  163         sc->sc_tc.tc_frequency = PCCTWO_TIMERFREQ;
  164         sc->sc_tc.tc_quality = 100;
  165         sc->sc_tc.tc_counter_mask = ~0;
  166         tc_init(&sc->sc_tc);
  167 }
  168 
  169 /* ARGSUSED */
  170 u_int
  171 clock_pcctwo_getcount(struct timecounter *tc)
  172 {
  173         u_int cnt;
  174         uint32_t tc1, tc2;
  175         uint8_t cr;
  176         int s;
  177 
  178         s = splhigh();
  179 
  180         /*
  181          * There's no way to latch the counter and overflow registers
  182          * without pausing the clock, so compensate for the possible
  183          * race by checking for counter wrap-around and re-reading the
  184          * overflow counter if necessary.
  185          *
  186          * Note: This only works because we're at splhigh().
  187          */
  188         tc1 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  189         cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  190         tc2 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  191         if (tc1 > tc2) {
  192                 cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  193                 tc1 = tc2;
  194         }
  195         cnt = clock_pcctwo_count;
  196         splx(s);
  197         /* XXX assume HZ == 100 */
  198         cnt += tc1 + (PCCTWO_TIMERFREQ / 100) * PCCTWO_TT_CTRL_OVF(cr);
  199 
  200         return cnt;
  201 }
  202 
  203 int
  204 clock_pcctwo_profintr(frame)
  205         void *frame;
  206 {
  207         u_int8_t cr;
  208         u_int32_t tc;
  209         int s;
  210 
  211         s = splhigh();
  212         tc = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  213         cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  214         if (tc > pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER))
  215                 cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  216         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
  217             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  218         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR,
  219             clock_pcctwo_sc->sc_clock_lvl);
  220         splx(s);
  221 
  222         for (cr = PCCTWO_TT_CTRL_OVF(cr); cr; cr--) {
  223                 /* XXX assume HZ == 100 */
  224                 clock_pcctwo_count += PCCTWO_TIMERFREQ / 100;
  225                 hardclock(frame);
  226         }
  227 
  228         return (1);
  229 }
  230 
  231 int
  232 clock_pcctwo_statintr(frame)
  233         void *frame;
  234 {
  235 
  236         /* Disable the timer interrupt while we handle it. */
  237         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
  238 
  239         statclock((struct clockframe *) frame);
  240 
  241         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  242         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
  243         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
  244             PCCTWO_US2LIM(CLOCK_NEWINT(clock_statvar, clock_statmin)));
  245         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
  246             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  247 
  248         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR,
  249             clock_pcctwo_sc->sc_clock_lvl);
  250 
  251         return (1);
  252 }
  253 
  254 /* ARGSUSED */
  255 void
  256 clock_pcctwo_shutdown(arg)
  257         void *arg;
  258 {
  259 
  260         /* Make sure the timer interrupts are turned off. */
  261         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
  262         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, 0);
  263         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  264         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
  265 }

Cache object: 0eff8b1e7b0591fc1cd92bf9bb1074fa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.