brintos

brintos / linux-shallow public Read only

0
0
Text · 24.1 KiB · 2b9d22c Raw
829 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2//3// Copyright(c) 2022 Intel Corporation4//5// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>6//7 8/*9 * Hardware interface for audio DSP on Meteorlake.10 */11 12#include <linux/debugfs.h>13#include <linux/firmware.h>14#include <sound/sof/ipc4/header.h>15#include <trace/events/sof_intel.h>16#include "../ipc4-priv.h"17#include "../ops.h"18#include "hda.h"19#include "hda-ipc.h"20#include "../sof-audio.h"21#include "mtl.h"22#include "telemetry.h"23 24static const struct snd_sof_debugfs_map mtl_dsp_debugfs[] = {25	{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},26	{"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},27	{"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},28	{"fw_regs", HDA_DSP_BAR,  MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY},29};30 31static void mtl_ipc_host_done(struct snd_sof_dev *sdev)32{33	/*34	 * clear busy interrupt to tell dsp controller this interrupt has been accepted,35	 * not trigger it again36	 */37	snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR,38				       MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY);39	/*40	 * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp41	 */42	snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA,43				       MTL_DSP_REG_HFIPCXTDA_BUSY, 0);44}45 46static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev)47{48	/*49	 * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it,50	 * don't send more reply to host51	 */52	snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA,53				       MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE);54 55	/* unmask Done interrupt */56	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,57				MTL_DSP_REG_HFIPCXCTL_DONE, MTL_DSP_REG_HFIPCXCTL_DONE);58}59 60/* Check if an IPC IRQ occurred */61bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)62{63	u32 irq_status;64	u32 hfintipptr;65 66	if (sdev->dspless_mode_selected)67		return false;68 69	/* read Interrupt IP Pointer */70	hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;71	irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);72 73	trace_sof_intel_hda_irq_ipc_check(sdev, irq_status);74 75	if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC))76		return true;77 78	return false;79}80EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, SND_SOC_SOF_INTEL_MTL);81 82/* Check if an SDW IRQ occurred */83static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)84{85	u32 irq_status;86	u32 hfintipptr;87 88	/* read Interrupt IP Pointer */89	hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;90	irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);91 92	if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_SDW))93		return true;94 95	return false;96}97 98int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)99{100	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;101	struct sof_ipc4_msg *msg_data = msg->msg_data;102 103	if (hda_ipc4_tx_is_busy(sdev)) {104		hdev->delayed_ipc_tx_msg = msg;105		return 0;106	}107 108	hdev->delayed_ipc_tx_msg = NULL;109 110	/* send the message via mailbox */111	if (msg_data->data_size)112		sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,113				  msg_data->data_size);114 115	snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY,116			  msg_data->extension);117	snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR,118			  msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY);119 120	hda_dsp_ipc4_schedule_d0i3_work(hdev, msg);121 122	return 0;123}124EXPORT_SYMBOL_NS(mtl_ipc_send_msg, SND_SOC_SOF_INTEL_MTL);125 126void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)127{128	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;129	const struct sof_intel_dsp_desc *chip = hda->desc;130 131	if (sdev->dspless_mode_selected)132		return;133 134	/* enable IPC DONE and BUSY interrupts */135	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,136				MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE,137				MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE);138}139 140void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)141{142	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;143	const struct sof_intel_dsp_desc *chip = hda->desc;144 145	if (sdev->dspless_mode_selected)146		return;147 148	/* disable IPC DONE and BUSY interrupts */149	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,150				MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);151}152EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, SND_SOC_SOF_INTEL_MTL);153 154static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)155{156	u32 hipcie;157	u32 mask;158	u32 val;159	int ret;160 161	if (sdev->dspless_mode_selected)162		return;163 164	/* Enable/Disable SoundWire interrupt */165	mask = MTL_DSP_REG_HfSNDWIE_IE_MASK;166	if (enable)167		val = mask;168	else169		val = 0;170 171	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val);172 173	/* check if operation was successful */174	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,175					    (hipcie & mask) == val,176					    HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);177	if (ret < 0)178		dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",179			enable ? "enable" : "disable");180}181 182int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)183{184	u32 hfintipptr;185	u32 irqinten;186	u32 hipcie;187	u32 mask;188	u32 val;189	int ret;190 191	if (sdev->dspless_mode_selected)192		return 0;193 194	/* read Interrupt IP Pointer */195	hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;196 197	/* Enable/Disable Host IPC and SOUNDWIRE */198	mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;199	if (enable)200		val = mask;201	else202		val = 0;203 204	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val);205 206	/* check if operation was successful */207	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,208					    (irqinten & mask) == val,209					    HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);210	if (ret < 0) {211		dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",212			enable ? "enable" : "disable");213		return ret;214	}215 216	/* Enable/Disable Host IPC interrupt*/217	mask = MTL_DSP_REG_HfHIPCIE_IE_MASK;218	if (enable)219		val = mask;220	else221		val = 0;222 223	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val);224 225	/* check if operation was successful */226	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,227					    (hipcie & mask) == val,228					    HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);229	if (ret < 0) {230		dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",231			enable ? "enable" : "disable");232		return ret;233	}234 235	return ret;236}237EXPORT_SYMBOL_NS(mtl_enable_interrupts, SND_SOC_SOF_INTEL_MTL);238 239/* pre fw run operations */240int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)241{242	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;243	u32 dsphfpwrsts;244	u32 dsphfdsscs;245	u32 cpa;246	u32 pgs;247	int ret;248	u32 dsppwrctl;249	u32 dsppwrsts;250	const struct sof_intel_dsp_desc *chip;251 252	chip = get_chip_info(sdev->pdata);253	if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {254		dsppwrctl = PTL_HFPWRCTL2;255		dsppwrsts = PTL_HFPWRSTS2;256	} else {257		dsppwrctl = MTL_HFPWRCTL;258		dsppwrsts = MTL_HFPWRSTS;259	}260 261	/* Set the DSP subsystem power on */262	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,263				MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK);264 265	/* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */266	usleep_range(1000, 1010);267 268	/* poll with timeout to check if operation successful */269	cpa = MTL_HFDSSCS_CPA_MASK;270	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,271					    (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,272					    HDA_DSP_RESET_TIMEOUT_US);273	if (ret < 0) {274		dev_err(sdev->dev, "failed to enable DSP subsystem\n");275		return ret;276	}277 278	/* Power up gated-DSP-0 domain in order to access the DSP shim register block. */279	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, dsppwrctl,280				MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);281 282	usleep_range(1000, 1010);283 284	/* poll with timeout to check if operation successful */285	pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;286	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, dsppwrsts, dsphfpwrsts,287					    (dsphfpwrsts & pgs) == pgs,288					    HDA_DSP_REG_POLL_INTERVAL_US,289					    HDA_DSP_RESET_TIMEOUT_US);290	if (ret < 0)291		dev_err(sdev->dev, "failed to power up gated DSP domain\n");292 293	/* if SoundWire is used, make sure it is not power-gated */294	if (hdev->info.handle && hdev->info.link_mask > 0)295		snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,296					MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1));297 298	return ret;299}300EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, SND_SOC_SOF_INTEL_MTL);301 302int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)303{304	int ret;305 306	if (sdev->first_boot) {307		struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;308 309		ret = hda_sdw_startup(sdev);310		if (ret < 0) {311			dev_err(sdev->dev, "could not startup SoundWire links\n");312			return ret;313		}314 315		/* Check if IMR boot is usable */316		if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) {317			hdev->imrboot_supported = true;318			debugfs_create_bool("skip_imr_boot",319					    0644, sdev->debugfs_root,320					    &hdev->skip_imr_boot);321		}322	}323 324	hda_sdw_int_enable(sdev, true);325	return 0;326}327EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, SND_SOC_SOF_INTEL_MTL);328 329void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)330{331	char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;332	u32 fwsts;333	u32 fwlec;334 335	hda_dsp_get_state(sdev, level);336	fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS);337	fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR);338 339	if (fwsts != 0xffffffff)340		dev_err(sdev->dev, "Firmware state: %#x, status/error code: %#x\n",341			fwsts, fwlec);342 343	sof_ipc4_intel_dump_telemetry_state(sdev, flags);344}345EXPORT_SYMBOL_NS(mtl_dsp_dump, SND_SOC_SOF_INTEL_MTL);346 347static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)348{349	int val;350 351	val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE);352	if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK)353		return true;354 355	return false;356}357 358static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)359{360	unsigned int cpa;361	u32 dspcxctl;362	int ret;363 364	/* Only the primary core can be powered up by the host */365	if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev))366		return 0;367 368	/* Program the owner of the IP & shim registers (10: Host CPU) */369	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,370				MTL_DSP2CXCTL_PRIMARY_CORE_OSEL,371				0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT);372 373	/* enable SPA bit */374	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,375				MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK,376				MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK);377 378	/* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */379	usleep_range(1000, 1010);380 381	/* poll with timeout to check if operation successful */382	cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK;383	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,384					    (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,385					    HDA_DSP_RESET_TIMEOUT_US);386	if (ret < 0) {387		dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",388			__func__);389		return ret;390	}391 392	/* set primary core mask and refcount to 1 */393	sdev->enabled_cores_mask = BIT(SOF_DSP_PRIMARY_CORE);394	sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 1;395 396	return 0;397}398 399static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)400{401	u32 dspcxctl;402	int ret;403 404	/* Only the primary core can be powered down by the host */405	if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev))406		return 0;407 408	/* disable SPA bit */409	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,410				MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);411 412	/* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */413	usleep_range(1000, 1010);414 415	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,416					    !(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK),417					    HDA_DSP_REG_POLL_INTERVAL_US,418					    HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);419	if (ret < 0) {420		dev_err(sdev->dev, "failed to power down primary core\n");421		return ret;422	}423 424	sdev->enabled_cores_mask = 0;425	sdev->dsp_core_ref_count[SOF_DSP_PRIMARY_CORE] = 0;426 427	return 0;428}429 430int mtl_power_down_dsp(struct snd_sof_dev *sdev)431{432	u32 dsphfdsscs, cpa;433	int ret;434 435	/* first power down core */436	ret = mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);437	if (ret) {438		dev_err(sdev->dev, "mtl dsp power down error, %d\n", ret);439		return ret;440	}441 442	/* Set the DSP subsystem power down */443	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,444				MTL_HFDSSCS_SPA_MASK, 0);445 446	/* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */447	usleep_range(1000, 1010);448 449	/* poll with timeout to check if operation successful */450	cpa = MTL_HFDSSCS_CPA_MASK;451	dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);452	return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,453					     (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US,454					     HDA_DSP_RESET_TIMEOUT_US);455}456EXPORT_SYMBOL_NS(mtl_power_down_dsp, SND_SOC_SOF_INTEL_MTL);457 458int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)459{460	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;461	const struct sof_intel_dsp_desc *chip = hda->desc;462	unsigned int status, target_status;463	u32 ipc_hdr, flags;464	char *dump_msg;465	int ret;466 467	/* step 1: purge FW request */468	ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;469	if (!imr_boot)470		ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9);471 472	snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);473 474	/* step 2: power up primary core */475	ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);476	if (ret < 0) {477		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)478			dev_err(sdev->dev, "dsp core 0/1 power up failed\n");479		goto err;480	}481 482	dev_dbg(sdev->dev, "Primary core power up successful\n");483 484	/* step 3: wait for IPC DONE bit from ROM */485	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,486					    ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),487					    HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_INIT_TIMEOUT_US);488	if (ret < 0) {489		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)490			dev_err(sdev->dev, "timeout waiting for purge IPC done\n");491		goto err;492	}493 494	/* set DONE bit to clear the reply IPC message */495	snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask,496				       chip->ipc_ack_mask);497 498	/* step 4: enable interrupts */499	ret = mtl_enable_interrupts(sdev, true);500	if (ret < 0) {501		if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)502			dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__);503		goto err;504	}505 506	mtl_enable_ipc_interrupts(sdev);507 508	if (chip->rom_status_reg == MTL_DSP_ROM_STS) {509		/*510		 * Workaround: when the ROM status register is pointing to511		 * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch512		 * ROM_INIT_DONE because of a very short timing window.513		 * Follow the recommendations and skip target state waiting.514		 */515		return 0;516	}517 518	/*519	 * step 7:520	 * - Cold/Full boot: wait for ROM init to proceed to download the firmware521	 * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)522	 */523	if (imr_boot)524		target_status = FSR_STATE_FW_ENTERED;525	else526		target_status = FSR_STATE_INIT_DONE;527 528	ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,529					chip->rom_status_reg, status,530					(FSR_TO_STATE_CODE(status) == target_status),531					HDA_DSP_REG_POLL_INTERVAL_US,532					chip->rom_init_timeout *533					USEC_PER_MSEC);534 535	if (!ret)536		return 0;537 538	if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)539		dev_err(sdev->dev,540			"%s: timeout with rom_status_reg (%#x) read\n",541			__func__, chip->rom_status_reg);542 543err:544	flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;545 546	/* after max boot attempts make sure that the dump is printed */547	if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)548		flags &= ~SOF_DBG_DUMP_OPTIONAL;549 550	dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",551			     hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);552	snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);553	mtl_enable_interrupts(sdev, false);554	mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);555 556	kfree(dump_msg);557	return ret;558}559EXPORT_SYMBOL_NS(mtl_dsp_cl_init, SND_SOC_SOF_INTEL_MTL);560 561irqreturn_t mtl_ipc_irq_thread(int irq, void *context)562{563	struct sof_ipc4_msg notification_data = {{ 0 }};564	struct snd_sof_dev *sdev = context;565	bool ack_received = false;566	bool ipc_irq = false;567	u32 hipcida;568	u32 hipctdr;569 570	hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);571	hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);572 573	/* reply message from DSP */574	if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {575		/* DSP received the message */576		snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,577					MTL_DSP_REG_HFIPCXCTL_DONE, 0);578 579		mtl_ipc_dsp_done(sdev);580 581		ipc_irq = true;582		ack_received = true;583	}584 585	if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {586		/* Message from DSP (reply or notification) */587		u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);588		u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK;589 590		/*591		 * ACE fw sends a new fw ipc message to host to592		 * notify the status of the last host ipc message593		 */594		if (primary & SOF_IPC4_MSG_DIR_MASK) {595			/* Reply received */596			if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {597				struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;598 599				data->primary = primary;600				data->extension = extension;601 602				spin_lock_irq(&sdev->ipc_lock);603 604				snd_sof_ipc_get_reply(sdev);605				mtl_ipc_host_done(sdev);606				snd_sof_ipc_reply(sdev, data->primary);607 608				spin_unlock_irq(&sdev->ipc_lock);609			} else {610				dev_dbg_ratelimited(sdev->dev,611						    "IPC reply before FW_READY: %#x|%#x\n",612						    primary, extension);613			}614		} else {615			/* Notification received */616			notification_data.primary = primary;617			notification_data.extension = extension;618 619			sdev->ipc->msg.rx_data = &notification_data;620			snd_sof_ipc_msgs_rx(sdev);621			sdev->ipc->msg.rx_data = NULL;622 623			mtl_ipc_host_done(sdev);624		}625 626		ipc_irq = true;627	}628 629	if (!ipc_irq) {630		/* This interrupt is not shared so no need to return IRQ_NONE. */631		dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");632	}633 634	if (ack_received) {635		struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;636 637		if (hdev->delayed_ipc_tx_msg)638			mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg);639	}640 641	return IRQ_HANDLED;642}643EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, SND_SOC_SOF_INTEL_MTL);644 645int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)646{647	return MTL_DSP_MBOX_UPLINK_OFFSET;648}649EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_MTL);650 651int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)652{653	return MTL_SRAM_WINDOW_OFFSET(id);654}655EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_MTL);656 657void mtl_ipc_dump(struct snd_sof_dev *sdev)658{659	u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;660 661	hipcidr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR);662	hipcidd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY);663	hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);664	hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);665	hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);666	hipctda = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA);667	hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL);668 669	dev_err(sdev->dev,670		"Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n",671		hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl);672}673EXPORT_SYMBOL_NS(mtl_ipc_dump, SND_SOC_SOF_INTEL_MTL);674 675static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)676{677	mtl_enable_sdw_irq(sdev, false);678	mtl_disable_ipc_interrupts(sdev);679	return mtl_enable_interrupts(sdev, false);680}681 682int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)683{684	const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;685 686	if (core == SOF_DSP_PRIMARY_CORE)687		return mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);688 689	if (pm_ops->set_core_state)690		return pm_ops->set_core_state(sdev, core, true);691 692	return 0;693}694EXPORT_SYMBOL_NS(mtl_dsp_core_get, SND_SOC_SOF_INTEL_MTL);695 696int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)697{698	const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;699	int ret;700 701	if (pm_ops->set_core_state) {702		ret = pm_ops->set_core_state(sdev, core, false);703		if (ret < 0)704			return ret;705	}706 707	if (core == SOF_DSP_PRIMARY_CORE)708		return mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);709 710	return 0;711}712EXPORT_SYMBOL_NS(mtl_dsp_core_put, SND_SOC_SOF_INTEL_MTL);713 714/* Meteorlake ops */715struct snd_sof_dsp_ops sof_mtl_ops;716 717int sof_mtl_ops_init(struct snd_sof_dev *sdev)718{719	struct sof_ipc4_fw_data *ipc4_data;720 721	/* common defaults */722	memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));723 724	/* shutdown */725	sof_mtl_ops.shutdown = hda_dsp_shutdown;726 727	/* doorbell */728	sof_mtl_ops.irq_thread = mtl_ipc_irq_thread;729 730	/* ipc */731	sof_mtl_ops.send_msg = mtl_ipc_send_msg;732	sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;733	sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;734 735	/* debug */736	sof_mtl_ops.debug_map = mtl_dsp_debugfs;737	sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);738	sof_mtl_ops.dbg_dump = mtl_dsp_dump;739	sof_mtl_ops.ipc_dump = mtl_ipc_dump;740 741	/* pre/post fw run */742	sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run;743	sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run;744 745	/* parse platform specific extended manifest */746	sof_mtl_ops.parse_platform_ext_manifest = NULL;747 748	/* dsp core get/put */749	sof_mtl_ops.core_get = mtl_dsp_core_get;750	sof_mtl_ops.core_put = mtl_dsp_core_put;751 752	sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);753	if (!sdev->private)754		return -ENOMEM;755 756	ipc4_data = sdev->private;757	ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;758 759	ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;760 761	ipc4_data->fw_context_save = true;762 763	/* External library loading support */764	ipc4_data->load_library = hda_dsp_ipc4_load_library;765 766	/* set DAI ops */767	hda_set_dai_drv_ops(sdev, &sof_mtl_ops);768 769	sof_mtl_ops.set_power_state = hda_dsp_set_power_state_ipc4;770 771	return 0;772};773 774const struct sof_intel_dsp_desc mtl_chip_info = {775	.cores_num = 3,776	.init_core_mask = BIT(0),777	.host_managed_cores_mask = BIT(0),778	.ipc_req = MTL_DSP_REG_HFIPCXIDR,779	.ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,780	.ipc_ack = MTL_DSP_REG_HFIPCXIDA,781	.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,782	.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,783	.rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,784	.rom_init_timeout	= 300,785	.ssp_count = MTL_SSP_COUNT,786	.ssp_base_offset = CNL_SSP_BASE_OFFSET,787	.sdw_shim_base = SDW_SHIM_BASE_ACE,788	.sdw_alh_base = SDW_ALH_BASE_ACE,789	.d0i3_offset = MTL_HDA_VS_D0I3C,790	.read_sdw_lcount =  hda_sdw_check_lcount_common,791	.enable_sdw_irq = mtl_enable_sdw_irq,792	.check_sdw_irq = mtl_dsp_check_sdw_irq,793	.check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,794	.sdw_process_wakeen = hda_sdw_process_wakeen_common,795	.check_ipc_irq = mtl_dsp_check_ipc_irq,796	.cl_init = mtl_dsp_cl_init,797	.power_down_dsp = mtl_power_down_dsp,798	.disable_interrupts = mtl_dsp_disable_interrupts,799	.hw_ip_version = SOF_INTEL_ACE_1_0,800};801 802const struct sof_intel_dsp_desc arl_s_chip_info = {803	.cores_num = 2,804	.init_core_mask = BIT(0),805	.host_managed_cores_mask = BIT(0),806	.ipc_req = MTL_DSP_REG_HFIPCXIDR,807	.ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,808	.ipc_ack = MTL_DSP_REG_HFIPCXIDA,809	.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,810	.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,811	.rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,812	.rom_init_timeout	= 300,813	.ssp_count = MTL_SSP_COUNT,814	.ssp_base_offset = CNL_SSP_BASE_OFFSET,815	.sdw_shim_base = SDW_SHIM_BASE_ACE,816	.sdw_alh_base = SDW_ALH_BASE_ACE,817	.d0i3_offset = MTL_HDA_VS_D0I3C,818	.read_sdw_lcount =  hda_sdw_check_lcount_common,819	.enable_sdw_irq = mtl_enable_sdw_irq,820	.check_sdw_irq = mtl_dsp_check_sdw_irq,821	.check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,822	.sdw_process_wakeen = hda_sdw_process_wakeen_common,823	.check_ipc_irq = mtl_dsp_check_ipc_irq,824	.cl_init = mtl_dsp_cl_init,825	.power_down_dsp = mtl_power_down_dsp,826	.disable_interrupts = mtl_dsp_disable_interrupts,827	.hw_ip_version = SOF_INTEL_ACE_1_0,828};829