1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <arch/io.h>
4 #include <device/pci_ops.h>
5 #include <cbmem.h>
6 #include <console/console.h>
7 #include <device/device.h>
8 #include <device/pci.h>
9 #include <string.h>
10 #include <soc/iomap.h>
11 #include <soc/lpc.h>
12 #include <soc/pci_devs.h>
13 #include <soc/pm.h>
14 #include <soc/romstage.h>
15
16 static struct chipset_power_state power_state;
17
migrate_power_state(int is_recovery)18 static void migrate_power_state(int is_recovery)
19 {
20 struct chipset_power_state *ps_cbmem;
21 struct chipset_power_state *ps_car;
22
23 ps_car = &power_state;
24 ps_cbmem = cbmem_add(CBMEM_ID_POWER_STATE, sizeof(*ps_cbmem));
25
26 if (ps_cbmem == NULL) {
27 printk(BIOS_DEBUG, "Not adding power state to cbmem!\n");
28 return;
29 }
30 memcpy(ps_cbmem, ps_car, sizeof(*ps_cbmem));
31 }
32 CBMEM_CREATION_HOOK(migrate_power_state);
33
34 /* Return 0, 3, or 5 to indicate the previous sleep state. */
prev_sleep_state(const struct chipset_power_state * ps)35 static int prev_sleep_state(const struct chipset_power_state *ps)
36 {
37 /* Default to S0. */
38 int prev_sleep_state = ACPI_S0;
39
40 if (ps->pm1_sts & WAK_STS) {
41 switch (acpi_sleep_from_pm1(ps->pm1_cnt)) {
42 case ACPI_S3:
43 if (CONFIG(HAVE_ACPI_RESUME))
44 prev_sleep_state = ACPI_S3;
45 break;
46 case ACPI_S5:
47 prev_sleep_state = ACPI_S5;
48 break;
49 }
50 /* Clear SLP_TYP. */
51 outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT);
52 }
53
54 if (ps->gen_pmcon3 & (PWR_FLR | SUS_PWR_FLR))
55 prev_sleep_state = ACPI_S5;
56
57 return prev_sleep_state;
58 }
59
dump_power_state(struct chipset_power_state * ps)60 static void dump_power_state(struct chipset_power_state *ps)
61 {
62 printk(BIOS_DEBUG, "PM1_STS: %04x\n", ps->pm1_sts);
63 printk(BIOS_DEBUG, "PM1_EN: %04x\n", ps->pm1_en);
64 printk(BIOS_DEBUG, "PM1_CNT: %08x\n", ps->pm1_cnt);
65 printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n",
66 ps->tco1_sts, ps->tco2_sts);
67
68 printk(BIOS_DEBUG, "GPE0_STS: %08x %08x %08x %08x\n",
69 ps->gpe0_sts[0], ps->gpe0_sts[1],
70 ps->gpe0_sts[2], ps->gpe0_sts[3]);
71 printk(BIOS_DEBUG, "GPE0_EN: %08x %08x %08x %08x\n",
72 ps->gpe0_en[0], ps->gpe0_en[1],
73 ps->gpe0_en[2], ps->gpe0_en[3]);
74
75 printk(BIOS_DEBUG, "GEN_PMCON: %04x %04x %04x\n",
76 ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
77
78 printk(BIOS_DEBUG, "Previous Sleep State: S%d\n",
79 ps->prev_sleep_state);
80 }
81
82 /* Fill power state structure from ACPI PM registers */
fill_power_state(void)83 struct chipset_power_state *fill_power_state(void)
84 {
85 struct chipset_power_state *ps = &power_state;
86
87 ps->pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
88 ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN);
89 ps->pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
90 ps->tco1_sts = inw(ACPI_BASE_ADDRESS + TCO1_STS);
91 ps->tco2_sts = inw(ACPI_BASE_ADDRESS + TCO2_STS);
92 ps->gpe0_sts[0] = inl(ACPI_BASE_ADDRESS + GPE0_STS(0));
93 ps->gpe0_sts[1] = inl(ACPI_BASE_ADDRESS + GPE0_STS(1));
94 ps->gpe0_sts[2] = inl(ACPI_BASE_ADDRESS + GPE0_STS(2));
95 ps->gpe0_sts[3] = inl(ACPI_BASE_ADDRESS + GPE0_STS(3));
96 ps->gpe0_en[0] = inl(ACPI_BASE_ADDRESS + GPE0_EN(0));
97 ps->gpe0_en[1] = inl(ACPI_BASE_ADDRESS + GPE0_EN(1));
98 ps->gpe0_en[2] = inl(ACPI_BASE_ADDRESS + GPE0_EN(2));
99 ps->gpe0_en[3] = inl(ACPI_BASE_ADDRESS + GPE0_EN(3));
100
101 ps->gen_pmcon1 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_1);
102 ps->gen_pmcon2 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_2);
103 ps->gen_pmcon3 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_3);
104
105 ps->prev_sleep_state = prev_sleep_state(ps);
106
107 dump_power_state(ps);
108
109 return ps;
110 }
111