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