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