timer_a9global.cc revision 13230:2988dc5d1d6f
13630SN/A/* 27090SN/A * Copyright (c) 2017 Gedare Bloom 37090SN/A * Copyright (c) 2010 ARM Limited 47090SN/A * All rights reserved 57090SN/A * 67090SN/A * The license below extends only to copyright in the software and shall 77090SN/A * not be construed as granting a license to any other intellectual 87090SN/A * property including but not limited to intellectual property relating 97090SN/A * to a hardware implementation of the functionality of the software 107090SN/A * licensed hereunder. You may use the software subject to the license 117090SN/A * terms below provided that you ensure that this notice is replicated 127090SN/A * unmodified and in its entirety in all distributions of the software, 137090SN/A * modified or unmodified, in source code or in binary form. 143630SN/A * 153630SN/A * Redistribution and use in source and binary forms, with or without 163630SN/A * modification, are permitted provided that the following conditions are 173630SN/A * met: redistributions of source code must retain the above copyright 183630SN/A * notice, this list of conditions and the following disclaimer; 193630SN/A * redistributions in binary form must reproduce the above copyright 203630SN/A * notice, this list of conditions and the following disclaimer in the 213630SN/A * documentation and/or other materials provided with the distribution; 223630SN/A * neither the name of the copyright holders nor the names of its 233630SN/A * contributors may be used to endorse or promote products derived from 243630SN/A * this software without specific prior written permission. 253630SN/A * 263630SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 273630SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 283630SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 293630SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 303630SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 313630SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 323630SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 333630SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 343630SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 353630SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 363630SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 373630SN/A * 383630SN/A * Authors: Ali Saidi 393630SN/A * Gedare Bloom 403630SN/A */ 413630SN/A 423630SN/A#include "dev/arm/timer_a9global.hh" 433630SN/A 443630SN/A#include "base/intmath.hh" 457584SAli.Saidi@arm.com#include "base/trace.hh" 463630SN/A#include "debug/Checkpoint.hh" 473630SN/A#include "debug/Timer.hh" 483630SN/A#include "dev/arm/base_gic.hh" 497584SAli.Saidi@arm.com#include "mem/packet.hh" 507584SAli.Saidi@arm.com#include "mem/packet_access.hh" 513630SN/A 523630SN/AA9GlobalTimer::A9GlobalTimer(Params *p) 537584SAli.Saidi@arm.com : BasicPioDevice(p, 0x1C), gic(p->gic), 543630SN/A global_timer(name() + ".globaltimer", this, p->int_num) 553630SN/A{ 563630SN/A} 573630SN/A 587584SAli.Saidi@arm.comA9GlobalTimer::Timer::Timer(std::string __name, A9GlobalTimer *_parent, 593630SN/A int int_num) 603630SN/A : _name(__name), parent(_parent), intNum(int_num), control(0x0), 613630SN/A rawInt(false), pendingInt(false), autoIncValue(0x0), cmpValEvent(this) 623630SN/A{ 633630SN/A} 643630SN/A 657584SAli.Saidi@arm.comTick 663630SN/AA9GlobalTimer::read(PacketPtr pkt) 673630SN/A{ 683630SN/A assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 693630SN/A assert(pkt->getSize() == 4); 703630SN/A Addr daddr = pkt->getAddr() - pioAddr; 713630SN/A 727584SAli.Saidi@arm.com if (daddr < Timer::Size) 733630SN/A global_timer.read(pkt, daddr); 743630SN/A else 753630SN/A panic("Tried to read A9GlobalTimer at offset %#x that doesn't exist\n", 763630SN/A daddr); 773630SN/A pkt->makeAtomicResponse(); 783630SN/A return pioDelay; 793630SN/A} 803630SN/A 813630SN/Auint64_t 823630SN/AA9GlobalTimer::Timer::getTimeCounterFromTicks(Tick ticks) 833630SN/A{ 843630SN/A return ticks / parent->clockPeriod() / (control.prescalar + 1) - 1; 853630SN/A} 863812SN/A 873630SN/Avoid 883630SN/AA9GlobalTimer::Timer::read(PacketPtr pkt, Addr daddr) 893630SN/A{ 903630SN/A DPRINTF(Timer, "Reading from A9GlobalTimer at offset: %#x\n", daddr); 913630SN/A uint64_t time; 923630SN/A 933630SN/A switch(daddr) { 943630SN/A case CounterRegLow32: 953630SN/A time = getTimeCounterFromTicks(curTick()); 963630SN/A DPRINTF(Timer, "-- returning lower 32-bits of counter: %u\n", time); 973630SN/A pkt->setLE<uint32_t>(time); 983630SN/A break; 993630SN/A case CounterRegHigh32: 1003630SN/A time = getTimeCounterFromTicks(curTick()); 1013630SN/A time >>= 32; 1023630SN/A DPRINTF(Timer, "-- returning upper 32-bits of counter: %u\n", time); 1033630SN/A pkt->setLE<uint32_t>(time); 1043630SN/A break; 1053630SN/A case ControlReg: 1065834SN/A pkt->setLE<uint32_t>(control); 1075834SN/A break; 1085834SN/A case IntStatusReg: 1095834SN/A pkt->setLE<uint32_t>(rawInt); 1105834SN/A break; 1115834SN/A case CmpValRegLow32: 1125834SN/A DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n", 1135834SN/A cmpValEvent.when(), parent->clockPeriod(), control.prescalar); 1145834SN/A if (cmpValEvent.scheduled()) { 1155834SN/A time = getTimeCounterFromTicks(cmpValEvent.when() - curTick()); 1165834SN/A } else { 1173630SN/A time = 0; 1183630SN/A } 1197584SAli.Saidi@arm.com DPRINTF(Timer, "-- returning lower 32-bits of comparator: %u\n", time); 120 pkt->setLE<uint32_t>(time); 121 break; 122 case CmpValRegHigh32: 123 DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n", 124 cmpValEvent.when(), parent->clockPeriod(), control.prescalar); 125 if (cmpValEvent.scheduled()) { 126 time = getTimeCounterFromTicks(cmpValEvent.when() - curTick()); 127 time >>= 32; 128 } else { 129 time = 0; 130 } 131 DPRINTF(Timer, "-- returning upper 32-bits of comparator: %u\n", time); 132 pkt->setLE<uint32_t>(time); 133 break; 134 case AutoIncrementReg: 135 pkt->setLE<uint32_t>(autoIncValue); 136 break; 137 default: 138 panic("Tried to read A9GlobalTimer at offset %#x\n", daddr); 139 break; 140 } 141 DPRINTF(Timer, "Reading %#x from A9GlobalTimer at offset: %#x\n", 142 pkt->getLE<uint32_t>(), daddr); 143} 144 145Tick 146A9GlobalTimer::write(PacketPtr pkt) 147{ 148 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 149 assert(pkt->getSize() == 4); 150 Addr daddr = pkt->getAddr() - pioAddr; 151 DPRINTF(Timer, "Writing to A9GlobalTimer at offset: %#x\n", daddr); 152 153 warn_once("A9 Global Timer doesn't support banked per-cpu registers\n"); 154 155 if (daddr < Timer::Size) 156 global_timer.write(pkt, daddr); 157 else 158 panic("Tried to write A9GlobalTimer at offset %#x doesn't exist\n", 159 daddr); 160 pkt->makeAtomicResponse(); 161 return pioDelay; 162} 163 164void 165A9GlobalTimer::Timer::write(PacketPtr pkt, Addr daddr) 166{ 167 DPRINTF(Timer, "Writing %#x to A9GlobalTimer at offset: %#x\n", 168 pkt->getLE<uint32_t>(), daddr); 169 switch (daddr) { 170 case CounterRegLow32: 171 case CounterRegHigh32: 172 DPRINTF(Timer, "Ignoring unsupported write to Global Timer Counter\n"); 173 break; 174 case ControlReg: 175 bool old_enable; 176 bool old_cmpEnable; 177 old_enable = control.enable; 178 old_cmpEnable = control.cmpEnable; 179 control = pkt->getLE<uint32_t>(); 180 if ((old_enable == 0) && control.enable) 181 restartCounter(); 182 if ((old_cmpEnable == 0) && control.cmpEnable) 183 restartCounter(); 184 break; 185 case IntStatusReg: 186 /* TODO: should check that '1' was written. */ 187 rawInt = false; 188 if (pendingInt) { 189 pendingInt = false; 190 DPRINTF(Timer, "Clearing interrupt\n"); 191 parent->gic->clearInt(intNum); 192 } 193 break; 194 case CmpValRegLow32: 195 cmpVal &= 0xFFFFFFFF00000000ULL; 196 cmpVal |= (uint64_t)pkt->getLE<uint32_t>(); 197 break; 198 case CmpValRegHigh32: 199 cmpVal &= 0x00000000FFFFFFFFULL; 200 cmpVal |= ((uint64_t)pkt->getLE<uint32_t>() << 32); 201 break; 202 case AutoIncrementReg: 203 autoIncValue = pkt->getLE<uint32_t>(); 204 break; 205 default: 206 panic("Tried to write A9GlobalTimer at offset %#x\n", daddr); 207 break; 208 } 209} 210 211void 212A9GlobalTimer::Timer::restartCounter() 213{ 214 if (!control.enable) 215 return; 216 DPRINTF(Timer, "Restarting counter with value %#x\n", cmpVal); 217 218 Tick time = parent->clockPeriod() * (control.prescalar + 1) * (cmpVal + 1); 219 220 if (time < curTick()) { 221 DPRINTF(Timer, "-- Event time %#x < curTick %#x\n", time, curTick()); 222 return; 223 } 224 if (cmpValEvent.scheduled()) { 225 DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 226 parent->deschedule(cmpValEvent); 227 } 228 parent->schedule(cmpValEvent, time); 229 DPRINTF(Timer, "-- Scheduling new event for: %d\n", time); 230} 231 232void 233A9GlobalTimer::Timer::counterAtCmpVal() 234{ 235 if (!control.enable) 236 return; 237 238 DPRINTF(Timer, "Counter reached cmpVal\n"); 239 240 rawInt = true; 241 bool old_pending = pendingInt; 242 if (control.intEnable) 243 pendingInt = true; 244 if (pendingInt && !old_pending) { 245 DPRINTF(Timer, "-- Causing interrupt\n"); 246 parent->gic->sendPPInt(intNum, 0); /* FIXME: cpuNum */ 247 } 248 249 if (control.autoIncrement == 0) // one-shot 250 return; 251 252 cmpVal += (uint64_t)autoIncValue; 253 restartCounter(); 254} 255 256void 257A9GlobalTimer::Timer::serialize(CheckpointOut &cp) const 258{ 259 DPRINTF(Checkpoint, "Serializing Arm A9GlobalTimer\n"); 260 261 uint32_t control_serial = control; 262 SERIALIZE_SCALAR(control_serial); 263 264 SERIALIZE_SCALAR(rawInt); 265 SERIALIZE_SCALAR(pendingInt); 266 SERIALIZE_SCALAR(cmpVal); 267 SERIALIZE_SCALAR(autoIncValue); 268 269 bool is_in_event = cmpValEvent.scheduled(); 270 SERIALIZE_SCALAR(is_in_event); 271 272 Tick event_time; 273 if (is_in_event){ 274 event_time = cmpValEvent.when(); 275 SERIALIZE_SCALAR(event_time); 276 } 277} 278 279void 280A9GlobalTimer::Timer::unserialize(CheckpointIn &cp) 281{ 282 DPRINTF(Checkpoint, "Unserializing Arm A9GlobalTimer\n"); 283 284 uint32_t control_serial; 285 UNSERIALIZE_SCALAR(control_serial); 286 control = control_serial; 287 288 UNSERIALIZE_SCALAR(rawInt); 289 UNSERIALIZE_SCALAR(pendingInt); 290 UNSERIALIZE_SCALAR(cmpVal); 291 UNSERIALIZE_SCALAR(autoIncValue); 292 293 bool is_in_event; 294 UNSERIALIZE_SCALAR(is_in_event); 295 296 Tick event_time; 297 if (is_in_event){ 298 UNSERIALIZE_SCALAR(event_time); 299 parent->schedule(cmpValEvent, event_time); 300 } 301} 302 303void 304A9GlobalTimer::serialize(CheckpointOut &cp) const 305{ 306 global_timer.serialize(cp); 307} 308 309void 310A9GlobalTimer::unserialize(CheckpointIn &cp) 311{ 312 global_timer.unserialize(cp); 313} 314 315A9GlobalTimer * 316A9GlobalTimerParams::create() 317{ 318 return new A9GlobalTimer(this); 319} 320