~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/skylake/skl-sst-dsp.c

Version: ~ [ linux-5.10-rc1 ] ~ [ linux-5.9.1 ] ~ [ linux-5.8.16 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.72 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.152 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.202 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.240 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.240 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * skl-sst-dsp.c - SKL SST library generic function
  4  *
  5  * Copyright (C) 2014-15, Intel Corporation.
  6  * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
  7  *      Jeeja KP <jeeja.kp@intel.com>
  8  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  9  */
 10 #include <sound/pcm.h>
 11 
 12 #include "../common/sst-dsp.h"
 13 #include "../common/sst-ipc.h"
 14 #include "../common/sst-dsp-priv.h"
 15 #include "skl.h"
 16 
 17 /* various timeout values */
 18 #define SKL_DSP_PU_TO           50
 19 #define SKL_DSP_PD_TO           50
 20 #define SKL_DSP_RESET_TO        50
 21 
 22 void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
 23 {
 24         mutex_lock(&ctx->mutex);
 25         ctx->sst_state = state;
 26         mutex_unlock(&ctx->mutex);
 27 }
 28 
 29 /*
 30  * Initialize core power state and usage count. To be called after
 31  * successful first boot. Hence core 0 will be running and other cores
 32  * will be reset
 33  */
 34 void skl_dsp_init_core_state(struct sst_dsp *ctx)
 35 {
 36         struct skl_dev *skl = ctx->thread_context;
 37         int i;
 38 
 39         skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
 40         skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
 41 
 42         for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
 43                 skl->cores.state[i] = SKL_DSP_RESET;
 44                 skl->cores.usage_count[i] = 0;
 45         }
 46 }
 47 
 48 /* Get the mask for all enabled cores */
 49 unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx)
 50 {
 51         struct skl_dev *skl = ctx->thread_context;
 52         unsigned int core_mask, en_cores_mask;
 53         u32 val;
 54 
 55         core_mask = SKL_DSP_CORES_MASK(skl->cores.count);
 56 
 57         val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
 58 
 59         /* Cores having CPA bit set */
 60         en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >>
 61                         SKL_ADSPCS_CPA_SHIFT;
 62 
 63         /* And cores having CRST bit cleared */
 64         en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >>
 65                         SKL_ADSPCS_CRST_SHIFT;
 66 
 67         /* And cores having CSTALL bit cleared */
 68         en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >>
 69                         SKL_ADSPCS_CSTALL_SHIFT;
 70         en_cores_mask &= core_mask;
 71 
 72         dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask);
 73 
 74         return en_cores_mask;
 75 }
 76 
 77 static int
 78 skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
 79 {
 80         int ret;
 81 
 82         /* update bits */
 83         sst_dsp_shim_update_bits_unlocked(ctx,
 84                         SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask),
 85                         SKL_ADSPCS_CRST_MASK(core_mask));
 86 
 87         /* poll with timeout to check if operation successful */
 88         ret = sst_dsp_register_poll(ctx,
 89                         SKL_ADSP_REG_ADSPCS,
 90                         SKL_ADSPCS_CRST_MASK(core_mask),
 91                         SKL_ADSPCS_CRST_MASK(core_mask),
 92                         SKL_DSP_RESET_TO,
 93                         "Set reset");
 94         if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
 95                                 SKL_ADSPCS_CRST_MASK(core_mask)) !=
 96                                 SKL_ADSPCS_CRST_MASK(core_mask)) {
 97                 dev_err(ctx->dev, "Set reset state failed: core_mask %x\n",
 98                                                         core_mask);
 99                 ret = -EIO;
100         }
101 
102         return ret;
103 }
104 
105 int skl_dsp_core_unset_reset_state(
106                 struct sst_dsp *ctx, unsigned int core_mask)
107 {
108         int ret;
109 
110         dev_dbg(ctx->dev, "In %s\n", __func__);
111 
112         /* update bits */
113         sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
114                                 SKL_ADSPCS_CRST_MASK(core_mask), 0);
115 
116         /* poll with timeout to check if operation successful */
117         ret = sst_dsp_register_poll(ctx,
118                         SKL_ADSP_REG_ADSPCS,
119                         SKL_ADSPCS_CRST_MASK(core_mask),
120                         0,
121                         SKL_DSP_RESET_TO,
122                         "Unset reset");
123 
124         if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
125                                 SKL_ADSPCS_CRST_MASK(core_mask)) != 0) {
126                 dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n",
127                                 core_mask);
128                 ret = -EIO;
129         }
130 
131         return ret;
132 }
133 
134 static bool
135 is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
136 {
137         int val;
138         bool is_enable;
139 
140         val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
141 
142         is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) &&
143                         (val & SKL_ADSPCS_SPA_MASK(core_mask)) &&
144                         !(val & SKL_ADSPCS_CRST_MASK(core_mask)) &&
145                         !(val & SKL_ADSPCS_CSTALL_MASK(core_mask)));
146 
147         dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n",
148                                                 is_enable, core_mask);
149 
150         return is_enable;
151 }
152 
153 static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
154 {
155         /* stall core */
156         sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
157                         SKL_ADSPCS_CSTALL_MASK(core_mask),
158                         SKL_ADSPCS_CSTALL_MASK(core_mask));
159 
160         /* set reset state */
161         return skl_dsp_core_set_reset_state(ctx, core_mask);
162 }
163 
164 int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
165 {
166         int ret;
167 
168         /* unset reset state */
169         ret = skl_dsp_core_unset_reset_state(ctx, core_mask);
170         if (ret < 0)
171                 return ret;
172 
173         /* run core */
174         dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask);
175         sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
176                         SKL_ADSPCS_CSTALL_MASK(core_mask), 0);
177 
178         if (!is_skl_dsp_core_enable(ctx, core_mask)) {
179                 skl_dsp_reset_core(ctx, core_mask);
180                 dev_err(ctx->dev, "DSP start core failed: core_mask %x\n",
181                                                         core_mask);
182                 ret = -EIO;
183         }
184 
185         return ret;
186 }
187 
188 int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
189 {
190         int ret;
191 
192         /* update bits */
193         sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
194                         SKL_ADSPCS_SPA_MASK(core_mask),
195                         SKL_ADSPCS_SPA_MASK(core_mask));
196 
197         /* poll with timeout to check if operation successful */
198         ret = sst_dsp_register_poll(ctx,
199                         SKL_ADSP_REG_ADSPCS,
200                         SKL_ADSPCS_CPA_MASK(core_mask),
201                         SKL_ADSPCS_CPA_MASK(core_mask),
202                         SKL_DSP_PU_TO,
203                         "Power up");
204 
205         if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
206                         SKL_ADSPCS_CPA_MASK(core_mask)) !=
207                         SKL_ADSPCS_CPA_MASK(core_mask)) {
208                 dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n",
209                                 core_mask);
210                 ret = -EIO;
211         }
212 
213         return ret;
214 }
215 
216 int skl_dsp_core_power_down(struct sst_dsp  *ctx, unsigned int core_mask)
217 {
218         /* update bits */
219         sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
220                                 SKL_ADSPCS_SPA_MASK(core_mask), 0);
221 
222         /* poll with timeout to check if operation successful */
223         return sst_dsp_register_poll(ctx,
224                         SKL_ADSP_REG_ADSPCS,
225                         SKL_ADSPCS_CPA_MASK(core_mask),
226                         0,
227                         SKL_DSP_PD_TO,
228                         "Power down");
229 }
230 
231 int skl_dsp_enable_core(struct sst_dsp  *ctx, unsigned int core_mask)
232 {
233         int ret;
234 
235         /* power up */
236         ret = skl_dsp_core_power_up(ctx, core_mask);
237         if (ret < 0) {
238                 dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n",
239                                                         core_mask);
240                 return ret;
241         }
242 
243         return skl_dsp_start_core(ctx, core_mask);
244 }
245 
246 int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
247 {
248         int ret;
249 
250         ret = skl_dsp_reset_core(ctx, core_mask);
251         if (ret < 0) {
252                 dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n",
253                                                         core_mask);
254                 return ret;
255         }
256 
257         /* power down core*/
258         ret = skl_dsp_core_power_down(ctx, core_mask);
259         if (ret < 0) {
260                 dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n",
261                                                         core_mask, ret);
262                 return ret;
263         }
264 
265         if (is_skl_dsp_core_enable(ctx, core_mask)) {
266                 dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n",
267                                                         core_mask, ret);
268                 ret = -EIO;
269         }
270 
271         return ret;
272 }
273 
274 int skl_dsp_boot(struct sst_dsp *ctx)
275 {
276         int ret;
277 
278         if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) {
279                 ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK);
280                 if (ret < 0) {
281                         dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret);
282                         return ret;
283                 }
284 
285                 ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
286                 if (ret < 0) {
287                         dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret);
288                         return ret;
289                 }
290         } else {
291                 ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
292                 if (ret < 0) {
293                         dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret);
294                         return ret;
295                 }
296                 ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
297         }
298 
299         return ret;
300 }
301 
302 irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
303 {
304         struct sst_dsp *ctx = dev_id;
305         u32 val;
306         irqreturn_t result = IRQ_NONE;
307 
308         spin_lock(&ctx->spinlock);
309 
310         val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
311         ctx->intr_status = val;
312 
313         if (val == 0xffffffff) {
314                 spin_unlock(&ctx->spinlock);
315                 return IRQ_NONE;
316         }
317 
318         if (val & SKL_ADSPIS_IPC) {
319                 skl_ipc_int_disable(ctx);
320                 result = IRQ_WAKE_THREAD;
321         }
322 
323         if (val & SKL_ADSPIS_CL_DMA) {
324                 skl_cldma_int_disable(ctx);
325                 result = IRQ_WAKE_THREAD;
326         }
327 
328         spin_unlock(&ctx->spinlock);
329 
330         return result;
331 }
332 /*
333  * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context
334  * within the dapm mutex. Hence no separate lock is used.
335  */
336 int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
337 {
338         struct skl_dev *skl = ctx->thread_context;
339         int ret = 0;
340 
341         if (core_id >= skl->cores.count) {
342                 dev_err(ctx->dev, "invalid core id: %d\n", core_id);
343                 return -EINVAL;
344         }
345 
346         skl->cores.usage_count[core_id]++;
347 
348         if (skl->cores.state[core_id] == SKL_DSP_RESET) {
349                 ret = ctx->fw_ops.set_state_D0(ctx, core_id);
350                 if (ret < 0) {
351                         dev_err(ctx->dev, "unable to get core%d\n", core_id);
352                         goto out;
353                 }
354         }
355 
356 out:
357         dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
358                         core_id, skl->cores.state[core_id],
359                         skl->cores.usage_count[core_id]);
360 
361         return ret;
362 }
363 EXPORT_SYMBOL_GPL(skl_dsp_get_core);
364 
365 int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id)
366 {
367         struct skl_dev *skl = ctx->thread_context;
368         int ret = 0;
369 
370         if (core_id >= skl->cores.count) {
371                 dev_err(ctx->dev, "invalid core id: %d\n", core_id);
372                 return -EINVAL;
373         }
374 
375         if ((--skl->cores.usage_count[core_id] == 0) &&
376                 (skl->cores.state[core_id] != SKL_DSP_RESET)) {
377                 ret = ctx->fw_ops.set_state_D3(ctx, core_id);
378                 if (ret < 0) {
379                         dev_err(ctx->dev, "unable to put core %d: %d\n",
380                                         core_id, ret);
381                         skl->cores.usage_count[core_id]++;
382                 }
383         }
384 
385         dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
386                         core_id, skl->cores.state[core_id],
387                         skl->cores.usage_count[core_id]);
388 
389         return ret;
390 }
391 EXPORT_SYMBOL_GPL(skl_dsp_put_core);
392 
393 int skl_dsp_wake(struct sst_dsp *ctx)
394 {
395         return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID);
396 }
397 EXPORT_SYMBOL_GPL(skl_dsp_wake);
398 
399 int skl_dsp_sleep(struct sst_dsp *ctx)
400 {
401         return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID);
402 }
403 EXPORT_SYMBOL_GPL(skl_dsp_sleep);
404 
405 struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
406                 struct sst_dsp_device *sst_dev, int irq)
407 {
408         int ret;
409         struct sst_dsp *sst;
410 
411         sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
412         if (sst == NULL)
413                 return NULL;
414 
415         spin_lock_init(&sst->spinlock);
416         mutex_init(&sst->mutex);
417         sst->dev = dev;
418         sst->sst_dev = sst_dev;
419         sst->irq = irq;
420         sst->ops = sst_dev->ops;
421         sst->thread_context = sst_dev->thread_context;
422 
423         /* Initialise SST Audio DSP */
424         if (sst->ops->init) {
425                 ret = sst->ops->init(sst);
426                 if (ret < 0)
427                         return NULL;
428         }
429 
430         return sst;
431 }
432 
433 int skl_dsp_acquire_irq(struct sst_dsp *sst)
434 {
435         struct sst_dsp_device *sst_dev = sst->sst_dev;
436         int ret;
437 
438         /* Register the ISR */
439         ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
440                 sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
441         if (ret)
442                 dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
443                                sst->irq);
444 
445         return ret;
446 }
447 
448 void skl_dsp_free(struct sst_dsp *dsp)
449 {
450         skl_ipc_int_disable(dsp);
451 
452         free_irq(dsp->irq, dsp);
453         skl_ipc_op_int_disable(dsp);
454         skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
455 }
456 EXPORT_SYMBOL_GPL(skl_dsp_free);
457 
458 bool is_skl_dsp_running(struct sst_dsp *ctx)
459 {
460         return (ctx->sst_state == SKL_DSP_RUNNING);
461 }
462 EXPORT_SYMBOL_GPL(is_skl_dsp_running);
463 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp