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