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