Skip to content

Commit a4c5a46

Browse files
Cheng JiangVudentz
authored andcommitted
Bluetooth: qca: Update firmware-name to support board specific nvm
Different connectivity boards may be attached to the same platform. For example, QCA6698-based boards can support either a two-antenna or three-antenna solution, both of which work on the sa8775p-ride platform. Due to differences in connectivity boards and variations in RF performance from different foundries, different NVM configurations are used based on the board ID. Therefore, in the firmware-name property, if the NVM file has an extension, the NVM file will be used. Otherwise, the system will first try the .bNN (board ID) file, and if that fails, it will fall back to the .bin file. Possible configurations: firmware-name = "QCA6698/hpnv21"; firmware-name = "QCA6698/hpnv21.bin"; Signed-off-by: Cheng Jiang <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 86029c6 commit a4c5a46

File tree

1 file changed

+85
-28
lines changed

1 file changed

+85
-28
lines changed

drivers/bluetooth/btqca.c

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,39 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
272272
}
273273
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
274274

275+
static bool qca_filename_has_extension(const char *filename)
276+
{
277+
const char *suffix = strrchr(filename, '.');
278+
279+
/* File extensions require a dot, but not as the first or last character */
280+
if (!suffix || suffix == filename || *(suffix + 1) == '\0')
281+
return 0;
282+
283+
/* Avoid matching directories with names that look like files with extensions */
284+
return !strchr(suffix, '/');
285+
}
286+
287+
static bool qca_get_alt_nvm_file(char *filename, size_t max_size)
288+
{
289+
char fwname[64];
290+
const char *suffix;
291+
292+
/* nvm file name has an extension, replace with .bin */
293+
if (qca_filename_has_extension(filename)) {
294+
suffix = strrchr(filename, '.');
295+
strscpy(fwname, filename, suffix - filename + 1);
296+
snprintf(fwname + (suffix - filename),
297+
sizeof(fwname) - (suffix - filename), ".bin");
298+
/* If nvm file is already the default one, return false to skip the retry. */
299+
if (strcmp(fwname, filename) == 0)
300+
return false;
301+
302+
snprintf(filename, max_size, "%s", fwname);
303+
return true;
304+
}
305+
return false;
306+
}
307+
275308
static int qca_tlv_check_data(struct hci_dev *hdev,
276309
struct qca_fw_config *config,
277310
u8 *fw_data, size_t fw_size,
@@ -564,6 +597,19 @@ static int qca_download_firmware(struct hci_dev *hdev,
564597
config->fwname, ret);
565598
return ret;
566599
}
600+
}
601+
/* If the board-specific file is missing, try loading the default
602+
* one, unless that was attempted already.
603+
*/
604+
else if (config->type == TLV_TYPE_NVM &&
605+
qca_get_alt_nvm_file(config->fwname, sizeof(config->fwname))) {
606+
bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
607+
ret = request_firmware(&fw, config->fwname, &hdev->dev);
608+
if (ret) {
609+
bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
610+
config->fwname, ret);
611+
return ret;
612+
}
567613
} else {
568614
bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
569615
config->fwname, ret);
@@ -700,34 +746,38 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
700746
return 0;
701747
}
702748

703-
static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size,
749+
static void qca_get_nvm_name_by_board(char *fwname, size_t max_size,
750+
const char *stem, enum qca_btsoc_type soc_type,
704751
struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
705752
{
706753
const char *variant;
754+
const char *prefix;
707755

708-
/* hsp gf chip */
709-
if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
710-
variant = "g";
711-
else
712-
variant = "";
756+
/* Set the default value to variant and prefix */
757+
variant = "";
758+
prefix = "b";
713759

714-
if (bid == 0x0)
715-
snprintf(fwname, max_size, "qca/hpnv%02x%s.bin", rom_ver, variant);
716-
else
717-
snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid);
718-
}
760+
if (soc_type == QCA_QCA2066)
761+
prefix = "";
719762

720-
static inline void qca_get_nvm_name_generic(struct qca_fw_config *cfg,
721-
const char *stem, u8 rom_ver, u16 bid)
722-
{
723-
if (bid == 0x0)
724-
snprintf(cfg->fwname, sizeof(cfg->fwname), "qca/%snv%02x.bin", stem, rom_ver);
725-
else if (bid & 0xff00)
726-
snprintf(cfg->fwname, sizeof(cfg->fwname),
727-
"qca/%snv%02x.b%x", stem, rom_ver, bid);
728-
else
729-
snprintf(cfg->fwname, sizeof(cfg->fwname),
730-
"qca/%snv%02x.b%02x", stem, rom_ver, bid);
763+
if (soc_type == QCA_WCN6855 || soc_type == QCA_QCA2066) {
764+
/* If the chip is manufactured by GlobalFoundries */
765+
if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
766+
variant = "g";
767+
}
768+
769+
if (rom_ver != 0) {
770+
if (bid == 0x0 || bid == 0xffff)
771+
snprintf(fwname, max_size, "qca/%s%02x%s.bin", stem, rom_ver, variant);
772+
else
773+
snprintf(fwname, max_size, "qca/%s%02x%s.%s%02x", stem, rom_ver,
774+
variant, prefix, bid);
775+
} else {
776+
if (bid == 0x0 || bid == 0xffff)
777+
snprintf(fwname, max_size, "qca/%s%s.bin", stem, variant);
778+
else
779+
snprintf(fwname, max_size, "qca/%s%s.%s%02x", stem, variant, prefix, bid);
780+
}
731781
}
732782

733783
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
@@ -816,8 +866,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
816866
/* Download NVM configuration */
817867
config.type = TLV_TYPE_NVM;
818868
if (firmware_name) {
819-
snprintf(config.fwname, sizeof(config.fwname),
820-
"qca/%s", firmware_name);
869+
/* The firmware name has an extension, use it directly */
870+
if (qca_filename_has_extension(firmware_name)) {
871+
snprintf(config.fwname, sizeof(config.fwname), "qca/%s", firmware_name);
872+
} else {
873+
qca_read_fw_board_id(hdev, &boardid);
874+
qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
875+
firmware_name, soc_type, ver, 0, boardid);
876+
}
821877
} else {
822878
switch (soc_type) {
823879
case QCA_WCN3990:
@@ -836,8 +892,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
836892
"qca/apnv%02x.bin", rom_ver);
837893
break;
838894
case QCA_QCA2066:
839-
qca_generate_hsp_nvm_name(config.fwname,
840-
sizeof(config.fwname), ver, rom_ver, boardid);
895+
qca_get_nvm_name_by_board(config.fwname,
896+
sizeof(config.fwname), "hpnv", soc_type, ver,
897+
rom_ver, boardid);
841898
break;
842899
case QCA_QCA6390:
843900
snprintf(config.fwname, sizeof(config.fwname),
@@ -852,9 +909,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
852909
"qca/hpnv%02x.bin", rom_ver);
853910
break;
854911
case QCA_WCN7850:
855-
qca_get_nvm_name_generic(&config, "hmt", rom_ver, boardid);
912+
qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
913+
"hmtnv", soc_type, ver, rom_ver, boardid);
856914
break;
857-
858915
default:
859916
snprintf(config.fwname, sizeof(config.fwname),
860917
"qca/nvm_%08x.bin", soc_ver);

0 commit comments

Comments
 (0)