SIMATIC IPCs 227E/277E share the same external watchdog (SCH5347)
than the IPC 4x7Es we already support. Initialization of the
SAFE_EN_N line differs a bit and was therefore moved to separate
setup functions. Programming and enabling of the timeout is the
same and is now handled in set_timeout(). With this change, both
Linux and efibootguard would use the same chip and no longer
depend on the built-in iTCO watchdog.
Signed-off-by: Cedric Hombourger <
Cedric_H...@mentor.com>
---
drivers/watchdog/ipc4x7e_wdt.c | 126 +++++++++++++++++++++------------
1 file changed, 81 insertions(+), 45 deletions(-)
diff --git a/drivers/watchdog/ipc4x7e_wdt.c b/drivers/watchdog/ipc4x7e_wdt.c
index 24faebe..12a9a87 100644
--- a/drivers/watchdog/ipc4x7e_wdt.c
+++ b/drivers/watchdog/ipc4x7e_wdt.c
@@ -25,6 +25,8 @@
#define SIMATIC_OEM_ENTRY_TYPE_BINARY 0xff
+#define SIMATIC_IPC227E 0x901
+#define SIMATIC_IPC277E 0x902
#define SIMATIC_IPC427E 0xa01
#define SIMATIC_IPC477E 0xa02
@@ -55,6 +57,8 @@ typedef struct {
/* drives SAFE_EN_N */
#define PAD_CFG_DW0_GPP_A_23 0x4b8
#define PAD_CFG_GPIOTXSTATE (1 << 0)
+#define GP_STATUS_REG_227E 0x404D
+#define SAFE_EN_N_227E 0x04
static UINT32 get_station_id(SMBIOS_STRUCTURE_POINTER oem_strct)
{
@@ -134,6 +138,70 @@ static UINT64 get_sbreg_rba(VOID)
return sbreg;
}
+/*
+ * created from linux/drivers/watchdog/simatic-ipc-wdt.c
+ * (submitted upstream but hasn't reached mainline)
+ */
+static VOID setup_2x7E(VOID)
+{
+ UINT16 resetbit;
+
+ /* enable SAFE_EN_N on GP_STATUS_REG_227E */
+ resetbit = inw(GP_STATUS_REG_227E);
+ resetbit &= ~SAFE_EN_N_227E;
+ outw(resetbit, GP_STATUS_REG_227E);
+}
+
+static VOID setup_4x7E(VOID)
+{
+ UINTN pad_cfg;
+
+ /*
+ * Drive SAFE_EN_N low to allow that watchdog can trigger a
+ * hard reset.
+ */
+ pad_cfg = get_sbreg_rba() + (GPIO_COMMUNITY0_PORT_ID << 16) +
+ PAD_CFG_DW0_GPP_A_23;
+ writel(readl(pad_cfg) & ~PAD_CFG_GPIOTXSTATE, pad_cfg);
+}
+
+static void set_timeout(UINTN timeout)
+{
+ UINT8 val;
+
+ if (timeout <= 2) {
+ val = 0 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 4) {
+ val = 1 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 6) {
+ val = 2 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 8) {
+ val = 3 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 16) {
+ val = 4 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 32) {
+ val = 5 << SIMATIC_WD_SCALER_SHIFT;
+ } else if (timeout <= 48) {
+ val = 6 << SIMATIC_WD_SCALER_SHIFT;
+ } else {
+ val = 7 << SIMATIC_WD_SCALER_SHIFT;
+ }
+ val |= SIMATIC_WD_MACRO_MOD;
+ if (inb(SIMATIC_WD_ENABLE_REG) & SIMATIC_WD_TRIGGERED) {
+ Print(L"NOTE: Detected watchdog triggered reboot\n");
+ /* acknowledge, turning off the LED */
+ val |= SIMATIC_WD_TRIGGERED;
+ }
+ outb(val, SIMATIC_WD_ENABLE_REG);
+
+ /* Enable the watchdog after programming it, just to be safe. */
+ val |= SIMATIC_WD_ENABLE;
+ outb(val, SIMATIC_WD_ENABLE_REG);
+
+ /* Trigger the watchdog once. Now the clock ticks. */
+ inb(SIMATIC_WD_TRIGGER_REG);
+}
+
static EFI_STATUS __attribute__((constructor))
init(EFI_PCI_IO *pci_io, UINT16 pci_vendor_id, UINT16 pci_device_id,
UINTN timeout)
@@ -141,13 +209,6 @@ init(EFI_PCI_IO *pci_io, UINT16 pci_vendor_id, UINT16 pci_device_id,
SMBIOS_STRUCTURE_TABLE *smbios_table;
SMBIOS_STRUCTURE_POINTER smbios_struct;
EFI_STATUS status;
- UINTN pad_cfg;
- UINT8 val;
-
- if (!pci_io || pci_vendor_id != PCI_VENDOR_ID_INTEL ||
- pci_device_id != PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_LPC) {
- return EFI_UNSUPPORTED;
- }
status = LibGetSystemConfigurationTable(&SMBIOSTableGuid,
(VOID **)&smbios_table);
@@ -161,50 +222,25 @@ init(EFI_PCI_IO *pci_io, UINT16 pci_vendor_id, UINT16 pci_device_id,
}
switch (get_station_id(smbios_struct)) {
+ case SIMATIC_IPC227E:
+ case SIMATIC_IPC277E:
+ Print(L"Detected SIMATIC IPC2x7E watchdog\n");
+
+ setup_2x7E();
+ set_timeout(timeout);
+ return EFI_SUCCESS;
+
case SIMATIC_IPC427E:
case SIMATIC_IPC477E:
Print(L"Detected SIMATIC IPC4x7E watchdog\n");
- /*
- * Drive SAFE_EN_N low to allow that watchdog can trigger a
- * hard reset.
- */
- pad_cfg = get_sbreg_rba() + (GPIO_COMMUNITY0_PORT_ID << 16) +
- PAD_CFG_DW0_GPP_A_23;
- writel(readl(pad_cfg) & ~PAD_CFG_GPIOTXSTATE, pad_cfg);
-
- if (timeout <= 2) {
- val = 0 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 4) {
- val = 1 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 6) {
- val = 2 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 8) {
- val = 3 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 16) {
- val = 4 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 32) {
- val = 5 << SIMATIC_WD_SCALER_SHIFT;
- } else if (timeout <= 48) {
- val = 6 << SIMATIC_WD_SCALER_SHIFT;
- } else {
- val = 7 << SIMATIC_WD_SCALER_SHIFT;
+ if (!pci_io || pci_vendor_id != PCI_VENDOR_ID_INTEL ||
+ pci_device_id != PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_LPC) {
+ return EFI_UNSUPPORTED;
}
- val |= SIMATIC_WD_MACRO_MOD;
- if (inb(SIMATIC_WD_ENABLE_REG) & SIMATIC_WD_TRIGGERED) {
- Print(L"NOTE: Detected watchdog triggered reboot\n");
- /* acknowledge, turning off the LED */
- val |= SIMATIC_WD_TRIGGERED;
- }
- outb(val, SIMATIC_WD_ENABLE_REG);
-
- /* Enable the watchdog after programming it, just to be safe. */
- val |= SIMATIC_WD_ENABLE;
- outb(val, SIMATIC_WD_ENABLE_REG);
-
- /* Trigger the watchdog once. Now the clock ticks. */
- inb(SIMATIC_WD_TRIGGER_REG);
+ setup_4x7E();
+ set_timeout(timeout);
return EFI_SUCCESS;
default:
--
2.30.2