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 generic Intel audio DSP HDA IP 16 */ 17 18 #include "../ops.h" 19 #include "hda.h" 20 21 static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev) 22 { 23 /* 24 * tell DSP cmd is done - clear busy 25 * interrupt and send reply msg to dsp 26 */ 27 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 28 HDA_DSP_REG_HIPCT, 29 HDA_DSP_REG_HIPCT_BUSY, 30 HDA_DSP_REG_HIPCT_BUSY); 31 32 /* unmask BUSY interrupt */ 33 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 34 HDA_DSP_REG_HIPCCTL, 35 HDA_DSP_REG_HIPCCTL_BUSY, 36 HDA_DSP_REG_HIPCCTL_BUSY); 37 } 38 39 static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) 40 { 41 /* 42 * set DONE bit - tell DSP we have received the reply msg 43 * from DSP, and processed it, don't send more reply to host 44 */ 45 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, 46 HDA_DSP_REG_HIPCIE, 47 HDA_DSP_REG_HIPCIE_DONE, 48 HDA_DSP_REG_HIPCIE_DONE); 49 50 /* unmask Done interrupt */ 51 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 52 HDA_DSP_REG_HIPCCTL, 53 HDA_DSP_REG_HIPCCTL_DONE, 54 HDA_DSP_REG_HIPCCTL_DONE); 55 } 56 57 int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 58 { 59 u32 cmd = msg->header; 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 cmd | HDA_DSP_REG_HIPCI_BUSY); 66 67 return 0; 68 } 69 70 void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) 71 { 72 struct snd_sof_ipc_msg *msg = sdev->msg; 73 struct sof_ipc_reply reply; 74 struct sof_ipc_cmd_hdr *hdr; 75 int ret = 0; 76 77 /* 78 * Sometimes, there is unexpected reply ipc arriving. The reply 79 * ipc belongs to none of the ipcs sent from driver. 80 * In this case, the driver must ignore the ipc. 81 */ 82 if (!msg) { 83 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); 84 return; 85 } 86 87 hdr = msg->msg_data; 88 if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { 89 /* 90 * memory windows are powered off before sending IPC reply, 91 * so we can't read the mailbox for CTX_SAVE reply. 92 */ 93 reply.error = 0; 94 reply.hdr.cmd = SOF_IPC_GLB_REPLY; 95 reply.hdr.size = sizeof(reply); 96 memcpy(msg->reply_data, &reply, sizeof(reply)); 97 goto out; 98 } 99 100 /* get IPC reply from DSP in the mailbox */ 101 sof_mailbox_read(sdev, sdev->host_box.offset, &reply, 102 sizeof(reply)); 103 104 if (reply.error < 0) { 105 memcpy(msg->reply_data, &reply, sizeof(reply)); 106 ret = reply.error; 107 } else { 108 /* reply correct size ? */ 109 if (reply.hdr.size != msg->reply_size) { 110 dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", 111 msg->reply_size, reply.hdr.size); 112 ret = -EINVAL; 113 } 114 115 /* read the message */ 116 if (msg->reply_size > 0) 117 sof_mailbox_read(sdev, sdev->host_box.offset, 118 msg->reply_data, msg->reply_size); 119 } 120 121 out: 122 msg->reply_error = ret; 123 124 } 125 126 static bool hda_dsp_ipc_is_sof(uint32_t msg) 127 { 128 return (msg & (HDA_DSP_IPC_PURGE_FW | 0xf << 9)) != msg || 129 (msg & HDA_DSP_IPC_PURGE_FW) != HDA_DSP_IPC_PURGE_FW; 130 } 131 132 /* IPC handler thread */ 133 irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) 134 { 135 struct snd_sof_dev *sdev = context; 136 irqreturn_t ret = IRQ_NONE; 137 u32 hipci; 138 u32 hipcie; 139 u32 hipct; 140 u32 hipcte; 141 u32 hipcctl; 142 u32 msg; 143 u32 msg_ext; 144 145 /* read IPC status */ 146 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 147 HDA_DSP_REG_HIPCIE); 148 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); 149 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); 150 151 /* reenable IPC interrupt */ 152 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, 153 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); 154 155 /* is this a reply message from the DSP */ 156 if (hipcie & HDA_DSP_REG_HIPCIE_DONE && 157 hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { 158 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 159 HDA_DSP_REG_HIPCI); 160 msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; 161 msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; 162 163 dev_vdbg(sdev->dev, 164 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", 165 msg, msg_ext); 166 167 /* mask Done interrupt */ 168 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 169 HDA_DSP_REG_HIPCCTL, 170 HDA_DSP_REG_HIPCCTL_DONE, 0); 171 172 /* 173 * Make sure the interrupt thread cannot be preempted between 174 * waking up the sender and re-enabling the interrupt. Also 175 * protect against a theoretical race with sof_ipc_tx_message(): 176 * if the DSP is fast enough to receive an IPC message, reply to 177 * it, and the host interrupt processing calls this function on 178 * a different core from the one, where the sending is taking 179 * place, the message might not yet be marked as expecting a 180 * reply. 181 */ 182 spin_lock_irq(&sdev->ipc_lock); 183 184 /* handle immediate reply from DSP core - ignore ROM messages */ 185 if (hda_dsp_ipc_is_sof(msg)) { 186 hda_dsp_ipc_get_reply(sdev); 187 snd_sof_ipc_reply(sdev, msg); 188 } 189 190 /* wake up sleeper if we are loading code */ 191 if (sdev->code_loading) { 192 sdev->code_loading = 0; 193 wake_up(&sdev->waitq); 194 } 195 196 /* set the done bit */ 197 hda_dsp_ipc_dsp_done(sdev); 198 199 spin_unlock_irq(&sdev->ipc_lock); 200 201 ret = IRQ_HANDLED; 202 } 203 204 /* is this a new message from DSP */ 205 if (hipct & HDA_DSP_REG_HIPCT_BUSY && 206 hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) { 207 208 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 209 HDA_DSP_REG_HIPCTE); 210 msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; 211 msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; 212 213 dev_vdbg(sdev->dev, 214 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", 215 msg, msg_ext); 216 217 /* mask BUSY interrupt */ 218 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 219 HDA_DSP_REG_HIPCCTL, 220 HDA_DSP_REG_HIPCCTL_BUSY, 0); 221 222 /* handle messages from DSP */ 223 if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { 224 /* this is a PANIC message !! */ 225 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); 226 } else { 227 /* normal message - process normally */ 228 snd_sof_ipc_msgs_rx(sdev); 229 } 230 231 hda_dsp_ipc_host_done(sdev); 232 233 ret = IRQ_HANDLED; 234 } 235 236 return ret; 237 } 238 239 /* is this IRQ for ADSP ? - we only care about IPC here */ 240 irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) 241 { 242 struct snd_sof_dev *sdev = context; 243 int ret = IRQ_NONE; 244 u32 irq_status; 245 246 spin_lock(&sdev->hw_lock); 247 248 /* store status */ 249 irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); 250 dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); 251 252 /* invalid message ? */ 253 if (irq_status == 0xffffffff) 254 goto out; 255 256 /* IPC message ? */ 257 if (irq_status & HDA_DSP_ADSPIS_IPC) { 258 /* disable IPC interrupt */ 259 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, 260 HDA_DSP_REG_ADSPIC, 261 HDA_DSP_ADSPIC_IPC, 0); 262 ret = IRQ_WAKE_THREAD; 263 } 264 265 out: 266 spin_unlock(&sdev->hw_lock); 267 return ret; 268 } 269 270 /* IPC Firmware ready */ 271 272 static void ipc_get_windows(struct snd_sof_dev *sdev) 273 { 274 struct sof_ipc_window_elem *elem; 275 u32 outbox_offset = 0; 276 u32 stream_offset = 0; 277 u32 inbox_offset = 0; 278 u32 outbox_size = 0; 279 u32 stream_size = 0; 280 u32 inbox_size = 0; 281 int i; 282 283 if (!sdev->info_window) { 284 dev_err(sdev->dev, "error: have no window info\n"); 285 return; 286 } 287 288 for (i = 0; i < sdev->info_window->num_windows; i++) { 289 elem = &sdev->info_window->window[i]; 290 291 switch (elem->type) { 292 case SOF_IPC_REGION_UPBOX: 293 inbox_offset = 294 elem->offset + SRAM_WINDOW_OFFSET(elem->id); 295 inbox_size = elem->size; 296 snd_sof_debugfs_io_item(sdev, 297 sdev->bar[HDA_DSP_BAR] + 298 inbox_offset, 299 elem->size, "inbox", 300 SOF_DEBUGFS_ACCESS_D0_ONLY); 301 break; 302 case SOF_IPC_REGION_DOWNBOX: 303 outbox_offset = 304 elem->offset + SRAM_WINDOW_OFFSET(elem->id); 305 outbox_size = elem->size; 306 snd_sof_debugfs_io_item(sdev, 307 sdev->bar[HDA_DSP_BAR] + 308 outbox_offset, 309 elem->size, "outbox", 310 SOF_DEBUGFS_ACCESS_D0_ONLY); 311 break; 312 case SOF_IPC_REGION_TRACE: 313 snd_sof_debugfs_io_item(sdev, 314 sdev->bar[HDA_DSP_BAR] + 315 elem->offset + 316 SRAM_WINDOW_OFFSET 317 (elem->id), 318 elem->size, "etrace", 319 SOF_DEBUGFS_ACCESS_D0_ONLY); 320 break; 321 case SOF_IPC_REGION_DEBUG: 322 snd_sof_debugfs_io_item(sdev, 323 sdev->bar[HDA_DSP_BAR] + 324 elem->offset + 325 SRAM_WINDOW_OFFSET 326 (elem->id), 327 elem->size, "debug", 328 SOF_DEBUGFS_ACCESS_D0_ONLY); 329 break; 330 case SOF_IPC_REGION_STREAM: 331 stream_offset = 332 elem->offset + SRAM_WINDOW_OFFSET(elem->id); 333 stream_size = elem->size; 334 snd_sof_debugfs_io_item(sdev, 335 sdev->bar[HDA_DSP_BAR] + 336 elem->offset + 337 SRAM_WINDOW_OFFSET 338 (elem->id), 339 elem->size, "stream", 340 SOF_DEBUGFS_ACCESS_D0_ONLY); 341 break; 342 case SOF_IPC_REGION_REGS: 343 snd_sof_debugfs_io_item(sdev, 344 sdev->bar[HDA_DSP_BAR] + 345 elem->offset + 346 SRAM_WINDOW_OFFSET 347 (elem->id), 348 elem->size, "regs", 349 SOF_DEBUGFS_ACCESS_D0_ONLY); 350 break; 351 case SOF_IPC_REGION_EXCEPTION: 352 sdev->dsp_oops_offset = elem->offset + 353 SRAM_WINDOW_OFFSET(elem->id); 354 snd_sof_debugfs_io_item(sdev, 355 sdev->bar[HDA_DSP_BAR] + 356 elem->offset + 357 SRAM_WINDOW_OFFSET 358 (elem->id), 359 elem->size, "exception", 360 SOF_DEBUGFS_ACCESS_D0_ONLY); 361 break; 362 default: 363 dev_err(sdev->dev, "error: get illegal window info\n"); 364 return; 365 } 366 } 367 368 if (outbox_size == 0 || inbox_size == 0) { 369 dev_err(sdev->dev, "error: get illegal mailbox window\n"); 370 return; 371 } 372 373 snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, 374 outbox_offset, outbox_size); 375 sdev->stream_box.offset = stream_offset; 376 sdev->stream_box.size = stream_size; 377 378 dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", 379 inbox_offset, inbox_size); 380 dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", 381 outbox_offset, outbox_size); 382 dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", 383 stream_offset, stream_size); 384 } 385 386 /* check for ABI compatibility and create memory windows on first boot */ 387 int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) 388 { 389 struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; 390 u32 offset; 391 int ret; 392 393 /* mailbox must be on 4k boundary */ 394 offset = HDA_DSP_MBOX_UPLINK_OFFSET; 395 396 dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", 397 msg_id, offset); 398 399 /* no need to re-check version/ABI for subsequent boots */ 400 if (!sdev->first_boot) 401 return 0; 402 403 /* copy data from the DSP FW ready offset */ 404 sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, 405 sizeof(*fw_ready)); 406 407 /* make sure ABI version is compatible */ 408 ret = snd_sof_ipc_valid(sdev); 409 if (ret < 0) 410 return ret; 411 412 /* now check for extended data */ 413 snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, 414 HDA_DSP_MBOX_UPLINK_OFFSET + 415 sizeof(struct sof_ipc_fw_ready)); 416 417 ipc_get_windows(sdev); 418 419 return 0; 420 } 421 422 void hda_ipc_msg_data(struct snd_sof_dev *sdev, 423 struct snd_pcm_substream *substream, 424 void *p, size_t sz) 425 { 426 if (!substream || !sdev->stream_box.size) { 427 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 428 } else { 429 struct hdac_stream *hstream = substream->runtime->private_data; 430 struct sof_intel_hda_stream *hda_stream; 431 432 hda_stream = container_of(hstream, 433 struct sof_intel_hda_stream, 434 hda_stream.hstream); 435 436 /* The stream might already be closed */ 437 if (hstream) 438 sof_mailbox_read(sdev, hda_stream->stream.posn_offset, 439 p, sz); 440 } 441 } 442 443 int hda_ipc_pcm_params(struct snd_sof_dev *sdev, 444 struct snd_pcm_substream *substream, 445 const struct sof_ipc_pcm_params_reply *reply) 446 { 447 struct hdac_stream *hstream = substream->runtime->private_data; 448 struct sof_intel_hda_stream *hda_stream; 449 /* validate offset */ 450 size_t posn_offset = reply->posn_offset; 451 452 hda_stream = container_of(hstream, struct sof_intel_hda_stream, 453 hda_stream.hstream); 454 455 /* check for unaligned offset or overflow */ 456 if (posn_offset > sdev->stream_box.size || 457 posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) 458 return -EINVAL; 459 460 hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset; 461 462 dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", 463 substream->stream, hda_stream->stream.posn_offset); 464 465 return 0; 466 } 467