397 lines · c
1// SPDX-License-Identifier: BSD-3-Clause-Clear2/*3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.4 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.5 */6 7#include "core.h"8#include "acpi.h"9#include "debug.h"10 11static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)12{13 union acpi_object *obj;14 acpi_handle root_handle;15 int ret;16 17 root_handle = ACPI_HANDLE(ab->dev);18 if (!root_handle) {19 ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid acpi handler\n");20 return -EOPNOTSUPP;21 }22 23 obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,24 NULL);25 26 if (!obj) {27 ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_evaluate_dsm() failed\n");28 return -ENOENT;29 }30 31 if (obj->type == ACPI_TYPE_INTEGER) {32 ab->acpi.func_bit = obj->integer.value;33 } else if (obj->type == ACPI_TYPE_BUFFER) {34 switch (func) {35 case ATH12K_ACPI_DSM_FUNC_TAS_CFG:36 if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {37 ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n",38 obj->buffer.length);39 ret = -EINVAL;40 goto out;41 }42 43 memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer,44 obj->buffer.length);45 46 break;47 case ATH12K_ACPI_DSM_FUNC_TAS_DATA:48 if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {49 ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n",50 obj->buffer.length);51 ret = -EINVAL;52 goto out;53 }54 55 memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer,56 obj->buffer.length);57 58 break;59 case ATH12K_ACPI_DSM_FUNC_BIOS_SAR:60 if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {61 ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n",62 obj->buffer.length);63 ret = -EINVAL;64 goto out;65 }66 67 memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer,68 obj->buffer.length);69 70 break;71 case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET:72 if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {73 ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n",74 obj->buffer.length);75 ret = -EINVAL;76 goto out;77 }78 79 memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer,80 obj->buffer.length);81 82 break;83 case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:84 if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {85 ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n",86 obj->buffer.length);87 ret = -EINVAL;88 goto out;89 }90 91 memcpy(&ab->acpi.cca_data, obj->buffer.pointer,92 obj->buffer.length);93 94 break;95 case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:96 if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {97 ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n",98 obj->buffer.length);99 ret = -EINVAL;100 goto out;101 }102 103 memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer,104 obj->buffer.length);105 106 break;107 }108 } else {109 ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n",110 obj->type);111 ret = -EINVAL;112 goto out;113 }114 115 ret = 0;116 117out:118 ACPI_FREE(obj);119 return ret;120}121 122static int ath12k_acpi_set_power_limit(struct ath12k_base *ab)123{124 const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table;125 int ret;126 127 if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION ||128 tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) {129 ath12k_warn(ab, "latest ACPI TAS data is invalid\n");130 return -EINVAL;131 }132 133 ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,134 tas_sar_power_table,135 ATH12K_ACPI_DSM_TAS_DATA_SIZE);136 if (ret) {137 ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret);138 return ret;139 }140 141 return ret;142}143 144static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab)145{146 int ret;147 148 if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION ||149 ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {150 ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n");151 return -EINVAL;152 }153 154 ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);155 if (ret) {156 ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);157 return ret;158 }159 160 return 0;161}162 163static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data)164{165 int ret;166 struct ath12k_base *ab = data;167 168 if (event == ATH12K_ACPI_NOTIFY_EVENT) {169 ath12k_warn(ab, "unknown acpi notify %u\n", event);170 return;171 }172 173 if (!ab->acpi.acpi_tas_enable) {174 ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n");175 return;176 }177 178 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);179 if (ret) {180 ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret);181 return;182 }183 184 ret = ath12k_acpi_set_power_limit(ab);185 if (ret) {186 ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret);187 return;188 }189 190 if (!ab->acpi.acpi_bios_sar_enable)191 return;192 193 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);194 if (ret) {195 ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret);196 return;197 }198 199 ret = ath12k_acpi_set_bios_sar_power(ab);200 if (ret) {201 ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret);202 return;203 }204}205 206static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab)207{208 int ret;209 210 ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data);211 if (ret) {212 ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret);213 return ret;214 }215 216 ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data);217 if (ret) {218 ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret);219 return ret;220 }221 222 return 0;223}224 225static int ath12k_acpi_set_tas_params(struct ath12k_base *ab)226{227 int ret;228 229 ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE,230 ab->acpi.tas_cfg,231 ATH12K_ACPI_DSM_TAS_CFG_SIZE);232 if (ret) {233 ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n",234 ret);235 return ret;236 }237 238 ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE,239 ab->acpi.tas_sar_power_table,240 ATH12K_ACPI_DSM_TAS_DATA_SIZE);241 if (ret) {242 ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n",243 ret);244 return ret;245 }246 247 return 0;248}249 250int ath12k_acpi_start(struct ath12k_base *ab)251{252 acpi_status status;253 u8 *buf;254 int ret;255 256 if (!ab->hw_params->acpi_guid)257 /* not supported with this hardware */258 return 0;259 260 ab->acpi.acpi_tas_enable = false;261 262 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS);263 if (ret) {264 ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret);265 return ret;266 }267 268 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {269 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG);270 if (ret) {271 ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret);272 return ret;273 }274 }275 276 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {277 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA);278 if (ret) {279 ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret);280 return ret;281 }282 283 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&284 ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&285 ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE)286 ab->acpi.acpi_tas_enable = true;287 }288 289 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {290 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR);291 if (ret) {292 ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret);293 return ret;294 }295 }296 297 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {298 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET);299 if (ret) {300 ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret);301 return ret;302 }303 304 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&305 ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&306 ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&307 !ab->acpi.acpi_tas_enable)308 ab->acpi.acpi_bios_sar_enable = true;309 }310 311 if (ab->acpi.acpi_tas_enable) {312 ret = ath12k_acpi_set_tas_params(ab);313 if (ret) {314 ath12k_warn(ab, "failed to send ACPI parameters: %d\n", ret);315 return ret;316 }317 }318 319 if (ab->acpi.acpi_bios_sar_enable) {320 ret = ath12k_acpi_set_bios_sar_params(ab);321 if (ret)322 return ret;323 }324 325 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) {326 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA);327 if (ret) {328 ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n",329 ret);330 return ret;331 }332 333 if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&334 ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==335 ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {336 buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;337 ret = ath12k_wmi_set_bios_cmd(ab,338 WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE,339 buf,340 ATH12K_ACPI_CCA_THR_OFFSET_LEN);341 if (ret) {342 ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n",343 ret);344 return ret;345 }346 }347 }348 349 if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi,350 ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {351 ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);352 if (ret) {353 ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n",354 ret);355 return ret;356 }357 358 if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&359 ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {360 ret = ath12k_wmi_set_bios_cmd(ab,361 WMI_BIOS_PARAM_TYPE_BANDEDGE,362 ab->acpi.band_edge_power,363 sizeof(ab->acpi.band_edge_power));364 if (ret) {365 ath12k_warn(ab,366 "failed to set ACPI DSM band edge channel power: %d\n",367 ret);368 return ret;369 }370 }371 }372 373 status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),374 ACPI_DEVICE_NOTIFY,375 ath12k_acpi_dsm_notify, ab);376 if (ACPI_FAILURE(status)) {377 ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status);378 return -EIO;379 }380 381 ab->acpi.started = true;382 383 return 0;384}385 386void ath12k_acpi_stop(struct ath12k_base *ab)387{388 if (!ab->acpi.started)389 return;390 391 acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),392 ACPI_DEVICE_NOTIFY,393 ath12k_acpi_dsm_notify);394 395 memset(&ab->acpi, 0, sizeof(ab->acpi));396}397