xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/oc_wdt/oc_wdt.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/io.h>
4 #include <console/console.h>
5 #include <intelblocks/oc_wdt.h>
6 #include <soc/iomap.h>
7 #include <types.h>
8 
9 /* OC WDT configuration */
10 #define PCH_OC_WDT_CTL				(ACPI_BASE_ADDRESS + 0x54)
11 #define   PCH_OC_WDT_CTL_RLD			BIT(31)
12 #define   PCH_OC_WDT_CTL_ICCSURV_STS		BIT(25)
13 #define   PCH_OC_WDT_CTL_NO_ICCSURV_STS		BIT(24)
14 #define   PCH_OC_WDT_CTL_FORCE_ALL		BIT(15)
15 #define   PCH_OC_WDT_CTL_EN			BIT(14)
16 #define   PCH_OC_WDT_CTL_ICCSURV		BIT(13)
17 #define   PCH_OC_WDT_CTL_LCK			BIT(12)
18 #define   PCH_OC_WDT_CTL_TOV_MASK		0x3FF
19 
20 /*
21  * Starts and reloads the OC watchdog with given timeout.
22  *
23  * timeout - Time in seconds before OC watchdog times out. Supported range = 70 - 1024
24  */
oc_wdt_start(unsigned int timeout)25 static void oc_wdt_start(unsigned int timeout)
26 {
27 	uint32_t oc_wdt_ctrl;
28 
29 	if (!CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE))
30 		return;
31 
32 	if ((timeout < 70) || (timeout > (PCH_OC_WDT_CTL_TOV_MASK + 1))) {
33 		timeout = CONFIG_SOC_INTEL_COMMON_OC_WDT_TIMEOUT_SECONDS;
34 		printk(BIOS_WARNING, "OC Watchdog: invalid timeout value,"
35 				     " using config default: %ds\n", timeout);
36 	}
37 
38 	printk(BIOS_SPEW, "OC Watchdog: start and relaod timer (timeout %ds)\n", timeout);
39 
40 	oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
41 	oc_wdt_ctrl |= (PCH_OC_WDT_CTL_EN | PCH_OC_WDT_CTL_FORCE_ALL | PCH_OC_WDT_CTL_ICCSURV);
42 
43 
44 	oc_wdt_ctrl &= ~PCH_OC_WDT_CTL_TOV_MASK;
45 	oc_wdt_ctrl |= (timeout - 1);
46 	oc_wdt_ctrl |= PCH_OC_WDT_CTL_RLD;
47 
48 	outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
49 }
50 
51 /* Checks if OC WDT is enabled and returns true if so, otherwise false. */
is_oc_wdt_enabled(void)52 static bool is_oc_wdt_enabled(void)
53 {
54 	return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_EN) ? true : false;
55 }
56 
57 /* Reloads the OC watchdog (if enabled) preserving the current settings. */
oc_wdt_reload(void)58 void oc_wdt_reload(void)
59 {
60 	uint32_t oc_wdt_ctrl;
61 
62 	/* Reload only works if OC WDT enable bit is set */
63 	if (!is_oc_wdt_enabled())
64 		return;
65 
66 	oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
67 	/* Unset write-1-to-clear bits and preserve other settings */
68 	oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_ICCSURV_STS | PCH_OC_WDT_CTL_NO_ICCSURV_STS);
69 	oc_wdt_ctrl |= PCH_OC_WDT_CTL_RLD;
70 	outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
71 }
72 
73 /* Disables the OC WDT. */
oc_wdt_disable(void)74 static void oc_wdt_disable(void)
75 {
76 	uint32_t oc_wdt_ctrl;
77 
78 	printk(BIOS_INFO, "OC Watchdog: disabling watchdog timer\n");
79 
80 	oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
81 	oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_EN | PCH_OC_WDT_CTL_FORCE_ALL);
82 	outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
83 }
84 
85 /* Returns currently programmed OC watchdog timeout in seconds */
oc_wdt_get_current_timeout(void)86 unsigned int oc_wdt_get_current_timeout(void)
87 {
88 	return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_TOV_MASK) + 1;
89 }
90 
91 /* Starts and reloads the OC watchdog if enabled in Kconfig */
setup_oc_wdt(void)92 void setup_oc_wdt(void)
93 {
94 	if (CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE)) {
95 		oc_wdt_start(CONFIG_SOC_INTEL_COMMON_OC_WDT_TIMEOUT_SECONDS);
96 		if (is_oc_wdt_enabled())
97 			printk(BIOS_DEBUG, "OC Watchdog enabled\n");
98 		else
99 			printk(BIOS_ERR, "Failed to enable OC watchdog\n");
100 	} else {
101 		oc_wdt_disable();
102 	}
103 }
104