xref: /linux/sound/soc/intel/common/sof-function-topology-lib.c (revision 299f489f5bad3554531f67335d1762225448ff39)
12fbeff33SBard Liao // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
22fbeff33SBard Liao //
32fbeff33SBard Liao // This file is provided under a dual BSD/GPLv2 license.  When using or
42fbeff33SBard Liao // redistributing this file, you may do so under either license.
52fbeff33SBard Liao //
62fbeff33SBard Liao // Copyright(c) 2025 Intel Corporation.
72fbeff33SBard Liao //
82fbeff33SBard Liao 
92fbeff33SBard Liao #include <linux/device.h>
102fbeff33SBard Liao #include <linux/errno.h>
112fbeff33SBard Liao #include <linux/firmware.h>
122fbeff33SBard Liao #include <sound/soc.h>
132fbeff33SBard Liao #include <sound/soc-acpi.h>
142fbeff33SBard Liao #include "sof-function-topology-lib.h"
152fbeff33SBard Liao 
162fbeff33SBard Liao enum tplg_device_id {
172fbeff33SBard Liao 	TPLG_DEVICE_SDCA_JACK,
182fbeff33SBard Liao 	TPLG_DEVICE_SDCA_AMP,
192fbeff33SBard Liao 	TPLG_DEVICE_SDCA_MIC,
202fbeff33SBard Liao 	TPLG_DEVICE_INTEL_PCH_DMIC,
212fbeff33SBard Liao 	TPLG_DEVICE_HDMI,
222fbeff33SBard Liao 	TPLG_DEVICE_MAX
232fbeff33SBard Liao };
242fbeff33SBard Liao 
252fbeff33SBard Liao #define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
262fbeff33SBard Liao 			  BIT(TPLG_DEVICE_SDCA_MIC))
272fbeff33SBard Liao 
282fbeff33SBard Liao #define SOF_INTEL_PLATFORM_NAME_MAX 4
292fbeff33SBard Liao 
sof_sdw_get_tplg_files(struct snd_soc_card * card,const struct snd_soc_acpi_mach * mach,const char * prefix,const char *** tplg_files)302fbeff33SBard Liao int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
312fbeff33SBard Liao 			   const char *prefix, const char ***tplg_files)
322fbeff33SBard Liao {
332fbeff33SBard Liao 	struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
342fbeff33SBard Liao 	struct snd_soc_dai_link *dai_link;
352fbeff33SBard Liao 	const struct firmware *fw;
362fbeff33SBard Liao 	char platform[SOF_INTEL_PLATFORM_NAME_MAX];
372fbeff33SBard Liao 	unsigned long tplg_mask = 0;
382fbeff33SBard Liao 	int tplg_num = 0;
392fbeff33SBard Liao 	int tplg_dev;
402fbeff33SBard Liao 	int ret;
412fbeff33SBard Liao 	int i;
422fbeff33SBard Liao 
432fbeff33SBard Liao 	ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
442fbeff33SBard Liao 	if (ret != 1) {
452fbeff33SBard Liao 		dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
462fbeff33SBard Liao 			platform, mach->sof_tplg_filename);
472fbeff33SBard Liao 		return -EINVAL;
482fbeff33SBard Liao 	}
492fbeff33SBard Liao 
502fbeff33SBard Liao 	for_each_card_prelinks(card, i, dai_link) {
512fbeff33SBard Liao 		char *tplg_dev_name;
522fbeff33SBard Liao 
532fbeff33SBard Liao 		dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
542fbeff33SBard Liao 		if (strstr(dai_link->name, "SimpleJack")) {
552fbeff33SBard Liao 			tplg_dev = TPLG_DEVICE_SDCA_JACK;
562fbeff33SBard Liao 			tplg_dev_name = "sdca-jack";
572fbeff33SBard Liao 		} else if (strstr(dai_link->name, "SmartAmp")) {
582fbeff33SBard Liao 			tplg_dev = TPLG_DEVICE_SDCA_AMP;
592fbeff33SBard Liao 			tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
602fbeff33SBard Liao 						       "sdca-%damp", dai_link->num_cpus);
612fbeff33SBard Liao 			if (!tplg_dev_name)
622fbeff33SBard Liao 				return -ENOMEM;
632fbeff33SBard Liao 		} else if (strstr(dai_link->name, "SmartMic")) {
642fbeff33SBard Liao 			tplg_dev = TPLG_DEVICE_SDCA_MIC;
652fbeff33SBard Liao 			tplg_dev_name = "sdca-mic";
662fbeff33SBard Liao 		} else if (strstr(dai_link->name, "dmic")) {
672fbeff33SBard Liao 			switch (mach_params.dmic_num) {
682fbeff33SBard Liao 			case 2:
692fbeff33SBard Liao 				tplg_dev_name = "dmic-2ch";
702fbeff33SBard Liao 				break;
712fbeff33SBard Liao 			case 4:
722fbeff33SBard Liao 				tplg_dev_name = "dmic-4ch";
732fbeff33SBard Liao 				break;
742fbeff33SBard Liao 			default:
752fbeff33SBard Liao 				dev_warn(card->dev,
76*16ea4666SPeter Ujfalusi 					 "unsupported number of dmics: %d\n",
77*16ea4666SPeter Ujfalusi 					 mach_params.dmic_num);
782fbeff33SBard Liao 				continue;
792fbeff33SBard Liao 			}
802fbeff33SBard Liao 			tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
812fbeff33SBard Liao 		} else if (strstr(dai_link->name, "iDisp")) {
822fbeff33SBard Liao 			tplg_dev = TPLG_DEVICE_HDMI;
832fbeff33SBard Liao 			tplg_dev_name = "hdmi-pcm5";
842fbeff33SBard Liao 
852fbeff33SBard Liao 		} else {
862fbeff33SBard Liao 			/* The dai link is not supported by separated tplg yet */
872fbeff33SBard Liao 			dev_dbg(card->dev,
882fbeff33SBard Liao 				"dai_link %s is not supported by separated tplg yet\n",
892fbeff33SBard Liao 				dai_link->name);
902fbeff33SBard Liao 			return 0;
912fbeff33SBard Liao 		}
922fbeff33SBard Liao 		if (tplg_mask & BIT(tplg_dev))
932fbeff33SBard Liao 			continue;
942fbeff33SBard Liao 
952fbeff33SBard Liao 		tplg_mask |= BIT(tplg_dev);
962fbeff33SBard Liao 
972fbeff33SBard Liao 		/*
982fbeff33SBard Liao 		 * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
992fbeff33SBard Liao 		 * where <platform> is only required for the DMIC function as the nhlt blob
1002fbeff33SBard Liao 		 * is platform dependent.
1012fbeff33SBard Liao 		 */
1022fbeff33SBard Liao 		switch (tplg_dev) {
1032fbeff33SBard Liao 		case TPLG_DEVICE_INTEL_PCH_DMIC:
1042fbeff33SBard Liao 			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
1052fbeff33SBard Liao 								 "%s/sof-%s-%s-id%d.tplg",
1062fbeff33SBard Liao 								 prefix, platform,
1072fbeff33SBard Liao 								 tplg_dev_name, dai_link->id);
1082fbeff33SBard Liao 			break;
1092fbeff33SBard Liao 		default:
1102fbeff33SBard Liao 			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
1112fbeff33SBard Liao 								 "%s/sof-%s-id%d.tplg",
1122fbeff33SBard Liao 								 prefix, tplg_dev_name,
1132fbeff33SBard Liao 								 dai_link->id);
1142fbeff33SBard Liao 			break;
1152fbeff33SBard Liao 		}
1162fbeff33SBard Liao 		if (!(*tplg_files)[tplg_num])
1172fbeff33SBard Liao 			return -ENOMEM;
1182fbeff33SBard Liao 		tplg_num++;
1192fbeff33SBard Liao 	}
1202fbeff33SBard Liao 
1212fbeff33SBard Liao 	dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);
1222fbeff33SBard Liao 
1232fbeff33SBard Liao 	/* Check presence of sub-topologies */
1242fbeff33SBard Liao 	for (i = 0; i < tplg_num; i++) {
1252fbeff33SBard Liao 		ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
1262fbeff33SBard Liao 		if (!ret) {
1272fbeff33SBard Liao 			release_firmware(fw);
1282fbeff33SBard Liao 		} else {
1292fbeff33SBard Liao 			dev_dbg(card->dev, "Failed to open topology file: %s\n", (*tplg_files)[i]);
1302fbeff33SBard Liao 			return 0;
1312fbeff33SBard Liao 		}
1322fbeff33SBard Liao 	}
1332fbeff33SBard Liao 
1342fbeff33SBard Liao 	return tplg_num;
1352fbeff33SBard Liao }
1362fbeff33SBard Liao 
137