uboot/cpu/arm1176/s3c64xx/timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003
   3 * Texas Instruments <www.ti.com>
   4 *
   5 * (C) Copyright 2002
   6 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   7 * Marius Groeger <mgroeger@sysgo.de>
   8 *
   9 * (C) Copyright 2002
  10 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  11 * Alex Zuepke <azu@sysgo.de>
  12 *
  13 * (C) Copyright 2002-2004
  14 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
  15 *
  16 * (C) Copyright 2004
  17 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
  18 *
  19 * (C) Copyright 2008
  20 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
  21 *
  22 * See file CREDITS for list of people who contributed to this
  23 * project.
  24 *
  25 * This program is free software; you can redistribute it and/or
  26 * modify it under the terms of the GNU General Public License as
  27 * published by the Free Software Foundation; either version 2 of
  28 * the License, or (at your option) any later version.
  29 *
  30 * This program is distributed in the hope that it will be useful,
  31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  33 * GNU General Public License for more details.
  34 *
  35 * You should have received a copy of the GNU General Public License
  36 * along with this program; if not, write to the Free Software
  37 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  38 * MA 02111-1307 USA
  39 */
  40
  41#include <common.h>
  42#include <asm/proc-armv/ptrace.h>
  43#include <s3c6400.h>
  44#include <div64.h>
  45
  46static ulong timer_load_val;
  47
  48#define PRESCALER       167
  49
  50static s3c64xx_timers *s3c64xx_get_base_timers(void)
  51{
  52        return (s3c64xx_timers *)ELFIN_TIMER_BASE;
  53}
  54
  55/* macro to read the 16 bit timer */
  56static inline ulong read_timer(void)
  57{
  58        s3c64xx_timers *const timers = s3c64xx_get_base_timers();
  59
  60        return timers->TCNTO4;
  61}
  62
  63/* Internal tick units */
  64/* Last decremneter snapshot */
  65static unsigned long lastdec;
  66/* Monotonic incrementing timer */
  67static unsigned long long timestamp;
  68
  69int timer_init(void)
  70{
  71        s3c64xx_timers *const timers = s3c64xx_get_base_timers();
  72
  73        /* use PWM Timer 4 because it has no output */
  74        /*
  75         * We use the following scheme for the timer:
  76         * Prescaler is hard fixed at 167, divider at 1/4.
  77         * This gives at PCLK frequency 66MHz approx. 10us ticks
  78         * The timer is set to wrap after 100s, at 66MHz this obviously
  79         * happens after 10,000,000 ticks. A long variable can thus
  80         * keep values up to 40,000s, i.e., 11 hours. This should be
  81         * enough for most uses:-) Possible optimizations: select a
  82         * binary-friendly frequency, e.g., 1ms / 128. Also calculate
  83         * the prescaler automatically for other PCLK frequencies.
  84         */
  85        timers->TCFG0 = PRESCALER << 8;
  86        if (timer_load_val == 0) {
  87                timer_load_val = get_PCLK() / PRESCALER * (100 / 4); /* 100s */
  88                timers->TCFG1 = (timers->TCFG1 & ~0xf0000) | 0x20000;
  89        }
  90
  91        /* load value for 10 ms timeout */
  92        lastdec = timers->TCNTB4 = timer_load_val;
  93        /* auto load, manual update of Timer 4 */
  94        timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO |
  95                TCON_4_UPDATE;
  96
  97        /* auto load, start Timer 4 */
  98        timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
  99        timestamp = 0;
 100
 101        return 0;
 102}
 103
 104/*
 105 * timer without interrupts
 106 */
 107
 108/*
 109 * This function is derived from PowerPC code (read timebase as long long).
 110 * On ARM it just returns the timer value.
 111 */
 112unsigned long long get_ticks(void)
 113{
 114        ulong now = read_timer();
 115
 116        if (lastdec >= now) {
 117                /* normal mode */
 118                timestamp += lastdec - now;
 119        } else {
 120                /* we have an overflow ... */
 121                timestamp += lastdec + timer_load_val - now;
 122        }
 123        lastdec = now;
 124
 125        return timestamp;
 126}
 127
 128/*
 129 * This function is derived from PowerPC code (timebase clock frequency).
 130 * On ARM it returns the number of timer ticks per second.
 131 */
 132ulong get_tbclk(void)
 133{
 134        /* We overrun in 100s */
 135        return (ulong)(timer_load_val / 100);
 136}
 137
 138void reset_timer_masked(void)
 139{
 140        /* reset time */
 141        lastdec = read_timer();
 142        timestamp = 0;
 143}
 144
 145void reset_timer(void)
 146{
 147        reset_timer_masked();
 148}
 149
 150ulong get_timer_masked(void)
 151{
 152        unsigned long long res = get_ticks();
 153        do_div (res, (timer_load_val / (100 * CONFIG_SYS_HZ)));
 154        return res;
 155}
 156
 157ulong get_timer(ulong base)
 158{
 159        return get_timer_masked() - base;
 160}
 161
 162void set_timer(ulong t)
 163{
 164        timestamp = t * (timer_load_val / (100 * CONFIG_SYS_HZ));
 165}
 166
 167void udelay(unsigned long usec)
 168{
 169        unsigned long long tmp;
 170        ulong tmo;
 171
 172        tmo = (usec + 9) / 10;
 173        tmp = get_ticks() + tmo;        /* get current timestamp */
 174
 175        while (get_ticks() < tmp)/* loop till event */
 176                 /*NOP*/;
 177}
 178