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