summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/common/block')
-rw-r--r--src/soc/intel/common/block/acpi/acpi.c175
-rw-r--r--src/soc/intel/common/block/include/intelblocks/tco.h9
-rw-r--r--src/soc/intel/common/block/smbus/tco.c25
3 files changed, 207 insertions, 2 deletions
diff --git a/src/soc/intel/common/block/acpi/acpi.c b/src/soc/intel/common/block/acpi/acpi.c
index eed153099d..cd60416c44 100644
--- a/src/soc/intel/common/block/acpi/acpi.c
+++ b/src/soc/intel/common/block/acpi/acpi.c
@@ -16,8 +16,10 @@
#include <intelblocks/lpc_lib.h>
#include <intelblocks/pmclib.h>
#include <intelblocks/sgx.h>
+#include <intelblocks/tco.h>
#include <intelblocks/uart.h>
#include <soc/gpio.h>
+#include <soc/intel/common/tco.h>
#include <soc/iomap.h>
#include <soc/pm.h>
@@ -389,3 +391,176 @@ void generate_cpu_entries(const struct device *device)
if (CONFIG(SOC_INTEL_COMMON_BLOCK_SGX_ENABLE))
sgx_fill_ssdt();
}
+
+
+static bool fill_wdat_timeout_entry(acpi_wdat_entry_t *entry)
+{
+ uint16_t tcobase = tco_get_bar();
+
+ if (tcobase == 0)
+ return false;
+
+ memset((void *)entry, 0, sizeof(acpi_wdat_entry_t));
+
+ entry->action = ACPI_WDAT_SET_COUNTDOWN;
+ entry->instruction = ACPI_WDAT_WRITE_COUNTDOWN | ACPI_WDAT_PRESERVE_REGISTER;
+ entry->mask = TCO_TMR_MASK;
+ entry->register_region.space_id = ACPI_ADDRESS_SPACE_IO;
+ entry->register_region.addrl = tcobase + TCO_TMR;
+ entry->register_region.access_size = ACPI_WDAT_ACCESS_SIZE_WORD;
+
+ return true;
+}
+
+static bool fill_wdat_boot_status_entry(acpi_wdat_entry_t *entry, uint8_t action,
+ uint8_t instruction, uint32_t value)
+{
+ uint16_t tcobase = tco_get_bar();
+
+ if (tcobase == 0)
+ return false;
+
+ memset((void *)entry, 0, sizeof(acpi_wdat_entry_t));
+
+ entry->action = action;
+ entry->instruction = instruction;
+ entry->value = value;
+ entry->mask = TCO2_STS_SECOND_TO;
+ entry->register_region.space_id = ACPI_ADDRESS_SPACE_IO;
+ entry->register_region.addrl = tcobase + TCO_MESSAGE1;
+ entry->register_region.access_size = ACPI_WDAT_ACCESS_SIZE_BYTE;
+
+ return true;
+}
+
+static bool fill_wdat_run_state_entry(acpi_wdat_entry_t *entry, uint8_t action,
+ uint8_t instruction, uint32_t value)
+{
+ uint16_t tcobase = tco_get_bar();
+
+ if (tcobase == 0)
+ return false;
+
+ memset((void *)entry, 0, sizeof(acpi_wdat_entry_t));
+
+ entry->action = action;
+ entry->instruction = instruction;
+ entry->value = value;
+ entry->mask = TCO1_TMR_HLT;
+ entry->register_region.space_id = ACPI_ADDRESS_SPACE_IO;
+ entry->register_region.addrl = tcobase + TCO1_CNT;
+ entry->register_region.access_size = ACPI_WDAT_ACCESS_SIZE_WORD;
+
+ return true;
+}
+
+static bool fill_wdat_ping_entry(acpi_wdat_entry_t *entry)
+{
+ uint16_t tcobase = tco_get_bar();
+
+ if (tcobase == 0)
+ return false;
+
+ memset((void *)entry, 0, sizeof(acpi_wdat_entry_t));
+
+ entry->action = ACPI_WDAT_RESET;
+ entry->instruction = ACPI_WDAT_WRITE_VALUE;
+ entry->value = 0x01;
+ entry->mask = 0x01;
+ entry->register_region.space_id = ACPI_ADDRESS_SPACE_IO;
+ entry->register_region.addrl = tcobase + TCO_RLD;
+ entry->register_region.access_size = ACPI_WDAT_ACCESS_SIZE_WORD;
+
+ return true;
+}
+
+unsigned long acpi_soc_fill_wdat(acpi_wdat_t *wdat, unsigned long current)
+{
+ if (!wdat)
+ return current;
+
+ uint16_t tcobase = tco_get_bar();
+
+ if (tcobase == 0)
+ goto out_err;
+
+ wdat->pci_segment = 0xff;
+ wdat->pci_bus = 0xff;
+ wdat->pci_device = 0xff;
+ wdat->pci_function = 0xff;
+
+ wdat->timer_period = tco_get_timer_period();
+ wdat->min_count = tco_get_timer_min_value();
+ wdat->max_count = tco_get_timer_max_value();
+ wdat->flags = ACPI_WDAT_FLAG_ENABLED;
+ wdat->entries = 0;
+
+ acpi_wdat_entry_t *entry = (acpi_wdat_entry_t *)current;
+
+ /* Write countdown */
+ if (!fill_wdat_timeout_entry(entry))
+ goto out_err;
+
+ entry++;
+
+ /* Get boot status */
+ if (!fill_wdat_boot_status_entry(entry, ACPI_WDAT_GET_STATUS,
+ ACPI_WDAT_READ_VALUE, TCO2_STS_SECOND_TO))
+ goto out_err;
+
+ entry++;
+
+ /* Set boot status */
+ if (!fill_wdat_boot_status_entry(entry, ACPI_WDAT_SET_STATUS,
+ ACPI_WDAT_WRITE_VALUE | ACPI_WDAT_PRESERVE_REGISTER,
+ 0))
+ goto out_err;
+
+ entry++;
+
+ /* Get running status */
+ if (!fill_wdat_run_state_entry(entry, ACPI_WDAT_GET_RUNNING_STATE,
+ ACPI_WDAT_READ_VALUE, 0))
+ goto out_err;
+
+ entry++;
+
+ /* Start the watchdog */
+ if (!fill_wdat_run_state_entry(entry, ACPI_WDAT_SET_RUNNING_STATE,
+ ACPI_WDAT_WRITE_VALUE | ACPI_WDAT_PRESERVE_REGISTER,
+ 0))
+ goto out_err;
+
+ entry++;
+
+ /* Get stopped status */
+ if (!fill_wdat_run_state_entry(entry, ACPI_WDAT_GET_STOPPED_STATE,
+ ACPI_WDAT_READ_VALUE, TCO1_TMR_HLT))
+ goto out_err;
+
+ entry++;
+
+ /* Stop the watchdog */
+ if (!fill_wdat_run_state_entry(entry, ACPI_WDAT_SET_STOPPED_STATE,
+ ACPI_WDAT_WRITE_VALUE | ACPI_WDAT_PRESERVE_REGISTER,
+ TCO1_TMR_HLT))
+ goto out_err;
+
+ entry++;
+
+ /* Ping */
+ if (!fill_wdat_ping_entry(entry))
+ goto out_err;
+
+ entry++;
+
+ wdat->entries = ((unsigned long)entry - current) / sizeof(acpi_wdat_entry_t);
+
+ return (unsigned long)entry;
+
+out_err:
+ wdat->flags = ACPI_WDAT_FLAG_DISABLED;
+ printk(BIOS_ERR, "Fail to populate WDAT ACPI Table");
+
+ return current;
+}
diff --git a/src/soc/intel/common/block/include/intelblocks/tco.h b/src/soc/intel/common/block/include/intelblocks/tco.h
index 35cbfb1f29..1ee24b6874 100644
--- a/src/soc/intel/common/block/include/intelblocks/tco.h
+++ b/src/soc/intel/common/block/include/intelblocks/tco.h
@@ -5,6 +5,8 @@
#include <stdint.h>
+/* Get base address of TCO I/O registers. */
+uint16_t tco_get_bar(void);
/*
* Enable TCO BAR using SMBUS TCO base to access TCO related register
* also disable the timer.
@@ -20,4 +22,11 @@ uint32_t tco_reset_status(void);
uint16_t tco_read_reg(uint16_t tco_reg);
void tco_write_reg(uint16_t tco_reg, uint16_t value);
+/* Get TCO timer period in milliseconds */
+uint32_t tco_get_timer_period(void);
+/* Get the minimum time value for the TCO timer */
+uint32_t tco_get_timer_min_value(void);
+/* Get the maximum time value for the TCO timer */
+uint32_t tco_get_timer_max_value(void);
+
#endif /* SOC_INTEL_COMMON_BLOCK_TCO_H */
diff --git a/src/soc/intel/common/block/smbus/tco.c b/src/soc/intel/common/block/smbus/tco.c
index 904534393d..ef7ef07d3f 100644
--- a/src/soc/intel/common/block/smbus/tco.c
+++ b/src/soc/intel/common/block/smbus/tco.c
@@ -22,8 +22,11 @@
#define TCO_BASE_EN (1 << 8)
#define TCO_BASE_LOCK (1 << 0)
-/* Get base address of TCO I/O registers. */
-static uint16_t tco_get_bar(void)
+#define TCO_TMR_MIN_VALUE 2
+#define TCO_TMR_MAX_VALUE 1023
+#define TCO_TMR_PERIOD_MS 600
+
+uint16_t tco_get_bar(void)
{
return TCO_BASE_ADDRESS;
}
@@ -73,6 +76,9 @@ uint32_t tco_reset_status(void)
tco2_sts = tco_read_reg(TCO2_STS);
tco_write_reg(TCO2_STS, tco2_sts | TCO2_STS_SECOND_TO);
+ if (CONFIG(ACPI_WDAT_WDT))
+ tco_write_reg(TCO_MESSAGE1, tco2_sts & TCO2_STS_SECOND_TO);
+
return (tco2_sts << 16) | tco1_sts;
}
@@ -137,3 +143,18 @@ void tco_configure(void)
if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE))
tco_intruder_smi_enable();
}
+
+uint32_t tco_get_timer_period(void)
+{
+ return TCO_TMR_PERIOD_MS;
+}
+
+uint32_t tco_get_timer_min_value(void)
+{
+ return TCO_TMR_MIN_VALUE;
+}
+
+uint32_t tco_get_timer_max_value(void)
+{
+ return TCO_TMR_MAX_VALUE;
+}