blob: a2d88aa8a4d0b9801d55dbedba2b35ea29ecde3f [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>
38#if IS_ENABLED(CONFIG_CHROMEOS)
39#include <vendorcode/google/chromeos/chromeos.h>
40#endif
41
42static const struct reg_script pch_pmc_misc_init_script[] = {
Aaron Durbinc5b91d62015-08-04 14:02:54 -050043 /* SLP_S4=4s, SLP_S3=50ms, disable SLP_X stretching after SUS loss. */
44 REG_PCI_RMW16(GEN_PMCON_B,
45 ~(S4MAW_MASK | SLP_S3_MIN_ASST_WDTH_MASK),
46 S4MAW_4S | SLP_S3_MIN_ASST_WDTH_50MS |
47 DIS_SLP_X_STRCH_SUS_UP),
48 /* Enable SCI and clear SLP requests. */
Lee Leahy1d14b3e2015-05-12 18:23:27 -070049 REG_IO_RMW32(ACPI_BASE_ADDRESS + PM1_CNT, ~SLP_TYP, SCI_EN),
Lee Leahy1d14b3e2015-05-12 18:23:27 -070050 REG_SCRIPT_END
51};
52
Aaron Durbin6fd5bd22015-08-04 21:04:02 -050053static const struct reg_script pmc_write1_to_clear_script[] = {
54 REG_PCI_OR32(GEN_PMCON_A, 0),
55 REG_PCI_OR32(GEN_PMCON_B, 0),
56 REG_PCI_OR32(GEN_PMCON_B, 0),
57 REG_RES_OR32(PWRMBASE, GBLRST_CAUSE0, 0),
58 REG_RES_OR32(PWRMBASE, GBLRST_CAUSE1, 0),
59 REG_SCRIPT_END
60};
61
Lee Leahy1d14b3e2015-05-12 18:23:27 -070062static void pch_pmc_add_mmio_resources(device_t dev)
63{
64 struct resource *res;
Lee Leahy1d14b3e2015-05-12 18:23:27 -070065
Aaron Durbin6fd5bd22015-08-04 21:04:02 -050066 /* Memory-mmapped I/O registers. */
67 res = new_resource(dev, PWRMBASE);
68 res->base = PCH_PWRM_BASE_ADDRESS;
69 res->size = PCH_PWRM_BASE_SIZE;
70 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
71 IORESOURCE_FIXED | IORESOURCE_RESERVE;
Lee Leahy1d14b3e2015-05-12 18:23:27 -070072}
73
74static void pch_pmc_add_io_resource(device_t dev, u16 base, u16 size, int index)
75{
76 struct resource *res;
77 res = new_resource(dev, index);
78 res->base = base;
79 res->size = size;
80 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
81}
82
83static void pch_pmc_add_io_resources(device_t dev)
84{
85 /* PMBASE */
86 pch_pmc_add_io_resource(dev, ACPI_BASE_ADDRESS, ACPI_BASE_SIZE, ABASE);
87}
88
89static void pch_pmc_read_resources(device_t dev)
90{
91 /* Get the normal PCI resources of this device. */
92 pci_dev_read_resources(dev);
93
94 /* Add non-standard MMIO resources. */
95 pch_pmc_add_mmio_resources(dev);
96
97 /* Add IO resources. */
98 pch_pmc_add_io_resources(dev);
99}
100
101static void pch_set_acpi_mode(void)
102{
103 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) && acpi_slp_type != 3) {
104 printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n");
105 outb(APM_CNT_ACPI_DISABLE, APM_CNT);
106 printk(BIOS_DEBUG, "done.\n");
107 }
108}
109
110#if IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS)
111/*
112 * Preserve Vboot NV data when clearing CMOS as it will
113 * have been re-initialized already by Vboot firmware init.
114 */
115static void pch_cmos_init_preserve(int reset)
116{
117 uint8_t vbnv[CONFIG_VBNV_SIZE];
118 if (reset)
119 read_vbnv(vbnv);
120
121 cmos_init(reset);
122
123 if (reset)
124 save_vbnv(vbnv);
125}
126#endif
127
128static void pch_rtc_init(void)
129{
130 u8 reg8;
131 int rtc_failed;
132 /*PMC Controller Device 0x1F, Func 02*/
133 device_t dev = PCH_DEV_PMC;
134 reg8 = pci_read_config8(dev, GEN_PMCON_B);
135 rtc_failed = reg8 & RTC_BATTERY_DEAD;
136 if (rtc_failed) {
137 reg8 &= ~RTC_BATTERY_DEAD;
138 pci_write_config8(dev, GEN_PMCON_B, reg8);
139 printk(BIOS_DEBUG, "rtc_failed = 0x%x\n", rtc_failed);
140 }
141
Aaron Durbin685ab2a22015-11-06 15:24:20 -0600142 /* Ensure the date is set including century byte. */
143 cmos_check_update_date();
144
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700145#if IS_ENABLED(CONFIG_CHROMEOS_VBNV_CMOS)
146 pch_cmos_init_preserve(rtc_failed);
147#else
148 cmos_init(rtc_failed);
149#endif
150}
151
Aaron Durbin9a8dc372015-08-07 22:29:42 -0500152static void pmc_gpe_init(config_t *config)
153{
154 uint8_t *pmc_regs;
155 uint32_t gpio_cfg;
156 uint32_t gpio_cfg_reg;
157 const uint32_t gpio_cfg_mask =
158 (GPE0_DWX_MASK << GPE0_DW0_SHIFT) |
159 (GPE0_DWX_MASK << GPE0_DW1_SHIFT) |
160 (GPE0_DWX_MASK << GPE0_DW2_SHIFT);
161
162 pmc_regs = pmc_mmio_regs();
163 gpio_cfg = 0;
164
165 /* Route the GPIOs to the GPE0 block. Determine that all values
166 * are different, and if they aren't use the reset values. */
167 if (config->gpe0_dw0 == config->gpe0_dw1 ||
168 config->gpe0_dw1 == config->gpe0_dw2) {
169 printk(BIOS_INFO, "PMC: Using default GPE route.\n");
170 gpio_cfg = read32(pmc_regs + GPIO_CFG);
171 } else {
172 gpio_cfg |= (uint32_t)config->gpe0_dw0 << GPE0_DW0_SHIFT;
173 gpio_cfg |= (uint32_t)config->gpe0_dw1 << GPE0_DW1_SHIFT;
174 gpio_cfg |= (uint32_t)config->gpe0_dw2 << GPE0_DW2_SHIFT;
175 }
176 gpio_cfg_reg = read32(pmc_regs + GPIO_CFG) & ~gpio_cfg_mask;
177 gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask;
178 write32(pmc_regs + GPIO_CFG, gpio_cfg_reg);
179
180 /* Set the routes in the GPIO communities as well. */
181 gpio_route_gpe(gpio_cfg_reg >> GPE0_DW0_SHIFT);
182
183 /* Set GPE enables based on devictree. */
184 enable_all_gpe(config->gpe0_en_1, config->gpe0_en_2,
185 config->gpe0_en_3, config->gpe0_en_4);
186}
187
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700188static void pch_power_options(void)
189{
190 u16 reg16;
191 const char *state;
192 /*PMC Controller Device 0x1F, Func 02*/
193 device_t dev = PCH_DEV_PMC;
194 /* Get the chip configuration */
195 config_t *config = dev->chip_info;
196 int pwr_on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
197
198 /*
199 * Which state do we want to goto after g3 (power restored)?
200 * 0 == S0 Full On
201 * 1 == S5 Soft Off
202 *
203 * If the option is not existent (Laptops), use Kconfig setting.
204 */
205 /*TODO: cmos_layout.bin need to verify; cause wrong CMOS setup*/
206 //get_option(&pwr_on, "power_on_after_fail");
207 pwr_on = MAINBOARD_POWER_ON;
208 reg16 = pci_read_config16(dev, GEN_PMCON_B);
209 reg16 &= 0xfffe;
210 switch (pwr_on) {
211 case MAINBOARD_POWER_OFF:
212 reg16 |= 1;
213 state = "off";
214 break;
215 case MAINBOARD_POWER_ON:
216 reg16 &= ~1;
217 state = "on";
218 break;
219 case MAINBOARD_POWER_KEEP:
220 reg16 &= ~1;
221 state = "state keep";
222 break;
223 default:
224 state = "undefined";
225 }
226 pci_write_config16(dev, GEN_PMCON_B, reg16);
227 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
Aaron Durbin9a8dc372015-08-07 22:29:42 -0500228
229 /* Set up GPE configuration. */
230 pmc_gpe_init(config);
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700231}
232
233static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable)
234{
235 uint32_t reg;
236 uint8_t *pmcbase = pmc_mmio_regs();
237
238 printk(BIOS_DEBUG, "%sabling Deep S%c\n",
239 enable ? "En" : "Dis", sx + '0');
240 reg = read32(pmcbase + offset);
241 if (enable)
242 reg |= mask;
243 else
244 reg &= ~mask;
245 write32(pmcbase + offset, reg);
246}
247
248static void config_deep_s5(int on)
249{
250 /* Treat S4 the same as S5. */
251 config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS | S4AC_GATE_SUS, 4, on);
252 config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS | S5AC_GATE_SUS, 5, on);
253}
254
255static void config_deep_s3(int on)
256{
257 config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS | S3AC_GATE_SUS, 3, on);
258}
259
Duncan Laurieedf1cb72015-07-24 15:37:13 -0700260static void config_deep_sx(uint32_t deepsx_config)
261{
262 uint32_t reg;
263 uint8_t *pmcbase = pmc_mmio_regs();
264
265 reg = read32(pmcbase + DSX_CFG);
266 reg &= ~DSX_CFG_MASK;
267 reg |= deepsx_config;
268 write32(pmcbase + DSX_CFG, reg);
269}
270
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700271static void pmc_init(struct device *dev)
272{
273 config_t *config = dev->chip_info;
274
275 pch_rtc_init();
276
277 /* Initialize power management */
278 pch_power_options();
279
Aaron Durbinc5b91d62015-08-04 14:02:54 -0500280 /* Note that certain bits may be cleared from running script as
281 * certain bit fields are write 1 to clear. */
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700282 reg_script_run_on_dev(dev, pch_pmc_misc_init_script);
283 pch_set_acpi_mode();
284
285 config_deep_s3(config->deep_s3_enable);
286 config_deep_s5(config->deep_s5_enable);
Duncan Laurieedf1cb72015-07-24 15:37:13 -0700287 config_deep_sx(config->deep_sx_config);
Aaron Durbin6fd5bd22015-08-04 21:04:02 -0500288
289 /* Clear registers that contain write-1-to-clear bits. */
290 reg_script_run_on_dev(dev, pmc_write1_to_clear_script);
Lee Leahy1d14b3e2015-05-12 18:23:27 -0700291}
292
293static struct device_operations device_ops = {
294 .read_resources = &pch_pmc_read_resources,
295 .set_resources = &pci_dev_set_resources,
296 .enable_resources = &pci_dev_enable_resources,
297 .init = &pmc_init,
298 .scan_bus = &scan_lpc_bus,
299 .ops_pci = &soc_pci_ops,
300};
301
302static const unsigned short pci_device_ids[] = {
303 0x9d21,
304 0
305};
306
307static const struct pci_driver pch_lpc __pci_driver = {
308 .ops = &device_ops,
309 .vendor = PCI_VENDOR_ID_INTEL,
310 .devices = pci_device_ids,
311};