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/econa/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: releng/9.0/sys/arm/econa/timer.c 201468 2010-01-04 03:35:45Z rpaulo $");
   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/frame.h>
   41 #include <machine/intr.h>
   42 
   43 #include "econa_reg.h"
   44 #include "econa_var.h"
   45 
   46 #define INITIAL_TIMECOUNTER     (0xffffffff)
   47 
   48 static int timers_initialized = 0;
   49 
   50 #define HZ      100
   51 
   52 extern unsigned int CPU_clock;
   53 extern unsigned int AHB_clock;
   54 extern unsigned int APB_clock;
   55 
   56 static unsigned long timer_counter = 0;
   57 
   58 struct ec_timer_softc {
   59         struct resource *       timer_res[3];
   60         bus_space_tag_t         timer_bst;
   61         bus_space_handle_t      timer_bsh;
   62         struct mtx              timer_mtx;
   63 };
   64 
   65 static struct resource_spec ec_timer_spec[] = {
   66         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   67         { SYS_RES_IRQ,          0,      RF_ACTIVE },
   68         { SYS_RES_IRQ,          1,      RF_ACTIVE },
   69         { -1, 0 }
   70 };
   71 
   72 static unsigned ec_timer_get_timecount(struct timecounter *);
   73 
   74 static struct timecounter ec_timecounter = {
   75         .tc_get_timecount = ec_timer_get_timecount,
   76         .tc_name = "CPU Timer",
   77         /* This is assigned on the fly in the init sequence */
   78         .tc_frequency = 0,
   79         .tc_counter_mask = ~0u,
   80         .tc_quality = 1000,
   81 };
   82 
   83 static struct ec_timer_softc *timer_softc = NULL;
   84 
   85 static inline
   86 void write_4(unsigned int val, unsigned int addr)
   87 {
   88         bus_space_write_4(timer_softc->timer_bst,
   89                           timer_softc->timer_bsh, addr, val);
   90 
   91 }
   92 
   93 static inline
   94 unsigned int read_4(unsigned int addr)
   95 {
   96 
   97         return bus_space_read_4(timer_softc->timer_bst,
   98             timer_softc->timer_bsh, addr);
   99 }
  100 
  101 #define uSECS_PER_TICK  (1000000 / APB_clock)
  102 #define TICKS2USECS(x)  ((x) * uSECS_PER_TICK)
  103 
  104 static unsigned
  105 read_timer_counter_noint(void)
  106 {
  107 
  108         arm_mask_irq(0);
  109         unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
  110         arm_unmask_irq(0);
  111         return v;
  112 }
  113 
  114 void
  115 DELAY(int usec)
  116 {
  117         uint32_t val, val_temp;
  118         int nticks;
  119 
  120         if (!timers_initialized) {
  121                 for (; usec > 0; usec--)
  122                         for (val = 100; val > 0; val--)
  123                                 ;
  124                 return;
  125         }
  126 
  127         val = read_timer_counter_noint();
  128         nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
  129 
  130         while (nticks > 0) {
  131                 val_temp = read_timer_counter_noint();
  132                 if (val > val_temp)
  133                         nticks -= (val - val_temp);
  134                 else
  135                         nticks -= (val + (timer_counter - val_temp));
  136 
  137                 val = val_temp;
  138         }
  139 
  140 }
  141 
  142 /*
  143  * Setup timer
  144  */
  145 static inline void
  146 setup_timer(unsigned int counter_value)
  147 {
  148         unsigned int control_value;
  149         unsigned int mask_value;
  150 
  151         control_value = read_4(TIMER_TM_CR_REG);
  152 
  153         mask_value = read_4(TIMER_TM_INTR_MASK_REG);
  154         write_4(counter_value, TIMER_TM1_COUNTER_REG);
  155         write_4(counter_value, TIMER_TM1_LOAD_REG);
  156         write_4(0, TIMER_TM1_MATCH1_REG);
  157         write_4(0,TIMER_TM1_MATCH2_REG);
  158 
  159         control_value &= ~(TIMER1_CLOCK_SOURCE);
  160         control_value |= TIMER1_UP_DOWN_COUNT;
  161 
  162         write_4(0, TIMER_TM2_COUNTER_REG);
  163         write_4(0, TIMER_TM2_LOAD_REG);
  164         write_4(~0u, TIMER_TM2_MATCH1_REG);
  165         write_4(~0u,TIMER_TM2_MATCH2_REG);
  166 
  167         control_value &= ~(TIMER2_CLOCK_SOURCE);
  168         control_value &= ~(TIMER2_UP_DOWN_COUNT);
  169 
  170         mask_value &= ~(63);
  171 
  172         write_4(control_value, TIMER_TM_CR_REG);
  173         write_4(mask_value, TIMER_TM_INTR_MASK_REG);
  174 }
  175 
  176 /*
  177  * Enable timer
  178  */
  179 static inline void
  180 timer_enable(void)
  181 {
  182         unsigned int control_value;
  183 
  184         control_value = read_4(TIMER_TM_CR_REG);
  185 
  186         control_value |= TIMER1_OVERFLOW_ENABLE;
  187         control_value |= TIMER1_ENABLE;
  188         control_value |= TIMER2_OVERFLOW_ENABLE;
  189         control_value |= TIMER2_ENABLE;
  190 
  191         write_4(control_value, TIMER_TM_CR_REG);
  192 }
  193 
  194 static inline unsigned int
  195 read_second_timer_counter(void)
  196 {
  197 
  198         return read_4(TIMER_TM2_COUNTER_REG);
  199 }
  200 
  201 /*
  202  * Get timer interrupt status
  203  */
  204 static inline unsigned int
  205 read_timer_interrupt_status(void)
  206 {
  207 
  208         return read_4(TIMER_TM_INTR_STATUS_REG);
  209 }
  210 
  211 /*
  212  * Clear timer interrupt status
  213  */
  214 static inline void
  215 clear_timer_interrupt_status(unsigned int irq)
  216 {
  217         unsigned int interrupt_status;
  218 
  219         interrupt_status =   read_4(TIMER_TM_INTR_STATUS_REG);
  220         if (irq == 0) {
  221                 if (interrupt_status & (TIMER1_MATCH1_INTR))
  222                         interrupt_status &= ~(TIMER1_MATCH1_INTR);
  223                 if (interrupt_status & (TIMER1_MATCH2_INTR))
  224                         interrupt_status &= ~(TIMER1_MATCH2_INTR);
  225                 if (interrupt_status & (TIMER1_OVERFLOW_INTR))
  226                         interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
  227         }
  228         if (irq == 1) {
  229                 if (interrupt_status & (TIMER2_MATCH1_INTR))
  230                         interrupt_status &= ~(TIMER2_MATCH1_INTR);
  231                 if (interrupt_status & (TIMER2_MATCH2_INTR))
  232                         interrupt_status &= ~(TIMER2_MATCH2_INTR);
  233                 if (interrupt_status & (TIMER2_OVERFLOW_INTR))
  234                         interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
  235         }
  236 
  237         write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
  238 }
  239 
  240 static unsigned
  241 ec_timer_get_timecount(struct timecounter *a)
  242 {
  243         unsigned int ticks1;
  244         arm_mask_irq(1);
  245         ticks1 = read_second_timer_counter();
  246         arm_unmask_irq(1);
  247         return ticks1;
  248 }
  249 
  250 /*
  251  * Setup timer
  252  */
  253 static inline void
  254 do_setup_timer(void)
  255 {
  256 
  257         timer_counter = APB_clock/HZ;
  258         /*
  259          * setup timer-related values
  260          */
  261         setup_timer(timer_counter);
  262 }
  263 
  264 void
  265 cpu_initclocks(void)
  266 {
  267 
  268         ec_timecounter.tc_frequency = APB_clock;
  269         tc_init(&ec_timecounter);
  270         timer_enable();
  271         timers_initialized = 1;
  272 }
  273 
  274 void
  275 cpu_startprofclock(void)
  276 {
  277 
  278 }
  279 
  280 void
  281 cpu_stopprofclock(void)
  282 {
  283 
  284 }
  285 
  286 static int
  287 ec_timer_probe(device_t dev)
  288 {
  289 
  290         device_set_desc(dev, "Econa CPU Timer");
  291         return (0);
  292 }
  293 
  294 static int
  295 ec_reset(void *arg)
  296 {
  297 
  298         arm_mask_irq(1);
  299         clear_timer_interrupt_status(1);
  300         arm_unmask_irq(1);
  301         return (FILTER_HANDLED);
  302 }
  303 
  304 static int
  305 ec_hardclock(void *arg)
  306 {
  307         struct  trapframe *frame;
  308         unsigned int val;
  309         /*clear timer interrupt status*/
  310 
  311         arm_mask_irq(0);
  312 
  313         val = read_4(TIMER_INTERRUPT_STATUS_REG);
  314         val &= ~(TIMER1_OVERFLOW_INTERRUPT);
  315         write_4(val, TIMER_INTERRUPT_STATUS_REG);
  316 
  317         frame = (struct trapframe *)arg;
  318         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
  319 
  320         arm_unmask_irq(0);
  321 
  322         return (FILTER_HANDLED);
  323 }
  324 
  325 static int
  326 ec_timer_attach(device_t dev)
  327 {
  328         struct  ec_timer_softc *sc;
  329         int     error;
  330         void    *ihl;
  331 
  332 
  333         if (timer_softc != NULL)
  334                 return (ENXIO);
  335 
  336         sc = (struct ec_timer_softc *)device_get_softc(dev);
  337 
  338         timer_softc = sc;
  339 
  340         error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
  341         if (error) {
  342                 device_printf(dev, "could not allocate resources\n");
  343                 return (ENXIO);
  344         }
  345 
  346         sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
  347         sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
  348 
  349         do_setup_timer();
  350 
  351         if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
  352             ec_hardclock, NULL, NULL, &ihl) != 0) {
  353                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
  354                 device_printf(dev, "could not setup hardclock interrupt\n");
  355                 return (ENXIO);
  356         }
  357 
  358         if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
  359             ec_reset, NULL, NULL, &ihl) != 0) {
  360                 bus_release_resources(dev, ec_timer_spec, sc->timer_res);
  361                 device_printf(dev, "could not setup timer interrupt\n");
  362                 return (ENXIO);
  363         }
  364 
  365         return (0);
  366 }
  367 
  368 static device_method_t ec_timer_methods[] = {
  369         DEVMETHOD(device_probe, ec_timer_probe),
  370         DEVMETHOD(device_attach, ec_timer_attach),
  371         { 0, 0 }
  372 };
  373 
  374 static driver_t ec_timer_driver = {
  375         "timer",
  376         ec_timer_methods,
  377         sizeof(struct ec_timer_softc),
  378 };
  379 
  380 static devclass_t ec_timer_devclass;
  381 
  382 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);

Cache object: dd203e187d1f20380895988a61256053


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