diff options
Diffstat (limited to 'sound/soc/intel')
94 files changed, 3327 insertions, 1105 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2db494b0e3cf..412555e626b8 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Intel" + config SND_SOC_INTEL_SST_TOPLEVEL bool "Intel ASoC SST drivers" default y @@ -115,3 +117,5 @@ source "sound/soc/intel/avs/boards/Kconfig" # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" + +endmenu diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 38116c758717..3629ceaaac17 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -142,7 +142,7 @@ static int sst_slot_enum_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; - strcpy(uinfo->value.enumerated.name, + strscpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]); return 0; @@ -218,7 +218,7 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol static int sst_slot_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); struct sst_data *drv = snd_soc_component_get_drvdata(c); struct sst_enum *e = (void *)kcontrol->private_value; int i, ret = 0; @@ -349,7 +349,7 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret = 0; - struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); struct sst_algo_control *bc = (void *)kcontrol->private_value; @@ -470,7 +470,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret = 0; - struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; struct sst_gain_value *gv = mc->gain_val; @@ -637,7 +637,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, * inputs as an IPC to the DSP. */ for (i = 0; i < w->num_kcontrols; i++) { - if (dapm_kcontrol_get_value(w->kcontrols[i])) { + if (snd_soc_dapm_kcontrol_get_value(w->kcontrols[i])) { mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value; val |= 1 << mc->shift; } @@ -1530,8 +1530,7 @@ static int sst_map_modules_to_pipe(struct snd_soc_component *component) int sst_dsp_init_v2_dpcm(struct snd_soc_component *component) { int i, ret = 0; - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); struct sst_data *drv = snd_soc_component_get_drvdata(component); unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3; @@ -1544,7 +1543,7 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_component *component) ARRAY_SIZE(sst_dapm_widgets)); snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(dapm->card); + snd_soc_dapm_new_widgets(component->card); for (i = 0; i < gains; i++) { sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT; diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c index 89c9c5ad6b21..9dfb0a814b94 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-compress.c +++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c @@ -18,6 +18,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/compress_driver.h> +#include <asm/div64.h> #include "sst-mfld-platform.h" /* compress stream operations */ @@ -202,15 +203,16 @@ static int sst_platform_compr_trigger(struct snd_soc_component *component, static int sst_platform_compr_pointer(struct snd_soc_component *component, struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct sst_runtime_stream *stream; + u64 temp_copied_total = tstamp->copied_total; - stream = cstream->runtime->private_data; + stream = cstream->runtime->private_data; stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); - tstamp->byte_offset = tstamp->copied_total % - (u32)cstream->runtime->buffer_size; - pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); + tstamp->byte_offset = + do_div(temp_copied_total, cstream->runtime->buffer_size); + pr_debug("calc bytes offset/copied bytes as %u\n", tstamp->byte_offset); return 0; } diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 8b5777d3229a..a0e33f7f01c5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -105,7 +105,7 @@ struct compress_sst_ops { int (*stream_pause_release)(struct device *dev, unsigned int str_id); int (*tstamp)(struct device *dev, unsigned int str_id, - struct snd_compr_tstamp *tstamp); + struct snd_compr_tstamp64 *tstamp); int (*ack)(struct device *dev, unsigned int str_id, unsigned long bytes); int (*close)(struct device *dev, unsigned int str_id); diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index e0357d257c6c..3c47c8de04b7 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -64,7 +64,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) header.p.header_high.part.done = 0; sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full); - /* write 1 to clear status register */; + /* write 1 to clear status register */ isr.part.done_interrupt = 1; sst_shim_write64(drv->shim, SST_ISRX, isr.full); spin_unlock(&drv->ipc_spin_lock); diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 126903e126e4..c43946c5ecee 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -443,9 +443,6 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param); int sst_set_metadata(int str_id, char *params); int sst_get_stream(struct intel_sst_drv *ctx, struct snd_sst_params *str_param); -int sst_get_stream_allocated(struct intel_sst_drv *ctx, - struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld); int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, int str_id, bool partial_drain); int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, @@ -461,8 +458,6 @@ void sst_post_download_mrfld(struct intel_sst_drv *ctx); int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx); -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block); int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block); int sst_create_ipc_msg(struct ipc_post **arg, bool large); @@ -470,7 +465,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id); void sst_clean_stream(struct stream_info *stream); int intel_sst_register_compress(struct intel_sst_drv *sst); int intel_sst_remove_compress(struct intel_sst_drv *sst); -void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id); int sst_send_sync_msg(int ipc, int str_id); int sst_get_num_channel(struct snd_sst_params *str_param); int sst_get_sfreq(struct snd_sst_params *str_param); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 257180630475..73624e1b138a 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -12,6 +12,7 @@ #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/string.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/firmware.h> @@ -356,7 +357,7 @@ static int sst_acpi_probe(struct platform_device *pdev) /* Fill sst platform data */ ctx->pdata = pdata; - strcpy(ctx->firmware_name, mach->fw_filename); + strscpy(ctx->firmware_name, mach->fw_filename); ret = sst_platform_get_resources(ctx); if (ret) diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index dc31c2c8f54c..2646c4632ca1 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -55,19 +55,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) return ret; } -int sst_get_stream_allocated(struct intel_sst_drv *ctx, - struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld) -{ - int retval; - - retval = ctx->ops->alloc_stream(ctx, str_param); - if (retval > 0) - dev_dbg(ctx->dev, "Stream allocated %d\n", retval); - return retval; - -} - /* * sst_get_sfreq - this function returns the frequency of the stream * @@ -339,7 +326,7 @@ static int sst_cdev_stream_partial_drain(struct device *dev, } static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, - struct snd_compr_tstamp *tstamp) + struct snd_compr_tstamp64 *tstamp) { struct snd_sst_tstamp fw_tstamp = {0,}; struct stream_info *stream; @@ -362,10 +349,11 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24)); tstamp->sampling_rate = fw_tstamp.sampling_frequency; - dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); - dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n", + dev_dbg(dev, "PCM = %llu\n", tstamp->pcm_io_frames); + dev_dbg(dev, + "Ptr Query on strid = %d copied_total %llu, decodec %llu\n", str_id, tstamp->copied_total, tstamp->pcm_frames); - dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames); + dev_dbg(dev, "rendered %llu\n", tstamp->pcm_io_frames); return 0; } @@ -430,17 +418,6 @@ static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec) return 0; } -void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id) -{ - struct stream_info *stream; - - dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n", - str_id); - stream = &ctx->streams[str_id]; - if (stream->compr_cb) - stream->compr_cb(stream->compr_cb_param); -} - /* * sst_close_pcm_stream - Close PCM interface * diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index d1e64c3500be..22ae2d22f121 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -26,7 +26,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) int ddr_base, ret = 0; struct pci_dev *pci = ctx->pci; - ret = pci_request_regions(pci, SST_DRV_NAME); + ret = pcim_request_all_regions(pci, SST_DRV_NAME); if (ret) return ret; @@ -38,67 +38,57 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); if (!ctx->pdata->lib_info) { dev_err(ctx->dev, "lib_info pointer NULL\n"); - ret = -EINVAL; - goto do_release_regions; + return -EINVAL; } if (ddr_base != ctx->pdata->lib_info->mod_base) { dev_err(ctx->dev, "FW LSP DDR BASE does not match with IFWI\n"); - ret = -EINVAL; - goto do_release_regions; + return -EINVAL; } ctx->ddr_end = pci_resource_end(pci, 0); - ctx->ddr = pcim_iomap(pci, 0, - pci_resource_len(pci, 0)); - if (!ctx->ddr) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->ddr = pcim_iomap(pci, 0, 0); + if (!ctx->ddr) + return -ENOMEM; + dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr); } else { ctx->ddr = NULL; } /* SHIM */ ctx->shim_phy_add = pci_resource_start(pci, 1); - ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1)); - if (!ctx->shim) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->shim = pcim_iomap(pci, 1, 0); + if (!ctx->shim) + return -ENOMEM; + dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim); /* Shared SRAM */ ctx->mailbox_add = pci_resource_start(pci, 2); - ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2)); - if (!ctx->mailbox) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->mailbox = pcim_iomap(pci, 2, 0); + if (!ctx->mailbox) + return -ENOMEM; + dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox); /* IRAM */ ctx->iram_end = pci_resource_end(pci, 3); ctx->iram_base = pci_resource_start(pci, 3); - ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3)); - if (!ctx->iram) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->iram = pcim_iomap(pci, 3, 0); + if (!ctx->iram) + return -ENOMEM; + dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram); /* DRAM */ ctx->dram_end = pci_resource_end(pci, 4); ctx->dram_base = pci_resource_start(pci, 4); - ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4)); - if (!ctx->dram) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->dram = pcim_iomap(pci, 4, 0); + if (!ctx->dram) + return -ENOMEM; + dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); -do_release_regions: - pci_release_regions(pci); - return ret; + return 0; } /* @@ -167,7 +157,6 @@ static void intel_sst_remove(struct pci_dev *pci) sst_context_cleanup(sst_drv_ctx); pci_dev_put(sst_drv_ctx->pci); - pci_release_regions(pci); pci_set_drvdata(pci, NULL); } diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index e6a5c18a7018..c01b29616ebc 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -70,39 +70,6 @@ void sst_set_fw_state_locked( } /* - * sst_wait_interruptible - wait on event - * - * @sst_drv_ctx: Driver context - * @block: Driver block to wait on - * - * This function waits without a timeout (and is interruptable) for a - * given block event - */ -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block) -{ - int retval = 0; - - if (!wait_event_interruptible(sst_drv_ctx->wait_queue, - block->condition)) { - /* event wake */ - if (block->ret_code < 0) { - dev_err(sst_drv_ctx->dev, - "stream failed %d\n", block->ret_code); - retval = -EBUSY; - } else { - dev_dbg(sst_drv_ctx->dev, "event up\n"); - retval = 0; - } - } else { - dev_err(sst_drv_ctx->dev, "signal interrupted\n"); - retval = -EINTR; - } - return retval; - -} - -/* * sst_wait_timeout - wait on event for timeout * * @sst_drv_ctx: Driver context @@ -292,7 +259,6 @@ int sst_pm_runtime_put(struct intel_sst_drv *sst_drv) { int ret; - pm_runtime_mark_last_busy(sst_drv->dev); ret = pm_runtime_put_autosuspend(sst_drv->dev); if (ret < 0) return ret; diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 5139a019a4ad..576dc0da381d 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-avs-y := dsp.o ipc.o messages.o utils.o core.o loader.o \ - topology.o path.o pcm.o board_selection.o control.o \ - sysfs.o + topology.o path.o pcm.o board_selection.o control.o \ + sysfs.o snd-soc-avs-y += cldma.o -snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o +snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o mtl.o lnl.o ptl.o snd-soc-avs-y += trace.o # tell define_trace.h where to find the trace header diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index 3dccf0a57a3a..b922eeaba843 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <sound/hdaudio_ext.h> #include "avs.h" +#include "debug.h" #include "messages.h" #include "path.h" #include "registers.h" diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 585543f872fc..0f8ddd0e9e5f 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -22,7 +22,6 @@ struct avs_dev; struct avs_tplg; struct avs_tplg_library; -struct avs_soc_component; struct avs_ipc_msg; #ifdef CONFIG_ACPI @@ -69,9 +68,12 @@ extern const struct avs_dsp_ops avs_apl_dsp_ops; extern const struct avs_dsp_ops avs_cnl_dsp_ops; extern const struct avs_dsp_ops avs_icl_dsp_ops; extern const struct avs_dsp_ops avs_tgl_dsp_ops; +extern const struct avs_dsp_ops avs_ptl_dsp_ops; #define AVS_PLATATTR_CLDMA BIT_ULL(0) #define AVS_PLATATTR_IMR BIT_ULL(1) +#define AVS_PLATATTR_ACE BIT_ULL(2) +#define AVS_PLATATTR_ALTHDA BIT_ULL(3) #define avs_platattr_test(adev, attr) \ ((adev)->spec->attributes & AVS_PLATATTR_##attr) @@ -79,7 +81,6 @@ extern const struct avs_dsp_ops avs_tgl_dsp_ops; struct avs_sram_spec { const u32 base_offset; const u32 window_size; - const u32 rom_status_offset; }; struct avs_hipc_spec { @@ -91,6 +92,7 @@ struct avs_hipc_spec { const u32 rsp_offset; const u32 rsp_busy_mask; const u32 ctl_offset; + const u32 sts_offset; }; /* Platform specific descriptor */ @@ -265,8 +267,14 @@ void avs_ipc_block(struct avs_ipc *ipc); int avs_dsp_disable_d0ix(struct avs_dev *adev); int avs_dsp_enable_d0ix(struct avs_dev *adev); +int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power); +int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power); +int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); +int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); +void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable); void avs_skl_ipc_interrupt(struct avs_dev *adev); irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev); +irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev); int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, u32 fifo_full_period, unsigned long resource_mask, u32 *priorities); int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, @@ -339,91 +347,18 @@ struct avs_soc_component { extern const struct snd_soc_dai_ops avs_dai_fe_ops; -int avs_soc_component_register(struct device *dev, const char *name, - const struct snd_soc_component_driver *drv, - struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); -int avs_dmic_platform_register(struct avs_dev *adev, const char *name); -int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, - unsigned long *tdms); -int avs_hda_platform_register(struct avs_dev *adev, const char *name); +int avs_register_dmic_component(struct avs_dev *adev, const char *name); +int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms); +int avs_register_hda_component(struct avs_dev *adev, const char *name); +int avs_register_component(struct device *dev, const char *name, + struct snd_soc_component_driver *drv, + struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); int avs_register_all_boards(struct avs_dev *adev); void avs_unregister_all_boards(struct avs_dev *adev); -/* Firmware tracing helpers */ - -#define avs_log_buffer_size(adev) \ - ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) - -#define avs_log_buffer_addr(adev, core) \ -({ \ - s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ - (__offset < 0) ? NULL : \ - (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ -}) - -static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&adev->trace_lock, flags); - ret = avs_dsp_op(adev, log_buffer_status, msg); - spin_unlock_irqrestore(&adev->trace_lock, flags); - - return ret; -} - -struct avs_apl_log_buffer_layout { - u32 read_ptr; - u32 write_ptr; - u8 buffer[]; -} __packed; -static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); - -#define avs_apl_log_payload_size(adev) \ - (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) - -#define avs_apl_log_payload_addr(addr) \ - (addr + sizeof(struct avs_apl_log_buffer_layout)) - -#ifdef CONFIG_DEBUG_FS -#define AVS_SET_ENABLE_LOGS_OP(name) \ - .enable_logs = avs_##name##_enable_logs - -bool avs_logging_fw(struct avs_dev *adev); -void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); -void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len); - -int avs_probe_platform_register(struct avs_dev *adev, const char *name); - -void avs_debugfs_init(struct avs_dev *adev); -void avs_debugfs_exit(struct avs_dev *adev); -#else -#define AVS_SET_ENABLE_LOGS_OP(name) - -static inline bool avs_logging_fw(struct avs_dev *adev) -{ - return false; -} - -static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) -{ -} - -static inline void -avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len) -{ -} - -static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name) -{ - return 0; -} - -static inline void avs_debugfs_init(struct avs_dev *adev) { } -static inline void avs_debugfs_exit(struct avs_dev *adev) { } -#endif +int avs_parse_sched_cfg(struct avs_dev *adev, const char *buf, size_t len); /* Filesystems integration */ diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 2d706edcbf92..52e6266a7cb8 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -17,10 +17,17 @@ #include <sound/soc-acpi.h> #include <sound/soc-component.h> #include "avs.h" +#include "debug.h" +#include "pcm.h" +#include "utils.h" -static bool i2s_test; -module_param(i2s_test, bool, 0444); -MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards"); +static char *i2s_test; +module_param(i2s_test, charp, 0444); +MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port"); + +bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE); +module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444); +MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes"); static const struct dmi_system_id kbl_dmi_table[] = { { @@ -51,19 +58,13 @@ static const struct dmi_system_id kblr_dmi_table[] = { static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; - const struct dmi_system_id *dmi_id; struct dmi_system_id *dmi_table; - if (mach->quirk_data == NULL) - return mach; - dmi_table = (struct dmi_system_id *)mach->quirk_data; - dmi_id = dmi_first_match(dmi_table); - if (!dmi_id) - return NULL; - - return mach; + if (!dmi_table || dmi_first_match(dmi_table)) + return mach; + return NULL; } #define AVS_SSP(x) (BIT(x)) @@ -141,7 +142,7 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { .mach_params = { .i2s_link_mask = AVS_SSP(0), }, - .pdata = (unsigned long[]){ 0x2, 0, 0, 0, 0, 0 }, /* SSP0 TDMs */ + .pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } }, .tplg_filename = "rt5514-tplg.bin", }, { @@ -202,7 +203,9 @@ static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = { .mach_params = { .i2s_link_mask = AVS_SSP_RANGE(0, 5), }, - .pdata = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }, /* SSP2 TDMs */ + .pdata = (struct avs_mach_pdata[]){ { + .tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 } + } }, .tplg_filename = "tdf8532-tplg.bin", }, { @@ -302,72 +305,53 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { .tplg_filename = "rt1308-tplg.bin", }, { - .id = "ESSX8336", - .drv_name = "avs_es8336", - .mach_params = { - .i2s_link_mask = AVS_SSP(0), - }, - .tplg_filename = "es8336-tplg.bin", - }, - {}, -}; - -static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = { - { - .id = "PCM3168A", - .drv_name = "avs_pcm3168a", - .mach_params = { - .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2), - }, - .tplg_filename = "pcm3168a-tplg.bin", - }, - {} -}; - -static struct snd_soc_acpi_mach avs_test_i2s_machines[] = { - { - .drv_name = "avs_i2s_test", + .id = "10EC5640", + .uid = "1", + .drv_name = "avs_rt5640", .mach_params = { .i2s_link_mask = AVS_SSP(0), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "rt5640-tplg.bin", }, { - .drv_name = "avs_i2s_test", + .id = "10EC5640", + .uid = "3", + .drv_name = "avs_rt5640", .mach_params = { .i2s_link_mask = AVS_SSP(1), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "rt5640-tplg.bin", }, { - .drv_name = "avs_i2s_test", + .id = "10EC5640", + .uid = "2", + .drv_name = "avs_rt5640", .mach_params = { .i2s_link_mask = AVS_SSP(2), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "rt5640-tplg.bin", }, { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(3), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, - { - .drv_name = "avs_i2s_test", + .id = "ESSX8336", + .drv_name = "avs_es8336", .mach_params = { - .i2s_link_mask = AVS_SSP(4), + .i2s_link_mask = AVS_SSP(0), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "es8336-tplg.bin", }, + {}, +}; + +static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = { { - .drv_name = "avs_i2s_test", + .id = "PCM3168A", + .drv_name = "avs_pcm3168a", .mach_params = { - .i2s_link_mask = AVS_SSP(5), + .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "pcm3168a-tplg.bin", }, - /* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */ + {} }; struct avs_acpi_boards { @@ -380,10 +364,10 @@ struct avs_acpi_boards { /* supported I2S boards per platform */ static const struct avs_acpi_boards i2s_boards[] = { - AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), - AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), - AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), - AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), + AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines), + AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), + AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), + AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines), AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines), AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines), @@ -394,144 +378,183 @@ static const struct avs_acpi_boards i2s_boards[] = { AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines), - {} + AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines), + { }, }; -static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev) +static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev) { int id, i; id = adev->base.pci->device; for (i = 0; i < ARRAY_SIZE(i2s_boards); i++) if (i2s_boards[i].id == id) - return &i2s_boards[i]; + return i2s_boards[i].machs; return NULL; } -/* platform devices owned by AVS audio are removed with this hook */ -static void board_pdev_unregister(void *data) +/* Platform devices spawned by AVS driver are removed with this hook. */ +static void avs_unregister_board(void *pdev) { - platform_device_unregister(data); + platform_device_unregister(pdev); } -static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) +static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name, + const void *data, size_t size) { - struct platform_device *board; - struct snd_soc_acpi_mach mach = {{0}}; + struct platform_device *pdev; int ret; - ret = avs_probe_platform_register(adev, "probe-platform"); - if (ret < 0) - return ret; + pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size); + if (IS_ERR(pdev)) + return pdev; - mach.mach_params.platform = "probe-platform"; + ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev); + if (ret) + return ERR_PTR(ret); - board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE, - (const void *)&mach, sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "probe board register failed\n"); - return PTR_ERR(board); - } + return pdev; +} - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - return 0; +static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name, + struct snd_soc_acpi_mach *mach, + struct hda_codec *codec, + unsigned long *tdms, char *codec_name) +{ + struct avs_mach_pdata *pdata; + + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->codec = codec; + pdata->tdms = tdms; + pdata->codec_name = codec_name; + pdata->obsolete_card_names = obsolete_card_names; + mach->pdata = pdata; + + return avs_register_board(adev, name, mach, sizeof(*mach)); +} + +static int __maybe_unused avs_register_probe_board(struct avs_dev *adev) +{ + struct platform_device *pdev; + + pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_probe_component(adev, dev_name(&pdev->dev)); } static int avs_register_dmic_board(struct avs_dev *adev) { - struct platform_device *codec, *board; - struct snd_soc_acpi_mach mach = {{0}}; - int ret; + static struct snd_soc_acpi_mach mach = { + .tplg_filename = "dmic-tplg.bin", + }; + struct platform_device *pdev; + char *codec_name; if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) { dev_dbg(adev->dev, "no DMIC endpoints present\n"); return 0; } - codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); - if (IS_ERR(codec)) { - dev_err(adev->dev, "dmic codec register failed\n"); - return PTR_ERR(codec); - } + /* DMIC present in Intel PCH is enumerated statically. */ + pdev = avs_register_board(adev, "dmic-codec", NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = devm_add_action(adev->dev, board_pdev_unregister, codec); - if (ret < 0) { - platform_device_unregister(codec); - return ret; - } + codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL); + if (!codec_name) + return -ENOMEM; - ret = avs_dmic_platform_register(adev, "dmic-platform"); - if (ret < 0) - return ret; + pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - mach.tplg_filename = "dmic-tplg.bin"; - mach.mach_params.platform = "dmic-platform"; + return avs_register_dmic_component(adev, dev_name(&pdev->dev)); +} - board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE, - (const void *)&mach, sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "dmic board register failed\n"); - return PTR_ERR(board); - } +static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot) +{ + struct snd_soc_acpi_mach mach = {{0}}; + struct platform_device *pdev; + unsigned long *tdms; + + tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL); + mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, + AVS_STRING_FMT("i2s", "-test-tplg.bin", + ssp_port, tdm_slot)); + if (!tdms || !mach.tplg_filename) + return -ENOMEM; - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } + tdms[ssp_port] = BIT(tdm_slot); + mach.drv_name = "avs_i2s_test"; + mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port); - return 0; + pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms); } -static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) +static int avs_register_i2s_test_boards(struct avs_dev *adev) { - struct platform_device *board; - int num_ssps; - char *name; - int ret; + int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count; + int ssp_port, tdm_slot, ret; + unsigned long tdm_slots; + u32 *array, num_elems; - num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; - if (fls(mach->mach_params.i2s_link_mask) > num_ssps) { - dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n", - num_ssps, mach->drv_name, - (unsigned long)__fls(mach->mach_params.i2s_link_mask)); - return -ENODEV; - } - - name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, - mach->mach_params.i2s_link_mask); - if (!name) - return -ENOMEM; + if (!i2s_test) + return 0; - ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata); - if (ret < 0) + ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array); + if (ret) { + dev_err(adev->dev, "failed to parse i2s_test parameter\n"); return ret; + } - mach->mach_params.platform = name; - - board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask, - (const void *)mach, sizeof(*mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "ssp board register failed\n"); - return PTR_ERR(board); + num_elems = *array; + if (num_elems > max_ssps) { + dev_err(adev->dev, "board supports only %d SSP, %d specified\n", + max_ssps, num_elems); + return -EINVAL; } - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; + for (ssp_port = 0; ssp_port < num_elems; ssp_port++) { + tdm_slots = array[1 + ssp_port]; + for_each_set_bit(tdm_slot, &tdm_slots, 16) { + ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot); + if (ret) + return ret; + } } return 0; } +static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) +{ + u32 i2s_mask = mach->mach_params.i2s_link_mask; + struct platform_device *pdev; + unsigned long *tdms = NULL; + + if (mach->pdata) + tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms; + + pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms); +} + static int avs_register_i2s_boards(struct avs_dev *adev) { - const struct avs_acpi_boards *boards; + int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; + struct snd_soc_acpi_mach *machs; struct snd_soc_acpi_mach *mach; int ret; @@ -540,34 +563,22 @@ static int avs_register_i2s_boards(struct avs_dev *adev) return 0; } - if (i2s_test) { - int i, num_ssps; - - num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; - /* constrain just in case FW says there can be more SSPs than possible */ - num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps); - - mach = avs_test_i2s_machines; - - for (i = 0; i < num_ssps; i++) { - ret = avs_register_i2s_board(adev, &mach[i]); - if (ret < 0) - dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, - ret); - } - return 0; - } - - boards = avs_get_i2s_boards(adev); - if (!boards) { + machs = avs_get_i2s_machines(adev); + if (!machs) { dev_dbg(adev->dev, "no I2S endpoints supported\n"); return 0; } - for (mach = boards->machs; mach->id[0]; mach++) { + for (mach = machs; mach->id[0]; mach++) { if (!acpi_dev_present(mach->id, mach->uid, -1)) continue; + if (fls(mach->mach_params.i2s_link_mask) > num_ssps) { + dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n", + num_ssps, mach->drv_name, + (unsigned long)__fls(mach->mach_params.i2s_link_mask)); + continue; + } if (mach->machine_quirk) if (!mach->machine_quirk(mach)) continue; @@ -582,42 +593,20 @@ static int avs_register_i2s_boards(struct avs_dev *adev) static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) { - struct snd_soc_acpi_mach mach = {{0}}; - struct platform_device *board; struct hdac_device *hdev = &codec->core; - char *pname; - int ret, id; - - pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev)); - if (!pname) - return -ENOMEM; - - ret = avs_hda_platform_register(adev, pname); - if (ret < 0) - return ret; + struct snd_soc_acpi_mach mach = {{0}}; + struct platform_device *pdev; - mach.pdata = codec; - mach.mach_params.platform = pname; mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin", hdev->vendor_id); if (!mach.tplg_filename) return -ENOMEM; - id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr; - board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach, - sizeof(mach)); - if (IS_ERR(board)) { - dev_err(adev->dev, "hda board register failed\n"); - return PTR_ERR(board); - } + pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = devm_add_action(adev->dev, board_pdev_unregister, board); - if (ret < 0) { - platform_device_unregister(board); - return ret; - } - - return 0; + return avs_register_hda_component(adev, dev_name(&pdev->dev)); } static int avs_register_hda_boards(struct avs_dev *adev) @@ -660,6 +649,10 @@ int avs_register_all_boards(struct avs_dev *adev) dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n", ret); + ret = avs_register_i2s_test_boards(adev); + if (ret) + dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret); + ret = avs_register_i2s_boards(adev); if (ret < 0) dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n", diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index ba4bee42124c..82f50207bb2f 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -4,6 +4,14 @@ menu "Intel AVS Machine drivers" comment "Available DSP configurations" +config SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE + bool "Use obsolete card names" + default n + help + Use obsolete names for some of avs cards. This option should be + used if your system depends on old card names, for example having + not up to date UCM files. + config SND_SOC_INTEL_AVS_MACH_DA7219 tristate "da7219 I2S board" depends on I2C @@ -145,6 +153,18 @@ config SND_SOC_INTEL_AVS_MACH_RT5514 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_RT5640 + tristate "rt5640 in I2S mode" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT5640 + help + This adds support for ASoC machine board connecting AVS with RT5640, + components representing Intel AudioDSP and Realtek 5640 codec respectively. + The codec chip is present on I2C bus and the streaming occurs over I2S + interface. + Say Y or m if you have such a device. + config SND_SOC_INTEL_AVS_MACH_RT5663 tristate "rt5663 in I2S mode" depends on I2C diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index a95256b94dc8..46ef1babda34 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -15,6 +15,7 @@ snd-soc-avs-rt274-y := rt274.o snd-soc-avs-rt286-y := rt286.o snd-soc-avs-rt298-y := rt298.o snd-soc-avs-rt5514-y := rt5514.o +snd-soc-avs-rt5640-y := rt5640.o snd-soc-avs-rt5663-y := rt5663.o snd-soc-avs-rt5682-y := rt5682.o snd-soc-avs-ssm4567-y := ssm4567.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5514) += snd-soc-avs-rt5514.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5640) += snd-soc-avs-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 7217ae51e89c..2b17abcbd2bc 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -29,8 +29,7 @@ static const struct snd_kcontrol_new card_controls[] = { static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; int ret = 0; @@ -165,8 +164,8 @@ avs_da7219_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_param return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -176,8 +175,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); @@ -193,6 +190,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -214,20 +212,20 @@ static int avs_da7219_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -238,7 +236,12 @@ static int avs_da7219_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_da7219"; + if (pdata->obsolete_card_names) { + card->name = "avs_da7219"; + } else { + card->driver_name = "avs_da7219"; + card->long_name = card->name = "AVS I2S DA7219"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -252,11 +255,7 @@ static int avs_da7219_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_da7219_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index 4dd9591ee98b..bf6f580a5164 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -10,33 +10,10 @@ #include <linux/module.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include "../utils.h" SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); -/* Name overridden on probe */ -SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM(""))); - -static struct snd_soc_dai_link card_dai_links[] = { - /* Back ends */ - { - .name = "DMIC", - .id = 0, - .capture_only = 1, - .nonatomic = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "DMIC WoV", - .id = 1, - .capture_only = 1, - .nonatomic = 1, - .no_pcm = 1, - .ignore_suspend = 1, - SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform), - }, -}; static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), @@ -46,35 +23,84 @@ static const struct snd_soc_dapm_route card_routes[] = { {"DMic", NULL, "SoC DMIC"}, }; +static int avs_create_dai_links(struct device *dev, const char *codec_name, + struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + const int num_dl = 2; + + dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->codecs) + return -ENOMEM; + + dl->codecs->name = devm_kstrdup(dev, codec_name, GFP_KERNEL); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "dmic-hifi"); + if (!dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + platform->name = dev_name(dev); + dl[0].num_cpus = 1; + dl[0].num_codecs = 1; + dl[0].platforms = platform; + dl[0].num_platforms = 1; + dl[0].nonatomic = 1; + dl[0].no_pcm = 1; + dl[0].capture_only = 1; + memcpy(&dl[1], &dl[0], sizeof(*dl)); + + dl[0].name = "DMIC"; + dl[0].cpus = dmic_pin; + dl[0].id = 0; + dl[1].name = "DMIC WoV"; + dl[1].cpus = dmic_wov_pin; + dl[1].id = 1; + dl[1].ignore_suspend = 1; + + *links = dl; + *num_links = num_dl; + return 0; +} + static int avs_dmic_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; - struct device *dev = &pdev->dev; int ret; mach = dev_get_platdata(dev); + pdata = mach->pdata; card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; - card->name = "avs_dmic"; + ret = avs_create_dai_links(dev, pdata->codec_name, &card->dai_link, &card->num_links); + if (ret) + return ret; + + if (pdata->obsolete_card_names) { + card->name = "avs_dmic"; + } else { + card->driver_name = "avs_dmic"; + card->long_name = card->name = "AVS DMIC"; + } card->dev = dev; card->owner = THIS_MODULE; - card->dai_link = card_dai_links; - card->num_links = ARRAY_SIZE(card_dai_links); card->dapm_widgets = card_widgets; card->num_dapm_widgets = ARRAY_SIZE(card_widgets); card->dapm_routes = card_routes; card->num_dapm_routes = ARRAY_SIZE(card_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_dmic_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 6f3c4f6c9302..301cfb3cf15b 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -38,7 +38,7 @@ static const struct acpi_gpio_mapping speaker_gpios[] = { static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_card *card = w->dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct avs_card_drvdata *data; bool speaker_en; @@ -101,6 +101,7 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct snd_soc_jack_pin *pins; struct avs_card_drvdata *data; struct gpio_desc *gpiod; @@ -132,7 +133,7 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_soc_component_set_jack(component, &data->jack, NULL); - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); return 0; } @@ -195,8 +196,9 @@ static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime, return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) + +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -206,8 +208,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -222,6 +222,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -259,20 +260,20 @@ static int avs_es8336_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct avs_card_drvdata *data; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -283,7 +284,12 @@ static int avs_es8336_probe(struct platform_device *pdev) if (!data || !card) return -ENOMEM; - card->name = "avs_es8336"; + if (pdata->obsolete_card_names) { + card->name = "avs_es8336"; + } else { + card->driver_name = "avs_es8336"; + card->long_name = card->name = "AVS I2S ES8336"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -299,11 +305,7 @@ static int avs_es8336_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, data); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_es8336_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index cb6d54db7189..aec769e2396c 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -13,9 +13,10 @@ #include <sound/soc.h> #include <sound/soc-acpi.h> #include "../../../codecs/hda.h" +#include "../utils.h" static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count, - const char *platform_name, struct snd_soc_dai_link **links) + struct snd_soc_dai_link **links) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -28,7 +29,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; + platform->name = dev_name(dev); pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { @@ -95,7 +96,8 @@ avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx) static int avs_card_late_probe(struct snd_soc_card *card) { struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); - struct hda_codec *codec = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + struct hda_codec *codec = pdata->codec; struct hda_pcm *hpcm; /* Topology pcm indexing is 1-based */ int i = 1; @@ -124,6 +126,7 @@ static int avs_card_late_probe(struct snd_soc_card *card) static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) { struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_dai_link *links = NULL; struct snd_soc_card *card = rtm->card; struct hda_codec *codec; @@ -131,14 +134,15 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) int ret, pcm_count = 0; mach = dev_get_platdata(card->dev); - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; if (list_empty(&codec->pcm_list_head)) return -EINVAL; list_for_each_entry(pcm, &codec->pcm_list_head, list) pcm_count++; - ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links); + ret = avs_create_dai_links(card->dev, codec, pcm_count, &links); if (ret < 0) { dev_err(card->dev, "create links failed: %d\n", ret); return ret; @@ -167,12 +171,14 @@ static int avs_hdaudio_probe(struct platform_device *pdev) { struct snd_soc_dai_link *binder; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; struct hda_codec *codec; mach = dev_get_platdata(dev); - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; /* codec may be unloaded before card's probe() fires */ if (!device_is_registered(&codec->core.dev)) @@ -191,7 +197,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (!binder->codecs->name) return -ENOMEM; - binder->platforms->name = mach->mach_params.platform; + binder->platforms->name = dev_name(dev); binder->num_platforms = 1; binder->codecs->dai_name = "codec-probing-DAI"; binder->num_codecs = 1; @@ -200,7 +206,19 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = binder->codecs->name; + if (pdata->obsolete_card_names) { + card->name = devm_kasprintf(dev, GFP_KERNEL, "hdaudioB%dD%d", codec->bus->core.idx, + codec->core.addr); + if (!card->name) + return -ENOMEM; + } else { + card->driver_name = "avs_hdaudio"; + if (hda_codec_is_display(codec)) + card->long_name = card->name = "AVS HDMI"; + else + card->long_name = card->name = "AVS HD-Audio"; + } + card->dev = dev; card->owner = THIS_MODULE; card->dai_link = binder; @@ -209,7 +227,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (hda_codec_is_display(codec)) card->late_probe = avs_card_late_probe; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_hdaudio_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 4556f105c793..9a6b89ffdf14 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -14,8 +14,8 @@ #include <sound/soc-dapm.h> #include "../utils.h" -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -25,8 +25,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -39,6 +37,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -56,13 +55,13 @@ static int avs_i2s_test_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; if (!avs_mach_singular_ssp(mach)) { dev_err(dev, "Invalid SSP configuration\n"); @@ -80,12 +79,19 @@ static int avs_i2s_test_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "-loopback", ssp_port, tdm_slot)); + if (pdata->obsolete_card_names) { + card->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("ssp", "-loopback", ssp_port, tdm_slot)); + } else { + card->driver_name = "avs_i2s_test"; + card->long_name = card->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("AVS I2S TEST-", "", + ssp_port, tdm_slot)); + } if (!card->name) return -ENOMEM; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d\n", ret); return ret; @@ -97,11 +103,7 @@ static int avs_i2s_test_probe(struct platform_device *pdev) card->num_links = 1; card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_i2s_test_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index c55c1d60b777..e9a87804f918 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -46,8 +46,8 @@ avs_max98357a_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_pa return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -57,8 +57,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -73,6 +71,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -93,19 +92,19 @@ static int avs_max98357a_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -115,7 +114,12 @@ static int avs_max98357a_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98357a"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98357a"; + } else { + card->driver_name = "avs_max98357a"; + card->long_name = card->name = "AVS I2S MAX98357A"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -128,11 +132,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98357a_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index 970f82bf4ce8..8b45b643ca29 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -95,8 +95,8 @@ static const struct snd_soc_ops avs_max98373_ops = { .hw_params = avs_max98373_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -106,8 +106,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -125,6 +123,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -146,19 +145,19 @@ static int avs_max98373_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -168,7 +167,12 @@ static int avs_max98373_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98373"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98373"; + } else { + card->driver_name = "avs_max98373"; + card->long_name = card->name = "AVS I2S MAX98373"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -183,11 +187,7 @@ static int avs_max98373_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98373_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index e4ce553bf1d6..db073125fa4d 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -92,8 +92,8 @@ static const struct snd_soc_ops avs_max98927_ops = { .hw_params = avs_max98927_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -103,8 +103,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -122,6 +120,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -143,19 +142,19 @@ static int avs_max98927_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -165,7 +164,12 @@ static int avs_max98927_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98927"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98927"; + } else { + card->driver_name = "avs_max98927"; + card->long_name = card->name = "AVS I2S MAX98927"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -180,11 +184,7 @@ static int avs_max98927_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98927_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index e203ceb83b87..d44edacbfc9a 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -23,8 +23,7 @@ static int avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; int ret; @@ -172,8 +171,8 @@ static const struct snd_soc_ops avs_nau8825_ops = { .trigger = avs_nau8825_trigger, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -183,8 +182,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -199,6 +196,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -246,20 +244,20 @@ static int avs_nau8825_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -270,7 +268,12 @@ static int avs_nau8825_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_nau8825"; + if (pdata->obsolete_card_names) { + card->name = "avs_nau8825"; + } else { + card->driver_name = "avs_nau8825"; + card->long_name = card->name = "AVS I2S NAU8825"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -286,11 +289,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_nau8825_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c index 5d0e7a5bdc74..b5bebadbbcb2 100644 --- a/sound/soc/intel/avs/boards/pcm3168a.c +++ b/sound/soc/intel/avs/boards/pcm3168a.c @@ -11,6 +11,8 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../utils.h" static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL), @@ -95,10 +97,15 @@ static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **li static int avs_pcm3168a_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct device *dev = &pdev->dev; struct snd_soc_card *card; int ret; + mach = dev_get_platdata(dev); + pdata = mach->pdata; + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; @@ -107,7 +114,12 @@ static int avs_pcm3168a_probe(struct platform_device *pdev) if (ret) return ret; - card->name = "avs_pcm3168a"; + if (pdata->obsolete_card_names) { + card->name = "avs_pcm3168a"; + } else { + card->driver_name = "avs_pcm3168a"; + card->long_name = card->name = "AVS I2S PCM3168A"; + } card->dev = dev; card->owner = THIS_MODULE; card->dapm_widgets = card_widgets; @@ -116,7 +128,7 @@ static int avs_pcm3168a_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_routes); card->fully_routed = true; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_pcm3168a_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 1cdc285ab810..73884f8a535c 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -9,45 +9,55 @@ #include <linux/device.h> #include <linux/module.h> #include <sound/soc.h> -#include <sound/soc-acpi.h> -SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); -SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI"))); -SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform"))); +static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link *dl; -static struct snd_soc_dai_link probe_mb_dai_links[] = { - { - .name = "Compress Probe Capture", - .nonatomic = 1, - SND_SOC_DAILINK_REG(probe_cp, dummy, platform), - }, -}; + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + if (!dl) + return -ENOMEM; + + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->platforms = devm_kzalloc(dev, sizeof(*dl->platforms), GFP_KERNEL); + if (!dl->cpus || !dl->platforms) + return -ENOMEM; + + dl->name = "Compress Probe Capture"; + dl->cpus->dai_name = "Probe Extraction CPU DAI"; + dl->num_cpus = 1; + dl->codecs = &snd_soc_dummy_dlc; + dl->num_codecs = 1; + dl->platforms->name = dev_name(dev); + dl->num_platforms = 1; + dl->nonatomic = 1; + + *links = dl; + *num_links = 1; + return 0; +} static int avs_probe_mb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct snd_soc_acpi_mach *mach; struct snd_soc_card *card; int ret; - mach = dev_get_platdata(dev); - card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; - card->name = "avs_probe_mb"; + ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links); + if (ret) + return ret; + + card->driver_name = "avs_probe_mb"; + card->long_name = card->name = "AVS PROBE"; card->dev = dev; card->owner = THIS_MODULE; - card->dai_link = probe_mb_dai_links; - card->num_links = ARRAY_SIZE(probe_mb_dai_links); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_probe_mb_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 29977aee2153..a689f4c80867 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -27,8 +27,7 @@ static const struct snd_kcontrol_new card_controls[] = { static int avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; int ret; @@ -93,6 +92,7 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_jack_pin *pins; struct snd_soc_jack *jack; struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int num_pins, ret; jack = snd_soc_card_get_drvdata(card); @@ -117,7 +117,7 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); return 0; } @@ -147,8 +147,8 @@ static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -158,8 +158,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -174,6 +172,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -210,20 +209,20 @@ static int avs_rt274_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -234,7 +233,12 @@ static int avs_rt274_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt274"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt274"; + } else { + card->driver_name = "avs_rt274"; + card->long_name = card->name = "AVS I2S ALC274"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -250,11 +254,7 @@ static int avs_rt274_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt274_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 6a27c6a9f394..4c9ac545555a 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -115,8 +115,8 @@ static const struct snd_soc_ops avs_rt286_ops = { .hw_params = avs_rt286_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -126,8 +126,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -142,6 +140,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -179,20 +178,20 @@ static int avs_rt286_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); @@ -204,7 +203,12 @@ static int avs_rt286_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt286"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt286"; + } else { + card->driver_name = "avs_rt286"; + card->long_name = card->name = "AVS I2S ALC286"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -220,11 +224,7 @@ static int avs_rt286_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt286_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index a7a463d6f852..2d7a7748d577 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -132,8 +132,8 @@ static const struct snd_soc_ops avs_rt298_ops = { .hw_params = avs_rt298_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -143,8 +143,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -159,6 +157,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -199,20 +198,20 @@ static int avs_rt298_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -223,7 +222,12 @@ static int avs_rt298_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt298"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt298"; + } else { + card->driver_name = "avs_rt298"; + card->long_name = card->name = "AVS I2S ALC298"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -239,11 +243,7 @@ static int avs_rt298_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt298_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index d1c3e29a28ff..22139eaad83a 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -33,7 +33,8 @@ static const struct snd_soc_dapm_route card_base_routes[] = { static int avs_rt5514_codec_init(struct snd_soc_pcm_runtime *runtime) { - int ret = snd_soc_dapm_ignore_suspend(&runtime->card->dapm, "DMIC"); + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(runtime->card); + int ret = snd_soc_dapm_ignore_suspend(dapm, "DMIC"); if (ret) dev_err(runtime->dev, "DMIC - Ignore suspend failed = %d\n", ret); @@ -84,8 +85,8 @@ static const struct snd_soc_ops avs_rt5514_ops = { .hw_params = avs_rt5514_hw_params, }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -95,8 +96,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -111,6 +110,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -133,19 +133,19 @@ static int avs_rt5514_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -155,7 +155,12 @@ static int avs_rt5514_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_rt5514"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5514"; + } else { + card->driver_name = "avs_rt5514"; + card->long_name = card->name = "AVS I2S ALC5514"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -166,11 +171,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5514_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c new file mode 100644 index 000000000000..2990d32f2301 --- /dev/null +++ b/sound/soc/intel/avs/boards/rt5640.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2022-2025 Intel Corporation +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/module.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../../../codecs/rt5640.h" +#include "../utils.h" + +#define AVS_RT5640_MCLK_HZ 19200000 +#define RT5640_CODEC_DAI "rt5640-aif1" + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + { "Headphone Jack", NULL, "HPOR" }, + { "Headphone Jack", NULL, "HPOL" }, + { "IN2P", NULL, "Mic Jack" }, + { "IN2P", NULL, "MICBIAS1" }, + { "Speaker", NULL, "SPOLP" }, + { "Speaker", NULL, "SPOLN" }, + { "Speaker", NULL, "SPORP" }, + { "Speaker", NULL, "SPORN" }, +}; + +static const struct snd_soc_jack_pin card_headset_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int avs_rt5640_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); + struct snd_soc_jack_pin *pins; + struct snd_soc_jack *jack; + int num_pins, ret; + + jack = snd_soc_card_get_drvdata(card); + num_pins = ARRAY_SIZE(card_headset_pins); + + pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins, + num_pins); + if (ret) + return ret; + + snd_soc_component_set_jack(codec_dai->component, jack, NULL); + snd_soc_dapm_set_idle_bias(dapm, false); + + return 0; +} + +static void avs_rt5640_codec_exit(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + + snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_rt5640_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* Format 24/32 is MSB-aligned for HDAudio and LSB-aligned for I2S. */ + if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) + snd_mask_set_format(fmask, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int avs_rt5640_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); + int ret; + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_MCLK, AVS_RT5640_MCLK_HZ, + params_rate(params) * 512); + if (ret < 0) { + dev_err(runtime->dev, "Set codec PLL failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(runtime->dev, "Set codec SCLK failed: %d\n", ret); + return ret; + } + + ret = rt5640_sel_asrc_clk_src(codec_dai->component, + RT5640_DA_STEREO_FILTER | RT5640_AD_STEREO_FILTER | + RT5640_DA_MONO_L_FILTER | RT5640_DA_MONO_R_FILTER | + RT5640_AD_MONO_L_FILTER | RT5640_AD_MONO_R_FILTER, + RT5640_CLK_SEL_ASRC); + if (ret) + dev_err(runtime->dev, "Set codec ASRC failed: %d\n", ret); + + return ret; +} + +static const struct snd_soc_ops avs_rt5640_ops = { + .hw_params = avs_rt5640_hw_params, +}; + +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_acpi_mach *mach, + struct snd_soc_dai_link **dai_link) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + u32 uid = 0; + int ret; + + if (mach->uid) { + ret = kstrtou32(mach->uid, 0, &uid); + if (ret) + return ret; + uid--; /* 0-based indexing. */ + } + + dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + dl->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); + dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); + dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); + if (!dl->name || !dl->cpus || !dl->codecs) + return -ENOMEM; + + dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("SSP", " Pin", ssp_port, tdm_slot)); + dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5640:0%d", uid); + dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5640_CODEC_DAI); + if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) + return -ENOMEM; + + platform->name = dev_name(dev); + dl->num_cpus = 1; + dl->num_codecs = 1; + dl->platforms = platform; + dl->num_platforms = 1; + dl->id = 0; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + dl->init = avs_rt5640_codec_init; + dl->exit = avs_rt5640_codec_exit; + dl->be_hw_params_fixup = avs_rt5640_be_fixup; + dl->ops = &avs_rt5640_ops; + dl->nonatomic = 1; + dl->no_pcm = 1; + + *dai_link = dl; + + return 0; +} + +static int avs_card_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + + return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); +} + +static int avs_card_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5640_CODEC_DAI); + struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + + return snd_soc_component_set_jack(codec_dai->component, jack, NULL); +} + +static int avs_rt5640_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link *dai_link; + struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach; + struct snd_soc_card *card; + struct snd_soc_jack *jack; + int ssp_port, tdm_slot, ret; + + mach = dev_get_platdata(dev); + + ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); + if (ret) + return ret; + + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, mach, &dai_link); + if (ret) { + dev_err(dev, "Failed to create dai link: %d", ret); + return ret; + } + + jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL); + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!jack || !card) + return -ENOMEM; + + if (mach->uid) { + card->name = devm_kasprintf(dev, GFP_KERNEL, "AVS I2S ALC5640.%s", mach->uid); + if (!card->name) + return -ENOMEM; + } else { + card->name = "AVS I2S ALC5640"; + } + card->driver_name = "avs_rt5640"; + card->long_name = card->name; + card->dev = dev; + card->owner = THIS_MODULE; + card->suspend_pre = avs_card_suspend_pre; + card->resume_post = avs_card_resume_post; + card->dai_link = dai_link; + card->num_links = 1; + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + snd_soc_card_set_drvdata(card, jack); + + return devm_snd_soc_register_deferrable_card(dev, card); +} + +static const struct platform_device_id avs_rt5640_driver_ids[] = { + { + .name = "avs_rt5640", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); + +static struct platform_driver avs_rt5640_driver = { + .probe = avs_rt5640_probe, + .driver = { + .name = "avs_rt5640", + .pm = &snd_soc_pm_ops, + }, + .id_table = avs_rt5640_driver_ids, +}; + +module_platform_driver(avs_rt5640_driver); + +MODULE_DESCRIPTION("Intel rt5640 machine driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index e3310b3268ba..68fea325376a 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -134,8 +134,8 @@ static const struct snd_soc_ops avs_rt5663_ops = { }; -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -145,8 +145,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -161,6 +159,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -198,20 +197,20 @@ static int avs_rt5663_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct rt5663_private *priv; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -222,7 +221,12 @@ static int avs_rt5663_probe(struct platform_device *pdev) if (!priv || !card) return -ENOMEM; - card->name = "avs_rt5663"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5663"; + } else { + card->driver_name = "avs_rt5663"; + card->long_name = card->name = "AVS I2S ALC5663"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -238,11 +242,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, priv); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5663_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 339df0b944c1..81863728da1d 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -204,8 +204,8 @@ avs_rt5682_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_param return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -215,8 +215,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -231,6 +229,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 1; dl->platforms = platform; @@ -268,10 +267,10 @@ static int avs_rt5682_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; if (pdev->id_entry && pdev->id_entry->driver_data) @@ -281,13 +280,13 @@ static int avs_rt5682_probe(struct platform_device *pdev) dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk); mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -298,7 +297,12 @@ static int avs_rt5682_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt5682"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5682"; + } else { + card->driver_name = "avs_rt5682"; + card->long_name = card->name = "AVS I2S ALC5682"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -314,11 +318,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) card->fully_routed = true; snd_soc_card_set_drvdata(card, jack); - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5682_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 7667790d5273..ae0e6e27a8b8 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -81,8 +81,8 @@ avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_para return 0; } -static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port, - int tdm_slot, struct snd_soc_dai_link **dai_link) +static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, + struct snd_soc_dai_link **dai_link) { struct snd_soc_dai_link_component *platform; struct snd_soc_dai_link *dl; @@ -92,8 +92,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in if (!dl || !platform) return -ENOMEM; - platform->name = platform_name; - dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); @@ -111,6 +109,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in !dl->codecs[1].name || !dl->codecs[1].dai_name) return -ENOMEM; + platform->name = dev_name(dev); dl->num_cpus = 1; dl->num_codecs = 2; dl->platforms = platform; @@ -132,19 +131,19 @@ static int avs_ssm4567_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; - const char *pname; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); - pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) return ret; - ret = avs_create_dai_link(dev, pname, ssp_port, tdm_slot, &dai_link); + ret = avs_create_dai_link(dev, ssp_port, tdm_slot, &dai_link); if (ret) { dev_err(dev, "Failed to create dai link: %d", ret); return ret; @@ -154,7 +153,12 @@ static int avs_ssm4567_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_ssm4567"; + if (pdata->obsolete_card_names) { + card->name = "avs_ssm4567"; + } else { + card->driver_name = "avs_ssm4567"; + card->long_name = card->name = "AVS I2S SSM4567"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -169,11 +173,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - ret = snd_soc_fixup_dai_links_platform_name(card, pname); - if (ret) - return ret; - - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_ssm4567_driver_ids[] = { diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c index 03f8fb0dc187..5b5359e9128b 100644 --- a/sound/soc/intel/avs/cnl.c +++ b/sound/soc/intel/avs/cnl.c @@ -8,6 +8,7 @@ #include <sound/hdaudio_ext.h> #include "avs.h" +#include "debug.h" #include "messages.h" #include "registers.h" diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index 2e01dc75a15a..a8f05de338e0 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.c @@ -15,11 +15,10 @@ static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol); + struct device *dev = snd_soc_dapm_to_dev(dapm); - w = snd_soc_dapm_kcontrol_widget(kcontrol); - - return to_avs_dev(w->dapm->component->dev); + return to_avs_dev(dev); } static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id) diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 8fbf33e30dfc..6e0e65584c7f 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -27,6 +27,7 @@ #include "../../codecs/hda.h" #include "avs.h" #include "cldma.h" +#include "debug.h" #include "messages.h" #include "pcm.h" @@ -54,14 +55,17 @@ void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable) { u32 value = enable ? 0 : pgctl_mask; - avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); + if (!avs_platattr_test(adev, ACE)) + avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); } static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable) { + struct avs_dev *adev = hdac_to_avs(bus); u32 value = enable ? cgctl_mask : 0; - avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); + if (!avs_platattr_test(adev, ACE)) + avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); } void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) @@ -71,6 +75,8 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) { + if (avs_platattr_test(adev, ACE)) + return; if (enable) { if (atomic_inc_and_test(&adev->l1sen_counter)) snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, @@ -99,6 +105,7 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus) static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) { + struct avs_dev *adev = hdac_to_avs(bus); struct hdac_ext_link *hlink; bool ret; @@ -114,7 +121,8 @@ static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) /* Set DUM bit to address incorrect position reporting for capture * streams. In order to do so, CTRL needs to be out of reset state */ - snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); + if (!avs_platattr_test(adev, ACE)) + snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); return ret; } @@ -224,7 +232,6 @@ static void avs_hda_probe_work(struct work_struct *work) /* configure PM */ pm_runtime_set_autosuspend_delay(bus->dev, 2000); pm_runtime_use_autosuspend(bus->dev); - pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); pm_runtime_allow(bus->dev); } @@ -439,23 +446,23 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); if (!adev) return -ENOMEM; + bus = &adev->base.core; + ret = avs_bus_init(adev, pci, id); if (ret < 0) { dev_err(dev, "failed to init avs bus: %d\n", ret); return ret; } - ret = pci_request_regions(pci, "AVS HDAudio"); + ret = pcim_request_all_regions(pci, "AVS HDAudio"); if (ret < 0) return ret; - bus = &adev->base.core; bus->addr = pci_resource_start(pci, 0); bus->remap_addr = pci_ioremap_bar(pci, 0); if (!bus->remap_addr) { dev_err(bus->dev, "ioremap error\n"); - ret = -ENXIO; - goto err_remap_bar0; + return -ENXIO; } adev->dsp_ba = pci_ioremap_bar(pci, 4); @@ -512,8 +519,6 @@ err_init_streams: iounmap(adev->dsp_ba); err_remap_bar4: iounmap(bus->remap_addr); -err_remap_bar0: - pci_release_regions(pci); return ret; } @@ -584,7 +589,6 @@ static void avs_pci_remove(struct pci_dev *pci) pci_free_irq_vectors(pci); iounmap(bus->remap_addr); iounmap(adev->dsp_ba); - pci_release_regions(pci); /* Firmware is not needed anymore */ avs_release_firmwares(adev); @@ -748,13 +752,16 @@ static const struct dev_pm_ops avs_dev_pm = { static const struct avs_sram_spec skl_sram_spec = { .base_offset = SKL_ADSP_SRAM_BASE_OFFSET, .window_size = SKL_ADSP_SRAM_WINDOW_SIZE, - .rom_status_offset = SKL_ADSP_SRAM_BASE_OFFSET, }; static const struct avs_sram_spec apl_sram_spec = { .base_offset = APL_ADSP_SRAM_BASE_OFFSET, .window_size = APL_ADSP_SRAM_WINDOW_SIZE, - .rom_status_offset = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_sram_spec mtl_sram_spec = { + .base_offset = MTL_ADSP_SRAM_BASE_OFFSET, + .window_size = MTL_ADSP_SRAM_WINDOW_SIZE, }; static const struct avs_hipc_spec skl_hipc_spec = { @@ -766,6 +773,19 @@ static const struct avs_hipc_spec skl_hipc_spec = { .rsp_offset = SKL_ADSP_REG_HIPCT, .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, .ctl_offset = SKL_ADSP_REG_HIPCCTL, + .sts_offset = SKL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_hipc_spec apl_hipc_spec = { + .req_offset = SKL_ADSP_REG_HIPCI, + .req_ext_offset = SKL_ADSP_REG_HIPCIE, + .req_busy_mask = SKL_ADSP_HIPCI_BUSY, + .ack_offset = SKL_ADSP_REG_HIPCIE, + .ack_done_mask = SKL_ADSP_HIPCIE_DONE, + .rsp_offset = SKL_ADSP_REG_HIPCT, + .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, + .ctl_offset = SKL_ADSP_REG_HIPCCTL, + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, }; static const struct avs_hipc_spec cnl_hipc_spec = { @@ -777,6 +797,19 @@ static const struct avs_hipc_spec cnl_hipc_spec = { .rsp_offset = CNL_ADSP_REG_HIPCTDR, .rsp_busy_mask = CNL_ADSP_HIPCTDR_BUSY, .ctl_offset = CNL_ADSP_REG_HIPCCTL, + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_hipc_spec lnl_hipc_spec = { + .req_offset = MTL_REG_HfIPCxIDR, + .req_ext_offset = MTL_REG_HfIPCxIDD, + .req_busy_mask = MTL_HfIPCxIDR_BUSY, + .ack_offset = MTL_REG_HfIPCxIDA, + .ack_done_mask = MTL_HfIPCxIDA_DONE, + .rsp_offset = MTL_REG_HfIPCxTDR, + .rsp_busy_mask = MTL_HfIPCxTDR_BUSY, + .ctl_offset = MTL_REG_HfIPCxCTL, + .sts_offset = LNL_REG_HfDFR(0), }; static const struct avs_spec skl_desc = { @@ -796,7 +829,7 @@ static const struct avs_spec apl_desc = { .core_init_mask = 3, .attributes = AVS_PLATATTR_IMR, .sram = &apl_sram_spec, - .hipc = &skl_hipc_spec, + .hipc = &apl_hipc_spec, }; static const struct avs_spec cnl_desc = { @@ -846,6 +879,16 @@ AVS_TGL_BASED_SPEC(ehl, 30); AVS_TGL_BASED_SPEC(adl, 35); AVS_TGL_BASED_SPEC(adl_n, 35); +static const struct avs_spec fcl_desc = { + .name = "fcl", + .min_fw_version = { 0 }, + .dsp_ops = &avs_ptl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_IMR | AVS_PLATATTR_ACE | AVS_PLATATTR_ALTHDA, + .sram = &mtl_sram_spec, + .hipc = &lnl_hipc_spec, +}; + static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) }, @@ -881,6 +924,7 @@ static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &adl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &adl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_FCL, &fcl_desc) }, { 0 } }; MODULE_DEVICE_TABLE(pci, avs_ids); @@ -902,13 +946,14 @@ MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>"); MODULE_DESCRIPTION("Intel cAVS sound driver"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("intel/skl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/apl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/cnl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/icl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/jsl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/lkf/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/tgl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/adl/dsp_basefw.bin"); -MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/skl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/apl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/cnl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/icl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/jsl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/lkf/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/tgl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/ehl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/adl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/avs/adl_n/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin"); diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h new file mode 100644 index 000000000000..94fe8729a5c1 --- /dev/null +++ b/sound/soc/intel/avs/debug.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2024-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H +#define __SOUND_SOC_INTEL_AVS_DEBUG_H + +#include "messages.h" +#include "registers.h" + +struct avs_dev; + +#define avs_log_buffer_size(adev) \ + ((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores) + +#define avs_log_buffer_addr(adev, core) \ +({ \ + s32 __offset = avs_dsp_op(adev, log_buffer_offset, core); \ + (__offset < 0) ? NULL : \ + (avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \ +}) + +static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&adev->trace_lock, flags); + ret = avs_dsp_op(adev, log_buffer_status, msg); + spin_unlock_irqrestore(&adev->trace_lock, flags); + + return ret; +} + +struct avs_apl_log_buffer_layout { + u32 read_ptr; + u32 write_ptr; + u8 buffer[]; +} __packed; +static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); + +#define avs_apl_log_payload_size(adev) \ + (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) + +#define avs_apl_log_payload_addr(addr) \ + (addr + sizeof(struct avs_apl_log_buffer_layout)) + +#ifdef CONFIG_DEBUG_FS +int avs_register_probe_component(struct avs_dev *adev, const char *name); + +#define AVS_SET_ENABLE_LOGS_OP(name) \ + .enable_logs = avs_##name##_enable_logs + +bool avs_logging_fw(struct avs_dev *adev); +void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); +void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len); + +void avs_debugfs_init(struct avs_dev *adev); +void avs_debugfs_exit(struct avs_dev *adev); + +#else +static inline int avs_register_probe_component(struct avs_dev *adev, const char *name) +{ + return -EOPNOTSUPP; +} + +#define AVS_SET_ENABLE_LOGS_OP(name) + +static inline bool avs_logging_fw(struct avs_dev *adev) +{ + return false; +} + +static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len) +{ +} + +static inline void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, + unsigned int len) +{ +} + +static inline void avs_debugfs_init(struct avs_dev *adev) { } +static inline void avs_debugfs_exit(struct avs_dev *adev) { } +#endif + +#endif diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 8c4edda97f75..701c247227bf 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -13,6 +13,7 @@ #include <linux/string_helpers.h> #include <sound/soc.h> #include "avs.h" +#include "debug.h" #include "messages.h" static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len) @@ -118,16 +119,13 @@ static ssize_t probe_points_read(struct file *file, char __user *to, size_t coun } for (i = 0; i < num_desc; i++) { - ret = snprintf(buf + len, PAGE_SIZE - len, - "Id: %#010x Purpose: %d Node id: %#x\n", - desc[i].id.value, desc[i].purpose, desc[i].node_id.val); - if (ret < 0) - goto free_desc; + ret = scnprintf(buf + len, PAGE_SIZE - len, + "Id: %#010x Purpose: %d Node id: %#x\n", + desc[i].id.value, desc[i].purpose, desc[i].node_id.val); len += ret; } ret = simple_read_from_buffer(to, count, ppos, buf, len); -free_desc: kfree(desc); exit: kfree(buf); @@ -144,7 +142,7 @@ static ssize_t probe_points_write(struct file *file, const char __user *from, si int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; @@ -181,7 +179,7 @@ static ssize_t probe_points_disconnect_write(struct file *file, const char __use int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; @@ -315,7 +313,6 @@ err_ipc: if (!adev->logged_resources) { avs_dsp_enable_d0ix(adev); err_d0ix: - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); } @@ -342,7 +339,6 @@ static int disable_logs(struct avs_dev *adev, u32 resource_mask) /* If that's the last resource, allow for D3. */ if (!adev->logged_resources) { avs_dsp_enable_d0ix(adev); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); } @@ -369,11 +365,14 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s int ret; ret = parse_int_array_user(from, count, (int **)&array); - if (ret < 0) + if (ret) return ret; num_elems = *array; - resource_mask = array[1]; + if (!num_elems) { + ret = -EINVAL; + goto free_array; + } /* * Disable if just resource mask is provided - no log priority flags. @@ -381,6 +380,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s * Enable input format: mask, prio1, .., prioN * Where 'N' equals number of bits set in the 'mask'. */ + resource_mask = array[1]; if (num_elems == 1) { ret = disable_logs(adev, resource_mask); } else { diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c index b9de691e9b9b..464bd6859182 100644 --- a/sound/soc/intel/avs/dsp.c +++ b/sound/soc/intel/avs/dsp.c @@ -12,8 +12,6 @@ #include "registers.h" #include "trace.h" -#define AVS_ADSPCS_INTERVAL_US 500 -#define AVS_ADSPCS_TIMEOUT_US 50000 #define AVS_ADSPCS_DELAY_US 1000 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c index f8d327ea2656..d655e727bebd 100644 --- a/sound/soc/intel/avs/icl.c +++ b/sound/soc/intel/avs/icl.c @@ -10,6 +10,7 @@ #include <sound/hdaudio.h> #include <sound/hdaudio_ext.h> #include "avs.h" +#include "debug.h" #include "messages.h" #define ICL_VS_LTRP_GB_ICCMAX 95 diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 08ed9d96738a..c0feb9edd7f6 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <sound/hdaudio_ext.h> #include "avs.h" +#include "debug.h" #include "messages.h" #include "registers.h" #include "trace.h" @@ -141,7 +142,6 @@ static void avs_dsp_recovery(struct avs_dev *adev) if (ret < 0) dev_err(adev->dev, "dsp reboot failed: %d\n", ret); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_enable(adev->dev); pm_request_autosuspend(adev->dev); @@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg dev_crit(adev->dev, "communication severed, rebooting dsp..\n"); - cancel_delayed_work_sync(&ipc->d0ix_work); + /* Avoid deadlock as the exception may be the response to SET_D0IX. */ + if (current_work() != &ipc->d0ix_work.work) + cancel_delayed_work_sync(&ipc->d0ix_work); ipc->in_d0ix = false; /* Re-enabled on recovery completion. */ pm_runtime_disable(adev->dev); diff --git a/sound/soc/intel/avs/lnl.c b/sound/soc/intel/avs/lnl.c new file mode 100644 index 000000000000..4fbc62bfd6c5 --- /dev/null +++ b/sound/soc/intel/avs/lnl.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "debug.h" +#include "registers.h" + +int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) +{ + struct hdac_bus *bus = &adev->base.core; + struct hdac_ext_link *hlink; + int ret; + + ret = avs_mtl_core_stall(adev, core_mask, stall); + + /* On unstall, route interrupts from the links to the DSP firmware. */ + if (!ret && !stall) + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_OFLEN, + AZX_ML_LCTL_OFLEN); + return ret; +} diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 0b29941feb0e..353e343b1d28 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -9,6 +9,7 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/string.h> #include <sound/hdaudio.h> #include <sound/hdaudio_ext.h> #include "avs.h" @@ -310,7 +311,7 @@ avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge) } /* await ROM init */ - ret = snd_hdac_adsp_readl_poll(adev, spec->sram->rom_status_offset, reg, + ret = snd_hdac_adsp_readl_poll(adev, spec->hipc->sts_offset, reg, (reg & 0xF) == AVS_ROM_INIT_DONE || (reg & 0xF) == APL_ROM_FW_ENTERED, AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US); @@ -683,6 +684,7 @@ int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) static int avs_dsp_alloc_resources(struct avs_dev *adev) { + struct hdac_ext_link *link; int ret, i; ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg); @@ -693,6 +695,14 @@ static int avs_dsp_alloc_resources(struct avs_dev *adev) if (ret) return AVS_IPC_RET(ret); + /* If hw allows, read capabilities directly from it. */ + if (avs_platattr_test(adev, ALTHDA)) { + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, + AZX_REG_ML_LEPTR_ID_INTEL_SSP); + if (link) + adev->hw_cfg.i2s_caps.ctrl_count = link->slcount; + } + adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores, sizeof(*adev->core_refs), GFP_KERNEL); adev->lib_names = devm_kcalloc(adev->dev, adev->fw_cfg.max_libs_count, diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 2f243802ccc2..55c04b0142ae 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -102,6 +102,8 @@ struct avs_tlv { } __packed; static_assert(sizeof(struct avs_tlv) == 8); +#define avs_tlv_size(tlv) struct_size(tlv, value, (tlv)->length / 4) + enum avs_module_msg_type { AVS_MOD_INIT_INSTANCE = 0, AVS_MOD_LARGE_CONFIG_GET = 3, @@ -697,8 +699,9 @@ enum avs_sample_type { AVS_SAMPLE_TYPE_FLOAT = 4, }; -#define AVS_CHANNELS_MAX 8 +#define AVS_COEFF_CHANNELS_MAX 8 #define AVS_ALL_CHANNELS_MASK UINT_MAX +#define AVS_CHANNELS_MAX 16 struct avs_audio_format { u32 sampling_freq; @@ -786,6 +789,33 @@ union avs_gtw_attributes { } __packed; static_assert(sizeof(union avs_gtw_attributes) == 4); +#define AVS_GTW_DMA_CONFIG_ID 0x1000 +#define AVS_DMA_METHOD_HDA 1 + +struct avs_dma_device_stream_channel_map { + u32 device_address; + u32 channel_map; +} __packed; +static_assert(sizeof(struct avs_dma_device_stream_channel_map) == 8); + +struct avs_dma_stream_channel_map { + u32 device_count; + struct avs_dma_device_stream_channel_map map[16]; +} __packed; +static_assert(sizeof(struct avs_dma_stream_channel_map) == 132); + +struct avs_dma_cfg { + u8 dma_method; + u8 pre_allocated; + u16 rsvd; + u32 dma_channel_id; + u32 stream_id; + struct avs_dma_stream_channel_map map; + u32 config_size; + u8 config[] __counted_by(config_size); +} __packed; +static_assert(sizeof(struct avs_dma_cfg) == 148); + struct avs_copier_gtw_cfg { union avs_connector_node_id node_id; u32 dma_buffer_size; @@ -846,7 +876,7 @@ struct avs_updown_mixer_cfg { struct avs_modcfg_base base; u32 out_channel_config; u32 coefficients_select; - s32 coefficients[AVS_CHANNELS_MAX]; + s32 coefficients[AVS_COEFF_CHANNELS_MAX]; u32 channel_map; } __packed; static_assert(sizeof(struct avs_updown_mixer_cfg) == 84); diff --git a/sound/soc/intel/avs/mtl.c b/sound/soc/intel/avs/mtl.c new file mode 100644 index 000000000000..d8bdd03275d7 --- /dev/null +++ b/sound/soc/intel/avs/mtl.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "debug.h" +#include "registers.h" +#include "trace.h" + +#define MTL_HfDSSGBL_BASE 0x1000 +#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) +#define MTL_HfDSSCS_SPA BIT(16) +#define MTL_HfDSSCS_CPA BIT(24) + +#define MTL_DSPCS_BASE 0x178D00 +#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) +#define MTL_DSPCCTL_SPA BIT(0) +#define MTL_DSPCCTL_CPA BIT(8) +#define MTL_DSPCCTL_OSEL GENMASK(25, 24) +#define MTL_DSPCCTL_OSEL_HOST BIT(25) + +#define MTL_HfINT_BASE 0x1100 +#define MTL_REG_HfINTIPPTR (MTL_HfINT_BASE + 0x8) +#define MTL_REG_HfHIPCIE (MTL_HfINT_BASE + 0x40) +#define MTL_HfINTIPPTR_PTR GENMASK(20, 0) +#define MTL_HfHIPCIE_IE BIT(0) + +#define MTL_DWICTL_INTENL_IE BIT(0) +#define MTL_DWICTL_FINALSTATUSL_IPC BIT(0) /* same as ADSPIS_IPC */ + +static int avs_mtl_core_power_on(struct avs_dev *adev) +{ + u32 reg; + int ret; + + /* Power up DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) { + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); + return ret; + } + + /* Prevent power gating of DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, + MTL_HfPWRCTL_WPDSPHPxPG); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS, reg, + (reg & MTL_HfPWRSTS_DSPHPxPGS) == MTL_HfPWRSTS_DSPHPxPGS, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + + /* Set ownership to HOST. */ + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); + return ret; +} + +static int avs_mtl_core_power_off(struct avs_dev *adev) +{ + u32 reg; + + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); + + /* Power down DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); + + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == 0, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); +} + +int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power) +{ + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + if (power) + return avs_mtl_core_power_on(adev); + return avs_mtl_core_power_off(adev); +} + +int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power) +{ + /* No logical equivalent on ACE 1.x. */ + return 0; +} + +int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) +{ + u32 value, reg; + int ret; + + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + value = snd_hdac_adsp_readl(adev, MTL_REG_DSPCCTL); + trace_avs_dsp_core_op(value, core_mask, "stall", stall); + if (value == UINT_MAX) + return 0; + + value = stall ? 0 : MTL_DSPCCTL_SPA; + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_SPA, value); + + value = stall ? 0 : MTL_DSPCCTL_CPA; + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_DSPCCTL, + reg, (reg & MTL_DSPCCTL_CPA) == value, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) + dev_err(adev->dev, "core_mask %d %sstall failed: %d\n", + core_mask, stall ? "" : "un", ret); + return ret; +} + +static void avs_mtl_ipc_interrupt(struct avs_dev *adev) +{ + const struct avs_spec *spec = adev->spec; + u32 hipc_ack, hipc_rsp; + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); + + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); + + /* DSP acked host's request. */ + if (hipc_ack & spec->hipc->ack_done_mask) { + complete(&adev->ipc->done_completion); + + /* Tell DSP it has our attention. */ + snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask, + spec->hipc->ack_done_mask); + } + + /* DSP sent new response to process. */ + if (hipc_rsp & spec->hipc->rsp_busy_mask) { + union avs_reply_msg msg; + + msg.primary = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDR); + msg.ext.val = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDD); + + avs_dsp_process_response(adev, msg.val); + + /* Tell DSP we accepted its message. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDR, + MTL_HfIPCxTDR_BUSY, MTL_HfIPCxTDR_BUSY); + /* Ack this response. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDA, MTL_HfIPCxTDA_BUSY, 0); + } + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY); +} + +irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev) +{ + u32 adspis = snd_hdac_adsp_readl(adev, MTL_DWICTL_REG_FINALSTATUSL); + irqreturn_t ret = IRQ_NONE; + + if (adspis == UINT_MAX) + return ret; + + if (adspis & MTL_DWICTL_FINALSTATUSL_IPC) { + avs_mtl_ipc_interrupt(adev); + ret = IRQ_HANDLED; + } + + return ret; +} + +void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable) +{ + if (enable) { + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, + MTL_DWICTL_INTENL_IE); + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, MTL_HfHIPCIE_IE); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, + AVS_ADSP_HIPCCTL_DONE); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_BUSY); + } else { + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 0); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 0); + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, 0); + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 0); + } +} diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index cafb8c6198be..c8b586aced20 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -115,6 +115,55 @@ avs_path_find_variant(struct avs_dev *adev, return NULL; } +static struct avs_tplg_path *avs_condpath_find_variant(struct avs_dev *adev, + struct avs_tplg_path_template *template, + struct avs_path *source, + struct avs_path *sink) +{ + struct avs_tplg_path *variant; + + list_for_each_entry(variant, &template->path_list, node) { + if (variant->source_path_id == source->template->id && + variant->sink_path_id == sink->template->id) + return variant; + } + + return NULL; +} + +static bool avs_tplg_path_template_id_equal(struct avs_tplg_path_template_id *id, + struct avs_tplg_path_template_id *id2) +{ + return id->id == id2->id && !strcmp(id->tplg_name, id2->tplg_name); +} + +static struct avs_path *avs_condpath_find_match(struct avs_dev *adev, + struct avs_tplg_path_template *template, + struct avs_path *path, int dir) +{ + struct avs_tplg_path_template_id *id, *id2; + + if (dir) { + id = &template->source; + id2 = &template->sink; + } else { + id = &template->sink; + id2 = &template->source; + } + + /* Check whether this path is either source or sink of condpath template. */ + if (id->id != path->template->owner->id || + strcmp(id->tplg_name, path->template->owner->owner->name)) + return NULL; + + /* Unidirectional condpaths are allowed. */ + if (avs_tplg_path_template_id_equal(id, id2)) + return path; + + /* Now find the counterpart. */ + return avs_path_find_path(adev, id2->tplg_name, id2->id); +} + static struct acpi_nhlt_config * avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t); @@ -131,9 +180,11 @@ int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template list_for_each_entry(path_template, &template->path_list, node) i++; - rlist = kcalloc(i, sizeof(rlist), GFP_KERNEL); - clist = kcalloc(i, sizeof(clist), GFP_KERNEL); - slist = kcalloc(i, sizeof(slist), GFP_KERNEL); + rlist = kcalloc(i, sizeof(*rlist), GFP_KERNEL); + clist = kcalloc(i, sizeof(*clist), GFP_KERNEL); + slist = kcalloc(i, sizeof(*slist), GFP_KERNEL); + if (!rlist || !clist || !slist) + return -ENOMEM; i = 0; list_for_each_entry(path_template, &template->path_list, node) { @@ -159,9 +210,11 @@ int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template continue; } - blob = avs_nhlt_config_or_default(adev, module_template); - if (IS_ERR(blob)) - continue; + if (!module_template->nhlt_config) { + blob = avs_nhlt_config_or_default(adev, module_template); + if (IS_ERR(blob)) + continue; + } rlist[i] = path_template->fe_fmt->sampling_freq; clist[i] = path_template->fe_fmt->num_channels; @@ -282,13 +335,59 @@ avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t) return &fmtcfg->config; } +static int avs_append_dma_cfg(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) +{ + u32 dma_type = t->cfg_ext->copier.dma_type; + struct avs_dma_cfg *dma; + struct avs_tlv *tlv; + size_t tlv_size; + + if (!avs_platattr_test(adev, ALTHDA)) + return 0; + + switch (dma_type) { + case AVS_DMA_HDA_HOST_OUTPUT: + case AVS_DMA_HDA_HOST_INPUT: + case AVS_DMA_HDA_LINK_OUTPUT: + case AVS_DMA_HDA_LINK_INPUT: + return 0; + default: + break; + } + + tlv_size = sizeof(*tlv) + sizeof(*dma); + if (*cfg_size + tlv_size > AVS_MAILBOX_SIZE) + return -E2BIG; + + /* DMA config is a TLV tailing the existing payload. */ + tlv = (struct avs_tlv *)>w->config.blob[gtw->config_length]; + tlv->type = AVS_GTW_DMA_CONFIG_ID; + tlv->length = sizeof(*dma); + + dma = (struct avs_dma_cfg *)tlv->value; + memset(dma, 0, sizeof(*dma)); + dma->dma_method = AVS_DMA_METHOD_HDA; + dma->pre_allocated = true; + dma->dma_channel_id = dma_id; + dma->stream_id = dma_id + 1; + + gtw->config_length += tlv_size / sizeof(u32); + *cfg_size += tlv_size; + + return 0; +} + static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, - struct avs_tplg_module *t, size_t *cfg_size) + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) { struct acpi_nhlt_config *blob; size_t gtw_size; - blob = avs_nhlt_config_or_default(adev, t); + if (t->nhlt_config) + blob = t->nhlt_config->blob; + else + blob = avs_nhlt_config_or_default(adev, t); if (IS_ERR(blob)) return PTR_ERR(blob); @@ -300,7 +399,7 @@ static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg * memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size); *cfg_size += gtw_size; - return 0; + return avs_append_dma_cfg(adev, gtw, t, dma_id, cfg_size); } static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) @@ -317,7 +416,7 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) dma_id = mod->owner->owner->dma_id; cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config); - ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); if (ret) return ret; @@ -351,7 +450,7 @@ static int avs_whm_create(struct avs_dev *adev, struct avs_path_module *mod) dma_id = mod->owner->owner->dma_id; cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config); - ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); if (ret) return ret; @@ -524,7 +623,7 @@ static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *m cfg.base.audio_fmt = *t->in_fmt; cfg.out_channel_config = t->cfg_ext->updown_mix.out_channel_config; cfg.coefficients_select = t->cfg_ext->updown_mix.coefficients_select; - for (i = 0; i < AVS_CHANNELS_MAX; i++) + for (i = 0; i < AVS_COEFF_CHANNELS_MAX; i++) cfg.coefficients[i] = t->cfg_ext->updown_mix.coefficients[i]; cfg.channel_map = t->cfg_ext->updown_mix.channel_map; @@ -1006,6 +1105,10 @@ static int avs_path_init(struct avs_dev *adev, struct avs_path *path, path->dma_id = dma_id; INIT_LIST_HEAD(&path->ppl_list); INIT_LIST_HEAD(&path->node); + INIT_LIST_HEAD(&path->source_list); + INIT_LIST_HEAD(&path->sink_list); + INIT_LIST_HEAD(&path->source_node); + INIT_LIST_HEAD(&path->sink_node); /* create all the pipelines */ list_for_each_entry(tppl, &template->ppl_list, node) { @@ -1089,12 +1192,129 @@ err: return ERR_PTR(ret); } +static void avs_condpath_free(struct avs_dev *adev, struct avs_path *path) +{ + int ret; + + list_del(&path->source_node); + list_del(&path->sink_node); + + ret = avs_path_reset(path); + if (ret < 0) + dev_err(adev->dev, "reset condpath failed: %d\n", ret); + + ret = avs_path_unbind(path); + if (ret < 0) + dev_err(adev->dev, "unbind condpath failed: %d\n", ret); + + avs_path_free_unlocked(path); +} + +static struct avs_path *avs_condpath_create(struct avs_dev *adev, + struct avs_tplg_path *template, + struct avs_path *source, + struct avs_path *sink) +{ + struct avs_path *path; + int ret; + + path = avs_path_create_unlocked(adev, 0, template); + if (IS_ERR(path)) + return path; + + ret = avs_path_bind(path); + if (ret) + goto err_bind; + + ret = avs_path_reset(path); + if (ret) + goto err_reset; + + path->source = source; + path->sink = sink; + list_add_tail(&path->source_node, &source->source_list); + list_add_tail(&path->sink_node, &sink->sink_list); + + return path; + +err_reset: + avs_path_unbind(path); +err_bind: + avs_path_free_unlocked(path); + return ERR_PTR(ret); +} + +static int avs_condpaths_walk(struct avs_dev *adev, struct avs_path *path, int dir) +{ + struct avs_soc_component *acomp; + struct avs_path *source, *sink; + struct avs_path **other; + + if (dir) { + source = path; + other = &sink; + } else { + sink = path; + other = &source; + } + + list_for_each_entry(acomp, &adev->comp_list, node) { + for (int i = 0; i < acomp->tplg->num_condpath_tmpls; i++) { + struct avs_tplg_path_template *template; + struct avs_tplg_path *variant; + struct avs_path *cpath; + + template = &acomp->tplg->condpath_tmpls[i]; + + /* Do not create unidirectional condpaths twice. */ + if (avs_tplg_path_template_id_equal(&template->source, + &template->sink) && dir) + continue; + + *other = avs_condpath_find_match(adev, template, path, dir); + if (!*other) + continue; + + variant = avs_condpath_find_variant(adev, template, source, sink); + if (!variant) + continue; + + cpath = avs_condpath_create(adev, variant, source, sink); + if (IS_ERR(cpath)) + return PTR_ERR(cpath); + } + } + + return 0; +} + +/* Caller responsible for holding adev->path_mutex. */ +static int avs_condpaths_walk_all(struct avs_dev *adev, struct avs_path *path) +{ + int ret; + + ret = avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + return ret; + + return avs_condpaths_walk(adev, path, SNDRV_PCM_STREAM_PLAYBACK); +} + void avs_path_free(struct avs_path *path) { + struct avs_path *cpath, *csave; struct avs_dev *adev = path->owner; mutex_lock(&adev->path_mutex); + + /* Free all condpaths this path spawned. */ + list_for_each_entry_safe(cpath, csave, &path->source_list, source_node) + avs_condpath_free(path->owner, cpath); + list_for_each_entry_safe(cpath, csave, &path->sink_list, sink_node) + avs_condpath_free(path->owner, cpath); + avs_path_free_unlocked(path); + mutex_unlock(&adev->path_mutex); } @@ -1105,6 +1325,7 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, { struct avs_tplg_path *variant; struct avs_path *path; + int ret; variant = avs_path_find_variant(adev, template, fe_params, be_params); if (!variant) { @@ -1118,7 +1339,16 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, mutex_lock(&adev->comp_list_mutex); path = avs_path_create_unlocked(adev, dma_id, variant); + if (IS_ERR(path)) + goto exit; + + ret = avs_condpaths_walk_all(adev, path); + if (ret) { + avs_path_free_unlocked(path); + path = ERR_PTR(ret); + } +exit: mutex_unlock(&adev->comp_list_mutex); mutex_unlock(&adev->path_mutex); @@ -1241,6 +1471,42 @@ int avs_path_reset(struct avs_path *path) return 0; } +static int avs_condpath_pause(struct avs_dev *adev, struct avs_path *cpath) +{ + struct avs_path_pipeline *ppl; + int ret; + + if (cpath->state == AVS_PPL_STATE_PAUSED) + return 0; + + list_for_each_entry_reverse(ppl, &cpath->ppl_list, node) { + ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED); + if (ret) { + dev_err(adev->dev, "pause cpath failed: %d\n", ret); + cpath->state = AVS_PPL_STATE_INVALID; + return AVS_IPC_RET(ret); + } + } + + cpath->state = AVS_PPL_STATE_PAUSED; + return 0; +} + +static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path) +{ + struct avs_path *cpath; + + mutex_lock(&adev->path_mutex); + + /* If either source or sink stops, so do the attached conditional paths. */ + list_for_each_entry(cpath, &path->source_list, source_node) + avs_condpath_pause(adev, cpath); + list_for_each_entry(cpath, &path->sink_list, sink_node) + avs_condpath_pause(adev, cpath); + + mutex_unlock(&adev->path_mutex); +} + int avs_path_pause(struct avs_path *path) { struct avs_path_pipeline *ppl; @@ -1250,6 +1516,8 @@ int avs_path_pause(struct avs_path *path) if (path->state == AVS_PPL_STATE_PAUSED) return 0; + avs_condpaths_pause(adev, path); + list_for_each_entry_reverse(ppl, &path->ppl_list, node) { ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_PAUSED); @@ -1264,6 +1532,50 @@ int avs_path_pause(struct avs_path *path) return 0; } +static int avs_condpath_run(struct avs_dev *adev, struct avs_path *cpath, int trigger) +{ + struct avs_path_pipeline *ppl; + int ret; + + if (cpath->state == AVS_PPL_STATE_RUNNING) + return 0; + + list_for_each_entry(ppl, &cpath->ppl_list, node) { + if (ppl->template->cfg->trigger != trigger) + continue; + + ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id, AVS_PPL_STATE_RUNNING); + if (ret) { + dev_err(adev->dev, "run cpath failed: %d\n", ret); + cpath->state = AVS_PPL_STATE_INVALID; + return AVS_IPC_RET(ret); + } + } + + cpath->state = AVS_PPL_STATE_RUNNING; + return 0; +} + +static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int trigger) +{ + struct avs_path *cpath; + + mutex_lock(&adev->path_mutex); + + /* Run conditional paths only if source and sink are both running. */ + list_for_each_entry(cpath, &path->source_list, source_node) + if (cpath->source->state == AVS_PPL_STATE_RUNNING && + cpath->sink->state == AVS_PPL_STATE_RUNNING) + avs_condpath_run(adev, cpath, trigger); + + list_for_each_entry(cpath, &path->sink_list, sink_node) + if (cpath->source->state == AVS_PPL_STATE_RUNNING && + cpath->sink->state == AVS_PPL_STATE_RUNNING) + avs_condpath_run(adev, cpath, trigger); + + mutex_unlock(&adev->path_mutex); +} + int avs_path_run(struct avs_path *path, int trigger) { struct avs_path_pipeline *ppl; @@ -1287,5 +1599,10 @@ int avs_path_run(struct avs_path *path, int trigger) } path->state = AVS_PPL_STATE_RUNNING; + + /* Granular pipeline triggering not intended for conditional paths. */ + if (trigger == AVS_TPLG_TRIGGER_AUTO) + avs_condpaths_run(adev, path, trigger); + return 0; } diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index c65ed84aa853..ceb89971a902 100644 --- a/sound/soc/intel/avs/path.h +++ b/sound/soc/intel/avs/path.h @@ -13,11 +13,24 @@ #include "avs.h" #include "topology.h" +#define AVS_COND_TYPE_NONE 0 +#define AVS_COND_TYPE_AECREF 1 + struct avs_path { u32 dma_id; struct list_head ppl_list; u32 state; + /* condpath navigation for standard paths */ + struct list_head source_list; + struct list_head sink_list; + + /* conditional path fields */ + struct avs_path *source; + struct avs_path *sink; + struct list_head source_node; + struct list_head sink_node; + struct avs_tplg_path *template; struct avs_dev *owner; /* device path management */ diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index d83ef504643b..4a6deb599c88 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -18,6 +18,7 @@ #include "path.h" #include "pcm.h" #include "topology.h" +#include "utils.h" #include "../../codecs/hda.h" struct avs_dma_data { @@ -36,6 +37,7 @@ struct avs_dma_data { struct snd_pcm_hw_constraint_list sample_bits_list; struct work_struct period_elapsed_work; + struct hdac_ext_link *link; struct snd_pcm_substream *substream; }; @@ -81,10 +83,8 @@ void avs_period_elapsed(struct snd_pcm_substream *substream) static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule); static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_constraint_list *r, *c, *s; - struct avs_tplg_path_template *template; struct avs_dma_data *data; int ret; @@ -97,8 +97,7 @@ static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct s c = &(data->channels_list); s = &(data->sample_bits_list); - template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream); - ret = avs_path_set_constraint(data->adev, template, r, c, s); + ret = avs_path_set_constraint(data->adev, data->template, r, c, s); if (ret <= 0) return ret; @@ -325,32 +324,75 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { .trigger = avs_dai_nonhda_be_trigger, }; -static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +static int __avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, + struct hdac_ext_link *link) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; struct avs_dma_data *data; - struct hda_codec *codec; int ret; ret = avs_dai_startup(substream, dai); if (ret) return ret; - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, + data = snd_soc_dai_get_dma_data(dai, substream); + link_stream = snd_hdac_ext_stream_assign(&data->adev->base.core, substream, HDAC_EXT_STREAM_TYPE_LINK); if (!link_stream) { avs_dai_shutdown(substream, dai); return -EBUSY; } - data = snd_soc_dai_get_dma_data(dai, substream); data->link_stream = link_stream; - substream->runtime->private_data = link_stream; + data->link = link; return 0; } +static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct hdac_ext_link *link; + struct avs_dma_data *data; + struct hda_codec *codec; + int ret; + + codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); + + link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); + if (!link) + return -EINVAL; + + ret = __avs_dai_hda_be_startup(substream, dai, link); + if (!ret) { + data = snd_soc_dai_get_dma_data(dai, substream); + substream->runtime->private_data = data->link_stream; + } + + return ret; +} + +static int avs_dai_i2shda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_SSP); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); +} + +static int avs_dai_dmichda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_DMIC); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); +} + static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); @@ -360,6 +402,14 @@ static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct avs_dai_shutdown(substream, dai); } +static void avs_dai_althda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); + + snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); + avs_dai_shutdown(substream, dai); +} + static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { @@ -375,13 +425,8 @@ static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct avs_dma_data *data; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; - struct hda_codec *codec; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + struct avs_dma_data *data; data = snd_soc_dai_get_dma_data(dai, substream); if (!data->path) @@ -393,54 +438,43 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn data->path = NULL; /* clear link <-> stream mapping */ - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_clear_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); return 0; } static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; + const struct snd_pcm_hw_params *p; struct avs_dma_data *data; - struct hda_codec *codec; - struct hdac_bus *bus; unsigned int format_val; unsigned int bits; int ret; data = snd_soc_dai_get_dma_data(dai, substream); link_stream = data->link_stream; + p = &be->dpcm[substream->stream].hw_params; if (link_stream->link_prepared) return 0; - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - bus = &codec->bus->core; stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); - bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, + bits = snd_hdac_stream_format_bits(params_format(p), params_subformat(p), stream_info->sig_bits); - format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); + format_val = snd_hdac_stream_format(params_channels(p), bits, params_rate(p)); - snd_hdac_ext_stream_decouple(bus, link_stream, true); + snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true); snd_hdac_ext_stream_reset(link_stream); snd_hdac_ext_stream_setup(link_stream, format_val); - link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_set_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); ret = avs_dai_prepare(substream, dai); if (ret) @@ -515,6 +549,24 @@ static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { .trigger = avs_dai_hda_be_trigger, }; +static const struct snd_soc_dai_ops avs_dai_i2shda_be_ops = { + .startup = avs_dai_i2shda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, +}; + +static const struct snd_soc_dai_ops avs_dai_dmichda_be_ops = { + .startup = avs_dai_dmichda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, +}; + static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *interval = hw_param_interval(params, rule->var); @@ -599,6 +651,7 @@ static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_ data = snd_soc_dai_get_dma_data(dai, substream); + disable_work_sync(&data->period_elapsed_work); snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST); avs_dai_shutdown(substream, dai); } @@ -702,6 +755,8 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so data = snd_soc_dai_get_dma_data(dai, substream); host_stream = data->host_stream; + if (runtime->state == SNDRV_PCM_STATE_XRUN) + hdac_stream(host_stream)->prepared = false; if (hdac_stream(host_stream)->prepared) return 0; @@ -927,7 +982,6 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp) if (!ret) ret = avs_module_info_init(adev, false); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); return ret; @@ -1314,7 +1368,7 @@ static int avs_component_construct(struct snd_soc_component *component, return 0; } -static const struct snd_soc_component_driver avs_component_driver = { +static struct snd_soc_component_driver avs_component_driver = { .name = "avs-pcm", .probe = avs_component_probe, .remove = avs_component_remove, @@ -1328,9 +1382,9 @@ static const struct snd_soc_component_driver avs_component_driver = { .topology_name_prefix = "intel/avs", }; -int avs_soc_component_register(struct device *dev, const char *name, - const struct snd_soc_component_driver *drv, - struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) +int avs_register_component(struct device *dev, const char *name, + struct snd_soc_component_driver *drv, + struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) { struct avs_soc_component *acomp; int ret; @@ -1339,21 +1393,24 @@ int avs_soc_component_register(struct device *dev, const char *name, if (!acomp) return -ENOMEM; + acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL); + if (!acomp->base.name) + return -ENOMEM; + + INIT_LIST_HEAD(&acomp->node); + + drv->use_dai_pcm_id = !obsolete_card_names; + ret = snd_soc_component_initialize(&acomp->base, drv, dev); if (ret < 0) return ret; - /* force name change after ASoC is done with its init */ - acomp->base.name = name; - INIT_LIST_HEAD(&acomp->node); - return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); } static struct snd_soc_dai_driver dmic_cpu_dais[] = { { .name = "DMIC Pin", - .ops = &avs_dai_nonhda_be_ops, .capture = { .stream_name = "DMIC Rx", .channels_min = 1, @@ -1364,7 +1421,6 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { }, { .name = "DMIC WoV Pin", - .ops = &avs_dai_nonhda_be_ops, .capture = { .stream_name = "DMIC WoV Rx", .channels_min = 1, @@ -1375,17 +1431,25 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { }, }; -int avs_dmic_platform_register(struct avs_dev *adev, const char *name) +int avs_register_dmic_component(struct avs_dev *adev, const char *name) { - return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, - ARRAY_SIZE(dmic_cpu_dais)); + const struct snd_soc_dai_ops *ops; + + if (avs_platattr_test(adev, ALTHDA)) + ops = &avs_dai_dmichda_be_ops; + else + ops = &avs_dai_nonhda_be_ops; + + dmic_cpu_dais[0].ops = ops; + dmic_cpu_dais[1].ops = ops; + return avs_register_component(adev->dev, name, &avs_component_driver, dmic_cpu_dais, + ARRAY_SIZE(dmic_cpu_dais)); } static const struct snd_soc_dai_driver i2s_dai_template = { - .ops = &avs_dai_nonhda_be_ops, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_24000 | @@ -1398,7 +1462,7 @@ static const struct snd_soc_dai_driver i2s_dai_template = { }, .capture = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_24000 | @@ -1411,14 +1475,19 @@ static const struct snd_soc_dai_driver i2s_dai_template = { }, }; -int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, - unsigned long *tdms) +int avs_register_i2s_component(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms) { struct snd_soc_dai_driver *cpus, *dai; + const struct snd_soc_dai_ops *ops; size_t ssp_count, cpu_count; int i, j; ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; + if (avs_platattr_test(adev, ALTHDA)) + ops = &avs_dai_i2shda_be_ops; + else + ops = &avs_dai_nonhda_be_ops; cpu_count = 0; for_each_set_bit(i, &port_mask, ssp_count) @@ -1446,6 +1515,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) return -ENOMEM; + dai->ops = ops; dai++; } } @@ -1454,7 +1524,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l goto plat_register; for_each_set_bit(i, &port_mask, ssp_count) { - for_each_set_bit(j, &tdms[i], ssp_count) { + for_each_set_bit(j, &tdms[i], AVS_CHANNELS_MAX) { memcpy(dai, &i2s_dai_template, sizeof(*dai)); dai->name = @@ -1466,12 +1536,13 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) return -ENOMEM; + dai->ops = ops; dai++; } } plat_register: - return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count); + return avs_register_component(adev->dev, name, &avs_component_driver, cpus, cpu_count); } /* HD-Audio CPU DAI template */ @@ -1479,7 +1550,7 @@ static const struct snd_soc_dai_driver hda_cpu_dai = { .ops = &avs_dai_hda_be_ops, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, @@ -1489,7 +1560,7 @@ static const struct snd_soc_dai_driver hda_cpu_dai = { }, .capture = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, @@ -1503,11 +1574,13 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen { struct snd_soc_acpi_mach *mach; struct snd_soc_dai *dai, *save; + struct avs_mach_pdata *pdata; struct hda_codec *codec; char name[32]; mach = dev_get_platdata(component->card->dev); - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; snprintf(name, sizeof(name), "%s-cpu", dev_name(&codec->core.dev)); for_each_component_dais_safe(component, dai, save) { @@ -1528,6 +1601,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component) struct snd_soc_dapm_context *dapm; struct snd_soc_dai_driver *dais; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct hda_codec *codec; struct hda_pcm *pcm; const char *cname; @@ -1537,7 +1611,8 @@ static int avs_component_hda_probe(struct snd_soc_component *component) if (!mach) return -EINVAL; - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; if (list_empty(&codec->pcm_list_head)) return -EINVAL; list_for_each_entry(pcm, &codec->pcm_list_head, list) @@ -1549,7 +1624,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component) return -ENOMEM; cname = dev_name(&codec->core.dev); - dapm = snd_soc_component_get_dapm(component); + dapm = snd_soc_component_to_dapm(component); pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { @@ -1671,7 +1746,7 @@ static int avs_component_hda_open(struct snd_soc_component *component, return 0; } -static const struct snd_soc_component_driver avs_hda_component_driver = { +static struct snd_soc_component_driver avs_hda_component_driver = { .name = "avs-hda-pcm", .probe = avs_component_hda_probe, .remove = avs_component_hda_remove, @@ -1692,8 +1767,7 @@ static const struct snd_soc_component_driver avs_hda_component_driver = { .topology_name_prefix = "intel/avs", }; -int avs_hda_platform_register(struct avs_dev *adev, const char *name) +int avs_register_hda_component(struct avs_dev *adev, const char *name) { - return avs_soc_component_register(adev->dev, name, - &avs_hda_component_driver, NULL, 0); + return avs_register_component(adev->dev, name, &avs_hda_component_driver, NULL, 0); } diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index f0b010956303..74096236984a 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -11,10 +11,11 @@ #include <sound/hdaudio.h> #include <sound/soc.h> #include "avs.h" +#include "debug.h" #include "messages.h" -static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, - size_t buffer_size) +static int avs_dsp_init_probe(struct avs_dev *adev, struct snd_compr_params *params, int bps, + union avs_connector_node_id node_id, size_t buffer_size) { struct avs_probe_cfg cfg = {{0}}; struct avs_module_entry mentry; @@ -26,12 +27,16 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id return ret; /* - * Probe module uses no cycles, audio data format and input and output - * frame sizes are unused. It is also not owned by any pipeline. + * Probe module uses no cycles, input and output frame sizes are unused. + * It is also not owned by any pipeline. */ cfg.base.ibs = 1; /* BSS module descriptor is always segment of index=2. */ cfg.base.is_pages = mentry.segments[2].flags.length; + cfg.base.audio_fmt.sampling_freq = params->codec.sample_rate; + cfg.base.audio_fmt.bit_depth = bps; + cfg.base.audio_fmt.num_channels = params->codec.ch_out; + cfg.base.audio_fmt.valid_bit_depth = bps; cfg.gtw_cfg.node_id = node_id; cfg.gtw_cfg.dma_buffer_size = buffer_size; @@ -127,8 +132,6 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); struct snd_compr_runtime *rtd = cstream->runtime; struct avs_dev *adev = to_avs_dev(dai->dev); - /* compr params do not store bit depth, default to S32_LE. */ - snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE; unsigned int format_val; int bps, ret; @@ -141,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); if (ret < 0) return ret; - bps = snd_pcm_format_physical_width(format); + bps = snd_pcm_format_physical_width(params->codec.format); if (bps < 0) return bps; format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate); @@ -165,7 +168,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, node_id.vindex = hdac_stream(host_stream)->stream_tag - 1; node_id.dma_type = AVS_DMA_HDA_HOST_INPUT; - ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes); + ret = avs_dsp_init_probe(adev, params, bps, node_id, rtd->dma_bytes); if (ret < 0) { dev_err(dai->dev, "probe init failed: %d\n", ret); avs_dsp_enable_d0ix(adev); @@ -213,7 +216,7 @@ static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, } static int avs_probe_compr_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) + struct snd_compr_tstamp64 *tstamp, struct snd_soc_dai *dai) { struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); struct snd_soc_pcm_stream *pstream; @@ -290,8 +293,22 @@ static const struct snd_soc_component_driver avs_probe_component_driver = { .module_get_upon_open = 1, /* increment refcount when a stream is opened */ }; -int avs_probe_platform_register(struct avs_dev *adev, const char *name) +int avs_register_probe_component(struct avs_dev *adev, const char *name) { - return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver, - probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); + struct snd_soc_component *component; + int ret; + + component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL); + if (!component->name) + return -ENOMEM; + + ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev); + if (ret) + return ret; + + return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); } diff --git a/sound/soc/intel/avs/ptl.c b/sound/soc/intel/avs/ptl.c new file mode 100644 index 000000000000..07da9b0aa2b8 --- /dev/null +++ b/sound/soc/intel/avs/ptl.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2024-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "debug.h" +#include "registers.h" +#include "trace.h" + +#define MTL_HfDSSGBL_BASE 0x1000 +#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) +#define MTL_HfDSSCS_SPA BIT(16) +#define MTL_HfDSSCS_CPA BIT(24) + +#define MTL_DSPCS_BASE 0x178D00 +#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) +#define MTL_DSPCCTL_OSEL GENMASK(25, 24) +#define MTL_DSPCCTL_OSEL_HOST BIT(25) + +static int avs_ptl_core_power_on(struct avs_dev *adev) +{ + u32 reg; + int ret; + + /* Power up DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) { + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); + return ret; + } + + /* Prevent power gating of DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, + MTL_HfPWRCTL2_WPDSPHPxPG); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS2, reg, + (reg & MTL_HfPWRSTS2_DSPHPxPGS) == MTL_HfPWRSTS2_DSPHPxPGS, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + + /* Set ownership to HOST. */ + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); + return ret; +} + +static int avs_ptl_core_power_off(struct avs_dev *adev) +{ + u32 reg; + + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); + + /* Power down DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); + + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == 0, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); +} + +static int avs_ptl_core_power(struct avs_dev *adev, u32 core_mask, bool power) +{ + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + if (power) + return avs_ptl_core_power_on(adev); + return avs_ptl_core_power_off(adev); +} + +const struct avs_dsp_ops avs_ptl_dsp_ops = { + .power = avs_ptl_core_power, + .reset = avs_mtl_core_reset, + .stall = avs_lnl_core_stall, + .dsp_interrupt = avs_mtl_dsp_interrupt, + .int_control = avs_mtl_interrupt_control, + .load_basefw = avs_hda_load_basefw, + .load_lib = avs_hda_load_library, + .transfer_mods = avs_hda_transfer_modules, + .log_buffer_offset = avs_icl_log_buffer_offset, + .log_buffer_status = avs_apl_log_buffer_status, + .coredump = avs_apl_coredump, + .d0ix_toggle = avs_icl_d0ix_toggle, + .set_d0ix = avs_icl_set_d0ix, + AVS_SET_ENABLE_LOGS_OP(icl) +}; diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h index 368ede05f2cd..97767882ffa1 100644 --- a/sound/soc/intel/avs/registers.h +++ b/sound/soc/intel/avs/registers.h @@ -35,6 +35,8 @@ #define AVS_ADSPCS_CSTALL_MASK(cm) ((cm) << 8) #define AVS_ADSPCS_SPA_MASK(cm) ((cm) << 16) #define AVS_ADSPCS_CPA_MASK(cm) ((cm) << 24) +#define AVS_ADSPCS_INTERVAL_US 500 +#define AVS_ADSPCS_TIMEOUT_US 10000 #define AVS_MAIN_CORE_MASK BIT(0) #define AVS_ADSP_HIPCCTL_BUSY BIT(0) @@ -67,14 +69,50 @@ #define CNL_ADSP_HIPCIDR_BUSY BIT(31) #define CNL_ADSP_HIPCIDA_DONE BIT(31) +/* MTL Intel HOST Inter-Processor Communication Registers */ +#define MTL_HfIPC_BASE 0x73000 +#define MTL_REG_HfIPCxTDR (MTL_HfIPC_BASE + 0x200) +#define MTL_REG_HfIPCxTDA (MTL_HfIPC_BASE + 0x204) +#define MTL_REG_HfIPCxIDR (MTL_HfIPC_BASE + 0x210) +#define MTL_REG_HfIPCxIDA (MTL_HfIPC_BASE + 0x214) +#define MTL_REG_HfIPCxCTL (MTL_HfIPC_BASE + 0x228) +#define MTL_REG_HfIPCxTDD (MTL_HfIPC_BASE + 0x300) +#define MTL_REG_HfIPCxIDD (MTL_HfIPC_BASE + 0x380) + +#define MTL_HfIPCxTDR_BUSY BIT(31) +#define MTL_HfIPCxTDA_BUSY BIT(31) +#define MTL_HfIPCxIDR_BUSY BIT(31) +#define MTL_HfIPCxIDA_DONE BIT(31) + +#define MTL_HfFLV_BASE 0x162000 +#define MTL_REG_HfFLGP(x, y) (MTL_HfFLV_BASE + 0x1200 + (x) * 0x20 + (y) * 0x08) +#define LNL_REG_HfDFR(x) (0x160200 + (x) * 0x8) + +#define MTL_DWICTL_BASE 0x1800 +#define MTL_DWICTL_REG_INTENL (MTL_DWICTL_BASE + 0x0) +#define MTL_DWICTL_REG_FINALSTATUSL (MTL_DWICTL_BASE + 0x30) + +#define MTL_HfPMCCU_BASE 0x1D00 +#define MTL_REG_HfCLKCTL (MTL_HfPMCCU_BASE + 0x10) +#define MTL_REG_HfPWRCTL (MTL_HfPMCCU_BASE + 0x18) +#define MTL_REG_HfPWRSTS (MTL_HfPMCCU_BASE + 0x1C) +#define MTL_REG_HfPWRCTL2 (MTL_HfPMCCU_BASE + 0x20) +#define MTL_REG_HfPWRSTS2 (MTL_HfPMCCU_BASE + 0x24) +#define MTL_HfPWRCTL_WPDSPHPxPG BIT(0) +#define MTL_HfPWRSTS_DSPHPxPGS BIT(0) +#define MTL_HfPWRCTL2_WPDSPHPxPG BIT(0) +#define MTL_HfPWRSTS2_DSPHPxPGS BIT(0) + /* Intel HD Audio SRAM windows base addresses */ #define SKL_ADSP_SRAM_BASE_OFFSET 0x8000 #define SKL_ADSP_SRAM_WINDOW_SIZE 0x2000 #define APL_ADSP_SRAM_BASE_OFFSET 0x80000 #define APL_ADSP_SRAM_WINDOW_SIZE 0x20000 +#define MTL_ADSP_SRAM_BASE_OFFSET 0x180000 +#define MTL_ADSP_SRAM_WINDOW_SIZE 0x8000 /* Constants used when accessing SRAM, space shared with firmware */ -#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram->base_offset) +#define AVS_FW_REG_BASE(adev) ((adev)->spec->hipc->sts_offset) #define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0) #define AVS_FW_REG_ERROR(adev) (AVS_FW_REG_BASE(adev) + 0x4) diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index d66ef000de9e..8fb86f364ff3 100644 --- a/sound/soc/intel/avs/skl.c +++ b/sound/soc/intel/avs/skl.c @@ -11,6 +11,7 @@ #include <sound/hdaudio_ext.h> #include "avs.h" #include "cldma.h" +#include "debug.h" #include "messages.h" #include "registers.h" diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c index 56905f2b9eb2..afb066516101 100644 --- a/sound/soc/intel/avs/tgl.c +++ b/sound/soc/intel/avs/tgl.c @@ -8,6 +8,7 @@ #include <linux/pci.h> #include "avs.h" +#include "debug.h" #include "messages.h" #define CPUID_TSC_LEAF 0x15 @@ -47,7 +48,7 @@ static int avs_tgl_config_basefw(struct avs_dev *adev) #ifdef CONFIG_X86 unsigned int ecx; -#include <asm/cpuid.h> +#include <asm/cpuid/api.h> ecx = cpuid_ecx(CPUID_TSC_LEAF); if (ecx) { ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 3c222c352701..9033f683393c 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base); AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext); AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs); AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings); +AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs); static int parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset) @@ -420,6 +421,22 @@ static int parse_link_formatted_string(struct snd_soc_component *comp, void *ele return 0; } +static int avs_parse_nhlt_config_size(struct snd_soc_component *comp, void *elem, void *object, + u32 offset) +{ + struct snd_soc_tplg_vendor_value_elem *tuple = elem; + struct acpi_nhlt_config **blob = (struct acpi_nhlt_config **)((u8 *)object + offset); + u32 size; + + size = le32_to_cpu(tuple->value); + *blob = devm_kzalloc(comp->card->dev, struct_size(*blob, capabilities, size), GFP_KERNEL); + if (!*blob) + return -ENOMEM; + + (*blob)->capabilities_size = size; + return 0; +} + static int parse_dictionary_header(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, @@ -1184,6 +1201,12 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, num_config_ids), .parse = avs_parse_byte_token, }, + { + .token = AVS_TKN_MOD_NHLT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, nhlt_config), + .parse = avs_parse_nhlt_config_ptr, + }, }; static const struct avs_tplg_token_parser init_config_parsers[] = { @@ -1387,6 +1410,27 @@ static const struct avs_tplg_token_parser path_parsers[] = { }, }; +static const struct avs_tplg_token_parser condpath_parsers[] = { + { + .token = AVS_TKN_CONDPATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_SOURCE_PATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, source_path_id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_SINK_PATH_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path, sink_path_id), + .parse = avs_parse_word_token, + }, +}; + static struct avs_tplg_path * avs_tplg_path_create(struct snd_soc_component *comp, struct avs_tplg_path_template *owner, struct snd_soc_tplg_vendor_array *tuples, u32 block_size, @@ -1454,6 +1498,39 @@ static const struct avs_tplg_token_parser path_tmpl_parsers[] = { }, }; +static const struct avs_tplg_token_parser condpath_tmpl_parsers[] = { + { + .token = AVS_TKN_CONDPATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SOURCE_TPLG_NAME_STRING, + .type = SND_SOC_TPLG_TUPLE_TYPE_STRING, + .offset = offsetof(struct avs_tplg_path_template, source.tplg_name), + .parse = avs_parse_string_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SOURCE_PATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, source.id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SINK_TPLG_NAME_STRING, + .type = SND_SOC_TPLG_TUPLE_TYPE_STRING, + .offset = offsetof(struct avs_tplg_path_template, sink.tplg_name), + .parse = avs_parse_string_token, + }, + { + .token = AVS_TKN_CONDPATH_TMPL_SINK_PATH_TMPL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_path_template, sink.id), + .parse = avs_parse_word_token, + }, +}; + static int parse_path_template(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, u32 block_size, struct avs_tplg_path_template *template, @@ -1524,6 +1601,56 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o return template; } +static int avs_tplg_parse_condpath_templates(struct snd_soc_component *comp, + struct snd_soc_tplg_vendor_array *tuples, + u32 block_size) +{ + struct avs_soc_component *acomp = to_avs_soc_component(comp); + struct avs_tplg *tplg = acomp->tplg; + int ret, i; + + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->condpath_tmpls, + &tplg->num_condpath_tmpls, + sizeof(*tplg->condpath_tmpls), + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_condpath_tmpls; i++) { + struct avs_tplg_path_template *template; + u32 esize; + + template = &tplg->condpath_tmpls[i]; + template->owner = tplg; /* Used when building sysfs hierarchy. */ + INIT_LIST_HEAD(&template->path_list); + INIT_LIST_HEAD(&template->node); + + ret = avs_tplg_vendor_entry_size(tuples, block_size, + AVS_TKN_CONDPATH_TMPL_ID_U32, &esize); + if (ret) + return ret; + + ret = parse_path_template(comp, tuples, esize, template, + condpath_tmpl_parsers, + ARRAY_SIZE(condpath_tmpl_parsers), + condpath_parsers, + ARRAY_SIZE(condpath_parsers)); + if (ret < 0) { + dev_err(comp->dev, "parse condpath_tmpl: %d failed: %d\n", i, ret); + return ret; + } + + block_size -= esize; + tuples = avs_tplg_vendor_array_at(tuples, esize); + } + + return 0; +} + static const struct avs_tplg_token_parser mod_init_config_parsers[] = { { .token = AVS_TKN_INIT_CONFIG_ID_U32, @@ -1547,12 +1674,14 @@ static const struct avs_tplg_token_parser mod_init_config_parsers[] = { static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, struct snd_soc_tplg_vendor_array *tuples, - u32 block_size) + u32 block_size, u32 *offset) { struct avs_soc_component *acomp = to_avs_soc_component(comp); struct avs_tplg *tplg = acomp->tplg; int ret, i; + *offset = 0; + /* Parse tuple section telling how many init configs there are. */ ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs, &tplg->num_init_configs, @@ -1562,6 +1691,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, return ret; block_size -= le32_to_cpu(tuples->size); + *offset += le32_to_cpu(tuples->size); /* With header parsed, move on to parsing entries. */ tuples = avs_tplg_vendor_array_next(tuples); @@ -1577,6 +1707,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, */ tmp = avs_tplg_vendor_array_next(tuples); esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); + *offset += esize; ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), AVS_TKN_INIT_CONFIG_ID_U32, @@ -1588,6 +1719,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, /* handle raw data section */ init_config_data = (void *)tuples + esize; esize = config->length; + *offset += esize; config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL); if (!config->data) @@ -1600,6 +1732,70 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, return 0; } +static const struct avs_tplg_token_parser mod_nhlt_config_parsers[] = { + { + .token = AVS_TKN_NHLT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_nhlt_config, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_NHLT_CONFIG_SIZE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_nhlt_config, blob), + .parse = avs_parse_nhlt_config_size, + }, +}; + +static int avs_tplg_parse_nhlt_configs(struct snd_soc_component *comp, + struct snd_soc_tplg_vendor_array *tuples, + u32 block_size) +{ + struct avs_soc_component *acomp = to_avs_soc_component(comp); + struct avs_tplg *tplg = acomp->tplg; + int ret, i; + + /* Parse the header section to know how many entries there are. */ + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->nhlt_configs, + &tplg->num_nhlt_configs, + sizeof(*tplg->nhlt_configs), + AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With the header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_nhlt_configs && block_size > 0; i++) { + struct avs_tplg_nhlt_config *config; + u32 esize; + + config = &tplg->nhlt_configs[i]; + esize = le32_to_cpu(tuples->size); + + ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), + AVS_TKN_NHLT_CONFIG_ID_U32, + mod_nhlt_config_parsers, + ARRAY_SIZE(mod_nhlt_config_parsers)); + if (ret) + return ret; + /* With tuples parsed, the blob shall be allocated. */ + if (!config->blob) + return -EINVAL; + + /* Consume the raw data and move to the next entry. */ + memcpy(config->blob->capabilities, (u8 *)tuples + esize, + config->blob->capabilities_size); + esize += config->blob->capabilities_size; + + block_size -= esize; + tuples = avs_tplg_vendor_array_at(tuples, esize); + } + + return 0; +} + static int avs_route_load(struct snd_soc_component *comp, int index, struct snd_soc_dapm_route *route) { @@ -1668,8 +1864,8 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, /* See parse_link_formatted_string() for dynamic naming when(s). */ if (avs_mach_singular_tdm(mach, ssp_port)) { - /* size is based on possible %d -> SSP:TDM, where SSP and TDM < 10 + '\0' */ - size_t size = strlen(dw->name) + 2; + /* size is based on possible %d -> SSP:TDM, where SSP and TDM < 16 + '\0' */ + size_t size = strlen(dw->name) + 3; char *buf; tdm_slot = avs_mach_ssp_tdm(mach, ssp_port); @@ -1891,6 +2087,12 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return ret; } + /* Condpaths dictionary. */ + ret = avs_tplg_parse_condpath_templates(comp, tuples, + has_init_config ? offset : remaining); + if (ret < 0) + return ret; + if (!has_init_config) return 0; @@ -1898,11 +2100,26 @@ static int avs_manifest(struct snd_soc_component *comp, int index, tuples = avs_tplg_vendor_array_at(tuples, offset); /* Initial configs dictionary. */ - ret = avs_tplg_parse_initial_configs(comp, tuples, remaining); + ret = avs_tplg_parse_initial_configs(comp, tuples, remaining, &offset); if (ret < 0) return ret; - return 0; + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32, &offset); + if (ret == -ENOENT) + return 0; + if (ret) { + dev_err(comp->dev, "NHLT config lookup failed: %d\n", ret); + return ret; + } + + tuples = avs_tplg_vendor_array_at(tuples, offset); + + /* NHLT configs dictionary. */ + return avs_tplg_parse_nhlt_configs(comp, tuples, remaining); } enum { diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 304880997717..1cf7455b6c01 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -33,9 +33,12 @@ struct avs_tplg { u32 num_pplcfgs; struct avs_tplg_binding *bindings; u32 num_bindings; + struct avs_tplg_path_template *condpath_tmpls; u32 num_condpath_tmpls; struct avs_tplg_init_config *init_configs; u32 num_init_configs; + struct avs_tplg_nhlt_config *nhlt_configs; + u32 num_nhlt_configs; struct list_head path_tmpl_list; }; @@ -87,7 +90,7 @@ struct avs_tplg_modcfg_ext { struct { u32 out_channel_config; u32 coefficients_select; - s32 coefficients[AVS_CHANNELS_MAX]; + s32 coefficients[AVS_COEFF_CHANNELS_MAX]; u32 channel_map; } updown_mix; struct { @@ -155,6 +158,10 @@ struct avs_tplg_path_template { struct snd_soc_dapm_widget *w; + /* Conditional path. */ + struct avs_tplg_path_template_id source; + struct avs_tplg_path_template_id sink; + struct list_head path_list; struct avs_tplg *owner; @@ -170,12 +177,20 @@ struct avs_tplg_init_config { void *data; }; +struct avs_tplg_nhlt_config { + u32 id; + struct acpi_nhlt_config *blob; +}; + struct avs_tplg_path { u32 id; /* Path format requirements. */ struct avs_audio_format *fe_fmt; struct avs_audio_format *be_fmt; + /* Condpath path-variant requirements. */ + u32 source_path_id; + u32 sink_path_id; struct list_head ppl_list; @@ -208,6 +223,7 @@ struct avs_tplg_module { u32 ctl_id; u32 num_config_ids; u32 *config_ids; + struct avs_tplg_nhlt_config *nhlt_config; struct avs_tplg_pipeline *owner; /* Pipeline modules management. */ diff --git a/sound/soc/intel/avs/utils.h b/sound/soc/intel/avs/utils.h index 5ee569c39380..955a40d2c30c 100644 --- a/sound/soc/intel/avs/utils.h +++ b/sound/soc/intel/avs/utils.h @@ -11,6 +11,16 @@ #include <sound/soc-acpi.h> +extern bool obsolete_card_names; + +struct avs_mach_pdata { + struct hda_codec *codec; + unsigned long *tdms; + char *codec_name; /* DMIC only */ + + bool obsolete_card_names; +}; + static inline bool avs_mach_singular_ssp(struct snd_soc_acpi_mach *mach) { return hweight_long(mach->mach_params.i2s_link_mask) == 1; @@ -23,14 +33,16 @@ static inline u32 avs_mach_ssp_port(struct snd_soc_acpi_mach *mach) static inline bool avs_mach_singular_tdm(struct snd_soc_acpi_mach *mach, u32 port) { - unsigned long *tdms = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + unsigned long *tdms = pdata->tdms; return !tdms || (hweight_long(tdms[port]) == 1); } static inline u32 avs_mach_ssp_tdm(struct snd_soc_acpi_mach *mach, u32 port) { - unsigned long *tdms = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + unsigned long *tdms = pdata->tdms; return tdms ? __ffs(tdms[port]) : 0; } diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 9b80b19bb8d0..c23fdb6aad4c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -11,7 +11,7 @@ menuconfig SND_SOC_INTEL_MACH kernel: saying N will just cause the configurator to skip all the questions about Intel ASoC machine drivers. -if SND_SOC_INTEL_MACH +if SND_SOC_INTEL_MACH && (SND_SOC_SOF_INTEL_COMMON || !SND_SOC_SOF_INTEL_COMMON) config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES bool "Use more user friendly long card names" @@ -42,6 +42,7 @@ config SND_SOC_INTEL_SOF_NUVOTON_COMMON tristate config SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_ACPI_INTEL_MATCH tristate if SND_SOC_INTEL_CATPT @@ -252,14 +253,6 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - tristate - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON - if SND_SOC_SOF_APOLLOLAKE config SND_SOC_INTEL_SOF_WM8804_MACH diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 9484f3410787..408d20ed8cee 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -27,8 +27,7 @@ struct bdw_rt5677_priv { static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -228,7 +227,7 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret; ret = devm_acpi_dev_add_driver_gpios(component->dev, bdw_rt5677_gpios); @@ -366,7 +365,7 @@ static int bdw_rt5677_suspend_pre(struct snd_soc_card *card) struct snd_soc_dapm_context *dapm; if (bdw_rt5677->component) { - dapm = snd_soc_component_get_dapm(bdw_rt5677->component); + dapm = snd_soc_component_to_dapm(bdw_rt5677->component); snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); } return 0; @@ -378,7 +377,7 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card) struct snd_soc_dapm_context *dapm; if (bdw_rt5677->component) { - dapm = snd_soc_component_get_dapm(bdw_rt5677->component); + dapm = snd_soc_component_to_dapm(bdw_rt5677->component); snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); } return 0; diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 68a3d345dc25..0a7e6d2e37cb 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -70,6 +70,7 @@ static const struct acpi_gpio_mapping byt_cht_cx2072x_acpi_gpios[] = { static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct snd_soc_component *codec = snd_soc_rtd_to_codec(rtd, 0)->component; int ret; @@ -77,7 +78,7 @@ static int byt_cht_cx2072x_init(struct snd_soc_pcm_runtime *rtd) byt_cht_cx2072x_acpi_gpios)) dev_warn(rtd->dev, "Unable to add GPIO mapping table\n"); - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); /* set the default PLL rate, the clock is handled by the codec driver */ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), CX2072X_MCLK_EXTERNAL_PLL, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 62594e7966ab..192e2a394ff3 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,7 +47,8 @@ enum { BYT_CHT_ES8316_INTMIC_IN2_MAP, }; -#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_CHT_ES8316_MAP_MASK GENMASK(3, 0) +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & BYT_CHT_ES8316_MAP_MASK) #define BYT_CHT_ES8316_SSP0 BIT(16) #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) #define BYT_CHT_ES8316_JD_INVERTED BIT(18) @@ -60,10 +61,23 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + int map; + + map = BYT_CHT_ES8316_MAP(quirk); + switch (map) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: dev_info(dev, "quirk IN1_MAP enabled"); - if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: dev_info(dev, "quirk IN2_MAP enabled"); + break; + default: + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to INTMIC_IN1_MAP\n", map); + quirk &= ~BYT_CHT_ES8316_MAP_MASK; + quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; + break; + } + if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) @@ -75,7 +89,7 @@ static void log_quirks(struct device *dev) static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_card *card = w->dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -160,12 +174,13 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; int ret; - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); switch (BYT_CHT_ES8316_MAP(quirk)) { case BYT_CHT_ES8316_INTMIC_IN1_MAP: @@ -178,7 +193,7 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); break; } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; @@ -189,7 +204,7 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_cht_es8316_ssp2_map; num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 0f3b8f44e701..103e0b445603 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -68,7 +68,8 @@ enum { BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13), }; -#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5640_MAP_MASK GENMASK(3, 0) +#define BYT_RT5640_MAP(quirk) ((quirk) & BYT_RT5640_MAP_MASK) #define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) #define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) #define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) @@ -140,7 +141,9 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk NO_INTERNAL_MIC_MAP enabled\n"); break; default: - dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC1_MAP\n", map); + byt_rt5640_quirk &= ~BYT_RT5640_MAP_MASK; + byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP; break; } if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) @@ -254,7 +257,7 @@ static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, static struct snd_soc_dai *byt_rt5640_get_codec_dai(struct snd_soc_dapm_context *dapm) { - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(dapm); struct snd_soc_dai *codec_dai; codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1); @@ -270,7 +273,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(dapm); struct snd_soc_dai *codec_dai; struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); int ret; @@ -1314,6 +1317,7 @@ put_adev: static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); struct rt5640_set_jack_data *jack_data = &priv->jack_data; struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; @@ -1321,7 +1325,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) int num_routes = 0; int ret; - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); jack_data->use_platform_clock = true; /* Start with RC clk for jack-detect (we disable MCLK below) */ @@ -1364,12 +1368,12 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) break; } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; if (byt_rt5640_quirk & BYT_RT5640_HSMIC2_ON_IN1) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_hsmic2_in1_map, ARRAY_SIZE(byt_rt5640_hsmic2_in1_map)); if (ret) @@ -1377,19 +1381,19 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_ssp2_aif2_map, ARRAY_SIZE(byt_rt5640_ssp2_aif2_map)); } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_ssp0_aif1_map, ARRAY_SIZE(byt_rt5640_ssp0_aif1_map)); } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_ssp0_aif2_map, ARRAY_SIZE(byt_rt5640_ssp0_aif2_map)); } else { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_ssp2_aif1_map, ARRAY_SIZE(byt_rt5640_ssp2_aif1_map)); } @@ -1397,11 +1401,11 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_mono_spk_map, ARRAY_SIZE(byt_rt5640_mono_spk_map)); } else if (!(byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_stereo_spk_map, ARRAY_SIZE(byt_rt5640_stereo_spk_map)); } @@ -1409,7 +1413,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; if (byt_rt5640_quirk & BYT_RT5640_LINEOUT) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5640_lineout_map, ARRAY_SIZE(byt_rt5640_lineout_map)); if (ret) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 67c62844ca2a..68cf463f1d50 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -58,7 +58,8 @@ enum { BYT_RT5651_OVCD_SF_1P5 = (RT5651_OVCD_SF_1P5 << 13), }; -#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(3, 0)) +#define BYT_RT5651_MAP_MASK GENMASK(3, 0) +#define BYT_RT5651_MAP(quirk) ((quirk) & BYT_RT5651_MAP_MASK) #define BYT_RT5651_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) #define BYT_RT5651_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) #define BYT_RT5651_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) @@ -100,14 +101,29 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) + int map; + + map = BYT_RT5651_MAP(byt_rt5651_quirk); + switch (map) { + case BYT_RT5651_DMIC_MAP: dev_info(dev, "quirk DMIC_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_MAP) + break; + case BYT_RT5651_IN1_MAP: dev_info(dev, "quirk IN1_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP) + break; + case BYT_RT5651_IN2_MAP: dev_info(dev, "quirk IN2_MAP enabled"); - if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_IN2_MAP) + break; + case BYT_RT5651_IN1_IN2_MAP: dev_info(dev, "quirk IN1_IN2_MAP enabled"); + break; + default: + dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to DMIC_MAP\n", map); + byt_rt5651_quirk &= ~BYT_RT5651_MAP_MASK; + byt_rt5651_quirk |= BYT_RT5651_DMIC_MAP; + break; + } + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { dev_info(dev, "quirk realtek,jack-detect-source %ld\n", BYT_RT5651_JDSRC(byt_rt5651_quirk)); @@ -172,8 +188,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); int ret; @@ -218,7 +233,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, static int rt5651_ext_amp_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_card *card = w->dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); if (SND_SOC_DAPM_EVENT_ON(event)) @@ -563,6 +578,7 @@ static int byt_rt5651_add_codec_device_props(struct device *i2c_dev, static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -570,7 +586,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) int report; int ret; - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); /* Start with RC clk for jack-detect (we disable MCLK below) */ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) @@ -594,24 +610,24 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5651_intmic_dmic_map; num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map); } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; if (byt_rt5651_quirk & BYT_RT5651_SSP2_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5651_ssp2_aif2_map, ARRAY_SIZE(byt_rt5651_ssp2_aif2_map)); } else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF1) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5651_ssp0_aif1_map, ARRAY_SIZE(byt_rt5651_ssp0_aif1_map)); } else if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5651_ssp0_aif2_map, ARRAY_SIZE(byt_rt5651_ssp0_aif2_map)); } else { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, byt_rt5651_ssp2_aif1_map, ARRAY_SIZE(byt_rt5651_ssp2_aif1_map)); } diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index a6dfbcfdf74e..4879f79aef29 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -99,7 +99,7 @@ static void log_quirks(struct device *dev) static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_card *card = w->dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); gpiod_set_value_cansleep(priv->spkvdd_en_gpio, @@ -150,8 +150,7 @@ static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); int ret; @@ -283,12 +282,13 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = { static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; const struct snd_soc_dapm_route *custom_map = NULL; int ret, jack_type, num_routes = 0; - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); ret = snd_soc_add_card_controls(card, byt_wm5102_controls, ARRAY_SIZE(byt_wm5102_controls)); @@ -307,7 +307,7 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(byt_wm5102_intmic_in1l_hsmic_in2l_map); break; } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; @@ -321,7 +321,7 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(byt_wm5102_spk_hpout2_map); break; } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; @@ -332,7 +332,7 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) custom_map = bytcr_wm5102_ssp0_map; num_routes = ARRAY_SIZE(bytcr_wm5102_ssp0_map); } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; @@ -552,7 +552,7 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) acpi_dev_put(adev); } else { /* Special case for when the codec is missing from the DSTD */ - strscpy(codec_name, "spi1.0", sizeof(codec_name)); + strscpy(codec_name, "spi-wm5102", sizeof(codec_name)); } codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 36984de8a067..ad45b79d3e4b 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -42,8 +42,7 @@ struct cht_mc_private { static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; @@ -130,7 +129,7 @@ static int cht_ti_jack_event(struct notifier_block *nb, unsigned long event, void *data) { struct snd_soc_jack *jack = (struct snd_soc_jack *)data; - struct snd_soc_dapm_context *dapm = &jack->card->dapm; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card); if (event & SND_JACK_MICROPHONE) { snd_soc_dapm_force_enable_pin(dapm, "SHDN"); diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index b977a2db73a3..249be121be15 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -66,8 +66,7 @@ static void log_quirks(struct device *dev) static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; @@ -250,6 +249,7 @@ static const struct dmi_system_id cht_rt5645_quirk_table[] = { static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component; int jack_type; @@ -275,19 +275,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) } if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_rt5645_ssp2_aif2_map, ARRAY_SIZE(cht_rt5645_ssp2_aif2_map)); } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_rt5645_ssp0_aif1_map, ARRAY_SIZE(cht_rt5645_ssp0_aif1_map)); } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_rt5645_ssp0_aif2_map, ARRAY_SIZE(cht_rt5645_ssp0_aif2_map)); } else { - ret = snd_soc_dapm_add_routes(&card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_rt5645_ssp2_aif1_map, ARRAY_SIZE(cht_rt5645_ssp2_aif1_map)); } diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index aaef212cf44e..359723f2700e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/string.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -50,8 +51,7 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct snd_soc_dai *codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; @@ -192,6 +192,7 @@ static const struct acpi_gpio_mapping cht_rt5672_gpios[] = { static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { int ret; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(runtime->card); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, 0); struct snd_soc_component *component = codec_dai->component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); @@ -214,11 +215,11 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) RT5670_CLK_SEL_I2S1_ASRC); if (ctx->use_ssp0) { - ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_audio_ssp0_map, ARRAY_SIZE(cht_audio_ssp0_map)); } else { - ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + ret = snd_soc_dapm_add_routes(dapm, cht_audio_ssp2_map, ARRAY_SIZE(cht_audio_ssp2_map)); } @@ -458,7 +459,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (!drv) return -ENOMEM; - strcpy(drv->codec_name, RT5672_I2C_DEFAULT); + strscpy(drv->codec_name, RT5672_I2C_DEFAULT, sizeof(drv->codec_name)); /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 86e541a2c204..328ffff336a8 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -15,7 +15,7 @@ /* * Search card topology and return PCM device number - * matching Nth HDMI device (zero-based index). + * matching Nth playback HDMI device (zero-based index). */ static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, int hdmi_idx) @@ -25,8 +25,17 @@ static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, int i = 0; for_each_card_rtds(card, rtd) { - spcm = rtd->pcm ? - rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].pcm : NULL; + /* ignore BE PCMs */ + if (rtd->dai_link && rtd->dai_link->no_pcm) + continue; + + spcm = rtd->pcm; + + /* ignore PCMs with no playback streams */ + if (!spcm || !spcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) + continue; + + /* look for FE PCMs with name "HDMI x" */ if (spcm && strstr(spcm->id, "HDMI")) { if (i == hdmi_idx) return rtd->pcm; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 0554c7e2cb34..519218385fdf 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -85,6 +85,18 @@ skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) return board_quirk; } +static int skl_hda_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + + /* Ignore the HDMI PCM link if iDisp is not present */ + if (strstr(link->stream_name, "HDMI") && !ctx->hdmi.idisp_codec) + link->ignore = true; + + return 0; +} + static int skl_hda_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; @@ -101,6 +113,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->fully_routed = true; card->late_probe = skl_hda_card_late_probe; + card->add_dai_link = skl_hda_add_dai_link; dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 2ea1dda446ec..f741a1e142be 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -51,16 +51,17 @@ static const struct snd_soc_dapm_route dmic_routes[] = { static int dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ret = snd_soc_dapm_new_controls(dapm, dmic_widgets, ARRAY_SIZE(dmic_widgets)); if (ret) { dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret); return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_routes, + ret = snd_soc_dapm_add_routes(dapm, dmic_routes, ARRAY_SIZE(dmic_routes)); if (ret) { dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret); @@ -111,16 +112,17 @@ static const struct snd_soc_dapm_route hda_routes[] = { static int hda_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets, + ret = snd_soc_dapm_new_controls(dapm, hda_widgets, ARRAY_SIZE(hda_widgets)); if (ret) { dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret); return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes, + ret = snd_soc_dapm_add_routes(dapm, hda_routes, ARRAY_SIZE(hda_routes)); if (ret) dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret); diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c index 8db7695b9747..88fc6cb2bfd4 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.c +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -48,9 +48,10 @@ static struct snd_soc_codec_conf cs35l41_codec_conf[CS35L41_MAX_AMPS]; static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, cs35l41_dapm_widgets, + ret = snd_soc_dapm_new_controls(dapm, cs35l41_dapm_widgets, ARRAY_SIZE(cs35l41_dapm_widgets)); if (ret) { dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret); @@ -64,7 +65,7 @@ static int cs35l41_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, cs35l41_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, cs35l41_dapm_routes, ARRAY_SIZE(cs35l41_dapm_routes)); if (ret) diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index 9b7082b239c1..ad845d32f642 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -29,8 +29,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai *codec_dai; int ret = 0; @@ -181,7 +180,7 @@ static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) static int card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dapm_context *dapm = &card->dapm; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int err; if (ctx->amp_type == CODEC_MAX98373) { diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index a0b3679b17b4..774fff58d51b 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -155,7 +155,7 @@ static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd) static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_card *card = w->dapm->card; + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event)) @@ -163,7 +163,7 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event); - queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); + queue_delayed_work(system_dfl_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); return 0; } @@ -231,16 +231,17 @@ static struct snd_soc_jack_pin sof_es8316_jack_pins[] = { static int dmic_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ret = snd_soc_dapm_new_controls(dapm, dmic_widgets, ARRAY_SIZE(dmic_widgets)); if (ret) { dev_err(card->dev, "DMic widget addition failed: %d\n", ret); return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ret = snd_soc_dapm_add_routes(dapm, dmic_map, ARRAY_SIZE(dmic_map)); if (ret) dev_err(card->dev, "DMic map addition failed: %d\n", ret); @@ -271,12 +272,13 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct snd_soc_card *card = runtime->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; int ret; - card->dapm.idle_bias_off = true; + snd_soc_dapm_set_idle_bias(dapm, false); if (quirk & SOC_ES8336_HEADSET_MIC1) { custom_map = sof_es8316_headset_mic1_map; @@ -286,7 +288,7 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(sof_es8316_headset_mic2_map); } - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) return ret; @@ -826,6 +828,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "ptl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index c98a67ae5e66..c3d0f697ff8d 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -201,8 +201,7 @@ static int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); for_each_rtd_codec_dais(rtd, j, codec_dai) { - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(cpu_dai->component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(cpu_dai->component); char pin_name[MAX_98373_PIN_NAME]; snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", @@ -239,12 +238,13 @@ static const struct snd_soc_ops max_98373_ops = { static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID); int ret; switch (num_codecs) { case 2: - ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, maxim_2spk_widgets, ARRAY_SIZE(maxim_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n", @@ -260,7 +260,7 @@ static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, max_98373_dapm_routes, ARRAY_SIZE(max_98373_dapm_routes)); if (ret) { dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n", @@ -416,13 +416,14 @@ static int max_98390_hw_params(struct snd_pcm_substream *substream, static int max_98390_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID); int ret; switch (num_codecs) { case 4: /* add widgets/controls/dapm for tweeter speakers */ - ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets, + ret = snd_soc_dapm_new_controls(dapm, max_98390_tt_dapm_widgets, ARRAY_SIZE(max_98390_tt_dapm_widgets)); if (ret) { dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n", @@ -439,7 +440,7 @@ static int max_98390_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, max_98390_tt_dapm_routes, ARRAY_SIZE(max_98390_tt_dapm_routes)); if (ret) { dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n", @@ -450,7 +451,7 @@ static int max_98390_init(struct snd_soc_pcm_runtime *rtd) fallthrough; case 2: /* add regular speakers dapm route */ - ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, maxim_2spk_widgets, ARRAY_SIZE(maxim_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n", @@ -466,7 +467,7 @@ static int max_98390_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, max_98390_dapm_routes, ARRAY_SIZE(max_98390_dapm_routes)); if (ret) { dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", @@ -564,9 +565,10 @@ static struct snd_soc_dai_link_component max_98360a_components[] = { static int max_98357a_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets, + ret = snd_soc_dapm_new_controls(dapm, max_98357a_dapm_widgets, ARRAY_SIZE(max_98357a_dapm_widgets)); if (ret) { dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret); @@ -581,7 +583,7 @@ static int max_98357a_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, max_98357a_dapm_routes, ARRAY_SIZE(max_98357a_dapm_routes)); if (ret) diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 72ce32e2cd57..15ba6f5c697c 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -122,7 +122,7 @@ static const struct snd_soc_ops sof_nau8825_ops = { static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dapm_context *dapm = &card->dapm; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int err; if (ctx->amp_type == CODEC_MAX98373) { diff --git a/sound/soc/intel/boards/sof_nuvoton_common.c b/sound/soc/intel/boards/sof_nuvoton_common.c index ed41cb6f7fa5..b09ecbab2fc9 100644 --- a/sound/soc/intel/boards/sof_nuvoton_common.c +++ b/sound/soc/intel/boards/sof_nuvoton_common.c @@ -34,9 +34,10 @@ static struct snd_soc_dai_link_component nau8318_components[] = { static int nau8318_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, nau8318_widgets, + ret = snd_soc_dapm_new_controls(dapm, nau8318_widgets, ARRAY_SIZE(nau8318_widgets)); if (ret) { dev_err(rtd->dev, "fail to add nau8318 widgets, ret %d\n", ret); @@ -50,7 +51,7 @@ static int nau8318_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, nau8318_routes, + ret = snd_soc_dapm_add_routes(dapm, nau8318_routes, ARRAY_SIZE(nau8318_routes)); if (ret) { diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 2f43710c1bae..359559b6175b 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -177,9 +177,10 @@ static const struct snd_soc_dapm_route dmic_map[] = { static int dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ret = snd_soc_dapm_new_controls(dapm, dmic_widgets, ARRAY_SIZE(dmic_widgets)); if (ret) { dev_err(card->dev, "DMic widget addition failed: %d\n", ret); @@ -187,7 +188,7 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ret = snd_soc_dapm_add_routes(dapm, dmic_map, ARRAY_SIZE(dmic_map)); if (ret) diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index 600707d403b9..835186cf04d0 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -186,13 +186,14 @@ static const struct snd_soc_ops rt1011_ops = { static int rt1011_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); int ret; switch (num_codecs) { case 2: if (!soc_intel_is_cml()) { - ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets, ARRAY_SIZE(realtek_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", @@ -208,7 +209,7 @@ static int rt1011_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, + ret = snd_soc_dapm_add_routes(dapm, speaker_map_lr, ARRAY_SIZE(speaker_map_lr)); if (ret) { dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", @@ -225,24 +226,21 @@ static int rt1011_init(struct snd_soc_pcm_runtime *rtd) */ fallthrough; case 4: - ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets, - num_codecs); + ret = snd_soc_dapm_new_controls(dapm, realtek_4spk_widgets, num_codecs); if (ret) { dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", ret); return ret; } - ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols, - num_codecs); + ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols, num_codecs); if (ret) { dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n", ret); return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes, - num_codecs); + ret = snd_soc_dapm_add_routes(dapm, rt1011_4spk_routes, num_codecs); if (ret) { dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", ret); @@ -344,9 +342,10 @@ static const struct snd_soc_ops rt1015p_ops = { static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets, ARRAY_SIZE(realtek_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret); @@ -360,7 +359,7 @@ static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, rt1015p_dapm_routes, ARRAY_SIZE(rt1015p_dapm_routes)); if (ret) dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); @@ -481,12 +480,13 @@ static struct snd_soc_dai_link_component rt1015_components[] = { static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID); int ret; switch (num_codecs) { case 2: - ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets, ARRAY_SIZE(realtek_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n", @@ -502,7 +502,7 @@ static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, + ret = snd_soc_dapm_add_routes(dapm, speaker_map_lr, ARRAY_SIZE(speaker_map_lr)); if (ret) { dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n", @@ -561,9 +561,10 @@ static struct snd_soc_dai_link_component rt1308_components[] = { static int rt1308_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_dapm_widgets, + ret = snd_soc_dapm_new_controls(dapm, rt1308_dapm_widgets, ARRAY_SIZE(rt1308_dapm_widgets)); if (ret) { dev_err(rtd->dev, "fail to add dapm controls, ret %d\n", ret); @@ -577,7 +578,7 @@ static int rt1308_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, rt1308_dapm_routes, ARRAY_SIZE(rt1308_dapm_routes)); if (ret) @@ -650,9 +651,10 @@ static struct snd_soc_dai_link_component rt1019p_components[] = { static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, realtek_2spk_widgets, ARRAY_SIZE(realtek_2spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret); @@ -666,7 +668,7 @@ static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, rt1019p_dapm_routes, ARRAY_SIZE(rt1019p_dapm_routes)); if (ret) { dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f5925bd0a3fc..3d9d8a97d153 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -35,6 +35,10 @@ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | SOF_SSP_PORT_CODEC(0); +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) { sof_rt5682_quirk = (unsigned long)id->driver_data; @@ -404,7 +408,7 @@ static const struct snd_soc_ops sof_rt5682_ops = { static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dapm_context *dapm = &card->dapm; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int err; if (ctx->amp_type == CODEC_MAX98373) { @@ -458,9 +462,10 @@ static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = { static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); int ret; - ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets, + ret = snd_soc_dapm_new_controls(dapm, rt5650_spk_widgets, ARRAY_SIZE(rt5650_spk_widgets)); if (ret) { dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n", @@ -476,7 +481,7 @@ static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes, + ret = snd_soc_dapm_add_routes(dapm, rt5650_spk_dapm_routes, ARRAY_SIZE(rt5650_spk_dapm_routes)); if (ret) dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret); @@ -643,6 +648,12 @@ static int sof_audio_probe(struct platform_device *pdev) dmi_check_system(sof_rt5682_quirk_table); + if (quirk_override != -1) { + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", + sof_rt5682_quirk, quirk_override); + sof_rt5682_quirk = quirk_override; + } + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); /* initialize ctx with board quirk */ @@ -892,6 +903,13 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_PORT_BT_OFFLOAD(2) | SOF_BT_OFFLOAD_PRESENT), }, + { + .name = "ptl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 095d08b3fc82..2c1001148d54 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -231,6 +231,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { RT711_JD1), }, { + /* + * Avell B.ON (OEM rebrand of NUC15 'Bishop County' LAPBC510 and + * LAPBC710) + */ + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Avell High Performance"), + DMI_MATCH(DMI_PRODUCT_NAME, "B.ON"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + SOC_SDW_PCH_DMIC | + RT711_JD1), + }, + { /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ .callback = sof_sdw_quirk_cb, .matches = { @@ -741,6 +755,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCC") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, /* Pantherlake devices*/ { .callback = sof_sdw_quirk_cb, @@ -753,7 +775,47 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"), + DMI_MATCH(DMI_PRODUCT_NAME, "Lapis"), + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR | + SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Francka"), + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR | + SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Fatcat"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + /* Wildcatlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"), }, .driver_data = (void *)(SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | @@ -765,6 +827,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC), + SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC), + SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC), + SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC), {} }; @@ -780,13 +845,6 @@ static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) sof_sdw_quirk = quirk_entry->value; } -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static const struct snd_soc_ops sdw_ops = { .startup = asoc_sdw_startup, .prepare = asoc_sdw_prepare, @@ -819,7 +877,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, (*codec_conf)++; } - if (sof_end->include_sidecar) { + if (sof_end->include_sidecar && sof_end->codec_info->add_sidecar) { ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); if (ret) return ret; @@ -836,6 +894,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, struct snd_soc_dai_link_ch_map *codec_maps; struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link_component *platform; int num_cpus = hweight32(sof_dai->link_mask[stream]); int num_codecs = sof_dai->num_devs[stream]; int playback, capture; @@ -876,6 +935,10 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (!codecs) return -ENOMEM; + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!platform) + return -ENOMEM; + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); if (!codec_maps) return -ENOMEM; @@ -917,8 +980,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, capture = (stream == SNDRV_PCM_STREAM_CAPTURE); asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, - cpus, num_cpus, platform_component, - ARRAY_SIZE(platform_component), codecs, num_codecs, + cpus, num_cpus, platform, 1, codecs, num_codecs, 1, asoc_sdw_rtd_init, &sdw_ops); /* @@ -994,8 +1056,7 @@ static int create_ssp_dailinks(struct snd_soc_card *card, ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, playback, capture, cpu_dai_name, - platform_component->name, - ARRAY_SIZE(platform_component), codec_name, + "dummy", codec_name, ssp_info->dais[0].dai_name, 1, NULL, ssp_info->ops); if (ret) @@ -1019,8 +1080,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", 0, 1, // DMIC only supports capture - "DMIC01 Pin", platform_component->name, - ARRAY_SIZE(platform_component), + "DMIC01 Pin", "dummy", "dmic-codec", "dmic-hifi", 1, asoc_sdw_dmic_init, NULL); if (ret) @@ -1030,8 +1090,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", 0, 1, // DMIC only supports capture - "DMIC16k Pin", platform_component->name, - ARRAY_SIZE(platform_component), + "DMIC16k Pin", "dummy", "dmic-codec", "dmic-hifi", 1, /* don't call asoc_sdw_dmic_init() twice */ NULL, NULL); @@ -1074,8 +1133,7 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1, 0, // HDMI only supports playback - cpu_dai_name, platform_component->name, - ARRAY_SIZE(platform_component), + cpu_dai_name, "dummy", codec_name, codec_dai_name, 1, i == 0 ? sof_sdw_hdmi_init : NULL, NULL); if (ret) @@ -1091,18 +1149,24 @@ static int create_bt_dailinks(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, int *be_id) { struct device *dev = card->dev; - int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); + struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); + char *cpu_dai_name; + char *name; + int port; + int ret; + + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; + else + port = fls(mach->mach_params.bt_link_mask) - 1; + + name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); if (!name || !cpu_dai_name) return -ENOMEM; - int ret; - ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, - 1, 1, cpu_dai_name, platform_component->name, - ARRAY_SIZE(platform_component), + 1, 1, cpu_dai_name, "dummy", snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1, NULL, NULL); if (ret) @@ -1125,8 +1189,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct asoc_sdw_codec_info *ssp_info; struct asoc_sdw_endpoint *sof_ends; struct asoc_sdw_dailink *sof_dais; + struct snd_soc_aux_dev *sof_aux; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; struct snd_soc_dai_link *dai_links; int num_links; int be_id = 0; @@ -1134,12 +1201,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) unsigned long ssp_mask; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; + /* * One per DAI link, worst case is a DAI link for every endpoint, also * add one additional to act as a terminator such that code can iterate @@ -1156,7 +1225,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); + if (!sof_aux) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs); if (ret < 0) goto err_end; @@ -1197,14 +1272,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; } - if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT || mach_params->bt_link_mask) bt_num = 1; dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", sdw_be_num, ssp_num, dmic_num, intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) { ret = -ENOMEM; goto err_end; @@ -1219,9 +1294,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) } card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = sof_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { @@ -1252,7 +1329,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_end; /* BT */ - if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + if (bt_num) { ret = create_bt_dailinks(card, &dai_links, &be_id); if (ret) goto err_end; @@ -1285,6 +1362,19 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card) return ret; } +static int sof_sdw_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + + /* Ignore the HDMI PCM link if iDisp is not present */ + if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec) + link->ignore = true; + + return 0; +} + static int mc_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); @@ -1311,6 +1401,7 @@ static int mc_probe(struct platform_device *pdev) card->name = "soundwire"; card->owner = THIS_MODULE; card->late_probe = sof_sdw_card_late_probe; + card->add_dai_link = sof_sdw_add_dai_link; snd_soc_card_set_drvdata(card, ctx); diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 48ee5353bdf1..729c0cd7c19c 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -216,6 +216,12 @@ static const struct platform_device_id board_ids[] = { /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_HDMI_PLAYBACK_PRESENT), }, + { + .name = "ptl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index faa916f40069..d13062c8e907 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -28,7 +28,7 @@ #define CREATE_TRACE_POINTS #include "trace.h" -static int catpt_suspend(struct device *dev) +static int catpt_do_suspend(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); struct dma_chan *chan; @@ -72,6 +72,13 @@ release_dma_chan: return catpt_dsp_power_down(cdev); } +/* Do not block the system from suspending, recover on resume() if needed. */ +static int catpt_suspend(struct device *dev) +{ + catpt_do_suspend(dev); + return 0; +} + static int catpt_resume(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); @@ -114,7 +121,7 @@ static int catpt_runtime_suspend(struct device *dev) } module_put(dev->driver->owner); - return catpt_suspend(dev); + return catpt_do_suspend(dev); } static int catpt_runtime_resume(struct device *dev) @@ -184,22 +191,25 @@ static int catpt_probe_components(struct catpt_dev *cdev) goto err_boot_fw; } - ret = catpt_register_board(cdev); - if (ret) { - dev_err(cdev->dev, "register board failed: %d\n", ret); - goto err_reg_board; - } - /* reflect actual ADSP state in pm_runtime */ pm_runtime_set_active(cdev->dev); pm_runtime_set_autosuspend_delay(cdev->dev, 2000); pm_runtime_use_autosuspend(cdev->dev); pm_runtime_mark_last_busy(cdev->dev); + /* Enable PM before spawning child device. See catpt_dai_pcm_new(). */ pm_runtime_enable(cdev->dev); + + ret = catpt_register_board(cdev); + if (ret) { + dev_err(cdev->dev, "register board failed: %d\n", ret); + goto err_reg_board; + } + return 0; err_reg_board: + pm_runtime_disable(cdev->dev); snd_soc_unregister_component(cdev->dev); err_boot_fw: catpt_dmac_remove(cdev); diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 696d84314eeb..f5705cd2c1e1 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -208,6 +208,7 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { struct catpt_save_meminfo *info; + struct resource r = {}; u32 off; int ret; @@ -216,7 +217,8 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) continue; off = catpt_to_host_offset(info->offset); - if (off < cdev->dram.start || off > cdev->dram.end) + resource_set_range(&r, off, info->size); + if (!resource_contains(&cdev->dram, &r)) continue; dev_dbg(cdev->dev, "restoring memdump: off 0x%08x size %d\n", @@ -239,34 +241,32 @@ static int catpt_restore_fwimage(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, struct catpt_fw_block_hdr *blk) { - struct resource r1, r2, common; + struct resource r1 = {}; int i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, blk, sizeof(*blk), false); - r1.start = cdev->dram.start + blk->ram_offset; - r1.end = r1.start + blk->size - 1; + resource_set_range(&r1, cdev->dram.start + blk->ram_offset, blk->size); /* advance to data area */ paddr += sizeof(*blk); for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) { struct catpt_save_meminfo *info; + struct resource common = {}; + struct resource r2 = {}; u32 off; int ret; info = &cdev->dx_ctx.meminfo[i]; - if (info->source != CATPT_DX_TYPE_FW_IMAGE) continue; off = catpt_to_host_offset(info->offset); - if (off < cdev->dram.start || off > cdev->dram.end) + resource_set_range(&r2, off, info->size); + if (!resource_contains(&cdev->dram, &r2)) continue; - r2.start = off; - r2.end = r2.start + info->size - 1; - if (!resource_intersection(&r2, &r1, &common)) continue; /* calculate start offset of common data area */ diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 81a2f0339e05..abd1cb07c60c 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -417,8 +417,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, return CATPT_IPC_ERROR(ret); ret = catpt_dai_apply_usettings(dai, stream); - if (ret) + if (ret) { + catpt_ipc_free_stream(cdev, stream->info.stream_hw_id); return ret; + } stream->allocated = true; return 0; @@ -568,8 +570,9 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = { SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, .period_bytes_min = PAGE_SIZE, .period_bytes_max = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN, .periods_min = CATPT_PCM_PERIODS_MIN, @@ -668,12 +671,11 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, return 0; ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; ret = catpt_ipc_set_device_format(cdev, &devfmt); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) @@ -699,14 +701,18 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, .capture = { .stream_name = "Analog Capture", .channels_min = 2, .channels_max = 4, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }, { @@ -718,7 +724,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }, { @@ -730,7 +738,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }, { @@ -742,7 +752,9 @@ static struct snd_soc_dai_driver dai_drivers[] = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_24 | + SNDRV_PCM_SUBFMTBIT_MSBITS_MAX, }, }, { @@ -855,15 +867,14 @@ static int catpt_volume_info(struct snd_kcontrol *kcontrol, static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct catpt_dev *cdev = dev_get_drvdata(component->dev); u32 dspvol; int ret; int i; ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; for (i = 0; i < CATPT_CHANNELS_MAX; i++) { @@ -871,7 +882,6 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); } - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return 0; @@ -880,19 +890,17 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol, static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct catpt_dev *cdev = dev_get_drvdata(component->dev); int ret; ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id, ucontrol->value.integer.value); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return ret; @@ -902,8 +910,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, enum catpt_pin_id pin_id) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct catpt_stream_runtime *stream; struct catpt_dev *cdev = dev_get_drvdata(component->dev); long *ctlvol = (long *)kcontrol->private_value; @@ -919,7 +926,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, } ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; for (i = 0; i < CATPT_CHANNELS_MAX; i++) { @@ -927,7 +934,6 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol); } - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); return 0; @@ -937,8 +943,7 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, enum catpt_pin_id pin_id) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct catpt_stream_runtime *stream; struct catpt_dev *cdev = dev_get_drvdata(component->dev); long *ctlvol = (long *)kcontrol->private_value; @@ -952,13 +957,12 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, } ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id, ucontrol->value.integer.value); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) @@ -1015,8 +1019,7 @@ static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol, static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct catpt_stream_runtime *stream; struct catpt_dev *cdev = dev_get_drvdata(component->dev); bool mute; @@ -1030,12 +1033,11 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, } ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c index 936ac9d503ff..e961e172f9b7 100644 --- a/sound/soc/intel/catpt/sysfs.c +++ b/sound/soc/intel/catpt/sysfs.c @@ -16,12 +16,11 @@ static ssize_t fw_version_show(struct device *dev, int ret; ret = pm_runtime_resume_and_get(cdev->dev); - if (ret < 0 && ret != -EACCES) + if (ret) return ret; ret = catpt_ipc_get_fw_version(cdev, &version); - pm_runtime_mark_last_busy(cdev->dev); pm_runtime_put_autosuspend(cdev->dev); if (ret) diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 0afd114be9e5..dbfd9e2ac015 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -11,8 +11,9 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc soc-acpi-intel-arl-match.o \ soc-acpi-intel-lnl-match.o \ soc-acpi-intel-ptl-match.o \ + soc-acpi-intel-nvl-match.o \ soc-acpi-intel-hda-match.o \ - soc-acpi-intel-sdw-mockup-match.o + soc-acpi-intel-sdw-mockup-match.o sof-function-topology-lib.o snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index 32147dc9d2d6..6bf7a6250ddc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -8,6 +8,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-ssp-common.h> +#include "sof-function-topology-lib.h" static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, @@ -237,6 +238,15 @@ static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = { + { + .adr = 0x000330025D131601ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1316-1" + } +}; + static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = { { .adr = 0x000230025D132001ull, @@ -367,6 +377,20 @@ static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr arl_rt711_l0_rt1316_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_single_adr), + .adr_d = rt1316_3_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = { { .mask = BIT(0), @@ -436,42 +460,55 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_cs42l43_l0_cs35l56_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2) | BIT(3), .links = arl_cs42l43_l0_cs35l56_2_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2) | BIT(3), .links = arl_cs42l43_l0_cs35l56_3_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2), .links = arl_cs42l43_l0_cs35l56_l2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = arl_cs42l43_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(2) | BIT(3), + .links = arl_cs42l43_l2_cs35l56_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(2), .links = arl_cs42l43_l2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(2) | BIT(3), - .links = arl_cs42l43_l2_cs35l56_l3, + .link_mask = BIT(0) | BIT(3), + .links = arl_rt711_l0_rt1316_l3, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg", + .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg", }, { .link_mask = 0x1, /* link0 required */ @@ -490,6 +527,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_rt722_l0_rt1320_l2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index e04f6de746eb..937a74a5d523 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -8,6 +8,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include "sof-function-topology-lib.h" #include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" @@ -136,7 +137,7 @@ static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = { }, }; -static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = { +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { /* Jack Endpoint */ { .num = 0, @@ -349,8 +350,8 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { { .adr = 0x000230025D071201ull, - .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), - .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, .name_prefix = "rt712" } }; @@ -418,6 +419,15 @@ static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = { + { + .adr = 0x000231025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-2" + } +}; + static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = { { .adr = 0x000130025D132001ull, @@ -608,6 +618,25 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_sdw_rt1320_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group2_adr), + .adr_d = rt1320_2_group2_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = { { .mask = BIT(0), @@ -712,6 +741,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_cs42l43_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -730,6 +760,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), @@ -738,6 +769,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg" }, { + .link_mask = GENMASK(2, 0), + .links = lnl_sdw_rt1320_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg" + }, + { .link_mask = BIT(0) | BIT(1), .links = lnl_sdw_rt713_l0_rt1318_l1, .drv_name = "sof_sdw", @@ -748,14 +785,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_sdw_rt712_vb_l2_rt1320_l1, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg" + .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(1) | BIT(2) | BIT(3), .links = lnl_sdw_rt713_vb_l2_rt1320_l13, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg" + .sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 9e611e3667ad..1270ee21ee72 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -11,6 +11,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-ssp-common.h> +#include "sof-function-topology-lib.h" #include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" @@ -698,6 +699,69 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_fb_adr[] = { }, }; +static const struct snd_soc_acpi_adr_device cs35l56_6amp_1_fb_adr[] = { + { + .adr = 0x00013701FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP6" + }, + { + .adr = 0x00013601FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP5" + }, + { + .adr = 0x00013501FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP4" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_6amp_3_fb_adr[] = { + { + .adr = 0x00033001FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033201FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints), + .endpoints = cs35l56_2_fb_endpoints, + .name_prefix = "AMP3" + }, + { + .adr = 0x00033401FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints), + .endpoints = cs35l56_4_fb_endpoints, + .name_prefix = "AMP5" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_6amp_2_fb_adr[] = { + { + .adr = 0x00023101FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP2" + }, + { + .adr = 0x00023301FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP4" + }, + { + .adr = 0x00023501FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP6" + }, +}; + static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { { .adr = 0x00023201FA355601ull, @@ -729,6 +793,24 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs35l63_1_fb_adr[] = { + { + .adr = 0x00013001FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_3_fb_adr[] = { + { + .adr = 0x00033101FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP2" + }, +}; + static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = { /* Expected order: jack -> amp */ { @@ -929,6 +1011,30 @@ static const struct snd_soc_acpi_adr_device cs42l42_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device tas2783_0_adr[] = { + { + .adr = 0x0000380102000001ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "tas2783-1" + }, + { + .adr = 0x0000390102000001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "tas2783-2" + } +}; + +static const struct snd_soc_acpi_link_adr tas2783_link0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(tas2783_0_adr), + .adr_d = tas2783_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr cs42l42_link0_max98363_link2[] = { /* Expected order: jack -> amp */ { @@ -1026,6 +1132,49 @@ static const struct snd_soc_acpi_link_adr mtl_cs35l56_x8_link0_link1_fb[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_cs35l56_x6_link0_link1_fb[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_6amp_1_fb_adr), + .adr_d = cs35l56_6amp_1_fb_adr, + }, + { + .mask = BIT(0), + /* First 3 amps in cs35l56_0_fb_adr */ + .num_adr = 3, + .adr_d = cs35l56_0_fb_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_cs35l63_x6_link2_link3_fb[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l63_6amp_3_fb_adr), + .adr_d = cs35l63_6amp_3_fb_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l63_6amp_2_fb_adr), + .adr_d = cs35l63_6amp_2_fb_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_cs35l63_x2_link1_link3_fb[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l63_3_fb_adr), + .adr_d = cs35l63_3_fb_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l63_1_fb_adr), + .adr_d = cs35l63_1_fb_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { /* mockup tests need to be first */ @@ -1048,6 +1197,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = BIT(0), + .links = tas2783_link0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-tas2783.tplg", + }, + { .link_mask = GENMASK(3, 0), .links = mtl_rt713_l0_rt1316_l12_rt1713_l3, .drv_name = "sof_sdw", @@ -1083,12 +1238,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = mtl_712_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), @@ -1101,30 +1258,53 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = cs42l43_link0_cs35l56_link2_link3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(1) | BIT(3), .links = cs42l43_link3_cs35l56_x4_link0_link1_spkagg, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l3-cs35l56-l01-spkagg.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), .links = mtl_cs42l43_cs35l56, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l12.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(1), .links = mtl_cs35l56_x8_link0_link1_fb, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg" + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(1), + .links = mtl_cs35l56_x6_link0_link1_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb6.tplg" }, { .link_mask = BIT(0), .links = mtl_cs42l43_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(3), + .links = mtl_cs35l63_x2_link1_link3_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg", + }, + { + .link_mask = BIT(2) | BIT(3), + .links = mtl_cs35l63_x6_link2_link3_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb6.tplg", }, { .link_mask = GENMASK(3, 0), @@ -1143,6 +1323,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = mtl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt722-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c new file mode 100644 index 000000000000..b8695d47e55b --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-nvl-match.c - tables and support for NVL ACPI enumeration. + * + * Copyright (c) 2025, Intel Corporation. + * + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include "soc-acpi-intel-sdw-mockup-match.h" + +struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_machines); + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_sdw_machines[] = { + /* mockup tests need to be first */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-nvl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-nvl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-nvl-rt715-rt711-rt1308-mono.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_nvl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index c599eb43eeb1..060955825fe0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -4,10 +4,14 @@ * * Copyright (c) 2024, Intel Corporation. * + * Order of entries in snd_soc_acpi_intel_ptl_sdw_machines[] matters. + * Check subset of link mask when matching the machine driver, rule is + * superset match should be ordered before subset matches. */ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include "sof-function-topology-lib.h" #include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" #include <sound/soc-acpi-intel-ssp-common.h> @@ -17,14 +21,52 @@ static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = { .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; +static const struct snd_soc_acpi_codecs ptl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + +static const struct snd_soc_acpi_codecs ptl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { { .comp_ids = &ptl_rt5682_rt5682s_hp, + .drv_name = "ptl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &ptl_lt6911_hdmi, + .sof_tplg_filename = "sof-ptl-rt5682-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &ptl_rt5682_rt5682s_hp, .drv_name = "ptl_rt5682_def", .sof_tplg_filename = "sof-ptl", /* the tplg suffix is added at run time */ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, + { + .comp_ids = &ptl_essx_83x6, + .drv_name = "ptl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &ptl_lt6911_hdmi, + .sof_tplg_filename = "sof-ptl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &ptl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-ptl-es8336", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, + /* place amp-only boards in the end of table */ + { + .id = "INTC10B0", + .drv_name = "ptl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-ptl-hdmi-ssp02.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); @@ -134,7 +176,7 @@ static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = { }, }; -static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = { +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { /* Jack Endpoint */ { .num = 0, @@ -185,33 +227,6 @@ static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = { }, }; -static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { - { /* Jack Playback Endpoint */ - .num = 0, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, - { /* DMIC Capture Endpoint */ - .num = 1, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, - { /* Jack Capture Endpoint */ - .num = 2, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, - { /* Speaker Playback Endpoint */ - .num = 3, - .aggregated = 0, - .group_position = 0, - .group_id = 0, - }, -}; - static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { { .adr = 0x00023001fa424301ull, @@ -221,6 +236,30 @@ static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs42l43_3_agg_adr[] = { + { + .adr = 0x00033001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints), + .endpoints = cs42l43_amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = { + { + .adr = 0x00023001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00023101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = { { .adr = 0x00013001fa355601ull, @@ -263,15 +302,6 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = { } }; -static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = { - { - .adr = 0x00033001FA424301ull, - .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), - .endpoints = cs42l43_endpoints, - .name_prefix = "cs42l43" - } -}; - static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -284,8 +314,8 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { { .adr = 0x000230025D071201ull, - .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), - .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, .name_prefix = "rt712" } }; @@ -293,8 +323,8 @@ static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { static const struct snd_soc_acpi_adr_device rt712_vb_3_group1_adr[] = { { .adr = 0x000330025D071201ull, - .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), - .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, .name_prefix = "rt712" } }; @@ -317,6 +347,24 @@ static const struct snd_soc_acpi_adr_device rt713_vb_3_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_3_group1_adr[] = { + { + .adr = 0x000330025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt721_0_single_adr[] = { + { + .adr = 0x000030025d072101ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt721" + } +}; + static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { { .adr = 0x000330025d072101ull, @@ -398,6 +446,15 @@ static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_2_group2_l_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { { .adr = 0x000330025D132001ull, @@ -407,6 +464,20 @@ static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { } }; +static const struct snd_soc_acpi_link_adr ptl_cs42l43_agg_l3_cs35l56_l2[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs42l43_3_agg_adr), + .adr_d = cs42l43_3_agg_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_lr_adr), + .adr_d = cs35l56_2_lr_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = { { .mask = BIT(2), @@ -426,11 +497,11 @@ static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = { {} }; -static const struct snd_soc_acpi_link_adr ptl_cs42l43_l3[] = { +static const struct snd_soc_acpi_link_adr ptl_rt721_l0[] = { { - .mask = BIT(3), - .num_adr = ARRAY_SIZE(cs42l43_3_adr), - .adr_d = cs42l43_3_adr, + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt721_0_single_adr), + .adr_d = rt721_0_single_adr, }, {} }; @@ -462,6 +533,25 @@ static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_rt722_l0_rt1320_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group2_l_adr), + .adr_d = rt1320_2_group2_l_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1320_3_group2_adr), + .adr_d = rt1320_3_group2_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_rvp[] = { { .mask = BIT(0), @@ -537,9 +627,23 @@ static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l2[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr), + .adr_d = rt712_vb_3_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1320_3_group1_adr), + .adr_d = rt1320_3_group1_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { - /* mockup tests need to be first */ +/* Order Priority: mockup > most links > most bit link-mask > alphabetical */ { .link_mask = GENMASK(3, 0), .links = sdw_mockup_headset_2amps_mic, @@ -559,80 +663,110 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = BIT(0), + .links = sdw_mockup_multi_func, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", /* Reuse the existing tplg file */ + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_sdw_rt713_vb_l2_rt1320_l13, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_sdw_rt713_vb_l3_rt1320_l12, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l12.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { .link_mask = BIT(1) | BIT(2) | BIT(3), .links = ptl_cs42l43_l2_cs35l56x6_l13, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-cs42l43-l2-cs35l56x6-l13.tplg", }, { - .link_mask = BIT(0), - .links = sdw_mockup_multi_func, + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = ptl_rt722_l0_rt1320_l23, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt722.tplg", /* Reuse the existing tplg file */ + .sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(0), - .links = ptl_rvp, + .link_mask = BIT(1) | BIT(2), + .links = ptl_sdw_rt712_vb_l2_rt1320_l1, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt711.tplg", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(3), - .links = ptl_cs42l43_l3, + .link_mask = BIT(2) | BIT(3), + .links = ptl_sdw_rt712_vb_l3_rt1320_l2, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-cs42l43-l3.tplg", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(3), - .links = ptl_rt721_l3, + .link_mask = BIT(2) | BIT(3), + .links = ptl_cs42l43_agg_l3_cs35l56_l2, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt721.tplg", + .sof_tplg_filename = "sof-ptl-cs42l43-agg-l3-cs35l56-l2.tplg", }, { .link_mask = BIT(0), - .links = ptl_rt722_only, + .links = ptl_rvp, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt722.tplg", + .sof_tplg_filename = "sof-ptl-rt711.tplg", }, { - .link_mask = BIT(1), - .links = ptl_rt722_l1, + .link_mask = BIT(0), + .links = ptl_rt721_l0, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt722.tplg", + .sof_tplg_filename = "sof-ptl-rt721.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(3), - .links = ptl_rt722_l3, + .link_mask = BIT(0), + .links = ptl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(1) | BIT(2), - .links = ptl_sdw_rt712_vb_l2_rt1320_l1, + .link_mask = BIT(1), + .links = ptl_rt722_l1, .drv_name = "sof_sdw", - .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg" + .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(2) | BIT(3), - .links = ptl_sdw_rt712_vb_l3_rt1320_l2, + .link_mask = BIT(3), + .links = ptl_sdw_rt712_vb_l3_rt1320_l3, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l2.tplg" + .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(1) | BIT(2) | BIT(3), - .links = ptl_sdw_rt713_vb_l2_rt1320_l13, + .link_mask = BIT(3), + .links = ptl_rt721_l3, .drv_name = "sof_sdw", - .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg" + .sof_tplg_filename = "sof-ptl-rt721.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { - .link_mask = BIT(1) | BIT(2) | BIT(3), - .links = ptl_sdw_rt713_vb_l3_rt1320_l12, + .link_mask = BIT(3), + .links = ptl_rt722_l3, .drv_name = "sof_sdw", - .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, - .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l12.tplg" + .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c new file mode 100644 index 000000000000..0daa7d83808b --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -0,0 +1,143 @@ +// 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) 2025 Intel Corporation. +// + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/firmware.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "sof-function-topology-lib.h" + +enum tplg_device_id { + TPLG_DEVICE_SDCA_JACK, + TPLG_DEVICE_SDCA_AMP, + TPLG_DEVICE_SDCA_MIC, + TPLG_DEVICE_INTEL_PCH_DMIC, + TPLG_DEVICE_HDMI, + TPLG_DEVICE_MAX +}; + +#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ + BIT(TPLG_DEVICE_SDCA_MIC)) + +#define SOF_INTEL_PLATFORM_NAME_MAX 4 + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files, bool best_effort) +{ + struct snd_soc_acpi_mach_params mach_params = mach->mach_params; + struct snd_soc_dai_link *dai_link; + const struct firmware *fw; + char platform[SOF_INTEL_PLATFORM_NAME_MAX]; + unsigned long tplg_mask = 0; + int tplg_num = 0; + int tplg_dev; + int ret; + int i; + + ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); + if (ret != 1) { + dev_err(card->dev, "Invalid platform name %s of tplg %s\n", + platform, mach->sof_tplg_filename); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + char *tplg_dev_name; + + dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id); + if (strstr(dai_link->name, "SimpleJack")) { + tplg_dev = TPLG_DEVICE_SDCA_JACK; + tplg_dev_name = "sdca-jack"; + } else if (strstr(dai_link->name, "SmartAmp")) { + tplg_dev = TPLG_DEVICE_SDCA_AMP; + tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, + "sdca-%damp", dai_link->num_cpus); + if (!tplg_dev_name) + return -ENOMEM; + } else if (strstr(dai_link->name, "SmartMic")) { + tplg_dev = TPLG_DEVICE_SDCA_MIC; + tplg_dev_name = "sdca-mic"; + } else if (strstr(dai_link->name, "dmic")) { + switch (mach_params.dmic_num) { + case 2: + tplg_dev_name = "dmic-2ch"; + break; + case 4: + tplg_dev_name = "dmic-4ch"; + break; + default: + dev_warn(card->dev, + "unsupported number of dmics: %d\n", + mach_params.dmic_num); + continue; + } + tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; + } else if (strstr(dai_link->name, "iDisp")) { + tplg_dev = TPLG_DEVICE_HDMI; + tplg_dev_name = "hdmi-pcm5"; + + } else { + /* The dai link is not supported by separated tplg yet */ + dev_dbg(card->dev, + "dai_link %s is not supported by separated tplg yet\n", + dai_link->name); + if (best_effort) + continue; + + return 0; + } + if (tplg_mask & BIT(tplg_dev)) + continue; + + tplg_mask |= BIT(tplg_dev); + + /* + * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg + * where <platform> is only required for the DMIC function as the nhlt blob + * is platform dependent. + */ + switch (tplg_dev) { + case TPLG_DEVICE_INTEL_PCH_DMIC: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-%s-id%d.tplg", + prefix, platform, + tplg_dev_name, dai_link->id); + break; + default: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-id%d.tplg", + prefix, tplg_dev_name, + dai_link->id); + break; + } + if (!(*tplg_files)[tplg_num]) + return -ENOMEM; + tplg_num++; + } + + dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); + + /* Check presence of sub-topologies */ + for (i = 0; i < tplg_num; i++) { + ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev); + if (!ret) { + release_firmware(fw); + } else { + dev_warn(card->dev, + "Failed to open topology file: %s, you might need to\n", + (*tplg_files)[i]); + dev_warn(card->dev, + "download it from https://github.com/thesofproject/sof-bin/\n"); + return 0; + } + } + + return tplg_num; +} +EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h new file mode 100644 index 000000000000..f358f8c52d78 --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-get-tplg.h - get-tplg-files ops + * + * Copyright (c) 2025, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_GET_TPLG_H +#define _SND_SOC_ACPI_INTEL_GET_TPLG_H + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files, bool best_effort); + +#endif |
