blob: 012621bb905cd6d4dba48fb08af7d0f074d47ae6 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <console/console.h>
#include <intelblocks/oc_wdt.h>
#include <soc/iomap.h>
#include <types.h>
/* OC WDT configuration */
#define PCH_OC_WDT_CTL (ACPI_BASE_ADDRESS + 0x54)
#define PCH_OC_WDT_CTL_RLD BIT(31)
#define PCH_OC_WDT_CTL_ICCSURV_STS BIT(25)
#define PCH_OC_WDT_CTL_NO_ICCSURV_STS BIT(24)
#define PCH_OC_WDT_CTL_FORCE_ALL BIT(15)
#define PCH_OC_WDT_CTL_EN BIT(14)
#define PCH_OC_WDT_CTL_ICCSURV BIT(13)
#define PCH_OC_WDT_CTL_LCK BIT(12)
#define PCH_OC_WDT_CTL_TOV_MASK 0x3FF
/*
* Starts and reloads the OC watchdog with given timeout.
*
* timeout - Time in seconds before OC watchdog times out. Supported range = 70 - 1024
*/
void oc_wdt_start(unsigned int timeout)
{
uint32_t oc_wdt_ctrl;
if (!CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE))
return;
if ((timeout < 70) || (timeout > (PCH_OC_WDT_CTL_TOV_MASK + 1))) {
timeout = CONFIG_SOC_INTEL_COMMON_OC_WDT_TIMEOUT_SECONDS;
printk(BIOS_WARNING, "OC Watchdog: invalid timeout value,"
" using config default: %ds\n", timeout);
}
printk(BIOS_SPEW, "OC Watchdog: start and relaod timer (timeout %ds)\n", timeout);
oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
oc_wdt_ctrl |= (PCH_OC_WDT_CTL_EN | PCH_OC_WDT_CTL_FORCE_ALL | PCH_OC_WDT_CTL_ICCSURV);
oc_wdt_ctrl &= ~PCH_OC_WDT_CTL_TOV_MASK;
oc_wdt_ctrl |= (timeout - 1);
oc_wdt_ctrl |= PCH_OC_WDT_CTL_RLD;
outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
}
/* Reloads the OC watchdog (if enabled) preserving the current settings. */
void oc_wdt_reload(void)
{
uint32_t oc_wdt_ctrl;
/* Reload only works if OC WDT enable bit is set */
if (!is_oc_wdt_enabled())
return;
oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
/* Unset write-1-to-clear bits and preserve other settings */
oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_ICCSURV_STS | PCH_OC_WDT_CTL_NO_ICCSURV_STS);
oc_wdt_ctrl |= PCH_OC_WDT_CTL_RLD;
outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
}
/* Disables the OC WDT. */
void oc_wdt_disable(void)
{
uint32_t oc_wdt_ctrl;
printk(BIOS_INFO, "OC Watchdog: disabling watchdog timer\n");
oc_wdt_ctrl = inl(PCH_OC_WDT_CTL);
oc_wdt_ctrl &= ~(PCH_OC_WDT_CTL_EN | PCH_OC_WDT_CTL_FORCE_ALL);
outl(oc_wdt_ctrl, PCH_OC_WDT_CTL);
}
/* Checks if OC WDT is enabled and returns true if so, otherwise false. */
bool is_oc_wdt_enabled(void)
{
return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_EN) ? true : false;
}
/* Returns currently programmed OC watchdog timeout in seconds */
unsigned int oc_wdt_get_current_timeout(void)
{
return (inl(PCH_OC_WDT_CTL) & PCH_OC_WDT_CTL_TOV_MASK) + 1;
}