blob: c1092b9242d92181022532dc374cd17339078884 [file] [log] [blame]
Duncan Lauriec88c54c2014-04-30 16:36:13 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2014 Google Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of 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.
Duncan Lauriec88c54c2014-04-30 16:36:13 -070015 */
16
17#include <delay.h>
18#include <types.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070019#include <arch/io.h>
20#include <console/console.h>
21#include <cpu/x86/cache.h>
22#include <device/pci_def.h>
23#include <cpu/x86/smm.h>
24#include <spi-generic.h>
25#include <elog.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010026#include <halt.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070027#include <pc80/mc146818rtc.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070028#include <soc/lpc.h>
29#include <soc/nvs.h>
30#include <soc/pci_devs.h>
31#include <soc/pm.h>
32#include <soc/rcba.h>
33#include <soc/smm.h>
34#include <soc/xhci.h>
Duncan Laurief3e0a132015-01-14 17:33:00 -080035#include <drivers/intel/gma/i915_reg.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070036
37static u8 smm_initialized = 0;
38
39/*
40 * GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
41 * by coreboot.
42 */
43static global_nvs_t *gnvs;
44global_nvs_t *smm_get_gnvs(void)
45{
46 return gnvs;
47}
48
49int southbridge_io_trap_handler(int smif)
50{
51 switch (smif) {
52 case 0x32:
53 printk(BIOS_DEBUG, "OS Init\n");
54 /* gnvs->smif:
55 * On success, the IO Trap Handler returns 0
56 * On failure, the IO Trap Handler returns a value != 0
57 */
58 gnvs->smif = 0;
59 return 1; /* IO trap handled */
60 }
61
62 /* Not handled */
63 return 0;
64}
65
66/**
67 * @brief Set the EOS bit
68 */
69void southbridge_smi_set_eos(void)
70{
71 enable_smi(EOS);
72}
73
74static void busmaster_disable_on_bus(int bus)
75{
Lee Leahy26b7cd02017-03-16 18:47:55 -070076 int slot, func;
77 unsigned int val;
78 unsigned char hdr;
Duncan Lauriec88c54c2014-04-30 16:36:13 -070079
Lee Leahy26b7cd02017-03-16 18:47:55 -070080 for (slot = 0; slot < 0x20; slot++) {
81 for (func = 0; func < 8; func++) {
82 u32 reg32;
83 device_t dev = PCI_DEV(bus, slot, func);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070084
Lee Leahy26b7cd02017-03-16 18:47:55 -070085 val = pci_read_config32(dev, PCI_VENDOR_ID);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070086
Lee Leahy26b7cd02017-03-16 18:47:55 -070087 if (val == 0xffffffff || val == 0x00000000 ||
88 val == 0x0000ffff || val == 0xffff0000)
89 continue;
Duncan Lauriec88c54c2014-04-30 16:36:13 -070090
Lee Leahy26b7cd02017-03-16 18:47:55 -070091 /* Disable Bus Mastering for this one device */
92 reg32 = pci_read_config32(dev, PCI_COMMAND);
93 reg32 &= ~PCI_COMMAND_MASTER;
94 pci_write_config32(dev, PCI_COMMAND, reg32);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070095
Lee Leahy26b7cd02017-03-16 18:47:55 -070096 /* If this is a bridge, then follow it. */
97 hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
98 hdr &= 0x7f;
99 if (hdr == PCI_HEADER_TYPE_BRIDGE ||
100 hdr == PCI_HEADER_TYPE_CARDBUS) {
101 unsigned int buses;
102 buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
103 busmaster_disable_on_bus((buses >> 8) & 0xff);
104 }
105 }
106 }
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700107}
108
Duncan Laurief3e0a132015-01-14 17:33:00 -0800109/*
110 * Turn off the backlight if it is on, and wait for the specified
111 * backlight off delay. This will allow panel power timings to meet
112 * spec and prevent brief garbage on the screen when turned off
113 * during firmware with power button triggered SMI.
114 */
115static void backlight_off(void)
116{
117 void *reg_base;
118 uint32_t pp_ctrl;
119 uint32_t bl_off_delay;
120
121 reg_base = (void *)((uintptr_t)pci_read_config32(SA_DEV_IGD, PCI_BASE_ADDRESS_0) & ~0xf);
122
123 /* Check if backlight is enabled */
124 pp_ctrl = read32(reg_base + PCH_PP_CONTROL);
125 if (!(pp_ctrl & EDP_BLC_ENABLE))
126 return;
127
128 /* Enable writes to this register */
129 pp_ctrl &= ~PANEL_UNLOCK_MASK;
130 pp_ctrl |= PANEL_UNLOCK_REGS;
131
132 /* Turn off backlight */
133 pp_ctrl &= ~EDP_BLC_ENABLE;
134
135 write32(reg_base + PCH_PP_CONTROL, pp_ctrl);
136 read32(reg_base + PCH_PP_CONTROL);
137
138 /* Read backlight off delay in 100us units */
139 bl_off_delay = read32(reg_base + PCH_PP_OFF_DELAYS);
140 bl_off_delay &= PANEL_LIGHT_OFF_DELAY_MASK;
141 bl_off_delay *= 100;
142
143 /* Wait for backlight to turn off */
144 udelay(bl_off_delay);
145
146 printk(BIOS_INFO, "Backlight turned off\n");
147}
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700148
149static void southbridge_smi_sleep(void)
150{
151 u8 reg8;
152 u32 reg32;
153 u8 slp_typ;
154 u8 s5pwr = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
155
156 /* save and recover RTC port values */
157 u8 tmp70, tmp72;
158 tmp70 = inb(0x70);
159 tmp72 = inb(0x72);
160 get_option(&s5pwr, "power_on_after_fail");
161 outb(tmp70, 0x70);
162 outb(tmp72, 0x72);
163
164 /* First, disable further SMIs */
165 disable_smi(SLP_SMI_EN);
166
167 /* Figure out SLP_TYP */
168 reg32 = inl(ACPI_BASE_ADDRESS + PM1_CNT);
169 printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500170 slp_typ = acpi_sleep_from_pm1(reg32);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700171
172 /* Do any mainboard sleep handling */
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500173 mainboard_smi_sleep(slp_typ);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700174
175 /* USB sleep preparations */
176 usb_xhci_sleep_prepare(PCH_DEV_XHCI, slp_typ);
177
178#if CONFIG_ELOG_GSMI
179 /* Log S3, S4, and S5 entry */
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500180 if (slp_typ >= ACPI_S3)
181 elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700182#endif
183
Duncan Lauried775dda2014-10-25 01:49:32 -0700184 /* Clear pending GPE events */
185 clear_gpe_status();
186
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700187 /* Next, do the deed.
188 */
189
190 switch (slp_typ) {
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500191 case ACPI_S0:
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700192 printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
193 break;
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500194 case ACPI_S1:
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700195 printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n");
196 break;
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500197 case ACPI_S3:
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700198 printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
199
200 /* Invalidate the cache before going to S3 */
201 wbinvd();
202 break;
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500203 case ACPI_S4:
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700204 printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
205 break;
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500206 case ACPI_S5:
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700207 printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
208
Duncan Laurief3e0a132015-01-14 17:33:00 -0800209 /* Turn off backlight if needed */
210 backlight_off();
211
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700212 /* Disable all GPE */
213 disable_all_gpe();
214
215 /* Always set the flag in case CMOS was changed on runtime. For
216 * "KEEP", switch to "OFF" - KEEP is software emulated
217 */
218 reg8 = pci_read_config8(PCH_DEV_LPC, GEN_PMCON_3);
219 if (s5pwr == MAINBOARD_POWER_ON)
220 reg8 &= ~1;
221 else
222 reg8 |= 1;
223 pci_write_config8(PCH_DEV_LPC, GEN_PMCON_3, reg8);
224
225 /* also iterates over all bridges on bus 0 */
226 busmaster_disable_on_bus(0);
227 break;
228 default:
229 printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
230 break;
231 }
232
233 /*
234 * Write back to the SLP register to cause the originally intended
235 * event again. We need to set BIT13 (SLP_EN) though to make the
236 * sleep happen.
237 */
238 enable_pm1_control(SLP_EN);
239
240 /* Make sure to stop executing code here for S3/S4/S5 */
Aaron Durbin9e6d1432016-07-13 23:21:41 -0500241 if (slp_typ >= ACPI_S3)
Patrick Georgi546953c2014-11-29 10:38:17 +0100242 halt();
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700243
244 /*
245 * In most sleep states, the code flow of this function ends at
246 * the line above. However, if we entered sleep state S1 and wake
247 * up again, we will continue to execute code in this function.
248 */
249 reg32 = inl(ACPI_BASE_ADDRESS + PM1_CNT);
250 if (reg32 & SCI_EN) {
251 /* The OS is not an ACPI OS, so we set the state to S0 */
252 disable_pm1_control(SLP_EN | SLP_TYP);
253 }
254}
255
256/*
257 * Look for Synchronous IO SMI and use save state from that
258 * core in case we are not running on the same core that
259 * initiated the IO transaction.
260 */
261static em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd)
262{
263 em64t101_smm_state_save_area_t *state;
264 int node;
265
266 /* Check all nodes looking for the one that issued the IO */
267 for (node = 0; node < CONFIG_MAX_CPUS; node++) {
268 state = smm_get_save_state(node);
269
270 /* Check for Synchronous IO (bit0==1) */
271 if (!(state->io_misc_info & (1 << 0)))
272 continue;
273
274 /* Make sure it was a write (bit4==0) */
275 if (state->io_misc_info & (1 << 4))
276 continue;
277
278 /* Check for APMC IO port */
279 if (((state->io_misc_info >> 16) & 0xff) != APM_CNT)
280 continue;
281
282 /* Check AX against the requested command */
283 if ((state->rax & 0xff) != cmd)
284 continue;
285
286 return state;
287 }
288
289 return NULL;
290}
291
292#if CONFIG_ELOG_GSMI
293static void southbridge_smi_gsmi(void)
294{
295 u32 *ret, *param;
296 u8 sub_command;
297 em64t101_smm_state_save_area_t *io_smi =
298 smi_apmc_find_state_save(ELOG_GSMI_APM_CNT);
299
300 if (!io_smi)
301 return;
302
303 /* Command and return value in EAX */
Lee Leahy26b7cd02017-03-16 18:47:55 -0700304 ret = (u32 *)&io_smi->rax;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700305 sub_command = (u8)(*ret >> 8);
306
307 /* Parameter buffer in EBX */
Lee Leahy26b7cd02017-03-16 18:47:55 -0700308 param = (u32 *)&io_smi->rbx;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700309
310 /* drivers/elog/gsmi.c */
311 *ret = gsmi_exec(sub_command, param);
312}
313#endif
314
315static void finalize(void)
316{
317 static int finalize_done;
318
319 if (finalize_done) {
320 printk(BIOS_DEBUG, "SMM already finalized.\n");
321 return;
322 }
323 finalize_done = 1;
324
325#if CONFIG_SPI_FLASH_SMM
326 /* Re-init SPI driver to handle locked BAR */
327 spi_init();
328#endif
329}
330
331static void southbridge_smi_apmc(void)
332{
333 u8 reg8;
334 em64t101_smm_state_save_area_t *state;
335
336 /* Emulate B2 register as the FADT / Linux expects it */
337
338 reg8 = inb(APM_CNT);
339 switch (reg8) {
340 case APM_CNT_CST_CONTROL:
341 printk(BIOS_DEBUG, "C-state control\n");
342 break;
343 case APM_CNT_PST_CONTROL:
344 printk(BIOS_DEBUG, "P-state control\n");
345 break;
346 case APM_CNT_ACPI_DISABLE:
347 disable_pm1_control(SCI_EN);
348 printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
349 break;
350 case APM_CNT_ACPI_ENABLE:
351 enable_pm1_control(SCI_EN);
352 printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
353 break;
354 case APM_CNT_FINALIZE:
355 finalize();
356 break;
357 case APM_CNT_GNVS_UPDATE:
358 if (smm_initialized) {
359 printk(BIOS_DEBUG,
360 "SMI#: SMM structures already initialized!\n");
361 return;
362 }
363 state = smi_apmc_find_state_save(reg8);
364 if (state) {
365 /* EBX in the state save contains the GNVS pointer */
366 gnvs = (global_nvs_t *)((u32)state->rbx);
367 smm_initialized = 1;
368 printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs);
369 }
370 break;
371#if CONFIG_ELOG_GSMI
372 case ELOG_GSMI_APM_CNT:
373 southbridge_smi_gsmi();
374 break;
375#endif
376 }
377
378 mainboard_smi_apmc(reg8);
379}
380
381static void southbridge_smi_pm1(void)
382{
383 u16 pm1_sts = clear_pm1_status();
384
385 /* While OSPM is not active, poweroff immediately
386 * on a power button event.
387 */
388 if (pm1_sts & PWRBTN_STS) {
389 /* power button pressed */
390#if CONFIG_ELOG_GSMI
391 elog_add_event(ELOG_TYPE_POWER_BUTTON);
392#endif
393 disable_pm1_control(-1UL);
394 enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10));
395 }
396}
397
398static void southbridge_smi_gpe0(void)
399{
400 clear_gpe_status();
401}
402
403static void southbridge_smi_gpi(void)
404{
405 mainboard_smi_gpi(clear_alt_smi_status());
406
407 /* Clear again after mainboard handler */
408 clear_alt_smi_status();
409}
410
411static void southbridge_smi_mc(void)
412{
413 u32 reg32 = inl(ACPI_BASE_ADDRESS + SMI_EN);
414
415 /* Are microcontroller SMIs enabled? */
416 if ((reg32 & MCSMI_EN) == 0)
417 return;
418
419 printk(BIOS_DEBUG, "Microcontroller SMI.\n");
420}
421
422static void southbridge_smi_tco(void)
423{
424 u32 tco_sts = clear_tco_status();
425
426 /* Any TCO event? */
427 if (!tco_sts)
428 return;
429
430 if (tco_sts & (1 << 8)) { // BIOSWR
431 u8 bios_cntl = pci_read_config16(PCH_DEV_LPC, BIOS_CNTL);
432
433 if (bios_cntl & 1) {
434 /*
435 * BWE is RW, so the SMI was caused by a
436 * write to BWE, not by a write to the BIOS
437 *
438 * This is the place where we notice someone
439 * is trying to tinker with the BIOS. We are
440 * trying to be nice and just ignore it. A more
441 * resolute answer would be to power down the
442 * box.
443 */
444 printk(BIOS_DEBUG, "Switching back to RO\n");
445 pci_write_config32(PCH_DEV_LPC, BIOS_CNTL,
446 (bios_cntl & ~1));
447 } /* No else for now? */
448 } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
449 /* Handle TCO timeout */
450 printk(BIOS_DEBUG, "TCO Timeout.\n");
451 }
452}
453
454static void southbridge_smi_periodic(void)
455{
456 u32 reg32 = inl(ACPI_BASE_ADDRESS + SMI_EN);
457
458 /* Are periodic SMIs enabled? */
459 if ((reg32 & PERIODIC_EN) == 0)
460 return;
461
462 printk(BIOS_DEBUG, "Periodic SMI.\n");
463}
464
465static void southbridge_smi_monitor(void)
466{
467#define IOTRAP(x) (trap_sts & (1 << x))
468 u32 trap_sts, trap_cycle;
469 u32 data, mask = 0;
470 int i;
471
472 trap_sts = RCBA32(0x1e00); // TRSR - Trap Status Register
473 RCBA32(0x1e00) = trap_sts; // Clear trap(s) in TRSR
474
475 trap_cycle = RCBA32(0x1e10);
Lee Leahy26b7cd02017-03-16 18:47:55 -0700476 for (i = 16; i < 20; i++) {
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700477 if (trap_cycle & (1 << i))
478 mask |= (0xff << ((i - 16) << 2));
479 }
480
481
482 /* IOTRAP(3) SMI function call */
483 if (IOTRAP(3)) {
484 if (gnvs && gnvs->smif)
485 io_trap_handler(gnvs->smif); // call function smif
486 return;
487 }
488
489 /* IOTRAP(2) currently unused
490 * IOTRAP(1) currently unused */
491
492 /* IOTRAP(0) SMIC */
493 if (IOTRAP(0)) {
494 if (!(trap_cycle & (1 << 24))) { // It's a write
495 printk(BIOS_DEBUG, "SMI1 command\n");
496 data = RCBA32(0x1e18);
497 data &= mask;
498 // if (smi1)
Lee Leahy26b7cd02017-03-16 18:47:55 -0700499 // southbridge_smi_command(data);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700500 // return;
501 }
502 // Fall through to debug
503 }
504
505 printk(BIOS_DEBUG, " trapped io address = 0x%x\n",
506 trap_cycle & 0xfffc);
Lee Leahy26b7cd02017-03-16 18:47:55 -0700507 for (i = 0; i < 4; i++)
Elyes HAOUAS4a83f1c2016-08-25 21:07:59 +0200508 if (IOTRAP(i)) printk(BIOS_DEBUG, " TRAP = %d\n", i);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700509 printk(BIOS_DEBUG, " AHBE = %x\n", (trap_cycle >> 16) & 0xf);
510 printk(BIOS_DEBUG, " MASK = 0x%08x\n", mask);
511 printk(BIOS_DEBUG, " read/write: %s\n",
512 (trap_cycle & (1 << 24)) ? "read" : "write");
513
514 if (!(trap_cycle & (1 << 24))) {
515 /* Write Cycle */
516 data = RCBA32(0x1e18);
517 printk(BIOS_DEBUG, " iotrap written data = 0x%08x\n", data);
518 }
519#undef IOTRAP
520}
521
522typedef void (*smi_handler_t)(void);
523
524static smi_handler_t southbridge_smi[32] = {
525 NULL, // [0] reserved
526 NULL, // [1] reserved
527 NULL, // [2] BIOS_STS
528 NULL, // [3] LEGACY_USB_STS
529 southbridge_smi_sleep, // [4] SLP_SMI_STS
530 southbridge_smi_apmc, // [5] APM_STS
531 NULL, // [6] SWSMI_TMR_STS
532 NULL, // [7] reserved
533 southbridge_smi_pm1, // [8] PM1_STS
534 southbridge_smi_gpe0, // [9] GPE0_STS
535 southbridge_smi_gpi, // [10] GPI_STS
536 southbridge_smi_mc, // [11] MCSMI_STS
537 NULL, // [12] DEVMON_STS
538 southbridge_smi_tco, // [13] TCO_STS
539 southbridge_smi_periodic, // [14] PERIODIC_STS
540 NULL, // [15] SERIRQ_SMI_STS
541 NULL, // [16] SMBUS_SMI_STS
542 NULL, // [17] LEGACY_USB2_STS
543 NULL, // [18] INTEL_USB2_STS
544 NULL, // [19] reserved
545 NULL, // [20] PCI_EXP_SMI_STS
546 southbridge_smi_monitor, // [21] MONITOR_STS
547 NULL, // [22] reserved
548 NULL, // [23] reserved
549 NULL, // [24] reserved
550 NULL, // [25] EL_SMI_STS
551 NULL, // [26] SPI_STS
552 NULL, // [27] reserved
553 NULL, // [28] reserved
554 NULL, // [29] reserved
555 NULL, // [30] reserved
556 NULL // [31] reserved
557};
558
559/**
560 * @brief Interrupt handler for SMI#
561 *
562 * @param smm_revision revision of the smm state save map
563 */
564
565void southbridge_smi_handler(void)
566{
567 int i;
568 u32 smi_sts;
569
570 /* We need to clear the SMI status registers, or we won't see what's
571 * happening in the following calls.
572 */
573 smi_sts = clear_smi_status();
574
575 /* Call SMI sub handler for each of the status bits */
576 for (i = 0; i < 31; i++) {
577 if (smi_sts & (1 << i)) {
578 if (southbridge_smi[i]) {
579 southbridge_smi[i]();
580 } else {
581 printk(BIOS_DEBUG,
Martin Rothde7ed6f2014-12-07 14:58:18 -0700582 "SMI_STS[%d] occurred, but no "
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700583 "handler available.\n", i);
584 }
585 }
586 }
587}