e85f8b6543e665cdb993541906f740e4e5303441
[platform/kernel/u-boot.git] / board / armltd / integratorap / timer.c
1 /*
2  * (C) Copyright 2002
3  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4  * Marius Groeger <mgroeger@sysgo.de>
5  *
6  * (C) Copyright 2002
7  * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
8  *
9  * (C) Copyright 2003
10  * Texas Instruments, <www.ti.com>
11  * Kshitij Gupta <Kshitij@ti.com>
12  *
13  * (C) Copyright 2004
14  * ARM Ltd.
15  * Philippe Robin, <philippe.robin@arm.com>
16  *
17  * See file CREDITS for list of people who contributed to this
18  * project.
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License as
22  * published by the Free Software Foundation; either version 2 of
23  * the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
33  * MA 02111-1307 USA
34  */
35
36 #include <common.h>
37
38 /* The Integrator/AP timer1 is clocked at 24MHz
39  * can be divided by 16 or 256
40  * and is a 16-bit counter
41  */
42 /* U-Boot expects a 32 bit timer running at CONFIG_SYS_HZ*/
43 static ulong timestamp;         /* U-Boot ticks since startup         */
44 static ulong total_count = 0;   /* Total timer count                  */
45 static ulong lastdec;           /* Timer reading at last call         */
46 static ulong div_clock   = 256; /* Divisor applied to the timer clock */
47 static ulong div_timer   = 1;   /* Divisor to convert timer reading
48                                  * change to U-Boot ticks
49                                  */
50 /* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */
51
52 #define TIMER_LOAD_VAL 0x0000FFFFL
53 #define READ_TIMER ((*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4)) & 0x0000FFFFL)
54
55 /* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec
56  *  - unless otherwise stated
57  */
58
59 /* starts a counter
60  * - the Integrator/AP timer issues an interrupt
61  *   each time it reaches zero
62  */
63 int timer_init (void)
64 {
65         /* Load timer with initial value */
66         *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL;
67         /* Set timer to be
68          *      enabled           1
69          *      free-running      0
70          *      XX               00
71          *      divider 256      10
72          *      XX               00
73          */
74         *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088;
75         total_count = 0;
76         /* init the timestamp and lastdec value */
77         reset_timer_masked();
78
79         div_timer  = CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ;
80         div_timer /= div_clock;
81
82         return (0);
83 }
84
85 /*
86  * timer without interrupts
87  */
88 void reset_timer (void)
89 {
90         reset_timer_masked ();
91 }
92
93 ulong get_timer (ulong base_ticks)
94 {
95         return get_timer_masked () - base_ticks;
96 }
97
98 void set_timer (ulong ticks)
99 {
100         timestamp = ticks;
101         total_count = ticks * div_timer;
102         reset_timer_masked();
103 }
104
105 /* delay x useconds */
106 void udelay (unsigned long usec)
107 {
108         ulong tmo, tmp;
109
110         /* Convert to U-Boot ticks */
111         tmo  = usec * CONFIG_SYS_HZ;
112         tmo /= (1000000L);
113
114         tmp  = get_timer_masked();      /* get current timestamp */
115         tmo += tmp;                     /* wake up timestamp     */
116
117         while (get_timer_masked () < tmo) { /* loop till event */
118                 /*NOP*/;
119         }
120 }
121
122 void reset_timer_masked (void)
123 {
124         /* reset time */
125         lastdec   = READ_TIMER; /* capture current decrementer value   */
126         timestamp = 0;          /* start "advancing" time stamp from 0 */
127 }
128
129 /* converts the timer reading to U-Boot ticks          */
130 /* the timestamp is the number of ticks since reset    */
131 /* This routine does not detect wraps unless called regularly
132    ASSUMES a call at least every 16 seconds to detect every reload */
133 ulong get_timer_masked (void)
134 {
135         ulong now = READ_TIMER;         /* current count */
136
137         if (now > lastdec) {
138                 /* Must have wrapped */
139                 total_count += lastdec + TIMER_LOAD_VAL + 1 - now;
140         } else {
141                 total_count += lastdec - now;
142         }
143         lastdec   = now;
144         timestamp = total_count/div_timer;
145
146         return timestamp;
147 }
148
149 /* waits specified delay value and resets timestamp */
150 void udelay_masked (unsigned long usec)
151 {
152         udelay(usec);
153 }
154
155 /*
156  * This function is derived from PowerPC code (read timebase as long long).
157  * On ARM it just returns the timer value.
158  */
159 unsigned long long get_ticks(void)
160 {
161         return get_timer(0);
162 }
163
164 /*
165  * Return the timebase clock frequency
166  * i.e. how often the timer decrements
167  */
168 ulong get_tbclk (void)
169 {
170         return CONFIG_SYS_HZ_CLOCK/div_clock;
171 }