2 * skl-sst-dsp.c - SKL SST library generic function
4 * Copyright (C) 2014-15, Intel Corporation.
5 * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
6 * Jeeja KP <jeeja.kp@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as version 2, as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 #include <sound/pcm.h>
20 #include "../common/sst-dsp.h"
21 #include "../common/sst-ipc.h"
22 #include "../common/sst-dsp-priv.h"
23 #include "skl-sst-ipc.h"
25 /* various timeout values */
26 #define SKL_DSP_PU_TO 50
27 #define SKL_DSP_PD_TO 50
28 #define SKL_DSP_RESET_TO 50
30 void skl_dsp_set_state_locked(struct sst_dsp
*ctx
, int state
)
32 mutex_lock(&ctx
->mutex
);
33 ctx
->sst_state
= state
;
34 mutex_unlock(&ctx
->mutex
);
38 * Initialize core power state and usage count. To be called after
39 * successful first boot. Hence core 0 will be running and other cores
42 void skl_dsp_init_core_state(struct sst_dsp
*ctx
)
44 struct skl_sst
*skl
= ctx
->thread_context
;
47 skl
->cores
.state
[SKL_DSP_CORE0_ID
] = SKL_DSP_RUNNING
;
48 skl
->cores
.usage_count
[SKL_DSP_CORE0_ID
] = 1;
50 for (i
= SKL_DSP_CORE0_ID
+ 1; i
< SKL_DSP_CORES_MAX
; i
++) {
51 skl
->cores
.state
[i
] = SKL_DSP_RESET
;
52 skl
->cores
.usage_count
[i
] = 0;
56 /* Get the mask for all enabled cores */
57 unsigned int skl_dsp_get_enabled_cores(struct sst_dsp
*ctx
)
59 struct skl_sst
*skl
= ctx
->thread_context
;
60 unsigned int core_mask
, en_cores_mask
;
63 core_mask
= SKL_DSP_CORES_MASK(skl
->cores
.count
);
65 val
= sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
);
67 /* Cores having CPA bit set */
68 en_cores_mask
= (val
& SKL_ADSPCS_CPA_MASK(core_mask
)) >>
71 /* And cores having CRST bit cleared */
72 en_cores_mask
&= (~val
& SKL_ADSPCS_CRST_MASK(core_mask
)) >>
73 SKL_ADSPCS_CRST_SHIFT
;
75 /* And cores having CSTALL bit cleared */
76 en_cores_mask
&= (~val
& SKL_ADSPCS_CSTALL_MASK(core_mask
)) >>
77 SKL_ADSPCS_CSTALL_SHIFT
;
78 en_cores_mask
&= core_mask
;
80 dev_dbg(ctx
->dev
, "DSP enabled cores mask = %x\n", en_cores_mask
);
86 skl_dsp_core_set_reset_state(struct sst_dsp
*ctx
, unsigned int core_mask
)
91 sst_dsp_shim_update_bits_unlocked(ctx
,
92 SKL_ADSP_REG_ADSPCS
, SKL_ADSPCS_CRST_MASK(core_mask
),
93 SKL_ADSPCS_CRST_MASK(core_mask
));
95 /* poll with timeout to check if operation successful */
96 ret
= sst_dsp_register_poll(ctx
,
98 SKL_ADSPCS_CRST_MASK(core_mask
),
99 SKL_ADSPCS_CRST_MASK(core_mask
),
102 if ((sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
) &
103 SKL_ADSPCS_CRST_MASK(core_mask
)) !=
104 SKL_ADSPCS_CRST_MASK(core_mask
)) {
105 dev_err(ctx
->dev
, "Set reset state failed: core_mask %x\n",
113 int skl_dsp_core_unset_reset_state(
114 struct sst_dsp
*ctx
, unsigned int core_mask
)
118 dev_dbg(ctx
->dev
, "In %s\n", __func__
);
121 sst_dsp_shim_update_bits_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
,
122 SKL_ADSPCS_CRST_MASK(core_mask
), 0);
124 /* poll with timeout to check if operation successful */
125 ret
= sst_dsp_register_poll(ctx
,
127 SKL_ADSPCS_CRST_MASK(core_mask
),
132 if ((sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
) &
133 SKL_ADSPCS_CRST_MASK(core_mask
)) != 0) {
134 dev_err(ctx
->dev
, "Unset reset state failed: core_mask %x\n",
143 is_skl_dsp_core_enable(struct sst_dsp
*ctx
, unsigned int core_mask
)
148 val
= sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
);
150 is_enable
= ((val
& SKL_ADSPCS_CPA_MASK(core_mask
)) &&
151 (val
& SKL_ADSPCS_SPA_MASK(core_mask
)) &&
152 !(val
& SKL_ADSPCS_CRST_MASK(core_mask
)) &&
153 !(val
& SKL_ADSPCS_CSTALL_MASK(core_mask
)));
155 dev_dbg(ctx
->dev
, "DSP core(s) enabled? %d : core_mask %x\n",
156 is_enable
, core_mask
);
161 static int skl_dsp_reset_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
164 sst_dsp_shim_update_bits_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
,
165 SKL_ADSPCS_CSTALL_MASK(core_mask
),
166 SKL_ADSPCS_CSTALL_MASK(core_mask
));
168 /* set reset state */
169 return skl_dsp_core_set_reset_state(ctx
, core_mask
);
172 int skl_dsp_start_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
176 /* unset reset state */
177 ret
= skl_dsp_core_unset_reset_state(ctx
, core_mask
);
182 dev_dbg(ctx
->dev
, "unstall/run core: core_mask = %x\n", core_mask
);
183 sst_dsp_shim_update_bits_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
,
184 SKL_ADSPCS_CSTALL_MASK(core_mask
), 0);
186 if (!is_skl_dsp_core_enable(ctx
, core_mask
)) {
187 skl_dsp_reset_core(ctx
, core_mask
);
188 dev_err(ctx
->dev
, "DSP start core failed: core_mask %x\n",
196 int skl_dsp_core_power_up(struct sst_dsp
*ctx
, unsigned int core_mask
)
201 sst_dsp_shim_update_bits_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
,
202 SKL_ADSPCS_SPA_MASK(core_mask
),
203 SKL_ADSPCS_SPA_MASK(core_mask
));
205 /* poll with timeout to check if operation successful */
206 ret
= sst_dsp_register_poll(ctx
,
208 SKL_ADSPCS_CPA_MASK(core_mask
),
209 SKL_ADSPCS_CPA_MASK(core_mask
),
213 if ((sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
) &
214 SKL_ADSPCS_CPA_MASK(core_mask
)) !=
215 SKL_ADSPCS_CPA_MASK(core_mask
)) {
216 dev_err(ctx
->dev
, "DSP core power up failed: core_mask %x\n",
224 int skl_dsp_core_power_down(struct sst_dsp
*ctx
, unsigned int core_mask
)
227 sst_dsp_shim_update_bits_unlocked(ctx
, SKL_ADSP_REG_ADSPCS
,
228 SKL_ADSPCS_SPA_MASK(core_mask
), 0);
230 /* poll with timeout to check if operation successful */
231 return sst_dsp_register_poll(ctx
,
233 SKL_ADSPCS_CPA_MASK(core_mask
),
239 int skl_dsp_enable_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
244 ret
= skl_dsp_core_power_up(ctx
, core_mask
);
246 dev_err(ctx
->dev
, "dsp core power up failed: core_mask %x\n",
251 return skl_dsp_start_core(ctx
, core_mask
);
254 int skl_dsp_disable_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
258 ret
= skl_dsp_reset_core(ctx
, core_mask
);
260 dev_err(ctx
->dev
, "dsp core reset failed: core_mask %x\n",
266 ret
= skl_dsp_core_power_down(ctx
, core_mask
);
268 dev_err(ctx
->dev
, "dsp core power down fail mask %x: %d\n",
273 if (is_skl_dsp_core_enable(ctx
, core_mask
)) {
274 dev_err(ctx
->dev
, "dsp core disable fail mask %x: %d\n",
282 int skl_dsp_boot(struct sst_dsp
*ctx
)
286 if (is_skl_dsp_core_enable(ctx
, SKL_DSP_CORE0_MASK
)) {
287 ret
= skl_dsp_reset_core(ctx
, SKL_DSP_CORE0_MASK
);
289 dev_err(ctx
->dev
, "dsp core0 reset fail: %d\n", ret
);
293 ret
= skl_dsp_start_core(ctx
, SKL_DSP_CORE0_MASK
);
295 dev_err(ctx
->dev
, "dsp core0 start fail: %d\n", ret
);
299 ret
= skl_dsp_disable_core(ctx
, SKL_DSP_CORE0_MASK
);
301 dev_err(ctx
->dev
, "dsp core0 disable fail: %d\n", ret
);
304 ret
= skl_dsp_enable_core(ctx
, SKL_DSP_CORE0_MASK
);
310 irqreturn_t
skl_dsp_sst_interrupt(int irq
, void *dev_id
)
312 struct sst_dsp
*ctx
= dev_id
;
314 irqreturn_t result
= IRQ_NONE
;
316 spin_lock(&ctx
->spinlock
);
318 val
= sst_dsp_shim_read_unlocked(ctx
, SKL_ADSP_REG_ADSPIS
);
319 ctx
->intr_status
= val
;
321 if (val
== 0xffffffff) {
322 spin_unlock(&ctx
->spinlock
);
326 if (val
& SKL_ADSPIS_IPC
) {
327 skl_ipc_int_disable(ctx
);
328 result
= IRQ_WAKE_THREAD
;
331 if (val
& SKL_ADSPIS_CL_DMA
) {
332 skl_cldma_int_disable(ctx
);
333 result
= IRQ_WAKE_THREAD
;
336 spin_unlock(&ctx
->spinlock
);
341 * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context
342 * within the dapm mutex. Hence no separate lock is used.
344 int skl_dsp_get_core(struct sst_dsp
*ctx
, unsigned int core_id
)
346 struct skl_sst
*skl
= ctx
->thread_context
;
349 if (core_id
>= skl
->cores
.count
) {
350 dev_err(ctx
->dev
, "invalid core id: %d\n", core_id
);
354 if (skl
->cores
.state
[core_id
] == SKL_DSP_RESET
) {
355 ret
= ctx
->fw_ops
.set_state_D0(ctx
, core_id
);
357 dev_err(ctx
->dev
, "unable to get core%d\n", core_id
);
362 skl
->cores
.usage_count
[core_id
]++;
364 dev_dbg(ctx
->dev
, "core id %d state %d usage_count %d\n",
365 core_id
, skl
->cores
.state
[core_id
],
366 skl
->cores
.usage_count
[core_id
]);
370 EXPORT_SYMBOL_GPL(skl_dsp_get_core
);
372 int skl_dsp_put_core(struct sst_dsp
*ctx
, unsigned int core_id
)
374 struct skl_sst
*skl
= ctx
->thread_context
;
377 if (core_id
>= skl
->cores
.count
) {
378 dev_err(ctx
->dev
, "invalid core id: %d\n", core_id
);
382 if (--skl
->cores
.usage_count
[core_id
] == 0) {
383 ret
= ctx
->fw_ops
.set_state_D3(ctx
, core_id
);
385 dev_err(ctx
->dev
, "unable to put core %d: %d\n",
387 skl
->cores
.usage_count
[core_id
]++;
391 dev_dbg(ctx
->dev
, "core id %d state %d usage_count %d\n",
392 core_id
, skl
->cores
.state
[core_id
],
393 skl
->cores
.usage_count
[core_id
]);
397 EXPORT_SYMBOL_GPL(skl_dsp_put_core
);
399 int skl_dsp_wake(struct sst_dsp
*ctx
)
401 return skl_dsp_get_core(ctx
, SKL_DSP_CORE0_ID
);
403 EXPORT_SYMBOL_GPL(skl_dsp_wake
);
405 int skl_dsp_sleep(struct sst_dsp
*ctx
)
407 return skl_dsp_put_core(ctx
, SKL_DSP_CORE0_ID
);
409 EXPORT_SYMBOL_GPL(skl_dsp_sleep
);
411 struct sst_dsp
*skl_dsp_ctx_init(struct device
*dev
,
412 struct sst_dsp_device
*sst_dev
, int irq
)
417 sst
= devm_kzalloc(dev
, sizeof(*sst
), GFP_KERNEL
);
421 spin_lock_init(&sst
->spinlock
);
422 mutex_init(&sst
->mutex
);
424 sst
->sst_dev
= sst_dev
;
426 sst
->ops
= sst_dev
->ops
;
427 sst
->thread_context
= sst_dev
->thread_context
;
429 /* Initialise SST Audio DSP */
430 if (sst
->ops
->init
) {
431 ret
= sst
->ops
->init(sst
, NULL
);
436 /* Register the ISR */
437 ret
= request_threaded_irq(sst
->irq
, sst
->ops
->irq_handler
,
438 sst_dev
->thread
, IRQF_SHARED
, "AudioDSP", sst
);
440 dev_err(sst
->dev
, "unable to grab threaded IRQ %d, disabling device\n",
448 void skl_dsp_free(struct sst_dsp
*dsp
)
450 skl_ipc_int_disable(dsp
);
452 free_irq(dsp
->irq
, dsp
);
453 skl_ipc_op_int_disable(dsp
);
454 skl_dsp_disable_core(dsp
, SKL_DSP_CORE0_MASK
);
456 EXPORT_SYMBOL_GPL(skl_dsp_free
);
458 bool is_skl_dsp_running(struct sst_dsp
*ctx
)
460 return (ctx
->sst_state
== SKL_DSP_RUNNING
);
462 EXPORT_SYMBOL_GPL(is_skl_dsp_running
);