xref: /aosp_15_r20/external/coreboot/src/soc/intel/broadwell/pch/power_state.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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