2 * Copyright (c) 2017 Gedare Bloom
3 * Copyright (c) 2010 ARM Limited
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
17 * met: redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer;
19 * redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution;
22 * neither the name of the copyright holders nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "dev/arm/timer_a9global.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 A9GlobalTimer::A9GlobalTimer(Params
*p
)
53 : BasicPioDevice(p
, 0x1C), gic(p
->gic
),
54 global_timer(name() + ".globaltimer", this, p
->int_num
)
58 A9GlobalTimer::Timer::Timer(std::string __name
, A9GlobalTimer
*_parent
,
60 : _name(__name
), parent(_parent
), intNum(int_num
), control(0x0),
61 rawInt(false), pendingInt(false), autoIncValue(0x0), cmpValEvent(this)
66 A9GlobalTimer::read(PacketPtr pkt
)
68 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
69 assert(pkt
->getSize() == 4);
70 Addr daddr
= pkt
->getAddr() - pioAddr
;
72 if (daddr
< Timer::Size
)
73 global_timer
.read(pkt
, daddr
);
75 panic("Tried to read A9GlobalTimer at offset %#x that doesn't exist\n",
77 pkt
->makeAtomicResponse();
82 A9GlobalTimer::Timer::getTimeCounterFromTicks(Tick ticks
)
84 return ticks
/ parent
->clockPeriod() / (control
.prescalar
+ 1) - 1;
88 A9GlobalTimer::Timer::read(PacketPtr pkt
, Addr daddr
)
90 DPRINTF(Timer
, "Reading from A9GlobalTimer at offset: %#x\n", daddr
);
95 time
= getTimeCounterFromTicks(curTick());
96 DPRINTF(Timer
, "-- returning lower 32-bits of counter: %u\n", time
);
97 pkt
->set
<uint32_t>(time
);
99 case CounterRegHigh32
:
100 time
= getTimeCounterFromTicks(curTick());
102 DPRINTF(Timer
, "-- returning upper 32-bits of counter: %u\n", time
);
103 pkt
->set
<uint32_t>(time
);
106 pkt
->set
<uint32_t>(control
);
109 pkt
->set
<uint32_t>(rawInt
);
112 DPRINTF(Timer
, "Event schedule for %d, clock=%d, prescale=%d\n",
113 cmpValEvent
.when(), parent
->clockPeriod(), control
.prescalar
);
114 if (cmpValEvent
.scheduled()) {
115 time
= getTimeCounterFromTicks(cmpValEvent
.when() - curTick());
119 DPRINTF(Timer
, "-- returning lower 32-bits of comparator: %u\n", time
);
120 pkt
->set
<uint32_t>(time
);
122 case CmpValRegHigh32
:
123 DPRINTF(Timer
, "Event schedule for %d, clock=%d, prescale=%d\n",
124 cmpValEvent
.when(), parent
->clockPeriod(), control
.prescalar
);
125 if (cmpValEvent
.scheduled()) {
126 time
= getTimeCounterFromTicks(cmpValEvent
.when() - curTick());
131 DPRINTF(Timer
, "-- returning upper 32-bits of comparator: %u\n", time
);
132 pkt
->set
<uint32_t>(time
);
134 case AutoIncrementReg
:
135 pkt
->set
<uint32_t>(autoIncValue
);
138 panic("Tried to read A9GlobalTimer at offset %#x\n", daddr
);
141 DPRINTF(Timer
, "Reading %#x from A9GlobalTimer at offset: %#x\n",
142 pkt
->get
<uint32_t>(), daddr
);
146 A9GlobalTimer::write(PacketPtr pkt
)
148 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
149 assert(pkt
->getSize() == 4);
150 Addr daddr
= pkt
->getAddr() - pioAddr
;
151 DPRINTF(Timer
, "Writing to A9GlobalTimer at offset: %#x\n", daddr
);
153 warn_once("A9 Global Timer doesn't support banked per-cpu registers\n");
155 if (daddr
< Timer::Size
)
156 global_timer
.write(pkt
, daddr
);
158 panic("Tried to write A9GlobalTimer at offset %#x doesn't exist\n",
160 pkt
->makeAtomicResponse();
165 A9GlobalTimer::Timer::write(PacketPtr pkt
, Addr daddr
)
167 DPRINTF(Timer
, "Writing %#x to A9GlobalTimer at offset: %#x\n",
168 pkt
->get
<uint32_t>(), daddr
);
170 case CounterRegLow32
:
171 case CounterRegHigh32
:
172 DPRINTF(Timer
, "Ignoring unsupported write to Global Timer Counter\n");
177 old_enable
= control
.enable
;
178 old_cmpEnable
= control
.cmpEnable
;
179 control
= pkt
->get
<uint32_t>();
180 if ((old_enable
== 0) && control
.enable
)
182 if ((old_cmpEnable
== 0) && control
.cmpEnable
)
186 /* TODO: should check that '1' was written. */
190 DPRINTF(Timer
, "Clearing interrupt\n");
191 parent
->gic
->clearInt(intNum
);
195 cmpVal
&= 0xFFFFFFFF00000000ULL
;
196 cmpVal
|= (uint64_t)pkt
->get
<uint32_t>();
198 case CmpValRegHigh32
:
199 cmpVal
&= 0x00000000FFFFFFFFULL
;
200 cmpVal
|= ((uint64_t)pkt
->get
<uint32_t>() << 32);
202 case AutoIncrementReg
:
203 autoIncValue
= pkt
->get
<uint32_t>();
206 panic("Tried to write A9GlobalTimer at offset %#x\n", daddr
);
212 A9GlobalTimer::Timer::restartCounter()
216 DPRINTF(Timer
, "Restarting counter with value %#x\n", cmpVal
);
218 Tick time
= parent
->clockPeriod() * (control
.prescalar
+ 1) * (cmpVal
+ 1);
220 if (time
< curTick()) {
221 DPRINTF(Timer
, "-- Event time %#x < curTick %#x\n", time
, curTick());
224 if (cmpValEvent
.scheduled()) {
225 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
226 parent
->deschedule(cmpValEvent
);
228 parent
->schedule(cmpValEvent
, time
);
229 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", time
);
233 A9GlobalTimer::Timer::counterAtCmpVal()
238 DPRINTF(Timer
, "Counter reached cmpVal\n");
241 bool old_pending
= pendingInt
;
242 if (control
.intEnable
)
244 if (pendingInt
&& !old_pending
) {
245 DPRINTF(Timer
, "-- Causing interrupt\n");
246 parent
->gic
->sendPPInt(intNum
, 0); /* FIXME: cpuNum */
249 if (control
.autoIncrement
== 0) // one-shot
252 cmpVal
+= (uint64_t)autoIncValue
;
257 A9GlobalTimer::Timer::serialize(CheckpointOut
&cp
) const
259 DPRINTF(Checkpoint
, "Serializing Arm A9GlobalTimer\n");
261 uint32_t control_serial
= control
;
262 SERIALIZE_SCALAR(control_serial
);
264 SERIALIZE_SCALAR(rawInt
);
265 SERIALIZE_SCALAR(pendingInt
);
266 SERIALIZE_SCALAR(cmpVal
);
267 SERIALIZE_SCALAR(autoIncValue
);
269 bool is_in_event
= cmpValEvent
.scheduled();
270 SERIALIZE_SCALAR(is_in_event
);
274 event_time
= cmpValEvent
.when();
275 SERIALIZE_SCALAR(event_time
);
280 A9GlobalTimer::Timer::unserialize(CheckpointIn
&cp
)
282 DPRINTF(Checkpoint
, "Unserializing Arm A9GlobalTimer\n");
284 uint32_t control_serial
;
285 UNSERIALIZE_SCALAR(control_serial
);
286 control
= control_serial
;
288 UNSERIALIZE_SCALAR(rawInt
);
289 UNSERIALIZE_SCALAR(pendingInt
);
290 UNSERIALIZE_SCALAR(cmpVal
);
291 UNSERIALIZE_SCALAR(autoIncValue
);
294 UNSERIALIZE_SCALAR(is_in_event
);
298 UNSERIALIZE_SCALAR(event_time
);
299 parent
->schedule(cmpValEvent
, event_time
);
304 A9GlobalTimer::serialize(CheckpointOut
&cp
) const
306 global_timer
.serialize(cp
);
310 A9GlobalTimer::unserialize(CheckpointIn
&cp
)
312 global_timer
.unserialize(cp
);
316 A9GlobalTimerParams::create()
318 return new A9GlobalTimer(this);