coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
smihandler.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <acpi/acpi.h>
4 #include <amdblocks/acpi.h>
5 #include <amdblocks/acpimmio.h>
6 #include <amdblocks/psp.h>
7 #include <amdblocks/smi.h>
8 #include <amdblocks/smm.h>
9 #include <arch/hlt.h>
10 #include <arch/io.h>
11 #include <console/console.h>
12 #include <cpu/x86/cache.h>
13 #include <cpu/x86/smm.h>
14 #include <elog.h>
15 #include <soc/smi.h>
16 #include <soc/smu.h>
17 #include <soc/southbridge.h>
18 #include <types.h>
19 
20 static void fch_apmc_smi_handler(void)
21 {
22  const uint8_t cmd = inb(pm_acpi_smi_cmd_port());
23 
24  switch (cmd) {
28  break;
31  break;
32  case APM_CNT_ELOG_GSMI:
33  if (CONFIG(ELOG_GSMI))
35  break;
36  case APM_CNT_SMMSTORE:
37  if (CONFIG(SMMSTORE))
39  break;
40  case APM_CNT_SMMINFO:
42  break;
43  }
44 
45  mainboard_smi_apmc(cmd);
46 }
47 
48 static void fch_slp_typ_handler(void)
49 {
50  uint32_t pci_ctrl, reg32;
51  uint16_t pm1cnt, reg16;
52  uint8_t slp_typ, rst_ctrl;
53 
54  /* Figure out SLP_TYP */
56  printk(BIOS_SPEW, "SMI#: SLP = 0x%04x\n", pm1cnt);
57  slp_typ = acpi_sleep_from_pm1(pm1cnt);
58 
59  /* Do any mainboard sleep handling */
60  mainboard_smi_sleep(slp_typ);
61 
62  switch (slp_typ) {
63  case ACPI_S0:
64  printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
65  break;
66  case ACPI_S3:
67  printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
68  break;
69  case ACPI_S4:
70  printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
71  break;
72  case ACPI_S5:
73  printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
74  break;
75  default:
76  printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
77  break;
78  }
79 
80  if (slp_typ >= ACPI_S3) {
81  /* Sleep Type Elog S3, S4, and S5 entry */
83 
84  wbinvd();
85 
87 
88  /* Do not send SMI before AcpiPm1CntBlkx00[SlpTyp] */
89  pci_ctrl = pm_read32(PM_PCI_CTRL);
90  pci_ctrl &= ~FORCE_SLPSTATE_RETRY;
91  pm_write32(PM_PCI_CTRL, pci_ctrl);
92 
93  /* Enable SlpTyp */
94  rst_ctrl = pm_read8(PM_RST_CTRL1);
95  rst_ctrl |= SLPTYPE_CONTROL_EN;
96  pm_write8(PM_RST_CTRL1, rst_ctrl);
97 
98  /*
99  * Before the final command, check if there's pending wake
100  * event. Read enable first, so that reading the actual status
101  * is as close as possible to entering S3. The idea is to
102  * minimize the opportunity for a wake event to happen before
103  * actually entering S3. If there's a pending wake event, log
104  * it and continue normal path. S3 will fail and the wake event
105  * becomes a SCI.
106  */
107  if (CONFIG(ELOG_GSMI)) {
108  reg16 = acpi_read16(MMIO_ACPI_PM1_EN);
109  reg16 &= acpi_read16(MMIO_ACPI_PM1_STS);
110  if (reg16)
113  (u32)reg16);
114 
117  if (reg32)
120  reg32);
121  } /* if (CONFIG(ELOG_GSMI)) */
122 
123  if (slp_typ == ACPI_S3)
125 
126  smu_sx_entry(); /* Leave SlpTypeEn clear, SMU will set */
127  printk(BIOS_ERR, "System did not go to sleep\n");
128 
129  hlt();
130  }
131 }
132 
134 {
135  return 0;
136 }
137 
138 /*
139  * Table of functions supported in the SMI handler. Note that SMI source setup
140  * in fch.c is unrelated to this list.
141  */
142 static const struct smi_sources_t smi_sources[] = {
144  { .type = SMITYPE_SLP_TYP, .handler = fch_slp_typ_handler},
145 };
146 
147 void *get_smi_source_handler(int source)
148 {
149  size_t i;
150 
151  for (i = 0 ; i < ARRAY_SIZE(smi_sources) ; i++)
152  if (smi_sources[i].type == source)
153  return smi_sources[i].handler;
154 
155  return NULL;
156 }
#define SLPTYPE_CONTROL_EN
Definition: acpimmio.h:32
static void pm_write32(uint8_t reg, uint32_t value)
Definition: acpimmio.h:191
static uint32_t acpi_read32(uint8_t reg)
Definition: acpimmio.h:216
static uint8_t pm_read8(uint8_t reg)
Definition: acpimmio.h:166
static uint32_t pm_read32(uint8_t reg)
Definition: acpimmio.h:176
static uint16_t acpi_read16(uint8_t reg)
Definition: acpimmio.h:211
static void pm_write8(uint8_t reg, uint8_t value)
Definition: acpimmio.h:181
#define PM_RST_CTRL1
Definition: acpimmio.h:31
static __always_inline void hlt(void)
Definition: hlt.h:6
#define ARRAY_SIZE(a)
Definition: helpers.h:12
void smu_sx_entry(void)
Definition: smu.c:11
#define FORCE_SLPSTATE_RETRY
Definition: southbridge.h:12
#define PM_PCI_CTRL
Definition: southbridge.h:11
#define ELOG_TYPE_ACPI_ENTER
Definition: elog.h:143
#define ELOG_SLEEP_PENDING_GPE0_WAKE
Definition: elog.h:298
#define ELOG_SLEEP_PENDING_PM1_WAKE
Definition: elog.h:297
#define printk(level,...)
Definition: stdlib.h:16
void __weak mainboard_smi_sleep(u8 slp_typ)
Definition: smihandler.c:210
int __weak mainboard_smi_apmc(u8 data)
Definition: smihandler.c:209
u8 inb(u16 port)
int elog_add_extended_event(u8 type, u32 complement)
Definition: elog.c:892
@ CONFIG
Definition: dsi_common.h:201
@ ACPI_S5
Definition: acpi.h:1385
@ ACPI_S4
Definition: acpi.h:1384
@ ACPI_S3
Definition: acpi.h:1383
@ ACPI_S0
Definition: acpi.h:1380
static void wbinvd(void)
Definition: cache.h:15
#define APM_CNT_ELOG_GSMI
Definition: smm.h:29
uint16_t pm_acpi_smi_cmd_port(void)
Definition: smi.c:6
#define APM_CNT_ACPI_DISABLE
Definition: smm.h:21
#define APM_CNT_ACPI_ENABLE
Definition: smm.h:22
#define APM_CNT_SMMSTORE
Definition: smm.h:28
#define APM_CNT_SMMINFO
Definition: smm.h:27
static int elog_gsmi_add_event_byte(u8 event_type, u8 data)
Definition: elog.h:46
unsigned int type
Definition: edid.c:57
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
int psp_notify_smm(void)
Definition: psp_smm.c:37
void psp_notify_sx_info(u8 sleep_type)
Definition: psp_smm.c:77
void handle_smi_store(void)
void handle_smi_gsmi(void)
#define SMITYPE_SLP_TYP
Definition: smi.h:107
#define SMITYPE_SMI_CMD_PORT
Definition: smi.h:113
void * get_smi_source_handler(int source)
Definition: smihandler.c:145
int southbridge_io_trap_handler(int smif)
Definition: smihandler.c:131
void acpi_enable_sci(void)
Definition: acpi.c:126
void acpi_clear_pm_gpe_status(void)
Definition: acpi.c:90
void acpi_disable_sci(void)
Definition: acpi.c:135
#define MMIO_ACPI_PM1_EN
Definition: acpi.h:13
#define MMIO_ACPI_GPE0_EN
Definition: acpi.h:21
#define MMIO_ACPI_GPE0_STS
Definition: acpi.h:20
#define MMIO_ACPI_PM1_STS
Definition: acpi.h:12
#define MMIO_ACPI_PM1_CNT_BLK
Definition: acpi.h:14
void clear_all_smi_status(void)
Definition: smi_util.c:142
static void fch_apmc_smi_handler(void)
Definition: smihandler.c:20
static const struct smi_sources_t smi_sources[]
Definition: smihandler.c:142
static void fch_slp_typ_handler(void)
Definition: smihandler.c:48
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
unsigned char uint8_t
Definition: stdint.h:8
void(* handler)(void)
Definition: smi.h:34
int type
Definition: smi.h:33