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