Merge "Add calibration data to qca9880_cal.py."
diff --git a/wifi/qca9880_cal.py b/wifi/qca9880_cal.py
index 4e5cc0c..134d138 100755
--- a/wifi/qca9880_cal.py
+++ b/wifi/qca9880_cal.py
@@ -9,6 +9,7 @@
import glob
import os
import os.path
+import struct
import experiment
import utils
@@ -23,9 +24,32 @@
VERSION_LEN = 3
SUSPECT_OUIS = ((0x28, 0x24, 0xff), (0x48, 0xa9, 0xd2), (0x60, 0x02, 0xb4),
(0xbc, 0x30, 0x7d), (0xbc, 0x30, 0x7e))
-MISCALIBRATED_VERSION_FIELD = (0x0, 0x0, 0x0)
MODULE_PATH = '/sys/class/net/{}/device/driver/module'
+# Each tuple starts with an offset, followed by a list of values to be
+# patched beginning at that offset.
+CAL_PATCH = ((0x050a, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0510, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0516, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x051c, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0531, (0x2a, 0x28, 0x26)),
+ (0x0535, (0x2a, 0x28, 0x26)),
+ (0x056b, (0xce, 0x8a, 0x66, 0x02, 0x68, 0x26, 0x80, 0x66)),
+ (0x05b4, (0x8a, 0x46, 0x02, 0x68, 0x24, 0x80, 0x46)),
+ (0x05c0, (0x8a, 0x46, 0x02, 0x68, 0x24, 0x80, 0x46)),
+ (0x05fc, (0x8c, 0x68, 0x02, 0x88, 0x26, 0x80)),
+ (0x0608, (0x8c, 0x68, 0x02, 0x88, 0x26, 0x80)))
+
+FCC_PATCH = ((0x0625, (0x50, 0x58, 0x5c, 0x8c, 0xbd, 0xc1, 0xcd,
+ 0x4c, 0x50, 0x58, 0x5c, 0x8c, 0xbd, 0xc1,
+ 0xcd, 0x4e, 0x56, 0x5e, 0x66, 0x8e)),
+ (0x06b4, (0x69, 0x6b, 0x6b, 0x62, 0x62, 0x6b, 0x6c,
+ 0x2d, 0x69, 0x6b, 0x6b, 0x62, 0x62, 0x6b,
+ 0x6d, 0x2d, 0x62, 0x6f, 0x68, 0x64, 0x64,
+ 0x68, 0x68, 0x2d, 0x5c, 0x60, 0x60, 0x66)))
+
+experiment.register(NO_CAL_EXPERIMENT)
+
def _log(msg):
utils.log('ath10k calibration: {}'.format(msg))
@@ -75,14 +99,23 @@
"""Check the QCA8990 module to see if it is improperly calibrated.
There are two manufacturers of the modules, Senao and Wistron of which only
- Wistron modules are suspect. Wistron provided a list of OUIs manufactured
- which are listed in SUSPECT_OUIS. Modules manufactured by Winstron containing
- V02 at offset VERSION_OFFSET have been corrected, while those containing 3
- zero's at this offset are still suspect and will be considered mis-calibrated.
+ Wistron modules are suspect. Wistron provided a list of suspect OUIs
+ which are listed in SUSPECT_OUIS.
+
+ The version field must also be checked, starting at offset VERSION_OFFSET.
+ If this fields is all zeros, then it is an implicit indication of V01,
+ otherwise it contains a version string.
+
+ V01 -- (version field contains 0's) These modules need both calibration and
+ FCC power limits patched.
+ V02 -- Only FCC power limits need to be patched
+ V03 -- No patching required.
Returns:
- True if module is mis-calibrated, None if it can't be determined, and False
- otherwise.
+ A tuple containing one or both of: fcc, cal. Or None.
+ 'fcc' -- FCC patching required.
+ 'cal' -- Calibration data patching required.
+ None -- No patching required.
"""
try:
@@ -94,7 +127,7 @@
f.seek(OUI_OFFSET)
oui = f.read(OUI_LEN)
f.seek(VERSION_OFFSET)
- version = f.read(VERSION_LEN)
+ version = struct.unpack('3s', f.read(VERSION_LEN))[0]
except IOError as e:
_log('unable to open cal_data {}: {}'.format(cal_data_path, e.strerror))
@@ -102,17 +135,27 @@
if oui not in (bytearray(s) for s in SUSPECT_OUIS):
_log('OUI {} is properly calibrated.'.format(_oui_string(oui)))
- return False
+ # Create an empty directory so this script short-circuits if run again.
+ _create_calibration_dir()
+ return None
- if version != (bytearray(MISCALIBRATED_VERSION_FIELD)):
- _log('version field {} signals proper calibration.'.
- format(_version_string(version)))
- return False
+ # V01 is retroactively represented not by a string, but by 3 0 value bytes.
+ if version == '\x00\x00\x00':
+ _log('version field is V01. CAL + FCC calibration required.')
+ return ('fcc', 'cal')
- _log('May be mis-calibrated. OUI: {} version: {}'.
- format(_oui_string(oui), _version_string(version)))
+ if version == 'V02':
+ _log('version field is V02. Only FCC calibration required.')
+ return ('fcc',)
- return True
+ if version == 'V03':
+ _log('version field is V03. No patching required.')
+ # Create an empty directory so this script short-circuits if run again.
+ _create_calibration_dir()
+ return None
+
+ _log('version field unknown: {}'.format(version))
+ return None
def _is_previously_calibrated():
@@ -160,9 +203,18 @@
return glob.glob(ATH10K_CAL_DATA)[0]
-def _generate_calibration_patch():
+def _apply_patch(msg, cal_data, patch):
+ _log(msg)
+ for offset, values in patch:
+ cal_data[offset:offset + len(values)] = values
+
+
+def _generate_calibration_patch(calibration_state):
"""Create calibration patch and write to storage.
+ Args:
+ calibration_state: data from ath10k to be patched.
+
Returns:
True for success or False for failure.
"""
@@ -174,11 +226,12 @@
format(_ath10k_cal_data_path(), e.strerror))
return False
- # Patch cal_data here once we get the actual calibration data.
- # For now just return False until we get the data.
- _log('patch not generated as data not supplied yet.')
- # pylint: disable=unreachable
- return False
+ # Actual calibration starts here.
+ if 'cal' in calibration_state:
+ _apply_patch('Applying CAL patch...', cal_data, CAL_PATCH)
+
+ if 'fcc' in calibration_state:
+ _apply_patch('Applying FCC patch...', cal_data, FCC_PATCH)
if not _create_calibration_dir():
return False
@@ -223,15 +276,9 @@
_log('this platform does not use ath10k.')
return
- cal_result = _is_module_miscalibrated()
- if cal_result is None:
- _log('unknown if miscalibrated.')
- elif not cal_result:
- _log('module is NOT miscalibrated.')
- # Creating an empty directory signals that this script has already run.
- _create_calibration_dir()
- else:
- if _generate_calibration_patch():
+ calibration_state = _is_module_miscalibrated()
+ if calibration_state is not None:
+ if _generate_calibration_patch(calibration_state):
_log('generated new patch.')
_reload_driver()