275 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2//3// Copyright(c) 2023 Intel Corporation4 5/*6 * Hardware interface for audio DSP on LunarLake.7 */8 9#include <linux/debugfs.h>10#include <linux/firmware.h>11#include <sound/hda_register.h>12#include <sound/sof/ipc4/header.h>13#include <trace/events/sof_intel.h>14#include "../ipc4-priv.h"15#include "../ops.h"16#include "hda.h"17#include "hda-ipc.h"18#include "../sof-audio.h"19#include "mtl.h"20#include "lnl.h"21#include <sound/hda-mlink.h>22 23/* LunarLake ops */24struct snd_sof_dsp_ops sof_lnl_ops;25EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_LNL);26 27static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {28 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},29 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},30 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},31 {"fw_regs", HDA_DSP_BAR, MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY},32};33 34/* this helps allows the DSP to setup DMIC/SSP */35static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable)36{37 int ret;38 39 ret = hdac_bus_eml_enable_offload(bus, true,40 AZX_REG_ML_LEPTR_ID_INTEL_SSP, enable);41 if (ret < 0)42 return ret;43 44 ret = hdac_bus_eml_enable_offload(bus, true,45 AZX_REG_ML_LEPTR_ID_INTEL_DMIC, enable);46 if (ret < 0)47 return ret;48 49 return 0;50}51 52static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)53{54 int ret;55 56 ret = hda_dsp_probe(sdev);57 if (ret < 0)58 return ret;59 60 return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);61}62 63static void lnl_hda_dsp_remove(struct snd_sof_dev *sdev)64{65 int ret;66 67 ret = hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), false);68 if (ret < 0)69 dev_warn(sdev->dev,70 "Failed to disable offload for DMIC/SSP: %d\n", ret);71 72 hda_dsp_remove(sdev);73}74 75static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)76{77 int ret;78 79 ret = hda_dsp_resume(sdev);80 if (ret < 0)81 return ret;82 83 return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);84}85 86static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)87{88 int ret;89 90 ret = hda_dsp_runtime_resume(sdev);91 if (ret < 0)92 return ret;93 94 return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);95}96 97static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)98{99 if (sdev->first_boot) {100 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;101 102 /* Check if IMR boot is usable */103 if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) {104 hda->imrboot_supported = true;105 debugfs_create_bool("skip_imr_boot",106 0644, sdev->debugfs_root,107 &hda->skip_imr_boot);108 }109 }110 111 return 0;112}113 114int sof_lnl_ops_init(struct snd_sof_dev *sdev)115{116 struct sof_ipc4_fw_data *ipc4_data;117 118 /* common defaults */119 memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));120 121 /* probe/remove */122 if (!sdev->dspless_mode_selected) {123 sof_lnl_ops.probe = lnl_hda_dsp_probe;124 sof_lnl_ops.remove = lnl_hda_dsp_remove;125 }126 127 /* shutdown */128 sof_lnl_ops.shutdown = hda_dsp_shutdown;129 130 /* doorbell */131 sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;132 133 /* ipc */134 sof_lnl_ops.send_msg = mtl_ipc_send_msg;135 sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;136 sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;137 138 /* debug */139 sof_lnl_ops.debug_map = lnl_dsp_debugfs;140 sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);141 sof_lnl_ops.dbg_dump = mtl_dsp_dump;142 sof_lnl_ops.ipc_dump = mtl_ipc_dump;143 144 /* pre/post fw run */145 sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;146 sof_lnl_ops.post_fw_run = lnl_dsp_post_fw_run;147 148 /* parse platform specific extended manifest */149 sof_lnl_ops.parse_platform_ext_manifest = NULL;150 151 /* dsp core get/put */152 /* TODO: add core_get and core_put */153 154 /* PM */155 if (!sdev->dspless_mode_selected) {156 sof_lnl_ops.resume = lnl_hda_dsp_resume;157 sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;158 }159 160 /* dsp core get/put */161 sof_lnl_ops.core_get = mtl_dsp_core_get;162 sof_lnl_ops.core_put = mtl_dsp_core_put;163 164 sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);165 if (!sdev->private)166 return -ENOMEM;167 168 ipc4_data = sdev->private;169 ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;170 171 ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;172 173 ipc4_data->fw_context_save = true;174 175 /* External library loading support */176 ipc4_data->load_library = hda_dsp_ipc4_load_library;177 178 /* set DAI ops */179 hda_set_dai_drv_ops(sdev, &sof_lnl_ops);180 181 sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;182 183 return 0;184};185EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_LNL);186 187/* Check if an SDW IRQ occurred */188static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)189{190 struct hdac_bus *bus = sof_to_bus(sdev);191 192 return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW);193}194 195static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)196{197 struct hdac_bus *bus = sof_to_bus(sdev);198 199 hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable);200}201 202static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)203{204 lnl_enable_sdw_irq(sdev, false);205 mtl_disable_ipc_interrupts(sdev);206 return mtl_enable_interrupts(sdev, false);207}208 209static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)210{211 struct hdac_bus *bus = sof_to_bus(sdev);212 u16 wake_sts;213 214 /*215 * we need to use the global HDaudio WAKEEN/STS to be able to216 * detect wakes in low-power modes. The link-specific information217 * is handled in the process_wakeen() helper, this helper only218 * detects a SoundWire wake without identifying the link.219 */220 wake_sts = snd_hdac_chip_readw(bus, STATESTS);221 222 /* filter out the range of SDIs that can be set for SoundWire */223 return wake_sts & GENMASK(SDW_MAX_DEVICES, SDW_INTEL_DEV_NUM_IDA_MIN);224}225 226const struct sof_intel_dsp_desc lnl_chip_info = {227 .cores_num = 5,228 .init_core_mask = BIT(0),229 .host_managed_cores_mask = BIT(0),230 .ipc_req = MTL_DSP_REG_HFIPCXIDR,231 .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,232 .ipc_ack = MTL_DSP_REG_HFIPCXIDA,233 .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,234 .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,235 .rom_status_reg = LNL_DSP_REG_HFDSC,236 .rom_init_timeout = 300,237 .ssp_count = MTL_SSP_COUNT,238 .d0i3_offset = MTL_HDA_VS_D0I3C,239 .read_sdw_lcount = hda_sdw_check_lcount_ext,240 .enable_sdw_irq = lnl_enable_sdw_irq,241 .check_sdw_irq = lnl_dsp_check_sdw_irq,242 .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,243 .sdw_process_wakeen = hda_sdw_process_wakeen_common,244 .check_ipc_irq = mtl_dsp_check_ipc_irq,245 .cl_init = mtl_dsp_cl_init,246 .power_down_dsp = mtl_power_down_dsp,247 .disable_interrupts = lnl_dsp_disable_interrupts,248 .hw_ip_version = SOF_INTEL_ACE_2_0,249};250 251const struct sof_intel_dsp_desc ptl_chip_info = {252 .cores_num = 5,253 .init_core_mask = BIT(0),254 .host_managed_cores_mask = BIT(0),255 .ipc_req = MTL_DSP_REG_HFIPCXIDR,256 .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,257 .ipc_ack = MTL_DSP_REG_HFIPCXIDA,258 .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,259 .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,260 .rom_status_reg = LNL_DSP_REG_HFDSC,261 .rom_init_timeout = 300,262 .ssp_count = MTL_SSP_COUNT,263 .d0i3_offset = MTL_HDA_VS_D0I3C,264 .read_sdw_lcount = hda_sdw_check_lcount_ext,265 .enable_sdw_irq = lnl_enable_sdw_irq,266 .check_sdw_irq = lnl_dsp_check_sdw_irq,267 .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,268 .check_ipc_irq = mtl_dsp_check_ipc_irq,269 .cl_init = mtl_dsp_cl_init,270 .power_down_dsp = mtl_power_down_dsp,271 .disable_interrupts = lnl_dsp_disable_interrupts,272 .hw_ip_version = SOF_INTEL_ACE_3_0,273};274EXPORT_SYMBOL_NS(ptl_chip_info, SND_SOC_SOF_INTEL_LNL);275