2021-10-15 17:17:42 +00:00
|
|
|
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/drivers/net/wireless/ath/ath10k/core.c
|
|
|
|
+++ b/drivers/net/wireless/ath/ath10k/core.c
|
|
|
|
@@ -12,6 +12,7 @@
|
|
|
|
#include <linux/dmi.h>
|
|
|
|
#include <linux/ctype.h>
|
|
|
|
#include <linux/pm_qos.h>
|
|
|
|
+#include <linux/nvmem-consumer.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
|
|
|
|
|
|
#include "core.h"
|
2022-04-05 22:29:44 +00:00
|
|
|
@@ -952,7 +953,8 @@ static int ath10k_core_get_board_id_from
|
2021-10-15 17:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2021-11-30 09:37:41 +00:00
|
|
|
@@ -1754,7 +1756,8 @@ static int ath10k_download_and_run_otp(s
|
2021-10-15 17:17:42 +00:00
|
|
|
|
|
|
|
/* 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);
|
2021-11-30 09:37:41 +00:00
|
|
|
@@ -1881,6 +1884,39 @@ out_free:
|
2021-10-15 17:17:42 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
+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)
|
|
|
|
{
|
2021-11-30 09:37:41 +00:00
|
|
|
@@ -2115,6 +2151,18 @@ static int ath10k_core_pre_cal_download(
|
2021-10-15 17:17:42 +00:00
|
|
|
{
|
|
|
|
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;
|
2021-11-30 09:37:41 +00:00
|
|
|
@@ -2181,6 +2229,18 @@ static int ath10k_download_cal_data(stru
|
2021-10-15 17:17:42 +00:00
|
|
|
"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/drivers/net/wireless/ath/ath10k/core.h
|
|
|
|
+++ b/drivers/net/wireless/ath/ath10k/core.h
|
|
|
|
@@ -877,8 +877,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,
|
|
|
|
};
|
|
|
|
|
|
|
|
@@ -898,10 +900,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";
|
|
|
|
}
|