Linux 4.15.6
[linux/fpc-iii.git] / sound / soc / intel / skylake / cnl-sst-dsp.c
blob2f8326707c21da955fbb0918e1a1145f9d91a28e
1 /*
2 * cnl-sst-dsp.c - CNL SST library generic function
4 * Copyright (C) 2016-17, Intel Corporation.
5 * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
7 * Modified from:
8 * SKL SST library generic function
9 * Copyright (C) 2014-15, Intel Corporation.
10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as version 2, as
14 * published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #include <linux/device.h>
24 #include "../common/sst-dsp.h"
25 #include "../common/sst-ipc.h"
26 #include "../common/sst-dsp-priv.h"
27 #include "cnl-sst-dsp.h"
29 /* various timeout values */
30 #define CNL_DSP_PU_TO 50
31 #define CNL_DSP_PD_TO 50
32 #define CNL_DSP_RESET_TO 50
34 static int
35 cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
37 /* update bits */
38 sst_dsp_shim_update_bits_unlocked(ctx,
39 CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
40 CNL_ADSPCS_CRST(core_mask));
42 /* poll with timeout to check if operation successful */
43 return sst_dsp_register_poll(ctx,
44 CNL_ADSP_REG_ADSPCS,
45 CNL_ADSPCS_CRST(core_mask),
46 CNL_ADSPCS_CRST(core_mask),
47 CNL_DSP_RESET_TO,
48 "Set reset");
51 static int
52 cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
54 /* update bits */
55 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
56 CNL_ADSPCS_CRST(core_mask), 0);
58 /* poll with timeout to check if operation successful */
59 return sst_dsp_register_poll(ctx,
60 CNL_ADSP_REG_ADSPCS,
61 CNL_ADSPCS_CRST(core_mask),
63 CNL_DSP_RESET_TO,
64 "Unset reset");
67 static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
69 int val;
70 bool is_enable;
72 val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
74 is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
75 (val & CNL_ADSPCS_SPA(core_mask)) &&
76 !(val & CNL_ADSPCS_CRST(core_mask)) &&
77 !(val & CNL_ADSPCS_CSTALL(core_mask));
79 dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
80 is_enable, core_mask);
82 return is_enable;
85 static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
87 /* stall core */
88 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
89 CNL_ADSPCS_CSTALL(core_mask),
90 CNL_ADSPCS_CSTALL(core_mask));
92 /* set reset state */
93 return cnl_dsp_core_set_reset_state(ctx, core_mask);
96 static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
98 int ret;
100 /* unset reset state */
101 ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
102 if (ret < 0)
103 return ret;
105 /* run core */
106 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
107 CNL_ADSPCS_CSTALL(core_mask), 0);
109 if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
110 cnl_dsp_reset_core(ctx, core_mask);
111 dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
112 core_mask);
113 ret = -EIO;
116 return ret;
119 static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
121 /* update bits */
122 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
123 CNL_ADSPCS_SPA(core_mask),
124 CNL_ADSPCS_SPA(core_mask));
126 /* poll with timeout to check if operation successful */
127 return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
128 CNL_ADSPCS_CPA(core_mask),
129 CNL_ADSPCS_CPA(core_mask),
130 CNL_DSP_PU_TO,
131 "Power up");
134 static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
136 /* update bits */
137 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
138 CNL_ADSPCS_SPA(core_mask), 0);
140 /* poll with timeout to check if operation successful */
141 return sst_dsp_register_poll(ctx,
142 CNL_ADSP_REG_ADSPCS,
143 CNL_ADSPCS_CPA(core_mask),
145 CNL_DSP_PD_TO,
146 "Power down");
149 int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
151 int ret;
153 /* power up */
154 ret = cnl_dsp_core_power_up(ctx, core_mask);
155 if (ret < 0) {
156 dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
157 core_mask);
158 return ret;
161 return cnl_dsp_start_core(ctx, core_mask);
164 int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
166 int ret;
168 ret = cnl_dsp_reset_core(ctx, core_mask);
169 if (ret < 0) {
170 dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
171 core_mask);
172 return ret;
175 /* power down core*/
176 ret = cnl_dsp_core_power_down(ctx, core_mask);
177 if (ret < 0) {
178 dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
179 core_mask);
180 return ret;
183 if (is_cnl_dsp_core_enable(ctx, core_mask)) {
184 dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
185 core_mask);
186 ret = -EIO;
189 return ret;
192 irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
194 struct sst_dsp *ctx = dev_id;
195 u32 val;
196 irqreturn_t ret = IRQ_NONE;
198 spin_lock(&ctx->spinlock);
200 val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
201 ctx->intr_status = val;
203 if (val == 0xffffffff) {
204 spin_unlock(&ctx->spinlock);
205 return IRQ_NONE;
208 if (val & CNL_ADSPIS_IPC) {
209 cnl_ipc_int_disable(ctx);
210 ret = IRQ_WAKE_THREAD;
213 spin_unlock(&ctx->spinlock);
215 return ret;
218 void cnl_dsp_free(struct sst_dsp *dsp)
220 cnl_ipc_int_disable(dsp);
222 free_irq(dsp->irq, dsp);
223 cnl_ipc_op_int_disable(dsp);
224 cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
226 EXPORT_SYMBOL_GPL(cnl_dsp_free);
228 void cnl_ipc_int_enable(struct sst_dsp *ctx)
230 sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
231 CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
234 void cnl_ipc_int_disable(struct sst_dsp *ctx)
236 sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
237 CNL_ADSPIC_IPC, 0);
240 void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
242 /* enable IPC DONE interrupt */
243 sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
244 CNL_ADSP_REG_HIPCCTL_DONE,
245 CNL_ADSP_REG_HIPCCTL_DONE);
247 /* enable IPC BUSY interrupt */
248 sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
249 CNL_ADSP_REG_HIPCCTL_BUSY,
250 CNL_ADSP_REG_HIPCCTL_BUSY);
253 void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
255 /* disable IPC DONE interrupt */
256 sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
257 CNL_ADSP_REG_HIPCCTL_DONE, 0);
259 /* disable IPC BUSY interrupt */
260 sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
261 CNL_ADSP_REG_HIPCCTL_BUSY, 0);
264 bool cnl_ipc_int_status(struct sst_dsp *ctx)
266 return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
267 CNL_ADSPIS_IPC;
270 void cnl_ipc_free(struct sst_generic_ipc *ipc)
272 cnl_ipc_op_int_disable(ipc->dsp);
273 sst_ipc_fini(ipc);