diff --git a/src/coreboot/default.nix b/src/coreboot/default.nix index c837b51..eb417d7 100644 --- a/src/coreboot/default.nix +++ b/src/coreboot/default.nix @@ -109,6 +109,7 @@ stdenv.mkDerivation { ./patches/0004-superio-winbond-w83667hg-a-superio.c-do-not-use-get_.patch ./patches/0001-romstage-print-out-dimm-voltages.patch ./patches/0002-kgpe-d16-do-not-enable-hw-monitor-until-kernel-boots.patch + ./patches/0026-kgpe-d16-start-w83667hg-a-watchdog-during-romstage.patch # am1i patches ./patches/0021-am1i-omit-amdfw.rom-completely-it-has-broken-address.patch diff --git a/src/coreboot/patches/0026-kgpe-d16-start-w83667hg-a-watchdog-during-romstage.patch b/src/coreboot/patches/0026-kgpe-d16-start-w83667hg-a-watchdog-during-romstage.patch new file mode 100644 index 0000000..b2ae2af --- /dev/null +++ b/src/coreboot/patches/0026-kgpe-d16-start-w83667hg-a-watchdog-during-romstage.patch @@ -0,0 +1,254 @@ +From d320221a74a641712d97066d616b81df5a1fb3c1 Mon Sep 17 00:00:00 2001 +From: Your Name +Date: Sun, 11 Jun 2023 22:18:37 -0700 +Subject: [PATCH] kgpe-d16: start w83667hg-a watchdog during romstage + +--- + src/mainboard/asus/kgpe-d16/Kconfig | 1 + + src/mainboard/asus/kgpe-d16/devicetree.cb | 2 +- + src/mainboard/asus/kgpe-d16/mainboard.c | 12 +++++ + src/mainboard/asus/kgpe-d16/romstage.c | 12 +++++ + src/superio/winbond/Makefile.inc | 1 + + src/superio/winbond/common/early_init.c | 53 ++++++++++++++++++++++- + src/superio/winbond/common/winbond.h | 1 + + src/superio/winbond/w83667hg-a/superio.c | 27 ++++++++++++ + 8 files changed, 106 insertions(+), 3 deletions(-) + +diff --git a/src/mainboard/asus/kgpe-d16/Kconfig b/src/mainboard/asus/kgpe-d16/Kconfig +index c6b2de3ab92..3660b7c644b 100644 +--- a/src/mainboard/asus/kgpe-d16/Kconfig ++++ b/src/mainboard/asus/kgpe-d16/Kconfig +@@ -32,6 +32,7 @@ config BOARD_SPECIFIC_OPTIONS + select DRIVERS_ASPEED_AST2050 + select MAINBOARD_FORCE_NATIVE_VGA_INIT + select MAINBOARD_HAS_NATIVE_VGA_INIT ++ select USE_WATCHDOG_ON_BOOT + + config MAINBOARD_DIR + string +diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb b/src/mainboard/asus/kgpe-d16/devicetree.cb +index ff2023ddd05..3be328d1725 100644 +--- a/src/mainboard/asus/kgpe-d16/devicetree.cb ++++ b/src/mainboard/asus/kgpe-d16/devicetree.cb +@@ -199,7 +199,7 @@ chip northbridge/amd/amdfam10/root_complex # Root complex + device pnp 2e.207 off end # GIPO7 + device pnp 2e.307 off end # GIPO8 + device pnp 2e.407 off end # GIPO9 +- device pnp 2e.8 off end # WDT ++ device pnp 2e.8 on end # WDT + device pnp 2e.108 off end # GPIO 1 + device pnp 2e.9 off end # GPIO2 + device pnp 2e.109 off end # GPIO3 +diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c b/src/mainboard/asus/kgpe-d16/mainboard.c +index 14a4a697620..8d377cafa95 100644 +--- a/src/mainboard/asus/kgpe-d16/mainboard.c ++++ b/src/mainboard/asus/kgpe-d16/mainboard.c +@@ -21,8 +21,12 @@ + #include + #include + #include ++#include + #include + #include ++#include ++#include ++#include + + void set_pcie_reset(void) + { +@@ -110,3 +114,11 @@ void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5) + struct chip_operations mainboard_ops = { + .enable_dev = mainboard_enable, + }; ++ ++#define PNP_DEV(PORT, FUNC) (((PORT) << 8) | (FUNC)) ++#define WDT_DEV PNP_DEV(0x2e, W83667HG_A_WDT1) ++#define ACPI_DEV PNP_DEV(0x2e, W83667HG_A_ACPI) ++void watchdog_off(void); ++void watchdog_off(void) { ++ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 0); ++} +diff --git a/src/mainboard/asus/kgpe-d16/romstage.c b/src/mainboard/asus/kgpe-d16/romstage.c +index 88fa60d2d1f..81a5bf5d67d 100644 +--- a/src/mainboard/asus/kgpe-d16/romstage.c ++++ b/src/mainboard/asus/kgpe-d16/romstage.c +@@ -53,6 +53,8 @@ + + #define SERIAL_0_DEV PNP_DEV(0x2e, W83667HG_A_SP1) + #define SERIAL_1_DEV PNP_DEV(0x2e, W83667HG_A_SP2) ++#define WDT_DEV PNP_DEV(0x2e, W83667HG_A_WDT1) ++#define ACPI_DEV PNP_DEV(0x2e, W83667HG_A_ACPI) + + void activate_spd_rom(const struct mem_controller *ctrl); + int spd_read_byte(unsigned int device, unsigned int address); +@@ -530,6 +532,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) + byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0x78); + byte &= ~(1 << 0); + pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte); ++ ++ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 40); + } + + printk(BIOS_SPEW, "Initial stack pointer: %08x\n", esp); +@@ -681,6 +685,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) + + post_code(0x40); + ++ if (!cpu_init_detectedx && boot_cpu()) { ++ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 60); ++ } ++ printk(BIOS_ERR, "initializing dram...\n"); + timestamp_add_now(TS_BEFORE_INITRAM); + printk(BIOS_DEBUG, "raminit_amdmct()\n"); + raminit_amdmct(sysinfo); +@@ -712,6 +720,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) + pci_write_config16(PCI_DEV(0, 0x14, 0), 0x54, 0x0707); + pci_write_config16(PCI_DEV(0, 0x14, 0), 0x56, 0x0bb0); + pci_write_config16(PCI_DEV(0, 0x14, 0), 0x5a, 0x0ff0); ++ ++ if (!cpu_init_detectedx && boot_cpu()) { ++ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 60); ++ } + } + + /** +diff --git a/src/superio/winbond/Makefile.inc b/src/superio/winbond/Makefile.inc +index b0b7b8c5202..0502441a2f0 100644 +--- a/src/superio/winbond/Makefile.inc ++++ b/src/superio/winbond/Makefile.inc +@@ -15,6 +15,7 @@ + + ## include generic winbond pre-ram stage driver + romstage-$(CONFIG_SUPERIO_WINBOND_COMMON_ROMSTAGE) += common/early_init.c ++ramstage-$(CONFIG_SUPERIO_WINBOND_COMMON_ROMSTAGE) += common/early_init.c + + subdirs-y += w83627dhg + subdirs-y += w83627ehg +diff --git a/src/superio/winbond/common/early_init.c b/src/superio/winbond/common/early_init.c +index 7c3ce2b3a56..ba3cbb2a34f 100644 +--- a/src/superio/winbond/common/early_init.c ++++ b/src/superio/winbond/common/early_init.c +@@ -33,9 +33,13 @@ + * + */ + +-#include +-#include ++#define __SIMPLE_DEVICE__ ++#include ++#include + #include ++#include ++#include ++#include + #include "winbond.h" + + #define WINBOND_ENTRY_KEY 0x87 +@@ -56,6 +60,51 @@ void pnp_exit_conf_state(pnp_devfn_t dev) + outb(WINBOND_EXIT_KEY, port); + } + ++void winbond_enable_watchdog(pnp_devfn_t dev, pnp_devfn_t dev_acpi, u8 seconds) ++{ ++#if IS_ENABLED(CONFIG_USE_WATCHDOG_ON_BOOT) ++ u8 byte; ++ ++ // ACPI device: set EN_WDT2PWROK //////////////////// ++ ++ pnp_enter_conf_state(dev_acpi); ++ pnp_set_logical_device(dev_acpi); ++ pnp_set_enable(dev_acpi, 1); ++ byte = pnp_read_config(dev_acpi, 0xf2); ++ byte |= (1<<7); // EN_WDT2PWROK = Enable PWROK0,1 or 2 pin drive pulse by WDTO ++ pnp_write_config(dev_acpi, 0xf2, byte); ++ pnp_exit_conf_state(dev_acpi); ++ ++ // WDT device: enable timer //////////////////// ++ ++ pnp_enter_conf_state(dev); ++ pnp_set_logical_device(dev); ++ pnp_set_enable(dev, 1); ++ ++ byte = pnp_read_config(dev, 0xf5); ++ byte &= ~0x4e; ++ //byte |= 0x1 << 4; // count 1000 times faster than usual (i.e. milliseconds/milliminutes) ++ //byte |= 0x1 << 3; // count in minutes rather than seconds ++ byte |= 0x1 << 1; // Enable the WDTO# output low pulse to the KBRST# pin (PIN28) ++ pnp_write_config(dev, 0xf5, byte); ++ ++ byte = pnp_read_config(dev, 0xf7); ++ byte &= ~0xc0; // keyboard/mouse interrupts do not reset WDT ++ pnp_write_config(dev, 0xf7, byte); ++ ++ // watchdog timer value in seconds; countdown starts ++ // immediately.; write 0 to disable counter. ++ pnp_write_config(dev, 0xf6, seconds); ++ ++ pnp_exit_conf_state(dev); ++ if (seconds == 0) { ++ printk(BIOS_ERR, "stopped W83667HG-A watchdog.\n"); ++ } else { ++ printk(BIOS_ERR, "started W83667HG-A watchdog; you have %d seconds to disable it with: modprobe w83627hf_wdt; echo -n V > /dev/watchdog\n", seconds); ++ } ++#endif ++} ++ + /* Bring up early serial debugging output before the RAM is initialized. */ + void winbond_enable_serial(pnp_devfn_t dev, u16 iobase) + { +diff --git a/src/superio/winbond/common/winbond.h b/src/superio/winbond/common/winbond.h +index e472018bf19..87aa32ae46d 100644 +--- a/src/superio/winbond/common/winbond.h ++++ b/src/superio/winbond/common/winbond.h +@@ -21,6 +21,7 @@ + #include + + void winbond_enable_serial(pnp_devfn_t dev, uint16_t iobase); ++void winbond_enable_watchdog(pnp_devfn_t dev, pnp_devfn_t dev_acpi, u8 seconds); + void winbond_set_pinmux(pnp_devfn_t dev, uint8_t offset, uint8_t mask, uint8_t state); + void winbond_set_clksel_48(pnp_devfn_t dev); + +diff --git a/src/superio/winbond/w83667hg-a/superio.c b/src/superio/winbond/w83667hg-a/superio.c +index ec1de699d0e..70794635293 100644 +--- a/src/superio/winbond/w83667hg-a/superio.c ++++ b/src/superio/winbond/w83667hg-a/superio.c +@@ -81,9 +81,36 @@ static void w83667hg_a_init(struct device *dev) + else if (power_status == 2) + byte |= (0x2 << 5); /* Use last power state */ + pnp_write_config(dev, 0xe4, byte); ++ ++ byte = pnp_read_config(dev, 0xf2); ++ byte |= (1<<7); // EN_WDT2PWROK = Enable PWROK0,1 or 2 pin drive pulse by WDTO ++ pnp_write_config(dev, 0xf2, byte); ++ + pnp_exit_conf_mode_aa(dev); + printk(BIOS_INFO, "set power %s after power fail\n", power_status ? "on" : "off"); + break; ++ case W83667HG_A_WDT1: ++ pnp_enter_conf_mode_8787(dev); ++ pnp_set_logical_device(dev); ++ ++ byte = pnp_read_config(dev, 0xf5); ++ byte &= ~0x4e; ++ //byte |= 0x1 << 1; // count 1000 times faster than usual (i.e. milliseconds/milliminutes) ++ //byte |= 0x1 << 1; // count in minutes rather than seconds ++ byte |= 0x1 << 1; // Enable the WDTO# output low pulse to the KBRST# pin (PIN28) ++ pnp_write_config(dev, 0xf5, byte); ++ ++ byte = pnp_read_config(dev, 0xf7); ++ byte &= ~0xc0; // keyboard/mouse interrupts do not reset WDT ++ pnp_write_config(dev, 0xf7, byte); ++ ++ // watchdog timer value in seconds; countdown starts ++ // immediately. write 0 to disable counter. ++ //pnp_write_config(dev, 0xf6, 0); ++ //printk(BIOS_INFO, "started watchdog timer!"); ++ ++ pnp_exit_conf_mode_aa(dev); ++ break; + } + } + +-- +2.39.1 + diff --git a/src/platform/kgpe/default.nix b/src/platform/kgpe/default.nix index 365964c..c26b098 100644 --- a/src/platform/kgpe/default.nix +++ b/src/platform/kgpe/default.nix @@ -97,6 +97,14 @@ CONSOLE_CBMEM = lib.mkForce no; ONBOARD_VGA_IS_PRIMARY = lib.mkForce no; + + # Coreboot on some versions of the kgpe-d16 will hang during + # PNP enumeration approximately ~10% of the time during PNP + # enumeration (before DRAM init); starting the watchdog from + # the romstage ensures that the machine will always finish + # booting, although it may take two (or in rare cases three) + # attempts. You absolutely want this for unattended servers. + USE_WATCHDOG_ON_BOOT = lib.mkForce yes; }; coreboot-toolchain = with final.coreboot-toolchain; [ x64 i386 ]; uart-for-console =