xref: /OK3568_Linux_fs/u-boot/arch/nds32/cpu/n1213/ag101/timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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