soc/intel/common/block/acpi: Add LPM requirements support to PEPD _DSM

This patch adds support for the S0ix UUID in the Intel Power Engine _DSM
method. This allows the ACPI tables to expose device/IP power states
requirements for different system low power states

BUG=b:185437326
TEST=Along with following patch on brya0 after resume from s0ix,
cat /sys/kernel/debug/pmc_core/substate_requirements
                       Element |    S0i2.0 |    S0i3.0 |    Status |
               USB2PLL_OFF_STS |  Required |  Required |       Yes |
   PCIe/USB3.1_Gen2PLL_OFF_STS |  Required |  Required |       Yes |
          PCIe_Gen3PLL_OFF_STS |  Required |  Required |       Yes |
               OPIOPLL_OFF_STS |  Required |  Required |       Yes |
                 OCPLL_OFF_STS |  Required |  Required |       Yes |
               MainPLL_OFF_STS |           |  Required |           |
               MIPIPLL_OFF_STS |  Required |  Required |       Yes |
         Fast_XTAL_Osc_OFF_STS |           |  Required |           |
           AC_Ring_Osc_OFF_STS |  Required |  Required |       Yes |
               SATAPLL_OFF_STS |  Required |  Required |       Yes |
          XTAL_USB2PLL_OFF_STS |           |  Required |       Yes |
                   CSME_PG_STS |  Required |  Required |       Yes |
                   SATA_PG_STS |  Required |  Required |       Yes |
                   xHCI_PG_STS |  Required |  Required |       Yes |
                  UFSX2_PG_STS |  Required |  Required |       Yes |
                    OTG_PG_STS |  Required |  Required |       Yes |
                    SPA_PG_STS |  Required |  Required |       Yes |
                    SPB_PG_STS |  Required |  Required |       Yes |
                    SPC_PG_STS |  Required |  Required |       Yes |
                   THC0_PG_STS |  Required |  Required |       Yes |
                   THC1_PG_STS |  Required |  Required |       Yes |
                 GBETSN_PG_STS |  Required |  Required |       Yes |
                    GBE_PG_STS |  Required |  Required |       Yes |
                   LPSS_PG_STS |  Required |  Required |       Yes |
                   ADSP_D3_STS |           |  Required |       Yes |
                  xHCI0_D3_STS |  Required |  Required |       Yes |
                  xDCI1_D3_STS |  Required |  Required |       Yes |
                     IS_D3_STS |  Required |  Required |       Yes |
                GBE_TSN_D3_STS |  Required |  Required |       Yes |
             CPU_C10_REQ_STS_0 |  Required |  Required |       Yes |
                CNVI_REQ_STS_6 |           |  Required |       Yes |
                 ISH_REQ_STS_7 |           |  Required |       Yes |
       MPHY_Core_DL_REQ_STS_16 |  Required |  Required |       Yes |
      Break-even_En_REQ_STS_17 |  Required |  Required |       Yes |
       Auto-demo_En_REQ_STS_18 |  Required |  Required |       Yes |
    Int_Timer_SS_Wake0_Pol_STS |  Required |  Required |           |
    Int_Timer_SS_Wake1_Pol_STS |  Required |  Required |           |
    Int_Timer_SS_Wake2_Pol_STS |  Required |  Required |           |
    Int_Timer_SS_Wake3_Pol_STS |  Required |  Required |           |
    Int_Timer_SS_Wake4_Pol_STS |  Required |  Required |           |
    Int_Timer_SS_Wake5_Pol_STS |  Required |  Required |           |

Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: I542290bd5490aa6580a5ae2b266da3d78bc17e6b
Reviewed-on: https://review.coreboot.org/c/coreboot/+/56005
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Tim Wawrzynczak
2021-07-01 08:20:17 -06:00
parent 593941b600
commit 2eb100dd12
4 changed files with 109 additions and 2 deletions

View File

@ -22,6 +22,15 @@ config SOC_INTEL_COMMON_BLOCK_ACPI_PEP
Generate an Intel Power Engine device object in the SSDT. This is Generate an Intel Power Engine device object in the SSDT. This is
usually used for providing ACPI hooks for S0ix exit/entry. usually used for providing ACPI hooks for S0ix exit/entry.
config SOC_INTEL_COMMON_BLOCK_ACPI_PEP_LPM_REQ
bool
depends on SOC_INTEL_COMMON_BLOCK_ACPI_PEP
help
Generate a 2nd set of _DSM functions for the Power Engine device that
will return a buffer that contains the contents of the PMC's LPM
requirements registers. A kernel can use this to display the
requirements for different LPM substates.
config SOC_INTEL_COMMON_BLOCK_CRASHLOG config SOC_INTEL_COMMON_BLOCK_CRASHLOG
bool bool
depends on SOC_INTEL_CRASHLOG depends on SOC_INTEL_CRASHLOG

View File

@ -3,9 +3,12 @@
#include <acpi/acpigen.h> #include <acpi/acpigen.h>
#include <console/console.h> #include <console/console.h>
#include <intelblocks/acpi.h> #include <intelblocks/acpi.h>
#include <intelblocks/pmc_ipc.h>
#include <stdlib.h>
#include <types.h> #include <types.h>
#define LPI_S0_HELPER_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" #define LPI_S0_HELPER_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
#define PEP_S0IX_UUID "57a6512e-3979-4e9d-9708-ff13b2508972"
#define SYSTEM_POWER_MANAGEMENT_HID "INT33A1" #define SYSTEM_POWER_MANAGEMENT_HID "INT33A1"
#define SYSTEM_POWER_MANAGEMENT_CID "PNP0D80" #define SYSTEM_POWER_MANAGEMENT_CID "PNP0D80"
#define EC_S0IX_HOOK "\\_SB.PCI0.LPCB.EC0.S0IX" #define EC_S0IX_HOOK "\\_SB.PCI0.LPCB.EC0.S0IX"
@ -16,6 +19,54 @@
#define MIN_DEVICE_STATE ACPI_DEVICE_SLEEP_D0 #define MIN_DEVICE_STATE ACPI_DEVICE_SLEEP_D0
#define PEPD_SCOPE "\\_SB.PCI0" #define PEPD_SCOPE "\\_SB.PCI0"
struct reg_info {
uint8_t *addr;
size_t buffer_size;
};
static void read_pmc_lpm_requirements(const struct soc_pmc_lpm *lpm,
struct reg_info *info)
{
if (!CONFIG(SOC_INTEL_COMMON_BLOCK_ACPI_PEP_LPM_REQ) || !lpm) {
memset(info, 0, sizeof(*info));
return;
}
const size_t register_count = lpm->num_substates * lpm->num_req_regs;
uint32_t *reg = calloc(register_count, sizeof(uint32_t));
/* Read the various LPM state requirement registers from the PMC */
for (size_t i = 0; i < lpm->num_substates; i++) {
if (!(lpm->lpm_enable_mask & BIT(i)))
continue;
for (size_t j = 0; j < lpm->num_req_regs; j++) {
const uint32_t offset = lpm->lpm_ipc_offset +
i * lpm->req_reg_stride +
j * sizeof(uint32_t);
const uint32_t cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_RD_PMC_REG, 0, 0);
struct pmc_ipc_buffer req = {.buf[0] = offset};
struct pmc_ipc_buffer res = {};
enum cb_err result = pmc_send_ipc_cmd(cmd_reg, &req, &res);
if (result != CB_SUCCESS) {
printk(BIOS_ERR, "Failed to retrieve LPM substate registers"
"from LPM, substate %lu, reg %lu\n", i, j);
free(reg);
return;
}
uint32_t *ptr = reg + i * lpm->num_req_regs + j;
*ptr = res.buf[0];
}
}
if (info) {
info->addr = (uint8_t *)reg;
info->buffer_size = register_count * sizeof(uint32_t);
}
}
/* /*
* For now there is only one disabled non-existent device, because Windows * For now there is only one disabled non-existent device, because Windows
* expects at least one device and crashes without it with a bluescreen * expects at least one device and crashes without it with a bluescreen
@ -104,8 +155,31 @@ static void (*lpi_s0_helpers[])(void *) = {
lpi_s0ix_exit, /* s0ix exit */ lpi_s0ix_exit, /* s0ix exit */
}; };
void generate_acpi_power_engine(void) static void pep_s0ix_return_lpm_requirements(void *arg)
{ {
if (!CONFIG(SOC_INTEL_COMMON_BLOCK_ACPI_PEP_LPM_REQ)) {
acpigen_write_return_singleton_buffer(0x0);
return;
}
struct reg_info *info = (struct reg_info *)arg;
acpigen_write_return_byte_buffer(info->addr, info->buffer_size);
}
static void (*pep_s0ix[])(void *) = {
NULL, /* enumerate functions (autogenerated) */
pep_s0ix_return_lpm_requirements, /* Return LPM requirements */
};
void generate_acpi_power_engine_with_lpm(const struct soc_pmc_lpm *lpm)
{
struct reg_info info;
size_t uuid_count = 1;
struct dsm_uuid ids[] = {
DSM_UUID(LPI_S0_HELPER_UUID, lpi_s0_helpers, ARRAY_SIZE(lpi_s0_helpers), NULL),
DSM_UUID(PEP_S0IX_UUID, pep_s0ix, ARRAY_SIZE(pep_s0ix), &info),
};
acpigen_write_scope(PEPD_SCOPE); acpigen_write_scope(PEPD_SCOPE);
acpigen_write_device("PEPD"); acpigen_write_device("PEPD");
@ -113,10 +187,19 @@ void generate_acpi_power_engine(void)
acpigen_write_name("_CID"); acpigen_write_name("_CID");
acpigen_emit_eisaid(SYSTEM_POWER_MANAGEMENT_CID); acpigen_emit_eisaid(SYSTEM_POWER_MANAGEMENT_CID);
acpigen_write_dsm(LPI_S0_HELPER_UUID, lpi_s0_helpers, ARRAY_SIZE(lpi_s0_helpers), NULL); read_pmc_lpm_requirements(lpm, &info);
if (info.buffer_size)
uuid_count++;
acpigen_write_dsm_uuid_arr(ids, uuid_count);
acpigen_write_device_end(); acpigen_write_device_end();
acpigen_write_scope_end(); acpigen_write_scope_end();
free(info.addr);
printk(BIOS_INFO, PEPD_SCOPE ".PEPD: Intel Power Engine Plug-in\n"); printk(BIOS_INFO, PEPD_SCOPE ".PEPD: Intel Power Engine Plug-in\n");
} }
void generate_acpi_power_engine(void)
{
generate_acpi_power_engine_with_lpm(NULL);
}

View File

@ -90,7 +90,19 @@ struct madt_ioapic_info {
*/ */
const struct madt_ioapic_info *soc_get_ioapic_info(size_t *entries); const struct madt_ioapic_info *soc_get_ioapic_info(size_t *entries);
struct soc_pmc_lpm {
unsigned int num_substates;
unsigned int num_req_regs;
unsigned int lpm_ipc_offset;
unsigned int req_reg_stride;
uint8_t lpm_enable_mask;
};
/* Generate an Intel Power Engine ACPI device */ /* Generate an Intel Power Engine ACPI device */
void generate_acpi_power_engine(void); void generate_acpi_power_engine(void);
/* Generate an Intel Power Engine ACPI device that supports exposing LPM
substate requirements */
void generate_acpi_power_engine_with_lpm(const struct soc_pmc_lpm *lpm);
#endif /* _SOC_INTEL_COMMON_BLOCK_ACPI_H_ */ #endif /* _SOC_INTEL_COMMON_BLOCK_ACPI_H_ */

View File

@ -30,6 +30,9 @@
#define PMC_IPC_CMD_NO_MSI 0 #define PMC_IPC_CMD_NO_MSI 0
/* IPC command for reading PMC registers */
#define PMC_IPC_CMD_RD_PMC_REG 0xA0
/* IPC command to enable/disable PCIe SRCCLK */ /* IPC command to enable/disable PCIe SRCCLK */
#define PMC_IPC_CMD_ID_SET_PCIE_CLOCK 0xAC #define PMC_IPC_CMD_ID_SET_PCIE_CLOCK 0xAC