Linux Sound subsystem development
 help / color / mirror / Atom feed
* [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override
@ 2025-11-15 18:06 Cezary Rojewski
  2025-11-15 18:06 ` [PATCH 1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data Cezary Rojewski
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Cezary Rojewski @ 2025-11-15 18:06 UTC (permalink / raw)
  To: broonie; +Cc: tiwai, perex, amade, linux-sound, Cezary Rojewski

Small set of changes providing new feature which the driver is already
utilizing on the market - for its Long-Term-Support (LTS) devices.

The goal is to cover systems which shipped with invalid Non HDAudio Link
Table (NHLT) - not just the descriptors (headers), but cases where the
hardware configuration is invalid too. The table is part of the ACPI
tree and forcing BIOS updates is not a feasible solution. With the
override, the topology file can carry the hardware configuration
instead.

From AudioDSP perspective, only gateway-related modules e.g.: Copier
care about the procedure. To ensure correct order of operations when
initializing such modules, the overrides take precedence over what's
currently there in the NHLT.

Cezary Rojewski (2):
  ASoC: Intel: avs: Allow the topology to carry NHLT data
  ASoC: Intel: avs: Honor NHLT override when setting up a path

 include/uapi/sound/intel/avs/tokens.h |   6 ++
 sound/soc/intel/avs/path.c            |  13 ++-
 sound/soc/intel/avs/topology.c        | 113 +++++++++++++++++++++++++-
 sound/soc/intel/avs/topology.h        |   8 ++
 4 files changed, 133 insertions(+), 7 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data
  2025-11-15 18:06 [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Cezary Rojewski
@ 2025-11-15 18:06 ` Cezary Rojewski
  2025-11-15 18:06 ` [PATCH 2/2] ASoC: Intel: avs: Honor NHLT override when setting up a path Cezary Rojewski
  2025-11-20  9:40 ` [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Mark Brown
  2 siblings, 0 replies; 4+ messages in thread
From: Cezary Rojewski @ 2025-11-15 18:06 UTC (permalink / raw)
  To: broonie; +Cc: tiwai, perex, amade, linux-sound, Cezary Rojewski

Typically the hardware configuration for I2S and DMIC devices resides
in the Non-HDAudio Link Table (NHLT) that is part of the ACPI tree. As
the NHLTs existing in the field are not always perfect, workaround
mechanisms are provided to patch them.

Currently the avs-driver is utilizing the ->blob_fmt override (see
topology.h and struct avs_tplg_modcfg_ext) when there is a valid entry
within a NHLT to configure the hardware for specific format but its
descriptor (header) is invalid.

A separate case is when there is no correct hardware configuration at
all within the NHLT available in the system. Patching the header won't
help and forcing ad-hoc BIOS updates for dated system is not feasible.
Allowing the topology to carry the data is the solution of choice as
replacing a userspace file that is part of /lib/firmware/intel/ is less
invasive than BIOS update and solves the problem.

Co-developed-by: Amadeusz Sławiński <amade@asmblr.net>
Signed-off-by: Amadeusz Sławiński <amade@asmblr.net>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/uapi/sound/intel/avs/tokens.h |   5 ++
 sound/soc/intel/avs/topology.c        | 106 +++++++++++++++++++++++++-
 sound/soc/intel/avs/topology.h        |   7 ++
 3 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h
index f3ff6aae09a9..f7cbbfb00227 100644
--- a/include/uapi/sound/intel/avs/tokens.h
+++ b/include/uapi/sound/intel/avs/tokens.h
@@ -21,6 +21,7 @@ enum avs_tplg_token {
 	AVS_TKN_MANIFEST_NUM_BINDINGS_U32		= 8,
 	AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32		= 9,
 	AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32		= 10,
+	AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32		= 11,
 
 	/* struct avs_tplg_library */
 	AVS_TKN_LIBRARY_ID_U32				= 101,
@@ -160,6 +161,10 @@ enum avs_tplg_token {
 	AVS_TKN_INIT_CONFIG_ID_U32			= 2401,
 	AVS_TKN_INIT_CONFIG_PARAM_U8			= 2402,
 	AVS_TKN_INIT_CONFIG_LENGTH_U32			= 2403,
+
+	/* struct avs_tplg_nhlt_config */
+	AVS_TKN_NHLT_CONFIG_ID_U32			= 2501,
+	AVS_TKN_NHLT_CONFIG_SIZE_U32			= 2502,
 };
 
 #endif
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index dfe8cf505381..48fdbaef56dd 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -420,6 +420,22 @@ static int parse_link_formatted_string(struct snd_soc_component *comp, void *ele
 	return 0;
 }
 
+static int avs_parse_nhlt_config_size(struct snd_soc_component *comp, void *elem, void *object,
+				      u32 offset)
+{
+	struct snd_soc_tplg_vendor_value_elem *tuple = elem;
+	struct acpi_nhlt_config **blob = (struct acpi_nhlt_config **)((u8 *)object + offset);
+	u32 size;
+
+	size = le32_to_cpu(tuple->value);
+	*blob = devm_kzalloc(comp->card->dev, struct_size(*blob, capabilities, size), GFP_KERNEL);
+	if (!*blob)
+		return -ENOMEM;
+
+	(*blob)->capabilities_size = size;
+	return 0;
+}
+
 static int
 parse_dictionary_header(struct snd_soc_component *comp,
 			struct snd_soc_tplg_vendor_array *tuples,
@@ -1651,12 +1667,14 @@ static const struct avs_tplg_token_parser mod_init_config_parsers[] = {
 
 static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
 					   struct snd_soc_tplg_vendor_array *tuples,
-					   u32 block_size)
+					   u32 block_size, u32 *offset)
 {
 	struct avs_soc_component *acomp = to_avs_soc_component(comp);
 	struct avs_tplg *tplg = acomp->tplg;
 	int ret, i;
 
+	*offset = 0;
+
 	/* Parse tuple section telling how many init configs there are. */
 	ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs,
 				      &tplg->num_init_configs,
@@ -1666,6 +1684,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
 		return ret;
 
 	block_size -= le32_to_cpu(tuples->size);
+	*offset += le32_to_cpu(tuples->size);
 	/* With header parsed, move on to parsing entries. */
 	tuples = avs_tplg_vendor_array_next(tuples);
 
@@ -1681,6 +1700,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
 		 */
 		tmp = avs_tplg_vendor_array_next(tuples);
 		esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size);
+		*offset += esize;
 
 		ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config),
 					       AVS_TKN_INIT_CONFIG_ID_U32,
@@ -1692,6 +1712,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
 		/* handle raw data section */
 		init_config_data = (void *)tuples + esize;
 		esize = config->length;
+		*offset += esize;
 
 		config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL);
 		if (!config->data)
@@ -1704,6 +1725,70 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
 	return 0;
 }
 
+static const struct avs_tplg_token_parser mod_nhlt_config_parsers[] = {
+	{
+		.token = AVS_TKN_NHLT_CONFIG_ID_U32,
+		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		.offset = offsetof(struct avs_tplg_nhlt_config, id),
+		.parse = avs_parse_word_token,
+	},
+	{
+		.token = AVS_TKN_NHLT_CONFIG_SIZE_U32,
+		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		.offset = offsetof(struct avs_tplg_nhlt_config, blob),
+		.parse = avs_parse_nhlt_config_size,
+	},
+};
+
+static int avs_tplg_parse_nhlt_configs(struct snd_soc_component *comp,
+				       struct snd_soc_tplg_vendor_array *tuples,
+				       u32 block_size)
+{
+	struct avs_soc_component *acomp = to_avs_soc_component(comp);
+	struct avs_tplg *tplg = acomp->tplg;
+	int ret, i;
+
+	/* Parse the header section to know how many entries there are. */
+	ret = parse_dictionary_header(comp, tuples, (void **)&tplg->nhlt_configs,
+				      &tplg->num_nhlt_configs,
+				      sizeof(*tplg->nhlt_configs),
+				      AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32);
+	if (ret)
+		return ret;
+
+	block_size -= le32_to_cpu(tuples->size);
+	/* With the header parsed, move on to parsing entries. */
+	tuples = avs_tplg_vendor_array_next(tuples);
+
+	for (i = 0; i < tplg->num_nhlt_configs && block_size > 0; i++) {
+		struct avs_tplg_nhlt_config *config;
+		u32 esize;
+
+		config = &tplg->nhlt_configs[i];
+		esize = le32_to_cpu(tuples->size);
+
+		ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config),
+					       AVS_TKN_NHLT_CONFIG_ID_U32,
+					       mod_nhlt_config_parsers,
+					       ARRAY_SIZE(mod_nhlt_config_parsers));
+		if (ret)
+			return ret;
+		/* With tuples parsed, the blob shall be allocated. */
+		if (!config->blob)
+			return -EINVAL;
+
+		/* Consume the raw data and move to the next entry. */
+		memcpy(config->blob->capabilities, (u8 *)tuples + esize,
+		       config->blob->capabilities_size);
+		esize += config->blob->capabilities_size;
+
+		block_size -= esize;
+		tuples = avs_tplg_vendor_array_at(tuples, esize);
+	}
+
+	return 0;
+}
+
 static int avs_route_load(struct snd_soc_component *comp, int index,
 			  struct snd_soc_dapm_route *route)
 {
@@ -2008,11 +2093,26 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
 	tuples = avs_tplg_vendor_array_at(tuples, offset);
 
 	/* Initial configs dictionary. */
-	ret = avs_tplg_parse_initial_configs(comp, tuples, remaining);
+	ret = avs_tplg_parse_initial_configs(comp, tuples, remaining, &offset);
 	if (ret < 0)
 		return ret;
 
-	return 0;
+	remaining -= offset;
+	tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+	ret = avs_tplg_vendor_array_lookup(tuples, remaining,
+					   AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32, &offset);
+	if (ret == -ENOENT)
+		return 0;
+	if (ret) {
+		dev_err(comp->dev, "NHLT config lookup failed: %d\n", ret);
+		return ret;
+	}
+
+	tuples = avs_tplg_vendor_array_at(tuples, offset);
+
+	/* NHLT configs dictionary. */
+	return avs_tplg_parse_nhlt_configs(comp, tuples, remaining);
 }
 
 enum {
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 1e83fccf2ea2..61d50960ef06 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -37,6 +37,8 @@ struct avs_tplg {
 	u32 num_condpath_tmpls;
 	struct avs_tplg_init_config *init_configs;
 	u32 num_init_configs;
+	struct avs_tplg_nhlt_config *nhlt_configs;
+	u32 num_nhlt_configs;
 
 	struct list_head path_tmpl_list;
 };
@@ -175,6 +177,11 @@ struct avs_tplg_init_config {
 	void *data;
 };
 
+struct avs_tplg_nhlt_config {
+	u32 id;
+	struct acpi_nhlt_config *blob;
+};
+
 struct avs_tplg_path {
 	u32 id;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] ASoC: Intel: avs: Honor NHLT override when setting up a path
  2025-11-15 18:06 [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Cezary Rojewski
  2025-11-15 18:06 ` [PATCH 1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data Cezary Rojewski
@ 2025-11-15 18:06 ` Cezary Rojewski
  2025-11-20  9:40 ` [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Mark Brown
  2 siblings, 0 replies; 4+ messages in thread
From: Cezary Rojewski @ 2025-11-15 18:06 UTC (permalink / raw)
  To: broonie; +Cc: tiwai, perex, amade, linux-sound, Cezary Rojewski

In case topology provides NHLT configuration, use it instead of relying
on the table in ACPI tree. Only gateway-related modules e.g.: Copier
care about the process. For those the order of fetching for hardware
configuration becomes:

1) check if NHLT override is set,
2) check if NHLT descriptor override is set,
3) use NHLT from ACPI directly

Such approach ensures no conflicts exist between 1) and 2) and that 1)
always takes precedence.

Co-developed-by: Amadeusz Sławiński <amade@asmblr.net>
Signed-off-by: Amadeusz Sławiński <amade@asmblr.net>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/uapi/sound/intel/avs/tokens.h |  1 +
 sound/soc/intel/avs/path.c            | 13 +++++++++----
 sound/soc/intel/avs/topology.c        |  7 +++++++
 sound/soc/intel/avs/topology.h        |  1 +
 4 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h
index f7cbbfb00227..3ff6d9150822 100644
--- a/include/uapi/sound/intel/avs/tokens.h
+++ b/include/uapi/sound/intel/avs/tokens.h
@@ -125,6 +125,7 @@ enum avs_tplg_token {
 	AVS_TKN_MOD_KCONTROL_ID_U32			= 1707,
 	AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32		= 1708,
 	AVS_TKN_MOD_INIT_CONFIG_ID_U32			= 1709,
+	AVS_TKN_MOD_NHLT_CONFIG_ID_U32			= 1710,
 
 	/* struct avs_tplg_path_template */
 	AVS_TKN_PATH_TMPL_ID_U32			= 1801,
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 7aa20fcf1a33..c8b586aced20 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -210,9 +210,11 @@ int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template
 					continue;
 				}
 
-				blob = avs_nhlt_config_or_default(adev, module_template);
-				if (IS_ERR(blob))
-					continue;
+				if (!module_template->nhlt_config) {
+					blob = avs_nhlt_config_or_default(adev, module_template);
+					if (IS_ERR(blob))
+						continue;
+				}
 
 				rlist[i] = path_template->fe_fmt->sampling_freq;
 				clist[i] = path_template->fe_fmt->num_channels;
@@ -382,7 +384,10 @@ static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *
 	struct acpi_nhlt_config *blob;
 	size_t gtw_size;
 
-	blob = avs_nhlt_config_or_default(adev, t);
+	if (t->nhlt_config)
+		blob = t->nhlt_config->blob;
+	else
+		blob = avs_nhlt_config_or_default(adev, t);
 	if (IS_ERR(blob))
 		return PTR_ERR(blob);
 
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 48fdbaef56dd..9033f683393c 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
 AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
 AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
 AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
+AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs);
 
 static int
 parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
@@ -1200,6 +1201,12 @@ static const struct avs_tplg_token_parser module_parsers[] = {
 		.offset = offsetof(struct avs_tplg_module, num_config_ids),
 		.parse = avs_parse_byte_token,
 	},
+	{
+		.token = AVS_TKN_MOD_NHLT_CONFIG_ID_U32,
+		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		.offset = offsetof(struct avs_tplg_module, nhlt_config),
+		.parse = avs_parse_nhlt_config_ptr,
+	},
 };
 
 static const struct avs_tplg_token_parser init_config_parsers[] = {
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 61d50960ef06..1cf7455b6c01 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -223,6 +223,7 @@ struct avs_tplg_module {
 	u32 ctl_id;
 	u32 num_config_ids;
 	u32 *config_ids;
+	struct avs_tplg_nhlt_config *nhlt_config;
 
 	struct avs_tplg_pipeline *owner;
 	/* Pipeline modules management. */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override
  2025-11-15 18:06 [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Cezary Rojewski
  2025-11-15 18:06 ` [PATCH 1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data Cezary Rojewski
  2025-11-15 18:06 ` [PATCH 2/2] ASoC: Intel: avs: Honor NHLT override when setting up a path Cezary Rojewski
@ 2025-11-20  9:40 ` Mark Brown
  2 siblings, 0 replies; 4+ messages in thread
From: Mark Brown @ 2025-11-20  9:40 UTC (permalink / raw)
  To: Cezary Rojewski; +Cc: tiwai, perex, amade, linux-sound

On Sat, 15 Nov 2025 19:06:25 +0100, Cezary Rojewski wrote:
> Small set of changes providing new feature which the driver is already
> utilizing on the market - for its Long-Term-Support (LTS) devices.
> 
> The goal is to cover systems which shipped with invalid Non HDAudio Link
> Table (NHLT) - not just the descriptors (headers), but cases where the
> hardware configuration is invalid too. The table is part of the ACPI
> tree and forcing BIOS updates is not a feasible solution. With the
> override, the topology file can carry the hardware configuration
> instead.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data
      commit: dd9896d41fdf1050934d6a46a1c5ca2164284e72
[2/2] ASoC: Intel: avs: Honor NHLT override when setting up a path
      commit: d5c8b7902a41625ea328b52c78ebe750fbf6fef7

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-11-20  9:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-15 18:06 [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Cezary Rojewski
2025-11-15 18:06 ` [PATCH 1/2] ASoC: Intel: avs: Allow the topology to carry NHLT data Cezary Rojewski
2025-11-15 18:06 ` [PATCH 2/2] ASoC: Intel: avs: Honor NHLT override when setting up a path Cezary Rojewski
2025-11-20  9:40 ` [PATCH 0/2] ASoC: Intel: avs: Allow for NHLT configuration override Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox