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