From 6e06df0c9891813d3323ff78961937b0caddc01b Mon Sep 17 00:00:00 2001 From: Jeremy Compostella Date: Fri, 13 Jun 2025 16:02:53 -0700 Subject: [PATCH] soc/intel/cmn/blk/cnvi: Add _PRR method for Bluetooth CNVi Reset [ Upstream commit 782ae11bc7ac6570cc0d8a27c62eaa6b393de105 ] The change introduces new Advanced Configuration and Power Interface (ACPI) methods to handle Bluetooth device states, including status checks and device reset procedures. Specifically, it adds a Power Resource for Reset (_PRR) method and the associated power resources to enable Operating System (OS)-level resets for Connectivity Integrated (CNVi) Bluetooth devices as specified in Intel document number 559910. This allows the OS to perform Bluetooth hardware recovery in case of errors, ensuring compliance with Intel's standards. The Power Resource ACPI code was adapted from Panther Lake (PTL) Firmware Support Package (FSP) revision 3144.01. The new ACPI Bluetooth code introduces the CNMT mutex, similar to the USB Bluetooth ACPI code, to avoid simultaneous CNVi resets when executing Wi-Fi and Bluetooth power resource _RST methods. TEST=The following two use cases were verified using acpidbg on a Fatcat device. 1. Test CNVi Bluetooth _RST() completion. acpidbg -b 'evaluate \_SB.PCI0.CNVB.PRRS' # 0x0 acpidbg -b 'evaluate \_SB.PCI0.CNVB.RSTT' # 0x0 acpidbg -b 'set N \_SB.PCI0.CNVB.RSTT 1' # 0x1 acpidbg -b 'evaluate \_SB.PCI0.CNVB.CNVP._RST' acpidbg -b 'evaluate \_SB.PCI0.CNVB.PRRS' # 0x2 2. Test that CNVi Wi-Fi _RST calls CNVi Bluetooth CFLR method. acpidbg -b 'evaluate \_SB.PCI0.CNVB.PRRS' # 0x0 acpidbg -b 'evaluate \_SB.PCI0.CNVW.RSTT' # 0x0 acpidbg -b 'set N \_SB.PCI0.CNVW.RSTT 1' # 0x0 acpidbg -b 'evaluate \_SB.PCI0.CNVW.CNVP._RST' acpidbg -b 'evaluate \_SB.PCI0.CNVB.PRRS' # 0x1 Change-Id: I2389901faf4fad131bb7226e356b47f4b1a4ddac Signed-off-by: Jeremy Compostella Reviewed-on: https://review.coreboot.org/c/coreboot/+/88111 Tested-by: build bot (Jenkins) Reviewed-by: Bora Guvendik Reviewed-by: Paul Menzel --- src/soc/intel/common/block/cnvi/cnvi.c | 313 +++++++++++++++++- .../common/block/include/intelblocks/cnvi.h | 4 +- 2 files changed, 315 insertions(+), 2 deletions(-) diff --git a/src/soc/intel/common/block/cnvi/cnvi.c b/src/soc/intel/common/block/cnvi/cnvi.c index d939738e48..153643d0f9 100644 --- a/src/soc/intel/common/block/cnvi/cnvi.c +++ b/src/soc/intel/common/block/cnvi/cnvi.c @@ -255,6 +255,12 @@ static void cnvw_fill_ssdt(const struct device *dev) } acpigen_pop_len(); + acpigen_write_if_cond_ref_of("\\_SB.PCI0.CNVB"); + { + acpigen_emit_namestring("\\_SB.PCI0.CNVB.CFLR"); + } + acpigen_pop_len(); + acpigen_emit_namestring("\\_SB.PCI0.PCRO"); acpigen_write_integer(CNVI_SIDEBAND_ID); acpigen_write_integer(CNVI_ABORT_PLDR); @@ -505,6 +511,311 @@ static const char *cnvi_bt_acpi_name(const struct device *dev) return "CNVB"; } +static void cnvb_fill_ssdt(const struct device *dev) +{ + const char *scope = acpi_device_path(dev); + +/* + * Mutex (CNMT, 0) + */ + acpigen_write_scope("\\_SB.PCI0"); + acpigen_write_mutex("CNMT", 0); + acpigen_write_scope_end(); + + acpi_device_write_pci_dev(dev); + + acpigen_write_scope(scope); + +/* + * OperationRegion (CBTR, SystemMemory, \_SB_.PCI0.BASE(_ADR), 0x100) + * Field (CBTR, WordAcc, NoLock, Preserve) { + * VDID, 32, // 0x00, VID DID + * Offset(R_CNVI_CFG_GIO_DEV_CAP), + * , 28, + * BFLR, 1, // Function Level Reset Capable + * Offset(R_CNVI_CFG_GIO_DEV), + * , 15, + * BIFR, 1, // Init Function Level Reset + * Offset (R_CNVI_CFG_GIO_DEV_CAP_2), + * , 11, + * BLTS, 1, // LTR Mechanism Supported + * Offset (R_CNVI_CFG_GIO_DEV_2), + * , 10, + * BLTE, 1, // LTR Mechanism Enable + * } + */ + + /* RegionOffset stored in Local0 */ + /* Local0 = \_SB_.PCI0.BASE(_ADR) */ + acpigen_write_store(); + acpigen_emit_namestring("BASE"); + acpigen_emit_namestring("_ADR"); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_emit_ext_op(OPREGION_OP); + acpigen_emit_namestring("CBTR"); + acpigen_emit_byte(SYSTEMMEMORY); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_integer(0x100); + + struct fieldlist fields[] = { + FIELDLIST_OFFSET(0), + FIELDLIST_NAMESTR("VDID", 32), + FIELDLIST_OFFSET(CNVI_DEV_CAP), + FIELDLIST_RESERVED(28), + FIELDLIST_NAMESTR("BFLR", 1), + FIELDLIST_OFFSET(CNVI_DEV_CONTROL), + FIELDLIST_RESERVED(15), + FIELDLIST_NAMESTR("BIFR", 1), + FIELDLIST_OFFSET(CNVI_DEV_CAP_2), + FIELDLIST_RESERVED(11), + FIELDLIST_NAMESTR("BLTS", 1), + FIELDLIST_OFFSET(CNVI_DEV_CONTROL_2), + FIELDLIST_RESERVED(10), + FIELDLIST_NAMESTR("BLTE", 1), + }; + acpigen_write_field("CBTR", fields, ARRAY_SIZE(fields), + FIELD_WORDACC | FIELD_NOLOCK | FIELD_PRESERVE); + +/* + * Name (_S0W, 3) + */ + acpigen_write_name_integer("_S0W", ACPI_DEVICE_SLEEP_D3_HOT); + +/* + * Name (PRRS, Zero) + * Last _PRR Status + * 0: Non-Platform-Level Device Reset (PLDR) executed [Default] + * 1: Core PLDR Completed successfully + * 2: Product PLDR Completed successfully + * 3: Previous PLDR Not Completed + * 4: Product PLDR timeout + */ + acpigen_write_name_integer("PRRS", 0); + +/* + * Name (RSTT, Zero) + * Reset Type + * 0: Core Reset + * 1: Product Reset + */ + acpigen_write_name_integer("RSTT", 0); + +/* + * Bluetooth PLDR request delay (default 50 ms) + */ + acpigen_write_name_integer("BTDL", 50); + +/* + * PowerResource (CNVP, 0x05, 0x0000) + * { + * Method (_STA, 0, NotSerialized) // _STA: Status + * { + * Return (One) + * } + * + * Method (_ON, 0, NotSerialized) // _ON_: Power On + * { + * } + * + * Method (_OFF, 0, NotSerialized) // _OFF: Power Off + * { + * } + * + * Method (_RST, 0, NotSerialized) // _RST: Device Reset + * { + * Local0 = Acquire (\_SB.PCI0.CNMT, 0x03E8) + * If ((Local0 == Zero)) + * { + * CFLR () + * If ((RSTT == One)) + * { + * Local0 = \_SB.PCI0.PCRR(PID_CNVI, CNVI_ABORT_PLDR) + * Local0 &= CNVI_ABORT_REQUEST + * If ((Local0 == Zero)) + * { + * \_SB.PCI0.PCRO (PID_CNVI, CNVI_ABORT_PLDR, 0x03) + * Sleep (BTDL) + * Local0 = \_SB.PCI0.PCRR(PID_CNVI, CNVI_ABORT_PLDR) + * Local1 = (Local0 & CNVI_ABORT_REQUEST) + * Local3 = (Local0 & CNVI_READY) + * If ((Local1 == Zero)) + * { + * If ((Local3 == CNVI_READY)) + * { + * PRRS = CNVI_PLDR_COMPLETE + * } + * } + * Else + * { + * PRRS = CNVI_PLDR_TIMEOUT + * } + * } + * Else + * { + * PRRS = CNVI_PLDR_NOT_COMPLETE + * } + * } + * + * If ((BLTS == One)) + * { + * If ((BLTE == Zero)) + * { + * BLTE = One + * } + * } + * + * Release (\_SB.PCI0.CNMT) + * } + * } + * } + */ + acpigen_write_power_res("CNVP", 5, 0, NULL, 0); + { + acpigen_write_method("_STA", 0); + { + acpigen_write_return_integer(1); + } + acpigen_pop_len(); + + acpigen_write_method("_ON", 0); + { + // Empty method body + } + acpigen_pop_len(); + + acpigen_write_method("_OFF", 0); + { + // Empty method body + } + acpigen_pop_len(); + + acpigen_write_method("_RST", 0); + { + acpigen_write_store(); + acpigen_write_acquire("\\_SB.PCI0.CNMT", 1000); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_write_if_lequal_op_int(LOCAL0_OP, 0); + { + acpigen_emit_namestring("CFLR"); + + acpigen_write_if_lequal_namestr_int("RSTT", 1); + { + acpigen_write_store(); + acpigen_emit_namestring("\\_SB.PCI0.PCRR"); + acpigen_write_integer(PID_CNVI); + acpigen_write_integer(CNVI_ABORT_PLDR); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_emit_byte(AND_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_integer(CNVI_ABORT_REQUEST); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_write_if_lequal_op_int(LOCAL0_OP, 0); + { + acpigen_emit_namestring("\\_SB.PCI0.PCRO"); + acpigen_write_integer(PID_CNVI); + acpigen_write_integer(CNVI_ABORT_PLDR); + acpigen_write_integer(CNVI_ABORT_REQUEST | CNVI_ABORT_ENABLE); + + acpigen_emit_ext_op(SLEEP_OP); + acpigen_emit_namestring("BTDL"); + + acpigen_write_store(); + acpigen_emit_namestring("\\_SB.PCI0.PCRR"); + acpigen_write_integer(PID_CNVI); + acpigen_write_integer(CNVI_ABORT_PLDR); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_emit_byte(AND_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_integer(CNVI_ABORT_REQUEST); + acpigen_emit_byte(LOCAL1_OP); + + acpigen_emit_byte(AND_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_integer(CNVI_READY); + acpigen_emit_byte(LOCAL3_OP); + + acpigen_write_if_lequal_op_int(LOCAL1_OP, 0); + { + acpigen_write_if_lequal_op_int(LOCAL3_OP, CNVI_READY); + { + acpigen_write_store_int_to_namestr(CNVI_PLDR_COMPLETE, "PRRS"); + } + acpigen_pop_len(); + } + acpigen_write_else(); + { + acpigen_write_store_int_to_namestr(CNVI_PLDR_TIMEOUT, "PRRS"); + } + acpigen_pop_len(); + } + acpigen_write_else(); + { + acpigen_write_store_int_to_namestr(CNVI_PLDR_NOT_COMPLETE, "PRRS"); + } + acpigen_pop_len(); + } + acpigen_pop_len(); + + acpigen_write_if_lequal_namestr_int("BLTS", 1); + { + acpigen_write_if_lequal_namestr_int("BLTE", 0); + { + acpigen_write_store_int_to_namestr(1, "BLTE"); + } + acpigen_pop_len(); + } + acpigen_pop_len(); + + acpigen_write_release("\\_SB.PCI0.CNMT"); + } + acpigen_pop_len(); + } + acpigen_pop_len(); + } + acpigen_write_power_res_end(); + +/* + * Name (_PRR, Package (0x01) // _PRR: Power Resource for Reset + * { + * CNVP + * }) +*/ + acpigen_write_name("_PRR"); + { + acpigen_write_package(1); + acpigen_emit_namestring("CNVP"); + } + acpigen_pop_len(); + +/* + * Method (CFLR, 0, NotSerialized) + * { + * If ((BFLR == One)) + * { + * BIFR = One + * PRRS = One + * } + * } +*/ + acpigen_write_method("CFLR", 0); + { + acpigen_write_if_lequal_namestr_int("BFLR", 1); + { + acpigen_write_store_int_to_namestr(1, "BIFR"); + acpigen_write_store_int_to_namestr(1, "PRRS"); + } + acpigen_pop_len(); + } + acpigen_pop_len(); + + acpigen_write_scope_end(); +} + static struct device_operations cnvi_bt_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -512,7 +823,7 @@ static struct device_operations cnvi_bt_ops = { .ops_pci = &pci_dev_ops_pci, .scan_bus = scan_static_bus, .acpi_name = cnvi_bt_acpi_name, - .acpi_fill_ssdt = acpi_device_write_pci_dev, + .acpi_fill_ssdt = cnvb_fill_ssdt, }; static const unsigned short bt_pci_device_ids[] = { diff --git a/src/soc/intel/common/block/include/intelblocks/cnvi.h b/src/soc/intel/common/block/include/intelblocks/cnvi.h index fa96fdd37d..a903941b2e 100644 --- a/src/soc/intel/common/block/include/intelblocks/cnvi.h +++ b/src/soc/intel/common/block/include/intelblocks/cnvi.h @@ -3,10 +3,12 @@ #ifndef _SOC_INTEL_COMMON_CNVI_H_ #define _SOC_INTEL_COMMON_CNVI_H_ -/* CNVi WiFi Register */ +/* CNVi PCI configuration Registers */ #define CNVI_DEV_CAP 0x44 #define CNVI_DEV_CONTROL 0x48 #define CNVI_POWER_STATUS 0xcc +#define CNVI_DEV_CAP_2 0x64 +#define CNVI_DEV_CONTROL_2 0x68 /* CNVi PLDR Results */ #define CNVI_PLDR_COMPLETE 0x02