1 /* 2 * (C) Copyright 2010 3 * Marvell Semiconductor <www.marvell.com> 4 * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 5 * Contributor: Mahavir Jain <mjain@marvell.com> 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 23 * MA 02110-1301 USA 24 */ 25 26 #include <common.h> 27 #include <asm/arch/cpu.h> 28 #include <asm/arch/armada100.h> 29 30 /* 31 * Timer registers 32 * Refer Section A.6 in Datasheet 33 */ 34 struct armd1tmr_registers { 35 u32 clk_ctrl; /* Timer clk control reg */ 36 u32 match[9]; /* Timer match registers */ 37 u32 count[3]; /* Timer count registers */ 38 u32 status[3]; 39 u32 ie[3]; 40 u32 preload[3]; /* Timer preload value */ 41 u32 preload_ctrl[3]; 42 u32 wdt_match_en; 43 u32 wdt_match_r; 44 u32 wdt_val; 45 u32 wdt_sts; 46 u32 icr[3]; 47 u32 wdt_icr; 48 u32 cer; /* Timer count enable reg */ 49 u32 cmr; 50 u32 ilr[3]; 51 u32 wcr; 52 u32 wfar; 53 u32 wsar; 54 u32 cvwr; 55 }; 56 57 #define TIMER 0 /* Use TIMER 0 */ 58 /* Each timer has 3 match registers */ 59 #define MATCH_CMP(x) ((3 * TIMER) + x) 60 #define TIMER_LOAD_VAL 0xffffffff 61 #define COUNT_RD_REQ 0x1 62 63 DECLARE_GLOBAL_DATA_PTR; 64 /* Using gd->tbu from timestamp and gd->tbl for lastdec */ 65 66 /* For preventing risk of instability in reading counter value, 67 * first set read request to register cvwr and then read same 68 * register after it captures counter value. 69 */ 70 ulong read_timer(void) 71 { 72 struct armd1tmr_registers *armd1timers = 73 (struct armd1tmr_registers *) ARMD1_TIMER_BASE; 74 volatile int loop=100; 75 76 writel(COUNT_RD_REQ, &armd1timers->cvwr); 77 while (loop--); 78 return(readl(&armd1timers->cvwr)); 79 } 80 81 ulong get_timer_masked(void) 82 { 83 ulong now = read_timer(); 84 85 if (now >= gd->tbl) { 86 /* normal mode */ 87 gd->tbu += now - gd->tbl; 88 } else { 89 /* we have an overflow ... */ 90 gd->tbu += now + TIMER_LOAD_VAL - gd->tbl; 91 } 92 gd->tbl = now; 93 94 return gd->tbu; 95 } 96 97 ulong get_timer(ulong base) 98 { 99 return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - 100 base); 101 } 102 103 void __udelay(unsigned long usec) 104 { 105 ulong delayticks; 106 ulong endtime; 107 108 delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); 109 endtime = get_timer_masked() + delayticks; 110 111 while (get_timer_masked() < endtime); 112 } 113 114 /* 115 * init the Timer 116 */ 117 int timer_init(void) 118 { 119 struct armd1apb1_registers *apb1clkres = 120 (struct armd1apb1_registers *) ARMD1_APBC1_BASE; 121 struct armd1tmr_registers *armd1timers = 122 (struct armd1tmr_registers *) ARMD1_TIMER_BASE; 123 124 /* Enable Timer clock at 3.25 MHZ */ 125 writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); 126 127 /* load value into timer */ 128 writel(0x0, &armd1timers->clk_ctrl); 129 /* Use Timer 0 Match Resiger 0 */ 130 writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]); 131 /* Preload value is 0 */ 132 writel(0x0, &armd1timers->preload[TIMER]); 133 /* Enable match comparator 0 for Timer 0 */ 134 writel(0x1, &armd1timers->preload_ctrl[TIMER]); 135 136 /* Enable timer 0 */ 137 writel(0x1, &armd1timers->cer); 138 /* init the gd->tbu and gd->tbl value */ 139 gd->tbl = read_timer(); 140 gd->tbu = 0; 141 142 return 0; 143 } 144 145 #define MPMU_APRR_WDTR (1<<4) 146 #define TMR_WFAR 0xbaba /* WDT Register First key */ 147 #define TMP_WSAR 0xeb10 /* WDT Register Second key */ 148 149 /* 150 * This function uses internal Watchdog Timer 151 * based reset mechanism. 152 * Steps to write watchdog registers (protected access) 153 * 1. Write key value to TMR_WFAR reg. 154 * 2. Write key value to TMP_WSAR reg. 155 * 3. Perform write operation. 156 */ 157 void reset_cpu (unsigned long ignored) 158 { 159 struct armd1mpmu_registers *mpmu = 160 (struct armd1mpmu_registers *) ARMD1_MPMU_BASE; 161 struct armd1tmr_registers *armd1timers = 162 (struct armd1tmr_registers *) ARMD1_TIMER_BASE; 163 u32 val; 164 165 /* negate hardware reset to the WDT after system reset */ 166 val = readl(&mpmu->aprr); 167 val = val | MPMU_APRR_WDTR; 168 writel(val, &mpmu->aprr); 169 170 /* reset/enable WDT clock */ 171 writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr); 172 readl(&mpmu->wdtpcr); 173 writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); 174 readl(&mpmu->wdtpcr); 175 176 /* clear previous WDT status */ 177 writel(TMR_WFAR, &armd1timers->wfar); 178 writel(TMP_WSAR, &armd1timers->wsar); 179 writel(0, &armd1timers->wdt_sts); 180 181 /* set match counter */ 182 writel(TMR_WFAR, &armd1timers->wfar); 183 writel(TMP_WSAR, &armd1timers->wsar); 184 writel(0xf, &armd1timers->wdt_match_r); 185 186 /* enable WDT reset */ 187 writel(TMR_WFAR, &armd1timers->wfar); 188 writel(TMP_WSAR, &armd1timers->wsar); 189 writel(0x3, &armd1timers->wdt_match_en); 190 191 while(1); 192 } 193 194 /* 195 * This function is derived from PowerPC code (read timebase as long long). 196 * On ARM it just returns the timer value. 197 */ 198 unsigned long long get_ticks(void) 199 { 200 return get_timer(0); 201 } 202 203 /* 204 * This function is derived from PowerPC code (timebase clock frequency). 205 * On ARM it returns the number of timer ticks per second. 206 */ 207 ulong get_tbclk (void) 208 { 209 return (ulong)CONFIG_SYS_HZ; 210 } 211