Hi Marcin, This watchdog is not compatible with ARM generic.
Thanks, Narinder > -----Original Message----- > From: Marcin Wojtas <m...@semihalf.com> > Sent: Friday, January 12, 2024 3:35 AM > To: devel@edk2.groups.io; Narinder Dhillon <ndhil...@marvell.com> > Cc: Leif Lindholm <quic_llind...@quicinc.com>; marcin.s.woj...@gmail.com; > Szymon Balcerak <sbalce...@marvell.com> > Subject: [EXT] Re: [edk2-devel] [edk2-platforms PATCH v2 4/8] > Silicon/Marvell: Odyssey watchdog driver > > External Email > > ---------------------------------------------------------------------- > +marcin.s.woj...@gmail.com > > Hi Narinder > > czw., 21 gru 2023 o 01:54 Narinder Dhillon <ndhil...@marvell.com> > napisaĆ(a): > > > > From: Narinder Dhillon <ndhil...@marvell.com> > > > > This patch adds watchdog driver for Odyssey SoC. > > To make sure - isn't this watchdog IP compatible with the ARM generic > watchdog (ArmPkg/Drivers/GenericWatchdogDxe/). FYI, there are some > recent fixes submitted for it > (https://urldefense.proofpoint.com/v2/url?u=https- > 3A__github.com_tianocore_edk2_pull_5176_commits&d=DwIFaQ&c=nKjWe > c2b6R0mOyPaz7xtfQ&r=1o2VA7xKsHvmQ4HFRY2JZggF- > gGh1t4bxHFABsB1WTo&m=qj9Q626HjLetYIq9pZF97XSPesJ0YDEFI5AB0hT7kZ > LhI8IBOoewS_231IjdayLA&s=Vo1YVzUgekaX4YbENSjyAq4eDVK9Fx_SHRHDc > 0oTsfU&e= ) > > Best regards, > Marcin > > > > > > > Signed-off-by: Narinder Dhillon <ndhil...@marvell.com> > > --- > > .../Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c | 408 > ++++++++++++++++++ > > .../Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf | 45 ++ > > 2 files changed, 453 insertions(+) > > create mode 100644 > > Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c > > create mode 100644 > > Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf > > > > diff --git a/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c > > b/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c > > new file mode 100644 > > index 0000000000..12be08ff24 > > --- /dev/null > > +++ b/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c > > @@ -0,0 +1,408 @@ > > +/** @file > > +* > > +* SPDX-License-Identifier: BSD-2-Clause-Patent > > +* > > +https://urldefense.proofpoint.com/v2/url?u=https- > 3A__spdx.org_license > > > +s&d=DwIFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=1o2VA7xKsHvmQ4HFRY2JZ > ggF-gGh1t4 > > > +bxHFABsB1WTo&m=qj9Q626HjLetYIq9pZF97XSPesJ0YDEFI5AB0hT7kZLhI8IB > OoewS_ > > +231IjdayLA&s=Tmg9C1Y51OhHhKeBL7ogbIVncE91tqOli4RO-RyXANM&e= > > +* > > +* Copyright (C) 2022 Marvell > > +* > > +* Source file for Marvell Watchdog driver > > +* > > +**/ > > + > > + > > +#include <PiDxe.h> > > + > > +#include <Library/BaseLib.h> > > +#include <Library/DebugLib.h> > > +#include <Library/IoLib.h> > > +#include <Library/PcdLib.h> > > +#include <Library/UefiBootServicesTableLib.h> > > +#include <Library/UefiLib.h> > > + > > +#include <Protocol/FdtClient.h> > > +#include <Protocol/WatchdogTimer.h> > > + > > +#define GTI_CWD_WDOG(Core) > (FixedPcdGet64(PcdGtiWatchdogBase64) + 0x40000 + Core * 0x8) > > +#define GTI_CWD_POKE(Core) > (FixedPcdGet64(PcdGtiWatchdogBase64) + 0x50000 + Core * 0x8) > > + > > +typedef union _GTI_CWD_WDOG_UNION { > > + UINT64 U64; > > + struct { > > + UINTN Mode : 2; > > + UINTN State : 2; > > + UINTN Len : 16; > > + UINTN Cnt : 24; > > + UINTN DStop : 1; > > + UINTN GStop : 1; > > + UINTN Rsvd : 18; > > + } PACKED S; > > +} GTI_CWD_WDOG_UNION; > > + > > +#define CWD_WDOG_MODE_RST (BIT1 | BIT0) > > + > > +#define RST_BOOT_PNR_MUL(Val) ((Val >> 33) & 0x1F) > > + > > +EFI_EVENT mGtiExitBootServicesEvent = (EFI_EVENT)NULL; > > +UINT32 mSclk = 0; > > +BOOLEAN mHardwarePlatform = TRUE; > > + > > +/** > > + Stop the GTI watchdog timer from counting down by disabling interrupts. > > +**/ > > +STATIC > > +VOID > > +GtiWdtStop ( > > + VOID > > + ) > > +{ > > + GTI_CWD_WDOG_UNION Wdog; > > + > > + MmioWrite64(GTI_CWD_POKE(0), 0); > > + > > + Wdog.U64 = MmioRead64(GTI_CWD_WDOG(0)); > > + > > + // Disable WDT > > + if (Wdog.S.Mode != 0) { > > + Wdog.S.Len = 1; > > + Wdog.S.Mode = 0; > > + MmioWrite64 (GTI_CWD_WDOG(0), Wdog.U64); > > + } > > +} > > + > > +/** > > + Starts the GTI WDT countdown by enabling interrupts. > > + The count down will start from the value stored in the Load > > +register, > > + not from the value where it was previously stopped. > > +**/ > > +STATIC > > +VOID > > +GtiWdtStart ( > > + VOID > > + ) > > +{ > > + GTI_CWD_WDOG_UNION Wdog; > > + > > + // Reset the WDT > > + MmioWrite64 (GTI_CWD_POKE(0), 0); > > + > > + Wdog.U64 = MmioRead64 (GTI_CWD_WDOG(0)); > > + > > + // Enable countdown > > + if (Wdog.S.Mode == 0) { > > + Wdog.S.Mode = CWD_WDOG_MODE_RST; > > + MmioWrite64 (GTI_CWD_WDOG(0), Wdog.U64); > > + } > > +} > > + > > +/** > > + On exiting boot services we must make sure the SP805 Watchdog Timer > > + is stopped. > > +**/ > > +VOID > > +EFIAPI > > +GtiExitBootServices ( > > + IN EFI_EVENT Event, > > + IN VOID *Context > > + ) > > +{ > > + MmioWrite64 (GTI_CWD_POKE(0), 0); > > + GtiWdtStop (); > > +} > > + > > +/** > > + This function registers the handler NotifyFunction so it is called > > +every time > > + the watchdog timer expires. It also passes the amount of time > > +since the last > > + handler call to the NotifyFunction. > > + If NotifyFunction is not NULL and a handler is not already > > +registered, > > + then the new handler is registered and EFI_SUCCESS is returned. > > + If NotifyFunction is NULL, and a handler is already registered, > > + then that handler is unregistered. > > + If an attempt is made to register a handler when a handler is > > +already registered, > > + then EFI_ALREADY_STARTED is returned. > > + If an attempt is made to unregister a handler when a handler is not > > +registered, > > + then EFI_INVALID_PARAMETER is returned. > > + > > + @param This The EFI_TIMER_ARCH_PROTOCOL instance. > > + @param NotifyFunction The function to call when a timer interrupt > fires. This > > + function executes at TPL_HIGH_LEVEL. The DXE > > Core will > > + register a handler for the timer interrupt, so > > it can know > > + how much time has passed. This information is > > used to > > + signal timer based events. NULL will unregister > > the handler. > > + > > + @retval EFI_SUCCESS The watchdog timer handler was registered. > > + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a > handler is already > > + registered. > > + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler > was not > > + previously registered. > > + @retval EFI_UNSUPPORTED HW does not support this functionality. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +GtiWdtRegisterHandler ( > > + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, > > + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction > > + ) > > +{ > > + // UNSUPPORTED - The hardware watchdog will reset the board > > + return EFI_UNSUPPORTED; > > +} > > + > > +/** > > + > > + This function adjusts the period of timer interrupts to the value > > + specified by TimerPeriod. If the timer period is updated, then the > > + selected timer period is stored in EFI_TIMER.TimerPeriod, and > > + EFI_SUCCESS is returned. If the timer hardware is not programmable, > then EFI_UNSUPPORTED is returned. > > + If an error occurs while attempting to update the timer period, > > + then the timer hardware will be put back in its state prior to this > > + call, and EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then > > + the timer interrupt is disabled. This is not the same as disabling the > > CPU's > interrupts. > > + Instead, it must either turn off the timer hardware, or it must > > + adjust the interrupt controller so that a CPU interrupt is not > > + generated when the timer interrupt fires. > > + > > + @param This The EFI_TIMER_ARCH_PROTOCOL instance. > > + @param TimerPeriod The rate to program the timer interrupt in 100 > nS units. If > > + the timer hardware is not programmable, then > EFI_UNSUPPORTED is > > + returned. If the timer is programmable, then > > the timer > period > > + will be rounded up to the nearest timer period > > that is > supported > > + by the timer hardware. If TimerPeriod is set to > > 0, then the > > + timer interrupts will be disabled. > > + > > + > > + @retval EFI_SUCCESS The timer period was changed. > > + @retval EFI_UNSUPPORTED The platform cannot change the period > of the timer interrupt. > > + @retval EFI_DEVICE_ERROR The timer period could not be changed > due to a device error. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +GtiWdtSetTimerPeriod ( > > + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, > > + IN UINT64 TimerPeriod // In 100ns > > units > > + ) > > +{ > > + UINT32 Clock; > > + UINT64 CountDown; > > + GTI_CWD_WDOG_UNION Wdog; > > + > > + if (TimerPeriod == 0) { > > + > > + // This is a watchdog stop request > > + GtiWdtStop(); > > + > > + return EFI_SUCCESS; > > + } else { > > + // > > + // The system is reset only after the WDT expires for the 3rd time > > + // > > + > > + Clock = mSclk / 1000000; //MHz > > + CountDown = DivU64x32 (MultU64x32 (TimerPeriod, Clock), 30); > > + > > + // WDT counts in 1024 cycle steps > > + // Only upper 16 bits can be used > > + > > + Wdog.U64 = 0; > > + Wdog.S.Len = (CountDown + (0xFF << 10)) >> 18; > > + MmioWrite64 (GTI_CWD_WDOG(0), Wdog.U64); > > + > > + // Start the watchdog > > + if (mHardwarePlatform == TRUE) { > > + GtiWdtStart(); > > + } > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + This function retrieves the period of timer interrupts in 100 ns > > +units, > > + returns that value in TimerPeriod, and returns EFI_SUCCESS. If > > +TimerPeriod > > + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod > > +of 0 is > > + returned, then the timer is currently disabled. > > + > > + @param This The EFI_TIMER_ARCH_PROTOCOL instance. > > + @param TimerPeriod A pointer to the timer period to retrieve in 100 > ns units. If > > + 0 is returned, then the timer is currently > > disabled. > > + > > + > > + @retval EFI_SUCCESS The timer period was returned in > TimerPeriod. > > + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +GtiWdtGetTimerPeriod ( > > + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, > > + OUT UINT64 *TimerPeriod > > + ) > > +{ > > + UINT32 Clock; > > + UINT64 CountDown; > > + UINT64 ReturnValue; > > + GTI_CWD_WDOG_UNION Wdog; > > + > > + if (TimerPeriod == NULL) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + Wdog.U64 = MmioRead64 (GTI_CWD_WDOG(0)); > > + > > + // Check if the watchdog is stopped if (Wdog.S.Mode == 0) { > > + // It is stopped, so return zero. > > + ReturnValue = 0; > > + } else { > > + // Convert the Watchdog ticks into TimerPeriod > > + Clock = mSclk / 1000000; //MHz > > + CountDown = Wdog.S.Len << 18; > > + > > + ReturnValue = MultU64x32(DivU64x32(3 * CountDown, Clock), 10); // > > + usecs * 10 } > > + > > + *TimerPeriod = ReturnValue; > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Interface structure for the Watchdog Architectural Protocol. > > + > > + @par Protocol Description: > > + This protocol provides a service to set the amount of time to wait > > + before firing the watchdog timer, and it also provides a service to > > + register a handler that is invoked when the watchdog timer fires. > > + > > + @par When the watchdog timer fires, control will be passed to a > > + handler if one has been registered. If no handler has been > > + registered, or the registered handler returns, then the system will > > + be reset by calling the Runtime Service ResetSystem(). > > + > > + @param RegisterHandler > > + Registers a handler that will be called each time the > > + watchdogtimer interrupt fires. TimerPeriod defines the minimum > > + time between timer interrupts, so TimerPeriod will also be the > > + minimum time between calls to the registered handler. > > + NOTE: If the watchdog resets the system in hardware, then > > + this function will not have any chance of executing. > > + > > + @param SetTimerPeriod > > + Sets the period of the timer interrupt in 100 nS units. > > + This function is optional, and may return EFI_UNSUPPORTED. > > + If this function is supported, then the timer period will be > > + rounded up to the nearest supported timer period. > > + > > + @param GetTimerPeriod > > + Retrieves the period of the timer interrupt in 100 nS units. > > + > > +**/ > > +EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = { > > + (EFI_WATCHDOG_TIMER_REGISTER_HANDLER) GtiWdtRegisterHandler, > > + (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD) GtiWdtSetTimerPeriod, > > + (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD) GtiWdtGetTimerPeriod > }; > > + > > +/** > > + Initialize the state information for the Watchdog Timer Architectural > Protocol. > > + > > + @param ImageHandle of the loaded driver > > + @param SystemTable Pointer to the System Table > > + > > + @retval EFI_SUCCESS Protocol registered > > + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data > structure > > + @retval EFI_DEVICE_ERROR Hardware problems > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +GtiWdtInitialize ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable > > + ) > > +{ > > + EFI_STATUS Status; > > + EFI_HANDLE Handle = NULL; > > + FDT_HANDLE SclkHandle = 0; > > + FDT_HANDLE RootHandle = 0; > > + CONST UINT32 *SclkFreq = NULL; > > + FDT_CLIENT_PROTOCOL *FdtClient = NULL; > > + CONST CHAR8 *Platform; > > + > > + DEBUG ((DEBUG_INFO, "GtiWdtInitialize: Start\n")); // Stop the > > + watchdog from triggering unexpectedly GtiWdtStop (); > > + > > + // > > + // Make sure the Watchdog Timer Architectural Protocol has not been > installed in the system yet. > > + // This will avoid conflicts with the universal watchdog // > > + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, > > + &gEfiWatchdogTimerArchProtocolGuid); > > + > > + Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, > > + NULL, > > + (VOID **)&FdtClient); > > + > > + if (EFI_ERROR (Status) || (FdtClient == NULL)) { > > + DEBUG ((DEBUG_ERROR, "%a: ERROR: cannot locate: > gFdtClientProtocolGuid\n", __func__)); > > + return EFI_ABORTED; > > + } > > + > > + Status = FdtClient->GetNode (FdtClient, "/soc@0/sclk", > > + &SclkHandle); if (EFI_ERROR (Status) || !SclkHandle) { > > + DEBUG ((DEBUG_ERROR, "%a: %s node not found!\n", __func__, > L"/soc@0/sclk")); > > + return EFI_NOT_FOUND; > > + } > > + > > + DEBUG ((DEBUG_INFO, "%a: Found: %s\n", __func__, L"/soc@0/sclk")); > > + Status = FdtClient->GetNodeProperty (FdtClient, > > + SclkHandle, > > + "clock-frequency", > > + (CONST VOID **)&SclkFreq, > > + NULL); if (EFI_ERROR > > + (Status) || NULL == SclkFreq) { > > + DEBUG ((DEBUG_ERROR, "%a: %s property not found!\n", __func__, > L"\"clock-frequency\"")); > > + return EFI_NO_MAPPING; > > + } > > + > > + mSclk = FdtToCpu32(*SclkFreq); > > + DEBUG ((DEBUG_INFO, "%a: DT sclk = %d Mhz (0x%x)\n", __func__, > > + mSclk/1000000, mSclk)); > > + > > + Status = FdtClient->GetNode (FdtClient, "/soc@0", &RootHandle); if > > + (!EFI_ERROR (Status) && RootHandle) { > > + Status = FdtClient->GetNodeProperty (FdtClient, > > + RootHandle, > > + "runplatform", > > + (CONST VOID **)&Platform, > > + NULL); > > + if (!EFI_ERROR (Status)) { > > + if (AsciiStrCmp (Platform, "HW_PLATFORM")) { > > + mHardwarePlatform = FALSE; > > + DEBUG ((DEBUG_INFO, "%a: Not a hardware platform\n", > __func__)); > > + } > > + } > > + } > > + > > + // Register for an ExitBootServicesEvent Status = gBS->CreateEvent > > + (EVT_SIGNAL_EXIT_BOOT_SERVICES, > > + TPL_NOTIFY, > > + GtiExitBootServices, > > + NULL, > > + &mGtiExitBootServicesEvent); > > + ASSERT_EFI_ERROR(Status); > > + > > + // Install the Timer Architectural Protocol onto a new handle > > + Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces( > > + &Handle, > > + &gEfiWatchdogTimerArchProtocolGuid, &gWatchdogTimer, > > + NULL > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + DEBUG ((DEBUG_INFO, "GtiWdtInitialize: Exit\n")); > > + > > + return EFI_SUCCESS; > > +} > > diff --git > > a/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf > > b/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf > > new file mode 100644 > > index 0000000000..f9aa4da246 > > --- /dev/null > > +++ b/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf > > @@ -0,0 +1,45 @@ > > +#/** @file > > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent # > > +https://urldefense.proofpoint.com/v2/url?u=https- > 3A__spdx.org_license > > > +s&d=DwIFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=1o2VA7xKsHvmQ4HFRY2JZ > ggF-gGh1t4 > > > +bxHFABsB1WTo&m=qj9Q626HjLetYIq9pZF97XSPesJ0YDEFI5AB0hT7kZLhI8IB > OoewS_ > > +231IjdayLA&s=Tmg9C1Y51OhHhKeBL7ogbIVncE91tqOli4RO-RyXANM&e= > > +# > > +# Copyright (C) 2022 Marvell > > +# > > +# Module definition file for Marvell Watchdog driver. > > +# > > +#**/ > > + > > +[Defines] > > + INF_VERSION = 0x00010005 > > + BASE_NAME = GtiWatchdogDxe > > + FILE_GUID = 789F5711-6FD3-4170-BE11-EE4000037EA8 > > + MODULE_TYPE = DXE_DRIVER > > + VERSION_STRING = 1.0 > > + > > + ENTRY_POINT = GtiWdtInitialize > > + > > +[Sources.common] > > + GtiWatchdog.c > > + > > +[Packages] > > + Silicon/Marvell/MarvellSiliconPkg/MarvellSiliconPkg.dec > > + MdePkg/MdePkg.dec > > + > > +[LibraryClasses] > > + BaseLib > > + DebugLib > > + IoLib > > + PcdLib > > + UefiLib > > + UefiBootServicesTableLib > > + UefiDriverEntryPoint > > + > > +[FixedPcd] > > + gMarvellSiliconTokenSpaceGuid.PcdGtiWatchdogBase64 > > + > > +[Protocols] > > + gEfiWatchdogTimerArchProtocolGuid #PRODUCES > > + gFdtClientProtocolGuid #CONSUMED > > + > > +[Depex] > > + gFdtClientProtocolGuid > > -- > > 2.34.1 > > > > > > > > > > > > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#113848): https://edk2.groups.io/g/devel/message/113848 Mute This Topic: https://groups.io/mt/103292512/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-