blob: 012621bb905cd6d4dba48fb08af7d0f074d47ae6 [file] [log] [blame]
Michał Żygowskid627f7b2022-10-28 15:44:48 +02001/* 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 */
25void 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/* Reloads the OC watchdog (if enabled) preserving the current settings. */
52void oc_wdt_reload(void)
53{
54 uint32_t oc_wdt_ctrl;
55
56 /* Reload only works if OC WDT enable bit is set */
57 if (!is_oc_wdt_enabled())
58 return;
59
60 oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
61 /* Unset write-1-to-clear bits and preserve other settings */
62 oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_ICCSURV_STS | PCH_OC_WDT_CTL_NO_ICCSURV_STS);
63 oc_wdt_ctrl |= PCH_OC_WDT_CTL_RLD;
64 outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
65}
66
67/* Disables the OC WDT. */
68void oc_wdt_disable(void)
69{
70 uint32_t oc_wdt_ctrl;
71
72 printk(BIOS_INFO, "OC Watchdog: disabling watchdog timer\n");
73
74 oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
75 oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_EN | PCH_OC_WDT_CTL_FORCE_ALL);
76 outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
77}
78
79/* Checks if OC WDT is enabled and returns true if so, otherwise false. */
80bool is_oc_wdt_enabled(void)
81{
82 return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_EN) ? true : false;
83}
84
85/* Returns currently programmed OC watchdog timeout in seconds */
86unsigned int oc_wdt_get_current_timeout(void)
87{
88 return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_TOV_MASK) + 1;
89}