rtc_pl031.cc revision 8904
17584SN/A/* 28869SAli.Saidi@ARM.com * Copyright (c) 2010-2012 ARM Limited 37584SN/A * All rights reserved 47584SN/A * 57584SN/A * The license below extends only to copyright in the software and shall 67584SN/A * not be construed as granting a license to any other intellectual 77584SN/A * property including but not limited to intellectual property relating 87584SN/A * to a hardware implementation of the functionality of the software 97584SN/A * licensed hereunder. You may use the software subject to the license 107584SN/A * terms below provided that you ensure that this notice is replicated 117584SN/A * unmodified and in its entirety in all distributions of the software, 127584SN/A * modified or unmodified, in source code or in binary form. 137584SN/A * 147584SN/A * Redistribution and use in source and binary forms, with or without 157584SN/A * modification, are permitted provided that the following conditions are 167584SN/A * met: redistributions of source code must retain the above copyright 177584SN/A * notice, this list of conditions and the following disclaimer; 187584SN/A * redistributions in binary form must reproduce the above copyright 197584SN/A * notice, this list of conditions and the following disclaimer in the 207584SN/A * documentation and/or other materials provided with the distribution; 217584SN/A * neither the name of the copyright holders nor the names of its 227584SN/A * contributors may be used to endorse or promote products derived from 237584SN/A * this software without specific prior written permission. 247584SN/A * 257584SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267584SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277584SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287584SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297584SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307584SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317584SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327584SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337584SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347584SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357584SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367584SN/A * 377584SN/A * Authors: Ali Saidi 387584SN/A */ 397584SN/A 407584SN/A#include "base/intmath.hh" 418869SAli.Saidi@ARM.com#include "base/time.hh" 427584SN/A#include "base/trace.hh" 438245SN/A#include "debug/Checkpoint.hh" 448245SN/A#include "debug/Timer.hh" 458869SAli.Saidi@ARM.com#include "dev/arm/amba_device.hh" 468869SAli.Saidi@ARM.com#include "dev/arm/rtc_pl031.hh" 478869SAli.Saidi@ARM.com#include "dev/mc146818.hh" 487584SN/A#include "mem/packet.hh" 497584SN/A#include "mem/packet_access.hh" 507584SN/A 517587SN/Ausing namespace AmbaDev; 527587SN/A 538869SAli.Saidi@ARM.comPL031::PL031(Params *p) 548869SAli.Saidi@ARM.com : AmbaIntDevice(p), timeVal(mkutctime(&p->time)), lastWrittenTick(0), 558904SAli.Saidi@ARM.com loadVal(0), matchVal(0), rawInt(false), maskInt(false), 568904SAli.Saidi@ARM.com pendingInt(false), matchEvent(this) 577584SN/A{ 587584SN/A pioSize = 0xfff; 597584SN/A} 607584SN/A 617584SN/A 627584SN/ATick 638869SAli.Saidi@ARM.comPL031::read(PacketPtr pkt) 647584SN/A{ 657584SN/A assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 667584SN/A assert(pkt->getSize() == 4); 677584SN/A Addr daddr = pkt->getAddr() - pioAddr; 687584SN/A pkt->allocate(); 698869SAli.Saidi@ARM.com uint32_t data; 707584SN/A 718869SAli.Saidi@ARM.com DPRINTF(Timer, "Reading from RTC at offset: %#x\n", daddr); 728869SAli.Saidi@ARM.com 738869SAli.Saidi@ARM.com switch (daddr) { 748869SAli.Saidi@ARM.com case DataReg: 758869SAli.Saidi@ARM.com data = timeVal + ((curTick() - lastWrittenTick) / SimClock::Int::s); 768869SAli.Saidi@ARM.com break; 778869SAli.Saidi@ARM.com case MatchReg: 788869SAli.Saidi@ARM.com data = matchVal; 798869SAli.Saidi@ARM.com break; 808869SAli.Saidi@ARM.com case LoadReg: 818869SAli.Saidi@ARM.com data = loadVal; 828869SAli.Saidi@ARM.com break; 838869SAli.Saidi@ARM.com case ControlReg: 848869SAli.Saidi@ARM.com data = 1; // Always enabled otherwise there is no point 858869SAli.Saidi@ARM.com break; 868869SAli.Saidi@ARM.com case IntMask: 878869SAli.Saidi@ARM.com data = maskInt; 888869SAli.Saidi@ARM.com break; 898869SAli.Saidi@ARM.com case RawISR: 908869SAli.Saidi@ARM.com data = rawInt; 918869SAli.Saidi@ARM.com break; 928869SAli.Saidi@ARM.com case MaskedISR: 938869SAli.Saidi@ARM.com data = pendingInt; 948869SAli.Saidi@ARM.com break; 958869SAli.Saidi@ARM.com default: 968869SAli.Saidi@ARM.com if (AmbaDev::readId(pkt, ambaId, pioAddr)) { 978869SAli.Saidi@ARM.com // Hack for variable sized access 988869SAli.Saidi@ARM.com data = pkt->get<uint32_t>(); 998869SAli.Saidi@ARM.com break; 1008869SAli.Saidi@ARM.com } 1018869SAli.Saidi@ARM.com panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr); 1028869SAli.Saidi@ARM.com break; 1038869SAli.Saidi@ARM.com } 1048869SAli.Saidi@ARM.com 1058869SAli.Saidi@ARM.com switch(pkt->getSize()) { 1068869SAli.Saidi@ARM.com case 1: 1078869SAli.Saidi@ARM.com pkt->set<uint8_t>(data); 1088869SAli.Saidi@ARM.com break; 1098869SAli.Saidi@ARM.com case 2: 1108869SAli.Saidi@ARM.com pkt->set<uint16_t>(data); 1118869SAli.Saidi@ARM.com break; 1128869SAli.Saidi@ARM.com case 4: 1138869SAli.Saidi@ARM.com pkt->set<uint32_t>(data); 1148869SAli.Saidi@ARM.com break; 1158869SAli.Saidi@ARM.com default: 1168869SAli.Saidi@ARM.com panic("Uart read size too big?\n"); 1178869SAli.Saidi@ARM.com break; 1188869SAli.Saidi@ARM.com } 1198869SAli.Saidi@ARM.com 1208869SAli.Saidi@ARM.com 1217584SN/A pkt->makeAtomicResponse(); 1227584SN/A return pioDelay; 1237584SN/A} 1247584SN/A 1257584SN/ATick 1268869SAli.Saidi@ARM.comPL031::write(PacketPtr pkt) 1277584SN/A{ 1287584SN/A assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1297584SN/A assert(pkt->getSize() == 4); 1307584SN/A Addr daddr = pkt->getAddr() - pioAddr; 1317584SN/A pkt->allocate(); 1328869SAli.Saidi@ARM.com DPRINTF(Timer, "Writing to RTC at offset: %#x\n", daddr); 1337584SN/A 1348869SAli.Saidi@ARM.com switch (daddr) { 1358869SAli.Saidi@ARM.com case DataReg: 1368869SAli.Saidi@ARM.com break; 1378869SAli.Saidi@ARM.com case MatchReg: 1388869SAli.Saidi@ARM.com matchVal = pkt->get<uint32_t>(); 1398869SAli.Saidi@ARM.com resyncMatch(); 1408869SAli.Saidi@ARM.com break; 1418869SAli.Saidi@ARM.com case LoadReg: 1428869SAli.Saidi@ARM.com lastWrittenTick = curTick(); 1438869SAli.Saidi@ARM.com timeVal = pkt->get<uint32_t>(); 1448869SAli.Saidi@ARM.com loadVal = timeVal; 1458869SAli.Saidi@ARM.com resyncMatch(); 1468869SAli.Saidi@ARM.com break; 1478869SAli.Saidi@ARM.com case ControlReg: 1488869SAli.Saidi@ARM.com break; // Can't stop when started 1498869SAli.Saidi@ARM.com case IntMask: 1508869SAli.Saidi@ARM.com maskInt = pkt->get<uint32_t>(); 1518869SAli.Saidi@ARM.com break; 1528869SAli.Saidi@ARM.com case IntClear: 1538869SAli.Saidi@ARM.com if (pkt->get<uint32_t>()) { 1548869SAli.Saidi@ARM.com rawInt = false; 1558869SAli.Saidi@ARM.com pendingInt = false; 1568869SAli.Saidi@ARM.com } 1578869SAli.Saidi@ARM.com break; 1588869SAli.Saidi@ARM.com default: 1598869SAli.Saidi@ARM.com if (AmbaDev::readId(pkt, ambaId, pioAddr)) 1608869SAli.Saidi@ARM.com break; 1618869SAli.Saidi@ARM.com panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr); 1628869SAli.Saidi@ARM.com break; 1638869SAli.Saidi@ARM.com } 1648869SAli.Saidi@ARM.com 1657584SN/A pkt->makeAtomicResponse(); 1667584SN/A return pioDelay; 1677584SN/A} 1687584SN/A 1697584SN/Avoid 1708869SAli.Saidi@ARM.comPL031::resyncMatch() 1717584SN/A{ 1728869SAli.Saidi@ARM.com DPRINTF(Timer, "Setting up new match event match=%d time=%d\n", matchVal, 1738869SAli.Saidi@ARM.com timeVal); 1748869SAli.Saidi@ARM.com 1758869SAli.Saidi@ARM.com uint32_t seconds_until = matchVal - timeVal; 1768869SAli.Saidi@ARM.com Tick ticks_until = SimClock::Int::s * seconds_until; 1778869SAli.Saidi@ARM.com 1788869SAli.Saidi@ARM.com if (matchEvent.scheduled()) { 1798869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 1808869SAli.Saidi@ARM.com deschedule(matchEvent); 1818869SAli.Saidi@ARM.com } 1828869SAli.Saidi@ARM.com schedule(matchEvent, curTick() + ticks_until); 1838869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + ticks_until); 1848869SAli.Saidi@ARM.com} 1858869SAli.Saidi@ARM.com 1868869SAli.Saidi@ARM.comvoid 1878869SAli.Saidi@ARM.comPL031::counterMatch() 1888869SAli.Saidi@ARM.com{ 1898869SAli.Saidi@ARM.com DPRINTF(Timer, "Counter reached zero\n"); 1908869SAli.Saidi@ARM.com 1918869SAli.Saidi@ARM.com rawInt = true; 1928869SAli.Saidi@ARM.com bool old_pending = pendingInt; 1938869SAli.Saidi@ARM.com pendingInt = maskInt & rawInt; 1948869SAli.Saidi@ARM.com if (pendingInt && ~old_pending) { 1958869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Causing interrupt\n"); 1968869SAli.Saidi@ARM.com gic->sendInt(intNum); 1977584SN/A } 1987584SN/A} 1997584SN/A 2007584SN/Avoid 2018869SAli.Saidi@ARM.comPL031::serialize(std::ostream &os) 2027584SN/A{ 2038869SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Serializing Arm PL031\n"); 2048869SAli.Saidi@ARM.com SERIALIZE_SCALAR(timeVal); 2058869SAli.Saidi@ARM.com SERIALIZE_SCALAR(lastWrittenTick); 2068869SAli.Saidi@ARM.com SERIALIZE_SCALAR(loadVal); 2078869SAli.Saidi@ARM.com SERIALIZE_SCALAR(matchVal); 2088869SAli.Saidi@ARM.com SERIALIZE_SCALAR(rawInt); 2098869SAli.Saidi@ARM.com SERIALIZE_SCALAR(maskInt); 2108869SAli.Saidi@ARM.com SERIALIZE_SCALAR(pendingInt); 2117584SN/A 2128869SAli.Saidi@ARM.com bool is_in_event = matchEvent.scheduled(); 2137733SN/A SERIALIZE_SCALAR(is_in_event); 2147733SN/A 2157733SN/A Tick event_time; 2167733SN/A if (is_in_event){ 2178869SAli.Saidi@ARM.com event_time = matchEvent.when(); 2187733SN/A SERIALIZE_SCALAR(event_time); 2197733SN/A } 2207733SN/A} 2217733SN/A 2227733SN/Avoid 2238869SAli.Saidi@ARM.comPL031::unserialize(Checkpoint *cp, const std::string §ion) 2247733SN/A{ 2258869SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PL031\n"); 2267733SN/A 2278869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(timeVal); 2288869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(lastWrittenTick); 2298869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(loadVal); 2308869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(matchVal); 2317733SN/A UNSERIALIZE_SCALAR(rawInt); 2328869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(maskInt); 2337733SN/A UNSERIALIZE_SCALAR(pendingInt); 2347733SN/A 2357733SN/A bool is_in_event; 2367733SN/A UNSERIALIZE_SCALAR(is_in_event); 2377733SN/A 2387733SN/A Tick event_time; 2397733SN/A if (is_in_event){ 2407733SN/A UNSERIALIZE_SCALAR(event_time); 2418869SAli.Saidi@ARM.com schedule(matchEvent, event_time); 2427733SN/A } 2437733SN/A} 2447733SN/A 2457733SN/A 2467584SN/A 2478869SAli.Saidi@ARM.comPL031 * 2488869SAli.Saidi@ARM.comPL031Params::create() 2497584SN/A{ 2508869SAli.Saidi@ARM.com return new PL031(this); 2517584SN/A} 252