1 /* 2 * (C) Copyright 2009 3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <asm/io.h> 26 #include <asm/arch/hardware.h> 27 #include <asm/arch/spr_gpt.h> 28 #include <asm/arch/spr_misc.h> 29 30 #define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ) 31 #define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING) 32 33 static struct gpt_regs *const gpt_regs_p = 34 (struct gpt_regs *)CONFIG_SPEAR_TIMERBASE; 35 36 static struct misc_regs *const misc_regs_p = 37 (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 38 39 static ulong timestamp; 40 static ulong lastdec; 41 42 int timer_init(void) 43 { 44 u32 synth; 45 46 /* Prescaler setting */ 47 #if defined(CONFIG_SPEAR3XX) 48 writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg); 49 synth = MISC_GPT4SYNTH; 50 #elif defined(CONFIG_SPEAR600) 51 writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg); 52 synth = MISC_GPT3SYNTH; 53 #else 54 # error Incorrect config. Can only be spear{600|300|310|320} 55 #endif 56 57 writel(readl(&misc_regs_p->periph_clk_cfg) | synth, 58 &misc_regs_p->periph_clk_cfg); 59 60 /* disable timers */ 61 writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control); 62 63 /* load value for free running */ 64 writel(GPT_FREE_RUNNING, &gpt_regs_p->compare); 65 66 /* auto reload, start timer */ 67 writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control); 68 69 reset_timer_masked(); 70 71 return 0; 72 } 73 74 /* 75 * timer without interrupts 76 */ 77 78 void reset_timer(void) 79 { 80 reset_timer_masked(); 81 } 82 83 ulong get_timer(ulong base) 84 { 85 return (get_timer_masked() / GPT_RESOLUTION) - base; 86 } 87 88 void set_timer(ulong t) 89 { 90 timestamp = t; 91 } 92 93 void __udelay(unsigned long usec) 94 { 95 ulong tmo; 96 ulong start = get_timer_masked(); 97 ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100); 98 ulong rndoff; 99 100 rndoff = (usec % 10) ? 1 : 0; 101 102 /* tenudelcnt timer tick gives 10 microsecconds delay */ 103 tmo = ((usec / 10) + rndoff) * tenudelcnt; 104 105 while ((ulong) (get_timer_masked() - start) < tmo) 106 ; 107 } 108 109 void reset_timer_masked(void) 110 { 111 /* reset time */ 112 lastdec = READ_TIMER(); 113 timestamp = 0; 114 } 115 116 ulong get_timer_masked(void) 117 { 118 ulong now = READ_TIMER(); 119 120 if (now >= lastdec) { 121 /* normal mode */ 122 timestamp += now - lastdec; 123 } else { 124 /* we have an overflow ... */ 125 timestamp += now + GPT_FREE_RUNNING - lastdec; 126 } 127 lastdec = now; 128 129 return timestamp; 130 } 131 132 void udelay_masked(unsigned long usec) 133 { 134 return udelay(usec); 135 } 136 137 /* 138 * This function is derived from PowerPC code (read timebase as long long). 139 * On ARM it just returns the timer value. 140 */ 141 unsigned long long get_ticks(void) 142 { 143 return get_timer(0); 144 } 145 146 /* 147 * This function is derived from PowerPC code (timebase clock frequency). 148 * On ARM it returns the number of timer ticks per second. 149 */ 150 ulong get_tbclk(void) 151 { 152 return CONFIG_SPEAR_HZ; 153 } 154