Attention is currently required from: Arthur Heymans, Christian Walter, Johnny Lin, Jonathan Zhang, Lean Sheng Tan, Patrick Rudolph, Tim Chu.
Shuo Liu has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81375?usp=email )
Change subject: soc/intel/xeon_sp: Add support of _OSC ASL generation ......................................................................
soc/intel/xeon_sp: Add support of _OSC ASL generation
Change-Id: I711ce5350d718e47feb2912555108801ad7f918d Signed-off-by: Shuo Liu shuo.liu@intel.com --- M src/soc/intel/xeon_sp/acpi.c M src/soc/intel/xeon_sp/gnr/soc_acpi.c M src/soc/intel/xeon_sp/include/soc/acpi.h 3 files changed, 340 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/75/81375/1
diff --git a/src/soc/intel/xeon_sp/acpi.c b/src/soc/intel/xeon_sp/acpi.c index 9ee8d6a..2a37070 100644 --- a/src/soc/intel/xeon_sp/acpi.c +++ b/src/soc/intel/xeon_sp/acpi.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <acpi/acpigen.h> #include <assert.h> #include <intelblocks/acpi.h> #include <soc/chip_common.h> @@ -157,3 +158,319 @@
return NULL; } + +#define PCI_HOST_BRIDGE_OSC_UUID "33db4d5b-1ff7-401c-9657-7441c03dd766" +#define CXL_HOST_BRIDGE_OSC_UUID "68f2d50b-c469-4d8a-bd3d-941a103fd3fc" + +#define OSC_RET_FAILURE 0x02 +#define OSC_RET_UNRECOGNIZED_UUID 0x04 +#define OSC_RET_UNRECOGNIZED_REV 0x08 +#define OSC_RET_CAPABILITIES_MASKED 0x10 + +#define OSC_QUERY_SUPPORT_SET 0x01 + +#define PCIE_NATIVE_HOTPLUG_CONTROL 0x01 +#define SHPC_NATIVE_HOTPLUG_CONTROL 0x02 +#define PCIE_PME_CONTROL 0x04 +#define PCIE_AER_CONTROL 0x08 +#define PCIE_CAP_STRUCTURE_CONTROL 0x10 +#define PCIE_LTR_CONTROL 0x20 + +#define ASL_BRANCH_HIT 0x01 +#define ASL_BRANCH_MISS 0x00 + +static void soc_acpigen_OSC_handle_pcie_request(const struct device *domain); +static void soc_acpigen_OSC_handle_cxl_request(const struct device *domain); + +/* + * soc_acpigen_write_OSC + * + * Reference: + * 6.2.11 in https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/06_Device_Configuration/Device... + * + * _OSC ASL Arguments: (4) + * Arg0 - A Buffer containing a UUID + * Arg1 - An Integer containing a Revision ID of the buffer format + * Arg2 - An Integer containing a count of entries in Arg3 + * Arg3 - A Buffer containing a list of DWORD capabilities + * + * _OSC ASL Return Value: + * A Buffer containing a list of capabilities + * + * Local Variables Assignment: + * Local0 - Temp assigned + * Local1 - Temp assigned + * Local2 - Temp assigned + * Local3 - Temp assigned + * Local4 - Temp assigned + * Local5 - Not used + * Local6 - Not used + * Local7 - Backs up the input value of Arg3 + * + * Field Definitions: + * Name - With, Source, Offset, Description + * -------------------------------- + * QSUP - DWord, Local7, 0x00, Query support + * RETE - DWord, Arg3, 0x00, Returned errors + * SUPP - Dword, Arg3, 0x04, PCIe Features that OS supported + * CTRL - Dword, Arg3, 0x08, PCIe Features that firmware grant control to OS + * OTRL - Dword, Local7, 0x08, PCIe Features that OS requests for control + * SUPC - Dword, Arg3, 0x0C, CXL Features that OS supported + * CTRC - Dword, Arg3, 0x10, CXL Features that firmware grant control to OS + * OTRC - Dword, Local7, 0x10, CXL Features that OS requests for control + */ +void soc_acpigen_write_OSC(const struct device *domain) +{ + /* + * Method (_OSC, 4, NotSerialized) + * { + */ + acpigen_write_method("_OSC", 4); + + /* + * Local7 = Arg3 + * CreateDwordField (Local7, 0x00, QSUP) + * CreateDWordField (Arg3, 0x00, RETE) + * RETE = 0x0 + */ + acpigen_write_store_ops(ARG3_OP, LOCAL7_OP); + acpigen_write_create_dword_field(LOCAL7_OP, 0x00, "QSUP"); + acpigen_write_create_dword_field(ARG3_OP, 0x00, "RETE"); + acpigen_write_store_int_to_namestr(0x0, "RETE"); + + if (is_cxl_domain(domain)) { + /* + * If ((Arg0 != ToUUID (PCI_HOST_BRIDGE_OSC_UUID)) && + * (Arg0 != ToUUID (CXL_HOST_BRIDGE_OSC_UUID))) + */ + acpigen_write_if(); + acpigen_emit_byte(LAND_OP); + acpigen_emit_byte(LNOT_OP); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_uuid(PCI_HOST_BRIDGE_OSC_UUID); + acpigen_emit_byte(LNOT_OP); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_uuid(CXL_HOST_BRIDGE_OSC_UUID); + } else { + /* + * If (Arg0 != ToUUID (PCI_HOST_BRIDGE_OSC_UUID)) + */ + acpigen_write_if(); + acpigen_emit_byte(LNOT_OP); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_uuid(PCI_HOST_BRIDGE_OSC_UUID); + } + + /* + * { + * RETE |= OSC_RET_UNRECOGNIZED_UUID + * Return (Arg3) + * } + */ + acpigen_write_store(); + acpigen_write_integer(ASL_BRANCH_HIT); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_write_else(); + + acpigen_write_store(); + acpigen_write_integer(ASL_BRANCH_MISS); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_write_if_end(); + + acpigen_write_if_lequal_op_int(LOCAL0_OP, ASL_BRANCH_HIT); + + acpigen_write_to_integer_from_namestring("RETE", LOCAL1_OP); + acpigen_write_store_int_to_op(OSC_RET_UNRECOGNIZED_UUID, LOCAL2_OP); + acpigen_write_or(LOCAL1_OP, LOCAL2_OP, LOCAL1_OP); + acpigen_write_store_op_to_namestr(LOCAL1_OP, "RETE"); + acpigen_write_return_op(ARG3_OP); + + acpigen_write_if_end(); + + if (!is_cxl_domain(domain)) { + /* + * // Handle PCIe _OSC request + */ + soc_acpigen_OSC_handle_pcie_request(domain); + + } else { + /* + * If (Arg0 == ToUUID (PCI_HOST_BRIDGE_OSC_UUID)) + * { + * // Handle PCIe _OSC request + * } + */ + acpigen_write_if(); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_uuid(PCI_HOST_BRIDGE_OSC_UUID); + + soc_acpigen_OSC_handle_pcie_request(domain); + + acpigen_write_if_end(); + /* + * If (Arg0 == ToUUID (CXL_HOST_BRIDGE_OSC_UUID)) + * { + * // Handle CXL _OSC request + * } + */ + acpigen_write_if(); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_uuid(CXL_HOST_BRIDGE_OSC_UUID); + + soc_acpigen_OSC_handle_pcie_request(domain); + soc_acpigen_OSC_handle_cxl_request(domain); + + acpigen_write_if_end(); + } + + /* + * Return (Arg3) + */ + acpigen_write_return_op(ARG3_OP); + + /* + * } + */ + acpigen_pop_len(); +} + +void soc_acpigen_OSC_handle_pcie_request(const struct device *domain) +{ + unsigned long osc_pci_host_bridge_features = get_supported_pci_host_bridge_features(domain); + + /* + * If (Arg2 < 2)) + * { + * RETE |= OSC_RET_FAILURE + * Return (Arg3) + * } + */ + acpigen_write_if(); + acpigen_emit_byte(LLESS_OP); + acpigen_emit_byte(ARG2_OP); + acpigen_write_integer(0x2); + + acpigen_write_to_integer_from_namestring("RETE", LOCAL1_OP); + acpigen_write_store_int_to_op(OSC_RET_FAILURE, LOCAL2_OP); + acpigen_write_or(LOCAL1_OP, LOCAL2_OP, LOCAL1_OP); + acpigen_write_store_op_to_namestr(LOCAL1_OP, "RETE"); + acpigen_write_return_op(ARG3_OP); + + acpigen_write_if_end(); + + /* + * CreateDWordField (Arg3, 0x04, SUPP) + * CreateDWordField (Arg3, 0x08, CTRL) + * CreateDWordField (Local7, 0x08, OTRL) + */ + acpigen_write_create_dword_field(ARG3_OP, 0x04, "SUPP"); + acpigen_write_create_dword_field(ARG3_OP, 0x08, "CTRL"); + acpigen_write_create_dword_field(LOCAL7_OP, 0x08, "OTRL"); + + /* + * // Grant PCIe feature controls to OS + * CTRL &= osc_pci_host_bridge_features + */ + acpigen_write_to_integer_from_namestring("CTRL", LOCAL1_OP); + acpigen_write_store_int_to_op(osc_pci_host_bridge_features, LOCAL2_OP); + acpigen_write_and(LOCAL1_OP, LOCAL2_OP, LOCAL1_OP); + acpigen_write_store_op_to_namestr(LOCAL1_OP, "CTRL"); + + /* + * If (CTRL != OTRL) + * { + * RETE |= OSC_RET_CAPABILITIES_MASKED + * } + */ + acpigen_write_to_integer_from_namestring("CTRL", LOCAL1_OP); + acpigen_write_to_integer_from_namestring("OTRL", LOCAL2_OP); + acpigen_write_if(); + acpigen_emit_byte(LNOT_OP); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(LOCAL2_OP); + acpigen_write_to_integer_from_namestring("RETE", LOCAL3_OP); + acpigen_write_store_int_to_op(OSC_RET_CAPABILITIES_MASKED, LOCAL4_OP); + acpigen_write_or(LOCAL3_OP, LOCAL4_OP, LOCAL3_OP); + acpigen_write_store_op_to_namestr(LOCAL3_OP, "RETE"); + acpigen_write_if_end(); +}; + +void soc_acpigen_OSC_handle_cxl_request(const struct device *domain) +{ + unsigned long osc_cxl_host_bridge_features = get_supported_cxl_host_bridge_features(domain); + + /* + * If (Arg2 < 4)) + * { + * RETE |= OSC_RET_FAILURE + * Return (Arg3) + * } + */ + acpigen_write_if(); + acpigen_emit_byte(LLESS_OP); + acpigen_emit_byte(ARG2_OP); + acpigen_write_integer(0x4); + + acpigen_write_to_integer_from_namestring("RETE", LOCAL1_OP); + acpigen_write_store_int_to_op(OSC_RET_FAILURE, LOCAL2_OP); + acpigen_write_or(LOCAL1_OP, LOCAL2_OP, LOCAL1_OP); + acpigen_write_store_op_to_namestr(LOCAL1_OP, "RETE"); + acpigen_write_return_op(ARG3_OP); + + acpigen_write_if_end(); + + /* + * CreateDWordField (Arg3, 0x0C, SUPC) + * CreateDWordField (Arg3, 0x10, CTRC) + * CreateDWordField (Local7, 0x10, OTRC) + */ + acpigen_write_create_dword_field(ARG3_OP, 0x0C, "SUPC"); + acpigen_write_create_dword_field(ARG3_OP, 0x10, "CTRC"); + acpigen_write_create_dword_field(LOCAL7_OP, 0x10, "OTRC"); + + /* + * // Grant CXL feature controls to OS + * CTRC &= osc_cxl_host_bridge_features + */ + acpigen_write_to_integer_from_namestring("CTRC", LOCAL1_OP); + acpigen_write_store_int_to_op(osc_cxl_host_bridge_features, LOCAL2_OP); + acpigen_write_and(LOCAL1_OP, LOCAL2_OP, LOCAL1_OP); + acpigen_write_store_op_to_namestr(LOCAL1_OP, "CTRC"); + + /* + * If (CTRC != OTRC) + * { + * RETE |= OSC_RET_CAPABILITIES_MASKED + * } + */ + acpigen_write_to_integer_from_namestring("CTRC", LOCAL1_OP); + acpigen_write_to_integer_from_namestring("OTRC", LOCAL2_OP); + acpigen_write_if(); + acpigen_emit_byte(LNOT_OP); + acpigen_emit_byte(LEQUAL_OP); + acpigen_emit_byte(LOCAL1_OP); + acpigen_emit_byte(LOCAL2_OP); + acpigen_write_to_integer_from_namestring("RETE", LOCAL3_OP); + acpigen_write_store_int_to_op(OSC_RET_CAPABILITIES_MASKED, LOCAL4_OP); + acpigen_write_or(LOCAL3_OP, LOCAL4_OP, LOCAL3_OP); + acpigen_write_store_op_to_namestr(LOCAL3_OP, "RETE"); + acpigen_write_if_end(); +}; + +__weak unsigned long get_supported_pci_host_bridge_features(const struct device *domain) +{ + return 0; +} + +__weak unsigned long get_supported_cxl_host_bridge_features(const struct device *domain) +{ + return 0; +} diff --git a/src/soc/intel/xeon_sp/gnr/soc_acpi.c b/src/soc/intel/xeon_sp/gnr/soc_acpi.c index ab4328a..fc83f09 100644 --- a/src/soc/intel/xeon_sp/gnr/soc_acpi.c +++ b/src/soc/intel/xeon_sp/gnr/soc_acpi.c @@ -95,6 +95,15 @@ acpigen_write_string(name);
/* + * Method (_OSC, 4, NotSerialized) + * { + */ + soc_acpigen_write_OSC(domain); + /* + * } + */ + + /* * } //Device * } //Scope */ @@ -103,3 +112,13 @@
return; } + +unsigned long get_supported_pci_host_bridge_features(const struct device *domain) +{ + return 0; +} + +unsigned long get_supported_cxl_host_bridge_features(const struct device *domain) +{ + return 0; +} diff --git a/src/soc/intel/xeon_sp/include/soc/acpi.h b/src/soc/intel/xeon_sp/include/soc/acpi.h index e374544..367dc25 100644 --- a/src/soc/intel/xeon_sp/include/soc/acpi.h +++ b/src/soc/intel/xeon_sp/include/soc/acpi.h @@ -25,4 +25,8 @@
void iio_domain_set_acpi_name(struct device *dev, const char *prefix);
+void soc_acpigen_write_OSC(const struct device *domain); +unsigned long get_supported_pci_host_bridge_features(const struct device *domain); +unsigned long get_supported_cxl_host_bridge_features(const struct device *domain); + #endif /* _SOC_ACPI_H_ */