1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
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>
15 * Hardware interface for generic Intel audio DSP HDA IP
21 static void hda_dsp_ipc_host_done(struct snd_sof_dev
*sdev
)
24 * tell DSP cmd is done - clear busy
25 * interrupt and send reply msg to dsp
27 snd_sof_dsp_update_bits_forced(sdev
, HDA_DSP_BAR
,
29 HDA_DSP_REG_HIPCT_BUSY
,
30 HDA_DSP_REG_HIPCT_BUSY
);
32 /* unmask BUSY interrupt */
33 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
35 HDA_DSP_REG_HIPCCTL_BUSY
,
36 HDA_DSP_REG_HIPCCTL_BUSY
);
39 static void hda_dsp_ipc_dsp_done(struct snd_sof_dev
*sdev
)
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
45 snd_sof_dsp_update_bits_forced(sdev
, HDA_DSP_BAR
,
47 HDA_DSP_REG_HIPCIE_DONE
,
48 HDA_DSP_REG_HIPCIE_DONE
);
50 /* unmask Done interrupt */
51 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
53 HDA_DSP_REG_HIPCCTL_DONE
,
54 HDA_DSP_REG_HIPCCTL_DONE
);
57 int hda_dsp_ipc_send_msg(struct snd_sof_dev
*sdev
, struct snd_sof_ipc_msg
*msg
)
59 /* send IPC message to DSP */
60 sof_mailbox_write(sdev
, sdev
->host_box
.offset
, msg
->msg_data
,
62 snd_sof_dsp_write(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_HIPCI
,
63 HDA_DSP_REG_HIPCI_BUSY
);
68 void hda_dsp_ipc_get_reply(struct snd_sof_dev
*sdev
)
70 struct snd_sof_ipc_msg
*msg
= sdev
->msg
;
71 struct sof_ipc_reply reply
;
72 struct sof_ipc_cmd_hdr
*hdr
;
76 * Sometimes, there is unexpected reply ipc arriving. The reply
77 * ipc belongs to none of the ipcs sent from driver.
78 * In this case, the driver must ignore the ipc.
81 dev_warn(sdev
->dev
, "unexpected ipc interrupt raised!\n");
86 if (hdr
->cmd
== (SOF_IPC_GLB_PM_MSG
| SOF_IPC_PM_CTX_SAVE
) ||
87 hdr
->cmd
== (SOF_IPC_GLB_PM_MSG
| SOF_IPC_PM_GATE
)) {
89 * memory windows are powered off before sending IPC reply,
90 * so we can't read the mailbox for CTX_SAVE and PM_GATE
94 reply
.hdr
.cmd
= SOF_IPC_GLB_REPLY
;
95 reply
.hdr
.size
= sizeof(reply
);
96 memcpy(msg
->reply_data
, &reply
, sizeof(reply
));
100 /* get IPC reply from DSP in the mailbox */
101 sof_mailbox_read(sdev
, sdev
->host_box
.offset
, &reply
,
104 if (reply
.error
< 0) {
105 memcpy(msg
->reply_data
, &reply
, sizeof(reply
));
108 /* reply correct size ? */
109 if (reply
.hdr
.size
!= msg
->reply_size
&&
110 /* getter payload is never known upfront */
111 !(reply
.hdr
.cmd
& SOF_IPC_GLB_PROBE
)) {
112 dev_err(sdev
->dev
, "error: reply expected %zu got %u bytes\n",
113 msg
->reply_size
, reply
.hdr
.size
);
117 /* read the message */
118 if (msg
->reply_size
> 0)
119 sof_mailbox_read(sdev
, sdev
->host_box
.offset
,
120 msg
->reply_data
, msg
->reply_size
);
124 msg
->reply_error
= ret
;
128 /* IPC handler thread */
129 irqreturn_t
hda_dsp_ipc_irq_thread(int irq
, void *context
)
131 struct snd_sof_dev
*sdev
= context
;
138 bool ipc_irq
= false;
140 /* read IPC status */
141 hipcie
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
,
143 hipct
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_HIPCT
);
144 hipci
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_HIPCI
);
145 hipcte
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_HIPCTE
);
147 /* is this a reply message from the DSP */
148 if (hipcie
& HDA_DSP_REG_HIPCIE_DONE
) {
149 msg
= hipci
& HDA_DSP_REG_HIPCI_MSG_MASK
;
150 msg_ext
= hipcie
& HDA_DSP_REG_HIPCIE_MSG_MASK
;
153 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
156 /* mask Done interrupt */
157 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
159 HDA_DSP_REG_HIPCCTL_DONE
, 0);
162 * Make sure the interrupt thread cannot be preempted between
163 * waking up the sender and re-enabling the interrupt. Also
164 * protect against a theoretical race with sof_ipc_tx_message():
165 * if the DSP is fast enough to receive an IPC message, reply to
166 * it, and the host interrupt processing calls this function on
167 * a different core from the one, where the sending is taking
168 * place, the message might not yet be marked as expecting a
171 spin_lock_irq(&sdev
->ipc_lock
);
173 /* handle immediate reply from DSP core */
174 hda_dsp_ipc_get_reply(sdev
);
175 snd_sof_ipc_reply(sdev
, msg
);
177 /* set the done bit */
178 hda_dsp_ipc_dsp_done(sdev
);
180 spin_unlock_irq(&sdev
->ipc_lock
);
185 /* is this a new message from DSP */
186 if (hipct
& HDA_DSP_REG_HIPCT_BUSY
) {
187 msg
= hipct
& HDA_DSP_REG_HIPCT_MSG_MASK
;
188 msg_ext
= hipcte
& HDA_DSP_REG_HIPCTE_MSG_MASK
;
191 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
194 /* mask BUSY interrupt */
195 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
197 HDA_DSP_REG_HIPCCTL_BUSY
, 0);
199 /* handle messages from DSP */
200 if ((hipct
& SOF_IPC_PANIC_MAGIC_MASK
) == SOF_IPC_PANIC_MAGIC
) {
201 /* this is a PANIC message !! */
202 snd_sof_dsp_panic(sdev
, HDA_DSP_PANIC_OFFSET(msg_ext
));
204 /* normal message - process normally */
205 snd_sof_ipc_msgs_rx(sdev
);
208 hda_dsp_ipc_host_done(sdev
);
215 * This interrupt is not shared so no need to return IRQ_NONE.
217 dev_dbg_ratelimited(sdev
->dev
,
218 "nothing to do in IPC IRQ thread\n");
224 /* Check if an IPC IRQ occurred */
225 bool hda_dsp_check_ipc_irq(struct snd_sof_dev
*sdev
)
231 irq_status
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_ADSPIS
);
232 dev_vdbg(sdev
->dev
, "irq handler: irq_status:0x%x\n", irq_status
);
234 /* invalid message ? */
235 if (irq_status
== 0xffffffff)
239 if (irq_status
& HDA_DSP_ADSPIS_IPC
)
246 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev
*sdev
)
248 return HDA_DSP_MBOX_UPLINK_OFFSET
;
251 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev
*sdev
, u32 id
)
253 return SRAM_WINDOW_OFFSET(id
);
256 void hda_ipc_msg_data(struct snd_sof_dev
*sdev
,
257 struct snd_pcm_substream
*substream
,
260 if (!substream
|| !sdev
->stream_box
.size
) {
261 sof_mailbox_read(sdev
, sdev
->dsp_box
.offset
, p
, sz
);
263 struct hdac_stream
*hstream
= substream
->runtime
->private_data
;
264 struct sof_intel_hda_stream
*hda_stream
;
266 hda_stream
= container_of(hstream
,
267 struct sof_intel_hda_stream
,
270 /* The stream might already be closed */
272 sof_mailbox_read(sdev
, hda_stream
->stream
.posn_offset
,
277 int hda_ipc_pcm_params(struct snd_sof_dev
*sdev
,
278 struct snd_pcm_substream
*substream
,
279 const struct sof_ipc_pcm_params_reply
*reply
)
281 struct hdac_stream
*hstream
= substream
->runtime
->private_data
;
282 struct sof_intel_hda_stream
*hda_stream
;
283 /* validate offset */
284 size_t posn_offset
= reply
->posn_offset
;
286 hda_stream
= container_of(hstream
, struct sof_intel_hda_stream
,
289 /* check for unaligned offset or overflow */
290 if (posn_offset
> sdev
->stream_box
.size
||
291 posn_offset
% sizeof(struct sof_ipc_stream_posn
) != 0)
294 hda_stream
->stream
.posn_offset
= sdev
->stream_box
.offset
+ posn_offset
;
296 dev_dbg(sdev
->dev
, "pcm: stream dir %d, posn mailbox offset is %zu",
297 substream
->stream
, hda_stream
->stream
.posn_offset
);