blob: 1b9442b1b6b3af2cc42af62f1b2029d32401f99e [file] [log] [blame]
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -05001/*
Martin Rothebace9f2018-05-26 18:56:17 -06002 * This file is part of the coreboot project.
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -05003 *
4 * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
Martin Rothebace9f2018-05-26 18:56:17 -06005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License, or (at your
9 * option) any later version.
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.
15 */
16
17/*
18 * SMI handler for Hudson southbridges
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050019 */
20
Kyösti Mälkkibdaec072019-03-02 23:18:29 +020021#include <arch/io.h>
Elyes HAOUASbf0970e2019-03-21 11:10:03 +010022#include <cpu/x86/smm.h>
23
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050024#include "hudson.h"
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050025#include "smi.h"
26
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050027#define SMI_0x88_ACPI_COMMAND (1 << 11)
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050028
29enum smi_source {
30 SMI_SOURCE_SCI = (1 << 0),
31 SMI_SOURCE_GPE = (1 << 1),
32 SMI_SOURCE_0x84 = (1 << 2),
33 SMI_SOURCE_0x88 = (1 << 3),
34 SMI_SOURCE_IRQ_TRAP = (1 << 4),
35 SMI_SOURCE_0x90 = (1 << 5)
36};
37
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050038static void hudson_apmc_smi_handler(void)
39{
40 u32 reg32;
41 const uint8_t cmd = inb(ACPI_SMI_CTL_PORT);
42
43 switch (cmd) {
44 case ACPI_SMI_CMD_ENABLE:
45 reg32 = inl(ACPI_PM1_CNT_BLK);
46 reg32 |= (1 << 0); /* SCI_EN */
47 outl(reg32, ACPI_PM1_CNT_BLK);
48 break;
49 case ACPI_SMI_CMD_DISABLE:
50 reg32 = inl(ACPI_PM1_CNT_BLK);
51 reg32 &= ~(1 << 0); /* clear SCI_EN */
52 outl(ACPI_PM1_CNT_BLK, reg32);
53 break;
54 }
55
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020056 mainboard_smi_apmc(cmd);
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050057}
58
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050059int southbridge_io_trap_handler(int smif)
60{
61 return 0;
62}
63
64static void process_smi_sci(void)
65{
66 const uint32_t status = smi_read32(0x10);
67
68 /* Clear events to prevent re-entering SMI if event isn't handled */
69 smi_write32(0x10, status);
70}
71
72static void process_gpe_smi(void)
73{
74 const uint32_t status = smi_read32(0x80);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050075 const uint32_t gevent_mask = (1 << 24) - 1;
76
77 /* Only Bits [23:0] indicate GEVENT SMIs. */
78 if (status & gevent_mask) {
Martin Roth3c3a50c2014-12-16 20:50:26 -070079 /* A GEVENT SMI occurred */
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020080 mainboard_smi_gpi(status & gevent_mask);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050081 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050082
83 /* Clear events to prevent re-entering SMI if event isn't handled */
84 smi_write32(0x80, status);
85}
86
87static void process_smi_0x84(void)
88{
89 const uint32_t status = smi_read32(0x84);
90
91 /* Clear events to prevent re-entering SMI if event isn't handled */
92 smi_write32(0x84, status);
93}
94
95static void process_smi_0x88(void)
96{
97 const uint32_t status = smi_read32(0x88);
98
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050099 if (status & SMI_0x88_ACPI_COMMAND) {
100 /* Command received via ACPI SMI command port */
101 hudson_apmc_smi_handler();
102 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -0500103 /* Clear events to prevent re-entering SMI if event isn't handled */
104 smi_write32(0x88, status);
105}
106
107static void process_smi_0x8c(void)
108{
109 const uint32_t status = smi_read32(0x8c);
110
111 /* Clear events to prevent re-entering SMI if event isn't handled */
112 smi_write32(0x8c, status);
113}
114
115static void process_smi_0x90(void)
116{
117 const uint32_t status = smi_read32(0x90);
118
119 /* Clear events to prevent re-entering SMI if event isn't handled */
120 smi_write32(0x90, status);
121}
122
123void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
124{
125 const uint16_t smi_src = smi_read16(0x94);
126
127 if (smi_src & SMI_SOURCE_SCI)
128 process_smi_sci();
129 if (smi_src & SMI_SOURCE_GPE)
130 process_gpe_smi();
131 if (smi_src & SMI_SOURCE_0x84)
132 process_smi_0x84();
133 if (smi_src & SMI_SOURCE_0x88)
134 process_smi_0x88();
135 if (smi_src & SMI_SOURCE_IRQ_TRAP)
136 process_smi_0x8c();
137 if (smi_src & SMI_SOURCE_0x90)
138 process_smi_0x90();
139}
140
141void southbridge_smi_set_eos(void)
142{
143 uint32_t reg = smi_read32(SMI_REG_SMITRIG0);
144 reg |= SMITRG0_EOS;
145 smi_write32(SMI_REG_SMITRIG0, reg);
146}