dev-arm: Implement Generic Watchdog

Change-Id: I53bcb6ae77c0bcc080f4be0bd2339d4d1f6a4b28
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/39699
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Giacomo Travaglini
2020-07-13 21:31:50 +01:00
parent b621de5cd6
commit 4a4f994ff1
4 changed files with 435 additions and 0 deletions

View File

@@ -441,6 +441,21 @@ Reference:
yield node
class GenericWatchdog(PioDevice):
type = 'GenericWatchdog'
cxx_header = 'dev/arm/watchdog_generic.hh'
refresh_start = Param.Addr("Start address for the refresh frame")
control_start = Param.Addr("Start address for the control frame")
pio_latency = Param.Latency('10ns', "Delay for PIO r/w")
ws0 = Param.ArmInterruptPin("WS0 Signal")
ws1 = Param.ArmInterruptPin("WS1 Signal")
system_counter = Param.SystemCounter(Parent.any,
"The Watchdog uses the Generic Timer system counter as the timebase "
"against which the decision to trigger an interrupt is made.")
class A9GlobalTimer(BasicPioDevice):
type = 'A9GlobalTimer'
cxx_header = "dev/arm/timer_a9global.hh"

View File

@@ -81,6 +81,7 @@ if env['TARGET_ISA'] == 'arm':
Source('smmu_v3_deviceifc.cc');
Source('smmu_v3_transl.cc');
Source('timer_sp804.cc')
Source('watchdog_generic.cc')
Source('watchdog_sp805.cc')
Source('gpu_nomali.cc')
Source('pci_host.cc')

View File

@@ -0,0 +1,263 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dev/arm/watchdog_generic.hh"
#include "dev/arm/base_gic.hh"
#include "params/GenericWatchdog.hh"
GenericWatchdog::GenericWatchdog(const GenericWatchdogParams &p)
: PioDevice(p),
timeoutEvent([this]{ timeout(); }, name()),
controlStatus(0),
offset(0),
compare(0),
iidr(0),
refreshFrame(p.refresh_start, p.refresh_start + 0x10000),
controlFrame(p.control_start, p.control_start + 0x10000),
pioLatency(p.pio_latency),
cnt(*p.system_counter),
cntListener(*this),
ws0(p.ws0->get()),
ws1(p.ws1->get())
{
cnt.registerListener(&cntListener);
}
AddrRangeList
GenericWatchdog::getAddrRanges() const
{
AddrRangeList ranges;
ranges.push_back(refreshFrame);
ranges.push_back(controlFrame);
return ranges;
}
Tick
GenericWatchdog::read(PacketPtr pkt)
{
const Addr addr = pkt->getAddr();
const size_t size = pkt->getSize();
panic_if(size != 4, "GenericWatchdog::read: Invalid size %i\n", size);
uint32_t resp = 0;
if (refreshFrame.contains(addr)) {
resp = readRefresh(addr);
} else if (controlFrame.contains(addr)) {
resp = readControl(addr);
} else {
panic("%s unknown address %#x\n", __func__, addr);
}
pkt->setUintX(resp, ByteOrder::little);
pkt->makeResponse();
return pioLatency;
}
uint32_t
GenericWatchdog::readRefresh(Addr addr)
{
const auto daddr = static_cast<RefreshOffset>(
addr - refreshFrame.start());
switch (daddr) {
case RefreshOffset::WRR:
// A read of the refresh register has no effect and returns 0
return 0;
case RefreshOffset::W_IIDR:
return iidr;
default:
panic("%s unknown address %#x\n", __func__, addr);
}
}
uint32_t
GenericWatchdog::readControl(Addr addr)
{
const auto daddr = static_cast<ControlOffset>(
addr - controlFrame.start());
switch (daddr) {
case ControlOffset::WCS:
return controlStatus;
case ControlOffset::WOR:
return offset;
case ControlOffset::WCV_LO:
return bits(compare, 31, 0);
case ControlOffset::WCV_HI:
return bits(compare, 63, 32);
case ControlOffset::W_IIDR:
return iidr;
default:
panic("%s unknown address %#x\n", __func__, addr);
}
}
Tick
GenericWatchdog::write(PacketPtr pkt)
{
const Addr addr = pkt->getAddr();
const size_t size = pkt->getSize();
panic_if(size != 4, "GenericWatchdog::write: Invalid size %i\n", size);
uint32_t data = pkt->getUintX(ByteOrder::little);
if (refreshFrame.contains(addr)) {
writeRefresh(addr, data);
} else if (controlFrame.contains(addr)) {
writeControl(addr, data);
} else {
panic("%s unknown address %#x\n", __func__, addr);
}
pkt->makeResponse();
return pioLatency;
}
void
GenericWatchdog::writeRefresh(Addr addr, uint32_t data)
{
const auto daddr = static_cast<RefreshOffset>(
addr - refreshFrame.start());
switch (daddr) {
case RefreshOffset::WRR:
explicitRefresh();
break;
default:
panic("%s unknown address %#x\n", __func__, addr);
}
}
void
GenericWatchdog::writeControl(Addr addr, uint32_t data)
{
const auto daddr = static_cast<ControlOffset>(
addr - controlFrame.start());
switch (daddr) {
case ControlOffset::WCS:
controlStatus = data & 0x1;
explicitRefresh();
break;
case ControlOffset::WOR:
offset = data;
explicitRefresh();
break;
case ControlOffset::WCV_LO:
compare = insertBits(compare, 31, 0, data);
break;
case ControlOffset::WCV_HI:
compare = insertBits(compare, 63, 32, data);
break;
default:
panic("%s unknown address %#x\n", __func__, addr);
}
}
void
GenericWatchdog::explicitRefresh()
{
// Watchdog signals are cleared in case of an explicit refresh
controlStatus.ws0 = 0;
controlStatus.ws1 = 0;
ws0->clear();
ws1->clear();
refresh();
}
void
GenericWatchdog::refresh()
{
// Update compare value
compare = cnt.value() + offset;
// Ask the System Counter how long we have to wait until
// it reaches the new compare value
Tick timeout_time = cnt.whenValue(compare);
reschedule(timeoutEvent, timeout_time, true);
}
void
GenericWatchdog::timeout()
{
if (!controlStatus.enabled)
return;
if (!controlStatus.ws0) {
controlStatus.ws0 = 1;
ws0->raise();
} else {
controlStatus.ws1 = 1;
ws1->raise();
}
refresh();
}
void
GenericWatchdog::serialize(CheckpointOut &cp) const
{
SERIALIZE_SCALAR(controlStatus);
SERIALIZE_SCALAR(offset);
SERIALIZE_SCALAR(compare);
bool ev_scheduled = timeoutEvent.scheduled();
SERIALIZE_SCALAR(ev_scheduled);
if (ev_scheduled)
SERIALIZE_SCALAR(timeoutEvent.when());
}
void
GenericWatchdog::unserialize(CheckpointIn &cp)
{
UNSERIALIZE_SCALAR(controlStatus);
UNSERIALIZE_SCALAR(offset);
UNSERIALIZE_SCALAR(compare);
bool ev_scheduled;
UNSERIALIZE_SCALAR(ev_scheduled);
if (ev_scheduled) {
Tick when;
UNSERIALIZE_SCALAR(when);
reschedule(timeoutEvent, when, true);
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DEV_ARM_WATCHDOG_GENERIC_HH__
#define __DEV_ARM_WATCHDOG_GENERIC_HH__
#include "dev/arm/generic_timer.hh"
#include "dev/io_device.hh"
class ArmInterruptPin;
class GenericWatchdogParams;
/**
* @file
* Arm SBSA Generic Watchdog
* Reference:
* Arm Server Base System Architecture (SBSA)
* Doc. ID: ARM-DEN-0029A Version 3.1
*/
class GenericWatchdog : public PioDevice
{
public:
GenericWatchdog(const GenericWatchdogParams &params);
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
bool enabled() const { return controlStatus.enabled; }
protected:
AddrRangeList getAddrRanges() const override;
Tick read(PacketPtr pkt) override;
Tick write(PacketPtr pkt) override;
uint32_t readRefresh(Addr addr);
uint32_t readControl(Addr addr);
void writeRefresh(Addr addr, uint32_t data);
void writeControl(Addr addr, uint32_t data);
protected:
/**
* System Counter Listener: This object is being notified
* any time there is a change in the SystemCounter.
* (Like a change in the counter frequency)
* This is needed since the Generic Watchdog doesn't have
* a standalone counter and it is instead relying on the
* global System Counter.
*/
class Listener : public SystemCounterListener
{
public:
explicit Listener(GenericWatchdog& _parent)
: parent(_parent)
{}
void notify(void) override
{
panic_if(parent.enabled(),
"The Generic Watchdog shall be disabled when "
"the System Counter is being updated, or "
"the results are unpredictable");
}
protected:
GenericWatchdog &parent;
};
void explicitRefresh();
void refresh();
void timeout();
EventFunctionWrapper timeoutEvent;
private:
enum class RefreshOffset : Addr
{
WRR = 0x000, // Watchdog Refresh Register
W_IIDR = 0xfcc, // Watchdog Interface Identification Register
};
enum class ControlOffset : Addr
{
WCS = 0x000, // Watchdog Control and Status Register
WOR = 0x008, // Watchdog Offset Register
WCV_LO = 0x010, // Watchdog Compare Register [31:0]
WCV_HI = 0x014, // Watchdog Compare Register [63:32]
W_IIDR = 0xfcc, // Watchdog Interface Identification Register
};
BitUnion32(WCTRLS)
Bitfield<2> ws1; // Watchdog Signal 1 Status
Bitfield<1> ws0; // Watchdog Signal 0 Status
Bitfield<0> enabled; // Watchdog Enable
EndBitUnion(WCTRLS)
/** Control and Status Register */
WCTRLS controlStatus;
/** Offset Register */
uint32_t offset;
/** Compare Register */
uint64_t compare;
/** Interface Identification Register */
const uint32_t iidr;
const AddrRange refreshFrame;
const AddrRange controlFrame;
const Tick pioLatency;
SystemCounter &cnt;
Listener cntListener;
/** Watchdog Signals (IRQs) */
ArmInterruptPin * const ws0;
ArmInterruptPin * const ws1;
};
#endif // __DEV_ARM_WATCHDOG_GENERIC_HH__