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