1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
9 #include <linux/module.h>
10 #include <sound/hdaudio_ext.h>
12 #include "registers.h"
15 #define AVS_ADSPCS_INTERVAL_US 500
16 #define AVS_ADSPCS_TIMEOUT_US 50000
18 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
23 value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
24 trace_avs_dsp_core_op(value, core_mask, "power", power);
26 mask = AVS_ADSPCS_SPA_MASK(core_mask);
27 value = power ? mask : 0;
29 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
31 mask = AVS_ADSPCS_CPA_MASK(core_mask);
32 value = power ? mask : 0;
34 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
35 reg, (reg & mask) == value,
36 AVS_ADSPCS_INTERVAL_US,
37 AVS_ADSPCS_TIMEOUT_US);
39 dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
40 core_mask, power ? "on" : "off", ret);
45 int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset)
50 value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
51 trace_avs_dsp_core_op(value, core_mask, "reset", reset);
53 mask = AVS_ADSPCS_CRST_MASK(core_mask);
54 value = reset ? mask : 0;
56 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
58 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
59 reg, (reg & mask) == value,
60 AVS_ADSPCS_INTERVAL_US,
61 AVS_ADSPCS_TIMEOUT_US);
63 dev_err(adev->dev, "core_mask %d %s reset failed: %d\n",
64 core_mask, reset ? "enter" : "exit", ret);
69 int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
74 value = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPCS);
75 trace_avs_dsp_core_op(value, core_mask, "stall", stall);
77 mask = AVS_ADSPCS_CSTALL_MASK(core_mask);
78 value = stall ? mask : 0;
80 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
82 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS,
83 reg, (reg & mask) == value,
84 AVS_ADSPCS_INTERVAL_US,
85 AVS_ADSPCS_TIMEOUT_US);
87 dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
88 core_mask, stall ? "" : "un", ret);
93 int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
97 ret = avs_dsp_op(adev, power, core_mask, true);
101 ret = avs_dsp_op(adev, reset, core_mask, false);
105 return avs_dsp_op(adev, stall, core_mask, false);
108 int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
110 /* No error checks to allow for complete DSP shutdown. */
111 avs_dsp_op(adev, stall, core_mask, true);
112 avs_dsp_op(adev, reset, core_mask, true);
114 return avs_dsp_op(adev, power, core_mask, false);
117 static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
122 ret = avs_dsp_core_enable(adev, core_mask);
126 mask = core_mask & ~AVS_MAIN_CORE_MASK;
129 * without main core, fw is dead anyway
130 * so setting D0 for it is futile.
134 ret = avs_ipc_set_dx(adev, mask, true);
135 return AVS_IPC_RET(ret);
138 static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
142 ret = avs_ipc_set_dx(adev, core_mask, false);
144 return AVS_IPC_RET(ret);
146 return avs_dsp_core_disable(adev, core_mask);
149 static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
154 mask = BIT_MASK(core_id);
155 if (mask == AVS_MAIN_CORE_MASK)
156 /* nothing to do for main core */
158 if (core_id >= adev->hw_cfg.dsp_cores) {
163 adev->core_refs[core_id]++;
164 if (adev->core_refs[core_id] == 1) {
166 * No cores other than main-core can be running for DSP
167 * to achieve d0ix. Conscious SET_D0IX IPC failure is permitted,
168 * simply d0ix power state will no longer be attempted.
170 ret = avs_dsp_disable_d0ix(adev);
171 if (ret && ret != -AVS_EIPC)
172 goto err_disable_d0ix;
174 ret = avs_dsp_enable(adev, mask);
182 avs_dsp_enable_d0ix(adev);
184 adev->core_refs[core_id]--;
186 dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
190 static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
195 mask = BIT_MASK(core_id);
196 if (mask == AVS_MAIN_CORE_MASK)
197 /* nothing to do for main core */
199 if (core_id >= adev->hw_cfg.dsp_cores) {
204 adev->core_refs[core_id]--;
205 if (!adev->core_refs[core_id]) {
206 ret = avs_dsp_disable(adev, mask);
210 /* Match disable_d0ix in avs_dsp_get_core(). */
211 avs_dsp_enable_d0ix(adev);
216 dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
220 int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
221 u8 core_id, u8 domain, void *param, u32 param_size,
224 struct avs_module_entry mentry;
225 bool was_loaded = false;
228 id = avs_module_id_alloc(adev, module_id);
232 ret = avs_get_module_id_entry(adev, module_id, &mentry);
236 ret = avs_dsp_get_core(adev, core_id);
240 /* Load code into memory if this is the first instance. */
241 if (!id && !avs_module_entry_is_loaded(&mentry)) {
242 ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1);
244 dev_err(adev->dev, "load modules failed: %d\n", ret);
250 ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
251 core_id, domain, param, param_size);
253 ret = AVS_IPC_RET(ret);
262 avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
263 avs_dsp_put_core(adev, core_id);
265 avs_module_id_free(adev, module_id, id);
269 void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
270 u8 ppl_instance_id, u8 core_id)
272 struct avs_module_entry mentry;
275 /* Modules not owned by any pipeline need to be freed explicitly. */
276 if (ppl_instance_id == INVALID_PIPELINE_ID)
277 avs_ipc_delete_instance(adev, module_id, instance_id);
279 avs_module_id_free(adev, module_id, instance_id);
281 ret = avs_get_module_id_entry(adev, module_id, &mentry);
282 /* Unload occupied memory if this was the last instance. */
283 if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) {
284 if (avs_is_module_ida_empty(adev, module_id)) {
285 ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
287 dev_err(adev->dev, "unload modules failed: %d\n", ret);
291 avs_dsp_put_core(adev, core_id);
294 int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
295 bool lp, u16 attributes, u8 *instance_id)
297 struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
300 id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
304 ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes);
306 ida_free(&adev->ppl_ida, id);
307 return AVS_IPC_RET(ret);
314 int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
318 ret = avs_ipc_delete_pipeline(adev, instance_id);
320 ret = AVS_IPC_RET(ret);
322 ida_free(&adev->ppl_ida, instance_id);
326 MODULE_LICENSE("GPL");