mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Matthew Schwartz <matthew.schwartz@linux.dev>
To: broonie@kernel.org
Cc: Matthew Schwartz <matthew.schwartz@linux.dev>,
	Shenghao Ding <shenghao-ding@ti.com>, Kevin Lu <kevin-lu@ti.com>,
	Baojun Xu <baojun.xu@ti.com>, Sen Wang <sen@ti.com>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
	linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name
Date: Tue,  3 Nov 2026 12:05:37 -0800	[thread overview]
Message-ID: <20261103200540.3863272-4-matthew.schwartz@linux.dev> (raw)
In-Reply-To: <20261103200540.3863272-1-matthew.schwartz@linux.dev>

Some boards have TAS2783 firmware in linux-firmware named
SSID-SPKID-LINK-0xUID.bin, with a speaker ID ahead of the link ID (the
HP 8EA1 has its amps on link 0 and ships 8EA1-{0,1}-0-0x*.bin). The
driver only builds the three-field SSID-LINK-0xUID name, so these boards
never load firmware. On the ASUS ROG Xbox Ally X20 (SSID 1954) the BIOS
provides the speaker ID in a 4-byte SPEAKER_ID EFI variable, and only
the four-field 1954-*-*-0x*.bin files exist.

Read SPEAKER_ID once at probe and try the firmware names in a fixed
order: the four-field name when the variable is present, then the
current SSID-LINK-0xUID name and the unprefixed SSID-LINK-UID one.
Boards without the variable keep the current names and order.

Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 sound/soc/codecs/tas2783-sdw.c | 123 ++++++++++++++++++++++-----------
 1 file changed, 84 insertions(+), 39 deletions(-)

diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index a57230e01f755..02fe74d457bfc 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -46,6 +46,8 @@
 #define TAS2783_PROBE_TIMEOUT 5000
 #define TAS2783_CALI_GUID EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, \
 				   0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92)
+#define TAS2783_SPKID_GUID EFI_GUID(0xaa61eaaf, 0x6e83, 0x7523, 0xb0, \
+				    0xd0, 0x7d, 0xf7, 0x4b, 0xb2, 0x4a, 0x81)
 
 static const u32 tas2783_cali_reg[] = {
 	TAS2783_CAL_R0,
@@ -102,8 +104,13 @@ struct tas2783_prv {
 	wait_queue_head_t fw_wait;
 	bool fw_dl_task_done;
 	bool fw_dl_success;
-	/* use fallback fw name */
-	bool fw_use_fallback;
+	/* the file for the firmware name being tried is missing */
+	bool fw_missing;
+#if IS_ENABLED(CONFIG_PCI)
+	/* UEFI speaker ID */
+	u32 spk_id;
+	bool spk_id_valid;
+#endif
 };
 
 static const struct reg_default tas2783_reg_default[] = {
@@ -757,19 +764,11 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
 		goto out;
 	}
 
-	/* firmware binary not found*/
+	/* firmware binary not found, tas_io_init() tries the next name */
 	if (!fmw || !fmw->data) {
-		if (!tas_dev->fw_use_fallback) {
-			tas_dev->fw_use_fallback = true;
-			dev_info(tas_dev->dev,
-				"Failed to read preferred fw binary: %s, attempting fallback binary load\n",
-				tas_dev->rca_binaryname);
-		} else {
-			dev_err(tas_dev->dev,
-				"Failed to read fallback fw binary %s\n",
-				tas_dev->rca_binaryname);
-		}
-
+		tas_dev->fw_missing = true;
+		dev_info(tas_dev->dev, "Failed to read fw binary %s\n",
+			 tas_dev->rca_binaryname);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1156,42 +1155,79 @@ static const struct dev_pm_ops tas2783_sdca_pm = {
 	RUNTIME_PM_OPS(tas2783_sdca_dev_suspend, tas2783_sdca_dev_resume, NULL)
 };
 
-static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t size)
+#if IS_ENABLED(CONFIG_PCI)
+/* BIOS speaker ID that selects the SSID-SPKID-LINK-UID firmware name */
+static int tas2783_get_spk_id(u32 *spk_id)
+{
+	efi_guid_t guid = TAS2783_SPKID_GUID;
+	unsigned long size = sizeof(*spk_id);
+	efi_status_t status;
+
+	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+		return -ENOENT;
+
+	status = efi.get_variable(L"SPEAKER_ID", &guid, NULL, &size, spk_id);
+	if (status != EFI_SUCCESS || size != sizeof(*spk_id))
+		return -ENOENT;
+
+	return 0;
+}
+#endif
+
+/*
+ * Firmware names in the order they are tried: SSID-SPKID-LINK-0xUID when the
+ * BIOS has a speaker ID, then SSID-LINK-0xUID and SSID-LINK-UID.
+ */
+static bool tas_generate_fw_name(struct sdw_slave *slave, unsigned int idx,
+				 char *name, size_t size)
 {
 	struct sdw_bus *bus = slave->bus;
 	u8 unique_id = slave->id.unique_id;
-	bool pci_found = false;
 #if IS_ENABLED(CONFIG_PCI)
-	struct device *dev = &slave->dev;
 	struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
-	struct pci_dev *pci = NULL;
-	const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
-
-	for (; dev; dev = dev->parent) {
-		if (dev->bus == &pci_bus_type) {
-			pci = to_pci_dev(dev);
-			scnprintf(name, size, "%04X-%1X-%s%1X.bin",
-				  pci->subsystem_device, bus->link_id,
-				  fw_uid_prefix, unique_id);
-			pci_found = true;
-			break;
+	struct device *dev;
+
+	for (dev = &slave->dev; dev; dev = dev->parent) {
+		u16 ssid;
+
+		if (dev->bus != &pci_bus_type)
+			continue;
+
+		ssid = to_pci_dev(dev)->subsystem_device;
+		if (!tas_dev->spk_id_valid)
+			idx++;
+
+		switch (idx) {
+		case 0:
+			scnprintf(name, size, "%04X-%X-%1X-0x%1X.bin", ssid,
+				  tas_dev->spk_id, bus->link_id, unique_id);
+			return true;
+		case 1:
+			scnprintf(name, size, "%04X-%1X-0x%1X.bin", ssid,
+				  bus->link_id, unique_id);
+			return true;
+		case 2:
+			scnprintf(name, size, "%04X-%1X-%1X.bin", ssid,
+				  bus->link_id, unique_id);
+			return true;
+		default:
+			return false;
 		}
 	}
 #endif
 
-	if (!pci_found)
-		scnprintf(name, size, "tas2783-%1X-%1X.bin",
-			  bus->link_id, unique_id);
+	if (idx)
+		return false;
+
+	scnprintf(name, size, "tas2783-%1X-%1X.bin", bus->link_id, unique_id);
+	return true;
 }
 
-static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
+static s32 tas_fw_load(struct tas2783_prv *tas_dev)
 {
 	s32 ret;
 	u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
 
-	tas_generate_fw_name(slave, tas_dev->rca_binaryname,
-			     sizeof(tas_dev->rca_binaryname));
-
 	tas_dev->fw_dl_task_done = false;
 	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
 				      tas_dev->rca_binaryname, tas_dev->dev,
@@ -1216,6 +1252,7 @@ static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
 static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
 {
 	struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+	unsigned int i;
 	s32 ret;
 
 	if (tas_dev->hw_init)
@@ -1230,10 +1267,15 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
 	}
 	usleep_range(2000, 2200);
 
-	tas_dev->fw_use_fallback = false;
-	ret = tas_fw_load(tas_dev, slave);
-	if (!ret && tas_dev->fw_use_fallback)
-		ret = tas_fw_load(tas_dev, slave);
+	for (i = 0; tas_generate_fw_name(slave, i, tas_dev->rca_binaryname,
+					 sizeof(tas_dev->rca_binaryname)); i++) {
+		tas_dev->fw_missing = false;
+		ret = tas_fw_load(tas_dev);
+		if (ret || !tas_dev->fw_missing)
+			break;
+	}
+	if (tas_dev->fw_missing)
+		dev_err(dev, "no firmware binary found\n");
 
 	if (!ret) {
 		if (tas_dev->sa_func_data)
@@ -1427,6 +1469,9 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
 	tas_dev->fw_version = 0;
 	mutex_init(&tas_dev->calib_lock);
 	mutex_init(&tas_dev->pde_lock);
+#if IS_ENABLED(CONFIG_PCI)
+	tas_dev->spk_id_valid = !tas2783_get_spk_id(&tas_dev->spk_id);
+#endif
 
 	init_waitqueue_head(&tas_dev->fw_wait);
 	dev_set_drvdata(dev, tas_dev);
-- 
2.56.0


  parent reply	other threads:[~2026-11-03 20:07 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
2026-11-03 20:05 ` Matthew Schwartz [this message]
2026-11-03 20:05 ` [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
2026-11-04  3:01   ` Liao, Bard
2026-11-03 20:05 ` [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz

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=20261103200540.3863272-4-matthew.schwartz@linux.dev \
    --to=matthew.schwartz@linux.dev \
    --cc=baojun.xu@ti.com \
    --cc=broonie@kernel.org \
    --cc=kevin-lu@ti.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=sen@ti.com \
    --cc=shenghao-ding@ti.com \
    --cc=tiwai@suse.com \
    /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

all inboxes | Powered by JetHome®