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