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 &section)
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 &section)
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