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