diff options
Diffstat (limited to 'sound/soc/sof/intel')
31 files changed, 941 insertions, 521 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 7af495fb6125..36a0e2bf30ff 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -277,7 +277,7 @@ if SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK bool "SOF support for HDA Links(HDA/HDMI)" - depends on SND_SOC_SOF_NOCODEC=n + depends on SND_SOC_SOF_NOCODEC_SUPPORT=n select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 8b8ea0361785..8201cbdd654c 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -5,7 +5,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ - hda-dai.o hda-bus.o \ + hda-dai.o hda-bus.o hda-mlink.o \ skl.o hda-loader-skl.o \ apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 1549ca7587a4..0e7a7e4ad976 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -62,6 +62,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev) ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5; + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + /* doorbell */ sof_apl_ops.irq_thread = hda_dsp_ipc4_irq_thread; @@ -106,6 +109,7 @@ const struct sof_intel_dsp_desc apl_chip_info = { .rom_init_timeout = 150, .ssp_count = APL_SSP_COUNT, .ssp_base_offset = APL_SSP_BASE_OFFSET, + .d0i3_offset = SOF_HDA_VS_D0I3C, .quirks = SOF_INTEL_PROCEN_FMT_QUIRK, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index a446154f2803..812a49b1d3f4 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -575,11 +575,7 @@ static struct snd_sof_dsp_ops sof_bdw_ops = { .run = bdw_run, .reset = bdw_reset, - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, + /* Register IO uses direct mmio */ /* Block IO */ .block_read = sof_block_read, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index e6dc4ff531c3..faf223b38360 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -225,11 +225,7 @@ static struct snd_sof_dsp_ops sof_byt_ops = { .run = atom_run, .reset = atom_reset, - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, + /* Register IO uses direct mmio */ /* Block IO */ .block_read = sof_block_read, @@ -304,11 +300,7 @@ static struct snd_sof_dsp_ops sof_cht_ops = { .run = atom_run, .reset = atom_reset, - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, + /* Register IO uses direct mmio */ /* Block IO */ .block_read = sof_block_read, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 19d0b1909bfd..6b075bbe5bfb 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -37,10 +37,12 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; + bool ack_received = false; bool ipc_irq = false; u32 hipcida, hipctdr; hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { /* DSP received the message */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -49,9 +51,9 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) cnl_ipc_dsp_done(sdev); ipc_irq = true; + ack_received = true; } - hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { /* Message from DSP (reply or notification) */ u32 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -70,6 +72,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) spin_lock_irq(&sdev->ipc_lock); snd_sof_ipc_get_reply(sdev); + cnl_ipc_host_done(sdev); snd_sof_ipc_reply(sdev, data->primary); spin_unlock_irq(&sdev->ipc_lock); @@ -86,10 +89,10 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) sdev->ipc->msg.rx_data = ¬ification_data; snd_sof_ipc_msgs_rx(sdev); sdev->ipc->msg.rx_data = NULL; - } - /* Let DSP know that we have finished processing the message */ - cnl_ipc_host_done(sdev); + /* Let DSP know that we have finished processing the message */ + cnl_ipc_host_done(sdev); + } ipc_irq = true; } @@ -98,6 +101,13 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) /* This interrupt is not shared so no need to return IRQ_NONE. */ dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); + if (ack_received) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + if (hdev->delayed_ipc_tx_msg) + cnl_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg); + } + return IRQ_HANDLED; } @@ -251,8 +261,16 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; + if (hda_ipc4_tx_is_busy(sdev)) { + hdev->delayed_ipc_tx_msg = msg; + return 0; + } + + hdev->delayed_ipc_tx_msg = NULL; + /* send the message via mailbox */ if (msg_data->data_size) sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, @@ -389,6 +407,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8; + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + /* doorbell */ sof_cnl_ops.irq_thread = cnl_ipc4_irq_thread; @@ -435,6 +456,9 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, @@ -467,6 +491,9 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 0862ff8b6627..acb4b85868d0 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -18,11 +18,7 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #include "../../codecs/hdac_hda.h" #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() -#else -#define sof_hda_ext_ops NULL -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power) { unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN); @@ -70,11 +66,13 @@ static const struct hdac_bus_ops bus_core_ops = { /* * This can be used for both with/without hda link support. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev) +void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); -#else /* CONFIG_SND_SOC_SOF_HDA */ +#else /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ memset(bus, 0, sizeof(*bus)); bus->dev = dev; @@ -89,5 +87,14 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev) bus->idx = 0; spin_lock_init(&bus->reg_lock); -#endif /* CONFIG_SND_SOC_SOF_HDA */ +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +} + +void sof_hda_bus_exit(struct snd_sof_dev *sdev) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + struct hdac_bus *bus = sof_to_bus(sdev); + + snd_hdac_ext_bus_exit(bus); +#endif } diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index f2ec2a6c2e0f..8a5e99a898ec 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -1,7 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. +// SPDX-License-Identifier: GPL-2.0-only // // Copyright(c) 2018 Intel Corporation. All rights reserved. // @@ -16,15 +13,18 @@ #include <sound/sof.h> #include "../ops.h" #include "hda.h" + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #include "../../codecs/hdac_hda.h" -#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ #define CODEC_PROBE_RETRIES 3 -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define IDISP_VID_INTEL 0x80860000 +static int hda_codec_mask = -1; +module_param_named(codec_mask, hda_codec_mask, int, 0444); +MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing"); + /* load the legacy HDA codec driver */ static int request_codec_module(struct hda_codec *codec) { @@ -72,6 +72,10 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) struct hda_codec *codec; unsigned int mask = 0; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + if (enable) { list_for_each_codec(codec, hbus) if (codec->jacktbl.used) @@ -80,6 +84,7 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); } +EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC); /* check jack status after resuming from suspend mode */ void hda_codec_jack_check(struct snd_sof_dev *sdev) @@ -87,6 +92,10 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev) struct hda_bus *hbus = sof_to_hbus(sdev); struct hda_codec *codec; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + list_for_each_codec(codec, hbus) /* * Wake up all jack-detecting codecs regardless whether an event @@ -95,12 +104,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev) if (codec->jacktbl.used) pm_request_resume(&codec->core.dev); } -#else -void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) {} -void hda_codec_jack_check(struct snd_sof_dev *sdev) {} -#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ -EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC); -EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); #if IS_ENABLED(CONFIG_SND_HDA_GENERIC) #define is_generic_config(bus) \ @@ -133,13 +137,9 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i } /* probe individual codec */ -static int hda_codec_probe(struct snd_sof_dev *sdev, int address, - bool hda_codec_use_common_hdmi) +static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; - int type = HDA_DEV_LEGACY; -#endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hda_codec *codec; u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | @@ -159,16 +159,11 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", address, resp); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) return -ENOMEM; - /* only probe ASoC codec drivers for HDAC-HDMI */ - if (!hda_codec_use_common_hdmi && (resp & 0xFFFF0000) == IDISP_VID_INTEL) - type = HDA_DEV_ASOC; - - codec = hda_codec_device_init(&hbus->core, address, type); + codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_LEGACY); ret = PTR_ERR_OR_ZERO(codec); if (ret < 0) return ret; @@ -191,43 +186,40 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, else codec->probe_id = 0; - if (type == HDA_DEV_LEGACY) { - ret = hda_codec_load_module(codec); - /* - * handle ret==0 (no driver bound) as an error, but pass - * other return codes without modification - */ - if (ret == 0) - ret = -ENOENT; - } + ret = hda_codec_load_module(codec); + /* + * handle ret==0 (no driver bound) as an error, but pass + * other return codes without modification + */ + if (ret == 0) + ret = -ENOENT; out: if (ret < 0) { snd_hdac_device_unregister(&codec->core); put_device(&codec->core.dev); } -#else - codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_ASOC); - ret = PTR_ERR_OR_ZERO(codec); -#endif return ret; } /* Codec initialization */ -void hda_codec_probe_bus(struct snd_sof_dev *sdev, - bool hda_codec_use_common_hdmi) +void hda_codec_probe_bus(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); int i, ret; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + /* probe codecs in avail slots */ for (i = 0; i < HDA_MAX_CODECS; i++) { if (!(bus->codec_mask & (1 << i))) continue; - ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi); + ret = hda_codec_probe(sdev, i); if (ret < 0) { dev_warn(bus->dev, "codec #%d probe error, ret: %d\n", i, ret); @@ -235,27 +227,193 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev, } } } -EXPORT_SYMBOL_NS(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + unsigned int codec_mask; + + codec_mask = snd_hdac_chip_readw(bus, STATESTS); + if (codec_mask) { + hda_codec_jack_check(sdev); + snd_hdac_chip_writew(bus, STATESTS, codec_mask); + } +} +EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_detect_mask(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* Accept unsolicited responses */ + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + + /* detect codecs */ + if (!bus->codec_mask) { + bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); + dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); + } + + if (hda_codec_mask != -1) { + bus->codec_mask &= hda_codec_mask; + dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n", + bus->codec_mask); + } +} +EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* initialize the codec command I/O */ + snd_hdac_bus_init_cmd_io(bus); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* set up CORB/RIRB buffers if was on before suspend */ + if (bus->cmd_dma_state) + snd_hdac_bus_init_cmd_io(bus); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* initialize the codec command I/O */ + snd_hdac_bus_stop_cmd_io(bus); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* stop the CORB/RIRB DMA if it is On */ + if (bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); + +} +EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* clear rirb status */ + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + snd_hdac_set_codec_wakeup(bus, status); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC); + +bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + bool active = false; + u32 rirb_status; + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return false; + + rirb_status = snd_hdac_chip_readb(bus, RIRBSTS); + if (rirb_status & RIRB_INT_MASK) { + /* + * Clearing the interrupt status here ensures + * that no interrupt gets masked after the RIRB + * wp is read in snd_hdac_bus_update_rirb. + */ + snd_hdac_chip_writeb(bus, RIRBSTS, + RIRB_INT_MASK); + active = true; + if (rirb_status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + } + return active; +} +EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC); + +void hda_codec_device_remove(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + + /* codec removal, invoke bus_device_remove */ + snd_hdac_ext_bus_device_remove(bus); +} +EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC); + +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ -#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ - IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) { struct hdac_bus *bus = sof_to_bus(sdev); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return; + if (HDA_IDISP_CODEC(bus->codec_mask)) { dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable); } } -EXPORT_SYMBOL_NS(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); int hda_codec_i915_init(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); int ret; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return 0; + /* i915 exposes a HDA codec for HDMI audio */ ret = snd_hdac_i915_init(bus); if (ret < 0) @@ -266,12 +424,16 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); int hda_codec_i915_exit(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && + sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) + return 0; + if (!bus->audio_component) return 0; @@ -280,7 +442,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) return snd_hdac_i915_exit(bus); } -EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); #endif diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index b2326396c870..397303b3ac9d 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -19,11 +19,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = { .probe = hda_dsp_probe, .remove = hda_dsp_remove, - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, + /* Register IO uses direct mmio */ /* Block IO */ .block_read = sof_block_read, diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 0c29bb196e59..3aea36c077c9 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -22,12 +22,6 @@ #include "../ops.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) -static int hda_codec_mask = -1; -module_param_named(codec_mask, hda_codec_mask, int, 0444); -MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing"); -#endif - /* * HDA Operations. */ @@ -182,72 +176,40 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) return 0; } -int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_ext_link *hlink; -#endif struct hdac_stream *stream; int sd_offset, ret = 0; if (bus->chip_init) return 0; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - snd_hdac_set_codec_wakeup(bus, true); -#endif - hda_dsp_ctrl_misc_clock_gating(sdev, false); + hda_codec_set_codec_wakeup(sdev, true); - if (full_reset) { - /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to reset HDA controller\n"); - goto err; - } - - usleep_range(500, 1000); - - /* exit HDA controller reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); - goto err; - } - - usleep_range(1000, 1200); - } + hda_dsp_ctrl_misc_clock_gating(sdev, false); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* check to see if controller is ready */ - if (!snd_hdac_chip_readb(bus, GCTL)) { - dev_dbg(bus->dev, "controller not ready!\n"); - ret = -EBUSY; + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset HDA controller\n"); goto err; } - /* Accept unsolicited responses */ - snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); - - /* detect codecs */ - if (!bus->codec_mask) { - bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); - dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); + goto err; } - if (hda_codec_mask != -1) { - bus->codec_mask &= hda_codec_mask; - dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n", - bus->codec_mask); - } -#endif + hda_codec_detect_mask(sdev); /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); } @@ -255,19 +217,13 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, SOF_HDA_WAKESTS_INT_MASK); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* clear rirb status */ - snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); -#endif + hda_codec_rirb_status_clear(sdev); /* clear interrupt status register */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* initialize the codec command I/O */ - snd_hdac_bus_init_cmd_io(bus); -#endif + hda_codec_init_cmd_io(sdev); /* enable CIE and GIE interrupts */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, @@ -282,19 +238,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) upper_32_bits(bus->posbuf.addr)); } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); -#endif + hda_bus_ml_reset_losidv(bus); bus->chip_init = true; err: hda_dsp_ctrl_misc_clock_gating(sdev, true); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - snd_hdac_set_codec_wakeup(bus, false); -#endif + + hda_codec_set_codec_wakeup(sdev, false); return ret; } @@ -313,7 +264,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) sd_offset = SOF_STREAM_SD_OFFSET(stream); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + - SOF_HDA_ADSP_REG_CL_SD_CTL, + SOF_HDA_ADSP_REG_SD_CTL, SOF_HDA_CL_DMA_SD_INT_MASK, 0); } @@ -331,7 +282,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); } @@ -339,19 +290,14 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, SOF_HDA_WAKESTS_INT_MASK); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* clear rirb status */ - snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); -#endif + hda_codec_rirb_status_clear(sdev); /* clear interrupt status register */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* disable CORB/RIRB */ - snd_hdac_bus_stop_cmd_io(bus); -#endif + hda_codec_stop_cmd_io(sdev); + /* disable position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 556e883a32ed..1c3d4887aa30 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -27,16 +27,13 @@ static bool hda_use_tplg_nhlt; module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hda_pipe_params { u32 ch; u32 s_freq; - u32 s_fmt; - u8 linktype; snd_pcm_format_t format; int link_index; - int stream; unsigned int link_bps; }; @@ -138,27 +135,27 @@ hda_link_stream_assign(struct hdac_bus *bus, } static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, - struct hdac_stream *hstream, + struct hdac_ext_stream *hext_stream, struct snd_soc_dai *cpu_dai, struct snd_soc_dai *codec_dai, bool trigger_suspend_stop) { - struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); + struct hdac_stream *hstream = &hext_stream->hstream; struct hdac_bus *bus = hstream->bus; struct sof_intel_hda_stream *hda_stream; - struct hdac_ext_link *link; + struct hdac_ext_link *hlink; int stream_tag; - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); - if (!link) + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); + if (!hlink) return -EINVAL; if (trigger_suspend_stop) - snd_hdac_ext_link_stream_clear(hext_stream); + snd_hdac_ext_stream_clear(hext_stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { stream_tag = hdac_stream(hext_stream)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag); } snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); @@ -177,10 +174,10 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream, struct hdac_stream *hstream = &hext_stream->hstream; unsigned char stream_tag = hstream->stream_tag; struct hdac_bus *bus = hstream->bus; - struct hdac_ext_link *link; + struct hdac_ext_link *hlink; unsigned int format_val; - snd_hdac_ext_link_stream_reset(hext_stream); + snd_hdac_ext_stream_reset(hext_stream); format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, params->format, @@ -189,13 +186,13 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream, dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params->s_freq, params->ch, params->format); - snd_hdac_ext_link_stream_setup(hext_stream, format_val); + snd_hdac_ext_stream_setup(hext_stream, format_val); if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_link_set_stream_id(link, - stream_tag); + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (hlink->index == params->link_index) + snd_hdac_ext_bus_link_set_stream_id(hlink, + stream_tag); } } @@ -207,14 +204,17 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream, static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct hdac_stream *hstream = substream->runtime->private_data; - struct hdac_ext_stream *hext_stream; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct hda_pipe_params p_params = {0}; - struct hdac_bus *bus = hstream->bus; - struct hdac_ext_link *link; + struct hdac_ext_stream *hext_stream; + struct hdac_ext_link *hlink; + struct snd_sof_dev *sdev; + struct hdac_bus *bus; + + sdev = snd_soc_component_get_drvdata(cpu_dai->component); + bus = sof_to_bus(sdev); hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream); if (!hext_stream) { @@ -225,18 +225,16 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream); } - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); - if (!link) + hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); + if (!hlink) return -EINVAL; /* set the hdac_stream in the codec dai */ snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream); - p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); - p_params.stream = substream->stream; - p_params.link_index = link->index; + p_params.link_index = hlink->index; p_params.format = params_format(params); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -257,7 +255,6 @@ static int hda_link_dma_prepare(struct snd_pcm_substream *substream) static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd) { - struct hdac_stream *hstream = substream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); @@ -270,17 +267,17 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_link_stream_start(hext_stream); + snd_hdac_ext_stream_start(hext_stream); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, true); + ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, true); if (ret < 0) return ret; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_hdac_ext_link_stream_clear(hext_stream); + snd_hdac_ext_stream_clear(hext_stream); break; default: @@ -291,7 +288,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd) static int hda_link_dma_hw_free(struct snd_pcm_substream *substream) { - struct hdac_stream *hstream = substream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); @@ -301,7 +297,7 @@ static int hda_link_dma_hw_free(struct snd_pcm_substream *substream) if (!hext_stream) return 0; - return hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false); + return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false); } static int hda_dai_widget_update(struct snd_soc_dapm_widget *w, @@ -458,14 +454,12 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; struct snd_soc_dai *codec_dai; - struct hdac_stream *hstream; struct snd_soc_dai *cpu_dai; int ret; dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, dai->name, substream->stream); - hstream = substream->runtime->private_data; rtd = asoc_substream_to_rtd(substream); cpu_dai = asoc_rtd_to_cpu(rtd, 0); codec_dai = asoc_rtd_to_codec(rtd, 0); @@ -476,7 +470,7 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_link_stream_start(hext_stream); + snd_hdac_ext_stream_start(hext_stream); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -484,23 +478,23 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, struct snd_sof_widget *pipe_widget = swidget->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_PAUSED; - snd_hdac_ext_link_stream_clear(hext_stream); + snd_hdac_ext_stream_clear(hext_stream); - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_RESET); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_RESET; - ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false); + ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false); if (ret < 0) { dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); return ret; @@ -512,14 +506,14 @@ static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, struct snd_sof_widget *pipe_widget = swidget->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_PAUSED; - snd_hdac_ext_link_stream_clear(hext_stream); + snd_hdac_ext_stream_clear(hext_stream); break; } default: @@ -575,7 +569,8 @@ static int hda_dai_suspend(struct hdac_bus *bus) cpu_dai = asoc_rtd_to_cpu(rtd, 0); codec_dai = asoc_rtd_to_codec(rtd, 0); - ret = hda_link_dma_cleanup(hext_stream->link_substream, s, + ret = hda_link_dma_cleanup(hext_stream->link_substream, + hext_stream, cpu_dai, codec_dai, false); if (ret < 0) return ret; @@ -726,20 +721,20 @@ static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stre switch (cmd) { case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_PAUSED; - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_RESET); if (ret < 0) return ret; pipeline->state = SOF_IPC4_PIPE_RESET; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, + ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, SOF_IPC4_PIPE_PAUSED); if (ret < 0) return ret; @@ -777,7 +772,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) ops->drv[i].ops = &ipc3_ssp_dai_ops; continue; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) if (strstr(ops->drv[i].name, "iDisp") || strstr(ops->drv[i].name, "Analog") || strstr(ops->drv[i].name, "Digital")) @@ -798,7 +793,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) ops->drv[i].ops = &ipc4_ssp_dai_ops; continue; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) if (strstr(ops->drv[i].name, "iDisp") || strstr(ops->drv[i].name, "Analog") || strstr(ops->drv[i].name, "Digital")) @@ -916,7 +911,7 @@ struct snd_soc_dai_driver skl_dai[] = { .channels_max = 4, }, }, -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) { .name = "iDisp1 Pin", .playback = { @@ -989,7 +984,7 @@ int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) * Since the component suspend is called last, we can trap this corner case * and force the DAIs to release their resources. */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) int ret; ret = hda_dai_suspend(sof_to_bus(sdev)); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 3c76f843454b..5fa29df54b42 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -347,10 +347,13 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); int retry = HDA_DSP_REG_POLL_RETRY_COUNT; + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_intel_dsp_desc *chip; - while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { + chip = get_chip_info(pdata); + while (snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset) & + SOF_HDA_VS_D0I3C_CIP) { if (!retry--) return -ETIMEDOUT; usleep_range(10, 15); @@ -378,27 +381,33 @@ static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags) static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) { - struct hdac_bus *bus = sof_to_bus(sdev); + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_intel_dsp_desc *chip; int ret; + u8 reg; + + chip = get_chip_info(pdata); /* Write to D0I3C after Command-In-Progress bit is cleared */ ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { - dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); + dev_err(sdev->dev, "CIP timeout before D0I3C update!\n"); return ret; } /* Update D0I3C register */ - snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); + snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset, + SOF_HDA_VS_D0I3C_I3, value); /* Wait for cmd in progress to be cleared before exiting the function */ ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { - dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); + dev_err(sdev->dev, "CIP timeout after D0I3C update!\n"); return ret; } - trace_sof_intel_D0I3C_updated(sdev, snd_hdac_chip_readb(bus, VS_D0I3C)); + reg = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, chip->d0i3_offset); + trace_sof_intel_D0I3C_updated(sdev, reg); return 0; } @@ -612,9 +621,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); -#endif int ret, j; /* @@ -633,12 +640,10 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) if (ret < 0) return ret; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) hda_codec_jack_wake_enable(sdev, runtime_suspend); - /* power down all hda link */ - snd_hdac_ext_bus_link_power_down_all(bus); -#endif + /* power down all hda links */ + hda_bus_ml_suspend(bus); ret = chip->power_down_dsp(sdev); if (ret < 0) { @@ -677,10 +682,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_link *hlink = NULL; -#endif int ret; /* display codec must be powered before link reset */ @@ -693,14 +694,13 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); /* reset and start hda controller */ - ret = hda_dsp_ctrl_init_chip(sdev, true); + ret = hda_dsp_ctrl_init_chip(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to start controller after resume\n"); goto cleanup; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* check jack status */ if (runtime_resume) { hda_codec_jack_wake_enable(sdev, false); @@ -708,17 +708,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) hda_codec_jack_check(sdev); } - /* turn off the links that were off before suspend */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (!hlink->ref_count) - snd_hdac_ext_bus_link_power_down(hlink); - } - - /* check dma status and clean up CORB/RIRB buffers */ - if (!bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); -#endif - /* enable ppcap interrupt */ hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true); @@ -733,37 +722,26 @@ cleanup: int hda_dsp_resume(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = to_pci_dev(sdev->dev); const struct sof_dsp_power_state target_state = { .state = SOF_DSP_PM_D0, .substate = SOF_HDA_DSP_PM_D0I0, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_link *hlink = NULL; -#endif int ret; /* resume from D0I3 */ if (sdev->dsp_power_state.state == SOF_DSP_PM_D0) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* power up links that were active before suspend */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (hlink->ref_count) { - ret = snd_hdac_ext_bus_link_power_up(hlink); - if (ret < 0) { - dev_err(sdev->dev, - "error %d in %s: failed to power up links", - ret, __func__); - return ret; - } - } + ret = hda_bus_ml_resume(bus); + if (ret < 0) { + dev_err(sdev->dev, + "error %d in %s: failed to power up links", + ret, __func__); + return ret; } /* set up CORB/RIRB buffers if was on before suspend */ - if (bus->cmd_dma_state) - snd_hdac_bus_init_cmd_io(bus); -#endif + hda_codec_resume_cmd_io(sdev); /* Set DSP power state */ ret = snd_sof_dsp_set_power_state(sdev, &target_state); @@ -872,20 +850,17 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* stop the CORB/RIRB DMA if it is On */ - if (bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); + hda_codec_suspend_cmd_io(sdev); /* no link can be powered in s0ix state */ - ret = snd_hdac_ext_bus_link_power_down_all(bus); + ret = hda_bus_ml_suspend(bus); if (ret < 0) { dev_err(sdev->dev, "error %d in %s: failed to power down links", ret, __func__); return ret; } -#endif /* enable the system waking up via IPC IRQ */ enable_irq_wake(pci->irq); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 9b3667c705e4..a7c454e03952 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -69,8 +69,16 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; + if (hda_ipc4_tx_is_busy(sdev)) { + hdev->delayed_ipc_tx_msg = msg; + return 0; + } + + hdev->delayed_ipc_tx_msg = NULL; + /* send the message via mailbox */ if (msg_data->data_size) sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, @@ -122,10 +130,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; + bool ack_received = false; bool ipc_irq = false; u32 hipcie, hipct; hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); + hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { /* DSP received the message */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL, @@ -133,9 +144,9 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) hda_dsp_ipc_dsp_done(sdev); ipc_irq = true; + ack_received = true; } - hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); if (hipct & HDA_DSP_REG_HIPCT_BUSY) { /* Message from DSP (reply or notification) */ u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -158,6 +169,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) spin_lock_irq(&sdev->ipc_lock); snd_sof_ipc_get_reply(sdev); + hda_dsp_ipc_host_done(sdev); snd_sof_ipc_reply(sdev, data->primary); spin_unlock_irq(&sdev->ipc_lock); @@ -174,10 +186,10 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) sdev->ipc->msg.rx_data = ¬ification_data; snd_sof_ipc_msgs_rx(sdev); sdev->ipc->msg.rx_data = NULL; - } - /* Let DSP know that we have finished processing the message */ - hda_dsp_ipc_host_done(sdev); + /* Let DSP know that we have finished processing the message */ + hda_dsp_ipc_host_done(sdev); + } ipc_irq = true; } @@ -186,6 +198,13 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) /* This interrupt is not shared so no need to return IRQ_NONE. */ dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); + if (ack_received) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + if (hdev->delayed_ipc_tx_msg) + hda_dsp_ipc4_send_msg(sdev, hdev->delayed_ipc_tx_msg); + } + return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 0193fb3964a0..69fdef8f89ae 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -141,7 +141,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) u32 run = enable ? 0x1 : 0; snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + sd_offset + SOF_HDA_ADSP_REG_SD_CTL, HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); retries = 300; @@ -150,7 +150,7 @@ static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) /* waiting for hardware to report the stream Run bit set */ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL); + sd_offset + SOF_HDA_ADSP_REG_SD_CTL); val &= HDA_CL_SD_CTL_RUN(1); if (enable && val) break; @@ -174,23 +174,23 @@ static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) * Descriptor Error Interrupt and set the cldma stream number to 0. */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + sd_offset + SOF_HDA_ADSP_REG_SD_CTL, HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + sd_offset + SOF_HDA_ADSP_REG_SD_CTL, HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, HDA_CL_SD_BDLPLBA(0)); + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(0)); snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); /* Set the Cyclic Buffer Length to 0. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0); + sd_offset + SOF_HDA_ADSP_REG_SD_CBL, 0); /* Set the Last Valid Index. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); + sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0); } static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, @@ -240,27 +240,27 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, /* setting the stream register */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); /* Set the Cyclic Buffer Length. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size); + sd_offset + SOF_HDA_ADSP_REG_SD_CBL, max_size); /* Set the Last Valid Index. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1); + sd_offset + SOF_HDA_ADSP_REG_SD_LVI, count - 1); /* Set the Interrupt On Completion, FIFO Error Interrupt, * Descriptor Error Interrupt and the cldma stream number. */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + sd_offset + SOF_HDA_ADSP_REG_SD_CTL, HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + sd_offset + SOF_HDA_ADSP_REG_SD_CTL, HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(1)); } @@ -439,7 +439,7 @@ static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev, /* now check DMA interrupt status */ cl_dma_intr_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS); + sd_offset + SOF_HDA_ADSP_REG_SD_STS); if (!(cl_dma_intr_status & HDA_CL_DMA_SD_INT_COMPLETE)) { dev_err(sdev->dev, "cldma copy failed\n"); @@ -494,14 +494,13 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab) { - struct snd_sof_pdata *plat_data = sdev->pdata; - const struct firmware *fw = plat_data->fw; + const struct firmware *fw = sdev->basefw.fw; struct firmware stripped_firmware; unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; int ret; - stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; - stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; + stripped_firmware.data = fw->data + sdev->basefw.payload_offset; + stripped_firmware.size = fw->size - sdev->basefw.payload_offset; dev_dbg(sdev->dev, "firmware size: %#zx buffer size %#x\n", fw->size, bufsize); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 98812d51b31c..d680562edb35 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -19,7 +19,9 @@ #include <sound/hdaudio_ext.h> #include <sound/hda_register.h> #include <sound/sof.h> +#include <sound/sof/ipc4/header.h> #include "ext_manifest.h" +#include "../ipc4-priv.h" #include "../ops.h" #include "../sof-priv.h" #include "hda.h" @@ -263,9 +265,9 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, /* reset BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); snd_dma_free_pages(dmab); @@ -318,10 +320,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) { - struct snd_sof_pdata *plat_data = sdev->pdata; struct hdac_ext_stream *iccmax_stream; struct hdac_bus *bus = sof_to_bus(sdev); - struct firmware stripped_firmware; struct snd_dma_buffer dmab_bdl; int ret, ret1; u8 original_gb; @@ -329,15 +329,11 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) /* save the original LTRP guardband value */ original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; - if (plat_data->fw->size <= plat_data->fw_offset) { - dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); - return -EINVAL; - } - - stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; - - /* prepare capture stream for ICCMAX */ - iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, + /* + * Prepare capture stream for ICCMAX. We do not need to store + * the data, so use a buffer of PAGE_SIZE for receiving. + */ + iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE, &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); if (IS_ERR(iccmax_stream)) { dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); @@ -397,21 +393,25 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n"); hda->boot_iteration = 0; ret = hda_dsp_boot_imr(sdev); - if (!ret) + if (!ret) { + hda->booted_from_imr = true; return 0; + } dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n"); } + hda->booted_from_imr = false; + chip_info = desc->chip_info; - if (plat_data->fw->size <= plat_data->fw_offset) { + if (sdev->basefw.fw->size <= sdev->basefw.payload_offset) { dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); return -EINVAL; } - stripped_firmware.data = plat_data->fw->data + plat_data->fw_offset; - stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; + stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset; + stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset; /* init for booting wait */ init_waitqueue_head(&sdev->boot_wait); @@ -515,6 +515,70 @@ cleanup: return ret; } +int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, + struct sof_ipc4_fw_library *fw_lib, bool reload) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_ext_stream *hext_stream; + struct firmware stripped_firmware; + struct sof_ipc4_msg msg = {}; + struct snd_dma_buffer dmab; + int ret, ret1; + + /* IMR booting will restore the libraries as well, skip the loading */ + if (reload && hda->booted_from_imr) + return 0; + + /* the fw_lib has been verified during loading, we can trust the validity here */ + stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset; + stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset; + + /* prepare DMA for code loader stream */ + hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, + stripped_firmware.size, + &dmab, SNDRV_PCM_STREAM_PLAYBACK); + if (IS_ERR(hext_stream)) { + dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__); + return PTR_ERR(hext_stream); + } + + memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size); + + msg.primary = hext_stream->hstream.stream_tag - 1; + msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); + msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(fw_lib->id); + + ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__); + goto cleanup; + } + + ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); + + ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); + if (ret1 < 0) { + dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__); + if (!ret) + ret = ret1; + } + +cleanup: + /* clean up even in case of error and return the first error */ + ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream); + if (ret1 < 0) { + dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); + + /* set return value to indicate cleanup failure */ + if (!ret) + ret = ret1; + } + + return ret; +} + /* pre fw run operations */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c new file mode 100644 index 000000000000..76ab9a2e7bb3 --- /dev/null +++ b/sound/soc/sof/intel/hda-mlink.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// + +/* + * Management of HDaudio multi-link (capabilities, power, coupling) + */ + +#include <sound/hdaudio_ext.h> +#include <sound/hda_register.h> + +#include <linux/acpi.h> +#include <linux/module.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_intel.h> +#include <sound/intel-dsp-config.h> +#include <sound/intel-nhlt.h> +#include <sound/sof.h> +#include <sound/sof/xtensa.h> +#include "../sof-audio.h" +#include "../sof-pci-dev.h" +#include "../ops.h" +#include "hda.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +void hda_bus_ml_get_capabilities(struct hdac_bus *bus) +{ + if (bus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(bus); +} + +void hda_bus_ml_free(struct hdac_bus *bus) +{ + struct hdac_ext_link *hlink; + + if (!bus->mlcap) + return; + + while (!list_empty(&bus->hlink_list)) { + hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list); + list_del(&hlink->list); + kfree(hlink); + } +} + +void hda_bus_ml_put_all(struct hdac_bus *bus) +{ + struct hdac_ext_link *hlink; + + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); +} + +void hda_bus_ml_reset_losidv(struct hdac_bus *bus) +{ + struct hdac_ext_link *hlink; + + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); +} + +int hda_bus_ml_resume(struct hdac_bus *bus) +{ + struct hdac_ext_link *hlink; + int ret; + + /* power up links that were active before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (hlink->ref_count) { + ret = snd_hdac_ext_bus_link_power_up(hlink); + if (ret < 0) + return ret; + } + } + return 0; +} + +int hda_bus_ml_suspend(struct hdac_bus *bus) +{ + return snd_hdac_ext_bus_link_power_down_all(bus); +} + +#endif diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 0a9c80216a8c..dc0b359ed9b6 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -142,7 +142,6 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { struct hdac_stream *hstream = substream->runtime->private_data; - struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); struct snd_pcm_runtime *runtime = substream->runtime; ssize_t appl_pos, buf_size; u32 spib; @@ -156,7 +155,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea if (!spib) spib = buf_size; - sof_io_write(sdev, hext_stream->spib_addr, spib); + sof_io_write(sdev, hstream->spib_addr, spib); return 0; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index be60e7785da9..7f0fd05a96e6 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -173,7 +173,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, enable << hstream->index); /* set the SPIB value */ - sof_io_write(sdev, hext_stream->spib_addr, size); + sof_io_write(sdev, hstream->spib_addr, size); return 0; } @@ -367,7 +367,7 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, if (ret >= 0) { snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); hstream->running = false; @@ -398,7 +398,6 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params) { - struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *hstream = &hext_stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret; @@ -419,10 +418,10 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st /* reset BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0x0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0x0); hstream->frags = 0; @@ -435,20 +434,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st /* program BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, (u32)hstream->bdl.addr); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, upper_32_bits(hstream->bdl.addr)); /* program cyclic buffer length */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + sd_offset + SOF_HDA_ADSP_REG_SD_CBL, hstream->bufsize); /* program last valid index */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0xffff, (hstream->frags - 1)); /* decouple host and link DMA, enable DSP features */ @@ -456,7 +455,8 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st mask, mask); /* Follow HW recommendation to set the guardband value to 95us during FW boot */ - snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US); + snd_sof_dsp_update8(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_LTRP, + HDA_VS_INTEL_LTRP_GB_MASK, HDA_LTRP_GB_VALUE_US); /* start DMA */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, @@ -520,7 +520,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_CL_DMA_SD_INT_MASK); @@ -534,10 +534,10 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* reset BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, 0x0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0x0); /* clear stream status */ @@ -562,7 +562,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_CL_DMA_SD_INT_MASK); @@ -582,7 +582,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* program cyclic buffer length */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + sd_offset + SOF_HDA_ADSP_REG_SD_CBL, hstream->bufsize); /* @@ -606,7 +606,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* program stream format */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + - SOF_HDA_ADSP_REG_CL_SD_FORMAT, + SOF_HDA_ADSP_REG_SD_FORMAT, 0xffff, hstream->format_val); if (chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK) { @@ -617,15 +617,15 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* program last valid index */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + sd_offset + SOF_HDA_ADSP_REG_SD_LVI, 0xffff, (hstream->frags - 1)); /* program BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPL, (u32)hstream->bdl.addr); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, upper_32_bits(hstream->bdl.addr)); /* enable position buffer, if needed */ @@ -649,7 +649,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, hstream->fifo_size = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, sd_offset + - SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE); + SOF_HDA_ADSP_REG_SD_FIFOSIZE); hstream->fifo_size &= 0xffff; hstream->fifo_size += 1; } else { @@ -697,7 +697,8 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) /* The function can be called at irq thread, so use spin_lock_irq */ spin_lock_irq(&bus->reg_lock); - status = snd_hdac_chip_readl(bus, INTSTS); + status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + trace_sof_intel_hda_dsp_check_stream_irq(sdev, status); /* if Register inaccessible, ignore it.*/ @@ -735,11 +736,11 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) list_for_each_entry(s, &bus->stream_list, list) { if (status & BIT(s->index) && s->opened) { - sd_status = snd_hdac_stream_readb(s, SD_STS); + sd_status = readb(s->sd_addr + SOF_HDA_ADSP_REG_SD_STS); trace_sof_intel_hda_dsp_stream_status(bus->dev, s, sd_status); - snd_hdac_stream_writeb(s, SD_STS, sd_status); + writeb(sd_status, s->sd_addr + SOF_HDA_ADSP_REG_SD_STS); active = true; if ((!s->substream && !s->cstream) || @@ -764,9 +765,6 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; struct hdac_bus *bus = sof_to_bus(sdev); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - u32 rirb_status; -#endif bool active; u32 status; int i; @@ -778,29 +776,15 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) for (i = 0, active = true; i < 10 && active; i++) { spin_lock_irq(&bus->reg_lock); - status = snd_hdac_chip_readl(bus, INTSTS); + status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); /* check streams */ active = hda_dsp_stream_check(bus, status); /* check and clear RIRB interrupt */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (status & AZX_INT_CTRL_EN) { - rirb_status = snd_hdac_chip_readb(bus, RIRBSTS); - if (rirb_status & RIRB_INT_MASK) { - /* - * Clearing the interrupt status here ensures - * that no interrupt gets masked after the RIRB - * wp is read in snd_hdac_bus_update_rirb. - */ - snd_hdac_chip_writeb(bus, RIRBSTS, - RIRB_INT_MASK); - active = true; - if (rirb_status & RIRB_INT_RESPONSE) - snd_hdac_bus_update_rirb(bus); - } + active |= hda_codec_check_rirb_status(sdev); } -#endif spin_unlock_irq(&bus->reg_lock); } @@ -853,15 +837,16 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* mem alloc for the CORB/RIRB ringbuffers */ + /* + * mem alloc for the CORB/RIRB ringbuffers - this will be used only for + * HDAudio codecs + */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, PAGE_SIZE, &bus->rb); if (ret < 0) { dev_err(sdev->dev, "error: RB alloc failed\n"); return -ENOMEM; } -#endif /* create capture streams */ for (i = 0; i < num_capture; i++) { @@ -883,18 +868,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + SOF_HDA_PPLC_INTERVAL * i; + hstream = &hext_stream->hstream; + /* do we support SPIB */ if (sdev->bar[HDA_DSP_SPIB_BAR]) { - hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + SOF_HDA_SPIB_SPIB; - hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + SOF_HDA_SPIB_MAXFIFO; } - hstream = &hext_stream->hstream; hstream->bus = bus; hstream->sd_int_sta_mask = 1 << i; hstream->index = i; @@ -939,18 +925,19 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + SOF_HDA_PPLC_INTERVAL * i; + hstream = &hext_stream->hstream; + /* do we support SPIB */ if (sdev->bar[HDA_DSP_SPIB_BAR]) { - hext_stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + SOF_HDA_SPIB_SPIB; - hext_stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + SOF_HDA_SPIB_MAXFIFO; } - hstream = &hext_stream->hstream; hstream->bus = bus; hstream->sd_int_sta_mask = 1 << i; hstream->index = i; @@ -992,11 +979,9 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) if (bus->posbuf.area) snd_dma_free_pages(&bus->posbuf); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* free position buffer */ + /* free CORB/RIRB buffer - only used for HDaudio codecs */ if (bus->rb.area) snd_dma_free_pages(&bus->rb); -#endif list_for_each_entry_safe(s, _s, &bus->stream_list, list) { /* TODO: decouple */ diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1188ec51816b..14a2f8701350 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -155,9 +155,27 @@ struct sdw_intel_ops sdw_callback = { .free_stream = sdw_free_stream, }; +void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) +{ + struct sof_intel_hda_dev *hdev; + + hdev = sdev->pdata->hw_pdata; + + if (!hdev->sdw) + return; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2, + HDA_DSP_REG_ADSPIC2_SNDW, + enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0); +} + void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { - sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable); + const struct sof_intel_dsp_desc *chip; + + chip = get_chip_info(sdev->pdata); + if (chip && chip->enable_sdw_irq) + chip->enable_sdw_irq(sdev, enable); } static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) @@ -220,10 +238,45 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) return 0; } +int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + struct sdw_intel_ctx *ctx; + u32 caps; + + hdev = sdev->pdata->hw_pdata; + ctx = hdev->sdw; + + caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP); + caps &= SDW_SHIM_LCAP_LCOUNT_MASK; + + /* Check HW supported vs property value */ + if (caps < ctx->count) { + dev_err(sdev->dev, + "BIOS master count %d is larger than hardware capabilities %d\n", + ctx->count, caps); + return -EINVAL; + } + + return 0; +} + +static int hda_sdw_check_lcount(struct snd_sof_dev *sdev) +{ + const struct sof_intel_dsp_desc *chip; + + chip = get_chip_info(sdev->pdata); + if (chip && chip->read_sdw_lcount) + return chip->read_sdw_lcount(sdev); + + return 0; +} + int hda_sdw_startup(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev; struct snd_sof_pdata *pdata = sdev->pdata; + int ret; hdev = sdev->pdata->hw_pdata; @@ -233,6 +286,10 @@ int hda_sdw_startup(struct snd_sof_dev *sdev) if (pdata->machine && !pdata->machine->mach_params.link_mask) return 0; + ret = hda_sdw_check_lcount(sdev); + if (ret < 0) + return ret; + return sdw_intel_startup(hdev->sdw); } @@ -383,12 +440,6 @@ static int mclk_id_override = -1; module_param_named(mclk_id, mclk_id_override, int, 0444); MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id"); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) -static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI); -module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444); -MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver"); -#endif - static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = { {HDA_DSP_ROM_CSE_ERROR, "error: cse error"}, {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"}, @@ -625,7 +676,6 @@ static bool hda_check_ipc_irq(struct snd_sof_dev *sdev) void hda_ipc_irq_dump(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); u32 adspis; u32 intsts; u32 intctl; @@ -637,7 +687,7 @@ void hda_ipc_irq_dump(struct snd_sof_dev *sdev) intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL); ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS); - rirbsts = snd_hdac_chip_readb(bus, RIRBSTS); + rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS); dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n", intsts, intctl, rirbsts); @@ -681,6 +731,17 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev) hipci, hipcie, hipct, hipcte, hipcctl); } +bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + u32 val; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req); + + return !!(val & chip->ipc_req_mask); +} + static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; @@ -692,7 +753,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus = sof_to_bus(sdev); /* HDA bus init */ - sof_hda_bus_init(bus, &pci->dev); + sof_hda_bus_init(sdev, &pci->dev); if (sof_hda_position_quirk == SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS) bus->use_posbuf = 0; @@ -787,7 +848,7 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num) return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num); } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) static const char *fixup_tplg_name(struct snd_sof_dev *sdev, const char *sof_tplg_filename, @@ -867,9 +928,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); struct snd_sof_pdata *pdata = sdev->pdata; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_ext_link *hlink; -#endif struct sof_intel_hda_dev *hdev = pdata->hw_pdata; u32 link_mask; int ret = 0; @@ -879,13 +937,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); /* Init HDA controller after i915 init */ - ret = hda_dsp_ctrl_init_chip(sdev, true); + ret = hda_dsp_ctrl_init_chip(sdev); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); return ret; } + hda_bus_ml_get_capabilities(bus); + /* scan SoundWire capabilities exposed by DSDT */ ret = hda_sdw_acpi_scan(sdev); if (ret < 0) { @@ -914,37 +974,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev) skip_soundwire: -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - if (bus->mlcap) - snd_hdac_ext_bus_get_ml_capabilities(bus); - /* create codec instances */ - hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi); + hda_codec_probe_bus(sdev); if (!HDA_IDISP_CODEC(bus->codec_mask)) hda_codec_i915_display_power(sdev, false); - /* - * we are done probing so decrement link counts - */ - list_for_each_entry(hlink, &bus->hlink_list, list) - snd_hdac_ext_bus_link_put(bus, hlink); -#endif - return 0; -} + hda_bus_ml_put_all(bus); -static void hda_check_for_state_change(struct snd_sof_dev *sdev) -{ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); - unsigned int codec_mask; - - codec_mask = snd_hdac_chip_readw(bus, STATESTS); - if (codec_mask) { - hda_codec_jack_check(sdev); - snd_hdac_chip_writew(bus, STATESTS, codec_mask); - } -#endif + return 0; } static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) @@ -996,7 +1034,7 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) hda_sdw_process_wakeen(sdev); } - hda_check_for_state_change(sdev); + hda_codec_check_for_state_change(sdev); /* enable GIE interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, @@ -1192,10 +1230,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) /* cancel any attempt for DSP D0I3 */ cancel_delayed_work_sync(&hda->d0i3_work); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* codec removal, invoke bus_device_remove */ - snd_hdac_ext_bus_device_remove(bus); -#endif + hda_codec_device_remove(sdev); hda_sdw_exit(sdev); @@ -1223,16 +1258,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - snd_hdac_link_free_all(bus); -#endif + + hda_bus_ml_free(sof_to_bus(sdev)); iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(bus->remap_addr); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - snd_hdac_ext_bus_exit(bus); -#endif + sof_hda_bus_exit(sdev); + hda_codec_i915_exit(sdev); return 0; @@ -1246,7 +1279,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev) return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) static void hda_generic_machine_select(struct snd_sof_dev *sdev, struct snd_soc_acpi_mach **mach) { @@ -1325,7 +1358,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (*mach) { mach_params = &(*mach)->mach_params; mach_params->codec_mask = bus->codec_mask; - mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; + mach_params->common_hdmi_codec_drv = true; } } #else diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 2ab3c3840b92..022ce80968dd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -122,17 +122,17 @@ #define SOF_HDA_ADSP_DPLBASE_ENABLE 0x01 /* Stream Registers */ -#define SOF_HDA_ADSP_REG_CL_SD_CTL 0x00 -#define SOF_HDA_ADSP_REG_CL_SD_STS 0x03 -#define SOF_HDA_ADSP_REG_CL_SD_LPIB 0x04 -#define SOF_HDA_ADSP_REG_CL_SD_CBL 0x08 -#define SOF_HDA_ADSP_REG_CL_SD_LVI 0x0C -#define SOF_HDA_ADSP_REG_CL_SD_FIFOW 0x0E -#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE 0x10 -#define SOF_HDA_ADSP_REG_CL_SD_FORMAT 0x12 -#define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14 -#define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18 -#define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C +#define SOF_HDA_ADSP_REG_SD_CTL 0x00 +#define SOF_HDA_ADSP_REG_SD_STS 0x03 +#define SOF_HDA_ADSP_REG_SD_LPIB 0x04 +#define SOF_HDA_ADSP_REG_SD_CBL 0x08 +#define SOF_HDA_ADSP_REG_SD_LVI 0x0C +#define SOF_HDA_ADSP_REG_SD_FIFOW 0x0E +#define SOF_HDA_ADSP_REG_SD_FIFOSIZE 0x10 +#define SOF_HDA_ADSP_REG_SD_FORMAT 0x12 +#define SOF_HDA_ADSP_REG_SD_FIFOL 0x14 +#define SOF_HDA_ADSP_REG_SD_BDLPL 0x18 +#define SOF_HDA_ADSP_REG_SD_BDLPU 0x1C #define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20 /* CL: Software Position Based FIFO Capability Registers */ @@ -294,6 +294,7 @@ #define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10) #define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) +#define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) #define HDA_DSP_REG_ADSPIS2_SNDW BIT(5) /* Intel HD Audio Inter-Processor Communication Registers */ @@ -307,6 +308,7 @@ /* Intel Vendor Specific Registers */ #define HDA_VS_INTEL_EM2 0x1030 #define HDA_VS_INTEL_EM2_L1SEN BIT(13) +#define HDA_VS_INTEL_LTRP 0x1048 #define HDA_VS_INTEL_LTRP_GB_MASK 0x3F /* HIPCI */ @@ -481,6 +483,7 @@ enum sof_hda_D0_substate { struct sof_intel_hda_dev { bool imrboot_supported; bool skip_imr_boot; + bool booted_from_imr; int boot_iteration; @@ -521,6 +524,14 @@ struct sof_intel_hda_dev { /* Intel NHLT information */ struct nhlt_acpi_table *nhlt; + + /* + * Pointing to the IPC message if immediate sending was not possible + * because the downlink communication channel was BUSY at the time. + * The message will be re-tried when the channel becomes free (the ACK + * is received from the DSP for the previous message) + */ + struct snd_sof_ipc_msg *delayed_ipc_tx_msg; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -693,27 +704,51 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); -int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev); void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev); /* * HDA bus operations. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev); +void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev); +void sof_hda_bus_exit(struct snd_sof_dev *sdev); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) /* * HDA Codec operations. */ -void hda_codec_probe_bus(struct snd_sof_dev *sdev, - bool hda_codec_use_common_hdmi); +void hda_codec_probe_bus(struct snd_sof_dev *sdev); void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable); void hda_codec_jack_check(struct snd_sof_dev *sdev); +void hda_codec_check_for_state_change(struct snd_sof_dev *sdev); +void hda_codec_init_cmd_io(struct snd_sof_dev *sdev); +void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev); +void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev); +void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev); +void hda_codec_detect_mask(struct snd_sof_dev *sdev); +void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev); +bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev); +void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status); +void hda_codec_device_remove(struct snd_sof_dev *sdev); -#endif /* CONFIG_SND_SOC_SOF_HDA */ +#else + +static inline void hda_codec_probe_bus(struct snd_sof_dev *sdev) { } +static inline void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) { } +static inline void hda_codec_jack_check(struct snd_sof_dev *sdev) { } +static inline void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) { } +static inline void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) { } +static inline void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) { } +static inline void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) { } +static inline void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) { } +static inline void hda_codec_detect_mask(struct snd_sof_dev *sdev) { } +static inline void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) { } +static inline bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) { return false; } +static inline void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) { } +static inline void hda_codec_device_remove(struct snd_sof_dev *sdev) { } + +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && \ - (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ - IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable); int hda_codec_i915_init(struct snd_sof_dev *sdev); @@ -721,13 +756,32 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev); #else -static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev, - bool enable) { } +static inline void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) { } static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +void hda_bus_ml_get_capabilities(struct hdac_bus *bus); +void hda_bus_ml_free(struct hdac_bus *bus); +void hda_bus_ml_put_all(struct hdac_bus *bus); +void hda_bus_ml_reset_losidv(struct hdac_bus *bus); +int hda_bus_ml_resume(struct hdac_bus *bus); +int hda_bus_ml_suspend(struct hdac_bus *bus); + +#else + +static inline void hda_bus_ml_get_capabilities(struct hdac_bus *bus) { } +static inline void hda_bus_ml_free(struct hdac_bus *bus) { } +static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { } +static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } +static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } +static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } + +#endif /* CONFIG_SND_SOC_SOF_HDA */ + /* * Trace Control. */ @@ -741,18 +795,29 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev); int hda_sdw_startup(struct snd_sof_dev *sdev); +void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); #else +static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) +{ + return 0; +} + static inline int hda_sdw_startup(struct snd_sof_dev *sdev) { return 0; } +static inline void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) +{ +} + static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } @@ -852,8 +917,12 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); irqreturn_t cnl_ipc4_irq_thread(int irq, void *context); int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context); +bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev); int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void hda_ipc4_dump(struct snd_sof_dev *sdev); extern struct sdw_intel_ops sdw_callback; +struct sof_ipc4_fw_library; +int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, + struct sof_ipc4_fw_library *fw_lib, bool reload); #endif diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index 6d5877108a3d..435941a1692f 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -130,6 +130,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev) ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + /* doorbell */ sof_icl_ops.irq_thread = cnl_ipc4_irq_thread; @@ -177,6 +180,9 @@ const struct sof_intel_dsp_desc icl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 10298532816f..904ae42534e1 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -90,8 +90,16 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; + if (hda_ipc4_tx_is_busy(sdev)) { + hdev->delayed_ipc_tx_msg = msg; + return 0; + } + + hdev->delayed_ipc_tx_msg = NULL; + /* send the message via mailbox */ if (msg_data->data_size) sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, @@ -126,111 +134,79 @@ static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev) MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0); } -static int mtl_enable_interrupts(struct snd_sof_dev *sdev) +static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) { - u32 hfintipptr; - u32 irqinten; - u32 host_ipc; u32 hipcie; + u32 mask; + u32 val; int ret; - /* read Interrupt IP Pointer */ - hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + /* Enable/Disable SoundWire interrupt */ + mask = MTL_DSP_REG_HfSNDWIE_IE_MASK; + if (enable) + val = mask; + else + val = 0; - /* Enable Host IPC and SOUNDWIRE */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK); + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val); /* check if operation was successful */ - host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, - (irqinten & host_ipc) == host_ipc, - HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n"); - return ret; - } - - /* Set Host IPC interrupt enable */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, - MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK); - - /* check if operation was successful */ - host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, - (hipcie & host_ipc) == host_ipc, - HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) { - dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n"); - return ret; - } - - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, - MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK); - host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, - (hipcie & host_ipc) == host_ipc, + (hipcie & mask) == val, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) - dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n"); - - return ret; + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n", + enable ? "enable" : "disable"); } -static int mtl_disable_interrupts(struct snd_sof_dev *sdev) +static int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) { u32 hfintipptr; u32 irqinten; - u32 host_ipc; u32 hipcie; - int ret1; + u32 mask; + u32 val; int ret; /* read Interrupt IP Pointer */ hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; - /* Disable Host IPC and SOUNDWIRE */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0); + /* Enable/Disable Host IPC and SOUNDWIRE */ + mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; + if (enable) + val = mask; + else + val = 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val); /* check if operation was successful */ - host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, - (irqinten & host_ipc) == 0, + (irqinten & mask) == val, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - /* Continue to disable other interrupts when error happens */ - if (ret < 0) - dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n"); + if (ret < 0) { + dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n", + enable ? "enable" : "disable"); + return ret; + } - /* Set Host IPC interrupt disable */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, - MTL_DSP_REG_HfHIPCIE_IE_MASK, 0); + /* Enable/Disable Host IPC interrupt*/ + mask = MTL_DSP_REG_HfHIPCIE_IE_MASK; + if (enable) + val = mask; + else + val = 0; - /* check if operation was successful */ - host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; - ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, - (hipcie & host_ipc) == 0, - HDA_DSP_REG_POLL_INTERVAL_US, - HDA_DSP_RESET_TIMEOUT_US); - if (ret1 < 0) { - dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n"); - if (!ret) - ret = ret1; - } + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val); - /* Set SoundWire IPC interrupt disable */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, - MTL_DSP_REG_HfSNDWIE_IE_MASK, 0); - host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; - ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, - (hipcie & host_ipc) == 0, - HDA_DSP_REG_POLL_INTERVAL_US, - HDA_DSP_RESET_TIMEOUT_US); - if (ret1 < 0) { - dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n"); - if (!ret) - ret = ret1; + /* check if operation was successful */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, + (hipcie & mask) == val, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n", + enable ? "enable" : "disable"); + return ret; } return ret; @@ -385,7 +361,7 @@ static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0); - /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */ usleep_range(1000, 1010); ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, @@ -414,7 +390,7 @@ static int mtl_power_down_dsp(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, MTL_HFDSSCS_SPA_MASK, 0); - /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + /* Wait for unstable CPA read (0 then 1 then 0) just after setting SPA bit */ usleep_range(1000, 1010); /* poll with timeout to check if operation successful */ @@ -465,7 +441,7 @@ static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_bo chip->ipc_ack_mask); /* step 4: enable interrupts */ - ret = mtl_enable_interrupts(sdev); + ret = mtl_enable_interrupts(sdev, true); if (ret < 0) { if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__); @@ -492,11 +468,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; + bool ack_received = false; bool ipc_irq = false; u32 hipcida; u32 hipctdr; hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); /* reply message from DSP */ if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) { @@ -507,9 +485,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) mtl_ipc_dsp_done(sdev); ipc_irq = true; + ack_received = true; } - hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) { /* Message from DSP (reply or notification) */ u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY); @@ -530,6 +508,7 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) spin_lock_irq(&sdev->ipc_lock); snd_sof_ipc_get_reply(sdev); + mtl_ipc_host_done(sdev); snd_sof_ipc_reply(sdev, data->primary); spin_unlock_irq(&sdev->ipc_lock); @@ -546,9 +525,9 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) sdev->ipc->msg.rx_data = ¬ification_data; snd_sof_ipc_msgs_rx(sdev); sdev->ipc->msg.rx_data = NULL; - } - mtl_ipc_host_done(sdev); + mtl_ipc_host_done(sdev); + } ipc_irq = true; } @@ -558,6 +537,13 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n"); } + if (ack_received) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + if (hdev->delayed_ipc_tx_msg) + mtl_ipc_send_msg(sdev, hdev->delayed_ipc_tx_msg); + } + return IRQ_HANDLED; } @@ -590,8 +576,9 @@ static void mtl_ipc_dump(struct snd_sof_dev *sdev) static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { + mtl_enable_sdw_irq(sdev, false); mtl_disable_ipc_interrupts(sdev); - return mtl_disable_interrupts(sdev); + return mtl_enable_interrupts(sdev, false); } /* Meteorlake ops */ @@ -641,6 +628,9 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + /* set DAI ops */ hda_set_dai_drv_ops(sdev, &sof_mtl_ops); @@ -663,6 +653,9 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE_ACE, .sdw_alh_base = SDW_ALH_BASE_ACE, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = mtl_enable_sdw_irq, .check_sdw_irq = mtl_dsp_check_sdw_irq, .check_ipc_irq = mtl_dsp_check_ipc_irq, .cl_init = mtl_dsp_cl_init, diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 788bf0e3ea87..0fd4e6fe09b8 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -21,6 +21,8 @@ #define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6) #define MTL_HFINTIPPTR_PTR_MASK GENMASK(20, 0) +#define MTL_HDA_VS_D0I3C 0x1D4A + #define MTL_DSP2CXCAP_PRIMARY_CORE 0x178D00 #define MTL_DSP2CXCTL_PRIMARY_CORE 0x178D04 #define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0) diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 998e219011f0..69279dcc92dc 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -33,6 +33,9 @@ static const struct sof_dev_desc bxt_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/apl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/apl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -61,6 +64,9 @@ static const struct sof_dev_desc glk_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/glk", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/glk", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index c797356f7028..8db3f8d15b55 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -34,6 +34,9 @@ static const struct sof_dev_desc cnl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/cnl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/cnl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -62,6 +65,9 @@ static const struct sof_dev_desc cfl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/cnl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/cnl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -91,6 +97,9 @@ static const struct sof_dev_desc cml_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/cnl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/cnl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 48f24f8ace26..d6cf75e357db 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -34,6 +34,9 @@ static const struct sof_dev_desc icl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/icl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/icl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -62,6 +65,9 @@ static const struct sof_dev_desc jsl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/jsl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/jsl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 9f39da984e9f..6e4e6d4ef5a5 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -34,6 +34,9 @@ static const struct sof_dev_desc mtl_desc = { .default_fw_path = { [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4-lib/mtl", + }, .default_tplg_path = { [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", }, diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 4cfe4f242fc5..e80c4dfef85a 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -34,6 +34,9 @@ static const struct sof_dev_desc tgl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/tgl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/tgl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -62,6 +65,9 @@ static const struct sof_dev_desc tglh_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/tgl-h", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/tgl-h", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -90,6 +96,9 @@ static const struct sof_dev_desc ehl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/ehl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/ehl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -118,6 +127,9 @@ static const struct sof_dev_desc adls_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/adl-s", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/adl-s", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -146,6 +158,9 @@ static const struct sof_dev_desc adl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/adl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/adl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -174,6 +189,9 @@ static const struct sof_dev_desc adl_n_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/adl-n", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/adl-n", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -202,6 +220,9 @@ static const struct sof_dev_desc rpls_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/rpl-s", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/rpl-s", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", @@ -230,6 +251,9 @@ static const struct sof_dev_desc rpl_desc = { [SOF_IPC] = "intel/sof", [SOF_INTEL_IPC4] = "intel/avs/rpl", }, + .default_lib_path = { + [SOF_INTEL_IPC4] = "intel/avs-lib/rpl", + }, .default_tplg_path = { [SOF_IPC] = "intel/sof-tplg", [SOF_INTEL_IPC4] = "intel/avs-tplg", diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index f0f6d9ba8803..5b2b409752c5 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -144,11 +144,7 @@ struct snd_sof_dsp_ops sof_tng_ops = { .run = atom_run, .reset = atom_reset, - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, + /* Register IO uses direct mmio */ /* Block IO */ .block_read = sof_block_read, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 3ceba5c39317..48428ccbcfe0 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -182,8 +182,11 @@ struct sof_intel_dsp_desc { int ssp_base_offset; /* base address of the SSPs */ u32 sdw_shim_base; u32 sdw_alh_base; + u32 d0i3_offset; u32 quirks; enum sof_intel_hw_ip_version hw_ip_version; + int (*read_sdw_lcount)(struct snd_sof_dev *sdev); + void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable); bool (*check_sdw_irq)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); int (*power_down_dsp)(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 9ae2890e9dac..30f2f49ee149 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -85,6 +85,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; + /* External library loading support */ + ipc4_data->load_library = hda_dsp_ipc4_load_library; + /* doorbell */ sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread; @@ -132,6 +135,9 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, @@ -157,6 +163,9 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, @@ -182,6 +191,9 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, @@ -207,6 +219,9 @@ const struct sof_intel_dsp_desc adls_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, .sdw_shim_base = SDW_SHIM_BASE, .sdw_alh_base = SDW_ALH_BASE, + .d0i3_offset = SOF_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_common, + .enable_sdw_irq = hda_common_enable_sdw_irq, .check_sdw_irq = hda_common_check_sdw_irq, .check_ipc_irq = hda_dsp_check_ipc_irq, .cl_init = cl_dsp_init, |