summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRebecca Cran <rebecca@os.amperecomputing.com>2024-01-29 11:25:11 -0700
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-01-30 15:01:17 +0000
commitbeefa753f3fc944891b2183049b70c2a0d10d3ed (patch)
tree515b1f2751d0a146d431a8a5453fcd23e9086cbd
parent98c7cb3be73d0f15151133abe91bc880a4400794 (diff)
downloadedk2-beefa753f3fc944891b2183049b70c2a0d10d3ed.tar.gz
edk2-beefa753f3fc944891b2183049b70c2a0d10d3ed.tar.bz2
edk2-beefa753f3fc944891b2183049b70c2a0d10d3ed.zip
ArmPkg: Update GenericWatchdogDxe to allow setting full 48-bit offset
The generic watchdog offset register is 48 bits wide, and can be set by performing two 32-bit writes. Add support for writing the high 16 bits of the offset register and update the signature of the WatchdogWriteOffsetRegister function to take a UINT64 value. Signed-off-by: Rebecca Cran <rebecca@os.amperecomputing.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
-rw-r--r--ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdog.h11
-rw-r--r--ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c48
2 files changed, 52 insertions, 7 deletions
diff --git a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdog.h b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdog.h
index 9bc3bf4704..b7d6f7e784 100644
--- a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdog.h
+++ b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdog.h
@@ -1,9 +1,13 @@
/** @file
*
+* Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
* Copyright (c) 2013-2017, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
+* @par Reference(s):
+* - Generic Watchdog specification in Arm Base System Architecture 1.0C:
+* https://developer.arm.com/documentation/den0094/c/
**/
#ifndef GENERIC_WATCHDOG_H_
@@ -14,12 +18,17 @@
// Control Frame:
#define GENERIC_WDOG_CONTROL_STATUS_REG ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x000)
-#define GENERIC_WDOG_OFFSET_REG ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x008)
+#define GENERIC_WDOG_OFFSET_REG_LOW ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x008)
+#define GENERIC_WDOG_OFFSET_REG_HIGH ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x00C)
#define GENERIC_WDOG_COMPARE_VALUE_REG_LOW ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x010)
#define GENERIC_WDOG_COMPARE_VALUE_REG_HIGH ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0x014)
+#define GENERIC_WDOG_IID_REG ((UINTN)FixedPcdGet64 (PcdGenericWatchdogControlBase) + 0xFCC)
// Values of bit 0 of the Control/Status Register
#define GENERIC_WDOG_ENABLED 1
#define GENERIC_WDOG_DISABLED 0
+#define GENERIC_WDOG_IID_ARCH_REV_SHIFT 16
+#define GENERIC_WDOG_IID_ARCH_REV_MASK 0xF
+
#endif // GENERIC_WATCHDOG_H_
diff --git a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c
index 66c6c37c08..c96dc31dc6 100644
--- a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c
+++ b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c
@@ -1,5 +1,6 @@
/** @file
*
+* Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
* Copyright (c) 2013-2018, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -35,16 +36,49 @@ STATIC UINTN mTimerFrequencyHz = 0;
It is therefore stored here. 0 means the timer is not running. */
STATIC UINT64 mNumTimerTicks = 0;
+#define MAX_UINT48 0xFFFFFFFFFFFFULL
+
STATIC EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol;
STATIC EFI_WATCHDOG_TIMER_NOTIFY mWatchdogNotify;
+/**
+ This function returns the maximum watchdog offset register value.
+
+ @retval MAX_UINT32 The watchdog offset register holds a 32-bit value.
+ @retval MAX_UINT48 The watchdog offset register holds a 48-bit value.
+**/
+STATIC
+UINT64
+GetMaxWatchdogOffsetRegisterValue (
+ VOID
+ )
+{
+ UINT64 MaxWatchdogOffsetValue;
+ UINT32 WatchdogIId;
+ UINT8 WatchdogArchRevision;
+
+ WatchdogIId = MmioRead32 (GENERIC_WDOG_IID_REG);
+ WatchdogArchRevision = (WatchdogIId >> GENERIC_WDOG_IID_ARCH_REV_SHIFT) & GENERIC_WDOG_IID_ARCH_REV_MASK;
+
+ if (WatchdogArchRevision == 0) {
+ MaxWatchdogOffsetValue = MAX_UINT32;
+ } else {
+ MaxWatchdogOffsetValue = MAX_UINT48;
+ }
+
+ return MaxWatchdogOffsetValue;
+}
+
STATIC
VOID
WatchdogWriteOffsetRegister (
- UINT32 Value
+ UINT64 Value
)
{
- MmioWrite32 (GENERIC_WDOG_OFFSET_REG, Value);
+ MmioWrite32 (GENERIC_WDOG_OFFSET_REG_LOW, Value & MAX_UINT32);
+ if (GetMaxWatchdogOffsetRegisterValue () == MAX_UINT48) {
+ MmioWrite32 (GENERIC_WDOG_OFFSET_REG_HIGH, (Value >> 32) & MAX_UINT16);
+ }
}
STATIC
@@ -196,7 +230,8 @@ WatchdogSetTimerPeriod (
IN UINT64 TimerPeriod // In 100ns units
)
{
- UINTN SystemCount;
+ UINTN SystemCount;
+ UINT64 MaxWatchdogOffsetValue;
// if TimerPeriod is 0, this is a request to stop the watchdog.
if (TimerPeriod == 0) {
@@ -211,17 +246,18 @@ WatchdogSetTimerPeriod (
/* If the number of required ticks is greater than the max the watchdog's
offset register (WOR) can hold, we need to manually compute and set
the compare register (WCV) */
- if (mNumTimerTicks > MAX_UINT32) {
+ MaxWatchdogOffsetValue = GetMaxWatchdogOffsetRegisterValue ();
+ if (mNumTimerTicks > MaxWatchdogOffsetValue) {
/* We need to enable the watchdog *before* writing to the compare register,
because enabling the watchdog causes an "explicit refresh", which
clobbers the compare register (WCV). In order to make sure this doesn't
trigger an interrupt, set the offset to max. */
- WatchdogWriteOffsetRegister (MAX_UINT32);
+ WatchdogWriteOffsetRegister (MaxWatchdogOffsetValue);
WatchdogEnable ();
SystemCount = ArmGenericTimerGetSystemCount ();
WatchdogWriteCompareRegister (SystemCount + mNumTimerTicks);
} else {
- WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks);
+ WatchdogWriteOffsetRegister (mNumTimerTicks);
WatchdogEnable ();
}