1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /* SMI utilities used in both SMM and normal mode */
5 #include <console/console.h>
6 #include <cpu/x86/smm.h>
7 #include <soc/southbridge.h>
9 #include <amdblocks/acpimmio.h>
10 #include <amdblocks/smi.h>
12 void configure_smi(uint8_t smi_num
, uint8_t mode
)
14 uint8_t reg32_offset
, bit_offset
;
17 if (smi_num
>= NUMBER_SMITYPES
) {
18 printk(BIOS_WARNING
, "BUG: Invalid SMI: %u\n", smi_num
);
22 /* 16 sources per register, 2 bits per source; registers are 4 bytes */
23 reg32_offset
= (smi_num
/ 16) * 4;
24 bit_offset
= (smi_num
% 16) * 2;
26 reg32
= smi_read32(SMI_REG_CONTROL0
+ reg32_offset
);
27 reg32
&= ~(0x3 << (bit_offset
));
28 reg32
|= (mode
& 0x3) << bit_offset
;
29 smi_write32(SMI_REG_CONTROL0
+ reg32_offset
, reg32
);
33 * Configure generation of interrupts for given GEVENT pin
35 * @param gevent The GEVENT pin number. Valid values are 0 thru 23
36 * @param mode The type of event this pin should generate. Note that only
37 * SMI_MODE_SMI generates an SMI. SMI_MODE_DISABLE disables events.
38 * @param level SMI__SCI_LVL_LOW or SMI_SCI_LVL_HIGH
40 void configure_gevent_smi(uint8_t gevent
, uint8_t mode
, uint8_t level
)
43 /* GEVENT pins range from [0:23] */
44 if (gevent
>= SMI_GEVENTS
) {
45 printk(BIOS_WARNING
, "BUG: Invalid GEVENT: %u\n", gevent
);
49 /* SMI0 source is GEVENT0 and so on */
50 configure_smi(gevent
, mode
);
52 /* And set the trigger level */
53 reg32
= smi_read32(SMI_REG_SMITRIG0
);
54 reg32
&= ~(1 << gevent
);
55 reg32
|= (level
& 0x1) << gevent
;
56 smi_write32(SMI_REG_SMITRIG0
, reg32
);
59 /** Set the EOS bit and enable SMI generation from southbridge */
60 void global_smi_enable(void)
62 uint32_t reg
= smi_read32(SMI_REG_SMITRIG0
);
63 reg
&= ~SMITRG0_SMIENB
; /* Enable SMI generation */
64 reg
|= SMITRG0_EOS
; /* Set EOS bit */
65 smi_write32(SMI_REG_SMITRIG0
, reg
);
68 void southbridge_smi_set_eos(void)
70 uint32_t reg
= smi_read32(SMI_REG_SMITRIG0
);
72 smi_write32(SMI_REG_SMITRIG0
, reg
);
76 * Configure generation of SCIs.
78 void configure_scimap(const struct sci_source
*sci
)
82 /* GEVENT pins range */
83 if (sci
->scimap
>= SCIMAPS
) {
84 printk(BIOS_WARNING
, "BUG: Invalid SCIMAP: %u\n",
89 /* GPEs range from [0:31] */
90 if (sci
->gpe
>= SCI_GPES
) {
91 printk(BIOS_WARNING
, "BUG: Invalid SCI GPE: %u\n", sci
->gpe
);
95 printk(BIOS_DEBUG
, "SCIMAP %u maps to GPE %u (active %s, %s trigger)\n",
96 sci
->scimap
, sci
->gpe
,
97 (!!sci
->direction
) ? "high" : "low",
98 (!!sci
->level
) ? "level" : "edge");
100 /* Map Gevent to SCI GPE# */
101 smi_write8(SMI_SCI_MAP(sci
->scimap
), sci
->gpe
);
103 /* Set the trigger direction (high/low) */
104 reg32
= smi_read32(SMI_SCI_TRIG
);
105 reg32
&= ~(1 << sci
->gpe
);
106 reg32
|= !!sci
->direction
<< sci
->gpe
;
107 smi_write32(SMI_SCI_TRIG
, reg32
);
109 /* Set the trigger level (edge/level) */
110 reg32
= smi_read32(SMI_SCI_LEVEL
);
111 reg32
&= ~(1 << sci
->gpe
);
112 reg32
|= !!sci
->level
<< sci
->gpe
;
113 smi_write32(SMI_SCI_LEVEL
, reg32
);
116 void gpe_configure_sci(const struct sci_source
*scis
, size_t num_gpes
)
120 for (i
= 0; i
< num_gpes
; i
++)
121 configure_scimap(scis
+ i
);
124 /** Disable events from given GEVENT pin */
125 void disable_gevent_smi(uint8_t gevent
)
127 /* GEVENT pins range from [0:23] */
129 printk(BIOS_WARNING
, "BUG: Invalid GEVENT: %u\n", gevent
);
133 /* SMI0 source is GEVENT0 and so on */
134 configure_smi(gevent
, SMI_MODE_DISABLE
);
137 uint16_t pm_acpi_smi_cmd_port(void)
139 return pm_read16(PM_ACPI_SMI_CMD
);
142 void clear_all_smi_status(void)
144 smi_write32(SMI_SCI_STATUS
, smi_read32(SMI_SCI_STATUS
));
145 smi_write32(SMI_EVENT_STATUS
, smi_read32(SMI_EVENT_STATUS
));
146 smi_write32(SMI_REG_SMISTS0
, smi_read32(SMI_REG_SMISTS0
));
147 smi_write32(SMI_REG_SMISTS1
, smi_read32(SMI_REG_SMISTS1
));
148 smi_write32(SMI_REG_SMISTS2
, smi_read32(SMI_REG_SMISTS2
));
149 smi_write32(SMI_REG_SMISTS3
, smi_read32(SMI_REG_SMISTS3
));
150 smi_write32(SMI_REG_SMISTS4
, smi_read32(SMI_REG_SMISTS4
));
153 void clear_smi_sci_status(void)
155 smi_write32(SMI_SCI_STATUS
, smi_read32(SMI_SCI_STATUS
));
158 static void clear_psp_smi(void)
161 /* SMITYPE_PSP is 33, so it's bit 33 % 32 in the second 32 bit SMI status register */
162 reg32
= smi_read32(SMI_REG_SMISTS1
);
163 reg32
|= 1 << (SMITYPE_PSP
% 32);
164 smi_write32(SMI_REG_SMISTS1
, reg32
);
167 void reset_psp_smi(void)
170 reg32
= smi_read32(SMI_REG_SMITRIG0
);
171 reg32
&= ~SMITRIG0_PSP
;
172 smi_write32(SMI_REG_SMITRIG0
, reg32
);
175 void configure_psp_smi(void)
179 configure_smi(SMITYPE_PSP
, SMI_MODE_SMI
);