uboot/board/armltd/integrator/timer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2002
   4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   5 * Marius Groeger <mgroeger@sysgo.de>
   6 *
   7 * (C) Copyright 2002
   8 * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
   9 *
  10 * (C) Copyright 2003
  11 * Texas Instruments, <www.ti.com>
  12 * Kshitij Gupta <Kshitij@ti.com>
  13 *
  14 * (C) Copyright 2004
  15 * ARM Ltd.
  16 * Philippe Robin, <philippe.robin@arm.com>
  17 */
  18
  19#include <common.h>
  20#include <div64.h>
  21#include <time.h>
  22#include <linux/delay.h>
  23
  24#ifdef CONFIG_ARCH_CINTEGRATOR
  25#define DIV_CLOCK_INIT  1
  26#define TIMER_LOAD_VAL  0xFFFFFFFFL
  27#else
  28#define DIV_CLOCK_INIT  256
  29#define TIMER_LOAD_VAL  0x0000FFFFL
  30#endif
  31/* The Integrator/CP timer1 is clocked at 1MHz
  32 * can be divided by 16 or 256
  33 * and can be set up as a 32-bit timer
  34 */
  35/* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */
  36/* Keep total timer count to avoid losing decrements < div_timer */
  37static unsigned long long total_count = 0;
  38static unsigned long long lastdec;       /* Timer reading at last call     */
  39/* Divisor applied to timer clock */
  40static unsigned long long div_clock = DIV_CLOCK_INIT;
  41static unsigned long long div_timer = 1; /* Divisor to convert timer reading
  42                                          * change to U-Boot ticks
  43                                          */
  44/* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */
  45static ulong timestamp;         /* U-Boot ticks since startup */
  46
  47#define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4))
  48
  49/* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec
  50 *  - unless otherwise stated
  51 */
  52
  53/* starts up a counter
  54 * - the Integrator/CP timer can be set up to issue an interrupt */
  55int timer_init (void)
  56{
  57        /* Load timer with initial value */
  58        *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL;
  59#ifdef CONFIG_ARCH_CINTEGRATOR
  60        /* Set timer to be
  61         *      enabled          1
  62         *      periodic         1
  63         *      no interrupts    0
  64         *      X                0
  65         *      divider 1       00 == less rounding error
  66         *      32 bit           1
  67         *      wrapping         0
  68         */
  69        *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2;
  70#else
  71        /* Set timer to be
  72         *      enabled          1
  73         *      free-running     0
  74         *      XX              00
  75         *      divider 256     10
  76         *      XX              00
  77         */
  78        *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088;
  79#endif
  80
  81        /* init the timestamp */
  82        total_count = 0ULL;
  83        /* capure current decrementer value    */
  84        lastdec   = READ_TIMER;
  85        /* start "advancing" time stamp from 0 */
  86        timestamp = 0L;
  87
  88        div_timer = CONFIG_SYS_HZ_CLOCK;
  89        do_div(div_timer, CONFIG_SYS_HZ);
  90        do_div(div_timer, div_clock);
  91
  92        return (0);
  93}
  94
  95/*
  96 * timer without interrupts
  97 */
  98
  99/* converts the timer reading to U-Boot ticks          */
 100/* the timestamp is the number of ticks since reset    */
 101static ulong get_timer_masked (void)
 102{
 103        /* get current count */
 104        unsigned long long now = READ_TIMER;
 105
 106        if(now > lastdec) {
 107                /* Must have wrapped */
 108                total_count += lastdec + TIMER_LOAD_VAL + 1 - now;
 109        } else {
 110                total_count += lastdec - now;
 111        }
 112        lastdec = now;
 113
 114        /* Reuse "now" */
 115        now = total_count;
 116        do_div(now, div_timer);
 117        timestamp = now;
 118
 119        return timestamp;
 120}
 121
 122ulong get_timer (ulong base_ticks)
 123{
 124        return get_timer_masked () - base_ticks;
 125}
 126
 127/* delay usec useconds */
 128void __udelay(unsigned long usec)
 129{
 130        ulong tmo, tmp;
 131
 132        /* Convert to U-Boot ticks */
 133        tmo  = usec * CONFIG_SYS_HZ;
 134        tmo /= (1000000L);
 135
 136        tmp  = get_timer_masked();      /* get current timestamp */
 137        tmo += tmp;                     /* form target timestamp */
 138
 139        while (get_timer_masked () < tmo) {/* loop till event */
 140                /*NOP*/;
 141        }
 142}
 143
 144/*
 145 * This function is derived from PowerPC code (read timebase as long long).
 146 * On ARM it just returns the timer value.
 147 */
 148unsigned long long get_ticks(void)
 149{
 150        return get_timer(0);
 151}
 152
 153/*
 154 * Return the timebase clock frequency
 155 * i.e. how often the timer decrements
 156 */
 157ulong get_tbclk(void)
 158{
 159        unsigned long long tmp = CONFIG_SYS_HZ_CLOCK;
 160
 161        do_div(tmp, div_clock);
 162
 163        return tmp;
 164}
 165