xref: /openbmc/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c (revision 6c08d5dcf845c798173b883d7cc3d453de1dbd7e)
1*6c08d5dcSPrafulla Wadaskar /*
2*6c08d5dcSPrafulla Wadaskar  * (C) Copyright 2010
3*6c08d5dcSPrafulla Wadaskar  * Marvell Semiconductor <www.marvell.com>
4*6c08d5dcSPrafulla Wadaskar  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
5*6c08d5dcSPrafulla Wadaskar  * Contributor: Mahavir Jain <mjain@marvell.com>
6*6c08d5dcSPrafulla Wadaskar  *
7*6c08d5dcSPrafulla Wadaskar  * See file CREDITS for list of people who contributed to this
8*6c08d5dcSPrafulla Wadaskar  * project.
9*6c08d5dcSPrafulla Wadaskar  *
10*6c08d5dcSPrafulla Wadaskar  * This program is free software; you can redistribute it and/or
11*6c08d5dcSPrafulla Wadaskar  * modify it under the terms of the GNU General Public License as
12*6c08d5dcSPrafulla Wadaskar  * published by the Free Software Foundation; either version 2 of
13*6c08d5dcSPrafulla Wadaskar  * the License, or (at your option) any later version.
14*6c08d5dcSPrafulla Wadaskar  *
15*6c08d5dcSPrafulla Wadaskar  * This program is distributed in the hope that it will be useful,
16*6c08d5dcSPrafulla Wadaskar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*6c08d5dcSPrafulla Wadaskar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18*6c08d5dcSPrafulla Wadaskar  * GNU General Public License for more details.
19*6c08d5dcSPrafulla Wadaskar  *
20*6c08d5dcSPrafulla Wadaskar  * You should have received a copy of the GNU General Public License
21*6c08d5dcSPrafulla Wadaskar  * along with this program; if not, write to the Free Software
22*6c08d5dcSPrafulla Wadaskar  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23*6c08d5dcSPrafulla Wadaskar  * MA 02110-1301 USA
24*6c08d5dcSPrafulla Wadaskar  */
25*6c08d5dcSPrafulla Wadaskar 
26*6c08d5dcSPrafulla Wadaskar #include <common.h>
27*6c08d5dcSPrafulla Wadaskar #include <asm/arch/armada100.h>
28*6c08d5dcSPrafulla Wadaskar 
29*6c08d5dcSPrafulla Wadaskar /*
30*6c08d5dcSPrafulla Wadaskar  * Timer registers
31*6c08d5dcSPrafulla Wadaskar  * Refer Section A.6 in Datasheet
32*6c08d5dcSPrafulla Wadaskar  */
33*6c08d5dcSPrafulla Wadaskar struct armd1tmr_registers {
34*6c08d5dcSPrafulla Wadaskar 	u32 clk_ctrl;	/* Timer clk control reg */
35*6c08d5dcSPrafulla Wadaskar 	u32 match[9];	/* Timer match registers */
36*6c08d5dcSPrafulla Wadaskar 	u32 count[3];	/* Timer count registers */
37*6c08d5dcSPrafulla Wadaskar 	u32 status[3];
38*6c08d5dcSPrafulla Wadaskar 	u32 ie[3];
39*6c08d5dcSPrafulla Wadaskar 	u32 preload[3];	/* Timer preload value */
40*6c08d5dcSPrafulla Wadaskar 	u32 preload_ctrl[3];
41*6c08d5dcSPrafulla Wadaskar 	u32 wdt_match_en;
42*6c08d5dcSPrafulla Wadaskar 	u32 wdt_match_r;
43*6c08d5dcSPrafulla Wadaskar 	u32 wdt_val;
44*6c08d5dcSPrafulla Wadaskar 	u32 wdt_sts;
45*6c08d5dcSPrafulla Wadaskar 	u32 icr[3];
46*6c08d5dcSPrafulla Wadaskar 	u32 wdt_icr;
47*6c08d5dcSPrafulla Wadaskar 	u32 cer;	/* Timer count enable reg */
48*6c08d5dcSPrafulla Wadaskar 	u32 cmr;
49*6c08d5dcSPrafulla Wadaskar 	u32 ilr[3];
50*6c08d5dcSPrafulla Wadaskar 	u32 wcr;
51*6c08d5dcSPrafulla Wadaskar 	u32 wfar;
52*6c08d5dcSPrafulla Wadaskar 	u32 wsar;
53*6c08d5dcSPrafulla Wadaskar 	u32 cvwr;
54*6c08d5dcSPrafulla Wadaskar };
55*6c08d5dcSPrafulla Wadaskar 
56*6c08d5dcSPrafulla Wadaskar #define TIMER			0	/* Use TIMER 0 */
57*6c08d5dcSPrafulla Wadaskar /* Each timer has 3 match registers */
58*6c08d5dcSPrafulla Wadaskar #define MATCH_CMP(x)		((3 * TIMER) + x)
59*6c08d5dcSPrafulla Wadaskar #define TIMER_LOAD_VAL 		0xffffffff
60*6c08d5dcSPrafulla Wadaskar #define	COUNT_RD_REQ		0x1
61*6c08d5dcSPrafulla Wadaskar 
62*6c08d5dcSPrafulla Wadaskar DECLARE_GLOBAL_DATA_PTR;
63*6c08d5dcSPrafulla Wadaskar /* Using gd->tbu from timestamp and gd->tbl for lastdec */
64*6c08d5dcSPrafulla Wadaskar 
65*6c08d5dcSPrafulla Wadaskar /* For preventing risk of instability in reading counter value,
66*6c08d5dcSPrafulla Wadaskar  * first set read request to register cvwr and then read same
67*6c08d5dcSPrafulla Wadaskar  * register after it captures counter value.
68*6c08d5dcSPrafulla Wadaskar  */
69*6c08d5dcSPrafulla Wadaskar ulong read_timer(void)
70*6c08d5dcSPrafulla Wadaskar {
71*6c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
72*6c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
73*6c08d5dcSPrafulla Wadaskar 	volatile int loop=100;
74*6c08d5dcSPrafulla Wadaskar 
75*6c08d5dcSPrafulla Wadaskar 	writel(COUNT_RD_REQ, &armd1timers->cvwr);
76*6c08d5dcSPrafulla Wadaskar 	while (loop--);
77*6c08d5dcSPrafulla Wadaskar 	return(readl(&armd1timers->cvwr));
78*6c08d5dcSPrafulla Wadaskar }
79*6c08d5dcSPrafulla Wadaskar 
80*6c08d5dcSPrafulla Wadaskar void reset_timer_masked(void)
81*6c08d5dcSPrafulla Wadaskar {
82*6c08d5dcSPrafulla Wadaskar 	/* reset time */
83*6c08d5dcSPrafulla Wadaskar 	gd->tbl = read_timer();
84*6c08d5dcSPrafulla Wadaskar 	gd->tbu = 0;
85*6c08d5dcSPrafulla Wadaskar }
86*6c08d5dcSPrafulla Wadaskar 
87*6c08d5dcSPrafulla Wadaskar ulong get_timer_masked(void)
88*6c08d5dcSPrafulla Wadaskar {
89*6c08d5dcSPrafulla Wadaskar 	ulong now = read_timer();
90*6c08d5dcSPrafulla Wadaskar 
91*6c08d5dcSPrafulla Wadaskar 	if (now >= gd->tbl) {
92*6c08d5dcSPrafulla Wadaskar 		/* normal mode */
93*6c08d5dcSPrafulla Wadaskar 		gd->tbu += now - gd->tbl;
94*6c08d5dcSPrafulla Wadaskar 	} else {
95*6c08d5dcSPrafulla Wadaskar 		/* we have an overflow ... */
96*6c08d5dcSPrafulla Wadaskar 		gd->tbu += now + TIMER_LOAD_VAL - gd->tbl;
97*6c08d5dcSPrafulla Wadaskar 	}
98*6c08d5dcSPrafulla Wadaskar 	gd->tbl = now;
99*6c08d5dcSPrafulla Wadaskar 
100*6c08d5dcSPrafulla Wadaskar 	return gd->tbu;
101*6c08d5dcSPrafulla Wadaskar }
102*6c08d5dcSPrafulla Wadaskar 
103*6c08d5dcSPrafulla Wadaskar void reset_timer(void)
104*6c08d5dcSPrafulla Wadaskar {
105*6c08d5dcSPrafulla Wadaskar 	reset_timer_masked();
106*6c08d5dcSPrafulla Wadaskar }
107*6c08d5dcSPrafulla Wadaskar 
108*6c08d5dcSPrafulla Wadaskar ulong get_timer(ulong base)
109*6c08d5dcSPrafulla Wadaskar {
110*6c08d5dcSPrafulla Wadaskar 	return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) -
111*6c08d5dcSPrafulla Wadaskar 		base);
112*6c08d5dcSPrafulla Wadaskar }
113*6c08d5dcSPrafulla Wadaskar 
114*6c08d5dcSPrafulla Wadaskar void set_timer(ulong t)
115*6c08d5dcSPrafulla Wadaskar {
116*6c08d5dcSPrafulla Wadaskar 	gd->tbu = t;
117*6c08d5dcSPrafulla Wadaskar }
118*6c08d5dcSPrafulla Wadaskar 
119*6c08d5dcSPrafulla Wadaskar void __udelay(unsigned long usec)
120*6c08d5dcSPrafulla Wadaskar {
121*6c08d5dcSPrafulla Wadaskar 	ulong delayticks;
122*6c08d5dcSPrafulla Wadaskar 	ulong endtime;
123*6c08d5dcSPrafulla Wadaskar 
124*6c08d5dcSPrafulla Wadaskar 	delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000));
125*6c08d5dcSPrafulla Wadaskar 	endtime = get_timer_masked() + delayticks;
126*6c08d5dcSPrafulla Wadaskar 
127*6c08d5dcSPrafulla Wadaskar 	while (get_timer_masked() < endtime);
128*6c08d5dcSPrafulla Wadaskar }
129*6c08d5dcSPrafulla Wadaskar 
130*6c08d5dcSPrafulla Wadaskar /*
131*6c08d5dcSPrafulla Wadaskar  * init the Timer
132*6c08d5dcSPrafulla Wadaskar  */
133*6c08d5dcSPrafulla Wadaskar int timer_init(void)
134*6c08d5dcSPrafulla Wadaskar {
135*6c08d5dcSPrafulla Wadaskar 	struct armd1apb1_registers *apb1clkres =
136*6c08d5dcSPrafulla Wadaskar 		(struct armd1apb1_registers *) ARMD1_APBC1_BASE;
137*6c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
138*6c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
139*6c08d5dcSPrafulla Wadaskar 
140*6c08d5dcSPrafulla Wadaskar 	/* Enable Timer clock at 3.25 MHZ */
141*6c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers);
142*6c08d5dcSPrafulla Wadaskar 
143*6c08d5dcSPrafulla Wadaskar 	/* load value into timer */
144*6c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->clk_ctrl);
145*6c08d5dcSPrafulla Wadaskar 	/* Use Timer 0 Match Resiger 0 */
146*6c08d5dcSPrafulla Wadaskar 	writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]);
147*6c08d5dcSPrafulla Wadaskar 	/* Preload value is 0 */
148*6c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->preload[TIMER]);
149*6c08d5dcSPrafulla Wadaskar 	/* Enable match comparator 0 for Timer 0 */
150*6c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->preload_ctrl[TIMER]);
151*6c08d5dcSPrafulla Wadaskar 
152*6c08d5dcSPrafulla Wadaskar 	/* Enable timer 0 */
153*6c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->cer);
154*6c08d5dcSPrafulla Wadaskar 	/* init the gd->tbu and gd->tbl value */
155*6c08d5dcSPrafulla Wadaskar 	reset_timer_masked();
156*6c08d5dcSPrafulla Wadaskar 
157*6c08d5dcSPrafulla Wadaskar 	return 0;
158*6c08d5dcSPrafulla Wadaskar }
159*6c08d5dcSPrafulla Wadaskar 
160*6c08d5dcSPrafulla Wadaskar #define MPMU_APRR_WDTR	(1<<4)
161*6c08d5dcSPrafulla Wadaskar #define TMR_WFAR	0xbaba	/* WDT Register First key */
162*6c08d5dcSPrafulla Wadaskar #define TMP_WSAR	0xeb10	/* WDT Register Second key */
163*6c08d5dcSPrafulla Wadaskar 
164*6c08d5dcSPrafulla Wadaskar /*
165*6c08d5dcSPrafulla Wadaskar  * This function uses internal Watchdog Timer
166*6c08d5dcSPrafulla Wadaskar  * based reset mechanism.
167*6c08d5dcSPrafulla Wadaskar  * Steps to write watchdog registers (protected access)
168*6c08d5dcSPrafulla Wadaskar  * 1. Write key value to TMR_WFAR reg.
169*6c08d5dcSPrafulla Wadaskar  * 2. Write key value to TMP_WSAR reg.
170*6c08d5dcSPrafulla Wadaskar  * 3. Perform write operation.
171*6c08d5dcSPrafulla Wadaskar  */
172*6c08d5dcSPrafulla Wadaskar void reset_cpu (unsigned long ignored)
173*6c08d5dcSPrafulla Wadaskar {
174*6c08d5dcSPrafulla Wadaskar 	struct armd1mpmu_registers *mpmu =
175*6c08d5dcSPrafulla Wadaskar 		(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
176*6c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
177*6c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
178*6c08d5dcSPrafulla Wadaskar 	u32 val;
179*6c08d5dcSPrafulla Wadaskar 
180*6c08d5dcSPrafulla Wadaskar 	/* negate hardware reset to the WDT after system reset */
181*6c08d5dcSPrafulla Wadaskar 	val = readl(&mpmu->aprr);
182*6c08d5dcSPrafulla Wadaskar 	val = val | MPMU_APRR_WDTR;
183*6c08d5dcSPrafulla Wadaskar 	writel(val, &mpmu->aprr);
184*6c08d5dcSPrafulla Wadaskar 
185*6c08d5dcSPrafulla Wadaskar 	/* reset/enable WDT clock */
186*6c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr);
187*6c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
188*6c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr);
189*6c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
190*6c08d5dcSPrafulla Wadaskar 
191*6c08d5dcSPrafulla Wadaskar 	/* clear previous WDT status */
192*6c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
193*6c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
194*6c08d5dcSPrafulla Wadaskar 	writel(0, &armd1timers->wdt_sts);
195*6c08d5dcSPrafulla Wadaskar 
196*6c08d5dcSPrafulla Wadaskar 	/* set match counter */
197*6c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
198*6c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
199*6c08d5dcSPrafulla Wadaskar 	writel(0xf, &armd1timers->wdt_match_r);
200*6c08d5dcSPrafulla Wadaskar 
201*6c08d5dcSPrafulla Wadaskar 	/* enable WDT reset */
202*6c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
203*6c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
204*6c08d5dcSPrafulla Wadaskar 	writel(0x3, &armd1timers->wdt_match_en);
205*6c08d5dcSPrafulla Wadaskar 
206*6c08d5dcSPrafulla Wadaskar 	while(1);
207*6c08d5dcSPrafulla Wadaskar }
208