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