blob: 6308227a8cf660bacb97f7656b573a1e872d7970 [file] [log] [blame]
Angel Ponsc3f58f62020-04-05 15:46:41 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin7837be62013-10-21 22:32:00 -05002
Angel Pons0db4b272021-04-17 12:30:12 +02003#define __SIMPLE_DEVICE__
4
Aaron Durbin7837be62013-10-21 22:32:00 -05005#include <stdint.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07006#include <acpi/acpi.h>
Kyösti Mälkki27872372021-01-21 16:05:26 +02007#include <acpi/acpi_pm.h>
Aaron Durbin7837be62013-10-21 22:32:00 -05008#include <arch/io.h>
Bill XIE516c0a52020-02-24 23:08:35 +08009#include <bootmode.h>
Kyösti Mälkki85556ac2023-05-02 12:53:00 +030010#include <console/console.h>
Kyösti Mälkki21d6a272019-11-05 18:50:38 +020011#include <device/device.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020012#include <device/mmio.h>
Kyösti Mälkki21d6a272019-11-05 18:50:38 +020013#include <device/pci.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020014#include <device/pci_ops.h>
Kyösti Mälkki83faa5d2023-01-05 15:39:16 +020015#include <halt.h>
Aaron Durbin7837be62013-10-21 22:32:00 -050016
Kyösti Mälkki85556ac2023-05-02 12:53:00 +030017#include <security/vboot/vbnv.h>
Julius Werner18ea2d32014-10-07 16:42:17 -070018#include <soc/iomap.h>
19#include <soc/lpc.h>
20#include <soc/pci_devs.h>
Angel Ponsb5320b22020-07-07 18:27:30 +020021#include <soc/pm.h>
Aaron Durbin7837be62013-10-21 22:32:00 -050022
Aaron Durbin7837be62013-10-21 22:32:00 -050023uint16_t get_pmbase(void)
24{
Angel Pons0db4b272021-04-17 12:30:12 +020025 return pci_read_config16(PCI_DEV(0, PCU_DEV, 0), ABASE) & 0xfff8;
Aaron Durbin7837be62013-10-21 22:32:00 -050026}
27
Angel Ponsa5c970d2020-07-07 18:09:45 +020028static void print_num_status_bits(int num_bits, uint32_t status, const char *const bit_names[])
Aaron Durbin7837be62013-10-21 22:32:00 -050029{
30 int i;
31
32 if (!status)
33 return;
34
Aaron Durbin9f83e872013-11-11 14:45:27 -060035 for (i = num_bits - 1; i >= 0; i--) {
Aaron Durbin7837be62013-10-21 22:32:00 -050036 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
45static uint32_t print_smi_status(uint32_t smi_sts)
46{
Angel Ponsa5c970d2020-07-07 18:09:45 +020047 static const char *const smi_sts_bits[] = {
Aaron Durbin7837be62013-10-21 22:32:00 -050048 [2] = "BIOS",
49 [4] = "SLP_SMI",
50 [5] = "APM",
51 [6] = "SWSMI_TMR",
52 [8] = "PM1",
53 [9] = "GPE0",
54 [12] = "DEVMON",
55 [13] = "TCO",
56 [14] = "PERIODIC",
57 [15] = "ILB",
58 [16] = "SMBUS_SMI",
59 [17] = "LEGACY_USB2",
60 [18] = "INTEL_USB2",
61 [20] = "PCI_EXP_SMI",
62 [26] = "SPI",
63 [28] = "PUNIT",
64 [29] = "GUNIT",
65 };
66
67 if (!smi_sts)
68 return 0;
69
70 printk(BIOS_DEBUG, "SMI_STS: ");
Angel Pons61dee5c2020-07-07 18:01:46 +020071 print_num_status_bits(30, smi_sts, smi_sts_bits);
Aaron Durbin7837be62013-10-21 22:32:00 -050072 printk(BIOS_DEBUG, "\n");
73
74 return smi_sts;
75}
76
77static uint32_t reset_smi_status(void)
78{
79 uint16_t pmbase = get_pmbase();
80 uint32_t smi_sts = inl(pmbase + SMI_STS);
81 outl(smi_sts, pmbase + SMI_STS);
82 return smi_sts;
83}
84
85uint32_t clear_smi_status(void)
86{
87 return print_smi_status(reset_smi_status());
88}
89
90void enable_smi(uint32_t mask)
91{
92 uint16_t pmbase = get_pmbase();
93 uint32_t smi_en = inl(pmbase + SMI_EN);
94 smi_en |= mask;
95 outl(smi_en, pmbase + SMI_EN);
96}
97
98void disable_smi(uint32_t mask)
99{
100 uint16_t pmbase = get_pmbase();
101 uint32_t smi_en = inl(pmbase + SMI_EN);
102 smi_en &= ~mask;
103 outl(smi_en, pmbase + SMI_EN);
104}
105
106void enable_pm1_control(uint32_t mask)
107{
108 uint16_t pmbase = get_pmbase();
109 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
110 pm1_cnt |= mask;
111 outl(pm1_cnt, pmbase + PM1_CNT);
112}
113
114void disable_pm1_control(uint32_t mask)
115{
116 uint16_t pmbase = get_pmbase();
117 uint32_t pm1_cnt = inl(pmbase + PM1_CNT);
118 pm1_cnt &= ~mask;
119 outl(pm1_cnt, pmbase + PM1_CNT);
120}
121
122static uint16_t reset_pm1_status(void)
123{
124 uint16_t pmbase = get_pmbase();
125 uint16_t pm1_sts = inw(pmbase + PM1_STS);
126 outw(pm1_sts, pmbase + PM1_STS);
127 return pm1_sts;
128}
129
130static uint16_t print_pm1_status(uint16_t pm1_sts)
131{
Angel Ponsa5c970d2020-07-07 18:09:45 +0200132 static const char *const pm1_sts_bits[] = {
Aaron Durbin7837be62013-10-21 22:32:00 -0500133 [0] = "TMROF",
134 [5] = "GBL",
135 [8] = "PWRBTN",
136 [10] = "RTC",
137 [11] = "PRBTNOR",
138 [13] = "USB",
139 [14] = "PCIEXPWAK",
140 [15] = "WAK",
141 };
142
143 if (!pm1_sts)
144 return 0;
145
146 printk(BIOS_SPEW, "PM1_STS: ");
Angel Pons61dee5c2020-07-07 18:01:46 +0200147 print_num_status_bits(16, pm1_sts, pm1_sts_bits);
Aaron Durbin7837be62013-10-21 22:32:00 -0500148 printk(BIOS_SPEW, "\n");
149
150 return pm1_sts;
151}
152
153uint16_t clear_pm1_status(void)
154{
155 return print_pm1_status(reset_pm1_status());
156}
157
158void enable_pm1(uint16_t events)
159{
160 outw(events, get_pmbase() + PM1_EN);
161}
162
163static uint32_t print_tco_status(uint32_t tco_sts)
164{
Angel Ponsa5c970d2020-07-07 18:09:45 +0200165 static const char *const tco_sts_bits[] = {
Aaron Durbin7837be62013-10-21 22:32:00 -0500166 [3] = "TIMEOUT",
167 [17] = "SECOND_TO",
168 };
169
170 if (!tco_sts)
171 return 0;
172
173 printk(BIOS_DEBUG, "TCO_STS: ");
Angel Pons61dee5c2020-07-07 18:01:46 +0200174 print_num_status_bits(18, tco_sts, tco_sts_bits);
Aaron Durbin7837be62013-10-21 22:32:00 -0500175 printk(BIOS_DEBUG, "\n");
176
177 return tco_sts;
178}
179
180static uint32_t reset_tco_status(void)
181{
182 uint16_t pmbase = get_pmbase();
183 uint32_t tco_sts = inl(pmbase + TCO_STS);
184 uint32_t tco_en = inl(pmbase + TCO1_CNT);
185
186 outl(tco_sts, pmbase + TCO_STS);
187 return tco_sts & tco_en;
188}
189
190uint32_t clear_tco_status(void)
191{
192 return print_tco_status(reset_tco_status());
193}
194
195void enable_gpe(uint32_t mask)
196{
197 uint16_t pmbase = get_pmbase();
198 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
199 gpe0_en |= mask;
200 outl(gpe0_en, pmbase + GPE0_EN);
201}
202
203void disable_gpe(uint32_t mask)
204{
205 uint16_t pmbase = get_pmbase();
206 uint32_t gpe0_en = inl(pmbase + GPE0_EN);
207 gpe0_en &= ~mask;
208 outl(gpe0_en, pmbase + GPE0_EN);
209}
210
211void disable_all_gpe(void)
212{
213 disable_gpe(~0);
214}
215
Aaron Durbin7837be62013-10-21 22:32:00 -0500216static uint32_t reset_gpe_status(void)
217{
218 uint16_t pmbase = get_pmbase();
219 uint32_t gpe_sts = inl(pmbase + GPE0_STS);
220 outl(gpe_sts, pmbase + GPE0_STS);
221 return gpe_sts;
222}
223
224static uint32_t print_gpe_sts(uint32_t gpe_sts)
225{
Angel Ponsa5c970d2020-07-07 18:09:45 +0200226 static const char *const gpe_sts_bits[] = {
Aaron Durbin7837be62013-10-21 22:32:00 -0500227 [1] = "HOTPLUG",
228 [2] = "SWGPE",
229 [3] = "PCIE_WAKE0",
230 [4] = "PUNIT",
231 [5] = "GUNIT",
232 [6] = "PCIE_WAKE1",
233 [7] = "PCIE_WAKE2",
234 [8] = "PCIE_WAKE3",
235 [9] = "PCI_EXP",
236 [10] = "BATLOW",
237 [13] = "PME_B0",
238 [16] = "SUS_GPIO_0",
239 [17] = "SUS_GPIO_1",
240 [18] = "SUS_GPIO_2",
241 [19] = "SUS_GPIO_3",
242 [20] = "SUS_GPIO_4",
243 [21] = "SUS_GPIO_5",
244 [22] = "SUS_GPIO_6",
245 [23] = "SUS_GPIO_7",
246 [24] = "CORE_GPIO_0",
247 [25] = "CORE_GPIO_1",
248 [26] = "CORE_GPIO_2",
249 [27] = "CORE_GPIO_3",
250 [28] = "CORE_GPIO_4",
251 [29] = "CORE_GPIO_5",
252 [30] = "CORE_GPIO_6",
253 [31] = "CORE_GPIO_7",
254 };
255
256 if (!gpe_sts)
257 return gpe_sts;
258
259 printk(BIOS_DEBUG, "GPE0a_STS: ");
Angel Pons61dee5c2020-07-07 18:01:46 +0200260 print_num_status_bits(32, gpe_sts, gpe_sts_bits);
Aaron Durbin7837be62013-10-21 22:32:00 -0500261 printk(BIOS_DEBUG, "\n");
262
263 return gpe_sts;
264}
265
266uint32_t clear_gpe_status(void)
267{
268 return print_gpe_sts(reset_gpe_status());
269}
Aaron Durbin9f83e872013-11-11 14:45:27 -0600270
271static uint32_t reset_alt_status(void)
272{
273 uint16_t pmbase = get_pmbase();
274 uint32_t alt_gpio_smi = inl(pmbase + ALT_GPIO_SMI);
275 outl(alt_gpio_smi, pmbase + ALT_GPIO_SMI);
276 return alt_gpio_smi;
277}
278
279static uint32_t print_alt_sts(uint32_t alt_gpio_smi)
280{
281 uint32_t alt_gpio_sts;
Angel Ponsa5c970d2020-07-07 18:09:45 +0200282 static const char *const alt_gpio_smi_sts_bits[] = {
283 [0] = "SUS_GPIO_0",
284 [1] = "SUS_GPIO_1",
285 [2] = "SUS_GPIO_2",
286 [3] = "SUS_GPIO_3",
287 [4] = "SUS_GPIO_4",
288 [5] = "SUS_GPIO_5",
289 [6] = "SUS_GPIO_6",
290 [7] = "SUS_GPIO_7",
291 [8] = "CORE_GPIO_0",
292 [9] = "CORE_GPIO_1",
Aaron Durbin9f83e872013-11-11 14:45:27 -0600293 [10] = "CORE_GPIO_2",
294 [11] = "CORE_GPIO_3",
295 [12] = "CORE_GPIO_4",
296 [13] = "CORE_GPIO_5",
297 [14] = "CORE_GPIO_6",
298 [15] = "CORE_GPIO_7",
299 };
300
301 /* Status bits are in the upper 16 bits. */
302 alt_gpio_sts = alt_gpio_smi >> 16;
303 if (!alt_gpio_sts)
304 return alt_gpio_smi;
305
306 printk(BIOS_DEBUG, "ALT_GPIO_SMI: ");
307 print_num_status_bits(16, alt_gpio_sts, alt_gpio_smi_sts_bits);
308 printk(BIOS_DEBUG, "\n");
309
310 return alt_gpio_smi;
311}
312
313uint32_t clear_alt_status(void)
314{
315 return print_alt_sts(reset_alt_status());
316}
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600317
318void clear_pmc_status(void)
319{
320 uint32_t prsts;
321 uint32_t gen_pmcon1;
322
Elyes Haouasbc849b52022-12-11 10:31:07 +0100323 prsts = read32p(PMC_BASE_ADDRESS + PRSTS);
324 gen_pmcon1 = read32p(PMC_BASE_ADDRESS + GEN_PMCON1);
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600325
Shawn Nematbakhsh51d787a2014-01-16 17:52:21 -0800326 /* Clear the status bits. The RPS field is cleared on a 0 write. */
Elyes Haouasbc849b52022-12-11 10:31:07 +0100327 write32p(PMC_BASE_ADDRESS + GEN_PMCON1, gen_pmcon1 & ~RPS);
328 write32p(PMC_BASE_ADDRESS + PRSTS, prsts);
Aaron Durbin19edc3a2014-01-09 11:17:37 -0600329}
Aaron Durbin64b4bdd2017-09-15 14:24:03 -0600330
331int rtc_failure(void)
332{
333 uint32_t gen_pmcon1;
334 int rtc_fail;
Kyösti Mälkki27872372021-01-21 16:05:26 +0200335 struct chipset_power_state *ps = acpi_get_pm_state();
Aaron Durbin64b4bdd2017-09-15 14:24:03 -0600336
337 if (ps != NULL)
338 gen_pmcon1 = ps->gen_pmcon1;
339 else
340 gen_pmcon1 = read32((u32 *)(PMC_BASE_ADDRESS + GEN_PMCON1));
341
342 rtc_fail = !!(gen_pmcon1 & RPS);
Aaron Durbin64b4bdd2017-09-15 14:24:03 -0600343 if (rtc_fail)
344 printk(BIOS_DEBUG, "RTC failure.\n");
345
346 return rtc_fail;
347}
Aaron Durbin0990fbf2017-09-15 15:23:04 -0600348
349int vbnv_cmos_failed(void)
350{
351 return rtc_failure();
352}
Joel Kitching1d93b882018-09-26 17:58:14 +0800353
Bill XIE516c0a52020-02-24 23:08:35 +0800354int platform_is_resuming(void)
Joel Kitching1d93b882018-09-26 17:58:14 +0800355{
356 if (!(inw(ACPI_BASE_ADDRESS + PM1_STS) & WAK_STS))
357 return 0;
358
359 return acpi_sleep_from_pm1(inl(ACPI_BASE_ADDRESS + PM1_CNT)) == ACPI_S3;
360}
Kyösti Mälkki83faa5d2023-01-05 15:39:16 +0200361
362void poweroff(void)
363{
364 uint32_t pm1_cnt;
365
366 /* Go to S5 */
367 pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
368 pm1_cnt |= (0xf << 10);
369 outl(pm1_cnt, ACPI_BASE_ADDRESS + PM1_CNT);
370}