blob: 003c462b05f036f777774bf4deba6e7b8c83a28c [file] [log] [blame]
Lee Leahy1d14b3e2015-05-12 18:23:27 -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 * Copyright (C) 2015 Intel Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of 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.
16 */
17
18#include <chip.h>
19#include <console/console.h>
20#include <device/device.h>
21#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <arch/io.h>
24#include <arch/ioapic.h>
25#include <arch/acpi.h>
26#include <cpu/cpu.h>
27#include <pc80/mc146818rtc.h>
28#include <reg_script.h>
29#include <string.h>
Aaron Durbin9a8dc372015-08-07 22:29:42 -050030#include <soc/gpio.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070031#include <soc/iomap.h>
32#include <soc/pci_devs.h>
33#include <soc/pmc.h>
34#include <soc/pm.h>
35#include <cpu/x86/smm.h>
36#include <soc/pcr.h>
37#include <soc/ramstage.h>
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070038#include <vboot/vbnv.h>
39#include <vboot/vbnv_layout.h>
Lee Leahy1d14b3e2015-05-12 18:23:27 -070040
41static const struct reg_script pch_pmc_misc_init_script[] = {
Aaron Durbinc5b91d62015-08-04 14:02:54 -050042 /* SLP_S4=4s, SLP_S3=50ms, disable SLP_X stretching after SUS loss. */
43 REG_PCI_RMW16(GEN_PMCON_B,
44 ~(S4MAW_MASK | SLP_S3_MIN_ASST_WDTH_MASK),
45 S4MAW_4S | SLP_S3_MIN_ASST_WDTH_50MS |
46 DIS_SLP_X_STRCH_SUS_UP),
47 /* Enable SCI and clear SLP requests. */
Lee Leahy1d14b3e2015-05-12 18:23:27 -070048 REG_IO_RMW32(ACPI_BASE_ADDRESS + PM1_CNT, ~SLP_TYP, SCI_EN),
Lee Leahy1d14b3e2015-05-12 18:23:27 -070049 REG_SCRIPT_END
50};
51
Aaron Durbin6fd5bd22015-08-04 21:04:02 -050052static const struct reg_script pmc_write1_to_clear_script[] = {
53 REG_PCI_OR32(GEN_PMCON_A, 0),
54 REG_PCI_OR32(GEN_PMCON_B, 0),
55 REG_PCI_OR32(GEN_PMCON_B, 0),
56 REG_RES_OR32(PWRMBASE, GBLRST_CAUSE0, 0),
57 REG_RES_OR32(PWRMBASE, GBLRST_CAUSE1, 0),
58 REG_SCRIPT_END
59};
60
Lee Leahy1d14b3e2015-05-12 18:23:27 -070061static void pch_pmc_add_mmio_resources(device_t dev)
62{
63 struct resource *res;
Lee Leahy1d14b3e2015-05-12 18:23:27 -070064
Aaron Durbin6fd5bd22015-08-04 21:04:02 -050065 /* Memory-mmapped I/O registers. */
66 res = new_resource(dev, PWRMBASE);
67 res->base = PCH_PWRM_BASE_ADDRESS;
68 res->size = PCH_PWRM_BASE_SIZE;
69 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
70 IORESOURCE_FIXED | IORESOURCE_RESERVE;
Lee Leahy1d14b3e2015-05-12 18:23:27 -070071}
72
73static void pch_pmc_add_io_resource(device_t dev, u16 base, u16 size, int index)
74{
75 struct resource *res;
76 res = new_resource(dev, index);
77 res->base = base;
78 res->size = size;
79 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
80}
81
82static void pch_pmc_add_io_resources(device_t dev)
83{
84 /* PMBASE */
85 pch_pmc_add_io_resource(dev, ACPI_BASE_ADDRESS, ACPI_BASE_SIZE, ABASE);
86}
87
88static void pch_pmc_read_resources(device_t dev)
89{
90 /* Get the normal PCI resources of this device. */
91 pci_dev_read_resources(dev);
92
93 /* Add non-standard MMIO resources. */
94 pch_pmc_add_mmio_resources(dev);
95
96 /* Add IO resources. */
97 pch_pmc_add_io_resources(dev);
98}
99
100static void pch_set_acpi_mode(void)
101{
Aaron Durbine0a49142016-07-13 23:20:51 -0500102 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) && !acpi_is_wakeup_s3()) {
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700103 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
104 outb(APM_CNT_ACPI_DISABLE, APM_CNT);
105 printk(BIOS_DEBUG, "done.\n");
106 }
107}
108
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700109static void pch_rtc_init(void)
110{
111 u8 reg8;
112 int rtc_failed;
113 /*PMC Controller Device 0x1F, Func 02*/
114 device_t dev = PCH_DEV_PMC;
115 reg8 = pci_read_config8(dev, GEN_PMCON_B);
116 rtc_failed = reg8 & RTC_BATTERY_DEAD;
117 if (rtc_failed) {
118 reg8 &= ~RTC_BATTERY_DEAD;
119 pci_write_config8(dev, GEN_PMCON_B, reg8);
120 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
121 }
122
Aaron Durbin685ab2a22015-11-06 15:24:20 -0600123 /* Ensure the date is set including century byte. */
124 cmos_check_update_date();
125
Furquan Shaikh33398612016-07-27 14:32:42 -0700126 if (IS_ENABLED(CONFIG_VBOOT_VBNV_CMOS))
127 init_vbnv_cmos(rtc_failed);
128 else
129 cmos_init(rtc_failed);
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700130}
131
132static void pch_power_options(void)
133{
134 u16 reg16;
135 const char *state;
136 /*PMC Controller Device 0x1F, Func 02*/
137 device_t dev = PCH_DEV_PMC;
138 /* Get the chip configuration */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700139 int pwr_on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
140
141 /*
142 * Which state do we want to goto after g3 (power restored)?
143 * 0 == S0 Full On
144 * 1 == S5 Soft Off
145 *
146 * If the option is not existent (Laptops), use Kconfig setting.
147 */
148 /*TODO: cmos_layout.bin need to verify; cause wrong CMOS setup*/
149 //get_option(&pwr_on, "power_on_after_fail");
150 pwr_on = MAINBOARD_POWER_ON;
151 reg16 = pci_read_config16(dev, GEN_PMCON_B);
152 reg16 &= 0xfffe;
153 switch (pwr_on) {
154 case MAINBOARD_POWER_OFF:
155 reg16 |= 1;
156 state = "off";
157 break;
158 case MAINBOARD_POWER_ON:
159 reg16 &= ~1;
160 state = "on";
161 break;
162 case MAINBOARD_POWER_KEEP:
163 reg16 &= ~1;
164 state = "state keep";
165 break;
166 default:
167 state = "undefined";
168 }
169 pci_write_config16(dev, GEN_PMCON_B, reg16);
170 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
Aaron Durbin9a8dc372015-08-07 22:29:42 -0500171
172 /* Set up GPE configuration. */
Duncan Laurief0ba2252016-10-25 20:03:56 -0700173 pmc_gpe_init();
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700174}
175
176static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable)
177{
178 uint32_t reg;
179 uint8_t *pmcbase = pmc_mmio_regs();
180
181 printk(BIOS_DEBUG, "%sabling Deep S%c\n",
182 enable ? "En" : "Dis", sx + '0');
183 reg = read32(pmcbase + offset);
184 if (enable)
185 reg |= mask;
186 else
187 reg &= ~mask;
188 write32(pmcbase + offset, reg);
189}
190
191static void config_deep_s5(int on)
192{
193 /* Treat S4 the same as S5. */
194 config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS | S4AC_GATE_SUS, 4, on);
195 config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS | S5AC_GATE_SUS, 5, on);
196}
197
198static void config_deep_s3(int on)
199{
200 config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS | S3AC_GATE_SUS, 3, on);
201}
202
Duncan Laurieedf1cb72015-07-24 15:37:13 -0700203static void config_deep_sx(uint32_t deepsx_config)
204{
205 uint32_t reg;
206 uint8_t *pmcbase = pmc_mmio_regs();
207
208 reg = read32(pmcbase + DSX_CFG);
209 reg &= ~DSX_CFG_MASK;
210 reg |= deepsx_config;
211 write32(pmcbase + DSX_CFG, reg);
212}
213
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700214static void pmc_init(struct device *dev)
215{
216 config_t *config = dev->chip_info;
217
218 pch_rtc_init();
219
220 /* Initialize power management */
221 pch_power_options();
222
Aaron Durbinc5b91d62015-08-04 14:02:54 -0500223 /* Note that certain bits may be cleared from running script as
224 * certain bit fields are write 1 to clear. */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700225 reg_script_run_on_dev(dev, pch_pmc_misc_init_script);
226 pch_set_acpi_mode();
227
228 config_deep_s3(config->deep_s3_enable);
229 config_deep_s5(config->deep_s5_enable);
Duncan Laurieedf1cb72015-07-24 15:37:13 -0700230 config_deep_sx(config->deep_sx_config);
Aaron Durbin6fd5bd22015-08-04 21:04:02 -0500231
232 /* Clear registers that contain write-1-to-clear bits. */
233 reg_script_run_on_dev(dev, pmc_write1_to_clear_script);
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700234}
235
236static struct device_operations device_ops = {
237 .read_resources = &pch_pmc_read_resources,
238 .set_resources = &pci_dev_set_resources,
239 .enable_resources = &pci_dev_enable_resources,
240 .init = &pmc_init,
241 .scan_bus = &scan_lpc_bus,
242 .ops_pci = &soc_pci_ops,
243};
244
245static const unsigned short pci_device_ids[] = {
246 0x9d21,
Sooi, Li Chengc76e9982017-01-04 13:36:06 +0800247 0xa121,
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700248 0
249};
250
251static const struct pci_driver pch_lpc __pci_driver = {
252 .ops = &device_ops,
253 .vendor = PCI_VENDOR_ID_INTEL,
254 .devices = pci_device_ids,
255};