summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBin Meng <bmeng.cn@gmail.com>2017-04-21 14:24:36 (GMT)
committerBin Meng <bmeng.cn@gmail.com>2017-05-17 09:11:46 (GMT)
commite76bf38f180b0c9325b17506f1518329d82cbed8 (patch)
tree8ce67b116d477a575794a7d391d71ba8085571fd
parent2b2d666f9caca189e4014f8e23088b0afc360e22 (diff)
downloadu-boot-e76bf38f180b0c9325b17506f1518329d82cbed8.tar.xz
x86: acpi: Add one API to find OS wakeup vector
This adds one API acpi_find_wakeup_vector() to locate OS wakeup vector from the ACPI FACS table, to be used in the S3 boot path. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Stefan Roese <sr@denx.de>
-rw-r--r--arch/x86/include/asm/acpi_table.h10
-rw-r--r--arch/x86/include/asm/tables.h1
-rw-r--r--arch/x86/lib/acpi_table.c72
3 files changed, 83 insertions, 0 deletions
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index bbd80a1..20b906c 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -317,3 +317,13 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
u32 acpi_fill_madt(u32 current);
void acpi_create_gnvs(struct acpi_global_nvs *gnvs);
ulong write_acpi_tables(ulong start);
+
+/**
+ * acpi_find_wakeup_vector() - find OS installed wake up vector address
+ *
+ * This routine parses the ACPI table to locate the wake up vector installed
+ * by the OS previously.
+ *
+ * @return: wake up vector address installed by the OS
+ */
+void *acpi_find_wakeup_vector(void);
diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h
index d1b2388..9e8208b 100644
--- a/arch/x86/include/asm/tables.h
+++ b/arch/x86/include/asm/tables.h
@@ -15,6 +15,7 @@
* PIRQ routing table, Multi-Processor table and ACPI table.
*/
#define ROM_TABLE_ADDR 0xf0000
+#define ROM_TABLE_END 0xfffff
#define ROM_TABLE_ALIGN 1024
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 355456d..f118345 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -438,3 +438,75 @@ ulong write_acpi_tables(ulong start)
return current;
}
+
+static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp)
+{
+ if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
+ return NULL;
+
+ debug("Looking on %p for valid checksum\n", rsdp);
+
+ if (table_compute_checksum((void *)rsdp, 20) != 0)
+ return NULL;
+ debug("acpi rsdp checksum 1 passed\n");
+
+ if ((rsdp->revision > 1) &&
+ (table_compute_checksum((void *)rsdp, rsdp->length) != 0))
+ return NULL;
+ debug("acpi rsdp checksum 2 passed\n");
+
+ return rsdp;
+}
+
+void *acpi_find_wakeup_vector(void)
+{
+ char *p, *end;
+ struct acpi_rsdp *rsdp = NULL;
+ struct acpi_rsdt *rsdt;
+ struct acpi_fadt *fadt = NULL;
+ struct acpi_facs *facs;
+ void *wake_vec;
+ int i;
+
+ debug("Trying to find the wakeup vector...\n");
+
+ /* Find RSDP */
+ for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) {
+ rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p);
+ if (rsdp)
+ break;
+ }
+
+ if (rsdp == NULL)
+ return NULL;
+
+ debug("RSDP found at %p\n", rsdp);
+ rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
+
+ end = (char *)rsdt + rsdt->header.length;
+ debug("RSDT found at %p ends at %p\n", rsdt, end);
+
+ for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
+ fadt = (struct acpi_fadt *)rsdt->entry[i];
+ if (strncmp((char *)fadt, "FACP", 4) == 0)
+ break;
+ fadt = NULL;
+ }
+
+ if (fadt == NULL)
+ return NULL;
+
+ debug("FADT found at %p\n", fadt);
+ facs = (struct acpi_facs *)fadt->firmware_ctrl;
+
+ if (facs == NULL) {
+ debug("No FACS found, wake up from S3 not possible.\n");
+ return NULL;
+ }
+
+ debug("FACS found at %p\n", facs);
+ wake_vec = (void *)facs->firmware_waking_vector;
+ debug("OS waking vector is %p\n", wake_vec);
+
+ return wake_vec;
+}