~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/arch/arm/cpu/armv7/zynq/timer.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
 
3
 * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
 
4
 *
 
5
 * (C) Copyright 2008
 
6
 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
 
7
 *
 
8
 * (C) Copyright 2004
 
9
 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
 
10
 *
 
11
 * (C) Copyright 2002-2004
 
12
 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
 
13
 *
 
14
 * (C) Copyright 2003
 
15
 * Texas Instruments <www.ti.com>
 
16
 *
 
17
 * (C) Copyright 2002
 
18
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 
19
 * Marius Groeger <mgroeger@sysgo.de>
 
20
 *
 
21
 * (C) Copyright 2002
 
22
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 
23
 * Alex Zuepke <azu@sysgo.de>
 
24
 *
 
25
 * SPDX-License-Identifier:     GPL-2.0+
 
26
 */
 
27
 
 
28
#include <common.h>
 
29
#include <div64.h>
 
30
#include <asm/io.h>
 
31
#include <asm/arch/hardware.h>
 
32
#include <asm/arch/clk.h>
 
33
 
 
34
DECLARE_GLOBAL_DATA_PTR;
 
35
 
 
36
struct scu_timer {
 
37
        u32 load; /* Timer Load Register */
 
38
        u32 counter; /* Timer Counter Register */
 
39
        u32 control; /* Timer Control Register */
 
40
};
 
41
 
 
42
static struct scu_timer *timer_base =
 
43
                              (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
 
44
 
 
45
#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
 
46
#define SCUTIMER_CONTROL_PRESCALER_SHIFT        8
 
47
#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK       0x00000002 /* Auto-reload */
 
48
#define SCUTIMER_CONTROL_ENABLE_MASK            0x00000001 /* Timer enable */
 
49
 
 
50
#define TIMER_LOAD_VAL 0xFFFFFFFF
 
51
#define TIMER_PRESCALE 255
 
52
 
 
53
int timer_init(void)
 
54
{
 
55
        const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
 
56
                        (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
 
57
                        SCUTIMER_CONTROL_ENABLE_MASK;
 
58
 
 
59
        gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
 
60
 
 
61
        /* Load the timer counter register */
 
62
        writel(0xFFFFFFFF, &timer_base->load);
 
63
 
 
64
        /*
 
65
         * Start the A9Timer device
 
66
         * Enable Auto reload mode, Clear prescaler control bits
 
67
         * Set prescaler value, Enable the decrementer
 
68
         */
 
69
        clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
 
70
                                                                emask);
 
71
 
 
72
        /* Reset time */
 
73
        gd->arch.lastinc = readl(&timer_base->counter) /
 
74
                                (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
 
75
        gd->arch.tbl = 0;
 
76
 
 
77
        return 0;
 
78
}
 
79
 
 
80
/*
 
81
 * This function is derived from PowerPC code (read timebase as long long).
 
82
 * On ARM it just returns the timer value.
 
83
 */
 
84
ulong get_timer_masked(void)
 
85
{
 
86
        ulong now;
 
87
 
 
88
        now = readl(&timer_base->counter) /
 
89
                        (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
 
90
 
 
91
        if (gd->arch.lastinc >= now) {
 
92
                /* Normal mode */
 
93
                gd->arch.tbl += gd->arch.lastinc - now;
 
94
        } else {
 
95
                /* We have an overflow ... */
 
96
                gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now + 1;
 
97
        }
 
98
        gd->arch.lastinc = now;
 
99
 
 
100
        return gd->arch.tbl;
 
101
}
 
102
 
 
103
void __udelay(unsigned long usec)
 
104
{
 
105
        u32 countticks;
 
106
        u32 timeend;
 
107
        u32 timediff;
 
108
        u32 timenow;
 
109
 
 
110
        if (usec == 0)
 
111
                return;
 
112
 
 
113
        countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec),
 
114
                           1000000);
 
115
 
 
116
        /* decrementing timer */
 
117
        timeend = readl(&timer_base->counter) - countticks;
 
118
 
 
119
#if TIMER_LOAD_VAL != 0xFFFFFFFF
 
120
        /* do not manage multiple overflow */
 
121
        if (countticks >= TIMER_LOAD_VAL)
 
122
                countticks = TIMER_LOAD_VAL - 1;
 
123
#endif
 
124
 
 
125
        do {
 
126
                timenow = readl(&timer_base->counter);
 
127
 
 
128
                if (timenow >= timeend) {
 
129
                        /* normal case */
 
130
                        timediff = timenow - timeend;
 
131
                } else {
 
132
                        if ((TIMER_LOAD_VAL - timeend + timenow) <=
 
133
                                                                countticks) {
 
134
                                /* overflow */
 
135
                                timediff = TIMER_LOAD_VAL - timeend + timenow;
 
136
                        } else {
 
137
                                /* missed the exact match */
 
138
                                break;
 
139
                        }
 
140
                }
 
141
        } while (timediff > 0);
 
142
}
 
143
 
 
144
/* Timer without interrupts */
 
145
ulong get_timer(ulong base)
 
146
{
 
147
        return get_timer_masked() - base;
 
148
}
 
149
 
 
150
/*
 
151
 * This function is derived from PowerPC code (read timebase as long long).
 
152
 * On ARM it just returns the timer value.
 
153
 */
 
154
unsigned long long get_ticks(void)
 
155
{
 
156
        return get_timer(0);
 
157
}
 
158
 
 
159
/*
 
160
 * This function is derived from PowerPC code (timebase clock frequency).
 
161
 * On ARM it returns the number of timer ticks per second.
 
162
 */
 
163
ulong get_tbclk(void)
 
164
{
 
165
        return CONFIG_SYS_HZ;
 
166
}