Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright(c) 2021-2022 Intel Corporation
  4//
  5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
  6//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  7//
  8
  9#include <sound/hdaudio_ext.h>
 10#include "avs.h"
 11#include "registers.h"
 12#include "trace.h"
 13
 14#define AVS_ADSPCS_INTERVAL_US		500
 15#define AVS_ADSPCS_TIMEOUT_US		50000
 16#define AVS_ADSPCS_DELAY_US		1000
 17
 18int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
 19{
 20	u32 value, mask, reg;
 21	int ret;
 22
 23	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 24	trace_avs_dsp_core_op(value, core_mask, "power", power);
 25
 26	mask = AVS_ADSPCS_SPA_MASK(core_mask);
 27	value = power ? mask : 0;
 28
 29	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 30	/* Delay the polling to avoid false positives. */
 31	usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
 32
 33	mask = AVS_ADSPCS_CPA_MASK(core_mask);
 34	value = power ? mask : 0;
 35
 36	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 37				       reg, (reg & mask) == value,
 38				       AVS_ADSPCS_INTERVAL_US,
 39				       AVS_ADSPCS_TIMEOUT_US);
 40	if (ret)
 41		dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
 42			core_mask, power ? "on" : "off", ret);
 43
 44	return ret;
 45}
 46
 47int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
 48{
 49	u32 value, mask, reg;
 50	int ret;
 51
 52	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 53	trace_avs_dsp_core_op(value, core_mask, "reset", reset);
 54
 55	mask = AVS_ADSPCS_CRST_MASK(core_mask);
 56	value = reset ? mask : 0;
 57
 58	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 59
 60	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 61				       reg, (reg & mask) == value,
 62				       AVS_ADSPCS_INTERVAL_US,
 63				       AVS_ADSPCS_TIMEOUT_US);
 64	if (ret)
 65		dev_err(adev->dev, "core_mask %d %s reset failed: %d\n",
 66			core_mask, reset ? "enter" : "exit", ret);
 67
 68	return ret;
 69}
 70
 71int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
 72{
 73	u32 value, mask, reg;
 74	int ret;
 75
 76	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 77	trace_avs_dsp_core_op(value, core_mask, "stall", stall);
 78
 79	mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
 80	value = stall ? mask : 0;
 81
 82	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 83
 84	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 85				       reg, (reg & mask) == value,
 86				       AVS_ADSPCS_INTERVAL_US,
 87				       AVS_ADSPCS_TIMEOUT_US);
 88	if (ret) {
 89		dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
 90			core_mask, stall ? "" : "un", ret);
 91		return ret;
 92	}
 93
 94	/* Give HW time to propagate the change. */
 95	usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
 96	return 0;
 97}
 98
 99int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
100{
101	int ret;
102
103	ret = avs_dsp_op(adev, power, core_mask, true);
104	if (ret)
105		return ret;
106
107	ret = avs_dsp_op(adev, reset, core_mask, false);
108	if (ret)
109		return ret;
110
111	return avs_dsp_op(adev, stall, core_mask, false);
112}
113
114int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
115{
116	/* No error checks to allow for complete DSP shutdown. */
117	avs_dsp_op(adev, stall, core_mask, true);
118	avs_dsp_op(adev, reset, core_mask, true);
119
120	return avs_dsp_op(adev, power, core_mask, false);
121}
122
123static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
124{
125	u32 mask;
126	int ret;
127
128	ret = avs_dsp_core_enable(adev, core_mask);
129	if (ret < 0)
130		return ret;
131
132	mask = core_mask & ~AVS_MAIN_CORE_MASK;
133	if (!mask)
134		/*
135		 * without main core, fw is dead anyway
136		 * so setting D0 for it is futile.
137		 */
138		return 0;
139
140	ret = avs_ipc_set_dx(adev, mask, true);
141	return AVS_IPC_RET(ret);
142}
143
144static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
145{
146	int ret;
147
148	ret = avs_ipc_set_dx(adev, core_mask, false);
149	if (ret)
150		return AVS_IPC_RET(ret);
151
152	return avs_dsp_core_disable(adev, core_mask);
153}
154
155static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
156{
157	u32 mask;
158	int ret;
159
160	mask = BIT_MASK(core_id);
161	if (mask == AVS_MAIN_CORE_MASK)
162		/* nothing to do for main core */
163		return 0;
164	if (core_id >= adev->hw_cfg.dsp_cores) {
165		ret = -EINVAL;
166		goto err;
167	}
168
169	adev->core_refs[core_id]++;
170	if (adev->core_refs[core_id] == 1) {
171		/*
172		 * No cores other than main-core can be running for DSP
173		 * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted,
174		 * simply d0ix power state will no longer be attempted.
175		 */
176		ret = avs_dsp_disable_d0ix(adev);
177		if (ret && ret != -AVS_EIPC)
178			goto err_disable_d0ix;
179
180		ret = avs_dsp_enable(adev, mask);
181		if (ret)
182			goto err_enable_dsp;
183	}
184
185	return 0;
186
187err_enable_dsp:
188	avs_dsp_enable_d0ix(adev);
189err_disable_d0ix:
190	adev->core_refs[core_id]--;
191err:
192	dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
193	return ret;
194}
195
196static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
197{
198	u32 mask;
199	int ret;
200
201	mask = BIT_MASK(core_id);
202	if (mask == AVS_MAIN_CORE_MASK)
203		/* nothing to do for main core */
204		return 0;
205	if (core_id >= adev->hw_cfg.dsp_cores) {
206		ret = -EINVAL;
207		goto err;
208	}
209
210	adev->core_refs[core_id]--;
211	if (!adev->core_refs[core_id]) {
212		ret = avs_dsp_disable(adev, mask);
213		if (ret)
214			goto err;
215
216		/* Match disable_d0ix in avs_dsp_get_core(). */
217		avs_dsp_enable_d0ix(adev);
218	}
219
220	return 0;
221err:
222	dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
223	return ret;
224}
225
226int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
227			u8 core_id, u8 domain, void *param, u32 param_size,
228			u8 *instance_id)
229{
230	struct avs_module_entry mentry;
231	bool was_loaded = false;
232	int ret, id;
233
234	id = avs_module_id_alloc(adev, module_id);
235	if (id < 0)
236		return id;
237
238	ret = avs_get_module_id_entry(adev, module_id, &mentry);
239	if (ret)
240		goto err_mod_entry;
241
242	ret = avs_dsp_get_core(adev, core_id);
243	if (ret)
244		goto err_mod_entry;
245
246	/* Load code into memory if this is the first instance. */
247	if (!id && !avs_module_entry_is_loaded(&mentry)) {
248		ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1);
249		if (ret) {
250			dev_err(adev->dev, "load modules failed: %d\n", ret);
251			goto err_mod_entry;
252		}
253		was_loaded = true;
254	}
255
256	ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
257				    core_id, domain, param, param_size);
258	if (ret) {
259		ret = AVS_IPC_RET(ret);
260		goto err_ipc;
261	}
262
263	*instance_id = id;
264	return 0;
265
266err_ipc:
267	if (was_loaded)
268		avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
269	avs_dsp_put_core(adev, core_id);
270err_mod_entry:
271	avs_module_id_free(adev, module_id, id);
272	return ret;
273}
274
275void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
276			   u8 ppl_instance_id, u8 core_id)
277{
278	struct avs_module_entry mentry;
279	int ret;
280
281	/* Modules not owned by any pipeline need to be freed explicitly. */
282	if (ppl_instance_id == INVALID_PIPELINE_ID)
283		avs_ipc_delete_instance(adev, module_id, instance_id);
284
285	avs_module_id_free(adev, module_id, instance_id);
286
287	ret = avs_get_module_id_entry(adev, module_id, &mentry);
288	/* Unload occupied memory if this was the last instance. */
289	if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) {
290		if (avs_is_module_ida_empty(adev, module_id)) {
291			ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
292			if (ret)
293				dev_err(adev->dev, "unload modules failed: %d\n", ret);
294		}
295	}
296
297	avs_dsp_put_core(adev, core_id);
298}
299
300int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
301			    bool lp, u16 attributes, u8 *instance_id)
302{
303	struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
304	int ret, id;
305
306	id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
307	if (id < 0)
308		return id;
309
310	ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes);
311	if (ret) {
312		ida_free(&adev->ppl_ida, id);
313		return AVS_IPC_RET(ret);
314	}
315
316	*instance_id = id;
317	return 0;
318}
319
320int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
321{
322	int ret;
323
324	ret = avs_ipc_delete_pipeline(adev, instance_id);
325	if (ret)
326		ret = AVS_IPC_RET(ret);
327
328	ida_free(&adev->ppl_ida, instance_id);
329	return ret;
330}
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
  4//
  5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
  6//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  7//
  8
  9#include <sound/hdaudio_ext.h>
 10#include "avs.h"
 11#include "registers.h"
 12#include "trace.h"
 13
 14#define AVS_ADSPCS_INTERVAL_US		500
 15#define AVS_ADSPCS_TIMEOUT_US		50000
 16#define AVS_ADSPCS_DELAY_US		1000
 17
 18int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
 19{
 20	u32 value, mask, reg;
 21	int ret;
 22
 23	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 24	trace_avs_dsp_core_op(value, core_mask, "power", power);
 25
 26	mask = AVS_ADSPCS_SPA_MASK(core_mask);
 27	value = power ? mask : 0;
 28
 29	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 30	/* Delay the polling to avoid false positives. */
 31	usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
 32
 33	mask = AVS_ADSPCS_CPA_MASK(core_mask);
 34	value = power ? mask : 0;
 35
 36	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 37				       reg, (reg & mask) == value,
 38				       AVS_ADSPCS_INTERVAL_US,
 39				       AVS_ADSPCS_TIMEOUT_US);
 40	if (ret)
 41		dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
 42			core_mask, power ? "on" : "off", ret);
 43
 44	return ret;
 45}
 46
 47int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
 48{
 49	u32 value, mask, reg;
 50	int ret;
 51
 52	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 53	trace_avs_dsp_core_op(value, core_mask, "reset", reset);
 54
 55	mask = AVS_ADSPCS_CRST_MASK(core_mask);
 56	value = reset ? mask : 0;
 57
 58	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 59
 60	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 61				       reg, (reg & mask) == value,
 62				       AVS_ADSPCS_INTERVAL_US,
 63				       AVS_ADSPCS_TIMEOUT_US);
 64	if (ret)
 65		dev_err(adev->dev, "core_mask %d %s reset failed: %d\n",
 66			core_mask, reset ? "enter" : "exit", ret);
 67
 68	return ret;
 69}
 70
 71int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
 72{
 73	u32 value, mask, reg;
 74	int ret;
 75
 76	value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
 77	trace_avs_dsp_core_op(value, core_mask, "stall", stall);
 78
 79	mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
 80	value = stall ? mask : 0;
 81
 82	snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
 83
 84	ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
 85				       reg, (reg & mask) == value,
 86				       AVS_ADSPCS_INTERVAL_US,
 87				       AVS_ADSPCS_TIMEOUT_US);
 88	if (ret) {
 89		dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
 90			core_mask, stall ? "" : "un", ret);
 91		return ret;
 92	}
 93
 94	/* Give HW time to propagate the change. */
 95	usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
 96	return 0;
 97}
 98
 99int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
100{
101	int ret;
102
103	ret = avs_dsp_op(adev, power, core_mask, true);
104	if (ret)
105		return ret;
106
107	ret = avs_dsp_op(adev, reset, core_mask, false);
108	if (ret)
109		return ret;
110
111	return avs_dsp_op(adev, stall, core_mask, false);
112}
113
114int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
115{
116	/* No error checks to allow for complete DSP shutdown. */
117	avs_dsp_op(adev, stall, core_mask, true);
118	avs_dsp_op(adev, reset, core_mask, true);
119
120	return avs_dsp_op(adev, power, core_mask, false);
121}
122
123static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
124{
125	u32 mask;
126	int ret;
127
128	ret = avs_dsp_core_enable(adev, core_mask);
129	if (ret < 0)
130		return ret;
131
132	mask = core_mask & ~AVS_MAIN_CORE_MASK;
133	if (!mask)
134		/*
135		 * without main core, fw is dead anyway
136		 * so setting D0 for it is futile.
137		 */
138		return 0;
139
140	ret = avs_ipc_set_dx(adev, mask, true);
141	return AVS_IPC_RET(ret);
142}
143
144static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
145{
146	int ret;
147
148	ret = avs_ipc_set_dx(adev, core_mask, false);
149	if (ret)
150		return AVS_IPC_RET(ret);
151
152	return avs_dsp_core_disable(adev, core_mask);
153}
154
155static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
156{
157	u32 mask;
158	int ret;
159
160	mask = BIT_MASK(core_id);
161	if (mask == AVS_MAIN_CORE_MASK)
162		/* nothing to do for main core */
163		return 0;
164	if (core_id >= adev->hw_cfg.dsp_cores) {
165		ret = -EINVAL;
166		goto err;
167	}
168
169	adev->core_refs[core_id]++;
170	if (adev->core_refs[core_id] == 1) {
171		/*
172		 * No cores other than main-core can be running for DSP
173		 * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted,
174		 * simply d0ix power state will no longer be attempted.
175		 */
176		ret = avs_dsp_disable_d0ix(adev);
177		if (ret && ret != -AVS_EIPC)
178			goto err_disable_d0ix;
179
180		ret = avs_dsp_enable(adev, mask);
181		if (ret)
182			goto err_enable_dsp;
183	}
184
185	return 0;
186
187err_enable_dsp:
188	avs_dsp_enable_d0ix(adev);
189err_disable_d0ix:
190	adev->core_refs[core_id]--;
191err:
192	dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
193	return ret;
194}
195
196static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
197{
198	u32 mask;
199	int ret;
200
201	mask = BIT_MASK(core_id);
202	if (mask == AVS_MAIN_CORE_MASK)
203		/* nothing to do for main core */
204		return 0;
205	if (core_id >= adev->hw_cfg.dsp_cores) {
206		ret = -EINVAL;
207		goto err;
208	}
209
210	adev->core_refs[core_id]--;
211	if (!adev->core_refs[core_id]) {
212		ret = avs_dsp_disable(adev, mask);
213		if (ret)
214			goto err;
215
216		/* Match disable_d0ix in avs_dsp_get_core(). */
217		avs_dsp_enable_d0ix(adev);
218	}
219
220	return 0;
221err:
222	dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
223	return ret;
224}
225
226int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
227			u8 core_id, u8 domain, void *param, u32 param_size,
228			u8 *instance_id)
229{
230	struct avs_module_entry mentry;
231	bool was_loaded = false;
232	int ret, id;
233
234	id = avs_module_id_alloc(adev, module_id);
235	if (id < 0)
236		return id;
237
238	ret = avs_get_module_id_entry(adev, module_id, &mentry);
239	if (ret)
240		goto err_mod_entry;
241
242	ret = avs_dsp_get_core(adev, core_id);
243	if (ret)
244		goto err_mod_entry;
245
246	/* Load code into memory if this is the first instance. */
247	if (!id && !avs_module_entry_is_loaded(&mentry)) {
248		ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1);
249		if (ret) {
250			dev_err(adev->dev, "load modules failed: %d\n", ret);
251			goto err_mod_entry;
252		}
253		was_loaded = true;
254	}
255
256	ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
257				    core_id, domain, param, param_size);
258	if (ret) {
259		ret = AVS_IPC_RET(ret);
260		goto err_ipc;
261	}
262
263	*instance_id = id;
264	return 0;
265
266err_ipc:
267	if (was_loaded)
268		avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
269	avs_dsp_put_core(adev, core_id);
270err_mod_entry:
271	avs_module_id_free(adev, module_id, id);
272	return ret;
273}
274
275void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
276			   u8 ppl_instance_id, u8 core_id)
277{
278	struct avs_module_entry mentry;
279	int ret;
280
281	/* Modules not owned by any pipeline need to be freed explicitly. */
282	if (ppl_instance_id == INVALID_PIPELINE_ID)
283		avs_ipc_delete_instance(adev, module_id, instance_id);
284
285	avs_module_id_free(adev, module_id, instance_id);
286
287	ret = avs_get_module_id_entry(adev, module_id, &mentry);
288	/* Unload occupied memory if this was the last instance. */
289	if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) {
290		if (avs_is_module_ida_empty(adev, module_id)) {
291			ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
292			if (ret)
293				dev_err(adev->dev, "unload modules failed: %d\n", ret);
294		}
295	}
296
297	avs_dsp_put_core(adev, core_id);
298}
299
300int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
301			    bool lp, u16 attributes, u8 *instance_id)
302{
303	struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
304	int ret, id;
305
306	id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
307	if (id < 0)
308		return id;
309
310	ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes);
311	if (ret) {
312		ida_free(&adev->ppl_ida, id);
313		return AVS_IPC_RET(ret);
314	}
315
316	*instance_id = id;
317	return 0;
318}
319
320int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
321{
322	int ret;
323
324	ret = avs_ipc_delete_pipeline(adev, instance_id);
325	if (ret)
326		ret = AVS_IPC_RET(ret);
327
328	ida_free(&adev->ppl_ida, instance_id);
329	return ret;
330}