arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / soc / intel / avs / dsp.c
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
18 int 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
47 int 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
71 int 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
99 int 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
114 int 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
123 static 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
144 static 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
155 static 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
187 err_enable_dsp:
188         avs_dsp_enable_d0ix(adev);
189 err_disable_d0ix:
190         adev->core_refs[core_id]--;
191 err:
192         dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
193         return ret;
194 }
195
196 static 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;
221 err:
222         dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
223         return ret;
224 }
225
226 int 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
266 err_ipc:
267         if (was_loaded)
268                 avs_dsp_op(adev, transfer_mods, false, &mentry, 1);
269         avs_dsp_put_core(adev, core_id);
270 err_mod_entry:
271         avs_module_id_free(adev, module_id, id);
272         return ret;
273 }
274
275 void 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
300 int 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
320 int 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 }