blob: cd77747716b3a4d4eb7c67e1aaa83207991e8fac [file] [log] [blame]
Lijian Zhaoac87a982017-08-28 17:46:55 -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) 2017 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
Subrata Banik0baad612017-11-23 13:58:34 +053018#include <bootstate.h>
Lijian Zhaoac87a982017-08-28 17:46:55 -070019#include <chip.h>
20#include <console/console.h>
21#include <device/device.h>
Subrata Banik0baad612017-11-23 13:58:34 +053022#include <intelblocks/pmc.h>
Lijian Zhaoac87a982017-08-28 17:46:55 -070023#include <intelblocks/pmclib.h>
24#include <intelblocks/rtc.h>
Lijian Zhaoac87a982017-08-28 17:46:55 -070025#include <soc/pci_devs.h>
26#include <soc/pm.h>
Lijian Zhaoac87a982017-08-28 17:46:55 -070027
Subrata Banik33cd28e2017-12-19 12:33:59 +053028/*
29 * Set which power state system will be after reapplying
30 * the power (from G3 State)
31 */
32static void pmc_set_afterg3(struct device *dev, int s5pwr)
33{
34 uint8_t reg8;
35
36 reg8 = pci_read_config8(dev, GEN_PMCON_B);
37
38 switch (s5pwr) {
39 case MAINBOARD_POWER_STATE_OFF:
40 reg8 |= 1;
41 break;
42 case MAINBOARD_POWER_STATE_ON:
43 reg8 &= ~1;
44 break;
45 case MAINBOARD_POWER_STATE_PREVIOUS:
46 default:
47 break;
48 }
49
50 pci_write_config8(dev, GEN_PMCON_B, reg8);
51}
52
53/*
54 * Set PMC register to know which state system should be after
55 * power reapplied
56 */
57void pmc_soc_restore_power_failure(void)
58{
59 pmc_set_afterg3(PCH_DEV_PMC,
60 pmc_get_mainboard_power_failure_state_choice());
61}
62
Lijian Zhaoac87a982017-08-28 17:46:55 -070063static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable)
64{
65 uint32_t reg;
66 uint8_t *pmcbase = pmc_mmio_regs();
67
68 printk(BIOS_DEBUG, "%sabling Deep S%c\n",
69 enable ? "En" : "Dis", sx + '0');
70 reg = read32(pmcbase + offset);
71 if (enable)
72 reg |= mask;
73 else
74 reg &= ~mask;
75 write32(pmcbase + offset, reg);
76}
77
78static void config_deep_s5(int on_ac, int on_dc)
79{
80 /* Treat S4 the same as S5. */
81 config_deep_sX(S4_PWRGATE_POL, S4AC_GATE_SUS, 4, on_ac);
82 config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS, 4, on_dc);
83 config_deep_sX(S5_PWRGATE_POL, S5AC_GATE_SUS, 5, on_ac);
84 config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS, 5, on_dc);
85}
86
87static void config_deep_s3(int on_ac, int on_dc)
88{
89 config_deep_sX(S3_PWRGATE_POL, S3AC_GATE_SUS, 3, on_ac);
90 config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS, 3, on_dc);
91}
92
93static void config_deep_sx(uint32_t deepsx_config)
94{
95 uint32_t reg;
96 uint8_t *pmcbase = pmc_mmio_regs();
97
98 reg = read32(pmcbase + DSX_CFG);
99 reg &= ~DSX_CFG_MASK;
100 reg |= deepsx_config;
101 write32(pmcbase + DSX_CFG, reg);
102}
103
Subrata Banik33cd28e2017-12-19 12:33:59 +0530104static void pch_power_options(struct device *dev)
105{
106 const char *state;
107
108 /* Get the chip configuration */
109 int pwr_on = pmc_get_mainboard_power_failure_state_choice();
110
111 /*
112 * Which state do we want to goto after g3 (power restored)?
113 * 0 == S5 Soft Off
114 * 1 == S0 Full On
115 * 2 == Keep Previous State
116 */
117 switch (pwr_on) {
118 case MAINBOARD_POWER_STATE_OFF:
119 state = "off";
120 break;
121 case MAINBOARD_POWER_STATE_ON:
122 state = "on";
123 break;
124 case MAINBOARD_POWER_STATE_PREVIOUS:
125 state = "state keep";
126 break;
127 default:
128 state = "undefined";
129 }
130 pmc_set_afterg3(dev, pwr_on);
131 printk(BIOS_INFO, "Set power %s after power failure.\n", state);
132
133 /* Set up GPE configuration. */
134 pmc_gpe_init();
135}
136
Subrata Banik0baad612017-11-23 13:58:34 +0530137static void pmc_init(void *unused)
Lijian Zhaoac87a982017-08-28 17:46:55 -0700138{
Subrata Banik0baad612017-11-23 13:58:34 +0530139 device_t dev = PCH_DEV_PMC;
Lijian Zhaoac87a982017-08-28 17:46:55 -0700140 config_t *config = dev->chip_info;
141
142 rtc_init();
143
144 /* Initialize power management */
Subrata Banik33cd28e2017-12-19 12:33:59 +0530145 pch_power_options(dev);
Lijian Zhaoac87a982017-08-28 17:46:55 -0700146
Subrata Banik0baad612017-11-23 13:58:34 +0530147 pmc_set_acpi_mode();
Lijian Zhaoac87a982017-08-28 17:46:55 -0700148
149 config_deep_s3(config->deep_s3_enable_ac, config->deep_s3_enable_dc);
150 config_deep_s5(config->deep_s5_enable_ac, config->deep_s5_enable_dc);
151 config_deep_sx(config->deep_sx_config);
152}
153
Subrata Banik0baad612017-11-23 13:58:34 +0530154/*
155* Initialize PMC controller.
156*
157* PMC controller gets hidden from PCI bus during FSP-Silicon init call.
158* Hence PCI enumeration can't be used to initialize bus device and
159* allocate resources.
160*/
161BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, pmc_init, NULL);