1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <acpi/acpi_gnvs.h>
4 #include <acpi/acpi_pm.h>
5 #include <bootstate.h>
6 #include <console/console.h>
7 #include <intelblocks/acpi_wake_source.h>
8 #include <soc/nvs.h>
9 #include <soc/pm.h>
10 #include <stdint.h>
11
12 /* Save wake source data for ACPI _SWS methods in NVS */
pm_fill_gnvs(struct global_nvs * gnvs,const struct chipset_power_state * ps)13 static void pm_fill_gnvs(struct global_nvs *gnvs, const struct chipset_power_state *ps)
14 {
15 uint32_t pm1, *gpe0;
16 int index, gpe_reg, gpe_reg_count;
17 int reg_size = sizeof(uint32_t) * 8;
18
19 gpe_reg_count = soc_fill_acpi_wake(ps, &pm1, &gpe0);
20 if (gpe_reg_count < 0)
21 return;
22
23 /* Scan for first set bit in PM1 */
24 for (index = 0; index < reg_size; index++) {
25 if (pm1 & 1)
26 break;
27 pm1 >>= 1;
28 }
29
30 if (index < 16)
31 gnvs->pm1i = index;
32
33 /* Scan for first set bit in GPE registers */
34 for (gpe_reg = 0; gpe_reg < gpe_reg_count; gpe_reg++) {
35 uint32_t gpe = gpe0[gpe_reg];
36 int start = gpe_reg * reg_size;
37 int end = start + reg_size;
38
39 for (index = start; index < end; index++) {
40 if (gpe & 1)
41 break;
42 gpe >>= 1;
43 }
44 }
45
46 if (index < gpe_reg_count * reg_size)
47 gnvs->gpei = index;
48 }
49
acpi_save_wake_source(void * unused)50 static void acpi_save_wake_source(void *unused)
51 {
52 const struct chipset_power_state *ps;
53 struct global_nvs *gnvs;
54
55 if (acpi_reset_gnvs_for_wake(&gnvs) < 0)
56 return;
57 if (acpi_fetch_pm_state(&ps, PS_CLAIMER_WAKE) < 0)
58 return;
59
60 pm_fill_gnvs(gnvs, ps);
61
62 printk(BIOS_DEBUG, "ACPI _SWS is PM1 Index %lld GPE Index %lld\n",
63 (long long)gnvs->pm1i, (long long)gnvs->gpei);
64 }
65
66 BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, acpi_save_wake_source, NULL);
67