ASoC: Intel: Skylake: Shield against no-NHLT configurations
[sfrench/cifs-2.6.git] / sound / soc / intel / skylake / cnl-sst-dsp.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * cnl-sst-dsp.c - CNL SST library generic function
4  *
5  * Copyright (C) 2016-17, Intel Corporation.
6  * Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
7  *
8  * Modified from:
9  *      SKL SST library generic function
10  *      Copyright (C) 2014-15, Intel Corporation.
11  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12  *
13  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14  */
15 #include <linux/device.h>
16 #include "../common/sst-dsp.h"
17 #include "../common/sst-ipc.h"
18 #include "../common/sst-dsp-priv.h"
19 #include "cnl-sst-dsp.h"
20
21 /* various timeout values */
22 #define CNL_DSP_PU_TO           50
23 #define CNL_DSP_PD_TO           50
24 #define CNL_DSP_RESET_TO        50
25
26 static int
27 cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
28 {
29         /* update bits */
30         sst_dsp_shim_update_bits_unlocked(ctx,
31                         CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
32                         CNL_ADSPCS_CRST(core_mask));
33
34         /* poll with timeout to check if operation successful */
35         return sst_dsp_register_poll(ctx,
36                         CNL_ADSP_REG_ADSPCS,
37                         CNL_ADSPCS_CRST(core_mask),
38                         CNL_ADSPCS_CRST(core_mask),
39                         CNL_DSP_RESET_TO,
40                         "Set reset");
41 }
42
43 static int
44 cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
45 {
46         /* update bits */
47         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
48                                         CNL_ADSPCS_CRST(core_mask), 0);
49
50         /* poll with timeout to check if operation successful */
51         return sst_dsp_register_poll(ctx,
52                         CNL_ADSP_REG_ADSPCS,
53                         CNL_ADSPCS_CRST(core_mask),
54                         0,
55                         CNL_DSP_RESET_TO,
56                         "Unset reset");
57 }
58
59 static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
60 {
61         int val;
62         bool is_enable;
63
64         val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
65
66         is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
67                         (val & CNL_ADSPCS_SPA(core_mask)) &&
68                         !(val & CNL_ADSPCS_CRST(core_mask)) &&
69                         !(val & CNL_ADSPCS_CSTALL(core_mask));
70
71         dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
72                 is_enable, core_mask);
73
74         return is_enable;
75 }
76
77 static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
78 {
79         /* stall core */
80         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
81                         CNL_ADSPCS_CSTALL(core_mask),
82                         CNL_ADSPCS_CSTALL(core_mask));
83
84         /* set reset state */
85         return cnl_dsp_core_set_reset_state(ctx, core_mask);
86 }
87
88 static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
89 {
90         int ret;
91
92         /* unset reset state */
93         ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
94         if (ret < 0)
95                 return ret;
96
97         /* run core */
98         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
99                                 CNL_ADSPCS_CSTALL(core_mask), 0);
100
101         if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
102                 cnl_dsp_reset_core(ctx, core_mask);
103                 dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
104                         core_mask);
105                 ret = -EIO;
106         }
107
108         return ret;
109 }
110
111 static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
112 {
113         /* update bits */
114         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
115                                           CNL_ADSPCS_SPA(core_mask),
116                                           CNL_ADSPCS_SPA(core_mask));
117
118         /* poll with timeout to check if operation successful */
119         return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
120                                     CNL_ADSPCS_CPA(core_mask),
121                                     CNL_ADSPCS_CPA(core_mask),
122                                     CNL_DSP_PU_TO,
123                                     "Power up");
124 }
125
126 static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
127 {
128         /* update bits */
129         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
130                                         CNL_ADSPCS_SPA(core_mask), 0);
131
132         /* poll with timeout to check if operation successful */
133         return sst_dsp_register_poll(ctx,
134                         CNL_ADSP_REG_ADSPCS,
135                         CNL_ADSPCS_CPA(core_mask),
136                         0,
137                         CNL_DSP_PD_TO,
138                         "Power down");
139 }
140
141 int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
142 {
143         int ret;
144
145         /* power up */
146         ret = cnl_dsp_core_power_up(ctx, core_mask);
147         if (ret < 0) {
148                 dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
149                         core_mask);
150                 return ret;
151         }
152
153         return cnl_dsp_start_core(ctx, core_mask);
154 }
155
156 int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
157 {
158         int ret;
159
160         ret = cnl_dsp_reset_core(ctx, core_mask);
161         if (ret < 0) {
162                 dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
163                         core_mask);
164                 return ret;
165         }
166
167         /* power down core*/
168         ret = cnl_dsp_core_power_down(ctx, core_mask);
169         if (ret < 0) {
170                 dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
171                         core_mask);
172                 return ret;
173         }
174
175         if (is_cnl_dsp_core_enable(ctx, core_mask)) {
176                 dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
177                         core_mask);
178                 ret = -EIO;
179         }
180
181         return ret;
182 }
183
184 irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
185 {
186         struct sst_dsp *ctx = dev_id;
187         u32 val;
188         irqreturn_t ret = IRQ_NONE;
189
190         spin_lock(&ctx->spinlock);
191
192         val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
193         ctx->intr_status = val;
194
195         if (val == 0xffffffff) {
196                 spin_unlock(&ctx->spinlock);
197                 return IRQ_NONE;
198         }
199
200         if (val & CNL_ADSPIS_IPC) {
201                 cnl_ipc_int_disable(ctx);
202                 ret = IRQ_WAKE_THREAD;
203         }
204
205         spin_unlock(&ctx->spinlock);
206
207         return ret;
208 }
209
210 void cnl_dsp_free(struct sst_dsp *dsp)
211 {
212         cnl_ipc_int_disable(dsp);
213
214         free_irq(dsp->irq, dsp);
215         cnl_ipc_op_int_disable(dsp);
216         cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
217 }
218 EXPORT_SYMBOL_GPL(cnl_dsp_free);
219
220 void cnl_ipc_int_enable(struct sst_dsp *ctx)
221 {
222         sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
223                                  CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
224 }
225
226 void cnl_ipc_int_disable(struct sst_dsp *ctx)
227 {
228         sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
229                                           CNL_ADSPIC_IPC, 0);
230 }
231
232 void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
233 {
234         /* enable IPC DONE interrupt */
235         sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
236                                  CNL_ADSP_REG_HIPCCTL_DONE,
237                                  CNL_ADSP_REG_HIPCCTL_DONE);
238
239         /* enable IPC BUSY interrupt */
240         sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
241                                  CNL_ADSP_REG_HIPCCTL_BUSY,
242                                  CNL_ADSP_REG_HIPCCTL_BUSY);
243 }
244
245 void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
246 {
247         /* disable IPC DONE interrupt */
248         sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
249                                  CNL_ADSP_REG_HIPCCTL_DONE, 0);
250
251         /* disable IPC BUSY interrupt */
252         sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
253                                  CNL_ADSP_REG_HIPCCTL_BUSY, 0);
254 }
255
256 bool cnl_ipc_int_status(struct sst_dsp *ctx)
257 {
258         return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
259                                                         CNL_ADSPIS_IPC;
260 }
261
262 void cnl_ipc_free(struct sst_generic_ipc *ipc)
263 {
264         cnl_ipc_op_int_disable(ipc->dsp);
265         sst_ipc_fini(ipc);
266 }