Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-at91/at91rm9200_time.c
10817 views
1
/*
2
* linux/arch/arm/mach-at91/at91rm9200_time.c
3
*
4
* Copyright (C) 2003 SAN People
5
* Copyright (C) 2003 ATMEL
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
*/
21
22
#include <linux/kernel.h>
23
#include <linux/interrupt.h>
24
#include <linux/irq.h>
25
#include <linux/clockchips.h>
26
27
#include <asm/mach/time.h>
28
29
#include <mach/at91_st.h>
30
31
static unsigned long last_crtr;
32
static u32 irqmask;
33
static struct clock_event_device clkevt;
34
35
/*
36
* The ST_CRTR is updated asynchronously to the master clock ... but
37
* the updates as seen by the CPU don't seem to be strictly monotonic.
38
* Waiting until we read the same value twice avoids glitching.
39
*/
40
static inline unsigned long read_CRTR(void)
41
{
42
unsigned long x1, x2;
43
44
x1 = at91_sys_read(AT91_ST_CRTR);
45
do {
46
x2 = at91_sys_read(AT91_ST_CRTR);
47
if (x1 == x2)
48
break;
49
x1 = x2;
50
} while (1);
51
return x1;
52
}
53
54
/*
55
* IRQ handler for the timer.
56
*/
57
static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
58
{
59
u32 sr = at91_sys_read(AT91_ST_SR) & irqmask;
60
61
/*
62
* irqs should be disabled here, but as the irq is shared they are only
63
* guaranteed to be off if the timer irq is registered first.
64
*/
65
WARN_ON_ONCE(!irqs_disabled());
66
67
/* simulate "oneshot" timer with alarm */
68
if (sr & AT91_ST_ALMS) {
69
clkevt.event_handler(&clkevt);
70
return IRQ_HANDLED;
71
}
72
73
/* periodic mode should handle delayed ticks */
74
if (sr & AT91_ST_PITS) {
75
u32 crtr = read_CRTR();
76
77
while (((crtr - last_crtr) & AT91_ST_CRTV) >= LATCH) {
78
last_crtr += LATCH;
79
clkevt.event_handler(&clkevt);
80
}
81
return IRQ_HANDLED;
82
}
83
84
/* this irq is shared ... */
85
return IRQ_NONE;
86
}
87
88
static struct irqaction at91rm9200_timer_irq = {
89
.name = "at91_tick",
90
.flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
91
.handler = at91rm9200_timer_interrupt
92
};
93
94
static cycle_t read_clk32k(struct clocksource *cs)
95
{
96
return read_CRTR();
97
}
98
99
static struct clocksource clk32k = {
100
.name = "32k_counter",
101
.rating = 150,
102
.read = read_clk32k,
103
.mask = CLOCKSOURCE_MASK(20),
104
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
105
};
106
107
static void
108
clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
109
{
110
/* Disable and flush pending timer interrupts */
111
at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
112
(void) at91_sys_read(AT91_ST_SR);
113
114
last_crtr = read_CRTR();
115
switch (mode) {
116
case CLOCK_EVT_MODE_PERIODIC:
117
/* PIT for periodic irqs; fixed rate of 1/HZ */
118
irqmask = AT91_ST_PITS;
119
at91_sys_write(AT91_ST_PIMR, LATCH);
120
break;
121
case CLOCK_EVT_MODE_ONESHOT:
122
/* ALM for oneshot irqs, set by next_event()
123
* before 32 seconds have passed
124
*/
125
irqmask = AT91_ST_ALMS;
126
at91_sys_write(AT91_ST_RTAR, last_crtr);
127
break;
128
case CLOCK_EVT_MODE_SHUTDOWN:
129
case CLOCK_EVT_MODE_UNUSED:
130
case CLOCK_EVT_MODE_RESUME:
131
irqmask = 0;
132
break;
133
}
134
at91_sys_write(AT91_ST_IER, irqmask);
135
}
136
137
static int
138
clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
139
{
140
u32 alm;
141
int status = 0;
142
143
BUG_ON(delta < 2);
144
145
/* The alarm IRQ uses absolute time (now+delta), not the relative
146
* time (delta) in our calling convention. Like all clockevents
147
* using such "match" hardware, we have a race to defend against.
148
*
149
* Our defense here is to have set up the clockevent device so the
150
* delta is at least two. That way we never end up writing RTAR
151
* with the value then held in CRTR ... which would mean the match
152
* wouldn't trigger until 32 seconds later, after CRTR wraps.
153
*/
154
alm = read_CRTR();
155
156
/* Cancel any pending alarm; flush any pending IRQ */
157
at91_sys_write(AT91_ST_RTAR, alm);
158
(void) at91_sys_read(AT91_ST_SR);
159
160
/* Schedule alarm by writing RTAR. */
161
alm += delta;
162
at91_sys_write(AT91_ST_RTAR, alm);
163
164
return status;
165
}
166
167
static struct clock_event_device clkevt = {
168
.name = "at91_tick",
169
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
170
.shift = 32,
171
.rating = 150,
172
.set_next_event = clkevt32k_next_event,
173
.set_mode = clkevt32k_mode,
174
};
175
176
/*
177
* ST (system timer) module supports both clockevents and clocksource.
178
*/
179
void __init at91rm9200_timer_init(void)
180
{
181
/* Disable all timer interrupts, and clear any pending ones */
182
at91_sys_write(AT91_ST_IDR,
183
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
184
(void) at91_sys_read(AT91_ST_SR);
185
186
/* Make IRQs happen for the system timer */
187
setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq);
188
189
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
190
* directly for the clocksource and all clockevents, after adjusting
191
* its prescaler from the 1 Hz default.
192
*/
193
at91_sys_write(AT91_ST_RTMR, 1);
194
195
/* Setup timer clockevent, with minimum of two ticks (important!!) */
196
clkevt.mult = div_sc(AT91_SLOW_CLOCK, NSEC_PER_SEC, clkevt.shift);
197
clkevt.max_delta_ns = clockevent_delta2ns(AT91_ST_ALMV, &clkevt);
198
clkevt.min_delta_ns = clockevent_delta2ns(2, &clkevt) + 1;
199
clkevt.cpumask = cpumask_of(0);
200
clockevents_register_device(&clkevt);
201
202
/* register clocksource */
203
clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
204
}
205
206
struct sys_timer at91rm9200_timer = {
207
.init = at91rm9200_timer_init,
208
};
209
210
211