From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 210B5AC12AD for ; Fri, 12 Jan 2024 11:34:50 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=pHdn3CyHm/uyAqfRpU+CK2VybOl6y4Cnhatu/Rd0a3Q=; c=relaxed/simple; d=groups.io; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject:To:Cc:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Transfer-Encoding; s=20140610; t=1705059289; v=1; b=cGVvbEVVXHpikKjofndw3ngRGGl1bPPcjQuR0hwHv/JiB9beKZDBLHsaezfI/AePKiarNl4O JNmml4C8dtC99MddscYm6YB6ttPXUna+hVPObdRt66o3oeTX2Zr8RmWUlBANuscgqcMvInY0Bb+ FNw8GLLW0JeL2RbcVCZoYXHc= X-Received: by 127.0.0.2 with SMTP id jj4EYY7687511xT93ooqcC4P; Fri, 12 Jan 2024 03:34:49 -0800 X-Received: from mail-oo1-f41.google.com (mail-oo1-f41.google.com [209.85.161.41]) by mx.groups.io with SMTP id smtpd.web10.5204.1705059289012979250 for ; Fri, 12 Jan 2024 03:34:49 -0800 X-Received: by mail-oo1-f41.google.com with SMTP id 006d021491bc7-5989e464910so1439840eaf.0 for ; Fri, 12 Jan 2024 03:34:48 -0800 (PST) X-Gm-Message-State: 9sHhg91NYKVg4ML2jXmpggVYx7686176AA= X-Google-Smtp-Source: AGHT+IHByEWCuI8ztTsn07VN8d1owK8zY/mmmji3N8gaKmXwrDENnhLIbOhbsuzcrK6ut9WP36rwTeBUyObSqCWlM+Q= X-Received: by 2002:a4a:241e:0:b0:598:b695:688a with SMTP id m30-20020a4a241e000000b00598b695688amr530172oof.8.1705059288139; Fri, 12 Jan 2024 03:34:48 -0800 (PST) MIME-Version: 1.0 References: <20231221005427.13932-1-ndhillon@marvell.com> <20231221005427.13932-5-ndhillon@marvell.com> In-Reply-To: <20231221005427.13932-5-ndhillon@marvell.com> From: "Marcin Wojtas via groups.io" Date: Fri, 12 Jan 2024 12:34:38 +0100 Message-ID: Subject: Re: [edk2-devel] [edk2-platforms PATCH v2 4/8] Silicon/Marvell: Odyssey watchdog driver To: devel@edk2.groups.io, ndhillon@marvell.com Cc: Leif Lindholm , marcin.s.wojtas@gmail.com, Szymon Balcerak Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,mw@semihalf.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=cGVvbEVV; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io +marcin.s.wojtas@gmail.com Hi Narinder czw., 21 gru 2023 o 01:54 Narinder Dhillon napisa=C5= =82(a): > > From: Narinder Dhillon > > 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://github.com/tianocore/edk2/pull/5176/commits) Best regards, Marcin > > Signed-off-by: Narinder Dhillon > --- > .../Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c | 408 ++++++++++++++++++ > .../Wdt/GtiWatchdogDxe/GtiWatchdogDxe.inf | 45 ++ > 2 files changed, 453 insertions(+) > create mode 100644 Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdo= g.c > create mode 100644 Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdo= gDxe.inf > > diff --git a/Silicon/Marvell/Drivers/Wdt/GtiWatchdogDxe/GtiWatchdog.c b/S= ilicon/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://spdx.org/licenses > +* > +* Copyright (C) 2022 Marvell > +* > +* Source file for Marvell Watchdog driver > +* > +**/ > + > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#define GTI_CWD_WDOG(Core) (FixedPcdGet64(PcdGtiWatchdogBase64) + 0x4= 0000 + Core * 0x8) > +#define GTI_CWD_POKE(Core) (FixedPcdGet64(PcdGtiWatchdogBase64) + 0x5= 0000 + 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 =3D (EFI_EVENT)NULL; > +UINT32 mSclk =3D 0; > +BOOLEAN mHardwarePlatform =3D 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 =3D MmioRead64(GTI_CWD_WDOG(0)); > + > + // Disable WDT > + if (Wdog.S.Mode !=3D 0) { > + Wdog.S.Len =3D 1; > + Wdog.S.Mode =3D 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 =3D MmioRead64 (GTI_CWD_WDOG(0)); > + > + // Enable countdown > + if (Wdog.S.Mode =3D=3D 0) { > + Wdog.S.Mode =3D 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 eve= ry time > + the watchdog timer expires. It also passes the amount of time since t= he 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 re= gistered, > + then EFI_INVALID_PARAMETER is returned. > + > + @param This The EFI_TIMER_ARCH_PROTOCOL instance. > + @param NotifyFunction The function to call when a timer interrupt f= ires. This > + function executes at TPL_HIGH_LEVEL. The DXE = Core will > + register a handler for the timer interrupt, s= o it can know > + how much time has passed. This information is= used to > + signal timer based events. NULL will unregist= er the handler. > + > + @retval EFI_SUCCESS The watchdog timer handler was registere= d. > + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handle= r is already > + registered. > + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler wa= s 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 spec= ified > + by TimerPeriod. If the timer period is updated, then the selected tim= er > + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned= . If > + the timer hardware is not programmable, then EFI_UNSUPPORTED is return= ed. > + If an error occurs while attempting to update the timer period, then t= he > + 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 int= errupt > + 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 10= 0 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 perio= d 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 du= e 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 =3D=3D 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 =3D mSclk / 1000000; //MHz > + CountDown =3D DivU64x32 (MultU64x32 (TimerPeriod, Clock), 30); > + > + // WDT counts in 1024 cycle steps > + // Only upper 16 bits can be used > + > + Wdog.U64 =3D 0; > + Wdog.S.Len =3D (CountDown + (0xFF << 10)) >> 18; > + MmioWrite64 (GTI_CWD_WDOG(0), Wdog.U64); > + > + // Start the watchdog > + if (mHardwarePlatform =3D=3D 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 TimerP= eriod > + 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 di= sabled. > + > + > + @retval EFI_SUCCESS The timer period was returned in TimerPe= riod. > + @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 =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Wdog.U64 =3D MmioRead64 (GTI_CWD_WDOG(0)); > + > + // Check if the watchdog is stopped > + if (Wdog.S.Mode =3D=3D 0) { > + // It is stopped, so return zero. > + ReturnValue =3D 0; > + } else { > + // Convert the Watchdog ticks into TimerPeriod > + Clock =3D mSclk / 1000000; //MHz > + CountDown =3D Wdog.S.Len << 18; > + > + ReturnValue =3D MultU64x32(DivU64x32(3 * CountDown, Clock), 10); // = usecs * 10 > + } > + > + *TimerPeriod =3D 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 handle= r > + 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 =3D { > + (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 =3D NULL; > + FDT_HANDLE SclkHandle =3D 0; > + FDT_HANDLE RootHandle =3D 0; > + CONST UINT32 *SclkFreq =3D NULL; > + FDT_CLIENT_PROTOCOL *FdtClient =3D 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 in= stalled in the system yet. > + // This will avoid conflicts with the universal watchdog > + // > + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtoco= lGuid); > + > + Status =3D gBS->LocateProtocol (&gFdtClientProtocolGuid, > + NULL, > + (VOID **)&FdtClient); > + > + if (EFI_ERROR (Status) || (FdtClient =3D=3D NULL)) { > + DEBUG ((DEBUG_ERROR, "%a: ERROR: cannot locate: gFdtClientProtocolGu= id\n", __func__)); > + return EFI_ABORTED; > + } > + > + Status =3D 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 =3D FdtClient->GetNodeProperty (FdtClient, > + SclkHandle, > + "clock-frequency", > + (CONST VOID **)&SclkFreq, > + NULL); > + if (EFI_ERROR (Status) || NULL =3D=3D SclkFreq) { > + DEBUG ((DEBUG_ERROR, "%a: %s property not found!\n", __func__, L"\"c= lock-frequency\"")); > + return EFI_NO_MAPPING; > + } > + > + mSclk =3D FdtToCpu32(*SclkFreq); > + DEBUG ((DEBUG_INFO, "%a: DT sclk =3D %d Mhz (0x%x)\n", __func__, mSclk= /1000000, mSclk)); > + > + Status =3D FdtClient->GetNode (FdtClient, "/soc@0", &RootHandle); > + if (!EFI_ERROR (Status) && RootHandle) { > + Status =3D FdtClient->GetNodeProperty (FdtClient, > + RootHandle, > + "runplatform", > + (CONST VOID **)&Platform, > + NULL); > + if (!EFI_ERROR (Status)) { > + if (AsciiStrCmp (Platform, "HW_PLATFORM")) { > + mHardwarePlatform =3D FALSE; > + DEBUG ((DEBUG_INFO, "%a: Not a hardware platform\n", __func__)); > + } > + } > + } > + > + // Register for an ExitBootServicesEvent > + Status =3D 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 =3D NULL; > + Status =3D 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.in= f 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://spdx.org/licenses > +# > +# Copyright (C) 2022 Marvell > +# > +# Module definition file for Marvell Watchdog driver. > +# > +#**/ > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D GtiWatchdogDxe > + FILE_GUID =3D 789F5711-6FD3-4170-BE11-EE4000037EA= 8 > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D 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 > > > >=20 > > -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#113714): https://edk2.groups.io/g/devel/message/113714 Mute This Topic: https://groups.io/mt/103292512/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-