diff options
Diffstat (limited to 'src/soc/intel/common/block')
-rw-r--r-- | src/soc/intel/common/block/acpi/acpi.c | 175 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/tco.h | 9 | ||||
-rw-r--r-- | src/soc/intel/common/block/smbus/tco.c | 25 |
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; +} |