cnl-sst-dsp.c (6408B)
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}