From: Bard Liao <yung-chuan.liao@linux.intel.com>
To: broonie@kernel.org, tiwai@suse.de
Cc: linux-sound@vger.kernel.org, bard.liao@intel.com,
peter.ujfalusi@linux.intel.com
Subject: [PATCH v2 1/7] ASoC: SOF: get nhlt from all topologies
Date: Wed, 23 Sep 2026 13:28:26 +0800 [thread overview]
Message-ID: <20260923052832.2392758-2-yung-chuan.liao@linux.intel.com> (raw)
In-Reply-To: <20260923052832.2392758-1-yung-chuan.liao@linux.intel.com>
The existing code assumes there is only one NHLT blob either from BIOS
or topology. As function topologies are used and each function topology
contains a NHLT blob section, we need to search the matching NHLT blob
from all the NHLT blobs.
The commit suggests adding a list of NHLTs and search the NHLTs from the
list.
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
---
sound/soc/sof/intel/apl.c | 1 +
sound/soc/sof/intel/cnl.c | 1 +
sound/soc/sof/intel/hda-dai.c | 26 +++++++++++++--
sound/soc/sof/intel/icl.c | 1 +
sound/soc/sof/intel/mtl.c | 1 +
sound/soc/sof/intel/skl.c | 1 +
sound/soc/sof/intel/tgl.c | 1 +
sound/soc/sof/ipc4-priv.h | 10 ++++--
sound/soc/sof/ipc4-topology.c | 63 ++++++++++++++++++++++++-----------
9 files changed, 80 insertions(+), 25 deletions(-)
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index b0072601181e..753da09301fa 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -59,6 +59,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5;
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 660c1475e5a4..ec33cd18e669 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -406,6 +406,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_8;
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index bb44d4f8a4da..c8729b6d82bd 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -760,8 +760,20 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct snd_ipc4_nhlt *entry;
- ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
+ entry = devm_kzalloc(sdev->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return;
+
+ entry->nhlt = intel_nhlt_init(sdev->dev);
+ if (!entry->nhlt) {
+ devm_kfree(sdev->dev, entry);
+ return;
+ }
+
+ entry->from_acpi = true;
+ list_add(&entry->list, &ipc4_data->nhlt_list);
}
}
EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
@@ -770,9 +782,17 @@ void hda_ops_free(struct snd_sof_dev *sdev)
{
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct snd_ipc4_nhlt *entry;
+ struct snd_ipc4_nhlt *tmp;
- if (!hda_use_tplg_nhlt)
- intel_nhlt_free(ipc4_data->nhlt);
+ if (!hda_use_tplg_nhlt) {
+ list_for_each_entry_safe(entry, tmp, &ipc4_data->nhlt_list, list) {
+ if (entry->from_acpi && entry->nhlt)
+ intel_nhlt_free(entry->nhlt);
+
+ list_del(&entry->list);
+ }
+ }
kfree(sdev->private);
sdev->private = NULL;
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 549bb4ca73e1..196caba14be0 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -131,6 +131,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 3d67d6777f1b..2506506f813a 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -762,6 +762,7 @@ int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index 90519ebd3168..f831143a7afc 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -67,6 +67,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET_CAVS_1_5;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_1_5;
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 7936361e2e39..09a8a4a2b017 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -95,6 +95,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
return -ENOMEM;
ipc4_data = sdev->private;
+ INIT_LIST_HEAD(&ipc4_data->nhlt_list);
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index a8cdf9bc750b..61dd48282dd3 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -58,13 +58,18 @@ struct sof_ipc4_fw_library {
struct sof_ipc4_fw_module *modules;
};
+struct snd_ipc4_nhlt {
+ struct list_head list;
+ void *nhlt;
+ bool from_acpi;
+};
+
/**
* struct sof_ipc4_fw_data - IPC4-specific data
* @manifest_fw_hdr_offset: FW header offset in the manifest
* @fw_lib_xa: XArray for firmware libraries, including basefw (ID = 0)
* Used to store the FW libraries and to manage the unique IDs of the
* libraries.
- * @nhlt: NHLT table either from the BIOS or the topology manifest
* @mtrace_type: mtrace type supported on the booted platform
* @mtrace_log_bytes: log bytes as reported by the firmware via fw_config reply
* @num_playback_streams: max number of playback DMAs, needed for CHAIN_DMA offset
@@ -74,6 +79,7 @@ struct sof_ipc4_fw_library {
* base firmware
* @fw_context_save: Firmware supports full context save and restore
* @libraries_restored: The libraries have been retained during firmware boot
+ * @nhlt_list: The NHLT tables from the BIOS and the topology manifest
*
* @load_library: Callback function for platform dependent library loading
* @pipeline_state_mutex: Mutex to protect pipeline triggers, ref counts, states and deletion
@@ -81,7 +87,6 @@ struct sof_ipc4_fw_library {
struct sof_ipc4_fw_data {
u32 manifest_fw_hdr_offset;
struct xarray fw_lib_xa;
- void *nhlt;
enum sof_ipc4_mtrace_type mtrace_type;
u32 mtrace_log_bytes;
int num_playback_streams;
@@ -90,6 +95,7 @@ struct sof_ipc4_fw_data {
u32 max_libs_count;
bool fw_context_save;
bool libraries_restored;
+ struct list_head nhlt_list;
int (*load_library)(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload);
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 24a1175dd690..f6617dcbf789 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1844,12 +1844,13 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
u32 linktype, u8 dir, u32 **dst, u32 *len)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct nhlt_specific_cfg *cfg;
+ struct nhlt_specific_cfg *cfg = NULL;
+ struct snd_ipc4_nhlt *entry = NULL;
int sample_rate, channel_count;
bool format_change = false;
int bit_depth, ret;
u32 nhlt_type;
- int dev_type = 0;
+ int dev_type = -EINVAL;
/* convert to NHLT type */
switch (linktype) {
@@ -1880,10 +1881,17 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
* Query the type for the port and then pass that information back
* to the blob lookup function.
*/
- dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
- dai_index);
- if (dev_type < 0)
+ list_for_each_entry(entry, &ipc4_data->nhlt_list, list) {
+ dev_type = intel_nhlt_ssp_device_type(sdev->dev, entry->nhlt,
+ dai_index);
+ if (dev_type >= 0)
+ break;
+ }
+ if (dev_type < 0) {
+ dev_err(sdev->dev, "%s: No match for SSP%d in NHLT table\n",
+ __func__, dai_index);
return dev_type;
+ }
break;
default:
return 0;
@@ -1893,9 +1901,14 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
dai_index, nhlt_type, dir, dev_type);
/* find NHLT blob with matching params */
- cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
- bit_depth, bit_depth, channel_count, sample_rate,
- dir, dev_type);
+ list_for_each_entry(entry, &ipc4_data->nhlt_list, list) {
+ cfg = intel_nhlt_get_endpoint_blob(sdev->dev, entry->nhlt, dai_index,
+ nhlt_type, bit_depth, bit_depth,
+ channel_count, sample_rate, dir,
+ dev_type);
+ if (cfg)
+ break;
+ }
if (!cfg) {
bool get_new_blob = false;
@@ -1929,13 +1942,15 @@ snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai
}
if (get_new_blob) {
- cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
- dai_index, nhlt_type,
- bit_depth, bit_depth,
- channel_count, sample_rate,
- dir, dev_type);
- if (cfg)
- goto out;
+ list_for_each_entry(entry, &ipc4_data->nhlt_list, list) {
+ cfg = intel_nhlt_get_endpoint_blob(sdev->dev, entry->nhlt,
+ dai_index, nhlt_type,
+ bit_depth, bit_depth,
+ channel_count, sample_rate,
+ dir, dev_type);
+ if (cfg)
+ goto out;
+ }
}
dev_err(sdev->dev,
@@ -4069,6 +4084,7 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_manifest_tlv *manifest_tlv;
+ struct snd_ipc4_nhlt *tplg_nhlt;
struct sof_manifest *manifest;
u32 size = le32_to_cpu(man->priv.size);
u8 *man_ptr = man->priv.data;
@@ -4104,13 +4120,20 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
switch (le32_to_cpu(manifest_tlv->type)) {
case SOF_MANIFEST_DATA_TYPE_NHLT:
- /* no NHLT in BIOS, so use the one from topology manifest */
- if (ipc4_data->nhlt)
- break;
- ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
+ /* Get the nhlt from topology manifest */
+ tplg_nhlt = devm_kzalloc(sdev->dev, sizeof(*tplg_nhlt), GFP_KERNEL);
+ if (!tplg_nhlt)
+ return -ENOMEM;
+
+ tplg_nhlt->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
- if (!ipc4_data->nhlt)
+ if (!tplg_nhlt->nhlt)
return -ENOMEM;
+
+ tplg_nhlt->from_acpi = false;
+
+ list_add(&tplg_nhlt->list, &ipc4_data->nhlt_list);
+
break;
default:
dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
--
2.43.0
next prev parent reply other threads:[~2026-09-23 5:28 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 5:28 [PATCH v2 0/7] ALSA/ASoC: Intel: add I2S function topology support Bard Liao
2026-09-23 5:28 ` Bard Liao [this message]
2026-09-23 5:28 ` [PATCH v2 2/7] ALSA: intel-nhlt: lower intel_nhlt_ssp_device_type log level Bard Liao
2026-09-23 5:28 ` [PATCH v2 3/7] ASoC: Intel: sof-function-topology-lib: create common helpers Bard Liao
2026-09-23 5:28 ` [PATCH v2 4/7] ASoC: Intel: sof-function-topology-lib: skip non-exist file in best_effort mode Bard Liao
2026-09-23 5:28 ` [PATCH v2 5/7] ASoC: Intel: sof-function-topology-lib: add I2S support for sof_sdw_get_tplg_files Bard Liao
2026-09-23 5:28 ` [PATCH v2 6/7] ASoC: Intel: sof-function-topology-lib: add get_function_topology for I2S machines Bard Liao
2026-09-23 5:28 ` [PATCH v2 7/7] ASoC: soc-acpi-intel-ptl-match: I2S machines: use function topology Bard Liao
2026-09-23 8:41 ` [PATCH v2 0/7] ALSA/ASoC: Intel: add I2S function topology support Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260923052832.2392758-2-yung-chuan.liao@linux.intel.com \
--to=yung-chuan.liao@linux.intel.com \
--cc=bard.liao@intel.com \
--cc=broonie@kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=peter.ujfalusi@linux.intel.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox