1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2018 Intel Corporation. All rights reserved. 7 // 8 // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 10 // Rander Wang <rander.wang@intel.com> 11 // Keyon Jie <yang.jie@linux.intel.com> 12 // 13 14 /* 15 * Hardware interface for audio DSP on Cannonlake. 16 */ 17 18 #include "../ops.h" 19 #include "hda.h" 20 #include "hda-ipc.h" 21 22 static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { 23 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, 24 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, 25 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, 26 }; 27 28 static void cnl_ipc_host_done(struct snd_sof_dev *sdev); 29 static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); 30 31 static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) 32 { 33 struct snd_sof_dev *sdev = context; 34 u32 hipci; 35 u32 hipcida; 36 u32 hipctdr; 37 u32 hipctdd; 38 u32 msg; 39 u32 msg_ext; 40 bool ipc_irq = false; 41 42 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); 43 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); 44 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); 45 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); 46 47 /* reply message from DSP */ 48 if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { 49 msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; 50 msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; 51 52 dev_vdbg(sdev->dev, 53 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", 54 msg, msg_ext); 55 56 /* mask Done interrupt */ 57 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 58 CNL_DSP_REG_HIPCCTL, 59 CNL_DSP_REG_HIPCCTL_DONE, 0); 60 61 spin_lock_irq(&sdev->ipc_lock); 62 63 /* handle immediate reply from DSP core */ 64 hda_dsp_ipc_get_reply(sdev); 65 snd_sof_ipc_reply(sdev, msg); 66 67 if (sdev->code_loading) { 68 sdev->code_loading = 0; 69 wake_up(&sdev->waitq); 70 } 71 72 cnl_ipc_dsp_done(sdev); 73 74 spin_unlock_irq(&sdev->ipc_lock); 75 76 ipc_irq = true; 77 } 78 79 /* new message from DSP */ 80 if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { 81 msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; 82 msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; 83 84 dev_vdbg(sdev->dev, 85 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", 86 msg, msg_ext); 87 88 /* handle messages from DSP */ 89 if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == 90 SOF_IPC_PANIC_MAGIC) { 91 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); 92 } else { 93 snd_sof_ipc_msgs_rx(sdev); 94 } 95 96 cnl_ipc_host_done(sdev); 97 98 ipc_irq = true; 99 } 100 101 if (!ipc_irq) { 102 /* 103 * This interrupt is not shared so no need to return IRQ_NONE. 104 */ 105 dev_dbg_ratelimited(sdev->dev, 106 "nothing to do in IPC IRQ thread\n"); 107 } 108 109 /* re-enable IPC interrupt */ 110 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 111 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); 112 113 return IRQ_HANDLED; 114 } 115 116 static void cnl_ipc_host_done(struct snd_sof_dev *sdev) 117 { 118 /* 119 * clear busy interrupt to tell dsp controller this 120 * interrupt has been accepted, not trigger it again 121 */ 122 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 123 CNL_DSP_REG_HIPCTDR, 124 CNL_DSP_REG_HIPCTDR_BUSY, 125 CNL_DSP_REG_HIPCTDR_BUSY); 126 /* 127 * set done bit to ack dsp the msg has been 128 * processed and send reply msg to dsp 129 */ 130 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 131 CNL_DSP_REG_HIPCTDA, 132 CNL_DSP_REG_HIPCTDA_DONE, 133 CNL_DSP_REG_HIPCTDA_DONE); 134 } 135 136 static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) 137 { 138 /* 139 * set DONE bit - tell DSP we have received the reply msg 140 * from DSP, and processed it, don't send more reply to host 141 */ 142 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 143 CNL_DSP_REG_HIPCIDA, 144 CNL_DSP_REG_HIPCIDA_DONE, 145 CNL_DSP_REG_HIPCIDA_DONE); 146 147 /* unmask Done interrupt */ 148 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 149 CNL_DSP_REG_HIPCCTL, 150 CNL_DSP_REG_HIPCCTL_DONE, 151 CNL_DSP_REG_HIPCCTL_DONE); 152 } 153 154 static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, 155 u32 *dr, u32 *dd) 156 { 157 struct sof_ipc_pm_gate *pm_gate; 158 159 if (msg->header == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { 160 pm_gate = msg->msg_data; 161 162 /* send the compact message via the primary register */ 163 *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; 164 165 /* send payload via the extended data register */ 166 *dd = pm_gate->flags; 167 168 return true; 169 } 170 171 return false; 172 } 173 174 static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, 175 struct snd_sof_ipc_msg *msg) 176 { 177 u32 dr = 0; 178 u32 dd = 0; 179 180 if (cnl_compact_ipc_compress(msg, &dr, &dd)) { 181 /* send the message via IPC registers */ 182 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, 183 dd); 184 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 185 CNL_DSP_REG_HIPCIDR_BUSY | dr); 186 } else { 187 /* send the message via mailbox */ 188 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 189 msg->msg_size); 190 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 191 CNL_DSP_REG_HIPCIDR_BUSY); 192 } 193 194 return 0; 195 } 196 197 static void cnl_ipc_dump(struct snd_sof_dev *sdev) 198 { 199 u32 hipcctl; 200 u32 hipcida; 201 u32 hipctdr; 202 203 hda_ipc_irq_dump(sdev); 204 205 /* read IPC status */ 206 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); 207 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); 208 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); 209 210 /* dump the IPC regs */ 211 /* TODO: parse the raw msg */ 212 dev_err(sdev->dev, 213 "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", 214 hipcida, hipctdr, hipcctl); 215 } 216 217 /* cannonlake ops */ 218 const struct snd_sof_dsp_ops sof_cnl_ops = { 219 /* probe and remove */ 220 .probe = hda_dsp_probe, 221 .remove = hda_dsp_remove, 222 223 /* Register IO */ 224 .write = sof_io_write, 225 .read = sof_io_read, 226 .write64 = sof_io_write64, 227 .read64 = sof_io_read64, 228 229 /* Block IO */ 230 .block_read = sof_block_read, 231 .block_write = sof_block_write, 232 233 /* doorbell */ 234 .irq_handler = hda_dsp_ipc_irq_handler, 235 .irq_thread = cnl_ipc_irq_thread, 236 237 /* ipc */ 238 .send_msg = cnl_ipc_send_msg, 239 .fw_ready = sof_fw_ready, 240 .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, 241 .get_window_offset = hda_dsp_ipc_get_window_offset, 242 243 .ipc_msg_data = hda_ipc_msg_data, 244 .ipc_pcm_params = hda_ipc_pcm_params, 245 246 /* debug */ 247 .debug_map = cnl_dsp_debugfs, 248 .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), 249 .dbg_dump = hda_dsp_dump, 250 .ipc_dump = cnl_ipc_dump, 251 252 /* stream callbacks */ 253 .pcm_open = hda_dsp_pcm_open, 254 .pcm_close = hda_dsp_pcm_close, 255 .pcm_hw_params = hda_dsp_pcm_hw_params, 256 .pcm_hw_free = hda_dsp_stream_hw_free, 257 .pcm_trigger = hda_dsp_pcm_trigger, 258 .pcm_pointer = hda_dsp_pcm_pointer, 259 260 /* firmware loading */ 261 .load_firmware = snd_sof_load_firmware_raw, 262 263 /* pre/post fw run */ 264 .pre_fw_run = hda_dsp_pre_fw_run, 265 .post_fw_run = hda_dsp_post_fw_run, 266 267 /* dsp core power up/down */ 268 .core_power_up = hda_dsp_enable_core, 269 .core_power_down = hda_dsp_core_reset_power_down, 270 271 /* firmware run */ 272 .run = hda_dsp_cl_boot_firmware, 273 274 /* trace callback */ 275 .trace_init = hda_dsp_trace_init, 276 .trace_release = hda_dsp_trace_release, 277 .trace_trigger = hda_dsp_trace_trigger, 278 279 /* DAI drivers */ 280 .drv = skl_dai, 281 .num_drv = SOF_SKL_NUM_DAIS, 282 283 /* PM */ 284 .suspend = hda_dsp_suspend, 285 .resume = hda_dsp_resume, 286 .runtime_suspend = hda_dsp_runtime_suspend, 287 .runtime_resume = hda_dsp_runtime_resume, 288 .runtime_idle = hda_dsp_runtime_idle, 289 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, 290 .set_power_state = hda_dsp_set_power_state, 291 292 /* ALSA HW info flags */ 293 .hw_info = SNDRV_PCM_INFO_MMAP | 294 SNDRV_PCM_INFO_MMAP_VALID | 295 SNDRV_PCM_INFO_INTERLEAVED | 296 SNDRV_PCM_INFO_PAUSE | 297 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 298 }; 299 EXPORT_SYMBOL(sof_cnl_ops); 300 301 const struct sof_intel_dsp_desc cnl_chip_info = { 302 /* Cannonlake */ 303 .cores_num = 4, 304 .init_core_mask = 1, 305 .cores_mask = HDA_DSP_CORE_MASK(0) | 306 HDA_DSP_CORE_MASK(1) | 307 HDA_DSP_CORE_MASK(2) | 308 HDA_DSP_CORE_MASK(3), 309 .ipc_req = CNL_DSP_REG_HIPCIDR, 310 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 311 .ipc_ack = CNL_DSP_REG_HIPCIDA, 312 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 313 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 314 .rom_init_timeout = 300, 315 .ssp_count = CNL_SSP_COUNT, 316 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 317 }; 318 EXPORT_SYMBOL(cnl_chip_info); 319 320 const struct sof_intel_dsp_desc icl_chip_info = { 321 /* Icelake */ 322 .cores_num = 4, 323 .init_core_mask = 1, 324 .cores_mask = HDA_DSP_CORE_MASK(0) | 325 HDA_DSP_CORE_MASK(1) | 326 HDA_DSP_CORE_MASK(2) | 327 HDA_DSP_CORE_MASK(3), 328 .ipc_req = CNL_DSP_REG_HIPCIDR, 329 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 330 .ipc_ack = CNL_DSP_REG_HIPCIDA, 331 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 332 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 333 .rom_init_timeout = 300, 334 .ssp_count = ICL_SSP_COUNT, 335 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 336 }; 337 EXPORT_SYMBOL(icl_chip_info); 338 339 const struct sof_intel_dsp_desc tgl_chip_info = { 340 /* Tigerlake */ 341 .cores_num = 4, 342 .init_core_mask = 1, 343 .cores_mask = HDA_DSP_CORE_MASK(0), 344 .ipc_req = CNL_DSP_REG_HIPCIDR, 345 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 346 .ipc_ack = CNL_DSP_REG_HIPCIDA, 347 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 348 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 349 .rom_init_timeout = 300, 350 .ssp_count = ICL_SSP_COUNT, 351 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 352 }; 353 EXPORT_SYMBOL(tgl_chip_info); 354 355 const struct sof_intel_dsp_desc ehl_chip_info = { 356 /* Elkhartlake */ 357 .cores_num = 4, 358 .init_core_mask = 1, 359 .cores_mask = HDA_DSP_CORE_MASK(0), 360 .ipc_req = CNL_DSP_REG_HIPCIDR, 361 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 362 .ipc_ack = CNL_DSP_REG_HIPCIDA, 363 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 364 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 365 .rom_init_timeout = 300, 366 .ssp_count = ICL_SSP_COUNT, 367 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 368 }; 369 EXPORT_SYMBOL(ehl_chip_info); 370 371 const struct sof_intel_dsp_desc jsl_chip_info = { 372 /* Jasperlake */ 373 .cores_num = 2, 374 .init_core_mask = 1, 375 .cores_mask = HDA_DSP_CORE_MASK(0) | 376 HDA_DSP_CORE_MASK(1), 377 .ipc_req = CNL_DSP_REG_HIPCIDR, 378 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 379 .ipc_ack = CNL_DSP_REG_HIPCIDA, 380 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 381 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 382 .rom_init_timeout = 300, 383 .ssp_count = ICL_SSP_COUNT, 384 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 385 }; 386 EXPORT_SYMBOL(jsl_chip_info); 387