1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Cirrus Logic EP93xx timer support. 4 * 5 * Copyright (C) 2009, 2010 Matthias Kaehlcke <matthias@kaehlcke.net> 6 * 7 * Copyright (C) 2004, 2005 8 * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com> 9 * 10 * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support, 11 * author unknown. 12 */ 13 14#include <common.h> 15#include <init.h> 16#include <time.h> 17#include <linux/delay.h> 18#include <linux/types.h> 19#include <asm/arch/ep93xx.h> 20#include <asm/io.h> 21#include <div64.h> 22 23#define TIMER_CLKSEL (1 << 3) 24#define TIMER_ENABLE (1 << 7) 25 26#define TIMER_FREQ 508469 /* ticks / second */ 27#define TIMER_MAX_VAL 0xFFFFFFFF 28 29static struct ep93xx_timer 30{ 31 unsigned long long ticks; 32 unsigned long last_read; 33} timer; 34 35static inline unsigned long long usecs_to_ticks(unsigned long usecs) 36{ 37 unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ; 38 do_div(ticks, 1000 * 1000); 39 40 return ticks; 41} 42 43static inline void read_timer(void) 44{ 45 struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE; 46 const unsigned long now = TIMER_MAX_VAL - readl(&timer_regs->timer3.value); 47 48 if (now >= timer.last_read) 49 timer.ticks += now - timer.last_read; 50 else 51 /* an overflow occurred */ 52 timer.ticks += TIMER_MAX_VAL - timer.last_read + now; 53 54 timer.last_read = now; 55} 56 57/* 58 * Get the number of ticks (in CONFIG_SYS_HZ resolution) 59 */ 60unsigned long long get_ticks(void) 61{ 62 unsigned long long sys_ticks; 63 64 read_timer(); 65 66 sys_ticks = timer.ticks * CONFIG_SYS_HZ; 67 do_div(sys_ticks, TIMER_FREQ); 68 69 return sys_ticks; 70} 71 72unsigned long get_timer(unsigned long base) 73{ 74 return get_ticks() - base; 75} 76 77void __udelay(unsigned long usec) 78{ 79 unsigned long long target; 80 81 read_timer(); 82 83 target = timer.ticks + usecs_to_ticks(usec); 84 85 while (timer.ticks < target) 86 read_timer(); 87} 88 89int timer_init(void) 90{ 91 struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE; 92 93 /* use timer 3 with 508KHz and free running, not enabled now */ 94 writel(TIMER_CLKSEL, &timer_regs->timer3.control); 95 96 /* set initial timer value */ 97 writel(TIMER_MAX_VAL, &timer_regs->timer3.load); 98 99 /* Enable the timer */ 100 writel(TIMER_ENABLE | TIMER_CLKSEL, 101 &timer_regs->timer3.control); 102 103 /* Reset the timer */ 104 read_timer(); 105 timer.ticks = 0; 106 107 return 0; 108} 109 110/* 111 * This function is derived from PowerPC code (timebase clock frequency). 112 * On ARM it returns the number of timer ticks per second. 113 */ 114unsigned long get_tbclk(void) 115{ 116 return CONFIG_SYS_HZ; 117} 118