1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2009 Faraday Technology
3*4882a593Smuzhiyun * Po-Yu Chuang <ratbert@faraday-tech.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2011 Andes Technology Corporation
6*4882a593Smuzhiyun * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
7*4882a593Smuzhiyun * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun #ifndef CONFIG_TIMER
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <faraday/fttmr010.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun static ulong timestamp;
17*4882a593Smuzhiyun static ulong lastdec;
18*4882a593Smuzhiyun
timer_init(void)19*4882a593Smuzhiyun int timer_init(void)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
22*4882a593Smuzhiyun unsigned int cr;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun debug("%s()\n", __func__);
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* disable timers */
27*4882a593Smuzhiyun writel(0, &tmr->cr);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
30*4882a593Smuzhiyun /* use 32768Hz oscillator for RTC, WDT, TIMER */
31*4882a593Smuzhiyun ftpmu010_32768osc_enable();
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /* setup timer */
35*4882a593Smuzhiyun writel(TIMER_LOAD_VAL, &tmr->timer3_load);
36*4882a593Smuzhiyun writel(TIMER_LOAD_VAL, &tmr->timer3_counter);
37*4882a593Smuzhiyun writel(0, &tmr->timer3_match1);
38*4882a593Smuzhiyun writel(0, &tmr->timer3_match2);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* we don't want timer to issue interrupts */
41*4882a593Smuzhiyun writel(FTTMR010_TM3_MATCH1 |
42*4882a593Smuzhiyun FTTMR010_TM3_MATCH2 |
43*4882a593Smuzhiyun FTTMR010_TM3_OVERFLOW,
44*4882a593Smuzhiyun &tmr->interrupt_mask);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun cr = readl(&tmr->cr);
47*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
48*4882a593Smuzhiyun cr |= FTTMR010_TM3_CLOCK; /* use external clock */
49*4882a593Smuzhiyun #endif
50*4882a593Smuzhiyun cr |= FTTMR010_TM3_ENABLE;
51*4882a593Smuzhiyun writel(cr, &tmr->cr);
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* init the timestamp and lastdec value */
54*4882a593Smuzhiyun reset_timer_masked();
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * timer without interrupts
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /*
64*4882a593Smuzhiyun * reset time
65*4882a593Smuzhiyun */
reset_timer_masked(void)66*4882a593Smuzhiyun void reset_timer_masked(void)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* capure current decrementer value time */
71*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
72*4882a593Smuzhiyun lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
73*4882a593Smuzhiyun #else
74*4882a593Smuzhiyun lastdec = readl(&tmr->timer3_counter) /
75*4882a593Smuzhiyun (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun timestamp = 0; /* start "advancing" time stamp from 0 */
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun debug("%s(): lastdec = %lx\n", __func__, lastdec);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
reset_timer(void)82*4882a593Smuzhiyun void reset_timer(void)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun debug("%s()\n", __func__);
85*4882a593Smuzhiyun reset_timer_masked();
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * return timer ticks
90*4882a593Smuzhiyun */
get_timer_masked(void)91*4882a593Smuzhiyun ulong get_timer_masked(void)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* current tick value */
96*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
97*4882a593Smuzhiyun ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
98*4882a593Smuzhiyun #else
99*4882a593Smuzhiyun ulong now = readl(&tmr->timer3_counter) /
100*4882a593Smuzhiyun (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
101*4882a593Smuzhiyun #endif
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (lastdec >= now) {
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun * normal mode (non roll)
108*4882a593Smuzhiyun * move stamp fordward with absoulte diff ticks
109*4882a593Smuzhiyun */
110*4882a593Smuzhiyun timestamp += lastdec - now;
111*4882a593Smuzhiyun } else {
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * we have overflow of the count down timer
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * nts = ts + ld + (TLV - now)
116*4882a593Smuzhiyun * ts=old stamp, ld=time that passed before passing through -1
117*4882a593Smuzhiyun * (TLV-now) amount of time after passing though -1
118*4882a593Smuzhiyun * nts = new "advancing time stamp"...it could also roll and
119*4882a593Smuzhiyun * cause problems.
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun timestamp += lastdec + TIMER_LOAD_VAL - now;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun lastdec = now;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun debug("%s() returns %lx\n", __func__, timestamp);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return timestamp;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /*
132*4882a593Smuzhiyun * return difference between timer ticks and base
133*4882a593Smuzhiyun */
get_timer(ulong base)134*4882a593Smuzhiyun ulong get_timer(ulong base)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun debug("%s(%lx)\n", __func__, base);
137*4882a593Smuzhiyun return get_timer_masked() - base;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
set_timer(ulong t)140*4882a593Smuzhiyun void set_timer(ulong t)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun debug("%s(%lx)\n", __func__, t);
143*4882a593Smuzhiyun timestamp = t;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* delay x useconds AND preserve advance timestamp value */
__udelay(unsigned long usec)147*4882a593Smuzhiyun void __udelay(unsigned long usec)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
152*4882a593Smuzhiyun long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
153*4882a593Smuzhiyun #else
154*4882a593Smuzhiyun long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000;
155*4882a593Smuzhiyun #endif
156*4882a593Smuzhiyun unsigned long now, last = readl(&tmr->timer3_counter);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun debug("%s(%lu)\n", __func__, usec);
159*4882a593Smuzhiyun while (tmo > 0) {
160*4882a593Smuzhiyun now = readl(&tmr->timer3_counter);
161*4882a593Smuzhiyun if (now > last) /* count down timer overflow */
162*4882a593Smuzhiyun tmo -= TIMER_LOAD_VAL + last - now;
163*4882a593Smuzhiyun else
164*4882a593Smuzhiyun tmo -= last - now;
165*4882a593Smuzhiyun last = now;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun * This function is derived from PowerPC code (read timebase as long long).
171*4882a593Smuzhiyun * On ARM it just returns the timer value.
172*4882a593Smuzhiyun */
get_ticks(void)173*4882a593Smuzhiyun unsigned long long get_ticks(void)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun debug("%s()\n", __func__);
176*4882a593Smuzhiyun return get_timer(0);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun * This function is derived from PowerPC code (timebase clock frequency).
181*4882a593Smuzhiyun * On ARM it returns the number of timer ticks per second.
182*4882a593Smuzhiyun */
get_tbclk(void)183*4882a593Smuzhiyun ulong get_tbclk(void)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun debug("%s()\n", __func__);
186*4882a593Smuzhiyun #ifdef CONFIG_FTTMR010_EXT_CLK
187*4882a593Smuzhiyun return CONFIG_SYS_HZ;
188*4882a593Smuzhiyun #else
189*4882a593Smuzhiyun return CONFIG_SYS_CLK_FREQ;
190*4882a593Smuzhiyun #endif
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun #endif /* CONFIG_TIMER */
193