blob: 775d0b748840c0b690cc6819e417bdd607ea377f [file] [log] [blame]
Alessandro Rubinid5254f12009-01-24 18:10:37 +01001/*
Alessandro Rubini095a4602009-06-29 10:52:37 +02002 * (C) Copyright 2009 Alessandro Rubini
Alessandro Rubinid5254f12009-01-24 18:10:37 +01003 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Alessandro Rubinid5254f12009-01-24 18:10:37 +01005 */
6
7#include <common.h>
8#include <asm/io.h>
Alessandro Rubini095a4602009-06-29 10:52:37 +02009#include <asm/arch/mtu.h>
Alessandro Rubinid5254f12009-01-24 18:10:37 +010010
Alessandro Rubini095a4602009-06-29 10:52:37 +020011/*
12 * The timer is a decrementer, we'll left it free running at 2.4MHz.
13 * We have 2.4 ticks per microsecond and an overflow in almost 30min
14 */
15#define TIMER_CLOCK (24 * 100 * 1000)
16#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */
17#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */
18#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ)
19#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ)
Alessandro Rubinid5254f12009-01-24 18:10:37 +010020
Alessandro Rubini4b894a92009-11-25 23:41:51 +010021/* macro to read the decrementing 32 bit timer as an increasing count */
22#define READ_TIMER() (0 - readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0)))
Alessandro Rubinid5254f12009-01-24 18:10:37 +010023
Alessandro Rubini095a4602009-06-29 10:52:37 +020024/* Configure a free-running, auto-wrap counter with no prescaler */
Alessandro Rubinid5254f12009-01-24 18:10:37 +010025int timer_init(void)
26{
Graeme Russ4769be22011-07-15 02:19:44 +000027 ulong val;
28
Alessandro Rubini095a4602009-06-29 10:52:37 +020029 writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS,
30 CONFIG_SYS_TIMERBASE + MTU_CR(0));
Alessandro Rubinid5254f12009-01-24 18:10:37 +010031
Graeme Russ4769be22011-07-15 02:19:44 +000032 /* Reset the timer */
Alessandro Rubini4b894a92009-11-25 23:41:51 +010033 writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0));
34 /*
35 * The load-register isn't really immediate: it changes on clock
36 * edges, so we must wait for our newly-written value to appear.
37 * Since we might miss reading 0, wait for any change in value.
38 */
39 val = READ_TIMER();
40 while (READ_TIMER() == val)
41 ;
Graeme Russ4769be22011-07-15 02:19:44 +000042
43 return 0;
Alessandro Rubinid5254f12009-01-24 18:10:37 +010044}
45
Alessandro Rubini095a4602009-06-29 10:52:37 +020046/* Return how many HZ passed since "base" */
Alessandro Rubinid5254f12009-01-24 18:10:37 +010047ulong get_timer(ulong base)
48{
Alessandro Rubini095a4602009-06-29 10:52:37 +020049 return TICKS_TO_HZ(READ_TIMER()) - base;
Alessandro Rubinid5254f12009-01-24 18:10:37 +010050}
51
Alessandro Rubini095a4602009-06-29 10:52:37 +020052/* Delay x useconds */
Ingo van Lil3eb90ba2009-11-24 14:09:21 +010053void __udelay(unsigned long usec)
Alessandro Rubinid5254f12009-01-24 18:10:37 +010054{
Alessandro Rubini095a4602009-06-29 10:52:37 +020055 ulong ini, end;
Alessandro Rubinid5254f12009-01-24 18:10:37 +010056
Alessandro Rubini095a4602009-06-29 10:52:37 +020057 ini = READ_TIMER();
58 end = ini + USEC_TO_COUNT(usec);
59 while ((signed)(end - READ_TIMER()) > 0)
60 ;
Alessandro Rubinid5254f12009-01-24 18:10:37 +010061}
Anatolij Gustschinb39643b2012-03-28 02:56:30 +000062
63unsigned long long get_ticks(void)
64{
65 return get_timer(0);
66}
67
68ulong get_tbclk(void)
69{
70 return CONFIG_SYS_HZ;
71}