]>
Commit | Line | Data |
---|---|---|
552ff8f1 JR |
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 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
8 | * Alex Zuepke <azu@sysgo.de> | |
9 | * | |
10 | * (C) Copyright 2002 | |
11 | * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> | |
12 | * | |
13 | * (C) Copyright 2009 | |
14 | * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> | |
15 | * | |
16 | * (C) Copyright 2009 DENX Software Engineering | |
17 | * Author: John Rigby <jrigby@gmail.com> | |
77f11a99 | 18 | * Add support for MX25 |
552ff8f1 | 19 | * |
1a459660 | 20 | * SPDX-License-Identifier: GPL-2.0+ |
552ff8f1 JR |
21 | */ |
22 | ||
23 | #include <common.h> | |
24 | #include <div64.h> | |
25 | #include <asm/io.h> | |
26 | #include <asm/arch/imx-regs.h> | |
1b2080f3 | 27 | #include <asm/arch/clock.h> |
552ff8f1 | 28 | |
c9ac3ba1 HS |
29 | DECLARE_GLOBAL_DATA_PTR; |
30 | ||
66ee6923 | 31 | #define timestamp (gd->arch.tbl) |
582601da | 32 | #define lastinc (gd->arch.lastinc) |
552ff8f1 JR |
33 | |
34 | /* | |
35 | * "time" is measured in 1 / CONFIG_SYS_HZ seconds, | |
36 | * "tick" is internal timer period | |
37 | */ | |
38 | #ifdef CONFIG_MX25_TIMER_HIGH_PRECISION | |
39 | /* ~0.4% error - measured with stop-watch on 100s boot-delay */ | |
40 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
41 | { | |
42 | tick *= CONFIG_SYS_HZ; | |
1b2080f3 | 43 | do_div(tick, MXC_CLK32); |
552ff8f1 JR |
44 | return tick; |
45 | } | |
46 | ||
47 | static inline unsigned long long time_to_tick(unsigned long long time) | |
48 | { | |
1b2080f3 | 49 | time *= MXC_CLK32; |
552ff8f1 JR |
50 | do_div(time, CONFIG_SYS_HZ); |
51 | return time; | |
52 | } | |
53 | ||
54 | static inline unsigned long long us_to_tick(unsigned long long us) | |
55 | { | |
1b2080f3 | 56 | us = us * MXC_CLK32 + 999999; |
552ff8f1 JR |
57 | do_div(us, 1000000); |
58 | return us; | |
59 | } | |
60 | #else | |
61 | /* ~2% error */ | |
1b2080f3 BT |
62 | #define TICK_PER_TIME ((MXC_CLK32 + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) |
63 | #define US_PER_TICK (1000000 / MXC_CLK32) | |
552ff8f1 JR |
64 | |
65 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
66 | { | |
67 | do_div(tick, TICK_PER_TIME); | |
68 | return tick; | |
69 | } | |
70 | ||
71 | static inline unsigned long long time_to_tick(unsigned long long time) | |
72 | { | |
73 | return time * TICK_PER_TIME; | |
74 | } | |
75 | ||
76 | static inline unsigned long long us_to_tick(unsigned long long us) | |
77 | { | |
78 | us += US_PER_TICK - 1; | |
79 | do_div(us, US_PER_TICK); | |
80 | return us; | |
81 | } | |
82 | #endif | |
83 | ||
84 | /* nothing really to do with interrupts, just starts up a counter. */ | |
85 | /* The 32KHz 32-bit timer overruns in 134217 seconds */ | |
86 | int timer_init(void) | |
87 | { | |
88 | int i; | |
89 | struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; | |
90 | struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; | |
91 | ||
92 | /* setup GP Timer 1 */ | |
93 | writel(GPT_CTRL_SWR, &gpt->ctrl); | |
94 | ||
95 | writel(readl(&ccm->cgr1) | CCM_CGR1_GPT1, &ccm->cgr1); | |
96 | ||
97 | for (i = 0; i < 100; i++) | |
98 | writel(0, &gpt->ctrl); /* We have no udelay by now */ | |
99 | writel(0, &gpt->pre); /* prescaler = 1 */ | |
100 | /* Freerun Mode, 32KHz input */ | |
101 | writel(readl(&gpt->ctrl) | GPT_CTRL_CLKSOURCE_32 | GPT_CTRL_FRR, | |
102 | &gpt->ctrl); | |
103 | writel(readl(&gpt->ctrl) | GPT_CTRL_TEN, &gpt->ctrl); | |
104 | ||
105 | return 0; | |
106 | } | |
107 | ||
77f11a99 | 108 | unsigned long long get_ticks(void) |
552ff8f1 JR |
109 | { |
110 | struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; | |
111 | ulong now = readl(&gpt->counter); /* current tick value */ | |
112 | ||
113 | if (now >= lastinc) { | |
114 | /* | |
115 | * normal mode (non roll) | |
116 | * move stamp forward with absolut diff ticks | |
117 | */ | |
118 | timestamp += (now - lastinc); | |
119 | } else { | |
120 | /* we have rollover of incrementer */ | |
121 | timestamp += (0xFFFFFFFF - lastinc) + now; | |
122 | } | |
123 | lastinc = now; | |
124 | return timestamp; | |
125 | } | |
126 | ||
77f11a99 | 127 | ulong get_timer_masked(void) |
552ff8f1 JR |
128 | { |
129 | /* | |
130 | * get_ticks() returns a long long (64 bit), it wraps in | |
1b2080f3 | 131 | * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ |
552ff8f1 JR |
132 | * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in |
133 | * 5 * 10^6 days - long enough. | |
134 | */ | |
135 | return tick_to_time(get_ticks()); | |
136 | } | |
137 | ||
77f11a99 | 138 | ulong get_timer(ulong base) |
552ff8f1 | 139 | { |
77f11a99 | 140 | return get_timer_masked() - base; |
552ff8f1 JR |
141 | } |
142 | ||
552ff8f1 | 143 | /* delay x useconds AND preserve advance timstamp value */ |
77f11a99 | 144 | void __udelay(unsigned long usec) |
552ff8f1 JR |
145 | { |
146 | unsigned long long tmp; | |
147 | ulong tmo; | |
148 | ||
149 | tmo = us_to_tick(usec); | |
150 | tmp = get_ticks() + tmo; /* get current timestamp */ | |
151 | ||
152 | while (get_ticks() < tmp) /* loop till event */ | |
153 | /*NOP*/; | |
154 | } | |
a7f39e7c MW |
155 | |
156 | /* | |
157 | * This function is derived from PowerPC code (timebase clock frequency). | |
158 | * On ARM it returns the number of timer ticks per second. | |
159 | */ | |
160 | ulong get_tbclk(void) | |
161 | { | |
162 | ulong tbclk; | |
163 | ||
1b2080f3 | 164 | tbclk = MXC_CLK32; |
a7f39e7c MW |
165 | return tbclk; |
166 | } |