uboot/cpu/arm_cortexa8/s5pc1xx/timer.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Samsung Electronics
   3 * Heungjun Kim <riverful.kim@samsung.com>
   4 * Inki Dae <inki.dae@samsung.com>
   5 * Minkyu Kang <mk7.kang@samsung.com>
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <common.h>
  27#include <asm/io.h>
  28#include <asm/arch/pwm.h>
  29#include <asm/arch/clk.h>
  30
  31#define PRESCALER_1             (16 - 1)        /* prescaler of timer 2, 3, 4 */
  32#define MUX_DIV_2               1               /* 1/2 period */
  33#define MUX_DIV_4               2               /* 1/4 period */
  34#define MUX_DIV_8               3               /* 1/8 period */
  35#define MUX_DIV_16              4               /* 1/16 period */
  36#define MUX4_DIV_SHIFT          16
  37
  38#define TCON_TIMER4_SHIFT       20
  39
  40static unsigned long count_value;
  41
  42/* Internal tick units */
  43static unsigned long long timestamp;    /* Monotonic incrementing timer */
  44static unsigned long lastdec;           /* Last decremneter snapshot */
  45
  46/* macro to read the 16 bit timer */
  47static inline struct s5pc1xx_timer *s5pc1xx_get_base_timer(void)
  48{
  49        if (cpu_is_s5pc110())
  50                return (struct s5pc1xx_timer *)S5PC110_TIMER_BASE;
  51        else
  52                return (struct s5pc1xx_timer *)S5PC100_TIMER_BASE;
  53}
  54
  55int timer_init(void)
  56{
  57        struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  58        u32 val;
  59
  60        /*
  61         * @ PWM Timer 4
  62         * Timer Freq(HZ) =
  63         *      PCLK / { (prescaler_value + 1) * (divider_value) }
  64         */
  65
  66        /* set prescaler : 16 */
  67        /* set divider : 2 */
  68        writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);
  69        writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);
  70
  71        if (count_value == 0) {
  72                /* reset initial value */
  73                /* count_value = 2085937.5(HZ) (per 1 sec)*/
  74                count_value = get_pclk() / ((PRESCALER_1 + 1) *
  75                                (MUX_DIV_2 + 1));
  76
  77                /* count_value / 100 = 20859.375(HZ) (per 10 msec) */
  78                count_value = count_value / 100;
  79        }
  80
  81        /* set count value */
  82        writel(count_value, &timer->tcntb4);
  83        lastdec = count_value;
  84
  85        val = (readl(&timer->tcon) & ~(0x07 << TCON_TIMER4_SHIFT)) |
  86                S5PC1XX_TCON4_AUTO_RELOAD;
  87
  88        /* auto reload & manual update */
  89        writel(val | S5PC1XX_TCON4_UPDATE, &timer->tcon);
  90
  91        /* start PWM timer 4 */
  92        writel(val | S5PC1XX_TCON4_START, &timer->tcon);
  93
  94        timestamp = 0;
  95
  96        return 0;
  97}
  98
  99/*
 100 * timer without interrupts
 101 */
 102void reset_timer(void)
 103{
 104        reset_timer_masked();
 105}
 106
 107unsigned long get_timer(unsigned long base)
 108{
 109        return get_timer_masked() - base;
 110}
 111
 112void set_timer(unsigned long t)
 113{
 114        timestamp = t;
 115}
 116
 117/* delay x useconds */
 118void __udelay(unsigned long usec)
 119{
 120        unsigned long tmo, tmp;
 121
 122        if (usec >= 1000) {
 123                /*
 124                 * if "big" number, spread normalization
 125                 * to seconds
 126                 * 1. start to normalize for usec to ticks per sec
 127                 * 2. find number of "ticks" to wait to achieve target
 128                 * 3. finish normalize.
 129                 */
 130                tmo = usec / 1000;
 131                tmo *= (CONFIG_SYS_HZ * count_value / 10);
 132                tmo /= 1000;
 133        } else {
 134                /* else small number, don't kill it prior to HZ multiply */
 135                tmo = usec * CONFIG_SYS_HZ * count_value / 10;
 136                tmo /= (1000 * 1000);
 137        }
 138
 139        /* get current timestamp */
 140        tmp = get_timer(0);
 141
 142        /* if setting this fordward will roll time stamp */
 143        /* reset "advancing" timestamp to 0, set lastdec value */
 144        /* else, set advancing stamp wake up time */
 145        if ((tmo + tmp + 1) < tmp)
 146                reset_timer_masked();
 147        else
 148                tmo += tmp;
 149
 150        /* loop till event */
 151        while (get_timer_masked() < tmo)
 152                ;       /* nop */
 153}
 154
 155void reset_timer_masked(void)
 156{
 157        struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
 158
 159        /* reset time */
 160        lastdec = readl(&timer->tcnto4);
 161        timestamp = 0;
 162}
 163
 164unsigned long get_timer_masked(void)
 165{
 166        struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
 167        unsigned long now = readl(&timer->tcnto4);
 168
 169        if (lastdec >= now)
 170                timestamp += lastdec - now;
 171        else
 172                timestamp += lastdec + count_value - now;
 173
 174        lastdec = now;
 175
 176        return timestamp;
 177}
 178
 179/*
 180 * This function is derived from PowerPC code (read timebase as long long).
 181 * On ARM it just returns the timer value.
 182 */
 183unsigned long long get_ticks(void)
 184{
 185        return get_timer(0);
 186}
 187
 188/*
 189 * This function is derived from PowerPC code (timebase clock frequency).
 190 * On ARM it returns the number of timer ticks per second.
 191 */
 192unsigned long get_tbclk(void)
 193{
 194        return CONFIG_SYS_HZ;
 195}
 196