diff --git a/src/soc/intel/common/block/pcie/rtd3/chip.h b/src/soc/intel/common/block/pcie/rtd3/chip.h index 15b8f64891..7541bc326d 100644 --- a/src/soc/intel/common/block/pcie/rtd3/chip.h +++ b/src/soc/intel/common/block/pcie/rtd3/chip.h @@ -5,6 +5,17 @@ #include +enum acpi_pcie_rp_pm_emit { + ACPI_PCIE_RP_EMIT_NONE = 0x00, /* None */ + ACPI_PCIE_RP_EMIT_L23 = 0x01, /* L23 */ + ACPI_PCIE_RP_EMIT_PSD0 = 0x02, /* PSD0 */ + ACPI_PCIE_RP_EMIT_SRCK = 0x04, /* SRCK */ + ACPI_PCIE_RP_EMIT_L23_PSD0 = 0x03, /* L23, PSD0 */ + ACPI_PCIE_RP_EMIT_L23_SRCK = 0x05, /* L23, SRCK */ + ACPI_PCIE_RP_EMIT_PSD0_SRCK = 0x06, /* PSD0, SRCK */ + ACPI_PCIE_RP_EMIT_ALL = 0x07 /* L23, PSD0, SRCK */ +}; + /* Device support at least one of enable/reset GPIO. */ struct soc_intel_common_block_pcie_rtd3_config { const char *desc; @@ -45,6 +56,26 @@ struct soc_intel_common_block_pcie_rtd3_config { * Disable the ACPI-driven L23 Ready-to-Detect transition for the root port. */ bool disable_l23; + + /* + * Provides L23, modPHY gating, source clock enabling methods to the device + * connected root port, mainly used in the device ACPI methods such as reset. + * The methods to export are following this table: + *-----------------------------------------------------------------------------------* + | ext_pm_support | disable_l123 | srcclk_pin | rp_type | exported methods | + *----------------+--------------+------------+-------------+------------------------* + | false | - | - | - | None | + | true | true | =0 | PCIE_RP_CPU | None | + | true | true | =0 | PCIE_RP_PCH | SRCK | + | true | true | >0 | PCIE_RP_CPU | PSD0 | + | true | true | >0 | PCIE_RP_PCH | PSD0, SRCK | + | true | false | =0 | PCIE_RP_CPU | L23D, LD23 | + | true | false | =0 | PCIE_RP_PCH | L23D, LD23, SRCK | + | true | false | >0 | PCIE_RP_CPU | L23D, LD23, PSD0 | + | true | false | >0 | PCIE_RP_PCH | L23D, LD23, PSD0, SRCK | + *-----------------------------------------------------------------------------------* + */ + enum acpi_pcie_rp_pm_emit ext_pm_support; }; #endif /* __SOC_INTEL_COMMON_BLOCK_PCIE_RTD3_CHIP_H__ */ diff --git a/src/soc/intel/common/block/pcie/rtd3/rtd3.c b/src/soc/intel/common/block/pcie/rtd3/rtd3.c index 9f91d21d3e..260aa6592c 100644 --- a/src/soc/intel/common/block/pcie/rtd3/rtd3.c +++ b/src/soc/intel/common/block/pcie/rtd3/rtd3.c @@ -100,6 +100,46 @@ static void pcie_rtd3_enable_modphy_pg(unsigned int pcie_rp, enum modphy_pg_stat acpigen_emit_namestring(RTD3_MUTEX_PATH); } +/* Method to enter L2/L3 */ +static void pcie_rtd3_acpi_method_dl23(void) +{ + acpigen_write_method_serialized("DL23", 0); + pcie_rtd3_acpi_l23_entry(); + acpigen_pop_len(); /* Method */ +} + +/* Method to exit L2/L3 */ +static void pcie_rtd3_acpi_method_l23d(void) +{ + acpigen_write_method_serialized("L23D", 0); + pcie_rtd3_acpi_l23_exit(); + acpigen_pop_len(); /* Method */ +} + +/* Method to disable PCH modPHY power gating */ +static void pcie_rtd3_acpi_method_pds0(unsigned int pcie_rp) +{ + acpigen_write_method_serialized("PSD0", 0); + pcie_rtd3_enable_modphy_pg(pcie_rp, PG_DISABLE); + acpigen_pop_len(); /* Method */ +} + +/* Method to enable/disable the source clock */ +static void pcie_rtd3_acpi_method_srck(unsigned int pcie_rp, + const struct soc_intel_common_block_pcie_rtd3_config *config) +{ + acpigen_write_method_serialized("SRCK", 1); + + if (config->srcclk_pin >= 0) { + acpigen_write_if_lequal_op_op(ARG0_OP, 0); + pmc_ipc_acpi_set_pci_clock(pcie_rp, config->srcclk_pin, false); + acpigen_write_else(); + pmc_ipc_acpi_set_pci_clock(pcie_rp, config->srcclk_pin, true); + acpigen_pop_len(); /* If */ + } + acpigen_pop_len(); /* Method */ +} + static void pcie_rtd3_acpi_method_on(unsigned int pcie_rp, const struct soc_intel_common_block_pcie_rtd3_config *config, @@ -293,6 +333,24 @@ static void pcie_rtd3_acpi_fill_ssdt(const struct device *dev) printk(BIOS_ERR, "%s: Unknown PCIe root port\n", __func__); return; } + if (config->disable_l23) { + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_L23) { + printk(BIOS_ERR, "%s: Can not export L23 methods\n", __func__); + return; + } + } + if (rp_type != PCIE_RP_PCH) { + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_PSD0) { + printk(BIOS_ERR, "%s: Can not export PSD0 method\n", __func__); + return; + } + } + if (config->srcclk_pin == 0) { + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_SRCK) { + printk(BIOS_ERR, "%s: Can not export SRCK method\n", __func__); + return; + } + } printk(BIOS_INFO, "%s: Enable RTD3 for %s (%s)\n", scope, dev_path(parent), config->desc ?: dev->chip_ops->name); @@ -316,10 +374,21 @@ static void pcie_rtd3_acpi_fill_ssdt(const struct device *dev) acpigen_write_field("PXCS", fieldlist, ARRAY_SIZE(fieldlist), FIELD_ANYACC | FIELD_NOLOCK | FIELD_PRESERVE); + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_L23) { + pcie_rtd3_acpi_method_dl23(); + pcie_rtd3_acpi_method_l23d(); + } + /* Create the OpRegion to access the ModPHY PG registers (PCH RPs only) */ if (rp_type == PCIE_RP_PCH) write_modphy_opregion(pcie_rp); + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_PSD0) + pcie_rtd3_acpi_method_pds0(pcie_rp); + + if (config->ext_pm_support | ACPI_PCIE_RP_EMIT_SRCK) + pcie_rtd3_acpi_method_srck(pcie_rp, config); + /* ACPI Power Resource for controlling the attached device power. */ acpigen_write_power_res("RTD3", 0, 0, power_res_states, ARRAY_SIZE(power_res_states)); pcie_rtd3_acpi_method_status(config);