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
next prev parent reply other threads:[~2026-11-03 20:07 UTC|newest]
Thread overview: 9+ 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-04 11:36 ` Pierre-Louis Bossart
2026-11-03 20:05 ` [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
2026-11-04 11:44 ` Pierre-Louis Bossart
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.