Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/*
  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}