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.17 2012/10/27 17:18:27 chs 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.17 2012/10/27 17:18:27 chs 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(device_t, cfdata_t, void *);
   56 void clock_pcctwo_attach(device_t, device_t, void *);
   57 
   58 struct clock_pcctwo_softc {
   59         struct clock_attach_args sc_clock_args;
   60         u_char sc_clock_lvl;
   61         struct timecounter sc_tc;
   62 };
   63 
   64 CFATTACH_DECL_NEW(clock_pcctwo, sizeof(struct clock_pcctwo_softc),
   65     clock_pcctwo_match, clock_pcctwo_attach, NULL, NULL);
   66 
   67 extern struct cfdriver clock_cd;
   68 
   69 static int clock_pcctwo_profintr(void *);
   70 static int clock_pcctwo_statintr(void *);
   71 static void clock_pcctwo_initclocks(void *, int, int);
   72 static u_int clock_pcctwo_getcount(struct timecounter *);
   73 static void clock_pcctwo_shutdown(void *);
   74 
   75 static struct clock_pcctwo_softc *clock_pcctwo_sc;
   76 static uint32_t clock_pcctwo_count;
   77 
   78 /* ARGSUSED */
   79 int
   80 clock_pcctwo_match(device_t parent, cfdata_t cf, void *aux)
   81 {
   82         struct pcctwo_attach_args *pa = aux;
   83 
   84         /* Only one clock, please. */
   85         if (clock_pcctwo_sc)
   86                 return (0);
   87 
   88         if (strcmp(pa->pa_name, clock_cd.cd_name))
   89                 return (0);
   90 
   91         pa->pa_ipl = cf->pcctwocf_ipl;
   92 
   93         return (1);
   94 }
   95 
   96 /* ARGSUSED */
   97 void
   98 clock_pcctwo_attach(device_t parent, device_t self, void *aux)
   99 {
  100         struct clock_pcctwo_softc *sc;
  101         struct pcctwo_attach_args *pa;
  102 
  103         sc = clock_pcctwo_sc = device_private(self);
  104         pa = aux;
  105 
  106         if (pa->pa_ipl != CLOCK_LEVEL)
  107                 panic("clock_pcctwo_attach: wrong interrupt level");
  108 
  109         sc->sc_clock_args.ca_arg = sc;
  110         sc->sc_clock_args.ca_initfunc = clock_pcctwo_initclocks;
  111 
  112         /* Do common portions of clock config. */
  113         clock_config(self, &sc->sc_clock_args, pcctwointr_evcnt(pa->pa_ipl));
  114 
  115         /* Ensure our interrupts get disabled at shutdown time. */
  116         (void) shutdownhook_establish(clock_pcctwo_shutdown, NULL);
  117 
  118         sc->sc_clock_lvl = (pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK) |
  119             PCCTWO_ICR_ICLR | PCCTWO_ICR_IEN;
  120 
  121         /* Attach the interrupt handlers. */
  122         pcctwointr_establish(PCCTWOV_TIMER1, clock_pcctwo_profintr,
  123             pa->pa_ipl, NULL, &clock_profcnt);
  124         pcctwointr_establish(PCCTWOV_TIMER2, clock_pcctwo_statintr,
  125             pa->pa_ipl, NULL, &clock_statcnt);
  126 }
  127 
  128 void
  129 clock_pcctwo_initclocks(void *arg, int prof_us, int stat_us)
  130 {
  131         struct clock_pcctwo_softc *sc;
  132 
  133         sc = arg;
  134 
  135         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
  136         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COUNTER, 0);
  137         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COMPARE,
  138             PCCTWO_US2LIM(prof_us));
  139         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
  140             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  141         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, sc->sc_clock_lvl);
  142 
  143         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  144         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
  145         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
  146             PCCTWO_US2LIM(stat_us));
  147         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
  148             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  149         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, sc->sc_clock_lvl);
  150 
  151         sc->sc_tc.tc_get_timecount = clock_pcctwo_getcount;
  152         sc->sc_tc.tc_name = "pcctwo_count";
  153         sc->sc_tc.tc_frequency = PCCTWO_TIMERFREQ;
  154         sc->sc_tc.tc_quality = 100;
  155         sc->sc_tc.tc_counter_mask = ~0;
  156         tc_init(&sc->sc_tc);
  157 }
  158 
  159 /* ARGSUSED */
  160 u_int
  161 clock_pcctwo_getcount(struct timecounter *tc)
  162 {
  163         u_int cnt;
  164         uint32_t tc1, tc2;
  165         uint8_t cr;
  166         int s;
  167 
  168         s = splhigh();
  169 
  170         /*
  171          * There's no way to latch the counter and overflow registers
  172          * without pausing the clock, so compensate for the possible
  173          * race by checking for counter wrap-around and re-reading the
  174          * overflow counter if necessary.
  175          *
  176          * Note: This only works because we're at splhigh().
  177          */
  178         tc1 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  179         cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  180         tc2 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  181         if (tc1 > tc2) {
  182                 cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  183                 tc1 = tc2;
  184         }
  185         cnt = clock_pcctwo_count;
  186         splx(s);
  187         /* XXX assume HZ == 100 */
  188         cnt += tc1 + (PCCTWO_TIMERFREQ / 100) * PCCTWO_TT_CTRL_OVF(cr);
  189 
  190         return cnt;
  191 }
  192 
  193 int
  194 clock_pcctwo_profintr(void *frame)
  195 {
  196         u_int8_t cr;
  197         u_int32_t tc;
  198         int s;
  199 
  200         s = splhigh();
  201         tc = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
  202         cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  203         if (tc > pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER))
  204                 cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
  205         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
  206             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  207         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR,
  208             clock_pcctwo_sc->sc_clock_lvl);
  209         splx(s);
  210 
  211         for (cr = PCCTWO_TT_CTRL_OVF(cr); cr; cr--) {
  212                 /* XXX assume HZ == 100 */
  213                 clock_pcctwo_count += PCCTWO_TIMERFREQ / 100;
  214                 hardclock(frame);
  215         }
  216 
  217         return (1);
  218 }
  219 
  220 int
  221 clock_pcctwo_statintr(void *frame)
  222 {
  223 
  224         /* Disable the timer interrupt while we handle it. */
  225         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
  226 
  227         statclock((struct clockframe *) frame);
  228 
  229         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  230         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
  231         pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
  232             PCCTWO_US2LIM(CLOCK_NEWINT(clock_statvar, clock_statmin)));
  233         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
  234             PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
  235 
  236         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR,
  237             clock_pcctwo_sc->sc_clock_lvl);
  238 
  239         return (1);
  240 }
  241 
  242 /* ARGSUSED */
  243 void
  244 clock_pcctwo_shutdown(void *arg)
  245 {
  246 
  247         /* Make sure the timer interrupts are turned off. */
  248         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
  249         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, 0);
  250         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
  251         pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
  252 }

Cache object: 2450dea6d3a489aaaa0dfdb67cf821dc


[ 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.