1/* 2 * (C) Copyright 2007-2008 3 * Stelian Pop <stelian@popies.net> 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/io.h> 27#include <asm/arch/hardware.h> 28#include <asm/arch/at91_pit.h> 29#include <asm/arch/at91_pmc.h> 30#include <asm/arch/clk.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 *) ATMEL_BASE_PMC; 74 at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; 75 76 /* Enable PITC Clock */ 77 writel(1 << ATMEL_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 *) ATMEL_BASE_PIT; 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 start; 107 ulong tmo; 108 109 start = get_ticks(); /* get current timestamp */ 110 tmo = usec_to_tick(usec); /* convert usecs to ticks */ 111 while ((get_ticks() - start) < tmo) 112 ; /* loop till time has passed */ 113} 114 115/* 116 * get_timer(base) can be used to check for timeouts or 117 * to measure elasped time relative to an event: 118 * 119 * ulong start_time = get_timer(0) sets start_time to the current 120 * time value. 121 * get_timer(start_time) returns the time elapsed since then. 122 * 123 * The time is used in CONFIG_SYS_HZ units! 124 */ 125ulong get_timer(ulong base) 126{ 127 return tick_to_time(get_ticks()) - base; 128} 129 130/* 131 * Return the number of timer ticks per second. 132 */ 133ulong get_tbclk(void) 134{ 135 return gd->timer_rate_hz; 136} 137