@@ -13,6 +13,10 @@
#include "hif.h"
#include <linux/remoteproc.h>
+#define CORE_TOP_CSR_OFFSET 0x01900000
+#define CORE_TOP_CSR_SIZE 0x100000
+#define TCSR_SOC_HW_VERSION 0x4D000
+
static const struct of_device_id ath11k_ahb_of_match[] = {
/* TODO: Should we change the compatible string to something similar
* to one that ath10k uses?
@@ -650,6 +654,44 @@ static int ath11k_core_get_rproc(struct ath11k_base *ab)
return 0;
}
+static int ath11k_check_hw_version(struct ath11k_base *ab)
+{
+ void __iomem *mem_core;
+ u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
+
+ switch (ab->hw_rev) {
+ case ATH11K_HW_IPQ8074:
+ case ATH11K_HW_IPQ6018_HW10:
+ /* CORE_TOP_CSR register is out of wcss */
+ mem_core = ioremap(CORE_TOP_CSR_OFFSET, CORE_TOP_CSR_SIZE);
+ if (IS_ERR(mem_core)) {
+ ath11k_err(ab, "core_top_csr ioremap error\n");
+ return -ENOMEM;
+ }
+ soc_hw_version = ioread32(mem_core + TCSR_SOC_HW_VERSION);
+ iounmap(mem_core);
+ soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
+ soc_hw_version);
+ soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
+ soc_hw_version);
+
+ ath11k_dbg(ab, ATH11K_DBG_AHB, "tcsr_soc_hw_version major %u minor %u\n",
+ soc_hw_version_major,
+ soc_hw_version_minor);
+
+ if (soc_hw_version_major != ath11k_hw_version[ab->hw_rev]) {
+ ath11k_err(ab, "Unsupported SOC hardware version: %u\n",
+ soc_hw_version_major);
+ return -EOPNOTSUPP;
+ }
+ break;
+ default:
+ ath11k_err(ab, "Unknown hw_ver: %u\n", ab->hw_rev);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
static int ath11k_ahb_probe(struct platform_device *pdev)
{
struct ath11k_base *ab;
@@ -691,6 +733,10 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
ab->mem_len = resource_size(mem_res);
platform_set_drvdata(pdev, ab);
+ ret = ath11k_check_hw_version(ab);
+ if (ret)
+ goto err_core_free;
+
ret = ath11k_core_pre_init(ab);
if (ret)
goto err_core_free;
@@ -916,6 +916,19 @@ struct ath11k_fw_stats_bcn {
u32 tx_bcn_outage_cnt;
};
+#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(15, 8)
+#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0)
+#define ATH11K_HW_VERSION_HW10 1
+#define ATH11K_HW_VERSION_HW20 2
+
+static const u32 ath11k_hw_version[] = {
+ [ATH11K_HW_IPQ8074] = ATH11K_HW_VERSION_HW20,
+ [ATH11K_HW_QCA6390_HW20] = ATH11K_HW_VERSION_HW20,
+ [ATH11K_HW_IPQ6018_HW10] = ATH11K_HW_VERSION_HW10,
+ [ATH11K_HW_QCN9074_HW10] = ATH11K_HW_VERSION_HW10,
+ [ATH11K_HW_WCN6855_HW20] = ATH11K_HW_VERSION_HW20,
+};
+
extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[];
extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[];
extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[];
@@ -25,8 +25,7 @@
#define WINDOW_RANGE_MASK GENMASK(18, 0)
#define TCSR_SOC_HW_VERSION 0x0224
-#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8)
-#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0)
+#define QCN9074_TCSR_SOC_HW_VERSION 0x1B00000
/* BAR0 + 4k is always accessible, and no
* need to force wakeup.
@@ -1206,11 +1205,12 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
};
-static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
+static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 offset,
+ u32 *major, u32 *minor)
{
u32 soc_hw_version;
- soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
+ soc_hw_version = ath11k_pci_read32(ab, offset);
*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
soc_hw_version);
*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
@@ -1253,10 +1253,11 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
switch (pci_dev->device) {
case QCA6390_DEVICE_ID:
- ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
+ ath11k_pci_read_hw_version(ab, TCSR_SOC_HW_VERSION,
+ &soc_hw_version_major,
&soc_hw_version_minor);
switch (soc_hw_version_major) {
- case 2:
+ case ATH11K_HW_VERSION_HW20:
ab->hw_rev = ATH11K_HW_QCA6390_HW20;
break;
default:
@@ -1268,15 +1269,28 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
ab_pci->msi_config = &ath11k_msi_config[0];
break;
case QCN9074_DEVICE_ID:
+ ath11k_pci_read_hw_version(ab, QCN9074_TCSR_SOC_HW_VERSION,
+ &soc_hw_version_major,
+ &soc_hw_version_minor);
+ switch (soc_hw_version_major) {
+ case ATH11K_HW_VERSION_HW10:
+ ab->hw_rev = ATH11K_HW_QCN9074_HW10;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported QCN9074 SOC hardware version: %d %d\n",
+ soc_hw_version_major, soc_hw_version_minor);
+ ret = -EOPNOTSUPP;
+ goto err_pci_free_region;
+ }
ab_pci->msi_config = &ath11k_msi_config[1];
ab->bus_params.static_window_map = true;
- ab->hw_rev = ATH11K_HW_QCN9074_HW10;
break;
case WCN6855_DEVICE_ID:
- ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
+ ath11k_pci_read_hw_version(ab, TCSR_SOC_HW_VERSION,
+ &soc_hw_version_major,
&soc_hw_version_minor);
switch (soc_hw_version_major) {
- case 2:
+ case ATH11K_HW_VERSION_HW20:
ab->hw_rev = ATH11K_HW_WCN6855_HW20;
break;
default:
Read register TCSR_SOC_HW_VERSION for hardware version. This register is present in all hardwares. Check whether the hardware version is supported. Returns error if the hardware is unsupported. This handling is already done for QCA6390 and WCN6855. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 Tested-on: IPQ6018 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 Signed-off-by: Seevalamuthu Mariappan <quic_seevalam@quicinc.com> --- drivers/net/wireless/ath/ath11k/ahb.c | 46 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h | 13 ++++++++++ drivers/net/wireless/ath/ath11k/pci.c | 32 ++++++++++++++++------- 3 files changed, 82 insertions(+), 9 deletions(-)