1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2002
3*4882a593Smuzhiyun * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4*4882a593Smuzhiyun * Marius Groeger <mgroeger@sysgo.de>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * (C) Copyright 2002
7*4882a593Smuzhiyun * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
8*4882a593Smuzhiyun * Alex Zuepke <azu@sysgo.de>
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * (C) Copyright 2002
11*4882a593Smuzhiyun * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * (C) Copyright 2009
14*4882a593Smuzhiyun * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <common.h>
20*4882a593Smuzhiyun #include <div64.h>
21*4882a593Smuzhiyun #include <asm/io.h>
22*4882a593Smuzhiyun #include <asm/arch/imx-regs.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* General purpose timers bitfields */
25*4882a593Smuzhiyun #define GPTCR_SWR (1 << 15) /* Software reset */
26*4882a593Smuzhiyun #define GPTCR_FRR (1 << 8) /* Freerun / restart */
27*4882a593Smuzhiyun #define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */
28*4882a593Smuzhiyun #define GPTCR_TEN 1 /* Timer enable */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define timestamp (gd->arch.tbl)
33*4882a593Smuzhiyun #define lastinc (gd->arch.lastinc)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /*
36*4882a593Smuzhiyun * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
37*4882a593Smuzhiyun * "tick" is internal timer period
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun #ifdef CONFIG_MX27_TIMER_HIGH_PRECISION
40*4882a593Smuzhiyun /* ~0.4% error - measured with stop-watch on 100s boot-delay */
tick_to_time(unsigned long long tick)41*4882a593Smuzhiyun static inline unsigned long long tick_to_time(unsigned long long tick)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun tick *= CONFIG_SYS_HZ;
44*4882a593Smuzhiyun do_div(tick, CONFIG_MX27_CLK32);
45*4882a593Smuzhiyun return tick;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
time_to_tick(unsigned long long time)48*4882a593Smuzhiyun static inline unsigned long long time_to_tick(unsigned long long time)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun time *= CONFIG_MX27_CLK32;
51*4882a593Smuzhiyun do_div(time, CONFIG_SYS_HZ);
52*4882a593Smuzhiyun return time;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
us_to_tick(unsigned long long us)55*4882a593Smuzhiyun static inline unsigned long long us_to_tick(unsigned long long us)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun us = us * CONFIG_MX27_CLK32 + 999999;
58*4882a593Smuzhiyun do_div(us, 1000000);
59*4882a593Smuzhiyun return us;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun #else
62*4882a593Smuzhiyun /* ~2% error */
63*4882a593Smuzhiyun #define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \
64*4882a593Smuzhiyun CONFIG_SYS_HZ)
65*4882a593Smuzhiyun #define US_PER_TICK (1000000 / CONFIG_MX27_CLK32)
66*4882a593Smuzhiyun
tick_to_time(unsigned long long tick)67*4882a593Smuzhiyun static inline unsigned long long tick_to_time(unsigned long long tick)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun do_div(tick, TICK_PER_TIME);
70*4882a593Smuzhiyun return tick;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
time_to_tick(unsigned long long time)73*4882a593Smuzhiyun static inline unsigned long long time_to_tick(unsigned long long time)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun return time * TICK_PER_TIME;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
us_to_tick(unsigned long long us)78*4882a593Smuzhiyun static inline unsigned long long us_to_tick(unsigned long long us)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun us += US_PER_TICK - 1;
81*4882a593Smuzhiyun do_div(us, US_PER_TICK);
82*4882a593Smuzhiyun return us;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* nothing really to do with interrupts, just starts up a counter. */
87*4882a593Smuzhiyun /* The 32768Hz 32-bit timer overruns in 131072 seconds */
timer_init(void)88*4882a593Smuzhiyun int timer_init(void)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun int i;
91*4882a593Smuzhiyun struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
92*4882a593Smuzhiyun struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* setup GP Timer 1 */
95*4882a593Smuzhiyun writel(GPTCR_SWR, ®s->gpt_tctl);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0);
98*4882a593Smuzhiyun writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun for (i = 0; i < 100; i++)
101*4882a593Smuzhiyun writel(0, ®s->gpt_tctl); /* We have no udelay by now */
102*4882a593Smuzhiyun writel(0, ®s->gpt_tprer); /* 32Khz */
103*4882a593Smuzhiyun /* Freerun Mode, PERCLK1 input */
104*4882a593Smuzhiyun writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
105*4882a593Smuzhiyun ®s->gpt_tctl);
106*4882a593Smuzhiyun writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
get_ticks(void)111*4882a593Smuzhiyun unsigned long long get_ticks(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
114*4882a593Smuzhiyun ulong now = readl(®s->gpt_tcn); /* current tick value */
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (now >= lastinc) {
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun * normal mode (non roll)
119*4882a593Smuzhiyun * move stamp forward with absolut diff ticks
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun timestamp += (now - lastinc);
122*4882a593Smuzhiyun } else {
123*4882a593Smuzhiyun /* we have rollover of incrementer */
124*4882a593Smuzhiyun timestamp += (0xFFFFFFFF - lastinc) + now;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun lastinc = now;
127*4882a593Smuzhiyun return timestamp;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
get_timer_masked(void)130*4882a593Smuzhiyun ulong get_timer_masked(void)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun * get_ticks() returns a long long (64 bit), it wraps in
134*4882a593Smuzhiyun * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
135*4882a593Smuzhiyun * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
136*4882a593Smuzhiyun * 5 * 10^6 days - long enough.
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun return tick_to_time(get_ticks());
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
get_timer(ulong base)141*4882a593Smuzhiyun ulong get_timer(ulong base)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun return get_timer_masked() - base;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* delay x useconds AND preserve advance timstamp value */
__udelay(unsigned long usec)147*4882a593Smuzhiyun void __udelay(unsigned long usec)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun unsigned long long tmp;
150*4882a593Smuzhiyun ulong tmo;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun tmo = us_to_tick(usec);
153*4882a593Smuzhiyun tmp = get_ticks() + tmo; /* get current timestamp */
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun while (get_ticks() < tmp) /* loop till event */
156*4882a593Smuzhiyun /*NOP*/;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
get_tbclk(void)159*4882a593Smuzhiyun ulong get_tbclk(void)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun return CONFIG_MX27_CLK32;
162*4882a593Smuzhiyun }
163