1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2007-2011 4 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 5 * Tom Cubie <tangliang@allwinnertech.com> 6 */ 7 8 #include <common.h> 9 #include <init.h> 10 #include <time.h> 11 #include <asm/global_data.h> 12 #include <asm/io.h> 13 #include <asm/arch/timer.h> 14 #include <linux/delay.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 #define TIMER_MODE (0x0 << 7) /* continuous mode */ 19 #define TIMER_DIV (0x0 << 4) /* pre scale 1 */ 20 #define TIMER_SRC (0x1 << 2) /* osc24m */ 21 #define TIMER_RELOAD (0x1 << 1) /* reload internal value */ 22 #define TIMER_EN (0x1 << 0) /* enable timer */ 23 24 #define TIMER_CLOCK (24 * 1000 * 1000) 25 #define COUNT_TO_USEC(x) ((x) / 24) 26 #define USEC_TO_COUNT(x) ((x) * 24) 27 #define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) 28 #define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) 29 30 #define TIMER_LOAD_VAL 0xffffffff 31 32 #define TIMER_NUM 0 /* we use timer 0 */ 33 34 /* read the 32-bit timer */ read_timer(void)35static ulong read_timer(void) 36 { 37 struct sunxi_timer_reg *timers = 38 (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; 39 struct sunxi_timer *timer = &timers->timer[TIMER_NUM]; 40 41 /* 42 * The hardware timer counts down, therefore we invert to 43 * produce an incrementing timer. 44 */ 45 return ~readl(&timer->val); 46 } 47 48 /* init timer register */ timer_init(void)49int timer_init(void) 50 { 51 struct sunxi_timer_reg *timers = 52 (struct sunxi_timer_reg *)SUNXI_TIMER_BASE; 53 struct sunxi_timer *timer = &timers->timer[TIMER_NUM]; 54 writel(TIMER_LOAD_VAL, &timer->inter); 55 writel(TIMER_MODE | TIMER_DIV | TIMER_SRC | TIMER_RELOAD | TIMER_EN, 56 &timer->ctl); 57 58 return 0; 59 } 60 61 /* timer without interrupts */ get_timer_masked(void)62static ulong get_timer_masked(void) 63 { 64 /* current tick value */ 65 ulong now = TICKS_TO_HZ(read_timer()); 66 67 if (now >= gd->arch.lastinc) /* normal (non rollover) */ 68 gd->arch.tbl += (now - gd->arch.lastinc); 69 else { 70 /* rollover */ 71 gd->arch.tbl += (TICKS_TO_HZ(TIMER_LOAD_VAL) 72 - gd->arch.lastinc) + now; 73 } 74 gd->arch.lastinc = now; 75 76 return gd->arch.tbl; 77 } 78 get_timer(ulong base)79ulong get_timer(ulong base) 80 { 81 return get_timer_masked() - base; 82 } 83 84 /* delay x useconds */ __udelay(unsigned long usec)85void __udelay(unsigned long usec) 86 { 87 long tmo = USEC_TO_COUNT(usec); 88 ulong now, last = read_timer(); 89 90 while (tmo > 0) { 91 now = read_timer(); 92 if (now > last) /* normal (non rollover) */ 93 tmo -= now - last; 94 else /* rollover */ 95 tmo -= TIMER_LOAD_VAL - last + now; 96 last = now; 97 } 98 } 99 100 /* 101 * This function is derived from PowerPC code (read timebase as long long). 102 * On ARM it just returns the timer value. 103 */ get_ticks(void)104unsigned long long get_ticks(void) 105 { 106 return get_timer(0); 107 } 108 109 /* 110 * This function is derived from PowerPC code (timebase clock frequency). 111 * On ARM it returns the number of timer ticks per second. 112 */ get_tbclk(void)113ulong get_tbclk(void) 114 { 115 return CONFIG_SYS_HZ; 116 } 117