summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2025-12-02 07:12:56 +0100
committerTakashi Iwai <tiwai@suse.de>2025-12-02 07:12:56 +0100
commit9747b22a417d2a7c478678143863b9777de104e4 (patch)
tree2690242ac1e95570c3e56a3106752af4cc2b5472 /sound/soc/sof/intel
parentef5e0a02d842b2c6dfcfd9b80feb185769b892ef (diff)
parentc5fae31f60a91dbe884ef2789fb3440bb4cddf05 (diff)
downloadlwn-9747b22a417d2a7c478678143863b9777de104e4.tar.gz
lwn-9747b22a417d2a7c478678143863b9777de104e4.zip
Merge tag 'asoc-v6.19' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.19 This is a very large set of updates, as well as some more extensive cleanup work from Morimto-san we've also added a generic SCDA class driver for SoundWire devices enabling us to support many chips with no custom code. There's also a batch of new drivers added for both SoCs and CODECs. - Added a SoundWire SCDA generic class driver, pulling in a little regmap work to support it. - A *lot* of cleaup and API improvement work from Morimoto-san. - Lots of work on the existing Cirrus, Intel, Maxim and Qualcomm drivers. - Support for Allwinner A523, Mediatek MT8189, Qualcomm QCM2290, QRB2210 and SM6115, SpacemiT K1, and TI TAS2568, TAS5802, TAS5806, TAS5815, TAS5828 and TAS5830. This also pulls in some gpiolib changes supporting shared GPIOs in the core there so we can convert some of the ASoC drivers open coding handling of that to the core functionality.
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r--sound/soc/sof/intel/Kconfig1
-rw-r--r--sound/soc/sof/intel/apl.c1
-rw-r--r--sound/soc/sof/intel/cnl.c4
-rw-r--r--sound/soc/sof/intel/hda-ipc.c2
-rw-r--r--sound/soc/sof/intel/hda.c213
-rw-r--r--sound/soc/sof/intel/icl.c1
-rw-r--r--sound/soc/sof/intel/lnl.c1
-rw-r--r--sound/soc/sof/intel/mtl.c2
-rw-r--r--sound/soc/sof/intel/ptl.c2
-rw-r--r--sound/soc/sof/intel/shim.h1
-rw-r--r--sound/soc/sof/intel/skl.c1
-rw-r--r--sound/soc/sof/intel/tgl.c4
12 files changed, 229 insertions, 4 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index b14e7ca60e91..54cd3807f8c6 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -328,6 +328,7 @@ config SND_SOC_SOF_HDA_GENERIC
select SND_INTEL_DSP_CONFIG
select SND_SOC_SOF_HDA_LINK_BASELINE
select SND_SOC_SOF_HDA_PROBES
+ select SND_SOC_SDW_UTILS if SND_SOC_SOF_INTEL_SOUNDWIRE
select SND_SOC_SOF_HDA_MLINK if SND_SOC_SOF_HDA_LINK
help
This option is not user-selectable but automagically handled by
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 76a92eaa1359..0c68ae41a8a8 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -118,4 +118,5 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS,
+ .platform = "apl",
};
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 385e5339f0a4..0cc5725515e7 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -329,7 +329,7 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
* CTX_SAVE IPC, which is sent before the DSP enters D3.
*/
if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE))
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
return 0;
@@ -479,6 +479,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_8,
+ .platform = "cnl",
};
/*
@@ -515,5 +516,6 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "jsl",
};
EXPORT_SYMBOL_NS(jsl_chip_info, "SND_SOC_SOF_INTEL_CNL");
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index f3fbf43a70c2..94425c510861 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -96,7 +96,7 @@ void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev,
if (hda_dsp_ipc4_pm_msg(msg_data->primary))
return;
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
}
EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 52e86fa60077..c1518dbee1b7 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -26,6 +26,7 @@
#include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h>
#include <sound/soc-acpi-intel-ssp-common.h>
+#include <sound/soc_sdw_utils.h>
#include <sound/sof.h>
#include <sound/sof/xtensa.h>
#include <sound/hda-mlink.h>
@@ -33,6 +34,7 @@
#include "../sof-pci-dev.h"
#include "../ops.h"
#include "../ipc4-topology.h"
+#include "../../intel/common/sof-function-topology-lib.h"
#include "hda.h"
#include <trace/events/sof_intel.h>
@@ -1131,14 +1133,174 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+static bool is_endpoint_present(struct sdw_slave *sdw_device,
+ struct asoc_sdw_codec_info *dai_info, int dai_type)
+{
+ int i;
+
+ for (i = 0; i < sdw_device->sdca_data.num_functions; i++) {
+ if (dai_type == dai_info->dais[i].dai_type)
+ return true;
+ }
+ dev_dbg(&sdw_device->dev, "Endpoint DAI type %d not found\n", dai_type);
+ return false;
+}
+
+static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
+ struct sdw_slave *sdw_device,
+ struct snd_soc_acpi_link_adr *link,
+ int *amp_index)
+{
+ struct snd_soc_acpi_adr_device *adr_dev;
+ const char *name_prefix = "";
+ int index = link->num_adr;
+ bool is_amp = true; /* Set it to false if the codec wiah any NON-AMP DAI type */
+ int ep_index = 0;
+ int i, j;
+
+ link->mask = BIT(sdw_device->bus->link_id);
+ /* index is 0 based, we need allocate index + 1 for the array size */
+ if (!index)
+ adr_dev = devm_kzalloc(dev, sizeof(*adr_dev), GFP_KERNEL);
+ else
+ adr_dev = devm_krealloc(dev, (struct snd_soc_acpi_adr_device *)link->adr_d,
+ (index + 1) * sizeof(*adr_dev), GFP_KERNEL);
+
+ if (!adr_dev)
+ return NULL;
+
+ for (i = 0; i < asoc_sdw_get_codec_info_list_count(); i++) {
+ struct snd_soc_acpi_endpoint *endpoints;
+ int amp_group_id = 1;
+
+ if (sdw_device->id.part_id != codec_info_list[i].part_id)
+ continue;
+
+ endpoints = devm_kcalloc(dev, codec_info_list[i].dai_num,
+ sizeof(struct snd_soc_acpi_endpoint), GFP_KERNEL);
+ if (!endpoints)
+ return NULL;
+
+ name_prefix = codec_info_list[i].name_prefix;
+ /*
+ * This should not happen, but add a paranoid check to avoid NULL pointer
+ * dereference
+ */
+ if (!name_prefix) {
+ dev_err(dev, "codec_info_list name_prefix of part id %#x is missing\n",
+ codec_info_list[i].part_id);
+ return NULL;
+ }
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ /* Check if the endpoint is present by the SDCA DisCo table */
+ if (!is_endpoint_present(sdw_device, &codec_info_list[i],
+ codec_info_list[i].dais[j].dai_type))
+ continue;
+
+ endpoints[ep_index].num = ep_index;
+ if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) {
+ /* Assume all amp are aggregated */
+ endpoints[ep_index].aggregated = 1;
+ endpoints[ep_index].group_id = amp_group_id;
+ endpoints[ep_index].group_position = *amp_index;
+ /* Set group id = 2 for feedback capture endpoint */
+ amp_group_id++;
+ } else {
+ endpoints[ep_index].aggregated = 0;
+ endpoints[ep_index].group_id = 0;
+ endpoints[ep_index].group_position = 0;
+ is_amp = false;
+ }
+ ep_index++;
+ }
+ adr_dev[index].endpoints = endpoints;
+ adr_dev[index].num_endpoints = ep_index;
+ break;
+ }
+
+ if (i == asoc_sdw_get_codec_info_list_count()) {
+ dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id);
+ return NULL;
+ }
+
+ adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) |
+ ((u64)sdw_device->id.part_id & 0xFFFF) << 8 |
+ ((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 |
+ ((u64)(sdw_device->id.unique_id & 0xF) << 40) |
+ ((u64)(sdw_device->id.sdw_version & 0xF) << 44) |
+ ((u64)(sdw_device->bus->link_id & 0xF) << 48);
+
+ if (!is_amp) {
+ /* For non-amp codecs, get name_prefix from codec_info_list[] */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s", name_prefix);
+ goto done_name_prefix;
+ }
+
+ /*
+ * The name_prefix comes from codec_info_list which has a name_prefix per codec.
+ * And we need to give a unique name_prefix for each amp and should be backwards
+ * compatible to the existing acpi match tables to not break existing UCMs.
+ * For the common name_prefix, we append the amp index to it. However, for the
+ * "Left" name_prefix, we convert the second amp name_prefix to "Right" and
+ * for the third and further amps, we set the name_prefix to "AMP<amp_index>".
+ */
+ if (!strcmp(name_prefix, "Left")) {
+ switch (*amp_index) {
+ case 1:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Left");
+ break;
+ case 2:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Right");
+ break;
+ default:
+ /* Set the name_fix to AMP<amp_index> if there are more than 2 amps */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ "AMP", *amp_index);
+ break;
+ }
+ } else if (!strcmp(name_prefix, "AMP")) {
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ name_prefix,
+ *amp_index);
+ } else {
+ /*
+ * The name_prefix will be the amp name if it is not "Left" or "AMP", set it to
+ * <name_prefix>-<amp_index> format. Like rt1320-1
+ */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s-%d",
+ name_prefix,
+ *amp_index);
+ }
+ (*amp_index)++;
+
+done_name_prefix:
+ if (!adr_dev[index].name_prefix) {
+ dev_err(dev, "failed to allocate memory for name_prefix\n");
+ return NULL;
+ }
+
+ dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n",
+ index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix);
+
+ link->num_adr++;
+
+ return adr_dev;
+}
+
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct snd_soc_acpi_link_adr *link;
+ const struct sof_intel_dsp_desc *chip;
+ struct snd_soc_acpi_link_adr *links;
struct sdw_peripherals *peripherals;
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
- u32 link_mask;
+ int link_index, link_num;
+ int amp_index = 1;
+ u32 link_mask = 0;
int i;
hdev = pdata->hw_pdata;
@@ -1215,7 +1377,53 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
peripherals->array[i]->id.part_id,
peripherals->array[i]->id.sdw_version);
- return NULL;
+ chip = get_chip_info(sdev->pdata);
+
+ /* SDCA was not well supported in the BIOS before ACE2.0 */
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+
+ if (!peripherals->num_peripherals)
+ return NULL;
+
+ /* Create default SDW mach */
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return NULL;
+
+ /* Get link mask and link number */
+ for (i = 0; i < peripherals->num_peripherals; i++)
+ link_mask |= BIT(peripherals->array[i]->bus->link_id);
+
+ link_num = hweight32(link_mask);
+ links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ if (!links)
+ return NULL;
+
+ /* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */
+ for (i = 0; i < peripherals->num_peripherals; i++) {
+ /* link_index = the number of used links below the current link */
+ link_index = hweight32(link_mask & (BIT(peripherals->array[i]->bus->link_id) - 1));
+ links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i],
+ &links[link_index], &amp_index);
+ if (!links[link_index].adr_d)
+ return NULL;
+ }
+
+ mach->drv_name = "sof_sdw";
+ mach->mach_params.links = links;
+ mach->mach_params.link_mask = link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
+ mach->get_function_tplg_files = sof_sdw_get_tplg_files;
+ /*
+ * Set mach->sof_tplg_filename as a dummy topology to avoid tplg file checking
+ * and being used.
+ */
+ mach->sof_tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-dummy.tplg", chip->platform);
+
+ dev_info(sdev->dev, "Use SoundWire default machine driver with function topologies\n");
+ return mach;
}
#else
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
@@ -1543,6 +1751,7 @@ MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT");
MODULE_IMPORT_NS("SOUNDWIRE_INTEL");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index dad6bc72ad37..dbc5ad62258b 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -193,4 +193,5 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "icl",
};
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
index 2f3222040f98..c01ea7e731aa 100644
--- a/sound/soc/sof/intel/lnl.c
+++ b/sound/soc/sof/intel/lnl.c
@@ -183,6 +183,7 @@ const struct sof_intel_dsp_desc lnl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_2_0,
+ .platform = "lnl",
};
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 2242c96bfa51..095dcf1a18e4 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -786,6 +786,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = mtl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "mtl",
};
const struct sof_intel_dsp_desc arl_s_chip_info = {
@@ -814,4 +815,5 @@ const struct sof_intel_dsp_desc arl_s_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = mtl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "arl",
};
diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c
index 4633cd01e7dd..c1db735237f8 100644
--- a/sound/soc/sof/intel/ptl.c
+++ b/sound/soc/sof/intel/ptl.c
@@ -125,6 +125,7 @@ const struct sof_intel_dsp_desc ptl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_3_0,
+ .platform = "ptl",
};
const struct sof_intel_dsp_desc wcl_chip_info = {
@@ -149,6 +150,7 @@ const struct sof_intel_dsp_desc wcl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_3_0,
+ .platform = "wcl",
};
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index 8b7ccb1596d5..33d27cb5f1d7 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -187,6 +187,7 @@ struct sof_intel_dsp_desc {
u32 sdw_alh_base;
u32 d0i3_offset;
u32 quirks;
+ const char *platform;
enum sof_intel_hw_ip_version hw_ip_version;
int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index 0696bce65e33..90a3c2e2334c 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -113,5 +113,6 @@ const struct sof_intel_dsp_desc skl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5,
+ .platform = "skl",
};
EXPORT_SYMBOL_NS(skl_chip_info, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index df2d26b78ddc..e68bbe685ba3 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -162,6 +162,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
const struct sof_intel_dsp_desc tglh_chip_info = {
@@ -191,6 +192,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
const struct sof_intel_dsp_desc ehl_chip_info = {
@@ -220,6 +222,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "ehl",
};
const struct sof_intel_dsp_desc adls_chip_info = {
@@ -249,4 +252,5 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "adl",
};