]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/u8500/timer.c
bb9165b0f45961c8124c3d418defded3835aef0d
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / u8500 / timer.c
1 /*
2  * Copyright (C) 2010 Linaro Limited
3  * John Rigby <john.rigby@linaro.org>
4  *
5  * Based on original from Linux kernel source and
6  * internal ST-Ericsson U-Boot source.
7  * (C) Copyright 2009 Alessandro Rubini
8  * (C) Copyright 2010 ST-Ericsson
9  *
10  * See file CREDITS for list of people who contributed to this
11  * project.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of
16  * the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28
29 #include <common.h>
30 #include <asm/io.h>
31 #include <asm/arch/hardware.h>
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 /*
36  * The MTU device has some interrupt control registers
37  * followed by 4 timers.
38  */
39
40 /* The timers */
41 struct u8500_mtu_timer {
42         u32 lr;                 /* Load value */
43         u32 cv;                 /* Current value */
44         u32 cr;                 /* Control reg */
45         u32 bglr;               /* ??? */
46 };
47
48 /* The MTU that contains the timers */
49 struct u8500_mtu {
50         u32 imsc;               /* Interrupt mask set/clear */
51         u32 ris;                /* Raw interrupt status */
52         u32 mis;                /* Masked interrupt status */
53         u32 icr;                /* Interrupt clear register */
54         struct u8500_mtu_timer pt[4];
55 };
56
57 /* bits for the control register */
58 #define MTU_CR_ONESHOT          0x01    /* if 0 = wraps reloading from BGLR */
59 #define MTU_CR_32BITS           0x02
60
61 #define MTU_CR_PRESCALE_1       0x00
62 #define MTU_CR_PRESCALE_16      0x04
63 #define MTU_CR_PRESCALE_256     0x08
64 #define MTU_CR_PRESCALE_MASK    0x0c
65
66 #define MTU_CR_PERIODIC         0x40    /* if 0 = free-running */
67 #define MTU_CR_ENA              0x80
68
69 /*
70  * The MTU is clocked at 133 MHz by default. (V1 and later)
71  */
72 #define TIMER_CLOCK             (133 * 1000 * 1000 / 16)
73 #define COUNT_TO_USEC(x)        ((x) * 16 / 133)
74 #define USEC_TO_COUNT(x)        ((x) * 133 / 16)
75 #define TICKS_PER_HZ            (TIMER_CLOCK / CONFIG_SYS_HZ)
76 #define TICKS_TO_HZ(x)          ((x) / TICKS_PER_HZ)
77 #define TIMER_LOAD_VAL          0xffffffff
78
79 /*
80  * MTU timer to use (from 0 to 3).
81  */
82 #define MTU_TIMER 2
83
84 static struct u8500_mtu_timer *timer_base =
85         &((struct u8500_mtu *)U8500_MTU0_BASE_V1)->pt[MTU_TIMER];
86
87 /* macro to read the 32 bit timer: since it decrements, we invert read value */
88 #define READ_TIMER() (~readl(&timer_base->cv))
89
90 /* Configure a free-running, auto-wrap counter with /16 prescaler */
91 int timer_init(void)
92 {
93         writel(MTU_CR_ENA | MTU_CR_PRESCALE_16 | MTU_CR_32BITS,
94                &timer_base->cr);
95         return 0;
96 }
97
98 ulong get_timer_masked(void)
99 {
100         /* current tick value */
101         ulong now = TICKS_TO_HZ(READ_TIMER());
102
103         if (now >= gd->lastinc) /* normal (non rollover) */
104                 gd->tbl += (now - gd->lastinc);
105         else                    /* rollover */
106                 gd->tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL) - gd->lastinc) + now;
107         gd->lastinc = now;
108         return gd->tbl;
109 }
110
111 /* Delay x useconds */
112 void __udelay(ulong usec)
113 {
114         long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
115         ulong now, last = READ_TIMER();
116
117         while (tmo > 0) {
118                 now = READ_TIMER();
119                 if (now > last) /* normal (non rollover) */
120                         tmo -= now - last;
121                 else            /* rollover */
122                         tmo -= TIMER_LOAD_VAL - last + now;
123                 last = now;
124         }
125 }
126
127 ulong get_timer(ulong base)
128 {
129         return get_timer_masked() - base;
130 }
131
132 /*
133  * Emulation of Power architecture long long timebase.
134  *
135  * TODO: Support gd->arch.tbu for real long long timebase.
136  */
137 unsigned long long get_ticks(void)
138 {
139         return get_timer(0);
140 }
141
142 /*
143  * Emulation of Power architecture timebase.
144  * NB: Low resolution compared to Power tbclk.
145  */
146 ulong get_tbclk(void)
147 {
148         return CONFIG_SYS_HZ;
149 }