mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
306 lines
8.9 KiB
Diff
306 lines
8.9 KiB
Diff
From ef5a3345d6af58fbfa5d9b1ae2df11d6ac259498 Mon Sep 17 00:00:00 2001
|
|
From: spycat88 <spycat88@users.noreply.github.com>
|
|
Date: Thu, 23 Jan 2025 15:18:25 +0000
|
|
Subject: [PATCH] drivers: use soc serial for wifi and bluetooth
|
|
|
|
---
|
|
drivers/bluetooth/btqca.c | 100 ++++++++++++++++++++++-
|
|
drivers/soc/qcom/socinfo.c | 10 +++
|
|
drivers/net/wireless/ath/ath12k/mac.c | 109 ++++++++++++++++++++++++--
|
|
3 files changed, 209 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
|
|
index dfbbac92242a..dbe838040a67 100644
|
|
--- a/drivers/bluetooth/btqca.c
|
|
+++ b/drivers/bluetooth/btqca.c
|
|
@@ -13,6 +13,78 @@
|
|
|
|
#include "btqca.h"
|
|
|
|
+extern const char *qcom_serial_number;
|
|
+
|
|
+/* Define a static, predefined BD_ADDR structure */
|
|
+static const bdaddr_t static_bdaddr = {
|
|
+ .b = { 0x00, 0x03, 0x7F, 0x33, 0x22, 0x11 }
|
|
+};
|
|
+
|
|
+/**
|
|
+ * generate_bdaddr_from_serial - Generates a BD_ADDR using the serial number
|
|
+ * @bdaddr: Pointer to bdaddr_t structure to populate
|
|
+ *
|
|
+ * This function sets the first 3 bytes to 00:03:7F and the last 3 bytes
|
|
+ * are derived from the last 6 characters of qcom_serial_number in reversed order.
|
|
+ *
|
|
+ * Returns 0 on success, negative error code on failure.
|
|
+ */
|
|
+static int generate_bdaddr_from_serial(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|
+{
|
|
+ size_t serial_len;
|
|
+ const char *serial = qcom_serial_number;
|
|
+ char last6[7] = {0}; // 6 characters + null terminator
|
|
+ int i;
|
|
+ int ret;
|
|
+
|
|
+ if (!serial) {
|
|
+ bt_dev_err(hdev, "qcom_serial_number is NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ serial_len = strlen(serial);
|
|
+ if (serial_len < 6) {
|
|
+ bt_dev_err(hdev, "qcom_serial_number is too short: %zu characters", serial_len);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Extract the last 6 characters
|
|
+ strncpy(last6, serial + serial_len - 6, 6);
|
|
+
|
|
+ // Initialize the first 3 bytes
|
|
+ bdaddr->b[5] = 0x00;
|
|
+ bdaddr->b[4] = 0x03;
|
|
+ bdaddr->b[3] = 0x7F;
|
|
+
|
|
+ // Convert the last 6 characters into 3 bytes in reversed order
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ char byte_str[3] = {0};
|
|
+ u8 byte_val;
|
|
+
|
|
+ byte_str[0] = last6[i * 2];
|
|
+ byte_str[1] = last6[i * 2 + 1];
|
|
+
|
|
+ if (!isxdigit(byte_str[0]) || !isxdigit(byte_str[1])) {
|
|
+ bt_dev_err(hdev, "Invalid hex characters in serial number: %c%c",
|
|
+ byte_str[0], byte_str[1]);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = kstrtou8(byte_str, 16, &byte_val);
|
|
+ if (ret < 0) {
|
|
+ bt_dev_err(hdev, "Failed to convert hex string to u8: %c%c",
|
|
+ byte_str[0], byte_str[1]);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ bdaddr->b[i] = byte_val; // Assign to bytes 0,1,2 (reversed order)
|
|
+ }
|
|
+
|
|
+ bt_dev_info(hdev, "Generated BD_ADDR: %pMR", bdaddr);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
|
|
enum qca_btsoc_type soc_type)
|
|
{
|
|
@@ -668,7 +740,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
|
}
|
|
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
|
|
|
|
-static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
|
|
+static int __maybe_unused qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
|
|
{
|
|
struct hci_rp_read_bd_addr *bda;
|
|
struct sk_buff *skb;
|
|
@@ -739,6 +811,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
u8 rom_ver = 0;
|
|
u32 soc_ver;
|
|
u16 boardid = 0;
|
|
+ bdaddr_t generated_bdaddr;
|
|
|
|
bt_dev_dbg(hdev, "QCA setup on UART");
|
|
|
|
@@ -918,9 +991,30 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
break;
|
|
}
|
|
|
|
- err = qca_check_bdaddr(hdev, &config);
|
|
- if (err)
|
|
+ /* Generate BD_ADDR from qcom_serial_number */
|
|
+ err = generate_bdaddr_from_serial(hdev, &generated_bdaddr);
|
|
+ if (err) {
|
|
+ bt_dev_err(hdev, "Failed to generate BD_ADDR from serial number");
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ /* Set the generated BD_ADDR */
|
|
+ err = qca_set_bdaddr(hdev, &generated_bdaddr);
|
|
+ if (err) {
|
|
+ bt_dev_err(hdev, "Failed to set the generated BD_ADDR from serial number");
|
|
return err;
|
|
+ }
|
|
+
|
|
+ /* Update hdev->public_addr and hdev->bdaddr */
|
|
+ bacpy(&hdev->public_addr, &generated_bdaddr);
|
|
+ bacpy(&hdev->bdaddr, &generated_bdaddr);
|
|
+ bt_dev_info(hdev, "BD_ADDR set to %pMR", &hdev->public_addr);
|
|
+
|
|
+
|
|
+ /* Disable reading BD_ADDR from NVM */
|
|
+ //err = qca_check_bdaddr(hdev, &config);
|
|
+ //if (err)
|
|
+ // return err;
|
|
|
|
bt_dev_info(hdev, "QCA setup on UART is completed");
|
|
|
|
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
|
|
index ecfd3da9d5e8..238f804e7fe0 100644
|
|
--- a/drivers/soc/qcom/socinfo.c
|
|
+++ b/drivers/soc/qcom/socinfo.c
|
|
@@ -163,6 +163,10 @@ struct smem_image_version {
|
|
};
|
|
#endif /* CONFIG_DEBUG_FS */
|
|
|
|
+/* Global variable to hold the serial number */
|
|
+const char *qcom_serial_number;
|
|
+EXPORT_SYMBOL(qcom_serial_number);
|
|
+
|
|
struct qcom_socinfo {
|
|
struct soc_device *soc_dev;
|
|
struct soc_device_attribute attr;
|
|
@@ -795,6 +799,9 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
|
|
le32_to_cpu(info->serial_num));
|
|
if (!qs->attr.serial_number)
|
|
return -ENOMEM;
|
|
+
|
|
+ /* Assign the serial number to the global variable */
|
|
+ qcom_serial_number = qs->attr.serial_number;
|
|
}
|
|
|
|
qs->soc_dev = soc_device_register(&qs->attr);
|
|
@@ -818,6 +825,9 @@ static void qcom_socinfo_remove(struct platform_device *pdev)
|
|
soc_device_unregister(qs->soc_dev);
|
|
|
|
socinfo_debugfs_exit(qs);
|
|
+
|
|
+ /* Clear the global serial number */
|
|
+ qcom_serial_number = NULL;
|
|
}
|
|
|
|
static struct platform_driver qcom_socinfo_driver = {
|
|
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
|
|
index d493ec812055..0e535e96e27b 100644
|
|
--- a/drivers/net/wireless/ath/ath12k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/mac.c
|
|
@@ -159,6 +159,91 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = {
|
|
CHAN6G(233, 7115, 0),
|
|
};
|
|
|
|
+extern const char *qcom_serial_number;
|
|
+
|
|
+/* Define a small struct for storing a 6-byte MAC address array */
|
|
+struct macaddr_t {
|
|
+ u8 b[ETH_ALEN];
|
|
+};
|
|
+
|
|
+/* Define a static, predefined MAC_ADDR structure */
|
|
+static const struct macaddr_t static_macaddr = {
|
|
+ .b = { 0x00, 0x03, 0x7F, 0x11, 0x22, 0x33 }
|
|
+};
|
|
+
|
|
+/**
|
|
+ * generate_macaddr_from_serial - Generates a MAC_ADDR using the serial number
|
|
+ * @macaddr: Pointer to macaddr_t structure to populate
|
|
+ *
|
|
+ * This function sets the first 3 bytes to 00:03:7F and the last 3 bytes
|
|
+ * are derived from the last 6 characters of qcom_serial_number.
|
|
+ *
|
|
+ * Returns 0 on success, negative error code on failure.
|
|
+ */
|
|
+static int generate_macaddr_from_serial(struct ath12k *ar, struct macaddr_t *macaddr)
|
|
+{
|
|
+ size_t serial_len;
|
|
+ const char *serial = qcom_serial_number;
|
|
+ char last6[7] = {0}; // 6 characters + null terminator
|
|
+ int i;
|
|
+ int ret;
|
|
+
|
|
+ if (!serial) {
|
|
+ ath12k_err(ar->ab, "qcom_serial_number is NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ serial_len = strlen(serial);
|
|
+ if (serial_len < 6) {
|
|
+ ath12k_err(ar->ab, "qcom_serial_number is too short: %zu characters", serial_len);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Extract the last 6 characters
|
|
+ strncpy(last6, serial + serial_len - 6, 6);
|
|
+
|
|
+ // Initialize the first 3 bytes
|
|
+ macaddr->b[5] = 0x00;
|
|
+ macaddr->b[4] = 0x03;
|
|
+ macaddr->b[3] = 0x7F;
|
|
+
|
|
+ // Convert the last 6 characters into 3 bytes
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ char byte_str[3] = {0};
|
|
+ u8 byte_val;
|
|
+
|
|
+ byte_str[0] = last6[i * 2];
|
|
+ byte_str[1] = last6[i * 2 + 1];
|
|
+
|
|
+ if (!isxdigit(byte_str[0]) || !isxdigit(byte_str[1])) {
|
|
+ ath12k_err(ar->ab, "Invalid hex characters in serial number: %c%c",
|
|
+ byte_str[0], byte_str[1]);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = kstrtou8(byte_str, 16, &byte_val);
|
|
+ if (ret < 0) {
|
|
+ ath12k_err(ar->ab, "Failed to convert hex string to u8: %c%c",
|
|
+ byte_str[0], byte_str[1]);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ macaddr->b[2 - i] = byte_val; // Assign to bytes 2,1,0
|
|
+ }
|
|
+
|
|
+ ath12k_info(ar->ab, "Generated MAC_ADDR: %pMR", macaddr);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ath12k_reverse_mac(u8 *dst, const u8 *src)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ETH_ALEN; i++)
|
|
+ dst[i] = src[ETH_ALEN - 1 - i];
|
|
+}
|
|
+
|
|
static struct ieee80211_rate ath12k_legacy_rates[] = {
|
|
{ .bitrate = 10,
|
|
.hw_value = ATH12K_HW_RATE_CCK_LP_1M },
|
|
@@ -9533,6 +9618,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
|
|
struct ath12k_base *ab = ar->ab;
|
|
struct ath12k_pdev *pdev;
|
|
struct ath12k_pdev_cap *cap;
|
|
+ struct macaddr_t generated_macaddr;
|
|
static const u32 cipher_suites[] = {
|
|
WLAN_CIPHER_SUITE_TKIP,
|
|
WLAN_CIPHER_SUITE_CCMP,
|
|
@@ -9556,11 +9642,17 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
|
|
u32 ht_cap_info = 0;
|
|
|
|
pdev = ar->pdev;
|
|
- if (ar->ab->pdevs_macaddr_valid) {
|
|
- ether_addr_copy(ar->mac_addr, pdev->mac_addr);
|
|
+ ret = generate_macaddr_from_serial(ar, &generated_macaddr);
|
|
+ if (ret) {
|
|
+ if (ar->ab->pdevs_macaddr_valid) {
|
|
+ ether_addr_copy(ar->mac_addr, pdev->mac_addr);
|
|
+ } else {
|
|
+ ether_addr_copy(ar->mac_addr, ar->ab->mac_addr);
|
|
+ ar->mac_addr[4] += ar->pdev_idx;
|
|
+ }
|
|
} else {
|
|
- ether_addr_copy(ar->mac_addr, ar->ab->mac_addr);
|
|
- ar->mac_addr[4] += ar->pdev_idx;
|
|
+ ath12k_reverse_mac(ar->mac_addr, generated_macaddr.b);
|
|
+ ath12k_info(ab, "MAC_ADDR set to %pMR", generated_macaddr.b);
|
|
}
|
|
|
|
ret = ath12k_mac_setup_register(ar, &ht_cap_info, hw->wiphy->bands);
|