1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2014, STMicroelectronics - All Rights Reserved 4 * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics. 5 */ 6 7 #include <common.h> 8 #include <time.h> 9 #include <asm/io.h> 10 #include <asm/arch-stv0991/hardware.h> 11 #include <asm/arch-stv0991/stv0991_cgu.h> 12 #include <asm/arch-stv0991/stv0991_gpt.h> 13 14 static struct stv0991_cgu_regs *const stv0991_cgu_regs = \ 15 (struct stv0991_cgu_regs *) (CGU_BASE_ADDR); 16 17 #define READ_TIMER() (readl(&gpt1_regs_ptr->cnt) & GPT_FREE_RUNNING) 18 #define GPT_RESOLUTION (CONFIG_STV0991_HZ_CLOCK / CONFIG_STV0991_HZ) 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 #define timestamp gd->arch.tbl 23 #define lastdec gd->arch.lastinc 24 25 static ulong get_timer_masked(void); 26 timer_init(void)27int timer_init(void) 28 { 29 /* Timer1 clock configuration */ 30 writel(TIMER1_CLK_CFG, &stv0991_cgu_regs->tim_freq); 31 writel(readl(&stv0991_cgu_regs->cgu_enable_2) | 32 TIMER1_CLK_EN, &stv0991_cgu_regs->cgu_enable_2); 33 34 /* Stop the timer */ 35 writel(readl(&gpt1_regs_ptr->cr1) & ~GPT_CR1_CEN, &gpt1_regs_ptr->cr1); 36 writel(GPT_PRESCALER_128, &gpt1_regs_ptr->psc); 37 /* Configure timer for auto-reload */ 38 writel(readl(&gpt1_regs_ptr->cr1) | GPT_MODE_AUTO_RELOAD, 39 &gpt1_regs_ptr->cr1); 40 41 /* load value for free running */ 42 writel(GPT_FREE_RUNNING, &gpt1_regs_ptr->arr); 43 44 /* start timer */ 45 writel(readl(&gpt1_regs_ptr->cr1) | GPT_CR1_CEN, 46 &gpt1_regs_ptr->cr1); 47 48 /* Reset the timer */ 49 lastdec = READ_TIMER(); 50 timestamp = 0; 51 52 return 0; 53 } 54 55 /* 56 * timer without interrupts 57 */ get_timer(ulong base)58ulong get_timer(ulong base) 59 { 60 return (get_timer_masked() / GPT_RESOLUTION) - base; 61 } 62 __udelay(unsigned long usec)63void __udelay(unsigned long usec) 64 { 65 ulong tmo; 66 ulong start = get_timer_masked(); 67 ulong tenudelcnt = CONFIG_STV0991_HZ_CLOCK / (1000 * 100); 68 ulong rndoff; 69 70 rndoff = (usec % 10) ? 1 : 0; 71 72 /* tenudelcnt timer tick gives 10 microsecconds delay */ 73 tmo = ((usec / 10) + rndoff) * tenudelcnt; 74 75 while ((ulong) (get_timer_masked() - start) < tmo) 76 ; 77 } 78 get_timer_masked(void)79static ulong get_timer_masked(void) 80 { 81 ulong now = READ_TIMER(); 82 83 if (now >= lastdec) { 84 /* normal mode */ 85 timestamp += now - lastdec; 86 } else { 87 /* we have an overflow ... */ 88 timestamp += now + GPT_FREE_RUNNING - lastdec; 89 } 90 lastdec = now; 91 92 return timestamp; 93 } 94 95 /* 96 * This function is derived from PowerPC code (read timebase as long long). 97 * On ARM it just returns the timer value. 98 */ get_ticks(void)99unsigned long long get_ticks(void) 100 { 101 return get_timer(0); 102 } 103 104 /* 105 * This function is derived from PowerPC code (timebase clock frequency). 106 * On ARM it returns the number of timer ticks per second. 107 */ get_tbclk(void)108ulong get_tbclk(void) 109 { 110 return CONFIG_STV0991_HZ; 111 } 112