2 * Copyright (c) 2010-2013,2018 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include "dev/arm/timer_cpulocal.hh"
43 #include "arch/arm/system.hh"
44 #include "base/intmath.hh"
45 #include "base/trace.hh"
46 #include "debug/Checkpoint.hh"
47 #include "debug/Timer.hh"
48 #include "dev/arm/base_gic.hh"
49 #include "mem/packet.hh"
50 #include "mem/packet_access.hh"
52 CpuLocalTimer::CpuLocalTimer(Params
*p
)
53 : BasicPioDevice(p
, 0x38)
61 // Initialize the timer registers for each per cpu timer
62 for (int i
= 0; i
< sys
->numContexts(); i
++) {
63 ThreadContext
* tc
= sys
->getThreadContext(i
);
64 std::stringstream oss
;
65 oss
<< name() << ".timer" << i
;
67 localTimer
.emplace_back(
68 new Timer(oss
.str(), this,
69 p
->int_timer
->get(tc
),
70 p
->int_watchdog
->get(tc
)));
73 BasicPioDevice::init();
76 CpuLocalTimer::Timer::Timer(const std::string
&timer_name
,
77 CpuLocalTimer
* _parent
,
78 ArmInterruptPin
* int_timer
,
79 ArmInterruptPin
* int_watchdog
)
80 : _name(timer_name
), parent(_parent
), intTimer(int_timer
),
81 intWatchdog(int_watchdog
), timerControl(0x0), watchdogControl(0x0),
82 rawIntTimer(false), rawIntWatchdog(false),
83 rawResetWatchdog(false), watchdogDisableReg(0x0),
84 pendingIntTimer(false), pendingIntWatchdog(false),
85 timerLoadValue(0x0), watchdogLoadValue(0x0),
86 timerZeroEvent([this]{ timerAtZero(); }, name()),
87 watchdogZeroEvent([this]{ watchdogAtZero(); }, name())
92 CpuLocalTimer::read(PacketPtr pkt
)
94 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
95 assert(pkt
->getSize() == 4);
96 Addr daddr
= pkt
->getAddr() - pioAddr
;
97 ContextID cpu_id
= pkt
->req
->contextId();
98 DPRINTF(Timer
, "Reading from CpuLocalTimer at offset: %#x\n", daddr
);
100 assert(cpu_id
< localTimer
.size());
102 if (daddr
< Timer::Size
)
103 localTimer
[cpu_id
]->read(pkt
, daddr
);
105 panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr
);
106 pkt
->makeAtomicResponse();
112 CpuLocalTimer::Timer::read(PacketPtr pkt
, Addr daddr
)
114 DPRINTF(Timer
, "Reading from CpuLocalTimer at offset: %#x\n", daddr
);
119 pkt
->setLE
<uint32_t>(timerLoadValue
);
121 case TimerCounterReg
:
122 DPRINTF(Timer
, "Event schedule for timer %d, clock=%d, prescale=%d\n",
123 timerZeroEvent
.when(), parent
->clockPeriod(),
124 timerControl
.prescalar
);
125 time
= timerZeroEvent
.when() - curTick();
126 time
= time
/ parent
->clockPeriod() /
127 power(16, timerControl
.prescalar
);
128 DPRINTF(Timer
, "-- returning counter at %d\n", time
);
129 pkt
->setLE
<uint32_t>(time
);
131 case TimerControlReg
:
132 pkt
->setLE
<uint32_t>(timerControl
);
134 case TimerIntStatusReg
:
135 pkt
->setLE
<uint32_t>(rawIntTimer
);
137 case WatchdogLoadReg
:
138 pkt
->setLE
<uint32_t>(watchdogLoadValue
);
140 case WatchdogCounterReg
:
142 "Event schedule for watchdog %d, clock=%d, prescale=%d\n",
143 watchdogZeroEvent
.when(), parent
->clockPeriod(),
144 watchdogControl
.prescalar
);
145 time
= watchdogZeroEvent
.when() - curTick();
146 time
= time
/ parent
->clockPeriod() /
147 power(16, watchdogControl
.prescalar
);
148 DPRINTF(Timer
, "-- returning counter at %d\n", time
);
149 pkt
->setLE
<uint32_t>(time
);
151 case WatchdogControlReg
:
152 pkt
->setLE
<uint32_t>(watchdogControl
);
154 case WatchdogIntStatusReg
:
155 pkt
->setLE
<uint32_t>(rawIntWatchdog
);
157 case WatchdogResetStatusReg
:
158 pkt
->setLE
<uint32_t>(rawResetWatchdog
);
160 case WatchdogDisableReg
:
161 panic("Tried to read from WatchdogDisableRegister\n");
164 panic("Tried to read CpuLocalTimer at offset %#x\n", daddr
);
170 CpuLocalTimer::write(PacketPtr pkt
)
172 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
173 assert(pkt
->getSize() == 4);
174 Addr daddr
= pkt
->getAddr() - pioAddr
;
175 ContextID cpu_id
= pkt
->req
->contextId();
176 DPRINTF(Timer
, "Writing to CpuLocalTimer at offset: %#x\n", daddr
);
178 assert(cpu_id
< localTimer
.size());
180 if (daddr
< Timer::Size
)
181 localTimer
[cpu_id
]->write(pkt
, daddr
);
183 panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr
);
184 pkt
->makeAtomicResponse();
189 CpuLocalTimer::Timer::write(PacketPtr pkt
, Addr daddr
)
191 DPRINTF(Timer
, "Writing to CpuLocalTimer at offset: %#x\n", daddr
);
198 // Writing to this register also resets the counter register and
199 // starts decrementing if the counter is enabled.
200 timerLoadValue
= pkt
->getLE
<uint32_t>();
201 restartTimerCounter(timerLoadValue
);
203 case TimerCounterReg
:
204 // Can be written, doesn't start counting unless the timer is enabled
205 restartTimerCounter(pkt
->getLE
<uint32_t>());
207 case TimerControlReg
:
208 old_enable
= timerControl
.enable
;
209 timerControl
= pkt
->getLE
<uint32_t>();
210 if ((old_enable
== 0) && timerControl
.enable
)
211 restartTimerCounter(timerLoadValue
);
213 case TimerIntStatusReg
:
215 if (pendingIntTimer
) {
216 pendingIntTimer
= false;
217 DPRINTF(Timer
, "Clearing interrupt\n");
220 case WatchdogLoadReg
:
221 watchdogLoadValue
= pkt
->getLE
<uint32_t>();
222 restartWatchdogCounter(watchdogLoadValue
);
224 case WatchdogCounterReg
:
225 // Can't be written when in watchdog mode, but can in timer mode
226 if (!watchdogControl
.watchdogMode
) {
227 restartWatchdogCounter(pkt
->getLE
<uint32_t>());
230 case WatchdogControlReg
:
231 old_enable
= watchdogControl
.enable
;
232 old_wd_mode
= watchdogControl
.watchdogMode
;
233 watchdogControl
= pkt
->getLE
<uint32_t>();
234 if ((old_enable
== 0) && watchdogControl
.enable
)
235 restartWatchdogCounter(watchdogLoadValue
);
236 // cannot disable watchdog using control register
237 if ((old_wd_mode
== 1) && watchdogControl
.watchdogMode
== 0)
238 watchdogControl
.watchdogMode
= 1;
240 case WatchdogIntStatusReg
:
241 rawIntWatchdog
= false;
242 if (pendingIntWatchdog
) {
243 pendingIntWatchdog
= false;
244 DPRINTF(Timer
, "Clearing watchdog interrupt\n");
247 case WatchdogResetStatusReg
:
248 rawResetWatchdog
= false;
249 DPRINTF(Timer
, "Clearing watchdog reset flag\n");
251 case WatchdogDisableReg
:
252 old_val
= watchdogDisableReg
;
253 watchdogDisableReg
= pkt
->getLE
<uint32_t>();
254 // if this sequence is observed, turn off watchdog mode
255 if (old_val
== 0x12345678 && watchdogDisableReg
== 0x87654321)
256 watchdogControl
.watchdogMode
= 0;
259 panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr
);
264 //XXX: Two functions are needed because the control registers are different types
266 CpuLocalTimer::Timer::restartTimerCounter(uint32_t val
)
268 DPRINTF(Timer
, "Resetting timer counter with value %#x\n", val
);
269 if (!timerControl
.enable
)
272 Tick time
= parent
->clockPeriod() * power(16, timerControl
.prescalar
);
275 if (timerZeroEvent
.scheduled()) {
276 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
277 parent
->deschedule(timerZeroEvent
);
279 parent
->schedule(timerZeroEvent
, curTick() + time
);
280 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", curTick() + time
);
284 CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val
)
286 DPRINTF(Timer
, "Resetting watchdog counter with value %#x\n", val
);
287 if (!watchdogControl
.enable
)
290 Tick time
= parent
->clockPeriod() * power(16, watchdogControl
.prescalar
);
293 if (watchdogZeroEvent
.scheduled()) {
294 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
295 parent
->deschedule(watchdogZeroEvent
);
297 parent
->schedule(watchdogZeroEvent
, curTick() + time
);
298 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", curTick() + time
);
303 CpuLocalTimer::Timer::timerAtZero()
305 if (!timerControl
.enable
)
308 DPRINTF(Timer
, "Timer Counter reached zero\n");
311 bool old_pending
= pendingIntTimer
;
312 if (timerControl
.intEnable
)
313 pendingIntTimer
= true;
314 if (pendingIntTimer
&& !old_pending
) {
315 DPRINTF(Timer
, "-- Causing interrupt\n");
319 if (!timerControl
.autoReload
)
322 restartTimerCounter(timerLoadValue
);
326 CpuLocalTimer::Timer::watchdogAtZero()
328 if (!watchdogControl
.enable
)
331 DPRINTF(Timer
, "Watchdog Counter reached zero\n");
333 rawIntWatchdog
= true;
334 bool old_pending
= pendingIntWatchdog
;
335 // generates an interrupt only if the watchdog is in timer
337 if (watchdogControl
.intEnable
&& !watchdogControl
.watchdogMode
)
338 pendingIntWatchdog
= true;
339 else if (watchdogControl
.watchdogMode
) {
340 rawResetWatchdog
= true;
341 fatal("gem5 ARM Model does not support true watchdog operation!\n");
342 //XXX: Should we ever support a true watchdog reset?
345 if (pendingIntWatchdog
&& !old_pending
) {
346 DPRINTF(Timer
, "-- Causing interrupt\n");
347 intWatchdog
->raise();
350 if (watchdogControl
.watchdogMode
)
352 else if (watchdogControl
.autoReload
)
353 restartWatchdogCounter(watchdogLoadValue
);
357 CpuLocalTimer::Timer::serialize(CheckpointOut
&cp
) const
359 DPRINTF(Checkpoint
, "Serializing Arm CpuLocalTimer\n");
361 uint32_t timer_control_serial
= timerControl
;
362 uint32_t watchdog_control_serial
= watchdogControl
;
363 SERIALIZE_SCALAR(timer_control_serial
);
364 SERIALIZE_SCALAR(watchdog_control_serial
);
366 SERIALIZE_SCALAR(rawIntTimer
);
367 SERIALIZE_SCALAR(rawIntWatchdog
);
368 SERIALIZE_SCALAR(rawResetWatchdog
);
369 SERIALIZE_SCALAR(watchdogDisableReg
);
370 SERIALIZE_SCALAR(pendingIntTimer
);
371 SERIALIZE_SCALAR(pendingIntWatchdog
);
372 SERIALIZE_SCALAR(timerLoadValue
);
373 SERIALIZE_SCALAR(watchdogLoadValue
);
375 bool timer_is_in_event
= timerZeroEvent
.scheduled();
376 SERIALIZE_SCALAR(timer_is_in_event
);
377 bool watchdog_is_in_event
= watchdogZeroEvent
.scheduled();
378 SERIALIZE_SCALAR(watchdog_is_in_event
);
380 Tick timer_event_time
;
381 if (timer_is_in_event
){
382 timer_event_time
= timerZeroEvent
.when();
383 SERIALIZE_SCALAR(timer_event_time
);
385 Tick watchdog_event_time
;
386 if (watchdog_is_in_event
){
387 watchdog_event_time
= watchdogZeroEvent
.when();
388 SERIALIZE_SCALAR(watchdog_event_time
);
393 CpuLocalTimer::Timer::unserialize(CheckpointIn
&cp
)
395 DPRINTF(Checkpoint
, "Unserializing Arm CpuLocalTimer\n");
397 uint32_t timer_control_serial
;
398 UNSERIALIZE_SCALAR(timer_control_serial
);
399 timerControl
= timer_control_serial
;
400 uint32_t watchdog_control_serial
;
401 UNSERIALIZE_SCALAR(watchdog_control_serial
);
402 watchdogControl
= watchdog_control_serial
;
404 UNSERIALIZE_SCALAR(rawIntTimer
);
405 UNSERIALIZE_SCALAR(rawIntWatchdog
);
406 UNSERIALIZE_SCALAR(rawResetWatchdog
);
407 UNSERIALIZE_SCALAR(watchdogDisableReg
);
408 UNSERIALIZE_SCALAR(pendingIntTimer
);
409 UNSERIALIZE_SCALAR(pendingIntWatchdog
);
410 UNSERIALIZE_SCALAR(timerLoadValue
);
411 UNSERIALIZE_SCALAR(watchdogLoadValue
);
413 bool timer_is_in_event
;
414 UNSERIALIZE_SCALAR(timer_is_in_event
);
415 bool watchdog_is_in_event
;
416 UNSERIALIZE_SCALAR(watchdog_is_in_event
);
418 Tick timer_event_time
;
419 if (timer_is_in_event
){
420 UNSERIALIZE_SCALAR(timer_event_time
);
421 parent
->schedule(timerZeroEvent
, timer_event_time
);
423 Tick watchdog_event_time
;
424 if (watchdog_is_in_event
) {
425 UNSERIALIZE_SCALAR(watchdog_event_time
);
426 parent
->schedule(watchdogZeroEvent
, watchdog_event_time
);
433 CpuLocalTimer::serialize(CheckpointOut
&cp
) const
435 for (int i
= 0; i
< sys
->numContexts(); i
++)
436 localTimer
[i
]->serializeSection(cp
, csprintf("timer%d", i
));
440 CpuLocalTimer::unserialize(CheckpointIn
&cp
)
442 for (int i
= 0; i
< sys
->numContexts(); i
++)
443 localTimer
[i
]->unserializeSection(cp
, csprintf("timer%d", i
));
447 CpuLocalTimerParams::create()
449 return new CpuLocalTimer(this);