blob: 18a55f6358c54df28895b46eb25a04cff7ffd1a6 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
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 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
Duncan Laurie0d0b3c52014-02-10 11:34:27 -080022#include <bootstate.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050023#include <device/device.h>
24#include <device/pci.h>
25#include <console/console.h>
26#include <arch/io.h>
27#include <cpu/cpu.h>
28#include <cpu/x86/cache.h>
29#include <cpu/x86/smm.h>
30#include <string.h>
31#include "pch.h"
32
Aaron Durbinaf3158c2013-03-27 20:57:28 -050033void southbridge_smm_clear_state(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050034{
35 u32 smi_en;
Aaron Durbin76c37002012-10-30 09:03:43 -050036
Aaron Durbin29ffa542012-12-21 21:21:48 -060037#if CONFIG_ELOG
38 /* Log events from chipset before clearing */
39 pch_log_state();
40#endif
41 printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
Duncan Laurie467f31d2013-03-08 17:00:37 -080042 printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", get_pmbase());
Aaron Durbin76c37002012-10-30 09:03:43 -050043
Duncan Laurie467f31d2013-03-08 17:00:37 -080044 smi_en = inl(get_pmbase() + SMI_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -050045 if (smi_en & APMC_EN) {
46 printk(BIOS_INFO, "SMI# handler already enabled?\n");
47 return;
48 }
49
Aaron Durbin76c37002012-10-30 09:03:43 -050050 printk(BIOS_DEBUG, "\n");
Aaron Durbin76c37002012-10-30 09:03:43 -050051
Duncan Laurie467f31d2013-03-08 17:00:37 -080052 /* Dump and clear status registers */
53 clear_smi_status();
54 clear_pm1_status();
55 clear_tco_status();
56 clear_gpe_status();
Aaron Durbinaf3158c2013-03-27 20:57:28 -050057}
Aaron Durbin76c37002012-10-30 09:03:43 -050058
Aaron Durbinaf3158c2013-03-27 20:57:28 -050059void southbridge_smm_enable_smi(void)
60{
61 printk(BIOS_DEBUG, "Enabling SMIs.\n");
Duncan Laurie467f31d2013-03-08 17:00:37 -080062 /* Configure events */
63 enable_pm1(PWRBTN_EN | GBL_EN);
64 disable_gpe(PME_B0_EN);
Aaron Durbin76c37002012-10-30 09:03:43 -050065
66 /* Enable SMI generation:
Aaron Durbin76c37002012-10-30 09:03:43 -050067 * - on APMC writes (io 0xb2)
68 * - on writes to SLP_EN (sleep states)
69 * - on writes to GBL_RLS (bios commands)
70 * No SMIs:
71 * - on microcontroller writes (io 0x62/0x66)
Duncan Lauried5acaaf2013-12-17 15:35:51 -080072 * - on TCO events
Aaron Durbin76c37002012-10-30 09:03:43 -050073 */
Duncan Lauried5acaaf2013-12-17 15:35:51 -080074 enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
Aaron Durbin29ffa542012-12-21 21:21:48 -060075}
Aaron Durbin76c37002012-10-30 09:03:43 -050076
Aaron Durbin29ffa542012-12-21 21:21:48 -060077void southbridge_trigger_smi(void)
78{
Aaron Durbin76c37002012-10-30 09:03:43 -050079 /**
80 * There are several methods of raising a controlled SMI# via
81 * software, among them:
82 * - Writes to io 0xb2 (APMC)
83 * - Writes to the Local Apic ICR with Delivery mode SMI.
84 *
85 * Using the local apic is a bit more tricky. According to
86 * AMD Family 11 Processor BKDG no destination shorthand must be
87 * used.
88 * The whole SMM initialization is quite a bit hardware specific, so
89 * I'm not too worried about the better of the methods at the moment
90 */
91
92 /* raise an SMI interrupt */
93 printk(BIOS_SPEW, " ... raise SMI#\n");
94 outb(0x00, 0xb2);
95}
96
Aaron Durbin29ffa542012-12-21 21:21:48 -060097void southbridge_clear_smi_status(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050098{
Aaron Durbin29ffa542012-12-21 21:21:48 -060099 /* Clear SMI status */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800100 clear_smi_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500101
Aaron Durbin29ffa542012-12-21 21:21:48 -0600102 /* Clear PM1 status */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800103 clear_pm1_status();
Aaron Durbin76c37002012-10-30 09:03:43 -0500104
Aaron Durbin29ffa542012-12-21 21:21:48 -0600105 /* Set EOS bit so other SMIs can occur. */
Duncan Laurie467f31d2013-03-08 17:00:37 -0800106 enable_smi(EOS);
Aaron Durbin76c37002012-10-30 09:03:43 -0500107}
108
Aaron Durbin76c37002012-10-30 09:03:43 -0500109void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
110{
111 /*
112 * Issue SMI to set the gnvs pointer in SMM.
113 * tcg and smi1 are unused.
114 *
115 * EAX = APM_CNT_GNVS_UPDATE
116 * EBX = gnvs pointer
117 * EDX = APM_CNT
118 */
119 asm volatile (
120 "outb %%al, %%dx\n\t"
121 : /* ignore result */
122 : "a" (APM_CNT_GNVS_UPDATE),
123 "b" ((u32)gnvs),
124 "d" (APM_CNT)
125 );
126}
Duncan Laurie0d0b3c52014-02-10 11:34:27 -0800127
128/*
129 * Finalize system before payload boot if not in ChromeOS environment.
130 */
131#if !CONFIG_CHROMEOS
132
133static void finalize_boot(void *unused)
134{
135 outb(0xcb, 0xb2);
136}
137
Aaron Durbin9ef9d852015-03-16 17:30:09 -0500138BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, finalize_boot, NULL);
Duncan Laurie0d0b3c52014-02-10 11:34:27 -0800139
140#endif