diff options
-rw-r--r-- | src/acpi/Kconfig | 6 | ||||
-rw-r--r-- | src/acpi/acpi.c | 61 | ||||
-rw-r--r-- | src/include/acpi/acpi.h | 9 |
3 files changed, 75 insertions, 1 deletions
diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig index a45a68c458..b3a87f9b5f 100644 --- a/src/acpi/Kconfig +++ b/src/acpi/Kconfig @@ -68,3 +68,9 @@ config ACPI_LPIT depends on HAVE_ACPI_TABLES help Selected by platforms that support and fill Intel Low Power Idle Table. + +config ACPI_GTDT + bool + depends on HAVE_ACPI_TABLES + help + Selected by platforms that implement ARM generic timers diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index 0563c24d3a..dfa91e0386 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -1134,6 +1134,64 @@ static void acpi_create_lpit(acpi_header_t *header, void *unused) header->length = current - (unsigned long)lpit; } +static void acpi_create_gtdt(acpi_header_t *header, void *unused) +{ + if (!CONFIG(ACPI_GTDT)) + return; + + acpi_gtdt_t *gtdt = (acpi_gtdt_t *)header; + unsigned long current = (unsigned long)gtdt + sizeof(acpi_gtdt_t); + + if (acpi_fill_header(header, "GTDT", GTDT, sizeof(acpi_gtdt_t)) != CB_SUCCESS) + return; + + /* Fill out header fields. */ + gtdt->platform_timer_offset = sizeof(acpi_gtdt_t); + + acpi_soc_fill_gtdt(gtdt); + current = acpi_soc_gtdt_add_timers(>dt->platform_timer_count, current); + + /* (Re)calculate length. */ + header->length = current - (unsigned long)gtdt; +} + +unsigned long acpi_gtdt_add_timer_block(unsigned long current, const uint64_t address, + struct acpi_gtdt_timer_entry *timers, size_t number) +{ + struct acpi_gtdt_timer_block *block = (struct acpi_gtdt_timer_block *)current; + memset(block, 0, sizeof(struct acpi_gtdt_timer_block)); + + assert(number < 8 && number != 0); + const size_t entries_size = number * sizeof(struct acpi_gtdt_timer_entry); + + block->header.type = ACPI_GTDT_TYPE_TIMER_BLOCK; + block->header.length = sizeof(struct acpi_gtdt_timer_block) + + entries_size; + block->block_address = address; + block->timer_count = number; + block->timer_offset = sizeof(struct acpi_gtdt_timer_block); + current += sizeof(struct acpi_gtdt_timer_block); + memcpy((void *)current, timers, entries_size); + current += entries_size; + return current; +} + +unsigned long acpi_gtdt_add_watchdog(unsigned long current, uint64_t refresh_frame, + uint64_t control_frame, uint32_t gsiv, uint32_t flags) +{ + struct acpi_gtdt_watchdog *wd = (struct acpi_gtdt_watchdog *)current; + memset(wd, 0, sizeof(struct acpi_gtdt_watchdog)); + + wd->header.type = ACPI_GTDT_TYPE_WATCHDOG; + wd->header.length = sizeof(struct acpi_gtdt_watchdog); + wd->refresh_frame_address = refresh_frame; + wd->control_frame_address = control_frame; + wd->timer_interrupt = gsiv; + wd->timer_flags = flags; + + return current + sizeof(struct acpi_gtdt_watchdog); +} + unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid) { memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t)); @@ -1333,6 +1391,7 @@ unsigned long write_acpi_tables(const unsigned long start) { acpi_create_madt, NULL, sizeof(acpi_header_t) }, { acpi_create_bert, NULL, sizeof(acpi_bert_t) }, { acpi_create_spcr, NULL, sizeof(acpi_spcr_t) }, + { acpi_create_gtdt, NULL, sizeof(acpi_gtdt_t) }, }; current = start; @@ -1647,6 +1706,8 @@ int get_acpi_table_revision(enum acpi_tables table) return 0; case SPCR: return 4; + case GTDT: + return 3; default: return -1; } diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index dc26b85597..f1c52d1560 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -77,7 +77,7 @@ enum acpi_tables { /* Tables defined by ACPI and used by coreboot */ BERT, CEDT, DBG2, DMAR, DSDT, EINJ, FACS, FADT, HEST, HMAT, HPET, IVRS, MADT, MCFG, RSDP, RSDT, SLIT, SRAT, SSDT, TCPA, TPM2, XSDT, ECDT, LPIT, - SPCR, + SPCR, GTDT, /* Additional proprietary tables used by coreboot */ VFCT, NHLT, SPMI, CRAT }; @@ -1576,6 +1576,13 @@ unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t /* chipsets that select ACPI_BERT must implement this function */ enum cb_err acpi_soc_get_bert_region(void **region, size_t *length); +void acpi_soc_fill_gtdt(acpi_gtdt_t *gtdt); +unsigned long acpi_soc_gtdt_add_timers(uint32_t *count, unsigned long current); +unsigned long acpi_gtdt_add_timer_block(unsigned long current, const uint64_t address, + struct acpi_gtdt_timer_entry *timers, size_t number); +unsigned long acpi_gtdt_add_watchdog(unsigned long current, uint64_t refresh_frame, + uint64_t control_frame, uint32_t gsiv, uint32_t flags); + /* For ACPI S3 support. */ void __noreturn acpi_resume(void *wake_vec); void mainboard_suspend_resume(void); |