timer_sp804.cc (8245:a9d06c894afe) timer_sp804.cc (8524:1ddd1aa0e55b)
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Ali Saidi
38 */
39
40#include "base/intmath.hh"
41#include "base/trace.hh"
42#include "debug/Checkpoint.hh"
43#include "debug/Timer.hh"
44#include "dev/arm/gic.hh"
45#include "dev/arm/timer_sp804.hh"
46#include "mem/packet.hh"
47#include "mem/packet_access.hh"
48
49using namespace AmbaDev;
50
51Sp804::Sp804(Params *p)
52 : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0),
53 timer1(name() + ".timer1", this, p->int_num1, p->clock1)
54{
55 pioSize = 0xfff;
56}
57
58Sp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock)
59 : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20),
60 rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this)
61{
62}
63
64
65Tick
66Sp804::read(PacketPtr pkt)
67{
68 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
69 assert(pkt->getSize() == 4);
70 Addr daddr = pkt->getAddr() - pioAddr;
71 pkt->allocate();
72 DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr);
73
74 if (daddr < Timer::Size)
75 timer0.read(pkt, daddr);
76 else if ((daddr - Timer::Size) < Timer::Size)
77 timer1.read(pkt, daddr - Timer::Size);
78 else if (!readId(pkt, ambaId, pioAddr))
79 panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr);
80 pkt->makeAtomicResponse();
81 return pioDelay;
82}
83
84
85void
86Sp804::Timer::read(PacketPtr pkt, Addr daddr)
87{
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Ali Saidi
38 */
39
40#include "base/intmath.hh"
41#include "base/trace.hh"
42#include "debug/Checkpoint.hh"
43#include "debug/Timer.hh"
44#include "dev/arm/gic.hh"
45#include "dev/arm/timer_sp804.hh"
46#include "mem/packet.hh"
47#include "mem/packet_access.hh"
48
49using namespace AmbaDev;
50
51Sp804::Sp804(Params *p)
52 : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0),
53 timer1(name() + ".timer1", this, p->int_num1, p->clock1)
54{
55 pioSize = 0xfff;
56}
57
58Sp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock)
59 : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20),
60 rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this)
61{
62}
63
64
65Tick
66Sp804::read(PacketPtr pkt)
67{
68 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
69 assert(pkt->getSize() == 4);
70 Addr daddr = pkt->getAddr() - pioAddr;
71 pkt->allocate();
72 DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr);
73
74 if (daddr < Timer::Size)
75 timer0.read(pkt, daddr);
76 else if ((daddr - Timer::Size) < Timer::Size)
77 timer1.read(pkt, daddr - Timer::Size);
78 else if (!readId(pkt, ambaId, pioAddr))
79 panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr);
80 pkt->makeAtomicResponse();
81 return pioDelay;
82}
83
84
85void
86Sp804::Timer::read(PacketPtr pkt, Addr daddr)
87{
88 DPRINTF(Timer, "Reading from Timer at offset: %#x\n", daddr);
89
90 switch(daddr) {
91 case LoadReg:
92 pkt->set<uint32_t>(loadValue);
93 break;
94 case CurrentReg:
95 DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n",
96 zeroEvent.when(), clock, control.timerPrescale);
97 Tick time;
98 time = zeroEvent.when() - curTick();
99 time = time / clock / power(16, control.timerPrescale);
100 DPRINTF(Timer, "-- returning counter at %d\n", time);
101 pkt->set<uint32_t>(time);
102 break;
103 case ControlReg:
104 pkt->set<uint32_t>(control);
105 break;
106 case RawISR:
107 pkt->set<uint32_t>(rawInt);
108 break;
109 case MaskedISR:
110 pkt->set<uint32_t>(pendingInt);
111 break;
112 case BGLoad:
113 pkt->set<uint32_t>(loadValue);
114 break;
115 default:
116 panic("Tried to read SP804 timer at offset %#x\n", daddr);
117 break;
118 }
88 switch(daddr) {
89 case LoadReg:
90 pkt->set<uint32_t>(loadValue);
91 break;
92 case CurrentReg:
93 DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n",
94 zeroEvent.when(), clock, control.timerPrescale);
95 Tick time;
96 time = zeroEvent.when() - curTick();
97 time = time / clock / power(16, control.timerPrescale);
98 DPRINTF(Timer, "-- returning counter at %d\n", time);
99 pkt->set<uint32_t>(time);
100 break;
101 case ControlReg:
102 pkt->set<uint32_t>(control);
103 break;
104 case RawISR:
105 pkt->set<uint32_t>(rawInt);
106 break;
107 case MaskedISR:
108 pkt->set<uint32_t>(pendingInt);
109 break;
110 case BGLoad:
111 pkt->set<uint32_t>(loadValue);
112 break;
113 default:
114 panic("Tried to read SP804 timer at offset %#x\n", daddr);
115 break;
116 }
117 DPRINTF(Timer, "Reading %#x from Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
119}
120
121Tick
122Sp804::write(PacketPtr pkt)
123{
124 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
125 assert(pkt->getSize() == 4);
126 Addr daddr = pkt->getAddr() - pioAddr;
127 pkt->allocate();
128 DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr);
129
130 if (daddr < Timer::Size)
131 timer0.write(pkt, daddr);
132 else if ((daddr - Timer::Size) < Timer::Size)
133 timer1.write(pkt, daddr - Timer::Size);
134 else if (!readId(pkt, ambaId, pioAddr))
135 panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr);
136 pkt->makeAtomicResponse();
137 return pioDelay;
138}
139
140void
141Sp804::Timer::write(PacketPtr pkt, Addr daddr)
142{
118}
119
120Tick
121Sp804::write(PacketPtr pkt)
122{
123 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
124 assert(pkt->getSize() == 4);
125 Addr daddr = pkt->getAddr() - pioAddr;
126 pkt->allocate();
127 DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr);
128
129 if (daddr < Timer::Size)
130 timer0.write(pkt, daddr);
131 else if ((daddr - Timer::Size) < Timer::Size)
132 timer1.write(pkt, daddr - Timer::Size);
133 else if (!readId(pkt, ambaId, pioAddr))
134 panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr);
135 pkt->makeAtomicResponse();
136 return pioDelay;
137}
138
139void
140Sp804::Timer::write(PacketPtr pkt, Addr daddr)
141{
143 DPRINTF(Timer, "Writing to Timer at offset: %#x\n", daddr);
142 DPRINTF(Timer, "Writing %#x to Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
144 switch (daddr) {
145 case LoadReg:
146 loadValue = pkt->get<uint32_t>();
147 restartCounter(loadValue);
148 break;
149 case CurrentReg:
150 // Spec says this value can't be written, but linux writes it anyway
151 break;
152 case ControlReg:
153 bool old_enable;
154 old_enable = control.timerEnable;
155 control = pkt->get<uint32_t>();
156 if ((old_enable == 0) && control.timerEnable)
157 restartCounter(loadValue);
158 break;
159 case IntClear:
160 rawInt = false;
161 if (pendingInt) {
162 pendingInt = false;
163 DPRINTF(Timer, "Clearing interrupt\n");
164 parent->gic->clearInt(intNum);
165 }
166 break;
167 case BGLoad:
168 loadValue = pkt->get<uint32_t>();
169 break;
170 default:
171 panic("Tried to write SP804 timer at offset %#x\n", daddr);
172 break;
173 }
174}
175
176void
177Sp804::Timer::restartCounter(uint32_t val)
178{
179 DPRINTF(Timer, "Resetting counter with value %#x\n", val);
180 if (!control.timerEnable)
181 return;
182
183 Tick time = clock * power(16, control.timerPrescale);
184 if (control.timerSize)
185 time *= val;
186 else
187 time *= bits(val,15,0);
188
189 if (zeroEvent.scheduled()) {
190 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
191 parent->deschedule(zeroEvent);
192 }
193 parent->schedule(zeroEvent, curTick() + time);
194 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
195}
196
197void
198Sp804::Timer::counterAtZero()
199{
200 if (!control.timerEnable)
201 return;
202
203 DPRINTF(Timer, "Counter reached zero\n");
204
205 rawInt = true;
206 bool old_pending = pendingInt;
207 if (control.intEnable)
208 pendingInt = true;
209 if (pendingInt && ~old_pending) {
210 DPRINTF(Timer, "-- Causing interrupt\n");
211 parent->gic->sendInt(intNum);
212 }
213
214 if (control.oneShot)
215 return;
216
217 // Free-running
218 if (control.timerMode == 0)
219 restartCounter(0xffffffff);
220 else
221 restartCounter(loadValue);
222}
223
224void
225Sp804::Timer::serialize(std::ostream &os)
226{
227 DPRINTF(Checkpoint, "Serializing Arm Sp804\n");
228 SERIALIZE_SCALAR(intNum);
229 SERIALIZE_SCALAR(clock);
230
231 uint32_t control_serial = control;
232 SERIALIZE_SCALAR(control_serial);
233
234 SERIALIZE_SCALAR(rawInt);
235 SERIALIZE_SCALAR(pendingInt);
236 SERIALIZE_SCALAR(loadValue);
237
238 bool is_in_event = zeroEvent.scheduled();
239 SERIALIZE_SCALAR(is_in_event);
240
241 Tick event_time;
242 if (is_in_event){
243 event_time = zeroEvent.when();
244 SERIALIZE_SCALAR(event_time);
245 }
246}
247
248void
249Sp804::Timer::unserialize(Checkpoint *cp, const std::string &section)
250{
251 DPRINTF(Checkpoint, "Unserializing Arm Sp804\n");
252
253 UNSERIALIZE_SCALAR(intNum);
254 UNSERIALIZE_SCALAR(clock);
255
256 uint32_t control_serial;
257 UNSERIALIZE_SCALAR(control_serial);
258 control = control_serial;
259
260 UNSERIALIZE_SCALAR(rawInt);
261 UNSERIALIZE_SCALAR(pendingInt);
262 UNSERIALIZE_SCALAR(loadValue);
263
264 bool is_in_event;
265 UNSERIALIZE_SCALAR(is_in_event);
266
267 Tick event_time;
268 if (is_in_event){
269 UNSERIALIZE_SCALAR(event_time);
270 parent->schedule(zeroEvent, event_time);
271 }
272}
273
274
275
276void
277Sp804::serialize(std::ostream &os)
278{
279 nameOut(os, csprintf("%s.timer0", name()));
280 timer0.serialize(os);
281 nameOut(os, csprintf("%s.timer1", name()));
282 timer1.serialize(os);
283}
284
285void
286Sp804::unserialize(Checkpoint *cp, const std::string &section)
287{
288 timer0.unserialize(cp, csprintf("%s.timer0", section));
289 timer1.unserialize(cp, csprintf("%s.timer1", section));
290}
291
292Sp804 *
293Sp804Params::create()
294{
295 return new Sp804(this);
296}
143 switch (daddr) {
144 case LoadReg:
145 loadValue = pkt->get<uint32_t>();
146 restartCounter(loadValue);
147 break;
148 case CurrentReg:
149 // Spec says this value can't be written, but linux writes it anyway
150 break;
151 case ControlReg:
152 bool old_enable;
153 old_enable = control.timerEnable;
154 control = pkt->get<uint32_t>();
155 if ((old_enable == 0) && control.timerEnable)
156 restartCounter(loadValue);
157 break;
158 case IntClear:
159 rawInt = false;
160 if (pendingInt) {
161 pendingInt = false;
162 DPRINTF(Timer, "Clearing interrupt\n");
163 parent->gic->clearInt(intNum);
164 }
165 break;
166 case BGLoad:
167 loadValue = pkt->get<uint32_t>();
168 break;
169 default:
170 panic("Tried to write SP804 timer at offset %#x\n", daddr);
171 break;
172 }
173}
174
175void
176Sp804::Timer::restartCounter(uint32_t val)
177{
178 DPRINTF(Timer, "Resetting counter with value %#x\n", val);
179 if (!control.timerEnable)
180 return;
181
182 Tick time = clock * power(16, control.timerPrescale);
183 if (control.timerSize)
184 time *= val;
185 else
186 time *= bits(val,15,0);
187
188 if (zeroEvent.scheduled()) {
189 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
190 parent->deschedule(zeroEvent);
191 }
192 parent->schedule(zeroEvent, curTick() + time);
193 DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
194}
195
196void
197Sp804::Timer::counterAtZero()
198{
199 if (!control.timerEnable)
200 return;
201
202 DPRINTF(Timer, "Counter reached zero\n");
203
204 rawInt = true;
205 bool old_pending = pendingInt;
206 if (control.intEnable)
207 pendingInt = true;
208 if (pendingInt && ~old_pending) {
209 DPRINTF(Timer, "-- Causing interrupt\n");
210 parent->gic->sendInt(intNum);
211 }
212
213 if (control.oneShot)
214 return;
215
216 // Free-running
217 if (control.timerMode == 0)
218 restartCounter(0xffffffff);
219 else
220 restartCounter(loadValue);
221}
222
223void
224Sp804::Timer::serialize(std::ostream &os)
225{
226 DPRINTF(Checkpoint, "Serializing Arm Sp804\n");
227 SERIALIZE_SCALAR(intNum);
228 SERIALIZE_SCALAR(clock);
229
230 uint32_t control_serial = control;
231 SERIALIZE_SCALAR(control_serial);
232
233 SERIALIZE_SCALAR(rawInt);
234 SERIALIZE_SCALAR(pendingInt);
235 SERIALIZE_SCALAR(loadValue);
236
237 bool is_in_event = zeroEvent.scheduled();
238 SERIALIZE_SCALAR(is_in_event);
239
240 Tick event_time;
241 if (is_in_event){
242 event_time = zeroEvent.when();
243 SERIALIZE_SCALAR(event_time);
244 }
245}
246
247void
248Sp804::Timer::unserialize(Checkpoint *cp, const std::string &section)
249{
250 DPRINTF(Checkpoint, "Unserializing Arm Sp804\n");
251
252 UNSERIALIZE_SCALAR(intNum);
253 UNSERIALIZE_SCALAR(clock);
254
255 uint32_t control_serial;
256 UNSERIALIZE_SCALAR(control_serial);
257 control = control_serial;
258
259 UNSERIALIZE_SCALAR(rawInt);
260 UNSERIALIZE_SCALAR(pendingInt);
261 UNSERIALIZE_SCALAR(loadValue);
262
263 bool is_in_event;
264 UNSERIALIZE_SCALAR(is_in_event);
265
266 Tick event_time;
267 if (is_in_event){
268 UNSERIALIZE_SCALAR(event_time);
269 parent->schedule(zeroEvent, event_time);
270 }
271}
272
273
274
275void
276Sp804::serialize(std::ostream &os)
277{
278 nameOut(os, csprintf("%s.timer0", name()));
279 timer0.serialize(os);
280 nameOut(os, csprintf("%s.timer1", name()));
281 timer1.serialize(os);
282}
283
284void
285Sp804::unserialize(Checkpoint *cp, const std::string &section)
286{
287 timer0.unserialize(cp, csprintf("%s.timer0", section));
288 timer1.unserialize(cp, csprintf("%s.timer1", section));
289}
290
291Sp804 *
292Sp804Params::create()
293{
294 return new Sp804(this);
295}