1 // SPDX-License-Identifier: (GPL-2.0 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
)) {
88 * memory windows are powered off before sending IPC reply,
89 * so we can't read the mailbox for CTX_SAVE reply.
92 reply
.hdr
.cmd
= SOF_IPC_GLB_REPLY
;
93 reply
.hdr
.size
= sizeof(reply
);
94 memcpy(msg
->reply_data
, &reply
, sizeof(reply
));
98 /* get IPC reply from DSP in the mailbox */
99 sof_mailbox_read(sdev
, sdev
->host_box
.offset
, &reply
,
102 if (reply
.error
< 0) {
103 memcpy(msg
->reply_data
, &reply
, sizeof(reply
));
106 /* reply correct size ? */
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
);
113 /* read the message */
114 if (msg
->reply_size
> 0)
115 sof_mailbox_read(sdev
, sdev
->host_box
.offset
,
116 msg
->reply_data
, msg
->reply_size
);
120 msg
->reply_error
= ret
;
124 static bool hda_dsp_ipc_is_sof(uint32_t msg
)
126 return (msg
& (HDA_DSP_IPC_PURGE_FW
| 0xf << 9)) != msg
||
127 (msg
& HDA_DSP_IPC_PURGE_FW
) != HDA_DSP_IPC_PURGE_FW
;
130 /* IPC handler thread */
131 irqreturn_t
hda_dsp_ipc_irq_thread(int irq
, void *context
)
133 struct snd_sof_dev
*sdev
= context
;
140 bool ipc_irq
= false;
142 /* read IPC status */
143 hipcie
= snd_sof_dsp_read(sdev
, HDA_DSP_BAR
,
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
);
149 /* is this a reply message from the DSP */
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
;
155 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
158 /* mask Done interrupt */
159 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
161 HDA_DSP_REG_HIPCCTL_DONE
, 0);
164 * Make sure the interrupt thread cannot be preempted between
165 * waking up the sender and re-enabling the interrupt. Also
166 * protect against a theoretical race with sof_ipc_tx_message():
167 * if the DSP is fast enough to receive an IPC message, reply to
168 * it, and the host interrupt processing calls this function on
169 * a different core from the one, where the sending is taking
170 * place, the message might not yet be marked as expecting a
173 spin_lock_irq(&sdev
->ipc_lock
);
175 /* handle immediate reply from DSP core - ignore ROM messages */
176 if (hda_dsp_ipc_is_sof(msg
)) {
177 hda_dsp_ipc_get_reply(sdev
);
178 snd_sof_ipc_reply(sdev
, msg
);
181 /* wake up sleeper if we are loading code */
182 if (sdev
->code_loading
) {
183 sdev
->code_loading
= 0;
184 wake_up(&sdev
->waitq
);
187 /* set the done bit */
188 hda_dsp_ipc_dsp_done(sdev
);
190 spin_unlock_irq(&sdev
->ipc_lock
);
195 /* is this a new message from DSP */
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
;
201 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
204 /* mask BUSY interrupt */
205 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
,
207 HDA_DSP_REG_HIPCCTL_BUSY
, 0);
209 /* handle messages from DSP */
210 if ((hipct
& SOF_IPC_PANIC_MAGIC_MASK
) == SOF_IPC_PANIC_MAGIC
) {
211 /* this is a PANIC message !! */
212 snd_sof_dsp_panic(sdev
, HDA_DSP_PANIC_OFFSET(msg_ext
));
214 /* normal message - process normally */
215 snd_sof_ipc_msgs_rx(sdev
);
218 hda_dsp_ipc_host_done(sdev
);
225 * This interrupt is not shared so no need to return IRQ_NONE.
227 dev_dbg_ratelimited(sdev
->dev
,
228 "nothing to do in IPC IRQ thread\n");
231 /* re-enable IPC interrupt */
232 snd_sof_dsp_update_bits(sdev
, HDA_DSP_BAR
, HDA_DSP_REG_ADSPIC
,
233 HDA_DSP_ADSPIC_IPC
, HDA_DSP_ADSPIC_IPC
);
238 /* is this IRQ for ADSP ? - we only care about IPC here */
239 irqreturn_t
hda_dsp_ipc_irq_handler(int irq
, void *context
)
241 struct snd_sof_dev
*sdev
= context
;
245 spin_lock(&sdev
->hw_lock
);
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
);
251 /* invalid message ? */
252 if (irq_status
== 0xffffffff)
256 if (irq_status
& HDA_DSP_ADSPIS_IPC
) {
257 /* disable IPC interrupt */
258 snd_sof_dsp_update_bits_unlocked(sdev
, HDA_DSP_BAR
,
260 HDA_DSP_ADSPIC_IPC
, 0);
261 ret
= IRQ_WAKE_THREAD
;
265 spin_unlock(&sdev
->hw_lock
);
269 int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev
*sdev
)
271 return HDA_DSP_MBOX_UPLINK_OFFSET
;
274 int hda_dsp_ipc_get_window_offset(struct snd_sof_dev
*sdev
, u32 id
)
276 return SRAM_WINDOW_OFFSET(id
);
279 void hda_ipc_msg_data(struct snd_sof_dev
*sdev
,
280 struct snd_pcm_substream
*substream
,
283 if (!substream
|| !sdev
->stream_box
.size
) {
284 sof_mailbox_read(sdev
, sdev
->dsp_box
.offset
, p
, sz
);
286 struct hdac_stream
*hstream
= substream
->runtime
->private_data
;
287 struct sof_intel_hda_stream
*hda_stream
;
289 hda_stream
= container_of(hstream
,
290 struct sof_intel_hda_stream
,
293 /* The stream might already be closed */
295 sof_mailbox_read(sdev
, hda_stream
->stream
.posn_offset
,
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
)
304 struct hdac_stream
*hstream
= substream
->runtime
->private_data
;
305 struct sof_intel_hda_stream
*hda_stream
;
306 /* validate offset */
307 size_t posn_offset
= reply
->posn_offset
;
309 hda_stream
= container_of(hstream
, struct sof_intel_hda_stream
,
312 /* check for unaligned offset or overflow */
313 if (posn_offset
> sdev
->stream_box
.size
||
314 posn_offset
% sizeof(struct sof_ipc_stream_posn
) != 0)
317 hda_stream
->stream
.posn_offset
= sdev
->stream_box
.offset
+ posn_offset
;
319 dev_dbg(sdev
->dev
, "pcm: stream dir %d, posn mailbox offset is %zu",
320 substream
->stream
, hda_stream
->stream
.posn_offset
);