rtc_pl031.cc revision 11793
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 4011793Sbrandon.potter@amd.com#include "dev/arm/rtc_pl031.hh" 4111793Sbrandon.potter@amd.com 427584SN/A#include "base/intmath.hh" 438869SAli.Saidi@ARM.com#include "base/time.hh" 447584SN/A#include "base/trace.hh" 458245SN/A#include "debug/Checkpoint.hh" 468245SN/A#include "debug/Timer.hh" 478869SAli.Saidi@ARM.com#include "dev/arm/amba_device.hh" 487584SN/A#include "mem/packet.hh" 497584SN/A#include "mem/packet_access.hh" 507584SN/A 518869SAli.Saidi@ARM.comPL031::PL031(Params *p) 529808Sstever@gmail.com : AmbaIntDevice(p, 0xfff), timeVal(mkutctime(&p->time)), 539808Sstever@gmail.com lastWrittenTick(0), loadVal(0), matchVal(0), 549808Sstever@gmail.com rawInt(false), maskInt(false), pendingInt(false), matchEvent(this) 557584SN/A{ 567584SN/A} 577584SN/A 587584SN/A 597584SN/ATick 608869SAli.Saidi@ARM.comPL031::read(PacketPtr pkt) 617584SN/A{ 627584SN/A assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 637584SN/A assert(pkt->getSize() == 4); 647584SN/A Addr daddr = pkt->getAddr() - pioAddr; 658869SAli.Saidi@ARM.com uint32_t data; 667584SN/A 678869SAli.Saidi@ARM.com DPRINTF(Timer, "Reading from RTC at offset: %#x\n", daddr); 688869SAli.Saidi@ARM.com 698869SAli.Saidi@ARM.com switch (daddr) { 708869SAli.Saidi@ARM.com case DataReg: 718869SAli.Saidi@ARM.com data = timeVal + ((curTick() - lastWrittenTick) / SimClock::Int::s); 728869SAli.Saidi@ARM.com break; 738869SAli.Saidi@ARM.com case MatchReg: 748869SAli.Saidi@ARM.com data = matchVal; 758869SAli.Saidi@ARM.com break; 768869SAli.Saidi@ARM.com case LoadReg: 778869SAli.Saidi@ARM.com data = loadVal; 788869SAli.Saidi@ARM.com break; 798869SAli.Saidi@ARM.com case ControlReg: 808869SAli.Saidi@ARM.com data = 1; // Always enabled otherwise there is no point 818869SAli.Saidi@ARM.com break; 828869SAli.Saidi@ARM.com case IntMask: 838869SAli.Saidi@ARM.com data = maskInt; 848869SAli.Saidi@ARM.com break; 858869SAli.Saidi@ARM.com case RawISR: 868869SAli.Saidi@ARM.com data = rawInt; 878869SAli.Saidi@ARM.com break; 888869SAli.Saidi@ARM.com case MaskedISR: 898869SAli.Saidi@ARM.com data = pendingInt; 908869SAli.Saidi@ARM.com break; 918869SAli.Saidi@ARM.com default: 929806Sstever@gmail.com if (readId(pkt, ambaId, pioAddr)) { 938869SAli.Saidi@ARM.com // Hack for variable sized access 948869SAli.Saidi@ARM.com data = pkt->get<uint32_t>(); 958869SAli.Saidi@ARM.com break; 968869SAli.Saidi@ARM.com } 978869SAli.Saidi@ARM.com panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr); 988869SAli.Saidi@ARM.com break; 998869SAli.Saidi@ARM.com } 1008869SAli.Saidi@ARM.com 1018869SAli.Saidi@ARM.com switch(pkt->getSize()) { 1028869SAli.Saidi@ARM.com case 1: 1038869SAli.Saidi@ARM.com pkt->set<uint8_t>(data); 1048869SAli.Saidi@ARM.com break; 1058869SAli.Saidi@ARM.com case 2: 1068869SAli.Saidi@ARM.com pkt->set<uint16_t>(data); 1078869SAli.Saidi@ARM.com break; 1088869SAli.Saidi@ARM.com case 4: 1098869SAli.Saidi@ARM.com pkt->set<uint32_t>(data); 1108869SAli.Saidi@ARM.com break; 1118869SAli.Saidi@ARM.com default: 1128869SAli.Saidi@ARM.com panic("Uart read size too big?\n"); 1138869SAli.Saidi@ARM.com break; 1148869SAli.Saidi@ARM.com } 1158869SAli.Saidi@ARM.com 1168869SAli.Saidi@ARM.com 1177584SN/A pkt->makeAtomicResponse(); 1187584SN/A return pioDelay; 1197584SN/A} 1207584SN/A 1217584SN/ATick 1228869SAli.Saidi@ARM.comPL031::write(PacketPtr pkt) 1237584SN/A{ 1247584SN/A assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1257584SN/A assert(pkt->getSize() == 4); 1267584SN/A Addr daddr = pkt->getAddr() - pioAddr; 1278869SAli.Saidi@ARM.com DPRINTF(Timer, "Writing to RTC at offset: %#x\n", daddr); 1287584SN/A 1298869SAli.Saidi@ARM.com switch (daddr) { 1308869SAli.Saidi@ARM.com case DataReg: 1318869SAli.Saidi@ARM.com break; 1328869SAli.Saidi@ARM.com case MatchReg: 1338869SAli.Saidi@ARM.com matchVal = pkt->get<uint32_t>(); 1348869SAli.Saidi@ARM.com resyncMatch(); 1358869SAli.Saidi@ARM.com break; 1368869SAli.Saidi@ARM.com case LoadReg: 1378869SAli.Saidi@ARM.com lastWrittenTick = curTick(); 1388869SAli.Saidi@ARM.com timeVal = pkt->get<uint32_t>(); 1398869SAli.Saidi@ARM.com loadVal = timeVal; 1408869SAli.Saidi@ARM.com resyncMatch(); 1418869SAli.Saidi@ARM.com break; 1428869SAli.Saidi@ARM.com case ControlReg: 1438869SAli.Saidi@ARM.com break; // Can't stop when started 1448869SAli.Saidi@ARM.com case IntMask: 1458869SAli.Saidi@ARM.com maskInt = pkt->get<uint32_t>(); 1468869SAli.Saidi@ARM.com break; 1478869SAli.Saidi@ARM.com case IntClear: 1488869SAli.Saidi@ARM.com if (pkt->get<uint32_t>()) { 1498869SAli.Saidi@ARM.com rawInt = false; 1508869SAli.Saidi@ARM.com pendingInt = false; 1518869SAli.Saidi@ARM.com } 1528869SAli.Saidi@ARM.com break; 1538869SAli.Saidi@ARM.com default: 1549806Sstever@gmail.com if (readId(pkt, ambaId, pioAddr)) 1558869SAli.Saidi@ARM.com break; 1568869SAli.Saidi@ARM.com panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr); 1578869SAli.Saidi@ARM.com break; 1588869SAli.Saidi@ARM.com } 1598869SAli.Saidi@ARM.com 1607584SN/A pkt->makeAtomicResponse(); 1617584SN/A return pioDelay; 1627584SN/A} 1637584SN/A 1647584SN/Avoid 1658869SAli.Saidi@ARM.comPL031::resyncMatch() 1667584SN/A{ 1678869SAli.Saidi@ARM.com DPRINTF(Timer, "Setting up new match event match=%d time=%d\n", matchVal, 1688869SAli.Saidi@ARM.com timeVal); 1698869SAli.Saidi@ARM.com 1708869SAli.Saidi@ARM.com uint32_t seconds_until = matchVal - timeVal; 1718869SAli.Saidi@ARM.com Tick ticks_until = SimClock::Int::s * seconds_until; 1728869SAli.Saidi@ARM.com 1738869SAli.Saidi@ARM.com if (matchEvent.scheduled()) { 1748869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 1758869SAli.Saidi@ARM.com deschedule(matchEvent); 1768869SAli.Saidi@ARM.com } 1778869SAli.Saidi@ARM.com schedule(matchEvent, curTick() + ticks_until); 1788869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + ticks_until); 1798869SAli.Saidi@ARM.com} 1808869SAli.Saidi@ARM.com 1818869SAli.Saidi@ARM.comvoid 1828869SAli.Saidi@ARM.comPL031::counterMatch() 1838869SAli.Saidi@ARM.com{ 1848869SAli.Saidi@ARM.com DPRINTF(Timer, "Counter reached zero\n"); 1858869SAli.Saidi@ARM.com 1868869SAli.Saidi@ARM.com rawInt = true; 1878869SAli.Saidi@ARM.com bool old_pending = pendingInt; 1888869SAli.Saidi@ARM.com pendingInt = maskInt & rawInt; 1898993SAli.Saidi@ARM.com if (pendingInt && !old_pending) { 1908869SAli.Saidi@ARM.com DPRINTF(Timer, "-- Causing interrupt\n"); 1918869SAli.Saidi@ARM.com gic->sendInt(intNum); 1927584SN/A } 1937584SN/A} 1947584SN/A 1957584SN/Avoid 19610905Sandreas.sandberg@arm.comPL031::serialize(CheckpointOut &cp) const 1977584SN/A{ 1988869SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Serializing Arm PL031\n"); 1998869SAli.Saidi@ARM.com SERIALIZE_SCALAR(timeVal); 2008869SAli.Saidi@ARM.com SERIALIZE_SCALAR(lastWrittenTick); 2018869SAli.Saidi@ARM.com SERIALIZE_SCALAR(loadVal); 2028869SAli.Saidi@ARM.com SERIALIZE_SCALAR(matchVal); 2038869SAli.Saidi@ARM.com SERIALIZE_SCALAR(rawInt); 2048869SAli.Saidi@ARM.com SERIALIZE_SCALAR(maskInt); 2058869SAli.Saidi@ARM.com SERIALIZE_SCALAR(pendingInt); 2067584SN/A 2078869SAli.Saidi@ARM.com bool is_in_event = matchEvent.scheduled(); 2087733SN/A SERIALIZE_SCALAR(is_in_event); 2097733SN/A 2107733SN/A Tick event_time; 2117733SN/A if (is_in_event){ 2128869SAli.Saidi@ARM.com event_time = matchEvent.when(); 2137733SN/A SERIALIZE_SCALAR(event_time); 2147733SN/A } 2157733SN/A} 2167733SN/A 2177733SN/Avoid 21810905Sandreas.sandberg@arm.comPL031::unserialize(CheckpointIn &cp) 2197733SN/A{ 2208869SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Unserializing Arm PL031\n"); 2217733SN/A 2228869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(timeVal); 2238869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(lastWrittenTick); 2248869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(loadVal); 2258869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(matchVal); 2267733SN/A UNSERIALIZE_SCALAR(rawInt); 2278869SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(maskInt); 2287733SN/A UNSERIALIZE_SCALAR(pendingInt); 2297733SN/A 2307733SN/A bool is_in_event; 2317733SN/A UNSERIALIZE_SCALAR(is_in_event); 2327733SN/A 2337733SN/A Tick event_time; 2347733SN/A if (is_in_event){ 2357733SN/A UNSERIALIZE_SCALAR(event_time); 2368869SAli.Saidi@ARM.com schedule(matchEvent, event_time); 2377733SN/A } 2387733SN/A} 2397733SN/A 2407733SN/A 2417584SN/A 2428869SAli.Saidi@ARM.comPL031 * 2438869SAli.Saidi@ARM.comPL031Params::create() 2447584SN/A{ 2458869SAli.Saidi@ARM.com return new PL031(this); 2467584SN/A} 247