xref: /openbmc/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c (revision 8ff43b03e9f38a6e136e2e20eec4e8b2eb4a1d3d)
16c08d5dcSPrafulla Wadaskar /*
26c08d5dcSPrafulla Wadaskar  * (C) Copyright 2010
36c08d5dcSPrafulla Wadaskar  * Marvell Semiconductor <www.marvell.com>
46c08d5dcSPrafulla Wadaskar  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
56c08d5dcSPrafulla Wadaskar  * Contributor: Mahavir Jain <mjain@marvell.com>
66c08d5dcSPrafulla Wadaskar  *
76c08d5dcSPrafulla Wadaskar  * See file CREDITS for list of people who contributed to this
86c08d5dcSPrafulla Wadaskar  * project.
96c08d5dcSPrafulla Wadaskar  *
106c08d5dcSPrafulla Wadaskar  * This program is free software; you can redistribute it and/or
116c08d5dcSPrafulla Wadaskar  * modify it under the terms of the GNU General Public License as
126c08d5dcSPrafulla Wadaskar  * published by the Free Software Foundation; either version 2 of
136c08d5dcSPrafulla Wadaskar  * the License, or (at your option) any later version.
146c08d5dcSPrafulla Wadaskar  *
156c08d5dcSPrafulla Wadaskar  * This program is distributed in the hope that it will be useful,
166c08d5dcSPrafulla Wadaskar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
176c08d5dcSPrafulla Wadaskar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
186c08d5dcSPrafulla Wadaskar  * GNU General Public License for more details.
196c08d5dcSPrafulla Wadaskar  *
206c08d5dcSPrafulla Wadaskar  * You should have received a copy of the GNU General Public License
216c08d5dcSPrafulla Wadaskar  * along with this program; if not, write to the Free Software
226c08d5dcSPrafulla Wadaskar  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
236c08d5dcSPrafulla Wadaskar  * MA 02110-1301 USA
246c08d5dcSPrafulla Wadaskar  */
256c08d5dcSPrafulla Wadaskar 
266c08d5dcSPrafulla Wadaskar #include <common.h>
27ab1b9552SLei Wen #include <asm/arch/cpu.h>
286c08d5dcSPrafulla Wadaskar #include <asm/arch/armada100.h>
296c08d5dcSPrafulla Wadaskar 
306c08d5dcSPrafulla Wadaskar /*
316c08d5dcSPrafulla Wadaskar  * Timer registers
326c08d5dcSPrafulla Wadaskar  * Refer Section A.6 in Datasheet
336c08d5dcSPrafulla Wadaskar  */
346c08d5dcSPrafulla Wadaskar struct armd1tmr_registers {
356c08d5dcSPrafulla Wadaskar 	u32 clk_ctrl;	/* Timer clk control reg */
366c08d5dcSPrafulla Wadaskar 	u32 match[9];	/* Timer match registers */
376c08d5dcSPrafulla Wadaskar 	u32 count[3];	/* Timer count registers */
386c08d5dcSPrafulla Wadaskar 	u32 status[3];
396c08d5dcSPrafulla Wadaskar 	u32 ie[3];
406c08d5dcSPrafulla Wadaskar 	u32 preload[3];	/* Timer preload value */
416c08d5dcSPrafulla Wadaskar 	u32 preload_ctrl[3];
426c08d5dcSPrafulla Wadaskar 	u32 wdt_match_en;
436c08d5dcSPrafulla Wadaskar 	u32 wdt_match_r;
446c08d5dcSPrafulla Wadaskar 	u32 wdt_val;
456c08d5dcSPrafulla Wadaskar 	u32 wdt_sts;
466c08d5dcSPrafulla Wadaskar 	u32 icr[3];
476c08d5dcSPrafulla Wadaskar 	u32 wdt_icr;
486c08d5dcSPrafulla Wadaskar 	u32 cer;	/* Timer count enable reg */
496c08d5dcSPrafulla Wadaskar 	u32 cmr;
506c08d5dcSPrafulla Wadaskar 	u32 ilr[3];
516c08d5dcSPrafulla Wadaskar 	u32 wcr;
526c08d5dcSPrafulla Wadaskar 	u32 wfar;
536c08d5dcSPrafulla Wadaskar 	u32 wsar;
546c08d5dcSPrafulla Wadaskar 	u32 cvwr;
556c08d5dcSPrafulla Wadaskar };
566c08d5dcSPrafulla Wadaskar 
576c08d5dcSPrafulla Wadaskar #define TIMER			0	/* Use TIMER 0 */
586c08d5dcSPrafulla Wadaskar /* Each timer has 3 match registers */
596c08d5dcSPrafulla Wadaskar #define MATCH_CMP(x)		((3 * TIMER) + x)
606c08d5dcSPrafulla Wadaskar #define TIMER_LOAD_VAL 		0xffffffff
616c08d5dcSPrafulla Wadaskar #define	COUNT_RD_REQ		0x1
626c08d5dcSPrafulla Wadaskar 
636c08d5dcSPrafulla Wadaskar DECLARE_GLOBAL_DATA_PTR;
64*8ff43b03SSimon Glass /* Using gd->arch.tbu from timestamp and gd->tbl for lastdec */
656c08d5dcSPrafulla Wadaskar 
666c08d5dcSPrafulla Wadaskar /* For preventing risk of instability in reading counter value,
676c08d5dcSPrafulla Wadaskar  * first set read request to register cvwr and then read same
686c08d5dcSPrafulla Wadaskar  * register after it captures counter value.
696c08d5dcSPrafulla Wadaskar  */
706c08d5dcSPrafulla Wadaskar ulong read_timer(void)
716c08d5dcSPrafulla Wadaskar {
726c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
736c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
746c08d5dcSPrafulla Wadaskar 	volatile int loop=100;
756c08d5dcSPrafulla Wadaskar 
766c08d5dcSPrafulla Wadaskar 	writel(COUNT_RD_REQ, &armd1timers->cvwr);
776c08d5dcSPrafulla Wadaskar 	while (loop--);
786c08d5dcSPrafulla Wadaskar 	return(readl(&armd1timers->cvwr));
796c08d5dcSPrafulla Wadaskar }
806c08d5dcSPrafulla Wadaskar 
816c08d5dcSPrafulla Wadaskar ulong get_timer_masked(void)
826c08d5dcSPrafulla Wadaskar {
836c08d5dcSPrafulla Wadaskar 	ulong now = read_timer();
846c08d5dcSPrafulla Wadaskar 
856c08d5dcSPrafulla Wadaskar 	if (now >= gd->tbl) {
866c08d5dcSPrafulla Wadaskar 		/* normal mode */
87*8ff43b03SSimon Glass 		gd->arch.tbu += now - gd->tbl;
886c08d5dcSPrafulla Wadaskar 	} else {
896c08d5dcSPrafulla Wadaskar 		/* we have an overflow ... */
90*8ff43b03SSimon Glass 		gd->arch.tbu += now + TIMER_LOAD_VAL - gd->tbl;
916c08d5dcSPrafulla Wadaskar 	}
926c08d5dcSPrafulla Wadaskar 	gd->tbl = now;
936c08d5dcSPrafulla Wadaskar 
94*8ff43b03SSimon Glass 	return gd->arch.tbu;
956c08d5dcSPrafulla Wadaskar }
966c08d5dcSPrafulla Wadaskar 
976c08d5dcSPrafulla Wadaskar ulong get_timer(ulong base)
986c08d5dcSPrafulla Wadaskar {
996c08d5dcSPrafulla Wadaskar 	return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) -
1006c08d5dcSPrafulla Wadaskar 		base);
1016c08d5dcSPrafulla Wadaskar }
1026c08d5dcSPrafulla Wadaskar 
1036c08d5dcSPrafulla Wadaskar void __udelay(unsigned long usec)
1046c08d5dcSPrafulla Wadaskar {
1056c08d5dcSPrafulla Wadaskar 	ulong delayticks;
1066c08d5dcSPrafulla Wadaskar 	ulong endtime;
1076c08d5dcSPrafulla Wadaskar 
1086c08d5dcSPrafulla Wadaskar 	delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000));
1096c08d5dcSPrafulla Wadaskar 	endtime = get_timer_masked() + delayticks;
1106c08d5dcSPrafulla Wadaskar 
1116c08d5dcSPrafulla Wadaskar 	while (get_timer_masked() < endtime);
1126c08d5dcSPrafulla Wadaskar }
1136c08d5dcSPrafulla Wadaskar 
1146c08d5dcSPrafulla Wadaskar /*
1156c08d5dcSPrafulla Wadaskar  * init the Timer
1166c08d5dcSPrafulla Wadaskar  */
1176c08d5dcSPrafulla Wadaskar int timer_init(void)
1186c08d5dcSPrafulla Wadaskar {
1196c08d5dcSPrafulla Wadaskar 	struct armd1apb1_registers *apb1clkres =
1206c08d5dcSPrafulla Wadaskar 		(struct armd1apb1_registers *) ARMD1_APBC1_BASE;
1216c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
1226c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
1236c08d5dcSPrafulla Wadaskar 
1246c08d5dcSPrafulla Wadaskar 	/* Enable Timer clock at 3.25 MHZ */
1256c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers);
1266c08d5dcSPrafulla Wadaskar 
1276c08d5dcSPrafulla Wadaskar 	/* load value into timer */
1286c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->clk_ctrl);
1296c08d5dcSPrafulla Wadaskar 	/* Use Timer 0 Match Resiger 0 */
1306c08d5dcSPrafulla Wadaskar 	writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]);
1316c08d5dcSPrafulla Wadaskar 	/* Preload value is 0 */
1326c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->preload[TIMER]);
1336c08d5dcSPrafulla Wadaskar 	/* Enable match comparator 0 for Timer 0 */
1346c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->preload_ctrl[TIMER]);
1356c08d5dcSPrafulla Wadaskar 
1366c08d5dcSPrafulla Wadaskar 	/* Enable timer 0 */
1376c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->cer);
138*8ff43b03SSimon Glass 	/* init the gd->arch.tbu and gd->tbl value */
13917659d7dSGraeme Russ 	gd->tbl = read_timer();
140*8ff43b03SSimon Glass 	gd->arch.tbu = 0;
1416c08d5dcSPrafulla Wadaskar 
1426c08d5dcSPrafulla Wadaskar 	return 0;
1436c08d5dcSPrafulla Wadaskar }
1446c08d5dcSPrafulla Wadaskar 
1456c08d5dcSPrafulla Wadaskar #define MPMU_APRR_WDTR	(1<<4)
1466c08d5dcSPrafulla Wadaskar #define TMR_WFAR	0xbaba	/* WDT Register First key */
1476c08d5dcSPrafulla Wadaskar #define TMP_WSAR	0xeb10	/* WDT Register Second key */
1486c08d5dcSPrafulla Wadaskar 
1496c08d5dcSPrafulla Wadaskar /*
1506c08d5dcSPrafulla Wadaskar  * This function uses internal Watchdog Timer
1516c08d5dcSPrafulla Wadaskar  * based reset mechanism.
1526c08d5dcSPrafulla Wadaskar  * Steps to write watchdog registers (protected access)
1536c08d5dcSPrafulla Wadaskar  * 1. Write key value to TMR_WFAR reg.
1546c08d5dcSPrafulla Wadaskar  * 2. Write key value to TMP_WSAR reg.
1556c08d5dcSPrafulla Wadaskar  * 3. Perform write operation.
1566c08d5dcSPrafulla Wadaskar  */
1576c08d5dcSPrafulla Wadaskar void reset_cpu (unsigned long ignored)
1586c08d5dcSPrafulla Wadaskar {
1596c08d5dcSPrafulla Wadaskar 	struct armd1mpmu_registers *mpmu =
1606c08d5dcSPrafulla Wadaskar 		(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
1616c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
1626c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
1636c08d5dcSPrafulla Wadaskar 	u32 val;
1646c08d5dcSPrafulla Wadaskar 
1656c08d5dcSPrafulla Wadaskar 	/* negate hardware reset to the WDT after system reset */
1666c08d5dcSPrafulla Wadaskar 	val = readl(&mpmu->aprr);
1676c08d5dcSPrafulla Wadaskar 	val = val | MPMU_APRR_WDTR;
1686c08d5dcSPrafulla Wadaskar 	writel(val, &mpmu->aprr);
1696c08d5dcSPrafulla Wadaskar 
1706c08d5dcSPrafulla Wadaskar 	/* reset/enable WDT clock */
1716c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr);
1726c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
1736c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr);
1746c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
1756c08d5dcSPrafulla Wadaskar 
1766c08d5dcSPrafulla Wadaskar 	/* clear previous WDT status */
1776c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1786c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1796c08d5dcSPrafulla Wadaskar 	writel(0, &armd1timers->wdt_sts);
1806c08d5dcSPrafulla Wadaskar 
1816c08d5dcSPrafulla Wadaskar 	/* set match counter */
1826c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1836c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1846c08d5dcSPrafulla Wadaskar 	writel(0xf, &armd1timers->wdt_match_r);
1856c08d5dcSPrafulla Wadaskar 
1866c08d5dcSPrafulla Wadaskar 	/* enable WDT reset */
1876c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1886c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1896c08d5dcSPrafulla Wadaskar 	writel(0x3, &armd1timers->wdt_match_en);
1906c08d5dcSPrafulla Wadaskar 
1916c08d5dcSPrafulla Wadaskar 	while(1);
1926c08d5dcSPrafulla Wadaskar }
19396f5c4b2SPrafulla Wadaskar 
19496f5c4b2SPrafulla Wadaskar /*
19596f5c4b2SPrafulla Wadaskar  * This function is derived from PowerPC code (read timebase as long long).
19696f5c4b2SPrafulla Wadaskar  * On ARM it just returns the timer value.
19796f5c4b2SPrafulla Wadaskar  */
19896f5c4b2SPrafulla Wadaskar unsigned long long get_ticks(void)
19996f5c4b2SPrafulla Wadaskar {
20096f5c4b2SPrafulla Wadaskar 	return get_timer(0);
20196f5c4b2SPrafulla Wadaskar }
20296f5c4b2SPrafulla Wadaskar 
20396f5c4b2SPrafulla Wadaskar /*
20496f5c4b2SPrafulla Wadaskar  * This function is derived from PowerPC code (timebase clock frequency).
20596f5c4b2SPrafulla Wadaskar  * On ARM it returns the number of timer ticks per second.
20696f5c4b2SPrafulla Wadaskar  */
20796f5c4b2SPrafulla Wadaskar ulong get_tbclk (void)
20896f5c4b2SPrafulla Wadaskar {
20996f5c4b2SPrafulla Wadaskar 	return (ulong)CONFIG_SYS_HZ;
21096f5c4b2SPrafulla Wadaskar }
211