]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/imx-common/timer.c
upgrade to upstream version 2013.07
[karo-tx-uboot.git] / arch / arm / imx-common / timer.c
1 /*
2  * (C) Copyright 2007
3  * Sascha Hauer, Pengutronix
4  *
5  * (C) Copyright 2009 Freescale Semiconductor, Inc.
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <asm/io.h>
12 #include <div64.h>
13 #include <asm/arch/imx-regs.h>
14 #include <asm/arch/clock.h>
15
16 /* General purpose timers registers */
17 struct mxc_gpt {
18         unsigned int control;
19         unsigned int prescaler;
20         unsigned int status;
21         unsigned int nouse[6];
22         unsigned int counter;
23 };
24
25 static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR;
26
27 /* General purpose timers bitfields */
28 #define GPTCR_SWR               (1 << 15)       /* Software reset */
29 #define GPTCR_FRR               (1 << 9)        /* Freerun / restart */
30 #define GPTCR_CLKSOURCE_32      (4 << 6)        /* Clock source */
31 #define GPTCR_TEN               1               /* Timer enable */
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 static inline unsigned long long tick_to_time(unsigned long long tick)
36 {
37         tick *= CONFIG_SYS_HZ;
38         do_div(tick, MXC_CLK32);
39         return tick;
40 }
41
42 static inline unsigned long time_to_tick(unsigned long time)
43 {
44         unsigned long long ticks = (unsigned long long)time;
45
46         ticks *= MXC_CLK32;
47         do_div(ticks, CONFIG_SYS_HZ);
48         return ticks;
49 }
50
51 static inline unsigned long long us_to_tick(unsigned long long usec)
52 {
53         usec = usec * MXC_CLK32 + 999999;
54         do_div(usec, 1000000);
55
56         return usec;
57 }
58
59 int timer_init(void)
60 {
61         int i;
62
63         /* setup GP Timer 1 */
64         __raw_writel(GPTCR_SWR, &cur_gpt->control);
65
66         /* We have no udelay by now */
67         for (i = 0; i < 100; i++)
68                 __raw_writel(0, &cur_gpt->control);
69
70         __raw_writel(0, &cur_gpt->prescaler); /* 32Khz */
71
72         /* Freerun Mode, PERCLK1 input */
73         i = __raw_readl(&cur_gpt->control);
74         __raw_writel(i | GPTCR_CLKSOURCE_32 | GPTCR_TEN, &cur_gpt->control);
75
76         gd->arch.tbl = __raw_readl(&cur_gpt->counter);
77         gd->arch.tbu = 0;
78
79         gd->arch.timer_rate_hz = MXC_CLK32;
80         return 0;
81 }
82
83 unsigned long long get_ticks(void)
84 {
85         ulong now = __raw_readl(&cur_gpt->counter); /* current tick value */
86
87         /* increment tbu if tbl has rolled over */
88         if (now < gd->arch.tbl)
89                 gd->arch.tbu++;
90         gd->arch.tbl = now;
91         return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl;
92 }
93
94 ulong get_timer_masked(void)
95 {
96         /*
97          * get_ticks() returns a long long (64 bit), it wraps in
98          * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
99          * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
100          * 5 * 10^6 days - long enough.
101          */
102         /*
103          * LW: get_ticks() returns a long long with the top 32 bits always ZERO!
104          * Thus the calculation above is not true.
105          * A 64bit timer value would only make sense if it was
106          * consistently used throughout the code. Thus also the parameter
107          * to get_timer() and its return value would need to be 64bit wide!
108          */
109         return tick_to_time(get_ticks());
110 }
111
112 ulong get_timer(ulong base)
113 {
114         return tick_to_time(get_ticks() - time_to_tick(base));
115 }
116
117 /* delay x useconds AND preserve advance timstamp value */
118 void __udelay(unsigned long usec)
119 {
120         unsigned long start = __raw_readl(&cur_gpt->counter);
121         unsigned long ticks;
122
123         if (usec == 0)
124                 return;
125
126         ticks = us_to_tick(usec);
127         if (ticks == 0)
128                 ticks++;
129
130         while (__raw_readl(&cur_gpt->counter) - start < ticks)
131                 /* loop till event */;
132 }
133
134 /*
135  * This function is derived from PowerPC code (timebase clock frequency).
136  * On ARM it returns the number of timer ticks per second.
137  */
138 ulong get_tbclk(void)
139 {
140         return gd->arch.timer_rate_hz;
141 }