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>
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
35 cnl_dsp_core_set_reset_state(struct sst_dsp
*ctx
, unsigned int core_mask
)
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
,
45 CNL_ADSPCS_CRST(core_mask
),
46 CNL_ADSPCS_CRST(core_mask
),
52 cnl_dsp_core_unset_reset_state(struct sst_dsp
*ctx
, unsigned int core_mask
)
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
,
61 CNL_ADSPCS_CRST(core_mask
),
67 static bool is_cnl_dsp_core_enable(struct sst_dsp
*ctx
, unsigned int core_mask
)
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
);
85 static int cnl_dsp_reset_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
88 sst_dsp_shim_update_bits_unlocked(ctx
, CNL_ADSP_REG_ADSPCS
,
89 CNL_ADSPCS_CSTALL(core_mask
),
90 CNL_ADSPCS_CSTALL(core_mask
));
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
)
100 /* unset reset state */
101 ret
= cnl_dsp_core_unset_reset_state(ctx
, core_mask
);
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",
119 static int cnl_dsp_core_power_up(struct sst_dsp
*ctx
, unsigned int core_mask
)
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
),
134 static int cnl_dsp_core_power_down(struct sst_dsp
*ctx
, unsigned int core_mask
)
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
,
143 CNL_ADSPCS_CPA(core_mask
),
149 int cnl_dsp_enable_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
154 ret
= cnl_dsp_core_power_up(ctx
, core_mask
);
156 dev_dbg(ctx
->dev
, "DSP core mask %#x power up failed",
161 return cnl_dsp_start_core(ctx
, core_mask
);
164 int cnl_dsp_disable_core(struct sst_dsp
*ctx
, unsigned int core_mask
)
168 ret
= cnl_dsp_reset_core(ctx
, core_mask
);
170 dev_err(ctx
->dev
, "DSP core mask %#x reset failed\n",
176 ret
= cnl_dsp_core_power_down(ctx
, core_mask
);
178 dev_err(ctx
->dev
, "DSP core mask %#x power down failed\n",
183 if (is_cnl_dsp_core_enable(ctx
, core_mask
)) {
184 dev_err(ctx
->dev
, "DSP core mask %#x disable failed\n",
192 irqreturn_t
cnl_dsp_sst_interrupt(int irq
, void *dev_id
)
194 struct sst_dsp
*ctx
= dev_id
;
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
);
208 if (val
& CNL_ADSPIS_IPC
) {
209 cnl_ipc_int_disable(ctx
);
210 ret
= IRQ_WAKE_THREAD
;
213 spin_unlock(&ctx
->spinlock
);
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
,
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
) &
270 void cnl_ipc_free(struct sst_generic_ipc
*ipc
)
272 cnl_ipc_op_int_disable(ipc
->dsp
);