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:
@@ -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"
|
||||
|
||||
@@ -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')
|
||||
|
||||
263
src/dev/arm/watchdog_generic.cc
Normal file
263
src/dev/arm/watchdog_generic.cc
Normal 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);
|
||||
}
|
||||
}
|
||||
156
src/dev/arm/watchdog_generic.hh
Normal file
156
src/dev/arm/watchdog_generic.hh
Normal 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 ¶ms);
|
||||
|
||||
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__
|
||||
Reference in New Issue
Block a user