From nobody Mon May 6 11:00:54 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail(p=none dis=none) header.from=nxp.com Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1524040966278561.9328713163482; Wed, 18 Apr 2018 01:42:46 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 3B00F2265A177; Wed, 18 Apr 2018 01:42:45 -0700 (PDT) Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id F0CB12263DD94 for ; Wed, 18 Apr 2018 01:42:43 -0700 (PDT) Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id A525E1A0107; Wed, 18 Apr 2018 10:42:41 +0200 (CEST) Received: from inv0113.in-blr01.nxp.com (inv0113.in-blr01.nxp.com [165.114.116.118]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 09E861A000C; Wed, 18 Apr 2018 10:42:41 +0200 (CEST) Received: from uefi-OptiPlex-790.ap.freescale.net (uefi-OptiPlex-790.ap.freescale.net [10.232.132.78]) by inv0113.in-blr01.nxp.com (Postfix) with ESMTP id 1691C33F; Wed, 18 Apr 2018 14:12:40 +0530 (IST) X-Original-To: edk2-devel@lists.01.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=92.121.34.13; helo=inva020.nxp.com; envelope-from=meenakshi.aggarwal@nxp.com; receiver=edk2-devel@lists.01.org From: Meenakshi Aggarwal To: ard.biesheuvel@linaro.org, leif.lindholm@linaro.org, michael.d.kinney@intel.com, lersek@redhat.com, edk2-devel@lists.01.org Date: Wed, 18 Apr 2018 19:59:58 +0530 Message-Id: <1524061798-3331-2-git-send-email-meenakshi.aggarwal@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1524061798-3331-1-git-send-email-meenakshi.aggarwal@nxp.com> References: <1524061798-3331-1-git-send-email-meenakshi.aggarwal@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Subject: [edk2] [PATCH edk2-platforms [Changes Suggested by Leif]] Silicon/NXP : Add support for Watchdog driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Installs watchdog timer arch protocol Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Meenakshi Aggarwal --- Silicon/NXP/Drivers/WatchDog/WatchDog.c | 422 +++++++++++++++++++++++= ++++ Silicon/NXP/Drivers/WatchDog/WatchDog.h | 46 +++ Silicon/NXP/Drivers/WatchDog/WatchDogDxe.inf | 47 +++ 3 files changed, 515 insertions(+) create mode 100644 Silicon/NXP/Drivers/WatchDog/WatchDog.c create mode 100644 Silicon/NXP/Drivers/WatchDog/WatchDog.h create mode 100644 Silicon/NXP/Drivers/WatchDog/WatchDogDxe.inf diff --git a/Silicon/NXP/Drivers/WatchDog/WatchDog.c b/Silicon/NXP/Drivers/= WatchDog/WatchDog.c new file mode 100644 index 0000000..9d73823 --- /dev/null +++ b/Silicon/NXP/Drivers/WatchDog/WatchDog.c @@ -0,0 +1,422 @@ +/** WatchDog.c +* +* Based on Watchdog driver implemenation available in +* ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c +* +* Copyright 2017 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "WatchDog.h" + +STATIC EFI_EVENT EfiExitBootServicesEvent; +STATIC EFI_EVENT WdogFeedEvent; +STATIC WDOG_OPERATION WdogOps; + +STATIC +VOID +SetUpWdogOps ( + ) +{ + if (FixedPcdGetBool (PcdWdogBigEndian)) { + WdogOps.WdogRead =3D BeMmioRead16; + WdogOps.WdogWrite =3D BeMmioWrite16; + WdogOps.WdogAndThenOr=3D BeMmioAndThenOr16; + WdogOps.WdogOr =3D BeMmioOr16; + } else { + WdogOps.WdogRead =3D MmioRead16; + WdogOps.WdogWrite =3D MmioWrite16; + WdogOps.WdogAndThenOr=3D MmioAndThenOr16; + WdogOps.WdogOr =3D MmioOr16; + } + + return; +} + +STATIC +VOID +WdogPing ( + VOID + ) +{ + // + // To reload a timeout value to the counter the proper service sequence = begins by + // writing 0x_5555 followed by 0x_AAAA to the Watchdog Service Register = (WDOG_WSR). + // This service sequence will reload the counter with the timeout value = WT[7:0] of + // Watchdog Control Register (WDOG_WCR). + // + + WdogOps.WdogWrite (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WSR_OFFSET, + WDOG_SERVICE_SEQ1); + WdogOps.WdogWrite (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WSR_OFFSET, + WDOG_SERVICE_SEQ2); +} + +/** + Stop the Wdog watchdog timer from counting down. +**/ +STATIC +VOID +WdogStop ( + VOID + ) +{ + // Watchdog cannot be disabled by software once started. + // At best, we can keep reload counter with maximum value + + WdogOps.WdogAndThenOr (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFSET, + (UINT16)(~WDOG_WCR_WT), + (WD_COUNT (WT_MAX_TIME) & WD_COUNT_MASK)); + WdogPing (); +} + +/** + Starts the Wdog counting down by feeding Service register with + desired pattern. + The count down will start from the value stored in the Load register, + not from the value where it was previously stopped. +**/ +STATIC +VOID +WdogStart ( + VOID + ) +{ + //Reload the timeout value + WdogPing (); +} + +/** + On exiting boot services we must make sure the Wdog Watchdog Timer + is stopped. +**/ +STATIC +VOID +EFIAPI +ExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + WdogStop (); +} + +/** + 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 re= gistered, + then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not regi= stered, + then EFI_INVALID_PARAMETER is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fir= es. This + function executes at TPL_HIGH_LEVEL. The DXE Co= re will + register a handler for the timer interrupt, so = it can know + how much time has passed. This information is u= sed 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +WdogRegisterHandler ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction + ) +{ + // ERROR: This function is not supported. + // The hardware watchdog will reset the board + return EFI_INVALID_PARAMETER; +} + +/** + + This function adjusts the period of timer interrupts to the value specif= ied + 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 inter= rupt + 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 t= he + interrupt controller so that a CPU interrupt is not generated when the t= imer + 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 EF= I_UNSUPPORTED is + returned. If the timer is programmable, then th= e 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 t= he timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due = to a device error. + +**/ +STATIC +EFI_STATUS +EFIAPI +WdogSetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod // In 100ns units + ) +{ + EFI_STATUS Status; + UINT64 TimerPeriodInSec; + UINT16 Val; + + Status =3D EFI_SUCCESS; + + if (TimerPeriod =3D=3D 0) { + // This is a watchdog stop request + WdogStop (); + return Status; + } else { + // Convert the TimerPeriod (in 100 ns unit) to an equivalent second va= lue + + TimerPeriodInSec =3D DivU64x32 (TimerPeriod, NANO_SECOND_BASE); + + // The registers in the Wdog are only 32 bits + if (TimerPeriodInSec > WT_MAX_TIME) { + // We could load the watchdog with the maximum supported value but + // if a smaller value was requested, this could have the watchdog + // triggering before it was intended. + // Better generate an error to let the caller know. + Status =3D EFI_DEVICE_ERROR; + return Status; + } + + // set the new timeout value in the WCR + // Convert the timeout value from Seconds to timer count + Val =3D ((WD_COUNT(TimerPeriodInSec) & WD_COUNT_MASK) << 8); + + WdogOps.WdogAndThenOr (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFSET, + (UINT16)(~WDOG_WCR_WT), + Val); + // Start the watchdog + WdogStart (); + } + + return Status; +} + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPer= iod + 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 10= 0 ns units. If + 0 is returned, then the timer is currently disa= bled. + + + @retval EFI_SUCCESS The timer period was returned in TimerPeri= od. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +WdogGetTimerPeriod ( + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + EFI_STATUS Status; + UINT64 ReturnValue; + UINT16 Val; + + Status =3D EFI_SUCCESS; + + if (TimerPeriod =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check if the watchdog is stopped + if ((WdogOps.WdogRead (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFSET) + & WDOG_WCR_WDE) =3D=3D 0 ) { + // It is stopped, so return zero. + ReturnValue =3D 0; + } else { + // Convert the Watchdog ticks into equivalent TimerPeriod second value. + Val =3D (WdogOps.WdogRead (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFS= ET) + & WDOG_WCR_WT ) >> 8; + ReturnValue =3D WD_SEC(Val); + } + + *TimerPeriod =3D ReturnValue; + return Status; +} + +/** + 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. + +**/ +STATIC +EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer =3D { + WdogRegisterHandler, + WdogSetTimerPeriod, + WdogGetTimerPeriod +}; + +/** + Call back function when the timer event is signaled. + This function will feed the watchdog with maximum value + so that system wont reset in idle case e.g. stopped on UEFI shell. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +WdogFeed ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + WdogPing(); +} +/** + Initialize state information for the Watchdog Timer Architectural Protoc= ol. + + @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 +WdogInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + SetUpWdogOps (); + + WdogOps.WdogAndThenOr (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFSET, + (UINT16)(~WDOG_WCR_WT), + (WD_COUNT (WT_MAX_TIME) & WD_COUNT_MASK)); + + WdogOps.WdogOr (PcdGet64 (PcdWdog1BaseAddr) + WDOG_WCR_OFFSET, WDOG_WCR_= WDE); + + // + // 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, &gEfiWatchdogTimerArchProtocolG= uid); + + // Register for an ExitBootServicesEvent + Status =3D gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, + ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); + if (EFI_ERROR (Status)) { + Status =3D EFI_OUT_OF_RESOURCES; + return Status; + } + + // + // Start the timer to feed Watchdog with maximum timeout value. + // + Status =3D gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + WdogFeed, + NULL, + &WdogFeedEvent + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->SetTimer (WdogFeedEvent, TimerPeriodic, WT_FEED_INTERVAL= ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Install the Timer Architectural Protocol onto a new handle + Handle =3D NULL; + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiWatchdogTimerArchProtocolGuid, &gWatchdogTimer, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (EfiExitBootServicesEvent); + Status =3D EFI_OUT_OF_RESOURCES; + return Status; + } + + WdogPing (); + + return Status; +} diff --git a/Silicon/NXP/Drivers/WatchDog/WatchDog.h b/Silicon/NXP/Drivers/= WatchDog/WatchDog.h new file mode 100644 index 0000000..81d9329 --- /dev/null +++ b/Silicon/NXP/Drivers/WatchDog/WatchDog.h @@ -0,0 +1,46 @@ +/** WatchDog.h +* +* Copyright 2017 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#ifndef __WATCHDOG_H__ +#define __WATCHDOG_H__ + +#define WDOG_SIZE 0x1000 +#define WDOG_WCR_OFFSET 0 +#define WDOG_WSR_OFFSET 2 +#define WDOG_WRSR_OFFSET 4 +#define WDOG_WICR_OFFSET 6 +#define WDOG_WCR_WT (0xFF << 8) +#define WDOG_WCR_WDE (1 << 2) +#define WDOG_SERVICE_SEQ1 0x5555 +#define WDOG_SERVICE_SEQ2 0xAAAA +#define WDOG_WCR_WDZST 0x1 +#define WDOG_WCR_WRE (1 << 3) /* -> WDOG Reset Enable */ + +#define WT_MAX_TIME 128 +#define WD_COUNT(Sec) (((Sec) * 2 - 1) << 8) +#define WD_COUNT_MASK 0xff00 +#define WD_SEC(Cnt) (((Cnt) + 1) / 2) + +#define NANO_SECOND_BASE 10000000 + +#define WT_FEED_INTERVAL (WT_MAX_TIME * NANO_SECOND_BASE) + +typedef struct { + UINT16 (*WdogRead) (UINTN Address); + UINT16 (*WdogWrite) (UINTN Address, UINT16 Value); + UINT16 (*WdogAndThenOr) (UINTN Address, UINT16 And, UINT16 Or); + UINT16 (*WdogOr) (UINTN Address, UINT16 Or); + } WDOG_OPERATION; + +#endif //__WATCHDOG_H__ diff --git a/Silicon/NXP/Drivers/WatchDog/WatchDogDxe.inf b/Silicon/NXP/Dri= vers/WatchDog/WatchDogDxe.inf new file mode 100644 index 0000000..e6c06ef --- /dev/null +++ b/Silicon/NXP/Drivers/WatchDog/WatchDogDxe.inf @@ -0,0 +1,47 @@ +# WatchDog.inf +# +# Component description file for WatchDog module +# +# Copyright 2017 NXP +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may = be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +# +# + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D WatchDogDxe + FILE_GUID =3D 0358b544-ec65-4339-89cd-cad60a3dd787 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D WdogInitialize + +[Sources.common] + WatchDog.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/NXP/NxpQoriqLs.dec + +[LibraryClasses] + BaseLib + BeIoLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Pcd] + gNxpQoriqLsTokenSpaceGuid.PcdWdog1BaseAddr + gNxpQoriqLsTokenSpaceGuid.PcdWdogBigEndian + +[Protocols] + gEfiWatchdogTimerArchProtocolGuid + +[Depex] + TRUE --=20 1.9.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel