1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4 // 5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 // 8 9 #include <linux/module.h> 10 #include <sound/hdaudio_ext.h> 11 #include "avs.h" 12 #include "registers.h" 13 14 #define AVS_ADSPCS_INTERVAL_US 500 15 #define AVS_ADSPCS_TIMEOUT_US 50000 16 17 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) 18 { 19 u32 value, mask, reg; 20 int ret; 21 22 mask = AVS_ADSPCS_SPA_MASK(core_mask); 23 value = power ? mask : 0; 24 25 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value); 26 27 mask = AVS_ADSPCS_CPA_MASK(core_mask); 28 value = power ? mask : 0; 29 30 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS, 31 reg, (reg & mask) == value, 32 AVS_ADSPCS_INTERVAL_US, 33 AVS_ADSPCS_TIMEOUT_US); 34 if (ret) 35 dev_err(adev->dev, "core_mask %d power %s failed: %d\n", 36 core_mask, power ? "on" : "off", ret); 37 38 return ret; 39 } 40 41 int avs_dsp_core_reset(struct avs_dev *adev, u32 core_mask, bool reset) 42 { 43 u32 value, mask, reg; 44 int ret; 45 46 mask = AVS_ADSPCS_CRST_MASK(core_mask); 47 value = reset ? mask : 0; 48 49 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value); 50 51 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS, 52 reg, (reg & mask) == value, 53 AVS_ADSPCS_INTERVAL_US, 54 AVS_ADSPCS_TIMEOUT_US); 55 if (ret) 56 dev_err(adev->dev, "core_mask %d %s reset failed: %d\n", 57 core_mask, reset ? "enter" : "exit", ret); 58 59 return ret; 60 } 61 62 int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) 63 { 64 u32 value, mask, reg; 65 int ret; 66 67 mask = AVS_ADSPCS_CSTALL_MASK(core_mask); 68 value = stall ? mask : 0; 69 70 snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value); 71 72 ret = snd_hdac_adsp_readl_poll(adev, AVS_ADSP_REG_ADSPCS, 73 reg, (reg & mask) == value, 74 AVS_ADSPCS_INTERVAL_US, 75 AVS_ADSPCS_TIMEOUT_US); 76 if (ret) 77 dev_err(adev->dev, "core_mask %d %sstall failed: %d\n", 78 core_mask, stall ? "" : "un", ret); 79 80 return ret; 81 } 82 83 int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask) 84 { 85 int ret; 86 87 ret = avs_dsp_op(adev, power, core_mask, true); 88 if (ret) 89 return ret; 90 91 ret = avs_dsp_op(adev, reset, core_mask, false); 92 if (ret) 93 return ret; 94 95 return avs_dsp_op(adev, stall, core_mask, false); 96 } 97 98 int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask) 99 { 100 /* No error checks to allow for complete DSP shutdown. */ 101 avs_dsp_op(adev, stall, core_mask, true); 102 avs_dsp_op(adev, reset, core_mask, true); 103 104 return avs_dsp_op(adev, power, core_mask, false); 105 } 106 107 static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask) 108 { 109 u32 mask; 110 int ret; 111 112 ret = avs_dsp_core_enable(adev, core_mask); 113 if (ret < 0) 114 return ret; 115 116 mask = core_mask & ~AVS_MAIN_CORE_MASK; 117 if (!mask) 118 /* 119 * without main core, fw is dead anyway 120 * so setting D0 for it is futile. 121 */ 122 return 0; 123 124 ret = avs_ipc_set_dx(adev, mask, true); 125 return AVS_IPC_RET(ret); 126 } 127 128 static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask) 129 { 130 int ret; 131 132 ret = avs_ipc_set_dx(adev, core_mask, false); 133 if (ret) 134 return AVS_IPC_RET(ret); 135 136 return avs_dsp_core_disable(adev, core_mask); 137 } 138 139 static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id) 140 { 141 u32 mask; 142 int ret; 143 144 mask = BIT_MASK(core_id); 145 if (mask == AVS_MAIN_CORE_MASK) 146 /* nothing to do for main core */ 147 return 0; 148 if (core_id >= adev->hw_cfg.dsp_cores) { 149 ret = -EINVAL; 150 goto err; 151 } 152 153 adev->core_refs[core_id]++; 154 if (adev->core_refs[core_id] == 1) { 155 ret = avs_dsp_enable(adev, mask); 156 if (ret) 157 goto err_enable_dsp; 158 } 159 160 return 0; 161 162 err_enable_dsp: 163 adev->core_refs[core_id]--; 164 err: 165 dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret); 166 return ret; 167 } 168 169 static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id) 170 { 171 u32 mask; 172 int ret; 173 174 mask = BIT_MASK(core_id); 175 if (mask == AVS_MAIN_CORE_MASK) 176 /* nothing to do for main core */ 177 return 0; 178 if (core_id >= adev->hw_cfg.dsp_cores) { 179 ret = -EINVAL; 180 goto err; 181 } 182 183 adev->core_refs[core_id]--; 184 if (!adev->core_refs[core_id]) { 185 ret = avs_dsp_disable(adev, mask); 186 if (ret) 187 goto err; 188 } 189 190 return 0; 191 err: 192 dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret); 193 return ret; 194 } 195 196 int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id, 197 u8 core_id, u8 domain, void *param, u32 param_size, 198 u16 *instance_id) 199 { 200 struct avs_module_entry mentry; 201 bool was_loaded = false; 202 int ret, id; 203 204 id = avs_module_id_alloc(adev, module_id); 205 if (id < 0) 206 return id; 207 208 ret = avs_get_module_id_entry(adev, module_id, &mentry); 209 if (ret) 210 goto err_mod_entry; 211 212 ret = avs_dsp_get_core(adev, core_id); 213 if (ret) 214 goto err_mod_entry; 215 216 /* Load code into memory if this is the first instance. */ 217 if (!id && !avs_module_entry_is_loaded(&mentry)) { 218 ret = avs_dsp_op(adev, transfer_mods, true, &mentry, 1); 219 if (ret) { 220 dev_err(adev->dev, "load modules failed: %d\n", ret); 221 goto err_mod_entry; 222 } 223 was_loaded = true; 224 } 225 226 ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id, 227 core_id, domain, param, param_size); 228 if (ret) { 229 ret = AVS_IPC_RET(ret); 230 goto err_ipc; 231 } 232 233 *instance_id = id; 234 return 0; 235 236 err_ipc: 237 if (was_loaded) 238 avs_dsp_op(adev, transfer_mods, false, &mentry, 1); 239 avs_dsp_put_core(adev, core_id); 240 err_mod_entry: 241 avs_module_id_free(adev, module_id, id); 242 return ret; 243 } 244 245 void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id, 246 u8 ppl_instance_id, u8 core_id) 247 { 248 struct avs_module_entry mentry; 249 int ret; 250 251 /* Modules not owned by any pipeline need to be freed explicitly. */ 252 if (ppl_instance_id == INVALID_PIPELINE_ID) 253 avs_ipc_delete_instance(adev, module_id, instance_id); 254 255 avs_module_id_free(adev, module_id, instance_id); 256 257 ret = avs_get_module_id_entry(adev, module_id, &mentry); 258 /* Unload occupied memory if this was the last instance. */ 259 if (!ret && mentry.type.load_type == AVS_MODULE_LOAD_TYPE_LOADABLE) { 260 if (avs_is_module_ida_empty(adev, module_id)) { 261 ret = avs_dsp_op(adev, transfer_mods, false, &mentry, 1); 262 if (ret) 263 dev_err(adev->dev, "unload modules failed: %d\n", ret); 264 } 265 } 266 267 avs_dsp_put_core(adev, core_id); 268 } 269 270 int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority, 271 bool lp, u16 attributes, u8 *instance_id) 272 { 273 struct avs_fw_cfg *fw_cfg = &adev->fw_cfg; 274 int ret, id; 275 276 id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL); 277 if (id < 0) 278 return id; 279 280 ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes); 281 if (ret) { 282 ida_free(&adev->ppl_ida, id); 283 return AVS_IPC_RET(ret); 284 } 285 286 *instance_id = id; 287 return 0; 288 } 289 290 int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id) 291 { 292 int ret; 293 294 ret = avs_ipc_delete_pipeline(adev, instance_id); 295 if (ret) 296 ret = AVS_IPC_RET(ret); 297 298 ida_free(&adev->ppl_ida, instance_id); 299 return ret; 300 } 301 302 MODULE_LICENSE("GPL"); 303