]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/zynq/timer.c
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / zynq / timer.c
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 #include <asm/arch/hardware.h>
48
49 DECLARE_GLOBAL_DATA_PTR;
50
51 struct scu_timer {
52         u32 load; /* Timer Load Register */
53         u32 counter; /* Timer Counter Register */
54         u32 control; /* Timer Control Register */
55 };
56
57 static struct scu_timer *timer_base =
58                               (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
59
60 #define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
61 #define SCUTIMER_CONTROL_PRESCALER_SHIFT        8
62 #define SCUTIMER_CONTROL_AUTO_RELOAD_MASK       0x00000002 /* Auto-reload */
63 #define SCUTIMER_CONTROL_ENABLE_MASK            0x00000001 /* Timer enable */
64
65 #define TIMER_LOAD_VAL 0xFFFFFFFF
66 #define TIMER_PRESCALE 255
67 #define TIMER_TICK_HZ  (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE)
68
69 int timer_init(void)
70 {
71         const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
72                         (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
73                         SCUTIMER_CONTROL_ENABLE_MASK;
74
75         /* Load the timer counter register */
76         writel(0xFFFFFFFF, &timer_base->counter);
77
78         /*
79          * Start the A9Timer device
80          * Enable Auto reload mode, Clear prescaler control bits
81          * Set prescaler value, Enable the decrementer
82          */
83         clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
84                                                                 emask);
85
86         /* Reset time */
87         gd->arch.lastinc = readl(&timer_base->counter) /
88                                         (TIMER_TICK_HZ / CONFIG_SYS_HZ);
89         gd->arch.tbl = 0;
90
91         return 0;
92 }
93
94 /*
95  * This function is derived from PowerPC code (read timebase as long long).
96  * On ARM it just returns the timer value.
97  */
98 ulong get_timer_masked(void)
99 {
100         ulong now;
101
102         now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ);
103
104         if (gd->arch.lastinc >= now) {
105                 /* Normal mode */
106                 gd->arch.tbl += gd->arch.lastinc - now;
107         } else {
108                 /* We have an overflow ... */
109                 gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now;
110         }
111         gd->arch.lastinc = now;
112
113         return gd->arch.tbl;
114 }
115
116 void __udelay(unsigned long usec)
117 {
118         u32 countticks;
119         u32 timeend;
120         u32 timediff;
121         u32 timenow;
122
123         if (usec == 0)
124                 return;
125
126         countticks = (u32) (((unsigned long long) TIMER_TICK_HZ * usec) /
127                                                                 1000000);
128
129         /* decrementing timer */
130         timeend = readl(&timer_base->counter) - countticks;
131
132 #if TIMER_LOAD_VAL != 0xFFFFFFFF
133         /* do not manage multiple overflow */
134         if (countticks >= TIMER_LOAD_VAL)
135                 countticks = TIMER_LOAD_VAL - 1;
136 #endif
137
138         do {
139                 timenow = readl(&timer_base->counter);
140
141                 if (timenow >= timeend) {
142                         /* normal case */
143                         timediff = timenow - timeend;
144                 } else {
145                         if ((TIMER_LOAD_VAL - timeend + timenow) <=
146                                                                 countticks) {
147                                 /* overflow */
148                                 timediff = TIMER_LOAD_VAL - timeend + timenow;
149                         } else {
150                                 /* missed the exact match */
151                                 break;
152                         }
153                 }
154         } while (timediff > 0);
155 }
156
157 /* Timer without interrupts */
158 ulong get_timer(ulong base)
159 {
160         return get_timer_masked() - base;
161 }
162
163 /*
164  * This function is derived from PowerPC code (read timebase as long long).
165  * On ARM it just returns the timer value.
166  */
167 unsigned long long get_ticks(void)
168 {
169         return get_timer(0);
170 }
171
172 /*
173  * This function is derived from PowerPC code (timebase clock frequency).
174  * On ARM it returns the number of timer ticks per second.
175  */
176 ulong get_tbclk(void)
177 {
178         return CONFIG_SYS_HZ;
179 }