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 = ¬ification_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