ath10k: support nvmem-cells for (pre-)calibration
[openwrt/openwrt.git] / package / kernel / ath10k-ct / patches / 120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch
diff --git a/package/kernel/ath10k-ct/patches/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch b/package/kernel/ath10k-ct/patches/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch
new file mode 100644 (file)
index 0000000..2a4b09a
--- /dev/null
@@ -0,0 +1,162 @@
+From e2333703373e8b81294da5d1c73c30154f75b082 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Fri, 15 Oct 2021 18:56:33 +0200
+Subject: [PATCH] ath10k: fetch (pre-)calibration data via nvmem subsystem
+
+On most embedded ath10k devices (like range extenders,
+routers, accesspoints, ...) the calibration data is
+stored in a easily accessible MTD partitions named
+"ART", "caldata", "calibration", etc...
+
+Since commit 4b361cfa8624 ("mtd: core: add OTP nvmem provider support"):
+MTD partitions and portions of them can be specified
+as potential nvmem-cells which are accessible through
+the nvmem subsystem.
+
+This feature - together with an nvmem cell definition either
+in the platform data or via device-tree allows drivers to get
+the (pre-)calibration data which is required for initializing
+the WIFI.
+
+Tested with Netgear EX6150v2 (IPQ4018)
+
+Cc: Robert Marko <robimarko@gmail.com>
+Cc: Thibaut Varene <hacks@slashdirt.org>
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+---
+--- a/ath10k-5.15/core.c
++++ b/ath10k-5.15/core.c
+@@ -13,6 +13,7 @@
+ #include <linux/dmi.h>
+ #include <linux/ctype.h>
+ #include <linux/pm_qos.h>
++#include <linux/nvmem-consumer.h>
+ #include <asm/byteorder.h>
+ #include <linux/ctype.h>
+@@ -988,7 +989,8 @@ static int ath10k_core_get_board_id_from
+       }
+       if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+-          ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
++          ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||
++          ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)
+               bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;
+       else
+               bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;
+@@ -2087,7 +2089,8 @@ static int ath10k_download_and_run_otp(s
+       /* As of now pre-cal is valid for 10_4 variants */
+       if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+-          ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
++          ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||
++          ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)
+               bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
+       ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
+@@ -2221,6 +2224,39 @@ struct ath10k_bss_rom_ie {
+       __le32 rom_len;
+ } __packed;
++static int ath10k_download_cal_nvmem(struct ath10k *ar, const char *cell_name)
++{
++      struct nvmem_cell *cell;
++      void *buf;
++      size_t len;
++      int ret;
++
++      cell = devm_nvmem_cell_get(ar->dev, cell_name);
++      if (IS_ERR(cell)) {
++              ret = PTR_ERR(cell);
++              return ret;
++      }
++
++      buf = nvmem_cell_read(cell, &len);
++      if (IS_ERR(buf))
++              return PTR_ERR(buf);
++
++      if (ar->hw_params.cal_data_len != len) {
++              kfree(buf);
++              ath10k_warn(ar, "invalid calibration data length in nvmem-cell '%s': %zu != %u\n",
++                          cell_name, len, ar->hw_params.cal_data_len);
++              return -EMSGSIZE;
++      }
++
++      ret = ath10k_download_board_data(ar, buf, len);
++      kfree(buf);
++      if (ret)
++              ath10k_warn(ar, "failed to download calibration data from nvmem-cell '%s': %d\n",
++                          cell_name, ret);
++
++      return ret;
++}
++
+ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
+                                    struct ath10k_fw_file *fw_file)
+ {
+@@ -2597,6 +2633,18 @@ static int ath10k_core_pre_cal_download(
+ {
+       int ret;
++      ret = ath10k_download_cal_nvmem(ar, "pre-calibration");
++      if (ret == 0) {
++              ar->cal_mode = ATH10K_PRE_CAL_MODE_NVMEM;
++              goto success;
++      } else if (ret == -EPROBE_DEFER) {
++              return ret;
++      }
++
++      ath10k_dbg(ar, ATH10K_DBG_BOOT,
++                 "boot did not find a pre-calibration nvmem-cell, try file next: %d\n",
++                 ret);
++
+       ret = ath10k_download_cal_file(ar, ar->pre_cal_file);
+       if (ret == 0) {
+               ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;
+@@ -2663,6 +2711,18 @@ static int ath10k_download_cal_data(stru
+                  "pre cal download procedure failed, try cal file: %d\n",
+                  ret);
++      ret = ath10k_download_cal_nvmem(ar, "calibration");
++      if (ret == 0) {
++              ar->cal_mode = ATH10K_CAL_MODE_NVMEM;
++              goto done;
++      } else if (ret == -EPROBE_DEFER) {
++              return ret;
++      }
++
++      ath10k_dbg(ar, ATH10K_DBG_BOOT,
++                 "boot did not find a calibration nvmem-cell, try file next: %d\n",
++                 ret);
++
+       ret = ath10k_download_cal_file(ar, ar->cal_file);
+       if (ret == 0) {
+               ar->cal_mode = ATH10K_CAL_MODE_FILE;
+--- a/ath10k-5.15/core.h
++++ b/ath10k-5.15/core.h
+@@ -1109,8 +1109,10 @@ enum ath10k_cal_mode {
+       ATH10K_CAL_MODE_FILE,
+       ATH10K_CAL_MODE_OTP,
+       ATH10K_CAL_MODE_DT,
++      ATH10K_CAL_MODE_NVMEM,
+       ATH10K_PRE_CAL_MODE_FILE,
+       ATH10K_PRE_CAL_MODE_DT,
++      ATH10K_PRE_CAL_MODE_NVMEM,
+       ATH10K_CAL_MODE_EEPROM,
+ };
+@@ -1130,10 +1132,14 @@ static inline const char *ath10k_cal_mod
+               return "otp";
+       case ATH10K_CAL_MODE_DT:
+               return "dt";
++      case ATH10K_CAL_MODE_NVMEM:
++              return "nvmem";
+       case ATH10K_PRE_CAL_MODE_FILE:
+               return "pre-cal-file";
+       case ATH10K_PRE_CAL_MODE_DT:
+               return "pre-cal-dt";
++      case ATH10K_PRE_CAL_MODE_NVMEM:
++              return "pre-cal-nvmem";
+       case ATH10K_CAL_MODE_EEPROM:
+               return "eeprom";
+       }