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 }
267