diff --git a/src/drivers/wifi/generic/acpi.c b/src/drivers/wifi/generic/acpi.c index 7c53b247ab..753492abad 100644 --- a/src/drivers/wifi/generic/acpi.c +++ b/src/drivers/wifi/generic/acpi.c @@ -362,6 +362,89 @@ static void (*wifi_dsm2_callbacks[])(void *) = { wifi_dsm_set_prr_reset_delay, /* Function 5 */ }; +/* + * Function 5: Set Power Resource for Reset (PRR) mode for Bluetooth + * + * Args3 is a buffer comparable to the following C structure: + * struct pldr_mode { + * uint16_t cmd_type; + * uint16_t cmd_payload; + * }; + * + * cmd_type can take one of the following values: + * 1 - Set PRR mode to cmd_payload; + */ +static void bluetooth_dsm_set_power_resource_for_reset(__always_unused void *args) +{ + acpigen_write_create_word_field(ARG3_OP, 0, "BCMT"); + acpigen_write_create_word_field(ARG3_OP, 2, "BCMP"); + + /* Set PRR mode */ + acpigen_write_if_lequal_namestr_int("BCMT", 1); + { + acpigen_write_if_cond_ref_of("RSTT"); + { + acpigen_write_store(); + acpigen_emit_namestring("BCMP"); + acpigen_emit_namestring("RSTT"); + + } + acpigen_pop_len(); + } + acpigen_pop_len(); + + acpigen_write_return_integer(0); +} + +/* + * Function 6: Get Power Resource for Reset (PRR) mode and status for Bluetooth + */ +static void bluetooth_dsm_get_power_resource_for_reset(__always_unused void *args) +{ + /* Get PRR mode and status */ + acpigen_write_if_cond_ref_of("RSTT"); + { + acpigen_write_if_cond_ref_of("PRRS"); + { + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(2); + acpigen_emit_namestring("RSTT"); + acpigen_emit_namestring("PRRS"); + acpigen_pop_len(); + } + acpigen_pop_len(); + } + acpigen_pop_len(); + + acpigen_write_return_integer(0); +} + +/* + * Function 7: Set Power Resource for Reset (PRR) reset delay for Bluetooth + */ +static void bluetooth_dsm_set_prr_reset_delay(__always_unused void *args) +{ + acpigen_write_if_cond_ref_of("BTDL"); + { + acpigen_write_store(); + acpigen_emit_byte(ARG3_OP); + acpigen_emit_namestring("BTDL"); + } + acpigen_pop_len(); +} + + +static void (*bluetooth_dsm_callbacks[])(void *) = { + NULL, /* Function 0 */ + NULL, /* Function 1 */ + NULL, /* Function 2 */ + NULL, /* Function 3 */ + NULL, /* Function 4 */ + bluetooth_dsm_set_power_resource_for_reset, /* Function 5 */ + bluetooth_dsm_get_power_resource_for_reset, /* Function 6 */ + bluetooth_dsm_set_prr_reset_delay, /* Function 7 */ +}; + static const uint8_t *sar_fetch_set(const struct sar_profile *sar, size_t set_num) { const uint8_t *sar_table = &sar->sar_table[0]; @@ -1212,7 +1295,7 @@ static void wifi_ssdt_write_properties(const struct device *dev, const char *sco acpigen_write_scope_end(); /* Scope */ - /* Fill Bluetooth companion SAR related ACPI structures */ + /* Fill Bluetooth companion SAR related ACPI structures and DSM functions. */ if (sar_loaded && is_dev_enabled(config->bluetooth_companion)) { const char *path = acpi_device_path(config->bluetooth_companion); if (path) { /* Bluetooth device under USB Hub scope or PCIe root port */ @@ -1226,6 +1309,17 @@ static void wifi_ssdt_write_properties(const struct device *dev, const char *sco sar_emit_bdmm(sar_limits.bdmm); sar_emit_ebrd(sar_limits.ebrd); sar_emit_dsbr(sar_limits.dsbr, DOMAIN_TYPE_BLUETOOTH); + + if (config->bluetooth_companion->path.type == DEVICE_PATH_PCI && + config->bluetooth_companion->vendor == PCI_VID_INTEL) { + struct dsm_uuid bt_dsm_ids = { + .uuid = ACPI_DSM_RFIM_WIFI_UUID, + .callbacks = bluetooth_dsm_callbacks, + .count = ARRAY_SIZE(bluetooth_dsm_callbacks) + }; + acpigen_write_dsm_uuid_arr(&bt_dsm_ids, 1); + } + acpigen_write_scope_end(); } else { printk(BIOS_ERR, "Failed to get %s Bluetooth companion ACPI path\n",