blob: a942c24adae99299defb8172cb4d0ba8405f061b [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Martin Rothebace9f2018-05-26 18:56:17 -06002
3/*
4 * SMI handler for Hudson southbridges
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -05005 */
6
Michał Żygowskif3db2ae2019-11-24 13:26:10 +01007#include <amdblocks/acpimmio.h>
Kyösti Mälkkibdaec072019-03-02 23:18:29 +02008#include <arch/io.h>
Elyes HAOUASbf0970e2019-03-21 11:10:03 +01009#include <cpu/x86/smm.h>
10
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050011#include "hudson.h"
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050012#include "smi.h"
13
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050014#define SMI_0x88_ACPI_COMMAND (1 << 11)
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050015
16enum smi_source {
17 SMI_SOURCE_SCI = (1 << 0),
18 SMI_SOURCE_GPE = (1 << 1),
19 SMI_SOURCE_0x84 = (1 << 2),
20 SMI_SOURCE_0x88 = (1 << 3),
21 SMI_SOURCE_IRQ_TRAP = (1 << 4),
22 SMI_SOURCE_0x90 = (1 << 5)
23};
24
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050025static void hudson_apmc_smi_handler(void)
26{
27 u32 reg32;
28 const uint8_t cmd = inb(ACPI_SMI_CTL_PORT);
29
30 switch (cmd) {
31 case ACPI_SMI_CMD_ENABLE:
32 reg32 = inl(ACPI_PM1_CNT_BLK);
33 reg32 |= (1 << 0); /* SCI_EN */
34 outl(reg32, ACPI_PM1_CNT_BLK);
35 break;
36 case ACPI_SMI_CMD_DISABLE:
37 reg32 = inl(ACPI_PM1_CNT_BLK);
38 reg32 &= ~(1 << 0); /* clear SCI_EN */
39 outl(ACPI_PM1_CNT_BLK, reg32);
40 break;
41 }
42
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020043 mainboard_smi_apmc(cmd);
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050044}
45
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050046int southbridge_io_trap_handler(int smif)
47{
48 return 0;
49}
50
51static void process_smi_sci(void)
52{
53 const uint32_t status = smi_read32(0x10);
54
55 /* Clear events to prevent re-entering SMI if event isn't handled */
56 smi_write32(0x10, status);
57}
58
59static void process_gpe_smi(void)
60{
61 const uint32_t status = smi_read32(0x80);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050062 const uint32_t gevent_mask = (1 << 24) - 1;
63
64 /* Only Bits [23:0] indicate GEVENT SMIs. */
65 if (status & gevent_mask) {
Martin Roth3c3a50c2014-12-16 20:50:26 -070066 /* A GEVENT SMI occurred */
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020067 mainboard_smi_gpi(status & gevent_mask);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050068 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050069
70 /* Clear events to prevent re-entering SMI if event isn't handled */
71 smi_write32(0x80, status);
72}
73
74static void process_smi_0x84(void)
75{
76 const uint32_t status = smi_read32(0x84);
77
78 /* Clear events to prevent re-entering SMI if event isn't handled */
79 smi_write32(0x84, status);
80}
81
82static void process_smi_0x88(void)
83{
84 const uint32_t status = smi_read32(0x88);
85
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050086 if (status & SMI_0x88_ACPI_COMMAND) {
87 /* Command received via ACPI SMI command port */
88 hudson_apmc_smi_handler();
89 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050090 /* Clear events to prevent re-entering SMI if event isn't handled */
91 smi_write32(0x88, status);
92}
93
94static void process_smi_0x8c(void)
95{
96 const uint32_t status = smi_read32(0x8c);
97
98 /* Clear events to prevent re-entering SMI if event isn't handled */
99 smi_write32(0x8c, status);
100}
101
102static void process_smi_0x90(void)
103{
104 const uint32_t status = smi_read32(0x90);
105
106 /* Clear events to prevent re-entering SMI if event isn't handled */
107 smi_write32(0x90, status);
108}
109
Kyösti Mälkki1ef039b2019-08-10 15:32:03 +0300110void southbridge_smi_handler(void)
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -0500111{
112 const uint16_t smi_src = smi_read16(0x94);
113
114 if (smi_src & SMI_SOURCE_SCI)
115 process_smi_sci();
116 if (smi_src & SMI_SOURCE_GPE)
117 process_gpe_smi();
118 if (smi_src & SMI_SOURCE_0x84)
119 process_smi_0x84();
120 if (smi_src & SMI_SOURCE_0x88)
121 process_smi_0x88();
122 if (smi_src & SMI_SOURCE_IRQ_TRAP)
123 process_smi_0x8c();
124 if (smi_src & SMI_SOURCE_0x90)
125 process_smi_0x90();
126}
127
128void southbridge_smi_set_eos(void)
129{
130 uint32_t reg = smi_read32(SMI_REG_SMITRIG0);
131 reg |= SMITRG0_EOS;
132 smi_write32(SMI_REG_SMITRIG0, reg);
133}