1/* 2 * (C) Copyright 2007-2008 3 * Stelian Pop <stelian.pop@leadtechdesign.com> 4 * Lead Tech Design <www.leadtechdesign.com> 5 * 6 * See file CREDITS for list of people who contributed to this 7 * project. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 */ 24 25#include <common.h> 26#include <asm/arch/hardware.h> 27#include <asm/arch/at91_pit.h> 28#include <asm/arch/at91_pmc.h> 29#include <asm/arch/clk.h> 30#include <asm/arch/io.h> 31#include <div64.h> 32 33#if !defined(CONFIG_AT91FAMILY) 34# error You need to define CONFIG_AT91FAMILY in your board config! 35#endif 36 37DECLARE_GLOBAL_DATA_PTR; 38 39/* 40 * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by 41 * setting the 20 bit counter period to its maximum (0xfffff). 42 * (See the relevant data sheets to understand that this really works) 43 * 44 * We do also mimic the typical powerpc way of incrementing 45 * two 32 bit registers called tbl and tbu. 46 * 47 * Those registers increment at 1/16 the main clock rate. 48 */ 49 50#define TIMER_LOAD_VAL 0xfffff 51 52static inline unsigned long long tick_to_time(unsigned long long tick) 53{ 54 tick *= CONFIG_SYS_HZ; 55 do_div(tick, gd->timer_rate_hz); 56 57 return tick; 58} 59 60static inline unsigned long long usec_to_tick(unsigned long long usec) 61{ 62 usec *= gd->timer_rate_hz; 63 do_div(usec, 1000000); 64 65 return usec; 66} 67 68/* 69 * Use the PITC in full 32 bit incrementing mode 70 */ 71int timer_init(void) 72{ 73 at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; 74 at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE; 75 76 /* Enable PITC Clock */ 77 writel(1 << AT91_ID_SYS, &pmc->pcer); 78 79 /* Enable PITC */ 80 writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr); 81 82 gd->timer_rate_hz = gd->mck_rate_hz / 16; 83 gd->tbu = gd->tbl = 0; 84 85 return 0; 86} 87 88/* 89 * Get the current 64 bit timer tick count 90 */ 91unsigned long long get_ticks(void) 92{ 93 at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE; 94 95 ulong now = readl(&pit->piir); 96 97 /* increment tbu if tbl has rolled over */ 98 if (now < gd->tbl) 99 gd->tbu++; 100 gd->tbl = now; 101 return (((unsigned long long)gd->tbu) << 32) | gd->tbl; 102} 103 104void __udelay(unsigned long usec) 105{ 106 unsigned long long tmp; 107 ulong tmo; 108 109 tmo = usec_to_tick(usec); 110 tmp = get_ticks() + tmo; /* get current timestamp */ 111 112 while (get_ticks() < tmp) /* loop till event */ 113 ; 114} 115 116/* 117 * reset_timer() and get_timer(base) are a pair of functions that are used by 118 * some timeout/sleep mechanisms in u-boot. 119 * 120 * reset_timer() marks the current time as epoch and 121 * get_timer(base) works relative to that epoch. 122 * 123 * The time is used in CONFIG_SYS_HZ units! 124 */ 125void reset_timer(void) 126{ 127 gd->timer_reset_value = get_ticks(); 128} 129 130ulong get_timer(ulong base) 131{ 132 return tick_to_time(get_ticks() - gd->timer_reset_value) - base; 133} 134 135/* 136 * Return the number of timer ticks per second. 137 */ 138ulong get_tbclk(void) 139{ 140 return gd->timer_rate_hz; 141} 142