Benjamin Doron has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81935?usp=email )
Change subject: soc/intel/common/block/pmc: Move ACPI generation to a separate file ......................................................................
soc/intel/common/block/pmc: Move ACPI generation to a separate file
The PMC IPC interface may be used in stages other than ramstage. Therefore, move the ACPI specific parts, so that pmc_ipc.c can be compiled into all necessary stages.
This change is needed for the follow-ups, which will dump any CrashLog data found to the console during bootblock.
Change-Id: If4df90e33f6982d3eae2474db6d095a9dda7a624 Signed-off-by: Benjamin Doron benjamin.doron@9elements.com --- M src/soc/intel/common/block/pmc/Makefile.mk M src/soc/intel/common/block/pmc/pmc_ipc.c A src/soc/intel/common/block/pmc/pmc_ipc_acpi.c 3 files changed, 176 insertions(+), 149 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/81935/1
diff --git a/src/soc/intel/common/block/pmc/Makefile.mk b/src/soc/intel/common/block/pmc/Makefile.mk index e46d5ee..ea9242b 100644 --- a/src/soc/intel/common/block/pmc/Makefile.mk +++ b/src/soc/intel/common/block/pmc/Makefile.mk @@ -8,4 +8,5 @@ verstage-y += pmclib.c postcar-y += pmclib.c ramstage-$(CONFIG_PMC_IPC_ACPI_INTERFACE) += pmc_ipc.c +ramstage-$(CONFIG_PMC_IPC_ACPI_INTERFACE) += pmc_ipc_acpi.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 7c811ae..3f0f27c 100644 --- a/src/soc/intel/common/block/pmc/pmc_ipc.c +++ b/src/soc/intel/common/block/pmc/pmc_ipc.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */
-#include <acpi/acpigen.h> #include <device/mmio.h> #include <console/console.h> #include <delay.h> @@ -96,151 +95,3 @@
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]); -} diff --git a/src/soc/intel/common/block/pmc/pmc_ipc_acpi.c b/src/soc/intel/common/block/pmc/pmc_ipc_acpi.c new file mode 100644 index 0000000..500e4fb --- /dev/null +++ b/src/soc/intel/common/block/pmc/pmc_ipc_acpi.c @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpigen.h> +#include <intelblocks/pmc_ipc.h> +#include <intelblocks/pmclib.h> +#include <soc/pci_devs.h> +#include <timer.h> + +/* + * WBUF register block offset 0x80..0x8f there are 4 consecutive + * 32 bit registers + */ +#define IPC_WBUF0 0x80 + +/* + * RBUF registers block offset 0x90..0x9f there are 4 consecutive + * 32 bit registers + */ +#define IPC_RBUF0 0x90 + +/* + * From Intel 500 Series PCH EDS vol2 s4.4 + */ +#define PMC_IPC_CMD_OFFSET 0x0 +#define PMC_IPC_STS_OFFSET 0x4 + +#define PMC_IPC_XFER_TIMEOUT_MS (1 * MSECS_PER_SEC) /* max 1s */ + +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]); +}