blob: 733c625f6c717ed46d435505ccd9733821721074 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Arthur Heymansa0508172018-01-25 11:30:22 +01002
3#include <types.h>
4#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02005#include <device/pci_ops.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07006#include <acpi/acpi.h>
Arthur Heymansa0508172018-01-25 11:30:22 +01007#include <console/console.h>
8#include <cpu/x86/cache.h>
9#include <device/pci_def.h>
10#include <cpu/x86/smm.h>
Kyösti Mälkkie31ec292019-08-10 17:27:01 +030011#include <cpu/intel/em64t101_save_state.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010012#include <elog.h>
13#include <halt.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020014#include <option.h>
Patrick Rudolphed3242e2018-06-29 10:34:37 +020015#include <southbridge/intel/common/pmbase.h>
Arthur Heymans4c804252018-12-03 01:28:18 +010016#include <smmstore.h>
Patrick Rudolphed3242e2018-06-29 10:34:37 +020017
Arthur Heymansa0508172018-01-25 11:30:22 +010018#include "pmutil.h"
19
Arthur Heymansa0508172018-01-25 11:30:22 +010020u16 get_pmbase(void)
21{
Patrick Rudolphed3242e2018-06-29 10:34:37 +020022 return lpc_get_pmbase();
Arthur Heymansa0508172018-01-25 11:30:22 +010023}
24
Arthur Heymansa0508172018-01-25 11:30:22 +010025void gpi_route_interrupt(u8 gpi, u8 mode)
26{
27 u32 gpi_rout;
28 if (gpi >= 16)
29 return;
30
31 alt_gpi_mask(1 << gpi, 0);
32 gpe0_mask(1 << (gpi+16), 0);
33
34 gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), D31F0_GPIO_ROUT);
35 gpi_rout &= ~(3 << (2 * gpi));
36 gpi_rout |= ((mode & 3) << (2 * gpi));
37 pci_write_config32(PCI_DEV(0, 0x1f, 0), D31F0_GPIO_ROUT, gpi_rout);
38
39 if (mode == GPI_IS_SCI)
40 gpe0_mask(0, 1 << (gpi+16));
41 else if (mode == GPI_IS_SMI)
42 alt_gpi_mask(0, 1 << gpi);
43}
44
45/**
46 * @brief Set the EOS bit
47 */
48void southbridge_smi_set_eos(void)
49{
Patrick Rudolphed3242e2018-06-29 10:34:37 +020050 write_pmbase8(SMI_EN, read_pmbase8(SMI_EN) | EOS);
Arthur Heymansa0508172018-01-25 11:30:22 +010051}
52
53static void busmaster_disable_on_bus(int bus)
54{
55 int slot, func;
56 unsigned int val;
57 unsigned char hdr;
58
59 for (slot = 0; slot < 0x20; slot++) {
60 for (func = 0; func < 8; func++) {
Elyes HAOUAS804a3402020-04-27 05:25:06 +020061 u16 reg16;
Arthur Heymansa0508172018-01-25 11:30:22 +010062 pci_devfn_t dev = PCI_DEV(bus, slot, func);
63
64 val = pci_read_config32(dev, PCI_VENDOR_ID);
65
66 if (val == 0xffffffff || val == 0x00000000 ||
67 val == 0x0000ffff || val == 0xffff0000)
68 continue;
69
70 /* Disable Bus Mastering for this one device */
Elyes HAOUAS804a3402020-04-27 05:25:06 +020071 reg16 = pci_read_config16(dev, PCI_COMMAND);
72 reg16 &= ~PCI_COMMAND_MASTER;
73 pci_write_config16(dev, PCI_COMMAND, reg16);
Arthur Heymansa0508172018-01-25 11:30:22 +010074
75 /* If this is a bridge, then follow it. */
76 hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
77 hdr &= 0x7f;
78 if (hdr == PCI_HEADER_TYPE_BRIDGE ||
79 hdr == PCI_HEADER_TYPE_CARDBUS) {
80 unsigned int buses;
81 buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
82 busmaster_disable_on_bus((buses >> 8) & 0xff);
83 }
84 }
85 }
86}
87
Aaron Durbin64031672018-04-21 14:45:32 -060088__weak void southbridge_gate_memory_reset(void)
Arthur Heymansa0508172018-01-25 11:30:22 +010089{
90}
91
Aaron Durbin64031672018-04-21 14:45:32 -060092__weak void southbridge_smm_xhci_sleep(u8 slp_type)
Arthur Heymansa0508172018-01-25 11:30:22 +010093{
94}
95
Kyösti Mälkki3c181862021-01-08 19:01:30 +020096static int power_on_after_fail(void)
Arthur Heymansa0508172018-01-25 11:30:22 +010097{
Nico Huber9faae2b2018-11-14 00:00:35 +010098 u8 s5pwr = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Arthur Heymansa0508172018-01-25 11:30:22 +010099
Kyösti Mälkki3c181862021-01-08 19:01:30 +0200100 /* save and recover RTC port values */
Arthur Heymansa0508172018-01-25 11:30:22 +0100101 u8 tmp70, tmp72;
102 tmp70 = inb(0x70);
103 tmp72 = inb(0x72);
104 get_option(&s5pwr, "power_on_after_fail");
105 outb(tmp70, 0x70);
106 outb(tmp72, 0x72);
107
Kyösti Mälkki3c181862021-01-08 19:01:30 +0200108 /* For "KEEP", switch to "OFF" - KEEP is software emulated. */
109 return (s5pwr == MAINBOARD_POWER_ON);
110}
111
112static void southbridge_smi_sleep(void)
113{
114 u32 reg32;
115 u8 slp_typ;
116
Arthur Heymansa0508172018-01-25 11:30:22 +0100117 /* First, disable further SMIs */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200118 write_pmbase8(SMI_EN, read_pmbase8(SMI_EN) & ~SLP_SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100119
120 /* Figure out SLP_TYP */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200121 reg32 = read_pmbase32(PM1_CNT);
Arthur Heymansa0508172018-01-25 11:30:22 +0100122 slp_typ = acpi_sleep_from_pm1(reg32);
123
Kyösti Mälkkic1d524b2021-01-08 16:41:02 +0200124 printk(BIOS_SPEW, "SMI#: SLP = 0x%08x, TYPE = 0x%02x\n", reg32, slp_typ);
125
Arthur Heymansa0508172018-01-25 11:30:22 +0100126 southbridge_smm_xhci_sleep(slp_typ);
127
128 /* Do any mainboard sleep handling */
129 mainboard_smi_sleep(slp_typ);
130
Arthur Heymansa0508172018-01-25 11:30:22 +0100131 /* Log S3, S4, and S5 entry */
132 if (slp_typ >= ACPI_S3)
Kyösti Mälkki9dd1a122019-11-06 11:04:27 +0200133 elog_gsmi_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ);
Arthur Heymansa0508172018-01-25 11:30:22 +0100134
135 /* Next, do the deed.
136 */
137
138 switch (slp_typ) {
139 case ACPI_S0:
140 printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
141 break;
142 case ACPI_S1:
143 printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n");
144 break;
145 case ACPI_S3:
146 printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
147
148 /* Gate memory reset */
149 southbridge_gate_memory_reset();
150
151 /* Invalidate the cache before going to S3 */
152 wbinvd();
153 break;
154 case ACPI_S4:
155 printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
156 break;
157 case ACPI_S5:
158 printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
159
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200160 write_pmbase32(GPE0_EN, 0);
Arthur Heymansa0508172018-01-25 11:30:22 +0100161
Kyösti Mälkki3c181862021-01-08 19:01:30 +0200162 /* Always set the flag in case CMOS was changed on runtime. */
163 if (power_on_after_fail())
164 pci_and_config8(PCI_DEV(0, 0x1f, 0), D31F0_GEN_PMCON_3, ~1);
165 else
166 pci_or_config8(PCI_DEV(0, 0x1f, 0), D31F0_GEN_PMCON_3, 1);
Arthur Heymansa0508172018-01-25 11:30:22 +0100167
168 /* also iterates over all bridges on bus 0 */
169 busmaster_disable_on_bus(0);
170 break;
171 default: printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); break;
172 }
173
174 /* Write back to the SLP register to cause the originally intended
175 * event again. We need to set BIT13 (SLP_EN) though to make the
176 * sleep happen.
177 */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200178 write_pmbase32(PM1_CNT, reg32 | SLP_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100179
180 /* Make sure to stop executing code here for S3/S4/S5 */
181 if (slp_typ >= ACPI_S3)
182 halt();
183
184 /* In most sleep states, the code flow of this function ends at
185 * the line above. However, if we entered sleep state S1 and wake
186 * up again, we will continue to execute code in this function.
187 */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200188 reg32 = read_pmbase32(PM1_CNT);
Arthur Heymansa0508172018-01-25 11:30:22 +0100189 if (reg32 & SCI_EN) {
190 /* The OS is not an ACPI OS, so we set the state to S0 */
191 reg32 &= ~(SLP_EN | SLP_TYP);
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200192 write_pmbase32(PM1_CNT, reg32);
Arthur Heymansa0508172018-01-25 11:30:22 +0100193 }
194}
195
196/*
197 * Look for Synchronous IO SMI and use save state from that
198 * core in case we are not running on the same core that
199 * initiated the IO transaction.
200 */
Kyösti Mälkki8c2cc682020-06-29 05:57:12 +0300201static em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd)
Arthur Heymansa0508172018-01-25 11:30:22 +0100202{
203 em64t101_smm_state_save_area_t *state;
204 int node;
205
206 /* Check all nodes looking for the one that issued the IO */
207 for (node = 0; node < CONFIG_MAX_CPUS; node++) {
208 state = smm_get_save_state(node);
209
Elyes HAOUAS581fe582018-04-26 09:57:07 +0200210 /* Check for Synchronous IO (bit0 == 1) */
Arthur Heymansa0508172018-01-25 11:30:22 +0100211 if (!(state->io_misc_info & (1 << 0)))
212 continue;
213
Elyes HAOUAS581fe582018-04-26 09:57:07 +0200214 /* Make sure it was a write (bit4 == 0) */
Arthur Heymansa0508172018-01-25 11:30:22 +0100215 if (state->io_misc_info & (1 << 4))
216 continue;
217
218 /* Check for APMC IO port */
219 if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
220 continue;
221
222 /* Check AX against the requested command */
223 if ((state->rax & 0xff) != cmd)
224 continue;
225
226 return state;
227 }
228
229 return NULL;
230}
231
Arthur Heymansa0508172018-01-25 11:30:22 +0100232static void southbridge_smi_gsmi(void)
233{
234 u32 *ret, *param;
235 u8 sub_command;
236 em64t101_smm_state_save_area_t *io_smi =
Patrick Georgid61839c2018-12-03 16:10:33 +0100237 smi_apmc_find_state_save(APM_CNT_ELOG_GSMI);
Arthur Heymansa0508172018-01-25 11:30:22 +0100238
239 if (!io_smi)
240 return;
241
242 /* Command and return value in EAX */
243 ret = (u32*)&io_smi->rax;
244 sub_command = (u8)(*ret >> 8);
245
246 /* Parameter buffer in EBX */
247 param = (u32*)&io_smi->rbx;
248
249 /* drivers/elog/gsmi.c */
250 *ret = gsmi_exec(sub_command, param);
251}
Arthur Heymansa0508172018-01-25 11:30:22 +0100252
Arthur Heymans4c804252018-12-03 01:28:18 +0100253static void southbridge_smi_store(void)
254{
255 u8 sub_command, ret;
256 em64t101_smm_state_save_area_t *io_smi =
257 smi_apmc_find_state_save(APM_CNT_SMMSTORE);
Patrick Rudolph03cfae42019-10-20 18:09:58 +0200258 uintptr_t reg_rbx;
Arthur Heymans4c804252018-12-03 01:28:18 +0100259
260 if (!io_smi)
261 return;
262 /* Command and return value in EAX */
263 sub_command = (io_smi->rax >> 8) & 0xff;
264
265 /* Parameter buffer in EBX */
Patrick Rudolph03cfae42019-10-20 18:09:58 +0200266 reg_rbx = (uintptr_t)io_smi->rbx;
Arthur Heymans4c804252018-12-03 01:28:18 +0100267
268 /* drivers/smmstore/smi.c */
Patrick Rudolph03cfae42019-10-20 18:09:58 +0200269 ret = smmstore_exec(sub_command, (void *)reg_rbx);
Arthur Heymans4c804252018-12-03 01:28:18 +0100270 io_smi->rax = ret;
271}
272
Arthur Heymansa0508172018-01-25 11:30:22 +0100273static int mainboard_finalized = 0;
274
275static void southbridge_smi_apmc(void)
276{
Arthur Heymansa0508172018-01-25 11:30:22 +0100277 u8 reg8;
278
Kyösti Mälkki9a1620f2021-01-08 13:27:33 +0200279 reg8 = apm_get_apmc();
Arthur Heymansa0508172018-01-25 11:30:22 +0100280 switch (reg8) {
Arthur Heymansa0508172018-01-25 11:30:22 +0100281 case APM_CNT_ACPI_DISABLE:
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200282 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT) & ~SCI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100283 break;
284 case APM_CNT_ACPI_ENABLE:
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200285 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT) | SCI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100286 break;
Arthur Heymansa0508172018-01-25 11:30:22 +0100287 case APM_CNT_FINALIZE:
288 if (mainboard_finalized) {
289 printk(BIOS_DEBUG, "SMI#: Already finalized\n");
290 return;
291 }
292
293 southbridge_finalize_all();
294 mainboard_finalized = 1;
295 break;
Patrick Georgid61839c2018-12-03 16:10:33 +0100296 case APM_CNT_ELOG_GSMI:
Kyösti Mälkki9dd1a122019-11-06 11:04:27 +0200297 if (CONFIG(ELOG_GSMI))
298 southbridge_smi_gsmi();
Arthur Heymansa0508172018-01-25 11:30:22 +0100299 break;
Arthur Heymans4c804252018-12-03 01:28:18 +0100300 case APM_CNT_SMMSTORE:
301 if (CONFIG(SMMSTORE))
302 southbridge_smi_store();
303 break;
Arthur Heymansa0508172018-01-25 11:30:22 +0100304 }
305
306 mainboard_smi_apmc(reg8);
307}
308
309static void southbridge_smi_pm1(void)
310{
311 u16 pm1_sts;
312
313 pm1_sts = reset_pm1_status();
314 dump_pm1_status(pm1_sts);
315
316 /* While OSPM is not active, poweroff immediately
317 * on a power button event.
318 */
319 if (pm1_sts & PWRBTN_STS) {
320 // power button pressed
321 u32 reg32;
322 reg32 = (7 << 10) | (1 << 13);
Kyösti Mälkki9dd1a122019-11-06 11:04:27 +0200323 elog_gsmi_add_event(ELOG_TYPE_POWER_BUTTON);
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200324 write_pmbase32(PM1_CNT, reg32);
Arthur Heymansa0508172018-01-25 11:30:22 +0100325 }
326}
327
328static void southbridge_smi_gpe0(void)
329{
330 u32 gpe0_sts;
331
332 gpe0_sts = reset_gpe0_status();
333 dump_gpe0_status(gpe0_sts);
334}
335
336static void southbridge_smi_gpi(void)
337{
338 u16 reg16;
Arthur Heymansa0508172018-01-25 11:30:22 +0100339
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200340 reg16 = reset_alt_gp_smi_status();
341 reg16 &= read_pmbase16(ALT_GP_SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100342
343 mainboard_smi_gpi(reg16);
344
345 if (reg16)
346 printk(BIOS_DEBUG, "GPI (mask %04x)\n", reg16);
347
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200348 write_pmbase16(ALT_GP_SMI_STS, reg16);
Arthur Heymansa0508172018-01-25 11:30:22 +0100349}
350
351static void southbridge_smi_mc(void)
352{
353 u32 reg32;
354
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200355 reg32 = read_pmbase32(SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100356
357 /* Are periodic SMIs enabled? */
358 if ((reg32 & MCSMI_EN) == 0)
359 return;
360
361 printk(BIOS_DEBUG, "Microcontroller SMI.\n");
362}
363
Arthur Heymansa0508172018-01-25 11:30:22 +0100364static void southbridge_smi_tco(void)
365{
366 u32 tco_sts;
367
368 tco_sts = reset_tco_status();
369
370 /* Any TCO event? */
371 if (!tco_sts)
372 return;
373
374 if (tco_sts & (1 << 8)) { // BIOSWR
375 u8 bios_cntl;
376
Angel Ponscc36c4c2021-03-30 10:49:24 +0200377 bios_cntl = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xdc);
Arthur Heymansa0508172018-01-25 11:30:22 +0100378
379 if (bios_cntl & 1) {
380 /* BWE is RW, so the SMI was caused by a
381 * write to BWE, not by a write to the BIOS
382 */
383
384 /* This is the place where we notice someone
385 * is trying to tinker with the BIOS. We are
386 * trying to be nice and just ignore it. A more
387 * resolute answer would be to power down the
388 * box.
389 */
390 printk(BIOS_DEBUG, "Switching back to RO\n");
Angel Ponscc36c4c2021-03-30 10:49:24 +0200391 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xdc,
Arthur Heymansa0508172018-01-25 11:30:22 +0100392 (bios_cntl & ~1));
393 } /* No else for now? */
394 } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
395 /* Handle TCO timeout */
396 printk(BIOS_DEBUG, "TCO Timeout.\n");
Jacob Garber7eb8eed2019-04-03 09:18:32 -0600397 } else {
Arthur Heymansa0508172018-01-25 11:30:22 +0100398 dump_tco_status(tco_sts);
399 }
400}
401
402static void southbridge_smi_periodic(void)
403{
404 u32 reg32;
405
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200406 reg32 = read_pmbase32(SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100407
408 /* Are periodic SMIs enabled? */
409 if ((reg32 & PERIODIC_EN) == 0)
410 return;
411
412 printk(BIOS_DEBUG, "Periodic SMI.\n");
413}
414
415typedef void (*smi_handler_t)(void);
416
417static smi_handler_t southbridge_smi[32] = {
418 NULL, // [0] reserved
419 NULL, // [1] reserved
420 NULL, // [2] BIOS_STS
421 NULL, // [3] LEGACY_USB_STS
422 southbridge_smi_sleep, // [4] SLP_SMI_STS
423 southbridge_smi_apmc, // [5] APM_STS
424 NULL, // [6] SWSMI_TMR_STS
425 NULL, // [7] reserved
426 southbridge_smi_pm1, // [8] PM1_STS
427 southbridge_smi_gpe0, // [9] GPE0_STS
428 southbridge_smi_gpi, // [10] GPI_STS
429 southbridge_smi_mc, // [11] MCSMI_STS
430 NULL, // [12] DEVMON_STS
431 southbridge_smi_tco, // [13] TCO_STS
432 southbridge_smi_periodic, // [14] PERIODIC_STS
433 NULL, // [15] SERIRQ_SMI_STS
434 NULL, // [16] SMBUS_SMI_STS
435 NULL, // [17] LEGACY_USB2_STS
436 NULL, // [18] INTEL_USB2_STS
437 NULL, // [19] reserved
438 NULL, // [20] PCI_EXP_SMI_STS
439 southbridge_smi_monitor, // [21] MONITOR_STS
440 NULL, // [22] reserved
441 NULL, // [23] reserved
442 NULL, // [24] reserved
443 NULL, // [25] EL_SMI_STS
444 NULL, // [26] SPI_STS
445 NULL, // [27] reserved
446 NULL, // [28] reserved
447 NULL, // [29] reserved
448 NULL, // [30] reserved
449 NULL // [31] reserved
450};
451
452/**
453 * @brief Interrupt handler for SMI#
Arthur Heymansa0508172018-01-25 11:30:22 +0100454 */
455void southbridge_smi_handler(void)
456{
457 int i, dump = 0;
458 u32 smi_sts;
459
Arthur Heymansa0508172018-01-25 11:30:22 +0100460 /* We need to clear the SMI status registers, or we won't see what's
461 * happening in the following calls.
462 */
463 smi_sts = reset_smi_status();
464
465 /* Call SMI sub handler for each of the status bits */
466 for (i = 0; i < 31; i++) {
467 if (smi_sts & (1 << i)) {
468 if (southbridge_smi[i]) {
469 southbridge_smi[i]();
470 } else {
471 printk(BIOS_DEBUG, "SMI_STS[%d] occurred,"
472 " but no handler available.\n", i);
473 dump = 1;
474 }
475 }
476 }
477
478 if (dump) {
479 dump_smi_status(smi_sts);
480 }
481}