Linux Audio

Check our new training course

Loading...
  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
 26static int
 27cnl_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
 43static int
 44cnl_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
 59static 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
 77static 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
 88static 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
111static 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
126static 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
141int 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
156int 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
184irqreturn_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
210void 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}
218EXPORT_SYMBOL_GPL(cnl_dsp_free);
219
220void 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
226void 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
232void 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
245void 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
256bool 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
262void cnl_ipc_free(struct sst_generic_ipc *ipc)
263{
264	cnl_ipc_op_int_disable(ipc->dsp);
265	sst_ipc_fini(ipc);
266}