1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2009 4 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 5 */ 6 7 #include <common.h> 8 #include <init.h> 9 #include <time.h> 10 #include <asm/global_data.h> 11 #include <asm/io.h> 12 #include <asm/arch/hardware.h> 13 #include <asm/arch/spr_gpt.h> 14 #include <asm/arch/spr_misc.h> 15 #include <asm/ptrace.h> 16 #include <linux/delay.h> 17 18 #define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ) 19 #define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING) 20 21 static struct gpt_regs *const gpt_regs_p = 22 (struct gpt_regs *)CONFIG_SPEAR_TIMERBASE; 23 24 static struct misc_regs *const misc_regs_p = 25 (struct misc_regs *)CONFIG_SPEAR_MISCBASE; 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 static ulong get_timer_masked(void); 30 31 #define timestamp gd->arch.tbl 32 #define lastdec gd->arch.lastinc 33 timer_init(void)34int timer_init(void) 35 { 36 u32 synth; 37 38 /* Prescaler setting */ 39 #if defined(CONFIG_SPEAR3XX) 40 writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg); 41 synth = MISC_GPT4SYNTH; 42 #elif defined(CONFIG_SPEAR600) 43 writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg); 44 synth = MISC_GPT3SYNTH; 45 #else 46 # error Incorrect config. Can only be SPEAR{600|300|310|320} 47 #endif 48 49 writel(readl(&misc_regs_p->periph_clk_cfg) | synth, 50 &misc_regs_p->periph_clk_cfg); 51 52 /* disable timers */ 53 writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control); 54 55 /* load value for free running */ 56 writel(GPT_FREE_RUNNING, &gpt_regs_p->compare); 57 58 /* auto reload, start timer */ 59 writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control); 60 61 /* Reset the timer */ 62 lastdec = READ_TIMER(); 63 timestamp = 0; 64 65 return 0; 66 } 67 68 /* 69 * timer without interrupts 70 */ get_timer(ulong base)71ulong get_timer(ulong base) 72 { 73 return (get_timer_masked() / GPT_RESOLUTION) - base; 74 } 75 __udelay(unsigned long usec)76void __udelay(unsigned long usec) 77 { 78 ulong tmo; 79 ulong start = get_timer_masked(); 80 ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100); 81 ulong rndoff; 82 83 rndoff = (usec % 10) ? 1 : 0; 84 85 /* tenudelcnt timer tick gives 10 microsecconds delay */ 86 tmo = ((usec / 10) + rndoff) * tenudelcnt; 87 88 while ((ulong) (get_timer_masked() - start) < tmo) 89 ; 90 } 91 get_timer_masked(void)92static ulong get_timer_masked(void) 93 { 94 ulong now = READ_TIMER(); 95 96 if (now >= lastdec) { 97 /* normal mode */ 98 timestamp += now - lastdec; 99 } else { 100 /* we have an overflow ... */ 101 timestamp += now + GPT_FREE_RUNNING - lastdec; 102 } 103 lastdec = now; 104 105 return timestamp; 106 } 107 108 /* 109 * This function is derived from PowerPC code (read timebase as long long). 110 * On ARM it just returns the timer value. 111 */ get_ticks(void)112unsigned long long get_ticks(void) 113 { 114 return get_timer(0); 115 } 116 117 /* 118 * This function is derived from PowerPC code (timebase clock frequency). 119 * On ARM it returns the number of timer ticks per second. 120 */ get_tbclk(void)121ulong get_tbclk(void) 122 { 123 return CONFIG_SPEAR_HZ; 124 } 125