blob: c159a759bf5ba43bfc4584fbc798199cd3bc7609 [file] [log] [blame]
Duncan Lauriec88c54c2014-04-30 16:36:13 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2014 Google Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of 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.
Duncan Lauriec88c54c2014-04-30 16:36:13 -070015 */
16
17#include <device/device.h>
18#include <device/pci.h>
19#include <console/console.h>
20#include <arch/io.h>
21#include <cpu/cpu.h>
22#include <cpu/x86/cache.h>
23#include <cpu/x86/smm.h>
24#include <string.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070025#include <soc/iomap.h>
26#include <soc/pch.h>
27#include <soc/pm.h>
28#include <soc/smm.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070029
30void southbridge_smm_clear_state(void)
31{
32 u32 smi_en;
33
34 printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
35 printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", ACPI_BASE_ADDRESS);
36
37 smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN);
38 if (smi_en & APMC_EN) {
39 printk(BIOS_INFO, "SMI# handler already enabled?\n");
40 return;
41 }
42
43 printk(BIOS_DEBUG, "\n");
44
45 /* Dump and clear status registers */
46 clear_smi_status();
47 clear_pm1_status();
48 clear_tco_status();
49 clear_gpe_status();
50}
51
52void southbridge_smm_enable_smi(void)
53{
54 printk(BIOS_DEBUG, "Enabling SMIs.\n");
55 /* Configure events */
56 enable_pm1(PWRBTN_EN | GBL_EN);
57 disable_gpe(PME_B0_EN);
58
59 /* Enable SMI generation:
60 * - on APMC writes (io 0xb2)
61 * - on writes to SLP_EN (sleep states)
62 * - on writes to GBL_RLS (bios commands)
63 * No SMIs:
64 * - on microcontroller writes (io 0x62/0x66)
65 * - on TCO events
66 */
67 enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
68}
69
70void southbridge_trigger_smi(void)
71{
72 /**
73 * There are several methods of raising a controlled SMI# via
74 * software, among them:
75 * - Writes to io 0xb2 (APMC)
76 * - Writes to the Local Apic ICR with Delivery mode SMI.
77 *
78 * Using the local apic is a bit more tricky. According to
79 * AMD Family 11 Processor BKDG no destination shorthand must be
80 * used.
81 * The whole SMM initialization is quite a bit hardware specific, so
82 * I'm not too worried about the better of the methods at the moment
83 */
84
85 /* raise an SMI interrupt */
86 printk(BIOS_SPEW, " ... raise SMI#\n");
87 outb(0x00, 0xb2);
88}
89
90void southbridge_clear_smi_status(void)
91{
92 /* Clear SMI status */
93 clear_smi_status();
94
95 /* Clear PM1 status */
96 clear_pm1_status();
97
98 /* Set EOS bit so other SMIs can occur. */
99 enable_smi(EOS);
100}
101
102void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
103{
104 /*
105 * Issue SMI to set the gnvs pointer in SMM.
106 * tcg and smi1 are unused.
107 *
108 * EAX = APM_CNT_GNVS_UPDATE
109 * EBX = gnvs pointer
110 * EDX = APM_CNT
111 */
112 asm volatile (
113 "outb %%al, %%dx\n\t"
114 : /* ignore result */
115 : "a" (APM_CNT_GNVS_UPDATE),
116 "b" ((u32)gnvs),
117 "d" (APM_CNT)
118 );
119}