1445a886dSMacpaul Lin /*
2445a886dSMacpaul Lin * (C) Copyright 2009 Faraday Technology
3445a886dSMacpaul Lin * Po-Yu Chuang <ratbert@faraday-tech.com>
4445a886dSMacpaul Lin *
5445a886dSMacpaul Lin * Copyright (C) 2011 Andes Technology Corporation
6445a886dSMacpaul Lin * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
7445a886dSMacpaul Lin * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
8445a886dSMacpaul Lin *
91a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
10445a886dSMacpaul Lin */
11*f5076f86Srick #ifndef CONFIG_TIMER
12445a886dSMacpaul Lin #include <common.h>
13445a886dSMacpaul Lin #include <asm/io.h>
14445a886dSMacpaul Lin #include <faraday/fttmr010.h>
15445a886dSMacpaul Lin
16445a886dSMacpaul Lin static ulong timestamp;
17445a886dSMacpaul Lin static ulong lastdec;
18445a886dSMacpaul Lin
timer_init(void)19445a886dSMacpaul Lin int timer_init(void)
20445a886dSMacpaul Lin {
2139c87743SMacpaul Lin struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
22445a886dSMacpaul Lin unsigned int cr;
23445a886dSMacpaul Lin
24445a886dSMacpaul Lin debug("%s()\n", __func__);
25445a886dSMacpaul Lin
26445a886dSMacpaul Lin /* disable timers */
27445a886dSMacpaul Lin writel(0, &tmr->cr);
28445a886dSMacpaul Lin
29445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
30445a886dSMacpaul Lin /* use 32768Hz oscillator for RTC, WDT, TIMER */
31445a886dSMacpaul Lin ftpmu010_32768osc_enable();
32445a886dSMacpaul Lin #endif
33445a886dSMacpaul Lin
34445a886dSMacpaul Lin /* setup timer */
35445a886dSMacpaul Lin writel(TIMER_LOAD_VAL, &tmr->timer3_load);
36445a886dSMacpaul Lin writel(TIMER_LOAD_VAL, &tmr->timer3_counter);
37445a886dSMacpaul Lin writel(0, &tmr->timer3_match1);
38445a886dSMacpaul Lin writel(0, &tmr->timer3_match2);
39445a886dSMacpaul Lin
40445a886dSMacpaul Lin /* we don't want timer to issue interrupts */
41445a886dSMacpaul Lin writel(FTTMR010_TM3_MATCH1 |
42445a886dSMacpaul Lin FTTMR010_TM3_MATCH2 |
43445a886dSMacpaul Lin FTTMR010_TM3_OVERFLOW,
44445a886dSMacpaul Lin &tmr->interrupt_mask);
45445a886dSMacpaul Lin
46445a886dSMacpaul Lin cr = readl(&tmr->cr);
47445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
48445a886dSMacpaul Lin cr |= FTTMR010_TM3_CLOCK; /* use external clock */
49445a886dSMacpaul Lin #endif
50445a886dSMacpaul Lin cr |= FTTMR010_TM3_ENABLE;
51445a886dSMacpaul Lin writel(cr, &tmr->cr);
52445a886dSMacpaul Lin
53445a886dSMacpaul Lin /* init the timestamp and lastdec value */
54445a886dSMacpaul Lin reset_timer_masked();
55445a886dSMacpaul Lin
56445a886dSMacpaul Lin return 0;
57445a886dSMacpaul Lin }
58445a886dSMacpaul Lin
59445a886dSMacpaul Lin /*
60445a886dSMacpaul Lin * timer without interrupts
61445a886dSMacpaul Lin */
62445a886dSMacpaul Lin
63445a886dSMacpaul Lin /*
64445a886dSMacpaul Lin * reset time
65445a886dSMacpaul Lin */
reset_timer_masked(void)66445a886dSMacpaul Lin void reset_timer_masked(void)
67445a886dSMacpaul Lin {
6839c87743SMacpaul Lin struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
69445a886dSMacpaul Lin
70445a886dSMacpaul Lin /* capure current decrementer value time */
71445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
72445a886dSMacpaul Lin lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
73445a886dSMacpaul Lin #else
744fc96705SAxel Lin lastdec = readl(&tmr->timer3_counter) /
754fc96705SAxel Lin (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
76445a886dSMacpaul Lin #endif
77445a886dSMacpaul Lin timestamp = 0; /* start "advancing" time stamp from 0 */
78445a886dSMacpaul Lin
79445a886dSMacpaul Lin debug("%s(): lastdec = %lx\n", __func__, lastdec);
80445a886dSMacpaul Lin }
81445a886dSMacpaul Lin
reset_timer(void)82445a886dSMacpaul Lin void reset_timer(void)
83445a886dSMacpaul Lin {
84445a886dSMacpaul Lin debug("%s()\n", __func__);
85445a886dSMacpaul Lin reset_timer_masked();
86445a886dSMacpaul Lin }
87445a886dSMacpaul Lin
88445a886dSMacpaul Lin /*
89445a886dSMacpaul Lin * return timer ticks
90445a886dSMacpaul Lin */
get_timer_masked(void)91445a886dSMacpaul Lin ulong get_timer_masked(void)
92445a886dSMacpaul Lin {
9339c87743SMacpaul Lin struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
94445a886dSMacpaul Lin
95445a886dSMacpaul Lin /* current tick value */
96445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
97445a886dSMacpaul Lin ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
98445a886dSMacpaul Lin #else
994fc96705SAxel Lin ulong now = readl(&tmr->timer3_counter) /
1004fc96705SAxel Lin (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
101445a886dSMacpaul Lin #endif
102445a886dSMacpaul Lin
103445a886dSMacpaul Lin debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
104445a886dSMacpaul Lin
105445a886dSMacpaul Lin if (lastdec >= now) {
106445a886dSMacpaul Lin /*
107445a886dSMacpaul Lin * normal mode (non roll)
108445a886dSMacpaul Lin * move stamp fordward with absoulte diff ticks
109445a886dSMacpaul Lin */
110445a886dSMacpaul Lin timestamp += lastdec - now;
111445a886dSMacpaul Lin } else {
112445a886dSMacpaul Lin /*
113445a886dSMacpaul Lin * we have overflow of the count down timer
114445a886dSMacpaul Lin *
115445a886dSMacpaul Lin * nts = ts + ld + (TLV - now)
116445a886dSMacpaul Lin * ts=old stamp, ld=time that passed before passing through -1
117445a886dSMacpaul Lin * (TLV-now) amount of time after passing though -1
118445a886dSMacpaul Lin * nts = new "advancing time stamp"...it could also roll and
119445a886dSMacpaul Lin * cause problems.
120445a886dSMacpaul Lin */
121445a886dSMacpaul Lin timestamp += lastdec + TIMER_LOAD_VAL - now;
122445a886dSMacpaul Lin }
123445a886dSMacpaul Lin
124445a886dSMacpaul Lin lastdec = now;
125445a886dSMacpaul Lin
126445a886dSMacpaul Lin debug("%s() returns %lx\n", __func__, timestamp);
127445a886dSMacpaul Lin
128445a886dSMacpaul Lin return timestamp;
129445a886dSMacpaul Lin }
130445a886dSMacpaul Lin
131445a886dSMacpaul Lin /*
132445a886dSMacpaul Lin * return difference between timer ticks and base
133445a886dSMacpaul Lin */
get_timer(ulong base)134445a886dSMacpaul Lin ulong get_timer(ulong base)
135445a886dSMacpaul Lin {
136445a886dSMacpaul Lin debug("%s(%lx)\n", __func__, base);
137445a886dSMacpaul Lin return get_timer_masked() - base;
138445a886dSMacpaul Lin }
139445a886dSMacpaul Lin
set_timer(ulong t)140445a886dSMacpaul Lin void set_timer(ulong t)
141445a886dSMacpaul Lin {
142445a886dSMacpaul Lin debug("%s(%lx)\n", __func__, t);
143445a886dSMacpaul Lin timestamp = t;
144445a886dSMacpaul Lin }
145445a886dSMacpaul Lin
146445a886dSMacpaul Lin /* delay x useconds AND preserve advance timestamp value */
__udelay(unsigned long usec)147445a886dSMacpaul Lin void __udelay(unsigned long usec)
148445a886dSMacpaul Lin {
14939c87743SMacpaul Lin struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
150445a886dSMacpaul Lin
151445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
152445a886dSMacpaul Lin long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
153445a886dSMacpaul Lin #else
154445a886dSMacpaul Lin long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000;
155445a886dSMacpaul Lin #endif
156445a886dSMacpaul Lin unsigned long now, last = readl(&tmr->timer3_counter);
157445a886dSMacpaul Lin
158445a886dSMacpaul Lin debug("%s(%lu)\n", __func__, usec);
159445a886dSMacpaul Lin while (tmo > 0) {
160445a886dSMacpaul Lin now = readl(&tmr->timer3_counter);
161445a886dSMacpaul Lin if (now > last) /* count down timer overflow */
162445a886dSMacpaul Lin tmo -= TIMER_LOAD_VAL + last - now;
163445a886dSMacpaul Lin else
164445a886dSMacpaul Lin tmo -= last - now;
165445a886dSMacpaul Lin last = now;
166445a886dSMacpaul Lin }
167445a886dSMacpaul Lin }
168445a886dSMacpaul Lin
169445a886dSMacpaul Lin /*
170445a886dSMacpaul Lin * This function is derived from PowerPC code (read timebase as long long).
171445a886dSMacpaul Lin * On ARM it just returns the timer value.
172445a886dSMacpaul Lin */
get_ticks(void)173445a886dSMacpaul Lin unsigned long long get_ticks(void)
174445a886dSMacpaul Lin {
175445a886dSMacpaul Lin debug("%s()\n", __func__);
176445a886dSMacpaul Lin return get_timer(0);
177445a886dSMacpaul Lin }
178445a886dSMacpaul Lin
179445a886dSMacpaul Lin /*
180445a886dSMacpaul Lin * This function is derived from PowerPC code (timebase clock frequency).
181445a886dSMacpaul Lin * On ARM it returns the number of timer ticks per second.
182445a886dSMacpaul Lin */
get_tbclk(void)183445a886dSMacpaul Lin ulong get_tbclk(void)
184445a886dSMacpaul Lin {
185445a886dSMacpaul Lin debug("%s()\n", __func__);
186445a886dSMacpaul Lin #ifdef CONFIG_FTTMR010_EXT_CLK
187445a886dSMacpaul Lin return CONFIG_SYS_HZ;
188445a886dSMacpaul Lin #else
189445a886dSMacpaul Lin return CONFIG_SYS_CLK_FREQ;
190445a886dSMacpaul Lin #endif
191445a886dSMacpaul Lin }
192*f5076f86Srick #endif /* CONFIG_TIMER */
193