blob: 45a368c4626de173198cc06c8739ce7a39d51671 [file] [log] [blame]
Tan, Lean Sheng05dfe312020-08-25 20:40:17 -07001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <bootstate.h>
4#include <console/console.h>
5#include <device/device.h>
6#include <device/mmio.h>
7#include <intelblocks/pmc.h>
8#include <intelblocks/pmclib.h>
9#include <intelblocks/rtc.h>
10#include <soc/pci_devs.h>
11#include <soc/pm.h>
12#include <soc/soc_chip.h>
13
Tan, Lean Sheng05dfe312020-08-25 20:40:17 -070014static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable)
15{
16 uint32_t reg;
17 uint8_t *pmcbase = pmc_mmio_regs();
18
19 printk(BIOS_DEBUG, "%sabling Deep S%c\n",
20 enable ? "En" : "Dis", sx + '0');
21 reg = read32(pmcbase + offset);
22 if (enable)
23 reg |= mask;
24 else
25 reg &= ~mask;
26 write32(pmcbase + offset, reg);
27}
28
29static void config_deep_s5(int on_ac, int on_dc)
30{
31 /* Treat S4 the same as S5. */
32 config_deep_sX(S4_PWRGATE_POL, S4AC_GATE_SUS, 4, on_ac);
33 config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS, 4, on_dc);
34 config_deep_sX(S5_PWRGATE_POL, S5AC_GATE_SUS, 5, on_ac);
35 config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS, 5, on_dc);
36}
37
38static void config_deep_s3(int on_ac, int on_dc)
39{
40 config_deep_sX(S3_PWRGATE_POL, S3AC_GATE_SUS, 3, on_ac);
41 config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS, 3, on_dc);
42}
43
44static void config_deep_sx(uint32_t deepsx_config)
45{
46 uint32_t reg;
47 uint8_t *pmcbase = pmc_mmio_regs();
48
49 reg = read32(pmcbase + DSX_CFG);
50 reg &= ~DSX_CFG_MASK;
51 reg |= deepsx_config;
52 write32(pmcbase + DSX_CFG, reg);
53}
54
55static void pmc_init(struct device *dev)
56{
57 const config_t *config = config_of_soc();
58
59 rtc_init();
60
61 pmc_set_power_failure_state(true);
62 pmc_gpe_init();
63
64 config_deep_s3(config->deep_s3_enable_ac, config->deep_s3_enable_dc);
65 config_deep_s5(config->deep_s5_enable_ac, config->deep_s5_enable_dc);
66 config_deep_sx(config->deep_sx_config);
67}
68
69static void soc_pmc_read_resources(struct device *dev)
70{
71 struct resource *res;
72
73 mmio_resource(dev, 0, PCH_PWRM_BASE_ADDRESS / KiB, PCH_PWRM_BASE_SIZE / KiB);
74
75 res = new_resource(dev, 1);
76 res->base = (resource_t)ACPI_BASE_ADDRESS;
77 res->size = (resource_t)ACPI_BASE_SIZE;
78 res->limit = res->base + res->size + 1;
79 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
80}
81
82static void soc_acpi_mode_init(struct device *dev)
83{
84 /*
85 * pmc_set_acpi_mode() should be delayed until BS_DEV_INIT in order
86 * to ensure the ordering does not break the assumptions that other
87 * drivers make about ACPI mode (e.g. Chrome EC). Since it disables
88 * ACPI mode, other drivers may take different actions based on this
89 * (e.g. Chrome EC will flush any pending hostevent bits). Because
90 * EHL has its PMC device available for device_operations, it can be
91 * done from the "ops->init" callback.
92 */
93 pmc_set_acpi_mode();
94}
95
96struct device_operations pmc_ops = {
97 .read_resources = soc_pmc_read_resources,
98 .set_resources = noop_set_resources,
99 .init = soc_acpi_mode_init,
100 .enable = pmc_init,
101};