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