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: 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®