diff options
Diffstat (limited to 'arch/nds32/cpu/n1213/ag102/timer.c')
-rw-r--r-- | arch/nds32/cpu/n1213/ag102/timer.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/arch/nds32/cpu/n1213/ag102/timer.c b/arch/nds32/cpu/n1213/ag102/timer.c new file mode 100644 index 0000000..caa36b8 --- /dev/null +++ b/arch/nds32/cpu/n1213/ag102/timer.c @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2009 Faraday Technology + * Po-Yu Chuang <ratbert@faraday-tech.com> + * + * Copyright (C) 2011 Andes Technology Corporation + * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> + * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/io.h> +#include <faraday/fttmr010.h> + +static ulong timestamp; +static ulong lastdec; + +int timer_init(void) +{ + struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; + unsigned int cr; + + debug("%s()\n", __func__); + + /* disable timers */ + writel(0, &tmr->cr); + +#ifdef CONFIG_FTTMR010_EXT_CLK + /* use 32768Hz oscillator for RTC, WDT, TIMER */ + ftpmu010_32768osc_enable(); +#endif + + /* setup timer */ + writel(TIMER_LOAD_VAL, &tmr->timer3_load); + writel(TIMER_LOAD_VAL, &tmr->timer3_counter); + writel(0, &tmr->timer3_match1); + writel(0, &tmr->timer3_match2); + + /* we don't want timer to issue interrupts */ + writel(FTTMR010_TM3_MATCH1 | + FTTMR010_TM3_MATCH2 | + FTTMR010_TM3_OVERFLOW, + &tmr->interrupt_mask); + + cr = readl(&tmr->cr); +#ifdef CONFIG_FTTMR010_EXT_CLK + cr |= FTTMR010_TM3_CLOCK; /* use external clock */ +#endif + cr |= FTTMR010_TM3_ENABLE; + writel(cr, &tmr->cr); + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} + +/* + * timer without interrupts + */ + +/* + * reset time + */ +void reset_timer_masked(void) +{ + struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; + + /* capure current decrementer value time */ +#ifdef CONFIG_FTTMR010_EXT_CLK + lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); +#else + lastdec = readl(&tmr->timer3_counter) / (CONFIG_SYS_CLK_FREQ / 2); +#endif + timestamp = 0; /* start "advancing" time stamp from 0 */ + + debug("%s(): lastdec = %lx\n", __func__, lastdec); +} + +void reset_timer(void) +{ + debug("%s()\n", __func__); + reset_timer_masked(); +} + +/* + * return timer ticks + */ +ulong get_timer_masked(void) +{ + struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; + + /* current tick value */ +#ifdef CONFIG_FTTMR010_EXT_CLK + ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); +#else + ulong now = readl(&tmr->timer3_counter) / \ + (CONFIG_SYS_CLK_FREQ / 2 / 1024); +#endif + + debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec); + + if (lastdec >= now) { + /* + * normal mode (non roll) + * move stamp fordward with absoulte diff ticks + */ + timestamp += lastdec - now; + } else { + /* + * we have overflow of the count down timer + * + * nts = ts + ld + (TLV - now) + * ts=old stamp, ld=time that passed before passing through -1 + * (TLV-now) amount of time after passing though -1 + * nts = new "advancing time stamp"...it could also roll and + * cause problems. + */ + timestamp += lastdec + TIMER_LOAD_VAL - now; + } + + lastdec = now; + + debug("%s() returns %lx\n", __func__, timestamp); + + return timestamp; +} + +/* + * return difference between timer ticks and base + */ +ulong get_timer(ulong base) +{ + debug("%s(%lx)\n", __func__, base); + return get_timer_masked() - base; +} + +void set_timer(ulong t) +{ + debug("%s(%lx)\n", __func__, t); + timestamp = t; +} + +/* delay x useconds AND preserve advance timestamp value */ +void __udelay(unsigned long usec) +{ + struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; + +#ifdef CONFIG_FTTMR010_EXT_CLK + long tmo = usec * (TIMER_CLOCK / 1000) / 1000; +#else + long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000; +#endif + unsigned long now, last = readl(&tmr->timer3_counter); + + debug("%s(%lu)\n", __func__, usec); + while (tmo > 0) { + now = readl(&tmr->timer3_counter); + if (now > last) /* count down timer overflow */ + tmo -= TIMER_LOAD_VAL + last - now; + else + tmo -= 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) +{ + debug("%s()\n", __func__); + 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) +{ + debug("%s()\n", __func__); +#ifdef CONFIG_FTTMR010_EXT_CLK + return CONFIG_SYS_HZ; +#else + return CONFIG_SYS_CLK_FREQ; +#endif +} |