blob: a87b75da0000df9b1b3b2b950bc0ece6dd9e4360 [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>
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050022#include "hudson.h"
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050023#include "smi.h"
24
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050025#include <cpu/x86/smm.h>
26#include <delay.h>
27
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050028#define SMI_0x88_ACPI_COMMAND (1 << 11)
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050029
30enum smi_source {
31 SMI_SOURCE_SCI = (1 << 0),
32 SMI_SOURCE_GPE = (1 << 1),
33 SMI_SOURCE_0x84 = (1 << 2),
34 SMI_SOURCE_0x88 = (1 << 3),
35 SMI_SOURCE_IRQ_TRAP = (1 << 4),
36 SMI_SOURCE_0x90 = (1 << 5)
37};
38
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050039static void hudson_apmc_smi_handler(void)
40{
41 u32 reg32;
42 const uint8_t cmd = inb(ACPI_SMI_CTL_PORT);
43
44 switch (cmd) {
45 case ACPI_SMI_CMD_ENABLE:
46 reg32 = inl(ACPI_PM1_CNT_BLK);
47 reg32 |= (1 << 0); /* SCI_EN */
48 outl(reg32, ACPI_PM1_CNT_BLK);
49 break;
50 case ACPI_SMI_CMD_DISABLE:
51 reg32 = inl(ACPI_PM1_CNT_BLK);
52 reg32 &= ~(1 << 0); /* clear SCI_EN */
53 outl(ACPI_PM1_CNT_BLK, reg32);
54 break;
55 }
56
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020057 mainboard_smi_apmc(cmd);
Alexandru Gagniuc288c9582014-04-14 16:35:34 -050058}
59
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050060int southbridge_io_trap_handler(int smif)
61{
62 return 0;
63}
64
65static void process_smi_sci(void)
66{
67 const uint32_t status = smi_read32(0x10);
68
69 /* Clear events to prevent re-entering SMI if event isn't handled */
70 smi_write32(0x10, status);
71}
72
73static void process_gpe_smi(void)
74{
75 const uint32_t status = smi_read32(0x80);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050076 const uint32_t gevent_mask = (1 << 24) - 1;
77
78 /* Only Bits [23:0] indicate GEVENT SMIs. */
79 if (status & gevent_mask) {
Martin Roth3c3a50c2014-12-16 20:50:26 -070080 /* A GEVENT SMI occurred */
Kyösti Mälkki48b3dbc2014-12-29 19:36:50 +020081 mainboard_smi_gpi(status & gevent_mask);
Alexandru Gagniuc22d90e32014-04-14 14:38:19 -050082 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -050083
84 /* Clear events to prevent re-entering SMI if event isn't handled */
85 smi_write32(0x80, status);
86}
87
88static void process_smi_0x84(void)
89{
90 const uint32_t status = smi_read32(0x84);
91
92 /* Clear events to prevent re-entering SMI if event isn't handled */
93 smi_write32(0x84, status);
94}
95
96static void process_smi_0x88(void)
97{
98 const uint32_t status = smi_read32(0x88);
99
Alexandru Gagniuc288c9582014-04-14 16:35:34 -0500100 if (status & SMI_0x88_ACPI_COMMAND) {
101 /* Command received via ACPI SMI command port */
102 hudson_apmc_smi_handler();
103 }
Alexandru Gagniuc2dbd08f2014-04-10 14:35:59 -0500104 /* Clear events to prevent re-entering SMI if event isn't handled */
105 smi_write32(0x88, status);
106}
107
108static void process_smi_0x8c(void)
109{
110 const uint32_t status = smi_read32(0x8c);
111
112 /* Clear events to prevent re-entering SMI if event isn't handled */
113 smi_write32(0x8c, status);
114}
115
116static void process_smi_0x90(void)
117{
118 const uint32_t status = smi_read32(0x90);
119
120 /* Clear events to prevent re-entering SMI if event isn't handled */
121 smi_write32(0x90, status);
122}
123
124void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
125{
126 const uint16_t smi_src = smi_read16(0x94);
127
128 if (smi_src & SMI_SOURCE_SCI)
129 process_smi_sci();
130 if (smi_src & SMI_SOURCE_GPE)
131 process_gpe_smi();
132 if (smi_src & SMI_SOURCE_0x84)
133 process_smi_0x84();
134 if (smi_src & SMI_SOURCE_0x88)
135 process_smi_0x88();
136 if (smi_src & SMI_SOURCE_IRQ_TRAP)
137 process_smi_0x8c();
138 if (smi_src & SMI_SOURCE_0x90)
139 process_smi_0x90();
140}
141
142void southbridge_smi_set_eos(void)
143{
144 uint32_t reg = smi_read32(SMI_REG_SMITRIG0);
145 reg |= SMITRG0_EOS;
146 smi_write32(SMI_REG_SMITRIG0, reg);
147}