1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <acpi/acpi.h>
4 #include <acpi/acpi_pm.h>
5 #include <amdblocks/acpimmio.h>
6 #include <amdblocks/acpi.h>
7 #include <bootmode.h>
8 #include <console/console.h>
9 #include <halt.h>
10 #include <security/vboot/vboot_common.h>
11 #include <soc/southbridge.h>
12
poweroff(void)13 void poweroff(void)
14 {
15 acpi_write32(MMIO_ACPI_PM1_CNT_BLK,
16 (SLP_TYP_S5 << SLP_TYP_SHIFT) | SLP_EN);
17
18 /*
19 * Setting SLP_TYP_S5 in PM1 triggers SLP_SMI, which is handled by SMM
20 * to transition to S5 state. If halt is called in SMM, then it prevents
21 * the SMI handler from being triggered and system never enters S5.
22 */
23 if (!ENV_SMM)
24 halt();
25 }
26
print_num_status_bits(int num_bits,uint32_t status,const char * const bit_names[])27 static void print_num_status_bits(int num_bits, uint32_t status,
28 const char *const bit_names[])
29 {
30 int i;
31
32 if (!status)
33 return;
34
35 for (i = num_bits - 1; i >= 0; i--) {
36 if (status & (1 << i)) {
37 if (bit_names[i])
38 printk(BIOS_DEBUG, "%s ", bit_names[i]);
39 else
40 printk(BIOS_DEBUG, "BIT%d ", i);
41 }
42 }
43 }
44
print_pm1_status(uint16_t pm1_sts)45 static uint16_t print_pm1_status(uint16_t pm1_sts)
46 {
47 static const char *const pm1_sts_bits[16] = {
48 [0] = "TMROF",
49 [4] = "BMSTATUS",
50 [5] = "GBL",
51 [8] = "PWRBTN",
52 [10] = "RTC",
53 [14] = "PCIEXPWAK",
54 [15] = "WAK",
55 };
56
57 if (!pm1_sts)
58 return 0;
59
60 printk(BIOS_DEBUG, "PM1_STS: ");
61 print_num_status_bits(ARRAY_SIZE(pm1_sts_bits), pm1_sts, pm1_sts_bits);
62 printk(BIOS_DEBUG, "\n");
63
64 return pm1_sts;
65 }
66
acpi_fill_pm_gpe_state(struct acpi_pm_gpe_state * state)67 void acpi_fill_pm_gpe_state(struct acpi_pm_gpe_state *state)
68 {
69 state->pm1_sts = acpi_read16(MMIO_ACPI_PM1_STS);
70 state->pm1_en = acpi_read16(MMIO_ACPI_PM1_EN);
71 state->gpe0_sts = acpi_read32(MMIO_ACPI_GPE0_STS);
72 state->gpe0_en = acpi_read32(MMIO_ACPI_GPE0_EN);
73 state->previous_sx_state = acpi_get_sleep_type();
74 state->aligning_field = 0;
75 }
76
acpi_pm_gpe_add_events_print_events(void)77 void acpi_pm_gpe_add_events_print_events(void)
78 {
79 const struct chipset_power_state *ps;
80 const struct acpi_pm_gpe_state *state;
81
82 if (acpi_fetch_pm_state(&ps, PS_CLAIMER_ELOG) < 0)
83 return;
84
85 state = &ps->gpe_state;
86 print_pm1_status(state->pm1_sts);
87 acpi_log_events(ps);
88 }
89
acpi_clear_pm_gpe_status(void)90 void acpi_clear_pm_gpe_status(void)
91 {
92 acpi_write16(MMIO_ACPI_PM1_STS, acpi_read16(MMIO_ACPI_PM1_STS));
93 acpi_write32(MMIO_ACPI_GPE0_STS, acpi_read32(MMIO_ACPI_GPE0_STS));
94 }
95
acpi_get_sleep_type(void)96 int acpi_get_sleep_type(void)
97 {
98 return acpi_sleep_from_pm1(acpi_read16(MMIO_ACPI_PM1_CNT_BLK));
99 }
100
platform_is_resuming(void)101 int platform_is_resuming(void)
102 {
103 if (!(acpi_read16(MMIO_ACPI_PM1_STS) & WAK_STS))
104 return 0;
105
106 return acpi_get_sleep_type() == ACPI_S3;
107 }
108
109 /* If a system reset is about to be requested, modify the PM1 register so it
110 * will never be misinterpreted as an S3 resume. */
set_pm1cnt_s5(void)111 void set_pm1cnt_s5(void)
112 {
113 uint16_t pm1;
114
115 pm1 = acpi_read16(MMIO_ACPI_PM1_CNT_BLK);
116 pm1 &= ~SLP_TYP;
117 pm1 |= SLP_TYP_S5 << SLP_TYP_SHIFT;
118 acpi_write16(MMIO_ACPI_PM1_CNT_BLK, pm1);
119 }
120
vboot_platform_prepare_reboot(void)121 void vboot_platform_prepare_reboot(void)
122 {
123 set_pm1cnt_s5();
124 }
125
acpi_enable_sci(void)126 void acpi_enable_sci(void)
127 {
128 uint32_t pm1;
129
130 pm1 = acpi_read32(MMIO_ACPI_PM1_CNT_BLK);
131 pm1 |= ACPI_PM1_CNT_SCIEN;
132 acpi_write32(MMIO_ACPI_PM1_CNT_BLK, pm1);
133 }
134
acpi_disable_sci(void)135 void acpi_disable_sci(void)
136 {
137 uint32_t pm1;
138
139 pm1 = acpi_read32(MMIO_ACPI_PM1_CNT_BLK);
140 pm1 &= ~ACPI_PM1_CNT_SCIEN;
141 acpi_write32(MMIO_ACPI_PM1_CNT_BLK, pm1);
142 }
143