1*83d290c5STom 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 */ 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 646c08d5dcSPrafulla Wadaskar 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 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 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 */ 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 */ 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 */ 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 */ 19096f5c4b2SPrafulla Wadaskar ulong get_tbclk (void) 19196f5c4b2SPrafulla Wadaskar { 19296f5c4b2SPrafulla Wadaskar return (ulong)CONFIG_SYS_HZ; 19396f5c4b2SPrafulla Wadaskar } 194