rtc_pl031.cc revision 7733
17199Sgblack@eecs.umich.edu/* 27199Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited 38868SMatt.Horsnell@arm.com * All rights reserved 47199Sgblack@eecs.umich.edu * 57199Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67199Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77199Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87199Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97199Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107199Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117199Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127199Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137199Sgblack@eecs.umich.edu * 147199Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 157199Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 167199Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 177199Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 187199Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 197199Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 207199Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 217199Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 227199Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 237199Sgblack@eecs.umich.edu * this software without specific prior written permission. 247199Sgblack@eecs.umich.edu * 257199Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267199Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277199Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287199Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297199Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307199Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317199Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327199Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337199Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347199Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357199Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367199Sgblack@eecs.umich.edu * 377199Sgblack@eecs.umich.edu * Authors: Ali Saidi 387199Sgblack@eecs.umich.edu */ 397199Sgblack@eecs.umich.edu 407199Sgblack@eecs.umich.edu#include "base/intmath.hh" 417199Sgblack@eecs.umich.edu#include "base/trace.hh" 427199Sgblack@eecs.umich.edu#include "dev/arm/gic.hh" 438782Sgblack@eecs.umich.edu#include "dev/arm/timer_sp804.hh" 448782Sgblack@eecs.umich.edu#include "mem/packet.hh" 458782Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 468782Sgblack@eecs.umich.edu 478782Sgblack@eecs.umich.eduusing namespace AmbaDev; 487199Sgblack@eecs.umich.edu 497199Sgblack@eecs.umich.eduSp804::Sp804(Params *p) 507199Sgblack@eecs.umich.edu : AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0), 517199Sgblack@eecs.umich.edu timer1(name() + ".timer1", this, p->int_num1, p->clock1) 528628SAli.Saidi@ARM.com{ 538628SAli.Saidi@ARM.com pioSize = 0xfff; 547199Sgblack@eecs.umich.edu} 557199Sgblack@eecs.umich.edu 567199Sgblack@eecs.umich.eduSp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock) 577199Sgblack@eecs.umich.edu : _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20), 587199Sgblack@eecs.umich.edu rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this) 597202Sgblack@eecs.umich.edu{ 607202Sgblack@eecs.umich.edu} 617202Sgblack@eecs.umich.edu 627202Sgblack@eecs.umich.edu 637202Sgblack@eecs.umich.eduTick 648301SAli.Saidi@ARM.comSp804::read(PacketPtr pkt) 658303SAli.Saidi@ARM.com{ 668303SAli.Saidi@ARM.com assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 678303SAli.Saidi@ARM.com assert(pkt->getSize() == 4); 688303SAli.Saidi@ARM.com Addr daddr = pkt->getAddr() - pioAddr; 698303SAli.Saidi@ARM.com pkt->allocate(); 708303SAli.Saidi@ARM.com DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr); 718301SAli.Saidi@ARM.com 728301SAli.Saidi@ARM.com if (daddr < Timer::Size) 737202Sgblack@eecs.umich.edu timer0.read(pkt, daddr); 747202Sgblack@eecs.umich.edu else if ((daddr - Timer::Size) < Timer::Size) 757599Sminkyu.jeong@arm.com timer1.read(pkt, daddr - Timer::Size); 767783SGiacomo.Gabrielli@arm.com else if (!readId(pkt, ambaId, pioAddr)) 777202Sgblack@eecs.umich.edu panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr); 787202Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 797202Sgblack@eecs.umich.edu return pioDelay; 807202Sgblack@eecs.umich.edu} 817202Sgblack@eecs.umich.edu 827202Sgblack@eecs.umich.edu 837202Sgblack@eecs.umich.eduvoid 847599Sminkyu.jeong@arm.comSp804::Timer::read(PacketPtr pkt, Addr daddr) 857783SGiacomo.Gabrielli@arm.com{ 867202Sgblack@eecs.umich.edu DPRINTF(Timer, "Reading from Timer at offset: %#x\n", daddr); 877202Sgblack@eecs.umich.edu 887202Sgblack@eecs.umich.edu switch(daddr) { 897202Sgblack@eecs.umich.edu case LoadReg: 907202Sgblack@eecs.umich.edu pkt->set<uint32_t>(loadValue); 917400SAli.Saidi@ARM.com break; 928303SAli.Saidi@ARM.com case CurrentReg: 938303SAli.Saidi@ARM.com DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n", 948303SAli.Saidi@ARM.com zeroEvent.when(), clock, control.timerPrescale); 958303SAli.Saidi@ARM.com Tick time; 968303SAli.Saidi@ARM.com time = zeroEvent.when() - curTick; 978303SAli.Saidi@ARM.com time = time / clock / power(16, control.timerPrescale); 988303SAli.Saidi@ARM.com DPRINTF(Timer, "-- returning counter at %d\n", time); 998303SAli.Saidi@ARM.com pkt->set<uint32_t>(time); 1008303SAli.Saidi@ARM.com break; 1018303SAli.Saidi@ARM.com case ControlReg: 1028303SAli.Saidi@ARM.com pkt->set<uint32_t>(control); 1038303SAli.Saidi@ARM.com break; 1048303SAli.Saidi@ARM.com case RawISR: 1057202Sgblack@eecs.umich.edu pkt->set<uint32_t>(rawInt); 1067202Sgblack@eecs.umich.edu break; 1077202Sgblack@eecs.umich.edu case MaskedISR: 1087599Sminkyu.jeong@arm.com pkt->set<uint32_t>(pendingInt); 1097599Sminkyu.jeong@arm.com break; 1107202Sgblack@eecs.umich.edu case BGLoad: 1117202Sgblack@eecs.umich.edu pkt->set<uint32_t>(loadValue); 1127202Sgblack@eecs.umich.edu break; 1137202Sgblack@eecs.umich.edu default: 1147202Sgblack@eecs.umich.edu panic("Tried to read SP804 timer at offset %#x\n", daddr); 1157202Sgblack@eecs.umich.edu break; 1167202Sgblack@eecs.umich.edu } 1177599Sminkyu.jeong@arm.com} 1187599Sminkyu.jeong@arm.com 1197202Sgblack@eecs.umich.eduTick 1207202Sgblack@eecs.umich.eduSp804::write(PacketPtr pkt) 1217202Sgblack@eecs.umich.edu{ 1227202Sgblack@eecs.umich.edu assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); 1237202Sgblack@eecs.umich.edu assert(pkt->getSize() == 4); 1247400SAli.Saidi@ARM.com Addr daddr = pkt->getAddr() - pioAddr; 1258303SAli.Saidi@ARM.com pkt->allocate(); 1268303SAli.Saidi@ARM.com DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr); 1278303SAli.Saidi@ARM.com 1288303SAli.Saidi@ARM.com if (daddr < Timer::Size) 1298303SAli.Saidi@ARM.com timer0.write(pkt, daddr); 1308303SAli.Saidi@ARM.com else if ((daddr - Timer::Size) < Timer::Size) 1318303SAli.Saidi@ARM.com timer1.write(pkt, daddr - Timer::Size); 1328303SAli.Saidi@ARM.com else if (!readId(pkt, ambaId, pioAddr)) 1338303SAli.Saidi@ARM.com panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr); 1348303SAli.Saidi@ARM.com pkt->makeAtomicResponse(); 1358303SAli.Saidi@ARM.com return pioDelay; 1368303SAli.Saidi@ARM.com} 1377202Sgblack@eecs.umich.edu 1387202Sgblack@eecs.umich.eduvoid 1397202Sgblack@eecs.umich.eduSp804::Timer::write(PacketPtr pkt, Addr daddr) 1407599Sminkyu.jeong@arm.com{ 1417599Sminkyu.jeong@arm.com DPRINTF(Timer, "Writing to Timer at offset: %#x\n", daddr); 1427202Sgblack@eecs.umich.edu switch (daddr) { 1437202Sgblack@eecs.umich.edu case LoadReg: 1447202Sgblack@eecs.umich.edu loadValue = pkt->get<uint32_t>(); 1457202Sgblack@eecs.umich.edu restartCounter(loadValue); 1467202Sgblack@eecs.umich.edu break; 1477202Sgblack@eecs.umich.edu case CurrentReg: 1487202Sgblack@eecs.umich.edu // Spec says this value can't be written, but linux writes it anyway 1497599Sminkyu.jeong@arm.com break; 1507599Sminkyu.jeong@arm.com case ControlReg: 1517202Sgblack@eecs.umich.edu bool old_enable; 1527202Sgblack@eecs.umich.edu old_enable = control.timerEnable; 1537202Sgblack@eecs.umich.edu control = pkt->get<uint32_t>(); 1547209Sgblack@eecs.umich.edu if ((old_enable == 0) && control.timerEnable) 1557209Sgblack@eecs.umich.edu restartCounter(loadValue); 1567209Sgblack@eecs.umich.edu break; 1577209Sgblack@eecs.umich.edu case IntClear: 1587209Sgblack@eecs.umich.edu rawInt = false; 1597261Sgblack@eecs.umich.edu if (pendingInt) { 1607209Sgblack@eecs.umich.edu pendingInt = false; 1617209Sgblack@eecs.umich.edu DPRINTF(Timer, "Clearing interrupt\n"); 1627261Sgblack@eecs.umich.edu parent->gic->clearInt(intNum); 1637261Sgblack@eecs.umich.edu } 1647209Sgblack@eecs.umich.edu break; 1657209Sgblack@eecs.umich.edu case BGLoad: 1667209Sgblack@eecs.umich.edu loadValue = pkt->get<uint32_t>(); 1677209Sgblack@eecs.umich.edu break; 1687209Sgblack@eecs.umich.edu default: 1697209Sgblack@eecs.umich.edu panic("Tried to write SP804 timer at offset %#x\n", daddr); 1707209Sgblack@eecs.umich.edu break; 1717209Sgblack@eecs.umich.edu } 1727209Sgblack@eecs.umich.edu} 1737261Sgblack@eecs.umich.edu 1747209Sgblack@eecs.umich.eduvoid 1757209Sgblack@eecs.umich.eduSp804::Timer::restartCounter(uint32_t val) 1767261Sgblack@eecs.umich.edu{ 1777261Sgblack@eecs.umich.edu DPRINTF(Timer, "Resetting counter with value %#x\n", val); 1787209Sgblack@eecs.umich.edu if (!control.timerEnable) 1797209Sgblack@eecs.umich.edu return; 1807209Sgblack@eecs.umich.edu 1817209Sgblack@eecs.umich.edu Tick time = clock << power(16, control.timerPrescale); 1827209Sgblack@eecs.umich.edu if (control.timerSize) 1837209Sgblack@eecs.umich.edu time *= bits(val,15,0); 1847261Sgblack@eecs.umich.edu else 1857209Sgblack@eecs.umich.edu time *= val; 1867209Sgblack@eecs.umich.edu 1877261Sgblack@eecs.umich.edu if (zeroEvent.scheduled()) { 1887261Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); 1897209Sgblack@eecs.umich.edu parent->deschedule(zeroEvent); 1907226Sgblack@eecs.umich.edu } 1917249Sgblack@eecs.umich.edu parent->schedule(zeroEvent, curTick + time); 1927249Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick + time); 1937249Sgblack@eecs.umich.edu} 1947249Sgblack@eecs.umich.edu 1957249Sgblack@eecs.umich.eduvoid 1967249Sgblack@eecs.umich.eduSp804::Timer::counterAtZero() 1977249Sgblack@eecs.umich.edu{ 1987249Sgblack@eecs.umich.edu if (!control.timerEnable) 1997249Sgblack@eecs.umich.edu return; 2007249Sgblack@eecs.umich.edu 2017249Sgblack@eecs.umich.edu DPRINTF(Timer, "Counter reached zero\n"); 2027249Sgblack@eecs.umich.edu 2037249Sgblack@eecs.umich.edu rawInt = true; 2047261Sgblack@eecs.umich.edu bool old_pending = pendingInt; 2057249Sgblack@eecs.umich.edu if (control.intEnable) 2067249Sgblack@eecs.umich.edu pendingInt = true; 2077261Sgblack@eecs.umich.edu if (pendingInt && ~old_pending) { 2087261Sgblack@eecs.umich.edu DPRINTF(Timer, "-- Causing interrupt\n"); 2097249Sgblack@eecs.umich.edu parent->gic->sendInt(intNum); 2107249Sgblack@eecs.umich.edu } 2117251Sgblack@eecs.umich.edu 2127251Sgblack@eecs.umich.edu if (control.oneShot) 2137251Sgblack@eecs.umich.edu return; 2147261Sgblack@eecs.umich.edu 2157251Sgblack@eecs.umich.edu // Free-running 2167251Sgblack@eecs.umich.edu if (control.timerMode == 0) 2177261Sgblack@eecs.umich.edu restartCounter(0xffffffff); 2187261Sgblack@eecs.umich.edu else 2197251Sgblack@eecs.umich.edu restartCounter(loadValue); 2207251Sgblack@eecs.umich.edu} 2217226Sgblack@eecs.umich.edu 2227226Sgblack@eecs.umich.eduvoid 2237226Sgblack@eecs.umich.eduSp804::Timer::serialize(std::ostream &os) 2247232Sgblack@eecs.umich.edu{ 2258302SAli.Saidi@ARM.com DPRINTF(Checkpoint, "Serializing Arm Sp804\n"); 2267226Sgblack@eecs.umich.edu SERIALIZE_SCALAR(intNum); 2277226Sgblack@eecs.umich.edu SERIALIZE_SCALAR(clock); 2287232Sgblack@eecs.umich.edu 2297226Sgblack@eecs.umich.edu uint32_t control_serial = control; 2308304SAli.Saidi@ARM.com SERIALIZE_SCALAR(control_serial); 2317232Sgblack@eecs.umich.edu 2327232Sgblack@eecs.umich.edu SERIALIZE_SCALAR(rawInt); 2337226Sgblack@eecs.umich.edu SERIALIZE_SCALAR(pendingInt); 2347226Sgblack@eecs.umich.edu SERIALIZE_SCALAR(loadValue); 2357226Sgblack@eecs.umich.edu 2367226Sgblack@eecs.umich.edu bool is_in_event = zeroEvent.scheduled(); 2377226Sgblack@eecs.umich.edu SERIALIZE_SCALAR(is_in_event); 2387232Sgblack@eecs.umich.edu 2398302SAli.Saidi@ARM.com Tick event_time; 2407226Sgblack@eecs.umich.edu if (is_in_event){ 2417226Sgblack@eecs.umich.edu event_time = zeroEvent.when(); 2427232Sgblack@eecs.umich.edu SERIALIZE_SCALAR(event_time); 2437226Sgblack@eecs.umich.edu } 2448304SAli.Saidi@ARM.com} 2457232Sgblack@eecs.umich.edu 2467232Sgblack@eecs.umich.eduvoid 2477226Sgblack@eecs.umich.eduSp804::Timer::unserialize(Checkpoint *cp, const std::string §ion) 2487226Sgblack@eecs.umich.edu{ 2497226Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "Unserializing Arm Sp804\n"); 2507226Sgblack@eecs.umich.edu 2517226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(intNum); 2527226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(clock); 2537226Sgblack@eecs.umich.edu 2547232Sgblack@eecs.umich.edu uint32_t control_serial; 2558302SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(control_serial); 2567226Sgblack@eecs.umich.edu control = control_serial; 2577232Sgblack@eecs.umich.edu 2588302SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(rawInt); 2597226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(pendingInt); 2607226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(loadValue); 2617226Sgblack@eecs.umich.edu 2627232Sgblack@eecs.umich.edu bool is_in_event; 2637226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(is_in_event); 2648304SAli.Saidi@ARM.com 2657232Sgblack@eecs.umich.edu Tick event_time; 2667232Sgblack@eecs.umich.edu if (is_in_event){ 2677226Sgblack@eecs.umich.edu UNSERIALIZE_SCALAR(event_time); 2687226Sgblack@eecs.umich.edu parent->schedule(zeroEvent, event_time); 2697226Sgblack@eecs.umich.edu } 2707226Sgblack@eecs.umich.edu} 2717226Sgblack@eecs.umich.edu 2727226Sgblack@eecs.umich.edu 2737226Sgblack@eecs.umich.edu 2747232Sgblack@eecs.umich.eduvoid 2758302SAli.Saidi@ARM.comSp804::serialize(std::ostream &os) 2767226Sgblack@eecs.umich.edu{ 2777232Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.timer0", name())); 2788302SAli.Saidi@ARM.com timer0.serialize(os); 2797226Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.timer1", name())); 2807226Sgblack@eecs.umich.edu timer1.serialize(os); 2817226Sgblack@eecs.umich.edu} 2827232Sgblack@eecs.umich.edu 2837226Sgblack@eecs.umich.eduvoid 2848304SAli.Saidi@ARM.comSp804::unserialize(Checkpoint *cp, const std::string §ion) 2857232Sgblack@eecs.umich.edu{ 2867232Sgblack@eecs.umich.edu timer0.unserialize(cp, csprintf("%s.timer0", section)); 2877226Sgblack@eecs.umich.edu timer1.unserialize(cp, csprintf("%s.timer1", section)); 2887234Sgblack@eecs.umich.edu} 2897234Sgblack@eecs.umich.edu 2907234Sgblack@eecs.umich.eduSp804 * 2918588Sgblack@eecs.umich.eduSp804Params::create() 2927234Sgblack@eecs.umich.edu{ 2937234Sgblack@eecs.umich.edu return new Sp804(this); 2947234Sgblack@eecs.umich.edu} 2957234Sgblack@eecs.umich.edu