2
* Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
3
* Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
6
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
9
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
11
* (C) Copyright 2002-2004
12
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
15
* Texas Instruments <www.ti.com>
18
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
19
* Marius Groeger <mgroeger@sysgo.de>
22
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
23
* Alex Zuepke <azu@sysgo.de>
25
* SPDX-License-Identifier: GPL-2.0+
31
#include <asm/arch/hardware.h>
32
#include <asm/arch/clk.h>
34
DECLARE_GLOBAL_DATA_PTR;
37
u32 load; /* Timer Load Register */
38
u32 counter; /* Timer Counter Register */
39
u32 control; /* Timer Control Register */
42
static struct scu_timer *timer_base =
43
(struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
45
#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
46
#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8
47
#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */
48
#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */
50
#define TIMER_LOAD_VAL 0xFFFFFFFF
51
#define TIMER_PRESCALE 255
55
const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
56
(TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
57
SCUTIMER_CONTROL_ENABLE_MASK;
59
gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
61
/* Load the timer counter register */
62
writel(0xFFFFFFFF, &timer_base->load);
65
* Start the A9Timer device
66
* Enable Auto reload mode, Clear prescaler control bits
67
* Set prescaler value, Enable the decrementer
69
clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
73
gd->arch.lastinc = readl(&timer_base->counter) /
74
(gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
81
* This function is derived from PowerPC code (read timebase as long long).
82
* On ARM it just returns the timer value.
84
ulong get_timer_masked(void)
88
now = readl(&timer_base->counter) /
89
(gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
91
if (gd->arch.lastinc >= now) {
93
gd->arch.tbl += gd->arch.lastinc - now;
95
/* We have an overflow ... */
96
gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now + 1;
98
gd->arch.lastinc = now;
103
void __udelay(unsigned long usec)
113
countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec),
116
/* decrementing timer */
117
timeend = readl(&timer_base->counter) - countticks;
119
#if TIMER_LOAD_VAL != 0xFFFFFFFF
120
/* do not manage multiple overflow */
121
if (countticks >= TIMER_LOAD_VAL)
122
countticks = TIMER_LOAD_VAL - 1;
126
timenow = readl(&timer_base->counter);
128
if (timenow >= timeend) {
130
timediff = timenow - timeend;
132
if ((TIMER_LOAD_VAL - timeend + timenow) <=
135
timediff = TIMER_LOAD_VAL - timeend + timenow;
137
/* missed the exact match */
141
} while (timediff > 0);
144
/* Timer without interrupts */
145
ulong get_timer(ulong base)
147
return get_timer_masked() - base;
151
* This function is derived from PowerPC code (read timebase as long long).
152
* On ARM it just returns the timer value.
154
unsigned long long get_ticks(void)
160
* This function is derived from PowerPC code (timebase clock frequency).
161
* On ARM it returns the number of timer ticks per second.
163
ulong get_tbclk(void)
165
return CONFIG_SYS_HZ;