blob: 05b73f20c3b48d697c07046f66200dd86e9bbc3b [file] [log] [blame]
Arthur Heymansa0508172018-01-25 11:30:22 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <types.h>
18#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020019#include <device/pci_ops.h>
Arthur Heymansa0508172018-01-25 11:30:22 +010020#include <arch/acpi.h>
21#include <console/console.h>
22#include <cpu/x86/cache.h>
23#include <device/pci_def.h>
24#include <cpu/x86/smm.h>
25#include <elog.h>
26#include <halt.h>
27#include <pc80/mc146818rtc.h>
Patrick Rudolphed3242e2018-06-29 10:34:37 +020028#include <southbridge/intel/common/pmbase.h>
29
Arthur Heymansa0508172018-01-25 11:30:22 +010030#include "pmutil.h"
31
32static int smm_initialized = 0;
33
Arthur Heymansa0508172018-01-25 11:30:22 +010034u16 get_pmbase(void)
35{
Patrick Rudolphed3242e2018-06-29 10:34:37 +020036 return lpc_get_pmbase();
Arthur Heymansa0508172018-01-25 11:30:22 +010037}
38
Arthur Heymansa0508172018-01-25 11:30:22 +010039void gpi_route_interrupt(u8 gpi, u8 mode)
40{
41 u32 gpi_rout;
42 if (gpi >= 16)
43 return;
44
45 alt_gpi_mask(1 << gpi, 0);
46 gpe0_mask(1 << (gpi+16), 0);
47
48 gpi_rout = pci_read_config32(PCI_DEV(0, 0x1f, 0), D31F0_GPIO_ROUT);
49 gpi_rout &= ~(3 << (2 * gpi));
50 gpi_rout |= ((mode & 3) << (2 * gpi));
51 pci_write_config32(PCI_DEV(0, 0x1f, 0), D31F0_GPIO_ROUT, gpi_rout);
52
53 if (mode == GPI_IS_SCI)
54 gpe0_mask(0, 1 << (gpi+16));
55 else if (mode == GPI_IS_SMI)
56 alt_gpi_mask(0, 1 << gpi);
57}
58
59/**
60 * @brief Set the EOS bit
61 */
62void southbridge_smi_set_eos(void)
63{
Patrick Rudolphed3242e2018-06-29 10:34:37 +020064 write_pmbase8(SMI_EN, read_pmbase8(SMI_EN) | EOS);
Arthur Heymansa0508172018-01-25 11:30:22 +010065}
66
67static void busmaster_disable_on_bus(int bus)
68{
69 int slot, func;
70 unsigned int val;
71 unsigned char hdr;
72
73 for (slot = 0; slot < 0x20; slot++) {
74 for (func = 0; func < 8; func++) {
75 u32 reg32;
76 pci_devfn_t dev = PCI_DEV(bus, slot, func);
77
78 val = pci_read_config32(dev, PCI_VENDOR_ID);
79
80 if (val == 0xffffffff || val == 0x00000000 ||
81 val == 0x0000ffff || val == 0xffff0000)
82 continue;
83
84 /* Disable Bus Mastering for this one device */
85 reg32 = pci_read_config32(dev, PCI_COMMAND);
86 reg32 &= ~PCI_COMMAND_MASTER;
87 pci_write_config32(dev, PCI_COMMAND, reg32);
88
89 /* If this is a bridge, then follow it. */
90 hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
91 hdr &= 0x7f;
92 if (hdr == PCI_HEADER_TYPE_BRIDGE ||
93 hdr == PCI_HEADER_TYPE_CARDBUS) {
94 unsigned int buses;
95 buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
96 busmaster_disable_on_bus((buses >> 8) & 0xff);
97 }
98 }
99 }
100}
101
Aaron Durbin64031672018-04-21 14:45:32 -0600102__weak void southbridge_gate_memory_reset(void)
Arthur Heymansa0508172018-01-25 11:30:22 +0100103{
104}
105
Aaron Durbin64031672018-04-21 14:45:32 -0600106__weak void southbridge_smm_xhci_sleep(u8 slp_type)
Arthur Heymansa0508172018-01-25 11:30:22 +0100107{
108}
109
110
111static void southbridge_smi_sleep(void)
112{
113 u8 reg8;
114 u32 reg32;
115 u8 slp_typ;
Nico Huber9faae2b2018-11-14 00:00:35 +0100116 u8 s5pwr = CONFIG_MAINBOARD_POWER_FAILURE_STATE;
Arthur Heymansa0508172018-01-25 11:30:22 +0100117
118 // save and recover RTC port values
119 u8 tmp70, tmp72;
120 tmp70 = inb(0x70);
121 tmp72 = inb(0x72);
122 get_option(&s5pwr, "power_on_after_fail");
123 outb(tmp70, 0x70);
124 outb(tmp72, 0x72);
125
126 /* First, disable further SMIs */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200127 write_pmbase8(SMI_EN, read_pmbase8(SMI_EN) & ~SLP_SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100128
129 /* Figure out SLP_TYP */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200130 reg32 = read_pmbase32(PM1_CNT);
Arthur Heymansa0508172018-01-25 11:30:22 +0100131 printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
132 slp_typ = acpi_sleep_from_pm1(reg32);
133
134 southbridge_smm_xhci_sleep(slp_typ);
135
136 /* Do any mainboard sleep handling */
137 mainboard_smi_sleep(slp_typ);
138
139#if IS_ENABLED(CONFIG_ELOG_GSMI)
140 /* Log S3, S4, and S5 entry */
141 if (slp_typ >= ACPI_S3)
142 elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ);
143#endif
144
145 /* Next, do the deed.
146 */
147
148 switch (slp_typ) {
149 case ACPI_S0:
150 printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
151 break;
152 case ACPI_S1:
153 printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n");
154 break;
155 case ACPI_S3:
156 printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
157
158 /* Gate memory reset */
159 southbridge_gate_memory_reset();
160
161 /* Invalidate the cache before going to S3 */
162 wbinvd();
163 break;
164 case ACPI_S4:
165 printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
166 break;
167 case ACPI_S5:
168 printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
169
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200170 write_pmbase32(GPE0_EN, 0);
Arthur Heymansa0508172018-01-25 11:30:22 +0100171
172 /* Always set the flag in case CMOS was changed on runtime. For
173 * "KEEP", switch to "OFF" - KEEP is software emulated
174 */
175 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), D31F0_GEN_PMCON_3);
176 if (s5pwr == MAINBOARD_POWER_ON) {
177 reg8 &= ~1;
178 } else {
179 reg8 |= 1;
180 }
181 pci_write_config8(PCI_DEV(0, 0x1f, 0), D31F0_GEN_PMCON_3, reg8);
182
183 /* also iterates over all bridges on bus 0 */
184 busmaster_disable_on_bus(0);
185 break;
186 default: printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); break;
187 }
188
189 /* Write back to the SLP register to cause the originally intended
190 * event again. We need to set BIT13 (SLP_EN) though to make the
191 * sleep happen.
192 */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200193 write_pmbase32(PM1_CNT, reg32 | SLP_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100194
195 /* Make sure to stop executing code here for S3/S4/S5 */
196 if (slp_typ >= ACPI_S3)
197 halt();
198
199 /* In most sleep states, the code flow of this function ends at
200 * the line above. However, if we entered sleep state S1 and wake
201 * up again, we will continue to execute code in this function.
202 */
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200203 reg32 = read_pmbase32(PM1_CNT);
Arthur Heymansa0508172018-01-25 11:30:22 +0100204 if (reg32 & SCI_EN) {
205 /* The OS is not an ACPI OS, so we set the state to S0 */
206 reg32 &= ~(SLP_EN | SLP_TYP);
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200207 write_pmbase32(PM1_CNT, reg32);
Arthur Heymansa0508172018-01-25 11:30:22 +0100208 }
209}
210
211/*
212 * Look for Synchronous IO SMI and use save state from that
213 * core in case we are not running on the same core that
214 * initiated the IO transaction.
215 */
216em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd)
217{
218 em64t101_smm_state_save_area_t *state;
219 int node;
220
221 /* Check all nodes looking for the one that issued the IO */
222 for (node = 0; node < CONFIG_MAX_CPUS; node++) {
223 state = smm_get_save_state(node);
224
Elyes HAOUAS581fe582018-04-26 09:57:07 +0200225 /* Check for Synchronous IO (bit0 == 1) */
Arthur Heymansa0508172018-01-25 11:30:22 +0100226 if (!(state->io_misc_info & (1 << 0)))
227 continue;
228
Elyes HAOUAS581fe582018-04-26 09:57:07 +0200229 /* Make sure it was a write (bit4 == 0) */
Arthur Heymansa0508172018-01-25 11:30:22 +0100230 if (state->io_misc_info & (1 << 4))
231 continue;
232
233 /* Check for APMC IO port */
234 if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
235 continue;
236
237 /* Check AX against the requested command */
238 if ((state->rax & 0xff) != cmd)
239 continue;
240
241 return state;
242 }
243
244 return NULL;
245}
246
247#if IS_ENABLED(CONFIG_ELOG_GSMI)
248static void southbridge_smi_gsmi(void)
249{
250 u32 *ret, *param;
251 u8 sub_command;
252 em64t101_smm_state_save_area_t *io_smi =
Patrick Georgid61839c2018-12-03 16:10:33 +0100253 smi_apmc_find_state_save(APM_CNT_ELOG_GSMI);
Arthur Heymansa0508172018-01-25 11:30:22 +0100254
255 if (!io_smi)
256 return;
257
258 /* Command and return value in EAX */
259 ret = (u32*)&io_smi->rax;
260 sub_command = (u8)(*ret >> 8);
261
262 /* Parameter buffer in EBX */
263 param = (u32*)&io_smi->rbx;
264
265 /* drivers/elog/gsmi.c */
266 *ret = gsmi_exec(sub_command, param);
267}
268#endif
269
270static int mainboard_finalized = 0;
271
272static void southbridge_smi_apmc(void)
273{
Arthur Heymansa0508172018-01-25 11:30:22 +0100274 u8 reg8;
275
276 /* Emulate B2 register as the FADT / Linux expects it */
277
278 reg8 = inb(APM_CNT);
279 switch (reg8) {
280 case APM_CNT_CST_CONTROL:
281 /* Calling this function seems to cause
282 * some kind of race condition in Linux
283 * and causes a kernel oops
284 */
285 printk(BIOS_DEBUG, "C-state control\n");
286 break;
287 case APM_CNT_PST_CONTROL:
288 /* Calling this function seems to cause
289 * some kind of race condition in Linux
290 * and causes a kernel oops
291 */
292 printk(BIOS_DEBUG, "P-state control\n");
293 break;
294 case APM_CNT_ACPI_DISABLE:
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200295 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT) & ~SCI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100296 printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
297 break;
298 case APM_CNT_ACPI_ENABLE:
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200299 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT) | SCI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100300 printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
301 break;
302 case APM_CNT_GNVS_UPDATE:
303 if (smm_initialized) {
304 printk(BIOS_DEBUG,
305 "SMI#: SMM structures already initialized!\n");
306 return;
307 }
308 southbridge_update_gnvs(reg8, &smm_initialized);
309 break;
310 case APM_CNT_FINALIZE:
311 if (mainboard_finalized) {
312 printk(BIOS_DEBUG, "SMI#: Already finalized\n");
313 return;
314 }
315
316 southbridge_finalize_all();
317 mainboard_finalized = 1;
318 break;
319#if IS_ENABLED(CONFIG_ELOG_GSMI)
Patrick Georgid61839c2018-12-03 16:10:33 +0100320 case APM_CNT_ELOG_GSMI:
Arthur Heymansa0508172018-01-25 11:30:22 +0100321 southbridge_smi_gsmi();
322 break;
323#endif
324 }
325
326 mainboard_smi_apmc(reg8);
327}
328
329static void southbridge_smi_pm1(void)
330{
331 u16 pm1_sts;
332
333 pm1_sts = reset_pm1_status();
334 dump_pm1_status(pm1_sts);
335
336 /* While OSPM is not active, poweroff immediately
337 * on a power button event.
338 */
339 if (pm1_sts & PWRBTN_STS) {
340 // power button pressed
341 u32 reg32;
342 reg32 = (7 << 10) | (1 << 13);
343#if IS_ENABLED(CONFIG_ELOG_GSMI)
344 elog_add_event(ELOG_TYPE_POWER_BUTTON);
345#endif
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200346 write_pmbase32(PM1_CNT, reg32);
Arthur Heymansa0508172018-01-25 11:30:22 +0100347 }
348}
349
350static void southbridge_smi_gpe0(void)
351{
352 u32 gpe0_sts;
353
354 gpe0_sts = reset_gpe0_status();
355 dump_gpe0_status(gpe0_sts);
356}
357
358static void southbridge_smi_gpi(void)
359{
360 u16 reg16;
Arthur Heymansa0508172018-01-25 11:30:22 +0100361
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200362 reg16 = reset_alt_gp_smi_status();
363 reg16 &= read_pmbase16(ALT_GP_SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100364
365 mainboard_smi_gpi(reg16);
366
367 if (reg16)
368 printk(BIOS_DEBUG, "GPI (mask %04x)\n", reg16);
369
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200370 write_pmbase16(ALT_GP_SMI_STS, reg16);
Arthur Heymansa0508172018-01-25 11:30:22 +0100371}
372
373static void southbridge_smi_mc(void)
374{
375 u32 reg32;
376
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200377 reg32 = read_pmbase32(SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100378
379 /* Are periodic SMIs enabled? */
380 if ((reg32 & MCSMI_EN) == 0)
381 return;
382
383 printk(BIOS_DEBUG, "Microcontroller SMI.\n");
384}
385
386
387
388static void southbridge_smi_tco(void)
389{
390 u32 tco_sts;
391
392 tco_sts = reset_tco_status();
393
394 /* Any TCO event? */
395 if (!tco_sts)
396 return;
397
398 if (tco_sts & (1 << 8)) { // BIOSWR
399 u8 bios_cntl;
400
401 bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc);
402
403 if (bios_cntl & 1) {
404 /* BWE is RW, so the SMI was caused by a
405 * write to BWE, not by a write to the BIOS
406 */
407
408 /* This is the place where we notice someone
409 * is trying to tinker with the BIOS. We are
410 * trying to be nice and just ignore it. A more
411 * resolute answer would be to power down the
412 * box.
413 */
414 printk(BIOS_DEBUG, "Switching back to RO\n");
415 pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc,
416 (bios_cntl & ~1));
417 } /* No else for now? */
418 } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
419 /* Handle TCO timeout */
420 printk(BIOS_DEBUG, "TCO Timeout.\n");
421 } else if (!tco_sts) {
422 dump_tco_status(tco_sts);
423 }
424}
425
426static void southbridge_smi_periodic(void)
427{
428 u32 reg32;
429
Patrick Rudolphed3242e2018-06-29 10:34:37 +0200430 reg32 = read_pmbase32(SMI_EN);
Arthur Heymansa0508172018-01-25 11:30:22 +0100431
432 /* Are periodic SMIs enabled? */
433 if ((reg32 & PERIODIC_EN) == 0)
434 return;
435
436 printk(BIOS_DEBUG, "Periodic SMI.\n");
437}
438
439typedef void (*smi_handler_t)(void);
440
441static smi_handler_t southbridge_smi[32] = {
442 NULL, // [0] reserved
443 NULL, // [1] reserved
444 NULL, // [2] BIOS_STS
445 NULL, // [3] LEGACY_USB_STS
446 southbridge_smi_sleep, // [4] SLP_SMI_STS
447 southbridge_smi_apmc, // [5] APM_STS
448 NULL, // [6] SWSMI_TMR_STS
449 NULL, // [7] reserved
450 southbridge_smi_pm1, // [8] PM1_STS
451 southbridge_smi_gpe0, // [9] GPE0_STS
452 southbridge_smi_gpi, // [10] GPI_STS
453 southbridge_smi_mc, // [11] MCSMI_STS
454 NULL, // [12] DEVMON_STS
455 southbridge_smi_tco, // [13] TCO_STS
456 southbridge_smi_periodic, // [14] PERIODIC_STS
457 NULL, // [15] SERIRQ_SMI_STS
458 NULL, // [16] SMBUS_SMI_STS
459 NULL, // [17] LEGACY_USB2_STS
460 NULL, // [18] INTEL_USB2_STS
461 NULL, // [19] reserved
462 NULL, // [20] PCI_EXP_SMI_STS
463 southbridge_smi_monitor, // [21] MONITOR_STS
464 NULL, // [22] reserved
465 NULL, // [23] reserved
466 NULL, // [24] reserved
467 NULL, // [25] EL_SMI_STS
468 NULL, // [26] SPI_STS
469 NULL, // [27] reserved
470 NULL, // [28] reserved
471 NULL, // [29] reserved
472 NULL, // [30] reserved
473 NULL // [31] reserved
474};
475
476/**
477 * @brief Interrupt handler for SMI#
478 * @param node
479 * @param state_save
480 */
Arthur Heymansaade90e2018-01-25 00:33:45 +0100481#if IS_ENABLED(CONFIG_SMM_TSEG)
Arthur Heymansa0508172018-01-25 11:30:22 +0100482void southbridge_smi_handler(void)
Arthur Heymansaade90e2018-01-25 00:33:45 +0100483#else
484void cpu_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
485#endif
Arthur Heymansa0508172018-01-25 11:30:22 +0100486{
487 int i, dump = 0;
488 u32 smi_sts;
489
Arthur Heymansa0508172018-01-25 11:30:22 +0100490 /* We need to clear the SMI status registers, or we won't see what's
491 * happening in the following calls.
492 */
493 smi_sts = reset_smi_status();
494
495 /* Call SMI sub handler for each of the status bits */
496 for (i = 0; i < 31; i++) {
497 if (smi_sts & (1 << i)) {
498 if (southbridge_smi[i]) {
499 southbridge_smi[i]();
500 } else {
501 printk(BIOS_DEBUG, "SMI_STS[%d] occurred,"
502 " but no handler available.\n", i);
503 dump = 1;
504 }
505 }
506 }
507
508 if (dump) {
509 dump_smi_status(smi_sts);
510 }
511}