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/arm/cavium/cns11xx/timer.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 /*-
    2  * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/bus.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/malloc.h>
   35 #include <sys/rman.h>
   36 #include <sys/timetc.h>
   37 #include <sys/watchdog.h>
   38 #include <machine/bus.h>
   39 #include <machine/cpu.h>
   40 #include <machine/intr.h>
   41 
   42 #include "econa_reg.h"
   43 #include "econa_var.h"
   44 
   45 #define INITIAL_TIMECOUNTER     (0xffffffff)
   46 
   47 static int timers_initialized = 0;
   48 
   49 #define HZ      100
   50 
   51 extern unsigned int CPU_clock;
   52 extern unsigned int AHB_clock;
   53 extern unsigned int APB_clock;
   54 
   55 static unsigned long timer_counter = 0;
   56 
   57 struct ec_timer_softc {
   58         struct resource *       timer_res[3];
   59         bus_space_tag_t         timer_bst;
   60         bus_space_handle_t      timer_bsh;
   61         struct mtx              timer_mtx;
   62 };
   63 
   64 static struct resource_spec ec_timer_spec[] = {
   65         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   66         { SYS_RES_IRQ,          0,      RF_ACTIVE },
   67         { SYS_RES_IRQ,          1,      RF_ACTIVE },
   68         { -1, 0 }
   69 };
   70 
   71 static unsigned ec_timer_get_timecount(struct timecounter *);
   72 
   73 static struct timecounter ec_timecounter = {
   74         .tc_get_timecount = ec_timer_get_timecount,
   75         .tc_name = "CPU Timer",
   76         /* This is assigned on the fly in the init sequence */
   77         .tc_frequency = 0,
   78         .tc_counter_mask = ~0u,
   79         .tc_quality = 1000,
   80 };
   81 
   82 static struct ec_timer_softc *timer_softc = NULL;
   83 
   84 static inline
   85 void write_4(unsigned int val, unsigned int addr)
   86 {
   87         bus_space_write_4(timer_softc->timer_bst,
   88                           timer_softc->timer_bsh, addr, val);
   89 
   90 }
   91 
   92 static inline
   93 unsigned int read_4(unsigned int addr)
   94 {
   95 
   96         return bus_space_read_4(timer_softc->timer_bst,
   97             timer_softc->timer_bsh, addr);
   98 }
   99 
  100 #define uSECS_PER_TICK  (1000000 / APB_clock)
  101 #define TICKS2USECS(x)  ((x) * uSECS_PER_TICK)
  102 
  103 static unsigned
  104 read_timer_counter_noint(void)
  105 {
  106 
  107         arm_mask_irq(0);
  108         unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
  109         arm_unmask_irq(0);
  110         return v;
  111 }
  112 
  113 void
  114 DELAY(int usec)
  115 {
  116         uint32_t val, val_temp;
  117         int nticks;
  118 
  119         if (!timers_initialized) {
  120                 for (; usec > 0; usec--)
  121                         for (val = 100; val > 0; val--)
  122                                 ;
  123                 return;
  124         }
  125 
  126         val = read_timer_counter_noint();
  127         nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
  128 
  129         while (nticks > 0) {
  130                 val_temp = read_timer_counter_noint();
  131                 if (val > val_temp)
  132                         nticks -= (val - val_temp);
  133                 else
  134                         nticks -= (val + (timer_counter - val_temp));
  135 
  136                 val = val_temp;
  137         }
  138 
  139 }
  140 
  141 /*
  142  * Setup timer
  143  */
  144 static inline void
  145 setup_timer(unsigned int counter_value)
  146 {
  147         unsigned int control_value;
  148         unsigned int mask_value;
  149 
  150         control_value = read_4(TIMER_TM_CR_REG);
  151 
  152         mask_value = read_4(TIMER_TM_INTR_MASK_REG);
  153         write_4(counter_value, TIMER_TM1_COUNTER_REG);
  154         write_4(counter_value, TIMER_TM1_LOAD_REG);
  155         write_4(0, TIMER_TM1_MATCH1_REG);
  156         write_4(0,TIMER_TM1_MATCH2_REG);
  157 
  158         control_value &= ~(TIMER1_CLOCK_SOURCE);
  159         control_value |= TIMER1_UP_DOWN_COUNT;
  160 
  161         write_4(0, TIMER_TM2_COUNTER_REG);
  162         write_4(0, TIMER_TM2_LOAD_REG);
  163         write_4(~0u, TIMER_TM2_MATCH1_REG);
  164         write_4(~0u,TIMER_TM2_MATCH2_REG);
  165 
  166         control_value &= ~(TIMER2_CLOCK_SOURCE);
  167         control_value &= ~(TIMER2_UP_DOWN_COUNT);
  168 
  169         mask_value &= ~(63);
  170 
  171         write_4(control_value, TIMER_TM_CR_REG);
  172         write_4(mask_value, TIMER_TM_INTR_MASK_REG);
  173 }
  174 
  175 /*
  176  * Enable timer
  177  */
  178 static inline void
  179 timer_enable(void)
  180 {
  181         unsigned int control_value;
  182 
  183         control_value = read_4(TIMER_TM_CR_REG);
  184 
  185         control_value |= TIMER1_OVERFLOW_ENABLE;
  186         control_value |= TIMER1_ENABLE;
  187         control_value |= TIMER2_OVERFLOW_ENABLE;
  188         control_value |= TIMER2_ENABLE;
  189 
  190         write_4(control_value, TIMER_TM_CR_REG);
  191 }
  192 
  193 static inline unsigned int
  194 read_second_timer_counter(void)
  195 {
  196 
  197         return read_4(TIMER_TM2_COUNTER_REG);
  198 }
  199 
  200 /*
  201  * Get timer interrupt status
  202  */
  203 static inline unsigned int
  204 read_timer_interrupt_status(void)
  205 {
  206 
  207         return read_4(TIMER_TM_INTR_STATUS_REG);
  208 }
  209 
  210 /*
  211  * Clear timer interrupt status
  212  */
  213 static inline void
  214 clear_timer_interrupt_status(unsigned int irq)
  215 {
  216         unsigned int interrupt_status;
  217 
  218         interrupt_status =   read_4(TIMER_TM_INTR_STATUS_REG);
  219         if (irq == 0) {
  220                 if (interrupt_status & (TIMER1_MATCH1_INTR))
  221                         interrupt_status &= ~(TIMER1_MATCH1_INTR);
  222                 if (interrupt_status & (TIMER1_MATCH2_INTR))
  223                         interrupt_status &= ~(TIMER1_MATCH2_INTR);
  224                 if (interrupt_status & (TIMER1_OVERFLOW_INTR))
  225                         interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
  226         }
  227         if (irq == 1) {
  228                 if (interrupt_status & (TIMER2_MATCH1_INTR))
  229                         interrupt_status &= ~(TIMER2_MATCH1_INTR);
  230                 if (interrupt_status & (TIMER2_MATCH2_INTR))
  231                         interrupt_status &= ~(TIMER2_MATCH2_INTR);
  232                 if (interrupt_status & (TIMER2_OVERFLOW_INTR))
  233                         interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
  234         }
  235 
  236         write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
  237 }
  238 
  239 static unsigned
  240 ec_timer_get_timecount(struct timecounter *a)
  241 {
  242         unsigned int ticks1;
  243         arm_mask_irq(1);
  244         ticks1 = read_second_timer_counter();
  245         arm_unmask_irq(1);
  246         return ticks1;
  247 }
  248 
  249 /*
  250  * Setup timer
  251  */
  252 static inline void
  253 do_setup_timer(void)
  254 {
  255 
  256         timer_counter = APB_clock/HZ;
  257         /*
  258          * setup timer-related values
  259          */
  260         setup_timer(timer_counter);
  261 }
  262 
  263 void
  264 cpu_initclocks(void)
  265 {
  266 
  267         ec_timecounter.tc_frequency = APB_clock;
  268         tc_init(&ec_timecounter);
  269         timer_enable();
  270         timers_initialized = 1;
  271 }
  272 
  273 void
  274 cpu_startprofclock(void)
  275 {
  276 
  277 }
  278 
  279 void
  280 cpu_stopprofclock(void)
  281 {
  282 
  283 }
  284 
  285 static int
  286 ec_timer_probe(device_t dev)
  287 {
  288 
  289         device_set_desc(dev, "Econa CPU Timer");
  290         return (0);
  291 }
  292 
  293 static int
  294 ec_reset(void *arg)
  295 {
  296 
  297         arm_mask_irq(1);
  298         clear_timer_interrupt_status(1);
  299         arm_unmask_irq(1);
  300         return (FILTER_HANDLED);
  301 }
  302 
  303 static int
  304 ec_hardclock(void *arg)
  305 {
  306         struct  trapframe *frame;
  307         unsigned int val;
  308         /*clear timer interrupt status*/
  309 
  310         arm_mask_irq(0);
  311 
  312         val = read_4(TIMER_INTERRUPT_STATUS_REG);
  313         val &= ~(TIMER1_OVERFLOW_INTERRUPT);
  314         write_4(val, TIMER_INTERRUPT_STATUS_REG);
  315 
  316         frame = (struct trapframe *)arg;
  317         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
  318 
  319         arm_unmask_irq(0);
  320 
  321         return (FILTER_HANDLED);
  322 }
  323 
  324 static int
  325 ec_timer_attach(device_t dev)
  326 {
  327         struct  ec_timer_softc *sc;
  328         int     error;
  329         void    *ihl;
  330 
  331 
  332         if (timer_softc != NULL)
  333                 return (ENXIO);
  334 
  335         sc = (struct ec_timer_softc *)device_get_softc(dev);
  336 
  337         timer_softc = sc;
  338 
  339         error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
  340         if (error) {
  341                 device_printf(dev, "could not allocate resources\n");
  342                 return (ENXIO);
  343         }
  344 
  345         sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
  346         sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
  347 
  348         do_setup_timer();
  349 
  350         if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
  351             ec_hardclock, NULL, NULL, &ihl) != 0) {
  352                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
  353                 device_printf(dev, "could not setup hardclock interrupt\n");
  354                 return (ENXIO);
  355         }
  356 
  357         if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
  358             ec_reset, NULL, NULL, &ihl) != 0) {
  359                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
  360                 device_printf(dev, "could not setup timer interrupt\n");
  361                 return (ENXIO);
  362         }
  363 
  364         return (0);
  365 }
  366 
  367 static device_method_t ec_timer_methods[] = {
  368         DEVMETHOD(device_probe, ec_timer_probe),
  369         DEVMETHOD(device_attach, ec_timer_attach),
  370         { 0, 0 }
  371 };
  372 
  373 static driver_t ec_timer_driver = {
  374         "timer",
  375         ec_timer_methods,
  376         sizeof(struct ec_timer_softc),
  377 };
  378 
  379 static devclass_t ec_timer_devclass;
  380 
  381 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);

Cache object: ad523c91e061cbc1285a2f23f4c2cc5c


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