blob: 3a7ab1cb69527b4f1b6ac8255825e1c59bdbba81 [file] [log] [blame]
Lee Leahy77ff0b12015-05-05 15:07:29 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
Lee Leahy32471722015-04-20 15:20:28 -07005 * Copyright (C) 2015 Intel Corp.
Lee Leahy77ff0b12015-05-05 15:07:29 -07006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Lee Leahy77ff0b12015-05-05 15:07:29 -070016 */
17
Lee Leahy77ff0b12015-05-05 15:07:29 -070018#include <arch/io.h>
Lee Leahy32471722015-04-20 15:20:28 -070019#include <console/console.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070020#include <cpu/cpu.h>
21#include <cpu/x86/smm.h>
Lee Leahy32471722015-04-20 15:20:28 -070022#include <device/device.h>
23#include <device/pci.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070024#include <soc/iomap.h>
Lee Leahy32471722015-04-20 15:20:28 -070025#include <soc/pm.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070026#include <soc/smm.h>
Lee Leahy32471722015-04-20 15:20:28 -070027#include <string.h>
Lee Leahy77ff0b12015-05-05 15:07:29 -070028
29/* Save settings which will be committed in SMI functions. */
30static uint32_t smm_save_params[SMM_SAVE_PARAM_COUNT];
31
32void southcluster_smm_save_param(int param, uint32_t data)
33{
34 smm_save_params[param] = data;
35}
36
37void 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();
58 clear_alt_status();
59 clear_pmc_status();
60}
61
62static void southcluster_smm_route_gpios(void)
63{
Lee Leahy32471722015-04-20 15:20:28 -070064 void *gpio_rout = (void *)(PMC_BASE_ADDRESS + GPIO_ROUT);
Lee Leahy77ff0b12015-05-05 15:07:29 -070065 const unsigned short alt_gpio_smi = ACPI_BASE_ADDRESS + ALT_GPIO_SMI;
66 uint32_t alt_gpio_reg = 0;
67 uint32_t route_reg = smm_save_params[SMM_SAVE_PARAM_GPIO_ROUTE];
68 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++) {
Lee Leahy32471722015-04-20 15:20:28 -070077 if ((route_reg & ROUTE_MASK) == ROUTE_SMI)
Lee Leahy77ff0b12015-05-05 15:07:29 -070078 alt_gpio_reg |= (1 << i);
Lee Leahy77ff0b12015-05-05 15:07:29 -070079 route_reg >>= 2;
80 }
81 printk(BIOS_DEBUG, "ALT_GPIO_SMI = %08x\n", alt_gpio_reg);
82
83 outl(alt_gpio_reg, alt_gpio_smi);
84}
85
86void southcluster_smm_enable_smi(void)
87{
88 uint16_t pm1_events = PWRBTN_EN | GBL_EN;
89
90 printk(BIOS_DEBUG, "Enabling SMIs.\n");
91 if (!smm_save_params[SMM_SAVE_PARAM_PCIE_WAKE_ENABLE])
92 pm1_events |= PCIEXPWAK_DIS;
93 enable_pm1(pm1_events);
94 disable_gpe(PME_B0_EN);
95
96 /* Set up the GPIO route. */
97 southcluster_smm_route_gpios();
98
Lee Leahy32471722015-04-20 15:20:28 -070099 /*
100 * Enable SMI generation:
Lee Leahy77ff0b12015-05-05 15:07:29 -0700101 * - on APMC writes (io 0xb2)
102 * - on writes to SLP_EN (sleep states)
103 * - on writes to GBL_RLS (bios commands)
104 * No SMIs:
105 * - on TCO events
106 * - on microcontroller writes (io 0x62/0x66)
107 */
108 enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | EOS);
109}
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}