Duncan Laurie has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/pmc.c 3 files changed, 175 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/1
diff --git a/src/soc/intel/common/block/include/intelblocks/pmc.h b/src/soc/intel/common/block/include/intelblocks/pmc.h index 75e2127..b70d4dd 100644 --- a/src/soc/intel/common/block/include/intelblocks/pmc.h +++ b/src/soc/intel/common/block/include/intelblocks/pmc.h @@ -60,4 +60,27 @@ */ const struct device *soc_get_pmc_mux_device(int port_number);
+/* + * Provides an ACPI method in the SSDT to write to the IPC mailbox which is + * defined in the PMC device MMIO address space. + * + * One possible use of this method is to to enable/disable the clock for a + * particular PCIe root port at runtime when the device is in D3 state. + * + * The ACPI method takes 7 arguments: + * IPCW (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) + * + * And can return: + * 0 = success + * 1 = error + * 2 = timeout + */ +void pmc_acpi_fill_ssdt_ipc_write_method(void); + +/* + * Call the ACPI method to write to the IPC mailbox and enable/disable the + * specified clock pin connected to the specified PCIe root port. + */ +void pmc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable); + #endif /* SOC_INTEL_COMMON_BLOCK_PMC_H */ diff --git a/src/soc/intel/common/block/pmc/Kconfig b/src/soc/intel/common/block/pmc/Kconfig index ce41b23..cb6d888 100644 --- a/src/soc/intel/common/block/pmc/Kconfig +++ b/src/soc/intel/common/block/pmc/Kconfig @@ -13,6 +13,14 @@ config POWER_STATE_DEFAULT_ON_AFTER_FAILURE default y
+config PMC_IPC_MAILBOX_ACPI_INTERFACE + bool + default n + depends on HAVE_ACPI_TABLES + help + Enable this to have the PMC IPC mailbox ACPI interface added + to the SSDT for use by other drivers. + endif # SOC_INTEL_COMMON_BLOCK_PMC
config PMC_INVALID_READ_AFTER_WRITE diff --git a/src/soc/intel/common/block/pmc/pmc.c b/src/soc/intel/common/block/pmc/pmc.c index 24f28e3..76eaddb 100644 --- a/src/soc/intel/common/block/pmc/pmc.c +++ b/src/soc/intel/common/block/pmc/pmc.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi.h> +#include <acpi/acpigen.h> #include <arch/io.h> #include <device/pci_ops.h> #include <console/console.h> @@ -9,6 +10,16 @@ #include <device/pci_ids.h> #include <intelblocks/pmc.h> #include <soc/pci_devs.h> +#include <soc/iomap.h> + +/* PMC IPC Mailbox Interface. */ +#define PMC_IPC_CMD 0x00 /* IPC command */ +#define PMC_IPC_CMD_OFFSET_COMMAND 0 /* IPC command.COMMAND */ +#define PMC_IPC_CMD_OFFSET_SUB_ID 12 /* IPC command.SUB_ID */ +#define PMC_IPC_CMD_OFFSET_SIZE 16 /* IPC command.SIZE */ +#define PMC_IPC_CMD_SET_PCIE_CLOCK 0xAC /* IPC command: Set PCIe Clock */ +#define PMC_IPC_STS 0x04 /* IPC Status */ +#define PMC_IPC_WBUF 0x80 /* IPC Write Buffer */
/* SoC overrides */
@@ -98,6 +109,138 @@ } }
+void pmc_acpi_fill_ssdt_ipc_write_method(void) +{ + const struct fieldlist ipcw_fields[] = { + FIELDLIST_OFFSET(PMC_IPC_CMD), /* Command */ + FIELDLIST_NAMESTR("ICMD", 32), /* Command Register */ + FIELDLIST_OFFSET(PMC_IPC_STS), /* Status */ + FIELDLIST_NAMESTR("IBSY", 1), /* Status Busy */ + FIELDLIST_NAMESTR("IERR", 1), /* Status Error */ + FIELDLIST_OFFSET(PMC_IPC_WBUF), /* Write Buffer */ + FIELDLIST_NAMESTR("IWB0", 32), /* Write Buffer 0 */ + FIELDLIST_NAMESTR("IWB1", 32), /* Write Buffer 1 */ + FIELDLIST_NAMESTR("IWB2", 32), /* Write Buffer 2 */ + FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */ + }; + const struct opregion ipcw_opregion = OPREGION("IPCS", SYSTEMMEMORY, + PCH_PWRM_BASE_ADDRESS, 0xff); + + if (!CONFIG(CONFIG_PMC_IPC_MAILBOX_ACPI_INTERFACE)) + return; + + acpigen_write_method_serialized("IPCW", 7); + + acpigen_write_opregion(&ipcw_opregion); + acpigen_write_field("IPCS", ipcw_fields, ARRAY_SIZE(ipcw_fields), + FIELD_DWORDACC | FIELD_NOLOCK | FIELD_PRESERVE); + + /* Fill write buffer data registers. */ + acpigen_write_store_op_to_namestr(ARG3_OP, "IWB0"); + acpigen_write_store_op_to_namestr(ARG4_OP, "IWB1"); + acpigen_write_store_op_to_namestr(ARG5_OP, "IWB2"); + acpigen_write_store_op_to_namestr(ARG6_OP, "IWB3"); + + /* Program the command register with command and size of write data. */ + acpigen_write_store_int_to_op(0, LOCAL0_OP); + + /* Local0 += (Arg0 << PMC_IPC_CMD_OFFSET_COMMAND) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG0_OP, PMC_IPC_CMD_OFFSET_COMMAND); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 += (Arg1 << PMC_IPC_CMD_OFFSET_SUB_ID) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG1_OP, PMC_IPC_CMD_OFFSET_SUB_ID); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 += (Arg1 << PMC_IPC_CMD_OFFSET_SIZE) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG2_OP, PMC_IPC_CMD_OFFSET_SIZE); + acpigen_emit_byte(LOCAL0_OP); + + /* Start mailbox command with one 32bit write. */ + acpigen_write_store_op_to_namestr(LOCAL0_OP, "ICMD"); + + /* Read status register to get busy/error status for up to 10ms. */ + acpigen_write_store_int_to_op(10, LOCAL1_OP); + + /* While (Local0 > 0) */ + acpigen_emit_byte(WHILE_OP); + acpigen_write_len_f(); + acpigen_emit_byte(LGREATER_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(ZERO_OP); + /* If (IBSY == 0) { Return (SUCCESS) } */ + acpigen_write_if_lequal_namestr_int("IBSY", 0); + acpigen_write_return_integer(0); + acpigen_pop_len(); + /* If (IERR == 1) { Return (ERROR) } */ + acpigen_write_if_lequal_namestr_int("IERR", 1); + acpigen_write_return_integer(1); + acpigen_pop_len(); + /* Sleep (1) */ + acpigen_write_sleep(1); + /* Decrement (Local0) */ + acpigen_emit_byte(DECREMENT_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_pop_len(); /* While */ + /* Return (TIMEOUT) */ + acpigen_write_return_integer(2); + + acpigen_pop_len(); /* Method */ +} + +void pmc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable) +{ + const uint32_t data[] = { + 1 << clock_pin, /* Clock pin to be modified */ + (enable ? 0 : 1) << clock_pin, /* Clock pin to set */ + 1 << pcie_rp, /* PCIe root port to be modified */ + (enable ? 0 : 1) << pcie_rp, /* PCIe root port to set */ + }; + const char *method = acpi_device_path_join(pcidev_path_on_root(PCH_DEVFN_PMC), "IPCW"); + + if (!CONFIG(CONFIG_PMC_IPC_MAILBOX_ACPI_INTERFACE)) + return; + + if (!method) { + printk(BIOS_ERR, "%s: Unable to find PMC device IPCW method\n", __func__); + return; + } + + /* + * The PMC IPC mailbox write method takes 7 arguments: + * IPCW (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) + */ + acpigen_emit_namestring(method); + acpigen_write_integer(PMC_IPC_CMD_SET_PCIE_CLOCK); + acpigen_write_integer(0); + acpigen_write_integer(sizeof(data)); + acpigen_write_integer(data[0]); + acpigen_write_integer(data[1]); + acpigen_write_integer(data[2]); + acpigen_write_integer(data[3]); +} + +static void pmc_fill_ssdt(const struct device *dev) +{ + const char *scope = acpi_device_scope(dev); + + if (!scope) + return; + + acpigen_write_scope(scope); + + /* Define IPC Write Method */ + pmc_acpi_fill_ssdt_ipc_write_method(); + + acpigen_pop_len(); /* Scope */ +} + static struct device_operations device_ops = { .read_resources = pch_pmc_read_resources, .set_resources = pci_dev_set_resources, @@ -105,6 +248,7 @@ .init = pmc_soc_init, .ops_pci = &pci_dev_ops_pci, .scan_bus = scan_static_bus, + .acpi_fill_ssdt = pmc_fill_ssdt, };
static const unsigned short pci_device_ids[] = {
Hello build bot (Jenkins), Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#2).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/pmc.c 3 files changed, 175 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/2
Hello build bot (Jenkins), Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#3).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/pmc.c 3 files changed, 175 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/3
Hello build bot (Jenkins), Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#4).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc A src/soc/intel/common/block/pmc/pmc_ipc.c 4 files changed, 159 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/4
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 4:
I need to rebase this on top of https://review.coreboot.org/c/coreboot/+/42077/12
Hello build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#5).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 5 files changed, 179 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/5
Hello build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#6).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 5 files changed, 179 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/6
Hello build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#10).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc.h M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 5 files changed, 181 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/10
Tim Wawrzynczak has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 10:
(5 comments)
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... File src/soc/intel/common/block/pmc/pmc_ipc.c:
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 112: FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */ I wonder if the results contained in the read buffer are ever worth keeping around? I see they weren't used in the .asl file, but does it provide additional status beyond the IERR bit?
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 164: Local0 Local1
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 172: 0 Should this be a #define in the .h file? So if the results of the IPCW call are needed elsehwere they can be referenced from here, same with error & timeout?
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 181: Local0 Local1
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 215: acpigen_write_integer acpigen_write_dword? probably doesn't matter, it does know the write buffer fields are 32 bits wide.
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 10:
(5 comments)
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... File src/soc/intel/common/block/pmc/pmc_ipc.c:
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 112: FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */
I wonder if the results contained in the read buffer are ever worth keeping around? I see they weren […]
I started by thinking a read function would be separate, but it would end up with a lot of duplicated code so I guess I might as well do it in here.
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 164: Local0
Local1
Done
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 172: 0
Should this be a #define in the . […]
Ya I can do that. The current RTD3 use case ignores the return value since there isn't much it can do about it but it might as well make it available.
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 181: Local0
Local1
Done
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 215: acpigen_write_integer
acpigen_write_dword? probably doesn't matter, it does know the write buffer fields are 32 bits wide.
Done
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 10:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... File src/soc/intel/common/block/include/intelblocks/pmc_ipc.h:
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 52: /* : * Provides an ACPI method in the SSDT to write to the IPC mailbox which is : * defined in the PMC device MMIO address space. : * : * One possible use of this method is to to enable/disable the clock for a : * particular PCIe root port at runtime when the device is in D3 state. : * : * The ACPI method takes 7 arguments: : * IPCW (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) : * : * And can return: : * 0 = success : * 1 = error : * 2 = timeout : */ : void pmc_ipc_acpi_fill_ssdt(void); : : /* : * Call the ACPI method to write to the IPC mailbox and enable/disable the : * specified clock pin connected to the specified PCIe root port. : */ : void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable); : not sure why this is in both headers...
Hello build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#11).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 4 files changed, 195 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/11
Tim Wawrzynczak has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 11:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... File src/soc/intel/common/block/pmc/pmc_ipc.c:
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... PS11, Line 127: /* Package with return value and read buffer. */ : acpigen_write_name("RVAL"); : acpigen_write_package(5); : for (i = 0; i < 5; ++i) : acpigen_write_integer(0); : acpigen_pop_len(); : suggestion: IASL always suggests not creating named objects inside of a method (i'm guessing it's a performance issue); I usually keep them in the same scope as the method if I can
Hello build bot (Jenkins), Patrick Georgi, Martin Roth, Patrick Rudolph,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/46259
to look at the new patch set (#12).
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 --- M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 4 files changed, 195 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/59/46259/12
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 12:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... File src/soc/intel/common/block/pmc/pmc_ipc.c:
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... PS11, Line 127: /* Package with return value and read buffer. */ : acpigen_write_name("RVAL"); : acpigen_write_package(5); : for (i = 0; i < 5; ++i) : acpigen_write_integer(0); : acpigen_pop_len(); :
suggestion: IASL always suggests not creating named objects inside of a method (i'm guessing it's a […]
Done. With the more complicated return package this might need a separate mutex if there were multiple devices trying to read (and process the return data). Currently the return is just ignored by the rtd3 driver so it doesn't really matter since the method itself is serialized. I guess I could make it take the package as an input, but that just complicates the caller...
Duncan Laurie has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 12:
(1 comment)
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... File src/soc/intel/common/block/include/intelblocks/pmc_ipc.h:
https://review.coreboot.org/c/coreboot/+/46259/10/src/soc/intel/common/block... PS10, Line 52: /* : * Provides an ACPI method in the SSDT to write to the IPC mailbox which is : * defined in the PMC device MMIO address space. : * : * One possible use of this method is to to enable/disable the clock for a : * particular PCIe root port at runtime when the device is in D3 state. : * : * The ACPI method takes 7 arguments: : * IPCW (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) : * : * And can return: : * 0 = success : * 1 = error : * 2 = timeout : */ : void pmc_ipc_acpi_fill_ssdt(void); : : /* : * Call the ACPI method to write to the IPC mailbox and enable/disable the : * specified clock pin connected to the specified PCIe root port. : */ : void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable); :
not sure why this is in both headers...
Ack
Tim Wawrzynczak has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
Patch Set 13: Code-Review+2
(1 comment)
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... File src/soc/intel/common/block/pmc/pmc_ipc.c:
https://review.coreboot.org/c/coreboot/+/46259/11/src/soc/intel/common/block... PS11, Line 127: /* Package with return value and read buffer. */ : acpigen_write_name("RVAL"); : acpigen_write_package(5); : for (i = 0; i < 5; ++i) : acpigen_write_integer(0); : acpigen_pop_len(); :
Done. […]
Yeah there's the implicit mutex around its usage now; if other usages come up, we may have to dynamically create the object or add locking
Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/46259 )
Change subject: intel/common/pmc: Add functions for IPC mailbox in ACPI ......................................................................
intel/common/pmc: Add functions for IPC mailbox in ACPI
This change adds two functions that provide an IPC mailbox method via ACPI for runtime clock configuration.
pmc_acpi_fill_ssdt_ipc_write_method() will provide a method in the SSDT that can be called by other ACPI devices to send an IPC mailbox command. This function is exported because some SOCs override the default PMC device and need to call this function to write the method into the SSDT.
pmc_acpi_set_pci_clock() will call the method defined by the previous function to enable or disable the PCIe SRCCLK for a specified root port and clock pin. It can be called by the PCIe root port after turning off power to the attached device.
BUG=b:160996445 TEST=boot on volteer device and disassemble the SSDT to ensure that this method exists.
Signed-off-by: Duncan Laurie dlaurie@google.com Change-Id: I95f5a1ba2bc6905e0f8ce0e8b2342ad1287a23a0 Reviewed-on: https://review.coreboot.org/c/coreboot/+/46259 Reviewed-by: Tim Wawrzynczak twawrzynczak@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/soc/intel/common/block/include/intelblocks/pmc_ipc.h M src/soc/intel/common/block/pmc/Kconfig M src/soc/intel/common/block/pmc/Makefile.inc M src/soc/intel/common/block/pmc/pmc_ipc.c 4 files changed, 195 insertions(+), 3 deletions(-)
Approvals: build bot (Jenkins): Verified Tim Wawrzynczak: Looks good to me, approved
diff --git a/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h b/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h index 0c90cd7..fbf9a6e 100644 --- a/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h +++ b/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h @@ -21,6 +21,14 @@
#define PMC_IPC_CMD_NO_MSI 0
+/* IPC command to enable/disable PCIe SRCCLK */ +#define PMC_IPC_CMD_ID_SET_PCIE_CLOCK 0xAC + +/* IPC return values */ +#define PMC_IPC_SUCCESS 0 +#define PMC_IPC_ERROR 1 +#define PMC_IPC_TIMEOUT 2 + /* * Create the IPC CMD to send to PMC */ @@ -46,4 +54,29 @@ enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf, struct pmc_ipc_buffer *rbuf);
+/* + * Provides an ACPI method in the SSDT to read/write to the IPC mailbox which is + * defined in the PMC device MMIO address space. + * + * One possible use of this method is to to enable/disable the clock for a + * particular PCIe root port at runtime when the device is in D3 state. + * + * The ACPI method takes 7 arguments: + * IPCW (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) + * + * And will return a package with 5 elements: + * 0 = Return code + * PMC_IPC_SUCCESS + * PMC_IPC_ERROR + * PMC_IPC_TIMEOUT + * 1..4 = Data read from IPC if return code is PMC_IPC_SUCCESS + */ +void pmc_ipc_acpi_fill_ssdt(void); + +/* + * Call the ACPI method to write to the IPC mailbox and enable/disable the + * specified clock pin connected to the specified PCIe root port. + */ +void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable); + #endif /* SOC_INTEL_COMMON_BLOCK_PMC_IPC_H */ diff --git a/src/soc/intel/common/block/pmc/Kconfig b/src/soc/intel/common/block/pmc/Kconfig index ce41b23..5cb2bea 100644 --- a/src/soc/intel/common/block/pmc/Kconfig +++ b/src/soc/intel/common/block/pmc/Kconfig @@ -22,6 +22,14 @@ Enable this for PMC devices where a read back of ACPI BAR and IO access bit does not return the previously written value.
+config PMC_IPC_ACPI_INTERFACE + bool + default n + depends on HAVE_ACPI_TABLES + help + Enable this to have the PMC IPC mailbox ACPI interface added + to the SSDT for use by other drivers. + config PMC_GLOBAL_RESET_ENABLE_LOCK bool help diff --git a/src/soc/intel/common/block/pmc/Makefile.inc b/src/soc/intel/common/block/pmc/Makefile.inc index 796a039..49a0902 100644 --- a/src/soc/intel/common/block/pmc/Makefile.inc +++ b/src/soc/intel/common/block/pmc/Makefile.inc @@ -6,4 +6,5 @@ smm-y += pmclib.c verstage-y += pmclib.c postcar-y += pmclib.c +ramstage-$(CONFIG_PMC_IPC_ACPI_INTERFACE) += pmc_ipc.c endif diff --git a/src/soc/intel/common/block/pmc/pmc_ipc.c b/src/soc/intel/common/block/pmc/pmc_ipc.c index 7decf79..7c811ae 100644 --- a/src/soc/intel/common/block/pmc/pmc_ipc.c +++ b/src/soc/intel/common/block/pmc/pmc_ipc.c @@ -1,10 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-only */
+#include <acpi/acpigen.h> #include <device/mmio.h> #include <console/console.h> #include <delay.h> #include <intelblocks/pmclib.h> #include <intelblocks/pmc_ipc.h> +#include <soc/pci_devs.h> #include <stdint.h> #include <timer.h>
@@ -64,16 +66,16 @@ if (IPC_STS_HAS_ERROR(ipc_sts)) { printk(BIOS_ERR, "IPC_STS.error_code 0x%x\n", IPC_STS_ERROR_CODE(ipc_sts)); - return -1; + return PMC_IPC_ERROR; } - return 0; + return PMC_IPC_SUCCESS; } udelay(50);
} while (!stopwatch_expired(&sw));
printk(BIOS_ERR, "PMC IPC timeout after %u ms\n", PMC_IPC_XFER_TIMEOUT_MS); - return -1; + return PMC_IPC_TIMEOUT; }
enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf, @@ -94,3 +96,151 @@
return CB_SUCCESS; } + +void pmc_ipc_acpi_fill_ssdt(void) +{ + const struct fieldlist ipcs_fields[] = { + FIELDLIST_OFFSET(PMC_IPC_CMD_OFFSET), /* Command */ + FIELDLIST_NAMESTR("ICMD", 32), /* Command Register */ + FIELDLIST_OFFSET(PMC_IPC_STS_OFFSET), /* Status */ + FIELDLIST_NAMESTR("IBSY", 1), /* Status Busy */ + FIELDLIST_NAMESTR("IERR", 1), /* Status Error */ + FIELDLIST_RESERVED(14), + FIELDLIST_NAMESTR("IERC", 8), /* Status Error Code */ + FIELDLIST_OFFSET(IPC_WBUF0), /* Write Buffer */ + FIELDLIST_NAMESTR("IWB0", 32), /* Write Buffer 0 */ + FIELDLIST_NAMESTR("IWB1", 32), /* Write Buffer 1 */ + FIELDLIST_NAMESTR("IWB2", 32), /* Write Buffer 2 */ + FIELDLIST_NAMESTR("IWB3", 32), /* Write Buffer 3 */ + FIELDLIST_OFFSET(IPC_RBUF0), /* Read Buffer */ + FIELDLIST_NAMESTR("IRB0", 32), /* Read Buffer 0 */ + FIELDLIST_NAMESTR("IRB1", 32), /* Read Buffer 1 */ + FIELDLIST_NAMESTR("IRB2", 32), /* Read Buffer 2 */ + FIELDLIST_NAMESTR("IRB3", 32), /* Read Buffer 3 */ + }; + const struct opregion ipcs_opregion = OPREGION("IPCM", SYSTEMMEMORY, + soc_read_pmc_base(), 0xff); + int i; + + /* Package with return value and read buffer. */ + acpigen_write_name("RVAL"); + acpigen_write_package(5); + for (i = 0; i < 5; ++i) + acpigen_write_integer(0); + acpigen_pop_len(); + + acpigen_write_method_serialized("IPCS", 7); + + acpigen_write_opregion(&ipcs_opregion); + acpigen_write_field("IPCM", ipcs_fields, ARRAY_SIZE(ipcs_fields), + FIELD_DWORDACC | FIELD_NOLOCK | FIELD_PRESERVE); + + /* Fill write buffer data registers. */ + acpigen_write_store_op_to_namestr(ARG3_OP, "IWB0"); + acpigen_write_store_op_to_namestr(ARG4_OP, "IWB1"); + acpigen_write_store_op_to_namestr(ARG5_OP, "IWB2"); + acpigen_write_store_op_to_namestr(ARG6_OP, "IWB3"); + + /* Program the command register with command and size of write data. */ + acpigen_write_store_int_to_op(0, LOCAL0_OP); + + /* Local0 += (Arg0 << PMC_IPC_CMD_COMMAND_SHIFT) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG0_OP, PMC_IPC_CMD_COMMAND_SHIFT); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 += (Arg1 << PMC_IPC_CMD_SUB_COMMAND_SHIFT) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG1_OP, PMC_IPC_CMD_SUB_COMMAND_SHIFT); + acpigen_emit_byte(LOCAL0_OP); + + /* Local1 = PMC_IPC_CMD_NO_MSI */ + acpigen_write_store_int_to_op(PMC_IPC_CMD_NO_MSI, LOCAL1_OP); + /* Local0 += (Local1 << PMC_IPC_CMD_MSI_SHIFT) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(LOCAL1_OP, PMC_IPC_CMD_MSI_SHIFT); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 += (Arg1 << PMC_IPC_CMD_SIZE_SHIFT) */ + acpigen_emit_byte(ADD_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_shiftleft_op_int(ARG2_OP, PMC_IPC_CMD_SIZE_SHIFT); + acpigen_emit_byte(LOCAL0_OP); + + /* Start mailbox command with one 32bit write. */ + acpigen_write_store_op_to_namestr(LOCAL0_OP, "ICMD"); + + /* Read status register to get busy/error status. */ + acpigen_write_store_int_to_op(PMC_IPC_XFER_TIMEOUT_MS, LOCAL1_OP); + + /* While (Local1 > 0) */ + acpigen_emit_byte(WHILE_OP); + acpigen_write_len_f(); + acpigen_emit_byte(LGREATER_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(ZERO_OP); + + /* If (IBSY == 0) { Return (SUCCESS) } */ + acpigen_write_if_lequal_namestr_int("IBSY", 0); + acpigen_set_package_element_int("RVAL", 0, PMC_IPC_SUCCESS); + acpigen_set_package_element_namestr("RVAL", 1, "IRB0"); + acpigen_set_package_element_namestr("RVAL", 2, "IRB1"); + acpigen_set_package_element_namestr("RVAL", 3, "IRB2"); + acpigen_set_package_element_namestr("RVAL", 4, "IRB3"); + acpigen_write_return_namestr("RVAL"); + acpigen_pop_len(); + + /* If (IERR == 1) { Return (ERROR) } */ + acpigen_write_if_lequal_namestr_int("IERR", 1); + acpigen_write_debug_string("IPCS ERROR"); + acpigen_write_debug_namestr("IERC"); + acpigen_set_package_element_int("RVAL", 0, PMC_IPC_ERROR); + acpigen_write_return_namestr("RVAL"); + acpigen_pop_len(); + + /* Sleep (1) */ + acpigen_write_sleep(1); + /* Decrement (Local1) */ + acpigen_emit_byte(DECREMENT_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_pop_len(); /* While */ + + /* Return (TIMEOUT) */ + acpigen_write_debug_string("IPCS TIMEOUT"); + acpigen_set_package_element_int("RVAL", 0, PMC_IPC_TIMEOUT); + acpigen_write_return_namestr("RVAL"); + + acpigen_pop_len(); /* Method */ +} + +void pmc_ipc_acpi_set_pci_clock(unsigned int pcie_rp, unsigned int clock_pin, bool enable) +{ + const uint32_t data[] = { + 1 << clock_pin, /* Clock pin to be modified */ + (enable ? 1 : 0) << clock_pin, /* Clock pin to set */ + 1 << pcie_rp, /* PCIe root port to be modified */ + (enable ? 1 : 0) << pcie_rp, /* PCIe root port to set */ + }; + const char *method = acpi_device_path_join(pcidev_path_on_root(PCH_DEVFN_PMC), "IPCS"); + + if (!method) { + printk(BIOS_ERR, "%s: Unable to find PMC device IPCS method\n", __func__); + return; + } + + /* + * The PMC IPC mailbox method takes 7 arguments: + * IPCS (COMMAND, SUB_ID, SIZE, DATA0, DATA1, DATA2, DATA3) + */ + acpigen_emit_namestring(method); + acpigen_write_integer(PMC_IPC_CMD_ID_SET_PCIE_CLOCK); + acpigen_write_integer(0); + acpigen_write_integer(sizeof(data)); + acpigen_write_dword(data[0]); + acpigen_write_dword(data[1]); + acpigen_write_dword(data[2]); + acpigen_write_dword(data[3]); +}