xref: /openbmc/u-boot/arch/arm/cpu/arm920t/ep93xx/timer.c (revision 6180ea7e663893cb7330219367252cba471bf225)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
284ad6884SPeter Tyser /*
384ad6884SPeter Tyser  * Cirrus Logic EP93xx timer support.
484ad6884SPeter Tyser  *
584ad6884SPeter Tyser  * Copyright (C) 2009, 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
684ad6884SPeter Tyser  *
784ad6884SPeter Tyser  * Copyright (C) 2004, 2005
884ad6884SPeter Tyser  * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
984ad6884SPeter Tyser  *
1084ad6884SPeter Tyser  * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
1184ad6884SPeter Tyser  * author unknown.
1284ad6884SPeter Tyser  */
1384ad6884SPeter Tyser 
1484ad6884SPeter Tyser #include <common.h>
1584ad6884SPeter Tyser #include <linux/types.h>
1684ad6884SPeter Tyser #include <asm/arch/ep93xx.h>
1784ad6884SPeter Tyser #include <asm/io.h>
1884ad6884SPeter Tyser #include <div64.h>
1984ad6884SPeter Tyser 
2084ad6884SPeter Tyser #define TIMER_CLKSEL	(1 << 3)
2184ad6884SPeter Tyser #define TIMER_ENABLE	(1 << 7)
2284ad6884SPeter Tyser 
2384ad6884SPeter Tyser #define TIMER_FREQ			508469		/* ticks / second */
2484ad6884SPeter Tyser #define TIMER_MAX_VAL			0xFFFFFFFF
2584ad6884SPeter Tyser 
2684ad6884SPeter Tyser static struct ep93xx_timer
2784ad6884SPeter Tyser {
2884ad6884SPeter Tyser 	unsigned long long ticks;
2984ad6884SPeter Tyser 	unsigned long last_read;
3084ad6884SPeter Tyser } timer;
3184ad6884SPeter Tyser 
usecs_to_ticks(unsigned long usecs)3284ad6884SPeter Tyser static inline unsigned long long usecs_to_ticks(unsigned long usecs)
3384ad6884SPeter Tyser {
3484ad6884SPeter Tyser 	unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ;
3584ad6884SPeter Tyser 	do_div(ticks, 1000 * 1000);
3684ad6884SPeter Tyser 
3784ad6884SPeter Tyser 	return ticks;
3884ad6884SPeter Tyser }
3984ad6884SPeter Tyser 
read_timer(void)4084ad6884SPeter Tyser static inline void read_timer(void)
4184ad6884SPeter Tyser {
4284ad6884SPeter Tyser 	struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
4384ad6884SPeter Tyser 	const unsigned long now = TIMER_MAX_VAL - readl(&timer_regs->timer3.value);
4484ad6884SPeter Tyser 
4584ad6884SPeter Tyser 	if (now >= timer.last_read)
4684ad6884SPeter Tyser 		timer.ticks += now - timer.last_read;
4784ad6884SPeter Tyser 	else
4884ad6884SPeter Tyser 		/* an overflow occurred */
4984ad6884SPeter Tyser 		timer.ticks += TIMER_MAX_VAL - timer.last_read + now;
5084ad6884SPeter Tyser 
5184ad6884SPeter Tyser 	timer.last_read = now;
5284ad6884SPeter Tyser }
5384ad6884SPeter Tyser 
5484ad6884SPeter Tyser /*
5584ad6884SPeter Tyser  * Get the number of ticks (in CONFIG_SYS_HZ resolution)
5684ad6884SPeter Tyser  */
get_ticks(void)5784ad6884SPeter Tyser unsigned long long get_ticks(void)
5884ad6884SPeter Tyser {
5984ad6884SPeter Tyser 	unsigned long long sys_ticks;
6084ad6884SPeter Tyser 
6184ad6884SPeter Tyser 	read_timer();
6284ad6884SPeter Tyser 
6384ad6884SPeter Tyser 	sys_ticks = timer.ticks * CONFIG_SYS_HZ;
6484ad6884SPeter Tyser 	do_div(sys_ticks, TIMER_FREQ);
6584ad6884SPeter Tyser 
6684ad6884SPeter Tyser 	return sys_ticks;
6784ad6884SPeter Tyser }
6884ad6884SPeter Tyser 
get_timer(unsigned long base)6984ad6884SPeter Tyser unsigned long get_timer(unsigned long base)
7084ad6884SPeter Tyser {
71*6180ea7eSPatrick Delaunay 	return get_ticks() - base;
7284ad6884SPeter Tyser }
7384ad6884SPeter Tyser 
__udelay(unsigned long usec)7484ad6884SPeter Tyser void __udelay(unsigned long usec)
7584ad6884SPeter Tyser {
7684ad6884SPeter Tyser 	unsigned long long target;
7784ad6884SPeter Tyser 
7884ad6884SPeter Tyser 	read_timer();
7984ad6884SPeter Tyser 
8084ad6884SPeter Tyser 	target = timer.ticks + usecs_to_ticks(usec);
8184ad6884SPeter Tyser 
8284ad6884SPeter Tyser 	while (timer.ticks < target)
8384ad6884SPeter Tyser 		read_timer();
8484ad6884SPeter Tyser }
8584ad6884SPeter Tyser 
timer_init(void)8684ad6884SPeter Tyser int timer_init(void)
8784ad6884SPeter Tyser {
8884ad6884SPeter Tyser 	struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
8984ad6884SPeter Tyser 
9084ad6884SPeter Tyser 	/* use timer 3 with 508KHz and free running, not enabled now */
9184ad6884SPeter Tyser 	writel(TIMER_CLKSEL, &timer_regs->timer3.control);
9284ad6884SPeter Tyser 
9384ad6884SPeter Tyser 	/* set initial timer value */
9484ad6884SPeter Tyser 	writel(TIMER_MAX_VAL, &timer_regs->timer3.load);
9584ad6884SPeter Tyser 
9684ad6884SPeter Tyser 	/* Enable the timer */
9784ad6884SPeter Tyser 	writel(TIMER_ENABLE | TIMER_CLKSEL,
9884ad6884SPeter Tyser 		&timer_regs->timer3.control);
9984ad6884SPeter Tyser 
10017659d7dSGraeme Russ 	/* Reset the timer */
10117659d7dSGraeme Russ 	read_timer();
10217659d7dSGraeme Russ 	timer.ticks = 0;
10384ad6884SPeter Tyser 
10484ad6884SPeter Tyser 	return 0;
10584ad6884SPeter Tyser }
10684ad6884SPeter Tyser 
10784ad6884SPeter Tyser /*
10884ad6884SPeter Tyser  * This function is derived from PowerPC code (timebase clock frequency).
10984ad6884SPeter Tyser  * On ARM it returns the number of timer ticks per second.
11084ad6884SPeter Tyser  */
get_tbclk(void)11184ad6884SPeter Tyser unsigned long get_tbclk(void)
11284ad6884SPeter Tyser {
11384ad6884SPeter Tyser 	return CONFIG_SYS_HZ;
11484ad6884SPeter Tyser }
115