2 * Copyright (c) 2010 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.
38 #include "dev/arm/timer_sp804.hh"
40 #include "base/intmath.hh"
41 #include "base/trace.hh"
42 #include "debug/Checkpoint.hh"
43 #include "debug/Timer.hh"
44 #include "dev/arm/base_gic.hh"
45 #include "mem/packet.hh"
46 #include "mem/packet_access.hh"
48 Sp804::Sp804(const Params
&p
)
49 : AmbaPioDevice(p
, 0x1000),
50 timer0(name() + ".timer0", this, p
.int0
->get(), p
.clock0
),
51 timer1(name() + ".timer1", this, p
.int1
->get(), p
.clock1
)
55 Sp804::Timer::Timer(std::string __name
, Sp804
*_parent
,
56 ArmInterruptPin
*_interrupt
, Tick _clock
)
57 : _name(__name
), parent(_parent
), interrupt(_interrupt
),
58 clock(_clock
), control(0x20),
59 rawInt(false), pendingInt(false), loadValue(0xffffffff),
60 zeroEvent([this]{ counterAtZero(); }, name())
66 Sp804::read(PacketPtr pkt
)
68 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
69 assert(pkt
->getSize() == 4);
70 Addr daddr
= pkt
->getAddr() - pioAddr
;
71 DPRINTF(Timer
, "Reading from DualTimer at offset: %#x\n", daddr
);
73 if (daddr
< Timer::Size
)
74 timer0
.read(pkt
, daddr
);
75 else if ((daddr
- Timer::Size
) < Timer::Size
)
76 timer1
.read(pkt
, daddr
- Timer::Size
);
77 else if (!readId(pkt
, ambaId
, pioAddr
))
78 panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr
);
79 pkt
->makeAtomicResponse();
85 Sp804::Timer::read(PacketPtr pkt
, Addr daddr
)
89 pkt
->setLE
<uint32_t>(loadValue
);
92 DPRINTF(Timer
, "Event schedule for %d, clock=%d, prescale=%d\n",
93 zeroEvent
.when(), clock
, control
.timerPrescale
);
95 time
= zeroEvent
.when() - curTick();
96 time
= time
/ clock
/ power(16, control
.timerPrescale
);
97 DPRINTF(Timer
, "-- returning counter at %d\n", time
);
98 pkt
->setLE
<uint32_t>(time
);
101 pkt
->setLE
<uint32_t>(control
);
104 pkt
->setLE
<uint32_t>(rawInt
);
107 pkt
->setLE
<uint32_t>(pendingInt
);
110 pkt
->setLE
<uint32_t>(loadValue
);
113 panic("Tried to read SP804 timer at offset %#x\n", daddr
);
116 DPRINTF(Timer
, "Reading %#x from Timer at offset: %#x\n",
117 pkt
->getLE
<uint32_t>(), daddr
);
121 Sp804::write(PacketPtr pkt
)
123 assert(pkt
->getAddr() >= pioAddr
&& pkt
->getAddr() < pioAddr
+ pioSize
);
124 assert(pkt
->getSize() == 4);
125 Addr daddr
= pkt
->getAddr() - pioAddr
;
126 DPRINTF(Timer
, "Writing to DualTimer at offset: %#x\n", daddr
);
128 if (daddr
< Timer::Size
)
129 timer0
.write(pkt
, daddr
);
130 else if ((daddr
- Timer::Size
) < Timer::Size
)
131 timer1
.write(pkt
, daddr
- Timer::Size
);
132 else if (!readId(pkt
, ambaId
, pioAddr
))
133 panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr
);
134 pkt
->makeAtomicResponse();
139 Sp804::Timer::write(PacketPtr pkt
, Addr daddr
)
141 DPRINTF(Timer
, "Writing %#x to Timer at offset: %#x\n",
142 pkt
->getLE
<uint32_t>(), daddr
);
145 loadValue
= pkt
->getLE
<uint32_t>();
146 restartCounter(loadValue
);
149 // Spec says this value can't be written, but linux writes it anyway
153 old_enable
= control
.timerEnable
;
154 control
= pkt
->getLE
<uint32_t>();
155 if ((old_enable
== 0) && control
.timerEnable
)
156 restartCounter(loadValue
);
162 DPRINTF(Timer
, "Clearing interrupt\n");
167 loadValue
= pkt
->getLE
<uint32_t>();
170 panic("Tried to write SP804 timer at offset %#x\n", daddr
);
176 Sp804::Timer::restartCounter(uint32_t val
)
178 DPRINTF(Timer
, "Resetting counter with value %#x\n", val
);
179 if (!control
.timerEnable
)
182 Tick time
= clock
* power(16, control
.timerPrescale
);
183 if (control
.timerSize
)
186 time
*= bits(val
,15,0);
188 if (zeroEvent
.scheduled()) {
189 DPRINTF(Timer
, "-- Event was already schedule, de-scheduling\n");
190 parent
->deschedule(zeroEvent
);
192 parent
->schedule(zeroEvent
, curTick() + time
);
193 DPRINTF(Timer
, "-- Scheduling new event for: %d\n", curTick() + time
);
197 Sp804::Timer::counterAtZero()
199 if (!control
.timerEnable
)
202 DPRINTF(Timer
, "Counter reached zero\n");
205 bool old_pending
= pendingInt
;
206 if (control
.intEnable
)
208 if (pendingInt
&& !old_pending
) {
209 DPRINTF(Timer
, "-- Causing interrupt\n");
217 if (control
.timerMode
== 0)
218 restartCounter(0xffffffff);
220 restartCounter(loadValue
);
224 Sp804::Timer::serialize(CheckpointOut
&cp
) const
226 DPRINTF(Checkpoint
, "Serializing Arm Sp804\n");
228 uint32_t control_serial
= control
;
229 SERIALIZE_SCALAR(control_serial
);
231 SERIALIZE_SCALAR(rawInt
);
232 SERIALIZE_SCALAR(pendingInt
);
233 SERIALIZE_SCALAR(loadValue
);
235 bool is_in_event
= zeroEvent
.scheduled();
236 SERIALIZE_SCALAR(is_in_event
);
240 event_time
= zeroEvent
.when();
241 SERIALIZE_SCALAR(event_time
);
246 Sp804::Timer::unserialize(CheckpointIn
&cp
)
248 DPRINTF(Checkpoint
, "Unserializing Arm Sp804\n");
250 uint32_t control_serial
;
251 UNSERIALIZE_SCALAR(control_serial
);
252 control
= control_serial
;
254 UNSERIALIZE_SCALAR(rawInt
);
255 UNSERIALIZE_SCALAR(pendingInt
);
256 UNSERIALIZE_SCALAR(loadValue
);
259 UNSERIALIZE_SCALAR(is_in_event
);
263 UNSERIALIZE_SCALAR(event_time
);
264 parent
->schedule(zeroEvent
, event_time
);
271 Sp804::serialize(CheckpointOut
&cp
) const
273 timer0
.serializeSection(cp
, "timer0");
274 timer1
.serializeSection(cp
, "timer1");
278 Sp804::unserialize(CheckpointIn
&cp
)
280 timer0
.unserializeSection(cp
, "timer0");
281 timer1
.unserializeSection(cp
, "timer1");