1 /* 2 * skl-sst-dsp.c - SKL SST library generic function 3 * 4 * Copyright (C) 2014-15, Intel Corporation. 5 * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> 6 * Jeeja KP <jeeja.kp@intel.com> 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 */ 18 #include <sound/pcm.h> 19 20 #include "../common/sst-dsp.h" 21 #include "../common/sst-ipc.h" 22 #include "../common/sst-dsp-priv.h" 23 #include "skl-sst-ipc.h" 24 25 /* various timeout values */ 26 #define SKL_DSP_PU_TO 50 27 #define SKL_DSP_PD_TO 50 28 #define SKL_DSP_RESET_TO 50 29 30 void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) 31 { 32 mutex_lock(&ctx->mutex); 33 ctx->sst_state = state; 34 mutex_unlock(&ctx->mutex); 35 } 36 37 static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) 38 { 39 int ret; 40 41 /* update bits */ 42 sst_dsp_shim_update_bits_unlocked(ctx, 43 SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, 44 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); 45 46 /* poll with timeout to check if operation successful */ 47 ret = sst_dsp_register_poll(ctx, 48 SKL_ADSP_REG_ADSPCS, 49 SKL_ADSPCS_CRST_MASK, 50 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), 51 SKL_DSP_RESET_TO, 52 "Set reset"); 53 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & 54 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 55 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { 56 dev_err(ctx->dev, "Set reset state failed\n"); 57 ret = -EIO; 58 } 59 60 return ret; 61 } 62 63 static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) 64 { 65 int ret; 66 67 dev_dbg(ctx->dev, "In %s\n", __func__); 68 69 /* update bits */ 70 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 71 SKL_ADSPCS_CRST_MASK, 0); 72 73 /* poll with timeout to check if operation successful */ 74 ret = sst_dsp_register_poll(ctx, 75 SKL_ADSP_REG_ADSPCS, 76 SKL_ADSPCS_CRST_MASK, 77 0, 78 SKL_DSP_RESET_TO, 79 "Unset reset"); 80 81 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & 82 SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { 83 dev_err(ctx->dev, "Unset reset state failed\n"); 84 ret = -EIO; 85 } 86 87 return ret; 88 } 89 90 static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) 91 { 92 int val; 93 bool is_enable; 94 95 val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); 96 97 is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && 98 (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && 99 !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && 100 !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); 101 102 dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); 103 return is_enable; 104 } 105 106 static int skl_dsp_reset_core(struct sst_dsp *ctx) 107 { 108 /* stall core */ 109 sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 110 sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & 111 SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); 112 113 /* set reset state */ 114 return skl_dsp_core_set_reset_state(ctx); 115 } 116 117 static int skl_dsp_start_core(struct sst_dsp *ctx) 118 { 119 int ret; 120 121 /* unset reset state */ 122 ret = skl_dsp_core_unset_reset_state(ctx); 123 if (ret < 0) { 124 dev_dbg(ctx->dev, "dsp unset reset fails\n"); 125 return ret; 126 } 127 128 /* run core */ 129 dev_dbg(ctx->dev, "run core...\n"); 130 sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 131 sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & 132 ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); 133 134 if (!is_skl_dsp_core_enable(ctx)) { 135 skl_dsp_reset_core(ctx); 136 dev_err(ctx->dev, "DSP core enable failed\n"); 137 ret = -EIO; 138 } 139 140 return ret; 141 } 142 143 static int skl_dsp_core_power_up(struct sst_dsp *ctx) 144 { 145 int ret; 146 147 /* update bits */ 148 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 149 SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); 150 151 /* poll with timeout to check if operation successful */ 152 ret = sst_dsp_register_poll(ctx, 153 SKL_ADSP_REG_ADSPCS, 154 SKL_ADSPCS_CPA_MASK, 155 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), 156 SKL_DSP_PU_TO, 157 "Power up"); 158 159 if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & 160 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) != 161 SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { 162 dev_err(ctx->dev, "DSP core power up failed\n"); 163 ret = -EIO; 164 } 165 166 return ret; 167 } 168 169 static int skl_dsp_core_power_down(struct sst_dsp *ctx) 170 { 171 /* update bits */ 172 sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 173 SKL_ADSPCS_SPA_MASK, 0); 174 175 /* poll with timeout to check if operation successful */ 176 return sst_dsp_register_poll(ctx, 177 SKL_ADSP_REG_ADSPCS, 178 SKL_ADSPCS_SPA_MASK, 179 0, 180 SKL_DSP_PD_TO, 181 "Power down"); 182 } 183 184 static int skl_dsp_enable_core(struct sst_dsp *ctx) 185 { 186 int ret; 187 188 /* power up */ 189 ret = skl_dsp_core_power_up(ctx); 190 if (ret < 0) { 191 dev_dbg(ctx->dev, "dsp core power up failed\n"); 192 return ret; 193 } 194 195 return skl_dsp_start_core(ctx); 196 } 197 198 int skl_dsp_disable_core(struct sst_dsp *ctx) 199 { 200 int ret; 201 202 ret = skl_dsp_reset_core(ctx); 203 if (ret < 0) { 204 dev_err(ctx->dev, "dsp core reset failed\n"); 205 return ret; 206 } 207 208 /* power down core*/ 209 ret = skl_dsp_core_power_down(ctx); 210 if (ret < 0) { 211 dev_err(ctx->dev, "dsp core power down failed\n"); 212 return ret; 213 } 214 215 if (is_skl_dsp_core_enable(ctx)) { 216 dev_err(ctx->dev, "DSP core disable failed\n"); 217 ret = -EIO; 218 } 219 220 return ret; 221 } 222 223 int skl_dsp_boot(struct sst_dsp *ctx) 224 { 225 int ret; 226 227 if (is_skl_dsp_core_enable(ctx)) { 228 dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); 229 ret = skl_dsp_reset_core(ctx); 230 if (ret < 0) { 231 dev_err(ctx->dev, "dsp reset failed\n"); 232 return ret; 233 } 234 235 ret = skl_dsp_start_core(ctx); 236 if (ret < 0) { 237 dev_err(ctx->dev, "dsp start failed\n"); 238 return ret; 239 } 240 } else { 241 dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); 242 ret = skl_dsp_disable_core(ctx); 243 244 if (ret < 0) { 245 dev_err(ctx->dev, "dsp disable core failes\n"); 246 return ret; 247 } 248 ret = skl_dsp_enable_core(ctx); 249 } 250 251 return ret; 252 } 253 254 irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) 255 { 256 struct sst_dsp *ctx = dev_id; 257 u32 val; 258 irqreturn_t result = IRQ_NONE; 259 260 spin_lock(&ctx->spinlock); 261 262 val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); 263 ctx->intr_status = val; 264 265 if (val & SKL_ADSPIS_IPC) { 266 skl_ipc_int_disable(ctx); 267 result = IRQ_WAKE_THREAD; 268 } 269 270 if (val & SKL_ADSPIS_CL_DMA) { 271 skl_cldma_int_disable(ctx); 272 result = IRQ_WAKE_THREAD; 273 } 274 275 spin_unlock(&ctx->spinlock); 276 277 return result; 278 } 279 280 int skl_dsp_wake(struct sst_dsp *ctx) 281 { 282 return ctx->fw_ops.set_state_D0(ctx); 283 } 284 EXPORT_SYMBOL_GPL(skl_dsp_wake); 285 286 int skl_dsp_sleep(struct sst_dsp *ctx) 287 { 288 return ctx->fw_ops.set_state_D3(ctx); 289 } 290 EXPORT_SYMBOL_GPL(skl_dsp_sleep); 291 292 struct sst_dsp *skl_dsp_ctx_init(struct device *dev, 293 struct sst_dsp_device *sst_dev, int irq) 294 { 295 int ret; 296 struct sst_dsp *sst; 297 298 sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); 299 if (sst == NULL) 300 return NULL; 301 302 spin_lock_init(&sst->spinlock); 303 mutex_init(&sst->mutex); 304 sst->dev = dev; 305 sst->sst_dev = sst_dev; 306 sst->irq = irq; 307 sst->ops = sst_dev->ops; 308 sst->thread_context = sst_dev->thread_context; 309 310 /* Initialise SST Audio DSP */ 311 if (sst->ops->init) { 312 ret = sst->ops->init(sst, NULL); 313 if (ret < 0) 314 return NULL; 315 } 316 317 /* Register the ISR */ 318 ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, 319 sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); 320 if (ret) { 321 dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", 322 sst->irq); 323 return NULL; 324 } 325 326 return sst; 327 } 328 329 void skl_dsp_free(struct sst_dsp *dsp) 330 { 331 skl_ipc_int_disable(dsp); 332 333 free_irq(dsp->irq, dsp); 334 skl_dsp_disable_core(dsp); 335 } 336 EXPORT_SYMBOL_GPL(skl_dsp_free); 337 338 bool is_skl_dsp_running(struct sst_dsp *ctx) 339 { 340 return (ctx->sst_state == SKL_DSP_RUNNING); 341 } 342 EXPORT_SYMBOL_GPL(is_skl_dsp_running); 343