diff options
55 files changed, 1018 insertions, 199 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml index 8c22e8348b14..d1ac84e518a0 100644 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -28,6 +28,9 @@ properties: - fsl,imx95-aonmix-mqs - fsl,imx95-netcmix-mqs + "#sound-dai-cells": + const: 0 + clocks: minItems: 1 maxItems: 2 @@ -55,6 +58,7 @@ required: - clock-names allOf: + - $ref: dai-common.yaml# - if: properties: compatible: @@ -86,7 +90,7 @@ allOf: required: - gpr -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/maxim,max98925.yaml b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml index 32fd86204a7a..121e8d2d44da 100644 --- a/Documentation/devicetree/bindings/sound/maxim,max98925.yaml +++ b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml @@ -77,11 +77,11 @@ additionalProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> i2c { #address-cells = <1>; #size-cells = <0>; - #include <dt-bindings/gpio/gpio.h> audio-codec@3a { compatible = "maxim,max98927"; reg = <0x3a>; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2e28182c3af0..981ed45cc45e 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3070,6 +3070,7 @@ #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 #define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 #define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff +#define PCI_DEVICE_ID_INTEL_HDA_FCL 0x67a8 #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 4c7a40e149a5..7de390022ac2 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -22,6 +22,7 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable); void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable); int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus); +struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id); struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr); struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, const char *codec_name); @@ -97,12 +98,17 @@ struct hdac_ext_link { void __iomem *ml_addr; /* link output stream reg pointer */ u32 lcaps; /* link capablities */ u16 lsdiid; /* link sdi identifier */ + u32 id; + u8 slcount; int ref_count; struct list_head list; }; +#define hdac_ext_link_alt(link) ((link)->lcaps & AZX_ML_HDA_LCAP_ALT) +#define hdac_ext_link_ofls(link) ((link)->lcaps & AZX_ML_HDA_LCAP_OFLS) + int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus); diff --git a/include/sound/soc.h b/include/sound/soc.h index 952ed77b8c87..484d8b3a34f3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -423,6 +423,7 @@ enum snd_soc_pcm_subclass { int snd_soc_register_card(struct snd_soc_card *card); void snd_soc_unregister_card(struct snd_soc_card *card); int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card); +int devm_snd_soc_register_deferrable_card(struct device *dev, struct snd_soc_card *card); #ifdef CONFIG_PM_SLEEP int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); @@ -1087,6 +1088,7 @@ struct snd_soc_card { unsigned int fully_routed:1; unsigned int probed:1; unsigned int component_chaining:1; + struct device *devres_dev; void *drvdata; }; diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 6199bb60ccf0..c84754434d16 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -9,6 +9,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/slab.h> #include <sound/hda_register.h> @@ -81,6 +82,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) int idx; u32 link_count; struct hdac_ext_link *hlink; + u32 leptr; link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; @@ -96,6 +98,12 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) (AZX_ML_INTERVAL * idx); hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); + hlink->slcount = FIELD_GET(AZX_ML_HDA_LCAP_SLCOUNT, hlink->lcaps) + 1; + + if (hdac_ext_link_alt(hlink)) { + leptr = readl(hlink->ml_addr + AZX_REG_ML_LEPTR); + hlink->id = FIELD_GET(AZX_REG_ML_LEPTR_ID, leptr); + } /* since link in On, update the ref */ hlink->ref_count = 1; @@ -125,6 +133,17 @@ void snd_hdac_ext_link_free_all(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all); +struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id) +{ + struct hdac_ext_link *hlink; + + list_for_each_entry(hlink, &bus->hlink_list, list) + if (hdac_ext_link_alt(hlink) && hlink->id == id) + return hlink; + return NULL; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_id); + /** * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address * @bus: hlink's parent bus device diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 5103e37be428..01594f858129 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -112,6 +112,10 @@ static const struct config_entry config_table[] = { .flags = FLAG_SST, .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, }, + { + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_FCL, + }, #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c index 21a44476f48d..6525d50b7ab2 100644 --- a/sound/soc/codecs/ak5386.c +++ b/sound/soc/codecs/ak5386.c @@ -6,11 +6,13 @@ * (c) 2013 Daniel Mack <zonque@gmail.com> */ +#include <linux/device.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regulator/consumer.h> +#include <linux/slab.h> #include <sound/soc.h> #include <sound/pcm.h> #include <sound/initval.h> @@ -20,7 +22,7 @@ static const char * const supply_names[] = { }; struct ak5386_priv { - int reset_gpio; + struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; }; @@ -110,8 +112,7 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream, * the AK5386 in power-down mode (PDN pin = āLā). */ - if (gpio_is_valid(priv->reset_gpio)) - gpio_set_value(priv->reset_gpio, 1); + gpiod_set_value(priv->reset_gpio, 1); return 0; } @@ -122,8 +123,7 @@ static int ak5386_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); - if (gpio_is_valid(priv->reset_gpio)) - gpio_set_value(priv->reset_gpio, 0); + gpiod_set_value(priv->reset_gpio, 0); return 0; } @@ -177,14 +177,12 @@ static int ak5386_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->reset_gpio = of_get_named_gpio(dev->of_node, - "reset-gpio", 0); + priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(priv->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), + "Failed to get AK5386 reset GPIO\n"); - if (gpio_is_valid(priv->reset_gpio)) - if (devm_gpio_request_one(dev, priv->reset_gpio, - GPIOF_OUT_INIT_LOW, - "AK5386 Reset")) - priv->reset_gpio = -EINVAL; + gpiod_set_consumer_name(priv->reset_gpio, "AK5386 Reset"); return devm_snd_soc_register_component(dev, &soc_component_ak5386, &ak5386_dai, 1); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 17019b1d680b..8bd125e18a7f 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -1010,6 +1010,7 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, .mute_stream = hdmi_codec_mute, .pcm_new = hdmi_codec_pcm_new, }; diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index b2bd2f172ae7..75af12231d1d 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -1642,8 +1642,7 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) } ret = pcmdev_profile_ctrl_add(pcm_dev); out: - if (fw_entry) - release_firmware(fw_entry); + release_firmware(fw_entry); mutex_unlock(&pcm_dev->codec_lock); return ret; diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index abe0a5a95770..885edcf0a3a5 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -365,8 +365,8 @@ static void rt5677_spi_copy_work(struct work_struct *work) new_bytes -= copy_bytes; } - delay = bytes_to_frames(runtime, period_bytes) / (runtime->rate / 1000); - schedule_delayed_work(&rt5677_dsp->copy_work, msecs_to_jiffies(delay)); + delay = bytes_to_frames(runtime, period_bytes) / runtime->rate; + schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay)); done: mutex_unlock(&rt5677_dsp->dma_lock); } diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index bd8848ea1ec2..24d4b643917d 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -983,8 +983,7 @@ static int sta32x_probe(struct snd_soc_component *component) err_regulator_bulk_disable: regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); err_clk_disable_unprepare: - if (sta32x->xti_clk) - clk_disable_unprepare(sta32x->xti_clk); + clk_disable_unprepare(sta32x->xti_clk); return ret; } @@ -995,8 +994,7 @@ static void sta32x_remove(struct snd_soc_component *component) sta32x_watchdog_stop(sta32x); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); - if (sta32x->xti_clk) - clk_disable_unprepare(sta32x->xti_clk); + clk_disable_unprepare(sta32x->xti_clk); } static const struct snd_soc_component_driver sta32x_component = { diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 13a197468193..684d23e5905e 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -2074,8 +2074,7 @@ int tas2781_load_calibration(void *context, char *file_name, } out: - if (fw_entry) - release_firmware(fw_entry); + release_firmware(fw_entry); return ret; } diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index b950914b7d48..8d8a84a53766 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -1505,8 +1505,7 @@ out: tasdevice_dsp_remove(tas_priv); } mutex_unlock(&tas_priv->codec_lock); - if (fmw) - release_firmware(fmw); + release_firmware(fmw); } static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 91c8697c29c3..ffd826f30e15 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -718,12 +718,10 @@ static void wm_adsp_release_firmware_files(struct wm_adsp *dsp, const struct firmware *coeff_firmware, char *coeff_filename) { - if (wmfw_firmware) - release_firmware(wmfw_firmware); + release_firmware(wmfw_firmware); kfree(wmfw_filename); - if (coeff_firmware) - release_firmware(coeff_firmware); + release_firmware(coeff_firmware); kfree(coeff_filename); } 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/avs.h b/sound/soc/intel/avs/avs.h index 585543f872fc..4c096afc5848 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -69,9 +69,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 +82,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 +93,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 +268,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, @@ -340,7 +349,7 @@ 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_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, diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 286d94df5f46..6f6137c3a02c 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -23,6 +23,10 @@ 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[] = { { .matches = { @@ -142,7 +146,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", }, { @@ -203,7 +207,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", }, { @@ -349,7 +355,8 @@ 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) @@ -400,6 +407,7 @@ static int avs_register_dmic_board(struct avs_dev *adev) { struct platform_device *codec, *board; struct snd_soc_acpi_mach mach = {{0}}; + struct avs_mach_pdata *pdata; int ret; if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) { @@ -423,6 +431,11 @@ static int avs_register_dmic_board(struct avs_dev *adev) if (ret < 0) return ret; + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + mach.pdata = pdata; mach.tplg_filename = "dmic-tplg.bin"; mach.mach_params.platform = "dmic-platform"; @@ -445,6 +458,7 @@ static int avs_register_dmic_board(struct avs_dev *adev) static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) { struct platform_device *board; + struct avs_mach_pdata *pdata; int num_ssps; char *name; int ret; @@ -466,7 +480,15 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach if (!name) return -ENOMEM; - ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata); + pdata = mach->pdata; + if (!pdata) + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + mach->pdata = pdata; + + ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms); if (ret < 0) return ret; @@ -590,6 +612,7 @@ 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 avs_mach_pdata *pdata; struct hdac_device *hdev = &codec->core; char *pname; int ret, id; @@ -598,11 +621,17 @@ static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) if (!pname) return -ENOMEM; + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + pdata->codec = codec; + ret = avs_hda_platform_register(adev, pname); if (ret < 0) return ret; - mach.pdata = codec; + mach.pdata = pdata; mach.mach_params.platform = pname; mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin", hdev->vendor_id); diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index ba4bee42124c..8b654181004e 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 diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 7217ae51e89c..3ef0db254142 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -214,6 +214,7 @@ 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; @@ -222,6 +223,7 @@ static int avs_da7219_probe(struct platform_device *pdev) 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) @@ -238,7 +240,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; @@ -256,7 +263,7 @@ static int avs_da7219_probe(struct platform_device *pdev) 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..a1448a98874d 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -10,6 +10,7 @@ #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"))); @@ -49,17 +50,24 @@ static const struct snd_soc_dapm_route card_routes[] = { static int avs_dmic_probe(struct platform_device *pdev) { 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"; + 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; @@ -74,7 +82,7 @@ static int avs_dmic_probe(struct platform_device *pdev) 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..1955f2d383c5 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -259,6 +259,7 @@ 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; @@ -267,6 +268,7 @@ static int avs_es8336_probe(struct platform_device *pdev) 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) @@ -283,7 +285,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; @@ -303,7 +310,7 @@ static int avs_es8336_probe(struct platform_device *pdev) 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..19b2255a8ac3 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -13,6 +13,7 @@ #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) @@ -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,7 +134,8 @@ 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; @@ -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)) @@ -200,7 +206,16 @@ 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 = binder->codecs->name; + } 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 +224,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..f7b6d7715738 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -56,6 +56,7 @@ 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; @@ -63,6 +64,7 @@ static int avs_i2s_test_probe(struct platform_device *pdev) 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,8 +82,15 @@ 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; @@ -101,7 +110,7 @@ static int avs_i2s_test_probe(struct platform_device *pdev) 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..72053f83e98b 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -93,6 +93,7 @@ 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; @@ -100,6 +101,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) 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) @@ -115,7 +117,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; @@ -132,7 +139,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) 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..cdba1c3ee20b 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -146,6 +146,7 @@ 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; @@ -153,6 +154,7 @@ static int avs_max98373_probe(struct platform_device *pdev) 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) @@ -168,7 +170,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; @@ -187,7 +194,7 @@ static int avs_max98373_probe(struct platform_device *pdev) 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..a68e227044c5 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -143,6 +143,7 @@ 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; @@ -150,6 +151,7 @@ static int avs_max98927_probe(struct platform_device *pdev) 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) @@ -165,7 +167,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; @@ -184,7 +191,7 @@ static int avs_max98927_probe(struct platform_device *pdev) 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..3fb1a5d07ae1 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -246,6 +246,7 @@ 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; @@ -254,6 +255,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) 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) @@ -270,7 +272,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; @@ -290,7 +297,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) 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..06c1f19f27aa 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -36,7 +36,8 @@ static int avs_probe_mb_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_probe_mb"; + 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; @@ -47,7 +48,7 @@ static int avs_probe_mb_probe(struct platform_device *pdev) 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..ec5382925157 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -210,6 +210,7 @@ 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; @@ -218,6 +219,7 @@ static int avs_rt274_probe(struct platform_device *pdev) 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) @@ -234,7 +236,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; @@ -254,7 +261,7 @@ static int avs_rt274_probe(struct platform_device *pdev) 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..2566e971ce1c 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -179,6 +179,7 @@ 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; @@ -187,6 +188,7 @@ static int avs_rt286_probe(struct platform_device *pdev) 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) @@ -204,7 +206,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; @@ -224,7 +231,7 @@ static int avs_rt286_probe(struct platform_device *pdev) 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..7be34c8ad167 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -199,6 +199,7 @@ 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; @@ -207,6 +208,7 @@ static int avs_rt298_probe(struct platform_device *pdev) 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) @@ -223,7 +225,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; @@ -243,7 +250,7 @@ static int avs_rt298_probe(struct platform_device *pdev) 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..45f091f2ce22 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -133,6 +133,7 @@ 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; @@ -140,6 +141,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) 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) @@ -155,7 +157,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; @@ -170,7 +177,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) 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/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index e3310b3268ba..122b6c48fd80 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -198,6 +198,7 @@ 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; @@ -206,6 +207,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) 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) @@ -222,7 +224,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 ALC5640"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -242,7 +249,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) 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..9677b9ebeff1 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -268,6 +268,7 @@ 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; @@ -282,6 +283,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) 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) @@ -298,7 +300,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; @@ -318,7 +325,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) 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..3786eef8c494 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -132,6 +132,7 @@ 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; @@ -139,6 +140,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) 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) @@ -154,7 +156,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; @@ -173,7 +180,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) 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/core.c b/sound/soc/intel/avs/core.c index 8fbf33e30dfc..a7aa3a6cde9e 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -54,14 +54,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 +74,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 +104,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 +120,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; } @@ -748,13 +755,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 +776,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 +800,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 +832,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 +882,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 +927,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); @@ -912,3 +959,4 @@ 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/fcl/dsp_basefw.bin"); 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/lnl.c b/sound/soc/intel/avs/lnl.c new file mode 100644 index 000000000000..03208596dfb1 --- /dev/null +++ b/sound/soc/intel/avs/lnl.c @@ -0,0 +1,27 @@ +// 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 "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..138e4e9de5e3 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -310,7 +310,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 +683,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 +694,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 e27c7587be9d..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, @@ -787,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; diff --git a/sound/soc/intel/avs/mtl.c b/sound/soc/intel/avs/mtl.c new file mode 100644 index 000000000000..e7b7915b2a82 --- /dev/null +++ b/sound/soc/intel/avs/mtl.c @@ -0,0 +1,200 @@ +// 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 "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 d5cce357b162..6ec60c9d5667 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -210,8 +210,51 @@ 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; @@ -228,7 +271,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) @@ -245,7 +288,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; @@ -279,7 +322,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; diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 9dd5215b2c72..af4e6fbadb01 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 { @@ -32,6 +33,7 @@ struct avs_dma_data { }; struct work_struct period_elapsed_work; + struct hdac_ext_link *link; struct snd_pcm_substream *substream; }; @@ -278,32 +280,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); @@ -313,6 +358,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) { @@ -328,13 +381,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) @@ -346,27 +394,19 @@ 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; const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; struct avs_dma_data *data; - struct hda_codec *codec; - struct hdac_bus *bus; unsigned int format_val; unsigned int bits; int ret; @@ -377,23 +417,18 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn 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, stream_info->sig_bits); format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); - 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) @@ -468,6 +503,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); @@ -1266,7 +1319,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, @@ -1281,7 +1334,7 @@ static const struct snd_soc_component_driver avs_component_driver = { }; int avs_soc_component_register(struct device *dev, const char *name, - const struct snd_soc_component_driver *drv, + struct snd_soc_component_driver *drv, struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) { struct avs_soc_component *acomp; @@ -1299,13 +1352,14 @@ int avs_soc_component_register(struct device *dev, const char *name, acomp->base.name = name; INIT_LIST_HEAD(&acomp->node); + drv->use_dai_pcm_id = !obsolete_card_names; + 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, @@ -1316,7 +1370,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, @@ -1329,12 +1382,20 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { int avs_dmic_platform_register(struct avs_dev *adev, const char *name) { + 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_soc_component_register(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 = AVS_CHANNELS_MAX, @@ -1367,10 +1428,15 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l 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) @@ -1398,6 +1464,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++; } } @@ -1418,6 +1485,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++; } } @@ -1480,6 +1548,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; @@ -1489,7 +1558,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) @@ -1623,7 +1693,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, diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index f0b010956303..a42736b9aa55 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -284,7 +284,7 @@ static struct snd_soc_dai_driver probe_cpu_dais[] = { }, }; -static const struct snd_soc_component_driver avs_probe_component_driver = { +static struct snd_soc_component_driver avs_probe_component_driver = { .name = "avs-probe-compr", .compress_ops = &avs_probe_compress_ops, .module_get_upon_open = 1, /* increment refcount when a stream is opened */ diff --git a/sound/soc/intel/avs/ptl.c b/sound/soc/intel/avs/ptl.c new file mode 100644 index 000000000000..2be4b545c91d --- /dev/null +++ b/sound/soc/intel/avs/ptl.c @@ -0,0 +1,98 @@ +// 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 "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/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..2df7afa2f469 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -252,14 +252,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/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c index d2d0e5d8cac9..1ea5501a97f8 100644 --- a/sound/soc/loongson/loongson_i2s_pci.c +++ b/sound/soc/loongson/loongson_i2s_pci.c @@ -16,6 +16,8 @@ #include "loongson_i2s.h" #include "loongson_dma.h" +#define DRIVER_NAME "loongson-i2s-pci" + static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -92,13 +94,12 @@ static int loongson_i2s_pci_probe(struct pci_dev *pdev, i2s->dev = dev; pci_set_drvdata(pdev, i2s); - ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(dev)); - if (ret < 0) { - dev_err(dev, "iomap_regions failed\n"); - return ret; + i2s->reg_base = pcim_iomap_region(pdev, 0, DRIVER_NAME); + if (IS_ERR(i2s->reg_base)) { + dev_err(dev, "iomap_region failed\n"); + return PTR_ERR(i2s->reg_base); } - i2s->reg_base = pcim_iomap_table(pdev)[0]; i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base, &loongson_i2s_regmap_config); if (IS_ERR(i2s->regmap)) @@ -147,7 +148,7 @@ static const struct pci_device_id loongson_i2s_ids[] = { MODULE_DEVICE_TABLE(pci, loongson_i2s_ids); static struct pci_driver loongson_i2s_driver = { - .name = "loongson-i2s-pci", + .name = DRIVER_NAME, .id_table = loongson_i2s_ids, .probe = loongson_i2s_pci_probe, .driver = { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3f97d1f132c6..ab615ec113d2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2134,18 +2134,13 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) } } -static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) +static void snd_soc_unbind_card(struct snd_soc_card *card) { if (snd_soc_card_is_instantiated(card)) { card->instantiated = false; snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); - if (!unregister) - list_add(&card->list, &unbind_card_list); - } else { - if (unregister) - list_del(&card->list); } } @@ -2155,9 +2150,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) struct snd_soc_component *component; int ret; - mutex_lock(&client_mutex); snd_soc_card_mutex_lock_root(card); - snd_soc_fill_dummy_dai(card); snd_soc_dapm_init(&card->dapm, card, NULL); @@ -2304,9 +2297,49 @@ static int snd_soc_bind_card(struct snd_soc_card *card) probe_end: if (ret < 0) soc_cleanup_card_resources(card); - snd_soc_card_mutex_unlock(card); - mutex_unlock(&client_mutex); + + return ret; +} + +static void devm_card_bind_release(struct device *dev, void *res) +{ + snd_soc_unregister_card(*(struct snd_soc_card **)res); +} + +static int devm_snd_soc_bind_card(struct device *dev, struct snd_soc_card *card) +{ + struct snd_soc_card **ptr; + int ret; + + ptr = devres_alloc(devm_card_bind_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_soc_bind_card(card); + if (ret == 0 || ret == -EPROBE_DEFER) { + *ptr = card; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} + +static int snd_soc_rebind_card(struct snd_soc_card *card) +{ + int ret; + + if (card->devres_dev) { + devres_destroy(card->devres_dev, devm_card_bind_release, NULL, NULL); + ret = devm_snd_soc_bind_card(card->devres_dev, card); + } else { + ret = snd_soc_bind_card(card); + } + + if (ret != -EPROBE_DEFER) + list_del_init(&card->list); return ret; } @@ -2506,6 +2539,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); */ int snd_soc_register_card(struct snd_soc_card *card) { + int ret; + if (!card->name || !card->dev) return -EINVAL; @@ -2526,7 +2561,21 @@ int snd_soc_register_card(struct snd_soc_card *card) mutex_init(&card->dapm_mutex); mutex_init(&card->pcm_mutex); - return snd_soc_bind_card(card); + mutex_lock(&client_mutex); + + if (card->devres_dev) { + ret = devm_snd_soc_bind_card(card->devres_dev, card); + if (ret == -EPROBE_DEFER) { + list_add(&card->list, &unbind_card_list); + ret = 0; + } + } else { + ret = snd_soc_bind_card(card); + } + + mutex_unlock(&client_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_register_card); @@ -2539,7 +2588,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); void snd_soc_unregister_card(struct snd_soc_card *card) { mutex_lock(&client_mutex); - snd_soc_unbind_card(card, true); + snd_soc_unbind_card(card); + list_del(&card->list); mutex_unlock(&client_mutex); dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); } @@ -2753,23 +2803,19 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) stream->formats |= endianness_format_map[i]; } -static void snd_soc_try_rebind_card(void) -{ - struct snd_soc_card *card, *c; - - list_for_each_entry_safe(card, c, &unbind_card_list, list) - if (!snd_soc_bind_card(card)) - list_del(&card->list); -} - static void snd_soc_del_component_unlocked(struct snd_soc_component *component) { struct snd_soc_card *card = component->card; + bool instantiated; snd_soc_unregister_dais(component); - if (card) - snd_soc_unbind_card(card, false); + if (card) { + instantiated = card->instantiated; + snd_soc_unbind_card(card); + if (instantiated) + list_add(&card->list, &unbind_card_list); + } list_del(&component->list); } @@ -2808,6 +2854,7 @@ int snd_soc_add_component(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, int num_dai) { + struct snd_soc_card *card, *c; int ret; int i; @@ -2838,15 +2885,14 @@ int snd_soc_add_component(struct snd_soc_component *component, /* see for_each_component */ list_add(&component->list, &component_list); + list_for_each_entry_safe(card, c, &unbind_card_list, list) + snd_soc_rebind_card(card); + err_cleanup: if (ret < 0) snd_soc_del_component_unlocked(component); mutex_unlock(&client_mutex); - - if (ret == 0) - snd_soc_try_rebind_card(); - return ret; } EXPORT_SYMBOL_GPL(snd_soc_add_component); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index c6364caabc0e..d33f83ec24f2 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -83,6 +83,13 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) } EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); +int devm_snd_soc_register_deferrable_card(struct device *dev, struct snd_soc_card *card) +{ + card->devres_dev = dev; + return snd_soc_register_card(card); +} +EXPORT_SYMBOL_GPL(devm_snd_soc_register_deferrable_card); + #ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM static void devm_dmaengine_pcm_release(struct device *dev, void *res) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 504a14584765..fa821e3fb427 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -169,20 +169,14 @@ static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) struct device *dev = &sai->pdev->dev; sai->clk_x8k = devm_clk_get(dev, "x8k"); - if (IS_ERR(sai->clk_x8k)) { - if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) - dev_err(dev, "missing x8k parent clock: %ld\n", - PTR_ERR(sai->clk_x8k)); - return PTR_ERR(sai->clk_x8k); - } + if (IS_ERR(sai->clk_x8k)) + return dev_err_probe(dev, PTR_ERR(sai->clk_x8k), + "missing x8k parent clock\n"); sai->clk_x11k = devm_clk_get(dev, "x11k"); - if (IS_ERR(sai->clk_x11k)) { - if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) - dev_err(dev, "missing x11k parent clock: %ld\n", - PTR_ERR(sai->clk_x11k)); - return PTR_ERR(sai->clk_x11k); - } + if (IS_ERR(sai->clk_x11k)) + return dev_err_probe(dev, PTR_ERR(sai->clk_x11k), + "missing x11k parent clock\n"); return 0; } diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 8b9eb1a202f7..7b3496caa31e 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -248,12 +248,10 @@ static int sun8i_codec_runtime_resume(struct device *dev) struct sun8i_codec *scodec = dev_get_drvdata(dev); int ret; - if (scodec->clk_bus) { - ret = clk_prepare_enable(scodec->clk_bus); - if (ret) { - dev_err(dev, "Failed to enable the bus clock\n"); - return ret; - } + ret = clk_prepare_enable(scodec->clk_bus); + if (ret) { + dev_err(dev, "Failed to enable the bus clock\n"); + return ret; } regcache_cache_only(scodec->regmap, false); @@ -274,8 +272,7 @@ static int sun8i_codec_runtime_suspend(struct device *dev) regcache_cache_only(scodec->regmap, true); regcache_mark_dirty(scodec->regmap); - if (scodec->clk_bus) - clk_disable_unprepare(scodec->clk_bus); + clk_disable_unprepare(scodec->clk_bus); return 0; } |