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 = msg->msg_data; 165 166 if (pm_gate->hdr.cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { 167 /* send the compact message via the primary register */ 168 *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; 169 170 /* send payload via the extended data register */ 171 *dd = pm_gate->flags; 172 173 return true; 174 } 175 176 return false; 177 } 178 179 int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 180 { 181 struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; 182 struct sof_ipc_cmd_hdr *hdr; 183 u32 dr = 0; 184 u32 dd = 0; 185 186 /* 187 * Currently the only compact IPC supported is the PM_GATE 188 * IPC which is used for transitioning the DSP between the 189 * D0I0 and D0I3 states. And these are sent only during the 190 * set_power_state() op. Therefore, there will never be a case 191 * that a compact IPC results in the DSP exiting D0I3 without 192 * the host and FW being in sync. 193 */ 194 if (cnl_compact_ipc_compress(msg, &dr, &dd)) { 195 /* send the message via IPC registers */ 196 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, 197 dd); 198 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 199 CNL_DSP_REG_HIPCIDR_BUSY | dr); 200 return 0; 201 } 202 203 /* send the message via mailbox */ 204 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 205 msg->msg_size); 206 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, 207 CNL_DSP_REG_HIPCIDR_BUSY); 208 209 hdr = msg->msg_data; 210 211 /* 212 * Use mod_delayed_work() to schedule the delayed work 213 * to avoid scheduling multiple workqueue items when 214 * IPCs are sent at a high-rate. mod_delayed_work() 215 * modifies the timer if the work is pending. 216 * Also, a new delayed work should not be queued after the 217 * CTX_SAVE IPC, which is sent before the DSP enters D3. 218 */ 219 if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) 220 mod_delayed_work(system_wq, &hdev->d0i3_work, 221 msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); 222 223 return 0; 224 } 225 226 void cnl_ipc_dump(struct snd_sof_dev *sdev) 227 { 228 u32 hipcctl; 229 u32 hipcida; 230 u32 hipctdr; 231 232 hda_ipc_irq_dump(sdev); 233 234 /* read IPC status */ 235 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); 236 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); 237 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); 238 239 /* dump the IPC regs */ 240 /* TODO: parse the raw msg */ 241 dev_err(sdev->dev, 242 "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", 243 hipcida, hipctdr, hipcctl); 244 } 245 246 /* cannonlake ops */ 247 const struct snd_sof_dsp_ops sof_cnl_ops = { 248 /* probe/remove/shutdown */ 249 .probe = hda_dsp_probe, 250 .remove = hda_dsp_remove, 251 .shutdown = hda_dsp_shutdown, 252 253 /* Register IO */ 254 .write = sof_io_write, 255 .read = sof_io_read, 256 .write64 = sof_io_write64, 257 .read64 = sof_io_read64, 258 259 /* Block IO */ 260 .block_read = sof_block_read, 261 .block_write = sof_block_write, 262 263 /* Mailbox IO */ 264 .mailbox_read = sof_mailbox_read, 265 .mailbox_write = sof_mailbox_write, 266 267 /* doorbell */ 268 .irq_thread = cnl_ipc_irq_thread, 269 270 /* ipc */ 271 .send_msg = cnl_ipc_send_msg, 272 .fw_ready = sof_fw_ready, 273 .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, 274 .get_window_offset = hda_dsp_ipc_get_window_offset, 275 276 .ipc_msg_data = hda_ipc_msg_data, 277 .set_stream_data_offset = hda_set_stream_data_offset, 278 279 /* machine driver */ 280 .machine_select = hda_machine_select, 281 .machine_register = sof_machine_register, 282 .machine_unregister = sof_machine_unregister, 283 .set_mach_params = hda_set_mach_params, 284 285 /* debug */ 286 .debug_map = cnl_dsp_debugfs, 287 .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), 288 .dbg_dump = hda_dsp_dump, 289 .ipc_dump = cnl_ipc_dump, 290 .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, 291 292 /* stream callbacks */ 293 .pcm_open = hda_dsp_pcm_open, 294 .pcm_close = hda_dsp_pcm_close, 295 .pcm_hw_params = hda_dsp_pcm_hw_params, 296 .pcm_hw_free = hda_dsp_stream_hw_free, 297 .pcm_trigger = hda_dsp_pcm_trigger, 298 .pcm_pointer = hda_dsp_pcm_pointer, 299 .pcm_ack = hda_dsp_pcm_ack, 300 301 /* firmware loading */ 302 .load_firmware = snd_sof_load_firmware_raw, 303 304 /* pre/post fw run */ 305 .pre_fw_run = hda_dsp_pre_fw_run, 306 .post_fw_run = hda_dsp_post_fw_run, 307 308 /* parse platform specific extended manifest */ 309 .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, 310 311 /* dsp core get/put */ 312 .core_get = hda_dsp_core_get, 313 314 /* firmware run */ 315 .run = hda_dsp_cl_boot_firmware, 316 317 /* trace callback */ 318 .trace_init = hda_dsp_trace_init, 319 .trace_release = hda_dsp_trace_release, 320 .trace_trigger = hda_dsp_trace_trigger, 321 322 /* client ops */ 323 .register_ipc_clients = hda_register_clients, 324 .unregister_ipc_clients = hda_unregister_clients, 325 326 /* DAI drivers */ 327 .drv = skl_dai, 328 .num_drv = SOF_SKL_NUM_DAIS, 329 330 /* PM */ 331 .suspend = hda_dsp_suspend, 332 .resume = hda_dsp_resume, 333 .runtime_suspend = hda_dsp_runtime_suspend, 334 .runtime_resume = hda_dsp_runtime_resume, 335 .runtime_idle = hda_dsp_runtime_idle, 336 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, 337 .set_power_state = hda_dsp_set_power_state, 338 339 /* ALSA HW info flags */ 340 .hw_info = SNDRV_PCM_INFO_MMAP | 341 SNDRV_PCM_INFO_MMAP_VALID | 342 SNDRV_PCM_INFO_INTERLEAVED | 343 SNDRV_PCM_INFO_PAUSE | 344 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, 345 346 .dsp_arch_ops = &sof_xtensa_arch_ops, 347 }; 348 EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); 349 350 const struct sof_intel_dsp_desc cnl_chip_info = { 351 /* Cannonlake */ 352 .cores_num = 4, 353 .init_core_mask = 1, 354 .host_managed_cores_mask = GENMASK(3, 0), 355 .ipc_req = CNL_DSP_REG_HIPCIDR, 356 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 357 .ipc_ack = CNL_DSP_REG_HIPCIDA, 358 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 359 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 360 .rom_init_timeout = 300, 361 .ssp_count = CNL_SSP_COUNT, 362 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 363 .sdw_shim_base = SDW_SHIM_BASE, 364 .sdw_alh_base = SDW_ALH_BASE, 365 .check_sdw_irq = hda_common_check_sdw_irq, 366 }; 367 EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); 368 369 /* 370 * JasperLake is technically derived from IceLake, and should be in 371 * described in icl.c. However since JasperLake was designed with 372 * two cores, it cannot support the IceLake-specific power-up sequences 373 * which rely on core3. To simplify, JasperLake uses the CannonLake ops and 374 * is described in cnl.c 375 */ 376 const struct sof_intel_dsp_desc jsl_chip_info = { 377 /* Jasperlake */ 378 .cores_num = 2, 379 .init_core_mask = 1, 380 .host_managed_cores_mask = GENMASK(1, 0), 381 .ipc_req = CNL_DSP_REG_HIPCIDR, 382 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, 383 .ipc_ack = CNL_DSP_REG_HIPCIDA, 384 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, 385 .ipc_ctl = CNL_DSP_REG_HIPCCTL, 386 .rom_init_timeout = 300, 387 .ssp_count = ICL_SSP_COUNT, 388 .ssp_base_offset = CNL_SSP_BASE_OFFSET, 389 .sdw_shim_base = SDW_SHIM_BASE, 390 .sdw_alh_base = SDW_ALH_BASE, 391 .check_sdw_irq = hda_common_check_sdw_irq, 392 }; 393 EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); 394