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 generic Intel audio DSP HDA IP 16 */ 17 18 #include <sound/sof/ipc4/header.h> 19 #include <trace/events/sof_intel.h> 20 #include "../ops.h" 21 #include "hda.h" 22 23 static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev) 24 { 25 /* 26 * tell DSP cmd is done - clear busy 27 * interrupt and send reply msg to dsp 28 */ 29 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 30 HDA_DSP_REG_HIPCT, 31 HDA_DSP_REG_HIPCT_BUSY, 32 HDA_DSP_REG_HIPCT_BUSY); 33 34 /* unmask BUSY interrupt */ 35 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 36 HDA_DSP_REG_HIPCCTL, 37 HDA_DSP_REG_HIPCCTL_BUSY, 38 HDA_DSP_REG_HIPCCTL_BUSY); 39 } 40 41 static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) 42 { 43 /* 44 * set DONE bit - tell DSP we have received the reply msg 45 * from DSP, and processed it, don't send more reply to host 46 */ 47 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 48 HDA_DSP_REG_HIPCIE, 49 HDA_DSP_REG_HIPCIE_DONE, 50 HDA_DSP_REG_HIPCIE_DONE); 51 52 /* unmask Done interrupt */ 53 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 54 HDA_DSP_REG_HIPCCTL, 55 HDA_DSP_REG_HIPCCTL_DONE, 56 HDA_DSP_REG_HIPCCTL_DONE); 57 } 58 59 int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 60 { 61 /* send IPC message to DSP */ 62 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, 63 msg->msg_size); 64 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, 65 HDA_DSP_REG_HIPCI_BUSY); 66 67 return 0; 68 } 69 70 static inline bool hda_dsp_ipc4_pm_msg(u32 primary) 71 { 72 /* pm setting is only supported by module msg */ 73 if (SOF_IPC4_MSG_IS_MODULE_MSG(primary) != SOF_IPC4_MODULE_MSG) 74 return false; 75 76 if (SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_DX || 77 SOF_IPC4_MSG_TYPE_GET(primary) == SOF_IPC4_MOD_SET_D0IX) 78 return true; 79 80 return false; 81 } 82 83 void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, 84 struct snd_sof_ipc_msg *msg) 85 { 86 struct sof_ipc4_msg *msg_data = msg->msg_data; 87 88 /* Schedule a delayed work for d0i3 entry after sending non-pm ipc msg */ 89 if (hda_dsp_ipc4_pm_msg(msg_data->primary)) 90 return; 91 92 mod_delayed_work(system_wq, &hdev->d0i3_work, 93 msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); 94 } 95 96 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 97 { 98 struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; 99 struct sof_ipc4_msg *msg_data = msg->msg_data; 100 101 if (hda_ipc4_tx_is_busy(sdev)) { 102 hdev->delayed_ipc_tx_msg = msg; 103 return 0; 104 } 105 106 hdev->delayed_ipc_tx_msg = NULL; 107 108 /* send the message via mailbox */ 109 if (msg_data->data_size) 110 sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, 111 msg_data->data_size); 112 113 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE, msg_data->extension); 114 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, 115 msg_data->primary | HDA_DSP_REG_HIPCI_BUSY); 116 117 hda_dsp_ipc4_schedule_d0i3_work(hdev, msg); 118 119 return 0; 120 } 121 122 void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) 123 { 124 struct snd_sof_ipc_msg *msg = sdev->msg; 125 struct sof_ipc_reply reply; 126 struct sof_ipc_cmd_hdr *hdr; 127 128 /* 129 * Sometimes, there is unexpected reply ipc arriving. The reply 130 * ipc belongs to none of the ipcs sent from driver. 131 * In this case, the driver must ignore the ipc. 132 */ 133 if (!msg) { 134 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); 135 return; 136 } 137 138 hdr = msg->msg_data; 139 if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || 140 hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { 141 /* 142 * memory windows are powered off before sending IPC reply, 143 * so we can't read the mailbox for CTX_SAVE and PM_GATE 144 * replies. 145 */ 146 reply.error = 0; 147 reply.hdr.cmd = SOF_IPC_GLB_REPLY; 148 reply.hdr.size = sizeof(reply); 149 memcpy(msg->reply_data, &reply, sizeof(reply)); 150 151 msg->reply_error = 0; 152 } else { 153 snd_sof_ipc_get_reply(sdev); 154 } 155 } 156 157 irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) 158 { 159 struct sof_ipc4_msg notification_data = {{ 0 }}; 160 struct snd_sof_dev *sdev = context; 161 bool ack_received = false; 162 bool ipc_irq = false; 163 u32 hipcie, hipct; 164 165 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); 166 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); 167 168 if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { 169 /* DSP received the message */ 170 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL, 171 HDA_DSP_REG_HIPCCTL_DONE, 0); 172 hda_dsp_ipc_dsp_done(sdev); 173 174 ipc_irq = true; 175 ack_received = true; 176 } 177 178 if (hipct & HDA_DSP_REG_HIPCT_BUSY) { 179 /* Message from DSP (reply or notification) */ 180 u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 181 HDA_DSP_REG_HIPCTE); 182 u32 primary = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; 183 u32 extension = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; 184 185 /* mask BUSY interrupt */ 186 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL, 187 HDA_DSP_REG_HIPCCTL_BUSY, 0); 188 189 if (primary & SOF_IPC4_MSG_DIR_MASK) { 190 /* Reply received */ 191 if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { 192 struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; 193 194 data->primary = primary; 195 data->extension = extension; 196 197 spin_lock_irq(&sdev->ipc_lock); 198 199 snd_sof_ipc_get_reply(sdev); 200 hda_dsp_ipc_host_done(sdev); 201 snd_sof_ipc_reply(sdev, data->primary); 202 203 spin_unlock_irq(&sdev->ipc_lock); 204 } else { 205 dev_dbg_ratelimited(sdev->dev, 206 "IPC reply before FW_READY: %#x|%#x\n", 207 primary, extension); 208 } 209 } else { 210 /* Notification received */ 211 212 notification_data.primary = primary; 213 notification_data.extension = extension; 214 sdev->ipc->msg.rx_data = ¬ification_data; 215 snd_sof_ipc_msgs_rx(sdev); 216 sdev->ipc->msg.rx_data = NULL; 217 218 /* Let DSP know that we have finished processing the message */ 219 hda_dsp_ipc_host_done(sdev); 220 } 221 222 ipc_irq = true; 223 } 224 225 if (!ipc_irq) 226 /* This interrupt is not shared so no need to return IRQ_NONE. */ 227 dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); 228 229 if (ack_received) { 230 struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; 231 232 if (hdev->delayed_ipc_tx_msg) 233 hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg); 234 } 235 236 return IRQ_HANDLED; 237 } 238 239 /* IPC handler thread */ 240 irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) 241 { 242 struct snd_sof_dev *sdev = context; 243 u32 hipci; 244 u32 hipcie; 245 u32 hipct; 246 u32 hipcte; 247 u32 msg; 248 u32 msg_ext; 249 bool ipc_irq = false; 250 251 /* read IPC status */ 252 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 253 HDA_DSP_REG_HIPCIE); 254 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); 255 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); 256 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); 257 258 /* is this a reply message from the DSP */ 259 if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { 260 msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; 261 msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; 262 263 trace_sof_intel_ipc_firmware_response(sdev, msg, msg_ext); 264 265 /* mask Done interrupt */ 266 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 267 HDA_DSP_REG_HIPCCTL, 268 HDA_DSP_REG_HIPCCTL_DONE, 0); 269 270 /* 271 * Make sure the interrupt thread cannot be preempted between 272 * waking up the sender and re-enabling the interrupt. Also 273 * protect against a theoretical race with sof_ipc_tx_message(): 274 * if the DSP is fast enough to receive an IPC message, reply to 275 * it, and the host interrupt processing calls this function on 276 * a different core from the one, where the sending is taking 277 * place, the message might not yet be marked as expecting a 278 * reply. 279 */ 280 if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { 281 spin_lock_irq(&sdev->ipc_lock); 282 283 /* handle immediate reply from DSP core */ 284 hda_dsp_ipc_get_reply(sdev); 285 snd_sof_ipc_reply(sdev, msg); 286 287 /* set the done bit */ 288 hda_dsp_ipc_dsp_done(sdev); 289 290 spin_unlock_irq(&sdev->ipc_lock); 291 } else { 292 dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n", 293 msg); 294 } 295 296 ipc_irq = true; 297 } 298 299 /* is this a new message from DSP */ 300 if (hipct & HDA_DSP_REG_HIPCT_BUSY) { 301 msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; 302 msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; 303 304 trace_sof_intel_ipc_firmware_initiated(sdev, msg, msg_ext); 305 306 /* mask BUSY interrupt */ 307 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 308 HDA_DSP_REG_HIPCCTL, 309 HDA_DSP_REG_HIPCCTL_BUSY, 0); 310 311 /* handle messages from DSP */ 312 if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { 313 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 314 bool non_recoverable = true; 315 316 /* 317 * This is a PANIC message! 318 * 319 * If it is arriving during firmware boot and it is not 320 * the last boot attempt then change the non_recoverable 321 * to false as the DSP might be able to boot in the next 322 * iteration(s) 323 */ 324 if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS && 325 hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS) 326 non_recoverable = false; 327 328 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext), 329 non_recoverable); 330 } else { 331 /* normal message - process normally */ 332 snd_sof_ipc_msgs_rx(sdev); 333 } 334 335 hda_dsp_ipc_host_done(sdev); 336 337 ipc_irq = true; 338 } 339 340 if (!ipc_irq) { 341 /* 342 * This interrupt is not shared so no need to return IRQ_NONE. 343 */ 344 dev_dbg_ratelimited(sdev->dev, 345 "nothing to do in IPC IRQ thread\n"); 346 } 347 348 return IRQ_HANDLED; 349 } 350 351 /* Check if an IPC IRQ occurred */ 352 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) 353 { 354 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 355 bool ret = false; 356 u32 irq_status; 357 358 /* store status */ 359 irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); 360 trace_sof_intel_hda_irq_ipc_check(sdev, irq_status); 361 362 /* invalid message ? */ 363 if (irq_status == 0xffffffff) 364 goto out; 365 366 /* IPC message ? */ 367 if (irq_status & HDA_DSP_ADSPIS_IPC) 368 ret = true; 369 370 /* CLDMA message ? */ 371 if (irq_status & HDA_DSP_ADSPIS_CL_DMA) { 372 hda->code_loading = 0; 373 wake_up(&hda->waitq); 374 ret = false; 375 } 376 377 out: 378 return ret; 379 } 380 381 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) 382 { 383 return HDA_DSP_MBOX_UPLINK_OFFSET; 384 } 385 386 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) 387 { 388 return SRAM_WINDOW_OFFSET(id); 389 } 390 391 int hda_ipc_msg_data(struct snd_sof_dev *sdev, 392 struct snd_sof_pcm_stream *sps, 393 void *p, size_t sz) 394 { 395 if (!sps || !sdev->stream_box.size) { 396 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 397 } else { 398 struct snd_pcm_substream *substream = sps->substream; 399 struct hdac_stream *hstream = substream->runtime->private_data; 400 struct sof_intel_hda_stream *hda_stream; 401 402 hda_stream = container_of(hstream, 403 struct sof_intel_hda_stream, 404 hext_stream.hstream); 405 406 /* The stream might already be closed */ 407 if (!hstream) 408 return -ESTRPIPE; 409 410 sof_mailbox_read(sdev, hda_stream->sof_intel_stream.posn_offset, p, sz); 411 } 412 413 return 0; 414 } 415 416 int hda_set_stream_data_offset(struct snd_sof_dev *sdev, 417 struct snd_sof_pcm_stream *sps, 418 size_t posn_offset) 419 { 420 struct snd_pcm_substream *substream = sps->substream; 421 struct hdac_stream *hstream = substream->runtime->private_data; 422 struct sof_intel_hda_stream *hda_stream; 423 424 hda_stream = container_of(hstream, struct sof_intel_hda_stream, 425 hext_stream.hstream); 426 427 /* check for unaligned offset or overflow */ 428 if (posn_offset > sdev->stream_box.size || 429 posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) 430 return -EINVAL; 431 432 hda_stream->sof_intel_stream.posn_offset = sdev->stream_box.offset + posn_offset; 433 434 dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", 435 substream->stream, hda_stream->sof_intel_stream.posn_offset); 436 437 return 0; 438 } 439