xref: /openbmc/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c (revision 6180ea7e663893cb7330219367252cba471bf225)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
26c08d5dcSPrafulla Wadaskar /*
36c08d5dcSPrafulla Wadaskar  * (C) Copyright 2010
46c08d5dcSPrafulla Wadaskar  * Marvell Semiconductor <www.marvell.com>
56c08d5dcSPrafulla Wadaskar  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
66c08d5dcSPrafulla Wadaskar  * Contributor: Mahavir Jain <mjain@marvell.com>
76c08d5dcSPrafulla Wadaskar  */
86c08d5dcSPrafulla Wadaskar 
96c08d5dcSPrafulla Wadaskar #include <common.h>
10ab1b9552SLei Wen #include <asm/arch/cpu.h>
116c08d5dcSPrafulla Wadaskar #include <asm/arch/armada100.h>
126c08d5dcSPrafulla Wadaskar 
136c08d5dcSPrafulla Wadaskar /*
146c08d5dcSPrafulla Wadaskar  * Timer registers
156c08d5dcSPrafulla Wadaskar  * Refer Section A.6 in Datasheet
166c08d5dcSPrafulla Wadaskar  */
176c08d5dcSPrafulla Wadaskar struct armd1tmr_registers {
186c08d5dcSPrafulla Wadaskar 	u32 clk_ctrl;	/* Timer clk control reg */
196c08d5dcSPrafulla Wadaskar 	u32 match[9];	/* Timer match registers */
206c08d5dcSPrafulla Wadaskar 	u32 count[3];	/* Timer count registers */
216c08d5dcSPrafulla Wadaskar 	u32 status[3];
226c08d5dcSPrafulla Wadaskar 	u32 ie[3];
236c08d5dcSPrafulla Wadaskar 	u32 preload[3];	/* Timer preload value */
246c08d5dcSPrafulla Wadaskar 	u32 preload_ctrl[3];
256c08d5dcSPrafulla Wadaskar 	u32 wdt_match_en;
266c08d5dcSPrafulla Wadaskar 	u32 wdt_match_r;
276c08d5dcSPrafulla Wadaskar 	u32 wdt_val;
286c08d5dcSPrafulla Wadaskar 	u32 wdt_sts;
296c08d5dcSPrafulla Wadaskar 	u32 icr[3];
306c08d5dcSPrafulla Wadaskar 	u32 wdt_icr;
316c08d5dcSPrafulla Wadaskar 	u32 cer;	/* Timer count enable reg */
326c08d5dcSPrafulla Wadaskar 	u32 cmr;
336c08d5dcSPrafulla Wadaskar 	u32 ilr[3];
346c08d5dcSPrafulla Wadaskar 	u32 wcr;
356c08d5dcSPrafulla Wadaskar 	u32 wfar;
366c08d5dcSPrafulla Wadaskar 	u32 wsar;
376c08d5dcSPrafulla Wadaskar 	u32 cvwr;
386c08d5dcSPrafulla Wadaskar };
396c08d5dcSPrafulla Wadaskar 
406c08d5dcSPrafulla Wadaskar #define TIMER			0	/* Use TIMER 0 */
416c08d5dcSPrafulla Wadaskar /* Each timer has 3 match registers */
426c08d5dcSPrafulla Wadaskar #define MATCH_CMP(x)		((3 * TIMER) + x)
436c08d5dcSPrafulla Wadaskar #define TIMER_LOAD_VAL 		0xffffffff
446c08d5dcSPrafulla Wadaskar #define	COUNT_RD_REQ		0x1
456c08d5dcSPrafulla Wadaskar 
466c08d5dcSPrafulla Wadaskar DECLARE_GLOBAL_DATA_PTR;
4766ee6923SSimon Glass /* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */
486c08d5dcSPrafulla Wadaskar 
496c08d5dcSPrafulla Wadaskar /* For preventing risk of instability in reading counter value,
506c08d5dcSPrafulla Wadaskar  * first set read request to register cvwr and then read same
516c08d5dcSPrafulla Wadaskar  * register after it captures counter value.
526c08d5dcSPrafulla Wadaskar  */
read_timer(void)536c08d5dcSPrafulla Wadaskar ulong read_timer(void)
546c08d5dcSPrafulla Wadaskar {
556c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
566c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
576c08d5dcSPrafulla Wadaskar 	volatile int loop=100;
586c08d5dcSPrafulla Wadaskar 
596c08d5dcSPrafulla Wadaskar 	writel(COUNT_RD_REQ, &armd1timers->cvwr);
606c08d5dcSPrafulla Wadaskar 	while (loop--);
616c08d5dcSPrafulla Wadaskar 	return(readl(&armd1timers->cvwr));
626c08d5dcSPrafulla Wadaskar }
636c08d5dcSPrafulla Wadaskar 
get_timer_masked(void)64*6180ea7eSPatrick Delaunay static ulong get_timer_masked(void)
656c08d5dcSPrafulla Wadaskar {
666c08d5dcSPrafulla Wadaskar 	ulong now = read_timer();
676c08d5dcSPrafulla Wadaskar 
6866ee6923SSimon Glass 	if (now >= gd->arch.tbl) {
696c08d5dcSPrafulla Wadaskar 		/* normal mode */
7066ee6923SSimon Glass 		gd->arch.tbu += now - gd->arch.tbl;
716c08d5dcSPrafulla Wadaskar 	} else {
726c08d5dcSPrafulla Wadaskar 		/* we have an overflow ... */
7366ee6923SSimon Glass 		gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl;
746c08d5dcSPrafulla Wadaskar 	}
7566ee6923SSimon Glass 	gd->arch.tbl = now;
766c08d5dcSPrafulla Wadaskar 
778ff43b03SSimon Glass 	return gd->arch.tbu;
786c08d5dcSPrafulla Wadaskar }
796c08d5dcSPrafulla Wadaskar 
get_timer(ulong base)806c08d5dcSPrafulla Wadaskar ulong get_timer(ulong base)
816c08d5dcSPrafulla Wadaskar {
826c08d5dcSPrafulla Wadaskar 	return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) -
836c08d5dcSPrafulla Wadaskar 		base);
846c08d5dcSPrafulla Wadaskar }
856c08d5dcSPrafulla Wadaskar 
__udelay(unsigned long usec)866c08d5dcSPrafulla Wadaskar void __udelay(unsigned long usec)
876c08d5dcSPrafulla Wadaskar {
886c08d5dcSPrafulla Wadaskar 	ulong delayticks;
896c08d5dcSPrafulla Wadaskar 	ulong endtime;
906c08d5dcSPrafulla Wadaskar 
916c08d5dcSPrafulla Wadaskar 	delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000));
926c08d5dcSPrafulla Wadaskar 	endtime = get_timer_masked() + delayticks;
936c08d5dcSPrafulla Wadaskar 
946c08d5dcSPrafulla Wadaskar 	while (get_timer_masked() < endtime);
956c08d5dcSPrafulla Wadaskar }
966c08d5dcSPrafulla Wadaskar 
976c08d5dcSPrafulla Wadaskar /*
986c08d5dcSPrafulla Wadaskar  * init the Timer
996c08d5dcSPrafulla Wadaskar  */
timer_init(void)1006c08d5dcSPrafulla Wadaskar int timer_init(void)
1016c08d5dcSPrafulla Wadaskar {
1026c08d5dcSPrafulla Wadaskar 	struct armd1apb1_registers *apb1clkres =
1036c08d5dcSPrafulla Wadaskar 		(struct armd1apb1_registers *) ARMD1_APBC1_BASE;
1046c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
1056c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
1066c08d5dcSPrafulla Wadaskar 
1076c08d5dcSPrafulla Wadaskar 	/* Enable Timer clock at 3.25 MHZ */
1086c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers);
1096c08d5dcSPrafulla Wadaskar 
1106c08d5dcSPrafulla Wadaskar 	/* load value into timer */
1116c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->clk_ctrl);
1126c08d5dcSPrafulla Wadaskar 	/* Use Timer 0 Match Resiger 0 */
1136c08d5dcSPrafulla Wadaskar 	writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]);
1146c08d5dcSPrafulla Wadaskar 	/* Preload value is 0 */
1156c08d5dcSPrafulla Wadaskar 	writel(0x0, &armd1timers->preload[TIMER]);
1166c08d5dcSPrafulla Wadaskar 	/* Enable match comparator 0 for Timer 0 */
1176c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->preload_ctrl[TIMER]);
1186c08d5dcSPrafulla Wadaskar 
1196c08d5dcSPrafulla Wadaskar 	/* Enable timer 0 */
1206c08d5dcSPrafulla Wadaskar 	writel(0x1, &armd1timers->cer);
12166ee6923SSimon Glass 	/* init the gd->arch.tbu and gd->arch.tbl value */
12266ee6923SSimon Glass 	gd->arch.tbl = read_timer();
1238ff43b03SSimon Glass 	gd->arch.tbu = 0;
1246c08d5dcSPrafulla Wadaskar 
1256c08d5dcSPrafulla Wadaskar 	return 0;
1266c08d5dcSPrafulla Wadaskar }
1276c08d5dcSPrafulla Wadaskar 
1286c08d5dcSPrafulla Wadaskar #define MPMU_APRR_WDTR	(1<<4)
1296c08d5dcSPrafulla Wadaskar #define TMR_WFAR	0xbaba	/* WDT Register First key */
1306c08d5dcSPrafulla Wadaskar #define TMP_WSAR	0xeb10	/* WDT Register Second key */
1316c08d5dcSPrafulla Wadaskar 
1326c08d5dcSPrafulla Wadaskar /*
1336c08d5dcSPrafulla Wadaskar  * This function uses internal Watchdog Timer
1346c08d5dcSPrafulla Wadaskar  * based reset mechanism.
1356c08d5dcSPrafulla Wadaskar  * Steps to write watchdog registers (protected access)
1366c08d5dcSPrafulla Wadaskar  * 1. Write key value to TMR_WFAR reg.
1376c08d5dcSPrafulla Wadaskar  * 2. Write key value to TMP_WSAR reg.
1386c08d5dcSPrafulla Wadaskar  * 3. Perform write operation.
1396c08d5dcSPrafulla Wadaskar  */
reset_cpu(unsigned long ignored)1406c08d5dcSPrafulla Wadaskar void reset_cpu (unsigned long ignored)
1416c08d5dcSPrafulla Wadaskar {
1426c08d5dcSPrafulla Wadaskar 	struct armd1mpmu_registers *mpmu =
1436c08d5dcSPrafulla Wadaskar 		(struct armd1mpmu_registers *) ARMD1_MPMU_BASE;
1446c08d5dcSPrafulla Wadaskar 	struct armd1tmr_registers *armd1timers =
1456c08d5dcSPrafulla Wadaskar 		(struct armd1tmr_registers *) ARMD1_TIMER_BASE;
1466c08d5dcSPrafulla Wadaskar 	u32 val;
1476c08d5dcSPrafulla Wadaskar 
1486c08d5dcSPrafulla Wadaskar 	/* negate hardware reset to the WDT after system reset */
1496c08d5dcSPrafulla Wadaskar 	val = readl(&mpmu->aprr);
1506c08d5dcSPrafulla Wadaskar 	val = val | MPMU_APRR_WDTR;
1516c08d5dcSPrafulla Wadaskar 	writel(val, &mpmu->aprr);
1526c08d5dcSPrafulla Wadaskar 
1536c08d5dcSPrafulla Wadaskar 	/* reset/enable WDT clock */
1546c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr);
1556c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
1566c08d5dcSPrafulla Wadaskar 	writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr);
1576c08d5dcSPrafulla Wadaskar 	readl(&mpmu->wdtpcr);
1586c08d5dcSPrafulla Wadaskar 
1596c08d5dcSPrafulla Wadaskar 	/* clear previous WDT status */
1606c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1616c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1626c08d5dcSPrafulla Wadaskar 	writel(0, &armd1timers->wdt_sts);
1636c08d5dcSPrafulla Wadaskar 
1646c08d5dcSPrafulla Wadaskar 	/* set match counter */
1656c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1666c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1676c08d5dcSPrafulla Wadaskar 	writel(0xf, &armd1timers->wdt_match_r);
1686c08d5dcSPrafulla Wadaskar 
1696c08d5dcSPrafulla Wadaskar 	/* enable WDT reset */
1706c08d5dcSPrafulla Wadaskar 	writel(TMR_WFAR, &armd1timers->wfar);
1716c08d5dcSPrafulla Wadaskar 	writel(TMP_WSAR, &armd1timers->wsar);
1726c08d5dcSPrafulla Wadaskar 	writel(0x3, &armd1timers->wdt_match_en);
1736c08d5dcSPrafulla Wadaskar 
1746c08d5dcSPrafulla Wadaskar 	while(1);
1756c08d5dcSPrafulla Wadaskar }
17696f5c4b2SPrafulla Wadaskar 
17796f5c4b2SPrafulla Wadaskar /*
17896f5c4b2SPrafulla Wadaskar  * This function is derived from PowerPC code (read timebase as long long).
17996f5c4b2SPrafulla Wadaskar  * On ARM it just returns the timer value.
18096f5c4b2SPrafulla Wadaskar  */
get_ticks(void)18196f5c4b2SPrafulla Wadaskar unsigned long long get_ticks(void)
18296f5c4b2SPrafulla Wadaskar {
18396f5c4b2SPrafulla Wadaskar 	return get_timer(0);
18496f5c4b2SPrafulla Wadaskar }
18596f5c4b2SPrafulla Wadaskar 
18696f5c4b2SPrafulla Wadaskar /*
18796f5c4b2SPrafulla Wadaskar  * This function is derived from PowerPC code (timebase clock frequency).
18896f5c4b2SPrafulla Wadaskar  * On ARM it returns the number of timer ticks per second.
18996f5c4b2SPrafulla Wadaskar  */
get_tbclk(void)19096f5c4b2SPrafulla Wadaskar ulong get_tbclk (void)
19196f5c4b2SPrafulla Wadaskar {
19296f5c4b2SPrafulla Wadaskar 	return (ulong)CONFIG_SYS_HZ;
19396f5c4b2SPrafulla Wadaskar }
194