Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / x86 / lib / acpi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4  */
5
6 #include <common.h>
7 #include <log.h>
8 #include <acpi/acpi_table.h>
9 #include <asm/io.h>
10 #include <asm/tables.h>
11
12 static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp)
13 {
14         if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
15                 return NULL;
16
17         debug("Looking on %p for valid checksum\n", rsdp);
18
19         if (table_compute_checksum((void *)rsdp, 20) != 0)
20                 return NULL;
21         debug("acpi rsdp checksum 1 passed\n");
22
23         if ((rsdp->revision > 1) &&
24             (table_compute_checksum((void *)rsdp, rsdp->length) != 0))
25                 return NULL;
26         debug("acpi rsdp checksum 2 passed\n");
27
28         return rsdp;
29 }
30
31 struct acpi_fadt *acpi_find_fadt(void)
32 {
33         char *p, *end;
34         struct acpi_rsdp *rsdp = NULL;
35         struct acpi_rsdt *rsdt;
36         struct acpi_fadt *fadt = NULL;
37         int i;
38
39         /* Find RSDP */
40         for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) {
41                 rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p);
42                 if (rsdp)
43                         break;
44         }
45
46         if (!rsdp)
47                 return NULL;
48
49         debug("RSDP found at %p\n", rsdp);
50         rsdt = (struct acpi_rsdt *)(uintptr_t)rsdp->rsdt_address;
51
52         end = (char *)rsdt + rsdt->header.length;
53         debug("RSDT found at %p ends at %p\n", rsdt, end);
54
55         for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
56                 fadt = (struct acpi_fadt *)(uintptr_t)rsdt->entry[i];
57                 if (strncmp((char *)fadt, "FACP", 4) == 0)
58                         break;
59                 fadt = NULL;
60         }
61
62         if (!fadt)
63                 return NULL;
64
65         debug("FADT found at %p\n", fadt);
66         return fadt;
67 }
68
69 void *acpi_find_wakeup_vector(struct acpi_fadt *fadt)
70 {
71         struct acpi_facs *facs;
72         void *wake_vec;
73
74         debug("Trying to find the wakeup vector...\n");
75
76         facs = (struct acpi_facs *)(uintptr_t)fadt->firmware_ctrl;
77
78         if (!facs) {
79                 debug("No FACS found, wake up from S3 not possible.\n");
80                 return NULL;
81         }
82
83         debug("FACS found at %p\n", facs);
84         wake_vec = (void *)(uintptr_t)facs->firmware_waking_vector;
85         debug("OS waking vector is %p\n", wake_vec);
86
87         return wake_vec;
88 }
89
90 void enter_acpi_mode(int pm1_cnt)
91 {
92         u16 val = inw(pm1_cnt);
93
94         /*
95          * PM1_CNT register bit0 selects the power management event to be
96          * either an SCI or SMI interrupt. When this bit is set, then power
97          * management events will generate an SCI interrupt. When this bit
98          * is reset power management events will generate an SMI interrupt.
99          *
100          * Per ACPI spec, it is the responsibility of the hardware to set
101          * or reset this bit. OSPM always preserves this bit position.
102          *
103          * U-Boot does not support SMI. And we don't have plan to support
104          * anything running in SMM within U-Boot. To create a legacy-free
105          * system, and expose ourselves to OSPM as working under ACPI mode
106          * already, turn this bit on.
107          */
108         outw(val | PM1_CNT_SCI_EN, pm1_cnt);
109 }