diff --git a/Makefile.am b/Makefile.am index 21e2d0d..0ceb090 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,7 @@ if BOOTLOADER if ARCH_IS_X86 # NOTE: wdat.c is placed first so it is tried before any other drivers +# NOTE: ipcbx21a.c must be *before* itco.c # NOTE: ipc4x7e_wdt.c must be *before* itco.c # NOTE: ipmi_wdt.c must be *before* itco.c efi_sources_watchdogs = \ @@ -170,6 +171,7 @@ efi_sources_watchdogs = \ drivers/watchdog/amdfch_wdt.c \ drivers/watchdog/i6300esb.c \ drivers/watchdog/atom-quark.c \ + drivers/watchdog/ipcbx21a.c \ drivers/watchdog/ipc4x7e_wdt.c \ drivers/watchdog/w83627hf_wdt.c \ drivers/watchdog/ipmi_wdt.c \ diff --git a/drivers/watchdog/ipcbx21a.c b/drivers/watchdog/ipcbx21a.c new file mode 100644 index 0000000..a1b8a9a --- /dev/null +++ b/drivers/watchdog/ipcbx21a.c @@ -0,0 +1,76 @@ +/* + * EFI Boot Guard + * + * Copyright (c) Siemens AG, 2024 + * + * Ported by Cedric Hombourger + * From unpublished code created by XingTong Wu + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include "simatic.h" +#include "utils.h" + +#define WDT_CTRL_REG_BX_21A 0x1854 +#define TIMEOUT_MIN_BX_21A (1) +#define TIMEOUT_DEF_BX_21A (60) +#define TIMEOUT_MAX_BX_21A (1024) +/* Over-Clocking WDT Timeout Value */ +#define WDT_CTRL_REG_TOV_MASK_BX_21A (0x3FF) +/* Over-Clocking WDT ICC Survivability Impact */ +#define WDT_CTRL_REG_ICCSURV_BIT_BX_21A BIT(13) +/* Over-Clocking WDT Enable */ +#define WDT_CTRL_REG_EN_BIT_BX_21A BIT(14) +/* Over-Clocking WDT Force All */ +#define WDT_CTRL_REG_FORCE_ALL_BIT_BX_21A BIT(15) +/* Over-Clocking WDT Non-ICC Survivability Mode Timeout Status */ +#define WDT_CTRL_REG_NO_ICCSURV_STS_BIT_BX_21A BIT(24) +/* Over-Clocking WDT ICC Survivability Mode Timeout Status */ +#define WDT_CTRL_REG_ICCSURV_STS_BIT_BX_21A BIT(25) + +static EFI_STATUS init(EFI_PCI_IO __attribute__((unused)) * pci_io, + UINT16 __attribute__((unused)) pci_vendor_id, + UINT16 __attribute__((unused)) pci_device_id, + UINTN timeout) +{ + UINT32 regval; + + if (simatic_station_id() != SIMATIC_IPCBX_21A) + return EFI_UNSUPPORTED; + + INFO(L"Detected SIMATIC BX-21A watchdog\n"); + + if (timeout < TIMEOUT_MIN_BX_21A || timeout > TIMEOUT_MAX_BX_21A) { + WARNING(L"Invalid timeout value (%d), default (%ds) is used.\n", + timeout, TIMEOUT_DEF_BX_21A); + timeout = TIMEOUT_DEF_BX_21A; + } + + regval = inl(WDT_CTRL_REG_BX_21A); + /* setup timeout value */ + regval &= (~WDT_CTRL_REG_TOV_MASK_BX_21A); + regval |= (timeout - 1); + /* get and clear status */ + regval |= WDT_CTRL_REG_NO_ICCSURV_STS_BIT_BX_21A; + regval |= WDT_CTRL_REG_ICCSURV_STS_BIT_BX_21A; + outl(regval, WDT_CTRL_REG_BX_21A); + + /* start watchdog */ + regval = inl(WDT_CTRL_REG_BX_21A); + regval |= (WDT_CTRL_REG_EN_BIT_BX_21A | + WDT_CTRL_REG_ICCSURV_BIT_BX_21A | + WDT_CTRL_REG_FORCE_ALL_BIT_BX_21A); + outl(regval, WDT_CTRL_REG_BX_21A); + + return EFI_SUCCESS; +} + +WATCHDOG_REGISTER(init); diff --git a/include/simatic.h b/include/simatic.h index 6685045..eed82da 100644 --- a/include/simatic.h +++ b/include/simatic.h @@ -25,6 +25,7 @@ #define SIMATIC_IPC427E 0x0a01 #define SIMATIC_IPC477E 0x0a02 +#define SIMATIC_IPCBX_21A 0x1101 #define SIMATIC_IPCBX_56A 0x1201 #define SIMATIC_IPCBX_59A 0x1202