rtc_pl031.cc revision 8245
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 } 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{ 143 DPRINTF(Timer, "Writing to Timer at offset: %#x\n", 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 §ion) 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 §ion) 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} 297