1064520e8SBard Liao // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2064520e8SBard Liao //
3064520e8SBard Liao // Copyright(c) 2022 Intel Corporation. All rights reserved.
4064520e8SBard Liao //
5064520e8SBard Liao // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
6064520e8SBard Liao //
7064520e8SBard Liao
8064520e8SBard Liao /*
9064520e8SBard Liao * Hardware interface for audio DSP on Meteorlake.
10064520e8SBard Liao */
11064520e8SBard Liao
12064520e8SBard Liao #include <linux/firmware.h>
13064520e8SBard Liao #include <sound/sof/ipc4/header.h>
14d272b657SBard Liao #include <trace/events/sof_intel.h>
15064520e8SBard Liao #include "../ipc4-priv.h"
16064520e8SBard Liao #include "../ops.h"
17064520e8SBard Liao #include "hda.h"
18064520e8SBard Liao #include "hda-ipc.h"
19064520e8SBard Liao #include "../sof-audio.h"
20064520e8SBard Liao #include "mtl.h"
21064520e8SBard Liao
22064520e8SBard Liao static const struct snd_sof_debugfs_map mtl_dsp_debugfs[] = {
23064520e8SBard Liao {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
24064520e8SBard Liao {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
25064520e8SBard Liao {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
26064520e8SBard Liao };
27064520e8SBard Liao
mtl_ipc_host_done(struct snd_sof_dev * sdev)28064520e8SBard Liao static void mtl_ipc_host_done(struct snd_sof_dev *sdev)
29064520e8SBard Liao {
30064520e8SBard Liao /*
31064520e8SBard Liao * clear busy interrupt to tell dsp controller this interrupt has been accepted,
32064520e8SBard Liao * not trigger it again
33064520e8SBard Liao */
34064520e8SBard Liao snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR,
35064520e8SBard Liao MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY);
36064520e8SBard Liao /*
37064520e8SBard Liao * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp
38064520e8SBard Liao */
39064520e8SBard Liao snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA,
40064520e8SBard Liao MTL_DSP_REG_HFIPCXTDA_BUSY, 0);
41064520e8SBard Liao }
42064520e8SBard Liao
mtl_ipc_dsp_done(struct snd_sof_dev * sdev)43064520e8SBard Liao static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev)
44064520e8SBard Liao {
45064520e8SBard Liao /*
46064520e8SBard Liao * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it,
47064520e8SBard Liao * don't send more reply to host
48064520e8SBard Liao */
49064520e8SBard Liao snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA,
50064520e8SBard Liao MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE);
51064520e8SBard Liao
52064520e8SBard Liao /* unmask Done interrupt */
53064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,
54064520e8SBard Liao MTL_DSP_REG_HFIPCXCTL_DONE, MTL_DSP_REG_HFIPCXCTL_DONE);
55064520e8SBard Liao }
56064520e8SBard Liao
57064520e8SBard Liao /* Check if an IPC IRQ occurred */
mtl_dsp_check_ipc_irq(struct snd_sof_dev * sdev)58730025cfSPierre-Louis Bossart bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
59064520e8SBard Liao {
60064520e8SBard Liao u32 irq_status;
61064520e8SBard Liao u32 hfintipptr;
62064520e8SBard Liao
63ef0128afSFred Oh if (sdev->dspless_mode_selected)
64ef0128afSFred Oh return false;
65ef0128afSFred Oh
66064520e8SBard Liao /* read Interrupt IP Pointer */
67064520e8SBard Liao hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
68064520e8SBard Liao irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);
69064520e8SBard Liao
70d272b657SBard Liao trace_sof_intel_hda_irq_ipc_check(sdev, irq_status);
71064520e8SBard Liao
72064520e8SBard Liao if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC))
73064520e8SBard Liao return true;
74064520e8SBard Liao
75064520e8SBard Liao return false;
76064520e8SBard Liao }
77064520e8SBard Liao
78064520e8SBard Liao /* Check if an SDW IRQ occurred */
mtl_dsp_check_sdw_irq(struct snd_sof_dev * sdev)79064520e8SBard Liao static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
80064520e8SBard Liao {
81064520e8SBard Liao u32 irq_status;
82064520e8SBard Liao u32 hfintipptr;
83064520e8SBard Liao
84064520e8SBard Liao /* read Interrupt IP Pointer */
85064520e8SBard Liao hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
86064520e8SBard Liao irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);
87064520e8SBard Liao
88064520e8SBard Liao if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_SDW))
89064520e8SBard Liao return true;
90064520e8SBard Liao
91064520e8SBard Liao return false;
92064520e8SBard Liao }
93064520e8SBard Liao
mtl_ipc_send_msg(struct snd_sof_dev * sdev,struct snd_sof_ipc_msg * msg)94c22d5327SPierre-Louis Bossart int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
95064520e8SBard Liao {
96483e4cdfSPeter Ujfalusi struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
97064520e8SBard Liao struct sof_ipc4_msg *msg_data = msg->msg_data;
98064520e8SBard Liao
99483e4cdfSPeter Ujfalusi if (hda_ipc4_tx_is_busy(sdev)) {
100483e4cdfSPeter Ujfalusi hdev->delayed_ipc_tx_msg = msg;
101483e4cdfSPeter Ujfalusi return 0;
102483e4cdfSPeter Ujfalusi }
103483e4cdfSPeter Ujfalusi
104483e4cdfSPeter Ujfalusi hdev->delayed_ipc_tx_msg = NULL;
105483e4cdfSPeter Ujfalusi
106064520e8SBard Liao /* send the message via mailbox */
107064520e8SBard Liao if (msg_data->data_size)
108064520e8SBard Liao sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
109064520e8SBard Liao msg_data->data_size);
110064520e8SBard Liao
111064520e8SBard Liao snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY,
112064520e8SBard Liao msg_data->extension);
113064520e8SBard Liao snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR,
114064520e8SBard Liao msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY);
115064520e8SBard Liao
1163e6b6ed3SRander Wang hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);
1173e6b6ed3SRander Wang
118064520e8SBard Liao return 0;
119064520e8SBard Liao }
120064520e8SBard Liao
mtl_enable_ipc_interrupts(struct snd_sof_dev * sdev)121730025cfSPierre-Louis Bossart void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
122064520e8SBard Liao {
123064520e8SBard Liao struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
124064520e8SBard Liao const struct sof_intel_dsp_desc *chip = hda->desc;
125064520e8SBard Liao
126ef0128afSFred Oh if (sdev->dspless_mode_selected)
127ef0128afSFred Oh return;
128ef0128afSFred Oh
129064520e8SBard Liao /* enable IPC DONE and BUSY interrupts */
130064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
131064520e8SBard Liao MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE,
132064520e8SBard Liao MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE);
133064520e8SBard Liao }
134064520e8SBard Liao
mtl_disable_ipc_interrupts(struct snd_sof_dev * sdev)135730025cfSPierre-Louis Bossart void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
136064520e8SBard Liao {
137064520e8SBard Liao struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
138064520e8SBard Liao const struct sof_intel_dsp_desc *chip = hda->desc;
139064520e8SBard Liao
140ef0128afSFred Oh if (sdev->dspless_mode_selected)
141ef0128afSFred Oh return;
142ef0128afSFred Oh
143064520e8SBard Liao /* disable IPC DONE and BUSY interrupts */
144064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
145064520e8SBard Liao MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
146064520e8SBard Liao }
147064520e8SBard Liao
mtl_enable_sdw_irq(struct snd_sof_dev * sdev,bool enable)148aa70a580SPierre-Louis Bossart static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
149aa70a580SPierre-Louis Bossart {
150aa70a580SPierre-Louis Bossart u32 hipcie;
151aa70a580SPierre-Louis Bossart u32 mask;
152aa70a580SPierre-Louis Bossart u32 val;
153aa70a580SPierre-Louis Bossart int ret;
154aa70a580SPierre-Louis Bossart
155ef0128afSFred Oh if (sdev->dspless_mode_selected)
156ef0128afSFred Oh return;
157ef0128afSFred Oh
158aa70a580SPierre-Louis Bossart /* Enable/Disable SoundWire interrupt */
159aa70a580SPierre-Louis Bossart mask = MTL_DSP_REG_HfSNDWIE_IE_MASK;
160aa70a580SPierre-Louis Bossart if (enable)
161aa70a580SPierre-Louis Bossart val = mask;
162aa70a580SPierre-Louis Bossart else
163aa70a580SPierre-Louis Bossart val = 0;
164aa70a580SPierre-Louis Bossart
165aa70a580SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val);
166aa70a580SPierre-Louis Bossart
167aa70a580SPierre-Louis Bossart /* check if operation was successful */
168aa70a580SPierre-Louis Bossart ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
169aa70a580SPierre-Louis Bossart (hipcie & mask) == val,
170aa70a580SPierre-Louis Bossart HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
171aa70a580SPierre-Louis Bossart if (ret < 0)
172aa70a580SPierre-Louis Bossart dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",
173aa70a580SPierre-Louis Bossart enable ? "enable" : "disable");
174aa70a580SPierre-Louis Bossart }
175aa70a580SPierre-Louis Bossart
mtl_enable_interrupts(struct snd_sof_dev * sdev,bool enable)176730025cfSPierre-Louis Bossart int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
177064520e8SBard Liao {
178064520e8SBard Liao u32 hfintipptr;
179064520e8SBard Liao u32 irqinten;
180064520e8SBard Liao u32 hipcie;
18100f4f338SPierre-Louis Bossart u32 mask;
18200f4f338SPierre-Louis Bossart u32 val;
183064520e8SBard Liao int ret;
184064520e8SBard Liao
185ef0128afSFred Oh if (sdev->dspless_mode_selected)
186ef0128afSFred Oh return 0;
187ef0128afSFred Oh
188064520e8SBard Liao /* read Interrupt IP Pointer */
189064520e8SBard Liao hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
190064520e8SBard Liao
19100f4f338SPierre-Louis Bossart /* Enable/Disable Host IPC and SOUNDWIRE */
19200f4f338SPierre-Louis Bossart mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
19300f4f338SPierre-Louis Bossart if (enable)
19400f4f338SPierre-Louis Bossart val = mask;
19500f4f338SPierre-Louis Bossart else
19600f4f338SPierre-Louis Bossart val = 0;
19700f4f338SPierre-Louis Bossart
19800f4f338SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val);
199064520e8SBard Liao
200064520e8SBard Liao /* check if operation was successful */
201064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
20200f4f338SPierre-Louis Bossart (irqinten & mask) == val,
203064520e8SBard Liao HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
204064520e8SBard Liao if (ret < 0) {
20500f4f338SPierre-Louis Bossart dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",
20600f4f338SPierre-Louis Bossart enable ? "enable" : "disable");
207064520e8SBard Liao return ret;
208064520e8SBard Liao }
209064520e8SBard Liao
21000f4f338SPierre-Louis Bossart /* Enable/Disable Host IPC interrupt*/
21100f4f338SPierre-Louis Bossart mask = MTL_DSP_REG_HfHIPCIE_IE_MASK;
21200f4f338SPierre-Louis Bossart if (enable)
21300f4f338SPierre-Louis Bossart val = mask;
21400f4f338SPierre-Louis Bossart else
21500f4f338SPierre-Louis Bossart val = 0;
21600f4f338SPierre-Louis Bossart
21700f4f338SPierre-Louis Bossart snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val);
218064520e8SBard Liao
219064520e8SBard Liao /* check if operation was successful */
220064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
22100f4f338SPierre-Louis Bossart (hipcie & mask) == val,
222064520e8SBard Liao HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
223064520e8SBard Liao if (ret < 0) {
22400f4f338SPierre-Louis Bossart dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",
22500f4f338SPierre-Louis Bossart enable ? "enable" : "disable");
226064520e8SBard Liao return ret;
227064520e8SBard Liao }
228064520e8SBard Liao
229064520e8SBard Liao return ret;
230064520e8SBard Liao }
231064520e8SBard Liao
232064520e8SBard Liao /* pre fw run operations */
mtl_dsp_pre_fw_run(struct snd_sof_dev * sdev)233c22d5327SPierre-Louis Bossart int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
234064520e8SBard Liao {
235f747eb86SYong Zhi struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
236064520e8SBard Liao u32 dsphfpwrsts;
237064520e8SBard Liao u32 dsphfdsscs;
238064520e8SBard Liao u32 cpa;
239064520e8SBard Liao u32 pgs;
240064520e8SBard Liao int ret;
241064520e8SBard Liao
242064520e8SBard Liao /* Set the DSP subsystem power on */
243064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
244064520e8SBard Liao MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK);
245064520e8SBard Liao
246064520e8SBard Liao /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
247064520e8SBard Liao usleep_range(1000, 1010);
248064520e8SBard Liao
249064520e8SBard Liao /* poll with timeout to check if operation successful */
250064520e8SBard Liao cpa = MTL_HFDSSCS_CPA_MASK;
251064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,
252064520e8SBard Liao (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
253064520e8SBard Liao HDA_DSP_RESET_TIMEOUT_US);
254064520e8SBard Liao if (ret < 0) {
255064520e8SBard Liao dev_err(sdev->dev, "failed to enable DSP subsystem\n");
256064520e8SBard Liao return ret;
257064520e8SBard Liao }
258064520e8SBard Liao
259064520e8SBard Liao /* Power up gated-DSP-0 domain in order to access the DSP shim register block. */
260064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
261064520e8SBard Liao MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);
262064520e8SBard Liao
263064520e8SBard Liao usleep_range(1000, 1010);
264064520e8SBard Liao
265064520e8SBard Liao /* poll with timeout to check if operation successful */
266064520e8SBard Liao pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;
267064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts,
268064520e8SBard Liao (dsphfpwrsts & pgs) == pgs,
269064520e8SBard Liao HDA_DSP_REG_POLL_INTERVAL_US,
270064520e8SBard Liao HDA_DSP_RESET_TIMEOUT_US);
271064520e8SBard Liao if (ret < 0)
272064520e8SBard Liao dev_err(sdev->dev, "failed to power up gated DSP domain\n");
273064520e8SBard Liao
274f747eb86SYong Zhi /* if SoundWire is used, make sure it is not power-gated */
275f747eb86SYong Zhi if (hdev->info.handle && hdev->info.link_mask > 0)
276418d2b2fSYong Zhi snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
277064520e8SBard Liao MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1));
278f747eb86SYong Zhi
279064520e8SBard Liao return ret;
280064520e8SBard Liao }
281064520e8SBard Liao
mtl_dsp_post_fw_run(struct snd_sof_dev * sdev)282c22d5327SPierre-Louis Bossart int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
283064520e8SBard Liao {
284064520e8SBard Liao int ret;
285064520e8SBard Liao
286064520e8SBard Liao if (sdev->first_boot) {
287064520e8SBard Liao struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
288064520e8SBard Liao
289064520e8SBard Liao ret = hda_sdw_startup(sdev);
290064520e8SBard Liao if (ret < 0) {
291064520e8SBard Liao dev_err(sdev->dev, "could not startup SoundWire links\n");
292064520e8SBard Liao return ret;
293064520e8SBard Liao }
294064520e8SBard Liao
295064520e8SBard Liao /* Check if IMR boot is usable */
296064520e8SBard Liao if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT))
297064520e8SBard Liao hdev->imrboot_supported = true;
298064520e8SBard Liao }
299064520e8SBard Liao
300064520e8SBard Liao hda_sdw_int_enable(sdev, true);
301064520e8SBard Liao return 0;
302064520e8SBard Liao }
303064520e8SBard Liao
mtl_dsp_dump(struct snd_sof_dev * sdev,u32 flags)304c22d5327SPierre-Louis Bossart void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
305064520e8SBard Liao {
306064520e8SBard Liao char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
307064520e8SBard Liao u32 romdbgsts;
308064520e8SBard Liao u32 romdbgerr;
309064520e8SBard Liao u32 fwsts;
310064520e8SBard Liao u32 fwlec;
311064520e8SBard Liao
312064520e8SBard Liao fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS);
313064520e8SBard Liao fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR);
314064520e8SBard Liao romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY);
315064520e8SBard Liao romdbgerr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY_ERROR);
316064520e8SBard Liao
317064520e8SBard Liao dev_err(sdev->dev, "ROM status: %#x, ROM error: %#x\n", fwsts, fwlec);
318064520e8SBard Liao dev_err(sdev->dev, "ROM debug status: %#x, ROM debug error: %#x\n", romdbgsts,
319064520e8SBard Liao romdbgerr);
320064520e8SBard Liao romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY + 0x8 * 3);
321064520e8SBard Liao dev_printk(level, sdev->dev, "ROM feature bit%s enabled\n",
322064520e8SBard Liao romdbgsts & BIT(24) ? "" : " not");
323064520e8SBard Liao }
324064520e8SBard Liao
mtl_dsp_primary_core_is_enabled(struct snd_sof_dev * sdev)325064520e8SBard Liao static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
326064520e8SBard Liao {
327064520e8SBard Liao int val;
328064520e8SBard Liao
329064520e8SBard Liao val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE);
330064520e8SBard Liao if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK)
331064520e8SBard Liao return true;
332064520e8SBard Liao
333064520e8SBard Liao return false;
334064520e8SBard Liao }
335064520e8SBard Liao
mtl_dsp_core_power_up(struct snd_sof_dev * sdev,int core)336064520e8SBard Liao static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
337064520e8SBard Liao {
338064520e8SBard Liao unsigned int cpa;
339064520e8SBard Liao u32 dspcxctl;
340064520e8SBard Liao int ret;
341064520e8SBard Liao
342064520e8SBard Liao /* Only the primary core can be powered up by the host */
343064520e8SBard Liao if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev))
344064520e8SBard Liao return 0;
345064520e8SBard Liao
346064520e8SBard Liao /* Program the owner of the IP & shim registers (10: Host CPU) */
347064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
348064520e8SBard Liao MTL_DSP2CXCTL_PRIMARY_CORE_OSEL,
349064520e8SBard Liao 0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT);
350064520e8SBard Liao
351064520e8SBard Liao /* enable SPA bit */
352064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
353064520e8SBard Liao MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK,
354064520e8SBard Liao MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK);
355064520e8SBard Liao
356064520e8SBard Liao /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
357064520e8SBard Liao usleep_range(1000, 1010);
358064520e8SBard Liao
359064520e8SBard Liao /* poll with timeout to check if operation successful */
360064520e8SBard Liao cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK;
361064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
362064520e8SBard Liao (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
363064520e8SBard Liao HDA_DSP_RESET_TIMEOUT_US);
364fd4e9e9bSRander Wang if (ret < 0) {
365064520e8SBard Liao dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
366064520e8SBard Liao __func__);
367064520e8SBard Liao return ret;
368064520e8SBard Liao }
369064520e8SBard Liao
370fd4e9e9bSRander Wang /* set primary core mask and refcount to 1 */
371fd4e9e9bSRander Wang sdev->enabled_cores_mask = BIT(SOF_DSP_PRIMARY_CORE);
372fd4e9e9bSRander Wang sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 1;
373fd4e9e9bSRander Wang
374fd4e9e9bSRander Wang return 0;
375fd4e9e9bSRander Wang }
376fd4e9e9bSRander Wang
mtl_dsp_core_power_down(struct snd_sof_dev * sdev,int core)377064520e8SBard Liao static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
378064520e8SBard Liao {
379064520e8SBard Liao u32 dspcxctl;
380064520e8SBard Liao int ret;
381064520e8SBard Liao
382064520e8SBard Liao /* Only the primary core can be powered down by the host */
383064520e8SBard Liao if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev))
384064520e8SBard Liao return 0;
385064520e8SBard Liao
386064520e8SBard Liao /* disable SPA bit */
387064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
388064520e8SBard Liao MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);
389064520e8SBard Liao
390514bc59bSYong Zhi /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
391064520e8SBard Liao usleep_range(1000, 1010);
392064520e8SBard Liao
393064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
394064520e8SBard Liao !(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK),
395064520e8SBard Liao HDA_DSP_REG_POLL_INTERVAL_US,
396064520e8SBard Liao HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
397fd4e9e9bSRander Wang if (ret < 0) {
398064520e8SBard Liao dev_err(sdev->dev, "failed to power down primary core\n");
399064520e8SBard Liao return ret;
400064520e8SBard Liao }
401064520e8SBard Liao
402fd4e9e9bSRander Wang sdev->enabled_cores_mask = 0;
403fd4e9e9bSRander Wang sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 0;
404fd4e9e9bSRander Wang
405fd4e9e9bSRander Wang return 0;
406fd4e9e9bSRander Wang }
407fd4e9e9bSRander Wang
mtl_power_down_dsp(struct snd_sof_dev * sdev)408730025cfSPierre-Louis Bossart int mtl_power_down_dsp(struct snd_sof_dev *sdev)
4092090cb9bSFred Oh {
4102090cb9bSFred Oh u32 dsphfdsscs, cpa;
4112090cb9bSFred Oh int ret;
4122090cb9bSFred Oh
4132090cb9bSFred Oh /* first power down core */
4142090cb9bSFred Oh ret = mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
4152090cb9bSFred Oh if (ret) {
4162090cb9bSFred Oh dev_err(sdev->dev, "mtl dsp power down error, %d\n", ret);
4172090cb9bSFred Oh return ret;
4182090cb9bSFred Oh }
4192090cb9bSFred Oh
4202090cb9bSFred Oh /* Set the DSP subsystem power down */
4212090cb9bSFred Oh snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
4222090cb9bSFred Oh MTL_HFDSSCS_SPA_MASK, 0);
4232090cb9bSFred Oh
424514bc59bSYong Zhi /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */
4252090cb9bSFred Oh usleep_range(1000, 1010);
4262090cb9bSFred Oh
4272090cb9bSFred Oh /* poll with timeout to check if operation successful */
4282090cb9bSFred Oh cpa = MTL_HFDSSCS_CPA_MASK;
4292090cb9bSFred Oh dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
4302090cb9bSFred Oh return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,
4312090cb9bSFred Oh (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US,
4322090cb9bSFred Oh HDA_DSP_RESET_TIMEOUT_US);
4332090cb9bSFred Oh }
4342090cb9bSFred Oh
mtl_dsp_cl_init(struct snd_sof_dev * sdev,int stream_tag,bool imr_boot)435730025cfSPierre-Louis Bossart int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
436064520e8SBard Liao {
437064520e8SBard Liao struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
438064520e8SBard Liao const struct sof_intel_dsp_desc *chip = hda->desc;
439*28049d5aSPeter Ujfalusi unsigned int status, target_status;
44002be4ce0SYong Zhi u32 ipc_hdr, flags;
44102be4ce0SYong Zhi char *dump_msg;
442064520e8SBard Liao int ret;
443064520e8SBard Liao
444064520e8SBard Liao /* step 1: purge FW request */
445064520e8SBard Liao ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;
446064520e8SBard Liao if (!imr_boot)
447064520e8SBard Liao ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9);
448064520e8SBard Liao
449064520e8SBard Liao snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
450064520e8SBard Liao
451064520e8SBard Liao /* step 2: power up primary core */
452064520e8SBard Liao ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);
453064520e8SBard Liao if (ret < 0) {
454064520e8SBard Liao if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
455064520e8SBard Liao dev_err(sdev->dev, "dsp core 0/1 power up failed\n");
456064520e8SBard Liao goto err;
457064520e8SBard Liao }
458064520e8SBard Liao
459064520e8SBard Liao dev_dbg(sdev->dev, "Primary core power up successful\n");
460064520e8SBard Liao
461064520e8SBard Liao /* step 3: wait for IPC DONE bit from ROM */
462064520e8SBard Liao ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,
463064520e8SBard Liao ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),
464e0f96246SRanjani Sridharan HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_INIT_TIMEOUT_US);
465064520e8SBard Liao if (ret < 0) {
466064520e8SBard Liao if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
467064520e8SBard Liao dev_err(sdev->dev, "timeout waiting for purge IPC done\n");
468064520e8SBard Liao goto err;
469064520e8SBard Liao }
470064520e8SBard Liao
471064520e8SBard Liao /* set DONE bit to clear the reply IPC message */
472064520e8SBard Liao snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask,
473064520e8SBard Liao chip->ipc_ack_mask);
474064520e8SBard Liao
475064520e8SBard Liao /* step 4: enable interrupts */
47600f4f338SPierre-Louis Bossart ret = mtl_enable_interrupts(sdev, true);
477064520e8SBard Liao if (ret < 0) {
478064520e8SBard Liao if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
479064520e8SBard Liao dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__);
480064520e8SBard Liao goto err;
481064520e8SBard Liao }
482064520e8SBard Liao
483064520e8SBard Liao mtl_enable_ipc_interrupts(sdev);
484064520e8SBard Liao
485*28049d5aSPeter Ujfalusi if (chip->rom_status_reg == MTL_DSP_ROM_STS) {
486064520e8SBard Liao /*
487*28049d5aSPeter Ujfalusi * Workaround: when the ROM status register is pointing to
488*28049d5aSPeter Ujfalusi * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch
489*28049d5aSPeter Ujfalusi * ROM_INIT_DONE because of a very short timing window.
490*28049d5aSPeter Ujfalusi * Follow the recommendations and skip target state waiting.
491064520e8SBard Liao */
492064520e8SBard Liao return 0;
493*28049d5aSPeter Ujfalusi }
494*28049d5aSPeter Ujfalusi
495*28049d5aSPeter Ujfalusi /*
496*28049d5aSPeter Ujfalusi * step 7:
497*28049d5aSPeter Ujfalusi * - Cold/Full boot: wait for ROM init to proceed to download the firmware
498*28049d5aSPeter Ujfalusi * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)
499*28049d5aSPeter Ujfalusi */
500*28049d5aSPeter Ujfalusi if (imr_boot)
501*28049d5aSPeter Ujfalusi target_status = FSR_STATE_FW_ENTERED;
502*28049d5aSPeter Ujfalusi else
503*28049d5aSPeter Ujfalusi target_status = FSR_STATE_INIT_DONE;
504*28049d5aSPeter Ujfalusi
505*28049d5aSPeter Ujfalusi ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
506*28049d5aSPeter Ujfalusi chip->rom_status_reg, status,
507*28049d5aSPeter Ujfalusi (FSR_TO_STATE_CODE(status) == target_status),
508*28049d5aSPeter Ujfalusi HDA_DSP_REG_POLL_INTERVAL_US,
509*28049d5aSPeter Ujfalusi chip->rom_init_timeout *
510*28049d5aSPeter Ujfalusi USEC_PER_MSEC);
511*28049d5aSPeter Ujfalusi
512*28049d5aSPeter Ujfalusi if (!ret)
513*28049d5aSPeter Ujfalusi return 0;
514*28049d5aSPeter Ujfalusi
515*28049d5aSPeter Ujfalusi if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
516*28049d5aSPeter Ujfalusi dev_err(sdev->dev,
517*28049d5aSPeter Ujfalusi "%s: timeout with rom_status_reg (%#x) read\n",
518*28049d5aSPeter Ujfalusi __func__, chip->rom_status_reg);
519064520e8SBard Liao
520064520e8SBard Liao err:
52102be4ce0SYong Zhi flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
52202be4ce0SYong Zhi
52302be4ce0SYong Zhi /* after max boot attempts make sure that the dump is printed */
52402be4ce0SYong Zhi if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
52502be4ce0SYong Zhi flags &= ~SOF_DBG_DUMP_OPTIONAL;
52602be4ce0SYong Zhi
52702be4ce0SYong Zhi dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
52802be4ce0SYong Zhi hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
52902be4ce0SYong Zhi snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
530f0bf72d1SPeter Ujfalusi mtl_enable_interrupts(sdev, false);
531064520e8SBard Liao mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
53202be4ce0SYong Zhi
53302be4ce0SYong Zhi kfree(dump_msg);
534064520e8SBard Liao return ret;
535064520e8SBard Liao }
536064520e8SBard Liao
mtl_ipc_irq_thread(int irq,void * context)537c22d5327SPierre-Louis Bossart irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
538064520e8SBard Liao {
539064520e8SBard Liao struct sof_ipc4_msg notification_data = {{ 0 }};
540064520e8SBard Liao struct snd_sof_dev *sdev = context;
541483e4cdfSPeter Ujfalusi bool ack_received = false;
542064520e8SBard Liao bool ipc_irq = false;
543064520e8SBard Liao u32 hipcida;
544064520e8SBard Liao u32 hipctdr;
545064520e8SBard Liao
546064520e8SBard Liao hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
547c8ed7ce2SPeter Ujfalusi hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
548064520e8SBard Liao
549064520e8SBard Liao /* reply message from DSP */
550064520e8SBard Liao if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {
551064520e8SBard Liao /* DSP received the message */
552064520e8SBard Liao snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,
553064520e8SBard Liao MTL_DSP_REG_HFIPCXCTL_DONE, 0);
554064520e8SBard Liao
555064520e8SBard Liao mtl_ipc_dsp_done(sdev);
556064520e8SBard Liao
557064520e8SBard Liao ipc_irq = true;
558483e4cdfSPeter Ujfalusi ack_received = true;
559064520e8SBard Liao }
560064520e8SBard Liao
561064520e8SBard Liao if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
562064520e8SBard Liao /* Message from DSP (reply or notification) */
563064520e8SBard Liao u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
564064520e8SBard Liao u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK;
565064520e8SBard Liao
566064520e8SBard Liao /*
567064520e8SBard Liao * ACE fw sends a new fw ipc message to host to
568064520e8SBard Liao * notify the status of the last host ipc message
569064520e8SBard Liao */
570064520e8SBard Liao if (primary & SOF_IPC4_MSG_DIR_MASK) {
571064520e8SBard Liao /* Reply received */
5721549a69bSPeter Ujfalusi if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
573064520e8SBard Liao struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
574064520e8SBard Liao
575064520e8SBard Liao data->primary = primary;
576064520e8SBard Liao data->extension = extension;
577064520e8SBard Liao
578064520e8SBard Liao spin_lock_irq(&sdev->ipc_lock);
579064520e8SBard Liao
580064520e8SBard Liao snd_sof_ipc_get_reply(sdev);
581010c050fSPeter Ujfalusi mtl_ipc_host_done(sdev);
582064520e8SBard Liao snd_sof_ipc_reply(sdev, data->primary);
583064520e8SBard Liao
584064520e8SBard Liao spin_unlock_irq(&sdev->ipc_lock);
585064520e8SBard Liao } else {
5861549a69bSPeter Ujfalusi dev_dbg_ratelimited(sdev->dev,
5871549a69bSPeter Ujfalusi "IPC reply before FW_READY: %#x|%#x\n",
5881549a69bSPeter Ujfalusi primary, extension);
5891549a69bSPeter Ujfalusi }
5901549a69bSPeter Ujfalusi } else {
591064520e8SBard Liao /* Notification received */
592064520e8SBard Liao notification_data.primary = primary;
593064520e8SBard Liao notification_data.extension = extension;
594064520e8SBard Liao
595064520e8SBard Liao sdev->ipc->msg.rx_data = ¬ification_data;
596064520e8SBard Liao snd_sof_ipc_msgs_rx(sdev);
597064520e8SBard Liao sdev->ipc->msg.rx_data = NULL;
598064520e8SBard Liao
599064520e8SBard Liao mtl_ipc_host_done(sdev);
600010c050fSPeter Ujfalusi }
601064520e8SBard Liao
602064520e8SBard Liao ipc_irq = true;
603064520e8SBard Liao }
604064520e8SBard Liao
605064520e8SBard Liao if (!ipc_irq) {
606064520e8SBard Liao /* This interrupt is not shared so no need to return IRQ_NONE. */
607b837870fSPierre-Louis Bossart dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
608064520e8SBard Liao }
609064520e8SBard Liao
610483e4cdfSPeter Ujfalusi if (ack_received) {
611483e4cdfSPeter Ujfalusi struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
612483e4cdfSPeter Ujfalusi
613483e4cdfSPeter Ujfalusi if (hdev->delayed_ipc_tx_msg)
614483e4cdfSPeter Ujfalusi mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);
615483e4cdfSPeter Ujfalusi }
616483e4cdfSPeter Ujfalusi
617064520e8SBard Liao return IRQ_HANDLED;
618064520e8SBard Liao }
619064520e8SBard Liao
mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev * sdev)620c22d5327SPierre-Louis Bossart int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
621064520e8SBard Liao {
622064520e8SBard Liao return MTL_DSP_MBOX_UPLINK_OFFSET;
623064520e8SBard Liao }
624064520e8SBard Liao
mtl_dsp_ipc_get_window_offset(struct snd_sof_dev * sdev,u32 id)625c22d5327SPierre-Louis Bossart int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
626064520e8SBard Liao {
627064520e8SBard Liao return MTL_SRAM_WINDOW_OFFSET(id);
628064520e8SBard Liao }
629064520e8SBard Liao
mtl_ipc_dump(struct snd_sof_dev * sdev)630c22d5327SPierre-Louis Bossart void mtl_ipc_dump(struct snd_sof_dev *sdev)
631064520e8SBard Liao {
632d01784eeSPeter Ujfalusi u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
633064520e8SBard Liao
634d01784eeSPeter Ujfalusi hipcidr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR);
635d01784eeSPeter Ujfalusi hipcidd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY);
636064520e8SBard Liao hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
637064520e8SBard Liao hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
638d01784eeSPeter Ujfalusi hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
639d01784eeSPeter Ujfalusi hipctda = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA);
640d01784eeSPeter Ujfalusi hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL);
641064520e8SBard Liao
642064520e8SBard Liao dev_err(sdev->dev,
643d01784eeSPeter Ujfalusi "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n",
644d01784eeSPeter Ujfalusi hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl);
645064520e8SBard Liao }
646064520e8SBard Liao
mtl_dsp_disable_interrupts(struct snd_sof_dev * sdev)64739df087fSRanjani Sridharan static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
64839df087fSRanjani Sridharan {
649aa70a580SPierre-Louis Bossart mtl_enable_sdw_irq(sdev, false);
65039df087fSRanjani Sridharan mtl_disable_ipc_interrupts(sdev);
65100f4f338SPierre-Louis Bossart return mtl_enable_interrupts(sdev, false);
65239df087fSRanjani Sridharan }
65339df087fSRanjani Sridharan
mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev * sdev,struct snd_soc_component * component,struct snd_pcm_substream * substream)654c22d5327SPierre-Louis Bossart u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
655faceb344SRander Wang struct snd_soc_component *component,
656faceb344SRander Wang struct snd_pcm_substream *substream)
657faceb344SRander Wang {
658faceb344SRander Wang struct hdac_stream *hstream = substream->runtime->private_data;
659faceb344SRander Wang u32 llp_l, llp_u;
660faceb344SRander Wang
661faceb344SRander Wang llp_l = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPL(hstream->index));
662faceb344SRander Wang llp_u = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPU(hstream->index));
663faceb344SRander Wang return ((u64)llp_u << 32) | llp_l;
664faceb344SRander Wang }
665faceb344SRander Wang
mtl_dsp_core_get(struct snd_sof_dev * sdev,int core)666c6d15567SRander Wang static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
667c6d15567SRander Wang {
668c6d15567SRander Wang const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
669c6d15567SRander Wang
670c6d15567SRander Wang if (core == SOF_DSP_PRIMARY_CORE)
671c6d15567SRander Wang return mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);
672c6d15567SRander Wang
673c6d15567SRander Wang if (pm_ops->set_core_state)
674c6d15567SRander Wang return pm_ops->set_core_state(sdev, core, true);
675c6d15567SRander Wang
676c6d15567SRander Wang return 0;
677c6d15567SRander Wang }
678c6d15567SRander Wang
mtl_dsp_core_put(struct snd_sof_dev * sdev,int core)679c6d15567SRander Wang static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
680c6d15567SRander Wang {
681c6d15567SRander Wang const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
682c6d15567SRander Wang int ret;
683c6d15567SRander Wang
684c6d15567SRander Wang if (pm_ops->set_core_state) {
685c6d15567SRander Wang ret = pm_ops->set_core_state(sdev, core, false);
686c6d15567SRander Wang if (ret < 0)
687c6d15567SRander Wang return ret;
688c6d15567SRander Wang }
689c6d15567SRander Wang
690c6d15567SRander Wang if (core == SOF_DSP_PRIMARY_CORE)
691c6d15567SRander Wang return mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
692c6d15567SRander Wang
693c6d15567SRander Wang return 0;
694c6d15567SRander Wang }
695c6d15567SRander Wang
696064520e8SBard Liao /* Meteorlake ops */
697064520e8SBard Liao struct snd_sof_dsp_ops sof_mtl_ops;
698064520e8SBard Liao EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
699064520e8SBard Liao
sof_mtl_ops_init(struct snd_sof_dev * sdev)700064520e8SBard Liao int sof_mtl_ops_init(struct snd_sof_dev *sdev)
701064520e8SBard Liao {
702064520e8SBard Liao struct sof_ipc4_fw_data *ipc4_data;
703064520e8SBard Liao
704064520e8SBard Liao /* common defaults */
705064520e8SBard Liao memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
706064520e8SBard Liao
707064520e8SBard Liao /* shutdown */
708064520e8SBard Liao sof_mtl_ops.shutdown = hda_dsp_shutdown;
709064520e8SBard Liao
710064520e8SBard Liao /* doorbell */
711064520e8SBard Liao sof_mtl_ops.irq_thread = mtl_ipc_irq_thread;
712064520e8SBard Liao
713064520e8SBard Liao /* ipc */
714064520e8SBard Liao sof_mtl_ops.send_msg = mtl_ipc_send_msg;
715064520e8SBard Liao sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
716064520e8SBard Liao sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
717064520e8SBard Liao
718064520e8SBard Liao /* debug */
719064520e8SBard Liao sof_mtl_ops.debug_map = mtl_dsp_debugfs;
720064520e8SBard Liao sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
721064520e8SBard Liao sof_mtl_ops.dbg_dump = mtl_dsp_dump;
722064520e8SBard Liao sof_mtl_ops.ipc_dump = mtl_ipc_dump;
723064520e8SBard Liao
724064520e8SBard Liao /* pre/post fw run */
725064520e8SBard Liao sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
726064520e8SBard Liao sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run;
727064520e8SBard Liao
728064520e8SBard Liao /* parse platform specific extended manifest */
729064520e8SBard Liao sof_mtl_ops.parse_platform_ext_manifest = NULL;
730064520e8SBard Liao
731064520e8SBard Liao /* dsp core get/put */
732c6d15567SRander Wang sof_mtl_ops.core_get = mtl_dsp_core_get;
733c6d15567SRander Wang sof_mtl_ops.core_put = mtl_dsp_core_put;
734064520e8SBard Liao
735faceb344SRander Wang sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
736faceb344SRander Wang
737064520e8SBard Liao sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
738064520e8SBard Liao if (!sdev->private)
739064520e8SBard Liao return -ENOMEM;
740064520e8SBard Liao
741064520e8SBard Liao ipc4_data = sdev->private;
742064520e8SBard Liao ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
743064520e8SBard Liao
744cc4a3a19SPeter Ujfalusi ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
745cc4a3a19SPeter Ujfalusi
7463ab2c21eSPeter Ujfalusi /* External library loading support */
7473ab2c21eSPeter Ujfalusi ipc4_data->load_library = hda_dsp_ipc4_load_library;
7483ab2c21eSPeter Ujfalusi
749064520e8SBard Liao /* set DAI ops */
750064520e8SBard Liao hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
751064520e8SBard Liao
752996b07efSRanjani Sridharan sof_mtl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
753996b07efSRanjani Sridharan
754064520e8SBard Liao return 0;
755064520e8SBard Liao };
756064520e8SBard Liao EXPORT_SYMBOL_NS(sof_mtl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
757064520e8SBard Liao
758064520e8SBard Liao const struct sof_intel_dsp_desc mtl_chip_info = {
759064520e8SBard Liao .cores_num = 3,
760064520e8SBard Liao .init_core_mask = BIT(0),
761064520e8SBard Liao .host_managed_cores_mask = BIT(0),
762064520e8SBard Liao .ipc_req = MTL_DSP_REG_HFIPCXIDR,
763064520e8SBard Liao .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
764064520e8SBard Liao .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
765064520e8SBard Liao .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
766064520e8SBard Liao .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
7678aeb3dc8SPeter Ujfalusi .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,
768064520e8SBard Liao .rom_init_timeout = 300,
7699ccbc2e1SPierre-Louis Bossart .ssp_count = MTL_SSP_COUNT,
770064520e8SBard Liao .ssp_base_offset = CNL_SSP_BASE_OFFSET,
771064520e8SBard Liao .sdw_shim_base = SDW_SHIM_BASE_ACE,
772064520e8SBard Liao .sdw_alh_base = SDW_ALH_BASE_ACE,
773f8632adcSRander Wang .d0i3_offset = MTL_HDA_VS_D0I3C,
774625339caSPierre-Louis Bossart .read_sdw_lcount = hda_sdw_check_lcount_common,
775aa70a580SPierre-Louis Bossart .enable_sdw_irq = mtl_enable_sdw_irq,
776064520e8SBard Liao .check_sdw_irq = mtl_dsp_check_sdw_irq,
7779362ab78SPierre-Louis Bossart .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
778064520e8SBard Liao .check_ipc_irq = mtl_dsp_check_ipc_irq,
779064520e8SBard Liao .cl_init = mtl_dsp_cl_init,
7802090cb9bSFred Oh .power_down_dsp = mtl_power_down_dsp,
78139df087fSRanjani Sridharan .disable_interrupts = mtl_dsp_disable_interrupts,
782064520e8SBard Liao .hw_ip_version = SOF_INTEL_ACE_1_0,
783064520e8SBard Liao };
784064520e8SBard Liao EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
785368017b1SPierre-Louis Bossart
786368017b1SPierre-Louis Bossart const struct sof_intel_dsp_desc arl_s_chip_info = {
787368017b1SPierre-Louis Bossart .cores_num = 2,
788368017b1SPierre-Louis Bossart .init_core_mask = BIT(0),
789368017b1SPierre-Louis Bossart .host_managed_cores_mask = BIT(0),
790368017b1SPierre-Louis Bossart .ipc_req = MTL_DSP_REG_HFIPCXIDR,
791368017b1SPierre-Louis Bossart .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
792368017b1SPierre-Louis Bossart .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
793368017b1SPierre-Louis Bossart .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
794368017b1SPierre-Louis Bossart .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
7958aeb3dc8SPeter Ujfalusi .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,
796368017b1SPierre-Louis Bossart .rom_init_timeout = 300,
797368017b1SPierre-Louis Bossart .ssp_count = MTL_SSP_COUNT,
798368017b1SPierre-Louis Bossart .ssp_base_offset = CNL_SSP_BASE_OFFSET,
799368017b1SPierre-Louis Bossart .sdw_shim_base = SDW_SHIM_BASE_ACE,
800368017b1SPierre-Louis Bossart .sdw_alh_base = SDW_ALH_BASE_ACE,
801368017b1SPierre-Louis Bossart .d0i3_offset = MTL_HDA_VS_D0I3C,
802368017b1SPierre-Louis Bossart .read_sdw_lcount = hda_sdw_check_lcount_common,
803368017b1SPierre-Louis Bossart .enable_sdw_irq = mtl_enable_sdw_irq,
804368017b1SPierre-Louis Bossart .check_sdw_irq = mtl_dsp_check_sdw_irq,
805368017b1SPierre-Louis Bossart .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
806368017b1SPierre-Louis Bossart .check_ipc_irq = mtl_dsp_check_ipc_irq,
807368017b1SPierre-Louis Bossart .cl_init = mtl_dsp_cl_init,
808368017b1SPierre-Louis Bossart .power_down_dsp = mtl_power_down_dsp,
809368017b1SPierre-Louis Bossart .disable_interrupts = mtl_dsp_disable_interrupts,
810368017b1SPierre-Louis Bossart .hw_ip_version = SOF_INTEL_ACE_1_0,
811368017b1SPierre-Louis Bossart };
812368017b1SPierre-Louis Bossart EXPORT_SYMBOL_NS(arl_s_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
813