x86: acpi: Support external GNVS tables

At present U-Boot puts a magic number in the ASL for the GNVS table and
searches for it later.

Add a Kconfig option to use a different approach, where the ASL files
declare the table as an external symbol. U-Boot can then put it wherever
it likes, without any magic numbers or searching.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2020-09-22 12:44:53 -06:00 committed by Bin Meng
parent 167c3f6e93
commit 55109f1d4e
4 changed files with 33 additions and 11 deletions

View File

@ -788,6 +788,13 @@ config GENERATE_ACPI_TABLE
by the operating system. It defines platform-independent interfaces
for configuration and power management monitoring.
config ACPI_GNVS_EXTERNAL
bool
help
Put the GNVS (Global Non-Volatile Sleeping) table separate from the
DSDT and add a pointer to the table from the DSDT. This allows
U-Boot to better control the address of the GNVS.
endmenu
config HAVE_ACPI_RESUME

View File

@ -17,6 +17,7 @@ config INTEL_APOLLOLAKE
select PCH_SUPPORT
select P2SB
select SMP_AP_WORK
select ACPI_GNVS_EXTERNAL
imply ENABLE_MRC_CACHE
imply AHCI_PCI
imply SCSI

View File

@ -11,6 +11,9 @@
* ACPI_GNVS_SIZE. They are to be used in platform's global_nvs.asl file
* to declare the GNVS OperationRegion, as well as write_acpi_tables()
* for the GNVS address runtime fix up.
*
* If using CONFIG_ACPI_GNVS_EXTERNAL, we don't need to locate the GNVS in
* DSDT, since it is created by code, so ACPI_GNVS_ADDR is unused.
*/
#define ACPI_GNVS_ADDR 0xdeadbeef
#define ACPI_GNVS_SIZE 0x100

View File

@ -430,17 +430,31 @@ ulong write_acpi_tables(ulong start_addr)
dsdt->length - sizeof(struct acpi_table_header));
acpi_inc(ctx, dsdt->length - sizeof(struct acpi_table_header));
dsdt->length = ctx->current - (void *)dsdt;
acpi_align(ctx);
/* Pack GNVS into the ACPI table area */
for (i = 0; i < dsdt->length; i++) {
u32 *gnvs = (u32 *)((u32)dsdt + i);
if (*gnvs == ACPI_GNVS_ADDR) {
ulong addr = (ulong)map_to_sysmem(ctx->current);
if (!IS_ENABLED(CONFIG_ACPI_GNVS_EXTERNAL)) {
/* Pack GNVS into the ACPI table area */
for (i = 0; i < dsdt->length; i++) {
u32 *gnvs = (u32 *)((u32)dsdt + i);
debug("Fix up global NVS in DSDT to %#08lx\n", addr);
*gnvs = addr;
break;
if (*gnvs == ACPI_GNVS_ADDR) {
*gnvs = map_to_sysmem(ctx->current);
debug("Fix up global NVS in DSDT to %#08x\n",
*gnvs);
break;
}
}
/*
* Fill in platform-specific global NVS variables. If this fails
* we cannot return the error but this should only happen while
* debugging.
*/
addr = acpi_create_gnvs(ctx->current);
if (IS_ERR_VALUE(addr))
printf("Error: Gailed to create GNVS\n");
acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
}
/*
@ -448,12 +462,9 @@ ulong write_acpi_tables(ulong start_addr)
* the GNVS address. Set the checksum to zero since it is part of the
* region being checksummed.
*/
dsdt->length = ctx->current - (void *)dsdt;
dsdt->checksum = 0;
dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
acpi_align(ctx);
/*
* Fill in platform-specific global NVS variables. If this fails we
* cannot return the error but this should only happen while debugging.