blob: b0b7fb93fba92e3b901879f67704dbfcd550f9c5 [file] [log] [blame]
Stelian Popd1aea1c2008-01-30 21:15:54 +00001/*
2 * (C) Copyright 2007-2008
Stelian Pop5ee0c7f2011-11-01 00:00:39 +01003 * Stelian Pop <stelian@popies.net>
Stelian Popd1aea1c2008-01-30 21:15:54 +00004 * Lead Tech Design <www.leadtechdesign.com>
5 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Stelian Popd1aea1c2008-01-30 21:15:54 +00007 */
8
9#include <common.h>
Reinhard Meyerb06208c2010-11-07 13:26:14 +010010#include <asm/io.h>
Stelian Popd1aea1c2008-01-30 21:15:54 +000011#include <asm/arch/hardware.h>
Stelian Popd4bfbc52008-03-26 20:52:32 +010012#include <asm/arch/at91_pit.h>
13#include <asm/arch/at91_pmc.h>
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020014#include <asm/arch/clk.h>
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020015#include <div64.h>
Stelian Popd1aea1c2008-01-30 21:15:54 +000016
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020017#if !defined(CONFIG_AT91FAMILY)
18# error You need to define CONFIG_AT91FAMILY in your board config!
19#endif
20
21DECLARE_GLOBAL_DATA_PTR;
22
Stelian Popd1aea1c2008-01-30 21:15:54 +000023/*
Stelian Popeea44aa2008-03-26 20:52:28 +010024 * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by
Stelian Popd1aea1c2008-01-30 21:15:54 +000025 * setting the 20 bit counter period to its maximum (0xfffff).
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020026 * (See the relevant data sheets to understand that this really works)
27 *
28 * We do also mimic the typical powerpc way of incrementing
29 * two 32 bit registers called tbl and tbu.
30 *
31 * Those registers increment at 1/16 the main clock rate.
Stelian Popd1aea1c2008-01-30 21:15:54 +000032 */
Stelian Popd1aea1c2008-01-30 21:15:54 +000033
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020034#define TIMER_LOAD_VAL 0xfffff
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020035
36static inline unsigned long long tick_to_time(unsigned long long tick)
37{
38 tick *= CONFIG_SYS_HZ;
Simon Glass6ed6e032012-12-13 20:48:32 +000039 do_div(tick, gd->arch.timer_rate_hz);
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020040
41 return tick;
42}
43
44static inline unsigned long long usec_to_tick(unsigned long long usec)
45{
Simon Glass6ed6e032012-12-13 20:48:32 +000046 usec *= gd->arch.timer_rate_hz;
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020047 do_div(usec, 1000000);
48
49 return usec;
50}
Stelian Popd1aea1c2008-01-30 21:15:54 +000051
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020052/*
53 * Use the PITC in full 32 bit incrementing mode
54 */
Stelian Pop6bf2de22008-03-26 21:52:27 +010055int timer_init(void)
Stelian Popd1aea1c2008-01-30 21:15:54 +000056{
Reinhard Meyere260d0b2010-11-03 15:39:55 +010057 at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
58 at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT;
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020059
60 /* Enable PITC Clock */
Reinhard Meyere260d0b2010-11-03 15:39:55 +010061 writel(1 << ATMEL_ID_SYS, &pmc->pcer);
Stelian Popd1aea1c2008-01-30 21:15:54 +000062
63 /* Enable PITC */
Jens Scharsiga4db1ca2010-02-03 22:46:58 +010064 writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr);
Stelian Popd1aea1c2008-01-30 21:15:54 +000065
Simon Glass6ed6e032012-12-13 20:48:32 +000066 gd->arch.timer_rate_hz = gd->arch.mck_rate_hz / 16;
Simon Glass2655ee12012-12-13 20:48:34 +000067 gd->arch.tbu = gd->arch.tbl = 0;
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020068
Stelian Popd1aea1c2008-01-30 21:15:54 +000069 return 0;
70}
71
72/*
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020073 * Get the current 64 bit timer tick count
Stelian Popd1aea1c2008-01-30 21:15:54 +000074 */
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020075unsigned long long get_ticks(void)
Stelian Popd1aea1c2008-01-30 21:15:54 +000076{
Reinhard Meyere260d0b2010-11-03 15:39:55 +010077 at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT;
Jens Scharsiga4db1ca2010-02-03 22:46:58 +010078
79 ulong now = readl(&pit->piir);
Stelian Popd4bfbc52008-03-26 20:52:32 +010080
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020081 /* increment tbu if tbl has rolled over */
Simon Glass2655ee12012-12-13 20:48:34 +000082 if (now < gd->arch.tbl)
Simon Glass8ca15202012-12-13 20:48:33 +000083 gd->arch.tbu++;
Simon Glass2655ee12012-12-13 20:48:34 +000084 gd->arch.tbl = now;
85 return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl;
Stelian Popd1aea1c2008-01-30 21:15:54 +000086}
87
Ingo van Lilf0f778a2009-11-24 14:09:21 +010088void __udelay(unsigned long usec)
Stelian Popd1aea1c2008-01-30 21:15:54 +000089{
Reinhard Meyer7beb9152010-11-10 18:07:56 +010090 unsigned long long start;
Jean-Christophe PLAGNIOL-VILLARD1d4a3792009-04-16 21:30:48 +020091 ulong tmo;
Stelian Popd1aea1c2008-01-30 21:15:54 +000092
Reinhard Meyer7beb9152010-11-10 18:07:56 +010093 start = get_ticks(); /* get current timestamp */
94 tmo = usec_to_tick(usec); /* convert usecs to ticks */
95 while ((get_ticks() - start) < tmo)
96 ; /* loop till time has passed */
Stelian Popd1aea1c2008-01-30 21:15:54 +000097}
98
Reinhard Meyer0a1790a2010-10-05 16:54:35 +020099/*
Reinhard Meyer7beb9152010-11-10 18:07:56 +0100100 * get_timer(base) can be used to check for timeouts or
101 * to measure elasped time relative to an event:
Reinhard Meyer0a1790a2010-10-05 16:54:35 +0200102 *
Reinhard Meyer7beb9152010-11-10 18:07:56 +0100103 * ulong start_time = get_timer(0) sets start_time to the current
104 * time value.
105 * get_timer(start_time) returns the time elapsed since then.
Reinhard Meyer0a1790a2010-10-05 16:54:35 +0200106 *
107 * The time is used in CONFIG_SYS_HZ units!
108 */
Stelian Popd1aea1c2008-01-30 21:15:54 +0000109ulong get_timer(ulong base)
110{
Reinhard Meyer7beb9152010-11-10 18:07:56 +0100111 return tick_to_time(get_ticks()) - base;
Stelian Popd1aea1c2008-01-30 21:15:54 +0000112}
113
114/*
Reinhard Meyer0a1790a2010-10-05 16:54:35 +0200115 * Return the number of timer ticks per second.
Stelian Popd1aea1c2008-01-30 21:15:54 +0000116 */
117ulong get_tbclk(void)
118{
Simon Glass6ed6e032012-12-13 20:48:32 +0000119 return gd->arch.timer_rate_hz;
Stelian Popd1aea1c2008-01-30 21:15:54 +0000120}