blob: 17541f684ab45b18f71c5ca148d92b0955d0391f [file] [log] [blame]
Aaron Durbin7837be62013-10-21 22:32:00 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
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.
Aaron Durbin7837be62013-10-21 22:32:00 -050015 */
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/smm.h>
23#include <string.h>
24
Julius Werner18ea2d32014-10-07 16:42:17 -070025#include <soc/iomap.h>
26#include <soc/pmc.h>
27#include <soc/smm.h>
Aaron Durbin7837be62013-10-21 22:32:00 -050028
Kein Yuan35110232014-02-22 12:26:55 -080029/* Save settings which will be committed in SMI functions. */
30static uint32_t smm_save_params[SMM_SAVE_PARAM_COUNT];
Aaron Durbin59a4cd52013-11-11 12:09:28 -060031
Kein Yuan35110232014-02-22 12:26:55 -080032void southcluster_smm_save_param(int param, uint32_t data)
Aaron Durbin59a4cd52013-11-11 12:09:28 -060033{
Kein Yuan35110232014-02-22 12:26:55 -080034 smm_save_params[param] = data;
Aaron Durbin59a4cd52013-11-11 12:09:28 -060035}
36
Aaron Durbin7837be62013-10-21 22:32:00 -050037void southcluster_smm_clear_state(void)
38{
39 uint32_t smi_en;
40
41 /* Log events from chipset before clearing */
42 southcluster_log_state();
43
44 printk(BIOS_DEBUG, "Initializing Southbridge SMI...");
45 printk(BIOS_SPEW, " pmbase = 0x%04x\n", get_pmbase());
46
47 smi_en = inl(get_pmbase() + SMI_EN);
48 if (smi_en & APMC_EN) {
49 printk(BIOS_INFO, "SMI# handler already enabled?\n");
50 return;
51 }
52
53 /* Dump and clear status registers */
54 clear_smi_status();
55 clear_pm1_status();
56 clear_tco_status();
57 clear_gpe_status();
Aaron Durbin9f83e872013-11-11 14:45:27 -060058 clear_alt_status();
Aaron Durbin19edc3a2014-01-09 11:17:37 -060059 clear_pmc_status();
Aaron Durbin7837be62013-10-21 22:32:00 -050060}
61
Aaron Durbin59a4cd52013-11-11 12:09:28 -060062static void southcluster_smm_route_gpios(void)
63{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080064 u32 *gpio_rout = (u32 *)(PMC_BASE_ADDRESS + GPIO_ROUT);
Aaron Durbin59a4cd52013-11-11 12:09:28 -060065 const unsigned short alt_gpio_smi = ACPI_BASE_ADDRESS + ALT_GPIO_SMI;
66 uint32_t alt_gpio_reg = 0;
Kein Yuan35110232014-02-22 12:26:55 -080067 uint32_t route_reg = smm_save_params[SMM_SAVE_PARAM_GPIO_ROUTE];
Aaron Durbin59a4cd52013-11-11 12:09:28 -060068 int i;
69
70 printk(BIOS_DEBUG, "GPIO_ROUT = %08x\n", route_reg);
71
72 /* Start the routing for the specific gpios. */
73 write32(gpio_rout, route_reg);
74
75 /* Enable SMIs for the gpios that are set to trigger the SMI. */
76 for (i = 0; i < 16; i++) {
77 if ((route_reg & ROUTE_MASK) == ROUTE_SMI) {
78 alt_gpio_reg |= (1 << i);
79 }
80 route_reg >>= 2;
81 }
82 printk(BIOS_DEBUG, "ALT_GPIO_SMI = %08x\n", alt_gpio_reg);
83
84 outl(alt_gpio_reg, alt_gpio_smi);
85}
86
Aaron Durbin7837be62013-10-21 22:32:00 -050087void southcluster_smm_enable_smi(void)
88{
Kein Yuan35110232014-02-22 12:26:55 -080089 uint16_t pm1_events = PWRBTN_EN | GBL_EN;
Aaron Durbin59a4cd52013-11-11 12:09:28 -060090
Aaron Durbin7837be62013-10-21 22:32:00 -050091 printk(BIOS_DEBUG, "Enabling SMIs.\n");
Kein Yuan35110232014-02-22 12:26:55 -080092 if (!smm_save_params[SMM_SAVE_PARAM_PCIE_WAKE_ENABLE])
93 pm1_events |= PCIEXPWAK_DIS;
94 enable_pm1(pm1_events);
Aaron Durbin7837be62013-10-21 22:32:00 -050095 disable_gpe(PME_B0_EN);
96
Aaron Durbin59a4cd52013-11-11 12:09:28 -060097 /* Set up the GPIO route. */
98 southcluster_smm_route_gpios();
99
Aaron Durbin7837be62013-10-21 22:32:00 -0500100 /* Enable SMI generation:
Aaron Durbin7837be62013-10-21 22:32:00 -0500101 * - on APMC writes (io 0xb2)
102 * - on writes to SLP_EN (sleep states)
103 * - on writes to GBL_RLS (bios commands)
104 * No SMIs:
Aaron Durbin766482d2014-01-09 10:44:06 -0600105 * - on TCO events
Aaron Durbin7837be62013-10-21 22:32:00 -0500106 * - on microcontroller writes (io 0x62/0x66)
107 */
Aaron Durbin766482d2014-01-09 10:44:06 -0600108 enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
Aaron Durbin7837be62013-10-21 22:32:00 -0500109}
110
111void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
112{
113 /*
114 * Issue SMI to set the gnvs pointer in SMM.
115 * tcg and smi1 are unused.
116 *
117 * EAX = APM_CNT_GNVS_UPDATE
118 * EBX = gnvs pointer
119 * EDX = APM_CNT
120 */
121 asm volatile (
122 "outb %%al, %%dx\n\t"
123 : /* ignore result */
124 : "a" (APM_CNT_GNVS_UPDATE),
125 "b" ((uint32_t)gnvs),
126 "d" (APM_CNT)
127 );
128}