rtc_pl031.cc revision 8245
17160Sgblack@eecs.umich.edu/* 27160Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited 37160Sgblack@eecs.umich.edu * All rights reserved 47160Sgblack@eecs.umich.edu * 57160Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67160Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77160Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87160Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97160Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107160Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117160Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127160Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137160Sgblack@eecs.umich.edu * 147160Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 157160Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 167160Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 177160Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 187160Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 197160Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 207160Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 217160Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 227160Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 237160Sgblack@eecs.umich.edu * this software without specific prior written permission. 247160Sgblack@eecs.umich.edu * 257160Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267160Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277160Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287160Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297160Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307160Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317160Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327160Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337160Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347160Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357160Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367160Sgblack@eecs.umich.edu * 377160Sgblack@eecs.umich.edu * Authors: Ali Saidi 387160Sgblack@eecs.umich.edu */ 397160Sgblack@eecs.umich.edu 407160Sgblack@eecs.umich.edu#include "base/intmath.hh" 417160Sgblack@eecs.umich.edu#include "base/trace.hh" 427160Sgblack@eecs.umich.edu#include "debug/Checkpoint.hh" 437160Sgblack@eecs.umich.edu#include "debug/Timer.hh" 447160Sgblack@eecs.umich.edu#include "dev/arm/gic.hh" 457160Sgblack@eecs.umich.edu#include "dev/arm/timer_sp804.hh" 467160Sgblack@eecs.umich.edu#include "mem/packet.hh" 478302SAli.Saidi@ARM.com#include "mem/packet_access.hh" 487160Sgblack@eecs.umich.edu 497160Sgblack@eecs.umich.eduusing namespace AmbaDev; 507160Sgblack@eecs.umich.edu 517160Sgblack@eecs.umich.eduSp804::Sp804(Params *p) 527160Sgblack@eecs.umich.edu : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0), 537160Sgblack@eecs.umich.edu timer1(name() + ".timer1", this, p->int_num1, p->clock1) 547160Sgblack@eecs.umich.edu{ 558301SAli.Saidi@ARM.com pioSize = 0xfff; 567160Sgblack@eecs.umich.edu} 577160Sgblack@eecs.umich.edu 587160Sgblack@eecs.umich.eduSp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock) 597160Sgblack@eecs.umich.edu : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20), 607160Sgblack@eecs.umich.edu rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this) 617160Sgblack@eecs.umich.edu{ 627160Sgblack@eecs.umich.edu} 637160Sgblack@eecs.umich.edu 647160Sgblack@eecs.umich.edu 657160Sgblack@eecs.umich.eduTick 667160Sgblack@eecs.umich.eduSp804::read(PacketPtr pkt) 677160Sgblack@eecs.umich.edu{ 687160Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 697160Sgblack@eecs.umich.edu assert(pkt->getSize() == 4); 707160Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 717160Sgblack@eecs.umich.edu pkt->allocate(); 727160Sgblack@eecs.umich.edu DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr); 737160Sgblack@eecs.umich.edu 747160Sgblack@eecs.umich.edu if (daddr < Timer::Size) 757160Sgblack@eecs.umich.edu timer0.read(pkt, daddr); 767160Sgblack@eecs.umich.edu else if ((daddr - Timer::Size) < Timer::Size) 777160Sgblack@eecs.umich.edu timer1.read(pkt, daddr - Timer::Size); 787160Sgblack@eecs.umich.edu else if (!readId(pkt, ambaId, pioAddr)) 797160Sgblack@eecs.umich.edu panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr); 807160Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 817160Sgblack@eecs.umich.edu return pioDelay; 827160Sgblack@eecs.umich.edu} 837160Sgblack@eecs.umich.edu 847160Sgblack@eecs.umich.edu 857160Sgblack@eecs.umich.eduvoid 867162Sgblack@eecs.umich.eduSp804::Timer::read(PacketPtr pkt, Addr daddr) 877160Sgblack@eecs.umich.edu{ 887160Sgblack@eecs.umich.edu DPRINTF(Timer, "Reading from Timer at offset: %#x\n", daddr); 897160Sgblack@eecs.umich.edu 907160Sgblack@eecs.umich.edu switch(daddr) { 917760SGiacomo.Gabrielli@arm.com case LoadReg: 927760SGiacomo.Gabrielli@arm.com pkt->set<uint32_t>(loadValue); 937160Sgblack@eecs.umich.edu break; 947160Sgblack@eecs.umich.edu case CurrentReg: 957160Sgblack@eecs.umich.edu DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n", 967760SGiacomo.Gabrielli@arm.com zeroEvent.when(), clock, control.timerPrescale); 977760SGiacomo.Gabrielli@arm.com Tick time; 987160Sgblack@eecs.umich.edu time = zeroEvent.when() - curTick(); 997160Sgblack@eecs.umich.edu time = time / clock / power(16, control.timerPrescale); 1007160Sgblack@eecs.umich.edu DPRINTF(Timer, "-- returning counter at %d\n", time); 1017160Sgblack@eecs.umich.edu pkt->set<uint32_t>(time); 1027160Sgblack@eecs.umich.edu break; 1037160Sgblack@eecs.umich.edu case ControlReg: 1047160Sgblack@eecs.umich.edu pkt->set<uint32_t>(control); 1057160Sgblack@eecs.umich.edu break; 1067160Sgblack@eecs.umich.edu case RawISR: 1077160Sgblack@eecs.umich.edu pkt->set<uint32_t>(rawInt); 1087160Sgblack@eecs.umich.edu break; 1097160Sgblack@eecs.umich.edu case MaskedISR: 1107160Sgblack@eecs.umich.edu pkt->set<uint32_t>(pendingInt); 1117160Sgblack@eecs.umich.edu break; 1127160Sgblack@eecs.umich.edu case BGLoad: 1137160Sgblack@eecs.umich.edu pkt->set<uint32_t>(loadValue); 1147160Sgblack@eecs.umich.edu break; 1157160Sgblack@eecs.umich.edu default: 1167160Sgblack@eecs.umich.edu panic("Tried to read SP804 timer at offset %#x\n", daddr); 1177160Sgblack@eecs.umich.edu break; 1187160Sgblack@eecs.umich.edu } 1197160Sgblack@eecs.umich.edu} 1207160Sgblack@eecs.umich.edu 1217160Sgblack@eecs.umich.eduTick 1227160Sgblack@eecs.umich.eduSp804::write(PacketPtr pkt) 1237160Sgblack@eecs.umich.edu{ 1247160Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1257160Sgblack@eecs.umich.edu assert(pkt->getSize() == 4); 1267160Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - pioAddr; 1277160Sgblack@eecs.umich.edu pkt->allocate(); 1287160Sgblack@eecs.umich.edu DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr); 1297160Sgblack@eecs.umich.edu 1307160Sgblack@eecs.umich.edu if (daddr < Timer::Size) 1317160Sgblack@eecs.umich.edu timer0.write(pkt, daddr); 1327160Sgblack@eecs.umich.edu else if ((daddr - Timer::Size) < Timer::Size) 1337160Sgblack@eecs.umich.edu timer1.write(pkt, daddr - Timer::Size); 1347160Sgblack@eecs.umich.edu else if (!readId(pkt, ambaId, pioAddr)) 1357160Sgblack@eecs.umich.edu panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr); 1367160Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 1377160Sgblack@eecs.umich.edu return pioDelay; 1387196Sgblack@eecs.umich.edu} 1397160Sgblack@eecs.umich.edu 1407196Sgblack@eecs.umich.eduvoid 1417196Sgblack@eecs.umich.eduSp804::Timer::write(PacketPtr pkt, Addr daddr) 1427160Sgblack@eecs.umich.edu{ 1437160Sgblack@eecs.umich.edu DPRINTF(Timer, "Writing to Timer at offset: %#x\n", daddr); 1447160Sgblack@eecs.umich.edu switch (daddr) { 1457196Sgblack@eecs.umich.edu case LoadReg: 1467160Sgblack@eecs.umich.edu loadValue = pkt->get<uint32_t>(); 1477196Sgblack@eecs.umich.edu restartCounter(loadValue); 1487196Sgblack@eecs.umich.edu break; 1497160Sgblack@eecs.umich.edu case CurrentReg: 1507160Sgblack@eecs.umich.edu // Spec says this value can't be written, but linux writes it anyway 1517160Sgblack@eecs.umich.edu break; 1527196Sgblack@eecs.umich.edu case ControlReg: 1537160Sgblack@eecs.umich.edu bool old_enable; 1547196Sgblack@eecs.umich.edu old_enable = control.timerEnable; 1557196Sgblack@eecs.umich.edu control = pkt->get<uint32_t>(); 1567160Sgblack@eecs.umich.edu if ((old_enable == 0) && control.timerEnable) 1577160Sgblack@eecs.umich.edu restartCounter(loadValue); 1587160Sgblack@eecs.umich.edu break; 1597196Sgblack@eecs.umich.edu case IntClear: 1607160Sgblack@eecs.umich.edu rawInt = false; 1617196Sgblack@eecs.umich.edu if (pendingInt) { 1627196Sgblack@eecs.umich.edu pendingInt = false; 1637160Sgblack@eecs.umich.edu DPRINTF(Timer, "Clearing interrupt\n"); 1647160Sgblack@eecs.umich.edu parent->gic->clearInt(intNum); 1657160Sgblack@eecs.umich.edu } 1667160Sgblack@eecs.umich.edu break; 1677160Sgblack@eecs.umich.edu case BGLoad: 1687160Sgblack@eecs.umich.edu loadValue = pkt->get<uint32_t>(); 1697160Sgblack@eecs.umich.edu break; 1707228Sgblack@eecs.umich.edu default: 1717228Sgblack@eecs.umich.edu panic("Tried to write SP804 timer at offset %#x\n", daddr); 1727160Sgblack@eecs.umich.edu break; 1737160Sgblack@eecs.umich.edu } 1747160Sgblack@eecs.umich.edu} 1757160Sgblack@eecs.umich.edu 1767160Sgblack@eecs.umich.eduvoid 1777160Sgblack@eecs.umich.eduSp804::Timer::restartCounter(uint32_t val) 1787160Sgblack@eecs.umich.edu{ 1797228Sgblack@eecs.umich.edu DPRINTF(Timer, "Resetting counter with value %#x\n", val); 1807228Sgblack@eecs.umich.edu if (!control.timerEnable) 1817160Sgblack@eecs.umich.edu return; 1827160Sgblack@eecs.umich.edu 1837160Sgblack@eecs.umich.edu Tick time = clock * power(16, control.timerPrescale); 1847160Sgblack@eecs.umich.edu if (control.timerSize) 1857160Sgblack@eecs.umich.edu time *= val; 1867160Sgblack@eecs.umich.edu else 1877160Sgblack@eecs.umich.edu time *= bits(val,15,0); 1887160Sgblack@eecs.umich.edu 1897160Sgblack@eecs.umich.edu if (zeroEvent.scheduled()) { 1907160Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 1917160Sgblack@eecs.umich.edu parent->deschedule(zeroEvent); 1927160Sgblack@eecs.umich.edu } 1937160Sgblack@eecs.umich.edu parent->schedule(zeroEvent, curTick() + time); 1947160Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time); 1957160Sgblack@eecs.umich.edu} 1967160Sgblack@eecs.umich.edu 1977160Sgblack@eecs.umich.eduvoid 1987160Sgblack@eecs.umich.eduSp804::Timer::counterAtZero() 1997160Sgblack@eecs.umich.edu{ 2007160Sgblack@eecs.umich.edu if (!control.timerEnable) 2017160Sgblack@eecs.umich.edu return; 2027160Sgblack@eecs.umich.edu 2037160Sgblack@eecs.umich.edu DPRINTF(Timer, "Counter reached zero\n"); 2047160Sgblack@eecs.umich.edu 2057160Sgblack@eecs.umich.edu rawInt = true; 2067160Sgblack@eecs.umich.edu bool old_pending = pendingInt; 2077160Sgblack@eecs.umich.edu if (control.intEnable) 2087160Sgblack@eecs.umich.edu pendingInt = true; 2097160Sgblack@eecs.umich.edu if (pendingInt && ~old_pending) { 2107160Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Causing interrupt\n"); 2117160Sgblack@eecs.umich.edu parent->gic->sendInt(intNum); 2127160Sgblack@eecs.umich.edu } 2137160Sgblack@eecs.umich.edu 2147160Sgblack@eecs.umich.edu if (control.oneShot) 2157160Sgblack@eecs.umich.edu return; 2167160Sgblack@eecs.umich.edu 2177160Sgblack@eecs.umich.edu // Free-running 2187160Sgblack@eecs.umich.edu if (control.timerMode == 0) 2197160Sgblack@eecs.umich.edu restartCounter(0xffffffff); 2207160Sgblack@eecs.umich.edu else 2217160Sgblack@eecs.umich.edu restartCounter(loadValue); 2227160Sgblack@eecs.umich.edu} 2237160Sgblack@eecs.umich.edu 2247160Sgblack@eecs.umich.eduvoid 2257160Sgblack@eecs.umich.eduSp804::Timer::serialize(std::ostream &os) 2267160Sgblack@eecs.umich.edu{ 2277160Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "Serializing Arm Sp804\n"); 2287160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(intNum); 2297160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(clock); 2307160Sgblack@eecs.umich.edu 2317160Sgblack@eecs.umich.edu uint32_t control_serial = control; 2327160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(control_serial); 2337160Sgblack@eecs.umich.edu 2347160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(rawInt); 2357160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(pendingInt); 2367160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(loadValue); 2377160Sgblack@eecs.umich.edu 2387196Sgblack@eecs.umich.edu bool is_in_event = zeroEvent.scheduled(); 2397196Sgblack@eecs.umich.edu SERIALIZE_SCALAR(is_in_event); 2407196Sgblack@eecs.umich.edu 2417160Sgblack@eecs.umich.edu Tick event_time; 2427160Sgblack@eecs.umich.edu if (is_in_event){ 2437160Sgblack@eecs.umich.edu event_time = zeroEvent.when(); 2447160Sgblack@eecs.umich.edu SERIALIZE_SCALAR(event_time); 2457196Sgblack@eecs.umich.edu } 2467196Sgblack@eecs.umich.edu} 2477196Sgblack@eecs.umich.edu 2487160Sgblack@eecs.umich.eduvoid 2497160Sgblack@eecs.umich.eduSp804::Timer::unserialize(Checkpoint *cp, const std::string §ion) 2507160Sgblack@eecs.umich.edu{ 2517160Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "Unserializing Arm Sp804\n"); 2527160Sgblack@eecs.umich.edu 2537160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(intNum); 2547160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(clock); 2557228Sgblack@eecs.umich.edu 2567228Sgblack@eecs.umich.edu uint32_t control_serial; 2577160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(control_serial); 2587160Sgblack@eecs.umich.edu control = control_serial; 2597160Sgblack@eecs.umich.edu 2607160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(rawInt); 2617160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(pendingInt); 2627160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(loadValue); 2637160Sgblack@eecs.umich.edu 2647228Sgblack@eecs.umich.edu bool is_in_event; 2657228Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(is_in_event); 2667160Sgblack@eecs.umich.edu 2677160Sgblack@eecs.umich.edu Tick event_time; 2687160Sgblack@eecs.umich.edu if (is_in_event){ 2697160Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(event_time); 2707160Sgblack@eecs.umich.edu parent->schedule(zeroEvent, event_time); 2717160Sgblack@eecs.umich.edu } 2727160Sgblack@eecs.umich.edu} 2737160Sgblack@eecs.umich.edu 2747160Sgblack@eecs.umich.edu 2757160Sgblack@eecs.umich.edu 2767160Sgblack@eecs.umich.eduvoid 2777160Sgblack@eecs.umich.eduSp804::serialize(std::ostream &os) 2787160Sgblack@eecs.umich.edu{ 2797160Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.timer0", name())); 2807160Sgblack@eecs.umich.edu timer0.serialize(os); 2817160Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.timer1", name())); 2827160Sgblack@eecs.umich.edu timer1.serialize(os); 2837160Sgblack@eecs.umich.edu} 2847160Sgblack@eecs.umich.edu 2857160Sgblack@eecs.umich.eduvoid 2867160Sgblack@eecs.umich.eduSp804::unserialize(Checkpoint *cp, const std::string §ion) 2877160Sgblack@eecs.umich.edu{ 2887160Sgblack@eecs.umich.edu timer0.unserialize(cp, csprintf("%s.timer0", section)); 2897229Sgblack@eecs.umich.edu timer1.unserialize(cp, csprintf("%s.timer1", section)); 2907229Sgblack@eecs.umich.edu} 2917160Sgblack@eecs.umich.edu 2927160Sgblack@eecs.umich.eduSp804 * 2937160Sgblack@eecs.umich.eduSp804Params::create() 2947229Sgblack@eecs.umich.edu{ 2957229Sgblack@eecs.umich.edu return new Sp804(this); 2967160Sgblack@eecs.umich.edu} 2977160Sgblack@eecs.umich.edu