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