This source file includes following definitions.
- hda_dsp_ipc_host_done
- hda_dsp_ipc_dsp_done
- hda_dsp_ipc_send_msg
- hda_dsp_ipc_get_reply
- hda_dsp_ipc_is_sof
- hda_dsp_ipc_irq_thread
- hda_dsp_ipc_irq_handler
- hda_dsp_ipc_get_mailbox_offset
- hda_dsp_ipc_get_window_offset
- hda_ipc_msg_data
- hda_ipc_pcm_params
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  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 
  25 
  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         
  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 
  43 
  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         
  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         
  60         sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
  61                           msg->msg_size);
  62         snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
  63                           HDA_DSP_REG_HIPCI_BUSY);
  64 
  65         return 0;
  66 }
  67 
  68 void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
  69 {
  70         struct snd_sof_ipc_msg *msg = sdev->msg;
  71         struct sof_ipc_reply reply;
  72         struct sof_ipc_cmd_hdr *hdr;
  73         int ret = 0;
  74 
  75         
  76 
  77 
  78 
  79 
  80         if (!msg) {
  81                 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
  82                 return;
  83         }
  84 
  85         hdr = msg->msg_data;
  86         if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) {
  87                 
  88 
  89 
  90 
  91                 reply.error = 0;
  92                 reply.hdr.cmd = SOF_IPC_GLB_REPLY;
  93                 reply.hdr.size = sizeof(reply);
  94                 memcpy(msg->reply_data, &reply, sizeof(reply));
  95                 goto out;
  96         }
  97 
  98         
  99         sof_mailbox_read(sdev, sdev->host_box.offset, &reply,
 100                          sizeof(reply));
 101 
 102         if (reply.error < 0) {
 103                 memcpy(msg->reply_data, &reply, sizeof(reply));
 104                 ret = reply.error;
 105         } else {
 106                 
 107                 if (reply.hdr.size != msg->reply_size) {
 108                         dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
 109                                 msg->reply_size, reply.hdr.size);
 110                         ret = -EINVAL;
 111                 }
 112 
 113                 
 114                 if (msg->reply_size > 0)
 115                         sof_mailbox_read(sdev, sdev->host_box.offset,
 116                                          msg->reply_data, msg->reply_size);
 117         }
 118 
 119 out:
 120         msg->reply_error = ret;
 121 
 122 }
 123 
 124 static bool hda_dsp_ipc_is_sof(uint32_t msg)
 125 {
 126         return (msg & (HDA_DSP_IPC_PURGE_FW | 0xf << 9)) != msg ||
 127                 (msg & HDA_DSP_IPC_PURGE_FW) != HDA_DSP_IPC_PURGE_FW;
 128 }
 129 
 130 
 131 irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
 132 {
 133         struct snd_sof_dev *sdev = context;
 134         u32 hipci;
 135         u32 hipcie;
 136         u32 hipct;
 137         u32 hipcte;
 138         u32 msg;
 139         u32 msg_ext;
 140         bool ipc_irq = false;
 141 
 142         
 143         hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
 144                                   HDA_DSP_REG_HIPCIE);
 145         hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
 146         hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
 147         hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
 148 
 149         
 150         if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
 151                 msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK;
 152                 msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK;
 153 
 154                 dev_vdbg(sdev->dev,
 155                          "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
 156                          msg, msg_ext);
 157 
 158                 
 159                 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
 160                                         HDA_DSP_REG_HIPCCTL,
 161                                         HDA_DSP_REG_HIPCCTL_DONE, 0);
 162 
 163                 
 164 
 165 
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173                 spin_lock_irq(&sdev->ipc_lock);
 174 
 175                 
 176                 if (hda_dsp_ipc_is_sof(msg)) {
 177                         hda_dsp_ipc_get_reply(sdev);
 178                         snd_sof_ipc_reply(sdev, msg);
 179                 }
 180 
 181                 
 182                 if (sdev->code_loading) {
 183                         sdev->code_loading = 0;
 184                         wake_up(&sdev->waitq);
 185                 }
 186 
 187                 
 188                 hda_dsp_ipc_dsp_done(sdev);
 189 
 190                 spin_unlock_irq(&sdev->ipc_lock);
 191 
 192                 ipc_irq = true;
 193         }
 194 
 195         
 196         if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
 197                 msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK;
 198                 msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK;
 199 
 200                 dev_vdbg(sdev->dev,
 201                          "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
 202                          msg, msg_ext);
 203 
 204                 
 205                 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
 206                                         HDA_DSP_REG_HIPCCTL,
 207                                         HDA_DSP_REG_HIPCCTL_BUSY, 0);
 208 
 209                 
 210                 if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
 211                         
 212                         snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
 213                 } else {
 214                         
 215                         snd_sof_ipc_msgs_rx(sdev);
 216                 }
 217 
 218                 hda_dsp_ipc_host_done(sdev);
 219 
 220                 ipc_irq = true;
 221         }
 222 
 223         if (!ipc_irq) {
 224                 
 225 
 226 
 227                 dev_dbg_ratelimited(sdev->dev,
 228                                     "nothing to do in IPC IRQ thread\n");
 229         }
 230 
 231         
 232         snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
 233                                 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
 234 
 235         return IRQ_HANDLED;
 236 }
 237 
 238 
 239 irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
 240 {
 241         struct snd_sof_dev *sdev = context;
 242         int ret = IRQ_NONE;
 243         u32 irq_status;
 244 
 245         spin_lock(&sdev->hw_lock);
 246 
 247         
 248         irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
 249         dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
 250 
 251         
 252         if (irq_status == 0xffffffff)
 253                 goto out;
 254 
 255         
 256         if (irq_status & HDA_DSP_ADSPIS_IPC) {
 257                 
 258                 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
 259                                                  HDA_DSP_REG_ADSPIC,
 260                                                  HDA_DSP_ADSPIC_IPC, 0);
 261                 ret = IRQ_WAKE_THREAD;
 262         }
 263 
 264 out:
 265         spin_unlock(&sdev->hw_lock);
 266         return ret;
 267 }
 268 
 269 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
 270 {
 271         return HDA_DSP_MBOX_UPLINK_OFFSET;
 272 }
 273 
 274 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
 275 {
 276         return SRAM_WINDOW_OFFSET(id);
 277 }
 278 
 279 void hda_ipc_msg_data(struct snd_sof_dev *sdev,
 280                       struct snd_pcm_substream *substream,
 281                       void *p, size_t sz)
 282 {
 283         if (!substream || !sdev->stream_box.size) {
 284                 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
 285         } else {
 286                 struct hdac_stream *hstream = substream->runtime->private_data;
 287                 struct sof_intel_hda_stream *hda_stream;
 288 
 289                 hda_stream = container_of(hstream,
 290                                           struct sof_intel_hda_stream,
 291                                           hda_stream.hstream);
 292 
 293                 
 294                 if (hstream)
 295                         sof_mailbox_read(sdev, hda_stream->stream.posn_offset,
 296                                          p, sz);
 297         }
 298 }
 299 
 300 int hda_ipc_pcm_params(struct snd_sof_dev *sdev,
 301                        struct snd_pcm_substream *substream,
 302                        const struct sof_ipc_pcm_params_reply *reply)
 303 {
 304         struct hdac_stream *hstream = substream->runtime->private_data;
 305         struct sof_intel_hda_stream *hda_stream;
 306         
 307         size_t posn_offset = reply->posn_offset;
 308 
 309         hda_stream = container_of(hstream, struct sof_intel_hda_stream,
 310                                   hda_stream.hstream);
 311 
 312         
 313         if (posn_offset > sdev->stream_box.size ||
 314             posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
 315                 return -EINVAL;
 316 
 317         hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset;
 318 
 319         dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
 320                 substream->stream, hda_stream->stream.posn_offset);
 321 
 322         return 0;
 323 }