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