1 // SPDX-License-Identifier: (GPL-2.0-only 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 #include "../sof-audio.h" 22 23 static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { 24 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, 25 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, 26 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, 27 }; 28 29 static void cnl_ipc_host_done(struct snd_sof_dev *sdev); 30 static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); 31 32 irqreturn_t cnl_ipc_irq_thread(int irq, void *context) 33 { 34 struct snd_sof_dev *sdev = context; 35 u32 hipci; 36 u32 hipcida; 37 u32 hipctdr; 38 u32 hipctdd; 39 u32 msg; 40 u32 msg_ext; 41 bool ipc_irq = false; 42 43 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); 44 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); 45 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); 46 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); 47 48 /* reply message from DSP */ 49 if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { 50 msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; 51 msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; 52 53 dev_vdbg(sdev->dev, 54 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", 55 msg, msg_ext); 56 57 /* mask Done interrupt */ 58 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 59 CNL_DSP_REG_HIPCCTL, 60 CNL_DSP_REG_HIPCCTL_DONE, 0); 61 62 spin_lock_irq(&sdev->ipc_lock); 63 64 /* handle immediate reply from DSP core */ 65 hda_dsp_ipc_get_reply(sdev); 66 snd_sof_ipc_reply(sdev, msg); 67 68 cnl_ipc_dsp_done(sdev); 69 70 spin_unlock_irq(&sdev->ipc_lock); 71 72 ipc_irq = true; 73 } 74 75 /* new message from DSP */ 76 if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { 77 msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; 78 msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; 79 80 dev_vdbg(sdev->dev, 81 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", 82 msg, msg_ext); 83 84 /* handle messages from DSP */ 85 if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { 86 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 87 bool non_recoverable = true; 88 89 /* 90 * This is a PANIC message! 91 * 92 * If it is arriving during firmware boot and it is not 93 * the last boot attempt then change the non_recoverable 94 * to false as the DSP might be able to boot in the next 95 * iteration(s) 96 */ 97 if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS && 98 hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS) 99 non_recoverable = false; 100 101 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext), 102 non_recoverable); 103 } else { 104 snd_sof_ipc_msgs_rx(sdev); 105 } 106 107 cnl_ipc_host_done(sdev); 108 109 ipc_irq = true; 110 } 111 112 if (!ipc_irq) { 113 /* 114 * This interrupt is not shared so no need to return IRQ_NONE. 115 */ 116 dev_dbg_ratelimited(sdev->dev, 117 "nothing to do in IPC IRQ thread\n"); 118 } 119 120 return IRQ_HANDLED; 121 } 122 123 static void cnl_ipc_host_done(struct snd_sof_dev *sdev) 124 { 125 /* 126 * clear busy interrupt to tell dsp controller this 127 * interrupt has been accepted, not trigger it again 128 */ 129 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 130 CNL_DSP_REG_HIPCTDR, 131 CNL_DSP_REG_HIPCTDR_BUSY, 132 CNL_DSP_REG_HIPCTDR_BUSY); 133 /* 134 * set done bit to ack dsp the msg has been 135 * processed and send reply msg to dsp 136 */ 137 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 138 CNL_DSP_REG_HIPCTDA, 139 CNL_DSP_REG_HIPCTDA_DONE, 140 CNL_DSP_REG_HIPCTDA_DONE); 141 } 142 143 static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) 144 { 145 /* 146 * set DONE bit - tell DSP we have received the reply msg 147 * from DSP, and processed it, don't send more reply to host 148 */ 149 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 150 CNL_DSP_REG_HIPCIDA, 151 CNL_DSP_REG_HIPCIDA_DONE, 152 CNL_DSP_REG_HIPCIDA_DONE); 153 154 /* unmask Done interrupt */ 155 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 156 CNL_DSP_REG_HIPCCTL, 157 CNL_DSP_REG_HIPCCTL_DONE, 158 CNL_DSP_REG_HIPCCTL_DONE); 159 } 160 161 static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, 162 u32 *dr, u32 *dd) 163 { 164 struct sof_ipc_pm_gate *pm_gate; 165 166 if (msg->header == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { 167 pm_gate = msg->msg_data; 168 169 /* send the compact message via the primary register */ 170 *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; 171 172 /* send payload via the extended data register */ 173 *dd = pm_gate->flags; 174 175 return true; 176 } 177 178 return false; 179 } 180 181 int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 182 { 183 struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; 184 struct sof_ipc_cmd_hdr *hdr; 185 u32 dr = 0; 186 u32 dd = 0; 187 188 /* 189 * Currently the only compact IPC supported is the PM_GATE 190 * IPC which is used for transitioning the DSP between the 191 * D0I0 and D0I3 states. And these are sent only during the 192 * set_power_state() op. Therefore, there will never be a case 193 * that a compact IPC results in the DSP exiting D0I3 without 194 * the host and FW being in sync. 195 */ 196 if (cnl_compact_ipc_compress(msg, &dr, &dd)) { 197 /* send the message via IPC registers */ 198 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, 199 dd); 200 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 201 CNL_DSP_REG_HIPCIDR_BUSY | dr); 202 return 0; 203 } 204 205 /* send the message via mailbox */ 206 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 207 msg->msg_size); 208 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 209 CNL_DSP_REG_HIPCIDR_BUSY); 210 211 hdr = msg->msg_data; 212 213 /* 214 * Use mod_delayed_work() to schedule the delayed work 215 * to avoid scheduling multiple workqueue items when 216 * IPCs are sent at a high-rate. mod_delayed_work() 217 * modifies the timer if the work is pending. 218 * Also, a new delayed work should not be queued after the 219 * CTX_SAVE IPC, which is sent before the DSP enters D3. 220 */ 221 if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) 222 mod_delayed_work(system_wq, &hdev->d0i3_work, 223 msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); 224 225 return 0; 226 } 227 228 void cnl_ipc_dump(struct snd_sof_dev *sdev) 229 { 230 u32 hipcctl; 231 u32 hipcida; 232 u32 hipctdr; 233 234 hda_ipc_irq_dump(sdev); 235 236 /* read IPC status */ 237 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); 238 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); 239 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); 240 241 /* dump the IPC regs */ 242 /* TODO: parse the raw msg */ 243 dev_err(sdev->dev, 244 "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", 245 hipcida, hipctdr, hipcctl); 246 } 247 248 /* cannonlake ops */ 249 const struct snd_sof_dsp_ops sof_cnl_ops = { 250 /* probe/remove/shutdown */ 251 .probe = hda_dsp_probe, 252 .remove = hda_dsp_remove, 253 .shutdown = hda_dsp_shutdown, 254 255 /* Register IO */ 256 .write = sof_io_write, 257 .read = sof_io_read, 258 .write64 = sof_io_write64, 259 .read64 = sof_io_read64, 260 261 /* Block IO */ 262 .block_read = sof_block_read, 263 .block_write = sof_block_write, 264 265 /* Mailbox IO */ 266 .mailbox_read = sof_mailbox_read, 267 .mailbox_write = sof_mailbox_write, 268 269 /* doorbell */ 270 .irq_thread = cnl_ipc_irq_thread, 271 272 /* ipc */ 273 .send_msg = cnl_ipc_send_msg, 274 .fw_ready = sof_fw_ready, 275 .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, 276 .get_window_offset = hda_dsp_ipc_get_window_offset, 277 278 .ipc_msg_data = hda_ipc_msg_data, 279 .ipc_pcm_params = hda_ipc_pcm_params, 280 281 /* machine driver */ 282 .machine_select = hda_machine_select, 283 .machine_register = sof_machine_register, 284 .machine_unregister = sof_machine_unregister, 285 .set_mach_params = hda_set_mach_params, 286 287 /* debug */ 288 .debug_map = cnl_dsp_debugfs, 289 .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), 290 .dbg_dump = hda_dsp_dump, 291 .ipc_dump = cnl_ipc_dump, 292 .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, 293 294 /* stream callbacks */ 295 .pcm_open = hda_dsp_pcm_open, 296 .pcm_close = hda_dsp_pcm_close, 297 .pcm_hw_params = hda_dsp_pcm_hw_params, 298 .pcm_hw_free = hda_dsp_stream_hw_free, 299 .pcm_trigger = hda_dsp_pcm_trigger, 300 .pcm_pointer = hda_dsp_pcm_pointer, 301 .pcm_ack = hda_dsp_pcm_ack, 302 303 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) 304 /* probe callbacks */ 305 .probe_assign = hda_probe_compr_assign, 306 .probe_free = hda_probe_compr_free, 307 .probe_set_params = hda_probe_compr_set_params, 308 .probe_trigger = hda_probe_compr_trigger, 309 .probe_pointer = hda_probe_compr_pointer, 310 #endif 311 312 /* firmware loading */ 313 .load_firmware = snd_sof_load_firmware_raw, 314 315 /* pre/post fw run */ 316 .pre_fw_run = hda_dsp_pre_fw_run, 317 .post_fw_run = hda_dsp_post_fw_run, 318 319 /* parse platform specific extended manifest */ 320 .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, 321 322 /* dsp core get/put */ 323 .core_get = hda_dsp_core_get, 324 325 /* firmware run */ 326 .run = hda_dsp_cl_boot_firmware, 327 328 /* trace callback */ 329 .trace_init = hda_dsp_trace_init, 330 .trace_release = hda_dsp_trace_release, 331 .trace_trigger = hda_dsp_trace_trigger, 332 333 /* DAI drivers */ 334 .drv = skl_dai, 335 .num_drv = SOF_SKL_NUM_DAIS, 336 337 /* PM */ 338 .suspend = hda_dsp_suspend, 339 .resume = hda_dsp_resume, 340 .runtime_suspend = hda_dsp_runtime_suspend, 341 .runtime_resume = hda_dsp_runtime_resume, 342 .runtime_idle = hda_dsp_runtime_idle, 343 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, 344 .set_power_state = hda_dsp_set_power_state, 345 346 /* ALSA HW info flags */ 347 .hw_info = SNDRV_PCM_INFO_MMAP | 348 SNDRV_PCM_INFO_MMAP_VALID | 349 SNDRV_PCM_INFO_INTERLEAVED | 350 SNDRV_PCM_INFO_PAUSE | 351 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 352 353 .dsp_arch_ops = &sof_xtensa_arch_ops, 354 }; 355 EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); 356 357 const struct sof_intel_dsp_desc cnl_chip_info = { 358 /* Cannonlake */ 359 .cores_num = 4, 360 .init_core_mask = 1, 361 .host_managed_cores_mask = GENMASK(3, 0), 362 .ipc_req = CNL_DSP_REG_HIPCIDR, 363 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 364 .ipc_ack = CNL_DSP_REG_HIPCIDA, 365 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 366 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 367 .rom_init_timeout = 300, 368 .ssp_count = CNL_SSP_COUNT, 369 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 370 .sdw_shim_base = SDW_SHIM_BASE, 371 .sdw_alh_base = SDW_ALH_BASE, 372 .check_sdw_irq = hda_common_check_sdw_irq, 373 }; 374 EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); 375 376 /* 377 * JasperLake is technically derived from IceLake, and should be in 378 * described in icl.c. However since JasperLake was designed with 379 * two cores, it cannot support the IceLake-specific power-up sequences 380 * which rely on core3. To simplify, JasperLake uses the CannonLake ops and 381 * is described in cnl.c 382 */ 383 const struct sof_intel_dsp_desc jsl_chip_info = { 384 /* Jasperlake */ 385 .cores_num = 2, 386 .init_core_mask = 1, 387 .host_managed_cores_mask = GENMASK(1, 0), 388 .ipc_req = CNL_DSP_REG_HIPCIDR, 389 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 390 .ipc_ack = CNL_DSP_REG_HIPCIDA, 391 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 392 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 393 .rom_init_timeout = 300, 394 .ssp_count = ICL_SSP_COUNT, 395 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 396 .sdw_shim_base = SDW_SHIM_BASE, 397 .sdw_alh_base = SDW_ALH_BASE, 398 .check_sdw_irq = hda_common_check_sdw_irq, 399 }; 400 EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); 401