blob: 7aa617781099e6c022786a8f88a735ab4241cc66 [file] [log] [blame]
Duncan Lauriec88c54c2014-04-30 16:36:13 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <arch/early_variables.h>
21#include <arch/io.h>
22#include <cbmem.h>
23#include <console/console.h>
24#include <device/device.h>
25#include <device/pci.h>
26#include <device/pci_def.h>
27#include <reg_script.h>
28#include <stdint.h>
29#include <stdlib.h>
30#include <string.h>
31#include <broadwell/iomap.h>
32#include <broadwell/lpc.h>
33#include <broadwell/pci_devs.h>
34#include <broadwell/pm.h>
35#include <broadwell/romstage.h>
36
37static struct chipset_power_state power_state CAR_GLOBAL;
38
39static void migrate_power_state(void)
40{
41 struct chipset_power_state *ps_cbmem;
42 struct chipset_power_state *ps_car;
43
44 ps_car = car_get_var_ptr(&power_state);
45 ps_cbmem = cbmem_add(CBMEM_ID_POWER_STATE, sizeof(*ps_cbmem));
46
47 if (ps_cbmem == NULL) {
48 printk(BIOS_DEBUG, "Not adding power state to cbmem!\n");
49 return;
50 }
51 memcpy(ps_cbmem, ps_car, sizeof(*ps_cbmem));
52}
53CAR_MIGRATE(migrate_power_state);
54
55/* Return 0, 3, or 5 to indicate the previous sleep state. */
56static int prev_sleep_state(struct chipset_power_state *ps)
57{
58 /* Default to S0. */
59 int prev_sleep_state = SLEEP_STATE_S0;
60
61 if (ps->pm1_sts & WAK_STS) {
62 switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
63#if CONFIG_HAVE_ACPI_RESUME
64 case SLP_TYP_S3:
65 prev_sleep_state = SLEEP_STATE_S3;
66 break;
67#endif
68 case SLP_TYP_S5:
69 prev_sleep_state = SLEEP_STATE_S5;
70 break;
71 }
72 /* Clear SLP_TYP. */
73 outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT);
74 }
75
76 if (ps->gen_pmcon3 & (PWR_FLR | SUS_PWR_FLR))
77 prev_sleep_state = SLEEP_STATE_S5;
78
79 return prev_sleep_state;
80}
81
82static void dump_power_state(struct chipset_power_state *ps)
83{
84 printk(BIOS_DEBUG, "PM1_STS: %04x\n", ps->pm1_sts);
85 printk(BIOS_DEBUG, "PM1_EN: %04x\n", ps->pm1_en);
86 printk(BIOS_DEBUG, "PM1_CNT: %08x\n", ps->pm1_cnt);
Duncan Laurie047f03a2014-08-11 09:54:19 -070087 printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n",
88 ps->tco1_sts, ps->tco2_sts);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070089
90 printk(BIOS_DEBUG, "GPE0_STS: %08x %08x %08x %08x\n",
91 ps->gpe0_sts[0], ps->gpe0_sts[1],
92 ps->gpe0_sts[2], ps->gpe0_sts[3]);
93 printk(BIOS_DEBUG, "GPE0_EN: %08x %08x %08x %08x\n",
94 ps->gpe0_en[0], ps->gpe0_en[1],
95 ps->gpe0_en[2], ps->gpe0_en[3]);
96
97 printk(BIOS_DEBUG, "GEN_PMCON: %04x %04x %04x\n",
98 ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
99
100 printk(BIOS_DEBUG, "Previous Sleep State: S%d\n",
101 ps->prev_sleep_state);
102}
103
104/* Fill power state structure from ACPI PM registers */
105struct chipset_power_state *fill_power_state(void)
106{
107 struct chipset_power_state *ps = car_get_var_ptr(&power_state);
108
109 ps->pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
110 ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN);
111 ps->pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
Duncan Laurie047f03a2014-08-11 09:54:19 -0700112 ps->tco1_sts = inw(ACPI_BASE_ADDRESS + TCO1_STS);
113 ps->tco2_sts = inw(ACPI_BASE_ADDRESS + TCO2_STS);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700114 ps->gpe0_sts[0] = inl(ACPI_BASE_ADDRESS + GPE0_STS(0));
115 ps->gpe0_sts[1] = inl(ACPI_BASE_ADDRESS + GPE0_STS(1));
116 ps->gpe0_sts[2] = inl(ACPI_BASE_ADDRESS + GPE0_STS(2));
117 ps->gpe0_sts[3] = inl(ACPI_BASE_ADDRESS + GPE0_STS(3));
118 ps->gpe0_en[0] = inl(ACPI_BASE_ADDRESS + GPE0_EN(0));
119 ps->gpe0_en[1] = inl(ACPI_BASE_ADDRESS + GPE0_EN(1));
120 ps->gpe0_en[2] = inl(ACPI_BASE_ADDRESS + GPE0_EN(2));
121 ps->gpe0_en[3] = inl(ACPI_BASE_ADDRESS + GPE0_EN(3));
122
123 ps->gen_pmcon1 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_1);
124 ps->gen_pmcon2 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_2);
125 ps->gen_pmcon3 = pci_read_config16(PCH_DEV_LPC, GEN_PMCON_3);
126
127 ps->prev_sleep_state = prev_sleep_state(ps);
128
129 dump_power_state(ps);
130
131 return ps;
132}