Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[deliverable/linux.git] / sound / soc / intel / skylake / skl-sst-dsp.c
CommitLineData
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
30void 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
a360b623 37static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
e973e31a
SP
38{
39 int ret;
40
41 /* update bits */
42 sst_dsp_shim_update_bits_unlocked(ctx,
43 SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK,
44 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK));
45
46 /* poll with timeout to check if operation successful */
47 ret = sst_dsp_register_poll(ctx,
48 SKL_ADSP_REG_ADSPCS,
49 SKL_ADSPCS_CRST_MASK,
50 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK),
51 SKL_DSP_RESET_TO,
52 "Set reset");
53 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
54 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) !=
55 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) {
56 dev_err(ctx->dev, "Set reset state failed\n");
57 ret = -EIO;
58 }
59
60 return ret;
61}
62
a360b623 63static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
e973e31a
SP
64{
65 int ret;
66
67 dev_dbg(ctx->dev, "In %s\n", __func__);
68
69 /* update bits */
70 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
71 SKL_ADSPCS_CRST_MASK, 0);
72
73 /* poll with timeout to check if operation successful */
74 ret = sst_dsp_register_poll(ctx,
75 SKL_ADSP_REG_ADSPCS,
76 SKL_ADSPCS_CRST_MASK,
77 0,
78 SKL_DSP_RESET_TO,
79 "Unset reset");
80
81 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
82 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) {
83 dev_err(ctx->dev, "Unset reset state failed\n");
84 ret = -EIO;
85 }
86
87 return ret;
88}
89
a360b623 90static bool is_skl_dsp_core_enable(struct sst_dsp *ctx)
e973e31a
SP
91{
92 int val;
93 bool is_enable;
94
95 val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
96
97 is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) &&
98 (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) &&
99 !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) &&
100 !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)));
101
102 dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable);
103 return is_enable;
104}
105
106static int skl_dsp_reset_core(struct sst_dsp *ctx)
107{
108 /* stall core */
109 sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
110 sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
111 SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
112
113 /* set reset state */
114 return skl_dsp_core_set_reset_state(ctx);
115}
116
117static int skl_dsp_start_core(struct sst_dsp *ctx)
118{
119 int ret;
120
121 /* unset reset state */
122 ret = skl_dsp_core_unset_reset_state(ctx);
123 if (ret < 0) {
124 dev_dbg(ctx->dev, "dsp unset reset fails\n");
125 return ret;
126 }
127
128 /* run core */
129 dev_dbg(ctx->dev, "run core...\n");
130 sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
131 sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
132 ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
133
134 if (!is_skl_dsp_core_enable(ctx)) {
135 skl_dsp_reset_core(ctx);
136 dev_err(ctx->dev, "DSP core enable failed\n");
137 ret = -EIO;
138 }
139
140 return ret;
141}
142
a360b623 143static int skl_dsp_core_power_up(struct sst_dsp *ctx)
e973e31a
SP
144{
145 int ret;
146
147 /* update bits */
148 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
149 SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK));
150
151 /* poll with timeout to check if operation successful */
152 ret = sst_dsp_register_poll(ctx,
153 SKL_ADSP_REG_ADSPCS,
154 SKL_ADSPCS_CPA_MASK,
155 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK),
156 SKL_DSP_PU_TO,
157 "Power up");
158
159 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
160 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) !=
161 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) {
162 dev_err(ctx->dev, "DSP core power up failed\n");
163 ret = -EIO;
164 }
165
166 return ret;
167}
168
a360b623 169static int skl_dsp_core_power_down(struct sst_dsp *ctx)
e973e31a
SP
170{
171 /* update bits */
172 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
173 SKL_ADSPCS_SPA_MASK, 0);
174
175 /* poll with timeout to check if operation successful */
176 return sst_dsp_register_poll(ctx,
177 SKL_ADSP_REG_ADSPCS,
6ea8ba33 178 SKL_ADSPCS_CPA_MASK,
e973e31a
SP
179 0,
180 SKL_DSP_PD_TO,
181 "Power down");
182}
183
130e69a4 184int skl_dsp_enable_core(struct sst_dsp *ctx)
e973e31a
SP
185{
186 int ret;
187
188 /* power up */
189 ret = skl_dsp_core_power_up(ctx);
190 if (ret < 0) {
191 dev_dbg(ctx->dev, "dsp core power up failed\n");
192 return ret;
193 }
194
195 return skl_dsp_start_core(ctx);
196}
197
a360b623 198int skl_dsp_disable_core(struct sst_dsp *ctx)
e973e31a
SP
199{
200 int ret;
201
202 ret = skl_dsp_reset_core(ctx);
203 if (ret < 0) {
204 dev_err(ctx->dev, "dsp core reset failed\n");
205 return ret;
206 }
207
208 /* power down core*/
209 ret = skl_dsp_core_power_down(ctx);
210 if (ret < 0) {
211 dev_err(ctx->dev, "dsp core power down failed\n");
212 return ret;
213 }
214
215 if (is_skl_dsp_core_enable(ctx)) {
216 dev_err(ctx->dev, "DSP core disable failed\n");
217 ret = -EIO;
218 }
219
220 return ret;
221}
222
223int skl_dsp_boot(struct sst_dsp *ctx)
224{
225 int ret;
226
227 if (is_skl_dsp_core_enable(ctx)) {
228 dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n");
229 ret = skl_dsp_reset_core(ctx);
230 if (ret < 0) {
231 dev_err(ctx->dev, "dsp reset failed\n");
232 return ret;
233 }
234
235 ret = skl_dsp_start_core(ctx);
236 if (ret < 0) {
237 dev_err(ctx->dev, "dsp start failed\n");
238 return ret;
239 }
240 } else {
241 dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n");
242 ret = skl_dsp_disable_core(ctx);
243
244 if (ret < 0) {
245 dev_err(ctx->dev, "dsp disable core failes\n");
246 return ret;
247 }
248 ret = skl_dsp_enable_core(ctx);
249 }
250
251 return ret;
252}
253
254irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
255{
256 struct sst_dsp *ctx = dev_id;
257 u32 val;
258 irqreturn_t result = IRQ_NONE;
259
260 spin_lock(&ctx->spinlock);
261
262 val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
263 ctx->intr_status = val;
264
def656fe
JK
265 if (val == 0xffffffff) {
266 spin_unlock(&ctx->spinlock);
267 return IRQ_NONE;
268 }
269
e973e31a
SP
270 if (val & SKL_ADSPIS_IPC) {
271 skl_ipc_int_disable(ctx);
272 result = IRQ_WAKE_THREAD;
273 }
274
6cb00333
SP
275 if (val & SKL_ADSPIS_CL_DMA) {
276 skl_cldma_int_disable(ctx);
277 result = IRQ_WAKE_THREAD;
278 }
279
e973e31a
SP
280 spin_unlock(&ctx->spinlock);
281
282 return result;
283}
284
285int skl_dsp_wake(struct sst_dsp *ctx)
286{
287 return ctx->fw_ops.set_state_D0(ctx);
288}
289EXPORT_SYMBOL_GPL(skl_dsp_wake);
290
291int skl_dsp_sleep(struct sst_dsp *ctx)
292{
293 return ctx->fw_ops.set_state_D3(ctx);
294}
295EXPORT_SYMBOL_GPL(skl_dsp_sleep);
296
297struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
298 struct sst_dsp_device *sst_dev, int irq)
299{
300 int ret;
301 struct sst_dsp *sst;
302
303 sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
304 if (sst == NULL)
305 return NULL;
306
307 spin_lock_init(&sst->spinlock);
308 mutex_init(&sst->mutex);
309 sst->dev = dev;
310 sst->sst_dev = sst_dev;
311 sst->irq = irq;
312 sst->ops = sst_dev->ops;
313 sst->thread_context = sst_dev->thread_context;
314
315 /* Initialise SST Audio DSP */
316 if (sst->ops->init) {
317 ret = sst->ops->init(sst, NULL);
318 if (ret < 0)
319 return NULL;
320 }
321
322 /* Register the ISR */
323 ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
324 sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
325 if (ret) {
326 dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
327 sst->irq);
328 return NULL;
329 }
330
331 return sst;
332}
333
334void skl_dsp_free(struct sst_dsp *dsp)
335{
336 skl_ipc_int_disable(dsp);
337
338 free_irq(dsp->irq, dsp);
3f7f8489
VK
339 dsp->cl_dev.ops.cl_cleanup_controller(dsp);
340 skl_cldma_int_disable(dsp);
341 skl_ipc_op_int_disable(dsp);
342 skl_ipc_int_disable(dsp);
343
e973e31a
SP
344 skl_dsp_disable_core(dsp);
345}
346EXPORT_SYMBOL_GPL(skl_dsp_free);
347
348bool is_skl_dsp_running(struct sst_dsp *ctx)
349{
350 return (ctx->sst_state == SKL_DSP_RUNNING);
351}
352EXPORT_SYMBOL_GPL(is_skl_dsp_running);
This page took 0.056498 seconds and 5 git commands to generate.