Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license.  When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2018 Intel Corporation. All rights reserved.
0007 //
0008 // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
0009 //      Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
0010 //      Rander Wang <rander.wang@intel.com>
0011 //          Keyon Jie <yang.jie@linux.intel.com>
0012 //
0013 
0014 /*
0015  * Hardware interface for generic Intel audio DSP HDA IP
0016  */
0017 
0018 #include <sound/sof/ipc4/header.h>
0019 #include "../ops.h"
0020 #include "hda.h"
0021 
0022 static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev)
0023 {
0024     /*
0025      * tell DSP cmd is done - clear busy
0026      * interrupt and send reply msg to dsp
0027      */
0028     snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
0029                        HDA_DSP_REG_HIPCT,
0030                        HDA_DSP_REG_HIPCT_BUSY,
0031                        HDA_DSP_REG_HIPCT_BUSY);
0032 
0033     /* unmask BUSY interrupt */
0034     snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
0035                 HDA_DSP_REG_HIPCCTL,
0036                 HDA_DSP_REG_HIPCCTL_BUSY,
0037                 HDA_DSP_REG_HIPCCTL_BUSY);
0038 }
0039 
0040 static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev)
0041 {
0042     /*
0043      * set DONE bit - tell DSP we have received the reply msg
0044      * from DSP, and processed it, don't send more reply to host
0045      */
0046     snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
0047                        HDA_DSP_REG_HIPCIE,
0048                        HDA_DSP_REG_HIPCIE_DONE,
0049                        HDA_DSP_REG_HIPCIE_DONE);
0050 
0051     /* unmask Done interrupt */
0052     snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
0053                 HDA_DSP_REG_HIPCCTL,
0054                 HDA_DSP_REG_HIPCCTL_DONE,
0055                 HDA_DSP_REG_HIPCCTL_DONE);
0056 }
0057 
0058 int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
0059 {
0060     /* send IPC message to DSP */
0061     sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
0062               msg->msg_size);
0063     snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
0064               HDA_DSP_REG_HIPCI_BUSY);
0065 
0066     return 0;
0067 }
0068 
0069 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
0070 {
0071     struct sof_ipc4_msg *msg_data = msg->msg_data;
0072 
0073     /* send the message via mailbox */
0074     if (msg_data->data_size)
0075         sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
0076                   msg_data->data_size);
0077 
0078     snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE, msg_data->extension);
0079     snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
0080               msg_data->primary | HDA_DSP_REG_HIPCI_BUSY);
0081 
0082     return 0;
0083 }
0084 
0085 void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
0086 {
0087     struct snd_sof_ipc_msg *msg = sdev->msg;
0088     struct sof_ipc_reply reply;
0089     struct sof_ipc_cmd_hdr *hdr;
0090 
0091     /*
0092      * Sometimes, there is unexpected reply ipc arriving. The reply
0093      * ipc belongs to none of the ipcs sent from driver.
0094      * In this case, the driver must ignore the ipc.
0095      */
0096     if (!msg) {
0097         dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
0098         return;
0099     }
0100 
0101     hdr = msg->msg_data;
0102     if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) ||
0103         hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) {
0104         /*
0105          * memory windows are powered off before sending IPC reply,
0106          * so we can't read the mailbox for CTX_SAVE and PM_GATE
0107          * replies.
0108          */
0109         reply.error = 0;
0110         reply.hdr.cmd = SOF_IPC_GLB_REPLY;
0111         reply.hdr.size = sizeof(reply);
0112         memcpy(msg->reply_data, &reply, sizeof(reply));
0113 
0114         msg->reply_error = 0;
0115     } else {
0116         snd_sof_ipc_get_reply(sdev);
0117     }
0118 }
0119 
0120 irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
0121 {
0122     struct sof_ipc4_msg notification_data = {{ 0 }};
0123     struct snd_sof_dev *sdev = context;
0124     bool ipc_irq = false;
0125     u32 hipcie, hipct;
0126 
0127     hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
0128     if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
0129         /* DSP received the message */
0130         snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
0131                     HDA_DSP_REG_HIPCCTL_DONE, 0);
0132         hda_dsp_ipc_dsp_done(sdev);
0133 
0134         ipc_irq = true;
0135     }
0136 
0137     hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
0138     if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
0139         /* Message from DSP (reply or notification) */
0140         u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
0141                           HDA_DSP_REG_HIPCTE);
0142         u32 primary = hipct & HDA_DSP_REG_HIPCT_MSG_MASK;
0143         u32 extension = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK;
0144 
0145         /* mask BUSY interrupt */
0146         snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
0147                     HDA_DSP_REG_HIPCCTL_BUSY, 0);
0148 
0149         if (primary & SOF_IPC4_MSG_DIR_MASK) {
0150             /* Reply received */
0151             if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
0152                 struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
0153 
0154                 data->primary = primary;
0155                 data->extension = extension;
0156 
0157                 spin_lock_irq(&sdev->ipc_lock);
0158 
0159                 snd_sof_ipc_get_reply(sdev);
0160                 snd_sof_ipc_reply(sdev, data->primary);
0161 
0162                 spin_unlock_irq(&sdev->ipc_lock);
0163             } else {
0164                 dev_dbg_ratelimited(sdev->dev,
0165                             "IPC reply before FW_READY: %#x|%#x\n",
0166                             primary, extension);
0167             }
0168         } else {
0169             /* Notification received */
0170 
0171             notification_data.primary = primary;
0172             notification_data.extension = extension;
0173             sdev->ipc->msg.rx_data = &notification_data;
0174             snd_sof_ipc_msgs_rx(sdev);
0175             sdev->ipc->msg.rx_data = NULL;
0176         }
0177 
0178         /* Let DSP know that we have finished processing the message */
0179         hda_dsp_ipc_host_done(sdev);
0180 
0181         ipc_irq = true;
0182     }
0183 
0184     if (!ipc_irq)
0185         /* This interrupt is not shared so no need to return IRQ_NONE. */
0186         dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
0187 
0188     return IRQ_HANDLED;
0189 }
0190 
0191 /* IPC handler thread */
0192 irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
0193 {
0194     struct snd_sof_dev *sdev = context;
0195     u32 hipci;
0196     u32 hipcie;
0197     u32 hipct;
0198     u32 hipcte;
0199     u32 msg;
0200     u32 msg_ext;
0201     bool ipc_irq = false;
0202 
0203     /* read IPC status */
0204     hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
0205                   HDA_DSP_REG_HIPCIE);
0206     hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
0207     hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
0208     hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
0209 
0210     /* is this a reply message from the DSP */
0211     if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
0212         msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK;
0213         msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK;
0214 
0215         dev_vdbg(sdev->dev,
0216              "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
0217              msg, msg_ext);
0218 
0219         /* mask Done interrupt */
0220         snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
0221                     HDA_DSP_REG_HIPCCTL,
0222                     HDA_DSP_REG_HIPCCTL_DONE, 0);
0223 
0224         /*
0225          * Make sure the interrupt thread cannot be preempted between
0226          * waking up the sender and re-enabling the interrupt. Also
0227          * protect against a theoretical race with sof_ipc_tx_message():
0228          * if the DSP is fast enough to receive an IPC message, reply to
0229          * it, and the host interrupt processing calls this function on
0230          * a different core from the one, where the sending is taking
0231          * place, the message might not yet be marked as expecting a
0232          * reply.
0233          */
0234         if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
0235             spin_lock_irq(&sdev->ipc_lock);
0236 
0237             /* handle immediate reply from DSP core */
0238             hda_dsp_ipc_get_reply(sdev);
0239             snd_sof_ipc_reply(sdev, msg);
0240 
0241             /* set the done bit */
0242             hda_dsp_ipc_dsp_done(sdev);
0243 
0244             spin_unlock_irq(&sdev->ipc_lock);
0245         } else {
0246             dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
0247                         msg);
0248         }
0249 
0250         ipc_irq = true;
0251     }
0252 
0253     /* is this a new message from DSP */
0254     if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
0255         msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK;
0256         msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK;
0257 
0258         dev_vdbg(sdev->dev,
0259              "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
0260              msg, msg_ext);
0261 
0262         /* mask BUSY interrupt */
0263         snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
0264                     HDA_DSP_REG_HIPCCTL,
0265                     HDA_DSP_REG_HIPCCTL_BUSY, 0);
0266 
0267         /* handle messages from DSP */
0268         if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
0269             struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
0270             bool non_recoverable = true;
0271 
0272             /*
0273              * This is a PANIC message!
0274              *
0275              * If it is arriving during firmware boot and it is not
0276              * the last boot attempt then change the non_recoverable
0277              * to false as the DSP might be able to boot in the next
0278              * iteration(s)
0279              */
0280             if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS &&
0281                 hda->boot_iteration < HDA_FW_BOOT_ATTEMPTS)
0282                 non_recoverable = false;
0283 
0284             snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext),
0285                       non_recoverable);
0286         } else {
0287             /* normal message - process normally */
0288             snd_sof_ipc_msgs_rx(sdev);
0289         }
0290 
0291         hda_dsp_ipc_host_done(sdev);
0292 
0293         ipc_irq = true;
0294     }
0295 
0296     if (!ipc_irq) {
0297         /*
0298          * This interrupt is not shared so no need to return IRQ_NONE.
0299          */
0300         dev_dbg_ratelimited(sdev->dev,
0301                     "nothing to do in IPC IRQ thread\n");
0302     }
0303 
0304     return IRQ_HANDLED;
0305 }
0306 
0307 /* Check if an IPC IRQ occurred */
0308 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
0309 {
0310     bool ret = false;
0311     u32 irq_status;
0312 
0313     /* store status */
0314     irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
0315     dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
0316 
0317     /* invalid message ? */
0318     if (irq_status == 0xffffffff)
0319         goto out;
0320 
0321     /* IPC message ? */
0322     if (irq_status & HDA_DSP_ADSPIS_IPC)
0323         ret = true;
0324 
0325 out:
0326     return ret;
0327 }
0328 
0329 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
0330 {
0331     return HDA_DSP_MBOX_UPLINK_OFFSET;
0332 }
0333 
0334 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
0335 {
0336     return SRAM_WINDOW_OFFSET(id);
0337 }
0338 
0339 int hda_ipc_msg_data(struct snd_sof_dev *sdev,
0340              struct snd_pcm_substream *substream,
0341              void *p, size_t sz)
0342 {
0343     if (!substream || !sdev->stream_box.size) {
0344         sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
0345     } else {
0346         struct hdac_stream *hstream = substream->runtime->private_data;
0347         struct sof_intel_hda_stream *hda_stream;
0348 
0349         hda_stream = container_of(hstream,
0350                       struct sof_intel_hda_stream,
0351                       hext_stream.hstream);
0352 
0353         /* The stream might already be closed */
0354         if (!hstream)
0355             return -ESTRPIPE;
0356 
0357         sof_mailbox_read(sdev, hda_stream->sof_intel_stream.posn_offset, p, sz);
0358     }
0359 
0360     return 0;
0361 }
0362 
0363 int hda_set_stream_data_offset(struct snd_sof_dev *sdev,
0364                    struct snd_pcm_substream *substream,
0365                    size_t posn_offset)
0366 {
0367     struct hdac_stream *hstream = substream->runtime->private_data;
0368     struct sof_intel_hda_stream *hda_stream;
0369 
0370     hda_stream = container_of(hstream, struct sof_intel_hda_stream,
0371                   hext_stream.hstream);
0372 
0373     /* check for unaligned offset or overflow */
0374     if (posn_offset > sdev->stream_box.size ||
0375         posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
0376         return -EINVAL;
0377 
0378     hda_stream->sof_intel_stream.posn_offset = sdev->stream_box.offset + posn_offset;
0379 
0380     dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
0381         substream->stream, hda_stream->sof_intel_stream.posn_offset);
0382 
0383     return 0;
0384 }