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.
39 #include "dev/arm/timer_a9global.hh"
41 #include "base/intmath.hh"
42 #include "base/trace.hh"
43 #include "debug/Checkpoint.hh"
44 #include "debug/Timer.hh"
45 #include "dev/arm/base_gic.hh"
46 #include "mem/packet.hh"
47 #include "mem/packet_access.hh"
49 A9GlobalTimer::A9GlobalTimer(Params
*p
)
50 : BasicPioDevice(p
, 0x1C), gic(p
->gic
),
51 global_timer(name() + ".globaltimer", this, p
->int_num
)
55 A9GlobalTimer::Timer::Timer(std::string __name
, A9GlobalTimer
*_parent
,
57 : _name(__name
), parent(_parent
), intNum(int_num
), control(0x0),
58 rawInt(false), pendingInt(false), autoIncValue(0x0), cmpValEvent(this)
63 A9GlobalTimer::read(PacketPtr pkt
)
65 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
66 assert(pkt
->getSize() == 4);
67 Addr daddr
= pkt
->getAddr() - pioAddr
;
69 if (daddr
< Timer::Size
)
70 global_timer
.read(pkt
, daddr
);
72 panic("Tried to read A9GlobalTimer at offset %#x that doesn't exist\n",
74 pkt
->makeAtomicResponse();
79 A9GlobalTimer::Timer::getTimeCounterFromTicks(Tick ticks
)
81 return ticks
/ parent
->clockPeriod() / (control
.prescalar
+ 1) - 1;
85 A9GlobalTimer::Timer::read(PacketPtr pkt
, Addr daddr
)
87 DPRINTF(Timer
, "Reading from A9GlobalTimer at offset: %#x\n", daddr
);
92 time
= getTimeCounterFromTicks(curTick());
93 DPRINTF(Timer
, "-- returning lower 32-bits of counter: %u\n", time
);
94 pkt
->setLE
<uint32_t>(time
);
96 case CounterRegHigh32
:
97 time
= getTimeCounterFromTicks(curTick());
99 DPRINTF(Timer
, "-- returning upper 32-bits of counter: %u\n", time
);
100 pkt
->setLE
<uint32_t>(time
);
103 pkt
->setLE
<uint32_t>(control
);
106 pkt
->setLE
<uint32_t>(rawInt
);
109 DPRINTF(Timer
, "Event schedule for %d, clock=%d, prescale=%d\n",
110 cmpValEvent
.when(), parent
->clockPeriod(), control
.prescalar
);
111 if (cmpValEvent
.scheduled()) {
112 time
= getTimeCounterFromTicks(cmpValEvent
.when() - curTick());
116 DPRINTF(Timer
, "-- returning lower 32-bits of comparator: %u\n", time
);
117 pkt
->setLE
<uint32_t>(time
);
119 case CmpValRegHigh32
:
120 DPRINTF(Timer
, "Event schedule for %d, clock=%d, prescale=%d\n",
121 cmpValEvent
.when(), parent
->clockPeriod(), control
.prescalar
);
122 if (cmpValEvent
.scheduled()) {
123 time
= getTimeCounterFromTicks(cmpValEvent
.when() - curTick());
128 DPRINTF(Timer
, "-- returning upper 32-bits of comparator: %u\n", time
);
129 pkt
->setLE
<uint32_t>(time
);
131 case AutoIncrementReg
:
132 pkt
->setLE
<uint32_t>(autoIncValue
);
135 panic("Tried to read A9GlobalTimer at offset %#x\n", daddr
);
138 DPRINTF(Timer
, "Reading %#x from A9GlobalTimer at offset: %#x\n",
139 pkt
->getLE
<uint32_t>(), daddr
);
143 A9GlobalTimer::write(PacketPtr pkt
)
145 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
146 assert(pkt
->getSize() == 4);
147 Addr daddr
= pkt
->getAddr() - pioAddr
;
148 DPRINTF(Timer
, "Writing to A9GlobalTimer at offset: %#x\n", daddr
);
150 warn_once("A9 Global Timer doesn't support banked per-cpu registers\n");
152 if (daddr
< Timer::Size
)
153 global_timer
.write(pkt
, daddr
);
155 panic("Tried to write A9GlobalTimer at offset %#x doesn't exist\n",
157 pkt
->makeAtomicResponse();
162 A9GlobalTimer::Timer::write(PacketPtr pkt
, Addr daddr
)
164 DPRINTF(Timer
, "Writing %#x to A9GlobalTimer at offset: %#x\n",
165 pkt
->getLE
<uint32_t>(), daddr
);
167 case CounterRegLow32
:
168 case CounterRegHigh32
:
169 DPRINTF(Timer
, "Ignoring unsupported write to Global Timer Counter\n");
174 old_enable
= control
.enable
;
175 old_cmpEnable
= control
.cmpEnable
;
176 control
= pkt
->getLE
<uint32_t>();
177 if ((old_enable
== 0) && control
.enable
)
179 if ((old_cmpEnable
== 0) && control
.cmpEnable
)
183 /* TODO: should check that '1' was written. */
187 DPRINTF(Timer
, "Clearing interrupt\n");
188 parent
->gic
->clearInt(intNum
);
192 cmpVal
&= 0xFFFFFFFF00000000ULL
;
193 cmpVal
|= (uint64_t)pkt
->getLE
<uint32_t>();
195 case CmpValRegHigh32
:
196 cmpVal
&= 0x00000000FFFFFFFFULL
;
197 cmpVal
|= ((uint64_t)pkt
->getLE
<uint32_t>() << 32);
199 case AutoIncrementReg
:
200 autoIncValue
= pkt
->getLE
<uint32_t>();
203 panic("Tried to write A9GlobalTimer at offset %#x\n", daddr
);
209 A9GlobalTimer::Timer::restartCounter()
213 DPRINTF(Timer
, "Restarting counter with value %#x\n", cmpVal
);
215 Tick time
= parent
->clockPeriod() * (control
.prescalar
+ 1) * (cmpVal
+ 1);
217 if (time
< curTick()) {
218 DPRINTF(Timer
, "-- Event time %#x < curTick %#x\n", time
, curTick());
221 if (cmpValEvent
.scheduled()) {
222 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
223 parent
->deschedule(cmpValEvent
);
225 parent
->schedule(cmpValEvent
, time
);
226 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", time
);
230 A9GlobalTimer::Timer::counterAtCmpVal()
235 DPRINTF(Timer
, "Counter reached cmpVal\n");
238 bool old_pending
= pendingInt
;
239 if (control
.intEnable
)
241 if (pendingInt
&& !old_pending
) {
242 DPRINTF(Timer
, "-- Causing interrupt\n");
243 parent
->gic
->sendPPInt(intNum
, 0); /* FIXME: cpuNum */
246 if (control
.autoIncrement
== 0) // one-shot
249 cmpVal
+= (uint64_t)autoIncValue
;
254 A9GlobalTimer::Timer::serialize(CheckpointOut
&cp
) const
256 DPRINTF(Checkpoint
, "Serializing Arm A9GlobalTimer\n");
258 uint32_t control_serial
= control
;
259 SERIALIZE_SCALAR(control_serial
);
261 SERIALIZE_SCALAR(rawInt
);
262 SERIALIZE_SCALAR(pendingInt
);
263 SERIALIZE_SCALAR(cmpVal
);
264 SERIALIZE_SCALAR(autoIncValue
);
266 bool is_in_event
= cmpValEvent
.scheduled();
267 SERIALIZE_SCALAR(is_in_event
);
271 event_time
= cmpValEvent
.when();
272 SERIALIZE_SCALAR(event_time
);
277 A9GlobalTimer::Timer::unserialize(CheckpointIn
&cp
)
279 DPRINTF(Checkpoint
, "Unserializing Arm A9GlobalTimer\n");
281 uint32_t control_serial
;
282 UNSERIALIZE_SCALAR(control_serial
);
283 control
= control_serial
;
285 UNSERIALIZE_SCALAR(rawInt
);
286 UNSERIALIZE_SCALAR(pendingInt
);
287 UNSERIALIZE_SCALAR(cmpVal
);
288 UNSERIALIZE_SCALAR(autoIncValue
);
291 UNSERIALIZE_SCALAR(is_in_event
);
295 UNSERIALIZE_SCALAR(event_time
);
296 parent
->schedule(cmpValEvent
, event_time
);
301 A9GlobalTimer::serialize(CheckpointOut
&cp
) const
303 global_timer
.serialize(cp
);
307 A9GlobalTimer::unserialize(CheckpointIn
&cp
)
309 global_timer
.unserialize(cp
);
313 A9GlobalTimerParams::create()
315 return new A9GlobalTimer(this);