blob: 39b2b95a2c99a4c2aaca67047f3a715a7ea8e712 [file] [log] [blame]
Felix Held4a8cd722020-04-18 22:26:39 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Martin Rothc5158982018-05-26 18:42:05 -06002
3/*
4 * SMM utilities used in both SMM and normal mode
Marc Jones24484842017-05-04 21:17:45 -06005 */
6
7#include <console/console.h>
Arthur Heymans34280272020-09-29 11:51:34 +02008#include <cpu/x86/smm.h>
Marshall Dawsoneecb7942017-09-28 17:32:30 -06009#include <soc/southbridge.h>
Marc Jones24484842017-05-04 21:17:45 -060010#include <soc/smi.h>
Marshall Dawson69486ca2019-05-02 12:03:45 -060011#include <amdblocks/acpimmio.h>
Felix Helda5a52952020-12-01 18:14:01 +010012#include <amdblocks/smi.h>
Marc Jones24484842017-05-04 21:17:45 -060013
Marshall Dawsona05fdcb2017-09-27 15:01:37 -060014void configure_smi(uint8_t smi_num, uint8_t mode)
Marc Jones24484842017-05-04 21:17:45 -060015{
16 uint8_t reg32_offset, bit_offset;
17 uint32_t reg32;
18
Marshall Dawson9db0a2d2017-09-22 15:35:32 -060019 if (smi_num >= NUMBER_SMITYPES) {
Marc Jones24484842017-05-04 21:17:45 -060020 printk(BIOS_WARNING, "BUG: Invalid SMI: %u\n", smi_num);
21 return;
22 }
23
24 /* 16 sources per register, 2 bits per source; registers are 4 bytes */
25 reg32_offset = (smi_num / 16) * 4;
26 bit_offset = (smi_num % 16) * 2;
27
28 reg32 = smi_read32(SMI_REG_CONTROL0 + reg32_offset);
29 reg32 &= ~(0x3 << (bit_offset));
30 reg32 |= (mode & 0x3) << bit_offset;
31 smi_write32(SMI_REG_CONTROL0 + reg32_offset, reg32);
32}
33
34/**
35 * Configure generation of interrupts for given GEVENT pin
36 *
37 * @param gevent The GEVENT pin number. Valid values are 0 thru 23
38 * @param mode The type of event this pin should generate. Note that only
39 * SMI_MODE_SMI generates an SMI. SMI_MODE_DISABLE disables events.
Marc Jonese8e72bd2017-10-04 22:12:31 -060040 * @param level SMI__SCI_LVL_LOW or SMI_SCI_LVL_HIGH
Marc Jones24484842017-05-04 21:17:45 -060041 */
Marc Jonesdfeb1c42017-08-07 19:08:24 -060042void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level)
Marc Jones24484842017-05-04 21:17:45 -060043{
44 uint32_t reg32;
45 /* GEVENT pins range from [0:23] */
Marc Jonese8e72bd2017-10-04 22:12:31 -060046 if (gevent >= SMI_GEVENTS) {
Marc Jones24484842017-05-04 21:17:45 -060047 printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent);
48 return;
49 }
50
51 /* SMI0 source is GEVENT0 and so on */
52 configure_smi(gevent, mode);
53
54 /* And set set the trigger level */
55 reg32 = smi_read32(SMI_REG_SMITRIG0);
56 reg32 &= ~(1 << gevent);
57 reg32 |= (level & 0x1) << gevent;
58 smi_write32(SMI_REG_SMITRIG0, reg32);
59}
60
Marc Jonese8e72bd2017-10-04 22:12:31 -060061/**
62 * Configure generation of SCIs.
63 */
64void configure_scimap(const struct sci_source *sci)
65{
66 uint32_t reg32;
67
68 /* GEVENT pins range */
69 if (sci->scimap >= SCIMAPS) {
70 printk(BIOS_WARNING, "BUG: Invalid SCIMAP: %u\n",
71 sci->scimap);
72 return;
73 }
74
75 /* GPEs range from [0:31] */
76 if (sci->gpe >= SCI_GPES) {
77 printk(BIOS_WARNING, "BUG: Invalid SCI GPE: %u\n", sci->gpe);
78 return;
79 }
80
81 printk(BIOS_DEBUG, "SCIMAP %u maps to GPE %u (active %s, %s trigger)\n",
82 sci->scimap, sci->gpe,
83 (!!sci->direction) ? "high" : "low",
84 (!!sci->level) ? "level" : "edge");
85
86 /* Map Gevent to SCI GPE# */
87 smi_write8(SMI_SCI_MAP(sci->scimap), sci->gpe);
88
89 /* Set the trigger direction (high/low) */
90 reg32 = smi_read32(SMI_SCI_TRIG);
91 reg32 &= ~(1 << sci->gpe);
92 reg32 |= !!sci->direction << sci->gpe;
93 smi_write32(SMI_SCI_TRIG, reg32);
94
95 /* Set the trigger level (edge/level) */
96 reg32 = smi_read32(SMI_SCI_LEVEL);
97 reg32 &= ~(1 << sci->gpe);
98 reg32 |= !!sci->level << sci->gpe;
99 smi_write32(SMI_SCI_LEVEL, reg32);
100}
101
102void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes)
103{
104 size_t i;
105
106 for (i = 0; i < num_gpes; i++)
107 configure_scimap(scis + i);
108}
109
Marc Jones24484842017-05-04 21:17:45 -0600110/** Disable events from given GEVENT pin */
Marc Jonesdfeb1c42017-08-07 19:08:24 -0600111void disable_gevent_smi(uint8_t gevent)
Marc Jones24484842017-05-04 21:17:45 -0600112{
113 /* GEVENT pins range from [0:23] */
114 if (gevent > 23) {
115 printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent);
116 return;
117 }
118
119 /* SMI0 source is GEVENT0 and so on */
120 configure_smi(gevent, SMI_MODE_DISABLE);
121}
122
Marshall Dawson66e62da2017-09-27 13:32:38 -0600123uint16_t pm_acpi_smi_cmd_port(void)
124{
125 return pm_read16(PM_ACPI_SMI_CMD);
126}