1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <console/console.h>
6 #include <device/mmio.h>
7 #include <device/device.h>
8 #include <device/pci_ops.h>
9 #include <intelblocks/pmc.h>
10 #include <intelblocks/pmclib.h>
11 #include <intelblocks/rtc.h>
12 #include <soc/pci_devs.h>
17 /* Fill up PMC resource structure */
18 int pmc_soc_get_resources(struct pmc_resource_config
*cfg
)
20 cfg
->pwrmbase_offset
= PWRMBASE
;
21 cfg
->pwrmbase_addr
= PCH_PWRM_BASE_ADDRESS
;
22 cfg
->pwrmbase_size
= PCH_PWRM_BASE_SIZE
;
23 cfg
->abase_offset
= ABASE
;
24 cfg
->abase_addr
= ACPI_BASE_ADDRESS
;
25 cfg
->abase_size
= ACPI_BASE_SIZE
;
30 static void config_deep_sX(uint32_t offset
, uint32_t mask
, int sx
, int enable
)
33 uint8_t *pmcbase
= pmc_mmio_regs();
35 printk(BIOS_DEBUG
, "%sabling Deep S%c\n",
36 enable
? "En" : "Dis", sx
+ '0');
37 reg
= read32(pmcbase
+ offset
);
42 write32(pmcbase
+ offset
, reg
);
45 static void config_deep_s5(int on_ac
, int on_dc
)
47 /* Treat S4 the same as S5. */
48 config_deep_sX(S4_PWRGATE_POL
, S4AC_GATE_SUS
, 4, on_ac
);
49 config_deep_sX(S4_PWRGATE_POL
, S4DC_GATE_SUS
, 4, on_dc
);
50 config_deep_sX(S5_PWRGATE_POL
, S5AC_GATE_SUS
, 5, on_ac
);
51 config_deep_sX(S5_PWRGATE_POL
, S5DC_GATE_SUS
, 5, on_dc
);
54 static void config_deep_s3(int on_ac
, int on_dc
)
56 config_deep_sX(S3_PWRGATE_POL
, S3AC_GATE_SUS
, 3, on_ac
);
57 config_deep_sX(S3_PWRGATE_POL
, S3DC_GATE_SUS
, 3, on_dc
);
60 static void config_deep_sx(uint32_t deepsx_config
)
63 uint8_t *pmcbase
= pmc_mmio_regs();
65 reg
= read32(pmcbase
+ DSX_CFG
);
68 write32(pmcbase
+ DSX_CFG
, reg
);
71 void pmc_soc_init(struct device
*dev
)
73 const config_t
*config
= config_of(dev
);
74 uint8_t *const pwrmbase
= pmc_mmio_regs();
79 pmc_set_power_failure_state(true);
82 /* SLP_S4=4s, SLP_S3=50ms, disable SLP_X stretching after SUS loss. */
83 pci_update_config32(dev
, GEN_PMCON_B
, ~(S4MAW_MASK
| SLP_S3_MIN_ASST_WDTH_MASK
),
84 S4MAW_4S
| SLP_S3_MIN_ASST_WDTH_50MS
| DIS_SLP_X_STRCH_SUS_UP
);
86 /* Enable SCI and clear SLP requests. */
87 reg32
= inl(ACPI_BASE_ADDRESS
+ PM1_CNT
);
90 outl(reg32
, ACPI_BASE_ADDRESS
+ PM1_CNT
);
94 config_deep_s3(config
->deep_s3_enable_ac
, config
->deep_s3_enable_dc
);
95 config_deep_s5(config
->deep_s5_enable_ac
, config
->deep_s5_enable_dc
);
96 config_deep_sx(config
->deep_sx_config
);
98 /* Clear registers that contain write-1-to-clear bits. */
99 pci_or_config32(dev
, GEN_PMCON_B
, 0);
100 pci_or_config32(dev
, GEN_PMCON_B
, 0);
101 setbits32(pwrmbase
+ GBLRST_CAUSE0
, 0);
102 setbits32(pwrmbase
+ GBLRST_CAUSE1
, 0);
105 * Disable ACPI PM timer based on Kconfig
107 * Disabling ACPI PM timer is necessary for XTAL OSC shutdown.
108 * Disabling ACPI PM timer also switches off TCO.
110 if (!CONFIG(USE_PM_ACPI_TIMER
))
111 setbits8(pmc_mmio_regs() + PCH_PWRM_ACPI_TMR_CTL
, ACPI_TIM_DIS
);
114 static void pm1_enable_pwrbtn_smi(void *unused
)
117 * Enable power button SMI only before jumping to payload. This ensures
119 * 1. Power button SMI is enabled only after coreboot is done.
120 * 2. On resume path, power button SMI is not enabled and thus avoids
121 * any shutdowns because of power button presses due to power button
122 * press in resume path.
124 pmc_update_pm1_enable(PWRBTN_EN
);
127 BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD
, BS_ON_EXIT
, pm1_enable_pwrbtn_smi
, NULL
);
130 * Check if WAKE# pin is enabled based on DSX_EN_WAKE_PIN setting in
131 * deep_sx_config. If WAKE# pin is not enabled, then PCI Express Wake Disable
132 * bit needs to be set in PM1_EN to avoid unnecessary wakes caused by WAKE#
135 static void pm1_handle_wake_pin(void *unused
)
137 const config_t
*conf
= config_of_soc();
139 /* If WAKE# pin is enabled, bail out early. */
140 if (conf
->deep_sx_config
& DSX_EN_WAKE_PIN
)
143 pmc_update_pm1_enable(PCIEXPWAK_DIS
);
146 BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD
, BS_ON_EXIT
, pm1_handle_wake_pin
, NULL
);
147 BOOT_STATE_INIT_ENTRY(BS_OS_RESUME
, BS_ON_ENTRY
, pm1_handle_wake_pin
, NULL
);