uboot/arch/arm/cpu/armv7/zynq/timer.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
   3 * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
   4 *
   5 * (C) Copyright 2008
   6 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
   7 *
   8 * (C) Copyright 2004
   9 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
  10 *
  11 * (C) Copyright 2002-2004
  12 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
  13 *
  14 * (C) Copyright 2003
  15 * Texas Instruments <www.ti.com>
  16 *
  17 * (C) Copyright 2002
  18 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  19 * Marius Groeger <mgroeger@sysgo.de>
  20 *
  21 * (C) Copyright 2002
  22 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  23 * Alex Zuepke <azu@sysgo.de>
  24 *
  25 * See file CREDITS for list of people who contributed to this
  26 * project.
  27 *
  28 * This program is free software; you can redistribute it and/or
  29 * modify it under the terms of the GNU General Public License as
  30 * published by the Free Software Foundation; either version 2 of
  31 * the License, or (at your option) any later version.
  32 *
  33 * This program is distributed in the hope that it will be useful,
  34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  36 * GNU General Public License for more details.
  37 *
  38 * You should have received a copy of the GNU General Public License
  39 * along with this program; if not, write to the Free Software
  40 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  41 * MA 02111-1307 USA
  42 */
  43
  44#include <common.h>
  45#include <div64.h>
  46#include <asm/io.h>
  47
  48DECLARE_GLOBAL_DATA_PTR;
  49
  50struct scu_timer {
  51        u32 load; /* Timer Load Register */
  52        u32 counter; /* Timer Counter Register */
  53        u32 control; /* Timer Control Register */
  54};
  55
  56static struct scu_timer *timer_base =
  57                              (struct scu_timer *) CONFIG_SCUTIMER_BASEADDR;
  58
  59#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
  60#define SCUTIMER_CONTROL_PRESCALER_SHIFT        8
  61#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK       0x00000002 /* Auto-reload */
  62#define SCUTIMER_CONTROL_ENABLE_MASK            0x00000001 /* Timer enable */
  63
  64#define TIMER_LOAD_VAL 0xFFFFFFFF
  65#define TIMER_PRESCALE 255
  66#define TIMER_TICK_HZ  (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE)
  67
  68int timer_init(void)
  69{
  70        const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
  71                        (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
  72                        SCUTIMER_CONTROL_ENABLE_MASK;
  73
  74        /* Load the timer counter register */
  75        writel(0xFFFFFFFF, &timer_base->counter);
  76
  77        /*
  78         * Start the A9Timer device
  79         * Enable Auto reload mode, Clear prescaler control bits
  80         * Set prescaler value, Enable the decrementer
  81         */
  82        clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
  83                                                                emask);
  84
  85        /* Reset time */
  86        gd->lastinc = readl(&timer_base->counter) /
  87                                        (TIMER_TICK_HZ / CONFIG_SYS_HZ);
  88        gd->tbl = 0;
  89
  90        return 0;
  91}
  92
  93/*
  94 * This function is derived from PowerPC code (read timebase as long long).
  95 * On ARM it just returns the timer value.
  96 */
  97ulong get_timer_masked(void)
  98{
  99        ulong now;
 100
 101        now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ);
 102
 103        if (gd->lastinc >= now) {
 104                /* Normal mode */
 105                gd->tbl += gd->lastinc - now;
 106        } else {
 107                /* We have an overflow ... */
 108                gd->tbl += gd->lastinc + TIMER_LOAD_VAL - now;
 109        }
 110        gd->lastinc = now;
 111
 112        return gd->tbl;
 113}
 114
 115void __udelay(unsigned long usec)
 116{
 117        unsigned long long tmp;
 118        ulong tmo;
 119
 120        tmo = usec / (1000000 / CONFIG_SYS_HZ);
 121        tmp = get_ticks() + tmo; /* Get current timestamp */
 122
 123        while (get_ticks() < tmp) { /* Loop till event */
 124                 /* NOP */;
 125        }
 126}
 127
 128/* Timer without interrupts */
 129ulong get_timer(ulong base)
 130{
 131        return get_timer_masked() - base;
 132}
 133
 134/*
 135 * This function is derived from PowerPC code (read timebase as long long).
 136 * On ARM it just returns the timer value.
 137 */
 138unsigned long long get_ticks(void)
 139{
 140        return get_timer(0);
 141}
 142
 143/*
 144 * This function is derived from PowerPC code (timebase clock frequency).
 145 * On ARM it returns the number of timer ticks per second.
 146 */
 147ulong get_tbclk(void)
 148{
 149        return CONFIG_SYS_HZ;
 150}
 151