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 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 71 { 72 struct sof_ipc4_msg *msg_data = msg->msg_data; 73 74 /* send the message via mailbox */ 75 if (msg_data->data_size) 76 sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, 77 msg_data->data_size); 78 79 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE, msg_data->extension); 80 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, 81 msg_data->primary | HDA_DSP_REG_HIPCI_BUSY); 82 83 return 0; 84 } 85 86 void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) 87 { 88 struct snd_sof_ipc_msg *msg = sdev->msg; 89 struct sof_ipc_reply reply; 90 struct sof_ipc_cmd_hdr *hdr; 91 92 /* 93 * Sometimes, there is unexpected reply ipc arriving. The reply 94 * ipc belongs to none of the ipcs sent from driver. 95 * In this case, the driver must ignore the ipc. 96 */ 97 if (!msg) { 98 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); 99 return; 100 } 101 102 hdr = msg->msg_data; 103 if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || 104 hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { 105 /* 106 * memory windows are powered off before sending IPC reply, 107 * so we can't read the mailbox for CTX_SAVE and PM_GATE 108 * replies. 109 */ 110 reply.error = 0; 111 reply.hdr.cmd = SOF_IPC_GLB_REPLY; 112 reply.hdr.size = sizeof(reply); 113 memcpy(msg->reply_data, &reply, sizeof(reply)); 114 115 msg->reply_error = 0; 116 } else { 117 snd_sof_ipc_get_reply(sdev); 118 } 119 } 120 121 irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) 122 { 123 struct sof_ipc4_msg notification_data = {{ 0 }}; 124 struct snd_sof_dev *sdev = context; 125 bool ipc_irq = false; 126 u32 hipcie, hipct; 127 128 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); 129 if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { 130 /* DSP received the message */ 131 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL, 132 HDA_DSP_REG_HIPCCTL_DONE, 0); 133 hda_dsp_ipc_dsp_done(sdev); 134 135 ipc_irq = true; 136 } 137 138 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); 139 if (hipct & HDA_DSP_REG_HIPCT_BUSY) { 140 /* Message from DSP (reply or notification) */ 141 u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 142 HDA_DSP_REG_HIPCTE); 143 u32 primary = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; 144 u32 extension = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; 145 146 /* mask BUSY interrupt */ 147 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL, 148 HDA_DSP_REG_HIPCCTL_BUSY, 0); 149 150 if (primary & SOF_IPC4_MSG_DIR_MASK) { 151 /* Reply received */ 152 if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { 153 struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; 154 155 data->primary = primary; 156 data->extension = extension; 157 158 spin_lock_irq(&sdev->ipc_lock); 159 160 snd_sof_ipc_get_reply(sdev); 161 snd_sof_ipc_reply(sdev, data->primary); 162 163 spin_unlock_irq(&sdev->ipc_lock); 164 } else { 165 dev_dbg_ratelimited(sdev->dev, 166 "IPC reply before FW_READY: %#x|%#x\n", 167 primary, extension); 168 } 169 } else { 170 /* Notification received */ 171 172 notification_data.primary = primary; 173 notification_data.extension = extension; 174 sdev->ipc->msg.rx_data = ¬ification_data; 175 snd_sof_ipc_msgs_rx(sdev); 176 sdev->ipc->msg.rx_data = NULL; 177 } 178 179 /* Let DSP know that we have finished processing the message */ 180 hda_dsp_ipc_host_done(sdev); 181 182 ipc_irq = true; 183 } 184 185 if (!ipc_irq) 186 /* This interrupt is not shared so no need to return IRQ_NONE. */ 187 dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); 188 189 return IRQ_HANDLED; 190 } 191 192 /* IPC handler thread */ 193 irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) 194 { 195 struct snd_sof_dev *sdev = context; 196 u32 hipci; 197 u32 hipcie; 198 u32 hipct; 199 u32 hipcte; 200 u32 msg; 201 u32 msg_ext; 202 bool ipc_irq = false; 203 204 /* read IPC status */ 205 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, 206 HDA_DSP_REG_HIPCIE); 207 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); 208 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); 209 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); 210 211 /* is this a reply message from the DSP */ 212 if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { 213 msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; 214 msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; 215 216 trace_sof_intel_ipc_firmware_response(sdev, msg, msg_ext); 217 218 /* mask Done interrupt */ 219 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 220 HDA_DSP_REG_HIPCCTL, 221 HDA_DSP_REG_HIPCCTL_DONE, 0); 222 223 /* 224 * Make sure the interrupt thread cannot be preempted between 225 * waking up the sender and re-enabling the interrupt. Also 226 * protect against a theoretical race with sof_ipc_tx_message(): 227 * if the DSP is fast enough to receive an IPC message, reply to 228 * it, and the host interrupt processing calls this function on 229 * a different core from the one, where the sending is taking 230 * place, the message might not yet be marked as expecting a 231 * reply. 232 */ 233 if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { 234 spin_lock_irq(&sdev->ipc_lock); 235 236 /* handle immediate reply from DSP core */ 237 hda_dsp_ipc_get_reply(sdev); 238 snd_sof_ipc_reply(sdev, msg); 239 240 /* set the done bit */ 241 hda_dsp_ipc_dsp_done(sdev); 242 243 spin_unlock_irq(&sdev->ipc_lock); 244 } else { 245 dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n", 246 msg); 247 } 248 249 ipc_irq = true; 250 } 251 252 /* is this a new message from DSP */ 253 if (hipct & HDA_DSP_REG_HIPCT_BUSY) { 254 msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; 255 msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; 256 257 trace_sof_intel_ipc_firmware_initiated(sdev, msg, msg_ext); 258 259 /* mask BUSY interrupt */ 260 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, 261 HDA_DSP_REG_HIPCCTL, 262 HDA_DSP_REG_HIPCCTL_BUSY, 0); 263 264 /* handle messages from DSP */ 265 if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { 266 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 267 bool non_recoverable = true; 268 269 /* 270 * This is a PANIC message! 271 * 272 * If it is arriving during firmware boot and it is not 273 * the last boot attempt then change the non_recoverable 274 * to false as the DSP might be able to boot in the next 275 * iteration(s) 276 */ 277 if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS && 278 hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS) 279 non_recoverable = false; 280 281 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext), 282 non_recoverable); 283 } else { 284 /* normal message - process normally */ 285 snd_sof_ipc_msgs_rx(sdev); 286 } 287 288 hda_dsp_ipc_host_done(sdev); 289 290 ipc_irq = true; 291 } 292 293 if (!ipc_irq) { 294 /* 295 * This interrupt is not shared so no need to return IRQ_NONE. 296 */ 297 dev_dbg_ratelimited(sdev->dev, 298 "nothing to do in IPC IRQ thread\n"); 299 } 300 301 return IRQ_HANDLED; 302 } 303 304 /* Check if an IPC IRQ occurred */ 305 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) 306 { 307 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 308 bool ret = false; 309 u32 irq_status; 310 311 /* store status */ 312 irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); 313 trace_sof_intel_hda_irq_ipc_check(sdev, irq_status); 314 315 /* invalid message ? */ 316 if (irq_status == 0xffffffff) 317 goto out; 318 319 /* IPC message ? */ 320 if (irq_status & HDA_DSP_ADSPIS_IPC) 321 ret = true; 322 323 /* CLDMA message ? */ 324 if (irq_status & HDA_DSP_ADSPIS_CL_DMA) { 325 hda->code_loading = 0; 326 wake_up(&hda->waitq); 327 ret = false; 328 } 329 330 out: 331 return ret; 332 } 333 334 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) 335 { 336 return HDA_DSP_MBOX_UPLINK_OFFSET; 337 } 338 339 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) 340 { 341 return SRAM_WINDOW_OFFSET(id); 342 } 343 344 int hda_ipc_msg_data(struct snd_sof_dev *sdev, 345 struct snd_pcm_substream *substream, 346 void *p, size_t sz) 347 { 348 if (!substream || !sdev->stream_box.size) { 349 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 350 } else { 351 struct hdac_stream *hstream = substream->runtime->private_data; 352 struct sof_intel_hda_stream *hda_stream; 353 354 hda_stream = container_of(hstream, 355 struct sof_intel_hda_stream, 356 hext_stream.hstream); 357 358 /* The stream might already be closed */ 359 if (!hstream) 360 return -ESTRPIPE; 361 362 sof_mailbox_read(sdev, hda_stream->sof_intel_stream.posn_offset, p, sz); 363 } 364 365 return 0; 366 } 367 368 int hda_set_stream_data_offset(struct snd_sof_dev *sdev, 369 struct snd_pcm_substream *substream, 370 size_t posn_offset) 371 { 372 struct hdac_stream *hstream = substream->runtime->private_data; 373 struct sof_intel_hda_stream *hda_stream; 374 375 hda_stream = container_of(hstream, struct sof_intel_hda_stream, 376 hext_stream.hstream); 377 378 /* check for unaligned offset or overflow */ 379 if (posn_offset > sdev->stream_box.size || 380 posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) 381 return -EINVAL; 382 383 hda_stream->sof_intel_stream.posn_offset = sdev->stream_box.offset + posn_offset; 384 385 dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", 386 substream->stream, hda_stream->sof_intel_stream.posn_offset); 387 388 return 0; 389 } 390