All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices
@ 2022-05-24 11:33 viktor.barna
  2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
                   ` (95 more replies)
  0 siblings, 96 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

Celeno Communications publishes to the opensource new wireless driver
for an own 802.11 chipset family - 80xx. The main chip supports multiple
simultaneous bands functioning (2.4G/5.2G or 5.2G/6G) over PCIe 3.0
dual-lane interface. Basically, the chip is dual-band concurrent up to
8x8 in total, and up to 6x6 per band, including 802.11ax 160MHz support
and functioning of AP/STA/MESH modes. The driver architecture is strong
SoftMAC.

The current patchset is the second one and is considered to be published 
in form of RFC (Request for Comments, version 2). If there are any
suggestions/propositions - we will be glad to fix them and
eventually share the driver with the community in form of an official patch
(including the firmware binaries).

The RFC is divided into separate patches on a per-file basis to simplify
the review process.

Known issues:
- driver may be configured via config files, that is discouraged by
  upstream and may be changed in the future.

Signed-off-by: Aviad Brikman <aviad.brikman@celeno.com>
Signed-off-by: Eliav Farber <eliav.farber@gmail.com>
Signed-off-by: Maksym Kokhan <maksym.kokhan@celeno.com>
Signed-off-by: Oleksandr Savchenko <oleksandr.savchenko@celeno.com>
Signed-off-by: Shay Bar <shay.bar@celeno.com>
Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
v2: 
- Reduce files amount from 256 to 98 (including 43 source files).
- Fix Kconfig vs code inconsistencies.
- Remove Celeno-specific wrappers like cl_snprintf, cl_timer, string
  processors.
- Namespace more functions (with cl_<something>).
- Remove DEV_COREDUMP support (temporary. to minimize size of the RFC).
- Remove CLI handling in the driver (forever, reimplement some of the features
  in the debugfs). 
- Remove netlink vendor-specific commands.
- Remove debugfs code.
- Fix sparse warnings.
- Fix more checkpatch errors/warnings/checks.
- Update codebase to the most recent internal codebase (as of 20.05.22).
- Adjust patch to support Kernel 5.18-rc7.
 
v1: 
- https://lore.kernel.org/linux-wireless/20210617160223.160998-1-viktor.barna@celeno.com/

Viktor Barna (96):
  celeno: add Kconfig
  celeno: add Makefile
  cl8k: add Kconfig
  cl8k: add Makefile
  cl8k: add ampdu.c
  cl8k: add ampdu.h
  cl8k: add bf.c
  cl8k: add bf.h
  cl8k: add calib.c
  cl8k: add calib.h
  cl8k: add channel.c
  cl8k: add channel.h
  cl8k: add chip.c
  cl8k: add chip.h
  cl8k: add config.c
  cl8k: add config.h
  cl8k: add debug.c
  cl8k: add debug.h
  cl8k: add def.h
  cl8k: add dfs.c
  cl8k: add dfs.h
  cl8k: add dsp.c
  cl8k: add dsp.h
  cl8k: add e2p.c
  cl8k: add e2p.h
  cl8k: add eeprom.h
  cl8k: add ela.c
  cl8k: add ela.h
  cl8k: add enhanced_tim.c
  cl8k: add enhanced_tim.h
  cl8k: add fw.c
  cl8k: add fw.h
  cl8k: add hw.c
  cl8k: add hw.h
  cl8k: add ipc_shared.h
  cl8k: add key.c
  cl8k: add key.h
  cl8k: add mac80211.c
  cl8k: add mac80211.h
  cl8k: add mac_addr.c
  cl8k: add mac_addr.h
  cl8k: add main.c
  cl8k: add main.h
  cl8k: add maintenance.c
  cl8k: add maintenance.h
  cl8k: add motion_sense.c
  cl8k: add motion_sense.h
  cl8k: add pci.c
  cl8k: add pci.h
  cl8k: add phy.c
  cl8k: add phy.h
  cl8k: add platform.c
  cl8k: add platform.h
  cl8k: add power.c
  cl8k: add power.h
  cl8k: add radio.c
  cl8k: add radio.h
  cl8k: add rates.c
  cl8k: add rates.h
  cl8k: add recovery.c
  cl8k: add recovery.h
  cl8k: add regdom.c
  cl8k: add regdom.h
  cl8k: add reg/reg_access.h
  cl8k: add reg/reg_defs.h
  cl8k: add rfic.c
  cl8k: add rfic.h
  cl8k: add rx.c
  cl8k: add rx.h
  cl8k: add scan.c
  cl8k: add scan.h
  cl8k: add sounding.c
  cl8k: add sounding.h
  cl8k: add sta.c
  cl8k: add sta.h
  cl8k: add stats.c
  cl8k: add stats.h
  cl8k: add tcv.c
  cl8k: add tcv.h
  cl8k: add temperature.c
  cl8k: add temperature.h
  cl8k: add traffic.c
  cl8k: add traffic.h
  cl8k: add tx.c
  cl8k: add tx.h
  cl8k: add utils.c
  cl8k: add utils.h
  cl8k: add version.c
  cl8k: add version.h
  cl8k: add vif.c
  cl8k: add vif.h
  cl8k: add vns.c
  cl8k: add vns.h
  cl8k: add wrs.c
  cl8k: add wrs.h
  wireless: add Celeno vendor

 drivers/net/wireless/Kconfig                  |    1 +
 drivers/net/wireless/Makefile                 |    1 +
 drivers/net/wireless/celeno/Kconfig           |   17 +
 drivers/net/wireless/celeno/Makefile          |    2 +
 drivers/net/wireless/celeno/cl8k/Kconfig      |   41 +
 drivers/net/wireless/celeno/cl8k/Makefile     |   66 +
 drivers/net/wireless/celeno/cl8k/ampdu.c      |  331 +
 drivers/net/wireless/celeno/cl8k/ampdu.h      |   39 +
 drivers/net/wireless/celeno/cl8k/bf.c         |  346 +
 drivers/net/wireless/celeno/cl8k/bf.h         |   52 +
 drivers/net/wireless/celeno/cl8k/calib.c      | 2266 ++++
 drivers/net/wireless/celeno/cl8k/calib.h      |  390 +
 drivers/net/wireless/celeno/cl8k/channel.c    | 1656 +++
 drivers/net/wireless/celeno/cl8k/channel.h    |  401 +
 drivers/net/wireless/celeno/cl8k/chip.c       |  580 +
 drivers/net/wireless/celeno/cl8k/chip.h       |  182 +
 drivers/net/wireless/celeno/cl8k/config.c     |   46 +
 drivers/net/wireless/celeno/cl8k/config.h     |  405 +
 drivers/net/wireless/celeno/cl8k/debug.c      |  442 +
 drivers/net/wireless/celeno/cl8k/debug.h      |  160 +
 drivers/net/wireless/celeno/cl8k/def.h        |  235 +
 drivers/net/wireless/celeno/cl8k/dfs.c        |  768 ++
 drivers/net/wireless/celeno/cl8k/dfs.h        |  146 +
 drivers/net/wireless/celeno/cl8k/dsp.c        |  627 ++
 drivers/net/wireless/celeno/cl8k/dsp.h        |   27 +
 drivers/net/wireless/celeno/cl8k/e2p.c        |  771 ++
 drivers/net/wireless/celeno/cl8k/e2p.h        |   25 +
 drivers/net/wireless/celeno/cl8k/eeprom.h     |  283 +
 drivers/net/wireless/celeno/cl8k/ela.c        |  230 +
 drivers/net/wireless/celeno/cl8k/ela.h        |   48 +
 .../net/wireless/celeno/cl8k/enhanced_tim.c   |  173 +
 .../net/wireless/celeno/cl8k/enhanced_tim.h   |   19 +
 drivers/net/wireless/celeno/cl8k/fw.c         | 3167 ++++++
 drivers/net/wireless/celeno/cl8k/fw.h         | 1462 +++
 drivers/net/wireless/celeno/cl8k/hw.c         |  432 +
 drivers/net/wireless/celeno/cl8k/hw.h         |  280 +
 drivers/net/wireless/celeno/cl8k/ipc_shared.h | 1386 +++
 drivers/net/wireless/celeno/cl8k/key.c        |  382 +
 drivers/net/wireless/celeno/cl8k/key.h        |   37 +
 drivers/net/wireless/celeno/cl8k/mac80211.c   | 2392 ++++
 drivers/net/wireless/celeno/cl8k/mac80211.h   |  197 +
 drivers/net/wireless/celeno/cl8k/mac_addr.c   |  418 +
 drivers/net/wireless/celeno/cl8k/mac_addr.h   |   61 +
 drivers/net/wireless/celeno/cl8k/main.c       |  603 ++
 drivers/net/wireless/celeno/cl8k/main.h       |   16 +
 .../net/wireless/celeno/cl8k/maintenance.c    |   81 +
 .../net/wireless/celeno/cl8k/maintenance.h    |   17 +
 .../net/wireless/celeno/cl8k/motion_sense.c   |  244 +
 .../net/wireless/celeno/cl8k/motion_sense.h   |   46 +
 drivers/net/wireless/celeno/cl8k/pci.c        | 2468 +++++
 drivers/net/wireless/celeno/cl8k/pci.h        |  194 +
 drivers/net/wireless/celeno/cl8k/phy.c        | 9648 +++++++++++++++++
 drivers/net/wireless/celeno/cl8k/phy.h        | 3680 +++++++
 drivers/net/wireless/celeno/cl8k/platform.c   |  392 +
 drivers/net/wireless/celeno/cl8k/platform.h   |  196 +
 drivers/net/wireless/celeno/cl8k/power.c      | 1123 ++
 drivers/net/wireless/celeno/cl8k/power.h      |   90 +
 drivers/net/wireless/celeno/cl8k/radio.c      | 1113 ++
 drivers/net/wireless/celeno/cl8k/radio.h      |  130 +
 drivers/net/wireless/celeno/cl8k/rates.c      | 1570 +++
 drivers/net/wireless/celeno/cl8k/rates.h      |  154 +
 drivers/net/wireless/celeno/cl8k/recovery.c   |  280 +
 drivers/net/wireless/celeno/cl8k/recovery.h   |   39 +
 .../net/wireless/celeno/cl8k/reg/reg_access.h |  199 +
 .../net/wireless/celeno/cl8k/reg/reg_defs.h   | 5494 ++++++++++
 drivers/net/wireless/celeno/cl8k/regdom.c     |  301 +
 drivers/net/wireless/celeno/cl8k/regdom.h     |   11 +
 drivers/net/wireless/celeno/cl8k/rfic.c       |  232 +
 drivers/net/wireless/celeno/cl8k/rfic.h       |   29 +
 drivers/net/wireless/celeno/cl8k/rx.c         | 1845 ++++
 drivers/net/wireless/celeno/cl8k/rx.h         |  505 +
 drivers/net/wireless/celeno/cl8k/scan.c       |  392 +
 drivers/net/wireless/celeno/cl8k/scan.h       |   53 +
 drivers/net/wireless/celeno/cl8k/sounding.c   | 1121 ++
 drivers/net/wireless/celeno/cl8k/sounding.h   |  151 +
 drivers/net/wireless/celeno/cl8k/sta.c        |  507 +
 drivers/net/wireless/celeno/cl8k/sta.h        |   99 +
 drivers/net/wireless/celeno/cl8k/stats.c      |  438 +
 drivers/net/wireless/celeno/cl8k/stats.h      |  108 +
 drivers/net/wireless/celeno/cl8k/tcv.c        | 1259 +++
 drivers/net/wireless/celeno/cl8k/tcv.h        |  283 +
 .../net/wireless/celeno/cl8k/temperature.c    |  634 ++
 .../net/wireless/celeno/cl8k/temperature.h    |   71 +
 drivers/net/wireless/celeno/cl8k/traffic.c    |  254 +
 drivers/net/wireless/celeno/cl8k/traffic.h    |   77 +
 drivers/net/wireless/celeno/cl8k/tx.c         | 3397 ++++++
 drivers/net/wireless/celeno/cl8k/tx.h         |  467 +
 drivers/net/wireless/celeno/cl8k/utils.c      |  642 ++
 drivers/net/wireless/celeno/cl8k/utils.h      |  185 +
 drivers/net/wireless/celeno/cl8k/version.c    |  147 +
 drivers/net/wireless/celeno/cl8k/version.h    |   23 +
 drivers/net/wireless/celeno/cl8k/vif.c        |  162 +
 drivers/net/wireless/celeno/cl8k/vif.h        |   81 +
 drivers/net/wireless/celeno/cl8k/vns.c        |  354 +
 drivers/net/wireless/celeno/cl8k/vns.h        |   65 +
 drivers/net/wireless/celeno/cl8k/wrs.c        | 3323 ++++++
 drivers/net/wireless/celeno/cl8k/wrs.h        |  565 +
 97 files changed, 66548 insertions(+)
 create mode 100755 drivers/net/wireless/celeno/Kconfig
 create mode 100755 drivers/net/wireless/celeno/Makefile
 create mode 100644 drivers/net/wireless/celeno/cl8k/Kconfig
 create mode 100644 drivers/net/wireless/celeno/cl8k/Makefile
 create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/bf.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/bf.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/calib.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/calib.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/channel.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/channel.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/chip.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/chip.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/config.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/config.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/debug.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/debug.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/def.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/dfs.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/dfs.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/eeprom.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/ipc_shared.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/main.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/main.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/pci.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/pci.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/platform.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/platform.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/rates.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/rates.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_access.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_defs.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/regdom.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/regdom.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/scan.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/scan.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.h
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs.c
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs.h

-- 
2.36.1


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [RFC v2 01/96] celeno: add Kconfig
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 02/96] celeno: add Makefile viktor.barna
                   ` (94 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/Kconfig | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100755 drivers/net/wireless/celeno/Kconfig

diff --git a/drivers/net/wireless/celeno/Kconfig b/drivers/net/wireless/celeno/Kconfig
new file mode 100755
index 000000000000..a5e8a9af1ee1
--- /dev/null
+++ b/drivers/net/wireless/celeno/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+config WLAN_VENDOR_CELENO
+	bool "Celeno devices"
+	default y
+	help
+	  If you have a wireless card belonging to this class, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all the
+	  questions about these cards. If you say Y, you will be asked for
+	  your specific card in the following questions.
+
+if WLAN_VENDOR_CELENO
+
+source "drivers/net/wireless/celeno/cl8k/Kconfig"
+
+endif # WLAN_VENDOR_CELENO
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 02/96] celeno: add Makefile
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
  2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
                   ` (93 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/Makefile | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100755 drivers/net/wireless/celeno/Makefile

diff --git a/drivers/net/wireless/celeno/Makefile b/drivers/net/wireless/celeno/Makefile
new file mode 100755
index 000000000000..b7a44afcb867
--- /dev/null
+++ b/drivers/net/wireless/celeno/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+obj-$(CONFIG_CL8K) += cl8k/
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 03/96] cl8k: add Kconfig
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
  2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
  2022-05-24 11:33 ` [RFC v2 02/96] celeno: add Makefile viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-26 18:18   ` Johannes Berg
  2022-07-13  7:32   ` Kalle Valo
  2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
                   ` (92 subsequent siblings)
  95 siblings, 2 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/Kconfig | 41 ++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/Kconfig

diff --git a/drivers/net/wireless/celeno/cl8k/Kconfig b/drivers/net/wireless/celeno/cl8k/Kconfig
new file mode 100644
index 000000000000..7af6dfafa6af
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/Kconfig
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+config CL8K
+	tristate "Celeno CL8K WLAN support"
+	depends on m
+	depends on MAC80211
+	help
+	  This option enables support for Celeno CL8K WLAN.
+	  Select M (recommended), if you have a wireless module.
+
+config CL8K_VERSION
+	string "Version"
+	depends on CL8K
+	default "8.1.x"
+	help
+	  Sets module version, which may be important for FW compatibility
+	  analysis and syncing upstream codebase with the internal codebase.
+
+config CL8K_EEPROM_STM24256
+	bool "EEPROM STM24256 support"
+	depends on CL8K
+	default n
+	help
+	  Enables EEPROM STM24256 (specific for some of the platforms).
+
+config CL8K_DYN_BCAST_RATE
+	bool "Enable dynamic broadcast rate selection"
+	depends on CL8K
+	default n
+	help
+	  Enables dynamic broadcast rate selection,
+	  that allows to tune rate of broadcast frames taking into account
+	  capabilities of all associated stations.
+
+config CL8K_DYN_MCAST_RATE
+	bool "Enable dynamic multicast rate selection"
+	depends on CL8K
+	default n
+	help
+	  Enables dynamic multicast rate selection,
+	  that allows to tune rate of multicast frames taking into account
+	  capabilities of all associated stations.
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 04/96] cl8k: add Makefile
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (2 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-26 18:24   ` Johannes Berg
  2022-07-13  7:39   ` Kalle Valo
  2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
                   ` (91 subsequent siblings)
  95 siblings, 2 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/Makefile | 66 +++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/Makefile

diff --git a/drivers/net/wireless/celeno/cl8k/Makefile b/drivers/net/wireless/celeno/cl8k/Makefile
new file mode 100644
index 000000000000..9ff98cda5261
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/Makefile
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+obj-$(CONFIG_CL8K) += cl8k.o
+
+ccflags-y += -I$(src) -I$(srctree)/net/wireless -I$(srctree)/net/mac80211/
+ccflags-y += -I$(src) -Werror
+
+define cc_ver_cmp
+$(shell [ "$$($(CC) -dumpversion | cut -d. -f1)" -$(1) "$(2)" ] && echo "true" || echo "false")
+endef
+
+ifeq ($(call cc_ver_cmp,ge,8),true)
+ccflags-y += -Wno-error=stringop-truncation
+ccflags-y += -Wno-error=format-truncation
+endif
+
+# Stop these C90 warnings. We use C99.
+ccflags-y += -Wno-declaration-after-statement -g
+
+cl-objs += \
+	wrs.o \
+	phy.o \
+	key.o \
+	sta.o \
+	hw.o \
+	chip.o \
+	fw.o \
+	utils.o \
+	channel.o \
+	rx.o \
+	tx.o \
+	main.o \
+	mac_addr.o \
+	ampdu.o \
+	dfs.o \
+	enhanced_tim.o \
+	e2p.o \
+	calib.o \
+	stats.o \
+	power.o \
+	motion_sense.o \
+	bf.o \
+	sounding.o \
+	debug.o \
+	temperature.o \
+	recovery.o \
+	rates.o \
+	radio.o \
+	config.o \
+	tcv.o \
+	traffic.o \
+	vns.o \
+	maintenance.o \
+	ela.o \
+	rfic.o \
+	vif.o \
+	dsp.o \
+	pci.o \
+	version.o \
+	regdom.o \
+	mac80211.o \
+	platform.o \
+	scan.o
+
+ifneq ($(CONFIG_CL8K),)
+cl8k-y += $(cl-objs)
+endif
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 05/96] cl8k: add ampdu.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (3 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-26 18:19   ` Johannes Berg
  2022-05-26 18:22   ` Johannes Berg
  2022-05-24 11:33 ` [RFC v2 06/96] cl8k: add ampdu.h viktor.barna
                   ` (90 subsequent siblings)
  95 siblings, 2 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ampdu.c | 331 +++++++++++++++++++++++
 1 file changed, 331 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.c

diff --git a/drivers/net/wireless/celeno/cl8k/ampdu.c b/drivers/net/wireless/celeno/cl8k/ampdu.c
new file mode 100644
index 000000000000..6609bc62d340
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ampdu.c
@@ -0,0 +1,331 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "recovery.h"
+#include "utils.h"
+#include "ampdu.h"
+
+int cl_ampdu_rx_start(struct cl_hw *cl_hw,
+		      struct cl_sta *cl_sta,
+		      u16 tid,
+		      u16 ssn,
+		      u16 buf_size)
+{
+	/* @IEEE80211_AMPDU_RX_START: start RX aggregation */
+	if (!cl_hw->conf->ci_agg_rx)
+		return -EOPNOTSUPP;
+
+	cl_dbg_trace(cl_hw, "sta_idx [%u] tid [%u]\n", cl_sta->sta_idx, tid);
+
+	buf_size = min(buf_size, cl_hw->conf->ce_max_agg_size_rx);
+
+	if (cl_hw->conf->ci_fast_rx_en)
+		cl_rx_reorder_init(cl_hw, cl_sta, tid, buf_size);
+
+	cl_msg_tx_ba_add(cl_hw, BA_AGMT_RX, cl_sta->sta_idx, tid, buf_size, ssn);
+
+	return 0;
+}
+
+void cl_ampdu_rx_stop(struct cl_hw *cl_hw,
+		      struct cl_sta *cl_sta,
+		      u16 tid)
+{
+	/* @IEEE80211_AMPDU_RX_STOP: stop RX aggregation */
+	cl_dbg_trace(cl_hw, "sta_idx [%u] tid [%u]\n", cl_sta->sta_idx, tid);
+
+	if (cl_hw->conf->ci_fast_rx_en)
+		cl_rx_reorder_close(cl_sta, tid);
+}
+
+int cl_ampdu_tx_start(struct cl_hw *cl_hw,
+		      struct ieee80211_vif *vif,
+		      struct cl_sta *cl_sta,
+		      u16 tid,
+		      u16 ssn)
+{
+	/* @IEEE80211_AMPDU_TX_START: start TX aggregation */
+	struct mm_available_ba_txq_cfm *cfm = NULL;
+	int ret = 0;
+
+	if (!ieee80211_hw_check(cl_hw->hw, AMPDU_AGGREGATION) || !cl_hw->conf->ci_agg_tx)
+		return -ENOTSUPP;
+
+	if (!cl_txq_is_agg_available(cl_hw)) {
+		cl_dbg_warn(cl_hw, "No free aggregation queue for sta_idx [%u] tid [%u]\n",
+			    cl_sta->sta_idx, tid);
+		return -1;
+	}
+
+	ret = cl_msg_tx_available_ba_txq(cl_hw, cl_sta->sta_idx, tid);
+	if (ret)
+		return ret;
+
+	/* Read FW confirm message */
+	cfm = (struct mm_available_ba_txq_cfm *)(cl_hw->msg_cfm_params[MM_AVAILABLE_BA_TXQ_CFM]);
+	if (!cfm)
+		return -ENOMSG;
+
+	/* Check if status is valid */
+	if (cfm->status != BA_TXQUEUE_INVALID && cfm->status != BA_TXQUEUE_VALID) {
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+		cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+		return -EIO;
+	}
+
+	if (cfm->status == BA_TXQUEUE_INVALID) {
+		cl_dbg_warn(cl_hw, "BA_TXQUEUE_INVALID - sta_idx [%u] tid [%u]\n",
+			    cfm->sta_idx, cfm->tid);
+		cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+		return -1;
+	}
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_AVAILABLE_BA_TXQ_CFM);
+	cl_txq_agg_request_add(cl_hw, cl_sta->sta_idx, tid);
+	cl_baw_start(&cl_sta->baws[tid], ssn);
+
+	/* Mandatory callback once setup preparations are done at lower level */
+	ieee80211_start_tx_ba_cb_irqsafe(vif, cl_sta->addr, tid);
+
+	return 0;
+}
+
+int cl_ampdu_tx_operational(struct cl_hw *cl_hw,
+			    struct cl_sta *cl_sta,
+			    u16 tid,
+			    u16 buf_size,
+			    bool amsdu_supported)
+{
+	/* @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational */
+	struct mm_ba_add_cfm *cfm = NULL;
+	struct cl_baw *baw = &cl_sta->baws[tid];
+	u16 ssn = baw->ssn;
+	int ret = 0;
+
+	buf_size = min(buf_size, cl_hw->conf->ce_max_agg_size_tx);
+
+	/* Send MM_BA_ADD_TX_REQ message to firmware */
+	ret = cl_msg_tx_ba_add(cl_hw, BA_AGMT_TX, cl_sta->sta_idx, tid, buf_size, ssn);
+	if (ret)
+		return ret;
+
+	/* Handle message confirmation */
+	cfm = (struct mm_ba_add_cfm *)(cl_hw->msg_cfm_params[MM_BA_ADD_TX_CFM]);
+	if (!cfm)
+		return -ENOMSG;
+
+	if (cfm->status != BA_AGMT_ESTABLISHED) {
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+		cl_msg_tx_free_cfm_params(cl_hw, MM_BA_ADD_TX_CFM);
+		cl_txq_agg_request_del(cl_hw, cl_sta->sta_idx, tid);
+		return -EIO;
+	}
+
+	cl_baw_operational(cl_hw, baw, cfm->agg_idx, amsdu_supported);
+	cl_agg_cfm_set_ssn(cl_hw, ssn, cfm->agg_idx);
+	cl_hw->ipc_env->ring_indices_elem->indices->new_ssn_idx[cfm->agg_idx] = cpu_to_le32(ssn);
+
+	if (amsdu_supported)
+		cl_tx_amsdu_set_max_len(cl_hw, cl_sta, tid);
+	else
+		cl_dbg_trace(cl_hw, "AMSDU not supported - sta_idx=%u\n", cl_sta->sta_idx);
+
+	cl_txq_agg_alloc(cl_hw, cl_sta, cfm, buf_size);
+	cl_msg_tx_free_cfm_params(cl_hw, MM_BA_ADD_TX_CFM);
+
+	return 0;
+}
+
+void _cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+		       struct cl_tx_queue *tx_queue,
+		       struct cl_sta *cl_sta,
+		       u8 tid)
+{
+	struct mm_ba_del_cfm *cfm = NULL;
+	u8 fw_agg_idx = tx_queue->index;
+
+	if (cl_recovery_in_progress(cl_hw))
+		goto out;
+
+	/*
+	 * TX stop flow:
+	 * 1) Flush TX queues - done in cl_ampdu_tx_stop()
+	 * 2) Poll confirmation queue and clear enhanced TIM
+	 * 3) Send MM_STA_DEL_REQ message to firmware
+	 * 4) Poll again confirmation and flush confirmation queue
+	 * 5) Reset write index
+	 */
+	cl_agg_cfm_poll_empty(cl_hw, fw_agg_idx, false);
+
+	/* Send MM_BA_DEL_REQ message to firmware */
+	if (cl_msg_tx_ba_del(cl_hw, cl_sta->sta_idx, tid))
+		goto out;
+
+	cfm = (struct mm_ba_del_cfm *)(cl_hw->msg_cfm_params[MM_BA_DEL_CFM]);
+	if (!cfm) {
+		cl_dbg_err(cl_hw, "Unable to fetch CFM\n");
+		goto out;
+	}
+
+	/* Check confirmation status */
+	if (cfm->status != BA_AGMT_DELETED && cfm->status != BA_AGMT_DOES_NOT_EXIST)
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", cfm->status);
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_BA_DEL_CFM);
+
+out:
+	cl_agg_cfm_poll_empty(cl_hw, fw_agg_idx, true);
+	cl_txq_agg_free(cl_hw, tx_queue, cl_sta, tid);
+
+	/* Reset the synchronization counters between the fw and the IPC layer */
+	cl_hw->ipc_env->ring_indices_elem->indices->txdesc_write_idx.agg[fw_agg_idx] = 0;
+}
+
+int cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+		     struct ieee80211_vif *vif,
+		     enum ieee80211_ampdu_mlme_action action,
+		     struct cl_sta *cl_sta,
+		     u16 tid)
+{
+	/*
+	 * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
+	 *	queued packets, now unaggregated. After all packets are transmitted the
+	 *	driver has to call ieee80211_stop_tx_ba_cb_irqsafe().
+	 * @IEEE80211_AMPDU_TX_STOP_FLUSH: stop TX aggregation and flush all packets,
+	 *	called when the station is removed. There's no need or reason to call
+	 *	ieee80211_stop_tx_ba_cb_irqsafe() in this case as mac80211 assumes the
+	 *	session is gone and removes the station.
+	 * @IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: called when TX aggregation is stopped
+	 *	but the driver hasn't called ieee80211_stop_tx_ba_cb_irqsafe() yet and
+	 *	now the connection is dropped and the station will be removed. Drivers
+	 *	should clean up and drop remaining packets when this is called.
+	 */
+
+	/* !!!  Comment in agg-tx.c, ___ieee80211_stop_tx_ba_session():  !!!
+	 * !!!  HW shall not deny going back to legacy                   !!!
+	 * !!!  Therefore cl_ampdu_tx_stop() always returns 0            !!!
+	 */
+
+	struct cl_tx_queue *tx_queue = cl_sta->agg_tx_queues[tid];
+	struct cl_baw *baw = &cl_sta->baws[tid];
+
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+
+	cl_baw_stop(baw);
+	cl_txq_agg_request_del(cl_hw, cl_sta->sta_idx, tid);
+
+	/* Check if BA session exist */
+	if (!tx_queue) {
+		spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+		if (!cl_recovery_in_progress(cl_hw))
+			cl_dbg_warn(cl_hw, "Queue doesn't exist - sta_idx [%u] tid [%u]\n",
+				    cl_sta->sta_idx, tid);
+
+		goto out;
+	}
+
+	if (action == IEEE80211_AMPDU_TX_STOP_CONT) {
+		/*
+		 * The order of flow here is very important here to avoid reorder problem!
+		 * 1) Take single lock to block single traffic
+		 * 2) Stop agg traffic.
+		 * 3) Transfer agg-to-single and push all skbs from agg queue to single queue.
+		 * 4) Transfer BA window pending queue to single queue.
+		 * 5) Release single lock
+		 */
+		spin_lock_bh(&cl_hw->tx_lock_single);
+		cl_txq_agg_stop(cl_sta, tid);
+		cl_txq_transfer_agg_to_single(cl_hw, tx_queue);
+		cl_baw_pending_to_single(cl_hw, cl_sta, baw);
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+	} else {
+		cl_txq_agg_stop(cl_sta, tid);
+		cl_txq_flush_agg(cl_hw, tx_queue, false);
+		cl_baw_pending_purge(baw);
+	}
+
+	cl_tx_amsdu_anchor_reset(&cl_sta->amsdu_anchor[tid]);
+
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+	_cl_ampdu_tx_stop(cl_hw, tx_queue, cl_sta, tid);
+
+out:
+	/* Mandatory callback once we've made our own tear down ops */
+	if (action != IEEE80211_AMPDU_TX_STOP_FLUSH)
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, cl_sta->addr, tid);
+
+	return 0;
+}
+
+#define HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET 3
+#define HE_EXP_MAX 22 /* 2 ^ 22 = 4194304 < 6500631 */
+
+static void _cl_ampdu_size_exp(struct ieee80211_sta *sta,
+			       u8 *ampdu_exp_he,
+			       u8 *ampdu_exp_vht,
+			       u8 *ampdu_exp_ht)
+{
+	struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+	u8 mac_cap_info3 = he_cap->he_cap_elem.mac_cap_info[3];
+	u8 he_exp;
+
+	if (sta->ht_cap.ht_supported)
+		*ampdu_exp_ht = IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor;
+
+	if (sta->vht_cap.vht_supported) {
+		u32 vht_exp = (sta->vht_cap.cap &
+			       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+		*ampdu_exp_vht = IEEE80211_HT_MAX_AMPDU_FACTOR + vht_exp;
+	}
+
+	he_exp = (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
+		HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET;
+
+	if (sta->vht_cap.vht_supported) {
+		if (he_exp)
+			*ampdu_exp_he = min(IEEE80211_HE_VHT_MAX_AMPDU_FACTOR + he_exp, HE_EXP_MAX);
+		else
+			*ampdu_exp_he = *ampdu_exp_vht;
+	} else if (sta->ht_cap.ht_supported) {
+		if (he_exp)
+			*ampdu_exp_he = IEEE80211_HE_HT_MAX_AMPDU_FACTOR + he_exp;
+		else
+			*ampdu_exp_he = *ampdu_exp_ht;
+	}
+}
+
+static void _cl_ampdu_size_exp_6g(struct ieee80211_sta *sta, u8 *ampdu_exp_he)
+{
+	u8 mac_cap_info3 = sta->he_cap.he_cap_elem.mac_cap_info[3];
+	u8 he_exp_ext = (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
+		HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET;
+
+	if (he_exp_ext) {
+		*ampdu_exp_he = min(IEEE80211_HE_VHT_MAX_AMPDU_FACTOR + he_exp_ext, HE_EXP_MAX);
+	} else {
+		struct ieee80211_he_6ghz_capa *he_6g_cap = &sta->he_6ghz_capa;
+		u8 he_exp_6ghz = (le16_to_cpu(he_6g_cap->capa) &
+				  HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+				  HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET;
+
+		*ampdu_exp_he = min(HE_6GHZ_CAP_MAX_AMPDU_LEN_FACTOR + he_exp_6ghz, HE_EXP_MAX);
+	}
+}
+
+void cl_ampdu_size_exp(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+		       u8 *ampdu_exp_he, u8 *ampdu_exp_vht, u8 *ampdu_exp_ht)
+{
+	if (cl_band_is_6g(cl_hw))
+		_cl_ampdu_size_exp_6g(sta, ampdu_exp_he);
+	else
+		_cl_ampdu_size_exp(sta, ampdu_exp_he, ampdu_exp_vht, ampdu_exp_ht);
+
+	cl_dbg_info(cl_hw, "ampdu_size_exp: he = %u, vht = %u, ht = %u\n",
+		    *ampdu_exp_he, *ampdu_exp_vht, *ampdu_exp_ht);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 06/96] cl8k: add ampdu.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (4 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
                   ` (89 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ampdu.h | 39 ++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ampdu.h

diff --git a/drivers/net/wireless/celeno/cl8k/ampdu.h b/drivers/net/wireless/celeno/cl8k/ampdu.h
new file mode 100644
index 000000000000..62c3f60c8c86
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ampdu.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_AMPDU_H
+#define CL_AMPDU_H
+
+#include "sta.h"
+
+int cl_ampdu_rx_start(struct cl_hw *cl_hw,
+		      struct cl_sta *cl_sta,
+		      u16 tid,
+		      u16 ssn,
+		      u16 buf_size);
+void cl_ampdu_rx_stop(struct cl_hw *cl_hw,
+		      struct cl_sta *cl_sta,
+		      u16 tid);
+int cl_ampdu_tx_start(struct cl_hw *cl_hw,
+		      struct ieee80211_vif *vif,
+		      struct cl_sta *cl_sta,
+		      u16 tid,
+		      u16 ssn);
+int cl_ampdu_tx_operational(struct cl_hw *hw,
+			    struct cl_sta *cl_sta,
+			    u16 tid,
+			    u16 buf_size,
+			    bool amsdu_supported);
+void _cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+		       struct cl_tx_queue *tx_queue,
+		       struct cl_sta *cl_sta,
+		       u8 tid);
+int cl_ampdu_tx_stop(struct cl_hw *cl_hw,
+		     struct ieee80211_vif *vif,
+		     enum ieee80211_ampdu_mlme_action action,
+		     struct cl_sta *cl_sta,
+		     u16 tid);
+void cl_ampdu_size_exp(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+		       u8 *ampdu_exp_he, u8 *ampdu_exp_vht, u8 *ampdu_exp_ht);
+
+#endif /* CL_AMPDU_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 07/96] cl8k: add bf.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (5 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 06/96] cl8k: add ampdu.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 17:24   ` Jeff Johnson
  2022-05-24 11:33 ` [RFC v2 08/96] cl8k: add bf.h viktor.barna
                   ` (88 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/bf.c | 346 ++++++++++++++++++++++++++
 1 file changed, 346 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/bf.c

diff --git a/drivers/net/wireless/celeno/cl8k/bf.c b/drivers/net/wireless/celeno/cl8k/bf.c
new file mode 100644
index 000000000000..49d16e13e6e4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bf.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "traffic.h"
+#include "sta.h"
+#include "sounding.h"
+#include "debug.h"
+#include "bf.h"
+
+#define CL_BF_MIN_SOUNDING_NR 3
+
+#define bf_pr(cl_hw, level, ...) \
+	do { \
+		if ((level) <= (cl_hw)->bf_db.dbg_level) \
+			pr_debug("[BF]" __VA_ARGS__); \
+	} while (0)
+
+#define bf_pr_verbose(cl_hw, ...) bf_pr((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define bf_pr_err(cl_hw, ...)     bf_pr((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define bf_pr_warn(cl_hw, ...)    bf_pr((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define bf_pr_trace(cl_hw, ...)   bf_pr((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define bf_pr_info(cl_hw, ...)    bf_pr((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+static bool cl_bf_is_beamformee_capable_he(struct ieee80211_sta *sta, bool mu_cap)
+{
+	u8 phy_cap_info4 = sta->he_cap.he_cap_elem.phy_cap_info[4];
+
+	if (mu_cap)
+		return (phy_cap_info4 & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER);
+	else
+		return (phy_cap_info4 & IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE);
+}
+
+static bool cl_bf_is_beamformee_capable_vht(struct ieee80211_sta *sta, bool mu_cap)
+{
+	u32 vht_cap = sta->vht_cap.cap;
+
+	if (mu_cap)
+		return (vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	else
+		return (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+}
+
+static bool cl_bf_is_beamformee_capable(struct cl_sta *cl_sta, bool mu_cap)
+{
+	struct ieee80211_sta *sta = cl_sta->sta;
+
+	if (sta->he_cap.has_he)
+		return cl_bf_is_beamformee_capable_he(sta, mu_cap);
+
+	if (sta->vht_cap.vht_supported)
+		return cl_bf_is_beamformee_capable_vht(sta, mu_cap);
+
+	return false;
+}
+
+void cl_bf_enable(struct cl_hw *cl_hw, bool enable, bool trigger_decision)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	if (cl_hw->bf_db.enable == enable)
+		return;
+
+	if (!conf->ci_bf_en && enable) {
+		bf_pr_err(cl_hw, "Unable to enable - BF is globally disabled\n");
+		return;
+	}
+
+	cl_hw->bf_db.enable = enable;
+	bf_pr_verbose(cl_hw, "%s\n", enable ? "Enable" : "Disable");
+
+	if (trigger_decision)
+		cl_sta_loop_bh(cl_hw, cl_bf_sounding_decision);
+}
+
+static void cl_bf_timer_callback(struct timer_list *t)
+{
+	/*
+	 * If timer expired it means that we started sounding but didn't get any
+	 * indication for (10 * sounding_interval).
+	 * So we disable sounding for this station (even when in starts again traffic).
+	 */
+	struct cl_bf_sta_db *bf_db = from_timer(bf_db, t, timer);
+	struct cl_sta *cl_sta = container_of(bf_db, struct cl_sta, bf_db);
+	struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+
+	bf_pr_trace(cl_hw, "Failed to get reply (%u)\n", cl_sta->sta_idx);
+	bf_db->indication_timeout = true;
+	cl_bf_sounding_decision(cl_hw, cl_sta);
+}
+
+static void cl_bf_reset_sounding_info(struct cl_sta *cl_sta)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	bf_db->synced = false;
+	bf_db->sounding_start = false;
+	bf_db->sounding_indications = 0;
+}
+
+void cl_bf_sounding_start(struct cl_hw *cl_hw, enum sounding_type type, struct cl_sta **cl_sta_arr,
+			  u8 sta_num, struct cl_sounding_info *recovery_elem)
+{
+#define STA_INDICES_STR_SIZE 64
+
+	/* Send request to start sounding */
+	u8 i, bw = CHNL_BW_MAX;
+	char sta_indices_str[STA_INDICES_STR_SIZE] = {0};
+	u8 str_len = 0;
+
+	for (i = 0; i < sta_num; i++) {
+		struct cl_sta *cl_sta = cl_sta_arr[i];
+		struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+		bw = cl_sta->wrs_sta.assoc_bw;
+		bf_db->synced = false;
+		bf_db->sounding_start = true;
+		bf_db->sounding_indications = 0;
+
+		str_len += snprintf(sta_indices_str, STA_INDICES_STR_SIZE - str_len, "%u%s",
+				    cl_sta->sta_idx, (i == sta_num - 1 ? ", " : ""));
+	}
+
+	bf_pr_trace(cl_hw, "Start sounding: Sta = %s\n", sta_indices_str);
+	cl_sounding_send_request(cl_hw, cl_sta_arr, sta_num, SOUNDING_ENABLE, type, bw, NULL, 0,
+				 recovery_elem);
+
+#undef STA_INDICES_STR_SIZE
+}
+
+void cl_bf_sounding_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	if (bf_db->sounding_start) {
+		/* Send request to stop sounding */
+		cl_bf_reset_sounding_info(cl_sta);
+		bf_pr_trace(cl_hw, "Sta = %u, Stop sounding\n", cl_sta->sta_idx);
+		cl_sounding_send_request(cl_hw, &cl_sta, 1, SOUNDING_DISABLE, SOUNDING_TYPE_HE_SU,
+					 0, NULL, 0, NULL);
+		bf_pr_trace(cl_hw, "Sta: %u, Beamforming disabled\n", cl_sta->sta_idx);
+	}
+}
+
+void cl_bf_sounding_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	if (cl_bf_is_enabled(cl_hw) &&
+	    cl_bf_is_beamformee_capable(cl_sta, false) &&
+	    !bf_db->indication_timeout &&
+	    ((bf_db->beamformee_sts + 1) >= CL_BF_MIN_SOUNDING_NR) &&
+	    (bf_db->traffic_active || cl_hw->bf_db.force)) {
+		if (!bf_db->sounding_start) {
+			if (cl_sta->su_sid == INVALID_SID)
+				cl_bf_sounding_start(cl_hw, SOUNDING_TYPE_HE_SU, &cl_sta, 1, NULL);
+			else
+				bf_pr_verbose(cl_hw, "[%s]: STA %u already belongs to sid %u\n",
+					      __func__, cl_sta->sta_idx, cl_sta->su_sid);
+		}
+	} else {
+		del_timer(&bf_db->timer);
+		cl_bf_sounding_stop(cl_hw, cl_sta);
+	}
+}
+
+static u8 cl_bf_get_sts_he(struct ieee80211_sta *sta)
+{
+	u8 *phy_cap_info = sta->he_cap.he_cap_elem.phy_cap_info;
+
+	if (phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
+	    phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+		return u8_get_bits(phy_cap_info[4],
+				   IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK);
+	else
+		return u8_get_bits(phy_cap_info[4],
+				   IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK);
+}
+
+static u8 cl_bf_get_sts_vht(struct ieee80211_sta *sta)
+{
+	struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+
+	return u32_get_bits(vht_cap->cap, IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
+}
+
+static u8 cl_bf_get_sts(struct ieee80211_sta *sta)
+{
+	if (sta->he_cap.has_he)
+		return cl_bf_get_sts_he(sta);
+
+	return cl_bf_get_sts_vht(sta);
+}
+
+void cl_bf_update_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	/* Old & new BF state for main rate */
+	bool bf_on_old = bf_db->is_on;
+	bool bf_on_new = cl_bf_is_on(cl_hw, cl_sta, bf_db->num_ss);
+
+	/* Old & new BF state for fallback rate */
+	bool bf_on_old_fbk = bf_db->is_on_fallback;
+	bool bf_on_new_fbk = cl_bf_is_on(cl_hw, cl_sta, bf_db->num_ss_fallback);
+
+	if (bf_on_old != bf_on_new || bf_on_old_fbk != bf_on_new_fbk) {
+		/* BF state for main rate or fallback rate changed */
+
+		/* Save the new state */
+		bf_db->is_on = bf_on_new;
+		bf_db->is_on_fallback = bf_on_new_fbk;
+
+		/* Update the firmware */
+		if (cl_msg_tx_set_tx_bf(cl_hw, cl_sta->sta_idx, bf_on_new, bf_on_new_fbk))
+			pr_err("%s: failed to set TX-BF\n", __func__);
+	}
+}
+
+void cl_bf_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct ieee80211_sta *sta)
+{
+	/* Beamformee capabilities */
+	bool su_beamformee_capable = cl_bf_is_beamformee_capable(cl_sta, false);
+	bool mu_beamformee_capable = cl_bf_is_beamformee_capable(cl_sta, true);
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	WARN_ON_ONCE(sta->rx_nss == 0);
+	bf_db->beamformee_sts = cl_bf_get_sts(sta);
+	bf_db->nc = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+	cl_sta->su_sid = INVALID_SID;
+
+	bf_pr_trace(cl_hw,
+		    "sta_idx: %u, su_beamformee_capable: %u, mu_beamformee_capable: %u, "
+		    "beamformee_sts: %u, nc = %u\n",
+		    cl_sta->sta_idx, su_beamformee_capable, mu_beamformee_capable,
+		    bf_db->beamformee_sts, bf_db->nc);
+
+	if (bf_db->beamformee_sts == 0)
+		bf_db->beamformee_sts = 3;
+
+	/*
+	 * Init the BF timer
+	 * Period is set to 0. It will be updated before enabling it.
+	 */
+	timer_setup(&bf_db->timer, cl_bf_timer_callback, 0);
+}
+
+void cl_bf_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	/* Disable timer before removing the station */
+	del_timer_sync(&bf_db->timer);
+
+	/*
+	 * Remove the sounding sequence associated with the STA and possibly start another sequence
+	 * for other stations that participate in the same sounding sequence with the STA
+	 */
+	if (cl_sta->su_sid != INVALID_SID) {
+		bf_db->sounding_remove_required = true;
+		cl_sounding_stop_by_sid(cl_hw, cl_sta->su_sid, true);
+	}
+}
+
+void cl_bf_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool active)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	if (bf_db->traffic_active != active) {
+		bf_pr_trace(cl_hw, "Sta: %u, Active: %s\n",
+			    cl_sta->sta_idx, active ? "True" : " False");
+
+		bf_db->traffic_active = active;
+		cl_bf_sounding_decision(cl_hw, cl_sta);
+	}
+}
+
+void cl_bf_reset_sounding_ind(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	cl_sta->bf_db.sounding_indications = 0;
+}
+
+bool cl_bf_is_enabled(struct cl_hw *cl_hw)
+{
+	return cl_hw->bf_db.enable;
+}
+
+bool cl_bf_is_on(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 nss)
+{
+	struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+	return (cl_bf_is_enabled(cl_hw) &&
+		bf_db->sounding_start &&
+		bf_db->sounding_indications &&
+		(nss <= min(cl_hw->conf->ci_bf_max_nss, bf_db->nc)));
+}
+
+void cl_bf_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem)
+{
+	/*
+	 * Start a timer to check that we are receiving indications from the station.
+	 * The period of the timer is set to 10 times the sounding-interval.
+	 */
+	u8 i;
+	struct cl_sta *cl_sta;
+	struct cl_bf_sta_db *bf_db;
+	unsigned long period = CL_SOUNDING_FACTOR * cl_sounding_get_interval(cl_hw);
+
+	for (i = 0; i < new_elem->sta_num; i++) {
+		cl_sta = new_elem->su_cl_sta_arr[i];
+		bf_db = &cl_sta->bf_db;
+
+		if (cl_sta) {
+			cl_sta->bf_db.sounding_start = true;
+			cl_sta->su_sid = new_elem->sounding_id;
+
+			/* Don't enable BF timer in case of force mode */
+			if (!cl_hw->bf_db.force)
+				mod_timer(&bf_db->timer, jiffies + msecs_to_jiffies(period));
+		}
+	}
+}
+
+void cl_bf_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem)
+{
+	u8 i;
+	struct cl_sta *cl_sta;
+	struct cl_bf_sta_db *bf_db;
+
+	for (i = 0; i < new_elem->sta_num; i++) {
+		cl_sta = new_elem->su_cl_sta_arr[i];
+
+		if (cl_sta) {
+			bf_db = &cl_sta->bf_db;
+			bf_db->sounding_start = false;
+			bf_db->sounding_indications = 0;
+		}
+	}
+}
+
+void cl_bf_init(struct cl_hw *cl_hw)
+{
+	cl_bf_enable(cl_hw, cl_hw->conf->ci_bf_en, false);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 08/96] cl8k: add bf.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (6 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 09/96] cl8k: add calib.c viktor.barna
                   ` (87 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/bf.h | 52 +++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/bf.h

diff --git a/drivers/net/wireless/celeno/cl8k/bf.h b/drivers/net/wireless/celeno/cl8k/bf.h
new file mode 100644
index 000000000000..efe433f55f7f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/bf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_BF_H
+#define CL_BF_H
+
+#include "debug.h"
+#include "sounding.h"
+
+/*
+ * BF (=BeamForming, 802.11)
+ */
+
+struct cl_bf_db {
+	bool enable;
+	bool force;
+	enum cl_dbg_level dbg_level;
+};
+
+struct cl_bf_sta_db {
+	bool traffic_active;
+	bool sounding_start;
+	bool sounding_remove_required;
+	bool indication_timeout;
+	bool synced;
+	bool is_on;
+	bool is_on_fallback;
+	u8 num_ss;
+	u8 num_ss_fallback;
+	u8 beamformee_sts;
+	u8 nc;
+	u32 sounding_indications;
+	struct timer_list timer;
+};
+
+void cl_bf_init(struct cl_hw *cl_hw);
+void cl_bf_update_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct ieee80211_sta *sta);
+void cl_bf_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool active);
+void cl_bf_reset_sounding_ind(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_bf_is_enabled(struct cl_hw *cl_hw);
+bool cl_bf_is_on(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 nss);
+void cl_bf_enable(struct cl_hw *cl_hw, bool enable, bool trigger_decision);
+void cl_bf_sounding_start(struct cl_hw *cl_hw, enum sounding_type type, struct cl_sta **cl_sta_arr,
+			  u8 sta_num, struct cl_sounding_info *recovery_elem);
+void cl_bf_sounding_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sounding_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_bf_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem);
+void cl_bf_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *new_elem);
+
+#endif /* CL_BF_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 09/96] cl8k: add calib.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (7 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 08/96] cl8k: add bf.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 10/96] cl8k: add calib.h viktor.barna
                   ` (86 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/calib.c | 2266 ++++++++++++++++++++++
 1 file changed, 2266 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/calib.c

diff --git a/drivers/net/wireless/celeno/cl8k/calib.c b/drivers/net/wireless/celeno/cl8k/calib.c
new file mode 100644
index 000000000000..93fe6a2e00ee
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/calib.c
@@ -0,0 +1,2266 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/dcache.h>
+
+#include "reg/reg_defs.h"
+#include "chip.h"
+#include "config.h"
+#include "radio.h"
+#include "e2p.h"
+#include "rfic.h"
+#include "debug.h"
+#include "utils.h"
+#include "calib.h"
+
+static void cl_calib_common_init_cfm(struct cl_iq_dcoc_data *iq_dcoc_data)
+{
+	int i;
+
+	for (i = 0; i < CALIB_CFM_MAX; i++)
+		iq_dcoc_data->dcoc_iq_cfm[i].status = CALIB_FAIL;
+}
+
+void cl_calib_common_fill_phy_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db,
+				   u8 flags)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 bw = cl_hw->bw;
+	u8 channel_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, cl_hw->channel, bw);
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+
+	if (flags & SET_PHY_DATA_FLAGS_DCOC)
+		cl_calib_dcoc_fill_data(cl_hw, iq_dcoc_db);
+
+	if (flags & SET_PHY_DATA_FLAGS_IQ_TX_LOLC)
+		cl_calib_iq_lolc_fill_data(cl_hw, iq_dcoc_db->iq_tx_lolc);
+
+	if (flags & SET_PHY_DATA_FLAGS_IQ_TX)
+		cl_calib_iq_fill_data(cl_hw, iq_dcoc_db->iq_tx,
+				      chip->calib_db.iq_tx[tcv_idx][channel_idx][bw][sx]);
+
+	if (flags & SET_PHY_DATA_FLAGS_IQ_RX)
+		cl_calib_iq_fill_data(cl_hw, iq_dcoc_db->iq_rx,
+				      chip->calib_db.iq_rx[tcv_idx][channel_idx][bw][sx]);
+}
+
+int cl_calib_common_tables_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_iq_dcoc_data *buf = NULL;
+	u32 len = sizeof(struct cl_iq_dcoc_data);
+	dma_addr_t phys_dma_addr;
+
+	buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cl_hw->iq_dcoc_data_info.iq_dcoc_data = buf;
+	cl_hw->iq_dcoc_data_info.dma_addr = phys_dma_addr;
+
+	cl_calib_common_init_cfm(cl_hw->iq_dcoc_data_info.iq_dcoc_data);
+	return 0;
+}
+
+void cl_calib_common_tables_free(struct cl_hw *cl_hw)
+{
+	struct cl_iq_dcoc_data_info *iq_dcoc_data_info = &cl_hw->iq_dcoc_data_info;
+	u32 len = sizeof(struct cl_iq_dcoc_data);
+	dma_addr_t phys_dma_addr = iq_dcoc_data_info->dma_addr;
+
+	if (!iq_dcoc_data_info->iq_dcoc_data)
+		return;
+
+	dma_free_coherent(cl_hw->chip->dev, len, (void *)iq_dcoc_data_info->iq_dcoc_data,
+			  phys_dma_addr);
+	iq_dcoc_data_info->iq_dcoc_data = NULL;
+}
+
+static void _cl_calib_common_start_work(struct work_struct *ws)
+{
+	struct cl_calib_work *calib_work = container_of(ws, struct cl_calib_work, ws);
+	struct cl_hw *cl_hw = calib_work->cl_hw;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+	struct cl_chip *chip = cl_hw->chip;
+
+	cl_calib_iq_init_calibration(cl_hw);
+
+	if (cl_chip_is_both_enabled(chip))
+		cl_calib_iq_init_calibration(cl_hw_other);
+
+	/* Start cl_radio_on after calibration ends */
+	cl_radio_on_start(cl_hw);
+
+	if (cl_chip_is_both_enabled(chip))
+		cl_radio_on_start(cl_hw_other);
+
+	kfree(calib_work);
+}
+
+void cl_calib_common_start_work(struct cl_hw *cl_hw)
+{
+	struct cl_calib_work *calib_work = kzalloc(sizeof(*calib_work), GFP_ATOMIC);
+
+	if (!calib_work)
+		return;
+
+	calib_work->cl_hw = cl_hw;
+	INIT_WORK(&calib_work->ws, _cl_calib_common_start_work);
+	queue_work(cl_hw->drv_workqueue, &calib_work->ws);
+}
+
+s16 cl_calib_common_get_temperature(struct cl_hw *cl_hw, u8 cfm_type)
+{
+	struct calib_cfm *dcoc_iq_cfm =
+		&cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[cfm_type];
+	u16 raw_bits = (le16_to_cpu(dcoc_iq_cfm->raw_bits_data_0) +
+		le16_to_cpu(dcoc_iq_cfm->raw_bits_data_1)) / 2;
+
+	return cl_temperature_calib_calc(cl_hw, raw_bits);
+}
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+static u16 cl_calib_common_eeprom_get_idx(struct cl_hw *cl_hw, int bw_idx, u16 channel,
+					  u16 channels_plan[], u8 num_of_channels)
+{
+	int i;
+
+	for (i = 0; i < num_of_channels; i++)
+		if (channels_plan[i] == channel)
+			return i;
+
+	return U16_MAX;
+}
+
+static u16 cl_calib_common_eeprom_get_addr(struct cl_hw *cl_hw, int bw_idx, u16 channel)
+{
+	int idx = 0;
+	u16 addr = 0;
+	u16 *channels;
+	u8 num_of_channels;
+
+	switch (bw_idx) {
+	case CHNL_BW_20:
+		channels = cl_hw->conf->ci_calib_eeprom_channels_20mhz;
+
+		if (cl_hw_is_tcv0(cl_hw)) {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0;
+		} else {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1;
+		}
+		break;
+	case CHNL_BW_40:
+		channels = cl_hw->conf->ci_calib_eeprom_channels_40mhz;
+
+		if (cl_hw_is_tcv0(cl_hw)) {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0;
+		} else {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1;
+		}
+		break;
+	case CHNL_BW_80:
+		channels = cl_hw->conf->ci_calib_eeprom_channels_80mhz;
+
+		if (cl_hw_is_tcv0(cl_hw)) {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0;
+		} else {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1;
+		}
+		break;
+	case CHNL_BW_160:
+		channels = cl_hw->conf->ci_calib_eeprom_channels_80mhz;
+
+		if (cl_hw_is_tcv0(cl_hw)) {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0;
+		} else {
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1;
+			idx = cl_calib_common_eeprom_get_idx(cl_hw, bw_idx, channel, channels,
+							     num_of_channels);
+			addr = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1;
+		}
+		break;
+	default:
+		return U16_MAX;
+	}
+
+	if (idx == U16_MAX)
+		return U16_MAX;
+
+	return ((u16)addr + (u16)(idx * sizeof(struct eeprom_calib_data)));
+}
+
+static void cl_calib_common_write_lolc_to_eeprom(struct cl_calib_db *calib_db,
+						 struct eeprom_calib_data *calib_data,
+						 u8 ch_idx, u8 bw, u8 sx_idx, u8 tcv_idx)
+{
+	memcpy(calib_data->lolc,
+	       calib_db->iq_tx_lolc[tcv_idx][ch_idx][bw][sx_idx],
+	       sizeof(u32) * MAX_ANTENNAS);
+}
+
+static void cl_calib_common_write_dcoc_to_eeprom(struct cl_calib_db *calib_db,
+						 struct eeprom_calib_data *calib_data,
+						 u8 ch_idx, u8 bw, u8 sx_idx, u8 tcv_idx)
+{
+	memcpy(calib_data->dcoc,
+	       calib_db->dcoc[tcv_idx][ch_idx][bw][sx_idx],
+	       sizeof(struct cl_dcoc_calib) * MAX_ANTENNAS * DCOC_LNA_GAIN_NUM);
+}
+
+static void cl_calib_common_write_iq_to_eeprom(struct cl_calib_db *calib_db,
+					       struct eeprom_calib_data *calib_data,
+					       u8 ch_idx, u8 bw, u8 sx_idx, u8 tcv_idx)
+{
+	memcpy(calib_data->iq_tx,
+	       calib_db->iq_tx[tcv_idx][ch_idx][bw][sx_idx],
+	       sizeof(struct cl_iq_calib) * MAX_ANTENNAS);
+	memcpy(calib_data->iq_rx,
+	       calib_db->iq_rx[tcv_idx][ch_idx][bw][sx_idx],
+	       sizeof(struct cl_iq_calib) * MAX_ANTENNAS);
+}
+
+static s8 cl_calib_common_find_worst_iq_tone(struct cl_iq_report iq_report_dma)
+{
+	u8 tone = 0;
+	s8 worst_tone = S8_MIN;
+
+	for (tone = 0; tone < IQ_NUM_TONES_CFM; tone++)
+		if (worst_tone < iq_report_dma.ir_db[IQ_POST_IDX][tone])
+			worst_tone = iq_report_dma.ir_db[IQ_POST_IDX][tone];
+
+	return worst_tone;
+}
+
+static void cl_calib_common_write_score_dcoc(struct cl_hw *cl_hw,
+					     struct eeprom_calib_data *calib_data)
+{
+	u8 lna, ant;
+
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+		for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+			struct cl_dcoc_report *dcoc_calib_report =
+				&cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.dcoc[lna][ant];
+
+			calib_data->score[ant].dcoc_i_mv[lna] =
+				(s16)le16_to_cpu(dcoc_calib_report->i_dc);
+			calib_data->score[ant].dcoc_q_mv[lna] =
+				(s16)le16_to_cpu(dcoc_calib_report->q_dc);
+		}
+	}
+}
+
+static void cl_calib_common_write_score_lolc(struct cl_hw *cl_hw,
+					     struct eeprom_calib_data *calib_data)
+{
+	u8 ant;
+	struct cl_iq_dcoc_report *report = &cl_hw->iq_dcoc_data_info.iq_dcoc_data->report;
+
+	for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+		calib_data->score[ant].lolc_score =
+			(s16)(le16_to_cpu(report->lolc_report[ant].lolc_qual)) >> 8;
+	}
+}
+
+static void cl_calib_common_write_score_iq(struct cl_hw *cl_hw,
+					   struct eeprom_calib_data *calib_data)
+{
+	u8 ant;
+
+	for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+		struct cl_iq_report iq_report_dma_tx =
+			cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.iq_tx[ant];
+		struct cl_iq_report iq_report_dma_rx =
+			cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.iq_rx[ant];
+
+		calib_data->score[ant].iq_tx_score = iq_report_dma_tx.ir_db_avg_post;
+		calib_data->score[ant].iq_rx_score = iq_report_dma_rx.ir_db_avg_post;
+		calib_data->score[ant].iq_tx_worst_score =
+			cl_calib_common_find_worst_iq_tone(iq_report_dma_tx);
+		calib_data->score[ant].iq_rx_worst_score =
+			cl_calib_common_find_worst_iq_tone(iq_report_dma_rx);
+	}
+}
+
+static void cl_calib_common_write_score_to_eeprom(struct cl_hw *cl_hw,
+						  struct eeprom_calib_data *calib_data)
+{
+	cl_calib_common_write_score_dcoc(cl_hw, calib_data);
+	cl_calib_common_write_score_lolc(cl_hw, calib_data);
+	cl_calib_common_write_score_iq(cl_hw, calib_data);
+}
+
+static void cl_calib_common_write_eeprom(struct cl_hw *cl_hw, u32 channel, u8 bw, u8 sx_idx,
+					 u8 tcv_idx)
+{
+	u8 ch_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel, bw);
+	u16 eeprom_addr = cl_calib_common_eeprom_get_addr(cl_hw, bw, channel);
+	struct eeprom_calib_data calib_data;
+	struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+
+	if (eeprom_addr == U16_MAX)
+		return;
+
+	calib_data.valid = true;
+	calib_data.temperature = cl_calib_common_get_temperature(cl_hw, CALIB_CFM_IQ);
+	cl_calib_common_write_lolc_to_eeprom(calib_db, &calib_data, ch_idx, bw, sx_idx, tcv_idx);
+	cl_calib_common_write_dcoc_to_eeprom(calib_db, &calib_data, ch_idx, bw, sx_idx, tcv_idx);
+	cl_calib_common_write_iq_to_eeprom(calib_db, &calib_data, ch_idx, bw, sx_idx, tcv_idx);
+	cl_calib_common_write_score_to_eeprom(cl_hw, &calib_data);
+
+	cl_e2p_write(cl_hw->chip, (u8 *)&calib_data, (u16)sizeof(struct eeprom_calib_data),
+		     eeprom_addr);
+}
+
+static bool cl_calib_common_is_channel_included_in_eeprom_bitmap(struct cl_hw *cl_hw)
+{
+	u16 i;
+	u16 *eeprom_valid_ch = NULL;
+	u16 num_of_channels;
+
+	switch (cl_hw->bw) {
+	case CHNL_BW_20:
+		eeprom_valid_ch = cl_hw->conf->ci_calib_eeprom_channels_20mhz;
+
+		if (cl_hw_is_tcv0(cl_hw))
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0;
+		else
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1;
+		break;
+	case CHNL_BW_40:
+		eeprom_valid_ch = cl_hw->conf->ci_calib_eeprom_channels_40mhz;
+
+		if (cl_hw_is_tcv0(cl_hw))
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0;
+		else
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1;
+		break;
+	case CHNL_BW_80:
+		eeprom_valid_ch = cl_hw->conf->ci_calib_eeprom_channels_80mhz;
+
+		if (cl_hw_is_tcv0(cl_hw))
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0;
+		else
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1;
+		break;
+	case CHNL_BW_160:
+		eeprom_valid_ch = cl_hw->conf->ci_calib_eeprom_channels_160mhz;
+
+		if (cl_hw_is_tcv0(cl_hw))
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0;
+		else
+			num_of_channels = EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1;
+		break;
+	default:
+		return false;
+	}
+	for (i = 0; i < num_of_channels; i++)
+		if (cl_hw->channel == eeprom_valid_ch[i])
+			return true;
+
+	return false;
+}
+#endif /* CONFIG_CL8K_EEPROM_STM24256 */
+
+int cl_calib_common_handle_set_channel_cfm(struct cl_hw *cl_hw, struct cl_calib_params calib_params)
+{
+	struct cl_iq_dcoc_data *iq_dcoc_data = cl_hw->iq_dcoc_data_info.iq_dcoc_data;
+	u8 mode = calib_params.mode;
+
+	cl_dbg_trace(cl_hw, "\n ------  FINISH CALIB CHANNEL  -----\n");
+
+	/*
+	 * In case any of the requested calibrations failed - no need to copy
+	 * the other Calibration data, and fail the whole calibration process.
+	 */
+	if ((mode & SET_CHANNEL_MODE_CALIB_DCOC &&
+	     iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status != CALIB_SUCCESS) ||
+	    (mode & SET_CHANNEL_MODE_CALIB_IQ &&
+	     iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status != CALIB_SUCCESS)) {
+		cl_dbg_err(cl_hw, "Calibration failed! mode = %u, DCOC_CFM_STATUS = %u, "
+			   "IQ_CFM_STATUS = %u\n", mode,
+			   iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status,
+			   iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status);
+		/* Set status to CALIB_FAIL to ensure that FW is writing the values. */
+		iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC].status = CALIB_FAIL;
+		iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ].status = CALIB_FAIL;
+		return -EINVAL;
+	}
+
+	cl_dbg_trace(cl_hw, "mode = %u\n", mode);
+
+	if (mode & SET_CHANNEL_MODE_CALIB_DCOC)
+		cl_calib_dcoc_handle_set_channel_cfm(cl_hw, calib_params.first_channel);
+
+	if (mode & SET_CHANNEL_MODE_CALIB_IQ)
+		cl_calib_iq_handle_set_channel_cfm(cl_hw, calib_params.plan_bitmap);
+
+	if (mode & SET_CHANNEL_MODE_CALIB_LOLC)
+		cl_calib_iq_lolc_handle_set_channel_cfm(cl_hw, calib_params.plan_bitmap);
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	if (cl_hw->chip->conf->ci_calib_eeprom_en && cl_hw->chip->conf->ce_production_mode &&
+	    cl_hw->chip->is_calib_eeprom_loaded && cl_hw->chip->conf->ce_calib_runtime_en)
+		if (cl_calib_common_is_channel_included_in_eeprom_bitmap(cl_hw))
+			cl_calib_common_write_eeprom(cl_hw, cl_hw->channel, cl_hw->bw,
+						     cl_hw->sx_idx, cl_hw->tcv_idx);
+#endif
+
+	return 0;
+}
+
+int cl_calib_common_check_errors(struct cl_hw *cl_hw)
+{
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u16 dcoc_erros = cl_hw->chip->calib_db.errors[tcv_idx].dcoc;
+	u16 lolc_erros = cl_hw->chip->calib_db.errors[tcv_idx].lolc;
+	u16 iq_tx_erros = cl_hw->chip->calib_db.errors[tcv_idx].iq_tx;
+	u16 iq_rx_erros = cl_hw->chip->calib_db.errors[tcv_idx].iq_rx;
+
+	if (!cl_hw->chip->conf->ci_calib_check_errors)
+		return 0;
+
+	if (dcoc_erros > 0 || lolc_erros > 0 || iq_tx_erros > 0 || iq_rx_erros > 0) {
+		CL_DBG_ERROR(cl_hw, "Abort: dcoc_erros %u, lolc_erros %u,"
+			     " iq_tx_erros %u, iq_rx_erros %u\n",
+			     dcoc_erros, lolc_erros, iq_tx_erros, iq_rx_erros);
+		return -ECANCELED;
+	}
+
+	return 0;
+}
+
+static const u8 calib_channels_24g[CALIB_CHAN_24G_MAX] = {
+	1, 6, 11
+};
+
+static const u8 calib_channels_5g_plan[CALIB_CHAN_5G_PLAN] = {
+	36, 52, 100, 116, 132, 149
+};
+
+static const u8 calib_channels_6g_plan[CALIB_CHAN_6G_PLAN] = {
+	1, 17, 33, 49, 65, 81, 97, 113, 129, 145, 161, 177, 193, 209, 225
+};
+
+static const u8 calib_channels_5g_bw_20[] = {
+	36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+	149, 153, 157, 161, 165
+};
+
+static const u8 calib_channels_5g_bw_40[] = {
+	36, 44, 52, 60, 100, 108, 116, 124, 132, 140, 149, 157
+};
+
+static const u8 calib_channels_5g_bw_80[] = {
+	36, 52, 100, 116, 132, 149
+};
+
+static const u8 calib_channels_5g_bw_160[] = {
+	36, 100
+};
+
+static const u8 calib_channels_6g_bw_20[] = {
+	1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93,
+	97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165,
+	169, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233
+};
+
+static const u8 calib_channels_6g_bw_40[] = {
+	1, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121, 129, 137, 145, 153, 161,
+	169, 177, 185, 193, 201, 209, 217, 225
+};
+
+static const u8 calib_channels_6g_bw_80[] = {
+	1, 17, 33, 49, 65, 81, 97, 113, 129, 145, 161, 177, 193, 209, 225
+};
+
+static const u8 calib_channels_6g_bw_160[] = {
+	1, 33, 65, 97, 129, 161, 193, 225
+};
+
+static void cl_calib_dcoc_handle_data(struct cl_hw *cl_hw, s16 calib_temperature, u8 channel, u8 bw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	int lna, chain;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+	u8 channel_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel, bw);
+	struct cl_dcoc_calib *dcoc_calib;
+	struct cl_dcoc_calib *dcoc_calib_dma;
+
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+		riu_chain_for_each(chain) {
+			dcoc_calib =
+				&chip->calib_db.dcoc[tcv_idx][channel_idx][bw][sx][chain][lna];
+			dcoc_calib_dma =
+				&cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.dcoc[lna][chain];
+			dcoc_calib->i = dcoc_calib_dma->i;
+			dcoc_calib->q = dcoc_calib_dma->q;
+		}
+	}
+}
+
+static void cl_calib_dcoc_handle_report(struct cl_hw *cl_hw, s16 calib_temperature,
+					int channel, u8 bw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	int lna, chain;
+	struct cl_dcoc_report *dcoc_calib_report_dma;
+	int bw_mhz = BW_TO_MHZ(bw);
+	u8 dcoc_threshold = chip->conf->ci_dcoc_mv_thr[bw];
+	s16 i, q;
+
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+		riu_chain_for_each(chain) {
+			dcoc_calib_report_dma =
+				&cl_hw->iq_dcoc_data_info.iq_dcoc_data->report.dcoc[lna][chain];
+
+			i = (s16)le16_to_cpu(dcoc_calib_report_dma->i_dc);
+			q = (s16)le16_to_cpu(dcoc_calib_report_dma->q_dc);
+
+			if (abs(i) > dcoc_threshold || abs(q) > dcoc_threshold) {
+				cl_dbg_warn(cl_hw,
+					    "Warning: DCOC value exceeds threshold [%umV]: channel %u, bw = %u, lna = %u, chain = %u, I[mV] = %d, I[Iter] = %u, Q[mV] = %d, Q[Iter] = %u\n",
+					    dcoc_threshold, channel, bw_mhz, lna, chain, i,
+					    le16_to_cpu(dcoc_calib_report_dma->i_iterations), q,
+					    le16_to_cpu(dcoc_calib_report_dma->q_iterations));
+				chip->calib_db.errors[cl_hw->tcv_idx].dcoc++;
+			}
+		}
+	}
+}
+
+static int cl_calib_dcoc_calibrate_channel(struct cl_hw *cl_hw, u32 channel, u32 bw,
+					   bool first_channel)
+{
+	u32 primary = 0;
+	u32 center = 0;
+	enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+	struct cl_calib_params calib_params = {SET_CHANNEL_MODE_CALIB_DCOC, first_channel, 0, 0};
+
+	if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center)) {
+		cl_dbg_err(cl_hw, "cl_chandef_calc failed\n");
+		return -EINVAL;
+	}
+
+	cl_dbg_trace(cl_hw, "\n ------  START CALIB DCOC CHANNEL  -----\n");
+	cl_dbg_trace(cl_hw, "channel = %u first_channel = %u\n", channel, first_channel);
+
+	/* Set Channel Mode to DCOC Calibration Mode */
+	return cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, calib_params);
+}
+
+static void cl_calib_dcoc_average(struct cl_chip *chip, u8 tcv_idx, u8 center,
+				  u8 bw, u8 chain, u8 sx, u8 lna)
+{
+	struct cl_dcoc_calib *dcoc_db_left;
+	struct cl_dcoc_calib *dcoc_db_center;
+	struct cl_dcoc_calib *dcoc_db_right;
+	u8 left_idx = cl_calib_dcoc_tcv_channel_to_idx(chip, tcv_idx,
+						       calib_channels_6g_plan[center - 1], bw);
+	u8 center_idx = cl_calib_dcoc_tcv_channel_to_idx(chip, tcv_idx,
+							 calib_channels_6g_plan[center], bw);
+	u8 right_idx = cl_calib_dcoc_tcv_channel_to_idx(chip, tcv_idx,
+							calib_channels_6g_plan[center + 1], bw);
+
+	dcoc_db_left = &chip->calib_db.dcoc[tcv_idx][left_idx][bw][sx][chain][lna];
+	dcoc_db_center = &chip->calib_db.dcoc[tcv_idx][center_idx][bw][sx][chain][lna];
+	dcoc_db_right = &chip->calib_db.dcoc[tcv_idx][right_idx][bw][sx][chain][lna];
+
+	dcoc_db_center->i = (dcoc_db_left->i + dcoc_db_right->i) / 2;
+	dcoc_db_center->q = (dcoc_db_left->q + dcoc_db_right->q) / 2;
+}
+
+static int cl_calib_dcoc_calibrate_6g(struct cl_hw *cl_hw)
+{
+	int i;
+	u8 chain, lna;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = tcv_idx;
+	bool first_channel = true;
+	struct cl_chip *chip = cl_hw->chip;
+
+	/* Calibrate channels: 1, 33, 65, 97, 129, 161, 193, 225 */
+	for (i = 0; i < CALIB_CHAN_6G_PLAN; i += 2) {
+		if (cl_hw->conf->ci_cap_bandwidth == CHNL_BW_160 &&
+		    (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_160,
+						     first_channel) == 0))
+			first_channel = false;
+
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_80,
+						    first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_20,
+						    first_channel) == 0)
+			first_channel = false;
+	}
+
+	/*
+	 * For these channels 17, 49, 81, 113, 145, 177, 209
+	 * calculate average of closest neighbors
+	 */
+	for (i = 1; i < CALIB_CHAN_6G_PLAN - 1; i += 2)
+		riu_chain_for_each(chain)
+			for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+				cl_calib_dcoc_average(chip, tcv_idx, i, CHNL_BW_80,
+						      chain, sx, lna);
+				cl_calib_dcoc_average(chip, tcv_idx, i, CHNL_BW_20,
+						      chain, sx, lna);
+			}
+
+	return first_channel;
+}
+
+static int cl_calib_dcoc_calibrate_5g(struct cl_hw *cl_hw)
+{
+	int i;
+	bool first_channel = true;
+
+	if (cl_hw->conf->ci_cap_bandwidth == CHNL_BW_160) {
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, 36, CHNL_BW_160, first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, 100, CHNL_BW_160, first_channel) == 0)
+			first_channel = false;
+	}
+
+	for (i = 0; i < CALIB_CHAN_5G_PLAN; i++) {
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_5g_plan[i], CHNL_BW_80,
+						    first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_5g_plan[i], CHNL_BW_20,
+						    first_channel) == 0)
+			first_channel = false;
+	}
+
+	return first_channel;
+}
+
+static int cl_calib_dcoc_calibrate_24g(struct cl_hw *cl_hw)
+{
+	int i;
+	bool first_channel = true;
+
+	for (i = 0; i < CALIB_CHAN_24G_MAX; i++) {
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_24g[i], CHNL_BW_40,
+						    first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_dcoc_calibrate_channel(cl_hw, calib_channels_24g[i], CHNL_BW_20,
+						    first_channel) == 0)
+			first_channel = false;
+	}
+
+	return first_channel;
+}
+
+static void cl_calib_dcoc_calibrate(struct cl_hw *cl_hw)
+{
+	if (cl_band_is_6g(cl_hw))
+		cl_calib_dcoc_calibrate_6g(cl_hw);
+	else if (cl_band_is_5g(cl_hw))
+		cl_calib_dcoc_calibrate_5g(cl_hw);
+	else if (cl_band_is_24g(cl_hw))
+		cl_calib_dcoc_calibrate_24g(cl_hw);
+}
+
+void cl_calib_dcoc_init_calibration(struct cl_hw *cl_hw)
+{
+	u8 tcv_idx = cl_hw->tcv_idx;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_iq_dcoc_conf *iq_dcoc_conf = &chip->iq_dcoc_conf;
+	u8 fem_mode = cl_hw->fem_mode;
+
+	/* No need to init calibration to non-Olympus phy */
+	if (!IS_REAL_PHY(chip))
+		return;
+	if (cl_hw_is_tcv0(cl_hw) && chip->conf->ci_tcv1_chains_sx0)
+		return;
+
+	if (!iq_dcoc_conf->dcoc_calib_needed[tcv_idx]) {
+		u8 file_num_antennas = iq_dcoc_conf->dcoc_file_num_ant[tcv_idx];
+
+		if (file_num_antennas < cl_hw->num_antennas) {
+			cl_dbg_verbose(cl_hw,
+				       "Num of antennas [%u], is larger than DCOC calibration file"
+				       " num of antennas [%u], recalibration is needed\n",
+				       cl_hw->num_antennas, file_num_antennas);
+		} else {
+			return;
+		}
+	}
+
+	/* Set FEM mode to LNA Bypass Only mode for DCOC Calibration. */
+	cl_fem_set_dcoc_bypass(cl_hw);
+	cl_afe_cfg_calib(chip);
+
+	cl_calib_dcoc_calibrate(cl_hw);
+
+	/* Restore FEM mode to its original mode. */
+	cl_fem_dcoc_restore(cl_hw, fem_mode);
+	cl_afe_cfg_restore(chip);
+
+	iq_dcoc_conf->dcoc_calib_needed[tcv_idx] = false;
+	iq_dcoc_conf->dcoc_file_num_ant[tcv_idx] = cl_hw->num_antennas;
+}
+
+static u8 cl_calib_dcoc_get_chan_idx(const u8 calib_chan_list[], u8 list_len, u8 channel)
+{
+	u8 i = 0;
+
+	for (i = 1; i < list_len; i++)
+		if (calib_chan_list[i] > channel)
+			return (i - 1);
+
+	return (list_len - 1);
+}
+
+static u8 cl_calib_dcoc_convert_to_channel_in_plan(u8 channel, u8 band)
+{
+	u8 idx;
+
+	if (band == BAND_6G) {
+		idx = cl_calib_dcoc_get_chan_idx(calib_channels_6g_plan,
+						 ARRAY_SIZE(calib_channels_6g_plan), channel);
+		return calib_channels_6g_plan[idx];
+	}
+
+	idx = cl_calib_dcoc_get_chan_idx(calib_channels_5g_plan,
+					 ARRAY_SIZE(calib_channels_5g_plan), channel);
+
+	return calib_channels_5g_plan[idx];
+}
+
+u8 cl_calib_dcoc_channel_bw_to_idx(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+	if (cl_band_is_6g(cl_hw)) {
+		if (bw == CHNL_BW_160)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_160,
+							  ARRAY_SIZE(calib_channels_6g_bw_160),
+							  channel);
+		/*
+		 * In case of non runtime calib - channels that don't exist in the plan list will
+		 * not be calibrated. Thus, the calib data need to be fetched from a close channel
+		 * that was calibrated - AKA "fallback channel".
+		 * In this case the channel value should convert to the "fallback channel" that had
+		 * been calibrated. The func will return the idx value of the "fallback channel"
+		 * instead of the original idx channel.
+		 */
+		if (!cl_hw->chip->conf->ce_calib_runtime_en)
+			channel = cl_calib_dcoc_convert_to_channel_in_plan(channel, BAND_6G);
+
+		if (bw == CHNL_BW_20)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_20,
+							  ARRAY_SIZE(calib_channels_6g_bw_20),
+							  channel);
+
+		if (bw == CHNL_BW_40)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_40,
+							  ARRAY_SIZE(calib_channels_6g_bw_40),
+							  channel);
+
+		if (bw == CHNL_BW_80)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_80,
+							  ARRAY_SIZE(calib_channels_6g_bw_80),
+							  channel);
+	}
+
+	if (cl_band_is_5g(cl_hw)) {
+		if (bw == CHNL_BW_160)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_160,
+							  ARRAY_SIZE(calib_channels_5g_bw_160),
+							  channel);
+
+		if (!cl_hw->chip->conf->ce_calib_runtime_en)
+			channel = cl_calib_dcoc_convert_to_channel_in_plan(channel, BAND_5G);
+
+		if (bw == CHNL_BW_20)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_20,
+							  ARRAY_SIZE(calib_channels_5g_bw_20),
+							  channel);
+
+		if (bw == CHNL_BW_40)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_40,
+							  ARRAY_SIZE(calib_channels_5g_bw_40),
+							  channel);
+
+		if (bw == CHNL_BW_80)
+			return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_80,
+							  ARRAY_SIZE(calib_channels_5g_bw_80),
+							  channel);
+	}
+
+	return cl_calib_dcoc_get_chan_idx(calib_channels_24g, ARRAY_SIZE(calib_channels_24g),
+					  channel);
+}
+
+void cl_calib_dcoc_fill_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 lna = 0, chain = 0;
+	u8 bw = cl_hw->bw;
+	u8 channel_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, cl_hw->channel, bw);
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++)
+		riu_chain_for_each(chain)
+			iq_dcoc_db->dcoc[lna][chain] =
+				chip->calib_db.dcoc[tcv_idx][channel_idx][bw][sx][chain][lna];
+}
+
+u8 cl_calib_dcoc_tcv_channel_to_idx(struct cl_chip *chip, u8 tcv_idx, u8 channel, u8 bw)
+{
+	u8 i = 0;
+
+	if (cl_chip_is_6g(chip)) {
+		if (tcv_idx == TCV0) {
+			if (bw == CHNL_BW_20)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_20,
+								  ARRAY_SIZE
+								  (calib_channels_6g_bw_20),
+								  channel);
+
+			if (bw == CHNL_BW_40)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_40,
+								  ARRAY_SIZE
+								  (calib_channels_6g_bw_40),
+								  channel);
+
+			if (bw == CHNL_BW_80)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_80,
+								  ARRAY_SIZE
+								  (calib_channels_6g_bw_80),
+								  channel);
+
+			if (bw == CHNL_BW_160)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_6g_bw_160,
+								  ARRAY_SIZE
+								  (calib_channels_6g_bw_160),
+								  channel);
+		} else if (tcv_idx == TCV1) {
+			if (bw == CHNL_BW_20)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_20,
+								  ARRAY_SIZE
+								  (calib_channels_5g_bw_20),
+								  channel);
+
+			if (bw == CHNL_BW_40)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_40,
+								  ARRAY_SIZE
+								  (calib_channels_5g_bw_40),
+								  channel);
+
+			if (bw == CHNL_BW_80)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_80,
+								  ARRAY_SIZE
+								  (calib_channels_5g_bw_80),
+								  channel);
+
+			if (bw == CHNL_BW_160)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_160,
+								  ARRAY_SIZE
+								  (calib_channels_5g_bw_160),
+								  channel);
+		}
+	} else {
+		if (channel <= NUM_CHANNELS_24G) {
+			for (i = 0; i < CALIB_CHAN_24G_MAX; i++)
+				if (calib_channels_24g[i] == channel)
+					return i;
+		} else {
+			if (bw == CHNL_BW_20)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_20,
+								ARRAY_SIZE
+								(calib_channels_5g_bw_20),
+								channel);
+
+			if (bw == CHNL_BW_40)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_40,
+								ARRAY_SIZE
+								(calib_channels_5g_bw_40),
+								channel);
+
+			if (bw == CHNL_BW_80)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_80,
+								ARRAY_SIZE
+								(calib_channels_5g_bw_80),
+								channel);
+
+			if (bw == CHNL_BW_160)
+				return cl_calib_dcoc_get_chan_idx(calib_channels_5g_bw_160,
+								ARRAY_SIZE
+								(calib_channels_5g_bw_160),
+								channel);
+		}
+	}
+
+	return 0;
+}
+
+void cl_calib_dcoc_handle_set_channel_cfm(struct cl_hw *cl_hw, bool first_channel)
+{
+	struct calib_cfm *dcoc_iq_cfm =
+		&cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_DCOC];
+	s16 calib_temperature = cl_calib_common_get_temperature(cl_hw, CALIB_CFM_DCOC);
+	u8 channel = cl_hw->channel;
+	u8 bw = cl_hw->bw;
+
+	cl_dbg_trace(cl_hw, "calib_temperature = %d, channel = %u, bw = %u\n", calib_temperature,
+		     channel, bw);
+
+	cl_calib_dcoc_handle_data(cl_hw, calib_temperature, channel, bw);
+	cl_calib_dcoc_handle_report(cl_hw, calib_temperature, channel, bw);
+
+	/*
+	 * Set the default status to FAIL, to ensure FW is actually changing the value,
+	 * if the calibration succeeded.
+	 */
+	dcoc_iq_cfm->status = CALIB_FAIL;
+}
+
+static void cl_calib_iq_handle_data(struct cl_hw *cl_hw, s16 calib_temperature, u8 channel,
+				    u8 bw, u8 plan_bitmap)
+{
+	int chain;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+	u8 channel_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel, bw);
+	struct cl_iq_calib iq_calib_dma;
+
+	riu_chain_for_each(chain) {
+		if ((plan_bitmap & (1 << chain)) == 0)
+			continue;
+
+		iq_calib_dma = cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_tx[chain];
+		cl_hw->chip->calib_db.iq_tx[tcv_idx][channel_idx][bw][sx][chain] = iq_calib_dma;
+
+		iq_calib_dma = cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_rx[chain];
+		cl_hw->chip->calib_db.iq_rx[tcv_idx][channel_idx][bw][sx][chain] = iq_calib_dma;
+	}
+}
+
+static void cl_calib_iq_lolc_handle_data(struct cl_hw *cl_hw, s16 calib_temperature,
+					 u8 channel, u8 bw, u8 plan_bitmap)
+{
+	int chain;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+	u8 channel_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel, bw);
+	__le32 lolc_calib_dma;
+
+	riu_chain_for_each(chain) {
+		if ((plan_bitmap & (1 << chain)) == 0)
+			continue;
+
+		lolc_calib_dma =
+			cl_hw->iq_dcoc_data_info.iq_dcoc_data->iq_dcoc_db.iq_tx_lolc[chain];
+		cl_hw->chip->calib_db.iq_tx_lolc[tcv_idx][channel_idx][bw][sx][chain] =
+			le32_to_cpu(lolc_calib_dma);
+	}
+}
+
+static void cl_calib_iq_lolc_handle_report(struct cl_hw *cl_hw, s16 calib_temperature,
+					   int channel, u8 bw, u8 plan_bitmap)
+{
+	struct cl_iq_dcoc_report *report = &cl_hw->iq_dcoc_data_info.iq_dcoc_data->report;
+	int chain;
+	struct cl_lolc_report lolc_report_dma;
+	int bw_mhz = BW_TO_MHZ(bw);
+	s16 lolc_threshold = cl_hw->chip->conf->ci_lolc_db_thr;
+	s32 lolc_qual = 0;
+
+	riu_chain_for_each(chain) {
+		if ((plan_bitmap & (1 << chain)) == 0)
+			continue;
+
+		lolc_report_dma = report->lolc_report[chain];
+		lolc_qual = (s16)(le16_to_cpu(lolc_report_dma.lolc_qual)) >> 8;
+
+		cl_dbg_trace(cl_hw, "LOLC Quality [chain = %u] = %d, Iter = %u\n",
+			     chain, lolc_qual, lolc_report_dma.n_iter);
+
+		if (lolc_qual > lolc_threshold) {
+			cl_dbg_warn(cl_hw,
+				    "Warning: LOLC value exceeds threshold [%ddB]: channel %u, "
+				    "bw  = %u, chain = %u, LOLC[dB] = %d, I[Iter] = %u\n",
+				    lolc_threshold, channel, bw_mhz, chain, lolc_qual,
+				    lolc_report_dma.n_iter);
+			cl_hw->chip->calib_db.errors[cl_hw->tcv_idx].lolc++;
+		}
+	}
+}
+
+static int cl_calib_iq_calibrate_channel(struct cl_hw *cl_hw, u32 channel, u32 bw,
+					 bool first_channel)
+{
+	u32 primary = 0;
+	u32 center = 0;
+	enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
+	struct cl_calib_params calib_params = {
+		(SET_CHANNEL_MODE_CALIB_IQ | SET_CHANNEL_MODE_CALIB_LOLC),
+		first_channel, SX_FREQ_OFFSET_Q2, 0
+	};
+
+	/* Convert ant to riu chain in the calib plan_bitmap */
+	calib_params.plan_bitmap =
+		cl_hw_ant_mask_to_riu_chain_mask(cl_hw, cl_hw->mask_num_antennas);
+
+	if (cl_chandef_calc(cl_hw, channel, bw, &width, &primary, &center)) {
+		cl_dbg_err(cl_hw, "cl_chandef_calc failed\n");
+		return -EINVAL;
+	}
+
+	cl_dbg_trace(cl_hw, "\n ------  START CALIB IQ CHANNEL  -----\n");
+	cl_dbg_trace(cl_hw, "channel = %u first_channel = %d\n", channel, first_channel);
+
+	/* Set channel mode to LO+IQ calibration mode */
+	return cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, calib_params);
+}
+
+static u8 cl_calib_iq_convert_plan_to_calib_db_idx(u8 chan_idx_src, u8 bw)
+{
+	u8 shift_idx = 0;
+	/*
+	 * Calibration data is fetched from calibrated channels to previous uncalibrated channels in
+	 * plan list.
+	 *
+	 * For example: channel 65 was calibrated due the channels plan list. Calibration data of
+	 * channel 65 saved in calib_db struct in the relevant chan idx place due the BW, as the
+	 * follow:
+	 * chan_idx 16 for BW 20,
+	 * chan_idx 8 for BW 40
+	 * chan_idx 4 for BW 80
+	 * chan_idx 2 for BW 160.
+	 *
+	 * We want to copy calib data of IQ & LOLC from channel 65 to channel 49. Doing the same
+	 * also to the other uncalib channels: 33->17, 65->49, 97->81 etc.
+	 *
+	 * The chan idx of channel 49 in the calib_db by BW is:
+	 * chan_idx 12 for BW 20,
+	 * chan_idx 6 for BW 40
+	 * chan_idx 3 for BW 80
+	 * (no exist chan_idx for BW 160)
+	 *
+	 * We copy the data in calib_db from idx of channel 65 to the idx of channel 49:
+	 * chan_idx 16 to chan_idx 12 (in BW 20)
+	 * chan_idx 8 to chan_idx 6 (in BW 40)
+	 * chan_idx 4 to chan_idx 3 (in BW 80)
+	 *
+	 * In general, the dst chan idx will be calculated by;
+	 * dst_idx = src_idx - 4 (for BW 20)
+	 * dst_idx = src_idx - 2 (for BW 40)
+	 * dst_idx = src_idx - 1 (for BW 80)
+	 *
+	 * The way to calc this is shiftting is by the follow bitmask:
+	 * 4 >> bw
+	 */
+	shift_idx = 4 >> bw;
+
+	return chan_idx_src - shift_idx;
+}
+
+static void cl_calib_iq_copy_data_to_uncalibrated_channels_6g(struct cl_hw *cl_hw)
+{
+	struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+	int i;
+	u8 sx = cl_hw->sx_idx;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 chan_idx_src = 0;
+	u8 chan_idx_dst = 0;
+	u8 chain = 0;
+	u8 bw = 0;
+
+	/*
+	 * Copy iq & lo calib data from 6g list plan calibrate channels: 1, 33, 65, 97, 129, 161,
+	 * 193, 22 to uncalibrated channels 17, 49, 81, 113, 145, 177, 209. copy to the correct
+	 * channel idx for each different bw
+	 */
+	for (i = 1; i < CALIB_CHAN_6G_PLAN - 1; i += 2)
+		riu_chain_for_each(chain)
+			/* Iterate only CHNL_BW_80 and CHNL_BW_20 */
+			for (bw = CHNL_BW_20; bw <= CHNL_BW_80; bw += 2) {
+				chan_idx_src =
+					cl_calib_dcoc_channel_bw_to_idx(cl_hw,
+									calib_channels_6g_plan[i],
+									bw);
+
+				chan_idx_dst =
+					cl_calib_iq_convert_plan_to_calib_db_idx(chan_idx_src, bw);
+				memcpy(&calib_db->iq_tx[tcv_idx][chan_idx_dst][bw][sx][chain],
+				       &calib_db->iq_tx[tcv_idx][chan_idx_src][bw][sx][chain],
+				       sizeof(struct cl_iq_calib));
+				memcpy(&calib_db->iq_rx[tcv_idx][chan_idx_dst][bw][sx][chain],
+				       &calib_db->iq_rx[tcv_idx][chan_idx_src][bw][sx][chain],
+				       sizeof(struct cl_iq_calib));
+				calib_db->iq_tx_lolc[tcv_idx][chan_idx_dst][bw][sx][chain] =
+					calib_db->iq_tx_lolc[tcv_idx][chan_idx_src][bw][sx][chain];
+			}
+}
+
+static bool cl_calib_iq_calibrate_6g(struct cl_hw *cl_hw)
+{
+	int i;
+	bool first_channel = true;
+
+	/* Calibrate channels: 1, 33, 65, 97, 129, 161, 193, 225 */
+	for (i = 0; i < CALIB_CHAN_6G_PLAN; i += 2) {
+		if ((cl_calib_iq_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_160,
+						   first_channel) == 0))
+			first_channel = false;
+
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_80,
+						  first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_6g_plan[i], CHNL_BW_20,
+						  first_channel) == 0)
+			first_channel = false;
+	}
+
+	/*
+	 * For these channels 17, 49, 81, 113, 145, 177, 209
+	 * copy data of next neighbor
+	 */
+	cl_calib_iq_copy_data_to_uncalibrated_channels_6g(cl_hw);
+
+	return first_channel;
+}
+
+static bool cl_calib_iq_calibrate_5g(struct cl_hw *cl_hw)
+{
+	int i;
+	bool first_channel = true;
+
+	if (cl_calib_iq_calibrate_channel(cl_hw, 36, CHNL_BW_160, first_channel) == 0)
+		first_channel = false;
+
+	if (cl_calib_iq_calibrate_channel(cl_hw, 100, CHNL_BW_160, first_channel) == 0)
+		first_channel = false;
+
+	for (i = 0; i < CALIB_CHAN_5G_PLAN; i++) {
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_5g_plan[i], CHNL_BW_80,
+						  first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_5g_plan[i], CHNL_BW_20,
+						  first_channel) == 0)
+			first_channel = false;
+	}
+
+	return first_channel;
+}
+
+static bool cl_calib_iq_calibrate_24g(struct cl_hw *cl_hw)
+{
+	int i;
+	bool first_channel = true;
+
+	if (cl_hw->chip->conf->ce_production_mode) {
+		if (cl_calib_iq_calibrate_channel(cl_hw, 1, CHNL_BW_160,
+						  first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_iq_calibrate_channel(cl_hw, 1, CHNL_BW_80,
+						  first_channel) == 0)
+			first_channel = false;
+	}
+
+	for (i = 0; i < CALIB_CHAN_24G_MAX; i++) {
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_24g[i], CHNL_BW_40,
+						  first_channel) == 0)
+			first_channel = false;
+
+		if (cl_calib_iq_calibrate_channel(cl_hw, calib_channels_24g[i], CHNL_BW_20,
+						  first_channel) == 0)
+			first_channel = false;
+	}
+
+	return first_channel;
+}
+
+static void cl_calib_iq_calibrate(struct cl_hw *cl_hw)
+{
+	if (cl_band_is_6g(cl_hw))
+		cl_calib_iq_calibrate_6g(cl_hw);
+	else if (cl_band_is_5g(cl_hw))
+		cl_calib_iq_calibrate_5g(cl_hw);
+	else if (cl_band_is_24g(cl_hw))
+		cl_calib_iq_calibrate_24g(cl_hw);
+}
+
+static void cl_calib_iq_init_calibration_tcv(struct cl_hw *cl_hw)
+{
+	u8 tcv_idx = cl_hw->tcv_idx;
+
+	cl_calib_iq_calibrate(cl_hw);
+
+	cl_hw->chip->iq_dcoc_conf.iq_file_num_ant[tcv_idx] = cl_hw->num_antennas;
+}
+
+void cl_calib_restore_channel(struct cl_hw *cl_hw, struct cl_calib_iq_restore *iq_restore)
+{
+	u8 bw = iq_restore->bw;
+	u32 primary = iq_restore->primary;
+	u32 center = iq_restore->center;
+	u8 channel = iq_restore->channel;
+
+	cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, CL_CALIB_PARAMS_DEFAULT_STRUCT);
+}
+
+void cl_calib_save_channel(struct cl_hw *cl_hw, struct cl_calib_iq_restore *iq_restore)
+{
+	iq_restore->bw = cl_hw->bw;
+	iq_restore->primary = cl_hw->primary_freq;
+	iq_restore->center = cl_hw->center_freq;
+	iq_restore->channel = ieee80211_frequency_to_channel(cl_hw->primary_freq);
+
+	cl_dbg_chip_trace(cl_hw, "bw = %u, primary = %d, center = %d, channel = %u\n",
+			  iq_restore->bw, iq_restore->primary,
+			  iq_restore->center, iq_restore->channel);
+}
+
+int cl_calib_iq_set_idle(struct cl_hw *cl_hw, bool idle)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	bool tcv0_en = cl_chip_is_tcv0_enabled(chip) && cl_radio_is_on(cl_hw_tcv0);
+	bool tcv1_en = cl_chip_is_tcv1_enabled(chip) && cl_radio_is_on(cl_hw_tcv1);
+
+	if (!idle) {
+		if (tcv1_en)
+			cl_msg_tx_set_idle(cl_hw_tcv1, MAC_ACTIVE, false);
+
+		if (tcv0_en)
+			cl_msg_tx_set_idle(cl_hw_tcv0, MAC_ACTIVE, false);
+
+		return 0;
+	}
+
+	if (tcv1_en)
+		cl_msg_tx_idle_async(cl_hw_tcv1, false);
+
+	if (tcv0_en)
+		cl_msg_tx_set_idle(cl_hw_tcv0, MAC_IDLE_SYNC, false);
+
+	cl_dbg_info(cl_hw, "idle_async_set = %u\n", cl_hw->idle_async_set);
+
+	if (wait_event_timeout(cl_hw->wait_queue, !cl_hw->idle_async_set,
+			       CL_MSG_CFM_TIMEOUT_JIFFIES))
+		return 0;
+
+	cl_dbg_err(cl_hw, "Timeout occurred - MM_IDLE_ASYNC_IND\n");
+	return -ETIMEDOUT;
+}
+
+bool cl_calib_iq_calibration_needed(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_iq_dcoc_conf *iq_dcoc_conf = &chip->iq_dcoc_conf;
+	bool calib_needed = false;
+
+	if (!IS_REAL_PHY(chip))
+		return false;
+
+	if (cl_hw->chip->conf->ce_calib_runtime_en)
+		return false;
+
+	if (cl_hw_is_tcv0(cl_hw) && chip->conf->ci_tcv1_chains_sx0)
+		return false;
+
+	if (cl_chip_is_tcv0_enabled(chip)) {
+		u8 num_antennas_tcv0 = chip->cl_hw_tcv0->num_antennas;
+
+		if (iq_dcoc_conf->iq_file_num_ant[TCV0] < num_antennas_tcv0 &&
+		    !chip->conf->ci_tcv1_chains_sx0) {
+			cl_dbg_verbose(cl_hw,
+				       "Num of antennas [%u], is larger than LOLC Calibration File "
+				       "num of antennas [%u], recalibration is needed\n",
+				       num_antennas_tcv0, iq_dcoc_conf->iq_file_num_ant[TCV0]);
+			calib_needed = true;
+		}
+	}
+
+	if (cl_chip_is_tcv1_enabled(chip)) {
+		u8 num_antennas_tcv1 = chip->cl_hw_tcv1->num_antennas;
+
+		if (iq_dcoc_conf->iq_file_num_ant[TCV1] < num_antennas_tcv1) {
+			cl_dbg_verbose(cl_hw,
+				       "Num of antennas [%u], is larger than LOLC Calibration File "
+				       "num of antennas [%u], recalibration is needed\n",
+				       num_antennas_tcv1, iq_dcoc_conf->iq_file_num_ant[TCV1]);
+			calib_needed = true;
+		}
+	}
+
+	return calib_needed;
+}
+
+void cl_calib_iq_init_calibration(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 fem_mode = cl_hw->fem_mode;
+	struct cl_iq_dcoc_conf *iq_dcoc_conf = &chip->iq_dcoc_conf;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	struct cl_calib_iq_restore iq_restore_tcv0;
+	struct cl_calib_iq_restore iq_restore_tcv1;
+	u8 save_tcv0_needed = cl_hw_tcv0 && cl_hw_tcv0->primary_freq &&
+		!chip->conf->ci_tcv1_chains_sx0;
+	u8 save_tcv1_needed = cl_hw_tcv1 && cl_hw_tcv1->primary_freq;
+
+	if (save_tcv0_needed)
+		cl_calib_save_channel(cl_hw_tcv0, &iq_restore_tcv0);
+
+	if (save_tcv1_needed)
+		cl_calib_save_channel(cl_hw_tcv1, &iq_restore_tcv1);
+
+	cl_fem_set_iq_bypass(cl_hw);
+	cl_afe_cfg_calib(chip);
+
+	if (cl_hw_tcv0 &&
+	    (chip->iq_dcoc_conf.force_calib ||
+	    (iq_dcoc_conf->iq_file_num_ant[TCV0] < cl_hw_tcv0->num_antennas &&
+	    !chip->conf->ci_tcv1_chains_sx0))) {
+		cl_calib_iq_init_calibration_tcv(cl_hw_tcv0);
+	}
+
+	if (cl_hw_tcv1 &&
+	    (chip->iq_dcoc_conf.force_calib ||
+	    iq_dcoc_conf->iq_file_num_ant[TCV1] < cl_hw_tcv1->num_antennas)) {
+		cl_calib_iq_init_calibration_tcv(cl_hw_tcv1);
+	}
+
+	cl_fem_iq_restore(cl_hw, fem_mode);
+	cl_afe_cfg_restore(chip);
+
+	if (save_tcv0_needed)
+		cl_calib_restore_channel(cl_hw_tcv0, &iq_restore_tcv0);
+
+	if (save_tcv1_needed)
+		cl_calib_restore_channel(cl_hw_tcv1, &iq_restore_tcv1);
+}
+
+void cl_calib_iq_fill_data(struct cl_hw *cl_hw, struct cl_iq_calib *iq_data,
+			   struct cl_iq_calib *iq_chip_data)
+{
+	u8 ant = 0;
+
+	for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+		iq_data[ant].coef0 = iq_chip_data[ant].coef0;
+		iq_data[ant].coef1 = iq_chip_data[ant].coef1;
+		iq_data[ant].coef2 = iq_chip_data[ant].coef2;
+		iq_data[ant].gain = iq_chip_data[ant].gain;
+	}
+}
+
+void cl_calib_iq_lolc_fill_data(struct cl_hw *cl_hw, __le32 *iq_lolc)
+{
+	struct cl_calib_db *calib_db = &cl_hw->chip->calib_db;
+	u8 ant = 0;
+	u8 bw = cl_hw->bw;
+	u8 chan_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, cl_hw->channel, bw);
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+
+	for (ant = 0; ant < MAX_ANTENNAS; ant++)
+		iq_lolc[ant] = cpu_to_le32(calib_db->iq_tx_lolc[tcv_idx][chan_idx][bw][sx][ant]);
+}
+
+void cl_calib_iq_handle_set_channel_cfm(struct cl_hw *cl_hw, u8 plan_bitmap)
+{
+	struct calib_cfm *dcoc_iq_cfm =
+		&cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ];
+	s16 calib_temperature = cl_calib_common_get_temperature(cl_hw, CALIB_CFM_IQ);
+	u8 channel = cl_hw->channel;
+	u8 bw = cl_hw->bw;
+
+	CL_DBG(cl_hw, DBG_LVL_TRACE, "calib_temperature = %d, channel = %u, bw = %u\n",
+	       calib_temperature, channel, bw);
+
+	cl_calib_iq_handle_data(cl_hw, calib_temperature, channel, bw, plan_bitmap);
+
+	/*
+	 * Set the default status to FAIL, to ensure FW is actually changing the value,
+	 * if the calibration succeeded.
+	 */
+	dcoc_iq_cfm->status = CALIB_FAIL;
+}
+
+void cl_calib_iq_lolc_handle_set_channel_cfm(struct cl_hw *cl_hw, u8 plan_bitmap)
+{
+	struct calib_cfm *dcoc_iq_cfm =
+		&cl_hw->iq_dcoc_data_info.iq_dcoc_data->dcoc_iq_cfm[CALIB_CFM_IQ];
+	s16 calib_temperature = cl_calib_common_get_temperature(cl_hw, CALIB_CFM_IQ);
+	u8 channel = cl_hw->channel;
+	u8 bw = cl_hw->bw;
+
+	cl_dbg_trace(cl_hw, "calib_temperature = %d, channel = %u, bw = %u\n", calib_temperature,
+		     channel, bw);
+
+	cl_calib_iq_lolc_handle_data(cl_hw, calib_temperature, channel, bw, plan_bitmap);
+	cl_calib_iq_lolc_handle_report(cl_hw, calib_temperature, channel, bw, plan_bitmap);
+
+	/*
+	 * Set the default status to FAIL, to ensure FW is actually changing the value,
+	 * if the calibration succeeded.
+	 */
+	dcoc_iq_cfm->status = CALIB_FAIL;
+}
+
+void cl_calib_iq_get_tone_vector(struct cl_hw *cl_hw, __le16 *tone_vector)
+{
+	u8 tone = 0;
+	u8 *vector_ptr = NULL;
+
+	switch (cl_hw->bw) {
+	case CHNL_BW_20:
+		vector_ptr = cl_hw->conf->ci_calib_conf_tone_vector_20bw;
+		break;
+	case CHNL_BW_40:
+		vector_ptr = cl_hw->conf->ci_calib_conf_tone_vector_40bw;
+		break;
+	case CHNL_BW_80:
+		vector_ptr = cl_hw->conf->ci_calib_conf_tone_vector_80bw;
+		break;
+	case CHNL_BW_160:
+		vector_ptr = cl_hw->conf->ci_calib_conf_tone_vector_160bw;
+		break;
+	default:
+		vector_ptr = cl_hw->conf->ci_calib_conf_tone_vector_20bw;
+		break;
+	}
+
+	for (tone = 0; tone < IQ_NUM_TONES_REQ; tone++)
+		tone_vector[tone] = cpu_to_le16((u16)vector_ptr[tone]);
+}
+
+void cl_calib_iq_init_production(struct cl_hw *cl_hw)
+{
+	struct cl_hw *cl_hw_other = NULL;
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (!cl_chip_is_both_enabled(chip) ||
+	    (cl_hw_is_tcv1(cl_hw) && chip->conf->ci_tcv1_chains_sx0)) {
+		if (cl_calib_iq_calibration_needed(cl_hw))
+			cl_calib_iq_init_calibration(cl_hw);
+		return;
+	}
+
+	cl_hw_other = cl_hw_other_tcv(cl_hw);
+	if (!cl_hw_other)
+		return;
+
+	if (cl_hw_other->iq_cal_ready) {
+		cl_hw_other->iq_cal_ready = false;
+		cl_calib_iq_init_calibration(cl_hw);
+	} else if (cl_calib_iq_calibration_needed(cl_hw)) {
+		cl_hw->iq_cal_ready = true;
+		cl_dbg_verbose(cl_hw, "IQ Calibration needed. Wait for both TCVs before starting "
+			       "calibration.\n");
+	}
+}
+
+/*
+ * CL80x0: TCV0 - 5g, TCV1 - 24g
+ * ==============================================
+ * 50  48  46  44  42  40  38  36  --> Start 5g
+ * 100 64  62  60  58  56  54  52
+ * 116 114 112 110 108 106 104 102
+ * 134 132 128 126 124 122 120 118
+ * 153 151 149 144 142 140 138 136
+ * 3   2   1   165 161 159 157 155  --> Start 24g
+ * 11  10  9   8   7   6   5   4
+ *                     14  13  12
+ */
+
+/*
+ * CL80x6: TCV0 - 6g, TCV1 - 5g
+ * ==============================================
+ * 25  21  17  13  9   5   2   1   --> Start 6g
+ * 57  53  49  45  41  37  33  29
+ * 89  85  81  77  73  69  65  61
+ * 121 117 113 109 105 101 97  93
+ * 153 147 143 139 135 131 127 123
+ * 185 181 177 173 169 165 161 157
+ * 217 213 209 205 201 197 193 189
+ * 42  40  38  36  233 229 225 221 --> Start 5g
+ * 58  56  54  52  50  48  46  44
+ * 108 106 104 102 100 64  62  60
+ * 124 122 120 118 116 114 112 110
+ * 142 140 138 136 134 132 128 126
+ * 161 159 157 155 153 151 149 144
+ *                             165
+ */
+
+#define BITMAP_80X0_START_TCV0  0
+#define BITMAP_80X0_MAX_TCV0    NUM_CHANNELS_5G
+
+#define BITMAP_80X0_START_TCV1 NUM_CHANNELS_5G
+#define BITMAP_80X0_MAX_TCV1   (NUM_CHANNELS_5G + NUM_CHANNELS_24G)
+
+#define BITMAP_80X6_START_TCV0  0
+#define BITMAP_80X6_MAX_TCV0    NUM_BITMAP_CHANNELS_6G
+
+#define BITMAP_80X6_START_TCV1  NUM_BITMAP_CHANNELS_6G
+#define BITMAP_80X6_MAX_TCV1    (NUM_BITMAP_CHANNELS_6G + NUM_CHANNELS_5G)
+
+#define INVALID_ADDR 0xffff
+
+static u8 cl_get_bitmap_start_tcv1(struct cl_chip *chip)
+{
+	if (cl_chip_is_6g(chip))
+		return BITMAP_80X6_START_TCV1;
+	else
+		return BITMAP_80X0_START_TCV1;
+}
+
+static u8 cl_idx_to_arr_offset(u8 idx)
+{
+	/* Divide by 8 for array index */
+	return idx >> 3;
+}
+
+static u8 cl_idx_to_bit_offset(u8 idx)
+{
+	/* Reminder is for bit index (assummed array of u8) */
+	return idx & 0x07;
+}
+
+static const u8 bits_cnt_table256[] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+static bool cl_is_vector_unset(const u8 *bitmap)
+{
+	/* Check bitmap is unset i.e. all values are CURR_BMP_UNSET */
+	u8 empty_bitmap[BIT_MAP_SIZE] = {0};
+
+	return !memcmp(bitmap, empty_bitmap, BIT_MAP_SIZE);
+}
+
+static bool cl_bitmap_test_bit_idx(const u8 *bitmap, u8 idx)
+{
+	/* Check bit at a given index is set i.e. 1 */
+	u8 arr_idx = cl_idx_to_arr_offset(idx), bit_idx = cl_idx_to_bit_offset(idx);
+
+	if (arr_idx >= BIT_MAP_SIZE)
+		return false;
+
+	/* Convert non-zero to true and zero to false */
+	return !!(bitmap[arr_idx] & BIT(bit_idx));
+}
+
+static void cl_bitmap_shift(u8 *bitmap, u8 shft)
+{
+	/* Shifts an array of byte of size len by shft number of bits to the left */
+	u8 bitmap_tmp[BIT_MAP_SIZE] = {0};
+	u8 msb_shifts = shft % 8;
+	u8 lsb_shifts = 8 - msb_shifts;
+	u8 byte_shift = shft / 8;
+	u8 last_byte = BIT_MAP_SIZE - byte_shift - 1;
+	u8 msb_idx;
+	u8 i;
+
+	memcpy(bitmap_tmp, bitmap, BIT_MAP_SIZE);
+	memset(bitmap, 0, BIT_MAP_SIZE);
+
+	for (i = 0;  i < BIT_MAP_SIZE; i++) {
+		if (i <= last_byte) {
+			msb_idx = i + byte_shift;
+			bitmap[i] = bitmap_tmp[msb_idx] >> msb_shifts;
+			if (i != last_byte)
+				bitmap[i] |= bitmap_tmp[msb_idx + 1] << lsb_shifts;
+		}
+	}
+}
+
+static bool cl_bitmap_set_bit_idx(struct cl_hw *cl_hw, u8 *bitmap, u8 bitmap_size, u8 idx)
+{
+	/* Set bit at a given index */
+	u8 arr_idx = cl_idx_to_arr_offset(idx), bit_idx = cl_idx_to_bit_offset(idx);
+
+	if (arr_idx >= bitmap_size) {
+		cl_dbg_err(cl_hw, "invalid arr_idx (%u)\n", arr_idx);
+		return false;
+	}
+
+	bitmap[arr_idx] |= BIT(bit_idx);
+	return true;
+}
+
+static u16 cl_bitmap_look_lsb_up(struct cl_hw *cl_hw, u8 *bitmap, u16 idx, bool ext)
+{
+	/* Find closest set bit with index higher than idx inside bitmap */
+	u16 curr_idx = idx;
+	u8 curr = 0;
+	u32 chan_num = ext ? NUM_EXT_CHANNELS_6G : cl_channel_num(cl_hw);
+
+	while (++curr_idx < chan_num) {
+		curr = bitmap[cl_idx_to_arr_offset(curr_idx)];
+		if (curr & (1ULL << cl_idx_to_bit_offset(curr_idx)))
+			return curr_idx;
+	}
+
+	/* No matching bit found - return original index */
+	return idx;
+}
+
+static u16 bitmap_look_msb_down(struct cl_hw *cl_hw, u8 *bitmap, u16 idx, bool ext)
+{
+	/* Find closest set bit with index lower than idx inside bitmap */
+	u16 curr_idx = idx;
+	u8 curr = 0;
+	u32 chan_num = ext ? NUM_EXT_CHANNELS_6G : cl_channel_num(cl_hw);
+
+	if (idx >= chan_num) {
+		cl_dbg_err(cl_hw, "Invalid channel index [%u]\n", idx);
+		return idx;
+	}
+
+	while (curr_idx-- != 0) {
+		curr = bitmap[cl_idx_to_arr_offset(curr_idx)];
+		if (curr & (1ULL << cl_idx_to_bit_offset(curr_idx)))
+			return curr_idx;
+	}
+
+	/* No matching bit found - return original index */
+	return idx;
+}
+
+static u8 cl_address_offset_tcv1(struct cl_hw *cl_hw)
+{
+	/* Calculate eeprom calibration data offset for tcv1 */
+	struct cl_chip *chip = cl_hw->chip;
+	u8 i, cnt = 0;
+	u8 bitmap[BIT_MAP_SIZE] = {0};
+
+	if (cl_e2p_read(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_POWER_CHAN_BMP))
+		return 0;
+
+	for (i = 0; i < cl_get_bitmap_start_tcv1(chip); i++)
+		cnt += cl_bitmap_test_bit_idx(bitmap, i);
+
+	return cnt;
+}
+
+static int cl_point_idx_to_address(struct cl_hw *cl_hw, u8 *bitmap, struct point *pt)
+{
+	/* Calculate eeprom address for a given idx and phy (initiated point) */
+	u8 i, cnt = 0;
+
+	pt->addr = INVALID_ADDR;
+
+	if (!cl_bitmap_test_bit_idx(bitmap, pt->idx))
+		return 0;
+
+	if (pt->phy >= MAX_ANTENNAS) {
+		cl_dbg_err(cl_hw, "Invalid phy number %u", pt->phy);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < pt->idx; i++)
+		cnt += cl_bitmap_test_bit_idx(bitmap, i);
+
+	if (cl_hw_is_tcv1(cl_hw))
+		cnt += cl_address_offset_tcv1(cl_hw);
+
+	pt->addr = ADDR_CALIB_POWER_PHY +
+		sizeof(struct eeprom_phy_calib) * (cnt * MAX_ANTENNAS + pt->phy);
+
+	return 0;
+}
+
+static bool cl_linear_equation_signed(struct cl_hw *cl_hw, const u16 x, s8 *y,
+				      const u16 x0, const s8 y0, const u16 x1, const s8 y1)
+{
+	/* Calculate y given to points (x0,y0) and (x1,y1) and x */
+	s32 numerator = (x - x0) * (y1 - y0);
+	s32 denominator = x1 - x0;
+
+	if (unlikely(!denominator)) {
+		cl_dbg_err(cl_hw, "zero denominator\n");
+		return false;
+	}
+
+	*y = (s8)(y0 + DIV_ROUND_CLOSEST(numerator, denominator));
+
+	return true;
+}
+
+static void cl_extend_bitmap_6g(struct cl_hw *cl_hw, u8 *bitmap, u8 *ext_bitmap)
+{
+	u8 i, ext_idx;
+
+	for (i = 0; i < cl_channel_num(cl_hw); ++i) {
+		if (cl_bitmap_test_bit_idx(bitmap, i)) {
+			ext_idx = CHAN_BITMAP_IDX_6G_2_EXT_IDX(i);
+			cl_bitmap_set_bit_idx(cl_hw, ext_bitmap, EXT_BIT_MAP_SIZE, ext_idx);
+		}
+	}
+}
+
+static bool cl_calculate_calib(struct cl_hw *cl_hw, u8 *bitmap,
+			       struct point *p0, struct point *p1, struct point *p2)
+{
+	/* Main interpolation/extrapolation function */
+	bool calc_succsess = false, use_ext = false;
+	u16 freq0, freq1, freq2;
+	u8 e2p_ext_bitmap[EXT_BIT_MAP_SIZE] = {0};
+	u8 *bitmap_to_use = bitmap;
+
+	if (unlikely(cl_is_vector_unset(bitmap)))
+		return false;
+
+	/*
+	 * In case that the band is 6g and the channel index wasn't found, it might be because
+	 * the channel is missing from the original bitmap (that includes only 20MHz channels).
+	 * In case of center channels in 40/180/160MHz, it can't be found in the original bitmap
+	 * and therefore we need to extend the bitmap to include these channels in order to perform
+	 * interpolation on it.
+	 */
+	if (cl_band_is_6g(cl_hw) && p0->idx == INVALID_CHAN_IDX) {
+		p0->idx = cl_channel_to_ext_index_6g(cl_hw, p0->chan);
+		cl_extend_bitmap_6g(cl_hw, bitmap, e2p_ext_bitmap);
+		bitmap_to_use = e2p_ext_bitmap;
+		use_ext = true;
+	}
+
+	p1->idx = cl_bitmap_look_lsb_up(cl_hw, bitmap_to_use, p0->idx, use_ext);
+	p2->idx = bitmap_look_msb_down(cl_hw, bitmap_to_use, p0->idx, use_ext);
+
+	/* Invalid case */
+	if (p1->idx == p0->idx && p2->idx == p0->idx) {
+		cl_dbg_err(cl_hw, "Invalid index %u or bad bit map\n", p0->idx);
+		return false;
+	}
+
+	/* Extrapolation case */
+	if (p1->idx == p0->idx)
+		p1->idx = bitmap_look_msb_down(cl_hw, bitmap_to_use, p2->idx, use_ext);
+	if (p2->idx == p0->idx)
+		p2->idx = cl_bitmap_look_lsb_up(cl_hw, bitmap_to_use, p1->idx, use_ext);
+
+	if (use_ext) {
+		/* Convert indices from extended bitmap to eeprom bitmap */
+		p1->idx = CHAN_EXT_IDX_6G_2_BITMAP_IDX(p1->idx);
+		p2->idx = CHAN_EXT_IDX_6G_2_BITMAP_IDX(p2->idx);
+	}
+
+	/* Address from index */
+	if (cl_point_idx_to_address(cl_hw, bitmap, p1) || p1->addr == INVALID_ADDR) {
+		cl_dbg_err(cl_hw, "Point calculation failed\n");
+		return false;
+	}
+
+	if (cl_point_idx_to_address(cl_hw, bitmap, p2) || p2->addr == INVALID_ADDR) {
+		cl_dbg_err(cl_hw, "Point calculation failed\n");
+		return false;
+	}
+
+	/* Read from eeprom */
+	if (cl_e2p_read(cl_hw->chip, (u8 *)&p1->calib, sizeof(struct eeprom_phy_calib), p1->addr))
+		return false;
+
+	/* No interpolation required */
+	if (p1->addr == p2->addr) {
+		p0->calib = p1->calib;
+		return true;
+	}
+
+	/* Interpolation or extrapolation is required - read from eeprom */
+	if (cl_e2p_read(cl_hw->chip, (u8 *)&p2->calib, sizeof(struct eeprom_phy_calib), p2->addr))
+		return false;
+
+	freq0 = (use_ext ? cl_channel_ext_idx_to_freq_6g(cl_hw, p0->idx) :
+		 cl_channel_idx_to_freq(cl_hw, p0->idx));
+	freq1 = cl_channel_idx_to_freq(cl_hw, p1->idx);
+	freq2 = cl_channel_idx_to_freq(cl_hw, p2->idx);
+
+	/* Interpolate/extrapolate target power */
+	calc_succsess = cl_linear_equation_signed(cl_hw,
+						  freq0, &p0->calib.pow,
+						  freq1, p1->calib.pow,
+						  freq2, p2->calib.pow);
+
+	/* Interpolate/extrapolate power offset */
+	calc_succsess = calc_succsess && cl_linear_equation_signed(cl_hw,
+								   freq0, &p0->calib.offset,
+								   freq1, p1->calib.offset,
+								   freq2, p2->calib.offset);
+
+	/* Interpolate/extrapolate calibration temperature */
+	calc_succsess = calc_succsess && cl_linear_equation_signed(cl_hw,
+								   freq0, &p0->calib.tmp,
+								   freq1, p1->calib.tmp,
+								   freq2, p2->calib.tmp);
+
+	if (unlikely(!calc_succsess)) {
+		cl_dbg_err(cl_hw,
+			   "Calc failed: freq0 %u idx0 %u%s, freq1 %u idx1 %u, freq2 %u idx2 %u\n",
+			   freq0, p0->idx, use_ext ? " (ext)" : "",
+			   freq1, p1->idx, freq2, p2->idx);
+		return false;
+	}
+
+	return true;
+}
+
+static int cl_read_validate_vector_bitmap(struct cl_hw *cl_hw, u8 *bitmap)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_e2p_read(chip, bitmap, BIT_MAP_SIZE, ADDR_CALIB_POWER_CHAN_BMP))
+		return -1;
+
+	/* Test if e2p was read succsefull since it is not ALL EMPTY */
+	if (cl_is_vector_unset(bitmap)) {
+		cl_dbg_err(cl_hw, "Vector not ready\n");
+		return -EPERM;
+	}
+
+	if (cl_hw_is_tcv1(cl_hw)) {
+		u8 bitmap_start = cl_get_bitmap_start_tcv1(chip);
+
+		cl_bitmap_shift(bitmap, bitmap_start);
+	}
+
+	return 0;
+}
+
+static int cl_read_or_interpolate_point(struct cl_hw *cl_hw, u8 *bitmap, struct point *p0)
+{
+	struct point p1 = {.phy = p0->phy};
+	struct point p2 = {.phy = p0->phy};
+	struct point tmp_pt = *p0;
+
+	/* Invalid address = no physical address was allocated to this channel */
+	if (tmp_pt.addr != INVALID_ADDR) {
+		if (cl_e2p_read(cl_hw->chip, (u8 *)&tmp_pt.calib,
+				sizeof(struct eeprom_phy_calib), tmp_pt.addr))
+			return -1;
+	} else {
+		/* Interpolate */
+		if (!cl_calculate_calib(cl_hw, bitmap, &tmp_pt, &p1, &p2)) {
+			cl_dbg_err(cl_hw, "Interpolation Error\n");
+			return -EFAULT;
+		}
+	}
+
+	if (tmp_pt.calib.pow == 0 && tmp_pt.calib.offset == 0 && tmp_pt.calib.tmp == 0) {
+		u16 freq = ieee80211_channel_to_frequency(tmp_pt.chan, cl_hw->nl_band);
+
+		cl_dbg_err(cl_hw, "Verify calibration point: addr %x, idx %u, freq %u, phy %u\n",
+			   tmp_pt.addr, tmp_pt.idx, freq, tmp_pt.phy);
+		/* *Uninitiated eeprom value */
+		return -EINVAL;
+	}
+
+	/* Now p0 will contain "Valid" calculations of calib" */
+	p0->calib = tmp_pt.calib;
+	return 0;
+}
+
+static void cl_calib_power_reset(struct cl_hw *cl_hw)
+{
+	u8 ch_idx;
+	u16 phy;
+	u32 chan_num = cl_band_is_6g(cl_hw) ? NUM_EXT_CHANNELS_6G : cl_channel_num(cl_hw);
+	static const struct cl_tx_power_info default_info = {
+		.power       = UNCALIBRATED_POWER,
+		.offset      = UNCALIBRATED_POWER_OFFSET,
+		.temperature = UNCALIBRATED_TEMPERATURE
+	};
+
+	/* Initiate tx_pow_info struct to default values */
+	for (ch_idx = 0; ch_idx < chan_num; ch_idx++)
+		for (phy = 0; phy < MAX_ANTENNAS; phy++)
+			cl_hw->tx_pow_info[ch_idx][phy] = default_info;
+}
+
+static void cl_calib_fill_power_info(struct cl_hw *cl_hw, u8 chan_idx, u8 ant,
+				     struct point *point)
+{
+	cl_hw->tx_pow_info[chan_idx][ant].power = point->calib.pow;
+	cl_hw->tx_pow_info[chan_idx][ant].offset = point->calib.offset;
+	cl_hw->tx_pow_info[chan_idx][ant].temperature = point->calib.tmp;
+}
+
+#define PHY0_OFFSET_FIX_Q2 -8 /* -2db */
+#define PHY3_OFFSET_FIX_Q2 14 /* +3.5db */
+
+static void cl_calib_phy_offset_adjust(struct cl_hw *cl_hw, u8 eeprom_version,
+				       u8 phy, struct point *point)
+{
+	/*
+	 * Work around:
+	 * Add 3.5dB offset to PHY3 if EEPROM version is 0.
+	 * Decrease 2dB offset to all PHYs if EEPROM version is 1.
+	 */
+	if (!cl_chip_is_6g(cl_hw->chip)) {
+		if (cl_band_is_5g(cl_hw) && eeprom_version == 0 && phy == 3)
+			point->calib.offset += PHY3_OFFSET_FIX_Q2;
+		else if (cl_band_is_24g(cl_hw) && eeprom_version == 1)
+			point->calib.offset += PHY0_OFFSET_FIX_Q2;
+	}
+}
+
+void cl_calib_power_read(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	int ret;
+	u8 bitmap[BIT_MAP_SIZE] = {0};
+	struct point curr_point = {0};
+	u8 *phy = &curr_point.phy;
+	u8 *ch_idx = &curr_point.idx;
+	u8 ext_chan_idx = 0;
+	u8 ant;
+	u8 eeprom_version = chip->eeprom_cache->general.version;
+	u32 tmp_freq = 0;
+
+	/* Initiate tx_pow_info struct to default values */
+	cl_calib_power_reset(cl_hw);
+
+	/* Vector not initiated set table to default values */
+	if (unlikely(cl_read_validate_vector_bitmap(cl_hw, bitmap))) {
+		cl_dbg_trace(cl_hw, "initiate to default values\n");
+		return;
+	}
+
+	/* Perform only on calibrated boards - cl_read_validate_vector_bitmap succeeded (0) */
+	for (*ch_idx = 0; *ch_idx < cl_channel_num(cl_hw); (*ch_idx)++) {
+		for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+			if (!(cl_hw->mask_num_antennas & BIT(ant)))
+				continue;
+
+			/*
+			 * In old eeprom versions (< 3) power info was saved in eeprom
+			 * per riu chain (unintentionally) so we need to fetch it accordingly
+			 */
+			if (eeprom_version < 3)
+				*phy = cl_hw_ant_to_riu_chain(cl_hw, ant);
+			else
+				*phy = ant;
+
+			ret = cl_point_idx_to_address(cl_hw, bitmap, &curr_point);
+
+			if (ret) {
+				/* Don't overwrite default values */
+				cl_dbg_err(cl_hw, "point idx to address failed\n");
+				continue;
+			}
+
+			if (cl_band_is_6g(cl_hw)) {
+				tmp_freq = cl_channel_idx_to_freq(cl_hw, *ch_idx);
+				curr_point.chan = ieee80211_frequency_to_channel(tmp_freq);
+			}
+
+			ret = cl_read_or_interpolate_point(cl_hw, bitmap, &curr_point);
+			/* Unable to calculate new value ==> DON'T overwrite default values */
+			if (unlikely(ret))
+				continue;
+
+			cl_calib_phy_offset_adjust(cl_hw, eeprom_version, *phy, &curr_point);
+
+			if (cl_band_is_6g(cl_hw))
+				ext_chan_idx = CHAN_BITMAP_IDX_6G_2_EXT_IDX(*ch_idx);
+			else
+				ext_chan_idx = *ch_idx;
+
+			cl_calib_fill_power_info(cl_hw, ext_chan_idx, ant, &curr_point);
+		}
+	}
+
+	if (!cl_band_is_6g(cl_hw))
+		goto calib_read_out;
+
+	/*
+	 * Fill info for channels that are missing from the original bitmap, which are the
+	 * center channels in 40/180/160MHz (channels 3, 7, 11, etc..).
+	 */
+	for (ext_chan_idx = 0; ext_chan_idx < NUM_EXT_CHANNELS_6G; ext_chan_idx++) {
+		/* Skip channels that were already filled above */
+		tmp_freq = cl_channel_ext_idx_to_freq_6g(cl_hw, ext_chan_idx);
+
+		/* Chan field needs to be updated before calling to cl_read_or_interpolate_point */
+		curr_point.chan = ieee80211_frequency_to_channel(tmp_freq);
+
+		/* If the channel is found in the bitmap - we already handled it above */
+		if (cl_channel_to_bitmap_index(cl_hw, curr_point.chan) != INVALID_CHAN_IDX)
+			continue;
+
+		for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+			if (!(cl_hw->mask_num_antennas & BIT(ant)))
+				continue;
+
+			/*
+			 * In old eeprom versions (< 3) power info was saved in eeprom
+			 * per riu chain (unintentionally) so we need to fetch it accordingly
+			 */
+			if (eeprom_version < 3)
+				*phy = cl_hw_ant_to_riu_chain(cl_hw, ant);
+			else
+				*phy = ant;
+
+			/*
+			 * Addr and idx fields needs to be invalid to successfully interpolate the
+			 * power info on the extended eeprom bitmap.
+			 */
+			curr_point.addr = INVALID_ADDR;
+			curr_point.idx = INVALID_CHAN_IDX;
+
+			ret = cl_read_or_interpolate_point(cl_hw, bitmap, &curr_point);
+
+			/* Unable to calculate new value ==> DON'T overwrite default values */
+			if (unlikely(ret))
+				continue;
+
+			cl_calib_fill_power_info(cl_hw, ext_chan_idx, ant, &curr_point);
+		}
+	}
+calib_read_out:
+	cl_dbg_trace(cl_hw, "Created tx_pow_info\n");
+}
+
+void cl_calib_power_offset_fill(struct cl_hw *cl_hw, u8 channel,
+				u8 bw, u8 offset[MAX_ANTENNAS])
+{
+	u8 i, chain;
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	s8 pow_offset;
+	s8 signed_offset;
+
+	if (chan_idx == INVALID_CHAN_IDX)
+		return;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		if (!(cl_hw->mask_num_antennas & BIT(i)))
+			continue;
+
+		pow_offset = cl_hw->tx_pow_info[chan_idx][i].offset;
+		signed_offset = cl_power_offset_check_margin(cl_hw, bw, i, pow_offset);
+		chain = cl_hw_ant_to_riu_chain(cl_hw, i);
+		offset[chain] = cl_convert_signed_to_reg_value(signed_offset);
+	}
+}
+
+struct cl_runtime_work {
+	struct work_struct ws;
+	struct cl_hw *cl_hw;
+	u32 channel;
+	u8 bw;
+	u16 primary;
+	u16 center;
+};
+
+static int _cl_calib_runtime_and_switch_channel(struct cl_hw *cl_hw, u32 channel, u8 bw,
+						u16 primary, u16 center,
+						struct cl_calib_params calib_params)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_calib_iq_restore iq_restore_other_tcv;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+	int ret = 0;
+	u8 fem_mode = cl_hw->fem_mode;
+	u8 save_other_tcv_needed = cl_chip_is_both_enabled(chip) && cl_hw_other &&
+					!!cl_hw_other->primary_freq;
+
+	cl_hw->calib_runtime_needed = false;
+
+	if (save_other_tcv_needed)
+		cl_calib_save_channel(cl_hw_other, &iq_restore_other_tcv);
+
+	if (cl_chip_is_both_enabled(chip)) {
+		ret = cl_calib_iq_set_idle(cl_hw, true);
+		if (ret)
+			return ret;
+	}
+
+	cl_fem_set_iq_bypass(cl_hw);
+	cl_afe_cfg_calib(chip);
+
+	/* Calibration by the default values */
+	if (cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center, calib_params)) {
+		cl_dbg_chip_err(cl_hw, "Failed to calibrate channel %u, bw %u\n",
+				channel, bw);
+		ret = -1;
+	}
+
+	cl_fem_iq_restore(cl_hw, fem_mode);
+	cl_afe_cfg_restore(chip);
+
+	if (save_other_tcv_needed)
+		cl_calib_restore_channel(cl_hw_other, &iq_restore_other_tcv);
+
+	/* Set channel to load the new calib data */
+	ret += cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center,
+				     CL_CALIB_PARAMS_DEFAULT_STRUCT);
+
+	if (cl_chip_is_both_enabled(chip))
+		cl_calib_iq_set_idle(cl_hw, false);
+
+	return ret;
+}
+
+static void cl_calib_runtime_work_handler(struct work_struct *ws)
+{
+	struct cl_runtime_work *runtime_work = container_of(ws, struct cl_runtime_work, ws);
+
+	cl_calib_runtime_and_switch_channel(runtime_work->cl_hw, runtime_work->channel,
+					    runtime_work->bw, runtime_work->primary,
+					    runtime_work->center);
+
+	kfree(runtime_work);
+}
+
+static bool cl_calib_runtime_is_channel_calibrated(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+	int chain, lna;
+	u8 chan_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel, bw);
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 sx = cl_hw->sx_idx;
+
+	riu_chain_for_each(chain) {
+		if (!cl_hw->chip->calib_db.iq_tx[tcv_idx][chan_idx][bw][sx][chain].gain &&
+		    !cl_hw->chip->calib_db.iq_tx[tcv_idx][chan_idx][bw][sx][chain].coef0 &&
+		    !cl_hw->chip->calib_db.iq_tx[tcv_idx][chan_idx][bw][sx][chain].coef1 &&
+		    !cl_hw->chip->calib_db.iq_tx[tcv_idx][chan_idx][bw][sx][chain].coef2) {
+			cl_dbg_trace(cl_hw, "IQ TX calibration data is missing\n");
+			return false;
+		}
+
+		if (!cl_hw->chip->calib_db.iq_rx[tcv_idx][chan_idx][bw][sx][chain].gain &&
+		    !cl_hw->chip->calib_db.iq_rx[tcv_idx][chan_idx][bw][sx][chain].coef0 &&
+		    !cl_hw->chip->calib_db.iq_rx[tcv_idx][chan_idx][bw][sx][chain].coef1 &&
+		    !cl_hw->chip->calib_db.iq_rx[tcv_idx][chan_idx][bw][sx][chain].coef2) {
+			cl_dbg_trace(cl_hw, "IQ RX calibration data is missing\n");
+			return false;
+		}
+
+		if (!cl_hw->chip->calib_db.iq_tx_lolc[tcv_idx][chan_idx][bw][sx][chain]) {
+			cl_dbg_trace(cl_hw, "LOLC calibration data is missing\n");
+			return false;
+		}
+	}
+
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+		riu_chain_for_each(chain) {
+			if (!cl_hw->chip->calib_db.dcoc[tcv_idx][chan_idx][bw][sx][chain][lna].i &&
+			    !cl_hw->chip->calib_db.dcoc[tcv_idx][chan_idx][bw][sx][chain][lna].q) {
+				cl_dbg_trace(cl_hw, "DCOC calibration data is missing\n");
+				return false;
+			}
+		}
+	}
+
+	/* If all the calibration data of channel exist */
+	return true;
+}
+
+bool cl_calib_runtime_is_allowed(struct cl_hw *cl_hw)
+{
+	if (!cl_hw)
+		return false;
+
+	if (cl_hw->scanner && cl_is_scan_in_progress(cl_hw->scanner))
+		return false;
+
+	return true;
+}
+
+void cl_calib_runtime_work(struct cl_hw *cl_hw, u32 channel, u8 bw, u16 primary,
+			   u16 center)
+{
+	struct cl_runtime_work *runtime_work = kzalloc(sizeof(*runtime_work), GFP_ATOMIC);
+
+	if (!runtime_work)
+		return;
+
+	runtime_work->cl_hw = cl_hw;
+	runtime_work->channel = channel;
+	runtime_work->bw = bw;
+	runtime_work->primary = primary;
+	runtime_work->center = center;
+	INIT_WORK(&runtime_work->ws, cl_calib_runtime_work_handler);
+	queue_work(cl_hw->drv_workqueue, (struct work_struct *)(&runtime_work->ws));
+}
+
+int cl_calib_runtime_and_switch_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+					u32 center)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+	struct cl_calib_params calib_params = {SET_CHANNEL_MODE_CALIB, false, SX_FREQ_OFFSET_Q2, 0};
+	int ret = 0;
+	bool calib_needed = (cl_hw->chip->conf->ci_calib_runtime_force ||
+			     !cl_calib_runtime_is_channel_calibrated(cl_hw, channel, bw)) &&
+			    !cl_hw->sw_scan_in_progress;
+
+	mutex_lock(&cl_hw->chip->calib_runtime_mutex);
+
+	if (!calib_needed || !cl_calib_runtime_is_allowed(cl_hw) ||
+	    (cl_chip_is_both_enabled(chip) && !cl_calib_runtime_is_allowed(cl_hw_other))) {
+		if (calib_needed)
+			cl_hw->calib_runtime_needed = true;
+
+		/* Switch channel without calibration */
+		ret = cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center,
+					    CL_CALIB_PARAMS_DEFAULT_STRUCT);
+		mutex_unlock(&cl_hw->chip->calib_runtime_mutex);
+
+		return ret;
+	}
+
+	/* Convert ant to riu chain in the calib plan_bitmap */
+	calib_params.plan_bitmap = cl_hw_ant_mask_to_riu_chain_mask(cl_hw,
+								    cl_hw->mask_num_antennas);
+
+	/* This mutex needs to be held during the whole calibration process */
+	mutex_lock(&cl_hw->chip->set_idle_mutex);
+	ret = _cl_calib_runtime_and_switch_channel(cl_hw, channel, bw, primary, center,
+						   calib_params);
+	mutex_unlock(&cl_hw->chip->set_idle_mutex);
+
+	mutex_unlock(&cl_hw->chip->calib_runtime_mutex);
+
+	return ret;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 10/96] cl8k: add calib.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (8 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 09/96] cl8k: add calib.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 11/96] cl8k: add channel.c viktor.barna
                   ` (85 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/calib.h | 390 +++++++++++++++++++++++
 1 file changed, 390 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/calib.h

diff --git a/drivers/net/wireless/celeno/cl8k/calib.h b/drivers/net/wireless/celeno/cl8k/calib.h
new file mode 100644
index 000000000000..6eb286392dd6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/calib.h
@@ -0,0 +1,390 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_CALIB_H
+#define CL_CALIB_H
+
+#include <linux/workqueue.h>
+#include <net/cfg80211.h>
+
+#include "def.h"
+
+#define DCOC_LNA_GAIN_NUM     8
+#define MAX_SX                2
+#define IQ_NUM_TONES_REQ      8
+#define IQ_NUM_TONES_CFM      (2 * IQ_NUM_TONES_REQ)
+#define SINGLETONS_MAX_NUM    1
+#define LOOPS_MAX_NUM         (2 + SINGLETONS_MAX_NUM) /* 1: pre,2-11:singletone,12:post */
+#define SX_FREQ_OFFSET_Q2     5
+
+enum calib_cfm_id_type {
+	CALIB_CFM_DCOC,
+	CALIB_CFM_IQ,
+	CALIB_CFM_MAX
+};
+
+enum calib_channel_idx_24g {
+	CALIB_CHAN_24G_1,
+	CALIB_CHAN_24G_6,
+	CALIB_CHAN_24G_11,
+	CALIB_CHAN_24G_MAX,
+};
+
+enum calib_channel_idx_5g {
+	CALIB_CHAN_5G_36,
+	CALIB_CHAN_5G_40,
+	CALIB_CHAN_5G_44,
+	CALIB_CHAN_5G_48,
+	CALIB_CHAN_5G_52,
+	CALIB_CHAN_5G_56,
+	CALIB_CHAN_5G_60,
+	CALIB_CHAN_5G_64,
+	CALIB_CHAN_5G_100,
+	CALIB_CHAN_5G_104,
+	CALIB_CHAN_5G_108,
+	CALIB_CHAN_5G_112,
+	CALIB_CHAN_5G_116,
+	CALIB_CHAN_5G_120,
+	CALIB_CHAN_5G_124,
+	CALIB_CHAN_5G_128,
+	CALIB_CHAN_5G_132,
+	CALIB_CHAN_5G_136,
+	CALIB_CHAN_5G_140,
+	CALIB_CHAN_5G_144,
+	CALIB_CHAN_5G_149,
+	CALIB_CHAN_5G_153,
+	CALIB_CHAN_5G_157,
+	CALIB_CHAN_5G_161,
+	CALIB_CHAN_5G_165,
+	CALIB_CHAN_5G_MAX
+};
+
+enum calib_channel_idx_6g {
+	CALIB_CHAN_6G_1,
+	CALIB_CHAN_6G_5,
+	CALIB_CHAN_6G_9,
+	CALIB_CHAN_6G_13,
+	CALIB_CHAN_6G_17,
+	CALIB_CHAN_6G_21,
+	CALIB_CHAN_6G_25,
+	CALIB_CHAN_6G_29,
+	CALIB_CHAN_6G_33,
+	CALIB_CHAN_6G_37,
+	CALIB_CHAN_6G_41,
+	CALIB_CHAN_6G_45,
+	CALIB_CHAN_6G_49,
+	CALIB_CHAN_6G_53,
+	CALIB_CHAN_6G_57,
+	CALIB_CHAN_6G_61,
+	CALIB_CHAN_6G_65,
+	CALIB_CHAN_6G_69,
+	CALIB_CHAN_6G_73,
+	CALIB_CHAN_6G_77,
+	CALIB_CHAN_6G_81,
+	CALIB_CHAN_6G_85,
+	CALIB_CHAN_6G_89,
+	CALIB_CHAN_6G_93,
+	CALIB_CHAN_6G_97,
+	CALIB_CHAN_6G_101,
+	CALIB_CHAN_6G_105,
+	CALIB_CHAN_6G_109,
+	CALIB_CHAN_6G_113,
+	CALIB_CHAN_6G_117,
+	CALIB_CHAN_6G_121,
+	CALIB_CHAN_6G_125,
+	CALIB_CHAN_6G_129,
+	CALIB_CHAN_6G_133,
+	CALIB_CHAN_6G_137,
+	CALIB_CHAN_6G_141,
+	CALIB_CHAN_6G_145,
+	CALIB_CHAN_6G_149,
+	CALIB_CHAN_6G_153,
+	CALIB_CHAN_6G_157,
+	CALIB_CHAN_6G_161,
+	CALIB_CHAN_6G_165,
+	CALIB_CHAN_6G_169,
+	CALIB_CHAN_6G_173,
+	CALIB_CHAN_6G_177,
+	CALIB_CHAN_6G_181,
+	CALIB_CHAN_6G_185,
+	CALIB_CHAN_6G_189,
+	CALIB_CHAN_6G_193,
+	CALIB_CHAN_6G_197,
+	CALIB_CHAN_6G_201,
+	CALIB_CHAN_6G_205,
+	CALIB_CHAN_6G_209,
+	CALIB_CHAN_6G_213,
+	CALIB_CHAN_6G_217,
+	CALIB_CHAN_6G_221,
+	CALIB_CHAN_6G_225,
+	CALIB_CHAN_6G_229,
+	CALIB_CHAN_6G_233,
+	CALIB_CHAN_6G_MAX,
+};
+
+/* MAX(CALIB_CHAN_24G_MAX, CALIB_CHAN_5G_MAX, CALIB_CHAN_6G_MAX) */
+#define CALIB_CHAN_MAX CALIB_CHAN_6G_MAX
+
+struct cl_dcoc_calib {
+	s8 i;
+	s8 q;
+};
+
+struct cl_dcoc_report {
+	__le16 i_dc;
+	__le16 i_iterations;
+	__le16 q_dc;
+	__le16 q_iterations;
+};
+
+struct cl_iq_report {
+	u8 status;
+	__le16 amplitude_mismatch[IQ_NUM_TONES_CFM];
+	__le16 phase_mismatch[IQ_NUM_TONES_CFM];
+	s8 ir_db[LOOPS_MAX_NUM][IQ_NUM_TONES_CFM];
+	s8 ir_db_avg_post;
+};
+
+struct cl_iq_calib {
+	__le32 coef0;
+	__le32 coef1;
+	__le32 coef2;
+	__le32 gain;
+};
+
+struct cl_lolc_report {
+	u8 status;
+	u8 n_iter;
+	__le16 lolc_qual;
+};
+
+struct cl_gain_report {
+	u8 status;
+	u8 rx_gain;
+	u8 tx_gain;
+	u8 gain_quality;
+	__le16 final_p2p;
+	__le16 initial_p2p;
+};
+
+struct cl_iq_dcoc_conf {
+	bool dcoc_calib_needed[TCV_MAX];
+	u8 dcoc_file_num_ant[TCV_MAX];
+	bool iq_calib_needed;
+	u8 iq_file_num_ant[TCV_MAX];
+	bool force_calib;
+};
+
+struct cl_iq_dcoc_info {
+	struct cl_dcoc_calib dcoc[DCOC_LNA_GAIN_NUM][MAX_ANTENNAS];
+	struct cl_iq_calib iq_tx[MAX_ANTENNAS];
+	__le32 iq_tx_lolc[MAX_ANTENNAS];
+	struct cl_iq_calib iq_rx[MAX_ANTENNAS];
+};
+
+struct cl_iq_dcoc_report {
+	struct cl_dcoc_report dcoc[DCOC_LNA_GAIN_NUM][MAX_ANTENNAS];
+	struct cl_gain_report gain_tx[MAX_ANTENNAS];
+	struct cl_gain_report gain_rx[MAX_ANTENNAS];
+	struct cl_lolc_report lolc_report[MAX_ANTENNAS];
+	struct cl_iq_report iq_tx[MAX_ANTENNAS];
+	struct cl_iq_report iq_rx[MAX_ANTENNAS];
+};
+
+struct calib_cfm {
+	u8 status;
+	__le16 raw_bits_data_0;
+	__le16 raw_bits_data_1;
+};
+
+struct cl_iq_dcoc_data {
+	struct cl_iq_dcoc_info iq_dcoc_db;
+	struct cl_iq_dcoc_report report;
+	struct calib_cfm dcoc_iq_cfm[CALIB_CFM_MAX];
+};
+
+struct cl_iq_dcoc_data_info {
+	struct cl_iq_dcoc_data *iq_dcoc_data;
+	u32 dma_addr;
+};
+
+struct cl_calib_params {
+	u8 mode;
+	bool first_channel;
+	s8 sx_freq_offset_mhz;
+	u32 plan_bitmap;
+};
+
+struct cl_calib_work {
+	struct work_struct ws;
+	struct cl_hw *cl_hw;
+};
+
+struct cl_calib_chain {
+	u8 pair;
+	u8 initial_tx_gain;
+	u8 initial_rx_gain;
+};
+
+enum cl_calib_flags {
+	CALIB_FLAG_CREATE = 1 << 0,
+	CALIB_FLAG_VERSION = 1 << 1,
+	CALIB_FLAG_TITLE = 1 << 2,
+	CALIB_FLAG_HEADER_TCV0 = 1 << 3,
+	CALIB_FLAG_HEADER_TCV1 = 1 << 4,
+
+	CALIB_FLAG_HEADER_TCV01 = (CALIB_FLAG_HEADER_TCV0 |
+				   CALIB_FLAG_HEADER_TCV1),
+	CALIB_FLAG_ALL_REPORT = (CALIB_FLAG_CREATE |
+				 CALIB_FLAG_VERSION |
+				 CALIB_FLAG_TITLE),
+	CALIB_FLAG_ALL = (CALIB_FLAG_CREATE |
+			  CALIB_FLAG_VERSION |
+			  CALIB_FLAG_TITLE |
+			  CALIB_FLAG_HEADER_TCV0 |
+			  CALIB_FLAG_HEADER_TCV1)
+};
+
+struct cl_calib_file_flags {
+	u8 dcoc;
+	u8 dcoc_report;
+	u8 lolc;
+	u8 lolc_report;
+	u8 iq_tx;
+	u8 iq_tx_report;
+	u8 iq_rx;
+	u8 iq_rx_report;
+	u8 rx_gain_report;
+	bool iq_plan;
+};
+
+struct cl_calib_errors {
+	u16 dcoc;
+	u16 lolc;
+	u16 iq_tx;
+	u16 iq_rx;
+};
+
+struct cl_calib_db {
+	struct cl_dcoc_calib
+		dcoc[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS][DCOC_LNA_GAIN_NUM];
+	u32 iq_tx_lolc[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+	struct cl_iq_calib iq_tx[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+	struct cl_iq_calib iq_rx[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX][MAX_SX][MAX_ANTENNAS];
+	struct cl_calib_file_flags file_flags;
+	struct cl_calib_errors errors[TCV_MAX];
+	struct list_head plan[TCV_MAX][CALIB_CHAN_MAX][CHNL_BW_MAX];
+	bool is_plan_initialized;
+};
+
+#define SET_PHY_DATA_FLAGS_DCOC       0x1 /* Set DCOC calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_TX      0x2 /* Set IQ Tx calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_RX      0x4 /* Set IQ Rx calibration data.*/
+#define SET_PHY_DATA_FLAGS_IQ_TX_LOLC 0x8 /* Set IQ Tx LOLC calibration data.*/
+#define SET_PHY_DATA_FLAGS_ALL ( \
+	SET_PHY_DATA_FLAGS_DCOC | \
+	SET_PHY_DATA_FLAGS_IQ_TX | \
+	SET_PHY_DATA_FLAGS_IQ_RX | \
+	SET_PHY_DATA_FLAGS_IQ_TX_LOLC)
+#define SET_PHY_DATA_FLAGS_LISTENER ( \
+	SET_PHY_DATA_FLAGS_DCOC | \
+	SET_PHY_DATA_FLAGS_IQ_RX)
+
+#define CL_CALIB_PARAMS_DEFAULT_STRUCT \
+	((struct cl_calib_params){SET_CHANNEL_MODE_OPERETIONAL, false, 0, 0})
+
+#define CALIB_CHAN_5G_PLAN 6
+#define CALIB_CHAN_6G_PLAN 15
+
+struct cl_chip;
+
+void cl_calib_dcoc_init_calibration(struct cl_hw *cl_hw);
+u8 cl_calib_dcoc_channel_bw_to_idx(struct cl_hw *cl_hw, u8 channel, u8 bw);
+void cl_calib_dcoc_fill_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db);
+u8 cl_calib_dcoc_tcv_channel_to_idx(struct cl_chip *chip, u8 tcv_idx, u8 channel, u8 bw);
+void cl_calib_dcoc_handle_set_channel_cfm(struct cl_hw *cl_hw, bool first_channel);
+void cl_calib_common_start_work(struct cl_hw *cl_hw);
+void cl_calib_common_fill_phy_data(struct cl_hw *cl_hw, struct cl_iq_dcoc_info *iq_dcoc_db,
+				   u8 flags);
+int cl_calib_common_tables_alloc(struct cl_hw *cl_hw);
+void cl_calib_common_tables_free(struct cl_hw *cl_hw);
+int cl_calib_common_handle_set_channel_cfm(struct cl_hw *cl_hw,
+					   struct cl_calib_params calib_params);
+int cl_calib_common_check_errors(struct cl_hw *cl_hw);
+s16 cl_calib_common_get_temperature(struct cl_hw *cl_hw, u8 cfm_type);
+
+/* Calibration constants */
+#define CALIB_TX_GAIN_DEFAULT        (0x75)
+#define GAIN_SLEEVE_TRSHLD_DEFAULT   (2)
+#define CALIB_NCO_AMP_DEFAULT        (-10)
+#define CALIB_NCO_FREQ_DEFAULT       (16)       /* 5M/312.5K for LO & RGC */
+#define LO_P_THRESH                  (1000000)
+#define N_SAMPLES_EXP_LOLC           (13)
+#define N_SAMPLES_EXP_IQC            (13)
+#define N_BIT_FIR_SCALE              (11)
+#define N_BIT_AMP_SCALE              (10)
+#define N_BIT_PHASE_SCALE            (10)
+#define GP_RAD_TRSHLD_DEFAULT        (1144) /* Represents 1 degree in Q(16,16): 1*(pi/180) */
+#define GA_LIN_UPPER_TRSHLD_DEFAULT  (66295) /* Represents 0.1 db in Q(16,16): 10^( 0.1/20)*2^16 */
+#define GA_LIN_LOWER_TRSHLD_DEFAULT  (64786) /* Represents -0.1 db in Q(16,16): 10^(-0.1/20)*2^16 */
+#define COMP_FILTER_LEN_DEFAULT      (9)
+#define SINGLETONS_NUM_DEFAULT       (10) /* Set to SINGLETONS_MAX_NUM for now */
+#define IQ_POST_IDX                  (LOOPS_MAX_NUM - 1)
+#define RAMPUP_TIME                  (50)
+#define LO_COARSE_STEP               (20)
+#define LO_FINE_STEP                 (1)
+
+#define DCOC_MAX_VGA                      0x14
+#define CALIB_RX_GAIN_DEFAULT             0x83
+#define CALIB_RX_GAIN_UPPER_LIMIT         0x14
+#define CALIB_RX_GAIN_LOWER_LIMIT         0x0
+#define DCOC_MAX_VGA_ATHOS                0x1E
+#define CALIB_RX_GAIN_DEFAULT_ATHOS       0x8D
+#define CALIB_RX_GAIN_UPPER_LIMIT_ATHOS   0x1E
+#define CALIB_RX_GAIN_LOWER_LIMIT_ATHOS   0x0A
+#define DCOC_MAX_VGA_ATHOS_B              0x14
+#define CALIB_RX_GAIN_DEFAULT_ATHOS_B     0x81
+#define CALIB_RX_GAIN_UPPER_LIMIT_ATHOS_B 0x14
+#define CALIB_RX_GAIN_LOWER_LIMIT_ATHOS_B 0x0
+
+struct cl_calib_iq_restore {
+	u8 bw;
+	u32 primary;
+	u32 center;
+	u8 channel;
+};
+
+bool cl_calib_iq_calibration_needed(struct cl_hw *cl_hw);
+void cl_calib_iq_file_flags_clear(struct cl_chip *chip);
+void cl_calib_iq_file_flags_set(struct cl_chip *chip);
+int cl_calib_iq_post_read_actions(struct cl_chip *chip, char *buf);
+void cl_calib_iq_init_calibration(struct cl_hw *cl_hw);
+void cl_calib_iq_fill_data(struct cl_hw *cl_hw, struct cl_iq_calib *iq_data,
+			   struct cl_iq_calib *iq_chip_data);
+void cl_calib_iq_lolc_fill_data(struct cl_hw *cl_hw, __le32 *iq_lolc);
+void cl_calib_iq_handle_set_channel_cfm(struct cl_hw *cl_hw, u8 plan_bitmap);
+void cl_calib_iq_lolc_handle_set_channel_cfm(struct cl_hw *cl_hw, u8 plan_bitmap);
+int cl_calib_iq_lolc_write_version(struct cl_hw *cl_hw);
+int cl_calib_iq_lolc_report_write_version(struct cl_hw *cl_hw);
+int cl_calib_iq_lolc_write_file(struct cl_hw *cl_hw, s32 *params);
+int cl_calib_iq_lolc_report_write_file(struct cl_hw *cl_hw, s32 *params);
+void cl_calib_iq_get_tone_vector(struct cl_hw *cl_hw, __le16 *tone_vector);
+void cl_calib_iq_init_production(struct cl_hw *cl_hw);
+int cl_calib_iq_set_idle(struct cl_hw *cl_hw, bool idle);
+void cl_calib_restore_channel(struct cl_hw *cl_hw, struct cl_calib_iq_restore *iq_restore);
+void cl_calib_save_channel(struct cl_hw *cl_hw, struct cl_calib_iq_restore *iq_restore);
+
+#define UNCALIBRATED_POWER        15
+#define UNCALIBRATED_POWER_OFFSET 0
+#define UNCALIBRATED_TEMPERATURE  35
+
+struct point;
+void cl_calib_power_read(struct cl_hw *cl_hw);
+void cl_calib_power_offset_fill(struct cl_hw *cl_hw, u8 channel,
+				u8 bw, u8 offset[MAX_ANTENNAS]);
+int cl_calib_runtime_and_switch_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+					u32 center);
+void cl_calib_runtime_work(struct cl_hw *cl_hw, u32 channel, u8 bw, u16 primary, u16 center);
+bool cl_calib_runtime_is_allowed(struct cl_hw *cl_hw);
+
+#endif /* CL_CALIB_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 11/96] cl8k: add channel.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (9 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 10/96] cl8k: add calib.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 12/96] cl8k: add channel.h viktor.barna
                   ` (84 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/channel.c | 1656 ++++++++++++++++++++
 1 file changed, 1656 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/channel.c

diff --git a/drivers/net/wireless/celeno/cl8k/channel.c b/drivers/net/wireless/celeno/cl8k/channel.c
new file mode 100644
index 000000000000..777c5f749059
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/channel.c
@@ -0,0 +1,1656 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "vif.h"
+#include "dfs.h"
+#include "reg/reg_defs.h"
+#include "hw.h"
+#include "utils.h"
+#include "channel.h"
+
+#define CASE_CHAN2BITMAP_IDX_6G(_chan) { case _chan: return (b6g_ch ## _chan); }
+#define CASE_CHAN2EXT_IDX_6G(_chan) { case _chan: return (ext_b6g_ch ## _chan); }
+#define CASE_CHAN2IDX_5G(_chan) { case _chan: return (b5g_ch ## _chan); }
+#define CASE_CHAN2IDX_2G(_chan) { case _chan: return (b24g_ch ## _chan); }
+
+#define CASE_BITMAP_IDX2FREQ_6G(_chan) { case (b6g_ch ## _chan): return FREQ6G(_chan); }
+#define CASE_EXT_IDX2FREQ_6G(_chan) { case (ext_b6g_ch ## _chan): return FREQ6G(_chan); }
+#define CASE_IDX2FREQ_5G(_chan) { case (b5g_ch ## _chan): return FREQ5G(_chan); }
+#define CASE_IDX2FREQ_2G(_chan) { case (b24g_ch ## _chan): return FREQ2G(_chan); }
+
+#define INVALID_FREQ 0xffff
+
+static u8 cl_channel_to_bitmap_index_6g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2BITMAP_IDX_6G(1);
+	CASE_CHAN2BITMAP_IDX_6G(2);
+	CASE_CHAN2BITMAP_IDX_6G(5);
+	CASE_CHAN2BITMAP_IDX_6G(9);
+	CASE_CHAN2BITMAP_IDX_6G(13);
+	CASE_CHAN2BITMAP_IDX_6G(17);
+	CASE_CHAN2BITMAP_IDX_6G(21);
+	CASE_CHAN2BITMAP_IDX_6G(25);
+	CASE_CHAN2BITMAP_IDX_6G(29);
+	CASE_CHAN2BITMAP_IDX_6G(33);
+	CASE_CHAN2BITMAP_IDX_6G(37);
+	CASE_CHAN2BITMAP_IDX_6G(41);
+	CASE_CHAN2BITMAP_IDX_6G(45);
+	CASE_CHAN2BITMAP_IDX_6G(49);
+	CASE_CHAN2BITMAP_IDX_6G(53);
+	CASE_CHAN2BITMAP_IDX_6G(57);
+	CASE_CHAN2BITMAP_IDX_6G(61);
+	CASE_CHAN2BITMAP_IDX_6G(65);
+	CASE_CHAN2BITMAP_IDX_6G(69);
+	CASE_CHAN2BITMAP_IDX_6G(73);
+	CASE_CHAN2BITMAP_IDX_6G(77);
+	CASE_CHAN2BITMAP_IDX_6G(81);
+	CASE_CHAN2BITMAP_IDX_6G(85);
+	CASE_CHAN2BITMAP_IDX_6G(89);
+	CASE_CHAN2BITMAP_IDX_6G(93);
+	CASE_CHAN2BITMAP_IDX_6G(97);
+	CASE_CHAN2BITMAP_IDX_6G(101);
+	CASE_CHAN2BITMAP_IDX_6G(105);
+	CASE_CHAN2BITMAP_IDX_6G(109);
+	CASE_CHAN2BITMAP_IDX_6G(113);
+	CASE_CHAN2BITMAP_IDX_6G(117);
+	CASE_CHAN2BITMAP_IDX_6G(121);
+	CASE_CHAN2BITMAP_IDX_6G(125);
+	CASE_CHAN2BITMAP_IDX_6G(129);
+	CASE_CHAN2BITMAP_IDX_6G(133);
+	CASE_CHAN2BITMAP_IDX_6G(137);
+	CASE_CHAN2BITMAP_IDX_6G(141);
+	CASE_CHAN2BITMAP_IDX_6G(145);
+	CASE_CHAN2BITMAP_IDX_6G(149);
+	CASE_CHAN2BITMAP_IDX_6G(153);
+	CASE_CHAN2BITMAP_IDX_6G(157);
+	CASE_CHAN2BITMAP_IDX_6G(161);
+	CASE_CHAN2BITMAP_IDX_6G(165);
+	CASE_CHAN2BITMAP_IDX_6G(169);
+	CASE_CHAN2BITMAP_IDX_6G(173);
+	CASE_CHAN2BITMAP_IDX_6G(177);
+	CASE_CHAN2BITMAP_IDX_6G(181);
+	CASE_CHAN2BITMAP_IDX_6G(185);
+	CASE_CHAN2BITMAP_IDX_6G(189);
+	CASE_CHAN2BITMAP_IDX_6G(193);
+	CASE_CHAN2BITMAP_IDX_6G(197);
+	CASE_CHAN2BITMAP_IDX_6G(201);
+	CASE_CHAN2BITMAP_IDX_6G(205);
+	CASE_CHAN2BITMAP_IDX_6G(209);
+	CASE_CHAN2BITMAP_IDX_6G(213);
+	CASE_CHAN2BITMAP_IDX_6G(217);
+	CASE_CHAN2BITMAP_IDX_6G(221);
+	CASE_CHAN2BITMAP_IDX_6G(225);
+	CASE_CHAN2BITMAP_IDX_6G(229);
+	CASE_CHAN2BITMAP_IDX_6G(233);
+	};
+
+	return INVALID_CHAN_IDX;
+}
+
+u8 cl_channel_to_ext_index_6g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2EXT_IDX_6G(1);
+	CASE_CHAN2EXT_IDX_6G(2);
+	CASE_CHAN2EXT_IDX_6G(3);
+	CASE_CHAN2EXT_IDX_6G(5);
+	CASE_CHAN2EXT_IDX_6G(7);
+	CASE_CHAN2EXT_IDX_6G(9);
+	CASE_CHAN2EXT_IDX_6G(11);
+	CASE_CHAN2EXT_IDX_6G(13);
+	CASE_CHAN2EXT_IDX_6G(15);
+	CASE_CHAN2EXT_IDX_6G(17);
+	CASE_CHAN2EXT_IDX_6G(19);
+	CASE_CHAN2EXT_IDX_6G(21);
+	CASE_CHAN2EXT_IDX_6G(23);
+	CASE_CHAN2EXT_IDX_6G(25);
+	CASE_CHAN2EXT_IDX_6G(27);
+	CASE_CHAN2EXT_IDX_6G(29);
+	CASE_CHAN2EXT_IDX_6G(31);
+	CASE_CHAN2EXT_IDX_6G(33);
+	CASE_CHAN2EXT_IDX_6G(35);
+	CASE_CHAN2EXT_IDX_6G(37);
+	CASE_CHAN2EXT_IDX_6G(39);
+	CASE_CHAN2EXT_IDX_6G(41);
+	CASE_CHAN2EXT_IDX_6G(43);
+	CASE_CHAN2EXT_IDX_6G(45);
+	CASE_CHAN2EXT_IDX_6G(47);
+	CASE_CHAN2EXT_IDX_6G(49);
+	CASE_CHAN2EXT_IDX_6G(51);
+	CASE_CHAN2EXT_IDX_6G(53);
+	CASE_CHAN2EXT_IDX_6G(55);
+	CASE_CHAN2EXT_IDX_6G(57);
+	CASE_CHAN2EXT_IDX_6G(59);
+	CASE_CHAN2EXT_IDX_6G(61);
+	CASE_CHAN2EXT_IDX_6G(63);
+	CASE_CHAN2EXT_IDX_6G(65);
+	CASE_CHAN2EXT_IDX_6G(67);
+	CASE_CHAN2EXT_IDX_6G(69);
+	CASE_CHAN2EXT_IDX_6G(71);
+	CASE_CHAN2EXT_IDX_6G(73);
+	CASE_CHAN2EXT_IDX_6G(75);
+	CASE_CHAN2EXT_IDX_6G(77);
+	CASE_CHAN2EXT_IDX_6G(79);
+	CASE_CHAN2EXT_IDX_6G(81);
+	CASE_CHAN2EXT_IDX_6G(83);
+	CASE_CHAN2EXT_IDX_6G(85);
+	CASE_CHAN2EXT_IDX_6G(87);
+	CASE_CHAN2EXT_IDX_6G(89);
+	CASE_CHAN2EXT_IDX_6G(91);
+	CASE_CHAN2EXT_IDX_6G(93);
+	CASE_CHAN2EXT_IDX_6G(95);
+	CASE_CHAN2EXT_IDX_6G(97);
+	CASE_CHAN2EXT_IDX_6G(99);
+	CASE_CHAN2EXT_IDX_6G(101);
+	CASE_CHAN2EXT_IDX_6G(103);
+	CASE_CHAN2EXT_IDX_6G(105);
+	CASE_CHAN2EXT_IDX_6G(107);
+	CASE_CHAN2EXT_IDX_6G(109);
+	CASE_CHAN2EXT_IDX_6G(111);
+	CASE_CHAN2EXT_IDX_6G(113);
+	CASE_CHAN2EXT_IDX_6G(115);
+	CASE_CHAN2EXT_IDX_6G(117);
+	CASE_CHAN2EXT_IDX_6G(119);
+	CASE_CHAN2EXT_IDX_6G(121);
+	CASE_CHAN2EXT_IDX_6G(123);
+	CASE_CHAN2EXT_IDX_6G(125);
+	CASE_CHAN2EXT_IDX_6G(127);
+	CASE_CHAN2EXT_IDX_6G(129);
+	CASE_CHAN2EXT_IDX_6G(131);
+	CASE_CHAN2EXT_IDX_6G(133);
+	CASE_CHAN2EXT_IDX_6G(135);
+	CASE_CHAN2EXT_IDX_6G(137);
+	CASE_CHAN2EXT_IDX_6G(139);
+	CASE_CHAN2EXT_IDX_6G(141);
+	CASE_CHAN2EXT_IDX_6G(143);
+	CASE_CHAN2EXT_IDX_6G(145);
+	CASE_CHAN2EXT_IDX_6G(147);
+	CASE_CHAN2EXT_IDX_6G(149);
+	CASE_CHAN2EXT_IDX_6G(151);
+	CASE_CHAN2EXT_IDX_6G(153);
+	CASE_CHAN2EXT_IDX_6G(155);
+	CASE_CHAN2EXT_IDX_6G(157);
+	CASE_CHAN2EXT_IDX_6G(159);
+	CASE_CHAN2EXT_IDX_6G(161);
+	CASE_CHAN2EXT_IDX_6G(163);
+	CASE_CHAN2EXT_IDX_6G(165);
+	CASE_CHAN2EXT_IDX_6G(167);
+	CASE_CHAN2EXT_IDX_6G(169);
+	CASE_CHAN2EXT_IDX_6G(171);
+	CASE_CHAN2EXT_IDX_6G(173);
+	CASE_CHAN2EXT_IDX_6G(175);
+	CASE_CHAN2EXT_IDX_6G(177);
+	CASE_CHAN2EXT_IDX_6G(179);
+	CASE_CHAN2EXT_IDX_6G(181);
+	CASE_CHAN2EXT_IDX_6G(183);
+	CASE_CHAN2EXT_IDX_6G(185);
+	CASE_CHAN2EXT_IDX_6G(187);
+	CASE_CHAN2EXT_IDX_6G(189);
+	CASE_CHAN2EXT_IDX_6G(191);
+	CASE_CHAN2EXT_IDX_6G(193);
+	CASE_CHAN2EXT_IDX_6G(195);
+	CASE_CHAN2EXT_IDX_6G(197);
+	CASE_CHAN2EXT_IDX_6G(199);
+	CASE_CHAN2EXT_IDX_6G(201);
+	CASE_CHAN2EXT_IDX_6G(203);
+	CASE_CHAN2EXT_IDX_6G(205);
+	CASE_CHAN2EXT_IDX_6G(207);
+	CASE_CHAN2EXT_IDX_6G(209);
+	CASE_CHAN2EXT_IDX_6G(211);
+	CASE_CHAN2EXT_IDX_6G(213);
+	CASE_CHAN2EXT_IDX_6G(215);
+	CASE_CHAN2EXT_IDX_6G(217);
+	CASE_CHAN2EXT_IDX_6G(219);
+	CASE_CHAN2EXT_IDX_6G(221);
+	CASE_CHAN2EXT_IDX_6G(223);
+	CASE_CHAN2EXT_IDX_6G(225);
+	CASE_CHAN2EXT_IDX_6G(227);
+	CASE_CHAN2EXT_IDX_6G(229);
+	CASE_CHAN2EXT_IDX_6G(231);
+	CASE_CHAN2EXT_IDX_6G(233);
+	};
+
+	return INVALID_CHAN_IDX;
+}
+
+static u8 cl_channel_to_index_5g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2IDX_5G(36);
+	CASE_CHAN2IDX_5G(38);
+	CASE_CHAN2IDX_5G(40);
+	CASE_CHAN2IDX_5G(42);
+	CASE_CHAN2IDX_5G(44);
+	CASE_CHAN2IDX_5G(46);
+	CASE_CHAN2IDX_5G(48);
+	CASE_CHAN2IDX_5G(50);
+	CASE_CHAN2IDX_5G(52);
+	CASE_CHAN2IDX_5G(54);
+	CASE_CHAN2IDX_5G(56);
+	CASE_CHAN2IDX_5G(58);
+	CASE_CHAN2IDX_5G(60);
+	CASE_CHAN2IDX_5G(62);
+	CASE_CHAN2IDX_5G(64);
+	CASE_CHAN2IDX_5G(100);
+	CASE_CHAN2IDX_5G(102);
+	CASE_CHAN2IDX_5G(104);
+	CASE_CHAN2IDX_5G(106);
+	CASE_CHAN2IDX_5G(108);
+	CASE_CHAN2IDX_5G(110);
+	CASE_CHAN2IDX_5G(112);
+	CASE_CHAN2IDX_5G(114);
+	CASE_CHAN2IDX_5G(116);
+	CASE_CHAN2IDX_5G(118);
+	CASE_CHAN2IDX_5G(120);
+	CASE_CHAN2IDX_5G(122);
+	CASE_CHAN2IDX_5G(124);
+	CASE_CHAN2IDX_5G(126);
+	CASE_CHAN2IDX_5G(128);
+	/* 130 - invalid */
+	CASE_CHAN2IDX_5G(132);
+	CASE_CHAN2IDX_5G(134);
+	CASE_CHAN2IDX_5G(136);
+	CASE_CHAN2IDX_5G(138);
+	CASE_CHAN2IDX_5G(140);
+	CASE_CHAN2IDX_5G(142);
+	CASE_CHAN2IDX_5G(144);
+	CASE_CHAN2IDX_5G(149);
+	CASE_CHAN2IDX_5G(151);
+	CASE_CHAN2IDX_5G(153);
+	CASE_CHAN2IDX_5G(155);
+	CASE_CHAN2IDX_5G(157);
+	CASE_CHAN2IDX_5G(159);
+	CASE_CHAN2IDX_5G(161);
+	/* 163 - invalid */
+	CASE_CHAN2IDX_5G(165);
+	};
+
+	return INVALID_CHAN_IDX;
+}
+
+static u8 cl_channel_to_index_24g(struct cl_hw *cl_hw, u32 channel)
+{
+	switch (channel) {
+	CASE_CHAN2IDX_2G(1);
+	CASE_CHAN2IDX_2G(2);
+	CASE_CHAN2IDX_2G(3);
+	CASE_CHAN2IDX_2G(4);
+	CASE_CHAN2IDX_2G(5);
+	CASE_CHAN2IDX_2G(6);
+	CASE_CHAN2IDX_2G(7);
+	CASE_CHAN2IDX_2G(8);
+	CASE_CHAN2IDX_2G(9);
+	CASE_CHAN2IDX_2G(10);
+	CASE_CHAN2IDX_2G(11);
+	CASE_CHAN2IDX_2G(12);
+	CASE_CHAN2IDX_2G(13);
+	CASE_CHAN2IDX_2G(14);
+	};
+
+	return INVALID_CHAN_IDX;
+}
+
+u8 cl_channel_to_index(struct cl_hw *cl_hw, u32 channel)
+{
+	/* Calculate index for a given channel */
+	if (cl_band_is_6g(cl_hw))
+		return cl_channel_to_ext_index_6g(cl_hw, channel);
+	else if (cl_band_is_5g(cl_hw))
+		return cl_channel_to_index_5g(cl_hw, channel);
+	else
+		return cl_channel_to_index_24g(cl_hw, channel);
+}
+
+u8 cl_channel_to_bitmap_index(struct cl_hw *cl_hw, u32 channel)
+{
+	/* Calculate index for a given channel */
+	if (cl_band_is_6g(cl_hw))
+		return cl_channel_to_bitmap_index_6g(cl_hw, channel);
+	else if (cl_band_is_5g(cl_hw))
+		return cl_channel_to_index_5g(cl_hw, channel);
+	else
+		return cl_channel_to_index_24g(cl_hw, channel);
+}
+
+static u16 cl_channel_bitmap_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_BITMAP_IDX2FREQ_6G(1);
+	CASE_BITMAP_IDX2FREQ_6G(2);
+	CASE_BITMAP_IDX2FREQ_6G(5);
+	CASE_BITMAP_IDX2FREQ_6G(9);
+	CASE_BITMAP_IDX2FREQ_6G(13);
+	CASE_BITMAP_IDX2FREQ_6G(17);
+	CASE_BITMAP_IDX2FREQ_6G(21);
+	CASE_BITMAP_IDX2FREQ_6G(25);
+	CASE_BITMAP_IDX2FREQ_6G(29);
+	CASE_BITMAP_IDX2FREQ_6G(33);
+	CASE_BITMAP_IDX2FREQ_6G(37);
+	CASE_BITMAP_IDX2FREQ_6G(41);
+	CASE_BITMAP_IDX2FREQ_6G(45);
+	CASE_BITMAP_IDX2FREQ_6G(49);
+	CASE_BITMAP_IDX2FREQ_6G(53);
+	CASE_BITMAP_IDX2FREQ_6G(57);
+	CASE_BITMAP_IDX2FREQ_6G(61);
+	CASE_BITMAP_IDX2FREQ_6G(65);
+	CASE_BITMAP_IDX2FREQ_6G(69);
+	CASE_BITMAP_IDX2FREQ_6G(73);
+	CASE_BITMAP_IDX2FREQ_6G(77);
+	CASE_BITMAP_IDX2FREQ_6G(81);
+	CASE_BITMAP_IDX2FREQ_6G(85);
+	CASE_BITMAP_IDX2FREQ_6G(89);
+	CASE_BITMAP_IDX2FREQ_6G(93);
+	CASE_BITMAP_IDX2FREQ_6G(97);
+	CASE_BITMAP_IDX2FREQ_6G(101);
+	CASE_BITMAP_IDX2FREQ_6G(105);
+	CASE_BITMAP_IDX2FREQ_6G(109);
+	CASE_BITMAP_IDX2FREQ_6G(113);
+	CASE_BITMAP_IDX2FREQ_6G(117);
+	CASE_BITMAP_IDX2FREQ_6G(121);
+	CASE_BITMAP_IDX2FREQ_6G(125);
+	CASE_BITMAP_IDX2FREQ_6G(129);
+	CASE_BITMAP_IDX2FREQ_6G(133);
+	CASE_BITMAP_IDX2FREQ_6G(137);
+	CASE_BITMAP_IDX2FREQ_6G(141);
+	CASE_BITMAP_IDX2FREQ_6G(145);
+	CASE_BITMAP_IDX2FREQ_6G(149);
+	CASE_BITMAP_IDX2FREQ_6G(153);
+	CASE_BITMAP_IDX2FREQ_6G(157);
+	CASE_BITMAP_IDX2FREQ_6G(161);
+	CASE_BITMAP_IDX2FREQ_6G(165);
+	CASE_BITMAP_IDX2FREQ_6G(169);
+	CASE_BITMAP_IDX2FREQ_6G(173);
+	CASE_BITMAP_IDX2FREQ_6G(177);
+	CASE_BITMAP_IDX2FREQ_6G(181);
+	CASE_BITMAP_IDX2FREQ_6G(185);
+	CASE_BITMAP_IDX2FREQ_6G(189);
+	CASE_BITMAP_IDX2FREQ_6G(193);
+	CASE_BITMAP_IDX2FREQ_6G(197);
+	CASE_BITMAP_IDX2FREQ_6G(201);
+	CASE_BITMAP_IDX2FREQ_6G(205);
+	CASE_BITMAP_IDX2FREQ_6G(209);
+	CASE_BITMAP_IDX2FREQ_6G(213);
+	CASE_BITMAP_IDX2FREQ_6G(217);
+	CASE_BITMAP_IDX2FREQ_6G(221);
+	CASE_BITMAP_IDX2FREQ_6G(225);
+	CASE_BITMAP_IDX2FREQ_6G(229);
+	CASE_BITMAP_IDX2FREQ_6G(233);
+	};
+
+	return INVALID_FREQ;
+}
+
+u16 cl_channel_ext_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_EXT_IDX2FREQ_6G(1);
+	CASE_EXT_IDX2FREQ_6G(2);
+	CASE_EXT_IDX2FREQ_6G(3);
+	CASE_EXT_IDX2FREQ_6G(5);
+	CASE_EXT_IDX2FREQ_6G(7);
+	CASE_EXT_IDX2FREQ_6G(9);
+	CASE_EXT_IDX2FREQ_6G(11);
+	CASE_EXT_IDX2FREQ_6G(13);
+	CASE_EXT_IDX2FREQ_6G(15);
+	CASE_EXT_IDX2FREQ_6G(17);
+	CASE_EXT_IDX2FREQ_6G(19);
+	CASE_EXT_IDX2FREQ_6G(21);
+	CASE_EXT_IDX2FREQ_6G(23);
+	CASE_EXT_IDX2FREQ_6G(25);
+	CASE_EXT_IDX2FREQ_6G(27);
+	CASE_EXT_IDX2FREQ_6G(29);
+	CASE_EXT_IDX2FREQ_6G(31);
+	CASE_EXT_IDX2FREQ_6G(33);
+	CASE_EXT_IDX2FREQ_6G(35);
+	CASE_EXT_IDX2FREQ_6G(37);
+	CASE_EXT_IDX2FREQ_6G(39);
+	CASE_EXT_IDX2FREQ_6G(41);
+	CASE_EXT_IDX2FREQ_6G(43);
+	CASE_EXT_IDX2FREQ_6G(45);
+	CASE_EXT_IDX2FREQ_6G(47);
+	CASE_EXT_IDX2FREQ_6G(49);
+	CASE_EXT_IDX2FREQ_6G(51);
+	CASE_EXT_IDX2FREQ_6G(53);
+	CASE_EXT_IDX2FREQ_6G(55);
+	CASE_EXT_IDX2FREQ_6G(57);
+	CASE_EXT_IDX2FREQ_6G(59);
+	CASE_EXT_IDX2FREQ_6G(61);
+	CASE_EXT_IDX2FREQ_6G(63);
+	CASE_EXT_IDX2FREQ_6G(65);
+	CASE_EXT_IDX2FREQ_6G(67);
+	CASE_EXT_IDX2FREQ_6G(69);
+	CASE_EXT_IDX2FREQ_6G(71);
+	CASE_EXT_IDX2FREQ_6G(73);
+	CASE_EXT_IDX2FREQ_6G(75);
+	CASE_EXT_IDX2FREQ_6G(77);
+	CASE_EXT_IDX2FREQ_6G(79);
+	CASE_EXT_IDX2FREQ_6G(81);
+	CASE_EXT_IDX2FREQ_6G(83);
+	CASE_EXT_IDX2FREQ_6G(85);
+	CASE_EXT_IDX2FREQ_6G(87);
+	CASE_EXT_IDX2FREQ_6G(89);
+	CASE_EXT_IDX2FREQ_6G(91);
+	CASE_EXT_IDX2FREQ_6G(93);
+	CASE_EXT_IDX2FREQ_6G(95);
+	CASE_EXT_IDX2FREQ_6G(97);
+	CASE_EXT_IDX2FREQ_6G(99);
+	CASE_EXT_IDX2FREQ_6G(101);
+	CASE_EXT_IDX2FREQ_6G(103);
+	CASE_EXT_IDX2FREQ_6G(105);
+	CASE_EXT_IDX2FREQ_6G(107);
+	CASE_EXT_IDX2FREQ_6G(109);
+	CASE_EXT_IDX2FREQ_6G(111);
+	CASE_EXT_IDX2FREQ_6G(113);
+	CASE_EXT_IDX2FREQ_6G(115);
+	CASE_EXT_IDX2FREQ_6G(117);
+	CASE_EXT_IDX2FREQ_6G(119);
+	CASE_EXT_IDX2FREQ_6G(121);
+	CASE_EXT_IDX2FREQ_6G(123);
+	CASE_EXT_IDX2FREQ_6G(125);
+	CASE_EXT_IDX2FREQ_6G(127);
+	CASE_EXT_IDX2FREQ_6G(129);
+	CASE_EXT_IDX2FREQ_6G(131);
+	CASE_EXT_IDX2FREQ_6G(133);
+	CASE_EXT_IDX2FREQ_6G(135);
+	CASE_EXT_IDX2FREQ_6G(137);
+	CASE_EXT_IDX2FREQ_6G(139);
+	CASE_EXT_IDX2FREQ_6G(141);
+	CASE_EXT_IDX2FREQ_6G(143);
+	CASE_EXT_IDX2FREQ_6G(145);
+	CASE_EXT_IDX2FREQ_6G(147);
+	CASE_EXT_IDX2FREQ_6G(149);
+	CASE_EXT_IDX2FREQ_6G(151);
+	CASE_EXT_IDX2FREQ_6G(153);
+	CASE_EXT_IDX2FREQ_6G(155);
+	CASE_EXT_IDX2FREQ_6G(157);
+	CASE_EXT_IDX2FREQ_6G(159);
+	CASE_EXT_IDX2FREQ_6G(161);
+	CASE_EXT_IDX2FREQ_6G(163);
+	CASE_EXT_IDX2FREQ_6G(165);
+	CASE_EXT_IDX2FREQ_6G(167);
+	CASE_EXT_IDX2FREQ_6G(169);
+	CASE_EXT_IDX2FREQ_6G(171);
+	CASE_EXT_IDX2FREQ_6G(173);
+	CASE_EXT_IDX2FREQ_6G(175);
+	CASE_EXT_IDX2FREQ_6G(177);
+	CASE_EXT_IDX2FREQ_6G(179);
+	CASE_EXT_IDX2FREQ_6G(181);
+	CASE_EXT_IDX2FREQ_6G(183);
+	CASE_EXT_IDX2FREQ_6G(185);
+	CASE_EXT_IDX2FREQ_6G(187);
+	CASE_EXT_IDX2FREQ_6G(189);
+	CASE_EXT_IDX2FREQ_6G(191);
+	CASE_EXT_IDX2FREQ_6G(193);
+	CASE_EXT_IDX2FREQ_6G(195);
+	CASE_EXT_IDX2FREQ_6G(197);
+	CASE_EXT_IDX2FREQ_6G(199);
+	CASE_EXT_IDX2FREQ_6G(201);
+	CASE_EXT_IDX2FREQ_6G(203);
+	CASE_EXT_IDX2FREQ_6G(205);
+	CASE_EXT_IDX2FREQ_6G(207);
+	CASE_EXT_IDX2FREQ_6G(209);
+	CASE_EXT_IDX2FREQ_6G(211);
+	CASE_EXT_IDX2FREQ_6G(213);
+	CASE_EXT_IDX2FREQ_6G(215);
+	CASE_EXT_IDX2FREQ_6G(217);
+	CASE_EXT_IDX2FREQ_6G(219);
+	CASE_EXT_IDX2FREQ_6G(221);
+	CASE_EXT_IDX2FREQ_6G(223);
+	CASE_EXT_IDX2FREQ_6G(225);
+	CASE_EXT_IDX2FREQ_6G(227);
+	CASE_EXT_IDX2FREQ_6G(229);
+	CASE_EXT_IDX2FREQ_6G(231);
+	CASE_EXT_IDX2FREQ_6G(233);
+	};
+
+	return INVALID_FREQ;
+}
+
+static u16 cl_channel_idx_to_freq_5g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_IDX2FREQ_5G(36);
+	CASE_IDX2FREQ_5G(38);
+	CASE_IDX2FREQ_5G(40);
+	CASE_IDX2FREQ_5G(42);
+	CASE_IDX2FREQ_5G(44);
+	CASE_IDX2FREQ_5G(46);
+	CASE_IDX2FREQ_5G(48);
+	CASE_IDX2FREQ_5G(50);
+	CASE_IDX2FREQ_5G(52);
+	CASE_IDX2FREQ_5G(54);
+	CASE_IDX2FREQ_5G(56);
+	CASE_IDX2FREQ_5G(58);
+	CASE_IDX2FREQ_5G(60);
+	CASE_IDX2FREQ_5G(62);
+	CASE_IDX2FREQ_5G(64);
+	CASE_IDX2FREQ_5G(100);
+	CASE_IDX2FREQ_5G(102);
+	CASE_IDX2FREQ_5G(104);
+	CASE_IDX2FREQ_5G(106);
+	CASE_IDX2FREQ_5G(108);
+	CASE_IDX2FREQ_5G(110);
+	CASE_IDX2FREQ_5G(112);
+	CASE_IDX2FREQ_5G(114);
+	CASE_IDX2FREQ_5G(116);
+	CASE_IDX2FREQ_5G(118);
+	CASE_IDX2FREQ_5G(120);
+	CASE_IDX2FREQ_5G(122);
+	CASE_IDX2FREQ_5G(124);
+	CASE_IDX2FREQ_5G(126);
+	CASE_IDX2FREQ_5G(128);
+	CASE_IDX2FREQ_5G(132);
+	CASE_IDX2FREQ_5G(134);
+	CASE_IDX2FREQ_5G(136);
+	CASE_IDX2FREQ_5G(138);
+	CASE_IDX2FREQ_5G(140);
+	CASE_IDX2FREQ_5G(142);
+	CASE_IDX2FREQ_5G(144);
+	CASE_IDX2FREQ_5G(149);
+	CASE_IDX2FREQ_5G(151);
+	CASE_IDX2FREQ_5G(153);
+	CASE_IDX2FREQ_5G(155);
+	CASE_IDX2FREQ_5G(157);
+	CASE_IDX2FREQ_5G(159);
+	CASE_IDX2FREQ_5G(161);
+	CASE_IDX2FREQ_5G(165);
+	};
+
+	return INVALID_FREQ;
+}
+
+static u16 cl_channel_idx_to_freq_24g(struct cl_hw *cl_hw, u8 index)
+{
+	switch (index) {
+	CASE_IDX2FREQ_2G(1);
+	CASE_IDX2FREQ_2G(2);
+	CASE_IDX2FREQ_2G(3);
+	CASE_IDX2FREQ_2G(4);
+	CASE_IDX2FREQ_2G(5);
+	CASE_IDX2FREQ_2G(6);
+	CASE_IDX2FREQ_2G(7);
+	CASE_IDX2FREQ_2G(8);
+	CASE_IDX2FREQ_2G(9);
+	CASE_IDX2FREQ_2G(10);
+	CASE_IDX2FREQ_2G(11);
+	CASE_IDX2FREQ_2G(12);
+	CASE_IDX2FREQ_2G(13);
+	CASE_IDX2FREQ_2G(14);
+	};
+
+	return INVALID_FREQ;
+}
+
+u16 cl_channel_idx_to_freq(struct cl_hw *cl_hw, u8 index)
+{
+	/* Calculate frequency of a given idnex */
+	if (cl_band_is_6g(cl_hw))
+		return cl_channel_bitmap_idx_to_freq_6g(cl_hw, index);
+	else if (cl_band_is_5g(cl_hw))
+		return cl_channel_idx_to_freq_5g(cl_hw, index);
+	else
+		return cl_channel_idx_to_freq_24g(cl_hw, index);
+}
+
+bool cl_channel_is_valid(struct cl_hw *cl_hw, u8 channel)
+{
+	if (cl_band_is_24g(cl_hw)) {
+		return (channel > 0 && channel <= 14);
+	} else if (cl_band_is_5g(cl_hw)) {
+		if (channel >= 36 && channel <= 64)
+			return ((channel & 0x1) == 0x0);
+
+		if (channel >= 100 && channel <= 144)
+			return ((channel & 0x1) == 0x0);
+
+		if (channel >= 149 && channel <= 161)
+			return ((channel & 0x1) == 0x1);
+
+		if (channel == 165)
+			return true;
+	} else {
+		if (channel == 2)
+			return true;
+
+		if (channel >= 1 && channel <= 233)
+			if ((channel & 0x3) == 0x1)
+				return true;
+	}
+
+	return false;
+}
+
+u32 cl_channel_num(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_band_num == 6)
+		return NUM_BITMAP_CHANNELS_6G;
+
+	if (cl_hw->conf->ci_band_num == 5)
+		return NUM_CHANNELS_5G;
+
+	return NUM_CHANNELS_24G;
+}
+
+bool cl_channel_is_dfs(struct cl_hw *cl_hw, u8 channel)
+{
+	if (!cl_band_is_5g(cl_hw))
+		return false;
+
+	return channel >= 36 && channel <= 144;
+}
+
+u32 cl_channel_get_cac_time_ms(struct cl_hw *cl_hw, u8 channel)
+{
+	if (!cl_band_is_5g(cl_hw))
+		return 0;
+
+	if (!cl_channel_is_dfs(cl_hw, channel))
+		return 0;
+
+	/* FIXME: CAC time for weather channels may differ for some regions */
+	if (channel >= 120 && channel <= 128)
+		return IEEE80211_DFS_WEATHER_MIN_CAC_TIME_MS;
+
+	return IEEE80211_DFS_MIN_CAC_TIME_MS;
+}
+
+static void _cl_fill_channel_info(struct cl_hw *cl_hw, u8 bw, u8 ch_idx, u8 channel,
+				  u8 country_max_power_q2, u8 max_power_q2,
+				  u32 flags, u32 dfs_cac_ms)
+{
+	struct cl_chan_info *chan_info = &cl_hw->channel_info.channels[bw][ch_idx];
+
+	chan_info->channel = channel;
+	chan_info->country_max_power_q2 = country_max_power_q2;
+	chan_info->max_power_q2 = max_power_q2;
+	chan_info->flags = flags;
+	chan_info->dfs_cac_ms = dfs_cac_ms;
+}
+
+static void cl_fill_channel_info(struct cl_hw *cl_hw, u8 bw, u8 ch_idx, u8 channel,
+				 u8 country_max_power_q2, u8 max_power_q2)
+{
+	_cl_fill_channel_info(cl_hw, bw, ch_idx, channel, country_max_power_q2, max_power_q2, 0, 0);
+}
+
+static void cl_fill_channel_info_5g(struct cl_hw *cl_hw, u8 bw, u8 ch_idx, u8 channel,
+				    u8 country_max_power_q2, u8 max_power_q2)
+{
+	u32 flags = 0;
+	u32 dfs_cac_ms = 0;
+
+	if (cl_hw->conf->ci_ieee80211h && cl_channel_is_dfs(cl_hw, channel)) {
+		flags |= IEEE80211_CHAN_RADAR;
+		dfs_cac_ms = cl_channel_get_cac_time_ms(cl_hw, channel);
+	}
+
+	_cl_fill_channel_info(cl_hw, bw, ch_idx, channel, country_max_power_q2,
+			      max_power_q2, flags, dfs_cac_ms);
+}
+
+static inline s32 cl_convert_str_int_q2(s8 *str)
+{
+	s32 x, y;
+
+	if (!str)
+		return 0;
+	if (sscanf(str, "%d.%2d", &x, &y) != 2)
+		return 0;
+	if (!strstr(str, "."))
+		return x * 4;
+	if (y < 10 && (*(strstr(str, ".") + 1) != '0'))
+		y *= 10;
+	return (x * 100 + y) * 4 / 100;
+}
+
+static int cl_parse_reg_domain(struct cl_hw *cl_hw, char **str)
+{
+	/* Check if current line contains "FCC" or "ETSI" */
+	char *token = strsep(str, "\n");
+
+	if (!token)
+		goto err;
+
+	if (strstr(token, "FCC")) {
+		cl_hw->channel_info.standard = NL80211_DFS_FCC;
+		cl_dbg_info(cl_hw, "Standard = FCC\n");
+		return 0;
+	}
+
+	if (strstr(token, "ETSI")) {
+		cl_hw->channel_info.standard = NL80211_DFS_ETSI;
+		cl_dbg_info(cl_hw, "Standard = ETSI\n");
+		return 0;
+	}
+
+err:
+	cl_dbg_err(cl_hw, "Illegal regulatory domain\n");
+	cl_hw->channel_info.standard = NL80211_DFS_UNSET;
+	return -1;
+}
+
+#define MAX_CC_STR 4
+#define MAX_BW_STR 8
+
+static bool cl_parse_channel_info_txt(struct cl_hw *cl_hw)
+{
+	/*
+	 * Example of country information in channel_info.txt:
+	 *
+	 * [EU (European Union)ETSI]
+	 * 2.4GHz/20MHz: 2412(1,20) 2417(2,20) 2422(3,20) 2427(4,20) 2432(5,20) 2437(6,20)
+	 *               2442(7,20) 2447(8,20) 2452(9,20) 2457(10,20) 2462(11,20) 2467(12,20)
+	 *               2472(13,20)
+	 * 2.4GHz/40MHz: 2422(1,20) 2427(2,20) 2432(3,20) 2437(4,20) 2442(5,20) 2447(6,20)
+	 *               2452(7,20) 2457(8,20) 2462(9,20) 2467(10,20) 2472(11,20)
+	 * 5.2GHz/20MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+	 *               5300(60,23) 5320(64,23) 5500(100,30) 5520(104,30) 5540(108,30)
+	 *               5560(112,30)5580(116,30) 5600(120,30) 5620(124,30) 5640(128,30)
+	 *               5660(132,30) 5680(136,30) 5700(140,30)
+	 * 5.2GHz/40MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+	 *               5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+	 *               5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+	 *               5670(132,30) 5670(136,30)
+	 * 5.2GHz/80MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+	 *               5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+	 *               5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+	 * 5.2GHz/160MHz: 5180(36,23) 5200(40,23) 5220(44,23) 5240(48,23) 5260(52,23) 5280(56,23)
+	 *                5300(60,23) 5310(64,23) 5510(100,30) 5510(104,30) 5550(108,30)
+	 *                5550(112,30) 5590(116,30) 5590(120,30) 5630(124,30) 5630(128,30)
+	 */
+
+	char *buf = NULL, *ptr = NULL;
+	char cc_str[MAX_CC_STR] = {0};
+	char bw_str[MAX_BW_STR] = {0};
+	size_t size;
+	u8 bw, bw_mhz, bw_max, max_power, channel, i;
+	char file_name[CL_FILENAME_MAX] = {0};
+
+	snprintf(file_name, sizeof(file_name), "channel_info_chip%d.txt", cl_hw->chip->idx);
+
+	/* Read channel_info.txt into buf */
+	size = cl_file_open_and_read(cl_hw->chip, file_name, &buf);
+
+	if (!buf)
+		return false;
+
+	/* Jump to the correct country in the file */
+	snprintf(cc_str, sizeof(cc_str), "[%s", cl_hw->chip->conf->ci_country_code);
+	ptr = strstr(buf, cc_str);
+	if (!ptr)
+		goto out;
+
+	if (cl_parse_reg_domain(cl_hw, &ptr))
+		goto out;
+
+	/* Jump to the relevant band */
+	if (cl_band_is_24g(cl_hw)) {
+		bw_max = CHNL_BW_40;
+		ptr = strstr(ptr, "2.4GHz");
+	} else if (cl_band_is_5g(cl_hw)) {
+		ptr = strstr(ptr, "5.2GHz");
+		bw_max = CHNL_BW_160;
+	} else {
+		ptr = strstr(ptr, "6GHz");
+		bw_max = CHNL_BW_160;
+	}
+
+	for (bw = 0; bw <= bw_max; bw++) {
+		if (!ptr)
+			goto out;
+
+		i = 0;
+
+		/* Jump to relevant bandwidth */
+		bw_mhz = BW_TO_MHZ(bw);
+		snprintf(bw_str, sizeof(bw_str), "%uMHz:", bw_mhz);
+		ptr = strstr(ptr, bw_str);
+
+		/* Iterate until end of line and parse (channel, max_power) */
+		while (ptr && (ptr + 1) && (*(ptr + 1) != '\n')) {
+			u32 flags = 0, dfs_cac_ms = 0;
+
+			ptr = strstr(ptr, "(");
+			if (!ptr)
+				goto out;
+
+			if (sscanf(ptr, "(%hhu,%hhu)", &channel, &max_power) != 2)
+				goto out;
+
+			if (!cl_channel_is_valid(cl_hw, channel) ||
+			    i == cl_channel_num(cl_hw))
+				goto out;
+
+			if (cl_hw->conf->ci_ieee80211h && cl_channel_is_dfs(cl_hw, channel)) {
+				flags |= IEEE80211_CHAN_RADAR;
+				dfs_cac_ms = cl_channel_get_cac_time_ms(cl_hw, channel);
+			}
+
+			_cl_fill_channel_info(cl_hw, bw, i, channel, max_power << 2,
+					      max_power << 2, flags, dfs_cac_ms);
+
+			i++;
+			ptr = strstr(ptr, ")");
+		}
+	}
+
+	kfree(buf);
+	return true;
+
+out:
+	kfree(buf);
+	return false;
+}
+
+static bool cl_is_parsing_success(struct cl_hw *cl_hw)
+{
+	/* Check that there is at least one channel in any bw */
+	u8 bw;
+	u8 max_bw = BAND_IS_5G_6G(cl_hw) ? CHNL_BW_160 : CHNL_BW_40;
+
+	for (bw = 0; bw <= max_bw; bw++)
+		if (!cl_hw->channel_info.channels[bw][0].channel)
+			return false;
+
+	return true;
+}
+
+static void cl_chan_info_set_max_bw_6g(struct cl_hw *cl_hw)
+{
+	u8 i, bw, bw_cnt, channel, channel_gap;
+	struct cl_chan_info *chan_info;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		chan_info = cl_hw->channel_info.channels[bw];
+		bw_cnt = 0;
+
+		for (i = 0; i < NUM_BITMAP_CHANNELS_6G; i++) {
+			channel = chan_info[i].channel;
+
+			if (channel == 0)
+				break;
+
+			channel_gap = channel - START_CHAN_IDX_6G;
+
+			/*
+			 * Verify that we don't combine together channels
+			 * from different 80MHz sections
+			 */
+			if ((channel_gap % CL_160MHZ_CH_GAP) == 0)
+				bw_cnt = 0;
+
+			if (i > 0)
+				bw_cnt++;
+
+			/* Verify that we don't make illegal 80MHz combination */
+			if ((channel_gap % CL_80MHZ_CH_GAP == 0) && bw_cnt == 3)
+				bw_cnt = 0;
+
+			/* Verify that we don't make illegal 40MHz combination */
+			if ((channel_gap % CL_40MHZ_CH_GAP == 0) && bw_cnt == 1)
+				bw_cnt = 0;
+
+			if ((((bw_cnt + 1) % CL_160MHZ_HOP) == 0) && bw == CHNL_BW_160) {
+				chan_info[i].max_bw = CHNL_BW_160;
+				chan_info[i - 1].max_bw = CHNL_BW_160;
+				chan_info[i - 2].max_bw = CHNL_BW_160;
+				chan_info[i - 3].max_bw = CHNL_BW_160;
+				chan_info[i - 4].max_bw = CHNL_BW_160;
+				chan_info[i - 5].max_bw = CHNL_BW_160;
+				chan_info[i - 6].max_bw = CHNL_BW_160;
+				chan_info[i - 7].max_bw = CHNL_BW_160;
+			} else if ((((bw_cnt + 1) % CL_80MHZ_HOP) == 0) && (bw == CHNL_BW_80)) {
+				chan_info[i].max_bw = CHNL_BW_80;
+				chan_info[i - 1].max_bw = CHNL_BW_80;
+				chan_info[i - 2].max_bw = CHNL_BW_80;
+				chan_info[i - 3].max_bw = CHNL_BW_80;
+			} else if ((((bw_cnt + 1) % CL_40MHZ_HOP) == 0) && (bw >= CHNL_BW_40)) {
+				chan_info[i].max_bw = CHNL_BW_40;
+				chan_info[i - 1].max_bw = CHNL_BW_40;
+			} else {
+				chan_info[i].max_bw = CHNL_BW_20;
+			}
+		}
+	}
+}
+
+static void cl_chan_info_set_max_bw_5g(struct cl_hw *cl_hw)
+{
+	u8 i, bw, bw_cnt, channel, channel_gap;
+	struct cl_chan_info *chan_info;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		chan_info = cl_hw->channel_info.channels[bw];
+		bw_cnt = 0;
+
+		for (i = 0; i < NUM_CHANNELS_5G; i++) {
+			channel = chan_info[i].channel;
+
+			if (channel == 0)
+				break;
+
+			if (channel < 149)
+				channel_gap = channel - 36;
+			else
+				channel_gap = channel - 149;
+
+			/*
+			 * Verify that we don't combine together channels from
+			 * different 80MHz sections
+			 * (i.e. 36-48 can be combined into 80MHz channels, unlike 40-52)
+			 */
+			if ((channel_gap % CL_160MHZ_CH_GAP) == 0)
+				bw_cnt = 0;
+
+			/* Check if 20MHz channels can be combined into 40MHz or 80MHz channels */
+			if (i > 0) {
+				/*
+				 * Verify that we don't combine together unsecutive channels
+				 * (like 36 and 44 when 40 is missing)
+				 */
+				if ((chan_info[i].channel - chan_info[i - 1].channel) >
+				    CL_20MHZ_CH_GAP)
+					bw_cnt = 0;
+				else
+					bw_cnt++;
+			}
+
+			/* Verify that we don't make illegal 80MHz combination (like 44-56) */
+			if ((channel_gap % CL_80MHZ_CH_GAP == 0) && bw_cnt == 3)
+				bw_cnt = 0;
+
+			/* Verify that we don't make illegal 40MHz combination (like 40-44) */
+			if ((channel_gap % CL_40MHZ_CH_GAP == 0) && bw_cnt == 1)
+				bw_cnt = 0;
+
+			if ((((bw_cnt + 1) % CL_160MHZ_HOP) == 0) && bw == CHNL_BW_160) {
+				chan_info[i].max_bw = CHNL_BW_160;
+				chan_info[i - 1].max_bw = CHNL_BW_160;
+				chan_info[i - 2].max_bw = CHNL_BW_160;
+				chan_info[i - 3].max_bw = CHNL_BW_160;
+				chan_info[i - 4].max_bw = CHNL_BW_160;
+				chan_info[i - 5].max_bw = CHNL_BW_160;
+				chan_info[i - 6].max_bw = CHNL_BW_160;
+				chan_info[i - 7].max_bw = CHNL_BW_160;
+			} else if ((((bw_cnt + 1) % CL_80MHZ_HOP) == 0) && bw == CHNL_BW_80) {
+				chan_info[i].max_bw = CHNL_BW_80;
+				chan_info[i - 1].max_bw = CHNL_BW_80;
+				chan_info[i - 2].max_bw = CHNL_BW_80;
+				chan_info[i - 3].max_bw = CHNL_BW_80;
+			} else if ((((bw_cnt + 1) % CL_40MHZ_HOP) == 0) && bw >= CHNL_BW_40) {
+				chan_info[i].max_bw = CHNL_BW_40;
+				chan_info[i - 1].max_bw = CHNL_BW_40;
+			} else {
+				chan_info[i].max_bw = CHNL_BW_20;
+			}
+		}
+	}
+}
+
+static void cl_chan_info_set_max_bw_24g(struct cl_hw *cl_hw)
+{
+	u8 i, bw, channel;
+	struct cl_chan_info *chan_info;
+
+	for (bw = 0; bw < CHNL_BW_80; bw++) {
+		chan_info = cl_hw->channel_info.channels[bw];
+
+		for (i = 0; i < NUM_CHANNELS_24G; i++) {
+			channel = chan_info[i].channel;
+
+			if (channel == 0)
+				break;
+
+			if (channel < 14)
+				chan_info[i].max_bw = CHNL_BW_40;
+			else
+				chan_info[i].max_bw = CHNL_BW_20;
+		}
+	}
+}
+
+static void cl_chan_info_set_max_bw(struct cl_hw *cl_hw)
+{
+	if (cl_band_is_6g(cl_hw))
+		cl_chan_info_set_max_bw_6g(cl_hw);
+	else if (cl_band_is_5g(cl_hw))
+		cl_chan_info_set_max_bw_5g(cl_hw);
+	else
+		cl_chan_info_set_max_bw_24g(cl_hw);
+}
+
+static void cl_chan_info_dbg(struct cl_hw *cl_hw)
+{
+	struct cl_chan_info *chan_info;
+	u32 max_power_integer, max_power_fraction;
+	u8 i, j;
+
+	for (i = 0; i < CHNL_BW_MAX; i++) {
+		cl_dbg_info(cl_hw, "Bandwidth = %uMHz\n", BW_TO_MHZ(i));
+		for (j = 0; j < cl_channel_num(cl_hw); j++) {
+			chan_info = &cl_hw->channel_info.channels[i][j];
+
+			if (chan_info->channel == 0)
+				continue;
+
+			max_power_integer = (chan_info->max_power_q2 / 4);
+			max_power_fraction =
+				(100 * (chan_info->max_power_q2 - 4 * max_power_integer) / 4);
+
+			cl_dbg_info(cl_hw, "Channel = %u, max EIRP = %3u.%02u, bw = %uMHz\n",
+				    chan_info->channel, max_power_integer,
+				    max_power_fraction, BW_TO_MHZ(chan_info->max_bw));
+		}
+	}
+}
+
+/* Band 6G - default power */
+#define UNII_5_POW_Q2     (27 << 2)
+#define UNII_6_POW_Q2     (27 << 2)
+#define UNII_7_POW_Q2     (27 << 2)
+#define UNII_8_POW_Q2     (27 << 2)
+
+/* Band 5G - default power */
+/* Default regulatory domain:
+ * country US: DFS-FCC
+ *       (2400 - 2472 @ 40), (N/A, 30), (N/A)
+ *       (5150 - 5250 @ 80), (N/A, 23), (N/A), AUTO-BW
+ *       (5250 - 5350 @ 80), (N/A, 23), (0 ms), DFS, AUTO-BW
+ *       (5470 - 5730 @ 160), (N/A, 23), (0 ms), DFS
+ *       (5730 - 5850 @ 80), (N/A, 30), (N/A), AUTO-BW
+ *       (5850 - 5895 @ 40), (N/A, 27), (N/A), NO-OUTDOOR, AUTO-BW, PASSIVE-SCAN
+ *       (57240 - 71000 @ 2160), (N/A, 40), (N/A)
+ */
+#define UNII_1_POW_Q2     (23 << 2)
+#define UNII_2_POW_Q2     (23 << 2)
+#define UNII_2_EXT_POW_Q2 (23 << 2)
+#define UNII_3_POW_Q2     (30 << 2)
+
+/* Band 2.4G - default power */
+#define BAND_24G_POW_Q2   (30 << 2)
+
+static void cl_set_default_channel_info_6g(struct cl_hw *cl_hw)
+{
+	u8 i, j, k;
+
+	for (i = 0; i < CHNL_BW_MAX; i++) {
+		k = 0;
+
+		/* Ch2 is a special case */
+		cl_fill_channel_info(cl_hw, i, k, 2, UNII_5_POW_Q2, UNII_5_POW_Q2);
+		k++;
+
+		for (j = START_CHAN_IDX_UNII5; j <= END_CHAN_IDX_UNII5; j += 4) {
+			cl_fill_channel_info(cl_hw, i, k, j, UNII_5_POW_Q2, UNII_5_POW_Q2);
+			k++;
+		}
+
+		for (j = START_CHAN_IDX_UNII6; j <= END_CHAN_IDX_UNII6; j += 4) {
+			cl_fill_channel_info(cl_hw, i, k, j, UNII_6_POW_Q2, UNII_6_POW_Q2);
+			k++;
+		}
+
+		for (j = START_CHAN_IDX_UNII7; j <= END_CHAN_IDX_UNII7; j += 4) {
+			cl_fill_channel_info(cl_hw, i, k, j, UNII_7_POW_Q2, UNII_7_POW_Q2);
+			k++;
+		}
+
+		for (j = START_CHAN_IDX_UNII8; j <= END_CHAN_IDX_UNII8; j += 4) {
+			/* Channel 233 is valid only in 20MHz */
+			if (i != CHNL_BW_20 && j == END_CHAN_IDX_UNII8)
+				break;
+
+			cl_fill_channel_info(cl_hw, i, k, j, UNII_8_POW_Q2, UNII_8_POW_Q2);
+			k++;
+		}
+	}
+}
+
+static void cl_set_default_channel_info_5g(struct cl_hw *cl_hw)
+{
+	u8 i, j, k;
+
+	for (i = 0; i < CHNL_BW_MAX; i++) {
+		k = 0;
+
+		for (j = 36; j <= 48; j += 4) {
+			cl_fill_channel_info_5g(cl_hw, i, k, j, UNII_1_POW_Q2, UNII_1_POW_Q2);
+			k++;
+		}
+
+		for (j = 52; j <= 64; j += 4) {
+			cl_fill_channel_info_5g(cl_hw, i, k, j, UNII_2_POW_Q2, UNII_2_POW_Q2);
+			k++;
+		}
+
+		for (j = 100; j <= 144; j += 4) {
+			/* 160MHz is supported only in channel 36 - 64 and 100 - 128 */
+			if (i == CHNL_BW_160 && j == 132)
+				return;
+
+			cl_fill_channel_info_5g(cl_hw, i, k, j,
+						UNII_2_EXT_POW_Q2, UNII_2_EXT_POW_Q2);
+			k++;
+		}
+
+		for (j = 149; j <= 165; j += 4) {
+			/* Channel 165 is valid only in 20MHz */
+			if (i != CHNL_BW_20 && j == 165)
+				break;
+
+			cl_fill_channel_info_5g(cl_hw, i, k, j, UNII_3_POW_Q2, UNII_3_POW_Q2);
+			k++;
+		}
+	}
+}
+
+static void cl_set_default_channel_info_24g(struct cl_hw *cl_hw)
+{
+	u8 i, j;
+
+	for (i = 0; i <= CHNL_BW_40; i++)
+		for (j = 0; j < 13; j++)
+			cl_fill_channel_info(cl_hw, i, j, j + 1, BAND_24G_POW_Q2, BAND_24G_POW_Q2);
+}
+
+static void cl_set_default_channel_info(struct cl_hw *cl_hw)
+{
+	struct cl_channel_info *channel_info = &cl_hw->channel_info;
+
+	memset(channel_info->channels, 0, sizeof(channel_info->channels));
+
+	channel_info->standard = NL80211_DFS_FCC;
+
+	if (cl_band_is_6g(cl_hw))
+		cl_set_default_channel_info_6g(cl_hw);
+	else if (cl_band_is_5g(cl_hw))
+		cl_set_default_channel_info_5g(cl_hw);
+	else
+		cl_set_default_channel_info_24g(cl_hw);
+}
+
+/*
+ * cl_hardware_power_table_update: Applies individual regulatory table entry
+ *   Inputs: cl_hw      - pointer to cl_hw
+ *           bw_mhz     - current bandwidth in MHz
+ *           chan_start - match channels greater or equal to chan_start
+ *           chan_end   - match channels less than chan_end
+ *           reg_pwr    - ensure channel_info.channels[bw][ch_idx].max_power does not exceed this
+ *   Output: updated channel_info.channels[bw][ch_idx].max_power
+ *           and channel_info.channels[bw][ch_idx].max_total_power
+ *           on all channels that match specified range
+ */
+static void cl_hardware_power_table_update(struct cl_hw *cl_hw, u8 bw_mhz,
+					   u8 chan_start, u8 chan_end, u8 pwr_q2)
+{
+	struct cl_chan_info *chan_info = NULL;
+	u8 bw = 0;
+	u8 ch_idx = 0;
+	bool ch_found = false;
+	bool is_24g = cl_band_is_24g(cl_hw);
+
+	if (bw_mhz == 20 || bw_mhz == 40 || (!is_24g && (bw_mhz == 80 || bw_mhz == 160))) {
+		bw = MHZ_TO_BW(bw_mhz);
+	} else {
+		cl_dbg_err(cl_hw, "Invalid bw %u\n", bw_mhz);
+		return;
+	}
+
+	/* Iterate through all cl_channels[bw][ch_idx] - to find all matches */
+	for (ch_idx = 0; ch_idx < cl_channel_num(cl_hw); ch_idx++) {
+		chan_info = &cl_hw->channel_info.channels[bw][ch_idx];
+
+		if (chan_start <= chan_info->channel && chan_info->channel < chan_end) {
+			ch_found = true;
+
+			/*
+			 * Max-Power =
+			 * minimum beteen hardware_power_table and country code definition
+			 */
+			chan_info->max_power_q2 = min(pwr_q2, chan_info->max_power_q2);
+			chan_info->hardware_max_power_q2 = pwr_q2;
+		}
+	}
+
+	if (!ch_found)
+		cl_dbg_info(cl_hw, "Skipping invalid channel range: %u - %u\n",
+			    chan_start, chan_end);
+}
+
+/*
+ * cl_hardware_power_table_parse():
+ * Iterate through hardware power table entries and apply each one.
+ * Expected format:
+ *     bw1(chan1=reg_pwr1;chan2=reg_pwr2;...)#bw2(chan3=reg_pwr3;chan4=reg_pwr4;...) ...
+ * Example:
+ *     20(36=22.0;40=22.75;149=21.75)#40(36=22.5;40=23.0;149=21.75)#80(36=21.75;40=21.5;149=22.25)
+ */
+static void cl_hardware_power_table_parse(struct cl_hw *cl_hw)
+{
+	char *table_str = NULL;
+	char *table_str_p = NULL;
+	char *channel_str = NULL;
+	char *channel_str_p = NULL;
+	char *bw_set = NULL;
+	char *out_tok = NULL;
+	s8 in_reg_pwr[16] = {0};
+	u8 bw_mhz = 0;
+	u8 chan_start = 0;
+	u8 chan_end = 0;
+	u8 curr_pwr_q2 = 0;
+	u8 next_pwr_q2 = 0;
+
+	if (strlen(cl_hw->conf->ce_hardware_power_table) == 0)
+		return; /* Not configured */
+
+	table_str_p = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+	if (!table_str_p)
+		return;
+
+	channel_str_p = kzalloc(CL_MAX_STR_BUFFER_SIZE / 2, GFP_KERNEL);
+	if (!channel_str_p) {
+		kfree(table_str_p);
+		cl_dbg_err(cl_hw, "Failed to allocate channel_str\n");
+		return;
+	}
+
+	table_str = table_str_p;
+
+	strncpy(table_str,
+		cl_hw->conf->ce_hardware_power_table,
+		(CL_MAX_STR_BUFFER_SIZE / 2) - 1);
+
+	/* Iterate through all bandwidth sets included in table_str */
+	bw_set = strsep(&table_str, "#");
+	while (bw_set) {
+		channel_str = channel_str_p;
+		if (sscanf(bw_set, "%hhu(%s)", &bw_mhz, channel_str) != 2) {
+			bw_set = strsep(&table_str, "#");
+			continue;
+		}
+
+		/* Iterate through each channel in this bandwidth set */
+		chan_start = 0;
+		chan_end = 0;
+		curr_pwr_q2 = 0;
+		next_pwr_q2 = 0;
+		out_tok = strsep(&channel_str, ";");
+
+		while (out_tok) {
+			if (sscanf(out_tok, "%hhu=%s", &chan_end, in_reg_pwr) == 2) {
+				next_pwr_q2 = cl_convert_str_int_q2(in_reg_pwr);
+
+				/* Apply regulatory table rule. Skip initial case */
+				if (curr_pwr_q2 != 0 && chan_start != 0)
+					cl_hardware_power_table_update(cl_hw, bw_mhz, chan_start,
+								       chan_end, curr_pwr_q2);
+
+				/* Prepare next iteration */
+				chan_start = chan_end;
+				curr_pwr_q2 = next_pwr_q2;
+			}
+			out_tok = strsep(&channel_str, ";");
+		}
+
+		/* Handle last channel case */
+		if (next_pwr_q2 != 0 && chan_start != 0) {
+			u8 chan_end;
+
+			if (cl_band_is_6g(cl_hw))
+				chan_end = 234;
+			else if (cl_band_is_5g(cl_hw))
+				chan_end = 166;
+			else
+				chan_end = 15;
+
+			cl_hardware_power_table_update(cl_hw, bw_mhz, chan_start,
+						       chan_end, curr_pwr_q2);
+		}
+
+		bw_set = strsep(&table_str, "#");
+	}
+
+	kfree(table_str_p);
+	kfree(channel_str_p);
+}
+
+static void cl_chan_info_ieee80211_update_max_power(struct cl_hw *cl_hw)
+{
+	struct ieee80211_supported_band *sband =  &cl_hw->sband;
+	struct ieee80211_channel *chan = NULL;
+	int i = 0, channel;
+
+	for (i = 0; i < sband->n_channels; i++) {
+		chan = &sband->channels[i];
+		channel = ieee80211_frequency_to_channel(chan->center_freq);
+		chan->max_power = cl_chan_info_get_max_power(cl_hw, channel);
+	}
+}
+
+void cl_chan_info_init(struct cl_hw *cl_hw)
+{
+	struct cl_channel_info *channel_info = &cl_hw->channel_info;
+
+	channel_info->use_channel_info = true;
+
+	if (channel_info->use_channel_info) {
+		if (!cl_parse_channel_info_txt(cl_hw) || !cl_is_parsing_success(cl_hw)) {
+			CL_DBG_WARNING(cl_hw, "Error parsing channel_info.txt. Using default!\n");
+			cl_set_default_channel_info(cl_hw);
+		}
+
+		cl_chan_info_ieee80211_update_max_power(cl_hw);
+		cl_chan_info_set_max_bw(cl_hw);
+		cl_chan_info_dbg(cl_hw);
+	} else {
+		cl_set_default_channel_info(cl_hw);
+	}
+
+	cl_hardware_power_table_parse(cl_hw);
+}
+
+void cl_chan_info_deinit(struct cl_hw *cl_hw)
+{
+	if (cl_hw->channel_info.rd &&
+	    cl_hw->channel_info.use_channel_info)
+		kfree(cl_hw->channel_info.rd);
+}
+
+struct cl_chan_info *cl_chan_info_get(struct cl_hw *cl_hw, u8 channel, u8 bw)
+{
+	int i = 0;
+	struct cl_chan_info *chan_info;
+
+	for (i = 0; i < cl_channel_num(cl_hw); i++) {
+		chan_info = &cl_hw->channel_info.channels[bw][i];
+
+		if (chan_info->channel == channel)
+			return chan_info;
+	}
+
+	return NULL;
+}
+
+u8 cl_chan_info_get_max_bw(struct cl_hw *cl_hw, u8 channel)
+{
+	s8 bw = 0;
+
+	for (bw = CHNL_BW_160; bw > CHNL_BW_20; bw--)
+		if (cl_chan_info_get(cl_hw, channel, bw))
+			return (u8)bw;
+
+	return CHNL_BW_20;
+}
+
+s16 cl_chan_info_get_eirp_limit_q8(struct cl_hw *cl_hw, u8 bw)
+{
+	/* Eirp_limit = min(country_limit, hw_limit) */
+	struct cl_chan_info *chan_info = cl_chan_info_get(cl_hw, cl_hw->channel, bw);
+
+	return chan_info ? (chan_info->max_power_q2 << 6) : CL_DEFAULT_CHANNEL_POWER_Q8;
+}
+
+u8 cl_chan_info_get_max_power(struct cl_hw *cl_hw, u8 channel)
+{
+	struct cl_chan_info *chan_info;
+	u8 bw = 0;
+	u8 max_power_q2 = 0;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		chan_info = cl_chan_info_get(cl_hw, channel, bw);
+
+		if (!chan_info)
+			continue;
+
+		if (chan_info->max_power_q2 > max_power_q2)
+			max_power_q2 = chan_info->max_power_q2;
+	}
+
+	return max_power_q2 >> 2;
+}
+
+static void cl_chan_update_channel_info(struct cl_hw *cl_hw, struct ieee80211_channel *channel)
+{
+	u8 bw;
+	u32 chan = ieee80211_frequency_to_channel(channel->center_freq);
+	struct cl_chan_info *chan_info;
+
+	for (bw = CHNL_BW_20; bw < CHNL_BW_MAX; bw++) {
+		chan_info = cl_chan_info_get(cl_hw, chan, bw);
+		if (!chan_info || chan_info->channel == 0)
+			continue;
+
+		chan_info->max_power_q2         = channel->max_power << 2;
+		chan_info->country_max_power_q2 = channel->max_reg_power << 2;
+		chan_info->flags = channel->flags;
+		chan_info->dfs_cac_ms = channel->dfs_cac_ms;
+	}
+}
+
+void cl_chan_update_channels_info(struct cl_hw *cl_hw,
+				  const struct ieee80211_supported_band *cfg_band)
+{
+	int i = 0;
+
+	spin_lock_bh(&cl_hw->channel_info_lock);
+	for (i = 0; i < cfg_band->n_channels; ++i)
+		cl_chan_update_channel_info(cl_hw, &cfg_band->channels[i]);
+	spin_unlock_bh(&cl_hw->channel_info_lock);
+}
+
+#define CENTER_FREQ_24G_BW_80MHZ  2442
+#define CENTER_FREQ_24G_BW_160MHZ 2482
+
+static int cl_chandef_calc_6g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+			      u32 *primary, u32 *center)
+{
+	u32 bw_mhz = BW_TO_MHZ(bw);
+	u32 min_freq = 0;
+
+	if (freq == FREQ6G(2)) {
+		min_freq = FREQ6G(2);
+	} else if (freq >= FREQ6G(1) && freq <= FREQ6G(233)) {
+		min_freq = FREQ6G(1);
+	} else {
+		cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+		return -EINVAL;
+	}
+
+	*primary = freq - (freq - min_freq) % 20;
+	*center = *primary - (*primary - min_freq) % bw_mhz + offset;
+
+	return 0;
+}
+
+static int cl_chandef_calc_5g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+			      u32 *primary, u32 *center)
+{
+	u32 bw_mhz = BW_TO_MHZ(bw);
+	u32 min_freq = 0;
+
+	if ((freq >= FREQ5G(36) && freq <= FREQ5G(64)) ||
+	    (freq >= FREQ5G(100) && freq <= FREQ5G(144))) {
+		min_freq = FREQ5G(36);
+	} else if (freq >= FREQ5G(149) && freq <= FREQ5G(165)) {
+		min_freq = FREQ5G(149);
+	} else {
+		cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+		return -EINVAL;
+	}
+
+	*primary = freq - (freq - min_freq) % 20;
+	*center = *primary - (*primary - min_freq) % bw_mhz + offset;
+
+	return 0;
+}
+
+static int cl_chandef_calc_24g(struct cl_hw *cl_hw, u16 freq, u32 bw, u32 offset,
+			       u32 *primary, u32 *center)
+{
+	u32 min_freq = 0;
+
+	if (freq < FREQ2G(1) || freq > FREQ2G(14)) {
+		cl_dbg_err(cl_hw, "Invalid frequecy - %u\n", freq);
+		return -EINVAL;
+	}
+
+	min_freq = freq < FREQ2G(14) ? FREQ2G(1) : FREQ2G(14);
+	*primary = freq - (freq - min_freq) % 5;
+
+	if (bw == CHNL_BW_20) {
+		*center = *primary;
+	} else if (bw == CHNL_BW_40) {
+		if (freq <= FREQ2G(4)) {
+			/* Above extension channel */
+			*center = *primary + offset;
+		} else if (freq >= FREQ2G(10)) {
+			/* Below extension channel */
+			*center = *primary - offset;
+		} else {
+			/* Channels 8-9 must be below if channel 13 is not supported */
+			if (freq >= FREQ2G(8) && !cl_chan_info_get(cl_hw, 13, CHNL_BW_20) &&
+			    /* For Calibration, when using 2.4GHz channels on TCV0 to set SX0. */
+			    !cl_chan_info_get(cl_hw->chip->cl_hw_tcv1, 13, CHNL_BW_20)) {
+				*center = *primary - offset;
+			} else {
+				/**
+				 * Set below/above according to the current hapd configuration.
+				 * If undefined, preffer above offset.
+				 */
+				if (cl_hw->ht40_preffered_ch_type == NL80211_CHAN_HT40MINUS)
+					*center = *primary - offset;
+				else
+					*center = *primary + offset;
+			}
+		}
+	} else if (bw == CHNL_BW_80) {
+		*center = CENTER_FREQ_24G_BW_80MHZ;
+	} else {
+		/* 160MHz */
+		*center = CENTER_FREQ_24G_BW_160MHZ;
+	}
+
+	return 0;
+}
+
+int cl_chandef_calc(struct cl_hw *cl_hw, u32 channel, u32 bw,
+		    enum nl80211_chan_width *width, u32 *primary, u32 *center)
+{
+	u16 freq = ieee80211_channel_to_frequency(channel, cl_hw->nl_band);
+	u32 offset = 0;
+	int ret = 0;
+
+	switch (bw) {
+	case CHNL_BW_20:
+		offset = 0;
+		if (channel == 14)
+			*width = NL80211_CHAN_WIDTH_20_NOHT;
+		else
+			*width = NL80211_CHAN_WIDTH_20;
+		break;
+	case CHNL_BW_40:
+		offset = 10;
+		*width = NL80211_CHAN_WIDTH_40;
+		break;
+	case CHNL_BW_80:
+		if (!cl_hw->chip->conf->ce_production_mode && cl_band_is_24g(cl_hw)) {
+			cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+			return -EINVAL;
+		}
+
+		offset = 30;
+		*width = NL80211_CHAN_WIDTH_80;
+		break;
+	case CHNL_BW_160:
+		/* Verify 2.4G bandwidth validity only in operational mode */
+		if (!cl_hw->chip->conf->ce_production_mode && cl_band_is_24g(cl_hw)) {
+			cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+			return -EINVAL;
+		}
+
+		offset = 70;
+		*width = NL80211_CHAN_WIDTH_160;
+		break;
+	default:
+		cl_dbg_err(cl_hw, "Invalid bandwidth - %u\n", bw);
+		return -EINVAL;
+	}
+
+	if (cl_band_is_6g(cl_hw))
+		ret = cl_chandef_calc_6g(cl_hw, freq, bw, offset, primary, center);
+	else if (cl_band_is_5g(cl_hw))
+		ret = cl_chandef_calc_5g(cl_hw, freq, bw, offset, primary, center);
+	else
+		ret = cl_chandef_calc_24g(cl_hw, freq, bw, offset, primary, center);
+
+	cl_dbg_trace(cl_hw, "primary=%u center=%u\n", *primary, *center);
+
+	return ret;
+}
+
+int cl_chandef_get_default(struct cl_hw *cl_hw, u32 *channel, u8 *bw,
+			   enum nl80211_chan_width *width,
+			   u32 *primary, u32 *center)
+{
+	*bw = cl_hw->conf->ci_chandef_bandwidth;
+	*channel = cl_hw->conf->ci_chandef_channel;
+
+	return cl_chandef_calc(cl_hw, *channel, *bw, width, primary, center);
+}
+
+int cl_init_channel_stats(struct cl_hw *cl_hw,
+			  struct cl_channel_stats *ch_stats, u32 freq)
+{
+	memset(ch_stats, 0, sizeof(*ch_stats));
+
+	ch_stats->channel = ieee80211_frequency_to_channel(freq);
+	if (ch_stats->channel == INVALID_CHAN_IDX) {
+		cl_dbg_err(cl_hw, "Failed to get channel num for freq %u\n", freq);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void cl_get_final_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats)
+{
+	u32 tx_mine, rx_mine, edca_cca;
+
+	/*
+	 * Currently mac_hw_rx_mine_busy_get() doesn't work properly,
+	 * so use mac_hw_edca_cca_busy_get() as workaround.
+	 * After scan mac_hw_rx_mine_busy_get almost always returns zeros
+	 * or some very small values.
+	 * Use of EDCA CCA is less accurate, since it also includes non-wifi noise
+	 */
+	tx_mine = mac_hw_tx_mine_busy_get(cl_hw);
+	edca_cca = mac_hw_edca_cca_busy_get(cl_hw);
+	rx_mine = edca_cca;
+
+	ch_stats->util_time_tx = max_t(s64, tx_mine - ch_stats->util_time_tx_total, 0);
+	ch_stats->util_time_rx = max_t(s64, rx_mine - ch_stats->util_time_rx_total, 0);
+	ch_stats->edca_cca_time = max_t(s64, edca_cca - ch_stats->edca_cca_time_total, 0);
+
+	ch_stats->util_time_busy = ch_stats->edca_cca_time + ch_stats->util_time_tx;
+
+	ch_stats->ch_noise = cl_calc_noise_floor(cl_hw, NULL);
+
+	ch_stats->scan_time_ms = jiffies_to_msecs(get_jiffies_64() - ch_stats->scan_start_jiffies);
+}
+
+void cl_get_initial_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats)
+{
+	ch_stats->util_time_tx = 0;
+	ch_stats->util_time_rx = 0;
+	ch_stats->edca_cca_time = 0;
+	ch_stats->util_time_busy = 0;
+	ch_stats->ch_noise = 0;
+	ch_stats->scan_time_ms = 0;
+
+	ch_stats->util_time_tx_total = mac_hw_tx_mine_busy_get(cl_hw);
+	ch_stats->edca_cca_time_total = mac_hw_edca_cca_busy_get(cl_hw);
+	ch_stats->util_time_rx_total = ch_stats->edca_cca_time_total;
+
+	ch_stats->scan_start_jiffies = get_jiffies_64();
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 12/96] cl8k: add channel.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (10 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 11/96] cl8k: add channel.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 13/96] cl8k: add chip.c viktor.barna
                   ` (83 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/channel.h | 401 +++++++++++++++++++++
 1 file changed, 401 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/channel.h

diff --git a/drivers/net/wireless/celeno/cl8k/channel.h b/drivers/net/wireless/celeno/cl8k/channel.h
new file mode 100644
index 000000000000..aec65b2d1b19
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/channel.h
@@ -0,0 +1,401 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_CHANNEL_H
+#define CL_CHANNEL_H
+
+#include <linux/types.h>
+#include <uapi/linux/nl80211.h>
+#include <net/cfg80211.h>
+
+#include "def.h"
+
+enum bitmap_chan_idx_6g {
+	b6g_ch1,
+	b6g_ch2,
+	b6g_ch5,
+	b6g_ch9,
+	b6g_ch13,
+	b6g_ch17,
+	b6g_ch21,
+	b6g_ch25,
+	b6g_ch29,
+	b6g_ch33,
+	b6g_ch37,
+	b6g_ch41,
+	b6g_ch45,
+	b6g_ch49,
+	b6g_ch53,
+	b6g_ch57,
+	b6g_ch61,
+	b6g_ch65,
+	b6g_ch69,
+	b6g_ch73,
+	b6g_ch77,
+	b6g_ch81,
+	b6g_ch85,
+	b6g_ch89,
+	b6g_ch93,
+	b6g_ch97,
+	b6g_ch101,
+	b6g_ch105,
+	b6g_ch109,
+	b6g_ch113,
+	b6g_ch117,
+	b6g_ch121,
+	b6g_ch125,
+	b6g_ch129,
+	b6g_ch133,
+	b6g_ch137,
+	b6g_ch141,
+	b6g_ch145,
+	b6g_ch149,
+	b6g_ch153,
+	b6g_ch157,
+	b6g_ch161,
+	b6g_ch165,
+	b6g_ch169,
+	b6g_ch173,
+	b6g_ch177,
+	b6g_ch181,
+	b6g_ch185,
+	b6g_ch189,
+	b6g_ch193,
+	b6g_ch197,
+	b6g_ch201,
+	b6g_ch205,
+	b6g_ch209,
+	b6g_ch213,
+	b6g_ch217,
+	b6g_ch221,
+	b6g_ch225,
+	b6g_ch229,
+	b6g_ch233,
+
+	NUM_BITMAP_CHANNELS_6G
+};
+
+enum ext_chan_idx_6g {
+	ext_b6g_ch1,
+	ext_b6g_ch2,
+	ext_b6g_ch3,
+	ext_b6g_ch5,
+	ext_b6g_ch7,
+	ext_b6g_ch9,
+	ext_b6g_ch11,
+	ext_b6g_ch13,
+	ext_b6g_ch15,
+	ext_b6g_ch17,
+	ext_b6g_ch19,
+	ext_b6g_ch21,
+	ext_b6g_ch23,
+	ext_b6g_ch25,
+	ext_b6g_ch27,
+	ext_b6g_ch29,
+	ext_b6g_ch31,
+	ext_b6g_ch33,
+	ext_b6g_ch35,
+	ext_b6g_ch37,
+	ext_b6g_ch39,
+	ext_b6g_ch41,
+	ext_b6g_ch43,
+	ext_b6g_ch45,
+	ext_b6g_ch47,
+	ext_b6g_ch49,
+	ext_b6g_ch51,
+	ext_b6g_ch53,
+	ext_b6g_ch55,
+	ext_b6g_ch57,
+	ext_b6g_ch59,
+	ext_b6g_ch61,
+	ext_b6g_ch63,
+	ext_b6g_ch65,
+	ext_b6g_ch67,
+	ext_b6g_ch69,
+	ext_b6g_ch71,
+	ext_b6g_ch73,
+	ext_b6g_ch75,
+	ext_b6g_ch77,
+	ext_b6g_ch79,
+	ext_b6g_ch81,
+	ext_b6g_ch83,
+	ext_b6g_ch85,
+	ext_b6g_ch87,
+	ext_b6g_ch89,
+	ext_b6g_ch91,
+	ext_b6g_ch93,
+	ext_b6g_ch95,
+	ext_b6g_ch97,
+	ext_b6g_ch99,
+	ext_b6g_ch101,
+	ext_b6g_ch103,
+	ext_b6g_ch105,
+	ext_b6g_ch107,
+	ext_b6g_ch109,
+	ext_b6g_ch111,
+	ext_b6g_ch113,
+	ext_b6g_ch115,
+	ext_b6g_ch117,
+	ext_b6g_ch119,
+	ext_b6g_ch121,
+	ext_b6g_ch123,
+	ext_b6g_ch125,
+	ext_b6g_ch127,
+	ext_b6g_ch129,
+	ext_b6g_ch131,
+	ext_b6g_ch133,
+	ext_b6g_ch135,
+	ext_b6g_ch137,
+	ext_b6g_ch139,
+	ext_b6g_ch141,
+	ext_b6g_ch143,
+	ext_b6g_ch145,
+	ext_b6g_ch147,
+	ext_b6g_ch149,
+	ext_b6g_ch151,
+	ext_b6g_ch153,
+	ext_b6g_ch155,
+	ext_b6g_ch157,
+	ext_b6g_ch159,
+	ext_b6g_ch161,
+	ext_b6g_ch163,
+	ext_b6g_ch165,
+	ext_b6g_ch167,
+	ext_b6g_ch169,
+	ext_b6g_ch171,
+	ext_b6g_ch173,
+	ext_b6g_ch175,
+	ext_b6g_ch177,
+	ext_b6g_ch179,
+	ext_b6g_ch181,
+	ext_b6g_ch183,
+	ext_b6g_ch185,
+	ext_b6g_ch187,
+	ext_b6g_ch189,
+	ext_b6g_ch191,
+	ext_b6g_ch193,
+	ext_b6g_ch195,
+	ext_b6g_ch197,
+	ext_b6g_ch199,
+	ext_b6g_ch201,
+	ext_b6g_ch203,
+	ext_b6g_ch205,
+	ext_b6g_ch207,
+	ext_b6g_ch209,
+	ext_b6g_ch211,
+	ext_b6g_ch213,
+	ext_b6g_ch215,
+	ext_b6g_ch217,
+	ext_b6g_ch219,
+	ext_b6g_ch221,
+	ext_b6g_ch223,
+	ext_b6g_ch225,
+	ext_b6g_ch227,
+	ext_b6g_ch229,
+	ext_b6g_ch231,
+	ext_b6g_ch233,
+
+	NUM_EXT_CHANNELS_6G
+};
+
+enum chan_idx_5g {
+	b5g_ch36,
+	b5g_ch38,
+	b5g_ch40,
+	b5g_ch42,
+	b5g_ch44,
+	b5g_ch46,
+	b5g_ch48,
+	b5g_ch50,
+	b5g_ch52,
+	b5g_ch54,
+	b5g_ch56,
+	b5g_ch58,
+	b5g_ch60,
+	b5g_ch62,
+	b5g_ch64,
+	b5g_ch100,
+	b5g_ch102,
+	b5g_ch104,
+	b5g_ch106,
+	b5g_ch108,
+	b5g_ch110,
+	b5g_ch112,
+	b5g_ch114,
+	b5g_ch116,
+	b5g_ch118,
+	b5g_ch120,
+	b5g_ch122,
+	b5g_ch124,
+	b5g_ch126,
+	b5g_ch128,
+	b5g_ch132,
+	b5g_ch134,
+	b5g_ch136,
+	b5g_ch138,
+	b5g_ch140,
+	b5g_ch142,
+	b5g_ch144,
+	b5g_ch149,
+	b5g_ch151,
+	b5g_ch153,
+	b5g_ch155,
+	b5g_ch157,
+	b5g_ch159,
+	b5g_ch161,
+	b5g_ch165,
+
+	NUM_CHANNELS_5G
+};
+
+enum chan_idx_24g {
+	b24g_ch1,
+	b24g_ch2,
+	b24g_ch3,
+	b24g_ch4,
+	b24g_ch5,
+	b24g_ch6,
+	b24g_ch7,
+	b24g_ch8,
+	b24g_ch9,
+	b24g_ch10,
+	b24g_ch11,
+	b24g_ch12,
+	b24g_ch13,
+	b24g_ch14,
+
+	NUM_CHANNELS_24G
+};
+
+/* 6g band has the largest list */
+#define MAX_CHANNELS        NUM_BITMAP_CHANNELS_6G
+#define MAX_EXT_CHANNELS    NUM_EXT_CHANNELS_6G
+#define START_CHAN_IDX_6G   1
+
+/* 1 ==> 5955 */
+#define FREQ6G(_chan) ((_chan) == 2 ? 5935 : 5950 + 5 * (_chan))
+/* 36 ==> 5180 */
+#define FREQ5G(_chan) (5000 + 5 * (_chan))
+/* 1 ==> 2412 */
+#define FREQ2G(_chan) ((_chan) == 14 ? 2484 : 2407 + (_chan) *  5)
+#define CHAN_BITMAP_IDX_6G_2_EXT_IDX(_idx) ((_idx) ? ((_idx) << 1) - 1 : 0)
+#define CHAN_EXT_IDX_6G_2_BITMAP_IDX(_ext_idx) (((_ext_idx) + 1) >> 1)
+
+/* 6G channels - UNII-5 */
+#define START_CHAN_IDX_UNII5 1
+#define END_CHAN_IDX_UNII5   85
+/* 6G channels - UNII-6 */
+#define START_CHAN_IDX_UNII6 89
+#define END_CHAN_IDX_UNII6   109
+/* 6G channels - UNII-7 */
+#define START_CHAN_IDX_UNII7 113
+#define END_CHAN_IDX_UNII7   165
+/* 6G channels - UNII-8 */
+#define START_CHAN_IDX_UNII8 169
+#define END_CHAN_IDX_UNII8   233
+
+#define INVALID_CHAN_IDX 0xff
+
+#ifndef IEEE80211_DFS_WEATHER_MIN_CAC_TIME_MS
+#define IEEE80211_DFS_WEATHER_MIN_CAC_TIME_MS 600000
+#endif
+
+struct cl_hw;
+
+u8 cl_channel_to_ext_index_6g(struct cl_hw *cl_hw, u32 channel);
+u8 cl_channel_to_index(struct cl_hw *cl_hw, u32 channel);
+u8 cl_channel_to_bitmap_index(struct cl_hw *cl_hw, u32 channel);
+u16 cl_channel_ext_idx_to_freq_6g(struct cl_hw *cl_hw, u8 index);
+u16 cl_channel_idx_to_freq(struct cl_hw *cl_hw, u8 index);
+bool cl_channel_is_valid(struct cl_hw *cl_hw, u8 channel);
+u32 cl_channel_num(struct cl_hw *cl_hw);
+bool cl_channel_is_dfs(struct cl_hw *cl_hw, u8 channel);
+u32 cl_channel_get_cac_time_ms(struct cl_hw *cl_hw, u8 channel);
+
+#define CL_MAX_STR_BUFFER_SIZE 1024
+
+#define CL_DEFAULT_CHANNEL_POWER_Q8 (30 << 8)
+
+#define CL_20MHZ_CH_GAP  4
+#define CL_40MHZ_CH_GAP  8
+#define CL_80MHZ_CH_GAP  16
+#define CL_160MHZ_CH_GAP 32
+#define CL_40MHZ_HOP     2
+#define CL_80MHZ_HOP     4
+#define CL_160MHZ_HOP    8
+
+struct cl_chan_info {
+	u8 channel;
+	u8 max_bw;
+	/* Resolution of 0.25dB */
+	u8 max_power_q2; /* MIN(country_max_power_q2, hardware_max_power_q2) */
+	u8 country_max_power_q2;
+	u8 hardware_max_power_q2;
+	u32 flags; /* channel flags from &enum ieee80211_channel_flags */
+	unsigned int dfs_cac_ms;
+};
+
+struct cl_channel_info {
+	bool use_channel_info;
+	struct cl_chan_info channels[CHNL_BW_MAX][MAX_CHANNELS];
+	enum nl80211_dfs_regions standard;
+	struct ieee80211_regdomain *rd;
+};
+
+void cl_chan_info_init(struct cl_hw *cl_hw);
+void cl_chan_info_deinit(struct cl_hw *cl_hw);
+struct cl_chan_info *cl_chan_info_get(struct cl_hw *cl_hw, u8 channel, u8 bw);
+u8 cl_chan_info_get_max_bw(struct cl_hw *cl_hw, u8 channel);
+s16 cl_chan_info_get_eirp_limit_q8(struct cl_hw *cl_hw, u8 bw);
+u8 cl_chan_info_get_max_power(struct cl_hw *cl_hw, u8 channel);
+void cl_chan_update_channels_info(struct cl_hw *cl_hw,
+				  const struct ieee80211_supported_band *cfg_band);
+int cl_chandef_calc(struct cl_hw *cl_hw, u32 channel, u32 bw,
+		    enum nl80211_chan_width *width, u32 *primary, u32 *center);
+int cl_chandef_get_default(struct cl_hw *cl_hw, u32 *channel, u8 *bw,
+			   enum nl80211_chan_width *width,
+			   u32 *primary, u32 *center);
+
+struct cl_channel_stats {
+	bool scan_enabled;
+	u8 channel;
+	enum cl_channel_bw scan_bw;
+
+	s8 avg_snr;
+	s8 avg_non_wifi_noise;
+	u32 avg_channel_util;
+	u32 avg_retry_rate;
+	u32 total_frames;
+	u32 total_retries;
+	u32 vendor_specific;
+
+	/* Time radio spent rx on channel + non wifi noise */
+	u64 edca_cca_time;
+	u64 edca_cca_time_total;
+
+	/* Time radio detected that channel was busy (Busy = Rx + Tx + Interference) */
+	u64 util_time_busy;
+
+	/* Time radio spent tx on channel */
+	u64 util_time_tx;
+	u64 util_time_tx_total;
+
+	/* Time radio spent rx on channel (Rx = Rx_obss + Rx_self + Rx_errr (self and obss errs) */
+	u64 util_time_rx;
+	u64 util_time_rx_total;
+
+	s8 ch_noise;
+
+	u64 scan_start_jiffies;
+	u32 scan_time_ms;
+
+	/* Currently this metric can't be calculated because fromat_mod in rxheader is always 0 */
+	/* u64 util_time_self; */
+};
+
+int cl_init_channel_stats(struct cl_hw *cl_hw,
+			  struct cl_channel_stats *ch_stats, u32 freq);
+void cl_get_final_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats);
+void cl_get_initial_channel_stats(struct cl_hw *cl_hw, struct cl_channel_stats *ch_stats);
+
+#endif /* CL_CHANNEL_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 13/96] cl8k: add chip.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (11 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 12/96] cl8k: add channel.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 14/96] cl8k: add chip.h viktor.barna
                   ` (82 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/chip.c | 580 ++++++++++++++++++++++++
 1 file changed, 580 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/chip.c

diff --git a/drivers/net/wireless/celeno/cl8k/chip.c b/drivers/net/wireless/celeno/cl8k/chip.c
new file mode 100644
index 000000000000..67f65dffd804
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/dmapool.h>
+
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "temperature.h"
+#include "phy.h"
+#include "e2p.h"
+#include "main.h"
+#include "rates.h"
+#include "calib.h"
+#include "config.h"
+#include "utils.h"
+#include "chip.h"
+
+#define CL_ALIGN_BOUND_64KB BIT(16)
+
+static void cl_chip_set_max_antennas(struct cl_chip *chip)
+{
+	u16 device_id = cl_chip_get_device_id(chip);
+
+	switch (device_id) {
+	case 0x8040:
+	case 0x8046:
+		chip->max_antennas = MAX_ANTENNAS_CL804X;
+		break;
+	case 0x8060:
+	case 0x8066:
+		chip->max_antennas = MAX_ANTENNAS_CL806X;
+		break;
+	case 0x8080:
+	case 0x8086:
+	default:
+		chip->max_antennas = MAX_ANTENNAS_CL808X;
+		break;
+	}
+}
+
+/*
+ * This function is necessary since now we can't determine the max antenna number by the
+ * device_id alone, since there is at least one case of device_id 8046 and max antenna of 3.
+ */
+static void cl_chip_update_max_antennas(struct cl_chip *chip)
+{
+	u8 wiring_id = chip->fem.wiring_id;
+
+	if (wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1 || wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+		chip->max_antennas = MAX_ANTENNAS_WIRING_ID_27_31;
+}
+
+static int cl_chip_print_serial_number(struct cl_chip *chip)
+{
+	u8 serial_number[SIZE_GEN_SERIAL_NUMBER + 1] = {0};
+
+	if (!IS_REAL_PHY(chip))
+		return 0;
+
+	if (cl_e2p_read(chip, (u8 *)&serial_number, SIZE_GEN_SERIAL_NUMBER, ADDR_GEN_SERIAL_NUMBER))
+		return -1;
+
+	if (strlen(serial_number) == 0)
+		cl_dbg_chip_verbose(chip, "Serial-number in not set in EEPROM\n");
+	else
+		cl_dbg_chip_verbose(chip, "Serial-number = %s\n", serial_number);
+
+	return 0;
+}
+
+static int cl_chip_ring_indices_init(struct cl_chip *chip)
+{
+	struct cl_ring_indices *ring_indices = &chip->ring_indices;
+
+	ring_indices->pool = dma_pool_create("cl_ring_indices_pool", chip->dev,
+					     (sizeof(struct cl_ipc_ring_indices) * TCV_MAX),
+					     CL_ALIGN_BOUND_64KB, CL_ALIGN_BOUND_64KB);
+
+	if (!ring_indices->pool) {
+		cl_dbg_chip_err(chip, "ring_indices pool create failed !!!\n");
+		return -ENOMEM;
+	}
+
+	ring_indices->params = dma_pool_alloc(ring_indices->pool, GFP_KERNEL,
+					      &ring_indices->dma_addr);
+	if (!ring_indices->params)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void cl_chip_ring_indices_deinit(struct cl_chip *chip)
+{
+	if (chip->ring_indices.params) {
+		dma_pool_free(chip->ring_indices.pool,
+			      chip->ring_indices.params,
+			      chip->ring_indices.dma_addr);
+		chip->ring_indices.params = NULL;
+	}
+
+	dma_pool_destroy(chip->ring_indices.pool);
+	chip->ring_indices.pool = NULL;
+}
+
+struct cl_chip *cl_chip_alloc(u8 idx)
+{
+	struct cl_chip *chip = vzalloc(sizeof(*chip));
+
+	if (!chip)
+		return NULL;
+
+	chip->idx = idx;
+	return chip;
+}
+
+void cl_chip_dealloc(struct cl_chip *chip)
+{
+	cl_chip_config_dealloc(chip);
+	vfree(chip);
+}
+
+static void cl_chip_workqueue_create(struct cl_chip *chip)
+{
+	if (!chip->chip_workqueue)
+		chip->chip_workqueue = create_singlethread_workqueue("chip_workqueue");
+}
+
+static void cl_chip_workqueue_destroy(struct cl_chip *chip)
+{
+	if (chip->chip_workqueue) {
+		destroy_workqueue(chip->chip_workqueue);
+		chip->chip_workqueue = NULL;
+	}
+}
+
+int cl_chip_init(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	chip->ipc_host2xmac_trigger_set = ipc_host_2_umac_trigger_set;
+
+	chip->platform.app = NULL;
+	chip->platform.app_size = 0;
+	chip->platform.idx = U8_MAX;
+
+	spin_lock_init(&chip->isr_lock);
+	spin_lock_init(&chip->spi_lock);
+	mutex_init(&chip->start_msg_lock);
+	mutex_init(&chip->calib_runtime_mutex);
+
+	rwlock_init(&chip->cl_hw_lock);
+	mutex_init(&chip->recovery_mutex);
+	mutex_init(&chip->set_idle_mutex);
+
+	cl_chip_set_max_antennas(chip);
+
+	ret = cl_irq_request(chip);
+	if (ret)
+		return ret;
+
+	ipc_host_global_int_en_set(chip, 1);
+
+	cl_temperature_init(chip);
+
+	ret = cl_e2p_init(chip);
+	if (ret) {
+		cl_dbg_chip_err(chip, "cl_e2p_init failed %d\n", ret);
+		return ret;
+	}
+
+	ret = cl_fem_init(chip);
+	if (ret)
+		return ret;
+
+	/*
+	 * Update chip->max_antennas according to wiring_id if needed.
+	 * Should be called after cl_fem_init(), where wiring_id is read from eeprom.
+	 */
+	cl_chip_update_max_antennas(chip);
+
+	ret = cl_chip_ring_indices_init(chip);
+	if (ret)
+		return ret;
+
+	cl_chip_print_serial_number(chip);
+
+	cl_wrs_tables_global_build();
+	cl_data_rates_inverse_build();
+	cl_chip_workqueue_create(chip);
+
+	return ret;
+}
+
+void cl_chip_deinit(struct cl_chip *chip)
+{
+	cl_chip_workqueue_destroy(chip);
+
+	cl_chip_ring_indices_deinit(chip);
+
+	cl_temperature_close(chip);
+
+	cl_e2p_close(chip);
+
+	ipc_host_global_int_en_set(chip, 0);
+
+	cl_irq_free(chip);
+}
+
+u16 cl_chip_get_device_id(struct cl_chip *chip)
+{
+	u16 device_id = chip->pci_dev->device;
+
+	if (chip->conf->ci_sim_device_id)
+		return chip->conf->ci_sim_device_id;
+
+	/* If device-id is default, set it accoridng to phy-dev. */
+	if (device_id == 0x8000 || device_id == 0x8001)
+		device_id = (chip->conf->ci_phy_dev == PHY_DEV_ATHOS) ? 0x8086 : 0x8080;
+
+	return device_id;
+}
+
+bool cl_chip_is_enabled(struct cl_chip *chip)
+{
+	return cl_chip_is_tcv0_enabled(chip) || cl_chip_is_tcv1_enabled(chip);
+}
+
+bool cl_chip_is_both_enabled(struct cl_chip *chip)
+{
+	return cl_chip_is_tcv0_enabled(chip) && cl_chip_is_tcv1_enabled(chip);
+}
+
+bool cl_chip_is_tcv0_enabled(struct cl_chip *chip)
+{
+	return chip->conf->ce_tcv_enabled[TCV0];
+}
+
+bool cl_chip_is_tcv1_enabled(struct cl_chip *chip)
+{
+	return chip->conf->ce_tcv_enabled[TCV1];
+}
+
+bool cl_chip_is_only_tcv0_enabled(struct cl_chip *chip)
+{
+	return cl_chip_is_tcv0_enabled(chip) && !cl_chip_is_tcv1_enabled(chip);
+}
+
+bool cl_chip_is_only_tcv1_enabled(struct cl_chip *chip)
+{
+	return !cl_chip_is_tcv0_enabled(chip) && cl_chip_is_tcv1_enabled(chip);
+}
+
+void cl_chip_set_hw(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	if (cl_hw_is_tcv0(cl_hw))
+		chip->cl_hw_tcv0 = cl_hw;
+	else
+		chip->cl_hw_tcv1 = cl_hw;
+}
+
+void cl_chip_unset_hw(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	if (cl_hw_is_tcv0(cl_hw))
+		chip->cl_hw_tcv0 = NULL;
+	else
+		chip->cl_hw_tcv1 = NULL;
+}
+
+bool cl_chip_is_8ant(struct cl_chip *chip)
+{
+	return chip->max_antennas == MAX_ANTENNAS_CL808X;
+}
+
+bool cl_chip_is_6ant(struct cl_chip *chip)
+{
+	return chip->max_antennas == MAX_ANTENNAS_CL806X;
+}
+
+bool cl_chip_is_4ant(struct cl_chip *chip)
+{
+	return chip->max_antennas == MAX_ANTENNAS_CL804X;
+}
+
+bool cl_chip_is_3ant(struct cl_chip *chip)
+{
+	return chip->max_antennas == MAX_ANTENNAS_WIRING_ID_27_31;
+}
+
+bool cl_chip_is_6g(struct cl_chip *chip)
+{
+	u16 device_id = cl_chip_get_device_id(chip);
+	u8 band = device_id & 0xf;
+
+	return (band == 6);
+}
+
+#define MAX_FIRST_MASK_BIT ((ETH_ALEN * 8) - 1)
+
+static struct cl_chip_conf chip_conf = {
+	.ce_tcv_enabled = {
+		[TCV0] = false,
+		[TCV1] = false
+	},
+	.ce_lmac = "lmacfw.bin",
+	.ce_smac = "smacfw.bin",
+	.ce_irq_smp_affinity = -1,
+	.ce_eeprom_mode = E2P_MODE_BIN,
+	.ce_production_mode = false,
+	.ci_pci_msi_enable = true,
+	.ci_dma_lli_max_chan = {
+		[TCV0] = 6,
+		[TCV1] = 3
+	},
+	.ci_regdom_mode = "self",
+	.ci_country_code = "US",
+	.ce_ela_mode = "default",
+	.ci_phy_dev = PHY_DEV_OLYMPUS,
+	.ce_debug_level = DBG_LVL_ERROR,
+	.ce_host_pci_gen_ver = 3,
+	.ci_scale_down_fw = 1,
+	.ce_temp_comp_en = true,
+	.ce_temp_protect_en = TEMP_PROTECT_EXTERNAL,
+	.ce_temp_protect_delta = 0,
+	.ce_temp_protect_th_max = 105,
+	.ce_temp_protect_th_min = 95,
+	.ce_temp_protect_tx_period_ms = 50,
+	.ce_temp_protect_radio_off_th = 110,
+	.ci_phy_load_bootdrv = false,
+	.ce_phys_mac_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	.ce_lam_enable = true,
+	.ce_first_mask_bit = 0,
+	.ci_no_capture_noise_sleep = true,
+	.ci_afe_config_en = true,
+	.ci_afe_vc_ref = 0x77777777,
+	.ci_afe_vc_avd = 0x55555555,
+	.ci_afe_eoc_ctrl = 0xaaaa,
+	.ci_afe_ch_cml_sel = 0xff,
+	.ci_afe_vc_cml = 0,
+	.ci_afe_cml_sel = 7,
+	.ci_afe_loopback = false,
+	.ci_afe_hw_mode = true,
+	.ci_dcoc_mv_thr = {
+		[CHNL_BW_20] = 150,
+		[CHNL_BW_40] = 100,
+		[CHNL_BW_80] = 100,
+		[CHNL_BW_160] = 100
+	},
+	.ci_calib_check_errors = false,
+	.ci_lolc_db_thr = -40,
+	.ci_iq_db_thr = -46,
+	.ci_rx_resched_tasklet = false,
+	.ci_rx_skb_max = 10000,
+	.ci_tcv1_chains_sx0 = false,
+	.ci_sim_device_id = 0,
+	.ce_calib_runtime_en = false,
+	.ci_calib_eeprom_en = 0,
+	.ci_calib_runtime_force = false,
+	.ci_la_mirror_en = true,
+};
+
+static int cl_chip_update_config(struct cl_chip *chip, char *name, char *value)
+{
+	struct cl_chip_conf *conf = chip->conf;
+	int ret = -ENOENT;
+
+	do {
+		READ_BOOL_ARR(ce_tcv_enabled, TCV_MAX);
+		READ_STR(ce_lmac);
+		READ_STR(ce_smac);
+		READ_S32(ce_irq_smp_affinity);
+		READ_U8(ce_eeprom_mode);
+		READ_BOOL(ce_production_mode);
+		READ_BOOL(ci_pci_msi_enable);
+		READ_U8_ARR(ci_dma_lli_max_chan, TCV_MAX, true);
+		READ_STR(ci_regdom_mode);
+		READ_STR(ci_country_code);
+		READ_STR(ce_ela_mode);
+		READ_U8(ci_phy_dev);
+		READ_S8(ce_debug_level);
+		READ_U8(ce_host_pci_gen_ver);
+		READ_S32(ci_scale_down_fw);
+		READ_BOOL(ce_temp_comp_en);
+		READ_U8(ce_temp_protect_en);
+		READ_S8(ce_temp_protect_delta);
+		READ_S16(ce_temp_protect_th_max);
+		READ_S16(ce_temp_protect_th_min);
+		READ_U16(ce_temp_protect_tx_period_ms);
+		READ_S16(ce_temp_protect_radio_off_th);
+		READ_BOOL(ci_phy_load_bootdrv);
+		READ_MAC(ce_phys_mac_addr);
+		READ_BOOL(ce_lam_enable);
+		READ_U8(ce_first_mask_bit);
+		READ_BOOL(ci_no_capture_noise_sleep);
+		READ_BOOL(ci_afe_config_en);
+		READ_U32(ci_afe_vc_ref);
+		READ_U8(ci_afe_cml_sel);
+		READ_BOOL(ci_afe_loopback);
+		READ_BOOL(ci_afe_hw_mode);
+		READ_U8_ARR(ci_dcoc_mv_thr, CHNL_BW_MAX, true);
+		READ_BOOL(ci_calib_check_errors);
+		READ_S8(ci_lolc_db_thr);
+		READ_S8(ci_iq_db_thr);
+		READ_BOOL(ci_rx_resched_tasklet);
+		READ_U32(ci_rx_skb_max);
+		READ_BOOL(ci_tcv1_chains_sx0);
+		READ_U16(ci_sim_device_id);
+		READ_BOOL(ce_calib_runtime_en);
+		READ_BOOL(ci_calib_eeprom_en);
+		READ_BOOL(ci_calib_runtime_force);
+		READ_BOOL(ci_la_mirror_en);
+	} while (0);
+
+	if (ret == -ENOENT) {
+		if (cl_config_is_non_driver_param(name))
+			ret = 0;
+		else
+			CL_DBG_ERROR_CHIP(chip, "No matching conf for nvram parameter %s\n", name);
+	}
+
+	return ret;
+}
+
+static bool cl_chip_is_valid_device_id(u16 device_id)
+{
+	switch (device_id) {
+	case 0x8000:
+	case 0x8001:
+	case 0x8080:
+	case 0x8086:
+	case 0x8060:
+	case 0x8040:
+	case 0x8066:
+	case 0x8046:
+		return true;
+	default:
+		pr_debug("Invalid device_id %u\n", device_id);
+		break;
+	}
+
+	return false;
+}
+
+static int cl_chip_post_configuration(struct cl_chip *chip)
+{
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (conf->ce_eeprom_mode >= E2P_MODE_MAX) {
+		CL_DBG_ERROR_CHIP(chip,
+				  "Invalid ce_eeprom_mode [%u]. Must be 0 (file) or 1 (eeprom)\n",
+				  conf->ce_eeprom_mode);
+		return -EINVAL;
+	}
+
+	if (conf->ce_first_mask_bit > MAX_FIRST_MASK_BIT) {
+		CL_DBG_ERROR_CHIP(chip, "Invalid ce_first_mask_bit (%u). Must be <= %u\n",
+				  conf->ce_first_mask_bit, MAX_FIRST_MASK_BIT);
+		return -EINVAL;
+	}
+
+	if (conf->ci_tcv1_chains_sx0 && !conf->ce_production_mode) {
+		cl_dbg_chip_verbose(chip, "Force ci_tcv1_chains_sx0 to 0 for operational mode\n");
+		conf->ci_tcv1_chains_sx0 = false;
+	}
+
+	if (conf->ci_sim_device_id && !cl_chip_is_valid_device_id(conf->ci_sim_device_id)) {
+		CL_DBG_ERROR_CHIP(chip, "Invalid ci_sim_device_id (0x%x)\n",
+				  conf->ci_sim_device_id);
+		return -1;
+	}
+	/* IQ and DCOC calibration data will be saved only if runtime feature is enable */
+	if (chip->conf->ci_calib_eeprom_en && !chip->conf->ce_calib_runtime_en) {
+		chip->conf->ci_calib_eeprom_en = 0;
+		CL_DBG_ERROR_CHIP(chip, "Writing/reading calibration data from the EEPROM is "
+				  "disabled because ce_calib_runtime_en nvram isn't set\n");
+	}
+
+	return 0;
+}
+
+static int cl_chip_set_all_params_from_buf(struct cl_chip *chip, char *buf, loff_t size)
+{
+	char *line = buf;
+	char name[MAX_PARAM_NAME_LENGTH];
+	char value[STR_LEN_256B];
+	char *begin;
+	char *end;
+	int ret = 0;
+	int name_length = 0;
+	int value_length = 0;
+
+	while (line && strlen(line) && (line != (buf + size))) {
+		if ((*line == '#') || (*line == '\n')) {
+			/* Skip comment or blank line */
+			line = strstr(line, "\n") + 1;
+		} else if (*line) {
+			begin = line;
+			end = strstr(begin, "=");
+
+			if (!end) {
+				ret = -EBADMSG;
+				goto exit;
+			}
+
+			end++;
+			name_length = end - begin;
+			value_length = strstr(end, "\n") - end + 1;
+
+			if (name_length >= MAX_PARAM_NAME_LENGTH) {
+				cl_dbg_chip_err(chip, "Name too long (%u)\n", name_length);
+				ret = -EBADMSG;
+				goto exit;
+			}
+			if (value_length >= STR_LEN_256B) {
+				cl_dbg_chip_err(chip, "Value too long (%u)\n", value_length);
+				ret = -EBADMSG;
+				goto exit;
+			}
+
+			snprintf(name, name_length, "%s", begin);
+			snprintf(value, value_length, "%s", end);
+
+			ret = cl_chip_update_config(chip, name, value);
+			if (ret)
+				goto exit;
+
+			line = strstr(line, "\n") + 1;
+		}
+	}
+
+exit:
+
+	return ret;
+}
+
+int cl_chip_config_read(struct cl_chip *chip)
+{
+	char *buf = NULL;
+	loff_t size = 0;
+	int ret = 0;
+	char filename[CL_FILENAME_MAX] = {0};
+
+	/* Allocate cl_chip_conf */
+	chip->conf = kzalloc(sizeof(*chip->conf), GFP_KERNEL);
+	if (!chip->conf)
+		return -ENOMEM;
+
+	/* Copy default parameters */
+	memcpy(chip->conf, &chip_conf, sizeof(*chip->conf));
+
+	snprintf(filename, sizeof(filename), "cl_chip%u.dat", chip->idx);
+	pr_debug("%s: %s\n", __func__, filename);
+	size = cl_file_open_and_read(chip, filename, &buf);
+
+	if (!buf) {
+		pr_err("read %s failed !!!\n", filename);
+		return -ENODATA;
+	}
+
+	ret = cl_chip_set_all_params_from_buf(chip, buf, size);
+	if (ret) {
+		kfree(buf);
+		return ret;
+	}
+
+	kfree(buf);
+
+	if (!cl_chip_is_enabled(chip)) {
+		cl_dbg_chip_verbose(chip, "Disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	ret = cl_chip_post_configuration(chip);
+
+	return ret;
+}
+
+void cl_chip_config_dealloc(struct cl_chip *chip)
+{
+	kfree(chip->conf);
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 14/96] cl8k: add chip.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (12 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 13/96] cl8k: add chip.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 15/96] cl8k: add config.c viktor.barna
                   ` (81 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/chip.h | 182 ++++++++++++++++++++++++
 1 file changed, 182 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/chip.h

diff --git a/drivers/net/wireless/celeno/cl8k/chip.h b/drivers/net/wireless/celeno/cl8k/chip.h
new file mode 100644
index 000000000000..29d02cb85fb4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/chip.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_CHIP_H
+#define CL_CHIP_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+#include "calib.h"
+#include "sounding.h"
+#include "temperature.h"
+#include "platform.h"
+#include "phy.h"
+#include "ela.h"
+
+/**
+ * DOC: Chip basics
+ *
+ * Each physical device of ours is a separate chip, that is being described by
+ * %cl_chip structure. Each chip may be several (%TCV_MAX) transceivers (bands),
+ * which are operating simultaneously and are described via own %ieee80211_hw
+ * unit (it refers to the private driver via specific pointer, described by
+ * %cl_hw). Totally, 3 types of bands are supported - 2.4G/5.2G/6G. Driver
+ * supports multiple chips (up to %CHIP_MAX). Since the driver can control up
+ * to %TCV_TOTAL entities, it is important to pass it's pointer to each
+ * function, that operates somehow with specific band/transceiver.
+ *
+ * Chip instance is being created during bus probing procedure and is being
+ * destroyed during bus removal procedure.
+ *
+ * Physically, 80xx chips family may have different amount of antennas (4/6/8),
+ * each of which may not be hardly bounded to the specific band (both bands are
+ * sharing them and may change antenna combinations in specific circumstances).
+ *
+ * Each band (transceiver) has own FW, that is being loaded by
+ * request_firmware() call during chip structure initialization procedure. At
+ * lower layer each band is associated with own HW die by LMAC and SMAC names
+ * (e.g: 5.2G and 2.4G). Celeno is using XMAC naming when we are referring to any
+ * of LMAC/SMAC components.
+ */
+
+struct cl_ring_indices {
+	struct cl_ipc_ring_indices *params;
+	dma_addr_t dma_addr;
+	struct dma_pool *pool;
+};
+
+struct cl_chip {
+	u8 idx;
+	bool umac_active;
+	u8 max_antennas;
+	u8 rfic_version;
+	enum cl_bus_type bus_type;
+	struct pci_driver pci_drv;
+	struct pci_dev *pci_dev;
+	void __iomem *pci_bar0_virt_addr;
+	struct cl_irq_stats irq_stats;
+	struct cl_temperature temperature;
+	struct cl_chip_conf *conf;
+	struct device *dev;
+	struct cl_hw *cl_hw_lut[TCV_MAX];
+	struct cl_hw *cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1;
+	u8 cdb_mode_maj;
+	spinlock_t isr_lock;
+	spinlock_t spi_lock;
+	struct mutex start_msg_lock;
+	bool first_start_sent;
+	rwlock_t cl_hw_lock;
+	void (*ipc_host2xmac_trigger_set)(struct cl_chip *chip, u32 value);
+	bool rf_reg_overwrite;
+	struct cl_fem_params fem;
+	struct eeprom *eeprom_cache;
+	size_t eeprom_bin_size;
+	int (*eeprom_read_block)(struct cl_chip *chip, u16 addr, u16 num_of_byte, u8 *data);
+	int (*eeprom_write_block)(struct cl_chip *chip, u16 addr, u16 num_of_byte, u8 *data);
+	struct cl_iq_dcoc_conf iq_dcoc_conf;
+	struct cl_afe_reg orig_afe_reg;
+	struct cl_calib_db calib_db;
+	struct cl_ela_db ela_db;
+	struct cl_ring_indices ring_indices;
+	u8 reg_dbg;
+	struct cl_xmem xmem_db;
+	bool is_calib_eeprom_loaded;
+	struct workqueue_struct *chip_workqueue;
+	struct mutex recovery_mutex;
+	struct mutex calib_runtime_mutex;
+	struct mutex set_idle_mutex;
+	struct cl_platform platform;
+};
+
+struct cl_controller_reg {
+	u32 breset;
+	u32 debug_enable;
+	u32 dreset;
+	u32 ocd_halt_on_reset;
+	u32 run_stall;
+};
+
+struct cl_chip *cl_chip_alloc(u8 idx);
+void cl_chip_dealloc(struct cl_chip *chip);
+int cl_chip_init(struct cl_chip *chip);
+void cl_chip_deinit(struct cl_chip *chip);
+bool cl_chip_is_enabled(struct cl_chip *chip);
+bool cl_chip_is_both_enabled(struct cl_chip *chip);
+bool cl_chip_is_tcv0_enabled(struct cl_chip *chip);
+bool cl_chip_is_tcv1_enabled(struct cl_chip *chip);
+bool cl_chip_is_only_tcv0_enabled(struct cl_chip *chip);
+bool cl_chip_is_only_tcv1_enabled(struct cl_chip *chip);
+void cl_chip_set_hw(struct cl_chip *chip, struct cl_hw *cl_hw);
+void cl_chip_unset_hw(struct cl_chip *chip, struct cl_hw *cl_hw);
+bool cl_chip_is_8ant(struct cl_chip *chip);
+bool cl_chip_is_6ant(struct cl_chip *chip);
+bool cl_chip_is_4ant(struct cl_chip *chip);
+bool cl_chip_is_3ant(struct cl_chip *chip);
+bool cl_chip_is_6g(struct cl_chip *chip);
+u16 cl_chip_get_device_id(struct cl_chip *chip);
+
+#define CC_MAX_LEN 3 /* 2 characters + null */
+#define RM_MAX_LEN 5 /* 4 characters + null */
+#define FW_MAX_NAME 32
+
+struct cl_chip_conf {
+	bool ce_tcv_enabled[TCV_MAX];
+	s8 ce_lmac[FW_MAX_NAME];
+	s8 ce_smac[FW_MAX_NAME];
+	s32 ce_irq_smp_affinity;
+	u8 ce_eeprom_mode;
+	bool ce_production_mode;
+	bool ci_pci_msi_enable;
+	u8 ci_dma_lli_max_chan[TCV_MAX];
+	s8 ci_country_code[CC_MAX_LEN];
+	s8 ci_regdom_mode[RM_MAX_LEN];
+	s8 ce_ela_mode[STR_LEN_64B];
+	u8 ci_phy_dev;
+	s8 ce_debug_level;
+	u8 ce_host_pci_gen_ver;
+	s32 ci_scale_down_fw;
+	bool ce_temp_comp_en;
+	u8 ce_temp_protect_en;
+	s8 ce_temp_protect_delta;
+	s16 ce_temp_protect_th_max;
+	s16 ce_temp_protect_th_min;
+	u16 ce_temp_protect_tx_period_ms;
+	s16 ce_temp_protect_radio_off_th;
+	bool ci_phy_load_bootdrv;
+	u8 ce_phys_mac_addr[ETH_ALEN];
+	bool ce_lam_enable;
+	u8 ce_first_mask_bit;
+	bool ci_no_capture_noise_sleep;
+	bool ci_afe_config_en;
+	u32 ci_afe_vc_ref;
+	u32 ci_afe_vc_avd;
+	u32 ci_afe_vc_cml;
+	u16 ci_afe_eoc_ctrl;
+	u8 ci_afe_ch_cml_sel;
+	u8 ci_afe_cml_sel;
+	bool ci_afe_loopback;
+	bool ci_afe_hw_mode;
+	u8 ci_dcoc_mv_thr[CHNL_BW_MAX];
+	bool ci_calib_check_errors;
+	s8 ci_lolc_db_thr;
+	s8 ci_iq_db_thr;
+	bool ci_rx_resched_tasklet;
+	u32 ci_rx_skb_max;
+	bool ci_tcv1_chains_sx0;
+	u16 ci_sim_device_id;
+	bool ce_calib_runtime_en;
+	bool ci_calib_eeprom_en;
+	bool ci_calib_runtime_force;
+	bool ci_la_mirror_en;
+
+	/* New NVRAM parameters must be added to cl_chip_config_print() */
+};
+
+int cl_chip_config_read(struct cl_chip *chip);
+void cl_chip_config_dealloc(struct cl_chip *chip);
+
+#endif /* CL_CHIP_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 15/96] cl8k: add config.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (13 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 14/96] cl8k: add chip.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
                   ` (80 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/config.c | 46 +++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/config.c

diff --git a/drivers/net/wireless/celeno/cl8k/config.c b/drivers/net/wireless/celeno/cl8k/config.c
new file mode 100644
index 000000000000..dbf94060bfa4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/config.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "debug.h"
+#include "config.h"
+
+static char *non_driver_conf_params[] = {
+	"ws_",
+	"ha_",
+	"uuid1",
+	"ce_pci_id",
+	"ce_rst_gpio",
+	"ce_iface_eth",
+	"ce_iface_vlan",
+	"ce_iface_ip",
+	"ci_sim_chip_num",
+	"ci_lcu_dump_folder",
+	"ci_server_addr",
+	"ci_server_user",
+	"ci_pci_tune_en",
+	"ce_uapsd_en",
+	"ce_channel_bandwidth",
+	"ce_ht_rxldpc_en",
+	"ce_vht_rxldpc_en",
+	"ce_he_rxldpc_en",
+	"ce_bf_en",
+	"ce_bss_num",
+	"ce_iface_type",
+	"ce_mu_mimo_state",
+	"ce_wireless_mode",
+	"ce_extension_channel",
+	NULL
+};
+
+bool cl_config_is_non_driver_param(char *name)
+{
+	int i = 0;
+
+	for (i = 0; non_driver_conf_params[i]; i++)
+		if (!strncmp(name, non_driver_conf_params[i], strlen(non_driver_conf_params[i])))
+			return true;
+
+	return false;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 16/96] cl8k: add config.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (14 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 15/96] cl8k: add config.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-25 18:31   ` Jeff Johnson
  2022-05-24 11:33 ` [RFC v2 17/96] cl8k: add debug.c viktor.barna
                   ` (79 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/config.h | 405 ++++++++++++++++++++++
 1 file changed, 405 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/config.h

diff --git a/drivers/net/wireless/celeno/cl8k/config.h b/drivers/net/wireless/celeno/cl8k/config.h
new file mode 100644
index 000000000000..b918e4423efe
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/config.h
@@ -0,0 +1,405 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_CONFIG_H
+#define CL_CONFIG_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/dcache.h>
+
+#define MAX_PARAM_NAME_LENGTH 64
+
+#define PRINT_UNSIGNED_ARR(param, old_val, size, new_val) \
+do { \
+	u8 i; \
+	char buf[STR_LEN_256B]; \
+	int len = 0; \
+	len += snprintf(buf, sizeof(buf), "%s: old value ", #param); \
+	for (i = 0; i < (size) - 1; i++) \
+		len += snprintf(buf + len, sizeof(buf) - len, \
+				"%u,", old_val[i]); \
+	len += snprintf(buf + len, sizeof(buf) - len, \
+			"%u --> new value %s\n", old_val[(size) - 1], new_val); \
+	pr_debug("%s", buf); \
+} while (0)
+
+#define READ_BOOL(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		bool new_val = false; \
+		ret = kstrtobool(value, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %u -> new value %u\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_U8(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 new_val = 0; \
+		ret = kstrtou8(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %u -> new value %u\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_U16(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u16 new_val = 0; \
+		ret = kstrtou16(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %u -> new value %u\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_U32(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u32 new_val = 0; \
+		ret = kstrtou32(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %u -> new value %u\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_S8(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		s8 new_val = 0; \
+		ret = kstrtos8(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %d -> new value %d\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_S16(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		s16 new_val = 0; \
+		ret = kstrtos16(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %d -> new value %d\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_S32(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		s32 new_val = 0; \
+		ret = kstrtos32(value, 0, &new_val); \
+		if (ret) { \
+			pr_err("%s: invalid value [%s]\n", #param, value); \
+			break; \
+		} \
+		if (conf->param != new_val) { \
+			pr_debug("%s: old value %d -> new value %d\n", \
+				 #param, conf->param, new_val); \
+			conf->param = new_val; \
+		} \
+		break; \
+	} \
+}
+
+#define READ_BOOL_ARR(param, size) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 i = 0; \
+		char *buf = NULL; \
+		char vector[STR_LEN_256B] = {0}; \
+		char *vector_p = &vector[i]; \
+		bool old_val[size] = {false}; \
+		memcpy(old_val, conf->param, sizeof(old_val)); \
+		if (strlen(value) >= sizeof(vector)) { \
+			pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+			ret = -E2BIG; \
+			break; \
+		} \
+		strscpy(vector_p, value, sizeof(vector)); \
+		buf = strsep(&vector_p, ","); \
+		if (!buf) { \
+			pr_err("%s: delimiter ',' not found\n", #param); \
+			ret = -EIO; \
+			break; \
+		} \
+		if (kstrtobool(buf, &conf->param[0]) != 0) { \
+			pr_err("%s: invalid argument [%s]\n", #param, value); \
+			ret = -EINVAL; \
+			break; \
+		} \
+		for (i = 1; i < (size); i++) { \
+			buf = strsep(&vector_p, ","); \
+			if (!buf) \
+				break; \
+			if (kstrtobool(buf, &conf->param[i]) != 0) { \
+				pr_err("%s: invalid argument [%s]\n", #param, value); \
+				break; \
+			} \
+		} \
+		if (i < size) { \
+			pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+			ret = -ENODATA; \
+			break; \
+		} \
+		ret = 0; \
+		if (memcmp(old_val, conf->param, sizeof(old_val))) \
+			PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+		break; \
+	} \
+}
+
+#define READ_U8_ARR(param, size, is_array_fix_size) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 i = 0; \
+		char *buf = NULL; \
+		char vector[STR_LEN_256B] = {0}; \
+		char *vector_p = &vector[0]; \
+		u8 old_val[size] = {false}; \
+		memcpy(old_val, conf->param, sizeof(old_val)); \
+		if (strlen(value) >= sizeof(vector)) { \
+			pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+			ret = -E2BIG; \
+			break; \
+		} \
+		strscpy(vector_p, value, sizeof(vector)); \
+		buf = strsep(&vector_p, ","); \
+		if (!buf) { \
+			pr_err("%s: delimiter ',' not found\n", #param); \
+			ret = -EIO; \
+			break; \
+		} \
+		if (kstrtou8(buf, 0, &conf->param[0]) != 0) { \
+			pr_err("%s: invalid argument [%s]\n", #param, value); \
+			ret = -EINVAL; \
+			break; \
+		} \
+		for (i = 1; i < (size); i++) { \
+			buf = strsep(&vector_p, ","); \
+			if (!buf) \
+				break; \
+			if (kstrtou8(buf, 0, &conf->param[i]) != 0) { \
+				pr_err("%s: invalid argument [%s]\n", #param, value); \
+				break; \
+			} \
+		} \
+		if ((is_array_fix_size) && i < (size)) { \
+			pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+			ret = -ENODATA; \
+			break; \
+		} \
+		ret = 0; \
+		if (memcmp(old_val, conf->param, sizeof(old_val))) \
+			PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+		break; \
+	} \
+}
+
+#define READ_U16_ARR(param, size, is_array_fix_size) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 i = 0; \
+		char *buf = NULL; \
+		char vector[STR_LEN_256B] = {0}; \
+		char *vector_p = &vector[0]; \
+		u16 old_val[size] = {false}; \
+		memcpy(old_val, conf->param, sizeof(old_val)); \
+		if (strlen(value) >= sizeof(vector)) { \
+			pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+			ret = -E2BIG; \
+			break; \
+		} \
+		strscpy(vector_p, value, sizeof(vector)); \
+		buf = strsep(&vector_p, ","); \
+		if (!buf) { \
+			pr_err("%s: delimiter ',' not found\n", #param); \
+			ret = -EIO; \
+			break; \
+		} \
+		if (kstrtou16(buf, 0, &conf->param[0]) != 0) { \
+			pr_err("%s: invalid argument [%s]\n", #param, value); \
+			ret = -EINVAL; \
+			break; \
+		} \
+		for (i = 1; i < (size); i++) { \
+			buf = strsep(&vector_p, ","); \
+			if (!buf) \
+				break; \
+			if (kstrtou16(buf, 0, &conf->param[i]) != 0) { \
+				pr_err("%s: invalid argument [%s]\n", #param, value); \
+				break; \
+			} \
+		} \
+		if ((is_array_fix_size) && i < (size)) { \
+			pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+			ret = -ENODATA; \
+			break; \
+		} \
+		ret = 0; \
+		if (memcmp(old_val, conf->param, sizeof(old_val))) \
+			PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+		break; \
+	} \
+}
+
+#define READ_S8_ARR(param, size) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 i = 0; \
+		char *buf = NULL; \
+		char vector[STR_LEN_256B] = {0}; \
+		char *vector_p = &vector[0]; \
+		s8 old_val[size] = {false}; \
+		memcpy(old_val, conf->param, sizeof(old_val)); \
+		if (strlen(value) >= sizeof(vector)) { \
+			pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+			ret = -E2BIG; \
+			break; \
+		} \
+		strscpy(vector_p, value, sizeof(vector)); \
+		buf = strsep(&vector_p, ","); \
+		if (!buf) { \
+			pr_err("%s: delimiter ',' not found\n", #param); \
+			ret = -EIO; \
+			break; \
+		} \
+		if (kstrtos8(buf, 0, &conf->param[0]) != 0) { \
+			pr_err("%s: invalid argument [%s]\n", #param, value); \
+			ret = -EINVAL; \
+			break; \
+		} \
+		for (i = 1; i < (size); i++) { \
+			buf = strsep(&vector_p, ","); \
+			if (!buf) \
+				break; \
+			if (kstrtos8(buf, 0, &conf->param[i]) != 0) { \
+				pr_err("%s: invalid argument [%s]\n", #param, value); \
+				break; \
+			} \
+		} \
+		if (i < (size)) { \
+			pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, size); \
+			ret = -ENODATA; \
+			break; \
+		} \
+		ret = 0; \
+		if (memcmp(old_val, conf->param, sizeof(old_val))) \
+			PRINT_UNSIGNED_ARR(param, old_val, size, value); \
+		break; \
+	} \
+}
+
+#define READ_STR(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		if (strcmp(value, conf->param)) { \
+			pr_debug("%s: old value %s -> new value %s\n", \
+				 #param, conf->param, value); \
+			strncpy(conf->param, value, sizeof(conf->param) - 1); \
+		} \
+		ret = 0; \
+		break; \
+	} \
+}
+
+#define READ_MAC(param) \
+{ \
+	if (!strcmp(name, #param)) { \
+		u8 i = 0; \
+		char *buf = NULL; \
+		char vector[STR_LEN_32B] = {0}; \
+		char *vector_p = &vector[0]; \
+		u8 old_val[ETH_ALEN] = {false}; \
+		memcpy(old_val, conf->param, ETH_ALEN); \
+		if (strlen(value) >= sizeof(vector)) { \
+			pr_err("%s: value [%s] too big [%zu]\n", #param, value, strlen(value)); \
+			ret = -E2BIG; \
+			break; \
+		} \
+		strscpy(vector_p, value, sizeof(vector)); \
+		buf = strsep(&vector_p, ":"); \
+		if (!buf) { \
+			pr_err("%s: delimiter ':' not found\n", #param); \
+			ret = -EIO; \
+			break; \
+		} \
+		if (kstrtou8(buf, 16, &conf->param[0]) != 0) { \
+			pr_err("%s: invalid argument [%s]\n", #param, value); \
+			ret = -EINVAL; \
+			break; \
+		} \
+		for (i = 1; i < ETH_ALEN; i++) { \
+			buf = strsep(&vector_p, ":"); \
+			if (!buf) \
+				break; \
+			if (kstrtou8(buf, 16, &conf->param[i]) != 0) { \
+				pr_err("%s: invalid argument [%s]\n", #param, value); \
+				break; \
+			} \
+		} \
+		if (i < ETH_ALEN) { \
+			pr_err("%s: value [%s] doesn't have %u elements\n", #param, value, \
+			       ETH_ALEN); \
+			ret = -ENODATA; \
+			break; \
+		} \
+		ret = 0; \
+		if (memcmp(old_val, conf->param, sizeof(old_val))) \
+			pr_debug("%s: old value %pM -> new value %pM\n", \
+				 #param, old_val, conf->param); \
+		break; \
+	} \
+}
+
+bool cl_config_is_non_driver_param(char *name);
+
+#endif /* CL_CONFIG_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 17/96] cl8k: add debug.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (15 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 18/96] cl8k: add debug.h viktor.barna
                   ` (78 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/debug.c | 442 +++++++++++++++++++++++
 1 file changed, 442 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/debug.c

diff --git a/drivers/net/wireless/celeno/cl8k/debug.c b/drivers/net/wireless/celeno/cl8k/debug.c
new file mode 100644
index 000000000000..f8a438747ac3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debug.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+
+#include "chip.h"
+#include "hw.h"
+#include "utils.h"
+#include "debug.h"
+
+const char *cl_dbgfile_get_msg_txt(struct cl_dbg_data *dbg_data, u16 file_id, u16 line)
+{
+	/* Get the message text from the .dbg file by file_id & line number */
+	int remaining_bytes = dbg_data->size;
+	const char *str = dbg_data->str;
+	char id_str[32];
+	int idstr_len;
+
+	if (!str || 0 == remaining_bytes)
+		return NULL;
+
+	idstr_len = snprintf(id_str, sizeof(id_str), "%u:%u:", file_id, line);
+
+	/* Skip hash */
+	while (*str++ != '\n')
+		;
+
+	remaining_bytes -= (str - (char *)dbg_data->str);
+
+	while (remaining_bytes > 0) {
+		if (strncmp(id_str, str, idstr_len) == 0) {
+			str += idstr_len;
+			while (*str == ' ')
+				++str;
+			return (const char *)str;
+		}
+
+		str += strnlen(str, 512) + 1;
+		remaining_bytes = dbg_data->size - (str - (char *)dbg_data->str);
+	}
+
+	/* No match found */
+	pr_err("error: file_id=%d line=%d not found in debug print file\n", file_id, line);
+	return NULL;
+}
+
+void cl_dbgfile_parse(struct cl_hw *cl_hw, void *edata, u32 esize)
+{
+	/* Parse & store the firmware debug file */
+	struct cl_dbg_data *dbg_data = &cl_hw->dbg_data;
+
+	dbg_data->size = esize;
+	dbg_data->str = edata;
+}
+
+void cl_dbgfile_release_mem(struct cl_dbg_data *dbg_data,
+			    struct cl_str_offload_env *str_offload_env)
+{
+	dbg_data->str = NULL;
+
+	str_offload_env->enabled = false;
+	str_offload_env->block1 = NULL;
+	str_offload_env->block2 = NULL;
+}
+
+/*
+ * Store debug print offload data
+ * - part 1: offloaded block that does not exist on target
+ * - part 2: resident block that remains on target [optional]
+ */
+int cl_dbgfile_store_offload_data(struct cl_chip *chip, struct cl_hw *cl_hw,
+				  void *data1, u32 size1, u32 base1,
+				  void *data2, u32 size2, u32 base2,
+				  void *data3, u32 size3, u32 base3)
+{
+	u32 u = size1;
+	struct cl_str_offload_env *str_offload_env = &cl_hw->str_offload_env;
+
+	if (u > 200000)
+		goto err_too_big;
+
+	/* TODO we modify offload data! if caller checks integrity, make a copy? */
+	str_offload_env->block1 = data1;
+	str_offload_env->size1 = size1;
+	str_offload_env->base1 = base1;
+
+	str_offload_env->block2 = data2;
+	str_offload_env->size2 = size2;
+	str_offload_env->base2 = base2;
+
+	str_offload_env->block3 = data3;
+	str_offload_env->size3 = size3;
+	str_offload_env->base3 = base3;
+
+	str_offload_env->enabled = true;
+
+	cl_dbg_info(cl_hw, "%cmac%u: FW prints offload memory use = %uK\n",
+		    cl_hw->fw_prefix, chip->idx, (size1 + size2 + 1023) / 1024);
+
+	return 0;
+
+err_too_big:
+	pr_err("%s: size too big: %u\n", __func__, u);
+	return 1;
+}
+
+static void cl_fw_do_print_n(struct cl_hw *cl_hw, const char *str, int n)
+{
+	/* Print formatted string with "band" prefix */
+	if (n < 0 || n > 256) {
+		cl_dbg_err(cl_hw, "%cmac%u: *** FW PRINT - BAD SIZE: %d\n",
+			   cl_hw->fw_prefix, cl_hw->chip->idx, n);
+		return;
+	}
+
+	cl_dbg_verbose(cl_hw, "%cmac%u: %.*s\n", cl_hw->fw_prefix, cl_hw->chip->idx, n, str);
+}
+
+static void cl_fw_do_hex_dump_bytes(struct cl_hw *cl_hw, u32 addr, void *data, u32 count)
+{
+	cl_dbg_verbose(cl_hw, "%cmac%u: hex dump:\n", cl_hw->fw_prefix, cl_hw->chip->idx);
+	cl_hex_dump(NULL, data, count, addr, true);
+}
+
+#define MAGIC_PRINT_OFFLOAD   0xFA  /* 1st (low) byte of signature */
+/* 2nd signature byte */
+#define MAGIC_PRINT_OFF_XDUMP 0xD0  /* Hex dump, by bytes */
+#define MAGIC_PRINT_OFF_LIT   0x01  /* Literal/preformatted string */
+#define MAGIC_PRINT_OFF_PRINT 0x02  /* Print with 'virtual' format string */
+
+static int cl_fw_offload_print(struct cl_str_offload_env *str_offload_env,
+			       char *fmt, const char *params)
+{
+	static char buf[1024] = {0};
+	const char *cur_prm = params;
+	char tmp;
+	char *fmt_end = fmt;
+	size_t size = sizeof(int);
+	int len = 0;
+
+	union v {
+		u32 val32;
+		u64 val64;
+		ptrdiff_t str;
+	} v;
+
+	while ((fmt_end = strchr(fmt_end, '%'))) {
+		fmt_end++;
+
+		/* Skip '%%'. */
+		if (*fmt_end == '%') {
+			fmt_end++;
+			continue;
+		}
+
+		/* Skip flags. */
+		while (strchr("-+ 0#", *fmt_end))
+			fmt_end++;
+
+		/* Skip width. */
+		while (isdigit(*fmt_end))
+			fmt_end++;
+
+		/* Skip precision. */
+		if (*fmt_end == '.') {
+			while (*fmt_end == '-' || *fmt_end == '+')
+				fmt_end++;
+
+			while (isdigit(*fmt_end))
+				fmt_end++;
+		}
+
+		/* Get size. */
+		if (*fmt_end == 'z') {
+			/* Remove 'z' from %zu, %zd, %zx and %zX,
+			 * because sizeof(size_t) == 4 in the firmware.
+			 * 'z' can only appear in front of 'd', 'u', 'x' or 'X'.
+			 */
+			if (!strchr("duxX", *(fmt_end + 1)))
+				return -1;
+
+			fmt_end++;
+			size = 4;
+		} else if (*fmt_end == 'l') {
+			fmt_end++;
+
+			if (*fmt_end == 'l') {
+				fmt_end++;
+				size = sizeof(long long);
+			} else {
+				size = sizeof(long);
+			}
+
+			if (*fmt_end == 'p') /* %p can't get 'l' or 'll' modifiers. */
+				return -1;
+		} else {
+			size = 4;
+		}
+
+		/* Get parameter. */
+		switch (*fmt_end) {
+		case 'p': /* Replace %p with %x, because the firmware's pointers are 32 bit wide */
+			*fmt_end = 'x';
+			fallthrough;
+		case 'd':
+		case 'u':
+		case 'x':
+		case 'X':
+			if (size == 4)
+				v.val32 = __le32_to_cpu(*(__le32 *)cur_prm);
+			else
+				v.val64 = __le64_to_cpu(*(__le64 *)cur_prm);
+			cur_prm += size;
+			break;
+		case 's':
+			v.str = __le32_to_cpu(*(__le32 *)cur_prm);
+			cur_prm += 4;
+			size = sizeof(ptrdiff_t);
+
+			if (v.str >= str_offload_env->base3 &&
+			    v.str < str_offload_env->base3 + str_offload_env->size3) {
+				v.str -= str_offload_env->base3;
+				v.str += (ptrdiff_t)str_offload_env->block3;
+			} else if (v.str >= str_offload_env->base2 &&
+				   v.str < str_offload_env->base2 + str_offload_env->size2) {
+				v.str -= str_offload_env->base2;
+				v.str += (ptrdiff_t)str_offload_env->block2;
+			} else {
+				return -1;
+			}
+
+			break;
+		default:
+			return -1;
+		}
+
+		/* Print into buffer. */
+		fmt_end++;
+		tmp = *fmt_end; /* Truncate the format to the current point and then restore. */
+		*fmt_end = 0;
+		len += snprintf(buf + len, sizeof(buf) - len, fmt, size == 4 ? v.val32 : v.val64);
+		*fmt_end = tmp;
+		fmt = fmt_end;
+	}
+
+	snprintf(buf + len, sizeof(buf) - len, "%s", fmt);
+
+	pr_debug("%s", buf);
+
+	return 0;
+}
+
+struct cl_pr_off_desc {
+	u8 file_id;
+	u8 flag;
+	__le16 line_num;
+	char fmt[];
+};
+
+char *cl_fw_print_normalize(char *s, char old, char new)
+{
+	for (; *s; ++s)
+		if (*s == old)
+			*s = new;
+	return s;
+}
+
+static int cl_fw_do_dprint(struct cl_hw *cl_hw, u32 fmtaddr, u32 nparams, u32 *params)
+{
+	/*
+	 * fmtaddr - virtual address of format descriptor in firmware,
+	 *           must be in the offloaded segment
+	 * nparams - size of parameters array in u32; min=0, max=MAX_PRINT_OFF_PARAMS
+	 * params  - array of parameters[nparams]
+	 */
+	struct cl_str_offload_env *str_offload_env = &cl_hw->str_offload_env;
+	struct cl_pr_off_desc *pfmt = NULL;
+
+	if (!str_offload_env->enabled)
+		return -1;
+
+	if (fmtaddr & 0x3)
+		cl_dbg_warn(cl_hw, "FW PRINT - format not aligned on 4? %8.8X\n", fmtaddr);
+
+	if (fmtaddr > str_offload_env->base1 &&
+	    fmtaddr < (str_offload_env->base1 + str_offload_env->size1)) {
+		pfmt = (void *)((fmtaddr - str_offload_env->base1) + str_offload_env->block1);
+	} else {
+		cl_dbg_err(cl_hw, "FW PRINT - format not in allowed area %8.8X\n", fmtaddr);
+		return -1;
+	}
+
+	/*
+	 * Current string sent by firmware is #mac@ where # is '253' and @ is '254'
+	 * Replace '253' with 'l' or 's' according to the fw_prefix.
+	 * Replace '254' with '0' or '1' according to chip index.
+	 */
+	cl_fw_print_normalize(pfmt->fmt, (char)253, cl_hw->fw_prefix);
+	cl_fw_print_normalize(pfmt->fmt, (char)254, (cl_hw->chip->idx == CHIP0) ? '0' : '1');
+
+	if (cl_fw_offload_print(str_offload_env, pfmt->fmt, (char *)params) < 0) {
+		cl_dbg_err(cl_hw, "FW PRINT - ERROR in format! (file %u:%u)\n",
+			   pfmt->file_id, pfmt->line_num);
+		cl_hex_dump(NULL, (void *)pfmt, 48, fmtaddr, true); /* $$$ dbg dump the struct */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cl_fw_do_offload(struct cl_hw *cl_hw, u8 *data, int bytes_remaining)
+{
+	u8 magic2 = data[1];
+	u32 nb = data[2] + (data[3] << 8); /* Following size in bytes */
+	/* DATA IS UNALIGNED! REVISE if alignment required or BIG ENDIAN! */
+	__le32 *dp = (__le32 *)data;
+	int bytes_consumed = 4; /* 1 + 1 + 2 */
+
+	/* Data: [0] u8 magic1, u8 magic2, u16 following size in bytes */
+	if (bytes_remaining < 8) {
+		cl_dbg_err(cl_hw, "*** FW PRINT - OFFLOAD PACKET TOO SHORT: %d\n",
+			   bytes_remaining);
+		return bytes_remaining;
+	}
+
+	if (bytes_remaining < (nb + bytes_consumed)) {
+		cl_dbg_err(cl_hw, "*** FW PRINT - OFFLOAD PACKET %u > remainder %d??\n",
+			   nb, bytes_remaining);
+		return bytes_remaining;
+	}
+
+	switch (magic2) {
+	case MAGIC_PRINT_OFF_PRINT: {
+		/*
+		 * [1] u32 format descriptor ptr
+		 * [2] u32[] parameters
+		 */
+		u32 fmtp = le32_to_cpu(dp[1]);
+		u32 np = (nb - 4) / 4; /* Number of printf parameters */
+
+		if (nb < 4 || nb & 3)  {
+			cl_dbg_err(cl_hw, "*** FW PRINT - bad pkt size: %u\n", nb);
+			goto err;
+		}
+
+		cl_fw_do_dprint(cl_hw, fmtp, np, (u32 *)&dp[2]);
+
+		bytes_consumed += nb; /* Already padded to 4 bytes */
+		}
+		break;
+
+	case MAGIC_PRINT_OFF_LIT: {
+		/* [1] Remaining bytes: literal string */
+		cl_fw_do_print_n(cl_hw, (char *)&dp[1], nb);
+		bytes_consumed += ((nb + 3) / 4) * 4; /* Padding to 4 bytes */
+		}
+		break;
+
+	case MAGIC_PRINT_OFF_XDUMP:
+		/* [1] bytes[nb] */
+		if (nb >= 1)
+			cl_fw_do_hex_dump_bytes(cl_hw, 0, &dp[1], nb);
+
+		bytes_consumed += ((nb + 3) / 4) * 4; /* Padding to 4 bytes */
+		break;
+
+	default:
+		cl_dbg_err(cl_hw, "*** FW PRINT - BAD TYPE: %4.4X\n", magic2);
+		goto err;
+	}
+
+	return bytes_consumed;
+
+err:
+	return bytes_remaining; /* Skip all */
+}
+
+void cl_dbgfile_print_fw_str(struct cl_hw *cl_hw, u8 *str, int max_size)
+{
+	/* Handler for firmware debug prints */
+	int bytes_remaining = max_size;
+	int i;
+	u8 delim = 0;
+
+	while (bytes_remaining > 0) {
+		/* Scan for normal print data: */
+		for (i = 0; i < bytes_remaining; i++) {
+			if (str[i] < ' ' || str[i] >= 0x7F) {
+				if (str[i] == '\t')
+					continue;
+				delim = str[i];
+				break;
+			}
+		}
+
+		if (i > 0) {
+			if (delim == '\n') {
+				bytes_remaining -= i + 1;
+				cl_fw_do_print_n(cl_hw, str, i);
+				str += i + 1;
+				continue;
+			}
+
+			if (delim != MAGIC_PRINT_OFFLOAD) {
+				cl_fw_do_print_n(cl_hw, str, i);
+				bytes_remaining -= i;
+				return; /* Better stop parsing this */
+			}
+			/* Found offload packet but previous string not terminated: */
+			cl_fw_do_print_n(cl_hw, str, i);
+			cl_dbg_err(cl_hw, "*** FW PRINT - NO LINE END2\n");
+			bytes_remaining -= i;
+			str += i;
+			continue;
+		}
+
+		/* Delimiter at offset 0 */
+		switch (delim) {
+		case '\n':
+			cl_fw_do_print_n(cl_hw, " ", 1); /* Print empty line */
+			str++;
+			bytes_remaining--;
+			continue;
+		case 0:
+			return;
+		case MAGIC_PRINT_OFFLOAD:
+			i = cl_fw_do_offload(cl_hw, str, bytes_remaining);
+			bytes_remaining -= i;
+			str += i;
+			break;
+		default:
+			cl_dbg_err(cl_hw, "*** FW PRINT - BAD BYTE=%2.2X ! rem=%d\n",
+				   delim, bytes_remaining);
+			return; /* Better stop parsing this */
+		}
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 18/96] cl8k: add debug.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (16 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 17/96] cl8k: add debug.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
                   ` (77 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/debug.h | 160 +++++++++++++++++++++++
 1 file changed, 160 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/debug.h

diff --git a/drivers/net/wireless/celeno/cl8k/debug.h b/drivers/net/wireless/celeno/cl8k/debug.h
new file mode 100644
index 000000000000..dffee2125903
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/debug.h
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_DEBUG_H
+#define CL_DEBUG_H
+
+#include <linux/string.h>
+
+enum cl_dbg_level {
+	DBG_LVL_VERBOSE,
+	DBG_LVL_ERROR,
+	DBG_LVL_WARNING,
+	DBG_LVL_TRACE,
+	DBG_LVL_INFO,
+
+	DBG_LVL_MAX,
+};
+
+#define CL_DBG(cl_hw, lvl, fmt, ...) \
+do { \
+	if ((lvl) <= (cl_hw)->conf->ce_debug_level) \
+		pr_debug("[tcv%u][%s][%d] " fmt, (cl_hw)->idx, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define CL_DBG_CHIP(chip, lvl, fmt, ...) \
+do { \
+	if ((lvl) <= (chip)->conf->ce_debug_level) \
+		pr_debug("[chip%u][%s][%d] " fmt, (chip)->idx, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define cl_dbg_verbose(cl_hw, ...) CL_DBG((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define cl_dbg_err(cl_hw, ...)     CL_DBG((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define cl_dbg_warn(cl_hw, ...)    CL_DBG((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define cl_dbg_trace(cl_hw, ...)   CL_DBG((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define cl_dbg_info(cl_hw, ...)    CL_DBG((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define cl_dbg_chip_verbose(chip, ...) CL_DBG_CHIP((chip), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define cl_dbg_chip_err(chip, ...)     CL_DBG_CHIP((chip), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define cl_dbg_chip_warn(chip, ...)    CL_DBG_CHIP((chip), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define cl_dbg_chip_trace(chip, ...)   CL_DBG_CHIP((chip), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define cl_dbg_chip_info(chip, ...)    CL_DBG_CHIP((chip), DBG_LVL_INFO, ##__VA_ARGS__)
+
+static inline char *cl_code_basename(const char *filename)
+{
+	char *p = strrchr(filename, '/');
+
+	return p ? p + 1 : (char *)filename;
+}
+
+#define TXT_ERROR \
+	do { \
+		pr_debug("\n"); \
+		pr_debug("#######  #####    #####     #####   #####\n"); \
+		pr_debug("#        #    #   #    #   #     #  #    #\n"); \
+		pr_debug("#        #    #   #    #   #     #  #    #\n"); \
+		pr_debug("#######  #####    #####    #     #  #####\n"); \
+		pr_debug("#        #    #   #    #   #     #  #    #\n"); \
+		pr_debug("#        #     #  #     #  #     #  #     #\n"); \
+		pr_debug("#######  #     #  #     #   #####   #     #\n"); \
+	} while (0)
+
+#define TXT_WARNING \
+	do { \
+		pr_debug("\n"); \
+		pr_debug("#       #   #####   #####    #     #  ###  #     #   #####\n"); \
+		pr_debug("#       #  #     #  #    #   ##    #   #   ##    #  #     #\n"); \
+		pr_debug("#       #  #     #  #    #   # #   #   #   # #   #  #\n"); \
+		pr_debug("#   #   #  #######  #####    #  #  #   #   #  #  #  #    ###\n"); \
+		pr_debug("#  # #  #  #     #  #    #   #   # #   #   #   # #  #     #\n"); \
+		pr_debug("# #   # #  #     #  #     #  #    ##   #   #    ##  #     #\n"); \
+		pr_debug(" #     #   #     #  #     #  #     #  ###  #     #   #####\n"); \
+	} while (0)
+
+#define INFO_CL_HW(cl_hw, ...) \
+	do { \
+		pr_debug("\n"); \
+		pr_debug("CHIP:        %u\n", (cl_hw)->chip->idx); \
+		pr_debug("TCV:         %u\n", (cl_hw)->idx); \
+		pr_debug("FILE:        %s\n", cl_code_basename(__FILE__)); \
+		pr_debug("FUNCTION:    %s\n", __func__); \
+		pr_debug("LINE:        %u\n", __LINE__); \
+		pr_debug("DESCRIPTION: " __VA_ARGS__); \
+		pr_debug("\n"); \
+	} while (0)
+
+#define INFO_CHIP(chip, ...) \
+	do { \
+		pr_debug("\n"); \
+		pr_debug("CHIP:        %u\n", (chip)->idx); \
+		pr_debug("FILE:        %s\n", cl_code_basename(__FILE__)); \
+		pr_debug("FUNCTION:    %s\n", __func__); \
+		pr_debug("LINE:        %u\n", __LINE__); \
+		pr_debug("DESCRIPTION: " __VA_ARGS__); \
+		pr_debug("\n"); \
+	} while (0)
+
+#define CL_DBG_ERROR(cl_hw, ...) \
+	do { \
+		TXT_ERROR; \
+		INFO_CL_HW(cl_hw, __VA_ARGS__); \
+	} while (0)
+
+#define CL_DBG_ERROR_CHIP(chip, ...) \
+	do { \
+		TXT_ERROR; \
+		INFO_CHIP(chip, __VA_ARGS__); \
+	} while (0)
+
+#define CL_DBG_WARNING(cl_hw, ...) \
+	do { \
+		TXT_WARNING; \
+		INFO_CL_HW(cl_hw, __VA_ARGS__); \
+	} while (0)
+
+#define CL_DBG_WARNING_CHIP(chip, ...) \
+	do { \
+		TXT_WARNING; \
+		INFO_CHIP(chip, __VA_ARGS__); \
+	} while (0)
+
+/* Min HW assert before testing asserts time-stamp */
+#define CL_MIN_ASSERT_CNT 10
+
+/* Define max time between hw asserts in msec */
+#define CL_HW_ASSERT_TIME_MAX 5000
+
+struct cl_dbg_data {
+	char *str; /* Pointer to debug strings start address */
+	int size; /* Size of debug strings pool */
+};
+
+/* String offloading to minimize FW size */
+struct cl_str_offload_env {
+	char *block1;
+	u32 size1;
+	u32 base1;
+	char *block2;
+	u32 size2;
+	u32 base2;
+	char *block3;
+	u32 size3;
+	u32 base3;
+	bool enabled;
+	char buf[512];
+};
+
+struct cl_hw;
+struct cl_chip;
+
+void cl_dbgfile_parse(struct cl_hw *cl_hw, void *edata, u32 esize);
+void cl_dbgfile_release_mem(struct cl_dbg_data *dbg_data,
+			    struct cl_str_offload_env *str_offload_env);
+void cl_dbgfile_print_fw_str(struct cl_hw *cl_hw, u8 *str, int max_size);
+int cl_dbgfile_store_offload_data(struct cl_chip *chip, struct cl_hw *cl_hw,
+				  void *data1, u32 size1, u32 base1,
+				  void *data2, u32 size2, u32 base2,
+				  void *data3, u32 size3, u32 base3);
+const char *cl_dbgfile_get_msg_txt(struct cl_dbg_data *dbg_data, u16 file_id, u16 line);
+
+#endif /* CL_DEBUG_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 19/96] cl8k: add def.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (17 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 18/96] cl8k: add debug.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-25 18:39   ` Jeff Johnson
  2022-05-24 11:33 ` [RFC v2 20/96] cl8k: add dfs.c viktor.barna
                   ` (76 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/def.h | 235 +++++++++++++++++++++++++
 1 file changed, 235 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/def.h

diff --git a/drivers/net/wireless/celeno/cl8k/def.h b/drivers/net/wireless/celeno/cl8k/def.h
new file mode 100644
index 000000000000..24613836d263
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/def.h
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_DEF_H
+#define CL_DEF_H
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#ifndef CONFIG_CL8K_VERSION
+#define CONFIG_CL8K_VERSION "8.0.0.0.0.0"
+#endif /* CONFIG_CL8K_VERSION */
+
+#define ASSERT_ERR(condition) \
+	do { \
+		if (unlikely(!(condition))) \
+			cl_dbg_err(cl_hw, ":ASSERT_ERR(" #condition ")\n"); \
+	} while (0)
+
+#define ASSERT_ERR_CHIP(condition) \
+	do { \
+		if (unlikely(!(condition))) \
+			cl_dbg_chip_err(chip, ":ASSERT_ERR(" #condition ")\n"); \
+	} while (0)
+
+#define msecs_round(ms) jiffies_to_msecs(msecs_to_jiffies(ms))
+
+/* Each chip supports two TCVs */
+#define TCV0            0
+#define TCV1            1
+#define TCV_MAX         2
+
+#define CHIP0    0
+#define CHIP1    1
+#define CHIP_MAX 2
+
+#define TCV_TOTAL (CHIP_MAX * TCV_MAX)
+
+enum cl_fw_band {
+	FW_BAND_2GHZ,
+	FW_BAND_5GHZ,
+	FW_BAND_6GHZ,
+
+	FW_BAND_MAX,
+};
+
+#define BAND_6G  6
+#define BAND_5G  5
+#define BAND_24G 24
+
+#define CL_VENDOR_ID 0x1d69
+
+#define CPU_MAX_NUM 8
+
+/* We support 128 stations and last station is assigned for high priority */
+#define CL_MAX_NUM_STA 128
+#define FW_MAX_NUM_STA (CL_MAX_NUM_STA + 1)
+
+#define MAX_SINGLE_QUEUES   (AC_MAX * FW_MAX_NUM_STA)
+#define HIGH_PRIORITY_QUEUE (MAX_SINGLE_QUEUES - 1)
+
+/* Must be aligned to NX_VIRT_DEV_MAX definition in rwnx_config.h */
+#define MAX_BSS_NUM 8
+#define BSS_INVALID_IDX 0xFF
+
+#define MAX_TX_SW_AMSDU_PACKET 15
+
+#define RX_MAX_MSDU_IN_AMSDU 128
+
+#define CL_PATH_MAX 200
+#define CL_FILENAME_MAX 100
+
+/* MAX/MIN number of antennas supported */
+#define MIN_ANTENNAS             1
+#define MAX_ANTENNAS             6
+#define MAX_ANTENNAS_OFDM_HT_VHT 4
+#define MAX_ANTENNAS_CCK         4
+#define MAX_ANTENNAS_CHIP        8
+
+#define MAX_ANTENNAS_CL808X          8
+#define MAX_ANTENNAS_CL806X          6
+#define MAX_ANTENNAS_CL804X          4
+#define MAX_ANTENNAS_WIRING_ID_27_31 3
+
+#define ANT_MASK(ant) (BIT(ant) - 1)
+
+/* 6GHz defines */
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET 3
+#define HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET      6
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_FACTOR     13
+#define HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_MASK   0x38
+
+#define MHZ_TO_BW(mhz) ilog2((mhz) / 20)
+#define BW_TO_MHZ(bw)  ((1 << (bw)) * 20)
+#define BW_TO_KHZ(bw)  ((1 << (bw)) * 20000)
+
+#define CL_HWQ_BK  0
+#define CL_HWQ_BE  1
+#define CL_HWQ_VI  2
+#define CL_HWQ_VO  3
+#define CL_HWQ_BCN 4
+
+/* Traffic ID enumeration */
+enum {
+	TID_0,
+	TID_1,
+	TID_2,
+	TID_3,
+	TID_4,
+	TID_5,
+	TID_6,
+	TID_7,
+	TID_MAX
+};
+
+/* Access Category enumeration */
+enum {
+	AC_BK = 0,
+	AC_BE,
+	AC_VI,
+	AC_VO,
+	AC_MAX
+};
+
+enum cl_dev_flag {
+	CL_DEV_HW_RESTART,
+	CL_DEV_SW_RESTART,
+	CL_DEV_STOP_HW,
+	CL_DEV_STARTED,
+	CL_DEV_AP_STARTED,
+	CL_DEV_INIT,
+	CL_DEV_FW_SYNC,
+	CL_DEV_FW_ERROR,
+	CL_DEV_REPEATER,
+	CL_DEV_MESH_AP,
+	CL_DEV_RADAR_LISTEN
+};
+
+enum cl_hw_mode {
+	HW_MODE_A,
+	HW_MODE_B,
+	HW_MODE_G,
+	HW_MODE_BG,
+
+	HW_MODE_MAX,
+};
+
+enum cl_channel_bw {
+	CHNL_BW_20,
+	CHNL_BW_40,
+	CHNL_BW_80,
+	CHNL_BW_160,
+
+	CHNL_BW_MAX,
+};
+
+#define MU_UL_MAX 4
+
+#define CHNL_BW_MAX_HE   CHNL_BW_MAX
+#define CHNL_BW_MAX_VHT  CHNL_BW_MAX
+#define CHNL_BW_MAX_HT   CHNL_BW_80
+
+#define CHNL_BW_2_5 4
+#define CHNL_BW_5   5
+#define CHNL_BW_10  6
+
+#define MESH_BASIC_RATE_MAX 12
+
+enum cl_wireless_mode {
+	WIRELESS_MODE_LEGACY,
+	WIRELESS_MODE_HT,
+	WIRELESS_MODE_HT_VHT,
+	WIRELESS_MODE_HT_VHT_HE,
+	WIRELESS_MODE_HE
+};
+
+enum cl_ndp_tx_chains {
+	NDP_TX_PHY0 = 0x1,
+	NDP_TX_PHY1 = 0x2,
+	NDP_TX_PHY01 = 0x3,
+};
+
+#define Q2_TO_FREQ(x)    ((x) >> 2)
+#define FREQ_TO_Q2(freq) ((freq) << 2)
+
+/* Values of the firmware FORMATMOD fields */
+enum format_mode {
+	FORMATMOD_NON_HT = 0,
+	FORMATMOD_NON_HT_DUP_OFDM = 1,
+	FORMATMOD_HT_MF = 2,
+	FORMATMOD_HT_GF = 3,
+	FORMATMOD_VHT = 4,
+	FORMATMOD_HE_SU = 5,
+	FORMATMOD_HE_MU = 6,
+	FORMATMOD_HE_EXT = 7,
+	FORMATMOD_HE_TRIG = 8,
+	FORMATMOD_MAX = 9
+};
+
+/* PHY device options */
+enum {
+	PHY_DEV_OLYMPUS,  /* Olympus - 5g/24g */
+	PHY_DEV_ATHOS,    /* Athos - 6g , AthosB - 6g/5g */
+	PHY_DEV_DUMMY,    /* Dummy */
+	PHY_DEV_FRU,      /* Fake RF Unit */
+	PHY_DEV_LOOPBACK, /* RICU loopback mode */
+	PHY_DEV_MAX,
+};
+
+#define IS_REAL_PHY(chip) ((chip)->conf->ci_phy_dev <= PHY_DEV_ATHOS)
+
+#define riu_chain_for_each(_chain) \
+	for (_chain = cl_hw->first_riu_chain; _chain <= cl_hw->last_riu_chain; _chain++)
+
+#define CL_MU_OFDMA_MAX_STA_PER_GRP   8
+#define CL_MU_MIMO_MAX_STA_PER_GRP    4
+
+#if CL_MU_MIMO_MAX_STA_PER_GRP > CL_MU_OFDMA_MAX_STA_PER_GRP
+#define CL_MU_MAX_STA_PER_GROUP       CL_MU_MIMO_MAX_STA_PER_GRP
+#else
+#define CL_MU_MAX_STA_PER_GROUP       CL_MU_OFDMA_MAX_STA_PER_GRP
+#endif
+
+/* Max flags for driver status description is defined as 32 * MAX_CFM_FLAGS */
+#define MAX_CFM_FLAGS 2
+#define DELAY_HIST_SIZE 32
+
+#define STR_LEN_32B  32
+#define STR_LEN_64B  64
+#define STR_LEN_256B 256
+
+#define STA_HASH_SIZE 256
+#define STA_IDX_INVALID U8_MAX
+
+#endif /* CL_DEF_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 20/96] cl8k: add dfs.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (18 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 21/96] cl8k: add dfs.h viktor.barna
                   ` (75 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/dfs.c | 768 +++++++++++++++++++++++++
 1 file changed, 768 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/dfs.c

diff --git a/drivers/net/wireless/celeno/cl8k/dfs.c b/drivers/net/wireless/celeno/cl8k/dfs.c
new file mode 100644
index 000000000000..f320e5885a58
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs.c
@@ -0,0 +1,768 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "utils.h"
+#include "debug.h"
+#include "temperature.h"
+#include "traffic.h"
+#include "reg/reg_defs.h"
+#include "config.h"
+#include "debug.h"
+#include "dfs.h"
+
+#define dfs_pr(cl_hw, level, ...) \
+	do { \
+		if ((level) <= (cl_hw)->dfs_db.dbg_lvl) \
+			pr_debug(__VA_ARGS__); \
+	} while (0)
+
+#define dfs_pr_verbose(cl_hw, ...) dfs_pr((cl_hw), DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define dfs_pr_err(cl_hw, ...)     dfs_pr((cl_hw), DBG_LVL_ERROR, ##__VA_ARGS__)
+#define dfs_pr_warn(cl_hw, ...)    dfs_pr((cl_hw), DBG_LVL_WARNING, ##__VA_ARGS__)
+#define dfs_pr_trace(cl_hw, ...)   dfs_pr((cl_hw), DBG_LVL_TRACE, ##__VA_ARGS__)
+#define dfs_pr_info(cl_hw, ...)    dfs_pr((cl_hw), DBG_LVL_INFO, ##__VA_ARGS__)
+
+/*
+ * ID  Min    Max    Tol    Min  Max  Tol  Tol   MIN    PPB  Trig   Type
+ *     Width  Width  Width  PRI  PRI  PRI  FREQ  Burst       Count
+ */
+
+/* ETSI Radar Types v1.8.2 */
+static struct cl_radar_type radar_type_etsi[] = {
+	{0, 1,  10, 2, 1428, 1428, 2, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+	{1, 1,  10, 2, 1000, 5000, 2, 1, 1, 10, 5,  RADAR_WAVEFORM_SHORT},
+	{2, 1,  15, 2, 625,  5000, 2, 1, 1, 15, 8,  RADAR_WAVEFORM_SHORT},
+	{3, 1,  15, 2, 250,  435,  2, 1, 1, 25, 9, RADAR_WAVEFORM_SHORT},
+	{4, 10, 30, 2, 250,  500,  2, 1, 1, 20, 9, RADAR_WAVEFORM_SHORT},
+	{5, 1,  10, 2, 2500, 3334, 2, 1, 2, 10, 5,  RADAR_WAVEFORM_STAGGERED},
+	{6, 1,  10, 2, 833,  2500, 2, 1, 2, 15, 8,  RADAR_WAVEFORM_STAGGERED},
+};
+
+/* FCC Radar Types 8/14 */
+static struct cl_radar_type radar_type_fcc[] = {
+	{0, 1,  10,   0,  1428, 1428, 1, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+	{1, 1,  10,   3,  518,  3066, 3, 1, 1, 18, 10, RADAR_WAVEFORM_SHORT},
+	{2, 1,  10,   3,  150,  230,  3, 1, 1, 23, 10, RADAR_WAVEFORM_SHORT},
+	{3, 3,  10,   3,  200,  500,  3, 1, 1, 16, 6,  RADAR_WAVEFORM_SHORT},
+	{4, 6,  20,   3,  200,  500,  3, 1, 1, 12, 6,  RADAR_WAVEFORM_SHORT},
+	{5, 50, 100,  50, 1000, 2000, 1, 1, 2, 10, 5,  RADAR_WAVEFORM_LONG},
+	{6, 1,  10,   0,  333,  333,  1, 1, 2, 30, 10, RADAR_WAVEFORM_LONG},
+};
+
+static void cl_dfs_en(struct cl_hw *cl_hw, u8 dfs_en)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	cl_msg_tx_set_dfs(cl_hw, dfs_en, dfs_db->dfs_standard,
+			  conf->ci_dfs_initial_gain, conf->ci_dfs_agc_cd_th);
+	dfs_pr_verbose(cl_hw, "DFS: %s\n", dfs_en ? "Enable" : "Disable");
+}
+
+static bool cl_dfs_create_detection_buffer(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+					   struct cl_dfs_pulse *pulse_buffer, u8 *samples_cnt,
+					   unsigned long time)
+{
+	u8 i;
+	u8 pulse_idx;
+	/* Init First index to last */
+	u8 first_pulse_idx = (dfs_db->buf_idx - 1 + CL_DFS_PULSE_BUF_SIZE) & CL_DFS_PULSE_BUF_MASK;
+
+	/* Find Start Pulse indexes */
+	for (i = 0; i < CL_DFS_PULSE_BUF_SIZE; i++) {
+		pulse_idx = (i + dfs_db->buf_idx) & CL_DFS_PULSE_BUF_MASK;
+
+		if ((time - dfs_db->dfs_pulse[pulse_idx].time) < dfs_db->search_window) {
+			first_pulse_idx = pulse_idx;
+			break;
+		}
+	}
+
+	dfs_pr_info(cl_hw, "DFS: First pulse idx = %u, Last  pulse idx = %u\n",
+		    first_pulse_idx, (dfs_db->buf_idx - 1 + CL_DFS_PULSE_BUF_SIZE)
+		    & CL_DFS_PULSE_BUF_MASK);
+
+	if (dfs_db->buf_idx >= first_pulse_idx + 1) {
+		if ((dfs_db->buf_idx - first_pulse_idx) < dfs_db->min_pulse_eeq)
+			goto not_enough_pulses;
+	} else {
+		if ((dfs_db->buf_idx + CL_DFS_PULSE_BUF_SIZE - first_pulse_idx) <
+		    dfs_db->min_pulse_eeq)
+			goto not_enough_pulses;
+	}
+
+	/* Copy the processed samples to local Buf to avoid index castings */
+	for (i = 0; pulse_idx != ((dfs_db->buf_idx - 1 + CL_DFS_PULSE_BUF_SIZE)
+		& CL_DFS_PULSE_BUF_MASK); i++) {
+		pulse_idx = (i + first_pulse_idx) & CL_DFS_PULSE_BUF_MASK;
+		memcpy(&pulse_buffer[i], &dfs_db->dfs_pulse[pulse_idx], sizeof(pulse_buffer[i]));
+	}
+	*samples_cnt = i + 1;
+
+	return true;
+not_enough_pulses:
+	/* Return if buffer don't hold enough valid samples */
+	dfs_pr_warn(cl_hw, "DFS: Not enough pulses in buffer\n");
+
+	return false;
+}
+
+static bool cl_dfs_is_valid_dfs_freq(struct cl_hw *cl_hw, u32 freq_off)
+{
+	u16 freq = cl_hw->center_freq + freq_off;
+	u16 freq_min = max((u16)(cl_hw->center_freq - cl_center_freq_offset(cl_hw->bw) - 10),
+		(u16)CL_DFS_MIN_FREQ);
+	u16 freq_max = min((u16)(cl_hw->center_freq + cl_center_freq_offset(cl_hw->bw) + 10),
+		(u16)CL_DFS_MAX_FREQ);
+
+	if (freq > freq_min && freq < freq_max)
+		return true;
+
+	return false;
+}
+
+static void cl_dfs_add_pulses_to_global_buffer(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+					       struct cl_radar_pulse *pulse, u8 pulse_cnt,
+					       unsigned long time)
+{
+	int  i;
+
+	for (i = 0; i < pulse_cnt; i++)
+		dfs_pr_info(cl_hw, "Pulse=%d, Width=%u, PRI=%u, FREQ=%d, Time=%lu, FOM=%x\n",
+			    i, pulse[i].len, pulse[i].rep, pulse[i].freq, time, pulse[i].fom);
+
+	/* Maintain cyclic pulse buffer */
+	for (i = 0; i < pulse_cnt; i++) {
+		if (!cl_dfs_is_valid_dfs_freq(cl_hw, (u32)pulse[i].freq))
+			continue;
+
+		dfs_db->dfs_pulse[dfs_db->buf_idx].freq = pulse[i].freq;
+		dfs_db->dfs_pulse[dfs_db->buf_idx].width = pulse[i].len;
+		dfs_db->dfs_pulse[dfs_db->buf_idx].pri = pulse[i].rep;
+		dfs_db->dfs_pulse[dfs_db->buf_idx].fom = pulse[i].fom;
+		dfs_db->dfs_pulse[dfs_db->buf_idx].occ = 0; /* occ temp disabled. */
+		dfs_db->dfs_pulse[dfs_db->buf_idx].time = time;
+
+		dfs_db->buf_idx++;
+		dfs_db->buf_idx &= CL_DFS_PULSE_BUF_MASK;
+	}
+}
+
+static bool cl_dfs_buf_maintain(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+				struct cl_dfs_pulse *pulse_buffer, u8 pulse_cnt,
+				unsigned long time, u8 *samples_cnt, struct cl_dfs_db *dfs_db)
+{
+	int  i;
+
+	cl_dfs_add_pulses_to_global_buffer(cl_hw, dfs_db, pulse, pulse_cnt, time);
+	if (!cl_dfs_create_detection_buffer(cl_hw, dfs_db, pulse_buffer, samples_cnt, time))
+		return false;
+
+	for (i = 0; i < *samples_cnt; i++)
+		dfs_pr_info(cl_hw, "DFS: pulse[%d]: width=%u, pri=%u, freq=%d\n",
+			    i, pulse_buffer[i].width, pulse_buffer[i].pri, pulse_buffer[i].freq);
+
+	return true;
+}
+
+static inline bool cl_dfs_pulse_match(s32 pulse_val, s32 spec_min_val,
+				      s32 spec_max_val, s32 spec_tol)
+{
+	return ((pulse_val >= (spec_min_val - spec_tol)) &&
+		(pulse_val <= (spec_max_val + spec_tol)));
+}
+
+static u8 cl_dfs_is_stag_pulse(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+			       struct cl_dfs_pulse *pulse)
+{
+	int  i;
+	struct cl_radar_type *radar_type;
+
+	for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+		radar_type = &dfs_db->radar_type[i];
+
+		if (radar_type->waveform != RADAR_WAVEFORM_STAGGERED)
+			continue;
+
+		if (cl_dfs_pulse_match((s32)pulse->width, radar_type->min_width,
+				       radar_type->max_width, radar_type->tol_width) &&
+		    cl_dfs_pulse_match((s32)pulse->pri, radar_type->min_pri,
+				       radar_type->max_pri, radar_type->tol_pri)) {
+			/* Search for the second burst */
+			if (abs(pulse[0].pri - pulse[2].pri) <= dfs_db->radar_type[i].tol_pri &&
+			    abs(pulse[1].pri - pulse[3].pri) <= radar_type->tol_pri &&
+			    abs(pulse[0].pri - pulse[1].pri) > radar_type->tol_pri &&
+			    abs(pulse[2].pri - pulse[3].pri) > radar_type->tol_pri) {
+				dfs_pr_info(cl_hw, "DFS: Found match type %d\n", i);
+				return (i + 1);
+			} else if (abs(pulse[0].pri - pulse[3].pri) <= radar_type->tol_pri &&
+				   abs(pulse[1].pri - pulse[4].pri) <= radar_type->tol_pri &&
+				   abs(pulse[0].pri - pulse[1].pri) > radar_type->tol_pri &&
+				   abs(pulse[3].pri - pulse[4].pri) > radar_type->tol_pri) {
+				dfs_pr_info(cl_hw, "DFS: Found match radar %d\n", i);
+				return (i + 1);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static u8 cl_dfs_is_non_stag_pulse(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db,
+				   struct cl_dfs_pulse *pulse)
+{
+	int  i;
+	struct cl_radar_type *radar_type;
+
+	for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+		radar_type = &dfs_db->radar_type[i];
+
+		if (radar_type->waveform == RADAR_WAVEFORM_STAGGERED)
+			continue;
+
+		if (cl_dfs_pulse_match((s32)pulse->width, radar_type->min_width,
+				       radar_type->max_width, radar_type->tol_width) &&
+		    cl_dfs_pulse_match((s32)pulse->pri, radar_type->min_pri,
+				       radar_type->max_pri, radar_type->tol_pri)) {
+			dfs_pr_info(cl_hw, "DFS: Found match type %d\n", i);
+			return (i + 1);
+		}
+	}
+
+	dfs_pr_warn(cl_hw, "DFS: Match not found\n");
+
+	return 0;
+}
+
+static u8 cl_dfs_get_pulse_type(struct cl_hw *cl_hw, struct cl_dfs_pulse *pulse,
+				bool stag_candidate)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	if (stag_candidate) {
+		u8 pulse_type = cl_dfs_is_stag_pulse(cl_hw, dfs_db, pulse);
+
+		if (pulse_type)
+			return pulse_type;
+	}
+
+	return cl_dfs_is_non_stag_pulse(cl_hw, dfs_db, pulse);
+}
+
+static bool cl_dfs_compare_cand(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db, u8 pulse_type,
+				struct cl_dfs_pulse radar_cand, u8 *match, int idx,
+				u8 *occ_ch_cand)
+{
+	int i;
+
+	if (!(abs(dfs_db->pulse_buffer[idx].width - radar_cand.width) <=
+	    dfs_db->radar_type[pulse_type].tol_width))
+		goto end;
+
+	if (!(abs(dfs_db->pulse_buffer[idx].freq - radar_cand.freq) <=
+	    dfs_db->radar_type[pulse_type].tol_freq))
+		goto end;
+
+	for (i = 1; i < CL_DFS_CONCEAL_CNT; i++)
+		if (abs(dfs_db->pulse_buffer[idx].pri - i * radar_cand.pri) <=
+		    dfs_db->radar_type[pulse_type].tol_pri)
+			break;
+
+	if (i == CL_DFS_CONCEAL_CNT)
+		goto end;
+
+	(*match)++;
+	(*occ_ch_cand) += dfs_db->pulse_buffer[i].occ;
+
+end:
+	dfs_pr_info(cl_hw, "DFS: compared pulse - width=%u, pri=%u, freq=%u match: %u "
+		    "trig cnt: %u\n",
+		    dfs_db->pulse_buffer[idx].width, dfs_db->pulse_buffer[idx].pri,
+		    dfs_db->pulse_buffer[idx].freq, *match,
+		    dfs_db->radar_type[pulse_type].trig_count);
+
+	if (*match < dfs_db->radar_type[pulse_type].trig_count)
+		return false;
+
+	return true;
+}
+
+static bool cl_dfs_check_cand(struct cl_hw *cl_hw, struct cl_dfs_db *dfs_db, u8 pulse_type,
+			      struct cl_dfs_pulse radar_cand, u8 samples_cnt)
+{
+	u8 occ_ch_cand = 0;
+	u8 match = 0;
+	int i;
+
+	dfs_pr_info(cl_hw, "DFS: candidate pulse - width=%u, pri=%u, freq=%u\n",
+		    radar_cand.width, radar_cand.pri, radar_cand.freq);
+
+	for (i = 0; i < samples_cnt; i++) {
+		if (!cl_dfs_compare_cand(cl_hw, dfs_db, pulse_type, radar_cand, &match, i,
+					 &occ_ch_cand))
+			continue;
+
+		dfs_pr_verbose(cl_hw, "DFS: Radar detected - type %u\n", pulse_type);
+
+		return true;
+	}
+
+	return false;
+}
+
+static bool cl_dfs_short_pulse_search(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+				      u8 pulse_cnt, unsigned long time, struct cl_dfs_db *dfs_db)
+{
+	int i;
+	bool stag_candidate;
+	u8 samples_cnt = 0;
+	u8 pulse_type;
+
+	/* Return if not enough pulses in the buffer */
+	if (!cl_dfs_buf_maintain(cl_hw, pulse, dfs_db->pulse_buffer, pulse_cnt, time,
+				 &samples_cnt, dfs_db))
+		return false;
+
+	for (i = 0; i < samples_cnt; i++) {
+		struct cl_dfs_pulse radar_cand;
+
+		stag_candidate = false;
+
+		/* Make sure there is enough samples to staggered check */
+		if (dfs_db->dfs_standard == NL80211_DFS_ETSI &&
+		    (samples_cnt - i) > CL_DFS_STAGGERED_CHEC_LEN)
+			stag_candidate = true;
+
+		pulse_type = cl_dfs_get_pulse_type(cl_hw, &dfs_db->pulse_buffer[i], stag_candidate);
+
+		if (!pulse_type)
+			continue;
+
+		radar_cand.width = dfs_db->pulse_buffer[i].width;
+		radar_cand.pri = dfs_db->pulse_buffer[i].pri;
+		radar_cand.freq = dfs_db->pulse_buffer[i].freq;
+
+		if (cl_dfs_check_cand(cl_hw, dfs_db, pulse_type - 1, radar_cand, samples_cnt))
+			return true;
+	}
+
+	return false;
+}
+
+static bool cl_dfs_long_pulse_search(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse,
+				     u8 pulse_cnt, unsigned long time)
+{
+	u32 prev_pulse_time_diff;
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	int i;
+
+	for (i = 0; i < pulse_cnt; i++) {
+		if (pulse[i].len > CL_DFS_LONG_MIN_WIDTH) {
+			prev_pulse_time_diff = time - dfs_db->last_long_pulse_ts;
+
+			if (pulse[i].rep >= dfs_db->radar_type[5].min_pri &&
+			    pulse[i].rep <= dfs_db->radar_type[5].max_pri)
+				dfs_db->long_pri_match_count += 1;
+
+			dfs_pr_info(cl_hw, "DFS: Long pulse search: width = %u, delta_time = %u\n",
+				    pulse[i].len, prev_pulse_time_diff);
+
+			if (dfs_db->long_pulse_count == 0 ||
+			    (prev_pulse_time_diff >= conf->ci_dfs_long_pulse_min &&
+			     prev_pulse_time_diff <= conf->ci_dfs_long_pulse_max)) {
+				dfs_db->long_pulse_count += 1;
+			} else if (prev_pulse_time_diff > min(dfs_db->max_interrupt_diff,
+						     conf->ci_dfs_long_pulse_min)) {
+				dfs_db->long_pulse_count = 0;
+				dfs_db->short_pulse_count = 0;
+				dfs_db->long_pri_match_count = 0;
+			}
+			dfs_db->last_long_pulse_ts = time;
+		} else if (pulse[i].len < CL_DFS_LONG_FALSE_WIDTH) {
+			dfs_db->short_pulse_count++;
+
+			if (dfs_db->short_pulse_count > CL_DFS_LONG_FALSE_IND) {
+				dfs_db->long_pulse_count = 0;
+				dfs_db->short_pulse_count = 0;
+				dfs_db->long_pri_match_count = 0;
+
+				dfs_pr_warn(cl_hw, "DFS: Restart long sequence search\n");
+			}
+		}
+	}
+
+	if (dfs_db->long_pulse_count >= dfs_db->radar_type[5].trig_count &&
+	    dfs_db->long_pri_match_count >= (dfs_db->radar_type[5].trig_count - 1)) {
+		dfs_db->short_pulse_count = 0;
+		dfs_db->long_pulse_count = 0;
+		dfs_db->long_pri_match_count = 0;
+		return true;
+	} else {
+		return false;
+	}
+}
+
+static bool cl_dfs_post_detection(struct cl_hw *cl_hw)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	/* Make sure firmware sets the DFS registers */
+	cl_radar_flush(cl_hw);
+	cl_msg_tx_set_dfs(cl_hw, false, dfs_db->dfs_standard,
+			  cl_hw->conf->ci_dfs_initial_gain, cl_hw->conf->ci_dfs_agc_cd_th);
+
+	ieee80211_radar_detected(cl_hw->hw);
+
+	return true;
+}
+
+bool cl_dfs_pulse_process(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse, u8 pulse_cnt,
+			  unsigned long time)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	dfs_db->pulse_cnt += pulse_cnt;
+
+	if (dfs_db->dfs_standard == NL80211_DFS_FCC &&
+	    cl_dfs_long_pulse_search(cl_hw, pulse, pulse_cnt, time)) {
+		dfs_pr_verbose(cl_hw, "DFS: Radar detected - long\n");
+		return cl_dfs_post_detection(cl_hw);
+	} else if (cl_dfs_short_pulse_search(cl_hw, pulse, pulse_cnt, time, dfs_db)) {
+		return cl_dfs_post_detection(cl_hw);
+	}
+
+	return false;
+}
+
+static void cl_dfs_set_min_pulse(struct cl_hw *cl_hw)
+{
+	int i;
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	dfs_db->min_pulse_eeq = U8_MAX;
+
+	for (i = 0; i < dfs_db->radar_type_cnt; i++) {
+		if (dfs_db->radar_type[i].trig_count < dfs_db->min_pulse_eeq)
+			dfs_db->min_pulse_eeq = dfs_db->radar_type[i].trig_count;
+	}
+	dfs_db->min_pulse_eeq = max(dfs_db->min_pulse_eeq, (u8)CL_DFS_MIN_PULSE_TRIG);
+}
+
+static void cl_dfs_set_region(struct cl_hw *cl_hw, enum nl80211_dfs_regions std)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	dfs_db->dfs_standard = std;
+
+	if (dfs_db->dfs_standard == NL80211_DFS_FCC) {
+		dfs_db->radar_type = radar_type_fcc;
+		dfs_db->radar_type_cnt = sizeof(radar_type_fcc) / sizeof(struct cl_radar_type);
+	} else {
+		dfs_db->radar_type = radar_type_etsi;
+		dfs_db->radar_type_cnt = sizeof(radar_type_etsi) / sizeof(struct cl_radar_type);
+	}
+}
+
+static void cl_dfs_start_cac(struct cl_dfs_db *db)
+{
+	db->cac.started = true;
+}
+
+static void cl_dfs_end_cac(struct cl_dfs_db *db)
+{
+	db->cac.started = false;
+}
+
+void cl_dfs_radar_listen_start(struct cl_hw *cl_hw)
+{
+	set_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+	cl_dfs_en(cl_hw, true);
+
+	dfs_pr_verbose(cl_hw, "DFS: Started radar listening\n");
+}
+
+void cl_dfs_radar_listen_end(struct cl_hw *cl_hw)
+{
+	clear_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+	cl_dfs_en(cl_hw, false);
+
+	dfs_pr_verbose(cl_hw, "DFS: Ended radar listening\n");
+}
+
+void cl_dfs_force_cac_start(struct cl_hw *cl_hw)
+{
+	bool is_listening = test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+	cl_dfs_start_cac(&cl_hw->dfs_db);
+
+	/* Reset request state upon completion */
+	cl_dfs_request_cac(cl_hw, false);
+
+	/* Disable all the TX flow - be silent */
+	cl_tx_en(cl_hw, CL_TX_EN_DFS, false);
+
+	/* If for some reason we are still not listening radar, do it */
+	if (unlikely(!is_listening && cl_hw->hw->conf.radar_enabled))
+		cl_dfs_radar_listen_start(cl_hw);
+
+	dfs_pr_verbose(cl_hw, "DFS: CAC started\n");
+}
+
+void cl_dfs_force_cac_end(struct cl_hw *cl_hw)
+{
+	bool is_listening = test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+
+	/* Enable all the TX flow */
+	cl_tx_en(cl_hw, CL_TX_EN_DFS, true);
+
+	/*
+	 * If for some reason we are still listening and mac80211 does not
+	 * require to listen radar - disable it
+	 */
+	if (unlikely(is_listening && !cl_hw->hw->conf.radar_enabled))
+		cl_dfs_radar_listen_end(cl_hw);
+
+	cl_dfs_end_cac(&cl_hw->dfs_db);
+
+	dfs_pr_verbose(cl_hw, "DFS: CAC ended\n");
+}
+
+bool __must_check cl_dfs_is_in_cac(struct cl_hw *cl_hw)
+{
+	return cl_hw->dfs_db.cac.started;
+}
+
+bool __must_check cl_dfs_radar_listening(struct cl_hw *cl_hw)
+{
+	return test_bit(CL_DEV_RADAR_LISTEN, &cl_hw->drv_flags);
+}
+
+bool __must_check cl_dfs_requested_cac(struct cl_hw *cl_hw)
+{
+	return cl_hw->dfs_db.cac.requested;
+}
+
+void cl_dfs_request_cac(struct cl_hw *cl_hw, bool should_do)
+{
+	cl_hw->dfs_db.cac.requested = should_do;
+}
+
+static void cl_dfs_edit_tbl(struct cl_hw *cl_hw, u8 row, u8 line, s16 val)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+
+	if (row > dfs_db->radar_type_cnt) {
+		dfs_pr_err(cl_hw, "Invalid row number (%u) [0 - %u]\n", line,
+			   dfs_db->radar_type_cnt - 1);
+		return;
+	}
+
+	if (line == 0 || line > CL_DFS_MAX_TBL_LINE) {
+		dfs_pr_err(cl_hw, "Invalid line number (%u) [1 - %u]\n", line,
+			   CL_DFS_MAX_TBL_LINE - 1);
+		return;
+	}
+
+	if (line == 1)
+		dfs_db->radar_type[row].min_width = (s32)val;
+	else if (line == 2)
+		dfs_db->radar_type[row].max_width = (s32)val;
+	else if (line == 3)
+		dfs_db->radar_type[row].tol_width = (s32)val;
+	else if (line == 4)
+		dfs_db->radar_type[row].min_pri = (s32)val;
+	else if (line == 5)
+		dfs_db->radar_type[row].max_pri = (s32)val;
+	else if (line == 6)
+		dfs_db->radar_type[row].tol_pri = (s32)val;
+	else if (line == 7)
+		dfs_db->radar_type[row].tol_freq = (s32)val;
+	else if (line == 8)
+		dfs_db->radar_type[row].min_burst = (u8)val;
+	else if (line == 9)
+		dfs_db->radar_type[row].ppb = (u8)val;
+	else if (line == 10)
+		dfs_db->radar_type[row].trig_count = (u8)val;
+	else if (line == 11)
+		dfs_db->radar_type[row].waveform = (enum cl_radar_waveform)val;
+
+	/* Verify if min_pulse_eeq was changed */
+	cl_dfs_set_min_pulse(cl_hw);
+}
+
+static void cl_dfs_tbl_overwrite_set(struct cl_hw *cl_hw)
+{
+	char *tok = NULL;
+	u8 param1 = 0;
+	u8 param2 = 0;
+	s16 param3 = 0;
+	char str[64];
+	char *strp = str;
+
+	if (strlen(cl_hw->conf->ce_dfs_tbl_overwrite) == 0)
+		return;
+
+	snprintf(str, sizeof(str), cl_hw->conf->ce_dfs_tbl_overwrite);
+
+	tok = strsep(&strp, ";");
+	while (tok) {
+		if (sscanf(tok, "%hhd,%hhd,%hd", &param1, &param2, &param3) == 3)
+			cl_dfs_edit_tbl(cl_hw, param1, param2, param3);
+		tok = strsep(&strp, ";");
+	}
+}
+
+void cl_dfs_init(struct cl_hw *cl_hw)
+{
+	struct cl_dfs_db *dfs_db = &cl_hw->dfs_db;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	if (!cl_band_is_5g(cl_hw))
+		return;
+
+	dfs_db->en = conf->ci_ieee80211h;
+
+	cl_hw->dfs_db.dbg_lvl = DBG_LVL_ERROR;
+
+	/*
+	 * Setting min window size to avoid the case where the second interrupt
+	 * within the burst is setting the counter to 0. the max is between jiffies
+	 * unit and max PRI in ms.
+	 */
+	dfs_db->max_interrupt_diff = max(1000 / HZ, 2);
+
+	cl_dfs_set_region(cl_hw, cl_hw->channel_info.standard);
+	dfs_db->search_window = CL_DFS_PULSE_WINDOW;
+
+	cl_dfs_set_min_pulse(cl_hw);
+	cl_dfs_tbl_overwrite_set(cl_hw);
+}
+
+void cl_dfs_reinit(struct cl_hw *cl_hw)
+{
+	cl_dfs_init(cl_hw);
+}
+
+void cl_dfs_recovery(struct cl_hw *cl_hw)
+{
+	/* Re-enable DFS after recovery */
+	if (cl_dfs_is_in_cac(cl_hw)) {
+		cl_dfs_en(cl_hw, true);
+
+		/* If recovery happened during CAC make sure to disable beacon backup */
+		cl_tx_en(cl_hw, CL_TX_EN_DFS, false);
+	}
+}
+
+static bool cl_radar_handler(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem,
+			     unsigned long time)
+{
+	/* Retrieve the radar pulses structure */
+	struct cl_radar_pulse_array *pulses = radar_elem->radarbuf_ptr;
+
+	cl_dfs_pulse_process(cl_hw, (struct cl_radar_pulse *)pulses->pulse, pulses->cnt, time);
+
+	return false;
+}
+
+static void cl_radar_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct cl_radar_queue_elem *radar_elem = NULL;
+	unsigned long flags = 0;
+	bool radar_stat = false;
+
+	while (!list_empty(&cl_hw->radar_queue.head)) {
+		spin_lock_irqsave(&cl_hw->radar_queue.lock, flags);
+		radar_elem = list_first_entry(&cl_hw->radar_queue.head,
+					      struct cl_radar_queue_elem, list);
+		list_del(&radar_elem->list);
+		spin_unlock_irqrestore(&cl_hw->radar_queue.lock, flags);
+
+		radar_stat = cl_radar_handler(radar_elem->cl_hw, &radar_elem->radar_elem,
+					      radar_elem->time);
+
+		kfree(radar_elem->radar_elem.radarbuf_ptr);
+		kfree(radar_elem);
+	}
+
+	if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+		if (!radar_stat)
+			cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.radar);
+}
+
+void cl_radar_init(struct cl_hw *cl_hw)
+{
+	INIT_LIST_HEAD(&cl_hw->radar_queue.head);
+
+	tasklet_init(&cl_hw->radar_tasklet, cl_radar_tasklet, (unsigned long)cl_hw);
+
+	spin_lock_init(&cl_hw->radar_queue.lock);
+}
+
+void cl_radar_push(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem)
+{
+	struct cl_radar_queue_elem *new_queue_elem = NULL;
+	u32 i;
+
+	new_queue_elem = kmalloc(sizeof(*new_queue_elem), GFP_ATOMIC);
+
+	if (new_queue_elem) {
+		new_queue_elem->radar_elem.radarbuf_ptr =
+			kmalloc(sizeof(*new_queue_elem->radar_elem.radarbuf_ptr), GFP_ATOMIC);
+
+		if (new_queue_elem->radar_elem.radarbuf_ptr) {
+			new_queue_elem->radar_elem.dma_addr = radar_elem->dma_addr;
+			new_queue_elem->radar_elem.radarbuf_ptr->cnt =
+				radar_elem->radarbuf_ptr->cnt;
+
+			/* Copy into local list */
+			for (i = 0; i < RADAR_PULSE_MAX; i++)
+				new_queue_elem->radar_elem.radarbuf_ptr->pulse[i] =
+					radar_elem->radarbuf_ptr->pulse[i];
+
+			new_queue_elem->time = jiffies_to_msecs(jiffies);
+			new_queue_elem->cl_hw = cl_hw;
+
+			spin_lock(&cl_hw->radar_queue.lock);
+			list_add_tail(&new_queue_elem->list, &cl_hw->radar_queue.head);
+			spin_unlock(&cl_hw->radar_queue.lock);
+		} else {
+			kfree(new_queue_elem);
+		}
+	}
+}
+
+void cl_radar_tasklet_schedule(struct cl_hw *cl_hw)
+{
+	tasklet_schedule(&cl_hw->radar_tasklet);
+}
+
+void cl_radar_flush(struct cl_hw *cl_hw)
+{
+	struct cl_radar_queue_elem *radar_elem = NULL;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&cl_hw->radar_queue.lock, flags);
+
+	while (!list_empty(&cl_hw->radar_queue.head)) {
+		radar_elem = list_first_entry(&cl_hw->radar_queue.head,
+					      struct cl_radar_queue_elem, list);
+		list_del(&radar_elem->list);
+		kfree(radar_elem->radar_elem.radarbuf_ptr);
+		kfree(radar_elem);
+	}
+
+	spin_unlock_irqrestore(&cl_hw->radar_queue.lock, flags);
+}
+
+void cl_radar_close(struct cl_hw *cl_hw)
+{
+	cl_radar_flush(cl_hw);
+	tasklet_kill(&cl_hw->radar_tasklet);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 21/96] cl8k: add dfs.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (19 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 20/96] cl8k: add dfs.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 22/96] cl8k: add dsp.c viktor.barna
                   ` (74 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/dfs.h | 146 +++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/dfs.h

diff --git a/drivers/net/wireless/celeno/cl8k/dfs.h b/drivers/net/wireless/celeno/cl8k/dfs.h
new file mode 100644
index 000000000000..a252844f854b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dfs.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_DFS_H
+#define CL_DFS_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include "debug.h"
+
+#define CL_DFS_MAX_TBL_LINE       11    /* Radar Table Max Line */
+#define CL_DFS_PULSE_BUF_SIZE     64    /* Radar Pulse buffer size */
+#define CL_DFS_PULSE_BUF_MASK     0x03F /* Radar Pulse buffer cyclic mask */
+#define CL_DFS_PULSE_WINDOW       100   /* Radar Pulse search window [ms] */
+#define CL_DFS_MIN_PULSE_TRIG     1     /* Minimum Pulse trigger num */
+#define CL_DFS_LONG_MIN_WIDTH     20    /* Min Long Pulse Width */
+#define CL_DFS_LONG_FALSE_WIDTH   10    /* Low width signals indicates of false detections */
+#define CL_DFS_LONG_FALSE_IND     6     /* False indication while searching for long sequence */
+#define CL_DFS_STAGGERED_CHEC_LEN 4     /* Staggered check length */
+#define CL_DFS_CONCEAL_CNT        10    /* Maximum concealed pulses search */
+#define CL_DFS_MIN_FREQ           5250  /* Min DFS frequency */
+#define CL_DFS_MAX_FREQ           5725  /* Max DFS frequency */
+
+enum cl_radar_waveform {
+	RADAR_WAVEFORM_SHORT,
+	RADAR_WAVEFORM_LONG,
+	RADAR_WAVEFORM_STAGGERED,
+	RADAR_WAVEFORM_SEVERE
+};
+
+struct cl_radar_type {
+	u8 id;
+	s32 min_width;
+	s32 max_width;
+	s32 tol_width;
+	s32 min_pri;
+	s32 max_pri;
+	s32 tol_pri;
+	s32 tol_freq;
+	u8 min_burst;
+	u8 ppb;
+	u8 trig_count;
+	enum cl_radar_waveform waveform;
+};
+
+/* Number of pulses in a radar event structure */
+#define RADAR_PULSE_MAX 4
+
+/*
+ * Structure used to store information regarding
+ * E2A radar events in the driver
+ */
+struct cl_radar_elem {
+	struct cl_radar_pulse_array *radarbuf_ptr;
+	dma_addr_t dma_addr;
+};
+
+/* Bit mapping inside a radar pulse element */
+struct cl_radar_pulse {
+	u64 freq        : 8;
+	u64 fom         : 8;
+	u64 len         : 8;  /* Pulse length timer */
+	u64 measure_cnt : 2;  /* Measure count */
+	u64 rsv1        : 6;  /* Reserve1 */
+	u64 rep         : 16; /* PRI */
+	u64 rsv2        : 16; /* Reserve2 */
+};
+
+/* Definition of an array of radar pulses */
+struct cl_radar_pulse_array {
+	/* Buffer containing the radar pulses */
+	u64 pulse[RADAR_PULSE_MAX];
+	/* Number of valid pulses in the buffer */
+	u32 cnt;
+};
+
+struct cl_radar_queue_elem {
+	struct list_head list;
+	struct cl_hw *cl_hw;
+	struct cl_radar_elem radar_elem;
+	unsigned long time;
+};
+
+struct cl_radar_queue {
+	struct list_head head;
+	spinlock_t lock;
+};
+
+struct cl_dfs_pulse {
+	s32 freq  : 8;      /* Radar Frequency offset [units of 4MHz] */
+	u32 fom   : 8;      /* Figure of Merit */
+	u32 width : 8;      /* Pulse Width [units of 2 micro sec] */
+	u32 occ   : 1;      /* OCC indication for Primary/Secondary channel */
+	u32 res1  : 7;      /* Reserve */
+	u32 pri   : 16;     /* Pulse Repetition Frequency */
+	u32 res2  : 16;
+	unsigned long time; /* Pulse Receive Time */
+};
+
+struct cl_dfs_db {
+	bool en;
+	enum cl_dbg_level dbg_lvl;
+	enum nl80211_dfs_regions dfs_standard;
+	struct {
+		bool started;
+		bool requested;
+	} cac;
+	u8 long_pulse_count;
+	u32 last_long_pulse_ts;
+	u8 short_pulse_count;
+	u8 long_pri_match_count;
+	u8 min_pulse_eeq;
+	u8 buf_idx;
+	u8 radar_type_cnt;
+	u16 search_window;
+	u16 max_interrupt_diff;
+	u16 remain_cac_time;
+	u32 pulse_cnt;
+	struct cl_radar_type *radar_type;
+	struct cl_dfs_pulse dfs_pulse[CL_DFS_PULSE_BUF_SIZE];
+	struct cl_dfs_pulse pulse_buffer[CL_DFS_PULSE_BUF_SIZE];
+};
+
+void cl_dfs_init(struct cl_hw *cl_hw);
+void cl_dfs_reinit(struct cl_hw *cl_hw);
+void cl_dfs_start(struct cl_hw *cl_hw);
+void cl_dfs_recovery(struct cl_hw *cl_hw);
+bool cl_dfs_pulse_process(struct cl_hw *cl_hw, struct cl_radar_pulse *pulse, u8 pulse_cnt,
+			  unsigned long time);
+bool __must_check cl_dfs_is_in_cac(struct cl_hw *cl_hw);
+bool __must_check cl_dfs_requested_cac(struct cl_hw *cl_hw);
+bool __must_check cl_dfs_radar_listening(struct cl_hw *cl_hw);
+void cl_dfs_request_cac(struct cl_hw *cl_hw, bool should_do);
+void cl_dfs_force_cac_start(struct cl_hw *cl_hw);
+void cl_dfs_force_cac_end(struct cl_hw *cl_hw);
+void cl_dfs_radar_listen_start(struct cl_hw *cl_hw);
+void cl_dfs_radar_listen_end(struct cl_hw *cl_hw);
+
+void cl_radar_init(struct cl_hw *cl_hw);
+void cl_radar_push(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem);
+void cl_radar_tasklet_schedule(struct cl_hw *cl_hw);
+void cl_radar_flush(struct cl_hw *cl_hw);
+void cl_radar_close(struct cl_hw *cl_hw);
+
+#endif /* CL_DFS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 22/96] cl8k: add dsp.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (20 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 21/96] cl8k: add dfs.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 23/96] cl8k: add dsp.h viktor.barna
                   ` (73 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/dsp.c | 627 +++++++++++++++++++++++++
 1 file changed, 627 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.c

diff --git a/drivers/net/wireless/celeno/cl8k/dsp.c b/drivers/net/wireless/celeno/cl8k/dsp.c
new file mode 100644
index 000000000000..fbc8b29b9257
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dsp.c
@@ -0,0 +1,627 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/firmware.h>
+
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "dsp.h"
+#include "hw.h"
+
+#define BUSY_WAIT_LIMIT 10000
+
+static int cl_dsp_busy_wait(struct cl_hw *cl_hw, u32 control_reg)
+{
+	int i;
+
+	for (i = 0; i < BUSY_WAIT_LIMIT; i++) {
+		/* Poll Bit29 to verify DMA transfer has ended. */
+		if ((cl_reg_read(cl_hw, control_reg) & 0x20000000) == 0)
+			return 0;
+
+		cpu_relax();
+	}
+
+	return -EIO;
+}
+
+static void cl_dsp_boot(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		/* Disable ceva_free_clk */
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+		/* Assert Ceva reset */
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+	} else {
+		/* Disable ceva_free_clk */
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+		/* Assert Ceva reset */
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+	}
+
+	/* Set Ceva boot=1 */
+	modem_gcu_ceva_ctrl_boot_setf(cl_hw, 1);
+	/* Set Ceva vector */
+	modem_gcu_ceva_vec_set(cl_hw, 0);
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		/* Enable ceva_clk */
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+		/* Disabel ceva_clk */
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+		/* De-Assert Ceva reset - Reset Release */
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+		/* Enable ceva_clk */
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+	} else {
+		/* Enable ceva_clk */
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+		/* Disabel ceva_clk */
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+		/* De-Assert Ceva reset - Reset Release */
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+		/* Enable ceva_clk */
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+	}
+
+	/* Release Ceva external_wait */
+	modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0);
+	/* Set Ceva boot=0 */
+	modem_gcu_ceva_ctrl_boot_setf(cl_hw, 0);
+}
+
+static void cl_dsp_config_dma_for_code_copy(struct cl_hw *cl_hw, u32 page, u32 page_size)
+{
+	/* Configure Program DMA to copy FW code from Shared PMEM to internal PMEM. */
+
+	/* External address to read from. */
+	cl_reg_write(cl_hw, CEVA_CPM_PDEA_REG, CEVA_SHARED_PMEM_BASE_ADDR_INTERNAL);
+	/* Internal address to write to. */
+	cl_reg_write(cl_hw, CEVA_CPM_PDIA_REG, CEVA_SHARED_PMEM_SIZE * page);
+	/* Page size */
+	cl_reg_write(cl_hw, CEVA_CPM_PDTC_REG, page_size);
+}
+
+static void cl_dsp_config_dma_for_external_data_copy(struct cl_hw *cl_hw)
+{
+	/* Configure Program DMA to copy FW code from Shared XMEM to internal XMEM. */
+
+	/* External address to read from. */
+	cl_reg_write(cl_hw, CEVA_CPM_DDEA_REG, CEVA_SHARED_XMEM_BASE_ADDR_INTERNAL);
+	/* Internal address to write to. */
+	cl_reg_write(cl_hw, CEVA_CPM_DDIA_REG, 0);
+	/* Page size + DMA direction is write */
+	cl_reg_write(cl_hw, CEVA_CPM_DDTC_REG,
+		     CEVA_SHARED_XMEM_SIZE | CEVA_CPM_DDTC_WRITE_COMMAND);
+}
+
+static int cl_dsp_hex_load(struct cl_hw *cl_hw, const u8 *buf,
+			   off_t offset, size_t size, size_t buf_size)
+{
+	u8 single_buf[4] = {0};
+	u32 bin_data = 0;
+	u8 next_byte;
+	u8 byte_num = 0;
+	int ret = 0;
+	ssize_t oft = 0;
+	size_t real_size = min(size * 3, buf_size);
+	/*
+	 * CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST is global and we don't
+	 * want to add TCV reg offset.
+	 */
+	bool chip_reg = (offset == CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST);
+
+	if (buf_size % 3) {
+		cl_dbg_err(cl_hw, "DSP size %zu must be divided by 3 !!!\n",
+			   buf_size);
+		return -EINVAL;
+	}
+
+	while (oft < real_size) {
+		memcpy(single_buf, buf + oft, 3);
+		/* Each line contains 2 hex digits + a line feed, i.e. 3 bytes */
+		ret = kstrtou8(single_buf, 16, &next_byte);
+		if (ret < 0) {
+			cl_dbg_err(cl_hw,
+				   "ret = %d, oft = %zu,"
+				   "single_buf = 0x%x 0x%x 0x%x 0x%x\n",
+				   ret, oft, single_buf[0], single_buf[1],
+				   single_buf[2], single_buf[3]);
+			return ret;
+		}
+
+		/* Little-endian order. */
+		bin_data += next_byte << (8 * byte_num);
+		byte_num = (byte_num + 1) % 4;
+
+		/* Read 4 lines from the file, and then write. */
+		if (byte_num == 0) {
+			if (chip_reg)
+				cl_reg_write_chip(cl_hw->chip, offset, bin_data);
+			else
+				cl_reg_write_direct(cl_hw, offset, bin_data);
+			offset += 4;
+			bin_data = 0;
+		}
+
+		memset(&single_buf, 0, sizeof(single_buf));
+		oft += 3;
+	}
+
+	return 0;
+}
+
+static int cl_dsp_load_code(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u32 real_size;
+	u32 page;
+	u32 page_size = CEVA_SHARED_PMEM_SIZE;
+	const struct firmware *fw;
+	size_t size = 0;
+	u8 *buf = NULL;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s",
+		 cl_hw->conf->ce_dsp_code);
+
+	cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_code);
+
+	ret = request_firmware(&fw, path_name, chip->dev);
+
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+			   path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+	buf = (u8 *)fw->data;
+
+	/* Load all pages + 1 extra cache page */
+	for (page = 0; page < CEVA_MAX_PAGES + 1; page++) {
+		if (page >= CEVA_MAX_PAGES)
+			page_size = CEVA_SHARED_PMEM_CACHE_SIZE;
+
+		real_size = min_t(u32, page_size * 3, size);
+
+		if (!real_size)
+			break;
+
+		/* Copy DSP code (one page each time) */
+		ret =  cl_dsp_hex_load(cl_hw, buf,
+				       CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST,
+				       page_size, size);
+		if (ret != 0) {
+			cl_dbg_err(cl_hw, "Failed to load pmem page 0x%x!\n", page);
+			break;
+		}
+
+		cl_dsp_config_dma_for_code_copy(cl_hw, page, page_size);
+		ret = cl_dsp_busy_wait(cl_hw, CEVA_CPM_PDTC_REG);
+
+		if (ret) {
+			cl_dbg_err(cl_hw, "cl_dsp_busy_wait failed!\n");
+			goto out;
+		}
+
+		buf += real_size;
+		size -= real_size;
+	}
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int cl_dsp_load_data(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	const struct firmware *fw;
+	size_t size = 0;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s",
+		 cl_hw->conf->ce_dsp_data);
+
+	cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_data);
+
+	ret = request_firmware(&fw, path_name, chip->dev);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+			   path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+
+	ret = cl_dsp_hex_load(cl_hw, fw->data, REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_DATA_SIZE, size);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load HEX file\n");
+		goto out;
+	}
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int cl_dsp_load_external_data(struct cl_hw *cl_hw)
+{
+	/*
+	 * Shared XMEM is not accessible by host.
+	 * Copy the XMEM section to DRAM first and then use CEVA internal DMA to copy to
+	 * SHARED XMEM.
+	 */
+	struct cl_chip *chip = cl_hw->chip;
+	const struct firmware *fw;
+	size_t size = 0;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s",
+		 cl_hw->conf->ce_dsp_external_data);
+
+	cl_dbg_verbose(cl_hw, "from %s\n", cl_hw->conf->ce_dsp_external_data);
+
+	ret = request_firmware(&fw, path_name, chip->dev);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to get %s, with error: %x!\n",
+			   path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+
+	ret = cl_dsp_hex_load(cl_hw, fw->data, REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_EXT_DATA_SIZE, size);
+
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load HEX file\n");
+		goto out;
+	}
+
+	cl_dsp_config_dma_for_external_data_copy(cl_hw);
+	ret = cl_dsp_busy_wait(cl_hw, CEVA_CPM_DDTC_REG);
+
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_dsp_busy_wait failed!\n");
+		goto out;
+	}
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static bool cl_dsp_is_universal_file(struct cl_chip *chip)
+{
+	return (cl_chip_is_tcv0_enabled(chip) &&
+		cl_chip_is_tcv1_enabled(chip) &&
+		!strcmp(chip->cl_hw_tcv0->conf->ce_dsp_code,
+			chip->cl_hw_tcv1->conf->ce_dsp_code));
+}
+
+static int cl_dsp_load_code_dual(struct cl_chip *chip, const char *filename)
+{
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	u32 real_size;
+	u32 page;
+	u32 page_size = CEVA_SHARED_PMEM_SIZE;
+	const struct firmware *fw;
+	size_t size = 0;
+	u8 *buf = NULL;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+	cl_dbg_chip_verbose(chip, "from %s\n", filename);
+	ret = request_firmware(&fw, path_name, chip->dev);
+
+	if (ret) {
+		cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+				path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+	buf = (u8 *)fw->data;
+
+	/* Load all pages + 1 extra cache page */
+	for (page = 0; page < CEVA_MAX_PAGES + 1; page++) {
+		if (page >= CEVA_MAX_PAGES)
+			page_size = CEVA_SHARED_PMEM_CACHE_SIZE;
+
+		real_size = min_t(u32, page_size * 3, size);
+
+		if (!real_size)
+			break;
+
+		/* Copy DSP code (one page each time) */
+		ret = cl_dsp_hex_load(chip->cl_hw_tcv0, buf,
+				      CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST,
+				      page_size, size);
+		if (ret) {
+			cl_dbg_chip_err(chip, "Failed to load pmem page 0x%x!\n", page);
+			break;
+		}
+
+		cl_dsp_config_dma_for_code_copy(cl_hw_tcv0, page, page_size);
+		ret = cl_dsp_busy_wait(cl_hw_tcv0, CEVA_CPM_PDTC_REG);
+
+		if (ret) {
+			cl_dbg_err(cl_hw_tcv0, "cl_dsp_busy_wait failed\n");
+			goto out;
+		}
+
+		cl_dsp_config_dma_for_code_copy(cl_hw_tcv1, page, page_size);
+		ret = cl_dsp_busy_wait(cl_hw_tcv1, CEVA_CPM_PDTC_REG);
+
+		if (ret) {
+			cl_dbg_err(cl_hw_tcv1, "cl_dsp_busy_wait failed\n");
+			goto out;
+		}
+
+		buf += real_size;
+		size -= real_size;
+	}
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int cl_dsp_load_external_data_dual(struct cl_chip *chip, const char *filename)
+{
+	/*
+	 * Shared XMEM is not accessible by host.
+	 * Copy the XMEM section to DRAM first and then use CEVA internal DMA to copy to
+	 * SHARED XMEM.
+	 */
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	const struct firmware *fw;
+	size_t size = 0;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+	cl_dbg_chip_verbose(chip, "from %s\n", filename);
+	ret = request_firmware(&fw, path_name, chip->dev);
+
+	if (ret) {
+		cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+				path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+
+	/* TCV0 */
+	ret = cl_dsp_hex_load(cl_hw_tcv0, fw->data, REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_EXT_DATA_SIZE, size);
+
+	if (ret) {
+		cl_dbg_err(cl_hw_tcv0, "Failed to load HEX file\n");
+		goto out;
+	}
+
+	cl_dsp_config_dma_for_external_data_copy(cl_hw_tcv0);
+	ret = cl_dsp_busy_wait(cl_hw_tcv0, CEVA_CPM_DDTC_REG);
+
+	if (ret) {
+		cl_dbg_err(cl_hw_tcv0, "dsp_busy_wait failed!\n");
+		goto out;
+	}
+
+	/* TCV1 */
+	ret = cl_dsp_hex_load(cl_hw_tcv1, fw->data, REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_EXT_DATA_SIZE, size);
+
+	if (ret) {
+		cl_dbg_err(cl_hw_tcv1, "Failed to load HEX file\n");
+		goto out;
+	}
+
+	cl_dsp_config_dma_for_external_data_copy(cl_hw_tcv1);
+	ret = cl_dsp_busy_wait(cl_hw_tcv1, CEVA_CPM_DDTC_REG);
+
+	if (ret) {
+		cl_dbg_err(cl_hw_tcv1, "cl_dsp_busy_wait failed!\n");
+		goto out;
+	}
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int cl_dsp_load_data_dual(struct cl_chip *chip, const char *filename)
+{
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	const struct firmware *fw;
+	size_t size = 0;
+	char path_name[CL_PATH_MAX] = {0};
+	int ret;
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+	cl_dbg_chip_verbose(chip, "from %s\n", filename);
+	ret = request_firmware(&fw, path_name, chip->dev);
+
+	if (ret) {
+		cl_dbg_chip_err(chip, "Failed to get %s, with error: %x!\n",
+				path_name, ret);
+		goto out;
+	}
+
+	size = fw->size;
+
+	ret = cl_dsp_hex_load(cl_hw_tcv0, fw->data,
+			      REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_DATA_SIZE, size);
+
+	if (ret != 0) {
+		cl_dbg_err(cl_hw_tcv0, "Failed to load HEX file\n");
+		goto out;
+	}
+
+	ret = cl_dsp_hex_load(cl_hw_tcv1, fw->data,
+			      REG_MACDSP_API_BASE_ADDR,
+			      CEVA_DSP_DATA_SIZE, size);
+
+	if (ret != 0) {
+		cl_dbg_err(cl_hw_tcv1, "Failed to load HEX file\n");
+		goto out;
+	}
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static void cl_dsp_print_ceva_core_info(struct cl_hw *cl_hw)
+{
+	cl_dbg_trace(cl_hw, "CEVA_CORE_VERSION_ADDR=0x%X.\n",
+		     cl_reg_read(cl_hw, CEVA_CORE_VERSION_ADDR));
+	cl_dbg_trace(cl_hw, "CEVA_CORE_ID_ADDR=0x%X.\n",
+		     cl_reg_read(cl_hw, CEVA_CORE_ID_ADDR));
+}
+
+static int cl_dsp_load_dual(struct cl_chip *chip)
+{
+	int ret = 0;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	struct cl_tcv_conf *tcv0_conf = cl_hw_tcv0->conf;
+
+	modem_gcu_ceva_ctrl_external_wait_setf(cl_hw_tcv0, 0x1);
+	modem_gcu_ceva_ctrl_external_wait_setf(cl_hw_tcv1, 0x1);
+
+	cl_dsp_print_ceva_core_info(cl_hw_tcv0);
+	cl_dsp_print_ceva_core_info(cl_hw_tcv1);
+
+	ret = cl_dsp_load_code_dual(chip, tcv0_conf->ce_dsp_code);
+	if (ret != 0) {
+		cl_dbg_chip_err(chip,
+				"Failed to load DSP code. Error code %d.\n",
+				ret);
+		return ret;
+	}
+
+	ret = cl_dsp_load_external_data_dual(chip, tcv0_conf->ce_dsp_external_data);
+	if (ret != 0) {
+		cl_dbg_chip_err(chip,
+				"Failed to load DSP external data. Error code %d.\n",
+				ret);
+		return ret;
+	}
+
+	ret = cl_dsp_load_data_dual(chip, tcv0_conf->ce_dsp_data);
+	if (ret != 0) {
+		cl_dbg_chip_err(chip,
+				"Failed to load DSP data. Error code %d.\n",
+				ret);
+		return ret;
+	}
+
+	macdsp_api_config_space_set(cl_hw_tcv0, 0);
+	/* Release DSP wait. */
+	cl_dsp_boot(cl_hw_tcv0);
+
+	macdsp_api_config_space_set(cl_hw_tcv1, 0);
+	/* Release DSP wait. */
+	cl_dsp_boot(cl_hw_tcv1);
+
+	return ret;
+}
+
+static int _cl_dsp_load(struct cl_hw *cl_hw)
+{
+	int ret = 0;
+
+	modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0x1);
+	cl_dsp_print_ceva_core_info(cl_hw);
+
+	ret = cl_dsp_load_code(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load DSP code %d\n", ret);
+		return ret;
+	}
+
+	ret = cl_dsp_load_external_data(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load DSP external data %d\n", ret);
+		return ret;
+	}
+
+	ret = cl_dsp_load_data(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load DSP data %d\n", ret);
+		return ret;
+	}
+
+	macdsp_api_config_space_set(cl_hw, 0);
+	/* Release DSP wait */
+	cl_dsp_boot(cl_hw);
+
+	return ret;
+}
+
+int cl_dsp_load_regular(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	if (cl_dsp_is_universal_file(chip))
+		return cl_dsp_load_dual(chip);
+
+	if (cl_chip_is_tcv0_enabled(chip)) {
+		ret = _cl_dsp_load(chip->cl_hw_tcv0);
+		if (ret)
+			return ret;
+	}
+
+	if (cl_chip_is_tcv1_enabled(chip)) {
+		ret = _cl_dsp_load(chip->cl_hw_tcv1);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cl_dsp_load_recovery(struct cl_hw *cl_hw)
+{
+	int ret = 0;
+
+	modem_gcu_ceva_ctrl_external_wait_setf(cl_hw, 0x1);
+
+	ret = cl_dsp_load_external_data(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load DSP external data %d\n", ret);
+		return ret;
+	}
+
+	ret = cl_dsp_load_data(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "Failed to load DSP data %d\n", ret);
+		return ret;
+	}
+
+	macdsp_api_config_space_set(cl_hw, 0);
+	/* Release DSP wait. */
+	cl_dsp_boot(cl_hw);
+
+	return ret;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 23/96] cl8k: add dsp.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (21 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 22/96] cl8k: add dsp.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 24/96] cl8k: add e2p.c viktor.barna
                   ` (72 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/dsp.h | 27 ++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/dsp.h

diff --git a/drivers/net/wireless/celeno/cl8k/dsp.h b/drivers/net/wireless/celeno/cl8k/dsp.h
new file mode 100644
index 000000000000..006043983ae3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/dsp.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_DSP_H
+#define CL_DSP_H
+
+#include "chip.h"
+
+/*
+ * cl_dsp_load_regular - Load DSP firmware for both TCV's.
+ *
+ * @chip - chip pointer.
+ *
+ * Return value: 0 upon success, negative errno code upon failure.
+ */
+int cl_dsp_load_regular(struct cl_chip *chip);
+
+/*
+ * cl_dsp_load_recovery - Load only DSP data for single TCV.
+ *
+ * @chip - chip pointer.
+ *
+ * Return value: 0 upon success, negative errno code upon failure.
+ */
+int cl_dsp_load_recovery(struct cl_hw *cl_hw);
+
+#endif /* CL_DSP_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 24/96] cl8k: add e2p.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (22 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 23/96] cl8k: add dsp.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 25/96] cl8k: add e2p.h viktor.barna
                   ` (71 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/e2p.c | 771 +++++++++++++++++++++++++
 1 file changed, 771 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.c

diff --git a/drivers/net/wireless/celeno/cl8k/e2p.c b/drivers/net/wireless/celeno/cl8k/e2p.c
new file mode 100644
index 000000000000..14e9a4498046
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.c
@@ -0,0 +1,771 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+
+#include "chip.h"
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "config.h"
+#include "utils.h"
+#include "e2p.h"
+#include "calib.h"
+#include "debug.h"
+
+#define EEPROM_VERSION 3
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+/* EEPROM Parameters - Suitable for ST-M24256 */
+#define E2P_SIZE       0x8000              /* 32KB = 256Kbit */
+#define E2P_PAGE_SIZE  0x40                /* 64 Bytes */
+#define E2P_PAGE_MASK  (E2P_PAGE_SIZE - 1) /* 0x3F */
+#define E2P_PAGE_SHIFT 0x6
+#else
+/* EEPROM Parameters - Suitable for ATMEL AT24C16BN */
+#define E2P_SIZE       0x800               /* 2KB = 16Kbit */
+#define E2P_PAGE_SIZE  0x10                /* 16 Bytes */
+#define E2P_PAGE_MASK  (E2P_PAGE_SIZE - 1) /* 0xF */
+#define E2P_PAGE_SHIFT 0x4
+#endif
+
+#define PAGE_NUM(addr) ((addr) >> E2P_PAGE_SHIFT)
+#define PAGE_OFF(addr) ((addr) & E2P_PAGE_MASK)
+
+#define CH_LIST_SIZE_CL80X0         59
+#define CH_LIST_SIZE_CL80X6         105
+
+static const u8 chan_list_cl80x0[CH_LIST_SIZE_CL80X0] = {
+	36, 38, 40, 42, 44, 46, 48, 50,
+	52, 54, 56, 58, 60, 62, 64, 100,
+	102, 104, 106, 108, 110, 112, 114, 116,
+	118, 120, 122, 124, 126, 128, 132, 134,
+	136, 138, 140, 142, 144, 149, 151, 153,
+	155, 157, 159, 161, 165, 1, 2, 3,
+	4, 5, 6, 7, 8, 9, 10, 11,
+	12, 13, 14
+};
+
+static const u16 chan_list_cl80x6[CH_LIST_SIZE_CL80X6] = {
+	1, 2, 5, 9, 13, 17, 21, 25,
+	29, 33, 37, 41, 45, 49, 53, 57,
+	61, 65, 69, 73, 77, 81, 85, 89,
+	93, 97, 101, 105, 109, 113, 117, 121,
+	125, 129, 133, 137, 141, 145, 149, 153,
+	157, 161, 165, 169, 173, 177, 181, 185,
+	189, 193, 197, 201, 205, 209, 213, 217,
+	221, 225, 229, 233, 36, 38, 40, 42,
+	44, 46, 48, 50, 52, 54, 56, 58,
+	60, 62, 64, 100, 102, 104, 106, 108,
+	110, 112, 114, 116, 118, 120, 122, 124,
+	126, 128, 132, 134, 136, 138, 140, 142,
+	144, 149, 151, 153, 155, 157, 159, 161,
+	165
+};
+
+enum bit_num {
+	BIT0,
+	BIT1,
+	BIT2,
+	BIT3,
+	BIT4,
+	BIT5,
+	BIT6,
+	BIT7,
+};
+
+struct cl_e2p_work {
+	struct work_struct ws;
+	struct cl_chip *chip;
+};
+
+/*
+ * MACSYS_I2C:: PRERLO (0x0) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERLO (I2C_REG_BASE_ADDR + 0x0)
+
+/*
+ * MACSYS_I2C:: PRERHI (0x4) - Clock Prescale register lo-byte
+ * Width: 8, Access: RW, Reset: 0xff.
+ */
+#define I2C_PRERHI (I2C_REG_BASE_ADDR + 0x4)
+
+/*
+ * MACSYS_I2C:: CTR (0x8) - Control Register
+ * Width: 8, Access: RW, Reset: 0x00.
+ */
+#define I2C_CTR (I2C_REG_BASE_ADDR + 0x8)
+
+#define EN (BIT7) /* ‘1’ the core is enabled. */
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Data
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 TXD */
+#define TXD (BIT0) /* Next byte to transmit via I2C */
+
+#define TXD_MASK (0xFF << TXD)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Transmit Register - Address
+ * Width: 8, Access: W, Reset: 0x00.
+ */
+#define I2C_TXADDR (I2C_REG_BASE_ADDR + 0xC)
+
+/*
+ * 7:1 TXADDR
+ * 0 RDWR
+ */
+#define TXADDR (BIT1) /* I2C Slave Address */
+#define RDWR   (BIT0) /* ‘1’ = reading from slave. ‘0’ = writing to slave. */
+
+#define TXADDR_MASK (0x7F << TXADDR)
+
+/*
+ * MACSYS_I2C:: TXR_RXR (0xC) - Receive Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_RXD (I2C_REG_BASE_ADDR + 0xC)
+
+/* 7:0 RXD */
+#define RXD (BIT0) /* Last byte received via I2C. */
+#define RXD_MASK (0xFF << RXD)
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Command Register
+ * Width: 8, Access: WC, Reset: 0x00.
+ */
+#define I2C_CR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 STA
+ * 6 STO
+ * 5 RD
+ * 4 WR
+ * 3 ACK
+ * 2:1 RES
+ * 0 IACK
+ */
+#define STA  (BIT7) /* Generate (repeated) start condition. */
+#define STO  (BIT6) /* Generate stop condition. */
+#define RD   (BIT5) /* Read from slave. */
+#define WR   (BIT4) /* Write to slave. */
+#define ACK  (BIT3) /* When a receiver, sent ACK (ACK = ‘0’) or NACK (NACK = ‘1’). */
+#define IACK (BIT0) /* Interrupt acknowledge, When set, clears a pending interrupt. */
+
+/*
+ * MACSYS_I2C:: CR_SR (0x10) - Status Register
+ * Width: 8, Access: R, Reset: 0x00.
+ */
+#define I2C_SR (I2C_REG_BASE_ADDR + 0x10)
+
+/*
+ * 7 RX_ACK - Received acknowledge from slave - ‘1’ = No acknowledge received.
+ * 6 BUSY - I2C bus busy - ‘1’ after START signal detected. ‘0’ after STOP signal detected.
+ * 5 AL - Arbitration lost - This bit is set when the core lost arbitration.
+ * 4:2 RES
+ * 1 TIP - Transfer in progress. ‘1’ when transferring data. ‘0’ when transfer complete.
+ * 0 IF - Set when interrupt is pending, cause a processor interrupt if the IEN bit is set.
+ */
+#define RX_ACK (BIT7)
+#define BUSY   (BIT6)
+#define AL     (BIT5)
+#define TIP    (BIT1)
+#define IF     (BIT0)
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 8) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+#else
+#define I2C_EEPROM_ADDR(page) (0xA0 | (((page) >> 3) & 0xE)) /* [1-0-1-0-P2-P1-P0-0] */
+#endif
+
+/* E2P_MAX_POLLS should not exceed 12 iterations (attemts) */
+#define E2P_MAX_POLLS 500
+#define E2P_INITIAL_DELAY 32
+
+static int i2c_poll_xfer_acked(struct cl_chip *chip)
+{
+	u32 val = cl_reg_read_chip(chip, I2C_SR);
+	int cnt = E2P_MAX_POLLS;
+	unsigned long delay = E2P_INITIAL_DELAY;
+
+	while ((val & BIT(TIP)) && cnt--) {
+		udelay(delay);
+		val = cl_reg_read_chip(chip, I2C_SR);
+		delay <<= 1;
+	}
+	++cnt;
+
+	while ((val & BIT(RX_ACK)) && cnt--) {
+		udelay(delay);
+		val = cl_reg_read_chip(chip, I2C_SR);
+		delay <<= 1;
+	}
+
+	if (cnt >= 0)
+		return 0;
+
+	cl_dbg_chip_err(chip, "ACK FAILED\n");
+	cl_dbg_chip_trace(chip, "I2C_POLL_XFER_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+	return -EBADE;
+}
+
+static int i2c_poll_xfer_no_acked(struct cl_chip *chip)
+{
+	u32 val = cl_reg_read_chip(chip, I2C_SR);
+	int cnt = E2P_MAX_POLLS;
+	unsigned long delay = E2P_INITIAL_DELAY;
+
+	while ((val & BIT(TIP)) && cnt--) {
+		udelay(delay);
+		val = cl_reg_read_chip(chip, I2C_SR);
+		delay <<= 1;
+	}
+
+	++cnt;
+
+	while (!(val & BIT(RX_ACK)) && cnt--) {
+		udelay(delay);
+		val = cl_reg_read_chip(chip, I2C_SR);
+		delay <<= 1;
+	}
+
+	if (cnt >= 0)
+		return 0;
+
+	cl_dbg_chip_err(chip, "NO ACK FAILED\n");
+	cl_dbg_chip_trace(chip, "I2C_POLL_XFER_NO_ACKED: val=%Xh, cnt=%d.\n", val, cnt);
+
+	return -EBADE;
+}
+
+static void i2c_write_start(struct cl_chip *chip, u16 page)
+{
+	u32 addr = I2C_EEPROM_ADDR(page) & TXADDR_MASK;
+
+	cl_reg_write_chip(chip, I2C_TXADDR, addr);
+	cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static void i2c_write(struct cl_chip *chip, u8 data)
+{
+	cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+	cl_reg_write_chip(chip, I2C_CR, BIT(WR));
+}
+
+static void i2c_write_stop(struct cl_chip *chip, u8 data)
+{
+	cl_reg_write_chip(chip, I2C_TXD, data & TXD_MASK);
+	cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(WR));
+}
+
+static void i2c_read_start(struct cl_chip *chip, u16 page)
+{
+	u32 addr = (I2C_EEPROM_ADDR(page) & TXADDR_MASK) | BIT(RDWR);
+
+	cl_reg_write_chip(chip, I2C_TXADDR, addr);
+	cl_reg_write_chip(chip, I2C_CR, BIT(STA) | BIT(WR));
+}
+
+static int i2c_read_stop(struct cl_chip *chip, u8 *data)
+{
+	int ret = 0;
+
+	cl_reg_write_chip(chip, I2C_CR, BIT(STO) | BIT(RD) | BIT(ACK));
+	ret = i2c_poll_xfer_no_acked(chip);
+	if (ret < 0)
+		return ret;
+	*data = cl_reg_read_chip(chip, I2C_RXD) & RXD_MASK;
+	return 0;
+}
+
+static void e2p_reg_set_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+	u32 regval = cl_reg_read_chip(chip, reg);
+
+	regval |= bit;
+	cl_reg_write_chip(chip, reg, regval);
+}
+
+static void e2p_reg_clear_bit(struct cl_chip *chip, u32 reg, u32 bit)
+{
+	u32 regval = cl_reg_read_chip(chip, reg);
+
+	regval &= ~bit;
+	cl_reg_write_chip(chip, reg, regval);
+}
+
+/*
+ * helpers for cl_e2p_write_addr_bytes()
+ */
+static inline u16 cl_e2p_addrbyte_lo(u16 v)
+{
+	return v & 0xff;
+}
+
+static inline u16 cl_e2p_addrbyte_hi(u16 v)
+{
+	return (v >> 8) & 0xff;
+}
+
+/*
+ * Helper writing address byte(s) to the eeprom, some eeprom need two
+ * byte address cycles, some need only one.
+ */
+static int cl_e2p_write_addr_bytes(struct cl_chip *chip, u16 addr)
+{
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	int ret = 0;
+
+	/* Addr 8 msbits are 8 bits msb page */
+	i2c_write(chip, cl_e2p_addrbyte_hi(addr));
+
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+#endif
+	/* Addr 8 lsbits are 4 bits page lsbits or`ed with 4 bits page offset */
+	i2c_write(chip, cl_e2p_addrbyte_lo(addr));
+
+	return i2c_poll_xfer_acked(chip);
+}
+
+static void e2p_enable(struct cl_chip *chip)
+{
+	/* Disable I2C Core */
+	e2p_reg_clear_bit(chip, I2C_CTR, BIT(EN));
+
+	/*
+	 * Set Pre-Scaler LO
+	 * pclk = 240MHz, desired SCL = 400KHz.
+	 * Prescale = [240e6 / (5*400e3) ] – 1 = 120 -1 = 119 = 77h
+	 */
+	cl_reg_write_chip(chip, I2C_PRERLO, 0x77);
+
+	/* Set Pre-Scaler HI */
+	cl_reg_write_chip(chip, I2C_PRERHI, 0x0);
+
+	/* Enable I2C Core */
+	e2p_reg_set_bit(chip, I2C_CTR, BIT(EN));
+}
+
+static int e2p_read_byte(struct cl_chip *chip, u16 addr, u8 *pbyte)
+{
+	int ret = 0;
+
+	if (addr > E2P_SIZE) {
+		cl_dbg_chip_err(chip, "Wrong addr or len\n");
+		return -EFAULT;
+	}
+
+	/* Clock in the address to read from. */
+	i2c_write_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_e2p_write_addr_bytes(chip, addr);
+	if (ret)
+		return ret;
+
+	/* Read single byte */
+	i2c_read_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	return i2c_read_stop(chip, pbyte);
+}
+
+static int e2p_write_page(struct cl_chip *chip, u16 addr, u8 *val, u16 num_of_bytes)
+{
+	/*
+	 * This is a write page (up to E2P_PAGE_SIZE bytes) operation indicating the offset
+	 * to write to.
+	 */
+	int i;
+	int ret = 0;
+
+	if (num_of_bytes > E2P_PAGE_SIZE)
+		return -EMSGSIZE;
+
+	/* Clock in the address to write to. */
+	i2c_write_start(chip, PAGE_NUM(addr));
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_e2p_write_addr_bytes(chip, addr);
+	if (ret)
+		return ret;
+
+	/* Clock in the data to write. */
+	for (i = 0; i < (num_of_bytes - 1); i++, val++) {
+		i2c_write(chip, *val);
+		ret = i2c_poll_xfer_acked(chip);
+		if (ret)
+			return ret;
+	}
+
+	/* Clock in the last data byte to write */
+	i2c_write_stop(chip, *val);
+	ret = i2c_poll_xfer_acked(chip);
+	if (ret)
+		return ret;
+
+	/* Wait for the write to finish */
+	mdelay(6);
+
+	return ret;
+}
+
+static int e2p_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+	u16 bytes_on_curr_page = 0, bytes_left_to_write = num_of_bytes;
+	int ret = 0;
+
+	do {
+		bytes_on_curr_page = E2P_PAGE_SIZE - PAGE_OFF(addr);
+		bytes_on_curr_page = min(bytes_left_to_write, bytes_on_curr_page);
+		bytes_left_to_write -= bytes_on_curr_page;
+
+		ret = e2p_write_page(chip, addr, val, bytes_on_curr_page);
+		if (ret) {
+			cl_dbg_chip_err(chip,
+					"Error writing page %u offset %u, ret %d\n",
+					PAGE_NUM(addr), PAGE_OFF(addr), ret);
+			/* Written less bytes than num_of_bytes */
+			return 0;
+		}
+
+		addr += bytes_on_curr_page;
+		val += bytes_on_curr_page;
+	} while (bytes_left_to_write);
+
+	return num_of_bytes - bytes_left_to_write;
+}
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+static void cl_e2p_init_calib_ch_bmp_per_bw(struct cl_hw *cl_hw, int data_elem_num,
+					    u16 channel_list[], int bw, int bmp_size,
+					    int bmp_addr, int eeprom_data_size, int data_addr)
+{
+	u8 chan_idx;
+	u8 chan_bmp[SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0] = {0};
+	u8 chan_bmp_prev[SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0] = {0};
+	struct eeprom_calib_data zero_calib = {0};
+	int i;
+
+	for (i = 0; i < data_elem_num; i++) {
+		chan_idx = cl_calib_dcoc_channel_bw_to_idx(cl_hw, channel_list[i], bw);
+		if (channel_list[i] && chan_idx != INVALID_CHAN_IDX)
+			chan_bmp[chan_idx / BITS_PER_BYTE] |= (BIT(chan_idx % BITS_PER_BYTE));
+	}
+
+	cl_e2p_read(cl_hw->chip, chan_bmp_prev, bmp_size, bmp_addr);
+	if (memcmp(chan_bmp, chan_bmp_prev, bmp_size))
+		for (i = 0; i < data_elem_num; i++)
+			cl_e2p_write(cl_hw->chip, (u8 *)&zero_calib,
+				     (u16)sizeof(struct eeprom_calib_data),
+				     data_addr + (i *
+				     (u16)sizeof(struct eeprom_calib_data)));
+
+	cl_e2p_write(cl_hw->chip, chan_bmp, bmp_size,
+		     bmp_addr);
+}
+
+static void cl_e2p_init_calib_ch_bmp(struct cl_hw *cl_hw)
+{
+	if (cl_hw->tcv_idx == 0) {
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_20mhz,
+						CHNL_BW_20, SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_40mhz,
+						CHNL_BW_40, SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_80mhz,
+						CHNL_BW_80, SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0,
+						cl_hw->conf->ci_calib_eeprom_channels_160mhz,
+						CHNL_BW_160, SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV0,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0,
+						SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV0,
+						ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV0);
+	} else {
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_20mhz,
+						CHNL_BW_20, SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_40mhz,
+						CHNL_BW_40, SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_80mhz,
+						CHNL_BW_80, SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1);
+
+		cl_e2p_init_calib_ch_bmp_per_bw(cl_hw, EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV1,
+						cl_hw->conf->ci_calib_eeprom_channels_160mhz,
+						CHNL_BW_160, SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV1,
+						ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1,
+						SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV1,
+						ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV1);
+	}
+}
+
+static void e2p_read_eeprom_handler(struct work_struct *ws)
+{
+	struct cl_e2p_work *e2p_work = container_of(ws, struct cl_e2p_work, ws);
+	struct cl_chip *chip = e2p_work->chip;
+	u8 *cache = (u8 *)chip->eeprom_cache;
+	u16 i;
+
+	if (chip->conf->ce_eeprom_mode == E2P_MODE_EEPROM)
+		for (i = EEPROM_BASIC_NUM_BYTES; i < EEPROM_NUM_BYTES; i++)
+			if (e2p_read_byte(chip, i, &cache[i]) < 0)
+				return;
+
+	if (chip->cl_hw_tcv0)
+		cl_e2p_init_calib_ch_bmp(chip->cl_hw_tcv0);
+	if (chip->cl_hw_tcv1)
+		cl_e2p_init_calib_ch_bmp(chip->cl_hw_tcv1);
+
+	chip->is_calib_eeprom_loaded = 1;
+}
+
+void cl_e2p_read_eeprom_start_work(struct cl_chip *chip)
+{
+	struct cl_e2p_work *e2p_work = kzalloc(sizeof(*e2p_work), GFP_ATOMIC);
+
+	if (!e2p_work)
+		return;
+
+	e2p_work->chip = chip;
+	INIT_WORK(&e2p_work->ws, e2p_read_eeprom_handler);
+	queue_work(chip->chip_workqueue, &e2p_work->ws);
+}
+#endif
+
+static int e2p_load_from_eeprom(struct cl_chip *chip)
+{
+	u8 *cache = (u8 *)chip->eeprom_cache;
+	u16 i;
+	int ret = 0;
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	u16 eeprom_load_len = EEPROM_BASIC_NUM_BYTES;
+#else
+	u16 eeprom_load_len = EEPROM_NUM_BYTES;
+#endif
+
+	for (i = 0; i < eeprom_load_len; i++) {
+		ret = e2p_read_byte(chip, i, &cache[i]);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int e2p_eeprom_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+	void *read_block = NULL;
+
+	if (!val)
+		return -EFAULT;
+
+	if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+		return -ENXIO;
+
+	read_block = (u8 *)chip->eeprom_cache + addr;
+	memcpy(val, read_block, num_of_bytes);
+
+	return num_of_bytes;
+}
+
+static int e2p_eeprom_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+	int bytes_written = -EIO;
+	void *write_block = NULL;
+
+	if (!val)
+		return -EFAULT;
+
+	if (addr + num_of_bytes > EEPROM_NUM_BYTES)
+		return -ENXIO;
+
+	bytes_written = e2p_write_block(chip, addr, num_of_bytes, val);
+	write_block = (u8 *)chip->eeprom_cache + addr;
+	memcpy(write_block, val, num_of_bytes);
+
+	return bytes_written;
+}
+
+static int e2p_load_from_bin(struct cl_chip *chip)
+{
+	char filename[CL_FILENAME_MAX];
+	size_t size = 0;
+	char *buf = NULL;
+	int ret = 0;
+
+	if (cl_chip_is_6g(chip))
+		snprintf(filename, sizeof(filename),
+			 "eeprom%u_cl80x6.bin", chip->idx);
+	else
+		snprintf(filename, sizeof(filename),
+			 "eeprom%u_cl80x0.bin", chip->idx);
+
+	size = cl_file_open_and_read(chip, filename,
+				     (char **)&buf);
+
+	if (size < EEPROM_BASIC_NUM_BYTES) {
+		cl_dbg_chip_err(chip,
+				"Invalid EEPROM size - %s (actual %zu) (min size %d)\n",
+				filename, size, EEPROM_BASIC_NUM_BYTES);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (size > EEPROM_NUM_BYTES) {
+		cl_dbg_chip_err(chip,
+				"Invalid EEPROM size - %s (actual %zu) (max size %d)\n",
+				filename, size, EEPROM_NUM_BYTES);
+		ret = -EFBIG;
+		goto err;
+	}
+
+	if (!buf) {
+		cl_dbg_chip_err(chip, "EEPROM data buffer is empty\n");
+
+		ret = -ENODATA;
+		goto err;
+	}
+
+	chip->eeprom_bin_size = size;
+	memcpy(chip->eeprom_cache, buf, size);
+
+err:
+	kfree(buf);
+
+	return ret;
+}
+
+static int e2p_bin_write_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+	return -EOPNOTSUPP;
+}
+
+static int e2p_bin_read_block(struct cl_chip *chip, u16 addr, u16 num_of_bytes, u8 *val)
+{
+	u8 *base;
+	u16 *offset_addr;
+
+	if (!val)
+		return -EFAULT;
+
+	if (addr + num_of_bytes > chip->eeprom_bin_size)
+		return -ENXIO;
+
+	base = (u8 *)chip->eeprom_cache;
+	offset_addr = (u16 *)(base + addr);
+	memmove(val, offset_addr, num_of_bytes);
+
+	return num_of_bytes;
+}
+
+static int cl_e2p_init_bin(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	ret = e2p_load_from_bin(chip);
+	if (ret)
+		return ret;
+
+	chip->eeprom_read_block = e2p_bin_read_block;
+	chip->eeprom_write_block = e2p_bin_write_block;
+
+	return ret;
+}
+
+static int cl_e2p_init_eeprom(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	e2p_enable(chip);
+
+	ret = e2p_load_from_eeprom(chip);
+	if (ret)
+		return ret;
+
+	chip->eeprom_read_block = e2p_eeprom_read_block;
+	chip->eeprom_write_block = e2p_eeprom_write_block;
+
+	return ret;
+}
+
+int cl_e2p_init(struct cl_chip *chip)
+{
+	u8 eeprom_mode = chip->conf->ce_eeprom_mode;
+
+	chip->eeprom_cache = kzalloc(EEPROM_NUM_BYTES, GFP_KERNEL);
+	if (!chip->eeprom_cache)
+		return -ENOMEM;
+
+	if (eeprom_mode == E2P_MODE_BIN)
+		return cl_e2p_init_bin(chip);
+	else if (eeprom_mode == E2P_MODE_EEPROM)
+		return cl_e2p_init_eeprom(chip);
+
+	return -EINVAL;
+}
+
+void cl_e2p_close(struct cl_chip *chip)
+{
+	kfree(chip->eeprom_cache);
+}
+
+int cl_e2p_write(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+	if (size != chip->eeprom_write_block(chip, addr, size, data)) {
+		cl_dbg_chip_err(chip, "Error writing eeprom addr 0x%x\n", addr);
+		return -EBADE;
+	}
+
+	return 0;
+}
+
+int cl_e2p_read(struct cl_chip *chip, u8 *data, u16 size, u16 addr)
+{
+	if (size != chip->eeprom_read_block(chip, addr, size, data)) {
+		cl_dbg_chip_err(chip, "Error reading eeprom addr 0x%x\n", addr);
+		return -EBADE;
+	}
+
+	return 0;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 25/96] cl8k: add e2p.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (23 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 24/96] cl8k: add e2p.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 26/96] cl8k: add eeprom.h viktor.barna
                   ` (70 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/e2p.h | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/e2p.h

diff --git a/drivers/net/wireless/celeno/cl8k/e2p.h b/drivers/net/wireless/celeno/cl8k/e2p.h
new file mode 100644
index 000000000000..3545e1d110f1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/e2p.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_E2P_H
+#define CL_E2P_H
+
+#include <linux/types.h>
+
+#include "chip.h"
+#include "eeprom.h"
+
+enum {
+	E2P_MODE_BIN,
+	E2P_MODE_EEPROM,
+
+	E2P_MODE_MAX
+};
+
+int cl_e2p_init(struct cl_chip *chip);
+void cl_e2p_close(struct cl_chip *chip);
+int cl_e2p_write(struct cl_chip *chip, u8 *data, u16 size, u16 addr);
+int cl_e2p_read(struct cl_chip *chip, u8 *data, u16 size, u16 addr);
+void cl_e2p_read_eeprom_start_work(struct cl_chip *chip);
+
+#endif /* CL_E2P_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 26/96] cl8k: add eeprom.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (24 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 25/96] cl8k: add e2p.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 27/96] cl8k: add ela.c viktor.barna
                   ` (69 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/eeprom.h | 283 ++++++++++++++++++++++
 1 file changed, 283 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/eeprom.h

diff --git a/drivers/net/wireless/celeno/cl8k/eeprom.h b/drivers/net/wireless/celeno/cl8k/eeprom.h
new file mode 100644
index 000000000000..2680af90484b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/eeprom.h
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_EEPROM_H
+#define CL_EEPROM_H
+
+#include <linux/kernel.h>
+
+#include "def.h"
+#include "phy.h"
+#include "calib.h"
+
+#define SERIAL_NUMBER_SIZE 32
+#define BIT_MAP_SIZE   20
+#define EXT_BIT_MAP_SIZE (BIT_MAP_SIZE * 2)
+#define NUM_OF_PIVOTS  20
+#define NUM_PIVOT_PHYS (MAX_ANTENNAS * NUM_OF_PIVOTS)
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+#define BIT_MAP_SIZE_20MHZ_TCV0  9
+#define BIT_MAP_SIZE_20MHZ_TCV1  6
+#define BIT_MAP_SIZE_40MHZ_TCV0  4
+#define BIT_MAP_SIZE_40MHZ_TCV1  4
+#define BIT_MAP_SIZE_80MHZ_TCV0  2
+#define BIT_MAP_SIZE_80MHZ_TCV1  2
+#define BIT_MAP_SIZE_160MHZ_TCV0 1
+#define BIT_MAP_SIZE_160MHZ_TCV1 3
+
+#define EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0   10
+#define EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1   7
+#define EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0   9
+#define EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1   7
+#define EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0   8
+#define EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1   6
+#define EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0  6
+#define EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV1  2
+#endif
+
+struct eeprom_hw {
+	u8 reserved[96];
+} __packed;
+
+struct eeprom_general {
+	u8 version;
+	u8 flavor;
+	u8 mac_address[6];
+	u8 temp_diff; /* Default value TEMP_DIFF_INVALID = 0x7F */
+	u8 serial_number[SERIAL_NUMBER_SIZE];
+	u8 pwr_table_id[2];
+	u8 reserved[53];
+} __packed;
+
+struct eeprom_fem {
+	u8 wiring_id;
+	u16 fem_lut[FEM_TYPE_MAX];
+	u32 platform_id;
+	u8 reserved[19];
+} __packed;
+
+struct eeprom_phy_calib {
+	s8 pow;
+	s8 offset;
+	s8 tmp;
+} __packed;
+
+struct point {
+	u8 chan;
+	u8 phy;
+	u8 idx;
+	u16 addr;
+	struct eeprom_phy_calib calib;
+} __packed;
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+struct iq {
+	__le32 coef0;
+	__le32 coef1;
+	__le32 coef2;
+	__le32 gain;
+} __packed;
+
+struct score {
+	s8 iq_tx_score;
+	s8 iq_tx_worst_score;
+	s8 iq_rx_score;
+	s8 iq_rx_worst_score;
+	s16 dcoc_i_mv[DCOC_LNA_GAIN_NUM];
+	s16 dcoc_q_mv[DCOC_LNA_GAIN_NUM];
+	s32 lolc_score;
+} __packed;
+
+struct eeprom_calib_data {
+	u8 valid;
+	u8 temperature;
+	u32 lolc[MAX_ANTENNAS];
+	struct cl_dcoc_calib dcoc[MAX_ANTENNAS][DCOC_LNA_GAIN_NUM];
+	struct iq iq_tx[MAX_ANTENNAS];
+	struct iq iq_rx[MAX_ANTENNAS];
+	struct score score[MAX_ANTENNAS];
+} __packed;
+#endif
+
+struct eeprom_calib_power {
+	u16 freq_offset;
+	u8 chan_bmp[BIT_MAP_SIZE];
+	struct eeprom_phy_calib phy_calib[NUM_PIVOT_PHYS];
+} __packed;
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+struct eeprom_calib_iq_dcoc {
+	u8 calib_version;
+	u8 chan_20mhz_bmp_tcv0[BIT_MAP_SIZE_20MHZ_TCV0];
+	u8 chan_20mhz_bmp_tcv1[BIT_MAP_SIZE_20MHZ_TCV1];
+	u8 chan_40mhz_bmp_tcv0[BIT_MAP_SIZE_40MHZ_TCV0];
+	u8 chan_40mhz_bmp_tcv1[BIT_MAP_SIZE_40MHZ_TCV1];
+	u8 chan_80mhz_bmp_tcv0[BIT_MAP_SIZE_80MHZ_TCV0];
+	u8 chan_80mhz_bmp_tcv1[BIT_MAP_SIZE_80MHZ_TCV1];
+	u8 chan_160mhz_bmp_tcv0[BIT_MAP_SIZE_160MHZ_TCV0];
+	u8 chan_160mhz_bmp_tcv1[BIT_MAP_SIZE_160MHZ_TCV1];
+	struct eeprom_calib_data
+		calib_20_data_tcv0[EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0];
+	struct eeprom_calib_data
+		calib_20_data_tcv1[EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1];
+	struct eeprom_calib_data
+		calib_40_data_tcv0[EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0];
+	struct eeprom_calib_data
+		calib_40_data_tcv1[EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1];
+	struct eeprom_calib_data
+		calib_80_data_tcv0[EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0];
+	struct eeprom_calib_data
+		calib_80_data_tcv1[EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1];
+	struct eeprom_calib_data
+		calib_160_data_tcv0[EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0];
+	struct eeprom_calib_data
+		calib_160_data_tcv1[EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV1];
+} __packed;
+#endif
+
+struct eeprom {
+	struct eeprom_hw hw;
+	struct eeprom_general general;
+	struct eeprom_fem fem;
+	struct eeprom_calib_power calib_power;
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	struct eeprom_calib_iq_dcoc calib_iq_dcoc;
+#endif
+} __packed;
+
+enum {
+	ADDR_HW = offsetof(struct eeprom, hw),
+	ADDR_HW_RESERVED = ADDR_HW + offsetof(struct eeprom_hw, reserved),
+
+	ADDR_GEN = offsetof(struct eeprom, general),
+	ADDR_GEN_VERSION = ADDR_GEN + offsetof(struct eeprom_general, version),
+	ADDR_GEN_FLAVOR = ADDR_GEN + offsetof(struct eeprom_general, flavor),
+	ADDR_GEN_MAC_ADDR = ADDR_GEN + offsetof(struct eeprom_general, mac_address),
+	ADDR_GEN_TEMP_DIFF = ADDR_GEN + offsetof(struct eeprom_general, temp_diff),
+	ADDR_GEN_SERIAL_NUMBER = ADDR_GEN + offsetof(struct eeprom_general, serial_number),
+	ADDR_GEN_PWR_TABLE_ID = ADDR_GEN + offsetof(struct eeprom_general, pwr_table_id),
+	ADDR_GEN_RESERVED = ADDR_GEN + offsetof(struct eeprom_general, reserved),
+
+	ADDR_FEM = offsetof(struct eeprom, fem),
+	ADDR_FEM_WIRING_ID = ADDR_FEM + offsetof(struct eeprom_fem, wiring_id),
+	ADDR_FEM_LUT = ADDR_FEM + offsetof(struct eeprom_fem, fem_lut),
+	ADDR_FEM_PLATFORM_ID = ADDR_FEM + offsetof(struct eeprom_fem, platform_id),
+	ADDR_FEM_RESERVED = ADDR_FEM + offsetof(struct eeprom_fem, reserved),
+
+	ADDR_CALIB_POWER = offsetof(struct eeprom, calib_power),
+	ADDR_CALIB_POWER_FREQ_OFFSET = ADDR_CALIB_POWER +
+		offsetof(struct eeprom_calib_power, freq_offset),
+	ADDR_CALIB_POWER_CHAN_BMP = ADDR_CALIB_POWER +
+		offsetof(struct eeprom_calib_power, chan_bmp),
+	ADDR_CALIB_POWER_PHY = ADDR_CALIB_POWER +
+		offsetof(struct eeprom_calib_power, phy_calib),
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	ADDR_CALIB_IQ_DCOC = offsetof(struct eeprom, calib_iq_dcoc),
+	ADDR_CALIB_IQ_DCOC_VERSION = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_version),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_20mhz_bmp_tcv0),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_20mhz_bmp_tcv1),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_40mhz_bmp_tcv0),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_40mhz_bmp_tcv1),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_80mhz_bmp_tcv0),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_80mhz_bmp_tcv1),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_160mhz_bmp_tcv0),
+	ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, chan_160mhz_bmp_tcv1),
+	ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_20_data_tcv0),
+	ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_20_data_tcv1),
+	ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_40_data_tcv0),
+	ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_40_data_tcv1),
+	ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_80_data_tcv0),
+	ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_80_data_tcv1),
+	ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV0 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_160_data_tcv0),
+	ADDR_CALIB_IQ_DCOC_DATA_160MHZ_TCV1 = ADDR_CALIB_IQ_DCOC +
+		offsetof(struct eeprom_calib_iq_dcoc, calib_160_data_tcv1),
+#endif
+	SIZE_HW = sizeof(struct eeprom_hw),
+	SIZE_HW_RESERVED = ADDR_GEN - ADDR_HW_RESERVED,
+
+	SIZE_GEN = sizeof(struct eeprom_general),
+	SIZE_GEN_VERSION = ADDR_GEN_FLAVOR - ADDR_GEN_VERSION,
+	SIZE_GEN_FLAVOR = ADDR_GEN_MAC_ADDR - ADDR_GEN_FLAVOR,
+	SIZE_GEN_MAC_ADDR = ADDR_GEN_TEMP_DIFF - ADDR_GEN_MAC_ADDR,
+	SIZE_GEN_TEMP_DIFF = ADDR_GEN_SERIAL_NUMBER - ADDR_GEN_TEMP_DIFF,
+	SIZE_GEN_SERIAL_NUMBER = ADDR_GEN_PWR_TABLE_ID - ADDR_GEN_SERIAL_NUMBER,
+	SIZE_GEN_PWR_TABLE_ID = ADDR_GEN_RESERVED - ADDR_GEN_PWR_TABLE_ID,
+	SIZE_GEN_RESERVED = ADDR_FEM - ADDR_GEN_RESERVED,
+
+	SIZE_FEM = sizeof(struct eeprom_fem),
+	SIZE_FEM_WIRING_ID = ADDR_FEM_LUT - ADDR_FEM_WIRING_ID,
+	SIZE_FEM_LUT = ADDR_FEM_PLATFORM_ID - ADDR_FEM_LUT,
+	SIZE_FEM_PLATFORM_ID = ADDR_FEM_RESERVED - ADDR_FEM_PLATFORM_ID,
+
+	SIZE_CALIB_POWER = sizeof(struct eeprom_calib_power),
+	SIZE_CALIB_POWER_FREQ_OFFSET = ADDR_CALIB_POWER_CHAN_BMP - ADDR_CALIB_POWER_FREQ_OFFSET,
+	SIZE_CALIB_POWER_CHAN_BMP = ADDR_CALIB_POWER_PHY - ADDR_CALIB_POWER_CHAN_BMP,
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	SIZE_CALIB_POWER_PHY = ADDR_CALIB_IQ_DCOC_VERSION - ADDR_CALIB_POWER_PHY,
+#else
+	SIZE_CALIB_POWER_PHY = sizeof(struct eeprom_phy_calib) * NUM_PIVOT_PHYS,
+#endif
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	SIZE_CALIB_IQ_DCOC_VERSION = ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV0 -
+		ADDR_CALIB_IQ_DCOC_VERSION,
+	SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV1 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV0,
+	SIZE_CALIB_IQ_DCOC_20MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV0 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_20MHZ_BMP_TCV1,
+	SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV1 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV0,
+	SIZE_CALIB_IQ_DCOC_40MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV0 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_40MHZ_BMP_TCV1,
+	SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV1 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV0,
+	SIZE_CALIB_IQ_DCOC_80MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_80MHZ_BMP_TCV1,
+	SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV0 = ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0,
+	SIZE_CALIB_IQ_DCOC_160MHZ_BMP_TCV1 = ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1,
+	SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV0 = ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1 -
+		ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV0,
+	SIZE_CALIB_IQ_DCOC_DATA_20MHZ_TCV1 = ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0 -
+		ADDR_CALIB_IQ_DCOC_DATA_20MHZ_TCV1,
+	SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV0 = ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1 -
+		ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV0,
+	SIZE_CALIB_IQ_DCOC_DATA_40MHZ_TCV1 = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0 -
+		ADDR_CALIB_IQ_DCOC_DATA_40MHZ_TCV1,
+	SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV0 = ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1 -
+		ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV0,
+	SIZE_CALIB_IQ_DCOC_DATA_80MHZ_TCV1 = ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0 -
+		ADDR_CALIB_IQ_DCOC_DATA_80MHZ_TCV1,
+	SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV0 = ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1 -
+		ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV0,
+	SIZE_CALIB_IQ_DCOC_DATA_160MHZ_TCV1 = sizeof(struct eeprom_calib_data) *
+		ADDR_CALIB_IQ_DCOC_CHANNEL_160MHZ_BMP_TCV1,
+	EEPROM_BASIC_NUM_BYTES = sizeof(struct eeprom) - sizeof(struct eeprom_calib_iq_dcoc),
+#else
+	EEPROM_BASIC_NUM_BYTES = sizeof(struct eeprom),
+#endif
+	EEPROM_NUM_BYTES = sizeof(struct eeprom),
+
+	EEPROM_LAST_BYTE = EEPROM_NUM_BYTES - 1,
+};
+
+#endif /* CL_EEPROM_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 27/96] cl8k: add ela.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (25 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 26/96] cl8k: add eeprom.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 28/96] cl8k: add ela.h viktor.barna
                   ` (68 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ela.c | 230 +++++++++++++++++++++++++
 1 file changed, 230 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.c

diff --git a/drivers/net/wireless/celeno/cl8k/ela.c b/drivers/net/wireless/celeno/cl8k/ela.c
new file mode 100644
index 000000000000..c2419b11b5c0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ela.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2021, Celeno Communications Ltd. */
+
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "utils.h"
+#include "ela.h"
+
+#define CL_ELA_MODE_DFLT_ALIAS          "default"
+#define CL_ELA_MODE_DFLT_SYMB_LINK      "lcu_default.conf"
+#define CL_ELA_MODE_DFLT_OFF            "OFF"
+#define CL_ELA_LCU_CONF_TOKENS_CNT      3 /* cmd addr1 addr2 */
+#define CL_ELA_LCU_MEM_WRITE_CMD_STR    "mem_write"
+#define CL_ELA_LCU_MEM_WRITE_CMD_SZ     sizeof(CL_ELA_LCU_MEM_WRITE_CMD_STR)
+#define CL_ELA_LCU_UNKNOWN_CMD_TYPE     0
+#define CL_ELA_LCU_MEM_WRITE_CMD_TYPE   1
+#define CL_ELA_LCU_UNKNOWN_CMD_STR      "unknown"
+
+static int __must_check get_lcu_cmd_type(char *cmd)
+{
+	if (!strncmp(CL_ELA_LCU_MEM_WRITE_CMD_STR, cmd, CL_ELA_LCU_MEM_WRITE_CMD_SZ))
+		return CL_ELA_LCU_MEM_WRITE_CMD_TYPE;
+
+	return CL_ELA_LCU_UNKNOWN_CMD_TYPE;
+}
+
+static int add_lcu_cmd(struct cl_ela_db *ed, u32 type, u32 offset, u32 value)
+{
+	struct cl_lcu_cmd *cmd = NULL;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->type = type;
+	cmd->offset = offset;
+	cmd->value = value;
+
+	list_add_tail(&cmd->cmd_list, &ed->cmd_head);
+
+	return 0;
+}
+
+static void remove_lcu_cmd(struct cl_lcu_cmd *cmd)
+{
+	list_del(&cmd->cmd_list);
+	kfree(cmd);
+}
+
+static void reset_stats(struct cl_ela_db *db)
+{
+	memset(&db->stats, 0, sizeof(db->stats));
+}
+
+static int load_cmds_from_buf(struct cl_chip *chip, char *buf, size_t size)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+	char *line = buf;
+	char cmd[STR_LEN_256B];
+	u32 type = CL_ELA_LCU_UNKNOWN_CMD_TYPE;
+	u32 offset = 0;
+	u32 value = 0;
+	int tokens_cnt = 0;
+	int ret = 0;
+
+	while (line && strlen(line) && (line != (buf + size))) {
+		if ((*line == '#') || (*line == '\n')) {
+			/* Skip comment or blank line */
+			line = strstr(line, "\n") + 1;
+		} else if (*line) {
+			tokens_cnt = sscanf(line, "%s %x %x\n", cmd, &offset, &value);
+			cl_dbg_chip_trace(chip,
+					  "tokens(%d):cmd(%s), offset(0x%X), value(0x%X)\n",
+					  tokens_cnt, cmd, offset, value);
+
+			type = get_lcu_cmd_type(cmd);
+			if (type == CL_ELA_LCU_UNKNOWN_CMD_TYPE) {
+				cl_dbg_chip_trace(chip, "Detected extra token, skipping\n");
+				goto newline;
+			}
+			if (tokens_cnt != CL_ELA_LCU_CONF_TOKENS_CNT) {
+				cl_dbg_chip_err(chip,
+						"Tokens count is wrong! (%d != %d)\n",
+						CL_ELA_LCU_CONF_TOKENS_CNT,
+						tokens_cnt);
+				ret = -EBADMSG;
+				goto exit;
+			}
+
+			ret = add_lcu_cmd(ed, type, offset, value);
+			if (ret)
+				goto exit;
+
+newline:
+			line = strstr(line, "\n") + 1;
+		}
+	}
+
+exit:
+	ed->stats.adaptations_cnt++;
+	return ret;
+}
+
+void cl_ela_lcu_reset(struct cl_chip *chip)
+{
+	lcu_common_sw_rst_set(chip, 0x1);
+
+	if (chip->cl_hw_tcv0)
+		lcu_phy_lcu_sw_rst_set(chip->cl_hw_tcv0, 0x1);
+
+	if (chip->cl_hw_tcv1)
+		lcu_phy_lcu_sw_rst_set(chip->cl_hw_tcv1, 0x1);
+}
+
+void cl_ela_lcu_apply_config(struct cl_chip *chip)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+	struct cl_lcu_cmd *cmd = NULL;
+	unsigned long flags;
+
+	if (!cl_ela_lcu_is_valid_config(chip)) {
+		cl_dbg_chip_err(chip, "Active ELA LCU config is not valid\n");
+		return;
+	}
+
+	/* Extra safety to avoid local CPU interference during LCU reconfiguration */
+	local_irq_save(flags);
+	list_for_each_entry(cmd, &ed->cmd_head, cmd_list) {
+		cl_dbg_chip_info(chip, "Writing cmd (0x%X, 0x%X)\n",
+				 cmd->offset, cmd->value);
+		if (!chip->cl_hw_tcv1 && cl_reg_is_phy_tcv1(cmd->offset)) {
+			ed->stats.tcv1_skips_cnt++;
+			continue;
+		} else if (!chip->cl_hw_tcv0 && cl_reg_is_phy_tcv0(cmd->offset)) {
+			ed->stats.tcv0_skips_cnt++;
+			continue;
+		}
+		cl_reg_write_chip(chip, cmd->offset, cmd->value);
+	}
+	local_irq_restore(flags);
+	ed->stats.applications_cnt++;
+}
+
+bool cl_ela_is_on(struct cl_chip *chip)
+{
+	return !!strncmp(CL_ELA_MODE_DFLT_OFF, chip->conf->ce_ela_mode,
+			 sizeof(chip->conf->ce_ela_mode));
+}
+
+bool cl_ela_is_default(struct cl_chip *chip)
+{
+	return !strncmp(CL_ELA_MODE_DFLT_ALIAS, chip->conf->ce_ela_mode,
+			sizeof(chip->conf->ce_ela_mode));
+}
+
+bool cl_ela_lcu_is_valid_config(struct cl_chip *chip)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+
+	return ed->error_state == 0;
+}
+
+char *cl_ela_lcu_config_name(struct cl_chip *chip)
+{
+	if (!cl_ela_is_on(chip))
+		return CL_ELA_MODE_DFLT_OFF;
+
+	if (cl_ela_is_default(chip))
+		return CL_ELA_MODE_DFLT_SYMB_LINK;
+
+	return chip->conf->ce_ela_mode;
+}
+
+int cl_ela_lcu_config_read(struct cl_chip *chip)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+	char filename[CL_FILENAME_MAX] = {0};
+	size_t size = 0;
+	int ret = 0;
+
+	if (!cl_ela_is_on(chip)) {
+		ret = -EOPNOTSUPP;
+		goto exit;
+	}
+
+	reset_stats(ed);
+
+	snprintf(filename, sizeof(filename), "%s", cl_ela_lcu_config_name(chip));
+	size = cl_file_open_and_read(chip, filename, &ed->raw_lcu_config);
+	if (!ed->raw_lcu_config) {
+		ret = -ENODATA;
+		goto exit;
+	}
+
+	ret = load_cmds_from_buf(chip, ed->raw_lcu_config, size);
+exit:
+	ed->error_state = ret;
+	return ret;
+}
+
+int cl_ela_init(struct cl_chip *chip)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+	int ret = 0;
+
+	INIT_LIST_HEAD(&ed->cmd_head);
+
+	if (!cl_ela_is_on(chip))
+		return 0;
+
+	ret = cl_ela_lcu_config_read(chip);
+	if (ret == 0) {
+		cl_ela_lcu_reset(chip);
+		cl_ela_lcu_apply_config(chip);
+	}
+
+	return ret;
+}
+
+void cl_ela_deinit(struct cl_chip *chip)
+{
+	struct cl_ela_db *ed = &chip->ela_db;
+	struct cl_lcu_cmd *cmd = NULL, *cmd_tmp = NULL;
+
+	kfree(ed->raw_lcu_config);
+	ed->raw_lcu_config = NULL;
+
+	list_for_each_entry_safe(cmd, cmd_tmp, &ed->cmd_head, cmd_list)
+		remove_lcu_cmd(cmd);
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 28/96] cl8k: add ela.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (26 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 27/96] cl8k: add ela.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 29/96] cl8k: add enhanced_tim.c viktor.barna
                   ` (67 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ela.h | 48 ++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ela.h

diff --git a/drivers/net/wireless/celeno/cl8k/ela.h b/drivers/net/wireless/celeno/cl8k/ela.h
new file mode 100644
index 000000000000..a0886c3a9331
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ela.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_ELA_H
+#define CL_ELA_H
+
+/**
+ * DOC: ELA (=Embedded Logic Analyzer)
+ *
+ * Chip contains built-in ELA with LCU (=Logic Capture Unit), that allows to
+ * collect profiling info. Collected data is aggregated via set of %cl_nlev
+ * elements, and saved inside special dump buffer (described by %cl_coredump)
+ * and fed to the userspace via DEV_COREDUMP subsystem.
+ *
+ * This layer is mandatory since it allows to set properly initial and
+ * post-recovery configuration.
+ */
+
+struct cl_lcu_cmd {
+	u32 type;
+	u32 offset;
+	u32 value;
+	struct list_head cmd_list;
+};
+
+struct cl_ela_db {
+	char *raw_lcu_config;
+	struct list_head cmd_head;
+	struct {
+		u32 adaptations_cnt;
+		u32 applications_cnt;
+		u32 tcv0_skips_cnt;
+		u32 tcv1_skips_cnt;
+	} stats;
+	int error_state;
+};
+
+void cl_ela_lcu_reset(struct cl_chip *chip);
+void cl_ela_lcu_apply_config(struct cl_chip *chip);
+bool cl_ela_is_on(struct cl_chip *chip);
+bool cl_ela_is_default(struct cl_chip *chip);
+bool cl_ela_lcu_is_valid_config(struct cl_chip *chip);
+char *cl_ela_lcu_config_name(struct cl_chip *chip);
+int cl_ela_lcu_config_read(struct cl_chip *chip);
+int cl_ela_init(struct cl_chip *chip);
+void cl_ela_deinit(struct cl_chip *chip);
+
+#endif /* CL_ELA_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 29/96] cl8k: add enhanced_tim.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (27 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 28/96] cl8k: add ela.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 30/96] cl8k: add enhanced_tim.h viktor.barna
                   ` (66 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/enhanced_tim.c   | 173 ++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.c

diff --git a/drivers/net/wireless/celeno/cl8k/enhanced_tim.c b/drivers/net/wireless/celeno/cl8k/enhanced_tim.c
new file mode 100644
index 000000000000..893bddb2b25b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/enhanced_tim.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "def.h"
+#include "hw.h"
+#include "sta.h"
+#include "enhanced_tim.h"
+
+/*
+ * The kernel's test_and_set_bit() gets unsigned long * as an argument, but we actually
+ * pass a pointer to u32, what cause to alignment fault in 64bit platforms.
+ * This function gets a pointer to u32 to prevent this alignment fault.
+ * Notice that the kernel's function sets the bit as an atomic operation,
+ * and our function doesn't. Vut it's not an issue since we set the bit from one context only.
+ */
+static int cl_test_and_set_bit(unsigned long nr, u32 *addr)
+{
+	u32 *new_addr, mask, old;
+
+	new_addr = ((u32 *)addr) + (nr >> 5);
+	mask = 1 << (nr & 31);
+	old = *new_addr & mask;
+	*new_addr |= mask;
+
+	return (old != 0);
+}
+
+static int cfm_test_and_clear_bit(unsigned long nr, u32 *addr)
+{
+	u32 *new_addr, mask, old;
+
+	new_addr = ((u32 *)addr) + (nr >> 5);
+	mask = 1 << (nr & 31);
+	old = *new_addr & mask;
+	*new_addr &= ~mask;
+
+	return (old != 0);
+}
+
+void cl_enhanced_tim_reset(struct cl_hw *cl_hw)
+{
+	/*
+	 * There is no need to reset cl_hw->ipc_env->shared->enhanced_tim.
+	 * It is done as part of ipc_shared_env_init()
+	 */
+	memset(&cl_hw->ipc_env->enhanced_tim, 0, sizeof(struct cl_ipc_enhanced_tim));
+}
+
+/*
+ * NOTE: the UMAC DRAM starts with the enhanced TIM elements stractures.
+ * This is hard coded in the FW, this memory allocation should be changed in
+ * the driver module .ELF file.
+ */
+
+void cl_enhanced_tim_clear_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx,
+				  u8 ac, struct cl_sta *cl_sta, u8 tid)
+{
+	/* Pointer to HOST enhanced TIM */
+	u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+	u32 ipc_queue_idx_common = IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(ipc_queue_idx);
+	/*
+	 * Does the UMAC enhanced TIM need update?
+	 * If the TIM element is set then clear it and update the UMAC TIM element
+	 */
+	if (cfm_test_and_clear_bit(ipc_queue_idx_common, source)) {
+		/* Pointer to UMAC enhanced TIM */
+		u32 __iomem *target =
+			(u32 __iomem *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+		/* Offset to UMAC encahned TIM array position */
+		u32 agg_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+		/* Update tim element */
+		if (cl_sta) {
+			struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+			if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+				ieee80211_sta_set_buffered(cl_sta->sta, tid, false);
+		}
+
+		iowrite32(source[agg_offset], (void __iomem *)&target[agg_offset]);
+	}
+}
+
+void cl_enhanced_tim_clear_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				     bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+	/* Pointer to HOST enhanced TIM */
+	u32 *source = cl_hw->ipc_env->enhanced_tim.tx_single[ac];
+	/* Staton index: 0 - 128 (do not use cl_sta->sta_idx which is 0 -127) */
+	u32 sta_idx = ipc_queue_idx % FW_MAX_NUM_STA;
+
+	/*
+	 * Does the UMAC enhanced TIM need update?
+	 * If the TIM element is set then clear it and update the UMAC TIM element
+	 */
+	if (cfm_test_and_clear_bit(sta_idx, source)) {
+		/* Pointer to UMAC enhanced TIM for singles or aggregation */
+		u32 __iomem *target =
+			(u32 __iomem *)cl_hw->ipc_env->shared->enhanced_tim.tx_single[ac];
+		/* Offset to UMAC encahned TIM array position */
+		u32 sta_offset = sta_idx / (BITS_PER_BYTE * sizeof(u32));
+
+		/* Update tim element */
+		if (!no_ps_buffer && cl_sta) {
+			struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+			if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+				ieee80211_sta_set_buffered(cl_sta->sta, tid, false);
+		}
+
+		iowrite32(source[sta_offset], (void __iomem *)&target[sta_offset]);
+	}
+}
+
+void cl_enhanced_tim_set_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+	/* Pointer to HOST enhanced TIM */
+	u32 *source = cl_hw->ipc_env->enhanced_tim.tx_rx_agg[ac];
+	u32 ipc_queue_idx_common = IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(ipc_queue_idx);
+	/*
+	 * Does the UMAC enhanced TIM need update?
+	 * If the TIM element is cleared then set it and update the UMAC TIM element
+	 */
+	if (!cl_test_and_set_bit(ipc_queue_idx_common, source)) {
+		/* Pointer to UMAC enhanced TIM */
+		u32 __iomem *target =
+			(u32 __iomem *)cl_hw->ipc_env->shared->enhanced_tim.tx_rx_agg[ac];
+		/* Offset to UMAC encahned TIM array position */
+		u32 agg_offset = ipc_queue_idx_common / (BITS_PER_BYTE * sizeof(u32));
+
+		/* Update tim element */
+		if (!no_ps_buffer && cl_sta) {
+			struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+			if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+				ieee80211_sta_set_buffered(cl_sta->sta, tid, true);
+		}
+
+		iowrite32(source[agg_offset], (void __iomem *)&target[agg_offset]);
+	}
+}
+
+void cl_enhanced_tim_set_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				   bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid)
+{
+	/* Pointer to HOST enhanced TIM */
+	u32 *source = cl_hw->ipc_env->enhanced_tim.tx_single[ac];
+	/* Staton index: 0 - 128 (do not use cl_sta->sta_idx which is 0 -127) */
+	u32 sta_idx = ipc_queue_idx % FW_MAX_NUM_STA;
+
+	/*
+	 * Does the UMAC enhanced TIM need update?
+	 * If the TIM element is cleared then set it and update the UMAC TIM element
+	 */
+	if (!cl_test_and_set_bit(sta_idx, source)) {
+		/* Pointer to UMAC enhanced TIM */
+		u32 __iomem *target =
+			(u32 __iomem *)cl_hw->ipc_env->shared->enhanced_tim.tx_single[ac];
+		/* Offset to UMAC encahned TIM array position */
+		u32 sta_offset = sta_idx / (BITS_PER_BYTE * sizeof(u32));
+
+		/* Update tim element */
+		if (!no_ps_buffer && cl_sta) {
+			struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+			if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+				ieee80211_sta_set_buffered(cl_sta->sta, tid, true);
+		}
+
+		iowrite32(source[sta_offset], (void __iomem *)&target[sta_offset]);
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 30/96] cl8k: add enhanced_tim.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (28 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 29/96] cl8k: add enhanced_tim.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 31/96] cl8k: add fw.c viktor.barna
                   ` (65 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/enhanced_tim.h   | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/enhanced_tim.h

diff --git a/drivers/net/wireless/celeno/cl8k/enhanced_tim.h b/drivers/net/wireless/celeno/cl8k/enhanced_tim.h
new file mode 100644
index 000000000000..ec40ac03df59
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/enhanced_tim.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_ENHANCED_TIM_H
+#define CL_ENHANCED_TIM_H
+
+#define BCN_IE_TIM_BIT_OFFSET 2
+
+void cl_enhanced_tim_reset(struct cl_hw *cl_hw);
+void cl_enhanced_tim_clear_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx,
+				  u8 ac, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_clear_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				     bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_set_tx_agg(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+void cl_enhanced_tim_set_tx_single(struct cl_hw *cl_hw, u32 ipc_queue_idx, u8 ac,
+				   bool no_ps_buffer, struct cl_sta *cl_sta, u8 tid);
+
+#endif /* CL_ENHANCED_TIM_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 31/96] cl8k: add fw.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (29 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 30/96] cl8k: add enhanced_tim.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
                   ` (64 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw.c | 3167 +++++++++++++++++++++++++
 1 file changed, 3167 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw.c

diff --git a/drivers/net/wireless/celeno/cl8k/fw.c b/drivers/net/wireless/celeno/cl8k/fw.c
new file mode 100644
index 000000000000..fd981ccdfaee
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw.c
@@ -0,0 +1,3167 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/utsname.h>
+#include <linux/firmware.h>
+
+#include "chip.h"
+#include "utils.h"
+#include "debug.h"
+#include "recovery.h"
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "phy.h"
+#include "rfic.h"
+#include "mac_addr.h"
+#include "mac80211.h"
+#include "ampdu.h"
+#include "tx.h"
+#include "stats.h"
+#include "fw.h"
+
+#define fw_pr(cl_hw, fmt, ...) \
+	pr_debug("%cmac%u " fmt, (cl_hw)->fw_prefix, (cl_hw)->chip->idx, ##__VA_ARGS__)
+
+/* Location where FW codes must be written */
+#define RAM_SMAC_FW_ADDR 0x00300000
+#define RAM_UMAC_FW_ADDR 0x00280000
+#define RAM_LMAC_FW_ADDR 0x00200000
+
+#define FW_START_MAGIC           "CEFWHDRSTART"
+#define FW_END_MAGIC             "CEFWHDREND"
+#define FW_OFFLOAD_MEM_BASE_ADDR 0x70000000 /* Defined in fw link script */
+#define FW_SECTION_SIZE_MASK     0x7FFFF    /* Mask for max. size of a section */
+#define FW_REMOTE_ROM_BASE_ADDR  0x80000000 /* Defined in fw link script */
+#define FW_REMOTE_ROM_MAX        150000
+
+/* Location (offset) where FW codes must be taken from */
+#define IRAM_START_OFFSET        0x40000
+
+/*
+ * Poor man parser of a plain zip file
+ * We use it just as a container for now. Could use cpio instead.
+ * (no compression, no 64-bit data ... no nothing)
+ * Reference: ZIP File Format Specification v.6.3.4 (2014)
+ *     http://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+ * For BIG ENDIAN host: zip format is always little endian.
+ * TODO: need alignment on non-intel hosts! zip format has no alignment,padding
+ * TODO: check CRC?
+ */
+
+struct pkzip_local_hdr  {
+	u32 signature;
+	u16 ver2extract;
+	u16 flags;
+	u16 cmpr_meth;
+	u16 filetime;
+	u16 filedate;
+	u32 crc32;
+	u32 cmpr_size;
+	u32 orig_size;
+	u16 fname_len;
+	u16 hdr_extra_len;
+	/* Filename goes here - not 0 terminated! */
+	/* Hdr_extra_data goes here */
+	/* File data goes here; no padding, no alignment */
+} __packed;
+
+#define PKZIP_LOCAL_HDR_MAGIC   0x04034b50
+#define PKZIP_CENTRAL_DIR_MAGIC 0x02014b50
+
+/*
+ * Enumerate zip data in buffer, find named item
+ * Return: 0 on success (the item found)
+ *        -ENOENT the item not found, normal end of data found
+ *        -EINVAL the data is not zip (maybe old format firmware)
+ *         else invalid data format or other error
+ */
+static int cl_enum_zipfile(const void *data, size_t size,
+			   const char *name, char **pdata, size_t *psize)
+{
+	const struct pkzip_local_hdr *phdr = data;
+	int remain_size = (int)size;
+
+	BUILD_BUG_ON(sizeof(struct pkzip_local_hdr) != 30);
+
+	while (remain_size > sizeof(struct pkzip_local_hdr)) {
+		char *pfname;
+		char *edata;
+
+		if (phdr->signature != PKZIP_LOCAL_HDR_MAGIC) {
+			if (phdr->signature == PKZIP_CENTRAL_DIR_MAGIC)
+				return -ENOENT; /* Normal end of zip */
+			if ((void *)phdr == data)
+				/* Bad signature in the first entry - not a zip at all */
+				return -EINVAL;
+			pr_err("ZIP - unexpected block: %8.8X\n", phdr->signature);
+			return -1;
+		}
+
+		if (phdr->fname_len == 0 || phdr->fname_len > 128) {
+			/* FIX max len */
+			pr_err("ZIP entry name len bad: %u\n", phdr->fname_len);
+			return -1;
+		}
+
+		if (phdr->hdr_extra_len == 0) {
+			pr_err("ZIP xtra hdr size=0! FIXME!\n"); /* Copy name to tmp buffer */
+			return -1;
+		}
+
+		pfname = (char *)phdr + sizeof(struct pkzip_local_hdr);
+		/* Because fname in zip is not null term! */
+		pfname[phdr->fname_len] = 0;
+		edata = pfname + phdr->fname_len + phdr->hdr_extra_len;
+		remain_size -= (sizeof(*phdr) + phdr->fname_len + phdr->hdr_extra_len);
+
+		if (phdr->cmpr_size == 0 || phdr->cmpr_size > remain_size) {
+			pr_err("ZIP entry data len bad: %u name=%s, left=%u\n",
+			       phdr->cmpr_size, pfname, remain_size);
+			return -1;
+		}
+
+		if (strncmp(name, pfname, phdr->fname_len) == 0) {
+			if (phdr->cmpr_meth != 0 || phdr->cmpr_size != phdr->orig_size) {
+				pr_err("ZIP entry compressed! name=%s\n", pfname);
+				return -1;
+			}
+
+			*pdata = edata;
+			*psize = (size_t)phdr->cmpr_size;
+			return 0;
+		}
+
+		remain_size -= phdr->cmpr_size;
+		phdr = (const struct pkzip_local_hdr *)(edata + phdr->cmpr_size);
+	}
+
+	return -1;
+}
+
+static int cl_fw_unpack(const void *data, size_t size,
+			const char *name, char **pdata, size_t *psize)
+{
+	/*
+	 * Get named item in firmware container
+	 * Args: pdata : pointer to pointer to item data, psize : pointer to item size
+	 */
+	*pdata = NULL;
+	*psize = 0;
+	return cl_enum_zipfile(data, size, name, pdata, psize);
+}
+
+static int cl_fw_load_other(struct cl_hw *cl_hw, const char *name)
+{
+	/* Handle other stuff in firmware container */
+	char *edata;
+	size_t esize;
+	struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+	int rc = cl_fw_unpack(cached_fw->data, cached_fw->size,
+			      name, &edata, &esize);
+
+	if (rc)
+		return rc;
+
+	cl_dbgfile_parse(cl_hw, edata, esize);
+
+	return 0;
+}
+
+/*
+ * Copy the FW code and data into the proper memory inside the firmware asic.
+ * vaddr - run address
+ * paddr - load address
+ * fsize - memory section size to copy
+ * msize - memory section physical size
+ * mem_base - base address of xtensa internal memory
+ * fw_buf - buffer holding the FW binary code and data
+ */
+static void cl_fw_copy_section(struct cl_chip *chip, char *fw_buf, u32 mem_base,
+			       u32 vaddr, u32 paddr, u32 fsize, u32 msize)
+{
+	u32 *src_addr;
+	u32 dst_addr;
+	u32 i;
+
+	src_addr = (u32 *)(fw_buf + (paddr & 0x0007FFFF));
+	/* 512KB - cover all internal iram and dram and some more */
+
+	/* Check if run address is external or internal from xtensa point of view */
+	if ((vaddr & 0xFF000000) == XTENSA_PIF_BASE_ADDR)
+		dst_addr = vaddr & 0x007FFFFF; /* Must be in 8M PCIe window */
+	else
+		dst_addr = (mem_base | (vaddr & 0x0007FFFF));
+
+	for (i = 0; i < fsize; i += sizeof(*src_addr))
+		cl_reg_write_chip(chip, dst_addr + i, *src_addr++);
+}
+
+static int cl_fw_phdrs_upload(struct cl_chip *chip, struct cl_hw *cl_hw,
+			      u32 fw_addr, const void *edata, size_t esize)
+{
+	/*
+	 * Load firmware image with "phdrs" header
+	 * and optional non-resident (offloaded) section
+	 */
+	u32 size = esize, section, section_cnt = 0;
+	char const *pbuf = edata;
+	u32 *src;
+
+	/* Verify FW image phdrs start magic */
+	if (strncmp(pbuf, FW_START_MAGIC, strlen(FW_START_MAGIC))) {
+		cl_dbg_err(cl_hw, "phdrs start magic not found, aborting...\n");
+		return -1;
+	}
+
+	cl_dbg_info(cl_hw, "phdrs start magic found !!!!!\n");
+	pbuf += (strlen(FW_START_MAGIC) + 1);
+	size -= (strlen(FW_START_MAGIC) + 1);
+
+	/* Verify FW image phdrs end magic */
+	while (size > 0) {
+		if (strncmp(pbuf, FW_END_MAGIC, strlen(FW_END_MAGIC)) == 0) {
+			cl_dbg_info(cl_hw, "phdrs end magic found !!!!!\n");
+			break;
+		}
+
+		pbuf += 16;
+		size -= 16;
+		section_cnt++;
+	}
+
+	/* FW image phdrs end magic not found */
+	if (size == 0 || section_cnt > 100) {
+		cl_dbg_err(cl_hw, "phdrs end magic not found, aborting...\n");
+		return -1;
+	}
+
+	/* Remember where the fw code start in firmware buffer */
+	src = (u32 *)(pbuf + (strlen(FW_END_MAGIC) + 1));
+	/* Re-assign firmware buffer ptrs to start */
+	pbuf = edata + (strlen(FW_START_MAGIC) + 1);
+	size = esize - (strlen(FW_START_MAGIC) + 1);
+
+	bool is_offload_present = false;
+	u32 off2_start = 0, off2_end = 0;
+	u32 off3_start = 0, off3_end = 0;
+
+	for (section = 0; section < section_cnt; section++) {
+		u32 *param = (u32 *)pbuf;
+
+		if (param[0] == FW_REMOTE_ROM_BASE_ADDR) {
+			if (param[2] > FW_REMOTE_ROM_MAX) {
+				cl_dbg_info(cl_hw, "%cmac%u: FW remote rom too big = %uK\n",
+					    cl_hw->fw_prefix, chip->idx, param[2]);
+			} else {
+				dma_addr_t phys_dma_addr;
+				char *pfake = (char *)src + (param[1] & FW_SECTION_SIZE_MASK);
+				struct cl_dma_accessed *fw_rom = &cl_hw->fw_remote_rom;
+
+				fw_rom->size = param[2];
+				fw_rom->drv_v_addr = dma_alloc_coherent(cl_hw->chip->dev,
+									fw_rom->size,
+									&phys_dma_addr, GFP_KERNEL);
+				if (!fw_rom->drv_v_addr) {
+					cl_dbg_info(cl_hw, "%cmac%u: FW remote rom dma_alloc_coherent failed = %uK\n",
+						    cl_hw->fw_prefix, chip->idx, fw_rom->size);
+					fw_rom->size = 0;
+				} else {
+					fw_rom->fw_v_addr = FW_REMOTE_ROM_BASE_ADDR;
+					fw_rom->dma_addr = phys_dma_addr;
+					memcpy(fw_rom->drv_v_addr, pfake, fw_rom->size);
+					cl_dbg_info(cl_hw, "%cmac%u: FW remote rom memory use = %uK\n",
+						    cl_hw->fw_prefix, chip->idx, fw_rom->size);
+				}
+			}
+			pbuf += 16;
+			continue;
+		}
+
+		if (param[0] == FW_OFFLOAD_MEM_BASE_ADDR) {
+			is_offload_present = true;
+			u32 *pdata = (u32 *)((char *)src + (param[1] & 0x7FFFF));
+
+			off2_start = pdata[0];
+			off2_end = pdata[1];
+			off3_start = pdata[2];
+			off3_end = pdata[3];
+			cl_dbg_info(cl_hw, "Resident RO DATA block: start=0x%x, end=0x%x\n\n",
+				    off2_start, off2_end);
+			pbuf += 16;
+			continue;
+		}
+
+		cl_fw_copy_section(chip, (char *)src, fw_addr,
+				   param[0],
+				   param[1],
+				   param[2],
+				   param[3]);
+		pbuf += 16;
+	}
+
+	if (is_offload_present) {
+		/* 2nd pass to find the resident RO data block */
+		pbuf -= (16 * section_cnt);
+		char *resident_file_data = NULL;
+		char *resident_umac_file_data = NULL;
+		u32 *param;
+
+		for (section = 0; section < section_cnt; section++) {
+			param = (u32 *)pbuf;
+			if (param[0] <= off2_start &&
+			    (param[0] + param[3]) > off2_end) {
+				resident_file_data =
+					(char *)src + (param[1] & FW_SECTION_SIZE_MASK) +
+					(off2_start - param[0]);
+				cl_dbg_info(cl_hw, "resident_file_data=0x%p.\n",
+					    resident_file_data);
+			}
+
+			if (param[0] <= off3_start &&
+			    (param[0] + param[3]) >= off3_end) {
+				resident_umac_file_data =
+					(char *)src + (param[1] & FW_SECTION_SIZE_MASK) +
+					(off3_start - param[0]);
+				cl_dbg_info(cl_hw, "resident_umac_file_data=0x%p.\n",
+					    resident_umac_file_data);
+			}
+
+			if (param[0] == FW_OFFLOAD_MEM_BASE_ADDR) {
+				char *pfake = (char *)src + (param[1] & FW_SECTION_SIZE_MASK);
+
+				cl_dbgfile_store_offload_data(chip,
+							      cl_hw,
+							      pfake, param[2],
+							      FW_OFFLOAD_MEM_BASE_ADDR,
+							      resident_file_data,
+							      off2_end - off2_start,
+							      off2_start,
+							      resident_umac_file_data,
+							      off3_end - off3_start,
+							      off3_start);
+
+				break; /* This should be last section */
+			}
+			pbuf += 16;
+		}
+
+		if (!resident_file_data)
+			cl_dbg_warn(cl_hw, "FW resident data block [%#X-%#X] not found!\n",
+				    off2_start, off2_end);
+	}
+
+	return 0;
+}
+
+static int cl_fw_upload(struct cl_chip *chip, struct cl_hw *cl_hw,
+			u32 fw_addr, const char *data, size_t size)
+{
+	/* Is it old .bin format (used for firmware tests) */
+	if (data[IRAM_START_OFFSET] == 0x06) {
+		const u32 *src = (const u32 *)data;
+		int i;
+
+		for (i = 0; i < size; i += sizeof(*src))
+			cl_reg_write_chip(chip, fw_addr + i, *src++);
+
+		return 0;
+	}
+
+	if (cl_hw)
+		return cl_fw_phdrs_upload(chip, cl_hw, fw_addr, data, size);
+
+	return 0;
+}
+
+static int cl_fw_load_operational(struct cl_hw *cl_hw, const char *fw_name,
+				  const char *main_str, const char *dbg_str,
+				  u32 ram_addr)
+{
+	int rc;
+	const struct firmware *fw;
+	char *fw_ptr;
+	size_t fw_size;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+
+	clear_bit(CL_DEV_FW_SYNC, &cl_hw->drv_flags);
+
+	if (!cached_fw->data) {
+		char path_name[CL_PATH_MAX] = {0};
+
+		snprintf(path_name, sizeof(path_name), "cl8k/%s", fw_name);
+		rc = request_firmware(&fw, path_name, chip->dev);
+
+		if (rc) {
+			cl_dbg_err(cl_hw, "# Failed to get %s, with error: %x\n",
+				   path_name, rc);
+			return rc;
+		}
+		cached_fw->data = vzalloc(fw->size);
+		if (!cached_fw->data) {
+			release_firmware(fw);
+			return -ENOMEM;
+		}
+		memcpy(cached_fw->data, fw->data, fw->size);
+		cached_fw->size = fw->size;
+		release_firmware(fw);
+	}
+
+	rc = cl_fw_unpack(cached_fw->data, cached_fw->size,
+			  main_str, &fw_ptr, &fw_size);
+
+	if (rc == 0) {
+		rc = cl_fw_upload(chip, cl_hw, ram_addr,
+				  fw_ptr, fw_size);
+		/* Load other stuff packed in firmware container */
+		if (rc == 0)
+			rc = cl_fw_load_other(cl_hw, dbg_str);
+	} else if (rc != -ENOENT) {
+		/* Assume it is a single file, not a container (used for tests) */
+		rc = cl_fw_upload(chip, cl_hw, ram_addr,
+				  cached_fw->data,
+				  cached_fw->size);
+	}
+
+	return rc;
+}
+
+static int cl_fw_load_lmac(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_fw_load_operational(cl_hw, chip->conf->ce_lmac,
+				   "lmacfw.main", "lmacfw.dbg",
+				   RAM_LMAC_FW_ADDR))
+		return -1;
+
+	cl_hw->fw_active = true;
+
+	return 0;
+}
+
+static int cl_fw_load_smac(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_fw_load_operational(cl_hw, chip->conf->ce_smac,
+				   "smacfw.main", "smacfw.dbg",
+				   RAM_SMAC_FW_ADDR))
+		return -1;
+
+	cl_hw->fw_active = true;
+
+	return 0;
+}
+
+int cl_fw_file_load(struct cl_hw *cl_hw)
+{
+	/* For TCV0 load lmac, and for TCV1 load smac */
+	if (cl_hw_is_tcv0(cl_hw) &&
+	    strcmp(cl_hw->chip->conf->ce_lmac, "no_load")) {
+		if (cl_fw_load_lmac(cl_hw))
+			return -1;
+	} else if (cl_hw_is_tcv1(cl_hw) &&
+		   strcmp(cl_hw->chip->conf->ce_smac, "no_load")) {
+		if (cl_fw_load_smac(cl_hw))
+			return -1;
+	}
+
+	return 0;
+}
+
+void cl_fw_file_cleanup(struct cl_hw *cl_hw)
+{
+	/* Clean up all firmware allocations in cl_hw */
+	cl_dbgfile_release_mem(&cl_hw->dbg_data, &cl_hw->str_offload_env);
+}
+
+void cl_fw_file_release(struct cl_hw *cl_hw)
+{
+	struct cl_cached_fw *cached_fw = &cl_hw->cached_fw;
+
+	if (cached_fw->data) {
+		struct cl_dma_accessed *fw_rom = &cl_hw->fw_remote_rom;
+
+		vfree(cached_fw->data);
+		cached_fw->data = NULL;
+		cached_fw->size = 0;
+
+		if (fw_rom->drv_v_addr) {
+			dma_addr_t phys_dma_addr = fw_rom->dma_addr;
+
+			dma_free_coherent(cl_hw->chip->dev, fw_rom->size, fw_rom->drv_v_addr,
+					  phys_dma_addr);
+			fw_rom->drv_v_addr = NULL;
+			fw_rom->size = 0;
+			fw_rom->fw_v_addr = 0;
+			fw_rom->dma_addr = 0;
+		}
+	}
+}
+
+/* Should be used for REQ and CFM only */
+const char *const msg2str[MSG_TOTAL_REQ_CFM] = {
+	/* MM messages */
+	[MM_RESET_REQ] = "MM_RESET_REQ",
+	[MM_RESET_CFM] = "MM_RESET_CFM",
+	[MM_START_REQ] = "MM_START_REQ",
+	[MM_START_CFM] = "MM_START_CFM",
+	[MM_VERSION_REQ] = "MM_VERSION_REQ",
+	[MM_VERSION_CFM] = "MM_VERSION_CFM",
+	[MM_ADD_IF_REQ] = "MM_ADD_IF_REQ",
+	[MM_ADD_IF_CFM] = "MM_ADD_IF_CFM",
+	[MM_REMOVE_IF_REQ] = "MM_REMOVE_IF_REQ",
+	[MM_REMOVE_IF_CFM] = "MM_REMOVE_IF_CFM",
+	[MM_STA_ADD_REQ] = "MM_STA_ADD_REQ",
+	[MM_STA_ADD_CFM] = "MM_STA_ADD_CFM",
+	[MM_STA_DEL_REQ] = "MM_STA_DEL_REQ",
+	[MM_STA_DEL_CFM] = "MM_STA_DEL_CFM",
+	[MM_SET_FILTER_REQ] = "MM_SET_FILTER_REQ",
+	[MM_SET_FILTER_CFM] = "MM_SET_FILTER_CFM",
+	[MM_SET_CHANNEL_REQ] = "MM_SET_CHANNEL_REQ",
+	[MM_SET_CHANNEL_CFM] = "MM_SET_CHANNEL_CFM",
+	[MM_EXT_CALIB_REQ] = "MM_EXT_CALIB_REQ",
+	[MM_EXT_CALIB_CFM] = "MM_EXT_CALIB_CFM",
+	[MM_SET_DTIM_REQ] = "MM_SET_DTIM_REQ",
+	[MM_SET_DTIM_CFM] = "MM_SET_DTIM_CFM",
+	[MM_SET_BEACON_INT_REQ] = "MM_SET_BEACON_INT_REQ",
+	[MM_SET_BEACON_INT_CFM] = "MM_SET_BEACON_INT_CFM",
+	[MM_SET_BASIC_RATES_REQ] = "MM_SET_BASIC_RATES_REQ",
+	[MM_SET_BASIC_RATES_CFM] = "MM_SET_BASIC_RATES_CFM",
+	[MM_SET_BSSID_REQ] = "MM_SET_BSSID_REQ",
+	[MM_SET_BSSID_CFM] = "MM_SET_BSSID_CFM",
+	[MM_SET_EDCA_REQ] = "MM_SET_EDCA_REQ",
+	[MM_SET_EDCA_CFM] = "MM_SET_EDCA_CFM",
+	[MM_SET_ASSOCIATED_REQ] = "MM_SET_ASSOCIATED_REQ",
+	[MM_SET_ASSOCIATED_CFM] = "MM_SET_ASSOCIATED_CFM",
+	[MM_SET_SLOTTIME_REQ] = "MM_SET_SLOTTIME_REQ",
+	[MM_SET_SLOTTIME_CFM] = "MM_SET_SLOTTIME_CFM",
+	[MM_SET_IDLE_REQ] = "MM_SET_IDLE_REQ",
+	[MM_SET_IDLE_CFM] = "MM_SET_IDLE_CFM",
+	[MM_KEY_ADD_REQ] = "MM_KEY_ADD_REQ",
+	[MM_KEY_ADD_CFM] = "MM_KEY_ADD_CFM",
+	[MM_KEY_DEL_REQ] = "MM_KEY_DEL_REQ",
+	[MM_KEY_DEL_CFM] = "MM_KEY_DEL_CFM",
+	[MM_BA_ADD_TX_REQ] = "MM_BA_ADD_TX_REQ",
+	[MM_BA_ADD_TX_CFM] = "MM_BA_ADD_TX_CFM",
+	[MM_BA_ADD_RX_REQ] = "MM_BA_ADD_RX_REQ",
+	[MM_BA_ADD_RX_CFM] = "MM_BA_ADD_RX_CFM",
+	[MM_BA_DEL_REQ] = "MM_BA_DEL_REQ",
+	[MM_BA_DEL_CFM] = "MM_BA_DEL_CFM",
+	[MM_PHY_RESET_REQ] = "MM_PHY_RESET_REQ",
+	[MM_PHY_RESET_CFM] = "MM_PHY_RESET_CFM",
+	[MM_AVAILABLE_BA_TXQ_REQ] = "MM_AVAILABLE_BA_TXQ_REQ",
+	[MM_AVAILABLE_BA_TXQ_CFM] = "MM_AVAILABLE_BA_TXQ_CFM",
+	[MM_UPDATE_RATE_DL_REQ] = "MM_UPDATE_RATE_DL_REQ",
+	[MM_UPDATE_RATE_DL_CFM] = "MM_UPDATE_RATE_DL_CFM",
+	[MM_UPDATE_RATE_UL_REQ] = "MM_UPDATE_RATE_UL_REQ",
+	[MM_UPDATE_RATE_UL_CFM] = "MM_UPDATE_RATE_UL_CFM",
+	[MM_SET_VNS_REQ] = "MM_SET_VNS_REQ",
+	[MM_SET_VNS_CFM] = "MM_SET_VNS_CFM",
+	[MM_SET_TX_BF_REQ] = "MM_SET_TX_BF_REQ",
+	[MM_SET_TX_BF_CFM] = "MM_SET_TX_BF_CFM",
+	[MM_SOUNDING_REQ] = "MM_SOUNDING_REQ",
+	[MM_SOUNDING_CFM] = "MM_SOUNDING_CFM",
+	[MM_SOUNDING_PAIRING_REQ] = "MM_SOUNDING_PAIRING_REQ",
+	[MM_SOUNDING_PAIRING_CFM] = "MM_SOUNDING_PAIRING_CFM",
+	[MM_SOUNDING_INTERVAL_REQ] = "MM_SOUNDING_INTERVAL_REQ",
+	[MM_SOUNDING_INTERVAL_CFM] = "MM_SOUNDING_INTERVAL_CFM",
+	[MM_SET_DFS_REQ] = "MM_SET_DFS_REQ",
+	[MM_SET_DFS_CFM] = "MM_SET_DFS_CFM",
+	[MM_NDP_TX_CONTROL_REQ] = "MM_NDP_TX_CONTROL_REQ",
+	[MM_NDP_TX_CONTROL_CFM] = "MM_NDP_TX_CONTROL_CFM",
+	[MM_REG_WRITE_REQ] = "MM_REG_WRITE_REQ",
+	[MM_REG_WRITE_CFM] = "MM_REG_WRITE_CFM",
+	[MM_PROT_MODE_REQ] = "MM_PROT_MODE_REQ",
+	[MM_PROT_MODE_CFM] = "MM_PROT_MODE_CFM",
+	[MM_BACKUP_BCN_EN_REQ] = "MM_BACKUP_BCN_EN_REQ",
+	[MM_BACKUP_BCN_EN_CFM] = "MM_BACKUP_BCN_EN_CFM",
+	[MM_START_PERIODIC_TX_TIME_REQ] = "MM_START_PERIODIC_TX_TIME_REQ",
+	[MM_START_PERIODIC_TX_TIME_CFM] = "MM_START_PERIODIC_TX_TIME_CFM",
+	[MM_ANAMON_READ_REQ] = "MM_ANAMON_READ_REQ",
+	[MM_ANAMON_READ_CFM] = "MM_ANAMON_READ_CFM",
+	[MM_REFRESH_PWR_REQ] = "MM_REFRESH_PWR_REQ",
+	[MM_REFRESH_PWR_CFM] = "MM_REFRESH_PWR_CFM",
+	[MM_SET_ANT_PWR_OFFSET_REQ] = "MM_SET_ANT_PWR_OFFSET_REQ",
+	[MM_SET_ANT_PWR_OFFSET_CFM] = "MM_SET_ANT_PWR_OFFSET_CFM",
+	[MM_SET_RATE_FALLBACK_REQ] = "MM_SET_RATE_FALLBACK_REQ",
+	[MM_SET_RATE_FALLBACK_CFM] = "MM_SET_RATE_FALLBACK_CFM",
+	[MM_SPI_WRITE_REQ] = "MM_SPI_WRITE_REQ",
+	[MM_SPI_WRITE_CFM] = "MM_SPI_WRITE_CFM",
+	[MM_SPI_READ_REQ] = "MM_SPI_READ_REQ",
+	[MM_SPI_READ_CFM] = "MM_SPI_READ_CFM",
+
+	/* DBG messages */
+	[DBG_STR_SHIFT(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ",
+	[DBG_STR_SHIFT(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM",
+	[DBG_STR_SHIFT(DBG_CE_SET_MOD_FILTER_REQ)] = "DBG_CE_SET_MOD_FILTER_REQ",
+	[DBG_STR_SHIFT(DBG_CE_SET_MOD_FILTER_CFM)] = "DBG_CE_SET_MOD_FILTER_CFM",
+	[DBG_STR_SHIFT(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ",
+	[DBG_STR_SHIFT(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM",
+	[DBG_STR_SHIFT(DBG_GET_E2W_STATS_REQ)] = "DBG_GET_E2W_STATS_REQ",
+	[DBG_STR_SHIFT(DBG_GET_E2W_STATS_CFM)] = "DBG_GET_E2W_STATS_CFM",
+	[DBG_STR_SHIFT(DBG_SET_LA_MPIF_MASK_REQ)] = "DBG_SET_LA_MPIF_MASK_REQ",
+	[DBG_STR_SHIFT(DBG_SET_LA_MPIF_MASK_CFM)] = "DBG_SET_LA_MPIF_MASK_CFM",
+	[DBG_STR_SHIFT(DBG_SET_LA_TRIG_POINT_REQ)] = "DBG_SET_LA_TRIG_POINT_REQ",
+	[DBG_STR_SHIFT(DBG_SET_LA_TRIG_POINT_CFM)] = "DBG_SET_LA_TRIG_POINT_CFM",
+	[DBG_STR_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_REQ)] = "DBG_SET_LA_MPIF_DEBUG_MODE_REQ",
+	[DBG_STR_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_CFM)] = "DBG_SET_LA_MPIF_DEBUG_MODE_CFM",
+	[DBG_STR_SHIFT(DBG_SET_LA_TRIG_RULE_REQ)] = "DBG_SET_LA_TRIG_RULE_REQ",
+	[DBG_STR_SHIFT(DBG_SET_LA_TRIG_RULE_CFM)] = "DBG_SET_LA_TRIG_RULE_CFM",
+	[DBG_STR_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_REQ)] = "DBG_TX_TRACE_DEBUG_FLAG_REQ",
+	[DBG_STR_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_CFM)] = "DBG_TX_TRACE_DEBUG_FLAG_CFM",
+	[DBG_STR_SHIFT(DBG_PRINT_STATS_REQ)] = "DBG_PRINT_STATS_REQ",
+	[DBG_STR_SHIFT(DBG_PRINT_STATS_CFM)] = "DBG_PRINT_STATS_CFM",
+	[DBG_STR_SHIFT(DBG_TRIGGER_REQ)] = "DBG_TRIGGER_REQ",
+	[DBG_STR_SHIFT(DBG_TRIGGER_CFM)] = "DBG_TRIGGER_CFM",
+	[DBG_STR_SHIFT(DBG_TEST_MODE_REQ)] = "DBG_TEST_MODE_REQ",
+	[DBG_STR_SHIFT(DBG_TEST_MODE_CFM)] = "DBG_TEST_MODE_CFM",
+	[DBG_STR_SHIFT(DBG_SOUNDING_CMD_REQ)] = "DBG_SOUNDING_CMD_REQ",
+	[DBG_STR_SHIFT(DBG_SOUNDING_CMD_CFM)] = "DBG_SOUNDING_CMD_CFM",
+	[DBG_STR_SHIFT(DBG_PRESILICON_TESTING_REQ)] = "DBG_PRESILICON_TESTING_REQ",
+	[DBG_STR_SHIFT(DBG_PRESILICON_TESTING_CFM)] = "DBG_PRESILICON_TESTING_CFM",
+};
+
+static void cl_check_exception(struct cl_hw *cl_hw)
+{
+	/* Check if Tensilica exception occurred */
+	int i;
+	struct cl_ipc_exception_struct __iomem *data =
+		(struct cl_ipc_exception_struct __iomem *)cl_hw->ipc_env->shared;
+
+	if (__raw_readl(&data->pattern) != IPC_EXCEPTION_PATTERN)
+		return;
+
+	cl_dbg_err(cl_hw, "######################### firmware tensilica exception:\n");
+	cl_dbg_err(cl_hw, "................................. type: ");
+
+	switch (__raw_readl(&data->type)) {
+	case 0:
+		cl_dbg_err(cl_hw, "EXCEPTION_ILLEGALINSTRUCTION\n");
+		break;
+	case 2:
+		cl_dbg_err(cl_hw, "EXCEPTION_INSTRUCTIONFETCHERROR\n");
+		break;
+	case 3:
+		cl_dbg_err(cl_hw, "EXCEPTION_LOADSTOREERROR\n");
+		break;
+	case 6:
+		cl_dbg_err(cl_hw, "EXCEPTION_INTEGERDIVIDEBYZERO\n");
+		break;
+	case 7:
+		cl_dbg_err(cl_hw, "EXCEPTION_SPECULATION\n");
+		break;
+	case 8:
+		cl_dbg_err(cl_hw, "EXCEPTION_PRIVILEGED\n");
+		break;
+	case 9:
+		cl_dbg_err(cl_hw, "EXCEPTION_UNALIGNED\n");
+		break;
+	case 16:
+		cl_dbg_err(cl_hw, "EXCEPTION_INSTTLBMISS\n");
+		break;
+	case 17:
+		cl_dbg_err(cl_hw, "EXCEPTION_INSTTLBMULTIHIT\n");
+		break;
+	case 18:
+		cl_dbg_err(cl_hw, "EXCEPTION_INSTFETCHPRIVILEGE\n");
+		break;
+	case 20:
+		cl_dbg_err(cl_hw, "EXCEPTION_INSTFETCHPROHIBITED\n");
+		break;
+	case 24:
+		cl_dbg_err(cl_hw, "EXCEPTION_LOADSTORETLBMISS\n");
+		break;
+	case 25:
+		cl_dbg_err(cl_hw, "EXCEPTION_LOADSTORETLBMULTIHIT\n");
+		break;
+	case 26:
+		cl_dbg_err(cl_hw, "EXCEPTION_LOADSTOREPRIVILEGE\n");
+		break;
+	case 28:
+		cl_dbg_err(cl_hw, "EXCEPTION_LOADPROHIBITED\n");
+		break;
+	default:
+		cl_dbg_err(cl_hw, "unknown\n");
+		break;
+	}
+
+	cl_dbg_err(cl_hw, "................................. EPC: %08X\n",
+		   __raw_readl(&data->epc));
+	cl_dbg_err(cl_hw, "................................. EXCSAVE: %08X\n",
+		   __raw_readl(&data->excsave));
+	cl_dbg_err(cl_hw, "..............BACKTRACE-PC.....................\n");
+
+	for (i = 0; i < IPC_BACKTRACT_DEPTH; i++)
+		cl_dbg_err(cl_hw, "PC#%d: 0x%08X\n", i,
+			   __raw_readl(&data->backtrace.pc[i]));
+}
+
+static u16 cl_msg_cfm_clear_bit(u16 cfm)
+{
+	if (cfm < MM_REQ_CFM_MAX)
+		return ((cfm - 1) >> 1);
+
+	return ((cfm - 1 - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX) >> 1);
+}
+
+u16 cl_msg_cfm_set_bit(u16 req)
+{
+	if (req < MM_REQ_CFM_MAX)
+		return (req >> 1);
+
+	return ((req - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX) >> 1);
+}
+
+int cl_msg_cfm_wait(struct cl_hw *cl_hw, u16 bit, u16 req_id)
+{
+	/*
+	 * Start a timeout to stop on the main waiting queue,
+	 * and then check the result.
+	 */
+	struct cl_chip *chip = cl_hw->chip;
+	int timeout = 0, error = 0;
+	int max_timeout = 0;
+
+	if (IS_REAL_PHY(chip)) {
+		if (!cl_hw->msg_calib_timeout)
+			max_timeout = CL_MSG_CFM_TIMEOUT_JIFFIES;
+		else
+			max_timeout = CL_MSG_CFM_TIMEOUT_CALIB_JIFFIES;
+	} else if (chip->conf->ci_phy_dev == PHY_DEV_FRU) {
+		max_timeout = CL_MSG_CFM_TIMEOUT_FRU_JIFFIES;
+	} else {
+		max_timeout = CL_MSG_CFM_TIMEOUT_DUMMY_JIFFIES;
+	}
+
+	/* Wait for confirmation message */
+	timeout = wait_event_timeout(cl_hw->wait_queue,
+				     !CFM_TEST_BIT(bit, &cl_hw->cfm_flags),
+				     max_timeout);
+
+	if (timeout == 0) {
+		/*
+		 * Timeout occurred!
+		 * Make sure that confirmation wasn't received after the timeout.
+		 */
+		if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+			cl_dbg_verbose(cl_hw, "[WARN] Timeout occurred - %s\n",
+				       MSG_ID_STR(req_id));
+			error = -ETIMEDOUT;
+		}
+	}
+
+	if (error) {
+		struct cl_irq_stats *irq_stats = &chip->irq_stats;
+		unsigned long now = jiffies, flags;
+		u32 status, raw_status;
+
+		/*
+		 * The interrupt was not handled in time, lets try to handle it safely.
+		 * The spin lock protects us from the following race scenarios:
+		 * 1) atomic read of the IPC status register,
+		 * 2) execution on the msg handler twice from different context.
+		 * 3) disable context switch from the same core.
+		 */
+		spin_lock_irqsave(&chip->isr_lock, flags);
+
+		status = ipc_xmac_2_host_status_get(chip);
+		raw_status = ipc_xmac_2_host_raw_status_get(chip);
+
+		cl_dbg_verbose(cl_hw,
+			       "[INFO] status=0x%x, raw_status=0x%x, last_isr_statuses=0x%x, "
+			       "last_rx=%ums, last_tx=%ums, last_isr=%ums\n",
+			       status,
+			       raw_status,
+			       irq_stats->last_isr_statuses,
+			       jiffies_to_msecs(now - irq_stats->last_rx),
+			       jiffies_to_msecs(now - irq_stats->last_tx),
+			       jiffies_to_msecs(now - irq_stats->last_isr));
+
+		if (status & cl_hw->ipc_e2a_irq.msg) {
+			/*
+			 * WORKAROUND #1: In some cases the kernel is losing sync with the
+			 * interrupt handler and the reason is still unknown.
+			 * It seems that disabling master interrupt for a couple of cycles and
+			 * then re-enabling it restores the sync with the cl interrupt handler.
+			 */
+			ipc_host_global_int_en_set(chip, 0);
+
+			/* Acknowledge the MSG interrupt */
+			ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.msg);
+
+			/*
+			 * Unlock before calling cl_msg_rx_tasklet() because
+			 * spin_unlock_irqrestore() disables interrupts, but in
+			 * cl_msg_rx_tasklet() there might be several places that
+			 * use spin_unlock_bh() which enables soft-irqs.
+			 */
+			spin_unlock_irqrestore(&chip->isr_lock, flags);
+
+			/*
+			 * Call the tasklet handler (it also gives the CPU that
+			 * is mapped to the cl_interrupt few cycle to recover)
+			 */
+			cl_msg_rx_tasklet((unsigned long)cl_hw);
+
+			/* Re-enable master interrupts */
+			ipc_host_global_int_en_set(chip, 1);
+		} else {
+			/*
+			 * WORKAROUND #2: Try to call the handler unconditioanly.
+			 * Maybe we cleared the "cl_hw->ipc_e2a_irq.msg" without handling it.
+			 */
+
+			/*
+			 * Unlock before calling cl_msg_rx_tasklet() because
+			 * spin_unlock_irqrestore() disables interrupts, but in
+			 * cl_msg_rx_tasklet() there might be several places
+			 * that use spin_unlock_bh() which enables soft-irqs.
+			 */
+			spin_unlock_irqrestore(&chip->isr_lock, flags);
+
+			/* Call the tasklet handler */
+			cl_msg_rx_tasklet((unsigned long)cl_hw);
+		}
+
+		/* Did the workarounds work? */
+		if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+			cl_dbg_verbose(cl_hw, "[ERR] Failed to recover from timeout\n");
+		} else {
+			cl_dbg_verbose(cl_hw, "[INFO] Managed to recover from timeout\n");
+			error = 0;
+			goto exit;
+		}
+
+		/* Failed handling the message */
+		CFM_CLEAR_BIT(bit, &cl_hw->cfm_flags);
+
+		cl_check_exception(cl_hw);
+
+		cl_hw_assert_check(cl_hw);
+
+		if (!strcmp(chip->conf->ce_ela_mode, "XTDEBUG") ||
+		    !strcmp(chip->conf->ce_ela_mode, "XTDEBUG_STD")) {
+			/*
+			 * TODO: Special debug hack: collect debug info & skip restart
+			 * "wait4cfm" string is expected by debug functionality
+			 */
+			goto exit;
+		}
+
+		if (!test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags) &&
+		    !test_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags) &&
+		    test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+		    !cl_hw->is_stop_context) {
+			/* Unlock msg mutex before restarting */
+			mutex_unlock(&cl_hw->msg_tx_mutex);
+
+			cl_recovery_start(cl_hw, RECOVERY_WAIT4CFM);
+			return error;
+		}
+	}
+
+exit:
+	/* Unlock msg mutex */
+	mutex_unlock(&cl_hw->msg_tx_mutex);
+
+	return error;
+}
+
+static void cl_msg_cfm_assign_params(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	u32 *param;
+	u16 msg_id = le16_to_cpu(msg->id);
+	u16 msg_len = le16_to_cpu(msg->param_len);
+
+	/* A message sent in background is not allowed to assign confirmation parameters */
+	if (cl_hw->msg_background) {
+		cl_dbg_verbose(cl_hw,
+			       "Background message can't assign confirmation parameters (%s)\n",
+			       MSG_ID_STR(msg_id));
+		return;
+	}
+
+	if (msg->param_len) {
+		param = kzalloc(msg_len, GFP_ATOMIC);
+		if (param) {
+			memcpy(param, msg->param, msg_len);
+			if (cl_hw->msg_cfm_params[msg_id])
+				cl_dbg_err(cl_hw, "msg_cfm_params is not NULL for %s\n",
+					   MSG_ID_STR(msg_id));
+			cl_hw->msg_cfm_params[msg_id] = param;
+		} else {
+			cl_dbg_err(cl_hw, "param allocation failed\n");
+		}
+	} else {
+		u16 dummy_dest_id = le16_to_cpu(msg->dummy_dest_id);
+		u16 dummy_src_id = le16_to_cpu(msg->dummy_src_id);
+
+		cl_dbg_err(cl_hw, "msg->param_len is 0 [%u,%u,%u]\n",
+			   msg_id, dummy_dest_id, dummy_src_id);
+	}
+}
+
+void cl_msg_cfm_assign_and_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	u16 bit = cl_msg_cfm_clear_bit(le16_to_cpu(msg->id));
+
+	if (CFM_TEST_BIT(bit, &cl_hw->cfm_flags)) {
+		cl_msg_cfm_assign_params(cl_hw, msg);
+		CFM_CLEAR_BIT(bit, &cl_hw->cfm_flags);
+	} else {
+		cl_dbg_verbose(cl_hw, "Msg ID not set in cfm_flags (%s)\n",
+			       MSG_ID_STR(le16_to_cpu(msg->id)));
+	}
+}
+
+void cl_msg_cfm_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	u16 bit = cl_msg_cfm_clear_bit(le16_to_cpu(msg->id));
+
+	if (!CFM_TEST_AND_CLEAR_BIT(bit, &cl_hw->cfm_flags))
+		cl_dbg_verbose(cl_hw, "Msg ID not set in cfm_flags (%s)\n",
+			       MSG_ID_STR(le16_to_cpu(msg->id)));
+}
+
+static inline void rx_mm_start_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	cl_msg_cfm_clear(cl_hw, msg);
+
+	/* Send indication to the embedded that a new rxbuffer element are ready */
+	cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_RXBUF_BACK);
+}
+
+static inline void rx_mm_ba_add_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	if (le16_to_cpu(msg->id) == MM_BA_ADD_TX_CFM)
+		cl_msg_cfm_assign_and_clear(cl_hw, msg);
+	else
+		cl_msg_cfm_clear(cl_hw, msg);
+}
+
+static inline void rx_mm_agg_tx_report_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	struct cl_agg_tx_report *agg_report = (struct cl_agg_tx_report *)msg->param;
+	struct cl_sta *cl_sta;
+	union cl_rate_ctrl_info rate_ctrl_info;
+	u8 queue_idx = agg_report->tx_queue_idx;
+	u16 ssn = agg_report->new_ssn;
+
+	/* First handle agg cfm */
+	cl_tx_release_skbs_from_cfm(cl_hw, queue_idx, ssn);
+	/*
+	 * Take care of endianness and update gi and format_mod fields of rate
+	 * ctrl info in agg_report for the sake of any function that needs to
+	 * use them
+	 */
+	rate_ctrl_info.word = le32_to_cpu(agg_report->rate_cntrl_info);
+
+	cl_rate_ctrl_convert(&rate_ctrl_info);
+	agg_report->rate_cntrl_info = cpu_to_le32(rate_ctrl_info.word);
+
+	cl_sta_lock(cl_hw);
+	cl_sta = cl_sta_get(cl_hw, agg_report->sta_idx);
+
+	if (cl_sta) {
+		/* TX stats */
+		cl_agg_tx_report_handler(cl_hw, cl_sta, (void *)agg_report);
+		cl_stats_update_tx_agg(cl_hw, cl_sta, agg_report);
+
+		/* RSSI stats */
+		if (!agg_report->ba_not_received)
+			cl_rssi_block_ack_handler(cl_hw, cl_sta, agg_report);
+
+		/*
+		 * TODO: Do we need to notify upper layer at agg_report->success?
+		 * Ageout may need to reset ageout counter if at least one
+		 * frame was success.
+		 * May be needed when sending UDP downlink because BA's are not
+		 * forwarded to driver.
+		 */
+	}
+
+	cl_sta_unlock(cl_hw);
+
+	/* Schedule tasklet to try and empty the queue */
+	tasklet_schedule(&cl_hw->tx_task);
+}
+
+static inline void rx_mm_agg_rx_report_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	struct mm_agg_rx_ind *agg_report = (struct mm_agg_rx_ind *)msg->param;
+	struct cl_sta *cl_sta = NULL;
+	u8 sta_loc;
+
+	for (sta_loc = 0; sta_loc < agg_report->sta_num; sta_loc++) {
+		cl_sta_lock(cl_hw);
+		cl_sta = cl_sta_get(cl_hw, agg_report->sta_idx[sta_loc]);
+		if (cl_sta)
+			cl_agg_rx_report_handler(cl_hw, cl_sta, sta_loc, agg_report);
+		cl_sta_unlock(cl_hw);
+	}
+}
+
+static inline void rx_mm_sounding_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	struct mm_sounding_ind *ind = (struct mm_sounding_ind *)msg->param;
+
+	cl_sounding_indication(cl_hw, ind);
+}
+
+static inline void rx_mm_fw_error_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	struct mm_fw_error_ind *ind = (struct mm_fw_error_ind *)msg->param;
+
+	switch (ind->error_type) {
+	case MM_FW_ERROR_TYPE_MAX:
+	default:
+		cl_dbg_err(cl_hw, "Invalid fw error type %u\n", ind->error_type);
+		break;
+	}
+}
+
+static inline void rx_mm_idle_async_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	cl_hw->idle_async_set = false;
+
+	cl_dbg_trace(cl_hw, "Clear MM_IDLE_ASYNC_IND\n");
+}
+
+static inline void rx_dbg_print_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	cl_hw_assert_print(cl_hw, msg);
+}
+
+static inline void rx_dbg_info_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	cl_fw_dbg_handler(cl_hw);
+}
+
+static void (*mm_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+	[MM_RESET_CFM]                  = cl_msg_cfm_clear,
+	[MM_START_CFM]                  = rx_mm_start_cfm,
+	[MM_VERSION_CFM]                = cl_msg_cfm_assign_and_clear,
+	[MM_ADD_IF_CFM]                 = cl_msg_cfm_assign_and_clear,
+	[MM_REMOVE_IF_CFM]              = cl_msg_cfm_clear,
+	[MM_STA_ADD_CFM]                = cl_msg_cfm_assign_and_clear,
+	[MM_STA_DEL_CFM]                = cl_msg_cfm_clear,
+	[MM_SET_FILTER_CFM]             = cl_msg_cfm_clear,
+	[MM_SET_CHANNEL_CFM]            = cl_msg_cfm_clear,
+	[MM_EXT_CALIB_CFM]              = cl_msg_cfm_clear,
+	[MM_SET_DTIM_CFM]               = cl_msg_cfm_clear,
+	[MM_SET_BEACON_INT_CFM]         = cl_msg_cfm_clear,
+	[MM_SET_BASIC_RATES_CFM]        = cl_msg_cfm_clear,
+	[MM_SET_BSSID_CFM]              = cl_msg_cfm_clear,
+	[MM_SET_EDCA_CFM]               = cl_msg_cfm_clear,
+	[MM_SET_ASSOCIATED_CFM]         = cl_msg_cfm_clear,
+	[MM_SET_SLOTTIME_CFM]           = cl_msg_cfm_clear,
+	[MM_SET_IDLE_CFM]               = cl_msg_cfm_clear,
+	[MM_KEY_ADD_CFM]                = cl_msg_cfm_assign_and_clear,
+	[MM_KEY_DEL_CFM]                = cl_msg_cfm_clear,
+	[MM_BA_ADD_TX_CFM]              = rx_mm_ba_add_cfm,
+	[MM_BA_ADD_RX_CFM]              = rx_mm_ba_add_cfm,
+	[MM_BA_DEL_CFM]                 = cl_msg_cfm_assign_and_clear,
+	[MM_AVAILABLE_BA_TXQ_CFM]       = cl_msg_cfm_assign_and_clear,
+	[MM_UPDATE_RATE_DL_CFM]         = cl_msg_cfm_clear,
+	[MM_UPDATE_RATE_UL_CFM]         = cl_msg_cfm_clear,
+	[MM_SET_VNS_CFM]                = cl_msg_cfm_clear,
+	[MM_SET_TX_BF_CFM]              = cl_msg_cfm_clear,
+	[MM_PHY_RESET_CFM]              = cl_msg_cfm_clear,
+	[MM_SET_DFS_CFM]                = cl_msg_cfm_clear,
+	[MM_NDP_TX_CONTROL_CFM]         = cl_msg_cfm_clear,
+	[MM_REG_WRITE_CFM]              = cl_msg_cfm_clear,
+	[MM_PROT_MODE_CFM]              = cl_msg_cfm_clear,
+	[MM_SOUNDING_CFM]               = cl_msg_cfm_assign_and_clear,
+	[MM_SOUNDING_PAIRING_CFM]       = cl_msg_cfm_clear,
+	[MM_SOUNDING_INTERVAL_CFM]      = cl_msg_cfm_assign_and_clear,
+	[MM_BACKUP_BCN_EN_CFM]          = cl_msg_cfm_clear,
+	[MM_START_PERIODIC_TX_TIME_CFM] = cl_msg_cfm_clear,
+	[MM_ANAMON_READ_CFM]            = cl_msg_cfm_assign_and_clear,
+	[MM_REFRESH_PWR_CFM]            = cl_msg_cfm_clear,
+	[MM_SET_ANT_PWR_OFFSET_CFM]     = cl_msg_cfm_clear,
+	[MM_SET_RATE_FALLBACK_CFM]      = cl_msg_cfm_clear,
+	[MM_SPI_WRITE_CFM]              = cl_msg_cfm_clear,
+	[MM_SPI_READ_CFM]               = cl_msg_cfm_assign_and_clear,
+	[MM_AGG_TX_REPORT_IND]          = rx_mm_agg_tx_report_ind,
+	[MM_AGG_RX_REPORT_IND]          = rx_mm_agg_rx_report_ind,
+	[MM_SOUNDING_IND]               = rx_mm_sounding_ind,
+	[MM_FW_ERROR_IND]               = rx_mm_fw_error_ind,
+	[MM_IDLE_ASYNC_IND]             = rx_mm_idle_async_ind,
+	[MM_MAX]                        = NULL,
+};
+
+#define DBG_MSG_SHIFT(id)  ((id) - FIRST_MSG(TASK_DBG))
+
+static void (*dbg_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+	[DBG_MSG_SHIFT(DBG_SET_MOD_FILTER_CFM)]         = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_SET_SEV_FILTER_CFM)]         = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_CE_SET_MOD_FILTER_CFM)]      = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_GET_E2W_STATS_CFM)]          = cl_msg_cfm_assign_and_clear,
+	[DBG_MSG_SHIFT(DBG_SET_LA_MPIF_MASK_CFM)]       = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_SET_LA_TRIG_POINT_CFM)]      = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_CFM)] = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_SET_LA_TRIG_RULE_CFM)]       = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_CFM)]    = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_PRINT_STATS_CFM)]            = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_TRIGGER_CFM)]                = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_TEST_MODE_CFM)]              = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_SOUNDING_CMD_CFM)]           = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_PRESILICON_TESTING_CFM)]     = cl_msg_cfm_clear,
+	[DBG_MSG_SHIFT(DBG_PRINT_IND)]                  = rx_dbg_print_ind,
+	[DBG_MSG_SHIFT(DBG_INFO_IND)]                   = rx_dbg_info_ind,
+	[DBG_MSG_SHIFT(DBG_MAX)]                        = NULL,
+};
+
+static bool cl_is_dbg_msg(u16 msg_id)
+{
+	return (msg_id >= FIRST_MSG(TASK_DBG) && msg_id < DBG_MAX);
+}
+
+static void cl_msg_rx_run_mm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+	if (msg_id < MM_REQ_CFM_MAX)
+		cl_dbg_trace(cl_hw, "%s\n", msg2str[msg_id]);
+
+	mm_hdlrs[msg_id](cl_hw, msg);
+}
+
+static int cl_msg_rx_run_dbg(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+	u16 dbg_id = DBG_MSG_SHIFT(msg_id);
+
+	if (dbg_hdlrs[dbg_id]) {
+		if (msg_id < DBG_REQ_CFM_MAX) {
+			u16 str_id = DBG_STR_SHIFT(msg_id);
+
+			cl_dbg_trace(cl_hw, "%s\n", msg2str[str_id]);
+		}
+
+		dbg_hdlrs[dbg_id](cl_hw, msg);
+		return 0;
+	}
+
+	return -1;
+}
+
+static int cl_msg_rx_run(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	u16 msg_id = le16_to_cpu(msg->id);
+
+	if (msg_id < MM_MAX && mm_hdlrs[msg_id]) {
+		cl_msg_rx_run_mm(cl_hw, msg, msg_id);
+		return 0;
+	}
+
+	if (cl_is_dbg_msg(msg_id))
+		return cl_msg_rx_run_dbg(cl_hw, msg, msg_id);
+
+	return -1;
+}
+
+static bool cl_is_cfm_msg(u16 msg_id)
+{
+	/* A confirmation must be an odd id */
+	if ((msg_id & 0x1) == 0)
+		return false;
+
+	return ((msg_id < MM_FIRST_IND) || cl_is_dbg_msg(msg_id));
+}
+
+static int cl_msg_rx_handler(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	int ret = 0;
+	u16 msg_id = le16_to_cpu(msg->id);
+
+	/* Relay further actions to the msg parser */
+	ret = cl_msg_rx_run(cl_hw, msg);
+
+	if (ret) {
+		cl_dbg_err(cl_hw, "Unexpected msg (%u)\n", msg_id);
+	} else {
+		/* Wake up the queue in case the msg is a confirmation */
+		if (cl_is_cfm_msg(msg_id))
+			wake_up(&cl_hw->wait_queue);
+	}
+
+	return ret;
+}
+
+void cl_msg_rx_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_e2a_msg_elem *msg_elem = NULL;
+	struct cl_ipc_e2a_msg *msg = NULL;
+	int msg_handled = 0;
+	u8 idx;
+
+	while (1) {
+		idx = ipc_env->e2a_msg_host_idx;
+		msg_elem = (struct cl_e2a_msg_elem *)(ipc_env->e2a_msg_hostbuf_array[idx].hostid);
+		msg = msg_elem->msgbuf_ptr;
+
+		/* Look for pattern which means that this hostbuf has been used for a MSG */
+		if (le32_to_cpu(msg->pattern) != IPC_E2A_MSG_VALID_PATTERN)
+			break;
+
+		cl_msg_rx_handler(cl_hw, msg);
+		msg_handled++;
+
+		/* Reset the msg element and re-use it */
+		msg->pattern = 0;
+
+		/* Make sure memory is written before push to HW */
+		wmb();
+
+		/* Push back the buffer */
+		cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+	}
+}
+
+void cl_msg_rx_flush_all(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	for (i = FIRST_MSG(TASK_MM); i < MM_MAX; i++) {
+		if (cl_hw->msg_cfm_params[i]) {
+			cl_dbg_verbose(cl_hw, "free MM msg_cfm_params %d\n", i);
+			cl_msg_tx_free_cfm_params(cl_hw, i);
+		}
+	}
+
+	for (i = FIRST_MSG(TASK_DBG); i < DBG_MAX; i++) {
+		if (cl_hw->msg_cfm_params[i]) {
+			cl_dbg_verbose(cl_hw, "free DBG msg_cfm_params %d\n", i);
+			cl_msg_tx_free_cfm_params(cl_hw, i);
+		}
+	}
+}
+
+#define DRV_TASK_ID 100
+
+#define CL_DEF_ANT_BITMAP 0x55
+
+/* No scale-down on ASIC platform */
+#define CL_ASIC_FW_SCALEDOWN 1
+
+struct cl_msg_tx_work {
+	struct work_struct ws;
+
+	/* Background message info */
+	struct cl_hw *cl_hw;
+	void *msg_params;
+};
+
+void cl_msg_tx_free_cfm_params(struct cl_hw *cl_hw, u16 id)
+{
+	/* Free message and set pointer to NULL */
+	kfree(cl_hw->msg_cfm_params[id]);
+	cl_hw->msg_cfm_params[id] = NULL;
+}
+
+static inline void *cl_msg_zalloc(struct cl_hw *cl_hw, u16 msg_id, u8 dst_task_id, u16 param_len)
+{
+	struct cl_fw_msg *msg;
+	u32 total_size = ALIGN(sizeof(struct cl_fw_msg) + param_len, sizeof(u32));
+	u32 max_size = sizeof(u32) * IPC_A2E_MSG_BUF_SIZE;
+
+	if (total_size > max_size) {
+		cl_dbg_err(cl_hw, "total size (%u) > max size (%u)\n",
+			   total_size, max_size);
+		return NULL;
+	}
+
+	/* msg is freed out of the scope of this function */
+	msg = kzalloc(total_size, GFP_ATOMIC);
+	if (!msg)
+		return NULL;
+
+	msg->msg_id = cpu_to_le16(msg_id);
+	msg->dst_kern_id = cl_hw->fw_dst_kern_id;
+	msg->dst_task_id = dst_task_id;
+	msg->src_kern_id = KERN_HOST;
+	msg->src_task_id = DRV_TASK_ID;
+	msg->param_len = cpu_to_le16(param_len);
+
+	return msg->param;
+}
+
+static inline void cl_msg_free(const void *msg_param)
+{
+	kfree(container_of((void *)msg_param, struct cl_fw_msg, param));
+}
+
+static void cl_send_msg_background_handler(struct work_struct *ws)
+{
+	struct cl_msg_tx_work *msg_tx_work = container_of(ws, struct cl_msg_tx_work, ws);
+
+	cl_drv_ops_msg_fw_send(msg_tx_work->cl_hw, msg_tx_work->msg_params, true);
+	kfree(msg_tx_work);
+}
+
+static int cl_send_msg_background(struct cl_hw *cl_hw,
+				  const void *msg_params)
+{
+	/* Generate & populate the work struct wrapper for the background msg */
+	struct cl_msg_tx_work *msg_tx_work = kzalloc(sizeof(*msg_tx_work), GFP_ATOMIC);
+
+	if (msg_tx_work) {
+		INIT_WORK(&msg_tx_work->ws, cl_send_msg_background_handler);
+		msg_tx_work->cl_hw = cl_hw;
+		msg_tx_work->msg_params = (void *)msg_params;
+
+		/* Schedule work, the work will be executed in the background */
+		queue_work(cl_hw->drv_workqueue, &msg_tx_work->ws);
+
+		return 0;
+	}
+
+	cl_dbg_err(cl_hw, "msg_tx_work allocation failed\n");
+	cl_msg_free(msg_params);
+
+	return -ENODATA;
+}
+
+static int cl_send_request(struct cl_hw *cl_hw, const void *msg_params)
+{
+	int ret;
+	bool background = (preempt_count() != 0);
+
+	if (background) {
+		/*
+		 * asynchronous operation mode, message would be triggered in the background
+		 */
+		ret = cl_send_msg_background(cl_hw, msg_params);
+	} else {
+		/*
+		 * synchronous operation mode, message would be triggered immediately
+		 * feedback to caller given immediately
+		 */
+		ret = cl_drv_ops_msg_fw_send(cl_hw, msg_params, false);
+	}
+
+	/*
+	 * In case of synchronous mode ret success implies that the msg was successfully
+	 * transmited where is asynchronous mode ret success implies that the msg was
+	 * successfully pushed to background queue
+	 */
+	return ret;
+}
+
+int cl_msg_tx_reset(struct cl_hw *cl_hw)
+{
+	void *void_param;
+
+	/* RESET REQ has no parameter */
+	void_param = cl_msg_zalloc(cl_hw, MM_RESET_REQ, TASK_MM, 0);
+	if (!void_param)
+		return -ENOMEM;
+
+	return cl_send_request(cl_hw, void_param);
+}
+
+static u8 cl_copy_mask_bits(u8 mask, u8 num_bits)
+{
+	/* Copy first X bits that are set in mask to new_mask */
+	u8 i = 0, cntr = 0, new_mask = 0;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		if (mask & BIT(i)) {
+			new_mask |= BIT(i);
+
+			cntr++;
+			if (cntr == num_bits)
+				break;
+		}
+	}
+
+	return new_mask;
+}
+
+static void cl_fill_ant_config(struct cl_hw *cl_hw,
+			       struct cl_antenna_config *ant_config,
+			       u8 num_antennas, u8 mask_antennas,
+			       u8 tx_mask_cck, u8 rx_mask_cck)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 ricu_cdb = 0;
+	u8 riu_chain_mask = 0x0;
+	u8 ant, riu_chain;
+
+	riu_chain_mask = cl_hw_ant_mask_to_riu_chain_mask(cl_hw, mask_antennas);
+	ant_config->num_tx_he = num_antennas;
+	ant_config->num_rx = num_antennas;
+	ant_config->mask_tx_he = riu_chain_mask;
+	ant_config->mask_rx = riu_chain_mask;
+
+	/* Configuration for TX OFDM/HT/VHT (limited to 4 antennas) */
+	if (num_antennas <= MAX_ANTENNAS_OFDM_HT_VHT) {
+		ant_config->num_tx_ofdm_ht_vht = num_antennas;
+		ant_config->mask_tx_ofdm_ht_vht = riu_chain_mask;
+	} else {
+		ant_config->num_tx_ofdm_ht_vht = MAX_ANTENNAS_OFDM_HT_VHT;
+		ant_config->mask_tx_ofdm_ht_vht =
+			cl_copy_mask_bits(riu_chain_mask, MAX_ANTENNAS_OFDM_HT_VHT);
+	}
+
+	/* Antenna configuration for CCK */
+	if (cl_band_is_24g(cl_hw)) {
+		for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+			riu_chain = cl_hw_ant_to_riu_chain(cl_hw, ant);
+
+			if (tx_mask_cck & BIT(ant))
+				ant_config->mask_tx_cck |= BIT(riu_chain);
+
+			if (rx_mask_cck & BIT(ant))
+				ant_config->mask_rx_cck |= BIT(riu_chain);
+		}
+	}
+
+	if (IS_REAL_PHY(chip))
+		ricu_cdb = ricu_static_conf_0_cdb_mode_maj_getf(chip);
+	else
+		ricu_cdb = 4;
+
+	/*
+	 * In current implementation cdb_mode equals the num of ants for SX1
+	 * cbd_mask 0x0 -> SX0 chain. 0x1-> SX1 chain.
+	 */
+	ricu_cdb = MAX_ANTENNAS_CHIP - ricu_cdb;
+	ricu_cdb = ANT_MASK(ricu_cdb);
+	ricu_cdb = ~ricu_cdb;
+
+	ant_config->cdb_mask = ricu_cdb;
+
+	cl_dbg_trace(cl_hw, "num_tx_he %u, num_rx %u, mask_tx he 0x%x, mask_rx 0x%x, "
+	       "mask_tx_ofdm_ht_vht 0x%x, mask_tx_cck 0x%x, mask_rx_cck 0x%x\n",
+	       ant_config->num_tx_he, ant_config->num_rx, ant_config->mask_tx_he,
+	       ant_config->mask_rx, ant_config->mask_tx_ofdm_ht_vht, ant_config->mask_tx_cck,
+	       ant_config->mask_rx_cck);
+}
+
+static void cl_fill_fem_config(struct cl_hw *cl_hw, struct cl_fem_config *fem_conf)
+{
+	int i;
+	u32 reg[FEM_REGISTERS_AMOUNT] = {0};
+
+	cl_fem_get_registers(cl_hw, reg);
+
+	for (i = 0; i < FEM_REGISTERS_AMOUNT; i++)
+		fem_conf->reg[i] = cpu_to_le32(reg[i]);
+}
+
+static void cl_fill_calib_chain(struct cl_calib_chain *chain, u8 pair, u8 tx_gain, u8 rx_gain)
+{
+	chain->pair = pair;
+	chain->initial_tx_gain = tx_gain;
+	chain->initial_rx_gain = rx_gain;
+}
+
+static void cl_fill_chain_by_plan(struct cl_hw *cl_hw, struct cl_calib_param *calib_param, u8 chain,
+				  bool is_tx)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	struct cl_calib_chain *chain_msg_dst = is_tx ?
+					       &calib_param->tx_calib_chain[chain] :
+					       &calib_param->rx_calib_chain[chain];
+
+	/* Fill chain params by default values from nvram */
+	if (is_tx)
+		cl_fill_calib_chain(chain_msg_dst, conf->ci_calib_ant_tx[chain],
+				    conf->ci_calib_tx_init_tx_gain[chain],
+				    conf->ci_calib_tx_init_rx_gain[chain]);
+	else
+		cl_fill_calib_chain(chain_msg_dst, conf->ci_calib_ant_rx[chain],
+				    conf->ci_calib_rx_init_tx_gain[chain],
+				    conf->ci_calib_rx_init_rx_gain[chain]);
+}
+
+static void cl_fill_calib_config(struct cl_hw *cl_hw, struct cl_calib_param *calib_param,
+				 u16 primary, u16 center, struct cl_calib_params calib_params)
+{
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	s8 sx_freq_offset_mhz;
+	u8 mode = calib_params.mode;
+	u8 chain = 0;
+	u8 calib_bitmap = calib_params.plan_bitmap;
+
+	memset(calib_param->tx_calib_chain, U8_MAX, sizeof(struct cl_calib_chain) * MAX_ANTENNAS);
+	memset(calib_param->rx_calib_chain, U8_MAX, sizeof(struct cl_calib_chain) * MAX_ANTENNAS);
+
+	riu_chain_for_each(chain) {
+		if (calib_bitmap & (1 << chain)) {
+			/* TX fill */
+			cl_fill_chain_by_plan(cl_hw, calib_param, chain, true);
+			if (mode & SET_CHANNEL_MODE_CALIB_IQ)
+				/* RX fill */
+				cl_fill_chain_by_plan(cl_hw, calib_param, chain, false);
+		}
+	}
+
+	calib_param->conf.rx_gain_upper_limit = conf->ci_calib_conf_rx_gain_upper_limit;
+	calib_param->conf.rx_gain_lower_limit = conf->ci_calib_conf_rx_gain_lower_limit;
+	calib_param->conf.nco_freq = cpu_to_le16(CALIB_NCO_FREQ_DEFAULT);
+	calib_param->conf.nco_amp = CALIB_NCO_AMP_DEFAULT;
+	calib_param->conf.sleeve_trshld = GAIN_SLEEVE_TRSHLD_DEFAULT;
+	calib_param->conf.n_samples_exp_lolc = N_SAMPLES_EXP_LOLC;
+	calib_param->conf.n_samples_exp_iqc = N_SAMPLES_EXP_IQC;
+	calib_param->conf.p_thresh = cpu_to_le32(LO_P_THRESH);
+	calib_param->conf.n_bit_fir_scale = N_BIT_FIR_SCALE;
+	calib_param->conf.n_bit_amp_scale = N_BIT_AMP_SCALE;
+	calib_param->conf.n_bit_phase_scale = N_BIT_PHASE_SCALE;
+
+	cl_calib_iq_get_tone_vector(cl_hw, calib_param->conf.tone_vector);
+
+	calib_param->conf.gp_rad_trshld = cpu_to_le32(conf->ci_calib_conf_gp_rad_trshld);
+	calib_param->conf.ga_lin_upper_trshld =
+		cpu_to_le32(conf->ci_calib_conf_ga_lin_upper_trshld);
+	calib_param->conf.ga_lin_lower_trshld =
+		cpu_to_le32(conf->ci_calib_conf_ga_lin_lower_trshld);
+	calib_param->conf.comp_filter_len = COMP_FILTER_LEN_DEFAULT;
+	calib_param->conf.singletons_num = conf->ci_calib_conf_singletons_num;
+	calib_param->conf.tones_num = IQ_NUM_TONES_REQ;
+	calib_param->conf.rampup_time = cpu_to_le16(conf->ci_calib_conf_rampup_time);
+	calib_param->conf.lo_coarse_step = cpu_to_le16(conf->ci_calib_conf_lo_coarse_step);
+	calib_param->conf.lo_fine_step = cpu_to_le16(conf->ci_calib_conf_lo_fine_step);
+
+	sx_freq_offset_mhz = calib_params.sx_freq_offset_mhz;
+
+	calib_param->other_tcv.prim20_freq = cpu_to_le16(primary + sx_freq_offset_mhz);
+	cl_phy_oly_lut_update(cl_hw->chip->rfic_version, cl_hw->nl_band,
+			      center + sx_freq_offset_mhz,
+			      &calib_param->other_tcv.center1_freq_lut);
+
+	if (cl_chip_is_both_enabled(cl_hw->chip)) {
+		calib_param->other_tcv.mask_tx_he =
+			cl_hw_ant_mask_to_riu_chain_mask(cl_hw_other,
+							 cl_hw_other->mask_num_antennas);
+		calib_param->other_tcv.num_tx_he = cl_hw_other->num_antennas;
+		calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw_other);
+	} else {
+		calib_param->other_tcv.mask_tx_he =
+			cl_hw_ant_mask_to_riu_chain_mask(cl_hw, cl_hw->mask_num_antennas);
+		calib_param->other_tcv.num_tx_he = cl_hw->num_antennas;
+		calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw);
+	}
+
+	cl_dbg_info(cl_hw, "tcv_idx = %u, channel = %u, bw = %u, sx_freq_offset_mhz = %d\n",
+		    cl_hw->tcv_idx, cl_hw->channel, cl_hw->bw, sx_freq_offset_mhz);
+	cl_dbg_info(cl_hw, "|       TX Calibration      ||       RX Calibration      |\n");
+	cl_dbg_info(cl_hw, "|chain|pair |tx_gain|rx_gain||chain|pair |tx_gain|rx_gain|\n");
+	riu_chain_for_each(chain) {
+		cl_dbg_info(cl_hw, "|  %u  |  %u  | 0x%X  | 0x%X  ||  %u  |  %u  | 0x%X  | 0x%X  |"
+			    "\n", chain, calib_param->tx_calib_chain[chain].pair,
+			    calib_param->tx_calib_chain[chain].initial_tx_gain,
+			    calib_param->tx_calib_chain[chain].initial_rx_gain, chain,
+			    calib_param->rx_calib_chain[chain].pair,
+			    calib_param->rx_calib_chain[chain].initial_tx_gain,
+			    calib_param->rx_calib_chain[chain].initial_rx_gain);
+	}
+}
+
+int cl_msg_tx_start(struct cl_hw *cl_hw)
+{
+	struct mm_start_req *req;
+	struct cl_phy_cfg *phy_cfg;
+	struct cl_start_param *param;
+	struct cl_cca_config *cca_config;
+	struct dbg_meta_data *dbg_metadata;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_tcv_conf *tcv_conf = cl_hw->conf;
+	struct cl_chip_conf *chip_conf = chip->conf;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+
+	u8 bw = 0, ant = 0;
+	int ret_val;
+
+	req = cl_msg_zalloc(cl_hw, MM_START_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	phy_cfg = &req->phy_cfg;
+	param = &req->param;
+	cca_config = &phy_cfg->cca_config;
+	dbg_metadata = &param->dbg_metadata;
+
+	phy_cfg->band = cl_band_to_fw_idx(cl_hw);
+
+	if (cl_hw_other)
+		phy_cfg->other_band = cl_band_to_fw_idx(cl_hw_other);
+
+	phy_cfg->channel_bandwidth = tcv_conf->ci_cap_bandwidth;
+	phy_cfg->ht_rxldpc_en = tcv_conf->ci_ht_rxldpc_en;
+	phy_cfg->freq_offset = cpu_to_le16(chip->eeprom_cache->calib_power.freq_offset);
+	phy_cfg->vns_tx_power_mode = cl_hw_is_prod_or_listener(cl_hw) ? 0 :
+		tcv_conf->ci_vns_pwr_mode;
+	phy_cfg->vns_rssi_suto_resp_th = tcv_conf->ci_vns_rssi_auto_resp_thr;
+	phy_cfg->afe_config_en = chip_conf->ci_afe_config_en;
+	phy_cfg->no_capture_noise_sleep = chip_conf->ci_no_capture_noise_sleep;
+	phy_cfg->gain_update_enable = tcv_conf->ci_gain_update_enable;
+	phy_cfg->mcs_sig_b = tcv_conf->ci_mcs_sig_b;
+	phy_cfg->ofdm_only = tcv_conf->ci_ofdm_only;
+	phy_cfg->hr_factor = tcv_conf->ci_hr_factor[phy_cfg->channel_bandwidth];
+	phy_cfg->td_csd_en = tcv_conf->ci_csd_en;
+	phy_cfg->pe_duration_bcast = tcv_conf->ci_pe_duration_bcast;
+	phy_cfg->tx_digital_gain = cpu_to_le32(tcv_conf->ci_tx_digital_gain);
+	phy_cfg->tx_digital_gain_cck = cpu_to_le32(tcv_conf->ci_tx_digital_gain_cck);
+	phy_cfg->ofdm_cck_power_offset = (u8)tcv_conf->ci_ofdm_cck_power_offset;
+	phy_cfg->phy_clk_gating_en = tcv_conf->ci_phy_clk_gating_en;
+	phy_cfg->tcv1_chains_sx0 = chip_conf->ci_tcv1_chains_sx0;
+	phy_cfg->dsp_lcu_mode = tcv_conf->ci_dsp_lcu_mode;
+
+	/*
+	 * Set rx_sensitivity according to number of antennas.
+	 * For all other antennas set 0xff which is equal to -1
+	 */
+	memcpy(phy_cfg->rx_sensitivity, cl_hw->rx_sensitivity, MAX_ANTENNAS);
+
+	if (!cl_hw->fw_send_start) {
+		cl_hw->fw_send_start = true;
+		phy_cfg->first_start = true;
+	}
+
+	cl_fill_ant_config(cl_hw, &phy_cfg->ant_config, cl_hw->num_antennas,
+			   cl_hw->mask_num_antennas, tcv_conf->ce_cck_tx_ant_mask,
+			   tcv_conf->ce_cck_rx_ant_mask);
+	cl_fill_fem_config(cl_hw, &phy_cfg->fem_conf);
+
+	if (!chip->rf_reg_overwrite || cl_recovery_in_progress(cl_hw)) {
+		chip->rf_reg_overwrite = true;
+		cl_rfic_read_overwrite_file(cl_hw,
+					    phy_cfg->rf_reg_overwrite_info,
+					    true);
+	}
+
+	cca_config->ed_rise_thr_dbm = (u8)tcv_conf->ci_cca_ed_rise_thr_dbm;
+	cca_config->ed_fall_thr_dbm = (u8)tcv_conf->ci_cca_ed_fall_thr_dbm;
+	cca_config->cs_en = tcv_conf->ci_cca_cs_en;
+	cca_config->modem_en = tcv_conf->ci_cca_modem_en;
+	cca_config->main_ant = cl_hw_ant_to_riu_chain(cl_hw, tcv_conf->ci_cca_main_ant);
+	cca_config->second_ant = cl_hw_ant_to_riu_chain(cl_hw, tcv_conf->ci_cca_second_ant);
+	cca_config->flag0_ctrl = tcv_conf->ci_cca_flag0_ctrl;
+	cca_config->flag1_ctrl = tcv_conf->ci_cca_flag1_ctrl;
+	cca_config->flag2_ctrl = tcv_conf->ci_cca_flag2_ctrl;
+	cca_config->flag3_ctrl = tcv_conf->ci_cca_flag3_ctrl;
+	cca_config->gi_rise_thr_dbm = (u8)tcv_conf->ci_cca_gi_rise_thr_dbm;
+	cca_config->gi_fall_thr_dbm = (u8)tcv_conf->ci_cca_gi_fall_thr_dbm;
+	cca_config->gi_pow_lim_dbm = (u8)tcv_conf->ci_cca_gi_pow_lim_dbm;
+	cca_config->ed_en = cpu_to_le16(tcv_conf->ci_cca_ed_en);
+	cca_config->gi_en = tcv_conf->ci_cca_gi_en;
+
+	param->prot_log_nav_en = tcv_conf->ce_prot_log_nav_en;
+	param->prot_mode = cl_prot_mode_get(cl_hw);
+	param->prot_rate_format = tcv_conf->ce_prot_rate_format;
+	param->prot_rate_mcs = tcv_conf->ce_prot_rate_mcs;
+	param->prot_rate_pre_type = tcv_conf->ce_prot_rate_pre_type;
+	param->bw_signaling_mode = tcv_conf->ce_bw_signaling_mode;
+	param->cfm_size = cpu_to_le16(IPC_CFM_SIZE);
+	param->cfm_dma_base_addr = cpu_to_le32(ipc_env->cfm_dma_base_addr);
+	param->phy_dev = cpu_to_le16(chip_conf->ci_phy_dev);
+	param->fw_scale_down = cpu_to_le16(CL_ASIC_FW_SCALEDOWN);
+	param->hal_timeout.idle = cpu_to_le32(tcv_conf->ci_hal_idle_to);
+	param->hal_timeout.ac0 = cpu_to_le32(tcv_conf->ci_tx_ac0_to);
+	param->hal_timeout.ac1 = cpu_to_le32(tcv_conf->ci_tx_ac1_to);
+	param->hal_timeout.ac2 = cpu_to_le32(tcv_conf->ci_tx_ac2_to);
+	param->hal_timeout.ac3 = cpu_to_le32(tcv_conf->ci_tx_ac3_to);
+	param->hal_timeout.bcn = cpu_to_le32(tcv_conf->ci_tx_bcn_to);
+
+	/* Update rxbuff/txqueue & ring_indices that hold the array metadata */
+	param->ipc_ring_indices_base = cpu_to_le32(ipc_env->ring_indices_elem->dma_addr);
+	param->host_rxbuf_base_addr[CL_RX_BUF_RXM] =
+		ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM].dma_payload_base_addr;
+	param->host_rxbuf_base_addr[CL_RX_BUF_FW] =
+		ipc_env->rx_hostbuf_array[CL_RX_BUF_FW].dma_payload_base_addr;
+
+	/*
+	 * The FW needs to be aware of the DMA addresses of the
+	 * TX queues so it could fetch txdesc from the host.
+	 */
+	param->ipc_host_tx_queues_dma_addr = cpu_to_le32(cl_hw->ipc_env->tx_queues.dma_addr);
+
+	/*
+	 * Compilation flags match check - please add here all compilation flags
+	 * which should be compiled on both driver and firmware.
+	 */
+	param->comp_flags = cpu_to_le32(0) | cpu_to_le32(BIT(CENX_CFG_CE_TX_CFM));
+	param->dbg_test_mode_max = cpu_to_le16(DBG_TEST_MODE_MAX);
+	param->ipc_rxbuf_size[CL_RX_BUF_RXM] =
+		cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM]);
+	param->ipc_rxbuf_size[CL_RX_BUF_FW] =
+		cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW]);
+
+	param->host_pci_gen_ver = chip_conf->ce_host_pci_gen_ver;
+	param->dma_lli_max_chan[0] = chip_conf->ci_dma_lli_max_chan[0];
+	param->dma_lli_max_chan[1] = chip_conf->ci_dma_lli_max_chan[1];
+	param->production_mode = chip_conf->ce_production_mode;
+	param->mult_ampdu_in_txop_en = tcv_conf->ci_mult_ampdu_in_txop_en;
+	param->cca_timeout = cpu_to_le32(tcv_conf->ci_cca_timeout);
+	param->long_retry_limit = tcv_conf->ce_long_retry_limit;
+	param->short_retry_limit = tcv_conf->ce_short_retry_limit;
+	param->assoc_auth_retry_limit = tcv_conf->ci_assoc_auth_retry_limit;
+	param->bcn_tx_path_min_time = cpu_to_le16(tcv_conf->ce_bcn_tx_path_min_time);
+	param->backup_bcn_en = tcv_conf->ci_backup_bcn_en;
+	param->tx_txop_cut_en = tcv_conf->ce_tx_txop_cut_en;
+	param->ac_with_bcns_flushed_cnt_thr = tcv_conf->ci_bcns_flushed_cnt_thr;
+	param->txl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_txl_statistics));
+	param->rxl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_rxl_statistics));
+	param->phy_err_prevents_phy_dump = tcv_conf->ci_phy_err_prevents_phy_dump;
+	param->tx_rx_delay = tcv_conf->ci_tx_rx_delay;
+	param->assert_storm_detect_thd = tcv_conf->ci_fw_assert_storm_detect_thd;
+	param->assert_time_diff_sec = tcv_conf->ci_fw_assert_time_diff_sec;
+	param->ps_ctrl_enabled = tcv_conf->ce_ps_ctrl_enabled;
+	param->phy_data_dma_addr = cpu_to_le32(cl_hw->phy_data_info.dma_addr);
+	param->phy_remote_rom_dma_addr = cpu_to_le32(cl_hw->fw_remote_rom.dma_addr);
+	param->iq_dcoc_calib_tables_dma_addr = cpu_to_le32(cl_hw->iq_dcoc_data_info.dma_addr);
+	param->power_table_dma_addr = cpu_to_le32(cl_hw->power_table_info.dma_addr);
+	param->min_ant_pwr_q1 = cl_power_min_ant_q1(cl_hw);
+
+	for (bw = 0; bw < ARRAY_SIZE(param->bw_factor_q2); bw++) {
+		cl_hw->power_db.bw_factor_q2[bw] = cl_power_bw_factor_q2(cl_hw, bw);
+		param->bw_factor_q2[bw] =
+			cl_convert_signed_to_reg_value(cl_hw->power_db.bw_factor_q2[bw]);
+	}
+
+	for (ant = 0; ant < ARRAY_SIZE(param->ant_factor_q2); ant++) {
+		cl_hw->power_db.ant_factor_q2[ant] = cl_power_array_gain_q2(cl_hw, ant + 1);
+		param->ant_factor_q2[ant] = cl_hw->power_db.ant_factor_q2[ant];
+	}
+
+	param->default_distance.auto_resp_all = tcv_conf->ci_distance_auto_resp_all;
+	param->default_distance.auto_resp_msta = tcv_conf->ci_distance_auto_resp_msta;
+	param->su_force_min_spacing_usec = tcv_conf->ci_su_force_min_spacing;
+	param->mu_force_min_spacing_usec = tcv_conf->ci_mu_force_min_spacing;
+	param->single_tcv = cl_hw_is_tcv0(cl_hw) ?
+		cl_chip_is_only_tcv0_enabled(chip) : cl_chip_is_only_tcv1_enabled(chip);
+	param->rx_padding = tcv_conf->ci_rx_padding_en;
+	param->bar_cap_disable = tcv_conf->ci_bar_disable;
+	param->hw_bsr = tcv_conf->ci_hw_bsr;
+	param->drop_to_lower_bw = tcv_conf->ci_drop_to_lower_bw;
+	param->dra_enable = cl_chip_is_both_enabled(chip); /* DRA enable only in CDB mode */
+	param->mac_clk_gating_en = tcv_conf->ci_mac_clk_gating_en;
+	param->imaging_blocker = tcv_conf->ci_imaging_blocker;
+	param->fec_coding = tcv_conf->ci_he_rxldpc_en;
+	param->cs_required = tcv_conf->ci_cs_required;
+	param->fw_disable_recovery = tcv_conf->ci_fw_disable_recovery;
+
+	dbg_metadata->lmac_req_buf_size = cpu_to_le32(sizeof(struct dbg_error_trace_info_drv));
+	dbg_metadata->physical_queue_cnt = CL_MAX_BA_PHYSICAL_QUEUE_CNT;
+	dbg_metadata->agg_index_max = AGG_IDX_MAX;
+	dbg_metadata->ce_ac_max = CE_AC_MAX;
+	dbg_metadata->mu_user_max = MU_MAX_STREAMS;
+	dbg_metadata->txl_exch_trace_depth = DBG_TXL_FRAME_EXCH_TRACE_DEPTH;
+	dbg_metadata->mac_hw_regs_max = cpu_to_le16(HAL_MACHW_REG_NUM);
+	dbg_metadata->phy_hw_regs_max = cpu_to_le16(PHY_HW_DBG_REGS_CNT);
+	dbg_metadata->thd_chains_data_size = cpu_to_le16(DBG_THD_CHAINS_INFO_ARRAY_SIZE);
+	dbg_metadata->chains_info_elem_cnt = DBG_CHAINS_INFO_ELEM_CNT;
+
+	/* RFIC_init requires that only one TCV may enter */
+	mutex_lock(&chip->start_msg_lock);
+	phy_cfg->is_first_rfic = !chip->first_start_sent;
+	chip->first_start_sent = true;
+
+	ret_val = cl_send_request(cl_hw, req);
+	mutex_unlock(&chip->start_msg_lock);
+
+	return ret_val;
+}
+
+int cl_msg_tx_version(struct cl_hw *cl_hw)
+{
+	void *void_param;
+
+	/* VERSION REQ has no parameter */
+	void_param = cl_msg_zalloc(cl_hw, MM_VERSION_REQ, TASK_MM, 0);
+	if (!void_param)
+		return -ENOMEM;
+
+	return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_add_if(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+		     u8 vif_index)
+{
+	struct mm_add_if_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_ADD_IF_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	cl_mac_addr_copy(req->addr.array, vif->addr);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		req->type = MM_STA;
+		break;
+
+	case NL80211_IFTYPE_ADHOC:
+		req->type = MM_IBSS;
+		break;
+
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		req->type = MM_AP;
+		break;
+
+	case NL80211_IFTYPE_MONITOR:
+		req->type = MM_MONITOR;
+		break;
+
+	case NL80211_IFTYPE_MESH_POINT:
+		req->type = MM_MESH_POINT;
+		break;
+
+	default:
+		req->type = MM_STA;
+		break;
+	}
+
+	req->tx_strip_vlan = 1;
+	req->mac_addr_hi_mask = cpu_to_le32(cl_hw->mask_hi);
+	req->mac_addr_low_mask = cpu_to_le32(cl_hw->mask_low);
+	req->inst_nbr = vif_index;
+
+	if (vif->type == NL80211_IFTYPE_AP) {
+		struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+		struct ps_data *ps = &sdata->u.ap.ps;
+
+		req->start_dtim_count = (u8)(ps->dtim_count);
+	}
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_remove_if(struct cl_hw *cl_hw, u8 vif_index)
+{
+	struct mm_remove_if_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_REMOVE_IF_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->inst_nbr = vif_index;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+		      struct cl_vif *cl_vif, u8 recovery_sta_idx,
+		      u32 rate_ctrl_info)
+{
+	struct mm_sta_add_req *req;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+	struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+	u16 my_aid = 0;
+	u8 inst_nbr = cl_vif->vif_index;
+	bool is_6g = cl_band_is_6g(cl_hw);
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+	req = cl_msg_zalloc(cl_hw, MM_STA_ADD_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	cl_mac_addr_copy(req->mac_addr.array, sta->addr);
+
+	if (cl_vif->vif->type == NL80211_IFTYPE_STATION)
+		my_aid = cl_vif->vif->bss_conf.aid;
+
+	if (is_6g) {
+		u8 mac_cap_info4 = he_cap->he_cap_elem.mac_cap_info[4];
+
+		req->su_bfee = !!(mac_cap_info4 & IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE);
+		req->mu_bfee = !!(mac_cap_info4 & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER);
+	} else if (vht_cap->vht_supported) {
+		req->su_bfee = !!(vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+		req->mu_bfee = !!(vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+	}
+
+	req->ampdu_min_spacing = cl_sta->ampdu_min_spacing;
+
+	if (he_cap->has_he) {
+		u8 mac_cap_info1 = he_cap->he_cap_elem.mac_cap_info[1];
+		u8 mac_cap_info3 = he_cap->he_cap_elem.mac_cap_info[3];
+
+		req->he_tf_mac_padding_duration =
+			(mac_cap_info1 & IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK);
+
+		req->he_rx_ctrl_frm_to_mbss =
+			(mac_cap_info3 & IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS);
+		/* Fill PE duration table */
+		cl_cap_ppe_duration(cl_hw, sta, req->pe_duration);
+	}
+
+	cl_ampdu_size_exp(cl_hw, sta, &req->ampdu_size_exp_he,
+			  &req->ampdu_size_exp_vht, &req->ampdu_size_exp_ht);
+
+	if (cl_hw->conf->ce_txldpc_en) {
+		if (he_cap->has_he)
+			req->ldpc_enabled = !!(he_cap->he_cap_elem.phy_cap_info[1] &
+					     IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD);
+		else if (vht_cap->vht_supported)
+			req->ldpc_enabled = !!(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC);
+		else if (ht_cap->ht_supported)
+			req->ldpc_enabled = !!(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING);
+	}
+
+	/* TODO: Set the interface index from the vif structure */
+	req->inst_nbr = inst_nbr;
+
+	req->aid = cpu_to_le16(sta->aid);
+	req->my_aid = cpu_to_le16(my_aid);
+	req->recovery_sta_idx = recovery_sta_idx;
+
+	/* Station power save configuration */
+	req->uapsd_queues = sta->uapsd_queues;
+	req->max_sp = sta->max_sp;
+
+	/* Set WRS default parameters for rate control */
+	req->tx_params.rate = cpu_to_le32(rate_ctrl_info);
+
+	/* Fill TX antenna with default value */
+	req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_del(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	struct mm_sta_del_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_STA_DEL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_filter(struct cl_hw *cl_hw, u32 filter, bool force)
+{
+	struct mm_set_filter_req *req;
+	u32 rx_filter = 0;
+
+	if (force)
+		rx_filter = filter;
+	else
+		rx_filter = cl_rx_filter_update_flags(cl_hw, filter);
+
+	if (rx_filter == cl_hw->rx_filter) {
+		cl_dbg_trace(cl_hw, "Rx filter 0x%x already set - return\n", rx_filter);
+		return 0;
+	}
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_FILTER_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	/* Now copy all the flags into the message parameter */
+	req->filter = cpu_to_le32(rx_filter);
+	cl_hw->rx_filter = rx_filter;
+
+	cl_dbg_trace(cl_hw, "new total_flags = 0x%08x\nrx filter set to  0x%08x\n",
+		     filter, rx_filter);
+
+	return cl_send_request(cl_hw, req);
+}
+
+static u8 cl_mark_calib_flags(struct cl_hw *cl_hw, u8 mode)
+{
+	int lna = 0;
+	int chain = 0;
+	u8 calib_info_set = 0;
+	struct cl_iq_dcoc_info *iq_dcoc_db = &cl_hw->phy_data_info.data->iq_dcoc_db;
+
+	/* In case DCOC is going to be calibrated, no need to raise any calibration flag. */
+	if (mode & SET_CHANNEL_MODE_CALIB_DCOC)
+		return calib_info_set;
+
+	/* Check if DCOC flag should be marked */
+	for (lna = 0; lna < DCOC_LNA_GAIN_NUM; lna++) {
+		riu_chain_for_each(chain) {
+			if (iq_dcoc_db->dcoc[lna][chain].i || iq_dcoc_db->dcoc[lna][chain].q) {
+				calib_info_set |= SET_PHY_DATA_FLAGS_DCOC;
+				break;
+			}
+		}
+	}
+
+	/* Check if IQ Tx LOLC flag should be marked */
+	riu_chain_for_each(chain) {
+		if (iq_dcoc_db->iq_tx_lolc[chain]) {
+			calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX_LOLC;
+			break;
+		}
+	}
+
+	/* Check if IQ Tx flag should be marked */
+	riu_chain_for_each(chain) {
+		if (iq_dcoc_db->iq_tx[chain].coef0 || iq_dcoc_db->iq_tx[chain].coef1 ||
+		    iq_dcoc_db->iq_tx[chain].coef2 || iq_dcoc_db->iq_tx[chain].gain) {
+			calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX;
+			break;
+		}
+	}
+
+	/* Check if IQ Rx flag should be marked */
+	riu_chain_for_each(chain) {
+		if (iq_dcoc_db->iq_rx[chain].coef0 || iq_dcoc_db->iq_rx[chain].coef1 ||
+		    iq_dcoc_db->iq_rx[chain].coef2 || iq_dcoc_db->iq_rx[chain].gain) {
+			calib_info_set |= SET_PHY_DATA_FLAGS_IQ_RX;
+			return calib_info_set;
+		}
+	}
+	return calib_info_set;
+}
+
+static int _cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u16 primary,
+				  u16 center, struct cl_calib_params calib_params)
+{
+	struct mm_set_channel_req *req;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+
+	int res = 0;
+	struct cl_phy_data *data = cl_hw->phy_data_info.data;
+	u8 mode = calib_params.mode;
+
+	if (WARN_ON_ONCE(channel == 0))
+		return -EINVAL;
+
+	/* Fill AGC parameters - check before we start building the message */
+	if (cl_agc_params_fill(cl_hw, &data->agc_params))
+		return -1;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_CHANNEL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->band = cl_band_to_fw_idx(cl_hw);
+
+	if (cl_hw_other)
+		req->other_band = cl_band_to_fw_idx(cl_hw_other);
+
+	req->bandwidth = bw;
+	req->prim20_freq = cpu_to_le16(primary);
+	cl_phy_oly_lut_update(cl_hw->chip->rfic_version, cl_hw->nl_band, center,
+			      &req->center1_freq_lut);
+	req->sx_freq_offset_mhz = calib_params.sx_freq_offset_mhz;
+	req->hr_factor = cl_hw->conf->ci_hr_factor[bw];
+	req->signal_ext = cl_hw->conf->ci_signal_extension_en;
+
+	/* Set power per mcs offset after EIRP truncation */
+	cl_power_tables_update(cl_hw, &data->pwr_tables);
+
+	/* Get antenna power offset from eeprom */
+	cl_calib_power_offset_fill(cl_hw, channel, bw, req->ant_pwr_offset);
+
+	if (cl_hw->conf->ce_listener_en)
+		cl_calib_common_fill_phy_data(cl_hw, &data->iq_dcoc_db,
+					      SET_PHY_DATA_FLAGS_LISTENER);
+	else
+		cl_calib_common_fill_phy_data(cl_hw, &data->iq_dcoc_db, SET_PHY_DATA_FLAGS_ALL);
+
+	req->calib_info_set = cl_mark_calib_flags(cl_hw, mode);
+	req->calib_param.mode = mode;
+
+	if (mode & (SET_CHANNEL_MODE_CALIB_LOLC | SET_CHANNEL_MODE_CALIB_IQ))
+		cl_fill_calib_config(cl_hw, &req->calib_param, primary, center, calib_params);
+
+	if (mode & SET_CHANNEL_MODE_CALIB_DCOC) {
+		if (cl_hw->chip->conf->ci_phy_dev == PHY_DEV_ATHOS) {
+			u8 rfic_version = cl_hw->chip->rfic_version;
+
+			if (rfic_version == U8_MAX)
+				cl_dbg_trace(cl_hw, "Couldn't read rfic version\n");
+
+			if (rfic_version == ATHOS_B_VER)
+				req->calib_param.dcoc_max_vga = DCOC_MAX_VGA_ATHOS_B;
+			else
+				req->calib_param.dcoc_max_vga = DCOC_MAX_VGA_ATHOS;
+		} else {
+			req->calib_param.dcoc_max_vga = DCOC_MAX_VGA;
+		}
+	}
+
+	/* Antenna configuration */
+	cl_fill_ant_config(cl_hw, &req->ant_config, cl_hw->num_antennas, cl_hw->mask_num_antennas,
+			   cl_hw->conf->ce_cck_tx_ant_mask, cl_hw->conf->ce_cck_rx_ant_mask);
+	/* FEM configuration */
+	cl_fill_fem_config(cl_hw, &req->fem_conf);
+
+	cl_rfic_read_overwrite_file(cl_hw, req->rf_reg_overwrite_info, false);
+
+	cl_dbg_info(cl_hw,
+		    "band=%u, other_band=%u, channel=%u, bw=%u, primary=%u.%u, center=%u.%u, sx_index=%u\n",
+		    cl_hw->conf->ci_band_num, req->other_band, channel, bw, GET_FREQ_INT(primary),
+		    GET_FREQ_FRAC(primary), GET_FREQ_INT(center), GET_FREQ_FRAC(center),
+		    cl_hw->tcv_idx);
+
+	res = cl_send_request(cl_hw, req);
+
+	cl_temperature_comp_update_calib(cl_hw);
+
+	return res;
+}
+
+int cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+			  u32 center, struct cl_calib_params calib_params)
+{
+	int res = 0;
+	u8 mode = calib_params.mode;
+	s8 sx_freq_offset_mhz = calib_params.sx_freq_offset_mhz;
+	u32 primary_q2 = FREQ_TO_Q2(primary);
+	u32 center_q2 = FREQ_TO_Q2(center);
+
+	/*
+	 * Need to take mutex lock to ensure that no one touching the phy_data
+	 * DMA before FW is reading all its values.
+	 * The mutex is unlocked right after the iq_dcoc_data_info DMA is
+	 * handled in cl_calib_common_handle_set_channel_cfm.
+	 */
+	res = mutex_lock_interruptible(&cl_hw->set_channel_mutex);
+
+	if (res != 0) {
+		cl_dbg_verbose(cl_hw, "Error - mutex_lock_interruptible (%d)\n", res);
+		return res;
+	}
+
+	cl_hw->channel = channel;
+	cl_hw->bw = bw;
+	cl_hw->primary_freq = primary;
+	cl_hw->center_freq = center;
+
+	if (mode == SET_CHANNEL_MODE_CALIB_MANUAL) {
+		primary_q2 += sx_freq_offset_mhz;
+		center_q2 += sx_freq_offset_mhz;
+	}
+
+	if (mode & SET_CHANNEL_MODE_CALIB)
+		cl_hw->msg_calib_timeout = true;
+
+	res = _cl_msg_tx_set_channel(cl_hw, channel, bw, primary_q2, center_q2, calib_params);
+
+	if (mode & SET_CHANNEL_MODE_CALIB) {
+		cl_hw->msg_calib_timeout = false;
+
+		if (!res)
+			res = cl_calib_common_handle_set_channel_cfm(cl_hw, calib_params);
+	}
+
+	mutex_unlock(&cl_hw->set_channel_mutex);
+
+	return res;
+}
+
+int cl_msg_tx_dtim(struct cl_hw *cl_hw, u8 dtim_period)
+{
+	struct mm_set_dtim_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_DTIM_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->dtim_period = dtim_period;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_beacon_int(struct cl_hw *cl_hw, u16 beacon_int, u8 vif_idx)
+{
+	struct mm_set_beacon_int_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_BEACON_INT_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->beacon_int = cpu_to_le16(beacon_int);
+	req->inst_nbr = vif_idx;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_basic_rates(struct cl_hw *cl_hw, u32 basic_rates)
+{
+	struct mm_set_basic_rates_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_BASIC_RATES_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->rates = cpu_to_le32(basic_rates);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_bssid(struct cl_hw *cl_hw, const u8 *bssid, u8 vif_idx)
+{
+	struct mm_set_bssid_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_BSSID_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	cl_mac_addr_copy(req->bssid.array, bssid);
+	req->inst_nbr = vif_idx;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_edca(struct cl_hw *cl_hw, u8 hw_queue, u32 param,
+		       struct ieee80211_he_mu_edca_param_ac_rec *mu_edca)
+{
+	struct mm_set_edca_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_EDCA_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->ac_param = cpu_to_le32(param);
+	req->hw_queue = hw_queue;
+
+	if (mu_edca) {
+		req->mu_edca_aifsn = mu_edca->aifsn;
+		req->mu_edca_ecw_min_max = mu_edca->ecw_min_max;
+		req->mu_edca_timer = mu_edca->mu_edca_timer;
+	}
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_associated(struct cl_hw *cl_hw,
+			     struct ieee80211_bss_conf *bss_conf)
+{
+	struct mm_set_associated_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_ASSOCIATED_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->aid = cpu_to_le16(bss_conf->aid);
+
+	/* Multiple BSSID feature support */
+	if (bss_conf->nontransmitted && bss_conf->assoc) {
+		u8 i = 0;
+		u8 mask_addr[ETH_ALEN] = {0};
+		u32 bssid_hi_mask = 0;
+		u32 bssid_low_mask = 0;
+
+		for (i = 0; i < ETH_ALEN; i++)
+			mask_addr[i] = (bss_conf->transmitter_bssid[i] ^
+					bss_conf->bssid[i]);
+		cl_mac_addr_array_to_nxmac(mask_addr, &bssid_low_mask,
+					   &bssid_hi_mask);
+		/* Set mask to allow the transmitter BSSID Rx reception */
+		req->bssid_hi_mask = cpu_to_le32(bssid_hi_mask);
+		req->bssid_low_mask = cpu_to_le32(bssid_low_mask);
+	}
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_slottime(struct cl_hw *cl_hw, bool use_short_slot)
+{
+	struct mm_set_slottime_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_SLOTTIME_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->slottime = use_short_slot ? 9 : 20;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_idle(struct cl_hw *cl_hw, u8 idle, bool is_lock)
+{
+	struct mm_set_idle_req *req;
+	int ret = 0;
+
+	if (cl_fem_read_wiring_id(cl_hw->chip)) {
+		cl_dbg_err(cl_hw, "!!! Invalid wiring id [%u] !!! Aborting\n",
+			   cl_hw->chip->fem.wiring_id);
+		return -1;
+	}
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_IDLE_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	if (is_lock)
+		mutex_lock(&cl_hw->chip->set_idle_mutex);
+
+	req->hw_idle = idle;
+
+	cl_dbg_info(cl_hw, "idle = %s\n", idle ? "True" : "False");
+
+	ret = cl_send_request(cl_hw, req);
+
+	if (is_lock)
+		mutex_unlock(&cl_hw->chip->set_idle_mutex);
+
+	return ret;
+}
+
+void cl_msg_tx_idle_async(struct cl_hw *cl_hw, bool is_lock)
+{
+	if (!IS_REAL_PHY(cl_hw->chip))
+		return;
+
+	cl_hw->idle_async_set = true;
+	cl_msg_tx_set_idle(cl_hw, MAC_IDLE_ASYNC, is_lock);
+}
+
+int cl_msg_tx_key_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+		      struct ieee80211_sta *sta,
+		      struct ieee80211_key_conf *key_conf,
+		      u8 cipher_suite)
+{
+	struct mm_key_add_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_KEY_ADD_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	/* Set Pairwise Default key */
+	if (sta)
+		req->sta_idx = ((struct cl_sta *)sta->drv_priv)->sta_idx;
+	else
+		req->sta_idx = 0xFF;
+
+	req->key_idx = (u8)(key_conf->keyidx);
+	req->inst_nbr = ((struct cl_vif *)vif->drv_priv)->vif_index;
+	req->key.length = key_conf->keylen;
+
+	/* TODO: check if this works well in Big endian platforms */
+	memcpy(req->key.array, key_conf->key, key_conf->keylen);
+
+	req->cipher_suite = cipher_suite;
+	req->spp = cl_hw->conf->ci_spp_ksr_value;
+
+	cl_dbg_info(cl_hw, "sta_idx:%u, key_idx:%u, inst_nbr:%u, cipher:%u, key_len:%u, spp:%u\n",
+		    req->sta_idx, req->key_idx, req->inst_nbr,
+		    req->cipher_suite, req->key.length, req->spp);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_key_del(struct cl_hw *cl_hw, u8 hw_key_idx)
+{
+	struct mm_key_del_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_KEY_DEL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->hw_key_idx = hw_key_idx;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_add(struct cl_hw *cl_hw, u8 type, u8 sta_idx,
+		     u16 tid, u16 bufsz, u16 ssn)
+{
+	struct mm_ba_add_req *req;
+	u16 msg_id = ((type == BA_AGMT_TX) ? MM_BA_ADD_TX_REQ : MM_BA_ADD_RX_REQ);
+
+	req = cl_msg_zalloc(cl_hw, msg_id, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->type = type;
+	req->sta_idx = sta_idx;
+	req->tid = (u8)tid;
+	req->bufsz = cpu_to_le16(bufsz);
+	req->ssn = cpu_to_le16(ssn);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_del(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+	struct mm_ba_del_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_BA_DEL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+	req->tid = (u8)tid;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_available_ba_txq(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+	struct mm_available_ba_txq_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_AVAILABLE_BA_TXQ_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+	req->tid = (u8)tid;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_update_rate_dl(struct cl_hw *cl_hw, u8 sta_idx, u32 rate, u32 rate_fallback,
+			     u8 req_bw_tx, u8 op_mode, u8 gid, u8 mu_valid, u8 ltf,
+			     u8 ltf_fallback, u32 rate_he)
+{
+	struct mm_update_rate_dl_req *req;
+
+	cl_dbg_info(cl_hw, "sta_idx=%u, rate=0x%x, rate_fallback=0x%x, req_bw_tx=%u, "
+		    "op_mode=%u, gid=%u, mu_valid=%u, ltf=%u, ltf_fallback=%u, rate_he=0x%x\n",
+		    sta_idx, rate, rate_fallback, req_bw_tx, op_mode, gid, mu_valid,
+		    ltf, ltf_fallback, rate_he);
+
+	req = cl_msg_zalloc(cl_hw, MM_UPDATE_RATE_DL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->tx_params.rate = cpu_to_le32(rate);
+	req->tx_params.rate_he = cpu_to_le32(rate_he);
+	req->tx_params.req_bw_tx = req_bw_tx;
+	req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+	req->tx_params.ltf = ltf;
+
+	req->op_mode = op_mode;
+	req->sta_idx = sta_idx;
+	req->rate_fallback = cpu_to_le32(rate_fallback);
+	req->ltf_fallback = ltf_fallback;
+
+	/* Gid & mu valid bit is relevant only for MU rate updates. */
+	if (op_mode == RATE_OP_MODE_STA_MU) {
+		req->group_id = gid;
+		req->mu_is_rate_valid = mu_valid;
+	}
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_update_rate_ul(struct cl_hw *cl_hw, u8 sta_idx, u8 bw, u8 nss, u8 mcs, u8 gi_ltf)
+{
+	struct mm_update_rate_ul_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_UPDATE_RATE_UL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+	req->bw = bw;
+	req->nss = nss;
+	req->mcs = mcs;
+	req->gi_ltf = gi_ltf;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_vns(struct cl_hw *cl_hw, u8 sta_idx, u8 is_vns)
+{
+	struct mm_set_vns_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_VNS_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+	req->is_vns = is_vns;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_tx_bf(struct cl_hw *cl_hw, u8 sta_idx, u8 is_on, u8 is_on_fallback)
+{
+	struct mm_set_tx_bf_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_TX_BF_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sta_idx = sta_idx;
+	req->is_on = is_on;
+	req->is_on_fallback = is_on_fallback;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding(struct cl_hw *cl_hw,
+		       struct mm_sounding_req *sounding_req)
+{
+	struct mm_sounding_req *req;
+	u8 i;
+
+	req = cl_msg_zalloc(cl_hw, MM_SOUNDING_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	memcpy(req, sounding_req, sizeof(*req));
+
+	/* In case of non-TB HE SU/CQI, nc should be set to 0 */
+	if (req->sounding_type == SOUNDING_TYPE_HE_CQI ||
+	    req->sounding_type == SOUNDING_TYPE_HE_SU)
+		for (i = 0; i < req->sta_num; i++)
+			req->info_per_sta[i].nc = 0;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_pairing(struct cl_hw *cl_hw, u8 sounding_id, u8 sounding_type,
+			       u8 gid, u8 sta_idx)
+{
+	struct mm_sounding_pairing *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SOUNDING_PAIRING_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sounding_type = sounding_type;
+	req->sta_idx = sta_idx;
+	req->gid = gid;
+	req->sounding_id = sounding_id;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_interval(struct cl_hw *cl_hw, u16 interval, u16 lifetime,
+				u8 sounding_type, u8 sta_idx)
+{
+	struct mm_sounding_interval_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SOUNDING_INTERVAL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->interval = cpu_to_le16(interval);
+	req->bfr_lifetime = cpu_to_le16(lifetime);
+	req->sounding_type = sounding_type;
+	req->sta_idx = sta_idx;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_dfs(struct cl_hw *cl_hw, bool enable, u8 standard,
+		      u8 initial_gain, u8 agc_cd_th)
+{
+	struct mm_set_dfs_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_DFS_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->enable = enable;
+	req->standard_fcc = standard == NL80211_DFS_FCC;
+	req->initial_gain = initial_gain;
+	req->agc_cd_th = agc_cd_th;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ndp_tx_control(struct cl_hw *cl_hw, u8 chain_mask, u8 bw, u8 format, u8 num_ltf)
+{
+	struct mm_ndp_tx_control_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_NDP_TX_CONTROL_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->chain_mask = chain_mask;
+	req->bw = bw;
+	req->format = format;
+	req->num_ltf = num_ltf;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_reg_write(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask)
+{
+	struct mm_reg_write_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_REG_WRITE_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->address = cpu_to_le32(address);
+	req->value = cpu_to_le32(value);
+	req->mask = cpu_to_le32(mask);
+
+	cl_dbg_info(cl_hw, "address=0x%x, value=0x%x, mask=0x%x\n", address, value, mask);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_prot_mode(struct cl_hw *cl_hw, u8 log_nav_en, u8 mode, u8 rate_format,
+			u8 rate_mcs, u8 rate_pre_type)
+{
+	struct mm_prot_mode_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_PROT_MODE_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->log_nav_en = log_nav_en;
+	req->mode = mode;
+	req->rate_format = rate_format;
+	req->rate_mcs = rate_mcs;
+	req->rate_pre_type = rate_pre_type;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_backup_bcn_en(struct cl_hw *cl_hw, bool backup_bcn_en)
+{
+	struct mm_set_backup_bcn_en_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_BACKUP_BCN_EN_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->backup_bcn_en = backup_bcn_en;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_start_periodic_tx_time(struct cl_hw *cl_hw, u16 periodic_tx_time_off,
+				     u16 periodic_tx_time_on)
+{
+	struct mm_start_periodic_tx_time_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_START_PERIODIC_TX_TIME_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->periodic_tx_time_off = cpu_to_le16(periodic_tx_time_off);
+	req->periodic_tx_time_on = cpu_to_le16(periodic_tx_time_on);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_anamon_read(struct cl_hw *cl_hw, u8 mode, u8 param1, u8 param2)
+{
+	struct mm_anamon_read_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_ANAMON_READ_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->mode = mode;
+	req->param1 = param1;
+	req->param2 = param2;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_refresh_power(struct cl_hw *cl_hw)
+{
+	void *void_param;
+
+	/* MM_REFRESH_PWR_REQ has no parameter */
+	void_param = cl_msg_zalloc(cl_hw, MM_REFRESH_PWR_REQ, TASK_MM, 0);
+	if (!void_param)
+		return -ENOMEM;
+
+	return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_set_ant_pwr_offset(struct cl_hw *cl_hw, s8 pwr_offset[MAX_ANTENNAS])
+{
+	struct mm_set_ant_pwr_offset_req *req;
+	u8 chain, i = 0;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_ANT_PWR_OFFSET_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		if (!(cl_hw->mask_num_antennas & BIT(i)))
+			continue;
+
+		chain = cl_hw_ant_to_riu_chain(cl_hw, i);
+		pwr_offset[i] = cl_power_offset_check_margin(cl_hw, cl_hw->bw, i, pwr_offset[i]);
+		req->pwr_offset[chain] = cl_convert_signed_to_reg_value(pwr_offset[i]);
+	}
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_rate_fallback(struct cl_hw *cl_hw)
+{
+	struct mm_rate_fallback_req *req;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	req = cl_msg_zalloc(cl_hw, MM_SET_RATE_FALLBACK_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->fallback_count_su = conf->ci_rate_fallback[CL_RATE_FALLBACK_COUNT_SU];
+	req->fallback_count_mu = conf->ci_rate_fallback[CL_RATE_FALLBACK_COUNT_MU];
+	req->retry_count_thr = conf->ci_rate_fallback[CL_RATE_FALLBACK_RETRY_COUNT_THR];
+	req->ba_per_thr = conf->ci_rate_fallback[CL_RATE_FALLBACK_BA_PER_THR];
+	req->ba_not_received_thr = conf->ci_rate_fallback[CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR];
+	req->disable_mcs0 = conf->ci_rate_fallback[CL_RATE_FALLBACK_DISABLE_MCS];
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_spi_write(struct cl_hw *cl_hw, u8 page, u8 addr, u8 val, u8 mask)
+{
+	struct mm_spi_write_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SPI_WRITE_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->page = page;
+	req->addr = addr;
+	req->val = val;
+	req->mask = mask;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr)
+{
+	struct mm_spi_read_req *req;
+
+	req = cl_msg_zalloc(cl_hw, MM_SPI_READ_REQ, TASK_MM, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->page = page;
+	req->addr = addr;
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_ce_mod_filter(struct cl_hw *cl_hw, u32 filter)
+{
+	struct dbg_set_mod_filter_req *req;
+
+	req = cl_msg_zalloc(cl_hw, DBG_CE_SET_MOD_FILTER_REQ, TASK_DBG, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->mod_filter = cpu_to_le32(filter);
+
+	return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_sev_filter(struct cl_hw *cl_hw, u32 filter)
+{
+	struct dbg_set_sev_filter_req *req;
+
+	req = cl_msg_zalloc(cl_hw, DBG_SET_SEV_FILTER_REQ, TASK_DBG, sizeof(*req));
+	if (!req)
+		return -ENOMEM;
+
+	req->sev_filter = cpu_to_le32(filter);
+
+	return cl_send_request(cl_hw, req);
+}
+
+/* Work struct wrapper for print statistics */
+struct cl_print_stats_work {
+	struct work_struct ws;
+	struct cl_hw *cl_hw;
+	u32 dbg_info_type;
+};
+
+static void cl_print_rx_stats_precent(struct cl_hw *cl_hw, const char *str, u32 x, u32 y)
+{
+	/*
+	 * Example:
+	 * x = 541, y = 19
+	 * Result 28.4736
+	 */
+	u32 integer = x / y;
+	u32 fraction = 10000 * (x - y * (x / y)) / y;
+
+	fw_pr(cl_hw, "%s = %u.%04u\n", str, integer, fraction);
+}
+
+static void cl_print_rx_stats(struct cl_hw *cl_hw, struct cl_rxl_statistics *rx_stats)
+{
+	int i, mu_idx, total_rx = 0;
+	enum format_mode fm;
+
+	fw_pr(cl_hw, "=========================================\n");
+	fw_pr(cl_hw, "        Global RX stats\n");
+	fw_pr(cl_hw, "=========================================\n");
+	fw_pr(cl_hw, "host rxelem not ready      = %u\n",
+	      rx_stats->host_rxelem_not_ready_cnt);
+	fw_pr(cl_hw, "MSDU host rxelem not ready = %u\n",
+	      rx_stats->msdu_host_rxelem_not_ready_cnt);
+	fw_pr(cl_hw, "MSDU dma pool not ready    = %u\n",
+	      rx_stats->dma_rx_pool_not_ready_cnt);
+	fw_pr(cl_hw, "Percent of Rx CCA busy      = %u\n",
+	      rx_stats->cca_busy_percent);
+	fw_pr(cl_hw, "Percent of Rx mine CCA busy = %u\n",
+	      rx_stats->rx_mine_busy_percent);
+	fw_pr(cl_hw, "Percent of Tx mine busy     = %u\n",
+	      rx_stats->tx_mine_busy_percent);
+	fw_pr(cl_hw, "\n");
+
+	fw_pr(cl_hw, "=== Rx Format ==\n");
+	for (fm = 0; fm < FORMATMOD_MAX; fm++)
+		if (rx_stats->stats_rx_format[fm])
+			fw_pr(cl_hw, "Rx Format[%d] = %u\n", fm, rx_stats->stats_rx_format[fm]);
+
+	fw_pr(cl_hw, "=== Rx Decryption errors ==\n");
+	for (i = RHD_DECR_ICVFAIL_IDX; i < RHD_DECR_IDX_MAX; i++)
+		if (rx_stats->decrypt_err[i])
+			fw_pr(cl_hw, "decrypt_err[%d] = %u\n", i, rx_stats->decrypt_err[i]);
+
+	/* RX prints */
+	for (mu_idx = 0; mu_idx < MU_UL_MAX; mu_idx++) {
+		fw_pr(cl_hw, "============================================\n");
+		fw_pr(cl_hw, "=====         RX MAC HW MU [%2d]       =====\n", mu_idx);
+		fw_pr(cl_hw, "============================================\n");
+		total_rx = rx_stats->total_rx_packets[mu_idx] +
+			rx_stats->fcs_error_counter[mu_idx] +
+			rx_stats->phy_error_counter[mu_idx] +
+			rx_stats->ampdu_incorrect_received_counter[mu_idx] +
+			rx_stats->delimiter_error_counter[mu_idx] +
+			rx_stats->rx_fifo_overflow_err_cnt[mu_idx];
+
+		if (total_rx == 0)
+			continue;
+
+		for (i = 0; i < MAX_HANDLED_FRM_TYPE; i++) {
+			if (!rx_stats->emb_ll1_handled_frame_counter[mu_idx][i])
+				continue;
+
+			fw_pr(cl_hw, "emb_handled_packet[%d] - %u\n",
+			      i, rx_stats->emb_ll1_handled_frame_counter[mu_idx][i]);
+		}
+
+		fw_pr(cl_hw, "Total packets dropped (pckt_len > %u) %u\n",
+		      rx_stats->max_mpdu_data_len[mu_idx],
+		      rx_stats->rx_pckt_exceed_max_len_cnt[mu_idx]);
+		fw_pr(cl_hw, "Number of bad formated BA frames = %u\n",
+		      rx_stats->rx_pckt_bad_ba_statinfo_cnt[mu_idx]);
+		fw_pr(cl_hw, "Max occupancy list2 = %u\n",
+		      rx_stats->rhd_ll2_max_cnt[mu_idx]);
+		fw_pr(cl_hw, "Max occupancy list1 = %u\n",
+		      rx_stats->rhd_ll1_max_cnt[mu_idx]);
+		fw_pr(cl_hw, "\n");
+		fw_pr(cl_hw, "Total Qos MPDU received    = %u\n",
+		      rx_stats->total_rx_packets[mu_idx]);
+		fw_pr(cl_hw, "Total Aggregation received = %u\n",
+		      rx_stats->total_agg_packets[mu_idx]);
+		fw_pr(cl_hw, "Number of Rx Fifo Overflow = %u\n",
+		      rx_stats->rx_fifo_overflow_err_cnt[mu_idx]);
+		fw_pr(cl_hw, "Number of FCS ERROR        = %u\n",
+		      rx_stats->fcs_error_counter[mu_idx]);
+		fw_pr(cl_hw, "Number of PHY ERROR        = %u\n",
+		      rx_stats->phy_error_counter[mu_idx]);
+		fw_pr(cl_hw, "Number of AMPDUS           = %u\n",
+		      rx_stats->ampdu_received_counter[mu_idx]);
+		fw_pr(cl_hw, "Number of Incorrect AMPDUS = %u\n",
+		      rx_stats->ampdu_incorrect_received_counter[mu_idx]);
+		fw_pr(cl_hw, "Number of Delimiter errors = %u\n",
+		      rx_stats->delimiter_error_counter[mu_idx]);
+
+		if (rx_stats->total_rx_packets[mu_idx]) {
+			u32 total_rx_packets = rx_stats->total_rx_packets[mu_idx] +
+				rx_stats->rx_fifo_overflow_err_cnt[mu_idx] +
+				rx_stats->fcs_error_counter[mu_idx] +
+				rx_stats->phy_error_counter[mu_idx] +
+				rx_stats->delimiter_error_counter[mu_idx];
+
+			cl_print_rx_stats_precent(cl_hw,
+						  "Rx Fifo Overflow percent  ",
+						  100 * rx_stats->rx_fifo_overflow_err_cnt[mu_idx],
+						  total_rx_packets);
+			cl_print_rx_stats_precent(cl_hw,
+						  "FCS Error percent         ",
+						  100 * rx_stats->fcs_error_counter[mu_idx],
+						  total_rx_packets);
+			cl_print_rx_stats_precent(cl_hw,
+						  "Phy Error percent         ",
+						  100 * rx_stats->phy_error_counter[mu_idx],
+						  total_rx_packets);
+			cl_print_rx_stats_precent(cl_hw,
+						  "Delimiter Error percent   ",
+						  100 * rx_stats->delimiter_error_counter[mu_idx],
+						  total_rx_packets);
+		}
+
+		fw_pr(cl_hw, "Current NAV value          = %u\n", rx_stats->nav_value[mu_idx]);
+		fw_pr(cl_hw, "\n");
+		fw_pr(cl_hw, "Rx LL split stats: 1st LL interrupts = %u\n",
+		      rx_stats->counter_timer_trigger_ll1[mu_idx]);
+		fw_pr(cl_hw, "Rx LL split stats: 2nd LL interrupts = %u\n",
+		      rx_stats->counter_timer_trigger_ll2[mu_idx]);
+		fw_pr(cl_hw, "Number of incorrect format mode received = %u\n",
+		      rx_stats->rx_incorrect_format_mode[mu_idx]);
+
+		for (i = 0; i < RX_CLASSIFICATION_MAX; i++) {
+			if (!rx_stats->rx_class_counter[mu_idx][i])
+				continue;
+
+			fw_pr(cl_hw, "Rx classification rules stats: Rx rule%d= %u\n",
+			      i, rx_stats->rx_class_counter[mu_idx][i]);
+		}
+
+		if (rx_stats->rx_class_int_counter[mu_idx])
+			fw_pr(cl_hw, "Rx classification interrupts rules = %u\n",
+			      rx_stats->rx_class_int_counter[mu_idx]);
+
+		fw_pr(cl_hw, "\n");
+		fw_pr(cl_hw, "Rx Implicit BF statistics:      = %u\n",
+		      rx_stats->rx_imp_bf_counter[mu_idx]);
+		fw_pr(cl_hw, "Rx Implicit BF interrupts stats = %u\n",
+		      rx_stats->rx_imp_bf_int_counter[mu_idx]);
+		fw_pr(cl_hw, "RXM STATISTICS\n");
+		fw_pr(cl_hw, "rxm_stats_overflow      = %u\n",
+		      rx_stats->rxm_stats_overflow[mu_idx]);
+		fw_pr(cl_hw, "rx_incorrect_format_mode= %u\n",
+		      rx_stats->rx_incorrect_format_mode[mu_idx]);
+		fw_pr(cl_hw, "correct_received_mpdu   = %u\n",
+		      rx_stats->correct_received_mpdu[mu_idx]);
+		fw_pr(cl_hw, "incorrect_received_mpdu = %u\n",
+		      rx_stats->incorrect_received_mpdu[mu_idx]);
+		fw_pr(cl_hw, "discarded_mpdu          = %u\n",
+		      rx_stats->discarded_mpdu[mu_idx]);
+		fw_pr(cl_hw, "incorrect_delimiter     = %u\n",
+		      rx_stats->incorrect_delimiter[mu_idx]);
+		fw_pr(cl_hw, "rts_bar_cnt             = %u\n",
+		      rx_stats->rts_bar_cnt[mu_idx]);
+		fw_pr(cl_hw, "rxm_mpdu_cnt            = %u\n",
+		      rx_stats->rxm_mpdu_cnt[mu_idx]);
+
+		if (rx_stats->rxm_mpdu_cnt[mu_idx]) {
+			fw_pr(cl_hw, "rxm_rule0_match        = %u\n",
+			      rx_stats->rxm_rule0_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule1_match        = %u\n",
+			      rx_stats->rxm_rule1_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule2_match        = %u\n",
+			      rx_stats->rxm_rule2_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule3_match        = %u\n",
+			      rx_stats->rxm_rule3_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule4_match        = %u\n",
+			      rx_stats->rxm_rule4_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule5_match        = %u\n",
+			      rx_stats->rxm_rule5_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_rule6_match        = %u\n",
+			      rx_stats->rxm_rule6_match[mu_idx]);
+			fw_pr(cl_hw, "rxm_default_rule_match = %u\n",
+			      rx_stats->rxm_default_rule_match[mu_idx]);
+
+			fw_pr(cl_hw, "RXM amsdu stat not supported. use iwcl stats instead\n");
+		}
+
+		/* RX AMSDU prints */
+		fw_pr(cl_hw, "\n");
+		fw_pr(cl_hw, "RX AMSDU STATS\n");
+		fw_pr(cl_hw, "AMSDU RX cnt  = %u\n",
+		      rx_stats->stats_tot_rx_amsdu_cnt[mu_idx]);
+
+		for (i = 0; i < ARRAY_SIZE(rx_stats->stats_rx_amsdu_cnt[mu_idx]); i++)
+			if (rx_stats->stats_rx_amsdu_cnt[mu_idx][i])
+				fw_pr(cl_hw, "A-MSDU of %d = %u\n",
+				      i + 1, rx_stats->stats_rx_amsdu_cnt[mu_idx][i]);
+
+		fw_pr(cl_hw, "A-MSDU RX errors:\n");
+		for (i = 0; i < AMSDU_DEAGGREGATION_ERR_MAX; i++)
+			if (rx_stats->stats_rx_amsdu_err[mu_idx][i])
+				fw_pr(cl_hw, " err_id[%d] = %u\n",
+				      i, rx_stats->stats_rx_amsdu_err[mu_idx][i]);
+	}
+
+	fw_pr(cl_hw, "Frequency offset:\n");
+	for (i = 0; i < FREQ_OFFSET_TABLE_IDX_MAX; i++)
+		if (rx_stats->frequency_offset[i])
+			fw_pr(cl_hw, "frequency_offset = %u\n", rx_stats->frequency_offset[i]);
+}
+
+static void cl_print_stats_handler(struct work_struct *ws)
+{
+	struct cl_print_stats_work *stats_work = container_of(ws, struct cl_print_stats_work, ws);
+	struct cl_hw *cl_hw = stats_work->cl_hw;
+	u32 dbg_info_type = stats_work->dbg_info_type;
+
+	if (dbg_info_type == DBG_INFO_RX_STATS) {
+		struct cl_rxl_statistics *rx_stats =
+			&(((struct dbg_info *)cl_hw->dbginfo.buf)->u.rx_stats);
+
+		cl_print_rx_stats(cl_hw, rx_stats);
+	} else {
+		cl_dbg_err(cl_hw, "Info type is not supported: %u\n", dbg_info_type);
+	}
+
+	cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+	kfree(stats_work);
+}
+
+static void cl_schedule_print_stats(struct cl_hw *cl_hw, u32 dbg_info_type)
+{
+	struct cl_print_stats_work *stats_work =
+		kzalloc(sizeof(*stats_work), GFP_ATOMIC);
+
+	if (stats_work) {
+		INIT_WORK(&stats_work->ws, cl_print_stats_handler);
+		stats_work->cl_hw = cl_hw;
+		stats_work->dbg_info_type = dbg_info_type;
+
+		/* Schedule work, the work will be executed in the background */
+		queue_work(cl_hw->drv_workqueue, &stats_work->ws);
+	} else {
+		cl_dbg_err(cl_hw, "stats_work allocation failed\n");
+	}
+}
+
+void cl_fw_dbg_handler(struct cl_hw *cl_hw)
+{
+	struct dbg_info *dbg_info = NULL;
+
+	/* Function called upon DBG_INFO_IND message reception. */
+	dma_sync_single_for_device(cl_hw->chip->dev, cl_hw->dbginfo.dma_addr,
+				   cl_hw->dbginfo.bufsz, DMA_FROM_DEVICE);
+	dbg_info = (struct dbg_info *)cl_hw->dbginfo.buf;
+
+	if (dbg_info->u.type == DBG_INFO_DUMP) {
+		cl_dbg_info(cl_hw, "type %u): dump received\n",
+			    cl_hw->dbginfo.buf->u.dump.general_data.error_type);
+	} else if (dbg_info->u.type < DBG_INFO_MAX) {
+		cl_schedule_print_stats(cl_hw, dbg_info->u.type);
+	} else {
+		cl_dbg_warn(cl_hw, "Debug info wrong type - %u\n", dbg_info->u.type);
+	}
+}
+
+int cl_fw_dbg_trigger_based_init(struct cl_hw *cl_hw)
+{
+	cl_hw->tb_stats = vzalloc(sizeof(*cl_hw->tb_stats));
+	if (!cl_hw->tb_stats)
+		return -ENOMEM;
+
+	cl_hw->tb_sta_stats = vzalloc(sizeof(*cl_hw->tb_sta_stats));
+	if (!cl_hw->tb_sta_stats)
+		return -ENOMEM;
+
+	cl_hw->tb_stats->ampdu_cnt = INVALID_AMPDU_CNT;
+
+	return 0;
+}
+
+void cl_fw_dbg_trigger_based_deinit(struct cl_hw *cl_hw)
+{
+	vfree(cl_hw->tb_stats);
+	vfree(cl_hw->tb_sta_stats);
+}
+
+void cl_fw_dbg_trigger_based_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+				    struct ieee80211_hdr *hdr)
+{
+	struct cl_rx_trigger_based_stats *tb_stats = cl_hw->tb_stats;
+	u8 mu = 0;
+
+	if (!tb_stats->enable)
+		return;
+
+	if (tb_stats->ampdu_cnt == INVALID_AMPDU_CNT) {
+		tb_stats->ampdu_cnt = rxhdr->ampdu_cnt;
+		if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+			if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+				tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+			else
+				tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+			tb_stats->total += rxhdr->frm_successful_rx;
+		}
+	} else if (tb_stats->ampdu_cnt == rxhdr->ampdu_cnt) {
+		if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+			if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+				tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+			else
+				tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+			tb_stats->total += rxhdr->frm_successful_rx;
+		}
+	} else {
+		tb_stats->ampdu_cnt = rxhdr->ampdu_cnt;
+		if (unlikely(tb_stats->data_per_agg >= DBG_STATS_MAX_AGG_SIZE))
+			cl_dbg_err(cl_hw, "rx trigger_based agg size %u > 256\n",
+				   tb_stats->data_per_agg);
+		else
+			tb_stats->data[tb_stats->data_per_agg]++;
+
+		if (unlikely(tb_stats->qos_null_per_agg > TID_MAX))
+			tb_stats->qos_null[TID_MAX + 1]++;
+		else
+			tb_stats->qos_null[tb_stats->qos_null_per_agg]++;
+
+		if (tb_stats->modify) {
+			tb_stats->modify = false;
+
+			for (mu = 0; mu < MU_UL_MAX; mu++) {
+				tb_stats->data_per_mu_agg_size[mu][tb_stats->data_per_mu_agg[mu]]++;
+				tb_stats->data_per_mu_agg[mu] = 0;
+			}
+		}
+
+		tb_stats->data_per_agg = 0;
+		tb_stats->qos_null_per_agg = 0;
+
+		if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+			if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+				tb_stats->qos_null_per_agg += rxhdr->frm_successful_rx;
+			else
+				tb_stats->data_per_agg += rxhdr->frm_successful_rx;
+
+			tb_stats->total += rxhdr->frm_successful_rx;
+		}
+	}
+
+	if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+		mu = rxhdr->key_sram_index - KEY_SRAM_BASE_VAL;
+
+		if (unlikely(mu >= MU_UL_MAX)) {
+			cl_dbg_err(cl_hw, "rxhdr->key_sram_index = %u; valid range: %u...%u\n",
+				   rxhdr->key_sram_index, KEY_SRAM_BASE_VAL,
+				   KEY_SRAM_BASE_VAL + MU_UL_MAX - 1);
+			return;
+		}
+
+		if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+			tb_stats->qos_null_per_mu[mu]++;
+		} else if (ieee80211_is_data(hdr->frame_control)) {
+			tb_stats->modify = true;
+			tb_stats->data_per_mu[mu]++;
+			tb_stats->data_per_mu_agg[mu]++;
+		}
+
+		tb_stats->total_per_mu[mu]++;
+	}
+}
+
+void cl_fw_dbg_trigger_based_sta_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+					struct ieee80211_hdr *hdr)
+{
+	struct cl_rx_trigger_based_sta_stats *tb_sta_stat = cl_hw->tb_sta_stats;
+	u8 id = 0;
+
+	if (tb_sta_stat->ampdu_cnt != rxhdr->ampdu_cnt) {
+		tb_sta_stat->ampdu_cnt = rxhdr->ampdu_cnt;
+		if (tb_sta_stat->modify) {
+			tb_sta_stat->modify = false;
+
+			for (id = 0; id < CL_MAX_NUM_STA; id++) {
+				tb_sta_stat->data_per_sta_agg[id][tb_sta_stat->data_per_sta[id]]++;
+				tb_sta_stat->data_per_sta[id] = 0;
+			}
+		}
+	}
+
+	if (rxhdr->format_mod == FORMATMOD_HE_TRIG) {
+		id = rxhdr->key_sram_index - KEY_SRAM_BASE_VAL;
+		tb_sta_stat->modify = true;
+		tb_sta_stat->data_per_sta[id]++;
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 32/96] cl8k: add fw.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (30 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 31/96] cl8k: add fw.c viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-25 18:58   ` Jeff Johnson
  2022-05-24 11:33 ` [RFC v2 33/96] cl8k: add hw.c viktor.barna
                   ` (63 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/fw.h | 1462 +++++++++++++++++++++++++
 1 file changed, 1462 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw.h

diff --git a/drivers/net/wireless/celeno/cl8k/fw.h b/drivers/net/wireless/celeno/cl8k/fw.h
new file mode 100644
index 000000000000..12f573c0188c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw.h
@@ -0,0 +1,1462 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_FW_H
+#define CL_FW_H
+
+#include <linux/module.h>
+
+#include "calib.h"
+#include "wrs.h"
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#define KEY_SRAM_BASE_VAL 64
+#define INVALID_AMPDU_CNT U8_MAX
+
+enum {
+	DBG_INFO_DUMP = 1,
+	DBG_INFO_TX_STATS,
+	DBG_INFO_BCN_STATS,
+	DBG_INFO_RX_STATS,
+	DBG_INFO_DYN_CAL_STATS,
+	DBG_INFO_RATE_FALLBACK_STATS,
+	DBG_INFO_BF,
+	DBG_INFO_TRIGGER_FLOW,
+	DBG_INFO_QUEUE_IDX_DIFF,
+	DBG_INFO_MAX,
+	DBG_INFO_UNSET = DBG_INFO_MAX
+};
+
+struct cl_rx_trigger_based_stats {
+	bool enable;
+	bool modify;
+	u8 ampdu_cnt;
+	u16 data_per_agg;
+	u16 qos_null_per_agg;
+	u32 total;
+	u32 data[DBG_STATS_MAX_AGG_SIZE];
+	u32 qos_null[TID_MAX + 2];
+	u32 total_per_mu[MU_UL_MAX];
+	u32 qos_null_per_mu[MU_UL_MAX];
+	u32 data_per_mu[MU_UL_MAX];
+	u16 data_per_mu_agg[MU_UL_MAX];
+	u32 data_per_mu_agg_size[MU_UL_MAX][DBG_STATS_MAX_AGG_SIZE];
+};
+
+struct cl_rx_trigger_based_sta_stats {
+	bool modify;
+	u8 ampdu_cnt;
+	u16 data_per_sta[CL_MAX_NUM_STA];
+	u32 data_per_sta_agg[CL_MAX_NUM_STA][DBG_STATS_MAX_AGG_SIZE];
+};
+
+void cl_fw_dbg_handler(struct cl_hw *cl_hw);
+int cl_fw_dbg_trigger_based_init(struct cl_hw *cl_hw);
+void cl_fw_dbg_trigger_based_deinit(struct cl_hw *cl_hw);
+void cl_fw_dbg_trigger_based_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+				    struct ieee80211_hdr *hdr);
+void cl_fw_dbg_trigger_based_sta_update(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+					struct ieee80211_hdr *hdr);
+
+struct cl_dma_accessed {
+	void *drv_v_addr;
+	u32 size;
+	u32 fw_v_addr;
+	u32 dma_addr;
+};
+
+struct cl_cached_fw {
+	void *data;
+	size_t size;
+};
+
+int cl_fw_file_load(struct cl_hw *cl_hw);
+void cl_fw_file_cleanup(struct cl_hw *cl_hw);
+void cl_fw_file_release(struct cl_hw *cl_hw);
+
+#define MSG_SHIFT              8
+#define NEW_MSG_SHIFT          1
+#define INTERNAL_MSG_COUNT     5
+#define FIRST_MSG(task)        ((task) << MSG_SHIFT)
+#define SHIFTED_MSG(id, shift) ((id) + NEW_MSG_SHIFT + (shift))
+
+/* Message structure. */
+struct cl_fw_msg {
+	__le16 msg_id;  /* Message ID. */
+	u8 dst_kern_id; /* Destination kernel ID. */
+	u8 dst_task_id; /* Destination task ID. */
+	u8 src_kern_id; /* Source kernel ID. */
+	u8 src_task_id; /* Source task ID. */
+	__le16 param_len;  /* Parameter embedded struct length. */
+	__le32 param[1];   /* Parameter embedded struct - must be word-aligned. */
+};
+
+enum {
+	TASK_MM,
+	TASK_DBG,
+	TASK_MAX,
+};
+
+/* List of messages related to the task. */
+enum mm_msg_tag {
+	/* Reset message */
+	MM_RESET_REQ = FIRST_MSG(TASK_MM),
+	MM_RESET_CFM,
+	/* Start message */
+	MM_START_REQ,
+	MM_START_CFM,
+	/* Version message */
+	MM_VERSION_REQ,
+	MM_VERSION_CFM,
+	/* Add interface message */
+	MM_ADD_IF_REQ,
+	MM_ADD_IF_CFM,
+	/* Remove interface message */
+	MM_REMOVE_IF_REQ,
+	MM_REMOVE_IF_CFM,
+	/* Station add message */
+	MM_STA_ADD_REQ,
+	MM_STA_ADD_CFM,
+	/* Station del message */
+	MM_STA_DEL_REQ,
+	MM_STA_DEL_CFM,
+	/* Set filter message */
+	MM_SET_FILTER_REQ,
+	MM_SET_FILTER_CFM,
+	/* Set channel message */
+	MM_SET_CHANNEL_REQ = SHIFTED_MSG(MM_SET_FILTER_CFM, 2),
+	MM_SET_CHANNEL_CFM,
+	/* External calibration message */
+	MM_EXT_CALIB_REQ,
+	MM_EXT_CALIB_CFM,
+	/* Set DTIM message */
+	MM_SET_DTIM_REQ,
+	MM_SET_DTIM_CFM,
+	/* Set beacon interval message */
+	MM_SET_BEACON_INT_REQ,
+	MM_SET_BEACON_INT_CFM,
+	/* Set basic rates message */
+	MM_SET_BASIC_RATES_REQ,
+	MM_SET_BASIC_RATES_CFM,
+	/* Set BSSID message */
+	MM_SET_BSSID_REQ,
+	MM_SET_BSSID_CFM,
+	/* Set EDCA message */
+	MM_SET_EDCA_REQ,
+	MM_SET_EDCA_CFM,
+	/* Set association message */
+	MM_SET_ASSOCIATED_REQ,
+	MM_SET_ASSOCIATED_CFM,
+	/* Set slot time message */
+	MM_SET_SLOTTIME_REQ,
+	MM_SET_SLOTTIME_CFM,
+	/* Set idle message */
+	MM_SET_IDLE_REQ,
+	MM_SET_IDLE_CFM,
+	/* Key add message */
+	MM_KEY_ADD_REQ = SHIFTED_MSG(MM_SET_IDLE_CFM, 2),
+	MM_KEY_ADD_CFM,
+	/* Key delete message */
+	MM_KEY_DEL_REQ,
+	MM_KEY_DEL_CFM,
+	/* Block ack add TX message */
+	MM_BA_ADD_TX_REQ,
+	MM_BA_ADD_TX_CFM,
+	/* Block ack add RX message */
+	MM_BA_ADD_RX_REQ,
+	MM_BA_ADD_RX_CFM,
+	/* Block ack delete message */
+	MM_BA_DEL_REQ,
+	MM_BA_DEL_CFM,
+	/* PHY reset message */
+	MM_PHY_RESET_REQ,
+	MM_PHY_RESET_CFM,
+	/* Available BA TX queue message */
+	MM_AVAILABLE_BA_TXQ_REQ,
+	MM_AVAILABLE_BA_TXQ_CFM,
+	/* Update rate DL message */
+	MM_UPDATE_RATE_DL_REQ,
+	MM_UPDATE_RATE_DL_CFM,
+	/* Update rate UL message */
+	MM_UPDATE_RATE_UL_REQ,
+	MM_UPDATE_RATE_UL_CFM,
+	/* Set VNS message */
+	MM_SET_VNS_REQ,
+	MM_SET_VNS_CFM,
+	/* Set TX BF message */
+	MM_SET_TX_BF_REQ,
+	MM_SET_TX_BF_CFM,
+	/* Sounding message */
+	MM_SOUNDING_REQ,
+	MM_SOUNDING_CFM,
+	/* Sounding pairing message */
+	MM_SOUNDING_PAIRING_REQ,
+	MM_SOUNDING_PAIRING_CFM,
+	/* Sounding interval message */
+	MM_SOUNDING_INTERVAL_REQ,
+	MM_SOUNDING_INTERVAL_CFM,
+	/* Set DFS message */
+	MM_SET_DFS_REQ = SHIFTED_MSG(MM_SOUNDING_INTERVAL_CFM, 4),
+	MM_SET_DFS_CFM,
+	/* Set NDP TX control message */
+	MM_NDP_TX_CONTROL_REQ = SHIFTED_MSG(MM_SET_DFS_CFM, 2),
+	MM_NDP_TX_CONTROL_CFM,
+	/* Register write message */
+	MM_REG_WRITE_REQ,
+	MM_REG_WRITE_CFM,
+	/* Protection mode message */
+	MM_PROT_MODE_REQ,
+	MM_PROT_MODE_CFM,
+	/* Backup beacon enable message */
+	MM_BACKUP_BCN_EN_REQ = SHIFTED_MSG(MM_PROT_MODE_CFM, 4),
+	MM_BACKUP_BCN_EN_CFM,
+	/* Start periodic TX time message */
+	MM_START_PERIODIC_TX_TIME_REQ,
+	MM_START_PERIODIC_TX_TIME_CFM,
+	/* Anamon read message */
+	MM_ANAMON_READ_REQ,
+	MM_ANAMON_READ_CFM,
+	/* Refresh power message */
+	MM_REFRESH_PWR_REQ = SHIFTED_MSG(MM_ANAMON_READ_CFM, 10),
+	MM_REFRESH_PWR_CFM,
+	/* Set antenna power offset message */
+	MM_SET_ANT_PWR_OFFSET_REQ,
+	MM_SET_ANT_PWR_OFFSET_CFM,
+	/* Set rate fallback message */
+	MM_SET_RATE_FALLBACK_REQ,
+	MM_SET_RATE_FALLBACK_CFM,
+	/* SPI write message */
+	MM_SPI_WRITE_REQ = SHIFTED_MSG(MM_SET_RATE_FALLBACK_CFM, 6),
+	MM_SPI_WRITE_CFM,
+	/* SPI read message */
+	MM_SPI_READ_REQ,
+	MM_SPI_READ_CFM,
+	MM_REQ_CFM_MAX = SHIFTED_MSG(MM_SPI_READ_CFM, 2),
+
+	/* ############### Firmware indication messages   ############### */
+	/* Start of indication messages */
+	MM_FIRST_IND = SHIFTED_MSG(MM_REQ_CFM_MAX, INTERNAL_MSG_COUNT),
+	/* TX aggregation indication from FW */
+	MM_AGG_TX_REPORT_IND = MM_FIRST_IND,
+	/* RX aggregation indication from FW */
+	MM_AGG_RX_REPORT_IND,
+	/* Indication for BF sounding */
+	MM_SOUNDING_IND,
+	/* Indication of fw error */
+	MM_FW_ERROR_IND = SHIFTED_MSG(MM_SOUNDING_IND, 2),
+	/* Async indication that MAC is in idle */
+	MM_IDLE_ASYNC_IND,
+
+	/* MAX number of messages */
+	MM_MAX,
+};
+
+/* Interface types */
+enum {
+	MM_STA,
+	MM_IBSS,
+	MM_AP,
+	MM_MONITOR,
+	MM_MESH_POINT,
+};
+
+/* BA agreement types */
+enum {
+	/* BlockAck agreement for TX */
+	BA_AGMT_TX,
+	/* BlockAck agreement for RX */
+	BA_AGMT_RX,
+};
+
+/* BA agreement related status */
+enum {
+	BA_AGMT_ESTABLISHED,
+	BA_AGMT_ALREADY_EXISTS,
+	BA_AGMT_DELETED,
+	BA_AGMT_DOES_NOT_EXIST,
+	BA_AGMT_NOT_ESTABLISHED,
+};
+
+/* MM_BA_TXQUEUE request / confirm related status */
+enum {
+	BA_TXQUEUE_INVALID,
+	BA_TXQUEUE_VALID,
+};
+
+/* MAC address structure. */
+struct mac_addr {
+	/* Array of bytes that make up the MAC address. */
+	u8 array[ETH_ALEN];
+};
+
+/* DCOC/IQ Calibration related defines */
+#define CALIB_SUCCESS 0x00
+#define CALIB_FAIL    0x01
+
+#define REG_OVERWRITE_DATA_MAX 3
+#define REG_OVERWRITE_REGS_MAX 20
+
+struct cl_rf_reg_overwrite_info {
+	u8 cmd;
+	__le32 data[REG_OVERWRITE_DATA_MAX];
+};
+
+struct cl_antenna_config {
+	/* Number of antennas */
+	u8 num_tx_he;
+	u8 num_tx_ofdm_ht_vht;
+	u8 num_rx;
+	/* Mask of antennas */
+	u8 mask_tx_he;
+	u8 mask_tx_ofdm_ht_vht;
+	u8 mask_rx;
+	/* CCK mask */
+	u8 mask_tx_cck;
+	u8 mask_rx_cck;
+	/* CDB_mask 0x0 -> SX0 chain. 0x1-> SX1 chain. */
+	u8 cdb_mask;
+};
+
+#define FEM_LUTS_PER_REGISTER  2
+#define FEM_LUT_AMOUNT_PER_MAC 6
+#define FEM_REGISTERS_AMOUNT   (FEM_LUT_AMOUNT_PER_MAC / FEM_LUTS_PER_REGISTER)
+
+struct cl_fem_config {
+	__le32 reg[FEM_REGISTERS_AMOUNT];
+};
+
+struct cl_cca_config {
+	u8 ed_rise_thr_dbm;
+	u8 ed_fall_thr_dbm;
+	u8 cs_en;
+	u8 modem_en;
+	u8 main_ant;
+	u8 second_ant;
+	u8 flag0_ctrl;
+	u8 flag1_ctrl;
+	u8 flag2_ctrl;
+	u8 flag3_ctrl;
+	u8 gi_rise_thr_dbm;
+	u8 gi_fall_thr_dbm;
+	u8 gi_pow_lim_dbm;
+	__le16 ed_en;
+	u8 gi_en;
+};
+
+/* Structure containing the parameters of the PHY configuration */
+struct cl_phy_cfg {
+	struct cl_cca_config cca_config;
+	struct cl_antenna_config ant_config;
+	struct cl_fem_config fem_conf;
+	u8 first_start;
+	u8 channel_bandwidth;
+	u8 band; /* 0 = 2.4g / 1 = 5g / 2 = 6g */
+	u8 other_band;
+	__le16 freq_offset;
+	u8 rx_sensitivity[MAX_ANTENNAS];
+	u8 vns_tx_power_mode;
+	u8 vns_rssi_suto_resp_th;
+	u8 afe_config_en;
+	u8 no_capture_noise_sleep;
+	u8 ht_rxldpc_en;
+	u8 gain_update_enable;
+	u8 mcs_sig_b;
+	u8 ofdm_only;
+	u8 hr_factor;
+	u8 td_csd_en;
+	u8 pe_duration_bcast;
+	__le32 tx_digital_gain;
+	__le32 tx_digital_gain_cck;
+	u8 ofdm_cck_power_offset;
+	u8 phy_clk_gating_en;
+	u8 tcv1_chains_sx0;
+	u8 dsp_lcu_mode;
+	u8 is_first_rfic;
+	u8 precalibration_enable;
+	/* For RF debug - this field should be deleted after RF bring up */
+	struct cl_rf_reg_overwrite_info rf_reg_overwrite_info[REG_OVERWRITE_REGS_MAX];
+};
+
+enum {
+	CENX_CFG_DEBUG_PRINT,
+	CENX_CFG_INT_FRAME,
+	CENX_CFG_CE_TX_CFM,
+};
+
+#define IPC_TXQ_CNT  5
+
+/* MM_START_REQ parameters */
+struct cl_start_param {
+	__le32 comp_flags;
+	__le16 cfm_size;
+	__le32 cfm_dma_base_addr;
+	__le16 phy_dev;
+	__le16 fw_scale_down;
+	__le16 dbg_test_mode_max;
+	struct {
+		__le32 idle;
+		__le32 ac0;
+		__le32 ac1;
+		__le32 ac2;
+		__le32 ac3;
+		__le32 bcn;
+	} hal_timeout;
+	/*
+	 * this is the pointer to the dma base address of the host struct
+	 * that hold all the dma addresses of the ipc host queues
+	 */
+	__le32 ipc_host_tx_queues_dma_addr;
+	/* Address of RX buffer in host RAM */
+	__le32 host_rxbuf_base_addr[CL_RX_BUF_MAX];
+	/* Address of HOST indices */
+	__le32 ipc_ring_indices_base;
+	u8 prot_log_nav_en;
+	u8 prot_mode;
+	u8 prot_rate_format;
+	u8 prot_rate_mcs;
+	u8 prot_rate_pre_type;
+	u8 bw_signaling_mode;
+	u8 mult_ampdu_in_txop_en;
+	u8 preemptive_backoff_en;
+	__le32 cca_timeout;
+	u8 short_retry_limit;
+	u8 long_retry_limit;
+	u8 assoc_auth_retry_limit;
+	__le16 bcn_tx_path_min_time;
+	u8 backup_bcn_en;
+	u8 tx_txop_cut_en;
+	u8 ps_ctrl_enabled;
+	u8 ac_with_bcns_flushed_cnt_thr;
+	__le32 txl_statistics_struct_size;
+	__le32 rxl_statistics_struct_size;
+	struct dbg_meta_data dbg_metadata;
+	u8 phy_err_prevents_phy_dump;
+	u8 tx_rx_delay;
+	u8 assert_storm_detect_thd;
+	u8 assert_time_diff_sec;
+	__le16 ipc_rxbuf_size[CL_RX_BUF_MAX];
+	u8 host_pci_gen_ver;
+	u8 dma_lli_max_chan[2];
+	u8 production_mode;
+	u8 bw_factor_q2[CHNL_BW_MAX];
+	u8 ant_factor_q2[MAX_ANTENNAS];
+	u8 min_ant_pwr_q1;
+	struct {
+		u8 auto_resp_all  : 2;
+		u8 auto_resp_msta : 2;
+		u8 rsv            : 4;
+	} default_distance;
+	__le32 phy_data_dma_addr;
+	__le32 phy_remote_rom_dma_addr;
+	__le32 iq_dcoc_calib_tables_dma_addr;
+	__le32 power_table_dma_addr;
+	__le32 tf_info_dma_addr;
+	u8 su_force_min_spacing_usec;
+	u8 mu_force_min_spacing_usec;
+	u8 single_tcv;
+	u8 rx_padding;
+	u8 bar_cap_disable;
+	u8 hw_bsr;
+	u8 drop_to_lower_bw;
+	u8 dra_enable;
+	u8 mac_clk_gating_en;
+	u8 imaging_blocker;
+	u8 fec_coding;
+	u8 cs_required;
+	u8 fw_disable_recovery;
+};
+
+struct cl_tx_params {
+	__le32 rate;
+	__le32 rate_he;
+	u8 req_bw_tx;
+	u8 ant_set;
+	u8 ltf;
+};
+
+struct mm_update_rate_dl_req {
+	u8 op_mode;
+	u8 sta_idx;
+	u8 mu_is_rate_valid;
+	u8 group_id;
+	struct cl_tx_params tx_params;
+	__le32 rate_fallback;
+	u8 ltf_fallback;
+};
+
+struct mm_update_rate_ul_req {
+	u8 op_mode;
+	u8 mu_is_rate_valid;
+	u8 group_id;
+	u8 sta_idx;
+	u8 bw;
+	u8 nss;
+	u8 mcs;
+	u8 gi_ltf;
+};
+
+struct mm_set_ant_pwr_offset_req {
+	/* Power offset (0.25dB resoultion) */
+	u8 pwr_offset[MAX_ANTENNAS];
+};
+
+struct mm_rate_fallback_req {
+	u8 fallback_count_su;
+	u8 fallback_count_mu;
+	u8 ba_per_thr;
+	u8 ba_not_received_thr;
+	u8 retry_count_thr;
+	u8 disable_mcs0;
+};
+
+struct mm_set_vns_req {
+	u8 sta_idx;
+	u8 is_vns;
+};
+
+struct mm_set_tx_bf_req {
+	u8 sta_idx;
+	u8 is_on;
+	u8 is_on_fallback;
+};
+
+/* Structure containing the parameters of the MM_START_REQ message */
+struct mm_start_req {
+	/* PHY configuration */
+	struct cl_phy_cfg phy_cfg;
+	/* Other start parameters */
+	struct cl_start_param param;
+};
+
+struct mm_mac_api_lut_line {
+	__le16 frequency_q2;
+	union {
+		struct {
+			struct {
+				u8 vcocalsel;
+				u8 nint;
+				__le32 nfrac;
+				__le32 freqmeastarg;
+			} xco_40M;
+			struct {
+				u8 vcocalsel;
+				u8 nint;
+				__le32 nfrac;
+				__le32 freqmeastarg;
+			} xco_60M;
+		} olympus_2_lines;
+		struct {
+			struct {
+				u8 vcocalsel;
+				u8 nint;
+				__le32 nfrac;
+				__le32 freqmeastarg;
+			} xco_40M;
+			struct {
+				u8 vcocalsel;
+				u8 nint;
+				__le32 nfrac;
+				__le32 freqmeastarg;
+			} xco_60M_s0;
+			struct {
+				u8 vcocalsel;
+				u8 nint;
+				__le32 nfrac;
+				__le32 freqmeastarg;
+			} xco_60M_s1;
+		} olympus_3_lines;
+	} rfic_specific;
+};
+
+struct cl_calib_other_tcv {
+	/* Parameters for calibration */
+	__le16 prim20_freq;
+	struct mm_mac_api_lut_line center1_freq_lut;
+	/* Parameter to restore previous configuration of other TCV */
+	u8 mask_tx_he;
+	u8 num_tx_he;
+	u8 band;
+};
+
+struct cl_calib_conf {
+	u8 rx_gain_upper_limit;
+	u8 rx_gain_lower_limit;
+	__le16 nco_freq;
+	s8 nco_amp;
+	u8 sleeve_trshld;
+	u8 n_samples_exp_lolc;
+	u8 n_samples_exp_iqc;
+	__le32 p_thresh;
+	u8 n_bit_fir_scale;
+	u8 n_bit_amp_scale;
+	u8 n_bit_phase_scale;
+	__le16 tone_vector[IQ_NUM_TONES_REQ];
+	__le32 gp_rad_trshld;
+	__le32 ga_lin_upper_trshld;
+	__le32 ga_lin_lower_trshld;
+	u8 comp_filter_len;
+	u8 singletons_num;
+	u8 tones_num;
+	__le16 rampup_time;
+	__le16 lo_coarse_step;
+	__le16 lo_fine_step;
+	u8 precalibration_enable;
+};
+
+struct cl_calib_param {
+	u8 mode;
+	u8 dcoc_max_vga;
+	struct cl_calib_chain tx_calib_chain[MAX_ANTENNAS];
+	struct cl_calib_chain rx_calib_chain[MAX_ANTENNAS];
+	struct cl_calib_conf conf;
+	struct cl_calib_other_tcv other_tcv;
+};
+
+/* Structure containing the parameters of the MM_SET_CHANNEL_REQ message */
+struct mm_set_channel_req {
+	/* Band (2.4GHz, 5GHz, 6GHz) */
+	u8 band;
+	u8 other_band;
+	/* Channel type: 20,40,80 or 160 MHz */
+	u8 bandwidth;
+	/* Frequency for Primary 20MHz channel (in MHz) */
+	__le16 prim20_freq;
+	/* Frequency for Center of the contiguous channel or center of Primary 80+80 */
+	struct mm_mac_api_lut_line center1_freq_lut;
+	/* Antenna configuration */
+	struct cl_antenna_config ant_config;
+	/* FEM configuration */
+	struct cl_fem_config fem_conf;
+	/* For RF debug - this field should be deleted after RF bring up */
+	struct cl_rf_reg_overwrite_info rf_reg_overwrite_info[REG_OVERWRITE_REGS_MAX];
+	u8 calib_info_set;
+	/* Calibration configuration */
+	struct cl_calib_param calib_param;
+	/* Antenna power offset */
+	u8 ant_pwr_offset[MAX_ANTENNAS];
+	/*
+	 * Frequency offset in MHz between current synthesizer's center channel,
+	 * and the other synthesizer's channel.
+	 * Needed for LOLC and IQC Calibration. Otherwise, shouldn't be used.
+	 */
+	s8 sx_freq_offset_mhz;
+	/* Hr factor */
+	u8 hr_factor;
+	/* Signal extension enable (for 2.4G sifs10 mode), should be 1 for 2,4 band by default */
+	u8 signal_ext;
+};
+
+enum mm_ext_calib_command {
+	MM_EXT_CALIB_CMD_INIT_SX,
+	MM_EXT_CALIB_CMD_SET_CHANNEL,
+	MM_EXT_CALIB_CMD_INIT_AND_SET_CHANNEL,
+	MM_EXT_CALIB_CMD_MAX
+};
+
+struct mm_ext_calib_init_sx_req {
+	u8 band;
+	u8 cdb_mask;
+	u8 mask_tx_he;
+	u8 num_tx_he;
+	u8 sx_idx;
+};
+
+struct mm_ext_calib_set_channel_req {
+	u8 band;
+	u8 bandwidth;
+	__le16 prim20_freq;
+	struct mm_mac_api_lut_line center1_freq_lut;
+	u8 sx_idx;
+};
+
+struct mm_ext_calib_init_and_set_req {
+	u8 band;
+	u8 cdb_mask;
+	u8 bandwidth;
+	__le16 prim20_freq;
+	struct mm_mac_api_lut_line center1_freq_lut;
+	__le16 remote_prim20_freq;
+	struct mm_mac_api_lut_line remote_center1_freq_lut;
+};
+
+union mm_ext_calib_cmd_req {
+	struct mm_ext_calib_init_sx_req init_sx;
+	struct mm_ext_calib_set_channel_req set_channel;
+	struct mm_ext_calib_init_and_set_req init_and_set;
+};
+
+struct mm_ext_calib_req {
+	u8 cmd;
+	union mm_ext_calib_cmd_req u;
+};
+
+/* Structure containing the parameters of the MM_SET_DTIM_REQ message */
+struct mm_set_dtim_req {
+	u8 dtim_period;
+};
+
+/* Structure containing the parameters of the MM_SET_BEACON_INT_REQ message */
+struct mm_set_beacon_int_req {
+	__le16 beacon_int;
+	/* Index of the interface */
+	u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_SET_BASIC_RATES_REQ message */
+struct mm_set_basic_rates_req {
+	/* Basic rate set (as expected by bssBasicRateSet field of Rates MAC HW register) */
+	__le32 rates;
+};
+
+/* Structure containing the parameters of the MM_SET_BSSID_REQ message */
+struct mm_set_bssid_req {
+	/* BSSID to be configured in HW */
+	struct mac_addr bssid;
+	/* Index of the interface for which the parameter is configured */
+	u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_SET_FILTER_REQ message */
+struct mm_set_filter_req {
+	__le32 filter;
+};
+
+/* Structure containing the parameters of the MM_ADD_IF_REQ message. */
+struct mm_add_if_req {
+	u8 type;
+	struct mac_addr addr;
+	u8 inst_nbr;
+	u8 tx_strip_vlan;
+	u8 rx_push_vlan;
+	__le32 rx_push_vlan_tag;
+	__le32 rx_filter_monitor_mask;
+	__le32 mac_addr_hi_mask;
+	__le32 mac_addr_low_mask;
+	u8 start_dtim_count;
+	u8 mbssid_mode;
+};
+
+/* Structure containing the parameters of the MM_SET_EDCA_REQ message */
+struct mm_set_edca_req {
+	__le32 ac_param;
+	u8 hw_queue;
+	u8 mu_edca_aifsn;
+	u8 mu_edca_ecw_min_max;
+	u8 mu_edca_timer;
+};
+
+struct mm_config_cca_req {
+	u8 enable;
+};
+
+struct mm_set_dfs_req {
+	bool enable;
+	bool standard_fcc;
+	u8 initial_gain;
+	u8 agc_cd_th;
+};
+
+struct mm_ndp_tx_control_req {
+	u8 chain_mask;
+	u8 bw;
+	u8 format;
+	u8 num_ltf;
+};
+
+struct mm_reg_write_req {
+	__le32 address;
+	__le32 value;
+	__le32 mask;
+};
+
+struct mm_prot_mode_req {
+	u8 log_nav_en;
+	u8 mode;
+	u8 rate_format;
+	u8 rate_mcs;
+	u8 rate_pre_type;
+};
+
+enum mac_idle_cmd {
+	MAC_ACTIVE = 0,
+	MAC_IDLE_SYNC,
+	MAC_IDLE_ASYNC
+};
+
+struct mm_set_idle_req {
+	u8 hw_idle;
+};
+
+/* Structure containing the parameters of the MM_SET_SLOTTIME_REQ message */
+struct mm_set_slottime_req {
+	/* Slot time expressed in us */
+	u8 slottime;
+};
+
+/* Structure containing the parameters of the MM_SET_ASSOCIATED_REQ message */
+struct mm_set_associated_req {
+	/* Association Id received from the AP */
+	__le16 aid;
+	/* Mask address high - [47:32] */
+	__le32 bssid_hi_mask;
+	/* Mask address low - [31:0] */
+	__le32 bssid_low_mask;
+};
+
+/* Structure containing the parameters of the MM_ADD_IF_CFM message. */
+struct mm_add_if_cfm {
+	/* Status of operation (different from 0 if unsuccessful) */
+	u8 status;
+};
+
+/* Structure containing the parameters of the MM_REMOVE_IF_REQ message. */
+struct mm_remove_if_req {
+	/* Interface index assigned by the firmware */
+	u8 inst_nbr;
+};
+
+/* Structure containing the parameters of the MM_VERSION_CFM message. */
+struct mm_version_cfm {
+	struct {
+		__le32 dsp;
+		__le32 rfic_sw;
+		__le32 rfic_hw;
+		__le32 agcram;
+		char fw[CL_VERSION_STR_SIZE];
+	} versions;
+	u8 rf_crystal_mhz;
+};
+
+/* Structure containing the parameters of the MM_STA_ADD_REQ message. */
+struct mm_sta_add_req {
+	/* Exponent for calculating HE Maximum A-MPDU size */
+	u8 ampdu_size_exp_he;
+	/* Exponent for calculating VHT Maximum A-MPDU size */
+	u8 ampdu_size_exp_vht;
+	/* Exponent for calculating HT Maximum A-MPDU size */
+	u8 ampdu_size_exp_ht;
+	/* MAC address of the station to be added */
+	struct mac_addr mac_addr;
+	/* A-MPDU spacing, in us */
+	u8 ampdu_min_spacing;
+	/* Interface index */
+	u8 inst_nbr;
+	/* Support ldpc Tx */
+	u8 ldpc_enabled;
+	/* MU beamformee capable */
+	u8 mu_bfee;
+	/* SU beamformee capable */
+	u8 su_bfee;
+	/* Station AID */
+	__le16 aid;
+	/* My_aid - ??? */
+	__le16 my_aid;
+	/* Index of station in case of recovery */
+	u8 recovery_sta_idx;
+	u8 max_sp;
+	u8 uapsd_queues;
+	/* TX params */
+	struct cl_tx_params tx_params;
+	/*
+	 * PE duration (0 = 0us, 1 = 8us, 2 = 16us)
+	 * SS0 bits 0-1, SS1 bits 2-3, SS2 bits 4-5, SS3 bits 6-7.
+	 */
+	u8 pe_duration[CHNL_BW_MAX][WRS_MCS_MAX_HE];
+	u8 he_tf_mac_padding_duration;
+	u8 he_rx_ctrl_frm_to_mbss;
+	u8 he_rx_1024qam_under_ru242;
+};
+
+/* Structure containing the parameters of the MM_STA_ADD_CFM message. */
+struct mm_sta_add_cfm {
+	/* Status of the operation (different from 0 if unsuccessful) */
+	u8 status;
+	/* Index assigned by the firmware to the newly added station */
+	u8 sta_idx;
+};
+
+/* Structure containing the parameters of the MM_STA_DEL_REQ message. */
+struct mm_sta_del_req {
+	u8 sta_idx;
+};
+
+/* MAC Secret Key */
+#define MAC_SEC_KEY_LEN 32  /* TKIP keys 256 bits (max length) with MIC keys */
+
+struct mac_sec_key {
+	/* Key material length */
+	u8 length;
+	/* Key material */
+	u32 array[MAC_SEC_KEY_LEN / 4];
+};
+
+enum mac_cipher_suite {
+	MAC_CIPHER_SUITE_NULL,
+	MAC_CIPHER_SUITE_WEP40,
+	MAC_CIPHER_SUITE_TKIP,
+	MAC_CIPHER_SUITE_CCMP,
+	MAC_CIPHER_SUITE_WEP104,
+	MAC_CIPHER_SUITE_GCMP,
+
+	MAC_CIPHER_SUITE_MAX
+};
+
+/* Structure containing the parameters of the MM_KEY_ADD REQ message. */
+struct mm_key_add_req {
+	/* Key index (valid only for default keys) */
+	u8 key_idx;
+	/* STA index (valid only for pairwise keys) */
+	u8 sta_idx;
+	/* Key material */
+	struct mac_sec_key key;
+	/* Cipher suite */
+	u8 cipher_suite;
+	/* Index of the interface for which the key is set (valid only for default keys) */
+	u8 inst_nbr;
+	/* A-MSDU SPP parameter */
+	u8 spp;
+};
+
+/* Structure containing the parameters of the MM_KEY_ADD_CFM message. */
+struct mm_key_add_cfm {
+	/* Status of the operation (different from 0 if unsuccessful) */
+	u8 status;
+	/* HW index of the key just added */
+	u8 hw_key_idx;
+};
+
+/* Structure containing the parameters of the MM_KEY_DEL_REQ message. */
+struct mm_key_del_req {
+	u8 hw_key_idx;
+};
+
+/* Structure containing the parameters of the MM_BA_ADD_REQ message. */
+struct mm_ba_add_req {
+	/* Type of agreement (0: TX, 1: RX) */
+	u8 type;
+	/* Index of peer station with which the agreement is made */
+	u8 sta_idx;
+	/* TID for which the agreement is made with peer station */
+	u8 tid;
+	/* Buffer size - number of MPDUs that can be held in its buffer per TID */
+	__le16 bufsz;
+	/* Start sequence number negotiated during BA setup */
+	__le16 ssn;
+};
+
+/* Structure containing the parameters of the MM_BA_ADD_CFM message. */
+struct mm_ba_add_cfm {
+	/* Index of peer station for which the agreement is being confirmed */
+	u8 sta_idx;
+	/* TID for which the agreement is being confirmed */
+	u8 tid;
+	/* Status of ba establishment */
+	u8 status;
+	/* Aggregation index */
+	u8 agg_idx;
+	/* Number of descriptors the queue of session can hold */
+	u16 desc_cnt;
+};
+
+/* Structure containing the parameters of the MM_BA_DEL_REQ message. */
+struct mm_ba_del_req {
+	/* Index of peer station for which the agreement is being deleted */
+	u8 sta_idx;
+	/* TID for which the agreement is being deleted */
+	u8 tid;
+};
+
+/* Structure containing the parameters of the MM_BA_DEL_CFM message. */
+struct mm_ba_del_cfm {
+	/* Index of peer station for which the agreement deletion is being confirmed */
+	u8 sta_idx;
+	/* TID for which the agreement deletion is being confirmed */
+	u8 tid;
+	/* Status of ba deletion */
+	u8 status;
+};
+
+/* Structure containing the parameters of the MM_AVAILABLE_BA_TXQ_REQ message. */
+struct mm_available_ba_txq_req {
+	/* Index of peer station for which the agreement deletion is being confirmed */
+	u8 sta_idx;
+	/* TID for which the agreement deletion is being confirmed */
+	u8 tid;
+};
+
+/* Structure containing the parameters of the MM_AVAILABLE_BA_TXQ_CFM message. */
+struct mm_available_ba_txq_cfm {
+	/* Index of peer station for which the agreement deletion is being confirmed */
+	u8 sta_idx;
+	/* TID for which the agreement deletion is being confirmed */
+	u8 tid;
+	/* Status if ba txqueue available */
+	u8 status;
+};
+
+struct sounding_info_per_sta {
+	u8 sta_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8 nc                 : 4, /* [3:0] NC of the STA */
+	   fb_type_ng_cb_size : 3, /* [6:4] */
+	   rsv1               : 1; /* [7] reserved */
+#else
+	u8 rsv1               : 1, /* [7] reserved */
+	   fb_type_ng_cb_size : 3, /* [6:4] */
+	   nc                 : 4; /* [3:0] NC of the STA */
+#endif
+};
+
+/* Information provided by application to firmware */
+struct mm_sounding_req {
+	struct sounding_info_per_sta info_per_sta[CL_MU_MAX_STA_PER_GROUP];
+	__le32 host_address;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		/* [2:0] sounding type (HE-SU/HE-MU/HE_CQI/VHT-SU/VHT-MU) */
+	u32     sounding_type        : 3,
+		/* [3:6] number of stations in the sounding sequence */
+		sta_num              : 4,
+		/* [7] start/stop sounding sequence */
+		start                : 1,
+		/* [19:8] life expectancy of BFR in ms */
+		lifetime             : 12,
+		/* [31:20] sounding interval. 0 means a single sounding */
+		interval             : 12;
+		/* [1:0] requested bw for the sounding sequence (BFR/NDP) */
+	u8      req_txbw             : 2,
+		/* [5:2] NSTS in the NDP frame */
+		ndp_nsts             : 4,
+		/* [7:6] reserved bits */
+		rsv1                 : 2;
+		/* [3:0] Bitmap of STAs to create SU Q-matrix for */
+	u8      q_matrix_bitmap      : 4,
+		/* [7:4] reserved bits */
+		rsv2                 : 4;
+#else
+		/* [31:20] sounding interval. 0 means a single sounding */
+	u32     interval             : 12,
+		/* [19:8] life expectancy of BFR in ms */
+		lifetime             : 12,
+		/* [7] start/stop sounding sequence */
+		start                : 1,
+		/* [3:6] number of stations in the sounding sequence */
+		sta_num              : 4,
+		/* [2:0] sounding type (HE-SU/HE-MU/HE_CQI/VHT-SU/VHT-MU) */
+		sounding_type        : 3;
+		/* [7:6] reserved bits */
+	u8      rsv1                 : 2,
+		/* [5:2] NSTS in the NDP frame */
+		ndp_nsts             : 4,
+		/* [1:0] requested bw for the sounding sequence (BFR/NDP) */
+		req_txbw             : 2;
+		/* [7:4] reserved bits */
+	u8      rsv2                 : 4,
+		/* [3:0] Bitmap of STAs to create SU Q-matrix for */
+		q_matrix_bitmap      : 4;
+#endif
+	/* Sounding id. Used when deleting a sounding sequence */
+	u8 sid;
+};
+
+/* Application feedback for sounding request */
+struct mm_sounding_cfm {
+	u8 param_err;
+	u8 sounding_id;
+};
+
+struct mm_sounding_pairing {
+	u8 sounding_type;
+	u8 sounding_id;
+	u8 sta_idx;
+	u8 gid;
+};
+
+struct mm_sounding_interval_req {
+	__le16 interval;     /* Sounding interval */
+	__le16 bfr_lifetime; /* Life expectancy of BFR in ms */
+	u8 sounding_type;    /* Type of sounding (VHT/HT/SU/MU) */
+	u8 sta_idx;          /* Sta idx */
+};
+
+struct mm_sounding_interval_cfm {
+	u8 param_err;
+};
+
+/* Structure containing the parameters of the MM_BACKUP_BCN_EN_REQ message */
+struct mm_set_backup_bcn_en_req {
+	/* Backup beacon disable/enable */
+	bool backup_bcn_en;
+};
+
+/* Structure containing the parameters of the MM_START_PERIODIC_TX_TIME_REQ message */
+struct mm_start_periodic_tx_time_req {
+	__le16 periodic_tx_time_off;
+	__le16 periodic_tx_time_on;
+};
+
+enum ANAMON_MODE {
+	ANAMON_MODE_TEMPERATURE,
+	ANAMON_MODE_CHAINS,
+	ANAMON_MODE_SX
+};
+
+/* Structure containing the parameters of the MM_ANAMON_READ_REQ message */
+struct mm_anamon_read_req {
+	u8 mode;   /* 0 - Temperature, 1 - Chains, 2 - SX */
+	u8 param1; /* For mode = 0: 0 - Internal, 1 - External ; For mode = 1/2: Page number */
+	u8 param2; /* For mode = 5 bit value corresponding to mode selection */
+};
+
+struct mm_anamon_read_cfm {
+	u8 retval;
+	__le16 raw_bits_data_0;
+	__le16 raw_bits_data_1;
+};
+
+struct mm_spi_write_req {
+	u8 page;
+	u8 addr;
+	u8 val;
+	u8 mask;
+};
+
+struct mm_spi_read_req {
+	u8 page;
+	u8 addr;
+};
+
+struct mm_spi_read_cfm {
+	u8 status;
+	u8 val;
+};
+
+/* +++++++++++++++++++++++++ Debug messages +++++++++++++++++++++++++ */
+
+/* Messages related to Debug Task */
+enum dbg_msg_tag {
+	/* Set module filter message */
+	DBG_SET_MOD_FILTER_REQ = FIRST_MSG(TASK_DBG),
+	DBG_SET_MOD_FILTER_CFM,
+	/* Set module filter message */
+	DBG_CE_SET_MOD_FILTER_REQ,
+	DBG_CE_SET_MOD_FILTER_CFM,
+	/* Set severity filter message */
+	DBG_SET_SEV_FILTER_REQ,
+	DBG_SET_SEV_FILTER_CFM,
+	/* Get ETH2WLAN statistics message */
+	DBG_GET_E2W_STATS_REQ,
+	DBG_GET_E2W_STATS_CFM,
+	/* Set LA MPIF mask message */
+	DBG_SET_LA_MPIF_MASK_REQ,
+	DBG_SET_LA_MPIF_MASK_CFM,
+	/* Set LA trigger point message */
+	DBG_SET_LA_TRIG_POINT_REQ,
+	DBG_SET_LA_TRIG_POINT_CFM,
+	/* Set LA MPIF debug mode message */
+	DBG_SET_LA_MPIF_DEBUG_MODE_REQ,
+	DBG_SET_LA_MPIF_DEBUG_MODE_CFM,
+	/* Set LA trigger rule message */
+	DBG_SET_LA_TRIG_RULE_REQ,
+	DBG_SET_LA_TRIG_RULE_CFM,
+	/* TX trace dump debug flag message */
+	DBG_TX_TRACE_DEBUG_FLAG_REQ,
+	DBG_TX_TRACE_DEBUG_FLAG_CFM,
+	/* Print statistics message */
+	DBG_PRINT_STATS_REQ,
+	DBG_PRINT_STATS_CFM,
+	/* Trigger the embedded logic analyzer message */
+	DBG_TRIGGER_REQ,
+	DBG_TRIGGER_CFM,
+	/* Test mode message */
+	DBG_TEST_MODE_REQ,
+	DBG_TEST_MODE_CFM,
+	/* Sounding command message */
+	DBG_SOUNDING_CMD_REQ,
+	DBG_SOUNDING_CMD_CFM,
+	/* Presilicon HW testing message */
+	DBG_PRESILICON_TESTING_REQ,
+	DBG_PRESILICON_TESTING_CFM,
+
+	DBG_REQ_CFM_MAX,
+
+	/* Print request */
+	DBG_PRINT_IND = DBG_REQ_CFM_MAX,
+	/* Information indication */
+	DBG_INFO_IND,
+	/* Max number of debug messages */
+	DBG_MAX,
+};
+
+/* Structure containing the parameters of the DBG_SET_MOD_FILTER_REQ message. */
+struct dbg_set_mod_filter_req {
+	/* Bit field indicating for each module if the traces are enabled or not */
+	__le32 mod_filter;
+};
+
+/* Structure containing the parameters of the DBG_SEV_MOD_FILTER_REQ message. */
+struct dbg_set_sev_filter_req {
+	/* Bit field indicating the severity threshold for the traces */
+	__le32 sev_filter;
+};
+
+/* Must be aligned with FW (dbg.h) */
+enum dbg_test_mode {
+	DBG_TEST_MODE_HELP = 0,
+	DBG_TEST_MODE_ASSERT_REC,
+	DBG_TEST_MODE_ERR_CORRECT_MODE,
+	DBG_TEST_MODE_PRESILICON_TESTS,
+	DBG_TEST_MODE_TRIGGER_BA_NOT_RECEIVED,
+	DBG_TEST_MODE_TRIGGER_ABOVE_BAW,
+	DBG_TEST_MODE_TRIGGER_BELOW_BAW,
+	DBG_TEST_MODE_TRIGGER_RETRY_LIMIT_REACHED,
+	DBG_TEST_MODE_DMA_DATA_PRINT,
+	DBG_TEST_MODE_SET_AGC_MEM,
+	DBG_TEST_MODE_FW_TRACE_MODE,
+	DBG_TEST_MODE_TX_POWER_DEBUG,
+	DBG_TEST_MODE_DCOC_IQ_MODE,
+	DBG_TEST_MODE_MACHW_STATE,
+	DBG_TEST_MODE_PHY_GLOBAL_RESET,
+	DBG_TEST_MODE_PHY_OLYMPUS_TXRX_MODE,
+	DBG_TEST_MODE_AFE_LOOPBACK_MODE,
+	DBG_TEST_MODE_MIN_SPACING_MODE,
+	DBG_TEST_MODE_DELAY_CHAIN,
+	DBG_TEST_MODE_ERR_DUMP_PRINT,
+	DBG_TEST_MODE_BW_SIG_PRINT,
+	DBG_TEST_MODE_RECOVER_BA_NOT_RECEIVED,
+	DBG_TEST_MODE_BAP_MODE,
+	DBG_TEST_MODE_DPHY_INJECT_RXERR,
+	DBG_TEST_MODE_RXM_RXVECTOR_PRINT,
+	DBG_TEST_MODE_STOP_CHAIN,
+	DBG_TEST_MODE_MAX_AGG_SIZE,
+	DBG_TEST_MODE_DISABLE_RECOVERY,
+	DBG_TEST_MODE_SET_NAV_DURATION,
+	DBG_TEST_MODE_SET_NAV_CLEAR,
+	DBG_TEST_MODE_DRA_GRP_LIMIT_SET,
+	DBG_TEST_MODE_DURATION_FROM_THD,
+	DBG_TEST_MODE_RIU_INT_EN,
+	DBG_TEST_MODE_MU_OF_1_USER,
+	DBG_TEST_MODE_FORCE_TRIGGER,
+	DBG_TEST_MODE_RECOVERY_DEBUG,
+	DBG_TEST_MODE_CHAIN_SUSPEND,
+	DBG_TEST_MODE_DSP_LCU_TRIG,
+	DBG_TEST_MODE_POWER_SAVE,
+	DBG_TEST_MODE_TRIGGER_RX_NOT_RECEIVED,
+	DBG_TEST_MODE_SNIFFER_MODE,
+	DBG_TEST_MODE_AGC_CAPTURE_NOISE,
+	DBG_TEST_MODE_TRIGGER_UNDERRUN,
+	DBG_TEST_MODE_TF_IN_AMPDU_EN,
+	DBG_TEST_MODE_HOST_FW_QUEUE_WR_RD,
+	DBG_TEST_MODE_TXDESC_DMA_TOKEN_SET,
+	DBG_TEST_MODE_ASSERT_ERR,
+	DBG_TEST_MODE_MAX,
+};
+
+/* Information sent from firmware to host indicating the rx bfr variables */
+struct mm_sounding_ind {
+	/* Param that are application private, collected by host without local copy */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8 sounding_type : 3,
+	   status        : 1,
+	   fail_reason   : 4;
+	u8 mu            : 1,
+	   rsv           : 7;
+#else
+	u8 fail_reason   : 4,
+	   status        : 1,
+	   sounding_type : 3;
+	u8 rsv           : 7,
+	   mu            : 1;
+#endif
+	u8 sid;
+	u8 sta_idx;
+	u16 v_matrix_offset[CL_MU_MAX_STA_PER_GROUP];
+};
+
+/* Possible fw errors types */
+enum mm_fw_error_type {
+	MM_FW_ERROR_TYPE_MU_OFDMA_SLOW_SECONDARY,
+	MM_FW_ERROR_TYPE_MAX
+};
+
+/* Structure containing the parameters of the MM_FW_ERROR_IND message */
+struct mm_fw_error_ind {
+	u8 group_id;
+	u8 error_type;
+	u8 sta_inidices[CL_MU_MAX_STA_PER_GROUP];
+	u8 sta_num;
+};
+
+enum mm_agg_rx_status_type {
+	MM_AGG_RX_REPORT_STAT_OK,
+	MM_AGG_RX_REPORT_STAT_COLISION_WITH_COUNTER,
+	MM_AGG_RX_REPORT_STAT_COUNTER_LOST,
+	MM_AGG_RX_REPORT_STAT_NOT_RECEIVED,
+	MM_AGG_RX_REPORT_STAT_NOT_HE
+};
+
+struct mm_agg_rx_ind {
+	u8 sta_num;
+	u8 sta_idx[CL_MU_MAX_STA_PER_GROUP];
+	u8 status[CL_MU_MAX_STA_PER_GROUP];
+	__le16 ampdu_received_counter[CL_MU_MAX_STA_PER_GROUP];
+	__le16 discarded_mpdu_count[CL_MU_MAX_STA_PER_GROUP];
+	__le16 correct_received_mpdu_count[CL_MU_MAX_STA_PER_GROUP];
+	__le16 incorrect_received_mpdu_count[CL_MU_MAX_STA_PER_GROUP];
+	__le16 rx_discarded_mpdu_count[CL_MU_MAX_STA_PER_GROUP];
+	__le16 incorrect_delimiter_count[CL_MU_MAX_STA_PER_GROUP];
+	u8 nss_per_user[CL_MU_MAX_STA_PER_GROUP];
+	u8 mcs_rate[CL_MU_MAX_STA_PER_GROUP];
+	u8 ru_allocation[CL_MU_MAX_STA_PER_GROUP];
+	u8 gi_ltf;
+	u8 rcpi[CL_MU_MAX_STA_PER_GROUP];
+	u8 evm1[CL_MU_MAX_STA_PER_GROUP];
+	u8 evm2[CL_MU_MAX_STA_PER_GROUP];
+	u8 evm3[CL_MU_MAX_STA_PER_GROUP];
+	u8 evm4[CL_MU_MAX_STA_PER_GROUP];
+};
+
+#define MSG_TOTAL_REQ_CFM (MM_REQ_CFM_MAX + DBG_REQ_CFM_MAX)
+#define DBG_STR_SHIFT(id) ((id) - FIRST_MSG(TASK_DBG) + MM_REQ_CFM_MAX)
+#define MSG_ID_STR(id)    (((id) < MM_REQ_CFM_MAX) ? msg2str[id] : msg2str[DBG_STR_SHIFT(id)])
+
+extern const char *const msg2str[MSG_TOTAL_REQ_CFM];
+
+/* Timeout waiting for firmware confirmation */
+#define CL_MSG_CFM_TIMEOUT_MS            400
+#define CL_MSG_CFM_TIMEOUT_JIFFIES       msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_MS)
+
+#define CL_MSG_CFM_TIMEOUT_CALIB_MS      1800
+#define CL_MSG_CFM_TIMEOUT_CALIB_JIFFIES msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_CALIB_MS)
+
+#define CL_MSG_CFM_TIMEOUT_DUMMY_MS      7000
+#define CL_MSG_CFM_TIMEOUT_DUMMY_JIFFIES msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_DUMMY_MS)
+
+#define CL_MSG_CFM_TIMEOUT_FRU_MS        35000
+#define CL_MSG_CFM_TIMEOUT_FRU_JIFFIES   msecs_to_jiffies(CL_MSG_CFM_TIMEOUT_FRU_MS)
+
+#define CFM_CLEAR_BIT(bit, cfm_flags) \
+	clear_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_SET_BIT(bit, cfm_flags) \
+	set_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_TEST_BIT(bit, cfm_flags) \
+	test_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+#define CFM_TEST_AND_CLEAR_BIT(bit, cfm_flags) \
+	test_and_clear_bit((bit) & 0x1f, *(cfm_flags) + ((bit) >> 5))
+
+u16 cl_msg_cfm_set_bit(u16 req);
+int cl_msg_cfm_wait(struct cl_hw *cl_hw, u16 bit, u16 req_id);
+void cl_msg_cfm_assign_and_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_msg_cfm_clear(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_msg_rx_tasklet(unsigned long data);
+void cl_msg_rx_flush_all(struct cl_hw *cl_hw);
+
+#define FREQUENCY_INT_MASK 0xfffc
+#define FREQUENCY_FRAC_MASK 0x0003
+#define FREQUENCY_INT_SHIFT 2
+#define FREQUENCY_FRAC_RESOLUTION 25
+
+#define GET_FREQ_INT(freq) (((freq) & FREQUENCY_INT_MASK) >> FREQUENCY_INT_SHIFT)
+#define GET_FREQ_FRAC(freq) (((freq) & FREQUENCY_FRAC_MASK) * FREQUENCY_FRAC_RESOLUTION)
+
+enum ke_kern_tag {
+	KERN_HOST,
+	KERN_LMAC,
+	KERN_UMAC,
+	KERN_SMAC,
+
+	KERN_MAX,
+};
+
+#define SET_CHANNEL_MODE_OPERETIONAL  0x01
+#define SET_CHANNEL_MODE_CALIB_DCOC   0x02
+#define SET_CHANNEL_MODE_CALIB_IQ     0x04
+#define SET_CHANNEL_MODE_CALIB_LOLC   0x08
+#define SET_CHANNEL_MODE_CALIB_MANUAL 0x10
+#define SET_CHANNEL_MODE_CALIB        (SET_CHANNEL_MODE_CALIB_DCOC | \
+				       SET_CHANNEL_MODE_CALIB_IQ | \
+				       SET_CHANNEL_MODE_CALIB_LOLC)
+
+/*
+ * confirmation call back params
+ * @err: general msg transmitting error
+ * @param: pointer to lower layer feedback param (FW layer)
+ */
+struct cl_msg_cfm_cb_param {
+	int err;
+	void *param; /* Pointer to msg cfm param, the caller should be aware to that type */
+};
+
+/*
+ * call back function definition, associate with all backgrounf triggered messages
+ * if caller intersting in message done feedback it must declare function of this type!
+ */
+typedef void (*cl_msg_cfm_cb_func)(struct cl_msg_cfm_cb_param *p_cfm_cb_param, u32 token);
+
+void cl_msg_tx_free_cfm_params(struct cl_hw *cl_hw, u16 id);
+int cl_msg_tx_reset(struct cl_hw *cl_hw);
+int cl_msg_tx_start(struct cl_hw *cl_hw);
+int cl_msg_tx_version(struct cl_hw *cl_hw);
+int cl_msg_tx_add_if(struct cl_hw *cl_hw, struct ieee80211_vif *vif, u8 vif_index);
+int cl_msg_tx_remove_if(struct cl_hw *cl_hw, u8 vif_index);
+int cl_msg_tx_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta, struct cl_vif *cl_vif,
+		      u8 recovery_sta_idx, u32 rate_ctrl_info);
+int cl_msg_tx_sta_del(struct cl_hw *cl_hw, u8 sta_idx);
+int cl_msg_tx_set_filter(struct cl_hw *cl_hw, u32 filter, bool force);
+int cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary, u32 center,
+			  struct cl_calib_params calib_params);
+int cl_msg_tx_dtim(struct cl_hw *cl_hw, u8 dtim_period);
+int cl_msg_tx_set_beacon_int(struct cl_hw *cl_hw, u16 beacon_int, u8 vif_idx);
+int cl_msg_tx_set_basic_rates(struct cl_hw *cl_hw, u32 basic_rates);
+int cl_msg_tx_set_bssid(struct cl_hw *cl_hw, const u8 *bssid, u8 vif_idx);
+int cl_msg_tx_set_edca(struct cl_hw *cl_hw, u8 hw_queue, u32 param,
+		       struct ieee80211_he_mu_edca_param_ac_rec *mu_edca);
+int cl_msg_tx_set_associated(struct cl_hw *cl_hw,
+			     struct ieee80211_bss_conf *bss_conf);
+int cl_msg_tx_set_slottime(struct cl_hw *cl_hw, bool use_short_slot);
+int cl_msg_tx_set_idle(struct cl_hw *cl_hw, u8 idle, bool is_lock);
+void cl_msg_tx_idle_async(struct cl_hw *cl_hw, bool is_lock);
+int cl_msg_tx_key_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+		      struct ieee80211_key_conf *key_conf, u8 cipher_suite);
+int cl_msg_tx_key_del(struct cl_hw *cl_hw, u8 hw_key_idx);
+int cl_msg_tx_ba_add(struct cl_hw *cl_hw, u8 type, u8 sta_idx, u16 tid, u16 bufsz, u16 ssn);
+int cl_msg_tx_ba_del(struct cl_hw *cl_hw, u8 sta_idx, u16 tid);
+int cl_msg_tx_available_ba_txq(struct cl_hw *cl_hw, u8 sta_idx, u16 tid);
+int cl_msg_tx_update_rate_dl(struct cl_hw *cl_hw, u8 sta_idx, u32 rate, u32 rate_fallback,
+			     u8 req_bw_tx, u8 op_mode, u8 gid, u8 mu_valid, u8 ltf,
+			     u8 ltf_fallback, u32 rate_he);
+int cl_msg_tx_update_rate_ul(struct cl_hw *cl_hw, u8 sta_idx, u8 bw, u8 nss, u8 mcs, u8 gi_ltf);
+int cl_msg_tx_set_vns(struct cl_hw *cl_hw, u8 sta_idx, u8 is_vns);
+int cl_msg_tx_set_tx_bf(struct cl_hw *cl_hw, u8 sta_idx, u8 is_on, u8 is_on_fallback);
+int cl_msg_tx_sounding(struct cl_hw *cl_hw,
+		       struct mm_sounding_req *sounding_req);
+int cl_msg_tx_sounding_pairing(struct cl_hw *cl_hw, u8 sounding_id, u8 sounding_type,
+			       u8 gid, u8 sta_idx);
+int cl_msg_tx_sounding_interval(struct cl_hw *cl_hw, u16 interval, u16 lifetime,
+				u8 sounding_type, u8 sta_idx);
+int cl_msg_tx_set_dfs(struct cl_hw *cl_hw, bool enable, u8 standard,
+		      u8 initial_gain, u8 agc_cd_th);
+int cl_msg_tx_ndp_tx_control(struct cl_hw *cl_hw, u8 chain_mask, u8 bw, u8 format, u8 num_ltf);
+int cl_msg_tx_reg_write(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask);
+int cl_msg_tx_prot_mode(struct cl_hw *cl_hw, u8 log_nav_en, u8 mode,
+			u8 rate_format, u8 rate_mcs, u8 rate_pre_type);
+int cl_msg_tx_backup_bcn_en(struct cl_hw *cl_hw, bool backup_bcn_en);
+int cl_msg_tx_start_periodic_tx_time(struct cl_hw *cl_hw, u16 periodic_tx_time_off,
+				     u16 periodic_tx_time_on);
+int cl_msg_tx_anamon_read(struct cl_hw *cl_hw, u8 mode, u8 param1, u8 param2);
+int cl_msg_tx_refresh_power(struct cl_hw *cl_hw);
+int cl_msg_tx_set_ant_pwr_offset(struct cl_hw *cl_hw, s8 pwr_offset[MAX_ANTENNAS]);
+int cl_msg_tx_set_rate_fallback(struct cl_hw *cl_hw);
+int cl_msg_tx_spi_write(struct cl_hw *cl_hw, u8 page, u8 addr, u8 val, u8 mask);
+int cl_msg_tx_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr);
+
+/* Debug messages */
+int cl_msg_tx_dbg_set_ce_mod_filter(struct cl_hw *cl_hw, u32 filter);
+int cl_msg_tx_dbg_set_sev_filter(struct cl_hw *cl_hw, u32 filter);
+
+#endif /* CL_FW_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 33/96] cl8k: add hw.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (31 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
@ 2022-05-24 11:33 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 34/96] cl8k: add hw.h viktor.barna
                   ` (62 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:33 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw.c | 432 ++++++++++++++++++++++++++
 1 file changed, 432 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.c

diff --git a/drivers/net/wireless/celeno/cl8k/hw.c b/drivers/net/wireless/celeno/cl8k/hw.c
new file mode 100644
index 000000000000..834622549f9a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/spinlock.h>
+
+#include "tx.h"
+#include "rates.h"
+#include "reg/reg_access.h"
+#include "recovery.h"
+#include "hw.h"
+
+static void cl_hw_init_tcv0(struct cl_hw *cl_hw)
+{
+	struct cl_controller_reg *controller_reg = &cl_hw->controller_reg;
+
+	cl_hw->fw_dst_kern_id = KERN_LMAC;
+	cl_hw->fw_prefix = 'l';
+
+	controller_reg->breset = LMAC_BRESET;
+	controller_reg->debug_enable = LMAC_DEBUG_ENABLE;
+	controller_reg->dreset = LMAC_DRESET;
+	controller_reg->ocd_halt_on_reset = LMAC_OCD_HALT_ON_RESET;
+	controller_reg->run_stall = LMAC_RUN_STALL;
+
+	cl_hw->mac_hw_regs_offset = 0;
+	cl_hw->phy_regs_offset = REG_PHY_LMAC_OFFSET;
+}
+
+static void cl_hw_init_tcv1(struct cl_hw *cl_hw)
+{
+	struct cl_controller_reg *controller_reg = &cl_hw->controller_reg;
+
+	cl_hw->fw_dst_kern_id = KERN_SMAC;
+	cl_hw->fw_prefix = 's';
+
+	controller_reg->breset = SMAC_BRESET;
+	controller_reg->debug_enable = SMAC_DEBUG_ENABLE;
+	controller_reg->dreset = SMAC_DRESET;
+	controller_reg->ocd_halt_on_reset = SMAC_OCD_HALT_ON_RESET;
+	controller_reg->run_stall = SMAC_RUN_STALL;
+
+	cl_hw->mac_hw_regs_offset = REG_MAC_HW_SMAC_OFFSET;
+	cl_hw->phy_regs_offset = REG_PHY_SMAC_OFFSET;
+}
+
+static void cl_hw_set_first_last_riu_chains(struct cl_hw *cl_hw, u8 first_ant, u8 last_ant)
+{
+	u8 ant, chain;
+	u8 min_chain = U8_MAX;
+	u8 max_chain = 0;
+
+	for (ant = first_ant; ant <= last_ant; ant++) {
+		chain = cl_hw_ant_to_riu_chain(cl_hw, ant);
+
+		if (chain < min_chain)
+			min_chain = chain;
+
+		if (chain > max_chain)
+			max_chain = chain;
+	}
+
+	cl_hw->first_riu_chain = min_chain;
+	cl_hw->last_riu_chain = max_chain;
+}
+
+void cl_hw_init(struct cl_chip *chip, struct cl_hw *cl_hw, u8 tcv_idx)
+{
+	write_lock(&chip->cl_hw_lock);
+	chip->cl_hw_lut[tcv_idx] = cl_hw;
+	write_unlock(&chip->cl_hw_lock);
+
+	if (tcv_idx == TCV0)
+		cl_hw_init_tcv0(cl_hw);
+	else
+		cl_hw_init_tcv1(cl_hw);
+}
+
+void cl_hw_deinit(struct cl_hw *cl_hw, u8 tcv_idx)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	write_lock(&chip->cl_hw_lock);
+	chip->cl_hw_lut[tcv_idx] = NULL;
+	write_unlock(&chip->cl_hw_lock);
+}
+
+struct cl_hw *cl_hw_other_tcv(struct cl_hw *cl_hw)
+{
+	/* This function must be called after read lock is taken */
+	return cl_hw->chip->cl_hw_lut[1 - cl_hw->tcv_idx];
+}
+
+bool cl_hw_is_tcv0(struct cl_hw *cl_hw)
+{
+	return (cl_hw->tcv_idx == TCV0);
+}
+
+bool cl_hw_is_tcv1(struct cl_hw *cl_hw)
+{
+	return (cl_hw->tcv_idx == TCV1);
+}
+
+bool cl_hw_is_first_tcv(struct cl_hw *cl_hw)
+{
+	if (cl_hw_is_tcv0(cl_hw))
+		return true;
+	else
+		return cl_chip_is_only_tcv1_enabled(cl_hw->chip);
+}
+
+int cl_hw_set_antennas(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 last_ant;
+	u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+	/* Set num_antennas and max_antennas + masks for both. */
+	switch (chip->fem.wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+		cl_hw->max_antennas = 6;
+		break;
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+		cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 6 : 4;
+		break;
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		cl_hw->max_antennas = 4;
+		break;
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+		cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 4 : 2;
+		break;
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+			cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 4 : 2;
+		break;
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+		cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 4 : 0;
+		break;
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+		cl_hw->max_antennas = 2;
+		break;
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		cl_hw->max_antennas = cl_hw_is_tcv0(cl_hw) ? 2 : 1;
+		break;
+	default:
+		if (chip->conf->ce_production_mode)
+			cl_hw->max_antennas = chip->max_antennas;
+		else
+			return -1;
+		break;
+	}
+
+	cl_hw->num_antennas = cl_hw->conf->ce_num_antennas;
+	cl_hw->mask_num_antennas = ANT_MASK(cl_hw->num_antennas) << ant_shift;
+	cl_hw->first_ant = ant_shift;
+	last_ant = max_t(s8, cl_hw->num_antennas + ant_shift - 1, 0);
+
+	cl_hw_set_first_last_riu_chains(cl_hw, cl_hw->first_ant, last_ant);
+
+	cl_dbg_trace(cl_hw, "num_antennas = %u, max_antennas = %u\n",
+		     cl_hw->num_antennas, cl_hw->max_antennas);
+
+	if (cl_hw->num_antennas > cl_hw->max_antennas) {
+		CL_DBG_ERROR(cl_hw, "num_antennas (%u) > max_antennas (%u)\n",
+			     cl_hw->num_antennas, cl_hw->max_antennas);
+		return -1;
+	}
+
+	return 0;
+}
+
+u8 cl_hw_ant_shift(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	/* CL808x uses antennas 0 - 3 for both bands */
+	if (cl_chip_is_8ant(chip))
+		return 0;
+
+	if (cl_chip_is_6ant(chip)) {
+		/*
+		 * CL806X on wiring id 24 uses antennas 0-3 for TCV0 and antennas 2-3 for TCV1.
+		 * When only 1 antenna is configured - ant 3 is used.
+		 */
+		if (cl_hw_is_tcv1(cl_hw) && chip->fem.wiring_id == FEM_WIRING_24_TCV0_6_TCV1_4)
+			return (4 - cl_hw->conf->ce_num_antennas);
+
+		/* Other CL806X use antennas 0 - 3 for TCV0 and antennas 0-1 for TCV1 */
+		return 0;
+	}
+
+	/*
+	 * CL8046 uses chains 0 - 3 for TCV0 and no chain for TCV1.
+	 * Wiring ID 31 uses chains 2-3 for TCV0 and chain 4 for TCV1.
+	 */
+	if (cl_chip_is_6g(chip)) {
+		if (chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+			return cl_hw_is_tcv0(cl_hw) ? 2 : 4;
+
+		return 0;
+	}
+
+	/* CL8040 uses chains 1 - 2 for TCV0 and TCV1 */
+	return 1;
+}
+
+u8 cl_hw_ant_to_riu_chain(struct cl_hw *cl_hw, u8 ant)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u8 res = ant;
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		if (chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+			return ((ant - 2) & 0x3);
+
+		if (chip->fem.wiring_id == FEM_WIRING_30_TCV0_4_TCV1_2) {
+			if (ant == 2)
+				return 3;
+			if (ant == 3)
+				return 2;
+
+			return ant;
+		}
+
+		return ant;
+	}
+
+	switch (chip->fem.wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+		return ant;
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		res = (3 - ant);
+		break;
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+		res = (5 - ant);
+		break;
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+		res = (2 - ant);
+		break;
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		res = (ant == 2 ? 4 : (ant == 4 ? 2 : 0));
+		break;
+	default:
+		break;
+	}
+
+	/* Verify that the returned value is valid */
+	return res & ANT_MASK(MAX_ANTENNAS);
+}
+
+u8 cl_hw_ant_mask_to_riu_chain_mask(struct cl_hw *cl_hw, u8 ant_mask)
+{
+	u8 ant, riu_chain, riu_chain_mask = 0x0;
+
+	for (ant = 0; ant < MAX_ANTENNAS; ant++) {
+		if (ant_mask & BIT(ant)) {
+			riu_chain = cl_hw_ant_to_riu_chain(cl_hw, ant);
+			riu_chain_mask |= BIT(riu_chain);
+		}
+	}
+
+	return riu_chain_mask;
+}
+
+bool cl_hw_is_prod_or_listener(struct cl_hw *cl_hw)
+{
+	/* TODO: Move ce_listener_en to cl_chip */
+	if (cl_hw->chip->conf->ce_production_mode ||
+	    (cl_hw->conf && cl_hw->conf->ce_listener_en))
+		return true;
+
+	return false;
+}
+
+#define ASSERT_PATTERN 0xC0DEDEAD
+
+/*
+ * Function will take time stamp for each hw error indication.
+ * when time diff between each error is less than ce_hw_assert_time_max
+ * cl_hw_restart work will be scheduled
+ */
+static bool cl_hw_assert_storm_detect(struct cl_hw *cl_hw)
+{
+	struct cl_hw_asserts_info *assert_info = &cl_hw->assert_info;
+	u8 idx = assert_info->index % CL_MIN_ASSERT_CNT;
+	/* Get the oldest assert timestamp. */
+	u8 prev_idx = (assert_info->index + 1) % CL_MIN_ASSERT_CNT;
+	bool is_hw_restarted = false;
+
+	if (assert_info->restart_sched) {
+		is_hw_restarted = true;
+	} else {
+		/* Take time stamp of the assert */
+		assert_info->timestamp[idx] = jiffies;
+		assert_info->index++;
+		/* In case hw assert time diff is less than CL_HW_ASSERT_TIME_MAX, restart hw. */
+		if (assert_info->index > CL_MIN_ASSERT_CNT) {
+			unsigned long time_diff_jiffies =
+				assert_info->timestamp[idx] - assert_info->timestamp[prev_idx];
+			unsigned int time_diff_msecs = jiffies_to_msecs(time_diff_jiffies);
+
+			if (time_diff_msecs < cl_hw->conf->ce_hw_assert_time_max) {
+				assert_info->index = 0;
+
+				cl_dbg_err(cl_hw, "Assert storm detect (time_diff = %u)\n",
+					   time_diff_msecs);
+				cl_recovery_start(cl_hw, RECOVERY_ASSERT_STORM_DETECT);
+
+				is_hw_restarted = true;
+			}
+		}
+	}
+
+	return is_hw_restarted;
+}
+
+void cl_hw_assert_info_init(struct cl_hw *cl_hw)
+{
+	memset(&cl_hw->assert_info, 0, sizeof(cl_hw->assert_info));
+}
+
+static void cl_recovery_no_dump_start(struct cl_hw *cl_hw, enum recovery_reason reason)
+{
+	cl_dbg_trace(cl_hw, "Starting recovery due to assert no dump\n");
+	cl_recovery_start(cl_hw, reason);
+}
+
+void cl_hw_assert_print(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+	struct dbg_print_ind *ind = (struct dbg_print_ind *)msg->param;
+	const char *assert_string;
+	u32 assert_pattern;
+	u16 file_id = le16_to_cpu(ind->file_id);
+	u16 line = le16_to_cpu(ind->line);
+	u16 has_param = le16_to_cpu(ind->has_param);
+	u32 param = le32_to_cpu(ind->param);
+
+	/* If ce_hw_assert_time_max is 0, HW assert storm detection is disabled */
+	if (cl_hw->conf->ce_hw_assert_time_max)
+		if (cl_hw_assert_storm_detect(cl_hw))
+			return;
+
+	assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+
+	/* Avoid printing background asserts */
+	if (cl_hw->conf->ce_bg_assert_print || !strstr(assert_string, "ASSERT_REC")) {
+		/* Print ASSERT message with file_id, line, [parameter] */
+		if (has_param)
+			cl_dbg_err(cl_hw, "ASSERT_TCV%u @ FILE=%u LINE=%u param=0x%08X\n",
+				   cl_hw->idx, file_id, line, param);
+		else
+			cl_dbg_err(cl_hw, "ASSERT_TCV%u @ file=%u line=%u\n",
+				   cl_hw->idx, file_id, line);
+
+		if (!assert_string)
+			assert_string = "ASSERT STRING NOT FOUND";
+
+		/* TODO:length of single print may be limited,consider print long msgs by pieces */
+		cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+	}
+
+	assert_pattern = ioread32((void __iomem *)&cl_hw->ipc_env->shared->assert_pattern);
+
+	/* Reset ASSERT pattern if needed (in order to prevent assert prints loop) */
+	if (assert_pattern == ASSERT_PATTERN)
+		iowrite32(0, (void __iomem *)&cl_hw->ipc_env->shared->assert_pattern);
+
+	if (!ind->err_no_dump)
+		return;
+
+	cl_recovery_no_dump_start(cl_hw, RECOVERY_UNRECOVERABLE_ASSERT_NO_DUMP);
+}
+
+void cl_hw_assert_check(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_shared_env __iomem *shared_env = cl_hw->ipc_env->shared;
+	u32 assert_pattern = ioread32((void __iomem *)&shared_env->assert_pattern);
+
+	if (assert_pattern == ASSERT_PATTERN) {
+		u16 line = ioread16((void __iomem *)&shared_env->assert_line_num);
+		u16 file_id = ioread16((void __iomem *)&shared_env->assert_file_id);
+		u32 param = ioread32((void __iomem *)&shared_env->assert_param);
+		const char *assert_string = cl_dbgfile_get_msg_txt(&cl_hw->dbg_data, file_id, line);
+
+		/* Print 1st ASSERT message with file_id, line, [parameter] */
+		cl_dbg_err(cl_hw, "ASSERT_%cmac @ FILE=%u LINE=%u param=0x%08X\n",
+			   cl_hw->fw_prefix, file_id, line, param);
+
+		if (!assert_string)
+			assert_string = "ASSERT STRING NOT FOUND";
+
+		cl_dbg_err(cl_hw, "%.500s\n", assert_string);
+
+		/* Reset ASSERT pattern in order to prevent assert prints loop */
+		iowrite32(0, (void __iomem *)&shared_env->assert_pattern);
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 34/96] cl8k: add hw.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (32 preceding siblings ...)
  2022-05-24 11:33 ` [RFC v2 33/96] cl8k: add hw.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 35/96] cl8k: add ipc_shared.h viktor.barna
                   ` (61 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/hw.h | 280 ++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/hw.h

diff --git a/drivers/net/wireless/celeno/cl8k/hw.h b/drivers/net/wireless/celeno/cl8k/hw.h
new file mode 100644
index 000000000000..c34a2bc0d990
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/hw.h
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_HW_H
+#define CL_HW_H
+
+#include <linux/module.h>
+
+#include "traffic.h"
+#include "temperature.h"
+#include "dfs.h"
+#include "calib.h"
+#include "ipc_shared.h"
+#include "fw.h"
+#include "rates.h"
+#include "def.h"
+#include "tx.h"
+#include "radio.h"
+#include "mac80211.h"
+#include "scan.h"
+#include "rx.h"
+#include "wrs.h"
+#include "vns.h"
+#include "sta.h"
+#include "debug.h"
+#include "chip.h"
+#include "recovery.h"
+#include "bf.h"
+#include "power.h"
+#include "phy.h"
+#include "vif.h"
+#include "tcv.h"
+#include "sounding.h"
+#include "version.h"
+
+#define cl_hw_get_iface_conf(cl_hw) atomic_read(&(cl_hw)->iface_conf)
+#define cl_hw_set_iface_conf(cl_hw, value) atomic_set(&(cl_hw)->iface_conf, value)
+
+/* Structure used to store information regarding E2A msg buffers in the driver */
+struct cl_e2a_msg_elem {
+	struct cl_ipc_e2a_msg *msgbuf_ptr;
+	dma_addr_t dma_addr;
+};
+
+enum cl_iface_conf {
+	CL_IFCONF_AP,
+	CL_IFCONF_STA,
+	CL_IFCONF_REPEATER,
+	CL_IFCONF_MESH_AP,
+	CL_IFCONF_MESH_ONLY,
+
+	CL_IFCONF_MAX
+};
+
+struct cl_hw_asserts_info {
+	/* Timestamp (jiffies) of the last CL_MIN_ASSERT_CNT hw assert. */
+	unsigned long timestamp[CL_MIN_ASSERT_CNT];
+	/* Hw assert index. */
+	u8 index;
+	/* Indicate if hw_restart was schedule */
+	u8 restart_sched;
+};
+
+struct cl_hw {
+	u8 idx; /* Global index (0-3) */
+	u8 tcv_idx; /* Transceiver index (0-1) */
+	u8 sx_idx;
+	struct cl_tcv_conf *conf;
+	struct cl_chip *chip;
+	struct ieee80211_hw *hw;
+	const struct cl_driver_ops *drv_ops;
+	struct cl_vif_db vif_db;
+	atomic_t iface_conf;
+	u32 num_ap_started;
+	u8 hw_mode;
+	enum cl_wireless_mode wireless_mode;
+	u8 tx_power_version;
+	struct cl_vif *mc_vif;
+	u8 bw;
+	u32 channel;
+	u32 primary_freq;
+	u32 center_freq;
+	enum nl80211_band nl_band;
+	u8 num_antennas;
+	u8 mask_num_antennas;
+	u8 first_ant;
+	u8 first_riu_chain;
+	u8 last_riu_chain;
+	u8 max_antennas;
+	struct cl_tx_db tx_db;
+	struct cl_sta_db cl_sta_db;
+	struct cl_ipc_e2a_irq ipc_e2a_irq;
+	struct cl_controller_reg controller_reg;
+	struct ieee80211_supported_band sband;
+	void (*ipc_host2xmac_trigger_set)(struct cl_chip *chip, u32 value);
+	unsigned long drv_flags;
+	unsigned long tx_disable_flags;
+	struct cl_ipc_host_env *ipc_env;
+	spinlock_t tx_lock_agg;
+	spinlock_t tx_lock_cfm_agg;
+	spinlock_t tx_lock_single;
+	spinlock_t tx_lock_bcmc;
+	struct mutex msg_tx_mutex;
+	wait_queue_head_t wait_queue; /* Synchronize driver<-->firmware message exchanges */
+	unsigned long cfm_flags[MAX_CFM_FLAGS];
+	void *msg_cfm_params[MM_MAX + DBG_MAX]; /* Array of pointers per received msg CFM */
+	bool msg_background;
+	wait_queue_head_t fw_sync_wq;
+	wait_queue_head_t radio_wait_queue;
+	struct cl_rx_elem *rx_elems;
+	struct cl_e2a_msg_elem *e2a_msg_elems;
+	struct cl_dbg_elem *dbg_elems;
+	struct cl_radar_elem *radar_elems;
+	struct dma_pool *txdesc_pool;
+	struct dma_pool *dbg_pool;
+	struct dma_pool *e2a_msg_pool;
+	struct dma_pool *radar_pool;
+	struct cl_debug_info dbginfo;
+	struct cl_hw_asserts_info assert_info;
+	char fw_prefix; /* Single character for fw prefix - l/u/s */
+	u8 fw_dst_kern_id; /* Firmware destination (LMAC/SMAC) */
+	bool fw_active; /* Firmware is active */
+	bool fw_send_start; /* Did driver already send a start request message to firmware? */
+	struct cl_dbg_data dbg_data;
+	struct cl_tx_power_info tx_pow_info[MAX_EXT_CHANNELS][MAX_ANTENNAS];
+	spinlock_t channel_info_lock;
+	struct cl_channel_info channel_info;
+	struct cl_phy_data_info phy_data_info;
+	u32 mask_hi;
+	u32 mask_low;
+	struct timer_list maintenance_slow_timer;
+	struct timer_list maintenance_fast_timer;
+	struct tasklet_struct tx_task;
+	struct list_head list_sched_q_agg;
+	struct list_head list_sched_q_single;
+	struct cl_req_agg_db req_agg_db[IPC_MAX_BA_SESSIONS];
+	u8 req_agg_queues;
+	u8 used_agg_queues;
+	bool is_stop_context;
+	struct workqueue_struct *drv_workqueue;
+	struct cl_amsdu_rx_state amsdu_rx_state;
+	struct cl_tx_queues *tx_queues;
+	struct kmem_cache *sw_txhdr_cache;
+	struct kmem_cache *amsdu_txhdr_cache;
+	u32 radio_stats[CL_RADIO_ERRORS_MAX];
+	struct cl_rx_path_info rx_info;
+	struct cl_prot_mode prot_mode;
+	struct cl_agg_cfm_queue agg_cfm_queues[IPC_MAX_BA_SESSIONS];
+	struct cl_single_cfm_queue single_cfm_queues[MAX_SINGLE_QUEUES];
+	struct cl_single_cfm_queue bcmc_cfm_queue;
+	atomic_t radio_lock;
+	struct cl_assoc_queue assoc_queue;
+	struct cl_wrs_db wrs_db;
+	struct cl_traffic_main traffic_db;
+	struct cl_power_db power_db;
+	struct cl_bf_db bf_db;
+	struct cl_edca_db edca_db;
+	struct cl_vns_db *vns_db;
+	struct cl_str_offload_env str_offload_env;
+	struct cl_dma_accessed fw_remote_rom;
+	struct cl_recovery_db recovery_db;
+	struct cl_radar_queue radar_queue;
+	struct tasklet_struct radar_tasklet;
+	struct cl_cached_fw cached_fw;
+	s8 rx_sensitivity[MAX_ANTENNAS];
+	struct cl_cca_db cca_db;
+	struct cl_noise_db noise_db;
+	struct cl_temp_comp_db temp_comp_db;
+	struct cl_sounding_db sounding;
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	struct cl_dyn_mcast_rate dyn_mcast_rate;
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	struct cl_dyn_bcast_rate dyn_bcast_rate;
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+	struct cl_dfs_db dfs_db;
+	struct cl_version_db version_db;
+	bool entry_fixed_rate;
+	unsigned long last_tbtt_irq;
+	u16 smallest_beacon_int;
+	u32 tbtt_cnt;
+	u8 mesh_tbtt_div;
+	struct tasklet_struct tx_mesh_bcn_task;
+	u32 fw_recovery_cntr;
+	u32 rx_filter;
+	ptrdiff_t mac_hw_regs_offset;
+	ptrdiff_t phy_regs_offset;
+	struct list_head head_amsdu_txhdr_pool;
+	struct list_head head_sw_txhdr_pool;
+	spinlock_t lock_sw_txhdr_pool;
+	struct sk_buff_head rx_remote_queue_mac;
+	struct sk_buff_head rx_skb_queue;
+	struct tasklet_struct rx_tasklet;
+	struct tasklet_struct rx_resched_tasklet;
+	u8 fem_mode;
+	struct cl_tx_packet_cntr tx_packet_cntr;
+	struct cl_cpu_cntr cpu_cntr;
+	struct cl_iq_dcoc_data_info iq_dcoc_data_info;
+	struct cl_power_table_info power_table_info;
+	struct ieee80211_sband_iftype_data iftype_data[3];
+	bool motion_sense_dbg;
+	struct cl_power_truncate pwr_trunc;
+	struct mutex set_channel_mutex;
+	u8 radio_status;
+	u8 rf_crystal_mhz;
+	bool iq_cal_ready;
+	s8 rssi_simulate;
+	struct mac_address addresses[MAX_BSS_NUM];
+	struct cl_rx_stats *rx_stats; /* RX statistics for production mode. */
+	spinlock_t lock_stats;
+	u16 n_addresses;
+	u8 txamsdu_en;
+	bool reg_dbg;
+	s32 new_tx_power;
+	struct cl_rx_trigger_based_stats *tb_stats;
+	struct cl_rx_trigger_based_sta_stats *tb_sta_stats;
+	bool idle_async_set;
+	bool msg_calib_timeout;
+	struct cl_calib_work *calib_work;
+	struct cl_chan_scanner *scanner;
+	bool calib_runtime_needed;
+	u8 ht40_preffered_ch_type;
+	u8 sw_scan_in_progress;
+};
+
+void cl_hw_init(struct cl_chip *chip, struct cl_hw *cl_hw, u8 tcv_idx);
+void cl_hw_deinit(struct cl_hw *cl_hw, u8 tcv_idx);
+struct cl_hw *cl_hw_other_tcv(struct cl_hw *cl_hw);
+bool cl_hw_is_tcv0(struct cl_hw *cl_hw);
+bool cl_hw_is_tcv1(struct cl_hw *cl_hw);
+bool cl_hw_is_first_tcv(struct cl_hw *cl_hw);
+int cl_hw_set_antennas(struct cl_hw *cl_hw);
+u8 cl_hw_ant_shift(struct cl_hw *cl_hw);
+u8 cl_hw_ant_to_riu_chain(struct cl_hw *cl_hw, u8 ant);
+u8 cl_hw_ant_mask_to_riu_chain_mask(struct cl_hw *cl_hw, u8 ant_mask);
+bool cl_hw_is_prod_or_listener(struct cl_hw *cl_hw);
+void cl_hw_assert_info_init(struct cl_hw *cl_hw);
+void cl_hw_assert_print(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg);
+void cl_hw_assert_check(struct cl_hw *cl_hw);
+
+static inline void cl_sta_lock_bh(struct cl_hw *cl_hw)
+{
+	read_lock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_unlock_bh(struct cl_hw *cl_hw)
+{
+	read_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_lock(struct cl_hw *cl_hw)
+{
+	read_lock(&cl_hw->cl_sta_db.lock);
+}
+
+static inline void cl_sta_unlock(struct cl_hw *cl_hw)
+{
+	read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+/* FW communication opses */
+static inline int cl_drv_ops_msg_fw_send(struct cl_hw *cl_hw,
+					 const void *msg_params,
+					 bool background)
+{
+	if (cl_hw->drv_ops->msg_fw_send)
+		return cl_hw->drv_ops->msg_fw_send(cl_hw, msg_params,
+						   background);
+	return 0;
+}
+
+static inline void cl_drv_ops_pkt_fw_send(struct cl_hw *cl_hw,
+					  struct cl_sw_txhdr *sw_txhdr,
+					  struct cl_tx_queue *tx_queue)
+{
+	if (cl_hw->drv_ops->pkt_fw_send)
+		cl_hw->drv_ops->pkt_fw_send(cl_hw, sw_txhdr, tx_queue);
+}
+
+#endif /* CL_HW_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 35/96] cl8k: add ipc_shared.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (33 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 34/96] cl8k: add hw.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
                   ` (60 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/ipc_shared.h | 1386 +++++++++++++++++
 1 file changed, 1386 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/ipc_shared.h

diff --git a/drivers/net/wireless/celeno/cl8k/ipc_shared.h b/drivers/net/wireless/celeno/cl8k/ipc_shared.h
new file mode 100644
index 000000000000..b8560bc632c7
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/ipc_shared.h
@@ -0,0 +1,1386 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_IPC_SHARED_H
+#define CL_IPC_SHARED_H
+
+#include <net/mac80211.h>
+
+#include "def.h"
+
+/** DOC: IPC - introduction
+ *
+ * IPC layer between the FW (XMAC -> LMAC, SMAC, UMAC) and the driver. Driver
+ * talks with lower layer via custom IPC messages and DMA. Basically, drv <->
+ * fw messages flow consists of %cl_fw_msg, that contains info about direction,
+ * message id (which is enum field of %mm_msg_tag or %dbg_msg_tag) and payload
+ * itself.
+ *
+ * Messages may be synchronous (with the confirmation feedback) and
+ * asynchronous. The latter is typically being used as inidication of
+ * occurrence of some event.
+ *
+ * Driver              LMAC/SMAC
+ *  +                     +
+ *  |       AA_REQ        |
+ *  |-------------------->|...+ (Request)
+ *  |       AA_CFM        |   | Mandatory control messages
+ *  |<--------------------|...+ (Confirmation)
+ *  |                     |
+ *  .       BB_IND        .
+ *  |<--------------------|... Asynchronous indication
+ *
+ *  Messages are using prelocated buffers and size limit of %IPC_RXBUF_SIZE.
+ *  Each message may have verification pattern, that allows to verify the
+ *  validity of payload. Most important TX/RX flow operations are tracked and
+ *  are reflected by stats change (like &cl_rx_path_info structure).
+ */
+
+/*
+ * Number of Host buffers available for Data Rx handling (through DMA)
+ * Must correspond to FW code definition, and must be power of 2.
+ */
+#define IPC_RXBUF_CNT_RXM 2048
+#define IPC_RXBUF_CNT_FW  128
+
+/* Bucket debug */
+#define IPC_RXBUF_BUCKET_POW_SIZE 5
+#define IPC_RXBUF_BUCKET_SIZE     BIT(IPC_RXBUF_BUCKET_POW_SIZE) /* 2 ^ 5 = 32 */
+#define IPC_RXBUF_NUM_BUCKETS_RXM (IPC_RXBUF_CNT_RXM / IPC_RXBUF_BUCKET_SIZE)
+#define IPC_RXBUF_NUM_BUCKETS_FW  (IPC_RXBUF_CNT_FW / IPC_RXBUF_BUCKET_SIZE)
+
+#define MU_MAX_STREAMS     8
+#define MU_MAX_SECONDARIES (MU_MAX_STREAMS - 1)
+
+#define CL_MU0_IDX 0
+#define CL_MU1_IDX 1
+#define CL_MU2_IDX 2
+#define CL_MU3_IDX 3
+#define CL_MU4_IDX 4
+#define CL_MU5_IDX 5
+#define CL_MU6_IDX 6
+#define CL_MU7_IDX 7
+#define CL_MU_IDX_MAX CL_MU7_IDX
+
+#define IPC_TX_QUEUE_CNT 5
+
+#define IPC_MAX_BA_SESSIONS 128
+
+#if IPC_MAX_BA_SESSIONS > CL_MAX_NUM_STA
+#define IPC_MAX_TIM_TX_OR_RX_AGG_SIZE IPC_MAX_BA_SESSIONS
+#else
+#define IPC_MAX_TIM_TX_OR_RX_AGG_SIZE CL_MAX_NUM_STA
+#endif
+
+#define IPC_QUEUE_IDX_DIFF_ARRAY_SIZE 6
+
+#define IPC_TIM_AGG_SIZE (IPC_MAX_TIM_TX_OR_RX_AGG_SIZE * 2)
+
+#define IPC_TX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(idx) ((idx) * 2)
+
+#define IPC_RX_QUEUE_IDX_TO_COMMON_QUEUE_IDX(idx) (((idx) * 2) + 1)
+
+#define CL_MAX_BA_PHYSICAL_QUEUE_CNT (AC_MAX + MU_MAX_SECONDARIES)
+#define CE_AC_MAX (IPC_TX_QUEUE_CNT + MU_MAX_SECONDARIES)
+
+enum {
+	AGG_AC0_IDX = AC_BK,
+	AGG_AC1_IDX = AC_BE,
+	AGG_AC2_IDX = AC_VI,
+	AGG_AC3_IDX = AC_VO,
+	AGG_MU1_IDX,
+	AGG_MU2_IDX,
+	AGG_MU3_IDX,
+	AGG_MU4_IDX,
+	AGG_MU5_IDX,
+	AGG_MU6_IDX,
+	AGG_MU7_IDX,
+	AGG_IDX_MAX,
+};
+
+#define DBG_DUMP_BUFFER_SIZE (1024 * 40)
+
+#define IPC_TXDESC_CNT_SINGLE 16
+#define IPC_TXDESC_CNT_BCMC   16
+
+/* Max count of Tx MSDU in A-MSDU */
+#define CL_AMSDU_TX_PAYLOAD_MAX 4
+
+#define TXDESC_AGG_Q_SIZE_MAX 512
+
+#define CL_MAX_AGG_IN_TXOP 20
+
+/* Keep LMAC & SMAC debug agg stats arrays size aligned */
+#define DBG_STATS_MAX_AGG_SIZE (256 + 1)
+
+/* Must be power of 2 */
+#define IPC_CFM_CNT 4096
+
+#define IPC_CFM_SIZE (IPC_CFM_CNT * sizeof(struct cl_ipc_cfm_msg))
+
+/* Number of rates in Policy table */
+#define CL_RATE_CONTROL_STEPS 4
+
+/*
+ * Stringified DRV/FW versions should be small enough to fit related ethtool
+ * descriptors size (32)
+ */
+#define CL_VERSION_STR_SIZE 32
+
+#if (IPC_CFM_CNT & (IPC_CFM_CNT - 1))
+#error "IPC_CFM_CNT Not a power of 2"
+#endif
+
+/*
+ * the calculation is conducted as follow:
+ * 1500 - max ethernet frame
+ * conversion of ETH to MSDU:
+ * 1500[eth max] - 12[hdr frame] + 14[msdu frame] + 8[llc snap] + 4[MSDU Padding] = 1514
+ * MSDU + WLAN HDR = 1514[MSDU MAX] + 36[MAX WLAN HDR] = 1550
+ * 2 bytes is being PADDED by SKB alloc for alignment.
+ * 18 byte encryption
+ * sizeof(struct hw_rxhdr)
+ */
+#define IPC_RXBUF_SIZE (1570 + sizeof(struct hw_rxhdr))
+
+/* Number of available host buffers */
+#define IPC_RADAR_BUF_CNT   32
+#define IPC_E2A_MSG_BUF_CNT 128
+#define IPC_DBG_BUF_CNT     64
+
+/* Length used in MSGs structures (size in 4-byte words) */
+#define IPC_A2E_MSG_BUF_SIZE   255
+#define IPC_E2A_MSG_PARAM_SIZE 63
+
+/* Debug messages buffers size (in bytes) */
+#define IPC_DBG_PARAM_SIZE 256
+
+/* Pattern indication for validity */
+#define IPC_RX_DMA_OVER_PATTERN   0xAAAAAA00
+#define IPC_E2A_MSG_VALID_PATTERN 0xADDEDE2A
+#define IPC_DBG_VALID_PATTERN     0x000CACA0
+#define IPC_EXCEPTION_PATTERN     0xDEADDEAD
+
+#define HB_POOL_DMA_DESCS_NUM 2
+
+/* Tensilica backtrace depth */
+#define IPC_BACKTRACT_DEPTH  5
+
+/* Maximum length of the SW diag trace */
+#define DBG_SW_DIAG_MAX_LEN  1024
+
+/* Maximum length of the error trace */
+#define DBG_ERROR_TRACE_SIZE 256
+
+/* Number of MAC diagnostic port banks */
+#define DBG_DIAGS_MAC_MAX    48
+
+/* Driver mem size used for THDs PTs & PBDs */
+#define DBG_THD_CHAINS_INFO_THD_CNT 5
+#define DBG_THD_CHAINS_INFO_PBD_CNT 9
+#define DBG_THD_CHAINS_INFO_PT_CNT  1
+#define DBG_THD_CHAINS_INFO_ARRAY_SIZE \
+	((DBG_THD_CHAINS_INFO_THD_CNT * sizeof(struct tx_hd)) + \
+	 (DBG_THD_CHAINS_INFO_PBD_CNT * sizeof(struct tx_pbd)) + \
+	 (DBG_THD_CHAINS_INFO_PT_CNT * sizeof(struct tx_policy_tbl)))
+
+#define DBG_CHAINS_INFO_ELEM_CNT 10
+
+/* Txl chain info - per ac */
+#define DBG_TXL_FRAME_EXCH_TRACE_DEPTH 5
+
+/* FW debug trace size */
+#define DBG_FW_TRACE_SIZE    30
+#define DBG_FW_TRACE_STR_MAX 20
+
+/* Number of embedded logic analyzers */
+#define LA_CNT               1
+
+/* Length of the configuration data of a logic analyzer */
+#define LA_CONF_LEN          102
+
+/* Structure containing the configuration data of a logic analyzer */
+struct la_conf_tag {
+	u32 conf[LA_CONF_LEN];
+};
+
+/* Size of a logic analyzer memory */
+#define LA_MEM_LEN (256 * 1024)
+
+/* Message structure for MSGs from Emb to App */
+struct cl_ipc_e2a_msg {
+	__le16 id;
+	__le16 dummy_dest_id;
+	__le16 dummy_src_id;
+	__le16 param_len;
+	u32 param[IPC_E2A_MSG_PARAM_SIZE];
+	__le32 pattern;
+};
+
+enum rx_buf_type {
+	CL_RX_BUF_RXM,
+	CL_RX_BUF_FW,
+	CL_RX_BUF_MAX
+};
+
+/*
+ * Structs & function  associated with HW & SW debug data
+ * The Debug information forwarded to host when an error occurs, and printed to stdout
+ * This data must be consistent with firmware, any new debug data should exist also in
+ * firmware side
+ */
+
+struct tx_hd {
+	u32 upatterntx;
+	u32 nextfrmexseq_ptr;
+	u32 nextmpdudesc_ptr;
+	u32 first_pbd_ptr;
+	u32 datastartptr;
+	u32 dataendptr;
+	u32 frmlen;
+	u32 spacinginfo;
+	u32 phyctrlinfo1;
+	u32 policyentryaddr;
+	u32 bar_thd_desc_ptr;
+	u32 reserved1;
+	u32 macctrlinfo1;
+	u32 macctrlinfo2;
+	u32 statinfo;
+	u32 phyctrlinfo2;
+};
+
+struct tx_policy_tbl {
+	u32 upatterntx;
+	u32 phycntrlinfo1;
+	u32 phycntrlinfo2;
+	u32 maccntrlinfo1;
+	u32 maccntrlinfo2;
+	u32 ratecntrlinfo[CL_RATE_CONTROL_STEPS];
+	u32 phycntrlinfo3;
+	u32 phycntrlinfo4;
+	u32 phycntrlinfo5;
+	u32 stationinfo;
+	u32 ratecntrlinfohe[CL_RATE_CONTROL_STEPS];
+	u32 maccntrlinfo3;
+	u32 triggercommoninfo;
+	u32 triggerinforuallocationu0u3;
+	u32 triggerinforuallocationu4u7;
+	u32 triggerperuserinfo[MU_MAX_STREAMS];
+};
+
+struct tx_pbd {
+	u32 upatterntx;
+	u32 next;
+	u32 datastartptr;
+	u32 dataendptr;
+	u32 bufctrlinfo;
+};
+
+enum cl_macfw_dbg_severity {
+	CL_MACFW_DBG_SEV_NONE,
+	CL_MACFW_DBG_SEV_ERROR,
+	CL_MACFW_DBG_SEV_WARNING,
+	CL_MACFW_DBG_SEV_INFO,
+	CL_MACFW_DBG_SEV_VERBOSE,
+
+	CL_MACFW_DBG_SEV_MAX
+};
+
+struct phy_channel_info {
+	__le32 info1;
+	__le32 info2;
+};
+
+struct dbg_debug_info_tag {
+	u32 error_type; /* (0: recoverable, 1: fatal) */
+	u32 hw_diag;
+	char error[DBG_ERROR_TRACE_SIZE];
+	u32 sw_diag_len;
+	char sw_diag[DBG_SW_DIAG_MAX_LEN];
+	struct phy_channel_info chan_info;
+	struct la_conf_tag la_conf[LA_CNT];
+	u16 diags_mac[DBG_DIAGS_MAC_MAX];
+};
+
+/*
+ * Defines, enums and structs below are used at TX statistics
+ * structure.
+ * Because of the TX statistics structure should be same at
+ * host and at firmware,the change of these parameters requires
+ * similar firmware changes
+ */
+
+struct cl_txl_ba_statistics {
+	u32 total_cnt;
+	u32 total_rtx_cnt;
+	u16 total_ba_received;
+	u16 total_ba_not_received_cnt;
+	u16 total_lifetime_expired_cnt;
+	u16 total_rtx_limit_reached;
+	u16 total_packets_below_baw;
+	u16 total_packets_above_baw;
+	u16 total_ba_not_received_cnt_ps;
+	u16 total_cleard_ba;
+	u16 total_unexpected_ba;
+	u16 total_invalid_ba;
+	u16 total_ack_instead_ba;
+};
+
+struct cl_txl_single_statistics {
+	u32 total_cnt;
+	u32 total_rtx_cnt;
+	u16 total_lifetime_expired_cnt;
+	u16 total_rtx_limit_reached;
+	u16 total_rtx_limit_reached_ps;
+};
+
+enum {
+	CE_BACKOFF_25,
+	CE_BACKOFF_50,
+	CE_BACKOFF_100,
+	CE_BACKOFF_500,
+	CE_BACKOFF_1000,
+	CE_BACKOFF_5000,
+	CE_BACKOFF_10000,
+	CE_BACKOFF_20000,
+	CE_BACKOFF_20000_ABOVE,
+	CE_BACKOFF_MAX
+};
+
+struct cl_txl_backoff_statistics {
+	u32 chain_time;
+	u32 backoff_hist[CE_BACKOFF_MAX];
+};
+
+struct cl_txl_tid_statistics {
+	u32 total_tid_desc_cnt;
+};
+
+/* Natt closed an aggregation due to one of the bellow reasons. */
+enum {
+	NATT_REASON_MAX_LEN    = 0x1,
+	NATT_REASON_TXOP_LIMIT = 0x2,
+	NATT_REASON_MPDU_NUM   = 0x4,
+	NATT_REASON_LAST_BIT   = 0x8,
+	NATT_REASON_MAX
+};
+
+/* Tx BW */
+enum {
+	NATT_BW_20,
+	NATT_BW_40,
+	NATT_BW_80,
+	NATT_BW_160,
+	NATT_BW_MAX
+};
+
+struct cl_txl_natt_statistics {
+	u32 agg_close_reason[NATT_REASON_MAX];
+	u32 chosen_frame_bw[NATT_BW_MAX];
+	u32 operation_mode[8];
+};
+
+enum {
+	AGG_IN_TXOP_CLOSE_REASON_NO_TXDESC,
+	AGG_IN_TXOP_CLOSE_REASON_TXOP_EXPIRED,
+	AGG_IN_TXOP_CLOSE_REASON_ACTIVE_DELBA,
+	AGG_IN_TXOP_CLOSE_REASON_MAX
+};
+
+struct amsdu_stat {
+	u16 packet_cnt_2;
+	u16 packet_cnt_3;
+	u16 packet_cnt_4;
+	u16 packet_cnt_5_or_more;
+};
+
+struct cl_txl_mu_statistics {
+	u16 chain_cnt;
+	u16 status_cnt;
+	u16 ba_received;
+	u16 ba_no_received;
+	u16 clear_ba;
+	u16 correct_ba;
+	u16 unexpected_ba;
+	u16 invalid_ba;
+};
+
+struct cl_txl_agg_statistics {
+	u16 agg_size_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u32 packet_failed_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u32 packet_passed_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u16 htp_agg_size_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u32 htp_packet_failed_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u32 htp_packet_passed_statistics[DBG_STATS_MAX_AGG_SIZE];
+	u16 agg_in_txop_statistics[CL_MAX_AGG_IN_TXOP];
+	u16 agg_in_txop_close_reason[AGG_IN_TXOP_CLOSE_REASON_MAX];
+	u16 agg_in_txop_queue_switch;
+	u16 agg_in_txop_queue_switch_abort_bw;
+	struct amsdu_stat amsdu_stat[IPC_MAX_BA_SESSIONS];
+	u16 mu_agg_size_statistics[MU_MAX_STREAMS][DBG_STATS_MAX_AGG_SIZE];
+	struct cl_txl_mu_statistics mu_stats[MU_MAX_STREAMS];
+};
+
+struct cl_txl_ac_statistics {
+	u32 total_q_switch_cnt;
+	u32 total_ac_desc_cnt;
+};
+
+struct cl_txl_underrun_statistics {
+	u16 length_cnt;
+	u16 pattern_cnt;
+	u16 flushed_frames_cnt;
+};
+
+struct cl_txl_rts_cts_statistics {
+	u32 fw_rts_cnt;
+	u32 fw_rts_retry_cnt;
+	u32 fw_rts_retry_limit_cnt;
+	u32 hw_rts_cnt;
+	u32 fw_cts_cnt;
+	u32 hw_cts_cnt;
+};
+
+struct cl_txl_backoff_params {
+	u32 singelton_total[AC_MAX];
+	u32 singelton_cnt[AC_MAX];
+	u32 agg_total[AC_MAX];
+	u32 agg_cnt[AC_MAX];
+};
+
+struct cl_txl_htp_statistics {
+	u32 total_cnt[TID_MAX];
+	u32 need_response;
+	u32 tb_response_required;
+	u32 ac_not_found;
+	u32 end_of_packet_int;
+	u32 tb_bw_decision;
+	u32 tb_ba_thd_removed;
+	u32 tb_ac_unchain;
+	u32 tb_htp_unchain;
+	u32 tb_dummy_htp_tx;
+	u32 tb_dummy_no_tx;
+	u32 msta_ba_received;
+	u32 msta_ba_aid_not_found;
+	u32 uora_cnt_trigger_frame_tx;
+	u32 uora_cnt_trigger_frame_rx;
+	u32 uora_cnt_probe_req_tx;
+	u32 uora_cnt_probe_req_rx;
+};
+
+struct cl_txl_vns_statistics {
+	u32 off_he;
+	u32 off_ht_vht;
+	u32 off_ofdm;
+	u32 off_cck;
+	u32 on_he;
+	u32 on_ht_vht;
+	u32 on_ofdm;
+	u32 on_cck;
+};
+
+struct cl_txl_fec_statistics {
+	u32 ldpc;
+	u32 bcc;
+};
+
+struct cl_txl_mu_desision_statistics {
+	u32 num_sta_in_mu_group[MU_MAX_STREAMS];
+	u32 mu_tx_active;
+	u32 prim_not_in_mu_group;
+	u32 prim_rate_invalid;
+	u32 other_reason;
+	u32 total_num_su;
+	u32 is_2nd_rate_invalid;
+	u32 is_2nd_awake;
+	u32 is_2nd_enouhg_data;
+};
+
+struct cl_txl_statistics {
+	u32 type; /* This field should be first in the struct */
+	u32 recovery_count;
+	u32 tx_obtain_bw_fail_cnt;
+	struct cl_txl_single_statistics single[IPC_TX_QUEUE_CNT];
+	struct cl_txl_ba_statistics ba[IPC_MAX_BA_SESSIONS];
+	struct cl_txl_backoff_statistics backoff_stats[AC_MAX];
+	struct cl_txl_natt_statistics natt;
+	struct cl_txl_tid_statistics tid[TID_MAX];
+	struct cl_txl_agg_statistics agg;
+	struct cl_txl_ac_statistics ac[CE_AC_MAX];
+	struct cl_txl_underrun_statistics underrun;
+	struct cl_txl_rts_cts_statistics rts_cts;
+	struct cl_txl_backoff_params backoff_params;
+	struct cl_txl_htp_statistics htp;
+	struct cl_txl_vns_statistics vns;
+	struct cl_txl_fec_statistics fec;
+	struct cl_txl_mu_desision_statistics mu_desision;
+};
+
+/* Flushed beacon list options */
+enum {
+	BCN_FLUSH_PENDING,
+	BCN_FLUSH_DOWNLOADING,
+	BCN_FLUSH_TRANSMITTING,
+	BCN_FLUSH_MAX,
+};
+
+struct bcn_backup_stats {
+	u32 bcn_backup_used_cnt;
+	u32 bcn_backup_tx_cnt;
+	u32 bcn_backup_flushed_cnt;
+	u32 bcn_backup_used_in_arow_cnt;
+	u32 bcn_backup_max_used_in_arow_cnt;
+};
+
+struct beacon_timing {
+	/* Time measurements between beacons */
+	u32 last_bcn_start_time;
+	u32 max_time_from_last_bcn;
+	u32 min_time_from_last_bcn;
+	u32 total_bcn_time;
+	/* Time measurements until beacon chained */
+	u32 imp_tbtt_start_time;
+	u32 bcn_chain_total_time;
+	u32 bcn_chain_max_time;
+	u32 bcn_chain_min_time;
+	/* Time measurements until received beacon from host */
+	u32 bcn_last_request_time;
+	u32 max_bcn_time_until_get_beacon_from_driver_in_tbtt;
+	u32 bcn_last_req_rec_time;
+	/* Time measurements of bcn from pending to chain */
+	u32 bcn_push_pending_start_time;
+	u32 bcn_pending_2_chain_max_time;
+};
+
+struct beacon_counters {
+	u32 bcn_time_from_driver_not_in_threshold_cnt;
+	u32 nof_time_intervals_between_beacons;
+	u32 total_cnt;
+	u32 bcn_chain_total_cnt;
+	u32 ce_txl_flushed_beacons[BCN_FLUSH_MAX];
+	u32 pending2chain_not_in_threshold_cnt;
+	u32 total_beacons_received_from_driver;
+};
+
+struct cl_bcn_statistics {
+	u32 type; /* This field should be first in the struct */
+	struct beacon_counters beacon_counters;
+	struct beacon_timing beacon_timing;
+	struct bcn_backup_stats bcn_backup_stats;
+};
+
+struct cl_queue_idx_dif_stats {
+	u32 type; /* This field should be first in the struct */
+	u32 diff_array_count[IPC_QUEUE_IDX_DIFF_ARRAY_SIZE];
+	u32 last_diff;
+	u32 wr_idx;
+	u32 rd_idx;
+};
+
+enum agg_tx_rate_drop_reason {
+	AGG_TX_RATE_DROP_MAX_BA_NOT_RECEIVED_REACHED,
+	AGG_TX_RATE_DROP_MAX_BA_PER_REACHED,
+	AGG_TX_RATE_DROP_MAX_RETRY_REACHED,
+	AGG_TX_RATE_DROP_MAX,
+};
+
+struct cl_rate_drop_statistics {
+	u32 type;
+	u32 drop_reason[AGG_TX_RATE_DROP_MAX];
+};
+
+#define BF_DB_MAX 16
+
+enum bfr_rx_err {
+	BFR_RX_ERR_BW_MISMATCH,
+	BFR_RX_ERR_NSS_MISMATCH,
+	BFR_RX_ERR_SOUNDING_CHBW,
+	BFR_RX_ERR_TOKEN_MISMATCH,
+	BFR_RX_ERR_NDP_DROP,
+	BFR_SEGMENTED_DROP,
+	BFR_RX_ERR_MISS_ACK,
+	BFR_RX_ERR_RESOURCE_NA,
+	BFR_RX_ERR_MAX
+};
+
+enum TX_BF_DATA_STAT {
+	TX_BF_DATA_OK = 0,
+	TX_BF_DATA_BUFFERED_RESOURCE_ERR,
+	TX_BF_DATA_RELEASED_RESOURCE_ERR,
+	TX_BF_DATA_BUFFERED_PS_STA,
+	TX_BF_DATA_RELEASED_PS_STA,
+	TX_BF_DATA_ERR_BFR_MISS,
+	TX_BF_DATA_ERR_BFR_OUTDATED,
+	TX_BF_DATA_ERR_MISMATCH_BW,
+	TX_BF_DATA_ERR_MISMATCH_NSS,
+	TX_BF_DATA_ERR_MAX
+};
+
+struct bf_ctrl_dbg {
+	u16 ndp_cnt;
+	u16 bfp_cnt;
+	u16 su_bfr_cnt;
+	u16 mu_bfr_cnt;
+	u16 bf_invalid_cnt[BFR_RX_ERR_MAX];
+	u16 tx_bf_data_err[TX_BF_DATA_ERR_MAX];
+};
+
+struct bf_stats_database {
+	bool is_active_list;
+	struct bf_ctrl_dbg dbg;
+	u8 sta_idx;
+	u16 active_dsp_idx;
+	u16 passive_dsp_idx;
+};
+
+struct cl_bf_statistics {
+	u32 type;
+	bool print_active_free_list;
+	struct bf_stats_database stats_data[BF_DB_MAX];
+};
+
+enum amsdu_deaggregation_err {
+	AMSDU_DEAGGREGATION_ERR_MAX_MSDU_REACH,
+	AMSDU_DEAGGREGATION_ERR_MSDU_GT_AMSDU_LEN,
+	AMSDU_DEAGGREGATION_ERR_MSDU_LEN,
+	AMSDU_ENCRYPTION_KEY_GET_ERR,
+
+	AMSDU_DEAGGREGATION_ERR_MAX
+};
+
+enum emb_ll1_handled_frm_type {
+	BA_FRM_TYPE,
+	NDPA_FRM_TYPE,
+	NDP_FRM_TYPE,
+	ACTION_NO_ACK_FRM_TYPE,
+
+	MAX_HANDLED_FRM_TYPE
+};
+
+enum rhd_decr_idx {
+	RHD_DECR_UNENC_IDX,
+	RHD_DECR_ICVFAIL_IDX,
+	RHD_DECR_CCMPFAIL_IDX,
+	RHD_DECR_AMSDUDISCARD_IDX,
+	RHD_DECR_NULLKEY_IDX,
+	RHD_DECR_IDX_MAX
+};
+
+#define RX_CLASSIFICATION_MAX 6
+#define FREQ_OFFSET_TABLE_IDX_MAX 8 /* Must be a power of 2 */
+#define RX_MAX_MSDU_IN_SINGLE_AMSDU 16
+
+struct cl_rxl_statistics {
+	u32 type; /* This field should be first in the struct */
+	u32 rx_imp_bf_counter[MU_UL_MAX];
+	u32 rx_imp_bf_int_counter[MU_UL_MAX];
+	u32 rx_class_counter[MU_UL_MAX][RX_CLASSIFICATION_MAX];
+	u32 rx_class_int_counter[MU_UL_MAX];
+	u32 counter_timer_trigger_ll1[MU_UL_MAX];
+	u32 counter_timer_trigger_ll2[MU_UL_MAX];
+	u32 total_rx_packets[MU_UL_MAX];
+	u32 total_agg_packets[MU_UL_MAX];
+	u32 rx_fifo_overflow_err_cnt[MU_UL_MAX];
+	u32 rx_dma_discard_cnt;
+	u32 host_rxelem_not_ready_cnt;
+	u32 msdu_host_rxelem_not_ready_cnt;
+	u32 dma_rx_pool_not_ready_cnt;
+	u32 rx_pckt_exceed_max_len_cnt[MU_UL_MAX];
+	u32 rx_pckt_bad_ba_statinfo_cnt[MU_UL_MAX];
+	u32 nav_value[MU_UL_MAX];
+	u16 max_mpdu_data_len[MU_UL_MAX];
+	u8 rhd_ll2_max_cnt[MU_UL_MAX]; /* Rhd first list */
+	u8 rhd_ll1_max_cnt[MU_UL_MAX]; /* Rhd second list */
+	u8 cca_busy_percent;
+	u8 rx_mine_busy_percent;
+	u8 tx_mine_busy_percent;
+	u8 sample_cnt;
+	/* Emb handled frames */
+	u32 emb_ll1_handled_frame_counter[MU_UL_MAX][MAX_HANDLED_FRM_TYPE];
+	u32 rxm_stats_overflow[MU_UL_MAX];
+	/* RX AMSDU statistics counters */
+	u32 stats_tot_rx_amsdu_cnt[MU_UL_MAX];
+	u32 stats_rx_amsdu_cnt[MU_UL_MAX][RX_MAX_MSDU_IN_SINGLE_AMSDU];
+	u32 stats_rx_amsdu_err[MU_UL_MAX][AMSDU_DEAGGREGATION_ERR_MAX];
+	u32 stats_rx_format[FORMATMOD_MAX];
+	/* RX decryption error */
+	u32 decrypt_err[RHD_DECR_IDX_MAX];
+	u32 rx_incorrect_format_mode[MU_UL_MAX];
+	u32 fcs_error_counter[MU_UL_MAX];
+	u32 phy_error_counter[MU_UL_MAX];
+	u32 ampdu_received_counter[MU_UL_MAX];
+	u32 delimiter_error_counter[MU_UL_MAX];
+	u32 ampdu_incorrect_received_counter[MU_UL_MAX];
+	u32 correct_received_mpdu[MU_UL_MAX];
+	u32 incorrect_received_mpdu[MU_UL_MAX];
+	u32 discarded_mpdu[MU_UL_MAX];
+	u32 incorrect_delimiter[MU_UL_MAX];
+	u32 rxm_mpdu_cnt[MU_UL_MAX];
+	u32 rxm_rule0_match[MU_UL_MAX];
+	u32 rxm_rule1_match[MU_UL_MAX];
+	u32 rxm_rule2_match[MU_UL_MAX];
+	u32 rxm_rule3_match[MU_UL_MAX];
+	u32 rxm_rule4_match[MU_UL_MAX];
+	u32 rxm_rule5_match[MU_UL_MAX];
+	u32 rxm_rule6_match[MU_UL_MAX];
+	u32 rxm_default_rule_match[MU_UL_MAX];
+	u32 rxm_amsdu_1[MU_UL_MAX];
+	u32 rxm_amsdu_2[MU_UL_MAX];
+	u32 rxm_amsdu_3[MU_UL_MAX];
+	u32 rxm_amsdu_4[MU_UL_MAX];
+	u32 rxm_amsdu_5_15[MU_UL_MAX];
+	u32 rxm_amsdu_16_or_more[MU_UL_MAX];
+	u32 frequency_offset[FREQ_OFFSET_TABLE_IDX_MAX];
+	u32 frequency_offset_idx;
+	u32 rts_bar_cnt[MU_UL_MAX];
+};
+
+enum trigger_flow_single_trigger_type {
+	TRIGGER_FLOW_BASIC_TRIGGER_TYPE,
+	TRIGGER_FLOW_BSRP_TYPE,
+	TRIGGER_FLOW_BFRP_TYPE,
+	TRIGGER_FLOW_MAX
+};
+
+struct cl_trigger_flow_statistics {
+	u32 type; /* This field should be first in the struct */
+	u32 single_trigger_sent[TRIGGER_FLOW_MAX][AC_MAX];
+	u32 htp_rx_failure[AC_MAX];
+	u32 trigger_based_mpdu[MU_UL_MAX];
+};
+
+#define DYN_CAL_DEBUG_NUM_ITER  3
+
+struct dyn_cal_debug_info_t {
+	u16 calib_num;
+	u8 curr_config;
+	union {
+		struct {
+			u8 iter_num;
+			u32 measured_val;
+		};
+		struct {
+			u8 min_config;
+			u32 dyn_cal_min_val;
+			u32 dyn_cal_max_val;
+			u8 max_config;
+		};
+	};
+
+	u8 new_config;
+};
+
+struct cl_dyn_calib_statistics {
+	u32 type; /* This field should be first in the struct */
+	u8 is_multi_client_mode;
+	u8 default_dyn_cal_val;
+	u8 dyn_cal_debug_info_ix;
+	u16 dyn_cal_process_cnt;
+	u16 mac_phy_sync_err_cnt;
+	struct dyn_cal_debug_info_t dyn_cal_debug_info[DYN_CAL_DEBUG_NUM_ITER];
+};
+
+/* End of parameters that require host changes */
+
+/* Structure containing the parameters for assert prints DBG_PRINT_IND message. */
+struct dbg_print_ind {
+	__le16 file_id;
+	__le16 line;
+	__le16 has_param;
+	u8 err_no_dump;
+	u8 reserved;
+	__le32 param;
+};
+
+/* 4 ACs + BCN + HTP + current THD */
+#define MACHW_THD_REGS_CNT (IPC_TX_QUEUE_CNT + 2)
+
+/* Enumeration of MAC-HW registers (debug dump at recovery event) */
+enum {
+	HAL_MACHW_AGGR_STATUS,
+	HAL_MACHW_DEBUG_HWSM_1,
+	HAL_MACHW_DEBUG_HWSM_2,
+	HAL_MACHW_DEBUG_HWSM_3,
+	HAL_MACHW_DMA_STATUS_1,
+	HAL_MACHW_DMA_STATUS_2,
+	HAL_MACHW_DMA_STATUS_3,
+	HAL_MACHW_DMA_STATUS_4,
+	HAL_MACHW_RX_HEADER_H_PTR,
+	HAL_MACHW_RX_PAYLOAD_H_PTR,
+	HAL_MACHW_DEBUG_BCN_S_PTR,
+	HAL_MACHW_DEBUG_AC0_S_PTR,
+	HAL_MACHW_DEBUG_AC1_S_PTR,
+	HAL_MACHW_DEBUG_AC2_S_PTR,
+	HAL_MACHW_DEBUG_AC3_S_PTR,
+	HAL_MACHW_DEBUG_HTP_S_PTR,
+	HAL_MACHW_DEBUG_TX_C_PTR,
+	HAL_MACHW_DEBUG_RX_HDR_C_PTR,
+	HAL_MACHW_DEBUG_RX_PAY_C_PTR,
+	HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_1,
+	HAL_MACHW_MU0_TX_POWER_LEVEL_DELTA_2,
+	HAL_MACHW_POWER_BW_CALIB_FACTOR,
+	HAL_MACHW_TX_POWER_ANTENNA_FACTOR_1_ADDR,
+	HAL_MACHW_TX_POWER_ANTENNA_FACTOR_2_ADDR,
+	/* Keep this entry last */
+	HAL_MACHW_REG_NUM
+};
+
+#define HAL_MACHW_FSM_REG_NUM ((HAL_MACHW_DEBUG_HWSM_3 - HAL_MACHW_AGGR_STATUS) + 1)
+
+enum {
+	MPU_COMMON_FORMAT,
+	MPU_COMMON_FIELD_CTRL,
+	MPU_COMMON_LEGACY_INFO,
+	MPU_COMMON_COMMON_CFG_1,
+	MPU_COMMON_COMMON_CFG_2,
+	MPU_COMMON_COMMON_CFG_3,
+	MPU_COMMON_HE_CFG_1,
+	MPU_COMMON_HE_CFG_2,
+	MPU_COMMON_INT_STAT_RAW,
+	RIU_CCAGENSTAT,
+	PHY_HW_DBG_REGS_CNT
+};
+
+/* Error trace CE_AC info */
+struct dbg_ac_info {
+	u8 chk_state;
+	u8 tx_path_state;
+	u8 physical_queue_idx;
+	u16 active_session;
+	u32 last_frame_exch_ptr;
+};
+
+/* Error trace txdesc lists info */
+struct dbg_txlist_info {
+	u8 curr_session_idx;
+	u8 next_session_idx;
+	u16 pending_cnt;
+	u16 download_cnt;
+	u16 transmit_cnt;
+	u16 wait_for_ba_cnt;
+	u16 next_pending_cnt;
+};
+
+/* Txl chain info */
+struct dbg_txl_chain_info {
+	u32 count;
+	u32 frm_type;
+	u32 first_thd_ptr;
+	u32 last_thd_ptr;
+	u32 prev_thd_ptr;
+	u32 req_phy_flags;
+	u8 reqbw;
+	u8 ce_txq_idx;
+	u16 mpdu_count;
+	u8 chbw;
+	u32 rate_ctrl_info;
+	u32 rate_ctrl_info_he;
+	u32 txstatus;
+	u32 length;
+	u32 tx_time;
+};
+
+struct dbg_txl_ac_chain_trace {
+	struct dbg_txl_chain_info data[DBG_TXL_FRAME_EXCH_TRACE_DEPTH];
+	u32 count;
+	u8 next_chain_index;
+	u8 next_done_index;
+	u8 delta;
+};
+
+struct dbg_fw_trace {
+	u32 string_ptr;
+	u32 var_1;
+	u32 var_2;
+	u32 var_3;
+	u32 var_4;
+	u32 var_5;
+	u32 var_6;
+	/*
+	 * This field is used only for driver pring dump file.
+	 * collect string char is done at error dump collect data function.
+	 */
+	char string_char[DBG_FW_TRACE_STR_MAX];
+};
+
+/* Error trace MAC-FW info */
+struct dbg_fw_info {
+	struct dbg_ac_info ac_info[CE_AC_MAX];
+	struct dbg_txlist_info txlist_info_singles[IPC_TX_QUEUE_CNT];
+	struct dbg_txlist_info txlist_info_agg[AGG_IDX_MAX];
+	struct dbg_txl_ac_chain_trace txl_ac_chain_trace[CE_AC_MAX];
+	struct dbg_fw_trace fw_trace[DBG_FW_TRACE_SIZE];
+	u32 fw_trace_idx;
+};
+
+/* TXM regs */
+struct dbg_txm_regs {
+	u8 hw_state;
+	u8 fw_state;
+	u8 spx_state;
+	u8 free_buf_state;
+	u8 mpdu_cnt;
+	u8 lli_cnt;
+	u8 lli_done_reason;
+	u8 lli_done_mpdu_num;
+	u16 active_bytes;
+	u16 prefetch_bytes;
+	u32 last_thd_done_addr;
+	u16 last_thd_done_mpdu_num;
+	u16 underrun_cnt;
+};
+
+/* Error trace HW registers */
+struct dbg_hw_reg_info {
+	u32 mac_hw_reg[HAL_MACHW_REG_NUM];
+	u32 mac_hw_sec_fsm[CL_MU_IDX_MAX][HAL_MACHW_FSM_REG_NUM];
+	u32 phy_mpu_hw_reg[PHY_HW_DBG_REGS_CNT];
+	struct dbg_txm_regs txm_regs[AGG_IDX_MAX];
+};
+
+struct dbg_meta_data {
+	__le32 lmac_req_buf_size;
+	u8 physical_queue_cnt;
+	u8 agg_index_max;
+	u8 ce_ac_max;
+	u8 mu_user_max;
+	u8 txl_exch_trace_depth;
+	__le16 mac_hw_regs_max;
+	__le16 phy_hw_regs_max;
+	__le16 thd_chains_data_size;
+	u8 chains_info_elem_cnt;
+};
+
+struct dbg_agg_thds_addr {
+	u32 rts_cts_thd_addr;
+	u32 athd_addr;
+	u32 tf_thd_addr;
+	u32 bar_thd_addr;
+	u32 policy_table_addr;
+};
+
+struct dbg_agg_thd_info {
+	struct tx_hd rts_cts_thd;
+	struct tx_hd athd;
+	struct tx_hd tf_thd;
+	struct tx_hd bar_thd;
+	struct tx_policy_tbl policy_table;
+};
+
+struct dbg_machw_regs_thd_info {
+	struct tx_hd thd[MACHW_THD_REGS_CNT];
+};
+
+struct dbg_thd_chains_info {
+	u8 type_array[DBG_CHAINS_INFO_ELEM_CNT];
+	u32 elem_address[DBG_CHAINS_INFO_ELEM_CNT];
+};
+
+struct dbg_thd_chains_data {
+	u8 data[DBG_THD_CHAINS_INFO_ARRAY_SIZE];
+};
+
+/* Error trace debug structure. common to fw & drv */
+struct dbg_error_trace_info_common {
+	struct dbg_print_ind error_info;
+	struct dbg_meta_data dbg_metadata;
+	struct dbg_hw_reg_info hw_info;
+	struct dbg_fw_info fw_info;
+	struct dbg_agg_thds_addr agg_thds_addr[AGG_IDX_MAX];
+};
+
+/* Dbg error info driver side */
+struct dbg_error_trace_info_drv {
+	struct dbg_error_trace_info_common common_info;
+	struct dbg_agg_thd_info agg_thd_info[AGG_IDX_MAX];
+	struct dbg_machw_regs_thd_info machw_thd_info;
+	struct dbg_thd_chains_info thd_chains_info[CE_AC_MAX];
+	struct dbg_thd_chains_data thd_chains_data[CE_AC_MAX];
+};
+
+/*
+ * This is the main debug struct, the kernel allocate the needed spaces using kmalloc().
+ * the firmware holds a pointer to this struct.
+ */
+struct dbg_dump_info {
+	u32 dbg_info; /* Should be first member in the struct */
+	/* Dump data transferred to host */
+	struct dbg_debug_info_tag general_data;
+	struct dbg_error_trace_info_drv fw_dump;
+	u8 la_mem[LA_CNT][LA_MEM_LEN];
+};
+
+struct dbg_info {
+	union {
+		u32 type;
+		struct cl_txl_statistics tx_stats;
+		struct cl_bcn_statistics bcn_stats;
+		struct cl_rxl_statistics rx_stats;
+		struct cl_dyn_calib_statistics dyn_calib_stats;
+		struct cl_rate_drop_statistics rate_drop_stats;
+		struct cl_bf_statistics bf_stats;
+		struct cl_trigger_flow_statistics trigger_flow_stats;
+		struct cl_queue_idx_dif_stats txdesc_idx_diff_stats;
+		struct dbg_dump_info dump;
+	} u;
+};
+
+/* Structure of a list element header */
+struct co_list_hdr {
+	__le32 next;
+};
+
+/* ETH2WLAN and NATT common parameters field (e2w_natt_param) struct definition: */
+struct cl_e2w_natt_param {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	u32 valid           : 1,  /* [0] */
+	    ampdu           : 1,  /* [1] */
+	    last_mpdu       : 1,  /* [2] */
+	    lc_snap         : 1,  /* [3] */
+	    vlan            : 1,  /* [4] */
+	    amsdu           : 1,  /* [5] */
+	    e2w_band_id     : 1,  /* [6] */
+	    use_local_addr  : 1,  /* [7] */
+	    hdr_conv_enable : 1,  /* [8] */
+	    sta_index       : 7,  /* [9:15] */
+	    packet_length   : 15, /* [30:16] */
+	    e2w_int_enable  : 1;  /* [31] */
+#else /* __BIG_ENDIAN_BITFIELD */
+	u32 e2w_int_enable  : 1,  /* [0] */
+	    packet_length   : 15, /* [15:1] */
+	    sta_index       : 7,  /* [22:16] */
+	    hdr_conv_enable : 1,  /* [23] */
+	    use_local_addr  : 1,  /* [24] */
+	    e2w_band_id     : 1,  /* [25] */
+	    amsdu           : 1,  /* [26] */
+	    vlan            : 1,  /* [27] */
+	    llc_snap        : 1,  /* [28] */
+	    last_mpdu       : 1,  /* [29] */
+	    ampdu           : 1,  /* [30] */
+	    valid           : 1;  /* [31] */
+#endif
+};
+
+#define CL_CCMP_GCMP_PN_SIZE 6
+
+struct cl_e2w_txhdr_param {
+	__le16 frame_ctrl;
+	__le16 seq_ctrl;
+	__le32 ht_ctrl;
+	u8 encrypt_pn[CL_CCMP_GCMP_PN_SIZE];
+	__le16 qos_ctrl;
+};
+
+/* Bit 16 Has different usage for single (valid sta - set by host) or agg (tx done - set by HW) */
+struct cl_e2w_result {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	u32 backup_bcn                        : 1,  /* [0] */
+	    dont_chain                        : 1,  /* [1] */
+	    is_flush_needed                   : 1,  /* [2] */
+	    is_internal                       : 1,  /* [3] */
+	    which_descriptor                  : 2,  /* [5:4] */
+	    is_first_in_AMPDU                 : 1,  /* [6] */
+	    is_ext_buff                       : 1,  /* [7] */
+	    is_txinject                       : 1,  /* [8] */
+	    is_vns                            : 1,  /* [9] */
+	    single_type                       : 2,  /* [11:10] */
+	    tid                               : 4,  /* [15:12] */
+	    single_valid_sta__agg_e2w_tx_done : 1,  /* [16] */
+	    msdu_length                       : 13, /* [29:17] */
+	    bcmc                              : 1,  /* [30] */
+	    sw_padding                        : 1;  /* [31] */
+#else /* __BIG_ENDIAN_BITFIELD */
+	u32 sw_padding                        : 1,  /* [0] */
+	    bcmc                              : 1,  /* [1] */
+	    msdu_length                       : 13, /* [14:2] */
+	    single_valid_sta__agg_e2w_tx_done : 1,  /* [15] */
+	    tid                               : 4,  /* [19:16] */
+	    single_type                       : 2,  /* [21:20] */
+	    is_vns                            : 1,  /* [22] */
+	    is_txinject                       : 1,  /* [23] */
+	    is_ext_buff                       : 1,  /* [24] */
+	    is_first_in_AMPDU                 : 1,  /* [25] */
+	    which_descriptor                  : 2,  /* [27:26] */
+	    is_internal                       : 1,  /* [28] */
+	    is_flush_needed                   : 1,  /* [29] */
+	    dont_chain                        : 1,  /* [30] */
+	    backup_bcn                        : 1;  /* [31] */
+#endif
+};
+
+struct tx_host_info {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	u32 packet_cnt               : 4, /* [3:0] */
+	    host_padding             : 8, /* [11:4] */
+	    last_MSDU_LLI_INT_enable : 1, /* [12] */
+	    is_eth_802_3             : 1, /* [13] */
+	    is_protected             : 1, /* [14] */
+	    vif_index                : 4, /* [18:15] */
+	    rate_ctrl_entry          : 3, /* [21:19] */
+	    expected_ack             : 1, /* [22] */
+	    is_bcn                   : 1, /* [23] */
+	    hw_key_idx               : 8; /* [31:24] */
+#else /* __BIG_ENDIAN_BITFIELD */
+	u32 hw_key_idx               : 8, /* [7:0] */
+	    is_bcn                   : 1, /* [8] */
+	    expected_ack             : 1, /* [9] */
+	    rate_ctrl_entry          : 3, /* [12:10] */
+	    vif_index                : 4, /* [16:13] */
+	    is_protected             : 1, /* [17] */
+	    is_eth_802_3             : 1, /* [18] */
+	    last_MSDU_LLI_INT_enable : 1, /* [19] */
+	    host_padding             : 8, /* [27:20] */
+	    packet_cnt               : 4; /* [31:28] */
+#endif
+};
+
+struct lmacapi {
+	__le32 packet_addr[CL_AMSDU_TX_PAYLOAD_MAX];
+	__le16 packet_len[CL_AMSDU_TX_PAYLOAD_MAX];
+	__le16 push_timestamp; /* Milisec */
+};
+
+struct txdesc {
+	/* Pointer to the next element in the queue */
+	struct co_list_hdr list_hdr;
+	/* E2w txhdr parameters */
+	struct cl_e2w_txhdr_param e2w_txhdr_param __aligned(4);
+	/* Celeno flags field */
+	struct tx_host_info host_info __aligned(4);
+	/* Common parameters for ETH2WLAN and NATT hardware modules */
+	struct cl_e2w_natt_param  e2w_natt_param;
+	/* ETH2WLAN status and NATT calculation results */
+	struct cl_e2w_result e2w_result;
+	/* Information provided by UMAC to LMAC */
+	struct lmacapi umacdesc;
+};
+
+/*
+ * Comes from ipc_dma.h
+ * Element in the pool of TX DMA bridge descriptors.
+ * PAY ATTENTION - Avoid Changing/adding pointers to that struct,
+ * or any shared-memory-related-structs !!!
+ * Since in 64Bit platforms (Where pointers are 64Bit) such pointers
+ * might change alignments in shared-memory-related-structs of FW and DRV.
+ */
+struct dma_desc {
+	/*
+	 * Application subsystem address which is used as source address for DMA payload
+	 * transfer
+	 */
+	u32 src;
+	/*
+	 * Points to the start of the embedded data buffer associated with this descriptor.
+	 * This address acts as the destination address for the DMA payload transfer
+	 */
+	u32 dest;
+	/* Complete length of the buffer in memory */
+	u16 length;
+	/* Control word for the DMA engine (e.g. for interrupt generation) */
+	u16 ctrl;
+	/* Pointer to the next element of the chained list */
+	u32 next;
+	/*
+	 * When working with 64bit application the high 32bit address should be provided
+	 * in the following variable (note: "PCIEW_CONF" register should be configured accordingly)
+	 */
+	u32 app_hi_32bit;
+};
+
+/* Message structure for CFMs from Emb to App */
+struct cl_ipc_cfm_msg {
+	__le32 status;
+	__le32 dma_addr;
+	__le32 single_queue_idx;
+};
+
+/* Message structure for Debug messages from Emb to App */
+struct cl_ipc_dbg_msg {
+	char string[IPC_DBG_PARAM_SIZE];
+	__le32 pattern;
+};
+
+/*
+ * Message structure for MSGs from App to Emb.
+ * Actually a sub-structure will be used when filling the messages.
+ */
+struct cl_ipc_a2e_msg {
+	u32 dummy_word;
+	u32 msg[IPC_A2E_MSG_BUF_SIZE];
+};
+
+/* Struct for tensilica  backtrace */
+struct cl_ipc_backtrace_struct {
+	u32 pc[IPC_BACKTRACT_DEPTH];
+};
+
+/* Struct for tensilica  exception indication */
+struct cl_ipc_exception_struct {
+	u32 pattern;
+	u32 type;
+	u32 epc;
+	u32 excsave;
+	struct cl_ipc_backtrace_struct backtrace;
+};
+
+/*
+ * Can't use BITS_TO_LONGS since in firmware sizeof(long) == 4 and in the host
+ * this might be different from compiler to compiler. We need our own macro to
+ * match the firmware definition.
+ */
+#define CL_BITS_TO_U32S(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
+
+/*
+ * struct cl_ipc_enhanced_tim - ipc enhanced tim element
+ *
+ * This structure hold indication on the buffered traffic resembles the TIM element.
+ * This enhanced TIM holds more info on the buffered traffic, it indicate whether the
+ * traffic is associated with BA or singles and on which AC's.
+ *
+ * @tx_agg: indicate buffered tx-aggregated traffic per AC per BA session index
+ * @tx_single: indicate buffered tx-singles traffic per AC per station index
+ * @rx: indicate buffered rx traffic per AC per station index
+ */
+struct cl_ipc_enhanced_tim {
+	/*
+	 * Traffic indication map
+	 * our driver push packets to the IPC queues (DRIVER_LAYER -> IPC_LAYER),
+	 * on each push it also notify the IPC_LAYER for which queue it pushed packets.
+	 * this indication done by filling the bitmap.
+	 *
+	 * this is enhanced tim element because it is divided into AC and packet type
+	 * (aggregatable/non aggregatable).
+	 * the regular tim element which exist in the beacon is divided by AID only
+	 * which is less informative.
+	 *
+	 * TODO: add TIM element maintenance in the FW, this can be achived by the
+	 * enhanced tim elements abstraction.
+	 */
+	u32 tx_rx_agg[AC_MAX][CL_BITS_TO_U32S(IPC_TIM_AGG_SIZE)];
+	u32 tx_single[AC_MAX][CL_BITS_TO_U32S(FW_MAX_NUM_STA)];
+};
+
+struct cl_ipc_shared_env {
+	volatile struct cl_ipc_a2e_msg a2e_msg_buf;
+	/* Fields for MSGs sending from Emb to App */
+	volatile struct cl_ipc_e2a_msg e2a_msg_buf;
+	volatile struct dma_desc msg_dma_desc;
+	volatile __le32 e2a_msg_hostbuf_addr[IPC_E2A_MSG_BUF_CNT];
+	/* Fields for Debug MSGs sending from Emb to App */
+	volatile struct cl_ipc_dbg_msg dbg_buf;
+	volatile struct dma_desc dbg_dma_desc;
+	volatile __le32 dbg_hostbuf_addr[IPC_DBG_BUF_CNT];
+	volatile __le32 dbginfo_addr;
+	volatile __le32 dbginfo_size;
+	volatile __le32 pattern_addr;
+	volatile __le32 radarbuf_hostbuf[IPC_RADAR_BUF_CNT]; /* Buffers for radar events */
+	/* Used to update host general debug data */
+	volatile struct dma_desc dbg_info_dma_desc;
+	/*
+	 * The following members are associated ith the process of fetching
+	 * "application txdesc" from the application and copy them to the
+	 * internal embedded queues.
+	 *
+	 * @host_address_dma: dedicated dma descriptor to fetch the addresses of
+	 * "application txdesc" queues
+	 * @write_dma_desc_pool: dedicated dma descriptor to fetch the "@txdesc_emb_wr_idx"
+	 * index (dma for application txdesc metadata)
+	 * @last_txdesc_dma_desc_pool: dedicated dma descriptor to fetch "application txdescs"
+	 * (dma for application txdesc)
+	 * @txdesc_emb_wr_idx: indicate the last valid "application txdesc" fetched
+	 */
+	volatile struct dma_desc host_address_dma;
+	volatile struct dma_desc tx_power_tables_dma_desc;
+	volatile __le32 txdesc_emb_wr_idx[IPC_TX_QUEUE_CNT + CL_MAX_BA_PHYSICAL_QUEUE_CNT];
+	volatile __le32 host_rxbuf_rd_idx[CL_RX_BUF_MAX];                       /* For FW only */
+	volatile struct dma_desc rx_fw_hb_pool_dma_desc[HB_POOL_DMA_DESCS_NUM]; /* For FW only */
+	volatile struct dma_desc rxm_hb_pool_dma_desc[HB_POOL_DMA_DESCS_NUM];   /* For FW only */
+	volatile __le32 cfm_read_pointer; /* CFM read point. Updated by Host, Read by FW */
+	volatile __le16 phy_dev;
+	volatile u8 la_enable;
+	volatile u8 flags;
+	volatile u8 first_tcv;
+	volatile u8 ant_num;
+	volatile __le16 max_retry;
+	volatile __le16 lft_limit_ms;
+	volatile __le16 bar_max_retry; /* Not used by driver */
+	volatile __le32 assert_pattern;
+	volatile __le16 assert_file_id;
+	volatile __le16 assert_line_num;
+	volatile __le32 assert_param;
+	volatile struct cl_ipc_enhanced_tim enhanced_tim;
+	volatile u8 la_mirror_enable;
+};
+
+/* IRQs from app to emb */
+#define IPC_IRQ_A2E_TXDESC     0xFF00
+#define IPC_IRQ_A2E_RXBUF_BACK BIT(2)
+#define IPC_IRQ_A2E_MSG        BIT(1)
+#define IPC_IRQ_A2E_RXREQ      0x78
+#define IPC_IRQ_A2E_ALL        (IPC_IRQ_A2E_TXDESC | IPC_IRQ_A2E_MSG)
+
+#define IPC_IRQ_A2E_TXDESC_FIRSTBIT 8
+#define IPC_IRQ_A2E_RXREQ_FIRSTBIT  3
+
+#define IPC_IRQ_A2E_TXDESC_AGG_MAP(ac)    (IPC_IRQ_A2E_TXDESC_FIRSTBIT + IPC_TXQ_CNT + (ac))
+#define IPC_IRQ_A2E_TXDESC_SINGLE_MAP(ac) (IPC_IRQ_A2E_TXDESC_FIRSTBIT + (ac))
+#define IPC_IRQ_A2E_RX_STA_MAP(ac)        (IPC_IRQ_A2E_RXREQ_FIRSTBIT + (ac))
+
+struct cl_ipc_e2a_irq {
+	u32 dbg;
+	u32 msg;
+	u32 rxdesc;
+	u32 txcfm;
+	u32 radar;
+	u32 txdesc_ind;
+	u32 tbtt;
+	u32 sync;
+	u32 all;
+};
+
+/*
+ * IRQs from emb to app
+ * This interrupt is used by the firmware to indicate the driver that it may proceed.
+ * The corresponding interrupt handler sets the CL_DEV_FW_SYNC flag in cl_hw->drv_flags.
+ * There is also the cl_hw->fw_sync_wq wait queue, on which we may sleep while waiting for
+ * the interrupt, if we are allowed to do so (e.g., when we are in a system call).
+ */
+#define IPC_IRQ_L2H_DBG        BIT(0)
+#define IPC_IRQ_L2H_MSG        BIT(1)
+#define IPC_IRQ_L2H_RXDESC     BIT(2)
+#define IPC_IRQ_L2H_TXCFM      0x000000F8
+#define IPC_IRQ_L2H_RADAR      BIT(8)
+#define IPC_IRQ_L2H_TXDESC_IND BIT(9)
+#define IPC_IRQ_L2H_TBTT       BIT(10)
+#define IPC_IRQ_L2H_SYNC       BIT(11)
+
+#define IPC_IRQ_L2H_ALL          \
+	(IPC_IRQ_L2H_TXCFM |     \
+	IPC_IRQ_L2H_RXDESC |     \
+	IPC_IRQ_L2H_MSG |        \
+	IPC_IRQ_L2H_DBG |        \
+	IPC_IRQ_L2H_RADAR |      \
+	IPC_IRQ_L2H_TXDESC_IND | \
+	IPC_IRQ_L2H_TBTT |       \
+	IPC_IRQ_L2H_SYNC)
+
+#define IPC_IRQ_S2H_DBG        BIT(12)
+#define IPC_IRQ_S2H_MSG        BIT(13)
+#define IPC_IRQ_S2H_RXDESC     BIT(14)
+#define IPC_IRQ_S2H_TXCFM      0x000F8000
+#define IPC_IRQ_S2H_RADAR      BIT(20)
+#define IPC_IRQ_S2H_TXDESC_IND BIT(21)
+#define IPC_IRQ_S2H_TBTT       BIT(22)
+#define IPC_IRQ_S2H_SYNC       BIT(23)
+
+#define IPC_IRQ_S2H_ALL          \
+	(IPC_IRQ_S2H_TXCFM |     \
+	IPC_IRQ_S2H_RXDESC |     \
+	IPC_IRQ_S2H_MSG |        \
+	IPC_IRQ_S2H_DBG |        \
+	IPC_IRQ_S2H_RADAR |      \
+	IPC_IRQ_S2H_TXDESC_IND | \
+	IPC_IRQ_S2H_TBTT |       \
+	IPC_IRQ_S2H_SYNC)
+
+#endif /* CL_IPC_SHARED_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 36/96] cl8k: add key.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (34 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 35/96] cl8k: add ipc_shared.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 19:38   ` Johannes Berg
  2022-05-24 11:34 ` [RFC v2 37/96] cl8k: add key.h viktor.barna
                   ` (59 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/key.c | 382 +++++++++++++++++++++++++
 1 file changed, 382 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.c

diff --git a/drivers/net/wireless/celeno/cl8k/key.c b/drivers/net/wireless/celeno/cl8k/key.c
new file mode 100644
index 000000000000..99821b86a795
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/key.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "phy.h"
+#include "fw.h"
+#include "sta.h"
+#include "enhanced_tim.h"
+#include "key.h"
+
+#define DECRYPT_CCMPSUCCESS_FLAGS (RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED)
+
+void cl_vif_key_init(struct cl_vif *cl_vif)
+{
+	INIT_LIST_HEAD(&cl_vif->key_list_head);
+}
+
+static struct cl_key_conf *cl_vif_key_find(struct cl_vif *cl_vif,
+					   struct ieee80211_key_conf *key_conf_in)
+{
+	struct cl_key_conf *key, *tmp, *out = NULL;
+
+	if (!key_conf_in)
+		return NULL;
+
+	list_for_each_entry_safe(key, tmp, &cl_vif->key_list_head, list) {
+		struct ieee80211_key_conf *key_conf = key->key_conf;
+
+		if (key_conf_in->keyidx != key_conf->keyidx)
+			continue;
+
+		out = key;
+		break;
+	}
+
+	return out;
+}
+
+static struct ieee80211_key_conf *cl_vif_key_conf_default(struct cl_vif *cl_vif)
+{
+	struct cl_key_conf *key, *tmp;
+	struct ieee80211_key_conf *out = NULL;
+
+	list_for_each_entry_safe(key, tmp, &cl_vif->key_list_head, list) {
+		if (key->key_conf->keyidx != cl_vif->key_idx_default)
+			continue;
+
+		out = key->key_conf;
+		break;
+	}
+
+	return out;
+}
+
+static int cl_vif_key_add(struct cl_vif *cl_vif, struct ieee80211_key_conf *key_conf)
+{
+	struct cl_key_conf *key = NULL, *old_key = NULL;
+
+	key = kzalloc(sizeof(*key), GFP_KERNEL);
+	if (!key)
+		return -ENOMEM;
+
+	if (!list_empty(&cl_vif->key_list_head))
+		old_key = list_first_entry(&cl_vif->key_list_head, struct cl_key_conf, list);
+
+	cl_vif->key_idx_default = old_key ? old_key->key_conf->keyidx : key_conf->keyidx;
+	key->key_conf = key_conf;
+	list_add_tail(&key->list, &cl_vif->key_list_head);
+
+	return 0;
+}
+
+static void cl_vif_key_del(struct cl_vif *cl_vif, struct ieee80211_key_conf *key_conf_in)
+{
+	struct cl_key_conf *key, *tmp;
+
+	if (!key_conf_in)
+		return;
+
+	list_for_each_entry_safe(key, tmp, &cl_vif->key_list_head, list) {
+		struct ieee80211_key_conf *key_conf = key->key_conf;
+
+		if (key_conf_in->keyidx != key_conf->keyidx)
+			continue;
+
+		list_del(&key->list);
+		kfree(key);
+	}
+
+	if (!list_empty(&cl_vif->key_list_head)) {
+		struct cl_key_conf *new_key = list_first_entry(&cl_vif->key_list_head,
+							       struct cl_key_conf, list);
+
+		cl_vif->key_idx_default = new_key->key_conf->keyidx;
+	}
+}
+
+static int cl_vif_key_check_and_add(struct cl_vif *cl_vif,
+				    struct ieee80211_key_conf *key_conf)
+{
+	struct cl_key_conf *key = cl_vif_key_find(cl_vif, key_conf);
+
+	if (key) {
+		cl_dbg_warn(cl_vif->cl_hw,
+			    "[%s] error: previous key found. delete old key and add new key\n",
+			    __func__);
+		cl_vif_key_del(cl_vif, key->key_conf);
+	}
+
+	return cl_vif_key_add(cl_vif, key_conf);
+}
+
+static inline void cl_ccmp_hdr2pn(u8 *pn, u8 *hdr)
+{
+	pn[0] = hdr[7];
+	pn[1] = hdr[6];
+	pn[2] = hdr[5];
+	pn[3] = hdr[4];
+	pn[4] = hdr[1];
+	pn[5] = hdr[0];
+}
+
+static int cl_key_validate_pn(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	int hdrlen = 0, res = 0;
+	u8 pn[IEEE80211_CCMP_PN_LEN];
+	u8 tid = 0;
+
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	tid = ieee80211_get_tid(hdr);
+
+	cl_ccmp_hdr2pn(pn, skb->data + hdrlen);
+	res = memcmp(pn, cl_sta->rx_pn[tid], IEEE80211_CCMP_PN_LEN);
+	if (res < 0) {
+		cl_hw->rx_info.pkt_drop_invalid_pn++;
+		return -1;
+	}
+
+	memcpy(cl_sta->rx_pn[tid], pn, IEEE80211_CCMP_PN_LEN);
+
+	return 0;
+}
+
+void cl_vif_key_deinit(struct cl_vif *cl_vif)
+{
+	struct cl_key_conf *key, *tmp;
+
+	list_for_each_entry_safe(key, tmp, &cl_vif->key_list_head, list) {
+		list_del(&key->list);
+		kfree(key);
+	}
+}
+
+static int cl_cmd_set_key(struct cl_hw *cl_hw,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  struct ieee80211_key_conf *key)
+{
+	int error = 0;
+	struct mm_key_add_cfm *key_add_cfm;
+	u8 cipher_suite = 0;
+
+	/* Retrieve the cipher suite selector */
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+		cipher_suite = MAC_CIPHER_SUITE_WEP40;
+		break;
+	case WLAN_CIPHER_SUITE_WEP104:
+		cipher_suite = MAC_CIPHER_SUITE_WEP104;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		cipher_suite = MAC_CIPHER_SUITE_TKIP;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		cipher_suite = MAC_CIPHER_SUITE_CCMP;
+		break;
+	case WLAN_CIPHER_SUITE_GCMP:
+	case WLAN_CIPHER_SUITE_GCMP_256:
+		cipher_suite = MAC_CIPHER_SUITE_GCMP;
+		break;
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
+	}
+
+	error = cl_msg_tx_key_add(cl_hw, vif, sta, key, cipher_suite);
+	if (error)
+		return error;
+
+	key_add_cfm = (struct mm_key_add_cfm *)(cl_hw->msg_cfm_params[MM_KEY_ADD_CFM]);
+	if (!key_add_cfm)
+		return -ENOMSG;
+
+	if (key_add_cfm->status != 0) {
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", key_add_cfm->status);
+		cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+		return -EIO;
+	}
+
+	/* Save the index retrieved from firmware */
+	key->hw_key_idx = key_add_cfm->hw_key_idx;
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_KEY_ADD_CFM);
+
+	/*
+	 * Now inform mac80211 about our choices regarding header fields generation:
+	 * we let mac80211 take care of all generations
+	 */
+	key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+	if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+
+	if (sta) {
+		struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+		cl_sta->key_conf = key;
+	} else {
+		error = cl_vif_key_check_and_add((struct cl_vif *)vif->drv_priv, key);
+	}
+
+	return error;
+}
+
+static int cl_cmd_disable_key(struct cl_hw *cl_hw,
+			      struct ieee80211_vif *vif,
+			      struct ieee80211_sta *sta,
+			      struct ieee80211_key_conf *key)
+{
+	int ret = 0;
+	struct cl_sta *cl_sta = NULL;
+	struct cl_tx_queue *tx_queue = &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE];
+
+	if (sta) {
+		cl_sta = (struct cl_sta *)sta->drv_priv;
+
+		cl_sta->key_conf = NULL;
+		cl_sta->key_disable = true;
+
+		/*
+		 * Make sure there aren't any packets in firmware before deleting the key,
+		 * otherwise they will be transmitted without encryption.
+		 */
+		cl_sta->stop_tx = true;
+		cl_single_cfm_clear_tim_bit_sta(cl_hw, cl_sta->sta_idx);
+		cl_agg_cfm_clear_tim_bit_sta(cl_hw, cl_sta);
+		cl_txq_flush_sta(cl_hw, cl_sta);
+		cl_single_cfm_poll_empty_sta(cl_hw, cl_sta->sta_idx);
+		cl_agg_cfm_poll_empty_sta(cl_hw, cl_sta);
+
+		if (!list_empty(&tx_queue->hdrs)) {
+			spin_lock_bh(&cl_hw->tx_lock_single);
+			cl_enhanced_tim_set_tx_single(cl_hw, HIGH_PRIORITY_QUEUE,
+						      tx_queue->hw_index,
+						      false, tx_queue->cl_sta,
+						      tx_queue->tid);
+			spin_unlock_bh(&cl_hw->tx_lock_single);
+		}
+	} else {
+		cl_vif_key_del((struct cl_vif *)vif->drv_priv, key);
+	}
+
+	ret = cl_msg_tx_key_del(cl_hw, key->hw_key_idx);
+
+	if (cl_sta)
+		cl_sta->stop_tx = false;
+
+	return ret;
+}
+
+int cl_key_set(struct cl_hw *cl_hw,
+	       enum set_key_cmd cmd,
+	       struct ieee80211_vif *vif,
+	       struct ieee80211_sta *sta,
+	       struct ieee80211_key_conf *key)
+{
+	int error = 0;
+
+	switch (cmd) {
+	case SET_KEY:
+		error = cl_cmd_set_key(cl_hw, vif, sta, key);
+		break;
+
+	case DISABLE_KEY:
+		error = cl_cmd_disable_key(cl_hw, vif, sta, key);
+		break;
+
+	default:
+		error = -EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+struct ieee80211_key_conf *cl_key_get(struct cl_sta *cl_sta)
+{
+	if (cl_sta->key_conf)
+		return cl_sta->key_conf;
+
+	if (cl_sta->cl_vif)
+		return cl_vif_key_conf_default(cl_sta->cl_vif);
+
+	return NULL;
+}
+
+bool cl_key_is_cipher_ccmp_gcmp(struct ieee80211_key_conf *keyconf)
+{
+	u32 cipher;
+
+	if (!keyconf)
+		return false;
+
+	cipher = keyconf->cipher;
+
+	return ((cipher == WLAN_CIPHER_SUITE_CCMP) ||
+		(cipher == WLAN_CIPHER_SUITE_GCMP) ||
+		(cipher == WLAN_CIPHER_SUITE_GCMP_256));
+}
+
+void cl_key_ccmp_gcmp_pn_to_hdr(u8 *hdr, u64 pn, int key_id)
+{
+	hdr[0] = pn;
+	hdr[1] = pn >> 8;
+	hdr[2] = 0;
+	hdr[3] = 0x20 | (key_id << 6);
+	hdr[4] = pn >> 16;
+	hdr[5] = pn >> 24;
+	hdr[6] = pn >> 32;
+	hdr[7] = pn >> 40;
+}
+
+u8 cl_key_get_cipher_len(struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+
+	if (key_conf) {
+		switch (key_conf->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
+			return IEEE80211_WEP_IV_LEN;
+		case WLAN_CIPHER_SUITE_TKIP:
+			return  IEEE80211_TKIP_IV_LEN;
+		case WLAN_CIPHER_SUITE_CCMP:
+			return  IEEE80211_CCMP_HDR_LEN;
+		case WLAN_CIPHER_SUITE_CCMP_256:
+			return  IEEE80211_CCMP_256_HDR_LEN;
+		case WLAN_CIPHER_SUITE_GCMP:
+		case WLAN_CIPHER_SUITE_GCMP_256:
+			return  IEEE80211_GCMP_HDR_LEN;
+		}
+	}
+
+	return 0;
+}
+
+int cl_key_handle_pn_validation(struct cl_hw *cl_hw, struct sk_buff *skb,
+				struct cl_sta *cl_sta)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    ieee80211_is_frag(hdr))
+		return CL_PN_VALID_STATE_NOT_NEEDED;
+
+	if (!(status->flag & DECRYPT_CCMPSUCCESS_FLAGS))
+		return CL_PN_VALID_STATE_NOT_NEEDED;
+
+	if (!cl_sta)
+		return CL_PN_VALID_STATE_NOT_NEEDED;
+
+	if (cl_key_validate_pn(cl_hw, cl_sta, skb))
+		return CL_PN_VALID_STATE_FAILED;
+
+	status = IEEE80211_SKB_RXCB(skb);
+	status->flag |= RX_FLAG_PN_VALIDATED;
+
+	return CL_PN_VALID_STATE_SUCCESS;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 37/96] cl8k: add key.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (35 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
                   ` (58 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/key.h | 37 ++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/key.h

diff --git a/drivers/net/wireless/celeno/cl8k/key.h b/drivers/net/wireless/celeno/cl8k/key.h
new file mode 100644
index 000000000000..3731347f8243
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/key.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_KEY_H
+#define CL_KEY_H
+
+#include "hw.h"
+#include "vif.h"
+
+enum cl_key_pn_valid_state {
+	CL_PN_VALID_STATE_SUCCESS,
+	CL_PN_VALID_STATE_FAILED,
+	CL_PN_VALID_STATE_NOT_NEEDED,
+
+	CL_PN_VALID_STATE_MAX
+};
+
+struct cl_key_conf {
+	struct list_head list;
+	struct ieee80211_key_conf *key_conf;
+};
+
+void cl_vif_key_init(struct cl_vif *cl_vif);
+void cl_vif_key_deinit(struct cl_vif *cl_vif);
+int cl_key_set(struct cl_hw *cl_hw,
+	       enum set_key_cmd cmd,
+	       struct ieee80211_vif *vif,
+	       struct ieee80211_sta *sta,
+	       struct ieee80211_key_conf *key);
+struct ieee80211_key_conf *cl_key_get(struct cl_sta *cl_sta);
+bool cl_key_is_cipher_ccmp_gcmp(struct ieee80211_key_conf *keyconf);
+void cl_key_ccmp_gcmp_pn_to_hdr(u8 *hdr, u64 pn, int key_id);
+u8 cl_key_get_cipher_len(struct sk_buff *skb);
+int cl_key_handle_pn_validation(struct cl_hw *cl_hw, struct sk_buff *skb,
+				struct cl_sta *cl_sta);
+
+#endif /* CL_KEY_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 38/96] cl8k: add mac80211.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (36 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 37/96] cl8k: add key.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 19:49   ` Johannes Berg
  2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
                   ` (57 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mac80211.c | 2392 +++++++++++++++++++
 1 file changed, 2392 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.c

diff --git a/drivers/net/wireless/celeno/cl8k/mac80211.c b/drivers/net/wireless/celeno/cl8k/mac80211.c
new file mode 100644
index 000000000000..13989327ccdb
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac80211.c
@@ -0,0 +1,2392 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/log2.h>
+#include <net/mac80211.h>
+
+#include "debug.h"
+#include "utils.h"
+#include "sta.h"
+#include "dfs.h"
+#include "regdom.h"
+#include "hw.h"
+#include "mac80211.h"
+#include "ampdu.h"
+#include "tx.h"
+#include "radio.h"
+#include "recovery.h"
+#include "rates.h"
+#include "temperature.h"
+#include "vns.h"
+#include "key.h"
+#include "version.h"
+#include "power.h"
+#include "stats.h"
+#include "scan.h"
+#include "mac_addr.h"
+#include "chip.h"
+
+#define RATE_1_MBPS   10
+#define RATE_2_MBPS   20
+#define RATE_5_5_MBPS 55
+#define RATE_11_MBPS  110
+#define RATE_6_MBPS   60
+#define RATE_9_MBPS   90
+#define RATE_12_MBPS  120
+#define RATE_18_MBPS  180
+#define RATE_24_MBPS  240
+#define RATE_36_MBPS  360
+#define RATE_48_MBPS  480
+#define RATE_54_MBPS  540
+
+#define CL_HT_CAPABILITIES                                              \
+{                                                                       \
+	.ht_supported = true,                                           \
+	.cap = IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, \
+	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,                     \
+	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_1,                   \
+	.mcs = {                                                        \
+		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 },         \
+		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,               \
+	},                                                              \
+}
+
+#define CL_VHT_CAPABILITIES                                             \
+{                                                                       \
+	.vht_supported = false,                                         \
+	.cap = 0,                                                       \
+	.vht_mcs = {                                                    \
+		.rx_mcs_map = cpu_to_le16(                              \
+				IEEE80211_VHT_MCS_SUPPORT_0_7   << 0  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 2  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 4  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 6  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 8  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+		.tx_mcs_map = cpu_to_le16(                              \
+				IEEE80211_VHT_MCS_SUPPORT_0_7   << 0  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 2  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 4  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 6  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 8  | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \
+				IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \
+	}                                                               \
+}
+
+#define CL_HE_CAP_ELEM_STATION                                                       \
+{                                                                                    \
+	.mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                             \
+	.mac_cap_info[1] = 0,                                                        \
+	.mac_cap_info[2] = 0,                                                        \
+	.mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,            \
+	.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                                \
+	.mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX,               \
+	.phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G, \
+	.phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                     \
+	.phy_cap_info[2] = 0,                                                        \
+	.phy_cap_info[3] = 0,                                                        \
+	.phy_cap_info[4] = 0,                                                        \
+	.phy_cap_info[5] = 0,                                                        \
+	.phy_cap_info[6] = 0,                                                        \
+	.phy_cap_info[7] = 0,                                                        \
+	.phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G,       \
+	.phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,           \
+	.phy_cap_info[10] = 0,                                                       \
+}
+
+#define CL_HE_CAP_ELEM_AP                                                       \
+{                                                                               \
+	.mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                        \
+	.mac_cap_info[1] = 0,                                                   \
+	.mac_cap_info[2] = 0,                                                   \
+	.mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,       \
+	.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                           \
+	.mac_cap_info[5] = 0,                                                   \
+	.phy_cap_info[0] = 0,                                                   \
+	.phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                \
+	.phy_cap_info[2] = 0,                                                   \
+	.phy_cap_info[3] = 0,                                                   \
+	.phy_cap_info[4] = 0,                                                   \
+	.phy_cap_info[5] = 0,                                                   \
+	.phy_cap_info[6] = 0,                                                   \
+	.phy_cap_info[7] = 0,                                                   \
+	.phy_cap_info[8] = 0,                                                   \
+	.phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,      \
+	.phy_cap_info[10] = 0,                                                  \
+}
+
+#define CL_HE_CAP_ELEM_MESH_POINT                                               \
+{                                                                               \
+	.mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE,                        \
+	.mac_cap_info[1] = 0,                                                   \
+	.mac_cap_info[2] = 0,                                                   \
+	.mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,       \
+	.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_BQR,                           \
+	.mac_cap_info[5] = 0,                                                   \
+	.phy_cap_info[0] = 0,                                                   \
+	.phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A,                \
+	.phy_cap_info[2] = 0,                                                   \
+	.phy_cap_info[3] = 0,                                                   \
+	.phy_cap_info[4] = 0,                                                   \
+	.phy_cap_info[5] = 0,                                                   \
+	.phy_cap_info[6] = 0,                                                   \
+	.phy_cap_info[7] = 0,                                                   \
+	.phy_cap_info[8] = 0,                                                   \
+	.phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,      \
+	.phy_cap_info[10] = 0,                                                  \
+}
+
+#define CL_HE_MCS_NSS_SUPP                   \
+{                                            \
+	.rx_mcs_80 = cpu_to_le16(0xff00),    \
+	.tx_mcs_80 = cpu_to_le16(0xff00),    \
+	.rx_mcs_160 = cpu_to_le16(0xff00),   \
+	.tx_mcs_160 = cpu_to_le16(0xff00),   \
+	.rx_mcs_80p80 = cpu_to_le16(0xffff), \
+	.tx_mcs_80p80 = cpu_to_le16(0xffff), \
+}
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+	.bitrate = (_bitrate),             \
+	.flags = (_flags),                 \
+	.hw_value = (_hw_rate),            \
+}
+
+#define CHAN(_freq, _idx) {     \
+	.center_freq = (_freq), \
+	.hw_value = (_idx),     \
+	.max_power = 18,        \
+}
+
+static struct ieee80211_sband_iftype_data cl_he_data[] = {
+	{
+		.types_mask = BIT(NL80211_IFTYPE_STATION),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = CL_HE_CAP_ELEM_STATION,
+			.he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+		},
+	},
+	{
+		.types_mask = BIT(NL80211_IFTYPE_AP),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = CL_HE_CAP_ELEM_AP,
+			.he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+		},
+	},
+	{
+		.types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
+		.he_cap = {
+			.has_he = true,
+			.he_cap_elem = CL_HE_CAP_ELEM_MESH_POINT,
+			.he_mcs_nss_supp = CL_HE_MCS_NSS_SUPP,
+		},
+	},
+};
+
+static struct ieee80211_rate cl_ratetable[] = {
+	RATE(10,  0x00, 0),
+	RATE(20,  0x01, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(55,  0x02, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(110, 0x03, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(60,  0x04, 0),
+	RATE(90,  0x05, 0),
+	RATE(120, 0x06, 0),
+	RATE(180, 0x07, 0),
+	RATE(240, 0x08, 0),
+	RATE(360, 0x09, 0),
+	RATE(480, 0x0A, 0),
+	RATE(540, 0x0B, 0),
+};
+
+/* The channels indexes here are not used anymore */
+static struct ieee80211_channel cl_2ghz_channels[] = {
+	CHAN(2412, 0),
+	CHAN(2417, 1),
+	CHAN(2422, 2),
+	CHAN(2427, 3),
+	CHAN(2432, 4),
+	CHAN(2437, 5),
+	CHAN(2442, 6),
+	CHAN(2447, 7),
+	CHAN(2452, 8),
+	CHAN(2457, 9),
+	CHAN(2462, 10),
+	CHAN(2467, 11),
+	CHAN(2472, 12),
+	CHAN(2484, 13),
+};
+
+static struct ieee80211_channel cl_5ghz_channels[] = {
+	CHAN(5180, 0),  /* 36 -  20MHz */
+	CHAN(5200, 1),  /* 40 -  20MHz */
+	CHAN(5220, 2),  /* 44 -  20MHz */
+	CHAN(5240, 3),  /* 48 -  20MHz */
+	CHAN(5260, 4),  /* 52 -  20MHz */
+	CHAN(5280, 5),  /* 56 -  20MHz */
+	CHAN(5300, 6),  /* 60 -  20MHz */
+	CHAN(5320, 7),  /* 64 -  20MHz */
+	CHAN(5500, 8),  /* 100 - 20MHz */
+	CHAN(5520, 9),  /* 104 - 20MHz */
+	CHAN(5540, 10), /* 108 - 20MHz */
+	CHAN(5560, 11), /* 112 - 20MHz */
+	CHAN(5580, 12), /* 116 - 20MHz */
+	CHAN(5600, 13), /* 120 - 20MHz */
+	CHAN(5620, 14), /* 124 - 20MHz */
+	CHAN(5640, 15), /* 128 - 20MHz */
+	CHAN(5660, 16), /* 132 - 20MHz */
+	CHAN(5680, 17), /* 136 - 20MHz */
+	CHAN(5700, 18), /* 140 - 20MHz */
+	CHAN(5720, 19), /* 144 - 20MHz */
+	CHAN(5745, 20), /* 149 - 20MHz */
+	CHAN(5765, 21), /* 153 - 20MHz */
+	CHAN(5785, 22), /* 157 - 20MHz */
+	CHAN(5805, 23), /* 161 - 20MHz */
+	CHAN(5825, 24), /* 165 - 20MHz */
+};
+
+static struct ieee80211_channel cl_6ghz_channels[] = {
+	CHAN(5955, 1),  /* 1 - 20MHz */
+	CHAN(5935, 2),  /* 2 - 20MHz */
+	CHAN(5975, 5),  /* 5 - 20MHz */
+	CHAN(5995, 9),  /* 9 - 20MHz */
+	CHAN(6015, 13),  /* 13 - 20MHz */
+	CHAN(6035, 17),  /* 17 - 20MHz */
+	CHAN(6055, 21),  /* 21 - 20MHz */
+	CHAN(6075, 25),  /* 25 - 20MHz */
+	CHAN(6095, 29),  /* 29 - 20MHz */
+	CHAN(6115, 33),  /* 33 - 20MHz */
+	CHAN(6135, 37),  /* 37 - 20MHz */
+	CHAN(6155, 41),  /* 41 - 20MHz */
+	CHAN(6175, 45),  /* 45 - 20MHz */
+	CHAN(6195, 49),  /* 49 - 20MHz */
+	CHAN(6215, 53),  /* 53 - 20MHz */
+	CHAN(6235, 57),  /* 57 - 20MHz */
+	CHAN(6255, 61),  /* 61 - 20MHz */
+	CHAN(6275, 65),  /* 65 - 20MHz */
+	CHAN(6295, 69),  /* 69 - 20MHz */
+	CHAN(6315, 73),  /* 73 - 20MHz */
+	CHAN(6335, 77),  /* 77 - 20MHz */
+	CHAN(6355, 81),  /* 81 - 20MHz */
+	CHAN(6375, 85),  /* 85 - 20MHz */
+	CHAN(6395, 89),  /* 89 - 20MHz */
+	CHAN(6415, 93),  /* 93 - 20MHz */
+	CHAN(6435, 97),  /* 97 - 20MHz */
+	CHAN(6455, 101),  /* 101 - 20MHz */
+	CHAN(6475, 105),  /* 105 - 20MHz */
+	CHAN(6495, 109),  /* 109 - 20MHz */
+	CHAN(6515, 113),  /* 113 - 20MHz */
+	CHAN(6535, 117),  /* 117 - 20MHz */
+	CHAN(6555, 121),  /* 121 - 20MHz */
+	CHAN(6575, 125),  /* 125 - 20MHz */
+	CHAN(6595, 129),  /* 129 - 20MHz */
+	CHAN(6615, 133),  /* 133 - 20MHz */
+	CHAN(6635, 137),  /* 137 - 20MHz */
+	CHAN(6655, 141),  /* 141 - 20MHz */
+	CHAN(6675, 145),  /* 145 - 20MHz */
+	CHAN(6695, 149),  /* 149 - 20MHz */
+	CHAN(6715, 153),  /* 153 - 20MHz */
+	CHAN(6735, 157),  /* 157 - 20MHz */
+	CHAN(6755, 161),  /* 161 - 20MHz */
+	CHAN(6775, 165),  /* 165 - 20MHz */
+	CHAN(6795, 169),  /* 169 - 20MHz */
+	CHAN(6815, 173),  /* 173 - 20MHz */
+	CHAN(6835, 177),  /* 177 - 20MHz */
+	CHAN(6855, 181),  /* 181 - 20MHz */
+	CHAN(6875, 188),  /* 185 - 20MHz */
+	CHAN(6895, 189),  /* 189 - 20MHz */
+	CHAN(6915, 193),  /* 193 - 20MHz */
+	CHAN(6935, 197),  /* 197 - 20MHz */
+	CHAN(6955, 201),  /* 201 - 20MHz */
+	CHAN(6975, 205),  /* 205 - 20MHz */
+	CHAN(6995, 209),  /* 209 - 20MHz */
+	CHAN(7015, 213),  /* 213 - 20MHz */
+	CHAN(7035, 217),  /* 217 - 20MHz */
+	CHAN(7055, 221),  /* 221 - 20MHz */
+	CHAN(7075, 225),  /* 225 - 20MHz */
+	CHAN(7095, 229),  /* 229 - 20MHz */
+	CHAN(7115, 233),  /* 233 - 20MHz */
+};
+
+static struct ieee80211_supported_band cl_band_2ghz = {
+	.channels   = cl_2ghz_channels,
+	.n_channels = ARRAY_SIZE(cl_2ghz_channels),
+	.bitrates   = cl_ratetable,
+	.n_bitrates = ARRAY_SIZE(cl_ratetable),
+	.ht_cap     = CL_HT_CAPABILITIES,
+	.vht_cap    = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_5ghz = {
+	.channels   = cl_5ghz_channels,
+	.n_channels = ARRAY_SIZE(cl_5ghz_channels),
+	.bitrates   = &cl_ratetable[4],
+	.n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+	.ht_cap     = CL_HT_CAPABILITIES,
+	.vht_cap    = CL_VHT_CAPABILITIES,
+};
+
+static struct ieee80211_supported_band cl_band_6ghz = {
+	.channels   = cl_6ghz_channels,
+	.n_channels = ARRAY_SIZE(cl_6ghz_channels),
+	.bitrates   = &cl_ratetable[4],
+	.n_bitrates = ARRAY_SIZE(cl_ratetable) - 4,
+};
+
+static const struct ieee80211_iface_limit cl_limits[] = {
+	{
+		.max   = ARRAY_SIZE(((struct cl_hw *)0)->addresses),
+		.types = BIT(NL80211_IFTYPE_AP) |
+			 BIT(NL80211_IFTYPE_STATION) |
+			 BIT(NL80211_IFTYPE_MESH_POINT),
+	},
+};
+
+#define WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED BIT(0)
+
+static u8 cl_if_types_ext_capa_ap_24g[] = {
+	[0]  = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+	[7]  = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+};
+
+static const struct wiphy_iftype_ext_capab cl_iftypes_ext_capa_24g[] = {
+	{
+		.iftype = NL80211_IFTYPE_AP,
+		.extended_capabilities = cl_if_types_ext_capa_ap_24g,
+		.extended_capabilities_mask = cl_if_types_ext_capa_ap_24g,
+		.extended_capabilities_len = sizeof(cl_if_types_ext_capa_ap_24g),
+	},
+};
+
+static u8 cl_if_types_ext_capa_ap_5g[] = {
+	[0]  = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+	[7]  = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+};
+
+static const struct wiphy_iftype_ext_capab cl_iftypes_ext_capa_5g[] = {
+	{
+		.iftype = NL80211_IFTYPE_AP,
+		.extended_capabilities = cl_if_types_ext_capa_ap_5g,
+		.extended_capabilities_mask = cl_if_types_ext_capa_ap_5g,
+		.extended_capabilities_len = sizeof(cl_if_types_ext_capa_ap_5g),
+	},
+};
+
+static u8 cl_if_types_ext_capa_ap_6g[] = {
+	[0]  = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+	[7]  = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+};
+
+static const struct wiphy_iftype_ext_capab cl_iftypes_ext_capa_6g[] = {
+	{
+		.iftype = NL80211_IFTYPE_AP,
+		.extended_capabilities = cl_if_types_ext_capa_ap_6g,
+		.extended_capabilities_mask = cl_if_types_ext_capa_ap_6g,
+		.extended_capabilities_len = sizeof(cl_if_types_ext_capa_ap_6g),
+	},
+};
+
+static struct ieee80211_iface_combination cl_combinations[] = {
+	{
+		.limits = cl_limits,
+		.n_limits = ARRAY_SIZE(cl_limits),
+		.num_different_channels = 1,
+		.max_interfaces = ARRAY_SIZE(((struct cl_hw *)0)->addresses),
+		.beacon_int_min_gcd = 100,
+		.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20) |
+				       BIT(NL80211_CHAN_WIDTH_40) |
+				       BIT(NL80211_CHAN_WIDTH_80) |
+				       BIT(NL80211_CHAN_WIDTH_160),
+	}
+};
+
+static const int cl_ac2hwq[AC_MAX] = {
+	[NL80211_TXQ_Q_VO] = CL_HWQ_VO,
+	[NL80211_TXQ_Q_VI] = CL_HWQ_VI,
+	[NL80211_TXQ_Q_BE] = CL_HWQ_BE,
+	[NL80211_TXQ_Q_BK] = CL_HWQ_BK
+};
+
+static const int cl_ac2edca[AC_MAX] = {
+	[NL80211_TXQ_Q_VO] = EDCA_AC_VO,
+	[NL80211_TXQ_Q_VI] = EDCA_AC_VI,
+	[NL80211_TXQ_Q_BE] = EDCA_AC_BE,
+	[NL80211_TXQ_Q_BK] = EDCA_AC_BK
+};
+
+static u8 cl_he_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+	u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_tx[nss];
+
+	switch (mcs) {
+	case WRS_MCS_7:
+		return IEEE80211_HE_MCS_SUPPORT_0_7;
+	case WRS_MCS_9:
+		return IEEE80211_HE_MCS_SUPPORT_0_9;
+	case WRS_MCS_11:
+		return IEEE80211_HE_MCS_SUPPORT_0_11;
+	}
+
+	cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+	return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 cl_he_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+	u8 mcs = cl_hw->conf->ce_he_mcs_nss_supp_rx[nss];
+
+	switch (mcs) {
+	case WRS_MCS_7:
+		return IEEE80211_HE_MCS_SUPPORT_0_7;
+	case WRS_MCS_9:
+		return IEEE80211_HE_MCS_SUPPORT_0_9;
+	case WRS_MCS_11:
+		return IEEE80211_HE_MCS_SUPPORT_0_11;
+	}
+
+	cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7, 9 or 11!\n", mcs, nss);
+	return IEEE80211_HE_MCS_NOT_SUPPORTED;
+}
+
+static u8 cl_vht_mcs_supp_tx(struct cl_hw *cl_hw, u8 nss)
+{
+	u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_tx[nss];
+
+	switch (mcs) {
+	case WRS_MCS_7:
+		return IEEE80211_VHT_MCS_SUPPORT_0_7;
+	case WRS_MCS_8:
+		return IEEE80211_VHT_MCS_SUPPORT_0_8;
+	case WRS_MCS_9:
+		return IEEE80211_VHT_MCS_SUPPORT_0_9;
+	}
+
+	cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+	return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static u8 cl_vht_mcs_supp_rx(struct cl_hw *cl_hw, u8 nss)
+{
+	u8 mcs = cl_hw->conf->ce_vht_mcs_nss_supp_rx[nss];
+
+	switch (mcs) {
+	case WRS_MCS_7:
+		return IEEE80211_VHT_MCS_SUPPORT_0_7;
+	case WRS_MCS_8:
+		return IEEE80211_VHT_MCS_SUPPORT_0_8;
+	case WRS_MCS_9:
+		return IEEE80211_VHT_MCS_SUPPORT_0_9;
+	}
+
+	cl_dbg_err(cl_hw, "Invalid mcs %u for nss %u. Must be 7-9!\n", mcs, nss);
+	return IEEE80211_VHT_MCS_NOT_SUPPORTED;
+}
+
+static void cl_set_he_6ghz_capab(struct cl_hw *cl_hw)
+{
+	struct ieee80211_he_6ghz_capa *he_6ghz_cap0 = &cl_hw->iftype_data[0].he_6ghz_capa;
+	struct ieee80211_he_6ghz_capa *he_6ghz_cap1 = &cl_hw->iftype_data[1].he_6ghz_capa;
+	struct ieee80211_he_6ghz_capa *he_6ghz_cap2 = &cl_hw->iftype_data[2].he_6ghz_capa;
+
+	he_6ghz_cap0->capa = cpu_to_le16(IEEE80211_HT_MPDU_DENSITY_1);
+
+	he_6ghz_cap0->capa |=
+		cpu_to_le16(cl_hw->conf->ci_max_mpdu_len << HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET);
+	he_6ghz_cap0->capa |=
+		cpu_to_le16(IEEE80211_VHT_MAX_AMPDU_1024K << HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET);
+
+	he_6ghz_cap0->capa |= cpu_to_le16(IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS |
+					  IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS);
+
+	he_6ghz_cap1->capa = he_6ghz_cap0->capa;
+	he_6ghz_cap2->capa = he_6ghz_cap0->capa;
+}
+
+static void _cl_set_he_capab(struct cl_hw *cl_hw, u8 idx)
+{
+	struct ieee80211_sta_he_cap *he_cap = &cl_hw->iftype_data[idx].he_cap;
+	struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp = &he_cap->he_mcs_nss_supp;
+	struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
+	u8 rx_nss = cl_hw->conf->ce_rx_nss;
+	u8 tx_nss = cl_hw->conf->ce_tx_nss;
+	int i = 0;
+
+	if (BAND_IS_5G_6G(cl_hw)) {
+		he_cap_elem->phy_cap_info[0] |=
+			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+		for (i = 0; i < rx_nss; i++)
+			he_mcs_nss_supp->rx_mcs_160 |=
+				cpu_to_le16(cl_he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+		for (i = 0; i < tx_nss; i++)
+			he_mcs_nss_supp->tx_mcs_160 |=
+				cpu_to_le16(cl_he_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+		he_cap_elem->phy_cap_info[0] |=
+			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+
+		for (i = 0; i < rx_nss; i++)
+			he_mcs_nss_supp->rx_mcs_80 |=
+				cpu_to_le16(cl_he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+		for (i = 0; i < tx_nss; i++)
+			he_mcs_nss_supp->tx_mcs_80 |=
+				cpu_to_le16(cl_he_mcs_supp_tx(cl_hw, i) << (i * 2));
+	} else {
+		he_cap_elem->phy_cap_info[0] |=
+			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
+
+		for (i = 0; i < rx_nss; i++)
+			he_mcs_nss_supp->rx_mcs_80 |=
+				cpu_to_le16(cl_he_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+		for (i = 0; i < tx_nss; i++)
+			he_mcs_nss_supp->tx_mcs_80 |=
+				cpu_to_le16(cl_he_mcs_supp_tx(cl_hw, i) << (i * 2));
+	}
+
+	for (i = rx_nss; i < 8; i++) {
+		he_mcs_nss_supp->rx_mcs_80 |=
+			cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+		he_mcs_nss_supp->rx_mcs_160 |=
+			cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+	}
+
+	for (i = tx_nss; i < 8; i++) {
+		he_mcs_nss_supp->tx_mcs_80 |=
+			cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+		he_mcs_nss_supp->tx_mcs_160 |=
+			cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+	}
+
+	if (cl_hw->conf->ci_he_rxldpc_en)
+		he_cap_elem->phy_cap_info[1] |=
+			IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
+
+	if (cl_hw->conf->ci_rx_he_mu_ppdu)
+		he_cap_elem->phy_cap_info[3] |=
+			IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+
+	if (cl_hw->conf->ci_bf_en) {
+		he_cap_elem->phy_cap_info[3] |=
+			IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
+		he_cap_elem->phy_cap_info[5] |=
+			IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4;
+	}
+}
+
+static void cl_set_he_capab(struct cl_hw *cl_hw)
+{
+	struct ieee80211_sta_he_cap *he_cap0 = &cl_hw->iftype_data[0].he_cap;
+	struct ieee80211_he_cap_elem *he_cap_elem = &he_cap0->he_cap_elem;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	u8 tf_mac_pad_dur = conf->ci_tf_mac_pad_dur;
+
+	memcpy(&cl_hw->iftype_data, cl_he_data, sizeof(cl_hw->iftype_data));
+
+	if (tf_mac_pad_dur == 1)
+		he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US;
+	else if (tf_mac_pad_dur == 2)
+		he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
+
+	_cl_set_he_capab(cl_hw, 0);
+	_cl_set_he_capab(cl_hw, 1);
+	_cl_set_he_capab(cl_hw, 2);
+
+	if (cl_band_is_6g(cl_hw))
+		cl_set_he_6ghz_capab(cl_hw);
+
+	cl_hw->sband.n_iftype_data = ARRAY_SIZE(cl_he_data);
+	cl_hw->sband.iftype_data = cl_hw->iftype_data;
+}
+
+#define RATE_1_MBPS   10
+#define RATE_2_MBPS   20
+#define RATE_5_5_MBPS 55
+#define RATE_11_MBPS  110
+#define RATE_6_MBPS   60
+#define RATE_9_MBPS   90
+#define RATE_12_MBPS  120
+#define RATE_18_MBPS  180
+#define RATE_24_MBPS  240
+#define RATE_36_MBPS  360
+#define RATE_48_MBPS  480
+#define RATE_54_MBPS  540
+
+static u16 cl_cap_convert_rate_to_bitmap(u16 rate)
+{
+	switch (rate) {
+	case RATE_1_MBPS:
+		return BIT(0);
+	case RATE_2_MBPS:
+		return BIT(1);
+	case RATE_5_5_MBPS:
+		return BIT(2);
+	case RATE_11_MBPS:
+		return BIT(3);
+	case RATE_6_MBPS:
+		return BIT(4);
+	case RATE_9_MBPS:
+		return BIT(5);
+	case RATE_12_MBPS:
+		return BIT(6);
+	case RATE_18_MBPS:
+		return BIT(7);
+	case RATE_24_MBPS:
+		return BIT(8);
+	case RATE_36_MBPS:
+		return BIT(9);
+	case RATE_48_MBPS:
+		return BIT(10);
+	case RATE_54_MBPS:
+		return BIT(11);
+	default:
+		return 0;
+	}
+}
+
+u16 cl_cap_set_mesh_basic_rates(struct cl_hw *cl_hw)
+{
+	int i;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	u16 basic_rates = 0;
+
+	for (i = 0; i < MESH_BASIC_RATE_MAX; i++)
+		basic_rates |= cl_cap_convert_rate_to_bitmap(conf->ci_mesh_basic_rates[i]);
+
+	return basic_rates;
+}
+
+void cl_cap_dyn_params(struct cl_hw *cl_hw)
+{
+	struct ieee80211_hw *hw = cl_hw->hw;
+	struct wiphy *wiphy = hw->wiphy;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	u8 rx_nss = conf->ce_rx_nss;
+	u8 tx_nss = conf->ce_tx_nss;
+	u8 guard_interval = conf->ci_short_guard_interval;
+	u8 i;
+	u8 bw = cl_hw->conf->ci_cap_bandwidth;
+	struct ieee80211_supported_band *sband = &cl_hw->sband;
+	struct ieee80211_sta_ht_cap *sband_ht_cap = &sband->ht_cap;
+	struct ieee80211_sta_vht_cap *sband_vht_cap = &sband->vht_cap;
+
+	if (cl_band_is_6g(cl_hw)) {
+		memcpy(sband, &cl_band_6ghz, sizeof(struct ieee80211_supported_band));
+	} else if (cl_band_is_5g(cl_hw)) {
+		memcpy(sband, &cl_band_5ghz, sizeof(struct ieee80211_supported_band));
+	} else {
+		memcpy(sband, &cl_band_2ghz, sizeof(struct ieee80211_supported_band));
+
+		if (!conf->ci_vht_cap_24g)
+			memset(&sband->vht_cap, 0, sizeof(struct ieee80211_sta_vht_cap));
+	}
+
+	/* 6GHz doesn't support HT/VHT */
+	if (!cl_band_is_6g(cl_hw)) {
+		if (bw > CHNL_BW_20)
+			sband_ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+		/* Guard_interval */
+		if (guard_interval) {
+			sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_20;
+
+			if (bw >= CHNL_BW_40)
+				sband_ht_cap->cap |= IEEE80211_HT_CAP_SGI_40;
+
+			if (bw >= CHNL_BW_80)
+				sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+
+			if (bw == CHNL_BW_160)
+				sband_vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+		}
+	}
+
+	/* Amsdu */
+	cl_rx_amsdu_hw_en(hw, conf->ce_rxamsdu_en);
+	cl_hw->txamsdu_en = conf->ce_txamsdu_en;
+
+	/* Hw flags */
+	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+	ieee80211_hw_set(hw, QUEUE_CONTROL);
+	ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+	ieee80211_hw_set(hw, SPECTRUM_MGMT);
+	ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+	ieee80211_hw_set(hw, NO_AUTO_VIF);
+	ieee80211_hw_set(hw, MFP_CAPABLE);
+	ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK);
+	ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+
+	wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+	wiphy->features |= NL80211_FEATURE_AP_SCAN;
+	wiphy->available_antennas_tx = ANT_MASK(cl_hw->max_antennas);
+	wiphy->available_antennas_rx = ANT_MASK(cl_hw->max_antennas);
+
+	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+
+	if (conf->ci_fast_rx_en) {
+		ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
+		ieee80211_hw_set(hw, AP_LINK_PS);
+	}
+
+	if (cl_band_is_6g(cl_hw)) {
+		hw->wiphy->iftype_ext_capab = cl_iftypes_ext_capa_6g;
+		hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(cl_iftypes_ext_capa_6g);
+	} else if (cl_band_is_5g(cl_hw)) {
+		hw->wiphy->iftype_ext_capab = cl_iftypes_ext_capa_5g;
+		hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(cl_iftypes_ext_capa_5g);
+	} else if (cl_band_is_24g(cl_hw)) {
+		/* Turn on "20/40 Coex Mgmt Support" bit (24g only) */
+		if (conf->ce_acs_coex_en) {
+			u8 *ext_cap = (u8 *)cl_iftypes_ext_capa_24g[0].extended_capabilities;
+
+			ext_cap[0] |= WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED;
+		}
+
+		hw->wiphy->iftype_ext_capab = cl_iftypes_ext_capa_24g;
+		hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(cl_iftypes_ext_capa_24g);
+	}
+
+	/*
+	 * To disable the dynamic PS we say to the stack that we support it in
+	 * HW. This will force mac80211 rely on us to handle this.
+	 */
+	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+
+	if (conf->ci_agg_tx)
+		ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				 BIT(NL80211_IFTYPE_AP) |
+				 BIT(NL80211_IFTYPE_MESH_POINT);
+
+	wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+			WIPHY_FLAG_HAS_CHANNEL_SWITCH |
+			WIPHY_FLAG_IBSS_RSN;
+
+	if (conf->ci_uapsd_en)
+		wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
+	/* Modify MAX BSS num according to the desired config value */
+	for (i = 0; i < ARRAY_SIZE(cl_combinations); i++)
+		cl_combinations[i].max_interfaces = conf->ci_max_bss_num;
+	wiphy->iface_combinations = cl_combinations;
+	wiphy->n_iface_combinations = ARRAY_SIZE(cl_combinations);
+
+	/*
+	 * hw_scan ops may ask driver to forge active scan request. So the
+	 * scan capabs are filled in (the are same as inside mac80211).
+	 * However, they are not representing real hw_scan logic, since it will
+	 * fallback to the sw_scan for active scan request.
+	 **/
+	wiphy->max_scan_ssids = 4;
+	wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+
+	hw->max_rates = IEEE80211_TX_MAX_RATES;
+	hw->max_report_rates = IEEE80211_TX_MAX_RATES;
+	hw->max_rate_tries = 1;
+
+	hw->max_tx_aggregation_subframes = conf->ce_max_agg_size_tx;
+	hw->max_rx_aggregation_subframes = conf->ce_max_agg_size_rx;
+
+	hw->vif_data_size = sizeof(struct cl_vif);
+	hw->sta_data_size = sizeof(struct cl_sta);
+
+	hw->extra_tx_headroom = 0;
+	hw->queues = IEEE80211_MAX_QUEUES;
+	hw->offchannel_tx_hw_queue = CL_HWQ_VO;
+
+	if (!cl_band_is_6g(cl_hw)) {
+		if (conf->ci_ht_rxldpc_en)
+			sband_ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+		sband_ht_cap->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+		sband_vht_cap->cap |= cl_hw->conf->ci_max_mpdu_len;
+		if (conf->ci_bf_en) {
+			sband_vht_cap->cap |=
+				IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+				IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+				(3 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) |
+				(3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
+		}
+	}
+
+	if (cl_band_is_5g(cl_hw) || (cl_band_is_24g(cl_hw) && conf->ci_vht_cap_24g)) {
+		if (bw == CHNL_BW_160)
+			sband_vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+
+		sband_vht_cap->cap |= (conf->ci_max_ampdu_len_exp <<
+				       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
+
+		if (conf->ci_vht_rxldpc_en)
+			sband_vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+		sband_vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
+		sband_vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+
+		sband_vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(0);
+		sband_vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(0);
+
+		for (i = 0; i < rx_nss; i++)
+			sband_vht_cap->vht_mcs.rx_mcs_map |=
+				cpu_to_le16(cl_vht_mcs_supp_rx(cl_hw, i) << (i * 2));
+
+		for (; i < 8; i++)
+			sband_vht_cap->vht_mcs.rx_mcs_map |=
+				cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+		for (i = 0; i < tx_nss; i++)
+			sband_vht_cap->vht_mcs.tx_mcs_map |=
+				cpu_to_le16(cl_vht_mcs_supp_tx(cl_hw, i) << (i * 2));
+
+		for (; i < 8; i++)
+			sband_vht_cap->vht_mcs.tx_mcs_map |=
+				cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+
+		sband_vht_cap->vht_supported = true;
+	}
+
+	/* 6GHz band supports HE only */
+	if (!cl_band_is_6g(cl_hw))
+		for (i = 0; i < rx_nss; i++)
+			sband_ht_cap->mcs.rx_mask[i] = U8_MAX;
+
+	cl_set_he_capab(cl_hw);
+
+	/* Get channels and power limitations information from ChannelInfo file */
+	cl_chan_info_init(cl_hw);
+
+	if (cl_band_is_6g(cl_hw)) {
+		wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+		wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+		wiphy->bands[NL80211_BAND_6GHZ] = sband;
+	} else if (cl_band_is_5g(cl_hw)) {
+		wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+		wiphy->bands[NL80211_BAND_5GHZ] = sband;
+		wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+	} else {
+		wiphy->bands[NL80211_BAND_2GHZ] = sband;
+		wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+		wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+	}
+}
+
+enum he_pkt_ext_constellations {
+	HE_PKT_EXT_BPSK = 0,
+	HE_PKT_EXT_QPSK,
+	HE_PKT_EXT_16QAM,
+	HE_PKT_EXT_64QAM,
+	HE_PKT_EXT_256QAM,
+	HE_PKT_EXT_1024QAM,
+	HE_PKT_EXT_RESERVED,
+	HE_PKT_EXT_NONE,
+};
+
+static u8 mcs_to_constellation[WRS_MCS_MAX_HE] = {
+	HE_PKT_EXT_BPSK,
+	HE_PKT_EXT_QPSK,
+	HE_PKT_EXT_QPSK,
+	HE_PKT_EXT_16QAM,
+	HE_PKT_EXT_16QAM,
+	HE_PKT_EXT_64QAM,
+	HE_PKT_EXT_64QAM,
+	HE_PKT_EXT_64QAM,
+	HE_PKT_EXT_256QAM,
+	HE_PKT_EXT_256QAM,
+	HE_PKT_EXT_1024QAM,
+	HE_PKT_EXT_1024QAM
+};
+
+#define QAM_THR_1 0
+#define QAM_THR_2 1
+#define QAM_THR_MAX 2
+
+static u8 cl_get_ppe_val(u8 *ppe, u8 ppe_pos_bit)
+{
+	u8 byte_num = ppe_pos_bit / 8;
+	u8 bit_num = ppe_pos_bit % 8;
+	u8 residue_bits;
+	u8 res;
+
+	if (bit_num <= 5)
+		return (ppe[byte_num] >> bit_num) &
+		       (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);
+
+	/*
+	 * If bit_num > 5, we have to combine bits with next byte.
+	 * Calculate how many bits we need to take from current byte (called
+	 * here "residue_bits"), and add them to bits from next byte.
+	 */
+	residue_bits = 8 - bit_num;
+
+	res = (ppe[byte_num + 1] &
+	       (BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<
+	      residue_bits;
+	res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);
+
+	return res;
+}
+
+static void cl_set_fixed_ppe_val(u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE], u8 dur)
+{
+	u8 val = ((dur << 6) | (dur << 4) | (dur << 2) | dur);
+
+	memset(pe_dur, val, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+}
+
+void cl_cap_ppe_duration(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+			 u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE])
+{
+	/* Force NVRAM parameter */
+	if (cl_hw->conf->ci_pe_duration <= PPE_16US) {
+		cl_set_fixed_ppe_val(pe_dur, cl_hw->conf->ci_pe_duration);
+		return;
+	}
+
+	/*
+	 * If STA sets the PPE Threshold Present subfield to 0,
+	 * the value should be set according to the Nominal Packet Padding subfield
+	 */
+	if ((sta->he_cap.he_cap_elem.phy_cap_info[6] &
+	     IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) {
+		switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
+			IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK) {
+		case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US:
+			cl_set_fixed_ppe_val(pe_dur, PPE_0US);
+			break;
+		case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US:
+			cl_set_fixed_ppe_val(pe_dur, PPE_8US);
+			break;
+		case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US:
+		default:
+			cl_set_fixed_ppe_val(pe_dur, PPE_16US);
+			break;
+		}
+
+		return;
+	}
+
+	/*
+	 * struct iwl_he_pkt_ext - QAM thresholds
+	 * The required PPE is set via HE Capabilities IE, per Nss x BW x MCS
+	 * The IE is organized in the following way:
+	 * Support for Nss x BW (or RU) matrix:
+	 *	(0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
+	 * Each entry contains 2 QAM thresholds for 8us and 16us:
+	 *	0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
+	 * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
+	 *	QAM_tx < QAM_th1            --> PPE=0us
+	 *	QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
+	 *	QAM_th2 <= QAM_tx           --> PPE=16us
+	 * @pkt_ext_qam_th: QAM thresholds
+	 *	For each Nss/Bw define 2 QAM thrsholds (0..5)
+	 *	For rates below the low_th, no need for PPE
+	 *	For rates between low_th and high_th, need 8us PPE
+	 *	For rates equal or higher then the high_th, need 16us PPE
+	 *	Nss (0-siso, 1-mimo2) x BW (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz) x
+	 *		(0-low_th, 1-high_th)
+	 */
+	u8 pkt_ext_qam_th[WRS_SS_MAX][CHNL_BW_MAX][QAM_THR_MAX];
+
+	/* If PPE Thresholds exist, parse them into a FW-familiar format. */
+	u8 nss = (sta->he_cap.ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) + 1;
+	u8 ru_index_bitmap = u32_get_bits(sta->he_cap.ppe_thres[0],
+					  IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
+	u8 *ppe = &sta->he_cap.ppe_thres[0];
+	u8 ppe_pos_bit = 7; /* Starting after PPE header */
+	u8 bw, ss, mcs, constellation;
+
+	if (nss > WRS_SS_MAX)
+		nss = WRS_SS_MAX;
+
+	for (ss = 0; ss < nss; ss++) {
+		u8 ru_index_tmp = ru_index_bitmap << 1;
+
+		for (bw = 0; bw <= cl_hw->bw; bw++) {
+			ru_index_tmp >>= 1;
+			if (!(ru_index_tmp & 1))
+				continue;
+
+			pkt_ext_qam_th[ss][bw][QAM_THR_2] = cl_get_ppe_val(ppe, ppe_pos_bit);
+			ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+			pkt_ext_qam_th[ss][bw][QAM_THR_1] = cl_get_ppe_val(ppe, ppe_pos_bit);
+			ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
+		}
+	}
+
+	/* Reset PE duration before filling it */
+	memset(pe_dur, 0, CHNL_BW_MAX * WRS_MCS_MAX_HE);
+
+	for (ss = 0; ss < nss; ss++) {
+		for (bw = 0; bw <= cl_hw->bw; bw++) {
+			for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+				constellation = mcs_to_constellation[mcs];
+
+				if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_1])
+					pe_dur[bw][mcs] |= (PPE_0US << (ss * 2));
+				else if (constellation < pkt_ext_qam_th[ss][bw][QAM_THR_2])
+					pe_dur[bw][mcs] |= (PPE_8US << (ss * 2));
+				else
+					pe_dur[bw][mcs] |= (PPE_16US << (ss * 2));
+			}
+		}
+	}
+}
+
+static void cl_ops_tx_agg(struct cl_hw *cl_hw,
+			  struct sk_buff *skb,
+			  struct ieee80211_tx_info *tx_info,
+			  struct cl_sta *cl_sta)
+{
+	cl_hw->tx_packet_cntr.forward.from_mac_agg++;
+
+	if (!cl_sta) {
+		struct cl_vif *cl_vif =
+			(struct cl_vif *)tx_info->control.vif->drv_priv;
+		u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+		u8 ac = tid_to_ac[tid];
+
+		kfree_skb(skb);
+		cl_dbg_err(cl_hw, "cl_sta null in agg packet\n");
+		cl_hw->tx_packet_cntr.drop.sta_null_in_agg++;
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		return;
+	}
+
+	/* AMSDU in HW can work only with header conversion. */
+	tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+	cl_tx_agg(cl_hw, cl_sta, skb, false, true);
+}
+
+static void cl_ops_tx_single(struct cl_hw *cl_hw,
+			     struct sk_buff *skb,
+			     struct ieee80211_tx_info *tx_info,
+			     struct cl_sta *cl_sta,
+			     struct ieee80211_sta *sta)
+{
+	bool is_vns = cl_vns_is_very_near(cl_hw, cl_sta, skb);
+
+	cl_hw->tx_packet_cntr.forward.from_mac_single++;
+	if (cl_hw->tx_db.block_prob_resp) {
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+		if (ieee80211_is_probe_resp(hdr->frame_control)) {
+			struct cl_vif *cl_vif = NETDEV_TO_CL_VIF(skb->dev);
+			u8 ac = cl_vif->vif->hw_queue[skb_get_queue_mapping(skb)];
+
+			cl_tx_single_free_skb(cl_hw, skb);
+			cl_hw->tx_packet_cntr.drop.probe_response++;
+			cl_vif->trfc_cntrs[ac].tx_dropped++;
+			return;
+		}
+	}
+
+	if (sta) {
+		u32 sta_vht_cap = sta->vht_cap.cap;
+		struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+
+		if (!(sta_vht_cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+			goto out_tx;
+
+		if (ieee80211_is_assoc_resp(mgmt->frame_control)) {
+			int len = skb->len - (mgmt->u.assoc_resp.variable - skb->data);
+			const u8 *vht_cap_addr = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY,
+								 mgmt->u.assoc_resp.variable,
+								 len);
+
+			if (vht_cap_addr) {
+				struct ieee80211_vht_cap *vht_cap =
+					(struct ieee80211_vht_cap *)(2 + vht_cap_addr);
+
+				vht_cap->vht_cap_info &=
+					~(cpu_to_le32(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK |
+						      IEEE80211_VHT_CAP_SHORT_GI_160));
+			}
+		}
+	}
+
+out_tx:
+	cl_tx_single(cl_hw, cl_sta, skb, is_vns, true);
+}
+
+static u16 cl_ops_recalc_smallest_tbtt(struct cl_hw *cl_hw)
+{
+	struct wiphy *wiphy = cl_hw->hw->wiphy;
+	u8 cmb_idx = wiphy->n_iface_combinations - 1;
+	struct cl_vif *cl_vif = NULL;
+	u16 ret = 0;
+	u8 topology = cl_hw_get_iface_conf(cl_hw);
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		if (cl_vif->vif->type == NL80211_IFTYPE_STATION)
+			continue;
+		else if (ret == 0)
+			ret = cl_vif->vif->bss_conf.beacon_int;
+		else if (cl_vif->vif->bss_conf.beacon_int)
+			ret = min(ret, cl_vif->vif->bss_conf.beacon_int);
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	if (ret == 0) {
+		WARN_ONCE(topology != CL_IFCONF_STA && topology != CL_IFCONF_MESH_ONLY,
+			  "invalid smallest beacon interval");
+		return wiphy->iface_combinations[cmb_idx].beacon_int_min_gcd;
+	}
+	return ret;
+}
+
+static void cl_ops_set_mesh_tbtt(struct cl_hw *cl_hw, u16 this_beacon_int,
+				 u16 smallest_beacon_int)
+{
+	u16 div = this_beacon_int / smallest_beacon_int;
+
+	cl_hw->mesh_tbtt_div = (div > 0) ? div : 1;
+}
+
+void cl_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb)
+{
+	/*
+	 * Almost all traffic passing here is singles.
+	 * Only when opening a BA session some packets with
+	 * IEEE80211_TX_CTL_AMPDU set can pass here.
+	 * All skbs passing here did header conversion.
+	 */
+	struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_sta *sta = control->sta;
+	struct cl_sta *cl_sta = NULL;
+
+	if (sta) {
+		cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+		/*
+		 * Prior to STA connection sta can be set but we don't
+		 * want cl_sta to be used since it's not initialized yet
+		 */
+		if (cl_sta->sta_idx == STA_IDX_INVALID)
+			cl_sta = NULL;
+	}
+
+	if (cl_recovery_in_progress(cl_hw)) {
+		cl_hw->tx_packet_cntr.drop.in_recovery++;
+
+		if (cl_sta) {
+			struct cl_vif *cl_vif = cl_sta->cl_vif;
+
+			if (cl_vif) {
+				struct ieee80211_vif *vif = cl_vif->vif;
+				u8 hw_queue;
+
+				if (vif) {
+					hw_queue = vif->hw_queue[skb_get_queue_mapping(skb)];
+					cl_vif->trfc_cntrs[hw_queue].tx_dropped++;
+				}
+			}
+		}
+
+		cl_tx_drop_skb(skb);
+		return;
+	}
+
+	if (cl_sta && (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
+		goto fast_tx;
+
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+		cl_ops_tx_agg(cl_hw, skb, tx_info, cl_sta);
+	else
+		cl_ops_tx_single(cl_hw, skb, tx_info, cl_sta, sta);
+
+	return;
+
+fast_tx:
+	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+		cl_tx_fast_agg(cl_hw, cl_sta, skb, true);
+	else
+		cl_tx_fast_single(cl_hw, cl_sta, skb, true);
+}
+
+int cl_ops_start(struct ieee80211_hw *hw)
+{
+	/*
+	 * Called before the first netdevice attached to the hardware
+	 * is enabled. This should turn on the hardware and must turn on
+	 * frame reception (for possibly enabled monitor interfaces.)
+	 * Returns negative error codes, these may be seen in userspace,
+	 * or zero.
+	 * When the device is started it should not have a MAC address
+	 * to avoid acknowledging frames before a non-monitor device
+	 * is added.
+	 * Must be implemented and can sleep.
+	 * It does not return until the firmware is up and running.
+	 */
+	int error = 0;
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+
+	if (!cl_hw->ipc_env) {
+		CL_DBG_ERROR(cl_hw, "ipc_env is NULL!\n");
+		return -ENODEV;
+	}
+
+	/* Exits if device is already started */
+	if (WARN_ON(test_bit(CL_DEV_STARTED, &cl_hw->drv_flags)))
+		return -EBUSY;
+
+	/* Device is now started.
+	 * Set CL_DEV_STARTED bit before the calls to other messages sent to
+	 * firmware, to prevent them from being blocked*
+	 */
+
+	set_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+
+	if (!cl_recovery_in_progress(cl_hw)) {
+		/* Read version */
+		error = cl_version_update(cl_hw);
+		if (error)
+			return error;
+
+		error = cl_temperature_diff_e2p_read(cl_hw);
+		if (error)
+			return error;
+	}
+
+	/* Set firmware debug module filter */
+	error = cl_msg_tx_dbg_set_ce_mod_filter(cl_hw, conf->ci_fw_dbg_module);
+	if (error)
+		return error;
+
+	/* Set firmware debug severity level */
+	error = cl_msg_tx_dbg_set_sev_filter(cl_hw, conf->ci_fw_dbg_severity);
+	if (error)
+		return error;
+
+	/* Set firmware rate fallbacks */
+	error = cl_msg_tx_set_rate_fallback(cl_hw);
+	if (error)
+		return error;
+
+	error = cl_msg_tx_ndp_tx_control(cl_hw,
+					 conf->ci_sensing_ndp_tx_chain_mask,
+					 conf->ci_sensing_ndp_tx_bw,
+					 conf->ci_sensing_ndp_tx_format,
+					 conf->ci_sensing_ndp_tx_num_ltf);
+	if (error)
+		return error;
+
+	/* Set default, multicast, broadcast rate */
+	cl_rate_ctrl_set_default(cl_hw);
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	cl_dyn_mcast_rate_set(cl_hw);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_set(cl_hw, 0);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+
+	ieee80211_wake_queues(hw);
+
+	clear_bit(CL_DEV_INIT, &cl_hw->drv_flags);
+
+	cl_edca_hw_conf(cl_hw);
+
+	if (!cl_hw->chip->conf->ce_calib_runtime_en) {
+		cl_calib_dcoc_init_calibration(cl_hw);
+
+		if (cl_hw->chip->conf->ce_production_mode)
+			cl_calib_iq_init_production(cl_hw);
+		else if (!cl_hw_other || test_bit(CL_DEV_STARTED, &cl_hw_other->drv_flags))
+			cl_calib_iq_init_calibration(cl_hw);
+	}
+
+	return error;
+}
+
+void cl_ops_stop(struct ieee80211_hw *hw)
+{
+	/*
+	 * Called after last netdevice attached to the hardware
+	 * is disabled. This should turn off the hardware (at least
+	 * it must turn off frame reception.)
+	 * May be called right after add_interface if that rejects
+	 * an interface. If you added any work onto the mac80211 workqueue
+	 * you should ensure to cancel it on this callback.
+	 * Must be implemented and can sleep.
+	 */
+	struct cl_hw *cl_hw = hw->priv;
+
+	/* Stop mac80211 queues */
+	ieee80211_stop_queues(hw);
+
+	/* Go to idle */
+	cl_msg_tx_set_idle(cl_hw, MAC_IDLE_SYNC, true);
+
+	/*
+	 * Clear CL_DEV_STARTED to prevent message to be sent (besides reset and start).
+	 * It also blocks transmission of new packets
+	 */
+	clear_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+
+	cl_hw->num_ap_started = 0;
+	cl_hw->channel = 0;
+	cl_hw->radio_status = RADIO_STATUS_OFF;
+}
+
+static int cl_add_interface_to_firmware(struct cl_hw *cl_hw,
+					struct ieee80211_vif *vif, u8 vif_index)
+{
+	struct mm_add_if_cfm *add_if_cfm;
+	int ret = 0;
+
+	/* Forward the information to the firmware */
+	ret = cl_msg_tx_add_if(cl_hw, vif, vif_index);
+	if (ret)
+		return ret;
+
+	add_if_cfm = (struct mm_add_if_cfm *)(cl_hw->msg_cfm_params[MM_ADD_IF_CFM]);
+	if (!add_if_cfm)
+		return -ENOMSG;
+
+	if (add_if_cfm->status != 0) {
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", add_if_cfm->status);
+		ret = -EIO;
+	}
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_ADD_IF_CFM);
+
+	return ret;
+}
+
+static enum cl_iface_conf cl_recalc_hw_iface(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif = NULL;
+	u8 num_ap = 0, num_sta = 0, num_mp = 0;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		switch (cl_vif->vif->type) {
+		case NL80211_IFTYPE_AP:
+			num_ap++;
+			break;
+		case NL80211_IFTYPE_STATION:
+			num_sta++;
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			num_mp++;
+			break;
+		default:
+			read_unlock_bh(&cl_hw->vif_db.lock);
+			return CL_IFCONF_MAX;
+		}
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	if (num_ap > 0 && num_sta == 0 && num_mp == 0)
+		return CL_IFCONF_AP;
+	if (num_ap == 0 && num_sta == 1 && num_mp == 0)
+		return CL_IFCONF_STA;
+	if (num_ap == 1 && num_sta == 1 && num_mp == 0)
+		return CL_IFCONF_REPEATER;
+	if (num_ap > 0 && num_sta == 0 && num_mp == 1)
+		return CL_IFCONF_MESH_AP;
+	if (num_ap == 0 && num_sta == 0 && num_mp == 1)
+		return CL_IFCONF_MESH_ONLY;
+
+	return CL_IFCONF_MAX;
+}
+
+int cl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	/*
+	 * Called when a netdevice attached to the hardware is
+	 * enabled. Because it is not called for monitor mode devices, start
+	 * and stop must be implemented.
+	 * The driver should perform any initialization it needs before
+	 * the device can be enabled. The initial configuration for the
+	 * interface is given in the conf parameter.
+	 * The callback may refuse to add an interface by returning a
+	 * negative error code (which will be seen in userspace.)
+	 * Must be implemented and can sleep.
+	 */
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
+	struct net_device *dev = NULL;
+	u8 ac;
+
+	if (!wdev)
+		return -ENODEV;
+
+	dev = wdev->netdev;
+	if (!dev)
+		return -ENODEV;
+
+	/*
+	 * In recovery just send the message to firmware and exit
+	 * (also make sure cl_vif already exists).
+	 */
+	if (cl_recovery_in_progress(cl_hw) && cl_vif_get_by_dev(cl_hw, dev))
+		return cl_add_interface_to_firmware(cl_hw, vif, cl_vif->vif_index);
+
+	cl_vif->cl_hw = cl_hw;
+	cl_vif->vif = vif;
+	cl_vif->dev = dev;
+	cl_vif->vif_index = cl_mac_addr_find_idx(cl_hw, vif->addr);
+
+	/* MAC address not found - invalid address */
+	if (cl_vif->vif_index == BSS_INVALID_IDX) {
+		cl_dbg_err(cl_hw, "Error: Invalid MAC address %pM for vif %s\n",
+			   vif->addr, dev->name);
+
+		return -EINVAL;
+	}
+
+	if (chip->conf->ce_production_mode || vif->type == NL80211_IFTYPE_STATION)
+		cl_vif->tx_en = true;
+
+	cl_vif_key_init(cl_vif);
+
+	if (cl_add_interface_to_firmware(cl_hw, vif, cl_vif->vif_index))
+		return -EINVAL;
+
+	cl_vif->conn_data = kzalloc(sizeof(*cl_vif->conn_data), GFP_KERNEL);
+	if (!cl_vif->conn_data) {
+		cl_dbg_verbose(cl_hw, "Memory allocation for conn_data failed !!!\n");
+		return -ENOMEM;
+	}
+
+	if (vif->type != NL80211_IFTYPE_STATION)
+		vif->cab_queue = CL_HWQ_VO;
+
+	cl_vif_add(cl_hw, cl_vif);
+	cl_hw_set_iface_conf(cl_hw, cl_recalc_hw_iface(cl_hw));
+
+	for (ac = 0; ac < AC_MAX; ac++)
+		vif->hw_queue[ac] = cl_ac2hwq[ac];
+
+	if (cl_radio_is_on(cl_hw) && vif->type == NL80211_IFTYPE_AP)
+		cl_vif->tx_en = true;
+
+	/* Set active state in station mode after ifconfig down and up */
+	if (cl_hw->conf->ce_listener_en)
+		cl_radio_on(cl_hw);
+	else if (cl_radio_is_on(cl_hw) && vif->type == NL80211_IFTYPE_STATION)
+		cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE, true);
+
+	if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+		tasklet_init(&cl_hw->tx_mesh_bcn_task, cl_tx_bcn_mesh_task,
+			     (unsigned long)cl_vif);
+		cl_radio_on(cl_hw);
+		cl_vif->tx_en = true;
+		cl_vif->mesh_basic_rates = cl_cap_set_mesh_basic_rates(cl_hw);
+	}
+
+	return 0;
+}
+
+void cl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	/*
+	 * Notifies a driver that an interface is going down.
+	 * The stop callback is called after this if it is the last interface
+	 * and no monitor interfaces are present.
+	 * When all interfaces are removed, the MAC address in the hardware
+	 * must be cleared so the device no longer acknowledges packets,
+	 * the mac_addr member of the conf structure is, however, set to the
+	 * MAC address of the device going away.
+	 * Hence, this callback must be implemented. It can sleep.
+	 */
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+	if (vif->type == NL80211_IFTYPE_MESH_POINT)
+		tasklet_kill(&cl_hw->tx_mesh_bcn_task);
+
+	if (!cl_recovery_in_progress(cl_hw)) {
+		kfree(cl_vif->conn_data);
+		cl_vif_remove(cl_hw, cl_vif);
+		cl_msg_tx_remove_if(cl_hw, cl_vif->vif_index);
+	} else {
+		cl_vif_remove(cl_hw, cl_vif);
+	}
+	cl_hw_set_iface_conf(cl_hw, cl_recalc_hw_iface(cl_hw));
+
+	cl_vif_key_deinit(cl_vif);
+
+	cl_vif->cl_hw = NULL;
+	cl_vif->vif = NULL;
+	cl_vif->dev = NULL;
+}
+
+static int cl_ops_conf_change_channel(struct ieee80211_hw *hw)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
+	enum nl80211_chan_width width = chandef->width;
+	u32 primary = chandef->chan->center_freq;
+	u32 center = chandef->center_freq1;
+	u32 channel = ieee80211_frequency_to_channel(primary);
+	u8 bw = cl_width_to_bw(width);
+	int ret = 0;
+
+	if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags))
+		return 0;
+
+	/* WA: for the first set-channel in production mode use the nvram values */
+	if (cl_hw_is_prod_or_listener(cl_hw) || !IS_REAL_PHY(chip)) {
+		ret = cl_chandef_get_default(cl_hw, &channel, &bw,
+					     &width, &primary, &center);
+
+		if (ret != 0)
+			return ret;
+	}
+
+	cl_dbg_trace(cl_hw,
+		     "channel(%u), primary(%u), center(%u), width(%u), bw(%u)\n",
+		     channel, primary, center, width, bw);
+
+	if (cl_hw->channel == channel &&
+	    cl_hw->bw == bw &&
+	    cl_hw->primary_freq == primary &&
+	    cl_hw->center_freq == center)
+		goto dfs_cac;
+
+	/*
+	 * Flush the pending data to ensure that we will finish the pending
+	 * transmissions before changing the channel
+	 */
+	if (IS_REAL_PHY(chip))
+		cl_ops_flush(hw, NULL, -1, false);
+
+	if (cl_hw->chip->conf->ce_calib_runtime_en)
+		ret = cl_calib_runtime_and_switch_channel(cl_hw, channel, bw, primary, center);
+	else
+		ret = cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center,
+					    CL_CALIB_PARAMS_DEFAULT_STRUCT);
+	if (ret)
+		return -EIO;
+
+	/**
+	 * Set preffered channel type to HT+/- based on current hapd
+	 * configuration.
+	 */
+	if (cl_band_is_24g(cl_hw)) {
+		u8 ct = cfg80211_get_chandef_type(&hw->conf.chandef);
+
+		switch (ct) {
+		case NL80211_CHAN_HT40PLUS:
+		case NL80211_CHAN_HT40MINUS:
+			if (ct != cl_hw->ht40_preffered_ch_type) {
+				cl_dbg_info(cl_hw, "HT40 preffered channel type=%s\n",
+					    ct == NL80211_CHAN_HT40PLUS ? "HT+" : "HT-");
+				cl_hw->ht40_preffered_ch_type = ct;
+			}
+		}
+	}
+
+	cl_wrs_api_bss_set_bw(cl_hw, bw);
+
+dfs_cac:
+	/*
+	 * TODO: This callback is being spawned even in STA mode, moreover,
+	 * "start_ap" comes later - it is unclear whether we are an AP at this
+	 * stage. Likely, may be solved by moving "force_cac_*" states to beginning
+	 * of "start_ap", but the request should stay in current callback
+	 */
+	if (!cl_band_is_5g(cl_hw))
+		return 0;
+
+	/*
+	 * Radar listening may occur at DFS channels during in-service mode,
+	 * so CAC may clear the channels, but radar listening should be
+	 * still active, and should start it as soon as we can.
+	 */
+	if (hw->conf.radar_enabled) {
+		/* If channel policy demans to be in CAC - need to request it */
+		if (!cl_dfs_is_in_cac(cl_hw) &&
+		    chandef->chan->dfs_state == NL80211_DFS_USABLE)
+			cl_dfs_request_cac(cl_hw, true);
+
+		if (!cl_dfs_radar_listening(cl_hw))
+			cl_dfs_radar_listen_start(cl_hw);
+	} else {
+		/*
+		 * No sense to continue be in silent mode if the channel was
+		 * cleared
+		 */
+
+		if (cl_dfs_is_in_cac(cl_hw) &&
+		    chandef->chan->dfs_state == NL80211_DFS_AVAILABLE)
+			cl_dfs_request_cac(cl_hw, false);
+
+		if (cl_dfs_radar_listening(cl_hw))
+			cl_dfs_radar_listen_end(cl_hw);
+	}
+	/*
+	 * We have just finished channel switch.
+	 * Now, check what to do with CAC.
+	 */
+	if (cl_dfs_requested_cac(cl_hw))
+		cl_dfs_force_cac_start(cl_hw);
+	else if (cl_dfs_is_in_cac(cl_hw))
+		cl_dfs_force_cac_end(cl_hw);
+
+	return 0;
+}
+
+int cl_ops_config(struct ieee80211_hw *hw, u32 changed)
+{
+	/*
+	 * Handler for configuration requests. IEEE 802.11 code calls this
+	 * function to change hardware configuration, e.g., channel.
+	 * This function should never fail but returns a negative error code
+	 * if it does. The callback can sleep
+	 */
+	int error = 0;
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
+		error = cl_ops_conf_change_channel(hw);
+
+	return error;
+}
+
+/*
+ * @bss_info_changed: Handler for configuration requests related to BSS
+ *  parameters that may vary during BSS's lifespan, and may affect low
+ *  level driver (e.g. assoc/disassoc status, erp parameters).
+ *  This function should not be used if no BSS has been set, unless
+ *  for association indication. The @changed parameter indicates which
+ *  of the bss parameters has changed when a call is made. The callback
+ *  can sleep.
+ */
+void cl_ops_bss_info_changed(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_bss_conf *info,
+			     u32 changed)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		if (cl_msg_tx_set_associated(cl_hw, info))
+			return;
+	}
+
+	if (changed & BSS_CHANGED_BSSID) {
+		if (cl_msg_tx_set_bssid(cl_hw, info->bssid, cl_vif->vif_index))
+			return;
+	}
+
+	if (changed & BSS_CHANGED_BEACON_INT) {
+		u16 smallest_int = cl_ops_recalc_smallest_tbtt(cl_hw);
+
+		cl_hw->smallest_beacon_int = smallest_int;
+
+		if (vif->type == NL80211_IFTYPE_AP ||
+		    cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_MESH_ONLY) {
+			if (cl_msg_tx_set_beacon_int(cl_hw, info->beacon_int,
+						     cl_vif->vif_index))
+				return;
+			if (cl_msg_tx_dtim(cl_hw, info->dtim_period))
+				return;
+		}
+
+		if (vif->type == NL80211_IFTYPE_MESH_POINT &&
+		    cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_MESH_AP) {
+			cl_ops_set_mesh_tbtt(cl_hw, info->beacon_int, smallest_int);
+		}
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		int shift = hw->wiphy->bands[hw->conf.chandef.chan->band]->bitrates[0].hw_value;
+
+		if (vif->type == NL80211_IFTYPE_MESH_POINT)
+			if (cl_vif->mesh_basic_rates)
+				info->basic_rates = cl_vif->mesh_basic_rates;
+
+		if (cl_msg_tx_set_basic_rates(cl_hw, info->basic_rates << shift))
+			return;
+		/* TODO: check if cl_msg_tx_set_mode() should be called */
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		/*
+		 * We must be in 11g mode here
+		 * TODO: we can add a check on the mode
+		 */
+		if (cl_msg_tx_set_slottime(cl_hw, info->use_short_slot))
+			return;
+	}
+
+	if (changed & BSS_CHANGED_BANDWIDTH)
+		cl_wrs_api_bss_set_bw(cl_hw, cl_width_to_bw(info->chandef.width));
+
+	if (changed & BSS_CHANGED_TXPOWER) {
+		if (info->txpower_type == NL80211_TX_POWER_FIXED) {
+			cl_hw->new_tx_power = info->txpower;
+			cl_power_tables_update(cl_hw, &cl_hw->phy_data_info.data->pwr_tables);
+			cl_msg_tx_refresh_power(cl_hw);
+		}
+	}
+
+	if (changed & BSS_CHANGED_BEACON) {
+		struct beacon_data *beacon = NULL;
+		struct ieee80211_sub_if_data *sdata =
+			container_of(vif, struct ieee80211_sub_if_data, vif);
+		struct ieee80211_ht_cap *ht_cap = NULL;
+		struct ieee80211_vht_cap *vht_cap = NULL;
+		struct ieee80211_he_cap_elem *he_cap = NULL;
+		bool sgi_en = false;
+		u8 hw_mode = cl_hw->hw_mode;
+		enum cl_wireless_mode wireless_mode = cl_hw->wireless_mode;
+
+		rcu_read_lock();
+
+		if (sdata->vif.type == NL80211_IFTYPE_AP)
+			beacon = rcu_dereference(sdata->u.ap.beacon);
+		else if (ieee80211_vif_is_mesh(&sdata->vif))
+			beacon = rcu_dereference(sdata->u.mesh.beacon);
+
+		if (beacon) {
+			size_t ies_len = beacon->tail_len;
+			const u8 *ies = beacon->tail;
+			const u8 *cap =  NULL;
+			int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+			int len = beacon->head_len - var_offset;
+			const u8 *var_pos = beacon->head + var_offset;
+			const u8 *rate_ie = NULL;
+
+			cl_vif->wmm_enabled = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+								      WLAN_OUI_TYPE_MICROSOFT_WMM,
+								      ies,
+								      ies_len);
+			cl_dbg_info(cl_hw, "vif=%d wmm_enabled=%d\n",
+				    cl_vif->vif_index,
+				    cl_vif->wmm_enabled);
+
+			cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+			if (cap && cap[1] >= sizeof(*ht_cap)) {
+				ht_cap = (void *)(cap + 2);
+				sgi_en |= (le16_to_cpu(ht_cap->cap_info) &
+					   IEEE80211_HT_CAP_SGI_20) ||
+					  (le16_to_cpu(ht_cap->cap_info) &
+					   IEEE80211_HT_CAP_SGI_40);
+			}
+
+			cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
+			if (cap && cap[1] >= sizeof(*vht_cap)) {
+				vht_cap = (void *)(cap + 2);
+				sgi_en |= (le32_to_cpu(vht_cap->vht_cap_info) &
+					   IEEE80211_VHT_CAP_SHORT_GI_80) ||
+					  (le32_to_cpu(vht_cap->vht_cap_info) &
+					   IEEE80211_VHT_CAP_SHORT_GI_160);
+			}
+
+			cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
+			if (cap && cap[1] >= sizeof(*he_cap) + 1)
+				he_cap = (void *)(cap + 3);
+
+			rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
+			if (rate_ie) {
+				if (cl_band_is_24g(cl_hw))
+					if (cl_is_valid_g_rates(rate_ie))
+						hw_mode = cl_hw->conf->ci_cck_in_hw_mode ?
+							     HW_MODE_BG : HW_MODE_G;
+					else
+						hw_mode = HW_MODE_B;
+				else
+					hw_mode = HW_MODE_A;
+			}
+		} else {
+			cl_dbg_warn(cl_hw, "beacon_data not set!\n");
+		}
+
+		rcu_read_unlock();
+
+		/*
+		 * FIXME: 1. WRS has no VIF-specific capabs settings.
+		 *        2. WRS has no BW-specific SGI configuration support.
+		 **/
+
+		/* If found any capabs info and state is different - update sgi */
+		if ((ht_cap || vht_cap) && (cl_wrs_api_bss_is_sgi_en(cl_hw) != sgi_en))
+			cl_wrs_api_bss_set_sgi(cl_hw, sgi_en);
+
+		if (hw_mode != cl_hw->hw_mode) {
+			cl_hw->hw_mode = hw_mode;
+			sgi_en =
+				(ht_cap || vht_cap) ? sgi_en : cl_hw->conf->ci_short_guard_interval;
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+			cl_dyn_bcast_update(cl_hw);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+			cl_dyn_mcast_update(cl_hw);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+			cl_wrs_api_bss_capab_update(cl_hw, cl_hw->bw, sgi_en);
+		}
+
+		wireless_mode = cl_recalc_wireless_mode(cl_hw, !!ht_cap, !!vht_cap, !!he_cap);
+		if (wireless_mode != cl_hw->wireless_mode) {
+			sgi_en =
+				(ht_cap || vht_cap) ? sgi_en : cl_hw->conf->ci_short_guard_interval;
+			cl_hw->wireless_mode = wireless_mode;
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+			cl_dyn_mcast_update(cl_hw);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+			cl_wrs_api_bss_capab_update(cl_hw, cl_hw->bw, sgi_en);
+		}
+	}
+}
+
+int cl_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	set_bit(CL_DEV_AP_STARTED, &cl_hw->drv_flags);
+
+	cl_hw->num_ap_started++;
+	if (cl_hw->conf->ce_radio_on) {
+		if (cl_radio_is_off(cl_hw))
+			cl_radio_on(cl_hw);
+
+		return 0;
+	}
+
+	/*
+	 * Set active state when cl_ops_start_ap() is called not during first driver start
+	 * but rather after removing all interfaces and then doing up again to one interface.
+	 */
+	if (cl_radio_is_on(cl_hw) && !cl_recovery_in_progress(cl_hw))
+		cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE, true);
+
+	return 0;
+}
+
+void cl_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	/*
+	 * Unset CL_DEV_AP_STARTED in order to avoid
+	 * calling cl_ops_conf_change_channel after unloading the driver
+	 */
+	clear_bit(CL_DEV_AP_STARTED, &cl_hw->drv_flags);
+
+	cl_hw->num_ap_started--;
+
+	if (!cl_hw->num_ap_started)
+		cl_hw->channel = 0;
+}
+
+u64 cl_ops_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list)
+{
+	return netdev_hw_addr_list_count(mc_list);
+}
+
+void cl_ops_configure_filter(struct ieee80211_hw *hw, u32 changed_flags,
+			     u32 *total_flags, u64 multicast)
+{
+	/*
+	 * configure_filter: Configure the device's RX filter.
+	 * See the section "Frame filtering" for more information.
+	 * This callback must be implemented and can sleep.
+	 */
+	struct cl_hw *cl_hw = hw->priv;
+
+	cl_dbg_trace(cl_hw, "total_flags = 0x%08x\n", *total_flags);
+
+	/*
+	 * Reset our filter flags since our start/stop ops reset
+	 * the programmed settings
+	 */
+	if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags)) {
+		*total_flags = 0;
+		return;
+	}
+
+	if (multicast)
+		*total_flags |= FIF_ALLMULTI;
+	else
+		*total_flags &= ~FIF_ALLMULTI;
+
+	/* TODO: optimize with changed_flags vs multicast */
+	cl_msg_tx_set_filter(cl_hw, *total_flags, false);
+
+	*total_flags &= ~(1 << 31);
+}
+
+int cl_ops_set_key(struct ieee80211_hw *hw,
+		   enum set_key_cmd cmd,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta,
+		   struct ieee80211_key_conf *key)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	return cl_key_set(cl_hw, cmd, vif, sta, key);
+}
+
+void cl_ops_sw_scan_start(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  const u8 *mac_addr)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	cl_hw->sw_scan_in_progress = 1;
+
+	if (cl_hw->conf->ce_radio_on &&
+	    cl_radio_is_off(cl_hw) &&
+	    vif->type == NL80211_IFTYPE_STATION)
+		cl_radio_on(cl_hw);
+
+	if (cl_dfs_is_in_cac(cl_hw))
+		cl_dfs_force_cac_end(cl_hw);
+}
+
+void cl_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	cl_hw->sw_scan_in_progress = 0;
+}
+
+int cl_ops_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+		     enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	int error = 0;
+
+	if (old_state == new_state)
+		return 0;
+
+	if (old_state == IEEE80211_STA_NOTEXIST &&
+	    new_state == IEEE80211_STA_NONE) {
+		cl_sta_init_sta(cl_hw, sta);
+	} else if (old_state == IEEE80211_STA_AUTH &&
+		   new_state == IEEE80211_STA_ASSOC) {
+		error = cl_sta_add(cl_hw, vif, sta);
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		   new_state == IEEE80211_STA_AUTH) {
+		cl_sta_remove(cl_hw, vif, sta);
+	}
+
+	return error;
+}
+
+void cl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		       enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	bool is_ps = (bool)!cmd;
+
+	cl_sta_ps_notify(cl_hw, cl_sta, is_ps);
+}
+
+int cl_ops_conf_tx(struct ieee80211_hw *hw,
+		   struct ieee80211_vif *vif,
+		   u16 ac_queue,
+		   const struct ieee80211_tx_queue_params *params)
+{
+	/*
+	 * Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
+	 * bursting) for a hardware TX queue.
+	 * Returns a negative error code on failure.
+	 * The callback can sleep.
+	 */
+
+	/* We only handle STA edca here */
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		struct cl_hw *cl_hw = hw->priv;
+		struct ieee80211_he_mu_edca_param_ac_rec mu_edca = {0};
+		struct edca_params edca_params = {
+			.aifsn = (u8)(params->aifs),
+			.cw_min = (u8)(ilog2(params->cw_min + 1)),
+			.cw_max = (u8)(ilog2(params->cw_max + 1)),
+			.txop = (u8)(params->txop)
+		};
+
+		if (cl_hw->wireless_mode > WIRELESS_MODE_HT_VHT)
+			memcpy(&mu_edca, &params->mu_edca_param_rec, sizeof(mu_edca));
+
+		cl_edca_set(cl_hw, cl_ac2edca[ac_queue], &edca_params, &mu_edca);
+	}
+	return 0;
+}
+
+void cl_ops_sta_rc_update(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  u32 changed)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u8 bw = wrs_sta->max_rate_cap.bw;
+	u8 nss = wrs_sta->max_rate_cap.nss;
+
+	if (changed & IEEE80211_RC_SMPS_CHANGED)
+		cl_wrs_api_set_smps_mode(cl_hw, sta, sta->bandwidth);
+
+	WARN_ON(sta->rx_nss == 0);
+	if (changed & IEEE80211_RC_NSS_CHANGED)
+		nss = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+
+	if (changed & IEEE80211_RC_BW_CHANGED)
+		bw = sta->bandwidth;
+
+	if ((changed & IEEE80211_RC_NSS_CHANGED) || (changed & IEEE80211_RC_BW_CHANGED))
+		cl_wrs_api_nss_or_bw_changed(cl_hw, sta, nss, bw);
+}
+
+int cl_ops_ampdu_action(struct ieee80211_hw *hw,
+			struct ieee80211_vif *vif,
+			struct ieee80211_ampdu_params *params)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(params->sta);
+	int ret = 0;
+
+	switch (params->action) {
+	case IEEE80211_AMPDU_RX_START:
+		ret = cl_ampdu_rx_start(cl_hw, cl_sta, params->tid,
+					params->ssn, params->buf_size);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		cl_ampdu_rx_stop(cl_hw, cl_sta, params->tid);
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		ret = cl_ampdu_tx_start(cl_hw, vif, cl_sta, params->tid,
+					params->ssn);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		ret = cl_ampdu_tx_operational(cl_hw, cl_sta, params->tid,
+					      params->buf_size, params->amsdu);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		ret = cl_ampdu_tx_stop(cl_hw, vif, params->action, cl_sta,
+				       params->tid);
+		break;
+	default:
+		pr_warn("Error: Unknown AMPDU action (%d)\n", params->action);
+	}
+
+	return ret;
+}
+
+int cl_ops_post_channel_switch(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif)
+{
+	/* TODO: Need to handle post switch */
+	return 0;
+}
+
+void cl_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	int flush_duration;
+
+	if (test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags)) {
+		cl_dbg_verbose(cl_hw, ": bypassing (CL_DEV_HW_RESTART set)\n");
+		return;
+	}
+
+	/* Wait for a maximum time of 200ms until all pending frames are flushed */
+	for (flush_duration = 0; flush_duration < 200; flush_duration++) {
+		if (!cl_txq_frames_pending(cl_hw))
+			return;
+
+		/* Lets sleep and hope for the best */
+		usleep_range(1000, 2000);
+	}
+}
+
+bool cl_ops_tx_frames_pending(struct ieee80211_hw *hw)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	return cl_txq_frames_pending(cl_hw);
+}
+
+void cl_ops_reconfig_complete(struct ieee80211_hw *hw,
+			      enum ieee80211_reconfig_type reconfig_type)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	cl_recovery_reconfig_complete(cl_hw);
+}
+
+int cl_ops_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	if (cl_hw->phy_data_info.data)
+		*dbm = cl_power_get_max(cl_hw);
+	else
+		*dbm = 0;
+
+	return 0;
+}
+
+int cl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+	/* TODO: Fix this call */
+	return 0;
+}
+
+static void cl_ops_mgd_assoc(struct cl_hw *cl_hw, struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = container_of(vif, struct ieee80211_sub_if_data, vif);
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	struct ieee80211_sta *sta = ieee80211_find_sta(vif, sdata->u.mgd.bssid);
+
+	if (!sta) {
+		/* Should never happen */
+		cl_dbg_verbose(cl_hw, "sta is NULL !!!\n");
+		return;
+	}
+
+	cl_sta_mgd_add(cl_hw, cl_vif, sta);
+
+	if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_REPEATER) {
+		cl_vif_ap_tx_enable(cl_hw, true);
+		set_bit(CL_DEV_REPEATER, &cl_hw->drv_flags);
+	}
+}
+
+static void cl_ops_mgd_disassoc(struct cl_hw *cl_hw)
+{
+	if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_REPEATER) {
+		cl_vif_ap_tx_enable(cl_hw, false);
+		clear_bit(CL_DEV_REPEATER, &cl_hw->drv_flags);
+	}
+}
+
+void cl_ops_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			   const struct ieee80211_event *event)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	if (event->type == MLME_EVENT) {
+		if (event->u.mlme.data == ASSOC_EVENT &&
+		    event->u.mlme.status == MLME_SUCCESS)
+			cl_ops_mgd_assoc(cl_hw, vif);
+		else if (event->u.mlme.data == DEAUTH_TX_EVENT ||
+			 event->u.mlme.data == DEAUTH_RX_EVENT)
+			cl_ops_mgd_disassoc(cl_hw);
+	}
+}
+
+/* This function is required for PS flow - do not remove */
+int cl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
+{
+	return 0;
+}
+
+int cl_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+	struct cl_hw *cl_hw = hw->priv;
+
+	*rx_ant = cl_hw->mask_num_antennas;
+	*tx_ant = cl_hw->mask_num_antennas;
+
+	return 0;
+}
+
+u32 cl_ops_get_expected_throughput(struct ieee80211_hw *hw,
+				   struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+	return cl_sta->wrs_sta.tx_su_params.data_rate;
+}
+
+void cl_ops_sta_statistics(struct ieee80211_hw *hw,
+			   struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta,
+			   struct station_info *sinfo)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_sta *cl_sta = NULL;
+	u64 total_tx_success = 0, total_tx_fail = 0;
+	struct cl_wrs_params *wrs_params = NULL;
+
+	if (!sta)
+		return;
+
+	cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+	/*
+	 * Since cl8k implements rate control algorithm (sets IEEE80211_HW_HAS_RATE_CONTROL)
+	 * it is needed to initialize both rx/tx bitrates manually
+	 */
+	cl_wrs_lock_bh(&cl_hw->wrs_db);
+	wrs_params = &cl_sta->wrs_sta.tx_su_params;
+	cl_wrs_fill_sinfo_rates(&sinfo->txrate, wrs_params, cl_sta);
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+	cl_wrs_unlock_bh(&cl_hw->wrs_db);
+
+	/* mac80211 will fill sinfo stats if driver not set sinfo->filled flag */
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	cl_stats_get_tx(cl_hw, cl_sta, &total_tx_success, &total_tx_fail);
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
+	sinfo->tx_packets = total_tx_success;
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+	sinfo->tx_failed = total_tx_fail;
+
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
+	sinfo->rx_packets = cl_stats_get_rx(cl_hw, cl_sta);
+
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
+	sinfo->tx_bytes = cl_sta->tx_bytes;
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
+	sinfo->rx_bytes = cl_sta->rx_bytes;
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+	sinfo->tx_retries = cl_sta->retry_count;
+
+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+	sinfo->signal_avg = cl_stats_get_rssi(cl_hw, cl_sta);
+}
+
+int cl_ops_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
+{
+	struct ieee80211_conf *conf = &hw->conf;
+	struct cl_hw *cl_hw = hw->priv;
+	struct ieee80211_supported_band *sband = hw->wiphy->bands[conf->chandef.chan->band];
+	struct cl_chan_scanner *scanner = cl_hw->scanner;
+	struct cl_channel_stats *scanned_channel = NULL;
+	int chan_num;
+	u8 i;
+
+	if (idx >= sband->n_channels)
+		return -ENOENT;
+
+	survey->channel = &sband->channels[idx];
+	chan_num = ieee80211_frequency_to_channel(sband->channels[idx].center_freq);
+
+	for (i = 0; i < scanner->channels_num; i++) {
+		if (scanner->channels[i].channel == chan_num) {
+			scanned_channel = &scanner->channels[i];
+			break;
+		}
+	}
+
+	if (!scanned_channel) {
+		survey->filled = 0;
+		return 0;
+	}
+
+	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_SCAN |
+			 SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME_TX |
+			 SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BUSY |
+			 SURVEY_INFO_TIME_EXT_BUSY;
+
+	survey->noise = scanned_channel->ch_noise;
+
+	survey->time = scanned_channel->scan_time_ms;
+	survey->time_scan = survey->time;
+
+	survey->time_rx = div64_u64(scanned_channel->util_time_rx, USEC_PER_MSEC);
+	survey->time_tx = div64_u64(scanned_channel->util_time_tx, USEC_PER_MSEC);
+
+	survey->time_busy = div64_u64(scanned_channel->util_time_busy, USEC_PER_MSEC);
+	survey->time_ext_busy = survey->time_busy;
+
+	return 0;
+}
+
+static void cl_scan_completion_cb(struct cl_hw *cl_hw, void *arg)
+{
+	struct cl_chan_scanner *scanner = cl_hw->scanner;
+	struct cfg80211_scan_info info = {
+		.aborted = scanner->scan_aborted,
+	};
+
+	cl_dbg_trace(cl_hw, "Completed scan request, aborted: %u\n", info.aborted);
+
+	cl_scan_channel_switch(cl_hw, scanner->prescan_channel, scanner->prescan_bw, true);
+	ieee80211_scan_completed(cl_hw->hw, &info);
+}
+
+int cl_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		   struct ieee80211_scan_request *hw_req)
+{
+	struct cfg80211_scan_request *req = &hw_req->req;
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_chan_scanner *scanner = cl_hw->scanner;
+	u8 scan_channels[MAX_CHANNELS] = {0};
+	u8 i;
+	int ret = 0;
+
+	cl_dbg_trace(cl_hw, "Hardware scan request: n_channels:%u, n_ssids:%d\n",
+		     req->n_channels, req->n_ssids);
+
+	if (cl_hw->conf->ce_radio_on && cl_radio_is_off(cl_hw))
+		cl_radio_on(cl_hw);
+
+	ret = mutex_lock_interruptible(&scanner->cl_hw->set_channel_mutex);
+	if (ret != 0)
+		return ret;
+	scanner->prescan_bw = cl_hw->bw;
+	scanner->prescan_channel = cl_hw->channel;
+	mutex_unlock(&scanner->cl_hw->set_channel_mutex);
+
+	if (req->n_ssids > 0) {
+		/*
+		 * This is active scan request. We do not support it yet, so we
+		 * need to force the mac80211 to fallback to the sw_scan.
+		 */
+		cl_dbg_trace(cl_hw, "activating fall-back strategy - sw_scan\n");
+		return 1;
+	}
+
+	if (req->n_channels > ARRAY_SIZE(scan_channels)) {
+		cl_dbg_warn(cl_hw, "invalid number of channels to scan: %u\n",
+			    req->n_channels);
+		return -ERANGE;
+	}
+
+	for (i = 0; i < req->n_channels; ++i) {
+		if (req->channels[i]->band != cl_hw->nl_band) {
+			cl_dbg_warn(cl_hw, "band %u is invalid\n", req->channels[i]->band);
+			return -EINVAL;
+		}
+		scan_channels[i] = ieee80211_frequency_to_channel(req->channels[i]->center_freq);
+	}
+
+	ret = cl_trigger_off_channel_scan(scanner, req->duration, 0,
+					  scan_channels, CHNL_BW_20, req->n_channels,
+					  cl_scan_completion_cb, NULL);
+	return ret;
+}
+
+void cl_ops_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct cl_hw *cl_hw = hw->priv;
+	struct cl_chan_scanner *scanner = cl_hw->scanner;
+
+	if (!cl_is_scan_in_progress(scanner))
+		return;
+
+	cl_abort_scan(scanner);
+	wait_event_interruptible_timeout(scanner->wq,
+					 !cl_is_scan_in_progress(scanner),
+					 msecs_to_jiffies(MSEC_PER_SEC));
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 39/96] cl8k: add mac80211.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (37 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 19:52   ` Johannes Berg
  2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
                   ` (56 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mac80211.h | 197 ++++++++++++++++++++
 1 file changed, 197 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac80211.h

diff --git a/drivers/net/wireless/celeno/cl8k/mac80211.h b/drivers/net/wireless/celeno/cl8k/mac80211.h
new file mode 100644
index 000000000000..f76c1a0ad820
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac80211.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_MAC80211_H
+#define CL_MAC80211_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <net/mac80211.h>
+
+#define PPE_0US 0
+#define PPE_8US 1
+#define PPE_16US 2
+
+/*
+ * Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED BIT(0)
+
+/* WLAN_EID_BSS_COEX_2040 = 72 */
+/* 802.11n 7.3.2.61 */
+struct ieee80211_bss_coex_20_40_ie {
+	u8 element_id;
+	u8 len;
+	u8 info_req : 1;
+	/* Inter-BSS set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS */
+	u8 intolerant40 : 1;
+	/* Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS */
+	u8 bss20_width_req : 1;
+	u8 obss_scan_exemp_req : 1;
+	u8 obss_scan_exemp_grant : 1;
+	u8 rsv : 3;
+} __packed;
+
+/* WLAN_EID_BSS_INTOLERANT_CHL_REPORT = 73 */
+/*802.11n 7.3.2.59 */
+struct ieee80211_bss_intolerant_chl_report_ie {
+	u8 element_id;
+	u8 len;
+	u8 regulatory_class;
+	u8 ch_list[0];
+} __packed;
+
+/* Union options that are not included in 'struct ieee80211_mgmt' */
+struct cl_ieee80211_mgmt {
+	__le16 frame_control;
+	__le16 duration;
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+	__le16 seq_ctrl;
+	union {
+		struct {
+			__le16 auth_alg;
+			__le16 auth_transaction;
+			__le16 status_code;
+			/* Possibly followed by Challenge text */
+			u8 variable[0];
+		} __packed auth;
+		struct {
+			__le16 reason_code;
+		} __packed deauth;
+		struct {
+			__le16 capab_info;
+			__le16 listen_interval;
+			/* Followed by SSID and Supported rates */
+			u8 variable[0];
+		} __packed assoc_req;
+		struct {
+			__le16 capab_info;
+			__le16 status_code;
+			__le16 aid;
+			/* Followed by Supported rates */
+			u8 variable[0];
+		} __packed assoc_resp, reassoc_resp;
+		struct {
+			__le16 capab_info;
+			__le16 listen_interval;
+			u8 current_ap[ETH_ALEN];
+			/* Followed by SSID and Supported rates */
+			u8 variable[0];
+		} __packed reassoc_req;
+		struct {
+			__le16 reason_code;
+		} __packed disassoc;
+		struct {
+			__le64 timestamp;
+			__le16 beacon_int;
+			__le16 capab_info;
+			/*
+			 * Followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM
+			 */
+			u8 variable[0];
+		} __packed beacon;
+		struct {
+			/* Only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} __packed probe_req;
+		struct {
+			__le64 timestamp;
+			__le16 beacon_int;
+			__le16 capab_info;
+			/*
+			 * Followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params
+			 */
+			u8 variable[0];
+		} __packed probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					struct ieee80211_bss_coex_20_40_ie bss_coex_20_40_ie;
+					/*
+					 * This IE May appear zero or more times,
+					 * that situation wasn't handled here.
+					 */
+					struct ieee80211_bss_intolerant_chl_report_ie
+						bss_intolerant_chl_report_ie;
+				} __packed coex_2040_mgmt;
+			} u;
+		} __packed action;
+	} u;
+} __packed __aligned(2);
+
+void cl_cap_dyn_params(struct cl_hw *cl_hw);
+void cl_cap_ppe_duration(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+			 u8 pe_dur[CHNL_BW_MAX][WRS_MCS_MAX_HE]);
+u16 cl_cap_set_mesh_basic_rates(struct cl_hw *cl_hw);
+void cl_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb);
+void cl_ops_rx_finish(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sta *sta);
+int cl_ops_start(struct ieee80211_hw *hw);
+void cl_ops_stop(struct ieee80211_hw *hw);
+int cl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void cl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+int cl_ops_config(struct ieee80211_hw *hw, u32 changed);
+void cl_ops_bss_info_changed(struct ieee80211_hw *hw,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_bss_conf *info,
+			     u32 changed);
+int cl_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void cl_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+u64 cl_ops_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list);
+void cl_ops_configure_filter(struct ieee80211_hw *hw, u32 changed_flags,
+			     u32 *total_flags, u64 multicast);
+int cl_ops_set_key(struct ieee80211_hw *hw,
+		   enum set_key_cmd cmd,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta,
+		   struct ieee80211_key_conf *key);
+void cl_ops_sw_scan_start(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  const u8 *mac_addr);
+void cl_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+int cl_ops_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+		     enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state);
+void cl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		       enum sta_notify_cmd cmd, struct ieee80211_sta *sta);
+int cl_ops_conf_tx(struct ieee80211_hw *hw,
+		   struct ieee80211_vif *vif,
+		   u16 ac_queue,
+		   const struct ieee80211_tx_queue_params *params);
+void cl_ops_sta_rc_update(struct ieee80211_hw *hw,
+			  struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta,
+			  u32 changed);
+int cl_ops_ampdu_action(struct ieee80211_hw *hw,
+			struct ieee80211_vif *vif,
+			struct ieee80211_ampdu_params *params);
+int cl_ops_post_channel_switch(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif);
+void cl_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop);
+bool cl_ops_tx_frames_pending(struct ieee80211_hw *hw);
+void cl_ops_reconfig_complete(struct ieee80211_hw *hw,
+			      enum ieee80211_reconfig_type reconfig_type);
+int cl_ops_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm);
+int cl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
+void cl_ops_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			   const struct ieee80211_event *event);
+int cl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
+int cl_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
+u32 cl_ops_get_expected_throughput(struct ieee80211_hw *hw, struct ieee80211_sta *sta);
+void cl_ops_sta_statistics(struct ieee80211_hw *hw,
+			   struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta,
+			   struct station_info *sinfo);
+int cl_ops_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			    const struct cfg80211_bitrate_mask *mask);
+int cl_ops_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey);
+int cl_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		   struct ieee80211_scan_request *hw_req);
+void cl_ops_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+
+#endif /* CL_MAC80211_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 40/96] cl8k: add mac_addr.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (38 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 22:31   ` Jeff Johnson
  2022-05-24 11:34 ` [RFC v2 41/96] cl8k: add mac_addr.h viktor.barna
                   ` (55 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mac_addr.c | 418 ++++++++++++++++++++
 1 file changed, 418 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.c

diff --git a/drivers/net/wireless/celeno/cl8k/mac_addr.c b/drivers/net/wireless/celeno/cl8k/mac_addr.c
new file mode 100644
index 000000000000..be9080564773
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac_addr.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "mac_addr.h"
+
+/** DOC: MAC identifier generation
+ *
+ * The driver allows to works with multiple MAC indentifiers via one base MAC,
+ * which it gets from:
+ *  a) EEPROM;
+ *  b) %ce_phys_mac_addr parameter in chip config;
+ *  c) randomly generated address with Celeno's OUI.
+ *
+ * All other MAC are generated from base MAC by modyfing specific byte in each
+ * new address (starting from %ce_first_mask_bit). All addresses should be in
+ * 4-bit range from each other (HW requirement).
+ *
+ * Both tranceivers are sharing MAC addresses pool per same chip, and with LAM
+ * (=Locally Administered Mac) there is the ability to have up to 16 different
+ * addrs starting with any base MAC. Otherwise (without LAM), base MAC should
+ * allow to generate addresses within 4-bit difference at max.
+ *
+ * Max addresses count is configurable on per-TCV basis via %ci_max_bss_num
+ * variable.
+ *
+ * If LAM is enabled, TCV0 is getting original MAC for the first interface. All
+ * another interfaces of the TCV0 and all interfaces of the TCV1 are getting
+ * LAM-based addresses, which will have 0x02 in the first byte and will have
+ * dynamic last (depends on %ce_first_mask_bit) byte, which typically is being
+ * incremented for each new address, but not always (the logic tries to fit
+ * addresses in 4-bit range, for the sake of this rule new LAM-based address be
+ * reseted to start from 0.
+ *
+ * MAC examples
+ * Case 1: Typical (with LAM)
+ *  - 00:1C:51:BD:FB:00; -> base MAC (valid with and without LAM)
+ *  - 02:1C:51:BD:FB:00;
+ *  - 02:1C:51:BD:FB:01;
+ *
+ * Case 2: Typical (without LAM)
+ *  - 00:1C:51:BD:FB:00; -> base MAC (valid with and without LAM)
+ *  - 00:1C:51:BD:FB:01;
+ *  - 00:1C:51:BD:FB:02;
+ *
+ * Case 3: With reset to fit 4-bit rule (with LAM)
+ *  - 00:1C:51:BD:FB:CF; -> base MAC (valid only with LAM)
+ *  - 02:1C:51:BD:FB:CF;
+ *  - 02:1C:51:BD:FB:C0:
+ *  - 02:1C:51:BD:FB:C1;
+ */
+
+#define CL_LAM_INDICATION 0x02
+
+static int cl_set_mask_addr_without_zeroing_bits(struct cl_hw *cl_hw, u64 mac64, u8 bss_num,
+						 u8 first_mask_bit, u8 *mask_addr)
+{
+	u64 mask = mac64;
+	s8 idx = 0;
+
+	mask >>= first_mask_bit;
+	mask += (bss_num - 1);
+
+	/*
+	 * After the following line the mask will contain the changed
+	 * bits between the first BSS MAC and the last BSS MAC
+	 */
+	mask ^= (mac64 >> first_mask_bit);
+
+	/* Find leftmost set bit */
+	for (idx = 47 - first_mask_bit; (idx >= 0) && (!(mask & (1ULL << idx))); idx--)
+		;
+
+	if (idx < 0) {
+		cl_dbg_err(cl_hw, "Invalid mask (mac=0x%02llx, first_mask_bit=%u, bss_num=%u)\n",
+			   mac64, first_mask_bit, bss_num);
+		mask = 0;
+		eth_zero_addr(mask_addr);
+
+		return -1;
+	}
+
+	mask = (1ULL << idx);
+	mask |= (mask - 1);
+	mask <<= first_mask_bit;
+
+	for (idx = 0; idx < ETH_ALEN; idx++) {
+		u8 shift = (BITS_PER_BYTE * (ETH_ALEN - 1 - idx));
+
+		mask_addr[idx] = (mask & ((u64)0xff << shift)) >> shift;
+	}
+
+	return 0;
+}
+
+static int cl_mask_mac_by_bss_num(struct cl_hw *cl_hw, u8 *mac_addr, u8 *mask_addr,
+				  bool use_lam, bool random_mac)
+{
+	u8 bss_num = cl_hw->conf->ci_max_bss_num;
+	struct cl_hw *cl_hw_tcv0 = cl_hw->chip->cl_hw_tcv0;
+	u8 first_mask_bit = cl_hw->chip->conf->ce_first_mask_bit;
+	u8 i;
+	/* Determine the bits necessary to cover the number of BSSIDs. */
+	u8 num_bits_to_mask[ARRAY_SIZE(cl_hw->addresses) * TCV_MAX] = {
+		0, /* 0 : 00:1C:51:BD:FB:(0b 0000 0000) -> 0-bit diff (no LAM, original MAC) */
+		0, /* 1 : 02:1C:51:BD:FB:(0b 0000 0000) -> 0-bit diff (LAM) */
+
+		1, /* 2 : 02:1C:51:BD:FB:(0b 0000 0001) -> 1-bit diff (LAM, between address #1) */
+
+		2, /* 3 : 02:1C:51:BD:FB:(0b 0000 0011) -> 2-bit diff (LAM) */
+		2, /* 4 : 02:1C:51:BD:FB:(0b 0000 0010) -> 2-bit diff (LAM) */
+
+		3, /* 5 : 02:1C:51:BD:FB:(0b 0000 0111) -> 3-bit diff (LAM) */
+		3, /* 6 : 02:1C:51:BD:FB:(0b 0000 0100) -> 3-bit diff (LAM) */
+		3, /* 7 : 02:1C:51:BD:FB:(0b 0000 0101) -> 3-bit diff (LAM) */
+		3, /* 8 : 02:1C:51:BD:FB:(0b 0000 0110) -> 3-bit diff (LAM) */
+
+		4, /* 9 : 02:1C:51:BD:FB:(0b 0000 1111) -> 4-bit diff (LAM) */
+		4, /* 10: 02:1C:51:BD:FB:(0b 0000 1000) -> 4-bit diff (LAM) */
+		4, /* 11: 02:1C:51:BD:FB:(0b 0000 1001) -> 4-bit diff (LAM) */
+		4, /* 12: 02:1C:51:BD:FB:(0b 0000 1010) -> 4-bit diff (LAM) */
+		4, /* 13: 02:1C:51:BD:FB:(0b 0000 1100) -> 4-bit diff (LAM) */
+		4, /* 14: 02:1C:51:BD:FB:(0b 0000 1110) -> 4-bit diff (LAM) */
+		4, /* 15: 02:1C:51:BD:FB:(0b 0000 1011) -> 4-bit diff (LAM) */
+	};
+
+	u8 mask_size = 0;
+	u8 byte_num = ETH_ALEN - 1 - (first_mask_bit / BITS_PER_BYTE);
+	u8 bit_in_byte = first_mask_bit % BITS_PER_BYTE; /* Referring to the index of the bit */
+
+	if ((first_mask_bit + num_bits_to_mask[bss_num]) > BITS_PER_TYPE(struct mac_address)) {
+		cl_dbg_err(cl_hw, "Invalid combination of first_mask_bit + bss_num. "
+		       "must be lower than 48 bit in total\n");
+		return -EINVAL;
+	}
+
+	if (cl_hw_is_first_tcv(cl_hw)) {
+		mask_size = num_bits_to_mask[bss_num - 1];
+	} else {
+		u64 mac64 = ether_addr_to_u64(mac_addr);
+		u8 tcv0_bss_num = cl_hw_tcv0 ? cl_hw_tcv0->conf->ci_max_bss_num : 0;
+		u8 bit_mask = (1 << num_bits_to_mask[bss_num + tcv0_bss_num - 1]) - 1;
+
+		/*
+		 * If we need to zero bits due to lack of room for the MAC addresses
+		 * of all BSSs of TCV1, then the mask is the number of zeroed bits
+		 */
+		if (((u64)bit_mask - ((mac64 >> first_mask_bit) & (u64)bit_mask) + 1) < bss_num) {
+			mask_size = num_bits_to_mask[bss_num + tcv0_bss_num - 1];
+		} else {
+			/*
+			 * Otherwise the mask is the different bits between the
+			 * addresses of the first and the last BSSs
+			 */
+			cl_set_mask_addr_without_zeroing_bits(cl_hw, mac64, bss_num,
+							      first_mask_bit, mask_addr);
+			return 0;
+		}
+	}
+
+	/* Build mac and mask addr */
+	for (i = 0; i < mask_size; i++) {
+		/*
+		 * Build mask - Convert to "1" the relevant bits in the mask
+		 * addr in order to support the desired number of BSSIDs
+		 */
+		mask_addr[byte_num] |= (0x01 << bit_in_byte);
+
+		/*
+		 * Build mac -convert to "0" the relevant bits in the mac addr
+		 * in order to support the desired number of BSSIDs
+		 */
+		if (random_mac && !use_lam)
+			mac_addr[byte_num] &= ~(0x01 << bit_in_byte);
+
+		bit_in_byte++;
+
+		/* Support cases where the mask bits are not at the same byte. */
+		if (bit_in_byte == BITS_PER_BYTE) {
+			byte_num--;
+			bit_in_byte = 0;
+		}
+	}
+
+	if (use_lam) {
+		/* Mask LAM bit (Locally Administered Mac) */
+		if (cl_hw_is_first_tcv(cl_hw))
+			mask_addr[0] |= CL_LAM_INDICATION;
+	} else {
+		/*
+		 * When not using LAM we do not zero the MAC address of the second BSS,
+		 * so the mask (the modified bits between the first and last BSS) depends
+		 * on initial MAC
+		 */
+		u64 mac64 = ether_addr_to_u64(mac_addr);
+
+		cl_set_mask_addr_without_zeroing_bits(cl_hw, mac64, bss_num,
+						      first_mask_bit, mask_addr);
+	}
+
+	return 0;
+}
+
+#define MAC_FILTER_BITS 4
+#define MAC_FILTER_MASK ((1 << MAC_FILTER_BITS) - 1)
+
+static bool cl_is_valid_mac_addr(u64 mac64, u8 first_mask_bit, u8 bss_num)
+{
+	u8 mac_bits = (mac64 >> first_mask_bit) & MAC_FILTER_MASK;
+	u8 mac_diff = 0;
+	u8 i;
+
+	for (i = 0; i < bss_num; i++) {
+		mac_diff |= mac_bits;
+		mac_bits++;
+	}
+
+	return hweight8(mac_diff) <= MAC_FILTER_BITS;
+}
+
+static int cl_mac_addr_set_addresses(struct cl_hw *cl_hw, bool use_lam,
+				     u8 *mask_addr)
+{
+	u8 first_mask_bit = cl_hw->chip->conf->ce_first_mask_bit;
+	int i = 0;
+	u8 bss_num = min_t(u8, cl_hw->conf->ci_max_bss_num, ARRAY_SIZE(cl_hw->addresses));
+	u64 mac64 = ether_addr_to_u64(cl_hw->hw->wiphy->perm_addr);
+	u64 mask64 = 0;
+	u8 new_addr[ETH_ALEN] = {0};
+
+	if (!use_lam && !cl_is_valid_mac_addr(mac64, first_mask_bit, bss_num)) {
+		cl_dbg_err(cl_hw,
+			   "perm_addr %pM is invalid for bss_num %d without LAM\n",
+			   cl_hw->hw->wiphy->perm_addr, bss_num);
+		return -1;
+	}
+
+	cl_mac_addr_copy(cl_hw->addresses[i].addr,
+			 cl_hw->hw->wiphy->perm_addr);
+	for (i = 1; i < bss_num; i++) {
+		u8 *prev_addr = cl_hw->addresses[i - 1].addr;
+
+		if (use_lam) {
+			mac64 = ether_addr_to_u64(prev_addr);
+			mask64 = ether_addr_to_u64(mask_addr);
+			if (cl_hw_is_first_tcv(cl_hw)) {
+				if (i == 1)
+					mac64 &= ~mask64;
+				else
+					mac64 += 1 << first_mask_bit;
+				u64_to_ether_addr(mac64, new_addr);
+				new_addr[0] |= CL_LAM_INDICATION;
+			} else {
+				if ((mac64 & mask64) == mask64)
+					mac64 &= ~mask64;
+				else
+					mac64 += 1 << first_mask_bit;
+				u64_to_ether_addr(mac64, new_addr);
+			}
+			cl_mac_addr_copy(cl_hw->addresses[i].addr, new_addr);
+		} else {
+			mac64 = ether_addr_to_u64(prev_addr);
+			mac64 += 1 << first_mask_bit;
+			u64_to_ether_addr(mac64, cl_hw->addresses[i].addr);
+		}
+	}
+	cl_hw->n_addresses = bss_num;
+
+	return 0;
+}
+
+static int cl_mac_addr_set_first_tcv(struct cl_hw *cl_hw, u8 *dflt_mac,
+				     bool *random_mac)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (!cl_mac_addr_is_zero(chip->conf->ce_phys_mac_addr)) {
+		/* Read MAC from NVRAM file */
+		cl_mac_addr_copy(dflt_mac, chip->conf->ce_phys_mac_addr);
+		cl_dbg_verbose(cl_hw, "Read MAC address from NVRAM [%pM]\n", dflt_mac);
+	} else {
+		/* Read MAC from EEPROM */
+		if (chip->eeprom_read_block(chip, ADDR_GEN_MAC_ADDR,
+					    ETH_ALEN, dflt_mac) != ETH_ALEN) {
+			CL_DBG_ERROR(cl_hw, "Error reading MAC address from EEPROM\n");
+			return -1;
+		}
+
+		cl_dbg_verbose(cl_hw, "Read MAC address from EEPROM [%pM]\n", dflt_mac);
+	}
+
+	/* Test if the new mac address is 00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff */
+	if (cl_mac_addr_is_zero(dflt_mac) || cl_mac_addr_is_broadcast(dflt_mac)) {
+		/* Set celeno oui */
+		dflt_mac[0] = 0x00;
+		dflt_mac[1] = 0x1c;
+		dflt_mac[2] = 0x51;
+		get_random_bytes(&dflt_mac[3], 3);
+		cl_dbg_verbose(cl_hw, "Random MAC address [%pM]\n", dflt_mac);
+		*random_mac = true;
+	}
+
+	return 0;
+}
+
+static void cl_mac_addr_set_second_tcv(struct cl_hw *cl_hw, u8 *dflt_mac)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	u8 tcv0_bss_num = cl_hw_tcv0->conf->ci_max_bss_num;
+	u8 first_mask_bit = chip->conf->ce_first_mask_bit;
+	u64 mac64;
+	u8 idx;
+	u8 bss_num = cl_hw->conf->ci_max_bss_num;
+	u8 lam_bit_mask[ARRAY_SIZE(cl_hw->addresses) * TCV_MAX] = {
+		0b0000, /* 1 addr,  0-bit diff between MAC addrs, LAM is not affecting it */
+		0b0000, /* 2 addrs, 0-bit diff between MAC addrs, first differs by LAM !!! */
+		0b0001, /* 3 addrs, 1-bit diff */
+		0b0011, /* 4 addrs, 2-bit diff */
+		0b0011, /* 5 addrs, 2-bit diff */
+
+		0b0111, /* 6 addrs, 3-bit diff */
+		0b0111, /* 7 addrs, 3-bit diff */
+		0b0111, /* 8 addrs, 3-bit diff */
+		0b0111, /* 9 addrs, 3-bit diff */
+
+		0b1111, /* 10 addrs, 4-bit diff */
+		0b1111, /* 11 addrs, 4-bit diff */
+		0b1111, /* 12 addrs, 4-bit diff */
+		0b1111, /* 13 addrs, 4-bit diff */
+		0b1111, /* 14 addrs, 4-bit diff */
+		0b1111, /* 15 addrs, 4-bit diff */
+		0b1111, /* 16 addrs, 4-bit diff */
+	};
+
+	mac64 = ether_addr_to_u64(cl_hw_tcv0->hw->wiphy->perm_addr);
+
+	if (chip->conf->ce_lam_enable) {
+		/* Find the first address of TCV1 */
+		if (tcv0_bss_num == 1) {
+			/*
+			 * For tcv0 bss num = 1, we have to zero the necessary bits
+			 * since it hasn't been done in TCV0
+			 */
+			mac64 &= ~((u64)lam_bit_mask[bss_num] << first_mask_bit);
+		} else {
+			u8 total_bss_to_mask = bss_num + tcv0_bss_num - 1;
+
+			mac64 &= ~((u64)lam_bit_mask[tcv0_bss_num - 1] << first_mask_bit);
+			/*
+			 * Get the first MAC address of TCV1 by incrementing the MAC
+			 * address of the last BSS of TCV0.
+			 * After the instruction below mac64 will hold the MAC of TCV0's
+			 * last BSS.
+			 */
+			mac64 += ((u64)(tcv0_bss_num - 2) << first_mask_bit);
+			/*
+			 * If there is no more room for another address in TCV0's mask
+			 * address then we have to zero bits else increment the last
+			 * address of TCV0
+			 */
+			if (((mac64 >> first_mask_bit) & (u64)lam_bit_mask[total_bss_to_mask]) ==
+			    (u64)lam_bit_mask[total_bss_to_mask])
+				mac64 &= ~((u64)lam_bit_mask[total_bss_to_mask] << first_mask_bit);
+			else
+				mac64 += (1ULL << first_mask_bit);
+		}
+
+		/* Enable LAM bit */
+		mac64 += (0x2ULL << 40);
+	} else {
+		mac64 += ((u64)tcv0_bss_num << first_mask_bit);
+	}
+
+	for (idx = 0; idx < ETH_ALEN; idx++) {
+		u8 shift = (8 * (ETH_ALEN - 1 - idx));
+
+		dflt_mac[idx] = (mac64 & ((u64)0xFF << shift)) >> shift;
+	}
+}
+
+int cl_mac_addr_set(struct cl_hw *cl_hw)
+{
+	bool random_mac = false;
+	u8 dflt_mac[ETH_ALEN] = {0x00, 0x1c, 0x51, 0x51, 0x51, 0x51};
+	u8 dflt_mask[ETH_ALEN] = {0};
+	bool use_lam = cl_hw->chip->conf->ce_lam_enable;
+	struct wiphy *wiphy = cl_hw->hw->wiphy;
+
+	if (cl_hw_is_first_tcv(cl_hw)) {
+		if (cl_mac_addr_set_first_tcv(cl_hw, dflt_mac, &random_mac))
+			return -1;
+	} else {
+		cl_mac_addr_set_second_tcv(cl_hw, dflt_mac);
+	}
+
+	if (cl_mask_mac_by_bss_num(cl_hw, dflt_mac, dflt_mask, use_lam, random_mac))
+		return -1;
+
+	/* Permanent address MAC (the MAC of the first BSS) */
+	SET_IEEE80211_PERM_ADDR(cl_hw->hw, dflt_mac);
+
+	/*
+	 * Addresses count must be power of 2
+	 * mac80211 doesn't handle non-contiguous masks
+	 */
+	BUILD_BUG_ON_NOT_POWER_OF_2(ARRAY_SIZE(cl_hw->addresses));
+
+	cl_mac_addr_array_to_nxmac(dflt_mask, &cl_hw->mask_low, &cl_hw->mask_hi);
+
+	if (cl_mac_addr_set_addresses(cl_hw, use_lam, dflt_mask))
+		return -1;
+
+	wiphy->addresses = cl_hw->addresses;
+	wiphy->n_addresses = cl_hw->n_addresses;
+
+	return 0;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 41/96] cl8k: add mac_addr.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (39 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
                   ` (54 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/mac_addr.h | 61 +++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/mac_addr.h

diff --git a/drivers/net/wireless/celeno/cl8k/mac_addr.h b/drivers/net/wireless/celeno/cl8k/mac_addr.h
new file mode 100644
index 000000000000..3f916f2b7f7b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/mac_addr.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_MAC_ADDR_H
+#define CL_MAC_ADDR_H
+
+#include "hw.h"
+
+int cl_mac_addr_set(struct cl_hw *cl_hw);
+
+static inline void cl_mac_addr_copy(u8 *dest_addr, const u8 *src_addr)
+{
+	memcpy(dest_addr, src_addr, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_compare(const u8 *addr1, const u8 *addr2)
+{
+	return !memcmp(addr1, addr2, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_is_zero(const u8 *addr)
+{
+	const u8 addr_zero[ETH_ALEN] = {0};
+
+	return !memcmp(addr, addr_zero, ETH_ALEN);
+}
+
+static inline bool cl_mac_addr_is_broadcast(const u8 *addr)
+{
+	const u8 addr_bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	return !memcmp(addr, addr_bcast, ETH_ALEN);
+}
+
+static inline void cl_mac_addr_array_to_nxmac(u8 *array, u32 *low, u32 *high)
+{
+	/* Convert mac address (in a form of array) to a C nxmac form.
+	 * Input: array - MAC address
+	 * Output: low - array[0..3], high - array[4..5]
+	 */
+	u8 i;
+
+	for (i = 0; i < 4; i++)
+		*low |= (u32)(((u32)array[i]) << (i * 8));
+
+	for (i = 0; i < 2; i++)
+		*high |= (u32)(((u32)array[i + 4]) << (i * 8));
+}
+
+static inline u8 cl_mac_addr_find_idx(struct cl_hw *cl_hw, u8 *addr)
+{
+	u8 i;
+
+	for (i = 0; i < cl_hw->n_addresses; i++)
+		if (cl_mac_addr_compare(cl_hw->addresses[i].addr, addr))
+			return i;
+
+	return BSS_INVALID_IDX;
+}
+
+#endif /* CL_MAC_ADDR_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 42/96] cl8k: add main.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (40 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 41/96] cl8k: add mac_addr.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 23:01   ` Jeff Johnson
  2022-05-24 11:34 ` [RFC v2 43/96] cl8k: add main.h viktor.barna
                   ` (53 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/main.c | 603 ++++++++++++++++++++++++
 1 file changed, 603 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/main.c

diff --git a/drivers/net/wireless/celeno/cl8k/main.c b/drivers/net/wireless/celeno/cl8k/main.c
new file mode 100644
index 000000000000..08abb16987ef
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/main.c
@@ -0,0 +1,603 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "tx.h"
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "stats.h"
+#include "maintenance.h"
+#include "vns.h"
+#include "traffic.h"
+#include "sounding.h"
+#include "recovery.h"
+#include "rates.h"
+#include "utils.h"
+#include "phy.h"
+#include "radio.h"
+#include "dsp.h"
+#include "dfs.h"
+#include "tcv.h"
+#include "mac_addr.h"
+#include "bf.h"
+#include "rfic.h"
+#include "e2p.h"
+#include "chip.h"
+#include "regdom.h"
+#include "platform.h"
+#include "mac80211.h"
+#include "main.h"
+
+MODULE_DESCRIPTION("Celeno 11ax driver for Linux");
+MODULE_VERSION(CONFIG_CL8K_VERSION);
+MODULE_AUTHOR("Copyright(c) 2022 Celeno Communications Ltd");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct ieee80211_ops cl_ops = {
+	.tx                     = cl_ops_tx,
+	.start                  = cl_ops_start,
+	.stop                   = cl_ops_stop,
+	.add_interface          = cl_ops_add_interface,
+	.remove_interface       = cl_ops_remove_interface,
+	.config                 = cl_ops_config,
+	.bss_info_changed       = cl_ops_bss_info_changed,
+	.start_ap               = cl_ops_start_ap,
+	.stop_ap                = cl_ops_stop_ap,
+	.prepare_multicast      = cl_ops_prepare_multicast,
+	.configure_filter       = cl_ops_configure_filter,
+	.set_key                = cl_ops_set_key,
+	.sw_scan_start          = cl_ops_sw_scan_start,
+	.sw_scan_complete       = cl_ops_sw_scan_complete,
+	.sta_state              = cl_ops_sta_state,
+	.sta_notify             = cl_ops_sta_notify,
+	.conf_tx                = cl_ops_conf_tx,
+	.sta_rc_update          = cl_ops_sta_rc_update,
+	.ampdu_action           = cl_ops_ampdu_action,
+	.post_channel_switch    = cl_ops_post_channel_switch,
+	.flush                  = cl_ops_flush,
+	.tx_frames_pending      = cl_ops_tx_frames_pending,
+	.reconfig_complete      = cl_ops_reconfig_complete,
+	.get_txpower            = cl_ops_get_txpower,
+	.set_rts_threshold      = cl_ops_set_rts_threshold,
+	.event_callback         = cl_ops_event_callback,
+	.set_tim                = cl_ops_set_tim,
+	.get_antenna            = cl_ops_get_antenna,
+	.get_expected_throughput = cl_ops_get_expected_throughput,
+	.sta_statistics         = cl_ops_sta_statistics,
+	.get_survey             = cl_ops_get_survey,
+	.hw_scan                = cl_ops_hw_scan,
+	.cancel_hw_scan         = cl_ops_cancel_hw_scan
+};
+
+static void cl_drv_workqueue_create(struct cl_hw *cl_hw)
+{
+	if (!cl_hw->drv_workqueue)
+		cl_hw->drv_workqueue = create_singlethread_workqueue("drv_workqueue");
+}
+
+static void cl_drv_workqueue_destroy(struct cl_hw *cl_hw)
+{
+	if (cl_hw->drv_workqueue) {
+		destroy_workqueue(cl_hw->drv_workqueue);
+		cl_hw->drv_workqueue = NULL;
+	}
+}
+
+static int cl_main_alloc(struct cl_hw *cl_hw)
+{
+	int ret = 0;
+
+	ret = cl_phy_data_alloc(cl_hw);
+	if (ret)
+		return ret;
+
+	ret = cl_calib_common_tables_alloc(cl_hw);
+	if (ret)
+		return ret;
+
+	ret = cl_power_table_alloc(cl_hw);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static void cl_main_free(struct cl_hw *cl_hw)
+{
+	cl_phy_data_free(cl_hw);
+	cl_calib_common_tables_free(cl_hw);
+	cl_power_table_free(cl_hw);
+}
+
+static void cl_free_hw(struct cl_hw *cl_hw)
+{
+	if (!cl_hw)
+		return;
+
+	cl_temperature_wait_for_measurement(cl_hw->chip, cl_hw->tcv_idx);
+
+	cl_tcv_config_free(cl_hw);
+
+	if (cl_hw->hw->wiphy->registered)
+		ieee80211_unregister_hw(cl_hw->hw);
+
+	cl_chip_unset_hw(cl_hw->chip, cl_hw);
+	ieee80211_free_hw(cl_hw->hw);
+}
+
+static void cl_free_chip(struct cl_chip *chip)
+{
+	cl_free_hw(chip->cl_hw_tcv0);
+	cl_free_hw(chip->cl_hw_tcv1);
+}
+
+static int cl_prepare_hw(struct cl_chip *chip, u8 tcv_idx,
+			 const struct cl_driver_ops *drv_ops)
+{
+	struct cl_hw *cl_hw = NULL;
+	struct ieee80211_hw *hw;
+	int ret = 0;
+
+	hw = ieee80211_alloc_hw(sizeof(struct cl_hw), &cl_ops);
+	if (!hw) {
+		cl_dbg_chip_err(chip, "ieee80211_alloc_hw failed\n");
+		return -ENOMEM;
+	}
+
+	cl_hw_init(chip, hw->priv, tcv_idx);
+
+	cl_hw = hw->priv;
+	cl_hw->hw = hw;
+	cl_hw->tcv_idx = tcv_idx;
+	cl_hw->sx_idx = chip->conf->ci_tcv1_chains_sx0 ? 0 : tcv_idx;
+	cl_hw->chip = chip;
+
+	/*
+	 * chip0, tcv0 --> 0
+	 * chip0, tcv1 --> 1
+	 * chip1, tcv0 --> 2
+	 * chip1, tcv1 --> 3
+	 */
+	cl_hw->idx = chip->idx * CHIP_MAX + tcv_idx;
+
+	cl_hw->drv_ops = drv_ops;
+
+	SET_IEEE80211_DEV(hw, chip->dev);
+
+	ret = cl_tcv_config_alloc(cl_hw);
+	if (ret)
+		goto out_free_hw;
+
+	ret = cl_tcv_config_read(cl_hw);
+	if (ret)
+		goto out_free_hw;
+
+	cl_chip_set_hw(chip, cl_hw);
+
+	ret = cl_mac_addr_set(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_mac_addr_set failed\n");
+		goto out_free_hw;
+	}
+
+	if (cl_band_is_6g(cl_hw))
+		cl_hw->nl_band = NL80211_BAND_6GHZ;
+	else if (cl_band_is_5g(cl_hw))
+		cl_hw->nl_band = NL80211_BAND_5GHZ;
+	else
+		cl_hw->nl_band = NL80211_BAND_2GHZ;
+
+	if (cl_band_is_24g(cl_hw))
+		cl_hw->hw_mode = HW_MODE_BG;
+	else
+		cl_hw->hw_mode = HW_MODE_A;
+
+	cl_hw->wireless_mode = WIRELESS_MODE_HT_VHT_HE;
+
+	cl_cap_dyn_params(cl_hw);
+
+	cl_dbg_verbose(cl_hw, "cl_hw created\n");
+
+	return 0;
+
+out_free_hw:
+	cl_free_hw(cl_hw);
+
+	return ret;
+}
+
+void cl_main_off(struct cl_hw *cl_hw)
+{
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
+	cl_ipc_stop(cl_hw);
+
+	if (!test_bit(CL_DEV_INIT, &cl_hw->drv_flags)) {
+		cl_tx_off(cl_hw);
+		cl_rx_off(cl_hw);
+		cl_msg_rx_flush_all(cl_hw);
+	}
+
+	cl_fw_file_cleanup(cl_hw);
+}
+
+static void _cl_main_deinit(struct cl_hw *cl_hw)
+{
+	if (!cl_hw)
+		return;
+
+	ieee80211_unregister_hw(cl_hw->hw);
+
+	/* Send reset message to firmware */
+	cl_msg_tx_reset(cl_hw);
+
+	cl_hw->is_stop_context = true;
+
+	cl_drv_workqueue_destroy(cl_hw);
+
+	cl_scanner_deinit(cl_hw);
+
+	cl_noise_close(cl_hw);
+	cl_maintenance_close(cl_hw);
+	cl_vns_close(cl_hw);
+	cl_rssi_assoc_exit(cl_hw);
+	cl_radar_close(cl_hw);
+	cl_sounding_close(cl_hw);
+	cl_chan_info_deinit(cl_hw);
+	cl_wrs_api_close(cl_hw);
+	cl_main_off(cl_hw);
+	/* These 2 must be called after cl_tx_off() (which is called from cl_main_off) */
+	cl_tx_amsdu_txhdr_deinit(cl_hw);
+	cl_sw_txhdr_deinit(cl_hw);
+	cl_fw_dbg_trigger_based_deinit(cl_hw);
+	cl_stats_deinit(cl_hw);
+	cl_main_free(cl_hw);
+	cl_fw_file_release(cl_hw);
+
+	cl_ipc_deinit(cl_hw);
+	cl_hw_deinit(cl_hw, cl_hw->tcv_idx);
+	vfree(cl_hw->tx_queues);
+}
+
+void cl_main_deinit(struct cl_chip *chip)
+{
+	struct cl_chip_conf *conf = chip->conf;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+
+	if (cl_chip_is_tcv1_enabled(chip) && cl_hw_tcv1)
+		_cl_main_deinit(cl_hw_tcv1);
+
+	if (cl_chip_is_tcv0_enabled(chip) && cl_hw_tcv0)
+		_cl_main_deinit(cl_hw_tcv0);
+
+	if (conf->ci_phy_dev != PHY_DEV_DUMMY) {
+		if (!conf->ci_phy_load_bootdrv)
+			cl_phy_off(cl_hw_tcv1);
+
+		cl_phy_off(cl_hw_tcv0);
+	}
+
+	cl_platform_dealloc(chip);
+
+	cl_free_chip(chip);
+}
+
+static struct cl_controller_reg all_controller_reg = {
+	.breset = XMAC_BRESET,
+	.debug_enable = XMAC_DEBUG_ENABLE,
+	.dreset = XMAC_DRESET,
+	.ocd_halt_on_reset = XMAC_OCD_HALT_ON_RESET,
+	.run_stall = XMAC_RUN_STALL
+};
+
+void cl_main_reset(struct cl_chip *chip, struct cl_controller_reg *controller_reg)
+{
+	/* Release TRST & BReset to enable JTAG connection to FPGA A */
+	u32 regval;
+
+	/* 1. return to reset value */
+	regval = macsys_gcu_xt_control_get(chip);
+	regval |= controller_reg->ocd_halt_on_reset;
+	regval &= ~(controller_reg->dreset | controller_reg->run_stall | controller_reg->breset);
+	macsys_gcu_xt_control_set(chip, regval);
+
+	regval = macsys_gcu_xt_control_get(chip);
+	regval |= controller_reg->dreset;
+	macsys_gcu_xt_control_set(chip, regval);
+
+	/* 2. stall xtensa & release ocd */
+	regval = macsys_gcu_xt_control_get(chip);
+	regval |= controller_reg->run_stall;
+	regval &= ~controller_reg->ocd_halt_on_reset;
+	macsys_gcu_xt_control_set(chip, regval);
+
+	/* 3. breset release & debug enable */
+	regval = macsys_gcu_xt_control_get(chip);
+	regval |= (controller_reg->debug_enable | controller_reg->breset);
+	macsys_gcu_xt_control_set(chip, regval);
+
+	msleep(100);
+}
+
+int cl_main_on(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	int ret;
+	u32 regval;
+
+	cl_hw->fw_active = false;
+
+	cl_txq_init(cl_hw);
+
+	cl_hw_assert_info_init(cl_hw);
+
+	if (cl_recovery_in_progress(cl_hw))
+		cl_main_reset(chip, &cl_hw->controller_reg);
+
+	ret = cl_fw_file_load(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_fw_file_load failed %d\n", ret);
+		return ret;
+	}
+
+	/* Clear CL_DEV_FW_ERROR after firmware loaded */
+	clear_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
+
+	if (cl_recovery_in_progress(cl_hw))
+		cl_ipc_recovery(cl_hw);
+
+	regval = macsys_gcu_xt_control_get(chip);
+
+	/* Set fw to run */
+	if (cl_hw->fw_active)
+		regval &= ~cl_hw->controller_reg.run_stall;
+
+	/* Set umac to run */
+	if (chip->umac_active)
+		regval &= ~UMAC_RUN_STALL;
+
+	/* Ack all possibly pending IRQs */
+	ipc_xmac_2_host_ack_set(chip, cl_hw->ipc_e2a_irq.all);
+	macsys_gcu_xt_control_set(chip, regval);
+	cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.all);
+	/*
+	 * cl_irq_status_sync will set CL_DEV_FW_SYNC when fw raises IPC_IRQ_E2A_SYNC
+	 * (indicate its ready to accept interrupts)
+	 */
+	ret = wait_event_interruptible_timeout(cl_hw->fw_sync_wq,
+					       test_and_clear_bit(CL_DEV_FW_SYNC,
+								  &cl_hw->drv_flags),
+					       msecs_to_jiffies(5000));
+
+	if (ret == 0) {
+		pr_err("[%s]: FW synchronization timeout.\n", __func__);
+		cl_hw_assert_check(cl_hw);
+		ret = -ETIMEDOUT;
+		goto out_free_cached_fw;
+	} else if (ret == -ERESTARTSYS) {
+		goto out_free_cached_fw;
+	}
+
+	return 0;
+
+out_free_cached_fw:
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
+	cl_fw_file_release(cl_hw);
+	return ret;
+}
+
+static int __cl_main_init(struct cl_hw *cl_hw)
+{
+	int ret;
+
+	if (!cl_hw)
+		return 0;
+
+	if (cl_regd_init(cl_hw, cl_hw->hw->wiphy))
+		cl_dbg_err(cl_hw, "regulatory failed\n");
+
+	/*
+	 * ieee80211_register_hw() will take care of calling wiphy_register() and
+	 * also ieee80211_if_add() (because IFTYPE_STATION is supported)
+	 * which will internally call register_netdev()
+	 */
+	ret = ieee80211_register_hw(cl_hw->hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "ieee80211_register_hw failed\n");
+		cl_main_deinit(cl_hw->chip);
+
+		return ret;
+	}
+
+	return ret;
+}
+
+static int _cl_main_init(struct cl_hw *cl_hw)
+{
+	int ret = 0;
+
+	if (!cl_hw)
+		return 0;
+
+	set_bit(CL_DEV_INIT, &cl_hw->drv_flags);
+
+	/* By default, set FEM mode to opertional mode. */
+	cl_hw->fem_mode = FEM_MODE_OPERETIONAL;
+
+	cl_vif_init(cl_hw);
+
+	cl_drv_workqueue_create(cl_hw);
+
+	init_waitqueue_head(&cl_hw->wait_queue);
+	init_waitqueue_head(&cl_hw->fw_sync_wq);
+	init_waitqueue_head(&cl_hw->radio_wait_queue);
+
+	mutex_init(&cl_hw->dbginfo.mutex);
+	mutex_init(&cl_hw->msg_tx_mutex);
+	mutex_init(&cl_hw->set_channel_mutex);
+
+	spin_lock_init(&cl_hw->tx_lock_agg);
+	spin_lock_init(&cl_hw->tx_lock_cfm_agg);
+	spin_lock_init(&cl_hw->tx_lock_single);
+	spin_lock_init(&cl_hw->tx_lock_bcmc);
+	spin_lock_init(&cl_hw->channel_info_lock);
+
+	ret = cl_ipc_init(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_ipc_init failed %d\n", ret);
+		return ret;
+	}
+
+	cl_chip_set_rfic_version(cl_hw);
+
+	/* Validate calib params should be called after setting the rfic version */
+	cl_tcv_config_validate_calib_params(cl_hw);
+
+	cl_hw->tx_queues = vzalloc(sizeof(*cl_hw->tx_queues));
+	if (!cl_hw->tx_queues) {
+		cl_ipc_deinit(cl_hw);
+		return -ENOMEM;
+	}
+
+	ret = cl_main_on(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_main_on failed %d\n", ret);
+		cl_ipc_deinit(cl_hw);
+		vfree(cl_hw->tx_queues);
+
+		return ret;
+	}
+
+	ret = cl_main_alloc(cl_hw);
+	if (ret)
+		goto out_free;
+
+	/* Reset firmware */
+	ret = cl_msg_tx_reset(cl_hw);
+	if (ret)
+		goto out_free;
+
+	cl_calib_power_read(cl_hw);
+	cl_sta_init(cl_hw);
+	cl_sw_txhdr_init(cl_hw);
+	cl_tx_amsdu_txhdr_init(cl_hw);
+	cl_rx_init(cl_hw);
+	cl_prot_mode_init(cl_hw);
+	cl_radar_init(cl_hw);
+	cl_sounding_init(cl_hw);
+	cl_traffic_init(cl_hw);
+	ret = cl_vns_init(cl_hw);
+	if (ret)
+		goto out_free;
+
+	cl_maintenance_init(cl_hw);
+	cl_rssi_assoc_init(cl_hw);
+	cl_agg_cfm_init(cl_hw);
+	cl_single_cfm_init(cl_hw);
+	cl_bcmc_cfm_init(cl_hw);
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	cl_dyn_mcast_rate_init(cl_hw);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_init(cl_hw);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+	cl_wrs_api_init(cl_hw);
+	cl_dfs_init(cl_hw);
+	cl_noise_init(cl_hw);
+	ret = cl_fw_dbg_trigger_based_init(cl_hw);
+	if (ret)
+		goto out_free;
+
+	cl_stats_init(cl_hw);
+	cl_cca_init(cl_hw);
+	cl_bf_init(cl_hw);
+
+	ret = cl_scanner_init(cl_hw);
+	if (ret)
+		goto out_free;
+
+	/* Start firmware */
+	ret = cl_msg_tx_start(cl_hw);
+	if (ret)
+		goto out_free;
+
+	return 0;
+
+out_free:
+	cl_main_free(cl_hw);
+	vfree(cl_hw->tx_queues);
+
+	return ret;
+}
+
+int cl_main_init(struct cl_chip *chip, const struct cl_driver_ops *drv_ops)
+{
+	int ret = 0;
+	struct cl_chip_conf *conf = chip->conf;
+
+	/* All cores needs to be reset first (once per chip) */
+	cl_main_reset(chip, &all_controller_reg);
+
+	/* Prepare HW for TCV0 */
+	if (cl_chip_is_tcv0_enabled(chip)) {
+		ret = cl_prepare_hw(chip, TCV0, drv_ops);
+
+		if (ret) {
+			cl_dbg_chip_err(chip, "Prepare HW for TCV0 failed %d\n", ret);
+			return ret;
+		}
+	}
+
+	/* Prepare HW for TCV1 */
+	if (cl_chip_is_tcv1_enabled(chip)) {
+		ret = cl_prepare_hw(chip, TCV1, drv_ops);
+
+		if (ret) {
+			cl_dbg_chip_err(chip, "Prepare HW for TCV1 failed %d\n", ret);
+			cl_free_hw(chip->cl_hw_tcv0);
+			return ret;
+		}
+	}
+
+	if (!conf->ci_phy_load_bootdrv &&
+	    conf->ci_phy_dev != PHY_DEV_DUMMY) {
+		ret = cl_radio_boot(chip);
+		if (ret) {
+			cl_dbg_chip_err(chip, "RF boot failed %d\n", ret);
+			return ret;
+		}
+
+		ret = cl_dsp_load_regular(chip);
+		if (ret) {
+			cl_dbg_chip_err(chip, "DSP load failed %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = _cl_main_init(chip->cl_hw_tcv0);
+	if (ret) {
+		cl_free_chip(chip);
+		return ret;
+	}
+
+	ret = _cl_main_init(chip->cl_hw_tcv1);
+	if (ret) {
+		_cl_main_deinit(chip->cl_hw_tcv0);
+		cl_free_chip(chip);
+		return ret;
+	}
+
+	ret = __cl_main_init(chip->cl_hw_tcv0);
+	if (ret)
+		return ret;
+
+	ret = __cl_main_init(chip->cl_hw_tcv1);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	if (conf->ci_calib_eeprom_en && conf->ce_production_mode && conf->ce_calib_runtime_en)
+		cl_e2p_read_eeprom_start_work(chip);
+#endif
+
+	return ret;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 43/96] cl8k: add main.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (41 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 44/96] cl8k: add maintenance.c viktor.barna
                   ` (52 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/main.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/main.h

diff --git a/drivers/net/wireless/celeno/cl8k/main.h b/drivers/net/wireless/celeno/cl8k/main.h
new file mode 100644
index 000000000000..69f4ae599902
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/main.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_MAIN_H
+#define CL_MAIN_H
+
+#include "chip.h"
+#include "hw.h"
+
+int cl_main_init(struct cl_chip *chip, const struct cl_driver_ops *drv_ops);
+void cl_main_deinit(struct cl_chip *chip);
+void cl_main_reset(struct cl_chip *chip, struct cl_controller_reg *controller_reg);
+int cl_main_on(struct cl_hw *cl_hw);
+void cl_main_off(struct cl_hw *cl_hw);
+
+#endif /* CL_MAIN_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 44/96] cl8k: add maintenance.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (42 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 43/96] cl8k: add main.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 45/96] cl8k: add maintenance.h viktor.barna
                   ` (51 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/maintenance.c    | 81 +++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.c

diff --git a/drivers/net/wireless/celeno/cl8k/maintenance.c b/drivers/net/wireless/celeno/cl8k/maintenance.c
new file mode 100644
index 000000000000..3230757edacc
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/maintenance.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "maintenance.h"
+#include "traffic.h"
+#include "vns.h"
+#include "reg/reg_access.h"
+#include "sounding.h"
+#include "sta.h"
+#include "motion_sense.h"
+#include "radio.h"
+
+static void cl_maintenance_callback_slow(struct timer_list *t)
+{
+	struct cl_hw *cl_hw = from_timer(cl_hw, t, maintenance_slow_timer);
+
+	cl_cca_maintenance(cl_hw);
+	cl_noise_maintenance(cl_hw);
+
+	if (cl_hw_is_prod_or_listener(cl_hw))
+		goto reschedule_timer;
+
+	cl_vns_maintenance(cl_hw);
+
+	if (cl_hw->conf->ci_traffic_mon_en)
+		cl_sta_loop(cl_hw, cl_traffic_mon_sta_maintenance);
+
+	if (cl_sta_num(cl_hw) == 0)
+		goto reschedule_timer;
+
+	cl_motion_sense_maintenance(cl_hw);
+	cl_sounding_maintenance(cl_hw);
+
+reschedule_timer:
+	mod_timer(&cl_hw->maintenance_slow_timer,
+		  jiffies + msecs_to_jiffies(CL_MAINTENANCE_PERIOD_SLOW_MS));
+}
+
+static void cl_maintenance_callback_fast(struct timer_list *t)
+{
+	struct cl_hw *cl_hw = from_timer(cl_hw, t, maintenance_fast_timer);
+
+	if (cl_sta_num(cl_hw) == 0)
+		goto reschedule_timer;
+
+	cl_traffic_maintenance(cl_hw);
+
+reschedule_timer:
+	mod_timer(&cl_hw->maintenance_fast_timer,
+		  jiffies + msecs_to_jiffies(CL_MAINTENANCE_PERIOD_FAST_MS));
+}
+
+void cl_maintenance_init(struct cl_hw *cl_hw)
+{
+	timer_setup(&cl_hw->maintenance_slow_timer, cl_maintenance_callback_slow, 0);
+	timer_setup(&cl_hw->maintenance_fast_timer, cl_maintenance_callback_fast, 0);
+
+	cl_maintenance_start(cl_hw);
+}
+
+void cl_maintenance_close(struct cl_hw *cl_hw)
+{
+	del_timer_sync(&cl_hw->maintenance_slow_timer);
+	del_timer_sync(&cl_hw->maintenance_fast_timer);
+}
+
+void cl_maintenance_stop(struct cl_hw *cl_hw)
+{
+	del_timer(&cl_hw->maintenance_slow_timer);
+	del_timer(&cl_hw->maintenance_fast_timer);
+}
+
+void cl_maintenance_start(struct cl_hw *cl_hw)
+{
+	mod_timer(&cl_hw->maintenance_slow_timer,
+		  jiffies + msecs_to_jiffies(CL_MAINTENANCE_PERIOD_SLOW_MS));
+
+	if (!cl_hw_is_prod_or_listener(cl_hw))
+		mod_timer(&cl_hw->maintenance_fast_timer,
+			  jiffies + msecs_to_jiffies(CL_MAINTENANCE_PERIOD_FAST_MS));
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 45/96] cl8k: add maintenance.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (43 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 44/96] cl8k: add maintenance.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 46/96] cl8k: add motion_sense.c viktor.barna
                   ` (50 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/maintenance.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/maintenance.h

diff --git a/drivers/net/wireless/celeno/cl8k/maintenance.h b/drivers/net/wireless/celeno/cl8k/maintenance.h
new file mode 100644
index 000000000000..c9d1526a47a0
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/maintenance.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_MAINTENANCE_H
+#define CL_MAINTENANCE_H
+
+#include "hw.h"
+
+#define CL_MAINTENANCE_PERIOD_SLOW_MS   1000
+#define CL_MAINTENANCE_PERIOD_FAST_MS   100
+
+void cl_maintenance_init(struct cl_hw *cl_hw);
+void cl_maintenance_close(struct cl_hw *cl_hw);
+void cl_maintenance_stop(struct cl_hw *cl_hw);
+void cl_maintenance_start(struct cl_hw *cl_hw);
+
+#endif /* CL_MAINTENANCE_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 46/96] cl8k: add motion_sense.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (44 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 45/96] cl8k: add maintenance.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 47/96] cl8k: add motion_sense.h viktor.barna
                   ` (49 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/motion_sense.c   | 244 ++++++++++++++++++
 1 file changed, 244 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.c

diff --git a/drivers/net/wireless/celeno/cl8k/motion_sense.c b/drivers/net/wireless/celeno/cl8k/motion_sense.c
new file mode 100644
index 000000000000..2e4c05564900
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/motion_sense.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "hw.h"
+#include "debug.h"
+#include "motion_sense.h"
+
+#define motion_pr(...) \
+	do { \
+		if (cl_hw->motion_sense_dbg) \
+			pr_debug("[MOTION SENSE]" __VA_ARGS__); \
+	} while (0)
+
+/* Minimum time (+1) for taking a decison */
+#define MOTION_SENSE_MIN_DECISION_MGMT_CTL 4
+#define MOTION_SENSE_MIN_DECISION_DATA     9
+#define MOTION_SENSE_MIN_DECISION_BA       9
+
+static void _cl_motion_sense_sta_add(struct cl_motion_rssi *motion_rssi)
+{
+	motion_rssi->max = S8_MIN;
+	motion_rssi->min = S8_MAX;
+}
+
+void cl_motion_sense_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	_cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_mgmt_ctl);
+	_cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_data);
+	_cl_motion_sense_sta_add(&cl_sta->motion_sense.rssi_ba);
+}
+
+static void cl_motion_sense_rssi_handler(struct cl_hw *cl_hw,
+					 struct cl_motion_rssi *motion_rssi,
+					 s8 rssi[MAX_ANTENNAS])
+{
+	u8 i;
+
+	motion_rssi->cnt++;
+
+	for (i = 0; i < cl_hw->num_antennas; i++)
+		motion_rssi->sum[i] += rssi[i];
+}
+
+void cl_motion_sense_rssi_mgmt_ctl(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				   struct hw_rxhdr *rxhdr)
+{
+	/* RSSI of mgmt and ctl packets */
+	if (cl_hw->conf->ci_motion_sense_en) {
+		s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+		u8 i;
+
+		if (!IS_REAL_PHY(cl_hw->chip))
+			for (i = 0; i < cl_hw->num_antennas; i++)
+				if (rssi[i] == 0)
+					return;
+
+		cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_mgmt_ctl, rssi);
+	}
+}
+
+void cl_motion_sense_rssi_data(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct hw_rxhdr *rxhdr)
+{
+	/* RSSI of data packets */
+	s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+	if (!cl_hw->conf->ci_motion_sense_en)
+		return;
+
+	if (!IS_REAL_PHY(cl_hw->chip) && rssi[0] == 0)
+		return;
+
+	cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_data, rssi);
+}
+
+void cl_motion_sense_rssi_ba(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+	/* RSSI of block-acks */
+	if (cl_hw->conf->ci_motion_sense_en)
+		cl_motion_sense_rssi_handler(cl_hw, &cl_sta->motion_sense.rssi_ba, rssi);
+}
+
+static s8 cl_motion_sense_calc_new_rssi(struct cl_hw *cl_hw, struct cl_motion_rssi *motion_rssi)
+{
+	u8 i = 0;
+	s8 rssi_avg[MAX_ANTENNAS] = {0};
+
+	/* Calculate average rssi */
+	for (i = 0; i < cl_hw->num_antennas; i++)
+		rssi_avg[i] = (s8)(motion_rssi->sum[i] / motion_rssi->cnt);
+
+	/* Reset rssi sum for next maintenance cycle */
+	memset(motion_rssi->sum, 0, sizeof(motion_rssi->sum));
+	motion_rssi->cnt = 0;
+
+	return cl_rssi_calc_equivalent(cl_hw, rssi_avg);
+}
+
+static void cl_motion_sense_state(struct cl_hw *cl_hw, struct cl_motion_rssi *motion_rssi,
+				  u8 sta_idx, u8 min_history, const s8 *type)
+{
+	u8 i = 0;
+	s8 rssi_new = 0, rssi_old = 0;
+
+	if (motion_rssi->cnt == 0)
+		return;
+
+	/* Get new and old rssi */
+	rssi_new = cl_motion_sense_calc_new_rssi(cl_hw, motion_rssi);
+	rssi_old = motion_rssi->history[motion_rssi->idx];
+
+	/* Add new rssi to history and increase history index */
+	motion_rssi->history[motion_rssi->idx] = rssi_new;
+
+	motion_rssi->idx++;
+	if (motion_rssi->idx == MOTION_SENSE_SIZE)
+		motion_rssi->idx = 0;
+
+	/* Check if new rssi is max or min */
+	if (rssi_new > motion_rssi->max) {
+		motion_rssi->max = rssi_new;
+		goto out;
+	} else if (rssi_new < motion_rssi->min) {
+		motion_rssi->min = rssi_new;
+		goto out;
+	}
+
+	/*
+	 * Check if old rssi was max or min.
+	 * If so, go over history and find new max/min
+	 */
+	if (rssi_old == motion_rssi->max) {
+		motion_rssi->max = S8_MIN;
+
+		for (i = 0; i < MOTION_SENSE_SIZE; i++) {
+			if (motion_rssi->history[i] == 0)
+				break;
+
+			if (motion_rssi->history[i] > motion_rssi->max)
+				motion_rssi->max = motion_rssi->history[i];
+		}
+	} else if (rssi_old == motion_rssi->min) {
+		motion_rssi->min = S8_MAX;
+
+		for (i = 0; i < MOTION_SENSE_SIZE; i++) {
+			if (motion_rssi->history[i] == 0)
+				break;
+
+			if (motion_rssi->history[i] < motion_rssi->min)
+				motion_rssi->min = motion_rssi->history[i];
+		}
+	}
+
+out:
+	/* Wait X second after connection, before making first decision */
+	if (motion_rssi->history[min_history] == 0)
+		return;
+
+	/* According to delta decide if station is STATIC or in MOTION */
+	if ((motion_rssi->max - motion_rssi->min) < cl_hw->conf->ci_motion_sense_rssi_thr) {
+		if (motion_rssi->state == STATE_STATIC)
+			return;
+
+		motion_rssi->state = STATE_STATIC;
+
+		motion_pr("%s - sta_idx=%u, min=%d, max=%d, state=STATIC\n",
+			  type, sta_idx, motion_rssi->min, motion_rssi->max);
+	} else {
+		if (motion_rssi->state == STATE_MOVING)
+			return;
+
+		motion_rssi->state = STATE_MOVING;
+
+		motion_pr("%s - sta_idx=%u, min=%d, max=%d, state=MOVING\n",
+			  type, sta_idx, motion_rssi->min, motion_rssi->max);
+	}
+}
+
+static void cl_motion_sense_moving(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				   struct cl_motion_sense *motion_sense)
+{
+	if (motion_sense->combined_state != STATE_MOVING) {
+		motion_sense->combined_state = STATE_MOVING;
+		motion_pr("sta_idx = %u, combined_state = MOVING\n",
+			  cl_sta->sta_idx);
+	}
+}
+
+static void cl_motion_sense_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				   struct cl_motion_sense *motion_sense)
+{
+	if (motion_sense->combined_state != STATE_STATIC) {
+		motion_sense->combined_state = STATE_STATIC;
+		motion_pr("sta_idx = %u, combined_state = STATIC\n",
+			  cl_sta->sta_idx);
+	}
+}
+
+static void cl_motion_sense_combined_state(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_motion_sense *motion_sense = &cl_sta->motion_sense;
+
+	if (motion_sense->rssi_mgmt_ctl.history[MOTION_SENSE_MIN_DECISION_MGMT_CTL] == 0 &&
+	    motion_sense->rssi_data.history[MOTION_SENSE_MIN_DECISION_DATA] == 0 &&
+	    motion_sense->rssi_ba.history[MOTION_SENSE_MIN_DECISION_BA] == 0)
+		return;
+
+	if (motion_sense->rssi_mgmt_ctl.state == STATE_MOVING ||
+	    motion_sense->rssi_data.state == STATE_MOVING ||
+	    motion_sense->rssi_ba.state == STATE_MOVING)
+		cl_motion_sense_moving(cl_hw, cl_sta, motion_sense);
+	else
+		cl_motion_sense_static(cl_hw, cl_sta, motion_sense);
+}
+
+static void cl_motion_sense_maintenance_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	u8 sta_idx = cl_sta->sta_idx;
+	struct cl_motion_sense *motion_sense = &cl_sta->motion_sense;
+
+	cl_motion_sense_state(cl_hw, &motion_sense->rssi_mgmt_ctl, sta_idx,
+			      MOTION_SENSE_MIN_DECISION_MGMT_CTL, "mgmt/ctl");
+	cl_motion_sense_state(cl_hw, &motion_sense->rssi_data, sta_idx,
+			      MOTION_SENSE_MIN_DECISION_DATA, "data");
+	cl_motion_sense_state(cl_hw, &motion_sense->rssi_ba, sta_idx,
+			      MOTION_SENSE_MIN_DECISION_BA, "ba");
+
+	if (motion_sense->forced_state != STATE_NULL)
+		return;
+
+	cl_motion_sense_combined_state(cl_hw, cl_sta);
+}
+
+void cl_motion_sense_maintenance(struct cl_hw *cl_hw)
+{
+	cl_sta_loop(cl_hw, cl_motion_sense_maintenance_sta);
+}
+
+bool cl_motion_sense_is_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	return (cl_sta->motion_sense.combined_state == STATE_STATIC);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 47/96] cl8k: add motion_sense.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (45 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 46/96] cl8k: add motion_sense.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 48/96] cl8k: add pci.c viktor.barna
                   ` (48 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/motion_sense.h   | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/motion_sense.h

diff --git a/drivers/net/wireless/celeno/cl8k/motion_sense.h b/drivers/net/wireless/celeno/cl8k/motion_sense.h
new file mode 100644
index 000000000000..9ea63f561a92
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/motion_sense.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_MOTION_SENSE_H
+#define CL_MOTION_SENSE_H
+
+#include <linux/types.h>
+
+#include "rx.h"
+
+#define MOTION_SENSE_SIZE 30
+
+enum cl_motion_state {
+	STATE_NULL,
+	STATE_MOVING,
+	STATE_STATIC
+};
+
+struct cl_motion_rssi {
+	s32 sum[MAX_ANTENNAS];
+	s32 cnt;
+	s8 history[MOTION_SENSE_SIZE];
+	u8 idx;
+	s8 max;
+	s8 min;
+	enum cl_motion_state state;
+};
+
+struct cl_motion_sense {
+	struct cl_motion_rssi rssi_mgmt_ctl;
+	struct cl_motion_rssi rssi_data;
+	struct cl_motion_rssi rssi_ba;
+	enum cl_motion_state combined_state;
+	enum cl_motion_state forced_state;
+};
+
+void cl_motion_sense_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_motion_sense_rssi_mgmt_ctl(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				   struct hw_rxhdr *rxhdr);
+void cl_motion_sense_rssi_data(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct hw_rxhdr *rxhdr);
+void cl_motion_sense_rssi_ba(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_motion_sense_maintenance(struct cl_hw *cl_hw);
+bool cl_motion_sense_is_static(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+
+#endif /* CL_MOTION_SENSE_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 48/96] cl8k: add pci.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (46 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 47/96] cl8k: add motion_sense.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 49/96] cl8k: add pci.h viktor.barna
                   ` (47 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/pci.c | 2468 ++++++++++++++++++++++++
 1 file changed, 2468 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/pci.c

diff --git a/drivers/net/wireless/celeno/cl8k/pci.c b/drivers/net/wireless/celeno/cl8k/pci.c
new file mode 100644
index 000000000000..dffbcc9478ee
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/pci.c
@@ -0,0 +1,2468 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/irq.h>
+
+#include "chip.h"
+#include "hw.h"
+#include "main.h"
+#include "ela.h"
+#include "debug.h"
+#include "reg/reg_defs.h"
+#include "enhanced_tim.h"
+#include "pci.h"
+
+#define DMA_CFM_QUEUE_SIZE 1024
+#define DMA_CFM_TOTAL_SIZE (8 * sizeof(struct cl_ipc_cfm_msg) * DMA_CFM_QUEUE_SIZE)
+
+static void cl_ipc_env_free(struct cl_hw *cl_hw)
+{
+	kfree(cl_hw->ipc_env);
+	cl_hw->ipc_env = NULL;
+}
+
+static void cl_ipc_ring_indices_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	if (!ipc_env->ring_indices_elem)
+		return;
+
+	memset(ipc_env->ring_indices_elem->indices, 0, sizeof(struct cl_ipc_ring_indices));
+	ipc_env->ring_indices_elem->indices = NULL;
+	kfree(ipc_env->ring_indices_elem);
+	ipc_env->ring_indices_elem = NULL;
+}
+
+static void _cl_ipc_txdesc_dealloc(struct cl_hw *cl_hw,
+				   struct txdesc *txdesc,
+				   __le32 dma_addr,
+				   u32 desc_num)
+{
+	dma_addr_t phys_dma_addr = le32_to_cpu(dma_addr);
+	u32 size = (desc_num * sizeof(struct txdesc));
+
+	if (size < PAGE_SIZE)
+		dma_pool_free(cl_hw->txdesc_pool, txdesc, phys_dma_addr);
+	else
+		dma_free_coherent(cl_hw->chip->dev, size, txdesc, phys_dma_addr);
+}
+
+static void cl_ipc_txdesc_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+	struct tx_queues_dma_addr *queues_dma_addr = tx_queues->queues_dma_addr;
+	u32 i;
+
+	if (queues_dma_addr->bcmc) {
+		_cl_ipc_txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_bcmc,
+				       queues_dma_addr->bcmc, IPC_TXDESC_CNT_BCMC);
+		queues_dma_addr->bcmc = 0;
+	}
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		if (queues_dma_addr->single[i]) {
+			_cl_ipc_txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_single[i],
+					       queues_dma_addr->single[i],
+					       IPC_TXDESC_CNT_SINGLE);
+			queues_dma_addr->single[i] = 0;
+		}
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		if (queues_dma_addr->agg[i]) {
+			_cl_ipc_txdesc_dealloc(cl_hw, tx_queues->ipc_txdesc_agg[i],
+					       queues_dma_addr->agg[i],
+					       TXDESC_AGG_Q_SIZE_MAX);
+			queues_dma_addr->agg[i] = 0;
+		}
+
+	dma_pool_destroy(cl_hw->txdesc_pool);
+	cl_hw->txdesc_pool = NULL;
+}
+
+static void cl_ipc_tx_queues_dealloc(struct cl_hw *cl_hw)
+{
+	u32 len = sizeof(struct tx_queues_dma_addr);
+	dma_addr_t phys_dma_addr = cl_hw->ipc_env->tx_queues.dma_addr;
+
+	if (!cl_hw->ipc_env->tx_queues.queues_dma_addr)
+		return;
+
+	dma_free_coherent(cl_hw->chip->dev, len,
+			  (void *)cl_hw->ipc_env->tx_queues.queues_dma_addr,
+			  phys_dma_addr);
+	cl_hw->ipc_env->tx_queues.queues_dma_addr = NULL;
+}
+
+static void cl_ipc_rx_dealloc_skb(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem,
+				  u16 len)
+{
+	dma_unmap_single(cl_hw->chip->dev, rx_elem->dma_addr, len,
+			 DMA_FROM_DEVICE);
+	kfree_skb(rx_elem->skb);
+	rx_elem->skb = NULL;
+}
+
+static void _cl_ipc_rx_dealloc_buff(struct cl_hw *cl_hw,
+				    u32 *rxbuf,
+				    __le32 dma_addr,
+				    u32 desc_num)
+{
+	dma_addr_t phys_dma_addr = le32_to_cpu(dma_addr);
+	u32 size = (desc_num * sizeof(u32));
+
+	dma_free_coherent(cl_hw->chip->dev, size, rxbuf, phys_dma_addr);
+}
+
+static void cl_ipc_rx_dealloc_buff(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+	struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+
+	if (rxbuf_rxm->dma_payload_base_addr)
+		_cl_ipc_rx_dealloc_buff(cl_hw,
+					rxbuf_rxm->dma_payload_addr,
+					rxbuf_rxm->dma_payload_base_addr,
+					IPC_RXBUF_CNT_RXM);
+
+	if (rxbuf_fw->dma_payload_base_addr)
+		_cl_ipc_rx_dealloc_buff(cl_hw,
+					rxbuf_fw->dma_payload_addr,
+					rxbuf_fw->dma_payload_base_addr,
+					IPC_RXBUF_CNT_FW);
+}
+
+static void cl_ipc_rx_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+	u16 rxbuf_size_rxm = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM];
+	u16 rxbuf_size_fw = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW];
+	int i;
+
+	if (!cl_hw->rx_elems)
+		return;
+
+	for (i = 0; i < IPC_RXBUF_CNT_RXM; i++, rx_elem++)
+		if (rx_elem->skb && !rx_elem->passed)
+			cl_ipc_rx_dealloc_skb(cl_hw, rx_elem, rxbuf_size_rxm);
+
+	for (i = 0; i < IPC_RXBUF_CNT_FW; i++, rx_elem++)
+		if (rx_elem->skb && !rx_elem->passed)
+			cl_ipc_rx_dealloc_skb(cl_hw, rx_elem, rxbuf_size_fw);
+
+	kfree(cl_hw->rx_elems);
+	cl_hw->rx_elems = NULL;
+
+	cl_ipc_rx_dealloc_buff(cl_hw);
+}
+
+static void cl_ipc_msg_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_e2a_msg_elem *msg_elem;
+	int i;
+
+	if (!cl_hw->e2a_msg_elems || !cl_hw->e2a_msg_pool)
+		return;
+
+	for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+	     i < IPC_E2A_MSG_BUF_CNT; i++, msg_elem++) {
+		if (msg_elem->msgbuf_ptr) {
+			dma_pool_free(cl_hw->e2a_msg_pool, msg_elem->msgbuf_ptr,
+				      msg_elem->dma_addr);
+			msg_elem->msgbuf_ptr = NULL;
+		}
+	}
+
+	dma_pool_destroy(cl_hw->e2a_msg_pool);
+	cl_hw->e2a_msg_pool = NULL;
+
+	kfree(cl_hw->e2a_msg_elems);
+	cl_hw->e2a_msg_elems = NULL;
+}
+
+static void cl_ipc_radar_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_radar_elem *radar_elem;
+	int i;
+
+	if (!cl_hw->radar_pool || !cl_hw->radar_elems)
+		return;
+
+	for (i = 0, radar_elem = cl_hw->radar_elems;
+	     i < IPC_RADAR_BUF_CNT; i++, radar_elem++) {
+		if (radar_elem->radarbuf_ptr) {
+			dma_pool_free(cl_hw->radar_pool, radar_elem->radarbuf_ptr,
+				      radar_elem->dma_addr);
+			radar_elem->radarbuf_ptr = NULL;
+		}
+	}
+
+	dma_pool_destroy(cl_hw->radar_pool);
+	cl_hw->radar_pool = NULL;
+
+	kfree(cl_hw->radar_elems);
+	cl_hw->radar_elems = NULL;
+}
+
+static void cl_ipc_dbg_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_dbg_elem *dbg_elem;
+	int i;
+
+	if (!cl_hw->dbg_pool || !cl_hw->dbg_elems)
+		return;
+
+	for (i = 0, dbg_elem = cl_hw->dbg_elems;
+	     i < IPC_DBG_BUF_CNT; i++, dbg_elem++) {
+		if (dbg_elem->dbgbuf_ptr) {
+			dma_pool_free(cl_hw->dbg_pool, dbg_elem->dbgbuf_ptr,
+				      dbg_elem->dma_addr);
+			dbg_elem->dbgbuf_ptr = NULL;
+		}
+	}
+
+	dma_pool_destroy(cl_hw->dbg_pool);
+	cl_hw->dbg_pool = NULL;
+
+	kfree(cl_hw->dbg_elems);
+	cl_hw->dbg_elems = NULL;
+}
+
+static void cl_ipc_cfm_dealloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	dma_free_coherent(cl_hw->chip->dev,
+			  DMA_CFM_TOTAL_SIZE,
+			  ipc_env->cfm_virt_base_addr,
+			  ipc_env->cfm_dma_base_addr);
+
+	ipc_env->cfm_dma_base_addr = 0;
+	ipc_env->cfm_virt_base_addr = NULL;
+}
+
+static void cl_ipc_dbg_info_dealloc(struct cl_hw *cl_hw)
+{
+	if (!cl_hw->dbginfo.buf)
+		return;
+
+	dma_free_coherent(cl_hw->chip->dev,
+			  cl_hw->dbginfo.bufsz,
+			  cl_hw->dbginfo.buf,
+			  cl_hw->dbginfo.dma_addr);
+
+	cl_hw->dbginfo.buf = NULL;
+}
+
+static void cl_ipc_elems_dealloc(struct cl_hw *cl_hw)
+{
+	cl_ipc_ring_indices_dealloc(cl_hw);
+	cl_ipc_txdesc_dealloc(cl_hw);
+	cl_ipc_tx_queues_dealloc(cl_hw);
+	cl_ipc_rx_dealloc(cl_hw);
+	cl_ipc_msg_dealloc(cl_hw);
+	cl_ipc_radar_dealloc(cl_hw);
+	cl_ipc_dbg_dealloc(cl_hw);
+	cl_ipc_cfm_dealloc(cl_hw);
+	cl_ipc_dbg_info_dealloc(cl_hw);
+}
+
+static int cl_ipc_ring_indices_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	ipc_env->ring_indices_elem = kzalloc(sizeof(*ipc_env->ring_indices_elem), GFP_KERNEL);
+
+	if (!ipc_env->ring_indices_elem)
+		return -ENOMEM;
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		ipc_env->ring_indices_elem->indices = chip->ring_indices.params;
+		ipc_env->ring_indices_elem->dma_addr = chip->ring_indices.dma_addr;
+	} else {
+		ipc_env->ring_indices_elem->indices = chip->ring_indices.params + 1;
+		ipc_env->ring_indices_elem->dma_addr =
+			(u32)chip->ring_indices.dma_addr + sizeof(struct cl_ipc_ring_indices);
+	}
+
+	memset(ipc_env->ring_indices_elem->indices, 0, sizeof(struct cl_ipc_ring_indices));
+
+	return 0;
+}
+
+static int cl_ipc_tx_queues_alloc(struct cl_hw *cl_hw)
+{
+	struct tx_queues_dma_addr *buf = NULL;
+	u32 size = sizeof(struct tx_queues_dma_addr);
+	dma_addr_t phys_dma_addr;
+
+	buf = dma_alloc_coherent(cl_hw->chip->dev, size, &phys_dma_addr, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	cl_hw->ipc_env->tx_queues.queues_dma_addr = buf;
+	cl_hw->ipc_env->tx_queues.dma_addr = phys_dma_addr;
+
+	return 0;
+}
+
+static int __cl_ipc_txdesc_alloc(struct cl_hw *cl_hw,
+				 struct txdesc **txdesc,
+				 __le32 *dma_addr,
+				 u32 desc_num)
+{
+	dma_addr_t phys_dma_addr;
+	u32 size = (desc_num * sizeof(struct txdesc));
+
+	if (size < PAGE_SIZE) {
+		*txdesc = dma_pool_alloc(cl_hw->txdesc_pool, GFP_KERNEL, &phys_dma_addr);
+
+		if (!(*txdesc)) {
+			cl_dbg_err(cl_hw, "dma_pool_alloc failed size=%d\n", size);
+			return -ENOMEM;
+		}
+	} else {
+		*txdesc = dma_alloc_coherent(cl_hw->chip->dev, size, &phys_dma_addr, GFP_KERNEL);
+
+		if (!(*txdesc)) {
+			cl_dbg_err(cl_hw, "dma_alloc_coherent failed size=%d\n", size);
+			return -ENOMEM;
+		}
+	}
+
+	*dma_addr = cpu_to_le32(phys_dma_addr);
+	memset(*txdesc, 0, size);
+
+	return 0;
+}
+
+static int _cl_ipc_txdesc_alloc(struct cl_hw *cl_hw)
+{
+	/*
+	 * Allocate ipc txdesc for each queue, map the base
+	 * address to the DMA and set the queues size
+	 */
+	struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+	struct tx_queues_dma_addr *queues_dma_addr = tx_queues->queues_dma_addr;
+	u32 i;
+	int ret = 0;
+
+	ret = __cl_ipc_txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_bcmc,
+				    &queues_dma_addr->bcmc, IPC_TXDESC_CNT_BCMC);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++) {
+		ret = __cl_ipc_txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_single[i],
+					    &queues_dma_addr->single[i],
+					    IPC_TXDESC_CNT_SINGLE);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+		ret = __cl_ipc_txdesc_alloc(cl_hw, &tx_queues->ipc_txdesc_agg[i],
+					    &queues_dma_addr->agg[i],
+					    TXDESC_AGG_Q_SIZE_MAX);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int cl_ipc_txdesc_alloc(struct cl_hw *cl_hw)
+{
+	u32 pool_size = IPC_TXDESC_CNT_SINGLE * sizeof(struct txdesc);
+
+	cl_hw->txdesc_pool = dma_pool_create("cl_txdesc_pool", cl_hw->chip->dev,
+					     pool_size, cache_line_size(), 0);
+
+	if (!cl_hw->txdesc_pool) {
+		cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+		return -ENOMEM;
+	}
+
+	return _cl_ipc_txdesc_alloc(cl_hw);
+}
+
+static int cl_ipc_rx_skb_alloc(struct cl_hw *cl_hw)
+{
+	/*
+	 * This function allocates Rx elements for DMA
+	 * transfers and pushes the DMA address to FW.
+	 */
+	struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	int i = 0;
+	u16 rxbuf_size_rxm = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM];
+	u16 rxbuf_size_fw = cl_hw->conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW];
+
+	/* Allocate and push RXM buffers */
+	for (i = 0; i < IPC_RXBUF_CNT_RXM; rx_elem++, i++) {
+		if (cl_ipc_rx_elem_alloc(cl_hw, rx_elem, rxbuf_size_rxm)) {
+			cl_dbg_verbose(cl_hw, "RXM rx_elem allocation failed !!!\n");
+			return -ENOMEM;
+		}
+		cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_RXM);
+	}
+
+	/* Allocate and push FW buffers */
+	for (i = 0; i < IPC_RXBUF_CNT_FW; rx_elem++, i++) {
+		if (cl_ipc_rx_elem_alloc(cl_hw, rx_elem, rxbuf_size_fw)) {
+			cl_dbg_verbose(cl_hw, "FW rx_elem allocation failed !!!\n");
+			return -ENOMEM;
+		}
+		cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_FW);
+	}
+
+	return 0;
+}
+
+static int _cl_ipc_rx_buf_alloc(struct cl_hw *cl_hw, u32 **rxbuf, __le32 *dma_addr, u32 desc_num)
+{
+	dma_addr_t phys_dma_addr;
+	u32 size = (desc_num * sizeof(u32));
+
+	*rxbuf = dma_alloc_coherent(cl_hw->chip->dev,
+				    size,
+				    &phys_dma_addr,
+				    GFP_KERNEL);
+
+	if (!(*rxbuf))
+		return -ENOMEM;
+
+	*dma_addr = cpu_to_le32(phys_dma_addr);
+	memset(*rxbuf, 0, size);
+
+	return 0;
+}
+
+static int cl_ipc_rx_buf_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+	struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+	int ret = 0;
+
+	rxbuf_rxm->ipc_host_rxdesc_ptr = ipc_env->ipc_host_rxdesc_rxm;
+	rxbuf_fw->ipc_host_rxdesc_ptr = ipc_env->ipc_host_rxdesc_fw;
+
+	/* Allocate RXM RX write/read indexes */
+	ret = _cl_ipc_rx_buf_alloc(cl_hw,
+				   (u32 **)&rxbuf_rxm->dma_payload_addr,
+				   &rxbuf_rxm->dma_payload_base_addr,
+				   IPC_RXBUF_CNT_RXM);
+	if (ret)
+		return ret;
+
+	/* Allocate FW RX write/read indexes */
+	ret = _cl_ipc_rx_buf_alloc(cl_hw,
+				   (u32 **)&rxbuf_fw->dma_payload_addr,
+				   &rxbuf_fw->dma_payload_base_addr,
+				   IPC_RXBUF_CNT_FW);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int cl_ipc_rx_alloc(struct cl_hw *cl_hw)
+{
+	u32 total_rx_elems = IPC_RXBUF_CNT_RXM + IPC_RXBUF_CNT_FW;
+	u32 alloc_size = total_rx_elems * sizeof(struct cl_rx_elem);
+	int ret = cl_ipc_rx_buf_alloc(cl_hw);
+
+	if (ret)
+		return ret;
+
+	cl_hw->rx_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+	if (!cl_hw->rx_elems)
+		return -ENOMEM;
+
+	return cl_ipc_rx_skb_alloc(cl_hw);
+}
+
+static int _cl_ipc_msg_alloc(struct cl_hw *cl_hw, struct cl_e2a_msg_elem *msg_elem)
+{
+	dma_addr_t dma_addr;
+	struct cl_ipc_e2a_msg *msg;
+
+	/* Initialize the message pattern to NULL */
+	msg = dma_pool_alloc(cl_hw->e2a_msg_pool, GFP_KERNEL, &dma_addr);
+	if (!msg)
+		return -ENOMEM;
+
+	msg->pattern = 0;
+
+	/* Save the msg pointer (for deallocation) and the dma_addr */
+	msg_elem->msgbuf_ptr = msg;
+	msg_elem->dma_addr = dma_addr;
+
+	return 0;
+}
+
+static int cl_ipc_msg_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_e2a_msg_elem *msg_elem;
+	u32 alloc_size = IPC_E2A_MSG_BUF_CNT * sizeof(struct cl_e2a_msg_elem);
+	u32 i;
+
+	cl_hw->e2a_msg_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+	if (!cl_hw->e2a_msg_elems)
+		return -ENOMEM;
+
+	cl_hw->e2a_msg_pool = dma_pool_create("dma_pool_msg",
+					      cl_hw->chip->dev,
+					      sizeof(struct cl_ipc_e2a_msg),
+					      cache_line_size(),
+					      0);
+
+	if (!cl_hw->e2a_msg_pool) {
+		cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize the msg buffers in the global IPC array. */
+	for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+	     i < IPC_E2A_MSG_BUF_CNT; msg_elem++, i++) {
+		if (_cl_ipc_msg_alloc(cl_hw, msg_elem)) {
+			cl_dbg_verbose(cl_hw, "msg allocation failed !!!\n");
+			return -ENOMEM;
+		}
+
+		cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+	}
+
+	return 0;
+}
+
+static int _cl_ipc_radar_alloc(struct cl_hw *cl_hw, struct cl_radar_elem *radar_elem)
+{
+	dma_addr_t dma_addr;
+	struct cl_radar_pulse_array *radar;
+
+	/* Initialize the message pattern to NULL */
+	radar = dma_pool_alloc(cl_hw->radar_pool, GFP_KERNEL, &dma_addr);
+	if (!radar)
+		return -ENOMEM;
+
+	radar->cnt = 0;
+
+	/* Save the msg pointer (for deallocation) and the dma_addr */
+	radar_elem->radarbuf_ptr = radar;
+	radar_elem->dma_addr = dma_addr;
+
+	return 0;
+}
+
+static int cl_ipc_radar_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_radar_elem *radar_elem;
+	u32 alloc_size = IPC_RADAR_BUF_CNT * sizeof(struct cl_radar_elem);
+	u32 i;
+
+	cl_hw->radar_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+	if (!cl_hw->radar_elems)
+		return -ENOMEM;
+
+	cl_hw->radar_pool = dma_pool_create("dma_pool_radar",
+					    cl_hw->chip->dev,
+					    sizeof(struct cl_radar_pulse_array),
+					    cache_line_size(),
+					    0);
+
+	if (!cl_hw->radar_pool) {
+		cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize the radar buffers in the global IPC array. */
+	for (i = 0, radar_elem = cl_hw->radar_elems;
+	     i < IPC_RADAR_BUF_CNT; radar_elem++, i++) {
+		if (_cl_ipc_radar_alloc(cl_hw, radar_elem)) {
+			cl_dbg_verbose(cl_hw, "radar allocation failed !!!\n");
+			return -ENOMEM;
+		}
+
+		cl_ipc_radarbuf_push(ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+	}
+
+	return 0;
+}
+
+static int _cl_ipc_dbg_alloc(struct cl_hw *cl_hw, struct cl_dbg_elem *dbg_elem)
+{
+	dma_addr_t dma_addr;
+	struct cl_ipc_dbg_msg *dbg_msg;
+
+	dbg_msg = dma_pool_alloc(cl_hw->dbg_pool, GFP_KERNEL, &dma_addr);
+	if (!dbg_msg)
+		return -ENOMEM;
+
+	dbg_msg->pattern = 0;
+
+	/* Save the Debug msg pointer (for deallocation) and the dma_addr */
+	dbg_elem->dbgbuf_ptr = dbg_msg;
+	dbg_elem->dma_addr = dma_addr;
+
+	return 0;
+}
+
+static int cl_ipc_dbg_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_dbg_elem *dbg_elem;
+	u32 alloc_size = IPC_DBG_BUF_CNT * sizeof(struct cl_dbg_elem);
+	u32 i;
+
+	cl_hw->dbg_elems = kzalloc(alloc_size, GFP_KERNEL);
+
+	if (!cl_hw->dbg_elems)
+		return -ENOMEM;
+
+	cl_hw->dbg_pool = dma_pool_create("dma_pool_dbg",
+					  cl_hw->chip->dev,
+					  sizeof(struct cl_ipc_dbg_msg),
+					  cache_line_size(),
+					  0);
+
+	if (!cl_hw->dbg_pool) {
+		cl_dbg_verbose(cl_hw, "dma_pool_create failed !!!\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize the dbg buffers in the global IPC array. */
+	for (i = 0, dbg_elem = cl_hw->dbg_elems;
+	     i < IPC_DBG_BUF_CNT; dbg_elem++, i++) {
+		if (_cl_ipc_dbg_alloc(cl_hw, dbg_elem)) {
+			cl_dbg_verbose(cl_hw, "dbgelem allocation failed !!!\n");
+			return -ENOMEM;
+		}
+
+		cl_ipc_dbgbuf_push(ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+	}
+
+	return 0;
+}
+
+static int cl_ipc_cfm_alloc(struct cl_hw *cl_hw)
+{
+	dma_addr_t dma_addr;
+	u8 *host_virt_addr;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	host_virt_addr = dma_alloc_coherent(cl_hw->chip->dev,
+					    DMA_CFM_TOTAL_SIZE,
+					    &dma_addr,
+					    GFP_KERNEL);
+
+	if (!host_virt_addr)
+		return -ENOMEM;
+
+	memset(host_virt_addr, 0, DMA_CFM_TOTAL_SIZE);
+	ipc_env->cfm_dma_base_addr = dma_addr;
+	ipc_env->cfm_virt_base_addr = host_virt_addr;
+
+	memset(ipc_env->cfm_virt_base_addr, 0, IPC_CFM_SIZE);
+
+	return 0;
+}
+
+static int _cl_ipc_dbg_info_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct dbg_info *buf;
+	dma_addr_t dma_addr;
+	u32 len = sizeof(struct dbg_info);
+
+	if (!chip->conf->ci_la_mirror_en)
+		len -= sizeof_field(struct dbg_dump_info, la_mem);
+
+	buf = dma_alloc_coherent(chip->dev, len, &dma_addr, GFP_KERNEL);
+
+	if (!buf) {
+		cl_dbg_verbose(cl_hw, "buffer alloc of size %u failed\n", len);
+		return -ENOMEM;
+	}
+
+	memset(buf, 0, len);
+	buf->u.type = DBG_INFO_UNSET;
+
+	cl_hw->dbginfo.buf = buf;
+	cl_hw->dbginfo.dma_addr = dma_addr;
+	cl_hw->dbginfo.bufsz = len;
+
+	return 0;
+}
+
+static int cl_ipc_dbg_info_alloc(struct cl_hw *cl_hw)
+{
+	/* Initialize the debug information buffer */
+	if (_cl_ipc_dbg_info_alloc(cl_hw)) {
+		cl_dbg_verbose(cl_hw, "dbginfo allocation failed !!!\n");
+		return -ENOMEM;
+	}
+
+	cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+
+	return 0;
+}
+
+static int cl_ipc_elems_alloc(struct cl_hw *cl_hw)
+{
+	/* Allocate all the elements required for communications with firmware */
+	if (cl_ipc_ring_indices_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_tx_queues_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_txdesc_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_rx_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_msg_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_radar_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_dbg_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_cfm_alloc(cl_hw))
+		goto out_err;
+
+	if (cl_ipc_dbg_info_alloc(cl_hw))
+		goto out_err;
+
+	return 0;
+
+out_err:
+	cl_ipc_elems_dealloc(cl_hw);
+	return -ENOMEM;
+}
+
+static u8 cl_ipc_dbgfile_handler(struct cl_hw *cl_hw, ptrdiff_t hostid)
+{
+	struct cl_dbg_elem *dbg_elem = (struct cl_dbg_elem *)hostid;
+	struct cl_ipc_dbg_msg *dbg_msg;
+	u8 ret = 0;
+
+	/* Retrieve the message structure */
+	dbg_msg = (struct cl_ipc_dbg_msg *)dbg_elem->dbgbuf_ptr;
+
+	if (!dbg_msg) {
+		ret = -1;
+		cl_dbg_err(cl_hw, "dbgbuf_ptr is NULL!!!!\n");
+		goto dbg_push;
+	}
+
+	/* Look for pattern which means that this hostbuf has been used for a MSG */
+	if (le32_to_cpu(dbg_msg->pattern) != IPC_DBG_VALID_PATTERN) {
+		ret = -1;
+		goto dbg_no_push;
+	}
+
+	/* Reset the msg element and re-use it */
+	dbg_msg->pattern = 0;
+
+	/* Display the firmware string */
+	cl_dbgfile_print_fw_str(cl_hw, dbg_msg->string, IPC_DBG_PARAM_SIZE);
+
+dbg_push:
+	/* make sure memory is written before push to HW */
+	wmb();
+
+	/* Push back the buffer to the firmware */
+	cl_ipc_dbgbuf_push(cl_hw->ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+
+dbg_no_push:
+	return ret;
+}
+
+static void cl_ipc_dbgfile_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_hostbuf *dbg_array = ipc_env->dbg_hostbuf_array;
+	int dbg_handled = 0;
+
+	while (!cl_ipc_dbgfile_handler(cl_hw, dbg_array[ipc_env->dbg_host_idx].hostid))
+		dbg_handled++;
+
+	/* Enable the DBG interrupt */
+	if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+		cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.dbg);
+}
+
+static void cl_ipc_tasklet_init(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	tasklet_init(&ipc_env->rxdesc_tasklet,
+		     cl_rx_pci_desc_tasklet,
+		     (unsigned long)cl_hw);
+	tasklet_init(&ipc_env->tx_single_cfm_tasklet,
+		     cl_tx_pci_single_cfm_tasklet,
+		     (unsigned long)cl_hw);
+	tasklet_init(&ipc_env->tx_agg_cfm_tasklet,
+		     cl_tx_pci_agg_cfm_tasklet,
+		     (unsigned long)cl_hw);
+	tasklet_init(&ipc_env->msg_tasklet,
+		     cl_msg_rx_tasklet,
+		     (unsigned long)cl_hw);
+	tasklet_init(&ipc_env->dbg_tasklet,
+		     cl_ipc_dbgfile_tasklet,
+		     (unsigned long)cl_hw);
+	tasklet_init(&ipc_env->bcn_tasklet,
+		     cl_tx_bcns_tasklet,
+		     (unsigned long)cl_hw);
+}
+
+static int cl_ipc_env_init(struct cl_hw *cl_hw)
+{
+	u32 *dst;
+	u32 i;
+
+	BUILD_BUG_ON_NOT_POWER_OF_2(IPC_RXBUF_CNT_RXM);
+	BUILD_BUG_ON_NOT_POWER_OF_2(IPC_RXBUF_CNT_FW);
+
+	/* Allocate the IPC environment */
+	cl_hw->ipc_env = kzalloc(sizeof(*cl_hw->ipc_env), GFP_KERNEL);
+
+	if (!cl_hw->ipc_env)
+		return -ENOMEM;
+
+	dst = (u32 *)(cl_hw->ipc_env);
+
+	/*
+	 * Reset the IPC Host environment.
+	 * Perform the reset word per word because memset() does
+	 * not correctly reset all (due to misaligned accesses)
+	 */
+	for (i = 0; i < sizeof(struct cl_ipc_host_env); i += sizeof(u32))
+		*dst++ = 0;
+
+	return 0;
+}
+
+static bool cl_pci_is_la_enabled(struct cl_chip *chip)
+{
+	s8 *ela_mode = chip->conf->ce_ela_mode;
+
+	return (!strcmp(ela_mode, "default") ||
+		!strncmp(ela_mode, "lcu_mac", 7) ||
+		!strncmp(ela_mode, "lcu_phy", 7));
+}
+
+static void cl_ipc_shared_env_init(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_shared_env __iomem *shared_env =
+		(struct cl_ipc_shared_env __iomem *)(chip->pci_bar0_virt_addr +
+					     SHARED_RAM_START_ADDR);
+	u32 i;
+	u16 max_retry = cl_hw_is_prod_or_listener(cl_hw) ?
+			0 : cl_hw->conf->ce_max_retry;
+	bool first_tcv = cl_hw_is_first_tcv(cl_hw) &&
+			 !cl_recovery_in_progress(cl_hw);
+	void __iomem *dst;
+
+	/* The shared environment of TCV1 is located after the shared environment of TCV0. */
+	if (cl_hw_is_tcv1(cl_hw))
+		shared_env++;
+
+	dst = (void __iomem *)(shared_env);
+
+	/* Reset the shared environment */
+	for (i = 0; i < sizeof(struct cl_ipc_shared_env); i += sizeof(u32),
+	     dst += sizeof(u32))
+		iowrite32(0, dst);
+
+	iowrite8(cl_pci_is_la_enabled(chip), (void __iomem *)&shared_env->la_enable);
+	iowrite16(max_retry, (void __iomem *)&shared_env->max_retry);
+	iowrite16(CL_TX_LIFETIME_MS, (void __iomem *)&shared_env->lft_limit_ms);
+	iowrite16(chip->conf->ci_phy_dev, (void __iomem *)&shared_env->phy_dev);
+	iowrite8(first_tcv, (void __iomem *)&shared_env->first_tcv);
+	iowrite8(chip->conf->ci_la_mirror_en,
+		 (void __iomem *)&shared_env->la_mirror_enable);
+
+	/* Initialize the shared environment pointer */
+	ipc_env->shared = shared_env;
+}
+
+static void cl_ipc_e2a_irq_init(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_e2a_irq *ipc_e2a_irq = &cl_hw->ipc_e2a_irq;
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		ipc_e2a_irq->dbg = IPC_IRQ_L2H_DBG;
+		ipc_e2a_irq->msg = IPC_IRQ_L2H_MSG;
+		ipc_e2a_irq->rxdesc = IPC_IRQ_L2H_RXDESC;
+		ipc_e2a_irq->txcfm = IPC_IRQ_L2H_TXCFM;
+		ipc_e2a_irq->radar = IPC_IRQ_L2H_RADAR;
+		ipc_e2a_irq->txdesc_ind = IPC_IRQ_L2H_TXDESC_IND;
+		ipc_e2a_irq->tbtt = IPC_IRQ_L2H_TBTT;
+		ipc_e2a_irq->sync = IPC_IRQ_L2H_SYNC;
+		ipc_e2a_irq->all = IPC_IRQ_L2H_ALL;
+	} else {
+		ipc_e2a_irq->dbg = IPC_IRQ_S2H_DBG;
+		ipc_e2a_irq->msg = IPC_IRQ_S2H_MSG;
+		ipc_e2a_irq->rxdesc = IPC_IRQ_S2H_RXDESC;
+		ipc_e2a_irq->txcfm = IPC_IRQ_S2H_TXCFM;
+		ipc_e2a_irq->radar = IPC_IRQ_S2H_RADAR;
+		ipc_e2a_irq->txdesc_ind = IPC_IRQ_S2H_TXDESC_IND;
+		ipc_e2a_irq->tbtt = IPC_IRQ_S2H_TBTT;
+		ipc_e2a_irq->sync = IPC_IRQ_S2H_SYNC;
+		ipc_e2a_irq->all = IPC_IRQ_S2H_ALL;
+	}
+}
+
+int cl_ipc_init(struct cl_hw *cl_hw)
+{
+	/*
+	 * This function initializes IPC interface by registering callbacks, setting
+	 * shared memory area and calling IPC Init function.
+	 * This function should be called only once during driver's lifetime.
+	 */
+	int ret = cl_ipc_env_init(cl_hw);
+
+	if (ret)
+		return ret;
+
+	cl_ipc_e2a_irq_init(cl_hw);
+	if (cl_hw_is_tcv0(cl_hw))
+		cl_hw->ipc_host2xmac_trigger_set = ipc_host_2_lmac_trigger_set;
+	else
+		cl_hw->ipc_host2xmac_trigger_set = ipc_host_2_smac_trigger_set;
+
+	cl_ipc_shared_env_init(cl_hw);
+
+	ret = cl_ipc_elems_alloc(cl_hw);
+	if (ret) {
+		cl_ipc_env_free(cl_hw);
+		return ret;
+	}
+
+	cl_ipc_tasklet_init(cl_hw);
+
+	return ret;
+}
+
+static void cl_ipc_ring_indices_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	memset(ipc_env->ring_indices_elem->indices, 0, sizeof(struct cl_ipc_ring_indices));
+
+	/* Reset host desc read idx follower */
+	ipc_env->host_rxdesc_read_idx[CL_RX_BUF_RXM] = 0;
+	ipc_env->host_rxdesc_read_idx[CL_RX_BUF_FW] = 0;
+}
+
+static void _cl_ipc_txdesc_reset(struct txdesc **txdesc, u32 desc_num)
+{
+	u32 size = (desc_num * sizeof(struct txdesc));
+
+	memset(*txdesc, 0, size);
+}
+
+static void cl_ipc_txdesc_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_tx_queues *tx_queues = &cl_hw->ipc_env->tx_queues;
+	u32 i;
+
+	_cl_ipc_txdesc_reset(&tx_queues->ipc_txdesc_bcmc, IPC_TXDESC_CNT_BCMC);
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		_cl_ipc_txdesc_reset(&tx_queues->ipc_txdesc_single[i], IPC_TXDESC_CNT_SINGLE);
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		_cl_ipc_txdesc_reset(&tx_queues->ipc_txdesc_agg[i], TXDESC_AGG_Q_SIZE_MAX);
+}
+
+static void cl_ipc_rx_skb_reset(struct cl_hw *cl_hw)
+{
+	/*
+	 * This function allocates Rx elements for DMA
+	 * transfers and pushes the DMA address to FW.
+	 */
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_rx_elem *rx_elem = cl_hw->rx_elems;
+	int i = 0;
+
+	/* Push RXM buffers */
+	for (i = 0; i < IPC_RXBUF_CNT_RXM; rx_elem++, i++)
+		cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_RXM);
+
+	/* Push FW buffers */
+	for (i = 0; i < IPC_RXBUF_CNT_FW; rx_elem++, i++)
+		cl_ipc_rxbuf_push(ipc_env, rx_elem, i, i, CL_RX_BUF_FW);
+}
+
+static void _cl_ipc_rx_buf_reset(u32 **rxbuf, u32 desc_num)
+{
+	u32 size = (desc_num * sizeof(u32));
+
+	memset(*rxbuf, 0, size);
+}
+
+static void cl_ipc_rx_buf_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_host_rxbuf *rxbuf_rxm = &ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM];
+	struct cl_ipc_host_rxbuf *rxbuf_fw = &ipc_env->rx_hostbuf_array[CL_RX_BUF_FW];
+
+	/* Reset RXM RX buffer */
+	_cl_ipc_rx_buf_reset((u32 **)&rxbuf_rxm->dma_payload_addr,
+			     IPC_RXBUF_CNT_RXM);
+
+	/* Reset FW RX buffer */
+	_cl_ipc_rx_buf_reset((u32 **)&rxbuf_fw->dma_payload_addr,
+			     IPC_RXBUF_CNT_FW);
+}
+
+static void cl_ipc_rx_reset(struct cl_hw *cl_hw)
+{
+	cl_ipc_rx_buf_reset(cl_hw);
+	cl_ipc_rx_skb_reset(cl_hw);
+}
+
+static void cl_ipc_msg_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_e2a_msg_elem *msg_elem;
+	u32 i;
+
+	ipc_env->e2a_msg_host_idx = 0;
+
+	/* Initialize the msg buffers in the global IPC array. */
+	for (i = 0, msg_elem = cl_hw->e2a_msg_elems;
+	     i < IPC_E2A_MSG_BUF_CNT; msg_elem++, i++) {
+		msg_elem->msgbuf_ptr->pattern = 0;
+		cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+	}
+}
+
+static void cl_ipc_radar_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_radar_elem *radar_elem;
+	u32 i;
+
+	ipc_env->radar_host_idx = 0;
+
+	/* Initialize the radar buffers in the global IPC array. */
+	for (i = 0, radar_elem = cl_hw->radar_elems;
+	     i < IPC_RADAR_BUF_CNT; radar_elem++, i++) {
+		radar_elem->radarbuf_ptr->cnt = 0;
+		cl_ipc_radarbuf_push(ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+	}
+}
+
+static void cl_ipc_dbg_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_dbg_elem *dbg_elem;
+	u32 i;
+
+	ipc_env->dbg_host_idx = 0;
+
+	/* Initialize the dbg buffers in the global IPC array. */
+	for (i = 0, dbg_elem = cl_hw->dbg_elems;
+	     i < IPC_DBG_BUF_CNT; dbg_elem++, i++) {
+		dbg_elem->dbgbuf_ptr->pattern = 0;
+		cl_ipc_dbgbuf_push(ipc_env, (ptrdiff_t)dbg_elem, dbg_elem->dma_addr);
+	}
+}
+
+static void cl_ipc_cfm_reset(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	ipc_env->cfm_used_idx = 0;
+	memset(ipc_env->cfm_virt_base_addr, 0, IPC_CFM_SIZE);
+}
+
+static void cl_ipc_dbg_info_reset(struct cl_hw *cl_hw)
+{
+	struct dbg_info *buf = cl_hw->dbginfo.buf;
+	struct cl_chip *chip = cl_hw->chip;
+	u32 len = sizeof(struct dbg_info);
+
+	if (!chip->conf->ci_la_mirror_en)
+		len -= sizeof_field(struct dbg_dump_info, la_mem);
+
+	memset(buf, 0, len);
+	buf->u.type = DBG_INFO_UNSET;
+
+	cl_ipc_dbginfobuf_push(cl_hw->ipc_env, cl_hw->dbginfo.dma_addr);
+}
+
+static void cl_ipc_elems_reset(struct cl_hw *cl_hw)
+{
+	cl_ipc_ring_indices_reset(cl_hw);
+	cl_ipc_txdesc_reset(cl_hw);
+	cl_ipc_rx_reset(cl_hw);
+	cl_ipc_msg_reset(cl_hw);
+	cl_ipc_radar_reset(cl_hw);
+	cl_ipc_dbg_reset(cl_hw);
+	cl_ipc_cfm_reset(cl_hw);
+	cl_ipc_dbg_info_reset(cl_hw);
+	cl_enhanced_tim_reset(cl_hw);
+}
+
+void cl_ipc_recovery(struct cl_hw *cl_hw)
+{
+	cl_ipc_shared_env_init(cl_hw);
+	cl_ipc_elems_reset(cl_hw);
+}
+
+void cl_ipc_deinit(struct cl_hw *cl_hw)
+{
+	cl_ipc_elems_dealloc(cl_hw);
+	cl_ipc_env_free(cl_hw);
+}
+
+void cl_ipc_stop(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	tasklet_kill(&ipc_env->bcn_tasklet);
+	tasklet_kill(&ipc_env->rxdesc_tasklet);
+	tasklet_kill(&ipc_env->tx_single_cfm_tasklet);
+	tasklet_kill(&ipc_env->tx_agg_cfm_tasklet);
+	tasklet_kill(&ipc_env->msg_tasklet);
+	tasklet_kill(&ipc_env->dbg_tasklet);
+}
+
+int cl_ipc_rx_elem_alloc(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem, u32 size)
+{
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+	struct hw_rxhdr *rxhdr;
+
+	rx_elem->passed = 0;
+
+	skb = dev_alloc_skb(size);
+
+	if (unlikely(!skb)) {
+		cl_dbg_verbose(cl_hw, "skb alloc failed (size %u)\n", size);
+		rx_elem->dma_addr = (dma_addr_t)0;
+		return -ENOMEM;
+	}
+
+	rxhdr = (struct hw_rxhdr *)skb->data;
+	rxhdr->pattern = 0;
+
+	dma_addr = dma_map_single(cl_hw->chip->dev, skb->data, size, DMA_FROM_DEVICE);
+
+	if (unlikely(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+		cl_dbg_verbose(cl_hw, "dma_mapping_error\n");
+		kfree_skb(skb);
+		return -1;
+	}
+
+	rx_elem->skb = skb;
+	rx_elem->dma_addr = dma_addr;
+
+	cl_rx_skb_alloc_handler(skb);
+
+	return 0;
+}
+
+void cl_ipc_msgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+	/*
+	 * Push a pre-allocated buffer descriptor for MSGs
+	 * This function is only called at Init time since the MSGs will be handled directly
+	 * and buffer can be re-used as soon as the message is handled, no need to re-allocate
+	 * new buffers in the meantime.
+	 */
+	struct cl_ipc_shared_env __iomem *shared_env = ipc_env->shared;
+	u8 e2a_msg_host_idx = ipc_env->e2a_msg_host_idx;
+
+	/* Save the hostid and the hostbuf in global array */
+	ipc_env->e2a_msg_hostbuf_array[e2a_msg_host_idx].hostid = hostid;
+	ipc_env->e2a_msg_hostbuf_array[e2a_msg_host_idx].dma_addr = hostbuf;
+
+	/* Copy the hostbuf (DMA address) in the ipc shared memory */
+	iowrite32(hostbuf, (void __iomem *)&shared_env->e2a_msg_hostbuf_addr[e2a_msg_host_idx]);
+
+	/* Increment the array index */
+	ipc_env->e2a_msg_host_idx = (e2a_msg_host_idx + 1) % IPC_E2A_MSG_BUF_CNT;
+}
+
+void cl_ipc_rxbuf_push(struct cl_ipc_host_env *ipc_env, struct cl_rx_elem *rx_elem,
+		       u32 rxdesc_read_idx, u32 host_read_idx, enum rx_buf_type type)
+{
+	/*
+	 * Push a pre-allocated buffer descriptor for Rx packet.
+	 * This function is called to supply the firmware with new empty buffer.
+	 */
+	struct cl_ipc_ring_indices *indices = ipc_env->ring_indices_elem->indices;
+	struct cl_ipc_host_rxbuf *host_rxbuf = &ipc_env->rx_hostbuf_array[type];
+
+	/* Save the hostid and the hostbuf in global array */
+	host_rxbuf->ipc_host_rxdesc_ptr[host_read_idx] = (ptrdiff_t *)rx_elem;
+	host_rxbuf->dma_payload_addr[host_read_idx] = rx_elem->dma_addr;
+
+	/* Update rxbuff metadata */
+	indices->rxdesc_read_idx[type] = cpu_to_le32(rxdesc_read_idx + 1);
+}
+
+void cl_ipc_radarbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+	/*
+	 * Push a pre-allocated radar event buffer descriptor.
+	 * This function should be called by the host IRQ handler to supply the embedded
+	 * side with new empty buffer.
+	 */
+	struct cl_ipc_shared_env __iomem *shared_env = ipc_env->shared;
+	u8 radar_host_idx = ipc_env->radar_host_idx;
+
+	/* Save the hostid and the hostbuf in global array */
+	ipc_env->radar_hostbuf_array[radar_host_idx].hostid = hostid;
+	ipc_env->radar_hostbuf_array[radar_host_idx].dma_addr = hostbuf;
+
+	/* Copy the hostbuf (DMA address) in the ipc shared memory */
+	iowrite32(hostbuf, (void __iomem *)&shared_env->radarbuf_hostbuf[radar_host_idx]);
+
+	/* Increment the array index */
+	ipc_env->radar_host_idx = (radar_host_idx + 1) % IPC_RADAR_BUF_CNT;
+}
+
+void cl_ipc_dbgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf)
+{
+	/*
+	 * Push a pre-allocated buffer descriptor for Debug messages.
+	 * This function is only called at Init time since the Debug messages will be
+	 * handled directly and buffer can be re-used as soon as the message is handled,
+	 * no need to re-allocate new buffers in the meantime.
+	 */
+	struct cl_ipc_shared_env __iomem *shared_env = ipc_env->shared;
+	u8 dbg_host_idx = ipc_env->dbg_host_idx;
+
+	/* Save the hostid and the hostbuf in global array */
+	ipc_env->dbg_hostbuf_array[dbg_host_idx].hostid = hostid;
+	ipc_env->dbg_hostbuf_array[dbg_host_idx].dma_addr = hostbuf;
+
+	/* Copy the hostbuf (DMA address) in the ipc shared memory */
+	iowrite32(hostbuf, (void __iomem *)&shared_env->dbg_hostbuf_addr[dbg_host_idx]);
+
+	/* Increment the array index */
+	ipc_env->dbg_host_idx = (dbg_host_idx + 1) % IPC_DBG_BUF_CNT;
+}
+
+void cl_ipc_dbginfobuf_push(struct cl_ipc_host_env *ipc_env, dma_addr_t infobuf)
+{
+	/*Push the pre-allocated logic analyzer and debug information buffer */
+	struct cl_ipc_shared_env __iomem *shared_env = ipc_env->shared;
+
+	/* Copy the hostbuf (DMA address) in the ipc shared memory */
+	iowrite32(infobuf, (void __iomem *)&shared_env->dbginfo_addr);
+	/* Copy the hostbuf size in the ipc shared memory */
+	iowrite32(DBG_DUMP_BUFFER_SIZE, (void __iomem *)&shared_env->dbginfo_size);
+}
+
+static void cl_irq_status_rxdesc(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/*
+	 * Handle the reception of a Rx Descriptor.
+	 *
+	 * Disable the RX interrupt until rxelement/skb handled
+	 * this would avoid redundant context switch + redundant tasklet scheduling
+	 */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.rxdesc);
+
+	/* Acknowledge the interrupt BEFORE handling the packet */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.rxdesc);
+
+	/*
+	 * If more than 50% of buffer are populated handle them in the interrupt,
+	 * otherwise schedule a tasklet to handle the buffers.
+	 */
+	if (cl_rx_process_in_irq(cl_hw))
+		cl_rx_pci_desc_handler(cl_hw);
+	else
+		tasklet_schedule(&ipc_env->rxdesc_tasklet);
+}
+
+static void cl_irq_status_txcfm(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/*
+	 * Disable the TXCFM interrupt bit - will be enabled
+	 * at the end of cl_tx_pci_single_cfm_tasklet()
+	 */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.txcfm);
+
+	/* Acknowledge the TXCFM interrupt */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.txcfm);
+
+	/* Schedule tasklet to handle the TXCFM */
+	tasklet_schedule(&ipc_env->tx_single_cfm_tasklet);
+}
+
+static void cl_irq_status_tbtt(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	unsigned long tbtt_diff_msec = jiffies_to_msecs(jiffies - cl_hw->last_tbtt_irq);
+
+	/* Acknowledge the interrupt BEFORE handling the request */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.tbtt);
+
+	cl_hw->last_tbtt_irq = jiffies;
+	cl_hw->tbtt_cnt++;
+
+	/*
+	 * Send beacon only if radio is on, there is at least one AP interface
+	 * up, we aren't in the middle of recovery, and user didn't disable them.
+	 */
+	if (unlikely(!cl_is_tx_allowed(cl_hw)))
+		return;
+
+	if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_MESH_ONLY) {
+		tasklet_hi_schedule(&cl_hw->tx_mesh_bcn_task);
+		return;
+	} else if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_MESH_AP && cl_hw->mesh_tbtt_div >= 1 &&
+		   ((cl_hw->tbtt_cnt % cl_hw->mesh_tbtt_div) == 0)) {
+		tasklet_hi_schedule(&cl_hw->tx_mesh_bcn_task);
+	} else if (IS_REAL_PHY(cl_hw->chip) && cl_hw->smallest_beacon_int > 0) {
+		/*
+		 * More than 2 times the beacon interval passed between beacons - WARNING
+		 * More than 3 times the beacon interval passed between beacons - ERROR
+		 */
+		if (tbtt_diff_msec > (cl_hw->smallest_beacon_int * 3))
+			cl_dbg_err(cl_hw, "last_tbtt_irq=%lu, curr_time=%lu, diff=%lu\n",
+				   cl_hw->last_tbtt_irq, jiffies, tbtt_diff_msec);
+		else if (tbtt_diff_msec > (cl_hw->smallest_beacon_int * 2))
+			cl_dbg_warn(cl_hw, "last_tbtt_irq=%lu, curr_time=%lu, diff=%lu\n",
+				    cl_hw->last_tbtt_irq, jiffies, tbtt_diff_msec);
+	}
+
+	tasklet_hi_schedule(&ipc_env->bcn_tasklet);
+}
+
+static void cl_irq_status_msg(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/* Acknowledge the interrupt BEFORE handling the request */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.msg);
+
+	/* Schedule tasklet to handle the messages */
+	tasklet_schedule(&ipc_env->msg_tasklet);
+}
+
+static u8 cl_radar_handler(struct cl_hw *cl_hw, ptrdiff_t hostid)
+{
+	struct cl_radar_elem *radar_elem = (struct cl_radar_elem *)hostid;
+	u8 ret = 0;
+	struct cl_radar_pulse_array *pulses;
+
+	/* Retrieve the radar pulses structure */
+	pulses = (struct cl_radar_pulse_array *)radar_elem->radarbuf_ptr;
+
+	/* Look for pulse count meaning that this hostbuf contains RADAR pulses */
+	if (pulses->cnt == 0) {
+		ret = -1;
+		goto radar_no_push;
+	}
+
+	/* Push pulse information to queue and schedule a tasklet to handle it */
+	cl_radar_push(cl_hw, radar_elem);
+
+	/* Reset the radar element and re-use it */
+	pulses->cnt = 0;
+
+	/* Make sure memory is written before push to HW */
+	wmb();
+
+	/* Push back the buffer to the firmware */
+	cl_ipc_radarbuf_push(cl_hw->ipc_env, (ptrdiff_t)radar_elem, radar_elem->dma_addr);
+
+radar_no_push:
+	return ret;
+}
+
+static void cl_irq_status_radar(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/*
+	 * Firmware has triggered an IT saying that a radar event has been sent to upper layer.
+	 * Then we first need to check the validity of the current msg buf, and the validity
+	 * of the next buffers too, because it is likely that several buffers have been
+	 * filled within the time needed for this irq handling
+	 */
+
+	/* Disable the RADAR interrupt bit - will be enabled at the end of cl_radar_tasklet() */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.radar);
+
+	/* Acknowledge the RADAR interrupt */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.radar);
+
+	/* Push all new radar pulses to queue */
+	while (cl_radar_handler(cl_hw,
+				ipc_env->radar_hostbuf_array[ipc_env->radar_host_idx].hostid) == 0)
+		;
+
+	/* Schedule tasklet to handle the radar pulses */
+	cl_radar_tasklet_schedule(cl_hw);
+}
+
+static void cl_irq_status_dbg(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/* Disable the DBG interrupt bit - will be enabled at the end of cl_dbgfile_tasklet() */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.dbg);
+
+	/* Acknowledge the DBG interrupt */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.dbg);
+
+	/* Schedule tasklet to handle the debug */
+	tasklet_schedule(&ipc_env->dbg_tasklet);
+}
+
+static void cl_irq_status_txdesc_ind(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/*
+	 * Disable the TXDESC_IND interrupt bit -
+	 * will be enabled at the end of cl_tx_pci_agg_cfm_tasklet()
+	 */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.txdesc_ind);
+
+	/* Acknowledge the TXDESC_IND interrupt */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.txdesc_ind);
+
+	tasklet_schedule(&ipc_env->tx_agg_cfm_tasklet);
+	tasklet_schedule(&cl_hw->tx_task);
+}
+
+static void cl_irq_status_sync(struct cl_hw *cl_hw, struct cl_ipc_host_env *ipc_env)
+{
+	/* Acknowledge the interrupt BEFORE handling the request */
+	ipc_xmac_2_host_ack_set(cl_hw->chip, cl_hw->ipc_e2a_irq.sync);
+
+	set_bit(CL_DEV_FW_SYNC, &cl_hw->drv_flags);
+	wake_up_interruptible(&cl_hw->fw_sync_wq);
+}
+
+void cl_irq_status(struct cl_hw *cl_hw, u32 status)
+{
+	/* Handle all IPC interrupts on the host side */
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+
+	if (status & cl_hw->ipc_e2a_irq.rxdesc)
+		cl_irq_status_rxdesc(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.txcfm)
+		cl_irq_status_txcfm(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.tbtt)
+		cl_irq_status_tbtt(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.msg)
+		cl_irq_status_msg(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.radar)
+		cl_irq_status_radar(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.dbg)
+		cl_irq_status_dbg(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.txdesc_ind)
+		cl_irq_status_txdesc_ind(cl_hw, ipc_env);
+
+	if (status & cl_hw->ipc_e2a_irq.sync)
+		cl_irq_status_sync(cl_hw, ipc_env);
+}
+
+static void cl_irq_handler(struct cl_chip *chip)
+{
+	/* Interrupt handler */
+	u32 status, statuses = 0;
+	unsigned long now = jiffies;
+	struct cl_irq_stats *irq_stats = &chip->irq_stats;
+
+	while ((status = ipc_xmac_2_host_status_get(chip))) {
+		statuses |= status;
+
+		if (status & IPC_IRQ_L2H_ALL)
+			cl_irq_status(chip->cl_hw_tcv0, status);
+
+		if (status & IPC_IRQ_S2H_ALL)
+			cl_irq_status(chip->cl_hw_tcv1, status);
+	}
+
+	if (statuses & (IPC_IRQ_L2H_RXDESC | IPC_IRQ_S2H_RXDESC))
+		irq_stats->last_rx = now;
+
+	if (statuses & (IPC_IRQ_L2H_TXCFM | IPC_IRQ_S2H_TXCFM))
+		irq_stats->last_tx = now;
+
+	irq_stats->last_isr = now;
+	irq_stats->last_isr_statuses = statuses;
+}
+
+static irqreturn_t cl_irq_request_handler(int irq, void *dev_id)
+{
+	struct cl_chip *chip = (struct cl_chip *)dev_id;
+
+	cl_irq_handler(chip);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_SMP
+static void cl_irq_set_affinity(struct cl_chip *chip, struct pci_dev *pci_dev)
+{
+	s32 irq_smp_affinity = chip->conf->ce_irq_smp_affinity;
+
+	if (irq_smp_affinity != -1) {
+		struct irq_data *data = irq_get_irq_data(pci_dev->irq);
+
+		if (data) {
+			static struct cpumask mask;
+
+			cpumask_clear(&mask);
+			cpumask_set_cpu(irq_smp_affinity, &mask);
+
+			if (data->chip->irq_set_affinity) {
+				data->chip->irq_set_affinity(data, &mask, false);
+				pr_debug("irq=%d, affinity=%d\n", pci_dev->irq, irq_smp_affinity);
+			}
+		}
+	}
+}
+#endif /* CONFIG_SMP */
+
+int cl_irq_request(struct cl_chip *chip)
+{
+	/*
+	 * Allocate host irq line.
+	 * Enable PCIe device interrupts
+	 */
+	int ret;
+	unsigned long flags = IRQF_SHARED;
+	struct pci_dev *pci_dev = chip->pci_dev;
+
+	ret = request_irq(pci_dev->irq, cl_irq_request_handler, flags, "cl", chip);
+
+	if (ret) {
+		pr_err("ERROR: could not assign interrupt %d, err=%d\n", pci_dev->irq, ret);
+		return ret;
+	}
+
+#ifdef CONFIG_SMP
+	cl_irq_set_affinity(chip, pci_dev);
+#endif /* CONFIG_SMP */
+
+	return ret;
+}
+
+void cl_irq_free(struct cl_chip *chip)
+{
+	struct pci_dev *pci_dev = chip->pci_dev;
+	/* Disable PCI device interrupt and release irq line */
+	free_irq(pci_dev->irq, chip);
+}
+
+void cl_irq_enable(struct cl_hw *cl_hw, u32 value)
+{
+	/* Enable IPC interrupts */
+	ipc_xmac_2_host_enable_set_set(cl_hw->chip, value);
+}
+
+void cl_irq_disable(struct cl_hw *cl_hw, u32 value)
+{
+	/* Disable IPC interrupts */
+	ipc_xmac_2_host_enable_clear_set(cl_hw->chip, value);
+}
+
+static void cl_msg_pci_fw_push(struct cl_hw *cl_hw, void *msg_buf, u16 len)
+{
+	/* Send a message to the embedded side */
+	int i;
+	u32 *src;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	void __iomem *dst = (void __iomem *)&ipc_env->shared->a2e_msg_buf;
+
+	/* Copy the message into the IPC MSG buffer */
+	src = (u32 *)msg_buf;
+
+	/*
+	 * Move the destination pointer forward by one word
+	 * (due to the format of the firmware kernel messages)
+	 */
+	dst += sizeof(u32);
+
+	/* Align length of message to 4 */
+	len = ALIGN(len, sizeof(u32));
+
+	/* Copy the message in the IPC queue */
+	for (i = 0; i < len; i += sizeof(u32), dst += sizeof(u32))
+		iowrite32(*src++, dst);
+
+	/* Trigger the irq to send the message to EMB */
+	cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_MSG);
+}
+
+int cl_msg_pci_msg_fw_send(struct cl_hw *cl_hw, const void *msg_params,
+			   bool background)
+{
+	struct cl_fw_msg *msg = container_of((void *)msg_params, struct cl_fw_msg, param);
+	u16 req_id = le16_to_cpu(msg->msg_id);
+	u16 cfm_bit = cl_msg_cfm_set_bit(req_id);
+	int length = sizeof(struct cl_fw_msg) + le16_to_cpu(msg->param_len);
+	int error = 0;
+
+	if (!cl_hw->fw_active) {
+		cl_dbg_verbose(cl_hw, "Bypass %s (firmware not loaded)\n", MSG_ID_STR(req_id));
+		/* Free the message */
+		kfree(msg);
+		return -EBUSY;
+	}
+
+	if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags)) {
+		cl_dbg_verbose(cl_hw, "Bypass %s (CL_DEV_FW_ERROR is set)\n", MSG_ID_STR(req_id));
+		/* Free the message */
+		kfree(msg);
+		return -EBUSY;
+	}
+
+	if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+	    req_id != MM_RESET_REQ &&
+	    req_id != MM_START_REQ) {
+		cl_dbg_verbose(cl_hw, "Bypass %s (CL_DEV_STARTED not set)\n", MSG_ID_STR(req_id));
+		/* Free the message */
+		kfree(msg);
+		return -EBUSY;
+	}
+
+	/* Lock msg tx of the correct msg buffer. */
+	error = mutex_lock_interruptible(&cl_hw->msg_tx_mutex);
+	if (error != 0) {
+		cl_dbg_verbose(cl_hw, "Bypass %s (mutex error %d)\n", MSG_ID_STR(req_id), error);
+		/* Free the message */
+		kfree(msg);
+		return error;
+	}
+
+	cl_hw->msg_background = background;
+
+	CFM_SET_BIT(cfm_bit, &cl_hw->cfm_flags);
+
+	cl_dbg_trace(cl_hw, "%s\n", MSG_ID_STR(req_id));
+
+	/* Push the message in the IPC */
+	cl_msg_pci_fw_push(cl_hw, msg, length);
+
+	/* Free the message */
+	kfree(msg);
+
+	return cl_msg_cfm_wait(cl_hw, cfm_bit, req_id);
+}
+
+static DEFINE_PER_CPU(struct tasklet_struct, rx_remote_tasklet_drv[TCV_TOTAL]);
+
+static void cl_rx_pci_stats_rxm(struct cl_hw *cl_hw, u16 bucket_idx)
+{
+	if (bucket_idx < IPC_RXBUF_NUM_BUCKETS_RXM)
+		cl_hw->rx_info.pkt_handle_bucket_rxm[bucket_idx]++;
+	else
+		cl_hw->rx_info.pkt_handle_bucket_rxm[IPC_RXBUF_NUM_BUCKETS_RXM - 1]++;
+}
+
+static void cl_rx_pci_stats_fw(struct cl_hw *cl_hw, u16 bucket_idx)
+{
+	if (bucket_idx < IPC_RXBUF_NUM_BUCKETS_FW)
+		cl_hw->rx_info.pkt_handle_bucket_fw[bucket_idx]++;
+	else
+		cl_hw->rx_info.pkt_handle_bucket_fw[IPC_RXBUF_NUM_BUCKETS_FW - 1]++;
+}
+
+static void cl_rx_pci_stats(struct cl_hw *cl_hw, u16 pkt_cnt, enum rx_buf_type type)
+{
+	/* Collect stats - fill the bucket stats */
+	if (pkt_cnt) {
+		u16 bucket_idx = pkt_cnt >> IPC_RXBUF_BUCKET_POW_SIZE;
+
+		if (type == CL_RX_BUF_RXM)
+			cl_rx_pci_stats_rxm(cl_hw, bucket_idx);
+		else
+			cl_rx_pci_stats_fw(cl_hw, bucket_idx);
+	}
+}
+
+static int _cl_rx_pci_start(struct cl_hw *cl_hw, u32 rxdesc_read_idx, u32 host_read_idx,
+			    enum rx_buf_type type)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_host_rxbuf *rx_hostbuf = &ipc_env->rx_hostbuf_array[type];
+	struct cl_rx_elem *rxelem =
+		(struct cl_rx_elem *)rx_hostbuf->ipc_host_rxdesc_ptr[host_read_idx];
+	struct sk_buff *skb;
+	int ret = 0;
+	dma_addr_t dma_addr;
+	u32 size = cl_hw->conf->ci_ipc_rxbuf_size[type];
+
+	cl_hw->rx_info.rx_desc[type]++;
+
+	/* Copy the current skb buffer & dma_addr. */
+	skb = rxelem->skb;
+	dma_addr = rxelem->dma_addr;
+
+	/* Try to populate the rxelem with new skb */
+	if (cl_ipc_rx_elem_alloc(cl_hw, rxelem, size)) {
+		cl_hw->rx_info.elem_alloc_fail++;
+		/* Restore skb and dma_addr value */
+		rxelem->skb = skb;
+		rxelem->dma_addr = dma_addr;
+		ret = -ENOMEM;
+		goto handle_done;
+	}
+
+	/* Release dma virtual memory early */
+	dma_unmap_single(cl_hw->chip->dev, dma_addr, size, DMA_FROM_DEVICE);
+
+	if (!skb) {
+		cl_hw->rx_info.skb_null++;
+		cl_rx_skb_error(cl_hw);
+		cl_dbg_verbose(cl_hw, "skb is NULL\n");
+		goto handle_done;
+	}
+
+	cl_ipc_rxbuf_push(ipc_env, rxelem, rxdesc_read_idx, host_read_idx, type);
+
+	cl_rx_push_queue(cl_hw, skb);
+
+handle_done:
+	return ret;
+}
+
+static void cl_rx_pci_start(struct cl_hw *cl_hw, enum rx_buf_type type, u16 rx_buf_cnt)
+{
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_ring_indices *indices = ipc_env->ring_indices_elem->indices;
+	u16 buf_cnt_mask = rx_buf_cnt - 1;
+	u16 pkt_cnt = 0;
+	u32 rxdesc_read_idx = le32_to_cpu(indices->rxdesc_read_idx[type]);
+	u32 host_read_idx = 0;
+	u32 rxdesc_write_idx = le32_to_cpu(indices->rxdesc_write_idx[type]);
+	u32 host_write_idx = 0;
+
+	/*
+	 * Firmware has triggered an interrupt saying that a reception has occurred.
+	 * Iterate over all valid rxdesc pushed by embedded.
+	 * The read index is incremented once the callback function finishes meaning
+	 * a new allocated skb pushed the rxbuff.
+	 * The write index is incremented in direct write by the embedded layer,
+	 * indicating that allocated skb was populated with packet data.
+	 */
+
+	do {
+		host_write_idx = rxdesc_write_idx;
+
+		while (ipc_env->host_rxdesc_read_idx[type] != host_write_idx) {
+			host_read_idx = rxdesc_read_idx & buf_cnt_mask;
+
+			if (_cl_rx_pci_start(cl_hw, rxdesc_read_idx, host_read_idx, type) == 0) {
+				/* Local application follower of embedded read idx */
+				ipc_env->host_rxdesc_read_idx[type]++;
+				rxdesc_read_idx++;
+				pkt_cnt++;
+			} else {
+				/*
+				 * Replacing old skb with new allocated skb failed
+				 * (should not happen). Postpone the handle of the
+				 * old skb until this function is reschduled again.
+				 */
+				if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+					tasklet_schedule(&ipc_env->rxdesc_tasklet);
+				goto out;
+			}
+		}
+
+		/* Check if firmware pushed new descriptors */
+		rxdesc_write_idx = le32_to_cpu(indices->rxdesc_write_idx[type]);
+	} while (host_write_idx != rxdesc_write_idx);
+
+out:
+	cl_rx_pci_stats(cl_hw, pkt_cnt, type);
+}
+
+static void cl_rx_pci_remote_tasklet_handler(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+	cl_rx_remote_cpu_info(cl_hw);
+	cl_rx_pci_desc_handler(cl_hw);
+}
+
+static call_single_data_t csd_rx_pci_remote_cpu_sched[TCV_TOTAL];
+static void cl_rx_pci_remote_cpu_sched(struct cl_hw *cl_hw)
+{
+	int cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+	struct tasklet_struct *t = csd_rx_pci_remote_cpu_sched[cl_hw->idx].info;
+
+	if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+		smp_call_function_single_async(cpu, &csd_rx_pci_remote_cpu_sched[cl_hw->idx]);
+}
+
+void cl_rx_pci_init(struct cl_hw *cl_hw)
+{
+	s8 cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+
+	if (cpu >= 0) {
+		struct tasklet_struct *t = &per_cpu(rx_remote_tasklet_drv[cl_hw->idx], cpu);
+
+		tasklet_init(t,
+			     cl_rx_pci_remote_tasklet_handler,
+			     (unsigned long)cl_hw);
+
+		csd_rx_pci_remote_cpu_sched[cl_hw->idx].func = cl_rx_remote_tasklet_sched;
+		csd_rx_pci_remote_cpu_sched[cl_hw->idx].info = t;
+	}
+}
+
+void cl_rx_pci_deinit(struct cl_hw *cl_hw)
+{
+	s8 cpu = cl_hw->conf->ci_rx_remote_cpu_drv;
+
+	if (cpu >= 0)
+		tasklet_kill(&per_cpu(rx_remote_tasklet_drv[cl_hw->idx], cpu));
+}
+
+void cl_rx_pci_desc_handler(struct cl_hw *cl_hw)
+{
+	/* Handle all RXM rx elements */
+	cl_rx_pci_start(cl_hw, CL_RX_BUF_RXM, IPC_RXBUF_CNT_RXM);
+	/* Handle all FW rx elements */
+	cl_rx_pci_start(cl_hw, CL_RX_BUF_FW, IPC_RXBUF_CNT_FW);
+
+	/* Initiate interrupt to embbeded when all rx elements were handled */
+	if (!test_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags))
+		cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_RXBUF_BACK);
+
+	/*
+	 * Finished handle all valid rx elements, restore the RX interrupt
+	 * to enable handling new populated rx elements
+	 */
+	if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+		cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.rxdesc);
+}
+
+void cl_rx_pci_desc_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+	if (cl_hw->conf->ci_rx_remote_cpu_drv == -1)
+		cl_rx_pci_desc_handler(cl_hw);
+	else
+		cl_rx_pci_remote_cpu_sched(cl_hw);
+}
+
+static void cl_tx_ipc_txdesc_populate(struct cl_hw *cl_hw, struct txdesc *txdesc,
+				      u8 queue_type, u32 ipc_queue_idx)
+{
+	/*
+	 * 1) Request allocation of txdesc associated with queue type and index from the ipc layer.
+	 * 2) Populate ipc-txdesc with the received txdesc.
+	 * 3) Increase write index - (must be last action since FW fetch WR idx first).
+	 */
+	__le32 *write_idx_ptr = NULL;
+	struct txdesc *ipc_txdesc = NULL;
+	struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+	struct cl_ipc_txdesc_write_idx *txdesc_write_idx =
+		(struct cl_ipc_txdesc_write_idx *)&indices->txdesc_write_idx;
+	u32 write_idx = 0;
+	u32 masked_write_idx = 0;
+
+	switch (queue_type) {
+	case QUEUE_TYPE_AGG:
+		ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_agg[ipc_queue_idx];
+		write_idx = le32_to_cpu(txdesc_write_idx->agg[ipc_queue_idx]);
+		write_idx_ptr = &txdesc_write_idx->agg[ipc_queue_idx];
+		masked_write_idx = write_idx & (TXDESC_AGG_Q_SIZE_MAX - 1);
+		break;
+	case QUEUE_TYPE_SINGLE:
+		ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_single[ipc_queue_idx];
+		write_idx = le32_to_cpu(txdesc_write_idx->single[ipc_queue_idx]);
+		write_idx_ptr = &txdesc_write_idx->single[ipc_queue_idx];
+		masked_write_idx = write_idx & (IPC_TXDESC_CNT_SINGLE - 1);
+		break;
+	case QUEUE_TYPE_BCMC:
+		ipc_txdesc = cl_hw->ipc_env->tx_queues.ipc_txdesc_bcmc;
+		write_idx = le32_to_cpu(txdesc_write_idx->bcmc);
+		write_idx_ptr = &txdesc_write_idx->bcmc;
+		masked_write_idx = write_idx & (IPC_TXDESC_CNT_BCMC - 1);
+		break;
+	default:
+		cl_dbg_verbose(cl_hw, "undefined queue type %u\n", queue_type);
+		WARN_ON(true);
+	}
+
+	ipc_txdesc += masked_write_idx;
+
+	memcpy(ipc_txdesc, txdesc, sizeof(struct txdesc));
+
+	/*
+	 * Update write pointer only after new txdesc copy is done since FW
+	 * fetch WR pointer first, if not, FW might read and old txdesc since
+	 * WR index indicate txdesc is valid.
+	 */
+	*write_idx_ptr = cpu_to_le32(write_idx + 1);
+}
+
+int cl_tx_release_skbs_from_cfm(struct cl_hw *cl_hw, u8 queue_idx, u16 new_ssn)
+{
+	struct cl_agg_cfm_queue *cfm_queue = NULL;
+	struct cl_tx_queue *tx_queue = NULL;
+	int free_space_add = 0;
+	u16 prev_ssn = 0;
+
+	if (new_ssn == CE_INVALID_SN)
+		return free_space_add;
+
+	cfm_queue = &cl_hw->agg_cfm_queues[queue_idx];
+	tx_queue = cfm_queue->tx_queue;
+
+	/*
+	 * Continue to free skb's until:
+	 * 1. list is empty.
+	 * 2. agg ssn is equal to new ssn received from ssn.
+	 */
+
+	spin_lock(&cl_hw->tx_lock_cfm_agg);
+	prev_ssn = cfm_queue->ssn;
+	while (!list_empty(&cfm_queue->head) && (cfm_queue->ssn != new_ssn)) {
+		cl_agg_cfm_free_head_skb(cl_hw, cfm_queue, queue_idx);
+		free_space_add++;
+		cfm_queue->ssn = ((cfm_queue->ssn + 1) & 0xFFF);
+	}
+
+	/* Sanity check. test if all skb's marked to be free. */
+	if (unlikely(cfm_queue->ssn != new_ssn))
+		cl_dbg_err(cl_hw, "ssn diff - queue idx=%u, new ssn=%u, prev ssn=%u, cfm ssn=%u\n",
+			   queue_idx, new_ssn, prev_ssn, cfm_queue->ssn);
+
+	spin_unlock(&cl_hw->tx_lock_cfm_agg);
+
+	if (free_space_add > 0) {
+		if (tx_queue) {
+			spin_lock(&cl_hw->tx_lock_agg);
+			tx_queue->fw_free_space += free_space_add;
+			tx_queue->total_fw_cfm += free_space_add;
+
+			/*
+			 * If FW used all packets that driver pushed to him,
+			 * clear the enhanced TIM bit.
+			 */
+			if (cl_txq_is_fw_empty(tx_queue))
+				cl_enhanced_tim_clear_tx_agg(cl_hw, queue_idx,
+							     tx_queue->hw_index, tx_queue->cl_sta,
+							     tx_queue->tid);
+			spin_unlock(&cl_hw->tx_lock_agg);
+		}
+	}
+
+	return free_space_add;
+}
+
+static int cl_tx_pci_agg_cfm_handler(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+	int total_cfm_handled = 0;
+	u16 new_ssn;
+	u8 used_cntr = 0;
+	u8 ba_queue_idx;
+
+	for (ba_queue_idx = 0; ba_queue_idx < IPC_MAX_BA_SESSIONS; ba_queue_idx++) {
+		new_ssn = (u16)le32_to_cpu(indices->new_ssn_idx[ba_queue_idx]);
+		total_cfm_handled += cl_tx_release_skbs_from_cfm(cl_hw, ba_queue_idx, new_ssn);
+
+		/* Optimization - avoid running the for loop IPC_MAX_BA_SESSIONS times */
+		used_cntr++;
+		if (used_cntr == cl_hw->used_agg_queues)
+			break;
+	}
+
+	return total_cfm_handled;
+}
+
+void cl_tx_pci_agg_cfm_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+	cl_tx_pci_agg_cfm_handler(cl_hw);
+
+	if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+		cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.txdesc_ind);
+}
+
+static void cl_tx_pci_single_cfm_handler(struct cl_hw *cl_hw, u32 cfm_status,
+					 u32 dma_addr, u32 single_queue_idx)
+{
+	struct sk_buff *skb = NULL;
+	struct ieee80211_tx_info *tx_info = NULL;
+	struct cl_hw_tx_status *status = (struct cl_hw_tx_status *)&cfm_status;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct cl_tx_queue *tx_queue = NULL;
+	struct cl_sta *cl_sta = NULL;
+	u8 hw_queue;
+	bool is_bcn;
+
+	if (status->is_bcmc) {
+		spin_lock_bh(&cl_hw->tx_lock_bcmc);
+		sw_txhdr = cl_bcmc_cfm_find(cl_hw, dma_addr, status->keep_skb);
+		tx_queue = &cl_hw->tx_queues->bcmc;
+	} else {
+		spin_lock_bh(&cl_hw->tx_lock_single);
+		sw_txhdr = cl_single_cfm_find(cl_hw, single_queue_idx, dma_addr);
+		tx_queue = &cl_hw->tx_queues->single[single_queue_idx];
+	}
+
+	if (!sw_txhdr) {
+		cl_dbg_trace(cl_hw, "Failed to find CFM for single_queue_idx %u status 0x%x\n",
+			     single_queue_idx, cfm_status);
+		goto out;
+	}
+
+	skb = sw_txhdr->skb;
+	tx_info = IEEE80211_SKB_CB(skb);
+	hw_queue = sw_txhdr->hw_queue;
+	is_bcn = sw_txhdr->is_bcn;
+
+	/*
+	 * Used for beacon frames only !!
+	 * if skb was already confirmed we do not need to inc FwFreeSpace counter
+	 */
+	if (likely(!status->freespace_inc_skip)) {
+		tx_queue->total_fw_cfm++;
+		tx_queue->fw_free_space++;
+
+		/* Clear the TIM element if assoicated IPC queue is empty */
+		if (!is_bcn && cl_txq_is_fw_empty(tx_queue)) {
+			bool no_ps_buffer =
+				(tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER);
+
+			cl_sta_lock(cl_hw);
+			cl_sta = cl_sta_get(cl_hw, sw_txhdr->sta_idx);
+			cl_enhanced_tim_clear_tx_single(cl_hw, single_queue_idx, hw_queue,
+							no_ps_buffer, cl_sta, sw_txhdr->tid);
+			cl_sta_unlock(cl_hw);
+		}
+	} else  if (!is_bcn) {
+		cl_dbg_verbose(cl_hw, "should no be here - is_bcn=%d hw_queue=%d\n",
+			       is_bcn, hw_queue);
+	}
+
+	/*
+	 * Used for beacon frames only !!
+	 * if this flag is set, it means FW still need this beacon skb, therefore
+	 * we do not free this skb.
+	 */
+	if (unlikely(status->keep_skb)) {
+		if (!is_bcn)
+			cl_dbg_verbose(cl_hw, "should not be here - is_bcn=%d hw_queue=%d\n",
+				       is_bcn, hw_queue);
+		goto out;
+	}
+
+	dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+	/*
+	 * If queue is not empty call cl_txq_sched() to
+	 * transfer packets from the queue to firmware
+	 */
+	if (!list_empty(&tx_queue->hdrs))
+		cl_txq_sched(cl_hw, tx_queue);
+
+	if (status->is_bcmc)
+		spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+	else
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+
+	if (is_bcn) {
+		struct ieee80211_vif *vif = sw_txhdr->cl_vif->vif;
+
+		if (vif) {
+			if (vif->csa_active &&
+			    ieee80211_beacon_cntdwn_is_complete(vif))
+				ieee80211_csa_finish(vif);
+		}
+
+		consume_skb(skb);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+		return;
+	}
+
+	if (status->frm_successful && !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+	cl_sta_lock(cl_hw);
+	cl_sta = cl_sta_get(cl_hw, sw_txhdr->sta_idx);
+
+	if (cl_sta) {
+		if (tx_queue->type != QUEUE_TYPE_BCMC &&
+		    ieee80211_is_data(sw_txhdr->fc) &&
+		    !cl_tx_ctrl_is_eapol(tx_info))
+			cl_agg_tx_report_simulate_for_single(cl_hw, cl_sta, status);
+
+		cl_tx_check_start_ba_session(cl_hw, cl_sta->sta, skb);
+	}
+
+	cl_sta_unlock(cl_hw);
+
+	if (tx_info->ack_frame_id)
+		ieee80211_tx_status(cl_hw->hw, skb);
+	else
+		consume_skb(skb);
+
+	cl_sw_txhdr_free(cl_hw, sw_txhdr);
+	return;
+
+out:
+	if (status->is_bcmc)
+		spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+	else
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_tx_pci_single_cfm_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+	struct cl_ipc_cfm_msg *msg = NULL;
+
+	msg = (struct cl_ipc_cfm_msg *)(ipc_env->cfm_virt_base_addr) +
+		(ipc_env->cfm_used_idx % IPC_CFM_CNT);
+
+	while (msg && msg->dma_addr) {
+		u32 cfm_used_idx = ipc_env->cfm_used_idx++;
+
+		cl_tx_pci_single_cfm_handler(cl_hw,
+					     le32_to_cpu(msg->status),
+					     le32_to_cpu(msg->dma_addr),
+					     le32_to_cpu(msg->single_queue_idx));
+		msg->dma_addr = 0;
+		iowrite32(cfm_used_idx, (void __iomem *)&ipc_env->shared->cfm_read_pointer);
+		msg = (struct cl_ipc_cfm_msg *)(ipc_env->cfm_virt_base_addr) +
+			(ipc_env->cfm_used_idx % IPC_CFM_CNT);
+	}
+
+	/* Enable the Tx CFM interrupt bit */
+	if (!test_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags))
+		cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.txcfm);
+}
+
+void cl_tx_pci_pkt_fw_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+			   struct cl_tx_queue *tx_queue)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	struct txdesc *txdesc = &sw_txhdr->txdesc;
+	struct tx_host_info *host_info = &txdesc->host_info;
+	struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+	struct cl_vif *cl_vif = sw_txhdr->cl_vif;
+	u8 hw_queue = sw_txhdr->hw_queue;
+	u16 a2e_trigger_bit_pos;
+	u8 tid = sw_txhdr->tid;
+	u8 queue_type = tx_queue->type;
+	bool no_ps_buffer = !!(tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER);
+	u16 ipc_queue_idx = tx_queue->index;
+	bool is_mgmt = ieee80211_is_mgmt(sw_txhdr->fc);
+	u8 i = 0;
+	u8 *cpu_addr = (u8 *)sw_txhdr->skb->data -
+		       ((host_info->host_padding & 1) * 2);
+	dma_addr_t dma_addr = dma_map_single(cl_hw->chip->dev, cpu_addr,
+					     sw_txhdr->map_len, DMA_TO_DEVICE);
+
+	if (WARN_ON(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+		tx_queue->dump_dma_map_fail++;
+
+		if (queue_type == QUEUE_TYPE_SINGLE) {
+			if (!is_mgmt)
+				cl_vif->sequence_number = DEC_SN(cl_vif->sequence_number);
+
+			cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+		} else {
+			if (queue_type == QUEUE_TYPE_AGG) {
+				struct cl_baw *baw = &cl_sta->baws[tid];
+
+				baw->tid_seq = DEC_SN(baw->tid_seq);
+			}
+
+			dev_kfree_skb_any(sw_txhdr->skb);
+		}
+
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+		return;
+	}
+
+	txdesc->umacdesc.packet_addr[0] = cpu_to_le32(dma_addr);
+
+	cl_tx_ipc_txdesc_populate(cl_hw, txdesc, queue_type, ipc_queue_idx);
+
+	/* make sure memory is written before push to HW */
+	wmb();
+
+	/*
+	 * 1) Notify firmware on new buffered traffic by updating the enhanced tim.
+	 * 2) Push sw_txhdr to confirmation list
+	 */
+	if (queue_type == QUEUE_TYPE_AGG) {
+		a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_AGG_MAP(hw_queue);
+		cl_agg_cfm_add(cl_hw, sw_txhdr, ipc_queue_idx);
+		cl_enhanced_tim_set_tx_agg(cl_hw, ipc_queue_idx, hw_queue,
+					   no_ps_buffer, cl_sta, tid);
+	} else if (queue_type == QUEUE_TYPE_SINGLE) {
+		a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_SINGLE_MAP(hw_queue);
+		cl_single_cfm_add(cl_hw, sw_txhdr, ipc_queue_idx);
+		cl_enhanced_tim_set_tx_single(cl_hw, ipc_queue_idx, hw_queue,
+					      no_ps_buffer, cl_sta, tid);
+	} else {
+		a2e_trigger_bit_pos = IPC_IRQ_A2E_TXDESC_SINGLE_MAP(hw_queue);
+		cl_bcmc_cfm_add(cl_hw, sw_txhdr);
+	}
+
+	if (cl_hw->conf->ci_tx_delay_tstamp_en)
+		cl_tx_update_hist_tstamp(tx_queue, sw_txhdr->skb, tx_queue->hist_xmit_to_push,
+					 true);
+
+	/* Tx_queue counters */
+	tx_queue->fw_free_space--;
+	tx_queue->total_fw_push_desc++;
+	tx_queue->total_fw_push_skb += host_info->packet_cnt;
+
+	/* VIF statistics */
+	cl_vif->trfc_cntrs[sw_txhdr->ac].tx_packets += host_info->packet_cnt;
+
+	for (i = 0; i < host_info->packet_cnt; i++)
+		cl_vif->trfc_cntrs[sw_txhdr->ac].tx_bytes +=
+			le16_to_cpu(txdesc->umacdesc.packet_len[i]);
+
+	/* Trigger interrupt to firmware so that it will know that a new descriptor is ready */
+	cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, BIT(a2e_trigger_bit_pos));
+}
+
+struct cl_pci_db {
+	u8 device_cntr;
+	struct pci_dev *dev[CHIP_MAX];
+};
+
+static struct cl_pci_db pci_db;
+
+static void cl_pci_get_celeno_device(void)
+{
+	/*
+	 * Search the PCI for all Celeno devices.
+	 * If there are two devices sort them in ascending order.
+	 */
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_get_device(CL_VENDOR_ID, PCI_ANY_ID, dev))) {
+		pci_db.dev[pci_db.device_cntr] = dev;
+		pci_db.device_cntr++;
+
+		if (pci_db.device_cntr == CHIP_MAX) {
+			if (pci_db.dev[CHIP0]->device > pci_db.dev[CHIP1]->device)
+				swap(pci_db.dev[CHIP0], pci_db.dev[CHIP1]);
+
+			break;
+		}
+	}
+}
+
+static u8 cl_pci_chip_idx(struct pci_dev *pci_dev)
+{
+	if (pci_db.device_cntr == 0)
+		cl_pci_get_celeno_device();
+
+	if (pci_db.device_cntr == 1)
+		return CHIP0;
+
+	return (pci_db.dev[CHIP0] == pci_dev) ? CHIP0 : CHIP1;
+}
+
+static const struct cl_driver_ops drv_ops = {
+	.msg_fw_send = cl_msg_pci_msg_fw_send,
+	.pkt_fw_send = cl_tx_pci_pkt_fw_send,
+};
+
+static int cl_pci_probe(struct pci_dev *pci_dev,
+			const struct pci_device_id *pci_id)
+{
+	u16 pci_cmd;
+	int ret;
+	u8 step_id;
+	u8 chip_idx = cl_pci_chip_idx(pci_dev);
+	struct cl_chip *chip = cl_chip_alloc(chip_idx);
+
+	if (!chip) {
+		pr_err("Chip [%u] alloc failed\n", chip_idx);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	chip->pci_dev = pci_dev;
+	chip->dev = &pci_dev->dev;
+	chip->bus_type = CL_BUS_TYPE_PCI;
+
+	ret = cl_chip_config_read(chip);
+	if (ret) {
+		cl_chip_dealloc(chip);
+		return 0;
+	}
+
+	pci_set_drvdata(pci_dev, chip);
+
+	/* Hotplug fixups */
+	pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
+	pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+	pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
+	pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
+
+	ret = pci_enable_device(pci_dev);
+	if (ret) {
+		cl_dbg_chip_err(chip, "pci_enable_device failed\n");
+		goto out;
+	}
+
+	if (!dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) {
+		cl_dbg_chip_verbose(chip, "Using 32bit DMA\n");
+	} else {
+		cl_dbg_chip_verbose(chip, "No suitable DMA available\n");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pci_dev);
+
+	ret = pci_request_regions(pci_dev, chip->pci_drv.name);
+	if (ret) {
+		cl_dbg_chip_verbose(chip, "pci_request_regions failed\n");
+		goto out_disable_device;
+	}
+
+	chip->pci_bar0_virt_addr = pci_ioremap_bar(pci_dev, 0);
+	if (!chip->pci_bar0_virt_addr) {
+		cl_dbg_chip_verbose(chip, "pci_ioremap_bar 0 failed\n");
+		ret = -ENOMEM;
+		goto out_release_regions;
+	}
+
+#ifdef CONFIG_PCI_MSI
+	if (chip->conf->ci_pci_msi_enable) {
+		ret = pci_enable_msi(pci_dev);
+		if (ret)
+			cl_dbg_chip_err(chip, "pci_enable_msi failed (%d)\n", ret);
+	}
+#endif
+
+	step_id = macsys_gcu_chip_version_step_id_getf(chip);
+	if (step_id != 0xB) {
+		cl_dbg_chip_err(chip, "Invalid Step ID: 0x%X\n", step_id);
+		ret = -EOPNOTSUPP;
+		goto out_release_regions;
+	}
+
+	ret = cl_chip_init(chip);
+	if (ret)
+		goto out_chip_deinit;
+
+	ret = cl_main_init(chip, &drv_ops);
+	if (ret)
+		goto out_chip_deinit;
+
+	if (cl_ela_init(chip))
+		cl_dbg_chip_info(chip, "Non-critical: cl_ela_init failed\n");
+
+	return 0;
+
+out_chip_deinit:
+	cl_chip_deinit(chip);
+#ifdef CONFIG_PCI_MSI
+	if (chip->conf->ci_pci_msi_enable)
+		pci_disable_msi(pci_dev);
+#endif
+	iounmap(chip->pci_bar0_virt_addr);
+out_release_regions:
+	pci_release_regions(pci_dev);
+out_disable_device:
+	pci_disable_device(pci_dev);
+out:
+
+	return ret;
+}
+
+static void cl_pci_remove(struct pci_dev *pci_dev)
+{
+	struct cl_chip *chip = pci_get_drvdata(pci_dev);
+
+	if (!chip) {
+		pr_err("%s: failed to find chip\n", __func__);
+		return;
+	}
+
+	cl_ela_deinit(chip);
+
+	cl_main_deinit(chip);
+
+	cl_chip_deinit(chip);
+
+#ifdef CONFIG_PCI_MSI
+	if (chip->conf->ci_pci_msi_enable) {
+		pci_disable_msi(pci_dev);
+		pr_debug("pci_disable_msi\n");
+	}
+#endif
+
+	iounmap(chip->pci_bar0_virt_addr);
+	cl_chip_dealloc(chip);
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
+}
+
+static const struct pci_device_id cl_pci_id_table[] = {
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8000) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8001) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8040) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8060) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8080) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8046) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8066) },
+	{ PCI_DEVICE(CL_VENDOR_ID, 0x8086) },
+	{ },
+};
+
+static struct pci_driver cl_pci_driver = {
+	.name = "cl_pci",
+	.id_table = cl_pci_id_table,
+	.probe = cl_pci_probe,
+	.remove = cl_pci_remove,
+};
+
+static int cl_pci_init(void)
+{
+	int ret;
+
+	ret = pci_register_driver(&cl_pci_driver);
+	if (ret)
+		pr_err("failed to register cl pci driver: %d\n", ret);
+
+	return ret;
+}
+module_init(cl_pci_init);
+
+static void cl_pci_exit(void)
+{
+	pci_unregister_driver(&cl_pci_driver);
+}
+module_exit(cl_pci_exit);
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 49/96] cl8k: add pci.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (47 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 48/96] cl8k: add pci.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
                   ` (46 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/pci.h | 194 +++++++++++++++++++++++++
 1 file changed, 194 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/pci.h

diff --git a/drivers/net/wireless/celeno/cl8k/pci.h b/drivers/net/wireless/celeno/cl8k/pci.h
new file mode 100644
index 000000000000..ec6801c7c71b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/pci.h
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_PCI_H
+#define CL_PCI_H
+
+#include "tx.h"
+
+#define CE_INVALID_SN 0xFFFF
+
+struct cl_chip;
+
+enum cl_bus_type {
+	CL_BUS_TYPE_PCI,
+};
+
+struct cl_driver_ops {
+	int (*msg_fw_send)(struct cl_hw *cl_hw, const void *msg_params, bool background);
+	void (*pkt_fw_send)(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+			    struct cl_tx_queue *tx_queue);
+};
+
+/* Struct used to store information about host buffers (DMA Address and local pointer) */
+struct cl_ipc_hostbuf {
+	ptrdiff_t hostid; /* Ptr to hostbuf client (ipc_host client) structure */
+	dma_addr_t dma_addr; /* Ptr to real hostbuf dma address */
+};
+
+/*
+ * Index in txdesc - updated by host on every push, used by firmware side
+ * Keep this structure aligned to 4-byte
+ */
+struct cl_ipc_txdesc_write_idx {
+	__le32 agg[IPC_MAX_BA_SESSIONS];
+	__le32 single[MAX_SINGLE_QUEUES];
+	__le32 bcmc;
+};
+
+struct cl_ipc_ring_indices {
+	/* Last copy of ipc txdesc write desc right after DMA push operation */
+	volatile struct cl_ipc_txdesc_write_idx txdesc_write_idx;
+	/*
+	 * new start sn - equal to last acknowledged sequence number + 1.
+	 * Updated by firmware and used by host.
+	 */
+	volatile __le32 new_ssn_idx[IPC_MAX_BA_SESSIONS];
+	volatile __le32 dtim_count[MAX_BSS_NUM];
+	/* Index in rxdesc array, updated by firmware on every payload push, used by host */
+	volatile __le32 rxdesc_write_idx[CL_RX_BUF_MAX];
+	/* Index in rxdesc array, updated by host on rxdesc copy completion, used by firmware */
+	volatile __le32 rxdesc_read_idx[CL_RX_BUF_MAX];
+	/* BSR data counters */
+	volatile __le32 bsr_data_ctrs[TID_MAX];
+};
+
+/* Structure used to store Shared Txring indices */
+struct cl_ipc_ring_indices_elem {
+	struct cl_ipc_ring_indices *indices;
+	dma_addr_t dma_addr;
+};
+
+struct cl_ipc_host_rxbuf {
+	/* Array of drv desc which holds the skb and additional data */
+	ptrdiff_t **ipc_host_rxdesc_ptr;
+	/* Address of payload for embedded push operation (part of rxdesc data) */
+	u32 *dma_payload_addr;
+	/* Dma pointer to array of DMA payload addresses */
+	__le32 dma_payload_base_addr;
+};
+
+/*
+ * struct tx_queues_dma_addr - ipc layer queues addresses casted to DMA addresses
+ *
+ * The ipc layer points to array of txdesc, there are:
+ * 'IPC_MAX_BA_SESSIONS' arrays for aggregation queues
+ * 'MAX_SINGLE_QUEUES' arrayes for singletons queues
+ * '1' arrays for broadcast/unicast queue
+ *
+ * Each one of this arrays should be copied compeletly to the FW, therefore we should
+ * cast all of the arrays to dma addresses.
+ */
+struct tx_queues_dma_addr {
+	__le32 agg[IPC_MAX_BA_SESSIONS];
+	__le32 single[MAX_SINGLE_QUEUES];
+	__le32 bcmc;
+};
+
+/* struct cl_ipc_tx_queues - ipc layer tx queues */
+struct cl_ipc_tx_queues {
+	struct txdesc *ipc_txdesc_agg[IPC_MAX_BA_SESSIONS];
+	struct txdesc *ipc_txdesc_single[MAX_SINGLE_QUEUES];
+	struct txdesc *ipc_txdesc_bcmc;
+	/* Mapping of the TXQ's addresses to DMA addresses */
+	struct tx_queues_dma_addr *queues_dma_addr;
+	/* DMA address of tx_queues_dma_addr */
+	u32 dma_addr;
+};
+
+struct cl_ipc_host_env {
+	/* Pointer to the shared environment */
+	struct cl_ipc_shared_env __iomem *shared;
+	/* TX ring indices (RD, WR idx & new_ssn) */
+	struct cl_ipc_ring_indices_elem *ring_indices_elem;
+	/* RX buffers (rxdesc & dma_addr) */
+	ptrdiff_t *ipc_host_rxdesc_rxm[IPC_RXBUF_CNT_RXM];
+	ptrdiff_t *ipc_host_rxdesc_fw[IPC_RXBUF_CNT_FW];
+	struct cl_ipc_host_rxbuf rx_hostbuf_array[CL_RX_BUF_MAX];
+	/* Host last read idx */
+	u32 host_rxdesc_read_idx[CL_RX_BUF_MAX];
+	/* Fields for Radar events handling */
+	struct cl_ipc_hostbuf radar_hostbuf_array[IPC_RADAR_BUF_CNT];
+	u8 radar_host_idx;
+	/* Fields for Emb->App MSGs handling */
+	struct cl_ipc_hostbuf e2a_msg_hostbuf_array[IPC_E2A_MSG_BUF_CNT];
+	u8 e2a_msg_host_idx;
+	/* Fields for Debug MSGs handling */
+	struct cl_ipc_hostbuf dbg_hostbuf_array[IPC_DBG_BUF_CNT];
+	u8 dbg_host_idx;
+	/* IPC queues */
+	struct cl_ipc_tx_queues tx_queues;
+	struct cl_ipc_enhanced_tim enhanced_tim;
+	/* Fields for single confirmation handling */
+	u8 *cfm_virt_base_addr;
+	dma_addr_t cfm_dma_base_addr;
+	/* Index used that points to the first used CFM */
+	u32 cfm_used_idx;
+	/* Tasklets */
+	struct tasklet_struct rxdesc_tasklet;
+	struct tasklet_struct tx_single_cfm_tasklet;
+	struct tasklet_struct tx_agg_cfm_tasklet;
+	struct tasklet_struct msg_tasklet;
+	struct tasklet_struct dbg_tasklet;
+	struct tasklet_struct bcn_tasklet;
+};
+
+/* Structure used to store information regarding Debug msg buffers in the driver */
+struct cl_dbg_elem {
+	struct cl_ipc_dbg_msg *dbgbuf_ptr;
+	dma_addr_t dma_addr;
+};
+
+struct cl_debug_info {
+	struct mutex mutex;
+	struct dbg_info *buf;
+	dma_addr_t dma_addr;
+	int bufsz;
+	struct timespec64 trigger_tstamp;
+};
+
+struct cl_rx_elem {
+	int passed;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+};
+
+int cl_ipc_init(struct cl_hw *cl_hw);
+void cl_ipc_recovery(struct cl_hw *cl_hw);
+void cl_ipc_deinit(struct cl_hw *cl_hw);
+void cl_ipc_stop(struct cl_hw *cl_hw);
+int cl_ipc_rx_elem_alloc(struct cl_hw *cl_hw, struct cl_rx_elem *rx_elem, u32 size);
+void cl_ipc_msgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_rxbuf_push(struct cl_ipc_host_env *ipc_env, struct cl_rx_elem *rx_elem,
+		       u32 rxdesc_read_idx, u32 host_read_idx, enum rx_buf_type type);
+void cl_ipc_radarbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_dbgbuf_push(struct cl_ipc_host_env *ipc_env, ptrdiff_t hostid, dma_addr_t hostbuf);
+void cl_ipc_dbginfobuf_push(struct cl_ipc_host_env *ipc_env, dma_addr_t infobuf);
+
+struct cl_irq_stats {
+	unsigned long last_rx;
+	unsigned long last_tx;
+	unsigned long last_isr;
+	u32 last_isr_statuses;
+	u32 count_irq;
+	u32 ipc_success;
+};
+
+int cl_irq_request(struct cl_chip *chip);
+void cl_irq_free(struct cl_chip *chip);
+void cl_irq_status(struct cl_hw *cl_hw, u32 status);
+void cl_irq_enable(struct cl_hw *cl_hw, u32 value);
+void cl_irq_disable(struct cl_hw *cl_hw, u32 value);
+int cl_msg_pci_msg_fw_send(struct cl_hw *cl_hw, const void *msg_params,
+			   bool background);
+void cl_rx_pci_init(struct cl_hw *cl_hw);
+void cl_rx_pci_deinit(struct cl_hw *cl_hw);
+void cl_rx_pci_desc_handler(struct cl_hw *cl_hw);
+void cl_rx_pci_desc_tasklet(unsigned long data);
+int cl_tx_release_skbs_from_cfm(struct cl_hw *cl_hw, u8 queue_idx, u16 new_ssn);
+void cl_tx_pci_single_cfm_tasklet(unsigned long data);
+void cl_tx_pci_agg_cfm_tasklet(unsigned long data);
+void cl_tx_pci_pkt_fw_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+			   struct cl_tx_queue *tx_queue);
+
+#endif /* CL_PCI_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 50/96] cl8k: add phy.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (48 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 49/96] cl8k: add pci.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-06-01  0:27   ` Jeff Johnson
  2022-05-24 11:34 ` [RFC v2 51/96] cl8k: add phy.h viktor.barna
                   ` (45 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/phy.c | 9648 ++++++++++++++++++++++++
 1 file changed, 9648 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy.c

diff --git a/drivers/net/wireless/celeno/cl8k/phy.c b/drivers/net/wireless/celeno/cl8k/phy.c
new file mode 100644
index 000000000000..dfc7f5a95d3d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy.c
@@ -0,0 +1,9648 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "tx.h"
+#include "reg/reg_defs.h"
+#include "radio.h"
+#include "dsp.h"
+#include "rfic.h"
+#include "e2p.h"
+#include "phy.h"
+
+#define FEM_LUT_EMPTY 0x0
+
+const struct common_lut_line athos_lut_6g_40_mhz[ATHOS_LUT_CHAN_6G_MAX] = {
+	[ATHOS_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x62, 0x1AAAAB, 0x7B9 },
+	[ATHOS_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x62, 0x1B5555, 0x7B9 },
+	[ATHOS_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x62, 0x1C0000, 0x7BA },
+	[ATHOS_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x62, 0x1CAAAB, 0x7BA },
+	[ATHOS_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x62, 0x1D5555, 0x7BA },
+	[ATHOS_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x62, 0x1E0000, 0x7BB },
+	[ATHOS_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x62, 0x1EAAAB, 0x7BB },
+	[ATHOS_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x62, 0x1F5555, 0x7BC },
+	[ATHOS_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x63, 0x0, 0x7BC },
+	[ATHOS_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x63, 0xAAAB, 0x7BC },
+	[ATHOS_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x63, 0x15555, 0x7BD },
+	[ATHOS_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x63, 0x20000, 0x7BD },
+	[ATHOS_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x63, 0x2AAAB, 0x7BE },
+	[ATHOS_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x63, 0x35555, 0x7BE },
+	[ATHOS_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x63, 0x40000, 0x7BF },
+	[ATHOS_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x63, 0x4AAAB, 0x7BF },
+	[ATHOS_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x63, 0x55555, 0x7BF },
+	[ATHOS_LUT_CHAN_595125_IDX] = { 23805, 0x0, 0x63, 0x60000, 0x7C0 },
+	[ATHOS_LUT_CHAN_595250_IDX] = { 23810, 0x0, 0x63, 0x6AAAB, 0x7C0 },
+	[ATHOS_LUT_CHAN_595375_IDX] = { 23815, 0x0, 0x63, 0x75555, 0x7C1 },
+	[ATHOS_LUT_CHAN_595500_IDX] = { 23820, 0x0, 0x63, 0x80000, 0x7C1 },
+	[ATHOS_LUT_CHAN_595625_IDX] = { 23825, 0x0, 0x63, 0x8AAAB, 0x7C1 },
+	[ATHOS_LUT_CHAN_595750_IDX] = { 23830, 0x0, 0x63, 0x95555, 0x7C2 },
+	[ATHOS_LUT_CHAN_595875_IDX] = { 23835, 0x0, 0x63, 0xA0000, 0x7C2 },
+	[ATHOS_LUT_CHAN_596000_IDX] = { 23840, 0x0, 0x63, 0xAAAAB, 0x7C3 },
+	[ATHOS_LUT_CHAN_596125_IDX] = { 23845, 0x0, 0x63, 0xB5555, 0x7C3 },
+	[ATHOS_LUT_CHAN_596250_IDX] = { 23850, 0x0, 0x63, 0xC0000, 0x7C4 },
+	[ATHOS_LUT_CHAN_596375_IDX] = { 23855, 0x0, 0x63, 0xCAAAB, 0x7C4 },
+	[ATHOS_LUT_CHAN_596500_IDX] = { 23860, 0x0, 0x63, 0xD5555, 0x7C4 },
+	[ATHOS_LUT_CHAN_596625_IDX] = { 23865, 0x0, 0x63, 0xE0000, 0x7C5 },
+	[ATHOS_LUT_CHAN_596750_IDX] = { 23870, 0x0, 0x63, 0xEAAAB, 0x7C5 },
+	[ATHOS_LUT_CHAN_596875_IDX] = { 23875, 0x0, 0x63, 0xF5555, 0x7C6 },
+	[ATHOS_LUT_CHAN_597000_IDX] = { 23880, 0x0, 0x63, 0x100000, 0x7C6 },
+	[ATHOS_LUT_CHAN_597125_IDX] = { 23885, 0x0, 0x63, 0x10AAAB, 0x7C6 },
+	[ATHOS_LUT_CHAN_597250_IDX] = { 23890, 0x0, 0x63, 0x115555, 0x7C7 },
+	[ATHOS_LUT_CHAN_597375_IDX] = { 23895, 0x0, 0x63, 0x120000, 0x7C7 },
+	[ATHOS_LUT_CHAN_597500_IDX] = { 23900, 0x0, 0x63, 0x12AAAB, 0x7C8 },
+	[ATHOS_LUT_CHAN_597625_IDX] = { 23905, 0x0, 0x63, 0x135555, 0x7C8 },
+	[ATHOS_LUT_CHAN_597750_IDX] = { 23910, 0x0, 0x63, 0x140000, 0x7C9 },
+	[ATHOS_LUT_CHAN_597875_IDX] = { 23915, 0x0, 0x63, 0x14AAAB, 0x7C9 },
+	[ATHOS_LUT_CHAN_598000_IDX] = { 23920, 0x0, 0x63, 0x155555, 0x7C9 },
+	[ATHOS_LUT_CHAN_598125_IDX] = { 23925, 0x0, 0x63, 0x160000, 0x7CA },
+	[ATHOS_LUT_CHAN_598250_IDX] = { 23930, 0x0, 0x63, 0x16AAAB, 0x7CA },
+	[ATHOS_LUT_CHAN_598375_IDX] = { 23935, 0x0, 0x63, 0x175555, 0x7CB },
+	[ATHOS_LUT_CHAN_598500_IDX] = { 23940, 0x0, 0x63, 0x180000, 0x7CB },
+	[ATHOS_LUT_CHAN_598625_IDX] = { 23945, 0x0, 0x63, 0x18AAAB, 0x7CB },
+	[ATHOS_LUT_CHAN_598750_IDX] = { 23950, 0x0, 0x63, 0x195555, 0x7CC },
+	[ATHOS_LUT_CHAN_598875_IDX] = { 23955, 0x0, 0x63, 0x1A0000, 0x7CC },
+	[ATHOS_LUT_CHAN_599000_IDX] = { 23960, 0x0, 0x63, 0x1AAAAB, 0x7CD },
+	[ATHOS_LUT_CHAN_599125_IDX] = { 23965, 0x0, 0x63, 0x1B5555, 0x7CD },
+	[ATHOS_LUT_CHAN_599250_IDX] = { 23970, 0x0, 0x63, 0x1C0000, 0x7CE },
+	[ATHOS_LUT_CHAN_599375_IDX] = { 23975, 0x0, 0x63, 0x1CAAAB, 0x7CE },
+	[ATHOS_LUT_CHAN_599500_IDX] = { 23980, 0x0, 0x63, 0x1D5555, 0x7CE },
+	[ATHOS_LUT_CHAN_599625_IDX] = { 23985, 0x0, 0x63, 0x1E0000, 0x7CF },
+	[ATHOS_LUT_CHAN_599750_IDX] = { 23990, 0x0, 0x63, 0x1EAAAB, 0x7CF },
+	[ATHOS_LUT_CHAN_599875_IDX] = { 23995, 0x0, 0x63, 0x1F5555, 0x7D0 },
+	[ATHOS_LUT_CHAN_600000_IDX] = { 24000, 0x0, 0x64, 0x0, 0x7D0 },
+	[ATHOS_LUT_CHAN_600125_IDX] = { 24005, 0x0, 0x64, 0xAAAB, 0x7D0 },
+	[ATHOS_LUT_CHAN_600250_IDX] = { 24010, 0x0, 0x64, 0x15555, 0x7D1 },
+	[ATHOS_LUT_CHAN_600375_IDX] = { 24015, 0x0, 0x64, 0x20000, 0x7D1 },
+	[ATHOS_LUT_CHAN_600500_IDX] = { 24020, 0x0, 0x64, 0x2AAAB, 0x7D2 },
+	[ATHOS_LUT_CHAN_600625_IDX] = { 24025, 0x0, 0x64, 0x35555, 0x7D2 },
+	[ATHOS_LUT_CHAN_600750_IDX] = { 24030, 0x0, 0x64, 0x40000, 0x7D3 },
+	[ATHOS_LUT_CHAN_600875_IDX] = { 24035, 0x0, 0x64, 0x4AAAB, 0x7D3 },
+	[ATHOS_LUT_CHAN_601000_IDX] = { 24040, 0x0, 0x64, 0x55555, 0x7D3 },
+	[ATHOS_LUT_CHAN_601125_IDX] = { 24045, 0x0, 0x64, 0x60000, 0x7D4 },
+	[ATHOS_LUT_CHAN_601250_IDX] = { 24050, 0x0, 0x64, 0x6AAAB, 0x7D4 },
+	[ATHOS_LUT_CHAN_601375_IDX] = { 24055, 0x0, 0x64, 0x75555, 0x7D5 },
+	[ATHOS_LUT_CHAN_601500_IDX] = { 24060, 0x0, 0x64, 0x80000, 0x7D5 },
+	[ATHOS_LUT_CHAN_601625_IDX] = { 24065, 0x0, 0x64, 0x8AAAB, 0x7D5 },
+	[ATHOS_LUT_CHAN_601750_IDX] = { 24070, 0x0, 0x64, 0x95555, 0x7D6 },
+	[ATHOS_LUT_CHAN_601875_IDX] = { 24075, 0x0, 0x64, 0xA0000, 0x7D6 },
+	[ATHOS_LUT_CHAN_602000_IDX] = { 24080, 0x0, 0x64, 0xAAAAB, 0x7D7 },
+	[ATHOS_LUT_CHAN_602125_IDX] = { 24085, 0x0, 0x64, 0xB5555, 0x7D7 },
+	[ATHOS_LUT_CHAN_602250_IDX] = { 24090, 0x0, 0x64, 0xC0000, 0x7D8 },
+	[ATHOS_LUT_CHAN_602375_IDX] = { 24095, 0x0, 0x64, 0xCAAAB, 0x7D8 },
+	[ATHOS_LUT_CHAN_602500_IDX] = { 24100, 0x0, 0x64, 0xD5555, 0x7D8 },
+	[ATHOS_LUT_CHAN_602625_IDX] = { 24105, 0x0, 0x64, 0xE0000, 0x7D9 },
+	[ATHOS_LUT_CHAN_602750_IDX] = { 24110, 0x0, 0x64, 0xEAAAB, 0x7D9 },
+	[ATHOS_LUT_CHAN_602875_IDX] = { 24115, 0x0, 0x64, 0xF5555, 0x7DA },
+	[ATHOS_LUT_CHAN_603000_IDX] = { 24120, 0x0, 0x64, 0x100000, 0x7DA },
+	[ATHOS_LUT_CHAN_603125_IDX] = { 24125, 0x0, 0x64, 0x10AAAB, 0x7DA },
+	[ATHOS_LUT_CHAN_603250_IDX] = { 24130, 0x0, 0x64, 0x115555, 0x7DB },
+	[ATHOS_LUT_CHAN_603375_IDX] = { 24135, 0x0, 0x64, 0x120000, 0x7DB },
+	[ATHOS_LUT_CHAN_603500_IDX] = { 24140, 0x0, 0x64, 0x12AAAB, 0x7DC },
+	[ATHOS_LUT_CHAN_603625_IDX] = { 24145, 0x0, 0x64, 0x135555, 0x7DC },
+	[ATHOS_LUT_CHAN_603750_IDX] = { 24150, 0x0, 0x64, 0x140000, 0x7DD },
+	[ATHOS_LUT_CHAN_603875_IDX] = { 24155, 0x0, 0x64, 0x14AAAB, 0x7DD },
+	[ATHOS_LUT_CHAN_604000_IDX] = { 24160, 0x0, 0x64, 0x155555, 0x7DD },
+	[ATHOS_LUT_CHAN_604125_IDX] = { 24165, 0x0, 0x64, 0x160000, 0x7DE },
+	[ATHOS_LUT_CHAN_604250_IDX] = { 24170, 0x0, 0x64, 0x16AAAB, 0x7DE },
+	[ATHOS_LUT_CHAN_604375_IDX] = { 24175, 0x0, 0x64, 0x175555, 0x7DF },
+	[ATHOS_LUT_CHAN_604500_IDX] = { 24180, 0x0, 0x64, 0x180000, 0x7DF },
+	[ATHOS_LUT_CHAN_604625_IDX] = { 24185, 0x0, 0x64, 0x18AAAB, 0x7DF },
+	[ATHOS_LUT_CHAN_604750_IDX] = { 24190, 0x0, 0x64, 0x195555, 0x7E0 },
+	[ATHOS_LUT_CHAN_604875_IDX] = { 24195, 0x0, 0x64, 0x1A0000, 0x7E0 },
+	[ATHOS_LUT_CHAN_605000_IDX] = { 24200, 0x0, 0x64, 0x1AAAAB, 0x7E1 },
+	[ATHOS_LUT_CHAN_605125_IDX] = { 24205, 0x0, 0x64, 0x1B5555, 0x7E1 },
+	[ATHOS_LUT_CHAN_605250_IDX] = { 24210, 0x0, 0x64, 0x1C0000, 0x7E2 },
+	[ATHOS_LUT_CHAN_605375_IDX] = { 24215, 0x0, 0x64, 0x1CAAAB, 0x7E2 },
+	[ATHOS_LUT_CHAN_605500_IDX] = { 24220, 0x0, 0x64, 0x1D5555, 0x7E2 },
+	[ATHOS_LUT_CHAN_605625_IDX] = { 24225, 0x0, 0x64, 0x1E0000, 0x7E3 },
+	[ATHOS_LUT_CHAN_605750_IDX] = { 24230, 0x0, 0x64, 0x1EAAAB, 0x7E3 },
+	[ATHOS_LUT_CHAN_605875_IDX] = { 24235, 0x0, 0x64, 0x1F5555, 0x7E4 },
+	[ATHOS_LUT_CHAN_606000_IDX] = { 24240, 0x0, 0x65, 0x0, 0x7E4 },
+	[ATHOS_LUT_CHAN_606125_IDX] = { 24245, 0x0, 0x65, 0xAAAB, 0x7E4 },
+	[ATHOS_LUT_CHAN_606250_IDX] = { 24250, 0x0, 0x65, 0x15555, 0x7E5 },
+	[ATHOS_LUT_CHAN_606375_IDX] = { 24255, 0x0, 0x65, 0x20000, 0x7E5 },
+	[ATHOS_LUT_CHAN_606500_IDX] = { 24260, 0x0, 0x65, 0x2AAAB, 0x7E6 },
+	[ATHOS_LUT_CHAN_606625_IDX] = { 24265, 0x0, 0x65, 0x35555, 0x7E6 },
+	[ATHOS_LUT_CHAN_606750_IDX] = { 24270, 0x0, 0x65, 0x40000, 0x7E7 },
+	[ATHOS_LUT_CHAN_606875_IDX] = { 24275, 0x0, 0x65, 0x4AAAB, 0x7E7 },
+	[ATHOS_LUT_CHAN_607000_IDX] = { 24280, 0x0, 0x65, 0x55555, 0x7E7 },
+	[ATHOS_LUT_CHAN_607125_IDX] = { 24285, 0x0, 0x65, 0x60000, 0x7E8 },
+	[ATHOS_LUT_CHAN_607250_IDX] = { 24290, 0x0, 0x65, 0x6AAAB, 0x7E8 },
+	[ATHOS_LUT_CHAN_607375_IDX] = { 24295, 0x0, 0x65, 0x75555, 0x7E9 },
+	[ATHOS_LUT_CHAN_607500_IDX] = { 24300, 0x0, 0x65, 0x80000, 0x7E9 },
+	[ATHOS_LUT_CHAN_607625_IDX] = { 24305, 0x0, 0x65, 0x8AAAB, 0x7E9 },
+	[ATHOS_LUT_CHAN_607750_IDX] = { 24310, 0x0, 0x65, 0x95555, 0x7EA },
+	[ATHOS_LUT_CHAN_607875_IDX] = { 24315, 0x0, 0x65, 0xA0000, 0x7EA },
+	[ATHOS_LUT_CHAN_608000_IDX] = { 24320, 0x0, 0x65, 0xAAAAB, 0x7EB },
+	[ATHOS_LUT_CHAN_608125_IDX] = { 24325, 0x0, 0x65, 0xB5555, 0x7EB },
+	[ATHOS_LUT_CHAN_608250_IDX] = { 24330, 0x0, 0x65, 0xC0000, 0x7EC },
+	[ATHOS_LUT_CHAN_608375_IDX] = { 24335, 0x0, 0x65, 0xCAAAB, 0x7EC },
+	[ATHOS_LUT_CHAN_608500_IDX] = { 24340, 0x0, 0x65, 0xD5555, 0x7EC },
+	[ATHOS_LUT_CHAN_608625_IDX] = { 24345, 0x0, 0x65, 0xE0000, 0x7ED },
+	[ATHOS_LUT_CHAN_608750_IDX] = { 24350, 0x0, 0x65, 0xEAAAB, 0x7ED },
+	[ATHOS_LUT_CHAN_608875_IDX] = { 24355, 0x0, 0x65, 0xF5555, 0x7EE },
+	[ATHOS_LUT_CHAN_609000_IDX] = { 24360, 0x0, 0x65, 0x100000, 0x7EE },
+	[ATHOS_LUT_CHAN_609125_IDX] = { 24365, 0x0, 0x65, 0x10AAAB, 0x7EE },
+	[ATHOS_LUT_CHAN_609250_IDX] = { 24370, 0x0, 0x65, 0x115555, 0x7EF },
+	[ATHOS_LUT_CHAN_609375_IDX] = { 24375, 0x0, 0x65, 0x120000, 0x7EF },
+	[ATHOS_LUT_CHAN_609500_IDX] = { 24380, 0x0, 0x65, 0x12AAAB, 0x7F0 },
+	[ATHOS_LUT_CHAN_609625_IDX] = { 24385, 0x0, 0x65, 0x135555, 0x7F0 },
+	[ATHOS_LUT_CHAN_609750_IDX] = { 24390, 0x0, 0x65, 0x140000, 0x7F1 },
+	[ATHOS_LUT_CHAN_609875_IDX] = { 24395, 0x0, 0x65, 0x14AAAB, 0x7F1 },
+	[ATHOS_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x65, 0x155555, 0x7F1 },
+	[ATHOS_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x65, 0x160000, 0x7F2 },
+	[ATHOS_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x65, 0x16AAAB, 0x7F2 },
+	[ATHOS_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x65, 0x175555, 0x7F3 },
+	[ATHOS_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x65, 0x180000, 0x7F3 },
+	[ATHOS_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x65, 0x18AAAB, 0x7F3 },
+	[ATHOS_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x65, 0x195555, 0x7F4 },
+	[ATHOS_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x65, 0x1A0000, 0x7F4 },
+	[ATHOS_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x65, 0x1AAAAB, 0x7F5 },
+	[ATHOS_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x65, 0x1B5555, 0x7F5 },
+	[ATHOS_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x65, 0x1C0000, 0x7F6 },
+	[ATHOS_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x65, 0x1CAAAB, 0x7F6 },
+	[ATHOS_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x65, 0x1D5555, 0x7F6 },
+	[ATHOS_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x65, 0x1E0000, 0x7F7 },
+	[ATHOS_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x65, 0x1EAAAB, 0x7F7 },
+	[ATHOS_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x65, 0x1F5555, 0x7F8 },
+	[ATHOS_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x66, 0x0, 0x7F8 },
+	[ATHOS_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x66, 0xAAAB, 0x7F8 },
+	[ATHOS_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x66, 0x15555, 0x7F9 },
+	[ATHOS_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x66, 0x20000, 0x7F9 },
+	[ATHOS_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x66, 0x2AAAB, 0x7FA },
+	[ATHOS_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x66, 0x35555, 0x7FA },
+	[ATHOS_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x66, 0x40000, 0x7FB },
+	[ATHOS_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x66, 0x4AAAB, 0x7FB },
+	[ATHOS_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x66, 0x55555, 0x7FB },
+	[ATHOS_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x66, 0x60000, 0x7FC },
+	[ATHOS_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x66, 0x6AAAB, 0x7FC },
+	[ATHOS_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x66, 0x75555, 0x7FD },
+	[ATHOS_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x66, 0x80000, 0x7FD },
+	[ATHOS_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x66, 0x8AAAB, 0x7FD },
+	[ATHOS_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x66, 0x95555, 0x7FE },
+	[ATHOS_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x66, 0xA0000, 0x7FE },
+	[ATHOS_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x66, 0xAAAAB, 0x7FF },
+	[ATHOS_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x66, 0xB5555, 0x7FF },
+	[ATHOS_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x66, 0xC0000, 0x800 },
+	[ATHOS_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x66, 0xCAAAB, 0x800 },
+	[ATHOS_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x66, 0xD5555, 0x800 },
+	[ATHOS_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x66, 0xE0000, 0x801 },
+	[ATHOS_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x66, 0xEAAAB, 0x801 },
+	[ATHOS_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x66, 0xF5555, 0x802 },
+	[ATHOS_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x66, 0x100000, 0x802 },
+	[ATHOS_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x66, 0x10AAAB, 0x802 },
+	[ATHOS_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x66, 0x115555, 0x803 },
+	[ATHOS_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x66, 0x120000, 0x803 },
+	[ATHOS_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x66, 0x12AAAB, 0x804 },
+	[ATHOS_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x66, 0x135555, 0x804 },
+	[ATHOS_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x66, 0x140000, 0x805 },
+	[ATHOS_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x66, 0x14AAAB, 0x805 },
+	[ATHOS_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x66, 0x155555, 0x805 },
+	[ATHOS_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x66, 0x160000, 0x806 },
+	[ATHOS_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x66, 0x16AAAB, 0x806 },
+	[ATHOS_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x66, 0x175555, 0x807 },
+	[ATHOS_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x66, 0x180000, 0x807 },
+	[ATHOS_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x66, 0x18AAAB, 0x807 },
+	[ATHOS_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x66, 0x195555, 0x808 },
+	[ATHOS_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x66, 0x1A0000, 0x808 },
+	[ATHOS_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x66, 0x1AAAAB, 0x809 },
+	[ATHOS_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x66, 0x1B5555, 0x809 },
+	[ATHOS_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x66, 0x1C0000, 0x80A },
+	[ATHOS_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x66, 0x1CAAAB, 0x80A },
+	[ATHOS_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x66, 0x1D5555, 0x80A },
+	[ATHOS_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x66, 0x1E0000, 0x80B },
+	[ATHOS_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x66, 0x1EAAAB, 0x80B },
+	[ATHOS_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x66, 0x1F5555, 0x80C },
+	[ATHOS_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x67, 0x0, 0x80C },
+	[ATHOS_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x67, 0xAAAB, 0x80C },
+	[ATHOS_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x67, 0x15555, 0x80D },
+	[ATHOS_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x67, 0x20000, 0x80D },
+	[ATHOS_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x67, 0x2AAAB, 0x80E },
+	[ATHOS_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x67, 0x35555, 0x80E },
+	[ATHOS_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x67, 0x40000, 0x80F },
+	[ATHOS_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x67, 0x4AAAB, 0x80F },
+	[ATHOS_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x67, 0x55555, 0x80F },
+	[ATHOS_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x67, 0x60000, 0x810 },
+	[ATHOS_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x67, 0x6AAAB, 0x810 },
+	[ATHOS_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x67, 0x75555, 0x811 },
+	[ATHOS_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x67, 0x80000, 0x811 },
+	[ATHOS_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x67, 0x8AAAB, 0x811 },
+	[ATHOS_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x67, 0x95555, 0x812 },
+	[ATHOS_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x67, 0xA0000, 0x812 },
+	[ATHOS_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x67, 0xAAAAB, 0x813 },
+	[ATHOS_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x67, 0xB5555, 0x813 },
+	[ATHOS_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x67, 0xC0000, 0x814 },
+	[ATHOS_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x67, 0xCAAAB, 0x814 },
+	[ATHOS_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x67, 0xD5555, 0x814 },
+	[ATHOS_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x67, 0xE0000, 0x815 },
+	[ATHOS_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x67, 0xEAAAB, 0x815 },
+	[ATHOS_LUT_CHAN_620875_IDX] = { 24835, 0x1, 0x67, 0xF5555, 0x816 },
+	[ATHOS_LUT_CHAN_621000_IDX] = { 24840, 0x1, 0x67, 0x100000, 0x816 },
+	[ATHOS_LUT_CHAN_621125_IDX] = { 24845, 0x1, 0x67, 0x10AAAB, 0x816 },
+	[ATHOS_LUT_CHAN_621250_IDX] = { 24850, 0x1, 0x67, 0x115555, 0x817 },
+	[ATHOS_LUT_CHAN_621375_IDX] = { 24855, 0x1, 0x67, 0x120000, 0x817 },
+	[ATHOS_LUT_CHAN_621500_IDX] = { 24860, 0x1, 0x67, 0x12AAAB, 0x818 },
+	[ATHOS_LUT_CHAN_621625_IDX] = { 24865, 0x1, 0x67, 0x135555, 0x818 },
+	[ATHOS_LUT_CHAN_621750_IDX] = { 24870, 0x1, 0x67, 0x140000, 0x819 },
+	[ATHOS_LUT_CHAN_621875_IDX] = { 24875, 0x1, 0x67, 0x14AAAB, 0x819 },
+	[ATHOS_LUT_CHAN_622000_IDX] = { 24880, 0x1, 0x67, 0x155555, 0x819 },
+	[ATHOS_LUT_CHAN_622125_IDX] = { 24885, 0x1, 0x67, 0x160000, 0x81A },
+	[ATHOS_LUT_CHAN_622250_IDX] = { 24890, 0x1, 0x67, 0x16AAAB, 0x81A },
+	[ATHOS_LUT_CHAN_622375_IDX] = { 24895, 0x1, 0x67, 0x175555, 0x81B },
+	[ATHOS_LUT_CHAN_622500_IDX] = { 24900, 0x1, 0x67, 0x180000, 0x81B },
+	[ATHOS_LUT_CHAN_622625_IDX] = { 24905, 0x1, 0x67, 0x18AAAB, 0x81B },
+	[ATHOS_LUT_CHAN_622750_IDX] = { 24910, 0x1, 0x67, 0x195555, 0x81C },
+	[ATHOS_LUT_CHAN_622875_IDX] = { 24915, 0x1, 0x67, 0x1A0000, 0x81C },
+	[ATHOS_LUT_CHAN_623000_IDX] = { 24920, 0x1, 0x67, 0x1AAAAB, 0x81D },
+	[ATHOS_LUT_CHAN_623125_IDX] = { 24925, 0x1, 0x67, 0x1B5555, 0x81D },
+	[ATHOS_LUT_CHAN_623250_IDX] = { 24930, 0x1, 0x67, 0x1C0000, 0x81E },
+	[ATHOS_LUT_CHAN_623375_IDX] = { 24935, 0x1, 0x67, 0x1CAAAB, 0x81E },
+	[ATHOS_LUT_CHAN_623500_IDX] = { 24940, 0x1, 0x67, 0x1D5555, 0x81E },
+	[ATHOS_LUT_CHAN_623625_IDX] = { 24945, 0x1, 0x67, 0x1E0000, 0x81F },
+	[ATHOS_LUT_CHAN_623750_IDX] = { 24950, 0x1, 0x67, 0x1EAAAB, 0x81F },
+	[ATHOS_LUT_CHAN_623875_IDX] = { 24955, 0x1, 0x67, 0x1F5555, 0x820 },
+	[ATHOS_LUT_CHAN_624000_IDX] = { 24960, 0x1, 0x68, 0x0, 0x820 },
+	[ATHOS_LUT_CHAN_624125_IDX] = { 24965, 0x1, 0x68, 0xAAAB, 0x820 },
+	[ATHOS_LUT_CHAN_624250_IDX] = { 24970, 0x1, 0x68, 0x15555, 0x821 },
+	[ATHOS_LUT_CHAN_624375_IDX] = { 24975, 0x1, 0x68, 0x20000, 0x821 },
+	[ATHOS_LUT_CHAN_624500_IDX] = { 24980, 0x1, 0x68, 0x2AAAB, 0x822 },
+	[ATHOS_LUT_CHAN_624625_IDX] = { 24985, 0x1, 0x68, 0x35555, 0x822 },
+	[ATHOS_LUT_CHAN_624750_IDX] = { 24990, 0x1, 0x68, 0x40000, 0x823 },
+	[ATHOS_LUT_CHAN_624875_IDX] = { 24995, 0x1, 0x68, 0x4AAAB, 0x823 },
+	[ATHOS_LUT_CHAN_625000_IDX] = { 25000, 0x1, 0x68, 0x55555, 0x823 },
+	[ATHOS_LUT_CHAN_625125_IDX] = { 25005, 0x1, 0x68, 0x60000, 0x824 },
+	[ATHOS_LUT_CHAN_625250_IDX] = { 25010, 0x1, 0x68, 0x6AAAB, 0x824 },
+	[ATHOS_LUT_CHAN_625375_IDX] = { 25015, 0x1, 0x68, 0x75555, 0x825 },
+	[ATHOS_LUT_CHAN_625500_IDX] = { 25020, 0x1, 0x68, 0x80000, 0x825 },
+	[ATHOS_LUT_CHAN_625625_IDX] = { 25025, 0x1, 0x68, 0x8AAAB, 0x825 },
+	[ATHOS_LUT_CHAN_625750_IDX] = { 25030, 0x1, 0x68, 0x95555, 0x826 },
+	[ATHOS_LUT_CHAN_625875_IDX] = { 25035, 0x1, 0x68, 0xA0000, 0x826 },
+	[ATHOS_LUT_CHAN_626000_IDX] = { 25040, 0x1, 0x68, 0xAAAAB, 0x827 },
+	[ATHOS_LUT_CHAN_626125_IDX] = { 25045, 0x1, 0x68, 0xB5555, 0x827 },
+	[ATHOS_LUT_CHAN_626250_IDX] = { 25050, 0x1, 0x68, 0xC0000, 0x828 },
+	[ATHOS_LUT_CHAN_626375_IDX] = { 25055, 0x1, 0x68, 0xCAAAB, 0x828 },
+	[ATHOS_LUT_CHAN_626500_IDX] = { 25060, 0x1, 0x68, 0xD5555, 0x828 },
+	[ATHOS_LUT_CHAN_626625_IDX] = { 25065, 0x1, 0x68, 0xE0000, 0x829 },
+	[ATHOS_LUT_CHAN_626750_IDX] = { 25070, 0x1, 0x68, 0xEAAAB, 0x829 },
+	[ATHOS_LUT_CHAN_626875_IDX] = { 25075, 0x1, 0x68, 0xF5555, 0x82A },
+	[ATHOS_LUT_CHAN_627000_IDX] = { 25080, 0x1, 0x68, 0x100000, 0x82A },
+	[ATHOS_LUT_CHAN_627125_IDX] = { 25085, 0x1, 0x68, 0x10AAAB, 0x82A },
+	[ATHOS_LUT_CHAN_627250_IDX] = { 25090, 0x1, 0x68, 0x115555, 0x82B },
+	[ATHOS_LUT_CHAN_627375_IDX] = { 25095, 0x1, 0x68, 0x120000, 0x82B },
+	[ATHOS_LUT_CHAN_627500_IDX] = { 25100, 0x1, 0x68, 0x12AAAB, 0x82C },
+	[ATHOS_LUT_CHAN_627625_IDX] = { 25105, 0x1, 0x68, 0x135555, 0x82C },
+	[ATHOS_LUT_CHAN_627750_IDX] = { 25110, 0x1, 0x68, 0x140000, 0x82D },
+	[ATHOS_LUT_CHAN_627875_IDX] = { 25115, 0x1, 0x68, 0x14AAAB, 0x82D },
+	[ATHOS_LUT_CHAN_628000_IDX] = { 25120, 0x1, 0x68, 0x155555, 0x82D },
+	[ATHOS_LUT_CHAN_628125_IDX] = { 25125, 0x1, 0x68, 0x160000, 0x82E },
+	[ATHOS_LUT_CHAN_628250_IDX] = { 25130, 0x1, 0x68, 0x16AAAB, 0x82E },
+	[ATHOS_LUT_CHAN_628375_IDX] = { 25135, 0x1, 0x68, 0x175555, 0x82F },
+	[ATHOS_LUT_CHAN_628500_IDX] = { 25140, 0x1, 0x68, 0x180000, 0x82F },
+	[ATHOS_LUT_CHAN_628625_IDX] = { 25145, 0x1, 0x68, 0x18AAAB, 0x82F },
+	[ATHOS_LUT_CHAN_628750_IDX] = { 25150, 0x1, 0x68, 0x195555, 0x830 },
+	[ATHOS_LUT_CHAN_628875_IDX] = { 25155, 0x1, 0x68, 0x1A0000, 0x830 },
+	[ATHOS_LUT_CHAN_629000_IDX] = { 25160, 0x1, 0x68, 0x1AAAAB, 0x831 },
+	[ATHOS_LUT_CHAN_629125_IDX] = { 25165, 0x1, 0x68, 0x1B5555, 0x831 },
+	[ATHOS_LUT_CHAN_629250_IDX] = { 25170, 0x1, 0x68, 0x1C0000, 0x832 },
+	[ATHOS_LUT_CHAN_629375_IDX] = { 25175, 0x1, 0x68, 0x1CAAAB, 0x832 },
+	[ATHOS_LUT_CHAN_629500_IDX] = { 25180, 0x1, 0x68, 0x1D5555, 0x832 },
+	[ATHOS_LUT_CHAN_629625_IDX] = { 25185, 0x1, 0x68, 0x1E0000, 0x833 },
+	[ATHOS_LUT_CHAN_629750_IDX] = { 25190, 0x1, 0x68, 0x1EAAAB, 0x833 },
+	[ATHOS_LUT_CHAN_629875_IDX] = { 25195, 0x1, 0x68, 0x1F5555, 0x834 },
+	[ATHOS_LUT_CHAN_630000_IDX] = { 25200, 0x1, 0x69, 0x0, 0x834 },
+	[ATHOS_LUT_CHAN_630125_IDX] = { 25205, 0x1, 0x69, 0xAAAB, 0x834 },
+	[ATHOS_LUT_CHAN_630250_IDX] = { 25210, 0x1, 0x69, 0x15555, 0x835 },
+	[ATHOS_LUT_CHAN_630375_IDX] = { 25215, 0x1, 0x69, 0x20000, 0x835 },
+	[ATHOS_LUT_CHAN_630500_IDX] = { 25220, 0x1, 0x69, 0x2AAAB, 0x836 },
+	[ATHOS_LUT_CHAN_630625_IDX] = { 25225, 0x1, 0x69, 0x35555, 0x836 },
+	[ATHOS_LUT_CHAN_630750_IDX] = { 25230, 0x1, 0x69, 0x40000, 0x837 },
+	[ATHOS_LUT_CHAN_630875_IDX] = { 25235, 0x1, 0x69, 0x4AAAB, 0x837 },
+	[ATHOS_LUT_CHAN_631000_IDX] = { 25240, 0x1, 0x69, 0x55555, 0x837 },
+	[ATHOS_LUT_CHAN_631125_IDX] = { 25245, 0x1, 0x69, 0x60000, 0x838 },
+	[ATHOS_LUT_CHAN_631250_IDX] = { 25250, 0x1, 0x69, 0x6AAAB, 0x838 },
+	[ATHOS_LUT_CHAN_631375_IDX] = { 25255, 0x1, 0x69, 0x75555, 0x839 },
+	[ATHOS_LUT_CHAN_631500_IDX] = { 25260, 0x1, 0x69, 0x80000, 0x839 },
+	[ATHOS_LUT_CHAN_631625_IDX] = { 25265, 0x1, 0x69, 0x8AAAB, 0x839 },
+	[ATHOS_LUT_CHAN_631750_IDX] = { 25270, 0x1, 0x69, 0x95555, 0x83A },
+	[ATHOS_LUT_CHAN_631875_IDX] = { 25275, 0x1, 0x69, 0xA0000, 0x83A },
+	[ATHOS_LUT_CHAN_632000_IDX] = { 25280, 0x1, 0x69, 0xAAAAB, 0x83B },
+	[ATHOS_LUT_CHAN_632125_IDX] = { 25285, 0x1, 0x69, 0xB5555, 0x83B },
+	[ATHOS_LUT_CHAN_632250_IDX] = { 25290, 0x1, 0x69, 0xC0000, 0x83C },
+	[ATHOS_LUT_CHAN_632375_IDX] = { 25295, 0x1, 0x69, 0xCAAAB, 0x83C },
+	[ATHOS_LUT_CHAN_632500_IDX] = { 25300, 0x1, 0x69, 0xD5555, 0x83C },
+	[ATHOS_LUT_CHAN_632625_IDX] = { 25305, 0x1, 0x69, 0xE0000, 0x83D },
+	[ATHOS_LUT_CHAN_632750_IDX] = { 25310, 0x1, 0x69, 0xEAAAB, 0x83D },
+	[ATHOS_LUT_CHAN_632875_IDX] = { 25315, 0x1, 0x69, 0xF5555, 0x83E },
+	[ATHOS_LUT_CHAN_633000_IDX] = { 25320, 0x1, 0x69, 0x100000, 0x83E },
+	[ATHOS_LUT_CHAN_633125_IDX] = { 25325, 0x1, 0x69, 0x10AAAB, 0x83E },
+	[ATHOS_LUT_CHAN_633250_IDX] = { 25330, 0x1, 0x69, 0x115555, 0x83F },
+	[ATHOS_LUT_CHAN_633375_IDX] = { 25335, 0x1, 0x69, 0x120000, 0x83F },
+	[ATHOS_LUT_CHAN_633500_IDX] = { 25340, 0x1, 0x69, 0x12AAAB, 0x840 },
+	[ATHOS_LUT_CHAN_633625_IDX] = { 25345, 0x1, 0x69, 0x135555, 0x840 },
+	[ATHOS_LUT_CHAN_633750_IDX] = { 25350, 0x1, 0x69, 0x140000, 0x841 },
+	[ATHOS_LUT_CHAN_633875_IDX] = { 25355, 0x1, 0x69, 0x14AAAB, 0x841 },
+	[ATHOS_LUT_CHAN_634000_IDX] = { 25360, 0x1, 0x69, 0x155555, 0x841 },
+	[ATHOS_LUT_CHAN_634125_IDX] = { 25365, 0x1, 0x69, 0x160000, 0x842 },
+	[ATHOS_LUT_CHAN_634250_IDX] = { 25370, 0x1, 0x69, 0x16AAAB, 0x842 },
+	[ATHOS_LUT_CHAN_634375_IDX] = { 25375, 0x1, 0x69, 0x175555, 0x843 },
+	[ATHOS_LUT_CHAN_634500_IDX] = { 25380, 0x1, 0x69, 0x180000, 0x843 },
+	[ATHOS_LUT_CHAN_634625_IDX] = { 25385, 0x1, 0x69, 0x18AAAB, 0x843 },
+	[ATHOS_LUT_CHAN_634750_IDX] = { 25390, 0x1, 0x69, 0x195555, 0x844 },
+	[ATHOS_LUT_CHAN_634875_IDX] = { 25395, 0x1, 0x69, 0x1A0000, 0x844 },
+	[ATHOS_LUT_CHAN_635000_IDX] = { 25400, 0x1, 0x69, 0x1AAAAB, 0x845 },
+	[ATHOS_LUT_CHAN_635125_IDX] = { 25405, 0x1, 0x69, 0x1B5555, 0x845 },
+	[ATHOS_LUT_CHAN_635250_IDX] = { 25410, 0x1, 0x69, 0x1C0000, 0x846 },
+	[ATHOS_LUT_CHAN_635375_IDX] = { 25415, 0x1, 0x69, 0x1CAAAB, 0x846 },
+	[ATHOS_LUT_CHAN_635500_IDX] = { 25420, 0x1, 0x69, 0x1D5555, 0x846 },
+	[ATHOS_LUT_CHAN_635625_IDX] = { 25425, 0x1, 0x69, 0x1E0000, 0x847 },
+	[ATHOS_LUT_CHAN_635750_IDX] = { 25430, 0x1, 0x69, 0x1EAAAB, 0x847 },
+	[ATHOS_LUT_CHAN_635875_IDX] = { 25435, 0x1, 0x69, 0x1F5555, 0x848 },
+	[ATHOS_LUT_CHAN_636000_IDX] = { 25440, 0x1, 0x6A, 0x0, 0x848 },
+	[ATHOS_LUT_CHAN_636125_IDX] = { 25445, 0x1, 0x6A, 0xAAAB, 0x848 },
+	[ATHOS_LUT_CHAN_636250_IDX] = { 25450, 0x1, 0x6A, 0x15555, 0x849 },
+	[ATHOS_LUT_CHAN_636375_IDX] = { 25455, 0x1, 0x6A, 0x20000, 0x849 },
+	[ATHOS_LUT_CHAN_636500_IDX] = { 25460, 0x1, 0x6A, 0x2AAAB, 0x84A },
+	[ATHOS_LUT_CHAN_636625_IDX] = { 25465, 0x1, 0x6A, 0x35555, 0x84A },
+	[ATHOS_LUT_CHAN_636750_IDX] = { 25470, 0x1, 0x6A, 0x40000, 0x84B },
+	[ATHOS_LUT_CHAN_636875_IDX] = { 25475, 0x1, 0x6A, 0x4AAAB, 0x84B },
+	[ATHOS_LUT_CHAN_637000_IDX] = { 25480, 0x1, 0x6A, 0x55555, 0x84B },
+	[ATHOS_LUT_CHAN_637125_IDX] = { 25485, 0x1, 0x6A, 0x60000, 0x84C },
+	[ATHOS_LUT_CHAN_637250_IDX] = { 25490, 0x1, 0x6A, 0x6AAAB, 0x84C },
+	[ATHOS_LUT_CHAN_637375_IDX] = { 25495, 0x1, 0x6A, 0x75555, 0x84D },
+	[ATHOS_LUT_CHAN_637500_IDX] = { 25500, 0x1, 0x6A, 0x80000, 0x84D },
+	[ATHOS_LUT_CHAN_637625_IDX] = { 25505, 0x1, 0x6A, 0x8AAAB, 0x84D },
+	[ATHOS_LUT_CHAN_637750_IDX] = { 25510, 0x1, 0x6A, 0x95555, 0x84E },
+	[ATHOS_LUT_CHAN_637875_IDX] = { 25515, 0x1, 0x6A, 0xA0000, 0x84E },
+	[ATHOS_LUT_CHAN_638000_IDX] = { 25520, 0x1, 0x6A, 0xAAAAB, 0x84F },
+	[ATHOS_LUT_CHAN_638125_IDX] = { 25525, 0x1, 0x6A, 0xB5555, 0x84F },
+	[ATHOS_LUT_CHAN_638250_IDX] = { 25530, 0x1, 0x6A, 0xC0000, 0x850 },
+	[ATHOS_LUT_CHAN_638375_IDX] = { 25535, 0x1, 0x6A, 0xCAAAB, 0x850 },
+	[ATHOS_LUT_CHAN_638500_IDX] = { 25540, 0x1, 0x6A, 0xD5555, 0x850 },
+	[ATHOS_LUT_CHAN_638625_IDX] = { 25545, 0x1, 0x6A, 0xE0000, 0x851 },
+	[ATHOS_LUT_CHAN_638750_IDX] = { 25550, 0x1, 0x6A, 0xEAAAB, 0x851 },
+	[ATHOS_LUT_CHAN_638875_IDX] = { 25555, 0x1, 0x6A, 0xF5555, 0x852 },
+	[ATHOS_LUT_CHAN_639000_IDX] = { 25560, 0x1, 0x6A, 0x100000, 0x852 },
+	[ATHOS_LUT_CHAN_639125_IDX] = { 25565, 0x1, 0x6A, 0x10AAAB, 0x852 },
+	[ATHOS_LUT_CHAN_639250_IDX] = { 25570, 0x1, 0x6A, 0x115555, 0x853 },
+	[ATHOS_LUT_CHAN_639375_IDX] = { 25575, 0x1, 0x6A, 0x120000, 0x853 },
+	[ATHOS_LUT_CHAN_639500_IDX] = { 25580, 0x1, 0x6A, 0x12AAAB, 0x854 },
+	[ATHOS_LUT_CHAN_639625_IDX] = { 25585, 0x1, 0x6A, 0x135555, 0x854 },
+	[ATHOS_LUT_CHAN_639750_IDX] = { 25590, 0x1, 0x6A, 0x140000, 0x855 },
+	[ATHOS_LUT_CHAN_639875_IDX] = { 25595, 0x1, 0x6A, 0x14AAAB, 0x855 },
+	[ATHOS_LUT_CHAN_640000_IDX] = { 25600, 0x1, 0x6A, 0x155555, 0x855 },
+	[ATHOS_LUT_CHAN_640125_IDX] = { 25605, 0x1, 0x6A, 0x160000, 0x856 },
+	[ATHOS_LUT_CHAN_640250_IDX] = { 25610, 0x1, 0x6A, 0x16AAAB, 0x856 },
+	[ATHOS_LUT_CHAN_640375_IDX] = { 25615, 0x1, 0x6A, 0x175555, 0x857 },
+	[ATHOS_LUT_CHAN_640500_IDX] = { 25620, 0x1, 0x6A, 0x180000, 0x857 },
+	[ATHOS_LUT_CHAN_640625_IDX] = { 25625, 0x1, 0x6A, 0x18AAAB, 0x857 },
+	[ATHOS_LUT_CHAN_640750_IDX] = { 25630, 0x1, 0x6A, 0x195555, 0x858 },
+	[ATHOS_LUT_CHAN_640875_IDX] = { 25635, 0x1, 0x6A, 0x1A0000, 0x858 },
+	[ATHOS_LUT_CHAN_641000_IDX] = { 25640, 0x1, 0x6A, 0x1AAAAB, 0x859 },
+	[ATHOS_LUT_CHAN_641125_IDX] = { 25645, 0x1, 0x6A, 0x1B5555, 0x859 },
+	[ATHOS_LUT_CHAN_641250_IDX] = { 25650, 0x1, 0x6A, 0x1C0000, 0x85A },
+	[ATHOS_LUT_CHAN_641375_IDX] = { 25655, 0x1, 0x6A, 0x1CAAAB, 0x85A },
+	[ATHOS_LUT_CHAN_641500_IDX] = { 25660, 0x1, 0x6A, 0x1D5555, 0x85A },
+	[ATHOS_LUT_CHAN_641625_IDX] = { 25665, 0x1, 0x6A, 0x1E0000, 0x85B },
+	[ATHOS_LUT_CHAN_641750_IDX] = { 25670, 0x1, 0x6A, 0x1EAAAB, 0x85B },
+	[ATHOS_LUT_CHAN_641875_IDX] = { 25675, 0x1, 0x6A, 0x1F5555, 0x85C },
+	[ATHOS_LUT_CHAN_642000_IDX] = { 25680, 0x1, 0x6B, 0x0, 0x85C },
+	[ATHOS_LUT_CHAN_642125_IDX] = { 25685, 0x1, 0x6B, 0xAAAB, 0x85C },
+	[ATHOS_LUT_CHAN_642250_IDX] = { 25690, 0x1, 0x6B, 0x15555, 0x85D },
+	[ATHOS_LUT_CHAN_642375_IDX] = { 25695, 0x1, 0x6B, 0x20000, 0x85D },
+	[ATHOS_LUT_CHAN_642500_IDX] = { 25700, 0x1, 0x6B, 0x2AAAB, 0x85E },
+	[ATHOS_LUT_CHAN_642625_IDX] = { 25705, 0x1, 0x6B, 0x35555, 0x85E },
+	[ATHOS_LUT_CHAN_642750_IDX] = { 25710, 0x1, 0x6B, 0x40000, 0x85F },
+	[ATHOS_LUT_CHAN_642875_IDX] = { 25715, 0x1, 0x6B, 0x4AAAB, 0x85F },
+	[ATHOS_LUT_CHAN_643000_IDX] = { 25720, 0x1, 0x6B, 0x55555, 0x85F },
+	[ATHOS_LUT_CHAN_643125_IDX] = { 25725, 0x1, 0x6B, 0x60000, 0x860 },
+	[ATHOS_LUT_CHAN_643250_IDX] = { 25730, 0x1, 0x6B, 0x6AAAB, 0x860 },
+	[ATHOS_LUT_CHAN_643375_IDX] = { 25735, 0x1, 0x6B, 0x75555, 0x861 },
+	[ATHOS_LUT_CHAN_643500_IDX] = { 25740, 0x1, 0x6B, 0x80000, 0x861 },
+	[ATHOS_LUT_CHAN_643625_IDX] = { 25745, 0x1, 0x6B, 0x8AAAB, 0x861 },
+	[ATHOS_LUT_CHAN_643750_IDX] = { 25750, 0x1, 0x6B, 0x95555, 0x862 },
+	[ATHOS_LUT_CHAN_643875_IDX] = { 25755, 0x1, 0x6B, 0xA0000, 0x862 },
+	[ATHOS_LUT_CHAN_644000_IDX] = { 25760, 0x1, 0x6B, 0xAAAAB, 0x863 },
+	[ATHOS_LUT_CHAN_644125_IDX] = { 25765, 0x1, 0x6B, 0xB5555, 0x863 },
+	[ATHOS_LUT_CHAN_644250_IDX] = { 25770, 0x1, 0x6B, 0xC0000, 0x864 },
+	[ATHOS_LUT_CHAN_644375_IDX] = { 25775, 0x1, 0x6B, 0xCAAAB, 0x864 },
+	[ATHOS_LUT_CHAN_644500_IDX] = { 25780, 0x1, 0x6B, 0xD5555, 0x864 },
+	[ATHOS_LUT_CHAN_644625_IDX] = { 25785, 0x1, 0x6B, 0xE0000, 0x865 },
+	[ATHOS_LUT_CHAN_644750_IDX] = { 25790, 0x1, 0x6B, 0xEAAAB, 0x865 },
+	[ATHOS_LUT_CHAN_644875_IDX] = { 25795, 0x1, 0x6B, 0xF5555, 0x866 },
+	[ATHOS_LUT_CHAN_645000_IDX] = { 25800, 0x1, 0x6B, 0x100000, 0x866 },
+	[ATHOS_LUT_CHAN_645125_IDX] = { 25805, 0x1, 0x6B, 0x10AAAB, 0x866 },
+	[ATHOS_LUT_CHAN_645250_IDX] = { 25810, 0x1, 0x6B, 0x115555, 0x867 },
+	[ATHOS_LUT_CHAN_645375_IDX] = { 25815, 0x1, 0x6B, 0x120000, 0x867 },
+	[ATHOS_LUT_CHAN_645500_IDX] = { 25820, 0x1, 0x6B, 0x12AAAB, 0x868 },
+	[ATHOS_LUT_CHAN_645625_IDX] = { 25825, 0x1, 0x6B, 0x135555, 0x868 },
+	[ATHOS_LUT_CHAN_645750_IDX] = { 25830, 0x1, 0x6B, 0x140000, 0x869 },
+	[ATHOS_LUT_CHAN_645875_IDX] = { 25835, 0x1, 0x6B, 0x14AAAB, 0x869 },
+	[ATHOS_LUT_CHAN_646000_IDX] = { 25840, 0x1, 0x6B, 0x155555, 0x869 },
+	[ATHOS_LUT_CHAN_646125_IDX] = { 25845, 0x1, 0x6B, 0x160000, 0x86A },
+	[ATHOS_LUT_CHAN_646250_IDX] = { 25850, 0x1, 0x6B, 0x16AAAB, 0x86A },
+	[ATHOS_LUT_CHAN_646375_IDX] = { 25855, 0x1, 0x6B, 0x175555, 0x86B },
+	[ATHOS_LUT_CHAN_646500_IDX] = { 25860, 0x1, 0x6B, 0x180000, 0x86B },
+	[ATHOS_LUT_CHAN_646625_IDX] = { 25865, 0x1, 0x6B, 0x18AAAB, 0x86B },
+	[ATHOS_LUT_CHAN_646750_IDX] = { 25870, 0x1, 0x6B, 0x195555, 0x86C },
+	[ATHOS_LUT_CHAN_646875_IDX] = { 25875, 0x1, 0x6B, 0x1A0000, 0x86C },
+	[ATHOS_LUT_CHAN_647000_IDX] = { 25880, 0x1, 0x6B, 0x1AAAAB, 0x86D },
+	[ATHOS_LUT_CHAN_647125_IDX] = { 25885, 0x1, 0x6B, 0x1B5555, 0x86D },
+	[ATHOS_LUT_CHAN_647250_IDX] = { 25890, 0x1, 0x6B, 0x1C0000, 0x86E },
+	[ATHOS_LUT_CHAN_647375_IDX] = { 25895, 0x1, 0x6B, 0x1CAAAB, 0x86E },
+	[ATHOS_LUT_CHAN_647500_IDX] = { 25900, 0x1, 0x6B, 0x1D5555, 0x86E },
+	[ATHOS_LUT_CHAN_647625_IDX] = { 25905, 0x1, 0x6B, 0x1E0000, 0x86F },
+	[ATHOS_LUT_CHAN_647750_IDX] = { 25910, 0x1, 0x6B, 0x1EAAAB, 0x86F },
+	[ATHOS_LUT_CHAN_647875_IDX] = { 25915, 0x1, 0x6B, 0x1F5555, 0x870 },
+	[ATHOS_LUT_CHAN_648000_IDX] = { 25920, 0x1, 0x6C, 0x0, 0x870 },
+	[ATHOS_LUT_CHAN_648125_IDX] = { 25925, 0x1, 0x6C, 0xAAAB, 0x870 },
+	[ATHOS_LUT_CHAN_648250_IDX] = { 25930, 0x1, 0x6C, 0x15555, 0x871 },
+	[ATHOS_LUT_CHAN_648375_IDX] = { 25935, 0x1, 0x6C, 0x20000, 0x871 },
+	[ATHOS_LUT_CHAN_648500_IDX] = { 25940, 0x1, 0x6C, 0x2AAAB, 0x872 },
+	[ATHOS_LUT_CHAN_648625_IDX] = { 25945, 0x1, 0x6C, 0x35555, 0x872 },
+	[ATHOS_LUT_CHAN_648750_IDX] = { 25950, 0x1, 0x6C, 0x40000, 0x873 },
+	[ATHOS_LUT_CHAN_648875_IDX] = { 25955, 0x1, 0x6C, 0x4AAAB, 0x873 },
+	[ATHOS_LUT_CHAN_649000_IDX] = { 25960, 0x1, 0x6C, 0x55555, 0x873 },
+	[ATHOS_LUT_CHAN_649125_IDX] = { 25965, 0x1, 0x6C, 0x60000, 0x874 },
+	[ATHOS_LUT_CHAN_649250_IDX] = { 25970, 0x1, 0x6C, 0x6AAAB, 0x874 },
+	[ATHOS_LUT_CHAN_649375_IDX] = { 25975, 0x1, 0x6C, 0x75555, 0x875 },
+	[ATHOS_LUT_CHAN_649500_IDX] = { 25980, 0x1, 0x6C, 0x80000, 0x875 },
+	[ATHOS_LUT_CHAN_649625_IDX] = { 25985, 0x1, 0x6C, 0x8AAAB, 0x875 },
+	[ATHOS_LUT_CHAN_649750_IDX] = { 25990, 0x1, 0x6C, 0x95555, 0x876 },
+	[ATHOS_LUT_CHAN_649875_IDX] = { 25995, 0x1, 0x6C, 0xA0000, 0x876 },
+	[ATHOS_LUT_CHAN_650000_IDX] = { 26000, 0x1, 0x6C, 0xAAAAB, 0x877 },
+	[ATHOS_LUT_CHAN_650125_IDX] = { 26005, 0x1, 0x6C, 0xB5555, 0x877 },
+	[ATHOS_LUT_CHAN_650250_IDX] = { 26010, 0x1, 0x6C, 0xC0000, 0x878 },
+	[ATHOS_LUT_CHAN_650375_IDX] = { 26015, 0x1, 0x6C, 0xCAAAB, 0x878 },
+	[ATHOS_LUT_CHAN_650500_IDX] = { 26020, 0x1, 0x6C, 0xD5555, 0x878 },
+	[ATHOS_LUT_CHAN_650625_IDX] = { 26025, 0x1, 0x6C, 0xE0000, 0x879 },
+	[ATHOS_LUT_CHAN_650750_IDX] = { 26030, 0x1, 0x6C, 0xEAAAB, 0x879 },
+	[ATHOS_LUT_CHAN_650875_IDX] = { 26035, 0x1, 0x6C, 0xF5555, 0x87A },
+	[ATHOS_LUT_CHAN_651000_IDX] = { 26040, 0x1, 0x6C, 0x100000, 0x87A },
+	[ATHOS_LUT_CHAN_651125_IDX] = { 26045, 0x1, 0x6C, 0x10AAAB, 0x87A },
+	[ATHOS_LUT_CHAN_651250_IDX] = { 26050, 0x1, 0x6C, 0x115555, 0x87B },
+	[ATHOS_LUT_CHAN_651375_IDX] = { 26055, 0x1, 0x6C, 0x120000, 0x87B },
+	[ATHOS_LUT_CHAN_651500_IDX] = { 26060, 0x1, 0x6C, 0x12AAAB, 0x87C },
+	[ATHOS_LUT_CHAN_651625_IDX] = { 26065, 0x1, 0x6C, 0x135555, 0x87C },
+	[ATHOS_LUT_CHAN_651750_IDX] = { 26070, 0x1, 0x6C, 0x140000, 0x87D },
+	[ATHOS_LUT_CHAN_651875_IDX] = { 26075, 0x1, 0x6C, 0x14AAAB, 0x87D },
+	[ATHOS_LUT_CHAN_652000_IDX] = { 26080, 0x1, 0x6C, 0x155555, 0x87D },
+	[ATHOS_LUT_CHAN_652125_IDX] = { 26085, 0x1, 0x6C, 0x160000, 0x87E },
+	[ATHOS_LUT_CHAN_652250_IDX] = { 26090, 0x1, 0x6C, 0x16AAAB, 0x87E },
+	[ATHOS_LUT_CHAN_652375_IDX] = { 26095, 0x1, 0x6C, 0x175555, 0x87F },
+	[ATHOS_LUT_CHAN_652500_IDX] = { 26100, 0x1, 0x6C, 0x180000, 0x87F },
+	[ATHOS_LUT_CHAN_652625_IDX] = { 26105, 0x1, 0x6C, 0x18AAAB, 0x87F },
+	[ATHOS_LUT_CHAN_652750_IDX] = { 26110, 0x1, 0x6C, 0x195555, 0x880 },
+	[ATHOS_LUT_CHAN_652875_IDX] = { 26115, 0x1, 0x6C, 0x1A0000, 0x880 },
+	[ATHOS_LUT_CHAN_653000_IDX] = { 26120, 0x1, 0x6C, 0x1AAAAB, 0x881 },
+	[ATHOS_LUT_CHAN_653125_IDX] = { 26125, 0x1, 0x6C, 0x1B5555, 0x881 },
+	[ATHOS_LUT_CHAN_653250_IDX] = { 26130, 0x1, 0x6C, 0x1C0000, 0x882 },
+	[ATHOS_LUT_CHAN_653375_IDX] = { 26135, 0x1, 0x6C, 0x1CAAAB, 0x882 },
+	[ATHOS_LUT_CHAN_653500_IDX] = { 26140, 0x1, 0x6C, 0x1D5555, 0x882 },
+	[ATHOS_LUT_CHAN_653625_IDX] = { 26145, 0x1, 0x6C, 0x1E0000, 0x883 },
+	[ATHOS_LUT_CHAN_653750_IDX] = { 26150, 0x1, 0x6C, 0x1EAAAB, 0x883 },
+	[ATHOS_LUT_CHAN_653875_IDX] = { 26155, 0x1, 0x6C, 0x1F5555, 0x884 },
+	[ATHOS_LUT_CHAN_654000_IDX] = { 26160, 0x1, 0x6D, 0x0, 0x884 },
+	[ATHOS_LUT_CHAN_654125_IDX] = { 26165, 0x1, 0x6D, 0xAAAB, 0x884 },
+	[ATHOS_LUT_CHAN_654250_IDX] = { 26170, 0x1, 0x6D, 0x15555, 0x885 },
+	[ATHOS_LUT_CHAN_654375_IDX] = { 26175, 0x1, 0x6D, 0x20000, 0x885 },
+	[ATHOS_LUT_CHAN_654500_IDX] = { 26180, 0x1, 0x6D, 0x2AAAB, 0x886 },
+	[ATHOS_LUT_CHAN_654625_IDX] = { 26185, 0x1, 0x6D, 0x35555, 0x886 },
+	[ATHOS_LUT_CHAN_654750_IDX] = { 26190, 0x1, 0x6D, 0x40000, 0x887 },
+	[ATHOS_LUT_CHAN_654875_IDX] = { 26195, 0x1, 0x6D, 0x4AAAB, 0x887 },
+	[ATHOS_LUT_CHAN_655000_IDX] = { 26200, 0x1, 0x6D, 0x55555, 0x887 },
+	[ATHOS_LUT_CHAN_655125_IDX] = { 26205, 0x1, 0x6D, 0x60000, 0x888 },
+	[ATHOS_LUT_CHAN_655250_IDX] = { 26210, 0x1, 0x6D, 0x6AAAB, 0x888 },
+	[ATHOS_LUT_CHAN_655375_IDX] = { 26215, 0x1, 0x6D, 0x75555, 0x889 },
+	[ATHOS_LUT_CHAN_655500_IDX] = { 26220, 0x1, 0x6D, 0x80000, 0x889 },
+	[ATHOS_LUT_CHAN_655625_IDX] = { 26225, 0x1, 0x6D, 0x8AAAB, 0x889 },
+	[ATHOS_LUT_CHAN_655750_IDX] = { 26230, 0x1, 0x6D, 0x95555, 0x88A },
+	[ATHOS_LUT_CHAN_655875_IDX] = { 26235, 0x1, 0x6D, 0xA0000, 0x88A },
+	[ATHOS_LUT_CHAN_656000_IDX] = { 26240, 0x1, 0x6D, 0xAAAAB, 0x88B },
+	[ATHOS_LUT_CHAN_656125_IDX] = { 26245, 0x1, 0x6D, 0xB5555, 0x88B },
+	[ATHOS_LUT_CHAN_656250_IDX] = { 26250, 0x1, 0x6D, 0xC0000, 0x88C },
+	[ATHOS_LUT_CHAN_656375_IDX] = { 26255, 0x1, 0x6D, 0xCAAAB, 0x88C },
+	[ATHOS_LUT_CHAN_656500_IDX] = { 26260, 0x1, 0x6D, 0xD5555, 0x88C },
+	[ATHOS_LUT_CHAN_656625_IDX] = { 26265, 0x1, 0x6D, 0xE0000, 0x88D },
+	[ATHOS_LUT_CHAN_656750_IDX] = { 26270, 0x1, 0x6D, 0xEAAAB, 0x88D },
+	[ATHOS_LUT_CHAN_656875_IDX] = { 26275, 0x1, 0x6D, 0xF5555, 0x88E },
+	[ATHOS_LUT_CHAN_657000_IDX] = { 26280, 0x1, 0x6D, 0x100000, 0x88E },
+	[ATHOS_LUT_CHAN_657125_IDX] = { 26285, 0x1, 0x6D, 0x10AAAB, 0x88E },
+	[ATHOS_LUT_CHAN_657250_IDX] = { 26290, 0x1, 0x6D, 0x115555, 0x88F },
+	[ATHOS_LUT_CHAN_657375_IDX] = { 26295, 0x1, 0x6D, 0x120000, 0x88F },
+	[ATHOS_LUT_CHAN_657500_IDX] = { 26300, 0x1, 0x6D, 0x12AAAB, 0x890 },
+	[ATHOS_LUT_CHAN_657625_IDX] = { 26305, 0x1, 0x6D, 0x135555, 0x890 },
+	[ATHOS_LUT_CHAN_657750_IDX] = { 26310, 0x1, 0x6D, 0x140000, 0x891 },
+	[ATHOS_LUT_CHAN_657875_IDX] = { 26315, 0x1, 0x6D, 0x14AAAB, 0x891 },
+	[ATHOS_LUT_CHAN_658000_IDX] = { 26320, 0x1, 0x6D, 0x155555, 0x891 },
+	[ATHOS_LUT_CHAN_658125_IDX] = { 26325, 0x1, 0x6D, 0x160000, 0x892 },
+	[ATHOS_LUT_CHAN_658250_IDX] = { 26330, 0x1, 0x6D, 0x16AAAB, 0x892 },
+	[ATHOS_LUT_CHAN_658375_IDX] = { 26335, 0x1, 0x6D, 0x175555, 0x893 },
+	[ATHOS_LUT_CHAN_658500_IDX] = { 26340, 0x1, 0x6D, 0x180000, 0x893 },
+	[ATHOS_LUT_CHAN_658625_IDX] = { 26345, 0x1, 0x6D, 0x18AAAB, 0x893 },
+	[ATHOS_LUT_CHAN_658750_IDX] = { 26350, 0x1, 0x6D, 0x195555, 0x894 },
+	[ATHOS_LUT_CHAN_658875_IDX] = { 26355, 0x1, 0x6D, 0x1A0000, 0x894 },
+	[ATHOS_LUT_CHAN_659000_IDX] = { 26360, 0x1, 0x6D, 0x1AAAAB, 0x895 },
+	[ATHOS_LUT_CHAN_659125_IDX] = { 26365, 0x1, 0x6D, 0x1B5555, 0x895 },
+	[ATHOS_LUT_CHAN_659250_IDX] = { 26370, 0x1, 0x6D, 0x1C0000, 0x896 },
+	[ATHOS_LUT_CHAN_659375_IDX] = { 26375, 0x1, 0x6D, 0x1CAAAB, 0x896 },
+	[ATHOS_LUT_CHAN_659500_IDX] = { 26380, 0x1, 0x6D, 0x1D5555, 0x896 },
+	[ATHOS_LUT_CHAN_659625_IDX] = { 26385, 0x1, 0x6D, 0x1E0000, 0x897 },
+	[ATHOS_LUT_CHAN_659750_IDX] = { 26390, 0x1, 0x6D, 0x1EAAAB, 0x897 },
+	[ATHOS_LUT_CHAN_659875_IDX] = { 26395, 0x1, 0x6D, 0x1F5555, 0x898 },
+	[ATHOS_LUT_CHAN_660000_IDX] = { 26400, 0x1, 0x6E, 0x0, 0x898 },
+	[ATHOS_LUT_CHAN_660125_IDX] = { 26405, 0x1, 0x6E, 0xAAAB, 0x898 },
+	[ATHOS_LUT_CHAN_660250_IDX] = { 26410, 0x1, 0x6E, 0x15555, 0x899 },
+	[ATHOS_LUT_CHAN_660375_IDX] = { 26415, 0x1, 0x6E, 0x20000, 0x899 },
+	[ATHOS_LUT_CHAN_660500_IDX] = { 26420, 0x1, 0x6E, 0x2AAAB, 0x89A },
+	[ATHOS_LUT_CHAN_660625_IDX] = { 26425, 0x1, 0x6E, 0x35555, 0x89A },
+	[ATHOS_LUT_CHAN_660750_IDX] = { 26430, 0x1, 0x6E, 0x40000, 0x89B },
+	[ATHOS_LUT_CHAN_660875_IDX] = { 26435, 0x1, 0x6E, 0x4AAAB, 0x89B },
+	[ATHOS_LUT_CHAN_661000_IDX] = { 26440, 0x1, 0x6E, 0x55555, 0x89B },
+	[ATHOS_LUT_CHAN_661125_IDX] = { 26445, 0x1, 0x6E, 0x60000, 0x89C },
+	[ATHOS_LUT_CHAN_661250_IDX] = { 26450, 0x1, 0x6E, 0x6AAAB, 0x89C },
+	[ATHOS_LUT_CHAN_661375_IDX] = { 26455, 0x1, 0x6E, 0x75555, 0x89D },
+	[ATHOS_LUT_CHAN_661500_IDX] = { 26460, 0x1, 0x6E, 0x80000, 0x89D },
+	[ATHOS_LUT_CHAN_661625_IDX] = { 26465, 0x1, 0x6E, 0x8AAAB, 0x89D },
+	[ATHOS_LUT_CHAN_661750_IDX] = { 26470, 0x1, 0x6E, 0x95555, 0x89E },
+	[ATHOS_LUT_CHAN_661875_IDX] = { 26475, 0x1, 0x6E, 0xA0000, 0x89E },
+	[ATHOS_LUT_CHAN_662000_IDX] = { 26480, 0x1, 0x6E, 0xAAAAB, 0x89F },
+	[ATHOS_LUT_CHAN_662125_IDX] = { 26485, 0x1, 0x6E, 0xB5555, 0x89F },
+	[ATHOS_LUT_CHAN_662250_IDX] = { 26490, 0x1, 0x6E, 0xC0000, 0x8A0 },
+	[ATHOS_LUT_CHAN_662375_IDX] = { 26495, 0x1, 0x6E, 0xCAAAB, 0x8A0 },
+	[ATHOS_LUT_CHAN_662500_IDX] = { 26500, 0x1, 0x6E, 0xD5555, 0x8A0 },
+	[ATHOS_LUT_CHAN_662625_IDX] = { 26505, 0x1, 0x6E, 0xE0000, 0x8A1 },
+	[ATHOS_LUT_CHAN_662750_IDX] = { 26510, 0x1, 0x6E, 0xEAAAB, 0x8A1 },
+	[ATHOS_LUT_CHAN_662875_IDX] = { 26515, 0x1, 0x6E, 0xF5555, 0x8A2 },
+	[ATHOS_LUT_CHAN_663000_IDX] = { 26520, 0x1, 0x6E, 0x100000, 0x8A2 },
+	[ATHOS_LUT_CHAN_663125_IDX] = { 26525, 0x1, 0x6E, 0x10AAAB, 0x8A2 },
+	[ATHOS_LUT_CHAN_663250_IDX] = { 26530, 0x1, 0x6E, 0x115555, 0x8A3 },
+	[ATHOS_LUT_CHAN_663375_IDX] = { 26535, 0x1, 0x6E, 0x120000, 0x8A3 },
+	[ATHOS_LUT_CHAN_663500_IDX] = { 26540, 0x1, 0x6E, 0x12AAAB, 0x8A4 },
+	[ATHOS_LUT_CHAN_663625_IDX] = { 26545, 0x1, 0x6E, 0x135555, 0x8A4 },
+	[ATHOS_LUT_CHAN_663750_IDX] = { 26550, 0x1, 0x6E, 0x140000, 0x8A5 },
+	[ATHOS_LUT_CHAN_663875_IDX] = { 26555, 0x1, 0x6E, 0x14AAAB, 0x8A5 },
+	[ATHOS_LUT_CHAN_664000_IDX] = { 26560, 0x1, 0x6E, 0x155555, 0x8A5 },
+	[ATHOS_LUT_CHAN_664125_IDX] = { 26565, 0x1, 0x6E, 0x160000, 0x8A6 },
+	[ATHOS_LUT_CHAN_664250_IDX] = { 26570, 0x1, 0x6E, 0x16AAAB, 0x8A6 },
+	[ATHOS_LUT_CHAN_664375_IDX] = { 26575, 0x1, 0x6E, 0x175555, 0x8A7 },
+	[ATHOS_LUT_CHAN_664500_IDX] = { 26580, 0x1, 0x6E, 0x180000, 0x8A7 },
+	[ATHOS_LUT_CHAN_664625_IDX] = { 26585, 0x1, 0x6E, 0x18AAAB, 0x8A7 },
+	[ATHOS_LUT_CHAN_664750_IDX] = { 26590, 0x1, 0x6E, 0x195555, 0x8A8 },
+	[ATHOS_LUT_CHAN_664875_IDX] = { 26595, 0x1, 0x6E, 0x1A0000, 0x8A8 },
+	[ATHOS_LUT_CHAN_665000_IDX] = { 26600, 0x1, 0x6E, 0x1AAAAB, 0x8A9 },
+	[ATHOS_LUT_CHAN_665125_IDX] = { 26605, 0x1, 0x6E, 0x1B5555, 0x8A9 },
+	[ATHOS_LUT_CHAN_665250_IDX] = { 26610, 0x1, 0x6E, 0x1C0000, 0x8AA },
+	[ATHOS_LUT_CHAN_665375_IDX] = { 26615, 0x1, 0x6E, 0x1CAAAB, 0x8AA },
+	[ATHOS_LUT_CHAN_665500_IDX] = { 26620, 0x1, 0x6E, 0x1D5555, 0x8AA },
+	[ATHOS_LUT_CHAN_665625_IDX] = { 26625, 0x1, 0x6E, 0x1E0000, 0x8AB },
+	[ATHOS_LUT_CHAN_665750_IDX] = { 26630, 0x1, 0x6E, 0x1EAAAB, 0x8AB },
+	[ATHOS_LUT_CHAN_665875_IDX] = { 26635, 0x1, 0x6E, 0x1F5555, 0x8AC },
+	[ATHOS_LUT_CHAN_666000_IDX] = { 26640, 0x1, 0x6F, 0x0, 0x8AC },
+	[ATHOS_LUT_CHAN_666125_IDX] = { 26645, 0x1, 0x6F, 0xAAAB, 0x8AC },
+	[ATHOS_LUT_CHAN_666250_IDX] = { 26650, 0x1, 0x6F, 0x15555, 0x8AD },
+	[ATHOS_LUT_CHAN_666375_IDX] = { 26655, 0x1, 0x6F, 0x20000, 0x8AD },
+	[ATHOS_LUT_CHAN_666500_IDX] = { 26660, 0x1, 0x6F, 0x2AAAB, 0x8AE },
+	[ATHOS_LUT_CHAN_666625_IDX] = { 26665, 0x1, 0x6F, 0x35555, 0x8AE },
+	[ATHOS_LUT_CHAN_666750_IDX] = { 26670, 0x1, 0x6F, 0x40000, 0x8AF },
+	[ATHOS_LUT_CHAN_666875_IDX] = { 26675, 0x1, 0x6F, 0x4AAAB, 0x8AF },
+	[ATHOS_LUT_CHAN_667000_IDX] = { 26680, 0x1, 0x6F, 0x55555, 0x8AF },
+	[ATHOS_LUT_CHAN_667125_IDX] = { 26685, 0x1, 0x6F, 0x60000, 0x8B0 },
+	[ATHOS_LUT_CHAN_667250_IDX] = { 26690, 0x1, 0x6F, 0x6AAAB, 0x8B0 },
+	[ATHOS_LUT_CHAN_667375_IDX] = { 26695, 0x1, 0x6F, 0x75555, 0x8B1 },
+	[ATHOS_LUT_CHAN_667500_IDX] = { 26700, 0x1, 0x6F, 0x80000, 0x8B1 },
+	[ATHOS_LUT_CHAN_667625_IDX] = { 26705, 0x1, 0x6F, 0x8AAAB, 0x8B1 },
+	[ATHOS_LUT_CHAN_667750_IDX] = { 26710, 0x1, 0x6F, 0x95555, 0x8B2 },
+	[ATHOS_LUT_CHAN_667875_IDX] = { 26715, 0x1, 0x6F, 0xA0000, 0x8B2 },
+	[ATHOS_LUT_CHAN_668000_IDX] = { 26720, 0x1, 0x6F, 0xAAAAB, 0x8B3 },
+	[ATHOS_LUT_CHAN_668125_IDX] = { 26725, 0x1, 0x6F, 0xB5555, 0x8B3 },
+	[ATHOS_LUT_CHAN_668250_IDX] = { 26730, 0x1, 0x6F, 0xC0000, 0x8B4 },
+	[ATHOS_LUT_CHAN_668375_IDX] = { 26735, 0x1, 0x6F, 0xCAAAB, 0x8B4 },
+	[ATHOS_LUT_CHAN_668500_IDX] = { 26740, 0x1, 0x6F, 0xD5555, 0x8B4 },
+	[ATHOS_LUT_CHAN_668625_IDX] = { 26745, 0x1, 0x6F, 0xE0000, 0x8B5 },
+	[ATHOS_LUT_CHAN_668750_IDX] = { 26750, 0x1, 0x6F, 0xEAAAB, 0x8B5 },
+	[ATHOS_LUT_CHAN_668875_IDX] = { 26755, 0x1, 0x6F, 0xF5555, 0x8B6 },
+	[ATHOS_LUT_CHAN_669000_IDX] = { 26760, 0x1, 0x6F, 0x100000, 0x8B6 },
+	[ATHOS_LUT_CHAN_669125_IDX] = { 26765, 0x1, 0x6F, 0x10AAAB, 0x8B6 },
+	[ATHOS_LUT_CHAN_669250_IDX] = { 26770, 0x1, 0x6F, 0x115555, 0x8B7 },
+	[ATHOS_LUT_CHAN_669375_IDX] = { 26775, 0x1, 0x6F, 0x120000, 0x8B7 },
+	[ATHOS_LUT_CHAN_669500_IDX] = { 26780, 0x1, 0x6F, 0x12AAAB, 0x8B8 },
+	[ATHOS_LUT_CHAN_669625_IDX] = { 26785, 0x1, 0x6F, 0x135555, 0x8B8 },
+	[ATHOS_LUT_CHAN_669750_IDX] = { 26790, 0x1, 0x6F, 0x140000, 0x8B9 },
+	[ATHOS_LUT_CHAN_669875_IDX] = { 26795, 0x1, 0x6F, 0x14AAAB, 0x8B9 },
+	[ATHOS_LUT_CHAN_670000_IDX] = { 26800, 0x1, 0x6F, 0x155555, 0x8B9 },
+	[ATHOS_LUT_CHAN_670125_IDX] = { 26805, 0x1, 0x6F, 0x160000, 0x8BA },
+	[ATHOS_LUT_CHAN_670250_IDX] = { 26810, 0x1, 0x6F, 0x16AAAB, 0x8BA },
+	[ATHOS_LUT_CHAN_670375_IDX] = { 26815, 0x1, 0x6F, 0x175555, 0x8BB },
+	[ATHOS_LUT_CHAN_670500_IDX] = { 26820, 0x1, 0x6F, 0x180000, 0x8BB },
+	[ATHOS_LUT_CHAN_670625_IDX] = { 26825, 0x1, 0x6F, 0x18AAAB, 0x8BB },
+	[ATHOS_LUT_CHAN_670750_IDX] = { 26830, 0x1, 0x6F, 0x195555, 0x8BC },
+	[ATHOS_LUT_CHAN_670875_IDX] = { 26835, 0x1, 0x6F, 0x1A0000, 0x8BC },
+	[ATHOS_LUT_CHAN_671000_IDX] = { 26840, 0x1, 0x6F, 0x1AAAAB, 0x8BD },
+	[ATHOS_LUT_CHAN_671125_IDX] = { 26845, 0x1, 0x6F, 0x1B5555, 0x8BD },
+	[ATHOS_LUT_CHAN_671250_IDX] = { 26850, 0x1, 0x6F, 0x1C0000, 0x8BE },
+	[ATHOS_LUT_CHAN_671375_IDX] = { 26855, 0x1, 0x6F, 0x1CAAAB, 0x8BE },
+	[ATHOS_LUT_CHAN_671500_IDX] = { 26860, 0x1, 0x6F, 0x1D5555, 0x8BE },
+	[ATHOS_LUT_CHAN_671625_IDX] = { 26865, 0x1, 0x6F, 0x1E0000, 0x8BF },
+	[ATHOS_LUT_CHAN_671750_IDX] = { 26870, 0x1, 0x6F, 0x1EAAAB, 0x8BF },
+	[ATHOS_LUT_CHAN_671875_IDX] = { 26875, 0x1, 0x6F, 0x1F5555, 0x8C0 },
+	[ATHOS_LUT_CHAN_672000_IDX] = { 26880, 0x1, 0x70, 0x0, 0x8C0 },
+	[ATHOS_LUT_CHAN_672125_IDX] = { 26885, 0x1, 0x70, 0xAAAB, 0x8C0 },
+	[ATHOS_LUT_CHAN_672250_IDX] = { 26890, 0x1, 0x70, 0x15555, 0x8C1 },
+	[ATHOS_LUT_CHAN_672375_IDX] = { 26895, 0x1, 0x70, 0x20000, 0x8C1 },
+	[ATHOS_LUT_CHAN_672500_IDX] = { 26900, 0x1, 0x70, 0x2AAAB, 0x8C2 },
+	[ATHOS_LUT_CHAN_672625_IDX] = { 26905, 0x1, 0x70, 0x35555, 0x8C2 },
+	[ATHOS_LUT_CHAN_672750_IDX] = { 26910, 0x1, 0x70, 0x40000, 0x8C3 },
+	[ATHOS_LUT_CHAN_672875_IDX] = { 26915, 0x1, 0x70, 0x4AAAB, 0x8C3 },
+	[ATHOS_LUT_CHAN_673000_IDX] = { 26920, 0x1, 0x70, 0x55555, 0x8C3 },
+	[ATHOS_LUT_CHAN_673125_IDX] = { 26925, 0x1, 0x70, 0x60000, 0x8C4 },
+	[ATHOS_LUT_CHAN_673250_IDX] = { 26930, 0x1, 0x70, 0x6AAAB, 0x8C4 },
+	[ATHOS_LUT_CHAN_673375_IDX] = { 26935, 0x1, 0x70, 0x75555, 0x8C5 },
+	[ATHOS_LUT_CHAN_673500_IDX] = { 26940, 0x1, 0x70, 0x80000, 0x8C5 },
+	[ATHOS_LUT_CHAN_673625_IDX] = { 26945, 0x1, 0x70, 0x8AAAB, 0x8C5 },
+	[ATHOS_LUT_CHAN_673750_IDX] = { 26950, 0x1, 0x70, 0x95555, 0x8C6 },
+	[ATHOS_LUT_CHAN_673875_IDX] = { 26955, 0x1, 0x70, 0xA0000, 0x8C6 },
+	[ATHOS_LUT_CHAN_674000_IDX] = { 26960, 0x1, 0x70, 0xAAAAB, 0x8C7 },
+	[ATHOS_LUT_CHAN_674125_IDX] = { 26965, 0x1, 0x70, 0xB5555, 0x8C7 },
+	[ATHOS_LUT_CHAN_674250_IDX] = { 26970, 0x1, 0x70, 0xC0000, 0x8C8 },
+	[ATHOS_LUT_CHAN_674375_IDX] = { 26975, 0x1, 0x70, 0xCAAAB, 0x8C8 },
+	[ATHOS_LUT_CHAN_674500_IDX] = { 26980, 0x1, 0x70, 0xD5555, 0x8C8 },
+	[ATHOS_LUT_CHAN_674625_IDX] = { 26985, 0x1, 0x70, 0xE0000, 0x8C9 },
+	[ATHOS_LUT_CHAN_674750_IDX] = { 26990, 0x1, 0x70, 0xEAAAB, 0x8C9 },
+	[ATHOS_LUT_CHAN_674875_IDX] = { 26995, 0x1, 0x70, 0xF5555, 0x8CA },
+	[ATHOS_LUT_CHAN_675000_IDX] = { 27000, 0x1, 0x70, 0x100000, 0x8CA },
+	[ATHOS_LUT_CHAN_675125_IDX] = { 27005, 0x1, 0x70, 0x10AAAB, 0x8CA },
+	[ATHOS_LUT_CHAN_675250_IDX] = { 27010, 0x1, 0x70, 0x115555, 0x8CB },
+	[ATHOS_LUT_CHAN_675375_IDX] = { 27015, 0x1, 0x70, 0x120000, 0x8CB },
+	[ATHOS_LUT_CHAN_675500_IDX] = { 27020, 0x1, 0x70, 0x12AAAB, 0x8CC },
+	[ATHOS_LUT_CHAN_675625_IDX] = { 27025, 0x1, 0x70, 0x135555, 0x8CC },
+	[ATHOS_LUT_CHAN_675750_IDX] = { 27030, 0x1, 0x70, 0x140000, 0x8CD },
+	[ATHOS_LUT_CHAN_675875_IDX] = { 27035, 0x1, 0x70, 0x14AAAB, 0x8CD },
+	[ATHOS_LUT_CHAN_676000_IDX] = { 27040, 0x1, 0x70, 0x155555, 0x8CD },
+	[ATHOS_LUT_CHAN_676125_IDX] = { 27045, 0x1, 0x70, 0x160000, 0x8CE },
+	[ATHOS_LUT_CHAN_676250_IDX] = { 27050, 0x1, 0x70, 0x16AAAB, 0x8CE },
+	[ATHOS_LUT_CHAN_676375_IDX] = { 27055, 0x1, 0x70, 0x175555, 0x8CF },
+	[ATHOS_LUT_CHAN_676500_IDX] = { 27060, 0x1, 0x70, 0x180000, 0x8CF },
+	[ATHOS_LUT_CHAN_676625_IDX] = { 27065, 0x1, 0x70, 0x18AAAB, 0x8CF },
+	[ATHOS_LUT_CHAN_676750_IDX] = { 27070, 0x1, 0x70, 0x195555, 0x8D0 },
+	[ATHOS_LUT_CHAN_676875_IDX] = { 27075, 0x1, 0x70, 0x1A0000, 0x8D0 },
+	[ATHOS_LUT_CHAN_677000_IDX] = { 27080, 0x1, 0x70, 0x1AAAAB, 0x8D1 },
+	[ATHOS_LUT_CHAN_677125_IDX] = { 27085, 0x1, 0x70, 0x1B5555, 0x8D1 },
+	[ATHOS_LUT_CHAN_677250_IDX] = { 27090, 0x1, 0x70, 0x1C0000, 0x8D2 },
+	[ATHOS_LUT_CHAN_677375_IDX] = { 27095, 0x1, 0x70, 0x1CAAAB, 0x8D2 },
+	[ATHOS_LUT_CHAN_677500_IDX] = { 27100, 0x1, 0x70, 0x1D5555, 0x8D2 },
+	[ATHOS_LUT_CHAN_677625_IDX] = { 27105, 0x1, 0x70, 0x1E0000, 0x8D3 },
+	[ATHOS_LUT_CHAN_677750_IDX] = { 27110, 0x1, 0x70, 0x1EAAAB, 0x8D3 },
+	[ATHOS_LUT_CHAN_677875_IDX] = { 27115, 0x1, 0x70, 0x1F5555, 0x8D4 },
+	[ATHOS_LUT_CHAN_678000_IDX] = { 27120, 0x1, 0x71, 0x0, 0x8D4 },
+	[ATHOS_LUT_CHAN_678125_IDX] = { 27125, 0x1, 0x71, 0xAAAB, 0x8D4 },
+	[ATHOS_LUT_CHAN_678250_IDX] = { 27130, 0x1, 0x71, 0x15555, 0x8D5 },
+	[ATHOS_LUT_CHAN_678375_IDX] = { 27135, 0x1, 0x71, 0x20000, 0x8D5 },
+	[ATHOS_LUT_CHAN_678500_IDX] = { 27140, 0x1, 0x71, 0x2AAAB, 0x8D6 },
+	[ATHOS_LUT_CHAN_678625_IDX] = { 27145, 0x1, 0x71, 0x35555, 0x8D6 },
+	[ATHOS_LUT_CHAN_678750_IDX] = { 27150, 0x1, 0x71, 0x40000, 0x8D7 },
+	[ATHOS_LUT_CHAN_678875_IDX] = { 27155, 0x1, 0x71, 0x4AAAB, 0x8D7 },
+	[ATHOS_LUT_CHAN_679000_IDX] = { 27160, 0x1, 0x71, 0x55555, 0x8D7 },
+	[ATHOS_LUT_CHAN_679125_IDX] = { 27165, 0x1, 0x71, 0x60000, 0x8D8 },
+	[ATHOS_LUT_CHAN_679250_IDX] = { 27170, 0x1, 0x71, 0x6AAAB, 0x8D8 },
+	[ATHOS_LUT_CHAN_679375_IDX] = { 27175, 0x1, 0x71, 0x75555, 0x8D9 },
+	[ATHOS_LUT_CHAN_679500_IDX] = { 27180, 0x1, 0x71, 0x80000, 0x8D9 },
+	[ATHOS_LUT_CHAN_679625_IDX] = { 27185, 0x1, 0x71, 0x8AAAB, 0x8D9 },
+	[ATHOS_LUT_CHAN_679750_IDX] = { 27190, 0x1, 0x71, 0x95555, 0x8DA },
+	[ATHOS_LUT_CHAN_679875_IDX] = { 27195, 0x1, 0x71, 0xA0000, 0x8DA },
+	[ATHOS_LUT_CHAN_680000_IDX] = { 27200, 0x1, 0x71, 0xAAAAB, 0x8DB },
+	[ATHOS_LUT_CHAN_680125_IDX] = { 27205, 0x1, 0x71, 0xB5555, 0x8DB },
+	[ATHOS_LUT_CHAN_680250_IDX] = { 27210, 0x1, 0x71, 0xC0000, 0x8DC },
+	[ATHOS_LUT_CHAN_680375_IDX] = { 27215, 0x1, 0x71, 0xCAAAB, 0x8DC },
+	[ATHOS_LUT_CHAN_680500_IDX] = { 27220, 0x1, 0x71, 0xD5555, 0x8DC },
+	[ATHOS_LUT_CHAN_680625_IDX] = { 27225, 0x1, 0x71, 0xE0000, 0x8DD },
+	[ATHOS_LUT_CHAN_680750_IDX] = { 27230, 0x1, 0x71, 0xEAAAB, 0x8DD },
+	[ATHOS_LUT_CHAN_680875_IDX] = { 27235, 0x1, 0x71, 0xF5555, 0x8DE },
+	[ATHOS_LUT_CHAN_681000_IDX] = { 27240, 0x1, 0x71, 0x100000, 0x8DE },
+	[ATHOS_LUT_CHAN_681125_IDX] = { 27245, 0x1, 0x71, 0x10AAAB, 0x8DE },
+	[ATHOS_LUT_CHAN_681250_IDX] = { 27250, 0x1, 0x71, 0x115555, 0x8DF },
+	[ATHOS_LUT_CHAN_681375_IDX] = { 27255, 0x1, 0x71, 0x120000, 0x8DF },
+	[ATHOS_LUT_CHAN_681500_IDX] = { 27260, 0x1, 0x71, 0x12AAAB, 0x8E0 },
+	[ATHOS_LUT_CHAN_681625_IDX] = { 27265, 0x1, 0x71, 0x135555, 0x8E0 },
+	[ATHOS_LUT_CHAN_681750_IDX] = { 27270, 0x1, 0x71, 0x140000, 0x8E1 },
+	[ATHOS_LUT_CHAN_681875_IDX] = { 27275, 0x1, 0x71, 0x14AAAB, 0x8E1 },
+	[ATHOS_LUT_CHAN_682000_IDX] = { 27280, 0x1, 0x71, 0x155555, 0x8E1 },
+	[ATHOS_LUT_CHAN_682125_IDX] = { 27285, 0x1, 0x71, 0x160000, 0x8E2 },
+	[ATHOS_LUT_CHAN_682250_IDX] = { 27290, 0x1, 0x71, 0x16AAAB, 0x8E2 },
+	[ATHOS_LUT_CHAN_682375_IDX] = { 27295, 0x1, 0x71, 0x175555, 0x8E3 },
+	[ATHOS_LUT_CHAN_682500_IDX] = { 27300, 0x1, 0x71, 0x180000, 0x8E3 },
+	[ATHOS_LUT_CHAN_682625_IDX] = { 27305, 0x1, 0x71, 0x18AAAB, 0x8E3 },
+	[ATHOS_LUT_CHAN_682750_IDX] = { 27310, 0x1, 0x71, 0x195555, 0x8E4 },
+	[ATHOS_LUT_CHAN_682875_IDX] = { 27315, 0x1, 0x71, 0x1A0000, 0x8E4 },
+	[ATHOS_LUT_CHAN_683000_IDX] = { 27320, 0x1, 0x71, 0x1AAAAB, 0x8E5 },
+	[ATHOS_LUT_CHAN_683125_IDX] = { 27325, 0x1, 0x71, 0x1B5555, 0x8E5 },
+	[ATHOS_LUT_CHAN_683250_IDX] = { 27330, 0x1, 0x71, 0x1C0000, 0x8E6 },
+	[ATHOS_LUT_CHAN_683375_IDX] = { 27335, 0x1, 0x71, 0x1CAAAB, 0x8E6 },
+	[ATHOS_LUT_CHAN_683500_IDX] = { 27340, 0x1, 0x71, 0x1D5555, 0x8E6 },
+	[ATHOS_LUT_CHAN_683625_IDX] = { 27345, 0x1, 0x71, 0x1E0000, 0x8E7 },
+	[ATHOS_LUT_CHAN_683750_IDX] = { 27350, 0x1, 0x71, 0x1EAAAB, 0x8E7 },
+	[ATHOS_LUT_CHAN_683875_IDX] = { 27355, 0x1, 0x71, 0x1F5555, 0x8E8 },
+	[ATHOS_LUT_CHAN_684000_IDX] = { 27360, 0x1, 0x72, 0x0, 0x8E8 },
+	[ATHOS_LUT_CHAN_684125_IDX] = { 27365, 0x1, 0x72, 0xAAAB, 0x8E8 },
+	[ATHOS_LUT_CHAN_684250_IDX] = { 27370, 0x1, 0x72, 0x15555, 0x8E9 },
+	[ATHOS_LUT_CHAN_684375_IDX] = { 27375, 0x1, 0x72, 0x20000, 0x8E9 },
+	[ATHOS_LUT_CHAN_684500_IDX] = { 27380, 0x1, 0x72, 0x2AAAB, 0x8EA },
+	[ATHOS_LUT_CHAN_684625_IDX] = { 27385, 0x1, 0x72, 0x35555, 0x8EA },
+	[ATHOS_LUT_CHAN_684750_IDX] = { 27390, 0x1, 0x72, 0x40000, 0x8EB },
+	[ATHOS_LUT_CHAN_684875_IDX] = { 27395, 0x1, 0x72, 0x4AAAB, 0x8EB },
+	[ATHOS_LUT_CHAN_685000_IDX] = { 27400, 0x1, 0x72, 0x55555, 0x8EB },
+	[ATHOS_LUT_CHAN_685125_IDX] = { 27405, 0x1, 0x72, 0x60000, 0x8EC },
+	[ATHOS_LUT_CHAN_685250_IDX] = { 27410, 0x1, 0x72, 0x6AAAB, 0x8EC },
+	[ATHOS_LUT_CHAN_685375_IDX] = { 27415, 0x1, 0x72, 0x75555, 0x8ED },
+	[ATHOS_LUT_CHAN_685500_IDX] = { 27420, 0x1, 0x72, 0x80000, 0x8ED },
+	[ATHOS_LUT_CHAN_685625_IDX] = { 27425, 0x1, 0x72, 0x8AAAB, 0x8ED },
+	[ATHOS_LUT_CHAN_685750_IDX] = { 27430, 0x1, 0x72, 0x95555, 0x8EE },
+	[ATHOS_LUT_CHAN_685875_IDX] = { 27435, 0x1, 0x72, 0xA0000, 0x8EE },
+	[ATHOS_LUT_CHAN_686000_IDX] = { 27440, 0x1, 0x72, 0xAAAAB, 0x8EF },
+	[ATHOS_LUT_CHAN_686125_IDX] = { 27445, 0x1, 0x72, 0xB5555, 0x8EF },
+	[ATHOS_LUT_CHAN_686250_IDX] = { 27450, 0x1, 0x72, 0xC0000, 0x8F0 },
+	[ATHOS_LUT_CHAN_686375_IDX] = { 27455, 0x1, 0x72, 0xCAAAB, 0x8F0 },
+	[ATHOS_LUT_CHAN_686500_IDX] = { 27460, 0x1, 0x72, 0xD5555, 0x8F0 },
+	[ATHOS_LUT_CHAN_686625_IDX] = { 27465, 0x1, 0x72, 0xE0000, 0x8F1 },
+	[ATHOS_LUT_CHAN_686750_IDX] = { 27470, 0x1, 0x72, 0xEAAAB, 0x8F1 },
+	[ATHOS_LUT_CHAN_686875_IDX] = { 27475, 0x1, 0x72, 0xF5555, 0x8F2 },
+	[ATHOS_LUT_CHAN_687000_IDX] = { 27480, 0x1, 0x72, 0x100000, 0x8F2 },
+	[ATHOS_LUT_CHAN_687125_IDX] = { 27485, 0x1, 0x72, 0x10AAAB, 0x8F2 },
+	[ATHOS_LUT_CHAN_687250_IDX] = { 27490, 0x1, 0x72, 0x115555, 0x8F3 },
+	[ATHOS_LUT_CHAN_687375_IDX] = { 27495, 0x1, 0x72, 0x120000, 0x8F3 },
+	[ATHOS_LUT_CHAN_687500_IDX] = { 27500, 0x1, 0x72, 0x12AAAB, 0x8F4 },
+	[ATHOS_LUT_CHAN_687625_IDX] = { 27505, 0x1, 0x72, 0x135555, 0x8F4 },
+	[ATHOS_LUT_CHAN_687750_IDX] = { 27510, 0x1, 0x72, 0x140000, 0x8F5 },
+	[ATHOS_LUT_CHAN_687875_IDX] = { 27515, 0x1, 0x72, 0x14AAAB, 0x8F5 },
+	[ATHOS_LUT_CHAN_688000_IDX] = { 27520, 0x1, 0x72, 0x155555, 0x8F5 },
+	[ATHOS_LUT_CHAN_688125_IDX] = { 27525, 0x1, 0x72, 0x160000, 0x8F6 },
+	[ATHOS_LUT_CHAN_688250_IDX] = { 27530, 0x1, 0x72, 0x16AAAB, 0x8F6 },
+	[ATHOS_LUT_CHAN_688375_IDX] = { 27535, 0x1, 0x72, 0x175555, 0x8F7 },
+	[ATHOS_LUT_CHAN_688500_IDX] = { 27540, 0x1, 0x72, 0x180000, 0x8F7 },
+	[ATHOS_LUT_CHAN_688625_IDX] = { 27545, 0x1, 0x72, 0x18AAAB, 0x8F7 },
+	[ATHOS_LUT_CHAN_688750_IDX] = { 27550, 0x1, 0x72, 0x195555, 0x8F8 },
+	[ATHOS_LUT_CHAN_688875_IDX] = { 27555, 0x1, 0x72, 0x1A0000, 0x8F8 },
+	[ATHOS_LUT_CHAN_689000_IDX] = { 27560, 0x1, 0x72, 0x1AAAAB, 0x8F9 },
+	[ATHOS_LUT_CHAN_689125_IDX] = { 27565, 0x1, 0x72, 0x1B5555, 0x8F9 },
+	[ATHOS_LUT_CHAN_689250_IDX] = { 27570, 0x1, 0x72, 0x1C0000, 0x8FA },
+	[ATHOS_LUT_CHAN_689375_IDX] = { 27575, 0x1, 0x72, 0x1CAAAB, 0x8FA },
+	[ATHOS_LUT_CHAN_689500_IDX] = { 27580, 0x1, 0x72, 0x1D5555, 0x8FA },
+	[ATHOS_LUT_CHAN_689625_IDX] = { 27585, 0x1, 0x72, 0x1E0000, 0x8FB },
+	[ATHOS_LUT_CHAN_689750_IDX] = { 27590, 0x1, 0x72, 0x1EAAAB, 0x8FB },
+	[ATHOS_LUT_CHAN_689875_IDX] = { 27595, 0x1, 0x72, 0x1F5555, 0x8FC },
+	[ATHOS_LUT_CHAN_690000_IDX] = { 27600, 0x1, 0x73, 0x0, 0x8FC },
+	[ATHOS_LUT_CHAN_690125_IDX] = { 27605, 0x1, 0x73, 0xAAAB, 0x8FC },
+	[ATHOS_LUT_CHAN_690250_IDX] = { 27610, 0x1, 0x73, 0x15555, 0x8FD },
+	[ATHOS_LUT_CHAN_690375_IDX] = { 27615, 0x1, 0x73, 0x20000, 0x8FD },
+	[ATHOS_LUT_CHAN_690500_IDX] = { 27620, 0x1, 0x73, 0x2AAAB, 0x8FE },
+	[ATHOS_LUT_CHAN_690625_IDX] = { 27625, 0x1, 0x73, 0x35555, 0x8FE },
+	[ATHOS_LUT_CHAN_690750_IDX] = { 27630, 0x1, 0x73, 0x40000, 0x8FF },
+	[ATHOS_LUT_CHAN_690875_IDX] = { 27635, 0x1, 0x73, 0x4AAAB, 0x8FF },
+	[ATHOS_LUT_CHAN_691000_IDX] = { 27640, 0x1, 0x73, 0x55555, 0x8FF },
+	[ATHOS_LUT_CHAN_691125_IDX] = { 27645, 0x1, 0x73, 0x60000, 0x900 },
+	[ATHOS_LUT_CHAN_691250_IDX] = { 27650, 0x1, 0x73, 0x6AAAB, 0x900 },
+	[ATHOS_LUT_CHAN_691375_IDX] = { 27655, 0x1, 0x73, 0x75555, 0x901 },
+	[ATHOS_LUT_CHAN_691500_IDX] = { 27660, 0x1, 0x73, 0x80000, 0x901 },
+	[ATHOS_LUT_CHAN_691625_IDX] = { 27665, 0x1, 0x73, 0x8AAAB, 0x901 },
+	[ATHOS_LUT_CHAN_691750_IDX] = { 27670, 0x1, 0x73, 0x95555, 0x902 },
+	[ATHOS_LUT_CHAN_691875_IDX] = { 27675, 0x1, 0x73, 0xA0000, 0x902 },
+	[ATHOS_LUT_CHAN_692000_IDX] = { 27680, 0x1, 0x73, 0xAAAAB, 0x903 },
+	[ATHOS_LUT_CHAN_692125_IDX] = { 27685, 0x1, 0x73, 0xB5555, 0x903 },
+	[ATHOS_LUT_CHAN_692250_IDX] = { 27690, 0x1, 0x73, 0xC0000, 0x904 },
+	[ATHOS_LUT_CHAN_692375_IDX] = { 27695, 0x1, 0x73, 0xCAAAB, 0x904 },
+	[ATHOS_LUT_CHAN_692500_IDX] = { 27700, 0x1, 0x73, 0xD5555, 0x904 },
+	[ATHOS_LUT_CHAN_692625_IDX] = { 27705, 0x1, 0x73, 0xE0000, 0x905 },
+	[ATHOS_LUT_CHAN_692750_IDX] = { 27710, 0x1, 0x73, 0xEAAAB, 0x905 },
+	[ATHOS_LUT_CHAN_692875_IDX] = { 27715, 0x1, 0x73, 0xF5555, 0x906 },
+	[ATHOS_LUT_CHAN_693000_IDX] = { 27720, 0x1, 0x73, 0x100000, 0x906 },
+	[ATHOS_LUT_CHAN_693125_IDX] = { 27725, 0x1, 0x73, 0x10AAAB, 0x906 },
+	[ATHOS_LUT_CHAN_693250_IDX] = { 27730, 0x1, 0x73, 0x115555, 0x907 },
+	[ATHOS_LUT_CHAN_693375_IDX] = { 27735, 0x1, 0x73, 0x120000, 0x907 },
+	[ATHOS_LUT_CHAN_693500_IDX] = { 27740, 0x1, 0x73, 0x12AAAB, 0x908 },
+	[ATHOS_LUT_CHAN_693625_IDX] = { 27745, 0x1, 0x73, 0x135555, 0x908 },
+	[ATHOS_LUT_CHAN_693750_IDX] = { 27750, 0x1, 0x73, 0x140000, 0x909 },
+	[ATHOS_LUT_CHAN_693875_IDX] = { 27755, 0x1, 0x73, 0x14AAAB, 0x909 },
+	[ATHOS_LUT_CHAN_694000_IDX] = { 27760, 0x1, 0x73, 0x155555, 0x909 },
+	[ATHOS_LUT_CHAN_694125_IDX] = { 27765, 0x1, 0x73, 0x160000, 0x90A },
+	[ATHOS_LUT_CHAN_694250_IDX] = { 27770, 0x1, 0x73, 0x16AAAB, 0x90A },
+	[ATHOS_LUT_CHAN_694375_IDX] = { 27775, 0x1, 0x73, 0x175555, 0x90B },
+	[ATHOS_LUT_CHAN_694500_IDX] = { 27780, 0x1, 0x73, 0x180000, 0x90B },
+	[ATHOS_LUT_CHAN_694625_IDX] = { 27785, 0x1, 0x73, 0x18AAAB, 0x90B },
+	[ATHOS_LUT_CHAN_694750_IDX] = { 27790, 0x1, 0x73, 0x195555, 0x90C },
+	[ATHOS_LUT_CHAN_694875_IDX] = { 27795, 0x1, 0x73, 0x1A0000, 0x90C },
+	[ATHOS_LUT_CHAN_695000_IDX] = { 27800, 0x1, 0x73, 0x1AAAAB, 0x90D },
+	[ATHOS_LUT_CHAN_695125_IDX] = { 27805, 0x1, 0x73, 0x1B5555, 0x90D },
+	[ATHOS_LUT_CHAN_695250_IDX] = { 27810, 0x1, 0x73, 0x1C0000, 0x90E },
+	[ATHOS_LUT_CHAN_695375_IDX] = { 27815, 0x1, 0x73, 0x1CAAAB, 0x90E },
+	[ATHOS_LUT_CHAN_695500_IDX] = { 27820, 0x1, 0x73, 0x1D5555, 0x90E },
+	[ATHOS_LUT_CHAN_695625_IDX] = { 27825, 0x1, 0x73, 0x1E0000, 0x90F },
+	[ATHOS_LUT_CHAN_695750_IDX] = { 27830, 0x1, 0x73, 0x1EAAAB, 0x90F },
+	[ATHOS_LUT_CHAN_695875_IDX] = { 27835, 0x1, 0x73, 0x1F5555, 0x910 },
+	[ATHOS_LUT_CHAN_696000_IDX] = { 27840, 0x1, 0x74, 0x0, 0x910 },
+	[ATHOS_LUT_CHAN_696125_IDX] = { 27845, 0x1, 0x74, 0xAAAB, 0x910 },
+	[ATHOS_LUT_CHAN_696250_IDX] = { 27850, 0x1, 0x74, 0x15555, 0x911 },
+	[ATHOS_LUT_CHAN_696375_IDX] = { 27855, 0x1, 0x74, 0x20000, 0x911 },
+	[ATHOS_LUT_CHAN_696500_IDX] = { 27860, 0x1, 0x74, 0x2AAAB, 0x912 },
+	[ATHOS_LUT_CHAN_696625_IDX] = { 27865, 0x1, 0x74, 0x35555, 0x912 },
+	[ATHOS_LUT_CHAN_696750_IDX] = { 27870, 0x1, 0x74, 0x40000, 0x913 },
+	[ATHOS_LUT_CHAN_696875_IDX] = { 27875, 0x1, 0x74, 0x4AAAB, 0x913 },
+	[ATHOS_LUT_CHAN_697000_IDX] = { 27880, 0x1, 0x74, 0x55555, 0x913 },
+	[ATHOS_LUT_CHAN_697125_IDX] = { 27885, 0x1, 0x74, 0x60000, 0x914 },
+	[ATHOS_LUT_CHAN_697250_IDX] = { 27890, 0x1, 0x74, 0x6AAAB, 0x914 },
+	[ATHOS_LUT_CHAN_697375_IDX] = { 27895, 0x1, 0x74, 0x75555, 0x915 },
+	[ATHOS_LUT_CHAN_697500_IDX] = { 27900, 0x1, 0x74, 0x80000, 0x915 },
+	[ATHOS_LUT_CHAN_697625_IDX] = { 27905, 0x1, 0x74, 0x8AAAB, 0x915 },
+	[ATHOS_LUT_CHAN_697750_IDX] = { 27910, 0x1, 0x74, 0x95555, 0x916 },
+	[ATHOS_LUT_CHAN_697875_IDX] = { 27915, 0x1, 0x74, 0xA0000, 0x916 },
+	[ATHOS_LUT_CHAN_698000_IDX] = { 27920, 0x1, 0x74, 0xAAAAB, 0x917 },
+	[ATHOS_LUT_CHAN_698125_IDX] = { 27925, 0x1, 0x74, 0xB5555, 0x917 },
+	[ATHOS_LUT_CHAN_698250_IDX] = { 27930, 0x1, 0x74, 0xC0000, 0x918 },
+	[ATHOS_LUT_CHAN_698375_IDX] = { 27935, 0x1, 0x74, 0xCAAAB, 0x918 },
+	[ATHOS_LUT_CHAN_698500_IDX] = { 27940, 0x1, 0x74, 0xD5555, 0x918 },
+	[ATHOS_LUT_CHAN_698625_IDX] = { 27945, 0x1, 0x74, 0xE0000, 0x919 },
+	[ATHOS_LUT_CHAN_698750_IDX] = { 27950, 0x1, 0x74, 0xEAAAB, 0x919 },
+	[ATHOS_LUT_CHAN_698875_IDX] = { 27955, 0x1, 0x74, 0xF5555, 0x91A },
+	[ATHOS_LUT_CHAN_699000_IDX] = { 27960, 0x1, 0x74, 0x100000, 0x91A },
+	[ATHOS_LUT_CHAN_699125_IDX] = { 27965, 0x1, 0x74, 0x10AAAB, 0x91A },
+	[ATHOS_LUT_CHAN_699250_IDX] = { 27970, 0x1, 0x74, 0x115555, 0x91B },
+	[ATHOS_LUT_CHAN_699375_IDX] = { 27975, 0x1, 0x74, 0x120000, 0x91B },
+	[ATHOS_LUT_CHAN_699500_IDX] = { 27980, 0x1, 0x74, 0x12AAAB, 0x91C },
+	[ATHOS_LUT_CHAN_699625_IDX] = { 27985, 0x1, 0x74, 0x135555, 0x91C },
+	[ATHOS_LUT_CHAN_699750_IDX] = { 27990, 0x1, 0x74, 0x140000, 0x91D },
+	[ATHOS_LUT_CHAN_699875_IDX] = { 27995, 0x1, 0x74, 0x14AAAB, 0x91D },
+	[ATHOS_LUT_CHAN_700000_IDX] = { 28000, 0x1, 0x74, 0x155555, 0x91D },
+	[ATHOS_LUT_CHAN_700125_IDX] = { 28005, 0x1, 0x74, 0x160000, 0x91E },
+	[ATHOS_LUT_CHAN_700250_IDX] = { 28010, 0x1, 0x74, 0x16AAAB, 0x91E },
+	[ATHOS_LUT_CHAN_700375_IDX] = { 28015, 0x1, 0x74, 0x175555, 0x91F },
+	[ATHOS_LUT_CHAN_700500_IDX] = { 28020, 0x1, 0x74, 0x180000, 0x91F },
+	[ATHOS_LUT_CHAN_700625_IDX] = { 28025, 0x1, 0x74, 0x18AAAB, 0x91F },
+	[ATHOS_LUT_CHAN_700750_IDX] = { 28030, 0x1, 0x74, 0x195555, 0x920 },
+	[ATHOS_LUT_CHAN_700875_IDX] = { 28035, 0x1, 0x74, 0x1A0000, 0x920 },
+	[ATHOS_LUT_CHAN_701000_IDX] = { 28040, 0x1, 0x74, 0x1AAAAB, 0x921 },
+	[ATHOS_LUT_CHAN_701125_IDX] = { 28045, 0x1, 0x74, 0x1B5555, 0x921 },
+	[ATHOS_LUT_CHAN_701250_IDX] = { 28050, 0x1, 0x74, 0x1C0000, 0x922 },
+	[ATHOS_LUT_CHAN_701375_IDX] = { 28055, 0x1, 0x74, 0x1CAAAB, 0x922 },
+	[ATHOS_LUT_CHAN_701500_IDX] = { 28060, 0x1, 0x74, 0x1D5555, 0x922 },
+	[ATHOS_LUT_CHAN_701625_IDX] = { 28065, 0x1, 0x74, 0x1E0000, 0x923 },
+	[ATHOS_LUT_CHAN_701750_IDX] = { 28070, 0x1, 0x74, 0x1EAAAB, 0x923 },
+	[ATHOS_LUT_CHAN_701875_IDX] = { 28075, 0x1, 0x74, 0x1F5555, 0x924 },
+	[ATHOS_LUT_CHAN_702000_IDX] = { 28080, 0x1, 0x75, 0x0, 0x924 },
+	[ATHOS_LUT_CHAN_702125_IDX] = { 28085, 0x1, 0x75, 0xAAAB, 0x924 },
+	[ATHOS_LUT_CHAN_702250_IDX] = { 28090, 0x1, 0x75, 0x15555, 0x925 },
+	[ATHOS_LUT_CHAN_702375_IDX] = { 28095, 0x1, 0x75, 0x20000, 0x925 },
+	[ATHOS_LUT_CHAN_702500_IDX] = { 28100, 0x1, 0x75, 0x2AAAB, 0x926 },
+	[ATHOS_LUT_CHAN_702625_IDX] = { 28105, 0x1, 0x75, 0x35555, 0x926 },
+	[ATHOS_LUT_CHAN_702750_IDX] = { 28110, 0x1, 0x75, 0x40000, 0x927 },
+	[ATHOS_LUT_CHAN_702875_IDX] = { 28115, 0x1, 0x75, 0x4AAAB, 0x927 },
+	[ATHOS_LUT_CHAN_703000_IDX] = { 28120, 0x1, 0x75, 0x55555, 0x927 },
+	[ATHOS_LUT_CHAN_703125_IDX] = { 28125, 0x1, 0x75, 0x60000, 0x928 },
+	[ATHOS_LUT_CHAN_703250_IDX] = { 28130, 0x1, 0x75, 0x6AAAB, 0x928 },
+	[ATHOS_LUT_CHAN_703375_IDX] = { 28135, 0x1, 0x75, 0x75555, 0x929 },
+	[ATHOS_LUT_CHAN_703500_IDX] = { 28140, 0x1, 0x75, 0x80000, 0x929 },
+	[ATHOS_LUT_CHAN_703625_IDX] = { 28145, 0x1, 0x75, 0x8AAAB, 0x929 },
+	[ATHOS_LUT_CHAN_703750_IDX] = { 28150, 0x1, 0x75, 0x95555, 0x92A },
+	[ATHOS_LUT_CHAN_703875_IDX] = { 28155, 0x1, 0x75, 0xA0000, 0x92A },
+	[ATHOS_LUT_CHAN_704000_IDX] = { 28160, 0x1, 0x75, 0xAAAAB, 0x92B },
+	[ATHOS_LUT_CHAN_704125_IDX] = { 28165, 0x1, 0x75, 0xB5555, 0x92B },
+	[ATHOS_LUT_CHAN_704250_IDX] = { 28170, 0x1, 0x75, 0xC0000, 0x92C },
+	[ATHOS_LUT_CHAN_704375_IDX] = { 28175, 0x1, 0x75, 0xCAAAB, 0x92C },
+	[ATHOS_LUT_CHAN_704500_IDX] = { 28180, 0x1, 0x75, 0xD5555, 0x92C },
+	[ATHOS_LUT_CHAN_704625_IDX] = { 28185, 0x1, 0x75, 0xE0000, 0x92D },
+	[ATHOS_LUT_CHAN_704750_IDX] = { 28190, 0x1, 0x75, 0xEAAAB, 0x92D },
+	[ATHOS_LUT_CHAN_704875_IDX] = { 28195, 0x1, 0x75, 0xF5555, 0x92E },
+	[ATHOS_LUT_CHAN_705000_IDX] = { 28200, 0x1, 0x75, 0x100000, 0x92E },
+	[ATHOS_LUT_CHAN_705125_IDX] = { 28205, 0x1, 0x75, 0x10AAAB, 0x92E },
+	[ATHOS_LUT_CHAN_705250_IDX] = { 28210, 0x1, 0x75, 0x115555, 0x92F },
+	[ATHOS_LUT_CHAN_705375_IDX] = { 28215, 0x1, 0x75, 0x120000, 0x92F },
+	[ATHOS_LUT_CHAN_705500_IDX] = { 28220, 0x1, 0x75, 0x12AAAB, 0x930 },
+	[ATHOS_LUT_CHAN_705625_IDX] = { 28225, 0x1, 0x75, 0x135555, 0x930 },
+	[ATHOS_LUT_CHAN_705750_IDX] = { 28230, 0x1, 0x75, 0x140000, 0x931 },
+	[ATHOS_LUT_CHAN_705875_IDX] = { 28235, 0x1, 0x75, 0x14AAAB, 0x931 },
+	[ATHOS_LUT_CHAN_706000_IDX] = { 28240, 0x1, 0x75, 0x155555, 0x931 },
+	[ATHOS_LUT_CHAN_706125_IDX] = { 28245, 0x1, 0x75, 0x160000, 0x932 },
+	[ATHOS_LUT_CHAN_706250_IDX] = { 28250, 0x1, 0x75, 0x16AAAB, 0x932 },
+	[ATHOS_LUT_CHAN_706375_IDX] = { 28255, 0x1, 0x75, 0x175555, 0x933 },
+	[ATHOS_LUT_CHAN_706500_IDX] = { 28260, 0x1, 0x75, 0x180000, 0x933 },
+	[ATHOS_LUT_CHAN_706625_IDX] = { 28265, 0x1, 0x75, 0x18AAAB, 0x933 },
+	[ATHOS_LUT_CHAN_706750_IDX] = { 28270, 0x1, 0x75, 0x195555, 0x934 },
+	[ATHOS_LUT_CHAN_706875_IDX] = { 28275, 0x1, 0x75, 0x1A0000, 0x934 },
+	[ATHOS_LUT_CHAN_707000_IDX] = { 28280, 0x1, 0x75, 0x1AAAAB, 0x935 },
+	[ATHOS_LUT_CHAN_707125_IDX] = { 28285, 0x1, 0x75, 0x1B5555, 0x935 },
+	[ATHOS_LUT_CHAN_707250_IDX] = { 28290, 0x1, 0x75, 0x1C0000, 0x936 },
+	[ATHOS_LUT_CHAN_707375_IDX] = { 28295, 0x1, 0x75, 0x1CAAAB, 0x936 },
+	[ATHOS_LUT_CHAN_707500_IDX] = { 28300, 0x1, 0x75, 0x1D5555, 0x936 },
+	[ATHOS_LUT_CHAN_707625_IDX] = { 28305, 0x1, 0x75, 0x1E0000, 0x937 },
+	[ATHOS_LUT_CHAN_707750_IDX] = { 28310, 0x1, 0x75, 0x1EAAAB, 0x937 },
+	[ATHOS_LUT_CHAN_707875_IDX] = { 28315, 0x1, 0x75, 0x1F5555, 0x938 },
+	[ATHOS_LUT_CHAN_708000_IDX] = { 28320, 0x1, 0x76, 0x0, 0x938 },
+	[ATHOS_LUT_CHAN_708125_IDX] = { 28325, 0x1, 0x76, 0xAAAB, 0x938 },
+	[ATHOS_LUT_CHAN_708250_IDX] = { 28330, 0x1, 0x76, 0x15555, 0x939 },
+	[ATHOS_LUT_CHAN_708375_IDX] = { 28335, 0x1, 0x76, 0x20000, 0x939 },
+	[ATHOS_LUT_CHAN_708500_IDX] = { 28340, 0x1, 0x76, 0x2AAAB, 0x93A },
+	[ATHOS_LUT_CHAN_708625_IDX] = { 28345, 0x1, 0x76, 0x35555, 0x93A },
+	[ATHOS_LUT_CHAN_708750_IDX] = { 28350, 0x1, 0x76, 0x40000, 0x93B },
+	[ATHOS_LUT_CHAN_708875_IDX] = { 28355, 0x1, 0x76, 0x4AAAB, 0x93B },
+	[ATHOS_LUT_CHAN_709000_IDX] = { 28360, 0x1, 0x76, 0x55555, 0x93B },
+	[ATHOS_LUT_CHAN_709125_IDX] = { 28365, 0x1, 0x76, 0x60000, 0x93C },
+	[ATHOS_LUT_CHAN_709250_IDX] = { 28370, 0x1, 0x76, 0x6AAAB, 0x93C },
+	[ATHOS_LUT_CHAN_709375_IDX] = { 28375, 0x1, 0x76, 0x75555, 0x93D },
+	[ATHOS_LUT_CHAN_709500_IDX] = { 28380, 0x1, 0x76, 0x80000, 0x93D },
+	[ATHOS_LUT_CHAN_709625_IDX] = { 28385, 0x1, 0x76, 0x8AAAB, 0x93D },
+	[ATHOS_LUT_CHAN_709750_IDX] = { 28390, 0x1, 0x76, 0x95555, 0x93E },
+	[ATHOS_LUT_CHAN_709875_IDX] = { 28395, 0x1, 0x76, 0xA0000, 0x93E },
+	[ATHOS_LUT_CHAN_710000_IDX] = { 28400, 0x1, 0x76, 0xAAAAB, 0x93F },
+	[ATHOS_LUT_CHAN_710125_IDX] = { 28405, 0x1, 0x76, 0xB5555, 0x93F },
+	[ATHOS_LUT_CHAN_710250_IDX] = { 28410, 0x1, 0x76, 0xC0000, 0x940 },
+	[ATHOS_LUT_CHAN_710375_IDX] = { 28415, 0x1, 0x76, 0xCAAAB, 0x940 },
+	[ATHOS_LUT_CHAN_710500_IDX] = { 28420, 0x1, 0x76, 0xD5555, 0x940 },
+	[ATHOS_LUT_CHAN_710625_IDX] = { 28425, 0x1, 0x76, 0xE0000, 0x941 },
+	[ATHOS_LUT_CHAN_710750_IDX] = { 28430, 0x1, 0x76, 0xEAAAB, 0x941 },
+	[ATHOS_LUT_CHAN_710875_IDX] = { 28435, 0x1, 0x76, 0xF5555, 0x942 },
+	[ATHOS_LUT_CHAN_711000_IDX] = { 28440, 0x1, 0x76, 0x100000, 0x942 },
+	[ATHOS_LUT_CHAN_711125_IDX] = { 28445, 0x1, 0x76, 0x10AAAB, 0x942 },
+	[ATHOS_LUT_CHAN_711250_IDX] = { 28450, 0x1, 0x76, 0x115555, 0x943 },
+	[ATHOS_LUT_CHAN_711375_IDX] = { 28455, 0x1, 0x76, 0x120000, 0x943 },
+	[ATHOS_LUT_CHAN_711500_IDX] = { 28460, 0x1, 0x76, 0x12AAAB, 0x944 },
+	[ATHOS_LUT_CHAN_711625_IDX] = { 28465, 0x1, 0x76, 0x135555, 0x944 },
+	[ATHOS_LUT_CHAN_711750_IDX] = { 28470, 0x1, 0x76, 0x140000, 0x945 },
+	[ATHOS_LUT_CHAN_711875_IDX] = { 28475, 0x1, 0x76, 0x14AAAB, 0x945 },
+	[ATHOS_LUT_CHAN_712000_IDX] = { 28480, 0x1, 0x76, 0x155555, 0x945 },
+	[ATHOS_LUT_CHAN_712125_IDX] = { 28485, 0x1, 0x76, 0x160000, 0x946 },
+	[ATHOS_LUT_CHAN_712250_IDX] = { 28490, 0x1, 0x76, 0x16AAAB, 0x946 },
+	[ATHOS_LUT_CHAN_712375_IDX] = { 28495, 0x1, 0x76, 0x175555, 0x947 },
+	[ATHOS_LUT_CHAN_712500_IDX] = { 28500, 0x1, 0x76, 0x180000, 0x947 },
+	[ATHOS_LUT_CHAN_712625_IDX] = { 28505, 0x1, 0x76, 0x18AAAB, 0x947 },
+	[ATHOS_LUT_CHAN_712750_IDX] = { 28510, 0x1, 0x76, 0x195555, 0x948 },
+	[ATHOS_LUT_CHAN_712875_IDX] = { 28515, 0x1, 0x76, 0x1A0000, 0x948 },
+	[ATHOS_LUT_CHAN_713000_IDX] = { 28520, 0x1, 0x76, 0x1AAAAB, 0x949 },
+	[ATHOS_LUT_CHAN_713125_IDX] = { 28525, 0x1, 0x76, 0x1B5555, 0x949 },
+	[ATHOS_LUT_CHAN_713250_IDX] = { 28530, 0x1, 0x76, 0x1C0000, 0x94A },
+	[ATHOS_LUT_CHAN_713375_IDX] = { 28535, 0x1, 0x76, 0x1CAAAB, 0x94A },
+	[ATHOS_LUT_CHAN_713500_IDX] = { 28540, 0x1, 0x76, 0x1D5555, 0x94A },
+	[ATHOS_LUT_CHAN_713625_IDX] = { 28545, 0x1, 0x76, 0x1E0000, 0x94B },
+	[ATHOS_LUT_CHAN_713750_IDX] = { 28550, 0x1, 0x76, 0x1EAAAB, 0x94B },
+	[ATHOS_LUT_CHAN_713875_IDX] = { 28555, 0x1, 0x76, 0x1F5555, 0x94C },
+	[ATHOS_LUT_CHAN_714000_IDX] = { 28560, 0x1, 0x77, 0x0, 0x94C },
+	[ATHOS_LUT_CHAN_714125_IDX] = { 28565, 0x1, 0x77, 0xAAAB, 0x94C },
+	[ATHOS_LUT_CHAN_714250_IDX] = { 28570, 0x1, 0x77, 0x15555, 0x94D },
+	[ATHOS_LUT_CHAN_714375_IDX] = { 28575, 0x1, 0x77, 0x20000, 0x94D },
+	[ATHOS_LUT_CHAN_714500_IDX] = { 28580, 0x1, 0x77, 0x2AAAB, 0x94E },
+	[ATHOS_LUT_CHAN_714625_IDX] = { 28585, 0x1, 0x77, 0x35555, 0x94E },
+	[ATHOS_LUT_CHAN_714750_IDX] = { 28590, 0x1, 0x77, 0x40000, 0x94F },
+	[ATHOS_LUT_CHAN_714875_IDX] = { 28595, 0x1, 0x77, 0x4AAAB, 0x94F },
+	[ATHOS_LUT_CHAN_715000_IDX] = { 28600, 0x1, 0x77, 0x55555, 0x94F },
+	[ATHOS_LUT_CHAN_715125_IDX] = { 28605, 0x1, 0x77, 0x60000, 0x950 },
+	[ATHOS_LUT_CHAN_715250_IDX] = { 28610, 0x1, 0x77, 0x6AAAB, 0x950 },
+	[ATHOS_LUT_CHAN_715375_IDX] = { 28615, 0x1, 0x77, 0x75555, 0x951 },
+	[ATHOS_LUT_CHAN_715500_IDX] = { 28620, 0x1, 0x77, 0x80000, 0x951 },
+	[ATHOS_LUT_CHAN_715625_IDX] = { 28625, 0x1, 0x77, 0x8AAAB, 0x951 },
+	[ATHOS_LUT_CHAN_715750_IDX] = { 28630, 0x1, 0x77, 0x95555, 0x952 },
+	[ATHOS_LUT_CHAN_715875_IDX] = { 28635, 0x1, 0x77, 0xA0000, 0x952 },
+	[ATHOS_LUT_CHAN_716000_IDX] = { 28640, 0x1, 0x77, 0xAAAAB, 0x953 },
+	[ATHOS_LUT_CHAN_716125_IDX] = { 28645, 0x1, 0x77, 0xB5555, 0x953 },
+	[ATHOS_LUT_CHAN_716250_IDX] = { 28650, 0x1, 0x77, 0xC0000, 0x954 },
+	[ATHOS_LUT_CHAN_716375_IDX] = { 28655, 0x1, 0x77, 0xCAAAB, 0x954 },
+	[ATHOS_LUT_CHAN_716500_IDX] = { 28660, 0x1, 0x77, 0xD5555, 0x954 },
+	[ATHOS_LUT_CHAN_716625_IDX] = { 28665, 0x1, 0x77, 0xE0000, 0x955 },
+	[ATHOS_LUT_CHAN_716750_IDX] = { 28670, 0x1, 0x77, 0xEAAAB, 0x955 },
+	[ATHOS_LUT_CHAN_716875_IDX] = { 28675, 0x1, 0x77, 0xF5555, 0x956 },
+	[ATHOS_LUT_CHAN_717000_IDX] = { 28680, 0x1, 0x77, 0x100000, 0x956 },
+	[ATHOS_LUT_CHAN_717125_IDX] = { 28685, 0x1, 0x77, 0x10AAAB, 0x956 },
+	[ATHOS_LUT_CHAN_717250_IDX] = { 28690, 0x1, 0x77, 0x115555, 0x957 },
+	[ATHOS_LUT_CHAN_717375_IDX] = { 28695, 0x1, 0x77, 0x120000, 0x957 },
+	[ATHOS_LUT_CHAN_717500_IDX] = { 28700, 0x1, 0x77, 0x12AAAB, 0x958 },
+	[ATHOS_LUT_CHAN_717625_IDX] = { 28705, 0x1, 0x77, 0x135555, 0x958 },
+	[ATHOS_LUT_CHAN_717750_IDX] = { 28710, 0x1, 0x77, 0x140000, 0x959 },
+	[ATHOS_LUT_CHAN_717875_IDX] = { 28715, 0x1, 0x77, 0x14AAAB, 0x959 },
+	[ATHOS_LUT_CHAN_718000_IDX] = { 28720, 0x1, 0x77, 0x155555, 0x959 },
+	[ATHOS_LUT_CHAN_718125_IDX] = { 28725, 0x1, 0x77, 0x160000, 0x95A },
+	[ATHOS_LUT_CHAN_718250_IDX] = { 28730, 0x1, 0x77, 0x16AAAB, 0x95A },
+	[ATHOS_LUT_CHAN_718375_IDX] = { 28735, 0x1, 0x77, 0x175555, 0x95B },
+	[ATHOS_LUT_CHAN_718500_IDX] = { 28740, 0x1, 0x77, 0x180000, 0x95B },
+	[ATHOS_LUT_CHAN_718625_IDX] = { 28745, 0x1, 0x77, 0x18AAAB, 0x95B },
+	[ATHOS_LUT_CHAN_718750_IDX] = { 28750, 0x1, 0x77, 0x195555, 0x95C },
+	[ATHOS_LUT_CHAN_718875_IDX] = { 28755, 0x1, 0x77, 0x1A0000, 0x95C },
+	[ATHOS_LUT_CHAN_719000_IDX] = { 28760, 0x1, 0x77, 0x1AAAAB, 0x95D },
+	[ATHOS_LUT_CHAN_719125_IDX] = { 28765, 0x1, 0x77, 0x1B5555, 0x95D },
+	[ATHOS_LUT_CHAN_719250_IDX] = { 28770, 0x1, 0x77, 0x1C0000, 0x95E },
+	[ATHOS_LUT_CHAN_719375_IDX] = { 28775, 0x1, 0x77, 0x1CAAAB, 0x95E },
+	[ATHOS_LUT_CHAN_719500_IDX] = { 28780, 0x1, 0x77, 0x1D5555, 0x95E },
+	[ATHOS_LUT_CHAN_719625_IDX] = { 28785, 0x1, 0x77, 0x1E0000, 0x95F },
+	[ATHOS_LUT_CHAN_719750_IDX] = { 28790, 0x1, 0x77, 0x1EAAAB, 0x95F },
+	[ATHOS_LUT_CHAN_719875_IDX] = { 28795, 0x1, 0x77, 0x1F5555, 0x960 },
+	[ATHOS_LUT_CHAN_720000_IDX] = { 28800, 0x1, 0x78, 0x0, 0x960 },
+	[ATHOS_LUT_CHAN_720125_IDX] = { 28805, 0x1, 0x78, 0xAAAB, 0x960 },
+	[ATHOS_LUT_CHAN_720250_IDX] = { 28810, 0x1, 0x78, 0x15555, 0x961 },
+	[ATHOS_LUT_CHAN_720375_IDX] = { 28815, 0x1, 0x78, 0x20000, 0x961 },
+	[ATHOS_LUT_CHAN_720500_IDX] = { 28820, 0x1, 0x78, 0x2AAAB, 0x962 },
+	[ATHOS_LUT_CHAN_720625_IDX] = { 28825, 0x1, 0x78, 0x35555, 0x962 },
+	[ATHOS_LUT_CHAN_720750_IDX] = { 28830, 0x1, 0x78, 0x40000, 0x963 },
+	[ATHOS_LUT_CHAN_720875_IDX] = { 28835, 0x1, 0x78, 0x4AAAB, 0x963 },
+	[ATHOS_LUT_CHAN_721000_IDX] = { 28840, 0x1, 0x78, 0x55555, 0x963 },
+	[ATHOS_LUT_CHAN_721125_IDX] = { 28845, 0x1, 0x78, 0x60000, 0x964 },
+	[ATHOS_LUT_CHAN_721250_IDX] = { 28850, 0x1, 0x78, 0x6AAAB, 0x964 },
+	[ATHOS_LUT_CHAN_721375_IDX] = { 28855, 0x1, 0x78, 0x75555, 0x965 },
+	[ATHOS_LUT_CHAN_721500_IDX] = { 28860, 0x1, 0x78, 0x80000, 0x965 }
+};
+
+const struct common_lut_line athos_lut_6g_60_mhz[ATHOS_LUT_CHAN_6G_MAX] = {
+	[ATHOS_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x41, 0x1C71C7, 0x7B9 },
+	[ATHOS_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x41, 0x1CE38E, 0x7B9 },
+	[ATHOS_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x41, 0x1D5555, 0x7BA },
+	[ATHOS_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x41, 0x1DC71C, 0x7BA },
+	[ATHOS_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x41, 0x1E38E4, 0x7BA },
+	[ATHOS_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x41, 0x1EAAAB, 0x7BB },
+	[ATHOS_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x41, 0x1F1C72, 0x7BB },
+	[ATHOS_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x41, 0x1F8E39, 0x7BC },
+	[ATHOS_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x42, 0x0, 0x7BC },
+	[ATHOS_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x42, 0x71C7, 0x7BC },
+	[ATHOS_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x42, 0xE38E, 0x7BD },
+	[ATHOS_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x42, 0x15555, 0x7BD },
+	[ATHOS_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x42, 0x1C71C, 0x7BE },
+	[ATHOS_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x42, 0x238E4, 0x7BE },
+	[ATHOS_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x42, 0x2AAAB, 0x7BF },
+	[ATHOS_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x42, 0x31C72, 0x7BF },
+	[ATHOS_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x42, 0x38E39, 0x7BF },
+	[ATHOS_LUT_CHAN_595125_IDX] = { 23805, 0x0, 0x42, 0x40000, 0x7C0 },
+	[ATHOS_LUT_CHAN_595250_IDX] = { 23810, 0x0, 0x42, 0x471C7, 0x7C0 },
+	[ATHOS_LUT_CHAN_595375_IDX] = { 23815, 0x0, 0x42, 0x4E38E, 0x7C1 },
+	[ATHOS_LUT_CHAN_595500_IDX] = { 23820, 0x0, 0x42, 0x55555, 0x7C1 },
+	[ATHOS_LUT_CHAN_595625_IDX] = { 23825, 0x0, 0x42, 0x5C71C, 0x7C1 },
+	[ATHOS_LUT_CHAN_595750_IDX] = { 23830, 0x0, 0x42, 0x638E4, 0x7C2 },
+	[ATHOS_LUT_CHAN_595875_IDX] = { 23835, 0x0, 0x42, 0x6AAAB, 0x7C2 },
+	[ATHOS_LUT_CHAN_596000_IDX] = { 23840, 0x0, 0x42, 0x71C72, 0x7C3 },
+	[ATHOS_LUT_CHAN_596125_IDX] = { 23845, 0x0, 0x42, 0x78E39, 0x7C3 },
+	[ATHOS_LUT_CHAN_596250_IDX] = { 23850, 0x0, 0x42, 0x80000, 0x7C4 },
+	[ATHOS_LUT_CHAN_596375_IDX] = { 23855, 0x0, 0x42, 0x871C7, 0x7C4 },
+	[ATHOS_LUT_CHAN_596500_IDX] = { 23860, 0x0, 0x42, 0x8E38E, 0x7C4 },
+	[ATHOS_LUT_CHAN_596625_IDX] = { 23865, 0x0, 0x42, 0x95555, 0x7C5 },
+	[ATHOS_LUT_CHAN_596750_IDX] = { 23870, 0x0, 0x42, 0x9C71C, 0x7C5 },
+	[ATHOS_LUT_CHAN_596875_IDX] = { 23875, 0x0, 0x42, 0xA38E4, 0x7C6 },
+	[ATHOS_LUT_CHAN_597000_IDX] = { 23880, 0x0, 0x42, 0xAAAAB, 0x7C6 },
+	[ATHOS_LUT_CHAN_597125_IDX] = { 23885, 0x0, 0x42, 0xB1C72, 0x7C6 },
+	[ATHOS_LUT_CHAN_597250_IDX] = { 23890, 0x0, 0x42, 0xB8E39, 0x7C7 },
+	[ATHOS_LUT_CHAN_597375_IDX] = { 23895, 0x0, 0x42, 0xC0000, 0x7C7 },
+	[ATHOS_LUT_CHAN_597500_IDX] = { 23900, 0x0, 0x42, 0xC71C7, 0x7C8 },
+	[ATHOS_LUT_CHAN_597625_IDX] = { 23905, 0x0, 0x42, 0xCE38E, 0x7C8 },
+	[ATHOS_LUT_CHAN_597750_IDX] = { 23910, 0x0, 0x42, 0xD5555, 0x7C9 },
+	[ATHOS_LUT_CHAN_597875_IDX] = { 23915, 0x0, 0x42, 0xDC71C, 0x7C9 },
+	[ATHOS_LUT_CHAN_598000_IDX] = { 23920, 0x0, 0x42, 0xE38E4, 0x7C9 },
+	[ATHOS_LUT_CHAN_598125_IDX] = { 23925, 0x0, 0x42, 0xEAAAB, 0x7CA },
+	[ATHOS_LUT_CHAN_598250_IDX] = { 23930, 0x0, 0x42, 0xF1C72, 0x7CA },
+	[ATHOS_LUT_CHAN_598375_IDX] = { 23935, 0x0, 0x42, 0xF8E39, 0x7CB },
+	[ATHOS_LUT_CHAN_598500_IDX] = { 23940, 0x0, 0x42, 0x100000, 0x7CB },
+	[ATHOS_LUT_CHAN_598625_IDX] = { 23945, 0x0, 0x42, 0x1071C7, 0x7CB },
+	[ATHOS_LUT_CHAN_598750_IDX] = { 23950, 0x0, 0x42, 0x10E38E, 0x7CC },
+	[ATHOS_LUT_CHAN_598875_IDX] = { 23955, 0x0, 0x42, 0x115555, 0x7CC },
+	[ATHOS_LUT_CHAN_599000_IDX] = { 23960, 0x0, 0x42, 0x11C71C, 0x7CD },
+	[ATHOS_LUT_CHAN_599125_IDX] = { 23965, 0x0, 0x42, 0x1238E4, 0x7CD },
+	[ATHOS_LUT_CHAN_599250_IDX] = { 23970, 0x0, 0x42, 0x12AAAB, 0x7CE },
+	[ATHOS_LUT_CHAN_599375_IDX] = { 23975, 0x0, 0x42, 0x131C72, 0x7CE },
+	[ATHOS_LUT_CHAN_599500_IDX] = { 23980, 0x0, 0x42, 0x138E39, 0x7CE },
+	[ATHOS_LUT_CHAN_599625_IDX] = { 23985, 0x0, 0x42, 0x140000, 0x7CF },
+	[ATHOS_LUT_CHAN_599750_IDX] = { 23990, 0x0, 0x42, 0x1471C7, 0x7CF },
+	[ATHOS_LUT_CHAN_599875_IDX] = { 23995, 0x0, 0x42, 0x14E38E, 0x7D0 },
+	[ATHOS_LUT_CHAN_600000_IDX] = { 24000, 0x0, 0x42, 0x155555, 0x7D0 },
+	[ATHOS_LUT_CHAN_600125_IDX] = { 24005, 0x0, 0x42, 0x15C71C, 0x7D0 },
+	[ATHOS_LUT_CHAN_600250_IDX] = { 24010, 0x0, 0x42, 0x1638E4, 0x7D1 },
+	[ATHOS_LUT_CHAN_600375_IDX] = { 24015, 0x0, 0x42, 0x16AAAB, 0x7D1 },
+	[ATHOS_LUT_CHAN_600500_IDX] = { 24020, 0x0, 0x42, 0x171C72, 0x7D2 },
+	[ATHOS_LUT_CHAN_600625_IDX] = { 24025, 0x0, 0x42, 0x178E39, 0x7D2 },
+	[ATHOS_LUT_CHAN_600750_IDX] = { 24030, 0x0, 0x42, 0x180000, 0x7D3 },
+	[ATHOS_LUT_CHAN_600875_IDX] = { 24035, 0x0, 0x42, 0x1871C7, 0x7D3 },
+	[ATHOS_LUT_CHAN_601000_IDX] = { 24040, 0x0, 0x42, 0x18E38E, 0x7D3 },
+	[ATHOS_LUT_CHAN_601125_IDX] = { 24045, 0x0, 0x42, 0x195555, 0x7D4 },
+	[ATHOS_LUT_CHAN_601250_IDX] = { 24050, 0x0, 0x42, 0x19C71C, 0x7D4 },
+	[ATHOS_LUT_CHAN_601375_IDX] = { 24055, 0x0, 0x42, 0x1A38E4, 0x7D5 },
+	[ATHOS_LUT_CHAN_601500_IDX] = { 24060, 0x0, 0x42, 0x1AAAAB, 0x7D5 },
+	[ATHOS_LUT_CHAN_601625_IDX] = { 24065, 0x0, 0x42, 0x1B1C72, 0x7D5 },
+	[ATHOS_LUT_CHAN_601750_IDX] = { 24070, 0x0, 0x42, 0x1B8E39, 0x7D6 },
+	[ATHOS_LUT_CHAN_601875_IDX] = { 24075, 0x0, 0x42, 0x1C0000, 0x7D6 },
+	[ATHOS_LUT_CHAN_602000_IDX] = { 24080, 0x0, 0x42, 0x1C71C7, 0x7D7 },
+	[ATHOS_LUT_CHAN_602125_IDX] = { 24085, 0x0, 0x42, 0x1CE38E, 0x7D7 },
+	[ATHOS_LUT_CHAN_602250_IDX] = { 24090, 0x0, 0x42, 0x1D5555, 0x7D8 },
+	[ATHOS_LUT_CHAN_602375_IDX] = { 24095, 0x0, 0x42, 0x1DC71C, 0x7D8 },
+	[ATHOS_LUT_CHAN_602500_IDX] = { 24100, 0x0, 0x42, 0x1E38E4, 0x7D8 },
+	[ATHOS_LUT_CHAN_602625_IDX] = { 24105, 0x0, 0x42, 0x1EAAAB, 0x7D9 },
+	[ATHOS_LUT_CHAN_602750_IDX] = { 24110, 0x0, 0x42, 0x1F1C72, 0x7D9 },
+	[ATHOS_LUT_CHAN_602875_IDX] = { 24115, 0x0, 0x42, 0x1F8E39, 0x7DA },
+	[ATHOS_LUT_CHAN_603000_IDX] = { 24120, 0x0, 0x43, 0x0, 0x7DA },
+	[ATHOS_LUT_CHAN_603125_IDX] = { 24125, 0x0, 0x43, 0x71C7, 0x7DA },
+	[ATHOS_LUT_CHAN_603250_IDX] = { 24130, 0x0, 0x43, 0xE38E, 0x7DB },
+	[ATHOS_LUT_CHAN_603375_IDX] = { 24135, 0x0, 0x43, 0x15555, 0x7DB },
+	[ATHOS_LUT_CHAN_603500_IDX] = { 24140, 0x0, 0x43, 0x1C71C, 0x7DC },
+	[ATHOS_LUT_CHAN_603625_IDX] = { 24145, 0x0, 0x43, 0x238E4, 0x7DC },
+	[ATHOS_LUT_CHAN_603750_IDX] = { 24150, 0x0, 0x43, 0x2AAAB, 0x7DD },
+	[ATHOS_LUT_CHAN_603875_IDX] = { 24155, 0x0, 0x43, 0x31C72, 0x7DD },
+	[ATHOS_LUT_CHAN_604000_IDX] = { 24160, 0x0, 0x43, 0x38E39, 0x7DD },
+	[ATHOS_LUT_CHAN_604125_IDX] = { 24165, 0x0, 0x43, 0x40000, 0x7DE },
+	[ATHOS_LUT_CHAN_604250_IDX] = { 24170, 0x0, 0x43, 0x471C7, 0x7DE },
+	[ATHOS_LUT_CHAN_604375_IDX] = { 24175, 0x0, 0x43, 0x4E38E, 0x7DF },
+	[ATHOS_LUT_CHAN_604500_IDX] = { 24180, 0x0, 0x43, 0x55555, 0x7DF },
+	[ATHOS_LUT_CHAN_604625_IDX] = { 24185, 0x0, 0x43, 0x5C71C, 0x7DF },
+	[ATHOS_LUT_CHAN_604750_IDX] = { 24190, 0x0, 0x43, 0x638E4, 0x7E0 },
+	[ATHOS_LUT_CHAN_604875_IDX] = { 24195, 0x0, 0x43, 0x6AAAB, 0x7E0 },
+	[ATHOS_LUT_CHAN_605000_IDX] = { 24200, 0x0, 0x43, 0x71C72, 0x7E1 },
+	[ATHOS_LUT_CHAN_605125_IDX] = { 24205, 0x0, 0x43, 0x78E39, 0x7E1 },
+	[ATHOS_LUT_CHAN_605250_IDX] = { 24210, 0x0, 0x43, 0x80000, 0x7E2 },
+	[ATHOS_LUT_CHAN_605375_IDX] = { 24215, 0x0, 0x43, 0x871C7, 0x7E2 },
+	[ATHOS_LUT_CHAN_605500_IDX] = { 24220, 0x0, 0x43, 0x8E38E, 0x7E2 },
+	[ATHOS_LUT_CHAN_605625_IDX] = { 24225, 0x0, 0x43, 0x95555, 0x7E3 },
+	[ATHOS_LUT_CHAN_605750_IDX] = { 24230, 0x0, 0x43, 0x9C71C, 0x7E3 },
+	[ATHOS_LUT_CHAN_605875_IDX] = { 24235, 0x0, 0x43, 0xA38E4, 0x7E4 },
+	[ATHOS_LUT_CHAN_606000_IDX] = { 24240, 0x0, 0x43, 0xAAAAB, 0x7E4 },
+	[ATHOS_LUT_CHAN_606125_IDX] = { 24245, 0x0, 0x43, 0xB1C72, 0x7E4 },
+	[ATHOS_LUT_CHAN_606250_IDX] = { 24250, 0x0, 0x43, 0xB8E39, 0x7E5 },
+	[ATHOS_LUT_CHAN_606375_IDX] = { 24255, 0x0, 0x43, 0xC0000, 0x7E5 },
+	[ATHOS_LUT_CHAN_606500_IDX] = { 24260, 0x0, 0x43, 0xC71C7, 0x7E6 },
+	[ATHOS_LUT_CHAN_606625_IDX] = { 24265, 0x0, 0x43, 0xCE38E, 0x7E6 },
+	[ATHOS_LUT_CHAN_606750_IDX] = { 24270, 0x0, 0x43, 0xD5555, 0x7E7 },
+	[ATHOS_LUT_CHAN_606875_IDX] = { 24275, 0x0, 0x43, 0xDC71C, 0x7E7 },
+	[ATHOS_LUT_CHAN_607000_IDX] = { 24280, 0x0, 0x43, 0xE38E4, 0x7E7 },
+	[ATHOS_LUT_CHAN_607125_IDX] = { 24285, 0x0, 0x43, 0xEAAAB, 0x7E8 },
+	[ATHOS_LUT_CHAN_607250_IDX] = { 24290, 0x0, 0x43, 0xF1C72, 0x7E8 },
+	[ATHOS_LUT_CHAN_607375_IDX] = { 24295, 0x0, 0x43, 0xF8E39, 0x7E9 },
+	[ATHOS_LUT_CHAN_607500_IDX] = { 24300, 0x0, 0x43, 0x100000, 0x7E9 },
+	[ATHOS_LUT_CHAN_607625_IDX] = { 24305, 0x0, 0x43, 0x1071C7, 0x7E9 },
+	[ATHOS_LUT_CHAN_607750_IDX] = { 24310, 0x0, 0x43, 0x10E38E, 0x7EA },
+	[ATHOS_LUT_CHAN_607875_IDX] = { 24315, 0x0, 0x43, 0x115555, 0x7EA },
+	[ATHOS_LUT_CHAN_608000_IDX] = { 24320, 0x0, 0x43, 0x11C71C, 0x7EB },
+	[ATHOS_LUT_CHAN_608125_IDX] = { 24325, 0x0, 0x43, 0x1238E4, 0x7EB },
+	[ATHOS_LUT_CHAN_608250_IDX] = { 24330, 0x0, 0x43, 0x12AAAB, 0x7EC },
+	[ATHOS_LUT_CHAN_608375_IDX] = { 24335, 0x0, 0x43, 0x131C72, 0x7EC },
+	[ATHOS_LUT_CHAN_608500_IDX] = { 24340, 0x0, 0x43, 0x138E39, 0x7EC },
+	[ATHOS_LUT_CHAN_608625_IDX] = { 24345, 0x0, 0x43, 0x140000, 0x7ED },
+	[ATHOS_LUT_CHAN_608750_IDX] = { 24350, 0x0, 0x43, 0x1471C7, 0x7ED },
+	[ATHOS_LUT_CHAN_608875_IDX] = { 24355, 0x0, 0x43, 0x14E38E, 0x7EE },
+	[ATHOS_LUT_CHAN_609000_IDX] = { 24360, 0x0, 0x43, 0x155555, 0x7EE },
+	[ATHOS_LUT_CHAN_609125_IDX] = { 24365, 0x0, 0x43, 0x15C71C, 0x7EE },
+	[ATHOS_LUT_CHAN_609250_IDX] = { 24370, 0x0, 0x43, 0x1638E4, 0x7EF },
+	[ATHOS_LUT_CHAN_609375_IDX] = { 24375, 0x0, 0x43, 0x16AAAB, 0x7EF },
+	[ATHOS_LUT_CHAN_609500_IDX] = { 24380, 0x0, 0x43, 0x171C72, 0x7F0 },
+	[ATHOS_LUT_CHAN_609625_IDX] = { 24385, 0x0, 0x43, 0x178E39, 0x7F0 },
+	[ATHOS_LUT_CHAN_609750_IDX] = { 24390, 0x0, 0x43, 0x180000, 0x7F1 },
+	[ATHOS_LUT_CHAN_609875_IDX] = { 24395, 0x0, 0x43, 0x1871C7, 0x7F1 },
+	[ATHOS_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x43, 0x18E38E, 0x7F1 },
+	[ATHOS_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x43, 0x195555, 0x7F2 },
+	[ATHOS_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x43, 0x19C71C, 0x7F2 },
+	[ATHOS_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x43, 0x1A38E4, 0x7F3 },
+	[ATHOS_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x43, 0x1AAAAB, 0x7F3 },
+	[ATHOS_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x43, 0x1B1C72, 0x7F3 },
+	[ATHOS_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x43, 0x1B8E39, 0x7F4 },
+	[ATHOS_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x43, 0x1C0000, 0x7F4 },
+	[ATHOS_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x43, 0x1C71C7, 0x7F5 },
+	[ATHOS_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x43, 0x1CE38E, 0x7F5 },
+	[ATHOS_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x43, 0x1D5555, 0x7F6 },
+	[ATHOS_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x43, 0x1DC71C, 0x7F6 },
+	[ATHOS_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x43, 0x1E38E4, 0x7F6 },
+	[ATHOS_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x43, 0x1EAAAB, 0x7F7 },
+	[ATHOS_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x43, 0x1F1C72, 0x7F7 },
+	[ATHOS_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x43, 0x1F8E39, 0x7F8 },
+	[ATHOS_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x44, 0x0, 0x7F8 },
+	[ATHOS_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x44, 0x71C7, 0x7F8 },
+	[ATHOS_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x44, 0xE38E, 0x7F9 },
+	[ATHOS_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x44, 0x15555, 0x7F9 },
+	[ATHOS_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x44, 0x1C71C, 0x7FA },
+	[ATHOS_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x44, 0x238E4, 0x7FA },
+	[ATHOS_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x44, 0x2AAAB, 0x7FB },
+	[ATHOS_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x44, 0x31C72, 0x7FB },
+	[ATHOS_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x44, 0x38E39, 0x7FB },
+	[ATHOS_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x44, 0x40000, 0x7FC },
+	[ATHOS_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x44, 0x471C7, 0x7FC },
+	[ATHOS_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x44, 0x4E38E, 0x7FD },
+	[ATHOS_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x44, 0x55555, 0x7FD },
+	[ATHOS_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x44, 0x5C71C, 0x7FD },
+	[ATHOS_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x44, 0x638E4, 0x7FE },
+	[ATHOS_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x44, 0x6AAAB, 0x7FE },
+	[ATHOS_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x44, 0x71C72, 0x7FF },
+	[ATHOS_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x44, 0x78E39, 0x7FF },
+	[ATHOS_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x44, 0x80000, 0x800 },
+	[ATHOS_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x44, 0x871C7, 0x800 },
+	[ATHOS_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x44, 0x8E38E, 0x800 },
+	[ATHOS_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x44, 0x95555, 0x801 },
+	[ATHOS_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x44, 0x9C71C, 0x801 },
+	[ATHOS_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x44, 0xA38E4, 0x802 },
+	[ATHOS_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x44, 0xAAAAB, 0x802 },
+	[ATHOS_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x44, 0xB1C72, 0x802 },
+	[ATHOS_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x44, 0xB8E39, 0x803 },
+	[ATHOS_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x44, 0xC0000, 0x803 },
+	[ATHOS_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x44, 0xC71C7, 0x804 },
+	[ATHOS_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x44, 0xCE38E, 0x804 },
+	[ATHOS_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x44, 0xD5555, 0x805 },
+	[ATHOS_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x44, 0xDC71C, 0x805 },
+	[ATHOS_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x44, 0xE38E4, 0x805 },
+	[ATHOS_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x44, 0xEAAAB, 0x806 },
+	[ATHOS_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x44, 0xF1C72, 0x806 },
+	[ATHOS_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x44, 0xF8E39, 0x807 },
+	[ATHOS_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x44, 0x100000, 0x807 },
+	[ATHOS_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x44, 0x1071C7, 0x807 },
+	[ATHOS_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x44, 0x10E38E, 0x808 },
+	[ATHOS_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x44, 0x115555, 0x808 },
+	[ATHOS_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x44, 0x11C71C, 0x809 },
+	[ATHOS_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x44, 0x1238E4, 0x809 },
+	[ATHOS_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x44, 0x12AAAB, 0x80A },
+	[ATHOS_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x44, 0x131C72, 0x80A },
+	[ATHOS_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x44, 0x138E39, 0x80A },
+	[ATHOS_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x44, 0x140000, 0x80B },
+	[ATHOS_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x44, 0x1471C7, 0x80B },
+	[ATHOS_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x44, 0x14E38E, 0x80C },
+	[ATHOS_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x44, 0x155555, 0x80C },
+	[ATHOS_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x44, 0x15C71C, 0x80C },
+	[ATHOS_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x44, 0x1638E4, 0x80D },
+	[ATHOS_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x44, 0x16AAAB, 0x80D },
+	[ATHOS_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x44, 0x171C72, 0x80E },
+	[ATHOS_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x44, 0x178E39, 0x80E },
+	[ATHOS_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x44, 0x180000, 0x80F },
+	[ATHOS_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x44, 0x1871C7, 0x80F },
+	[ATHOS_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x44, 0x18E38E, 0x80F },
+	[ATHOS_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x44, 0x195555, 0x810 },
+	[ATHOS_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x44, 0x19C71C, 0x810 },
+	[ATHOS_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x44, 0x1A38E4, 0x811 },
+	[ATHOS_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x44, 0x1AAAAB, 0x811 },
+	[ATHOS_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x44, 0x1B1C72, 0x811 },
+	[ATHOS_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x44, 0x1B8E39, 0x812 },
+	[ATHOS_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x44, 0x1C0000, 0x812 },
+	[ATHOS_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x44, 0x1C71C7, 0x813 },
+	[ATHOS_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x44, 0x1CE38E, 0x813 },
+	[ATHOS_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x44, 0x1D5555, 0x814 },
+	[ATHOS_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x44, 0x1DC71C, 0x814 },
+	[ATHOS_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x44, 0x1E38E4, 0x814 },
+	[ATHOS_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x44, 0x1EAAAB, 0x815 },
+	[ATHOS_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x44, 0x1F1C72, 0x815 },
+	[ATHOS_LUT_CHAN_620875_IDX] = { 24835, 0x1, 0x44, 0x1F8E39, 0x816 },
+	[ATHOS_LUT_CHAN_621000_IDX] = { 24840, 0x1, 0x45, 0x0, 0x816 },
+	[ATHOS_LUT_CHAN_621125_IDX] = { 24845, 0x1, 0x45, 0x71C7, 0x816 },
+	[ATHOS_LUT_CHAN_621250_IDX] = { 24850, 0x1, 0x45, 0xE38E, 0x817 },
+	[ATHOS_LUT_CHAN_621375_IDX] = { 24855, 0x1, 0x45, 0x15555, 0x817 },
+	[ATHOS_LUT_CHAN_621500_IDX] = { 24860, 0x1, 0x45, 0x1C71C, 0x818 },
+	[ATHOS_LUT_CHAN_621625_IDX] = { 24865, 0x1, 0x45, 0x238E4, 0x818 },
+	[ATHOS_LUT_CHAN_621750_IDX] = { 24870, 0x1, 0x45, 0x2AAAB, 0x819 },
+	[ATHOS_LUT_CHAN_621875_IDX] = { 24875, 0x1, 0x45, 0x31C72, 0x819 },
+	[ATHOS_LUT_CHAN_622000_IDX] = { 24880, 0x1, 0x45, 0x38E39, 0x819 },
+	[ATHOS_LUT_CHAN_622125_IDX] = { 24885, 0x1, 0x45, 0x40000, 0x81A },
+	[ATHOS_LUT_CHAN_622250_IDX] = { 24890, 0x1, 0x45, 0x471C7, 0x81A },
+	[ATHOS_LUT_CHAN_622375_IDX] = { 24895, 0x1, 0x45, 0x4E38E, 0x81B },
+	[ATHOS_LUT_CHAN_622500_IDX] = { 24900, 0x1, 0x45, 0x55555, 0x81B },
+	[ATHOS_LUT_CHAN_622625_IDX] = { 24905, 0x1, 0x45, 0x5C71C, 0x81B },
+	[ATHOS_LUT_CHAN_622750_IDX] = { 24910, 0x1, 0x45, 0x638E4, 0x81C },
+	[ATHOS_LUT_CHAN_622875_IDX] = { 24915, 0x1, 0x45, 0x6AAAB, 0x81C },
+	[ATHOS_LUT_CHAN_623000_IDX] = { 24920, 0x1, 0x45, 0x71C72, 0x81D },
+	[ATHOS_LUT_CHAN_623125_IDX] = { 24925, 0x1, 0x45, 0x78E39, 0x81D },
+	[ATHOS_LUT_CHAN_623250_IDX] = { 24930, 0x1, 0x45, 0x80000, 0x81E },
+	[ATHOS_LUT_CHAN_623375_IDX] = { 24935, 0x1, 0x45, 0x871C7, 0x81E },
+	[ATHOS_LUT_CHAN_623500_IDX] = { 24940, 0x1, 0x45, 0x8E38E, 0x81E },
+	[ATHOS_LUT_CHAN_623625_IDX] = { 24945, 0x1, 0x45, 0x95555, 0x81F },
+	[ATHOS_LUT_CHAN_623750_IDX] = { 24950, 0x1, 0x45, 0x9C71C, 0x81F },
+	[ATHOS_LUT_CHAN_623875_IDX] = { 24955, 0x1, 0x45, 0xA38E4, 0x820 },
+	[ATHOS_LUT_CHAN_624000_IDX] = { 24960, 0x1, 0x45, 0xAAAAB, 0x820 },
+	[ATHOS_LUT_CHAN_624125_IDX] = { 24965, 0x1, 0x45, 0xB1C72, 0x820 },
+	[ATHOS_LUT_CHAN_624250_IDX] = { 24970, 0x1, 0x45, 0xB8E39, 0x821 },
+	[ATHOS_LUT_CHAN_624375_IDX] = { 24975, 0x1, 0x45, 0xC0000, 0x821 },
+	[ATHOS_LUT_CHAN_624500_IDX] = { 24980, 0x1, 0x45, 0xC71C7, 0x822 },
+	[ATHOS_LUT_CHAN_624625_IDX] = { 24985, 0x1, 0x45, 0xCE38E, 0x822 },
+	[ATHOS_LUT_CHAN_624750_IDX] = { 24990, 0x1, 0x45, 0xD5555, 0x823 },
+	[ATHOS_LUT_CHAN_624875_IDX] = { 24995, 0x1, 0x45, 0xDC71C, 0x823 },
+	[ATHOS_LUT_CHAN_625000_IDX] = { 25000, 0x1, 0x45, 0xE38E4, 0x823 },
+	[ATHOS_LUT_CHAN_625125_IDX] = { 25005, 0x1, 0x45, 0xEAAAB, 0x824 },
+	[ATHOS_LUT_CHAN_625250_IDX] = { 25010, 0x1, 0x45, 0xF1C72, 0x824 },
+	[ATHOS_LUT_CHAN_625375_IDX] = { 25015, 0x1, 0x45, 0xF8E39, 0x825 },
+	[ATHOS_LUT_CHAN_625500_IDX] = { 25020, 0x1, 0x45, 0x100000, 0x825 },
+	[ATHOS_LUT_CHAN_625625_IDX] = { 25025, 0x1, 0x45, 0x1071C7, 0x825 },
+	[ATHOS_LUT_CHAN_625750_IDX] = { 25030, 0x1, 0x45, 0x10E38E, 0x826 },
+	[ATHOS_LUT_CHAN_625875_IDX] = { 25035, 0x1, 0x45, 0x115555, 0x826 },
+	[ATHOS_LUT_CHAN_626000_IDX] = { 25040, 0x1, 0x45, 0x11C71C, 0x827 },
+	[ATHOS_LUT_CHAN_626125_IDX] = { 25045, 0x1, 0x45, 0x1238E4, 0x827 },
+	[ATHOS_LUT_CHAN_626250_IDX] = { 25050, 0x1, 0x45, 0x12AAAB, 0x828 },
+	[ATHOS_LUT_CHAN_626375_IDX] = { 25055, 0x1, 0x45, 0x131C72, 0x828 },
+	[ATHOS_LUT_CHAN_626500_IDX] = { 25060, 0x1, 0x45, 0x138E39, 0x828 },
+	[ATHOS_LUT_CHAN_626625_IDX] = { 25065, 0x1, 0x45, 0x140000, 0x829 },
+	[ATHOS_LUT_CHAN_626750_IDX] = { 25070, 0x1, 0x45, 0x1471C7, 0x829 },
+	[ATHOS_LUT_CHAN_626875_IDX] = { 25075, 0x1, 0x45, 0x14E38E, 0x82A },
+	[ATHOS_LUT_CHAN_627000_IDX] = { 25080, 0x1, 0x45, 0x155555, 0x82A },
+	[ATHOS_LUT_CHAN_627125_IDX] = { 25085, 0x1, 0x45, 0x15C71C, 0x82A },
+	[ATHOS_LUT_CHAN_627250_IDX] = { 25090, 0x1, 0x45, 0x1638E4, 0x82B },
+	[ATHOS_LUT_CHAN_627375_IDX] = { 25095, 0x1, 0x45, 0x16AAAB, 0x82B },
+	[ATHOS_LUT_CHAN_627500_IDX] = { 25100, 0x1, 0x45, 0x171C72, 0x82C },
+	[ATHOS_LUT_CHAN_627625_IDX] = { 25105, 0x1, 0x45, 0x178E39, 0x82C },
+	[ATHOS_LUT_CHAN_627750_IDX] = { 25110, 0x1, 0x45, 0x180000, 0x82D },
+	[ATHOS_LUT_CHAN_627875_IDX] = { 25115, 0x1, 0x45, 0x1871C7, 0x82D },
+	[ATHOS_LUT_CHAN_628000_IDX] = { 25120, 0x1, 0x45, 0x18E38E, 0x82D },
+	[ATHOS_LUT_CHAN_628125_IDX] = { 25125, 0x1, 0x45, 0x195555, 0x82E },
+	[ATHOS_LUT_CHAN_628250_IDX] = { 25130, 0x1, 0x45, 0x19C71C, 0x82E },
+	[ATHOS_LUT_CHAN_628375_IDX] = { 25135, 0x1, 0x45, 0x1A38E4, 0x82F },
+	[ATHOS_LUT_CHAN_628500_IDX] = { 25140, 0x1, 0x45, 0x1AAAAB, 0x82F },
+	[ATHOS_LUT_CHAN_628625_IDX] = { 25145, 0x1, 0x45, 0x1B1C72, 0x82F },
+	[ATHOS_LUT_CHAN_628750_IDX] = { 25150, 0x1, 0x45, 0x1B8E39, 0x830 },
+	[ATHOS_LUT_CHAN_628875_IDX] = { 25155, 0x1, 0x45, 0x1C0000, 0x830 },
+	[ATHOS_LUT_CHAN_629000_IDX] = { 25160, 0x1, 0x45, 0x1C71C7, 0x831 },
+	[ATHOS_LUT_CHAN_629125_IDX] = { 25165, 0x1, 0x45, 0x1CE38E, 0x831 },
+	[ATHOS_LUT_CHAN_629250_IDX] = { 25170, 0x1, 0x45, 0x1D5555, 0x832 },
+	[ATHOS_LUT_CHAN_629375_IDX] = { 25175, 0x1, 0x45, 0x1DC71C, 0x832 },
+	[ATHOS_LUT_CHAN_629500_IDX] = { 25180, 0x1, 0x45, 0x1E38E4, 0x832 },
+	[ATHOS_LUT_CHAN_629625_IDX] = { 25185, 0x1, 0x45, 0x1EAAAB, 0x833 },
+	[ATHOS_LUT_CHAN_629750_IDX] = { 25190, 0x1, 0x45, 0x1F1C72, 0x833 },
+	[ATHOS_LUT_CHAN_629875_IDX] = { 25195, 0x1, 0x45, 0x1F8E39, 0x834 },
+	[ATHOS_LUT_CHAN_630000_IDX] = { 25200, 0x1, 0x46, 0x0, 0x834 },
+	[ATHOS_LUT_CHAN_630125_IDX] = { 25205, 0x1, 0x46, 0x71C7, 0x834 },
+	[ATHOS_LUT_CHAN_630250_IDX] = { 25210, 0x1, 0x46, 0xE38E, 0x835 },
+	[ATHOS_LUT_CHAN_630375_IDX] = { 25215, 0x1, 0x46, 0x15555, 0x835 },
+	[ATHOS_LUT_CHAN_630500_IDX] = { 25220, 0x1, 0x46, 0x1C71C, 0x836 },
+	[ATHOS_LUT_CHAN_630625_IDX] = { 25225, 0x1, 0x46, 0x238E4, 0x836 },
+	[ATHOS_LUT_CHAN_630750_IDX] = { 25230, 0x1, 0x46, 0x2AAAB, 0x837 },
+	[ATHOS_LUT_CHAN_630875_IDX] = { 25235, 0x1, 0x46, 0x31C72, 0x837 },
+	[ATHOS_LUT_CHAN_631000_IDX] = { 25240, 0x1, 0x46, 0x38E39, 0x837 },
+	[ATHOS_LUT_CHAN_631125_IDX] = { 25245, 0x1, 0x46, 0x40000, 0x838 },
+	[ATHOS_LUT_CHAN_631250_IDX] = { 25250, 0x1, 0x46, 0x471C7, 0x838 },
+	[ATHOS_LUT_CHAN_631375_IDX] = { 25255, 0x1, 0x46, 0x4E38E, 0x839 },
+	[ATHOS_LUT_CHAN_631500_IDX] = { 25260, 0x1, 0x46, 0x55555, 0x839 },
+	[ATHOS_LUT_CHAN_631625_IDX] = { 25265, 0x1, 0x46, 0x5C71C, 0x839 },
+	[ATHOS_LUT_CHAN_631750_IDX] = { 25270, 0x1, 0x46, 0x638E4, 0x83A },
+	[ATHOS_LUT_CHAN_631875_IDX] = { 25275, 0x1, 0x46, 0x6AAAB, 0x83A },
+	[ATHOS_LUT_CHAN_632000_IDX] = { 25280, 0x1, 0x46, 0x71C72, 0x83B },
+	[ATHOS_LUT_CHAN_632125_IDX] = { 25285, 0x1, 0x46, 0x78E39, 0x83B },
+	[ATHOS_LUT_CHAN_632250_IDX] = { 25290, 0x1, 0x46, 0x80000, 0x83C },
+	[ATHOS_LUT_CHAN_632375_IDX] = { 25295, 0x1, 0x46, 0x871C7, 0x83C },
+	[ATHOS_LUT_CHAN_632500_IDX] = { 25300, 0x1, 0x46, 0x8E38E, 0x83C },
+	[ATHOS_LUT_CHAN_632625_IDX] = { 25305, 0x1, 0x46, 0x95555, 0x83D },
+	[ATHOS_LUT_CHAN_632750_IDX] = { 25310, 0x1, 0x46, 0x9C71C, 0x83D },
+	[ATHOS_LUT_CHAN_632875_IDX] = { 25315, 0x1, 0x46, 0xA38E4, 0x83E },
+	[ATHOS_LUT_CHAN_633000_IDX] = { 25320, 0x1, 0x46, 0xAAAAB, 0x83E },
+	[ATHOS_LUT_CHAN_633125_IDX] = { 25325, 0x1, 0x46, 0xB1C72, 0x83E },
+	[ATHOS_LUT_CHAN_633250_IDX] = { 25330, 0x1, 0x46, 0xB8E39, 0x83F },
+	[ATHOS_LUT_CHAN_633375_IDX] = { 25335, 0x1, 0x46, 0xC0000, 0x83F },
+	[ATHOS_LUT_CHAN_633500_IDX] = { 25340, 0x1, 0x46, 0xC71C7, 0x840 },
+	[ATHOS_LUT_CHAN_633625_IDX] = { 25345, 0x1, 0x46, 0xCE38E, 0x840 },
+	[ATHOS_LUT_CHAN_633750_IDX] = { 25350, 0x1, 0x46, 0xD5555, 0x841 },
+	[ATHOS_LUT_CHAN_633875_IDX] = { 25355, 0x1, 0x46, 0xDC71C, 0x841 },
+	[ATHOS_LUT_CHAN_634000_IDX] = { 25360, 0x1, 0x46, 0xE38E4, 0x841 },
+	[ATHOS_LUT_CHAN_634125_IDX] = { 25365, 0x1, 0x46, 0xEAAAB, 0x842 },
+	[ATHOS_LUT_CHAN_634250_IDX] = { 25370, 0x1, 0x46, 0xF1C72, 0x842 },
+	[ATHOS_LUT_CHAN_634375_IDX] = { 25375, 0x1, 0x46, 0xF8E39, 0x843 },
+	[ATHOS_LUT_CHAN_634500_IDX] = { 25380, 0x1, 0x46, 0x100000, 0x843 },
+	[ATHOS_LUT_CHAN_634625_IDX] = { 25385, 0x1, 0x46, 0x1071C7, 0x843 },
+	[ATHOS_LUT_CHAN_634750_IDX] = { 25390, 0x1, 0x46, 0x10E38E, 0x844 },
+	[ATHOS_LUT_CHAN_634875_IDX] = { 25395, 0x1, 0x46, 0x115555, 0x844 },
+	[ATHOS_LUT_CHAN_635000_IDX] = { 25400, 0x1, 0x46, 0x11C71C, 0x845 },
+	[ATHOS_LUT_CHAN_635125_IDX] = { 25405, 0x1, 0x46, 0x1238E4, 0x845 },
+	[ATHOS_LUT_CHAN_635250_IDX] = { 25410, 0x1, 0x46, 0x12AAAB, 0x846 },
+	[ATHOS_LUT_CHAN_635375_IDX] = { 25415, 0x1, 0x46, 0x131C72, 0x846 },
+	[ATHOS_LUT_CHAN_635500_IDX] = { 25420, 0x1, 0x46, 0x138E39, 0x846 },
+	[ATHOS_LUT_CHAN_635625_IDX] = { 25425, 0x1, 0x46, 0x140000, 0x847 },
+	[ATHOS_LUT_CHAN_635750_IDX] = { 25430, 0x1, 0x46, 0x1471C7, 0x847 },
+	[ATHOS_LUT_CHAN_635875_IDX] = { 25435, 0x1, 0x46, 0x14E38E, 0x848 },
+	[ATHOS_LUT_CHAN_636000_IDX] = { 25440, 0x1, 0x46, 0x155555, 0x848 },
+	[ATHOS_LUT_CHAN_636125_IDX] = { 25445, 0x1, 0x46, 0x15C71C, 0x848 },
+	[ATHOS_LUT_CHAN_636250_IDX] = { 25450, 0x1, 0x46, 0x1638E4, 0x849 },
+	[ATHOS_LUT_CHAN_636375_IDX] = { 25455, 0x1, 0x46, 0x16AAAB, 0x849 },
+	[ATHOS_LUT_CHAN_636500_IDX] = { 25460, 0x1, 0x46, 0x171C72, 0x84A },
+	[ATHOS_LUT_CHAN_636625_IDX] = { 25465, 0x1, 0x46, 0x178E39, 0x84A },
+	[ATHOS_LUT_CHAN_636750_IDX] = { 25470, 0x1, 0x46, 0x180000, 0x84B },
+	[ATHOS_LUT_CHAN_636875_IDX] = { 25475, 0x1, 0x46, 0x1871C7, 0x84B },
+	[ATHOS_LUT_CHAN_637000_IDX] = { 25480, 0x1, 0x46, 0x18E38E, 0x84B },
+	[ATHOS_LUT_CHAN_637125_IDX] = { 25485, 0x1, 0x46, 0x195555, 0x84C },
+	[ATHOS_LUT_CHAN_637250_IDX] = { 25490, 0x1, 0x46, 0x19C71C, 0x84C },
+	[ATHOS_LUT_CHAN_637375_IDX] = { 25495, 0x1, 0x46, 0x1A38E4, 0x84D },
+	[ATHOS_LUT_CHAN_637500_IDX] = { 25500, 0x1, 0x46, 0x1AAAAB, 0x84D },
+	[ATHOS_LUT_CHAN_637625_IDX] = { 25505, 0x1, 0x46, 0x1B1C72, 0x84D },
+	[ATHOS_LUT_CHAN_637750_IDX] = { 25510, 0x1, 0x46, 0x1B8E39, 0x84E },
+	[ATHOS_LUT_CHAN_637875_IDX] = { 25515, 0x1, 0x46, 0x1C0000, 0x84E },
+	[ATHOS_LUT_CHAN_638000_IDX] = { 25520, 0x1, 0x46, 0x1C71C7, 0x84F },
+	[ATHOS_LUT_CHAN_638125_IDX] = { 25525, 0x1, 0x46, 0x1CE38E, 0x84F },
+	[ATHOS_LUT_CHAN_638250_IDX] = { 25530, 0x1, 0x46, 0x1D5555, 0x850 },
+	[ATHOS_LUT_CHAN_638375_IDX] = { 25535, 0x1, 0x46, 0x1DC71C, 0x850 },
+	[ATHOS_LUT_CHAN_638500_IDX] = { 25540, 0x1, 0x46, 0x1E38E4, 0x850 },
+	[ATHOS_LUT_CHAN_638625_IDX] = { 25545, 0x1, 0x46, 0x1EAAAB, 0x851 },
+	[ATHOS_LUT_CHAN_638750_IDX] = { 25550, 0x1, 0x46, 0x1F1C72, 0x851 },
+	[ATHOS_LUT_CHAN_638875_IDX] = { 25555, 0x1, 0x46, 0x1F8E39, 0x852 },
+	[ATHOS_LUT_CHAN_639000_IDX] = { 25560, 0x1, 0x47, 0x0, 0x852 },
+	[ATHOS_LUT_CHAN_639125_IDX] = { 25565, 0x1, 0x47, 0x71C7, 0x852 },
+	[ATHOS_LUT_CHAN_639250_IDX] = { 25570, 0x1, 0x47, 0xE38E, 0x853 },
+	[ATHOS_LUT_CHAN_639375_IDX] = { 25575, 0x1, 0x47, 0x15555, 0x853 },
+	[ATHOS_LUT_CHAN_639500_IDX] = { 25580, 0x1, 0x47, 0x1C71C, 0x854 },
+	[ATHOS_LUT_CHAN_639625_IDX] = { 25585, 0x1, 0x47, 0x238E4, 0x854 },
+	[ATHOS_LUT_CHAN_639750_IDX] = { 25590, 0x1, 0x47, 0x2AAAB, 0x855 },
+	[ATHOS_LUT_CHAN_639875_IDX] = { 25595, 0x1, 0x47, 0x31C72, 0x855 },
+	[ATHOS_LUT_CHAN_640000_IDX] = { 25600, 0x1, 0x47, 0x38E39, 0x855 },
+	[ATHOS_LUT_CHAN_640125_IDX] = { 25605, 0x1, 0x47, 0x40000, 0x856 },
+	[ATHOS_LUT_CHAN_640250_IDX] = { 25610, 0x1, 0x47, 0x471C7, 0x856 },
+	[ATHOS_LUT_CHAN_640375_IDX] = { 25615, 0x1, 0x47, 0x4E38E, 0x857 },
+	[ATHOS_LUT_CHAN_640500_IDX] = { 25620, 0x1, 0x47, 0x55555, 0x857 },
+	[ATHOS_LUT_CHAN_640625_IDX] = { 25625, 0x1, 0x47, 0x5C71C, 0x857 },
+	[ATHOS_LUT_CHAN_640750_IDX] = { 25630, 0x1, 0x47, 0x638E4, 0x858 },
+	[ATHOS_LUT_CHAN_640875_IDX] = { 25635, 0x1, 0x47, 0x6AAAB, 0x858 },
+	[ATHOS_LUT_CHAN_641000_IDX] = { 25640, 0x1, 0x47, 0x71C72, 0x859 },
+	[ATHOS_LUT_CHAN_641125_IDX] = { 25645, 0x1, 0x47, 0x78E39, 0x859 },
+	[ATHOS_LUT_CHAN_641250_IDX] = { 25650, 0x1, 0x47, 0x80000, 0x85A },
+	[ATHOS_LUT_CHAN_641375_IDX] = { 25655, 0x1, 0x47, 0x871C7, 0x85A },
+	[ATHOS_LUT_CHAN_641500_IDX] = { 25660, 0x1, 0x47, 0x8E38E, 0x85A },
+	[ATHOS_LUT_CHAN_641625_IDX] = { 25665, 0x1, 0x47, 0x95555, 0x85B },
+	[ATHOS_LUT_CHAN_641750_IDX] = { 25670, 0x1, 0x47, 0x9C71C, 0x85B },
+	[ATHOS_LUT_CHAN_641875_IDX] = { 25675, 0x1, 0x47, 0xA38E4, 0x85C },
+	[ATHOS_LUT_CHAN_642000_IDX] = { 25680, 0x1, 0x47, 0xAAAAB, 0x85C },
+	[ATHOS_LUT_CHAN_642125_IDX] = { 25685, 0x1, 0x47, 0xB1C72, 0x85C },
+	[ATHOS_LUT_CHAN_642250_IDX] = { 25690, 0x1, 0x47, 0xB8E39, 0x85D },
+	[ATHOS_LUT_CHAN_642375_IDX] = { 25695, 0x1, 0x47, 0xC0000, 0x85D },
+	[ATHOS_LUT_CHAN_642500_IDX] = { 25700, 0x1, 0x47, 0xC71C7, 0x85E },
+	[ATHOS_LUT_CHAN_642625_IDX] = { 25705, 0x1, 0x47, 0xCE38E, 0x85E },
+	[ATHOS_LUT_CHAN_642750_IDX] = { 25710, 0x1, 0x47, 0xD5555, 0x85F },
+	[ATHOS_LUT_CHAN_642875_IDX] = { 25715, 0x1, 0x47, 0xDC71C, 0x85F },
+	[ATHOS_LUT_CHAN_643000_IDX] = { 25720, 0x1, 0x47, 0xE38E4, 0x85F },
+	[ATHOS_LUT_CHAN_643125_IDX] = { 25725, 0x1, 0x47, 0xEAAAB, 0x860 },
+	[ATHOS_LUT_CHAN_643250_IDX] = { 25730, 0x1, 0x47, 0xF1C72, 0x860 },
+	[ATHOS_LUT_CHAN_643375_IDX] = { 25735, 0x1, 0x47, 0xF8E39, 0x861 },
+	[ATHOS_LUT_CHAN_643500_IDX] = { 25740, 0x1, 0x47, 0x100000, 0x861 },
+	[ATHOS_LUT_CHAN_643625_IDX] = { 25745, 0x1, 0x47, 0x1071C7, 0x861 },
+	[ATHOS_LUT_CHAN_643750_IDX] = { 25750, 0x1, 0x47, 0x10E38E, 0x862 },
+	[ATHOS_LUT_CHAN_643875_IDX] = { 25755, 0x1, 0x47, 0x115555, 0x862 },
+	[ATHOS_LUT_CHAN_644000_IDX] = { 25760, 0x1, 0x47, 0x11C71C, 0x863 },
+	[ATHOS_LUT_CHAN_644125_IDX] = { 25765, 0x1, 0x47, 0x1238E4, 0x863 },
+	[ATHOS_LUT_CHAN_644250_IDX] = { 25770, 0x1, 0x47, 0x12AAAB, 0x864 },
+	[ATHOS_LUT_CHAN_644375_IDX] = { 25775, 0x1, 0x47, 0x131C72, 0x864 },
+	[ATHOS_LUT_CHAN_644500_IDX] = { 25780, 0x1, 0x47, 0x138E39, 0x864 },
+	[ATHOS_LUT_CHAN_644625_IDX] = { 25785, 0x1, 0x47, 0x140000, 0x865 },
+	[ATHOS_LUT_CHAN_644750_IDX] = { 25790, 0x1, 0x47, 0x1471C7, 0x865 },
+	[ATHOS_LUT_CHAN_644875_IDX] = { 25795, 0x1, 0x47, 0x14E38E, 0x866 },
+	[ATHOS_LUT_CHAN_645000_IDX] = { 25800, 0x1, 0x47, 0x155555, 0x866 },
+	[ATHOS_LUT_CHAN_645125_IDX] = { 25805, 0x1, 0x47, 0x15C71C, 0x866 },
+	[ATHOS_LUT_CHAN_645250_IDX] = { 25810, 0x1, 0x47, 0x1638E4, 0x867 },
+	[ATHOS_LUT_CHAN_645375_IDX] = { 25815, 0x1, 0x47, 0x16AAAB, 0x867 },
+	[ATHOS_LUT_CHAN_645500_IDX] = { 25820, 0x1, 0x47, 0x171C72, 0x868 },
+	[ATHOS_LUT_CHAN_645625_IDX] = { 25825, 0x1, 0x47, 0x178E39, 0x868 },
+	[ATHOS_LUT_CHAN_645750_IDX] = { 25830, 0x1, 0x47, 0x180000, 0x869 },
+	[ATHOS_LUT_CHAN_645875_IDX] = { 25835, 0x1, 0x47, 0x1871C7, 0x869 },
+	[ATHOS_LUT_CHAN_646000_IDX] = { 25840, 0x1, 0x47, 0x18E38E, 0x869 },
+	[ATHOS_LUT_CHAN_646125_IDX] = { 25845, 0x1, 0x47, 0x195555, 0x86A },
+	[ATHOS_LUT_CHAN_646250_IDX] = { 25850, 0x1, 0x47, 0x19C71C, 0x86A },
+	[ATHOS_LUT_CHAN_646375_IDX] = { 25855, 0x1, 0x47, 0x1A38E4, 0x86B },
+	[ATHOS_LUT_CHAN_646500_IDX] = { 25860, 0x1, 0x47, 0x1AAAAB, 0x86B },
+	[ATHOS_LUT_CHAN_646625_IDX] = { 25865, 0x1, 0x47, 0x1B1C72, 0x86B },
+	[ATHOS_LUT_CHAN_646750_IDX] = { 25870, 0x1, 0x47, 0x1B8E39, 0x86C },
+	[ATHOS_LUT_CHAN_646875_IDX] = { 25875, 0x1, 0x47, 0x1C0000, 0x86C },
+	[ATHOS_LUT_CHAN_647000_IDX] = { 25880, 0x1, 0x47, 0x1C71C7, 0x86D },
+	[ATHOS_LUT_CHAN_647125_IDX] = { 25885, 0x1, 0x47, 0x1CE38E, 0x86D },
+	[ATHOS_LUT_CHAN_647250_IDX] = { 25890, 0x1, 0x47, 0x1D5555, 0x86E },
+	[ATHOS_LUT_CHAN_647375_IDX] = { 25895, 0x1, 0x47, 0x1DC71C, 0x86E },
+	[ATHOS_LUT_CHAN_647500_IDX] = { 25900, 0x1, 0x47, 0x1E38E4, 0x86E },
+	[ATHOS_LUT_CHAN_647625_IDX] = { 25905, 0x1, 0x47, 0x1EAAAB, 0x86F },
+	[ATHOS_LUT_CHAN_647750_IDX] = { 25910, 0x1, 0x47, 0x1F1C72, 0x86F },
+	[ATHOS_LUT_CHAN_647875_IDX] = { 25915, 0x1, 0x47, 0x1F8E39, 0x870 },
+	[ATHOS_LUT_CHAN_648000_IDX] = { 25920, 0x1, 0x48, 0x0, 0x870 },
+	[ATHOS_LUT_CHAN_648125_IDX] = { 25925, 0x1, 0x48, 0x71C7, 0x870 },
+	[ATHOS_LUT_CHAN_648250_IDX] = { 25930, 0x1, 0x48, 0xE38E, 0x871 },
+	[ATHOS_LUT_CHAN_648375_IDX] = { 25935, 0x1, 0x48, 0x15555, 0x871 },
+	[ATHOS_LUT_CHAN_648500_IDX] = { 25940, 0x1, 0x48, 0x1C71C, 0x872 },
+	[ATHOS_LUT_CHAN_648625_IDX] = { 25945, 0x1, 0x48, 0x238E4, 0x872 },
+	[ATHOS_LUT_CHAN_648750_IDX] = { 25950, 0x1, 0x48, 0x2AAAB, 0x873 },
+	[ATHOS_LUT_CHAN_648875_IDX] = { 25955, 0x1, 0x48, 0x31C72, 0x873 },
+	[ATHOS_LUT_CHAN_649000_IDX] = { 25960, 0x1, 0x48, 0x38E39, 0x873 },
+	[ATHOS_LUT_CHAN_649125_IDX] = { 25965, 0x1, 0x48, 0x40000, 0x874 },
+	[ATHOS_LUT_CHAN_649250_IDX] = { 25970, 0x1, 0x48, 0x471C7, 0x874 },
+	[ATHOS_LUT_CHAN_649375_IDX] = { 25975, 0x1, 0x48, 0x4E38E, 0x875 },
+	[ATHOS_LUT_CHAN_649500_IDX] = { 25980, 0x1, 0x48, 0x55555, 0x875 },
+	[ATHOS_LUT_CHAN_649625_IDX] = { 25985, 0x1, 0x48, 0x5C71C, 0x875 },
+	[ATHOS_LUT_CHAN_649750_IDX] = { 25990, 0x1, 0x48, 0x638E4, 0x876 },
+	[ATHOS_LUT_CHAN_649875_IDX] = { 25995, 0x1, 0x48, 0x6AAAB, 0x876 },
+	[ATHOS_LUT_CHAN_650000_IDX] = { 26000, 0x1, 0x48, 0x71C72, 0x877 },
+	[ATHOS_LUT_CHAN_650125_IDX] = { 26005, 0x1, 0x48, 0x78E39, 0x877 },
+	[ATHOS_LUT_CHAN_650250_IDX] = { 26010, 0x1, 0x48, 0x80000, 0x878 },
+	[ATHOS_LUT_CHAN_650375_IDX] = { 26015, 0x1, 0x48, 0x871C7, 0x878 },
+	[ATHOS_LUT_CHAN_650500_IDX] = { 26020, 0x1, 0x48, 0x8E38E, 0x878 },
+	[ATHOS_LUT_CHAN_650625_IDX] = { 26025, 0x1, 0x48, 0x95555, 0x879 },
+	[ATHOS_LUT_CHAN_650750_IDX] = { 26030, 0x1, 0x48, 0x9C71C, 0x879 },
+	[ATHOS_LUT_CHAN_650875_IDX] = { 26035, 0x1, 0x48, 0xA38E4, 0x87A },
+	[ATHOS_LUT_CHAN_651000_IDX] = { 26040, 0x1, 0x48, 0xAAAAB, 0x87A },
+	[ATHOS_LUT_CHAN_651125_IDX] = { 26045, 0x1, 0x48, 0xB1C72, 0x87A },
+	[ATHOS_LUT_CHAN_651250_IDX] = { 26050, 0x1, 0x48, 0xB8E39, 0x87B },
+	[ATHOS_LUT_CHAN_651375_IDX] = { 26055, 0x1, 0x48, 0xC0000, 0x87B },
+	[ATHOS_LUT_CHAN_651500_IDX] = { 26060, 0x1, 0x48, 0xC71C7, 0x87C },
+	[ATHOS_LUT_CHAN_651625_IDX] = { 26065, 0x1, 0x48, 0xCE38E, 0x87C },
+	[ATHOS_LUT_CHAN_651750_IDX] = { 26070, 0x1, 0x48, 0xD5555, 0x87D },
+	[ATHOS_LUT_CHAN_651875_IDX] = { 26075, 0x1, 0x48, 0xDC71C, 0x87D },
+	[ATHOS_LUT_CHAN_652000_IDX] = { 26080, 0x1, 0x48, 0xE38E4, 0x87D },
+	[ATHOS_LUT_CHAN_652125_IDX] = { 26085, 0x1, 0x48, 0xEAAAB, 0x87E },
+	[ATHOS_LUT_CHAN_652250_IDX] = { 26090, 0x1, 0x48, 0xF1C72, 0x87E },
+	[ATHOS_LUT_CHAN_652375_IDX] = { 26095, 0x1, 0x48, 0xF8E39, 0x87F },
+	[ATHOS_LUT_CHAN_652500_IDX] = { 26100, 0x1, 0x48, 0x100000, 0x87F },
+	[ATHOS_LUT_CHAN_652625_IDX] = { 26105, 0x1, 0x48, 0x1071C7, 0x87F },
+	[ATHOS_LUT_CHAN_652750_IDX] = { 26110, 0x1, 0x48, 0x10E38E, 0x880 },
+	[ATHOS_LUT_CHAN_652875_IDX] = { 26115, 0x1, 0x48, 0x115555, 0x880 },
+	[ATHOS_LUT_CHAN_653000_IDX] = { 26120, 0x1, 0x48, 0x11C71C, 0x881 },
+	[ATHOS_LUT_CHAN_653125_IDX] = { 26125, 0x1, 0x48, 0x1238E4, 0x881 },
+	[ATHOS_LUT_CHAN_653250_IDX] = { 26130, 0x1, 0x48, 0x12AAAB, 0x882 },
+	[ATHOS_LUT_CHAN_653375_IDX] = { 26135, 0x1, 0x48, 0x131C72, 0x882 },
+	[ATHOS_LUT_CHAN_653500_IDX] = { 26140, 0x1, 0x48, 0x138E39, 0x882 },
+	[ATHOS_LUT_CHAN_653625_IDX] = { 26145, 0x1, 0x48, 0x140000, 0x883 },
+	[ATHOS_LUT_CHAN_653750_IDX] = { 26150, 0x1, 0x48, 0x1471C7, 0x883 },
+	[ATHOS_LUT_CHAN_653875_IDX] = { 26155, 0x1, 0x48, 0x14E38E, 0x884 },
+	[ATHOS_LUT_CHAN_654000_IDX] = { 26160, 0x1, 0x48, 0x155555, 0x884 },
+	[ATHOS_LUT_CHAN_654125_IDX] = { 26165, 0x1, 0x48, 0x15C71C, 0x884 },
+	[ATHOS_LUT_CHAN_654250_IDX] = { 26170, 0x1, 0x48, 0x1638E4, 0x885 },
+	[ATHOS_LUT_CHAN_654375_IDX] = { 26175, 0x1, 0x48, 0x16AAAB, 0x885 },
+	[ATHOS_LUT_CHAN_654500_IDX] = { 26180, 0x1, 0x48, 0x171C72, 0x886 },
+	[ATHOS_LUT_CHAN_654625_IDX] = { 26185, 0x1, 0x48, 0x178E39, 0x886 },
+	[ATHOS_LUT_CHAN_654750_IDX] = { 26190, 0x1, 0x48, 0x180000, 0x887 },
+	[ATHOS_LUT_CHAN_654875_IDX] = { 26195, 0x1, 0x48, 0x1871C7, 0x887 },
+	[ATHOS_LUT_CHAN_655000_IDX] = { 26200, 0x1, 0x48, 0x18E38E, 0x887 },
+	[ATHOS_LUT_CHAN_655125_IDX] = { 26205, 0x1, 0x48, 0x195555, 0x888 },
+	[ATHOS_LUT_CHAN_655250_IDX] = { 26210, 0x1, 0x48, 0x19C71C, 0x888 },
+	[ATHOS_LUT_CHAN_655375_IDX] = { 26215, 0x1, 0x48, 0x1A38E4, 0x889 },
+	[ATHOS_LUT_CHAN_655500_IDX] = { 26220, 0x1, 0x48, 0x1AAAAB, 0x889 },
+	[ATHOS_LUT_CHAN_655625_IDX] = { 26225, 0x1, 0x48, 0x1B1C72, 0x889 },
+	[ATHOS_LUT_CHAN_655750_IDX] = { 26230, 0x1, 0x48, 0x1B8E39, 0x88A },
+	[ATHOS_LUT_CHAN_655875_IDX] = { 26235, 0x1, 0x48, 0x1C0000, 0x88A },
+	[ATHOS_LUT_CHAN_656000_IDX] = { 26240, 0x1, 0x48, 0x1C71C7, 0x88B },
+	[ATHOS_LUT_CHAN_656125_IDX] = { 26245, 0x1, 0x48, 0x1CE38E, 0x88B },
+	[ATHOS_LUT_CHAN_656250_IDX] = { 26250, 0x1, 0x48, 0x1D5555, 0x88C },
+	[ATHOS_LUT_CHAN_656375_IDX] = { 26255, 0x1, 0x48, 0x1DC71C, 0x88C },
+	[ATHOS_LUT_CHAN_656500_IDX] = { 26260, 0x1, 0x48, 0x1E38E4, 0x88C },
+	[ATHOS_LUT_CHAN_656625_IDX] = { 26265, 0x1, 0x48, 0x1EAAAB, 0x88D },
+	[ATHOS_LUT_CHAN_656750_IDX] = { 26270, 0x1, 0x48, 0x1F1C72, 0x88D },
+	[ATHOS_LUT_CHAN_656875_IDX] = { 26275, 0x1, 0x48, 0x1F8E39, 0x88E },
+	[ATHOS_LUT_CHAN_657000_IDX] = { 26280, 0x1, 0x49, 0x0, 0x88E },
+	[ATHOS_LUT_CHAN_657125_IDX] = { 26285, 0x1, 0x49, 0x71C7, 0x88E },
+	[ATHOS_LUT_CHAN_657250_IDX] = { 26290, 0x1, 0x49, 0xE38E, 0x88F },
+	[ATHOS_LUT_CHAN_657375_IDX] = { 26295, 0x1, 0x49, 0x15555, 0x88F },
+	[ATHOS_LUT_CHAN_657500_IDX] = { 26300, 0x1, 0x49, 0x1C71C, 0x890 },
+	[ATHOS_LUT_CHAN_657625_IDX] = { 26305, 0x1, 0x49, 0x238E4, 0x890 },
+	[ATHOS_LUT_CHAN_657750_IDX] = { 26310, 0x1, 0x49, 0x2AAAB, 0x891 },
+	[ATHOS_LUT_CHAN_657875_IDX] = { 26315, 0x1, 0x49, 0x31C72, 0x891 },
+	[ATHOS_LUT_CHAN_658000_IDX] = { 26320, 0x1, 0x49, 0x38E39, 0x891 },
+	[ATHOS_LUT_CHAN_658125_IDX] = { 26325, 0x1, 0x49, 0x40000, 0x892 },
+	[ATHOS_LUT_CHAN_658250_IDX] = { 26330, 0x1, 0x49, 0x471C7, 0x892 },
+	[ATHOS_LUT_CHAN_658375_IDX] = { 26335, 0x1, 0x49, 0x4E38E, 0x893 },
+	[ATHOS_LUT_CHAN_658500_IDX] = { 26340, 0x1, 0x49, 0x55555, 0x893 },
+	[ATHOS_LUT_CHAN_658625_IDX] = { 26345, 0x1, 0x49, 0x5C71C, 0x893 },
+	[ATHOS_LUT_CHAN_658750_IDX] = { 26350, 0x1, 0x49, 0x638E4, 0x894 },
+	[ATHOS_LUT_CHAN_658875_IDX] = { 26355, 0x1, 0x49, 0x6AAAB, 0x894 },
+	[ATHOS_LUT_CHAN_659000_IDX] = { 26360, 0x1, 0x49, 0x71C72, 0x895 },
+	[ATHOS_LUT_CHAN_659125_IDX] = { 26365, 0x1, 0x49, 0x78E39, 0x895 },
+	[ATHOS_LUT_CHAN_659250_IDX] = { 26370, 0x1, 0x49, 0x80000, 0x896 },
+	[ATHOS_LUT_CHAN_659375_IDX] = { 26375, 0x1, 0x49, 0x871C7, 0x896 },
+	[ATHOS_LUT_CHAN_659500_IDX] = { 26380, 0x1, 0x49, 0x8E38E, 0x896 },
+	[ATHOS_LUT_CHAN_659625_IDX] = { 26385, 0x1, 0x49, 0x95555, 0x897 },
+	[ATHOS_LUT_CHAN_659750_IDX] = { 26390, 0x1, 0x49, 0x9C71C, 0x897 },
+	[ATHOS_LUT_CHAN_659875_IDX] = { 26395, 0x1, 0x49, 0xA38E4, 0x898 },
+	[ATHOS_LUT_CHAN_660000_IDX] = { 26400, 0x1, 0x49, 0xAAAAB, 0x898 },
+	[ATHOS_LUT_CHAN_660125_IDX] = { 26405, 0x1, 0x49, 0xB1C72, 0x898 },
+	[ATHOS_LUT_CHAN_660250_IDX] = { 26410, 0x1, 0x49, 0xB8E39, 0x899 },
+	[ATHOS_LUT_CHAN_660375_IDX] = { 26415, 0x1, 0x49, 0xC0000, 0x899 },
+	[ATHOS_LUT_CHAN_660500_IDX] = { 26420, 0x1, 0x49, 0xC71C7, 0x89A },
+	[ATHOS_LUT_CHAN_660625_IDX] = { 26425, 0x1, 0x49, 0xCE38E, 0x89A },
+	[ATHOS_LUT_CHAN_660750_IDX] = { 26430, 0x1, 0x49, 0xD5555, 0x89B },
+	[ATHOS_LUT_CHAN_660875_IDX] = { 26435, 0x1, 0x49, 0xDC71C, 0x89B },
+	[ATHOS_LUT_CHAN_661000_IDX] = { 26440, 0x1, 0x49, 0xE38E4, 0x89B },
+	[ATHOS_LUT_CHAN_661125_IDX] = { 26445, 0x1, 0x49, 0xEAAAB, 0x89C },
+	[ATHOS_LUT_CHAN_661250_IDX] = { 26450, 0x1, 0x49, 0xF1C72, 0x89C },
+	[ATHOS_LUT_CHAN_661375_IDX] = { 26455, 0x1, 0x49, 0xF8E39, 0x89D },
+	[ATHOS_LUT_CHAN_661500_IDX] = { 26460, 0x1, 0x49, 0x100000, 0x89D },
+	[ATHOS_LUT_CHAN_661625_IDX] = { 26465, 0x1, 0x49, 0x1071C7, 0x89D },
+	[ATHOS_LUT_CHAN_661750_IDX] = { 26470, 0x1, 0x49, 0x10E38E, 0x89E },
+	[ATHOS_LUT_CHAN_661875_IDX] = { 26475, 0x1, 0x49, 0x115555, 0x89E },
+	[ATHOS_LUT_CHAN_662000_IDX] = { 26480, 0x1, 0x49, 0x11C71C, 0x89F },
+	[ATHOS_LUT_CHAN_662125_IDX] = { 26485, 0x1, 0x49, 0x1238E4, 0x89F },
+	[ATHOS_LUT_CHAN_662250_IDX] = { 26490, 0x1, 0x49, 0x12AAAB, 0x8A0 },
+	[ATHOS_LUT_CHAN_662375_IDX] = { 26495, 0x1, 0x49, 0x131C72, 0x8A0 },
+	[ATHOS_LUT_CHAN_662500_IDX] = { 26500, 0x1, 0x49, 0x138E39, 0x8A0 },
+	[ATHOS_LUT_CHAN_662625_IDX] = { 26505, 0x1, 0x49, 0x140000, 0x8A1 },
+	[ATHOS_LUT_CHAN_662750_IDX] = { 26510, 0x1, 0x49, 0x1471C7, 0x8A1 },
+	[ATHOS_LUT_CHAN_662875_IDX] = { 26515, 0x1, 0x49, 0x14E38E, 0x8A2 },
+	[ATHOS_LUT_CHAN_663000_IDX] = { 26520, 0x1, 0x49, 0x155555, 0x8A2 },
+	[ATHOS_LUT_CHAN_663125_IDX] = { 26525, 0x1, 0x49, 0x15C71C, 0x8A2 },
+	[ATHOS_LUT_CHAN_663250_IDX] = { 26530, 0x1, 0x49, 0x1638E4, 0x8A3 },
+	[ATHOS_LUT_CHAN_663375_IDX] = { 26535, 0x1, 0x49, 0x16AAAB, 0x8A3 },
+	[ATHOS_LUT_CHAN_663500_IDX] = { 26540, 0x1, 0x49, 0x171C72, 0x8A4 },
+	[ATHOS_LUT_CHAN_663625_IDX] = { 26545, 0x1, 0x49, 0x178E39, 0x8A4 },
+	[ATHOS_LUT_CHAN_663750_IDX] = { 26550, 0x1, 0x49, 0x180000, 0x8A5 },
+	[ATHOS_LUT_CHAN_663875_IDX] = { 26555, 0x1, 0x49, 0x1871C7, 0x8A5 },
+	[ATHOS_LUT_CHAN_664000_IDX] = { 26560, 0x1, 0x49, 0x18E38E, 0x8A5 },
+	[ATHOS_LUT_CHAN_664125_IDX] = { 26565, 0x1, 0x49, 0x195555, 0x8A6 },
+	[ATHOS_LUT_CHAN_664250_IDX] = { 26570, 0x1, 0x49, 0x19C71C, 0x8A6 },
+	[ATHOS_LUT_CHAN_664375_IDX] = { 26575, 0x1, 0x49, 0x1A38E4, 0x8A7 },
+	[ATHOS_LUT_CHAN_664500_IDX] = { 26580, 0x1, 0x49, 0x1AAAAB, 0x8A7 },
+	[ATHOS_LUT_CHAN_664625_IDX] = { 26585, 0x1, 0x49, 0x1B1C72, 0x8A7 },
+	[ATHOS_LUT_CHAN_664750_IDX] = { 26590, 0x1, 0x49, 0x1B8E39, 0x8A8 },
+	[ATHOS_LUT_CHAN_664875_IDX] = { 26595, 0x1, 0x49, 0x1C0000, 0x8A8 },
+	[ATHOS_LUT_CHAN_665000_IDX] = { 26600, 0x1, 0x49, 0x1C71C7, 0x8A9 },
+	[ATHOS_LUT_CHAN_665125_IDX] = { 26605, 0x1, 0x49, 0x1CE38E, 0x8A9 },
+	[ATHOS_LUT_CHAN_665250_IDX] = { 26610, 0x1, 0x49, 0x1D5555, 0x8AA },
+	[ATHOS_LUT_CHAN_665375_IDX] = { 26615, 0x1, 0x49, 0x1DC71C, 0x8AA },
+	[ATHOS_LUT_CHAN_665500_IDX] = { 26620, 0x1, 0x49, 0x1E38E4, 0x8AA },
+	[ATHOS_LUT_CHAN_665625_IDX] = { 26625, 0x1, 0x49, 0x1EAAAB, 0x8AB },
+	[ATHOS_LUT_CHAN_665750_IDX] = { 26630, 0x1, 0x49, 0x1F1C72, 0x8AB },
+	[ATHOS_LUT_CHAN_665875_IDX] = { 26635, 0x1, 0x49, 0x1F8E39, 0x8AC },
+	[ATHOS_LUT_CHAN_666000_IDX] = { 26640, 0x1, 0x4A, 0x0, 0x8AC },
+	[ATHOS_LUT_CHAN_666125_IDX] = { 26645, 0x1, 0x4A, 0x71C7, 0x8AC },
+	[ATHOS_LUT_CHAN_666250_IDX] = { 26650, 0x1, 0x4A, 0xE38E, 0x8AD },
+	[ATHOS_LUT_CHAN_666375_IDX] = { 26655, 0x1, 0x4A, 0x15555, 0x8AD },
+	[ATHOS_LUT_CHAN_666500_IDX] = { 26660, 0x1, 0x4A, 0x1C71C, 0x8AE },
+	[ATHOS_LUT_CHAN_666625_IDX] = { 26665, 0x1, 0x4A, 0x238E4, 0x8AE },
+	[ATHOS_LUT_CHAN_666750_IDX] = { 26670, 0x1, 0x4A, 0x2AAAB, 0x8AF },
+	[ATHOS_LUT_CHAN_666875_IDX] = { 26675, 0x1, 0x4A, 0x31C72, 0x8AF },
+	[ATHOS_LUT_CHAN_667000_IDX] = { 26680, 0x1, 0x4A, 0x38E39, 0x8AF },
+	[ATHOS_LUT_CHAN_667125_IDX] = { 26685, 0x1, 0x4A, 0x40000, 0x8B0 },
+	[ATHOS_LUT_CHAN_667250_IDX] = { 26690, 0x1, 0x4A, 0x471C7, 0x8B0 },
+	[ATHOS_LUT_CHAN_667375_IDX] = { 26695, 0x1, 0x4A, 0x4E38E, 0x8B1 },
+	[ATHOS_LUT_CHAN_667500_IDX] = { 26700, 0x1, 0x4A, 0x55555, 0x8B1 },
+	[ATHOS_LUT_CHAN_667625_IDX] = { 26705, 0x1, 0x4A, 0x5C71C, 0x8B1 },
+	[ATHOS_LUT_CHAN_667750_IDX] = { 26710, 0x1, 0x4A, 0x638E4, 0x8B2 },
+	[ATHOS_LUT_CHAN_667875_IDX] = { 26715, 0x1, 0x4A, 0x6AAAB, 0x8B2 },
+	[ATHOS_LUT_CHAN_668000_IDX] = { 26720, 0x1, 0x4A, 0x71C72, 0x8B3 },
+	[ATHOS_LUT_CHAN_668125_IDX] = { 26725, 0x1, 0x4A, 0x78E39, 0x8B3 },
+	[ATHOS_LUT_CHAN_668250_IDX] = { 26730, 0x1, 0x4A, 0x80000, 0x8B4 },
+	[ATHOS_LUT_CHAN_668375_IDX] = { 26735, 0x1, 0x4A, 0x871C7, 0x8B4 },
+	[ATHOS_LUT_CHAN_668500_IDX] = { 26740, 0x1, 0x4A, 0x8E38E, 0x8B4 },
+	[ATHOS_LUT_CHAN_668625_IDX] = { 26745, 0x1, 0x4A, 0x95555, 0x8B5 },
+	[ATHOS_LUT_CHAN_668750_IDX] = { 26750, 0x1, 0x4A, 0x9C71C, 0x8B5 },
+	[ATHOS_LUT_CHAN_668875_IDX] = { 26755, 0x1, 0x4A, 0xA38E4, 0x8B6 },
+	[ATHOS_LUT_CHAN_669000_IDX] = { 26760, 0x1, 0x4A, 0xAAAAB, 0x8B6 },
+	[ATHOS_LUT_CHAN_669125_IDX] = { 26765, 0x1, 0x4A, 0xB1C72, 0x8B6 },
+	[ATHOS_LUT_CHAN_669250_IDX] = { 26770, 0x1, 0x4A, 0xB8E39, 0x8B7 },
+	[ATHOS_LUT_CHAN_669375_IDX] = { 26775, 0x1, 0x4A, 0xC0000, 0x8B7 },
+	[ATHOS_LUT_CHAN_669500_IDX] = { 26780, 0x1, 0x4A, 0xC71C7, 0x8B8 },
+	[ATHOS_LUT_CHAN_669625_IDX] = { 26785, 0x1, 0x4A, 0xCE38E, 0x8B8 },
+	[ATHOS_LUT_CHAN_669750_IDX] = { 26790, 0x1, 0x4A, 0xD5555, 0x8B9 },
+	[ATHOS_LUT_CHAN_669875_IDX] = { 26795, 0x1, 0x4A, 0xDC71C, 0x8B9 },
+	[ATHOS_LUT_CHAN_670000_IDX] = { 26800, 0x1, 0x4A, 0xE38E4, 0x8B9 },
+	[ATHOS_LUT_CHAN_670125_IDX] = { 26805, 0x1, 0x4A, 0xEAAAB, 0x8BA },
+	[ATHOS_LUT_CHAN_670250_IDX] = { 26810, 0x1, 0x4A, 0xF1C72, 0x8BA },
+	[ATHOS_LUT_CHAN_670375_IDX] = { 26815, 0x1, 0x4A, 0xF8E39, 0x8BB },
+	[ATHOS_LUT_CHAN_670500_IDX] = { 26820, 0x1, 0x4A, 0x100000, 0x8BB },
+	[ATHOS_LUT_CHAN_670625_IDX] = { 26825, 0x1, 0x4A, 0x1071C7, 0x8BB },
+	[ATHOS_LUT_CHAN_670750_IDX] = { 26830, 0x1, 0x4A, 0x10E38E, 0x8BC },
+	[ATHOS_LUT_CHAN_670875_IDX] = { 26835, 0x1, 0x4A, 0x115555, 0x8BC },
+	[ATHOS_LUT_CHAN_671000_IDX] = { 26840, 0x1, 0x4A, 0x11C71C, 0x8BD },
+	[ATHOS_LUT_CHAN_671125_IDX] = { 26845, 0x1, 0x4A, 0x1238E4, 0x8BD },
+	[ATHOS_LUT_CHAN_671250_IDX] = { 26850, 0x1, 0x4A, 0x12AAAB, 0x8BE },
+	[ATHOS_LUT_CHAN_671375_IDX] = { 26855, 0x1, 0x4A, 0x131C72, 0x8BE },
+	[ATHOS_LUT_CHAN_671500_IDX] = { 26860, 0x1, 0x4A, 0x138E39, 0x8BE },
+	[ATHOS_LUT_CHAN_671625_IDX] = { 26865, 0x1, 0x4A, 0x140000, 0x8BF },
+	[ATHOS_LUT_CHAN_671750_IDX] = { 26870, 0x1, 0x4A, 0x1471C7, 0x8BF },
+	[ATHOS_LUT_CHAN_671875_IDX] = { 26875, 0x1, 0x4A, 0x14E38E, 0x8C0 },
+	[ATHOS_LUT_CHAN_672000_IDX] = { 26880, 0x1, 0x4A, 0x155555, 0x8C0 },
+	[ATHOS_LUT_CHAN_672125_IDX] = { 26885, 0x1, 0x4A, 0x15C71C, 0x8C0 },
+	[ATHOS_LUT_CHAN_672250_IDX] = { 26890, 0x1, 0x4A, 0x1638E4, 0x8C1 },
+	[ATHOS_LUT_CHAN_672375_IDX] = { 26895, 0x1, 0x4A, 0x16AAAB, 0x8C1 },
+	[ATHOS_LUT_CHAN_672500_IDX] = { 26900, 0x1, 0x4A, 0x171C72, 0x8C2 },
+	[ATHOS_LUT_CHAN_672625_IDX] = { 26905, 0x1, 0x4A, 0x178E39, 0x8C2 },
+	[ATHOS_LUT_CHAN_672750_IDX] = { 26910, 0x1, 0x4A, 0x180000, 0x8C3 },
+	[ATHOS_LUT_CHAN_672875_IDX] = { 26915, 0x1, 0x4A, 0x1871C7, 0x8C3 },
+	[ATHOS_LUT_CHAN_673000_IDX] = { 26920, 0x1, 0x4A, 0x18E38E, 0x8C3 },
+	[ATHOS_LUT_CHAN_673125_IDX] = { 26925, 0x1, 0x4A, 0x195555, 0x8C4 },
+	[ATHOS_LUT_CHAN_673250_IDX] = { 26930, 0x1, 0x4A, 0x19C71C, 0x8C4 },
+	[ATHOS_LUT_CHAN_673375_IDX] = { 26935, 0x1, 0x4A, 0x1A38E4, 0x8C5 },
+	[ATHOS_LUT_CHAN_673500_IDX] = { 26940, 0x1, 0x4A, 0x1AAAAB, 0x8C5 },
+	[ATHOS_LUT_CHAN_673625_IDX] = { 26945, 0x1, 0x4A, 0x1B1C72, 0x8C5 },
+	[ATHOS_LUT_CHAN_673750_IDX] = { 26950, 0x1, 0x4A, 0x1B8E39, 0x8C6 },
+	[ATHOS_LUT_CHAN_673875_IDX] = { 26955, 0x1, 0x4A, 0x1C0000, 0x8C6 },
+	[ATHOS_LUT_CHAN_674000_IDX] = { 26960, 0x1, 0x4A, 0x1C71C7, 0x8C7 },
+	[ATHOS_LUT_CHAN_674125_IDX] = { 26965, 0x1, 0x4A, 0x1CE38E, 0x8C7 },
+	[ATHOS_LUT_CHAN_674250_IDX] = { 26970, 0x1, 0x4A, 0x1D5555, 0x8C8 },
+	[ATHOS_LUT_CHAN_674375_IDX] = { 26975, 0x1, 0x4A, 0x1DC71C, 0x8C8 },
+	[ATHOS_LUT_CHAN_674500_IDX] = { 26980, 0x1, 0x4A, 0x1E38E4, 0x8C8 },
+	[ATHOS_LUT_CHAN_674625_IDX] = { 26985, 0x1, 0x4A, 0x1EAAAB, 0x8C9 },
+	[ATHOS_LUT_CHAN_674750_IDX] = { 26990, 0x1, 0x4A, 0x1F1C72, 0x8C9 },
+	[ATHOS_LUT_CHAN_674875_IDX] = { 26995, 0x1, 0x4A, 0x1F8E39, 0x8CA },
+	[ATHOS_LUT_CHAN_675000_IDX] = { 27000, 0x1, 0x4B, 0x0, 0x8CA },
+	[ATHOS_LUT_CHAN_675125_IDX] = { 27005, 0x1, 0x4B, 0x71C7, 0x8CA },
+	[ATHOS_LUT_CHAN_675250_IDX] = { 27010, 0x1, 0x4B, 0xE38E, 0x8CB },
+	[ATHOS_LUT_CHAN_675375_IDX] = { 27015, 0x1, 0x4B, 0x15555, 0x8CB },
+	[ATHOS_LUT_CHAN_675500_IDX] = { 27020, 0x1, 0x4B, 0x1C71C, 0x8CC },
+	[ATHOS_LUT_CHAN_675625_IDX] = { 27025, 0x1, 0x4B, 0x238E4, 0x8CC },
+	[ATHOS_LUT_CHAN_675750_IDX] = { 27030, 0x1, 0x4B, 0x2AAAB, 0x8CD },
+	[ATHOS_LUT_CHAN_675875_IDX] = { 27035, 0x1, 0x4B, 0x31C72, 0x8CD },
+	[ATHOS_LUT_CHAN_676000_IDX] = { 27040, 0x1, 0x4B, 0x38E39, 0x8CD },
+	[ATHOS_LUT_CHAN_676125_IDX] = { 27045, 0x1, 0x4B, 0x40000, 0x8CE },
+	[ATHOS_LUT_CHAN_676250_IDX] = { 27050, 0x1, 0x4B, 0x471C7, 0x8CE },
+	[ATHOS_LUT_CHAN_676375_IDX] = { 27055, 0x1, 0x4B, 0x4E38E, 0x8CF },
+	[ATHOS_LUT_CHAN_676500_IDX] = { 27060, 0x1, 0x4B, 0x55555, 0x8CF },
+	[ATHOS_LUT_CHAN_676625_IDX] = { 27065, 0x1, 0x4B, 0x5C71C, 0x8CF },
+	[ATHOS_LUT_CHAN_676750_IDX] = { 27070, 0x1, 0x4B, 0x638E4, 0x8D0 },
+	[ATHOS_LUT_CHAN_676875_IDX] = { 27075, 0x1, 0x4B, 0x6AAAB, 0x8D0 },
+	[ATHOS_LUT_CHAN_677000_IDX] = { 27080, 0x1, 0x4B, 0x71C72, 0x8D1 },
+	[ATHOS_LUT_CHAN_677125_IDX] = { 27085, 0x1, 0x4B, 0x78E39, 0x8D1 },
+	[ATHOS_LUT_CHAN_677250_IDX] = { 27090, 0x1, 0x4B, 0x80000, 0x8D2 },
+	[ATHOS_LUT_CHAN_677375_IDX] = { 27095, 0x1, 0x4B, 0x871C7, 0x8D2 },
+	[ATHOS_LUT_CHAN_677500_IDX] = { 27100, 0x1, 0x4B, 0x8E38E, 0x8D2 },
+	[ATHOS_LUT_CHAN_677625_IDX] = { 27105, 0x1, 0x4B, 0x95555, 0x8D3 },
+	[ATHOS_LUT_CHAN_677750_IDX] = { 27110, 0x1, 0x4B, 0x9C71C, 0x8D3 },
+	[ATHOS_LUT_CHAN_677875_IDX] = { 27115, 0x1, 0x4B, 0xA38E4, 0x8D4 },
+	[ATHOS_LUT_CHAN_678000_IDX] = { 27120, 0x1, 0x4B, 0xAAAAB, 0x8D4 },
+	[ATHOS_LUT_CHAN_678125_IDX] = { 27125, 0x1, 0x4B, 0xB1C72, 0x8D4 },
+	[ATHOS_LUT_CHAN_678250_IDX] = { 27130, 0x1, 0x4B, 0xB8E39, 0x8D5 },
+	[ATHOS_LUT_CHAN_678375_IDX] = { 27135, 0x1, 0x4B, 0xC0000, 0x8D5 },
+	[ATHOS_LUT_CHAN_678500_IDX] = { 27140, 0x1, 0x4B, 0xC71C7, 0x8D6 },
+	[ATHOS_LUT_CHAN_678625_IDX] = { 27145, 0x1, 0x4B, 0xCE38E, 0x8D6 },
+	[ATHOS_LUT_CHAN_678750_IDX] = { 27150, 0x1, 0x4B, 0xD5555, 0x8D7 },
+	[ATHOS_LUT_CHAN_678875_IDX] = { 27155, 0x1, 0x4B, 0xDC71C, 0x8D7 },
+	[ATHOS_LUT_CHAN_679000_IDX] = { 27160, 0x1, 0x4B, 0xE38E4, 0x8D7 },
+	[ATHOS_LUT_CHAN_679125_IDX] = { 27165, 0x1, 0x4B, 0xEAAAB, 0x8D8 },
+	[ATHOS_LUT_CHAN_679250_IDX] = { 27170, 0x1, 0x4B, 0xF1C72, 0x8D8 },
+	[ATHOS_LUT_CHAN_679375_IDX] = { 27175, 0x1, 0x4B, 0xF8E39, 0x8D9 },
+	[ATHOS_LUT_CHAN_679500_IDX] = { 27180, 0x1, 0x4B, 0x100000, 0x8D9 },
+	[ATHOS_LUT_CHAN_679625_IDX] = { 27185, 0x1, 0x4B, 0x1071C7, 0x8D9 },
+	[ATHOS_LUT_CHAN_679750_IDX] = { 27190, 0x1, 0x4B, 0x10E38E, 0x8DA },
+	[ATHOS_LUT_CHAN_679875_IDX] = { 27195, 0x1, 0x4B, 0x115555, 0x8DA },
+	[ATHOS_LUT_CHAN_680000_IDX] = { 27200, 0x1, 0x4B, 0x11C71C, 0x8DB },
+	[ATHOS_LUT_CHAN_680125_IDX] = { 27205, 0x1, 0x4B, 0x1238E4, 0x8DB },
+	[ATHOS_LUT_CHAN_680250_IDX] = { 27210, 0x1, 0x4B, 0x12AAAB, 0x8DC },
+	[ATHOS_LUT_CHAN_680375_IDX] = { 27215, 0x1, 0x4B, 0x131C72, 0x8DC },
+	[ATHOS_LUT_CHAN_680500_IDX] = { 27220, 0x1, 0x4B, 0x138E39, 0x8DC },
+	[ATHOS_LUT_CHAN_680625_IDX] = { 27225, 0x1, 0x4B, 0x140000, 0x8DD },
+	[ATHOS_LUT_CHAN_680750_IDX] = { 27230, 0x1, 0x4B, 0x1471C7, 0x8DD },
+	[ATHOS_LUT_CHAN_680875_IDX] = { 27235, 0x1, 0x4B, 0x14E38E, 0x8DE },
+	[ATHOS_LUT_CHAN_681000_IDX] = { 27240, 0x1, 0x4B, 0x155555, 0x8DE },
+	[ATHOS_LUT_CHAN_681125_IDX] = { 27245, 0x1, 0x4B, 0x15C71C, 0x8DE },
+	[ATHOS_LUT_CHAN_681250_IDX] = { 27250, 0x1, 0x4B, 0x1638E4, 0x8DF },
+	[ATHOS_LUT_CHAN_681375_IDX] = { 27255, 0x1, 0x4B, 0x16AAAB, 0x8DF },
+	[ATHOS_LUT_CHAN_681500_IDX] = { 27260, 0x1, 0x4B, 0x171C72, 0x8E0 },
+	[ATHOS_LUT_CHAN_681625_IDX] = { 27265, 0x1, 0x4B, 0x178E39, 0x8E0 },
+	[ATHOS_LUT_CHAN_681750_IDX] = { 27270, 0x1, 0x4B, 0x180000, 0x8E1 },
+	[ATHOS_LUT_CHAN_681875_IDX] = { 27275, 0x1, 0x4B, 0x1871C7, 0x8E1 },
+	[ATHOS_LUT_CHAN_682000_IDX] = { 27280, 0x1, 0x4B, 0x18E38E, 0x8E1 },
+	[ATHOS_LUT_CHAN_682125_IDX] = { 27285, 0x1, 0x4B, 0x195555, 0x8E2 },
+	[ATHOS_LUT_CHAN_682250_IDX] = { 27290, 0x1, 0x4B, 0x19C71C, 0x8E2 },
+	[ATHOS_LUT_CHAN_682375_IDX] = { 27295, 0x1, 0x4B, 0x1A38E4, 0x8E3 },
+	[ATHOS_LUT_CHAN_682500_IDX] = { 27300, 0x1, 0x4B, 0x1AAAAB, 0x8E3 },
+	[ATHOS_LUT_CHAN_682625_IDX] = { 27305, 0x1, 0x4B, 0x1B1C72, 0x8E3 },
+	[ATHOS_LUT_CHAN_682750_IDX] = { 27310, 0x1, 0x4B, 0x1B8E39, 0x8E4 },
+	[ATHOS_LUT_CHAN_682875_IDX] = { 27315, 0x1, 0x4B, 0x1C0000, 0x8E4 },
+	[ATHOS_LUT_CHAN_683000_IDX] = { 27320, 0x1, 0x4B, 0x1C71C7, 0x8E5 },
+	[ATHOS_LUT_CHAN_683125_IDX] = { 27325, 0x1, 0x4B, 0x1CE38E, 0x8E5 },
+	[ATHOS_LUT_CHAN_683250_IDX] = { 27330, 0x1, 0x4B, 0x1D5555, 0x8E6 },
+	[ATHOS_LUT_CHAN_683375_IDX] = { 27335, 0x1, 0x4B, 0x1DC71C, 0x8E6 },
+	[ATHOS_LUT_CHAN_683500_IDX] = { 27340, 0x1, 0x4B, 0x1E38E4, 0x8E6 },
+	[ATHOS_LUT_CHAN_683625_IDX] = { 27345, 0x1, 0x4B, 0x1EAAAB, 0x8E7 },
+	[ATHOS_LUT_CHAN_683750_IDX] = { 27350, 0x1, 0x4B, 0x1F1C72, 0x8E7 },
+	[ATHOS_LUT_CHAN_683875_IDX] = { 27355, 0x1, 0x4B, 0x1F8E39, 0x8E8 },
+	[ATHOS_LUT_CHAN_684000_IDX] = { 27360, 0x1, 0x4C, 0x0, 0x8E8 },
+	[ATHOS_LUT_CHAN_684125_IDX] = { 27365, 0x1, 0x4C, 0x71C7, 0x8E8 },
+	[ATHOS_LUT_CHAN_684250_IDX] = { 27370, 0x1, 0x4C, 0xE38E, 0x8E9 },
+	[ATHOS_LUT_CHAN_684375_IDX] = { 27375, 0x1, 0x4C, 0x15555, 0x8E9 },
+	[ATHOS_LUT_CHAN_684500_IDX] = { 27380, 0x1, 0x4C, 0x1C71C, 0x8EA },
+	[ATHOS_LUT_CHAN_684625_IDX] = { 27385, 0x1, 0x4C, 0x238E4, 0x8EA },
+	[ATHOS_LUT_CHAN_684750_IDX] = { 27390, 0x1, 0x4C, 0x2AAAB, 0x8EB },
+	[ATHOS_LUT_CHAN_684875_IDX] = { 27395, 0x1, 0x4C, 0x31C72, 0x8EB },
+	[ATHOS_LUT_CHAN_685000_IDX] = { 27400, 0x1, 0x4C, 0x38E39, 0x8EB },
+	[ATHOS_LUT_CHAN_685125_IDX] = { 27405, 0x1, 0x4C, 0x40000, 0x8EC },
+	[ATHOS_LUT_CHAN_685250_IDX] = { 27410, 0x1, 0x4C, 0x471C7, 0x8EC },
+	[ATHOS_LUT_CHAN_685375_IDX] = { 27415, 0x1, 0x4C, 0x4E38E, 0x8ED },
+	[ATHOS_LUT_CHAN_685500_IDX] = { 27420, 0x1, 0x4C, 0x55555, 0x8ED },
+	[ATHOS_LUT_CHAN_685625_IDX] = { 27425, 0x1, 0x4C, 0x5C71C, 0x8ED },
+	[ATHOS_LUT_CHAN_685750_IDX] = { 27430, 0x1, 0x4C, 0x638E4, 0x8EE },
+	[ATHOS_LUT_CHAN_685875_IDX] = { 27435, 0x1, 0x4C, 0x6AAAB, 0x8EE },
+	[ATHOS_LUT_CHAN_686000_IDX] = { 27440, 0x1, 0x4C, 0x71C72, 0x8EF },
+	[ATHOS_LUT_CHAN_686125_IDX] = { 27445, 0x1, 0x4C, 0x78E39, 0x8EF },
+	[ATHOS_LUT_CHAN_686250_IDX] = { 27450, 0x1, 0x4C, 0x80000, 0x8F0 },
+	[ATHOS_LUT_CHAN_686375_IDX] = { 27455, 0x1, 0x4C, 0x871C7, 0x8F0 },
+	[ATHOS_LUT_CHAN_686500_IDX] = { 27460, 0x1, 0x4C, 0x8E38E, 0x8F0 },
+	[ATHOS_LUT_CHAN_686625_IDX] = { 27465, 0x1, 0x4C, 0x95555, 0x8F1 },
+	[ATHOS_LUT_CHAN_686750_IDX] = { 27470, 0x1, 0x4C, 0x9C71C, 0x8F1 },
+	[ATHOS_LUT_CHAN_686875_IDX] = { 27475, 0x1, 0x4C, 0xA38E4, 0x8F2 },
+	[ATHOS_LUT_CHAN_687000_IDX] = { 27480, 0x1, 0x4C, 0xAAAAB, 0x8F2 },
+	[ATHOS_LUT_CHAN_687125_IDX] = { 27485, 0x1, 0x4C, 0xB1C72, 0x8F2 },
+	[ATHOS_LUT_CHAN_687250_IDX] = { 27490, 0x1, 0x4C, 0xB8E39, 0x8F3 },
+	[ATHOS_LUT_CHAN_687375_IDX] = { 27495, 0x1, 0x4C, 0xC0000, 0x8F3 },
+	[ATHOS_LUT_CHAN_687500_IDX] = { 27500, 0x1, 0x4C, 0xC71C7, 0x8F4 },
+	[ATHOS_LUT_CHAN_687625_IDX] = { 27505, 0x1, 0x4C, 0xCE38E, 0x8F4 },
+	[ATHOS_LUT_CHAN_687750_IDX] = { 27510, 0x1, 0x4C, 0xD5555, 0x8F5 },
+	[ATHOS_LUT_CHAN_687875_IDX] = { 27515, 0x1, 0x4C, 0xDC71C, 0x8F5 },
+	[ATHOS_LUT_CHAN_688000_IDX] = { 27520, 0x1, 0x4C, 0xE38E4, 0x8F5 },
+	[ATHOS_LUT_CHAN_688125_IDX] = { 27525, 0x1, 0x4C, 0xEAAAB, 0x8F6 },
+	[ATHOS_LUT_CHAN_688250_IDX] = { 27530, 0x1, 0x4C, 0xF1C72, 0x8F6 },
+	[ATHOS_LUT_CHAN_688375_IDX] = { 27535, 0x1, 0x4C, 0xF8E39, 0x8F7 },
+	[ATHOS_LUT_CHAN_688500_IDX] = { 27540, 0x1, 0x4C, 0x100000, 0x8F7 },
+	[ATHOS_LUT_CHAN_688625_IDX] = { 27545, 0x1, 0x4C, 0x1071C7, 0x8F7 },
+	[ATHOS_LUT_CHAN_688750_IDX] = { 27550, 0x1, 0x4C, 0x10E38E, 0x8F8 },
+	[ATHOS_LUT_CHAN_688875_IDX] = { 27555, 0x1, 0x4C, 0x115555, 0x8F8 },
+	[ATHOS_LUT_CHAN_689000_IDX] = { 27560, 0x1, 0x4C, 0x11C71C, 0x8F9 },
+	[ATHOS_LUT_CHAN_689125_IDX] = { 27565, 0x1, 0x4C, 0x1238E4, 0x8F9 },
+	[ATHOS_LUT_CHAN_689250_IDX] = { 27570, 0x1, 0x4C, 0x12AAAB, 0x8FA },
+	[ATHOS_LUT_CHAN_689375_IDX] = { 27575, 0x1, 0x4C, 0x131C72, 0x8FA },
+	[ATHOS_LUT_CHAN_689500_IDX] = { 27580, 0x1, 0x4C, 0x138E39, 0x8FA },
+	[ATHOS_LUT_CHAN_689625_IDX] = { 27585, 0x1, 0x4C, 0x140000, 0x8FB },
+	[ATHOS_LUT_CHAN_689750_IDX] = { 27590, 0x1, 0x4C, 0x1471C7, 0x8FB },
+	[ATHOS_LUT_CHAN_689875_IDX] = { 27595, 0x1, 0x4C, 0x14E38E, 0x8FC },
+	[ATHOS_LUT_CHAN_690000_IDX] = { 27600, 0x1, 0x4C, 0x155555, 0x8FC },
+	[ATHOS_LUT_CHAN_690125_IDX] = { 27605, 0x1, 0x4C, 0x15C71C, 0x8FC },
+	[ATHOS_LUT_CHAN_690250_IDX] = { 27610, 0x1, 0x4C, 0x1638E4, 0x8FD },
+	[ATHOS_LUT_CHAN_690375_IDX] = { 27615, 0x1, 0x4C, 0x16AAAB, 0x8FD },
+	[ATHOS_LUT_CHAN_690500_IDX] = { 27620, 0x1, 0x4C, 0x171C72, 0x8FE },
+	[ATHOS_LUT_CHAN_690625_IDX] = { 27625, 0x1, 0x4C, 0x178E39, 0x8FE },
+	[ATHOS_LUT_CHAN_690750_IDX] = { 27630, 0x1, 0x4C, 0x180000, 0x8FF },
+	[ATHOS_LUT_CHAN_690875_IDX] = { 27635, 0x1, 0x4C, 0x1871C7, 0x8FF },
+	[ATHOS_LUT_CHAN_691000_IDX] = { 27640, 0x1, 0x4C, 0x18E38E, 0x8FF },
+	[ATHOS_LUT_CHAN_691125_IDX] = { 27645, 0x1, 0x4C, 0x195555, 0x900 },
+	[ATHOS_LUT_CHAN_691250_IDX] = { 27650, 0x1, 0x4C, 0x19C71C, 0x900 },
+	[ATHOS_LUT_CHAN_691375_IDX] = { 27655, 0x1, 0x4C, 0x1A38E4, 0x901 },
+	[ATHOS_LUT_CHAN_691500_IDX] = { 27660, 0x1, 0x4C, 0x1AAAAB, 0x901 },
+	[ATHOS_LUT_CHAN_691625_IDX] = { 27665, 0x1, 0x4C, 0x1B1C72, 0x901 },
+	[ATHOS_LUT_CHAN_691750_IDX] = { 27670, 0x1, 0x4C, 0x1B8E39, 0x902 },
+	[ATHOS_LUT_CHAN_691875_IDX] = { 27675, 0x1, 0x4C, 0x1C0000, 0x902 },
+	[ATHOS_LUT_CHAN_692000_IDX] = { 27680, 0x1, 0x4C, 0x1C71C7, 0x903 },
+	[ATHOS_LUT_CHAN_692125_IDX] = { 27685, 0x1, 0x4C, 0x1CE38E, 0x903 },
+	[ATHOS_LUT_CHAN_692250_IDX] = { 27690, 0x1, 0x4C, 0x1D5555, 0x904 },
+	[ATHOS_LUT_CHAN_692375_IDX] = { 27695, 0x1, 0x4C, 0x1DC71C, 0x904 },
+	[ATHOS_LUT_CHAN_692500_IDX] = { 27700, 0x1, 0x4C, 0x1E38E4, 0x904 },
+	[ATHOS_LUT_CHAN_692625_IDX] = { 27705, 0x1, 0x4C, 0x1EAAAB, 0x905 },
+	[ATHOS_LUT_CHAN_692750_IDX] = { 27710, 0x1, 0x4C, 0x1F1C72, 0x905 },
+	[ATHOS_LUT_CHAN_692875_IDX] = { 27715, 0x1, 0x4C, 0x1F8E39, 0x906 },
+	[ATHOS_LUT_CHAN_693000_IDX] = { 27720, 0x1, 0x4D, 0x0, 0x906 },
+	[ATHOS_LUT_CHAN_693125_IDX] = { 27725, 0x1, 0x4D, 0x71C7, 0x906 },
+	[ATHOS_LUT_CHAN_693250_IDX] = { 27730, 0x1, 0x4D, 0xE38E, 0x907 },
+	[ATHOS_LUT_CHAN_693375_IDX] = { 27735, 0x1, 0x4D, 0x15555, 0x907 },
+	[ATHOS_LUT_CHAN_693500_IDX] = { 27740, 0x1, 0x4D, 0x1C71C, 0x908 },
+	[ATHOS_LUT_CHAN_693625_IDX] = { 27745, 0x1, 0x4D, 0x238E4, 0x908 },
+	[ATHOS_LUT_CHAN_693750_IDX] = { 27750, 0x1, 0x4D, 0x2AAAB, 0x909 },
+	[ATHOS_LUT_CHAN_693875_IDX] = { 27755, 0x1, 0x4D, 0x31C72, 0x909 },
+	[ATHOS_LUT_CHAN_694000_IDX] = { 27760, 0x1, 0x4D, 0x38E39, 0x909 },
+	[ATHOS_LUT_CHAN_694125_IDX] = { 27765, 0x1, 0x4D, 0x40000, 0x90A },
+	[ATHOS_LUT_CHAN_694250_IDX] = { 27770, 0x1, 0x4D, 0x471C7, 0x90A },
+	[ATHOS_LUT_CHAN_694375_IDX] = { 27775, 0x1, 0x4D, 0x4E38E, 0x90B },
+	[ATHOS_LUT_CHAN_694500_IDX] = { 27780, 0x1, 0x4D, 0x55555, 0x90B },
+	[ATHOS_LUT_CHAN_694625_IDX] = { 27785, 0x1, 0x4D, 0x5C71C, 0x90B },
+	[ATHOS_LUT_CHAN_694750_IDX] = { 27790, 0x1, 0x4D, 0x638E4, 0x90C },
+	[ATHOS_LUT_CHAN_694875_IDX] = { 27795, 0x1, 0x4D, 0x6AAAB, 0x90C },
+	[ATHOS_LUT_CHAN_695000_IDX] = { 27800, 0x1, 0x4D, 0x71C72, 0x90D },
+	[ATHOS_LUT_CHAN_695125_IDX] = { 27805, 0x1, 0x4D, 0x78E39, 0x90D },
+	[ATHOS_LUT_CHAN_695250_IDX] = { 27810, 0x1, 0x4D, 0x80000, 0x90E },
+	[ATHOS_LUT_CHAN_695375_IDX] = { 27815, 0x1, 0x4D, 0x871C7, 0x90E },
+	[ATHOS_LUT_CHAN_695500_IDX] = { 27820, 0x1, 0x4D, 0x8E38E, 0x90E },
+	[ATHOS_LUT_CHAN_695625_IDX] = { 27825, 0x1, 0x4D, 0x95555, 0x90F },
+	[ATHOS_LUT_CHAN_695750_IDX] = { 27830, 0x1, 0x4D, 0x9C71C, 0x90F },
+	[ATHOS_LUT_CHAN_695875_IDX] = { 27835, 0x1, 0x4D, 0xA38E4, 0x910 },
+	[ATHOS_LUT_CHAN_696000_IDX] = { 27840, 0x1, 0x4D, 0xAAAAB, 0x910 },
+	[ATHOS_LUT_CHAN_696125_IDX] = { 27845, 0x1, 0x4D, 0xB1C72, 0x910 },
+	[ATHOS_LUT_CHAN_696250_IDX] = { 27850, 0x1, 0x4D, 0xB8E39, 0x911 },
+	[ATHOS_LUT_CHAN_696375_IDX] = { 27855, 0x1, 0x4D, 0xC0000, 0x911 },
+	[ATHOS_LUT_CHAN_696500_IDX] = { 27860, 0x1, 0x4D, 0xC71C7, 0x912 },
+	[ATHOS_LUT_CHAN_696625_IDX] = { 27865, 0x1, 0x4D, 0xCE38E, 0x912 },
+	[ATHOS_LUT_CHAN_696750_IDX] = { 27870, 0x1, 0x4D, 0xD5555, 0x913 },
+	[ATHOS_LUT_CHAN_696875_IDX] = { 27875, 0x1, 0x4D, 0xDC71C, 0x913 },
+	[ATHOS_LUT_CHAN_697000_IDX] = { 27880, 0x1, 0x4D, 0xE38E4, 0x913 },
+	[ATHOS_LUT_CHAN_697125_IDX] = { 27885, 0x1, 0x4D, 0xEAAAB, 0x914 },
+	[ATHOS_LUT_CHAN_697250_IDX] = { 27890, 0x1, 0x4D, 0xF1C72, 0x914 },
+	[ATHOS_LUT_CHAN_697375_IDX] = { 27895, 0x1, 0x4D, 0xF8E39, 0x915 },
+	[ATHOS_LUT_CHAN_697500_IDX] = { 27900, 0x1, 0x4D, 0x100000, 0x915 },
+	[ATHOS_LUT_CHAN_697625_IDX] = { 27905, 0x1, 0x4D, 0x1071C7, 0x915 },
+	[ATHOS_LUT_CHAN_697750_IDX] = { 27910, 0x1, 0x4D, 0x10E38E, 0x916 },
+	[ATHOS_LUT_CHAN_697875_IDX] = { 27915, 0x1, 0x4D, 0x115555, 0x916 },
+	[ATHOS_LUT_CHAN_698000_IDX] = { 27920, 0x1, 0x4D, 0x11C71C, 0x917 },
+	[ATHOS_LUT_CHAN_698125_IDX] = { 27925, 0x1, 0x4D, 0x1238E4, 0x917 },
+	[ATHOS_LUT_CHAN_698250_IDX] = { 27930, 0x1, 0x4D, 0x12AAAB, 0x918 },
+	[ATHOS_LUT_CHAN_698375_IDX] = { 27935, 0x1, 0x4D, 0x131C72, 0x918 },
+	[ATHOS_LUT_CHAN_698500_IDX] = { 27940, 0x1, 0x4D, 0x138E39, 0x918 },
+	[ATHOS_LUT_CHAN_698625_IDX] = { 27945, 0x1, 0x4D, 0x140000, 0x919 },
+	[ATHOS_LUT_CHAN_698750_IDX] = { 27950, 0x1, 0x4D, 0x1471C7, 0x919 },
+	[ATHOS_LUT_CHAN_698875_IDX] = { 27955, 0x1, 0x4D, 0x14E38E, 0x91A },
+	[ATHOS_LUT_CHAN_699000_IDX] = { 27960, 0x1, 0x4D, 0x155555, 0x91A },
+	[ATHOS_LUT_CHAN_699125_IDX] = { 27965, 0x1, 0x4D, 0x15C71C, 0x91A },
+	[ATHOS_LUT_CHAN_699250_IDX] = { 27970, 0x1, 0x4D, 0x1638E4, 0x91B },
+	[ATHOS_LUT_CHAN_699375_IDX] = { 27975, 0x1, 0x4D, 0x16AAAB, 0x91B },
+	[ATHOS_LUT_CHAN_699500_IDX] = { 27980, 0x1, 0x4D, 0x171C72, 0x91C },
+	[ATHOS_LUT_CHAN_699625_IDX] = { 27985, 0x1, 0x4D, 0x178E39, 0x91C },
+	[ATHOS_LUT_CHAN_699750_IDX] = { 27990, 0x1, 0x4D, 0x180000, 0x91D },
+	[ATHOS_LUT_CHAN_699875_IDX] = { 27995, 0x1, 0x4D, 0x1871C7, 0x91D },
+	[ATHOS_LUT_CHAN_700000_IDX] = { 28000, 0x1, 0x4D, 0x18E38E, 0x91D },
+	[ATHOS_LUT_CHAN_700125_IDX] = { 28005, 0x1, 0x4D, 0x195555, 0x91E },
+	[ATHOS_LUT_CHAN_700250_IDX] = { 28010, 0x1, 0x4D, 0x19C71C, 0x91E },
+	[ATHOS_LUT_CHAN_700375_IDX] = { 28015, 0x1, 0x4D, 0x1A38E4, 0x91F },
+	[ATHOS_LUT_CHAN_700500_IDX] = { 28020, 0x1, 0x4D, 0x1AAAAB, 0x91F },
+	[ATHOS_LUT_CHAN_700625_IDX] = { 28025, 0x1, 0x4D, 0x1B1C72, 0x91F },
+	[ATHOS_LUT_CHAN_700750_IDX] = { 28030, 0x1, 0x4D, 0x1B8E39, 0x920 },
+	[ATHOS_LUT_CHAN_700875_IDX] = { 28035, 0x1, 0x4D, 0x1C0000, 0x920 },
+	[ATHOS_LUT_CHAN_701000_IDX] = { 28040, 0x1, 0x4D, 0x1C71C7, 0x921 },
+	[ATHOS_LUT_CHAN_701125_IDX] = { 28045, 0x1, 0x4D, 0x1CE38E, 0x921 },
+	[ATHOS_LUT_CHAN_701250_IDX] = { 28050, 0x1, 0x4D, 0x1D5555, 0x922 },
+	[ATHOS_LUT_CHAN_701375_IDX] = { 28055, 0x1, 0x4D, 0x1DC71C, 0x922 },
+	[ATHOS_LUT_CHAN_701500_IDX] = { 28060, 0x1, 0x4D, 0x1E38E4, 0x922 },
+	[ATHOS_LUT_CHAN_701625_IDX] = { 28065, 0x1, 0x4D, 0x1EAAAB, 0x923 },
+	[ATHOS_LUT_CHAN_701750_IDX] = { 28070, 0x1, 0x4D, 0x1F1C72, 0x923 },
+	[ATHOS_LUT_CHAN_701875_IDX] = { 28075, 0x1, 0x4D, 0x1F8E39, 0x924 },
+	[ATHOS_LUT_CHAN_702000_IDX] = { 28080, 0x1, 0x4E, 0x0, 0x924 },
+	[ATHOS_LUT_CHAN_702125_IDX] = { 28085, 0x1, 0x4E, 0x71C7, 0x924 },
+	[ATHOS_LUT_CHAN_702250_IDX] = { 28090, 0x1, 0x4E, 0xE38E, 0x925 },
+	[ATHOS_LUT_CHAN_702375_IDX] = { 28095, 0x1, 0x4E, 0x15555, 0x925 },
+	[ATHOS_LUT_CHAN_702500_IDX] = { 28100, 0x1, 0x4E, 0x1C71C, 0x926 },
+	[ATHOS_LUT_CHAN_702625_IDX] = { 28105, 0x1, 0x4E, 0x238E4, 0x926 },
+	[ATHOS_LUT_CHAN_702750_IDX] = { 28110, 0x1, 0x4E, 0x2AAAB, 0x927 },
+	[ATHOS_LUT_CHAN_702875_IDX] = { 28115, 0x1, 0x4E, 0x31C72, 0x927 },
+	[ATHOS_LUT_CHAN_703000_IDX] = { 28120, 0x1, 0x4E, 0x38E39, 0x927 },
+	[ATHOS_LUT_CHAN_703125_IDX] = { 28125, 0x1, 0x4E, 0x40000, 0x928 },
+	[ATHOS_LUT_CHAN_703250_IDX] = { 28130, 0x1, 0x4E, 0x471C7, 0x928 },
+	[ATHOS_LUT_CHAN_703375_IDX] = { 28135, 0x1, 0x4E, 0x4E38E, 0x929 },
+	[ATHOS_LUT_CHAN_703500_IDX] = { 28140, 0x1, 0x4E, 0x55555, 0x929 },
+	[ATHOS_LUT_CHAN_703625_IDX] = { 28145, 0x1, 0x4E, 0x5C71C, 0x929 },
+	[ATHOS_LUT_CHAN_703750_IDX] = { 28150, 0x1, 0x4E, 0x638E4, 0x92A },
+	[ATHOS_LUT_CHAN_703875_IDX] = { 28155, 0x1, 0x4E, 0x6AAAB, 0x92A },
+	[ATHOS_LUT_CHAN_704000_IDX] = { 28160, 0x1, 0x4E, 0x71C72, 0x92B },
+	[ATHOS_LUT_CHAN_704125_IDX] = { 28165, 0x1, 0x4E, 0x78E39, 0x92B },
+	[ATHOS_LUT_CHAN_704250_IDX] = { 28170, 0x1, 0x4E, 0x80000, 0x92C },
+	[ATHOS_LUT_CHAN_704375_IDX] = { 28175, 0x1, 0x4E, 0x871C7, 0x92C },
+	[ATHOS_LUT_CHAN_704500_IDX] = { 28180, 0x1, 0x4E, 0x8E38E, 0x92C },
+	[ATHOS_LUT_CHAN_704625_IDX] = { 28185, 0x1, 0x4E, 0x95555, 0x92D },
+	[ATHOS_LUT_CHAN_704750_IDX] = { 28190, 0x1, 0x4E, 0x9C71C, 0x92D },
+	[ATHOS_LUT_CHAN_704875_IDX] = { 28195, 0x1, 0x4E, 0xA38E4, 0x92E },
+	[ATHOS_LUT_CHAN_705000_IDX] = { 28200, 0x1, 0x4E, 0xAAAAB, 0x92E },
+	[ATHOS_LUT_CHAN_705125_IDX] = { 28205, 0x1, 0x4E, 0xB1C72, 0x92E },
+	[ATHOS_LUT_CHAN_705250_IDX] = { 28210, 0x1, 0x4E, 0xB8E39, 0x92F },
+	[ATHOS_LUT_CHAN_705375_IDX] = { 28215, 0x1, 0x4E, 0xC0000, 0x92F },
+	[ATHOS_LUT_CHAN_705500_IDX] = { 28220, 0x1, 0x4E, 0xC71C7, 0x930 },
+	[ATHOS_LUT_CHAN_705625_IDX] = { 28225, 0x1, 0x4E, 0xCE38E, 0x930 },
+	[ATHOS_LUT_CHAN_705750_IDX] = { 28230, 0x1, 0x4E, 0xD5555, 0x931 },
+	[ATHOS_LUT_CHAN_705875_IDX] = { 28235, 0x1, 0x4E, 0xDC71C, 0x931 },
+	[ATHOS_LUT_CHAN_706000_IDX] = { 28240, 0x1, 0x4E, 0xE38E4, 0x931 },
+	[ATHOS_LUT_CHAN_706125_IDX] = { 28245, 0x1, 0x4E, 0xEAAAB, 0x932 },
+	[ATHOS_LUT_CHAN_706250_IDX] = { 28250, 0x1, 0x4E, 0xF1C72, 0x932 },
+	[ATHOS_LUT_CHAN_706375_IDX] = { 28255, 0x1, 0x4E, 0xF8E39, 0x933 },
+	[ATHOS_LUT_CHAN_706500_IDX] = { 28260, 0x1, 0x4E, 0x100000, 0x933 },
+	[ATHOS_LUT_CHAN_706625_IDX] = { 28265, 0x1, 0x4E, 0x1071C7, 0x933 },
+	[ATHOS_LUT_CHAN_706750_IDX] = { 28270, 0x1, 0x4E, 0x10E38E, 0x934 },
+	[ATHOS_LUT_CHAN_706875_IDX] = { 28275, 0x1, 0x4E, 0x115555, 0x934 },
+	[ATHOS_LUT_CHAN_707000_IDX] = { 28280, 0x1, 0x4E, 0x11C71C, 0x935 },
+	[ATHOS_LUT_CHAN_707125_IDX] = { 28285, 0x1, 0x4E, 0x1238E4, 0x935 },
+	[ATHOS_LUT_CHAN_707250_IDX] = { 28290, 0x1, 0x4E, 0x12AAAB, 0x936 },
+	[ATHOS_LUT_CHAN_707375_IDX] = { 28295, 0x1, 0x4E, 0x131C72, 0x936 },
+	[ATHOS_LUT_CHAN_707500_IDX] = { 28300, 0x1, 0x4E, 0x138E39, 0x936 },
+	[ATHOS_LUT_CHAN_707625_IDX] = { 28305, 0x1, 0x4E, 0x140000, 0x937 },
+	[ATHOS_LUT_CHAN_707750_IDX] = { 28310, 0x1, 0x4E, 0x1471C7, 0x937 },
+	[ATHOS_LUT_CHAN_707875_IDX] = { 28315, 0x1, 0x4E, 0x14E38E, 0x938 },
+	[ATHOS_LUT_CHAN_708000_IDX] = { 28320, 0x1, 0x4E, 0x155555, 0x938 },
+	[ATHOS_LUT_CHAN_708125_IDX] = { 28325, 0x1, 0x4E, 0x15C71C, 0x938 },
+	[ATHOS_LUT_CHAN_708250_IDX] = { 28330, 0x1, 0x4E, 0x1638E4, 0x939 },
+	[ATHOS_LUT_CHAN_708375_IDX] = { 28335, 0x1, 0x4E, 0x16AAAB, 0x939 },
+	[ATHOS_LUT_CHAN_708500_IDX] = { 28340, 0x1, 0x4E, 0x171C72, 0x93A },
+	[ATHOS_LUT_CHAN_708625_IDX] = { 28345, 0x1, 0x4E, 0x178E39, 0x93A },
+	[ATHOS_LUT_CHAN_708750_IDX] = { 28350, 0x1, 0x4E, 0x180000, 0x93B },
+	[ATHOS_LUT_CHAN_708875_IDX] = { 28355, 0x1, 0x4E, 0x1871C7, 0x93B },
+	[ATHOS_LUT_CHAN_709000_IDX] = { 28360, 0x1, 0x4E, 0x18E38E, 0x93B },
+	[ATHOS_LUT_CHAN_709125_IDX] = { 28365, 0x1, 0x4E, 0x195555, 0x93C },
+	[ATHOS_LUT_CHAN_709250_IDX] = { 28370, 0x1, 0x4E, 0x19C71C, 0x93C },
+	[ATHOS_LUT_CHAN_709375_IDX] = { 28375, 0x1, 0x4E, 0x1A38E4, 0x93D },
+	[ATHOS_LUT_CHAN_709500_IDX] = { 28380, 0x1, 0x4E, 0x1AAAAB, 0x93D },
+	[ATHOS_LUT_CHAN_709625_IDX] = { 28385, 0x1, 0x4E, 0x1B1C72, 0x93D },
+	[ATHOS_LUT_CHAN_709750_IDX] = { 28390, 0x1, 0x4E, 0x1B8E39, 0x93E },
+	[ATHOS_LUT_CHAN_709875_IDX] = { 28395, 0x1, 0x4E, 0x1C0000, 0x93E },
+	[ATHOS_LUT_CHAN_710000_IDX] = { 28400, 0x1, 0x4E, 0x1C71C7, 0x93F },
+	[ATHOS_LUT_CHAN_710125_IDX] = { 28405, 0x1, 0x4E, 0x1CE38E, 0x93F },
+	[ATHOS_LUT_CHAN_710250_IDX] = { 28410, 0x1, 0x4E, 0x1D5555, 0x940 },
+	[ATHOS_LUT_CHAN_710375_IDX] = { 28415, 0x1, 0x4E, 0x1DC71C, 0x940 },
+	[ATHOS_LUT_CHAN_710500_IDX] = { 28420, 0x1, 0x4E, 0x1E38E4, 0x940 },
+	[ATHOS_LUT_CHAN_710625_IDX] = { 28425, 0x1, 0x4E, 0x1EAAAB, 0x941 },
+	[ATHOS_LUT_CHAN_710750_IDX] = { 28430, 0x1, 0x4E, 0x1F1C72, 0x941 },
+	[ATHOS_LUT_CHAN_710875_IDX] = { 28435, 0x1, 0x4E, 0x1F8E39, 0x942 },
+	[ATHOS_LUT_CHAN_711000_IDX] = { 28440, 0x1, 0x4F, 0x0, 0x942 },
+	[ATHOS_LUT_CHAN_711125_IDX] = { 28445, 0x1, 0x4F, 0x71C7, 0x942 },
+	[ATHOS_LUT_CHAN_711250_IDX] = { 28450, 0x1, 0x4F, 0xE38E, 0x943 },
+	[ATHOS_LUT_CHAN_711375_IDX] = { 28455, 0x1, 0x4F, 0x15555, 0x943 },
+	[ATHOS_LUT_CHAN_711500_IDX] = { 28460, 0x1, 0x4F, 0x1C71C, 0x944 },
+	[ATHOS_LUT_CHAN_711625_IDX] = { 28465, 0x1, 0x4F, 0x238E4, 0x944 },
+	[ATHOS_LUT_CHAN_711750_IDX] = { 28470, 0x1, 0x4F, 0x2AAAB, 0x945 },
+	[ATHOS_LUT_CHAN_711875_IDX] = { 28475, 0x1, 0x4F, 0x31C72, 0x945 },
+	[ATHOS_LUT_CHAN_712000_IDX] = { 28480, 0x1, 0x4F, 0x38E39, 0x945 },
+	[ATHOS_LUT_CHAN_712125_IDX] = { 28485, 0x1, 0x4F, 0x40000, 0x946 },
+	[ATHOS_LUT_CHAN_712250_IDX] = { 28490, 0x1, 0x4F, 0x471C7, 0x946 },
+	[ATHOS_LUT_CHAN_712375_IDX] = { 28495, 0x1, 0x4F, 0x4E38E, 0x947 },
+	[ATHOS_LUT_CHAN_712500_IDX] = { 28500, 0x1, 0x4F, 0x55555, 0x947 },
+	[ATHOS_LUT_CHAN_712625_IDX] = { 28505, 0x1, 0x4F, 0x5C71C, 0x947 },
+	[ATHOS_LUT_CHAN_712750_IDX] = { 28510, 0x1, 0x4F, 0x638E4, 0x948 },
+	[ATHOS_LUT_CHAN_712875_IDX] = { 28515, 0x1, 0x4F, 0x6AAAB, 0x948 },
+	[ATHOS_LUT_CHAN_713000_IDX] = { 28520, 0x1, 0x4F, 0x71C72, 0x949 },
+	[ATHOS_LUT_CHAN_713125_IDX] = { 28525, 0x1, 0x4F, 0x78E39, 0x949 },
+	[ATHOS_LUT_CHAN_713250_IDX] = { 28530, 0x1, 0x4F, 0x80000, 0x94A },
+	[ATHOS_LUT_CHAN_713375_IDX] = { 28535, 0x1, 0x4F, 0x871C7, 0x94A },
+	[ATHOS_LUT_CHAN_713500_IDX] = { 28540, 0x1, 0x4F, 0x8E38E, 0x94A },
+	[ATHOS_LUT_CHAN_713625_IDX] = { 28545, 0x1, 0x4F, 0x95555, 0x94B },
+	[ATHOS_LUT_CHAN_713750_IDX] = { 28550, 0x1, 0x4F, 0x9C71C, 0x94B },
+	[ATHOS_LUT_CHAN_713875_IDX] = { 28555, 0x1, 0x4F, 0xA38E4, 0x94C },
+	[ATHOS_LUT_CHAN_714000_IDX] = { 28560, 0x1, 0x4F, 0xAAAAB, 0x94C },
+	[ATHOS_LUT_CHAN_714125_IDX] = { 28565, 0x1, 0x4F, 0xB1C72, 0x94C },
+	[ATHOS_LUT_CHAN_714250_IDX] = { 28570, 0x1, 0x4F, 0xB8E39, 0x94D },
+	[ATHOS_LUT_CHAN_714375_IDX] = { 28575, 0x1, 0x4F, 0xC0000, 0x94D },
+	[ATHOS_LUT_CHAN_714500_IDX] = { 28580, 0x1, 0x4F, 0xC71C7, 0x94E },
+	[ATHOS_LUT_CHAN_714625_IDX] = { 28585, 0x1, 0x4F, 0xCE38E, 0x94E },
+	[ATHOS_LUT_CHAN_714750_IDX] = { 28590, 0x1, 0x4F, 0xD5555, 0x94F },
+	[ATHOS_LUT_CHAN_714875_IDX] = { 28595, 0x1, 0x4F, 0xDC71C, 0x94F },
+	[ATHOS_LUT_CHAN_715000_IDX] = { 28600, 0x1, 0x4F, 0xE38E4, 0x94F },
+	[ATHOS_LUT_CHAN_715125_IDX] = { 28605, 0x1, 0x4F, 0xEAAAB, 0x950 },
+	[ATHOS_LUT_CHAN_715250_IDX] = { 28610, 0x1, 0x4F, 0xF1C72, 0x950 },
+	[ATHOS_LUT_CHAN_715375_IDX] = { 28615, 0x1, 0x4F, 0xF8E39, 0x951 },
+	[ATHOS_LUT_CHAN_715500_IDX] = { 28620, 0x1, 0x4F, 0x100000, 0x951 },
+	[ATHOS_LUT_CHAN_715625_IDX] = { 28625, 0x1, 0x4F, 0x1071C7, 0x951 },
+	[ATHOS_LUT_CHAN_715750_IDX] = { 28630, 0x1, 0x4F, 0x10E38E, 0x952 },
+	[ATHOS_LUT_CHAN_715875_IDX] = { 28635, 0x1, 0x4F, 0x115555, 0x952 },
+	[ATHOS_LUT_CHAN_716000_IDX] = { 28640, 0x1, 0x4F, 0x11C71C, 0x953 },
+	[ATHOS_LUT_CHAN_716125_IDX] = { 28645, 0x1, 0x4F, 0x1238E4, 0x953 },
+	[ATHOS_LUT_CHAN_716250_IDX] = { 28650, 0x1, 0x4F, 0x12AAAB, 0x954 },
+	[ATHOS_LUT_CHAN_716375_IDX] = { 28655, 0x1, 0x4F, 0x131C72, 0x954 },
+	[ATHOS_LUT_CHAN_716500_IDX] = { 28660, 0x1, 0x4F, 0x138E39, 0x954 },
+	[ATHOS_LUT_CHAN_716625_IDX] = { 28665, 0x1, 0x4F, 0x140000, 0x955 },
+	[ATHOS_LUT_CHAN_716750_IDX] = { 28670, 0x1, 0x4F, 0x1471C7, 0x955 },
+	[ATHOS_LUT_CHAN_716875_IDX] = { 28675, 0x1, 0x4F, 0x14E38E, 0x956 },
+	[ATHOS_LUT_CHAN_717000_IDX] = { 28680, 0x1, 0x4F, 0x155555, 0x956 },
+	[ATHOS_LUT_CHAN_717125_IDX] = { 28685, 0x1, 0x4F, 0x15C71C, 0x956 },
+	[ATHOS_LUT_CHAN_717250_IDX] = { 28690, 0x1, 0x4F, 0x1638E4, 0x957 },
+	[ATHOS_LUT_CHAN_717375_IDX] = { 28695, 0x1, 0x4F, 0x16AAAB, 0x957 },
+	[ATHOS_LUT_CHAN_717500_IDX] = { 28700, 0x1, 0x4F, 0x171C72, 0x958 },
+	[ATHOS_LUT_CHAN_717625_IDX] = { 28705, 0x1, 0x4F, 0x178E39, 0x958 },
+	[ATHOS_LUT_CHAN_717750_IDX] = { 28710, 0x1, 0x4F, 0x180000, 0x959 },
+	[ATHOS_LUT_CHAN_717875_IDX] = { 28715, 0x1, 0x4F, 0x1871C7, 0x959 },
+	[ATHOS_LUT_CHAN_718000_IDX] = { 28720, 0x1, 0x4F, 0x18E38E, 0x959 },
+	[ATHOS_LUT_CHAN_718125_IDX] = { 28725, 0x1, 0x4F, 0x195555, 0x95A },
+	[ATHOS_LUT_CHAN_718250_IDX] = { 28730, 0x1, 0x4F, 0x19C71C, 0x95A },
+	[ATHOS_LUT_CHAN_718375_IDX] = { 28735, 0x1, 0x4F, 0x1A38E4, 0x95B },
+	[ATHOS_LUT_CHAN_718500_IDX] = { 28740, 0x1, 0x4F, 0x1AAAAB, 0x95B },
+	[ATHOS_LUT_CHAN_718625_IDX] = { 28745, 0x1, 0x4F, 0x1B1C72, 0x95B },
+	[ATHOS_LUT_CHAN_718750_IDX] = { 28750, 0x1, 0x4F, 0x1B8E39, 0x95C },
+	[ATHOS_LUT_CHAN_718875_IDX] = { 28755, 0x1, 0x4F, 0x1C0000, 0x95C },
+	[ATHOS_LUT_CHAN_719000_IDX] = { 28760, 0x1, 0x4F, 0x1C71C7, 0x95D },
+	[ATHOS_LUT_CHAN_719125_IDX] = { 28765, 0x1, 0x4F, 0x1CE38E, 0x95D },
+	[ATHOS_LUT_CHAN_719250_IDX] = { 28770, 0x1, 0x4F, 0x1D5555, 0x95E },
+	[ATHOS_LUT_CHAN_719375_IDX] = { 28775, 0x1, 0x4F, 0x1DC71C, 0x95E },
+	[ATHOS_LUT_CHAN_719500_IDX] = { 28780, 0x1, 0x4F, 0x1E38E4, 0x95E },
+	[ATHOS_LUT_CHAN_719625_IDX] = { 28785, 0x1, 0x4F, 0x1EAAAB, 0x95F },
+	[ATHOS_LUT_CHAN_719750_IDX] = { 28790, 0x1, 0x4F, 0x1F1C72, 0x95F },
+	[ATHOS_LUT_CHAN_719875_IDX] = { 28795, 0x1, 0x4F, 0x1F8E39, 0x960 },
+	[ATHOS_LUT_CHAN_720000_IDX] = { 28800, 0x1, 0x50, 0x0, 0x960 },
+	[ATHOS_LUT_CHAN_720125_IDX] = { 28805, 0x1, 0x50, 0x71C7, 0x960 },
+	[ATHOS_LUT_CHAN_720250_IDX] = { 28810, 0x1, 0x50, 0xE38E, 0x961 },
+	[ATHOS_LUT_CHAN_720375_IDX] = { 28815, 0x1, 0x50, 0x15555, 0x961 },
+	[ATHOS_LUT_CHAN_720500_IDX] = { 28820, 0x1, 0x50, 0x1C71C, 0x962 },
+	[ATHOS_LUT_CHAN_720625_IDX] = { 28825, 0x1, 0x50, 0x238E4, 0x962 },
+	[ATHOS_LUT_CHAN_720750_IDX] = { 28830, 0x1, 0x50, 0x2AAAB, 0x963 },
+	[ATHOS_LUT_CHAN_720875_IDX] = { 28835, 0x1, 0x50, 0x31C72, 0x963 },
+	[ATHOS_LUT_CHAN_721000_IDX] = { 28840, 0x1, 0x50, 0x38E39, 0x963 },
+	[ATHOS_LUT_CHAN_721125_IDX] = { 28845, 0x1, 0x50, 0x40000, 0x964 },
+	[ATHOS_LUT_CHAN_721250_IDX] = { 28850, 0x1, 0x50, 0x471C7, 0x964 },
+	[ATHOS_LUT_CHAN_721375_IDX] = { 28855, 0x1, 0x50, 0x4E38E, 0x965 },
+	[ATHOS_LUT_CHAN_721500_IDX] = { 28860, 0x1, 0x50, 0x55555, 0x965 }
+};
+
+const struct common_lut_line athos_b_lut_6g_40_mhz[ATHOS_B_6G_LUT_CHAN_6G_MAX] = {
+	[ATHOS_B_6G_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x62, 0x1AAAAB, 0x7B9 },
+	[ATHOS_B_6G_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x62, 0x1B5555, 0x7B9 },
+	[ATHOS_B_6G_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x62, 0x1C0000, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x62, 0x1CAAAB, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x62, 0x1D5555, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x62, 0x1E0000, 0x7BB },
+	[ATHOS_B_6G_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x62, 0x1EAAAB, 0x7BB },
+	[ATHOS_B_6G_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x62, 0x1F5555, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x63, 0x0, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x63, 0xAAAB, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x63, 0x15555, 0x7BD },
+	[ATHOS_B_6G_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x63, 0x20000, 0x7BD },
+	[ATHOS_B_6G_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x63, 0x2AAAB, 0x7BE },
+	[ATHOS_B_6G_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x63, 0x35555, 0x7BE },
+	[ATHOS_B_6G_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x63, 0x40000, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x63, 0x4AAAB, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x63, 0x55555, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_595125_IDX] = { 23805, 0x0, 0x63, 0x60000, 0x7C0 },
+	[ATHOS_B_6G_LUT_CHAN_595250_IDX] = { 23810, 0x0, 0x63, 0x6AAAB, 0x7C0 },
+	[ATHOS_B_6G_LUT_CHAN_595375_IDX] = { 23815, 0x0, 0x63, 0x75555, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595500_IDX] = { 23820, 0x0, 0x63, 0x80000, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595625_IDX] = { 23825, 0x0, 0x63, 0x8AAAB, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595750_IDX] = { 23830, 0x0, 0x63, 0x95555, 0x7C2 },
+	[ATHOS_B_6G_LUT_CHAN_595875_IDX] = { 23835, 0x0, 0x63, 0xA0000, 0x7C2 },
+	[ATHOS_B_6G_LUT_CHAN_596000_IDX] = { 23840, 0x0, 0x63, 0xAAAAB, 0x7C3 },
+	[ATHOS_B_6G_LUT_CHAN_596125_IDX] = { 23845, 0x0, 0x63, 0xB5555, 0x7C3 },
+	[ATHOS_B_6G_LUT_CHAN_596250_IDX] = { 23850, 0x0, 0x63, 0xC0000, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596375_IDX] = { 23855, 0x0, 0x63, 0xCAAAB, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596500_IDX] = { 23860, 0x0, 0x63, 0xD5555, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596625_IDX] = { 23865, 0x0, 0x63, 0xE0000, 0x7C5 },
+	[ATHOS_B_6G_LUT_CHAN_596750_IDX] = { 23870, 0x0, 0x63, 0xEAAAB, 0x7C5 },
+	[ATHOS_B_6G_LUT_CHAN_596875_IDX] = { 23875, 0x0, 0x63, 0xF5555, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597000_IDX] = { 23880, 0x0, 0x63, 0x100000, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597125_IDX] = { 23885, 0x0, 0x63, 0x10AAAB, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597250_IDX] = { 23890, 0x0, 0x63, 0x115555, 0x7C7 },
+	[ATHOS_B_6G_LUT_CHAN_597375_IDX] = { 23895, 0x0, 0x63, 0x120000, 0x7C7 },
+	[ATHOS_B_6G_LUT_CHAN_597500_IDX] = { 23900, 0x0, 0x63, 0x12AAAB, 0x7C8 },
+	[ATHOS_B_6G_LUT_CHAN_597625_IDX] = { 23905, 0x0, 0x63, 0x135555, 0x7C8 },
+	[ATHOS_B_6G_LUT_CHAN_597750_IDX] = { 23910, 0x0, 0x63, 0x140000, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_597875_IDX] = { 23915, 0x0, 0x63, 0x14AAAB, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_598000_IDX] = { 23920, 0x0, 0x63, 0x155555, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_598125_IDX] = { 23925, 0x0, 0x63, 0x160000, 0x7CA },
+	[ATHOS_B_6G_LUT_CHAN_598250_IDX] = { 23930, 0x0, 0x63, 0x16AAAB, 0x7CA },
+	[ATHOS_B_6G_LUT_CHAN_598375_IDX] = { 23935, 0x0, 0x63, 0x175555, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598500_IDX] = { 23940, 0x0, 0x63, 0x180000, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598625_IDX] = { 23945, 0x0, 0x63, 0x18AAAB, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598750_IDX] = { 23950, 0x0, 0x63, 0x195555, 0x7CC },
+	[ATHOS_B_6G_LUT_CHAN_598875_IDX] = { 23955, 0x0, 0x63, 0x1A0000, 0x7CC },
+	[ATHOS_B_6G_LUT_CHAN_599000_IDX] = { 23960, 0x0, 0x63, 0x1AAAAB, 0x7CD },
+	[ATHOS_B_6G_LUT_CHAN_599125_IDX] = { 23965, 0x0, 0x63, 0x1B5555, 0x7CD },
+	[ATHOS_B_6G_LUT_CHAN_599250_IDX] = { 23970, 0x0, 0x63, 0x1C0000, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599375_IDX] = { 23975, 0x0, 0x63, 0x1CAAAB, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599500_IDX] = { 23980, 0x0, 0x63, 0x1D5555, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599625_IDX] = { 23985, 0x0, 0x63, 0x1E0000, 0x7CF },
+	[ATHOS_B_6G_LUT_CHAN_599750_IDX] = { 23990, 0x0, 0x63, 0x1EAAAB, 0x7CF },
+	[ATHOS_B_6G_LUT_CHAN_599875_IDX] = { 23995, 0x0, 0x63, 0x1F5555, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600000_IDX] = { 24000, 0x0, 0x64, 0x0, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600125_IDX] = { 24005, 0x0, 0x64, 0xAAAB, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600250_IDX] = { 24010, 0x0, 0x64, 0x15555, 0x7D1 },
+	[ATHOS_B_6G_LUT_CHAN_600375_IDX] = { 24015, 0x0, 0x64, 0x20000, 0x7D1 },
+	[ATHOS_B_6G_LUT_CHAN_600500_IDX] = { 24020, 0x0, 0x64, 0x2AAAB, 0x7D2 },
+	[ATHOS_B_6G_LUT_CHAN_600625_IDX] = { 24025, 0x0, 0x64, 0x35555, 0x7D2 },
+	[ATHOS_B_6G_LUT_CHAN_600750_IDX] = { 24030, 0x0, 0x64, 0x40000, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_600875_IDX] = { 24035, 0x0, 0x64, 0x4AAAB, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_601000_IDX] = { 24040, 0x0, 0x64, 0x55555, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_601125_IDX] = { 24045, 0x0, 0x64, 0x60000, 0x7D4 },
+	[ATHOS_B_6G_LUT_CHAN_601250_IDX] = { 24050, 0x0, 0x64, 0x6AAAB, 0x7D4 },
+	[ATHOS_B_6G_LUT_CHAN_601375_IDX] = { 24055, 0x0, 0x64, 0x75555, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601500_IDX] = { 24060, 0x0, 0x64, 0x80000, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601625_IDX] = { 24065, 0x0, 0x64, 0x8AAAB, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601750_IDX] = { 24070, 0x0, 0x64, 0x95555, 0x7D6 },
+	[ATHOS_B_6G_LUT_CHAN_601875_IDX] = { 24075, 0x0, 0x64, 0xA0000, 0x7D6 },
+	[ATHOS_B_6G_LUT_CHAN_602000_IDX] = { 24080, 0x0, 0x64, 0xAAAAB, 0x7D7 },
+	[ATHOS_B_6G_LUT_CHAN_602125_IDX] = { 24085, 0x0, 0x64, 0xB5555, 0x7D7 },
+	[ATHOS_B_6G_LUT_CHAN_602250_IDX] = { 24090, 0x0, 0x64, 0xC0000, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602375_IDX] = { 24095, 0x0, 0x64, 0xCAAAB, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602500_IDX] = { 24100, 0x0, 0x64, 0xD5555, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602625_IDX] = { 24105, 0x0, 0x64, 0xE0000, 0x7D9 },
+	[ATHOS_B_6G_LUT_CHAN_602750_IDX] = { 24110, 0x0, 0x64, 0xEAAAB, 0x7D9 },
+	[ATHOS_B_6G_LUT_CHAN_602875_IDX] = { 24115, 0x0, 0x64, 0xF5555, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603000_IDX] = { 24120, 0x0, 0x64, 0x100000, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603125_IDX] = { 24125, 0x0, 0x64, 0x10AAAB, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603250_IDX] = { 24130, 0x0, 0x64, 0x115555, 0x7DB },
+	[ATHOS_B_6G_LUT_CHAN_603375_IDX] = { 24135, 0x0, 0x64, 0x120000, 0x7DB },
+	[ATHOS_B_6G_LUT_CHAN_603500_IDX] = { 24140, 0x0, 0x64, 0x12AAAB, 0x7DC },
+	[ATHOS_B_6G_LUT_CHAN_603625_IDX] = { 24145, 0x0, 0x64, 0x135555, 0x7DC },
+	[ATHOS_B_6G_LUT_CHAN_603750_IDX] = { 24150, 0x0, 0x64, 0x140000, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_603875_IDX] = { 24155, 0x0, 0x64, 0x14AAAB, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_604000_IDX] = { 24160, 0x0, 0x64, 0x155555, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_604125_IDX] = { 24165, 0x0, 0x64, 0x160000, 0x7DE },
+	[ATHOS_B_6G_LUT_CHAN_604250_IDX] = { 24170, 0x0, 0x64, 0x16AAAB, 0x7DE },
+	[ATHOS_B_6G_LUT_CHAN_604375_IDX] = { 24175, 0x0, 0x64, 0x175555, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604500_IDX] = { 24180, 0x0, 0x64, 0x180000, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604625_IDX] = { 24185, 0x0, 0x64, 0x18AAAB, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604750_IDX] = { 24190, 0x0, 0x64, 0x195555, 0x7E0 },
+	[ATHOS_B_6G_LUT_CHAN_604875_IDX] = { 24195, 0x0, 0x64, 0x1A0000, 0x7E0 },
+	[ATHOS_B_6G_LUT_CHAN_605000_IDX] = { 24200, 0x0, 0x64, 0x1AAAAB, 0x7E1 },
+	[ATHOS_B_6G_LUT_CHAN_605125_IDX] = { 24205, 0x0, 0x64, 0x1B5555, 0x7E1 },
+	[ATHOS_B_6G_LUT_CHAN_605250_IDX] = { 24210, 0x0, 0x64, 0x1C0000, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605375_IDX] = { 24215, 0x0, 0x64, 0x1CAAAB, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605500_IDX] = { 24220, 0x0, 0x64, 0x1D5555, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605625_IDX] = { 24225, 0x0, 0x64, 0x1E0000, 0x7E3 },
+	[ATHOS_B_6G_LUT_CHAN_605750_IDX] = { 24230, 0x0, 0x64, 0x1EAAAB, 0x7E3 },
+	[ATHOS_B_6G_LUT_CHAN_605875_IDX] = { 24235, 0x0, 0x64, 0x1F5555, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606000_IDX] = { 24240, 0x0, 0x65, 0x0, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606125_IDX] = { 24245, 0x0, 0x65, 0xAAAB, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606250_IDX] = { 24250, 0x0, 0x65, 0x15555, 0x7E5 },
+	[ATHOS_B_6G_LUT_CHAN_606375_IDX] = { 24255, 0x0, 0x65, 0x20000, 0x7E5 },
+	[ATHOS_B_6G_LUT_CHAN_606500_IDX] = { 24260, 0x0, 0x65, 0x2AAAB, 0x7E6 },
+	[ATHOS_B_6G_LUT_CHAN_606625_IDX] = { 24265, 0x0, 0x65, 0x35555, 0x7E6 },
+	[ATHOS_B_6G_LUT_CHAN_606750_IDX] = { 24270, 0x0, 0x65, 0x40000, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_606875_IDX] = { 24275, 0x0, 0x65, 0x4AAAB, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_607000_IDX] = { 24280, 0x0, 0x65, 0x55555, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_607125_IDX] = { 24285, 0x0, 0x65, 0x60000, 0x7E8 },
+	[ATHOS_B_6G_LUT_CHAN_607250_IDX] = { 24290, 0x0, 0x65, 0x6AAAB, 0x7E8 },
+	[ATHOS_B_6G_LUT_CHAN_607375_IDX] = { 24295, 0x0, 0x65, 0x75555, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607500_IDX] = { 24300, 0x0, 0x65, 0x80000, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607625_IDX] = { 24305, 0x0, 0x65, 0x8AAAB, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607750_IDX] = { 24310, 0x0, 0x65, 0x95555, 0x7EA },
+	[ATHOS_B_6G_LUT_CHAN_607875_IDX] = { 24315, 0x0, 0x65, 0xA0000, 0x7EA },
+	[ATHOS_B_6G_LUT_CHAN_608000_IDX] = { 24320, 0x0, 0x65, 0xAAAAB, 0x7EB },
+	[ATHOS_B_6G_LUT_CHAN_608125_IDX] = { 24325, 0x0, 0x65, 0xB5555, 0x7EB },
+	[ATHOS_B_6G_LUT_CHAN_608250_IDX] = { 24330, 0x0, 0x65, 0xC0000, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608375_IDX] = { 24335, 0x0, 0x65, 0xCAAAB, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608500_IDX] = { 24340, 0x0, 0x65, 0xD5555, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608625_IDX] = { 24345, 0x0, 0x65, 0xE0000, 0x7ED },
+	[ATHOS_B_6G_LUT_CHAN_608750_IDX] = { 24350, 0x0, 0x65, 0xEAAAB, 0x7ED },
+	[ATHOS_B_6G_LUT_CHAN_608875_IDX] = { 24355, 0x0, 0x65, 0xF5555, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609000_IDX] = { 24360, 0x0, 0x65, 0x100000, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609125_IDX] = { 24365, 0x0, 0x65, 0x10AAAB, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609250_IDX] = { 24370, 0x0, 0x65, 0x115555, 0x7EF },
+	[ATHOS_B_6G_LUT_CHAN_609375_IDX] = { 24375, 0x0, 0x65, 0x120000, 0x7EF },
+	[ATHOS_B_6G_LUT_CHAN_609500_IDX] = { 24380, 0x0, 0x65, 0x12AAAB, 0x7F0 },
+	[ATHOS_B_6G_LUT_CHAN_609625_IDX] = { 24385, 0x0, 0x65, 0x135555, 0x7F0 },
+	[ATHOS_B_6G_LUT_CHAN_609750_IDX] = { 24390, 0x0, 0x65, 0x140000, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_609875_IDX] = { 24395, 0x0, 0x65, 0x14AAAB, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x65, 0x155555, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x65, 0x160000, 0x7F2 },
+	[ATHOS_B_6G_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x65, 0x16AAAB, 0x7F2 },
+	[ATHOS_B_6G_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x65, 0x175555, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x65, 0x180000, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x65, 0x18AAAB, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x65, 0x195555, 0x7F4 },
+	[ATHOS_B_6G_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x65, 0x1A0000, 0x7F4 },
+	[ATHOS_B_6G_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x65, 0x1AAAAB, 0x7F5 },
+	[ATHOS_B_6G_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x65, 0x1B5555, 0x7F5 },
+	[ATHOS_B_6G_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x65, 0x1C0000, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x65, 0x1CAAAB, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x65, 0x1D5555, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x65, 0x1E0000, 0x7F7 },
+	[ATHOS_B_6G_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x65, 0x1EAAAB, 0x7F7 },
+	[ATHOS_B_6G_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x65, 0x1F5555, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x66, 0x0, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x66, 0xAAAB, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x66, 0x15555, 0x7F9 },
+	[ATHOS_B_6G_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x66, 0x20000, 0x7F9 },
+	[ATHOS_B_6G_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x66, 0x2AAAB, 0x7FA },
+	[ATHOS_B_6G_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x66, 0x35555, 0x7FA },
+	[ATHOS_B_6G_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x66, 0x40000, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x66, 0x4AAAB, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x66, 0x55555, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x66, 0x60000, 0x7FC },
+	[ATHOS_B_6G_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x66, 0x6AAAB, 0x7FC },
+	[ATHOS_B_6G_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x66, 0x75555, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x66, 0x80000, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x66, 0x8AAAB, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x66, 0x95555, 0x7FE },
+	[ATHOS_B_6G_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x66, 0xA0000, 0x7FE },
+	[ATHOS_B_6G_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x66, 0xAAAAB, 0x7FF },
+	[ATHOS_B_6G_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x66, 0xB5555, 0x7FF },
+	[ATHOS_B_6G_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x66, 0xC0000, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x66, 0xCAAAB, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x66, 0xD5555, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x66, 0xE0000, 0x801 },
+	[ATHOS_B_6G_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x66, 0xEAAAB, 0x801 },
+	[ATHOS_B_6G_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x66, 0xF5555, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x66, 0x100000, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x66, 0x10AAAB, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x66, 0x115555, 0x803 },
+	[ATHOS_B_6G_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x66, 0x120000, 0x803 },
+	[ATHOS_B_6G_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x66, 0x12AAAB, 0x804 },
+	[ATHOS_B_6G_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x66, 0x135555, 0x804 },
+	[ATHOS_B_6G_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x66, 0x140000, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x66, 0x14AAAB, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x66, 0x155555, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x66, 0x160000, 0x806 },
+	[ATHOS_B_6G_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x66, 0x16AAAB, 0x806 },
+	[ATHOS_B_6G_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x66, 0x175555, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x66, 0x180000, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x66, 0x18AAAB, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x66, 0x195555, 0x808 },
+	[ATHOS_B_6G_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x66, 0x1A0000, 0x808 },
+	[ATHOS_B_6G_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x66, 0x1AAAAB, 0x809 },
+	[ATHOS_B_6G_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x66, 0x1B5555, 0x809 },
+	[ATHOS_B_6G_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x66, 0x1C0000, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x66, 0x1CAAAB, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x66, 0x1D5555, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x66, 0x1E0000, 0x80B },
+	[ATHOS_B_6G_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x66, 0x1EAAAB, 0x80B },
+	[ATHOS_B_6G_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x66, 0x1F5555, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x67, 0x0, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x67, 0xAAAB, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x67, 0x15555, 0x80D },
+	[ATHOS_B_6G_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x67, 0x20000, 0x80D },
+	[ATHOS_B_6G_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x67, 0x2AAAB, 0x80E },
+	[ATHOS_B_6G_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x67, 0x35555, 0x80E },
+	[ATHOS_B_6G_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x67, 0x40000, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x67, 0x4AAAB, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x67, 0x55555, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x67, 0x60000, 0x810 },
+	[ATHOS_B_6G_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x67, 0x6AAAB, 0x810 },
+	[ATHOS_B_6G_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x67, 0x75555, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x67, 0x80000, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x67, 0x8AAAB, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x67, 0x95555, 0x812 },
+	[ATHOS_B_6G_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x67, 0xA0000, 0x812 },
+	[ATHOS_B_6G_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x67, 0xAAAAB, 0x813 },
+	[ATHOS_B_6G_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x67, 0xB5555, 0x813 },
+	[ATHOS_B_6G_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x67, 0xC0000, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x67, 0xCAAAB, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x67, 0xD5555, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x67, 0xE0000, 0x815 },
+	[ATHOS_B_6G_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x67, 0xEAAAB, 0x815 },
+	[ATHOS_B_6G_LUT_CHAN_620875_IDX] = { 24835, 0x1, 0x67, 0xF5555, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621000_IDX] = { 24840, 0x1, 0x67, 0x100000, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621125_IDX] = { 24845, 0x1, 0x67, 0x10AAAB, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621250_IDX] = { 24850, 0x1, 0x67, 0x115555, 0x817 },
+	[ATHOS_B_6G_LUT_CHAN_621375_IDX] = { 24855, 0x1, 0x67, 0x120000, 0x817 },
+	[ATHOS_B_6G_LUT_CHAN_621500_IDX] = { 24860, 0x1, 0x67, 0x12AAAB, 0x818 },
+	[ATHOS_B_6G_LUT_CHAN_621625_IDX] = { 24865, 0x1, 0x67, 0x135555, 0x818 },
+	[ATHOS_B_6G_LUT_CHAN_621750_IDX] = { 24870, 0x1, 0x67, 0x140000, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_621875_IDX] = { 24875, 0x1, 0x67, 0x14AAAB, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_622000_IDX] = { 24880, 0x1, 0x67, 0x155555, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_622125_IDX] = { 24885, 0x1, 0x67, 0x160000, 0x81A },
+	[ATHOS_B_6G_LUT_CHAN_622250_IDX] = { 24890, 0x1, 0x67, 0x16AAAB, 0x81A },
+	[ATHOS_B_6G_LUT_CHAN_622375_IDX] = { 24895, 0x1, 0x67, 0x175555, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622500_IDX] = { 24900, 0x1, 0x67, 0x180000, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622625_IDX] = { 24905, 0x1, 0x67, 0x18AAAB, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622750_IDX] = { 24910, 0x1, 0x67, 0x195555, 0x81C },
+	[ATHOS_B_6G_LUT_CHAN_622875_IDX] = { 24915, 0x1, 0x67, 0x1A0000, 0x81C },
+	[ATHOS_B_6G_LUT_CHAN_623000_IDX] = { 24920, 0x1, 0x67, 0x1AAAAB, 0x81D },
+	[ATHOS_B_6G_LUT_CHAN_623125_IDX] = { 24925, 0x1, 0x67, 0x1B5555, 0x81D },
+	[ATHOS_B_6G_LUT_CHAN_623250_IDX] = { 24930, 0x1, 0x67, 0x1C0000, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623375_IDX] = { 24935, 0x1, 0x67, 0x1CAAAB, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623500_IDX] = { 24940, 0x1, 0x67, 0x1D5555, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623625_IDX] = { 24945, 0x1, 0x67, 0x1E0000, 0x81F },
+	[ATHOS_B_6G_LUT_CHAN_623750_IDX] = { 24950, 0x1, 0x67, 0x1EAAAB, 0x81F },
+	[ATHOS_B_6G_LUT_CHAN_623875_IDX] = { 24955, 0x1, 0x67, 0x1F5555, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624000_IDX] = { 24960, 0x1, 0x68, 0x0, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624125_IDX] = { 24965, 0x1, 0x68, 0xAAAB, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624250_IDX] = { 24970, 0x1, 0x68, 0x15555, 0x821 },
+	[ATHOS_B_6G_LUT_CHAN_624375_IDX] = { 24975, 0x1, 0x68, 0x20000, 0x821 },
+	[ATHOS_B_6G_LUT_CHAN_624500_IDX] = { 24980, 0x1, 0x68, 0x2AAAB, 0x822 },
+	[ATHOS_B_6G_LUT_CHAN_624625_IDX] = { 24985, 0x1, 0x68, 0x35555, 0x822 },
+	[ATHOS_B_6G_LUT_CHAN_624750_IDX] = { 24990, 0x1, 0x68, 0x40000, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_624875_IDX] = { 24995, 0x1, 0x68, 0x4AAAB, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_625000_IDX] = { 25000, 0x1, 0x68, 0x55555, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_625125_IDX] = { 25005, 0x1, 0x68, 0x60000, 0x824 },
+	[ATHOS_B_6G_LUT_CHAN_625250_IDX] = { 25010, 0x1, 0x68, 0x6AAAB, 0x824 },
+	[ATHOS_B_6G_LUT_CHAN_625375_IDX] = { 25015, 0x1, 0x68, 0x75555, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625500_IDX] = { 25020, 0x1, 0x68, 0x80000, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625625_IDX] = { 25025, 0x1, 0x68, 0x8AAAB, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625750_IDX] = { 25030, 0x1, 0x68, 0x95555, 0x826 },
+	[ATHOS_B_6G_LUT_CHAN_625875_IDX] = { 25035, 0x1, 0x68, 0xA0000, 0x826 },
+	[ATHOS_B_6G_LUT_CHAN_626000_IDX] = { 25040, 0x1, 0x68, 0xAAAAB, 0x827 },
+	[ATHOS_B_6G_LUT_CHAN_626125_IDX] = { 25045, 0x1, 0x68, 0xB5555, 0x827 },
+	[ATHOS_B_6G_LUT_CHAN_626250_IDX] = { 25050, 0x1, 0x68, 0xC0000, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626375_IDX] = { 25055, 0x1, 0x68, 0xCAAAB, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626500_IDX] = { 25060, 0x1, 0x68, 0xD5555, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626625_IDX] = { 25065, 0x1, 0x68, 0xE0000, 0x829 },
+	[ATHOS_B_6G_LUT_CHAN_626750_IDX] = { 25070, 0x1, 0x68, 0xEAAAB, 0x829 },
+	[ATHOS_B_6G_LUT_CHAN_626875_IDX] = { 25075, 0x1, 0x68, 0xF5555, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627000_IDX] = { 25080, 0x1, 0x68, 0x100000, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627125_IDX] = { 25085, 0x1, 0x68, 0x10AAAB, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627250_IDX] = { 25090, 0x1, 0x68, 0x115555, 0x82B },
+	[ATHOS_B_6G_LUT_CHAN_627375_IDX] = { 25095, 0x1, 0x68, 0x120000, 0x82B },
+	[ATHOS_B_6G_LUT_CHAN_627500_IDX] = { 25100, 0x1, 0x68, 0x12AAAB, 0x82C },
+	[ATHOS_B_6G_LUT_CHAN_627625_IDX] = { 25105, 0x1, 0x68, 0x135555, 0x82C },
+	[ATHOS_B_6G_LUT_CHAN_627750_IDX] = { 25110, 0x1, 0x68, 0x140000, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_627875_IDX] = { 25115, 0x1, 0x68, 0x14AAAB, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_628000_IDX] = { 25120, 0x1, 0x68, 0x155555, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_628125_IDX] = { 25125, 0x1, 0x68, 0x160000, 0x82E },
+	[ATHOS_B_6G_LUT_CHAN_628250_IDX] = { 25130, 0x1, 0x68, 0x16AAAB, 0x82E },
+	[ATHOS_B_6G_LUT_CHAN_628375_IDX] = { 25135, 0x1, 0x68, 0x175555, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628500_IDX] = { 25140, 0x1, 0x68, 0x180000, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628625_IDX] = { 25145, 0x1, 0x68, 0x18AAAB, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628750_IDX] = { 25150, 0x1, 0x68, 0x195555, 0x830 },
+	[ATHOS_B_6G_LUT_CHAN_628875_IDX] = { 25155, 0x1, 0x68, 0x1A0000, 0x830 },
+	[ATHOS_B_6G_LUT_CHAN_629000_IDX] = { 25160, 0x1, 0x68, 0x1AAAAB, 0x831 },
+	[ATHOS_B_6G_LUT_CHAN_629125_IDX] = { 25165, 0x1, 0x68, 0x1B5555, 0x831 },
+	[ATHOS_B_6G_LUT_CHAN_629250_IDX] = { 25170, 0x1, 0x68, 0x1C0000, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629375_IDX] = { 25175, 0x1, 0x68, 0x1CAAAB, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629500_IDX] = { 25180, 0x1, 0x68, 0x1D5555, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629625_IDX] = { 25185, 0x1, 0x68, 0x1E0000, 0x833 },
+	[ATHOS_B_6G_LUT_CHAN_629750_IDX] = { 25190, 0x1, 0x68, 0x1EAAAB, 0x833 },
+	[ATHOS_B_6G_LUT_CHAN_629875_IDX] = { 25195, 0x1, 0x68, 0x1F5555, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630000_IDX] = { 25200, 0x1, 0x69, 0x0, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630125_IDX] = { 25205, 0x1, 0x69, 0xAAAB, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630250_IDX] = { 25210, 0x1, 0x69, 0x15555, 0x835 },
+	[ATHOS_B_6G_LUT_CHAN_630375_IDX] = { 25215, 0x1, 0x69, 0x20000, 0x835 },
+	[ATHOS_B_6G_LUT_CHAN_630500_IDX] = { 25220, 0x1, 0x69, 0x2AAAB, 0x836 },
+	[ATHOS_B_6G_LUT_CHAN_630625_IDX] = { 25225, 0x1, 0x69, 0x35555, 0x836 },
+	[ATHOS_B_6G_LUT_CHAN_630750_IDX] = { 25230, 0x1, 0x69, 0x40000, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_630875_IDX] = { 25235, 0x1, 0x69, 0x4AAAB, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_631000_IDX] = { 25240, 0x1, 0x69, 0x55555, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_631125_IDX] = { 25245, 0x1, 0x69, 0x60000, 0x838 },
+	[ATHOS_B_6G_LUT_CHAN_631250_IDX] = { 25250, 0x1, 0x69, 0x6AAAB, 0x838 },
+	[ATHOS_B_6G_LUT_CHAN_631375_IDX] = { 25255, 0x1, 0x69, 0x75555, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631500_IDX] = { 25260, 0x1, 0x69, 0x80000, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631625_IDX] = { 25265, 0x1, 0x69, 0x8AAAB, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631750_IDX] = { 25270, 0x1, 0x69, 0x95555, 0x83A },
+	[ATHOS_B_6G_LUT_CHAN_631875_IDX] = { 25275, 0x1, 0x69, 0xA0000, 0x83A },
+	[ATHOS_B_6G_LUT_CHAN_632000_IDX] = { 25280, 0x1, 0x69, 0xAAAAB, 0x83B },
+	[ATHOS_B_6G_LUT_CHAN_632125_IDX] = { 25285, 0x1, 0x69, 0xB5555, 0x83B },
+	[ATHOS_B_6G_LUT_CHAN_632250_IDX] = { 25290, 0x1, 0x69, 0xC0000, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632375_IDX] = { 25295, 0x1, 0x69, 0xCAAAB, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632500_IDX] = { 25300, 0x1, 0x69, 0xD5555, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632625_IDX] = { 25305, 0x1, 0x69, 0xE0000, 0x83D },
+	[ATHOS_B_6G_LUT_CHAN_632750_IDX] = { 25310, 0x1, 0x69, 0xEAAAB, 0x83D },
+	[ATHOS_B_6G_LUT_CHAN_632875_IDX] = { 25315, 0x1, 0x69, 0xF5555, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633000_IDX] = { 25320, 0x1, 0x69, 0x100000, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633125_IDX] = { 25325, 0x1, 0x69, 0x10AAAB, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633250_IDX] = { 25330, 0x1, 0x69, 0x115555, 0x83F },
+	[ATHOS_B_6G_LUT_CHAN_633375_IDX] = { 25335, 0x1, 0x69, 0x120000, 0x83F },
+	[ATHOS_B_6G_LUT_CHAN_633500_IDX] = { 25340, 0x1, 0x69, 0x12AAAB, 0x840 },
+	[ATHOS_B_6G_LUT_CHAN_633625_IDX] = { 25345, 0x1, 0x69, 0x135555, 0x840 },
+	[ATHOS_B_6G_LUT_CHAN_633750_IDX] = { 25350, 0x1, 0x69, 0x140000, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_633875_IDX] = { 25355, 0x1, 0x69, 0x14AAAB, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_634000_IDX] = { 25360, 0x1, 0x69, 0x155555, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_634125_IDX] = { 25365, 0x1, 0x69, 0x160000, 0x842 },
+	[ATHOS_B_6G_LUT_CHAN_634250_IDX] = { 25370, 0x1, 0x69, 0x16AAAB, 0x842 },
+	[ATHOS_B_6G_LUT_CHAN_634375_IDX] = { 25375, 0x1, 0x69, 0x175555, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634500_IDX] = { 25380, 0x1, 0x69, 0x180000, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634625_IDX] = { 25385, 0x1, 0x69, 0x18AAAB, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634750_IDX] = { 25390, 0x1, 0x69, 0x195555, 0x844 },
+	[ATHOS_B_6G_LUT_CHAN_634875_IDX] = { 25395, 0x1, 0x69, 0x1A0000, 0x844 },
+	[ATHOS_B_6G_LUT_CHAN_635000_IDX] = { 25400, 0x1, 0x69, 0x1AAAAB, 0x845 },
+	[ATHOS_B_6G_LUT_CHAN_635125_IDX] = { 25405, 0x1, 0x69, 0x1B5555, 0x845 },
+	[ATHOS_B_6G_LUT_CHAN_635250_IDX] = { 25410, 0x1, 0x69, 0x1C0000, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635375_IDX] = { 25415, 0x1, 0x69, 0x1CAAAB, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635500_IDX] = { 25420, 0x1, 0x69, 0x1D5555, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635625_IDX] = { 25425, 0x1, 0x69, 0x1E0000, 0x847 },
+	[ATHOS_B_6G_LUT_CHAN_635750_IDX] = { 25430, 0x1, 0x69, 0x1EAAAB, 0x847 },
+	[ATHOS_B_6G_LUT_CHAN_635875_IDX] = { 25435, 0x1, 0x69, 0x1F5555, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636000_IDX] = { 25440, 0x1, 0x6A, 0x0, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636125_IDX] = { 25445, 0x1, 0x6A, 0xAAAB, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636250_IDX] = { 25450, 0x1, 0x6A, 0x15555, 0x849 },
+	[ATHOS_B_6G_LUT_CHAN_636375_IDX] = { 25455, 0x1, 0x6A, 0x20000, 0x849 },
+	[ATHOS_B_6G_LUT_CHAN_636500_IDX] = { 25460, 0x1, 0x6A, 0x2AAAB, 0x84A },
+	[ATHOS_B_6G_LUT_CHAN_636625_IDX] = { 25465, 0x1, 0x6A, 0x35555, 0x84A },
+	[ATHOS_B_6G_LUT_CHAN_636750_IDX] = { 25470, 0x1, 0x6A, 0x40000, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_636875_IDX] = { 25475, 0x1, 0x6A, 0x4AAAB, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_637000_IDX] = { 25480, 0x1, 0x6A, 0x55555, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_637125_IDX] = { 25485, 0x1, 0x6A, 0x60000, 0x84C },
+	[ATHOS_B_6G_LUT_CHAN_637250_IDX] = { 25490, 0x1, 0x6A, 0x6AAAB, 0x84C },
+	[ATHOS_B_6G_LUT_CHAN_637375_IDX] = { 25495, 0x1, 0x6A, 0x75555, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637500_IDX] = { 25500, 0x1, 0x6A, 0x80000, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637625_IDX] = { 25505, 0x1, 0x6A, 0x8AAAB, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637750_IDX] = { 25510, 0x1, 0x6A, 0x95555, 0x84E },
+	[ATHOS_B_6G_LUT_CHAN_637875_IDX] = { 25515, 0x1, 0x6A, 0xA0000, 0x84E },
+	[ATHOS_B_6G_LUT_CHAN_638000_IDX] = { 25520, 0x1, 0x6A, 0xAAAAB, 0x84F },
+	[ATHOS_B_6G_LUT_CHAN_638125_IDX] = { 25525, 0x1, 0x6A, 0xB5555, 0x84F },
+	[ATHOS_B_6G_LUT_CHAN_638250_IDX] = { 25530, 0x1, 0x6A, 0xC0000, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638375_IDX] = { 25535, 0x1, 0x6A, 0xCAAAB, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638500_IDX] = { 25540, 0x1, 0x6A, 0xD5555, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638625_IDX] = { 25545, 0x1, 0x6A, 0xE0000, 0x851 },
+	[ATHOS_B_6G_LUT_CHAN_638750_IDX] = { 25550, 0x1, 0x6A, 0xEAAAB, 0x851 },
+	[ATHOS_B_6G_LUT_CHAN_638875_IDX] = { 25555, 0x1, 0x6A, 0xF5555, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639000_IDX] = { 25560, 0x1, 0x6A, 0x100000, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639125_IDX] = { 25565, 0x1, 0x6A, 0x10AAAB, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639250_IDX] = { 25570, 0x1, 0x6A, 0x115555, 0x853 },
+	[ATHOS_B_6G_LUT_CHAN_639375_IDX] = { 25575, 0x1, 0x6A, 0x120000, 0x853 },
+	[ATHOS_B_6G_LUT_CHAN_639500_IDX] = { 25580, 0x1, 0x6A, 0x12AAAB, 0x854 },
+	[ATHOS_B_6G_LUT_CHAN_639625_IDX] = { 25585, 0x1, 0x6A, 0x135555, 0x854 },
+	[ATHOS_B_6G_LUT_CHAN_639750_IDX] = { 25590, 0x1, 0x6A, 0x140000, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_639875_IDX] = { 25595, 0x1, 0x6A, 0x14AAAB, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_640000_IDX] = { 25600, 0x1, 0x6A, 0x155555, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_640125_IDX] = { 25605, 0x1, 0x6A, 0x160000, 0x856 },
+	[ATHOS_B_6G_LUT_CHAN_640250_IDX] = { 25610, 0x1, 0x6A, 0x16AAAB, 0x856 },
+	[ATHOS_B_6G_LUT_CHAN_640375_IDX] = { 25615, 0x1, 0x6A, 0x175555, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640500_IDX] = { 25620, 0x1, 0x6A, 0x180000, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640625_IDX] = { 25625, 0x1, 0x6A, 0x18AAAB, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640750_IDX] = { 25630, 0x1, 0x6A, 0x195555, 0x858 },
+	[ATHOS_B_6G_LUT_CHAN_640875_IDX] = { 25635, 0x1, 0x6A, 0x1A0000, 0x858 },
+	[ATHOS_B_6G_LUT_CHAN_641000_IDX] = { 25640, 0x1, 0x6A, 0x1AAAAB, 0x859 },
+	[ATHOS_B_6G_LUT_CHAN_641125_IDX] = { 25645, 0x1, 0x6A, 0x1B5555, 0x859 },
+	[ATHOS_B_6G_LUT_CHAN_641250_IDX] = { 25650, 0x1, 0x6A, 0x1C0000, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641375_IDX] = { 25655, 0x1, 0x6A, 0x1CAAAB, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641500_IDX] = { 25660, 0x1, 0x6A, 0x1D5555, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641625_IDX] = { 25665, 0x1, 0x6A, 0x1E0000, 0x85B },
+	[ATHOS_B_6G_LUT_CHAN_641750_IDX] = { 25670, 0x1, 0x6A, 0x1EAAAB, 0x85B },
+	[ATHOS_B_6G_LUT_CHAN_641875_IDX] = { 25675, 0x1, 0x6A, 0x1F5555, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642000_IDX] = { 25680, 0x1, 0x6B, 0x0, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642125_IDX] = { 25685, 0x1, 0x6B, 0xAAAB, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642250_IDX] = { 25690, 0x1, 0x6B, 0x15555, 0x85D },
+	[ATHOS_B_6G_LUT_CHAN_642375_IDX] = { 25695, 0x1, 0x6B, 0x20000, 0x85D },
+	[ATHOS_B_6G_LUT_CHAN_642500_IDX] = { 25700, 0x1, 0x6B, 0x2AAAB, 0x85E },
+	[ATHOS_B_6G_LUT_CHAN_642625_IDX] = { 25705, 0x1, 0x6B, 0x35555, 0x85E },
+	[ATHOS_B_6G_LUT_CHAN_642750_IDX] = { 25710, 0x1, 0x6B, 0x40000, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_642875_IDX] = { 25715, 0x1, 0x6B, 0x4AAAB, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_643000_IDX] = { 25720, 0x1, 0x6B, 0x55555, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_643125_IDX] = { 25725, 0x1, 0x6B, 0x60000, 0x860 },
+	[ATHOS_B_6G_LUT_CHAN_643250_IDX] = { 25730, 0x1, 0x6B, 0x6AAAB, 0x860 },
+	[ATHOS_B_6G_LUT_CHAN_643375_IDX] = { 25735, 0x1, 0x6B, 0x75555, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643500_IDX] = { 25740, 0x1, 0x6B, 0x80000, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643625_IDX] = { 25745, 0x1, 0x6B, 0x8AAAB, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643750_IDX] = { 25750, 0x1, 0x6B, 0x95555, 0x862 },
+	[ATHOS_B_6G_LUT_CHAN_643875_IDX] = { 25755, 0x1, 0x6B, 0xA0000, 0x862 },
+	[ATHOS_B_6G_LUT_CHAN_644000_IDX] = { 25760, 0x1, 0x6B, 0xAAAAB, 0x863 },
+	[ATHOS_B_6G_LUT_CHAN_644125_IDX] = { 25765, 0x1, 0x6B, 0xB5555, 0x863 },
+	[ATHOS_B_6G_LUT_CHAN_644250_IDX] = { 25770, 0x1, 0x6B, 0xC0000, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644375_IDX] = { 25775, 0x1, 0x6B, 0xCAAAB, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644500_IDX] = { 25780, 0x1, 0x6B, 0xD5555, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644625_IDX] = { 25785, 0x1, 0x6B, 0xE0000, 0x865 },
+	[ATHOS_B_6G_LUT_CHAN_644750_IDX] = { 25790, 0x1, 0x6B, 0xEAAAB, 0x865 },
+	[ATHOS_B_6G_LUT_CHAN_644875_IDX] = { 25795, 0x1, 0x6B, 0xF5555, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645000_IDX] = { 25800, 0x1, 0x6B, 0x100000, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645125_IDX] = { 25805, 0x1, 0x6B, 0x10AAAB, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645250_IDX] = { 25810, 0x1, 0x6B, 0x115555, 0x867 },
+	[ATHOS_B_6G_LUT_CHAN_645375_IDX] = { 25815, 0x1, 0x6B, 0x120000, 0x867 },
+	[ATHOS_B_6G_LUT_CHAN_645500_IDX] = { 25820, 0x1, 0x6B, 0x12AAAB, 0x868 },
+	[ATHOS_B_6G_LUT_CHAN_645625_IDX] = { 25825, 0x1, 0x6B, 0x135555, 0x868 },
+	[ATHOS_B_6G_LUT_CHAN_645750_IDX] = { 25830, 0x1, 0x6B, 0x140000, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_645875_IDX] = { 25835, 0x1, 0x6B, 0x14AAAB, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_646000_IDX] = { 25840, 0x1, 0x6B, 0x155555, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_646125_IDX] = { 25845, 0x1, 0x6B, 0x160000, 0x86A },
+	[ATHOS_B_6G_LUT_CHAN_646250_IDX] = { 25850, 0x1, 0x6B, 0x16AAAB, 0x86A },
+	[ATHOS_B_6G_LUT_CHAN_646375_IDX] = { 25855, 0x1, 0x6B, 0x175555, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646500_IDX] = { 25860, 0x1, 0x6B, 0x180000, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646625_IDX] = { 25865, 0x1, 0x6B, 0x18AAAB, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646750_IDX] = { 25870, 0x1, 0x6B, 0x195555, 0x86C },
+	[ATHOS_B_6G_LUT_CHAN_646875_IDX] = { 25875, 0x1, 0x6B, 0x1A0000, 0x86C },
+	[ATHOS_B_6G_LUT_CHAN_647000_IDX] = { 25880, 0x1, 0x6B, 0x1AAAAB, 0x86D },
+	[ATHOS_B_6G_LUT_CHAN_647125_IDX] = { 25885, 0x1, 0x6B, 0x1B5555, 0x86D },
+	[ATHOS_B_6G_LUT_CHAN_647250_IDX] = { 25890, 0x1, 0x6B, 0x1C0000, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647375_IDX] = { 25895, 0x1, 0x6B, 0x1CAAAB, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647500_IDX] = { 25900, 0x1, 0x6B, 0x1D5555, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647625_IDX] = { 25905, 0x1, 0x6B, 0x1E0000, 0x86F },
+	[ATHOS_B_6G_LUT_CHAN_647750_IDX] = { 25910, 0x1, 0x6B, 0x1EAAAB, 0x86F },
+	[ATHOS_B_6G_LUT_CHAN_647875_IDX] = { 25915, 0x1, 0x6B, 0x1F5555, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648000_IDX] = { 25920, 0x1, 0x6C, 0x0, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648125_IDX] = { 25925, 0x1, 0x6C, 0xAAAB, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648250_IDX] = { 25930, 0x1, 0x6C, 0x15555, 0x871 },
+	[ATHOS_B_6G_LUT_CHAN_648375_IDX] = { 25935, 0x1, 0x6C, 0x20000, 0x871 },
+	[ATHOS_B_6G_LUT_CHAN_648500_IDX] = { 25940, 0x1, 0x6C, 0x2AAAB, 0x872 },
+	[ATHOS_B_6G_LUT_CHAN_648625_IDX] = { 25945, 0x1, 0x6C, 0x35555, 0x872 },
+	[ATHOS_B_6G_LUT_CHAN_648750_IDX] = { 25950, 0x1, 0x6C, 0x40000, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_648875_IDX] = { 25955, 0x1, 0x6C, 0x4AAAB, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_649000_IDX] = { 25960, 0x1, 0x6C, 0x55555, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_649125_IDX] = { 25965, 0x1, 0x6C, 0x60000, 0x874 },
+	[ATHOS_B_6G_LUT_CHAN_649250_IDX] = { 25970, 0x1, 0x6C, 0x6AAAB, 0x874 },
+	[ATHOS_B_6G_LUT_CHAN_649375_IDX] = { 25975, 0x1, 0x6C, 0x75555, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649500_IDX] = { 25980, 0x1, 0x6C, 0x80000, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649625_IDX] = { 25985, 0x1, 0x6C, 0x8AAAB, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649750_IDX] = { 25990, 0x1, 0x6C, 0x95555, 0x876 },
+	[ATHOS_B_6G_LUT_CHAN_649875_IDX] = { 25995, 0x1, 0x6C, 0xA0000, 0x876 },
+	[ATHOS_B_6G_LUT_CHAN_650000_IDX] = { 26000, 0x1, 0x6C, 0xAAAAB, 0x877 },
+	[ATHOS_B_6G_LUT_CHAN_650125_IDX] = { 26005, 0x1, 0x6C, 0xB5555, 0x877 },
+	[ATHOS_B_6G_LUT_CHAN_650250_IDX] = { 26010, 0x1, 0x6C, 0xC0000, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650375_IDX] = { 26015, 0x1, 0x6C, 0xCAAAB, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650500_IDX] = { 26020, 0x1, 0x6C, 0xD5555, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650625_IDX] = { 26025, 0x1, 0x6C, 0xE0000, 0x879 },
+	[ATHOS_B_6G_LUT_CHAN_650750_IDX] = { 26030, 0x1, 0x6C, 0xEAAAB, 0x879 },
+	[ATHOS_B_6G_LUT_CHAN_650875_IDX] = { 26035, 0x1, 0x6C, 0xF5555, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651000_IDX] = { 26040, 0x1, 0x6C, 0x100000, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651125_IDX] = { 26045, 0x1, 0x6C, 0x10AAAB, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651250_IDX] = { 26050, 0x1, 0x6C, 0x115555, 0x87B },
+	[ATHOS_B_6G_LUT_CHAN_651375_IDX] = { 26055, 0x1, 0x6C, 0x120000, 0x87B },
+	[ATHOS_B_6G_LUT_CHAN_651500_IDX] = { 26060, 0x1, 0x6C, 0x12AAAB, 0x87C },
+	[ATHOS_B_6G_LUT_CHAN_651625_IDX] = { 26065, 0x1, 0x6C, 0x135555, 0x87C },
+	[ATHOS_B_6G_LUT_CHAN_651750_IDX] = { 26070, 0x1, 0x6C, 0x140000, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_651875_IDX] = { 26075, 0x1, 0x6C, 0x14AAAB, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_652000_IDX] = { 26080, 0x1, 0x6C, 0x155555, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_652125_IDX] = { 26085, 0x1, 0x6C, 0x160000, 0x87E },
+	[ATHOS_B_6G_LUT_CHAN_652250_IDX] = { 26090, 0x1, 0x6C, 0x16AAAB, 0x87E },
+	[ATHOS_B_6G_LUT_CHAN_652375_IDX] = { 26095, 0x1, 0x6C, 0x175555, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652500_IDX] = { 26100, 0x1, 0x6C, 0x180000, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652625_IDX] = { 26105, 0x1, 0x6C, 0x18AAAB, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652750_IDX] = { 26110, 0x1, 0x6C, 0x195555, 0x880 },
+	[ATHOS_B_6G_LUT_CHAN_652875_IDX] = { 26115, 0x1, 0x6C, 0x1A0000, 0x880 },
+	[ATHOS_B_6G_LUT_CHAN_653000_IDX] = { 26120, 0x1, 0x6C, 0x1AAAAB, 0x881 },
+	[ATHOS_B_6G_LUT_CHAN_653125_IDX] = { 26125, 0x1, 0x6C, 0x1B5555, 0x881 },
+	[ATHOS_B_6G_LUT_CHAN_653250_IDX] = { 26130, 0x1, 0x6C, 0x1C0000, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653375_IDX] = { 26135, 0x1, 0x6C, 0x1CAAAB, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653500_IDX] = { 26140, 0x1, 0x6C, 0x1D5555, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653625_IDX] = { 26145, 0x1, 0x6C, 0x1E0000, 0x883 },
+	[ATHOS_B_6G_LUT_CHAN_653750_IDX] = { 26150, 0x1, 0x6C, 0x1EAAAB, 0x883 },
+	[ATHOS_B_6G_LUT_CHAN_653875_IDX] = { 26155, 0x1, 0x6C, 0x1F5555, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654000_IDX] = { 26160, 0x1, 0x6D, 0x0, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654125_IDX] = { 26165, 0x1, 0x6D, 0xAAAB, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654250_IDX] = { 26170, 0x1, 0x6D, 0x15555, 0x885 },
+	[ATHOS_B_6G_LUT_CHAN_654375_IDX] = { 26175, 0x1, 0x6D, 0x20000, 0x885 },
+	[ATHOS_B_6G_LUT_CHAN_654500_IDX] = { 26180, 0x1, 0x6D, 0x2AAAB, 0x886 },
+	[ATHOS_B_6G_LUT_CHAN_654625_IDX] = { 26185, 0x1, 0x6D, 0x35555, 0x886 },
+	[ATHOS_B_6G_LUT_CHAN_654750_IDX] = { 26190, 0x1, 0x6D, 0x40000, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_654875_IDX] = { 26195, 0x1, 0x6D, 0x4AAAB, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_655000_IDX] = { 26200, 0x1, 0x6D, 0x55555, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_655125_IDX] = { 26205, 0x1, 0x6D, 0x60000, 0x888 },
+	[ATHOS_B_6G_LUT_CHAN_655250_IDX] = { 26210, 0x1, 0x6D, 0x6AAAB, 0x888 },
+	[ATHOS_B_6G_LUT_CHAN_655375_IDX] = { 26215, 0x1, 0x6D, 0x75555, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655500_IDX] = { 26220, 0x1, 0x6D, 0x80000, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655625_IDX] = { 26225, 0x1, 0x6D, 0x8AAAB, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655750_IDX] = { 26230, 0x1, 0x6D, 0x95555, 0x88A },
+	[ATHOS_B_6G_LUT_CHAN_655875_IDX] = { 26235, 0x1, 0x6D, 0xA0000, 0x88A },
+	[ATHOS_B_6G_LUT_CHAN_656000_IDX] = { 26240, 0x1, 0x6D, 0xAAAAB, 0x88B },
+	[ATHOS_B_6G_LUT_CHAN_656125_IDX] = { 26245, 0x1, 0x6D, 0xB5555, 0x88B },
+	[ATHOS_B_6G_LUT_CHAN_656250_IDX] = { 26250, 0x1, 0x6D, 0xC0000, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656375_IDX] = { 26255, 0x1, 0x6D, 0xCAAAB, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656500_IDX] = { 26260, 0x1, 0x6D, 0xD5555, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656625_IDX] = { 26265, 0x1, 0x6D, 0xE0000, 0x88D },
+	[ATHOS_B_6G_LUT_CHAN_656750_IDX] = { 26270, 0x1, 0x6D, 0xEAAAB, 0x88D },
+	[ATHOS_B_6G_LUT_CHAN_656875_IDX] = { 26275, 0x1, 0x6D, 0xF5555, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657000_IDX] = { 26280, 0x1, 0x6D, 0x100000, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657125_IDX] = { 26285, 0x1, 0x6D, 0x10AAAB, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657250_IDX] = { 26290, 0x1, 0x6D, 0x115555, 0x88F },
+	[ATHOS_B_6G_LUT_CHAN_657375_IDX] = { 26295, 0x1, 0x6D, 0x120000, 0x88F },
+	[ATHOS_B_6G_LUT_CHAN_657500_IDX] = { 26300, 0x1, 0x6D, 0x12AAAB, 0x890 },
+	[ATHOS_B_6G_LUT_CHAN_657625_IDX] = { 26305, 0x1, 0x6D, 0x135555, 0x890 },
+	[ATHOS_B_6G_LUT_CHAN_657750_IDX] = { 26310, 0x1, 0x6D, 0x140000, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_657875_IDX] = { 26315, 0x1, 0x6D, 0x14AAAB, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_658000_IDX] = { 26320, 0x1, 0x6D, 0x155555, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_658125_IDX] = { 26325, 0x1, 0x6D, 0x160000, 0x892 },
+	[ATHOS_B_6G_LUT_CHAN_658250_IDX] = { 26330, 0x1, 0x6D, 0x16AAAB, 0x892 },
+	[ATHOS_B_6G_LUT_CHAN_658375_IDX] = { 26335, 0x1, 0x6D, 0x175555, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658500_IDX] = { 26340, 0x1, 0x6D, 0x180000, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658625_IDX] = { 26345, 0x1, 0x6D, 0x18AAAB, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658750_IDX] = { 26350, 0x1, 0x6D, 0x195555, 0x894 },
+	[ATHOS_B_6G_LUT_CHAN_658875_IDX] = { 26355, 0x1, 0x6D, 0x1A0000, 0x894 },
+	[ATHOS_B_6G_LUT_CHAN_659000_IDX] = { 26360, 0x1, 0x6D, 0x1AAAAB, 0x895 },
+	[ATHOS_B_6G_LUT_CHAN_659125_IDX] = { 26365, 0x1, 0x6D, 0x1B5555, 0x895 },
+	[ATHOS_B_6G_LUT_CHAN_659250_IDX] = { 26370, 0x1, 0x6D, 0x1C0000, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659375_IDX] = { 26375, 0x1, 0x6D, 0x1CAAAB, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659500_IDX] = { 26380, 0x1, 0x6D, 0x1D5555, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659625_IDX] = { 26385, 0x1, 0x6D, 0x1E0000, 0x897 },
+	[ATHOS_B_6G_LUT_CHAN_659750_IDX] = { 26390, 0x1, 0x6D, 0x1EAAAB, 0x897 },
+	[ATHOS_B_6G_LUT_CHAN_659875_IDX] = { 26395, 0x1, 0x6D, 0x1F5555, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660000_IDX] = { 26400, 0x1, 0x6E, 0x0, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660125_IDX] = { 26405, 0x1, 0x6E, 0xAAAB, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660250_IDX] = { 26410, 0x1, 0x6E, 0x15555, 0x899 },
+	[ATHOS_B_6G_LUT_CHAN_660375_IDX] = { 26415, 0x1, 0x6E, 0x20000, 0x899 },
+	[ATHOS_B_6G_LUT_CHAN_660500_IDX] = { 26420, 0x1, 0x6E, 0x2AAAB, 0x89A },
+	[ATHOS_B_6G_LUT_CHAN_660625_IDX] = { 26425, 0x1, 0x6E, 0x35555, 0x89A },
+	[ATHOS_B_6G_LUT_CHAN_660750_IDX] = { 26430, 0x1, 0x6E, 0x40000, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_660875_IDX] = { 26435, 0x1, 0x6E, 0x4AAAB, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_661000_IDX] = { 26440, 0x1, 0x6E, 0x55555, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_661125_IDX] = { 26445, 0x1, 0x6E, 0x60000, 0x89C },
+	[ATHOS_B_6G_LUT_CHAN_661250_IDX] = { 26450, 0x1, 0x6E, 0x6AAAB, 0x89C },
+	[ATHOS_B_6G_LUT_CHAN_661375_IDX] = { 26455, 0x1, 0x6E, 0x75555, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661500_IDX] = { 26460, 0x1, 0x6E, 0x80000, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661625_IDX] = { 26465, 0x1, 0x6E, 0x8AAAB, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661750_IDX] = { 26470, 0x1, 0x6E, 0x95555, 0x89E },
+	[ATHOS_B_6G_LUT_CHAN_661875_IDX] = { 26475, 0x1, 0x6E, 0xA0000, 0x89E },
+	[ATHOS_B_6G_LUT_CHAN_662000_IDX] = { 26480, 0x1, 0x6E, 0xAAAAB, 0x89F },
+	[ATHOS_B_6G_LUT_CHAN_662125_IDX] = { 26485, 0x1, 0x6E, 0xB5555, 0x89F },
+	[ATHOS_B_6G_LUT_CHAN_662250_IDX] = { 26490, 0x1, 0x6E, 0xC0000, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662375_IDX] = { 26495, 0x1, 0x6E, 0xCAAAB, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662500_IDX] = { 26500, 0x1, 0x6E, 0xD5555, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662625_IDX] = { 26505, 0x1, 0x6E, 0xE0000, 0x8A1 },
+	[ATHOS_B_6G_LUT_CHAN_662750_IDX] = { 26510, 0x1, 0x6E, 0xEAAAB, 0x8A1 },
+	[ATHOS_B_6G_LUT_CHAN_662875_IDX] = { 26515, 0x1, 0x6E, 0xF5555, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663000_IDX] = { 26520, 0x1, 0x6E, 0x100000, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663125_IDX] = { 26525, 0x1, 0x6E, 0x10AAAB, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663250_IDX] = { 26530, 0x1, 0x6E, 0x115555, 0x8A3 },
+	[ATHOS_B_6G_LUT_CHAN_663375_IDX] = { 26535, 0x1, 0x6E, 0x120000, 0x8A3 },
+	[ATHOS_B_6G_LUT_CHAN_663500_IDX] = { 26540, 0x1, 0x6E, 0x12AAAB, 0x8A4 },
+	[ATHOS_B_6G_LUT_CHAN_663625_IDX] = { 26545, 0x1, 0x6E, 0x135555, 0x8A4 },
+	[ATHOS_B_6G_LUT_CHAN_663750_IDX] = { 26550, 0x1, 0x6E, 0x140000, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_663875_IDX] = { 26555, 0x1, 0x6E, 0x14AAAB, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_664000_IDX] = { 26560, 0x1, 0x6E, 0x155555, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_664125_IDX] = { 26565, 0x1, 0x6E, 0x160000, 0x8A6 },
+	[ATHOS_B_6G_LUT_CHAN_664250_IDX] = { 26570, 0x1, 0x6E, 0x16AAAB, 0x8A6 },
+	[ATHOS_B_6G_LUT_CHAN_664375_IDX] = { 26575, 0x1, 0x6E, 0x175555, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664500_IDX] = { 26580, 0x1, 0x6E, 0x180000, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664625_IDX] = { 26585, 0x1, 0x6E, 0x18AAAB, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664750_IDX] = { 26590, 0x1, 0x6E, 0x195555, 0x8A8 },
+	[ATHOS_B_6G_LUT_CHAN_664875_IDX] = { 26595, 0x1, 0x6E, 0x1A0000, 0x8A8 },
+	[ATHOS_B_6G_LUT_CHAN_665000_IDX] = { 26600, 0x1, 0x6E, 0x1AAAAB, 0x8A9 },
+	[ATHOS_B_6G_LUT_CHAN_665125_IDX] = { 26605, 0x1, 0x6E, 0x1B5555, 0x8A9 },
+	[ATHOS_B_6G_LUT_CHAN_665250_IDX] = { 26610, 0x1, 0x6E, 0x1C0000, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665375_IDX] = { 26615, 0x1, 0x6E, 0x1CAAAB, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665500_IDX] = { 26620, 0x1, 0x6E, 0x1D5555, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665625_IDX] = { 26625, 0x1, 0x6E, 0x1E0000, 0x8AB },
+	[ATHOS_B_6G_LUT_CHAN_665750_IDX] = { 26630, 0x1, 0x6E, 0x1EAAAB, 0x8AB },
+	[ATHOS_B_6G_LUT_CHAN_665875_IDX] = { 26635, 0x1, 0x6E, 0x1F5555, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666000_IDX] = { 26640, 0x1, 0x6F, 0x0, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666125_IDX] = { 26645, 0x1, 0x6F, 0xAAAB, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666250_IDX] = { 26650, 0x1, 0x6F, 0x15555, 0x8AD },
+	[ATHOS_B_6G_LUT_CHAN_666375_IDX] = { 26655, 0x1, 0x6F, 0x20000, 0x8AD },
+	[ATHOS_B_6G_LUT_CHAN_666500_IDX] = { 26660, 0x1, 0x6F, 0x2AAAB, 0x8AE },
+	[ATHOS_B_6G_LUT_CHAN_666625_IDX] = { 26665, 0x1, 0x6F, 0x35555, 0x8AE },
+	[ATHOS_B_6G_LUT_CHAN_666750_IDX] = { 26670, 0x1, 0x6F, 0x40000, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_666875_IDX] = { 26675, 0x1, 0x6F, 0x4AAAB, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_667000_IDX] = { 26680, 0x1, 0x6F, 0x55555, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_667125_IDX] = { 26685, 0x1, 0x6F, 0x60000, 0x8B0 },
+	[ATHOS_B_6G_LUT_CHAN_667250_IDX] = { 26690, 0x1, 0x6F, 0x6AAAB, 0x8B0 },
+	[ATHOS_B_6G_LUT_CHAN_667375_IDX] = { 26695, 0x1, 0x6F, 0x75555, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667500_IDX] = { 26700, 0x1, 0x6F, 0x80000, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667625_IDX] = { 26705, 0x1, 0x6F, 0x8AAAB, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667750_IDX] = { 26710, 0x1, 0x6F, 0x95555, 0x8B2 },
+	[ATHOS_B_6G_LUT_CHAN_667875_IDX] = { 26715, 0x1, 0x6F, 0xA0000, 0x8B2 },
+	[ATHOS_B_6G_LUT_CHAN_668000_IDX] = { 26720, 0x1, 0x6F, 0xAAAAB, 0x8B3 },
+	[ATHOS_B_6G_LUT_CHAN_668125_IDX] = { 26725, 0x1, 0x6F, 0xB5555, 0x8B3 },
+	[ATHOS_B_6G_LUT_CHAN_668250_IDX] = { 26730, 0x1, 0x6F, 0xC0000, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668375_IDX] = { 26735, 0x1, 0x6F, 0xCAAAB, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668500_IDX] = { 26740, 0x1, 0x6F, 0xD5555, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668625_IDX] = { 26745, 0x1, 0x6F, 0xE0000, 0x8B5 },
+	[ATHOS_B_6G_LUT_CHAN_668750_IDX] = { 26750, 0x1, 0x6F, 0xEAAAB, 0x8B5 },
+	[ATHOS_B_6G_LUT_CHAN_668875_IDX] = { 26755, 0x1, 0x6F, 0xF5555, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669000_IDX] = { 26760, 0x1, 0x6F, 0x100000, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669125_IDX] = { 26765, 0x1, 0x6F, 0x10AAAB, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669250_IDX] = { 26770, 0x1, 0x6F, 0x115555, 0x8B7 },
+	[ATHOS_B_6G_LUT_CHAN_669375_IDX] = { 26775, 0x1, 0x6F, 0x120000, 0x8B7 },
+	[ATHOS_B_6G_LUT_CHAN_669500_IDX] = { 26780, 0x1, 0x6F, 0x12AAAB, 0x8B8 },
+	[ATHOS_B_6G_LUT_CHAN_669625_IDX] = { 26785, 0x1, 0x6F, 0x135555, 0x8B8 },
+	[ATHOS_B_6G_LUT_CHAN_669750_IDX] = { 26790, 0x1, 0x6F, 0x140000, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_669875_IDX] = { 26795, 0x1, 0x6F, 0x14AAAB, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_670000_IDX] = { 26800, 0x1, 0x6F, 0x155555, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_670125_IDX] = { 26805, 0x1, 0x6F, 0x160000, 0x8BA },
+	[ATHOS_B_6G_LUT_CHAN_670250_IDX] = { 26810, 0x1, 0x6F, 0x16AAAB, 0x8BA },
+	[ATHOS_B_6G_LUT_CHAN_670375_IDX] = { 26815, 0x1, 0x6F, 0x175555, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670500_IDX] = { 26820, 0x1, 0x6F, 0x180000, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670625_IDX] = { 26825, 0x1, 0x6F, 0x18AAAB, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670750_IDX] = { 26830, 0x1, 0x6F, 0x195555, 0x8BC },
+	[ATHOS_B_6G_LUT_CHAN_670875_IDX] = { 26835, 0x1, 0x6F, 0x1A0000, 0x8BC },
+	[ATHOS_B_6G_LUT_CHAN_671000_IDX] = { 26840, 0x1, 0x6F, 0x1AAAAB, 0x8BD },
+	[ATHOS_B_6G_LUT_CHAN_671125_IDX] = { 26845, 0x1, 0x6F, 0x1B5555, 0x8BD },
+	[ATHOS_B_6G_LUT_CHAN_671250_IDX] = { 26850, 0x1, 0x6F, 0x1C0000, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671375_IDX] = { 26855, 0x1, 0x6F, 0x1CAAAB, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671500_IDX] = { 26860, 0x1, 0x6F, 0x1D5555, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671625_IDX] = { 26865, 0x1, 0x6F, 0x1E0000, 0x8BF },
+	[ATHOS_B_6G_LUT_CHAN_671750_IDX] = { 26870, 0x1, 0x6F, 0x1EAAAB, 0x8BF },
+	[ATHOS_B_6G_LUT_CHAN_671875_IDX] = { 26875, 0x1, 0x6F, 0x1F5555, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672000_IDX] = { 26880, 0x1, 0x70, 0x0, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672125_IDX] = { 26885, 0x1, 0x70, 0xAAAB, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672250_IDX] = { 26890, 0x1, 0x70, 0x15555, 0x8C1 },
+	[ATHOS_B_6G_LUT_CHAN_672375_IDX] = { 26895, 0x1, 0x70, 0x20000, 0x8C1 },
+	[ATHOS_B_6G_LUT_CHAN_672500_IDX] = { 26900, 0x1, 0x70, 0x2AAAB, 0x8C2 },
+	[ATHOS_B_6G_LUT_CHAN_672625_IDX] = { 26905, 0x1, 0x70, 0x35555, 0x8C2 },
+	[ATHOS_B_6G_LUT_CHAN_672750_IDX] = { 26910, 0x1, 0x70, 0x40000, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_672875_IDX] = { 26915, 0x1, 0x70, 0x4AAAB, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_673000_IDX] = { 26920, 0x1, 0x70, 0x55555, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_673125_IDX] = { 26925, 0x1, 0x70, 0x60000, 0x8C4 },
+	[ATHOS_B_6G_LUT_CHAN_673250_IDX] = { 26930, 0x1, 0x70, 0x6AAAB, 0x8C4 },
+	[ATHOS_B_6G_LUT_CHAN_673375_IDX] = { 26935, 0x1, 0x70, 0x75555, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673500_IDX] = { 26940, 0x1, 0x70, 0x80000, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673625_IDX] = { 26945, 0x1, 0x70, 0x8AAAB, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673750_IDX] = { 26950, 0x1, 0x70, 0x95555, 0x8C6 },
+	[ATHOS_B_6G_LUT_CHAN_673875_IDX] = { 26955, 0x1, 0x70, 0xA0000, 0x8C6 },
+	[ATHOS_B_6G_LUT_CHAN_674000_IDX] = { 26960, 0x1, 0x70, 0xAAAAB, 0x8C7 },
+	[ATHOS_B_6G_LUT_CHAN_674125_IDX] = { 26965, 0x1, 0x70, 0xB5555, 0x8C7 },
+	[ATHOS_B_6G_LUT_CHAN_674250_IDX] = { 26970, 0x1, 0x70, 0xC0000, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674375_IDX] = { 26975, 0x1, 0x70, 0xCAAAB, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674500_IDX] = { 26980, 0x1, 0x70, 0xD5555, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674625_IDX] = { 26985, 0x1, 0x70, 0xE0000, 0x8C9 },
+	[ATHOS_B_6G_LUT_CHAN_674750_IDX] = { 26990, 0x1, 0x70, 0xEAAAB, 0x8C9 },
+	[ATHOS_B_6G_LUT_CHAN_674875_IDX] = { 26995, 0x1, 0x70, 0xF5555, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675000_IDX] = { 27000, 0x1, 0x70, 0x100000, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675125_IDX] = { 27005, 0x1, 0x70, 0x10AAAB, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675250_IDX] = { 27010, 0x1, 0x70, 0x115555, 0x8CB },
+	[ATHOS_B_6G_LUT_CHAN_675375_IDX] = { 27015, 0x1, 0x70, 0x120000, 0x8CB },
+	[ATHOS_B_6G_LUT_CHAN_675500_IDX] = { 27020, 0x1, 0x70, 0x12AAAB, 0x8CC },
+	[ATHOS_B_6G_LUT_CHAN_675625_IDX] = { 27025, 0x1, 0x70, 0x135555, 0x8CC },
+	[ATHOS_B_6G_LUT_CHAN_675750_IDX] = { 27030, 0x1, 0x70, 0x140000, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_675875_IDX] = { 27035, 0x1, 0x70, 0x14AAAB, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_676000_IDX] = { 27040, 0x1, 0x70, 0x155555, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_676125_IDX] = { 27045, 0x1, 0x70, 0x160000, 0x8CE },
+	[ATHOS_B_6G_LUT_CHAN_676250_IDX] = { 27050, 0x1, 0x70, 0x16AAAB, 0x8CE },
+	[ATHOS_B_6G_LUT_CHAN_676375_IDX] = { 27055, 0x1, 0x70, 0x175555, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676500_IDX] = { 27060, 0x1, 0x70, 0x180000, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676625_IDX] = { 27065, 0x1, 0x70, 0x18AAAB, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676750_IDX] = { 27070, 0x1, 0x70, 0x195555, 0x8D0 },
+	[ATHOS_B_6G_LUT_CHAN_676875_IDX] = { 27075, 0x1, 0x70, 0x1A0000, 0x8D0 },
+	[ATHOS_B_6G_LUT_CHAN_677000_IDX] = { 27080, 0x1, 0x70, 0x1AAAAB, 0x8D1 },
+	[ATHOS_B_6G_LUT_CHAN_677125_IDX] = { 27085, 0x1, 0x70, 0x1B5555, 0x8D1 },
+	[ATHOS_B_6G_LUT_CHAN_677250_IDX] = { 27090, 0x1, 0x70, 0x1C0000, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677375_IDX] = { 27095, 0x1, 0x70, 0x1CAAAB, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677500_IDX] = { 27100, 0x1, 0x70, 0x1D5555, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677625_IDX] = { 27105, 0x1, 0x70, 0x1E0000, 0x8D3 },
+	[ATHOS_B_6G_LUT_CHAN_677750_IDX] = { 27110, 0x1, 0x70, 0x1EAAAB, 0x8D3 },
+	[ATHOS_B_6G_LUT_CHAN_677875_IDX] = { 27115, 0x1, 0x70, 0x1F5555, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678000_IDX] = { 27120, 0x1, 0x71, 0x0, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678125_IDX] = { 27125, 0x1, 0x71, 0xAAAB, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678250_IDX] = { 27130, 0x1, 0x71, 0x15555, 0x8D5 },
+	[ATHOS_B_6G_LUT_CHAN_678375_IDX] = { 27135, 0x1, 0x71, 0x20000, 0x8D5 },
+	[ATHOS_B_6G_LUT_CHAN_678500_IDX] = { 27140, 0x1, 0x71, 0x2AAAB, 0x8D6 },
+	[ATHOS_B_6G_LUT_CHAN_678625_IDX] = { 27145, 0x1, 0x71, 0x35555, 0x8D6 },
+	[ATHOS_B_6G_LUT_CHAN_678750_IDX] = { 27150, 0x1, 0x71, 0x40000, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_678875_IDX] = { 27155, 0x1, 0x71, 0x4AAAB, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_679000_IDX] = { 27160, 0x1, 0x71, 0x55555, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_679125_IDX] = { 27165, 0x1, 0x71, 0x60000, 0x8D8 },
+	[ATHOS_B_6G_LUT_CHAN_679250_IDX] = { 27170, 0x1, 0x71, 0x6AAAB, 0x8D8 },
+	[ATHOS_B_6G_LUT_CHAN_679375_IDX] = { 27175, 0x1, 0x71, 0x75555, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679500_IDX] = { 27180, 0x1, 0x71, 0x80000, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679625_IDX] = { 27185, 0x1, 0x71, 0x8AAAB, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679750_IDX] = { 27190, 0x1, 0x71, 0x95555, 0x8DA },
+	[ATHOS_B_6G_LUT_CHAN_679875_IDX] = { 27195, 0x1, 0x71, 0xA0000, 0x8DA },
+	[ATHOS_B_6G_LUT_CHAN_680000_IDX] = { 27200, 0x1, 0x71, 0xAAAAB, 0x8DB },
+	[ATHOS_B_6G_LUT_CHAN_680125_IDX] = { 27205, 0x1, 0x71, 0xB5555, 0x8DB },
+	[ATHOS_B_6G_LUT_CHAN_680250_IDX] = { 27210, 0x1, 0x71, 0xC0000, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680375_IDX] = { 27215, 0x1, 0x71, 0xCAAAB, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680500_IDX] = { 27220, 0x1, 0x71, 0xD5555, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680625_IDX] = { 27225, 0x1, 0x71, 0xE0000, 0x8DD },
+	[ATHOS_B_6G_LUT_CHAN_680750_IDX] = { 27230, 0x1, 0x71, 0xEAAAB, 0x8DD },
+	[ATHOS_B_6G_LUT_CHAN_680875_IDX] = { 27235, 0x1, 0x71, 0xF5555, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681000_IDX] = { 27240, 0x1, 0x71, 0x100000, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681125_IDX] = { 27245, 0x1, 0x71, 0x10AAAB, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681250_IDX] = { 27250, 0x1, 0x71, 0x115555, 0x8DF },
+	[ATHOS_B_6G_LUT_CHAN_681375_IDX] = { 27255, 0x1, 0x71, 0x120000, 0x8DF },
+	[ATHOS_B_6G_LUT_CHAN_681500_IDX] = { 27260, 0x1, 0x71, 0x12AAAB, 0x8E0 },
+	[ATHOS_B_6G_LUT_CHAN_681625_IDX] = { 27265, 0x1, 0x71, 0x135555, 0x8E0 },
+	[ATHOS_B_6G_LUT_CHAN_681750_IDX] = { 27270, 0x1, 0x71, 0x140000, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_681875_IDX] = { 27275, 0x1, 0x71, 0x14AAAB, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_682000_IDX] = { 27280, 0x1, 0x71, 0x155555, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_682125_IDX] = { 27285, 0x1, 0x71, 0x160000, 0x8E2 },
+	[ATHOS_B_6G_LUT_CHAN_682250_IDX] = { 27290, 0x1, 0x71, 0x16AAAB, 0x8E2 },
+	[ATHOS_B_6G_LUT_CHAN_682375_IDX] = { 27295, 0x1, 0x71, 0x175555, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682500_IDX] = { 27300, 0x1, 0x71, 0x180000, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682625_IDX] = { 27305, 0x1, 0x71, 0x18AAAB, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682750_IDX] = { 27310, 0x1, 0x71, 0x195555, 0x8E4 },
+	[ATHOS_B_6G_LUT_CHAN_682875_IDX] = { 27315, 0x1, 0x71, 0x1A0000, 0x8E4 },
+	[ATHOS_B_6G_LUT_CHAN_683000_IDX] = { 27320, 0x1, 0x71, 0x1AAAAB, 0x8E5 },
+	[ATHOS_B_6G_LUT_CHAN_683125_IDX] = { 27325, 0x1, 0x71, 0x1B5555, 0x8E5 },
+	[ATHOS_B_6G_LUT_CHAN_683250_IDX] = { 27330, 0x1, 0x71, 0x1C0000, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683375_IDX] = { 27335, 0x1, 0x71, 0x1CAAAB, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683500_IDX] = { 27340, 0x1, 0x71, 0x1D5555, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683625_IDX] = { 27345, 0x1, 0x71, 0x1E0000, 0x8E7 },
+	[ATHOS_B_6G_LUT_CHAN_683750_IDX] = { 27350, 0x1, 0x71, 0x1EAAAB, 0x8E7 },
+	[ATHOS_B_6G_LUT_CHAN_683875_IDX] = { 27355, 0x1, 0x71, 0x1F5555, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684000_IDX] = { 27360, 0x1, 0x72, 0x0, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684125_IDX] = { 27365, 0x1, 0x72, 0xAAAB, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684250_IDX] = { 27370, 0x1, 0x72, 0x15555, 0x8E9 },
+	[ATHOS_B_6G_LUT_CHAN_684375_IDX] = { 27375, 0x1, 0x72, 0x20000, 0x8E9 },
+	[ATHOS_B_6G_LUT_CHAN_684500_IDX] = { 27380, 0x1, 0x72, 0x2AAAB, 0x8EA },
+	[ATHOS_B_6G_LUT_CHAN_684625_IDX] = { 27385, 0x1, 0x72, 0x35555, 0x8EA },
+	[ATHOS_B_6G_LUT_CHAN_684750_IDX] = { 27390, 0x1, 0x72, 0x40000, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_684875_IDX] = { 27395, 0x1, 0x72, 0x4AAAB, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_685000_IDX] = { 27400, 0x1, 0x72, 0x55555, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_685125_IDX] = { 27405, 0x1, 0x72, 0x60000, 0x8EC },
+	[ATHOS_B_6G_LUT_CHAN_685250_IDX] = { 27410, 0x1, 0x72, 0x6AAAB, 0x8EC },
+	[ATHOS_B_6G_LUT_CHAN_685375_IDX] = { 27415, 0x1, 0x72, 0x75555, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685500_IDX] = { 27420, 0x1, 0x72, 0x80000, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685625_IDX] = { 27425, 0x1, 0x72, 0x8AAAB, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685750_IDX] = { 27430, 0x1, 0x72, 0x95555, 0x8EE },
+	[ATHOS_B_6G_LUT_CHAN_685875_IDX] = { 27435, 0x1, 0x72, 0xA0000, 0x8EE },
+	[ATHOS_B_6G_LUT_CHAN_686000_IDX] = { 27440, 0x1, 0x72, 0xAAAAB, 0x8EF },
+	[ATHOS_B_6G_LUT_CHAN_686125_IDX] = { 27445, 0x1, 0x72, 0xB5555, 0x8EF },
+	[ATHOS_B_6G_LUT_CHAN_686250_IDX] = { 27450, 0x1, 0x72, 0xC0000, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686375_IDX] = { 27455, 0x1, 0x72, 0xCAAAB, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686500_IDX] = { 27460, 0x1, 0x72, 0xD5555, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686625_IDX] = { 27465, 0x1, 0x72, 0xE0000, 0x8F1 },
+	[ATHOS_B_6G_LUT_CHAN_686750_IDX] = { 27470, 0x1, 0x72, 0xEAAAB, 0x8F1 },
+	[ATHOS_B_6G_LUT_CHAN_686875_IDX] = { 27475, 0x1, 0x72, 0xF5555, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687000_IDX] = { 27480, 0x1, 0x72, 0x100000, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687125_IDX] = { 27485, 0x1, 0x72, 0x10AAAB, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687250_IDX] = { 27490, 0x1, 0x72, 0x115555, 0x8F3 },
+	[ATHOS_B_6G_LUT_CHAN_687375_IDX] = { 27495, 0x1, 0x72, 0x120000, 0x8F3 },
+	[ATHOS_B_6G_LUT_CHAN_687500_IDX] = { 27500, 0x1, 0x72, 0x12AAAB, 0x8F4 },
+	[ATHOS_B_6G_LUT_CHAN_687625_IDX] = { 27505, 0x1, 0x72, 0x135555, 0x8F4 },
+	[ATHOS_B_6G_LUT_CHAN_687750_IDX] = { 27510, 0x1, 0x72, 0x140000, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_687875_IDX] = { 27515, 0x1, 0x72, 0x14AAAB, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_688000_IDX] = { 27520, 0x1, 0x72, 0x155555, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_688125_IDX] = { 27525, 0x1, 0x72, 0x160000, 0x8F6 },
+	[ATHOS_B_6G_LUT_CHAN_688250_IDX] = { 27530, 0x1, 0x72, 0x16AAAB, 0x8F6 },
+	[ATHOS_B_6G_LUT_CHAN_688375_IDX] = { 27535, 0x1, 0x72, 0x175555, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688500_IDX] = { 27540, 0x1, 0x72, 0x180000, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688625_IDX] = { 27545, 0x1, 0x72, 0x18AAAB, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688750_IDX] = { 27550, 0x1, 0x72, 0x195555, 0x8F8 },
+	[ATHOS_B_6G_LUT_CHAN_688875_IDX] = { 27555, 0x1, 0x72, 0x1A0000, 0x8F8 },
+	[ATHOS_B_6G_LUT_CHAN_689000_IDX] = { 27560, 0x1, 0x72, 0x1AAAAB, 0x8F9 },
+	[ATHOS_B_6G_LUT_CHAN_689125_IDX] = { 27565, 0x1, 0x72, 0x1B5555, 0x8F9 },
+	[ATHOS_B_6G_LUT_CHAN_689250_IDX] = { 27570, 0x1, 0x72, 0x1C0000, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689375_IDX] = { 27575, 0x1, 0x72, 0x1CAAAB, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689500_IDX] = { 27580, 0x1, 0x72, 0x1D5555, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689625_IDX] = { 27585, 0x1, 0x72, 0x1E0000, 0x8FB },
+	[ATHOS_B_6G_LUT_CHAN_689750_IDX] = { 27590, 0x1, 0x72, 0x1EAAAB, 0x8FB },
+	[ATHOS_B_6G_LUT_CHAN_689875_IDX] = { 27595, 0x1, 0x72, 0x1F5555, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690000_IDX] = { 27600, 0x1, 0x73, 0x0, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690125_IDX] = { 27605, 0x1, 0x73, 0xAAAB, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690250_IDX] = { 27610, 0x1, 0x73, 0x15555, 0x8FD },
+	[ATHOS_B_6G_LUT_CHAN_690375_IDX] = { 27615, 0x1, 0x73, 0x20000, 0x8FD },
+	[ATHOS_B_6G_LUT_CHAN_690500_IDX] = { 27620, 0x1, 0x73, 0x2AAAB, 0x8FE },
+	[ATHOS_B_6G_LUT_CHAN_690625_IDX] = { 27625, 0x1, 0x73, 0x35555, 0x8FE },
+	[ATHOS_B_6G_LUT_CHAN_690750_IDX] = { 27630, 0x1, 0x73, 0x40000, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_690875_IDX] = { 27635, 0x1, 0x73, 0x4AAAB, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_691000_IDX] = { 27640, 0x1, 0x73, 0x55555, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_691125_IDX] = { 27645, 0x1, 0x73, 0x60000, 0x900 },
+	[ATHOS_B_6G_LUT_CHAN_691250_IDX] = { 27650, 0x1, 0x73, 0x6AAAB, 0x900 },
+	[ATHOS_B_6G_LUT_CHAN_691375_IDX] = { 27655, 0x1, 0x73, 0x75555, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691500_IDX] = { 27660, 0x1, 0x73, 0x80000, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691625_IDX] = { 27665, 0x1, 0x73, 0x8AAAB, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691750_IDX] = { 27670, 0x1, 0x73, 0x95555, 0x902 },
+	[ATHOS_B_6G_LUT_CHAN_691875_IDX] = { 27675, 0x1, 0x73, 0xA0000, 0x902 },
+	[ATHOS_B_6G_LUT_CHAN_692000_IDX] = { 27680, 0x1, 0x73, 0xAAAAB, 0x903 },
+	[ATHOS_B_6G_LUT_CHAN_692125_IDX] = { 27685, 0x1, 0x73, 0xB5555, 0x903 },
+	[ATHOS_B_6G_LUT_CHAN_692250_IDX] = { 27690, 0x1, 0x73, 0xC0000, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692375_IDX] = { 27695, 0x1, 0x73, 0xCAAAB, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692500_IDX] = { 27700, 0x1, 0x73, 0xD5555, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692625_IDX] = { 27705, 0x1, 0x73, 0xE0000, 0x905 },
+	[ATHOS_B_6G_LUT_CHAN_692750_IDX] = { 27710, 0x1, 0x73, 0xEAAAB, 0x905 },
+	[ATHOS_B_6G_LUT_CHAN_692875_IDX] = { 27715, 0x1, 0x73, 0xF5555, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693000_IDX] = { 27720, 0x1, 0x73, 0x100000, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693125_IDX] = { 27725, 0x1, 0x73, 0x10AAAB, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693250_IDX] = { 27730, 0x1, 0x73, 0x115555, 0x907 },
+	[ATHOS_B_6G_LUT_CHAN_693375_IDX] = { 27735, 0x1, 0x73, 0x120000, 0x907 },
+	[ATHOS_B_6G_LUT_CHAN_693500_IDX] = { 27740, 0x1, 0x73, 0x12AAAB, 0x908 },
+	[ATHOS_B_6G_LUT_CHAN_693625_IDX] = { 27745, 0x1, 0x73, 0x135555, 0x908 },
+	[ATHOS_B_6G_LUT_CHAN_693750_IDX] = { 27750, 0x1, 0x73, 0x140000, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_693875_IDX] = { 27755, 0x1, 0x73, 0x14AAAB, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_694000_IDX] = { 27760, 0x1, 0x73, 0x155555, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_694125_IDX] = { 27765, 0x1, 0x73, 0x160000, 0x90A },
+	[ATHOS_B_6G_LUT_CHAN_694250_IDX] = { 27770, 0x1, 0x73, 0x16AAAB, 0x90A },
+	[ATHOS_B_6G_LUT_CHAN_694375_IDX] = { 27775, 0x1, 0x73, 0x175555, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694500_IDX] = { 27780, 0x1, 0x73, 0x180000, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694625_IDX] = { 27785, 0x1, 0x73, 0x18AAAB, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694750_IDX] = { 27790, 0x1, 0x73, 0x195555, 0x90C },
+	[ATHOS_B_6G_LUT_CHAN_694875_IDX] = { 27795, 0x1, 0x73, 0x1A0000, 0x90C },
+	[ATHOS_B_6G_LUT_CHAN_695000_IDX] = { 27800, 0x1, 0x73, 0x1AAAAB, 0x90D },
+	[ATHOS_B_6G_LUT_CHAN_695125_IDX] = { 27805, 0x1, 0x73, 0x1B5555, 0x90D },
+	[ATHOS_B_6G_LUT_CHAN_695250_IDX] = { 27810, 0x1, 0x73, 0x1C0000, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695375_IDX] = { 27815, 0x1, 0x73, 0x1CAAAB, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695500_IDX] = { 27820, 0x1, 0x73, 0x1D5555, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695625_IDX] = { 27825, 0x1, 0x73, 0x1E0000, 0x90F },
+	[ATHOS_B_6G_LUT_CHAN_695750_IDX] = { 27830, 0x1, 0x73, 0x1EAAAB, 0x90F },
+	[ATHOS_B_6G_LUT_CHAN_695875_IDX] = { 27835, 0x1, 0x73, 0x1F5555, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696000_IDX] = { 27840, 0x1, 0x74, 0x0, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696125_IDX] = { 27845, 0x1, 0x74, 0xAAAB, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696250_IDX] = { 27850, 0x1, 0x74, 0x15555, 0x911 },
+	[ATHOS_B_6G_LUT_CHAN_696375_IDX] = { 27855, 0x1, 0x74, 0x20000, 0x911 },
+	[ATHOS_B_6G_LUT_CHAN_696500_IDX] = { 27860, 0x1, 0x74, 0x2AAAB, 0x912 },
+	[ATHOS_B_6G_LUT_CHAN_696625_IDX] = { 27865, 0x1, 0x74, 0x35555, 0x912 },
+	[ATHOS_B_6G_LUT_CHAN_696750_IDX] = { 27870, 0x1, 0x74, 0x40000, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_696875_IDX] = { 27875, 0x1, 0x74, 0x4AAAB, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_697000_IDX] = { 27880, 0x1, 0x74, 0x55555, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_697125_IDX] = { 27885, 0x1, 0x74, 0x60000, 0x914 },
+	[ATHOS_B_6G_LUT_CHAN_697250_IDX] = { 27890, 0x1, 0x74, 0x6AAAB, 0x914 },
+	[ATHOS_B_6G_LUT_CHAN_697375_IDX] = { 27895, 0x1, 0x74, 0x75555, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697500_IDX] = { 27900, 0x1, 0x74, 0x80000, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697625_IDX] = { 27905, 0x1, 0x74, 0x8AAAB, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697750_IDX] = { 27910, 0x1, 0x74, 0x95555, 0x916 },
+	[ATHOS_B_6G_LUT_CHAN_697875_IDX] = { 27915, 0x1, 0x74, 0xA0000, 0x916 },
+	[ATHOS_B_6G_LUT_CHAN_698000_IDX] = { 27920, 0x1, 0x74, 0xAAAAB, 0x917 },
+	[ATHOS_B_6G_LUT_CHAN_698125_IDX] = { 27925, 0x1, 0x74, 0xB5555, 0x917 },
+	[ATHOS_B_6G_LUT_CHAN_698250_IDX] = { 27930, 0x1, 0x74, 0xC0000, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698375_IDX] = { 27935, 0x1, 0x74, 0xCAAAB, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698500_IDX] = { 27940, 0x1, 0x74, 0xD5555, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698625_IDX] = { 27945, 0x1, 0x74, 0xE0000, 0x919 },
+	[ATHOS_B_6G_LUT_CHAN_698750_IDX] = { 27950, 0x1, 0x74, 0xEAAAB, 0x919 },
+	[ATHOS_B_6G_LUT_CHAN_698875_IDX] = { 27955, 0x1, 0x74, 0xF5555, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699000_IDX] = { 27960, 0x1, 0x74, 0x100000, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699125_IDX] = { 27965, 0x1, 0x74, 0x10AAAB, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699250_IDX] = { 27970, 0x1, 0x74, 0x115555, 0x91B },
+	[ATHOS_B_6G_LUT_CHAN_699375_IDX] = { 27975, 0x1, 0x74, 0x120000, 0x91B },
+	[ATHOS_B_6G_LUT_CHAN_699500_IDX] = { 27980, 0x1, 0x74, 0x12AAAB, 0x91C },
+	[ATHOS_B_6G_LUT_CHAN_699625_IDX] = { 27985, 0x1, 0x74, 0x135555, 0x91C },
+	[ATHOS_B_6G_LUT_CHAN_699750_IDX] = { 27990, 0x1, 0x74, 0x140000, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_699875_IDX] = { 27995, 0x1, 0x74, 0x14AAAB, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_700000_IDX] = { 28000, 0x1, 0x74, 0x155555, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_700125_IDX] = { 28005, 0x1, 0x74, 0x160000, 0x91E },
+	[ATHOS_B_6G_LUT_CHAN_700250_IDX] = { 28010, 0x1, 0x74, 0x16AAAB, 0x91E },
+	[ATHOS_B_6G_LUT_CHAN_700375_IDX] = { 28015, 0x1, 0x74, 0x175555, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700500_IDX] = { 28020, 0x1, 0x74, 0x180000, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700625_IDX] = { 28025, 0x1, 0x74, 0x18AAAB, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700750_IDX] = { 28030, 0x1, 0x74, 0x195555, 0x920 },
+	[ATHOS_B_6G_LUT_CHAN_700875_IDX] = { 28035, 0x1, 0x74, 0x1A0000, 0x920 },
+	[ATHOS_B_6G_LUT_CHAN_701000_IDX] = { 28040, 0x1, 0x74, 0x1AAAAB, 0x921 },
+	[ATHOS_B_6G_LUT_CHAN_701125_IDX] = { 28045, 0x1, 0x74, 0x1B5555, 0x921 },
+	[ATHOS_B_6G_LUT_CHAN_701250_IDX] = { 28050, 0x1, 0x74, 0x1C0000, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701375_IDX] = { 28055, 0x1, 0x74, 0x1CAAAB, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701500_IDX] = { 28060, 0x1, 0x74, 0x1D5555, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701625_IDX] = { 28065, 0x1, 0x74, 0x1E0000, 0x923 },
+	[ATHOS_B_6G_LUT_CHAN_701750_IDX] = { 28070, 0x1, 0x74, 0x1EAAAB, 0x923 },
+	[ATHOS_B_6G_LUT_CHAN_701875_IDX] = { 28075, 0x1, 0x74, 0x1F5555, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702000_IDX] = { 28080, 0x1, 0x75, 0x0, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702125_IDX] = { 28085, 0x1, 0x75, 0xAAAB, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702250_IDX] = { 28090, 0x1, 0x75, 0x15555, 0x925 },
+	[ATHOS_B_6G_LUT_CHAN_702375_IDX] = { 28095, 0x1, 0x75, 0x20000, 0x925 },
+	[ATHOS_B_6G_LUT_CHAN_702500_IDX] = { 28100, 0x1, 0x75, 0x2AAAB, 0x926 },
+	[ATHOS_B_6G_LUT_CHAN_702625_IDX] = { 28105, 0x1, 0x75, 0x35555, 0x926 },
+	[ATHOS_B_6G_LUT_CHAN_702750_IDX] = { 28110, 0x1, 0x75, 0x40000, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_702875_IDX] = { 28115, 0x1, 0x75, 0x4AAAB, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_703000_IDX] = { 28120, 0x1, 0x75, 0x55555, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_703125_IDX] = { 28125, 0x1, 0x75, 0x60000, 0x928 },
+	[ATHOS_B_6G_LUT_CHAN_703250_IDX] = { 28130, 0x1, 0x75, 0x6AAAB, 0x928 },
+	[ATHOS_B_6G_LUT_CHAN_703375_IDX] = { 28135, 0x1, 0x75, 0x75555, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703500_IDX] = { 28140, 0x1, 0x75, 0x80000, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703625_IDX] = { 28145, 0x1, 0x75, 0x8AAAB, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703750_IDX] = { 28150, 0x1, 0x75, 0x95555, 0x92A },
+	[ATHOS_B_6G_LUT_CHAN_703875_IDX] = { 28155, 0x1, 0x75, 0xA0000, 0x92A },
+	[ATHOS_B_6G_LUT_CHAN_704000_IDX] = { 28160, 0x1, 0x75, 0xAAAAB, 0x92B },
+	[ATHOS_B_6G_LUT_CHAN_704125_IDX] = { 28165, 0x1, 0x75, 0xB5555, 0x92B },
+	[ATHOS_B_6G_LUT_CHAN_704250_IDX] = { 28170, 0x1, 0x75, 0xC0000, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704375_IDX] = { 28175, 0x1, 0x75, 0xCAAAB, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704500_IDX] = { 28180, 0x1, 0x75, 0xD5555, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704625_IDX] = { 28185, 0x1, 0x75, 0xE0000, 0x92D },
+	[ATHOS_B_6G_LUT_CHAN_704750_IDX] = { 28190, 0x1, 0x75, 0xEAAAB, 0x92D },
+	[ATHOS_B_6G_LUT_CHAN_704875_IDX] = { 28195, 0x1, 0x75, 0xF5555, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705000_IDX] = { 28200, 0x1, 0x75, 0x100000, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705125_IDX] = { 28205, 0x1, 0x75, 0x10AAAB, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705250_IDX] = { 28210, 0x1, 0x75, 0x115555, 0x92F },
+	[ATHOS_B_6G_LUT_CHAN_705375_IDX] = { 28215, 0x1, 0x75, 0x120000, 0x92F },
+	[ATHOS_B_6G_LUT_CHAN_705500_IDX] = { 28220, 0x1, 0x75, 0x12AAAB, 0x930 },
+	[ATHOS_B_6G_LUT_CHAN_705625_IDX] = { 28225, 0x1, 0x75, 0x135555, 0x930 },
+	[ATHOS_B_6G_LUT_CHAN_705750_IDX] = { 28230, 0x1, 0x75, 0x140000, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_705875_IDX] = { 28235, 0x1, 0x75, 0x14AAAB, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_706000_IDX] = { 28240, 0x1, 0x75, 0x155555, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_706125_IDX] = { 28245, 0x1, 0x75, 0x160000, 0x932 },
+	[ATHOS_B_6G_LUT_CHAN_706250_IDX] = { 28250, 0x1, 0x75, 0x16AAAB, 0x932 },
+	[ATHOS_B_6G_LUT_CHAN_706375_IDX] = { 28255, 0x1, 0x75, 0x175555, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706500_IDX] = { 28260, 0x1, 0x75, 0x180000, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706625_IDX] = { 28265, 0x1, 0x75, 0x18AAAB, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706750_IDX] = { 28270, 0x1, 0x75, 0x195555, 0x934 },
+	[ATHOS_B_6G_LUT_CHAN_706875_IDX] = { 28275, 0x1, 0x75, 0x1A0000, 0x934 },
+	[ATHOS_B_6G_LUT_CHAN_707000_IDX] = { 28280, 0x1, 0x75, 0x1AAAAB, 0x935 },
+	[ATHOS_B_6G_LUT_CHAN_707125_IDX] = { 28285, 0x1, 0x75, 0x1B5555, 0x935 },
+	[ATHOS_B_6G_LUT_CHAN_707250_IDX] = { 28290, 0x1, 0x75, 0x1C0000, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707375_IDX] = { 28295, 0x1, 0x75, 0x1CAAAB, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707500_IDX] = { 28300, 0x1, 0x75, 0x1D5555, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707625_IDX] = { 28305, 0x1, 0x75, 0x1E0000, 0x937 },
+	[ATHOS_B_6G_LUT_CHAN_707750_IDX] = { 28310, 0x1, 0x75, 0x1EAAAB, 0x937 },
+	[ATHOS_B_6G_LUT_CHAN_707875_IDX] = { 28315, 0x1, 0x75, 0x1F5555, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708000_IDX] = { 28320, 0x1, 0x76, 0x0, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708125_IDX] = { 28325, 0x1, 0x76, 0xAAAB, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708250_IDX] = { 28330, 0x1, 0x76, 0x15555, 0x939 },
+	[ATHOS_B_6G_LUT_CHAN_708375_IDX] = { 28335, 0x1, 0x76, 0x20000, 0x939 },
+	[ATHOS_B_6G_LUT_CHAN_708500_IDX] = { 28340, 0x1, 0x76, 0x2AAAB, 0x93A },
+	[ATHOS_B_6G_LUT_CHAN_708625_IDX] = { 28345, 0x1, 0x76, 0x35555, 0x93A },
+	[ATHOS_B_6G_LUT_CHAN_708750_IDX] = { 28350, 0x1, 0x76, 0x40000, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_708875_IDX] = { 28355, 0x1, 0x76, 0x4AAAB, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_709000_IDX] = { 28360, 0x1, 0x76, 0x55555, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_709125_IDX] = { 28365, 0x1, 0x76, 0x60000, 0x93C },
+	[ATHOS_B_6G_LUT_CHAN_709250_IDX] = { 28370, 0x1, 0x76, 0x6AAAB, 0x93C },
+	[ATHOS_B_6G_LUT_CHAN_709375_IDX] = { 28375, 0x1, 0x76, 0x75555, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709500_IDX] = { 28380, 0x1, 0x76, 0x80000, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709625_IDX] = { 28385, 0x1, 0x76, 0x8AAAB, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709750_IDX] = { 28390, 0x1, 0x76, 0x95555, 0x93E },
+	[ATHOS_B_6G_LUT_CHAN_709875_IDX] = { 28395, 0x1, 0x76, 0xA0000, 0x93E },
+	[ATHOS_B_6G_LUT_CHAN_710000_IDX] = { 28400, 0x1, 0x76, 0xAAAAB, 0x93F },
+	[ATHOS_B_6G_LUT_CHAN_710125_IDX] = { 28405, 0x1, 0x76, 0xB5555, 0x93F },
+	[ATHOS_B_6G_LUT_CHAN_710250_IDX] = { 28410, 0x1, 0x76, 0xC0000, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710375_IDX] = { 28415, 0x1, 0x76, 0xCAAAB, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710500_IDX] = { 28420, 0x1, 0x76, 0xD5555, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710625_IDX] = { 28425, 0x1, 0x76, 0xE0000, 0x941 },
+	[ATHOS_B_6G_LUT_CHAN_710750_IDX] = { 28430, 0x1, 0x76, 0xEAAAB, 0x941 },
+	[ATHOS_B_6G_LUT_CHAN_710875_IDX] = { 28435, 0x1, 0x76, 0xF5555, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711000_IDX] = { 28440, 0x1, 0x76, 0x100000, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711125_IDX] = { 28445, 0x1, 0x76, 0x10AAAB, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711250_IDX] = { 28450, 0x1, 0x76, 0x115555, 0x943 },
+	[ATHOS_B_6G_LUT_CHAN_711375_IDX] = { 28455, 0x1, 0x76, 0x120000, 0x943 },
+	[ATHOS_B_6G_LUT_CHAN_711500_IDX] = { 28460, 0x1, 0x76, 0x12AAAB, 0x944 },
+	[ATHOS_B_6G_LUT_CHAN_711625_IDX] = { 28465, 0x1, 0x76, 0x135555, 0x944 },
+	[ATHOS_B_6G_LUT_CHAN_711750_IDX] = { 28470, 0x1, 0x76, 0x140000, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_711875_IDX] = { 28475, 0x1, 0x76, 0x14AAAB, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_712000_IDX] = { 28480, 0x1, 0x76, 0x155555, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_712125_IDX] = { 28485, 0x1, 0x76, 0x160000, 0x946 },
+	[ATHOS_B_6G_LUT_CHAN_712250_IDX] = { 28490, 0x1, 0x76, 0x16AAAB, 0x946 },
+	[ATHOS_B_6G_LUT_CHAN_712375_IDX] = { 28495, 0x1, 0x76, 0x175555, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712500_IDX] = { 28500, 0x1, 0x76, 0x180000, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712625_IDX] = { 28505, 0x1, 0x76, 0x18AAAB, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712750_IDX] = { 28510, 0x1, 0x76, 0x195555, 0x948 },
+	[ATHOS_B_6G_LUT_CHAN_712875_IDX] = { 28515, 0x1, 0x76, 0x1A0000, 0x948 },
+	[ATHOS_B_6G_LUT_CHAN_713000_IDX] = { 28520, 0x1, 0x76, 0x1AAAAB, 0x949 },
+	[ATHOS_B_6G_LUT_CHAN_713125_IDX] = { 28525, 0x1, 0x76, 0x1B5555, 0x949 },
+	[ATHOS_B_6G_LUT_CHAN_713250_IDX] = { 28530, 0x1, 0x76, 0x1C0000, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713375_IDX] = { 28535, 0x1, 0x76, 0x1CAAAB, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713500_IDX] = { 28540, 0x1, 0x76, 0x1D5555, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713625_IDX] = { 28545, 0x1, 0x76, 0x1E0000, 0x94B },
+	[ATHOS_B_6G_LUT_CHAN_713750_IDX] = { 28550, 0x1, 0x76, 0x1EAAAB, 0x94B },
+	[ATHOS_B_6G_LUT_CHAN_713875_IDX] = { 28555, 0x1, 0x76, 0x1F5555, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714000_IDX] = { 28560, 0x1, 0x77, 0x0, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714125_IDX] = { 28565, 0x1, 0x77, 0xAAAB, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714250_IDX] = { 28570, 0x1, 0x77, 0x15555, 0x94D },
+	[ATHOS_B_6G_LUT_CHAN_714375_IDX] = { 28575, 0x1, 0x77, 0x20000, 0x94D },
+	[ATHOS_B_6G_LUT_CHAN_714500_IDX] = { 28580, 0x1, 0x77, 0x2AAAB, 0x94E },
+	[ATHOS_B_6G_LUT_CHAN_714625_IDX] = { 28585, 0x1, 0x77, 0x35555, 0x94E },
+	[ATHOS_B_6G_LUT_CHAN_714750_IDX] = { 28590, 0x1, 0x77, 0x40000, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_714875_IDX] = { 28595, 0x1, 0x77, 0x4AAAB, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_715000_IDX] = { 28600, 0x1, 0x77, 0x55555, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_715125_IDX] = { 28605, 0x1, 0x77, 0x60000, 0x950 },
+	[ATHOS_B_6G_LUT_CHAN_715250_IDX] = { 28610, 0x1, 0x77, 0x6AAAB, 0x950 },
+	[ATHOS_B_6G_LUT_CHAN_715375_IDX] = { 28615, 0x1, 0x77, 0x75555, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715500_IDX] = { 28620, 0x1, 0x77, 0x80000, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715625_IDX] = { 28625, 0x1, 0x77, 0x8AAAB, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715750_IDX] = { 28630, 0x1, 0x77, 0x95555, 0x952 },
+	[ATHOS_B_6G_LUT_CHAN_715875_IDX] = { 28635, 0x1, 0x77, 0xA0000, 0x952 },
+	[ATHOS_B_6G_LUT_CHAN_716000_IDX] = { 28640, 0x1, 0x77, 0xAAAAB, 0x953 },
+	[ATHOS_B_6G_LUT_CHAN_716125_IDX] = { 28645, 0x1, 0x77, 0xB5555, 0x953 },
+	[ATHOS_B_6G_LUT_CHAN_716250_IDX] = { 28650, 0x1, 0x77, 0xC0000, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716375_IDX] = { 28655, 0x1, 0x77, 0xCAAAB, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716500_IDX] = { 28660, 0x1, 0x77, 0xD5555, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716625_IDX] = { 28665, 0x1, 0x77, 0xE0000, 0x955 },
+	[ATHOS_B_6G_LUT_CHAN_716750_IDX] = { 28670, 0x1, 0x77, 0xEAAAB, 0x955 },
+	[ATHOS_B_6G_LUT_CHAN_716875_IDX] = { 28675, 0x1, 0x77, 0xF5555, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717000_IDX] = { 28680, 0x1, 0x77, 0x100000, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717125_IDX] = { 28685, 0x1, 0x77, 0x10AAAB, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717250_IDX] = { 28690, 0x1, 0x77, 0x115555, 0x957 },
+	[ATHOS_B_6G_LUT_CHAN_717375_IDX] = { 28695, 0x1, 0x77, 0x120000, 0x957 },
+	[ATHOS_B_6G_LUT_CHAN_717500_IDX] = { 28700, 0x1, 0x77, 0x12AAAB, 0x958 },
+	[ATHOS_B_6G_LUT_CHAN_717625_IDX] = { 28705, 0x1, 0x77, 0x135555, 0x958 },
+	[ATHOS_B_6G_LUT_CHAN_717750_IDX] = { 28710, 0x1, 0x77, 0x140000, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_717875_IDX] = { 28715, 0x1, 0x77, 0x14AAAB, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_718000_IDX] = { 28720, 0x1, 0x77, 0x155555, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_718125_IDX] = { 28725, 0x1, 0x77, 0x160000, 0x95A },
+	[ATHOS_B_6G_LUT_CHAN_718250_IDX] = { 28730, 0x1, 0x77, 0x16AAAB, 0x95A },
+	[ATHOS_B_6G_LUT_CHAN_718375_IDX] = { 28735, 0x1, 0x77, 0x175555, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718500_IDX] = { 28740, 0x1, 0x77, 0x180000, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718625_IDX] = { 28745, 0x1, 0x77, 0x18AAAB, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718750_IDX] = { 28750, 0x1, 0x77, 0x195555, 0x95C },
+	[ATHOS_B_6G_LUT_CHAN_718875_IDX] = { 28755, 0x1, 0x77, 0x1A0000, 0x95C },
+	[ATHOS_B_6G_LUT_CHAN_719000_IDX] = { 28760, 0x1, 0x77, 0x1AAAAB, 0x95D },
+	[ATHOS_B_6G_LUT_CHAN_719125_IDX] = { 28765, 0x1, 0x77, 0x1B5555, 0x95D },
+	[ATHOS_B_6G_LUT_CHAN_719250_IDX] = { 28770, 0x1, 0x77, 0x1C0000, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719375_IDX] = { 28775, 0x1, 0x77, 0x1CAAAB, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719500_IDX] = { 28780, 0x1, 0x77, 0x1D5555, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719625_IDX] = { 28785, 0x1, 0x77, 0x1E0000, 0x95F },
+	[ATHOS_B_6G_LUT_CHAN_719750_IDX] = { 28790, 0x1, 0x77, 0x1EAAAB, 0x95F },
+	[ATHOS_B_6G_LUT_CHAN_719875_IDX] = { 28795, 0x1, 0x77, 0x1F5555, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720000_IDX] = { 28800, 0x1, 0x78, 0x0, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720125_IDX] = { 28805, 0x1, 0x78, 0xAAAB, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720250_IDX] = { 28810, 0x1, 0x78, 0x15555, 0x961 },
+	[ATHOS_B_6G_LUT_CHAN_720375_IDX] = { 28815, 0x1, 0x78, 0x20000, 0x961 },
+	[ATHOS_B_6G_LUT_CHAN_720500_IDX] = { 28820, 0x1, 0x78, 0x2AAAB, 0x962 },
+	[ATHOS_B_6G_LUT_CHAN_720625_IDX] = { 28825, 0x1, 0x78, 0x35555, 0x962 },
+	[ATHOS_B_6G_LUT_CHAN_720750_IDX] = { 28830, 0x1, 0x78, 0x40000, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_720875_IDX] = { 28835, 0x1, 0x78, 0x4AAAB, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_721000_IDX] = { 28840, 0x1, 0x78, 0x55555, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_721125_IDX] = { 28845, 0x1, 0x78, 0x60000, 0x964 },
+	[ATHOS_B_6G_LUT_CHAN_721250_IDX] = { 28850, 0x1, 0x78, 0x6AAAB, 0x964 },
+	[ATHOS_B_6G_LUT_CHAN_721375_IDX] = { 28855, 0x1, 0x78, 0x75555, 0x965 },
+	[ATHOS_B_6G_LUT_CHAN_721500_IDX] = { 28860, 0x1, 0x78, 0x80000, 0x965 }
+};
+
+const struct common_lut_line athos_b_lut_6g_60_mhz[ATHOS_B_6G_LUT_CHAN_6G_MAX] = {
+	[ATHOS_B_6G_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x41, 0x1C71C7, 0x7B9 },
+	[ATHOS_B_6G_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x41, 0x1CE38E, 0x7B9 },
+	[ATHOS_B_6G_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x41, 0x1D5555, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x41, 0x1DC71C, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x41, 0x1E38E4, 0x7BA },
+	[ATHOS_B_6G_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x41, 0x1EAAAB, 0x7BB },
+	[ATHOS_B_6G_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x41, 0x1F1C72, 0x7BB },
+	[ATHOS_B_6G_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x41, 0x1F8E39, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x42, 0x0, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x42, 0x71C7, 0x7BC },
+	[ATHOS_B_6G_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x42, 0xE38E, 0x7BD },
+	[ATHOS_B_6G_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x42, 0x15555, 0x7BD },
+	[ATHOS_B_6G_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x42, 0x1C71C, 0x7BE },
+	[ATHOS_B_6G_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x42, 0x238E4, 0x7BE },
+	[ATHOS_B_6G_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x42, 0x2AAAB, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x42, 0x31C72, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x42, 0x38E39, 0x7BF },
+	[ATHOS_B_6G_LUT_CHAN_595125_IDX] = { 23805, 0x1, 0x42, 0x40000, 0x7C0 },
+	[ATHOS_B_6G_LUT_CHAN_595250_IDX] = { 23810, 0x1, 0x42, 0x471C7, 0x7C0 },
+	[ATHOS_B_6G_LUT_CHAN_595375_IDX] = { 23815, 0x1, 0x42, 0x4E38E, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595500_IDX] = { 23820, 0x1, 0x42, 0x55555, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595625_IDX] = { 23825, 0x1, 0x42, 0x5C71C, 0x7C1 },
+	[ATHOS_B_6G_LUT_CHAN_595750_IDX] = { 23830, 0x1, 0x42, 0x638E4, 0x7C2 },
+	[ATHOS_B_6G_LUT_CHAN_595875_IDX] = { 23835, 0x1, 0x42, 0x6AAAB, 0x7C2 },
+	[ATHOS_B_6G_LUT_CHAN_596000_IDX] = { 23840, 0x1, 0x42, 0x71C72, 0x7C3 },
+	[ATHOS_B_6G_LUT_CHAN_596125_IDX] = { 23845, 0x1, 0x42, 0x78E39, 0x7C3 },
+	[ATHOS_B_6G_LUT_CHAN_596250_IDX] = { 23850, 0x1, 0x42, 0x80000, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596375_IDX] = { 23855, 0x1, 0x42, 0x871C7, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596500_IDX] = { 23860, 0x1, 0x42, 0x8E38E, 0x7C4 },
+	[ATHOS_B_6G_LUT_CHAN_596625_IDX] = { 23865, 0x1, 0x42, 0x95555, 0x7C5 },
+	[ATHOS_B_6G_LUT_CHAN_596750_IDX] = { 23870, 0x1, 0x42, 0x9C71C, 0x7C5 },
+	[ATHOS_B_6G_LUT_CHAN_596875_IDX] = { 23875, 0x1, 0x42, 0xA38E4, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597000_IDX] = { 23880, 0x1, 0x42, 0xAAAAB, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597125_IDX] = { 23885, 0x1, 0x42, 0xB1C72, 0x7C6 },
+	[ATHOS_B_6G_LUT_CHAN_597250_IDX] = { 23890, 0x1, 0x42, 0xB8E39, 0x7C7 },
+	[ATHOS_B_6G_LUT_CHAN_597375_IDX] = { 23895, 0x1, 0x42, 0xC0000, 0x7C7 },
+	[ATHOS_B_6G_LUT_CHAN_597500_IDX] = { 23900, 0x1, 0x42, 0xC71C7, 0x7C8 },
+	[ATHOS_B_6G_LUT_CHAN_597625_IDX] = { 23905, 0x1, 0x42, 0xCE38E, 0x7C8 },
+	[ATHOS_B_6G_LUT_CHAN_597750_IDX] = { 23910, 0x1, 0x42, 0xD5555, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_597875_IDX] = { 23915, 0x1, 0x42, 0xDC71C, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_598000_IDX] = { 23920, 0x1, 0x42, 0xE38E4, 0x7C9 },
+	[ATHOS_B_6G_LUT_CHAN_598125_IDX] = { 23925, 0x1, 0x42, 0xEAAAB, 0x7CA },
+	[ATHOS_B_6G_LUT_CHAN_598250_IDX] = { 23930, 0x1, 0x42, 0xF1C72, 0x7CA },
+	[ATHOS_B_6G_LUT_CHAN_598375_IDX] = { 23935, 0x1, 0x42, 0xF8E39, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598500_IDX] = { 23940, 0x1, 0x42, 0x100000, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598625_IDX] = { 23945, 0x1, 0x42, 0x1071C7, 0x7CB },
+	[ATHOS_B_6G_LUT_CHAN_598750_IDX] = { 23950, 0x1, 0x42, 0x10E38E, 0x7CC },
+	[ATHOS_B_6G_LUT_CHAN_598875_IDX] = { 23955, 0x1, 0x42, 0x115555, 0x7CC },
+	[ATHOS_B_6G_LUT_CHAN_599000_IDX] = { 23960, 0x1, 0x42, 0x11C71C, 0x7CD },
+	[ATHOS_B_6G_LUT_CHAN_599125_IDX] = { 23965, 0x1, 0x42, 0x1238E4, 0x7CD },
+	[ATHOS_B_6G_LUT_CHAN_599250_IDX] = { 23970, 0x1, 0x42, 0x12AAAB, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599375_IDX] = { 23975, 0x1, 0x42, 0x131C72, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599500_IDX] = { 23980, 0x1, 0x42, 0x138E39, 0x7CE },
+	[ATHOS_B_6G_LUT_CHAN_599625_IDX] = { 23985, 0x1, 0x42, 0x140000, 0x7CF },
+	[ATHOS_B_6G_LUT_CHAN_599750_IDX] = { 23990, 0x1, 0x42, 0x1471C7, 0x7CF },
+	[ATHOS_B_6G_LUT_CHAN_599875_IDX] = { 23995, 0x1, 0x42, 0x14E38E, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600000_IDX] = { 24000, 0x1, 0x42, 0x155555, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600125_IDX] = { 24005, 0x1, 0x42, 0x15C71C, 0x7D0 },
+	[ATHOS_B_6G_LUT_CHAN_600250_IDX] = { 24010, 0x1, 0x42, 0x1638E4, 0x7D1 },
+	[ATHOS_B_6G_LUT_CHAN_600375_IDX] = { 24015, 0x1, 0x42, 0x16AAAB, 0x7D1 },
+	[ATHOS_B_6G_LUT_CHAN_600500_IDX] = { 24020, 0x1, 0x42, 0x171C72, 0x7D2 },
+	[ATHOS_B_6G_LUT_CHAN_600625_IDX] = { 24025, 0x1, 0x42, 0x178E39, 0x7D2 },
+	[ATHOS_B_6G_LUT_CHAN_600750_IDX] = { 24030, 0x1, 0x42, 0x180000, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_600875_IDX] = { 24035, 0x1, 0x42, 0x1871C7, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_601000_IDX] = { 24040, 0x1, 0x42, 0x18E38E, 0x7D3 },
+	[ATHOS_B_6G_LUT_CHAN_601125_IDX] = { 24045, 0x1, 0x42, 0x195555, 0x7D4 },
+	[ATHOS_B_6G_LUT_CHAN_601250_IDX] = { 24050, 0x1, 0x42, 0x19C71C, 0x7D4 },
+	[ATHOS_B_6G_LUT_CHAN_601375_IDX] = { 24055, 0x1, 0x42, 0x1A38E4, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601500_IDX] = { 24060, 0x1, 0x42, 0x1AAAAB, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601625_IDX] = { 24065, 0x1, 0x42, 0x1B1C72, 0x7D5 },
+	[ATHOS_B_6G_LUT_CHAN_601750_IDX] = { 24070, 0x1, 0x42, 0x1B8E39, 0x7D6 },
+	[ATHOS_B_6G_LUT_CHAN_601875_IDX] = { 24075, 0x1, 0x42, 0x1C0000, 0x7D6 },
+	[ATHOS_B_6G_LUT_CHAN_602000_IDX] = { 24080, 0x1, 0x42, 0x1C71C7, 0x7D7 },
+	[ATHOS_B_6G_LUT_CHAN_602125_IDX] = { 24085, 0x1, 0x42, 0x1CE38E, 0x7D7 },
+	[ATHOS_B_6G_LUT_CHAN_602250_IDX] = { 24090, 0x1, 0x42, 0x1D5555, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602375_IDX] = { 24095, 0x1, 0x42, 0x1DC71C, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602500_IDX] = { 24100, 0x1, 0x42, 0x1E38E4, 0x7D8 },
+	[ATHOS_B_6G_LUT_CHAN_602625_IDX] = { 24105, 0x1, 0x42, 0x1EAAAB, 0x7D9 },
+	[ATHOS_B_6G_LUT_CHAN_602750_IDX] = { 24110, 0x1, 0x42, 0x1F1C72, 0x7D9 },
+	[ATHOS_B_6G_LUT_CHAN_602875_IDX] = { 24115, 0x1, 0x42, 0x1F8E39, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603000_IDX] = { 24120, 0x1, 0x43, 0x0, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603125_IDX] = { 24125, 0x1, 0x43, 0x71C7, 0x7DA },
+	[ATHOS_B_6G_LUT_CHAN_603250_IDX] = { 24130, 0x1, 0x43, 0xE38E, 0x7DB },
+	[ATHOS_B_6G_LUT_CHAN_603375_IDX] = { 24135, 0x1, 0x43, 0x15555, 0x7DB },
+	[ATHOS_B_6G_LUT_CHAN_603500_IDX] = { 24140, 0x1, 0x43, 0x1C71C, 0x7DC },
+	[ATHOS_B_6G_LUT_CHAN_603625_IDX] = { 24145, 0x1, 0x43, 0x238E4, 0x7DC },
+	[ATHOS_B_6G_LUT_CHAN_603750_IDX] = { 24150, 0x1, 0x43, 0x2AAAB, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_603875_IDX] = { 24155, 0x1, 0x43, 0x31C72, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_604000_IDX] = { 24160, 0x1, 0x43, 0x38E39, 0x7DD },
+	[ATHOS_B_6G_LUT_CHAN_604125_IDX] = { 24165, 0x1, 0x43, 0x40000, 0x7DE },
+	[ATHOS_B_6G_LUT_CHAN_604250_IDX] = { 24170, 0x1, 0x43, 0x471C7, 0x7DE },
+	[ATHOS_B_6G_LUT_CHAN_604375_IDX] = { 24175, 0x1, 0x43, 0x4E38E, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604500_IDX] = { 24180, 0x1, 0x43, 0x55555, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604625_IDX] = { 24185, 0x1, 0x43, 0x5C71C, 0x7DF },
+	[ATHOS_B_6G_LUT_CHAN_604750_IDX] = { 24190, 0x1, 0x43, 0x638E4, 0x7E0 },
+	[ATHOS_B_6G_LUT_CHAN_604875_IDX] = { 24195, 0x1, 0x43, 0x6AAAB, 0x7E0 },
+	[ATHOS_B_6G_LUT_CHAN_605000_IDX] = { 24200, 0x1, 0x43, 0x71C72, 0x7E1 },
+	[ATHOS_B_6G_LUT_CHAN_605125_IDX] = { 24205, 0x1, 0x43, 0x78E39, 0x7E1 },
+	[ATHOS_B_6G_LUT_CHAN_605250_IDX] = { 24210, 0x1, 0x43, 0x80000, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605375_IDX] = { 24215, 0x1, 0x43, 0x871C7, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605500_IDX] = { 24220, 0x1, 0x43, 0x8E38E, 0x7E2 },
+	[ATHOS_B_6G_LUT_CHAN_605625_IDX] = { 24225, 0x1, 0x43, 0x95555, 0x7E3 },
+	[ATHOS_B_6G_LUT_CHAN_605750_IDX] = { 24230, 0x1, 0x43, 0x9C71C, 0x7E3 },
+	[ATHOS_B_6G_LUT_CHAN_605875_IDX] = { 24235, 0x1, 0x43, 0xA38E4, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606000_IDX] = { 24240, 0x1, 0x43, 0xAAAAB, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606125_IDX] = { 24245, 0x1, 0x43, 0xB1C72, 0x7E4 },
+	[ATHOS_B_6G_LUT_CHAN_606250_IDX] = { 24250, 0x1, 0x43, 0xB8E39, 0x7E5 },
+	[ATHOS_B_6G_LUT_CHAN_606375_IDX] = { 24255, 0x1, 0x43, 0xC0000, 0x7E5 },
+	[ATHOS_B_6G_LUT_CHAN_606500_IDX] = { 24260, 0x1, 0x43, 0xC71C7, 0x7E6 },
+	[ATHOS_B_6G_LUT_CHAN_606625_IDX] = { 24265, 0x1, 0x43, 0xCE38E, 0x7E6 },
+	[ATHOS_B_6G_LUT_CHAN_606750_IDX] = { 24270, 0x1, 0x43, 0xD5555, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_606875_IDX] = { 24275, 0x1, 0x43, 0xDC71C, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_607000_IDX] = { 24280, 0x1, 0x43, 0xE38E4, 0x7E7 },
+	[ATHOS_B_6G_LUT_CHAN_607125_IDX] = { 24285, 0x1, 0x43, 0xEAAAB, 0x7E8 },
+	[ATHOS_B_6G_LUT_CHAN_607250_IDX] = { 24290, 0x1, 0x43, 0xF1C72, 0x7E8 },
+	[ATHOS_B_6G_LUT_CHAN_607375_IDX] = { 24295, 0x1, 0x43, 0xF8E39, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607500_IDX] = { 24300, 0x1, 0x43, 0x100000, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607625_IDX] = { 24305, 0x1, 0x43, 0x1071C7, 0x7E9 },
+	[ATHOS_B_6G_LUT_CHAN_607750_IDX] = { 24310, 0x1, 0x43, 0x10E38E, 0x7EA },
+	[ATHOS_B_6G_LUT_CHAN_607875_IDX] = { 24315, 0x1, 0x43, 0x115555, 0x7EA },
+	[ATHOS_B_6G_LUT_CHAN_608000_IDX] = { 24320, 0x1, 0x43, 0x11C71C, 0x7EB },
+	[ATHOS_B_6G_LUT_CHAN_608125_IDX] = { 24325, 0x1, 0x43, 0x1238E4, 0x7EB },
+	[ATHOS_B_6G_LUT_CHAN_608250_IDX] = { 24330, 0x1, 0x43, 0x12AAAB, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608375_IDX] = { 24335, 0x1, 0x43, 0x131C72, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608500_IDX] = { 24340, 0x1, 0x43, 0x138E39, 0x7EC },
+	[ATHOS_B_6G_LUT_CHAN_608625_IDX] = { 24345, 0x1, 0x43, 0x140000, 0x7ED },
+	[ATHOS_B_6G_LUT_CHAN_608750_IDX] = { 24350, 0x1, 0x43, 0x1471C7, 0x7ED },
+	[ATHOS_B_6G_LUT_CHAN_608875_IDX] = { 24355, 0x1, 0x43, 0x14E38E, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609000_IDX] = { 24360, 0x1, 0x43, 0x155555, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609125_IDX] = { 24365, 0x1, 0x43, 0x15C71C, 0x7EE },
+	[ATHOS_B_6G_LUT_CHAN_609250_IDX] = { 24370, 0x1, 0x43, 0x1638E4, 0x7EF },
+	[ATHOS_B_6G_LUT_CHAN_609375_IDX] = { 24375, 0x1, 0x43, 0x16AAAB, 0x7EF },
+	[ATHOS_B_6G_LUT_CHAN_609500_IDX] = { 24380, 0x1, 0x43, 0x171C72, 0x7F0 },
+	[ATHOS_B_6G_LUT_CHAN_609625_IDX] = { 24385, 0x1, 0x43, 0x178E39, 0x7F0 },
+	[ATHOS_B_6G_LUT_CHAN_609750_IDX] = { 24390, 0x1, 0x43, 0x180000, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_609875_IDX] = { 24395, 0x1, 0x43, 0x1871C7, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_610000_IDX] = { 24400, 0x1, 0x43, 0x18E38E, 0x7F1 },
+	[ATHOS_B_6G_LUT_CHAN_610125_IDX] = { 24405, 0x1, 0x43, 0x195555, 0x7F2 },
+	[ATHOS_B_6G_LUT_CHAN_610250_IDX] = { 24410, 0x1, 0x43, 0x19C71C, 0x7F2 },
+	[ATHOS_B_6G_LUT_CHAN_610375_IDX] = { 24415, 0x1, 0x43, 0x1A38E4, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610500_IDX] = { 24420, 0x1, 0x43, 0x1AAAAB, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610625_IDX] = { 24425, 0x1, 0x43, 0x1B1C72, 0x7F3 },
+	[ATHOS_B_6G_LUT_CHAN_610750_IDX] = { 24430, 0x1, 0x43, 0x1B8E39, 0x7F4 },
+	[ATHOS_B_6G_LUT_CHAN_610875_IDX] = { 24435, 0x1, 0x43, 0x1C0000, 0x7F4 },
+	[ATHOS_B_6G_LUT_CHAN_611000_IDX] = { 24440, 0x1, 0x43, 0x1C71C7, 0x7F5 },
+	[ATHOS_B_6G_LUT_CHAN_611125_IDX] = { 24445, 0x1, 0x43, 0x1CE38E, 0x7F5 },
+	[ATHOS_B_6G_LUT_CHAN_611250_IDX] = { 24450, 0x1, 0x43, 0x1D5555, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611375_IDX] = { 24455, 0x1, 0x43, 0x1DC71C, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611500_IDX] = { 24460, 0x1, 0x43, 0x1E38E4, 0x7F6 },
+	[ATHOS_B_6G_LUT_CHAN_611625_IDX] = { 24465, 0x1, 0x43, 0x1EAAAB, 0x7F7 },
+	[ATHOS_B_6G_LUT_CHAN_611750_IDX] = { 24470, 0x1, 0x43, 0x1F1C72, 0x7F7 },
+	[ATHOS_B_6G_LUT_CHAN_611875_IDX] = { 24475, 0x1, 0x43, 0x1F8E39, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612000_IDX] = { 24480, 0x1, 0x44, 0x0, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612125_IDX] = { 24485, 0x1, 0x44, 0x71C7, 0x7F8 },
+	[ATHOS_B_6G_LUT_CHAN_612250_IDX] = { 24490, 0x1, 0x44, 0xE38E, 0x7F9 },
+	[ATHOS_B_6G_LUT_CHAN_612375_IDX] = { 24495, 0x1, 0x44, 0x15555, 0x7F9 },
+	[ATHOS_B_6G_LUT_CHAN_612500_IDX] = { 24500, 0x1, 0x44, 0x1C71C, 0x7FA },
+	[ATHOS_B_6G_LUT_CHAN_612625_IDX] = { 24505, 0x1, 0x44, 0x238E4, 0x7FA },
+	[ATHOS_B_6G_LUT_CHAN_612750_IDX] = { 24510, 0x1, 0x44, 0x2AAAB, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_612875_IDX] = { 24515, 0x1, 0x44, 0x31C72, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_613000_IDX] = { 24520, 0x1, 0x44, 0x38E39, 0x7FB },
+	[ATHOS_B_6G_LUT_CHAN_613125_IDX] = { 24525, 0x1, 0x44, 0x40000, 0x7FC },
+	[ATHOS_B_6G_LUT_CHAN_613250_IDX] = { 24530, 0x1, 0x44, 0x471C7, 0x7FC },
+	[ATHOS_B_6G_LUT_CHAN_613375_IDX] = { 24535, 0x1, 0x44, 0x4E38E, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613500_IDX] = { 24540, 0x1, 0x44, 0x55555, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613625_IDX] = { 24545, 0x1, 0x44, 0x5C71C, 0x7FD },
+	[ATHOS_B_6G_LUT_CHAN_613750_IDX] = { 24550, 0x1, 0x44, 0x638E4, 0x7FE },
+	[ATHOS_B_6G_LUT_CHAN_613875_IDX] = { 24555, 0x1, 0x44, 0x6AAAB, 0x7FE },
+	[ATHOS_B_6G_LUT_CHAN_614000_IDX] = { 24560, 0x1, 0x44, 0x71C72, 0x7FF },
+	[ATHOS_B_6G_LUT_CHAN_614125_IDX] = { 24565, 0x1, 0x44, 0x78E39, 0x7FF },
+	[ATHOS_B_6G_LUT_CHAN_614250_IDX] = { 24570, 0x1, 0x44, 0x80000, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614375_IDX] = { 24575, 0x1, 0x44, 0x871C7, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614500_IDX] = { 24580, 0x1, 0x44, 0x8E38E, 0x800 },
+	[ATHOS_B_6G_LUT_CHAN_614625_IDX] = { 24585, 0x1, 0x44, 0x95555, 0x801 },
+	[ATHOS_B_6G_LUT_CHAN_614750_IDX] = { 24590, 0x1, 0x44, 0x9C71C, 0x801 },
+	[ATHOS_B_6G_LUT_CHAN_614875_IDX] = { 24595, 0x1, 0x44, 0xA38E4, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615000_IDX] = { 24600, 0x1, 0x44, 0xAAAAB, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615125_IDX] = { 24605, 0x1, 0x44, 0xB1C72, 0x802 },
+	[ATHOS_B_6G_LUT_CHAN_615250_IDX] = { 24610, 0x1, 0x44, 0xB8E39, 0x803 },
+	[ATHOS_B_6G_LUT_CHAN_615375_IDX] = { 24615, 0x1, 0x44, 0xC0000, 0x803 },
+	[ATHOS_B_6G_LUT_CHAN_615500_IDX] = { 24620, 0x1, 0x44, 0xC71C7, 0x804 },
+	[ATHOS_B_6G_LUT_CHAN_615625_IDX] = { 24625, 0x1, 0x44, 0xCE38E, 0x804 },
+	[ATHOS_B_6G_LUT_CHAN_615750_IDX] = { 24630, 0x1, 0x44, 0xD5555, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_615875_IDX] = { 24635, 0x1, 0x44, 0xDC71C, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_616000_IDX] = { 24640, 0x1, 0x44, 0xE38E4, 0x805 },
+	[ATHOS_B_6G_LUT_CHAN_616125_IDX] = { 24645, 0x1, 0x44, 0xEAAAB, 0x806 },
+	[ATHOS_B_6G_LUT_CHAN_616250_IDX] = { 24650, 0x1, 0x44, 0xF1C72, 0x806 },
+	[ATHOS_B_6G_LUT_CHAN_616375_IDX] = { 24655, 0x1, 0x44, 0xF8E39, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616500_IDX] = { 24660, 0x1, 0x44, 0x100000, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616625_IDX] = { 24665, 0x1, 0x44, 0x1071C7, 0x807 },
+	[ATHOS_B_6G_LUT_CHAN_616750_IDX] = { 24670, 0x1, 0x44, 0x10E38E, 0x808 },
+	[ATHOS_B_6G_LUT_CHAN_616875_IDX] = { 24675, 0x1, 0x44, 0x115555, 0x808 },
+	[ATHOS_B_6G_LUT_CHAN_617000_IDX] = { 24680, 0x1, 0x44, 0x11C71C, 0x809 },
+	[ATHOS_B_6G_LUT_CHAN_617125_IDX] = { 24685, 0x1, 0x44, 0x1238E4, 0x809 },
+	[ATHOS_B_6G_LUT_CHAN_617250_IDX] = { 24690, 0x1, 0x44, 0x12AAAB, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617375_IDX] = { 24695, 0x1, 0x44, 0x131C72, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617500_IDX] = { 24700, 0x1, 0x44, 0x138E39, 0x80A },
+	[ATHOS_B_6G_LUT_CHAN_617625_IDX] = { 24705, 0x1, 0x44, 0x140000, 0x80B },
+	[ATHOS_B_6G_LUT_CHAN_617750_IDX] = { 24710, 0x1, 0x44, 0x1471C7, 0x80B },
+	[ATHOS_B_6G_LUT_CHAN_617875_IDX] = { 24715, 0x1, 0x44, 0x14E38E, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618000_IDX] = { 24720, 0x1, 0x44, 0x155555, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618125_IDX] = { 24725, 0x1, 0x44, 0x15C71C, 0x80C },
+	[ATHOS_B_6G_LUT_CHAN_618250_IDX] = { 24730, 0x1, 0x44, 0x1638E4, 0x80D },
+	[ATHOS_B_6G_LUT_CHAN_618375_IDX] = { 24735, 0x1, 0x44, 0x16AAAB, 0x80D },
+	[ATHOS_B_6G_LUT_CHAN_618500_IDX] = { 24740, 0x1, 0x44, 0x171C72, 0x80E },
+	[ATHOS_B_6G_LUT_CHAN_618625_IDX] = { 24745, 0x1, 0x44, 0x178E39, 0x80E },
+	[ATHOS_B_6G_LUT_CHAN_618750_IDX] = { 24750, 0x1, 0x44, 0x180000, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_618875_IDX] = { 24755, 0x1, 0x44, 0x1871C7, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_619000_IDX] = { 24760, 0x1, 0x44, 0x18E38E, 0x80F },
+	[ATHOS_B_6G_LUT_CHAN_619125_IDX] = { 24765, 0x1, 0x44, 0x195555, 0x810 },
+	[ATHOS_B_6G_LUT_CHAN_619250_IDX] = { 24770, 0x1, 0x44, 0x19C71C, 0x810 },
+	[ATHOS_B_6G_LUT_CHAN_619375_IDX] = { 24775, 0x1, 0x44, 0x1A38E4, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619500_IDX] = { 24780, 0x1, 0x44, 0x1AAAAB, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619625_IDX] = { 24785, 0x1, 0x44, 0x1B1C72, 0x811 },
+	[ATHOS_B_6G_LUT_CHAN_619750_IDX] = { 24790, 0x1, 0x44, 0x1B8E39, 0x812 },
+	[ATHOS_B_6G_LUT_CHAN_619875_IDX] = { 24795, 0x1, 0x44, 0x1C0000, 0x812 },
+	[ATHOS_B_6G_LUT_CHAN_620000_IDX] = { 24800, 0x1, 0x44, 0x1C71C7, 0x813 },
+	[ATHOS_B_6G_LUT_CHAN_620125_IDX] = { 24805, 0x1, 0x44, 0x1CE38E, 0x813 },
+	[ATHOS_B_6G_LUT_CHAN_620250_IDX] = { 24810, 0x1, 0x44, 0x1D5555, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620375_IDX] = { 24815, 0x1, 0x44, 0x1DC71C, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620500_IDX] = { 24820, 0x1, 0x44, 0x1E38E4, 0x814 },
+	[ATHOS_B_6G_LUT_CHAN_620625_IDX] = { 24825, 0x1, 0x44, 0x1EAAAB, 0x815 },
+	[ATHOS_B_6G_LUT_CHAN_620750_IDX] = { 24830, 0x1, 0x44, 0x1F1C72, 0x815 },
+	[ATHOS_B_6G_LUT_CHAN_620875_IDX] = { 24835, 0x2, 0x44, 0x1F8E39, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621000_IDX] = { 24840, 0x2, 0x45, 0x0, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621125_IDX] = { 24845, 0x2, 0x45, 0x71C7, 0x816 },
+	[ATHOS_B_6G_LUT_CHAN_621250_IDX] = { 24850, 0x2, 0x45, 0xE38E, 0x817 },
+	[ATHOS_B_6G_LUT_CHAN_621375_IDX] = { 24855, 0x2, 0x45, 0x15555, 0x817 },
+	[ATHOS_B_6G_LUT_CHAN_621500_IDX] = { 24860, 0x2, 0x45, 0x1C71C, 0x818 },
+	[ATHOS_B_6G_LUT_CHAN_621625_IDX] = { 24865, 0x2, 0x45, 0x238E4, 0x818 },
+	[ATHOS_B_6G_LUT_CHAN_621750_IDX] = { 24870, 0x2, 0x45, 0x2AAAB, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_621875_IDX] = { 24875, 0x2, 0x45, 0x31C72, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_622000_IDX] = { 24880, 0x2, 0x45, 0x38E39, 0x819 },
+	[ATHOS_B_6G_LUT_CHAN_622125_IDX] = { 24885, 0x2, 0x45, 0x40000, 0x81A },
+	[ATHOS_B_6G_LUT_CHAN_622250_IDX] = { 24890, 0x2, 0x45, 0x471C7, 0x81A },
+	[ATHOS_B_6G_LUT_CHAN_622375_IDX] = { 24895, 0x2, 0x45, 0x4E38E, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622500_IDX] = { 24900, 0x2, 0x45, 0x55555, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622625_IDX] = { 24905, 0x2, 0x45, 0x5C71C, 0x81B },
+	[ATHOS_B_6G_LUT_CHAN_622750_IDX] = { 24910, 0x2, 0x45, 0x638E4, 0x81C },
+	[ATHOS_B_6G_LUT_CHAN_622875_IDX] = { 24915, 0x2, 0x45, 0x6AAAB, 0x81C },
+	[ATHOS_B_6G_LUT_CHAN_623000_IDX] = { 24920, 0x2, 0x45, 0x71C72, 0x81D },
+	[ATHOS_B_6G_LUT_CHAN_623125_IDX] = { 24925, 0x2, 0x45, 0x78E39, 0x81D },
+	[ATHOS_B_6G_LUT_CHAN_623250_IDX] = { 24930, 0x2, 0x45, 0x80000, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623375_IDX] = { 24935, 0x2, 0x45, 0x871C7, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623500_IDX] = { 24940, 0x2, 0x45, 0x8E38E, 0x81E },
+	[ATHOS_B_6G_LUT_CHAN_623625_IDX] = { 24945, 0x2, 0x45, 0x95555, 0x81F },
+	[ATHOS_B_6G_LUT_CHAN_623750_IDX] = { 24950, 0x2, 0x45, 0x9C71C, 0x81F },
+	[ATHOS_B_6G_LUT_CHAN_623875_IDX] = { 24955, 0x2, 0x45, 0xA38E4, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624000_IDX] = { 24960, 0x2, 0x45, 0xAAAAB, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624125_IDX] = { 24965, 0x2, 0x45, 0xB1C72, 0x820 },
+	[ATHOS_B_6G_LUT_CHAN_624250_IDX] = { 24970, 0x2, 0x45, 0xB8E39, 0x821 },
+	[ATHOS_B_6G_LUT_CHAN_624375_IDX] = { 24975, 0x2, 0x45, 0xC0000, 0x821 },
+	[ATHOS_B_6G_LUT_CHAN_624500_IDX] = { 24980, 0x2, 0x45, 0xC71C7, 0x822 },
+	[ATHOS_B_6G_LUT_CHAN_624625_IDX] = { 24985, 0x2, 0x45, 0xCE38E, 0x822 },
+	[ATHOS_B_6G_LUT_CHAN_624750_IDX] = { 24990, 0x2, 0x45, 0xD5555, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_624875_IDX] = { 24995, 0x2, 0x45, 0xDC71C, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_625000_IDX] = { 25000, 0x2, 0x45, 0xE38E4, 0x823 },
+	[ATHOS_B_6G_LUT_CHAN_625125_IDX] = { 25005, 0x2, 0x45, 0xEAAAB, 0x824 },
+	[ATHOS_B_6G_LUT_CHAN_625250_IDX] = { 25010, 0x2, 0x45, 0xF1C72, 0x824 },
+	[ATHOS_B_6G_LUT_CHAN_625375_IDX] = { 25015, 0x2, 0x45, 0xF8E39, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625500_IDX] = { 25020, 0x2, 0x45, 0x100000, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625625_IDX] = { 25025, 0x2, 0x45, 0x1071C7, 0x825 },
+	[ATHOS_B_6G_LUT_CHAN_625750_IDX] = { 25030, 0x2, 0x45, 0x10E38E, 0x826 },
+	[ATHOS_B_6G_LUT_CHAN_625875_IDX] = { 25035, 0x2, 0x45, 0x115555, 0x826 },
+	[ATHOS_B_6G_LUT_CHAN_626000_IDX] = { 25040, 0x2, 0x45, 0x11C71C, 0x827 },
+	[ATHOS_B_6G_LUT_CHAN_626125_IDX] = { 25045, 0x2, 0x45, 0x1238E4, 0x827 },
+	[ATHOS_B_6G_LUT_CHAN_626250_IDX] = { 25050, 0x2, 0x45, 0x12AAAB, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626375_IDX] = { 25055, 0x2, 0x45, 0x131C72, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626500_IDX] = { 25060, 0x2, 0x45, 0x138E39, 0x828 },
+	[ATHOS_B_6G_LUT_CHAN_626625_IDX] = { 25065, 0x2, 0x45, 0x140000, 0x829 },
+	[ATHOS_B_6G_LUT_CHAN_626750_IDX] = { 25070, 0x2, 0x45, 0x1471C7, 0x829 },
+	[ATHOS_B_6G_LUT_CHAN_626875_IDX] = { 25075, 0x2, 0x45, 0x14E38E, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627000_IDX] = { 25080, 0x2, 0x45, 0x155555, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627125_IDX] = { 25085, 0x2, 0x45, 0x15C71C, 0x82A },
+	[ATHOS_B_6G_LUT_CHAN_627250_IDX] = { 25090, 0x2, 0x45, 0x1638E4, 0x82B },
+	[ATHOS_B_6G_LUT_CHAN_627375_IDX] = { 25095, 0x2, 0x45, 0x16AAAB, 0x82B },
+	[ATHOS_B_6G_LUT_CHAN_627500_IDX] = { 25100, 0x2, 0x45, 0x171C72, 0x82C },
+	[ATHOS_B_6G_LUT_CHAN_627625_IDX] = { 25105, 0x2, 0x45, 0x178E39, 0x82C },
+	[ATHOS_B_6G_LUT_CHAN_627750_IDX] = { 25110, 0x2, 0x45, 0x180000, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_627875_IDX] = { 25115, 0x2, 0x45, 0x1871C7, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_628000_IDX] = { 25120, 0x2, 0x45, 0x18E38E, 0x82D },
+	[ATHOS_B_6G_LUT_CHAN_628125_IDX] = { 25125, 0x2, 0x45, 0x195555, 0x82E },
+	[ATHOS_B_6G_LUT_CHAN_628250_IDX] = { 25130, 0x2, 0x45, 0x19C71C, 0x82E },
+	[ATHOS_B_6G_LUT_CHAN_628375_IDX] = { 25135, 0x2, 0x45, 0x1A38E4, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628500_IDX] = { 25140, 0x2, 0x45, 0x1AAAAB, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628625_IDX] = { 25145, 0x2, 0x45, 0x1B1C72, 0x82F },
+	[ATHOS_B_6G_LUT_CHAN_628750_IDX] = { 25150, 0x2, 0x45, 0x1B8E39, 0x830 },
+	[ATHOS_B_6G_LUT_CHAN_628875_IDX] = { 25155, 0x2, 0x45, 0x1C0000, 0x830 },
+	[ATHOS_B_6G_LUT_CHAN_629000_IDX] = { 25160, 0x2, 0x45, 0x1C71C7, 0x831 },
+	[ATHOS_B_6G_LUT_CHAN_629125_IDX] = { 25165, 0x2, 0x45, 0x1CE38E, 0x831 },
+	[ATHOS_B_6G_LUT_CHAN_629250_IDX] = { 25170, 0x2, 0x45, 0x1D5555, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629375_IDX] = { 25175, 0x2, 0x45, 0x1DC71C, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629500_IDX] = { 25180, 0x2, 0x45, 0x1E38E4, 0x832 },
+	[ATHOS_B_6G_LUT_CHAN_629625_IDX] = { 25185, 0x2, 0x45, 0x1EAAAB, 0x833 },
+	[ATHOS_B_6G_LUT_CHAN_629750_IDX] = { 25190, 0x2, 0x45, 0x1F1C72, 0x833 },
+	[ATHOS_B_6G_LUT_CHAN_629875_IDX] = { 25195, 0x2, 0x45, 0x1F8E39, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630000_IDX] = { 25200, 0x2, 0x46, 0x0, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630125_IDX] = { 25205, 0x2, 0x46, 0x71C7, 0x834 },
+	[ATHOS_B_6G_LUT_CHAN_630250_IDX] = { 25210, 0x2, 0x46, 0xE38E, 0x835 },
+	[ATHOS_B_6G_LUT_CHAN_630375_IDX] = { 25215, 0x2, 0x46, 0x15555, 0x835 },
+	[ATHOS_B_6G_LUT_CHAN_630500_IDX] = { 25220, 0x2, 0x46, 0x1C71C, 0x836 },
+	[ATHOS_B_6G_LUT_CHAN_630625_IDX] = { 25225, 0x2, 0x46, 0x238E4, 0x836 },
+	[ATHOS_B_6G_LUT_CHAN_630750_IDX] = { 25230, 0x2, 0x46, 0x2AAAB, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_630875_IDX] = { 25235, 0x2, 0x46, 0x31C72, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_631000_IDX] = { 25240, 0x2, 0x46, 0x38E39, 0x837 },
+	[ATHOS_B_6G_LUT_CHAN_631125_IDX] = { 25245, 0x2, 0x46, 0x40000, 0x838 },
+	[ATHOS_B_6G_LUT_CHAN_631250_IDX] = { 25250, 0x2, 0x46, 0x471C7, 0x838 },
+	[ATHOS_B_6G_LUT_CHAN_631375_IDX] = { 25255, 0x2, 0x46, 0x4E38E, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631500_IDX] = { 25260, 0x2, 0x46, 0x55555, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631625_IDX] = { 25265, 0x2, 0x46, 0x5C71C, 0x839 },
+	[ATHOS_B_6G_LUT_CHAN_631750_IDX] = { 25270, 0x2, 0x46, 0x638E4, 0x83A },
+	[ATHOS_B_6G_LUT_CHAN_631875_IDX] = { 25275, 0x2, 0x46, 0x6AAAB, 0x83A },
+	[ATHOS_B_6G_LUT_CHAN_632000_IDX] = { 25280, 0x2, 0x46, 0x71C72, 0x83B },
+	[ATHOS_B_6G_LUT_CHAN_632125_IDX] = { 25285, 0x2, 0x46, 0x78E39, 0x83B },
+	[ATHOS_B_6G_LUT_CHAN_632250_IDX] = { 25290, 0x2, 0x46, 0x80000, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632375_IDX] = { 25295, 0x2, 0x46, 0x871C7, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632500_IDX] = { 25300, 0x2, 0x46, 0x8E38E, 0x83C },
+	[ATHOS_B_6G_LUT_CHAN_632625_IDX] = { 25305, 0x2, 0x46, 0x95555, 0x83D },
+	[ATHOS_B_6G_LUT_CHAN_632750_IDX] = { 25310, 0x2, 0x46, 0x9C71C, 0x83D },
+	[ATHOS_B_6G_LUT_CHAN_632875_IDX] = { 25315, 0x2, 0x46, 0xA38E4, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633000_IDX] = { 25320, 0x2, 0x46, 0xAAAAB, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633125_IDX] = { 25325, 0x2, 0x46, 0xB1C72, 0x83E },
+	[ATHOS_B_6G_LUT_CHAN_633250_IDX] = { 25330, 0x2, 0x46, 0xB8E39, 0x83F },
+	[ATHOS_B_6G_LUT_CHAN_633375_IDX] = { 25335, 0x2, 0x46, 0xC0000, 0x83F },
+	[ATHOS_B_6G_LUT_CHAN_633500_IDX] = { 25340, 0x2, 0x46, 0xC71C7, 0x840 },
+	[ATHOS_B_6G_LUT_CHAN_633625_IDX] = { 25345, 0x2, 0x46, 0xCE38E, 0x840 },
+	[ATHOS_B_6G_LUT_CHAN_633750_IDX] = { 25350, 0x2, 0x46, 0xD5555, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_633875_IDX] = { 25355, 0x2, 0x46, 0xDC71C, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_634000_IDX] = { 25360, 0x2, 0x46, 0xE38E4, 0x841 },
+	[ATHOS_B_6G_LUT_CHAN_634125_IDX] = { 25365, 0x2, 0x46, 0xEAAAB, 0x842 },
+	[ATHOS_B_6G_LUT_CHAN_634250_IDX] = { 25370, 0x2, 0x46, 0xF1C72, 0x842 },
+	[ATHOS_B_6G_LUT_CHAN_634375_IDX] = { 25375, 0x2, 0x46, 0xF8E39, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634500_IDX] = { 25380, 0x2, 0x46, 0x100000, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634625_IDX] = { 25385, 0x2, 0x46, 0x1071C7, 0x843 },
+	[ATHOS_B_6G_LUT_CHAN_634750_IDX] = { 25390, 0x2, 0x46, 0x10E38E, 0x844 },
+	[ATHOS_B_6G_LUT_CHAN_634875_IDX] = { 25395, 0x2, 0x46, 0x115555, 0x844 },
+	[ATHOS_B_6G_LUT_CHAN_635000_IDX] = { 25400, 0x2, 0x46, 0x11C71C, 0x845 },
+	[ATHOS_B_6G_LUT_CHAN_635125_IDX] = { 25405, 0x2, 0x46, 0x1238E4, 0x845 },
+	[ATHOS_B_6G_LUT_CHAN_635250_IDX] = { 25410, 0x2, 0x46, 0x12AAAB, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635375_IDX] = { 25415, 0x2, 0x46, 0x131C72, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635500_IDX] = { 25420, 0x2, 0x46, 0x138E39, 0x846 },
+	[ATHOS_B_6G_LUT_CHAN_635625_IDX] = { 25425, 0x2, 0x46, 0x140000, 0x847 },
+	[ATHOS_B_6G_LUT_CHAN_635750_IDX] = { 25430, 0x2, 0x46, 0x1471C7, 0x847 },
+	[ATHOS_B_6G_LUT_CHAN_635875_IDX] = { 25435, 0x2, 0x46, 0x14E38E, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636000_IDX] = { 25440, 0x2, 0x46, 0x155555, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636125_IDX] = { 25445, 0x2, 0x46, 0x15C71C, 0x848 },
+	[ATHOS_B_6G_LUT_CHAN_636250_IDX] = { 25450, 0x2, 0x46, 0x1638E4, 0x849 },
+	[ATHOS_B_6G_LUT_CHAN_636375_IDX] = { 25455, 0x2, 0x46, 0x16AAAB, 0x849 },
+	[ATHOS_B_6G_LUT_CHAN_636500_IDX] = { 25460, 0x2, 0x46, 0x171C72, 0x84A },
+	[ATHOS_B_6G_LUT_CHAN_636625_IDX] = { 25465, 0x2, 0x46, 0x178E39, 0x84A },
+	[ATHOS_B_6G_LUT_CHAN_636750_IDX] = { 25470, 0x2, 0x46, 0x180000, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_636875_IDX] = { 25475, 0x2, 0x46, 0x1871C7, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_637000_IDX] = { 25480, 0x2, 0x46, 0x18E38E, 0x84B },
+	[ATHOS_B_6G_LUT_CHAN_637125_IDX] = { 25485, 0x2, 0x46, 0x195555, 0x84C },
+	[ATHOS_B_6G_LUT_CHAN_637250_IDX] = { 25490, 0x2, 0x46, 0x19C71C, 0x84C },
+	[ATHOS_B_6G_LUT_CHAN_637375_IDX] = { 25495, 0x2, 0x46, 0x1A38E4, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637500_IDX] = { 25500, 0x2, 0x46, 0x1AAAAB, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637625_IDX] = { 25505, 0x2, 0x46, 0x1B1C72, 0x84D },
+	[ATHOS_B_6G_LUT_CHAN_637750_IDX] = { 25510, 0x2, 0x46, 0x1B8E39, 0x84E },
+	[ATHOS_B_6G_LUT_CHAN_637875_IDX] = { 25515, 0x2, 0x46, 0x1C0000, 0x84E },
+	[ATHOS_B_6G_LUT_CHAN_638000_IDX] = { 25520, 0x2, 0x46, 0x1C71C7, 0x84F },
+	[ATHOS_B_6G_LUT_CHAN_638125_IDX] = { 25525, 0x2, 0x46, 0x1CE38E, 0x84F },
+	[ATHOS_B_6G_LUT_CHAN_638250_IDX] = { 25530, 0x2, 0x46, 0x1D5555, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638375_IDX] = { 25535, 0x2, 0x46, 0x1DC71C, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638500_IDX] = { 25540, 0x2, 0x46, 0x1E38E4, 0x850 },
+	[ATHOS_B_6G_LUT_CHAN_638625_IDX] = { 25545, 0x2, 0x46, 0x1EAAAB, 0x851 },
+	[ATHOS_B_6G_LUT_CHAN_638750_IDX] = { 25550, 0x2, 0x46, 0x1F1C72, 0x851 },
+	[ATHOS_B_6G_LUT_CHAN_638875_IDX] = { 25555, 0x2, 0x46, 0x1F8E39, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639000_IDX] = { 25560, 0x2, 0x47, 0x0, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639125_IDX] = { 25565, 0x2, 0x47, 0x71C7, 0x852 },
+	[ATHOS_B_6G_LUT_CHAN_639250_IDX] = { 25570, 0x2, 0x47, 0xE38E, 0x853 },
+	[ATHOS_B_6G_LUT_CHAN_639375_IDX] = { 25575, 0x2, 0x47, 0x15555, 0x853 },
+	[ATHOS_B_6G_LUT_CHAN_639500_IDX] = { 25580, 0x2, 0x47, 0x1C71C, 0x854 },
+	[ATHOS_B_6G_LUT_CHAN_639625_IDX] = { 25585, 0x2, 0x47, 0x238E4, 0x854 },
+	[ATHOS_B_6G_LUT_CHAN_639750_IDX] = { 25590, 0x2, 0x47, 0x2AAAB, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_639875_IDX] = { 25595, 0x2, 0x47, 0x31C72, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_640000_IDX] = { 25600, 0x2, 0x47, 0x38E39, 0x855 },
+	[ATHOS_B_6G_LUT_CHAN_640125_IDX] = { 25605, 0x2, 0x47, 0x40000, 0x856 },
+	[ATHOS_B_6G_LUT_CHAN_640250_IDX] = { 25610, 0x2, 0x47, 0x471C7, 0x856 },
+	[ATHOS_B_6G_LUT_CHAN_640375_IDX] = { 25615, 0x2, 0x47, 0x4E38E, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640500_IDX] = { 25620, 0x2, 0x47, 0x55555, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640625_IDX] = { 25625, 0x2, 0x47, 0x5C71C, 0x857 },
+	[ATHOS_B_6G_LUT_CHAN_640750_IDX] = { 25630, 0x2, 0x47, 0x638E4, 0x858 },
+	[ATHOS_B_6G_LUT_CHAN_640875_IDX] = { 25635, 0x2, 0x47, 0x6AAAB, 0x858 },
+	[ATHOS_B_6G_LUT_CHAN_641000_IDX] = { 25640, 0x2, 0x47, 0x71C72, 0x859 },
+	[ATHOS_B_6G_LUT_CHAN_641125_IDX] = { 25645, 0x2, 0x47, 0x78E39, 0x859 },
+	[ATHOS_B_6G_LUT_CHAN_641250_IDX] = { 25650, 0x2, 0x47, 0x80000, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641375_IDX] = { 25655, 0x2, 0x47, 0x871C7, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641500_IDX] = { 25660, 0x2, 0x47, 0x8E38E, 0x85A },
+	[ATHOS_B_6G_LUT_CHAN_641625_IDX] = { 25665, 0x2, 0x47, 0x95555, 0x85B },
+	[ATHOS_B_6G_LUT_CHAN_641750_IDX] = { 25670, 0x2, 0x47, 0x9C71C, 0x85B },
+	[ATHOS_B_6G_LUT_CHAN_641875_IDX] = { 25675, 0x2, 0x47, 0xA38E4, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642000_IDX] = { 25680, 0x2, 0x47, 0xAAAAB, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642125_IDX] = { 25685, 0x2, 0x47, 0xB1C72, 0x85C },
+	[ATHOS_B_6G_LUT_CHAN_642250_IDX] = { 25690, 0x2, 0x47, 0xB8E39, 0x85D },
+	[ATHOS_B_6G_LUT_CHAN_642375_IDX] = { 25695, 0x2, 0x47, 0xC0000, 0x85D },
+	[ATHOS_B_6G_LUT_CHAN_642500_IDX] = { 25700, 0x2, 0x47, 0xC71C7, 0x85E },
+	[ATHOS_B_6G_LUT_CHAN_642625_IDX] = { 25705, 0x2, 0x47, 0xCE38E, 0x85E },
+	[ATHOS_B_6G_LUT_CHAN_642750_IDX] = { 25710, 0x2, 0x47, 0xD5555, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_642875_IDX] = { 25715, 0x2, 0x47, 0xDC71C, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_643000_IDX] = { 25720, 0x2, 0x47, 0xE38E4, 0x85F },
+	[ATHOS_B_6G_LUT_CHAN_643125_IDX] = { 25725, 0x2, 0x47, 0xEAAAB, 0x860 },
+	[ATHOS_B_6G_LUT_CHAN_643250_IDX] = { 25730, 0x2, 0x47, 0xF1C72, 0x860 },
+	[ATHOS_B_6G_LUT_CHAN_643375_IDX] = { 25735, 0x2, 0x47, 0xF8E39, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643500_IDX] = { 25740, 0x2, 0x47, 0x100000, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643625_IDX] = { 25745, 0x2, 0x47, 0x1071C7, 0x861 },
+	[ATHOS_B_6G_LUT_CHAN_643750_IDX] = { 25750, 0x2, 0x47, 0x10E38E, 0x862 },
+	[ATHOS_B_6G_LUT_CHAN_643875_IDX] = { 25755, 0x2, 0x47, 0x115555, 0x862 },
+	[ATHOS_B_6G_LUT_CHAN_644000_IDX] = { 25760, 0x2, 0x47, 0x11C71C, 0x863 },
+	[ATHOS_B_6G_LUT_CHAN_644125_IDX] = { 25765, 0x2, 0x47, 0x1238E4, 0x863 },
+	[ATHOS_B_6G_LUT_CHAN_644250_IDX] = { 25770, 0x2, 0x47, 0x12AAAB, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644375_IDX] = { 25775, 0x2, 0x47, 0x131C72, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644500_IDX] = { 25780, 0x2, 0x47, 0x138E39, 0x864 },
+	[ATHOS_B_6G_LUT_CHAN_644625_IDX] = { 25785, 0x2, 0x47, 0x140000, 0x865 },
+	[ATHOS_B_6G_LUT_CHAN_644750_IDX] = { 25790, 0x2, 0x47, 0x1471C7, 0x865 },
+	[ATHOS_B_6G_LUT_CHAN_644875_IDX] = { 25795, 0x2, 0x47, 0x14E38E, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645000_IDX] = { 25800, 0x2, 0x47, 0x155555, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645125_IDX] = { 25805, 0x2, 0x47, 0x15C71C, 0x866 },
+	[ATHOS_B_6G_LUT_CHAN_645250_IDX] = { 25810, 0x2, 0x47, 0x1638E4, 0x867 },
+	[ATHOS_B_6G_LUT_CHAN_645375_IDX] = { 25815, 0x2, 0x47, 0x16AAAB, 0x867 },
+	[ATHOS_B_6G_LUT_CHAN_645500_IDX] = { 25820, 0x2, 0x47, 0x171C72, 0x868 },
+	[ATHOS_B_6G_LUT_CHAN_645625_IDX] = { 25825, 0x2, 0x47, 0x178E39, 0x868 },
+	[ATHOS_B_6G_LUT_CHAN_645750_IDX] = { 25830, 0x2, 0x47, 0x180000, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_645875_IDX] = { 25835, 0x2, 0x47, 0x1871C7, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_646000_IDX] = { 25840, 0x2, 0x47, 0x18E38E, 0x869 },
+	[ATHOS_B_6G_LUT_CHAN_646125_IDX] = { 25845, 0x2, 0x47, 0x195555, 0x86A },
+	[ATHOS_B_6G_LUT_CHAN_646250_IDX] = { 25850, 0x2, 0x47, 0x19C71C, 0x86A },
+	[ATHOS_B_6G_LUT_CHAN_646375_IDX] = { 25855, 0x2, 0x47, 0x1A38E4, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646500_IDX] = { 25860, 0x2, 0x47, 0x1AAAAB, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646625_IDX] = { 25865, 0x2, 0x47, 0x1B1C72, 0x86B },
+	[ATHOS_B_6G_LUT_CHAN_646750_IDX] = { 25870, 0x2, 0x47, 0x1B8E39, 0x86C },
+	[ATHOS_B_6G_LUT_CHAN_646875_IDX] = { 25875, 0x2, 0x47, 0x1C0000, 0x86C },
+	[ATHOS_B_6G_LUT_CHAN_647000_IDX] = { 25880, 0x2, 0x47, 0x1C71C7, 0x86D },
+	[ATHOS_B_6G_LUT_CHAN_647125_IDX] = { 25885, 0x2, 0x47, 0x1CE38E, 0x86D },
+	[ATHOS_B_6G_LUT_CHAN_647250_IDX] = { 25890, 0x2, 0x47, 0x1D5555, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647375_IDX] = { 25895, 0x2, 0x47, 0x1DC71C, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647500_IDX] = { 25900, 0x2, 0x47, 0x1E38E4, 0x86E },
+	[ATHOS_B_6G_LUT_CHAN_647625_IDX] = { 25905, 0x2, 0x47, 0x1EAAAB, 0x86F },
+	[ATHOS_B_6G_LUT_CHAN_647750_IDX] = { 25910, 0x2, 0x47, 0x1F1C72, 0x86F },
+	[ATHOS_B_6G_LUT_CHAN_647875_IDX] = { 25915, 0x2, 0x47, 0x1F8E39, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648000_IDX] = { 25920, 0x2, 0x48, 0x0, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648125_IDX] = { 25925, 0x2, 0x48, 0x71C7, 0x870 },
+	[ATHOS_B_6G_LUT_CHAN_648250_IDX] = { 25930, 0x2, 0x48, 0xE38E, 0x871 },
+	[ATHOS_B_6G_LUT_CHAN_648375_IDX] = { 25935, 0x2, 0x48, 0x15555, 0x871 },
+	[ATHOS_B_6G_LUT_CHAN_648500_IDX] = { 25940, 0x2, 0x48, 0x1C71C, 0x872 },
+	[ATHOS_B_6G_LUT_CHAN_648625_IDX] = { 25945, 0x2, 0x48, 0x238E4, 0x872 },
+	[ATHOS_B_6G_LUT_CHAN_648750_IDX] = { 25950, 0x2, 0x48, 0x2AAAB, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_648875_IDX] = { 25955, 0x2, 0x48, 0x31C72, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_649000_IDX] = { 25960, 0x2, 0x48, 0x38E39, 0x873 },
+	[ATHOS_B_6G_LUT_CHAN_649125_IDX] = { 25965, 0x2, 0x48, 0x40000, 0x874 },
+	[ATHOS_B_6G_LUT_CHAN_649250_IDX] = { 25970, 0x2, 0x48, 0x471C7, 0x874 },
+	[ATHOS_B_6G_LUT_CHAN_649375_IDX] = { 25975, 0x2, 0x48, 0x4E38E, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649500_IDX] = { 25980, 0x2, 0x48, 0x55555, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649625_IDX] = { 25985, 0x2, 0x48, 0x5C71C, 0x875 },
+	[ATHOS_B_6G_LUT_CHAN_649750_IDX] = { 25990, 0x2, 0x48, 0x638E4, 0x876 },
+	[ATHOS_B_6G_LUT_CHAN_649875_IDX] = { 25995, 0x2, 0x48, 0x6AAAB, 0x876 },
+	[ATHOS_B_6G_LUT_CHAN_650000_IDX] = { 26000, 0x2, 0x48, 0x71C72, 0x877 },
+	[ATHOS_B_6G_LUT_CHAN_650125_IDX] = { 26005, 0x2, 0x48, 0x78E39, 0x877 },
+	[ATHOS_B_6G_LUT_CHAN_650250_IDX] = { 26010, 0x2, 0x48, 0x80000, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650375_IDX] = { 26015, 0x2, 0x48, 0x871C7, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650500_IDX] = { 26020, 0x2, 0x48, 0x8E38E, 0x878 },
+	[ATHOS_B_6G_LUT_CHAN_650625_IDX] = { 26025, 0x2, 0x48, 0x95555, 0x879 },
+	[ATHOS_B_6G_LUT_CHAN_650750_IDX] = { 26030, 0x2, 0x48, 0x9C71C, 0x879 },
+	[ATHOS_B_6G_LUT_CHAN_650875_IDX] = { 26035, 0x2, 0x48, 0xA38E4, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651000_IDX] = { 26040, 0x2, 0x48, 0xAAAAB, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651125_IDX] = { 26045, 0x2, 0x48, 0xB1C72, 0x87A },
+	[ATHOS_B_6G_LUT_CHAN_651250_IDX] = { 26050, 0x2, 0x48, 0xB8E39, 0x87B },
+	[ATHOS_B_6G_LUT_CHAN_651375_IDX] = { 26055, 0x2, 0x48, 0xC0000, 0x87B },
+	[ATHOS_B_6G_LUT_CHAN_651500_IDX] = { 26060, 0x2, 0x48, 0xC71C7, 0x87C },
+	[ATHOS_B_6G_LUT_CHAN_651625_IDX] = { 26065, 0x2, 0x48, 0xCE38E, 0x87C },
+	[ATHOS_B_6G_LUT_CHAN_651750_IDX] = { 26070, 0x2, 0x48, 0xD5555, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_651875_IDX] = { 26075, 0x2, 0x48, 0xDC71C, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_652000_IDX] = { 26080, 0x2, 0x48, 0xE38E4, 0x87D },
+	[ATHOS_B_6G_LUT_CHAN_652125_IDX] = { 26085, 0x2, 0x48, 0xEAAAB, 0x87E },
+	[ATHOS_B_6G_LUT_CHAN_652250_IDX] = { 26090, 0x2, 0x48, 0xF1C72, 0x87E },
+	[ATHOS_B_6G_LUT_CHAN_652375_IDX] = { 26095, 0x2, 0x48, 0xF8E39, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652500_IDX] = { 26100, 0x2, 0x48, 0x100000, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652625_IDX] = { 26105, 0x2, 0x48, 0x1071C7, 0x87F },
+	[ATHOS_B_6G_LUT_CHAN_652750_IDX] = { 26110, 0x2, 0x48, 0x10E38E, 0x880 },
+	[ATHOS_B_6G_LUT_CHAN_652875_IDX] = { 26115, 0x2, 0x48, 0x115555, 0x880 },
+	[ATHOS_B_6G_LUT_CHAN_653000_IDX] = { 26120, 0x2, 0x48, 0x11C71C, 0x881 },
+	[ATHOS_B_6G_LUT_CHAN_653125_IDX] = { 26125, 0x2, 0x48, 0x1238E4, 0x881 },
+	[ATHOS_B_6G_LUT_CHAN_653250_IDX] = { 26130, 0x2, 0x48, 0x12AAAB, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653375_IDX] = { 26135, 0x2, 0x48, 0x131C72, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653500_IDX] = { 26140, 0x2, 0x48, 0x138E39, 0x882 },
+	[ATHOS_B_6G_LUT_CHAN_653625_IDX] = { 26145, 0x2, 0x48, 0x140000, 0x883 },
+	[ATHOS_B_6G_LUT_CHAN_653750_IDX] = { 26150, 0x2, 0x48, 0x1471C7, 0x883 },
+	[ATHOS_B_6G_LUT_CHAN_653875_IDX] = { 26155, 0x2, 0x48, 0x14E38E, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654000_IDX] = { 26160, 0x2, 0x48, 0x155555, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654125_IDX] = { 26165, 0x2, 0x48, 0x15C71C, 0x884 },
+	[ATHOS_B_6G_LUT_CHAN_654250_IDX] = { 26170, 0x2, 0x48, 0x1638E4, 0x885 },
+	[ATHOS_B_6G_LUT_CHAN_654375_IDX] = { 26175, 0x2, 0x48, 0x16AAAB, 0x885 },
+	[ATHOS_B_6G_LUT_CHAN_654500_IDX] = { 26180, 0x2, 0x48, 0x171C72, 0x886 },
+	[ATHOS_B_6G_LUT_CHAN_654625_IDX] = { 26185, 0x2, 0x48, 0x178E39, 0x886 },
+	[ATHOS_B_6G_LUT_CHAN_654750_IDX] = { 26190, 0x2, 0x48, 0x180000, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_654875_IDX] = { 26195, 0x2, 0x48, 0x1871C7, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_655000_IDX] = { 26200, 0x2, 0x48, 0x18E38E, 0x887 },
+	[ATHOS_B_6G_LUT_CHAN_655125_IDX] = { 26205, 0x2, 0x48, 0x195555, 0x888 },
+	[ATHOS_B_6G_LUT_CHAN_655250_IDX] = { 26210, 0x2, 0x48, 0x19C71C, 0x888 },
+	[ATHOS_B_6G_LUT_CHAN_655375_IDX] = { 26215, 0x2, 0x48, 0x1A38E4, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655500_IDX] = { 26220, 0x2, 0x48, 0x1AAAAB, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655625_IDX] = { 26225, 0x2, 0x48, 0x1B1C72, 0x889 },
+	[ATHOS_B_6G_LUT_CHAN_655750_IDX] = { 26230, 0x2, 0x48, 0x1B8E39, 0x88A },
+	[ATHOS_B_6G_LUT_CHAN_655875_IDX] = { 26235, 0x2, 0x48, 0x1C0000, 0x88A },
+	[ATHOS_B_6G_LUT_CHAN_656000_IDX] = { 26240, 0x2, 0x48, 0x1C71C7, 0x88B },
+	[ATHOS_B_6G_LUT_CHAN_656125_IDX] = { 26245, 0x2, 0x48, 0x1CE38E, 0x88B },
+	[ATHOS_B_6G_LUT_CHAN_656250_IDX] = { 26250, 0x2, 0x48, 0x1D5555, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656375_IDX] = { 26255, 0x2, 0x48, 0x1DC71C, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656500_IDX] = { 26260, 0x2, 0x48, 0x1E38E4, 0x88C },
+	[ATHOS_B_6G_LUT_CHAN_656625_IDX] = { 26265, 0x2, 0x48, 0x1EAAAB, 0x88D },
+	[ATHOS_B_6G_LUT_CHAN_656750_IDX] = { 26270, 0x2, 0x48, 0x1F1C72, 0x88D },
+	[ATHOS_B_6G_LUT_CHAN_656875_IDX] = { 26275, 0x2, 0x48, 0x1F8E39, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657000_IDX] = { 26280, 0x2, 0x49, 0x0, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657125_IDX] = { 26285, 0x2, 0x49, 0x71C7, 0x88E },
+	[ATHOS_B_6G_LUT_CHAN_657250_IDX] = { 26290, 0x2, 0x49, 0xE38E, 0x88F },
+	[ATHOS_B_6G_LUT_CHAN_657375_IDX] = { 26295, 0x2, 0x49, 0x15555, 0x88F },
+	[ATHOS_B_6G_LUT_CHAN_657500_IDX] = { 26300, 0x2, 0x49, 0x1C71C, 0x890 },
+	[ATHOS_B_6G_LUT_CHAN_657625_IDX] = { 26305, 0x2, 0x49, 0x238E4, 0x890 },
+	[ATHOS_B_6G_LUT_CHAN_657750_IDX] = { 26310, 0x2, 0x49, 0x2AAAB, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_657875_IDX] = { 26315, 0x2, 0x49, 0x31C72, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_658000_IDX] = { 26320, 0x2, 0x49, 0x38E39, 0x891 },
+	[ATHOS_B_6G_LUT_CHAN_658125_IDX] = { 26325, 0x2, 0x49, 0x40000, 0x892 },
+	[ATHOS_B_6G_LUT_CHAN_658250_IDX] = { 26330, 0x2, 0x49, 0x471C7, 0x892 },
+	[ATHOS_B_6G_LUT_CHAN_658375_IDX] = { 26335, 0x2, 0x49, 0x4E38E, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658500_IDX] = { 26340, 0x2, 0x49, 0x55555, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658625_IDX] = { 26345, 0x2, 0x49, 0x5C71C, 0x893 },
+	[ATHOS_B_6G_LUT_CHAN_658750_IDX] = { 26350, 0x2, 0x49, 0x638E4, 0x894 },
+	[ATHOS_B_6G_LUT_CHAN_658875_IDX] = { 26355, 0x2, 0x49, 0x6AAAB, 0x894 },
+	[ATHOS_B_6G_LUT_CHAN_659000_IDX] = { 26360, 0x2, 0x49, 0x71C72, 0x895 },
+	[ATHOS_B_6G_LUT_CHAN_659125_IDX] = { 26365, 0x2, 0x49, 0x78E39, 0x895 },
+	[ATHOS_B_6G_LUT_CHAN_659250_IDX] = { 26370, 0x2, 0x49, 0x80000, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659375_IDX] = { 26375, 0x2, 0x49, 0x871C7, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659500_IDX] = { 26380, 0x2, 0x49, 0x8E38E, 0x896 },
+	[ATHOS_B_6G_LUT_CHAN_659625_IDX] = { 26385, 0x2, 0x49, 0x95555, 0x897 },
+	[ATHOS_B_6G_LUT_CHAN_659750_IDX] = { 26390, 0x2, 0x49, 0x9C71C, 0x897 },
+	[ATHOS_B_6G_LUT_CHAN_659875_IDX] = { 26395, 0x2, 0x49, 0xA38E4, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660000_IDX] = { 26400, 0x2, 0x49, 0xAAAAB, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660125_IDX] = { 26405, 0x2, 0x49, 0xB1C72, 0x898 },
+	[ATHOS_B_6G_LUT_CHAN_660250_IDX] = { 26410, 0x2, 0x49, 0xB8E39, 0x899 },
+	[ATHOS_B_6G_LUT_CHAN_660375_IDX] = { 26415, 0x2, 0x49, 0xC0000, 0x899 },
+	[ATHOS_B_6G_LUT_CHAN_660500_IDX] = { 26420, 0x2, 0x49, 0xC71C7, 0x89A },
+	[ATHOS_B_6G_LUT_CHAN_660625_IDX] = { 26425, 0x2, 0x49, 0xCE38E, 0x89A },
+	[ATHOS_B_6G_LUT_CHAN_660750_IDX] = { 26430, 0x2, 0x49, 0xD5555, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_660875_IDX] = { 26435, 0x2, 0x49, 0xDC71C, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_661000_IDX] = { 26440, 0x2, 0x49, 0xE38E4, 0x89B },
+	[ATHOS_B_6G_LUT_CHAN_661125_IDX] = { 26445, 0x2, 0x49, 0xEAAAB, 0x89C },
+	[ATHOS_B_6G_LUT_CHAN_661250_IDX] = { 26450, 0x2, 0x49, 0xF1C72, 0x89C },
+	[ATHOS_B_6G_LUT_CHAN_661375_IDX] = { 26455, 0x2, 0x49, 0xF8E39, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661500_IDX] = { 26460, 0x2, 0x49, 0x100000, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661625_IDX] = { 26465, 0x2, 0x49, 0x1071C7, 0x89D },
+	[ATHOS_B_6G_LUT_CHAN_661750_IDX] = { 26470, 0x2, 0x49, 0x10E38E, 0x89E },
+	[ATHOS_B_6G_LUT_CHAN_661875_IDX] = { 26475, 0x2, 0x49, 0x115555, 0x89E },
+	[ATHOS_B_6G_LUT_CHAN_662000_IDX] = { 26480, 0x2, 0x49, 0x11C71C, 0x89F },
+	[ATHOS_B_6G_LUT_CHAN_662125_IDX] = { 26485, 0x2, 0x49, 0x1238E4, 0x89F },
+	[ATHOS_B_6G_LUT_CHAN_662250_IDX] = { 26490, 0x2, 0x49, 0x12AAAB, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662375_IDX] = { 26495, 0x2, 0x49, 0x131C72, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662500_IDX] = { 26500, 0x2, 0x49, 0x138E39, 0x8A0 },
+	[ATHOS_B_6G_LUT_CHAN_662625_IDX] = { 26505, 0x2, 0x49, 0x140000, 0x8A1 },
+	[ATHOS_B_6G_LUT_CHAN_662750_IDX] = { 26510, 0x2, 0x49, 0x1471C7, 0x8A1 },
+	[ATHOS_B_6G_LUT_CHAN_662875_IDX] = { 26515, 0x2, 0x49, 0x14E38E, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663000_IDX] = { 26520, 0x2, 0x49, 0x155555, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663125_IDX] = { 26525, 0x2, 0x49, 0x15C71C, 0x8A2 },
+	[ATHOS_B_6G_LUT_CHAN_663250_IDX] = { 26530, 0x2, 0x49, 0x1638E4, 0x8A3 },
+	[ATHOS_B_6G_LUT_CHAN_663375_IDX] = { 26535, 0x2, 0x49, 0x16AAAB, 0x8A3 },
+	[ATHOS_B_6G_LUT_CHAN_663500_IDX] = { 26540, 0x2, 0x49, 0x171C72, 0x8A4 },
+	[ATHOS_B_6G_LUT_CHAN_663625_IDX] = { 26545, 0x2, 0x49, 0x178E39, 0x8A4 },
+	[ATHOS_B_6G_LUT_CHAN_663750_IDX] = { 26550, 0x2, 0x49, 0x180000, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_663875_IDX] = { 26555, 0x2, 0x49, 0x1871C7, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_664000_IDX] = { 26560, 0x2, 0x49, 0x18E38E, 0x8A5 },
+	[ATHOS_B_6G_LUT_CHAN_664125_IDX] = { 26565, 0x2, 0x49, 0x195555, 0x8A6 },
+	[ATHOS_B_6G_LUT_CHAN_664250_IDX] = { 26570, 0x2, 0x49, 0x19C71C, 0x8A6 },
+	[ATHOS_B_6G_LUT_CHAN_664375_IDX] = { 26575, 0x2, 0x49, 0x1A38E4, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664500_IDX] = { 26580, 0x2, 0x49, 0x1AAAAB, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664625_IDX] = { 26585, 0x2, 0x49, 0x1B1C72, 0x8A7 },
+	[ATHOS_B_6G_LUT_CHAN_664750_IDX] = { 26590, 0x2, 0x49, 0x1B8E39, 0x8A8 },
+	[ATHOS_B_6G_LUT_CHAN_664875_IDX] = { 26595, 0x2, 0x49, 0x1C0000, 0x8A8 },
+	[ATHOS_B_6G_LUT_CHAN_665000_IDX] = { 26600, 0x2, 0x49, 0x1C71C7, 0x8A9 },
+	[ATHOS_B_6G_LUT_CHAN_665125_IDX] = { 26605, 0x2, 0x49, 0x1CE38E, 0x8A9 },
+	[ATHOS_B_6G_LUT_CHAN_665250_IDX] = { 26610, 0x2, 0x49, 0x1D5555, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665375_IDX] = { 26615, 0x2, 0x49, 0x1DC71C, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665500_IDX] = { 26620, 0x2, 0x49, 0x1E38E4, 0x8AA },
+	[ATHOS_B_6G_LUT_CHAN_665625_IDX] = { 26625, 0x2, 0x49, 0x1EAAAB, 0x8AB },
+	[ATHOS_B_6G_LUT_CHAN_665750_IDX] = { 26630, 0x2, 0x49, 0x1F1C72, 0x8AB },
+	[ATHOS_B_6G_LUT_CHAN_665875_IDX] = { 26635, 0x2, 0x49, 0x1F8E39, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666000_IDX] = { 26640, 0x2, 0x4A, 0x0, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666125_IDX] = { 26645, 0x2, 0x4A, 0x71C7, 0x8AC },
+	[ATHOS_B_6G_LUT_CHAN_666250_IDX] = { 26650, 0x2, 0x4A, 0xE38E, 0x8AD },
+	[ATHOS_B_6G_LUT_CHAN_666375_IDX] = { 26655, 0x2, 0x4A, 0x15555, 0x8AD },
+	[ATHOS_B_6G_LUT_CHAN_666500_IDX] = { 26660, 0x2, 0x4A, 0x1C71C, 0x8AE },
+	[ATHOS_B_6G_LUT_CHAN_666625_IDX] = { 26665, 0x2, 0x4A, 0x238E4, 0x8AE },
+	[ATHOS_B_6G_LUT_CHAN_666750_IDX] = { 26670, 0x2, 0x4A, 0x2AAAB, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_666875_IDX] = { 26675, 0x2, 0x4A, 0x31C72, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_667000_IDX] = { 26680, 0x2, 0x4A, 0x38E39, 0x8AF },
+	[ATHOS_B_6G_LUT_CHAN_667125_IDX] = { 26685, 0x2, 0x4A, 0x40000, 0x8B0 },
+	[ATHOS_B_6G_LUT_CHAN_667250_IDX] = { 26690, 0x2, 0x4A, 0x471C7, 0x8B0 },
+	[ATHOS_B_6G_LUT_CHAN_667375_IDX] = { 26695, 0x2, 0x4A, 0x4E38E, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667500_IDX] = { 26700, 0x2, 0x4A, 0x55555, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667625_IDX] = { 26705, 0x2, 0x4A, 0x5C71C, 0x8B1 },
+	[ATHOS_B_6G_LUT_CHAN_667750_IDX] = { 26710, 0x2, 0x4A, 0x638E4, 0x8B2 },
+	[ATHOS_B_6G_LUT_CHAN_667875_IDX] = { 26715, 0x2, 0x4A, 0x6AAAB, 0x8B2 },
+	[ATHOS_B_6G_LUT_CHAN_668000_IDX] = { 26720, 0x2, 0x4A, 0x71C72, 0x8B3 },
+	[ATHOS_B_6G_LUT_CHAN_668125_IDX] = { 26725, 0x2, 0x4A, 0x78E39, 0x8B3 },
+	[ATHOS_B_6G_LUT_CHAN_668250_IDX] = { 26730, 0x2, 0x4A, 0x80000, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668375_IDX] = { 26735, 0x2, 0x4A, 0x871C7, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668500_IDX] = { 26740, 0x2, 0x4A, 0x8E38E, 0x8B4 },
+	[ATHOS_B_6G_LUT_CHAN_668625_IDX] = { 26745, 0x2, 0x4A, 0x95555, 0x8B5 },
+	[ATHOS_B_6G_LUT_CHAN_668750_IDX] = { 26750, 0x2, 0x4A, 0x9C71C, 0x8B5 },
+	[ATHOS_B_6G_LUT_CHAN_668875_IDX] = { 26755, 0x2, 0x4A, 0xA38E4, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669000_IDX] = { 26760, 0x2, 0x4A, 0xAAAAB, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669125_IDX] = { 26765, 0x2, 0x4A, 0xB1C72, 0x8B6 },
+	[ATHOS_B_6G_LUT_CHAN_669250_IDX] = { 26770, 0x2, 0x4A, 0xB8E39, 0x8B7 },
+	[ATHOS_B_6G_LUT_CHAN_669375_IDX] = { 26775, 0x2, 0x4A, 0xC0000, 0x8B7 },
+	[ATHOS_B_6G_LUT_CHAN_669500_IDX] = { 26780, 0x2, 0x4A, 0xC71C7, 0x8B8 },
+	[ATHOS_B_6G_LUT_CHAN_669625_IDX] = { 26785, 0x2, 0x4A, 0xCE38E, 0x8B8 },
+	[ATHOS_B_6G_LUT_CHAN_669750_IDX] = { 26790, 0x2, 0x4A, 0xD5555, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_669875_IDX] = { 26795, 0x2, 0x4A, 0xDC71C, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_670000_IDX] = { 26800, 0x2, 0x4A, 0xE38E4, 0x8B9 },
+	[ATHOS_B_6G_LUT_CHAN_670125_IDX] = { 26805, 0x2, 0x4A, 0xEAAAB, 0x8BA },
+	[ATHOS_B_6G_LUT_CHAN_670250_IDX] = { 26810, 0x2, 0x4A, 0xF1C72, 0x8BA },
+	[ATHOS_B_6G_LUT_CHAN_670375_IDX] = { 26815, 0x2, 0x4A, 0xF8E39, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670500_IDX] = { 26820, 0x2, 0x4A, 0x100000, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670625_IDX] = { 26825, 0x2, 0x4A, 0x1071C7, 0x8BB },
+	[ATHOS_B_6G_LUT_CHAN_670750_IDX] = { 26830, 0x2, 0x4A, 0x10E38E, 0x8BC },
+	[ATHOS_B_6G_LUT_CHAN_670875_IDX] = { 26835, 0x2, 0x4A, 0x115555, 0x8BC },
+	[ATHOS_B_6G_LUT_CHAN_671000_IDX] = { 26840, 0x2, 0x4A, 0x11C71C, 0x8BD },
+	[ATHOS_B_6G_LUT_CHAN_671125_IDX] = { 26845, 0x2, 0x4A, 0x1238E4, 0x8BD },
+	[ATHOS_B_6G_LUT_CHAN_671250_IDX] = { 26850, 0x2, 0x4A, 0x12AAAB, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671375_IDX] = { 26855, 0x2, 0x4A, 0x131C72, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671500_IDX] = { 26860, 0x2, 0x4A, 0x138E39, 0x8BE },
+	[ATHOS_B_6G_LUT_CHAN_671625_IDX] = { 26865, 0x2, 0x4A, 0x140000, 0x8BF },
+	[ATHOS_B_6G_LUT_CHAN_671750_IDX] = { 26870, 0x2, 0x4A, 0x1471C7, 0x8BF },
+	[ATHOS_B_6G_LUT_CHAN_671875_IDX] = { 26875, 0x2, 0x4A, 0x14E38E, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672000_IDX] = { 26880, 0x2, 0x4A, 0x155555, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672125_IDX] = { 26885, 0x2, 0x4A, 0x15C71C, 0x8C0 },
+	[ATHOS_B_6G_LUT_CHAN_672250_IDX] = { 26890, 0x2, 0x4A, 0x1638E4, 0x8C1 },
+	[ATHOS_B_6G_LUT_CHAN_672375_IDX] = { 26895, 0x2, 0x4A, 0x16AAAB, 0x8C1 },
+	[ATHOS_B_6G_LUT_CHAN_672500_IDX] = { 26900, 0x2, 0x4A, 0x171C72, 0x8C2 },
+	[ATHOS_B_6G_LUT_CHAN_672625_IDX] = { 26905, 0x2, 0x4A, 0x178E39, 0x8C2 },
+	[ATHOS_B_6G_LUT_CHAN_672750_IDX] = { 26910, 0x2, 0x4A, 0x180000, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_672875_IDX] = { 26915, 0x2, 0x4A, 0x1871C7, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_673000_IDX] = { 26920, 0x2, 0x4A, 0x18E38E, 0x8C3 },
+	[ATHOS_B_6G_LUT_CHAN_673125_IDX] = { 26925, 0x2, 0x4A, 0x195555, 0x8C4 },
+	[ATHOS_B_6G_LUT_CHAN_673250_IDX] = { 26930, 0x2, 0x4A, 0x19C71C, 0x8C4 },
+	[ATHOS_B_6G_LUT_CHAN_673375_IDX] = { 26935, 0x2, 0x4A, 0x1A38E4, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673500_IDX] = { 26940, 0x2, 0x4A, 0x1AAAAB, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673625_IDX] = { 26945, 0x2, 0x4A, 0x1B1C72, 0x8C5 },
+	[ATHOS_B_6G_LUT_CHAN_673750_IDX] = { 26950, 0x2, 0x4A, 0x1B8E39, 0x8C6 },
+	[ATHOS_B_6G_LUT_CHAN_673875_IDX] = { 26955, 0x2, 0x4A, 0x1C0000, 0x8C6 },
+	[ATHOS_B_6G_LUT_CHAN_674000_IDX] = { 26960, 0x2, 0x4A, 0x1C71C7, 0x8C7 },
+	[ATHOS_B_6G_LUT_CHAN_674125_IDX] = { 26965, 0x2, 0x4A, 0x1CE38E, 0x8C7 },
+	[ATHOS_B_6G_LUT_CHAN_674250_IDX] = { 26970, 0x2, 0x4A, 0x1D5555, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674375_IDX] = { 26975, 0x2, 0x4A, 0x1DC71C, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674500_IDX] = { 26980, 0x2, 0x4A, 0x1E38E4, 0x8C8 },
+	[ATHOS_B_6G_LUT_CHAN_674625_IDX] = { 26985, 0x2, 0x4A, 0x1EAAAB, 0x8C9 },
+	[ATHOS_B_6G_LUT_CHAN_674750_IDX] = { 26990, 0x2, 0x4A, 0x1F1C72, 0x8C9 },
+	[ATHOS_B_6G_LUT_CHAN_674875_IDX] = { 26995, 0x2, 0x4A, 0x1F8E39, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675000_IDX] = { 27000, 0x2, 0x4B, 0x0, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675125_IDX] = { 27005, 0x2, 0x4B, 0x71C7, 0x8CA },
+	[ATHOS_B_6G_LUT_CHAN_675250_IDX] = { 27010, 0x2, 0x4B, 0xE38E, 0x8CB },
+	[ATHOS_B_6G_LUT_CHAN_675375_IDX] = { 27015, 0x2, 0x4B, 0x15555, 0x8CB },
+	[ATHOS_B_6G_LUT_CHAN_675500_IDX] = { 27020, 0x2, 0x4B, 0x1C71C, 0x8CC },
+	[ATHOS_B_6G_LUT_CHAN_675625_IDX] = { 27025, 0x2, 0x4B, 0x238E4, 0x8CC },
+	[ATHOS_B_6G_LUT_CHAN_675750_IDX] = { 27030, 0x2, 0x4B, 0x2AAAB, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_675875_IDX] = { 27035, 0x2, 0x4B, 0x31C72, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_676000_IDX] = { 27040, 0x2, 0x4B, 0x38E39, 0x8CD },
+	[ATHOS_B_6G_LUT_CHAN_676125_IDX] = { 27045, 0x2, 0x4B, 0x40000, 0x8CE },
+	[ATHOS_B_6G_LUT_CHAN_676250_IDX] = { 27050, 0x2, 0x4B, 0x471C7, 0x8CE },
+	[ATHOS_B_6G_LUT_CHAN_676375_IDX] = { 27055, 0x2, 0x4B, 0x4E38E, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676500_IDX] = { 27060, 0x2, 0x4B, 0x55555, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676625_IDX] = { 27065, 0x2, 0x4B, 0x5C71C, 0x8CF },
+	[ATHOS_B_6G_LUT_CHAN_676750_IDX] = { 27070, 0x2, 0x4B, 0x638E4, 0x8D0 },
+	[ATHOS_B_6G_LUT_CHAN_676875_IDX] = { 27075, 0x2, 0x4B, 0x6AAAB, 0x8D0 },
+	[ATHOS_B_6G_LUT_CHAN_677000_IDX] = { 27080, 0x2, 0x4B, 0x71C72, 0x8D1 },
+	[ATHOS_B_6G_LUT_CHAN_677125_IDX] = { 27085, 0x2, 0x4B, 0x78E39, 0x8D1 },
+	[ATHOS_B_6G_LUT_CHAN_677250_IDX] = { 27090, 0x2, 0x4B, 0x80000, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677375_IDX] = { 27095, 0x2, 0x4B, 0x871C7, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677500_IDX] = { 27100, 0x2, 0x4B, 0x8E38E, 0x8D2 },
+	[ATHOS_B_6G_LUT_CHAN_677625_IDX] = { 27105, 0x2, 0x4B, 0x95555, 0x8D3 },
+	[ATHOS_B_6G_LUT_CHAN_677750_IDX] = { 27110, 0x2, 0x4B, 0x9C71C, 0x8D3 },
+	[ATHOS_B_6G_LUT_CHAN_677875_IDX] = { 27115, 0x2, 0x4B, 0xA38E4, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678000_IDX] = { 27120, 0x2, 0x4B, 0xAAAAB, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678125_IDX] = { 27125, 0x2, 0x4B, 0xB1C72, 0x8D4 },
+	[ATHOS_B_6G_LUT_CHAN_678250_IDX] = { 27130, 0x2, 0x4B, 0xB8E39, 0x8D5 },
+	[ATHOS_B_6G_LUT_CHAN_678375_IDX] = { 27135, 0x2, 0x4B, 0xC0000, 0x8D5 },
+	[ATHOS_B_6G_LUT_CHAN_678500_IDX] = { 27140, 0x2, 0x4B, 0xC71C7, 0x8D6 },
+	[ATHOS_B_6G_LUT_CHAN_678625_IDX] = { 27145, 0x2, 0x4B, 0xCE38E, 0x8D6 },
+	[ATHOS_B_6G_LUT_CHAN_678750_IDX] = { 27150, 0x2, 0x4B, 0xD5555, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_678875_IDX] = { 27155, 0x2, 0x4B, 0xDC71C, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_679000_IDX] = { 27160, 0x2, 0x4B, 0xE38E4, 0x8D7 },
+	[ATHOS_B_6G_LUT_CHAN_679125_IDX] = { 27165, 0x2, 0x4B, 0xEAAAB, 0x8D8 },
+	[ATHOS_B_6G_LUT_CHAN_679250_IDX] = { 27170, 0x2, 0x4B, 0xF1C72, 0x8D8 },
+	[ATHOS_B_6G_LUT_CHAN_679375_IDX] = { 27175, 0x2, 0x4B, 0xF8E39, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679500_IDX] = { 27180, 0x2, 0x4B, 0x100000, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679625_IDX] = { 27185, 0x2, 0x4B, 0x1071C7, 0x8D9 },
+	[ATHOS_B_6G_LUT_CHAN_679750_IDX] = { 27190, 0x2, 0x4B, 0x10E38E, 0x8DA },
+	[ATHOS_B_6G_LUT_CHAN_679875_IDX] = { 27195, 0x2, 0x4B, 0x115555, 0x8DA },
+	[ATHOS_B_6G_LUT_CHAN_680000_IDX] = { 27200, 0x2, 0x4B, 0x11C71C, 0x8DB },
+	[ATHOS_B_6G_LUT_CHAN_680125_IDX] = { 27205, 0x2, 0x4B, 0x1238E4, 0x8DB },
+	[ATHOS_B_6G_LUT_CHAN_680250_IDX] = { 27210, 0x2, 0x4B, 0x12AAAB, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680375_IDX] = { 27215, 0x2, 0x4B, 0x131C72, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680500_IDX] = { 27220, 0x2, 0x4B, 0x138E39, 0x8DC },
+	[ATHOS_B_6G_LUT_CHAN_680625_IDX] = { 27225, 0x2, 0x4B, 0x140000, 0x8DD },
+	[ATHOS_B_6G_LUT_CHAN_680750_IDX] = { 27230, 0x2, 0x4B, 0x1471C7, 0x8DD },
+	[ATHOS_B_6G_LUT_CHAN_680875_IDX] = { 27235, 0x2, 0x4B, 0x14E38E, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681000_IDX] = { 27240, 0x2, 0x4B, 0x155555, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681125_IDX] = { 27245, 0x2, 0x4B, 0x15C71C, 0x8DE },
+	[ATHOS_B_6G_LUT_CHAN_681250_IDX] = { 27250, 0x2, 0x4B, 0x1638E4, 0x8DF },
+	[ATHOS_B_6G_LUT_CHAN_681375_IDX] = { 27255, 0x2, 0x4B, 0x16AAAB, 0x8DF },
+	[ATHOS_B_6G_LUT_CHAN_681500_IDX] = { 27260, 0x2, 0x4B, 0x171C72, 0x8E0 },
+	[ATHOS_B_6G_LUT_CHAN_681625_IDX] = { 27265, 0x2, 0x4B, 0x178E39, 0x8E0 },
+	[ATHOS_B_6G_LUT_CHAN_681750_IDX] = { 27270, 0x2, 0x4B, 0x180000, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_681875_IDX] = { 27275, 0x2, 0x4B, 0x1871C7, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_682000_IDX] = { 27280, 0x2, 0x4B, 0x18E38E, 0x8E1 },
+	[ATHOS_B_6G_LUT_CHAN_682125_IDX] = { 27285, 0x2, 0x4B, 0x195555, 0x8E2 },
+	[ATHOS_B_6G_LUT_CHAN_682250_IDX] = { 27290, 0x2, 0x4B, 0x19C71C, 0x8E2 },
+	[ATHOS_B_6G_LUT_CHAN_682375_IDX] = { 27295, 0x2, 0x4B, 0x1A38E4, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682500_IDX] = { 27300, 0x2, 0x4B, 0x1AAAAB, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682625_IDX] = { 27305, 0x2, 0x4B, 0x1B1C72, 0x8E3 },
+	[ATHOS_B_6G_LUT_CHAN_682750_IDX] = { 27310, 0x2, 0x4B, 0x1B8E39, 0x8E4 },
+	[ATHOS_B_6G_LUT_CHAN_682875_IDX] = { 27315, 0x2, 0x4B, 0x1C0000, 0x8E4 },
+	[ATHOS_B_6G_LUT_CHAN_683000_IDX] = { 27320, 0x2, 0x4B, 0x1C71C7, 0x8E5 },
+	[ATHOS_B_6G_LUT_CHAN_683125_IDX] = { 27325, 0x2, 0x4B, 0x1CE38E, 0x8E5 },
+	[ATHOS_B_6G_LUT_CHAN_683250_IDX] = { 27330, 0x2, 0x4B, 0x1D5555, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683375_IDX] = { 27335, 0x2, 0x4B, 0x1DC71C, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683500_IDX] = { 27340, 0x2, 0x4B, 0x1E38E4, 0x8E6 },
+	[ATHOS_B_6G_LUT_CHAN_683625_IDX] = { 27345, 0x2, 0x4B, 0x1EAAAB, 0x8E7 },
+	[ATHOS_B_6G_LUT_CHAN_683750_IDX] = { 27350, 0x2, 0x4B, 0x1F1C72, 0x8E7 },
+	[ATHOS_B_6G_LUT_CHAN_683875_IDX] = { 27355, 0x2, 0x4B, 0x1F8E39, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684000_IDX] = { 27360, 0x2, 0x4C, 0x0, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684125_IDX] = { 27365, 0x2, 0x4C, 0x71C7, 0x8E8 },
+	[ATHOS_B_6G_LUT_CHAN_684250_IDX] = { 27370, 0x2, 0x4C, 0xE38E, 0x8E9 },
+	[ATHOS_B_6G_LUT_CHAN_684375_IDX] = { 27375, 0x2, 0x4C, 0x15555, 0x8E9 },
+	[ATHOS_B_6G_LUT_CHAN_684500_IDX] = { 27380, 0x2, 0x4C, 0x1C71C, 0x8EA },
+	[ATHOS_B_6G_LUT_CHAN_684625_IDX] = { 27385, 0x2, 0x4C, 0x238E4, 0x8EA },
+	[ATHOS_B_6G_LUT_CHAN_684750_IDX] = { 27390, 0x2, 0x4C, 0x2AAAB, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_684875_IDX] = { 27395, 0x2, 0x4C, 0x31C72, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_685000_IDX] = { 27400, 0x2, 0x4C, 0x38E39, 0x8EB },
+	[ATHOS_B_6G_LUT_CHAN_685125_IDX] = { 27405, 0x2, 0x4C, 0x40000, 0x8EC },
+	[ATHOS_B_6G_LUT_CHAN_685250_IDX] = { 27410, 0x2, 0x4C, 0x471C7, 0x8EC },
+	[ATHOS_B_6G_LUT_CHAN_685375_IDX] = { 27415, 0x2, 0x4C, 0x4E38E, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685500_IDX] = { 27420, 0x2, 0x4C, 0x55555, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685625_IDX] = { 27425, 0x2, 0x4C, 0x5C71C, 0x8ED },
+	[ATHOS_B_6G_LUT_CHAN_685750_IDX] = { 27430, 0x2, 0x4C, 0x638E4, 0x8EE },
+	[ATHOS_B_6G_LUT_CHAN_685875_IDX] = { 27435, 0x2, 0x4C, 0x6AAAB, 0x8EE },
+	[ATHOS_B_6G_LUT_CHAN_686000_IDX] = { 27440, 0x2, 0x4C, 0x71C72, 0x8EF },
+	[ATHOS_B_6G_LUT_CHAN_686125_IDX] = { 27445, 0x2, 0x4C, 0x78E39, 0x8EF },
+	[ATHOS_B_6G_LUT_CHAN_686250_IDX] = { 27450, 0x2, 0x4C, 0x80000, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686375_IDX] = { 27455, 0x2, 0x4C, 0x871C7, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686500_IDX] = { 27460, 0x2, 0x4C, 0x8E38E, 0x8F0 },
+	[ATHOS_B_6G_LUT_CHAN_686625_IDX] = { 27465, 0x2, 0x4C, 0x95555, 0x8F1 },
+	[ATHOS_B_6G_LUT_CHAN_686750_IDX] = { 27470, 0x2, 0x4C, 0x9C71C, 0x8F1 },
+	[ATHOS_B_6G_LUT_CHAN_686875_IDX] = { 27475, 0x2, 0x4C, 0xA38E4, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687000_IDX] = { 27480, 0x2, 0x4C, 0xAAAAB, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687125_IDX] = { 27485, 0x2, 0x4C, 0xB1C72, 0x8F2 },
+	[ATHOS_B_6G_LUT_CHAN_687250_IDX] = { 27490, 0x2, 0x4C, 0xB8E39, 0x8F3 },
+	[ATHOS_B_6G_LUT_CHAN_687375_IDX] = { 27495, 0x2, 0x4C, 0xC0000, 0x8F3 },
+	[ATHOS_B_6G_LUT_CHAN_687500_IDX] = { 27500, 0x2, 0x4C, 0xC71C7, 0x8F4 },
+	[ATHOS_B_6G_LUT_CHAN_687625_IDX] = { 27505, 0x2, 0x4C, 0xCE38E, 0x8F4 },
+	[ATHOS_B_6G_LUT_CHAN_687750_IDX] = { 27510, 0x2, 0x4C, 0xD5555, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_687875_IDX] = { 27515, 0x2, 0x4C, 0xDC71C, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_688000_IDX] = { 27520, 0x2, 0x4C, 0xE38E4, 0x8F5 },
+	[ATHOS_B_6G_LUT_CHAN_688125_IDX] = { 27525, 0x2, 0x4C, 0xEAAAB, 0x8F6 },
+	[ATHOS_B_6G_LUT_CHAN_688250_IDX] = { 27530, 0x2, 0x4C, 0xF1C72, 0x8F6 },
+	[ATHOS_B_6G_LUT_CHAN_688375_IDX] = { 27535, 0x2, 0x4C, 0xF8E39, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688500_IDX] = { 27540, 0x2, 0x4C, 0x100000, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688625_IDX] = { 27545, 0x2, 0x4C, 0x1071C7, 0x8F7 },
+	[ATHOS_B_6G_LUT_CHAN_688750_IDX] = { 27550, 0x2, 0x4C, 0x10E38E, 0x8F8 },
+	[ATHOS_B_6G_LUT_CHAN_688875_IDX] = { 27555, 0x2, 0x4C, 0x115555, 0x8F8 },
+	[ATHOS_B_6G_LUT_CHAN_689000_IDX] = { 27560, 0x2, 0x4C, 0x11C71C, 0x8F9 },
+	[ATHOS_B_6G_LUT_CHAN_689125_IDX] = { 27565, 0x2, 0x4C, 0x1238E4, 0x8F9 },
+	[ATHOS_B_6G_LUT_CHAN_689250_IDX] = { 27570, 0x2, 0x4C, 0x12AAAB, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689375_IDX] = { 27575, 0x2, 0x4C, 0x131C72, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689500_IDX] = { 27580, 0x2, 0x4C, 0x138E39, 0x8FA },
+	[ATHOS_B_6G_LUT_CHAN_689625_IDX] = { 27585, 0x2, 0x4C, 0x140000, 0x8FB },
+	[ATHOS_B_6G_LUT_CHAN_689750_IDX] = { 27590, 0x2, 0x4C, 0x1471C7, 0x8FB },
+	[ATHOS_B_6G_LUT_CHAN_689875_IDX] = { 27595, 0x2, 0x4C, 0x14E38E, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690000_IDX] = { 27600, 0x2, 0x4C, 0x155555, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690125_IDX] = { 27605, 0x2, 0x4C, 0x15C71C, 0x8FC },
+	[ATHOS_B_6G_LUT_CHAN_690250_IDX] = { 27610, 0x2, 0x4C, 0x1638E4, 0x8FD },
+	[ATHOS_B_6G_LUT_CHAN_690375_IDX] = { 27615, 0x2, 0x4C, 0x16AAAB, 0x8FD },
+	[ATHOS_B_6G_LUT_CHAN_690500_IDX] = { 27620, 0x2, 0x4C, 0x171C72, 0x8FE },
+	[ATHOS_B_6G_LUT_CHAN_690625_IDX] = { 27625, 0x2, 0x4C, 0x178E39, 0x8FE },
+	[ATHOS_B_6G_LUT_CHAN_690750_IDX] = { 27630, 0x2, 0x4C, 0x180000, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_690875_IDX] = { 27635, 0x2, 0x4C, 0x1871C7, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_691000_IDX] = { 27640, 0x2, 0x4C, 0x18E38E, 0x8FF },
+	[ATHOS_B_6G_LUT_CHAN_691125_IDX] = { 27645, 0x2, 0x4C, 0x195555, 0x900 },
+	[ATHOS_B_6G_LUT_CHAN_691250_IDX] = { 27650, 0x2, 0x4C, 0x19C71C, 0x900 },
+	[ATHOS_B_6G_LUT_CHAN_691375_IDX] = { 27655, 0x2, 0x4C, 0x1A38E4, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691500_IDX] = { 27660, 0x2, 0x4C, 0x1AAAAB, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691625_IDX] = { 27665, 0x2, 0x4C, 0x1B1C72, 0x901 },
+	[ATHOS_B_6G_LUT_CHAN_691750_IDX] = { 27670, 0x2, 0x4C, 0x1B8E39, 0x902 },
+	[ATHOS_B_6G_LUT_CHAN_691875_IDX] = { 27675, 0x2, 0x4C, 0x1C0000, 0x902 },
+	[ATHOS_B_6G_LUT_CHAN_692000_IDX] = { 27680, 0x2, 0x4C, 0x1C71C7, 0x903 },
+	[ATHOS_B_6G_LUT_CHAN_692125_IDX] = { 27685, 0x2, 0x4C, 0x1CE38E, 0x903 },
+	[ATHOS_B_6G_LUT_CHAN_692250_IDX] = { 27690, 0x2, 0x4C, 0x1D5555, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692375_IDX] = { 27695, 0x2, 0x4C, 0x1DC71C, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692500_IDX] = { 27700, 0x2, 0x4C, 0x1E38E4, 0x904 },
+	[ATHOS_B_6G_LUT_CHAN_692625_IDX] = { 27705, 0x2, 0x4C, 0x1EAAAB, 0x905 },
+	[ATHOS_B_6G_LUT_CHAN_692750_IDX] = { 27710, 0x2, 0x4C, 0x1F1C72, 0x905 },
+	[ATHOS_B_6G_LUT_CHAN_692875_IDX] = { 27715, 0x2, 0x4C, 0x1F8E39, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693000_IDX] = { 27720, 0x2, 0x4D, 0x0, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693125_IDX] = { 27725, 0x2, 0x4D, 0x71C7, 0x906 },
+	[ATHOS_B_6G_LUT_CHAN_693250_IDX] = { 27730, 0x2, 0x4D, 0xE38E, 0x907 },
+	[ATHOS_B_6G_LUT_CHAN_693375_IDX] = { 27735, 0x2, 0x4D, 0x15555, 0x907 },
+	[ATHOS_B_6G_LUT_CHAN_693500_IDX] = { 27740, 0x2, 0x4D, 0x1C71C, 0x908 },
+	[ATHOS_B_6G_LUT_CHAN_693625_IDX] = { 27745, 0x2, 0x4D, 0x238E4, 0x908 },
+	[ATHOS_B_6G_LUT_CHAN_693750_IDX] = { 27750, 0x2, 0x4D, 0x2AAAB, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_693875_IDX] = { 27755, 0x2, 0x4D, 0x31C72, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_694000_IDX] = { 27760, 0x2, 0x4D, 0x38E39, 0x909 },
+	[ATHOS_B_6G_LUT_CHAN_694125_IDX] = { 27765, 0x2, 0x4D, 0x40000, 0x90A },
+	[ATHOS_B_6G_LUT_CHAN_694250_IDX] = { 27770, 0x2, 0x4D, 0x471C7, 0x90A },
+	[ATHOS_B_6G_LUT_CHAN_694375_IDX] = { 27775, 0x2, 0x4D, 0x4E38E, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694500_IDX] = { 27780, 0x2, 0x4D, 0x55555, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694625_IDX] = { 27785, 0x2, 0x4D, 0x5C71C, 0x90B },
+	[ATHOS_B_6G_LUT_CHAN_694750_IDX] = { 27790, 0x2, 0x4D, 0x638E4, 0x90C },
+	[ATHOS_B_6G_LUT_CHAN_694875_IDX] = { 27795, 0x2, 0x4D, 0x6AAAB, 0x90C },
+	[ATHOS_B_6G_LUT_CHAN_695000_IDX] = { 27800, 0x2, 0x4D, 0x71C72, 0x90D },
+	[ATHOS_B_6G_LUT_CHAN_695125_IDX] = { 27805, 0x2, 0x4D, 0x78E39, 0x90D },
+	[ATHOS_B_6G_LUT_CHAN_695250_IDX] = { 27810, 0x2, 0x4D, 0x80000, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695375_IDX] = { 27815, 0x2, 0x4D, 0x871C7, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695500_IDX] = { 27820, 0x2, 0x4D, 0x8E38E, 0x90E },
+	[ATHOS_B_6G_LUT_CHAN_695625_IDX] = { 27825, 0x2, 0x4D, 0x95555, 0x90F },
+	[ATHOS_B_6G_LUT_CHAN_695750_IDX] = { 27830, 0x2, 0x4D, 0x9C71C, 0x90F },
+	[ATHOS_B_6G_LUT_CHAN_695875_IDX] = { 27835, 0x2, 0x4D, 0xA38E4, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696000_IDX] = { 27840, 0x2, 0x4D, 0xAAAAB, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696125_IDX] = { 27845, 0x2, 0x4D, 0xB1C72, 0x910 },
+	[ATHOS_B_6G_LUT_CHAN_696250_IDX] = { 27850, 0x2, 0x4D, 0xB8E39, 0x911 },
+	[ATHOS_B_6G_LUT_CHAN_696375_IDX] = { 27855, 0x2, 0x4D, 0xC0000, 0x911 },
+	[ATHOS_B_6G_LUT_CHAN_696500_IDX] = { 27860, 0x2, 0x4D, 0xC71C7, 0x912 },
+	[ATHOS_B_6G_LUT_CHAN_696625_IDX] = { 27865, 0x2, 0x4D, 0xCE38E, 0x912 },
+	[ATHOS_B_6G_LUT_CHAN_696750_IDX] = { 27870, 0x2, 0x4D, 0xD5555, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_696875_IDX] = { 27875, 0x2, 0x4D, 0xDC71C, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_697000_IDX] = { 27880, 0x2, 0x4D, 0xE38E4, 0x913 },
+	[ATHOS_B_6G_LUT_CHAN_697125_IDX] = { 27885, 0x2, 0x4D, 0xEAAAB, 0x914 },
+	[ATHOS_B_6G_LUT_CHAN_697250_IDX] = { 27890, 0x2, 0x4D, 0xF1C72, 0x914 },
+	[ATHOS_B_6G_LUT_CHAN_697375_IDX] = { 27895, 0x2, 0x4D, 0xF8E39, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697500_IDX] = { 27900, 0x2, 0x4D, 0x100000, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697625_IDX] = { 27905, 0x2, 0x4D, 0x1071C7, 0x915 },
+	[ATHOS_B_6G_LUT_CHAN_697750_IDX] = { 27910, 0x2, 0x4D, 0x10E38E, 0x916 },
+	[ATHOS_B_6G_LUT_CHAN_697875_IDX] = { 27915, 0x2, 0x4D, 0x115555, 0x916 },
+	[ATHOS_B_6G_LUT_CHAN_698000_IDX] = { 27920, 0x2, 0x4D, 0x11C71C, 0x917 },
+	[ATHOS_B_6G_LUT_CHAN_698125_IDX] = { 27925, 0x2, 0x4D, 0x1238E4, 0x917 },
+	[ATHOS_B_6G_LUT_CHAN_698250_IDX] = { 27930, 0x2, 0x4D, 0x12AAAB, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698375_IDX] = { 27935, 0x2, 0x4D, 0x131C72, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698500_IDX] = { 27940, 0x2, 0x4D, 0x138E39, 0x918 },
+	[ATHOS_B_6G_LUT_CHAN_698625_IDX] = { 27945, 0x2, 0x4D, 0x140000, 0x919 },
+	[ATHOS_B_6G_LUT_CHAN_698750_IDX] = { 27950, 0x2, 0x4D, 0x1471C7, 0x919 },
+	[ATHOS_B_6G_LUT_CHAN_698875_IDX] = { 27955, 0x2, 0x4D, 0x14E38E, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699000_IDX] = { 27960, 0x2, 0x4D, 0x155555, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699125_IDX] = { 27965, 0x2, 0x4D, 0x15C71C, 0x91A },
+	[ATHOS_B_6G_LUT_CHAN_699250_IDX] = { 27970, 0x2, 0x4D, 0x1638E4, 0x91B },
+	[ATHOS_B_6G_LUT_CHAN_699375_IDX] = { 27975, 0x2, 0x4D, 0x16AAAB, 0x91B },
+	[ATHOS_B_6G_LUT_CHAN_699500_IDX] = { 27980, 0x2, 0x4D, 0x171C72, 0x91C },
+	[ATHOS_B_6G_LUT_CHAN_699625_IDX] = { 27985, 0x2, 0x4D, 0x178E39, 0x91C },
+	[ATHOS_B_6G_LUT_CHAN_699750_IDX] = { 27990, 0x2, 0x4D, 0x180000, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_699875_IDX] = { 27995, 0x2, 0x4D, 0x1871C7, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_700000_IDX] = { 28000, 0x2, 0x4D, 0x18E38E, 0x91D },
+	[ATHOS_B_6G_LUT_CHAN_700125_IDX] = { 28005, 0x2, 0x4D, 0x195555, 0x91E },
+	[ATHOS_B_6G_LUT_CHAN_700250_IDX] = { 28010, 0x2, 0x4D, 0x19C71C, 0x91E },
+	[ATHOS_B_6G_LUT_CHAN_700375_IDX] = { 28015, 0x2, 0x4D, 0x1A38E4, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700500_IDX] = { 28020, 0x2, 0x4D, 0x1AAAAB, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700625_IDX] = { 28025, 0x2, 0x4D, 0x1B1C72, 0x91F },
+	[ATHOS_B_6G_LUT_CHAN_700750_IDX] = { 28030, 0x2, 0x4D, 0x1B8E39, 0x920 },
+	[ATHOS_B_6G_LUT_CHAN_700875_IDX] = { 28035, 0x2, 0x4D, 0x1C0000, 0x920 },
+	[ATHOS_B_6G_LUT_CHAN_701000_IDX] = { 28040, 0x2, 0x4D, 0x1C71C7, 0x921 },
+	[ATHOS_B_6G_LUT_CHAN_701125_IDX] = { 28045, 0x2, 0x4D, 0x1CE38E, 0x921 },
+	[ATHOS_B_6G_LUT_CHAN_701250_IDX] = { 28050, 0x2, 0x4D, 0x1D5555, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701375_IDX] = { 28055, 0x2, 0x4D, 0x1DC71C, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701500_IDX] = { 28060, 0x2, 0x4D, 0x1E38E4, 0x922 },
+	[ATHOS_B_6G_LUT_CHAN_701625_IDX] = { 28065, 0x2, 0x4D, 0x1EAAAB, 0x923 },
+	[ATHOS_B_6G_LUT_CHAN_701750_IDX] = { 28070, 0x2, 0x4D, 0x1F1C72, 0x923 },
+	[ATHOS_B_6G_LUT_CHAN_701875_IDX] = { 28075, 0x2, 0x4D, 0x1F8E39, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702000_IDX] = { 28080, 0x2, 0x4E, 0x0, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702125_IDX] = { 28085, 0x2, 0x4E, 0x71C7, 0x924 },
+	[ATHOS_B_6G_LUT_CHAN_702250_IDX] = { 28090, 0x2, 0x4E, 0xE38E, 0x925 },
+	[ATHOS_B_6G_LUT_CHAN_702375_IDX] = { 28095, 0x2, 0x4E, 0x15555, 0x925 },
+	[ATHOS_B_6G_LUT_CHAN_702500_IDX] = { 28100, 0x2, 0x4E, 0x1C71C, 0x926 },
+	[ATHOS_B_6G_LUT_CHAN_702625_IDX] = { 28105, 0x2, 0x4E, 0x238E4, 0x926 },
+	[ATHOS_B_6G_LUT_CHAN_702750_IDX] = { 28110, 0x2, 0x4E, 0x2AAAB, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_702875_IDX] = { 28115, 0x2, 0x4E, 0x31C72, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_703000_IDX] = { 28120, 0x2, 0x4E, 0x38E39, 0x927 },
+	[ATHOS_B_6G_LUT_CHAN_703125_IDX] = { 28125, 0x2, 0x4E, 0x40000, 0x928 },
+	[ATHOS_B_6G_LUT_CHAN_703250_IDX] = { 28130, 0x2, 0x4E, 0x471C7, 0x928 },
+	[ATHOS_B_6G_LUT_CHAN_703375_IDX] = { 28135, 0x2, 0x4E, 0x4E38E, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703500_IDX] = { 28140, 0x2, 0x4E, 0x55555, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703625_IDX] = { 28145, 0x2, 0x4E, 0x5C71C, 0x929 },
+	[ATHOS_B_6G_LUT_CHAN_703750_IDX] = { 28150, 0x2, 0x4E, 0x638E4, 0x92A },
+	[ATHOS_B_6G_LUT_CHAN_703875_IDX] = { 28155, 0x2, 0x4E, 0x6AAAB, 0x92A },
+	[ATHOS_B_6G_LUT_CHAN_704000_IDX] = { 28160, 0x2, 0x4E, 0x71C72, 0x92B },
+	[ATHOS_B_6G_LUT_CHAN_704125_IDX] = { 28165, 0x2, 0x4E, 0x78E39, 0x92B },
+	[ATHOS_B_6G_LUT_CHAN_704250_IDX] = { 28170, 0x2, 0x4E, 0x80000, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704375_IDX] = { 28175, 0x2, 0x4E, 0x871C7, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704500_IDX] = { 28180, 0x2, 0x4E, 0x8E38E, 0x92C },
+	[ATHOS_B_6G_LUT_CHAN_704625_IDX] = { 28185, 0x2, 0x4E, 0x95555, 0x92D },
+	[ATHOS_B_6G_LUT_CHAN_704750_IDX] = { 28190, 0x2, 0x4E, 0x9C71C, 0x92D },
+	[ATHOS_B_6G_LUT_CHAN_704875_IDX] = { 28195, 0x2, 0x4E, 0xA38E4, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705000_IDX] = { 28200, 0x2, 0x4E, 0xAAAAB, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705125_IDX] = { 28205, 0x2, 0x4E, 0xB1C72, 0x92E },
+	[ATHOS_B_6G_LUT_CHAN_705250_IDX] = { 28210, 0x2, 0x4E, 0xB8E39, 0x92F },
+	[ATHOS_B_6G_LUT_CHAN_705375_IDX] = { 28215, 0x2, 0x4E, 0xC0000, 0x92F },
+	[ATHOS_B_6G_LUT_CHAN_705500_IDX] = { 28220, 0x2, 0x4E, 0xC71C7, 0x930 },
+	[ATHOS_B_6G_LUT_CHAN_705625_IDX] = { 28225, 0x2, 0x4E, 0xCE38E, 0x930 },
+	[ATHOS_B_6G_LUT_CHAN_705750_IDX] = { 28230, 0x2, 0x4E, 0xD5555, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_705875_IDX] = { 28235, 0x2, 0x4E, 0xDC71C, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_706000_IDX] = { 28240, 0x2, 0x4E, 0xE38E4, 0x931 },
+	[ATHOS_B_6G_LUT_CHAN_706125_IDX] = { 28245, 0x2, 0x4E, 0xEAAAB, 0x932 },
+	[ATHOS_B_6G_LUT_CHAN_706250_IDX] = { 28250, 0x2, 0x4E, 0xF1C72, 0x932 },
+	[ATHOS_B_6G_LUT_CHAN_706375_IDX] = { 28255, 0x2, 0x4E, 0xF8E39, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706500_IDX] = { 28260, 0x2, 0x4E, 0x100000, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706625_IDX] = { 28265, 0x2, 0x4E, 0x1071C7, 0x933 },
+	[ATHOS_B_6G_LUT_CHAN_706750_IDX] = { 28270, 0x2, 0x4E, 0x10E38E, 0x934 },
+	[ATHOS_B_6G_LUT_CHAN_706875_IDX] = { 28275, 0x2, 0x4E, 0x115555, 0x934 },
+	[ATHOS_B_6G_LUT_CHAN_707000_IDX] = { 28280, 0x2, 0x4E, 0x11C71C, 0x935 },
+	[ATHOS_B_6G_LUT_CHAN_707125_IDX] = { 28285, 0x2, 0x4E, 0x1238E4, 0x935 },
+	[ATHOS_B_6G_LUT_CHAN_707250_IDX] = { 28290, 0x2, 0x4E, 0x12AAAB, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707375_IDX] = { 28295, 0x2, 0x4E, 0x131C72, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707500_IDX] = { 28300, 0x2, 0x4E, 0x138E39, 0x936 },
+	[ATHOS_B_6G_LUT_CHAN_707625_IDX] = { 28305, 0x2, 0x4E, 0x140000, 0x937 },
+	[ATHOS_B_6G_LUT_CHAN_707750_IDX] = { 28310, 0x2, 0x4E, 0x1471C7, 0x937 },
+	[ATHOS_B_6G_LUT_CHAN_707875_IDX] = { 28315, 0x2, 0x4E, 0x14E38E, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708000_IDX] = { 28320, 0x2, 0x4E, 0x155555, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708125_IDX] = { 28325, 0x2, 0x4E, 0x15C71C, 0x938 },
+	[ATHOS_B_6G_LUT_CHAN_708250_IDX] = { 28330, 0x2, 0x4E, 0x1638E4, 0x939 },
+	[ATHOS_B_6G_LUT_CHAN_708375_IDX] = { 28335, 0x2, 0x4E, 0x16AAAB, 0x939 },
+	[ATHOS_B_6G_LUT_CHAN_708500_IDX] = { 28340, 0x2, 0x4E, 0x171C72, 0x93A },
+	[ATHOS_B_6G_LUT_CHAN_708625_IDX] = { 28345, 0x2, 0x4E, 0x178E39, 0x93A },
+	[ATHOS_B_6G_LUT_CHAN_708750_IDX] = { 28350, 0x2, 0x4E, 0x180000, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_708875_IDX] = { 28355, 0x2, 0x4E, 0x1871C7, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_709000_IDX] = { 28360, 0x2, 0x4E, 0x18E38E, 0x93B },
+	[ATHOS_B_6G_LUT_CHAN_709125_IDX] = { 28365, 0x2, 0x4E, 0x195555, 0x93C },
+	[ATHOS_B_6G_LUT_CHAN_709250_IDX] = { 28370, 0x2, 0x4E, 0x19C71C, 0x93C },
+	[ATHOS_B_6G_LUT_CHAN_709375_IDX] = { 28375, 0x2, 0x4E, 0x1A38E4, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709500_IDX] = { 28380, 0x2, 0x4E, 0x1AAAAB, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709625_IDX] = { 28385, 0x2, 0x4E, 0x1B1C72, 0x93D },
+	[ATHOS_B_6G_LUT_CHAN_709750_IDX] = { 28390, 0x2, 0x4E, 0x1B8E39, 0x93E },
+	[ATHOS_B_6G_LUT_CHAN_709875_IDX] = { 28395, 0x2, 0x4E, 0x1C0000, 0x93E },
+	[ATHOS_B_6G_LUT_CHAN_710000_IDX] = { 28400, 0x2, 0x4E, 0x1C71C7, 0x93F },
+	[ATHOS_B_6G_LUT_CHAN_710125_IDX] = { 28405, 0x2, 0x4E, 0x1CE38E, 0x93F },
+	[ATHOS_B_6G_LUT_CHAN_710250_IDX] = { 28410, 0x2, 0x4E, 0x1D5555, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710375_IDX] = { 28415, 0x2, 0x4E, 0x1DC71C, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710500_IDX] = { 28420, 0x2, 0x4E, 0x1E38E4, 0x940 },
+	[ATHOS_B_6G_LUT_CHAN_710625_IDX] = { 28425, 0x2, 0x4E, 0x1EAAAB, 0x941 },
+	[ATHOS_B_6G_LUT_CHAN_710750_IDX] = { 28430, 0x2, 0x4E, 0x1F1C72, 0x941 },
+	[ATHOS_B_6G_LUT_CHAN_710875_IDX] = { 28435, 0x2, 0x4E, 0x1F8E39, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711000_IDX] = { 28440, 0x2, 0x4F, 0x0, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711125_IDX] = { 28445, 0x2, 0x4F, 0x71C7, 0x942 },
+	[ATHOS_B_6G_LUT_CHAN_711250_IDX] = { 28450, 0x2, 0x4F, 0xE38E, 0x943 },
+	[ATHOS_B_6G_LUT_CHAN_711375_IDX] = { 28455, 0x2, 0x4F, 0x15555, 0x943 },
+	[ATHOS_B_6G_LUT_CHAN_711500_IDX] = { 28460, 0x2, 0x4F, 0x1C71C, 0x944 },
+	[ATHOS_B_6G_LUT_CHAN_711625_IDX] = { 28465, 0x2, 0x4F, 0x238E4, 0x944 },
+	[ATHOS_B_6G_LUT_CHAN_711750_IDX] = { 28470, 0x2, 0x4F, 0x2AAAB, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_711875_IDX] = { 28475, 0x2, 0x4F, 0x31C72, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_712000_IDX] = { 28480, 0x2, 0x4F, 0x38E39, 0x945 },
+	[ATHOS_B_6G_LUT_CHAN_712125_IDX] = { 28485, 0x2, 0x4F, 0x40000, 0x946 },
+	[ATHOS_B_6G_LUT_CHAN_712250_IDX] = { 28490, 0x2, 0x4F, 0x471C7, 0x946 },
+	[ATHOS_B_6G_LUT_CHAN_712375_IDX] = { 28495, 0x2, 0x4F, 0x4E38E, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712500_IDX] = { 28500, 0x2, 0x4F, 0x55555, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712625_IDX] = { 28505, 0x2, 0x4F, 0x5C71C, 0x947 },
+	[ATHOS_B_6G_LUT_CHAN_712750_IDX] = { 28510, 0x2, 0x4F, 0x638E4, 0x948 },
+	[ATHOS_B_6G_LUT_CHAN_712875_IDX] = { 28515, 0x2, 0x4F, 0x6AAAB, 0x948 },
+	[ATHOS_B_6G_LUT_CHAN_713000_IDX] = { 28520, 0x2, 0x4F, 0x71C72, 0x949 },
+	[ATHOS_B_6G_LUT_CHAN_713125_IDX] = { 28525, 0x2, 0x4F, 0x78E39, 0x949 },
+	[ATHOS_B_6G_LUT_CHAN_713250_IDX] = { 28530, 0x2, 0x4F, 0x80000, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713375_IDX] = { 28535, 0x2, 0x4F, 0x871C7, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713500_IDX] = { 28540, 0x2, 0x4F, 0x8E38E, 0x94A },
+	[ATHOS_B_6G_LUT_CHAN_713625_IDX] = { 28545, 0x2, 0x4F, 0x95555, 0x94B },
+	[ATHOS_B_6G_LUT_CHAN_713750_IDX] = { 28550, 0x2, 0x4F, 0x9C71C, 0x94B },
+	[ATHOS_B_6G_LUT_CHAN_713875_IDX] = { 28555, 0x2, 0x4F, 0xA38E4, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714000_IDX] = { 28560, 0x2, 0x4F, 0xAAAAB, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714125_IDX] = { 28565, 0x2, 0x4F, 0xB1C72, 0x94C },
+	[ATHOS_B_6G_LUT_CHAN_714250_IDX] = { 28570, 0x2, 0x4F, 0xB8E39, 0x94D },
+	[ATHOS_B_6G_LUT_CHAN_714375_IDX] = { 28575, 0x2, 0x4F, 0xC0000, 0x94D },
+	[ATHOS_B_6G_LUT_CHAN_714500_IDX] = { 28580, 0x2, 0x4F, 0xC71C7, 0x94E },
+	[ATHOS_B_6G_LUT_CHAN_714625_IDX] = { 28585, 0x2, 0x4F, 0xCE38E, 0x94E },
+	[ATHOS_B_6G_LUT_CHAN_714750_IDX] = { 28590, 0x2, 0x4F, 0xD5555, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_714875_IDX] = { 28595, 0x2, 0x4F, 0xDC71C, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_715000_IDX] = { 28600, 0x2, 0x4F, 0xE38E4, 0x94F },
+	[ATHOS_B_6G_LUT_CHAN_715125_IDX] = { 28605, 0x2, 0x4F, 0xEAAAB, 0x950 },
+	[ATHOS_B_6G_LUT_CHAN_715250_IDX] = { 28610, 0x2, 0x4F, 0xF1C72, 0x950 },
+	[ATHOS_B_6G_LUT_CHAN_715375_IDX] = { 28615, 0x2, 0x4F, 0xF8E39, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715500_IDX] = { 28620, 0x2, 0x4F, 0x100000, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715625_IDX] = { 28625, 0x2, 0x4F, 0x1071C7, 0x951 },
+	[ATHOS_B_6G_LUT_CHAN_715750_IDX] = { 28630, 0x2, 0x4F, 0x10E38E, 0x952 },
+	[ATHOS_B_6G_LUT_CHAN_715875_IDX] = { 28635, 0x2, 0x4F, 0x115555, 0x952 },
+	[ATHOS_B_6G_LUT_CHAN_716000_IDX] = { 28640, 0x2, 0x4F, 0x11C71C, 0x953 },
+	[ATHOS_B_6G_LUT_CHAN_716125_IDX] = { 28645, 0x2, 0x4F, 0x1238E4, 0x953 },
+	[ATHOS_B_6G_LUT_CHAN_716250_IDX] = { 28650, 0x2, 0x4F, 0x12AAAB, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716375_IDX] = { 28655, 0x2, 0x4F, 0x131C72, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716500_IDX] = { 28660, 0x2, 0x4F, 0x138E39, 0x954 },
+	[ATHOS_B_6G_LUT_CHAN_716625_IDX] = { 28665, 0x2, 0x4F, 0x140000, 0x955 },
+	[ATHOS_B_6G_LUT_CHAN_716750_IDX] = { 28670, 0x2, 0x4F, 0x1471C7, 0x955 },
+	[ATHOS_B_6G_LUT_CHAN_716875_IDX] = { 28675, 0x2, 0x4F, 0x14E38E, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717000_IDX] = { 28680, 0x2, 0x4F, 0x155555, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717125_IDX] = { 28685, 0x2, 0x4F, 0x15C71C, 0x956 },
+	[ATHOS_B_6G_LUT_CHAN_717250_IDX] = { 28690, 0x2, 0x4F, 0x1638E4, 0x957 },
+	[ATHOS_B_6G_LUT_CHAN_717375_IDX] = { 28695, 0x2, 0x4F, 0x16AAAB, 0x957 },
+	[ATHOS_B_6G_LUT_CHAN_717500_IDX] = { 28700, 0x2, 0x4F, 0x171C72, 0x958 },
+	[ATHOS_B_6G_LUT_CHAN_717625_IDX] = { 28705, 0x2, 0x4F, 0x178E39, 0x958 },
+	[ATHOS_B_6G_LUT_CHAN_717750_IDX] = { 28710, 0x2, 0x4F, 0x180000, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_717875_IDX] = { 28715, 0x2, 0x4F, 0x1871C7, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_718000_IDX] = { 28720, 0x2, 0x4F, 0x18E38E, 0x959 },
+	[ATHOS_B_6G_LUT_CHAN_718125_IDX] = { 28725, 0x2, 0x4F, 0x195555, 0x95A },
+	[ATHOS_B_6G_LUT_CHAN_718250_IDX] = { 28730, 0x2, 0x4F, 0x19C71C, 0x95A },
+	[ATHOS_B_6G_LUT_CHAN_718375_IDX] = { 28735, 0x2, 0x4F, 0x1A38E4, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718500_IDX] = { 28740, 0x2, 0x4F, 0x1AAAAB, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718625_IDX] = { 28745, 0x2, 0x4F, 0x1B1C72, 0x95B },
+	[ATHOS_B_6G_LUT_CHAN_718750_IDX] = { 28750, 0x2, 0x4F, 0x1B8E39, 0x95C },
+	[ATHOS_B_6G_LUT_CHAN_718875_IDX] = { 28755, 0x2, 0x4F, 0x1C0000, 0x95C },
+	[ATHOS_B_6G_LUT_CHAN_719000_IDX] = { 28760, 0x2, 0x4F, 0x1C71C7, 0x95D },
+	[ATHOS_B_6G_LUT_CHAN_719125_IDX] = { 28765, 0x2, 0x4F, 0x1CE38E, 0x95D },
+	[ATHOS_B_6G_LUT_CHAN_719250_IDX] = { 28770, 0x2, 0x4F, 0x1D5555, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719375_IDX] = { 28775, 0x2, 0x4F, 0x1DC71C, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719500_IDX] = { 28780, 0x2, 0x4F, 0x1E38E4, 0x95E },
+	[ATHOS_B_6G_LUT_CHAN_719625_IDX] = { 28785, 0x2, 0x4F, 0x1EAAAB, 0x95F },
+	[ATHOS_B_6G_LUT_CHAN_719750_IDX] = { 28790, 0x2, 0x4F, 0x1F1C72, 0x95F },
+	[ATHOS_B_6G_LUT_CHAN_719875_IDX] = { 28795, 0x2, 0x4F, 0x1F8E39, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720000_IDX] = { 28800, 0x2, 0x50, 0x0, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720125_IDX] = { 28805, 0x2, 0x50, 0x71C7, 0x960 },
+	[ATHOS_B_6G_LUT_CHAN_720250_IDX] = { 28810, 0x2, 0x50, 0xE38E, 0x961 },
+	[ATHOS_B_6G_LUT_CHAN_720375_IDX] = { 28815, 0x2, 0x50, 0x15555, 0x961 },
+	[ATHOS_B_6G_LUT_CHAN_720500_IDX] = { 28820, 0x2, 0x50, 0x1C71C, 0x962 },
+	[ATHOS_B_6G_LUT_CHAN_720625_IDX] = { 28825, 0x2, 0x50, 0x238E4, 0x962 },
+	[ATHOS_B_6G_LUT_CHAN_720750_IDX] = { 28830, 0x2, 0x50, 0x2AAAB, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_720875_IDX] = { 28835, 0x2, 0x50, 0x31C72, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_721000_IDX] = { 28840, 0x2, 0x50, 0x38E39, 0x963 },
+	[ATHOS_B_6G_LUT_CHAN_721125_IDX] = { 28845, 0x2, 0x50, 0x40000, 0x964 },
+	[ATHOS_B_6G_LUT_CHAN_721250_IDX] = { 28850, 0x2, 0x50, 0x471C7, 0x964 },
+	[ATHOS_B_6G_LUT_CHAN_721375_IDX] = { 28855, 0x2, 0x50, 0x4E38E, 0x965 },
+	[ATHOS_B_6G_LUT_CHAN_721500_IDX] = { 28860, 0x2, 0x50, 0x55555, 0x965 }
+};
+
+const struct common_lut_line athos_b_lut_5g_60_mhz[ATHOS_B_5G_LUT_CHAN_5G_MAX] = {
+	[ATHOS_B_5G_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x39, 0x11C71C, 0x6BF },
+	[ATHOS_B_5G_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x39, 0xB1C72, 0x6B8 },
+	[ATHOS_B_5G_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x39, 0xB8E39, 0x6B9 },
+	[ATHOS_B_5G_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x39, 0xC0000, 0x6B9 },
+	[ATHOS_B_5G_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x39, 0xC71C7, 0x6BA },
+	[ATHOS_B_5G_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x39, 0xCE38E, 0x6BA },
+	[ATHOS_B_5G_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x39, 0xD5555, 0x6BB },
+	[ATHOS_B_5G_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x39, 0xDC71C, 0x6BB },
+	[ATHOS_B_5G_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x39, 0xE38E4, 0x6BB },
+	[ATHOS_B_5G_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x39, 0xEAAAB, 0x6BC },
+	[ATHOS_B_5G_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x39, 0xF1C72, 0x6BC },
+	[ATHOS_B_5G_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x39, 0xF8E39, 0x6BD },
+	[ATHOS_B_5G_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x39, 0x100000, 0x6BD },
+	[ATHOS_B_5G_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x39, 0x1071C7, 0x6BD },
+	[ATHOS_B_5G_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x39, 0x10E38E, 0x6BE },
+	[ATHOS_B_5G_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x39, 0x115555, 0x6BE },
+	[ATHOS_B_5G_LUT_CHAN_518000_IDX] = { 20720, 0x0, 0x39, 0x11C71C, 0x6BF },
+	[ATHOS_B_5G_LUT_CHAN_518125_IDX] = { 20725, 0x0, 0x39, 0x1238E4, 0x6BF },
+	[ATHOS_B_5G_LUT_CHAN_518250_IDX] = { 20730, 0x0, 0x39, 0x12AAAB, 0x6C0 },
+	[ATHOS_B_5G_LUT_CHAN_518375_IDX] = { 20735, 0x0, 0x39, 0x131C72, 0x6C0 },
+	[ATHOS_B_5G_LUT_CHAN_518500_IDX] = { 20740, 0x0, 0x39, 0x138E39, 0x6C0 },
+	[ATHOS_B_5G_LUT_CHAN_518625_IDX] = { 20745, 0x0, 0x39, 0x140000, 0x6C1 },
+	[ATHOS_B_5G_LUT_CHAN_518750_IDX] = { 20750, 0x0, 0x39, 0x1471C7, 0x6C1 },
+	[ATHOS_B_5G_LUT_CHAN_518875_IDX] = { 20755, 0x0, 0x39, 0x14E38E, 0x6C2 },
+	[ATHOS_B_5G_LUT_CHAN_519000_IDX] = { 20760, 0x0, 0x39, 0x155555, 0x6C2 },
+	[ATHOS_B_5G_LUT_CHAN_519125_IDX] = { 20765, 0x0, 0x39, 0x15C71C, 0x6C2 },
+	[ATHOS_B_5G_LUT_CHAN_519250_IDX] = { 20770, 0x0, 0x39, 0x1638E4, 0x6C3 },
+	[ATHOS_B_5G_LUT_CHAN_519375_IDX] = { 20775, 0x0, 0x39, 0x16AAAB, 0x6C3 },
+	[ATHOS_B_5G_LUT_CHAN_519500_IDX] = { 20780, 0x0, 0x39, 0x171C72, 0x6C4 },
+	[ATHOS_B_5G_LUT_CHAN_519625_IDX] = { 20785, 0x0, 0x39, 0x178E39, 0x6C4 },
+	[ATHOS_B_5G_LUT_CHAN_519750_IDX] = { 20790, 0x0, 0x39, 0x180000, 0x6C5 },
+	[ATHOS_B_5G_LUT_CHAN_519875_IDX] = { 20795, 0x0, 0x39, 0x1871C7, 0x6C5 },
+	[ATHOS_B_5G_LUT_CHAN_520000_IDX] = { 20800, 0x0, 0x39, 0x18E38E, 0x6C5 },
+	[ATHOS_B_5G_LUT_CHAN_520125_IDX] = { 20805, 0x0, 0x39, 0x195555, 0x6C6 },
+	[ATHOS_B_5G_LUT_CHAN_520250_IDX] = { 20810, 0x0, 0x39, 0x19C71C, 0x6C6 },
+	[ATHOS_B_5G_LUT_CHAN_520375_IDX] = { 20815, 0x0, 0x39, 0x1A38E4, 0x6C7 },
+	[ATHOS_B_5G_LUT_CHAN_520500_IDX] = { 20820, 0x0, 0x39, 0x1AAAAB, 0x6C7 },
+	[ATHOS_B_5G_LUT_CHAN_520625_IDX] = { 20825, 0x0, 0x39, 0x1B1C72, 0x6C7 },
+	[ATHOS_B_5G_LUT_CHAN_520750_IDX] = { 20830, 0x0, 0x39, 0x1B8E39, 0x6C8 },
+	[ATHOS_B_5G_LUT_CHAN_520875_IDX] = { 20835, 0x0, 0x39, 0x1C0000, 0x6C8 },
+	[ATHOS_B_5G_LUT_CHAN_521000_IDX] = { 20840, 0x0, 0x39, 0x1C71C7, 0x6C9 },
+	[ATHOS_B_5G_LUT_CHAN_521125_IDX] = { 20845, 0x0, 0x39, 0x1CE38E, 0x6C9 },
+	[ATHOS_B_5G_LUT_CHAN_521250_IDX] = { 20850, 0x0, 0x39, 0x1D5555, 0x6CA },
+	[ATHOS_B_5G_LUT_CHAN_521375_IDX] = { 20855, 0x0, 0x39, 0x1DC71C, 0x6CA },
+	[ATHOS_B_5G_LUT_CHAN_521500_IDX] = { 20860, 0x0, 0x39, 0x1E38E4, 0x6CA },
+	[ATHOS_B_5G_LUT_CHAN_521625_IDX] = { 20865, 0x0, 0x39, 0x1EAAAB, 0x6CB },
+	[ATHOS_B_5G_LUT_CHAN_521750_IDX] = { 20870, 0x0, 0x39, 0x1F1C72, 0x6CB },
+	[ATHOS_B_5G_LUT_CHAN_521875_IDX] = { 20875, 0x0, 0x39, 0x1F8E39, 0x6CC },
+	[ATHOS_B_5G_LUT_CHAN_522000_IDX] = { 20880, 0x0, 0x3A, 0x0, 0x6CC },
+	[ATHOS_B_5G_LUT_CHAN_522125_IDX] = { 20885, 0x0, 0x3A, 0x71C7, 0x6CC },
+	[ATHOS_B_5G_LUT_CHAN_522250_IDX] = { 20890, 0x0, 0x3A, 0xE38E, 0x6CD },
+	[ATHOS_B_5G_LUT_CHAN_522375_IDX] = { 20895, 0x0, 0x3A, 0x15555, 0x6CD },
+	[ATHOS_B_5G_LUT_CHAN_522500_IDX] = { 20900, 0x0, 0x3A, 0x1C71C, 0x6CE },
+	[ATHOS_B_5G_LUT_CHAN_522625_IDX] = { 20905, 0x0, 0x3A, 0x238E4, 0x6CE },
+	[ATHOS_B_5G_LUT_CHAN_522750_IDX] = { 20910, 0x0, 0x3A, 0x2AAAB, 0x6CF },
+	[ATHOS_B_5G_LUT_CHAN_522875_IDX] = { 20915, 0x0, 0x3A, 0x31C72, 0x6CF },
+	[ATHOS_B_5G_LUT_CHAN_523000_IDX] = { 20920, 0x0, 0x3A, 0x38E39, 0x6CF },
+	[ATHOS_B_5G_LUT_CHAN_523125_IDX] = { 20925, 0x0, 0x3A, 0x40000, 0x6D0 },
+	[ATHOS_B_5G_LUT_CHAN_523250_IDX] = { 20930, 0x0, 0x3A, 0x471C7, 0x6D0 },
+	[ATHOS_B_5G_LUT_CHAN_523375_IDX] = { 20935, 0x0, 0x3A, 0x4E38E, 0x6D1 },
+	[ATHOS_B_5G_LUT_CHAN_523500_IDX] = { 20940, 0x0, 0x3A, 0x55555, 0x6D1 },
+	[ATHOS_B_5G_LUT_CHAN_523625_IDX] = { 20945, 0x0, 0x3A, 0x5C71C, 0x6D1 },
+	[ATHOS_B_5G_LUT_CHAN_523750_IDX] = { 20950, 0x0, 0x3A, 0x638E4, 0x6D2 },
+	[ATHOS_B_5G_LUT_CHAN_523875_IDX] = { 20955, 0x0, 0x3A, 0x6AAAB, 0x6D2 },
+	[ATHOS_B_5G_LUT_CHAN_524000_IDX] = { 20960, 0x0, 0x3A, 0x71C72, 0x6D3 },
+	[ATHOS_B_5G_LUT_CHAN_524125_IDX] = { 20965, 0x0, 0x3A, 0x78E39, 0x6D3 },
+	[ATHOS_B_5G_LUT_CHAN_524250_IDX] = { 20970, 0x0, 0x3A, 0x80000, 0x6D4 },
+	[ATHOS_B_5G_LUT_CHAN_524375_IDX] = { 20975, 0x0, 0x3A, 0x871C7, 0x6D4 },
+	[ATHOS_B_5G_LUT_CHAN_524500_IDX] = { 20980, 0x0, 0x3A, 0x8E38E, 0x6D4 },
+	[ATHOS_B_5G_LUT_CHAN_524625_IDX] = { 20985, 0x0, 0x3A, 0x95555, 0x6D5 },
+	[ATHOS_B_5G_LUT_CHAN_524750_IDX] = { 20990, 0x0, 0x3A, 0x9C71C, 0x6D5 },
+	[ATHOS_B_5G_LUT_CHAN_524875_IDX] = { 20995, 0x0, 0x3A, 0xA38E4, 0x6D6 },
+	[ATHOS_B_5G_LUT_CHAN_525000_IDX] = { 21000, 0x0, 0x3A, 0xAAAAB, 0x6D6 },
+	[ATHOS_B_5G_LUT_CHAN_525125_IDX] = { 21005, 0x0, 0x3A, 0xB1C72, 0x6D6 },
+	[ATHOS_B_5G_LUT_CHAN_525250_IDX] = { 21010, 0x0, 0x3A, 0xB8E39, 0x6D7 },
+	[ATHOS_B_5G_LUT_CHAN_525375_IDX] = { 21015, 0x0, 0x3A, 0xC0000, 0x6D7 },
+	[ATHOS_B_5G_LUT_CHAN_525500_IDX] = { 21020, 0x0, 0x3A, 0xC71C7, 0x6D8 },
+	[ATHOS_B_5G_LUT_CHAN_525625_IDX] = { 21025, 0x0, 0x3A, 0xCE38E, 0x6D8 },
+	[ATHOS_B_5G_LUT_CHAN_525750_IDX] = { 21030, 0x0, 0x3A, 0xD5555, 0x6D9 },
+	[ATHOS_B_5G_LUT_CHAN_525875_IDX] = { 21035, 0x0, 0x3A, 0xDC71C, 0x6D9 },
+	[ATHOS_B_5G_LUT_CHAN_526000_IDX] = { 21040, 0x0, 0x3A, 0xE38E4, 0x6D9 },
+	[ATHOS_B_5G_LUT_CHAN_526125_IDX] = { 21045, 0x0, 0x3A, 0xEAAAB, 0x6DA },
+	[ATHOS_B_5G_LUT_CHAN_526250_IDX] = { 21050, 0x0, 0x3A, 0xF1C72, 0x6DA },
+	[ATHOS_B_5G_LUT_CHAN_526375_IDX] = { 21055, 0x0, 0x3A, 0xF8E39, 0x6DB },
+	[ATHOS_B_5G_LUT_CHAN_526500_IDX] = { 21060, 0x0, 0x3A, 0x100000, 0x6DB },
+	[ATHOS_B_5G_LUT_CHAN_526625_IDX] = { 21065, 0x0, 0x3A, 0x1071C7, 0x6DB },
+	[ATHOS_B_5G_LUT_CHAN_526750_IDX] = { 21070, 0x0, 0x3A, 0x10E38E, 0x6DC },
+	[ATHOS_B_5G_LUT_CHAN_526875_IDX] = { 21075, 0x0, 0x3A, 0x115555, 0x6DC },
+	[ATHOS_B_5G_LUT_CHAN_527000_IDX] = { 21080, 0x0, 0x3A, 0x11C71C, 0x6DD },
+	[ATHOS_B_5G_LUT_CHAN_527125_IDX] = { 21085, 0x0, 0x3A, 0x1238E4, 0x6DD },
+	[ATHOS_B_5G_LUT_CHAN_527250_IDX] = { 21090, 0x0, 0x3A, 0x12AAAB, 0x6DE },
+	[ATHOS_B_5G_LUT_CHAN_527375_IDX] = { 21095, 0x0, 0x3A, 0x131C72, 0x6DE },
+	[ATHOS_B_5G_LUT_CHAN_527500_IDX] = { 21100, 0x0, 0x3A, 0x138E39, 0x6DE },
+	[ATHOS_B_5G_LUT_CHAN_527625_IDX] = { 21105, 0x0, 0x3A, 0x140000, 0x6DF },
+	[ATHOS_B_5G_LUT_CHAN_527750_IDX] = { 21110, 0x0, 0x3A, 0x1471C7, 0x6DF },
+	[ATHOS_B_5G_LUT_CHAN_527875_IDX] = { 21115, 0x0, 0x3A, 0x14E38E, 0x6E0 },
+	[ATHOS_B_5G_LUT_CHAN_528000_IDX] = { 21120, 0x0, 0x3A, 0x155555, 0x6E0 },
+	[ATHOS_B_5G_LUT_CHAN_528125_IDX] = { 21125, 0x0, 0x3A, 0x15C71C, 0x6E0 },
+	[ATHOS_B_5G_LUT_CHAN_528250_IDX] = { 21130, 0x0, 0x3A, 0x1638E4, 0x6E1 },
+	[ATHOS_B_5G_LUT_CHAN_528375_IDX] = { 21135, 0x0, 0x3A, 0x16AAAB, 0x6E1 },
+	[ATHOS_B_5G_LUT_CHAN_528500_IDX] = { 21140, 0x0, 0x3A, 0x171C72, 0x6E2 },
+	[ATHOS_B_5G_LUT_CHAN_528625_IDX] = { 21145, 0x0, 0x3A, 0x178E39, 0x6E2 },
+	[ATHOS_B_5G_LUT_CHAN_528750_IDX] = { 21150, 0x0, 0x3A, 0x180000, 0x6E3 },
+	[ATHOS_B_5G_LUT_CHAN_528875_IDX] = { 21155, 0x0, 0x3A, 0x1871C7, 0x6E3 },
+	[ATHOS_B_5G_LUT_CHAN_529000_IDX] = { 21160, 0x0, 0x3A, 0x18E38E, 0x6E3 },
+	[ATHOS_B_5G_LUT_CHAN_529125_IDX] = { 21165, 0x0, 0x3A, 0x195555, 0x6E4 },
+	[ATHOS_B_5G_LUT_CHAN_529250_IDX] = { 21170, 0x0, 0x3A, 0x19C71C, 0x6E4 },
+	[ATHOS_B_5G_LUT_CHAN_529375_IDX] = { 21175, 0x0, 0x3A, 0x1A38E4, 0x6E5 },
+	[ATHOS_B_5G_LUT_CHAN_529500_IDX] = { 21180, 0x0, 0x3A, 0x1AAAAB, 0x6E5 },
+	[ATHOS_B_5G_LUT_CHAN_529625_IDX] = { 21185, 0x0, 0x3A, 0x1B1C72, 0x6E5 },
+	[ATHOS_B_5G_LUT_CHAN_529750_IDX] = { 21190, 0x0, 0x3A, 0x1B8E39, 0x6E6 },
+	[ATHOS_B_5G_LUT_CHAN_529875_IDX] = { 21195, 0x0, 0x3A, 0x1C0000, 0x6E6 },
+	[ATHOS_B_5G_LUT_CHAN_530000_IDX] = { 21200, 0x0, 0x3A, 0x1C71C7, 0x6E7 },
+	[ATHOS_B_5G_LUT_CHAN_530125_IDX] = { 21205, 0x0, 0x3A, 0x1CE38E, 0x6E7 },
+	[ATHOS_B_5G_LUT_CHAN_530250_IDX] = { 21210, 0x0, 0x3A, 0x1D5555, 0x6E8 },
+	[ATHOS_B_5G_LUT_CHAN_530375_IDX] = { 21215, 0x0, 0x3A, 0x1DC71C, 0x6E8 },
+	[ATHOS_B_5G_LUT_CHAN_530500_IDX] = { 21220, 0x0, 0x3A, 0x1E38E4, 0x6E8 },
+	[ATHOS_B_5G_LUT_CHAN_530625_IDX] = { 21225, 0x0, 0x3A, 0x1EAAAB, 0x6E9 },
+	[ATHOS_B_5G_LUT_CHAN_530750_IDX] = { 21230, 0x0, 0x3A, 0x1F1C72, 0x6E9 },
+	[ATHOS_B_5G_LUT_CHAN_530875_IDX] = { 21235, 0x0, 0x3A, 0x1F8E39, 0x6EA },
+	[ATHOS_B_5G_LUT_CHAN_531000_IDX] = { 21240, 0x0, 0x3B, 0x0, 0x6EA },
+	[ATHOS_B_5G_LUT_CHAN_531125_IDX] = { 21245, 0x0, 0x3B, 0x71C7, 0x6EA },
+	[ATHOS_B_5G_LUT_CHAN_531250_IDX] = { 21250, 0x0, 0x3B, 0xE38E, 0x6EB },
+	[ATHOS_B_5G_LUT_CHAN_531375_IDX] = { 21255, 0x0, 0x3B, 0x15555, 0x6EB },
+	[ATHOS_B_5G_LUT_CHAN_531500_IDX] = { 21260, 0x0, 0x3B, 0x1C71C, 0x6EC },
+	[ATHOS_B_5G_LUT_CHAN_531625_IDX] = { 21265, 0x0, 0x3B, 0x238E4, 0x6EC },
+	[ATHOS_B_5G_LUT_CHAN_531750_IDX] = { 21270, 0x0, 0x3B, 0x2AAAB, 0x6ED },
+	[ATHOS_B_5G_LUT_CHAN_531875_IDX] = { 21275, 0x0, 0x3B, 0x31C72, 0x6ED },
+	[ATHOS_B_5G_LUT_CHAN_532000_IDX] = { 21280, 0x0, 0x3B, 0x38E39, 0x6ED },
+	[ATHOS_B_5G_LUT_CHAN_532125_IDX] = { 21285, 0x0, 0x3B, 0x40000, 0x6EE },
+	[ATHOS_B_5G_LUT_CHAN_532250_IDX] = { 21290, 0x0, 0x3B, 0x471C7, 0x6EE },
+	[ATHOS_B_5G_LUT_CHAN_532375_IDX] = { 21295, 0x0, 0x3B, 0x4E38E, 0x6EF },
+	[ATHOS_B_5G_LUT_CHAN_532500_IDX] = { 21300, 0x0, 0x3B, 0x55555, 0x6EF },
+	[ATHOS_B_5G_LUT_CHAN_532625_IDX] = { 21305, 0x0, 0x3B, 0x5C71C, 0x6EF },
+	[ATHOS_B_5G_LUT_CHAN_532750_IDX] = { 21310, 0x0, 0x3B, 0x638E4, 0x6F0 },
+	[ATHOS_B_5G_LUT_CHAN_532875_IDX] = { 21315, 0x0, 0x3B, 0x6AAAB, 0x6F0 },
+	[ATHOS_B_5G_LUT_CHAN_533000_IDX] = { 21320, 0x0, 0x3B, 0x71C72, 0x6F1 },
+	[ATHOS_B_5G_LUT_CHAN_533125_IDX] = { 21325, 0x0, 0x3B, 0x78E39, 0x6F1 },
+	[ATHOS_B_5G_LUT_CHAN_533250_IDX] = { 21330, 0x0, 0x3B, 0x80000, 0x6F2 },
+	[ATHOS_B_5G_LUT_CHAN_533375_IDX] = { 21335, 0x0, 0x3B, 0x871C7, 0x6F2 },
+	[ATHOS_B_5G_LUT_CHAN_533500_IDX] = { 21340, 0x0, 0x3B, 0x8E38E, 0x6F2 },
+	[ATHOS_B_5G_LUT_CHAN_533625_IDX] = { 21345, 0x0, 0x3B, 0x95555, 0x6F3 },
+	[ATHOS_B_5G_LUT_CHAN_533750_IDX] = { 21350, 0x0, 0x3B, 0x9C71C, 0x6F3 },
+	[ATHOS_B_5G_LUT_CHAN_533875_IDX] = { 21355, 0x0, 0x3B, 0xA38E4, 0x6F4 },
+	[ATHOS_B_5G_LUT_CHAN_534000_IDX] = { 21360, 0x0, 0x3B, 0xAAAAB, 0x6F4 },
+	[ATHOS_B_5G_LUT_CHAN_534125_IDX] = { 21365, 0x0, 0x3B, 0xB1C72, 0x6F4 },
+	[ATHOS_B_5G_LUT_CHAN_534250_IDX] = { 21370, 0x0, 0x3B, 0xB8E39, 0x6F5 },
+	[ATHOS_B_5G_LUT_CHAN_534375_IDX] = { 21375, 0x0, 0x3B, 0xC0000, 0x6F5 },
+	[ATHOS_B_5G_LUT_CHAN_534500_IDX] = { 21380, 0x0, 0x3B, 0xC71C7, 0x6F6 },
+	[ATHOS_B_5G_LUT_CHAN_534625_IDX] = { 21385, 0x0, 0x3B, 0xCE38E, 0x6F6 },
+	[ATHOS_B_5G_LUT_CHAN_534750_IDX] = { 21390, 0x0, 0x3B, 0xD5555, 0x6F7 },
+	[ATHOS_B_5G_LUT_CHAN_534875_IDX] = { 21395, 0x0, 0x3B, 0xDC71C, 0x6F7 },
+	[ATHOS_B_5G_LUT_CHAN_535000_IDX] = { 21400, 0x0, 0x3B, 0xE38E4, 0x6F7 },
+	[ATHOS_B_5G_LUT_CHAN_535125_IDX] = { 21405, 0x0, 0x3B, 0xEAAAB, 0x6F8 },
+	[ATHOS_B_5G_LUT_CHAN_535250_IDX] = { 21410, 0x0, 0x3B, 0xF1C72, 0x6F8 },
+	[ATHOS_B_5G_LUT_CHAN_535375_IDX] = { 21415, 0x0, 0x3B, 0xF8E39, 0x6F9 },
+	[ATHOS_B_5G_LUT_CHAN_535500_IDX] = { 21420, 0x0, 0x3B, 0x100000, 0x6F9 },
+	[ATHOS_B_5G_LUT_CHAN_535625_IDX] = { 21425, 0x0, 0x3B, 0x1071C7, 0x6F9 },
+	[ATHOS_B_5G_LUT_CHAN_535750_IDX] = { 21430, 0x0, 0x3B, 0x10E38E, 0x6FA },
+	[ATHOS_B_5G_LUT_CHAN_535875_IDX] = { 21435, 0x0, 0x3B, 0x115555, 0x6FA },
+	[ATHOS_B_5G_LUT_CHAN_536000_IDX] = { 21440, 0x0, 0x3B, 0x11C71C, 0x6FB },
+	[ATHOS_B_5G_LUT_CHAN_536125_IDX] = { 21445, 0x0, 0x3B, 0x1238E4, 0x6FB },
+	[ATHOS_B_5G_LUT_CHAN_536250_IDX] = { 21450, 0x0, 0x3B, 0x12AAAB, 0x6FC },
+	[ATHOS_B_5G_LUT_CHAN_536375_IDX] = { 21455, 0x0, 0x3B, 0x131C72, 0x6FC },
+	[ATHOS_B_5G_LUT_CHAN_536500_IDX] = { 21460, 0x0, 0x3B, 0x138E39, 0x6FC },
+	[ATHOS_B_5G_LUT_CHAN_536625_IDX] = { 21465, 0x0, 0x3B, 0x140000, 0x6FD },
+	[ATHOS_B_5G_LUT_CHAN_536750_IDX] = { 21470, 0x0, 0x3B, 0x1471C7, 0x6FD },
+	[ATHOS_B_5G_LUT_CHAN_536875_IDX] = { 21475, 0x0, 0x3B, 0x14E38E, 0x6FE },
+	[ATHOS_B_5G_LUT_CHAN_537000_IDX] = { 21480, 0x0, 0x3B, 0x155555, 0x6FE },
+	[ATHOS_B_5G_LUT_CHAN_537125_IDX] = { 21485, 0x0, 0x3B, 0x15C71C, 0x6FE },
+	[ATHOS_B_5G_LUT_CHAN_537250_IDX] = { 21490, 0x0, 0x3B, 0x1638E4, 0x6FF },
+	[ATHOS_B_5G_LUT_CHAN_537375_IDX] = { 21495, 0x0, 0x3B, 0x16AAAB, 0x6FF },
+	[ATHOS_B_5G_LUT_CHAN_537500_IDX] = { 21500, 0x0, 0x3B, 0x171C72, 0x700 },
+	[ATHOS_B_5G_LUT_CHAN_537625_IDX] = { 21505, 0x0, 0x3B, 0x178E39, 0x700 },
+	[ATHOS_B_5G_LUT_CHAN_537750_IDX] = { 21510, 0x0, 0x3B, 0x180000, 0x701 },
+	[ATHOS_B_5G_LUT_CHAN_537875_IDX] = { 21515, 0x0, 0x3B, 0x1871C7, 0x701 },
+	[ATHOS_B_5G_LUT_CHAN_538000_IDX] = { 21520, 0x0, 0x3B, 0x18E38E, 0x701 },
+	[ATHOS_B_5G_LUT_CHAN_538125_IDX] = { 21525, 0x0, 0x3B, 0x195555, 0x702 },
+	[ATHOS_B_5G_LUT_CHAN_538250_IDX] = { 21530, 0x0, 0x3B, 0x19C71C, 0x702 },
+	[ATHOS_B_5G_LUT_CHAN_538375_IDX] = { 21535, 0x0, 0x3B, 0x1A38E4, 0x703 },
+	[ATHOS_B_5G_LUT_CHAN_538500_IDX] = { 21540, 0x0, 0x3B, 0x1AAAAB, 0x703 },
+	[ATHOS_B_5G_LUT_CHAN_538625_IDX] = { 21545, 0x0, 0x3B, 0x1B1C72, 0x703 },
+	[ATHOS_B_5G_LUT_CHAN_538750_IDX] = { 21550, 0x0, 0x3B, 0x1B8E39, 0x704 },
+	[ATHOS_B_5G_LUT_CHAN_538875_IDX] = { 21555, 0x0, 0x3B, 0x1C0000, 0x704 },
+	[ATHOS_B_5G_LUT_CHAN_539000_IDX] = { 21560, 0x0, 0x3B, 0x1C71C7, 0x705 },
+	[ATHOS_B_5G_LUT_CHAN_539125_IDX] = { 21565, 0x0, 0x3B, 0x1CE38E, 0x705 },
+	[ATHOS_B_5G_LUT_CHAN_539250_IDX] = { 21570, 0x0, 0x3B, 0x1D5555, 0x706 },
+	[ATHOS_B_5G_LUT_CHAN_539375_IDX] = { 21575, 0x0, 0x3B, 0x1DC71C, 0x706 },
+	[ATHOS_B_5G_LUT_CHAN_539500_IDX] = { 21580, 0x0, 0x3B, 0x1E38E4, 0x706 },
+	[ATHOS_B_5G_LUT_CHAN_539625_IDX] = { 21585, 0x0, 0x3B, 0x1EAAAB, 0x707 },
+	[ATHOS_B_5G_LUT_CHAN_539750_IDX] = { 21590, 0x0, 0x3B, 0x1F1C72, 0x707 },
+	[ATHOS_B_5G_LUT_CHAN_539875_IDX] = { 21595, 0x0, 0x3B, 0x1F8E39, 0x708 },
+	[ATHOS_B_5G_LUT_CHAN_540000_IDX] = { 21600, 0x0, 0x3C, 0x0, 0x708 },
+	[ATHOS_B_5G_LUT_CHAN_540125_IDX] = { 21605, 0x0, 0x3C, 0x71C7, 0x708 },
+	[ATHOS_B_5G_LUT_CHAN_540250_IDX] = { 21610, 0x0, 0x3C, 0xE38E, 0x709 },
+	[ATHOS_B_5G_LUT_CHAN_540375_IDX] = { 21615, 0x0, 0x3C, 0x15555, 0x709 },
+	[ATHOS_B_5G_LUT_CHAN_540500_IDX] = { 21620, 0x0, 0x3C, 0x1C71C, 0x70A },
+	[ATHOS_B_5G_LUT_CHAN_540625_IDX] = { 21625, 0x0, 0x3C, 0x238E4, 0x70A },
+	[ATHOS_B_5G_LUT_CHAN_540750_IDX] = { 21630, 0x0, 0x3C, 0x2AAAB, 0x70B },
+	[ATHOS_B_5G_LUT_CHAN_540875_IDX] = { 21635, 0x0, 0x3C, 0x31C72, 0x70B },
+	[ATHOS_B_5G_LUT_CHAN_541000_IDX] = { 21640, 0x0, 0x3C, 0x38E39, 0x70B },
+	[ATHOS_B_5G_LUT_CHAN_541125_IDX] = { 21645, 0x0, 0x3C, 0x40000, 0x70C },
+	[ATHOS_B_5G_LUT_CHAN_541250_IDX] = { 21650, 0x0, 0x3C, 0x471C7, 0x70C },
+	[ATHOS_B_5G_LUT_CHAN_541375_IDX] = { 21655, 0x0, 0x3C, 0x4E38E, 0x70D },
+	[ATHOS_B_5G_LUT_CHAN_541500_IDX] = { 21660, 0x0, 0x3C, 0x55555, 0x70D },
+	[ATHOS_B_5G_LUT_CHAN_541625_IDX] = { 21665, 0x0, 0x3C, 0x5C71C, 0x70D },
+	[ATHOS_B_5G_LUT_CHAN_541750_IDX] = { 21670, 0x0, 0x3C, 0x638E4, 0x70E },
+	[ATHOS_B_5G_LUT_CHAN_541875_IDX] = { 21675, 0x0, 0x3C, 0x6AAAB, 0x70E },
+	[ATHOS_B_5G_LUT_CHAN_542000_IDX] = { 21680, 0x0, 0x3C, 0x71C72, 0x70F },
+	[ATHOS_B_5G_LUT_CHAN_542125_IDX] = { 21685, 0x0, 0x3C, 0x78E39, 0x70F },
+	[ATHOS_B_5G_LUT_CHAN_542250_IDX] = { 21690, 0x0, 0x3C, 0x80000, 0x710 },
+	[ATHOS_B_5G_LUT_CHAN_542375_IDX] = { 21695, 0x0, 0x3C, 0x871C7, 0x710 },
+	[ATHOS_B_5G_LUT_CHAN_542500_IDX] = { 21700, 0x0, 0x3C, 0x8E38E, 0x710 },
+	[ATHOS_B_5G_LUT_CHAN_542625_IDX] = { 21705, 0x0, 0x3C, 0x95555, 0x711 },
+	[ATHOS_B_5G_LUT_CHAN_542750_IDX] = { 21710, 0x0, 0x3C, 0x9C71C, 0x711 },
+	[ATHOS_B_5G_LUT_CHAN_542875_IDX] = { 21715, 0x0, 0x3C, 0xA38E4, 0x712 },
+	[ATHOS_B_5G_LUT_CHAN_543000_IDX] = { 21720, 0x0, 0x3C, 0xAAAAB, 0x712 },
+	[ATHOS_B_5G_LUT_CHAN_543125_IDX] = { 21725, 0x0, 0x3C, 0xB1C72, 0x712 },
+	[ATHOS_B_5G_LUT_CHAN_543250_IDX] = { 21730, 0x0, 0x3C, 0xB8E39, 0x713 },
+	[ATHOS_B_5G_LUT_CHAN_543375_IDX] = { 21735, 0x0, 0x3C, 0xC0000, 0x713 },
+	[ATHOS_B_5G_LUT_CHAN_543500_IDX] = { 21740, 0x0, 0x3C, 0xC71C7, 0x714 },
+	[ATHOS_B_5G_LUT_CHAN_543625_IDX] = { 21745, 0x0, 0x3C, 0xCE38E, 0x714 },
+	[ATHOS_B_5G_LUT_CHAN_543750_IDX] = { 21750, 0x0, 0x3C, 0xD5555, 0x715 },
+	[ATHOS_B_5G_LUT_CHAN_543875_IDX] = { 21755, 0x0, 0x3C, 0xDC71C, 0x715 },
+	[ATHOS_B_5G_LUT_CHAN_544000_IDX] = { 21760, 0x0, 0x3C, 0xE38E4, 0x715 },
+	[ATHOS_B_5G_LUT_CHAN_544125_IDX] = { 21765, 0x0, 0x3C, 0xEAAAB, 0x716 },
+	[ATHOS_B_5G_LUT_CHAN_544250_IDX] = { 21770, 0x0, 0x3C, 0xF1C72, 0x716 },
+	[ATHOS_B_5G_LUT_CHAN_544375_IDX] = { 21775, 0x0, 0x3C, 0xF8E39, 0x717 },
+	[ATHOS_B_5G_LUT_CHAN_544500_IDX] = { 21780, 0x0, 0x3C, 0x100000, 0x717 },
+	[ATHOS_B_5G_LUT_CHAN_544625_IDX] = { 21785, 0x0, 0x3C, 0x1071C7, 0x717 },
+	[ATHOS_B_5G_LUT_CHAN_544750_IDX] = { 21790, 0x0, 0x3C, 0x10E38E, 0x718 },
+	[ATHOS_B_5G_LUT_CHAN_544875_IDX] = { 21795, 0x0, 0x3C, 0x115555, 0x718 },
+	[ATHOS_B_5G_LUT_CHAN_545000_IDX] = { 21800, 0x0, 0x3C, 0x11C71C, 0x719 },
+	[ATHOS_B_5G_LUT_CHAN_545125_IDX] = { 21805, 0x0, 0x3C, 0x1238E4, 0x719 },
+	[ATHOS_B_5G_LUT_CHAN_545250_IDX] = { 21810, 0x0, 0x3C, 0x12AAAB, 0x71A },
+	[ATHOS_B_5G_LUT_CHAN_545375_IDX] = { 21815, 0x0, 0x3C, 0x131C72, 0x71A },
+	[ATHOS_B_5G_LUT_CHAN_545500_IDX] = { 21820, 0x0, 0x3C, 0x138E39, 0x71A },
+	[ATHOS_B_5G_LUT_CHAN_545625_IDX] = { 21825, 0x0, 0x3C, 0x140000, 0x71B },
+	[ATHOS_B_5G_LUT_CHAN_545750_IDX] = { 21830, 0x0, 0x3C, 0x1471C7, 0x71B },
+	[ATHOS_B_5G_LUT_CHAN_545875_IDX] = { 21835, 0x0, 0x3C, 0x14E38E, 0x71C },
+	[ATHOS_B_5G_LUT_CHAN_546000_IDX] = { 21840, 0x0, 0x3C, 0x155555, 0x71C },
+	[ATHOS_B_5G_LUT_CHAN_546125_IDX] = { 21845, 0x0, 0x3C, 0x15C71C, 0x71C },
+	[ATHOS_B_5G_LUT_CHAN_546250_IDX] = { 21850, 0x0, 0x3C, 0x1638E4, 0x71D },
+	[ATHOS_B_5G_LUT_CHAN_546375_IDX] = { 21855, 0x0, 0x3C, 0x16AAAB, 0x71D },
+	[ATHOS_B_5G_LUT_CHAN_546500_IDX] = { 21860, 0x0, 0x3C, 0x171C72, 0x71E },
+	[ATHOS_B_5G_LUT_CHAN_546625_IDX] = { 21865, 0x0, 0x3C, 0x178E39, 0x71E },
+	[ATHOS_B_5G_LUT_CHAN_546750_IDX] = { 21870, 0x0, 0x3C, 0x180000, 0x71F },
+	[ATHOS_B_5G_LUT_CHAN_546875_IDX] = { 21875, 0x0, 0x3C, 0x1871C7, 0x71F },
+	[ATHOS_B_5G_LUT_CHAN_547000_IDX] = { 21880, 0x0, 0x3C, 0x18E38E, 0x71F },
+	[ATHOS_B_5G_LUT_CHAN_547125_IDX] = { 21885, 0x0, 0x3C, 0x195555, 0x720 },
+	[ATHOS_B_5G_LUT_CHAN_547250_IDX] = { 21890, 0x0, 0x3C, 0x19C71C, 0x720 },
+	[ATHOS_B_5G_LUT_CHAN_547375_IDX] = { 21895, 0x0, 0x3C, 0x1A38E4, 0x721 },
+	[ATHOS_B_5G_LUT_CHAN_547500_IDX] = { 21900, 0x0, 0x3C, 0x1AAAAB, 0x721 },
+	[ATHOS_B_5G_LUT_CHAN_547625_IDX] = { 21905, 0x0, 0x3C, 0x1B1C72, 0x721 },
+	[ATHOS_B_5G_LUT_CHAN_547750_IDX] = { 21910, 0x0, 0x3C, 0x1B8E39, 0x722 },
+	[ATHOS_B_5G_LUT_CHAN_547875_IDX] = { 21915, 0x0, 0x3C, 0x1C0000, 0x722 },
+	[ATHOS_B_5G_LUT_CHAN_548000_IDX] = { 21920, 0x0, 0x3C, 0x1C71C7, 0x723 },
+	[ATHOS_B_5G_LUT_CHAN_548125_IDX] = { 21925, 0x0, 0x3C, 0x1CE38E, 0x723 },
+	[ATHOS_B_5G_LUT_CHAN_548250_IDX] = { 21930, 0x0, 0x3C, 0x1D5555, 0x724 },
+	[ATHOS_B_5G_LUT_CHAN_548375_IDX] = { 21935, 0x0, 0x3C, 0x1DC71C, 0x724 },
+	[ATHOS_B_5G_LUT_CHAN_548500_IDX] = { 21940, 0x0, 0x3C, 0x1E38E4, 0x724 },
+	[ATHOS_B_5G_LUT_CHAN_548625_IDX] = { 21945, 0x0, 0x3C, 0x1EAAAB, 0x725 },
+	[ATHOS_B_5G_LUT_CHAN_548750_IDX] = { 21950, 0x0, 0x3C, 0x1F1C72, 0x725 },
+	[ATHOS_B_5G_LUT_CHAN_548875_IDX] = { 21955, 0x0, 0x3C, 0x1F8E39, 0x726 },
+	[ATHOS_B_5G_LUT_CHAN_549000_IDX] = { 21960, 0x0, 0x3D, 0x0, 0x726 },
+	[ATHOS_B_5G_LUT_CHAN_549125_IDX] = { 21965, 0x0, 0x3D, 0x71C7, 0x726 },
+	[ATHOS_B_5G_LUT_CHAN_549250_IDX] = { 21970, 0x0, 0x3D, 0xE38E, 0x727 },
+	[ATHOS_B_5G_LUT_CHAN_549375_IDX] = { 21975, 0x0, 0x3D, 0x15555, 0x727 },
+	[ATHOS_B_5G_LUT_CHAN_549500_IDX] = { 21980, 0x0, 0x3D, 0x1C71C, 0x728 },
+	[ATHOS_B_5G_LUT_CHAN_549625_IDX] = { 21985, 0x0, 0x3D, 0x238E4, 0x728 },
+	[ATHOS_B_5G_LUT_CHAN_549750_IDX] = { 21990, 0x0, 0x3D, 0x2AAAB, 0x729 },
+	[ATHOS_B_5G_LUT_CHAN_549875_IDX] = { 21995, 0x0, 0x3D, 0x31C72, 0x729 },
+	[ATHOS_B_5G_LUT_CHAN_550000_IDX] = { 22000, 0x0, 0x3D, 0x38E39, 0x729 },
+	[ATHOS_B_5G_LUT_CHAN_550125_IDX] = { 22005, 0x0, 0x3D, 0x40000, 0x72A },
+	[ATHOS_B_5G_LUT_CHAN_550250_IDX] = { 22010, 0x0, 0x3D, 0x471C7, 0x72A },
+	[ATHOS_B_5G_LUT_CHAN_550375_IDX] = { 22015, 0x0, 0x3D, 0x4E38E, 0x72B },
+	[ATHOS_B_5G_LUT_CHAN_550500_IDX] = { 22020, 0x0, 0x3D, 0x55555, 0x72B },
+	[ATHOS_B_5G_LUT_CHAN_550625_IDX] = { 22025, 0x0, 0x3D, 0x5C71C, 0x72B },
+	[ATHOS_B_5G_LUT_CHAN_550750_IDX] = { 22030, 0x0, 0x3D, 0x638E4, 0x72C },
+	[ATHOS_B_5G_LUT_CHAN_550875_IDX] = { 22035, 0x0, 0x3D, 0x6AAAB, 0x72C },
+	[ATHOS_B_5G_LUT_CHAN_551000_IDX] = { 22040, 0x0, 0x3D, 0x71C72, 0x72D },
+	[ATHOS_B_5G_LUT_CHAN_551125_IDX] = { 22045, 0x0, 0x3D, 0x78E39, 0x72D },
+	[ATHOS_B_5G_LUT_CHAN_551250_IDX] = { 22050, 0x0, 0x3D, 0x80000, 0x72E },
+	[ATHOS_B_5G_LUT_CHAN_551375_IDX] = { 22055, 0x0, 0x3D, 0x871C7, 0x72E },
+	[ATHOS_B_5G_LUT_CHAN_551500_IDX] = { 22060, 0x0, 0x3D, 0x8E38E, 0x72E },
+	[ATHOS_B_5G_LUT_CHAN_551625_IDX] = { 22065, 0x0, 0x3D, 0x95555, 0x72F },
+	[ATHOS_B_5G_LUT_CHAN_551750_IDX] = { 22070, 0x0, 0x3D, 0x9C71C, 0x72F },
+	[ATHOS_B_5G_LUT_CHAN_551875_IDX] = { 22075, 0x0, 0x3D, 0xA38E4, 0x730 },
+	[ATHOS_B_5G_LUT_CHAN_552000_IDX] = { 22080, 0x0, 0x3D, 0xAAAAB, 0x730 },
+	[ATHOS_B_5G_LUT_CHAN_552125_IDX] = { 22085, 0x0, 0x3D, 0xB1C72, 0x730 },
+	[ATHOS_B_5G_LUT_CHAN_552250_IDX] = { 22090, 0x0, 0x3D, 0xB8E39, 0x731 },
+	[ATHOS_B_5G_LUT_CHAN_552375_IDX] = { 22095, 0x0, 0x3D, 0xC0000, 0x731 },
+	[ATHOS_B_5G_LUT_CHAN_552500_IDX] = { 22100, 0x0, 0x3D, 0xC71C7, 0x732 },
+	[ATHOS_B_5G_LUT_CHAN_552625_IDX] = { 22105, 0x0, 0x3D, 0xCE38E, 0x732 },
+	[ATHOS_B_5G_LUT_CHAN_552750_IDX] = { 22110, 0x0, 0x3D, 0xD5555, 0x733 },
+	[ATHOS_B_5G_LUT_CHAN_552875_IDX] = { 22115, 0x0, 0x3D, 0xDC71C, 0x733 },
+	[ATHOS_B_5G_LUT_CHAN_553000_IDX] = { 22120, 0x0, 0x3D, 0xE38E4, 0x733 },
+	[ATHOS_B_5G_LUT_CHAN_553125_IDX] = { 22125, 0x0, 0x3D, 0xEAAAB, 0x734 },
+	[ATHOS_B_5G_LUT_CHAN_553250_IDX] = { 22130, 0x0, 0x3D, 0xF1C72, 0x734 },
+	[ATHOS_B_5G_LUT_CHAN_553375_IDX] = { 22135, 0x0, 0x3D, 0xF8E39, 0x735 },
+	[ATHOS_B_5G_LUT_CHAN_553500_IDX] = { 22140, 0x0, 0x3D, 0x100000, 0x735 },
+	[ATHOS_B_5G_LUT_CHAN_553625_IDX] = { 22145, 0x0, 0x3D, 0x1071C7, 0x735 },
+	[ATHOS_B_5G_LUT_CHAN_553750_IDX] = { 22150, 0x0, 0x3D, 0x10E38E, 0x736 },
+	[ATHOS_B_5G_LUT_CHAN_553875_IDX] = { 22155, 0x0, 0x3D, 0x115555, 0x736 },
+	[ATHOS_B_5G_LUT_CHAN_554000_IDX] = { 22160, 0x0, 0x3D, 0x11C71C, 0x737 },
+	[ATHOS_B_5G_LUT_CHAN_554125_IDX] = { 22165, 0x0, 0x3D, 0x1238E4, 0x737 },
+	[ATHOS_B_5G_LUT_CHAN_554250_IDX] = { 22170, 0x0, 0x3D, 0x12AAAB, 0x738 },
+	[ATHOS_B_5G_LUT_CHAN_554375_IDX] = { 22175, 0x0, 0x3D, 0x131C72, 0x738 },
+	[ATHOS_B_5G_LUT_CHAN_554500_IDX] = { 22180, 0x0, 0x3D, 0x138E39, 0x738 },
+	[ATHOS_B_5G_LUT_CHAN_554625_IDX] = { 22185, 0x0, 0x3D, 0x140000, 0x739 },
+	[ATHOS_B_5G_LUT_CHAN_554750_IDX] = { 22190, 0x0, 0x3D, 0x1471C7, 0x739 },
+	[ATHOS_B_5G_LUT_CHAN_554875_IDX] = { 22195, 0x0, 0x3D, 0x14E38E, 0x73A },
+	[ATHOS_B_5G_LUT_CHAN_555000_IDX] = { 22200, 0x0, 0x3D, 0x155555, 0x73A },
+	[ATHOS_B_5G_LUT_CHAN_555125_IDX] = { 22205, 0x0, 0x3D, 0x15C71C, 0x73A },
+	[ATHOS_B_5G_LUT_CHAN_555250_IDX] = { 22210, 0x0, 0x3D, 0x1638E4, 0x73B },
+	[ATHOS_B_5G_LUT_CHAN_555375_IDX] = { 22215, 0x0, 0x3D, 0x16AAAB, 0x73B },
+	[ATHOS_B_5G_LUT_CHAN_555500_IDX] = { 22220, 0x0, 0x3D, 0x171C72, 0x73C },
+	[ATHOS_B_5G_LUT_CHAN_555625_IDX] = { 22225, 0x0, 0x3D, 0x178E39, 0x73C },
+	[ATHOS_B_5G_LUT_CHAN_555750_IDX] = { 22230, 0x0, 0x3D, 0x180000, 0x73D },
+	[ATHOS_B_5G_LUT_CHAN_555875_IDX] = { 22235, 0x0, 0x3D, 0x1871C7, 0x73D },
+	[ATHOS_B_5G_LUT_CHAN_556000_IDX] = { 22240, 0x0, 0x3D, 0x18E38E, 0x73D },
+	[ATHOS_B_5G_LUT_CHAN_556125_IDX] = { 22245, 0x0, 0x3D, 0x195555, 0x73E },
+	[ATHOS_B_5G_LUT_CHAN_556250_IDX] = { 22250, 0x0, 0x3D, 0x19C71C, 0x73E },
+	[ATHOS_B_5G_LUT_CHAN_556375_IDX] = { 22255, 0x0, 0x3D, 0x1A38E4, 0x73F },
+	[ATHOS_B_5G_LUT_CHAN_556500_IDX] = { 22260, 0x0, 0x3D, 0x1AAAAB, 0x73F },
+	[ATHOS_B_5G_LUT_CHAN_556625_IDX] = { 22265, 0x0, 0x3D, 0x1B1C72, 0x73F },
+	[ATHOS_B_5G_LUT_CHAN_556750_IDX] = { 22270, 0x0, 0x3D, 0x1B8E39, 0x740 },
+	[ATHOS_B_5G_LUT_CHAN_556875_IDX] = { 22275, 0x0, 0x3D, 0x1C0000, 0x740 },
+	[ATHOS_B_5G_LUT_CHAN_557000_IDX] = { 22280, 0x0, 0x3D, 0x1C71C7, 0x741 },
+	[ATHOS_B_5G_LUT_CHAN_557125_IDX] = { 22285, 0x0, 0x3D, 0x1CE38E, 0x741 },
+	[ATHOS_B_5G_LUT_CHAN_557250_IDX] = { 22290, 0x0, 0x3D, 0x1D5555, 0x742 },
+	[ATHOS_B_5G_LUT_CHAN_557375_IDX] = { 22295, 0x0, 0x3D, 0x1DC71C, 0x742 },
+	[ATHOS_B_5G_LUT_CHAN_557500_IDX] = { 22300, 0x0, 0x3D, 0x1E38E4, 0x742 },
+	[ATHOS_B_5G_LUT_CHAN_557625_IDX] = { 22305, 0x0, 0x3D, 0x1EAAAB, 0x743 },
+	[ATHOS_B_5G_LUT_CHAN_557750_IDX] = { 22310, 0x0, 0x3D, 0x1F1C72, 0x743 },
+	[ATHOS_B_5G_LUT_CHAN_557875_IDX] = { 22315, 0x0, 0x3D, 0x1F8E39, 0x744 },
+	[ATHOS_B_5G_LUT_CHAN_558000_IDX] = { 22320, 0x0, 0x3E, 0x0, 0x744 },
+	[ATHOS_B_5G_LUT_CHAN_558125_IDX] = { 22325, 0x0, 0x3E, 0x71C7, 0x744 },
+	[ATHOS_B_5G_LUT_CHAN_558250_IDX] = { 22330, 0x0, 0x3E, 0xE38E, 0x745 },
+	[ATHOS_B_5G_LUT_CHAN_558375_IDX] = { 22335, 0x0, 0x3E, 0x15555, 0x745 },
+	[ATHOS_B_5G_LUT_CHAN_558500_IDX] = { 22340, 0x0, 0x3E, 0x1C71C, 0x746 },
+	[ATHOS_B_5G_LUT_CHAN_558625_IDX] = { 22345, 0x0, 0x3E, 0x238E4, 0x746 },
+	[ATHOS_B_5G_LUT_CHAN_558750_IDX] = { 22350, 0x0, 0x3E, 0x2AAAB, 0x747 },
+	[ATHOS_B_5G_LUT_CHAN_558875_IDX] = { 22355, 0x0, 0x3E, 0x31C72, 0x747 },
+	[ATHOS_B_5G_LUT_CHAN_559000_IDX] = { 22360, 0x0, 0x3E, 0x38E39, 0x747 },
+	[ATHOS_B_5G_LUT_CHAN_559125_IDX] = { 22365, 0x0, 0x3E, 0x40000, 0x748 },
+	[ATHOS_B_5G_LUT_CHAN_559250_IDX] = { 22370, 0x0, 0x3E, 0x471C7, 0x748 },
+	[ATHOS_B_5G_LUT_CHAN_559375_IDX] = { 22375, 0x0, 0x3E, 0x4E38E, 0x749 },
+	[ATHOS_B_5G_LUT_CHAN_559500_IDX] = { 22380, 0x0, 0x3E, 0x55555, 0x749 },
+	[ATHOS_B_5G_LUT_CHAN_559625_IDX] = { 22385, 0x0, 0x3E, 0x5C71C, 0x749 },
+	[ATHOS_B_5G_LUT_CHAN_559750_IDX] = { 22390, 0x0, 0x3E, 0x638E4, 0x74A },
+	[ATHOS_B_5G_LUT_CHAN_559875_IDX] = { 22395, 0x0, 0x3E, 0x6AAAB, 0x74A },
+	[ATHOS_B_5G_LUT_CHAN_560000_IDX] = { 22400, 0x0, 0x3E, 0x71C72, 0x74B },
+	[ATHOS_B_5G_LUT_CHAN_560125_IDX] = { 22405, 0x0, 0x3E, 0x78E39, 0x74B },
+	[ATHOS_B_5G_LUT_CHAN_560250_IDX] = { 22410, 0x0, 0x3E, 0x80000, 0x74C },
+	[ATHOS_B_5G_LUT_CHAN_560375_IDX] = { 22415, 0x0, 0x3E, 0x871C7, 0x74C },
+	[ATHOS_B_5G_LUT_CHAN_560500_IDX] = { 22420, 0x0, 0x3E, 0x8E38E, 0x74C },
+	[ATHOS_B_5G_LUT_CHAN_560625_IDX] = { 22425, 0x0, 0x3E, 0x95555, 0x74D },
+	[ATHOS_B_5G_LUT_CHAN_560750_IDX] = { 22430, 0x0, 0x3E, 0x9C71C, 0x74D },
+	[ATHOS_B_5G_LUT_CHAN_560875_IDX] = { 22435, 0x0, 0x3E, 0xA38E4, 0x74E },
+	[ATHOS_B_5G_LUT_CHAN_561000_IDX] = { 22440, 0x0, 0x3E, 0xAAAAB, 0x74E },
+	[ATHOS_B_5G_LUT_CHAN_561125_IDX] = { 22445, 0x0, 0x3E, 0xB1C72, 0x74E },
+	[ATHOS_B_5G_LUT_CHAN_561250_IDX] = { 22450, 0x0, 0x3E, 0xB8E39, 0x74F },
+	[ATHOS_B_5G_LUT_CHAN_561375_IDX] = { 22455, 0x0, 0x3E, 0xC0000, 0x74F },
+	[ATHOS_B_5G_LUT_CHAN_561500_IDX] = { 22460, 0x0, 0x3E, 0xC71C7, 0x750 },
+	[ATHOS_B_5G_LUT_CHAN_561625_IDX] = { 22465, 0x0, 0x3E, 0xCE38E, 0x750 },
+	[ATHOS_B_5G_LUT_CHAN_561750_IDX] = { 22470, 0x0, 0x3E, 0xD5555, 0x751 },
+	[ATHOS_B_5G_LUT_CHAN_561875_IDX] = { 22475, 0x0, 0x3E, 0xDC71C, 0x751 },
+	[ATHOS_B_5G_LUT_CHAN_562000_IDX] = { 22480, 0x0, 0x3E, 0xE38E4, 0x751 },
+	[ATHOS_B_5G_LUT_CHAN_562125_IDX] = { 22485, 0x0, 0x3E, 0xEAAAB, 0x752 },
+	[ATHOS_B_5G_LUT_CHAN_562250_IDX] = { 22490, 0x0, 0x3E, 0xF1C72, 0x752 },
+	[ATHOS_B_5G_LUT_CHAN_562375_IDX] = { 22495, 0x0, 0x3E, 0xF8E39, 0x753 },
+	[ATHOS_B_5G_LUT_CHAN_562500_IDX] = { 22500, 0x0, 0x3E, 0x100000, 0x753 },
+	[ATHOS_B_5G_LUT_CHAN_562625_IDX] = { 22505, 0x0, 0x3E, 0x1071C7, 0x753 },
+	[ATHOS_B_5G_LUT_CHAN_562750_IDX] = { 22510, 0x0, 0x3E, 0x10E38E, 0x754 },
+	[ATHOS_B_5G_LUT_CHAN_562875_IDX] = { 22515, 0x0, 0x3E, 0x115555, 0x754 },
+	[ATHOS_B_5G_LUT_CHAN_563000_IDX] = { 22520, 0x0, 0x3E, 0x11C71C, 0x755 },
+	[ATHOS_B_5G_LUT_CHAN_563125_IDX] = { 22525, 0x0, 0x3E, 0x1238E4, 0x755 },
+	[ATHOS_B_5G_LUT_CHAN_563250_IDX] = { 22530, 0x0, 0x3E, 0x12AAAB, 0x756 },
+	[ATHOS_B_5G_LUT_CHAN_563375_IDX] = { 22535, 0x0, 0x3E, 0x131C72, 0x756 },
+	[ATHOS_B_5G_LUT_CHAN_563500_IDX] = { 22540, 0x0, 0x3E, 0x138E39, 0x756 },
+	[ATHOS_B_5G_LUT_CHAN_563625_IDX] = { 22545, 0x0, 0x3E, 0x140000, 0x757 },
+	[ATHOS_B_5G_LUT_CHAN_563750_IDX] = { 22550, 0x0, 0x3E, 0x1471C7, 0x757 },
+	[ATHOS_B_5G_LUT_CHAN_563875_IDX] = { 22555, 0x0, 0x3E, 0x14E38E, 0x758 },
+	[ATHOS_B_5G_LUT_CHAN_564000_IDX] = { 22560, 0x0, 0x3E, 0x155555, 0x758 },
+	[ATHOS_B_5G_LUT_CHAN_564125_IDX] = { 22565, 0x0, 0x3E, 0x15C71C, 0x758 },
+	[ATHOS_B_5G_LUT_CHAN_564250_IDX] = { 22570, 0x0, 0x3E, 0x1638E4, 0x759 },
+	[ATHOS_B_5G_LUT_CHAN_564375_IDX] = { 22575, 0x0, 0x3E, 0x16AAAB, 0x759 },
+	[ATHOS_B_5G_LUT_CHAN_564500_IDX] = { 22580, 0x0, 0x3E, 0x171C72, 0x75A },
+	[ATHOS_B_5G_LUT_CHAN_564625_IDX] = { 22585, 0x0, 0x3E, 0x178E39, 0x75A },
+	[ATHOS_B_5G_LUT_CHAN_564750_IDX] = { 22590, 0x0, 0x3E, 0x180000, 0x75B },
+	[ATHOS_B_5G_LUT_CHAN_564875_IDX] = { 22595, 0x0, 0x3E, 0x1871C7, 0x75B },
+	[ATHOS_B_5G_LUT_CHAN_565000_IDX] = { 22600, 0x0, 0x3E, 0x18E38E, 0x75B },
+	[ATHOS_B_5G_LUT_CHAN_565125_IDX] = { 22605, 0x0, 0x3E, 0x195555, 0x75C },
+	[ATHOS_B_5G_LUT_CHAN_565250_IDX] = { 22610, 0x0, 0x3E, 0x19C71C, 0x75C },
+	[ATHOS_B_5G_LUT_CHAN_565375_IDX] = { 22615, 0x0, 0x3E, 0x1A38E4, 0x75D },
+	[ATHOS_B_5G_LUT_CHAN_565500_IDX] = { 22620, 0x0, 0x3E, 0x1AAAAB, 0x75D },
+	[ATHOS_B_5G_LUT_CHAN_565625_IDX] = { 22625, 0x0, 0x3E, 0x1B1C72, 0x75D },
+	[ATHOS_B_5G_LUT_CHAN_565750_IDX] = { 22630, 0x0, 0x3E, 0x1B8E39, 0x75E },
+	[ATHOS_B_5G_LUT_CHAN_565875_IDX] = { 22635, 0x0, 0x3E, 0x1C0000, 0x75E },
+	[ATHOS_B_5G_LUT_CHAN_566000_IDX] = { 22640, 0x0, 0x3E, 0x1C71C7, 0x75F },
+	[ATHOS_B_5G_LUT_CHAN_566125_IDX] = { 22645, 0x0, 0x3E, 0x1CE38E, 0x75F },
+	[ATHOS_B_5G_LUT_CHAN_566250_IDX] = { 22650, 0x0, 0x3E, 0x1D5555, 0x760 },
+	[ATHOS_B_5G_LUT_CHAN_566375_IDX] = { 22655, 0x0, 0x3E, 0x1DC71C, 0x760 },
+	[ATHOS_B_5G_LUT_CHAN_566500_IDX] = { 22660, 0x0, 0x3E, 0x1E38E4, 0x760 },
+	[ATHOS_B_5G_LUT_CHAN_566625_IDX] = { 22665, 0x0, 0x3E, 0x1EAAAB, 0x761 },
+	[ATHOS_B_5G_LUT_CHAN_566750_IDX] = { 22670, 0x0, 0x3E, 0x1F1C72, 0x761 },
+	[ATHOS_B_5G_LUT_CHAN_566875_IDX] = { 22675, 0x0, 0x3E, 0x1F8E39, 0x762 },
+	[ATHOS_B_5G_LUT_CHAN_567000_IDX] = { 22680, 0x0, 0x3F, 0x0, 0x762 },
+	[ATHOS_B_5G_LUT_CHAN_567125_IDX] = { 22685, 0x0, 0x3F, 0x71C7, 0x762 },
+	[ATHOS_B_5G_LUT_CHAN_567250_IDX] = { 22690, 0x0, 0x3F, 0xE38E, 0x763 },
+	[ATHOS_B_5G_LUT_CHAN_567375_IDX] = { 22695, 0x0, 0x3F, 0x15555, 0x763 },
+	[ATHOS_B_5G_LUT_CHAN_567500_IDX] = { 22700, 0x0, 0x3F, 0x1C71C, 0x764 },
+	[ATHOS_B_5G_LUT_CHAN_567625_IDX] = { 22705, 0x0, 0x3F, 0x238E4, 0x764 },
+	[ATHOS_B_5G_LUT_CHAN_567750_IDX] = { 22710, 0x0, 0x3F, 0x2AAAB, 0x765 },
+	[ATHOS_B_5G_LUT_CHAN_567875_IDX] = { 22715, 0x0, 0x3F, 0x31C72, 0x765 },
+	[ATHOS_B_5G_LUT_CHAN_568000_IDX] = { 22720, 0x0, 0x3F, 0x38E39, 0x765 },
+	[ATHOS_B_5G_LUT_CHAN_568125_IDX] = { 22725, 0x0, 0x3F, 0x40000, 0x766 },
+	[ATHOS_B_5G_LUT_CHAN_568250_IDX] = { 22730, 0x0, 0x3F, 0x471C7, 0x766 },
+	[ATHOS_B_5G_LUT_CHAN_568375_IDX] = { 22735, 0x0, 0x3F, 0x4E38E, 0x767 },
+	[ATHOS_B_5G_LUT_CHAN_568500_IDX] = { 22740, 0x0, 0x3F, 0x55555, 0x767 },
+	[ATHOS_B_5G_LUT_CHAN_568625_IDX] = { 22745, 0x0, 0x3F, 0x5C71C, 0x767 },
+	[ATHOS_B_5G_LUT_CHAN_568750_IDX] = { 22750, 0x0, 0x3F, 0x638E4, 0x768 },
+	[ATHOS_B_5G_LUT_CHAN_568875_IDX] = { 22755, 0x0, 0x3F, 0x6AAAB, 0x768 },
+	[ATHOS_B_5G_LUT_CHAN_569000_IDX] = { 22760, 0x0, 0x3F, 0x71C72, 0x769 },
+	[ATHOS_B_5G_LUT_CHAN_569125_IDX] = { 22765, 0x0, 0x3F, 0x78E39, 0x769 },
+	[ATHOS_B_5G_LUT_CHAN_569250_IDX] = { 22770, 0x0, 0x3F, 0x80000, 0x76A },
+	[ATHOS_B_5G_LUT_CHAN_569375_IDX] = { 22775, 0x0, 0x3F, 0x871C7, 0x76A },
+	[ATHOS_B_5G_LUT_CHAN_569500_IDX] = { 22780, 0x0, 0x3F, 0x8E38E, 0x76A },
+	[ATHOS_B_5G_LUT_CHAN_569625_IDX] = { 22785, 0x0, 0x3F, 0x95555, 0x76B },
+	[ATHOS_B_5G_LUT_CHAN_569750_IDX] = { 22790, 0x0, 0x3F, 0x9C71C, 0x76B },
+	[ATHOS_B_5G_LUT_CHAN_569875_IDX] = { 22795, 0x0, 0x3F, 0xA38E4, 0x76C },
+	[ATHOS_B_5G_LUT_CHAN_570000_IDX] = { 22800, 0x0, 0x3F, 0xAAAAB, 0x76C },
+	[ATHOS_B_5G_LUT_CHAN_570125_IDX] = { 22805, 0x0, 0x3F, 0xB1C72, 0x76C },
+	[ATHOS_B_5G_LUT_CHAN_570250_IDX] = { 22810, 0x0, 0x3F, 0xB8E39, 0x76D },
+	[ATHOS_B_5G_LUT_CHAN_570375_IDX] = { 22815, 0x0, 0x3F, 0xC0000, 0x76D },
+	[ATHOS_B_5G_LUT_CHAN_570500_IDX] = { 22820, 0x0, 0x3F, 0xC71C7, 0x76E },
+	[ATHOS_B_5G_LUT_CHAN_570625_IDX] = { 22825, 0x0, 0x3F, 0xCE38E, 0x76E },
+	[ATHOS_B_5G_LUT_CHAN_570750_IDX] = { 22830, 0x0, 0x3F, 0xD5555, 0x76F },
+	[ATHOS_B_5G_LUT_CHAN_570875_IDX] = { 22835, 0x0, 0x3F, 0xDC71C, 0x76F },
+	[ATHOS_B_5G_LUT_CHAN_571000_IDX] = { 22840, 0x0, 0x3F, 0xE38E4, 0x76F },
+	[ATHOS_B_5G_LUT_CHAN_571125_IDX] = { 22845, 0x0, 0x3F, 0xEAAAB, 0x770 },
+	[ATHOS_B_5G_LUT_CHAN_571250_IDX] = { 22850, 0x0, 0x3F, 0xF1C72, 0x770 },
+	[ATHOS_B_5G_LUT_CHAN_571375_IDX] = { 22855, 0x0, 0x3F, 0xF8E39, 0x771 },
+	[ATHOS_B_5G_LUT_CHAN_571500_IDX] = { 22860, 0x0, 0x3F, 0x100000, 0x771 },
+	[ATHOS_B_5G_LUT_CHAN_571625_IDX] = { 22865, 0x0, 0x3F, 0x1071C7, 0x771 },
+	[ATHOS_B_5G_LUT_CHAN_571750_IDX] = { 22870, 0x0, 0x3F, 0x10E38E, 0x772 },
+	[ATHOS_B_5G_LUT_CHAN_571875_IDX] = { 22875, 0x0, 0x3F, 0x115555, 0x772 },
+	[ATHOS_B_5G_LUT_CHAN_572000_IDX] = { 22880, 0x0, 0x3F, 0x11C71C, 0x773 },
+	[ATHOS_B_5G_LUT_CHAN_572125_IDX] = { 22885, 0x0, 0x3F, 0x1238E4, 0x773 },
+	[ATHOS_B_5G_LUT_CHAN_572250_IDX] = { 22890, 0x0, 0x3F, 0x12AAAB, 0x774 },
+	[ATHOS_B_5G_LUT_CHAN_572375_IDX] = { 22895, 0x0, 0x3F, 0x131C72, 0x774 },
+	[ATHOS_B_5G_LUT_CHAN_572500_IDX] = { 22900, 0x0, 0x3F, 0x138E39, 0x774 },
+	[ATHOS_B_5G_LUT_CHAN_572625_IDX] = { 22905, 0x0, 0x3F, 0x140000, 0x775 },
+	[ATHOS_B_5G_LUT_CHAN_572750_IDX] = { 22910, 0x0, 0x3F, 0x1471C7, 0x775 },
+	[ATHOS_B_5G_LUT_CHAN_572875_IDX] = { 22915, 0x0, 0x3F, 0x14E38E, 0x776 },
+	[ATHOS_B_5G_LUT_CHAN_573000_IDX] = { 22920, 0x0, 0x3F, 0x155555, 0x776 },
+	[ATHOS_B_5G_LUT_CHAN_573125_IDX] = { 22925, 0x0, 0x3F, 0x15C71C, 0x776 },
+	[ATHOS_B_5G_LUT_CHAN_573250_IDX] = { 22930, 0x0, 0x3F, 0x1638E4, 0x777 },
+	[ATHOS_B_5G_LUT_CHAN_573375_IDX] = { 22935, 0x0, 0x3F, 0x16AAAB, 0x777 },
+	[ATHOS_B_5G_LUT_CHAN_573500_IDX] = { 22940, 0x0, 0x3F, 0x171C72, 0x778 },
+	[ATHOS_B_5G_LUT_CHAN_573625_IDX] = { 22945, 0x0, 0x3F, 0x178E39, 0x778 },
+	[ATHOS_B_5G_LUT_CHAN_573750_IDX] = { 22950, 0x0, 0x3F, 0x180000, 0x779 },
+	[ATHOS_B_5G_LUT_CHAN_573875_IDX] = { 22955, 0x0, 0x3F, 0x1871C7, 0x779 },
+	[ATHOS_B_5G_LUT_CHAN_574000_IDX] = { 22960, 0x0, 0x3F, 0x18E38E, 0x779 },
+	[ATHOS_B_5G_LUT_CHAN_574125_IDX] = { 22965, 0x0, 0x3F, 0x195555, 0x77A },
+	[ATHOS_B_5G_LUT_CHAN_574250_IDX] = { 22970, 0x0, 0x3F, 0x19C71C, 0x77A },
+	[ATHOS_B_5G_LUT_CHAN_574375_IDX] = { 22975, 0x0, 0x3F, 0x1A38E4, 0x77B },
+	[ATHOS_B_5G_LUT_CHAN_574500_IDX] = { 22980, 0x0, 0x3F, 0x1AAAAB, 0x77B },
+	[ATHOS_B_5G_LUT_CHAN_574625_IDX] = { 22985, 0x0, 0x3F, 0x1B1C72, 0x77B },
+	[ATHOS_B_5G_LUT_CHAN_574750_IDX] = { 22990, 0x0, 0x3F, 0x1B8E39, 0x77C },
+	[ATHOS_B_5G_LUT_CHAN_574875_IDX] = { 22995, 0x0, 0x3F, 0x1C0000, 0x77C },
+	[ATHOS_B_5G_LUT_CHAN_575000_IDX] = { 23000, 0x0, 0x3F, 0x1C71C7, 0x77D },
+	[ATHOS_B_5G_LUT_CHAN_575125_IDX] = { 23005, 0x0, 0x3F, 0x1CE38E, 0x77D },
+	[ATHOS_B_5G_LUT_CHAN_575250_IDX] = { 23010, 0x0, 0x3F, 0x1D5555, 0x77E },
+	[ATHOS_B_5G_LUT_CHAN_575375_IDX] = { 23015, 0x0, 0x3F, 0x1DC71C, 0x77E },
+	[ATHOS_B_5G_LUT_CHAN_575500_IDX] = { 23020, 0x0, 0x3F, 0x1E38E4, 0x77E },
+	[ATHOS_B_5G_LUT_CHAN_575625_IDX] = { 23025, 0x0, 0x3F, 0x1EAAAB, 0x77F },
+	[ATHOS_B_5G_LUT_CHAN_575750_IDX] = { 23030, 0x0, 0x3F, 0x1F1C72, 0x77F },
+	[ATHOS_B_5G_LUT_CHAN_575875_IDX] = { 23035, 0x0, 0x3F, 0x1F8E39, 0x780 },
+	[ATHOS_B_5G_LUT_CHAN_576000_IDX] = { 23040, 0x0, 0x40, 0x0, 0x780 },
+	[ATHOS_B_5G_LUT_CHAN_576125_IDX] = { 23045, 0x0, 0x40, 0x71C7, 0x780 },
+	[ATHOS_B_5G_LUT_CHAN_576250_IDX] = { 23050, 0x0, 0x40, 0xE38E, 0x781 },
+	[ATHOS_B_5G_LUT_CHAN_576375_IDX] = { 23055, 0x0, 0x40, 0x15555, 0x781 },
+	[ATHOS_B_5G_LUT_CHAN_576500_IDX] = { 23060, 0x0, 0x40, 0x1C71C, 0x782 },
+	[ATHOS_B_5G_LUT_CHAN_576625_IDX] = { 23065, 0x0, 0x40, 0x238E4, 0x782 },
+	[ATHOS_B_5G_LUT_CHAN_576750_IDX] = { 23070, 0x0, 0x40, 0x2AAAB, 0x783 },
+	[ATHOS_B_5G_LUT_CHAN_576875_IDX] = { 23075, 0x0, 0x40, 0x31C72, 0x783 },
+	[ATHOS_B_5G_LUT_CHAN_577000_IDX] = { 23080, 0x0, 0x40, 0x38E39, 0x783 },
+	[ATHOS_B_5G_LUT_CHAN_577125_IDX] = { 23085, 0x0, 0x40, 0x40000, 0x784 },
+	[ATHOS_B_5G_LUT_CHAN_577250_IDX] = { 23090, 0x0, 0x40, 0x471C7, 0x784 },
+	[ATHOS_B_5G_LUT_CHAN_577375_IDX] = { 23095, 0x0, 0x40, 0x4E38E, 0x785 },
+	[ATHOS_B_5G_LUT_CHAN_577500_IDX] = { 23100, 0x0, 0x40, 0x55555, 0x785 },
+	[ATHOS_B_5G_LUT_CHAN_577625_IDX] = { 23105, 0x0, 0x40, 0x5C71C, 0x785 },
+	[ATHOS_B_5G_LUT_CHAN_577750_IDX] = { 23110, 0x0, 0x40, 0x638E4, 0x786 },
+	[ATHOS_B_5G_LUT_CHAN_577875_IDX] = { 23115, 0x0, 0x40, 0x6AAAB, 0x786 },
+	[ATHOS_B_5G_LUT_CHAN_578000_IDX] = { 23120, 0x0, 0x40, 0x71C72, 0x787 },
+	[ATHOS_B_5G_LUT_CHAN_578125_IDX] = { 23125, 0x0, 0x40, 0x78E39, 0x787 },
+	[ATHOS_B_5G_LUT_CHAN_578250_IDX] = { 23130, 0x0, 0x40, 0x80000, 0x788 },
+	[ATHOS_B_5G_LUT_CHAN_578375_IDX] = { 23135, 0x0, 0x40, 0x871C7, 0x788 },
+	[ATHOS_B_5G_LUT_CHAN_578500_IDX] = { 23140, 0x0, 0x40, 0x8E38E, 0x788 },
+	[ATHOS_B_5G_LUT_CHAN_578625_IDX] = { 23145, 0x0, 0x40, 0x95555, 0x789 },
+	[ATHOS_B_5G_LUT_CHAN_578750_IDX] = { 23150, 0x0, 0x40, 0x9C71C, 0x789 },
+	[ATHOS_B_5G_LUT_CHAN_578875_IDX] = { 23155, 0x0, 0x40, 0xA38E4, 0x78A },
+	[ATHOS_B_5G_LUT_CHAN_579000_IDX] = { 23160, 0x0, 0x40, 0xAAAAB, 0x78A },
+	[ATHOS_B_5G_LUT_CHAN_579125_IDX] = { 23165, 0x0, 0x40, 0xB1C72, 0x78A },
+	[ATHOS_B_5G_LUT_CHAN_579250_IDX] = { 23170, 0x0, 0x40, 0xB8E39, 0x78B },
+	[ATHOS_B_5G_LUT_CHAN_579375_IDX] = { 23175, 0x0, 0x40, 0xC0000, 0x78B },
+	[ATHOS_B_5G_LUT_CHAN_579500_IDX] = { 23180, 0x0, 0x40, 0xC71C7, 0x78C },
+	[ATHOS_B_5G_LUT_CHAN_579625_IDX] = { 23185, 0x0, 0x40, 0xCE38E, 0x78C },
+	[ATHOS_B_5G_LUT_CHAN_579750_IDX] = { 23190, 0x0, 0x40, 0xD5555, 0x78D },
+	[ATHOS_B_5G_LUT_CHAN_579875_IDX] = { 23195, 0x0, 0x40, 0xDC71C, 0x78D },
+	[ATHOS_B_5G_LUT_CHAN_580000_IDX] = { 23200, 0x0, 0x40, 0xE38E4, 0x78D },
+	[ATHOS_B_5G_LUT_CHAN_580125_IDX] = { 23205, 0x0, 0x40, 0xEAAAB, 0x78E },
+	[ATHOS_B_5G_LUT_CHAN_580250_IDX] = { 23210, 0x0, 0x40, 0xF1C72, 0x78E },
+	[ATHOS_B_5G_LUT_CHAN_580375_IDX] = { 23215, 0x0, 0x40, 0xF8E39, 0x78F },
+	[ATHOS_B_5G_LUT_CHAN_580500_IDX] = { 23220, 0x0, 0x40, 0x100000, 0x78F },
+	[ATHOS_B_5G_LUT_CHAN_580625_IDX] = { 23225, 0x0, 0x40, 0x1071C7, 0x78F },
+	[ATHOS_B_5G_LUT_CHAN_580750_IDX] = { 23230, 0x0, 0x40, 0x10E38E, 0x790 },
+	[ATHOS_B_5G_LUT_CHAN_580875_IDX] = { 23235, 0x0, 0x40, 0x115555, 0x790 },
+	[ATHOS_B_5G_LUT_CHAN_581000_IDX] = { 23240, 0x0, 0x40, 0x11C71C, 0x791 },
+	[ATHOS_B_5G_LUT_CHAN_581125_IDX] = { 23245, 0x0, 0x40, 0x1238E4, 0x791 },
+	[ATHOS_B_5G_LUT_CHAN_581250_IDX] = { 23250, 0x0, 0x40, 0x12AAAB, 0x792 },
+	[ATHOS_B_5G_LUT_CHAN_581375_IDX] = { 23255, 0x0, 0x40, 0x131C72, 0x792 },
+	[ATHOS_B_5G_LUT_CHAN_581500_IDX] = { 23260, 0x0, 0x40, 0x138E39, 0x792 },
+	[ATHOS_B_5G_LUT_CHAN_581625_IDX] = { 23265, 0x0, 0x40, 0x140000, 0x793 },
+	[ATHOS_B_5G_LUT_CHAN_581750_IDX] = { 23270, 0x0, 0x40, 0x1471C7, 0x793 },
+	[ATHOS_B_5G_LUT_CHAN_581875_IDX] = { 23275, 0x0, 0x40, 0x14E38E, 0x794 },
+	[ATHOS_B_5G_LUT_CHAN_582000_IDX] = { 23280, 0x0, 0x40, 0x155555, 0x794 },
+	[ATHOS_B_5G_LUT_CHAN_582125_IDX] = { 23285, 0x0, 0x40, 0x15C71C, 0x794 },
+	[ATHOS_B_5G_LUT_CHAN_582250_IDX] = { 23290, 0x0, 0x40, 0x1638E4, 0x795 },
+	[ATHOS_B_5G_LUT_CHAN_582375_IDX] = { 23295, 0x0, 0x40, 0x16AAAB, 0x795 },
+	[ATHOS_B_5G_LUT_CHAN_582500_IDX] = { 23300, 0x0, 0x40, 0x171C72, 0x796 },
+	[ATHOS_B_5G_LUT_CHAN_582625_IDX] = { 23305, 0x0, 0x40, 0x178E39, 0x796 },
+	[ATHOS_B_5G_LUT_CHAN_582750_IDX] = { 23310, 0x0, 0x40, 0x180000, 0x797 },
+	[ATHOS_B_5G_LUT_CHAN_582875_IDX] = { 23315, 0x0, 0x40, 0x1871C7, 0x797 },
+	[ATHOS_B_5G_LUT_CHAN_583000_IDX] = { 23320, 0x0, 0x40, 0x18E38E, 0x797 },
+	[ATHOS_B_5G_LUT_CHAN_583125_IDX] = { 23325, 0x0, 0x40, 0x195555, 0x798 },
+	[ATHOS_B_5G_LUT_CHAN_583250_IDX] = { 23330, 0x0, 0x40, 0x19C71C, 0x798 },
+	[ATHOS_B_5G_LUT_CHAN_583375_IDX] = { 23335, 0x0, 0x40, 0x1A38E4, 0x799 },
+	[ATHOS_B_5G_LUT_CHAN_583500_IDX] = { 23340, 0x0, 0x40, 0x1AAAAB, 0x799 },
+	[ATHOS_B_5G_LUT_CHAN_583625_IDX] = { 23345, 0x0, 0x40, 0x1B1C72, 0x799 },
+	[ATHOS_B_5G_LUT_CHAN_583750_IDX] = { 23350, 0x0, 0x40, 0x1B8E39, 0x79A },
+	[ATHOS_B_5G_LUT_CHAN_583875_IDX] = { 23355, 0x0, 0x40, 0x1C0000, 0x79A },
+	[ATHOS_B_5G_LUT_CHAN_584000_IDX] = { 23360, 0x0, 0x40, 0x1C71C7, 0x79B },
+	[ATHOS_B_5G_LUT_CHAN_584125_IDX] = { 23365, 0x0, 0x40, 0x1CE38E, 0x79B },
+	[ATHOS_B_5G_LUT_CHAN_584250_IDX] = { 23370, 0x0, 0x40, 0x1D5555, 0x79C },
+	[ATHOS_B_5G_LUT_CHAN_584375_IDX] = { 23375, 0x0, 0x40, 0x1DC71C, 0x79C },
+	[ATHOS_B_5G_LUT_CHAN_584500_IDX] = { 23380, 0x0, 0x40, 0x1E38E4, 0x79C },
+	[ATHOS_B_5G_LUT_CHAN_584625_IDX] = { 23385, 0x0, 0x40, 0x1EAAAB, 0x79D },
+	[ATHOS_B_5G_LUT_CHAN_584750_IDX] = { 23390, 0x0, 0x40, 0x1F1C72, 0x79D },
+	[ATHOS_B_5G_LUT_CHAN_584875_IDX] = { 23395, 0x0, 0x40, 0x1F8E39, 0x79E },
+	[ATHOS_B_5G_LUT_CHAN_585000_IDX] = { 23400, 0x0, 0x41, 0x0, 0x79E },
+	[ATHOS_B_5G_LUT_CHAN_585125_IDX] = { 23405, 0x0, 0x41, 0x71C7, 0x79E },
+	[ATHOS_B_5G_LUT_CHAN_585250_IDX] = { 23410, 0x0, 0x41, 0xE38E, 0x79F },
+	[ATHOS_B_5G_LUT_CHAN_585375_IDX] = { 23415, 0x0, 0x41, 0x15555, 0x79F },
+	[ATHOS_B_5G_LUT_CHAN_585500_IDX] = { 23420, 0x0, 0x41, 0x1C71C, 0x7A0 },
+	[ATHOS_B_5G_LUT_CHAN_585625_IDX] = { 23425, 0x0, 0x41, 0x238E4, 0x7A0 },
+	[ATHOS_B_5G_LUT_CHAN_585750_IDX] = { 23430, 0x0, 0x41, 0x2AAAB, 0x7A1 },
+	[ATHOS_B_5G_LUT_CHAN_585875_IDX] = { 23435, 0x0, 0x41, 0x31C72, 0x7A1 },
+	[ATHOS_B_5G_LUT_CHAN_586000_IDX] = { 23440, 0x0, 0x41, 0x38E39, 0x7A1 },
+	[ATHOS_B_5G_LUT_CHAN_586125_IDX] = { 23445, 0x0, 0x41, 0x40000, 0x7A2 },
+	[ATHOS_B_5G_LUT_CHAN_586250_IDX] = { 23450, 0x0, 0x41, 0x471C7, 0x7A2 },
+	[ATHOS_B_5G_LUT_CHAN_586375_IDX] = { 23455, 0x0, 0x41, 0x4E38E, 0x7A3 },
+	[ATHOS_B_5G_LUT_CHAN_586500_IDX] = { 23460, 0x0, 0x41, 0x55555, 0x7A3 },
+	[ATHOS_B_5G_LUT_CHAN_586625_IDX] = { 23465, 0x0, 0x41, 0x5C71C, 0x7A3 },
+	[ATHOS_B_5G_LUT_CHAN_586750_IDX] = { 23470, 0x0, 0x41, 0x638E4, 0x7A4 },
+	[ATHOS_B_5G_LUT_CHAN_586875_IDX] = { 23475, 0x0, 0x41, 0x6AAAB, 0x7A4 },
+	[ATHOS_B_5G_LUT_CHAN_587000_IDX] = { 23480, 0x0, 0x41, 0x71C72, 0x7A5 },
+	[ATHOS_B_5G_LUT_CHAN_587125_IDX] = { 23485, 0x0, 0x41, 0x78E39, 0x7A5 },
+	[ATHOS_B_5G_LUT_CHAN_587250_IDX] = { 23490, 0x0, 0x41, 0x80000, 0x7A6 },
+	[ATHOS_B_5G_LUT_CHAN_587375_IDX] = { 23495, 0x0, 0x41, 0x871C7, 0x7A6 },
+	[ATHOS_B_5G_LUT_CHAN_587500_IDX] = { 23500, 0x0, 0x41, 0x8E38E, 0x7A6 },
+	[ATHOS_B_5G_LUT_CHAN_587625_IDX] = { 23505, 0x0, 0x41, 0x95555, 0x7A7 },
+	[ATHOS_B_5G_LUT_CHAN_587750_IDX] = { 23510, 0x0, 0x41, 0x9C71C, 0x7A7 },
+	[ATHOS_B_5G_LUT_CHAN_587875_IDX] = { 23515, 0x0, 0x41, 0xA38E4, 0x7A8 },
+	[ATHOS_B_5G_LUT_CHAN_588000_IDX] = { 23520, 0x0, 0x41, 0xAAAAB, 0x7A8 },
+	[ATHOS_B_5G_LUT_CHAN_588125_IDX] = { 23525, 0x0, 0x41, 0xB1C72, 0x7A8 },
+	[ATHOS_B_5G_LUT_CHAN_588250_IDX] = { 23530, 0x0, 0x41, 0xB8E39, 0x7A9 },
+	[ATHOS_B_5G_LUT_CHAN_588375_IDX] = { 23535, 0x0, 0x41, 0xC0000, 0x7A9 },
+	[ATHOS_B_5G_LUT_CHAN_588500_IDX] = { 23540, 0x0, 0x41, 0xC71C7, 0x7AA },
+	[ATHOS_B_5G_LUT_CHAN_588625_IDX] = { 23545, 0x0, 0x41, 0xCE38E, 0x7AA },
+	[ATHOS_B_5G_LUT_CHAN_588750_IDX] = { 23550, 0x0, 0x41, 0xD5555, 0x7AB },
+	[ATHOS_B_5G_LUT_CHAN_588875_IDX] = { 23555, 0x0, 0x41, 0xDC71C, 0x7AB },
+	[ATHOS_B_5G_LUT_CHAN_589000_IDX] = { 23560, 0x0, 0x41, 0xE38E4, 0x7AB },
+	[ATHOS_B_5G_LUT_CHAN_589125_IDX] = { 23565, 0x0, 0x41, 0xEAAAB, 0x7AC },
+	[ATHOS_B_5G_LUT_CHAN_589250_IDX] = { 23570, 0x0, 0x41, 0xF1C72, 0x7AC },
+	[ATHOS_B_5G_LUT_CHAN_589375_IDX] = { 23575, 0x0, 0x41, 0xF8E39, 0x7AD },
+	[ATHOS_B_5G_LUT_CHAN_589500_IDX] = { 23580, 0x0, 0x41, 0x100000, 0x7AD },
+	[ATHOS_B_5G_LUT_CHAN_589625_IDX] = { 23585, 0x0, 0x41, 0x1071C7, 0x7AD },
+	[ATHOS_B_5G_LUT_CHAN_589750_IDX] = { 23590, 0x0, 0x41, 0x10E38E, 0x7AE },
+	[ATHOS_B_5G_LUT_CHAN_589875_IDX] = { 23595, 0x0, 0x41, 0x115555, 0x7AE },
+	[ATHOS_B_5G_LUT_CHAN_590000_IDX] = { 23600, 0x0, 0x41, 0x11C71C, 0x7AF },
+	[ATHOS_B_5G_LUT_CHAN_590125_IDX] = { 23605, 0x0, 0x41, 0x1238E4, 0x7AF },
+	[ATHOS_B_5G_LUT_CHAN_590250_IDX] = { 23610, 0x0, 0x41, 0x12AAAB, 0x7B0 },
+	[ATHOS_B_5G_LUT_CHAN_590375_IDX] = { 23615, 0x0, 0x41, 0x131C72, 0x7B0 },
+	[ATHOS_B_5G_LUT_CHAN_590500_IDX] = { 23620, 0x0, 0x41, 0x138E39, 0x7B0 },
+	[ATHOS_B_5G_LUT_CHAN_590625_IDX] = { 23625, 0x0, 0x41, 0x140000, 0x7B1 },
+	[ATHOS_B_5G_LUT_CHAN_590750_IDX] = { 23630, 0x0, 0x41, 0x1471C7, 0x7B1 },
+	[ATHOS_B_5G_LUT_CHAN_590875_IDX] = { 23635, 0x0, 0x41, 0x14E38E, 0x7B2 },
+	[ATHOS_B_5G_LUT_CHAN_591000_IDX] = { 23640, 0x0, 0x41, 0x155555, 0x7B2 },
+	[ATHOS_B_5G_LUT_CHAN_591125_IDX] = { 23645, 0x0, 0x41, 0x15C71C, 0x7B2 },
+	[ATHOS_B_5G_LUT_CHAN_591250_IDX] = { 23650, 0x0, 0x41, 0x1638E4, 0x7B3 },
+	[ATHOS_B_5G_LUT_CHAN_591375_IDX] = { 23655, 0x0, 0x41, 0x16AAAB, 0x7B3 },
+	[ATHOS_B_5G_LUT_CHAN_591500_IDX] = { 23660, 0x0, 0x41, 0x171C72, 0x7B4 },
+	[ATHOS_B_5G_LUT_CHAN_591625_IDX] = { 23665, 0x0, 0x41, 0x178E39, 0x7B4 },
+	[ATHOS_B_5G_LUT_CHAN_591750_IDX] = { 23670, 0x0, 0x41, 0x180000, 0x7B5 },
+	[ATHOS_B_5G_LUT_CHAN_591875_IDX] = { 23675, 0x0, 0x41, 0x1871C7, 0x7B5 },
+	[ATHOS_B_5G_LUT_CHAN_592000_IDX] = { 23680, 0x0, 0x41, 0x18E38E, 0x7B5 },
+	[ATHOS_B_5G_LUT_CHAN_592125_IDX] = { 23685, 0x0, 0x41, 0x195555, 0x7B6 },
+	[ATHOS_B_5G_LUT_CHAN_592250_IDX] = { 23690, 0x0, 0x41, 0x19C71C, 0x7B6 },
+	[ATHOS_B_5G_LUT_CHAN_592375_IDX] = { 23695, 0x0, 0x41, 0x1A38E4, 0x7B7 },
+	[ATHOS_B_5G_LUT_CHAN_592500_IDX] = { 23700, 0x0, 0x41, 0x1AAAAB, 0x7B7 },
+	[ATHOS_B_5G_LUT_CHAN_592625_IDX] = { 23705, 0x0, 0x41, 0x1B1C72, 0x7B7 },
+	[ATHOS_B_5G_LUT_CHAN_592750_IDX] = { 23710, 0x0, 0x41, 0x1B8E39, 0x7B8 },
+	[ATHOS_B_5G_LUT_CHAN_592875_IDX] = { 23715, 0x0, 0x41, 0x1C0000, 0x7B8 },
+	[ATHOS_B_5G_LUT_CHAN_593000_IDX] = { 23720, 0x0, 0x41, 0x1C71C7, 0x7B9 },
+	[ATHOS_B_5G_LUT_CHAN_593125_IDX] = { 23725, 0x0, 0x41, 0x1CE38E, 0x7B9 },
+	[ATHOS_B_5G_LUT_CHAN_593250_IDX] = { 23730, 0x0, 0x41, 0x1D5555, 0x7BA },
+	[ATHOS_B_5G_LUT_CHAN_593375_IDX] = { 23735, 0x0, 0x41, 0x1DC71C, 0x7BA },
+	[ATHOS_B_5G_LUT_CHAN_593500_IDX] = { 23740, 0x0, 0x41, 0x1E38E4, 0x7BA },
+	[ATHOS_B_5G_LUT_CHAN_593625_IDX] = { 23745, 0x0, 0x41, 0x1EAAAB, 0x7BB },
+	[ATHOS_B_5G_LUT_CHAN_593750_IDX] = { 23750, 0x0, 0x41, 0x1F1C72, 0x7BB },
+	[ATHOS_B_5G_LUT_CHAN_593875_IDX] = { 23755, 0x0, 0x41, 0x1F8E39, 0x7BC },
+	[ATHOS_B_5G_LUT_CHAN_594000_IDX] = { 23760, 0x0, 0x42, 0x0, 0x7BC },
+	[ATHOS_B_5G_LUT_CHAN_594125_IDX] = { 23765, 0x0, 0x42, 0x71C7, 0x7BC },
+	[ATHOS_B_5G_LUT_CHAN_594250_IDX] = { 23770, 0x0, 0x42, 0xE38E, 0x7BD },
+	[ATHOS_B_5G_LUT_CHAN_594375_IDX] = { 23775, 0x0, 0x42, 0x15555, 0x7BD },
+	[ATHOS_B_5G_LUT_CHAN_594500_IDX] = { 23780, 0x0, 0x42, 0x1C71C, 0x7BE },
+	[ATHOS_B_5G_LUT_CHAN_594625_IDX] = { 23785, 0x0, 0x42, 0x238E4, 0x7BE },
+	[ATHOS_B_5G_LUT_CHAN_594750_IDX] = { 23790, 0x0, 0x42, 0x2AAAB, 0x7BF },
+	[ATHOS_B_5G_LUT_CHAN_594875_IDX] = { 23795, 0x0, 0x42, 0x31C72, 0x7BF },
+	[ATHOS_B_5G_LUT_CHAN_595000_IDX] = { 23800, 0x0, 0x42, 0x38E39, 0x7BF }
+};
+
+const struct common_lut_line olympus_lut_5g_40_mhz[OLYMPUS_LUT_CHAN_5G_MAX] = {
+	[OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x56, 0x0, 0x6B8 },
+	[OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x56, 0xAAAB, 0x6B8 },
+	[OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x56, 0x15555, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x56, 0x20000, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x56, 0x2AAAB, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x56, 0x35555, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x56, 0x40000, 0x6BB },
+	[OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x56, 0x4AAAB, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x56, 0x55555, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x56, 0x60000, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x56, 0x6AAAB, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x56, 0x75555, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x56, 0x80000, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x56, 0x8AAAB, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x56, 0x95555, 0x6BE },
+	[OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x56, 0xA0000, 0x6BE },
+	[OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x1, 0x56, 0xAAAAB, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x1, 0x56, 0xB5555, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x1, 0x56, 0xC0000, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x1, 0x56, 0xCAAAB, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x1, 0x56, 0xD5555, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x1, 0x56, 0xE0000, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x1, 0x56, 0xEAAAB, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x1, 0x56, 0xF5555, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x1, 0x56, 0x100000, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x1, 0x56, 0x10AAAB, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x1, 0x56, 0x115555, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x1, 0x56, 0x120000, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x1, 0x56, 0x12AAAB, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x1, 0x56, 0x135555, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x1, 0x56, 0x140000, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x1, 0x56, 0x14AAAB, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x56, 0x155555, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x56, 0x160000, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x56, 0x16AAAB, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x56, 0x175555, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x56, 0x180000, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x56, 0x18AAAB, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x56, 0x195555, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x56, 0x1A0000, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x56, 0x1AAAAB, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x56, 0x1B5555, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x56, 0x1C0000, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x56, 0x1CAAAB, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x56, 0x1D5555, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x56, 0x1E0000, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x56, 0x1EAAAB, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x56, 0x1F5555, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x57, 0x0, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x57, 0xAAAB, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x57, 0x15555, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x57, 0x20000, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x57, 0x2AAAB, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x57, 0x35555, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x57, 0x40000, 0x6CF },
+	[OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x57, 0x4AAAB, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x57, 0x55555, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x57, 0x60000, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x57, 0x6AAAB, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x57, 0x75555, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x57, 0x80000, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x57, 0x8AAAB, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x57, 0x95555, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x57, 0xA0000, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x57, 0xAAAAB, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x57, 0xB5555, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x57, 0xC0000, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x57, 0xCAAAB, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x57, 0xD5555, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x57, 0xE0000, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x57, 0xEAAAB, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x57, 0xF5555, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x57, 0x100000, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x57, 0x10AAAB, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x57, 0x115555, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x57, 0x120000, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x57, 0x12AAAB, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x57, 0x135555, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x57, 0x140000, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x57, 0x14AAAB, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x57, 0x155555, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x57, 0x160000, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x57, 0x16AAAB, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x57, 0x175555, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x57, 0x180000, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x57, 0x18AAAB, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x57, 0x195555, 0x6DC },
+	[OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x57, 0x1A0000, 0x6DC },
+	[OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x57, 0x1AAAAB, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x57, 0x1B5555, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x57, 0x1C0000, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x57, 0x1CAAAB, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x57, 0x1D5555, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x57, 0x1E0000, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x57, 0x1EAAAB, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x57, 0x1F5555, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x58, 0x0, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x58, 0xAAAB, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x58, 0x15555, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x58, 0x20000, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x58, 0x2AAAB, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x58, 0x35555, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x58, 0x40000, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x58, 0x4AAAB, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x58, 0x55555, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x58, 0x60000, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x58, 0x6AAAB, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x58, 0x75555, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x58, 0x80000, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x58, 0x8AAAB, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x58, 0x95555, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x58, 0xA0000, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x58, 0xAAAAB, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x58, 0xB5555, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x58, 0xC0000, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x58, 0xCAAAB, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x58, 0xD5555, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x58, 0xE0000, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x58, 0xEAAAB, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x58, 0xF5555, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x58, 0x100000, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x58, 0x10AAAB, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x58, 0x115555, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x58, 0x120000, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x58, 0x12AAAB, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x58, 0x135555, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x58, 0x140000, 0x6ED },
+	[OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x58, 0x14AAAB, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x58, 0x155555, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x58, 0x160000, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x58, 0x16AAAB, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x58, 0x175555, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x58, 0x180000, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x58, 0x18AAAB, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x58, 0x195555, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x58, 0x1A0000, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x58, 0x1AAAAB, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x58, 0x1B5555, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x58, 0x1C0000, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x58, 0x1CAAAB, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x58, 0x1D5555, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x58, 0x1E0000, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x58, 0x1EAAAB, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x58, 0x1F5555, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x59, 0x0, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x59, 0xAAAB, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x59, 0x15555, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x59, 0x20000, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x59, 0x2AAAB, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x59, 0x35555, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x59, 0x40000, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x59, 0x4AAAB, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x59, 0x55555, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x59, 0x60000, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x59, 0x6AAAB, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x59, 0x75555, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x59, 0x80000, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x59, 0x8AAAB, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x59, 0x95555, 0x6FA },
+	[OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x59, 0xA0000, 0x6FA },
+	[OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x59, 0xAAAAB, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x59, 0xB5555, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x59, 0xC0000, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x59, 0xCAAAB, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x59, 0xD5555, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x59, 0xE0000, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x59, 0xEAAAB, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x59, 0xF5555, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x59, 0x100000, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x59, 0x10AAAB, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x59, 0x115555, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x59, 0x120000, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x59, 0x12AAAB, 0x700 },
+	[OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x59, 0x135555, 0x700 },
+	[OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x59, 0x140000, 0x701 },
+	[OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x59, 0x14AAAB, 0x701 },
+	[OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x59, 0x155555, 0x701 },
+	[OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x59, 0x160000, 0x702 },
+	[OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x59, 0x16AAAB, 0x702 },
+	[OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x59, 0x175555, 0x703 },
+	[OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x59, 0x180000, 0x703 },
+	[OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x59, 0x18AAAB, 0x703 },
+	[OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x59, 0x195555, 0x704 },
+	[OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x59, 0x1A0000, 0x704 },
+	[OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x59, 0x1AAAAB, 0x705 },
+	[OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x59, 0x1B5555, 0x705 },
+	[OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x59, 0x1C0000, 0x706 },
+	[OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x59, 0x1CAAAB, 0x706 },
+	[OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x59, 0x1D5555, 0x706 },
+	[OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x59, 0x1E0000, 0x707 },
+	[OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x59, 0x1EAAAB, 0x707 },
+	[OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x59, 0x1F5555, 0x708 },
+	[OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x5A, 0x0, 0x708 },
+	[OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x5A, 0xAAAB, 0x708 },
+	[OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x5A, 0x15555, 0x709 },
+	[OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x5A, 0x20000, 0x709 },
+	[OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x5A, 0x2AAAB, 0x70A },
+	[OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x5A, 0x35555, 0x70A },
+	[OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x5A, 0x40000, 0x70B },
+	[OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x5A, 0x4AAAB, 0x70B },
+	[OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x5A, 0x55555, 0x70B },
+	[OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x5A, 0x60000, 0x70C },
+	[OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x5A, 0x6AAAB, 0x70C },
+	[OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x5A, 0x75555, 0x70D },
+	[OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x5A, 0x80000, 0x70D },
+	[OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x5A, 0x8AAAB, 0x70D },
+	[OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x5A, 0x95555, 0x70E },
+	[OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x5A, 0xA0000, 0x70E },
+	[OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x5A, 0xAAAAB, 0x70F },
+	[OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x5A, 0xB5555, 0x70F },
+	[OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x5A, 0xC0000, 0x710 },
+	[OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x5A, 0xCAAAB, 0x710 },
+	[OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x5A, 0xD5555, 0x710 },
+	[OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x5A, 0xE0000, 0x711 },
+	[OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x5A, 0xEAAAB, 0x711 },
+	[OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x5A, 0xF5555, 0x712 },
+	[OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x5A, 0x100000, 0x712 },
+	[OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x5A, 0x10AAAB, 0x712 },
+	[OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x5A, 0x115555, 0x713 },
+	[OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x5A, 0x120000, 0x713 },
+	[OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x5A, 0x12AAAB, 0x714 },
+	[OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x5A, 0x135555, 0x714 },
+	[OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x5A, 0x140000, 0x715 },
+	[OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x5A, 0x14AAAB, 0x715 },
+	[OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x5A, 0x155555, 0x715 },
+	[OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x5A, 0x160000, 0x716 },
+	[OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x5A, 0x16AAAB, 0x716 },
+	[OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x5A, 0x175555, 0x717 },
+	[OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x5A, 0x180000, 0x717 },
+	[OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x5A, 0x18AAAB, 0x717 },
+	[OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x5A, 0x195555, 0x718 },
+	[OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x5A, 0x1A0000, 0x718 },
+	[OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x5A, 0x1AAAAB, 0x719 },
+	[OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x5A, 0x1B5555, 0x719 },
+	[OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x5A, 0x1C0000, 0x71A },
+	[OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x5A, 0x1CAAAB, 0x71A },
+	[OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x5A, 0x1D5555, 0x71A },
+	[OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x5A, 0x1E0000, 0x71B },
+	[OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x5A, 0x1EAAAB, 0x71B },
+	[OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x5A, 0x1F5555, 0x71C },
+	[OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x5B, 0x0, 0x71C },
+	[OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x5B, 0xAAAB, 0x71C },
+	[OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x5B, 0x15555, 0x71D },
+	[OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x5B, 0x20000, 0x71D },
+	[OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x5B, 0x2AAAB, 0x71E },
+	[OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x5B, 0x35555, 0x71E },
+	[OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x5B, 0x40000, 0x71F },
+	[OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x5B, 0x4AAAB, 0x71F },
+	[OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x5B, 0x55555, 0x71F },
+	[OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x5B, 0x60000, 0x720 },
+	[OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x5B, 0x6AAAB, 0x720 },
+	[OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x5B, 0x75555, 0x721 },
+	[OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x5B, 0x80000, 0x721 },
+	[OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x5B, 0x8AAAB, 0x721 },
+	[OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x5B, 0x95555, 0x722 },
+	[OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x5B, 0xA0000, 0x722 },
+	[OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x5B, 0xAAAAB, 0x723 },
+	[OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x5B, 0xB5555, 0x723 },
+	[OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x5B, 0xC0000, 0x724 },
+	[OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x5B, 0xCAAAB, 0x724 },
+	[OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x5B, 0xD5555, 0x724 },
+	[OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x5B, 0xE0000, 0x725 },
+	[OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x5B, 0xEAAAB, 0x725 },
+	[OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x5B, 0xF5555, 0x726 },
+	[OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x5B, 0x100000, 0x726 },
+	[OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x5B, 0x10AAAB, 0x726 },
+	[OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x5B, 0x115555, 0x727 },
+	[OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x5B, 0x120000, 0x727 },
+	[OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x5B, 0x12AAAB, 0x728 },
+	[OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x5B, 0x135555, 0x728 },
+	[OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x5B, 0x140000, 0x729 },
+	[OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x5B, 0x14AAAB, 0x729 },
+	[OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x5B, 0x155555, 0x729 },
+	[OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x5B, 0x160000, 0x72A },
+	[OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x5B, 0x16AAAB, 0x72A },
+	[OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x5B, 0x175555, 0x72B },
+	[OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x5B, 0x180000, 0x72B },
+	[OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x5B, 0x18AAAB, 0x72B },
+	[OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x5B, 0x195555, 0x72C },
+	[OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x5B, 0x1A0000, 0x72C },
+	[OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x5B, 0x1AAAAB, 0x72D },
+	[OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x5B, 0x1B5555, 0x72D },
+	[OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x5B, 0x1C0000, 0x72E },
+	[OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x5B, 0x1CAAAB, 0x72E },
+	[OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x5B, 0x1D5555, 0x72E },
+	[OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x5B, 0x1E0000, 0x72F },
+	[OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x5B, 0x1EAAAB, 0x72F },
+	[OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x5B, 0x1F5555, 0x730 },
+	[OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x5C, 0x0, 0x730 },
+	[OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x5C, 0xAAAB, 0x730 },
+	[OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x5C, 0x15555, 0x731 },
+	[OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x5C, 0x20000, 0x731 },
+	[OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x5C, 0x2AAAB, 0x732 },
+	[OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x5C, 0x35555, 0x732 },
+	[OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x5C, 0x40000, 0x733 },
+	[OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x5C, 0x4AAAB, 0x733 },
+	[OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x5C, 0x55555, 0x733 },
+	[OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x5C, 0x60000, 0x734 },
+	[OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x5C, 0x6AAAB, 0x734 },
+	[OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x5C, 0x75555, 0x735 },
+	[OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x5C, 0x80000, 0x735 },
+	[OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x5C, 0x8AAAB, 0x735 },
+	[OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x5C, 0x95555, 0x736 },
+	[OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x5C, 0xA0000, 0x736 },
+	[OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x5C, 0xAAAAB, 0x737 },
+	[OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x5C, 0xB5555, 0x737 },
+	[OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x5C, 0xC0000, 0x738 },
+	[OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x5C, 0xCAAAB, 0x738 },
+	[OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x5C, 0xD5555, 0x738 },
+	[OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x5C, 0xE0000, 0x739 },
+	[OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x5C, 0xEAAAB, 0x739 },
+	[OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x5C, 0xF5555, 0x73A },
+	[OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x5C, 0x100000, 0x73A },
+	[OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x5C, 0x10AAAB, 0x73A },
+	[OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x5C, 0x115555, 0x73B },
+	[OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x5C, 0x120000, 0x73B },
+	[OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x5C, 0x12AAAB, 0x73C },
+	[OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x5C, 0x135555, 0x73C },
+	[OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x5C, 0x140000, 0x73D },
+	[OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x5C, 0x14AAAB, 0x73D },
+	[OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x5C, 0x155555, 0x73D },
+	[OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x5C, 0x160000, 0x73E },
+	[OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x5C, 0x16AAAB, 0x73E },
+	[OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x5C, 0x175555, 0x73F },
+	[OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x5C, 0x180000, 0x73F },
+	[OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x5C, 0x18AAAB, 0x73F },
+	[OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x5C, 0x195555, 0x740 },
+	[OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x5C, 0x1A0000, 0x740 },
+	[OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x5C, 0x1AAAAB, 0x741 },
+	[OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x5C, 0x1B5555, 0x741 },
+	[OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x5C, 0x1C0000, 0x742 },
+	[OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x5C, 0x1CAAAB, 0x742 },
+	[OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x5C, 0x1D5555, 0x742 },
+	[OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x5C, 0x1E0000, 0x743 },
+	[OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x5C, 0x1EAAAB, 0x743 },
+	[OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x5C, 0x1F5555, 0x744 },
+	[OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x5D, 0x0, 0x744 },
+	[OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x5D, 0xAAAB, 0x744 },
+	[OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x5D, 0x15555, 0x745 },
+	[OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x5D, 0x20000, 0x745 },
+	[OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x5D, 0x2AAAB, 0x746 },
+	[OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x5D, 0x35555, 0x746 },
+	[OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x5D, 0x40000, 0x747 },
+	[OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x5D, 0x4AAAB, 0x747 },
+	[OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x5D, 0x55555, 0x747 },
+	[OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x5D, 0x60000, 0x748 },
+	[OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x5D, 0x6AAAB, 0x748 },
+	[OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x5D, 0x75555, 0x749 },
+	[OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x5D, 0x80000, 0x749 },
+	[OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x5D, 0x8AAAB, 0x749 },
+	[OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x5D, 0x95555, 0x74A },
+	[OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x5D, 0xA0000, 0x74A },
+	[OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x5D, 0xAAAAB, 0x74B },
+	[OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x5D, 0xB5555, 0x74B },
+	[OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x5D, 0xC0000, 0x74C },
+	[OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x5D, 0xCAAAB, 0x74C },
+	[OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x5D, 0xD5555, 0x74C },
+	[OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x5D, 0xE0000, 0x74D },
+	[OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x5D, 0xEAAAB, 0x74D },
+	[OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x5D, 0xF5555, 0x74E },
+	[OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x5D, 0x100000, 0x74E },
+	[OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x5D, 0x10AAAB, 0x74E },
+	[OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x5D, 0x115555, 0x74F },
+	[OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x5D, 0x120000, 0x74F },
+	[OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x5D, 0x12AAAB, 0x750 },
+	[OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x5D, 0x135555, 0x750 },
+	[OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x5D, 0x140000, 0x751 },
+	[OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x5D, 0x14AAAB, 0x751 },
+	[OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x5D, 0x155555, 0x751 },
+	[OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x5D, 0x160000, 0x752 },
+	[OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x5D, 0x16AAAB, 0x752 },
+	[OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x5D, 0x175555, 0x753 },
+	[OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x5D, 0x180000, 0x753 },
+	[OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x5D, 0x18AAAB, 0x753 },
+	[OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x5D, 0x195555, 0x754 },
+	[OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x5D, 0x1A0000, 0x754 },
+	[OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x5D, 0x1AAAAB, 0x755 },
+	[OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x5D, 0x1B5555, 0x755 },
+	[OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x5D, 0x1C0000, 0x756 },
+	[OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x5D, 0x1CAAAB, 0x756 },
+	[OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x5D, 0x1D5555, 0x756 },
+	[OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x5D, 0x1E0000, 0x757 },
+	[OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x5D, 0x1EAAAB, 0x757 },
+	[OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x5D, 0x1F5555, 0x758 },
+	[OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x5E, 0x0, 0x758 },
+	[OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x5E, 0xAAAB, 0x758 },
+	[OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x5E, 0x15555, 0x759 },
+	[OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x5E, 0x20000, 0x759 },
+	[OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x5E, 0x2AAAB, 0x75A },
+	[OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x5E, 0x35555, 0x75A },
+	[OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x5E, 0x40000, 0x75B },
+	[OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x5E, 0x4AAAB, 0x75B },
+	[OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x5E, 0x55555, 0x75B },
+	[OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x5E, 0x60000, 0x75C },
+	[OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x5E, 0x6AAAB, 0x75C },
+	[OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x5E, 0x75555, 0x75D },
+	[OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x5E, 0x80000, 0x75D },
+	[OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x5E, 0x8AAAB, 0x75D },
+	[OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x5E, 0x95555, 0x75E },
+	[OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x5E, 0xA0000, 0x75E },
+	[OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x5E, 0xAAAAB, 0x75F },
+	[OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x5E, 0xB5555, 0x75F },
+	[OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x5E, 0xC0000, 0x760 },
+	[OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x5E, 0xCAAAB, 0x760 },
+	[OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x5E, 0xD5555, 0x760 },
+	[OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x5E, 0xE0000, 0x761 },
+	[OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x5E, 0xEAAAB, 0x761 },
+	[OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x5E, 0xF5555, 0x762 },
+	[OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x5E, 0x100000, 0x762 },
+	[OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x5E, 0x10AAAB, 0x762 },
+	[OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x5E, 0x115555, 0x763 },
+	[OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x5E, 0x120000, 0x763 },
+	[OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x5E, 0x12AAAB, 0x764 },
+	[OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x5E, 0x135555, 0x764 },
+	[OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x5E, 0x140000, 0x765 },
+	[OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x5E, 0x14AAAB, 0x765 },
+	[OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x5E, 0x155555, 0x765 },
+	[OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x5E, 0x160000, 0x766 },
+	[OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x5E, 0x16AAAB, 0x766 },
+	[OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x5E, 0x175555, 0x767 },
+	[OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x5E, 0x180000, 0x767 },
+	[OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x5E, 0x18AAAB, 0x767 },
+	[OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x5E, 0x195555, 0x768 },
+	[OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x5E, 0x1A0000, 0x768 },
+	[OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x5E, 0x1AAAAB, 0x769 },
+	[OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x5E, 0x1B5555, 0x769 },
+	[OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x5E, 0x1C0000, 0x76A },
+	[OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x5E, 0x1CAAAB, 0x76A },
+	[OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x5E, 0x1D5555, 0x76A },
+	[OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x5E, 0x1E0000, 0x76B },
+	[OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x5E, 0x1EAAAB, 0x76B },
+	[OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x5E, 0x1F5555, 0x76C },
+	[OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x5F, 0x0, 0x76C },
+	[OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x5F, 0xAAAB, 0x76C },
+	[OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x5F, 0x15555, 0x76D },
+	[OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x5F, 0x20000, 0x76D },
+	[OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x5F, 0x2AAAB, 0x76E },
+	[OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x5F, 0x35555, 0x76E },
+	[OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x5F, 0x40000, 0x76F },
+	[OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x5F, 0x4AAAB, 0x76F },
+	[OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x5F, 0x55555, 0x76F },
+	[OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x5F, 0x60000, 0x770 },
+	[OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x5F, 0x6AAAB, 0x770 },
+	[OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x5F, 0x75555, 0x771 },
+	[OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x5F, 0x80000, 0x771 },
+	[OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x5F, 0x8AAAB, 0x771 },
+	[OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x5F, 0x95555, 0x772 },
+	[OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x5F, 0xA0000, 0x772 },
+	[OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x5F, 0xAAAAB, 0x773 },
+	[OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x5F, 0xB5555, 0x773 },
+	[OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x5F, 0xC0000, 0x774 },
+	[OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x5F, 0xCAAAB, 0x774 },
+	[OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x5F, 0xD5555, 0x774 },
+	[OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x5F, 0xE0000, 0x775 },
+	[OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x5F, 0xEAAAB, 0x775 },
+	[OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x5F, 0xF5555, 0x776 },
+	[OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x5F, 0x100000, 0x776 },
+	[OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x5F, 0x10AAAB, 0x776 },
+	[OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x5F, 0x115555, 0x777 },
+	[OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x5F, 0x120000, 0x777 },
+	[OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x5F, 0x12AAAB, 0x778 },
+	[OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x5F, 0x135555, 0x778 },
+	[OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x5F, 0x140000, 0x779 },
+	[OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x5F, 0x14AAAB, 0x779 },
+	[OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x5F, 0x155555, 0x779 },
+	[OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x5F, 0x160000, 0x77A },
+	[OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x5F, 0x16AAAB, 0x77A },
+	[OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x5F, 0x175555, 0x77B },
+	[OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x5F, 0x180000, 0x77B },
+	[OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x5F, 0x18AAAB, 0x77B },
+	[OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x5F, 0x195555, 0x77C },
+	[OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x5F, 0x1A0000, 0x77C },
+	[OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x5F, 0x1AAAAB, 0x77D },
+	[OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x5F, 0x1B5555, 0x77D },
+	[OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x5F, 0x1C0000, 0x77E },
+	[OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x5F, 0x1CAAAB, 0x77E },
+	[OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x5F, 0x1D5555, 0x77E },
+	[OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x5F, 0x1E0000, 0x77F },
+	[OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x5F, 0x1EAAAB, 0x77F },
+	[OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x5F, 0x1F5555, 0x780 },
+	[OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x60, 0x0, 0x780 },
+	[OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x60, 0xAAAB, 0x780 },
+	[OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x60, 0x15555, 0x781 },
+	[OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x60, 0x20000, 0x781 },
+	[OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x60, 0x2AAAB, 0x782 },
+	[OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x60, 0x35555, 0x782 },
+	[OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x60, 0x40000, 0x783 },
+	[OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x60, 0x4AAAB, 0x783 },
+	[OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x60, 0x55555, 0x783 },
+	[OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x60, 0x60000, 0x784 },
+	[OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x60, 0x6AAAB, 0x784 },
+	[OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x60, 0x75555, 0x785 },
+	[OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x60, 0x80000, 0x785 },
+	[OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x60, 0x8AAAB, 0x785 },
+	[OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x60, 0x95555, 0x786 },
+	[OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x60, 0xA0000, 0x786 },
+	[OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x60, 0xAAAAB, 0x787 },
+	[OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x60, 0xB5555, 0x787 },
+	[OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x60, 0xC0000, 0x788 },
+	[OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x60, 0xCAAAB, 0x788 },
+	[OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x60, 0xD5555, 0x788 },
+	[OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x60, 0xE0000, 0x789 },
+	[OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x60, 0xEAAAB, 0x789 },
+	[OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x60, 0xF5555, 0x78A },
+	[OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x60, 0x100000, 0x78A },
+	[OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x60, 0x10AAAB, 0x78A },
+	[OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x60, 0x115555, 0x78B },
+	[OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x60, 0x120000, 0x78B },
+	[OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x60, 0x12AAAB, 0x78C },
+	[OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x60, 0x135555, 0x78C },
+	[OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x60, 0x140000, 0x78D },
+	[OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x60, 0x14AAAB, 0x78D },
+	[OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x60, 0x155555, 0x78D },
+	[OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x60, 0x160000, 0x78E },
+	[OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x60, 0x16AAAB, 0x78E },
+	[OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x60, 0x175555, 0x78F },
+	[OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x60, 0x180000, 0x78F },
+	[OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x60, 0x18AAAB, 0x78F },
+	[OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x60, 0x195555, 0x790 },
+	[OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x60, 0x1A0000, 0x790 },
+	[OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x60, 0x1AAAAB, 0x791 },
+	[OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x60, 0x1B5555, 0x791 },
+	[OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x60, 0x1C0000, 0x792 },
+	[OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x60, 0x1CAAAB, 0x792 },
+	[OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x60, 0x1D5555, 0x792 },
+	[OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x60, 0x1E0000, 0x793 },
+	[OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x60, 0x1EAAAB, 0x793 },
+	[OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x60, 0x1F5555, 0x794 },
+	[OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x61, 0x0, 0x794 },
+	[OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x61, 0xAAAB, 0x794 },
+	[OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x61, 0x15555, 0x795 },
+	[OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x61, 0x20000, 0x795 },
+	[OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x61, 0x2AAAB, 0x796 },
+	[OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x61, 0x35555, 0x796 },
+	[OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x61, 0x40000, 0x797 },
+	[OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x61, 0x4AAAB, 0x797 },
+	[OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x61, 0x55555, 0x797 },
+	[OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x61, 0x60000, 0x798 },
+	[OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x61, 0x6AAAB, 0x798 },
+	[OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x61, 0x75555, 0x799 },
+	[OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x61, 0x80000, 0x799 },
+	[OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x61, 0x8AAAB, 0x799 },
+	[OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x61, 0x95555, 0x79A },
+	[OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x61, 0xA0000, 0x79A },
+	[OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x61, 0xAAAAB, 0x79B },
+	[OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x61, 0xB5555, 0x79B },
+	[OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x61, 0xC0000, 0x79C },
+	[OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x61, 0xCAAAB, 0x79C },
+	[OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x61, 0xD5555, 0x79C },
+	[OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x61, 0xE0000, 0x79D },
+	[OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x61, 0xEAAAB, 0x79D },
+	[OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x61, 0xF5555, 0x79E },
+	[OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x61, 0x100000, 0x79E },
+	[OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x61, 0x10AAAB, 0x79E },
+	[OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x61, 0x115555, 0x79F },
+	[OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x61, 0x120000, 0x79F },
+	[OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x61, 0x12AAAB, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x61, 0x135555, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x61, 0x140000, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x61, 0x14AAAB, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x61, 0x155555, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x61, 0x160000, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x61, 0x16AAAB, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x61, 0x175555, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x61, 0x180000, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x61, 0x18AAAB, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x61, 0x195555, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x61, 0x1A0000, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x61, 0x1AAAAB, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x61, 0x1B5555, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x61, 0x1C0000, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x61, 0x1CAAAB, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x61, 0x1D5555, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x61, 0x1E0000, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x61, 0x1EAAAB, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x61, 0x1F5555, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x62, 0x0, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x62, 0xAAAB, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x62, 0x15555, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x62, 0x20000, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x62, 0x2AAAB, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x62, 0x35555, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x62, 0x40000, 0x7AB },
+	[OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x62, 0x4AAAB, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x62, 0x55555, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x62, 0x60000, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x62, 0x6AAAB, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x62, 0x75555, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x62, 0x80000, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x62, 0x8AAAB, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x62, 0x95555, 0x7AE },
+	[OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x62, 0xA0000, 0x7AE },
+	[OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x62, 0xAAAAB, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x62, 0xB5555, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x62, 0xC0000, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x62, 0xCAAAB, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x62, 0xD5555, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x62, 0xE0000, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x62, 0xEAAAB, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x62, 0xF5555, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x62, 0x100000, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x62, 0x10AAAB, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x62, 0x115555, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x62, 0x120000, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x62, 0x12AAAB, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x62, 0x135555, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x62, 0x140000, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x62, 0x14AAAB, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x62, 0x155555, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x62, 0x160000, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x62, 0x16AAAB, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x62, 0x175555, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x62, 0x180000, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x62, 0x18AAAB, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x62, 0x195555, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x62, 0x1A0000, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x62, 0x1AAAAB, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x62, 0x1B5555, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x62, 0x1C0000, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x62, 0x1CAAAB, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x62, 0x1D5555, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x62, 0x1E0000, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x62, 0x1EAAAB, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x62, 0x1F5555, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x63, 0x0, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x63, 0xAAAB, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x63, 0x15555, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x63, 0x20000, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x63, 0x2AAAB, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x63, 0x35555, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x63, 0x40000, 0x7BF },
+	[OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x63, 0x4AAAB, 0x7BF },
+	[OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x63, 0x55555, 0x7BF },
+	[OLYMPUS_LUT_CHAN_595125_IDX] = { 23805, 0x1, 0x63, 0x60000, 0x7C0 },
+	[OLYMPUS_LUT_CHAN_595250_IDX] = { 23810, 0x1, 0x63, 0x6AAAB, 0x7C0 },
+	[OLYMPUS_LUT_CHAN_595375_IDX] = { 23815, 0x1, 0x63, 0x75555, 0x7C1 },
+	[OLYMPUS_LUT_CHAN_595500_IDX] = { 23820, 0x1, 0x63, 0x80000, 0x7C1 },
+	[OLYMPUS_LUT_CHAN_595625_IDX] = { 23825, 0x1, 0x63, 0x8AAAB, 0x7C1 },
+	[OLYMPUS_LUT_CHAN_595750_IDX] = { 23830, 0x1, 0x63, 0x95555, 0x7C2 },
+	[OLYMPUS_LUT_CHAN_595875_IDX] = { 23835, 0x1, 0x63, 0xA0000, 0x7C2 },
+	[OLYMPUS_LUT_CHAN_596000_IDX] = { 23840, 0x1, 0x63, 0xAAAAB, 0x7C3 },
+	[OLYMPUS_LUT_CHAN_596125_IDX] = { 23845, 0x1, 0x63, 0xB5555, 0x7C3 },
+	[OLYMPUS_LUT_CHAN_596250_IDX] = { 23850, 0x1, 0x63, 0xC0000, 0x7C4 },
+	[OLYMPUS_LUT_CHAN_596375_IDX] = { 23855, 0x1, 0x63, 0xCAAAB, 0x7C4 },
+	[OLYMPUS_LUT_CHAN_596500_IDX] = { 23860, 0x1, 0x63, 0xD5555, 0x7C4 },
+	[OLYMPUS_LUT_CHAN_596625_IDX] = { 23865, 0x1, 0x63, 0xE0000, 0x7C5 },
+	[OLYMPUS_LUT_CHAN_596750_IDX] = { 23870, 0x1, 0x63, 0xEAAAB, 0x7C5 },
+	[OLYMPUS_LUT_CHAN_596875_IDX] = { 23875, 0x1, 0x63, 0xF5555, 0x7C6 },
+	[OLYMPUS_LUT_CHAN_597000_IDX] = { 23880, 0x1, 0x63, 0x100000, 0x7C6 },
+	[OLYMPUS_LUT_CHAN_597125_IDX] = { 23885, 0x1, 0x63, 0x10AAAB, 0x7C6 },
+	[OLYMPUS_LUT_CHAN_597250_IDX] = { 23890, 0x1, 0x63, 0x115555, 0x7C7 },
+	[OLYMPUS_LUT_CHAN_597375_IDX] = { 23895, 0x1, 0x63, 0x120000, 0x7C7 },
+	[OLYMPUS_LUT_CHAN_597500_IDX] = { 23900, 0x1, 0x63, 0x12AAAB, 0x7C8 },
+	[OLYMPUS_LUT_CHAN_597625_IDX] = { 23905, 0x1, 0x63, 0x135555, 0x7C8 },
+	[OLYMPUS_LUT_CHAN_597750_IDX] = { 23910, 0x1, 0x63, 0x140000, 0x7C9 },
+	[OLYMPUS_LUT_CHAN_597875_IDX] = { 23915, 0x1, 0x63, 0x14AAAB, 0x7C9 },
+	[OLYMPUS_LUT_CHAN_598000_IDX] = { 23920, 0x1, 0x63, 0x155555, 0x7C9 },
+	[OLYMPUS_LUT_CHAN_598125_IDX] = { 23925, 0x1, 0x63, 0x160000, 0x7CA },
+	[OLYMPUS_LUT_CHAN_598250_IDX] = { 23930, 0x1, 0x63, 0x16AAAB, 0x7CA },
+	[OLYMPUS_LUT_CHAN_598375_IDX] = { 23935, 0x1, 0x63, 0x175555, 0x7CB },
+	[OLYMPUS_LUT_CHAN_598500_IDX] = { 23940, 0x1, 0x63, 0x180000, 0x7CB },
+	[OLYMPUS_LUT_CHAN_598625_IDX] = { 23945, 0x1, 0x63, 0x18AAAB, 0x7CB },
+	[OLYMPUS_LUT_CHAN_598750_IDX] = { 23950, 0x1, 0x63, 0x195555, 0x7CC },
+	[OLYMPUS_LUT_CHAN_598875_IDX] = { 23955, 0x1, 0x63, 0x1A0000, 0x7CC },
+	[OLYMPUS_LUT_CHAN_599000_IDX] = { 23960, 0x1, 0x63, 0x1AAAAB, 0x7CD },
+	[OLYMPUS_LUT_CHAN_599125_IDX] = { 23965, 0x1, 0x63, 0x1B5555, 0x7CD },
+	[OLYMPUS_LUT_CHAN_599250_IDX] = { 23970, 0x1, 0x63, 0x1C0000, 0x7CE },
+	[OLYMPUS_LUT_CHAN_599375_IDX] = { 23975, 0x1, 0x63, 0x1CAAAB, 0x7CE },
+	[OLYMPUS_LUT_CHAN_599500_IDX] = { 23980, 0x1, 0x63, 0x1D5555, 0x7CE },
+	[OLYMPUS_LUT_CHAN_599625_IDX] = { 23985, 0x1, 0x63, 0x1E0000, 0x7CF },
+	[OLYMPUS_LUT_CHAN_599750_IDX] = { 23990, 0x1, 0x63, 0x1EAAAB, 0x7CF },
+	[OLYMPUS_LUT_CHAN_599875_IDX] = { 23995, 0x1, 0x63, 0x1F5555, 0x7D0 },
+	[OLYMPUS_LUT_CHAN_600000_IDX] = { 24000, 0x1, 0x64, 0x0, 0x7D0 }
+};
+
+const struct common_lut_line olympus_lut_5g_60_mhz_s1[OLYMPUS_LUT_CHAN_5G_MAX] = {
+	[OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x39, 0x11C71C, 0x6BF },
+	[OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x39, 0xB1C72, 0x6B8 },
+	[OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x39, 0xB8E39, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x39, 0xC0000, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x39, 0xC71C7, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x39, 0xCE38E, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x39, 0xD5555, 0x6BB },
+	[OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x39, 0xDC71C, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x39, 0xE38E4, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x39, 0xEAAAB, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x39, 0xF1C72, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x39, 0xF8E39, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x39, 0x100000, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x39, 0x1071C7, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x39, 0x10E38E, 0x6BE },
+	[OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x39, 0x115555, 0x6BE },
+	[OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x1, 0x39, 0x11C71C, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x1, 0x39, 0x1238E4, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x1, 0x39, 0x12AAAB, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x1, 0x39, 0x131C72, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x1, 0x39, 0x138E39, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x1, 0x39, 0x140000, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x1, 0x39, 0x1471C7, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x1, 0x39, 0x14E38E, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x1, 0x39, 0x155555, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x1, 0x39, 0x15C71C, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x1, 0x39, 0x1638E4, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x1, 0x39, 0x16AAAB, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x1, 0x39, 0x171C72, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x1, 0x39, 0x178E39, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x1, 0x39, 0x180000, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x1, 0x39, 0x1871C7, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x39, 0x18E38E, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x39, 0x195555, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x39, 0x19C71C, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x39, 0x1A38E4, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x39, 0x1AAAAB, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x39, 0x1B1C72, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x39, 0x1B8E39, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x39, 0x1C0000, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x39, 0x1C71C7, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x39, 0x1CE38E, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x39, 0x1D5555, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x39, 0x1DC71C, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x39, 0x1E38E4, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x39, 0x1EAAAB, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x39, 0x1F1C72, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x39, 0x1F8E39, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x3A, 0x0, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x3A, 0x71C7, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x3A, 0xE38E, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x3A, 0x15555, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x3A, 0x1C71C, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x3A, 0x238E4, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x3A, 0x2AAAB, 0x6CF },
+	[OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x3A, 0x31C72, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x3A, 0x38E39, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x3A, 0x40000, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x3A, 0x471C7, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x3A, 0x4E38E, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x3A, 0x55555, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x3A, 0x5C71C, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x3A, 0x638E4, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x3A, 0x6AAAB, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x3A, 0x71C72, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x3A, 0x78E39, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x3A, 0x80000, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x3A, 0x871C7, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x3A, 0x8E38E, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x3A, 0x95555, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x3A, 0x9C71C, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x3A, 0xA38E4, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x3A, 0xAAAAB, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x3A, 0xB1C72, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x3A, 0xB8E39, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x3A, 0xC0000, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x3A, 0xC71C7, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x3A, 0xCE38E, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x3A, 0xD5555, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x3A, 0xDC71C, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x3A, 0xE38E4, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x3A, 0xEAAAB, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x3A, 0xF1C72, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x3A, 0xF8E39, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x3A, 0x100000, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x3A, 0x1071C7, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x3A, 0x10E38E, 0x6DC },
+	[OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x3A, 0x115555, 0x6DC },
+	[OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x3A, 0x11C71C, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x3A, 0x1238E4, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x3A, 0x12AAAB, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x3A, 0x131C72, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x3A, 0x138E39, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x3A, 0x140000, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x3A, 0x1471C7, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x3A, 0x14E38E, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x3A, 0x155555, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x3A, 0x15C71C, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x3A, 0x1638E4, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x3A, 0x16AAAB, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x3A, 0x171C72, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x3A, 0x178E39, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x3A, 0x180000, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x3A, 0x1871C7, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x3A, 0x18E38E, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x3A, 0x195555, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x3A, 0x19C71C, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x3A, 0x1A38E4, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x3A, 0x1AAAAB, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x3A, 0x1B1C72, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x3A, 0x1B8E39, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x3A, 0x1C0000, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x3A, 0x1C71C7, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x3A, 0x1CE38E, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x3A, 0x1D5555, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x3A, 0x1DC71C, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x3A, 0x1E38E4, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x3A, 0x1EAAAB, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x3A, 0x1F1C72, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x3A, 0x1F8E39, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x3B, 0x0, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x3B, 0x71C7, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x3B, 0xE38E, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x3B, 0x15555, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x3B, 0x1C71C, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x3B, 0x238E4, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x3B, 0x2AAAB, 0x6ED },
+	[OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x3B, 0x31C72, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x3B, 0x38E39, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x3B, 0x40000, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x3B, 0x471C7, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x3B, 0x4E38E, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x3B, 0x55555, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x3B, 0x5C71C, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x3B, 0x638E4, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x3B, 0x6AAAB, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x3B, 0x71C72, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x3B, 0x78E39, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x3B, 0x80000, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x3B, 0x871C7, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x3B, 0x8E38E, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x3B, 0x95555, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x3B, 0x9C71C, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x3B, 0xA38E4, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x3B, 0xAAAAB, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x3B, 0xB1C72, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x3B, 0xB8E39, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x3B, 0xC0000, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x3B, 0xC71C7, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x3B, 0xCE38E, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x3B, 0xD5555, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x3B, 0xDC71C, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x3B, 0xE38E4, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x3B, 0xEAAAB, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x3B, 0xF1C72, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x3B, 0xF8E39, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x3B, 0x100000, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x3B, 0x1071C7, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x3B, 0x10E38E, 0x6FA },
+	[OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x3B, 0x115555, 0x6FA },
+	[OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x3B, 0x11C71C, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x3B, 0x1238E4, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x3B, 0x12AAAB, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x3B, 0x131C72, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x3B, 0x138E39, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x3B, 0x140000, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x3B, 0x1471C7, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x3B, 0x14E38E, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x3B, 0x155555, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x3B, 0x15C71C, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x3B, 0x1638E4, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x3B, 0x16AAAB, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x3B, 0x171C72, 0x700 },
+	[OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x3B, 0x178E39, 0x700 },
+	[OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x3B, 0x180000, 0x701 },
+	[OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x3B, 0x1871C7, 0x701 },
+	[OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x3B, 0x18E38E, 0x701 },
+	[OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x3B, 0x195555, 0x702 },
+	[OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x3B, 0x19C71C, 0x702 },
+	[OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x3B, 0x1A38E4, 0x703 },
+	[OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x3B, 0x1AAAAB, 0x703 },
+	[OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x3B, 0x1B1C72, 0x703 },
+	[OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x3B, 0x1B8E39, 0x704 },
+	[OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x3B, 0x1C0000, 0x704 },
+	[OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x3B, 0x1C71C7, 0x705 },
+	[OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x3B, 0x1CE38E, 0x705 },
+	[OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x3B, 0x1D5555, 0x706 },
+	[OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x3B, 0x1DC71C, 0x706 },
+	[OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x3B, 0x1E38E4, 0x706 },
+	[OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x3B, 0x1EAAAB, 0x707 },
+	[OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x3B, 0x1F1C72, 0x707 },
+	[OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x3B, 0x1F8E39, 0x708 },
+	[OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x3C, 0x0, 0x708 },
+	[OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x3C, 0x71C7, 0x708 },
+	[OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x3C, 0xE38E, 0x709 },
+	[OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x3C, 0x15555, 0x709 },
+	[OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x3C, 0x1C71C, 0x70A },
+	[OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x3C, 0x238E4, 0x70A },
+	[OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x3C, 0x2AAAB, 0x70B },
+	[OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x3C, 0x31C72, 0x70B },
+	[OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x3C, 0x38E39, 0x70B },
+	[OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x3C, 0x40000, 0x70C },
+	[OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x3C, 0x471C7, 0x70C },
+	[OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x3C, 0x4E38E, 0x70D },
+	[OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x3C, 0x55555, 0x70D },
+	[OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x3C, 0x5C71C, 0x70D },
+	[OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x3C, 0x638E4, 0x70E },
+	[OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x3C, 0x6AAAB, 0x70E },
+	[OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x3C, 0x71C72, 0x70F },
+	[OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x3C, 0x78E39, 0x70F },
+	[OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x3C, 0x80000, 0x710 },
+	[OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x3C, 0x871C7, 0x710 },
+	[OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x3C, 0x8E38E, 0x710 },
+	[OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x3C, 0x95555, 0x711 },
+	[OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x3C, 0x9C71C, 0x711 },
+	[OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x3C, 0xA38E4, 0x712 },
+	[OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x3C, 0xAAAAB, 0x712 },
+	[OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x3C, 0xB1C72, 0x712 },
+	[OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x3C, 0xB8E39, 0x713 },
+	[OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x3C, 0xC0000, 0x713 },
+	[OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x3C, 0xC71C7, 0x714 },
+	[OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x3C, 0xCE38E, 0x714 },
+	[OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x3C, 0xD5555, 0x715 },
+	[OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x3C, 0xDC71C, 0x715 },
+	[OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x3C, 0xE38E4, 0x715 },
+	[OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x3C, 0xEAAAB, 0x716 },
+	[OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x3C, 0xF1C72, 0x716 },
+	[OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x3C, 0xF8E39, 0x717 },
+	[OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x3C, 0x100000, 0x717 },
+	[OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x3C, 0x1071C7, 0x717 },
+	[OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x3C, 0x10E38E, 0x718 },
+	[OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x3C, 0x115555, 0x718 },
+	[OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x3C, 0x11C71C, 0x719 },
+	[OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x3C, 0x1238E4, 0x719 },
+	[OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x3C, 0x12AAAB, 0x71A },
+	[OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x3C, 0x131C72, 0x71A },
+	[OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x3C, 0x138E39, 0x71A },
+	[OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x3C, 0x140000, 0x71B },
+	[OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x3C, 0x1471C7, 0x71B },
+	[OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x3C, 0x14E38E, 0x71C },
+	[OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x3C, 0x155555, 0x71C },
+	[OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x3C, 0x15C71C, 0x71C },
+	[OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x3C, 0x1638E4, 0x71D },
+	[OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x3C, 0x16AAAB, 0x71D },
+	[OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x3C, 0x171C72, 0x71E },
+	[OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x3C, 0x178E39, 0x71E },
+	[OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x3C, 0x180000, 0x71F },
+	[OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x3C, 0x1871C7, 0x71F },
+	[OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x3C, 0x18E38E, 0x71F },
+	[OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x3C, 0x195555, 0x720 },
+	[OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x3C, 0x19C71C, 0x720 },
+	[OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x3C, 0x1A38E4, 0x721 },
+	[OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x3C, 0x1AAAAB, 0x721 },
+	[OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x3C, 0x1B1C72, 0x721 },
+	[OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x3C, 0x1B8E39, 0x722 },
+	[OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x3C, 0x1C0000, 0x722 },
+	[OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x3C, 0x1C71C7, 0x723 },
+	[OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x3C, 0x1CE38E, 0x723 },
+	[OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x3C, 0x1D5555, 0x724 },
+	[OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x3C, 0x1DC71C, 0x724 },
+	[OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x3C, 0x1E38E4, 0x724 },
+	[OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x3C, 0x1EAAAB, 0x725 },
+	[OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x3C, 0x1F1C72, 0x725 },
+	[OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x3C, 0x1F8E39, 0x726 },
+	[OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x3D, 0x0, 0x726 },
+	[OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x3D, 0x71C7, 0x726 },
+	[OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x3D, 0xE38E, 0x727 },
+	[OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x3D, 0x15555, 0x727 },
+	[OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x3D, 0x1C71C, 0x728 },
+	[OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x3D, 0x238E4, 0x728 },
+	[OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x3D, 0x2AAAB, 0x729 },
+	[OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x3D, 0x31C72, 0x729 },
+	[OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x3D, 0x38E39, 0x729 },
+	[OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x3D, 0x40000, 0x72A },
+	[OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x3D, 0x471C7, 0x72A },
+	[OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x3D, 0x4E38E, 0x72B },
+	[OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x3D, 0x55555, 0x72B },
+	[OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x3D, 0x5C71C, 0x72B },
+	[OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x3D, 0x638E4, 0x72C },
+	[OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x3D, 0x6AAAB, 0x72C },
+	[OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x3D, 0x71C72, 0x72D },
+	[OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x3D, 0x78E39, 0x72D },
+	[OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x3D, 0x80000, 0x72E },
+	[OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x3D, 0x871C7, 0x72E },
+	[OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x3D, 0x8E38E, 0x72E },
+	[OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x3D, 0x95555, 0x72F },
+	[OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x3D, 0x9C71C, 0x72F },
+	[OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x3D, 0xA38E4, 0x730 },
+	[OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x3D, 0xAAAAB, 0x730 },
+	[OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x3D, 0xB1C72, 0x730 },
+	[OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x3D, 0xB8E39, 0x731 },
+	[OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x3D, 0xC0000, 0x731 },
+	[OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x3D, 0xC71C7, 0x732 },
+	[OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x3D, 0xCE38E, 0x732 },
+	[OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x3D, 0xD5555, 0x733 },
+	[OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x3D, 0xDC71C, 0x733 },
+	[OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x3D, 0xE38E4, 0x733 },
+	[OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x3D, 0xEAAAB, 0x734 },
+	[OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x3D, 0xF1C72, 0x734 },
+	[OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x3D, 0xF8E39, 0x735 },
+	[OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x3D, 0x100000, 0x735 },
+	[OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x3D, 0x1071C7, 0x735 },
+	[OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x3D, 0x10E38E, 0x736 },
+	[OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x3D, 0x115555, 0x736 },
+	[OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x3D, 0x11C71C, 0x737 },
+	[OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x3D, 0x1238E4, 0x737 },
+	[OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x3D, 0x12AAAB, 0x738 },
+	[OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x3D, 0x131C72, 0x738 },
+	[OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x3D, 0x138E39, 0x738 },
+	[OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x3D, 0x140000, 0x739 },
+	[OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x3D, 0x1471C7, 0x739 },
+	[OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x3D, 0x14E38E, 0x73A },
+	[OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x3D, 0x155555, 0x73A },
+	[OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x3D, 0x15C71C, 0x73A },
+	[OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x3D, 0x1638E4, 0x73B },
+	[OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x3D, 0x16AAAB, 0x73B },
+	[OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x3D, 0x171C72, 0x73C },
+	[OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x3D, 0x178E39, 0x73C },
+	[OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x3D, 0x180000, 0x73D },
+	[OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x3D, 0x1871C7, 0x73D },
+	[OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x3D, 0x18E38E, 0x73D },
+	[OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x3D, 0x195555, 0x73E },
+	[OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x3D, 0x19C71C, 0x73E },
+	[OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x3D, 0x1A38E4, 0x73F },
+	[OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x3D, 0x1AAAAB, 0x73F },
+	[OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x3D, 0x1B1C72, 0x73F },
+	[OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x3D, 0x1B8E39, 0x740 },
+	[OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x3D, 0x1C0000, 0x740 },
+	[OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x3D, 0x1C71C7, 0x741 },
+	[OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x3D, 0x1CE38E, 0x741 },
+	[OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x3D, 0x1D5555, 0x742 },
+	[OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x3D, 0x1DC71C, 0x742 },
+	[OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x3D, 0x1E38E4, 0x742 },
+	[OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x3D, 0x1EAAAB, 0x743 },
+	[OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x3D, 0x1F1C72, 0x743 },
+	[OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x3D, 0x1F8E39, 0x744 },
+	[OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x3E, 0x0, 0x744 },
+	[OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x3E, 0x71C7, 0x744 },
+	[OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x3E, 0xE38E, 0x745 },
+	[OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x3E, 0x15555, 0x745 },
+	[OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x3E, 0x1C71C, 0x746 },
+	[OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x3E, 0x238E4, 0x746 },
+	[OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x3E, 0x2AAAB, 0x747 },
+	[OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x3E, 0x31C72, 0x747 },
+	[OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x3E, 0x38E39, 0x747 },
+	[OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x3E, 0x40000, 0x748 },
+	[OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x3E, 0x471C7, 0x748 },
+	[OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x3E, 0x4E38E, 0x749 },
+	[OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x3E, 0x55555, 0x749 },
+	[OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x3E, 0x5C71C, 0x749 },
+	[OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x3E, 0x638E4, 0x74A },
+	[OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x3E, 0x6AAAB, 0x74A },
+	[OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x3E, 0x71C72, 0x74B },
+	[OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x3E, 0x78E39, 0x74B },
+	[OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x3E, 0x80000, 0x74C },
+	[OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x3E, 0x871C7, 0x74C },
+	[OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x3E, 0x8E38E, 0x74C },
+	[OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x3E, 0x95555, 0x74D },
+	[OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x3E, 0x9C71C, 0x74D },
+	[OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x3E, 0xA38E4, 0x74E },
+	[OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x3E, 0xAAAAB, 0x74E },
+	[OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x3E, 0xB1C72, 0x74E },
+	[OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x3E, 0xB8E39, 0x74F },
+	[OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x3E, 0xC0000, 0x74F },
+	[OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x3E, 0xC71C7, 0x750 },
+	[OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x3E, 0xCE38E, 0x750 },
+	[OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x3E, 0xD5555, 0x751 },
+	[OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x3E, 0xDC71C, 0x751 },
+	[OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x3E, 0xE38E4, 0x751 },
+	[OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x3E, 0xEAAAB, 0x752 },
+	[OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x3E, 0xF1C72, 0x752 },
+	[OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x3E, 0xF8E39, 0x753 },
+	[OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x3E, 0x100000, 0x753 },
+	[OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x3E, 0x1071C7, 0x753 },
+	[OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x3E, 0x10E38E, 0x754 },
+	[OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x3E, 0x115555, 0x754 },
+	[OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x3E, 0x11C71C, 0x755 },
+	[OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x3E, 0x1238E4, 0x755 },
+	[OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x3E, 0x12AAAB, 0x756 },
+	[OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x3E, 0x131C72, 0x756 },
+	[OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x3E, 0x138E39, 0x756 },
+	[OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x3E, 0x140000, 0x757 },
+	[OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x3E, 0x1471C7, 0x757 },
+	[OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x3E, 0x14E38E, 0x758 },
+	[OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x3E, 0x155555, 0x758 },
+	[OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x3E, 0x15C71C, 0x758 },
+	[OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x3E, 0x1638E4, 0x759 },
+	[OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x3E, 0x16AAAB, 0x759 },
+	[OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x3E, 0x171C72, 0x75A },
+	[OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x3E, 0x178E39, 0x75A },
+	[OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x3E, 0x180000, 0x75B },
+	[OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x3E, 0x1871C7, 0x75B },
+	[OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x3E, 0x18E38E, 0x75B },
+	[OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x3E, 0x195555, 0x75C },
+	[OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x3E, 0x19C71C, 0x75C },
+	[OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x3E, 0x1A38E4, 0x75D },
+	[OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x3E, 0x1AAAAB, 0x75D },
+	[OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x3E, 0x1B1C72, 0x75D },
+	[OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x3E, 0x1B8E39, 0x75E },
+	[OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x3E, 0x1C0000, 0x75E },
+	[OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x3E, 0x1C71C7, 0x75F },
+	[OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x3E, 0x1CE38E, 0x75F },
+	[OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x3E, 0x1D5555, 0x760 },
+	[OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x3E, 0x1DC71C, 0x760 },
+	[OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x3E, 0x1E38E4, 0x760 },
+	[OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x3E, 0x1EAAAB, 0x761 },
+	[OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x3E, 0x1F1C72, 0x761 },
+	[OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x3E, 0x1F8E39, 0x762 },
+	[OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x3F, 0x0, 0x762 },
+	[OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x3F, 0x71C7, 0x762 },
+	[OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x3F, 0xE38E, 0x763 },
+	[OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x3F, 0x15555, 0x763 },
+	[OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x3F, 0x1C71C, 0x764 },
+	[OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x3F, 0x238E4, 0x764 },
+	[OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x3F, 0x2AAAB, 0x765 },
+	[OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x3F, 0x31C72, 0x765 },
+	[OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x3F, 0x38E39, 0x765 },
+	[OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x3F, 0x40000, 0x766 },
+	[OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x3F, 0x471C7, 0x766 },
+	[OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x3F, 0x4E38E, 0x767 },
+	[OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x3F, 0x55555, 0x767 },
+	[OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x3F, 0x5C71C, 0x767 },
+	[OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x3F, 0x638E4, 0x768 },
+	[OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x3F, 0x6AAAB, 0x768 },
+	[OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x3F, 0x71C72, 0x769 },
+	[OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x3F, 0x78E39, 0x769 },
+	[OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x3F, 0x80000, 0x76A },
+	[OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x3F, 0x871C7, 0x76A },
+	[OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x3F, 0x8E38E, 0x76A },
+	[OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x3F, 0x95555, 0x76B },
+	[OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x3F, 0x9C71C, 0x76B },
+	[OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x3F, 0xA38E4, 0x76C },
+	[OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x3F, 0xAAAAB, 0x76C },
+	[OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x3F, 0xB1C72, 0x76C },
+	[OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x3F, 0xB8E39, 0x76D },
+	[OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x3F, 0xC0000, 0x76D },
+	[OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x3F, 0xC71C7, 0x76E },
+	[OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x3F, 0xCE38E, 0x76E },
+	[OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x3F, 0xD5555, 0x76F },
+	[OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x3F, 0xDC71C, 0x76F },
+	[OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x3F, 0xE38E4, 0x76F },
+	[OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x3F, 0xEAAAB, 0x770 },
+	[OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x3F, 0xF1C72, 0x770 },
+	[OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x3F, 0xF8E39, 0x771 },
+	[OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x3F, 0x100000, 0x771 },
+	[OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x3F, 0x1071C7, 0x771 },
+	[OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x3F, 0x10E38E, 0x772 },
+	[OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x3F, 0x115555, 0x772 },
+	[OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x3F, 0x11C71C, 0x773 },
+	[OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x3F, 0x1238E4, 0x773 },
+	[OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x3F, 0x12AAAB, 0x774 },
+	[OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x3F, 0x131C72, 0x774 },
+	[OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x3F, 0x138E39, 0x774 },
+	[OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x3F, 0x140000, 0x775 },
+	[OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x3F, 0x1471C7, 0x775 },
+	[OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x3F, 0x14E38E, 0x776 },
+	[OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x3F, 0x155555, 0x776 },
+	[OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x3F, 0x15C71C, 0x776 },
+	[OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x3F, 0x1638E4, 0x777 },
+	[OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x3F, 0x16AAAB, 0x777 },
+	[OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x3F, 0x171C72, 0x778 },
+	[OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x3F, 0x178E39, 0x778 },
+	[OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x3F, 0x180000, 0x779 },
+	[OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x3F, 0x1871C7, 0x779 },
+	[OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x3F, 0x18E38E, 0x779 },
+	[OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x3F, 0x195555, 0x77A },
+	[OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x3F, 0x19C71C, 0x77A },
+	[OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x3F, 0x1A38E4, 0x77B },
+	[OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x3F, 0x1AAAAB, 0x77B },
+	[OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x3F, 0x1B1C72, 0x77B },
+	[OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x3F, 0x1B8E39, 0x77C },
+	[OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x3F, 0x1C0000, 0x77C },
+	[OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x3F, 0x1C71C7, 0x77D },
+	[OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x3F, 0x1CE38E, 0x77D },
+	[OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x3F, 0x1D5555, 0x77E },
+	[OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x3F, 0x1DC71C, 0x77E },
+	[OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x3F, 0x1E38E4, 0x77E },
+	[OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x3F, 0x1EAAAB, 0x77F },
+	[OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x3F, 0x1F1C72, 0x77F },
+	[OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x3F, 0x1F8E39, 0x780 },
+	[OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x40, 0x0, 0x780 },
+	[OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x40, 0x71C7, 0x780 },
+	[OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x40, 0xE38E, 0x781 },
+	[OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x40, 0x15555, 0x781 },
+	[OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x40, 0x1C71C, 0x782 },
+	[OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x40, 0x238E4, 0x782 },
+	[OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x40, 0x2AAAB, 0x783 },
+	[OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x40, 0x31C72, 0x783 },
+	[OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x40, 0x38E39, 0x783 },
+	[OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x40, 0x40000, 0x784 },
+	[OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x40, 0x471C7, 0x784 },
+	[OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x40, 0x4E38E, 0x785 },
+	[OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x40, 0x55555, 0x785 },
+	[OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x40, 0x5C71C, 0x785 },
+	[OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x40, 0x638E4, 0x786 },
+	[OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x40, 0x6AAAB, 0x786 },
+	[OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x40, 0x71C72, 0x787 },
+	[OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x40, 0x78E39, 0x787 },
+	[OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x40, 0x80000, 0x788 },
+	[OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x40, 0x871C7, 0x788 },
+	[OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x40, 0x8E38E, 0x788 },
+	[OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x40, 0x95555, 0x789 },
+	[OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x40, 0x9C71C, 0x789 },
+	[OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x40, 0xA38E4, 0x78A },
+	[OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x40, 0xAAAAB, 0x78A },
+	[OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x40, 0xB1C72, 0x78A },
+	[OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x40, 0xB8E39, 0x78B },
+	[OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x40, 0xC0000, 0x78B },
+	[OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x40, 0xC71C7, 0x78C },
+	[OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x40, 0xCE38E, 0x78C },
+	[OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x40, 0xD5555, 0x78D },
+	[OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x40, 0xDC71C, 0x78D },
+	[OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x40, 0xE38E4, 0x78D },
+	[OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x40, 0xEAAAB, 0x78E },
+	[OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x40, 0xF1C72, 0x78E },
+	[OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x40, 0xF8E39, 0x78F },
+	[OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x40, 0x100000, 0x78F },
+	[OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x40, 0x1071C7, 0x78F },
+	[OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x40, 0x10E38E, 0x790 },
+	[OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x40, 0x115555, 0x790 },
+	[OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x40, 0x11C71C, 0x791 },
+	[OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x40, 0x1238E4, 0x791 },
+	[OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x40, 0x12AAAB, 0x792 },
+	[OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x40, 0x131C72, 0x792 },
+	[OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x40, 0x138E39, 0x792 },
+	[OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x40, 0x140000, 0x793 },
+	[OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x40, 0x1471C7, 0x793 },
+	[OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x40, 0x14E38E, 0x794 },
+	[OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x40, 0x155555, 0x794 },
+	[OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x40, 0x15C71C, 0x794 },
+	[OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x40, 0x1638E4, 0x795 },
+	[OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x40, 0x16AAAB, 0x795 },
+	[OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x40, 0x171C72, 0x796 },
+	[OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x40, 0x178E39, 0x796 },
+	[OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x40, 0x180000, 0x797 },
+	[OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x40, 0x1871C7, 0x797 },
+	[OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x40, 0x18E38E, 0x797 },
+	[OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x40, 0x195555, 0x798 },
+	[OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x40, 0x19C71C, 0x798 },
+	[OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x40, 0x1A38E4, 0x799 },
+	[OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x40, 0x1AAAAB, 0x799 },
+	[OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x40, 0x1B1C72, 0x799 },
+	[OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x40, 0x1B8E39, 0x79A },
+	[OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x40, 0x1C0000, 0x79A },
+	[OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x40, 0x1C71C7, 0x79B },
+	[OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x40, 0x1CE38E, 0x79B },
+	[OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x40, 0x1D5555, 0x79C },
+	[OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x40, 0x1DC71C, 0x79C },
+	[OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x40, 0x1E38E4, 0x79C },
+	[OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x40, 0x1EAAAB, 0x79D },
+	[OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x40, 0x1F1C72, 0x79D },
+	[OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x40, 0x1F8E39, 0x79E },
+	[OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x41, 0x0, 0x79E },
+	[OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x41, 0x71C7, 0x79E },
+	[OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x41, 0xE38E, 0x79F },
+	[OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x41, 0x15555, 0x79F },
+	[OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x41, 0x1C71C, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x41, 0x238E4, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x41, 0x2AAAB, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x41, 0x31C72, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x41, 0x38E39, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x41, 0x40000, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x41, 0x471C7, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x41, 0x4E38E, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x41, 0x55555, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x41, 0x5C71C, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x41, 0x638E4, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x41, 0x6AAAB, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x41, 0x71C72, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x41, 0x78E39, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x41, 0x80000, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x41, 0x871C7, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x41, 0x8E38E, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x41, 0x95555, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x41, 0x9C71C, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x41, 0xA38E4, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x41, 0xAAAAB, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x41, 0xB1C72, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x41, 0xB8E39, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x41, 0xC0000, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x41, 0xC71C7, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x41, 0xCE38E, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x41, 0xD5555, 0x7AB },
+	[OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x41, 0xDC71C, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x41, 0xE38E4, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x41, 0xEAAAB, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x41, 0xF1C72, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x41, 0xF8E39, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x41, 0x100000, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x41, 0x1071C7, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x41, 0x10E38E, 0x7AE },
+	[OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x41, 0x115555, 0x7AE },
+	[OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x41, 0x11C71C, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x41, 0x1238E4, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x41, 0x12AAAB, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x41, 0x131C72, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x41, 0x138E39, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x41, 0x140000, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x41, 0x1471C7, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x41, 0x14E38E, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x41, 0x155555, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x41, 0x15C71C, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x41, 0x1638E4, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x41, 0x16AAAB, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x41, 0x171C72, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x41, 0x178E39, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x41, 0x180000, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x41, 0x1871C7, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x41, 0x18E38E, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x41, 0x195555, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x41, 0x19C71C, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x41, 0x1A38E4, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x41, 0x1AAAAB, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x41, 0x1B1C72, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x41, 0x1B8E39, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x41, 0x1C0000, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x41, 0x1C71C7, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x41, 0x1CE38E, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x41, 0x1D5555, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x41, 0x1DC71C, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x41, 0x1E38E4, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x41, 0x1EAAAB, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x41, 0x1F1C72, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x41, 0x1F8E39, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x42, 0x0, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x42, 0x71C7, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x42, 0xE38E, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x42, 0x15555, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x42, 0x1C71C, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x42, 0x238E4, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x42, 0x2AAAB, 0x7BF },
+	[OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x42, 0x31C72, 0x7BF },
+	[OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x42, 0x38E39, 0x7BF }
+};
+
+const struct common_lut_line olympus_lut_24g_40_mhz[OLYMPUS_LUT_CHAN_24G_MAX] = {
+	[OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x50, 0x77777, 0x645 },
+	[OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x50, 0x8CCCD, 0x646 },
+	[OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x50, 0xA2222, 0x646 },
+	[OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x50, 0xB7777, 0x647 },
+	[OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x50, 0xCCCCD, 0x648 },
+	[OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x50, 0xE2222, 0x649 },
+	[OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x50, 0xF7777, 0x64A },
+	[OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x50, 0x10CCCD, 0x64B },
+	[OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x50, 0x122222, 0x64B },
+	[OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x50, 0x137777, 0x64C },
+	[OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x50, 0x14CCCD, 0x64D },
+	[OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x50, 0x162222, 0x64E },
+	[OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x50, 0x177777, 0x64F },
+	[OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x50, 0x18CCCD, 0x650 },
+	[OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x50, 0x1A2222, 0x650 },
+	[OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x50, 0x1B7777, 0x651 },
+	[OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x50, 0x1CCCCD, 0x652 },
+	[OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x50, 0x1E2222, 0x653 },
+	[OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x50, 0x1F7777, 0x654 },
+	[OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x51, 0xCCCD, 0x655 },
+	[OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x51, 0x22222, 0x655 },
+	[OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x51, 0x37777, 0x656 },
+	[OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x51, 0x4CCCD, 0x657 },
+	[OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x51, 0x62222, 0x658 },
+	[OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x51, 0x77777, 0x659 },
+	[OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x51, 0x8CCCD, 0x65A },
+	[OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x51, 0xA2222, 0x65A },
+	[OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x51, 0xB7777, 0x65B },
+	[OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x51, 0xCCCCD, 0x65C },
+	[OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x51, 0xE2222, 0x65D },
+	[OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x51, 0xF7777, 0x65E },
+	[OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x51, 0x10CCCD, 0x65F },
+	[OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x51, 0x122222, 0x65F },
+	[OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x51, 0x137777, 0x660 },
+	[OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x51, 0x14CCCD, 0x661 },
+	[OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x51, 0x162222, 0x662 },
+	[OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x51, 0x177777, 0x663 },
+	[OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x51, 0x18CCCD, 0x664 },
+	[OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x51, 0x1A2222, 0x664 },
+	[OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x51, 0x1B7777, 0x665 },
+	[OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x51, 0x1CCCCD, 0x666 },
+	[OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x51, 0x1E2222, 0x667 },
+	[OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x51, 0x1F7777, 0x668 },
+	[OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x52, 0xCCCD, 0x669 },
+	[OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x52, 0x22222, 0x669 },
+	[OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x52, 0x37777, 0x66A },
+	[OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x52, 0x4CCCD, 0x66B },
+	[OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x52, 0x62222, 0x66C },
+	[OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x52, 0x77777, 0x66D },
+	[OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x52, 0x8CCCD, 0x66E },
+	[OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x52, 0xA2222, 0x66E },
+	[OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x52, 0xB7777, 0x66F },
+	[OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x52, 0xCCCCD, 0x670 },
+	[OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x52, 0xE2222, 0x671 },
+	[OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x52, 0xF7777, 0x672 },
+	[OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x52, 0x10CCCD, 0x673 },
+	[OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x52, 0x122222, 0x673 },
+	[OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x52, 0x137777, 0x674 },
+	[OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x52, 0x14CCCD, 0x675 },
+	[OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x52, 0x162222, 0x676 },
+	[OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x52, 0x177777, 0x677 },
+	[OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x52, 0x18CCCD, 0x678 },
+	[OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x52, 0x1A2222, 0x678 },
+	[OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x52, 0x1B7777, 0x679 },
+	[OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x52, 0x1CCCCD, 0x67A },
+	[OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x52, 0x1E2222, 0x67B },
+	[OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x52, 0x1F7777, 0x67C },
+	[OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x53, 0xCCCD, 0x67D },
+	[OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x53, 0x22222, 0x67D },
+	[OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x53, 0x37777, 0x67E },
+	[OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x53, 0x4CCCD, 0x67F },
+	[OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x53, 0x62222, 0x680 },
+	[OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x53, 0x77777, 0x681 },
+	[OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x53, 0x8CCCD, 0x682 },
+	[OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x53, 0xA2222, 0x682 },
+	[OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x53, 0xB7777, 0x683 }
+};
+
+const struct common_lut_line olympus_lut_24g_60_mhz_s0[OLYMPUS_LUT_CHAN_24G_MAX] = {
+	[OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x6A, 0x1F49F5, 0x645 },
+	[OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x6B, 0x11111, 0x646 },
+	[OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x6B, 0x2D82E, 0x646 },
+	[OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x6B, 0x49F4A, 0x647 },
+	[OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x6B, 0x66666, 0x648 },
+	[OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x6B, 0x82D83, 0x649 },
+	[OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x6B, 0x9F49F, 0x64A },
+	[OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x6B, 0xBBBBC, 0x64B },
+	[OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x6B, 0xD82D8, 0x64B },
+	[OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x6B, 0xF49F5, 0x64C },
+	[OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x6B, 0x111111, 0x64D },
+	[OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x6B, 0x12D82E, 0x64E },
+	[OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x6B, 0x149F4A, 0x64F },
+	[OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x6B, 0x166666, 0x650 },
+	[OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x6B, 0x182D83, 0x650 },
+	[OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x6B, 0x19F49F, 0x651 },
+	[OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x6B, 0x1BBBBC, 0x652 },
+	[OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x6B, 0x1D82D8, 0x653 },
+	[OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x6B, 0x1F49F5, 0x654 },
+	[OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x6C, 0x11111, 0x655 },
+	[OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x6C, 0x2D82E, 0x655 },
+	[OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x6C, 0x49F4A, 0x656 },
+	[OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x6C, 0x66666, 0x657 },
+	[OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x6C, 0x82D83, 0x658 },
+	[OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x6C, 0x9F49F, 0x659 },
+	[OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x6C, 0xBBBBC, 0x65A },
+	[OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x6C, 0xD82D8, 0x65A },
+	[OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x6C, 0xF49F5, 0x65B },
+	[OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x6C, 0x111111, 0x65C },
+	[OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x6C, 0x12D82E, 0x65D },
+	[OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x6C, 0x149F4A, 0x65E },
+	[OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x6C, 0x166666, 0x65F },
+	[OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x6C, 0x182D83, 0x65F },
+	[OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x6C, 0x19F49F, 0x660 },
+	[OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x6C, 0x1BBBBC, 0x661 },
+	[OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x6C, 0x1D82D8, 0x662 },
+	[OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x6C, 0x1F49F5, 0x663 },
+	[OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x6D, 0x11111, 0x664 },
+	[OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x6D, 0x2D82E, 0x664 },
+	[OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x6D, 0x49F4A, 0x665 },
+	[OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x6D, 0x66666, 0x666 },
+	[OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x6D, 0x82D83, 0x667 },
+	[OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x6D, 0x9F49F, 0x668 },
+	[OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x6D, 0xBBBBC, 0x669 },
+	[OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x6D, 0xD82D8, 0x669 },
+	[OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x6D, 0xF49F5, 0x66A },
+	[OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x6D, 0x111111, 0x66B },
+	[OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x6D, 0x12D82E, 0x66C },
+	[OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x6D, 0x149F4A, 0x66D },
+	[OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x6D, 0x166666, 0x66E },
+	[OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x6D, 0x182D83, 0x66E },
+	[OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x6D, 0x19F49F, 0x66F },
+	[OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x6D, 0x1BBBBC, 0x670 },
+	[OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x6D, 0x1D82D8, 0x671 },
+	[OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x6D, 0x1F49F5, 0x672 },
+	[OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x6E, 0x11111, 0x673 },
+	[OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x6E, 0x2D82E, 0x673 },
+	[OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x6E, 0x49F4A, 0x674 },
+	[OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x6E, 0x66666, 0x675 },
+	[OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x6E, 0x82D83, 0x676 },
+	[OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x6E, 0x9F49F, 0x677 },
+	[OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x6E, 0xBBBBC, 0x678 },
+	[OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x6E, 0xD82D8, 0x678 },
+	[OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x6E, 0xF49F5, 0x679 },
+	[OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x6E, 0x111111, 0x67A },
+	[OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x6E, 0x12D82E, 0x67B },
+	[OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x6E, 0x149F4A, 0x67C },
+	[OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x6E, 0x166666, 0x67D },
+	[OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x6E, 0x182D83, 0x67D },
+	[OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x6E, 0x19F49F, 0x67E },
+	[OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x6E, 0x1BBBBC, 0x67F },
+	[OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x6E, 0x1D82D8, 0x680 },
+	[OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x6E, 0x1F49F5, 0x681 },
+	[OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x6F, 0x11111, 0x682 },
+	[OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x6F, 0x2D82E, 0x682 },
+	[OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x6F, 0x49F4A, 0x683 }
+};
+
+const struct common_lut_line olympus_lut_24g_60_mhz_s1[OLYMPUS_LUT_CHAN_24G_MAX] = {
+	[OLYMPUS_LUT_CHAN_240700_IDX] = { 9628, 0x0, 0x35, 0xFA4FA, 0x645 },
+	[OLYMPUS_LUT_CHAN_240825_IDX] = { 9633, 0x0, 0x35, 0x108889, 0x646 },
+	[OLYMPUS_LUT_CHAN_240950_IDX] = { 9638, 0x0, 0x35, 0x116C17, 0x646 },
+	[OLYMPUS_LUT_CHAN_241075_IDX] = { 9643, 0x0, 0x35, 0x124FA5, 0x647 },
+	[OLYMPUS_LUT_CHAN_241200_IDX] = { 9648, 0x0, 0x35, 0x133333, 0x648 },
+	[OLYMPUS_LUT_CHAN_241325_IDX] = { 9653, 0x0, 0x35, 0x1416C1, 0x649 },
+	[OLYMPUS_LUT_CHAN_241450_IDX] = { 9658, 0x0, 0x35, 0x14FA50, 0x64A },
+	[OLYMPUS_LUT_CHAN_241575_IDX] = { 9663, 0x0, 0x35, 0x15DDDE, 0x64B },
+	[OLYMPUS_LUT_CHAN_241700_IDX] = { 9668, 0x0, 0x35, 0x16C16C, 0x64B },
+	[OLYMPUS_LUT_CHAN_241825_IDX] = { 9673, 0x0, 0x35, 0x17A4FA, 0x64C },
+	[OLYMPUS_LUT_CHAN_241950_IDX] = { 9678, 0x0, 0x35, 0x188889, 0x64D },
+	[OLYMPUS_LUT_CHAN_242075_IDX] = { 9683, 0x0, 0x35, 0x196C17, 0x64E },
+	[OLYMPUS_LUT_CHAN_242200_IDX] = { 9688, 0x0, 0x35, 0x1A4FA5, 0x64F },
+	[OLYMPUS_LUT_CHAN_242325_IDX] = { 9693, 0x0, 0x35, 0x1B3333, 0x650 },
+	[OLYMPUS_LUT_CHAN_242450_IDX] = { 9698, 0x0, 0x35, 0x1C16C1, 0x650 },
+	[OLYMPUS_LUT_CHAN_242575_IDX] = { 9703, 0x0, 0x35, 0x1CFA50, 0x651 },
+	[OLYMPUS_LUT_CHAN_242700_IDX] = { 9708, 0x0, 0x35, 0x1DDDDE, 0x652 },
+	[OLYMPUS_LUT_CHAN_242825_IDX] = { 9713, 0x0, 0x35, 0x1EC16C, 0x653 },
+	[OLYMPUS_LUT_CHAN_242950_IDX] = { 9718, 0x0, 0x35, 0x1FA4FA, 0x654 },
+	[OLYMPUS_LUT_CHAN_243075_IDX] = { 9723, 0x0, 0x36, 0x8889, 0x655 },
+	[OLYMPUS_LUT_CHAN_243200_IDX] = { 9728, 0x0, 0x36, 0x16C17, 0x655 },
+	[OLYMPUS_LUT_CHAN_243325_IDX] = { 9733, 0x0, 0x36, 0x24FA5, 0x656 },
+	[OLYMPUS_LUT_CHAN_243450_IDX] = { 9738, 0x0, 0x36, 0x33333, 0x657 },
+	[OLYMPUS_LUT_CHAN_243575_IDX] = { 9743, 0x0, 0x36, 0x416C1, 0x658 },
+	[OLYMPUS_LUT_CHAN_243700_IDX] = { 9748, 0x0, 0x36, 0x4FA50, 0x659 },
+	[OLYMPUS_LUT_CHAN_243825_IDX] = { 9753, 0x0, 0x36, 0x5DDDE, 0x65A },
+	[OLYMPUS_LUT_CHAN_243950_IDX] = { 9758, 0x0, 0x36, 0x6C16C, 0x65A },
+	[OLYMPUS_LUT_CHAN_244075_IDX] = { 9763, 0x0, 0x36, 0x7A4FA, 0x65B },
+	[OLYMPUS_LUT_CHAN_244200_IDX] = { 9768, 0x0, 0x36, 0x88889, 0x65C },
+	[OLYMPUS_LUT_CHAN_244325_IDX] = { 9773, 0x0, 0x36, 0x96C17, 0x65D },
+	[OLYMPUS_LUT_CHAN_244450_IDX] = { 9778, 0x0, 0x36, 0xA4FA5, 0x65E },
+	[OLYMPUS_LUT_CHAN_244575_IDX] = { 9783, 0x0, 0x36, 0xB3333, 0x65F },
+	[OLYMPUS_LUT_CHAN_244700_IDX] = { 9788, 0x0, 0x36, 0xC16C1, 0x65F },
+	[OLYMPUS_LUT_CHAN_244825_IDX] = { 9793, 0x0, 0x36, 0xCFA50, 0x660 },
+	[OLYMPUS_LUT_CHAN_244950_IDX] = { 9798, 0x0, 0x36, 0xDDDDE, 0x661 },
+	[OLYMPUS_LUT_CHAN_245075_IDX] = { 9803, 0x0, 0x36, 0xEC16C, 0x662 },
+	[OLYMPUS_LUT_CHAN_245200_IDX] = { 9808, 0x0, 0x36, 0xFA4FA, 0x663 },
+	[OLYMPUS_LUT_CHAN_245325_IDX] = { 9813, 0x0, 0x36, 0x108889, 0x664 },
+	[OLYMPUS_LUT_CHAN_245450_IDX] = { 9818, 0x0, 0x36, 0x116C17, 0x664 },
+	[OLYMPUS_LUT_CHAN_245575_IDX] = { 9823, 0x0, 0x36, 0x124FA5, 0x665 },
+	[OLYMPUS_LUT_CHAN_245700_IDX] = { 9828, 0x0, 0x36, 0x133333, 0x666 },
+	[OLYMPUS_LUT_CHAN_245825_IDX] = { 9833, 0x0, 0x36, 0x1416C1, 0x667 },
+	[OLYMPUS_LUT_CHAN_245950_IDX] = { 9838, 0x0, 0x36, 0x14FA50, 0x668 },
+	[OLYMPUS_LUT_CHAN_246075_IDX] = { 9843, 0x0, 0x36, 0x15DDDE, 0x669 },
+	[OLYMPUS_LUT_CHAN_246200_IDX] = { 9848, 0x0, 0x36, 0x16C16C, 0x669 },
+	[OLYMPUS_LUT_CHAN_246325_IDX] = { 9853, 0x0, 0x36, 0x17A4FA, 0x66A },
+	[OLYMPUS_LUT_CHAN_246450_IDX] = { 9858, 0x0, 0x36, 0x188889, 0x66B },
+	[OLYMPUS_LUT_CHAN_246575_IDX] = { 9863, 0x0, 0x36, 0x196C17, 0x66C },
+	[OLYMPUS_LUT_CHAN_246700_IDX] = { 9868, 0x0, 0x36, 0x1A4FA5, 0x66D },
+	[OLYMPUS_LUT_CHAN_246825_IDX] = { 9873, 0x0, 0x36, 0x1B3333, 0x66E },
+	[OLYMPUS_LUT_CHAN_246950_IDX] = { 9878, 0x0, 0x36, 0x1C16C1, 0x66E },
+	[OLYMPUS_LUT_CHAN_247075_IDX] = { 9883, 0x0, 0x36, 0x1CFA50, 0x66F },
+	[OLYMPUS_LUT_CHAN_247200_IDX] = { 9888, 0x0, 0x36, 0x1DDDDE, 0x670 },
+	[OLYMPUS_LUT_CHAN_247325_IDX] = { 9893, 0x0, 0x36, 0x1EC16C, 0x671 },
+	[OLYMPUS_LUT_CHAN_247450_IDX] = { 9898, 0x0, 0x36, 0x1FA4FA, 0x672 },
+	[OLYMPUS_LUT_CHAN_247575_IDX] = { 9903, 0x0, 0x37, 0x8889, 0x673 },
+	[OLYMPUS_LUT_CHAN_247700_IDX] = { 9908, 0x0, 0x37, 0x16C17, 0x673 },
+	[OLYMPUS_LUT_CHAN_247825_IDX] = { 9913, 0x0, 0x37, 0x24FA5, 0x674 },
+	[OLYMPUS_LUT_CHAN_247950_IDX] = { 9918, 0x0, 0x37, 0x33333, 0x675 },
+	[OLYMPUS_LUT_CHAN_248075_IDX] = { 9923, 0x0, 0x37, 0x416C1, 0x676 },
+	[OLYMPUS_LUT_CHAN_248200_IDX] = { 9928, 0x0, 0x37, 0x4FA50, 0x677 },
+	[OLYMPUS_LUT_CHAN_248325_IDX] = { 9933, 0x0, 0x37, 0x5DDDE, 0x678 },
+	[OLYMPUS_LUT_CHAN_248450_IDX] = { 9938, 0x0, 0x37, 0x6C16C, 0x678 },
+	[OLYMPUS_LUT_CHAN_248575_IDX] = { 9943, 0x0, 0x37, 0x7A4FA, 0x679 },
+	[OLYMPUS_LUT_CHAN_248700_IDX] = { 9948, 0x0, 0x37, 0x88889, 0x67A },
+	[OLYMPUS_LUT_CHAN_248825_IDX] = { 9953, 0x0, 0x37, 0x96C17, 0x67B },
+	[OLYMPUS_LUT_CHAN_248950_IDX] = { 9958, 0x0, 0x37, 0xA4FA5, 0x67C },
+	[OLYMPUS_LUT_CHAN_249075_IDX] = { 9963, 0x0, 0x37, 0xB3333, 0x67D },
+	[OLYMPUS_LUT_CHAN_249200_IDX] = { 9968, 0x0, 0x37, 0xC16C1, 0x67D },
+	[OLYMPUS_LUT_CHAN_249325_IDX] = { 9973, 0x0, 0x37, 0xCFA50, 0x67E },
+	[OLYMPUS_LUT_CHAN_249450_IDX] = { 9978, 0x0, 0x37, 0xDDDDE, 0x67F },
+	[OLYMPUS_LUT_CHAN_249575_IDX] = { 9983, 0x0, 0x37, 0xEC16C, 0x680 },
+	[OLYMPUS_LUT_CHAN_249700_IDX] = { 9988, 0x0, 0x37, 0xFA4FA, 0x681 },
+	[OLYMPUS_LUT_CHAN_249825_IDX] = { 9993, 0x0, 0x37, 0x108889, 0x682 },
+	[OLYMPUS_LUT_CHAN_249950_IDX] = { 9998, 0x0, 0x37, 0x116C17, 0x682 },
+	[OLYMPUS_LUT_CHAN_250075_IDX] = { 10003, 0x0, 0x37, 0x124FA5, 0x683 }
+};
+
+const struct common_lut_line olympus_lut_5g_60_mhz_s0[OLYMPUS_LUT_CHAN_5G_MAX] = {
+	[OLYMPUS_LUT_CHAN_516000_IDX] = { 20640, 0x0, 0x73, 0x38E39, 0x6BF },
+	[OLYMPUS_LUT_CHAN_516125_IDX] = { 20645, 0x0, 0x72, 0x1638E4, 0x6B8 },
+	[OLYMPUS_LUT_CHAN_516250_IDX] = { 20650, 0x0, 0x72, 0x171C72, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516375_IDX] = { 20655, 0x0, 0x72, 0x180000, 0x6B9 },
+	[OLYMPUS_LUT_CHAN_516500_IDX] = { 20660, 0x0, 0x72, 0x18E38E, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516625_IDX] = { 20665, 0x0, 0x72, 0x19C71C, 0x6BA },
+	[OLYMPUS_LUT_CHAN_516750_IDX] = { 20670, 0x0, 0x72, 0x1AAAAB, 0x6BB },
+	[OLYMPUS_LUT_CHAN_516875_IDX] = { 20675, 0x0, 0x72, 0x1B8E39, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517000_IDX] = { 20680, 0x0, 0x72, 0x1C71C7, 0x6BB },
+	[OLYMPUS_LUT_CHAN_517125_IDX] = { 20685, 0x0, 0x72, 0x1D5555, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517250_IDX] = { 20690, 0x0, 0x72, 0x1E38E4, 0x6BC },
+	[OLYMPUS_LUT_CHAN_517375_IDX] = { 20695, 0x0, 0x72, 0x1F1C72, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517500_IDX] = { 20700, 0x0, 0x73, 0x0, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517625_IDX] = { 20705, 0x0, 0x73, 0xE38E, 0x6BD },
+	[OLYMPUS_LUT_CHAN_517750_IDX] = { 20710, 0x0, 0x73, 0x1C71C, 0x6BE },
+	[OLYMPUS_LUT_CHAN_517875_IDX] = { 20715, 0x0, 0x73, 0x2AAAB, 0x6BE },
+	[OLYMPUS_LUT_CHAN_518000_IDX] = { 20720, 0x0, 0x73, 0x38E39, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518125_IDX] = { 20725, 0x0, 0x73, 0x471C7, 0x6BF },
+	[OLYMPUS_LUT_CHAN_518250_IDX] = { 20730, 0x0, 0x73, 0x55555, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518375_IDX] = { 20735, 0x0, 0x73, 0x638E4, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518500_IDX] = { 20740, 0x0, 0x73, 0x71C72, 0x6C0 },
+	[OLYMPUS_LUT_CHAN_518625_IDX] = { 20745, 0x0, 0x73, 0x80000, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518750_IDX] = { 20750, 0x0, 0x73, 0x8E38E, 0x6C1 },
+	[OLYMPUS_LUT_CHAN_518875_IDX] = { 20755, 0x0, 0x73, 0x9C71C, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519000_IDX] = { 20760, 0x0, 0x73, 0xAAAAB, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519125_IDX] = { 20765, 0x0, 0x73, 0xB8E39, 0x6C2 },
+	[OLYMPUS_LUT_CHAN_519250_IDX] = { 20770, 0x0, 0x73, 0xC71C7, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519375_IDX] = { 20775, 0x0, 0x73, 0xD5555, 0x6C3 },
+	[OLYMPUS_LUT_CHAN_519500_IDX] = { 20780, 0x0, 0x73, 0xE38E4, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519625_IDX] = { 20785, 0x0, 0x73, 0xF1C72, 0x6C4 },
+	[OLYMPUS_LUT_CHAN_519750_IDX] = { 20790, 0x0, 0x73, 0x100000, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_519875_IDX] = { 20795, 0x0, 0x73, 0x10E38E, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520000_IDX] = { 20800, 0x1, 0x73, 0x11C71C, 0x6C5 },
+	[OLYMPUS_LUT_CHAN_520125_IDX] = { 20805, 0x1, 0x73, 0x12AAAB, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520250_IDX] = { 20810, 0x1, 0x73, 0x138E39, 0x6C6 },
+	[OLYMPUS_LUT_CHAN_520375_IDX] = { 20815, 0x1, 0x73, 0x1471C7, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520500_IDX] = { 20820, 0x1, 0x73, 0x155555, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520625_IDX] = { 20825, 0x1, 0x73, 0x1638E4, 0x6C7 },
+	[OLYMPUS_LUT_CHAN_520750_IDX] = { 20830, 0x1, 0x73, 0x171C72, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_520875_IDX] = { 20835, 0x1, 0x73, 0x180000, 0x6C8 },
+	[OLYMPUS_LUT_CHAN_521000_IDX] = { 20840, 0x1, 0x73, 0x18E38E, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521125_IDX] = { 20845, 0x1, 0x73, 0x19C71C, 0x6C9 },
+	[OLYMPUS_LUT_CHAN_521250_IDX] = { 20850, 0x1, 0x73, 0x1AAAAB, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521375_IDX] = { 20855, 0x1, 0x73, 0x1B8E39, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521500_IDX] = { 20860, 0x1, 0x73, 0x1C71C7, 0x6CA },
+	[OLYMPUS_LUT_CHAN_521625_IDX] = { 20865, 0x1, 0x73, 0x1D5555, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521750_IDX] = { 20870, 0x1, 0x73, 0x1E38E4, 0x6CB },
+	[OLYMPUS_LUT_CHAN_521875_IDX] = { 20875, 0x1, 0x73, 0x1F1C72, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522000_IDX] = { 20880, 0x1, 0x74, 0x0, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522125_IDX] = { 20885, 0x1, 0x74, 0xE38E, 0x6CC },
+	[OLYMPUS_LUT_CHAN_522250_IDX] = { 20890, 0x1, 0x74, 0x1C71C, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522375_IDX] = { 20895, 0x1, 0x74, 0x2AAAB, 0x6CD },
+	[OLYMPUS_LUT_CHAN_522500_IDX] = { 20900, 0x1, 0x74, 0x38E39, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522625_IDX] = { 20905, 0x1, 0x74, 0x471C7, 0x6CE },
+	[OLYMPUS_LUT_CHAN_522750_IDX] = { 20910, 0x1, 0x74, 0x55555, 0x6CF },
+	[OLYMPUS_LUT_CHAN_522875_IDX] = { 20915, 0x1, 0x74, 0x638E4, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523000_IDX] = { 20920, 0x1, 0x74, 0x71C72, 0x6CF },
+	[OLYMPUS_LUT_CHAN_523125_IDX] = { 20925, 0x1, 0x74, 0x80000, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523250_IDX] = { 20930, 0x1, 0x74, 0x8E38E, 0x6D0 },
+	[OLYMPUS_LUT_CHAN_523375_IDX] = { 20935, 0x1, 0x74, 0x9C71C, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523500_IDX] = { 20940, 0x1, 0x74, 0xAAAAB, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523625_IDX] = { 20945, 0x1, 0x74, 0xB8E39, 0x6D1 },
+	[OLYMPUS_LUT_CHAN_523750_IDX] = { 20950, 0x1, 0x74, 0xC71C7, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_523875_IDX] = { 20955, 0x1, 0x74, 0xD5555, 0x6D2 },
+	[OLYMPUS_LUT_CHAN_524000_IDX] = { 20960, 0x1, 0x74, 0xE38E4, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524125_IDX] = { 20965, 0x1, 0x74, 0xF1C72, 0x6D3 },
+	[OLYMPUS_LUT_CHAN_524250_IDX] = { 20970, 0x1, 0x74, 0x100000, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524375_IDX] = { 20975, 0x1, 0x74, 0x10E38E, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524500_IDX] = { 20980, 0x1, 0x74, 0x11C71C, 0x6D4 },
+	[OLYMPUS_LUT_CHAN_524625_IDX] = { 20985, 0x1, 0x74, 0x12AAAB, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524750_IDX] = { 20990, 0x1, 0x74, 0x138E39, 0x6D5 },
+	[OLYMPUS_LUT_CHAN_524875_IDX] = { 20995, 0x1, 0x74, 0x1471C7, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525000_IDX] = { 21000, 0x1, 0x74, 0x155555, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525125_IDX] = { 21005, 0x1, 0x74, 0x1638E4, 0x6D6 },
+	[OLYMPUS_LUT_CHAN_525250_IDX] = { 21010, 0x1, 0x74, 0x171C72, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525375_IDX] = { 21015, 0x1, 0x74, 0x180000, 0x6D7 },
+	[OLYMPUS_LUT_CHAN_525500_IDX] = { 21020, 0x1, 0x74, 0x18E38E, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525625_IDX] = { 21025, 0x1, 0x74, 0x19C71C, 0x6D8 },
+	[OLYMPUS_LUT_CHAN_525750_IDX] = { 21030, 0x1, 0x74, 0x1AAAAB, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_525875_IDX] = { 21035, 0x1, 0x74, 0x1B8E39, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526000_IDX] = { 21040, 0x1, 0x74, 0x1C71C7, 0x6D9 },
+	[OLYMPUS_LUT_CHAN_526125_IDX] = { 21045, 0x1, 0x74, 0x1D5555, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526250_IDX] = { 21050, 0x1, 0x74, 0x1E38E4, 0x6DA },
+	[OLYMPUS_LUT_CHAN_526375_IDX] = { 21055, 0x1, 0x74, 0x1F1C72, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526500_IDX] = { 21060, 0x1, 0x75, 0x0, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526625_IDX] = { 21065, 0x1, 0x75, 0xE38E, 0x6DB },
+	[OLYMPUS_LUT_CHAN_526750_IDX] = { 21070, 0x1, 0x75, 0x1C71C, 0x6DC },
+	[OLYMPUS_LUT_CHAN_526875_IDX] = { 21075, 0x1, 0x75, 0x2AAAB, 0x6DC },
+	[OLYMPUS_LUT_CHAN_527000_IDX] = { 21080, 0x1, 0x75, 0x38E39, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527125_IDX] = { 21085, 0x1, 0x75, 0x471C7, 0x6DD },
+	[OLYMPUS_LUT_CHAN_527250_IDX] = { 21090, 0x1, 0x75, 0x55555, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527375_IDX] = { 21095, 0x1, 0x75, 0x638E4, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527500_IDX] = { 21100, 0x1, 0x75, 0x71C72, 0x6DE },
+	[OLYMPUS_LUT_CHAN_527625_IDX] = { 21105, 0x1, 0x75, 0x80000, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527750_IDX] = { 21110, 0x1, 0x75, 0x8E38E, 0x6DF },
+	[OLYMPUS_LUT_CHAN_527875_IDX] = { 21115, 0x1, 0x75, 0x9C71C, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528000_IDX] = { 21120, 0x1, 0x75, 0xAAAAB, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528125_IDX] = { 21125, 0x1, 0x75, 0xB8E39, 0x6E0 },
+	[OLYMPUS_LUT_CHAN_528250_IDX] = { 21130, 0x1, 0x75, 0xC71C7, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528375_IDX] = { 21135, 0x1, 0x75, 0xD5555, 0x6E1 },
+	[OLYMPUS_LUT_CHAN_528500_IDX] = { 21140, 0x1, 0x75, 0xE38E4, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528625_IDX] = { 21145, 0x1, 0x75, 0xF1C72, 0x6E2 },
+	[OLYMPUS_LUT_CHAN_528750_IDX] = { 21150, 0x1, 0x75, 0x100000, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_528875_IDX] = { 21155, 0x1, 0x75, 0x10E38E, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529000_IDX] = { 21160, 0x1, 0x75, 0x11C71C, 0x6E3 },
+	[OLYMPUS_LUT_CHAN_529125_IDX] = { 21165, 0x1, 0x75, 0x12AAAB, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529250_IDX] = { 21170, 0x1, 0x75, 0x138E39, 0x6E4 },
+	[OLYMPUS_LUT_CHAN_529375_IDX] = { 21175, 0x1, 0x75, 0x1471C7, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529500_IDX] = { 21180, 0x1, 0x75, 0x155555, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529625_IDX] = { 21185, 0x1, 0x75, 0x1638E4, 0x6E5 },
+	[OLYMPUS_LUT_CHAN_529750_IDX] = { 21190, 0x1, 0x75, 0x171C72, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_529875_IDX] = { 21195, 0x1, 0x75, 0x180000, 0x6E6 },
+	[OLYMPUS_LUT_CHAN_530000_IDX] = { 21200, 0x1, 0x75, 0x18E38E, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530125_IDX] = { 21205, 0x1, 0x75, 0x19C71C, 0x6E7 },
+	[OLYMPUS_LUT_CHAN_530250_IDX] = { 21210, 0x1, 0x75, 0x1AAAAB, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530375_IDX] = { 21215, 0x1, 0x75, 0x1B8E39, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530500_IDX] = { 21220, 0x1, 0x75, 0x1C71C7, 0x6E8 },
+	[OLYMPUS_LUT_CHAN_530625_IDX] = { 21225, 0x1, 0x75, 0x1D5555, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530750_IDX] = { 21230, 0x1, 0x75, 0x1E38E4, 0x6E9 },
+	[OLYMPUS_LUT_CHAN_530875_IDX] = { 21235, 0x1, 0x75, 0x1F1C72, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531000_IDX] = { 21240, 0x1, 0x76, 0x0, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531125_IDX] = { 21245, 0x1, 0x76, 0xE38E, 0x6EA },
+	[OLYMPUS_LUT_CHAN_531250_IDX] = { 21250, 0x1, 0x76, 0x1C71C, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531375_IDX] = { 21255, 0x1, 0x76, 0x2AAAB, 0x6EB },
+	[OLYMPUS_LUT_CHAN_531500_IDX] = { 21260, 0x1, 0x76, 0x38E39, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531625_IDX] = { 21265, 0x1, 0x76, 0x471C7, 0x6EC },
+	[OLYMPUS_LUT_CHAN_531750_IDX] = { 21270, 0x1, 0x76, 0x55555, 0x6ED },
+	[OLYMPUS_LUT_CHAN_531875_IDX] = { 21275, 0x1, 0x76, 0x638E4, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532000_IDX] = { 21280, 0x1, 0x76, 0x71C72, 0x6ED },
+	[OLYMPUS_LUT_CHAN_532125_IDX] = { 21285, 0x1, 0x76, 0x80000, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532250_IDX] = { 21290, 0x1, 0x76, 0x8E38E, 0x6EE },
+	[OLYMPUS_LUT_CHAN_532375_IDX] = { 21295, 0x1, 0x76, 0x9C71C, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532500_IDX] = { 21300, 0x1, 0x76, 0xAAAAB, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532625_IDX] = { 21305, 0x1, 0x76, 0xB8E39, 0x6EF },
+	[OLYMPUS_LUT_CHAN_532750_IDX] = { 21310, 0x1, 0x76, 0xC71C7, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_532875_IDX] = { 21315, 0x1, 0x76, 0xD5555, 0x6F0 },
+	[OLYMPUS_LUT_CHAN_533000_IDX] = { 21320, 0x1, 0x76, 0xE38E4, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533125_IDX] = { 21325, 0x1, 0x76, 0xF1C72, 0x6F1 },
+	[OLYMPUS_LUT_CHAN_533250_IDX] = { 21330, 0x1, 0x76, 0x100000, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533375_IDX] = { 21335, 0x1, 0x76, 0x10E38E, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533500_IDX] = { 21340, 0x1, 0x76, 0x11C71C, 0x6F2 },
+	[OLYMPUS_LUT_CHAN_533625_IDX] = { 21345, 0x1, 0x76, 0x12AAAB, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533750_IDX] = { 21350, 0x1, 0x76, 0x138E39, 0x6F3 },
+	[OLYMPUS_LUT_CHAN_533875_IDX] = { 21355, 0x1, 0x76, 0x1471C7, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534000_IDX] = { 21360, 0x1, 0x76, 0x155555, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534125_IDX] = { 21365, 0x1, 0x76, 0x1638E4, 0x6F4 },
+	[OLYMPUS_LUT_CHAN_534250_IDX] = { 21370, 0x1, 0x76, 0x171C72, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534375_IDX] = { 21375, 0x1, 0x76, 0x180000, 0x6F5 },
+	[OLYMPUS_LUT_CHAN_534500_IDX] = { 21380, 0x1, 0x76, 0x18E38E, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534625_IDX] = { 21385, 0x1, 0x76, 0x19C71C, 0x6F6 },
+	[OLYMPUS_LUT_CHAN_534750_IDX] = { 21390, 0x1, 0x76, 0x1AAAAB, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_534875_IDX] = { 21395, 0x1, 0x76, 0x1B8E39, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535000_IDX] = { 21400, 0x1, 0x76, 0x1C71C7, 0x6F7 },
+	[OLYMPUS_LUT_CHAN_535125_IDX] = { 21405, 0x1, 0x76, 0x1D5555, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535250_IDX] = { 21410, 0x1, 0x76, 0x1E38E4, 0x6F8 },
+	[OLYMPUS_LUT_CHAN_535375_IDX] = { 21415, 0x1, 0x76, 0x1F1C72, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535500_IDX] = { 21420, 0x1, 0x77, 0x0, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535625_IDX] = { 21425, 0x1, 0x77, 0xE38E, 0x6F9 },
+	[OLYMPUS_LUT_CHAN_535750_IDX] = { 21430, 0x1, 0x77, 0x1C71C, 0x6FA },
+	[OLYMPUS_LUT_CHAN_535875_IDX] = { 21435, 0x1, 0x77, 0x2AAAB, 0x6FA },
+	[OLYMPUS_LUT_CHAN_536000_IDX] = { 21440, 0x1, 0x77, 0x38E39, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536125_IDX] = { 21445, 0x1, 0x77, 0x471C7, 0x6FB },
+	[OLYMPUS_LUT_CHAN_536250_IDX] = { 21450, 0x1, 0x77, 0x55555, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536375_IDX] = { 21455, 0x1, 0x77, 0x638E4, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536500_IDX] = { 21460, 0x1, 0x77, 0x71C72, 0x6FC },
+	[OLYMPUS_LUT_CHAN_536625_IDX] = { 21465, 0x1, 0x77, 0x80000, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536750_IDX] = { 21470, 0x1, 0x77, 0x8E38E, 0x6FD },
+	[OLYMPUS_LUT_CHAN_536875_IDX] = { 21475, 0x1, 0x77, 0x9C71C, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537000_IDX] = { 21480, 0x1, 0x77, 0xAAAAB, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537125_IDX] = { 21485, 0x1, 0x77, 0xB8E39, 0x6FE },
+	[OLYMPUS_LUT_CHAN_537250_IDX] = { 21490, 0x1, 0x77, 0xC71C7, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537375_IDX] = { 21495, 0x1, 0x77, 0xD5555, 0x6FF },
+	[OLYMPUS_LUT_CHAN_537500_IDX] = { 21500, 0x1, 0x77, 0xE38E4, 0x700 },
+	[OLYMPUS_LUT_CHAN_537625_IDX] = { 21505, 0x1, 0x77, 0xF1C72, 0x700 },
+	[OLYMPUS_LUT_CHAN_537750_IDX] = { 21510, 0x1, 0x77, 0x100000, 0x701 },
+	[OLYMPUS_LUT_CHAN_537875_IDX] = { 21515, 0x1, 0x77, 0x10E38E, 0x701 },
+	[OLYMPUS_LUT_CHAN_538000_IDX] = { 21520, 0x1, 0x77, 0x11C71C, 0x701 },
+	[OLYMPUS_LUT_CHAN_538125_IDX] = { 21525, 0x1, 0x77, 0x12AAAB, 0x702 },
+	[OLYMPUS_LUT_CHAN_538250_IDX] = { 21530, 0x1, 0x77, 0x138E39, 0x702 },
+	[OLYMPUS_LUT_CHAN_538375_IDX] = { 21535, 0x1, 0x77, 0x1471C7, 0x703 },
+	[OLYMPUS_LUT_CHAN_538500_IDX] = { 21540, 0x1, 0x77, 0x155555, 0x703 },
+	[OLYMPUS_LUT_CHAN_538625_IDX] = { 21545, 0x1, 0x77, 0x1638E4, 0x703 },
+	[OLYMPUS_LUT_CHAN_538750_IDX] = { 21550, 0x1, 0x77, 0x171C72, 0x704 },
+	[OLYMPUS_LUT_CHAN_538875_IDX] = { 21555, 0x1, 0x77, 0x180000, 0x704 },
+	[OLYMPUS_LUT_CHAN_539000_IDX] = { 21560, 0x1, 0x77, 0x18E38E, 0x705 },
+	[OLYMPUS_LUT_CHAN_539125_IDX] = { 21565, 0x1, 0x77, 0x19C71C, 0x705 },
+	[OLYMPUS_LUT_CHAN_539250_IDX] = { 21570, 0x1, 0x77, 0x1AAAAB, 0x706 },
+	[OLYMPUS_LUT_CHAN_539375_IDX] = { 21575, 0x1, 0x77, 0x1B8E39, 0x706 },
+	[OLYMPUS_LUT_CHAN_539500_IDX] = { 21580, 0x1, 0x77, 0x1C71C7, 0x706 },
+	[OLYMPUS_LUT_CHAN_539625_IDX] = { 21585, 0x1, 0x77, 0x1D5555, 0x707 },
+	[OLYMPUS_LUT_CHAN_539750_IDX] = { 21590, 0x1, 0x77, 0x1E38E4, 0x707 },
+	[OLYMPUS_LUT_CHAN_539875_IDX] = { 21595, 0x1, 0x77, 0x1F1C72, 0x708 },
+	[OLYMPUS_LUT_CHAN_540000_IDX] = { 21600, 0x1, 0x78, 0x0, 0x708 },
+	[OLYMPUS_LUT_CHAN_540125_IDX] = { 21605, 0x1, 0x78, 0xE38E, 0x708 },
+	[OLYMPUS_LUT_CHAN_540250_IDX] = { 21610, 0x1, 0x78, 0x1C71C, 0x709 },
+	[OLYMPUS_LUT_CHAN_540375_IDX] = { 21615, 0x1, 0x78, 0x2AAAB, 0x709 },
+	[OLYMPUS_LUT_CHAN_540500_IDX] = { 21620, 0x1, 0x78, 0x38E39, 0x70A },
+	[OLYMPUS_LUT_CHAN_540625_IDX] = { 21625, 0x1, 0x78, 0x471C7, 0x70A },
+	[OLYMPUS_LUT_CHAN_540750_IDX] = { 21630, 0x1, 0x78, 0x55555, 0x70B },
+	[OLYMPUS_LUT_CHAN_540875_IDX] = { 21635, 0x1, 0x78, 0x638E4, 0x70B },
+	[OLYMPUS_LUT_CHAN_541000_IDX] = { 21640, 0x1, 0x78, 0x71C72, 0x70B },
+	[OLYMPUS_LUT_CHAN_541125_IDX] = { 21645, 0x1, 0x78, 0x80000, 0x70C },
+	[OLYMPUS_LUT_CHAN_541250_IDX] = { 21650, 0x1, 0x78, 0x8E38E, 0x70C },
+	[OLYMPUS_LUT_CHAN_541375_IDX] = { 21655, 0x1, 0x78, 0x9C71C, 0x70D },
+	[OLYMPUS_LUT_CHAN_541500_IDX] = { 21660, 0x1, 0x78, 0xAAAAB, 0x70D },
+	[OLYMPUS_LUT_CHAN_541625_IDX] = { 21665, 0x1, 0x78, 0xB8E39, 0x70D },
+	[OLYMPUS_LUT_CHAN_541750_IDX] = { 21670, 0x1, 0x78, 0xC71C7, 0x70E },
+	[OLYMPUS_LUT_CHAN_541875_IDX] = { 21675, 0x1, 0x78, 0xD5555, 0x70E },
+	[OLYMPUS_LUT_CHAN_542000_IDX] = { 21680, 0x1, 0x78, 0xE38E4, 0x70F },
+	[OLYMPUS_LUT_CHAN_542125_IDX] = { 21685, 0x1, 0x78, 0xF1C72, 0x70F },
+	[OLYMPUS_LUT_CHAN_542250_IDX] = { 21690, 0x1, 0x78, 0x100000, 0x710 },
+	[OLYMPUS_LUT_CHAN_542375_IDX] = { 21695, 0x1, 0x78, 0x10E38E, 0x710 },
+	[OLYMPUS_LUT_CHAN_542500_IDX] = { 21700, 0x1, 0x78, 0x11C71C, 0x710 },
+	[OLYMPUS_LUT_CHAN_542625_IDX] = { 21705, 0x1, 0x78, 0x12AAAB, 0x711 },
+	[OLYMPUS_LUT_CHAN_542750_IDX] = { 21710, 0x1, 0x78, 0x138E39, 0x711 },
+	[OLYMPUS_LUT_CHAN_542875_IDX] = { 21715, 0x1, 0x78, 0x1471C7, 0x712 },
+	[OLYMPUS_LUT_CHAN_543000_IDX] = { 21720, 0x1, 0x78, 0x155555, 0x712 },
+	[OLYMPUS_LUT_CHAN_543125_IDX] = { 21725, 0x1, 0x78, 0x1638E4, 0x712 },
+	[OLYMPUS_LUT_CHAN_543250_IDX] = { 21730, 0x1, 0x78, 0x171C72, 0x713 },
+	[OLYMPUS_LUT_CHAN_543375_IDX] = { 21735, 0x1, 0x78, 0x180000, 0x713 },
+	[OLYMPUS_LUT_CHAN_543500_IDX] = { 21740, 0x1, 0x78, 0x18E38E, 0x714 },
+	[OLYMPUS_LUT_CHAN_543625_IDX] = { 21745, 0x1, 0x78, 0x19C71C, 0x714 },
+	[OLYMPUS_LUT_CHAN_543750_IDX] = { 21750, 0x1, 0x78, 0x1AAAAB, 0x715 },
+	[OLYMPUS_LUT_CHAN_543875_IDX] = { 21755, 0x1, 0x78, 0x1B8E39, 0x715 },
+	[OLYMPUS_LUT_CHAN_544000_IDX] = { 21760, 0x1, 0x78, 0x1C71C7, 0x715 },
+	[OLYMPUS_LUT_CHAN_544125_IDX] = { 21765, 0x1, 0x78, 0x1D5555, 0x716 },
+	[OLYMPUS_LUT_CHAN_544250_IDX] = { 21770, 0x1, 0x78, 0x1E38E4, 0x716 },
+	[OLYMPUS_LUT_CHAN_544375_IDX] = { 21775, 0x1, 0x78, 0x1F1C72, 0x717 },
+	[OLYMPUS_LUT_CHAN_544500_IDX] = { 21780, 0x1, 0x79, 0x0, 0x717 },
+	[OLYMPUS_LUT_CHAN_544625_IDX] = { 21785, 0x1, 0x79, 0xE38E, 0x717 },
+	[OLYMPUS_LUT_CHAN_544750_IDX] = { 21790, 0x1, 0x79, 0x1C71C, 0x718 },
+	[OLYMPUS_LUT_CHAN_544875_IDX] = { 21795, 0x1, 0x79, 0x2AAAB, 0x718 },
+	[OLYMPUS_LUT_CHAN_545000_IDX] = { 21800, 0x1, 0x79, 0x38E39, 0x719 },
+	[OLYMPUS_LUT_CHAN_545125_IDX] = { 21805, 0x1, 0x79, 0x471C7, 0x719 },
+	[OLYMPUS_LUT_CHAN_545250_IDX] = { 21810, 0x1, 0x79, 0x55555, 0x71A },
+	[OLYMPUS_LUT_CHAN_545375_IDX] = { 21815, 0x1, 0x79, 0x638E4, 0x71A },
+	[OLYMPUS_LUT_CHAN_545500_IDX] = { 21820, 0x1, 0x79, 0x71C72, 0x71A },
+	[OLYMPUS_LUT_CHAN_545625_IDX] = { 21825, 0x1, 0x79, 0x80000, 0x71B },
+	[OLYMPUS_LUT_CHAN_545750_IDX] = { 21830, 0x1, 0x79, 0x8E38E, 0x71B },
+	[OLYMPUS_LUT_CHAN_545875_IDX] = { 21835, 0x1, 0x79, 0x9C71C, 0x71C },
+	[OLYMPUS_LUT_CHAN_546000_IDX] = { 21840, 0x1, 0x79, 0xAAAAB, 0x71C },
+	[OLYMPUS_LUT_CHAN_546125_IDX] = { 21845, 0x1, 0x79, 0xB8E39, 0x71C },
+	[OLYMPUS_LUT_CHAN_546250_IDX] = { 21850, 0x1, 0x79, 0xC71C7, 0x71D },
+	[OLYMPUS_LUT_CHAN_546375_IDX] = { 21855, 0x1, 0x79, 0xD5555, 0x71D },
+	[OLYMPUS_LUT_CHAN_546500_IDX] = { 21860, 0x1, 0x79, 0xE38E4, 0x71E },
+	[OLYMPUS_LUT_CHAN_546625_IDX] = { 21865, 0x1, 0x79, 0xF1C72, 0x71E },
+	[OLYMPUS_LUT_CHAN_546750_IDX] = { 21870, 0x1, 0x79, 0x100000, 0x71F },
+	[OLYMPUS_LUT_CHAN_546875_IDX] = { 21875, 0x1, 0x79, 0x10E38E, 0x71F },
+	[OLYMPUS_LUT_CHAN_547000_IDX] = { 21880, 0x1, 0x79, 0x11C71C, 0x71F },
+	[OLYMPUS_LUT_CHAN_547125_IDX] = { 21885, 0x1, 0x79, 0x12AAAB, 0x720 },
+	[OLYMPUS_LUT_CHAN_547250_IDX] = { 21890, 0x1, 0x79, 0x138E39, 0x720 },
+	[OLYMPUS_LUT_CHAN_547375_IDX] = { 21895, 0x1, 0x79, 0x1471C7, 0x721 },
+	[OLYMPUS_LUT_CHAN_547500_IDX] = { 21900, 0x1, 0x79, 0x155555, 0x721 },
+	[OLYMPUS_LUT_CHAN_547625_IDX] = { 21905, 0x1, 0x79, 0x1638E4, 0x721 },
+	[OLYMPUS_LUT_CHAN_547750_IDX] = { 21910, 0x1, 0x79, 0x171C72, 0x722 },
+	[OLYMPUS_LUT_CHAN_547875_IDX] = { 21915, 0x1, 0x79, 0x180000, 0x722 },
+	[OLYMPUS_LUT_CHAN_548000_IDX] = { 21920, 0x1, 0x79, 0x18E38E, 0x723 },
+	[OLYMPUS_LUT_CHAN_548125_IDX] = { 21925, 0x1, 0x79, 0x19C71C, 0x723 },
+	[OLYMPUS_LUT_CHAN_548250_IDX] = { 21930, 0x1, 0x79, 0x1AAAAB, 0x724 },
+	[OLYMPUS_LUT_CHAN_548375_IDX] = { 21935, 0x1, 0x79, 0x1B8E39, 0x724 },
+	[OLYMPUS_LUT_CHAN_548500_IDX] = { 21940, 0x1, 0x79, 0x1C71C7, 0x724 },
+	[OLYMPUS_LUT_CHAN_548625_IDX] = { 21945, 0x1, 0x79, 0x1D5555, 0x725 },
+	[OLYMPUS_LUT_CHAN_548750_IDX] = { 21950, 0x1, 0x79, 0x1E38E4, 0x725 },
+	[OLYMPUS_LUT_CHAN_548875_IDX] = { 21955, 0x1, 0x79, 0x1F1C72, 0x726 },
+	[OLYMPUS_LUT_CHAN_549000_IDX] = { 21960, 0x1, 0x7A, 0x0, 0x726 },
+	[OLYMPUS_LUT_CHAN_549125_IDX] = { 21965, 0x1, 0x7A, 0xE38E, 0x726 },
+	[OLYMPUS_LUT_CHAN_549250_IDX] = { 21970, 0x1, 0x7A, 0x1C71C, 0x727 },
+	[OLYMPUS_LUT_CHAN_549375_IDX] = { 21975, 0x1, 0x7A, 0x2AAAB, 0x727 },
+	[OLYMPUS_LUT_CHAN_549500_IDX] = { 21980, 0x1, 0x7A, 0x38E39, 0x728 },
+	[OLYMPUS_LUT_CHAN_549625_IDX] = { 21985, 0x1, 0x7A, 0x471C7, 0x728 },
+	[OLYMPUS_LUT_CHAN_549750_IDX] = { 21990, 0x1, 0x7A, 0x55555, 0x729 },
+	[OLYMPUS_LUT_CHAN_549875_IDX] = { 21995, 0x1, 0x7A, 0x638E4, 0x729 },
+	[OLYMPUS_LUT_CHAN_550000_IDX] = { 22000, 0x1, 0x7A, 0x71C72, 0x729 },
+	[OLYMPUS_LUT_CHAN_550125_IDX] = { 22005, 0x1, 0x7A, 0x80000, 0x72A },
+	[OLYMPUS_LUT_CHAN_550250_IDX] = { 22010, 0x1, 0x7A, 0x8E38E, 0x72A },
+	[OLYMPUS_LUT_CHAN_550375_IDX] = { 22015, 0x1, 0x7A, 0x9C71C, 0x72B },
+	[OLYMPUS_LUT_CHAN_550500_IDX] = { 22020, 0x1, 0x7A, 0xAAAAB, 0x72B },
+	[OLYMPUS_LUT_CHAN_550625_IDX] = { 22025, 0x1, 0x7A, 0xB8E39, 0x72B },
+	[OLYMPUS_LUT_CHAN_550750_IDX] = { 22030, 0x1, 0x7A, 0xC71C7, 0x72C },
+	[OLYMPUS_LUT_CHAN_550875_IDX] = { 22035, 0x1, 0x7A, 0xD5555, 0x72C },
+	[OLYMPUS_LUT_CHAN_551000_IDX] = { 22040, 0x1, 0x7A, 0xE38E4, 0x72D },
+	[OLYMPUS_LUT_CHAN_551125_IDX] = { 22045, 0x1, 0x7A, 0xF1C72, 0x72D },
+	[OLYMPUS_LUT_CHAN_551250_IDX] = { 22050, 0x1, 0x7A, 0x100000, 0x72E },
+	[OLYMPUS_LUT_CHAN_551375_IDX] = { 22055, 0x1, 0x7A, 0x10E38E, 0x72E },
+	[OLYMPUS_LUT_CHAN_551500_IDX] = { 22060, 0x1, 0x7A, 0x11C71C, 0x72E },
+	[OLYMPUS_LUT_CHAN_551625_IDX] = { 22065, 0x1, 0x7A, 0x12AAAB, 0x72F },
+	[OLYMPUS_LUT_CHAN_551750_IDX] = { 22070, 0x1, 0x7A, 0x138E39, 0x72F },
+	[OLYMPUS_LUT_CHAN_551875_IDX] = { 22075, 0x1, 0x7A, 0x1471C7, 0x730 },
+	[OLYMPUS_LUT_CHAN_552000_IDX] = { 22080, 0x1, 0x7A, 0x155555, 0x730 },
+	[OLYMPUS_LUT_CHAN_552125_IDX] = { 22085, 0x1, 0x7A, 0x1638E4, 0x730 },
+	[OLYMPUS_LUT_CHAN_552250_IDX] = { 22090, 0x1, 0x7A, 0x171C72, 0x731 },
+	[OLYMPUS_LUT_CHAN_552375_IDX] = { 22095, 0x1, 0x7A, 0x180000, 0x731 },
+	[OLYMPUS_LUT_CHAN_552500_IDX] = { 22100, 0x1, 0x7A, 0x18E38E, 0x732 },
+	[OLYMPUS_LUT_CHAN_552625_IDX] = { 22105, 0x1, 0x7A, 0x19C71C, 0x732 },
+	[OLYMPUS_LUT_CHAN_552750_IDX] = { 22110, 0x1, 0x7A, 0x1AAAAB, 0x733 },
+	[OLYMPUS_LUT_CHAN_552875_IDX] = { 22115, 0x1, 0x7A, 0x1B8E39, 0x733 },
+	[OLYMPUS_LUT_CHAN_553000_IDX] = { 22120, 0x1, 0x7A, 0x1C71C7, 0x733 },
+	[OLYMPUS_LUT_CHAN_553125_IDX] = { 22125, 0x1, 0x7A, 0x1D5555, 0x734 },
+	[OLYMPUS_LUT_CHAN_553250_IDX] = { 22130, 0x1, 0x7A, 0x1E38E4, 0x734 },
+	[OLYMPUS_LUT_CHAN_553375_IDX] = { 22135, 0x1, 0x7A, 0x1F1C72, 0x735 },
+	[OLYMPUS_LUT_CHAN_553500_IDX] = { 22140, 0x1, 0x7B, 0x0, 0x735 },
+	[OLYMPUS_LUT_CHAN_553625_IDX] = { 22145, 0x1, 0x7B, 0xE38E, 0x735 },
+	[OLYMPUS_LUT_CHAN_553750_IDX] = { 22150, 0x1, 0x7B, 0x1C71C, 0x736 },
+	[OLYMPUS_LUT_CHAN_553875_IDX] = { 22155, 0x1, 0x7B, 0x2AAAB, 0x736 },
+	[OLYMPUS_LUT_CHAN_554000_IDX] = { 22160, 0x1, 0x7B, 0x38E39, 0x737 },
+	[OLYMPUS_LUT_CHAN_554125_IDX] = { 22165, 0x1, 0x7B, 0x471C7, 0x737 },
+	[OLYMPUS_LUT_CHAN_554250_IDX] = { 22170, 0x1, 0x7B, 0x55555, 0x738 },
+	[OLYMPUS_LUT_CHAN_554375_IDX] = { 22175, 0x1, 0x7B, 0x638E4, 0x738 },
+	[OLYMPUS_LUT_CHAN_554500_IDX] = { 22180, 0x1, 0x7B, 0x71C72, 0x738 },
+	[OLYMPUS_LUT_CHAN_554625_IDX] = { 22185, 0x1, 0x7B, 0x80000, 0x739 },
+	[OLYMPUS_LUT_CHAN_554750_IDX] = { 22190, 0x1, 0x7B, 0x8E38E, 0x739 },
+	[OLYMPUS_LUT_CHAN_554875_IDX] = { 22195, 0x1, 0x7B, 0x9C71C, 0x73A },
+	[OLYMPUS_LUT_CHAN_555000_IDX] = { 22200, 0x1, 0x7B, 0xAAAAB, 0x73A },
+	[OLYMPUS_LUT_CHAN_555125_IDX] = { 22205, 0x1, 0x7B, 0xB8E39, 0x73A },
+	[OLYMPUS_LUT_CHAN_555250_IDX] = { 22210, 0x1, 0x7B, 0xC71C7, 0x73B },
+	[OLYMPUS_LUT_CHAN_555375_IDX] = { 22215, 0x1, 0x7B, 0xD5555, 0x73B },
+	[OLYMPUS_LUT_CHAN_555500_IDX] = { 22220, 0x1, 0x7B, 0xE38E4, 0x73C },
+	[OLYMPUS_LUT_CHAN_555625_IDX] = { 22225, 0x1, 0x7B, 0xF1C72, 0x73C },
+	[OLYMPUS_LUT_CHAN_555750_IDX] = { 22230, 0x1, 0x7B, 0x100000, 0x73D },
+	[OLYMPUS_LUT_CHAN_555875_IDX] = { 22235, 0x1, 0x7B, 0x10E38E, 0x73D },
+	[OLYMPUS_LUT_CHAN_556000_IDX] = { 22240, 0x1, 0x7B, 0x11C71C, 0x73D },
+	[OLYMPUS_LUT_CHAN_556125_IDX] = { 22245, 0x1, 0x7B, 0x12AAAB, 0x73E },
+	[OLYMPUS_LUT_CHAN_556250_IDX] = { 22250, 0x1, 0x7B, 0x138E39, 0x73E },
+	[OLYMPUS_LUT_CHAN_556375_IDX] = { 22255, 0x1, 0x7B, 0x1471C7, 0x73F },
+	[OLYMPUS_LUT_CHAN_556500_IDX] = { 22260, 0x1, 0x7B, 0x155555, 0x73F },
+	[OLYMPUS_LUT_CHAN_556625_IDX] = { 22265, 0x1, 0x7B, 0x1638E4, 0x73F },
+	[OLYMPUS_LUT_CHAN_556750_IDX] = { 22270, 0x1, 0x7B, 0x171C72, 0x740 },
+	[OLYMPUS_LUT_CHAN_556875_IDX] = { 22275, 0x1, 0x7B, 0x180000, 0x740 },
+	[OLYMPUS_LUT_CHAN_557000_IDX] = { 22280, 0x1, 0x7B, 0x18E38E, 0x741 },
+	[OLYMPUS_LUT_CHAN_557125_IDX] = { 22285, 0x1, 0x7B, 0x19C71C, 0x741 },
+	[OLYMPUS_LUT_CHAN_557250_IDX] = { 22290, 0x1, 0x7B, 0x1AAAAB, 0x742 },
+	[OLYMPUS_LUT_CHAN_557375_IDX] = { 22295, 0x1, 0x7B, 0x1B8E39, 0x742 },
+	[OLYMPUS_LUT_CHAN_557500_IDX] = { 22300, 0x1, 0x7B, 0x1C71C7, 0x742 },
+	[OLYMPUS_LUT_CHAN_557625_IDX] = { 22305, 0x1, 0x7B, 0x1D5555, 0x743 },
+	[OLYMPUS_LUT_CHAN_557750_IDX] = { 22310, 0x1, 0x7B, 0x1E38E4, 0x743 },
+	[OLYMPUS_LUT_CHAN_557875_IDX] = { 22315, 0x1, 0x7B, 0x1F1C72, 0x744 },
+	[OLYMPUS_LUT_CHAN_558000_IDX] = { 22320, 0x1, 0x7C, 0x0, 0x744 },
+	[OLYMPUS_LUT_CHAN_558125_IDX] = { 22325, 0x1, 0x7C, 0xE38E, 0x744 },
+	[OLYMPUS_LUT_CHAN_558250_IDX] = { 22330, 0x1, 0x7C, 0x1C71C, 0x745 },
+	[OLYMPUS_LUT_CHAN_558375_IDX] = { 22335, 0x1, 0x7C, 0x2AAAB, 0x745 },
+	[OLYMPUS_LUT_CHAN_558500_IDX] = { 22340, 0x1, 0x7C, 0x38E39, 0x746 },
+	[OLYMPUS_LUT_CHAN_558625_IDX] = { 22345, 0x1, 0x7C, 0x471C7, 0x746 },
+	[OLYMPUS_LUT_CHAN_558750_IDX] = { 22350, 0x1, 0x7C, 0x55555, 0x747 },
+	[OLYMPUS_LUT_CHAN_558875_IDX] = { 22355, 0x1, 0x7C, 0x638E4, 0x747 },
+	[OLYMPUS_LUT_CHAN_559000_IDX] = { 22360, 0x1, 0x7C, 0x71C72, 0x747 },
+	[OLYMPUS_LUT_CHAN_559125_IDX] = { 22365, 0x1, 0x7C, 0x80000, 0x748 },
+	[OLYMPUS_LUT_CHAN_559250_IDX] = { 22370, 0x1, 0x7C, 0x8E38E, 0x748 },
+	[OLYMPUS_LUT_CHAN_559375_IDX] = { 22375, 0x1, 0x7C, 0x9C71C, 0x749 },
+	[OLYMPUS_LUT_CHAN_559500_IDX] = { 22380, 0x1, 0x7C, 0xAAAAB, 0x749 },
+	[OLYMPUS_LUT_CHAN_559625_IDX] = { 22385, 0x1, 0x7C, 0xB8E39, 0x749 },
+	[OLYMPUS_LUT_CHAN_559750_IDX] = { 22390, 0x1, 0x7C, 0xC71C7, 0x74A },
+	[OLYMPUS_LUT_CHAN_559875_IDX] = { 22395, 0x1, 0x7C, 0xD5555, 0x74A },
+	[OLYMPUS_LUT_CHAN_560000_IDX] = { 22400, 0x1, 0x7C, 0xE38E4, 0x74B },
+	[OLYMPUS_LUT_CHAN_560125_IDX] = { 22405, 0x1, 0x7C, 0xF1C72, 0x74B },
+	[OLYMPUS_LUT_CHAN_560250_IDX] = { 22410, 0x1, 0x7C, 0x100000, 0x74C },
+	[OLYMPUS_LUT_CHAN_560375_IDX] = { 22415, 0x1, 0x7C, 0x10E38E, 0x74C },
+	[OLYMPUS_LUT_CHAN_560500_IDX] = { 22420, 0x1, 0x7C, 0x11C71C, 0x74C },
+	[OLYMPUS_LUT_CHAN_560625_IDX] = { 22425, 0x1, 0x7C, 0x12AAAB, 0x74D },
+	[OLYMPUS_LUT_CHAN_560750_IDX] = { 22430, 0x1, 0x7C, 0x138E39, 0x74D },
+	[OLYMPUS_LUT_CHAN_560875_IDX] = { 22435, 0x1, 0x7C, 0x1471C7, 0x74E },
+	[OLYMPUS_LUT_CHAN_561000_IDX] = { 22440, 0x1, 0x7C, 0x155555, 0x74E },
+	[OLYMPUS_LUT_CHAN_561125_IDX] = { 22445, 0x1, 0x7C, 0x1638E4, 0x74E },
+	[OLYMPUS_LUT_CHAN_561250_IDX] = { 22450, 0x1, 0x7C, 0x171C72, 0x74F },
+	[OLYMPUS_LUT_CHAN_561375_IDX] = { 22455, 0x1, 0x7C, 0x180000, 0x74F },
+	[OLYMPUS_LUT_CHAN_561500_IDX] = { 22460, 0x1, 0x7C, 0x18E38E, 0x750 },
+	[OLYMPUS_LUT_CHAN_561625_IDX] = { 22465, 0x1, 0x7C, 0x19C71C, 0x750 },
+	[OLYMPUS_LUT_CHAN_561750_IDX] = { 22470, 0x1, 0x7C, 0x1AAAAB, 0x751 },
+	[OLYMPUS_LUT_CHAN_561875_IDX] = { 22475, 0x1, 0x7C, 0x1B8E39, 0x751 },
+	[OLYMPUS_LUT_CHAN_562000_IDX] = { 22480, 0x1, 0x7C, 0x1C71C7, 0x751 },
+	[OLYMPUS_LUT_CHAN_562125_IDX] = { 22485, 0x1, 0x7C, 0x1D5555, 0x752 },
+	[OLYMPUS_LUT_CHAN_562250_IDX] = { 22490, 0x1, 0x7C, 0x1E38E4, 0x752 },
+	[OLYMPUS_LUT_CHAN_562375_IDX] = { 22495, 0x1, 0x7C, 0x1F1C72, 0x753 },
+	[OLYMPUS_LUT_CHAN_562500_IDX] = { 22500, 0x1, 0x7D, 0x0, 0x753 },
+	[OLYMPUS_LUT_CHAN_562625_IDX] = { 22505, 0x1, 0x7D, 0xE38E, 0x753 },
+	[OLYMPUS_LUT_CHAN_562750_IDX] = { 22510, 0x1, 0x7D, 0x1C71C, 0x754 },
+	[OLYMPUS_LUT_CHAN_562875_IDX] = { 22515, 0x1, 0x7D, 0x2AAAB, 0x754 },
+	[OLYMPUS_LUT_CHAN_563000_IDX] = { 22520, 0x1, 0x7D, 0x38E39, 0x755 },
+	[OLYMPUS_LUT_CHAN_563125_IDX] = { 22525, 0x1, 0x7D, 0x471C7, 0x755 },
+	[OLYMPUS_LUT_CHAN_563250_IDX] = { 22530, 0x1, 0x7D, 0x55555, 0x756 },
+	[OLYMPUS_LUT_CHAN_563375_IDX] = { 22535, 0x1, 0x7D, 0x638E4, 0x756 },
+	[OLYMPUS_LUT_CHAN_563500_IDX] = { 22540, 0x1, 0x7D, 0x71C72, 0x756 },
+	[OLYMPUS_LUT_CHAN_563625_IDX] = { 22545, 0x1, 0x7D, 0x80000, 0x757 },
+	[OLYMPUS_LUT_CHAN_563750_IDX] = { 22550, 0x1, 0x7D, 0x8E38E, 0x757 },
+	[OLYMPUS_LUT_CHAN_563875_IDX] = { 22555, 0x1, 0x7D, 0x9C71C, 0x758 },
+	[OLYMPUS_LUT_CHAN_564000_IDX] = { 22560, 0x1, 0x7D, 0xAAAAB, 0x758 },
+	[OLYMPUS_LUT_CHAN_564125_IDX] = { 22565, 0x1, 0x7D, 0xB8E39, 0x758 },
+	[OLYMPUS_LUT_CHAN_564250_IDX] = { 22570, 0x1, 0x7D, 0xC71C7, 0x759 },
+	[OLYMPUS_LUT_CHAN_564375_IDX] = { 22575, 0x1, 0x7D, 0xD5555, 0x759 },
+	[OLYMPUS_LUT_CHAN_564500_IDX] = { 22580, 0x1, 0x7D, 0xE38E4, 0x75A },
+	[OLYMPUS_LUT_CHAN_564625_IDX] = { 22585, 0x1, 0x7D, 0xF1C72, 0x75A },
+	[OLYMPUS_LUT_CHAN_564750_IDX] = { 22590, 0x1, 0x7D, 0x100000, 0x75B },
+	[OLYMPUS_LUT_CHAN_564875_IDX] = { 22595, 0x1, 0x7D, 0x10E38E, 0x75B },
+	[OLYMPUS_LUT_CHAN_565000_IDX] = { 22600, 0x1, 0x7D, 0x11C71C, 0x75B },
+	[OLYMPUS_LUT_CHAN_565125_IDX] = { 22605, 0x1, 0x7D, 0x12AAAB, 0x75C },
+	[OLYMPUS_LUT_CHAN_565250_IDX] = { 22610, 0x1, 0x7D, 0x138E39, 0x75C },
+	[OLYMPUS_LUT_CHAN_565375_IDX] = { 22615, 0x1, 0x7D, 0x1471C7, 0x75D },
+	[OLYMPUS_LUT_CHAN_565500_IDX] = { 22620, 0x1, 0x7D, 0x155555, 0x75D },
+	[OLYMPUS_LUT_CHAN_565625_IDX] = { 22625, 0x1, 0x7D, 0x1638E4, 0x75D },
+	[OLYMPUS_LUT_CHAN_565750_IDX] = { 22630, 0x1, 0x7D, 0x171C72, 0x75E },
+	[OLYMPUS_LUT_CHAN_565875_IDX] = { 22635, 0x1, 0x7D, 0x180000, 0x75E },
+	[OLYMPUS_LUT_CHAN_566000_IDX] = { 22640, 0x1, 0x7D, 0x18E38E, 0x75F },
+	[OLYMPUS_LUT_CHAN_566125_IDX] = { 22645, 0x1, 0x7D, 0x19C71C, 0x75F },
+	[OLYMPUS_LUT_CHAN_566250_IDX] = { 22650, 0x1, 0x7D, 0x1AAAAB, 0x760 },
+	[OLYMPUS_LUT_CHAN_566375_IDX] = { 22655, 0x1, 0x7D, 0x1B8E39, 0x760 },
+	[OLYMPUS_LUT_CHAN_566500_IDX] = { 22660, 0x1, 0x7D, 0x1C71C7, 0x760 },
+	[OLYMPUS_LUT_CHAN_566625_IDX] = { 22665, 0x1, 0x7D, 0x1D5555, 0x761 },
+	[OLYMPUS_LUT_CHAN_566750_IDX] = { 22670, 0x1, 0x7D, 0x1E38E4, 0x761 },
+	[OLYMPUS_LUT_CHAN_566875_IDX] = { 22675, 0x1, 0x7D, 0x1F1C72, 0x762 },
+	[OLYMPUS_LUT_CHAN_567000_IDX] = { 22680, 0x1, 0x7E, 0x0, 0x762 },
+	[OLYMPUS_LUT_CHAN_567125_IDX] = { 22685, 0x1, 0x7E, 0xE38E, 0x762 },
+	[OLYMPUS_LUT_CHAN_567250_IDX] = { 22690, 0x1, 0x7E, 0x1C71C, 0x763 },
+	[OLYMPUS_LUT_CHAN_567375_IDX] = { 22695, 0x1, 0x7E, 0x2AAAB, 0x763 },
+	[OLYMPUS_LUT_CHAN_567500_IDX] = { 22700, 0x1, 0x7E, 0x38E39, 0x764 },
+	[OLYMPUS_LUT_CHAN_567625_IDX] = { 22705, 0x1, 0x7E, 0x471C7, 0x764 },
+	[OLYMPUS_LUT_CHAN_567750_IDX] = { 22710, 0x1, 0x7E, 0x55555, 0x765 },
+	[OLYMPUS_LUT_CHAN_567875_IDX] = { 22715, 0x1, 0x7E, 0x638E4, 0x765 },
+	[OLYMPUS_LUT_CHAN_568000_IDX] = { 22720, 0x1, 0x7E, 0x71C72, 0x765 },
+	[OLYMPUS_LUT_CHAN_568125_IDX] = { 22725, 0x1, 0x7E, 0x80000, 0x766 },
+	[OLYMPUS_LUT_CHAN_568250_IDX] = { 22730, 0x1, 0x7E, 0x8E38E, 0x766 },
+	[OLYMPUS_LUT_CHAN_568375_IDX] = { 22735, 0x1, 0x7E, 0x9C71C, 0x767 },
+	[OLYMPUS_LUT_CHAN_568500_IDX] = { 22740, 0x1, 0x7E, 0xAAAAB, 0x767 },
+	[OLYMPUS_LUT_CHAN_568625_IDX] = { 22745, 0x1, 0x7E, 0xB8E39, 0x767 },
+	[OLYMPUS_LUT_CHAN_568750_IDX] = { 22750, 0x1, 0x7E, 0xC71C7, 0x768 },
+	[OLYMPUS_LUT_CHAN_568875_IDX] = { 22755, 0x1, 0x7E, 0xD5555, 0x768 },
+	[OLYMPUS_LUT_CHAN_569000_IDX] = { 22760, 0x1, 0x7E, 0xE38E4, 0x769 },
+	[OLYMPUS_LUT_CHAN_569125_IDX] = { 22765, 0x1, 0x7E, 0xF1C72, 0x769 },
+	[OLYMPUS_LUT_CHAN_569250_IDX] = { 22770, 0x1, 0x7E, 0x100000, 0x76A },
+	[OLYMPUS_LUT_CHAN_569375_IDX] = { 22775, 0x1, 0x7E, 0x10E38E, 0x76A },
+	[OLYMPUS_LUT_CHAN_569500_IDX] = { 22780, 0x1, 0x7E, 0x11C71C, 0x76A },
+	[OLYMPUS_LUT_CHAN_569625_IDX] = { 22785, 0x1, 0x7E, 0x12AAAB, 0x76B },
+	[OLYMPUS_LUT_CHAN_569750_IDX] = { 22790, 0x1, 0x7E, 0x138E39, 0x76B },
+	[OLYMPUS_LUT_CHAN_569875_IDX] = { 22795, 0x1, 0x7E, 0x1471C7, 0x76C },
+	[OLYMPUS_LUT_CHAN_570000_IDX] = { 22800, 0x1, 0x7E, 0x155555, 0x76C },
+	[OLYMPUS_LUT_CHAN_570125_IDX] = { 22805, 0x1, 0x7E, 0x1638E4, 0x76C },
+	[OLYMPUS_LUT_CHAN_570250_IDX] = { 22810, 0x1, 0x7E, 0x171C72, 0x76D },
+	[OLYMPUS_LUT_CHAN_570375_IDX] = { 22815, 0x1, 0x7E, 0x180000, 0x76D },
+	[OLYMPUS_LUT_CHAN_570500_IDX] = { 22820, 0x1, 0x7E, 0x18E38E, 0x76E },
+	[OLYMPUS_LUT_CHAN_570625_IDX] = { 22825, 0x1, 0x7E, 0x19C71C, 0x76E },
+	[OLYMPUS_LUT_CHAN_570750_IDX] = { 22830, 0x1, 0x7E, 0x1AAAAB, 0x76F },
+	[OLYMPUS_LUT_CHAN_570875_IDX] = { 22835, 0x1, 0x7E, 0x1B8E39, 0x76F },
+	[OLYMPUS_LUT_CHAN_571000_IDX] = { 22840, 0x1, 0x7E, 0x1C71C7, 0x76F },
+	[OLYMPUS_LUT_CHAN_571125_IDX] = { 22845, 0x1, 0x7E, 0x1D5555, 0x770 },
+	[OLYMPUS_LUT_CHAN_571250_IDX] = { 22850, 0x1, 0x7E, 0x1E38E4, 0x770 },
+	[OLYMPUS_LUT_CHAN_571375_IDX] = { 22855, 0x1, 0x7E, 0x1F1C72, 0x771 },
+	[OLYMPUS_LUT_CHAN_571500_IDX] = { 22860, 0x1, 0x7F, 0x0, 0x771 },
+	[OLYMPUS_LUT_CHAN_571625_IDX] = { 22865, 0x1, 0x7F, 0xE38E, 0x771 },
+	[OLYMPUS_LUT_CHAN_571750_IDX] = { 22870, 0x1, 0x7F, 0x1C71C, 0x772 },
+	[OLYMPUS_LUT_CHAN_571875_IDX] = { 22875, 0x1, 0x7F, 0x2AAAB, 0x772 },
+	[OLYMPUS_LUT_CHAN_572000_IDX] = { 22880, 0x1, 0x7F, 0x38E39, 0x773 },
+	[OLYMPUS_LUT_CHAN_572125_IDX] = { 22885, 0x1, 0x7F, 0x471C7, 0x773 },
+	[OLYMPUS_LUT_CHAN_572250_IDX] = { 22890, 0x1, 0x7F, 0x55555, 0x774 },
+	[OLYMPUS_LUT_CHAN_572375_IDX] = { 22895, 0x1, 0x7F, 0x638E4, 0x774 },
+	[OLYMPUS_LUT_CHAN_572500_IDX] = { 22900, 0x1, 0x7F, 0x71C72, 0x774 },
+	[OLYMPUS_LUT_CHAN_572625_IDX] = { 22905, 0x1, 0x7F, 0x80000, 0x775 },
+	[OLYMPUS_LUT_CHAN_572750_IDX] = { 22910, 0x1, 0x7F, 0x8E38E, 0x775 },
+	[OLYMPUS_LUT_CHAN_572875_IDX] = { 22915, 0x1, 0x7F, 0x9C71C, 0x776 },
+	[OLYMPUS_LUT_CHAN_573000_IDX] = { 22920, 0x1, 0x7F, 0xAAAAB, 0x776 },
+	[OLYMPUS_LUT_CHAN_573125_IDX] = { 22925, 0x1, 0x7F, 0xB8E39, 0x776 },
+	[OLYMPUS_LUT_CHAN_573250_IDX] = { 22930, 0x1, 0x7F, 0xC71C7, 0x777 },
+	[OLYMPUS_LUT_CHAN_573375_IDX] = { 22935, 0x1, 0x7F, 0xD5555, 0x777 },
+	[OLYMPUS_LUT_CHAN_573500_IDX] = { 22940, 0x1, 0x7F, 0xE38E4, 0x778 },
+	[OLYMPUS_LUT_CHAN_573625_IDX] = { 22945, 0x1, 0x7F, 0xF1C72, 0x778 },
+	[OLYMPUS_LUT_CHAN_573750_IDX] = { 22950, 0x1, 0x7F, 0x100000, 0x779 },
+	[OLYMPUS_LUT_CHAN_573875_IDX] = { 22955, 0x1, 0x7F, 0x10E38E, 0x779 },
+	[OLYMPUS_LUT_CHAN_574000_IDX] = { 22960, 0x1, 0x7F, 0x11C71C, 0x779 },
+	[OLYMPUS_LUT_CHAN_574125_IDX] = { 22965, 0x1, 0x7F, 0x12AAAB, 0x77A },
+	[OLYMPUS_LUT_CHAN_574250_IDX] = { 22970, 0x1, 0x7F, 0x138E39, 0x77A },
+	[OLYMPUS_LUT_CHAN_574375_IDX] = { 22975, 0x1, 0x7F, 0x1471C7, 0x77B },
+	[OLYMPUS_LUT_CHAN_574500_IDX] = { 22980, 0x1, 0x7F, 0x155555, 0x77B },
+	[OLYMPUS_LUT_CHAN_574625_IDX] = { 22985, 0x1, 0x7F, 0x1638E4, 0x77B },
+	[OLYMPUS_LUT_CHAN_574750_IDX] = { 22990, 0x1, 0x7F, 0x171C72, 0x77C },
+	[OLYMPUS_LUT_CHAN_574875_IDX] = { 22995, 0x1, 0x7F, 0x180000, 0x77C },
+	[OLYMPUS_LUT_CHAN_575000_IDX] = { 23000, 0x1, 0x7F, 0x18E38E, 0x77D },
+	[OLYMPUS_LUT_CHAN_575125_IDX] = { 23005, 0x1, 0x7F, 0x19C71C, 0x77D },
+	[OLYMPUS_LUT_CHAN_575250_IDX] = { 23010, 0x1, 0x7F, 0x1AAAAB, 0x77E },
+	[OLYMPUS_LUT_CHAN_575375_IDX] = { 23015, 0x1, 0x7F, 0x1B8E39, 0x77E },
+	[OLYMPUS_LUT_CHAN_575500_IDX] = { 23020, 0x1, 0x7F, 0x1C71C7, 0x77E },
+	[OLYMPUS_LUT_CHAN_575625_IDX] = { 23025, 0x1, 0x7F, 0x1D5555, 0x77F },
+	[OLYMPUS_LUT_CHAN_575750_IDX] = { 23030, 0x1, 0x7F, 0x1E38E4, 0x77F },
+	[OLYMPUS_LUT_CHAN_575875_IDX] = { 23035, 0x1, 0x7F, 0x1F1C72, 0x780 },
+	[OLYMPUS_LUT_CHAN_576000_IDX] = { 23040, 0x1, 0x80, 0x0, 0x780 },
+	[OLYMPUS_LUT_CHAN_576125_IDX] = { 23045, 0x1, 0x80, 0xE38E, 0x780 },
+	[OLYMPUS_LUT_CHAN_576250_IDX] = { 23050, 0x1, 0x80, 0x1C71C, 0x781 },
+	[OLYMPUS_LUT_CHAN_576375_IDX] = { 23055, 0x1, 0x80, 0x2AAAB, 0x781 },
+	[OLYMPUS_LUT_CHAN_576500_IDX] = { 23060, 0x1, 0x80, 0x38E39, 0x782 },
+	[OLYMPUS_LUT_CHAN_576625_IDX] = { 23065, 0x1, 0x80, 0x471C7, 0x782 },
+	[OLYMPUS_LUT_CHAN_576750_IDX] = { 23070, 0x1, 0x80, 0x55555, 0x783 },
+	[OLYMPUS_LUT_CHAN_576875_IDX] = { 23075, 0x1, 0x80, 0x638E4, 0x783 },
+	[OLYMPUS_LUT_CHAN_577000_IDX] = { 23080, 0x1, 0x80, 0x71C72, 0x783 },
+	[OLYMPUS_LUT_CHAN_577125_IDX] = { 23085, 0x1, 0x80, 0x80000, 0x784 },
+	[OLYMPUS_LUT_CHAN_577250_IDX] = { 23090, 0x1, 0x80, 0x8E38E, 0x784 },
+	[OLYMPUS_LUT_CHAN_577375_IDX] = { 23095, 0x1, 0x80, 0x9C71C, 0x785 },
+	[OLYMPUS_LUT_CHAN_577500_IDX] = { 23100, 0x1, 0x80, 0xAAAAB, 0x785 },
+	[OLYMPUS_LUT_CHAN_577625_IDX] = { 23105, 0x1, 0x80, 0xB8E39, 0x785 },
+	[OLYMPUS_LUT_CHAN_577750_IDX] = { 23110, 0x1, 0x80, 0xC71C7, 0x786 },
+	[OLYMPUS_LUT_CHAN_577875_IDX] = { 23115, 0x1, 0x80, 0xD5555, 0x786 },
+	[OLYMPUS_LUT_CHAN_578000_IDX] = { 23120, 0x1, 0x80, 0xE38E4, 0x787 },
+	[OLYMPUS_LUT_CHAN_578125_IDX] = { 23125, 0x1, 0x80, 0xF1C72, 0x787 },
+	[OLYMPUS_LUT_CHAN_578250_IDX] = { 23130, 0x1, 0x80, 0x100000, 0x788 },
+	[OLYMPUS_LUT_CHAN_578375_IDX] = { 23135, 0x1, 0x80, 0x10E38E, 0x788 },
+	[OLYMPUS_LUT_CHAN_578500_IDX] = { 23140, 0x1, 0x80, 0x11C71C, 0x788 },
+	[OLYMPUS_LUT_CHAN_578625_IDX] = { 23145, 0x1, 0x80, 0x12AAAB, 0x789 },
+	[OLYMPUS_LUT_CHAN_578750_IDX] = { 23150, 0x1, 0x80, 0x138E39, 0x789 },
+	[OLYMPUS_LUT_CHAN_578875_IDX] = { 23155, 0x1, 0x80, 0x1471C7, 0x78A },
+	[OLYMPUS_LUT_CHAN_579000_IDX] = { 23160, 0x1, 0x80, 0x155555, 0x78A },
+	[OLYMPUS_LUT_CHAN_579125_IDX] = { 23165, 0x1, 0x80, 0x1638E4, 0x78A },
+	[OLYMPUS_LUT_CHAN_579250_IDX] = { 23170, 0x1, 0x80, 0x171C72, 0x78B },
+	[OLYMPUS_LUT_CHAN_579375_IDX] = { 23175, 0x1, 0x80, 0x180000, 0x78B },
+	[OLYMPUS_LUT_CHAN_579500_IDX] = { 23180, 0x1, 0x80, 0x18E38E, 0x78C },
+	[OLYMPUS_LUT_CHAN_579625_IDX] = { 23185, 0x1, 0x80, 0x19C71C, 0x78C },
+	[OLYMPUS_LUT_CHAN_579750_IDX] = { 23190, 0x1, 0x80, 0x1AAAAB, 0x78D },
+	[OLYMPUS_LUT_CHAN_579875_IDX] = { 23195, 0x1, 0x80, 0x1B8E39, 0x78D },
+	[OLYMPUS_LUT_CHAN_580000_IDX] = { 23200, 0x1, 0x80, 0x1C71C7, 0x78D },
+	[OLYMPUS_LUT_CHAN_580125_IDX] = { 23205, 0x1, 0x80, 0x1D5555, 0x78E },
+	[OLYMPUS_LUT_CHAN_580250_IDX] = { 23210, 0x1, 0x80, 0x1E38E4, 0x78E },
+	[OLYMPUS_LUT_CHAN_580375_IDX] = { 23215, 0x1, 0x80, 0x1F1C72, 0x78F },
+	[OLYMPUS_LUT_CHAN_580500_IDX] = { 23220, 0x1, 0x81, 0x0, 0x78F },
+	[OLYMPUS_LUT_CHAN_580625_IDX] = { 23225, 0x1, 0x81, 0xE38E, 0x78F },
+	[OLYMPUS_LUT_CHAN_580750_IDX] = { 23230, 0x1, 0x81, 0x1C71C, 0x790 },
+	[OLYMPUS_LUT_CHAN_580875_IDX] = { 23235, 0x1, 0x81, 0x2AAAB, 0x790 },
+	[OLYMPUS_LUT_CHAN_581000_IDX] = { 23240, 0x1, 0x81, 0x38E39, 0x791 },
+	[OLYMPUS_LUT_CHAN_581125_IDX] = { 23245, 0x1, 0x81, 0x471C7, 0x791 },
+	[OLYMPUS_LUT_CHAN_581250_IDX] = { 23250, 0x1, 0x81, 0x55555, 0x792 },
+	[OLYMPUS_LUT_CHAN_581375_IDX] = { 23255, 0x1, 0x81, 0x638E4, 0x792 },
+	[OLYMPUS_LUT_CHAN_581500_IDX] = { 23260, 0x1, 0x81, 0x71C72, 0x792 },
+	[OLYMPUS_LUT_CHAN_581625_IDX] = { 23265, 0x1, 0x81, 0x80000, 0x793 },
+	[OLYMPUS_LUT_CHAN_581750_IDX] = { 23270, 0x1, 0x81, 0x8E38E, 0x793 },
+	[OLYMPUS_LUT_CHAN_581875_IDX] = { 23275, 0x1, 0x81, 0x9C71C, 0x794 },
+	[OLYMPUS_LUT_CHAN_582000_IDX] = { 23280, 0x1, 0x81, 0xAAAAB, 0x794 },
+	[OLYMPUS_LUT_CHAN_582125_IDX] = { 23285, 0x1, 0x81, 0xB8E39, 0x794 },
+	[OLYMPUS_LUT_CHAN_582250_IDX] = { 23290, 0x1, 0x81, 0xC71C7, 0x795 },
+	[OLYMPUS_LUT_CHAN_582375_IDX] = { 23295, 0x1, 0x81, 0xD5555, 0x795 },
+	[OLYMPUS_LUT_CHAN_582500_IDX] = { 23300, 0x1, 0x81, 0xE38E4, 0x796 },
+	[OLYMPUS_LUT_CHAN_582625_IDX] = { 23305, 0x1, 0x81, 0xF1C72, 0x796 },
+	[OLYMPUS_LUT_CHAN_582750_IDX] = { 23310, 0x1, 0x81, 0x100000, 0x797 },
+	[OLYMPUS_LUT_CHAN_582875_IDX] = { 23315, 0x1, 0x81, 0x10E38E, 0x797 },
+	[OLYMPUS_LUT_CHAN_583000_IDX] = { 23320, 0x1, 0x81, 0x11C71C, 0x797 },
+	[OLYMPUS_LUT_CHAN_583125_IDX] = { 23325, 0x1, 0x81, 0x12AAAB, 0x798 },
+	[OLYMPUS_LUT_CHAN_583250_IDX] = { 23330, 0x1, 0x81, 0x138E39, 0x798 },
+	[OLYMPUS_LUT_CHAN_583375_IDX] = { 23335, 0x1, 0x81, 0x1471C7, 0x799 },
+	[OLYMPUS_LUT_CHAN_583500_IDX] = { 23340, 0x1, 0x81, 0x155555, 0x799 },
+	[OLYMPUS_LUT_CHAN_583625_IDX] = { 23345, 0x1, 0x81, 0x1638E4, 0x799 },
+	[OLYMPUS_LUT_CHAN_583750_IDX] = { 23350, 0x1, 0x81, 0x171C72, 0x79A },
+	[OLYMPUS_LUT_CHAN_583875_IDX] = { 23355, 0x1, 0x81, 0x180000, 0x79A },
+	[OLYMPUS_LUT_CHAN_584000_IDX] = { 23360, 0x1, 0x81, 0x18E38E, 0x79B },
+	[OLYMPUS_LUT_CHAN_584125_IDX] = { 23365, 0x1, 0x81, 0x19C71C, 0x79B },
+	[OLYMPUS_LUT_CHAN_584250_IDX] = { 23370, 0x1, 0x81, 0x1AAAAB, 0x79C },
+	[OLYMPUS_LUT_CHAN_584375_IDX] = { 23375, 0x1, 0x81, 0x1B8E39, 0x79C },
+	[OLYMPUS_LUT_CHAN_584500_IDX] = { 23380, 0x1, 0x81, 0x1C71C7, 0x79C },
+	[OLYMPUS_LUT_CHAN_584625_IDX] = { 23385, 0x1, 0x81, 0x1D5555, 0x79D },
+	[OLYMPUS_LUT_CHAN_584750_IDX] = { 23390, 0x1, 0x81, 0x1E38E4, 0x79D },
+	[OLYMPUS_LUT_CHAN_584875_IDX] = { 23395, 0x1, 0x81, 0x1F1C72, 0x79E },
+	[OLYMPUS_LUT_CHAN_585000_IDX] = { 23400, 0x1, 0x82, 0x0, 0x79E },
+	[OLYMPUS_LUT_CHAN_585125_IDX] = { 23405, 0x1, 0x82, 0xE38E, 0x79E },
+	[OLYMPUS_LUT_CHAN_585250_IDX] = { 23410, 0x1, 0x82, 0x1C71C, 0x79F },
+	[OLYMPUS_LUT_CHAN_585375_IDX] = { 23415, 0x1, 0x82, 0x2AAAB, 0x79F },
+	[OLYMPUS_LUT_CHAN_585500_IDX] = { 23420, 0x1, 0x82, 0x38E39, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585625_IDX] = { 23425, 0x1, 0x82, 0x471C7, 0x7A0 },
+	[OLYMPUS_LUT_CHAN_585750_IDX] = { 23430, 0x1, 0x82, 0x55555, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_585875_IDX] = { 23435, 0x1, 0x82, 0x638E4, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586000_IDX] = { 23440, 0x1, 0x82, 0x71C72, 0x7A1 },
+	[OLYMPUS_LUT_CHAN_586125_IDX] = { 23445, 0x1, 0x82, 0x80000, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586250_IDX] = { 23450, 0x1, 0x82, 0x8E38E, 0x7A2 },
+	[OLYMPUS_LUT_CHAN_586375_IDX] = { 23455, 0x1, 0x82, 0x9C71C, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586500_IDX] = { 23460, 0x1, 0x82, 0xAAAAB, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586625_IDX] = { 23465, 0x1, 0x82, 0xB8E39, 0x7A3 },
+	[OLYMPUS_LUT_CHAN_586750_IDX] = { 23470, 0x1, 0x82, 0xC71C7, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_586875_IDX] = { 23475, 0x1, 0x82, 0xD5555, 0x7A4 },
+	[OLYMPUS_LUT_CHAN_587000_IDX] = { 23480, 0x1, 0x82, 0xE38E4, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587125_IDX] = { 23485, 0x1, 0x82, 0xF1C72, 0x7A5 },
+	[OLYMPUS_LUT_CHAN_587250_IDX] = { 23490, 0x1, 0x82, 0x100000, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587375_IDX] = { 23495, 0x1, 0x82, 0x10E38E, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587500_IDX] = { 23500, 0x1, 0x82, 0x11C71C, 0x7A6 },
+	[OLYMPUS_LUT_CHAN_587625_IDX] = { 23505, 0x1, 0x82, 0x12AAAB, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587750_IDX] = { 23510, 0x1, 0x82, 0x138E39, 0x7A7 },
+	[OLYMPUS_LUT_CHAN_587875_IDX] = { 23515, 0x1, 0x82, 0x1471C7, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588000_IDX] = { 23520, 0x1, 0x82, 0x155555, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588125_IDX] = { 23525, 0x1, 0x82, 0x1638E4, 0x7A8 },
+	[OLYMPUS_LUT_CHAN_588250_IDX] = { 23530, 0x1, 0x82, 0x171C72, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588375_IDX] = { 23535, 0x1, 0x82, 0x180000, 0x7A9 },
+	[OLYMPUS_LUT_CHAN_588500_IDX] = { 23540, 0x1, 0x82, 0x18E38E, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588625_IDX] = { 23545, 0x1, 0x82, 0x19C71C, 0x7AA },
+	[OLYMPUS_LUT_CHAN_588750_IDX] = { 23550, 0x1, 0x82, 0x1AAAAB, 0x7AB },
+	[OLYMPUS_LUT_CHAN_588875_IDX] = { 23555, 0x1, 0x82, 0x1B8E39, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589000_IDX] = { 23560, 0x1, 0x82, 0x1C71C7, 0x7AB },
+	[OLYMPUS_LUT_CHAN_589125_IDX] = { 23565, 0x1, 0x82, 0x1D5555, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589250_IDX] = { 23570, 0x1, 0x82, 0x1E38E4, 0x7AC },
+	[OLYMPUS_LUT_CHAN_589375_IDX] = { 23575, 0x1, 0x82, 0x1F1C72, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589500_IDX] = { 23580, 0x1, 0x83, 0x0, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589625_IDX] = { 23585, 0x1, 0x83, 0xE38E, 0x7AD },
+	[OLYMPUS_LUT_CHAN_589750_IDX] = { 23590, 0x1, 0x83, 0x1C71C, 0x7AE },
+	[OLYMPUS_LUT_CHAN_589875_IDX] = { 23595, 0x1, 0x83, 0x2AAAB, 0x7AE },
+	[OLYMPUS_LUT_CHAN_590000_IDX] = { 23600, 0x1, 0x83, 0x38E39, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590125_IDX] = { 23605, 0x1, 0x83, 0x471C7, 0x7AF },
+	[OLYMPUS_LUT_CHAN_590250_IDX] = { 23610, 0x1, 0x83, 0x55555, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590375_IDX] = { 23615, 0x1, 0x83, 0x638E4, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590500_IDX] = { 23620, 0x1, 0x83, 0x71C72, 0x7B0 },
+	[OLYMPUS_LUT_CHAN_590625_IDX] = { 23625, 0x1, 0x83, 0x80000, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590750_IDX] = { 23630, 0x1, 0x83, 0x8E38E, 0x7B1 },
+	[OLYMPUS_LUT_CHAN_590875_IDX] = { 23635, 0x1, 0x83, 0x9C71C, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591000_IDX] = { 23640, 0x1, 0x83, 0xAAAAB, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591125_IDX] = { 23645, 0x1, 0x83, 0xB8E39, 0x7B2 },
+	[OLYMPUS_LUT_CHAN_591250_IDX] = { 23650, 0x1, 0x83, 0xC71C7, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591375_IDX] = { 23655, 0x1, 0x83, 0xD5555, 0x7B3 },
+	[OLYMPUS_LUT_CHAN_591500_IDX] = { 23660, 0x1, 0x83, 0xE38E4, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591625_IDX] = { 23665, 0x1, 0x83, 0xF1C72, 0x7B4 },
+	[OLYMPUS_LUT_CHAN_591750_IDX] = { 23670, 0x1, 0x83, 0x100000, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_591875_IDX] = { 23675, 0x1, 0x83, 0x10E38E, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592000_IDX] = { 23680, 0x1, 0x83, 0x11C71C, 0x7B5 },
+	[OLYMPUS_LUT_CHAN_592125_IDX] = { 23685, 0x1, 0x83, 0x12AAAB, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592250_IDX] = { 23690, 0x1, 0x83, 0x138E39, 0x7B6 },
+	[OLYMPUS_LUT_CHAN_592375_IDX] = { 23695, 0x1, 0x83, 0x1471C7, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592500_IDX] = { 23700, 0x1, 0x83, 0x155555, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592625_IDX] = { 23705, 0x1, 0x83, 0x1638E4, 0x7B7 },
+	[OLYMPUS_LUT_CHAN_592750_IDX] = { 23710, 0x1, 0x83, 0x171C72, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_592875_IDX] = { 23715, 0x1, 0x83, 0x180000, 0x7B8 },
+	[OLYMPUS_LUT_CHAN_593000_IDX] = { 23720, 0x1, 0x83, 0x18E38E, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593125_IDX] = { 23725, 0x1, 0x83, 0x19C71C, 0x7B9 },
+	[OLYMPUS_LUT_CHAN_593250_IDX] = { 23730, 0x1, 0x83, 0x1AAAAB, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593375_IDX] = { 23735, 0x1, 0x83, 0x1B8E39, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593500_IDX] = { 23740, 0x1, 0x83, 0x1C71C7, 0x7BA },
+	[OLYMPUS_LUT_CHAN_593625_IDX] = { 23745, 0x1, 0x83, 0x1D5555, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593750_IDX] = { 23750, 0x1, 0x83, 0x1E38E4, 0x7BB },
+	[OLYMPUS_LUT_CHAN_593875_IDX] = { 23755, 0x1, 0x83, 0x1F1C72, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594000_IDX] = { 23760, 0x1, 0x84, 0x0, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594125_IDX] = { 23765, 0x1, 0x84, 0xE38E, 0x7BC },
+	[OLYMPUS_LUT_CHAN_594250_IDX] = { 23770, 0x1, 0x84, 0x1C71C, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594375_IDX] = { 23775, 0x1, 0x84, 0x2AAAB, 0x7BD },
+	[OLYMPUS_LUT_CHAN_594500_IDX] = { 23780, 0x1, 0x84, 0x38E39, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594625_IDX] = { 23785, 0x1, 0x84, 0x471C7, 0x7BE },
+	[OLYMPUS_LUT_CHAN_594750_IDX] = { 23790, 0x1, 0x84, 0x55555, 0x7BF },
+	[OLYMPUS_LUT_CHAN_594875_IDX] = { 23795, 0x1, 0x84, 0x638E4, 0x7BF },
+	[OLYMPUS_LUT_CHAN_595000_IDX] = { 23800, 0x1, 0x84, 0x71C72, 0x7BF }
+};
+
+static void cl_ceva_disable(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_hw_is_tcv0(cl_hw)) {
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 0);
+	} else {
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 0);
+	}
+}
+
+static void cl_ceva_reset(struct cl_hw *cl_hw)
+{
+	if (cl_hw_is_tcv0(cl_hw))
+		cmu_phy_0_rst_set(cl_hw->chip, CMU_PHY0_RST_EN);
+	else
+		cmu_phy_1_rst_set(cl_hw->chip, CMU_PHY1_RST_EN);
+}
+
+static void cl_phy_disable(struct cl_hw *cl_hw)
+{
+	/* Modem GCU modules - Reset */
+
+	/* Disable clocks (reset is not asserted) */
+	modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+	modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+			  MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+	modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+	modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+	modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+	modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+	modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+	modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+			  MODEM_GCU_LCU_REG_RST_N_BIT);
+	modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+			      MODEM_GCU_MUX_FIC_RST_N_BIT);
+	modem_gcu_riu_clk_set(cl_hw, 0);
+	modem_gcu_riu_clk_1_set(cl_hw, 0);
+
+	/* Assert reset (clocks already disabled) */
+	modem_gcu_mpu_set(cl_hw, 0);
+	modem_gcu_bpu_set(cl_hw, 0);
+	modem_gcu_tfu_set(cl_hw, 0);
+	modem_gcu_smu_set(cl_hw, 0);
+	modem_gcu_spu_set(cl_hw, 0);
+	modem_gcu_bf_set(cl_hw, 0);
+	modem_gcu_epa_set(cl_hw, 0);
+	modem_gcu_lcu_set(cl_hw, 0);
+	modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT);
+	modem_gcu_riu_rst_set(cl_hw, 0);
+}
+
+static void _cl_phy_reset(struct cl_hw *cl_hw)
+{
+	/* Isolate FIC bus in case CEVA reset is not required */
+	modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 1);
+	while (modem_gcu_mux_fic_config_fic_isolated_getf(cl_hw) == 0)
+		;
+	modem_gcu_mux_fic_config_fic_isolate_setf(cl_hw, 0);
+
+	/*
+	 * Stop the LCU recording.
+	 * Stop on one channel actually stops the recording on all channels.
+	 * This stop is required because PHY LCU is going to be reset.
+	 */
+	if (cl_hw_is_tcv0(cl_hw))
+		lcu_phy_lcu_ch_0_stop_set(cl_hw, 1);
+	else
+		lcu_phy_lcu_ch_1_stop_set(cl_hw, 1);
+
+	/* PHY reset sequence */
+	cl_phy_disable(cl_hw);
+}
+
+static void _cl_phy0_off(struct cl_chip *chip)
+{
+	/* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+	cmu_phy_0_clk_en_pack(chip, 1, 0, 1);
+	/* DSP0, MPIF0, APB0 reset */
+	cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+	/* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+	cmu_phy_0_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+	/* Enable APB0 clock (all other clocks are already active) */
+	cmu_phy_0_clk_en_phy_0_apb_clk_en_setf(chip, 1);
+}
+
+static void _cl_phy1_off(struct cl_chip *chip)
+{
+	/* Disable APB0 clock but keep other clocks (main clock and DSP0 clock) active */
+	cmu_phy_1_clk_en_pack(chip, 1, 0, 1);
+	/* DSP0, MPIF0, APB0 reset */
+	cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT);
+	/* DSP0, MPIF0 are still in reset, but take APB0 out of reset to allow writing to GCU */
+	cmu_phy_1_rst_set(chip, CMU_PHY_0_RST_N_BIT | CMU_PHY_0_PRESET_N_BIT);
+	/* Enable APB0 clock (all other clocks are already active) */
+	cmu_phy_1_clk_en_phy_1_apb_clk_en_setf(chip, 1);
+}
+
+static void _cl_phy_off(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (cl_hw_is_tcv0(cl_hw))
+		_cl_phy0_off(chip);
+	else
+		_cl_phy1_off(chip);
+
+	cl_phy_disable(cl_hw);
+}
+
+static void cl_system_ctrl_reg_reset(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	u32 regval = macsys_gcu_xt_control_get(chip);
+	u8 i;
+
+	/* Set XMAC_RUN_STALL */
+	regval |= cl_hw->controller_reg.run_stall;
+	/* Clear XMAC_OCD_HALT_ON_RESET and clear XMAC_BRESET */
+	regval &= ~(cl_hw->controller_reg.ocd_halt_on_reset | cl_hw->controller_reg.breset);
+
+	/* Reset MACHW */
+	macsys_gcu_xt_control_set(chip, regval);
+
+	for (i = 0; i < MAX_MU_CNT; i++)
+		mac_hw_mu_mac_cntrl_2_set(cl_hw, 1, i);
+}
+
+void cl_phy_off(struct cl_hw *cl_hw)
+{
+	if (!cl_hw)
+		return;
+
+	cl_system_ctrl_reg_reset(cl_hw);
+	_cl_phy_off(cl_hw);
+	cl_ceva_disable(cl_hw);
+}
+
+static void cl_save_ela_state(struct cl_hw *cl_hw)
+{
+	struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+	/* Save eLA state before MAC-HW reset */
+	recovery_db->ela_en = mac_hw_debug_port_en_get(cl_hw);
+
+	if (recovery_db->ela_en) {
+		recovery_db->ela_sel_a = mac_hw_debug_port_sel_a_get(cl_hw);
+		recovery_db->ela_sel_b = mac_hw_debug_port_sel_b_get(cl_hw);
+		recovery_db->ela_sel_c = mac_hw_debug_port_sel_c_get(cl_hw);
+	}
+}
+
+void cl_phy_reset(struct cl_hw *cl_hw)
+{
+	if (!cl_hw)
+		return;
+
+	cl_save_ela_state(cl_hw);
+	cl_system_ctrl_reg_reset(cl_hw);
+	_cl_phy_reset(cl_hw);
+	cl_ceva_reset(cl_hw);
+}
+
+int cl_phy_load_recovery(struct cl_hw *cl_hw)
+{
+	int ret = cl_radio_boot_recovery(cl_hw);
+
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_radio_boot_recovery failed %d\n", ret);
+		return ret;
+	}
+
+	/* Load DSP */
+	ret = cl_dsp_load_recovery(cl_hw);
+	if (ret) {
+		cl_dbg_err(cl_hw, "cl_dsp_load_recovery failed %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * FIXME: It looks like there is a bug in the DSP. If we poll REG_CFG_SPACE
+	 * (0x600018) at this point to verify that DSP has been initialized
+	 * successfully, we read '1' and continue.
+	 * However, the calibration fails.
+	 *
+	 * Please note that this is a WORKAROUND, not a final fix.
+	 * The problem should be investigated
+	 * further by the DSP team.
+	 */
+	msleep(500);
+	return 0;
+}
+
+int cl_phy_data_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_phy_data *buf = NULL;
+	u32 len = (u32)PAGE_SIZE;
+	dma_addr_t phys_dma_addr;
+
+	buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cl_hw->phy_data_info.data = buf;
+	cl_hw->phy_data_info.dma_addr = phys_dma_addr;
+
+	return 0;
+}
+
+void cl_phy_data_free(struct cl_hw *cl_hw)
+{
+	dma_addr_t phys_dma_addr = cl_hw->phy_data_info.dma_addr;
+
+	if (!cl_hw->phy_data_info.data)
+		return;
+
+	dma_free_coherent(cl_hw->chip->dev, PAGE_SIZE,
+			  (void *)cl_hw->phy_data_info.data, phys_dma_addr);
+	cl_hw->phy_data_info.data = NULL;
+}
+
+void cl_phy_enable(struct cl_hw *cl_hw)
+{
+	/* Modem GCU modules - De-assert Reset */
+	if (!cl_hw)
+		return;
+
+	/* De-assert reset (clocks disabled) */
+	modem_gcu_mpu_set(cl_hw, MODEM_GCU_MPU_RST_N_BIT | MODEM_GCU_MPU_REG_RST_N_BIT);
+	modem_gcu_bpu_set(cl_hw, MODEM_GCU_BPU_RST_N_BIT | MODEM_GCU_BPU_RX_RST_N_BIT |
+			  MODEM_GCU_BPU_TX_RST_N_BIT | MODEM_GCU_BPU_REG_RST_N_BIT);
+	modem_gcu_tfu_set(cl_hw, MODEM_GCU_TFU_RST_N_BIT | MODEM_GCU_TFU_REG_RST_N_BIT);
+	modem_gcu_smu_set(cl_hw, MODEM_GCU_SMU_RST_N_BIT | MODEM_GCU_SMU_REG_RST_N_BIT);
+	modem_gcu_spu_set(cl_hw, MODEM_GCU_SPU_RST_N_BIT | MODEM_GCU_SPU_REG_RST_N_BIT);
+	modem_gcu_bf_set(cl_hw, MODEM_GCU_BF_RST_N_BIT | MODEM_GCU_BF_REG_RST_N_BIT);
+	modem_gcu_epa_set(cl_hw, MODEM_GCU_EPA_RST_N_BIT | MODEM_GCU_EPA_REG_RST_N_BIT);
+	modem_gcu_lcu_set(cl_hw, MODEM_GCU_LCU_HLF_RST_N_BIT | MODEM_GCU_LCU_RST_N_BIT |
+			  MODEM_GCU_LCU_REG_RST_N_BIT);
+	modem_gcu_mux_fic_set(cl_hw, MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT |
+			      MODEM_GCU_MUX_FIC_RST_N_BIT);
+	modem_gcu_riu_rst_set(cl_hw, MODEM_GCU_RIU_FE_RST_N_BIT | MODEM_GCU_RIU_AGC_RST_N_BIT |
+			      MODEM_GCU_RIU_MDM_B_RST_N_BIT | MODEM_GCU_RIU_LB_RST_N_BIT |
+			      MODEM_GCU_RIU_RC_RST_N_BIT | MODEM_GCU_RIU_RADAR_RST_N_BIT |
+			      MODEM_GCU_RIU_RST_N_BIT | MODEM_GCU_RIU_REG_RST_N_BIT);
+
+	/* Enable clocks */
+	modem_gcu_mpu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_bpu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_tfu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_smu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_spu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_bf_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_epa_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_lcu_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_mux_fic_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+	modem_gcu_riu_clk_1_set(cl_hw, 0xFFFFFFFF);
+
+	/*
+	 * Configure minimum latency between 2 masters connected
+	 * to same FIC, Read/Write transaction
+	 */
+	modem_gcu_mux_fic_config_set(cl_hw, 0x00000808);
+}
+
+static const struct common_lut_line *
+cl_phy_oly_get_lut_index(const struct common_lut_line *lut_table,
+			 const u16 lut_table_size, u16 freq)
+{
+	u16 frequency_idx;
+
+	/* Fine highest frequency in  lut table that is lower or equal freq */
+	for (frequency_idx = 0;
+		frequency_idx < lut_table_size && lut_table[frequency_idx].frequency_q2 <= freq;
+		++frequency_idx)
+		;
+
+	if (frequency_idx)
+		frequency_idx--;
+
+	return &lut_table[frequency_idx];
+}
+
+static void cl_phy_lut_2_lines_update(u16 freq,
+				      const struct common_lut_line *lut_table_60m,
+				      const u16 lut_table_60m_size,
+				      const struct common_lut_line *lut_table_40m,
+				      const u16 lut_table_40m_size,
+				      struct mm_mac_api_lut_line *api_lut_line)
+{
+	/* 1. configure the 40M xco lut table */
+	const struct common_lut_line *data_line =
+		cl_phy_oly_get_lut_index(lut_table_40m, lut_table_40m_size, freq);
+
+	api_lut_line->rfic_specific.olympus_2_lines.xco_40M.freqmeastarg =
+		cpu_to_le32(data_line->freqmeastarg);
+	api_lut_line->rfic_specific.olympus_2_lines.xco_40M.nfrac =
+		cpu_to_le32(data_line->nfrac);
+	api_lut_line->rfic_specific.olympus_2_lines.xco_40M.nint =
+		data_line->nint;
+	api_lut_line->rfic_specific.olympus_2_lines.xco_40M.vcocalsel =
+		data_line->vcocalsel;
+
+	/* 2. configure the 60M xco lut table */
+	data_line = cl_phy_oly_get_lut_index(lut_table_60m, lut_table_60m_size, freq);
+	api_lut_line->rfic_specific.olympus_2_lines.xco_60M.freqmeastarg =
+		cpu_to_le32(data_line->freqmeastarg);
+	api_lut_line->rfic_specific.olympus_2_lines.xco_60M.nfrac =
+		cpu_to_le32(data_line->nfrac);
+	api_lut_line->rfic_specific.olympus_2_lines.xco_60M.nint =
+		data_line->nint;
+	api_lut_line->rfic_specific.olympus_2_lines.xco_60M.vcocalsel =
+		data_line->vcocalsel;
+
+	/* 3. set frequency */
+	api_lut_line->frequency_q2 = cpu_to_le16(freq);
+}
+
+static void cl_phy_lut_3_lines_update(u16 freq,
+				      const struct common_lut_line *lut_table_60m_s1,
+				      const u16 lut_table_60m_s1_size,
+				      const struct common_lut_line *lut_table_60m_s0,
+				      const u16 lut_table_60m_s0_size,
+				      const struct common_lut_line *lut_table_40m,
+				      const u16 lut_table_40m_size,
+				      struct mm_mac_api_lut_line *api_lut_line)
+{
+	/* 1. configure the 40M xco lut table */
+	const struct common_lut_line *data_line =
+	cl_phy_oly_get_lut_index(lut_table_40m, lut_table_40m_size, freq);
+
+	api_lut_line->rfic_specific.olympus_3_lines.xco_40M.freqmeastarg =
+	cpu_to_le32(data_line->freqmeastarg);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_40M.nfrac =
+	cpu_to_le32(data_line->nfrac);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_40M.nint =
+	data_line->nint;
+	api_lut_line->rfic_specific.olympus_3_lines.xco_40M.vcocalsel =
+	data_line->vcocalsel;
+
+	/* 2. configure the 60M xco lut table , sxpfddesel=1*/
+	data_line = cl_phy_oly_get_lut_index(lut_table_60m_s1, lut_table_60m_s1_size, freq);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.freqmeastarg =
+	cpu_to_le32(data_line->freqmeastarg);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.nfrac =
+	cpu_to_le32(data_line->nfrac);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.nint =
+	data_line->nint;
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s1.vcocalsel =
+	data_line->vcocalsel;
+
+	/* 3. configure the 60M xco lut table , sxpfddesel=0*/
+	data_line = cl_phy_oly_get_lut_index(lut_table_60m_s0, lut_table_60m_s0_size, freq);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.freqmeastarg =
+	cpu_to_le32(data_line->freqmeastarg);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.nfrac =
+	cpu_to_le32(data_line->nfrac);
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.nint =
+	data_line->nint;
+	api_lut_line->rfic_specific.olympus_3_lines.xco_60M_s0.vcocalsel =
+	data_line->vcocalsel;
+
+	/* 4. set frequency */
+	api_lut_line->frequency_q2 = cpu_to_le16(freq);
+}
+
+void cl_phy_oly_lut_update(u8 rfic_version, u8 nl_band, u16 freq,
+			   struct mm_mac_api_lut_line *api_lut_line)
+{
+	switch (nl_band) {
+	case NL80211_BAND_2GHZ:
+		cl_phy_lut_3_lines_update(freq,
+					  olympus_lut_24g_60_mhz_s1,
+					  OLYMPUS_LUT_CHAN_24G_MAX,
+					  olympus_lut_24g_60_mhz_s0,
+					  OLYMPUS_LUT_CHAN_24G_MAX,
+					  olympus_lut_24g_40_mhz,
+					  OLYMPUS_LUT_CHAN_24G_MAX,
+					  api_lut_line);
+		break;
+	case NL80211_BAND_5GHZ:
+		if (rfic_version == ATHOS_B_VER)
+			cl_phy_lut_2_lines_update(freq,
+						  athos_b_lut_5g_60_mhz,
+						  ATHOS_B_5G_LUT_CHAN_5G_MAX,
+						  athos_b_lut_5g_60_mhz,
+						  ATHOS_B_5G_LUT_CHAN_5G_MAX,
+						  api_lut_line);
+		else
+			cl_phy_lut_3_lines_update(freq,
+						  olympus_lut_5g_60_mhz_s1,
+						  OLYMPUS_LUT_CHAN_5G_MAX,
+						  olympus_lut_5g_60_mhz_s0,
+						  OLYMPUS_LUT_CHAN_5G_MAX,
+						  olympus_lut_5g_40_mhz,
+						  OLYMPUS_LUT_CHAN_5G_MAX,
+						  api_lut_line);
+		break;
+	case NL80211_BAND_6GHZ:
+		if (rfic_version == ATHOS_B_VER)
+			cl_phy_lut_2_lines_update(freq,
+						  athos_b_lut_6g_60_mhz,
+						  ATHOS_B_6G_LUT_CHAN_6G_MAX,
+						  athos_b_lut_6g_40_mhz,
+						  ATHOS_B_6G_LUT_CHAN_6G_MAX,
+						  api_lut_line);
+		else
+			cl_phy_lut_2_lines_update(freq,
+						  athos_lut_6g_60_mhz,
+						  ATHOS_LUT_CHAN_6G_MAX,
+						  athos_lut_6g_40_mhz,
+						  ATHOS_LUT_CHAN_6G_MAX,
+						  api_lut_line);
+		break;
+
+	default:
+		/* If nl_band is not supported return zero's */
+		memset(api_lut_line, 0, sizeof(struct mm_mac_api_lut_line));
+		api_lut_line->frequency_q2 = cpu_to_le16(freq);
+	}
+}
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL808X \
+	(RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_3_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_4_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_5_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_6_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_7_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL806X \
+	(RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_3_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_4_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_5_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL8046 \
+	(RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_3_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_CL8040 \
+	(RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_2_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_5_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_6_BIT)
+
+#define RICU_AFE_CTL_9_EN_DAC_REF_WIRING_27 \
+	(RICU_AFE_CTL_9_EN_DAC_REF_0_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_1_BIT | \
+	 RICU_AFE_CTL_9_EN_DAC_REF_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL808X \
+	(RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_3_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_4_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_5_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_6_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_7_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL806X \
+	(RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_3_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_4_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL8046 \
+	(RICU_AFE_CTL_8_EN_BGR_0_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_3_BIT)
+
+#define RICU_AFE_CTL_8_EN_BGR_CL8040 \
+	(RICU_AFE_CTL_8_EN_BGR_1_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_2_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_5_BIT | \
+	 RICU_AFE_CTL_8_EN_BGR_6_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL808X \
+	(RICU_AFE_CTL_8_EN_REF_0_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_1_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_2_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_3_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_4_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_5_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_6_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_7_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_WIRING_27_31 \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_WIRING_27_31 \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL806X \
+	(RICU_AFE_CTL_8_EN_REF_0_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_1_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_2_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_3_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_4_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_5_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL8046 \
+	(RICU_AFE_CTL_8_EN_REF_0_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_1_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_2_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_3_BIT)
+
+#define RICU_AFE_CTL_8_EN_REF_CL8040 \
+	(RICU_AFE_CTL_8_EN_REF_1_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_2_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_5_BIT | \
+	 RICU_AFE_CTL_8_EN_REF_6_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL808X \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL806X \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL8046 \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_CL804X \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_WIRING_27_31 \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_0_DAC_WIRING_33 \
+	(RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL808X \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL806X \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_CL804X \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_WIRING_27_31 \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT)
+
+#define RICU_AFE_CTRL_37_PHY_1_DAC_WIRING_33 \
+	(RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT | \
+	 RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT)
+
+static int cl_afe_enable(struct cl_chip *chip)
+{
+	u32 regval;
+	bool tcv0_enabled = cl_chip_is_tcv0_enabled(chip);
+	bool tcv1_enabled = cl_chip_is_tcv1_enabled(chip);
+
+	/* Enable PLL LDO */
+	ricu_afe_ctl_1_en_pll_ldo_setf(chip, 1);
+
+	/* Enable DAC BGR & reference */
+	regval = ricu_afe_ctl_9_get(chip);
+
+	if (chip->fem.wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1 ||
+	    chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1) {
+		regval |= RICU_AFE_CTL_9_EN_DAC_REF_WIRING_27;
+	} else if (cl_chip_is_8ant(chip)) {
+		regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL808X;
+	} else if (cl_chip_is_6ant(chip)) {
+		regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL806X;
+
+	} else {
+		if (cl_chip_is_6g(chip))
+			regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL8046;
+		else
+			regval |= RICU_AFE_CTL_9_EN_DAC_REF_CL8040;
+	}
+
+	ricu_afe_ctl_9_set(chip, regval);
+
+	/* Enable ADC BGR & Reference */
+	regval = ricu_afe_ctl_8_get(chip);
+
+	if (cl_chip_is_8ant(chip)) {
+		regval |= RICU_AFE_CTL_8_EN_BGR_CL808X;
+		regval |= RICU_AFE_CTL_8_EN_REF_CL808X;
+	} else if (cl_chip_is_6ant(chip)) {
+		regval |= RICU_AFE_CTL_8_EN_BGR_CL806X;
+		regval |= RICU_AFE_CTL_8_EN_REF_CL806X;
+	} else {
+		if (cl_chip_is_6g(chip)) {
+			regval |= RICU_AFE_CTL_8_EN_BGR_CL8046;
+			regval |= RICU_AFE_CTL_8_EN_REF_CL8046;
+		} else {
+			regval |= RICU_AFE_CTL_8_EN_BGR_CL8040;
+			regval |= RICU_AFE_CTL_8_EN_REF_CL8040;
+		}
+	}
+	ricu_afe_ctl_8_set(chip, regval);
+
+	/* Enable Embedded LDO */
+	if (tcv0_enabled) {
+		regval = ricu_afe_ctrl_36_phy_0_get(chip);
+		regval |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT |
+			   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+			   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT);
+		ricu_afe_ctrl_36_phy_0_set(chip, regval);
+	}
+
+	if (tcv1_enabled) {
+		regval = ricu_afe_ctrl_36_phy_1_get(chip);
+		regval |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT |
+			   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+			   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT);
+		ricu_afe_ctrl_36_phy_1_set(chip, regval);
+	}
+
+	/* Wait 2 ms PLL LDO settling time */
+	usleep_range(2000, 2100);
+
+	/* Enable the LC oscillator of the LCPLL */
+	ricu_afe_ctl_2_lock_con_rev_lc_setf(chip, 1);
+	/* Enable the LC PBIAS of the LCPLL */
+	ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(chip, 1);
+
+	/* Wait 200 us */
+	usleep_range(200, 210);
+
+	/* Power up control for LCPLL */
+	ricu_afe_ctl_1_resetb_lc_setf(chip, 1);
+
+	ricu_afe_ctl_0_lock_en_lc_setf(chip, 0x1);
+
+	/* Wait 1 ms */
+	usleep_range(1000, 1100);
+
+	if (!cmu_pll_0_stat_pll_lock_getf(chip)) {
+		cl_dbg_chip_err(chip, "ERROR: pll0 is not locked !!!\n");
+		return -ENOLCK;
+	}
+
+	/* Enable DAC & ADC cores */
+	if (tcv0_enabled) {
+		if (chip->fem.wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1 ||
+		    chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_WIRING_27_31);
+		else if (chip->fem.wiring_id == FEM_WIRING_33_TCV0_4_TCV1_4)
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_WIRING_33);
+		else if (cl_chip_is_8ant(chip) || cl_fem_wiring_id_is_evb(chip))
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL808X);
+		else if (cl_chip_is_6ant(chip))
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL806X);
+		else if (cl_chip_is_6g(chip))
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL8046);
+		else
+			ricu_afe_ctrl_37_phy_0_set(chip, RICU_AFE_CTRL_37_PHY_0_DAC_CL804X);
+	}
+
+	if (tcv1_enabled) {
+		if (chip->fem.wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1 ||
+		    chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+			ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_WIRING_27_31);
+		else if (chip->fem.wiring_id == FEM_WIRING_33_TCV0_4_TCV1_4)
+			ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_WIRING_33);
+		else if (cl_chip_is_8ant(chip) || cl_fem_wiring_id_is_evb(chip))
+			ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL808X);
+		else if (cl_chip_is_6ant(chip))
+			ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL806X);
+		else
+			ricu_afe_ctrl_37_phy_1_set(chip, RICU_AFE_CTRL_37_PHY_1_DAC_CL804X);
+	}
+
+	/* Enable DAC & ADC cores */
+	if (tcv0_enabled) {
+		regval = ricu_afe_ctrl_36_phy_0_get(chip);
+		regval |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+			   RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+		ricu_afe_ctrl_36_phy_0_set(chip, regval);
+	}
+
+	if (tcv1_enabled) {
+		regval = ricu_afe_ctrl_36_phy_1_get(chip);
+		regval |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+			   RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+		ricu_afe_ctrl_36_phy_1_set(chip, regval);
+	}
+
+	/* Wait 50us */
+	udelay(50);
+
+	/* Enable Main & 2nd CDB clock generators */
+	ricu_afe_ctl_0_cdb_clk_resetb_setf(chip, 1);
+
+	return 0;
+}
+
+static void cl_afe_disable(struct cl_chip *chip)
+{
+	u32 regval;
+	bool tcv0_enabled = cl_chip_is_tcv0_enabled(chip);
+	bool tcv1_enabled = cl_chip_is_tcv1_enabled(chip);
+
+	/* Power down control for LCPLL */
+	ricu_afe_ctl_1_resetb_lc_setf(chip, 0);
+	/* Disable PLL LDO */
+	ricu_afe_ctl_1_en_pll_ldo_setf(chip, 0);
+	/* Disable the LC oscillator of the LCPLL */
+	ricu_afe_ctl_2_lock_con_rev_lc_setf(chip, 0);
+	/* Disable the LC PBIAS of the LCPLL */
+	ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(chip, 0);
+
+	/* Disable DAC BGR & reference */
+	regval = ricu_afe_ctl_9_get(chip);
+	if (cl_chip_is_8ant(chip)) {
+		regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL808X;
+	} else if (cl_chip_is_6ant(chip)) {
+		regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL806X;
+	} else {
+		if (cl_chip_is_6g(chip))
+			regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL8046;
+		else
+			regval &= ~RICU_AFE_CTL_9_EN_DAC_REF_CL8040;
+	}
+	ricu_afe_ctl_9_set(chip, regval);
+
+	/* Disable ADC BGR & Reference */
+	regval = ricu_afe_ctl_8_get(chip);
+	if (cl_chip_is_8ant(chip)) {
+		regval &= ~RICU_AFE_CTL_8_EN_BGR_CL808X;
+		regval &= ~RICU_AFE_CTL_8_EN_REF_CL808X;
+	} else if (cl_chip_is_6ant(chip)) {
+		regval &= ~RICU_AFE_CTL_8_EN_BGR_CL806X;
+		regval &= ~RICU_AFE_CTL_8_EN_REF_CL806X;
+	} else {
+		if (cl_chip_is_6g(chip)) {
+			regval &= ~RICU_AFE_CTL_8_EN_BGR_CL8046;
+			regval &= ~RICU_AFE_CTL_8_EN_REF_CL8046;
+		} else {
+			regval &= ~RICU_AFE_CTL_8_EN_BGR_CL8040;
+			regval &= ~RICU_AFE_CTL_8_EN_REF_CL8040;
+		}
+	}
+	ricu_afe_ctl_8_set(chip, regval);
+
+	/* Disable Embedded LDO */
+	if (tcv0_enabled) {
+		regval = ricu_afe_ctrl_36_phy_0_get(chip);
+		regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT |
+			    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+			    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT);
+		ricu_afe_ctrl_36_phy_0_set(chip, regval);
+	}
+
+	if (tcv1_enabled) {
+		regval = ricu_afe_ctrl_36_phy_1_get(chip);
+		regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT |
+			    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT |
+			    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT);
+		ricu_afe_ctrl_36_phy_1_set(chip, regval);
+	}
+
+	/* Disable DAC & ADC cores */
+	if (tcv0_enabled)
+		ricu_afe_ctrl_37_phy_0_set(chip, 0);
+
+	if (tcv1_enabled)
+		ricu_afe_ctrl_37_phy_1_set(chip, 0);
+
+	/* Disable DAC & ADC cores */
+	if (tcv0_enabled) {
+		regval = ricu_afe_ctrl_36_phy_0_get(chip);
+		regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+			    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+		ricu_afe_ctrl_36_phy_0_set(chip, regval);
+	}
+
+	if (tcv1_enabled) {
+		regval = ricu_afe_ctrl_36_phy_1_get(chip);
+		regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+			    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+		ricu_afe_ctrl_36_phy_1_set(chip, regval);
+	}
+
+	/* Disable Main & 2nd CDB clock generators */
+	ricu_afe_ctl_0_cdb_clk_resetb_setf(chip, 0);
+}
+
+static void cl_io_ctrl_config(struct cl_chip *chip)
+{
+	io_ctrl_fastwr_0_set(chip, 0x2338);
+	io_ctrl_fastwr_1_set(chip, 0x2338);
+	io_ctrl_fastwr_2_set(chip, 0x2338);
+	io_ctrl_fastwr_3_set(chip, 0x2338);
+	io_ctrl_fastwr_4_set(chip, 0x2338);
+	io_ctrl_fastwr_5_set(chip, 0x2338);
+	io_ctrl_fastwr_6_set(chip, 0x2338);
+	io_ctrl_fastwr_7_set(chip, 0x2338);
+	io_ctrl_fwr_en_1_set(chip, 0x338);
+	io_ctrl_spiclk_set(chip, 0x308);
+}
+
+static int cl_adc_sampling_cfg_tcv0(struct cl_chip *chip, u16 adc_sampling_clk)
+{
+	switch (adc_sampling_clk) {
+	case 40:
+		ricu_afe_ctrl_43_freq_sel_setf(chip, 0x0);
+		/* Configure ADC sampling for primary chains */
+		ricu_afe_ctl_25_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_26_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_27_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_33_pack(chip, 0x1, 0x3D, 0x3D);
+		break;
+	case 80:
+		ricu_afe_ctrl_43_freq_sel_setf(chip, 0x1);
+		/* Configure ADC sampling for primary chains */
+		ricu_afe_ctl_25_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_26_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_27_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctl_33_pack(chip, 0x1, 0x3D, 0x3D);
+		break;
+	case 160:
+		ricu_afe_ctrl_43_freq_sel_setf(chip, 0x2);
+		/* Configure ADC sampling for primary chains */
+		ricu_afe_ctl_25_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_26_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_27_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_33_pack(chip, 0x0, 0x7, 0x7);
+		break;
+	case 320:
+		ricu_afe_ctrl_43_freq_sel_setf(chip, 0x3);
+		/* Configure ADC sampling for primary chains */
+		ricu_afe_ctl_25_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_26_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_27_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctl_33_pack(chip, 0x0, 0x7, 0x7);
+		break;
+	default:
+		CL_DBG_ERROR_CHIP(chip, "Invalid adc_sampling_clk %u\n", adc_sampling_clk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cl_adc_sampling_cfg_tcv1(struct cl_chip *chip, u32 adc_sampling_clk)
+{
+	switch (adc_sampling_clk) {
+	case 40:
+		ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x0);
+		/* Configure ADC sampling for secondary chains */
+		ricu_afe_ctrl_39_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_40_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_41_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_42_pack(chip, 0x1, 0x3D, 0x3D);
+		break;
+	case 80:
+		ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x1);
+		/* Configure ADC sampling for secondary chains */
+		ricu_afe_ctrl_39_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_40_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_41_pack(chip, 0x1, 0x3D, 0x3D);
+		ricu_afe_ctrl_42_pack(chip, 0x1, 0x3D, 0x3D);
+		break;
+	case 160:
+		ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x2);
+		/* Configure ADC sampling for secondary chains */
+		ricu_afe_ctrl_39_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_40_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_41_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_42_pack(chip, 0x0, 0x7, 0x7);
+		break;
+	case 320:
+		ricu_afe_ctrl_44_cdb_freq_sel_setf(chip, 0x3);
+		/* Configure ADC sampling for secondary chains */
+		ricu_afe_ctrl_39_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_40_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_41_pack(chip, 0x0, 0x7, 0x7);
+		ricu_afe_ctrl_42_pack(chip, 0x0, 0x7, 0x7);
+		break;
+	default:
+		CL_DBG_ERROR_CHIP(chip, "Invalid adc_sampling_clk %u\n", adc_sampling_clk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cl_afe_adc_and_dac_cfg(struct cl_chip *chip)
+{
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	bool tcv0_enabled = cl_chip_is_tcv0_enabled(chip);
+	bool tcv1_enabled = cl_chip_is_tcv1_enabled(chip);
+	bool hw_mode = chip->conf->ci_afe_hw_mode;
+	u16 bw_tcv0 = 0;
+	u16 bw_tcv1 = 0;
+	u16 riu_sampling_clk_tcv0 = 0;
+	u16 riu_sampling_clk_tcv1 = 0;
+	u16 adc_sampling_clk_tcv0 = 80;
+	u16 adc_sampling_clk_tcv1 = 80;
+	u8 sb_rd_delay_tcv0 = 0;
+	u8 sb_rd_delay_tcv1 = 0;
+	u32 regval;
+	u8 main_sel_7_2 = 0;
+
+	if (tcv0_enabled) {
+		bw_tcv0 = cl_hw_tcv0->conf->ci_cap_bandwidth;
+		riu_sampling_clk_tcv0 =
+			cl_hw_tcv0->conf->ci_hr_factor[bw_tcv0] * BW_TO_MHZ(bw_tcv0);
+		adc_sampling_clk_tcv0 = 2 * riu_sampling_clk_tcv0;
+		sb_rd_delay_tcv0 = ((riu_sampling_clk_tcv0 == 80) ||
+				    (riu_sampling_clk_tcv0 == 160)) ? 4 : 2;
+	}
+
+	if (tcv1_enabled) {
+		bw_tcv1 = cl_hw_tcv1->conf->ci_cap_bandwidth;
+		riu_sampling_clk_tcv1 =
+			cl_hw_tcv1->conf->ci_hr_factor[bw_tcv1] * BW_TO_MHZ(bw_tcv1);
+		adc_sampling_clk_tcv1 = 2 * riu_sampling_clk_tcv1;
+		sb_rd_delay_tcv1 = ((riu_sampling_clk_tcv1 == 80) ||
+				    (riu_sampling_clk_tcv1 == 160)) ? 4 : 2;
+	}
+
+	/*
+	 * For ADC sampling CLK=40MHz set to 0
+	 * For ADC sampling CLK=80MHz set to 1
+	 * For ADC sampling CLK=160MHz set to 2
+	 * For ADC sampling CLK=320MHz set to 3
+	 *
+	 * The sampling clock depends on the channel_bandwidth (20/40/80/160MHz)
+	 * and hr_factor (1,2,4,8):
+	 * ADC Sampling (MHz) = 2 * hr_factor * channel_bandwidth
+	 *
+	 * Select the external forced clock for ADC0..7:
+	 * For ADC sampling CLK=40MHz/80MHz set to 1
+	 * For ADC sampling CLK=160MHz/320MHz set to 0
+	 * In our default case: rosel0-3 = 0x0; rosel4-7 = 0x1
+	 *
+	 * Internal clock frequency of ADCI0..7 I (when its ROSEL is low):
+	 * For ADC sampling CLK=40MHz/80MHz set to 7'b011_1101
+	 * For ADC sampling CLK=160MHz/320MHz set to 7'b000_0111
+	 * In our default case: roctrli0-3 = 0x7; roctrli4-7 = 0x3D
+	 *
+	 * Internal clock frequency of ADCQ0..7 I (when its ROSEL is low):
+	 * For ADC sampling CLK=40MHz/80MHz set to 7'b011_1101
+	 * For ADC sampling CLK=160MHz/320MHz set to 7'b000_0111
+	 * In our default case: roctrlq0-3 = 0x7; roctrlq4-7 = 0x3D
+	 */
+
+	if (cl_adc_sampling_cfg_tcv0(chip, adc_sampling_clk_tcv0))
+		return -1;
+	if (cl_adc_sampling_cfg_tcv1(chip, adc_sampling_clk_tcv1))
+		return -1;
+
+	/* AFE_CTL_0 - AUX ADC for debug + for second band */
+	regval = ricu_afe_ctl_0_get(chip);
+	if (chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1)
+		regval |= (RICU_AFE_CTL_0_EN_CDB_DAC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_CDB_ADC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_CDB_GEN_BIT |
+			   RICU_AFE_CTL_0_EN_GPADC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_GPADC_BIT);
+	else if (cl_chip_is_4ant(chip) && cl_chip_is_6g(chip) &&
+		 !(chip->fem.wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1))
+		regval |= (RICU_AFE_CTL_0_EN_GPADC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_GPADC_BIT);
+	else
+		regval |= (RICU_AFE_CTL_0_EN_CDB_DAC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_CDB_ADC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_CDB_GEN_BIT |
+			   RICU_AFE_CTL_0_EN_GPADC_CLK_BIT |
+			   RICU_AFE_CTL_0_EN_GPADC_BIT);
+	ricu_afe_ctl_0_set(chip, regval);
+
+	ricu_afe_ctl_3_cml_sel_setf(chip, chip->conf->ci_afe_cml_sel);
+
+	/* VC_LD_AVDI0..7 */
+	ricu_afe_ctl_23_set(chip, chip->conf->ci_afe_vc_avd);
+	/* VC_LD_AVDQ0..7 */
+	ricu_afe_ctl_24_set(chip, chip->conf->ci_afe_vc_avd);
+	/* EN_BGR0..7 = 0x1, CH_CML_SEL0..7, EN_EXT_LOAD0..7 = 0x0, EN_REF0..7 = 0x1 */
+	ricu_afe_ctl_8_set(chip, 0xff0000ff |
+			   (chip->conf->ci_afe_ch_cml_sel << RICU_AFE_CTL_8_CH_CML_SEL_0_POS));
+	/* VC_CML0..7_I */
+	ricu_afe_ctl_29_set(chip, chip->conf->ci_afe_vc_cml);
+	/* VC_CML0..7_Q */
+	ricu_afe_ctl_30_set(chip, chip->conf->ci_afe_vc_cml);
+	/* IC_REFSSF0..7 = 0x3, EOC_CTRL0..7 */
+	ricu_afe_ctl_12_set(chip, 0x0000ffff |
+			    (chip->conf->ci_afe_eoc_ctrl << RICU_AFE_CTL_12_EOC_CTRL_0_LSB));
+
+	/*
+	 * Set channels to Transceiver0 (phy0) or Transceiver1 (phy1):
+	 * 6'b11_0000 (Transceiver1 @CH7~6, Transceiver0 @CH5~0)
+	 * 6'b11_1000 (Transceiver1 @CH7~5, Transceiver0 @CH4~0)
+	 * 6'b11_1100 (Transceiver1 @CH7~4, Transceiver0 @CH3~0)
+	 * 6'b11_1110 (Transceiver1 @CH7~3, Transceiver0 @CH3~0)
+	 * 6'b11_1111 (Transceiver1 @CH7~2, Transceiver0 @CH2~0)
+	 * In our default case: mainsel72 = 0x3C
+	 */
+	if (chip->cdb_mode_maj < 2 || chip->cdb_mode_maj > 6) {
+		main_sel_7_2 = 0x3C;
+	} else {
+		u8 chains_tcv0 = MAX_ANTENNAS - chip->cdb_mode_maj;
+
+		/* Turn off TCV0's chains */
+		chains_tcv0 = BIT(chains_tcv0) - 1;
+		main_sel_7_2 = 0x3F & (~chains_tcv0);
+	}
+
+	ricu_afe_ctl_5_main_sel_7_2_setf(chip, main_sel_7_2);
+	cl_dbg_chip_trace(chip, "Set main_sel_7_2 = 0x%x\n", main_sel_7_2);
+
+	/*
+	 * Set 1 - b0 to MINV0/1/2/3/4/5/6/7 (DAC)
+	 * Set 1 - b1 to TWOS0/1/2/3/4/5/6/7 (ADC)
+	 */
+	ricu_afe_ctl_10_set(chip, 0x00FF0000);
+
+	/* Set VC_REF0/1/2/../7 */
+	ricu_afe_ctl_17_set(chip, chip->conf->ci_afe_vc_ref);
+
+	if (chip->conf->ci_afe_loopback) {
+		ricu_afe_ctl_13_pack(chip, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1);
+		ricu_afe_ctl_15_pack(chip, 6, 6, 6, 6, 6, 6, 6, 6);
+		/* Set COMP_CTRL0/1/2/.../7[3:0] to 4'b1001 for loopback mode */
+		ricu_afe_ctl_19_set(chip, 0x99999999);
+	} else {
+		/* Set COMP_CTRL0/1/2/.../7[3:0] to 4'b1010 for normal mode */
+		ricu_afe_ctl_19_set(chip, 0xAAAAAAAA);
+	}
+
+	if (hw_mode) {
+		/*
+		 * Disable DAC & ADC cores (To save power.
+		 * Assuming RIU HW will control it due to HW_MODE_ADC/DAC)
+		 */
+		if (tcv0_enabled)
+			ricu_afe_ctrl_37_phy_0_set(chip, 0);
+
+		if (tcv1_enabled)
+			ricu_afe_ctrl_37_phy_1_set(chip, 0);
+
+		if (tcv0_enabled) {
+			regval = ricu_afe_ctrl_36_phy_0_get(chip);
+			regval &= ~(RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+				    RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+			ricu_afe_ctrl_36_phy_0_set(chip, regval);
+		}
+
+		if (tcv1_enabled) {
+			regval = ricu_afe_ctrl_36_phy_1_get(chip);
+			regval &= ~(RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+				    RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+			ricu_afe_ctrl_36_phy_1_set(chip, regval);
+		}
+	}
+
+	/* Sync buffer read delay, ignore fifo indication */
+	if (tcv0_enabled) {
+		ricu_afe_ctrl_34_phy_0_adc_sb_rd_delay_setf(chip, sb_rd_delay_tcv0);
+		ricu_afe_ctrl_34_phy_0_adc_sb_ignore_fifo_indication_setf(chip, 1);
+	}
+
+	if (tcv1_enabled) {
+		ricu_afe_ctrl_34_phy_1_adc_sb_rd_delay_setf(chip, sb_rd_delay_tcv1);
+		ricu_afe_ctrl_34_phy_1_adc_sb_ignore_fifo_indication_setf(chip, 1);
+	}
+
+	/* DAC - ignore fifo indication = true */
+	if (tcv0_enabled) {
+		ricu_afe_ctrl_35_phy_0_dac_sb_rd_delay_setf(chip, 1);
+		ricu_afe_ctrl_35_phy_0_dac_sb_ignore_fifo_indication_setf(chip, 1);
+	}
+
+	if (tcv1_enabled) {
+		ricu_afe_ctrl_35_phy_1_dac_sb_rd_delay_setf(chip, 1);
+		ricu_afe_ctrl_35_phy_1_dac_sb_ignore_fifo_indication_setf(chip, 1);
+	}
+
+	/* Set to HW/SW control mode */
+	if (tcv0_enabled) {
+		ricu_afe_ctrl_36_phy_0_hw_mode_adc_setf(chip, hw_mode);
+		ricu_afe_ctrl_36_phy_0_hw_mode_dac_setf(chip, hw_mode);
+	}
+
+	if (tcv1_enabled) {
+		ricu_afe_ctrl_36_phy_1_hw_mode_adc_setf(chip, hw_mode);
+
+		if (chip->fem.wiring_id != FEM_WIRING_31_TCV0_2_TCV1_1)
+			ricu_afe_ctrl_36_phy_1_hw_mode_dac_setf(chip, hw_mode);
+	}
+
+	return 0;
+}
+
+static void cl_afe_set_cdb_mode_maj(struct cl_chip *chip, u8 maj_val)
+{
+	ricu_static_conf_0_cdb_mode_maj_setf(chip, maj_val);
+	chip->cdb_mode_maj = maj_val;
+}
+
+static int cl_afe_set_cdb_mode(struct cl_chip *chip)
+{
+	/* Configure number of RF chains per PHY */
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	u8 ant_tcv0 = 0;
+	u8 ant_tcv1 = 0;
+	u8 ant_total = 0;
+
+	if (cl_hw_tcv0 && cl_hw_tcv1) {
+		ant_tcv0 = cl_hw_tcv0->num_antennas;
+		ant_tcv1 = cl_hw_tcv1->num_antennas;
+	} else if (cl_hw_tcv0) {
+		ant_tcv0 = cl_hw_tcv0->num_antennas;
+		ant_tcv1 = chip->max_antennas - ant_tcv0;
+	} else {
+		ant_tcv1 = cl_hw_tcv1->num_antennas;
+		ant_tcv0 = chip->max_antennas - ant_tcv1;
+	}
+
+	if (chip->conf->ci_phy_dev == PHY_DEV_LOOPBACK) {
+		cl_afe_set_cdb_mode_maj(chip, 0xf);
+
+		return 0;
+	}
+
+	if (cl_fem_wiring_id_is_evb(chip)) {
+		/*
+		 * Extend the num antennas of TCV1 as if there were 8 antennas
+		 * on the chip, for the purpose of calculating the maj value.
+		 */
+		u8 ant_ext = MAX_ANTENNAS_CHIP - chip->max_antennas;
+
+		ant_tcv1 += ant_ext;
+	} else if (!cl_chip_is_8ant(chip)) {
+		cl_afe_set_cdb_mode_maj(chip, 0x4);
+
+		return 0;
+	}
+
+	ant_total = ant_tcv0 + ant_tcv1;
+
+	if (ant_total < MAX_ANTENNAS_CHIP) {
+		if (ant_tcv0 <= 4 && ant_tcv1 <= 4) {
+			ant_tcv0 = 4;
+			ant_tcv1 = 4;
+		} else {
+			if (cl_hw_tcv0)
+				ant_tcv0 = min_t(u8, cl_hw_tcv0->max_antennas,
+						 MAX_ANTENNAS_CHIP - ant_tcv1);
+			else
+				ant_tcv0 = MAX_ANTENNAS_CHIP - ant_tcv1;
+
+			if (cl_hw_tcv1) {
+				ant_total = ant_tcv0 + ant_tcv1;
+				ant_tcv1 += min_t(u8, cl_hw_tcv1->max_antennas -
+						      cl_hw_tcv1->num_antennas,
+						  MAX_ANTENNAS_CHIP - ant_total);
+			} else {
+				ant_tcv1 = MAX_ANTENNAS_CHIP - ant_tcv0;
+			}
+		}
+	}
+
+	if (ant_tcv0 + ant_tcv1 != 8) {
+		CL_DBG_ERROR_CHIP(chip, "Invalid antenna configuration (tcv0 %u) (tcv1 %u)\n",
+				  ant_tcv0, ant_tcv1);
+
+		return -EINVAL;
+	}
+
+	cl_afe_set_cdb_mode_maj(chip, ant_tcv1);
+
+	return 0;
+}
+
+static int cl_afe_phy_type_and_rf_chains(struct cl_chip *chip)
+{
+	ricu_spi_clk_ctrl_set(chip, 0x1c); /* SPI clock bitmap */
+	ricu_static_conf_0_btc_sel_setf(chip, 0); /* Clear BTC select */
+
+	if (cl_afe_set_cdb_mode(chip))
+		return -1;
+
+	ricu_static_conf_0_clk_save_mode_setf(chip, 1);
+
+	if (chip->fem.wiring_id == FEM_WIRING_27_TCV0_2_TCV1_1 ||
+	    chip->fem.wiring_id == FEM_WIRING_31_TCV0_2_TCV1_1) {
+		ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x23);
+	} else if (cl_chip_is_8ant(chip) || cl_fem_wiring_id_is_evb(chip)) {
+		ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, U8_MAX);
+	} else if (cl_chip_is_6ant(chip)) {
+		ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x3f);
+	} else {
+		if (cl_chip_is_6g(chip))
+			ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0xf);
+		else
+			ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, 0x66);
+	}
+
+	/* Reset RFIC */
+	ricu_static_conf_0_rf_rst_n_req_setf(chip, 0x1);
+
+	return 0;
+}
+
+int cl_afe_cfg(struct cl_chip *chip)
+{
+	/* 1. Define PHY Type & RF Chains per band */
+	if (cl_afe_phy_type_and_rf_chains(chip))
+		return -1;
+
+	if (!chip->conf->ci_afe_config_en)
+		goto fem_conf;
+
+	/* 2. AFE Disable */
+	cl_afe_disable(chip);
+
+	/* Wait 2.5ms for AFE LDO settling time */
+	usleep_range(2500, 2600);
+
+	/* 3. AFE Enable */
+	if (cl_afe_enable(chip))
+		return -1;
+
+	/* 4. ADC & DAC Configuration */
+	cl_afe_adc_and_dac_cfg(chip);
+
+	cl_io_ctrl_config(chip);
+
+fem_conf:
+	/* 5. FEM Configuration */
+	cl_fem_update_conf_params(chip);
+
+	return 0;
+}
+
+void cl_afe_cfg_calib(struct cl_chip *chip)
+{
+	struct cl_afe_reg *orig_afe_reg = &chip->orig_afe_reg;
+	u32 reg_phy0 = 0, reg_phy1 = 0;
+
+	orig_afe_reg->ctrl36_phy0 = ricu_afe_ctrl_36_phy_0_get(chip);
+	orig_afe_reg->ctrl37_phy0 = ricu_afe_ctrl_37_phy_0_get(chip);
+	orig_afe_reg->ctrl36_phy1 = ricu_afe_ctrl_36_phy_1_get(chip);
+	orig_afe_reg->ctrl37_phy1 = ricu_afe_ctrl_37_phy_1_get(chip);
+	orig_afe_reg->ctrl8 = ricu_afe_ctl_8_get(chip);
+	orig_afe_reg->ctrl9 = ricu_afe_ctl_9_get(chip);
+	orig_afe_reg->adc_ch_alloc = ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_getf(chip);
+
+	/* Enable all ADC channels */
+	reg_phy0 = 0xFF;
+	ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, reg_phy0);
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_ADC_CH_ALLOC = 0x%x\n", reg_phy0);
+
+	/* Enable DAC REF0-7 */
+	reg_phy0 = orig_afe_reg->ctrl9 | 0xFF0000;
+	ricu_afe_ctl_9_set(chip, reg_phy0);
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTL_9 = 0x%x\n", reg_phy0);
+
+	/* Enable ADC BGR0-7 and REF0-7 */
+	reg_phy0 = orig_afe_reg->ctrl8 | RICU_AFE_CTL_8_EN_BGR_CL808X |
+			RICU_AFE_CTL_8_EN_REF_CL808X;
+	ricu_afe_ctl_8_set(chip, reg_phy0);
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTL_8 = 0x%x\n", reg_phy0);
+
+	/* Wait PLL LDO setting time(1.5ms) + margin = 2ms */
+	usleep_range(2000, 2100);
+
+	/* Enable DAC cores */
+	reg_phy0 = RICU_AFE_CTRL_37_PHY_0_DAC_CL808X;
+	ricu_afe_ctrl_37_phy_0_set(chip, reg_phy0);
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_37_PHY_0 = 0x%x\n", reg_phy0);
+
+	reg_phy1 = RICU_AFE_CTRL_37_PHY_1_DAC_CL808X;
+	ricu_afe_ctrl_37_phy_1_set(chip, reg_phy1);
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_37_PHY_1 = 0x%x\n", reg_phy1);
+
+	/* Enable ADC cores and set to SW control mode */
+	reg_phy0 = orig_afe_reg->ctrl36_phy0;
+	reg_phy0 |= (RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT |
+			RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT);
+	reg_phy0 &= ~(RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_BIT |
+			RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_BIT);
+	ricu_afe_ctrl_36_phy_0_set(chip, reg_phy0);
+
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_36_PHY_0 = 0x%x\n", reg_phy0);
+
+	/* Enable ADC cores and set to SW control mode */
+	reg_phy1 = orig_afe_reg->ctrl36_phy1;
+	reg_phy1 |= (RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT |
+			RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT);
+	reg_phy1 &= ~(RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_BIT |
+			RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_BIT);
+	ricu_afe_ctrl_36_phy_1_set(chip, reg_phy1);
+
+	cl_dbg_chip_trace(chip, "Setting: RICU_AFE_CTRL_36_PHY_1 = 0x%x\n", reg_phy1);
+}
+
+void cl_afe_cfg_restore(struct cl_chip *chip)
+{
+	struct cl_afe_reg *orig_afe_reg = &chip->orig_afe_reg;
+
+	ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(chip, orig_afe_reg->adc_ch_alloc);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_ADC_CH_ALLOC = 0x%x\n",
+			  orig_afe_reg->adc_ch_alloc);
+
+	ricu_afe_ctl_9_set(chip, orig_afe_reg->ctrl9);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTL_9 = 0x%x\n", orig_afe_reg->ctrl9);
+
+	ricu_afe_ctl_8_set(chip, orig_afe_reg->ctrl8);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTL_8 = 0x%x\n", orig_afe_reg->ctrl8);
+
+	ricu_afe_ctrl_37_phy_0_set(chip, orig_afe_reg->ctrl37_phy0);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_37_PHY_0 = 0x%x\n",
+			  orig_afe_reg->ctrl37_phy0);
+
+	ricu_afe_ctrl_37_phy_1_set(chip, orig_afe_reg->ctrl37_phy1);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_37_PHY_1 = 0x%x\n",
+			  orig_afe_reg->ctrl37_phy1);
+
+	ricu_afe_ctrl_36_phy_0_set(chip, orig_afe_reg->ctrl36_phy0);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_36_PHY_0 = 0x%x\n",
+			  orig_afe_reg->ctrl36_phy0);
+
+	ricu_afe_ctrl_36_phy_1_set(chip, orig_afe_reg->ctrl36_phy1);
+	cl_dbg_chip_trace(chip, "Restoring: RICU_AFE_CTRL_36_PHY_1 = 0x%x\n",
+			  orig_afe_reg->ctrl36_phy1);
+}
+
+static const struct cl_fem_lna_enable_gpio lna_enable_gpio[FEM_WIRING_MAX] = {
+	[FEM_WIRING_0_TCV0_6_TCV1_6]                    = { .val = 0b000000000000 },
+	[FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+	[FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+	[FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2]          = { .val = 0b001100110000 },
+	[FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+	[FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+	[FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b001100110000 },
+	[FEM_WIRING_7_TCV0_4_TCV1_4]                    = { .val = 0b000000111010 },
+	[FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+	[FEM_WIRING_9_TCV0_4_TCV1_4]                    = { .val = 0b111100000000 },
+	[FEM_WIRING_10_TCV0_4_TCV1_4]                   = { .val = 0b111100000000 },
+	[FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b111100000000 },
+	[FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b111100000000 },
+	[FEM_WIRING_13_SENSING_4RX_2TX]                 = { .val = 0b001111110000 },
+	[FEM_WIRING_14_SENSING_4TX_2RX]                 = { .val = 0b111100110000 },
+	[FEM_WIRING_15_CHAMELEON_4TX_4RX]               = { .val = 0b001100001010 },
+	[FEM_WIRING_16_TCV0_2_TCV1_2]                   = { .val = 0b100110111110 },
+	[FEM_WIRING_17_TCV0_4_TCV1_0]                   = { .val = 0b111111110000 },
+	[FEM_WIRING_18_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+	[FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b000011111111 },
+	[FEM_WIRING_20_TCV0_2_TCV1_2]                   = { .val = 0b100110111110 },
+	[FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2]          = { .val = 0b000110111010 },
+	[FEM_WIRING_22_OBSOLETE]                        = { .val = 0b111111000000 },
+	[FEM_WIRING_23_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+	[FEM_WIRING_24_TCV0_6_TCV1_4]                   = { .val = 0b000011000000 },
+	[FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0]            = { .val = 0b111100100000 },
+	[FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1]            = { .val = 0b111100100000 },
+	[FEM_WIRING_27_TCV0_2_TCV1_1]                   = { .val = 0b111101111100 },
+	[FEM_WIRING_28_TCV0_4_TCV1_2]                   = { .val = 0b000011111010 },
+	[FEM_WIRING_29_TCV0_4_TCV1_2]                   = { .val = 0b111100110000 },
+	[FEM_WIRING_30_TCV0_4_TCV1_2]                   = { .val = 0b000011111010 },
+	[FEM_WIRING_31_TCV0_2_TCV1_1]                   = { .val = 0b111101111100 },
+	[FEM_WIRING_32_TCV0_4_TCV1_0]                   = { .val = 0b111111110000 },
+	[FEM_WIRING_33_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+};
+
+static const struct cl_fem_pa_enable_gpio pa_enable_gpio[FEM_WIRING_MAX] = {
+	[FEM_WIRING_0_TCV0_6_TCV1_6]                    = { .val = 0b000000000000 },
+	[FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+	[FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b000000000000 },
+	[FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2]          = { .val = 0b000000000000 },
+	[FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+	[FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+	[FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b000000000000 },
+	[FEM_WIRING_7_TCV0_4_TCV1_4]                    = { .val = 0b000000111010 },
+	[FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4]           = { .val = 0b000000111010 },
+	[FEM_WIRING_9_TCV0_4_TCV1_4]                    = { .val = 0b111100000000 },
+	[FEM_WIRING_10_TCV0_4_TCV1_4]                   = { .val = 0b111100000000 },
+	[FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b111111110000 },
+	[FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b111111110000 },
+	[FEM_WIRING_13_SENSING_4RX_2TX]                 = { .val = 0b001111110000 },
+	[FEM_WIRING_14_SENSING_4TX_2RX]                 = { .val = 0b001111111010 },
+	[FEM_WIRING_15_CHAMELEON_4TX_4RX]               = { .val = 0b001111111010 },
+	[FEM_WIRING_16_TCV0_2_TCV1_2]                   = { .val = 0b100110111110 },
+	[FEM_WIRING_17_TCV0_4_TCV1_0]                   = { .val = 0b111111110000 },
+	[FEM_WIRING_18_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+	[FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b000011111111 },
+	[FEM_WIRING_20_TCV0_2_TCV1_2]                   = { .val = 0b100110111110 },
+	[FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2]          = { .val = 0b111111110000 },
+	[FEM_WIRING_22_OBSOLETE]                        = { .val = 0b111111000000 },
+	[FEM_WIRING_23_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+	[FEM_WIRING_24_TCV0_6_TCV1_4]                   = { .val = 0b000011000000 },
+	[FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0]            = { .val = 0b111100110000 },
+	[FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1]            = { .val = 0b111100110000 },
+	[FEM_WIRING_27_TCV0_2_TCV1_1]                   = { .val = 0b111101111100 },
+	[FEM_WIRING_28_TCV0_4_TCV1_2]                   = { .val = 0b000011111010 },
+	[FEM_WIRING_29_TCV0_4_TCV1_2]                   = { .val = 0b111100110000 },
+	[FEM_WIRING_30_TCV0_4_TCV1_2]                   = { .val = 0b000011111010 },
+	[FEM_WIRING_31_TCV0_2_TCV1_1]                   = { .val = 0b111111111100 },
+	[FEM_WIRING_32_TCV0_4_TCV1_0]                   = { .val = 0b111111110000 },
+	[FEM_WIRING_33_TCV0_4_TCV1_4]                   = { .val = 0b000000111010 },
+};
+
+static const struct cl_fem_rx_active_gpio rx_active_gpio[FEM_WIRING_MAX] = {
+	[FEM_WIRING_0_TCV0_6_TCV1_6]                    = { .val = 0b11000000 },
+	[FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b11111111 },
+	[FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6]           = { .val = 0b00000000 }, /* N/A */
+	[FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2]          = { .val = 0b11111100 },
+	[FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b11111111 },
+	[FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b00000000 }, /* N/A */
+	[FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { .val = 0b00000000 }, /* N/A */
+	[FEM_WIRING_7_TCV0_4_TCV1_4]                    = { .val = 0b11110000 },
+	[FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4]           = { .val = 0b00000000 }, /* N/A */
+	[FEM_WIRING_9_TCV0_4_TCV1_4]                    = { .val = 0b11111111 },
+	[FEM_WIRING_10_TCV0_4_TCV1_4]                   = { .val = 0b00000000 },
+	[FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b11110000 },
+	[FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]           = { .val = 0b11111111 },
+	[FEM_WIRING_13_SENSING_4RX_2TX]                 = { .val = 0b11000000 },
+	[FEM_WIRING_14_SENSING_4TX_2RX]                 = { .val = 0b11110000 },
+	[FEM_WIRING_15_CHAMELEON_4TX_4RX]               = { .val = 0b11110000 },
+	[FEM_WIRING_16_TCV0_2_TCV1_2]                   = { .val = 0b11111001 },
+	[FEM_WIRING_17_TCV0_4_TCV1_0]                   = { .val = 0b11111111 },
+	[FEM_WIRING_18_TCV0_4_TCV1_4]                   = { .val = 0b00000000 },
+	[FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED]  = { .val = 0b11001111 },
+	[FEM_WIRING_20_TCV0_2_TCV1_2]                   = { .val = 0b11111111 },
+	[FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2]          = { .val = 0b11110000 },
+	[FEM_WIRING_22_OBSOLETE]                        = { .val = 0b00000000 },
+	[FEM_WIRING_23_TCV0_4_TCV1_4]                   = { .val = 0b00000000 },
+	[FEM_WIRING_24_TCV0_6_TCV1_4]                   = { .val = 0b11000011 },
+	[FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0]            = { .val = 0b11001111 },
+	[FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1]            = { .val = 0b11001111 },
+	[FEM_WIRING_27_TCV0_2_TCV1_1]                   = { .val = 0b11011111 },
+	[FEM_WIRING_28_TCV0_4_TCV1_2]                   = { .val = 0b11110000 },
+	[FEM_WIRING_29_TCV0_4_TCV1_2]                   = { .val = 0b11000000 },
+	[FEM_WIRING_30_TCV0_4_TCV1_2]                   = { .val = 0b11111111 },
+	[FEM_WIRING_31_TCV0_2_TCV1_1]                   = { .val = 0b11111100 },
+	[FEM_WIRING_32_TCV0_4_TCV1_0]                   = { .val = 0b11110000 },
+	[FEM_WIRING_33_TCV0_4_TCV1_4]                   = { .val = 0b11111111 },
+};
+
+static const u32 ricu_fem_conf[FEM_WIRING_MAX][TCV_MAX] = {
+	[FEM_WIRING_0_TCV0_6_TCV1_6]                    = { 0x00AB3021, 0x0054CD89 },
+	[FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6]           = { 0x00AB3021, 0x0054CD89 },
+	[FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6]           = { 0x00AB3021, 0x0054CD89 },
+	[FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2]          = { 0x00003021, 0x00AB0089 },
+	[FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089 },
+	[FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089 },
+	[FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = { 0x00003021, 0x00AB0089 },
+	[FEM_WIRING_7_TCV0_4_TCV1_4]                    = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4]           = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_9_TCV0_4_TCV1_4]                    = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_10_TCV0_4_TCV1_4]                   = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY]           = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY]           = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_13_SENSING_4RX_2TX]                 = { 0x00003021, 0x00890000 },
+	[FEM_WIRING_14_SENSING_4TX_2RX]                 = { 0x00003021, 0x00000089 },
+	[FEM_WIRING_15_CHAMELEON_4TX_4RX]               = { 0x00AB0001, 0x00320089 },
+	[FEM_WIRING_16_TCV0_2_TCV1_2]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_17_TCV0_4_TCV1_0]                   = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_18_TCV0_4_TCV1_4]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED]  = { 0x00000000, 0x00AB3289 },
+	[FEM_WIRING_20_TCV0_2_TCV1_2]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2]          = { 0x00AB3210, 0x00000089 },
+	[FEM_WIRING_22_OBSOLETE]                        = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_23_TCV0_4_TCV1_4]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_24_TCV0_6_TCV1_4]                   = { 0x00543210, 0x00ABCD00 },
+	[FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0]            = { 0x000A3210, 0x000000AB },
+	[FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1]            = { 0x000A3210, 0x000000AB },
+	[FEM_WIRING_27_TCV0_2_TCV1_1]                   = { 0x000A3210, 0x000000AB },
+	[FEM_WIRING_28_TCV0_4_TCV1_2]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_29_TCV0_4_TCV1_2]                   = { 0x000A3210, 0x000000AB },
+	[FEM_WIRING_30_TCV0_4_TCV1_2]                   = { 0x00000001, 0x0032AB89 },
+	[FEM_WIRING_31_TCV0_2_TCV1_1]                   = { 0x00000010, 0x000000AB },
+	[FEM_WIRING_32_TCV0_4_TCV1_0]                   = { 0x000A3210, 0x000000AB },
+	[FEM_WIRING_33_TCV0_4_TCV1_4]                   = { 0x00000001, 0x0032AB89 },
+};
+
+static const u8 fem_full_list[FEM_WIRING_MAX][TCV_MAX][FEM_LUT_AMOUNT_PER_MAC] = {
+	[FEM_WIRING_0_TCV0_6_TCV1_6] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+	},
+	[FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+	},
+	[FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+	},
+	[FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_ELASTIC,
+			FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC, FEM_TYPE_ELASTIC},
+	},
+	[FEM_WIRING_7_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_9_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_10_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+			FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+			FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_13_SENSING_4RX_2TX] = {
+		{FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+			FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_14_SENSING_4TX_2RX] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_15_CHAMELEON_4TX_4RX] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_SENSING, FEM_TYPE_SENSING, FEM_TYPE_SENSING,
+			FEM_TYPE_SENSING, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_16_TCV0_2_TCV1_2] = {
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_17_TCV0_4_TCV1_0] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_18_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED] = {
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_20_TCV0_2_TCV1_2] = {
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_22_OBSOLETE] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_23_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_24_TCV0_6_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1},
+	},
+	[FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_SENSING,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_27_TCV0_2_TCV1_1] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_28_TCV0_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_29_TCV0_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_30_TCV0_4_TCV1_2] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_31_TCV0_2_TCV1_1] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_TYPE_SENSING,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_32_TCV0_4_TCV1_0] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY,
+			FEM_LUT_EMPTY, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	},
+	[FEM_WIRING_33_TCV0_4_TCV1_4] = {
+		{FEM_TYPE_TCV0, FEM_TYPE_TCV0, FEM_TYPE_TCV0,
+			FEM_TYPE_TCV0, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+		{FEM_TYPE_TCV1, FEM_TYPE_TCV1, FEM_TYPE_TCV1,
+			FEM_TYPE_TCV1, FEM_LUT_EMPTY, FEM_LUT_EMPTY},
+	}
+};
+
+static u16 cl_fem_reg_manual(struct cl_hw *cl_hw, u16 val, u8 ant_idx)
+{
+	u16 lut, lut0, lut1, lut2;
+	u8 shift = cl_hw->fem_mode * 4;
+
+	lut = (val >> shift) & RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK;
+	lut0 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_0_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK);
+	lut1 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_1_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_1_MASK);
+	lut2 = ((lut << RIU_RC_RF_LNA_LUT_RFLNALUT_2_LSB) & (u16)RIU_RC_RF_LNA_LUT_RFLNALUT_2_MASK);
+
+	return (lut0 | lut1 | lut2);
+}
+
+int cl_fem_get_registers(struct cl_hw *cl_hw, u32 fem_reg[FEM_REGISTERS_AMOUNT])
+{
+	u8 i;
+	u8 reg_idx;
+	u8 reg_shift;
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u16 reg_val;
+	struct cl_fem_params *fem = &cl_hw->chip->fem;
+	u8 chain_mask = cl_hw_ant_mask_to_riu_chain_mask(cl_hw, cl_hw->mask_num_antennas);
+
+	/* In case there's no valid wiring_id, keep the fem lut registers empty. */
+	if (fem->wiring_id >= FEM_WIRING_MAX)
+		return 0;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		reg_idx = i >> 1; /* 0 - 2 */
+		reg_shift = (i & 0x1) ? 16 : 0; /* even - 0. odd  - 16 */
+
+		if (chain_mask & BIT(i)) {
+			if (cl_hw->fem_mode == FEM_MODE_OPERETIONAL) {
+				reg_val = fem->lut_registers[tcv_idx][i];
+			} else {
+				u16 fem_val = fem->lut_registers[tcv_idx][i];
+
+				reg_val = cl_fem_reg_manual(cl_hw, fem_val, i);
+			}
+		} else {
+			reg_val = fem->lut_off_register[tcv_idx];
+		}
+
+		fem_reg[reg_idx] |= ((u32)reg_val << reg_shift);
+	}
+
+	for (i = 0; i < FEM_REGISTERS_AMOUNT; i++)
+		cl_dbg_trace(cl_hw, "RC_RFLNALUT_%u: [0x%08X]\n", i, fem_reg[i]);
+
+	return 0;
+}
+
+static int cl_fem_read_lut(struct cl_chip *chip)
+{
+	int i;
+	int has_valid_fem_lut = 0;
+	struct cl_fem_params *fem = &chip->fem;
+
+	/* Read FEM LUT from eeprom */
+	if (cl_e2p_read(chip, (u8 *)&fem->lut, SIZE_FEM_LUT, ADDR_FEM_LUT))
+		return -1;
+
+	for (i = 0; i < FEM_TYPE_MAX; i++) {
+		if (fem->lut[i] == U16_MAX)
+			continue;
+
+		/* Mark as valid if at least one the FEM LUTs has a valid value. */
+		has_valid_fem_lut = 1;
+		fem->lut_off_register_list[i] = EXTRACT_BYPASS_LUT(fem->lut[i]);
+		fem->lut[i] &= FEM_LUT_MASK;
+		cl_dbg_chip_trace(chip, "lut[%d] = 0x%X, lut_off_register_list[%d] = 0x%X\n",
+				  i, fem->lut[i], i, fem->lut_off_register_list[i]);
+	}
+
+	return !has_valid_fem_lut;
+}
+
+#define FEM_LUT_OFFSET_BYPASS 0
+#define FEM_LUT_OFFSET_TX     4
+#define FEM_LUT_OFFSET_RX     8
+#define FEM_LUT_VAL_MASK      0x7
+
+static int _cl_fem_check_lut_validity(struct cl_chip *chip, enum fem_type type)
+{
+	u16 fem_lut = chip->fem.lut[type];
+	u16 bypass = (fem_lut >> FEM_LUT_OFFSET_BYPASS) & FEM_LUT_VAL_MASK;
+	u16 tx = (fem_lut >> FEM_LUT_OFFSET_TX) & FEM_LUT_VAL_MASK;
+	u16 rx = (fem_lut >> FEM_LUT_OFFSET_RX) & FEM_LUT_VAL_MASK;
+	int ret = 0;
+
+	if (fem_lut == U16_MAX) {
+		cl_dbg_chip_err(chip, "Wiring_id [%u] must have valid FEM LUTs for %s\n",
+				chip->fem.wiring_id, FEM_TYPE_STR(type));
+		return -ERANGE;
+	}
+
+	/* Skip uniqueness check for sensing type */
+	if (type == FEM_TYPE_SENSING)
+		return 0;
+
+	/* Check uniqueness of BYPASS/TX/RX/OFF */
+	if (bypass == tx) {
+		cl_dbg_chip_err(chip, "Error: bypass (%u) and tx (%u) values are equal\n",
+				bypass, tx);
+		ret = -EIO;
+	}
+
+	if (bypass == rx) {
+		cl_dbg_chip_err(chip, "Error: bypass (%u) and rx (%u) values are equal\n",
+				bypass, rx);
+		ret = -EIO;
+	}
+
+	if (tx == rx) {
+		cl_dbg_chip_err(chip, "Error: tx (%u) and rx (%u) values are equal\n",
+				tx, rx);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int cl_fem_check_lut_validity(struct cl_chip *chip, u8 wiring_id)
+{
+	if (cl_fem_read_lut(chip)) {
+		cl_dbg_chip_err(chip, "None of the FEM LUTs is valid. Aborting.\n");
+		return -EINVAL;
+	}
+
+	switch (wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1))
+			return -EINVAL;
+		break;
+
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0))
+			return -EINVAL;
+		break;
+
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_ELASTIC))
+			return -EINVAL;
+		break;
+
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_SENSING))
+			return -EINVAL;
+		break;
+
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_SENSING))
+			return -EINVAL;
+		break;
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+		if (_cl_fem_check_lut_validity(chip, FEM_TYPE_TCV0) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_TCV1) ||
+		    _cl_fem_check_lut_validity(chip, FEM_TYPE_SENSING))
+			return -EINVAL;
+		break;
+
+	case FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6:
+	case FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6:
+	case FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2:
+	case FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2:
+	case FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2:
+	case FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4:
+	case FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED:
+	case FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2:
+	case FEM_WIRING_22_OBSOLETE:
+		cl_dbg_chip_err(chip, "wiring_id %u is not supported\n", wiring_id);
+		return -EOPNOTSUPP;
+
+	default:
+		cl_dbg_chip_err(chip, "Wiring_id [%u] is not valid [0..%u]\n",
+				wiring_id, FEM_WIRING_MAX - 1);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cl_fem_validate_wiring_id(struct cl_chip *chip, u8 wiring_id)
+{
+	switch (wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		return cl_chip_is_8ant(chip) ? 0 : -1;
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+		return cl_chip_is_6ant(chip) ? 0 : -1;
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+		return cl_chip_is_4ant(chip) ? 0 : -1;
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		return cl_chip_is_4ant(chip) || cl_chip_is_3ant(chip) ? 0 : -1;
+	default:
+		cl_dbg_chip_err(chip, "wiring_id %u is not valid. [0..%u] are valid values\n",
+				wiring_id, (FEM_WIRING_MAX - 1));
+		return -ERANGE;
+	}
+
+	return -EINVAL;
+}
+
+int cl_fem_read_wiring_id(struct cl_chip *chip)
+{
+	struct cl_fem_params *fem = &chip->fem;
+
+	/* In case there's a valid wiring id in chip, no need to re-read it from EEPROM */
+	if (fem->wiring_id < FEM_WIRING_MAX)
+		return 0;
+
+	/* Read wiring_id from eeprom */
+	if (cl_e2p_read(chip, &fem->wiring_id, SIZE_FEM_WIRING_ID, ADDR_FEM_WIRING_ID))
+		return -1;
+
+	return cl_fem_validate_wiring_id(chip, fem->wiring_id);
+}
+
+static void cl_fem_set_registers(struct cl_chip *chip)
+{
+	struct cl_fem_params *fem = &chip->fem;
+	int i;
+	u8 wiring_id = fem->wiring_id;
+
+	if (wiring_id >= FEM_WIRING_MAX)
+		return;
+
+	for (i = 0; i < FEM_LUT_AMOUNT_PER_MAC; i++) {
+		fem->lut_registers[TCV0][i] = fem->lut[fem_full_list[wiring_id][TCV0][i]];
+		fem->lut_registers[TCV1][i] = fem->lut[fem_full_list[wiring_id][TCV1][i]];
+	}
+}
+
+static int cl_fem_set_lut_off(struct cl_chip *chip)
+{
+	struct cl_fem_params *fem = &chip->fem;
+
+	switch (fem->wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_TCV0];
+		fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_TCV1];
+		break;
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+		fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_TCV0];
+		break;
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+		fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_ELASTIC];
+		fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_ELASTIC];
+		break;
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_TCV0];
+		fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_SENSING];
+		break;
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+		fem->lut_off_register[TCV0] = fem->lut_off_register_list[FEM_TYPE_SENSING];
+		fem->lut_off_register[TCV1] = fem->lut_off_register_list[FEM_TYPE_TCV1];
+		break;
+	default:
+		cl_dbg_chip_err(chip, "Unsupported wiring id [%u]\n", fem->wiring_id);
+		return -EINVAL;
+	}
+
+	cl_dbg_chip_trace(chip, "wiring_id = %u, lut_off_register = [%u %u]\n",
+			  fem->wiring_id,
+			  fem->lut_off_register[TCV0],
+			  fem->lut_off_register[TCV1]);
+	return 0;
+}
+
+int cl_fem_init(struct cl_chip *chip)
+{
+	int ret = 0;
+	struct cl_fem_params *fem = &chip->fem;
+
+	fem->wiring_id = FEM_WIRING_DEFAULT;
+
+	ret = cl_fem_read_wiring_id(chip);
+
+	if (ret) {
+		CL_DBG_ERROR_CHIP(chip, "Invalid wiring_id = %u. Aborting.\n", fem->wiring_id);
+
+		if (!chip->conf->ce_production_mode)
+			return ret;
+	}
+
+	if (cl_fem_read_lut(chip)) {
+		CL_DBG_ERROR_CHIP(chip, "None of the FEM_LUT registers is valid. Aborting.\n");
+
+		if (!chip->conf->ce_production_mode)
+			return -EINVAL;
+	}
+
+	if (cl_fem_check_lut_validity(chip, fem->wiring_id) &&
+	    !chip->conf->ce_production_mode)
+		return -EINVAL;
+
+	if (cl_fem_set_lut_off(chip) &&
+	    !chip->conf->ce_production_mode)
+		return -EINVAL;
+
+	cl_dbg_chip_verbose(chip, "wiring_id = %u\n", fem->wiring_id);
+	cl_fem_set_registers(chip);
+
+	ret = cl_platform_alloc(chip);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void cl_fem_get_conf_params(struct cl_chip *chip,
+				   u32 *ricu_fem_conf_0,
+				   u32 *ricu_fem_conf_1)
+{
+	u8 wiring_id = chip->fem.wiring_id;
+
+	*ricu_fem_conf_0 = ricu_fem_conf[wiring_id][0];
+	*ricu_fem_conf_1 = ricu_fem_conf[wiring_id][1];
+
+	cl_dbg_chip_verbose(chip, "ricu_fem_conf_0 = 0x%08X, ricu_fem_conf_1 = 0x%08X\n",
+			    *ricu_fem_conf_0, *ricu_fem_conf_1);
+}
+
+static u8 get_num_antennas_tcv0(struct cl_chip *chip)
+{
+	if (chip->cl_hw_tcv0)
+		return chip->cl_hw_tcv0->num_antennas;
+	else
+		return chip->max_antennas - chip->cl_hw_tcv1->num_antennas;
+}
+
+static void cl_update_formation_1_band_select(struct cl_chip *chip)
+{
+	u8 num_antennas_tcv0 = get_num_antennas_tcv0(chip);
+
+	if (num_antennas_tcv0 == 2) {
+		io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+	} else if (num_antennas_tcv0 == 3) {
+		io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+	} else if (num_antennas_tcv0 == 4) {
+		io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+	} else if (num_antennas_tcv0 == 5) {
+		io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(0));
+		io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+	} else if (num_antennas_tcv0 == 6) {
+		io_ctrl_pa_enable_4_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_5_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_8_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+		io_ctrl_pa_enable_9_set(chip, PA_ENABLE_GPIO_OUT_CFG(1));
+	}
+}
+
+static u8 cl_fem_extract_val(struct cl_chip *chip, u16 fem_lut, enum fem_mode mode)
+{
+	switch (mode) {
+	case FEM_MODE_LNA_BYPASS_ONLY:
+		return (fem_lut >> FEM_LUT_OFFSET_BYPASS) & FEM_LUT_VAL_MASK;
+	case FEM_MODE_TX_ONLY:
+		return (fem_lut >> FEM_LUT_OFFSET_TX) & FEM_LUT_VAL_MASK;
+	case FEM_MODE_RX_ONLY:
+		return (fem_lut >> FEM_LUT_OFFSET_RX) & FEM_LUT_VAL_MASK;
+	default:
+		cl_dbg_chip_err(chip, "Invalid fem mode %u\n", mode);
+	}
+
+	/* Return bypass value for invalid fem modes */
+	return (fem_lut >> FEM_LUT_OFFSET_BYPASS) & FEM_LUT_VAL_MASK;
+}
+
+static void cl_set_manual_fem_gpio(struct cl_chip *chip, enum fem_mode mode)
+{
+	struct cl_fem_params *fem = &chip->fem;
+	u8 fem_val_tcv0 = cl_fem_extract_val(chip, fem->lut[FEM_TYPE_TCV0], mode);
+	u8 fem_val_tcv1 = cl_fem_extract_val(chip, fem->lut[FEM_TYPE_TCV1], mode);
+	u8 fem_val_elastic = cl_fem_extract_val(chip, fem->lut[FEM_TYPE_ELASTIC], mode);
+	u8 fem_val_sensing = cl_fem_extract_val(chip, fem->lut[FEM_TYPE_SENSING], mode);
+	u8 pa_enable_bit_tcv0 = GET_BIT(fem_val_tcv0, PA_ENABLE_POS);
+	u8 pa_enable_bit_tcv1 = GET_BIT(fem_val_tcv1, PA_ENABLE_POS);
+	u8 pa_enable_bit_elastic = GET_BIT(fem_val_elastic, PA_ENABLE_POS);
+	u8 pa_enable_bit_sensing = GET_BIT(fem_val_sensing, PA_ENABLE_POS);
+	u8 lna_enable_bit_tcv0 = GET_BIT(fem_val_tcv0, LNA_ENABLE_POS);
+	u8 lna_enable_bit_tcv1 = GET_BIT(fem_val_tcv1, LNA_ENABLE_POS);
+	u8 lna_enable_bit_elastic = GET_BIT(fem_val_elastic, LNA_ENABLE_POS);
+	u8 lna_enable_bit_sensing = GET_BIT(fem_val_sensing, LNA_ENABLE_POS);
+	u8 rx_active_bit_tcv0 = GET_BIT(fem_val_tcv0, RX_ACTIVE_POS);
+	u8 rx_active_bit_tcv1 = GET_BIT(fem_val_tcv1, RX_ACTIVE_POS);
+	u8 rx_active_bit_sensing = GET_BIT(fem_val_sensing, RX_ACTIVE_POS);
+	u32 pa_enable_cfg_tcv0 = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_tcv0);
+	u32 pa_enable_cfg_tcv1 = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_tcv1);
+	u32 pa_enable_cfg_elastic = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_elastic);
+	u32 pa_enable_cfg_sensing = PA_ENABLE_GPIO_OUT_CFG(pa_enable_bit_sensing);
+	u32 lna_enable_cfg_tcv0 = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_tcv0);
+	u32 lna_enable_cfg_tcv1 = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_tcv1);
+	u32 lna_enable_cfg_elastic = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_elastic);
+	u32 lna_enable_cfg_sensing = LNA_ENABLE_GPIO_OUT_CFG(lna_enable_bit_sensing);
+	u32 rx_active_cfg_tcv0 = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_tcv0);
+	u32 rx_active_cfg_tcv1 = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_tcv1);
+	u32 rx_active_cfg_sensing = RX_ACTIVE_GPIO_OUT_CFG(rx_active_bit_sensing);
+
+	switch (fem->wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_7_TCV0_4_TCV1_4:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_16_TCV0_2_TCV1_2:
+	case FEM_WIRING_17_TCV0_4_TCV1_0:
+	case FEM_WIRING_18_TCV0_4_TCV1_4:
+	case FEM_WIRING_20_TCV0_2_TCV1_2:
+	case FEM_WIRING_23_TCV0_4_TCV1_4:
+	case FEM_WIRING_28_TCV0_4_TCV1_2:
+	case FEM_WIRING_30_TCV0_4_TCV1_2:
+	case FEM_WIRING_32_TCV0_4_TCV1_0:
+	case FEM_WIRING_33_TCV0_4_TCV1_4:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv0);
+		break;
+	case FEM_WIRING_31_TCV0_2_TCV1_1:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv0);
+		break;
+	case FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_elastic);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_elastic);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_elastic);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_elastic);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+		break;
+	case FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_15_CHAMELEON_4TX_4RX:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv0);
+		break;
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_sensing);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_sensing);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_4_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_pa_enable_5_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_pa_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_pa_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_pa_enable_8_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_pa_enable_9_set(chip, lna_enable_cfg_tcv1);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_sensing);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_sensing);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_sensing);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_sensing);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+		break;
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv1);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv1);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+		break;
+	case FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0:
+	case FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1:
+	case FEM_WIRING_27_TCV0_2_TCV1_1:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv1);
+		break;
+	case FEM_WIRING_29_TCV0_4_TCV1_2:
+		io_ctrl_lna_enable_0_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_1_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_2_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_3_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_4_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_5_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_6_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_7_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_8_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_9_set(chip, lna_enable_cfg_tcv1);
+		io_ctrl_lna_enable_10_set(chip, lna_enable_cfg_tcv0);
+		io_ctrl_lna_enable_11_set(chip, lna_enable_cfg_tcv0);
+
+		io_ctrl_pa_enable_0_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_1_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_2_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_3_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_4_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_5_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_6_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_7_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_8_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_9_set(chip, pa_enable_cfg_tcv1);
+		io_ctrl_pa_enable_10_set(chip, pa_enable_cfg_tcv0);
+		io_ctrl_pa_enable_11_set(chip, pa_enable_cfg_tcv0);
+
+		io_ctrl_rx_active_0_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_1_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_2_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_3_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_4_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_5_set(chip, rx_active_cfg_tcv1);
+		io_ctrl_rx_active_6_set(chip, rx_active_cfg_tcv0);
+		io_ctrl_rx_active_7_set(chip, rx_active_cfg_tcv0);
+		break;
+	default:
+		break;
+	}
+}
+
+static void cl_set_lna_bypass_gpio(struct cl_chip *chip)
+{
+	cl_set_manual_fem_gpio(chip, FEM_MODE_LNA_BYPASS_ONLY);
+}
+
+static void _cl_fem_conf_gpio(struct cl_chip *chip,
+			      const struct cl_fem_lna_enable_gpio *lna_enable_gpio,
+			      const struct cl_fem_pa_enable_gpio *pa_enable_gpio,
+			      const struct cl_fem_rx_active_gpio *rx_active_gpio)
+{
+	io_ctrl_lna_enable_0_gpio_enable_setf(chip, lna_enable_gpio->bits.b0);
+	io_ctrl_lna_enable_1_gpio_enable_setf(chip, lna_enable_gpio->bits.b1);
+	io_ctrl_lna_enable_2_gpio_enable_setf(chip, lna_enable_gpio->bits.b2);
+	io_ctrl_lna_enable_3_gpio_enable_setf(chip, lna_enable_gpio->bits.b3);
+	io_ctrl_lna_enable_4_gpio_enable_setf(chip, lna_enable_gpio->bits.b4);
+	io_ctrl_lna_enable_5_gpio_enable_setf(chip, lna_enable_gpio->bits.b5);
+	io_ctrl_lna_enable_6_gpio_enable_setf(chip, lna_enable_gpio->bits.b6);
+	io_ctrl_lna_enable_7_gpio_enable_setf(chip, lna_enable_gpio->bits.b7);
+	io_ctrl_lna_enable_8_gpio_enable_setf(chip, lna_enable_gpio->bits.b8);
+	io_ctrl_lna_enable_9_gpio_enable_setf(chip, lna_enable_gpio->bits.b9);
+	io_ctrl_lna_enable_10_gpio_enable_setf(chip, lna_enable_gpio->bits.b10);
+	io_ctrl_lna_enable_11_gpio_enable_setf(chip, lna_enable_gpio->bits.b11);
+
+	io_ctrl_pa_enable_0_gpio_enable_setf(chip, pa_enable_gpio->bits.b0);
+	io_ctrl_pa_enable_1_gpio_enable_setf(chip, pa_enable_gpio->bits.b1);
+	io_ctrl_pa_enable_2_gpio_enable_setf(chip, pa_enable_gpio->bits.b2);
+	io_ctrl_pa_enable_3_gpio_enable_setf(chip, pa_enable_gpio->bits.b3);
+	io_ctrl_pa_enable_4_gpio_enable_setf(chip, pa_enable_gpio->bits.b4);
+	io_ctrl_pa_enable_5_gpio_enable_setf(chip, pa_enable_gpio->bits.b5);
+	io_ctrl_pa_enable_6_gpio_enable_setf(chip, pa_enable_gpio->bits.b6);
+	io_ctrl_pa_enable_7_gpio_enable_setf(chip, pa_enable_gpio->bits.b7);
+	io_ctrl_pa_enable_8_gpio_enable_setf(chip, pa_enable_gpio->bits.b8);
+	io_ctrl_pa_enable_9_gpio_enable_setf(chip, pa_enable_gpio->bits.b9);
+	io_ctrl_pa_enable_10_gpio_enable_setf(chip, pa_enable_gpio->bits.b10);
+	io_ctrl_pa_enable_11_gpio_enable_setf(chip, pa_enable_gpio->bits.b11);
+
+	io_ctrl_rx_active_0_gpio_enable_setf(chip, rx_active_gpio->bits.b0);
+	io_ctrl_rx_active_1_gpio_enable_setf(chip, rx_active_gpio->bits.b1);
+	io_ctrl_rx_active_2_gpio_enable_setf(chip, rx_active_gpio->bits.b2);
+	io_ctrl_rx_active_3_gpio_enable_setf(chip, rx_active_gpio->bits.b3);
+	io_ctrl_rx_active_4_gpio_enable_setf(chip, rx_active_gpio->bits.b4);
+	io_ctrl_rx_active_5_gpio_enable_setf(chip, rx_active_gpio->bits.b5);
+	io_ctrl_rx_active_6_gpio_enable_setf(chip, rx_active_gpio->bits.b7);
+	io_ctrl_rx_active_7_gpio_enable_setf(chip, rx_active_gpio->bits.b7);
+}
+
+static int cl_fem_conf_gpio(struct cl_chip *chip)
+{
+	struct cl_fem_params *fem = &chip->fem;
+	u8 wiring_id = fem->wiring_id;
+
+	if (wiring_id == FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6 ||
+	    wiring_id == FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6 ||
+	    wiring_id == FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 ||
+	    wiring_id == FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 ||
+	    wiring_id == FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 ||
+	    wiring_id == FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4 ||
+	    wiring_id == FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED ||
+	    wiring_id == FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2 ||
+	    wiring_id == FEM_WIRING_22_OBSOLETE) {
+		cl_dbg_chip_err(chip, "Unsupported wiring id [%u]\n", wiring_id);
+		return -EOPNOTSUPP;
+	}
+
+	if (cl_fem_validate_wiring_id(chip, wiring_id))
+		return -EINVAL;
+
+	_cl_fem_conf_gpio(chip,
+			  &lna_enable_gpio[wiring_id],
+			  &pa_enable_gpio[wiring_id],
+			  &rx_active_gpio[wiring_id]);
+
+	if (wiring_id == FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2)
+		cl_update_formation_1_band_select(chip);
+
+	return 0;
+}
+
+static int cl_fem_update_lut(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	ret = cl_fem_read_lut(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_fem_check_lut_validity(chip, chip->fem.wiring_id);
+	if (ret)
+		return ret;
+
+	/* In case of invalid platform id, don't update FEM conf params*/
+	ret = cl_fem_set_lut_off(chip);
+	if (ret)
+		return ret;
+
+	cl_fem_set_registers(chip);
+
+	return ret;
+}
+
+void cl_fem_set_dcoc_bypass(struct cl_hw *cl_hw)
+{
+	cl_hw->fem_mode = FEM_MODE_LNA_BYPASS_ONLY;
+}
+
+void cl_fem_dcoc_restore(struct cl_hw *cl_hw, u8 fem_mode)
+{
+	cl_hw->fem_mode = fem_mode;
+}
+
+void cl_fem_set_iq_bypass(struct cl_hw *cl_hw)
+{
+	cl_set_lna_bypass_gpio(cl_hw->chip);
+
+	cl_hw->fem_mode = FEM_MODE_LNA_BYPASS_ONLY;
+}
+
+void cl_fem_iq_restore(struct cl_hw *cl_hw, u8 fem_mode)
+{
+	cl_fem_conf_gpio(cl_hw->chip);
+	cl_hw->fem_mode = fem_mode;
+}
+
+int cl_fem_update_conf_params(struct cl_chip *chip)
+{
+	u32 ricu_fem_conf_0, ricu_fem_conf_1 = 0;
+	int ret = 0;
+
+	ret = cl_fem_update_lut(chip);
+	if (ret)
+		return ret;
+
+	cl_fem_get_conf_params(chip, &ricu_fem_conf_0, &ricu_fem_conf_1);
+	ricu_fem_conf_0_set(chip, ricu_fem_conf_0);
+	ricu_fem_conf_1_set(chip, ricu_fem_conf_1);
+
+	ret = cl_fem_conf_gpio(chip);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+bool cl_fem_wiring_id_is_evb(struct cl_chip *chip)
+{
+	u8 wiring_id = chip->fem.wiring_id;
+
+	switch (wiring_id) {
+	case FEM_WIRING_0_TCV0_6_TCV1_6:
+	case FEM_WIRING_9_TCV0_4_TCV1_4:
+	case FEM_WIRING_10_TCV0_4_TCV1_4:
+	case FEM_WIRING_13_SENSING_4RX_2TX:
+	case FEM_WIRING_14_SENSING_4TX_2RX:
+	case FEM_WIRING_24_TCV0_6_TCV1_4:
+		return true;
+	default:
+		break;
+	}
+
+	return false;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 51/96] cl8k: add phy.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (49 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 52/96] cl8k: add platform.c viktor.barna
                   ` (44 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/phy.h | 3680 ++++++++++++++++++++++++
 1 file changed, 3680 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/phy.h

diff --git a/drivers/net/wireless/celeno/cl8k/phy.h b/drivers/net/wireless/celeno/cl8k/phy.h
new file mode 100644
index 000000000000..ed5a2d847d3d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/phy.h
@@ -0,0 +1,3680 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_PHY_H
+#define CL_PHY_H
+
+#include <linux/types.h>
+
+#include "power.h"
+#include "def.h"
+
+struct cl_phy_data {
+	struct cl_pwr_tables pwr_tables;
+	struct cl_iq_dcoc_info iq_dcoc_db;
+	struct cl_agc_params agc_params;
+};
+
+struct cl_phy_data_info {
+	struct cl_phy_data *data;
+	u32 dma_addr;
+};
+
+void cl_phy_reset(struct cl_hw *cl_hw);
+void cl_phy_off(struct cl_hw *cl_hw);
+int cl_phy_load_recovery(struct cl_hw *cl_hw);
+int cl_phy_data_alloc(struct cl_hw *cl_hw);
+void cl_phy_data_free(struct cl_hw *cl_hw);
+void cl_phy_enable(struct cl_hw *cl_hw);
+
+struct common_lut_line {
+	u16 frequency_q2;
+	u8 vcocalsel;
+	u8 nint;
+	u32 nfrac;
+	u32 freqmeastarg;
+};
+
+void cl_phy_oly_lut_update(u8 rfic_version, u8 nl_band, u16 freq,
+			   struct mm_mac_api_lut_line *api_lut_line);
+
+enum athos_lut_idx_6g {
+	ATHOS_LUT_CHAN_593000_IDX,
+	ATHOS_LUT_CHAN_593125_IDX,
+	ATHOS_LUT_CHAN_593250_IDX,
+	ATHOS_LUT_CHAN_593375_IDX,
+	ATHOS_LUT_CHAN_593500_IDX,
+	ATHOS_LUT_CHAN_593625_IDX,
+	ATHOS_LUT_CHAN_593750_IDX,
+	ATHOS_LUT_CHAN_593875_IDX,
+	ATHOS_LUT_CHAN_594000_IDX,
+	ATHOS_LUT_CHAN_594125_IDX,
+	ATHOS_LUT_CHAN_594250_IDX,
+	ATHOS_LUT_CHAN_594375_IDX,
+	ATHOS_LUT_CHAN_594500_IDX,
+	ATHOS_LUT_CHAN_594625_IDX,
+	ATHOS_LUT_CHAN_594750_IDX,
+	ATHOS_LUT_CHAN_594875_IDX,
+	ATHOS_LUT_CHAN_595000_IDX,
+	ATHOS_LUT_CHAN_595125_IDX,
+	ATHOS_LUT_CHAN_595250_IDX,
+	ATHOS_LUT_CHAN_595375_IDX,
+	ATHOS_LUT_CHAN_595500_IDX,
+	ATHOS_LUT_CHAN_595625_IDX,
+	ATHOS_LUT_CHAN_595750_IDX,
+	ATHOS_LUT_CHAN_595875_IDX,
+	ATHOS_LUT_CHAN_596000_IDX,
+	ATHOS_LUT_CHAN_596125_IDX,
+	ATHOS_LUT_CHAN_596250_IDX,
+	ATHOS_LUT_CHAN_596375_IDX,
+	ATHOS_LUT_CHAN_596500_IDX,
+	ATHOS_LUT_CHAN_596625_IDX,
+	ATHOS_LUT_CHAN_596750_IDX,
+	ATHOS_LUT_CHAN_596875_IDX,
+	ATHOS_LUT_CHAN_597000_IDX,
+	ATHOS_LUT_CHAN_597125_IDX,
+	ATHOS_LUT_CHAN_597250_IDX,
+	ATHOS_LUT_CHAN_597375_IDX,
+	ATHOS_LUT_CHAN_597500_IDX,
+	ATHOS_LUT_CHAN_597625_IDX,
+	ATHOS_LUT_CHAN_597750_IDX,
+	ATHOS_LUT_CHAN_597875_IDX,
+	ATHOS_LUT_CHAN_598000_IDX,
+	ATHOS_LUT_CHAN_598125_IDX,
+	ATHOS_LUT_CHAN_598250_IDX,
+	ATHOS_LUT_CHAN_598375_IDX,
+	ATHOS_LUT_CHAN_598500_IDX,
+	ATHOS_LUT_CHAN_598625_IDX,
+	ATHOS_LUT_CHAN_598750_IDX,
+	ATHOS_LUT_CHAN_598875_IDX,
+	ATHOS_LUT_CHAN_599000_IDX,
+	ATHOS_LUT_CHAN_599125_IDX,
+	ATHOS_LUT_CHAN_599250_IDX,
+	ATHOS_LUT_CHAN_599375_IDX,
+	ATHOS_LUT_CHAN_599500_IDX,
+	ATHOS_LUT_CHAN_599625_IDX,
+	ATHOS_LUT_CHAN_599750_IDX,
+	ATHOS_LUT_CHAN_599875_IDX,
+	ATHOS_LUT_CHAN_600000_IDX,
+	ATHOS_LUT_CHAN_600125_IDX,
+	ATHOS_LUT_CHAN_600250_IDX,
+	ATHOS_LUT_CHAN_600375_IDX,
+	ATHOS_LUT_CHAN_600500_IDX,
+	ATHOS_LUT_CHAN_600625_IDX,
+	ATHOS_LUT_CHAN_600750_IDX,
+	ATHOS_LUT_CHAN_600875_IDX,
+	ATHOS_LUT_CHAN_601000_IDX,
+	ATHOS_LUT_CHAN_601125_IDX,
+	ATHOS_LUT_CHAN_601250_IDX,
+	ATHOS_LUT_CHAN_601375_IDX,
+	ATHOS_LUT_CHAN_601500_IDX,
+	ATHOS_LUT_CHAN_601625_IDX,
+	ATHOS_LUT_CHAN_601750_IDX,
+	ATHOS_LUT_CHAN_601875_IDX,
+	ATHOS_LUT_CHAN_602000_IDX,
+	ATHOS_LUT_CHAN_602125_IDX,
+	ATHOS_LUT_CHAN_602250_IDX,
+	ATHOS_LUT_CHAN_602375_IDX,
+	ATHOS_LUT_CHAN_602500_IDX,
+	ATHOS_LUT_CHAN_602625_IDX,
+	ATHOS_LUT_CHAN_602750_IDX,
+	ATHOS_LUT_CHAN_602875_IDX,
+	ATHOS_LUT_CHAN_603000_IDX,
+	ATHOS_LUT_CHAN_603125_IDX,
+	ATHOS_LUT_CHAN_603250_IDX,
+	ATHOS_LUT_CHAN_603375_IDX,
+	ATHOS_LUT_CHAN_603500_IDX,
+	ATHOS_LUT_CHAN_603625_IDX,
+	ATHOS_LUT_CHAN_603750_IDX,
+	ATHOS_LUT_CHAN_603875_IDX,
+	ATHOS_LUT_CHAN_604000_IDX,
+	ATHOS_LUT_CHAN_604125_IDX,
+	ATHOS_LUT_CHAN_604250_IDX,
+	ATHOS_LUT_CHAN_604375_IDX,
+	ATHOS_LUT_CHAN_604500_IDX,
+	ATHOS_LUT_CHAN_604625_IDX,
+	ATHOS_LUT_CHAN_604750_IDX,
+	ATHOS_LUT_CHAN_604875_IDX,
+	ATHOS_LUT_CHAN_605000_IDX,
+	ATHOS_LUT_CHAN_605125_IDX,
+	ATHOS_LUT_CHAN_605250_IDX,
+	ATHOS_LUT_CHAN_605375_IDX,
+	ATHOS_LUT_CHAN_605500_IDX,
+	ATHOS_LUT_CHAN_605625_IDX,
+	ATHOS_LUT_CHAN_605750_IDX,
+	ATHOS_LUT_CHAN_605875_IDX,
+	ATHOS_LUT_CHAN_606000_IDX,
+	ATHOS_LUT_CHAN_606125_IDX,
+	ATHOS_LUT_CHAN_606250_IDX,
+	ATHOS_LUT_CHAN_606375_IDX,
+	ATHOS_LUT_CHAN_606500_IDX,
+	ATHOS_LUT_CHAN_606625_IDX,
+	ATHOS_LUT_CHAN_606750_IDX,
+	ATHOS_LUT_CHAN_606875_IDX,
+	ATHOS_LUT_CHAN_607000_IDX,
+	ATHOS_LUT_CHAN_607125_IDX,
+	ATHOS_LUT_CHAN_607250_IDX,
+	ATHOS_LUT_CHAN_607375_IDX,
+	ATHOS_LUT_CHAN_607500_IDX,
+	ATHOS_LUT_CHAN_607625_IDX,
+	ATHOS_LUT_CHAN_607750_IDX,
+	ATHOS_LUT_CHAN_607875_IDX,
+	ATHOS_LUT_CHAN_608000_IDX,
+	ATHOS_LUT_CHAN_608125_IDX,
+	ATHOS_LUT_CHAN_608250_IDX,
+	ATHOS_LUT_CHAN_608375_IDX,
+	ATHOS_LUT_CHAN_608500_IDX,
+	ATHOS_LUT_CHAN_608625_IDX,
+	ATHOS_LUT_CHAN_608750_IDX,
+	ATHOS_LUT_CHAN_608875_IDX,
+	ATHOS_LUT_CHAN_609000_IDX,
+	ATHOS_LUT_CHAN_609125_IDX,
+	ATHOS_LUT_CHAN_609250_IDX,
+	ATHOS_LUT_CHAN_609375_IDX,
+	ATHOS_LUT_CHAN_609500_IDX,
+	ATHOS_LUT_CHAN_609625_IDX,
+	ATHOS_LUT_CHAN_609750_IDX,
+	ATHOS_LUT_CHAN_609875_IDX,
+	ATHOS_LUT_CHAN_610000_IDX,
+	ATHOS_LUT_CHAN_610125_IDX,
+	ATHOS_LUT_CHAN_610250_IDX,
+	ATHOS_LUT_CHAN_610375_IDX,
+	ATHOS_LUT_CHAN_610500_IDX,
+	ATHOS_LUT_CHAN_610625_IDX,
+	ATHOS_LUT_CHAN_610750_IDX,
+	ATHOS_LUT_CHAN_610875_IDX,
+	ATHOS_LUT_CHAN_611000_IDX,
+	ATHOS_LUT_CHAN_611125_IDX,
+	ATHOS_LUT_CHAN_611250_IDX,
+	ATHOS_LUT_CHAN_611375_IDX,
+	ATHOS_LUT_CHAN_611500_IDX,
+	ATHOS_LUT_CHAN_611625_IDX,
+	ATHOS_LUT_CHAN_611750_IDX,
+	ATHOS_LUT_CHAN_611875_IDX,
+	ATHOS_LUT_CHAN_612000_IDX,
+	ATHOS_LUT_CHAN_612125_IDX,
+	ATHOS_LUT_CHAN_612250_IDX,
+	ATHOS_LUT_CHAN_612375_IDX,
+	ATHOS_LUT_CHAN_612500_IDX,
+	ATHOS_LUT_CHAN_612625_IDX,
+	ATHOS_LUT_CHAN_612750_IDX,
+	ATHOS_LUT_CHAN_612875_IDX,
+	ATHOS_LUT_CHAN_613000_IDX,
+	ATHOS_LUT_CHAN_613125_IDX,
+	ATHOS_LUT_CHAN_613250_IDX,
+	ATHOS_LUT_CHAN_613375_IDX,
+	ATHOS_LUT_CHAN_613500_IDX,
+	ATHOS_LUT_CHAN_613625_IDX,
+	ATHOS_LUT_CHAN_613750_IDX,
+	ATHOS_LUT_CHAN_613875_IDX,
+	ATHOS_LUT_CHAN_614000_IDX,
+	ATHOS_LUT_CHAN_614125_IDX,
+	ATHOS_LUT_CHAN_614250_IDX,
+	ATHOS_LUT_CHAN_614375_IDX,
+	ATHOS_LUT_CHAN_614500_IDX,
+	ATHOS_LUT_CHAN_614625_IDX,
+	ATHOS_LUT_CHAN_614750_IDX,
+	ATHOS_LUT_CHAN_614875_IDX,
+	ATHOS_LUT_CHAN_615000_IDX,
+	ATHOS_LUT_CHAN_615125_IDX,
+	ATHOS_LUT_CHAN_615250_IDX,
+	ATHOS_LUT_CHAN_615375_IDX,
+	ATHOS_LUT_CHAN_615500_IDX,
+	ATHOS_LUT_CHAN_615625_IDX,
+	ATHOS_LUT_CHAN_615750_IDX,
+	ATHOS_LUT_CHAN_615875_IDX,
+	ATHOS_LUT_CHAN_616000_IDX,
+	ATHOS_LUT_CHAN_616125_IDX,
+	ATHOS_LUT_CHAN_616250_IDX,
+	ATHOS_LUT_CHAN_616375_IDX,
+	ATHOS_LUT_CHAN_616500_IDX,
+	ATHOS_LUT_CHAN_616625_IDX,
+	ATHOS_LUT_CHAN_616750_IDX,
+	ATHOS_LUT_CHAN_616875_IDX,
+	ATHOS_LUT_CHAN_617000_IDX,
+	ATHOS_LUT_CHAN_617125_IDX,
+	ATHOS_LUT_CHAN_617250_IDX,
+	ATHOS_LUT_CHAN_617375_IDX,
+	ATHOS_LUT_CHAN_617500_IDX,
+	ATHOS_LUT_CHAN_617625_IDX,
+	ATHOS_LUT_CHAN_617750_IDX,
+	ATHOS_LUT_CHAN_617875_IDX,
+	ATHOS_LUT_CHAN_618000_IDX,
+	ATHOS_LUT_CHAN_618125_IDX,
+	ATHOS_LUT_CHAN_618250_IDX,
+	ATHOS_LUT_CHAN_618375_IDX,
+	ATHOS_LUT_CHAN_618500_IDX,
+	ATHOS_LUT_CHAN_618625_IDX,
+	ATHOS_LUT_CHAN_618750_IDX,
+	ATHOS_LUT_CHAN_618875_IDX,
+	ATHOS_LUT_CHAN_619000_IDX,
+	ATHOS_LUT_CHAN_619125_IDX,
+	ATHOS_LUT_CHAN_619250_IDX,
+	ATHOS_LUT_CHAN_619375_IDX,
+	ATHOS_LUT_CHAN_619500_IDX,
+	ATHOS_LUT_CHAN_619625_IDX,
+	ATHOS_LUT_CHAN_619750_IDX,
+	ATHOS_LUT_CHAN_619875_IDX,
+	ATHOS_LUT_CHAN_620000_IDX,
+	ATHOS_LUT_CHAN_620125_IDX,
+	ATHOS_LUT_CHAN_620250_IDX,
+	ATHOS_LUT_CHAN_620375_IDX,
+	ATHOS_LUT_CHAN_620500_IDX,
+	ATHOS_LUT_CHAN_620625_IDX,
+	ATHOS_LUT_CHAN_620750_IDX,
+	ATHOS_LUT_CHAN_620875_IDX,
+	ATHOS_LUT_CHAN_621000_IDX,
+	ATHOS_LUT_CHAN_621125_IDX,
+	ATHOS_LUT_CHAN_621250_IDX,
+	ATHOS_LUT_CHAN_621375_IDX,
+	ATHOS_LUT_CHAN_621500_IDX,
+	ATHOS_LUT_CHAN_621625_IDX,
+	ATHOS_LUT_CHAN_621750_IDX,
+	ATHOS_LUT_CHAN_621875_IDX,
+	ATHOS_LUT_CHAN_622000_IDX,
+	ATHOS_LUT_CHAN_622125_IDX,
+	ATHOS_LUT_CHAN_622250_IDX,
+	ATHOS_LUT_CHAN_622375_IDX,
+	ATHOS_LUT_CHAN_622500_IDX,
+	ATHOS_LUT_CHAN_622625_IDX,
+	ATHOS_LUT_CHAN_622750_IDX,
+	ATHOS_LUT_CHAN_622875_IDX,
+	ATHOS_LUT_CHAN_623000_IDX,
+	ATHOS_LUT_CHAN_623125_IDX,
+	ATHOS_LUT_CHAN_623250_IDX,
+	ATHOS_LUT_CHAN_623375_IDX,
+	ATHOS_LUT_CHAN_623500_IDX,
+	ATHOS_LUT_CHAN_623625_IDX,
+	ATHOS_LUT_CHAN_623750_IDX,
+	ATHOS_LUT_CHAN_623875_IDX,
+	ATHOS_LUT_CHAN_624000_IDX,
+	ATHOS_LUT_CHAN_624125_IDX,
+	ATHOS_LUT_CHAN_624250_IDX,
+	ATHOS_LUT_CHAN_624375_IDX,
+	ATHOS_LUT_CHAN_624500_IDX,
+	ATHOS_LUT_CHAN_624625_IDX,
+	ATHOS_LUT_CHAN_624750_IDX,
+	ATHOS_LUT_CHAN_624875_IDX,
+	ATHOS_LUT_CHAN_625000_IDX,
+	ATHOS_LUT_CHAN_625125_IDX,
+	ATHOS_LUT_CHAN_625250_IDX,
+	ATHOS_LUT_CHAN_625375_IDX,
+	ATHOS_LUT_CHAN_625500_IDX,
+	ATHOS_LUT_CHAN_625625_IDX,
+	ATHOS_LUT_CHAN_625750_IDX,
+	ATHOS_LUT_CHAN_625875_IDX,
+	ATHOS_LUT_CHAN_626000_IDX,
+	ATHOS_LUT_CHAN_626125_IDX,
+	ATHOS_LUT_CHAN_626250_IDX,
+	ATHOS_LUT_CHAN_626375_IDX,
+	ATHOS_LUT_CHAN_626500_IDX,
+	ATHOS_LUT_CHAN_626625_IDX,
+	ATHOS_LUT_CHAN_626750_IDX,
+	ATHOS_LUT_CHAN_626875_IDX,
+	ATHOS_LUT_CHAN_627000_IDX,
+	ATHOS_LUT_CHAN_627125_IDX,
+	ATHOS_LUT_CHAN_627250_IDX,
+	ATHOS_LUT_CHAN_627375_IDX,
+	ATHOS_LUT_CHAN_627500_IDX,
+	ATHOS_LUT_CHAN_627625_IDX,
+	ATHOS_LUT_CHAN_627750_IDX,
+	ATHOS_LUT_CHAN_627875_IDX,
+	ATHOS_LUT_CHAN_628000_IDX,
+	ATHOS_LUT_CHAN_628125_IDX,
+	ATHOS_LUT_CHAN_628250_IDX,
+	ATHOS_LUT_CHAN_628375_IDX,
+	ATHOS_LUT_CHAN_628500_IDX,
+	ATHOS_LUT_CHAN_628625_IDX,
+	ATHOS_LUT_CHAN_628750_IDX,
+	ATHOS_LUT_CHAN_628875_IDX,
+	ATHOS_LUT_CHAN_629000_IDX,
+	ATHOS_LUT_CHAN_629125_IDX,
+	ATHOS_LUT_CHAN_629250_IDX,
+	ATHOS_LUT_CHAN_629375_IDX,
+	ATHOS_LUT_CHAN_629500_IDX,
+	ATHOS_LUT_CHAN_629625_IDX,
+	ATHOS_LUT_CHAN_629750_IDX,
+	ATHOS_LUT_CHAN_629875_IDX,
+	ATHOS_LUT_CHAN_630000_IDX,
+	ATHOS_LUT_CHAN_630125_IDX,
+	ATHOS_LUT_CHAN_630250_IDX,
+	ATHOS_LUT_CHAN_630375_IDX,
+	ATHOS_LUT_CHAN_630500_IDX,
+	ATHOS_LUT_CHAN_630625_IDX,
+	ATHOS_LUT_CHAN_630750_IDX,
+	ATHOS_LUT_CHAN_630875_IDX,
+	ATHOS_LUT_CHAN_631000_IDX,
+	ATHOS_LUT_CHAN_631125_IDX,
+	ATHOS_LUT_CHAN_631250_IDX,
+	ATHOS_LUT_CHAN_631375_IDX,
+	ATHOS_LUT_CHAN_631500_IDX,
+	ATHOS_LUT_CHAN_631625_IDX,
+	ATHOS_LUT_CHAN_631750_IDX,
+	ATHOS_LUT_CHAN_631875_IDX,
+	ATHOS_LUT_CHAN_632000_IDX,
+	ATHOS_LUT_CHAN_632125_IDX,
+	ATHOS_LUT_CHAN_632250_IDX,
+	ATHOS_LUT_CHAN_632375_IDX,
+	ATHOS_LUT_CHAN_632500_IDX,
+	ATHOS_LUT_CHAN_632625_IDX,
+	ATHOS_LUT_CHAN_632750_IDX,
+	ATHOS_LUT_CHAN_632875_IDX,
+	ATHOS_LUT_CHAN_633000_IDX,
+	ATHOS_LUT_CHAN_633125_IDX,
+	ATHOS_LUT_CHAN_633250_IDX,
+	ATHOS_LUT_CHAN_633375_IDX,
+	ATHOS_LUT_CHAN_633500_IDX,
+	ATHOS_LUT_CHAN_633625_IDX,
+	ATHOS_LUT_CHAN_633750_IDX,
+	ATHOS_LUT_CHAN_633875_IDX,
+	ATHOS_LUT_CHAN_634000_IDX,
+	ATHOS_LUT_CHAN_634125_IDX,
+	ATHOS_LUT_CHAN_634250_IDX,
+	ATHOS_LUT_CHAN_634375_IDX,
+	ATHOS_LUT_CHAN_634500_IDX,
+	ATHOS_LUT_CHAN_634625_IDX,
+	ATHOS_LUT_CHAN_634750_IDX,
+	ATHOS_LUT_CHAN_634875_IDX,
+	ATHOS_LUT_CHAN_635000_IDX,
+	ATHOS_LUT_CHAN_635125_IDX,
+	ATHOS_LUT_CHAN_635250_IDX,
+	ATHOS_LUT_CHAN_635375_IDX,
+	ATHOS_LUT_CHAN_635500_IDX,
+	ATHOS_LUT_CHAN_635625_IDX,
+	ATHOS_LUT_CHAN_635750_IDX,
+	ATHOS_LUT_CHAN_635875_IDX,
+	ATHOS_LUT_CHAN_636000_IDX,
+	ATHOS_LUT_CHAN_636125_IDX,
+	ATHOS_LUT_CHAN_636250_IDX,
+	ATHOS_LUT_CHAN_636375_IDX,
+	ATHOS_LUT_CHAN_636500_IDX,
+	ATHOS_LUT_CHAN_636625_IDX,
+	ATHOS_LUT_CHAN_636750_IDX,
+	ATHOS_LUT_CHAN_636875_IDX,
+	ATHOS_LUT_CHAN_637000_IDX,
+	ATHOS_LUT_CHAN_637125_IDX,
+	ATHOS_LUT_CHAN_637250_IDX,
+	ATHOS_LUT_CHAN_637375_IDX,
+	ATHOS_LUT_CHAN_637500_IDX,
+	ATHOS_LUT_CHAN_637625_IDX,
+	ATHOS_LUT_CHAN_637750_IDX,
+	ATHOS_LUT_CHAN_637875_IDX,
+	ATHOS_LUT_CHAN_638000_IDX,
+	ATHOS_LUT_CHAN_638125_IDX,
+	ATHOS_LUT_CHAN_638250_IDX,
+	ATHOS_LUT_CHAN_638375_IDX,
+	ATHOS_LUT_CHAN_638500_IDX,
+	ATHOS_LUT_CHAN_638625_IDX,
+	ATHOS_LUT_CHAN_638750_IDX,
+	ATHOS_LUT_CHAN_638875_IDX,
+	ATHOS_LUT_CHAN_639000_IDX,
+	ATHOS_LUT_CHAN_639125_IDX,
+	ATHOS_LUT_CHAN_639250_IDX,
+	ATHOS_LUT_CHAN_639375_IDX,
+	ATHOS_LUT_CHAN_639500_IDX,
+	ATHOS_LUT_CHAN_639625_IDX,
+	ATHOS_LUT_CHAN_639750_IDX,
+	ATHOS_LUT_CHAN_639875_IDX,
+	ATHOS_LUT_CHAN_640000_IDX,
+	ATHOS_LUT_CHAN_640125_IDX,
+	ATHOS_LUT_CHAN_640250_IDX,
+	ATHOS_LUT_CHAN_640375_IDX,
+	ATHOS_LUT_CHAN_640500_IDX,
+	ATHOS_LUT_CHAN_640625_IDX,
+	ATHOS_LUT_CHAN_640750_IDX,
+	ATHOS_LUT_CHAN_640875_IDX,
+	ATHOS_LUT_CHAN_641000_IDX,
+	ATHOS_LUT_CHAN_641125_IDX,
+	ATHOS_LUT_CHAN_641250_IDX,
+	ATHOS_LUT_CHAN_641375_IDX,
+	ATHOS_LUT_CHAN_641500_IDX,
+	ATHOS_LUT_CHAN_641625_IDX,
+	ATHOS_LUT_CHAN_641750_IDX,
+	ATHOS_LUT_CHAN_641875_IDX,
+	ATHOS_LUT_CHAN_642000_IDX,
+	ATHOS_LUT_CHAN_642125_IDX,
+	ATHOS_LUT_CHAN_642250_IDX,
+	ATHOS_LUT_CHAN_642375_IDX,
+	ATHOS_LUT_CHAN_642500_IDX,
+	ATHOS_LUT_CHAN_642625_IDX,
+	ATHOS_LUT_CHAN_642750_IDX,
+	ATHOS_LUT_CHAN_642875_IDX,
+	ATHOS_LUT_CHAN_643000_IDX,
+	ATHOS_LUT_CHAN_643125_IDX,
+	ATHOS_LUT_CHAN_643250_IDX,
+	ATHOS_LUT_CHAN_643375_IDX,
+	ATHOS_LUT_CHAN_643500_IDX,
+	ATHOS_LUT_CHAN_643625_IDX,
+	ATHOS_LUT_CHAN_643750_IDX,
+	ATHOS_LUT_CHAN_643875_IDX,
+	ATHOS_LUT_CHAN_644000_IDX,
+	ATHOS_LUT_CHAN_644125_IDX,
+	ATHOS_LUT_CHAN_644250_IDX,
+	ATHOS_LUT_CHAN_644375_IDX,
+	ATHOS_LUT_CHAN_644500_IDX,
+	ATHOS_LUT_CHAN_644625_IDX,
+	ATHOS_LUT_CHAN_644750_IDX,
+	ATHOS_LUT_CHAN_644875_IDX,
+	ATHOS_LUT_CHAN_645000_IDX,
+	ATHOS_LUT_CHAN_645125_IDX,
+	ATHOS_LUT_CHAN_645250_IDX,
+	ATHOS_LUT_CHAN_645375_IDX,
+	ATHOS_LUT_CHAN_645500_IDX,
+	ATHOS_LUT_CHAN_645625_IDX,
+	ATHOS_LUT_CHAN_645750_IDX,
+	ATHOS_LUT_CHAN_645875_IDX,
+	ATHOS_LUT_CHAN_646000_IDX,
+	ATHOS_LUT_CHAN_646125_IDX,
+	ATHOS_LUT_CHAN_646250_IDX,
+	ATHOS_LUT_CHAN_646375_IDX,
+	ATHOS_LUT_CHAN_646500_IDX,
+	ATHOS_LUT_CHAN_646625_IDX,
+	ATHOS_LUT_CHAN_646750_IDX,
+	ATHOS_LUT_CHAN_646875_IDX,
+	ATHOS_LUT_CHAN_647000_IDX,
+	ATHOS_LUT_CHAN_647125_IDX,
+	ATHOS_LUT_CHAN_647250_IDX,
+	ATHOS_LUT_CHAN_647375_IDX,
+	ATHOS_LUT_CHAN_647500_IDX,
+	ATHOS_LUT_CHAN_647625_IDX,
+	ATHOS_LUT_CHAN_647750_IDX,
+	ATHOS_LUT_CHAN_647875_IDX,
+	ATHOS_LUT_CHAN_648000_IDX,
+	ATHOS_LUT_CHAN_648125_IDX,
+	ATHOS_LUT_CHAN_648250_IDX,
+	ATHOS_LUT_CHAN_648375_IDX,
+	ATHOS_LUT_CHAN_648500_IDX,
+	ATHOS_LUT_CHAN_648625_IDX,
+	ATHOS_LUT_CHAN_648750_IDX,
+	ATHOS_LUT_CHAN_648875_IDX,
+	ATHOS_LUT_CHAN_649000_IDX,
+	ATHOS_LUT_CHAN_649125_IDX,
+	ATHOS_LUT_CHAN_649250_IDX,
+	ATHOS_LUT_CHAN_649375_IDX,
+	ATHOS_LUT_CHAN_649500_IDX,
+	ATHOS_LUT_CHAN_649625_IDX,
+	ATHOS_LUT_CHAN_649750_IDX,
+	ATHOS_LUT_CHAN_649875_IDX,
+	ATHOS_LUT_CHAN_650000_IDX,
+	ATHOS_LUT_CHAN_650125_IDX,
+	ATHOS_LUT_CHAN_650250_IDX,
+	ATHOS_LUT_CHAN_650375_IDX,
+	ATHOS_LUT_CHAN_650500_IDX,
+	ATHOS_LUT_CHAN_650625_IDX,
+	ATHOS_LUT_CHAN_650750_IDX,
+	ATHOS_LUT_CHAN_650875_IDX,
+	ATHOS_LUT_CHAN_651000_IDX,
+	ATHOS_LUT_CHAN_651125_IDX,
+	ATHOS_LUT_CHAN_651250_IDX,
+	ATHOS_LUT_CHAN_651375_IDX,
+	ATHOS_LUT_CHAN_651500_IDX,
+	ATHOS_LUT_CHAN_651625_IDX,
+	ATHOS_LUT_CHAN_651750_IDX,
+	ATHOS_LUT_CHAN_651875_IDX,
+	ATHOS_LUT_CHAN_652000_IDX,
+	ATHOS_LUT_CHAN_652125_IDX,
+	ATHOS_LUT_CHAN_652250_IDX,
+	ATHOS_LUT_CHAN_652375_IDX,
+	ATHOS_LUT_CHAN_652500_IDX,
+	ATHOS_LUT_CHAN_652625_IDX,
+	ATHOS_LUT_CHAN_652750_IDX,
+	ATHOS_LUT_CHAN_652875_IDX,
+	ATHOS_LUT_CHAN_653000_IDX,
+	ATHOS_LUT_CHAN_653125_IDX,
+	ATHOS_LUT_CHAN_653250_IDX,
+	ATHOS_LUT_CHAN_653375_IDX,
+	ATHOS_LUT_CHAN_653500_IDX,
+	ATHOS_LUT_CHAN_653625_IDX,
+	ATHOS_LUT_CHAN_653750_IDX,
+	ATHOS_LUT_CHAN_653875_IDX,
+	ATHOS_LUT_CHAN_654000_IDX,
+	ATHOS_LUT_CHAN_654125_IDX,
+	ATHOS_LUT_CHAN_654250_IDX,
+	ATHOS_LUT_CHAN_654375_IDX,
+	ATHOS_LUT_CHAN_654500_IDX,
+	ATHOS_LUT_CHAN_654625_IDX,
+	ATHOS_LUT_CHAN_654750_IDX,
+	ATHOS_LUT_CHAN_654875_IDX,
+	ATHOS_LUT_CHAN_655000_IDX,
+	ATHOS_LUT_CHAN_655125_IDX,
+	ATHOS_LUT_CHAN_655250_IDX,
+	ATHOS_LUT_CHAN_655375_IDX,
+	ATHOS_LUT_CHAN_655500_IDX,
+	ATHOS_LUT_CHAN_655625_IDX,
+	ATHOS_LUT_CHAN_655750_IDX,
+	ATHOS_LUT_CHAN_655875_IDX,
+	ATHOS_LUT_CHAN_656000_IDX,
+	ATHOS_LUT_CHAN_656125_IDX,
+	ATHOS_LUT_CHAN_656250_IDX,
+	ATHOS_LUT_CHAN_656375_IDX,
+	ATHOS_LUT_CHAN_656500_IDX,
+	ATHOS_LUT_CHAN_656625_IDX,
+	ATHOS_LUT_CHAN_656750_IDX,
+	ATHOS_LUT_CHAN_656875_IDX,
+	ATHOS_LUT_CHAN_657000_IDX,
+	ATHOS_LUT_CHAN_657125_IDX,
+	ATHOS_LUT_CHAN_657250_IDX,
+	ATHOS_LUT_CHAN_657375_IDX,
+	ATHOS_LUT_CHAN_657500_IDX,
+	ATHOS_LUT_CHAN_657625_IDX,
+	ATHOS_LUT_CHAN_657750_IDX,
+	ATHOS_LUT_CHAN_657875_IDX,
+	ATHOS_LUT_CHAN_658000_IDX,
+	ATHOS_LUT_CHAN_658125_IDX,
+	ATHOS_LUT_CHAN_658250_IDX,
+	ATHOS_LUT_CHAN_658375_IDX,
+	ATHOS_LUT_CHAN_658500_IDX,
+	ATHOS_LUT_CHAN_658625_IDX,
+	ATHOS_LUT_CHAN_658750_IDX,
+	ATHOS_LUT_CHAN_658875_IDX,
+	ATHOS_LUT_CHAN_659000_IDX,
+	ATHOS_LUT_CHAN_659125_IDX,
+	ATHOS_LUT_CHAN_659250_IDX,
+	ATHOS_LUT_CHAN_659375_IDX,
+	ATHOS_LUT_CHAN_659500_IDX,
+	ATHOS_LUT_CHAN_659625_IDX,
+	ATHOS_LUT_CHAN_659750_IDX,
+	ATHOS_LUT_CHAN_659875_IDX,
+	ATHOS_LUT_CHAN_660000_IDX,
+	ATHOS_LUT_CHAN_660125_IDX,
+	ATHOS_LUT_CHAN_660250_IDX,
+	ATHOS_LUT_CHAN_660375_IDX,
+	ATHOS_LUT_CHAN_660500_IDX,
+	ATHOS_LUT_CHAN_660625_IDX,
+	ATHOS_LUT_CHAN_660750_IDX,
+	ATHOS_LUT_CHAN_660875_IDX,
+	ATHOS_LUT_CHAN_661000_IDX,
+	ATHOS_LUT_CHAN_661125_IDX,
+	ATHOS_LUT_CHAN_661250_IDX,
+	ATHOS_LUT_CHAN_661375_IDX,
+	ATHOS_LUT_CHAN_661500_IDX,
+	ATHOS_LUT_CHAN_661625_IDX,
+	ATHOS_LUT_CHAN_661750_IDX,
+	ATHOS_LUT_CHAN_661875_IDX,
+	ATHOS_LUT_CHAN_662000_IDX,
+	ATHOS_LUT_CHAN_662125_IDX,
+	ATHOS_LUT_CHAN_662250_IDX,
+	ATHOS_LUT_CHAN_662375_IDX,
+	ATHOS_LUT_CHAN_662500_IDX,
+	ATHOS_LUT_CHAN_662625_IDX,
+	ATHOS_LUT_CHAN_662750_IDX,
+	ATHOS_LUT_CHAN_662875_IDX,
+	ATHOS_LUT_CHAN_663000_IDX,
+	ATHOS_LUT_CHAN_663125_IDX,
+	ATHOS_LUT_CHAN_663250_IDX,
+	ATHOS_LUT_CHAN_663375_IDX,
+	ATHOS_LUT_CHAN_663500_IDX,
+	ATHOS_LUT_CHAN_663625_IDX,
+	ATHOS_LUT_CHAN_663750_IDX,
+	ATHOS_LUT_CHAN_663875_IDX,
+	ATHOS_LUT_CHAN_664000_IDX,
+	ATHOS_LUT_CHAN_664125_IDX,
+	ATHOS_LUT_CHAN_664250_IDX,
+	ATHOS_LUT_CHAN_664375_IDX,
+	ATHOS_LUT_CHAN_664500_IDX,
+	ATHOS_LUT_CHAN_664625_IDX,
+	ATHOS_LUT_CHAN_664750_IDX,
+	ATHOS_LUT_CHAN_664875_IDX,
+	ATHOS_LUT_CHAN_665000_IDX,
+	ATHOS_LUT_CHAN_665125_IDX,
+	ATHOS_LUT_CHAN_665250_IDX,
+	ATHOS_LUT_CHAN_665375_IDX,
+	ATHOS_LUT_CHAN_665500_IDX,
+	ATHOS_LUT_CHAN_665625_IDX,
+	ATHOS_LUT_CHAN_665750_IDX,
+	ATHOS_LUT_CHAN_665875_IDX,
+	ATHOS_LUT_CHAN_666000_IDX,
+	ATHOS_LUT_CHAN_666125_IDX,
+	ATHOS_LUT_CHAN_666250_IDX,
+	ATHOS_LUT_CHAN_666375_IDX,
+	ATHOS_LUT_CHAN_666500_IDX,
+	ATHOS_LUT_CHAN_666625_IDX,
+	ATHOS_LUT_CHAN_666750_IDX,
+	ATHOS_LUT_CHAN_666875_IDX,
+	ATHOS_LUT_CHAN_667000_IDX,
+	ATHOS_LUT_CHAN_667125_IDX,
+	ATHOS_LUT_CHAN_667250_IDX,
+	ATHOS_LUT_CHAN_667375_IDX,
+	ATHOS_LUT_CHAN_667500_IDX,
+	ATHOS_LUT_CHAN_667625_IDX,
+	ATHOS_LUT_CHAN_667750_IDX,
+	ATHOS_LUT_CHAN_667875_IDX,
+	ATHOS_LUT_CHAN_668000_IDX,
+	ATHOS_LUT_CHAN_668125_IDX,
+	ATHOS_LUT_CHAN_668250_IDX,
+	ATHOS_LUT_CHAN_668375_IDX,
+	ATHOS_LUT_CHAN_668500_IDX,
+	ATHOS_LUT_CHAN_668625_IDX,
+	ATHOS_LUT_CHAN_668750_IDX,
+	ATHOS_LUT_CHAN_668875_IDX,
+	ATHOS_LUT_CHAN_669000_IDX,
+	ATHOS_LUT_CHAN_669125_IDX,
+	ATHOS_LUT_CHAN_669250_IDX,
+	ATHOS_LUT_CHAN_669375_IDX,
+	ATHOS_LUT_CHAN_669500_IDX,
+	ATHOS_LUT_CHAN_669625_IDX,
+	ATHOS_LUT_CHAN_669750_IDX,
+	ATHOS_LUT_CHAN_669875_IDX,
+	ATHOS_LUT_CHAN_670000_IDX,
+	ATHOS_LUT_CHAN_670125_IDX,
+	ATHOS_LUT_CHAN_670250_IDX,
+	ATHOS_LUT_CHAN_670375_IDX,
+	ATHOS_LUT_CHAN_670500_IDX,
+	ATHOS_LUT_CHAN_670625_IDX,
+	ATHOS_LUT_CHAN_670750_IDX,
+	ATHOS_LUT_CHAN_670875_IDX,
+	ATHOS_LUT_CHAN_671000_IDX,
+	ATHOS_LUT_CHAN_671125_IDX,
+	ATHOS_LUT_CHAN_671250_IDX,
+	ATHOS_LUT_CHAN_671375_IDX,
+	ATHOS_LUT_CHAN_671500_IDX,
+	ATHOS_LUT_CHAN_671625_IDX,
+	ATHOS_LUT_CHAN_671750_IDX,
+	ATHOS_LUT_CHAN_671875_IDX,
+	ATHOS_LUT_CHAN_672000_IDX,
+	ATHOS_LUT_CHAN_672125_IDX,
+	ATHOS_LUT_CHAN_672250_IDX,
+	ATHOS_LUT_CHAN_672375_IDX,
+	ATHOS_LUT_CHAN_672500_IDX,
+	ATHOS_LUT_CHAN_672625_IDX,
+	ATHOS_LUT_CHAN_672750_IDX,
+	ATHOS_LUT_CHAN_672875_IDX,
+	ATHOS_LUT_CHAN_673000_IDX,
+	ATHOS_LUT_CHAN_673125_IDX,
+	ATHOS_LUT_CHAN_673250_IDX,
+	ATHOS_LUT_CHAN_673375_IDX,
+	ATHOS_LUT_CHAN_673500_IDX,
+	ATHOS_LUT_CHAN_673625_IDX,
+	ATHOS_LUT_CHAN_673750_IDX,
+	ATHOS_LUT_CHAN_673875_IDX,
+	ATHOS_LUT_CHAN_674000_IDX,
+	ATHOS_LUT_CHAN_674125_IDX,
+	ATHOS_LUT_CHAN_674250_IDX,
+	ATHOS_LUT_CHAN_674375_IDX,
+	ATHOS_LUT_CHAN_674500_IDX,
+	ATHOS_LUT_CHAN_674625_IDX,
+	ATHOS_LUT_CHAN_674750_IDX,
+	ATHOS_LUT_CHAN_674875_IDX,
+	ATHOS_LUT_CHAN_675000_IDX,
+	ATHOS_LUT_CHAN_675125_IDX,
+	ATHOS_LUT_CHAN_675250_IDX,
+	ATHOS_LUT_CHAN_675375_IDX,
+	ATHOS_LUT_CHAN_675500_IDX,
+	ATHOS_LUT_CHAN_675625_IDX,
+	ATHOS_LUT_CHAN_675750_IDX,
+	ATHOS_LUT_CHAN_675875_IDX,
+	ATHOS_LUT_CHAN_676000_IDX,
+	ATHOS_LUT_CHAN_676125_IDX,
+	ATHOS_LUT_CHAN_676250_IDX,
+	ATHOS_LUT_CHAN_676375_IDX,
+	ATHOS_LUT_CHAN_676500_IDX,
+	ATHOS_LUT_CHAN_676625_IDX,
+	ATHOS_LUT_CHAN_676750_IDX,
+	ATHOS_LUT_CHAN_676875_IDX,
+	ATHOS_LUT_CHAN_677000_IDX,
+	ATHOS_LUT_CHAN_677125_IDX,
+	ATHOS_LUT_CHAN_677250_IDX,
+	ATHOS_LUT_CHAN_677375_IDX,
+	ATHOS_LUT_CHAN_677500_IDX,
+	ATHOS_LUT_CHAN_677625_IDX,
+	ATHOS_LUT_CHAN_677750_IDX,
+	ATHOS_LUT_CHAN_677875_IDX,
+	ATHOS_LUT_CHAN_678000_IDX,
+	ATHOS_LUT_CHAN_678125_IDX,
+	ATHOS_LUT_CHAN_678250_IDX,
+	ATHOS_LUT_CHAN_678375_IDX,
+	ATHOS_LUT_CHAN_678500_IDX,
+	ATHOS_LUT_CHAN_678625_IDX,
+	ATHOS_LUT_CHAN_678750_IDX,
+	ATHOS_LUT_CHAN_678875_IDX,
+	ATHOS_LUT_CHAN_679000_IDX,
+	ATHOS_LUT_CHAN_679125_IDX,
+	ATHOS_LUT_CHAN_679250_IDX,
+	ATHOS_LUT_CHAN_679375_IDX,
+	ATHOS_LUT_CHAN_679500_IDX,
+	ATHOS_LUT_CHAN_679625_IDX,
+	ATHOS_LUT_CHAN_679750_IDX,
+	ATHOS_LUT_CHAN_679875_IDX,
+	ATHOS_LUT_CHAN_680000_IDX,
+	ATHOS_LUT_CHAN_680125_IDX,
+	ATHOS_LUT_CHAN_680250_IDX,
+	ATHOS_LUT_CHAN_680375_IDX,
+	ATHOS_LUT_CHAN_680500_IDX,
+	ATHOS_LUT_CHAN_680625_IDX,
+	ATHOS_LUT_CHAN_680750_IDX,
+	ATHOS_LUT_CHAN_680875_IDX,
+	ATHOS_LUT_CHAN_681000_IDX,
+	ATHOS_LUT_CHAN_681125_IDX,
+	ATHOS_LUT_CHAN_681250_IDX,
+	ATHOS_LUT_CHAN_681375_IDX,
+	ATHOS_LUT_CHAN_681500_IDX,
+	ATHOS_LUT_CHAN_681625_IDX,
+	ATHOS_LUT_CHAN_681750_IDX,
+	ATHOS_LUT_CHAN_681875_IDX,
+	ATHOS_LUT_CHAN_682000_IDX,
+	ATHOS_LUT_CHAN_682125_IDX,
+	ATHOS_LUT_CHAN_682250_IDX,
+	ATHOS_LUT_CHAN_682375_IDX,
+	ATHOS_LUT_CHAN_682500_IDX,
+	ATHOS_LUT_CHAN_682625_IDX,
+	ATHOS_LUT_CHAN_682750_IDX,
+	ATHOS_LUT_CHAN_682875_IDX,
+	ATHOS_LUT_CHAN_683000_IDX,
+	ATHOS_LUT_CHAN_683125_IDX,
+	ATHOS_LUT_CHAN_683250_IDX,
+	ATHOS_LUT_CHAN_683375_IDX,
+	ATHOS_LUT_CHAN_683500_IDX,
+	ATHOS_LUT_CHAN_683625_IDX,
+	ATHOS_LUT_CHAN_683750_IDX,
+	ATHOS_LUT_CHAN_683875_IDX,
+	ATHOS_LUT_CHAN_684000_IDX,
+	ATHOS_LUT_CHAN_684125_IDX,
+	ATHOS_LUT_CHAN_684250_IDX,
+	ATHOS_LUT_CHAN_684375_IDX,
+	ATHOS_LUT_CHAN_684500_IDX,
+	ATHOS_LUT_CHAN_684625_IDX,
+	ATHOS_LUT_CHAN_684750_IDX,
+	ATHOS_LUT_CHAN_684875_IDX,
+	ATHOS_LUT_CHAN_685000_IDX,
+	ATHOS_LUT_CHAN_685125_IDX,
+	ATHOS_LUT_CHAN_685250_IDX,
+	ATHOS_LUT_CHAN_685375_IDX,
+	ATHOS_LUT_CHAN_685500_IDX,
+	ATHOS_LUT_CHAN_685625_IDX,
+	ATHOS_LUT_CHAN_685750_IDX,
+	ATHOS_LUT_CHAN_685875_IDX,
+	ATHOS_LUT_CHAN_686000_IDX,
+	ATHOS_LUT_CHAN_686125_IDX,
+	ATHOS_LUT_CHAN_686250_IDX,
+	ATHOS_LUT_CHAN_686375_IDX,
+	ATHOS_LUT_CHAN_686500_IDX,
+	ATHOS_LUT_CHAN_686625_IDX,
+	ATHOS_LUT_CHAN_686750_IDX,
+	ATHOS_LUT_CHAN_686875_IDX,
+	ATHOS_LUT_CHAN_687000_IDX,
+	ATHOS_LUT_CHAN_687125_IDX,
+	ATHOS_LUT_CHAN_687250_IDX,
+	ATHOS_LUT_CHAN_687375_IDX,
+	ATHOS_LUT_CHAN_687500_IDX,
+	ATHOS_LUT_CHAN_687625_IDX,
+	ATHOS_LUT_CHAN_687750_IDX,
+	ATHOS_LUT_CHAN_687875_IDX,
+	ATHOS_LUT_CHAN_688000_IDX,
+	ATHOS_LUT_CHAN_688125_IDX,
+	ATHOS_LUT_CHAN_688250_IDX,
+	ATHOS_LUT_CHAN_688375_IDX,
+	ATHOS_LUT_CHAN_688500_IDX,
+	ATHOS_LUT_CHAN_688625_IDX,
+	ATHOS_LUT_CHAN_688750_IDX,
+	ATHOS_LUT_CHAN_688875_IDX,
+	ATHOS_LUT_CHAN_689000_IDX,
+	ATHOS_LUT_CHAN_689125_IDX,
+	ATHOS_LUT_CHAN_689250_IDX,
+	ATHOS_LUT_CHAN_689375_IDX,
+	ATHOS_LUT_CHAN_689500_IDX,
+	ATHOS_LUT_CHAN_689625_IDX,
+	ATHOS_LUT_CHAN_689750_IDX,
+	ATHOS_LUT_CHAN_689875_IDX,
+	ATHOS_LUT_CHAN_690000_IDX,
+	ATHOS_LUT_CHAN_690125_IDX,
+	ATHOS_LUT_CHAN_690250_IDX,
+	ATHOS_LUT_CHAN_690375_IDX,
+	ATHOS_LUT_CHAN_690500_IDX,
+	ATHOS_LUT_CHAN_690625_IDX,
+	ATHOS_LUT_CHAN_690750_IDX,
+	ATHOS_LUT_CHAN_690875_IDX,
+	ATHOS_LUT_CHAN_691000_IDX,
+	ATHOS_LUT_CHAN_691125_IDX,
+	ATHOS_LUT_CHAN_691250_IDX,
+	ATHOS_LUT_CHAN_691375_IDX,
+	ATHOS_LUT_CHAN_691500_IDX,
+	ATHOS_LUT_CHAN_691625_IDX,
+	ATHOS_LUT_CHAN_691750_IDX,
+	ATHOS_LUT_CHAN_691875_IDX,
+	ATHOS_LUT_CHAN_692000_IDX,
+	ATHOS_LUT_CHAN_692125_IDX,
+	ATHOS_LUT_CHAN_692250_IDX,
+	ATHOS_LUT_CHAN_692375_IDX,
+	ATHOS_LUT_CHAN_692500_IDX,
+	ATHOS_LUT_CHAN_692625_IDX,
+	ATHOS_LUT_CHAN_692750_IDX,
+	ATHOS_LUT_CHAN_692875_IDX,
+	ATHOS_LUT_CHAN_693000_IDX,
+	ATHOS_LUT_CHAN_693125_IDX,
+	ATHOS_LUT_CHAN_693250_IDX,
+	ATHOS_LUT_CHAN_693375_IDX,
+	ATHOS_LUT_CHAN_693500_IDX,
+	ATHOS_LUT_CHAN_693625_IDX,
+	ATHOS_LUT_CHAN_693750_IDX,
+	ATHOS_LUT_CHAN_693875_IDX,
+	ATHOS_LUT_CHAN_694000_IDX,
+	ATHOS_LUT_CHAN_694125_IDX,
+	ATHOS_LUT_CHAN_694250_IDX,
+	ATHOS_LUT_CHAN_694375_IDX,
+	ATHOS_LUT_CHAN_694500_IDX,
+	ATHOS_LUT_CHAN_694625_IDX,
+	ATHOS_LUT_CHAN_694750_IDX,
+	ATHOS_LUT_CHAN_694875_IDX,
+	ATHOS_LUT_CHAN_695000_IDX,
+	ATHOS_LUT_CHAN_695125_IDX,
+	ATHOS_LUT_CHAN_695250_IDX,
+	ATHOS_LUT_CHAN_695375_IDX,
+	ATHOS_LUT_CHAN_695500_IDX,
+	ATHOS_LUT_CHAN_695625_IDX,
+	ATHOS_LUT_CHAN_695750_IDX,
+	ATHOS_LUT_CHAN_695875_IDX,
+	ATHOS_LUT_CHAN_696000_IDX,
+	ATHOS_LUT_CHAN_696125_IDX,
+	ATHOS_LUT_CHAN_696250_IDX,
+	ATHOS_LUT_CHAN_696375_IDX,
+	ATHOS_LUT_CHAN_696500_IDX,
+	ATHOS_LUT_CHAN_696625_IDX,
+	ATHOS_LUT_CHAN_696750_IDX,
+	ATHOS_LUT_CHAN_696875_IDX,
+	ATHOS_LUT_CHAN_697000_IDX,
+	ATHOS_LUT_CHAN_697125_IDX,
+	ATHOS_LUT_CHAN_697250_IDX,
+	ATHOS_LUT_CHAN_697375_IDX,
+	ATHOS_LUT_CHAN_697500_IDX,
+	ATHOS_LUT_CHAN_697625_IDX,
+	ATHOS_LUT_CHAN_697750_IDX,
+	ATHOS_LUT_CHAN_697875_IDX,
+	ATHOS_LUT_CHAN_698000_IDX,
+	ATHOS_LUT_CHAN_698125_IDX,
+	ATHOS_LUT_CHAN_698250_IDX,
+	ATHOS_LUT_CHAN_698375_IDX,
+	ATHOS_LUT_CHAN_698500_IDX,
+	ATHOS_LUT_CHAN_698625_IDX,
+	ATHOS_LUT_CHAN_698750_IDX,
+	ATHOS_LUT_CHAN_698875_IDX,
+	ATHOS_LUT_CHAN_699000_IDX,
+	ATHOS_LUT_CHAN_699125_IDX,
+	ATHOS_LUT_CHAN_699250_IDX,
+	ATHOS_LUT_CHAN_699375_IDX,
+	ATHOS_LUT_CHAN_699500_IDX,
+	ATHOS_LUT_CHAN_699625_IDX,
+	ATHOS_LUT_CHAN_699750_IDX,
+	ATHOS_LUT_CHAN_699875_IDX,
+	ATHOS_LUT_CHAN_700000_IDX,
+	ATHOS_LUT_CHAN_700125_IDX,
+	ATHOS_LUT_CHAN_700250_IDX,
+	ATHOS_LUT_CHAN_700375_IDX,
+	ATHOS_LUT_CHAN_700500_IDX,
+	ATHOS_LUT_CHAN_700625_IDX,
+	ATHOS_LUT_CHAN_700750_IDX,
+	ATHOS_LUT_CHAN_700875_IDX,
+	ATHOS_LUT_CHAN_701000_IDX,
+	ATHOS_LUT_CHAN_701125_IDX,
+	ATHOS_LUT_CHAN_701250_IDX,
+	ATHOS_LUT_CHAN_701375_IDX,
+	ATHOS_LUT_CHAN_701500_IDX,
+	ATHOS_LUT_CHAN_701625_IDX,
+	ATHOS_LUT_CHAN_701750_IDX,
+	ATHOS_LUT_CHAN_701875_IDX,
+	ATHOS_LUT_CHAN_702000_IDX,
+	ATHOS_LUT_CHAN_702125_IDX,
+	ATHOS_LUT_CHAN_702250_IDX,
+	ATHOS_LUT_CHAN_702375_IDX,
+	ATHOS_LUT_CHAN_702500_IDX,
+	ATHOS_LUT_CHAN_702625_IDX,
+	ATHOS_LUT_CHAN_702750_IDX,
+	ATHOS_LUT_CHAN_702875_IDX,
+	ATHOS_LUT_CHAN_703000_IDX,
+	ATHOS_LUT_CHAN_703125_IDX,
+	ATHOS_LUT_CHAN_703250_IDX,
+	ATHOS_LUT_CHAN_703375_IDX,
+	ATHOS_LUT_CHAN_703500_IDX,
+	ATHOS_LUT_CHAN_703625_IDX,
+	ATHOS_LUT_CHAN_703750_IDX,
+	ATHOS_LUT_CHAN_703875_IDX,
+	ATHOS_LUT_CHAN_704000_IDX,
+	ATHOS_LUT_CHAN_704125_IDX,
+	ATHOS_LUT_CHAN_704250_IDX,
+	ATHOS_LUT_CHAN_704375_IDX,
+	ATHOS_LUT_CHAN_704500_IDX,
+	ATHOS_LUT_CHAN_704625_IDX,
+	ATHOS_LUT_CHAN_704750_IDX,
+	ATHOS_LUT_CHAN_704875_IDX,
+	ATHOS_LUT_CHAN_705000_IDX,
+	ATHOS_LUT_CHAN_705125_IDX,
+	ATHOS_LUT_CHAN_705250_IDX,
+	ATHOS_LUT_CHAN_705375_IDX,
+	ATHOS_LUT_CHAN_705500_IDX,
+	ATHOS_LUT_CHAN_705625_IDX,
+	ATHOS_LUT_CHAN_705750_IDX,
+	ATHOS_LUT_CHAN_705875_IDX,
+	ATHOS_LUT_CHAN_706000_IDX,
+	ATHOS_LUT_CHAN_706125_IDX,
+	ATHOS_LUT_CHAN_706250_IDX,
+	ATHOS_LUT_CHAN_706375_IDX,
+	ATHOS_LUT_CHAN_706500_IDX,
+	ATHOS_LUT_CHAN_706625_IDX,
+	ATHOS_LUT_CHAN_706750_IDX,
+	ATHOS_LUT_CHAN_706875_IDX,
+	ATHOS_LUT_CHAN_707000_IDX,
+	ATHOS_LUT_CHAN_707125_IDX,
+	ATHOS_LUT_CHAN_707250_IDX,
+	ATHOS_LUT_CHAN_707375_IDX,
+	ATHOS_LUT_CHAN_707500_IDX,
+	ATHOS_LUT_CHAN_707625_IDX,
+	ATHOS_LUT_CHAN_707750_IDX,
+	ATHOS_LUT_CHAN_707875_IDX,
+	ATHOS_LUT_CHAN_708000_IDX,
+	ATHOS_LUT_CHAN_708125_IDX,
+	ATHOS_LUT_CHAN_708250_IDX,
+	ATHOS_LUT_CHAN_708375_IDX,
+	ATHOS_LUT_CHAN_708500_IDX,
+	ATHOS_LUT_CHAN_708625_IDX,
+	ATHOS_LUT_CHAN_708750_IDX,
+	ATHOS_LUT_CHAN_708875_IDX,
+	ATHOS_LUT_CHAN_709000_IDX,
+	ATHOS_LUT_CHAN_709125_IDX,
+	ATHOS_LUT_CHAN_709250_IDX,
+	ATHOS_LUT_CHAN_709375_IDX,
+	ATHOS_LUT_CHAN_709500_IDX,
+	ATHOS_LUT_CHAN_709625_IDX,
+	ATHOS_LUT_CHAN_709750_IDX,
+	ATHOS_LUT_CHAN_709875_IDX,
+	ATHOS_LUT_CHAN_710000_IDX,
+	ATHOS_LUT_CHAN_710125_IDX,
+	ATHOS_LUT_CHAN_710250_IDX,
+	ATHOS_LUT_CHAN_710375_IDX,
+	ATHOS_LUT_CHAN_710500_IDX,
+	ATHOS_LUT_CHAN_710625_IDX,
+	ATHOS_LUT_CHAN_710750_IDX,
+	ATHOS_LUT_CHAN_710875_IDX,
+	ATHOS_LUT_CHAN_711000_IDX,
+	ATHOS_LUT_CHAN_711125_IDX,
+	ATHOS_LUT_CHAN_711250_IDX,
+	ATHOS_LUT_CHAN_711375_IDX,
+	ATHOS_LUT_CHAN_711500_IDX,
+	ATHOS_LUT_CHAN_711625_IDX,
+	ATHOS_LUT_CHAN_711750_IDX,
+	ATHOS_LUT_CHAN_711875_IDX,
+	ATHOS_LUT_CHAN_712000_IDX,
+	ATHOS_LUT_CHAN_712125_IDX,
+	ATHOS_LUT_CHAN_712250_IDX,
+	ATHOS_LUT_CHAN_712375_IDX,
+	ATHOS_LUT_CHAN_712500_IDX,
+	ATHOS_LUT_CHAN_712625_IDX,
+	ATHOS_LUT_CHAN_712750_IDX,
+	ATHOS_LUT_CHAN_712875_IDX,
+	ATHOS_LUT_CHAN_713000_IDX,
+	ATHOS_LUT_CHAN_713125_IDX,
+	ATHOS_LUT_CHAN_713250_IDX,
+	ATHOS_LUT_CHAN_713375_IDX,
+	ATHOS_LUT_CHAN_713500_IDX,
+	ATHOS_LUT_CHAN_713625_IDX,
+	ATHOS_LUT_CHAN_713750_IDX,
+	ATHOS_LUT_CHAN_713875_IDX,
+	ATHOS_LUT_CHAN_714000_IDX,
+	ATHOS_LUT_CHAN_714125_IDX,
+	ATHOS_LUT_CHAN_714250_IDX,
+	ATHOS_LUT_CHAN_714375_IDX,
+	ATHOS_LUT_CHAN_714500_IDX,
+	ATHOS_LUT_CHAN_714625_IDX,
+	ATHOS_LUT_CHAN_714750_IDX,
+	ATHOS_LUT_CHAN_714875_IDX,
+	ATHOS_LUT_CHAN_715000_IDX,
+	ATHOS_LUT_CHAN_715125_IDX,
+	ATHOS_LUT_CHAN_715250_IDX,
+	ATHOS_LUT_CHAN_715375_IDX,
+	ATHOS_LUT_CHAN_715500_IDX,
+	ATHOS_LUT_CHAN_715625_IDX,
+	ATHOS_LUT_CHAN_715750_IDX,
+	ATHOS_LUT_CHAN_715875_IDX,
+	ATHOS_LUT_CHAN_716000_IDX,
+	ATHOS_LUT_CHAN_716125_IDX,
+	ATHOS_LUT_CHAN_716250_IDX,
+	ATHOS_LUT_CHAN_716375_IDX,
+	ATHOS_LUT_CHAN_716500_IDX,
+	ATHOS_LUT_CHAN_716625_IDX,
+	ATHOS_LUT_CHAN_716750_IDX,
+	ATHOS_LUT_CHAN_716875_IDX,
+	ATHOS_LUT_CHAN_717000_IDX,
+	ATHOS_LUT_CHAN_717125_IDX,
+	ATHOS_LUT_CHAN_717250_IDX,
+	ATHOS_LUT_CHAN_717375_IDX,
+	ATHOS_LUT_CHAN_717500_IDX,
+	ATHOS_LUT_CHAN_717625_IDX,
+	ATHOS_LUT_CHAN_717750_IDX,
+	ATHOS_LUT_CHAN_717875_IDX,
+	ATHOS_LUT_CHAN_718000_IDX,
+	ATHOS_LUT_CHAN_718125_IDX,
+	ATHOS_LUT_CHAN_718250_IDX,
+	ATHOS_LUT_CHAN_718375_IDX,
+	ATHOS_LUT_CHAN_718500_IDX,
+	ATHOS_LUT_CHAN_718625_IDX,
+	ATHOS_LUT_CHAN_718750_IDX,
+	ATHOS_LUT_CHAN_718875_IDX,
+	ATHOS_LUT_CHAN_719000_IDX,
+	ATHOS_LUT_CHAN_719125_IDX,
+	ATHOS_LUT_CHAN_719250_IDX,
+	ATHOS_LUT_CHAN_719375_IDX,
+	ATHOS_LUT_CHAN_719500_IDX,
+	ATHOS_LUT_CHAN_719625_IDX,
+	ATHOS_LUT_CHAN_719750_IDX,
+	ATHOS_LUT_CHAN_719875_IDX,
+	ATHOS_LUT_CHAN_720000_IDX,
+	ATHOS_LUT_CHAN_720125_IDX,
+	ATHOS_LUT_CHAN_720250_IDX,
+	ATHOS_LUT_CHAN_720375_IDX,
+	ATHOS_LUT_CHAN_720500_IDX,
+	ATHOS_LUT_CHAN_720625_IDX,
+	ATHOS_LUT_CHAN_720750_IDX,
+	ATHOS_LUT_CHAN_720875_IDX,
+	ATHOS_LUT_CHAN_721000_IDX,
+	ATHOS_LUT_CHAN_721125_IDX,
+	ATHOS_LUT_CHAN_721250_IDX,
+	ATHOS_LUT_CHAN_721375_IDX,
+	ATHOS_LUT_CHAN_721500_IDX,
+	ATHOS_LUT_CHAN_6G_MAX
+};
+
+enum athos_b_idx_5g {
+	ATHOS_B_5G_LUT_CHAN_516000_IDX,
+	ATHOS_B_5G_LUT_CHAN_516125_IDX,
+	ATHOS_B_5G_LUT_CHAN_516250_IDX,
+	ATHOS_B_5G_LUT_CHAN_516375_IDX,
+	ATHOS_B_5G_LUT_CHAN_516500_IDX,
+	ATHOS_B_5G_LUT_CHAN_516625_IDX,
+	ATHOS_B_5G_LUT_CHAN_516750_IDX,
+	ATHOS_B_5G_LUT_CHAN_516875_IDX,
+	ATHOS_B_5G_LUT_CHAN_517000_IDX,
+	ATHOS_B_5G_LUT_CHAN_517125_IDX,
+	ATHOS_B_5G_LUT_CHAN_517250_IDX,
+	ATHOS_B_5G_LUT_CHAN_517375_IDX,
+	ATHOS_B_5G_LUT_CHAN_517500_IDX,
+	ATHOS_B_5G_LUT_CHAN_517625_IDX,
+	ATHOS_B_5G_LUT_CHAN_517750_IDX,
+	ATHOS_B_5G_LUT_CHAN_517875_IDX,
+	ATHOS_B_5G_LUT_CHAN_518000_IDX,
+	ATHOS_B_5G_LUT_CHAN_518125_IDX,
+	ATHOS_B_5G_LUT_CHAN_518250_IDX,
+	ATHOS_B_5G_LUT_CHAN_518375_IDX,
+	ATHOS_B_5G_LUT_CHAN_518500_IDX,
+	ATHOS_B_5G_LUT_CHAN_518625_IDX,
+	ATHOS_B_5G_LUT_CHAN_518750_IDX,
+	ATHOS_B_5G_LUT_CHAN_518875_IDX,
+	ATHOS_B_5G_LUT_CHAN_519000_IDX,
+	ATHOS_B_5G_LUT_CHAN_519125_IDX,
+	ATHOS_B_5G_LUT_CHAN_519250_IDX,
+	ATHOS_B_5G_LUT_CHAN_519375_IDX,
+	ATHOS_B_5G_LUT_CHAN_519500_IDX,
+	ATHOS_B_5G_LUT_CHAN_519625_IDX,
+	ATHOS_B_5G_LUT_CHAN_519750_IDX,
+	ATHOS_B_5G_LUT_CHAN_519875_IDX,
+	ATHOS_B_5G_LUT_CHAN_520000_IDX,
+	ATHOS_B_5G_LUT_CHAN_520125_IDX,
+	ATHOS_B_5G_LUT_CHAN_520250_IDX,
+	ATHOS_B_5G_LUT_CHAN_520375_IDX,
+	ATHOS_B_5G_LUT_CHAN_520500_IDX,
+	ATHOS_B_5G_LUT_CHAN_520625_IDX,
+	ATHOS_B_5G_LUT_CHAN_520750_IDX,
+	ATHOS_B_5G_LUT_CHAN_520875_IDX,
+	ATHOS_B_5G_LUT_CHAN_521000_IDX,
+	ATHOS_B_5G_LUT_CHAN_521125_IDX,
+	ATHOS_B_5G_LUT_CHAN_521250_IDX,
+	ATHOS_B_5G_LUT_CHAN_521375_IDX,
+	ATHOS_B_5G_LUT_CHAN_521500_IDX,
+	ATHOS_B_5G_LUT_CHAN_521625_IDX,
+	ATHOS_B_5G_LUT_CHAN_521750_IDX,
+	ATHOS_B_5G_LUT_CHAN_521875_IDX,
+	ATHOS_B_5G_LUT_CHAN_522000_IDX,
+	ATHOS_B_5G_LUT_CHAN_522125_IDX,
+	ATHOS_B_5G_LUT_CHAN_522250_IDX,
+	ATHOS_B_5G_LUT_CHAN_522375_IDX,
+	ATHOS_B_5G_LUT_CHAN_522500_IDX,
+	ATHOS_B_5G_LUT_CHAN_522625_IDX,
+	ATHOS_B_5G_LUT_CHAN_522750_IDX,
+	ATHOS_B_5G_LUT_CHAN_522875_IDX,
+	ATHOS_B_5G_LUT_CHAN_523000_IDX,
+	ATHOS_B_5G_LUT_CHAN_523125_IDX,
+	ATHOS_B_5G_LUT_CHAN_523250_IDX,
+	ATHOS_B_5G_LUT_CHAN_523375_IDX,
+	ATHOS_B_5G_LUT_CHAN_523500_IDX,
+	ATHOS_B_5G_LUT_CHAN_523625_IDX,
+	ATHOS_B_5G_LUT_CHAN_523750_IDX,
+	ATHOS_B_5G_LUT_CHAN_523875_IDX,
+	ATHOS_B_5G_LUT_CHAN_524000_IDX,
+	ATHOS_B_5G_LUT_CHAN_524125_IDX,
+	ATHOS_B_5G_LUT_CHAN_524250_IDX,
+	ATHOS_B_5G_LUT_CHAN_524375_IDX,
+	ATHOS_B_5G_LUT_CHAN_524500_IDX,
+	ATHOS_B_5G_LUT_CHAN_524625_IDX,
+	ATHOS_B_5G_LUT_CHAN_524750_IDX,
+	ATHOS_B_5G_LUT_CHAN_524875_IDX,
+	ATHOS_B_5G_LUT_CHAN_525000_IDX,
+	ATHOS_B_5G_LUT_CHAN_525125_IDX,
+	ATHOS_B_5G_LUT_CHAN_525250_IDX,
+	ATHOS_B_5G_LUT_CHAN_525375_IDX,
+	ATHOS_B_5G_LUT_CHAN_525500_IDX,
+	ATHOS_B_5G_LUT_CHAN_525625_IDX,
+	ATHOS_B_5G_LUT_CHAN_525750_IDX,
+	ATHOS_B_5G_LUT_CHAN_525875_IDX,
+	ATHOS_B_5G_LUT_CHAN_526000_IDX,
+	ATHOS_B_5G_LUT_CHAN_526125_IDX,
+	ATHOS_B_5G_LUT_CHAN_526250_IDX,
+	ATHOS_B_5G_LUT_CHAN_526375_IDX,
+	ATHOS_B_5G_LUT_CHAN_526500_IDX,
+	ATHOS_B_5G_LUT_CHAN_526625_IDX,
+	ATHOS_B_5G_LUT_CHAN_526750_IDX,
+	ATHOS_B_5G_LUT_CHAN_526875_IDX,
+	ATHOS_B_5G_LUT_CHAN_527000_IDX,
+	ATHOS_B_5G_LUT_CHAN_527125_IDX,
+	ATHOS_B_5G_LUT_CHAN_527250_IDX,
+	ATHOS_B_5G_LUT_CHAN_527375_IDX,
+	ATHOS_B_5G_LUT_CHAN_527500_IDX,
+	ATHOS_B_5G_LUT_CHAN_527625_IDX,
+	ATHOS_B_5G_LUT_CHAN_527750_IDX,
+	ATHOS_B_5G_LUT_CHAN_527875_IDX,
+	ATHOS_B_5G_LUT_CHAN_528000_IDX,
+	ATHOS_B_5G_LUT_CHAN_528125_IDX,
+	ATHOS_B_5G_LUT_CHAN_528250_IDX,
+	ATHOS_B_5G_LUT_CHAN_528375_IDX,
+	ATHOS_B_5G_LUT_CHAN_528500_IDX,
+	ATHOS_B_5G_LUT_CHAN_528625_IDX,
+	ATHOS_B_5G_LUT_CHAN_528750_IDX,
+	ATHOS_B_5G_LUT_CHAN_528875_IDX,
+	ATHOS_B_5G_LUT_CHAN_529000_IDX,
+	ATHOS_B_5G_LUT_CHAN_529125_IDX,
+	ATHOS_B_5G_LUT_CHAN_529250_IDX,
+	ATHOS_B_5G_LUT_CHAN_529375_IDX,
+	ATHOS_B_5G_LUT_CHAN_529500_IDX,
+	ATHOS_B_5G_LUT_CHAN_529625_IDX,
+	ATHOS_B_5G_LUT_CHAN_529750_IDX,
+	ATHOS_B_5G_LUT_CHAN_529875_IDX,
+	ATHOS_B_5G_LUT_CHAN_530000_IDX,
+	ATHOS_B_5G_LUT_CHAN_530125_IDX,
+	ATHOS_B_5G_LUT_CHAN_530250_IDX,
+	ATHOS_B_5G_LUT_CHAN_530375_IDX,
+	ATHOS_B_5G_LUT_CHAN_530500_IDX,
+	ATHOS_B_5G_LUT_CHAN_530625_IDX,
+	ATHOS_B_5G_LUT_CHAN_530750_IDX,
+	ATHOS_B_5G_LUT_CHAN_530875_IDX,
+	ATHOS_B_5G_LUT_CHAN_531000_IDX,
+	ATHOS_B_5G_LUT_CHAN_531125_IDX,
+	ATHOS_B_5G_LUT_CHAN_531250_IDX,
+	ATHOS_B_5G_LUT_CHAN_531375_IDX,
+	ATHOS_B_5G_LUT_CHAN_531500_IDX,
+	ATHOS_B_5G_LUT_CHAN_531625_IDX,
+	ATHOS_B_5G_LUT_CHAN_531750_IDX,
+	ATHOS_B_5G_LUT_CHAN_531875_IDX,
+	ATHOS_B_5G_LUT_CHAN_532000_IDX,
+	ATHOS_B_5G_LUT_CHAN_532125_IDX,
+	ATHOS_B_5G_LUT_CHAN_532250_IDX,
+	ATHOS_B_5G_LUT_CHAN_532375_IDX,
+	ATHOS_B_5G_LUT_CHAN_532500_IDX,
+	ATHOS_B_5G_LUT_CHAN_532625_IDX,
+	ATHOS_B_5G_LUT_CHAN_532750_IDX,
+	ATHOS_B_5G_LUT_CHAN_532875_IDX,
+	ATHOS_B_5G_LUT_CHAN_533000_IDX,
+	ATHOS_B_5G_LUT_CHAN_533125_IDX,
+	ATHOS_B_5G_LUT_CHAN_533250_IDX,
+	ATHOS_B_5G_LUT_CHAN_533375_IDX,
+	ATHOS_B_5G_LUT_CHAN_533500_IDX,
+	ATHOS_B_5G_LUT_CHAN_533625_IDX,
+	ATHOS_B_5G_LUT_CHAN_533750_IDX,
+	ATHOS_B_5G_LUT_CHAN_533875_IDX,
+	ATHOS_B_5G_LUT_CHAN_534000_IDX,
+	ATHOS_B_5G_LUT_CHAN_534125_IDX,
+	ATHOS_B_5G_LUT_CHAN_534250_IDX,
+	ATHOS_B_5G_LUT_CHAN_534375_IDX,
+	ATHOS_B_5G_LUT_CHAN_534500_IDX,
+	ATHOS_B_5G_LUT_CHAN_534625_IDX,
+	ATHOS_B_5G_LUT_CHAN_534750_IDX,
+	ATHOS_B_5G_LUT_CHAN_534875_IDX,
+	ATHOS_B_5G_LUT_CHAN_535000_IDX,
+	ATHOS_B_5G_LUT_CHAN_535125_IDX,
+	ATHOS_B_5G_LUT_CHAN_535250_IDX,
+	ATHOS_B_5G_LUT_CHAN_535375_IDX,
+	ATHOS_B_5G_LUT_CHAN_535500_IDX,
+	ATHOS_B_5G_LUT_CHAN_535625_IDX,
+	ATHOS_B_5G_LUT_CHAN_535750_IDX,
+	ATHOS_B_5G_LUT_CHAN_535875_IDX,
+	ATHOS_B_5G_LUT_CHAN_536000_IDX,
+	ATHOS_B_5G_LUT_CHAN_536125_IDX,
+	ATHOS_B_5G_LUT_CHAN_536250_IDX,
+	ATHOS_B_5G_LUT_CHAN_536375_IDX,
+	ATHOS_B_5G_LUT_CHAN_536500_IDX,
+	ATHOS_B_5G_LUT_CHAN_536625_IDX,
+	ATHOS_B_5G_LUT_CHAN_536750_IDX,
+	ATHOS_B_5G_LUT_CHAN_536875_IDX,
+	ATHOS_B_5G_LUT_CHAN_537000_IDX,
+	ATHOS_B_5G_LUT_CHAN_537125_IDX,
+	ATHOS_B_5G_LUT_CHAN_537250_IDX,
+	ATHOS_B_5G_LUT_CHAN_537375_IDX,
+	ATHOS_B_5G_LUT_CHAN_537500_IDX,
+	ATHOS_B_5G_LUT_CHAN_537625_IDX,
+	ATHOS_B_5G_LUT_CHAN_537750_IDX,
+	ATHOS_B_5G_LUT_CHAN_537875_IDX,
+	ATHOS_B_5G_LUT_CHAN_538000_IDX,
+	ATHOS_B_5G_LUT_CHAN_538125_IDX,
+	ATHOS_B_5G_LUT_CHAN_538250_IDX,
+	ATHOS_B_5G_LUT_CHAN_538375_IDX,
+	ATHOS_B_5G_LUT_CHAN_538500_IDX,
+	ATHOS_B_5G_LUT_CHAN_538625_IDX,
+	ATHOS_B_5G_LUT_CHAN_538750_IDX,
+	ATHOS_B_5G_LUT_CHAN_538875_IDX,
+	ATHOS_B_5G_LUT_CHAN_539000_IDX,
+	ATHOS_B_5G_LUT_CHAN_539125_IDX,
+	ATHOS_B_5G_LUT_CHAN_539250_IDX,
+	ATHOS_B_5G_LUT_CHAN_539375_IDX,
+	ATHOS_B_5G_LUT_CHAN_539500_IDX,
+	ATHOS_B_5G_LUT_CHAN_539625_IDX,
+	ATHOS_B_5G_LUT_CHAN_539750_IDX,
+	ATHOS_B_5G_LUT_CHAN_539875_IDX,
+	ATHOS_B_5G_LUT_CHAN_540000_IDX,
+	ATHOS_B_5G_LUT_CHAN_540125_IDX,
+	ATHOS_B_5G_LUT_CHAN_540250_IDX,
+	ATHOS_B_5G_LUT_CHAN_540375_IDX,
+	ATHOS_B_5G_LUT_CHAN_540500_IDX,
+	ATHOS_B_5G_LUT_CHAN_540625_IDX,
+	ATHOS_B_5G_LUT_CHAN_540750_IDX,
+	ATHOS_B_5G_LUT_CHAN_540875_IDX,
+	ATHOS_B_5G_LUT_CHAN_541000_IDX,
+	ATHOS_B_5G_LUT_CHAN_541125_IDX,
+	ATHOS_B_5G_LUT_CHAN_541250_IDX,
+	ATHOS_B_5G_LUT_CHAN_541375_IDX,
+	ATHOS_B_5G_LUT_CHAN_541500_IDX,
+	ATHOS_B_5G_LUT_CHAN_541625_IDX,
+	ATHOS_B_5G_LUT_CHAN_541750_IDX,
+	ATHOS_B_5G_LUT_CHAN_541875_IDX,
+	ATHOS_B_5G_LUT_CHAN_542000_IDX,
+	ATHOS_B_5G_LUT_CHAN_542125_IDX,
+	ATHOS_B_5G_LUT_CHAN_542250_IDX,
+	ATHOS_B_5G_LUT_CHAN_542375_IDX,
+	ATHOS_B_5G_LUT_CHAN_542500_IDX,
+	ATHOS_B_5G_LUT_CHAN_542625_IDX,
+	ATHOS_B_5G_LUT_CHAN_542750_IDX,
+	ATHOS_B_5G_LUT_CHAN_542875_IDX,
+	ATHOS_B_5G_LUT_CHAN_543000_IDX,
+	ATHOS_B_5G_LUT_CHAN_543125_IDX,
+	ATHOS_B_5G_LUT_CHAN_543250_IDX,
+	ATHOS_B_5G_LUT_CHAN_543375_IDX,
+	ATHOS_B_5G_LUT_CHAN_543500_IDX,
+	ATHOS_B_5G_LUT_CHAN_543625_IDX,
+	ATHOS_B_5G_LUT_CHAN_543750_IDX,
+	ATHOS_B_5G_LUT_CHAN_543875_IDX,
+	ATHOS_B_5G_LUT_CHAN_544000_IDX,
+	ATHOS_B_5G_LUT_CHAN_544125_IDX,
+	ATHOS_B_5G_LUT_CHAN_544250_IDX,
+	ATHOS_B_5G_LUT_CHAN_544375_IDX,
+	ATHOS_B_5G_LUT_CHAN_544500_IDX,
+	ATHOS_B_5G_LUT_CHAN_544625_IDX,
+	ATHOS_B_5G_LUT_CHAN_544750_IDX,
+	ATHOS_B_5G_LUT_CHAN_544875_IDX,
+	ATHOS_B_5G_LUT_CHAN_545000_IDX,
+	ATHOS_B_5G_LUT_CHAN_545125_IDX,
+	ATHOS_B_5G_LUT_CHAN_545250_IDX,
+	ATHOS_B_5G_LUT_CHAN_545375_IDX,
+	ATHOS_B_5G_LUT_CHAN_545500_IDX,
+	ATHOS_B_5G_LUT_CHAN_545625_IDX,
+	ATHOS_B_5G_LUT_CHAN_545750_IDX,
+	ATHOS_B_5G_LUT_CHAN_545875_IDX,
+	ATHOS_B_5G_LUT_CHAN_546000_IDX,
+	ATHOS_B_5G_LUT_CHAN_546125_IDX,
+	ATHOS_B_5G_LUT_CHAN_546250_IDX,
+	ATHOS_B_5G_LUT_CHAN_546375_IDX,
+	ATHOS_B_5G_LUT_CHAN_546500_IDX,
+	ATHOS_B_5G_LUT_CHAN_546625_IDX,
+	ATHOS_B_5G_LUT_CHAN_546750_IDX,
+	ATHOS_B_5G_LUT_CHAN_546875_IDX,
+	ATHOS_B_5G_LUT_CHAN_547000_IDX,
+	ATHOS_B_5G_LUT_CHAN_547125_IDX,
+	ATHOS_B_5G_LUT_CHAN_547250_IDX,
+	ATHOS_B_5G_LUT_CHAN_547375_IDX,
+	ATHOS_B_5G_LUT_CHAN_547500_IDX,
+	ATHOS_B_5G_LUT_CHAN_547625_IDX,
+	ATHOS_B_5G_LUT_CHAN_547750_IDX,
+	ATHOS_B_5G_LUT_CHAN_547875_IDX,
+	ATHOS_B_5G_LUT_CHAN_548000_IDX,
+	ATHOS_B_5G_LUT_CHAN_548125_IDX,
+	ATHOS_B_5G_LUT_CHAN_548250_IDX,
+	ATHOS_B_5G_LUT_CHAN_548375_IDX,
+	ATHOS_B_5G_LUT_CHAN_548500_IDX,
+	ATHOS_B_5G_LUT_CHAN_548625_IDX,
+	ATHOS_B_5G_LUT_CHAN_548750_IDX,
+	ATHOS_B_5G_LUT_CHAN_548875_IDX,
+	ATHOS_B_5G_LUT_CHAN_549000_IDX,
+	ATHOS_B_5G_LUT_CHAN_549125_IDX,
+	ATHOS_B_5G_LUT_CHAN_549250_IDX,
+	ATHOS_B_5G_LUT_CHAN_549375_IDX,
+	ATHOS_B_5G_LUT_CHAN_549500_IDX,
+	ATHOS_B_5G_LUT_CHAN_549625_IDX,
+	ATHOS_B_5G_LUT_CHAN_549750_IDX,
+	ATHOS_B_5G_LUT_CHAN_549875_IDX,
+	ATHOS_B_5G_LUT_CHAN_550000_IDX,
+	ATHOS_B_5G_LUT_CHAN_550125_IDX,
+	ATHOS_B_5G_LUT_CHAN_550250_IDX,
+	ATHOS_B_5G_LUT_CHAN_550375_IDX,
+	ATHOS_B_5G_LUT_CHAN_550500_IDX,
+	ATHOS_B_5G_LUT_CHAN_550625_IDX,
+	ATHOS_B_5G_LUT_CHAN_550750_IDX,
+	ATHOS_B_5G_LUT_CHAN_550875_IDX,
+	ATHOS_B_5G_LUT_CHAN_551000_IDX,
+	ATHOS_B_5G_LUT_CHAN_551125_IDX,
+	ATHOS_B_5G_LUT_CHAN_551250_IDX,
+	ATHOS_B_5G_LUT_CHAN_551375_IDX,
+	ATHOS_B_5G_LUT_CHAN_551500_IDX,
+	ATHOS_B_5G_LUT_CHAN_551625_IDX,
+	ATHOS_B_5G_LUT_CHAN_551750_IDX,
+	ATHOS_B_5G_LUT_CHAN_551875_IDX,
+	ATHOS_B_5G_LUT_CHAN_552000_IDX,
+	ATHOS_B_5G_LUT_CHAN_552125_IDX,
+	ATHOS_B_5G_LUT_CHAN_552250_IDX,
+	ATHOS_B_5G_LUT_CHAN_552375_IDX,
+	ATHOS_B_5G_LUT_CHAN_552500_IDX,
+	ATHOS_B_5G_LUT_CHAN_552625_IDX,
+	ATHOS_B_5G_LUT_CHAN_552750_IDX,
+	ATHOS_B_5G_LUT_CHAN_552875_IDX,
+	ATHOS_B_5G_LUT_CHAN_553000_IDX,
+	ATHOS_B_5G_LUT_CHAN_553125_IDX,
+	ATHOS_B_5G_LUT_CHAN_553250_IDX,
+	ATHOS_B_5G_LUT_CHAN_553375_IDX,
+	ATHOS_B_5G_LUT_CHAN_553500_IDX,
+	ATHOS_B_5G_LUT_CHAN_553625_IDX,
+	ATHOS_B_5G_LUT_CHAN_553750_IDX,
+	ATHOS_B_5G_LUT_CHAN_553875_IDX,
+	ATHOS_B_5G_LUT_CHAN_554000_IDX,
+	ATHOS_B_5G_LUT_CHAN_554125_IDX,
+	ATHOS_B_5G_LUT_CHAN_554250_IDX,
+	ATHOS_B_5G_LUT_CHAN_554375_IDX,
+	ATHOS_B_5G_LUT_CHAN_554500_IDX,
+	ATHOS_B_5G_LUT_CHAN_554625_IDX,
+	ATHOS_B_5G_LUT_CHAN_554750_IDX,
+	ATHOS_B_5G_LUT_CHAN_554875_IDX,
+	ATHOS_B_5G_LUT_CHAN_555000_IDX,
+	ATHOS_B_5G_LUT_CHAN_555125_IDX,
+	ATHOS_B_5G_LUT_CHAN_555250_IDX,
+	ATHOS_B_5G_LUT_CHAN_555375_IDX,
+	ATHOS_B_5G_LUT_CHAN_555500_IDX,
+	ATHOS_B_5G_LUT_CHAN_555625_IDX,
+	ATHOS_B_5G_LUT_CHAN_555750_IDX,
+	ATHOS_B_5G_LUT_CHAN_555875_IDX,
+	ATHOS_B_5G_LUT_CHAN_556000_IDX,
+	ATHOS_B_5G_LUT_CHAN_556125_IDX,
+	ATHOS_B_5G_LUT_CHAN_556250_IDX,
+	ATHOS_B_5G_LUT_CHAN_556375_IDX,
+	ATHOS_B_5G_LUT_CHAN_556500_IDX,
+	ATHOS_B_5G_LUT_CHAN_556625_IDX,
+	ATHOS_B_5G_LUT_CHAN_556750_IDX,
+	ATHOS_B_5G_LUT_CHAN_556875_IDX,
+	ATHOS_B_5G_LUT_CHAN_557000_IDX,
+	ATHOS_B_5G_LUT_CHAN_557125_IDX,
+	ATHOS_B_5G_LUT_CHAN_557250_IDX,
+	ATHOS_B_5G_LUT_CHAN_557375_IDX,
+	ATHOS_B_5G_LUT_CHAN_557500_IDX,
+	ATHOS_B_5G_LUT_CHAN_557625_IDX,
+	ATHOS_B_5G_LUT_CHAN_557750_IDX,
+	ATHOS_B_5G_LUT_CHAN_557875_IDX,
+	ATHOS_B_5G_LUT_CHAN_558000_IDX,
+	ATHOS_B_5G_LUT_CHAN_558125_IDX,
+	ATHOS_B_5G_LUT_CHAN_558250_IDX,
+	ATHOS_B_5G_LUT_CHAN_558375_IDX,
+	ATHOS_B_5G_LUT_CHAN_558500_IDX,
+	ATHOS_B_5G_LUT_CHAN_558625_IDX,
+	ATHOS_B_5G_LUT_CHAN_558750_IDX,
+	ATHOS_B_5G_LUT_CHAN_558875_IDX,
+	ATHOS_B_5G_LUT_CHAN_559000_IDX,
+	ATHOS_B_5G_LUT_CHAN_559125_IDX,
+	ATHOS_B_5G_LUT_CHAN_559250_IDX,
+	ATHOS_B_5G_LUT_CHAN_559375_IDX,
+	ATHOS_B_5G_LUT_CHAN_559500_IDX,
+	ATHOS_B_5G_LUT_CHAN_559625_IDX,
+	ATHOS_B_5G_LUT_CHAN_559750_IDX,
+	ATHOS_B_5G_LUT_CHAN_559875_IDX,
+	ATHOS_B_5G_LUT_CHAN_560000_IDX,
+	ATHOS_B_5G_LUT_CHAN_560125_IDX,
+	ATHOS_B_5G_LUT_CHAN_560250_IDX,
+	ATHOS_B_5G_LUT_CHAN_560375_IDX,
+	ATHOS_B_5G_LUT_CHAN_560500_IDX,
+	ATHOS_B_5G_LUT_CHAN_560625_IDX,
+	ATHOS_B_5G_LUT_CHAN_560750_IDX,
+	ATHOS_B_5G_LUT_CHAN_560875_IDX,
+	ATHOS_B_5G_LUT_CHAN_561000_IDX,
+	ATHOS_B_5G_LUT_CHAN_561125_IDX,
+	ATHOS_B_5G_LUT_CHAN_561250_IDX,
+	ATHOS_B_5G_LUT_CHAN_561375_IDX,
+	ATHOS_B_5G_LUT_CHAN_561500_IDX,
+	ATHOS_B_5G_LUT_CHAN_561625_IDX,
+	ATHOS_B_5G_LUT_CHAN_561750_IDX,
+	ATHOS_B_5G_LUT_CHAN_561875_IDX,
+	ATHOS_B_5G_LUT_CHAN_562000_IDX,
+	ATHOS_B_5G_LUT_CHAN_562125_IDX,
+	ATHOS_B_5G_LUT_CHAN_562250_IDX,
+	ATHOS_B_5G_LUT_CHAN_562375_IDX,
+	ATHOS_B_5G_LUT_CHAN_562500_IDX,
+	ATHOS_B_5G_LUT_CHAN_562625_IDX,
+	ATHOS_B_5G_LUT_CHAN_562750_IDX,
+	ATHOS_B_5G_LUT_CHAN_562875_IDX,
+	ATHOS_B_5G_LUT_CHAN_563000_IDX,
+	ATHOS_B_5G_LUT_CHAN_563125_IDX,
+	ATHOS_B_5G_LUT_CHAN_563250_IDX,
+	ATHOS_B_5G_LUT_CHAN_563375_IDX,
+	ATHOS_B_5G_LUT_CHAN_563500_IDX,
+	ATHOS_B_5G_LUT_CHAN_563625_IDX,
+	ATHOS_B_5G_LUT_CHAN_563750_IDX,
+	ATHOS_B_5G_LUT_CHAN_563875_IDX,
+	ATHOS_B_5G_LUT_CHAN_564000_IDX,
+	ATHOS_B_5G_LUT_CHAN_564125_IDX,
+	ATHOS_B_5G_LUT_CHAN_564250_IDX,
+	ATHOS_B_5G_LUT_CHAN_564375_IDX,
+	ATHOS_B_5G_LUT_CHAN_564500_IDX,
+	ATHOS_B_5G_LUT_CHAN_564625_IDX,
+	ATHOS_B_5G_LUT_CHAN_564750_IDX,
+	ATHOS_B_5G_LUT_CHAN_564875_IDX,
+	ATHOS_B_5G_LUT_CHAN_565000_IDX,
+	ATHOS_B_5G_LUT_CHAN_565125_IDX,
+	ATHOS_B_5G_LUT_CHAN_565250_IDX,
+	ATHOS_B_5G_LUT_CHAN_565375_IDX,
+	ATHOS_B_5G_LUT_CHAN_565500_IDX,
+	ATHOS_B_5G_LUT_CHAN_565625_IDX,
+	ATHOS_B_5G_LUT_CHAN_565750_IDX,
+	ATHOS_B_5G_LUT_CHAN_565875_IDX,
+	ATHOS_B_5G_LUT_CHAN_566000_IDX,
+	ATHOS_B_5G_LUT_CHAN_566125_IDX,
+	ATHOS_B_5G_LUT_CHAN_566250_IDX,
+	ATHOS_B_5G_LUT_CHAN_566375_IDX,
+	ATHOS_B_5G_LUT_CHAN_566500_IDX,
+	ATHOS_B_5G_LUT_CHAN_566625_IDX,
+	ATHOS_B_5G_LUT_CHAN_566750_IDX,
+	ATHOS_B_5G_LUT_CHAN_566875_IDX,
+	ATHOS_B_5G_LUT_CHAN_567000_IDX,
+	ATHOS_B_5G_LUT_CHAN_567125_IDX,
+	ATHOS_B_5G_LUT_CHAN_567250_IDX,
+	ATHOS_B_5G_LUT_CHAN_567375_IDX,
+	ATHOS_B_5G_LUT_CHAN_567500_IDX,
+	ATHOS_B_5G_LUT_CHAN_567625_IDX,
+	ATHOS_B_5G_LUT_CHAN_567750_IDX,
+	ATHOS_B_5G_LUT_CHAN_567875_IDX,
+	ATHOS_B_5G_LUT_CHAN_568000_IDX,
+	ATHOS_B_5G_LUT_CHAN_568125_IDX,
+	ATHOS_B_5G_LUT_CHAN_568250_IDX,
+	ATHOS_B_5G_LUT_CHAN_568375_IDX,
+	ATHOS_B_5G_LUT_CHAN_568500_IDX,
+	ATHOS_B_5G_LUT_CHAN_568625_IDX,
+	ATHOS_B_5G_LUT_CHAN_568750_IDX,
+	ATHOS_B_5G_LUT_CHAN_568875_IDX,
+	ATHOS_B_5G_LUT_CHAN_569000_IDX,
+	ATHOS_B_5G_LUT_CHAN_569125_IDX,
+	ATHOS_B_5G_LUT_CHAN_569250_IDX,
+	ATHOS_B_5G_LUT_CHAN_569375_IDX,
+	ATHOS_B_5G_LUT_CHAN_569500_IDX,
+	ATHOS_B_5G_LUT_CHAN_569625_IDX,
+	ATHOS_B_5G_LUT_CHAN_569750_IDX,
+	ATHOS_B_5G_LUT_CHAN_569875_IDX,
+	ATHOS_B_5G_LUT_CHAN_570000_IDX,
+	ATHOS_B_5G_LUT_CHAN_570125_IDX,
+	ATHOS_B_5G_LUT_CHAN_570250_IDX,
+	ATHOS_B_5G_LUT_CHAN_570375_IDX,
+	ATHOS_B_5G_LUT_CHAN_570500_IDX,
+	ATHOS_B_5G_LUT_CHAN_570625_IDX,
+	ATHOS_B_5G_LUT_CHAN_570750_IDX,
+	ATHOS_B_5G_LUT_CHAN_570875_IDX,
+	ATHOS_B_5G_LUT_CHAN_571000_IDX,
+	ATHOS_B_5G_LUT_CHAN_571125_IDX,
+	ATHOS_B_5G_LUT_CHAN_571250_IDX,
+	ATHOS_B_5G_LUT_CHAN_571375_IDX,
+	ATHOS_B_5G_LUT_CHAN_571500_IDX,
+	ATHOS_B_5G_LUT_CHAN_571625_IDX,
+	ATHOS_B_5G_LUT_CHAN_571750_IDX,
+	ATHOS_B_5G_LUT_CHAN_571875_IDX,
+	ATHOS_B_5G_LUT_CHAN_572000_IDX,
+	ATHOS_B_5G_LUT_CHAN_572125_IDX,
+	ATHOS_B_5G_LUT_CHAN_572250_IDX,
+	ATHOS_B_5G_LUT_CHAN_572375_IDX,
+	ATHOS_B_5G_LUT_CHAN_572500_IDX,
+	ATHOS_B_5G_LUT_CHAN_572625_IDX,
+	ATHOS_B_5G_LUT_CHAN_572750_IDX,
+	ATHOS_B_5G_LUT_CHAN_572875_IDX,
+	ATHOS_B_5G_LUT_CHAN_573000_IDX,
+	ATHOS_B_5G_LUT_CHAN_573125_IDX,
+	ATHOS_B_5G_LUT_CHAN_573250_IDX,
+	ATHOS_B_5G_LUT_CHAN_573375_IDX,
+	ATHOS_B_5G_LUT_CHAN_573500_IDX,
+	ATHOS_B_5G_LUT_CHAN_573625_IDX,
+	ATHOS_B_5G_LUT_CHAN_573750_IDX,
+	ATHOS_B_5G_LUT_CHAN_573875_IDX,
+	ATHOS_B_5G_LUT_CHAN_574000_IDX,
+	ATHOS_B_5G_LUT_CHAN_574125_IDX,
+	ATHOS_B_5G_LUT_CHAN_574250_IDX,
+	ATHOS_B_5G_LUT_CHAN_574375_IDX,
+	ATHOS_B_5G_LUT_CHAN_574500_IDX,
+	ATHOS_B_5G_LUT_CHAN_574625_IDX,
+	ATHOS_B_5G_LUT_CHAN_574750_IDX,
+	ATHOS_B_5G_LUT_CHAN_574875_IDX,
+	ATHOS_B_5G_LUT_CHAN_575000_IDX,
+	ATHOS_B_5G_LUT_CHAN_575125_IDX,
+	ATHOS_B_5G_LUT_CHAN_575250_IDX,
+	ATHOS_B_5G_LUT_CHAN_575375_IDX,
+	ATHOS_B_5G_LUT_CHAN_575500_IDX,
+	ATHOS_B_5G_LUT_CHAN_575625_IDX,
+	ATHOS_B_5G_LUT_CHAN_575750_IDX,
+	ATHOS_B_5G_LUT_CHAN_575875_IDX,
+	ATHOS_B_5G_LUT_CHAN_576000_IDX,
+	ATHOS_B_5G_LUT_CHAN_576125_IDX,
+	ATHOS_B_5G_LUT_CHAN_576250_IDX,
+	ATHOS_B_5G_LUT_CHAN_576375_IDX,
+	ATHOS_B_5G_LUT_CHAN_576500_IDX,
+	ATHOS_B_5G_LUT_CHAN_576625_IDX,
+	ATHOS_B_5G_LUT_CHAN_576750_IDX,
+	ATHOS_B_5G_LUT_CHAN_576875_IDX,
+	ATHOS_B_5G_LUT_CHAN_577000_IDX,
+	ATHOS_B_5G_LUT_CHAN_577125_IDX,
+	ATHOS_B_5G_LUT_CHAN_577250_IDX,
+	ATHOS_B_5G_LUT_CHAN_577375_IDX,
+	ATHOS_B_5G_LUT_CHAN_577500_IDX,
+	ATHOS_B_5G_LUT_CHAN_577625_IDX,
+	ATHOS_B_5G_LUT_CHAN_577750_IDX,
+	ATHOS_B_5G_LUT_CHAN_577875_IDX,
+	ATHOS_B_5G_LUT_CHAN_578000_IDX,
+	ATHOS_B_5G_LUT_CHAN_578125_IDX,
+	ATHOS_B_5G_LUT_CHAN_578250_IDX,
+	ATHOS_B_5G_LUT_CHAN_578375_IDX,
+	ATHOS_B_5G_LUT_CHAN_578500_IDX,
+	ATHOS_B_5G_LUT_CHAN_578625_IDX,
+	ATHOS_B_5G_LUT_CHAN_578750_IDX,
+	ATHOS_B_5G_LUT_CHAN_578875_IDX,
+	ATHOS_B_5G_LUT_CHAN_579000_IDX,
+	ATHOS_B_5G_LUT_CHAN_579125_IDX,
+	ATHOS_B_5G_LUT_CHAN_579250_IDX,
+	ATHOS_B_5G_LUT_CHAN_579375_IDX,
+	ATHOS_B_5G_LUT_CHAN_579500_IDX,
+	ATHOS_B_5G_LUT_CHAN_579625_IDX,
+	ATHOS_B_5G_LUT_CHAN_579750_IDX,
+	ATHOS_B_5G_LUT_CHAN_579875_IDX,
+	ATHOS_B_5G_LUT_CHAN_580000_IDX,
+	ATHOS_B_5G_LUT_CHAN_580125_IDX,
+	ATHOS_B_5G_LUT_CHAN_580250_IDX,
+	ATHOS_B_5G_LUT_CHAN_580375_IDX,
+	ATHOS_B_5G_LUT_CHAN_580500_IDX,
+	ATHOS_B_5G_LUT_CHAN_580625_IDX,
+	ATHOS_B_5G_LUT_CHAN_580750_IDX,
+	ATHOS_B_5G_LUT_CHAN_580875_IDX,
+	ATHOS_B_5G_LUT_CHAN_581000_IDX,
+	ATHOS_B_5G_LUT_CHAN_581125_IDX,
+	ATHOS_B_5G_LUT_CHAN_581250_IDX,
+	ATHOS_B_5G_LUT_CHAN_581375_IDX,
+	ATHOS_B_5G_LUT_CHAN_581500_IDX,
+	ATHOS_B_5G_LUT_CHAN_581625_IDX,
+	ATHOS_B_5G_LUT_CHAN_581750_IDX,
+	ATHOS_B_5G_LUT_CHAN_581875_IDX,
+	ATHOS_B_5G_LUT_CHAN_582000_IDX,
+	ATHOS_B_5G_LUT_CHAN_582125_IDX,
+	ATHOS_B_5G_LUT_CHAN_582250_IDX,
+	ATHOS_B_5G_LUT_CHAN_582375_IDX,
+	ATHOS_B_5G_LUT_CHAN_582500_IDX,
+	ATHOS_B_5G_LUT_CHAN_582625_IDX,
+	ATHOS_B_5G_LUT_CHAN_582750_IDX,
+	ATHOS_B_5G_LUT_CHAN_582875_IDX,
+	ATHOS_B_5G_LUT_CHAN_583000_IDX,
+	ATHOS_B_5G_LUT_CHAN_583125_IDX,
+	ATHOS_B_5G_LUT_CHAN_583250_IDX,
+	ATHOS_B_5G_LUT_CHAN_583375_IDX,
+	ATHOS_B_5G_LUT_CHAN_583500_IDX,
+	ATHOS_B_5G_LUT_CHAN_583625_IDX,
+	ATHOS_B_5G_LUT_CHAN_583750_IDX,
+	ATHOS_B_5G_LUT_CHAN_583875_IDX,
+	ATHOS_B_5G_LUT_CHAN_584000_IDX,
+	ATHOS_B_5G_LUT_CHAN_584125_IDX,
+	ATHOS_B_5G_LUT_CHAN_584250_IDX,
+	ATHOS_B_5G_LUT_CHAN_584375_IDX,
+	ATHOS_B_5G_LUT_CHAN_584500_IDX,
+	ATHOS_B_5G_LUT_CHAN_584625_IDX,
+	ATHOS_B_5G_LUT_CHAN_584750_IDX,
+	ATHOS_B_5G_LUT_CHAN_584875_IDX,
+	ATHOS_B_5G_LUT_CHAN_585000_IDX,
+	ATHOS_B_5G_LUT_CHAN_585125_IDX,
+	ATHOS_B_5G_LUT_CHAN_585250_IDX,
+	ATHOS_B_5G_LUT_CHAN_585375_IDX,
+	ATHOS_B_5G_LUT_CHAN_585500_IDX,
+	ATHOS_B_5G_LUT_CHAN_585625_IDX,
+	ATHOS_B_5G_LUT_CHAN_585750_IDX,
+	ATHOS_B_5G_LUT_CHAN_585875_IDX,
+	ATHOS_B_5G_LUT_CHAN_586000_IDX,
+	ATHOS_B_5G_LUT_CHAN_586125_IDX,
+	ATHOS_B_5G_LUT_CHAN_586250_IDX,
+	ATHOS_B_5G_LUT_CHAN_586375_IDX,
+	ATHOS_B_5G_LUT_CHAN_586500_IDX,
+	ATHOS_B_5G_LUT_CHAN_586625_IDX,
+	ATHOS_B_5G_LUT_CHAN_586750_IDX,
+	ATHOS_B_5G_LUT_CHAN_586875_IDX,
+	ATHOS_B_5G_LUT_CHAN_587000_IDX,
+	ATHOS_B_5G_LUT_CHAN_587125_IDX,
+	ATHOS_B_5G_LUT_CHAN_587250_IDX,
+	ATHOS_B_5G_LUT_CHAN_587375_IDX,
+	ATHOS_B_5G_LUT_CHAN_587500_IDX,
+	ATHOS_B_5G_LUT_CHAN_587625_IDX,
+	ATHOS_B_5G_LUT_CHAN_587750_IDX,
+	ATHOS_B_5G_LUT_CHAN_587875_IDX,
+	ATHOS_B_5G_LUT_CHAN_588000_IDX,
+	ATHOS_B_5G_LUT_CHAN_588125_IDX,
+	ATHOS_B_5G_LUT_CHAN_588250_IDX,
+	ATHOS_B_5G_LUT_CHAN_588375_IDX,
+	ATHOS_B_5G_LUT_CHAN_588500_IDX,
+	ATHOS_B_5G_LUT_CHAN_588625_IDX,
+	ATHOS_B_5G_LUT_CHAN_588750_IDX,
+	ATHOS_B_5G_LUT_CHAN_588875_IDX,
+	ATHOS_B_5G_LUT_CHAN_589000_IDX,
+	ATHOS_B_5G_LUT_CHAN_589125_IDX,
+	ATHOS_B_5G_LUT_CHAN_589250_IDX,
+	ATHOS_B_5G_LUT_CHAN_589375_IDX,
+	ATHOS_B_5G_LUT_CHAN_589500_IDX,
+	ATHOS_B_5G_LUT_CHAN_589625_IDX,
+	ATHOS_B_5G_LUT_CHAN_589750_IDX,
+	ATHOS_B_5G_LUT_CHAN_589875_IDX,
+	ATHOS_B_5G_LUT_CHAN_590000_IDX,
+	ATHOS_B_5G_LUT_CHAN_590125_IDX,
+	ATHOS_B_5G_LUT_CHAN_590250_IDX,
+	ATHOS_B_5G_LUT_CHAN_590375_IDX,
+	ATHOS_B_5G_LUT_CHAN_590500_IDX,
+	ATHOS_B_5G_LUT_CHAN_590625_IDX,
+	ATHOS_B_5G_LUT_CHAN_590750_IDX,
+	ATHOS_B_5G_LUT_CHAN_590875_IDX,
+	ATHOS_B_5G_LUT_CHAN_591000_IDX,
+	ATHOS_B_5G_LUT_CHAN_591125_IDX,
+	ATHOS_B_5G_LUT_CHAN_591250_IDX,
+	ATHOS_B_5G_LUT_CHAN_591375_IDX,
+	ATHOS_B_5G_LUT_CHAN_591500_IDX,
+	ATHOS_B_5G_LUT_CHAN_591625_IDX,
+	ATHOS_B_5G_LUT_CHAN_591750_IDX,
+	ATHOS_B_5G_LUT_CHAN_591875_IDX,
+	ATHOS_B_5G_LUT_CHAN_592000_IDX,
+	ATHOS_B_5G_LUT_CHAN_592125_IDX,
+	ATHOS_B_5G_LUT_CHAN_592250_IDX,
+	ATHOS_B_5G_LUT_CHAN_592375_IDX,
+	ATHOS_B_5G_LUT_CHAN_592500_IDX,
+	ATHOS_B_5G_LUT_CHAN_592625_IDX,
+	ATHOS_B_5G_LUT_CHAN_592750_IDX,
+	ATHOS_B_5G_LUT_CHAN_592875_IDX,
+	ATHOS_B_5G_LUT_CHAN_593000_IDX,
+	ATHOS_B_5G_LUT_CHAN_593125_IDX,
+	ATHOS_B_5G_LUT_CHAN_593250_IDX,
+	ATHOS_B_5G_LUT_CHAN_593375_IDX,
+	ATHOS_B_5G_LUT_CHAN_593500_IDX,
+	ATHOS_B_5G_LUT_CHAN_593625_IDX,
+	ATHOS_B_5G_LUT_CHAN_593750_IDX,
+	ATHOS_B_5G_LUT_CHAN_593875_IDX,
+	ATHOS_B_5G_LUT_CHAN_594000_IDX,
+	ATHOS_B_5G_LUT_CHAN_594125_IDX,
+	ATHOS_B_5G_LUT_CHAN_594250_IDX,
+	ATHOS_B_5G_LUT_CHAN_594375_IDX,
+	ATHOS_B_5G_LUT_CHAN_594500_IDX,
+	ATHOS_B_5G_LUT_CHAN_594625_IDX,
+	ATHOS_B_5G_LUT_CHAN_594750_IDX,
+	ATHOS_B_5G_LUT_CHAN_594875_IDX,
+	ATHOS_B_5G_LUT_CHAN_595000_IDX,
+	ATHOS_B_5G_LUT_CHAN_595125_IDX,
+	ATHOS_B_5G_LUT_CHAN_595250_IDX,
+	ATHOS_B_5G_LUT_CHAN_595375_IDX,
+	ATHOS_B_5G_LUT_CHAN_595500_IDX,
+	ATHOS_B_5G_LUT_CHAN_595625_IDX,
+	ATHOS_B_5G_LUT_CHAN_595750_IDX,
+	ATHOS_B_5G_LUT_CHAN_595875_IDX,
+	ATHOS_B_5G_LUT_CHAN_596000_IDX,
+	ATHOS_B_5G_LUT_CHAN_596125_IDX,
+	ATHOS_B_5G_LUT_CHAN_596250_IDX,
+	ATHOS_B_5G_LUT_CHAN_596375_IDX,
+	ATHOS_B_5G_LUT_CHAN_596500_IDX,
+	ATHOS_B_5G_LUT_CHAN_596625_IDX,
+	ATHOS_B_5G_LUT_CHAN_596750_IDX,
+	ATHOS_B_5G_LUT_CHAN_596875_IDX,
+	ATHOS_B_5G_LUT_CHAN_597000_IDX,
+	ATHOS_B_5G_LUT_CHAN_597125_IDX,
+	ATHOS_B_5G_LUT_CHAN_597250_IDX,
+	ATHOS_B_5G_LUT_CHAN_597375_IDX,
+	ATHOS_B_5G_LUT_CHAN_597500_IDX,
+	ATHOS_B_5G_LUT_CHAN_597625_IDX,
+	ATHOS_B_5G_LUT_CHAN_597750_IDX,
+	ATHOS_B_5G_LUT_CHAN_597875_IDX,
+	ATHOS_B_5G_LUT_CHAN_598000_IDX,
+	ATHOS_B_5G_LUT_CHAN_598125_IDX,
+	ATHOS_B_5G_LUT_CHAN_598250_IDX,
+	ATHOS_B_5G_LUT_CHAN_598375_IDX,
+	ATHOS_B_5G_LUT_CHAN_598500_IDX,
+	ATHOS_B_5G_LUT_CHAN_598625_IDX,
+	ATHOS_B_5G_LUT_CHAN_598750_IDX,
+	ATHOS_B_5G_LUT_CHAN_598875_IDX,
+	ATHOS_B_5G_LUT_CHAN_599000_IDX,
+	ATHOS_B_5G_LUT_CHAN_599125_IDX,
+	ATHOS_B_5G_LUT_CHAN_599250_IDX,
+	ATHOS_B_5G_LUT_CHAN_599375_IDX,
+	ATHOS_B_5G_LUT_CHAN_599500_IDX,
+	ATHOS_B_5G_LUT_CHAN_599625_IDX,
+	ATHOS_B_5G_LUT_CHAN_599750_IDX,
+	ATHOS_B_5G_LUT_CHAN_599875_IDX,
+	ATHOS_B_5G_LUT_CHAN_600000_IDX,
+	ATHOS_B_5G_LUT_CHAN_5G_MAX
+};
+
+enum athos_b_idx_6g {
+	ATHOS_B_6G_LUT_CHAN_593000_IDX,
+	ATHOS_B_6G_LUT_CHAN_593125_IDX,
+	ATHOS_B_6G_LUT_CHAN_593250_IDX,
+	ATHOS_B_6G_LUT_CHAN_593375_IDX,
+	ATHOS_B_6G_LUT_CHAN_593500_IDX,
+	ATHOS_B_6G_LUT_CHAN_593625_IDX,
+	ATHOS_B_6G_LUT_CHAN_593750_IDX,
+	ATHOS_B_6G_LUT_CHAN_593875_IDX,
+	ATHOS_B_6G_LUT_CHAN_594000_IDX,
+	ATHOS_B_6G_LUT_CHAN_594125_IDX,
+	ATHOS_B_6G_LUT_CHAN_594250_IDX,
+	ATHOS_B_6G_LUT_CHAN_594375_IDX,
+	ATHOS_B_6G_LUT_CHAN_594500_IDX,
+	ATHOS_B_6G_LUT_CHAN_594625_IDX,
+	ATHOS_B_6G_LUT_CHAN_594750_IDX,
+	ATHOS_B_6G_LUT_CHAN_594875_IDX,
+	ATHOS_B_6G_LUT_CHAN_595000_IDX,
+	ATHOS_B_6G_LUT_CHAN_595125_IDX,
+	ATHOS_B_6G_LUT_CHAN_595250_IDX,
+	ATHOS_B_6G_LUT_CHAN_595375_IDX,
+	ATHOS_B_6G_LUT_CHAN_595500_IDX,
+	ATHOS_B_6G_LUT_CHAN_595625_IDX,
+	ATHOS_B_6G_LUT_CHAN_595750_IDX,
+	ATHOS_B_6G_LUT_CHAN_595875_IDX,
+	ATHOS_B_6G_LUT_CHAN_596000_IDX,
+	ATHOS_B_6G_LUT_CHAN_596125_IDX,
+	ATHOS_B_6G_LUT_CHAN_596250_IDX,
+	ATHOS_B_6G_LUT_CHAN_596375_IDX,
+	ATHOS_B_6G_LUT_CHAN_596500_IDX,
+	ATHOS_B_6G_LUT_CHAN_596625_IDX,
+	ATHOS_B_6G_LUT_CHAN_596750_IDX,
+	ATHOS_B_6G_LUT_CHAN_596875_IDX,
+	ATHOS_B_6G_LUT_CHAN_597000_IDX,
+	ATHOS_B_6G_LUT_CHAN_597125_IDX,
+	ATHOS_B_6G_LUT_CHAN_597250_IDX,
+	ATHOS_B_6G_LUT_CHAN_597375_IDX,
+	ATHOS_B_6G_LUT_CHAN_597500_IDX,
+	ATHOS_B_6G_LUT_CHAN_597625_IDX,
+	ATHOS_B_6G_LUT_CHAN_597750_IDX,
+	ATHOS_B_6G_LUT_CHAN_597875_IDX,
+	ATHOS_B_6G_LUT_CHAN_598000_IDX,
+	ATHOS_B_6G_LUT_CHAN_598125_IDX,
+	ATHOS_B_6G_LUT_CHAN_598250_IDX,
+	ATHOS_B_6G_LUT_CHAN_598375_IDX,
+	ATHOS_B_6G_LUT_CHAN_598500_IDX,
+	ATHOS_B_6G_LUT_CHAN_598625_IDX,
+	ATHOS_B_6G_LUT_CHAN_598750_IDX,
+	ATHOS_B_6G_LUT_CHAN_598875_IDX,
+	ATHOS_B_6G_LUT_CHAN_599000_IDX,
+	ATHOS_B_6G_LUT_CHAN_599125_IDX,
+	ATHOS_B_6G_LUT_CHAN_599250_IDX,
+	ATHOS_B_6G_LUT_CHAN_599375_IDX,
+	ATHOS_B_6G_LUT_CHAN_599500_IDX,
+	ATHOS_B_6G_LUT_CHAN_599625_IDX,
+	ATHOS_B_6G_LUT_CHAN_599750_IDX,
+	ATHOS_B_6G_LUT_CHAN_599875_IDX,
+	ATHOS_B_6G_LUT_CHAN_600000_IDX,
+	ATHOS_B_6G_LUT_CHAN_600125_IDX,
+	ATHOS_B_6G_LUT_CHAN_600250_IDX,
+	ATHOS_B_6G_LUT_CHAN_600375_IDX,
+	ATHOS_B_6G_LUT_CHAN_600500_IDX,
+	ATHOS_B_6G_LUT_CHAN_600625_IDX,
+	ATHOS_B_6G_LUT_CHAN_600750_IDX,
+	ATHOS_B_6G_LUT_CHAN_600875_IDX,
+	ATHOS_B_6G_LUT_CHAN_601000_IDX,
+	ATHOS_B_6G_LUT_CHAN_601125_IDX,
+	ATHOS_B_6G_LUT_CHAN_601250_IDX,
+	ATHOS_B_6G_LUT_CHAN_601375_IDX,
+	ATHOS_B_6G_LUT_CHAN_601500_IDX,
+	ATHOS_B_6G_LUT_CHAN_601625_IDX,
+	ATHOS_B_6G_LUT_CHAN_601750_IDX,
+	ATHOS_B_6G_LUT_CHAN_601875_IDX,
+	ATHOS_B_6G_LUT_CHAN_602000_IDX,
+	ATHOS_B_6G_LUT_CHAN_602125_IDX,
+	ATHOS_B_6G_LUT_CHAN_602250_IDX,
+	ATHOS_B_6G_LUT_CHAN_602375_IDX,
+	ATHOS_B_6G_LUT_CHAN_602500_IDX,
+	ATHOS_B_6G_LUT_CHAN_602625_IDX,
+	ATHOS_B_6G_LUT_CHAN_602750_IDX,
+	ATHOS_B_6G_LUT_CHAN_602875_IDX,
+	ATHOS_B_6G_LUT_CHAN_603000_IDX,
+	ATHOS_B_6G_LUT_CHAN_603125_IDX,
+	ATHOS_B_6G_LUT_CHAN_603250_IDX,
+	ATHOS_B_6G_LUT_CHAN_603375_IDX,
+	ATHOS_B_6G_LUT_CHAN_603500_IDX,
+	ATHOS_B_6G_LUT_CHAN_603625_IDX,
+	ATHOS_B_6G_LUT_CHAN_603750_IDX,
+	ATHOS_B_6G_LUT_CHAN_603875_IDX,
+	ATHOS_B_6G_LUT_CHAN_604000_IDX,
+	ATHOS_B_6G_LUT_CHAN_604125_IDX,
+	ATHOS_B_6G_LUT_CHAN_604250_IDX,
+	ATHOS_B_6G_LUT_CHAN_604375_IDX,
+	ATHOS_B_6G_LUT_CHAN_604500_IDX,
+	ATHOS_B_6G_LUT_CHAN_604625_IDX,
+	ATHOS_B_6G_LUT_CHAN_604750_IDX,
+	ATHOS_B_6G_LUT_CHAN_604875_IDX,
+	ATHOS_B_6G_LUT_CHAN_605000_IDX,
+	ATHOS_B_6G_LUT_CHAN_605125_IDX,
+	ATHOS_B_6G_LUT_CHAN_605250_IDX,
+	ATHOS_B_6G_LUT_CHAN_605375_IDX,
+	ATHOS_B_6G_LUT_CHAN_605500_IDX,
+	ATHOS_B_6G_LUT_CHAN_605625_IDX,
+	ATHOS_B_6G_LUT_CHAN_605750_IDX,
+	ATHOS_B_6G_LUT_CHAN_605875_IDX,
+	ATHOS_B_6G_LUT_CHAN_606000_IDX,
+	ATHOS_B_6G_LUT_CHAN_606125_IDX,
+	ATHOS_B_6G_LUT_CHAN_606250_IDX,
+	ATHOS_B_6G_LUT_CHAN_606375_IDX,
+	ATHOS_B_6G_LUT_CHAN_606500_IDX,
+	ATHOS_B_6G_LUT_CHAN_606625_IDX,
+	ATHOS_B_6G_LUT_CHAN_606750_IDX,
+	ATHOS_B_6G_LUT_CHAN_606875_IDX,
+	ATHOS_B_6G_LUT_CHAN_607000_IDX,
+	ATHOS_B_6G_LUT_CHAN_607125_IDX,
+	ATHOS_B_6G_LUT_CHAN_607250_IDX,
+	ATHOS_B_6G_LUT_CHAN_607375_IDX,
+	ATHOS_B_6G_LUT_CHAN_607500_IDX,
+	ATHOS_B_6G_LUT_CHAN_607625_IDX,
+	ATHOS_B_6G_LUT_CHAN_607750_IDX,
+	ATHOS_B_6G_LUT_CHAN_607875_IDX,
+	ATHOS_B_6G_LUT_CHAN_608000_IDX,
+	ATHOS_B_6G_LUT_CHAN_608125_IDX,
+	ATHOS_B_6G_LUT_CHAN_608250_IDX,
+	ATHOS_B_6G_LUT_CHAN_608375_IDX,
+	ATHOS_B_6G_LUT_CHAN_608500_IDX,
+	ATHOS_B_6G_LUT_CHAN_608625_IDX,
+	ATHOS_B_6G_LUT_CHAN_608750_IDX,
+	ATHOS_B_6G_LUT_CHAN_608875_IDX,
+	ATHOS_B_6G_LUT_CHAN_609000_IDX,
+	ATHOS_B_6G_LUT_CHAN_609125_IDX,
+	ATHOS_B_6G_LUT_CHAN_609250_IDX,
+	ATHOS_B_6G_LUT_CHAN_609375_IDX,
+	ATHOS_B_6G_LUT_CHAN_609500_IDX,
+	ATHOS_B_6G_LUT_CHAN_609625_IDX,
+	ATHOS_B_6G_LUT_CHAN_609750_IDX,
+	ATHOS_B_6G_LUT_CHAN_609875_IDX,
+	ATHOS_B_6G_LUT_CHAN_610000_IDX,
+	ATHOS_B_6G_LUT_CHAN_610125_IDX,
+	ATHOS_B_6G_LUT_CHAN_610250_IDX,
+	ATHOS_B_6G_LUT_CHAN_610375_IDX,
+	ATHOS_B_6G_LUT_CHAN_610500_IDX,
+	ATHOS_B_6G_LUT_CHAN_610625_IDX,
+	ATHOS_B_6G_LUT_CHAN_610750_IDX,
+	ATHOS_B_6G_LUT_CHAN_610875_IDX,
+	ATHOS_B_6G_LUT_CHAN_611000_IDX,
+	ATHOS_B_6G_LUT_CHAN_611125_IDX,
+	ATHOS_B_6G_LUT_CHAN_611250_IDX,
+	ATHOS_B_6G_LUT_CHAN_611375_IDX,
+	ATHOS_B_6G_LUT_CHAN_611500_IDX,
+	ATHOS_B_6G_LUT_CHAN_611625_IDX,
+	ATHOS_B_6G_LUT_CHAN_611750_IDX,
+	ATHOS_B_6G_LUT_CHAN_611875_IDX,
+	ATHOS_B_6G_LUT_CHAN_612000_IDX,
+	ATHOS_B_6G_LUT_CHAN_612125_IDX,
+	ATHOS_B_6G_LUT_CHAN_612250_IDX,
+	ATHOS_B_6G_LUT_CHAN_612375_IDX,
+	ATHOS_B_6G_LUT_CHAN_612500_IDX,
+	ATHOS_B_6G_LUT_CHAN_612625_IDX,
+	ATHOS_B_6G_LUT_CHAN_612750_IDX,
+	ATHOS_B_6G_LUT_CHAN_612875_IDX,
+	ATHOS_B_6G_LUT_CHAN_613000_IDX,
+	ATHOS_B_6G_LUT_CHAN_613125_IDX,
+	ATHOS_B_6G_LUT_CHAN_613250_IDX,
+	ATHOS_B_6G_LUT_CHAN_613375_IDX,
+	ATHOS_B_6G_LUT_CHAN_613500_IDX,
+	ATHOS_B_6G_LUT_CHAN_613625_IDX,
+	ATHOS_B_6G_LUT_CHAN_613750_IDX,
+	ATHOS_B_6G_LUT_CHAN_613875_IDX,
+	ATHOS_B_6G_LUT_CHAN_614000_IDX,
+	ATHOS_B_6G_LUT_CHAN_614125_IDX,
+	ATHOS_B_6G_LUT_CHAN_614250_IDX,
+	ATHOS_B_6G_LUT_CHAN_614375_IDX,
+	ATHOS_B_6G_LUT_CHAN_614500_IDX,
+	ATHOS_B_6G_LUT_CHAN_614625_IDX,
+	ATHOS_B_6G_LUT_CHAN_614750_IDX,
+	ATHOS_B_6G_LUT_CHAN_614875_IDX,
+	ATHOS_B_6G_LUT_CHAN_615000_IDX,
+	ATHOS_B_6G_LUT_CHAN_615125_IDX,
+	ATHOS_B_6G_LUT_CHAN_615250_IDX,
+	ATHOS_B_6G_LUT_CHAN_615375_IDX,
+	ATHOS_B_6G_LUT_CHAN_615500_IDX,
+	ATHOS_B_6G_LUT_CHAN_615625_IDX,
+	ATHOS_B_6G_LUT_CHAN_615750_IDX,
+	ATHOS_B_6G_LUT_CHAN_615875_IDX,
+	ATHOS_B_6G_LUT_CHAN_616000_IDX,
+	ATHOS_B_6G_LUT_CHAN_616125_IDX,
+	ATHOS_B_6G_LUT_CHAN_616250_IDX,
+	ATHOS_B_6G_LUT_CHAN_616375_IDX,
+	ATHOS_B_6G_LUT_CHAN_616500_IDX,
+	ATHOS_B_6G_LUT_CHAN_616625_IDX,
+	ATHOS_B_6G_LUT_CHAN_616750_IDX,
+	ATHOS_B_6G_LUT_CHAN_616875_IDX,
+	ATHOS_B_6G_LUT_CHAN_617000_IDX,
+	ATHOS_B_6G_LUT_CHAN_617125_IDX,
+	ATHOS_B_6G_LUT_CHAN_617250_IDX,
+	ATHOS_B_6G_LUT_CHAN_617375_IDX,
+	ATHOS_B_6G_LUT_CHAN_617500_IDX,
+	ATHOS_B_6G_LUT_CHAN_617625_IDX,
+	ATHOS_B_6G_LUT_CHAN_617750_IDX,
+	ATHOS_B_6G_LUT_CHAN_617875_IDX,
+	ATHOS_B_6G_LUT_CHAN_618000_IDX,
+	ATHOS_B_6G_LUT_CHAN_618125_IDX,
+	ATHOS_B_6G_LUT_CHAN_618250_IDX,
+	ATHOS_B_6G_LUT_CHAN_618375_IDX,
+	ATHOS_B_6G_LUT_CHAN_618500_IDX,
+	ATHOS_B_6G_LUT_CHAN_618625_IDX,
+	ATHOS_B_6G_LUT_CHAN_618750_IDX,
+	ATHOS_B_6G_LUT_CHAN_618875_IDX,
+	ATHOS_B_6G_LUT_CHAN_619000_IDX,
+	ATHOS_B_6G_LUT_CHAN_619125_IDX,
+	ATHOS_B_6G_LUT_CHAN_619250_IDX,
+	ATHOS_B_6G_LUT_CHAN_619375_IDX,
+	ATHOS_B_6G_LUT_CHAN_619500_IDX,
+	ATHOS_B_6G_LUT_CHAN_619625_IDX,
+	ATHOS_B_6G_LUT_CHAN_619750_IDX,
+	ATHOS_B_6G_LUT_CHAN_619875_IDX,
+	ATHOS_B_6G_LUT_CHAN_620000_IDX,
+	ATHOS_B_6G_LUT_CHAN_620125_IDX,
+	ATHOS_B_6G_LUT_CHAN_620250_IDX,
+	ATHOS_B_6G_LUT_CHAN_620375_IDX,
+	ATHOS_B_6G_LUT_CHAN_620500_IDX,
+	ATHOS_B_6G_LUT_CHAN_620625_IDX,
+	ATHOS_B_6G_LUT_CHAN_620750_IDX,
+	ATHOS_B_6G_LUT_CHAN_620875_IDX,
+	ATHOS_B_6G_LUT_CHAN_621000_IDX,
+	ATHOS_B_6G_LUT_CHAN_621125_IDX,
+	ATHOS_B_6G_LUT_CHAN_621250_IDX,
+	ATHOS_B_6G_LUT_CHAN_621375_IDX,
+	ATHOS_B_6G_LUT_CHAN_621500_IDX,
+	ATHOS_B_6G_LUT_CHAN_621625_IDX,
+	ATHOS_B_6G_LUT_CHAN_621750_IDX,
+	ATHOS_B_6G_LUT_CHAN_621875_IDX,
+	ATHOS_B_6G_LUT_CHAN_622000_IDX,
+	ATHOS_B_6G_LUT_CHAN_622125_IDX,
+	ATHOS_B_6G_LUT_CHAN_622250_IDX,
+	ATHOS_B_6G_LUT_CHAN_622375_IDX,
+	ATHOS_B_6G_LUT_CHAN_622500_IDX,
+	ATHOS_B_6G_LUT_CHAN_622625_IDX,
+	ATHOS_B_6G_LUT_CHAN_622750_IDX,
+	ATHOS_B_6G_LUT_CHAN_622875_IDX,
+	ATHOS_B_6G_LUT_CHAN_623000_IDX,
+	ATHOS_B_6G_LUT_CHAN_623125_IDX,
+	ATHOS_B_6G_LUT_CHAN_623250_IDX,
+	ATHOS_B_6G_LUT_CHAN_623375_IDX,
+	ATHOS_B_6G_LUT_CHAN_623500_IDX,
+	ATHOS_B_6G_LUT_CHAN_623625_IDX,
+	ATHOS_B_6G_LUT_CHAN_623750_IDX,
+	ATHOS_B_6G_LUT_CHAN_623875_IDX,
+	ATHOS_B_6G_LUT_CHAN_624000_IDX,
+	ATHOS_B_6G_LUT_CHAN_624125_IDX,
+	ATHOS_B_6G_LUT_CHAN_624250_IDX,
+	ATHOS_B_6G_LUT_CHAN_624375_IDX,
+	ATHOS_B_6G_LUT_CHAN_624500_IDX,
+	ATHOS_B_6G_LUT_CHAN_624625_IDX,
+	ATHOS_B_6G_LUT_CHAN_624750_IDX,
+	ATHOS_B_6G_LUT_CHAN_624875_IDX,
+	ATHOS_B_6G_LUT_CHAN_625000_IDX,
+	ATHOS_B_6G_LUT_CHAN_625125_IDX,
+	ATHOS_B_6G_LUT_CHAN_625250_IDX,
+	ATHOS_B_6G_LUT_CHAN_625375_IDX,
+	ATHOS_B_6G_LUT_CHAN_625500_IDX,
+	ATHOS_B_6G_LUT_CHAN_625625_IDX,
+	ATHOS_B_6G_LUT_CHAN_625750_IDX,
+	ATHOS_B_6G_LUT_CHAN_625875_IDX,
+	ATHOS_B_6G_LUT_CHAN_626000_IDX,
+	ATHOS_B_6G_LUT_CHAN_626125_IDX,
+	ATHOS_B_6G_LUT_CHAN_626250_IDX,
+	ATHOS_B_6G_LUT_CHAN_626375_IDX,
+	ATHOS_B_6G_LUT_CHAN_626500_IDX,
+	ATHOS_B_6G_LUT_CHAN_626625_IDX,
+	ATHOS_B_6G_LUT_CHAN_626750_IDX,
+	ATHOS_B_6G_LUT_CHAN_626875_IDX,
+	ATHOS_B_6G_LUT_CHAN_627000_IDX,
+	ATHOS_B_6G_LUT_CHAN_627125_IDX,
+	ATHOS_B_6G_LUT_CHAN_627250_IDX,
+	ATHOS_B_6G_LUT_CHAN_627375_IDX,
+	ATHOS_B_6G_LUT_CHAN_627500_IDX,
+	ATHOS_B_6G_LUT_CHAN_627625_IDX,
+	ATHOS_B_6G_LUT_CHAN_627750_IDX,
+	ATHOS_B_6G_LUT_CHAN_627875_IDX,
+	ATHOS_B_6G_LUT_CHAN_628000_IDX,
+	ATHOS_B_6G_LUT_CHAN_628125_IDX,
+	ATHOS_B_6G_LUT_CHAN_628250_IDX,
+	ATHOS_B_6G_LUT_CHAN_628375_IDX,
+	ATHOS_B_6G_LUT_CHAN_628500_IDX,
+	ATHOS_B_6G_LUT_CHAN_628625_IDX,
+	ATHOS_B_6G_LUT_CHAN_628750_IDX,
+	ATHOS_B_6G_LUT_CHAN_628875_IDX,
+	ATHOS_B_6G_LUT_CHAN_629000_IDX,
+	ATHOS_B_6G_LUT_CHAN_629125_IDX,
+	ATHOS_B_6G_LUT_CHAN_629250_IDX,
+	ATHOS_B_6G_LUT_CHAN_629375_IDX,
+	ATHOS_B_6G_LUT_CHAN_629500_IDX,
+	ATHOS_B_6G_LUT_CHAN_629625_IDX,
+	ATHOS_B_6G_LUT_CHAN_629750_IDX,
+	ATHOS_B_6G_LUT_CHAN_629875_IDX,
+	ATHOS_B_6G_LUT_CHAN_630000_IDX,
+	ATHOS_B_6G_LUT_CHAN_630125_IDX,
+	ATHOS_B_6G_LUT_CHAN_630250_IDX,
+	ATHOS_B_6G_LUT_CHAN_630375_IDX,
+	ATHOS_B_6G_LUT_CHAN_630500_IDX,
+	ATHOS_B_6G_LUT_CHAN_630625_IDX,
+	ATHOS_B_6G_LUT_CHAN_630750_IDX,
+	ATHOS_B_6G_LUT_CHAN_630875_IDX,
+	ATHOS_B_6G_LUT_CHAN_631000_IDX,
+	ATHOS_B_6G_LUT_CHAN_631125_IDX,
+	ATHOS_B_6G_LUT_CHAN_631250_IDX,
+	ATHOS_B_6G_LUT_CHAN_631375_IDX,
+	ATHOS_B_6G_LUT_CHAN_631500_IDX,
+	ATHOS_B_6G_LUT_CHAN_631625_IDX,
+	ATHOS_B_6G_LUT_CHAN_631750_IDX,
+	ATHOS_B_6G_LUT_CHAN_631875_IDX,
+	ATHOS_B_6G_LUT_CHAN_632000_IDX,
+	ATHOS_B_6G_LUT_CHAN_632125_IDX,
+	ATHOS_B_6G_LUT_CHAN_632250_IDX,
+	ATHOS_B_6G_LUT_CHAN_632375_IDX,
+	ATHOS_B_6G_LUT_CHAN_632500_IDX,
+	ATHOS_B_6G_LUT_CHAN_632625_IDX,
+	ATHOS_B_6G_LUT_CHAN_632750_IDX,
+	ATHOS_B_6G_LUT_CHAN_632875_IDX,
+	ATHOS_B_6G_LUT_CHAN_633000_IDX,
+	ATHOS_B_6G_LUT_CHAN_633125_IDX,
+	ATHOS_B_6G_LUT_CHAN_633250_IDX,
+	ATHOS_B_6G_LUT_CHAN_633375_IDX,
+	ATHOS_B_6G_LUT_CHAN_633500_IDX,
+	ATHOS_B_6G_LUT_CHAN_633625_IDX,
+	ATHOS_B_6G_LUT_CHAN_633750_IDX,
+	ATHOS_B_6G_LUT_CHAN_633875_IDX,
+	ATHOS_B_6G_LUT_CHAN_634000_IDX,
+	ATHOS_B_6G_LUT_CHAN_634125_IDX,
+	ATHOS_B_6G_LUT_CHAN_634250_IDX,
+	ATHOS_B_6G_LUT_CHAN_634375_IDX,
+	ATHOS_B_6G_LUT_CHAN_634500_IDX,
+	ATHOS_B_6G_LUT_CHAN_634625_IDX,
+	ATHOS_B_6G_LUT_CHAN_634750_IDX,
+	ATHOS_B_6G_LUT_CHAN_634875_IDX,
+	ATHOS_B_6G_LUT_CHAN_635000_IDX,
+	ATHOS_B_6G_LUT_CHAN_635125_IDX,
+	ATHOS_B_6G_LUT_CHAN_635250_IDX,
+	ATHOS_B_6G_LUT_CHAN_635375_IDX,
+	ATHOS_B_6G_LUT_CHAN_635500_IDX,
+	ATHOS_B_6G_LUT_CHAN_635625_IDX,
+	ATHOS_B_6G_LUT_CHAN_635750_IDX,
+	ATHOS_B_6G_LUT_CHAN_635875_IDX,
+	ATHOS_B_6G_LUT_CHAN_636000_IDX,
+	ATHOS_B_6G_LUT_CHAN_636125_IDX,
+	ATHOS_B_6G_LUT_CHAN_636250_IDX,
+	ATHOS_B_6G_LUT_CHAN_636375_IDX,
+	ATHOS_B_6G_LUT_CHAN_636500_IDX,
+	ATHOS_B_6G_LUT_CHAN_636625_IDX,
+	ATHOS_B_6G_LUT_CHAN_636750_IDX,
+	ATHOS_B_6G_LUT_CHAN_636875_IDX,
+	ATHOS_B_6G_LUT_CHAN_637000_IDX,
+	ATHOS_B_6G_LUT_CHAN_637125_IDX,
+	ATHOS_B_6G_LUT_CHAN_637250_IDX,
+	ATHOS_B_6G_LUT_CHAN_637375_IDX,
+	ATHOS_B_6G_LUT_CHAN_637500_IDX,
+	ATHOS_B_6G_LUT_CHAN_637625_IDX,
+	ATHOS_B_6G_LUT_CHAN_637750_IDX,
+	ATHOS_B_6G_LUT_CHAN_637875_IDX,
+	ATHOS_B_6G_LUT_CHAN_638000_IDX,
+	ATHOS_B_6G_LUT_CHAN_638125_IDX,
+	ATHOS_B_6G_LUT_CHAN_638250_IDX,
+	ATHOS_B_6G_LUT_CHAN_638375_IDX,
+	ATHOS_B_6G_LUT_CHAN_638500_IDX,
+	ATHOS_B_6G_LUT_CHAN_638625_IDX,
+	ATHOS_B_6G_LUT_CHAN_638750_IDX,
+	ATHOS_B_6G_LUT_CHAN_638875_IDX,
+	ATHOS_B_6G_LUT_CHAN_639000_IDX,
+	ATHOS_B_6G_LUT_CHAN_639125_IDX,
+	ATHOS_B_6G_LUT_CHAN_639250_IDX,
+	ATHOS_B_6G_LUT_CHAN_639375_IDX,
+	ATHOS_B_6G_LUT_CHAN_639500_IDX,
+	ATHOS_B_6G_LUT_CHAN_639625_IDX,
+	ATHOS_B_6G_LUT_CHAN_639750_IDX,
+	ATHOS_B_6G_LUT_CHAN_639875_IDX,
+	ATHOS_B_6G_LUT_CHAN_640000_IDX,
+	ATHOS_B_6G_LUT_CHAN_640125_IDX,
+	ATHOS_B_6G_LUT_CHAN_640250_IDX,
+	ATHOS_B_6G_LUT_CHAN_640375_IDX,
+	ATHOS_B_6G_LUT_CHAN_640500_IDX,
+	ATHOS_B_6G_LUT_CHAN_640625_IDX,
+	ATHOS_B_6G_LUT_CHAN_640750_IDX,
+	ATHOS_B_6G_LUT_CHAN_640875_IDX,
+	ATHOS_B_6G_LUT_CHAN_641000_IDX,
+	ATHOS_B_6G_LUT_CHAN_641125_IDX,
+	ATHOS_B_6G_LUT_CHAN_641250_IDX,
+	ATHOS_B_6G_LUT_CHAN_641375_IDX,
+	ATHOS_B_6G_LUT_CHAN_641500_IDX,
+	ATHOS_B_6G_LUT_CHAN_641625_IDX,
+	ATHOS_B_6G_LUT_CHAN_641750_IDX,
+	ATHOS_B_6G_LUT_CHAN_641875_IDX,
+	ATHOS_B_6G_LUT_CHAN_642000_IDX,
+	ATHOS_B_6G_LUT_CHAN_642125_IDX,
+	ATHOS_B_6G_LUT_CHAN_642250_IDX,
+	ATHOS_B_6G_LUT_CHAN_642375_IDX,
+	ATHOS_B_6G_LUT_CHAN_642500_IDX,
+	ATHOS_B_6G_LUT_CHAN_642625_IDX,
+	ATHOS_B_6G_LUT_CHAN_642750_IDX,
+	ATHOS_B_6G_LUT_CHAN_642875_IDX,
+	ATHOS_B_6G_LUT_CHAN_643000_IDX,
+	ATHOS_B_6G_LUT_CHAN_643125_IDX,
+	ATHOS_B_6G_LUT_CHAN_643250_IDX,
+	ATHOS_B_6G_LUT_CHAN_643375_IDX,
+	ATHOS_B_6G_LUT_CHAN_643500_IDX,
+	ATHOS_B_6G_LUT_CHAN_643625_IDX,
+	ATHOS_B_6G_LUT_CHAN_643750_IDX,
+	ATHOS_B_6G_LUT_CHAN_643875_IDX,
+	ATHOS_B_6G_LUT_CHAN_644000_IDX,
+	ATHOS_B_6G_LUT_CHAN_644125_IDX,
+	ATHOS_B_6G_LUT_CHAN_644250_IDX,
+	ATHOS_B_6G_LUT_CHAN_644375_IDX,
+	ATHOS_B_6G_LUT_CHAN_644500_IDX,
+	ATHOS_B_6G_LUT_CHAN_644625_IDX,
+	ATHOS_B_6G_LUT_CHAN_644750_IDX,
+	ATHOS_B_6G_LUT_CHAN_644875_IDX,
+	ATHOS_B_6G_LUT_CHAN_645000_IDX,
+	ATHOS_B_6G_LUT_CHAN_645125_IDX,
+	ATHOS_B_6G_LUT_CHAN_645250_IDX,
+	ATHOS_B_6G_LUT_CHAN_645375_IDX,
+	ATHOS_B_6G_LUT_CHAN_645500_IDX,
+	ATHOS_B_6G_LUT_CHAN_645625_IDX,
+	ATHOS_B_6G_LUT_CHAN_645750_IDX,
+	ATHOS_B_6G_LUT_CHAN_645875_IDX,
+	ATHOS_B_6G_LUT_CHAN_646000_IDX,
+	ATHOS_B_6G_LUT_CHAN_646125_IDX,
+	ATHOS_B_6G_LUT_CHAN_646250_IDX,
+	ATHOS_B_6G_LUT_CHAN_646375_IDX,
+	ATHOS_B_6G_LUT_CHAN_646500_IDX,
+	ATHOS_B_6G_LUT_CHAN_646625_IDX,
+	ATHOS_B_6G_LUT_CHAN_646750_IDX,
+	ATHOS_B_6G_LUT_CHAN_646875_IDX,
+	ATHOS_B_6G_LUT_CHAN_647000_IDX,
+	ATHOS_B_6G_LUT_CHAN_647125_IDX,
+	ATHOS_B_6G_LUT_CHAN_647250_IDX,
+	ATHOS_B_6G_LUT_CHAN_647375_IDX,
+	ATHOS_B_6G_LUT_CHAN_647500_IDX,
+	ATHOS_B_6G_LUT_CHAN_647625_IDX,
+	ATHOS_B_6G_LUT_CHAN_647750_IDX,
+	ATHOS_B_6G_LUT_CHAN_647875_IDX,
+	ATHOS_B_6G_LUT_CHAN_648000_IDX,
+	ATHOS_B_6G_LUT_CHAN_648125_IDX,
+	ATHOS_B_6G_LUT_CHAN_648250_IDX,
+	ATHOS_B_6G_LUT_CHAN_648375_IDX,
+	ATHOS_B_6G_LUT_CHAN_648500_IDX,
+	ATHOS_B_6G_LUT_CHAN_648625_IDX,
+	ATHOS_B_6G_LUT_CHAN_648750_IDX,
+	ATHOS_B_6G_LUT_CHAN_648875_IDX,
+	ATHOS_B_6G_LUT_CHAN_649000_IDX,
+	ATHOS_B_6G_LUT_CHAN_649125_IDX,
+	ATHOS_B_6G_LUT_CHAN_649250_IDX,
+	ATHOS_B_6G_LUT_CHAN_649375_IDX,
+	ATHOS_B_6G_LUT_CHAN_649500_IDX,
+	ATHOS_B_6G_LUT_CHAN_649625_IDX,
+	ATHOS_B_6G_LUT_CHAN_649750_IDX,
+	ATHOS_B_6G_LUT_CHAN_649875_IDX,
+	ATHOS_B_6G_LUT_CHAN_650000_IDX,
+	ATHOS_B_6G_LUT_CHAN_650125_IDX,
+	ATHOS_B_6G_LUT_CHAN_650250_IDX,
+	ATHOS_B_6G_LUT_CHAN_650375_IDX,
+	ATHOS_B_6G_LUT_CHAN_650500_IDX,
+	ATHOS_B_6G_LUT_CHAN_650625_IDX,
+	ATHOS_B_6G_LUT_CHAN_650750_IDX,
+	ATHOS_B_6G_LUT_CHAN_650875_IDX,
+	ATHOS_B_6G_LUT_CHAN_651000_IDX,
+	ATHOS_B_6G_LUT_CHAN_651125_IDX,
+	ATHOS_B_6G_LUT_CHAN_651250_IDX,
+	ATHOS_B_6G_LUT_CHAN_651375_IDX,
+	ATHOS_B_6G_LUT_CHAN_651500_IDX,
+	ATHOS_B_6G_LUT_CHAN_651625_IDX,
+	ATHOS_B_6G_LUT_CHAN_651750_IDX,
+	ATHOS_B_6G_LUT_CHAN_651875_IDX,
+	ATHOS_B_6G_LUT_CHAN_652000_IDX,
+	ATHOS_B_6G_LUT_CHAN_652125_IDX,
+	ATHOS_B_6G_LUT_CHAN_652250_IDX,
+	ATHOS_B_6G_LUT_CHAN_652375_IDX,
+	ATHOS_B_6G_LUT_CHAN_652500_IDX,
+	ATHOS_B_6G_LUT_CHAN_652625_IDX,
+	ATHOS_B_6G_LUT_CHAN_652750_IDX,
+	ATHOS_B_6G_LUT_CHAN_652875_IDX,
+	ATHOS_B_6G_LUT_CHAN_653000_IDX,
+	ATHOS_B_6G_LUT_CHAN_653125_IDX,
+	ATHOS_B_6G_LUT_CHAN_653250_IDX,
+	ATHOS_B_6G_LUT_CHAN_653375_IDX,
+	ATHOS_B_6G_LUT_CHAN_653500_IDX,
+	ATHOS_B_6G_LUT_CHAN_653625_IDX,
+	ATHOS_B_6G_LUT_CHAN_653750_IDX,
+	ATHOS_B_6G_LUT_CHAN_653875_IDX,
+	ATHOS_B_6G_LUT_CHAN_654000_IDX,
+	ATHOS_B_6G_LUT_CHAN_654125_IDX,
+	ATHOS_B_6G_LUT_CHAN_654250_IDX,
+	ATHOS_B_6G_LUT_CHAN_654375_IDX,
+	ATHOS_B_6G_LUT_CHAN_654500_IDX,
+	ATHOS_B_6G_LUT_CHAN_654625_IDX,
+	ATHOS_B_6G_LUT_CHAN_654750_IDX,
+	ATHOS_B_6G_LUT_CHAN_654875_IDX,
+	ATHOS_B_6G_LUT_CHAN_655000_IDX,
+	ATHOS_B_6G_LUT_CHAN_655125_IDX,
+	ATHOS_B_6G_LUT_CHAN_655250_IDX,
+	ATHOS_B_6G_LUT_CHAN_655375_IDX,
+	ATHOS_B_6G_LUT_CHAN_655500_IDX,
+	ATHOS_B_6G_LUT_CHAN_655625_IDX,
+	ATHOS_B_6G_LUT_CHAN_655750_IDX,
+	ATHOS_B_6G_LUT_CHAN_655875_IDX,
+	ATHOS_B_6G_LUT_CHAN_656000_IDX,
+	ATHOS_B_6G_LUT_CHAN_656125_IDX,
+	ATHOS_B_6G_LUT_CHAN_656250_IDX,
+	ATHOS_B_6G_LUT_CHAN_656375_IDX,
+	ATHOS_B_6G_LUT_CHAN_656500_IDX,
+	ATHOS_B_6G_LUT_CHAN_656625_IDX,
+	ATHOS_B_6G_LUT_CHAN_656750_IDX,
+	ATHOS_B_6G_LUT_CHAN_656875_IDX,
+	ATHOS_B_6G_LUT_CHAN_657000_IDX,
+	ATHOS_B_6G_LUT_CHAN_657125_IDX,
+	ATHOS_B_6G_LUT_CHAN_657250_IDX,
+	ATHOS_B_6G_LUT_CHAN_657375_IDX,
+	ATHOS_B_6G_LUT_CHAN_657500_IDX,
+	ATHOS_B_6G_LUT_CHAN_657625_IDX,
+	ATHOS_B_6G_LUT_CHAN_657750_IDX,
+	ATHOS_B_6G_LUT_CHAN_657875_IDX,
+	ATHOS_B_6G_LUT_CHAN_658000_IDX,
+	ATHOS_B_6G_LUT_CHAN_658125_IDX,
+	ATHOS_B_6G_LUT_CHAN_658250_IDX,
+	ATHOS_B_6G_LUT_CHAN_658375_IDX,
+	ATHOS_B_6G_LUT_CHAN_658500_IDX,
+	ATHOS_B_6G_LUT_CHAN_658625_IDX,
+	ATHOS_B_6G_LUT_CHAN_658750_IDX,
+	ATHOS_B_6G_LUT_CHAN_658875_IDX,
+	ATHOS_B_6G_LUT_CHAN_659000_IDX,
+	ATHOS_B_6G_LUT_CHAN_659125_IDX,
+	ATHOS_B_6G_LUT_CHAN_659250_IDX,
+	ATHOS_B_6G_LUT_CHAN_659375_IDX,
+	ATHOS_B_6G_LUT_CHAN_659500_IDX,
+	ATHOS_B_6G_LUT_CHAN_659625_IDX,
+	ATHOS_B_6G_LUT_CHAN_659750_IDX,
+	ATHOS_B_6G_LUT_CHAN_659875_IDX,
+	ATHOS_B_6G_LUT_CHAN_660000_IDX,
+	ATHOS_B_6G_LUT_CHAN_660125_IDX,
+	ATHOS_B_6G_LUT_CHAN_660250_IDX,
+	ATHOS_B_6G_LUT_CHAN_660375_IDX,
+	ATHOS_B_6G_LUT_CHAN_660500_IDX,
+	ATHOS_B_6G_LUT_CHAN_660625_IDX,
+	ATHOS_B_6G_LUT_CHAN_660750_IDX,
+	ATHOS_B_6G_LUT_CHAN_660875_IDX,
+	ATHOS_B_6G_LUT_CHAN_661000_IDX,
+	ATHOS_B_6G_LUT_CHAN_661125_IDX,
+	ATHOS_B_6G_LUT_CHAN_661250_IDX,
+	ATHOS_B_6G_LUT_CHAN_661375_IDX,
+	ATHOS_B_6G_LUT_CHAN_661500_IDX,
+	ATHOS_B_6G_LUT_CHAN_661625_IDX,
+	ATHOS_B_6G_LUT_CHAN_661750_IDX,
+	ATHOS_B_6G_LUT_CHAN_661875_IDX,
+	ATHOS_B_6G_LUT_CHAN_662000_IDX,
+	ATHOS_B_6G_LUT_CHAN_662125_IDX,
+	ATHOS_B_6G_LUT_CHAN_662250_IDX,
+	ATHOS_B_6G_LUT_CHAN_662375_IDX,
+	ATHOS_B_6G_LUT_CHAN_662500_IDX,
+	ATHOS_B_6G_LUT_CHAN_662625_IDX,
+	ATHOS_B_6G_LUT_CHAN_662750_IDX,
+	ATHOS_B_6G_LUT_CHAN_662875_IDX,
+	ATHOS_B_6G_LUT_CHAN_663000_IDX,
+	ATHOS_B_6G_LUT_CHAN_663125_IDX,
+	ATHOS_B_6G_LUT_CHAN_663250_IDX,
+	ATHOS_B_6G_LUT_CHAN_663375_IDX,
+	ATHOS_B_6G_LUT_CHAN_663500_IDX,
+	ATHOS_B_6G_LUT_CHAN_663625_IDX,
+	ATHOS_B_6G_LUT_CHAN_663750_IDX,
+	ATHOS_B_6G_LUT_CHAN_663875_IDX,
+	ATHOS_B_6G_LUT_CHAN_664000_IDX,
+	ATHOS_B_6G_LUT_CHAN_664125_IDX,
+	ATHOS_B_6G_LUT_CHAN_664250_IDX,
+	ATHOS_B_6G_LUT_CHAN_664375_IDX,
+	ATHOS_B_6G_LUT_CHAN_664500_IDX,
+	ATHOS_B_6G_LUT_CHAN_664625_IDX,
+	ATHOS_B_6G_LUT_CHAN_664750_IDX,
+	ATHOS_B_6G_LUT_CHAN_664875_IDX,
+	ATHOS_B_6G_LUT_CHAN_665000_IDX,
+	ATHOS_B_6G_LUT_CHAN_665125_IDX,
+	ATHOS_B_6G_LUT_CHAN_665250_IDX,
+	ATHOS_B_6G_LUT_CHAN_665375_IDX,
+	ATHOS_B_6G_LUT_CHAN_665500_IDX,
+	ATHOS_B_6G_LUT_CHAN_665625_IDX,
+	ATHOS_B_6G_LUT_CHAN_665750_IDX,
+	ATHOS_B_6G_LUT_CHAN_665875_IDX,
+	ATHOS_B_6G_LUT_CHAN_666000_IDX,
+	ATHOS_B_6G_LUT_CHAN_666125_IDX,
+	ATHOS_B_6G_LUT_CHAN_666250_IDX,
+	ATHOS_B_6G_LUT_CHAN_666375_IDX,
+	ATHOS_B_6G_LUT_CHAN_666500_IDX,
+	ATHOS_B_6G_LUT_CHAN_666625_IDX,
+	ATHOS_B_6G_LUT_CHAN_666750_IDX,
+	ATHOS_B_6G_LUT_CHAN_666875_IDX,
+	ATHOS_B_6G_LUT_CHAN_667000_IDX,
+	ATHOS_B_6G_LUT_CHAN_667125_IDX,
+	ATHOS_B_6G_LUT_CHAN_667250_IDX,
+	ATHOS_B_6G_LUT_CHAN_667375_IDX,
+	ATHOS_B_6G_LUT_CHAN_667500_IDX,
+	ATHOS_B_6G_LUT_CHAN_667625_IDX,
+	ATHOS_B_6G_LUT_CHAN_667750_IDX,
+	ATHOS_B_6G_LUT_CHAN_667875_IDX,
+	ATHOS_B_6G_LUT_CHAN_668000_IDX,
+	ATHOS_B_6G_LUT_CHAN_668125_IDX,
+	ATHOS_B_6G_LUT_CHAN_668250_IDX,
+	ATHOS_B_6G_LUT_CHAN_668375_IDX,
+	ATHOS_B_6G_LUT_CHAN_668500_IDX,
+	ATHOS_B_6G_LUT_CHAN_668625_IDX,
+	ATHOS_B_6G_LUT_CHAN_668750_IDX,
+	ATHOS_B_6G_LUT_CHAN_668875_IDX,
+	ATHOS_B_6G_LUT_CHAN_669000_IDX,
+	ATHOS_B_6G_LUT_CHAN_669125_IDX,
+	ATHOS_B_6G_LUT_CHAN_669250_IDX,
+	ATHOS_B_6G_LUT_CHAN_669375_IDX,
+	ATHOS_B_6G_LUT_CHAN_669500_IDX,
+	ATHOS_B_6G_LUT_CHAN_669625_IDX,
+	ATHOS_B_6G_LUT_CHAN_669750_IDX,
+	ATHOS_B_6G_LUT_CHAN_669875_IDX,
+	ATHOS_B_6G_LUT_CHAN_670000_IDX,
+	ATHOS_B_6G_LUT_CHAN_670125_IDX,
+	ATHOS_B_6G_LUT_CHAN_670250_IDX,
+	ATHOS_B_6G_LUT_CHAN_670375_IDX,
+	ATHOS_B_6G_LUT_CHAN_670500_IDX,
+	ATHOS_B_6G_LUT_CHAN_670625_IDX,
+	ATHOS_B_6G_LUT_CHAN_670750_IDX,
+	ATHOS_B_6G_LUT_CHAN_670875_IDX,
+	ATHOS_B_6G_LUT_CHAN_671000_IDX,
+	ATHOS_B_6G_LUT_CHAN_671125_IDX,
+	ATHOS_B_6G_LUT_CHAN_671250_IDX,
+	ATHOS_B_6G_LUT_CHAN_671375_IDX,
+	ATHOS_B_6G_LUT_CHAN_671500_IDX,
+	ATHOS_B_6G_LUT_CHAN_671625_IDX,
+	ATHOS_B_6G_LUT_CHAN_671750_IDX,
+	ATHOS_B_6G_LUT_CHAN_671875_IDX,
+	ATHOS_B_6G_LUT_CHAN_672000_IDX,
+	ATHOS_B_6G_LUT_CHAN_672125_IDX,
+	ATHOS_B_6G_LUT_CHAN_672250_IDX,
+	ATHOS_B_6G_LUT_CHAN_672375_IDX,
+	ATHOS_B_6G_LUT_CHAN_672500_IDX,
+	ATHOS_B_6G_LUT_CHAN_672625_IDX,
+	ATHOS_B_6G_LUT_CHAN_672750_IDX,
+	ATHOS_B_6G_LUT_CHAN_672875_IDX,
+	ATHOS_B_6G_LUT_CHAN_673000_IDX,
+	ATHOS_B_6G_LUT_CHAN_673125_IDX,
+	ATHOS_B_6G_LUT_CHAN_673250_IDX,
+	ATHOS_B_6G_LUT_CHAN_673375_IDX,
+	ATHOS_B_6G_LUT_CHAN_673500_IDX,
+	ATHOS_B_6G_LUT_CHAN_673625_IDX,
+	ATHOS_B_6G_LUT_CHAN_673750_IDX,
+	ATHOS_B_6G_LUT_CHAN_673875_IDX,
+	ATHOS_B_6G_LUT_CHAN_674000_IDX,
+	ATHOS_B_6G_LUT_CHAN_674125_IDX,
+	ATHOS_B_6G_LUT_CHAN_674250_IDX,
+	ATHOS_B_6G_LUT_CHAN_674375_IDX,
+	ATHOS_B_6G_LUT_CHAN_674500_IDX,
+	ATHOS_B_6G_LUT_CHAN_674625_IDX,
+	ATHOS_B_6G_LUT_CHAN_674750_IDX,
+	ATHOS_B_6G_LUT_CHAN_674875_IDX,
+	ATHOS_B_6G_LUT_CHAN_675000_IDX,
+	ATHOS_B_6G_LUT_CHAN_675125_IDX,
+	ATHOS_B_6G_LUT_CHAN_675250_IDX,
+	ATHOS_B_6G_LUT_CHAN_675375_IDX,
+	ATHOS_B_6G_LUT_CHAN_675500_IDX,
+	ATHOS_B_6G_LUT_CHAN_675625_IDX,
+	ATHOS_B_6G_LUT_CHAN_675750_IDX,
+	ATHOS_B_6G_LUT_CHAN_675875_IDX,
+	ATHOS_B_6G_LUT_CHAN_676000_IDX,
+	ATHOS_B_6G_LUT_CHAN_676125_IDX,
+	ATHOS_B_6G_LUT_CHAN_676250_IDX,
+	ATHOS_B_6G_LUT_CHAN_676375_IDX,
+	ATHOS_B_6G_LUT_CHAN_676500_IDX,
+	ATHOS_B_6G_LUT_CHAN_676625_IDX,
+	ATHOS_B_6G_LUT_CHAN_676750_IDX,
+	ATHOS_B_6G_LUT_CHAN_676875_IDX,
+	ATHOS_B_6G_LUT_CHAN_677000_IDX,
+	ATHOS_B_6G_LUT_CHAN_677125_IDX,
+	ATHOS_B_6G_LUT_CHAN_677250_IDX,
+	ATHOS_B_6G_LUT_CHAN_677375_IDX,
+	ATHOS_B_6G_LUT_CHAN_677500_IDX,
+	ATHOS_B_6G_LUT_CHAN_677625_IDX,
+	ATHOS_B_6G_LUT_CHAN_677750_IDX,
+	ATHOS_B_6G_LUT_CHAN_677875_IDX,
+	ATHOS_B_6G_LUT_CHAN_678000_IDX,
+	ATHOS_B_6G_LUT_CHAN_678125_IDX,
+	ATHOS_B_6G_LUT_CHAN_678250_IDX,
+	ATHOS_B_6G_LUT_CHAN_678375_IDX,
+	ATHOS_B_6G_LUT_CHAN_678500_IDX,
+	ATHOS_B_6G_LUT_CHAN_678625_IDX,
+	ATHOS_B_6G_LUT_CHAN_678750_IDX,
+	ATHOS_B_6G_LUT_CHAN_678875_IDX,
+	ATHOS_B_6G_LUT_CHAN_679000_IDX,
+	ATHOS_B_6G_LUT_CHAN_679125_IDX,
+	ATHOS_B_6G_LUT_CHAN_679250_IDX,
+	ATHOS_B_6G_LUT_CHAN_679375_IDX,
+	ATHOS_B_6G_LUT_CHAN_679500_IDX,
+	ATHOS_B_6G_LUT_CHAN_679625_IDX,
+	ATHOS_B_6G_LUT_CHAN_679750_IDX,
+	ATHOS_B_6G_LUT_CHAN_679875_IDX,
+	ATHOS_B_6G_LUT_CHAN_680000_IDX,
+	ATHOS_B_6G_LUT_CHAN_680125_IDX,
+	ATHOS_B_6G_LUT_CHAN_680250_IDX,
+	ATHOS_B_6G_LUT_CHAN_680375_IDX,
+	ATHOS_B_6G_LUT_CHAN_680500_IDX,
+	ATHOS_B_6G_LUT_CHAN_680625_IDX,
+	ATHOS_B_6G_LUT_CHAN_680750_IDX,
+	ATHOS_B_6G_LUT_CHAN_680875_IDX,
+	ATHOS_B_6G_LUT_CHAN_681000_IDX,
+	ATHOS_B_6G_LUT_CHAN_681125_IDX,
+	ATHOS_B_6G_LUT_CHAN_681250_IDX,
+	ATHOS_B_6G_LUT_CHAN_681375_IDX,
+	ATHOS_B_6G_LUT_CHAN_681500_IDX,
+	ATHOS_B_6G_LUT_CHAN_681625_IDX,
+	ATHOS_B_6G_LUT_CHAN_681750_IDX,
+	ATHOS_B_6G_LUT_CHAN_681875_IDX,
+	ATHOS_B_6G_LUT_CHAN_682000_IDX,
+	ATHOS_B_6G_LUT_CHAN_682125_IDX,
+	ATHOS_B_6G_LUT_CHAN_682250_IDX,
+	ATHOS_B_6G_LUT_CHAN_682375_IDX,
+	ATHOS_B_6G_LUT_CHAN_682500_IDX,
+	ATHOS_B_6G_LUT_CHAN_682625_IDX,
+	ATHOS_B_6G_LUT_CHAN_682750_IDX,
+	ATHOS_B_6G_LUT_CHAN_682875_IDX,
+	ATHOS_B_6G_LUT_CHAN_683000_IDX,
+	ATHOS_B_6G_LUT_CHAN_683125_IDX,
+	ATHOS_B_6G_LUT_CHAN_683250_IDX,
+	ATHOS_B_6G_LUT_CHAN_683375_IDX,
+	ATHOS_B_6G_LUT_CHAN_683500_IDX,
+	ATHOS_B_6G_LUT_CHAN_683625_IDX,
+	ATHOS_B_6G_LUT_CHAN_683750_IDX,
+	ATHOS_B_6G_LUT_CHAN_683875_IDX,
+	ATHOS_B_6G_LUT_CHAN_684000_IDX,
+	ATHOS_B_6G_LUT_CHAN_684125_IDX,
+	ATHOS_B_6G_LUT_CHAN_684250_IDX,
+	ATHOS_B_6G_LUT_CHAN_684375_IDX,
+	ATHOS_B_6G_LUT_CHAN_684500_IDX,
+	ATHOS_B_6G_LUT_CHAN_684625_IDX,
+	ATHOS_B_6G_LUT_CHAN_684750_IDX,
+	ATHOS_B_6G_LUT_CHAN_684875_IDX,
+	ATHOS_B_6G_LUT_CHAN_685000_IDX,
+	ATHOS_B_6G_LUT_CHAN_685125_IDX,
+	ATHOS_B_6G_LUT_CHAN_685250_IDX,
+	ATHOS_B_6G_LUT_CHAN_685375_IDX,
+	ATHOS_B_6G_LUT_CHAN_685500_IDX,
+	ATHOS_B_6G_LUT_CHAN_685625_IDX,
+	ATHOS_B_6G_LUT_CHAN_685750_IDX,
+	ATHOS_B_6G_LUT_CHAN_685875_IDX,
+	ATHOS_B_6G_LUT_CHAN_686000_IDX,
+	ATHOS_B_6G_LUT_CHAN_686125_IDX,
+	ATHOS_B_6G_LUT_CHAN_686250_IDX,
+	ATHOS_B_6G_LUT_CHAN_686375_IDX,
+	ATHOS_B_6G_LUT_CHAN_686500_IDX,
+	ATHOS_B_6G_LUT_CHAN_686625_IDX,
+	ATHOS_B_6G_LUT_CHAN_686750_IDX,
+	ATHOS_B_6G_LUT_CHAN_686875_IDX,
+	ATHOS_B_6G_LUT_CHAN_687000_IDX,
+	ATHOS_B_6G_LUT_CHAN_687125_IDX,
+	ATHOS_B_6G_LUT_CHAN_687250_IDX,
+	ATHOS_B_6G_LUT_CHAN_687375_IDX,
+	ATHOS_B_6G_LUT_CHAN_687500_IDX,
+	ATHOS_B_6G_LUT_CHAN_687625_IDX,
+	ATHOS_B_6G_LUT_CHAN_687750_IDX,
+	ATHOS_B_6G_LUT_CHAN_687875_IDX,
+	ATHOS_B_6G_LUT_CHAN_688000_IDX,
+	ATHOS_B_6G_LUT_CHAN_688125_IDX,
+	ATHOS_B_6G_LUT_CHAN_688250_IDX,
+	ATHOS_B_6G_LUT_CHAN_688375_IDX,
+	ATHOS_B_6G_LUT_CHAN_688500_IDX,
+	ATHOS_B_6G_LUT_CHAN_688625_IDX,
+	ATHOS_B_6G_LUT_CHAN_688750_IDX,
+	ATHOS_B_6G_LUT_CHAN_688875_IDX,
+	ATHOS_B_6G_LUT_CHAN_689000_IDX,
+	ATHOS_B_6G_LUT_CHAN_689125_IDX,
+	ATHOS_B_6G_LUT_CHAN_689250_IDX,
+	ATHOS_B_6G_LUT_CHAN_689375_IDX,
+	ATHOS_B_6G_LUT_CHAN_689500_IDX,
+	ATHOS_B_6G_LUT_CHAN_689625_IDX,
+	ATHOS_B_6G_LUT_CHAN_689750_IDX,
+	ATHOS_B_6G_LUT_CHAN_689875_IDX,
+	ATHOS_B_6G_LUT_CHAN_690000_IDX,
+	ATHOS_B_6G_LUT_CHAN_690125_IDX,
+	ATHOS_B_6G_LUT_CHAN_690250_IDX,
+	ATHOS_B_6G_LUT_CHAN_690375_IDX,
+	ATHOS_B_6G_LUT_CHAN_690500_IDX,
+	ATHOS_B_6G_LUT_CHAN_690625_IDX,
+	ATHOS_B_6G_LUT_CHAN_690750_IDX,
+	ATHOS_B_6G_LUT_CHAN_690875_IDX,
+	ATHOS_B_6G_LUT_CHAN_691000_IDX,
+	ATHOS_B_6G_LUT_CHAN_691125_IDX,
+	ATHOS_B_6G_LUT_CHAN_691250_IDX,
+	ATHOS_B_6G_LUT_CHAN_691375_IDX,
+	ATHOS_B_6G_LUT_CHAN_691500_IDX,
+	ATHOS_B_6G_LUT_CHAN_691625_IDX,
+	ATHOS_B_6G_LUT_CHAN_691750_IDX,
+	ATHOS_B_6G_LUT_CHAN_691875_IDX,
+	ATHOS_B_6G_LUT_CHAN_692000_IDX,
+	ATHOS_B_6G_LUT_CHAN_692125_IDX,
+	ATHOS_B_6G_LUT_CHAN_692250_IDX,
+	ATHOS_B_6G_LUT_CHAN_692375_IDX,
+	ATHOS_B_6G_LUT_CHAN_692500_IDX,
+	ATHOS_B_6G_LUT_CHAN_692625_IDX,
+	ATHOS_B_6G_LUT_CHAN_692750_IDX,
+	ATHOS_B_6G_LUT_CHAN_692875_IDX,
+	ATHOS_B_6G_LUT_CHAN_693000_IDX,
+	ATHOS_B_6G_LUT_CHAN_693125_IDX,
+	ATHOS_B_6G_LUT_CHAN_693250_IDX,
+	ATHOS_B_6G_LUT_CHAN_693375_IDX,
+	ATHOS_B_6G_LUT_CHAN_693500_IDX,
+	ATHOS_B_6G_LUT_CHAN_693625_IDX,
+	ATHOS_B_6G_LUT_CHAN_693750_IDX,
+	ATHOS_B_6G_LUT_CHAN_693875_IDX,
+	ATHOS_B_6G_LUT_CHAN_694000_IDX,
+	ATHOS_B_6G_LUT_CHAN_694125_IDX,
+	ATHOS_B_6G_LUT_CHAN_694250_IDX,
+	ATHOS_B_6G_LUT_CHAN_694375_IDX,
+	ATHOS_B_6G_LUT_CHAN_694500_IDX,
+	ATHOS_B_6G_LUT_CHAN_694625_IDX,
+	ATHOS_B_6G_LUT_CHAN_694750_IDX,
+	ATHOS_B_6G_LUT_CHAN_694875_IDX,
+	ATHOS_B_6G_LUT_CHAN_695000_IDX,
+	ATHOS_B_6G_LUT_CHAN_695125_IDX,
+	ATHOS_B_6G_LUT_CHAN_695250_IDX,
+	ATHOS_B_6G_LUT_CHAN_695375_IDX,
+	ATHOS_B_6G_LUT_CHAN_695500_IDX,
+	ATHOS_B_6G_LUT_CHAN_695625_IDX,
+	ATHOS_B_6G_LUT_CHAN_695750_IDX,
+	ATHOS_B_6G_LUT_CHAN_695875_IDX,
+	ATHOS_B_6G_LUT_CHAN_696000_IDX,
+	ATHOS_B_6G_LUT_CHAN_696125_IDX,
+	ATHOS_B_6G_LUT_CHAN_696250_IDX,
+	ATHOS_B_6G_LUT_CHAN_696375_IDX,
+	ATHOS_B_6G_LUT_CHAN_696500_IDX,
+	ATHOS_B_6G_LUT_CHAN_696625_IDX,
+	ATHOS_B_6G_LUT_CHAN_696750_IDX,
+	ATHOS_B_6G_LUT_CHAN_696875_IDX,
+	ATHOS_B_6G_LUT_CHAN_697000_IDX,
+	ATHOS_B_6G_LUT_CHAN_697125_IDX,
+	ATHOS_B_6G_LUT_CHAN_697250_IDX,
+	ATHOS_B_6G_LUT_CHAN_697375_IDX,
+	ATHOS_B_6G_LUT_CHAN_697500_IDX,
+	ATHOS_B_6G_LUT_CHAN_697625_IDX,
+	ATHOS_B_6G_LUT_CHAN_697750_IDX,
+	ATHOS_B_6G_LUT_CHAN_697875_IDX,
+	ATHOS_B_6G_LUT_CHAN_698000_IDX,
+	ATHOS_B_6G_LUT_CHAN_698125_IDX,
+	ATHOS_B_6G_LUT_CHAN_698250_IDX,
+	ATHOS_B_6G_LUT_CHAN_698375_IDX,
+	ATHOS_B_6G_LUT_CHAN_698500_IDX,
+	ATHOS_B_6G_LUT_CHAN_698625_IDX,
+	ATHOS_B_6G_LUT_CHAN_698750_IDX,
+	ATHOS_B_6G_LUT_CHAN_698875_IDX,
+	ATHOS_B_6G_LUT_CHAN_699000_IDX,
+	ATHOS_B_6G_LUT_CHAN_699125_IDX,
+	ATHOS_B_6G_LUT_CHAN_699250_IDX,
+	ATHOS_B_6G_LUT_CHAN_699375_IDX,
+	ATHOS_B_6G_LUT_CHAN_699500_IDX,
+	ATHOS_B_6G_LUT_CHAN_699625_IDX,
+	ATHOS_B_6G_LUT_CHAN_699750_IDX,
+	ATHOS_B_6G_LUT_CHAN_699875_IDX,
+	ATHOS_B_6G_LUT_CHAN_700000_IDX,
+	ATHOS_B_6G_LUT_CHAN_700125_IDX,
+	ATHOS_B_6G_LUT_CHAN_700250_IDX,
+	ATHOS_B_6G_LUT_CHAN_700375_IDX,
+	ATHOS_B_6G_LUT_CHAN_700500_IDX,
+	ATHOS_B_6G_LUT_CHAN_700625_IDX,
+	ATHOS_B_6G_LUT_CHAN_700750_IDX,
+	ATHOS_B_6G_LUT_CHAN_700875_IDX,
+	ATHOS_B_6G_LUT_CHAN_701000_IDX,
+	ATHOS_B_6G_LUT_CHAN_701125_IDX,
+	ATHOS_B_6G_LUT_CHAN_701250_IDX,
+	ATHOS_B_6G_LUT_CHAN_701375_IDX,
+	ATHOS_B_6G_LUT_CHAN_701500_IDX,
+	ATHOS_B_6G_LUT_CHAN_701625_IDX,
+	ATHOS_B_6G_LUT_CHAN_701750_IDX,
+	ATHOS_B_6G_LUT_CHAN_701875_IDX,
+	ATHOS_B_6G_LUT_CHAN_702000_IDX,
+	ATHOS_B_6G_LUT_CHAN_702125_IDX,
+	ATHOS_B_6G_LUT_CHAN_702250_IDX,
+	ATHOS_B_6G_LUT_CHAN_702375_IDX,
+	ATHOS_B_6G_LUT_CHAN_702500_IDX,
+	ATHOS_B_6G_LUT_CHAN_702625_IDX,
+	ATHOS_B_6G_LUT_CHAN_702750_IDX,
+	ATHOS_B_6G_LUT_CHAN_702875_IDX,
+	ATHOS_B_6G_LUT_CHAN_703000_IDX,
+	ATHOS_B_6G_LUT_CHAN_703125_IDX,
+	ATHOS_B_6G_LUT_CHAN_703250_IDX,
+	ATHOS_B_6G_LUT_CHAN_703375_IDX,
+	ATHOS_B_6G_LUT_CHAN_703500_IDX,
+	ATHOS_B_6G_LUT_CHAN_703625_IDX,
+	ATHOS_B_6G_LUT_CHAN_703750_IDX,
+	ATHOS_B_6G_LUT_CHAN_703875_IDX,
+	ATHOS_B_6G_LUT_CHAN_704000_IDX,
+	ATHOS_B_6G_LUT_CHAN_704125_IDX,
+	ATHOS_B_6G_LUT_CHAN_704250_IDX,
+	ATHOS_B_6G_LUT_CHAN_704375_IDX,
+	ATHOS_B_6G_LUT_CHAN_704500_IDX,
+	ATHOS_B_6G_LUT_CHAN_704625_IDX,
+	ATHOS_B_6G_LUT_CHAN_704750_IDX,
+	ATHOS_B_6G_LUT_CHAN_704875_IDX,
+	ATHOS_B_6G_LUT_CHAN_705000_IDX,
+	ATHOS_B_6G_LUT_CHAN_705125_IDX,
+	ATHOS_B_6G_LUT_CHAN_705250_IDX,
+	ATHOS_B_6G_LUT_CHAN_705375_IDX,
+	ATHOS_B_6G_LUT_CHAN_705500_IDX,
+	ATHOS_B_6G_LUT_CHAN_705625_IDX,
+	ATHOS_B_6G_LUT_CHAN_705750_IDX,
+	ATHOS_B_6G_LUT_CHAN_705875_IDX,
+	ATHOS_B_6G_LUT_CHAN_706000_IDX,
+	ATHOS_B_6G_LUT_CHAN_706125_IDX,
+	ATHOS_B_6G_LUT_CHAN_706250_IDX,
+	ATHOS_B_6G_LUT_CHAN_706375_IDX,
+	ATHOS_B_6G_LUT_CHAN_706500_IDX,
+	ATHOS_B_6G_LUT_CHAN_706625_IDX,
+	ATHOS_B_6G_LUT_CHAN_706750_IDX,
+	ATHOS_B_6G_LUT_CHAN_706875_IDX,
+	ATHOS_B_6G_LUT_CHAN_707000_IDX,
+	ATHOS_B_6G_LUT_CHAN_707125_IDX,
+	ATHOS_B_6G_LUT_CHAN_707250_IDX,
+	ATHOS_B_6G_LUT_CHAN_707375_IDX,
+	ATHOS_B_6G_LUT_CHAN_707500_IDX,
+	ATHOS_B_6G_LUT_CHAN_707625_IDX,
+	ATHOS_B_6G_LUT_CHAN_707750_IDX,
+	ATHOS_B_6G_LUT_CHAN_707875_IDX,
+	ATHOS_B_6G_LUT_CHAN_708000_IDX,
+	ATHOS_B_6G_LUT_CHAN_708125_IDX,
+	ATHOS_B_6G_LUT_CHAN_708250_IDX,
+	ATHOS_B_6G_LUT_CHAN_708375_IDX,
+	ATHOS_B_6G_LUT_CHAN_708500_IDX,
+	ATHOS_B_6G_LUT_CHAN_708625_IDX,
+	ATHOS_B_6G_LUT_CHAN_708750_IDX,
+	ATHOS_B_6G_LUT_CHAN_708875_IDX,
+	ATHOS_B_6G_LUT_CHAN_709000_IDX,
+	ATHOS_B_6G_LUT_CHAN_709125_IDX,
+	ATHOS_B_6G_LUT_CHAN_709250_IDX,
+	ATHOS_B_6G_LUT_CHAN_709375_IDX,
+	ATHOS_B_6G_LUT_CHAN_709500_IDX,
+	ATHOS_B_6G_LUT_CHAN_709625_IDX,
+	ATHOS_B_6G_LUT_CHAN_709750_IDX,
+	ATHOS_B_6G_LUT_CHAN_709875_IDX,
+	ATHOS_B_6G_LUT_CHAN_710000_IDX,
+	ATHOS_B_6G_LUT_CHAN_710125_IDX,
+	ATHOS_B_6G_LUT_CHAN_710250_IDX,
+	ATHOS_B_6G_LUT_CHAN_710375_IDX,
+	ATHOS_B_6G_LUT_CHAN_710500_IDX,
+	ATHOS_B_6G_LUT_CHAN_710625_IDX,
+	ATHOS_B_6G_LUT_CHAN_710750_IDX,
+	ATHOS_B_6G_LUT_CHAN_710875_IDX,
+	ATHOS_B_6G_LUT_CHAN_711000_IDX,
+	ATHOS_B_6G_LUT_CHAN_711125_IDX,
+	ATHOS_B_6G_LUT_CHAN_711250_IDX,
+	ATHOS_B_6G_LUT_CHAN_711375_IDX,
+	ATHOS_B_6G_LUT_CHAN_711500_IDX,
+	ATHOS_B_6G_LUT_CHAN_711625_IDX,
+	ATHOS_B_6G_LUT_CHAN_711750_IDX,
+	ATHOS_B_6G_LUT_CHAN_711875_IDX,
+	ATHOS_B_6G_LUT_CHAN_712000_IDX,
+	ATHOS_B_6G_LUT_CHAN_712125_IDX,
+	ATHOS_B_6G_LUT_CHAN_712250_IDX,
+	ATHOS_B_6G_LUT_CHAN_712375_IDX,
+	ATHOS_B_6G_LUT_CHAN_712500_IDX,
+	ATHOS_B_6G_LUT_CHAN_712625_IDX,
+	ATHOS_B_6G_LUT_CHAN_712750_IDX,
+	ATHOS_B_6G_LUT_CHAN_712875_IDX,
+	ATHOS_B_6G_LUT_CHAN_713000_IDX,
+	ATHOS_B_6G_LUT_CHAN_713125_IDX,
+	ATHOS_B_6G_LUT_CHAN_713250_IDX,
+	ATHOS_B_6G_LUT_CHAN_713375_IDX,
+	ATHOS_B_6G_LUT_CHAN_713500_IDX,
+	ATHOS_B_6G_LUT_CHAN_713625_IDX,
+	ATHOS_B_6G_LUT_CHAN_713750_IDX,
+	ATHOS_B_6G_LUT_CHAN_713875_IDX,
+	ATHOS_B_6G_LUT_CHAN_714000_IDX,
+	ATHOS_B_6G_LUT_CHAN_714125_IDX,
+	ATHOS_B_6G_LUT_CHAN_714250_IDX,
+	ATHOS_B_6G_LUT_CHAN_714375_IDX,
+	ATHOS_B_6G_LUT_CHAN_714500_IDX,
+	ATHOS_B_6G_LUT_CHAN_714625_IDX,
+	ATHOS_B_6G_LUT_CHAN_714750_IDX,
+	ATHOS_B_6G_LUT_CHAN_714875_IDX,
+	ATHOS_B_6G_LUT_CHAN_715000_IDX,
+	ATHOS_B_6G_LUT_CHAN_715125_IDX,
+	ATHOS_B_6G_LUT_CHAN_715250_IDX,
+	ATHOS_B_6G_LUT_CHAN_715375_IDX,
+	ATHOS_B_6G_LUT_CHAN_715500_IDX,
+	ATHOS_B_6G_LUT_CHAN_715625_IDX,
+	ATHOS_B_6G_LUT_CHAN_715750_IDX,
+	ATHOS_B_6G_LUT_CHAN_715875_IDX,
+	ATHOS_B_6G_LUT_CHAN_716000_IDX,
+	ATHOS_B_6G_LUT_CHAN_716125_IDX,
+	ATHOS_B_6G_LUT_CHAN_716250_IDX,
+	ATHOS_B_6G_LUT_CHAN_716375_IDX,
+	ATHOS_B_6G_LUT_CHAN_716500_IDX,
+	ATHOS_B_6G_LUT_CHAN_716625_IDX,
+	ATHOS_B_6G_LUT_CHAN_716750_IDX,
+	ATHOS_B_6G_LUT_CHAN_716875_IDX,
+	ATHOS_B_6G_LUT_CHAN_717000_IDX,
+	ATHOS_B_6G_LUT_CHAN_717125_IDX,
+	ATHOS_B_6G_LUT_CHAN_717250_IDX,
+	ATHOS_B_6G_LUT_CHAN_717375_IDX,
+	ATHOS_B_6G_LUT_CHAN_717500_IDX,
+	ATHOS_B_6G_LUT_CHAN_717625_IDX,
+	ATHOS_B_6G_LUT_CHAN_717750_IDX,
+	ATHOS_B_6G_LUT_CHAN_717875_IDX,
+	ATHOS_B_6G_LUT_CHAN_718000_IDX,
+	ATHOS_B_6G_LUT_CHAN_718125_IDX,
+	ATHOS_B_6G_LUT_CHAN_718250_IDX,
+	ATHOS_B_6G_LUT_CHAN_718375_IDX,
+	ATHOS_B_6G_LUT_CHAN_718500_IDX,
+	ATHOS_B_6G_LUT_CHAN_718625_IDX,
+	ATHOS_B_6G_LUT_CHAN_718750_IDX,
+	ATHOS_B_6G_LUT_CHAN_718875_IDX,
+	ATHOS_B_6G_LUT_CHAN_719000_IDX,
+	ATHOS_B_6G_LUT_CHAN_719125_IDX,
+	ATHOS_B_6G_LUT_CHAN_719250_IDX,
+	ATHOS_B_6G_LUT_CHAN_719375_IDX,
+	ATHOS_B_6G_LUT_CHAN_719500_IDX,
+	ATHOS_B_6G_LUT_CHAN_719625_IDX,
+	ATHOS_B_6G_LUT_CHAN_719750_IDX,
+	ATHOS_B_6G_LUT_CHAN_719875_IDX,
+	ATHOS_B_6G_LUT_CHAN_720000_IDX,
+	ATHOS_B_6G_LUT_CHAN_720125_IDX,
+	ATHOS_B_6G_LUT_CHAN_720250_IDX,
+	ATHOS_B_6G_LUT_CHAN_720375_IDX,
+	ATHOS_B_6G_LUT_CHAN_720500_IDX,
+	ATHOS_B_6G_LUT_CHAN_720625_IDX,
+	ATHOS_B_6G_LUT_CHAN_720750_IDX,
+	ATHOS_B_6G_LUT_CHAN_720875_IDX,
+	ATHOS_B_6G_LUT_CHAN_721000_IDX,
+	ATHOS_B_6G_LUT_CHAN_721125_IDX,
+	ATHOS_B_6G_LUT_CHAN_721250_IDX,
+	ATHOS_B_6G_LUT_CHAN_721375_IDX,
+	ATHOS_B_6G_LUT_CHAN_721500_IDX,
+	ATHOS_B_6G_LUT_CHAN_6G_MAX
+};
+
+enum olympus_lut_idx_5g {
+	OLYMPUS_LUT_CHAN_516000_IDX,
+	OLYMPUS_LUT_CHAN_516125_IDX,
+	OLYMPUS_LUT_CHAN_516250_IDX,
+	OLYMPUS_LUT_CHAN_516375_IDX,
+	OLYMPUS_LUT_CHAN_516500_IDX,
+	OLYMPUS_LUT_CHAN_516625_IDX,
+	OLYMPUS_LUT_CHAN_516750_IDX,
+	OLYMPUS_LUT_CHAN_516875_IDX,
+	OLYMPUS_LUT_CHAN_517000_IDX,
+	OLYMPUS_LUT_CHAN_517125_IDX,
+	OLYMPUS_LUT_CHAN_517250_IDX,
+	OLYMPUS_LUT_CHAN_517375_IDX,
+	OLYMPUS_LUT_CHAN_517500_IDX,
+	OLYMPUS_LUT_CHAN_517625_IDX,
+	OLYMPUS_LUT_CHAN_517750_IDX,
+	OLYMPUS_LUT_CHAN_517875_IDX,
+	OLYMPUS_LUT_CHAN_518000_IDX,
+	OLYMPUS_LUT_CHAN_518125_IDX,
+	OLYMPUS_LUT_CHAN_518250_IDX,
+	OLYMPUS_LUT_CHAN_518375_IDX,
+	OLYMPUS_LUT_CHAN_518500_IDX,
+	OLYMPUS_LUT_CHAN_518625_IDX,
+	OLYMPUS_LUT_CHAN_518750_IDX,
+	OLYMPUS_LUT_CHAN_518875_IDX,
+	OLYMPUS_LUT_CHAN_519000_IDX,
+	OLYMPUS_LUT_CHAN_519125_IDX,
+	OLYMPUS_LUT_CHAN_519250_IDX,
+	OLYMPUS_LUT_CHAN_519375_IDX,
+	OLYMPUS_LUT_CHAN_519500_IDX,
+	OLYMPUS_LUT_CHAN_519625_IDX,
+	OLYMPUS_LUT_CHAN_519750_IDX,
+	OLYMPUS_LUT_CHAN_519875_IDX,
+	OLYMPUS_LUT_CHAN_520000_IDX,
+	OLYMPUS_LUT_CHAN_520125_IDX,
+	OLYMPUS_LUT_CHAN_520250_IDX,
+	OLYMPUS_LUT_CHAN_520375_IDX,
+	OLYMPUS_LUT_CHAN_520500_IDX,
+	OLYMPUS_LUT_CHAN_520625_IDX,
+	OLYMPUS_LUT_CHAN_520750_IDX,
+	OLYMPUS_LUT_CHAN_520875_IDX,
+	OLYMPUS_LUT_CHAN_521000_IDX,
+	OLYMPUS_LUT_CHAN_521125_IDX,
+	OLYMPUS_LUT_CHAN_521250_IDX,
+	OLYMPUS_LUT_CHAN_521375_IDX,
+	OLYMPUS_LUT_CHAN_521500_IDX,
+	OLYMPUS_LUT_CHAN_521625_IDX,
+	OLYMPUS_LUT_CHAN_521750_IDX,
+	OLYMPUS_LUT_CHAN_521875_IDX,
+	OLYMPUS_LUT_CHAN_522000_IDX,
+	OLYMPUS_LUT_CHAN_522125_IDX,
+	OLYMPUS_LUT_CHAN_522250_IDX,
+	OLYMPUS_LUT_CHAN_522375_IDX,
+	OLYMPUS_LUT_CHAN_522500_IDX,
+	OLYMPUS_LUT_CHAN_522625_IDX,
+	OLYMPUS_LUT_CHAN_522750_IDX,
+	OLYMPUS_LUT_CHAN_522875_IDX,
+	OLYMPUS_LUT_CHAN_523000_IDX,
+	OLYMPUS_LUT_CHAN_523125_IDX,
+	OLYMPUS_LUT_CHAN_523250_IDX,
+	OLYMPUS_LUT_CHAN_523375_IDX,
+	OLYMPUS_LUT_CHAN_523500_IDX,
+	OLYMPUS_LUT_CHAN_523625_IDX,
+	OLYMPUS_LUT_CHAN_523750_IDX,
+	OLYMPUS_LUT_CHAN_523875_IDX,
+	OLYMPUS_LUT_CHAN_524000_IDX,
+	OLYMPUS_LUT_CHAN_524125_IDX,
+	OLYMPUS_LUT_CHAN_524250_IDX,
+	OLYMPUS_LUT_CHAN_524375_IDX,
+	OLYMPUS_LUT_CHAN_524500_IDX,
+	OLYMPUS_LUT_CHAN_524625_IDX,
+	OLYMPUS_LUT_CHAN_524750_IDX,
+	OLYMPUS_LUT_CHAN_524875_IDX,
+	OLYMPUS_LUT_CHAN_525000_IDX,
+	OLYMPUS_LUT_CHAN_525125_IDX,
+	OLYMPUS_LUT_CHAN_525250_IDX,
+	OLYMPUS_LUT_CHAN_525375_IDX,
+	OLYMPUS_LUT_CHAN_525500_IDX,
+	OLYMPUS_LUT_CHAN_525625_IDX,
+	OLYMPUS_LUT_CHAN_525750_IDX,
+	OLYMPUS_LUT_CHAN_525875_IDX,
+	OLYMPUS_LUT_CHAN_526000_IDX,
+	OLYMPUS_LUT_CHAN_526125_IDX,
+	OLYMPUS_LUT_CHAN_526250_IDX,
+	OLYMPUS_LUT_CHAN_526375_IDX,
+	OLYMPUS_LUT_CHAN_526500_IDX,
+	OLYMPUS_LUT_CHAN_526625_IDX,
+	OLYMPUS_LUT_CHAN_526750_IDX,
+	OLYMPUS_LUT_CHAN_526875_IDX,
+	OLYMPUS_LUT_CHAN_527000_IDX,
+	OLYMPUS_LUT_CHAN_527125_IDX,
+	OLYMPUS_LUT_CHAN_527250_IDX,
+	OLYMPUS_LUT_CHAN_527375_IDX,
+	OLYMPUS_LUT_CHAN_527500_IDX,
+	OLYMPUS_LUT_CHAN_527625_IDX,
+	OLYMPUS_LUT_CHAN_527750_IDX,
+	OLYMPUS_LUT_CHAN_527875_IDX,
+	OLYMPUS_LUT_CHAN_528000_IDX,
+	OLYMPUS_LUT_CHAN_528125_IDX,
+	OLYMPUS_LUT_CHAN_528250_IDX,
+	OLYMPUS_LUT_CHAN_528375_IDX,
+	OLYMPUS_LUT_CHAN_528500_IDX,
+	OLYMPUS_LUT_CHAN_528625_IDX,
+	OLYMPUS_LUT_CHAN_528750_IDX,
+	OLYMPUS_LUT_CHAN_528875_IDX,
+	OLYMPUS_LUT_CHAN_529000_IDX,
+	OLYMPUS_LUT_CHAN_529125_IDX,
+	OLYMPUS_LUT_CHAN_529250_IDX,
+	OLYMPUS_LUT_CHAN_529375_IDX,
+	OLYMPUS_LUT_CHAN_529500_IDX,
+	OLYMPUS_LUT_CHAN_529625_IDX,
+	OLYMPUS_LUT_CHAN_529750_IDX,
+	OLYMPUS_LUT_CHAN_529875_IDX,
+	OLYMPUS_LUT_CHAN_530000_IDX,
+	OLYMPUS_LUT_CHAN_530125_IDX,
+	OLYMPUS_LUT_CHAN_530250_IDX,
+	OLYMPUS_LUT_CHAN_530375_IDX,
+	OLYMPUS_LUT_CHAN_530500_IDX,
+	OLYMPUS_LUT_CHAN_530625_IDX,
+	OLYMPUS_LUT_CHAN_530750_IDX,
+	OLYMPUS_LUT_CHAN_530875_IDX,
+	OLYMPUS_LUT_CHAN_531000_IDX,
+	OLYMPUS_LUT_CHAN_531125_IDX,
+	OLYMPUS_LUT_CHAN_531250_IDX,
+	OLYMPUS_LUT_CHAN_531375_IDX,
+	OLYMPUS_LUT_CHAN_531500_IDX,
+	OLYMPUS_LUT_CHAN_531625_IDX,
+	OLYMPUS_LUT_CHAN_531750_IDX,
+	OLYMPUS_LUT_CHAN_531875_IDX,
+	OLYMPUS_LUT_CHAN_532000_IDX,
+	OLYMPUS_LUT_CHAN_532125_IDX,
+	OLYMPUS_LUT_CHAN_532250_IDX,
+	OLYMPUS_LUT_CHAN_532375_IDX,
+	OLYMPUS_LUT_CHAN_532500_IDX,
+	OLYMPUS_LUT_CHAN_532625_IDX,
+	OLYMPUS_LUT_CHAN_532750_IDX,
+	OLYMPUS_LUT_CHAN_532875_IDX,
+	OLYMPUS_LUT_CHAN_533000_IDX,
+	OLYMPUS_LUT_CHAN_533125_IDX,
+	OLYMPUS_LUT_CHAN_533250_IDX,
+	OLYMPUS_LUT_CHAN_533375_IDX,
+	OLYMPUS_LUT_CHAN_533500_IDX,
+	OLYMPUS_LUT_CHAN_533625_IDX,
+	OLYMPUS_LUT_CHAN_533750_IDX,
+	OLYMPUS_LUT_CHAN_533875_IDX,
+	OLYMPUS_LUT_CHAN_534000_IDX,
+	OLYMPUS_LUT_CHAN_534125_IDX,
+	OLYMPUS_LUT_CHAN_534250_IDX,
+	OLYMPUS_LUT_CHAN_534375_IDX,
+	OLYMPUS_LUT_CHAN_534500_IDX,
+	OLYMPUS_LUT_CHAN_534625_IDX,
+	OLYMPUS_LUT_CHAN_534750_IDX,
+	OLYMPUS_LUT_CHAN_534875_IDX,
+	OLYMPUS_LUT_CHAN_535000_IDX,
+	OLYMPUS_LUT_CHAN_535125_IDX,
+	OLYMPUS_LUT_CHAN_535250_IDX,
+	OLYMPUS_LUT_CHAN_535375_IDX,
+	OLYMPUS_LUT_CHAN_535500_IDX,
+	OLYMPUS_LUT_CHAN_535625_IDX,
+	OLYMPUS_LUT_CHAN_535750_IDX,
+	OLYMPUS_LUT_CHAN_535875_IDX,
+	OLYMPUS_LUT_CHAN_536000_IDX,
+	OLYMPUS_LUT_CHAN_536125_IDX,
+	OLYMPUS_LUT_CHAN_536250_IDX,
+	OLYMPUS_LUT_CHAN_536375_IDX,
+	OLYMPUS_LUT_CHAN_536500_IDX,
+	OLYMPUS_LUT_CHAN_536625_IDX,
+	OLYMPUS_LUT_CHAN_536750_IDX,
+	OLYMPUS_LUT_CHAN_536875_IDX,
+	OLYMPUS_LUT_CHAN_537000_IDX,
+	OLYMPUS_LUT_CHAN_537125_IDX,
+	OLYMPUS_LUT_CHAN_537250_IDX,
+	OLYMPUS_LUT_CHAN_537375_IDX,
+	OLYMPUS_LUT_CHAN_537500_IDX,
+	OLYMPUS_LUT_CHAN_537625_IDX,
+	OLYMPUS_LUT_CHAN_537750_IDX,
+	OLYMPUS_LUT_CHAN_537875_IDX,
+	OLYMPUS_LUT_CHAN_538000_IDX,
+	OLYMPUS_LUT_CHAN_538125_IDX,
+	OLYMPUS_LUT_CHAN_538250_IDX,
+	OLYMPUS_LUT_CHAN_538375_IDX,
+	OLYMPUS_LUT_CHAN_538500_IDX,
+	OLYMPUS_LUT_CHAN_538625_IDX,
+	OLYMPUS_LUT_CHAN_538750_IDX,
+	OLYMPUS_LUT_CHAN_538875_IDX,
+	OLYMPUS_LUT_CHAN_539000_IDX,
+	OLYMPUS_LUT_CHAN_539125_IDX,
+	OLYMPUS_LUT_CHAN_539250_IDX,
+	OLYMPUS_LUT_CHAN_539375_IDX,
+	OLYMPUS_LUT_CHAN_539500_IDX,
+	OLYMPUS_LUT_CHAN_539625_IDX,
+	OLYMPUS_LUT_CHAN_539750_IDX,
+	OLYMPUS_LUT_CHAN_539875_IDX,
+	OLYMPUS_LUT_CHAN_540000_IDX,
+	OLYMPUS_LUT_CHAN_540125_IDX,
+	OLYMPUS_LUT_CHAN_540250_IDX,
+	OLYMPUS_LUT_CHAN_540375_IDX,
+	OLYMPUS_LUT_CHAN_540500_IDX,
+	OLYMPUS_LUT_CHAN_540625_IDX,
+	OLYMPUS_LUT_CHAN_540750_IDX,
+	OLYMPUS_LUT_CHAN_540875_IDX,
+	OLYMPUS_LUT_CHAN_541000_IDX,
+	OLYMPUS_LUT_CHAN_541125_IDX,
+	OLYMPUS_LUT_CHAN_541250_IDX,
+	OLYMPUS_LUT_CHAN_541375_IDX,
+	OLYMPUS_LUT_CHAN_541500_IDX,
+	OLYMPUS_LUT_CHAN_541625_IDX,
+	OLYMPUS_LUT_CHAN_541750_IDX,
+	OLYMPUS_LUT_CHAN_541875_IDX,
+	OLYMPUS_LUT_CHAN_542000_IDX,
+	OLYMPUS_LUT_CHAN_542125_IDX,
+	OLYMPUS_LUT_CHAN_542250_IDX,
+	OLYMPUS_LUT_CHAN_542375_IDX,
+	OLYMPUS_LUT_CHAN_542500_IDX,
+	OLYMPUS_LUT_CHAN_542625_IDX,
+	OLYMPUS_LUT_CHAN_542750_IDX,
+	OLYMPUS_LUT_CHAN_542875_IDX,
+	OLYMPUS_LUT_CHAN_543000_IDX,
+	OLYMPUS_LUT_CHAN_543125_IDX,
+	OLYMPUS_LUT_CHAN_543250_IDX,
+	OLYMPUS_LUT_CHAN_543375_IDX,
+	OLYMPUS_LUT_CHAN_543500_IDX,
+	OLYMPUS_LUT_CHAN_543625_IDX,
+	OLYMPUS_LUT_CHAN_543750_IDX,
+	OLYMPUS_LUT_CHAN_543875_IDX,
+	OLYMPUS_LUT_CHAN_544000_IDX,
+	OLYMPUS_LUT_CHAN_544125_IDX,
+	OLYMPUS_LUT_CHAN_544250_IDX,
+	OLYMPUS_LUT_CHAN_544375_IDX,
+	OLYMPUS_LUT_CHAN_544500_IDX,
+	OLYMPUS_LUT_CHAN_544625_IDX,
+	OLYMPUS_LUT_CHAN_544750_IDX,
+	OLYMPUS_LUT_CHAN_544875_IDX,
+	OLYMPUS_LUT_CHAN_545000_IDX,
+	OLYMPUS_LUT_CHAN_545125_IDX,
+	OLYMPUS_LUT_CHAN_545250_IDX,
+	OLYMPUS_LUT_CHAN_545375_IDX,
+	OLYMPUS_LUT_CHAN_545500_IDX,
+	OLYMPUS_LUT_CHAN_545625_IDX,
+	OLYMPUS_LUT_CHAN_545750_IDX,
+	OLYMPUS_LUT_CHAN_545875_IDX,
+	OLYMPUS_LUT_CHAN_546000_IDX,
+	OLYMPUS_LUT_CHAN_546125_IDX,
+	OLYMPUS_LUT_CHAN_546250_IDX,
+	OLYMPUS_LUT_CHAN_546375_IDX,
+	OLYMPUS_LUT_CHAN_546500_IDX,
+	OLYMPUS_LUT_CHAN_546625_IDX,
+	OLYMPUS_LUT_CHAN_546750_IDX,
+	OLYMPUS_LUT_CHAN_546875_IDX,
+	OLYMPUS_LUT_CHAN_547000_IDX,
+	OLYMPUS_LUT_CHAN_547125_IDX,
+	OLYMPUS_LUT_CHAN_547250_IDX,
+	OLYMPUS_LUT_CHAN_547375_IDX,
+	OLYMPUS_LUT_CHAN_547500_IDX,
+	OLYMPUS_LUT_CHAN_547625_IDX,
+	OLYMPUS_LUT_CHAN_547750_IDX,
+	OLYMPUS_LUT_CHAN_547875_IDX,
+	OLYMPUS_LUT_CHAN_548000_IDX,
+	OLYMPUS_LUT_CHAN_548125_IDX,
+	OLYMPUS_LUT_CHAN_548250_IDX,
+	OLYMPUS_LUT_CHAN_548375_IDX,
+	OLYMPUS_LUT_CHAN_548500_IDX,
+	OLYMPUS_LUT_CHAN_548625_IDX,
+	OLYMPUS_LUT_CHAN_548750_IDX,
+	OLYMPUS_LUT_CHAN_548875_IDX,
+	OLYMPUS_LUT_CHAN_549000_IDX,
+	OLYMPUS_LUT_CHAN_549125_IDX,
+	OLYMPUS_LUT_CHAN_549250_IDX,
+	OLYMPUS_LUT_CHAN_549375_IDX,
+	OLYMPUS_LUT_CHAN_549500_IDX,
+	OLYMPUS_LUT_CHAN_549625_IDX,
+	OLYMPUS_LUT_CHAN_549750_IDX,
+	OLYMPUS_LUT_CHAN_549875_IDX,
+	OLYMPUS_LUT_CHAN_550000_IDX,
+	OLYMPUS_LUT_CHAN_550125_IDX,
+	OLYMPUS_LUT_CHAN_550250_IDX,
+	OLYMPUS_LUT_CHAN_550375_IDX,
+	OLYMPUS_LUT_CHAN_550500_IDX,
+	OLYMPUS_LUT_CHAN_550625_IDX,
+	OLYMPUS_LUT_CHAN_550750_IDX,
+	OLYMPUS_LUT_CHAN_550875_IDX,
+	OLYMPUS_LUT_CHAN_551000_IDX,
+	OLYMPUS_LUT_CHAN_551125_IDX,
+	OLYMPUS_LUT_CHAN_551250_IDX,
+	OLYMPUS_LUT_CHAN_551375_IDX,
+	OLYMPUS_LUT_CHAN_551500_IDX,
+	OLYMPUS_LUT_CHAN_551625_IDX,
+	OLYMPUS_LUT_CHAN_551750_IDX,
+	OLYMPUS_LUT_CHAN_551875_IDX,
+	OLYMPUS_LUT_CHAN_552000_IDX,
+	OLYMPUS_LUT_CHAN_552125_IDX,
+	OLYMPUS_LUT_CHAN_552250_IDX,
+	OLYMPUS_LUT_CHAN_552375_IDX,
+	OLYMPUS_LUT_CHAN_552500_IDX,
+	OLYMPUS_LUT_CHAN_552625_IDX,
+	OLYMPUS_LUT_CHAN_552750_IDX,
+	OLYMPUS_LUT_CHAN_552875_IDX,
+	OLYMPUS_LUT_CHAN_553000_IDX,
+	OLYMPUS_LUT_CHAN_553125_IDX,
+	OLYMPUS_LUT_CHAN_553250_IDX,
+	OLYMPUS_LUT_CHAN_553375_IDX,
+	OLYMPUS_LUT_CHAN_553500_IDX,
+	OLYMPUS_LUT_CHAN_553625_IDX,
+	OLYMPUS_LUT_CHAN_553750_IDX,
+	OLYMPUS_LUT_CHAN_553875_IDX,
+	OLYMPUS_LUT_CHAN_554000_IDX,
+	OLYMPUS_LUT_CHAN_554125_IDX,
+	OLYMPUS_LUT_CHAN_554250_IDX,
+	OLYMPUS_LUT_CHAN_554375_IDX,
+	OLYMPUS_LUT_CHAN_554500_IDX,
+	OLYMPUS_LUT_CHAN_554625_IDX,
+	OLYMPUS_LUT_CHAN_554750_IDX,
+	OLYMPUS_LUT_CHAN_554875_IDX,
+	OLYMPUS_LUT_CHAN_555000_IDX,
+	OLYMPUS_LUT_CHAN_555125_IDX,
+	OLYMPUS_LUT_CHAN_555250_IDX,
+	OLYMPUS_LUT_CHAN_555375_IDX,
+	OLYMPUS_LUT_CHAN_555500_IDX,
+	OLYMPUS_LUT_CHAN_555625_IDX,
+	OLYMPUS_LUT_CHAN_555750_IDX,
+	OLYMPUS_LUT_CHAN_555875_IDX,
+	OLYMPUS_LUT_CHAN_556000_IDX,
+	OLYMPUS_LUT_CHAN_556125_IDX,
+	OLYMPUS_LUT_CHAN_556250_IDX,
+	OLYMPUS_LUT_CHAN_556375_IDX,
+	OLYMPUS_LUT_CHAN_556500_IDX,
+	OLYMPUS_LUT_CHAN_556625_IDX,
+	OLYMPUS_LUT_CHAN_556750_IDX,
+	OLYMPUS_LUT_CHAN_556875_IDX,
+	OLYMPUS_LUT_CHAN_557000_IDX,
+	OLYMPUS_LUT_CHAN_557125_IDX,
+	OLYMPUS_LUT_CHAN_557250_IDX,
+	OLYMPUS_LUT_CHAN_557375_IDX,
+	OLYMPUS_LUT_CHAN_557500_IDX,
+	OLYMPUS_LUT_CHAN_557625_IDX,
+	OLYMPUS_LUT_CHAN_557750_IDX,
+	OLYMPUS_LUT_CHAN_557875_IDX,
+	OLYMPUS_LUT_CHAN_558000_IDX,
+	OLYMPUS_LUT_CHAN_558125_IDX,
+	OLYMPUS_LUT_CHAN_558250_IDX,
+	OLYMPUS_LUT_CHAN_558375_IDX,
+	OLYMPUS_LUT_CHAN_558500_IDX,
+	OLYMPUS_LUT_CHAN_558625_IDX,
+	OLYMPUS_LUT_CHAN_558750_IDX,
+	OLYMPUS_LUT_CHAN_558875_IDX,
+	OLYMPUS_LUT_CHAN_559000_IDX,
+	OLYMPUS_LUT_CHAN_559125_IDX,
+	OLYMPUS_LUT_CHAN_559250_IDX,
+	OLYMPUS_LUT_CHAN_559375_IDX,
+	OLYMPUS_LUT_CHAN_559500_IDX,
+	OLYMPUS_LUT_CHAN_559625_IDX,
+	OLYMPUS_LUT_CHAN_559750_IDX,
+	OLYMPUS_LUT_CHAN_559875_IDX,
+	OLYMPUS_LUT_CHAN_560000_IDX,
+	OLYMPUS_LUT_CHAN_560125_IDX,
+	OLYMPUS_LUT_CHAN_560250_IDX,
+	OLYMPUS_LUT_CHAN_560375_IDX,
+	OLYMPUS_LUT_CHAN_560500_IDX,
+	OLYMPUS_LUT_CHAN_560625_IDX,
+	OLYMPUS_LUT_CHAN_560750_IDX,
+	OLYMPUS_LUT_CHAN_560875_IDX,
+	OLYMPUS_LUT_CHAN_561000_IDX,
+	OLYMPUS_LUT_CHAN_561125_IDX,
+	OLYMPUS_LUT_CHAN_561250_IDX,
+	OLYMPUS_LUT_CHAN_561375_IDX,
+	OLYMPUS_LUT_CHAN_561500_IDX,
+	OLYMPUS_LUT_CHAN_561625_IDX,
+	OLYMPUS_LUT_CHAN_561750_IDX,
+	OLYMPUS_LUT_CHAN_561875_IDX,
+	OLYMPUS_LUT_CHAN_562000_IDX,
+	OLYMPUS_LUT_CHAN_562125_IDX,
+	OLYMPUS_LUT_CHAN_562250_IDX,
+	OLYMPUS_LUT_CHAN_562375_IDX,
+	OLYMPUS_LUT_CHAN_562500_IDX,
+	OLYMPUS_LUT_CHAN_562625_IDX,
+	OLYMPUS_LUT_CHAN_562750_IDX,
+	OLYMPUS_LUT_CHAN_562875_IDX,
+	OLYMPUS_LUT_CHAN_563000_IDX,
+	OLYMPUS_LUT_CHAN_563125_IDX,
+	OLYMPUS_LUT_CHAN_563250_IDX,
+	OLYMPUS_LUT_CHAN_563375_IDX,
+	OLYMPUS_LUT_CHAN_563500_IDX,
+	OLYMPUS_LUT_CHAN_563625_IDX,
+	OLYMPUS_LUT_CHAN_563750_IDX,
+	OLYMPUS_LUT_CHAN_563875_IDX,
+	OLYMPUS_LUT_CHAN_564000_IDX,
+	OLYMPUS_LUT_CHAN_564125_IDX,
+	OLYMPUS_LUT_CHAN_564250_IDX,
+	OLYMPUS_LUT_CHAN_564375_IDX,
+	OLYMPUS_LUT_CHAN_564500_IDX,
+	OLYMPUS_LUT_CHAN_564625_IDX,
+	OLYMPUS_LUT_CHAN_564750_IDX,
+	OLYMPUS_LUT_CHAN_564875_IDX,
+	OLYMPUS_LUT_CHAN_565000_IDX,
+	OLYMPUS_LUT_CHAN_565125_IDX,
+	OLYMPUS_LUT_CHAN_565250_IDX,
+	OLYMPUS_LUT_CHAN_565375_IDX,
+	OLYMPUS_LUT_CHAN_565500_IDX,
+	OLYMPUS_LUT_CHAN_565625_IDX,
+	OLYMPUS_LUT_CHAN_565750_IDX,
+	OLYMPUS_LUT_CHAN_565875_IDX,
+	OLYMPUS_LUT_CHAN_566000_IDX,
+	OLYMPUS_LUT_CHAN_566125_IDX,
+	OLYMPUS_LUT_CHAN_566250_IDX,
+	OLYMPUS_LUT_CHAN_566375_IDX,
+	OLYMPUS_LUT_CHAN_566500_IDX,
+	OLYMPUS_LUT_CHAN_566625_IDX,
+	OLYMPUS_LUT_CHAN_566750_IDX,
+	OLYMPUS_LUT_CHAN_566875_IDX,
+	OLYMPUS_LUT_CHAN_567000_IDX,
+	OLYMPUS_LUT_CHAN_567125_IDX,
+	OLYMPUS_LUT_CHAN_567250_IDX,
+	OLYMPUS_LUT_CHAN_567375_IDX,
+	OLYMPUS_LUT_CHAN_567500_IDX,
+	OLYMPUS_LUT_CHAN_567625_IDX,
+	OLYMPUS_LUT_CHAN_567750_IDX,
+	OLYMPUS_LUT_CHAN_567875_IDX,
+	OLYMPUS_LUT_CHAN_568000_IDX,
+	OLYMPUS_LUT_CHAN_568125_IDX,
+	OLYMPUS_LUT_CHAN_568250_IDX,
+	OLYMPUS_LUT_CHAN_568375_IDX,
+	OLYMPUS_LUT_CHAN_568500_IDX,
+	OLYMPUS_LUT_CHAN_568625_IDX,
+	OLYMPUS_LUT_CHAN_568750_IDX,
+	OLYMPUS_LUT_CHAN_568875_IDX,
+	OLYMPUS_LUT_CHAN_569000_IDX,
+	OLYMPUS_LUT_CHAN_569125_IDX,
+	OLYMPUS_LUT_CHAN_569250_IDX,
+	OLYMPUS_LUT_CHAN_569375_IDX,
+	OLYMPUS_LUT_CHAN_569500_IDX,
+	OLYMPUS_LUT_CHAN_569625_IDX,
+	OLYMPUS_LUT_CHAN_569750_IDX,
+	OLYMPUS_LUT_CHAN_569875_IDX,
+	OLYMPUS_LUT_CHAN_570000_IDX,
+	OLYMPUS_LUT_CHAN_570125_IDX,
+	OLYMPUS_LUT_CHAN_570250_IDX,
+	OLYMPUS_LUT_CHAN_570375_IDX,
+	OLYMPUS_LUT_CHAN_570500_IDX,
+	OLYMPUS_LUT_CHAN_570625_IDX,
+	OLYMPUS_LUT_CHAN_570750_IDX,
+	OLYMPUS_LUT_CHAN_570875_IDX,
+	OLYMPUS_LUT_CHAN_571000_IDX,
+	OLYMPUS_LUT_CHAN_571125_IDX,
+	OLYMPUS_LUT_CHAN_571250_IDX,
+	OLYMPUS_LUT_CHAN_571375_IDX,
+	OLYMPUS_LUT_CHAN_571500_IDX,
+	OLYMPUS_LUT_CHAN_571625_IDX,
+	OLYMPUS_LUT_CHAN_571750_IDX,
+	OLYMPUS_LUT_CHAN_571875_IDX,
+	OLYMPUS_LUT_CHAN_572000_IDX,
+	OLYMPUS_LUT_CHAN_572125_IDX,
+	OLYMPUS_LUT_CHAN_572250_IDX,
+	OLYMPUS_LUT_CHAN_572375_IDX,
+	OLYMPUS_LUT_CHAN_572500_IDX,
+	OLYMPUS_LUT_CHAN_572625_IDX,
+	OLYMPUS_LUT_CHAN_572750_IDX,
+	OLYMPUS_LUT_CHAN_572875_IDX,
+	OLYMPUS_LUT_CHAN_573000_IDX,
+	OLYMPUS_LUT_CHAN_573125_IDX,
+	OLYMPUS_LUT_CHAN_573250_IDX,
+	OLYMPUS_LUT_CHAN_573375_IDX,
+	OLYMPUS_LUT_CHAN_573500_IDX,
+	OLYMPUS_LUT_CHAN_573625_IDX,
+	OLYMPUS_LUT_CHAN_573750_IDX,
+	OLYMPUS_LUT_CHAN_573875_IDX,
+	OLYMPUS_LUT_CHAN_574000_IDX,
+	OLYMPUS_LUT_CHAN_574125_IDX,
+	OLYMPUS_LUT_CHAN_574250_IDX,
+	OLYMPUS_LUT_CHAN_574375_IDX,
+	OLYMPUS_LUT_CHAN_574500_IDX,
+	OLYMPUS_LUT_CHAN_574625_IDX,
+	OLYMPUS_LUT_CHAN_574750_IDX,
+	OLYMPUS_LUT_CHAN_574875_IDX,
+	OLYMPUS_LUT_CHAN_575000_IDX,
+	OLYMPUS_LUT_CHAN_575125_IDX,
+	OLYMPUS_LUT_CHAN_575250_IDX,
+	OLYMPUS_LUT_CHAN_575375_IDX,
+	OLYMPUS_LUT_CHAN_575500_IDX,
+	OLYMPUS_LUT_CHAN_575625_IDX,
+	OLYMPUS_LUT_CHAN_575750_IDX,
+	OLYMPUS_LUT_CHAN_575875_IDX,
+	OLYMPUS_LUT_CHAN_576000_IDX,
+	OLYMPUS_LUT_CHAN_576125_IDX,
+	OLYMPUS_LUT_CHAN_576250_IDX,
+	OLYMPUS_LUT_CHAN_576375_IDX,
+	OLYMPUS_LUT_CHAN_576500_IDX,
+	OLYMPUS_LUT_CHAN_576625_IDX,
+	OLYMPUS_LUT_CHAN_576750_IDX,
+	OLYMPUS_LUT_CHAN_576875_IDX,
+	OLYMPUS_LUT_CHAN_577000_IDX,
+	OLYMPUS_LUT_CHAN_577125_IDX,
+	OLYMPUS_LUT_CHAN_577250_IDX,
+	OLYMPUS_LUT_CHAN_577375_IDX,
+	OLYMPUS_LUT_CHAN_577500_IDX,
+	OLYMPUS_LUT_CHAN_577625_IDX,
+	OLYMPUS_LUT_CHAN_577750_IDX,
+	OLYMPUS_LUT_CHAN_577875_IDX,
+	OLYMPUS_LUT_CHAN_578000_IDX,
+	OLYMPUS_LUT_CHAN_578125_IDX,
+	OLYMPUS_LUT_CHAN_578250_IDX,
+	OLYMPUS_LUT_CHAN_578375_IDX,
+	OLYMPUS_LUT_CHAN_578500_IDX,
+	OLYMPUS_LUT_CHAN_578625_IDX,
+	OLYMPUS_LUT_CHAN_578750_IDX,
+	OLYMPUS_LUT_CHAN_578875_IDX,
+	OLYMPUS_LUT_CHAN_579000_IDX,
+	OLYMPUS_LUT_CHAN_579125_IDX,
+	OLYMPUS_LUT_CHAN_579250_IDX,
+	OLYMPUS_LUT_CHAN_579375_IDX,
+	OLYMPUS_LUT_CHAN_579500_IDX,
+	OLYMPUS_LUT_CHAN_579625_IDX,
+	OLYMPUS_LUT_CHAN_579750_IDX,
+	OLYMPUS_LUT_CHAN_579875_IDX,
+	OLYMPUS_LUT_CHAN_580000_IDX,
+	OLYMPUS_LUT_CHAN_580125_IDX,
+	OLYMPUS_LUT_CHAN_580250_IDX,
+	OLYMPUS_LUT_CHAN_580375_IDX,
+	OLYMPUS_LUT_CHAN_580500_IDX,
+	OLYMPUS_LUT_CHAN_580625_IDX,
+	OLYMPUS_LUT_CHAN_580750_IDX,
+	OLYMPUS_LUT_CHAN_580875_IDX,
+	OLYMPUS_LUT_CHAN_581000_IDX,
+	OLYMPUS_LUT_CHAN_581125_IDX,
+	OLYMPUS_LUT_CHAN_581250_IDX,
+	OLYMPUS_LUT_CHAN_581375_IDX,
+	OLYMPUS_LUT_CHAN_581500_IDX,
+	OLYMPUS_LUT_CHAN_581625_IDX,
+	OLYMPUS_LUT_CHAN_581750_IDX,
+	OLYMPUS_LUT_CHAN_581875_IDX,
+	OLYMPUS_LUT_CHAN_582000_IDX,
+	OLYMPUS_LUT_CHAN_582125_IDX,
+	OLYMPUS_LUT_CHAN_582250_IDX,
+	OLYMPUS_LUT_CHAN_582375_IDX,
+	OLYMPUS_LUT_CHAN_582500_IDX,
+	OLYMPUS_LUT_CHAN_582625_IDX,
+	OLYMPUS_LUT_CHAN_582750_IDX,
+	OLYMPUS_LUT_CHAN_582875_IDX,
+	OLYMPUS_LUT_CHAN_583000_IDX,
+	OLYMPUS_LUT_CHAN_583125_IDX,
+	OLYMPUS_LUT_CHAN_583250_IDX,
+	OLYMPUS_LUT_CHAN_583375_IDX,
+	OLYMPUS_LUT_CHAN_583500_IDX,
+	OLYMPUS_LUT_CHAN_583625_IDX,
+	OLYMPUS_LUT_CHAN_583750_IDX,
+	OLYMPUS_LUT_CHAN_583875_IDX,
+	OLYMPUS_LUT_CHAN_584000_IDX,
+	OLYMPUS_LUT_CHAN_584125_IDX,
+	OLYMPUS_LUT_CHAN_584250_IDX,
+	OLYMPUS_LUT_CHAN_584375_IDX,
+	OLYMPUS_LUT_CHAN_584500_IDX,
+	OLYMPUS_LUT_CHAN_584625_IDX,
+	OLYMPUS_LUT_CHAN_584750_IDX,
+	OLYMPUS_LUT_CHAN_584875_IDX,
+	OLYMPUS_LUT_CHAN_585000_IDX,
+	OLYMPUS_LUT_CHAN_585125_IDX,
+	OLYMPUS_LUT_CHAN_585250_IDX,
+	OLYMPUS_LUT_CHAN_585375_IDX,
+	OLYMPUS_LUT_CHAN_585500_IDX,
+	OLYMPUS_LUT_CHAN_585625_IDX,
+	OLYMPUS_LUT_CHAN_585750_IDX,
+	OLYMPUS_LUT_CHAN_585875_IDX,
+	OLYMPUS_LUT_CHAN_586000_IDX,
+	OLYMPUS_LUT_CHAN_586125_IDX,
+	OLYMPUS_LUT_CHAN_586250_IDX,
+	OLYMPUS_LUT_CHAN_586375_IDX,
+	OLYMPUS_LUT_CHAN_586500_IDX,
+	OLYMPUS_LUT_CHAN_586625_IDX,
+	OLYMPUS_LUT_CHAN_586750_IDX,
+	OLYMPUS_LUT_CHAN_586875_IDX,
+	OLYMPUS_LUT_CHAN_587000_IDX,
+	OLYMPUS_LUT_CHAN_587125_IDX,
+	OLYMPUS_LUT_CHAN_587250_IDX,
+	OLYMPUS_LUT_CHAN_587375_IDX,
+	OLYMPUS_LUT_CHAN_587500_IDX,
+	OLYMPUS_LUT_CHAN_587625_IDX,
+	OLYMPUS_LUT_CHAN_587750_IDX,
+	OLYMPUS_LUT_CHAN_587875_IDX,
+	OLYMPUS_LUT_CHAN_588000_IDX,
+	OLYMPUS_LUT_CHAN_588125_IDX,
+	OLYMPUS_LUT_CHAN_588250_IDX,
+	OLYMPUS_LUT_CHAN_588375_IDX,
+	OLYMPUS_LUT_CHAN_588500_IDX,
+	OLYMPUS_LUT_CHAN_588625_IDX,
+	OLYMPUS_LUT_CHAN_588750_IDX,
+	OLYMPUS_LUT_CHAN_588875_IDX,
+	OLYMPUS_LUT_CHAN_589000_IDX,
+	OLYMPUS_LUT_CHAN_589125_IDX,
+	OLYMPUS_LUT_CHAN_589250_IDX,
+	OLYMPUS_LUT_CHAN_589375_IDX,
+	OLYMPUS_LUT_CHAN_589500_IDX,
+	OLYMPUS_LUT_CHAN_589625_IDX,
+	OLYMPUS_LUT_CHAN_589750_IDX,
+	OLYMPUS_LUT_CHAN_589875_IDX,
+	OLYMPUS_LUT_CHAN_590000_IDX,
+	OLYMPUS_LUT_CHAN_590125_IDX,
+	OLYMPUS_LUT_CHAN_590250_IDX,
+	OLYMPUS_LUT_CHAN_590375_IDX,
+	OLYMPUS_LUT_CHAN_590500_IDX,
+	OLYMPUS_LUT_CHAN_590625_IDX,
+	OLYMPUS_LUT_CHAN_590750_IDX,
+	OLYMPUS_LUT_CHAN_590875_IDX,
+	OLYMPUS_LUT_CHAN_591000_IDX,
+	OLYMPUS_LUT_CHAN_591125_IDX,
+	OLYMPUS_LUT_CHAN_591250_IDX,
+	OLYMPUS_LUT_CHAN_591375_IDX,
+	OLYMPUS_LUT_CHAN_591500_IDX,
+	OLYMPUS_LUT_CHAN_591625_IDX,
+	OLYMPUS_LUT_CHAN_591750_IDX,
+	OLYMPUS_LUT_CHAN_591875_IDX,
+	OLYMPUS_LUT_CHAN_592000_IDX,
+	OLYMPUS_LUT_CHAN_592125_IDX,
+	OLYMPUS_LUT_CHAN_592250_IDX,
+	OLYMPUS_LUT_CHAN_592375_IDX,
+	OLYMPUS_LUT_CHAN_592500_IDX,
+	OLYMPUS_LUT_CHAN_592625_IDX,
+	OLYMPUS_LUT_CHAN_592750_IDX,
+	OLYMPUS_LUT_CHAN_592875_IDX,
+	OLYMPUS_LUT_CHAN_593000_IDX,
+	OLYMPUS_LUT_CHAN_593125_IDX,
+	OLYMPUS_LUT_CHAN_593250_IDX,
+	OLYMPUS_LUT_CHAN_593375_IDX,
+	OLYMPUS_LUT_CHAN_593500_IDX,
+	OLYMPUS_LUT_CHAN_593625_IDX,
+	OLYMPUS_LUT_CHAN_593750_IDX,
+	OLYMPUS_LUT_CHAN_593875_IDX,
+	OLYMPUS_LUT_CHAN_594000_IDX,
+	OLYMPUS_LUT_CHAN_594125_IDX,
+	OLYMPUS_LUT_CHAN_594250_IDX,
+	OLYMPUS_LUT_CHAN_594375_IDX,
+	OLYMPUS_LUT_CHAN_594500_IDX,
+	OLYMPUS_LUT_CHAN_594625_IDX,
+	OLYMPUS_LUT_CHAN_594750_IDX,
+	OLYMPUS_LUT_CHAN_594875_IDX,
+	OLYMPUS_LUT_CHAN_595000_IDX,
+	OLYMPUS_LUT_CHAN_595125_IDX,
+	OLYMPUS_LUT_CHAN_595250_IDX,
+	OLYMPUS_LUT_CHAN_595375_IDX,
+	OLYMPUS_LUT_CHAN_595500_IDX,
+	OLYMPUS_LUT_CHAN_595625_IDX,
+	OLYMPUS_LUT_CHAN_595750_IDX,
+	OLYMPUS_LUT_CHAN_595875_IDX,
+	OLYMPUS_LUT_CHAN_596000_IDX,
+	OLYMPUS_LUT_CHAN_596125_IDX,
+	OLYMPUS_LUT_CHAN_596250_IDX,
+	OLYMPUS_LUT_CHAN_596375_IDX,
+	OLYMPUS_LUT_CHAN_596500_IDX,
+	OLYMPUS_LUT_CHAN_596625_IDX,
+	OLYMPUS_LUT_CHAN_596750_IDX,
+	OLYMPUS_LUT_CHAN_596875_IDX,
+	OLYMPUS_LUT_CHAN_597000_IDX,
+	OLYMPUS_LUT_CHAN_597125_IDX,
+	OLYMPUS_LUT_CHAN_597250_IDX,
+	OLYMPUS_LUT_CHAN_597375_IDX,
+	OLYMPUS_LUT_CHAN_597500_IDX,
+	OLYMPUS_LUT_CHAN_597625_IDX,
+	OLYMPUS_LUT_CHAN_597750_IDX,
+	OLYMPUS_LUT_CHAN_597875_IDX,
+	OLYMPUS_LUT_CHAN_598000_IDX,
+	OLYMPUS_LUT_CHAN_598125_IDX,
+	OLYMPUS_LUT_CHAN_598250_IDX,
+	OLYMPUS_LUT_CHAN_598375_IDX,
+	OLYMPUS_LUT_CHAN_598500_IDX,
+	OLYMPUS_LUT_CHAN_598625_IDX,
+	OLYMPUS_LUT_CHAN_598750_IDX,
+	OLYMPUS_LUT_CHAN_598875_IDX,
+	OLYMPUS_LUT_CHAN_599000_IDX,
+	OLYMPUS_LUT_CHAN_599125_IDX,
+	OLYMPUS_LUT_CHAN_599250_IDX,
+	OLYMPUS_LUT_CHAN_599375_IDX,
+	OLYMPUS_LUT_CHAN_599500_IDX,
+	OLYMPUS_LUT_CHAN_599625_IDX,
+	OLYMPUS_LUT_CHAN_599750_IDX,
+	OLYMPUS_LUT_CHAN_599875_IDX,
+	OLYMPUS_LUT_CHAN_600000_IDX,
+	OLYMPUS_LUT_CHAN_5G_MAX
+};
+
+enum olympus_lut_idx_24g {
+	OLYMPUS_LUT_CHAN_240700_IDX,
+	OLYMPUS_LUT_CHAN_240825_IDX,
+	OLYMPUS_LUT_CHAN_240950_IDX,
+	OLYMPUS_LUT_CHAN_241075_IDX,
+	OLYMPUS_LUT_CHAN_241200_IDX,
+	OLYMPUS_LUT_CHAN_241325_IDX,
+	OLYMPUS_LUT_CHAN_241450_IDX,
+	OLYMPUS_LUT_CHAN_241575_IDX,
+	OLYMPUS_LUT_CHAN_241700_IDX,
+	OLYMPUS_LUT_CHAN_241825_IDX,
+	OLYMPUS_LUT_CHAN_241950_IDX,
+	OLYMPUS_LUT_CHAN_242075_IDX,
+	OLYMPUS_LUT_CHAN_242200_IDX,
+	OLYMPUS_LUT_CHAN_242325_IDX,
+	OLYMPUS_LUT_CHAN_242450_IDX,
+	OLYMPUS_LUT_CHAN_242575_IDX,
+	OLYMPUS_LUT_CHAN_242700_IDX,
+	OLYMPUS_LUT_CHAN_242825_IDX,
+	OLYMPUS_LUT_CHAN_242950_IDX,
+	OLYMPUS_LUT_CHAN_243075_IDX,
+	OLYMPUS_LUT_CHAN_243200_IDX,
+	OLYMPUS_LUT_CHAN_243325_IDX,
+	OLYMPUS_LUT_CHAN_243450_IDX,
+	OLYMPUS_LUT_CHAN_243575_IDX,
+	OLYMPUS_LUT_CHAN_243700_IDX,
+	OLYMPUS_LUT_CHAN_243825_IDX,
+	OLYMPUS_LUT_CHAN_243950_IDX,
+	OLYMPUS_LUT_CHAN_244075_IDX,
+	OLYMPUS_LUT_CHAN_244200_IDX,
+	OLYMPUS_LUT_CHAN_244325_IDX,
+	OLYMPUS_LUT_CHAN_244450_IDX,
+	OLYMPUS_LUT_CHAN_244575_IDX,
+	OLYMPUS_LUT_CHAN_244700_IDX,
+	OLYMPUS_LUT_CHAN_244825_IDX,
+	OLYMPUS_LUT_CHAN_244950_IDX,
+	OLYMPUS_LUT_CHAN_245075_IDX,
+	OLYMPUS_LUT_CHAN_245200_IDX,
+	OLYMPUS_LUT_CHAN_245325_IDX,
+	OLYMPUS_LUT_CHAN_245450_IDX,
+	OLYMPUS_LUT_CHAN_245575_IDX,
+	OLYMPUS_LUT_CHAN_245700_IDX,
+	OLYMPUS_LUT_CHAN_245825_IDX,
+	OLYMPUS_LUT_CHAN_245950_IDX,
+	OLYMPUS_LUT_CHAN_246075_IDX,
+	OLYMPUS_LUT_CHAN_246200_IDX,
+	OLYMPUS_LUT_CHAN_246325_IDX,
+	OLYMPUS_LUT_CHAN_246450_IDX,
+	OLYMPUS_LUT_CHAN_246575_IDX,
+	OLYMPUS_LUT_CHAN_246700_IDX,
+	OLYMPUS_LUT_CHAN_246825_IDX,
+	OLYMPUS_LUT_CHAN_246950_IDX,
+	OLYMPUS_LUT_CHAN_247075_IDX,
+	OLYMPUS_LUT_CHAN_247200_IDX,
+	OLYMPUS_LUT_CHAN_247325_IDX,
+	OLYMPUS_LUT_CHAN_247450_IDX,
+	OLYMPUS_LUT_CHAN_247575_IDX,
+	OLYMPUS_LUT_CHAN_247700_IDX,
+	OLYMPUS_LUT_CHAN_247825_IDX,
+	OLYMPUS_LUT_CHAN_247950_IDX,
+	OLYMPUS_LUT_CHAN_248075_IDX,
+	OLYMPUS_LUT_CHAN_248200_IDX,
+	OLYMPUS_LUT_CHAN_248325_IDX,
+	OLYMPUS_LUT_CHAN_248450_IDX,
+	OLYMPUS_LUT_CHAN_248575_IDX,
+	OLYMPUS_LUT_CHAN_248700_IDX,
+	OLYMPUS_LUT_CHAN_248825_IDX,
+	OLYMPUS_LUT_CHAN_248950_IDX,
+	OLYMPUS_LUT_CHAN_249075_IDX,
+	OLYMPUS_LUT_CHAN_249200_IDX,
+	OLYMPUS_LUT_CHAN_249325_IDX,
+	OLYMPUS_LUT_CHAN_249450_IDX,
+	OLYMPUS_LUT_CHAN_249575_IDX,
+	OLYMPUS_LUT_CHAN_249700_IDX,
+	OLYMPUS_LUT_CHAN_249825_IDX,
+	OLYMPUS_LUT_CHAN_249950_IDX,
+	OLYMPUS_LUT_CHAN_250075_IDX,
+	OLYMPUS_LUT_CHAN_24G_MAX
+};
+
+/**
+ * DOC: AFE (=Analog Front End)
+ *
+ * Configuration layer for the HW component, most of the defined operations
+ * happen  when we start the driver.
+ *
+ * The configuration supports:
+ * CL8080: 4 + 4 (chains 0-3 @ TCV0 and chains 0-3 @ TCV1)
+ * CL8060: 4 + 2 (chains 0-3 @ TCV0 and chains 2-3 @ TCV1)
+ * CL8064: 4 + 2 (chains 0-3 @ TCV0 and chains 2-3 @ TCV1)
+ * CL8040: 2 + 2 (chains 1-2 @ TCV0 and chains 1-2 @ TCV1)
+ * CL8046: 4 + 0 (chains 0-3 @ TCV0)
+ */
+
+struct cl_afe_reg {
+	u32 ctrl8;
+	u32 ctrl9;
+	u32 ctrl36_phy0;
+	u32 ctrl36_phy1;
+	u32 ctrl37_phy0;
+	u32 ctrl37_phy1;
+	u8 adc_ch_alloc;
+};
+
+int cl_afe_cfg(struct cl_chip *chip);
+void cl_afe_cfg_calib(struct cl_chip *chip);
+void cl_afe_cfg_restore(struct cl_chip *chip);
+
+/**
+ * FEM (=Front End Module)
+ */
+
+enum fem_wiring_id {
+	/* TCV0 - 6 FEMs 3 wires, TCV1 - 6 FEMs 2 wires */
+	FEM_WIRING_0_TCV0_6_TCV1_6                    = 0,
+	/* TCV0 - 6 FEMs 2 wires, TCV1 - 6 FEMs 2 wires */
+	FEM_WIRING_1_OBSOLETE_TCV0_6_TCV1_6           = 1,
+	/* TCV0 - 6 FEMs 2 wires, TCV1 - 6 FEMs 3 wires */
+	FEM_WIRING_2_OBSOLETE_TCV0_6_TCV1_6           = 2,
+	/* TCV0 - 2 FEMs 3 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires */
+	FEM_WIRING_3_TCV0_2_ELASTIC_4_TCV1_2          = 3,
+	/* TCV0 - 2 FEMs 2 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires */
+	FEM_WIRING_4_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 = 4,
+	/* TCV0 - 2 FEMs 3 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 3 wires */
+	FEM_WIRING_5_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 = 5,
+	/* TCV0 - 2 FEMs 2 wires, Elastic - 4 FEMs 3 wires, TCV1 - 2 FEMs 3 wires */
+	FEM_WIRING_6_OBSOLETE_TCV0_2_ELASTIC_4_TCV1_2 = 6,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 2 wires */
+	FEM_WIRING_7_TCV0_4_TCV1_4                    = 7,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+	FEM_WIRING_8_OBSOLETE_TCV0_4_TCV1_4           = 8,
+	/* TCV0 - 4 FEMs 2 wires, TCV1 - 4 FEMs 2 wires */
+	FEM_WIRING_9_TCV0_4_TCV1_4                    = 9,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+	FEM_WIRING_10_TCV0_4_TCV1_4                   = 10,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 LNAs (RX only) */
+	FEM_WIRING_11_TCV0_4_TCV1_4_RX_ONLY           = 11,
+	/* TCV0 - 4 FEMs 2 wires, TCV1 - 4 LNAs (RX only) */
+	FEM_WIRING_12_TCV0_4_TCV1_4_RX_ONLY           = 12,
+	/* TCV0 - 6 FEMs 3 wires, TCV1 - 6 FEMs 2 wires (not active), 2 LNAs 1 wire (not active) */
+	FEM_WIRING_13_SENSING_4RX_2TX                 = 13,
+	/* TCV0 - 6 FEMs 3 wires (4 active), TCV1 - 6 FEMs 2 wires (not active), 2 LNAs 1 wire */
+	FEM_WIRING_14_SENSING_4TX_2RX                 = 14,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs (RX only) */
+	FEM_WIRING_15_CHAMELEON_4TX_4RX               = 15,
+	/* TCV0 - 2 FEMs 3 wires, TCV1 - 2 FEMs 2 wires (CL8040) */
+	FEM_WIRING_16_TCV0_2_TCV1_2                   = 16,
+	/* TCV0 - 4 FEMs 2 wires, TCV1 - 0 FEMs (CL8046) */
+	FEM_WIRING_17_TCV0_4_TCV1_0                   = 17,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 4 FEMs 3 wires */
+	FEM_WIRING_18_TCV0_4_TCV1_4                   = 18,
+	/* TCV0 - 2 FEMs 3 wires, TCV1 - 2 FEMs 3 wires (EVB swapped) */
+	FEM_WIRING_19_OBSOLETE_TCV0_2_TCV1_2_SWAPPED  = 19,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 2 FEMs 2 wires (CL8060 4+2) */
+	FEM_WIRING_20_TCV0_2_TCV1_2                   = 20,
+	/* TCV0 - 4 FEMs 3 wires, TCV1 - 2 LNAs (RX only) (CL8066 4+2) */
+	FEM_WIRING_21_OBSOLETE_TCV0_4_TCV1_2          = 21,
+	FEM_WIRING_22_OBSOLETE                        = 22,
+	FEM_WIRING_23_TCV0_4_TCV1_4                   = 23,
+	FEM_WIRING_24_TCV0_6_TCV1_4                   = 24,
+	FEM_WIRING_25_TCV0_4_TCV1_2_MODE_0            = 25,
+	FEM_WIRING_26_TCV0_4_TCV1_2_MODE_1            = 26,
+	FEM_WIRING_27_TCV0_2_TCV1_1                   = 27,
+	FEM_WIRING_28_TCV0_4_TCV1_2                   = 28,
+	FEM_WIRING_29_TCV0_4_TCV1_2                   = 29,
+	FEM_WIRING_30_TCV0_4_TCV1_2                   = 30,
+	FEM_WIRING_31_TCV0_2_TCV1_1                   = 31,
+	FEM_WIRING_32_TCV0_4_TCV1_0                   = 32,
+	FEM_WIRING_33_TCV0_4_TCV1_4                   = 33,
+
+	FEM_WIRING_MAX,
+	FEM_WIRING_DEFAULT = 255
+};
+
+enum fem_type {
+	FEM_TYPE_TCV0    = 0,
+	FEM_TYPE_TCV1    = 1,
+	FEM_TYPE_ELASTIC = 2,
+	FEM_TYPE_SENSING = 3,
+
+	FEM_TYPE_MAX,
+};
+
+#define FEM_TYPE_STR(type) \
+	((type == FEM_TYPE_TCV0) ? "TCV0" : \
+	((type == FEM_TYPE_TCV1) ? "TCV1" : \
+	((type == FEM_TYPE_ELASTIC) ? "ELASTIC" : \
+	((type == FEM_TYPE_SENSING) ? "SENSING" : "ERROR"))))
+
+enum fem_mode {
+	FEM_MODE_LNA_BYPASS_ONLY = 0,
+	FEM_MODE_TX_ONLY = 1,
+	FEM_MODE_RX_ONLY = 2,
+
+	FEM_MODE_MAX,
+	FEM_MODE_OPERETIONAL = 255
+};
+
+struct cl_fem_params {
+	u8 wiring_id;
+	u16 lut[FEM_TYPE_MAX];
+	u16 lut_registers[TCV_MAX][FEM_LUT_AMOUNT_PER_MAC];
+	u16 lut_off_register[TCV_MAX];
+	u16 lut_off_register_list[FEM_TYPE_MAX];
+};
+
+struct cl_chip;
+struct cl_hw;
+
+int cl_fem_init(struct cl_chip *chip);
+int cl_fem_read_wiring_id(struct cl_chip *chip);
+int cl_fem_get_registers(struct cl_hw *cl_hw, u32 fem_data[FEM_REGISTERS_AMOUNT]);
+void cl_fem_set_dcoc_bypass(struct cl_hw *cl_hw);
+void cl_fem_dcoc_restore(struct cl_hw *cl_hw, u8 fem_mode);
+void cl_fem_set_iq_bypass(struct cl_hw *cl_hw);
+void cl_fem_iq_restore(struct cl_hw *cl_hw, u8 fem_mode);
+int cl_fem_update_conf_params(struct cl_chip *chip);
+bool cl_fem_wiring_id_is_evb(struct cl_chip *chip);
+
+#endif /* CL_PHY_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 52/96] cl8k: add platform.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (50 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 51/96] cl8k: add phy.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 53/96] cl8k: add platform.h viktor.barna
                   ` (43 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/platform.c | 392 ++++++++++++++++++++
 1 file changed, 392 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/platform.c

diff --git a/drivers/net/wireless/celeno/cl8k/platform.c b/drivers/net/wireless/celeno/cl8k/platform.c
new file mode 100644
index 000000000000..140505523fb2
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/platform.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/types.h>
+
+#include "e2p.h"
+#include "debug.h"
+#include "utils.h"
+#include "hw.h"
+#include "platform.h"
+
+static int cl_platform_update_idx_v1(struct cl_chip *chip)
+{
+	u8 i = 0;
+	u32 platform_id = 0;
+	struct cl_agc_platform_pack *app = chip->platform.app;
+	ssize_t buf_len = chip->platform.app_size;
+	ssize_t data_len = buf_len - sizeof(*app);
+	ssize_t offset = 0;
+	struct cl_platform_binding *platform = NULL;
+
+	if (cl_e2p_read(chip, (u8 *)&platform_id, SIZE_FEM_PLATFORM_ID, ADDR_FEM_PLATFORM_ID))
+		return -1;
+
+	cl_dbg_chip_verbose(chip,
+			    "platform_id: 0x%08x, "
+			    "customer_id: 0x%04x, board_id: 0x%02x, chip_id: 0x%x\n",
+			    platform_id,
+			    PLATFORM_CUSTOMER(platform_id),
+			    PLATFORM_BOARD(platform_id),
+			    PLATFORM_CHIP(platform_id));
+
+	while (offset <= data_len) {
+		struct cl_agc_tilv *tilv = (struct cl_agc_tilv *)((u8 *)app->data + offset);
+
+		if (tilv->t == CL_AGC_PACK_EOF || tilv->t == CL_AGC_PACK_UNDEFINED)
+			break;
+
+		if (tilv->t != CL_AGC_PACK_PLATFORM_BINDING)
+			goto next_tilv;
+
+		platform = (void *)tilv->v;
+		if (platform_id != platform->platform_id)
+			goto next_tilv;
+
+		cl_dbg_chip_verbose(chip, "%s\n", platform->platform_description);
+		chip->platform.idx = i;
+		return 0;
+next_tilv:
+		i += 1;
+		offset += sizeof(*tilv) + tilv->l;
+	}
+
+	if (IS_REAL_PHY(chip)) {
+		CL_DBG_ERROR_CHIP(chip, "Invalid platform_id 0x%08x\n", platform_id);
+
+		if (!chip->conf->ce_production_mode)
+			return -1;
+	}
+
+	return 0;
+}
+
+struct cl_platform_table *cl_platform_get_active_table(struct cl_chip *chip, u8 idx)
+{
+	bool is_active = (idx == chip->platform.idx);
+
+	if (idx >= cl_platform_get_tables_cnt(chip))
+		return NULL;
+
+	if (is_active && chip->platform.app)
+		return &chip->platform.table;
+
+	return NULL;
+}
+
+static int cl_calc_platforms_number(struct cl_agc_platform_pack *app, ssize_t buf_len)
+{
+	ssize_t data_len = buf_len - sizeof(*app);
+	ssize_t offset = 0;
+	int ret = 0;
+
+	while (offset <= data_len) {
+		struct cl_agc_tilv *tilv = (struct cl_agc_tilv *)((u8 *)app->data + offset);
+
+		if (tilv->t == CL_AGC_PACK_EOF || tilv->t == CL_AGC_PACK_UNDEFINED)
+			break;
+
+		if (tilv->t != CL_AGC_PACK_PLATFORM_BINDING)
+			goto next_tilv;
+
+		ret += 1;
+next_tilv:
+		offset += sizeof(*tilv) + tilv->l;
+	}
+
+	return ret;
+}
+
+static void *cl_find_tilv_data(struct cl_agc_platform_pack *app,
+			       ssize_t buf_len, u8 seeking_id, u8 seeking_type)
+{
+	ssize_t data_len = buf_len - sizeof(*app);
+	ssize_t offset = 0;
+	void *ret = NULL;
+
+	if (seeking_type >= CL_AGC_PACK_MAX)
+		return NULL;
+
+	while (offset <= data_len) {
+		struct cl_agc_tilv *tilv = (struct cl_agc_tilv *)((u8 *)app->data + offset);
+
+		if (tilv->t == CL_AGC_PACK_EOF || tilv->t == CL_AGC_PACK_UNDEFINED)
+			break;
+
+		if (tilv->t != seeking_type)
+			goto next_tilv;
+
+		if (tilv->i == seeking_id) {
+			ret = (void *)&tilv->v;
+			break;
+		}
+
+next_tilv:
+		offset += sizeof(*tilv) + tilv->l;
+	}
+
+	return ret;
+}
+
+static struct cl_platform_binding *cl_find_binding(struct cl_agc_platform_pack *app,
+						   ssize_t buf_len, u8 seeking_id)
+{
+	return cl_find_tilv_data(app, buf_len, seeking_id, CL_AGC_PACK_PLATFORM_BINDING);
+}
+
+static struct cl_agc_profile_per_bw *cl_find_agc_profile(struct cl_agc_platform_pack *app,
+							 ssize_t buf_len, u8 seeking_id)
+{
+	return cl_find_tilv_data(app, buf_len, seeking_id, CL_AGC_PACK_PROFILE);
+}
+
+static const u8 *cl_find_power_table(struct cl_agc_platform_pack *app,
+				     ssize_t buf_len, u8 seeking_id)
+{
+	return cl_find_tilv_data(app, buf_len, seeking_id, CL_AGC_PACK_POWER_TABLE);
+}
+
+static bool cl_is_valid_agc_profile(u8 profile_id)
+{
+	return (profile_id >= CL_AGC_PROFILE_FIRST) &&
+		(profile_id < CL_AGC_PROFILE_MAX);
+}
+
+static bool cl_is_valid_power_table(u8 table_id)
+{
+	return (table_id >= CL_POWER_TO_POWERWORD_CONV_TABLE_FIRST) &&
+		(table_id < CL_POWER_TO_POWERWORD_CONV_TABLE_MAX);
+}
+
+int cl_platform_get_tables_cnt(struct cl_chip *chip)
+{
+	return cl_calc_platforms_number(chip->platform.app, chip->platform.app_size);
+}
+
+int cl_platform_unpack_v1(struct cl_platform_table *table,
+			  struct cl_agc_platform_pack *app,
+			  ssize_t buf_len, u8 platform_idx)
+{
+	struct cl_platform_binding *binding = NULL;
+	u8 profile_id = CL_AGC_PROFILE_UNDEFINED;
+
+	binding = cl_find_binding(app, buf_len, platform_idx);
+	if (!binding)
+		return -ENODATA;
+
+	/* Find corresponding binding */
+	table->platform_id = binding->platform_id;
+	memcpy(table->platform_description, binding->platform_description,
+	       sizeof(table->platform_description));
+
+	/* Bind AGC profiles */
+	profile_id = binding->agc_profile[TCV0];
+	if (cl_is_valid_agc_profile(profile_id))
+		table->agc_profile[TCV0] = cl_find_agc_profile(app, buf_len, profile_id);
+
+	profile_id = binding->agc_profile[TCV1];
+	if (cl_is_valid_agc_profile(profile_id))
+		table->agc_profile[TCV1] = cl_find_agc_profile(app, buf_len, profile_id);
+
+	profile_id = binding->agc_profile_elastic[TCV0];
+	if (cl_is_valid_agc_profile(profile_id))
+		table->agc_profile_elastic[TCV0] = cl_find_agc_profile(app, buf_len, profile_id);
+
+	profile_id = binding->agc_profile_elastic[TCV1];
+	if (cl_is_valid_agc_profile(profile_id))
+		table->agc_profile_elastic[TCV1] = cl_find_agc_profile(app, buf_len, profile_id);
+
+	profile_id = binding->agc_profile_sensing;
+	if (cl_is_valid_agc_profile(profile_id))
+		table->agc_profile_sensing = cl_find_agc_profile(app, buf_len, profile_id);
+
+	/* Bind power tables */
+	if (cl_is_valid_power_table(binding->power_conv_table_2))
+		table->power_conv_table_2 = cl_find_power_table(app, buf_len,
+								binding->power_conv_table_2);
+
+	if (cl_is_valid_power_table(binding->power_conv_table_5))
+		table->power_conv_table_5 = cl_find_power_table(app, buf_len,
+								binding->power_conv_table_5);
+
+	if (cl_is_valid_power_table(binding->power_conv_table_6))
+		table->power_conv_table_6 = cl_find_power_table(app, buf_len,
+								binding->power_conv_table_6);
+
+	return 0;
+}
+
+static int cl_platform_unpack(struct cl_chip *chip)
+{
+	int ret = 0;
+	struct cl_agc_platform_pack *app = chip->platform.app;
+	ssize_t buf_len = chip->platform.app_size;
+
+	if (strncmp(app->magic, PLATFORM_PACK_MAGIC_V1, sizeof(app->magic)) != 0) {
+		cl_dbg_chip_err(chip,
+				"Magic differs, got %s, expected %s\n",
+				app->magic, PLATFORM_PACK_MAGIC_V1);
+		return -EINVAL;
+	}
+	if (le32_to_cpu(app->version) != PLATFORM_PACK_VERSION_V1) {
+		cl_dbg_chip_err(chip,
+				"Invalid pack version: %u\n",
+				le32_to_cpu(app->version));
+		return -EINVAL;
+	}
+
+	ret = cl_platform_update_idx_v1(chip);
+	if (ret)
+		return ret;
+
+	ret = cl_platform_unpack_v1(&chip->platform.table, app, buf_len,
+				    chip->platform.idx);
+	return ret;
+}
+
+int cl_platform_alloc(struct cl_chip *chip)
+{
+	char filename[CL_FILENAME_MAX];
+	size_t size = 0;
+	char *buf = NULL;
+	int ret = 0;
+
+	snprintf(filename, sizeof(filename), PLATFORM_PACK_FILENAME_V1);
+	size = cl_file_open_and_read(chip, filename, (char **)&buf);
+	if (!buf) {
+		cl_dbg_chip_err(chip, "AGC platform pack data buffer is empty\n");
+
+		ret = -ENODATA;
+		goto err;
+	}
+
+	chip->platform.app_size = size;
+	chip->platform.app = (struct cl_agc_platform_pack *)buf;
+
+	ret = cl_platform_unpack(chip);
+err:
+	return ret;
+}
+
+void cl_platform_dealloc(struct cl_chip *chip)
+{
+	if (chip->platform.app) {
+		kvfree(chip->platform.app);
+		chip->platform.app = NULL;
+		chip->platform.app_size = 0;
+	}
+}
+
+/* AGC PROFILE */
+#define AGC_PROFILE_BAND_MASK       0xff000000
+#define AGC_PROFILE_BRANCH_MASK     0x00ff0000
+#define AGC_PROFILE_VERSION_MASK    0x0000ff00
+
+#define AGC_PROFILE_BAND(profile) \
+	u32_get_bits(profile, AGC_PROFILE_BAND_MASK)
+#define AGC_PROFILE_BRANCH(profile) \
+	u32_get_bits(profile, AGC_PROFILE_BRANCH_MASK)
+#define AGC_PROFILE_VERSION(profile) \
+	u32_get_bits(profile, AGC_PROFILE_VERSION_MASK)
+
+#ifdef __BIG_ENDIAN_BITFIELD
+static void cl_agc_profile_to_le32(struct cl_agc_profile *profile)
+{
+	u32 i;
+	u32 size = sizeof(struct cl_agc_profile);
+	u32 *ptr = (u32 *)profile;
+
+	/* Make sure that size divides by 4 */
+	WARN_ON((size & 0x3) != 0);
+
+	for (i = 0; i < size / 4; i++)
+		ptr[i] = cpu_to_le32(ptr[i]);
+}
+#endif
+
+int cl_agc_params_fill(struct cl_hw *cl_hw, struct cl_agc_params *agc_params)
+{
+	u8 tcv_idx = cl_hw->tcv_idx;
+	u8 platform_idx = cl_hw->chip->platform.idx;
+	u8 bw = cl_hw->bw;
+	struct cl_platform_table *table = NULL;
+
+	memset(agc_params, 0, sizeof(struct cl_agc_params));
+
+	if (platform_idx == U8_MAX)
+		return 0;
+
+	table = cl_platform_get_active_table(cl_hw->chip, platform_idx);
+	if (!table)
+		return -EINVAL;
+
+	if (!table->agc_profile_elastic[tcv_idx] || cl_hw->num_antennas <= 2) {
+		u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+		if (table->agc_profile[tcv_idx]) {
+			agc_params->profile1.id = table->agc_profile[tcv_idx]->id;
+			agc_params->profile1.regs = table->agc_profile[tcv_idx]->regs[bw];
+		} else if (tcv_idx == TCV1 && table->agc_profile_sensing) {
+			agc_params->profile1.id = table->agc_profile_sensing->id;
+			agc_params->profile1.regs = table->agc_profile_sensing->regs[bw];
+		} else {
+			CL_DBG_ERROR(cl_hw, "Invalid tcv/sensing profile");
+			return -1;
+		}
+
+		agc_params->num_profiles = 1;
+		agc_params->ant_mask1 = ANT_MASK(cl_hw->num_antennas) << ant_shift;
+		agc_params->ant_mask2 = 0;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+		cl_agc_profile_to_le32(&agc_params->profile1);
+#endif
+	} else {
+		if (table->agc_profile[tcv_idx]) {
+			memcpy(&agc_params->profile1,
+			       table->agc_profile[tcv_idx],
+			       sizeof(struct cl_agc_profile));
+		} else {
+			CL_DBG_ERROR(cl_hw, "Invalid tcv profile");
+			return -1;
+		}
+
+		if (table->agc_profile_elastic[tcv_idx]) {
+			memcpy(&agc_params->profile2,
+			       table->agc_profile_elastic[tcv_idx],
+			       sizeof(struct cl_agc_profile));
+		} else {
+			CL_DBG_ERROR(cl_hw, "Invalid elastic profile");
+			return -1;
+		}
+
+		agc_params->num_profiles = 2;
+		agc_params->ant_mask1 = ANT_MASK(2);
+		agc_params->ant_mask2 = ANT_MASK(cl_hw->num_antennas - 2) << 2;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+		cl_agc_profile_to_le32(&agc_params->profile1);
+		cl_agc_profile_to_le32(&agc_params->profile2);
+#endif
+	}
+
+	return 0;
+}
+
+void cl_agc_params_dump_profile_id(char *buf, ssize_t buf_size, ssize_t *len,
+				   u32 id, const char *str)
+{
+	u8 band, branch, version;
+
+	band = AGC_PROFILE_BAND(id);
+	branch = AGC_PROFILE_BRANCH(id);
+	version = AGC_PROFILE_VERSION(id);
+
+	if (*buf) {
+		*len += scnprintf(buf + *len, buf_size - *len,
+				  "%s %u.%u.%u\n", str, band, branch, version);
+	} else {
+		pr_debug("%s %u.%u.%u\n", str, band, branch, version);
+	}
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 53/96] cl8k: add platform.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (51 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 52/96] cl8k: add platform.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 54/96] cl8k: add power.c viktor.barna
                   ` (42 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/platform.h | 196 ++++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/platform.h

diff --git a/drivers/net/wireless/celeno/cl8k/platform.h b/drivers/net/wireless/celeno/cl8k/platform.h
new file mode 100644
index 000000000000..d0268eded0c3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/platform.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_PLATFORM_H
+#define CL_PLATFORM_H
+
+#define PLATFORM_DESCRIPTION_LENGTH 100
+#define PLATFORM_CUSTOMER_MASK   0xffff0000
+#define PLATFORM_BOARD_MASK      0x0000ff00
+#define PLATFORM_CHIP_MASK       0x000000f0
+
+#define PLATFORM_CUSTOMER(platform) \
+	u32_get_bits(platform, PLATFORM_CUSTOMER_MASK)
+#define PLATFORM_BOARD(platform) \
+	u32_get_bits(platform, PLATFORM_BOARD_MASK)
+#define PLATFORM_CHIP(platform) \
+	u32_get_bits(platform, PLATFORM_CHIP_MASK)
+
+#define PLATFORM_PACK_VERSION_V1  1
+#define PLATFORM_PACK_MAGIC_V1    "CL8K-AGC-PPCK"
+#define PLATFORM_PACK_FILENAME_V1 "agcppk.bin"
+#define PLATFORM_PACK_MAGIC_LEN   16
+
+struct cl_platform_table {
+	u32 platform_id;
+	u8 platform_description[PLATFORM_DESCRIPTION_LENGTH];
+	struct cl_agc_profile_per_bw *agc_profile[TCV_MAX];
+	struct cl_agc_profile_per_bw *agc_profile_elastic[TCV_MAX];
+	struct cl_agc_profile_per_bw *agc_profile_sensing;
+	const u8 *power_conv_table_2;
+	const u8 *power_conv_table_5;
+	const u8 *power_conv_table_6;
+};
+
+enum cl_agc_pack_type {
+	CL_AGC_PACK_UNDEFINED,
+	CL_AGC_PACK_PLATFORM_BINDING,
+	CL_AGC_PACK_PROFILE,
+	CL_AGC_PACK_POWER_TABLE,
+	CL_AGC_PACK_EOF,
+
+	CL_AGC_PACK_MAX
+};
+
+enum cl_agc_profile_type {
+	CL_AGC_PROFILE_UNDEFINED,
+	CL_AGC_PROFILE_FIRST,
+	CL_AGC_PROFILE_2_1_9 = CL_AGC_PROFILE_FIRST,
+	CL_AGC_PROFILE_5_1_9,
+	CL_AGC_PROFILE_6_1_3,
+	CL_AGC_PROFILE_50_0_1,
+	CL_AGC_PROFILE_60_1_3,
+
+	CL_AGC_PROFILE_MAX
+};
+
+enum cl_power_table_type {
+	CL_POWER_TO_POWERWORD_CONV_TABLE_UNDEFINED,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_FIRST,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_COMMON_ID_0 = CL_POWER_TO_POWERWORD_CONV_TABLE_FIRST,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_COMMON_ID_1,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_COMMON_ID_2,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_ATHOS_B_ID_0,
+	CL_POWER_TO_POWERWORD_CONV_TABLE_ATHOS_B_ID_1,
+
+	CL_POWER_TO_POWERWORD_CONV_TABLE_MAX
+};
+
+struct cl_agc_platform_pack {
+	char magic[PLATFORM_PACK_MAGIC_LEN];
+	__le32 version;
+	u8 reserved[249];
+	u8 data[];
+} __packed;
+
+struct cl_agc_tilv {
+	u8 t;
+	u8 i;
+	u32 l;
+	u8 v[];
+} __packed;
+
+struct cl_platform_binding {
+	u32 platform_id;
+	u8 platform_description[PLATFORM_DESCRIPTION_LENGTH];
+	u8 agc_profile[TCV_MAX];
+	u8 agc_profile_elastic[TCV_MAX];
+	u8 agc_profile_sensing;
+	u8 power_conv_table_2;
+	u8 power_conv_table_5;
+	u8 power_conv_table_6;
+} __packed;
+
+struct cl_platform {
+	struct cl_agc_platform_pack *app;
+	ssize_t app_size;
+	struct cl_platform_table table;
+	u8 idx;
+};
+
+struct cl_platform_table *cl_platform_get_active_table(struct cl_chip *chip,
+						       u8 idx);
+int cl_platform_get_tables_cnt(struct cl_chip *chip);
+int cl_platform_unpack_v1(struct cl_platform_table *table,
+			  struct cl_agc_platform_pack *app,
+			  ssize_t buf_len, u8 platform_idx);
+int cl_platform_alloc(struct cl_chip *chip);
+void cl_platform_dealloc(struct cl_chip *chip);
+
+/**
+ * AGC (=Automatic Gain Control)
+ */
+
+struct cl_agc_reg {
+	u32 val;
+	u32 mask;
+};
+
+struct cl_agc_regs {
+	struct cl_agc_reg fsm_preset_p2;      /* 0x244 */
+	struct cl_agc_reg lna_thr_set0_ref2;  /* 0x25C */
+	struct cl_agc_reg lna_thr_set0_ref3;  /* 0x260 */
+	struct cl_agc_reg lna_thr_set1_ref2;  /* 0x264 */
+	struct cl_agc_reg lna_thr_set1_ref3;  /* 0x268 */
+	struct cl_agc_reg lna_thr_set2_ref2;  /* 0x26C */
+	struct cl_agc_reg lna_thr_set2_ref3;  /* 0x270 */
+	struct cl_agc_reg lna_gain_set0_ref2; /* 0x274 */
+	struct cl_agc_reg lna_gain_set0_ref3; /* 0x278 */
+	struct cl_agc_reg lna_nf_set0_ref2;   /* 0x27C */
+	struct cl_agc_reg lna_nf_set0_ref3;   /* 0x280 */
+	struct cl_agc_reg lna_icp1_set0_ref2; /* 0x284 */
+	struct cl_agc_reg lna_icp1_set0_ref3; /* 0x288 */
+	struct cl_agc_reg fsm_preset_p10;     /* 0x2A8 */
+	struct cl_agc_reg fsm_preset_p11;     /* 0x2AC */
+	struct cl_agc_reg fsm_preset_p12;     /* 0x2B0 */
+	struct cl_agc_reg ant_loss;           /* 0x300 */
+	struct cl_agc_reg gain_range;         /* 0x304 */
+	struct cl_agc_reg vga_ref0;           /* 0x308 */
+	struct cl_agc_reg lna_gain_set0_ref0; /* 0x30C */
+	struct cl_agc_reg lna_gain_set0_ref1; /* 0x310 */
+	struct cl_agc_reg lna_thr_set0_ref0;  /* 0x314 */
+	struct cl_agc_reg lna_thr_set0_ref1;  /* 0x318 */
+	struct cl_agc_reg lna_thr_set1_ref0;  /* 0x31C */
+	struct cl_agc_reg lna_thr_set1_ref1;  /* 0x320 */
+	struct cl_agc_reg lna_thr_set2_ref0;  /* 0x324 */
+	struct cl_agc_reg lna_thr_set2_ref1;  /* 0x328 */
+	struct cl_agc_reg lna_nf_set0_ref0;   /* 0x32C */
+	struct cl_agc_reg lna_nf_set0_ref1;   /* 0x330 */
+	struct cl_agc_reg lna_icp1_set0_ref0; /* 0x334 */
+	struct cl_agc_reg lna_icp1_set0_ref1; /* 0x338 */
+	struct cl_agc_reg saturation;         /* 0x364 */
+	struct cl_agc_reg ramp;               /* 0x36C */
+	struct cl_agc_reg dsp0;               /* 0x394 */
+	struct cl_agc_reg dsp1;               /* 0x398 */
+	struct cl_agc_reg dsp2;               /* 0x39C */
+	struct cl_agc_reg dsp3;               /* 0x3A0 */
+	struct cl_agc_reg lna_gain_set1_ref0; /* 0x590 */
+	struct cl_agc_reg lna_gain_set1_ref1; /* 0x594 */
+	struct cl_agc_reg lna_gain_set1_ref2; /* 0x598 */
+	struct cl_agc_reg lna_gain_set1_ref3; /* 0x59c */
+	struct cl_agc_reg lna_nf_set1_ref0;   /* 0x5A0 */
+	struct cl_agc_reg lna_nf_set1_ref1;   /* 0x5A4 */
+	struct cl_agc_reg lna_nf_set1_ref2;   /* 0x5A8 */
+	struct cl_agc_reg lna_nf_set1_ref3 ;  /* 0x5AC */
+	struct cl_agc_reg lna_icp1_set1_ref0; /* 0x5B0 */
+	struct cl_agc_reg lna_icp1_set1_ref1; /* 0x5B4 */
+	struct cl_agc_reg lna_icp1_set1_ref2; /* 0x5B8 */
+	struct cl_agc_reg lna_icp1_set1_ref3 ;/* 0x5BC */
+};
+
+struct cl_agc_profile_per_bw {
+	u32 id;
+	struct cl_agc_regs regs[CHNL_BW_MAX];
+};
+
+struct cl_agc_profile {
+	u32 id;
+	struct cl_agc_regs regs;
+};
+
+struct cl_agc_params {
+	u8 num_profiles;
+	u8 ant_mask1;
+	u8 ant_mask2;
+	struct cl_agc_profile profile1;
+	struct cl_agc_profile profile2;
+};
+
+struct cl_chip;
+
+int cl_agc_params_read_platform_id(struct cl_chip *chip);
+int cl_agc_params_fill(struct cl_hw *cl_hw, struct cl_agc_params *agc_params);
+void cl_agc_params_dump_profile_id(char *buf, ssize_t buf_size, ssize_t *len,
+				   u32 id, const char *str);
+
+#endif /* CL_PLATFORM_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 54/96] cl8k: add power.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (52 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 53/96] cl8k: add platform.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 55/96] cl8k: add power.h viktor.barna
                   ` (41 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power.c | 1123 ++++++++++++++++++++++
 1 file changed, 1123 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.c

diff --git a/drivers/net/wireless/celeno/cl8k/power.c b/drivers/net/wireless/celeno/cl8k/power.c
new file mode 100644
index 000000000000..ef62c4b7a332
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power.c
@@ -0,0 +1,1123 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/string.h>
+
+#include "reg/reg_access.h"
+#include "channel.h"
+#include "debug.h"
+#include "utils.h"
+#include "e2p.h"
+#include "power.h"
+
+static u8 cl_power_table_read(struct cl_hw *cl_hw)
+{
+	u8 pwr_table_id = 0;
+
+	if (cl_e2p_read(cl_hw->chip, &pwr_table_id, 1, ADDR_GEN_PWR_TABLE_ID + cl_hw->tcv_idx))
+		return U8_MAX;
+
+	return pwr_table_id;
+}
+
+static int cl_power_table_fill(struct cl_hw *cl_hw)
+{
+	u8 pwr_table_id = cl_power_table_read(cl_hw);
+	u8 platform_idx = cl_hw->chip->platform.idx;
+	struct cl_platform_table *table = NULL;
+
+	table = cl_platform_get_active_table(cl_hw->chip, platform_idx);
+	if (!table)
+		return cl_hw->chip->conf->ce_production_mode ? 0 : -1;
+
+	switch (pwr_table_id) {
+	case 0:
+		if (cl_band_is_5g(cl_hw)) {
+			memcpy(cl_hw->power_table_info.data->conv_table,
+			       table->power_conv_table_5,
+			       NUM_POWER_WORDS);
+			cl_hw->tx_power_version = 5;
+		} else if (IS_REAL_PHY(cl_hw->chip)) {
+			CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 5g only\n",
+				     pwr_table_id);
+
+			if (!cl_hw_is_prod_or_listener(cl_hw))
+				return -EINVAL;
+		}
+		break;
+	case 1:
+		if (cl_band_is_24g(cl_hw)) {
+			memcpy(cl_hw->power_table_info.data->conv_table,
+			       table->power_conv_table_2,
+			       NUM_POWER_WORDS);
+			cl_hw->tx_power_version = 25;
+		} else if (IS_REAL_PHY(cl_hw->chip)) {
+			CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 2.4g only\n",
+				     pwr_table_id);
+
+			if (!cl_hw_is_prod_or_listener(cl_hw))
+				return -1;
+		}
+		break;
+	case 2:
+		if (cl_band_is_6g(cl_hw)) {
+			memcpy(cl_hw->power_table_info.data->conv_table,
+			       table->power_conv_table_6,
+			       NUM_POWER_WORDS);
+			cl_hw->tx_power_version = 1;
+		} else if (IS_REAL_PHY(cl_hw->chip)) {
+			CL_DBG_ERROR(cl_hw, "Power table ID (%u) is valid for 6g only\n",
+				     pwr_table_id);
+
+			if (!cl_hw_is_prod_or_listener(cl_hw))
+				return -1;
+		}
+		break;
+	default:
+		if (IS_REAL_PHY(cl_hw->chip)) {
+			CL_DBG_ERROR(cl_hw, "Power table ID is not configured in EEPROM\n");
+
+			if (!cl_hw_is_prod_or_listener(cl_hw))
+				return -1;
+		}
+	}
+
+	cl_dbg_verbose(cl_hw, "Power table ID %u (V%u)\n", pwr_table_id, cl_hw->tx_power_version);
+
+	return 0;
+}
+
+int cl_power_table_alloc(struct cl_hw *cl_hw)
+{
+	struct cl_power_table_data *buf = NULL;
+	u32 len = sizeof(struct cl_power_table_data);
+	dma_addr_t phys_dma_addr;
+
+	buf = dma_alloc_coherent(cl_hw->chip->dev, len, &phys_dma_addr, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cl_hw->power_table_info.data = buf;
+	cl_hw->power_table_info.dma_addr = phys_dma_addr;
+
+	return cl_power_table_fill(cl_hw);
+}
+
+void cl_power_table_free(struct cl_hw *cl_hw)
+{
+	struct cl_power_table_info *power_table_info = &cl_hw->power_table_info;
+	u32 len = sizeof(struct cl_power_table_data);
+	dma_addr_t phys_dma_addr = power_table_info->dma_addr;
+
+	if (!power_table_info->data)
+		return;
+
+	dma_free_coherent(cl_hw->chip->dev, len, (void *)power_table_info->data, phys_dma_addr);
+	power_table_info->data = NULL;
+}
+
+static s32 convert_str_int_q8(s8 *str)
+{
+	s32 x, y;
+
+	if (!str)
+		return 0;
+	if (sscanf(str, "%d.%2d", &x, &y) == 0)
+		return 0;
+	if (!strstr(str, "."))
+		return x << 8;
+	if (y < 10 && (*(strstr(str, ".") + 1) != '0'))
+		y *= 10;
+	return ((x * 100 + y) << 8) / 100;
+}
+
+u8 cl_power_tx_ant(struct cl_hw *cl_hw, enum cl_wrs_mode mode)
+{
+	if (mode == WRS_MODE_CCK)
+		return hweight8(cl_hw->conf->ce_cck_tx_ant_mask);
+
+	if (mode <= WRS_MODE_VHT)
+		return min_t(u8, cl_hw->num_antennas, MAX_ANTENNAS_OFDM_HT_VHT);
+
+	return cl_hw->num_antennas;
+}
+
+s32 cl_power_antenna_gain_q8(struct cl_hw *cl_hw)
+{
+	u8 channel = cl_hw->channel;
+
+	if (channel >= 36 && channel <= 64)
+		return convert_str_int_q8(cl_hw->conf->ce_ant_gain_36_64);
+	else if (channel >= 100 && channel <= 140)
+		return convert_str_int_q8(cl_hw->conf->ce_ant_gain_100_140);
+	else if (channel >= 149 && channel < 165)
+		return convert_str_int_q8(cl_hw->conf->ce_ant_gain_149_165);
+	else
+		return convert_str_int_q8(cl_hw->conf->ce_ant_gain); /* 2.4g and 6g */
+}
+
+s32 cl_power_antenna_gain_q1(struct cl_hw *cl_hw)
+{
+	return cl_power_antenna_gain_q8(cl_hw) >> 7;
+}
+
+s32 cl_power_array_gain_q8(struct cl_hw *cl_hw, u8 tx_ant)
+{
+	/*
+	 * Format in NVRAM of ce_arr_gain=A,B,C,D,E,F
+	 * A is the array gain with 1 tx_ant, B is with 2 tx_ant and so on...
+	 */
+	int arr_gain_val = 0;
+	int arr_gain_len = 0;
+	int idx = 0;
+	char *arr_gain_cpy = NULL;
+	char *arr_gain_cpy_p = NULL;
+	char *arr_gain_str = NULL;
+
+	arr_gain_len = strlen(cl_hw->conf->ce_arr_gain) + 1;
+	arr_gain_cpy_p = kzalloc(arr_gain_len, GFP_ATOMIC);
+	arr_gain_cpy = arr_gain_cpy_p;
+
+	if (!arr_gain_cpy)
+		return 0;
+
+	/* Copy cl_hw->conf->ce_arr_gain so its value won't be changed by strsep() */
+	memcpy(arr_gain_cpy, cl_hw->conf->ce_arr_gain, arr_gain_len);
+
+	/* Arr_gain_str points to the array gain of 1 tx_ant */
+	arr_gain_str = strsep(&arr_gain_cpy, ",");
+
+	/* Only a single value in ce_arr_gain - same value will be applied for all tx_ant */
+	if (!arr_gain_cpy) {
+		arr_gain_val = convert_str_int_q8(arr_gain_str);
+	} else {
+		/* Keep iterating until getting to the correct ant idx */
+		for (idx = 1; arr_gain_str && (idx < tx_ant); idx++)
+			arr_gain_str = strsep(&arr_gain_cpy, ",");
+
+		arr_gain_val = arr_gain_str ? convert_str_int_q8(arr_gain_str) : 0;
+	}
+
+	kfree(arr_gain_cpy_p);
+
+	return arr_gain_val;
+}
+
+s8 cl_power_array_gain_q2(struct cl_hw *cl_hw, u8 tx_ant)
+{
+	return (s8)(cl_power_array_gain_q8(cl_hw, tx_ant) >> 6);
+}
+
+s32 cl_power_array_gain_q1(struct cl_hw *cl_hw, u8 tx_ant)
+{
+	return cl_power_array_gain_q8(cl_hw, tx_ant) >> 7;
+}
+
+static s32 cl_power_bf_gain_q8(struct cl_hw *cl_hw, u8 tx_ant, u8 nss)
+{
+	/*
+	 * Format in NVRAM of ce_bf_gain=A,B,C,D
+	 * A is the bf gain with 1 NSS, B is with 2 NSS and so on...
+	 */
+	int bf_gain_val = 0;
+	int bf_gain_len = 0;
+	int idx = 0;
+	char *bf_gain_cpy = NULL;
+	char *bf_gain_cpy_p = NULL;
+	char *bf_gain_str = NULL;
+	s8 *bf_gain_ptr = NULL;
+
+	if (tx_ant == 6) {
+		bf_gain_ptr = cl_hw->conf->ce_bf_gain_6_ant;
+	} else if (tx_ant == 5) {
+		bf_gain_ptr = cl_hw->conf->ce_bf_gain_5_ant;
+	} else if (tx_ant == 4) {
+		bf_gain_ptr = cl_hw->conf->ce_bf_gain_4_ant;
+	} else if (tx_ant == 3) {
+		bf_gain_ptr = cl_hw->conf->ce_bf_gain_3_ant;
+	} else if (tx_ant == 2) {
+		bf_gain_ptr = cl_hw->conf->ce_bf_gain_2_ant;
+	} else if (tx_ant == 1) {
+		goto out;
+	} else {
+		pr_err("[%s]: invalid tx_ant %u\n", __func__, tx_ant);
+		goto out;
+	}
+
+	bf_gain_len = strlen(bf_gain_ptr) + 1;
+	bf_gain_cpy_p = kzalloc(bf_gain_len, GFP_ATOMIC);
+	bf_gain_cpy = bf_gain_cpy_p;
+
+	if (!bf_gain_cpy)
+		return 0;
+
+	/* Copy cl_hw->conf->ce_bf_gain_*_ant so its value won't be changed by strsep() */
+	memcpy(bf_gain_cpy, bf_gain_ptr, bf_gain_len);
+
+	/* Bf_gain_str points to the bf gain of 1 SS */
+	bf_gain_str = strsep(&bf_gain_cpy, ",");
+
+	/* Keep iterating until getting to the correct ss index */
+	for (idx = 0; bf_gain_str && (idx < nss); idx++)
+		bf_gain_str = strsep(&bf_gain_cpy, ",");
+
+	bf_gain_val = bf_gain_str ? convert_str_int_q8(bf_gain_str) : 0;
+
+	kfree(bf_gain_cpy_p);
+ out:
+	return bf_gain_val;
+}
+
+s32 cl_power_bf_gain_q1(struct cl_hw *cl_hw, u8 tx_ant, u8 nss)
+{
+	return cl_power_bf_gain_q8(cl_hw, tx_ant, nss) >> 7;
+}
+
+static s32 cl_power_min_ant_q8(struct cl_hw *cl_hw)
+{
+	return convert_str_int_q8(cl_hw->conf->ci_min_ant_pwr);
+}
+
+s32 cl_power_min_ant_q1(struct cl_hw *cl_hw)
+{
+	return cl_power_min_ant_q8(cl_hw) >> 7;
+};
+
+s8 cl_power_bw_factor_q2(struct cl_hw *cl_hw, u8 bw)
+{
+	/*
+	 * Format in NVRAM of ci_bw_factor=A,B,C,D
+	 * A is the bw factor for bw 20MHz, B is for 40MHz and so on..
+	 */
+	int bw_factor_val = 0;
+	int bw_factor_len = 0;
+	int idx = 0;
+	char *bw_factor_cpy = NULL;
+	char *bw_factor_cpy_p = NULL;
+	char *bw_factor_str = NULL;
+
+	bw_factor_len = strlen(cl_hw->conf->ci_bw_factor) + 1;
+	bw_factor_cpy = kzalloc(bw_factor_len, GFP_ATOMIC);
+	bw_factor_cpy = bw_factor_cpy_p;
+
+	if (!bw_factor_cpy)
+		return 0;
+
+	/* Copy cl_hw->conf->ci_bw_factor so its value won't be changed by strsep() */
+	memcpy(bw_factor_cpy, cl_hw->conf->ci_bw_factor, bw_factor_len);
+
+	/* Bw_factor_str points to the bw factor of 20MHz */
+	bw_factor_str = strsep(&bw_factor_cpy, ",");
+
+	/* Only a single value in ci_bw_factor - same value will be applied for all bandwidths */
+	if (!bw_factor_cpy) {
+		bw_factor_val = convert_str_int_q8(bw_factor_str);
+	} else {
+		/* Keep iterating until getting to the correct bw index */
+		for (idx = 0; bw_factor_str && (idx < bw); idx++)
+			bw_factor_str = strsep(&bw_factor_cpy, ",");
+
+		bw_factor_val = bw_factor_str ? convert_str_int_q8(bw_factor_str) : 0;
+	}
+
+	kfree(bw_factor_cpy_p);
+
+	return (s8)(bw_factor_val >> 6);
+}
+
+static s32 cl_power_average_calib_q8(struct cl_hw *cl_hw, u8 ant_num)
+{
+	u8 ant = 0, ant_cnt = 0;
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	s32 total_calib_pow = 0;
+
+	if (chan_idx == INVALID_CHAN_IDX)
+		return 0;
+
+	for (ant = 0; ant < MAX_ANTENNAS && ant_cnt < ant_num; ant++) {
+		if (!(cl_hw->mask_num_antennas & BIT(ant)))
+			continue;
+
+		total_calib_pow += cl_hw->tx_pow_info[chan_idx][ant].power;
+		ant_cnt++;
+	}
+
+	return ((total_calib_pow << 8) / ant_num);
+}
+
+s32 cl_power_average_calib_q1(struct cl_hw *cl_hw, u8 ant_num)
+{
+	return cl_power_average_calib_q8(cl_hw, ant_num) >> 7;
+}
+
+static s32 cl_power_total_q8(struct cl_hw *cl_hw, s8 pwr_offset_q1, u8 tx_ant, u8 nss,
+			     enum cl_wrs_mode mode, bool is_auto_resp)
+{
+	s32 bf_gain_q8 =  0;
+	s32 antenna_gain_q8 = cl_power_antenna_gain_q8(cl_hw);
+	s32 array_gain_q8 = cl_power_array_gain_q8(cl_hw, tx_ant);
+	s32 pwr_offset_q8 = (s32)pwr_offset_q1 << 7;
+	s32 calib_power_q8 = cl_power_average_calib_q8(cl_hw, tx_ant);
+	s32 total_power_q8 = 0;
+
+	if (!is_auto_resp)
+		bf_gain_q8 = (mode > WRS_MODE_OFDM) ? cl_power_bf_gain_q8(cl_hw, tx_ant, nss) : 0;
+
+	total_power_q8 = calib_power_q8 + bf_gain_q8 + array_gain_q8 +
+		antenna_gain_q8 + pwr_offset_q8;
+
+	/* FCC calculation */
+	if (cl_hw->channel_info.standard == NL80211_DFS_FCC)
+		total_power_q8 -= min(bf_gain_q8 + antenna_gain_q8, 6 << 8);
+
+	return total_power_q8;
+}
+
+static s32 cl_power_eirp_delta_q1(struct cl_hw *cl_hw, u8 bw, s8 pwr_offset_q1, u8 tx_ant,
+				  u8 nss, enum cl_wrs_mode mode, bool is_auto_resp)
+{
+	/* Calculate total TX power */
+	s32 total_power_q8 = cl_power_total_q8(cl_hw, pwr_offset_q1, tx_ant, nss,
+					       mode, is_auto_resp);
+
+	/* EIRP power limit */
+	s32 eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+
+	/* Delta between total TX power and EIRP limit */
+	return (total_power_q8 - eirp_power_limit_q8) >> 7;
+}
+
+static s8 cl_power_calc_q1(struct cl_hw *cl_hw, s8 mcs_offset_q1, u8 bw, u8 nss,
+			   enum cl_wrs_mode mode, bool is_auto_resp, u8 *trunc_pwr_q1)
+{
+	/* Result is in 0.5dBm resolution */
+	u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+	s32 calib_power_q1 = cl_power_average_calib_q1(cl_hw, tx_ant);
+	s32 res_q1 = calib_power_q1 + mcs_offset_q1;
+	s32 min_pwr_q1 = POWER_MIN_DB_Q1;
+	u32 trunc_pwr_val_q1 = 0;
+	bool eirp_regulatory_en = cl_hw->chip->conf->ce_production_mode ?
+		cl_hw->conf->ce_eirp_regulatory_prod_en : cl_hw->conf->ce_eirp_regulatory_op_en;
+
+	if (cl_hw->channel_info.use_channel_info && eirp_regulatory_en) {
+		s32 delta_power_q1 = cl_power_eirp_delta_q1(cl_hw, bw, mcs_offset_q1,
+							    tx_ant, nss, mode, is_auto_resp);
+
+		if (delta_power_q1 > 0) {
+			/*
+			 * If tx power is greater than the limitation
+			 * subtract delta power from the result
+			 */
+			res_q1 -= delta_power_q1;
+			trunc_pwr_val_q1 = delta_power_q1;
+		}
+	}
+
+	if (is_auto_resp)
+		min_pwr_q1 += cl_power_min_ant_q1(cl_hw);
+
+	if (res_q1 < min_pwr_q1) {
+		trunc_pwr_val_q1 = max((s32)trunc_pwr_val_q1 - min_pwr_q1 - res_q1, 0);
+		res_q1 = min_pwr_q1;
+	}
+
+	if (is_auto_resp)
+		res_q1 += cl_power_array_gain_q1(cl_hw, tx_ant);
+
+	if (trunc_pwr_q1)
+		*trunc_pwr_q1 = (u8)trunc_pwr_val_q1;
+
+	return (s8)res_q1;
+}
+
+static s8 cl_power_offset_he(struct cl_hw *cl_hw, u8 bw, u8 mcs)
+{
+	u8 channel = cl_hw->channel;
+	s8 *ppmcs = NULL;
+
+	switch (cl_hw->conf->ci_band_num) {
+	case BAND_5G:
+		if (channel >= 36 && channel <= 64)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_he_36_64;
+		else if (channel >= 100 && channel <= 140)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_he_100_140;
+		else
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_he_149_165;
+		break;
+	case BAND_24G:
+		ppmcs = cl_hw->conf->ce_ppmcs_offset_he;
+		break;
+	case BAND_6G:
+		ppmcs = cl_hw->conf->ce_ppmcs_offset_he_6g;
+		break;
+	default:
+		return 0;
+	}
+
+	return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[bw];
+}
+
+static s8 cl_power_offset_ht_vht(struct cl_hw *cl_hw, u8 bw, u8 mcs)
+{
+	u8 channel = cl_hw->channel;
+	s8 *ppmcs = NULL;
+
+	switch (cl_hw->conf->ci_band_num) {
+	case BAND_5G:
+		if (channel >= 36 && channel <= 64)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_36_64;
+		else if (channel >= 100 && channel <= 140)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_100_140;
+		else
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ht_vht_149_165;
+		break;
+	case BAND_24G:
+		ppmcs = cl_hw->conf->ce_ppmcs_offset_ht;
+		break;
+	case BAND_6G:
+	default:
+		return 0;
+	}
+
+	return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[bw];
+}
+
+static s8 cl_power_offset_ofdm(struct cl_hw *cl_hw, u8 mcs)
+{
+	u8 channel = cl_hw->channel;
+	s8 *ppmcs = NULL;
+
+	switch (cl_hw->conf->ci_band_num) {
+	case BAND_5G:
+		if (channel >= 36 && channel <= 64)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_36_64;
+		else if (channel >= 100 && channel <= 140)
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_100_140;
+		else
+			ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm_149_165;
+		break;
+	case BAND_24G:
+		ppmcs = cl_hw->conf->ce_ppmcs_offset_ofdm;
+		break;
+	case BAND_6G:
+	default:
+		return 0;
+	}
+
+	return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[CHNL_BW_20];
+}
+
+static s8 cl_power_offset_cck(struct cl_hw *cl_hw, u8 mcs)
+{
+	s8 *ppmcs = cl_hw->conf->ce_ppmcs_offset_cck;
+
+	if (cl_band_is_24g(cl_hw))
+		return ppmcs[mcs] + cl_hw->conf->ce_ppbw_offset[CHNL_BW_20];
+
+	return 0;
+}
+
+s8 cl_power_offset_q1(struct cl_hw *cl_hw, u8 mode, u8 bw, u8 mcs)
+{
+	if (mode == WRS_MODE_HE)
+		return cl_power_offset_he(cl_hw, bw, mcs);
+	else if (mode == WRS_MODE_HT || mode == WRS_MODE_VHT)
+		return cl_power_offset_ht_vht(cl_hw, bw, mcs);
+	else if (mode == WRS_MODE_OFDM)
+		return cl_power_offset_ofdm(cl_hw, mcs);
+	else if (mode == WRS_MODE_CCK)
+		return cl_power_offset_cck(cl_hw, mcs);
+
+	return 0;
+}
+
+#define UPPER_POWER_MARGIN_Q2 (38 << 2)
+#define LOWER_POWER_MARGIN_Q2 (50 << 2)
+
+s8 cl_power_offset_check_margin(struct cl_hw *cl_hw, u8 bw, u8 ant_idx, s8 offset_q2)
+{
+	s8 new_offset_q2 = 0;
+	s8 bw_factor_q2 = cl_hw->power_db.bw_factor_q2[bw];
+	s8 ant_factor_q2 = cl_hw->power_db.ant_factor_q2[ant_idx];
+	s8 total_offset_upper_q2 = bw_factor_q2 + offset_q2;
+	s8 total_offset_lower_q2 = bw_factor_q2 + ant_factor_q2 + offset_q2;
+	bool upper_limit_valid = (total_offset_upper_q2 <= UPPER_POWER_MARGIN_Q2);
+	bool lower_limit_valid = (total_offset_lower_q2 <= LOWER_POWER_MARGIN_Q2);
+
+	if (upper_limit_valid && lower_limit_valid) {
+		return offset_q2;
+	} else if (!upper_limit_valid && lower_limit_valid) {
+		new_offset_q2 = UPPER_POWER_MARGIN_Q2 - bw_factor_q2;
+
+		return new_offset_q2;
+	} else if (upper_limit_valid && !lower_limit_valid) {
+		new_offset_q2 = LOWER_POWER_MARGIN_Q2 - bw_factor_q2 - ant_factor_q2;
+
+		return new_offset_q2;
+	}
+
+	new_offset_q2 = min(UPPER_POWER_MARGIN_Q2 - bw_factor_q2,
+			    LOWER_POWER_MARGIN_Q2 - bw_factor_q2 - ant_factor_q2);
+
+	return new_offset_q2;
+}
+
+static s32 cl_power_calc_total_from_eirp_q1(struct cl_hw *cl_hw, s32 tx_power, u8 nss,
+					    enum cl_wrs_mode mode, u8 *trunc_pwr_q1)
+{
+	s32 pwr_q1, total_pwr_q1, delta_pwr_q1 = 0;
+	u8 tx_ant;
+	s32 antenna_gain_q1;
+	s32 array_gain_q1;
+	s32 bf_gain_q1;
+	bool eirp_regulatory_en = cl_hw->chip->conf->ce_production_mode ?
+		cl_hw->conf->ce_eirp_regulatory_prod_en : cl_hw->conf->ce_eirp_regulatory_op_en;
+
+	pwr_q1 = tx_power << 1;
+
+	tx_ant = cl_power_tx_ant(cl_hw, mode);
+	array_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	antenna_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+	/* bf gain is not used for CCK or OFDM */
+	bf_gain_q1 = (mode > WRS_MODE_OFDM) ? cl_power_bf_gain_q1(cl_hw, tx_ant, nss) : 0;
+
+	/* FCC calculation */
+	if (cl_hw->channel_info.standard == NL80211_DFS_FCC)
+		pwr_q1 -= min(bf_gain_q1 + antenna_gain_q1, 6 << 1);
+
+	if (cl_hw->channel_info.use_channel_info && eirp_regulatory_en) {
+		s32 eirp_pwr_limit_q1;
+
+		eirp_pwr_limit_q1 = cl_chan_info_get_eirp_limit_q8(cl_hw, 0) >> 7;
+		if (pwr_q1 > eirp_pwr_limit_q1) {
+			delta_pwr_q1 = pwr_q1 - eirp_pwr_limit_q1;
+			pwr_q1 = eirp_pwr_limit_q1;
+		}
+	}
+
+	total_pwr_q1 = pwr_q1 - antenna_gain_q1 - array_gain_q1 - bf_gain_q1;
+	if (total_pwr_q1 < POWER_MIN_DB_Q1) {
+		delta_pwr_q1 = max(delta_pwr_q1 - (POWER_MIN_DB_Q1 - total_pwr_q1), 0);
+		total_pwr_q1 = POWER_MIN_DB_Q1;
+	}
+
+	if (trunc_pwr_q1)
+		*trunc_pwr_q1 = (u8)delta_pwr_q1;
+
+	return total_pwr_q1;
+}
+
+static s32 cl_power_calc_auto_resp_from_eirp_q1(struct cl_hw *cl_hw, s32 tx_power, u8 nss,
+						enum cl_wrs_mode mode)
+{
+	s32 auto_resp_total_pwr_q1, auto_resp_min_pwr_q1;
+	u8 tx_ant;
+	s32 array_gain_q1;
+	s32 total_pwr_q1;
+
+	auto_resp_min_pwr_q1 = POWER_MIN_DB_Q1 + cl_power_min_ant_q1(cl_hw);
+	tx_ant = cl_power_tx_ant(cl_hw, mode);
+	array_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	total_pwr_q1 = cl_power_calc_total_from_eirp_q1(cl_hw, tx_power, nss, mode, NULL);
+
+	auto_resp_total_pwr_q1 = array_gain_q1 + total_pwr_q1;
+	if (auto_resp_total_pwr_q1 < auto_resp_min_pwr_q1)
+		auto_resp_total_pwr_q1 = auto_resp_min_pwr_q1;
+
+	return auto_resp_total_pwr_q1;
+}
+
+static s8 cl_calc_ant_pwr_q1(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs,
+			     enum cl_wrs_mode mode, u8 *trunc_val)
+{
+	s32 eirp_pwr = 0;
+	s8 ant_pwr_q1;
+
+	eirp_pwr = cl_hw->new_tx_power;
+	if (eirp_pwr) {
+		ant_pwr_q1 = cl_power_calc_total_from_eirp_q1(cl_hw, eirp_pwr, nss,
+							      mode, trunc_val);
+	} else {
+		s8 pwr_offset_q1;
+
+		pwr_offset_q1 = cl_power_offset_q1(cl_hw, mode, bw, mcs);
+		ant_pwr_q1 = cl_power_calc_q1(cl_hw, pwr_offset_q1, bw, nss,
+					      mode, false, trunc_val);
+	}
+	return ant_pwr_q1;
+}
+
+static s8 cl_calc_auto_resp_pwr_q1(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs,
+				   enum cl_wrs_mode mode)
+{
+	s32 eirp_pwr = 0;
+	s8 auto_resp_pwr_q1;
+
+	eirp_pwr = cl_hw->new_tx_power;
+	if (eirp_pwr) {
+		auto_resp_pwr_q1 = cl_power_calc_auto_resp_from_eirp_q1(cl_hw, eirp_pwr,
+									nss, mode);
+	} else {
+		s8 pwr_offset_q1;
+
+		pwr_offset_q1 = cl_power_offset_q1(cl_hw, mode, bw, mcs);
+		auto_resp_pwr_q1 = cl_power_calc_q1(cl_hw, pwr_offset_q1, bw, nss,
+						    mode, true, NULL);
+	}
+	return auto_resp_pwr_q1;
+}
+
+static void cl_power_tables_update_cck(struct cl_hw *cl_hw,
+				       struct cl_pwr_tables *pwr_tables)
+{
+	u8 mcs;
+	u8 trunc_value = 0;
+
+	/* CCK - Enforce EIRP limitations */
+	for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+		pwr_tables->ant_pwr_cck[mcs] = cl_calc_ant_pwr_q1(cl_hw, 0, 0, mcs, WRS_MODE_CCK,
+								  &trunc_value);
+
+		cl_hw->pwr_trunc.cck[mcs] = trunc_value;
+
+		/* Auto response */
+		pwr_tables->pwr_auto_resp_cck[mcs] = cl_calc_auto_resp_pwr_q1(cl_hw, 0, 0, mcs,
+									      WRS_MODE_CCK);
+	}
+}
+
+static void cl_power_tables_update_ofdm(struct cl_hw *cl_hw,
+					struct cl_pwr_tables *pwr_tables)
+{
+	u8 mcs;
+	u8 trunc_value = 0;
+
+	/* OFDM - Enforce EIRP limitations */
+	for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+		pwr_tables->ant_pwr_ofdm[mcs] = cl_calc_ant_pwr_q1(cl_hw, 0, 0, mcs, WRS_MODE_OFDM,
+								   &trunc_value);
+		cl_hw->pwr_trunc.ofdm[mcs] = trunc_value;
+
+		/* Auto response */
+		pwr_tables->pwr_auto_resp_ofdm[mcs] = cl_calc_auto_resp_pwr_q1(cl_hw, 0, 0, mcs,
+									       WRS_MODE_OFDM);
+	}
+}
+
+static u8 cl_power_tables_update_ht_vht(struct cl_hw *cl_hw,
+					struct cl_pwr_tables *pwr_tables)
+{
+	bool is_24g = cl_band_is_24g(cl_hw);
+	bool is_5g = cl_band_is_5g(cl_hw);
+	u8 bw;
+	u8 nss;
+	u8 mcs;
+	u8 trunc_value = 0;
+	u8 min_bw_idx_limit_vht = 0;
+	u8 max_mcs_ht_vht = (is_5g || (is_24g && cl_hw->conf->ci_vht_cap_24g)) ?
+		WRS_MCS_MAX_VHT : WRS_MCS_MAX_HT;
+	s16 min_bw_limit = 0;
+	s32 eirp_power_limit_q8;
+
+	for (bw = 0, min_bw_limit = 0xFFFF; bw < cl_max_bw_idx(WRS_MODE_VHT, is_24g); bw++) {
+		if (!cl_hw_is_prod_or_listener(cl_hw) &&
+		    !cl_chan_info_get(cl_hw, cl_hw->channel, bw))
+			continue;
+
+		/* Find lowest EIRP power limitation among all bw for auto resp calculations */
+		eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+		if (eirp_power_limit_q8 < min_bw_limit) {
+			min_bw_limit = eirp_power_limit_q8;
+			min_bw_idx_limit_vht = bw;
+		}
+
+		/* HT/VHT - Enforce EIRP limitations */
+		for (mcs = 0; mcs < max_mcs_ht_vht; mcs++) {
+			for (nss = 0; nss < PWR_TBL_VHT_BF_SIZE; nss++) {
+				pwr_tables->ant_pwr_ht_vht[bw][mcs][nss] =
+					cl_calc_ant_pwr_q1(cl_hw, bw, nss, mcs, WRS_MODE_VHT,
+							   &trunc_value);
+				cl_hw->pwr_trunc.ht_vht[bw][mcs][nss] = trunc_value;
+			}
+		}
+	}
+
+	/* Auto resp HT/VHT - Enforce EIRP limitations */
+	for (mcs = 0; mcs < max_mcs_ht_vht; mcs++)
+		pwr_tables->pwr_auto_resp_ht_vht[mcs] =
+			cl_calc_auto_resp_pwr_q1(cl_hw, min_bw_idx_limit_vht, 0, mcs,
+						 WRS_MODE_VHT);
+
+	return min_bw_idx_limit_vht;
+}
+
+static u8 cl_power_tables_update_he(struct cl_hw *cl_hw,
+				    struct cl_pwr_tables *pwr_tables)
+{
+	bool is_24g = cl_band_is_24g(cl_hw);
+	u8 bw;
+	u8 nss;
+	u8 mcs;
+	u8 trunc_value = 0;
+	u8 min_bw_idx_limit_he = 0;
+	s16 min_bw_limit = 0;
+	s32 eirp_power_limit_q8;
+
+	for (bw = 0, min_bw_limit = 0xFFFF; bw < cl_max_bw_idx(WRS_MODE_HE, is_24g); bw++) {
+		if (!cl_hw_is_prod_or_listener(cl_hw) &&
+		    !cl_chan_info_get(cl_hw, cl_hw->channel, bw))
+			continue;
+
+		/* Find lowest EIRP power limitation among all bw for auto resp calculations */
+		eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+		if (eirp_power_limit_q8 < min_bw_limit) {
+			min_bw_limit = eirp_power_limit_q8;
+			min_bw_idx_limit_he = bw;
+		}
+
+		/* HE - Enforce EIRP limitations */
+		for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+			for (nss = 0; nss < PWR_TBL_HE_BF_SIZE; nss++) {
+				pwr_tables->ant_pwr_he[bw][mcs][nss] =
+					cl_calc_ant_pwr_q1(cl_hw, bw, nss, mcs, WRS_MODE_HE,
+							   &trunc_value);
+				cl_hw->pwr_trunc.he[bw][mcs][nss] = trunc_value;
+			}
+		}
+	}
+
+	/* Auto resp HE - Enforce EIRP limitations */
+	for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++)
+		pwr_tables->pwr_auto_resp_he[mcs] =
+			cl_calc_auto_resp_pwr_q1(cl_hw, min_bw_idx_limit_he, 0, mcs, WRS_MODE_HE);
+
+	return min_bw_idx_limit_he;
+}
+
+static u8 cl_power_calc_max(struct cl_hw *cl_hw, u8 bw, enum cl_wrs_mode mode)
+{
+	u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+	/* Total TX power - pass is_auto_resp = true in order to ignore bf gain */
+	s32 total_power_q8 = cl_power_total_q8(cl_hw, 0, tx_ant, 0, mode, true);
+	/* EIRP power limit */
+	s32 eirp_power_limit_q8 = cl_chan_info_get_eirp_limit_q8(cl_hw, bw);
+
+	return (min(total_power_q8, eirp_power_limit_q8) >> 8);
+}
+
+static s8 cl_power_vns_calc_q1(struct cl_hw *cl_hw, u8 bw,
+			       enum cl_wrs_mode mode, bool is_auto_resp)
+{
+	u8 max_tx_pwr = cl_power_calc_max(cl_hw, bw, mode);
+	u8 tx_ant = cl_power_tx_ant(cl_hw, mode);
+	s32 vns_pwr_limit_q8 = min_t(u8, cl_hw->conf->ci_vns_pwr_limit, max_tx_pwr) << 8;
+	s32 antenna_gain_q8 = cl_power_antenna_gain_q8(cl_hw);
+	s32 array_gain_q8 = (is_auto_resp ? 0 : cl_power_array_gain_q8(cl_hw, tx_ant));
+	s32 min_ant_pwr_q8 = cl_power_min_ant_q8(cl_hw);
+	s32 min_pwr_q8 = is_auto_resp ? (POWER_MIN_DB_Q8 + min_ant_pwr_q8) : POWER_MIN_DB_Q8;
+	s32 res_q8 = vns_pwr_limit_q8 - antenna_gain_q8 - array_gain_q8;
+
+	if (res_q8 < min_pwr_q8)
+		res_q8 = min_pwr_q8;
+
+	/* Result should be in 0.5dBm resolution */
+	return (s8)(res_q8 >> 7);
+}
+
+static void cl_power_tables_update_vns(struct cl_hw *cl_hw,
+				       struct cl_pwr_tables *pwr_tables,
+				       u8 min_bw_idx_limit_vht,
+				       u8 min_bw_idx_limit_he)
+{
+	/* VNS */
+	pwr_tables->ant_pwr_vns_he =
+		cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_he, WRS_MODE_HE, false);
+	pwr_tables->ant_pwr_vns_ht_vht =
+		cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_vht, WRS_MODE_VHT, false);
+	pwr_tables->ant_pwr_vns_ofdm =
+		cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_OFDM, false);
+	pwr_tables->ant_pwr_vns_cck =
+		cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_CCK, false);
+
+	/* Auto response VNS */
+	pwr_tables->pwr_auto_resp_vns_he =
+		cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_he, WRS_MODE_HE, true);
+	pwr_tables->pwr_auto_resp_vns_ht_vht =
+		cl_power_vns_calc_q1(cl_hw, min_bw_idx_limit_vht, WRS_MODE_VHT, true);
+	pwr_tables->pwr_auto_resp_vns_ofdm =
+		cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_OFDM, true);
+	pwr_tables->pwr_auto_resp_vns_cck =
+		cl_power_vns_calc_q1(cl_hw, 0, WRS_MODE_CCK, true);
+}
+
+static void cl_power_tables_update_by_offset(struct cl_hw *cl_hw,
+					     struct cl_pwr_tables *pwr_tables,
+					     s8 offset)
+{
+	u8 mcs = 0;
+	u8 bw = 0;
+	u8 nss = 0;
+
+	/* CCK - Enforce EIRP limitations */
+	for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+		pwr_tables->ant_pwr_cck[mcs] += offset;
+
+		/* Auto response */
+		pwr_tables->pwr_auto_resp_cck[mcs] += offset;
+	}
+
+	/* OFDM - Enforce EIRP limitations */
+	for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+		pwr_tables->ant_pwr_ofdm[mcs] += offset;
+
+		/* Auto response */
+		pwr_tables->pwr_auto_resp_ofdm[mcs] += offset;
+	}
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		/* HT/VHT - Enforce EIRP limitations */
+		for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++) {
+			for (nss = 0; nss < PWR_TBL_VHT_BF_SIZE; nss++)
+				pwr_tables->ant_pwr_ht_vht[bw][mcs][nss] += offset;
+
+			/*
+			 * Auto response:
+			 * always with disabled BF so the offset of the last nss is used
+			 */
+			pwr_tables->pwr_auto_resp_ht_vht[mcs] += offset;
+		}
+
+		/* HE - Enforce EIRP limitations */
+		for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+			for (nss = 0; nss < PWR_TBL_HE_BF_SIZE; nss++)
+				pwr_tables->ant_pwr_he[bw][mcs][nss] += offset;
+
+			/*
+			 * Auto response:
+			 * always with disabled BF so the offset of the last nss is used
+			 */
+			pwr_tables->pwr_auto_resp_he[mcs] += offset;
+		}
+	}
+}
+
+static s8 cl_power_get_offset(u16 percentage)
+{
+	if (percentage >= 94)
+		return 0;
+	else if (percentage >= 84)
+		return -1; /* -0.5dBm */
+	else if (percentage >= 75)
+		return -2; /* -1dBm */
+	else if (percentage >= 67)
+		return -3; /* -1.5dBm */
+	else if (percentage >= 59)
+		return -4; /* -2dBm */
+	else if (percentage >= 54)
+		return -5; /* -2.5dBm */
+	else if (percentage >= 48)
+		return -6; /* -3dBm */
+	else if (percentage >= 43)
+		return -7; /* -3.5dBm */
+	else if (percentage >= 38)
+		return -8; /* -4dBm */
+	else if (percentage >= 34)
+		return -9; /* -4.5dBm */
+	else if (percentage >= 30)
+		return -10; /* -5dBm */
+	else if (percentage >= 27)
+		return -11; /* -5.5dBm */
+	else if (percentage >= 24)
+		return -12; /* -6dBm */
+	else if (percentage >= 22)
+		return -13; /* -6.5dBm */
+	else if (percentage >= 19)
+		return -14; /* -7dBm */
+	else if (percentage >= 17)
+		return -15; /* -7.5dBm */
+	else if (percentage >= 15)
+		return -16; /* -8dBm */
+	else if (percentage >= 14)
+		return -17; /* -8.5dBm */
+	else if (percentage >= 12)
+		return -18; /* -9dBm */
+	else if (percentage >= 11)
+		return -19; /* -9.5dBm */
+	else if (percentage >= 10)
+		return -20; /* -10dBm */
+	else if (percentage >= 9)
+		return -21; /* -10.5dBm */
+	else if (percentage >= 8)
+		return -22; /* -11dBm */
+	else if (percentage >= 7)
+		return -23; /* -11.5dBm */
+	else if (percentage >= 6)
+		return -24; /* -12dBm */
+	else if (percentage >= 5)
+		return -26; /* -13dBm */
+	else if (percentage >= 4)
+		return -28; /* -14dBm */
+	else if (percentage >= 3)
+		return -30; /* -15dBm */
+	else if (percentage >= 2)
+		return -34; /* -17dBm */
+	else if (percentage >= 1)
+		return -40; /* -20dBm */
+
+	/* Should not get here */
+	return 0;
+}
+
+static void cl_power_control_apply_percentage(struct cl_hw *cl_hw)
+{
+	struct cl_power_db *power_db = &cl_hw->power_db;
+	u8 percentage = cl_hw->conf->ce_tx_power_control;
+
+	power_db->curr_percentage = percentage;
+
+	if (percentage != 100) {
+		power_db->curr_offset = cl_power_get_offset(percentage);
+		cl_power_tables_update_by_offset(cl_hw,
+						 &cl_hw->phy_data_info.data->pwr_tables,
+						 power_db->curr_offset);
+	}
+}
+
+void cl_power_tables_update(struct cl_hw *cl_hw, struct cl_pwr_tables *pwr_tables)
+{
+	bool is_24g = cl_band_is_24g(cl_hw);
+	bool is_6g = cl_band_is_6g(cl_hw);
+	u8 min_bw_idx_limit_he = 0;
+	u8 min_bw_idx_limit_vht = 0;
+
+	memset(pwr_tables, 0, sizeof(struct cl_pwr_tables));
+
+	if (is_24g)
+		cl_power_tables_update_cck(cl_hw, pwr_tables);
+
+	cl_power_tables_update_ofdm(cl_hw, pwr_tables);
+
+	if (!is_6g)
+		min_bw_idx_limit_vht = cl_power_tables_update_ht_vht(cl_hw, pwr_tables);
+
+	min_bw_idx_limit_he = cl_power_tables_update_he(cl_hw, pwr_tables);
+
+	cl_hw->new_tx_power = 0;
+
+	cl_power_tables_update_vns(cl_hw, pwr_tables, min_bw_idx_limit_vht, min_bw_idx_limit_he);
+
+	cl_power_control_apply_percentage(cl_hw);
+}
+
+static s32 cl_power_get_max_cck(struct cl_hw *cl_hw)
+{
+	struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+	u8 mcs = 0;
+	u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_CCK);
+	s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+	s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	s32 total_pwr_q1 = 0;
+	s32 max_pwr_q1 = 0;
+
+	for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++) {
+		total_pwr_q1 = pwr_tables->ant_pwr_cck[mcs] + ant_gain_q1 + arr_gain_q1;
+
+		if (total_pwr_q1 > max_pwr_q1)
+			max_pwr_q1 = total_pwr_q1;
+	}
+
+	return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_ofdm(struct cl_hw *cl_hw)
+{
+	struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+	u8 mcs = 0;
+	u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_OFDM);
+	s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+	s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	s32 total_pwr_q1 = 0;
+	s32 max_pwr_q1 = 0;
+
+	for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++) {
+		total_pwr_q1 = pwr_tables->ant_pwr_ofdm[mcs] + ant_gain_q1 + arr_gain_q1;
+
+		if (total_pwr_q1 > max_pwr_q1)
+			max_pwr_q1 = total_pwr_q1;
+	}
+
+	return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_ht_vht(struct cl_hw *cl_hw)
+{
+	struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+	u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_VHT);
+	u8 mcs = 0;
+	u8 bw = 0;
+	u8 bf = 0;
+	s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+	s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	s32 total_pwr_q1 = 0;
+	s32 max_pwr_q1 = 0;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++) {
+			for (bf = 0; bf < PWR_TBL_VHT_BF_SIZE; bf++) {
+				total_pwr_q1 = pwr_tables->ant_pwr_ht_vht[bw][mcs][bf] +
+					ant_gain_q1 + arr_gain_q1;
+
+				if (total_pwr_q1 > max_pwr_q1)
+					max_pwr_q1 = total_pwr_q1;
+			}
+		}
+	}
+
+	return max_pwr_q1;
+}
+
+static s32 cl_power_get_max_he(struct cl_hw *cl_hw)
+{
+	struct cl_pwr_tables *pwr_tables = &cl_hw->phy_data_info.data->pwr_tables;
+	u8 tx_ant = cl_power_tx_ant(cl_hw, WRS_MODE_HE);
+	u8 mcs = 0;
+	u8 bw = 0;
+	u8 bf = 0;
+	s32 ant_gain_q1 = cl_power_antenna_gain_q1(cl_hw);
+	s32 arr_gain_q1 = cl_power_array_gain_q1(cl_hw, tx_ant);
+	s32 total_pwr_q1 = 0;
+	s32 max_pwr_q1 = 0;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++) {
+		for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++) {
+			for (bf = 0; bf < PWR_TBL_HE_BF_SIZE; bf++) {
+				total_pwr_q1 = pwr_tables->ant_pwr_he[bw][mcs][bf] +
+					ant_gain_q1 + arr_gain_q1;
+
+				if (total_pwr_q1 > max_pwr_q1)
+					max_pwr_q1 = total_pwr_q1;
+			}
+		}
+	}
+
+	return max_pwr_q1;
+}
+
+s32 cl_power_get_max(struct cl_hw *cl_hw)
+{
+	bool is_24g = cl_band_is_24g(cl_hw);
+	bool is_6g = cl_band_is_6g(cl_hw);
+	s32 max_pwr_cck_q1 = is_24g ? cl_power_get_max_cck(cl_hw) : S32_MIN;
+	s32 max_pwr_ofdm_q1 = cl_power_get_max_ofdm(cl_hw);
+	s32 max_pwr_ht_vht_q1 = !is_6g ? cl_power_get_max_ht_vht(cl_hw) : S32_MIN;
+	s32 max_pwr_he_q1 = cl_power_get_max_he(cl_hw);
+	s32 max_pwr_q1 = 0;
+
+	max_pwr_q1 = max(max_pwr_q1, max_pwr_cck_q1);
+	max_pwr_q1 = max(max_pwr_q1, max_pwr_ofdm_q1);
+	max_pwr_q1 = max(max_pwr_q1, max_pwr_ht_vht_q1);
+	max_pwr_q1 = max(max_pwr_q1, max_pwr_he_q1);
+
+	return (max_pwr_q1 >> 1);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 55/96] cl8k: add power.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (53 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 54/96] cl8k: add power.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 56/96] cl8k: add radio.c viktor.barna
                   ` (40 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/power.h | 90 ++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/power.h

diff --git a/drivers/net/wireless/celeno/cl8k/power.h b/drivers/net/wireless/celeno/cl8k/power.h
new file mode 100644
index 000000000000..cd1d36492317
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/power.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_POWER_H
+#define CL_POWER_H
+
+#define NUM_POWER_WORDS  256
+#define POWER_MIN_DB     -10
+#define POWER_MIN_DB_Q1  (POWER_MIN_DB << 1)
+#define POWER_MIN_DB_Q8  (POWER_MIN_DB << 8)
+#define POWER_OFFSET_RES 4
+
+struct cl_power_table_data {
+	u8 conv_table[NUM_POWER_WORDS];
+};
+
+struct cl_power_table_info {
+	struct cl_power_table_data *data;
+	u32 dma_addr;
+};
+
+#define PWR_TBL_HE_BF_SIZE  (WRS_SS_MAX + 1)
+#define PWR_TBL_VHT_BF_SIZE WRS_SS_MAX
+
+/*
+ * Structure containing the power tables
+ * All values are in resolution of 0.5dBm
+ */
+struct cl_pwr_tables {
+	/* Regular Tx */
+	s8 ant_pwr_he[CHNL_BW_MAX][WRS_MCS_MAX_HE][PWR_TBL_HE_BF_SIZE];
+	s8 ant_pwr_ht_vht[CHNL_BW_MAX][WRS_MCS_MAX_VHT][PWR_TBL_VHT_BF_SIZE];
+	s8 ant_pwr_ofdm[WRS_MCS_MAX_OFDM];
+	s8 ant_pwr_cck[WRS_MCS_MAX_CCK];
+	/* VNS */
+	s8 ant_pwr_vns_he;
+	s8 ant_pwr_vns_ht_vht;
+	s8 ant_pwr_vns_ofdm;
+	s8 ant_pwr_vns_cck;
+	/* Auto response */
+	s8 pwr_auto_resp_he[WRS_MCS_MAX_HE];
+	s8 pwr_auto_resp_ht_vht[WRS_MCS_MAX_VHT];
+	s8 pwr_auto_resp_ofdm[WRS_MCS_MAX_OFDM];
+	s8 pwr_auto_resp_cck[WRS_MCS_MAX_CCK];
+	/* Auto response VNS */
+	s8 pwr_auto_resp_vns_he;
+	s8 pwr_auto_resp_vns_ht_vht;
+	s8 pwr_auto_resp_vns_ofdm;
+	s8 pwr_auto_resp_vns_cck;
+};
+
+struct cl_power_db {
+	u8 curr_percentage;
+	s8 curr_offset;
+	/* Used to validate margins of MAC power */
+	s8 bw_factor_q2[CHNL_BW_MAX];
+	s8 ant_factor_q2[MAX_ANTENNAS];
+};
+
+struct cl_tx_power_info {
+	s8 power;
+	s8 offset;
+	s8 temperature;
+};
+
+struct cl_power_truncate {
+	u8 he[CHNL_BW_MAX][WRS_MCS_MAX_HE][PWR_TBL_HE_BF_SIZE];
+	u8 ht_vht[CHNL_BW_MAX][WRS_MCS_MAX_VHT][PWR_TBL_VHT_BF_SIZE];
+	u8 ofdm[WRS_MCS_MAX_OFDM];
+	u8 cck[WRS_MCS_MAX_CCK];
+};
+
+int cl_power_table_alloc(struct cl_hw *cl_hw);
+void cl_power_table_free(struct cl_hw *cl_hw);
+u8 cl_power_tx_ant(struct cl_hw *cl_hw, enum cl_wrs_mode mode);
+s32 cl_power_antenna_gain_q8(struct cl_hw *cl_hw);
+s32 cl_power_antenna_gain_q1(struct cl_hw *cl_hw);
+s32 cl_power_array_gain_q8(struct cl_hw *cl_hw, u8 tx_ant);
+s8 cl_power_array_gain_q2(struct cl_hw *cl_hw, u8 tx_ant);
+s32 cl_power_array_gain_q1(struct cl_hw *cl_hw, u8 tx_ant);
+s32 cl_power_bf_gain_q1(struct cl_hw *cl_hw, u8 tx_ant, u8 nss);
+s32 cl_power_min_ant_q1(struct cl_hw *cl_hw);
+s8 cl_power_bw_factor_q2(struct cl_hw *cl_hw, u8 bw);
+s32 cl_power_average_calib_q1(struct cl_hw *cl_hw, u8 ant_num);
+s8 cl_power_offset_q1(struct cl_hw *cl_hw, u8 mode, u8 bw, u8 mcs);
+s8 cl_power_offset_check_margin(struct cl_hw *cl_hw, u8 bw, u8 ant_idx, s8 offset_q2);
+void cl_power_tables_update(struct cl_hw *cl_hw, struct cl_pwr_tables *pwr_tables);
+s32 cl_power_get_max(struct cl_hw *cl_hw);
+
+#endif /* CL_POWER_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 56/96] cl8k: add radio.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (54 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 55/96] cl8k: add power.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 57/96] cl8k: add radio.h viktor.barna
                   ` (39 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/radio.c | 1113 ++++++++++++++++++++++
 1 file changed, 1113 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.c

diff --git a/drivers/net/wireless/celeno/cl8k/radio.c b/drivers/net/wireless/celeno/cl8k/radio.c
new file mode 100644
index 000000000000..416c2bdff07e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/radio.c
@@ -0,0 +1,1113 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/kthread.h>
+#include <linux/jiffies.h>
+#include <linux/list.h>
+
+#include "vif.h"
+#include "sta.h"
+#include "chip.h"
+#include "debug.h"
+#include "hw.h"
+#include "phy.h"
+#include "utils.h"
+#include "reg/reg_access.h"
+#include "reg/reg_defs.h"
+#include "mac_addr.h"
+#include "stats.h"
+#include "radio.h"
+
+static int cl_radio_off_kthread(void *arg)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)arg;
+	struct cl_vif *cl_vif;
+
+	cl_dbg_verbose(cl_hw, "Waiting for stations to disconnect\n");
+
+	if (wait_event_timeout(cl_hw->radio_wait_queue,
+			       cl_sta_num_bh(cl_hw) == 0,
+			       msecs_to_jiffies(5000)) == 0) {
+		cl_dbg_verbose(cl_hw,
+			       "Failed to disconnect stations. %u stations still remaining\n",
+			       cl_sta_num_bh(cl_hw));
+	}
+
+	cl_dbg_trace(cl_hw, "Stopping queues ...\n");
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		cl_vif->tx_en = false;
+		cl_dbg_verbose(cl_hw, "Radio OFF vif_index = %u\n",
+			       cl_vif->vif_index);
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	cl_msg_tx_set_idle(cl_hw, MAC_IDLE_SYNC, true);
+
+	cl_dbg_trace(cl_hw, "Radio shut down successfully\n");
+
+	cl_hw->radio_status = RADIO_STATUS_OFF;
+	atomic_set(&cl_hw->radio_lock, 0);
+
+	return 0;
+}
+
+static int cl_radio_off(struct cl_hw *cl_hw)
+{
+	struct task_struct *k;
+
+	if (cl_hw->radio_status != RADIO_STATUS_ON ||
+	    atomic_xchg(&cl_hw->radio_lock, 1))
+		return 1;
+
+	cl_hw->radio_status = RADIO_STATUS_GOING_DOWN;
+
+	/* Relegate the job to a kthread to free the system call. */
+	k = kthread_run(cl_radio_off_kthread, cl_hw, "cl_radio_off_kthread");
+	if (IS_ERR(k))
+		cl_dbg_verbose(cl_hw,
+			       "Error: failed to run cl_radio_off_kthread\n");
+	return 0;
+}
+
+void cl_radio_on_start(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif;
+
+	if (cl_calib_common_check_errors(cl_hw) != 0 || !cl_hw->conf->ce_num_antennas)
+		return;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		if (cl_vif->vif->type == NL80211_IFTYPE_AP) {
+			if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_REPEATER &&
+			    !test_bit(CL_DEV_REPEATER, &cl_hw->drv_flags))
+				continue;
+			if (cl_hw_get_iface_conf(cl_hw) == CL_IFCONF_MESH_AP &&
+			    !test_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags))
+				continue;
+		}
+
+		if (!cl_hw->conf->ce_listener_en)
+			cl_vif->tx_en = true;
+
+		cl_dbg_verbose(cl_hw, "Radio ON vif=%u\n", cl_vif->vif_index);
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE, true);
+
+	cl_dbg_verbose(cl_hw, "Radio has been started\n");
+
+	cl_hw->radio_status = RADIO_STATUS_ON;
+	atomic_set(&cl_hw->radio_lock, 0);
+}
+
+int cl_radio_on(struct cl_hw *cl_hw)
+{
+	struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+	bool both_enabled = cl_chip_is_both_enabled(cl_hw->chip);
+
+	if (cl_hw->radio_status != RADIO_STATUS_OFF ||
+	    atomic_xchg(&cl_hw->radio_lock, 1))
+		return 1;
+
+	if (!both_enabled ||
+	    (both_enabled && cl_hw_other && !cl_hw_other->conf->ce_radio_on) ||
+	    (cl_hw_is_tcv1(cl_hw) && cl_hw->chip->conf->ci_tcv1_chains_sx0)) {
+		if (cl_calib_iq_calibration_needed(cl_hw)) {
+			cl_calib_common_start_work(cl_hw);
+
+			return 0;
+		}
+	} else if (cl_hw_other) {
+		if (cl_hw_other->iq_cal_ready) {
+			cl_hw_other->iq_cal_ready = false;
+			cl_calib_common_start_work(cl_hw);
+
+			return 0;
+		} else if (cl_calib_iq_calibration_needed(cl_hw)) {
+			cl_hw->iq_cal_ready = true;
+			cl_dbg_verbose(cl_hw, "IQ Calibration needed. Wait for both TCVs "
+					      "to get to radio-on before turning both on.\n");
+			return 1;
+		}
+	}
+
+	cl_radio_on_start(cl_hw);
+
+	return 0;
+}
+
+void cl_radio_off_chip(struct cl_chip *chip)
+{
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_radio_off(chip->cl_hw_tcv0);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_radio_off(chip->cl_hw_tcv1);
+}
+
+void cl_radio_on_chip(struct cl_chip *chip)
+{
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_radio_on(chip->cl_hw_tcv0);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_radio_on(chip->cl_hw_tcv1);
+}
+
+bool cl_radio_is_off(struct cl_hw *cl_hw)
+{
+	return cl_hw->radio_status == RADIO_STATUS_OFF;
+}
+
+bool cl_radio_is_on(struct cl_hw *cl_hw)
+{
+	return cl_hw->radio_status == RADIO_STATUS_ON;
+}
+
+bool cl_radio_is_going_down(struct cl_hw *cl_hw)
+{
+	return cl_hw->radio_status == RADIO_STATUS_GOING_DOWN;
+}
+
+void cl_radio_off_wake_up(struct cl_hw *cl_hw)
+{
+	wake_up(&cl_hw->radio_wait_queue);
+}
+
+static void cl_clk_init(struct cl_chip *chip)
+{
+	cmu_clk_en_set(chip, CMU_MAC_ALL_CLK_EN);
+
+	if (cl_chip_is_both_enabled(chip)) {
+		cmu_phy_0_clk_en_set(chip, CMU_PHY_0_APB_CLK_EN_BIT | CMU_PHY_0_MAIN_CLK_EN_BIT);
+		cmu_phy_1_clk_en_set(chip, CMU_PHY_1_APB_CLK_EN_BIT | CMU_PHY_1_MAIN_CLK_EN_BIT);
+
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+		modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv0, 1);
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+		modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv1, 1);
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+	} else if (cl_chip_is_tcv0_enabled(chip)) {
+		/* Even if only PHY0 is enabled we need to set CMU_PHY_1_MAIN_CLK_EN_BIT */
+		cmu_phy_0_clk_en_set(chip, CMU_PHY_0_APB_CLK_EN_BIT | CMU_PHY_0_MAIN_CLK_EN_BIT);
+		cmu_phy_1_clk_en_set(chip, CMU_PHY_1_MAIN_CLK_EN_BIT);
+
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 0);
+		modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv0, 1);
+		cmu_phy_0_rst_ceva_0_global_rst_n_setf(chip, 1);
+
+		cmu_phy_0_clk_en_ceva_0_clk_en_setf(chip, 1);
+	} else {
+		/* Even if only PHY1 is enabled we need to set CMU_PHY_0_MAIN_CLK_EN_BIT */
+		cmu_phy_0_clk_en_set(chip, CMU_PHY_0_MAIN_CLK_EN_BIT);
+		cmu_phy_1_clk_en_set(chip, CMU_PHY_1_APB_CLK_EN_BIT | CMU_PHY_1_MAIN_CLK_EN_BIT);
+
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 0);
+		modem_gcu_ceva_ctrl_external_wait_setf(chip->cl_hw_tcv1, 1);
+		cmu_phy_1_rst_ceva_1_global_rst_n_setf(chip, 1);
+
+		cmu_phy_1_clk_en_ceva_1_clk_en_setf(chip, 1);
+	}
+}
+
+static int cl_pll1_init(struct cl_chip *chip)
+{
+	int retry = 0;
+
+	/* Verify pll is locked */
+	while (!cmu_pll_1_stat_pll_lock_getf(chip) && (++retry < 10)) {
+		cl_dbg_chip_verbose(chip, "retry=%d\n", retry);
+		usleep_range(100, 200);
+	}
+
+	/* Pll is not locked - fatal error */
+	if (retry == 10) {
+		cl_dbg_chip_err(chip, "retry limit reached - pll1 is not locked !!!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int cl_cmu_init(struct cl_chip *chip)
+{
+	int ret = 0;
+
+	if (IS_REAL_PHY(chip)) {
+		ret = cl_pll1_init(chip);
+		if (ret)
+			return ret;
+	}
+
+	/* Set gl_mux_sel bit to work with pll1 instead of crystal */
+	cmu_control_gl_mux_sel_setf(chip, 1);
+
+	if (cl_chip_is_both_enabled(chip)) {
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+		cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+		cmu_phy_0_rst_set(chip, 0x0);
+		cmu_phy_1_rst_set(chip, 0x0);
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+		cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+	} else if (cl_chip_is_tcv0_enabled(chip)) {
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+		cmu_phy_0_rst_set(chip, 0x0);
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_0_rst_set(chip, CMU_PHY0_RST_EN);
+	} else {
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+		cmu_phy_1_rst_set(chip, 0x0);
+		cmu_rst_n_ricurst_setf(chip, 1);
+		cmu_phy_1_rst_set(chip, CMU_PHY1_RST_EN);
+	}
+
+	return ret;
+}
+
+static void cl_riu_clk_bw_init(struct cl_hw *cl_hw)
+{
+	u32 regval;
+
+	if (!cl_hw)
+		return;
+
+	switch (cl_hw->conf->ci_cap_bandwidth) {
+	case CHNL_BW_20:
+		regval = 0x00000100;
+		break;
+	case CHNL_BW_40:
+		regval = 0x00000555;
+		break;
+	case CHNL_BW_160:
+		regval = 0x00000dff;
+		break;
+	case CHNL_BW_80:
+	default:
+		regval = 0x000009aa;
+		break;
+	}
+
+	/* Set RIU modules clock BW */
+	modem_gcu_riu_clk_bw_set(cl_hw, regval);
+}
+
+static int cl_load_riu_rsf_memory(struct cl_chip *chip, const char *filename)
+{
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	char *buf = NULL;
+	loff_t size, i = 0;
+	int ret = 0;
+
+	size = cl_file_open_and_read(chip, filename, &buf);
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (size > RIU_RSF_FILE_SIZE) {
+		ret = -EFBIG;
+		goto out;
+	}
+
+	/* Enable re-sampling filter init. */
+	riu_rsf_control_rsf_init_en_setf(cl_hw_tcv0, 0x1);
+	if (cl_hw_tcv1)
+		riu_rsf_control_rsf_init_en_setf(cl_hw_tcv1, 0x1);
+
+	while (i < size) {
+		riu_rsf_init_set(cl_hw_tcv0, *(u32 *)&buf[i]);
+		if (cl_hw_tcv1)
+			riu_rsf_init_set(cl_hw_tcv1, *(u32 *)&buf[i]);
+		i += 4;
+	}
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+static int cl_load_riu_rsf_memory_recovery(struct cl_hw *cl_hw, const char *filename)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	char *buf = NULL;
+	loff_t size, i = 0;
+	int ret = 0;
+
+	size = cl_file_open_and_read(chip, filename, &buf);
+
+	if (!buf)
+		return -ENOMEM;
+
+	if (size > RIU_RSF_FILE_SIZE) {
+		ret = -EFBIG;
+		goto out;
+	}
+
+	/* Enable re-sampling filter init. */
+	riu_rsf_control_rsf_init_en_setf(cl_hw, 0x1);
+
+	while (i < size) {
+		riu_rsf_init_set(cl_hw, *(u32 *)&buf[i]);
+		i += 4;
+	}
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+static int cl_load_agc_data(struct cl_hw *cl_hw, const char *filename)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	char *buf = NULL;
+	loff_t size, i = 0;
+
+	size = cl_file_open_and_read(chip, filename, &buf);
+
+	if (!buf)
+		return -ENOMEM;
+
+	/* Enable AGC FSM ram init state */
+	riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x1);
+	/* Start writing the firmware from WPTR=0 */
+	riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_setf(cl_hw, 0x0);
+	/* Allow WPTR register to be writable */
+	riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_set_setf(cl_hw, 0x1);
+	/* Enable auto increment WPTR by 1 upon any write */
+	riu_agcfsm_ram_init_1_agc_fsm_ram_init_ainc_1_setf(cl_hw, 0x1);
+
+	while (i < size) {
+		riu_agcfsm_ram_init_2_set(cl_hw, *(u32 *)&buf[i]);
+		i += 4;
+	}
+
+	/* Disable AGC FSM ram init state */
+	riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(cl_hw, 0x0);
+
+	kfree(buf);
+
+	return 0;
+}
+
+static int cl_load_agc_fw(struct cl_hw *cl_hw, const char *filename)
+{
+	int ret = 0;
+
+	if (!cl_hw)
+		goto out;
+
+	/* Switch AGC to programming mode */
+
+	/* Disable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+	modem_gcu_riu_clk_set(cl_hw, 0);
+
+	/* Switch AGC MEM clock to 480MHz */
+	modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 3);
+
+	/* Enable RIU Modules clocks (RC,LB,ModemB,FE,ADC,Regs,AGC,Radar) */
+	modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+	/* Assert AGC FSM reset */
+	riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 1);
+
+	/* Load AGC RAM data */
+	ret = cl_load_agc_data(cl_hw, filename);
+	if (ret)
+		goto out;
+
+	/* Switch AGC back to operational mode */
+
+	/* Disable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+	modem_gcu_riu_clk_set(cl_hw, 0);
+	/* Switch AGC MEM clock back to 80M */
+	modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(cl_hw, 1);
+	/* Enable RIU Modules clocks (RC, LB, ModemB, FE, ADC, Regs, AGC, Radar) */
+	modem_gcu_riu_clk_set(cl_hw, 0xFFFFFFFF);
+
+	/* Release AGC FSM reset */
+	riu_rwnxagccntl_agcfsmreset_setf(cl_hw, 0);
+
+out:
+	return ret;
+}
+
+int cl_radio_boot(struct cl_chip *chip)
+{
+	int ret = 0;
+	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
+	bool tcv0_enabled = cl_chip_is_tcv0_enabled(chip);
+	bool tcv1_enabled = cl_chip_is_tcv1_enabled(chip);
+
+	/* Call only once per chip after ASIC reset - configure both phys */
+	ret = cl_cmu_init(chip);
+	if (ret != 0)
+		goto out;
+
+	cl_clk_init(chip);
+	cmu_phase_sel_set(chip, (CMU_GP_CLK_PHASE_SEL_BIT |
+				 CMU_DAC_CDB_CLK_PHASE_SEL_BIT |
+				 CMU_DAC_CLK_PHASE_SEL_BIT) &
+				 ~(CMU_ADC_CDB_CLK_PHASE_SEL_BIT |
+				 CMU_ADC_CLK_PHASE_SEL_BIT));
+
+	if (tcv0_enabled) {
+		mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv0, 1); /* Disable MPIF clock */
+		mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 2);        /* Move to doze */
+	}
+
+	if (tcv1_enabled) {
+		mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw_tcv1, 1); /* Disable MPIF clock */
+		mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 2);        /* Move to doze */
+	}
+
+	/* Enable all PHY modules */
+	cl_phy_enable(cl_hw_tcv0);
+	cl_phy_enable(cl_hw_tcv1);
+
+	if (tcv0_enabled) {
+		mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv0, 1); /* Exit from doze */
+		mac_hw_state_cntrl_next_state_setf(cl_hw_tcv0, 0);  /* Move to idle */
+	}
+
+	if (tcv1_enabled) {
+		mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw_tcv1, 1); /* Exit from doze */
+		mac_hw_state_cntrl_next_state_setf(cl_hw_tcv1, 0);  /* Move to idle */
+	}
+
+	cl_riu_clk_bw_init(cl_hw_tcv0);
+	cl_riu_clk_bw_init(cl_hw_tcv1);
+
+	/* Load RIU re-sampling filter memory with coefficients */
+	ret = cl_load_riu_rsf_memory(chip, "riu_rsf.bin");
+	if (ret != 0) {
+		pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+		goto out;
+	}
+
+	/* Load AGC FW */
+	ret = cl_load_agc_fw(cl_hw_tcv0, "agcram.bin");
+	if (ret) {
+		pr_err("cl_load_agc_fw failed for tcv0 with error code %d.\n", ret);
+		goto out;
+	}
+
+	ret = cl_load_agc_fw(cl_hw_tcv1, "agcram.bin");
+	if (ret) {
+		pr_err("cl_load_agc_fw failed for tcv1 with error code %d.\n", ret);
+		goto out;
+	}
+
+	/* AFE Registers configuration */
+	ret = cl_afe_cfg(chip);
+
+out:
+	return ret;
+}
+
+static void cl_restore_ela_state(struct cl_hw *cl_hw)
+{
+	struct cl_recovery_db *recovery_db = &cl_hw->recovery_db;
+
+	/* Restore eLA state after MAC-HW reset */
+	if (recovery_db->ela_en) {
+		mac_hw_debug_port_sel_a_set(cl_hw, recovery_db->ela_sel_a);
+		mac_hw_debug_port_sel_b_set(cl_hw, recovery_db->ela_sel_b);
+		mac_hw_debug_port_sel_c_set(cl_hw, recovery_db->ela_sel_c);
+	}
+
+	mac_hw_debug_port_en_set(cl_hw, recovery_db->ela_en);
+}
+
+int cl_radio_boot_recovery(struct cl_hw *cl_hw)
+{
+	int ret = 0;
+
+	mac_hw_mac_cntrl_1_active_clk_gating_setf(cl_hw, 1); /* Disable MPIF clock */
+	mac_hw_state_cntrl_next_state_setf(cl_hw, 2);        /* Move to doze */
+
+	/* Enable all PHY modules */
+	cl_phy_enable(cl_hw);
+
+	/* Restart LCU recording */
+	if (cl_hw_is_tcv0(cl_hw))
+		lcu_phy_lcu_ch_0_stop_set(cl_hw, 0);
+	else
+		lcu_phy_lcu_ch_1_stop_set(cl_hw, 0);
+
+	cl_restore_ela_state(cl_hw);
+
+	mac_hw_doze_cntrl_2_wake_up_sw_setf(cl_hw, 1); /* Exit from doze */
+	mac_hw_state_cntrl_next_state_setf(cl_hw, 0);  /* Move to idle */
+
+	cl_riu_clk_bw_init(cl_hw);
+
+	/* Load RIU re-sampling filter memory with coefficients */
+	ret = cl_load_riu_rsf_memory_recovery(cl_hw, "riu_rsf.bin");
+	if (ret != 0) {
+		pr_err("cl_load_riu_rsf_memory failed with error code %d.\n", ret);
+		goto out;
+	}
+
+	/* Load AGC FW */
+	ret = cl_load_agc_fw(cl_hw, "agcram.bin");
+	if (ret) {
+		pr_err("cl_load_agc_fw failed for with error code %d.\n", ret);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+#define NOISE_MAX_ANT_PER_REG 4
+
+void cl_noise_init(struct cl_hw *cl_hw)
+{
+	struct cl_noise_db *noise_db = &cl_hw->noise_db;
+
+	INIT_LIST_HEAD(&noise_db->reg_list);
+}
+
+void cl_noise_close(struct cl_hw *cl_hw)
+{
+	struct cl_noise_db *noise_db = &cl_hw->noise_db;
+	struct cl_noise_reg *elem = NULL;
+	struct cl_noise_reg *tmp = NULL;
+
+	list_for_each_entry_safe(elem, tmp, &noise_db->reg_list, list) {
+		list_del(&elem->list);
+		kfree(elem);
+	}
+}
+
+void cl_noise_maintenance(struct cl_hw *cl_hw)
+{
+	struct cl_noise_db *noise_db = &cl_hw->noise_db;
+	struct cl_noise_reg *reg = NULL;
+	u8 ch_bw = cl_hw->bw;
+
+	if (noise_db->sample_cnt == 0)
+		return;
+
+	reg = kzalloc(sizeof(*reg), GFP_ATOMIC);
+
+	if (!reg)
+		return;
+
+	/*collect statistics */
+	reg->np_prim20_per_ant = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+	reg->np_sub20_per_chn = riu_agcinbdpownoiseper_20_stat_0_get(cl_hw);
+	reg->np_sec20_dens_per_ant = riu_agcinbdpowsecnoisestat_get(cl_hw);
+	reg->nasp_prim20_per_ant = riu_inbdpowformac_0_get(cl_hw);
+	reg->nasp_sub20_per_chn = riu_inbdpowformac_3_get(cl_hw);
+	reg->nasp_sec20_dens_per_ant = riu_inbdpowformac_2_get(cl_hw);
+
+	if (ch_bw == CHNL_BW_160) {
+		reg->np_sub20_per_chn2 = riu_agcinbdpownoiseper_20_stat_1_get(cl_hw);
+		reg->nasp_sub20_per_chn2 = riu_inbdpowformac_4_get(cl_hw);
+	}
+
+	if (cl_hw->num_antennas > NOISE_MAX_ANT_PER_REG) {
+		reg->np_prim20_per_ant2 = riu_agcinbdpow_20_pnoisestat_2_get(cl_hw);
+		reg->nasp_prim20_per_ant2 = riu_inbdpowformac_1_get(cl_hw);
+	}
+
+	list_add(&reg->list, &noise_db->reg_list);
+
+	noise_db->sample_cnt--;
+
+	if (noise_db->sample_cnt == 0)
+		pr_debug("record done\n");
+}
+
+/** DOC: RSSI tracking
+ *
+ * RSSI values of association packets (request in AP mode and respone in STA mode)
+ * are not added to rssi pool sample, because at this stage station is not added
+ * to driver database.
+ * RSSI of association is important for WRS in order to select its initial rate.
+ * The goal of this code is to save MAC address and RSSI values of all association
+ * packets, and after station fully connects, search for the correct RSSI and add
+ * it to the rssi pool sample.
+ */
+struct assoc_queue_elem {
+	struct list_head list;
+	u8 addr[ETH_ALEN];
+	s8 rssi[MAX_ANTENNAS];
+	unsigned long timestamp;
+};
+
+#define CL_RSSI_LIFETIME_MS 5000
+
+static void cl_rssi_add_to_wrs(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+	struct cl_wrs_rssi *wrs_rssi = &cl_sta->wrs_rssi;
+	int i = 0;
+
+	for (i = 0; i < cl_hw->num_antennas; i++)
+		wrs_rssi->sum[i] += rssi[i];
+
+	wrs_rssi->cnt++;
+}
+
+void cl_rssi_assoc_init(struct cl_hw *cl_hw)
+{
+	INIT_LIST_HEAD(&cl_hw->assoc_queue.list);
+	spin_lock_init(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_assoc_exit(struct cl_hw *cl_hw)
+{
+	/* Delete all remaining elements in list */
+	spin_lock_bh(&cl_hw->assoc_queue.lock);
+
+	if (!list_empty(&cl_hw->assoc_queue.list)) {
+		struct assoc_queue_elem *elem = NULL;
+		struct assoc_queue_elem *tmp = NULL;
+
+		list_for_each_entry_safe(elem, tmp, &cl_hw->assoc_queue.list, list) {
+			list_del(&elem->list);
+			kfree(elem);
+		}
+	}
+
+	spin_unlock_bh(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_assoc_handle(struct cl_hw *cl_hw, u8 *mac_addr, struct hw_rxhdr *rxhdr)
+{
+	/* Allocate new element and add to list */
+	struct assoc_queue_elem *elem = kmalloc(sizeof(*elem), GFP_ATOMIC);
+
+	if (elem) {
+		INIT_LIST_HEAD(&elem->list);
+		cl_mac_addr_copy(elem->addr, mac_addr);
+
+		elem->rssi[0] = (s8)rxhdr->rssi1;
+		elem->rssi[1] = (s8)rxhdr->rssi2;
+		elem->rssi[2] = (s8)rxhdr->rssi3;
+		elem->rssi[3] = (s8)rxhdr->rssi4;
+		elem->rssi[4] = (s8)rxhdr->rssi5;
+		elem->rssi[5] = (s8)rxhdr->rssi6;
+
+		elem->timestamp = jiffies;
+
+		spin_lock(&cl_hw->assoc_queue.lock);
+		list_add(&elem->list, &cl_hw->assoc_queue.list);
+		spin_unlock(&cl_hw->assoc_queue.lock);
+	}
+}
+
+void cl_rssi_assoc_find(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 num_sta)
+{
+	/* Search for rssi of association according to mac address */
+	spin_lock_bh(&cl_hw->assoc_queue.lock);
+
+	if (!list_empty(&cl_hw->assoc_queue.list)) {
+		unsigned long lifetime = 0;
+		struct assoc_queue_elem *elem = NULL;
+		struct assoc_queue_elem *tmp = NULL;
+
+		list_for_each_entry_safe(elem, tmp, &cl_hw->assoc_queue.list, list) {
+			lifetime = jiffies_to_msecs(jiffies - elem->timestamp);
+
+			/* Check lifetime of rssi before using it */
+			if (lifetime > CL_RSSI_LIFETIME_MS) {
+				/* Delete element from list */
+				list_del(&elem->list);
+				kfree(elem);
+				continue;
+			}
+
+			if (ether_addr_equal(elem->addr, cl_sta->addr)) {
+				struct hw_rxhdr rxhdr;
+				s8 equivalent_rssi = cl_rssi_calc_equivalent(cl_hw, elem->rssi);
+
+				rxhdr.rssi1 = elem->rssi[0];
+				rxhdr.rssi2 = elem->rssi[1];
+				rxhdr.rssi3 = elem->rssi[2];
+				rxhdr.rssi4 = elem->rssi[3];
+				rxhdr.rssi5 = elem->rssi[4];
+				rxhdr.rssi6 = elem->rssi[5];
+
+				cl_rssi_rx_handler(cl_hw, cl_sta, &rxhdr, equivalent_rssi);
+
+				/* Delete element from list */
+				list_del(&elem->list);
+				kfree(elem);
+			}
+		}
+	}
+
+	spin_unlock_bh(&cl_hw->assoc_queue.lock);
+}
+
+void cl_rssi_sort_descending(s8 rssi[MAX_ANTENNAS], u8 num_ant)
+{
+	int i, j;
+
+	for (i = 0; i < num_ant - 1; i++)
+		for (j = 0; j < num_ant - i - 1; j++)
+			if (rssi[j] < rssi[j + 1])
+				swap(rssi[j], rssi[j + 1]);
+}
+
+static s8 cl_rssi_equivalent_2_phys(s8 rssi_max, s8 rssi_min)
+{
+	s8 rssi_diff = rssi_min - rssi_max;
+
+	if (rssi_diff > (-2))
+		return (rssi_max + 3);
+	else if (rssi_diff > (-5))
+		return (rssi_max + 2);
+	else if (rssi_diff > (-9))
+		return (rssi_max + 1);
+	else
+		return rssi_max;
+}
+
+s8 cl_rssi_calc_equivalent(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS])
+{
+	s8 rssi_tmp[MAX_ANTENNAS] = {0};
+	u8 rx_ant = cl_hw->num_antennas;
+	int i, j;
+
+	/* Copy to rssi_tmp */
+	memcpy(rssi_tmp, rssi, rx_ant);
+
+	/* Sort the rssi's in desceding order */
+	cl_rssi_sort_descending(rssi_tmp, rx_ant);
+
+	/*
+	 * 1) Calc equivalent rssi between the two lowest values.
+	 * 2) Sort again
+	 * 3) Repeat steps 1 and 2 according to number of antennas.
+	 */
+	for (i = 0; i < rx_ant - 1; i++) {
+		rssi_tmp[rx_ant - i - 2] = cl_rssi_equivalent_2_phys(rssi_tmp[rx_ant - i - 2],
+								     rssi_tmp[rx_ant - i - 1]);
+
+		for (j = rx_ant - i - 2; j > 0; j--) {
+			if (rssi_tmp[j] > rssi_tmp[j - 1])
+				swap(rssi_tmp[j], rssi_tmp[j - 1]);
+			else
+				break;
+		}
+	}
+
+	return rssi_tmp[0];
+}
+
+s8 cl_rssi_get_strongest(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS])
+{
+	int i;
+	s8 strongest_rssi = S8_MIN;
+
+	for (i = 0; i < cl_hw->num_antennas; i++) {
+		if (rssi[i] > strongest_rssi)
+			strongest_rssi = rssi[i];
+	}
+
+	return strongest_rssi;
+}
+
+static void cl_update_sta_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       s8 rssi[MAX_ANTENNAS], s8 equivalent_rssi)
+{
+	/* Last RSSI */
+	memcpy(cl_sta->last_rssi, rssi, cl_hw->num_antennas);
+
+	if (cl_sta->manual_alpha_rssi)
+		return;
+
+	/* Alpha RSSI - use alpha filter (87.5% current + 12.5% new) */
+	if (cl_sta->alpha_rssi)
+		cl_sta->alpha_rssi =
+			((cl_sta->alpha_rssi << 3) - cl_sta->alpha_rssi + equivalent_rssi) >> 3;
+	else
+		cl_sta->alpha_rssi = equivalent_rssi;
+}
+
+static bool cl_rssi_is_valid_ru_type_factor(u8 ru_type)
+{
+	return (ru_type >= CL_MU_OFDMA_RU_TYPE_26 && ru_type <= CL_MU_OFDMA_RU_TYPE_106);
+}
+
+static void cl_rssi_agg_ind_rssi_values_fill(struct cl_hw *cl_hw,
+					     struct cl_agg_tx_report *agg_report,
+					     s8 *rssi_buf)
+{
+	/* Fill the rssi buffer with the correct rssi values */
+	switch (cl_hw->first_riu_chain) {
+	case 0:
+		rssi_buf[0] = agg_report->rssi1;
+		rssi_buf[1] = agg_report->rssi2;
+		rssi_buf[2] = agg_report->rssi3;
+		rssi_buf[3] = agg_report->rssi4;
+		rssi_buf[4] = agg_report->rssi5;
+		rssi_buf[5] = agg_report->rssi6;
+		break;
+	case 1:
+		rssi_buf[0] = agg_report->rssi2;
+		rssi_buf[1] = agg_report->rssi3;
+		rssi_buf[2] = agg_report->rssi4;
+		rssi_buf[3] = agg_report->rssi5;
+		rssi_buf[4] = agg_report->rssi6;
+		break;
+	case 2:
+		rssi_buf[0] = agg_report->rssi3;
+		rssi_buf[1] = agg_report->rssi4;
+		rssi_buf[2] = agg_report->rssi5;
+		rssi_buf[3] = agg_report->rssi6;
+		break;
+	case 3:
+		rssi_buf[0] = agg_report->rssi4;
+		rssi_buf[1] = agg_report->rssi5;
+		rssi_buf[2] = agg_report->rssi6;
+		break;
+	case 4:
+		rssi_buf[0] = agg_report->rssi5;
+		rssi_buf[1] = agg_report->rssi6;
+		break;
+	case 5:
+		rssi_buf[0] = agg_report->rssi6;
+		break;
+	default:
+		break;
+	}
+}
+
+void cl_rssi_block_ack_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct cl_agg_tx_report *agg_report)
+{
+	/* Handle RSSI of block-ack's */
+	union cl_rate_ctrl_info rate_ctrl_info = {
+		.word = le32_to_cpu(agg_report->rate_cntrl_info)};
+	u8 bw = rate_ctrl_info.field.bw;
+
+	s8 rssi[MAX_ANTENNAS];
+	s8 equivalent_rssi;
+	int i;
+
+	cl_rssi_agg_ind_rssi_values_fill(cl_hw, agg_report, rssi);
+
+	if (cl_hw->rssi_simulate)
+		for (i = 0; i < cl_hw->num_antennas; i++)
+			rssi[i] = cl_hw->rssi_simulate;
+
+	if (!cl_hw->rssi_simulate) {
+		union cl_rate_ctrl_info_he rate_ctrl_info_he = {
+			.word = le32_to_cpu(agg_report->rate_cntrl_info_he)};
+		u8 ru_type = rate_ctrl_info_he.field.ru_type;
+		u8 format_mode = rate_ctrl_info.field.format_mod;
+		s8 bw_factor = 0;
+
+		/*
+		 * RSSI adjustment according to BW
+		 * The BA is transmitted in the BW of the aggregation it acknowledges
+		 */
+		if (format_mode == FORMATMOD_HE_MU &&
+		    cl_rssi_is_valid_ru_type_factor(ru_type)) {
+			if (ru_type == CL_MU_OFDMA_RU_TYPE_26)
+				bw_factor = -9;
+			else if (ru_type == CL_MU_OFDMA_RU_TYPE_52)
+				bw_factor = -6;
+			else if (ru_type == CL_MU_OFDMA_RU_TYPE_106)
+				bw_factor = -3;
+		} else {
+			if (bw == CHNL_BW_160)
+				bw_factor = 9;
+			else if (bw == CHNL_BW_80)
+				bw_factor = 6;
+			else if (bw == CHNL_BW_40)
+				bw_factor = 3;
+		}
+
+		for (i = 0; i < cl_hw->num_antennas; i++)
+			rssi[i] += bw_factor;
+	}
+
+	equivalent_rssi = cl_rssi_calc_equivalent(cl_hw, rssi);
+
+	/* Handle RSSI after BW adjustment */
+	cl_rssi_add_to_wrs(cl_hw, cl_sta, rssi);
+	cl_stats_update_rx_rssi(cl_hw, cl_sta, rssi);
+	cl_vns_handle_rssi(cl_hw, cl_sta, rssi);
+	cl_update_sta_rssi(cl_hw, cl_sta, rssi, equivalent_rssi);
+	cl_motion_sense_rssi_ba(cl_hw, cl_sta, rssi);
+}
+
+void cl_rssi_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			struct hw_rxhdr *rxhdr, s8 equivalent_rssi)
+{
+	/* Called after BW adjustment */
+	s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+	if (!IS_REAL_PHY(cl_hw->chip) && rssi[0] == 0)
+		return;
+
+	cl_rssi_add_to_wrs(cl_hw, cl_sta, rssi);
+	cl_stats_update_rx_rssi(cl_hw, cl_sta, rssi);
+	cl_vns_handle_rssi(cl_hw, cl_sta, rssi);
+	cl_update_sta_rssi(cl_hw, cl_sta, rssi, equivalent_rssi);
+}
+
+void cl_rssi_bw_adjust(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr, s8 bw_factor)
+{
+	if (cl_hw->rssi_simulate)
+		return;
+
+	rxhdr->rssi1 += bw_factor;
+	rxhdr->rssi2 += bw_factor;
+	rxhdr->rssi3 += bw_factor;
+	rxhdr->rssi4 += bw_factor;
+	rxhdr->rssi5 += bw_factor;
+	rxhdr->rssi6 += bw_factor;
+}
+
+void cl_rssi_simulate(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+	rxhdr->rssi1 = cl_hw->rssi_simulate;
+	rxhdr->rssi2 = cl_hw->rssi_simulate;
+	rxhdr->rssi3 = cl_hw->rssi_simulate;
+	rxhdr->rssi4 = cl_hw->rssi_simulate;
+	rxhdr->rssi5 = cl_hw->rssi_simulate;
+	rxhdr->rssi6 = cl_hw->rssi_simulate;
+}
+
+#define CCA_CNT_RATE_40MHZ    3
+
+static void cl_cca_reset_phy_counters(struct cl_hw *cl_hw)
+{
+	riu_rwnxagccca_1_cca_cnt_clear_setf(cl_hw, 1);
+	riu_rwnxagccca_1_cca_cnt_clear_setf(cl_hw, 0);
+}
+
+void cl_cca_init(struct cl_hw *cl_hw)
+{
+	/* Set PHY registers rate */
+	riu_rwnxagccca_1_cca_cnt_rate_setf(cl_hw, CCA_CNT_RATE_40MHZ);
+}
+
+void cl_cca_maintenance(struct cl_hw *cl_hw)
+{
+	struct cl_cca_db *cca_db = &cl_hw->cca_db;
+	unsigned long time = jiffies_to_usecs(jiffies);
+	unsigned long diff_time = time - cca_db->time;
+
+	cca_db->time = time;
+	if (!diff_time)
+		return;
+
+	/* Rest PHY counters */
+	cl_cca_reset_phy_counters(cl_hw);
+}
+
+void cl_prot_mode_init(struct cl_hw *cl_hw)
+{
+	struct cl_prot_mode *prot_mode = &cl_hw->prot_mode;
+	u8 init = cl_hw->conf->ce_prot_mode;
+
+	prot_mode->current_val = init;
+	prot_mode->default_val = init;
+	prot_mode->dynamic_val = (init != TXL_NO_PROT) ? init : TXL_PROT_RTS_FW;
+}
+
+void cl_prot_mode_set(struct cl_hw *cl_hw, u8 prot_mode_new)
+{
+	struct cl_prot_mode *prot_mode = &cl_hw->prot_mode;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	if (prot_mode->current_val != prot_mode_new) {
+		prot_mode->current_val = prot_mode_new;
+		cl_msg_tx_prot_mode(cl_hw,
+				    conf->ce_prot_log_nav_en,
+				    prot_mode_new,
+				    conf->ce_prot_rate_format,
+				    conf->ce_prot_rate_mcs,
+				    conf->ce_prot_rate_pre_type);
+	}
+}
+
+u8 cl_prot_mode_get(struct cl_hw *cl_hw)
+{
+	return cl_hw->prot_mode.current_val;
+}
+
+static u8 conv_to_fw_ac[EDCA_AC_MAX] = {
+	[EDCA_AC_BE] = AC_BE,
+	[EDCA_AC_BK] = AC_BK,
+	[EDCA_AC_VI] = AC_VI,
+	[EDCA_AC_VO] = AC_VO
+};
+
+static const char *edca_ac_str[EDCA_AC_MAX] = {
+	[EDCA_AC_BE] = "BE",
+	[EDCA_AC_BK] = "BK",
+	[EDCA_AC_VI] = "VI",
+	[EDCA_AC_VO] = "VO",
+};
+
+void cl_edca_hw_conf(struct cl_hw *cl_hw)
+{
+	u8 ac = 0;
+	struct cl_tcv_conf *conf = cl_hw->conf;
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		struct edca_params params = {
+			.aifsn = conf->ce_wmm_aifsn[ac],
+			.cw_min = conf->ce_wmm_cwmin[ac],
+			.cw_max = conf->ce_wmm_cwmax[ac],
+			.txop = conf->ce_wmm_txop[ac]
+		};
+
+		cl_edca_set(cl_hw, ac, &params, NULL);
+	}
+}
+
+void cl_edca_set(struct cl_hw *cl_hw, u8 ac, struct edca_params *params,
+		 struct ieee80211_he_mu_edca_param_ac_rec *mu_edca)
+{
+	u32 edca_reg_val = 0;
+
+	if (ac >= AC_MAX) {
+		pr_err("%s: Invalid AC index\n", __func__);
+		return;
+	}
+
+	edca_reg_val  = (u32)(params->aifsn);
+	edca_reg_val |= (u32)(params->cw_min << 4);
+	edca_reg_val |= (u32)(params->cw_max << 8);
+	edca_reg_val |= (u32)(params->txop << 12);
+
+	memcpy(&cl_hw->edca_db.hw_params[ac], params, sizeof(struct edca_params));
+
+	cl_msg_tx_set_edca(cl_hw, conv_to_fw_ac[ac], edca_reg_val, mu_edca);
+
+	cl_dbg_trace(cl_hw, "EDCA-%s: aifsn=%u, cw_min=%u, cw_max=%u, txop=%u\n",
+		     edca_ac_str[ac], params->aifsn, params->cw_min,
+		     params->cw_max, params->txop);
+}
+
+void cl_edca_recovery(struct cl_hw *cl_hw)
+{
+	u8 ac;
+
+	for (ac = 0; ac < AC_MAX; ac++)
+		cl_edca_set(cl_hw, ac, &cl_hw->edca_db.hw_params[ac], NULL);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 57/96] cl8k: add radio.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (55 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 56/96] cl8k: add radio.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 58/96] cl8k: add rates.c viktor.barna
                   ` (38 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/radio.h | 130 +++++++++++++++++++++++
 1 file changed, 130 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/radio.h

diff --git a/drivers/net/wireless/celeno/cl8k/radio.h b/drivers/net/wireless/celeno/cl8k/radio.h
new file mode 100644
index 000000000000..b51dec5b7b1e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/radio.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_RADIO_H
+#define CL_RADIO_H
+
+#define RADIO_STATUS_OFF        0
+#define RADIO_STATUS_ON         1
+#define RADIO_STATUS_GOING_DOWN 2
+
+int cl_radio_on(struct cl_hw *cl_hw);
+void cl_radio_off_chip(struct cl_chip *chip);
+void cl_radio_on_chip(struct cl_chip *chip);
+bool cl_radio_is_off(struct cl_hw *cl_hw);
+bool cl_radio_is_on(struct cl_hw *cl_hw);
+bool cl_radio_is_going_down(struct cl_hw *cl_hw);
+void cl_radio_on_start(struct cl_hw *cl_hw);
+int cl_radio_boot(struct cl_chip *chip);
+int cl_radio_boot_recovery(struct cl_hw *cl_hw);
+/* Wakes up cl_radio_off_kthread after all the stations have disconnected. */
+void cl_radio_off_wake_up(struct cl_hw *cl_hw);
+
+struct cl_noise_reg {
+	struct list_head list;
+	u32 np_prim20_per_ant;
+	u32 np_prim20_per_ant2;
+	u32 nasp_prim20_per_ant;
+	u32 nasp_prim20_per_ant2;
+	u32 np_sub20_per_chn;
+	u32 np_sub20_per_chn2;
+	u32 nasp_sub20_per_chn;
+	u32 nasp_sub20_per_chn2;
+	u32 np_sec20_dens_per_ant;
+	u32 nasp_sec20_dens_per_ant;
+};
+
+struct cl_noise_db {
+	struct list_head reg_list;
+	bool hist_record;
+	u8 active_ant;
+	u8 sample_cnt;
+};
+
+void cl_noise_init(struct cl_hw *cl_hw);
+void cl_noise_close(struct cl_hw *cl_hw);
+void cl_noise_maintenance(struct cl_hw *cl_hw);
+
+#define RX_HDR_RSSI(rxhdr) \
+	{(rxhdr)->rssi1, (rxhdr)->rssi2, (rxhdr)->rssi3, \
+	 (rxhdr)->rssi4, (rxhdr)->rssi5, (rxhdr)->rssi6}
+
+struct cl_assoc_queue {
+	struct list_head list;
+	spinlock_t lock;
+};
+
+void cl_rssi_assoc_init(struct cl_hw *cl_hw);
+void cl_rssi_assoc_exit(struct cl_hw *cl_hw);
+void cl_rssi_assoc_handle(struct cl_hw *cl_hw, u8 *mac_addr, struct hw_rxhdr *rxhdr);
+void cl_rssi_assoc_find(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 num_sta);
+void cl_rssi_sort_descending(s8 rssi[MAX_ANTENNAS], u8 num_ant);
+s8 cl_rssi_calc_equivalent(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS]);
+s8 cl_rssi_get_strongest(struct cl_hw *cl_hw, s8 rssi[MAX_ANTENNAS]);
+void cl_rssi_block_ack_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct cl_agg_tx_report *agg_report);
+void cl_rssi_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			struct hw_rxhdr *rxhdr, s8 equivalent_rssi);
+void cl_rssi_bw_adjust(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr, s8 bw_factor);
+void cl_rssi_simulate(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr);
+
+/**
+ * CCA (=Clear Channel Assessment)
+ */
+
+struct cl_cca_db {
+	unsigned long time;
+};
+
+void cl_cca_maintenance(struct cl_hw *cl_hw);
+void cl_cca_init(struct cl_hw *cl_hw);
+
+/**
+ * Protection mode (RTS/CTS) control
+ */
+enum cl_txl_prot_mode {
+	TXL_NO_PROT,
+	TXL_PROT_RTS,
+	TXL_PROT_CTS,
+	TXL_PROT_RTS_FW,
+	TXL_PROT_CTS_FW,
+
+	TXL_PROT_MAX,
+};
+
+struct cl_prot_mode {
+	u8 current_val;
+	u8 default_val;
+	u8 dynamic_val;
+};
+
+void cl_prot_mode_init(struct cl_hw *cl_hw);
+void cl_prot_mode_set(struct cl_hw *cl_hw, u8 prot_mode_new);
+u8 cl_prot_mode_get(struct cl_hw *cl_hw);
+
+enum edca_ac {
+	EDCA_AC_BE,
+	EDCA_AC_BK,
+	EDCA_AC_VI,
+	EDCA_AC_VO,
+
+	EDCA_AC_MAX
+};
+
+struct edca_params {
+	u16 txop;
+	u8 cw_max;
+	u8 cw_min;
+	u8 aifsn;
+};
+
+struct cl_edca_db {
+	struct edca_params hw_params[AC_MAX];
+};
+
+void cl_edca_hw_conf(struct cl_hw *cl_hw);
+void cl_edca_set(struct cl_hw *cl_hw, u8 ac, struct edca_params *params,
+		 struct ieee80211_he_mu_edca_param_ac_rec *mu_edca);
+void cl_edca_recovery(struct cl_hw *cl_hw);
+
+#endif /* CL_RADIO_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 58/96] cl8k: add rates.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (56 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 57/96] cl8k: add radio.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
                   ` (37 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rates.c | 1570 ++++++++++++++++++++++
 1 file changed, 1570 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rates.c

diff --git a/drivers/net/wireless/celeno/cl8k/rates.c b/drivers/net/wireless/celeno/cl8k/rates.c
new file mode 100644
index 000000000000..8f21f3d6ff84
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rates.c
@@ -0,0 +1,1570 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "tx.h"
+#include "bf.h"
+#include "utils.h"
+#include "hw.h"
+#include "rates.h"
+
+/*
+ * This table of rates was taken from IEEE 802.11ax Draft v3.3, 28.5. Parameters
+ * for HE-HE_MCSs. The units are 1/10 Mbs. Note that we don't support DCM, so it is
+ * not taken into account in this table.
+ */
+const u16 data_rate_he_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE] = {
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]     = 73,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]    = 81,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT]   = 86,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]     = 146,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]    = 163,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT]   = 172,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]     = 219,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]    = 244,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT]   = 258,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]     = 293,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]    = 325,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT]   = 344,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]     = 439,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]    = 488,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT]   = 516,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]     = 585,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]     = 658,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]    = 731,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT]   = 774,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]     = 731,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]    = 813,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT]   = 860,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]     = 878,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]     = 975,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]    = 1083,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT]   = 1147,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG]    = 1097,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT]   = 1219,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT]  = 1290,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG]    = 1219,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT]   = 1354,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT]  = 1434,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]     = 146,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]    = 163,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT]   = 172,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]     = 293,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]    = 325,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT]   = 344,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]     = 439,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]    = 488,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT]   = 516,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]     = 585,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]     = 878,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]     = 1170,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]    = 1300,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT]   = 1376,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]     = 1316,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]    = 1463,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT]   = 1549,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]     = 1463,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]    = 1625,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT]   = 1721,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]     = 1950,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]    = 2167,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT]   = 2294,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG]    = 2194,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT]   = 2438,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT]  = 2581,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG]    = 2438,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT]   = 2708,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT]  = 2868,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]     = 219,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]    = 244,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT]   = 258,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]     = 439,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]    = 488,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT]   = 516,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]     = 658,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]    = 731,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT]   = 774,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]     = 878,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]     = 1316,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]    = 1463,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT]   = 1549,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]     = 1974,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]    = 2194,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT]   = 2323,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]     = 2194,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]    = 2438,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT]   = 2581,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]     = 2633,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]    = 2925,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT]   = 3097,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]     = 2925,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]    = 3250,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT]   = 3441,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG]    = 3291,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT]   = 3656,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT]  = 3871,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG]    = 3656,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT]   = 4063,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT]  = 4301,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]     = 293,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]    = 325,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT]   = 344,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]     = 585,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]     = 878,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]     = 1170,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]    = 1300,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT]   = 1376,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]     = 2340,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]    = 2600,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT]   = 2753,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]     = 2633,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]    = 2925,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT]   = 3097,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]     = 2925,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]    = 3250,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT]   = 3441,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]     = 3510,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]    = 3900,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT]   = 4129,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]     = 3900,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]    = 4333,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT]   = 4588,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG]    = 4388,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT]   = 4875,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT]  = 5162,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG]    = 4875,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT]   = 5417,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT]  = 5735,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]     = 146,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]    = 163,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT]   = 172,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]     = 293,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]    = 325,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT]   = 344,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]     = 439,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]    = 488,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT]   = 516,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]     = 585,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]     = 878,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]     = 1170,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]    = 1300,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT]   = 1376,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]     = 1316,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]    = 1463,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT]   = 1549,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]     = 1463,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]    = 1625,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT]   = 1721,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]     = 1950,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]    = 2167,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT]   = 2294,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG]    = 2194,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT]   = 2438,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT]  = 2581,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG]    = 2438,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT]   = 2708,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT]  = 2868,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]     = 293,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]    = 325,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT]   = 344,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]     = 585,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]     = 878,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]     = 1170,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]    = 1300,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT]   = 1376,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]     = 2340,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]    = 2600,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT]   = 2753,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]     = 2633,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]    = 2925,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT]   = 3097,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]     = 2925,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]    = 3250,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT]   = 3441,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]     = 3510,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]    = 3900,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT]   = 4129,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]     = 3900,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]    = 4333,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT]   = 4588,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG]    = 4388,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT]   = 4875,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT]  = 5162,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG]    = 4875,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT]   = 5417,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT]  = 5735,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]     = 439,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]    = 488,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT]   = 516,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]     = 878,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]    = 975,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT]   = 1032,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]     = 1316,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]    = 1463,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT]   = 1549,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]     = 2633,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]    = 2925,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT]   = 3097,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]     = 3510,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]    = 3900,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT]   = 4129,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]     = 3949,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]    = 4388,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT]   = 4646,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]     = 4388,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]    = 4875,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT]   = 5162,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]     = 5265,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]    = 5850,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT]   = 6194,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]     = 5850,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]    = 6500,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT]   = 6882,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG]    = 6581,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT]   = 7313,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT]  = 7743,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG]    = 7313,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT]   = 8125,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT]  = 8603,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]     = 585,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]    = 650,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT]   = 688,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]     = 1170,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]    = 1300,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT]   = 1376,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]     = 1755,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]    = 1950,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT]   = 2065,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]     = 2340,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]    = 2600,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT]   = 2753,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]     = 3510,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]    = 3900,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT]   = 4129,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]     = 4680,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]    = 5200,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT]   = 5506,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]     = 5265,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]    = 5850,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT]   = 6194,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]     = 5850,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]    = 6500,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT]   = 6882,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]     = 7020,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]    = 7800,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT]   = 8259,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]     = 7800,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]    = 8667,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT]   = 9176,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG]    = 8775,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT]   = 9750,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT]  = 10324,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG]    = 9750,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT]   = 10833,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT]  = 11471,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]     = 306,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]    = 340,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT]   = 360,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]     = 613,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]    = 681,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT]   = 721,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]     = 919,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]    = 1021,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT]   = 1081,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]     = 1225,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]    = 1361,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT]   = 1441,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]     = 1838,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]    = 2042,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT]   = 2162,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]     = 2450,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]    = 2722,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT]   = 2882,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]     = 2756,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]    = 3063,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT]   = 3243,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]     = 3063,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]    = 3403,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT]   = 3603,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]     = 3675,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]    = 4083,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT]   = 4324,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]     = 4083,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]    = 4537,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT]   = 4804,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG]    = 4594,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT]   = 5104,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT]  = 5404,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG]    = 5104,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT]   = 5671,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT]  = 6004,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]     = 613,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]    = 681,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT]   = 721,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]     = 1225,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]    = 1361,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT]   = 1441,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]     = 1838,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]    = 2042,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT]   = 2162,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]     = 2450,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]    = 2722,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT]   = 2882,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]     = 3675,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]    = 4083,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT]   = 4324,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]     = 4900,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]    = 5444,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT]   = 5765,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]     = 5513,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]    = 6125,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT]   = 6485,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]     = 6125,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]    = 6806,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT]   = 7206,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]     = 7350,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]    = 8167,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT]   = 8647,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]     = 8166,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]    = 9074,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT]   = 9607,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG]    = 9188,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT]   = 10208,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT]  = 10809,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG]    = 10208,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT]   = 11343,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT]  = 12010,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]     = 919,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]    = 1021,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT]   = 1081,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]     = 1838,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]    = 2042,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT]   = 2162,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]     = 2756,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]    = 3063,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT]   = 3243,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]     = 3675,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]    = 4083,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT]   = 4324,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]     = 5513,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]    = 6125,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT]   = 6485,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]     = 7350,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]    = 8167,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT]   = 8647,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]     = 8269,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]    = 9188,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT]   = 9728,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]     = 9188,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]    = 10208,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT]   = 10809,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]     = 11025,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]    = 12250,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT]   = 12971,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]     = 12250,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]    = 13611,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT]   = 14412,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG]    = 13781,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT]   = 15313,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT]  = 16213,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG]    = 15313,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT]   = 17014,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT]  = 18015,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]     = 1225,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]    = 1361,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT]   = 1441,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]     = 2450,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]    = 2722,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT]   = 2882,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]     = 3675,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]    = 4083,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT]   = 4324,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]     = 4900,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]    = 5444,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT]   = 5765,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]     = 7350,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]    = 8167,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT]   = 8647,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]     = 9800,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]    = 10889,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT]   = 11529,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]     = 11025,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]    = 12250,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT]   = 12971,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]     = 12250,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]    = 13611,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT]   = 14412,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]     = 14700,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]    = 16333,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT]   = 17294,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]     = 16333,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]    = 18148,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT]   = 19215,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG]    = 18375,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT]   = 20417,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT]  = 21618,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG]    = 20416,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT]   = 22685,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT]  = 24019,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]    = 613,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]   = 681,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_VSHORT]  = 721,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]    = 1225,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]   = 1361,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_VSHORT]  = 1441,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]    = 1838,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]   = 2042,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_VSHORT]  = 2162,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]    = 2450,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]   = 2722,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_VSHORT]  = 2882,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]    = 3675,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]   = 4083,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_VSHORT]  = 4324,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]    = 4900,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]   = 5444,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_VSHORT]  = 5765,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]    = 5513,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]   = 6125,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_VSHORT]  = 6485,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]    = 6125,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]   = 6806,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_VSHORT]  = 7206,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]    = 7350,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]   = 8167,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_VSHORT]  = 8647,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]    = 8166,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]   = 9074,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_VSHORT]  = 9607,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_LONG]   = 9188,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_SHORT]  = 10208,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_10][WRS_GI_VSHORT] = 10809,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_LONG]   = 10208,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_SHORT]  = 11342,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_11][WRS_GI_VSHORT] = 12010,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]    = 1225,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]   = 1361,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_VSHORT]  = 1441,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]    = 2450,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]   = 2722,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_VSHORT]  = 2882,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]    = 3675,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]   = 4083,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_VSHORT]  = 4324,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]    = 4900,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]   = 5444,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_VSHORT]  = 5765,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]    = 7350,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]   = 8167,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_VSHORT]  = 8647,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]    = 9800,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]   = 10889,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_VSHORT]  = 11529,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]    = 11025,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]   = 12250,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_VSHORT]  = 12971,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]    = 12250,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]   = 13611,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_VSHORT]  = 14412,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]    = 14700,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]   = 16333,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_VSHORT]  = 17294,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]    = 16333,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]   = 18148,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_VSHORT]  = 19215,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_LONG]   = 18375,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_SHORT]  = 20417,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_10][WRS_GI_VSHORT] = 21618,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_LONG]   = 20416,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_SHORT]  = 22685,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_11][WRS_GI_VSHORT] = 24019,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]    = 1838,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]   = 2042,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_VSHORT]  = 2162,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]    = 3675,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]   = 4083,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_VSHORT]  = 4324,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]    = 5513,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]   = 6125,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_VSHORT]  = 6485,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]    = 7350,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]   = 8167,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_VSHORT]  = 8647,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]    = 11025,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]   = 12250,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_VSHORT]  = 12971,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]    = 14700,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]   = 16333,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_VSHORT]  = 17294,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]    = 16538,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]   = 18375,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_VSHORT]  = 19456,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]    = 18375,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]   = 20417,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_VSHORT]  = 21618,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]    = 22050,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]   = 24500,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_VSHORT]  = 25941,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]    = 24500,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]   = 27222,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_VSHORT]  = 28824,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_LONG]   = 27563,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_SHORT]  = 30625,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_10][WRS_GI_VSHORT] = 32426,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_LONG]   = 30625,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_SHORT]  = 34028,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_11][WRS_GI_VSHORT] = 36029,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]    = 2450,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]   = 2722,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_VSHORT]  = 2882,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]    = 4900,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]   = 5444,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_VSHORT]  = 5765,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]    = 7350,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]   = 8167,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_VSHORT]  = 8647,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]    = 9800,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]   = 10889,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_VSHORT]  = 11529,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]    = 14700,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]   = 16333,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_VSHORT]  = 17294,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]    = 19600,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]   = 21778,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_VSHORT]  = 23059,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]    = 22050,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]   = 24500,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_VSHORT]  = 25941,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]    = 24500,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]   = 27222,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_VSHORT]  = 28824,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]    = 29400,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]   = 32667,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_VSHORT]  = 34588,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]    = 32666,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]   = 36296,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_VSHORT]  = 38431,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_LONG]   = 36750,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_SHORT]  = 40833,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_10][WRS_GI_VSHORT] = 43235,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_LONG]   = 40833,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_SHORT]  = 45370,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_11][WRS_GI_VSHORT] = 48039,
+};
+
+/*
+ * This table of rates was taken from IEEE Std 802.11TM-2016, 21.5 Parameters
+ * for VHT-MCSs. The units are 1/10 Mbs. Invalid combinations are with 0's. Note
+ * that HT data rates are a subset of VHT data rates, so we can use a single
+ * table for both.
+ */
+const u16 data_rate_ht_vht_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT] = {
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]   = 65,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]  = 72,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]   = 130,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]  = 144,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]   = 195,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]  = 217,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]   = 260,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]  = 289,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]   = 390,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]  = 433,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]   = 520,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]  = 578,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]   = 585,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]  = 650,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]   = 650,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]  = 722,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]   = 780,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]  = 867,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]   = 0,
+	[CHNL_BW_20][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]  = 0,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]   = 130,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]  = 144,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]   = 260,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]  = 289,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]   = 390,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]  = 433,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]   = 520,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]  = 578,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]   = 780,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]  = 867,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]   = 1040,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]  = 1156,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]   = 1170,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]  = 1303,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]   = 1300,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]  = 1444,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]   = 1560,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]  = 1733,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]   = 0,
+	[CHNL_BW_20][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]  = 0,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]   = 195,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]  = 217,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]   = 390,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]  = 433,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]   = 585,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]  = 650,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]   = 780,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]  = 867,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]   = 1170,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]  = 1300,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]   = 1560,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]  = 1733,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]   = 1755,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]  = 1950,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]   = 1950,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]  = 2167,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]   = 2340,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]  = 2600,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]   = 2600,
+	[CHNL_BW_20][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]  = 2889,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]   = 260,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]  = 288,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]   = 520,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]  = 576,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]   = 780,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]  = 868,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]   = 1040,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]  = 1156,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]   = 1560,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]  = 1732,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]   = 2080,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]  = 2312,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]   = 2340,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]  = 2600,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]   = 2600,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]  = 2888,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]   = 3120,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]  = 3468,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]   = 0,
+	[CHNL_BW_20][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]  = 0,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]   = 135,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]  = 150,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]   = 270,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]  = 300,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]   = 405,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]  = 450,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]   = 540,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]  = 600,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]   = 810,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]  = 900,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]   = 1080,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]  = 1200,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]   = 1215,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]  = 1350,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]   = 1350,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]  = 1500,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]   = 1620,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]  = 1800,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]   = 1800,
+	[CHNL_BW_40][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]  = 2000,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]   = 270,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]  = 300,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]   = 540,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]  = 600,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]   = 810,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]  = 900,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]   = 1080,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]  = 1200,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]   = 1620,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]  = 1800,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]   = 2160,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]  = 2400,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]   = 2430,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]  = 2700,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]   = 2700,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]  = 3000,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]   = 3240,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]  = 3600,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]   = 3600,
+	[CHNL_BW_40][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]  = 4000,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]   = 405,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]  = 450,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]   = 810,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]  = 900,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]   = 1215,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]  = 1350,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]   = 1620,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]  = 1800,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]   = 2430,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]  = 2700,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]   = 3240,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]  = 3600,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]   = 3645,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]  = 4050,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]   = 4050,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]  = 4500,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]   = 4860,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]  = 5400,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]   = 5400,
+	[CHNL_BW_40][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]  = 6000,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]   = 540,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]  = 600,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]   = 1080,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]  = 1200,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]   = 1620,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]  = 1800,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]   = 2160,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]  = 2400,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]   = 3240,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]  = 3600,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]   = 4320,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]  = 4800,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]   = 4860,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]  = 5400,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]   = 5400,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]  = 6000,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]   = 6480,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]  = 7200,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]   = 7200,
+	[CHNL_BW_40][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]  = 8000,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]   = 293,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT]  = 325,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]   = 585,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT]  = 650,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]   = 878,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT]  = 975,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]   = 1170,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT]  = 1300,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]   = 1755,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT]  = 1950,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]   = 2340,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT]  = 2600,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]   = 2633,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT]  = 2925,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]   = 2925,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT]  = 3250,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]   = 3510,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT]  = 3900,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]   = 3900,
+	[CHNL_BW_80][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT]  = 4333,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]   = 585,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT]  = 650,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]   = 1170,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT]  = 1300,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]   = 1755,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT]  = 1950,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]   = 2340,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT]  = 2600,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]   = 3510,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT]  = 3900,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]   = 4680,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT]  = 5200,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]   = 5265,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT]  = 5850,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]   = 5850,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT]  = 6500,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]   = 7020,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT]  = 7800,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]   = 7800,
+	[CHNL_BW_80][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT]  = 8667,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]   = 878,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT]  = 975,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]   = 1755,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT]  = 1950,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]   = 2633,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT]  = 2925,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]   = 3510,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT]  = 3900,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]   = 5265,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT]  = 5850,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]   = 7020,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT]  = 7800,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]   = 0,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT]  = 0,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]   = 8775,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT]  = 9750,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]   = 10530,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT]  = 11700,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]   = 11700,
+	[CHNL_BW_80][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT]  = 13000,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]   = 1172,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT]  = 1300,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]   = 2340,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT]  = 2600,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]   = 3512,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT]  = 3900,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]   = 4680,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT]  = 5200,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]   = 7020,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT]  = 7800,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]   = 9360,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT]  = 10400,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]   = 10532,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT]  = 11700,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]   = 11700,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT]  = 13000,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]   = 14040,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT]  = 15600,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]   = 15600,
+	[CHNL_BW_80][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT]  = 17332,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_LONG]  = 585,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_0][WRS_GI_SHORT] = 650,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_LONG]  = 1170,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_1][WRS_GI_SHORT] = 1300,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_LONG]  = 1755,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_2][WRS_GI_SHORT] = 1950,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_LONG]  = 2340,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_3][WRS_GI_SHORT] = 2600,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_LONG]  = 3510,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_4][WRS_GI_SHORT] = 3900,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_LONG]  = 4680,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_5][WRS_GI_SHORT] = 5200,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_LONG]  = 5265,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_6][WRS_GI_SHORT] = 5850,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_LONG]  = 5850,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_7][WRS_GI_SHORT] = 6500,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_LONG]  = 7020,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_8][WRS_GI_SHORT] = 7800,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_LONG]  = 7800,
+	[CHNL_BW_160][WRS_SS_1][WRS_MCS_9][WRS_GI_SHORT] = 8667,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_LONG]  = 1170,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_0][WRS_GI_SHORT] = 1300,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_LONG]  = 2340,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_1][WRS_GI_SHORT] = 2600,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_LONG]  = 3510,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_2][WRS_GI_SHORT] = 3900,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_LONG]  = 4680,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_3][WRS_GI_SHORT] = 5200,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_LONG]  = 7020,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_4][WRS_GI_SHORT] = 7800,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_LONG]  = 9360,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_5][WRS_GI_SHORT] = 10400,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_LONG]  = 10530,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_6][WRS_GI_SHORT] = 11700,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_LONG]  = 11700,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_7][WRS_GI_SHORT] = 13000,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_LONG]  = 14040,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_8][WRS_GI_SHORT] = 15600,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_LONG]  = 15600,
+	[CHNL_BW_160][WRS_SS_2][WRS_MCS_9][WRS_GI_SHORT] = 17333,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_LONG]  = 1755,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_0][WRS_GI_SHORT] = 1950,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_LONG]  = 3510,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_1][WRS_GI_SHORT] = 3900,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_LONG]  = 5265,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_2][WRS_GI_SHORT] = 5850,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_LONG]  = 7020,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_3][WRS_GI_SHORT] = 7800,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_LONG]  = 10530,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_4][WRS_GI_SHORT] = 11700,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_LONG]  = 14040,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_5][WRS_GI_SHORT] = 15600,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_LONG]  = 15795,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_6][WRS_GI_SHORT] = 17550,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_LONG]  = 17550,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_7][WRS_GI_SHORT] = 19500,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_LONG]  = 21060,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_8][WRS_GI_SHORT] = 23400,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_LONG]  = 0,
+	[CHNL_BW_160][WRS_SS_3][WRS_MCS_9][WRS_GI_SHORT] = 0,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_LONG]  = 2340,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_0][WRS_GI_SHORT] = 2600,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_LONG]  = 4680,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_1][WRS_GI_SHORT] = 5200,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_LONG]  = 7020,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_2][WRS_GI_SHORT] = 7800,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_LONG]  = 9360,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_3][WRS_GI_SHORT] = 10400,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_LONG]  = 10400,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_4][WRS_GI_SHORT] = 15600,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_LONG]  = 18720,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_5][WRS_GI_SHORT] = 20800,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_LONG]  = 21060,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_6][WRS_GI_SHORT] = 23400,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_LONG]  = 23400,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_7][WRS_GI_SHORT] = 26000,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_LONG]  = 28080,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_8][WRS_GI_SHORT] = 31200,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_LONG]  = 31200,
+	[CHNL_BW_160][WRS_SS_4][WRS_MCS_9][WRS_GI_SHORT] = 34667,
+};
+
+/* OFDM Data Rates - (multiplied by 10) */
+const u16 data_rate_ofdm_x10[] = {
+	60,
+	90,
+	120,
+	180,
+	240,
+	360,
+	480,
+	540,
+};
+
+/* CCK Data Rates - (multiplied by 10) */
+const u16 data_rate_cck_x10[] = {
+	10,
+	20,
+	55,
+	110,
+};
+
+struct cl_inverse_data_rate inverse_data_rate;
+
+static u16 cl_data_rates_inverse_he(u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	return (80 << DATA_RATE_INVERSE_Q) / data_rate_he_x10[bw][nss][mcs][gi];
+}
+
+static u16 cl_data_rates_inverse_vht(u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	u16 data_rate = data_rate_ht_vht_x10[bw][nss][mcs][gi];
+
+	if (data_rate)
+		return (80 << DATA_RATE_INVERSE_Q) / data_rate;
+
+	return 0;
+}
+
+static u16 cl_data_rates_inverse_ofdm(u8 mcs)
+{
+	return (80 << DATA_RATE_INVERSE_Q) / data_rate_ofdm_x10[mcs];
+}
+
+static u16 cl_data_rates_inverse_cck(u8 mcs)
+{
+	return (80 << DATA_RATE_INVERSE_Q) / data_rate_cck_x10[mcs];
+}
+
+void cl_data_rates_inverse_build(void)
+{
+	/*
+	 * The calculation is: round((2^15[Q] * 8[bits] * 10)/rate[Mbps]) - unit (us * 2^15)
+	 * multiply by 10 because data rates in the above tables are also multiplied by 10
+	 */
+	u8 bw, nss, mcs, gi;
+
+	for (bw = 0; bw < CHNL_BW_MAX; bw++)
+		for (nss = 0; nss < WRS_SS_MAX; nss++) {
+			/* HE */
+			for (mcs = 0; mcs < WRS_MCS_MAX_HE; mcs++)
+				for (gi = 0; gi < WRS_GI_MAX_HE; gi++)
+					inverse_data_rate.he[bw][nss][mcs][gi] =
+						cl_data_rates_inverse_he(bw, nss, mcs, gi);
+
+			/* VHT */
+			for (mcs = 0; mcs < WRS_MCS_MAX_VHT; mcs++)
+				for (gi = 0; gi < WRS_GI_MAX_VHT; gi++)
+					inverse_data_rate.ht_vht[bw][nss][mcs][gi] =
+						cl_data_rates_inverse_vht(bw, nss, mcs, gi);
+		}
+
+	/* OFDM */
+	for (mcs = 0; mcs < WRS_MCS_MAX_OFDM; mcs++)
+		inverse_data_rate.ofdm[mcs] = cl_data_rates_inverse_ofdm(mcs);
+
+	/* CCK */
+	for (mcs = 0; mcs < WRS_MCS_MAX_CCK; mcs++)
+		inverse_data_rate.cck[mcs] = cl_data_rates_inverse_cck(mcs);
+}
+
+u16 cl_data_rates_get(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	return cl_data_rates_get_x10(mode, bw, nss, mcs, gi) / 10;
+}
+
+u16 cl_data_rates_get_x10(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	switch (mode) {
+	case WRS_MODE_HE:
+		return data_rate_he_x10[bw][nss][mcs][gi];
+	case WRS_MODE_VHT:
+	case WRS_MODE_HT:
+		return data_rate_ht_vht_x10[bw][nss][mcs][gi];
+	case WRS_MODE_OFDM:
+		return data_rate_ofdm_x10[mcs];
+	case WRS_MODE_CCK:
+		return data_rate_cck_x10[mcs];
+	default:
+		return 0;
+	}
+}
+
+u32 cl_rate_ctrl_generate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			  u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi,
+			  bool fallback_en, bool mu_valid)
+{
+	union cl_rate_ctrl_info rate_ctrl_info;
+
+	rate_ctrl_info.word = 0;
+
+	/* Format_mod + mcs_index */
+	if (mode == WRS_MODE_HE) {
+		rate_ctrl_info.field.mcs_index = (nss << 4) | mcs;
+		rate_ctrl_info.field.format_mod = FORMATMOD_HE_SU;
+	} else if (mode == WRS_MODE_VHT) {
+		rate_ctrl_info.field.mcs_index = (nss << 4) | mcs;
+		rate_ctrl_info.field.format_mod = FORMATMOD_VHT;
+	} else if (mode == WRS_MODE_HT) {
+		rate_ctrl_info.field.mcs_index = (nss << 3) | mcs;
+		rate_ctrl_info.field.format_mod = FORMATMOD_HT_MF;
+	} else if (mode == WRS_MODE_OFDM) {
+		rate_ctrl_info.field.mcs_index = mcs + RATE_CTRL_OFFSET_OFDM;
+		rate_ctrl_info.field.format_mod =
+			(bw == CHNL_BW_20) ? FORMATMOD_NON_HT : FORMATMOD_NON_HT_DUP_OFDM;
+	} else { /* WRS_MODE_CCK */
+		rate_ctrl_info.field.mcs_index = mcs;
+		rate_ctrl_info.field.format_mod = FORMATMOD_NON_HT;
+	}
+
+	/* Gi */
+	rate_ctrl_info.field.gi = cl_convert_gi_format_wrs_to_fw(mode, gi);
+
+	/* Bw */
+	rate_ctrl_info.field.bw = bw;
+
+	/* Fallback */
+	rate_ctrl_info.field.fallback = fallback_en;
+
+	/* Tx_bf */
+	if (!mu_valid && cl_sta && cl_bf_is_on(cl_hw, cl_sta, nss))
+		rate_ctrl_info.field.tx_bf = true;
+
+	/* Pre_type/stbc */
+	if (rate_ctrl_info.field.format_mod == FORMATMOD_NON_HT)
+		rate_ctrl_info.field.pre_type_or_stbc = 1;
+
+	return rate_ctrl_info.word;
+}
+
+void cl_rate_ctrl_convert(union cl_rate_ctrl_info *rate_ctrl_info)
+{
+	u32 format_mod = rate_ctrl_info->field.format_mod;
+
+	/*
+	 * Convert gi from firmware format to driver format
+	 * !!! Must be done before converting the format mode !!!
+	 */
+	rate_ctrl_info->field.gi = cl_convert_gi_format_fw_to_wrs(format_mod,
+								  rate_ctrl_info->field.gi);
+
+	/* Convert format_mod from firmware format to WRS format */
+	if (format_mod >= FORMATMOD_HE_SU) {
+		rate_ctrl_info->field.format_mod = WRS_MODE_HE;
+	} else if (format_mod == FORMATMOD_VHT) {
+		rate_ctrl_info->field.format_mod = WRS_MODE_VHT;
+	} else if (format_mod >= FORMATMOD_HT_MF) {
+		rate_ctrl_info->field.format_mod = WRS_MODE_HT;
+	} else if (format_mod == FORMATMOD_NON_HT_DUP_OFDM) {
+		rate_ctrl_info->field.format_mod = WRS_MODE_OFDM;
+	} else {
+		if (rate_ctrl_info->field.mcs_index >= RATE_CTRL_OFFSET_OFDM)
+			rate_ctrl_info->field.format_mod = WRS_MODE_OFDM;
+		else
+			rate_ctrl_info->field.format_mod = WRS_MODE_CCK;
+	}
+}
+
+void cl_rate_ctrl_parse(union cl_rate_ctrl_info *rate_ctrl_info, u8 *nss, u8 *mcs)
+{
+	switch (rate_ctrl_info->field.format_mod) {
+	case WRS_MODE_HE:
+	case WRS_MODE_VHT:
+		*nss = (rate_ctrl_info->field.mcs_index >> 4);
+		*mcs = (rate_ctrl_info->field.mcs_index & 0xF);
+		break;
+	case WRS_MODE_HT:
+		*nss = (rate_ctrl_info->field.mcs_index >> 3);
+		*mcs = (rate_ctrl_info->field.mcs_index & 0x7);
+		break;
+	case WRS_MODE_OFDM:
+		*nss = 0;
+		*mcs = rate_ctrl_info->field.mcs_index - RATE_CTRL_OFFSET_OFDM;
+		break;
+	case WRS_MODE_CCK:
+		*nss = 0;
+		*mcs = rate_ctrl_info->field.mcs_index;
+		break;
+	default:
+		*nss = *mcs = 0;
+	}
+}
+
+void cl_rate_ctrl_set_default(struct cl_hw *cl_hw)
+{
+	u32 rate_ctrl = 0;
+	union cl_rate_ctrl_info_he rate_ctrl_he;
+
+	/* HE default */
+	rate_ctrl_he.word = 0;
+	rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+	rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_HE,
+					  0, 0, 0, 0, false, false);
+
+	cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_DEFAULT_HE, 0, 0, LTF_X4, 0, rate_ctrl_he.word);
+
+	/* OFDM default */
+	rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_OFDM, 0, 0,
+					  cl_hw->conf->ce_default_mcs_ofdm, 0, false, false);
+
+	cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_DEFAULT_OFDM, 0, 0, 0, 0, 0);
+
+	/* CCK default */
+	if (cl_band_is_24g(cl_hw)) {
+		rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_CCK, 0, 0,
+						  cl_hw->conf->ce_default_mcs_cck, 0, false, false);
+
+		cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+					 RATE_OP_MODE_DEFAULT_CCK, 0, 0, 0, 0, 0);
+	}
+}
+
+void cl_rate_ctrl_set_default_per_he_minrate(struct cl_hw *cl_hw, u8 bw,
+					     u8 nss, u8 mcs, u8 gi)
+{
+	union cl_rate_ctrl_info_he rate_ctrl_he;
+	u32 rate_ctrl = 0;
+	u8 ltf = cl_map_gi_to_ltf(WRS_MODE_HE, gi);
+
+	rate_ctrl_he.word = 0;
+	rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+	rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, WRS_MODE_HE, bw,
+					  nss, mcs, gi, false, false);
+
+	cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_DEFAULT_HE, 0, 0, ltf,
+				 0, rate_ctrl_he.word);
+
+	cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_MCAST, 0, 0, ltf, 0, 0);
+
+	cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_BCAST, 0, 0, ltf, 0, 0);
+}
+
+bool cl_rate_ctrl_set_mcast(struct cl_hw *cl_hw, u8 mode, u8 mcs)
+{
+	u32 rate_ctrl_mcast = cl_rate_ctrl_generate(cl_hw, NULL, mode, 0, 0, mcs,
+						    WRS_GI_LONG, false, false);
+	u8 ltf = cl_map_gi_to_ltf(mode, WRS_GI_LONG);
+
+	if (cl_msg_tx_update_rate_dl(cl_hw, 0xff, rate_ctrl_mcast, 0, 0,
+				     RATE_OP_MODE_MCAST, 0, 0, ltf, 0, 0))
+		return false;
+
+	return true;
+}
+
+static u8 cl_rate_ctrl_get_min(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_min_he_en &&
+	    cl_hw->wireless_mode == WIRELESS_MODE_HE)
+		return RATE_CTRL_ENTRY_MIN_HE;
+
+	if (cl_hw_mode_is_b_or_bg(cl_hw))
+		return RATE_CTRL_ENTRY_MIN_CCK;
+
+	return RATE_CTRL_ENTRY_MIN_OFDM;
+}
+
+void cl_rate_ctrl_update_desc_single(struct cl_hw *cl_hw, struct tx_host_info *info,
+				     struct cl_sw_txhdr *sw_txhdr)
+{
+	struct ieee80211_hdr *mac_hdr = sw_txhdr->hdr80211;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	bool is_data = ieee80211_is_data(sw_txhdr->fc);
+
+	if (sw_txhdr->cl_sta && is_data) {
+		if (cl_tx_ctrl_is_eapol(tx_info)) {
+			info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+		} else {
+			if (cl_hw->entry_fixed_rate)
+				info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+			else
+				info->rate_ctrl_entry = RATE_CTRL_ENTRY_STA;
+		}
+	} else {
+		if (sw_txhdr->is_bcn) {
+			info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+		} else if (is_multicast_ether_addr(mac_hdr->addr1) &&
+			   !is_broadcast_ether_addr(mac_hdr->addr1)) {
+			info->rate_ctrl_entry = RATE_CTRL_ENTRY_MCAST;
+		} else if (is_broadcast_ether_addr(mac_hdr->addr1) &&
+			   !cl_hw->entry_fixed_rate) {
+			info->rate_ctrl_entry = RATE_CTRL_ENTRY_BCAST;
+		} else {
+			if (cl_hw->entry_fixed_rate && is_data)
+				info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+			else
+				info->rate_ctrl_entry = cl_rate_ctrl_get_min(cl_hw);
+		}
+	}
+}
+
+void cl_rate_ctrl_update_desc_agg(struct cl_hw *cl_hw, struct tx_host_info *info)
+{
+	/* For aggregation there are only two options - STA and FIXED_RATE */
+	if (cl_hw->entry_fixed_rate)
+		info->rate_ctrl_entry = RATE_CTRL_ENTRY_FIXED_RATE;
+	else
+		info->rate_ctrl_entry = RATE_CTRL_ENTRY_STA;
+}
+
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+
+/*
+ * MIN_MCS | BCAST_MCS
+ * -------------------
+ * 0 - 1   | 0
+ * 2 - 3   | 1
+ * 4 - 5   | 2
+ * 6 - 7   | 3
+ * 8 - 9   | 4
+ * 10 - 11 | 5
+ */
+
+static u8 conv_min_mcs_to_bcast_mcs[WRS_MCS_MAX] = {
+	0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5
+};
+
+static void cl_dyn_bcast_rate_update(struct cl_hw *cl_hw, u8 min_mcs)
+{
+	struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+	u8 bcast_mcs = conv_min_mcs_to_bcast_mcs[min_mcs];
+
+	dyn_bcast_rate->sta_min_mcs = min_mcs;
+
+	if (bcast_mcs != dyn_bcast_rate->bcast_mcs)
+		cl_dyn_bcast_rate_set(cl_hw, bcast_mcs);
+}
+
+static struct cl_dyn_bcast_rate cl_dyn_bcast_rate_prepare(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_bcast_rate dyn_bcast_rate;
+
+	memset(&dyn_bcast_rate, 0, sizeof(struct cl_dyn_bcast_rate));
+	dyn_bcast_rate.sta_min_mcs = 0;
+	dyn_bcast_rate.bcast_mcs = conv_min_mcs_to_bcast_mcs[0];
+
+	if (cl_band_is_6g(cl_hw)) {
+		dyn_bcast_rate.wrs_mode = cl_hw->conf->ci_min_he_en ?
+			WRS_MODE_HE : WRS_MODE_OFDM;
+		dyn_bcast_rate.ltf = LTF_X4;
+	} else if (cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw)) {
+		dyn_bcast_rate.wrs_mode = WRS_MODE_CCK;
+		dyn_bcast_rate.ltf = 0;
+	} else {
+		dyn_bcast_rate.wrs_mode = WRS_MODE_OFDM;
+		dyn_bcast_rate.ltf = 0;
+	}
+
+	return dyn_bcast_rate;
+}
+
+void cl_dyn_bcast_rate_init(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_bcast_rate dyn_bcast_rate;
+
+	dyn_bcast_rate = cl_dyn_bcast_rate_prepare(cl_hw);
+	memcpy(&cl_hw->dyn_bcast_rate, &dyn_bcast_rate, sizeof(struct cl_dyn_bcast_rate));
+}
+
+void cl_dyn_bcast_rate_set(struct cl_hw *cl_hw, u8 bcast_mcs)
+{
+	struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+	u8 wrs_mode = dyn_bcast_rate->wrs_mode;
+	u8 ltf = dyn_bcast_rate->ltf;
+	u32 rate_ctrl;
+
+	cl_hw->dyn_bcast_rate.bcast_mcs = bcast_mcs;
+
+	rate_ctrl = cl_rate_ctrl_generate(cl_hw, NULL, wrs_mode, 0, 0, bcast_mcs,
+					  0, false, false);
+	cl_msg_tx_update_rate_dl(cl_hw, U8_MAX, rate_ctrl, 0, 0,
+				 RATE_OP_MODE_BCAST, 0, 0, ltf, 0, 0);
+
+	cl_dbg_info(cl_hw, "Broadcast MCS set to %u\n", bcast_mcs);
+}
+
+void cl_dyn_bcast_update(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_bcast_rate dyn_bcast_rate;
+
+	dyn_bcast_rate = cl_dyn_bcast_rate_prepare(cl_hw);
+	if (cl_hw->dyn_bcast_rate.wrs_mode == dyn_bcast_rate.wrs_mode)
+		return;
+
+	memcpy(&cl_hw->dyn_bcast_rate, &dyn_bcast_rate, sizeof(struct cl_dyn_bcast_rate));
+	cl_dyn_bcast_rate_set(cl_hw, cl_hw->dyn_bcast_rate.bcast_mcs);
+}
+
+void cl_dyn_bcast_rate_recovery(struct cl_hw *cl_hw)
+{
+	cl_dyn_bcast_rate_set(cl_hw, cl_hw->dyn_bcast_rate.bcast_mcs);
+}
+
+void cl_dyn_bcast_rate_change(struct cl_hw *cl_hw, struct cl_sta *cl_sta_change,
+			      u8 old_mcs, u8 new_mcs)
+{
+	struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+	struct cl_sta *cl_sta = NULL;
+	u8 min_mcs = WRS_MCS_MAX - 1;
+	u8 sta_mcs = 0;
+
+	if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+		return;
+
+	if (!cl_sta_change->add_complete)
+		return;
+
+	/* Single station */
+	if (cl_sta_num_bh(cl_hw) == 1) {
+		cl_dyn_bcast_rate_update(cl_hw, new_mcs);
+		return;
+	}
+
+	/*
+	 * If this station did not have the minimum mcs,
+	 * and the new rate is now below the minimum mcs there is nothing to do
+	 */
+	if (old_mcs > dyn_bcast_rate->sta_min_mcs &&
+	    new_mcs > dyn_bcast_rate->sta_min_mcs)
+		return;
+
+	/* Multi station - find new minimum MCS of all stations */
+	cl_sta_lock_bh(cl_hw);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+		sta_mcs = (cl_sta->sta_idx == cl_sta_change->sta_idx) ?
+			new_mcs : cl_sta->wrs_sta.tx_su_params.rate_params.mcs;
+
+		if (sta_mcs < min_mcs) {
+			min_mcs = sta_mcs;
+
+			if (min_mcs == 0)
+				break;
+		}
+	}
+
+	cl_sta_unlock_bh(cl_hw);
+
+	cl_dyn_bcast_rate_update(cl_hw, min_mcs);
+}
+
+void cl_dyn_bcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta)
+{
+	struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+
+	if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+		return;
+
+	if (num_sta == 1 || mcs < dyn_bcast_rate->sta_min_mcs)
+		cl_dyn_bcast_rate_update(cl_hw, mcs);
+}
+
+void cl_dyn_bcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta)
+{
+	struct cl_dyn_bcast_rate *dyn_bcast_rate = &cl_hw->dyn_bcast_rate;
+	struct cl_sta *cl_sta = NULL;
+	u8 min_mcs = WRS_MCS_MAX - 1;
+
+	if (!cl_hw->conf->ce_dyn_bcast_rate_en)
+		return;
+
+	/* When the last station disconnects - set bcast back to 0 */
+	if (num_sta == 0) {
+		cl_dyn_bcast_rate_update(cl_hw, 0);
+		return;
+	}
+
+	/* If this station did not have the minimum rate there is nothing to do */
+	if (mcs > dyn_bcast_rate->sta_min_mcs)
+		return;
+
+	/*
+	 * Find new minimum MCS of all station (the disassociating
+	 * station is not in list at this stage)
+	 */
+	cl_sta_lock_bh(cl_hw);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+		if (cl_sta->wrs_sta.tx_su_params.rate_params.mcs < min_mcs) {
+			min_mcs = cl_sta->wrs_sta.tx_su_params.rate_params.mcs;
+
+			if (min_mcs == 0)
+				break;
+		}
+	}
+
+	cl_sta_unlock_bh(cl_hw);
+
+	cl_dyn_bcast_rate_update(cl_hw, min_mcs);
+}
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+
+static void _cl_dyn_mcast_rate_send(struct cl_hw *cl_hw, u8 wrs_mode_new)
+{
+	struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+	if (dyn_mcast_rate->wrs_mode_curr == wrs_mode_new)
+		return;
+
+	if (!cl_rate_ctrl_set_mcast(cl_hw, wrs_mode_new, cl_hw->conf->ce_mcast_rate))
+		return;
+
+	dyn_mcast_rate->wrs_mode_curr = wrs_mode_new;
+	cl_dbg_trace(cl_hw, "New multicast mode = %u\n", wrs_mode_new);
+}
+
+static struct cl_dyn_mcast_rate cl_dyn_mcast_rate_prepare(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_mcast_rate dyn_mcast_rate;
+
+	memset(&dyn_mcast_rate, 0, sizeof(struct cl_dyn_mcast_rate));
+	if (cl_hw->conf->ci_min_he_en &&
+	    cl_hw->wireless_mode == WIRELESS_MODE_HE)
+		dyn_mcast_rate.wrs_mode_default = WRS_MODE_HE;
+	else if (cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw))
+		dyn_mcast_rate.wrs_mode_default = WRS_MODE_CCK;
+	else
+		dyn_mcast_rate.wrs_mode_default = WRS_MODE_OFDM;
+
+	return dyn_mcast_rate;
+}
+
+void cl_dyn_mcast_rate_init(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_mcast_rate dyn_mcast_rate;
+
+	dyn_mcast_rate = cl_dyn_mcast_rate_prepare(cl_hw);
+	cl_hw->dyn_mcast_rate.wrs_mode_default = dyn_mcast_rate.wrs_mode_default;
+
+	cl_dbg_trace(cl_hw, "mode = %u, mcs = %u\n",
+		     dyn_mcast_rate.wrs_mode_default, cl_hw->conf->ce_mcast_rate);
+}
+
+void cl_dyn_mcast_rate_set(struct cl_hw *cl_hw)
+{
+	/*
+	 * Set wrs_mode_curr to 0xff so that the message will be sent to
+	 * firmware when this function is called from cl_ops_start()
+	 */
+	struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+	dyn_mcast_rate->wrs_mode_curr = U8_MAX;
+
+	_cl_dyn_mcast_rate_send(cl_hw, dyn_mcast_rate->wrs_mode_default);
+}
+
+void cl_dyn_mcast_update(struct cl_hw *cl_hw)
+{
+	struct cl_dyn_mcast_rate dyn_mcast_rate;
+
+	dyn_mcast_rate = cl_dyn_mcast_rate_prepare(cl_hw);
+	if (cl_hw->dyn_mcast_rate.wrs_mode_default == dyn_mcast_rate.wrs_mode_default)
+		return;
+
+	cl_hw->dyn_mcast_rate.wrs_mode_default = dyn_mcast_rate.wrs_mode_default;
+	cl_dyn_mcast_rate_set(cl_hw);
+}
+
+void cl_dyn_mcast_rate_recovery(struct cl_hw *cl_hw)
+{
+	/*
+	 * cl_dyn_mcast_rate_recovery() is called during recovery process().
+	 * Reset wrs_mode_curr so that message will be sent.
+	 */
+	struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+	u8 wrs_mode_curr = dyn_mcast_rate->wrs_mode_curr;
+
+	dyn_mcast_rate->wrs_mode_curr = U8_MAX;
+
+	_cl_dyn_mcast_rate_send(cl_hw, wrs_mode_curr);
+}
+
+void cl_dyn_mcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta)
+{
+	struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+
+	if (!cl_hw->conf->ce_dyn_mcast_rate_en)
+		return;
+
+	/*
+	 * If the wrs_mode of the new station is lower than the current multicast
+	 * wrs_mode, or if this is the first station to connect - update multicast mode
+	 */
+	if (wrs_mode < dyn_mcast_rate->wrs_mode_curr || num_sta == 1)
+		_cl_dyn_mcast_rate_send(cl_hw, wrs_mode);
+}
+
+void cl_dyn_mcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta)
+{
+	struct cl_dyn_mcast_rate *dyn_mcast_rate = &cl_hw->dyn_mcast_rate;
+	struct cl_sta *cl_sta = NULL;
+	u8 wrs_mode_min = WRS_MODE_HE;
+
+	if (!cl_hw->conf->ce_dyn_mcast_rate_en)
+		return;
+
+	/* When the last station disconnects - set default mcast rate */
+	if (num_sta == 0) {
+		_cl_dyn_mcast_rate_send(cl_hw, dyn_mcast_rate->wrs_mode_default);
+		return;
+	}
+
+	/*
+	 * If wrs_mode of the disassociating station is bigger
+	 * than the current mode then there is nothing to update.
+	 */
+	if (wrs_mode > dyn_mcast_rate->wrs_mode_curr)
+		return;
+
+	/*
+	 * Find minimal wrs_mode among the connected stations (the
+	 * disassociating station is not in list at this stage).
+	 */
+	cl_sta_lock_bh(cl_hw);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+		if (cl_sta->wrs_sta.mode < wrs_mode_min)
+			wrs_mode_min = cl_sta->wrs_sta.mode;
+
+	cl_sta_unlock_bh(cl_hw);
+
+	_cl_dyn_mcast_rate_send(cl_hw, wrs_mode_min);
+}
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 59/96] cl8k: add rates.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (57 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 58/96] cl8k: add rates.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-26 19:54   ` Johannes Berg
  2022-05-24 11:34 ` [RFC v2 60/96] cl8k: add recovery.c viktor.barna
                   ` (36 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rates.h | 154 +++++++++++++++++++++++
 1 file changed, 154 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rates.h

diff --git a/drivers/net/wireless/celeno/cl8k/rates.h b/drivers/net/wireless/celeno/cl8k/rates.h
new file mode 100644
index 000000000000..223924f21dc2
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rates.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_RATE_CTRL_H
+#define CL_RATE_CTRL_H
+
+#include <linux/types.h>
+
+#include "ipc_shared.h"
+#include "wrs.h"
+
+#define RATE_CTRL_OFFSET_OFDM          4
+#define RATE_CNTRL_HE_SPATIAL_CONF_DEF 0xF
+
+/* Op_mode field in mm_update_rate_dl_req structure */
+enum cl_op_mode {
+	RATE_OP_MODE_FIXED,
+	RATE_OP_MODE_DEFAULT_HE,
+	RATE_OP_MODE_DEFAULT_OFDM,
+	RATE_OP_MODE_DEFAULT_CCK,
+	RATE_OP_MODE_STA_SU,
+	RATE_OP_MODE_STA_MU,
+	RATE_OP_MODE_MCAST,
+	RATE_OP_MODE_BCAST
+};
+
+/* Value to be set in tx_host_info */
+enum cl_rate_ctrl_entry {
+	RATE_CTRL_ENTRY_NA = 0,
+
+	RATE_CTRL_ENTRY_STA,
+	RATE_CTRL_ENTRY_FIXED_RATE,
+	RATE_CTRL_ENTRY_MIN_HE,
+	RATE_CTRL_ENTRY_MIN_OFDM,
+	RATE_CTRL_ENTRY_MIN_CCK,
+	RATE_CTRL_ENTRY_MCAST,
+	RATE_CTRL_ENTRY_BCAST,
+
+	/* Entry size in firmware is represented by 3 bits */
+	RATE_CTRL_ENTRY_MAX = 8
+};
+
+/*
+ * sw_ctrl includes eights bits (16 - 23) to be used by software.
+ * Bit 16 is used by driver to indicate tx_bf.
+ * Bit 17 is used by driver to indicate fallback.
+ * Bit 18 - 23 are still free.
+ */
+struct cl_rate_ctrl_info_fields {
+	u32 mcs_index        : 7;   /* [6:0] */
+	u32 bw               : 2;   /* [8:7] */
+	u32 gi               : 2;   /* [10:9] */
+	u32 pre_type_or_stbc : 1;   /* [11] */
+	u32 format_mod       : 4;   /* [15:12] */
+	u32 tx_bf            : 1;   /* [16] */
+	u32 fallback         : 1;   /* [17] */
+	u32 sw_ctrl          : 6;   /* [23:18] */
+	u32 tx_chains        : 8;   /* [31:24] */
+};
+
+union cl_rate_ctrl_info {
+	struct cl_rate_ctrl_info_fields field;
+	u32 word;
+};
+
+struct cl_rate_ctrl_info_he_fields {
+	u32 spatial_conf    : 4;   /* [3:0] */
+	u32 starting_sts    : 3;   /* [6:4] */
+	u32 ru_index        : 6;   /* [12:7] */
+	u32 ru_type         : 3;   /* [15:13] */
+	u32 ru_band         : 1;   /* [16] */
+	u32 mu_usr_pos      : 2;   /* [18:17] */
+	u32 dcm_data        : 1;   /* [19] */
+	u32 num_usrs_mu_dl  : 4;   /* [23:20] */
+	u32 ru_alloc        : 8;   /* [31:24] */
+};
+
+union cl_rate_ctrl_info_he {
+	struct cl_rate_ctrl_info_he_fields field;
+	u32 word;
+};
+
+#define DATA_RATE_INVERSE_Q 15
+
+struct cl_inverse_data_rate {
+	u16 he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+	u16 ht_vht[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+	u16 ofdm[WRS_MCS_MAX_OFDM];
+	u16 cck[WRS_MCS_MAX_CCK];
+};
+
+extern struct cl_inverse_data_rate inverse_data_rate;
+
+extern const u16 data_rate_he_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+extern const u16 data_rate_ht_vht_x10[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+extern const u16 data_rate_ofdm_x10[];
+extern const u16 data_rate_cck_x10[];
+
+struct cl_hw;
+struct cl_sta;
+struct cl_sw_txhdr;
+
+u32 cl_rate_ctrl_generate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			  u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi,
+			  bool fallback_en, bool mu_valid);
+void cl_rate_ctrl_convert(union cl_rate_ctrl_info *rate_ctrl_info);
+void cl_rate_ctrl_parse(union cl_rate_ctrl_info *rate_ctrl_info, u8 *nss, u8 *mcs);
+
+void cl_rate_ctrl_set_default(struct cl_hw *cl_hw);
+
+void cl_rate_ctrl_set_default_per_he_minrate(struct cl_hw *cl_hw, u8 bw,
+					     u8 nss, u8 mcs, u8 gi);
+bool cl_rate_ctrl_set_mcast(struct cl_hw *cl_hw, u8 mode, u8 mcs);
+void cl_rate_ctrl_update_desc_single(struct cl_hw *cl_hw, struct tx_host_info *info,
+				     struct cl_sw_txhdr *sw_txhdr);
+void cl_rate_ctrl_update_desc_agg(struct cl_hw *cl_hw, struct tx_host_info *info);
+void cl_data_rates_inverse_build(void);
+u16 cl_data_rates_get(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi);
+u16 cl_data_rates_get_x10(u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi);
+
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+
+struct cl_dyn_bcast_rate {
+	u8 sta_min_mcs;
+	u8 bcast_mcs;
+	u8 wrs_mode;
+	u8 ltf;
+};
+
+void cl_dyn_bcast_rate_init(struct cl_hw *cl_hw);
+void cl_dyn_bcast_rate_set(struct cl_hw *cl_hw, u8 bcast_mcs);
+void cl_dyn_bcast_rate_recovery(struct cl_hw *cl_hw);
+void cl_dyn_bcast_rate_change(struct cl_hw *cl_hw, struct cl_sta *cl_sta_change,
+			      u8 old_mcs, u8 new_mcs);
+void cl_dyn_bcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta);
+void cl_dyn_bcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 mcs, u8 num_sta);
+void cl_dyn_bcast_update(struct cl_hw *cl_hw);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+
+struct cl_dyn_mcast_rate {
+	u8 wrs_mode_default;
+	u8 wrs_mode_curr;
+};
+
+void cl_dyn_mcast_rate_init(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_set(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_recovery(struct cl_hw *cl_hw);
+void cl_dyn_mcast_rate_update_upon_assoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta);
+void cl_dyn_mcast_rate_update_upon_disassoc(struct cl_hw *cl_hw, u8 wrs_mode, u8 num_sta);
+void cl_dyn_mcast_update(struct cl_hw *cl_hw);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+
+#endif /* CL_RATE_CTRL_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 60/96] cl8k: add recovery.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (58 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 61/96] cl8k: add recovery.h viktor.barna
                   ` (35 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/recovery.c | 280 ++++++++++++++++++++
 1 file changed, 280 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.c

diff --git a/drivers/net/wireless/celeno/cl8k/recovery.c b/drivers/net/wireless/celeno/cl8k/recovery.c
new file mode 100644
index 000000000000..dc0c33be9200
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/recovery.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "hw.h"
+#include "main.h"
+#include "phy.h"
+#include "vif.h"
+#include "dfs.h"
+#include "maintenance.h"
+#include "vns.h"
+#include "config.h"
+#include "ela.h"
+#include "radio.h"
+#include "recovery.h"
+
+struct cl_recovery_work {
+	struct work_struct ws;
+	struct cl_hw *cl_hw;
+	int reason;
+};
+
+#define RECOVERY_POLL_TIMEOUT 6
+
+static void cl_recovery_poll_completion(struct cl_hw *cl_hw)
+{
+	u8 cntr = 0;
+
+	while (test_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags)) {
+		msleep(1000);
+
+		if (++cntr == RECOVERY_POLL_TIMEOUT) {
+			cl_dbg_verbose(cl_hw, "\n");
+			cl_dbg_err(cl_hw, "Driver handgup was detected!...");
+			break;
+		}
+	}
+}
+
+static void cl_recovery_start_hw(struct cl_hw *cl_hw)
+{
+	clear_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags);
+
+	/* Restart MAC firmware... */
+	if (cl_main_on(cl_hw)) {
+		cl_dbg_err(cl_hw, "Couldn't turn platform on .. aborting\n");
+		return;
+	}
+
+	if (cl_msg_tx_reset(cl_hw)) {
+		cl_dbg_err(cl_hw, "Failed to send firmware reset .. aborting\n");
+		return;
+	}
+
+	set_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags);
+	clear_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags);
+
+	/* Hand over to mac80211 from here */
+	ieee80211_restart_hw(cl_hw->hw);
+	/* Start firmware */
+	if (cl_msg_tx_start(cl_hw)) {
+		cl_dbg_err(cl_hw, "Failed to send firmware start .. aborting\n");
+		return;
+	}
+
+	cl_recovery_poll_completion(cl_hw);
+}
+
+static void cl_recovery_stop_hw(struct cl_hw *cl_hw)
+{
+	/* Start recovery process */
+	ieee80211_stop_queues(cl_hw->hw);
+	cl_hw->recovery_db.in_recovery = true;
+
+	clear_bit(CL_DEV_STARTED, &cl_hw->drv_flags);
+	set_bit(CL_DEV_HW_RESTART, &cl_hw->drv_flags);
+	set_bit(CL_DEV_STOP_HW, &cl_hw->drv_flags);
+	/* Disable interrupts */
+	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
+	cl_maintenance_stop(cl_hw);
+
+	mutex_lock(&cl_hw->dbginfo.mutex);
+
+	cl_main_off(cl_hw);
+
+	cl_hw->fw_active = false;
+	cl_hw->fw_send_start = false;
+
+	mutex_unlock(&cl_hw->dbginfo.mutex);
+
+	/* Reset it so MM_SET_FILTER_REQ will be called during the recovery */
+	cl_hw->rx_filter = 0;
+
+	/*
+	 * Reset channel/frequency parameters so that cl_msg_tx_set_channel()
+	 * will not be skipped in cl_ops_config()
+	 */
+	cl_hw->channel = 0;
+	cl_hw->primary_freq = 0;
+	cl_hw->center_freq = 0;
+}
+
+static void cl_recovery_process(struct cl_hw *cl_hw)
+{
+	int ret;
+	struct cl_chip *chip = cl_hw->chip;
+
+	mutex_lock(&chip->recovery_mutex);
+
+	cl_dbg_verbose(cl_hw, "Start\n");
+
+	cl_recovery_stop_hw(cl_hw);
+
+	if (chip->conf->ci_phy_dev != PHY_DEV_DUMMY) {
+		cl_phy_reset(cl_hw);
+
+		ret = cl_phy_load_recovery(cl_hw);
+		if (ret) {
+			cl_dbg_err(cl_hw, "cl_phy_load_recovery failed %d\n", ret);
+			goto out;
+		}
+	}
+
+	cl_recovery_start_hw(cl_hw);
+
+out:
+	mutex_unlock(&chip->recovery_mutex);
+}
+
+static void cl_recovery_handler(struct cl_hw *cl_hw, int reason)
+{
+	unsigned long recovery_diff = jiffies_to_msecs(jiffies - cl_hw->recovery_db.last_restart);
+
+	cl_hw->recovery_db.restart_cnt++;
+
+	if (recovery_diff > cl_hw->conf->ce_fw_watchdog_limit_time) {
+		cl_hw->recovery_db.restart_cnt = 1;
+	} else if (cl_hw->recovery_db.restart_cnt > cl_hw->conf->ce_fw_watchdog_limit_count) {
+		cl_dbg_verbose(cl_hw, "Too many failures... aborting\n");
+		cl_hw->conf->ce_fw_watchdog_mode = FW_WD_DISABLE;
+		return;
+	}
+
+	cl_hw->recovery_db.last_restart = jiffies;
+
+	/* Count recovery attempts for statistics */
+	cl_hw->fw_recovery_cntr++;
+	cl_dbg_trace(cl_hw, "Recovering from firmware failure, attempt #%i\n",
+		     cl_hw->fw_recovery_cntr);
+
+	cl_recovery_process(cl_hw);
+}
+
+static void cl_recovery_work_do(struct work_struct *ws)
+{
+	/* Worker for restarting hw. */
+	struct cl_recovery_work *recovery_work = container_of(ws, struct cl_recovery_work, ws);
+
+	recovery_work->cl_hw->assert_info.restart_sched = false;
+	cl_recovery_handler(recovery_work->cl_hw, recovery_work->reason);
+	kfree(recovery_work);
+}
+
+static void cl_recovery_work_sched(struct cl_hw *cl_hw, int reason)
+{
+	/*
+	 * Schedule work to restart device and firmware
+	 * This is scheduled when driver detects hw assert storm.
+	 */
+	struct cl_recovery_work *recovery_work;
+
+	if (!cl_hw->ipc_env || cl_hw->is_stop_context) {
+		cl_dbg_warn(cl_hw, "Skip recovery - Running down!\n");
+		return;
+	}
+
+	/* If restart is already scheduled - exit */
+	if (cl_hw->assert_info.restart_sched)
+		return;
+
+	cl_hw->assert_info.restart_sched = true;
+
+	/* Recovery_work will be freed by cl_recovery_work_do */
+	recovery_work = kzalloc(sizeof(*recovery_work), GFP_ATOMIC);
+
+	if (!recovery_work)
+		return;
+
+	INIT_WORK(&recovery_work->ws, cl_recovery_work_do);
+	recovery_work->cl_hw = cl_hw;
+	recovery_work->reason = reason;
+
+	queue_work(cl_hw->drv_workqueue, &recovery_work->ws);
+}
+
+bool cl_recovery_in_progress(struct cl_hw *cl_hw)
+{
+	return cl_hw->recovery_db.in_recovery;
+}
+
+void cl_recovery_reconfig_complete(struct cl_hw *cl_hw)
+{
+	clear_bit(CL_DEV_SW_RESTART, &cl_hw->drv_flags);
+
+	if (cl_ela_is_on(cl_hw->chip)) {
+		cl_ela_lcu_reset(cl_hw->chip);
+		cl_ela_lcu_apply_config(cl_hw->chip);
+	}
+
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	cl_dyn_mcast_rate_recovery(cl_hw);
+
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_recovery(cl_hw);
+
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+	/* DFS recovery */
+	cl_dfs_recovery(cl_hw);
+
+	/* VNS recovery */
+	cl_vns_recovery(cl_hw);
+
+	/* Restore EDCA configuration */
+	cl_edca_recovery(cl_hw);
+
+	/* Temperature  recovery */
+	cl_temperature_recovery(cl_hw);
+
+	/* Sounding recovery */
+	cl_sounding_recovery(cl_hw);
+
+	/*
+	 * Update Tx params for all connected stations to sync firmware after the
+	 * recovery process. Should be called after cl_mu_ofdma_grp_recovery to let
+	 * MU-OFDMA rates in FW be updated successfully
+	 */
+	cl_wrs_api_recovery(cl_hw);
+
+	/* Enable maintenance timers back */
+	cl_maintenance_start(cl_hw);
+	if (cl_radio_is_on(cl_hw)) {
+		/*
+		 * Rearm last_tbtt_ind so that error message will
+		 * not be printed in cl_irq_status_tbtt()
+		 */
+		cl_hw->last_tbtt_irq = jiffies;
+
+		cl_msg_tx_set_idle(cl_hw, MAC_ACTIVE, true);
+	}
+
+	cl_hw->recovery_db.in_recovery = false;
+
+	pr_debug("cl_recovery: complete\n");
+
+	cl_rx_post_recovery(cl_hw);
+}
+
+void cl_recovery_start(struct cl_hw *cl_hw, int reason)
+{
+	/* Prevent new messages to be sent until firmware has recovered */
+	set_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
+
+	switch (cl_hw->conf->ce_fw_watchdog_mode) {
+	case FW_WD_DISABLE:
+		cl_dbg_info(cl_hw, "Skip recovery - Watchdog is off!\n");
+		break;
+
+	case FW_WD_INTERNAL_RECOVERY:
+		cl_recovery_work_sched(cl_hw, reason);
+		break;
+
+	case FW_WD_DRV_RELOAD:
+		/* TODO: Implement netlink hint to the userspace */
+		cl_dbg_info(cl_hw, "RELOAD handler is absent, doing nothing");
+		break;
+
+	default:
+		break;
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 61/96] cl8k: add recovery.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (59 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 60/96] cl8k: add recovery.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 62/96] cl8k: add regdom.c viktor.barna
                   ` (34 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/recovery.h | 39 +++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/recovery.h

diff --git a/drivers/net/wireless/celeno/cl8k/recovery.h b/drivers/net/wireless/celeno/cl8k/recovery.h
new file mode 100644
index 000000000000..303259d5d802
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/recovery.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_RECOVERY_H
+#define CL_RECOVERY_H
+
+#include <linux/types.h>
+
+enum recovery_reason {
+	RECOVERY_WAIT4CFM,
+	RECOVERY_UNRECOVERABLE_ASSERT,
+	RECOVERY_UNRECOVERABLE_ASSERT_NO_DUMP,
+	RECOVERY_ASSERT_STORM_DETECT,
+	RECOVERY_DRV_FAILED,
+};
+
+enum cl_fw_wd_mode {
+	FW_WD_DISABLE,
+	FW_WD_INTERNAL_RECOVERY,
+	FW_WD_DRV_RELOAD,
+};
+
+struct cl_recovery_db {
+	unsigned long last_restart;
+	u32 restart_cnt;
+
+	u32 ela_en;
+	u32 ela_sel_a;
+	u32 ela_sel_b;
+	u32 ela_sel_c;
+
+	bool in_recovery;
+};
+
+bool cl_recovery_in_progress(struct cl_hw *cl_hw);
+void cl_recovery_reconfig_complete(struct cl_hw *cl_hw);
+void cl_recovery_start(struct cl_hw *cl_hw, int reason);
+
+#endif /* CL_RECOVERY_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 62/96] cl8k: add regdom.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (60 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 61/96] cl8k: add recovery.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 63/96] cl8k: add regdom.h viktor.barna
                   ` (33 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/regdom.c | 301 ++++++++++++++++++++++
 1 file changed, 301 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/regdom.c

diff --git a/drivers/net/wireless/celeno/cl8k/regdom.c b/drivers/net/wireless/celeno/cl8k/regdom.c
new file mode 100644
index 000000000000..1b9d33a33d98
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/regdom.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "dfs.h"
+#include "core.h"
+#include "debug.h"
+#include "hw.h"
+#include "utils.h"
+#include "regdom.h"
+
+static struct ieee80211_regdomain cl_regdom_24g = {
+	.n_reg_rules = 2,
+	.alpha2 = "99",
+	.reg_rules = {
+		REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0),
+		REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0),
+	}
+};
+
+static struct ieee80211_regdomain cl_regdom_5g = {
+	.n_reg_rules = 1,
+	.alpha2 = "99",
+	.reg_rules = {
+		REG_RULE(5150 - 10, 5850 + 10, 80, 6, 30, 0),
+	}
+};
+
+static struct ieee80211_regdomain cl_regdom_6g = {
+	.n_reg_rules = 1,
+	.alpha2 = "99",
+	.reg_rules = {
+		REG_RULE(5935 - 10, 7115 + 10, 80, 6, 30, 0),
+	}
+};
+
+static int cl_regd_is_legal_bw(int freq_diff)
+{
+	int bw = 0;
+
+	for (bw = CHNL_BW_20; bw < CHNL_BW_MAX; bw++)
+		if (freq_diff == BW_TO_KHZ(bw))
+			return bw;
+
+	return -EINVAL;
+}
+
+static int cl_regd_domain_update_rule(struct cl_hw *cl_hw, struct ieee80211_regdomain *rd,
+				      int freq, int power, u8 max_bw, u32 flags, u32 dfs_cac_ms)
+{
+	struct ieee80211_reg_rule *reg_rule = &rd->reg_rules[rd->n_reg_rules - 1];
+	struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+	int bw, diff;
+
+	reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
+	if (power_rule->max_eirp < DBM_TO_MBM(power))
+		power_rule->max_eirp = DBM_TO_MBM(power);
+
+	diff = reg_rule->freq_range.end_freq_khz - reg_rule->freq_range.start_freq_khz;
+	/* if freq diff is equal to legal BW then update max_bandwidth_khz */
+	bw = cl_regd_is_legal_bw(diff);
+	if (bw >= 0)
+		reg_rule->freq_range.max_bandwidth_khz = BW_TO_KHZ(min((u8)bw, max_bw));
+
+	reg_rule->flags |= flags;
+	reg_rule->dfs_cac_ms = max_t(u32, reg_rule->dfs_cac_ms, dfs_cac_ms);
+
+	return diff;
+}
+
+/*
+ * Add first rule with minimal BW and increase then in cl_regd_domain_update_rule
+ * if new freq range will added
+ */
+static void cl_regd_domain_add_rule(struct cl_hw *cl_hw, struct ieee80211_regdomain *rd,
+				    int freq, int max_power, u8 min_bw, u32 flags, u32 dfs_cac_ms)
+{
+	struct ieee80211_reg_rule *reg_rule = &rd->reg_rules[rd->n_reg_rules];
+	struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
+	struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
+
+	freq_range->start_freq_khz = MHZ_TO_KHZ(freq - 10);
+	freq_range->end_freq_khz = MHZ_TO_KHZ(freq + 10);
+	freq_range->max_bandwidth_khz = BW_TO_KHZ(min_bw);
+
+	power_rule->max_eirp = DBM_TO_MBM(max_power);
+	power_rule->max_antenna_gain = DBI_TO_MBI(3);
+
+	reg_rule->flags |= flags;
+	reg_rule->dfs_cac_ms = dfs_cac_ms;
+
+	rd->n_reg_rules++;
+}
+
+static u32 cl_regd_map_reg_flags(u32 reg_flags)
+{
+	u32 flags = 0;
+
+	if (reg_flags & IEEE80211_CHAN_NO_IR)
+		flags = NL80211_RRF_NO_IR;
+
+	if (reg_flags & IEEE80211_CHAN_RADAR)
+		flags |= NL80211_RRF_DFS;
+
+	if (reg_flags & IEEE80211_CHAN_NO_OFDM)
+		flags |= NL80211_RRF_NO_OFDM;
+
+	if (reg_flags & IEEE80211_CHAN_INDOOR_ONLY)
+		flags |= NL80211_RRF_NO_OUTDOOR;
+
+	if (reg_flags & (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS))
+		flags |= NL80211_RRF_NO_HT40;
+
+	if (reg_flags & IEEE80211_CHAN_NO_80MHZ)
+		flags |= NL80211_RRF_NO_80MHZ;
+
+	if (reg_flags & IEEE80211_CHAN_NO_160MHZ)
+		flags |= NL80211_RRF_NO_160MHZ;
+
+	return flags;
+}
+
+void cl_regd_set(struct cl_hw *cl_hw, struct ieee80211_regdomain *rd,
+		 struct regulatory_request *request)
+{
+	int j = 0;
+	int power = 0, prev_power = 0;
+	u8 bw = 0, prev_bw = 0;
+	int freq = 0, prev_freq = 0;
+	u8 chan = 0;
+	u32 flags = 0, prev_flags = 0;
+	u32 dfs_cac_ms = 0;
+
+	spin_lock_bh(&cl_hw->channel_info_lock);
+
+	memset(rd, 0, sizeof(*rd) + NL80211_MAX_SUPP_REG_RULES * sizeof(struct ieee80211_reg_rule));
+	memcpy(rd->alpha2, request->alpha2, 2);
+
+	rd->dfs_region = request->dfs_region;
+
+	if (request->dfs_region == NL80211_DFS_FCC)
+		cl_hw->channel_info.standard = NL80211_DFS_FCC;
+	else if (request->dfs_region == NL80211_DFS_ETSI)
+		cl_hw->channel_info.standard = NL80211_DFS_ETSI;
+	else
+		cl_hw->channel_info.standard = NL80211_DFS_UNSET;
+
+	for (j = 0; j < cl_channel_num(cl_hw); j++) {
+		struct cl_chan_info *chan_info = &cl_hw->channel_info.channels[CHNL_BW_20][j];
+
+		chan = chan_info->channel;
+		if (!chan)
+			continue;
+
+		/* Translate from country_power (.25dBm) to max_power (1dBm) */
+		power = cl_hw->channel_info.channels[CHNL_BW_20][j].country_max_power_q2 >> 2;
+		bw = cl_chan_info_get_max_bw(cl_hw, chan);
+		freq = ieee80211_channel_to_frequency(chan, cl_hw->nl_band);
+		flags = cl_regd_map_reg_flags(chan_info->flags);
+		dfs_cac_ms = chan_info->dfs_cac_ms;
+		if (freq - prev_freq > 20 || prev_power != power || prev_bw != bw ||
+		    prev_flags != flags)
+			cl_regd_domain_add_rule(cl_hw, rd, freq, power,
+						CHNL_BW_20, flags, dfs_cac_ms);
+		else
+			cl_regd_domain_update_rule(cl_hw, rd, freq, power, bw, flags, dfs_cac_ms);
+
+		prev_freq = freq;
+		prev_power = power;
+		prev_bw = bw;
+		prev_flags = flags;
+	}
+
+	spin_unlock_bh(&cl_hw->channel_info_lock);
+}
+
+static void cl_regd_update_channels(struct cl_hw *cl_hw, struct wiphy *wiphy)
+{
+	enum nl80211_band band;
+	const struct ieee80211_supported_band *cfg_band = NULL;
+
+	for (band = 0; band < NUM_NL80211_BANDS; band++) {
+		if (band != cl_hw->nl_band)
+			continue;
+
+		cfg_band = wiphy->bands[band];
+		if (!cfg_band)
+			continue;
+
+		cl_chan_update_channels_info(cl_hw, cfg_band);
+	}
+}
+
+static void cl_regd_set_by_user(struct cl_hw *cl_hw, struct wiphy *wiphy,
+				struct regulatory_request *request)
+{
+	if (!cl_hw->channel_info.use_channel_info)
+		return;
+
+	cl_regd_update_channels(cl_hw, wiphy);
+	/*
+	 * Here is updated cl_hw->channel_info,
+	 * let's generates new regdom rules into cl_hw->channel_info.rd
+	 */
+	cl_regd_set(cl_hw, cl_hw->channel_info.rd, request);
+	if (cl_band_is_5g(cl_hw))
+		cl_dfs_reinit(cl_hw);
+	/* TODO: calib callback for channels update */
+}
+
+static bool cl_regd_dyn_mode_enabled(struct cl_hw *cl_hw)
+{
+	return !strcmp(cl_hw->chip->conf->ci_regdom_mode, "auto");
+}
+
+static void cl_regd_notifier_apply(struct cl_hw *cl_hw,
+				   struct wiphy *wiphy,
+				   struct regulatory_request *request)
+{
+	if (!request)
+		return;
+
+	switch (request->initiator) {
+	case NL80211_REGDOM_SET_BY_CORE:
+		break;
+	case NL80211_REGDOM_SET_BY_DRIVER:
+		break;
+	case NL80211_REGDOM_SET_BY_USER:
+		if (cl_regd_dyn_mode_enabled(cl_hw))
+			cl_regd_set_by_user(cl_hw, wiphy, request);
+		break;
+	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+		break;
+	default:
+		break;
+	}
+}
+
+static void cl_regd_notifier(struct wiphy *wiphy,
+			     struct regulatory_request *request)
+{
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+
+	cl_regd_notifier_apply(hw->priv, wiphy, request);
+}
+
+static int _cl_regd_init(struct cl_hw *cl_hw, struct wiphy *wiphy,
+			 void (*reg_notifier)(struct wiphy *wiphy,
+					      struct regulatory_request *request))
+{
+	if (cl_regd_dyn_mode_enabled(cl_hw)) {
+		const struct ieee80211_regdomain *regd = cl_hw->channel_info.rd;
+
+		wiphy->reg_notifier = reg_notifier;
+		wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+					   REGULATORY_DISABLE_BEACON_HINTS |
+					   REGULATORY_COUNTRY_IE_IGNORE;
+
+		wiphy_apply_custom_regulatory(wiphy, regd);
+
+		return 0;
+	}
+
+	/* default is self managed mode */
+	wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
+
+	return regulatory_set_wiphy_regd(wiphy, cl_hw->channel_info.rd);
+}
+
+int cl_regd_init(struct cl_hw *cl_hw, struct wiphy *wiphy)
+{
+	if (cl_hw->channel_info.use_channel_info) {
+		cl_hw->channel_info.rd = kzalloc(sizeof(*cl_hw->channel_info.rd) +
+						 NL80211_MAX_SUPP_REG_RULES *
+						 sizeof(struct ieee80211_reg_rule),
+						 GFP_KERNEL);
+		if (!cl_hw->channel_info.rd) {
+			cl_dbg_err(cl_hw, "memory allocation failed!\n");
+			return -ENOMEM;
+		}
+
+		struct regulatory_request request = {
+			.alpha2[0]  = cl_hw->chip->conf->ci_country_code[0],
+			.alpha2[1]  = cl_hw->chip->conf->ci_country_code[1],
+			.alpha2[2]  = 0,
+			.dfs_region = cl_hw->channel_info.standard,
+		};
+
+		cl_regd_set(cl_hw, cl_hw->channel_info.rd, &request);
+	} else {
+		if (cl_band_is_6g(cl_hw))
+			cl_hw->channel_info.rd = &cl_regdom_6g;
+		else if (cl_band_is_5g(cl_hw))
+			cl_hw->channel_info.rd = &cl_regdom_5g;
+		else
+			cl_hw->channel_info.rd = &cl_regdom_24g;
+	}
+
+	return _cl_regd_init(cl_hw, wiphy, cl_regd_notifier);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 63/96] cl8k: add regdom.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (61 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 62/96] cl8k: add regdom.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 64/96] cl8k: add reg/reg_access.h viktor.barna
                   ` (32 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/regdom.h | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/regdom.h

diff --git a/drivers/net/wireless/celeno/cl8k/regdom.h b/drivers/net/wireless/celeno/cl8k/regdom.h
new file mode 100644
index 000000000000..0a063716ef4f
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/regdom.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_REGDOM_H
+#define CL_REGDOM_H
+
+int cl_regd_init(struct cl_hw *cl_hw, struct wiphy *wiphy);
+void cl_regd_set(struct cl_hw *cl_hw, struct ieee80211_regdomain *rd,
+		 struct regulatory_request *request);
+
+#endif /* CL_REGDOM_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 64/96] cl8k: add reg/reg_access.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (62 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 63/96] cl8k: add regdom.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 65/96] cl8k: add reg/reg_defs.h viktor.barna
                   ` (31 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_access.h | 199 ++++++++++++++++++
 1 file changed, 199 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_access.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_access.h b/drivers/net/wireless/celeno/cl8k/reg/reg_access.h
new file mode 100644
index 000000000000..c9d00f7553ea
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_access.h
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_REG_ACCESS_H
+#define CL_REG_ACCESS_H
+
+#include "hw.h"
+#include "chip.h"
+
+#define hwreg_pr(...) \
+	do { \
+		if (cl_hw->reg_dbg) \
+			cl_dbg_verbose(__VA_ARGS__); \
+	} while (0)
+
+#define chipreg_pr(...) \
+	do { \
+		if (chip->reg_dbg) \
+			cl_dbg_chip_verbose(__VA_ARGS__); \
+	} while (0)
+
+#define XTENSA_PIF_BASE_ADDR     0x60000000
+
+/*
+ * SHARED_RAM Address.
+ * Actually the PCI BAR4 window will be configured such as SHARED RAM
+ * is accessed with offset 0 (within the AHB Bridge main window)
+ */
+#define SHARED_RAM_START_ADDR    0x00000000
+#define REG_MAC_HW_SMAC_OFFSET   0x80000
+#define REG_PHY_LMAC_OFFSET      0x000000
+#define REG_PHY_SMAC_OFFSET      0x100000
+#define REG_MACDSP_API_BASE_ADDR 0x00400000
+#define REG_MAC_HW_BASE_ADDR     0x00600000
+#define REG_RIU_BASE_ADDR        0x00486000
+#define REG_RICU_BASE_ADDR       0x004B4000
+#define APB_REGS_BASE_ADDR       0x007C0000
+#define I2C_REG_BASE_ADDR        (APB_REGS_BASE_ADDR + 0x3000)
+
+/* MACSYS_GCU_XT_CONTROL fields */
+#define SMAC_DEBUG_ENABLE      BIT(21)
+#define SMAC_BREAKPOINT        BIT(20)
+#define SMAC_OCD_HALT_ON_RESET BIT(19)
+#define SMAC_RUN_STALL         BIT(18)
+#define SMAC_DRESET            BIT(17)
+#define SMAC_BRESET            BIT(16)
+#define UMAC_DEBUG_ENABLE      BIT(13)
+#define UMAC_BREAKPOINT        BIT(11)
+#define UMAC_OCD_HALT_ON_RESET BIT(11)
+#define UMAC_RUN_STALL         BIT(10)
+#define UMAC_DRESET            BIT(9)
+#define UMAC_BRESET            BIT(8)
+#define LMAC_DEBUG_ENABLE      BIT(5)
+#define LMAC_BREAKPOINT        BIT(4)
+#define LMAC_OCD_HALT_ON_RESET BIT(3)
+#define LMAC_RUN_STALL         BIT(2)
+#define LMAC_DRESET            BIT(1)
+#define LMAC_BRESET            BIT(0)
+
+#define XMAC_BRESET \
+	(LMAC_BRESET | SMAC_BRESET | UMAC_BRESET)
+#define XMAC_DRESET \
+	(LMAC_DRESET | SMAC_DRESET | UMAC_DRESET)
+#define XMAC_RUN_STALL \
+	(LMAC_RUN_STALL | SMAC_RUN_STALL | UMAC_RUN_STALL)
+#define XMAC_OCD_HALT_ON_RESET \
+	(LMAC_OCD_HALT_ON_RESET | SMAC_OCD_HALT_ON_RESET | UMAC_OCD_HALT_ON_RESET)
+#define XMAC_DEBUG_ENABLE \
+	(LMAC_DEBUG_ENABLE | SMAC_DEBUG_ENABLE | UMAC_DEBUG_ENABLE)
+
+static inline u32 get_actual_reg(struct cl_hw *cl_hw, u32 reg)
+{
+	if (!cl_hw)
+		return -1;
+
+	if ((reg & 0x00ff0000) == REG_MAC_HW_BASE_ADDR)
+		return cl_hw->mac_hw_regs_offset + reg;
+
+	if ((reg & 0x00f00000) == REG_MACDSP_API_BASE_ADDR) {
+		if (cl_hw->chip->conf->ci_phy_dev == PHY_DEV_DUMMY)
+			return -1;
+		return cl_hw->phy_regs_offset + reg;
+	}
+
+	return reg;
+}
+
+static inline bool cl_reg_is_phy_tcvX(u32 phy_reg, u32 reg_offset)
+{
+	return (phy_reg & 0xf00000) == (REG_MACDSP_API_BASE_ADDR + reg_offset);
+}
+
+static inline bool cl_reg_is_phy_tcv0(u32 phy_reg)
+{
+	return cl_reg_is_phy_tcvX(phy_reg, REG_PHY_LMAC_OFFSET);
+}
+
+static inline bool cl_reg_is_phy_tcv1(u32 phy_reg)
+{
+	return cl_reg_is_phy_tcvX(phy_reg, REG_PHY_SMAC_OFFSET);
+}
+
+static inline u32 cl_reg_read(struct cl_hw *cl_hw, u32 reg)
+{
+	u32 actual_reg = get_actual_reg(cl_hw, reg);
+	u32 val = 0;
+
+	if (actual_reg == (u32)(-1))
+		return 0xff;
+
+	val = ioread32(cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+	hwreg_pr(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+	return val;
+}
+
+static inline void cl_reg_write_direct(struct cl_hw *cl_hw, u32 reg, u32 val)
+{
+	u32 actual_reg = get_actual_reg(cl_hw, reg);
+
+	if (actual_reg == (u32)(-1))
+		return;
+
+	hwreg_pr(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+	iowrite32(val, cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+}
+
+#define BASE_ADDR(reg) ((ptrdiff_t)(reg) & 0x00fff000)
+
+static inline bool should_send_msg(struct cl_hw *cl_hw, u32 reg)
+{
+	/*
+	 * Check in what cases we should send a message to the firmware,
+	 * and in what cases we should write directly.
+	 */
+	if (!cl_hw->fw_active)
+		return false;
+
+	return ((BASE_ADDR(reg) == REG_RIU_BASE_ADDR) ||
+		(BASE_ADDR(reg) == REG_MAC_HW_BASE_ADDR));
+}
+
+static inline int cl_reg_write(struct cl_hw *cl_hw, u32 reg, u32 val)
+{
+	u32 actual_reg = get_actual_reg(cl_hw, reg);
+	int ret = 0;
+
+	if (actual_reg == (u32)(-1))
+		return -1;
+
+	if (should_send_msg(cl_hw, reg)) {
+		hwreg_pr(cl_hw, "calling cl_msg_tx_reg_write: reg=0x%x, val=0x%x\n",
+			 actual_reg, val);
+		cl_msg_tx_reg_write(cl_hw, (XTENSA_PIF_BASE_ADDR + actual_reg), val, U32_MAX);
+	} else {
+		hwreg_pr(cl_hw, "reg=0x%x, val=0x%x\n", actual_reg, val);
+		iowrite32(val, cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+	}
+
+	return ret;
+}
+
+static inline int cl_reg_write_mask(struct cl_hw *cl_hw, u32 reg, u32 val, u32 mask)
+{
+	u32 actual_reg = get_actual_reg(cl_hw, reg);
+	int ret = 0;
+
+	if (actual_reg == (u32)(-1))
+		return -1;
+
+	if (should_send_msg(cl_hw, reg)) {
+		hwreg_pr(cl_hw, "calling cl_msg_tx_reg_write: reg=0x%x, val=0x%x, mask=0x%x\n",
+			 actual_reg, val, mask);
+		cl_msg_tx_reg_write(cl_hw, (XTENSA_PIF_BASE_ADDR + actual_reg), val, mask);
+	} else {
+		u32 reg_rd = ioread32(cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+		u32 val_write = ((reg_rd & ~mask) | (val & mask));
+
+		hwreg_pr(cl_hw, "reg=0x%x, mask=0x%x, val=0x%x\n", actual_reg, mask, val_write);
+		iowrite32(val_write, cl_hw->chip->pci_bar0_virt_addr + actual_reg);
+	}
+
+	return ret;
+}
+
+static inline void cl_reg_write_chip(struct cl_chip *chip, u32 reg, u32 val)
+{
+	chipreg_pr(chip, "reg=0x%x, val=0x%x\n", reg, val);
+	iowrite32(val, chip->pci_bar0_virt_addr + reg);
+}
+
+static inline u32 cl_reg_read_chip(struct cl_chip *chip, u32 reg)
+{
+	u32 val = ioread32(chip->pci_bar0_virt_addr + reg);
+
+	chipreg_pr(chip, "reg=0x%x, val=0x%x\n", reg, val);
+	return val;
+}
+
+#endif /* CL_REG_ACCESS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 65/96] cl8k: add reg/reg_defs.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (63 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 64/96] cl8k: add reg/reg_access.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 66/96] cl8k: add rfic.c viktor.barna
                   ` (30 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/reg/reg_defs.h   | 5494 +++++++++++++++++
 1 file changed, 5494 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/reg/reg_defs.h

diff --git a/drivers/net/wireless/celeno/cl8k/reg/reg_defs.h b/drivers/net/wireless/celeno/cl8k/reg/reg_defs.h
new file mode 100644
index 000000000000..6dd137629ab5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/reg/reg_defs.h
@@ -0,0 +1,5494 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_REG_DEFS_H
+#define CL_REG_DEFS_H
+
+#include <linux/types.h>
+#include "reg/reg_access.h"
+#include "hw.h"
+#include "chip.h"
+
+#define CEVA_MCCI_BASE_ADDR 0x004B0000
+
+#define CEVA_CORE_VERSION_ADDR (CEVA_MCCI_BASE_ADDR + 0x1000)
+#define CEVA_CORE_ID_ADDR (CEVA_MCCI_BASE_ADDR + 0x1004)
+
+#define CEVA_CPM_BASE_ADDR (CEVA_MCCI_BASE_ADDR + 0x2000)
+
+/* PDMA */
+#define CEVA_CPM_PDEA_REG (CEVA_CPM_BASE_ADDR + 0x0008) /* External */
+#define CEVA_CPM_PDIA_REG (CEVA_CPM_BASE_ADDR + 0x000C) /* Internal */
+#define CEVA_CPM_PDTC_REG (CEVA_CPM_BASE_ADDR + 0x0010) /* Control */
+
+/* DDMA */
+#define CEVA_CPM_DDEA_REG (CEVA_CPM_BASE_ADDR + 0x001c) /* External */
+#define CEVA_CPM_DDIA_REG (CEVA_CPM_BASE_ADDR + 0x0020) /* Internal */
+#define CEVA_CPM_DDTC_REG (CEVA_CPM_BASE_ADDR + 0x0024) /* Control */
+
+#define CEVA_CPM_DDTC_WRITE_COMMAND 0x40000000
+
+/* Translated internally to 0x60600000. */
+#define CEVA_SHARED_PMEM_BASE_ADDR_FROM_HOST 0x004C0000
+
+/* Internal address to access Shared */
+#define CEVA_SHARED_PMEM_BASE_ADDR_INTERNAL 0x60600000 /* PMEM */
+#define CEVA_SHARED_XMEM_BASE_ADDR_INTERNAL 0x60900000 /* XMEM */
+
+#define CEVA_DSP_DATA_SIZE 0x80000 /* 512kB. */
+#define CEVA_DSP_EXT_DATA_SIZE 0x60000 /* 384kB. */
+
+/* 512kb */
+#define CEVA_INTERNAL_PMEM_SIZE 0x80000
+
+#define CEVA_SHARED_PMEM_SIZE 0x20000 /* 128kb */
+#define CEVA_SHARED_XMEM_SIZE 0x60000 /* 384kB */
+
+#define CEVA_MAX_PAGES (CEVA_INTERNAL_PMEM_SIZE / CEVA_SHARED_PMEM_SIZE)
+
+#define CEVA_SHARED_PMEM_CACHE_SIZE 0x8000 /* 32kb */
+
+#define REG_CMU_BASE_ADDR 0x007C6000
+
+/*
+ * @brief CMU_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    spare_afe_gnrl_en         0
+ *    30    spare_sys_gnrl_en         0
+ *    27    spare_riu44_clk_en        0
+ *    26    spare_riu_clk_en          0
+ *    25    spare_riu2x_clk_en        0
+ *    24    spare_riu4x_clk_en        0
+ *    23    spare_phy_clk_en          0
+ *    22    spare_phy2x_clk_en        0
+ *    21    spare_sysx_clk_en         0
+ *    20    spare_sys2x_clk_en        0
+ *    19    ricu_clk_en               0
+ *    05    smac_proc_clk_en          1
+ *    04    umac_proc_clk_en          1
+ *    03    lmac_proc_clk_en          1
+ * </pre>
+ */
+#define CMU_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000000)
+#define CMU_CLK_EN_OFFSET      0x00000000
+#define CMU_CLK_EN_INDEX       0x00000000
+#define CMU_CLK_EN_RESET       0x00000038
+
+static inline void cmu_clk_en_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_CLK_EN_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_SPARE_AFE_GNRL_EN_BIT           ((u32)0x80000000)
+#define CMU_SPARE_AFE_GNRL_EN_POS           31
+#define CMU_SPARE_SYS_GNRL_EN_BIT           ((u32)0x40000000)
+#define CMU_SPARE_SYS_GNRL_EN_POS           30
+#define CMU_SPARE_RIU_44_CLK_EN_BIT         ((u32)0x08000000)
+#define CMU_SPARE_RIU_44_CLK_EN_POS         27
+#define CMU_SPARE_RIU_CLK_EN_BIT            ((u32)0x04000000)
+#define CMU_SPARE_RIU_CLK_EN_POS            26
+#define CMU_SPARE_RIU_2_X_CLK_EN_BIT        ((u32)0x02000000)
+#define CMU_SPARE_RIU_2_X_CLK_EN_POS        25
+#define CMU_SPARE_RIU_4_X_CLK_EN_BIT        ((u32)0x01000000)
+#define CMU_SPARE_RIU_4_X_CLK_EN_POS        24
+#define CMU_SPARE_PHY_CLK_EN_BIT            ((u32)0x00800000)
+#define CMU_SPARE_PHY_CLK_EN_POS            23
+#define CMU_SPARE_PHY_2_X_CLK_EN_BIT        ((u32)0x00400000)
+#define CMU_SPARE_PHY_2_X_CLK_EN_POS        22
+#define CMU_SPARE_SYSX_CLK_EN_BIT           ((u32)0x00200000)
+#define CMU_SPARE_SYSX_CLK_EN_POS           21
+#define CMU_SPARE_SYS_2_X_CLK_EN_BIT        ((u32)0x00100000)
+#define CMU_SPARE_SYS_2_X_CLK_EN_POS        20
+#define CMU_RICU_CLK_EN_BIT                 ((u32)0x00080000)
+#define CMU_RICU_CLK_EN_POS                 19
+#define CMU_SMAC_PROC_CLK_EN_BIT            ((u32)0x00000020)
+#define CMU_SMAC_PROC_CLK_EN_POS            5
+#define CMU_UMAC_PROC_CLK_EN_BIT            ((u32)0x00000010)
+#define CMU_UMAC_PROC_CLK_EN_POS            4
+#define CMU_LMAC_PROC_CLK_EN_BIT            ((u32)0x00000008)
+#define CMU_LMAC_PROC_CLK_EN_POS            3
+
+#define CMU_MAC_ALL_CLK_EN		    (CMU_RICU_CLK_EN_BIT     | \
+		CMU_SMAC_PROC_CLK_EN_BIT | \
+		CMU_UMAC_PROC_CLK_EN_BIT | \
+		CMU_LMAC_PROC_CLK_EN_BIT)
+
+/*
+ * @brief CMU_PHY_0_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    02    ceva0_clk_en              0
+ *    01    phy0_apb_clk_en           0
+ *    00    phy0_main_clk_en          0
+ * </pre>
+ */
+#define CMU_PHY_0_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000004)
+#define CMU_PHY_0_CLK_EN_OFFSET      0x00000004
+#define CMU_PHY_0_CLK_EN_INDEX       0x00000001
+#define CMU_PHY_0_CLK_EN_RESET       0x00000000
+
+static inline void cmu_phy_0_clk_en_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_0_CLK_EN_BIT               ((u32)0x00000004)
+#define CMU_CEVA_0_CLK_EN_POS               2
+#define CMU_PHY_0_APB_CLK_EN_BIT            ((u32)0x00000002)
+#define CMU_PHY_0_APB_CLK_EN_POS            1
+#define CMU_PHY_0_MAIN_CLK_EN_BIT           ((u32)0x00000001)
+#define CMU_PHY_0_MAIN_CLK_EN_POS           0
+
+#define CMU_PHY0_CLK_EN			    (CMU_CEVA_0_CLK_EN_BIT   | \
+		CMU_PHY_0_APB_CLK_EN_BIT | \
+		CMU_PHY_0_MAIN_CLK_EN_BIT)
+
+static inline void cmu_phy_0_clk_en_pack(struct cl_chip *chip, u8 ceva0clken,
+					 u8 phy0apbclken, u8 phy0mainclken)
+{
+	ASSERT_ERR_CHIP((((u32)ceva0clken << 2) & ~((u32)0x00000004)) == 0);
+	ASSERT_ERR_CHIP((((u32)phy0apbclken << 1) & ~((u32)0x00000002)) == 0);
+	ASSERT_ERR_CHIP((((u32)phy0mainclken << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR,
+			  ((u32)ceva0clken << 2) | ((u32)phy0apbclken << 1) |
+			  ((u32)phy0mainclken << 0));
+}
+
+static inline void cmu_phy_0_clk_en_ceva_0_clk_en_setf(struct cl_chip *chip, u8 ceva0clken)
+{
+	ASSERT_ERR_CHIP((((u32)ceva0clken << 2) & ~((u32)0x00000004)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_0_CLK_EN_ADDR) & ~((u32)0x00000004)) |
+			  ((u32)ceva0clken << 2));
+}
+
+static inline void cmu_phy_0_clk_en_phy_0_apb_clk_en_setf(struct cl_chip *chip, u8 phy0apbclken)
+{
+	ASSERT_ERR_CHIP((((u32)phy0apbclken << 1) & ~((u32)0x00000002)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_0_CLK_EN_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_0_CLK_EN_ADDR) & ~((u32)0x00000002)) |
+			  ((u32)phy0apbclken << 1));
+}
+
+/*
+ * @brief CMU_PHY_1_CLK_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    02    ceva1_clk_en              0
+ *    01    phy1_apb_clk_en           0
+ *    00    phy1_main_clk_en          0
+ * </pre>
+ */
+#define CMU_PHY_1_CLK_EN_ADDR        (REG_CMU_BASE_ADDR + 0x00000008)
+#define CMU_PHY_1_CLK_EN_OFFSET      0x00000008
+#define CMU_PHY_1_CLK_EN_INDEX       0x00000002
+#define CMU_PHY_1_CLK_EN_RESET       0x00000000
+
+static inline void cmu_phy_1_clk_en_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_1_CLK_EN_BIT               ((u32)0x00000004)
+#define CMU_CEVA_1_CLK_EN_POS               2
+#define CMU_PHY_1_APB_CLK_EN_BIT            ((u32)0x00000002)
+#define CMU_PHY_1_APB_CLK_EN_POS            1
+#define CMU_PHY_1_MAIN_CLK_EN_BIT           ((u32)0x00000001)
+#define CMU_PHY_1_MAIN_CLK_EN_POS           0
+
+#define CMU_PHY1_CLK_EN			    (CMU_CEVA_1_CLK_EN_BIT   | \
+		CMU_PHY_1_APB_CLK_EN_BIT | \
+		CMU_PHY_1_MAIN_CLK_EN_BIT)
+
+static inline void cmu_phy_1_clk_en_pack(struct cl_chip *chip, u8 ceva1clken,
+					 u8 phy1apbclken, u8 phy1mainclken)
+{
+	ASSERT_ERR_CHIP((((u32)ceva1clken << 2) & ~((u32)0x00000004)) == 0);
+	ASSERT_ERR_CHIP((((u32)phy1apbclken << 1) & ~((u32)0x00000002)) == 0);
+	ASSERT_ERR_CHIP((((u32)phy1mainclken << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR,
+			  ((u32)ceva1clken << 2) | ((u32)phy1apbclken << 1) |
+			  ((u32)phy1mainclken << 0));
+}
+
+static inline void cmu_phy_1_clk_en_ceva_1_clk_en_setf(struct cl_chip *chip, u8 ceva1clken)
+{
+	ASSERT_ERR_CHIP((((u32)ceva1clken << 2) & ~((u32)0x00000004)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_1_CLK_EN_ADDR) & ~((u32)0x00000004)) |
+			  ((u32)ceva1clken << 2));
+}
+
+static inline void cmu_phy_1_clk_en_phy_1_apb_clk_en_setf(struct cl_chip *chip, u8 phy1apbclken)
+{
+	ASSERT_ERR_CHIP((((u32)phy1apbclken << 1) & ~((u32)0x00000002)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_1_CLK_EN_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_1_CLK_EN_ADDR) & ~((u32)0x00000002)) |
+			  ((u32)phy1apbclken << 1));
+}
+
+/*
+ * @brief CMU_CONTROL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    gl_mux_sel                0
+ * </pre>
+ */
+#define CMU_CONTROL_ADDR        (REG_CMU_BASE_ADDR + 0x0000000C)
+#define CMU_CONTROL_OFFSET      0x0000000C
+#define CMU_CONTROL_INDEX       0x00000003
+#define CMU_CONTROL_RESET       0x00000000
+
+static inline void cmu_control_gl_mux_sel_setf(struct cl_chip *chip, u8 glmuxsel)
+{
+	ASSERT_ERR_CHIP((((u32)glmuxsel << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, CMU_CONTROL_ADDR, (u32)glmuxsel << 0);
+}
+
+/*
+ * @brief CMU_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    18    spare_riu44_reset_n       0
+ *    17    spare_modem_reset_n       0
+ *    16    spare_sys_reset_n         0
+ *    15    n_RICURst                 1
+ * </pre>
+ */
+#define CMU_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000010)
+#define CMU_RST_OFFSET      0x00000010
+#define CMU_RST_INDEX       0x00000004
+#define CMU_RST_RESET       0x0000FF80
+
+static inline void cmu_rst_n_ricurst_setf(struct cl_chip *chip, u8 nricurst)
+{
+	ASSERT_ERR_CHIP((((u32)nricurst << 15) & ~((u32)0x00008000)) == 0);
+	cl_reg_write_chip(chip, CMU_RST_ADDR,
+			  (cl_reg_read_chip(chip, CMU_RST_ADDR) & ~((u32)0x00008000)) |
+			  ((u32)nricurst << 15));
+}
+
+/*
+ * @brief CMU_PHY_0_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    03    ceva0_global_rst_n        1
+ *    02    mpif0_rst_n               1
+ *    01    phy0_preset_n             1
+ *    00    phy0_rst_n                1
+ * </pre>
+ */
+#define CMU_PHY_0_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000014)
+#define CMU_PHY_0_RST_OFFSET      0x00000014
+#define CMU_PHY_0_RST_INDEX       0x00000005
+#define CMU_PHY_0_RST_RESET       0x0000000F
+
+static inline void cmu_phy_0_rst_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_PHY_0_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_0_GLOBAL_RST_N_BIT         ((u32)0x00000008)
+#define CMU_CEVA_0_GLOBAL_RST_N_POS         3
+#define CMU_MPIF_0_RST_N_BIT                ((u32)0x00000004)
+#define CMU_MPIF_0_RST_N_POS                2
+#define CMU_PHY_0_PRESET_N_BIT              ((u32)0x00000002)
+#define CMU_PHY_0_PRESET_N_POS              1
+#define CMU_PHY_0_RST_N_BIT                 ((u32)0x00000001)
+#define CMU_PHY_0_RST_N_POS                 0
+
+#define CMU_PHY0_RST_EN			    (CMU_PHY_0_PRESET_N_BIT | \
+		CMU_MPIF_0_RST_N_BIT |    \
+		CMU_PHY_0_RST_N_BIT |     \
+		CMU_CEVA_0_GLOBAL_RST_N_BIT)
+
+static inline void cmu_phy_0_rst_ceva_0_global_rst_n_setf(struct cl_chip *chip, u8 ceva0globalrstn)
+{
+	ASSERT_ERR_CHIP((((u32)ceva0globalrstn << 3) & ~((u32)0x00000008)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_0_RST_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_0_RST_ADDR) & ~((u32)0x00000008)) |
+			  ((u32)ceva0globalrstn << 3));
+}
+
+/*
+ * @brief CMU_PHY_1_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    03    ceva1_global_rst_n        1
+ *    02    mpif1_rst_n               1
+ *    01    phy1_preset_n             1
+ *    00    phy1_rst_n                1
+ * </pre>
+ */
+#define CMU_PHY_1_RST_ADDR        (REG_CMU_BASE_ADDR + 0x00000018)
+#define CMU_PHY_1_RST_OFFSET      0x00000018
+#define CMU_PHY_1_RST_INDEX       0x00000006
+#define CMU_PHY_1_RST_RESET       0x0000000F
+
+static inline void cmu_phy_1_rst_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_PHY_1_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_CEVA_1_GLOBAL_RST_N_BIT         ((u32)0x00000008)
+#define CMU_CEVA_1_GLOBAL_RST_N_POS         3
+#define CMU_MPIF_1_RST_N_BIT                ((u32)0x00000004)
+#define CMU_MPIF_1_RST_N_POS                2
+#define CMU_PHY_1_PRESET_N_BIT              ((u32)0x00000002)
+#define CMU_PHY_1_PRESET_N_POS              1
+#define CMU_PHY_1_RST_N_BIT                 ((u32)0x00000001)
+#define CMU_PHY_1_RST_N_POS                 0
+
+#define CMU_PHY1_RST_EN			    (CMU_PHY_1_PRESET_N_BIT | \
+		CMU_MPIF_1_RST_N_BIT |    \
+		CMU_PHY_1_RST_N_BIT |     \
+		CMU_CEVA_1_GLOBAL_RST_N_BIT)
+
+static inline void cmu_phy_1_rst_ceva_1_global_rst_n_setf(struct cl_chip *chip, u8 ceva1globalrstn)
+{
+	ASSERT_ERR_CHIP((((u32)ceva1globalrstn << 3) & ~((u32)0x00000008)) == 0);
+	cl_reg_write_chip(chip, CMU_PHY_1_RST_ADDR,
+			  (cl_reg_read_chip(chip, CMU_PHY_1_RST_ADDR) & ~((u32)0x00000008)) |
+			  ((u32)ceva1globalrstn << 3));
+}
+
+/*
+ * @brief CMU_PLL_0_STAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    pll_lock                  0
+ * </pre>
+ */
+#define CMU_PLL_0_STAT_ADDR        (REG_CMU_BASE_ADDR + 0x00000040)
+#define CMU_PLL_0_STAT_OFFSET      0x00000040
+#define CMU_PLL_0_STAT_INDEX       0x00000010
+#define CMU_PLL_0_STAT_RESET       0x00000000
+
+static inline u8 cmu_pll_0_stat_pll_lock_getf(struct cl_chip *chip)
+{
+	u32 local_val = cl_reg_read_chip(chip, CMU_PLL_0_STAT_ADDR);
+
+	ASSERT_ERR_CHIP((local_val & ~((u32)0x80000000)) == 0);
+	return (local_val >> 31);
+}
+
+/*
+ * @brief CMU_PLL_1_STAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    pll_lock                  0
+ * </pre>
+ */
+#define CMU_PLL_1_STAT_ADDR        (REG_CMU_BASE_ADDR + 0x00000050)
+#define CMU_PLL_1_STAT_OFFSET      0x00000050
+#define CMU_PLL_1_STAT_INDEX       0x00000014
+#define CMU_PLL_1_STAT_RESET       0x00000000
+
+static inline u8 cmu_pll_1_stat_pll_lock_getf(struct cl_chip *chip)
+{
+	u32 local_val = cl_reg_read_chip(chip, CMU_PLL_1_STAT_ADDR);
+
+	ASSERT_ERR_CHIP((local_val & ~((u32)0x80000000)) == 0);
+	return (local_val >> 31);
+}
+
+/*
+ * @brief CMU_PHASE_SEL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    20    gp_clk_phase_sel          1
+ *    19    dac_cdb_clk_phase_sel     0
+ *    18    adc_cdb_clk_phase_sel     0
+ *    17    dac_clk_phase_sel         0
+ *    16    adc_clk_phase_sel         0
+ * </pre>
+ */
+#define CMU_PHASE_SEL_ADDR        (REG_CMU_BASE_ADDR + 0x00000060)
+#define CMU_PHASE_SEL_OFFSET      0x00000060
+#define CMU_PHASE_SEL_INDEX       0x00000018
+#define CMU_PHASE_SEL_RESET       0x00100000
+
+static inline void cmu_phase_sel_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, CMU_PHASE_SEL_ADDR, value);
+}
+
+/* Field definitions */
+#define CMU_GP_CLK_PHASE_SEL_BIT            ((u32)0x00100000)
+#define CMU_GP_CLK_PHASE_SEL_POS            20
+#define CMU_DAC_CDB_CLK_PHASE_SEL_BIT       ((u32)0x00080000)
+#define CMU_DAC_CDB_CLK_PHASE_SEL_POS       19
+#define CMU_ADC_CDB_CLK_PHASE_SEL_BIT       ((u32)0x00040000)
+#define CMU_ADC_CDB_CLK_PHASE_SEL_POS       18
+#define CMU_DAC_CLK_PHASE_SEL_BIT           ((u32)0x00020000)
+#define CMU_DAC_CLK_PHASE_SEL_POS           17
+#define CMU_ADC_CLK_PHASE_SEL_BIT           ((u32)0x00010000)
+#define CMU_ADC_CLK_PHASE_SEL_POS           16
+
+struct cl_fem_lna_enable_gpio {
+	union {
+		struct {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+			u16 b0 : 1,
+			    b1 : 1,
+			    b2 : 1,
+			    b3 : 1,
+			    b4 : 1,
+			    b5 : 1,
+			    b6 : 1,
+			    b7 : 1,
+			    b8 : 1,
+			    b9 : 1,
+			    b10 : 1,
+			    b11 : 1,
+			    rsv : 4;
+#else /* __BIG_ENDIAN_BITFIELD */
+			u16 rsv : 4,
+			    b11 : 1,
+			    b10 : 1,
+			    b9 : 1,
+			    b8 : 1,
+			    b7 : 1,
+			    b6 : 1,
+			    b5 : 1,
+			    b4 : 1,
+			    b3 : 1,
+			    b2 : 1,
+			    b1 : 1,
+			    b0 : 1;
+#endif
+		} bits;
+		u16 val;
+	};
+};
+
+struct cl_fem_pa_enable_gpio {
+	union {
+		struct {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+			u16 b0 : 1,
+			    b1 : 1,
+			    b2 : 1,
+			    b3 : 1,
+			    b4 : 1,
+			    b5 : 1,
+			    b6 : 1,
+			    b7 : 1,
+			    b8 : 1,
+			    b9 : 1,
+			    b10 : 1,
+			    b11 : 1,
+			    rsv : 4;
+#else /* __BIG_ENDIAN_BITFIELD */
+			u16 rsv : 4,
+			    b11 : 1,
+			    b10 : 1,
+			    b9 : 1,
+			    b8 : 1,
+			    b7 : 1,
+			    b6 : 1,
+			    b5 : 1,
+			    b4 : 1,
+			    b3 : 1,
+			    b2 : 1,
+			    b1 : 1,
+			    b0 : 1;
+#endif
+		} bits;
+		u16 val;
+	};
+};
+
+struct cl_fem_rx_active_gpio {
+	union {
+		struct {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+			u8 b0 : 1,
+			   b1 : 1,
+			   b2 : 1,
+			   b3 : 1,
+			   b4 : 1,
+			   b5 : 1,
+			   b6 : 1,
+			   b7 : 1;
+#else /* __BIG_ENDIAN_BITFIELD */
+			u8 b7 : 1,
+			   b6 : 1,
+			   b5 : 1,
+			   b4 : 1,
+			   b3 : 1,
+			   b2 : 1,
+			   b1 : 1,
+			   b0 : 1;
+#endif
+		} bits;
+		u8 val;
+	};
+};
+
+#define EXTRACT_BYPASS_LUT(lut) ((lut) & 0x7)
+#define FEM_LUT_MASK            0x7777
+
+#define PA_ENABLE_POS  0
+#define LNA_ENABLE_POS 1
+#define RX_ACTIVE_POS  2
+#define GET_BIT(reg, pos) (((reg) >> (pos)) & 0x1)
+
+#define LNA_ENABLE_GPIO_OUT_CFG(val) \
+	(((1 << IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_BIT) | \
+	 ((1 << IO_CTRL_LNA_ENABLE_0_GPIO_OE_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_OE_BIT) | \
+	 (((u32)(val) << IO_CTRL_LNA_ENABLE_0_GPIO_OUT_POS) & IO_CTRL_LNA_ENABLE_0_GPIO_OUT_BIT))
+#define PA_ENABLE_GPIO_OUT_CFG(val) \
+	 (((1 << IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_POS) & IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_BIT) | \
+	  ((1 << IO_CTRL_PA_ENABLE_0_GPIO_OE_POS) & IO_CTRL_PA_ENABLE_0_GPIO_OE_BIT) | \
+	  (((u32)(val) << IO_CTRL_PA_ENABLE_0_GPIO_OUT_POS) & IO_CTRL_PA_ENABLE_0_GPIO_OUT_BIT))
+#define RX_ACTIVE_GPIO_OUT_CFG(val) \
+	  (((1 << IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_BIT) | \
+	   ((1 << IO_CTRL_RX_ACTIVE_0_GPIO_OE_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_OE_BIT) | \
+	   (((u32)(val) << IO_CTRL_RX_ACTIVE_0_GPIO_OUT_POS) & IO_CTRL_RX_ACTIVE_0_GPIO_OUT_BIT))
+
+#define REG_IPC_BASE_ADDR 0x007C4000
+
+/*
+ * @brief XMAC_2_HOST_RAW_STATUS register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_raw_status      0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_RAW_STATUS_ADDR        (REG_IPC_BASE_ADDR + 0x00000004)
+#define IPC_XMAC_2_HOST_RAW_STATUS_OFFSET      0x00000004
+#define IPC_XMAC_2_HOST_RAW_STATUS_INDEX       0x00000001
+#define IPC_XMAC_2_HOST_RAW_STATUS_RESET       0x00000000
+
+static inline u32 ipc_xmac_2_host_raw_status_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, IPC_XMAC_2_HOST_RAW_STATUS_ADDR);
+}
+
+/*
+ * @brief XMAC_2_HOST_ACK register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_trigger_clr     0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ACK_ADDR        (REG_IPC_BASE_ADDR + 0x00000008)
+#define IPC_XMAC_2_HOST_ACK_OFFSET      0x00000008
+#define IPC_XMAC_2_HOST_ACK_INDEX       0x00000002
+#define IPC_XMAC_2_HOST_ACK_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_ack_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ACK_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_ENABLE_SET register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_enable_set      0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ENABLE_SET_ADDR        (REG_IPC_BASE_ADDR + 0x0000000C)
+#define IPC_XMAC_2_HOST_ENABLE_SET_OFFSET      0x0000000C
+#define IPC_XMAC_2_HOST_ENABLE_SET_INDEX       0x00000003
+#define IPC_XMAC_2_HOST_ENABLE_SET_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_enable_set_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ENABLE_SET_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_ENABLE_CLEAR register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_enable_clear    0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_ADDR        (REG_IPC_BASE_ADDR + 0x00000010)
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_OFFSET      0x00000010
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_INDEX       0x00000004
+#define IPC_XMAC_2_HOST_ENABLE_CLEAR_RESET       0x00000000
+
+static inline void ipc_xmac_2_host_enable_clear_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_XMAC_2_HOST_ENABLE_CLEAR_ADDR, value);
+}
+
+/*
+ * @brief XMAC_2_HOST_STATUS register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 xmac2host_status          0x0
+ * </pre>
+ */
+#define IPC_XMAC_2_HOST_STATUS_ADDR        (REG_IPC_BASE_ADDR + 0x00000014)
+#define IPC_XMAC_2_HOST_STATUS_OFFSET      0x00000014
+#define IPC_XMAC_2_HOST_STATUS_INDEX       0x00000005
+#define IPC_XMAC_2_HOST_STATUS_RESET       0x00000000
+
+static inline u32 ipc_xmac_2_host_status_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, IPC_XMAC_2_HOST_STATUS_ADDR);
+}
+
+/*
+ * @brief HOST_GLOBAL_INT_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    master_int_enable         0
+ * </pre>
+ */
+#define IPC_HOST_GLOBAL_INT_EN_ADDR        (REG_IPC_BASE_ADDR + 0x00000030)
+#define IPC_HOST_GLOBAL_INT_EN_OFFSET      0x00000030
+#define IPC_HOST_GLOBAL_INT_EN_INDEX       0x0000000C
+#define IPC_HOST_GLOBAL_INT_EN_RESET       0x00000000
+
+static inline void ipc_host_global_int_en_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_HOST_GLOBAL_INT_EN_ADDR, value);
+}
+
+/*
+ * @brief HOST_2_LMAC_TRIGGER register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 host2lmac_trigger         0x0
+ * </pre>
+ */
+#define IPC_HOST_2_LMAC_TRIGGER_ADDR        (REG_IPC_BASE_ADDR + 0x00000080)
+#define IPC_HOST_2_LMAC_TRIGGER_OFFSET      0x00000080
+#define IPC_HOST_2_LMAC_TRIGGER_INDEX       0x00000020
+#define IPC_HOST_2_LMAC_TRIGGER_RESET       0x00000000
+
+static inline void ipc_host_2_lmac_trigger_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_HOST_2_LMAC_TRIGGER_ADDR, value);
+}
+
+/*
+ * @brief HOST_2_UMAC_TRIGGER register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 host2umac_trigger         0x0
+ * </pre>
+ */
+#define IPC_HOST_2_UMAC_TRIGGER_ADDR        (REG_IPC_BASE_ADDR + 0x00000084)
+#define IPC_HOST_2_UMAC_TRIGGER_OFFSET      0x00000084
+#define IPC_HOST_2_UMAC_TRIGGER_INDEX       0x00000021
+#define IPC_HOST_2_UMAC_TRIGGER_RESET       0x00000000
+
+static inline void ipc_host_2_umac_trigger_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_HOST_2_UMAC_TRIGGER_ADDR, value);
+}
+
+/*
+ * @brief HOST_2_SMAC_TRIGGER register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 host2smac_trigger         0x0
+ * </pre>
+ */
+#define IPC_HOST_2_SMAC_TRIGGER_ADDR        (REG_IPC_BASE_ADDR + 0x00000088)
+#define IPC_HOST_2_SMAC_TRIGGER_OFFSET      0x00000088
+#define IPC_HOST_2_SMAC_TRIGGER_INDEX       0x00000022
+#define IPC_HOST_2_SMAC_TRIGGER_RESET       0x00000000
+
+static inline void ipc_host_2_smac_trigger_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IPC_HOST_2_SMAC_TRIGGER_ADDR, value);
+}
+
+#define REG_LCU_COMMON_BASE_ADDR 0x007CF000
+
+/*
+ * @brief LCU_COMMON_SW_RST register definition
+ *  Software reset register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    SW_RST                    0
+ * </pre>
+ */
+#define LCU_COMMON_SW_RST_ADDR        (REG_LCU_COMMON_BASE_ADDR + 0x00000048)
+#define LCU_COMMON_SW_RST_OFFSET      0x00000048
+#define LCU_COMMON_SW_RST_INDEX       0x00000012
+#define LCU_COMMON_SW_RST_RESET       0x00000000
+
+static inline void lcu_common_sw_rst_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, LCU_COMMON_SW_RST_ADDR, value);
+}
+
+#define REG_LCU_PHY_BASE_ADDR 0x0048E000
+
+/*
+ * @brief LCU_CH_0_START register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    CH0_START                 0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_0_START_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000020)
+#define LCU_PHY_LCU_CH_0_START_OFFSET      0x00000020
+#define LCU_PHY_LCU_CH_0_START_INDEX       0x00000008
+#define LCU_PHY_LCU_CH_0_START_RESET       0x00000000
+
+/*
+ * @brief LCU_CH_0_STOP register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    CH0_STOP                  0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_0_STOP_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000070)
+#define LCU_PHY_LCU_CH_0_STOP_OFFSET      0x00000070
+#define LCU_PHY_LCU_CH_0_STOP_INDEX       0x0000001C
+#define LCU_PHY_LCU_CH_0_STOP_RESET       0x00000000
+
+static inline void lcu_phy_lcu_ch_0_stop_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, LCU_PHY_LCU_CH_0_STOP_ADDR, value);
+}
+
+/*
+ * @brief LCU_CH_1_STOP register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    CH1_STOP                  0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_1_STOP_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000074)
+#define LCU_PHY_LCU_CH_1_STOP_OFFSET      0x00000074
+#define LCU_PHY_LCU_CH_1_STOP_INDEX       0x0000001D
+#define LCU_PHY_LCU_CH_1_STOP_RESET       0x00000000
+
+static inline void lcu_phy_lcu_ch_1_stop_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, LCU_PHY_LCU_CH_1_STOP_ADDR, value);
+}
+
+/*
+ * @brief LCU_CH_0_STOP_EN register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    02    CH0_EXT_STOP_EN           0
+ *    01    CH0_FIC_STOP_EN           0
+ *    00    CH0_STOP_PTRN_EN          0
+ * </pre>
+ */
+#define LCU_PHY_LCU_CH_0_STOP_EN_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000078)
+#define LCU_PHY_LCU_CH_0_STOP_EN_OFFSET      0x00000078
+#define LCU_PHY_LCU_CH_0_STOP_EN_INDEX       0x0000001E
+#define LCU_PHY_LCU_CH_0_STOP_EN_RESET       0x00000000
+
+/*
+ * @brief LCU_SW_RST register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    00    SW_RST                    0
+ * </pre>
+ */
+#define LCU_PHY_LCU_SW_RST_ADDR        (REG_LCU_PHY_BASE_ADDR + 0x00000154)
+#define LCU_PHY_LCU_SW_RST_OFFSET      0x00000154
+#define LCU_PHY_LCU_SW_RST_INDEX       0x00000055
+#define LCU_PHY_LCU_SW_RST_RESET       0x00000000
+
+static inline void lcu_phy_lcu_sw_rst_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, LCU_PHY_LCU_SW_RST_ADDR, value);
+}
+
+/*
+ * @brief CONFIG_SPACE register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:26 ActiveAntennaSet          0x0
+ *    25:20 RxCckActiveChain          0x0
+ *    19:14 RxOfdmActiveChain         0x0
+ *    13:08 TxCckActiveChain          0x0
+ *    07:06 Band                      0x0
+ *    05:04 ChannelBandwidth          0x0
+ *    03    OfdmOnly                  0
+ *    02    RxSensingMode             0
+ *    01    UpdateSync                0
+ *    00    StartupSync               0
+ * </pre>
+ */
+#define MACDSP_API_CONFIG_SPACE_ADDR        (REG_MACDSP_API_BASE_ADDR + 0x00000010)
+#define MACDSP_API_CONFIG_SPACE_OFFSET      0x00000010
+#define MACDSP_API_CONFIG_SPACE_INDEX       0x00000004
+#define MACDSP_API_CONFIG_SPACE_RESET       0x00000000
+
+static inline void macdsp_api_config_space_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MACDSP_API_CONFIG_SPACE_ADDR, value);
+}
+
+/*
+ * @brief STATE_CNTRL register definition
+ * This register controls the core's state transitions. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   07:04 NEXT_STATE                0x0
+ *   03:00 CURRENT_STATE             0x0
+ * </pre>
+ */
+#define MAC_HW_STATE_CNTRL_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000038)
+#define MAC_HW_STATE_CNTRL_OFFSET      0x00000038
+#define MAC_HW_STATE_CNTRL_INDEX       0x0000000E
+#define MAC_HW_STATE_CNTRL_RESET       0x00000000
+
+static inline void mac_hw_state_cntrl_next_state_setf(struct cl_hw *cl_hw, u8 nextstate)
+{
+	ASSERT_ERR((((u32)nextstate << 4) & ~((u32)0x000000F0)) == 0);
+	cl_reg_write(cl_hw, MAC_HW_STATE_CNTRL_ADDR,
+		     (cl_reg_read(cl_hw, MAC_HW_STATE_CNTRL_ADDR) & ~((u32)0x000000F0)) |
+		     ((u32)nextstate << 4));
+}
+
+/*
+ * @brief MAC_CNTRL_1 register definition
+ * Contains various settings for controlling the operation of the core. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    EOF_PAD_FOR_HE            1
+ *   30    EOF_PAD_FOR_VHT           0
+ *   29:28 IMPLICIT_BF_INT_CONF      0x0
+ *   27    DISABLE_BFR_RESP          0
+ *   26    RX_RIFS_EN                0
+ *   25    TSF_MGT_DISABLE           0
+ *   24    TSF_UPDATED_BY_SW         0
+ *   22    MAC_DETECT_UNDERRUN_EN    0
+ *   21    DISABLE_MU_CTS_RESP       0
+ *   20    BQRP_RESP_BY_FW           0
+ *   19    BSRP_RESP_BY_FW           0
+ *   18    ENABLE_NORMAL_ACK_RESP_IN_HE_MU_W_TRIG 0
+ *   17    DISABLE_NORMAL_ACK_RESP_IN_HE_MU_WO_TRIG 0
+ *   16:14 ABGN_MODE                 0x3
+ *   13    KEY_STO_RAM_RESET         0
+ *   12    MIB_TABLE_RESET           0
+ *   11    RATE_CONTROLLER_MPIF      1
+ *   10    DISABLE_BA_RESP           0
+ *   09    DISABLE_CTS_RESP          0
+ *   08    DISABLE_ACK_RESP          0
+ *   07    ACTIVE_CLK_GATING         1
+ *   06    ENABLE_LP_CLK_SWITCH      0
+ *   05    FORCE_MSTA_BA             0
+ *   04    DISABLE_FAST_COMPARE      0
+ *   03    CFP_AWARE                 0
+ *   02    PWR_MGT                   0
+ *   01    AP                        0
+ *   00    BSS_TYPE                  1
+ * </pre>
+ */
+#define MAC_HW_MAC_CNTRL_1_ADDR        (REG_MAC_HW_BASE_ADDR + 0x0000004C)
+#define MAC_HW_MAC_CNTRL_1_OFFSET      0x0000004C
+#define MAC_HW_MAC_CNTRL_1_INDEX       0x00000013
+#define MAC_HW_MAC_CNTRL_1_RESET       0x8000C881
+
+static inline void mac_hw_mac_cntrl_1_active_clk_gating_setf(struct cl_hw *cl_hw,
+							     u8 activeclkgating)
+{
+	ASSERT_ERR((((u32)activeclkgating << 7) & ~((u32)0x00000080)) == 0);
+	cl_reg_write(cl_hw, MAC_HW_MAC_CNTRL_1_ADDR,
+		     (cl_reg_read(cl_hw, MAC_HW_MAC_CNTRL_1_ADDR) & ~((u32)0x00000080)) |
+		     ((u32)activeclkgating << 7));
+}
+
+/*
+ * @brief EDCA_CCA_BUSY register definition
+ * Indicates the CCA busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR              0x0
+ * </pre>
+ */
+#define MAC_HW_EDCA_CCA_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000220)
+#define MAC_HW_EDCA_CCA_BUSY_OFFSET      0x00000220
+#define MAC_HW_EDCA_CCA_BUSY_INDEX       0x00000088
+#define MAC_HW_EDCA_CCA_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_edca_cca_busy_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_EDCA_CCA_BUSY_ADDR);
+}
+
+/*
+ * @brief TX_MINE_BUSY register definition
+ * TX BUSY time by my TX frames register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 TX_MINE_TIME              0x0
+ * </pre>
+ */
+#define MAC_HW_TX_MINE_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000238)
+#define MAC_HW_TX_MINE_BUSY_OFFSET      0x00000238
+#define MAC_HW_TX_MINE_BUSY_INDEX       0x0000008E
+#define MAC_HW_TX_MINE_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_tx_mine_busy_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_TX_MINE_BUSY_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_20 register definition
+ * Indicates the CCA on Secondary 20MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_20       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000290)
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_OFFSET      0x00000290
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_INDEX       0x000000A4
+#define MAC_HW_ADD_CCA_BUSY_SEC_20_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_20_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_20_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_40 register definition
+ * Indicates the CCA on Secondary 40MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_40       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000294)
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_OFFSET      0x00000294
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_INDEX       0x000000A5
+#define MAC_HW_ADD_CCA_BUSY_SEC_40_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_40_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_40_ADDR);
+}
+
+/*
+ * @brief ADD_CCA_BUSY_SEC_80 register definition
+ * Indicates the CCA on Secondary 80MHz busy time. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 CCA_BUSY_DUR_SEC_80       0x0
+ * </pre>
+ */
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000298)
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_OFFSET      0x00000298
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_INDEX       0x000000A6
+#define MAC_HW_ADD_CCA_BUSY_SEC_80_RESET       0x00000000
+
+static inline u32 mac_hw_add_cca_busy_sec_80_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_ADD_CCA_BUSY_SEC_80_ADDR);
+}
+
+/*
+ * @brief INTRA_BSS_NAV_BUSY register definition
+ * Count intra BSS NAV busy period register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 INTRA_BSS_NAV_BUSY_DUR    0x0
+ * </pre>
+ */
+#define MAC_HW_INTRA_BSS_NAV_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000408)
+#define MAC_HW_INTRA_BSS_NAV_BUSY_OFFSET      0x00000408
+#define MAC_HW_INTRA_BSS_NAV_BUSY_INDEX       0x00000102
+#define MAC_HW_INTRA_BSS_NAV_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_intra_bss_nav_busy_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_INTRA_BSS_NAV_BUSY_ADDR);
+}
+
+/*
+ * @brief INTER_BSS_NAV_BUSY register definition
+ * Count inter BSS NAV busy period register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 INTER_BSS_NAV_BUSY_DUR    0x0
+ * </pre>
+ */
+#define MAC_HW_INTER_BSS_NAV_BUSY_ADDR        (REG_MAC_HW_BASE_ADDR + 0x0000040C)
+#define MAC_HW_INTER_BSS_NAV_BUSY_OFFSET      0x0000040C
+#define MAC_HW_INTER_BSS_NAV_BUSY_INDEX       0x00000103
+#define MAC_HW_INTER_BSS_NAV_BUSY_RESET       0x00000000
+
+static inline u32 mac_hw_inter_bss_nav_busy_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_INTER_BSS_NAV_BUSY_ADDR);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_A register definition
+ * Used to multiplex different sets of signals on the debug pins. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_1          0x0
+ *   07:00 DEBUG_PORT_SEL_0          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_A_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000510)
+#define MAC_HW_DEBUG_PORT_SEL_A_OFFSET      0x00000510
+#define MAC_HW_DEBUG_PORT_SEL_A_INDEX       0x00000144
+#define MAC_HW_DEBUG_PORT_SEL_A_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_a_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_A_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_a_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_A_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_B register definition
+ * Used to multiplex different sets of signals on the register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_3          0x0
+ *   07:00 DEBUG_PORT_SEL_2          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_B_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000530)
+#define MAC_HW_DEBUG_PORT_SEL_B_OFFSET      0x00000530
+#define MAC_HW_DEBUG_PORT_SEL_B_INDEX       0x0000014C
+#define MAC_HW_DEBUG_PORT_SEL_B_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_b_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_B_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_b_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_B_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_SEL_C register definition
+ * Used to multiplex different sets of signals on the register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   15:08 DEBUG_PORT_SEL_5          0x0
+ *   07:00 DEBUG_PORT_SEL_4          0x0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_SEL_C_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000534)
+#define MAC_HW_DEBUG_PORT_SEL_C_OFFSET      0x00000534
+#define MAC_HW_DEBUG_PORT_SEL_C_INDEX       0x0000014D
+#define MAC_HW_DEBUG_PORT_SEL_C_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_sel_c_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_SEL_C_ADDR);
+}
+
+static inline void mac_hw_debug_port_sel_c_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_SEL_C_ADDR, value);
+}
+
+/*
+ * @brief DEBUG_PORT_EN register definition
+ * Used to determine which debug ports are enabled register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   05    EN5                       0
+ *   04    EN4                       0
+ *   03    EN3                       0
+ *   02    EN2                       0
+ *   01    EN1                       0
+ *   00    EN0                       0
+ * </pre>
+ */
+#define MAC_HW_DEBUG_PORT_EN_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000538)
+#define MAC_HW_DEBUG_PORT_EN_OFFSET      0x00000538
+#define MAC_HW_DEBUG_PORT_EN_INDEX       0x0000014E
+#define MAC_HW_DEBUG_PORT_EN_RESET       0x00000000
+
+static inline u32 mac_hw_debug_port_en_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, MAC_HW_DEBUG_PORT_EN_ADDR);
+}
+
+static inline void mac_hw_debug_port_en_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MAC_HW_DEBUG_PORT_EN_ADDR, value);
+}
+
+/*
+ * @brief DOZE_CNTRL_2 register definition
+ * Contains settings for controlling DOZE state. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    WAKE_UP_FROM_DOZE         0
+ *   00    WAKE_UP_SW                1
+ * </pre>
+ */
+#define MAC_HW_DOZE_CNTRL_2_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00008048)
+#define MAC_HW_DOZE_CNTRL_2_OFFSET      0x00008048
+#define MAC_HW_DOZE_CNTRL_2_INDEX       0x00002012
+#define MAC_HW_DOZE_CNTRL_2_RESET       0x00000001
+
+static inline void mac_hw_doze_cntrl_2_wake_up_sw_setf(struct cl_hw *cl_hw, u8 wakeupsw)
+{
+	ASSERT_ERR((((u32)wakeupsw << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write(cl_hw, MAC_HW_DOZE_CNTRL_2_ADDR,
+		     (cl_reg_read(cl_hw, MAC_HW_DOZE_CNTRL_2_ADDR) & ~((u32)0x00000001)) |
+		     ((u32)wakeupsw << 0));
+}
+
+#define MU_ADDR_OFFSET(i) ((i) << 16)
+#define MAX_MU_CNT 8
+
+/*
+ * @brief MAC_CNTRL_2 register definition
+ * Contains various settings for controlling the operation of the core. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   00    SOFT_RESET                0
+ * </pre>
+ */
+#define MAC_HW_MU_MAC_CNTRL_2_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00008050)
+#define MAC_HW_MU_MAC_CNTRL_2_OFFSET      0x00008050
+#define MAC_HW_MU_MAC_CNTRL_2_INDEX       0x00002014
+#define MAC_HW_MU_MAC_CNTRL_2_RESET       0x00000000
+
+static inline void mac_hw_mu_mac_cntrl_2_set(struct cl_hw *cl_hw, u32 value, u8 mu_idx)
+{
+	ASSERT_ERR(mu_idx < MAX_MU_CNT);
+	cl_reg_write(cl_hw, (MAC_HW_MU_MAC_CNTRL_2_ADDR + MU_ADDR_OFFSET(mu_idx)), value);
+}
+
+/*
+ * @brief MIB_TABLE register definition
+ * MIB table register description
+ * 1024 memory size
+ * </pre>
+ */
+#define MAC_HW_MU_MIB_TABLE_ADDR        (REG_MAC_HW_BASE_ADDR + 0x00000800)
+#define MAC_HW_MU_MIB_TABLE_OFFSET      0x00000800
+#define MAC_HW_MU_MIB_TABLE_SIZE        0x00000400
+#define MAC_HW_MU_MIB_TABLE_END_ADDR    (MAC_HW_MU_MIB_TABLE_ADDR + MAC_HW_MU_MIB_TABLE_SIZE - 1)
+
+#define REG_MACSYS_GCU_BASE_ADDR 0x007C5000
+
+/*
+ * @brief CHIP_VERSION register definition
+ * Chip Version 8000B0 register description
+ * <pre>
+ * Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *  23:08 PRODUCT_ID                0x8000
+ *  07:04 STEP_ID                   0xB
+ *  03:00 REV_ID                    0x0
+ * </pre>
+ */
+#define MACSYS_GCU_CHIP_VERSION_ADDR        (REG_MACSYS_GCU_BASE_ADDR + 0x00000050)
+#define MACSYS_GCU_CHIP_VERSION_OFFSET      0x00000050
+#define MACSYS_GCU_CHIP_VERSION_INDEX       0x00000014
+#define MACSYS_GCU_CHIP_VERSION_RESET       0x008000B0
+
+static inline u8 macsys_gcu_chip_version_step_id_getf(struct cl_chip *chip)
+{
+	u32 local_val = cl_reg_read_chip(chip, MACSYS_GCU_CHIP_VERSION_ADDR);
+
+	return ((local_val & ((u32)0x000000F0)) >> 4);
+}
+
+/*
+ * @brief XT_CONTROL register definition
+ * Tensilica control register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   21    smac_debug_en             0
+ *   20    smac_break_in             0
+ *   19    smac_ocd_halt_on_reset    1
+ *   18    smac_run_stall            0
+ *   17    smac_dreset_n             1
+ *   16    smac_breset_n             0
+ *   13    umac_debug_en             0
+ *   12    umac_break_in             0
+ *   11    umac_ocd_halt_on_reset    1
+ *   10    umac_run_stall            0
+ *   09    umac_dreset_n             1
+ *   08    umac_breset_n             0
+ *   05    lmac_debug_en             0
+ *   04    lmac_break_in             0
+ *   03    lmac_ocd_halt_on_reset    1
+ *   02    lmac_run_stall            0
+ *   01    lmac_dreset_n             1
+ *   00    lmac_breset_n             0
+ * </pre>
+ */
+#define MACSYS_GCU_XT_CONTROL_ADDR        (REG_MACSYS_GCU_BASE_ADDR + 0x000000F0)
+#define MACSYS_GCU_XT_CONTROL_OFFSET      0x000000F0
+#define MACSYS_GCU_XT_CONTROL_INDEX       0x0000003C
+#define MACSYS_GCU_XT_CONTROL_RESET       0x000A0A0A
+
+static inline u32 macsys_gcu_xt_control_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, MACSYS_GCU_XT_CONTROL_ADDR);
+}
+
+static inline void macsys_gcu_xt_control_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, MACSYS_GCU_XT_CONTROL_ADDR, value);
+}
+
+#define REG_MODEM_GCU_BASE_ADDR 0x00480000
+
+/*
+ * @brief MPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    MPU_CLK_F                 0
+ *   20    MPU_REG_CLK_F             0
+ *   13    MPU_CLK_EN                0
+ *   12    MPU_REG_CLK_EN            0
+ *   01    MPU_RST_N                 0
+ *   00    MPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_MPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000004)
+#define MODEM_GCU_MPU_OFFSET      0x00000004
+#define MODEM_GCU_MPU_INDEX       0x00000001
+#define MODEM_GCU_MPU_RESET       0x00000000
+
+static inline void modem_gcu_mpu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_MPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_MPU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_MPU_CLK_F_POS         21
+#define MODEM_GCU_MPU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_MPU_REG_CLK_F_POS     20
+#define MODEM_GCU_MPU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_MPU_CLK_EN_POS        13
+#define MODEM_GCU_MPU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_MPU_REG_CLK_EN_POS    12
+#define MODEM_GCU_MPU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_MPU_RST_N_POS         1
+#define MODEM_GCU_MPU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_MPU_REG_RST_N_POS     0
+
+/*
+ * @brief BPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   24    BPUL_RX_CLK_F             0
+ *   23    BPU_CLK_F                 0
+ *   22    BPU_RX_CLK_F              0
+ *   21    BPU_TX_CLK_F              0
+ *   20    BPU_REG_CLK_F             0
+ *   16    BPUL_RX_CLK_EN            0
+ *   15    BPU_CLK_EN                0
+ *   14    BPU_RX_CLK_EN             0
+ *   13    BPU_TX_CLK_EN             0
+ *   12    BPU_REG_CLK_EN            0
+ *   03    BPU_RST_N                 0
+ *   02    BPU_RX_RST_N              0
+ *   01    BPU_TX_RST_N              0
+ *   00    BPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_BPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000008)
+#define MODEM_GCU_BPU_OFFSET      0x00000008
+#define MODEM_GCU_BPU_INDEX       0x00000002
+#define MODEM_GCU_BPU_RESET       0x00000000
+
+static inline void modem_gcu_bpu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_BPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_BPU_BPUL_RX_CLK_F_BIT     ((u32)0x01000000)
+#define MODEM_GCU_BPU_BPUL_RX_CLK_F_POS     24
+#define MODEM_GCU_BPU_CLK_F_BIT         ((u32)0x00800000)
+#define MODEM_GCU_BPU_CLK_F_POS         23
+#define MODEM_GCU_BPU_RX_CLK_F_BIT      ((u32)0x00400000)
+#define MODEM_GCU_BPU_RX_CLK_F_POS      22
+#define MODEM_GCU_BPU_TX_CLK_F_BIT      ((u32)0x00200000)
+#define MODEM_GCU_BPU_TX_CLK_F_POS      21
+#define MODEM_GCU_BPU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_BPU_REG_CLK_F_POS     20
+#define MODEM_GCU_BPU_BPUL_RX_CLK_EN_BIT    ((u32)0x00010000)
+#define MODEM_GCU_BPU_BPUL_RX_CLK_EN_POS    16
+#define MODEM_GCU_BPU_CLK_EN_BIT        ((u32)0x00008000)
+#define MODEM_GCU_BPU_CLK_EN_POS        15
+#define MODEM_GCU_BPU_RX_CLK_EN_BIT     ((u32)0x00004000)
+#define MODEM_GCU_BPU_RX_CLK_EN_POS     14
+#define MODEM_GCU_BPU_TX_CLK_EN_BIT     ((u32)0x00002000)
+#define MODEM_GCU_BPU_TX_CLK_EN_POS     13
+#define MODEM_GCU_BPU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_BPU_REG_CLK_EN_POS    12
+#define MODEM_GCU_BPU_RST_N_BIT         ((u32)0x00000008)
+#define MODEM_GCU_BPU_RST_N_POS         3
+#define MODEM_GCU_BPU_RX_RST_N_BIT      ((u32)0x00000004)
+#define MODEM_GCU_BPU_RX_RST_N_POS      2
+#define MODEM_GCU_BPU_TX_RST_N_BIT      ((u32)0x00000002)
+#define MODEM_GCU_BPU_TX_RST_N_POS      1
+#define MODEM_GCU_BPU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_BPU_REG_RST_N_POS     0
+
+/*
+ * @brief TFU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    TFU_CLK_F                 0
+ *   20    TFU_REG_CLK_F             0
+ *   13    TFU_CLK_EN                0
+ *   12    TFU_REG_CLK_EN            0
+ *   01    TFU_RST_N                 0
+ *   00    TFU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_TFU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000000C)
+#define MODEM_GCU_TFU_OFFSET      0x0000000C
+#define MODEM_GCU_TFU_INDEX       0x00000003
+#define MODEM_GCU_TFU_RESET       0x00000000
+
+static inline void modem_gcu_tfu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_TFU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_TFU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_TFU_CLK_F_POS         21
+#define MODEM_GCU_TFU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_TFU_REG_CLK_F_POS     20
+#define MODEM_GCU_TFU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_TFU_CLK_EN_POS        13
+#define MODEM_GCU_TFU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_TFU_REG_CLK_EN_POS    12
+#define MODEM_GCU_TFU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_TFU_RST_N_POS         1
+#define MODEM_GCU_TFU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_TFU_REG_RST_N_POS     0
+
+/*
+ * @brief SMU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    SMU_CLK_F                 0
+ *   20    SMU_REG_CLK_F             0
+ *   13    SMU_CLK_EN                0
+ *   12    SMU_REG_CLK_EN            0
+ *   01    SMU_RST_N                 0
+ *   00    SMU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_SMU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000010)
+#define MODEM_GCU_SMU_OFFSET      0x00000010
+#define MODEM_GCU_SMU_INDEX       0x00000004
+#define MODEM_GCU_SMU_RESET       0x00000000
+
+static inline void modem_gcu_smu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_SMU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_SMU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_SMU_CLK_F_POS         21
+#define MODEM_GCU_SMU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_SMU_REG_CLK_F_POS     20
+#define MODEM_GCU_SMU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_SMU_CLK_EN_POS        13
+#define MODEM_GCU_SMU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_SMU_REG_CLK_EN_POS    12
+#define MODEM_GCU_SMU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_SMU_RST_N_POS         1
+#define MODEM_GCU_SMU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_SMU_REG_RST_N_POS     0
+
+/*
+ * @brief MUX_FIC register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   20    MUX_FIC_CLK_F             0
+ *   12    MUX_FIC_CLK_EN            0
+ *   01    FIC_MUX_SOFT_RST_N        1
+ *   00    MUX_FIC_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_MUX_FIC_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000014)
+#define MODEM_GCU_MUX_FIC_OFFSET      0x00000014
+#define MODEM_GCU_MUX_FIC_INDEX       0x00000005
+#define MODEM_GCU_MUX_FIC_RESET       0x00000002
+
+static inline void modem_gcu_mux_fic_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_MUX_FIC_CLK_F_BIT    ((u32)0x00100000)
+#define MODEM_GCU_MUX_FIC_CLK_F_POS    20
+#define MODEM_GCU_MUX_FIC_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_MUX_FIC_CLK_EN_POS    12
+#define MODEM_GCU_MUX_FIC_SOFT_RST_N_BIT    ((u32)0x00000002)
+#define MODEM_GCU_MUX_FIC_SOFT_RST_N_POS    1
+#define MODEM_GCU_MUX_FIC_RST_N_BIT    ((u32)0x00000001)
+#define MODEM_GCU_MUX_FIC_RST_N_POS    0
+
+/*
+ * @brief MUX_FIC_CONFIG register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    FIC_ISOLATED              0
+ *   17    FIC_ISOLATE               0
+ *   16    DISABLE_FIC_MESS          0
+ *   15:08 MUX_FIC_CONFLICT_DELAY_WRITE 0x0
+ *   07:00 MUX_FIC_CONFLICT_DELAY_READ 0x0
+ * </pre>
+ */
+#define MODEM_GCU_MUX_FIC_CONFIG_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000001C)
+#define MODEM_GCU_MUX_FIC_CONFIG_OFFSET      0x0000001C
+#define MODEM_GCU_MUX_FIC_CONFIG_INDEX       0x00000007
+#define MODEM_GCU_MUX_FIC_CONFIG_RESET       0x00000000
+
+static inline void modem_gcu_mux_fic_config_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR, value);
+}
+
+static inline u8 modem_gcu_mux_fic_config_fic_isolated_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR);
+
+	return ((local_val & ((u32)0x80000000)) >> 31);
+}
+
+static inline void modem_gcu_mux_fic_config_fic_isolate_setf(struct cl_hw *cl_hw, u8 ficisolate)
+{
+	ASSERT_ERR((((u32)ficisolate << 17) & ~((u32)0x00020000)) == 0);
+	cl_reg_write(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR,
+		     (cl_reg_read(cl_hw, MODEM_GCU_MUX_FIC_CONFIG_ADDR) & ~((u32)0x00020000)) |
+		     ((u32)ficisolate << 17));
+}
+
+/*
+ * @brief RIU_RST register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   07    RIUFE_RST_N               0
+ *   06    RIUAGC_RST_N              0
+ *   05    RIU_MDM_B_RST_N           0
+ *   04    RIULB_RST_N               0
+ *   03    RIURC_RST_N               0
+ *   02    RIU_RADAR_RST_N           0
+ *   01    RIU_RST_N                 0
+ *   00    RIU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_RST_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000020)
+#define MODEM_GCU_RIU_RST_OFFSET      0x00000020
+#define MODEM_GCU_RIU_RST_INDEX       0x00000008
+#define MODEM_GCU_RIU_RST_RESET       0x00000000
+
+static inline void modem_gcu_riu_rst_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_RIU_RST_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_RIU_FE_RST_N_BIT    ((u32)0x00000080)
+#define MODEM_GCU_RIU_FE_RST_N_POS    7
+#define MODEM_GCU_RIU_AGC_RST_N_BIT    ((u32)0x00000040)
+#define MODEM_GCU_RIU_AGC_RST_N_POS    6
+#define MODEM_GCU_RIU_MDM_B_RST_N_BIT    ((u32)0x00000020)
+#define MODEM_GCU_RIU_MDM_B_RST_N_POS    5
+#define MODEM_GCU_RIU_LB_RST_N_BIT    ((u32)0x00000010)
+#define MODEM_GCU_RIU_LB_RST_N_POS    4
+#define MODEM_GCU_RIU_RC_RST_N_BIT    ((u32)0x00000008)
+#define MODEM_GCU_RIU_RC_RST_N_POS    3
+#define MODEM_GCU_RIU_RADAR_RST_N_BIT    ((u32)0x00000004)
+#define MODEM_GCU_RIU_RADAR_RST_N_POS    2
+#define MODEM_GCU_RIU_RST_N_BIT     ((u32)0x00000002)
+#define MODEM_GCU_RIU_RST_N_POS     1
+#define MODEM_GCU_RIU_REG_RST_N_BIT    ((u32)0x00000001)
+#define MODEM_GCU_RIU_REG_RST_N_POS    0
+
+/*
+ * @brief RIU_CLK register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31    RIUADC_PWR_CLK_F          0
+ *   30    RIUFEA_5_CLK_F            0
+ *   29    RIUFEA_4_CLK_F            0
+ *   28    RIUFEA_3_CLK_F            0
+ *   27    RIUFEA_2_CLK_F            0
+ *   26    RIUFEA_1_CLK_F            0
+ *   25    RIUFEA_0_CLK_F            0
+ *   24    RIU_MDM_B_TX_CLK_F        0
+ *   23    RIU_MDM_B_RX_CLK_F        0
+ *   22    RIU_MDM_B_CLK_F           0
+ *   21    RIULB_CLK_F               0
+ *   20    RIURC_CLK_F               0
+ *   19    RIU_RADAR_CLK_F           0
+ *   18    RIUAGC_CLK_F              0
+ *   17    RIU_CLK_F                 0
+ *   16    RIU_REG_CLK_F             0
+ *   15    RIUADC_PWR_CLK_EN         0
+ *   14    RIUFEA_5_CLK_EN           0
+ *   13    RIUFEA_4_CLK_EN           0
+ *   12    RIUFEA_3_CLK_EN           0
+ *   11    RIUFEA_2_CLK_EN           0
+ *   10    RIUFEA_1_CLK_EN           0
+ *   09    RIUFEA_0_CLK_EN           0
+ *   08    RIU_MDM_B_TX_CLK_EN       0
+ *   07    RIU_MDM_B_RX_CLK_EN       0
+ *   06    RIU_MDM_B_CLK_EN          0
+ *   05    RIULB_CLK_EN              0
+ *   04    RIURCR_CLK_EN             0
+ *   03    RIU_RADAR_CLK_EN          0
+ *   02    RIUAGC_CLK_EN             0
+ *   01    RIU_CLK_EN                0
+ *   00    RIU_REG_CLK_EN            0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000024)
+#define MODEM_GCU_RIU_CLK_OFFSET      0x00000024
+#define MODEM_GCU_RIU_CLK_INDEX       0x00000009
+#define MODEM_GCU_RIU_CLK_RESET       0x00000000
+
+static inline void modem_gcu_riu_clk_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_ADDR, value);
+}
+
+/*
+ * @brief SPU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   21    SPU_CLK_F                 0
+ *   20    SPU_REG_CLK_F             0
+ *   13    SPU_CLK_EN                0
+ *   12    SPU_REG_CLK_EN            0
+ *   01    SPU_RST_N                 0
+ *   00    SPU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_SPU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000030)
+#define MODEM_GCU_SPU_OFFSET      0x00000030
+#define MODEM_GCU_SPU_INDEX       0x0000000C
+#define MODEM_GCU_SPU_RESET       0x00000000
+
+static inline void modem_gcu_spu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_SPU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_SPU_CLK_F_BIT         ((u32)0x00200000)
+#define MODEM_GCU_SPU_CLK_F_POS         21
+#define MODEM_GCU_SPU_REG_CLK_F_BIT     ((u32)0x00100000)
+#define MODEM_GCU_SPU_REG_CLK_F_POS     20
+#define MODEM_GCU_SPU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_SPU_CLK_EN_POS        13
+#define MODEM_GCU_SPU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_SPU_REG_CLK_EN_POS    12
+#define MODEM_GCU_SPU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_SPU_RST_N_POS         1
+#define MODEM_GCU_SPU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_SPU_REG_RST_N_POS     0
+
+/*
+ * @brief LCU register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   14    LCU_HLF_CLK_EN            0
+ *   13    LCU_CLK_EN                0
+ *   12    LCU_REG_CLK_EN            0
+ *   02    LCU_HLF_RST_N             0
+ *   01    LCU_RST_N                 0
+ *   00    LCU_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_LCU_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000034)
+#define MODEM_GCU_LCU_OFFSET      0x00000034
+#define MODEM_GCU_LCU_INDEX       0x0000000D
+#define MODEM_GCU_LCU_RESET       0x00000000
+
+static inline void modem_gcu_lcu_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_LCU_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_LCU_HLF_CLK_EN_BIT    ((u32)0x00004000)
+#define MODEM_GCU_LCU_HLF_CLK_EN_POS    14
+#define MODEM_GCU_LCU_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_LCU_CLK_EN_POS        13
+#define MODEM_GCU_LCU_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_LCU_REG_CLK_EN_POS    12
+#define MODEM_GCU_LCU_HLF_RST_N_BIT     ((u32)0x00000004)
+#define MODEM_GCU_LCU_HLF_RST_N_POS     2
+#define MODEM_GCU_LCU_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_LCU_RST_N_POS         1
+#define MODEM_GCU_LCU_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_LCU_REG_RST_N_POS     0
+
+/*
+ * @brief EPA register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    EPA_CLK_EN                0
+ *   12    EPA_REG_CLK_EN            0
+ *   01    EPA_RST_N                 0
+ *   00    EPA_REG_RST_N             0
+ * </pre>
+ */
+#define MODEM_GCU_EPA_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000038)
+#define MODEM_GCU_EPA_OFFSET      0x00000038
+#define MODEM_GCU_EPA_INDEX       0x0000000E
+#define MODEM_GCU_EPA_RESET       0x00000000
+
+static inline void modem_gcu_epa_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_EPA_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_EPA_CLK_EN_BIT        ((u32)0x00002000)
+#define MODEM_GCU_EPA_CLK_EN_POS        13
+#define MODEM_GCU_EPA_REG_CLK_EN_BIT    ((u32)0x00001000)
+#define MODEM_GCU_EPA_REG_CLK_EN_POS    12
+#define MODEM_GCU_EPA_RST_N_BIT         ((u32)0x00000002)
+#define MODEM_GCU_EPA_RST_N_POS         1
+#define MODEM_GCU_EPA_REG_RST_N_BIT     ((u32)0x00000001)
+#define MODEM_GCU_EPA_REG_RST_N_POS     0
+
+/*
+ * @brief BF register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    BF_CLK_EN                 0
+ *   12    BF_REG_CLK_EN             0
+ *   01    BF_RST_N                  0
+ *   00    BF_REG_RST_N              0
+ * </pre>
+ */
+#define MODEM_GCU_BF_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x0000003C)
+#define MODEM_GCU_BF_OFFSET      0x0000003C
+#define MODEM_GCU_BF_INDEX       0x0000000F
+#define MODEM_GCU_BF_RESET       0x00000000
+
+static inline void modem_gcu_bf_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_BF_ADDR, value);
+}
+
+/* Field definitions */
+#define MODEM_GCU_BF_CLK_EN_BIT          ((u32)0x00002000)
+#define MODEM_GCU_BF_CLK_EN_POS          13
+#define MODEM_GCU_BF_REG_CLK_EN_BIT      ((u32)0x00001000)
+#define MODEM_GCU_BF_REG_CLK_EN_POS      12
+#define MODEM_GCU_BF_RST_N_BIT           ((u32)0x00000002)
+#define MODEM_GCU_BF_RST_N_POS           1
+#define MODEM_GCU_BF_REG_RST_N_BIT       ((u32)0x00000001)
+#define MODEM_GCU_BF_REG_RST_N_POS       0
+
+/*
+ * @brief RIU_CLK_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   17    RIUFE_EXT_CLK_F           0
+ *   16    RIUFRC_CLK_F              0
+ *   01    RIUFE_EXT_CLK_EN          0
+ *   00    RIUFRC_CLK_EN             0
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_1_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00000124)
+#define MODEM_GCU_RIU_CLK_1_OFFSET      0x00000124
+#define MODEM_GCU_RIU_CLK_1_INDEX       0x00000049
+#define MODEM_GCU_RIU_CLK_1_RESET       0x00000000
+
+static inline void modem_gcu_riu_clk_1_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_1_ADDR, value);
+}
+
+/*
+ * @brief CEVA_CTRL register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   16    MCCI_ADDR_BASE            0
+ *   14    VINTC                     0
+ *   12    NMI                       0
+ *   10:09 EXT_VOM                   0x0
+ *   08    EXT_PV                    0
+ *   07:06 UIA                       0x0
+ *   05    STOP_SD                   0
+ *   04    MON_STAT                  0
+ *   02    EXTERNAL_WAIT             1
+ *   00    BOOT                      0
+ * </pre>
+ */
+#define MODEM_GCU_CEVA_CTRL_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001004)
+#define MODEM_GCU_CEVA_CTRL_OFFSET      0x00001004
+#define MODEM_GCU_CEVA_CTRL_INDEX       0x00000401
+#define MODEM_GCU_CEVA_CTRL_RESET       0x00000004
+
+static inline void modem_gcu_ceva_ctrl_external_wait_setf(struct cl_hw *cl_hw, u8 externalwait)
+{
+	ASSERT_ERR((((u32)externalwait << 2) & ~((u32)0x00000004)) == 0);
+	cl_reg_write(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR,
+		     (cl_reg_read(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR) & ~((u32)0x00000004)) |
+		     ((u32)externalwait << 2));
+}
+
+static inline void modem_gcu_ceva_ctrl_boot_setf(struct cl_hw *cl_hw, u8 boot)
+{
+	ASSERT_ERR((((u32)boot << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR,
+		     (cl_reg_read(cl_hw, MODEM_GCU_CEVA_CTRL_ADDR) & ~((u32)0x00000001)) |
+		     ((u32)boot << 0));
+}
+
+/*
+ * @brief CEVA_VEC register definition
+ * Ceva Vector register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   31:00 VECTOR                    0x0
+ * </pre>
+ */
+#define MODEM_GCU_CEVA_VEC_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001008)
+#define MODEM_GCU_CEVA_VEC_OFFSET      0x00001008
+#define MODEM_GCU_CEVA_VEC_INDEX       0x00000402
+#define MODEM_GCU_CEVA_VEC_RESET       0x00000000
+
+static inline void modem_gcu_ceva_vec_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_CEVA_VEC_ADDR, value);
+}
+
+/*
+ * @brief RIU_CLK_BW register definition
+ * RIU clocks BW. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *   13    agc_clk_bw                0
+ *   12:10 lb_mem_clk_bw             0x2
+ *   09:08 agc_mem_clk_bw            0x1
+ *   07:06 riu_afe_clk_bw            0x2
+ *   05:04 phyfesync_bw              0x2
+ *   03:02 adcpowclk_bw              0x2
+ *   01:00 riulbgclk_bw              0x2
+ * </pre>
+ */
+#define MODEM_GCU_RIU_CLK_BW_ADDR        (REG_MODEM_GCU_BASE_ADDR + 0x00001240)
+#define MODEM_GCU_RIU_CLK_BW_OFFSET      0x00001240
+#define MODEM_GCU_RIU_CLK_BW_INDEX       0x00000490
+#define MODEM_GCU_RIU_CLK_BW_RESET       0x000009AA
+
+static inline void modem_gcu_riu_clk_bw_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR, value);
+}
+
+static inline void modem_gcu_riu_clk_bw_agc_mem_clk_bw_setf(struct cl_hw *cl_hw, u8 agcmemclkbw)
+{
+	ASSERT_ERR((((u32)agcmemclkbw << 8) & ~((u32)0x00000300)) == 0);
+	cl_reg_write(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR,
+		     (cl_reg_read(cl_hw, MODEM_GCU_RIU_CLK_BW_ADDR) & ~((u32)0x00000300)) |
+		     ((u32)agcmemclkbw << 8));
+}
+
+/*
+ * @brief STATIC_CONF_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30    ARB_ONESHOT_BYPASS        1
+ *    28    BTC_SEL                   0
+ *    27    CLK_SAVE_MODE             0
+ *    26    RF_RST_N_DEFAULT          0
+ *    25    RF_RST_N_REQ              0
+ *    24    FORCE_RSSI_ON             0
+ *    23:20 RSSI_M                    0x2
+ *    19:16 RSSI_N                    0x6
+ *    03:00 CDB_MODE_MAJ              0x0
+ * </pre>
+ */
+#define RICU_STATIC_CONF_0_ADDR        (REG_RICU_BASE_ADDR + 0x00000004)
+#define RICU_STATIC_CONF_0_OFFSET      0x00000004
+#define RICU_STATIC_CONF_0_INDEX       0x00000001
+#define RICU_STATIC_CONF_0_RESET       0x40260000
+
+static inline void ricu_static_conf_0_btc_sel_setf(struct cl_chip *chip, u8 btcsel)
+{
+	ASSERT_ERR_CHIP((((u32)btcsel << 28) & ~((u32)0x10000000)) == 0);
+	cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x10000000)) |
+			  ((u32)btcsel << 28));
+}
+
+static inline void ricu_static_conf_0_clk_save_mode_setf(struct cl_chip *chip, u8 clksavemode)
+{
+	ASSERT_ERR_CHIP((((u32)clksavemode << 27) & ~((u32)0x08000000)) == 0);
+	cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x08000000)) |
+			  ((u32)clksavemode << 27));
+}
+
+static inline void ricu_static_conf_0_rf_rst_n_req_setf(struct cl_chip *chip, u8 rfrstnreq)
+{
+	ASSERT_ERR_CHIP((((u32)rfrstnreq << 25) & ~((u32)0x02000000)) == 0);
+	cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x02000000)) |
+			  ((u32)rfrstnreq << 25));
+}
+
+static inline u8 ricu_static_conf_0_cdb_mode_maj_getf(struct cl_chip *chip)
+{
+	u32 local_val = cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR);
+
+	return ((local_val & ((u32)0x0000000F)) >> 0);
+}
+
+static inline void ricu_static_conf_0_cdb_mode_maj_setf(struct cl_chip *chip, u8 cdbmodemaj)
+{
+	ASSERT_ERR_CHIP((((u32)cdbmodemaj << 0) & ~((u32)0x0000000F)) == 0);
+	cl_reg_write_chip(chip, RICU_STATIC_CONF_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_STATIC_CONF_0_ADDR) & ~((u32)0x0000000F)) |
+			  ((u32)cdbmodemaj << 0));
+}
+
+/*
+ * @brief AFE_CTL_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    PBIAS_CTRL_EN_LC          0
+ *    30    PBIAS_CTRL_EN             0
+ *    29    LRD_EN_LC                 0
+ *    28    LRD_EN                    0
+ *    27    LOCK_EN_LC                0
+ *    26    LOCK_EN                   1
+ *    25    EN_GPADC_CLK              0
+ *    24    EN_GPADC                  0
+ *    23    FEED_EN_LC                0
+ *    22    FEED_EN                   0
+ *    21    EN_CS                     1
+ *    20    EN_CML_GEN                1
+ *    18    EN_AFE_LDO                1
+ *    17    EN_ADC_CLK                1
+ *    15    AFC_ENB_LC                0
+ *    14    AFC_ENB                   0
+ *    13    CP_MODE_LC                1
+ *    12    BYPASS_LC                 0
+ *    11    BYPASS                    0
+ *    10    AFCINIT_SEL_LC            1
+ *    09    AFCINIT_SEL               1
+ *    08    EN_CLK_MON                0
+ *    07    EN_DAC_CLK                1
+ *    06    EN_CDB_DAC_CLK            0
+ *    05    EN_CDB_ADC_CLK            0
+ *    03    EN_CDB_GEN                0
+ *    02    DACCLK_PHASESEL           0
+ *    01    ADCCLK_PHASESEL           0
+ *    00    CDB_CLK_RESETB            0
+ * </pre>
+ */
+#define RICU_AFE_CTL_0_ADDR        (REG_RICU_BASE_ADDR + 0x00000010)
+#define RICU_AFE_CTL_0_OFFSET      0x00000010
+#define RICU_AFE_CTL_0_INDEX       0x00000004
+#define RICU_AFE_CTL_0_RESET       0x04362680
+
+static inline u32 ricu_afe_ctl_0_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR);
+}
+
+static inline void ricu_afe_ctl_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR, value);
+}
+
+static inline void ricu_afe_ctl_0_lock_en_lc_setf(struct cl_chip *chip, u8 lockenlc)
+{
+	ASSERT_ERR_CHIP((((u32)lockenlc << 27) & ~((u32)0x08000000)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR) & ~((u32)0x08000000)) |
+			  ((u32)lockenlc << 27));
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_LC_BIT    ((u32)0x80000000)
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_LC_POS    31
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_BIT    ((u32)0x40000000)
+#define RICU_AFE_CTL_0_PBIAS_CTRL_EN_POS    30
+#define RICU_AFE_CTL_0_LRD_EN_LC_BIT        ((u32)0x20000000)
+#define RICU_AFE_CTL_0_LRD_EN_LC_POS        29
+#define RICU_AFE_CTL_0_LRD_EN_BIT           ((u32)0x10000000)
+#define RICU_AFE_CTL_0_LRD_EN_POS           28
+#define RICU_AFE_CTL_0_LOCK_EN_LC_BIT       ((u32)0x08000000)
+#define RICU_AFE_CTL_0_LOCK_EN_LC_POS       27
+#define RICU_AFE_CTL_0_LOCK_EN_BIT          ((u32)0x04000000)
+#define RICU_AFE_CTL_0_LOCK_EN_POS          26
+#define RICU_AFE_CTL_0_EN_GPADC_CLK_BIT     ((u32)0x02000000)
+#define RICU_AFE_CTL_0_EN_GPADC_CLK_POS     25
+#define RICU_AFE_CTL_0_EN_GPADC_BIT         ((u32)0x01000000)
+#define RICU_AFE_CTL_0_EN_GPADC_POS         24
+#define RICU_AFE_CTL_0_FEED_EN_LC_BIT       ((u32)0x00800000)
+#define RICU_AFE_CTL_0_FEED_EN_LC_POS       23
+#define RICU_AFE_CTL_0_FEED_EN_BIT          ((u32)0x00400000)
+#define RICU_AFE_CTL_0_FEED_EN_POS          22
+#define RICU_AFE_CTL_0_EN_CS_BIT            ((u32)0x00200000)
+#define RICU_AFE_CTL_0_EN_CS_POS            21
+#define RICU_AFE_CTL_0_EN_CML_GEN_BIT       ((u32)0x00100000)
+#define RICU_AFE_CTL_0_EN_CML_GEN_POS       20
+#define RICU_AFE_CTL_0_EN_AFE_LDO_BIT       ((u32)0x00040000)
+#define RICU_AFE_CTL_0_EN_AFE_LDO_POS       18
+#define RICU_AFE_CTL_0_EN_ADC_CLK_BIT       ((u32)0x00020000)
+#define RICU_AFE_CTL_0_EN_ADC_CLK_POS       17
+#define RICU_AFE_CTL_0_AFC_ENB_LC_BIT       ((u32)0x00008000)
+#define RICU_AFE_CTL_0_AFC_ENB_LC_POS       15
+#define RICU_AFE_CTL_0_AFC_ENB_BIT          ((u32)0x00004000)
+#define RICU_AFE_CTL_0_AFC_ENB_POS          14
+#define RICU_AFE_CTL_0_CP_MODE_LC_BIT       ((u32)0x00002000)
+#define RICU_AFE_CTL_0_CP_MODE_LC_POS       13
+#define RICU_AFE_CTL_0_BYPASS_LC_BIT        ((u32)0x00001000)
+#define RICU_AFE_CTL_0_BYPASS_LC_POS        12
+#define RICU_AFE_CTL_0_BYPASS_BIT           ((u32)0x00000800)
+#define RICU_AFE_CTL_0_BYPASS_POS           11
+#define RICU_AFE_CTL_0_AFCINIT_SEL_LC_BIT    ((u32)0x00000400)
+#define RICU_AFE_CTL_0_AFCINIT_SEL_LC_POS    10
+#define RICU_AFE_CTL_0_AFCINIT_SEL_BIT      ((u32)0x00000200)
+#define RICU_AFE_CTL_0_AFCINIT_SEL_POS      9
+#define RICU_AFE_CTL_0_EN_CLK_MON_BIT       ((u32)0x00000100)
+#define RICU_AFE_CTL_0_EN_CLK_MON_POS       8
+#define RICU_AFE_CTL_0_EN_DAC_CLK_BIT       ((u32)0x00000080)
+#define RICU_AFE_CTL_0_EN_DAC_CLK_POS       7
+#define RICU_AFE_CTL_0_EN_CDB_DAC_CLK_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTL_0_EN_CDB_DAC_CLK_POS    6
+#define RICU_AFE_CTL_0_EN_CDB_ADC_CLK_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTL_0_EN_CDB_ADC_CLK_POS    5
+#define RICU_AFE_CTL_0_EN_CDB_GEN_BIT       ((u32)0x00000008)
+#define RICU_AFE_CTL_0_EN_CDB_GEN_POS       3
+#define RICU_AFE_CTL_0_DACCLK_PHASESEL_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTL_0_DACCLK_PHASESEL_POS    2
+#define RICU_AFE_CTL_0_ADCCLK_PHASESEL_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTL_0_ADCCLK_PHASESEL_POS    1
+#define RICU_AFE_CTL_0_CDB_CLK_RESETB_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTL_0_CDB_CLK_RESETB_POS    0
+
+static inline void ricu_afe_ctl_0_pbias_ctrl_en_lc_setf(struct cl_chip *chip, u8 pbiasctrlenlc)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR) & ~((u32)0x80000000)) |
+			  ((u32)pbiasctrlenlc << 31));
+}
+
+static inline void ricu_afe_ctl_0_cdb_clk_resetb_setf(struct cl_chip *chip, u8 cdbclkresetb)
+{
+	ASSERT_ERR_CHIP((((u32)cdbclkresetb << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_0_ADDR) & ~((u32)0x00000001)) |
+			  ((u32)cdbclkresetb << 0));
+}
+
+/*
+ * @brief AFE_CTL_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    14    VCO_BOOST                 0
+ *    13    SYS_ADCCLK_SEL            0
+ *    12    SOC_PHASE_SEL             1
+ *    11    SOC_CLK_SEL               1
+ *    10    RESETB_LC                 0
+ *    09    RESETB                    1
+ *    08    PBIAS_CTRL_LC             0
+ *    07    PBIAS_CTRL                0
+ *    06    GP_CLK_PHASESEL           0
+ *    05    FSEL_LC                   0
+ *    04    FSEL                      0
+ *    03    FOUT_MASK_LC              0
+ *    02    FOUT_MASK                 0
+ *    01    EXTCLK_SEL                0
+ *    00    EN_PLL_LDO                0
+ * </pre>
+ */
+#define RICU_AFE_CTL_1_ADDR        (REG_RICU_BASE_ADDR + 0x00000014)
+#define RICU_AFE_CTL_1_OFFSET      0x00000014
+#define RICU_AFE_CTL_1_INDEX       0x00000005
+#define RICU_AFE_CTL_1_RESET       0x00001A00
+
+static inline void ricu_afe_ctl_1_resetb_lc_setf(struct cl_chip *chip, u8 resetblc)
+{
+	ASSERT_ERR_CHIP((((u32)resetblc << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_1_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)resetblc << 10));
+}
+
+static inline void ricu_afe_ctl_1_en_pll_ldo_setf(struct cl_chip *chip, u8 enpllldo)
+{
+	ASSERT_ERR_CHIP((((u32)enpllldo << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_1_ADDR) & ~((u32)0x00000001)) |
+			  ((u32)enpllldo << 0));
+}
+
+/*
+ * @brief AFE_CTL_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:22 LOCK_CON_REV_LC           0x0
+ *    21:20 LOCK_CON_REV              0x0
+ *    19:18 LOCK_CON_OUT_LC           0x3
+ *    17:16 LOCK_CON_OUT              0x3
+ *    15:14 LOCK_CON_IN_LC            0x3
+ *    13:12 LOCK_CON_IN               0x3
+ *    11:10 LOCK_CON_DLY_LC           0x3
+ *    09:08 LOCK_CON_DLY              0x3
+ *    07:06 ICP                       0x1
+ *    03:02 CTRL_IB                   0x2
+ *    01:00 CLK_MON_SEL               0x0
+ * </pre>
+ */
+#define RICU_AFE_CTL_2_ADDR        (REG_RICU_BASE_ADDR + 0x00000018)
+#define RICU_AFE_CTL_2_OFFSET      0x00000018
+#define RICU_AFE_CTL_2_INDEX       0x00000006
+#define RICU_AFE_CTL_2_RESET       0x000FFF48
+
+static inline void ricu_afe_ctl_2_lock_con_rev_lc_setf(struct cl_chip *chip, u8 lockconrevlc)
+{
+	ASSERT_ERR_CHIP((((u32)lockconrevlc << 22) & ~((u32)0x00C00000)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_2_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_2_ADDR) & ~((u32)0x00C00000)) |
+			  ((u32)lockconrevlc << 22));
+}
+
+/*
+ * @brief AFE_CTL_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:28 RSEL                      0x0
+ *    27:24 I_CSEL_LC                 0xc
+ *    23:20 GM_LC                     0xf
+ *    19:16 CSEL_LC                   0x3
+ *    15:12 CML_SEL                   0x9
+ *    11:09 S_LC                      0x0
+ *    08:06 S                         0x0
+ *    05:03 LBW_LC                    0x7
+ *    02:00 ICP_LC                    0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_3_ADDR        (REG_RICU_BASE_ADDR + 0x0000001C)
+#define RICU_AFE_CTL_3_OFFSET      0x0000001C
+#define RICU_AFE_CTL_3_INDEX       0x00000007
+#define RICU_AFE_CTL_3_RESET       0x0CF3903F
+
+static inline void ricu_afe_ctl_3_cml_sel_setf(struct cl_chip *chip, u8 cmlsel)
+{
+	ASSERT_ERR_CHIP((((u32)cmlsel << 12) & ~((u32)0x0000F000)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_3_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_3_ADDR) & ~((u32)0x0000F000)) |
+			  ((u32)cmlsel << 12));
+}
+
+/*
+ * @brief AFE_CTL_5 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:18 MAIN_SEL_7_2              0x0
+ *    17:12 P_LC                      0x1
+ *    11:06 P                         0xA
+ *    05:00 CAP_BIAS_CODE_LC          0x4
+ * </pre>
+ */
+#define RICU_AFE_CTL_5_ADDR        (REG_RICU_BASE_ADDR + 0x00000024)
+#define RICU_AFE_CTL_5_OFFSET      0x00000024
+#define RICU_AFE_CTL_5_INDEX       0x00000009
+#define RICU_AFE_CTL_5_RESET       0x00001284
+
+static inline void ricu_afe_ctl_5_main_sel_7_2_setf(struct cl_chip *chip, u8 mainsel72)
+{
+	ASSERT_ERR_CHIP((((u32)mainsel72 << 18) & ~((u32)0x00FC0000)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_5_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTL_5_ADDR) & ~((u32)0x00FC0000)) |
+			  ((u32)mainsel72 << 18));
+}
+
+/*
+ * @brief AFE_CTL_8 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    EN_REF7                   0
+ *    30    EN_REF6                   0
+ *    29    EN_REF5                   0
+ *    28    EN_REF4                   0
+ *    27    EN_REF3                   0
+ *    26    EN_REF2                   0
+ *    25    EN_REF1                   0
+ *    24    EN_REF0                   0
+ *    23    EN_EXT_LOAD7              0
+ *    22    EN_EXT_LOAD6              0
+ *    21    EN_EXT_LOAD5              0
+ *    20    EN_EXT_LOAD4              0
+ *    19    EN_EXT_LOAD3              0
+ *    18    EN_EXT_LOAD2              0
+ *    17    EN_EXT_LOAD1              0
+ *    16    EN_EXT_LOAD0              0
+ *    15    CH_CML_SEL7               0
+ *    14    CH_CML_SEL6               0
+ *    13    CH_CML_SEL5               0
+ *    12    CH_CML_SEL4               0
+ *    11    CH_CML_SEL3               0
+ *    10    CH_CML_SEL2               0
+ *    09    CH_CML_SEL1               0
+ *    08    CH_CML_SEL0               0
+ *    07    EN_BGR7                   0
+ *    06    EN_BGR6                   0
+ *    05    EN_BGR5                   0
+ *    04    EN_BGR4                   0
+ *    03    EN_BGR3                   0
+ *    02    EN_BGR2                   0
+ *    01    EN_BGR1                   0
+ *    00    EN_BGR0                   0
+ * </pre>
+ */
+#define RICU_AFE_CTL_8_ADDR        (REG_RICU_BASE_ADDR + 0x00000030)
+#define RICU_AFE_CTL_8_OFFSET      0x00000030
+#define RICU_AFE_CTL_8_INDEX       0x0000000C
+#define RICU_AFE_CTL_8_RESET       0x00000000
+
+static inline u32 ricu_afe_ctl_8_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTL_8_ADDR);
+}
+
+static inline void ricu_afe_ctl_8_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_8_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_8_EN_REF_7_BIT         ((u32)0x80000000)
+#define RICU_AFE_CTL_8_EN_REF_7_POS         31
+#define RICU_AFE_CTL_8_EN_REF_6_BIT         ((u32)0x40000000)
+#define RICU_AFE_CTL_8_EN_REF_6_POS         30
+#define RICU_AFE_CTL_8_EN_REF_5_BIT         ((u32)0x20000000)
+#define RICU_AFE_CTL_8_EN_REF_5_POS         29
+#define RICU_AFE_CTL_8_EN_REF_4_BIT         ((u32)0x10000000)
+#define RICU_AFE_CTL_8_EN_REF_4_POS         28
+#define RICU_AFE_CTL_8_EN_REF_3_BIT         ((u32)0x08000000)
+#define RICU_AFE_CTL_8_EN_REF_3_POS         27
+#define RICU_AFE_CTL_8_EN_REF_2_BIT         ((u32)0x04000000)
+#define RICU_AFE_CTL_8_EN_REF_2_POS         26
+#define RICU_AFE_CTL_8_EN_REF_1_BIT         ((u32)0x02000000)
+#define RICU_AFE_CTL_8_EN_REF_1_POS         25
+#define RICU_AFE_CTL_8_EN_REF_0_BIT         ((u32)0x01000000)
+#define RICU_AFE_CTL_8_EN_REF_0_POS         24
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_7_BIT    ((u32)0x00800000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_7_POS    23
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_6_BIT    ((u32)0x00400000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_6_POS    22
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_5_BIT    ((u32)0x00200000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_5_POS    21
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_4_BIT    ((u32)0x00100000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_4_POS    20
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_3_BIT    ((u32)0x00080000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_3_POS    19
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_2_BIT    ((u32)0x00040000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_2_POS    18
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_1_BIT    ((u32)0x00020000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_1_POS    17
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_0_BIT    ((u32)0x00010000)
+#define RICU_AFE_CTL_8_EN_EXT_LOAD_0_POS    16
+#define RICU_AFE_CTL_8_CH_CML_SEL_7_BIT     ((u32)0x00008000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_7_POS     15
+#define RICU_AFE_CTL_8_CH_CML_SEL_6_BIT     ((u32)0x00004000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_6_POS     14
+#define RICU_AFE_CTL_8_CH_CML_SEL_5_BIT     ((u32)0x00002000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_5_POS     13
+#define RICU_AFE_CTL_8_CH_CML_SEL_4_BIT     ((u32)0x00001000)
+#define RICU_AFE_CTL_8_CH_CML_SEL_4_POS     12
+#define RICU_AFE_CTL_8_CH_CML_SEL_3_BIT     ((u32)0x00000800)
+#define RICU_AFE_CTL_8_CH_CML_SEL_3_POS     11
+#define RICU_AFE_CTL_8_CH_CML_SEL_2_BIT     ((u32)0x00000400)
+#define RICU_AFE_CTL_8_CH_CML_SEL_2_POS     10
+#define RICU_AFE_CTL_8_CH_CML_SEL_1_BIT     ((u32)0x00000200)
+#define RICU_AFE_CTL_8_CH_CML_SEL_1_POS     9
+#define RICU_AFE_CTL_8_CH_CML_SEL_0_BIT     ((u32)0x00000100)
+#define RICU_AFE_CTL_8_CH_CML_SEL_0_POS     8
+#define RICU_AFE_CTL_8_EN_BGR_7_BIT         ((u32)0x00000080)
+#define RICU_AFE_CTL_8_EN_BGR_7_POS         7
+#define RICU_AFE_CTL_8_EN_BGR_6_BIT         ((u32)0x00000040)
+#define RICU_AFE_CTL_8_EN_BGR_6_POS         6
+#define RICU_AFE_CTL_8_EN_BGR_5_BIT         ((u32)0x00000020)
+#define RICU_AFE_CTL_8_EN_BGR_5_POS         5
+#define RICU_AFE_CTL_8_EN_BGR_4_BIT         ((u32)0x00000010)
+#define RICU_AFE_CTL_8_EN_BGR_4_POS         4
+#define RICU_AFE_CTL_8_EN_BGR_3_BIT         ((u32)0x00000008)
+#define RICU_AFE_CTL_8_EN_BGR_3_POS         3
+#define RICU_AFE_CTL_8_EN_BGR_2_BIT         ((u32)0x00000004)
+#define RICU_AFE_CTL_8_EN_BGR_2_POS         2
+#define RICU_AFE_CTL_8_EN_BGR_1_BIT         ((u32)0x00000002)
+#define RICU_AFE_CTL_8_EN_BGR_1_POS         1
+#define RICU_AFE_CTL_8_EN_BGR_0_BIT         ((u32)0x00000001)
+#define RICU_AFE_CTL_8_EN_BGR_0_POS         0
+
+/*
+ * @brief AFE_CTL_9 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    EN_SIN2_BIAS7             1
+ *    30    EN_SIN2_BIAS6             1
+ *    29    EN_SIN2_BIAS5             1
+ *    28    EN_SIN2_BIAS4             1
+ *    27    EN_SIN2_BIAS3             1
+ *    26    EN_SIN2_BIAS2             1
+ *    25    EN_SIN2_BIAS1             1
+ *    24    EN_SIN2_BIAS0             1
+ *    23    EN_DAC_REF7               0
+ *    22    EN_DAC_REF6               0
+ *    21    EN_DAC_REF5               0
+ *    20    EN_DAC_REF4               0
+ *    19    EN_DAC_REF3               0
+ *    18    EN_DAC_REF2               0
+ *    17    EN_DAC_REF1               0
+ *    16    EN_DAC_REF0               0
+ * </pre>
+ */
+#define RICU_AFE_CTL_9_ADDR        (REG_RICU_BASE_ADDR + 0x00000034)
+#define RICU_AFE_CTL_9_OFFSET      0x00000034
+#define RICU_AFE_CTL_9_INDEX       0x0000000D
+#define RICU_AFE_CTL_9_RESET       0xFF000000
+
+static inline u32 ricu_afe_ctl_9_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTL_9_ADDR);
+}
+
+static inline void ricu_afe_ctl_9_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_9_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_7_BIT    ((u32)0x80000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_7_POS    31
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_6_BIT    ((u32)0x40000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_6_POS    30
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_5_BIT    ((u32)0x20000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_5_POS    29
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_4_BIT    ((u32)0x10000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_4_POS    28
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_3_BIT    ((u32)0x08000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_3_POS    27
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_2_BIT    ((u32)0x04000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_2_POS    26
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_1_BIT    ((u32)0x02000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_1_POS    25
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_0_BIT    ((u32)0x01000000)
+#define RICU_AFE_CTL_9_EN_SIN_2_BIAS_0_POS    24
+#define RICU_AFE_CTL_9_EN_DAC_REF_7_BIT     ((u32)0x00800000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_7_POS     23
+#define RICU_AFE_CTL_9_EN_DAC_REF_6_BIT     ((u32)0x00400000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_6_POS     22
+#define RICU_AFE_CTL_9_EN_DAC_REF_5_BIT     ((u32)0x00200000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_5_POS     21
+#define RICU_AFE_CTL_9_EN_DAC_REF_4_BIT     ((u32)0x00100000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_4_POS     20
+#define RICU_AFE_CTL_9_EN_DAC_REF_3_BIT     ((u32)0x00080000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_3_POS     19
+#define RICU_AFE_CTL_9_EN_DAC_REF_2_BIT     ((u32)0x00040000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_2_POS     18
+#define RICU_AFE_CTL_9_EN_DAC_REF_1_BIT     ((u32)0x00020000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_1_POS     17
+#define RICU_AFE_CTL_9_EN_DAC_REF_0_BIT     ((u32)0x00010000)
+#define RICU_AFE_CTL_9_EN_DAC_REF_0_POS     16
+
+/*
+ * @brief AFE_CTL_10 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    VC_LD7                    0
+ *    30    VC_LD6                    0
+ *    29    VC_LD5                    0
+ *    28    VC_LD4                    0
+ *    27    VC_LD3                    0
+ *    26    VC_LD2                    0
+ *    25    VC_LD1                    0
+ *    24    VC_LD0                    0
+ *    23    TWOS7                     0
+ *    22    TWOS6                     0
+ *    21    TWOS5                     0
+ *    20    TWOS4                     0
+ *    19    TWOS3                     0
+ *    18    TWOS2                     0
+ *    17    TWOS1                     0
+ *    16    TWOS0                     0
+ *    07    MINV7                     1
+ *    06    MINV6                     1
+ *    05    MINV5                     1
+ *    04    MINV4                     1
+ *    03    MINV3                     1
+ *    02    MINV2                     1
+ *    01    MINV1                     1
+ *    00    MINV0                     1
+ * </pre>
+ */
+#define RICU_AFE_CTL_10_ADDR        (REG_RICU_BASE_ADDR + 0x00000038)
+#define RICU_AFE_CTL_10_OFFSET      0x00000038
+#define RICU_AFE_CTL_10_INDEX       0x0000000E
+#define RICU_AFE_CTL_10_RESET       0x000000FF
+
+static inline void ricu_afe_ctl_10_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_10_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_12 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:30 EOC_CTRL7                 0x0
+ *    29:28 EOC_CTRL6                 0x0
+ *    27:26 EOC_CTRL5                 0x0
+ *    25:24 EOC_CTRL4                 0x0
+ *    23:22 EOC_CTRL3                 0x0
+ *    21:20 EOC_CTRL2                 0x0
+ *    19:18 EOC_CTRL1                 0x0
+ *    17:16 EOC_CTRL0                 0x0
+ *    15:14 IC_REFSSF7                0x1
+ *    13:12 IC_REFSSF6                0x1
+ *    11:10 IC_REFSSF5                0x1
+ *    09:08 IC_REFSSF4                0x1
+ *    07:06 IC_REFSSF3                0x1
+ *    05:04 IC_REFSSF2                0x1
+ *    03:02 IC_REFSSF1                0x1
+ *    01:00 IC_REFSSF0                0x1
+ * </pre>
+ */
+#define RICU_AFE_CTL_12_ADDR        (REG_RICU_BASE_ADDR + 0x00000040)
+#define RICU_AFE_CTL_12_OFFSET      0x00000040
+#define RICU_AFE_CTL_12_INDEX       0x00000010
+#define RICU_AFE_CTL_12_RESET       0x00005555
+
+static inline void ricu_afe_ctl_12_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_12_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTL_12_EOC_CTRL_7_MASK     ((u32)0xC0000000)
+#define RICU_AFE_CTL_12_EOC_CTRL_7_LSB      30
+#define RICU_AFE_CTL_12_EOC_CTRL_7_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_6_MASK     ((u32)0x30000000)
+#define RICU_AFE_CTL_12_EOC_CTRL_6_LSB      28
+#define RICU_AFE_CTL_12_EOC_CTRL_6_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_5_MASK     ((u32)0x0C000000)
+#define RICU_AFE_CTL_12_EOC_CTRL_5_LSB      26
+#define RICU_AFE_CTL_12_EOC_CTRL_5_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_4_MASK     ((u32)0x03000000)
+#define RICU_AFE_CTL_12_EOC_CTRL_4_LSB      24
+#define RICU_AFE_CTL_12_EOC_CTRL_4_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_3_MASK     ((u32)0x00C00000)
+#define RICU_AFE_CTL_12_EOC_CTRL_3_LSB      22
+#define RICU_AFE_CTL_12_EOC_CTRL_3_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_2_MASK     ((u32)0x00300000)
+#define RICU_AFE_CTL_12_EOC_CTRL_2_LSB      20
+#define RICU_AFE_CTL_12_EOC_CTRL_2_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_1_MASK     ((u32)0x000C0000)
+#define RICU_AFE_CTL_12_EOC_CTRL_1_LSB      18
+#define RICU_AFE_CTL_12_EOC_CTRL_1_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_EOC_CTRL_0_MASK     ((u32)0x00030000)
+#define RICU_AFE_CTL_12_EOC_CTRL_0_LSB      16
+#define RICU_AFE_CTL_12_EOC_CTRL_0_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_7_MASK    ((u32)0x0000C000)
+#define RICU_AFE_CTL_12_IC_REFSSF_7_LSB     14
+#define RICU_AFE_CTL_12_IC_REFSSF_7_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_6_MASK    ((u32)0x00003000)
+#define RICU_AFE_CTL_12_IC_REFSSF_6_LSB     12
+#define RICU_AFE_CTL_12_IC_REFSSF_6_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_5_MASK    ((u32)0x00000C00)
+#define RICU_AFE_CTL_12_IC_REFSSF_5_LSB     10
+#define RICU_AFE_CTL_12_IC_REFSSF_5_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_4_MASK    ((u32)0x00000300)
+#define RICU_AFE_CTL_12_IC_REFSSF_4_LSB     8
+#define RICU_AFE_CTL_12_IC_REFSSF_4_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_3_MASK    ((u32)0x000000C0)
+#define RICU_AFE_CTL_12_IC_REFSSF_3_LSB     6
+#define RICU_AFE_CTL_12_IC_REFSSF_3_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_2_MASK    ((u32)0x00000030)
+#define RICU_AFE_CTL_12_IC_REFSSF_2_LSB     4
+#define RICU_AFE_CTL_12_IC_REFSSF_2_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_1_MASK    ((u32)0x0000000C)
+#define RICU_AFE_CTL_12_IC_REFSSF_1_LSB     2
+#define RICU_AFE_CTL_12_IC_REFSSF_1_WIDTH    ((u32)0x00000002)
+#define RICU_AFE_CTL_12_IC_REFSSF_0_MASK    ((u32)0x00000003)
+#define RICU_AFE_CTL_12_IC_REFSSF_0_LSB     0
+#define RICU_AFE_CTL_12_IC_REFSSF_0_WIDTH    ((u32)0x00000002)
+
+/*
+ * @brief AFE_CTL_13 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    FORCE_ADC_ON_PHY1         0
+ *    30    FORCE_ADC_ON_PHY0         0
+ *    16    EN_LB8_AUX                0
+ *    15    EN_LB7                    0
+ *    14    EN_LB6                    0
+ *    13    EN_LB5                    0
+ *    12    EN_LB4                    0
+ *    11    EN_LB3                    0
+ *    10    EN_LB2                    0
+ *    09    EN_LB1                    0
+ *    08    EN_LB0                    0
+ * </pre>
+ */
+#define RICU_AFE_CTL_13_ADDR        (REG_RICU_BASE_ADDR + 0x00000044)
+#define RICU_AFE_CTL_13_OFFSET      0x00000044
+#define RICU_AFE_CTL_13_INDEX       0x00000011
+#define RICU_AFE_CTL_13_RESET       0x00000000
+
+static inline void ricu_afe_ctl_13_pack(struct cl_chip *chip, u8 forceadconphy1, u8 forceadconphy0,
+					u8 enlb8aux, u8 enlb7, u8 enlb6, u8 enlb5, u8 enlb4,
+					u8 enlb3, u8 enlb2, u8 enlb1, u8 enlb0)
+{
+	ASSERT_ERR_CHIP((((u32)forceadconphy0 << 30) & ~((u32)0x40000000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb8aux << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb7 << 15) & ~((u32)0x00008000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb6 << 14) & ~((u32)0x00004000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb5 << 13) & ~((u32)0x00002000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb4 << 12) & ~((u32)0x00001000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb3 << 11) & ~((u32)0x00000800)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb2 << 10) & ~((u32)0x00000400)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb1 << 9) & ~((u32)0x00000200)) == 0);
+	ASSERT_ERR_CHIP((((u32)enlb0 << 8) & ~((u32)0x00000100)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_13_ADDR,
+			  ((u32)forceadconphy1 << 31) | ((u32)forceadconphy0 << 30) |
+			  ((u32)enlb8aux << 16) | ((u32)enlb7 << 15) | ((u32)enlb6 << 14) |
+			  ((u32)enlb5 << 13) | ((u32)enlb4 << 12) | ((u32)enlb3 << 11) |
+			  ((u32)enlb2 << 10) | ((u32)enlb1 << 9) | ((u32)enlb0 << 8));
+}
+
+/*
+ * @brief AFE_CTL_15 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 EN_OUT_CM7                0x0
+ *    26:24 EN_OUT_CM6                0x0
+ *    22:20 EN_OUT_CM5                0x0
+ *    18:16 EN_OUT_CM4                0x0
+ *    14:12 EN_OUT_CM3                0x0
+ *    10:08 EN_OUT_CM2                0x0
+ *    06:04 EN_OUT_CM1                0x0
+ *    02:00 EN_OUT_CM0                0x0
+ * </pre>
+ */
+#define RICU_AFE_CTL_15_ADDR        (REG_RICU_BASE_ADDR + 0x0000004C)
+#define RICU_AFE_CTL_15_OFFSET      0x0000004C
+#define RICU_AFE_CTL_15_INDEX       0x00000013
+#define RICU_AFE_CTL_15_RESET       0x00000000
+
+static inline void ricu_afe_ctl_15_pack(struct cl_chip *chip, u8 enoutcm7, u8 enoutcm6,
+					u8 enoutcm5, u8 enoutcm4, u8 enoutcm3,
+					u8 enoutcm2, u8 enoutcm1, u8 enoutcm0)
+{
+	ASSERT_ERR_CHIP((((u32)enoutcm7 << 28) & ~((u32)0x70000000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm6 << 24) & ~((u32)0x07000000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm5 << 20) & ~((u32)0x00700000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm4 << 16) & ~((u32)0x00070000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm3 << 12) & ~((u32)0x00007000)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm2 << 8) & ~((u32)0x00000700)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm1 << 4) & ~((u32)0x00000070)) == 0);
+	ASSERT_ERR_CHIP((((u32)enoutcm0 << 0) & ~((u32)0x00000007)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_15_ADDR,
+			  ((u32)enoutcm7 << 28) | ((u32)enoutcm6 << 24) | ((u32)enoutcm5 << 20) |
+			  ((u32)enoutcm4 << 16) | ((u32)enoutcm3 << 12) | ((u32)enoutcm2 << 8) |
+			  ((u32)enoutcm1 << 4) | ((u32)enoutcm0 << 0));
+}
+
+/*
+ * @brief AFE_CTL_17 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_REF7                   0x1
+ *    26:24 VC_REF6                   0x1
+ *    22:20 VC_REF5                   0x1
+ *    18:16 VC_REF4                   0x1
+ *    14:12 VC_REF3                   0x1
+ *    10:08 VC_REF2                   0x1
+ *    06:04 VC_REF1                   0x1
+ *    02:00 VC_REF0                   0x1
+ * </pre>
+ */
+#define RICU_AFE_CTL_17_ADDR        (REG_RICU_BASE_ADDR + 0x00000054)
+#define RICU_AFE_CTL_17_OFFSET      0x00000054
+#define RICU_AFE_CTL_17_INDEX       0x00000015
+#define RICU_AFE_CTL_17_RESET       0x11111111
+
+static inline void ricu_afe_ctl_17_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_17_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_19 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:28 COMP_CTRL7                0x4
+ *    27:24 COMP_CTRL6                0x4
+ *    23:20 COMP_CTRL5                0x4
+ *    19:16 COMP_CTRL4                0x4
+ *    15:12 COMP_CTRL3                0x4
+ *    11:08 COMP_CTRL2                0x4
+ *    07:04 COMP_CTRL1                0x4
+ *    03:00 COMP_CTRL0                0x4
+ * </pre>
+ */
+#define RICU_AFE_CTL_19_ADDR        (REG_RICU_BASE_ADDR + 0x0000005C)
+#define RICU_AFE_CTL_19_OFFSET      0x0000005C
+#define RICU_AFE_CTL_19_INDEX       0x00000017
+#define RICU_AFE_CTL_19_RESET       0x44444444
+
+static inline void ricu_afe_ctl_19_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_19_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_23 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_LD_AVDI7               0x3
+ *    26:24 VC_LD_AVDI6               0x3
+ *    22:20 VC_LD_AVDI5               0x3
+ *    18:16 VC_LD_AVDI4               0x3
+ *    14:12 VC_LD_AVDI3               0x3
+ *    10:08 VC_LD_AVDI2               0x3
+ *    06:04 VC_LD_AVDI1               0x3
+ *    02:00 VC_LD_AVDI0               0x3
+ * </pre>
+ */
+#define RICU_AFE_CTL_23_ADDR        (REG_RICU_BASE_ADDR + 0x0000006C)
+#define RICU_AFE_CTL_23_OFFSET      0x0000006C
+#define RICU_AFE_CTL_23_INDEX       0x0000001B
+#define RICU_AFE_CTL_23_RESET       0x33333333
+
+static inline void ricu_afe_ctl_23_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_23_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_24 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_LD_AVDQ7               0x3
+ *    26:24 VC_LD_AVDQ6               0x3
+ *    22:20 VC_LD_AVDQ5               0x3
+ *    18:16 VC_LD_AVDQ4               0x3
+ *    14:12 VC_LD_AVDQ3               0x3
+ *    10:08 VC_LD_AVDQ2               0x3
+ *    06:04 VC_LD_AVDQ1               0x3
+ *    02:00 VC_LD_AVDQ0               0x3
+ * </pre>
+ */
+#define RICU_AFE_CTL_24_ADDR        (REG_RICU_BASE_ADDR + 0x00000070)
+#define RICU_AFE_CTL_24_OFFSET      0x00000070
+#define RICU_AFE_CTL_24_INDEX       0x0000001C
+#define RICU_AFE_CTL_24_RESET       0x33333333
+
+static inline void ricu_afe_ctl_24_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_24_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_25 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL0                    0
+ *    14:08 RO_CTRLQ0                 0x7
+ *    06:00 RO_CTRLI0                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_25_ADDR        (REG_RICU_BASE_ADDR + 0x00000074)
+#define RICU_AFE_CTL_25_OFFSET      0x00000074
+#define RICU_AFE_CTL_25_INDEX       0x0000001D
+#define RICU_AFE_CTL_25_RESET       0x00000707
+
+static inline void ricu_afe_ctl_25_pack(struct cl_chip *chip, u8 rosel0, u8 roctrlq0, u8 roctrli0)
+{
+	ASSERT_ERR_CHIP((((u32)rosel0 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq0 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli0 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_25_ADDR,
+			  ((u32)rosel0 << 16) | ((u32)roctrlq0 << 8) | ((u32)roctrli0 << 0));
+}
+
+/*
+ * @brief AFE_CTL_26 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL1                    0
+ *    14:08 RO_CTRLQ1                 0x7
+ *    06:00 RO_CTRLI1                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_26_ADDR        (REG_RICU_BASE_ADDR + 0x00000078)
+#define RICU_AFE_CTL_26_OFFSET      0x00000078
+#define RICU_AFE_CTL_26_INDEX       0x0000001E
+#define RICU_AFE_CTL_26_RESET       0x00000707
+
+static inline void ricu_afe_ctl_26_pack(struct cl_chip *chip, u8 rosel1, u8 roctrlq1, u8 roctrli1)
+{
+	ASSERT_ERR_CHIP((((u32)rosel1 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq1 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli1 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_26_ADDR,
+			  ((u32)rosel1 << 16) | ((u32)roctrlq1 << 8) | ((u32)roctrli1 << 0));
+}
+
+/*
+ * @brief AFE_CTL_27 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL2                    0
+ *    14:08 RO_CTRLQ2                 0x7
+ *    06:00 RO_CTRLI2                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_27_ADDR        (REG_RICU_BASE_ADDR + 0x0000007C)
+#define RICU_AFE_CTL_27_OFFSET      0x0000007C
+#define RICU_AFE_CTL_27_INDEX       0x0000001F
+#define RICU_AFE_CTL_27_RESET       0x00000707
+
+static inline void ricu_afe_ctl_27_pack(struct cl_chip *chip, u8 rosel2, u8 roctrlq2, u8 roctrli2)
+{
+	ASSERT_ERR_CHIP((((u32)rosel2 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq2 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli2 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_27_ADDR,
+			  ((u32)rosel2 << 16) | ((u32)roctrlq2 << 8) | ((u32)roctrli2 << 0));
+}
+
+/*
+ * @brief AFE_CTL_29 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_CML7_I                 0x5
+ *    26:24 VC_CML6_I                 0x5
+ *    22:20 VC_CML5_I                 0x5
+ *    18:16 VC_CML4_I                 0x5
+ *    14:12 VC_CML3_I                 0x5
+ *    10:08 VC_CML2_I                 0x5
+ *    06:04 VC_CML1_I                 0x5
+ *    02:00 VC_CML0_I                 0x5
+ * </pre>
+ */
+#define RICU_AFE_CTL_29_ADDR        (REG_RICU_BASE_ADDR + 0x00000084)
+#define RICU_AFE_CTL_29_OFFSET      0x00000084
+#define RICU_AFE_CTL_29_INDEX       0x00000021
+#define RICU_AFE_CTL_29_RESET       0x55555555
+
+static inline void ricu_afe_ctl_29_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_29_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_30 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    30:28 VC_CML7_Q                 0x5
+ *    26:24 VC_CML6_Q                 0x5
+ *    22:20 VC_CML5_Q                 0x5
+ *    18:16 VC_CML4_Q                 0x5
+ *    14:12 VC_CML3_Q                 0x5
+ *    10:08 VC_CML2_Q                 0x5
+ *    06:04 VC_CML1_Q                 0x5
+ *    02:00 VC_CML0_Q                 0x5
+ * </pre>
+ */
+#define RICU_AFE_CTL_30_ADDR        (REG_RICU_BASE_ADDR + 0x00000088)
+#define RICU_AFE_CTL_30_OFFSET      0x00000088
+#define RICU_AFE_CTL_30_INDEX       0x00000022
+#define RICU_AFE_CTL_30_RESET       0x55555555
+
+static inline void ricu_afe_ctl_30_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTL_30_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTL_33 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL3                    0
+ *    14:08 RO_CTRL3_Q                0x7
+ *    06:00 RO_CTRL3_I                0x7
+ * </pre>
+ */
+#define RICU_AFE_CTL_33_ADDR        (REG_RICU_BASE_ADDR + 0x00000094)
+#define RICU_AFE_CTL_33_OFFSET      0x00000094
+#define RICU_AFE_CTL_33_INDEX       0x00000025
+#define RICU_AFE_CTL_33_RESET       0x00000707
+
+static inline void ricu_afe_ctl_33_pack(struct cl_chip *chip, u8 rosel3, u8 roctrl3q, u8 roctrl3i)
+{
+	ASSERT_ERR_CHIP((((u32)rosel3 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrl3q << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrl3i << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTL_33_ADDR,
+			  ((u32)rosel3 << 16) | ((u32)roctrl3q << 8) | ((u32)roctrl3i << 0));
+}
+
+/*
+ * @brief AFE_CTRL_34_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY0_ADC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY0_ADC_SB_RD_DELAY      0x4
+ *    01:00 PHY0_ADC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_34_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x0000009C)
+#define RICU_AFE_CTRL_34_PHY_0_OFFSET      0x0000009C
+#define RICU_AFE_CTRL_34_PHY_0_INDEX       0x00000027
+#define RICU_AFE_CTRL_34_PHY_0_RESET       0x00000010
+
+static inline
+void ricu_afe_ctrl_34_phy_0_adc_sb_ignore_fifo_indication_setf(struct cl_chip *chip,
+							       u8 phy0adcsbignorefifoindication)
+{
+	ASSERT_ERR_CHIP((((u32)phy0adcsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR) &
+			   ~((u32)0x00000040)) | ((u32)phy0adcsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_34_phy_0_adc_sb_rd_delay_setf(struct cl_chip *chip,
+							       u8 phy0adcsbrddelay)
+{
+	ASSERT_ERR_CHIP((((u32)phy0adcsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_0_ADDR) &
+			   ~((u32)0x0000003C)) | ((u32)phy0adcsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_36_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07    PHY0_ADC_ALWAYS_EN_LD_IR  0
+ *    06    PHY0_ADC_ALWAYS_EN_LD_AVDQ 0
+ *    05    PHY0_ADC_ALWAYS_EN_LD_AVDI 0
+ *    04    PHY0_ADC_ALWAYS_EN_ADCQ   0
+ *    03    PHY0_ADC_ALWAYS_EN_ADCI   0
+ *    01    PHY0_HW_MODE_DAC          0
+ *    00    PHY0_HW_MODE_ADC          0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_36_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000A0)
+#define RICU_AFE_CTRL_36_PHY_0_OFFSET      0x000000A0
+#define RICU_AFE_CTRL_36_PHY_0_INDEX       0x00000028
+#define RICU_AFE_CTRL_36_PHY_0_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_36_phy_0_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR);
+}
+
+static inline void ricu_afe_ctrl_36_phy_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_BIT    ((u32)0x00000080)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_IR_POS    7
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDQ_POS    6
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_LD_AVDI_POS    5
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCQ_POS    4
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_36_PHY_0_ADC_ALWAYS_EN_ADCI_POS    3
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_DAC_POS    1
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_36_PHY_0_HW_MODE_ADC_POS    0
+
+static inline void ricu_afe_ctrl_36_phy_0_hw_mode_dac_setf(struct cl_chip *chip, u8 phy0hwmodedac)
+{
+	ASSERT_ERR_CHIP((((u32)phy0hwmodedac << 1) & ~((u32)0x00000002)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR) &
+			   ~((u32)0x00000002)) | ((u32)phy0hwmodedac << 1));
+}
+
+static inline void ricu_afe_ctrl_36_phy_0_hw_mode_adc_setf(struct cl_chip *chip, u8 phy0hwmodeadc)
+{
+	ASSERT_ERR_CHIP((((u32)phy0hwmodeadc << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_0_ADDR) &
+			   ~((u32)0x00000001)) | ((u32)phy0hwmodeadc << 0));
+}
+
+/*
+ * @brief AFE_CTRL_34_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY1_ADC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY1_ADC_SB_RD_DELAY      0x4
+ *    01:00 PHY1_ADC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_34_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000A4)
+#define RICU_AFE_CTRL_34_PHY_1_OFFSET      0x000000A4
+#define RICU_AFE_CTRL_34_PHY_1_INDEX       0x00000029
+#define RICU_AFE_CTRL_34_PHY_1_RESET       0x00000010
+
+static inline
+void ricu_afe_ctrl_34_phy_1_adc_sb_ignore_fifo_indication_setf(struct cl_chip *chip,
+							       u8 phy1adcsbignorefifoindication)
+{
+	ASSERT_ERR_CHIP((((u32)phy1adcsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR) &
+			   ~((u32)0x00000040)) | ((u32)phy1adcsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_34_phy_1_adc_sb_rd_delay_setf(struct cl_chip *chip,
+							       u8 phy1adcsbrddelay)
+{
+	ASSERT_ERR_CHIP((((u32)phy1adcsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_34_PHY_1_ADDR) &
+			   ~((u32)0x0000003C)) | ((u32)phy1adcsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_35_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY0_DAC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY0_DAC_SB_RD_DELAY      0x1
+ *    01:00 PHY0_DAC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_35_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000A8)
+#define RICU_AFE_CTRL_35_PHY_0_OFFSET      0x000000A8
+#define RICU_AFE_CTRL_35_PHY_0_INDEX       0x0000002A
+#define RICU_AFE_CTRL_35_PHY_0_RESET       0x00000004
+
+static inline
+void ricu_afe_ctrl_35_phy_0_dac_sb_ignore_fifo_indication_setf(struct cl_chip *chip,
+							       u8 phy0dacsbignorefifoindication)
+{
+	ASSERT_ERR_CHIP((((u32)phy0dacsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR) &
+			   ~((u32)0x00000040)) | ((u32)phy0dacsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_35_phy_0_dac_sb_rd_delay_setf(struct cl_chip *chip,
+							       u8 phy0dacsbrddelay)
+{
+	ASSERT_ERR_CHIP((((u32)phy0dacsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_0_ADDR) &
+			   ~((u32)0x0000003C)) | ((u32)phy0dacsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_35_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    06    PHY1_DAC_SB_IGNORE_FIFO_INDICATION 0
+ *    05:02 PHY1_DAC_SB_RD_DELAY      0x1
+ *    01:00 PHY1_DAC_SB_MODE          0x0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_35_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000AC)
+#define RICU_AFE_CTRL_35_PHY_1_OFFSET      0x000000AC
+#define RICU_AFE_CTRL_35_PHY_1_INDEX       0x0000002B
+#define RICU_AFE_CTRL_35_PHY_1_RESET       0x00000004
+
+static inline
+void ricu_afe_ctrl_35_phy_1_dac_sb_ignore_fifo_indication_setf(struct cl_chip *chip,
+							       u8 phy1dacsbignorefifoindication)
+{
+	ASSERT_ERR_CHIP((((u32)phy1dacsbignorefifoindication << 6) & ~((u32)0x00000040)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR) &
+			   ~((u32)0x00000040)) | ((u32)phy1dacsbignorefifoindication << 6));
+}
+
+static inline void ricu_afe_ctrl_35_phy_1_dac_sb_rd_delay_setf(struct cl_chip *chip,
+							       u8 phy1dacsbrddelay)
+{
+	ASSERT_ERR_CHIP((((u32)phy1dacsbrddelay << 2) & ~((u32)0x0000003C)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_35_PHY_1_ADDR) &
+			   ~((u32)0x0000003C)) | ((u32)phy1dacsbrddelay << 2));
+}
+
+/*
+ * @brief AFE_CTRL_37_PHY_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05    PHY0_EN_DAC5              0
+ *    04    PHY0_EN_DAC4              0
+ *    03    PHY0_EN_DAC3              0
+ *    02    PHY0_EN_DAC2              0
+ *    01    PHY0_EN_DAC1              0
+ *    00    PHY0_EN_DAC0              0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_37_PHY_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000BC)
+#define RICU_AFE_CTRL_37_PHY_0_OFFSET      0x000000BC
+#define RICU_AFE_CTRL_37_PHY_0_INDEX       0x0000002F
+#define RICU_AFE_CTRL_37_PHY_0_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_37_phy_0_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTRL_37_PHY_0_ADDR);
+}
+
+static inline void ricu_afe_ctrl_37_phy_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_37_PHY_0_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_5_POS    5
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_4_POS    4
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_3_POS    3
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_2_POS    2
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_1_POS    1
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_37_PHY_0_EN_DAC_0_POS    0
+
+/*
+ * @brief AFE_CTRL_37_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05    PHY1_EN_DAC5              0
+ *    04    PHY1_EN_DAC4              0
+ *    03    PHY1_EN_DAC3              0
+ *    02    PHY1_EN_DAC2              0
+ *    01    PHY1_EN_DAC1              0
+ *    00    PHY1_EN_DAC0              0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_37_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000C0)
+#define RICU_AFE_CTRL_37_PHY_1_OFFSET      0x000000C0
+#define RICU_AFE_CTRL_37_PHY_1_INDEX       0x00000030
+#define RICU_AFE_CTRL_37_PHY_1_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_37_phy_1_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTRL_37_PHY_1_ADDR);
+}
+
+static inline void ricu_afe_ctrl_37_phy_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_37_PHY_1_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_5_POS    5
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_4_POS    4
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_3_POS    3
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_BIT    ((u32)0x00000004)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_2_POS    2
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_1_POS    1
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_37_PHY_1_EN_DAC_0_POS    0
+
+/*
+ * @brief AFE_CTRL_39 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL4                    0
+ *    14:08 RO_CTRLQ4                 0x7
+ *    06:00 RO_CTRLI4                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_39_ADDR        (REG_RICU_BASE_ADDR + 0x000000CC)
+#define RICU_AFE_CTRL_39_OFFSET      0x000000CC
+#define RICU_AFE_CTRL_39_INDEX       0x00000033
+#define RICU_AFE_CTRL_39_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_39_pack(struct cl_chip *chip, u8 rosel4, u8 roctrlq4, u8 roctrli4)
+{
+	ASSERT_ERR_CHIP((((u32)rosel4 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq4 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli4 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_39_ADDR,
+			  ((u32)rosel4 << 16) | ((u32)roctrlq4 << 8) | ((u32)roctrli4 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_40 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL5                    0
+ *    14:08 RO_CTRLQ5                 0x7
+ *    06:00 RO_CTRLI5                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_40_ADDR        (REG_RICU_BASE_ADDR + 0x000000D0)
+#define RICU_AFE_CTRL_40_OFFSET      0x000000D0
+#define RICU_AFE_CTRL_40_INDEX       0x00000034
+#define RICU_AFE_CTRL_40_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_40_pack(struct cl_chip *chip, u8 rosel5, u8 roctrlq5, u8 roctrli5)
+{
+	ASSERT_ERR_CHIP((((u32)rosel5 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq5 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli5 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_40_ADDR,
+			  ((u32)rosel5 << 16) | ((u32)roctrlq5 << 8) | ((u32)roctrli5 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_41 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL6                    0
+ *    14:08 RO_CTRLQ6                 0x7
+ *    06:00 RO_CTRLI6                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_41_ADDR        (REG_RICU_BASE_ADDR + 0x000000D4)
+#define RICU_AFE_CTRL_41_OFFSET      0x000000D4
+#define RICU_AFE_CTRL_41_INDEX       0x00000035
+#define RICU_AFE_CTRL_41_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_41_pack(struct cl_chip *chip, u8 rosel6, u8 roctrlq6, u8 roctrli6)
+{
+	ASSERT_ERR_CHIP((((u32)rosel6 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq6 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli6 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_41_ADDR,
+			  ((u32)rosel6 << 16) | ((u32)roctrlq6 << 8) | ((u32)roctrli6 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_42 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    16    ROSEL7                    0
+ *    14:08 RO_CTRLQ7                 0x7
+ *    06:00 RO_CTRLI7                 0x7
+ * </pre>
+ */
+#define RICU_AFE_CTRL_42_ADDR        (REG_RICU_BASE_ADDR + 0x000000D8)
+#define RICU_AFE_CTRL_42_OFFSET      0x000000D8
+#define RICU_AFE_CTRL_42_INDEX       0x00000036
+#define RICU_AFE_CTRL_42_RESET       0x00000707
+
+static inline void ricu_afe_ctrl_42_pack(struct cl_chip *chip, u8 rosel7, u8 roctrlq7, u8 roctrli7)
+{
+	ASSERT_ERR_CHIP((((u32)rosel7 << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrlq7 << 8) & ~((u32)0x00007F00)) == 0);
+	ASSERT_ERR_CHIP((((u32)roctrli7 << 0) & ~((u32)0x0000007F)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_42_ADDR,
+			  ((u32)rosel7 << 16) | ((u32)roctrlq7 << 8) | ((u32)roctrli7 << 0));
+}
+
+/*
+ * @brief AFE_CTRL_43 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    01:00 FREQ_SEL                  0x3
+ * </pre>
+ */
+#define RICU_AFE_CTRL_43_ADDR        (REG_RICU_BASE_ADDR + 0x000000DC)
+#define RICU_AFE_CTRL_43_OFFSET      0x000000DC
+#define RICU_AFE_CTRL_43_INDEX       0x00000037
+#define RICU_AFE_CTRL_43_RESET       0x00000003
+
+static inline void ricu_afe_ctrl_43_freq_sel_setf(struct cl_chip *chip, u8 freqsel)
+{
+	ASSERT_ERR_CHIP((((u32)freqsel << 0) & ~((u32)0x00000003)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_43_ADDR, (u32)freqsel << 0);
+}
+
+/*
+ * @brief AFE_CTRL_44 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    01:00 CDB_FREQ_SEL              0x3
+ * </pre>
+ */
+#define RICU_AFE_CTRL_44_ADDR        (REG_RICU_BASE_ADDR + 0x000000E0)
+#define RICU_AFE_CTRL_44_OFFSET      0x000000E0
+#define RICU_AFE_CTRL_44_INDEX       0x00000038
+#define RICU_AFE_CTRL_44_RESET       0x00000003
+
+static inline void ricu_afe_ctrl_44_cdb_freq_sel_setf(struct cl_chip *chip, u8 cdbfreqsel)
+{
+	ASSERT_ERR_CHIP((((u32)cdbfreqsel << 0) & ~((u32)0x00000003)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_44_ADDR, (u32)cdbfreqsel << 0);
+}
+
+/*
+ * @brief SPI_CLK_CTRL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    05:00 SPI_CLK_BITMAP            0xE
+ * </pre>
+ */
+#define RICU_SPI_CLK_CTRL_ADDR        (REG_RICU_BASE_ADDR + 0x000000E4)
+#define RICU_SPI_CLK_CTRL_OFFSET      0x000000E4
+#define RICU_SPI_CLK_CTRL_INDEX       0x00000039
+#define RICU_SPI_CLK_CTRL_RESET       0x0000000E
+
+static inline void ricu_spi_clk_ctrl_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_SPI_CLK_CTRL_ADDR, value);
+}
+
+/*
+ * @brief FEM_CONF_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:20 FEM5_CTL_SEL              0x5
+ *    19:16 FEM4_CTL_SEL              0x4
+ *    15:12 FEM3_CTL_SEL              0x3
+ *    11:08 FEM2_CTL_SEL              0x2
+ *    07:04 FEM1_CTL_SEL              0x1
+ *    03:00 FEM0_CTL_SEL              0x0
+ * </pre>
+ */
+#define RICU_FEM_CONF_0_ADDR        (REG_RICU_BASE_ADDR + 0x000000F0)
+#define RICU_FEM_CONF_0_OFFSET      0x000000F0
+#define RICU_FEM_CONF_0_INDEX       0x0000003C
+#define RICU_FEM_CONF_0_RESET       0x00543210
+
+static inline void ricu_fem_conf_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_FEM_CONF_0_ADDR, value);
+}
+
+/*
+ * @brief FEM_CONF_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:20 FEM11_CTL_SEL             0xd
+ *    19:16 FEM10_CTL_SEL             0xc
+ *    15:12 FEM9_CTL_SEL              0xb
+ *    11:08 FEM8_CTL_SEL              0xa
+ *    07:04 FEM7_CTL_SEL              0x9
+ *    03:00 FEM6_CTL_SEL              0x8
+ * </pre>
+ */
+#define RICU_FEM_CONF_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000F4)
+#define RICU_FEM_CONF_1_OFFSET      0x000000F4
+#define RICU_FEM_CONF_1_INDEX       0x0000003D
+#define RICU_FEM_CONF_1_RESET       0x00DCBA98
+
+static inline void ricu_fem_conf_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_FEM_CONF_1_ADDR, value);
+}
+
+/*
+ * @brief AFE_CTRL_36_PHY_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07    PHY1_ADC_ALWAYS_EN_LD_IR  0
+ *    06    PHY1_ADC_ALWAYS_EN_LD_AVDQ 0
+ *    05    PHY1_ADC_ALWAYS_EN_LD_AVDI 0
+ *    04    PHY1_ADC_ALWAYS_EN_ADCQ   0
+ *    03    PHY1_ADC_ALWAYS_EN_ADCI   0
+ *    01    PHY1_HW_MODE_DAC          0
+ *    00    PHY1_HW_MODE_ADC          0
+ * </pre>
+ */
+#define RICU_AFE_CTRL_36_PHY_1_ADDR        (REG_RICU_BASE_ADDR + 0x000000F8)
+#define RICU_AFE_CTRL_36_PHY_1_OFFSET      0x000000F8
+#define RICU_AFE_CTRL_36_PHY_1_INDEX       0x0000003E
+#define RICU_AFE_CTRL_36_PHY_1_RESET       0x00000000
+
+static inline u32 ricu_afe_ctrl_36_phy_1_get(struct cl_chip *chip)
+{
+	return cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR);
+}
+
+static inline void ricu_afe_ctrl_36_phy_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR, value);
+}
+
+/* Field definitions */
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_BIT    ((u32)0x00000080)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_IR_POS    7
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_BIT    ((u32)0x00000040)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDQ_POS    6
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_BIT    ((u32)0x00000020)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_LD_AVDI_POS    5
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_BIT    ((u32)0x00000010)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCQ_POS    4
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_BIT    ((u32)0x00000008)
+#define RICU_AFE_CTRL_36_PHY_1_ADC_ALWAYS_EN_ADCI_POS    3
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_BIT    ((u32)0x00000002)
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_DAC_POS    1
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_BIT    ((u32)0x00000001)
+#define RICU_AFE_CTRL_36_PHY_1_HW_MODE_ADC_POS    0
+
+static inline void ricu_afe_ctrl_36_phy_1_hw_mode_dac_setf(struct cl_chip *chip, u8 phy1hwmodedac)
+{
+	ASSERT_ERR_CHIP((((u32)phy1hwmodedac << 1) & ~((u32)0x00000002)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR) &
+			   ~((u32)0x00000002)) | ((u32)phy1hwmodedac << 1));
+}
+
+static inline void ricu_afe_ctrl_36_phy_1_hw_mode_adc_setf(struct cl_chip *chip, u8 phy1hwmodeadc)
+{
+	ASSERT_ERR_CHIP((((u32)phy1hwmodeadc << 0) & ~((u32)0x00000001)) == 0);
+	cl_reg_write_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR,
+			  (cl_reg_read_chip(chip, RICU_AFE_CTRL_36_PHY_1_ADDR) &
+			   ~((u32)0x00000001)) | ((u32)phy1hwmodeadc << 0));
+}
+
+/*
+ * @brief AFE_ADC_CH_ALLOC register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    07:00 AFE_ADC_CH_ALLOC          0xFF
+ * </pre>
+ */
+#define RICU_AFE_ADC_CH_ALLOC_ADDR        (REG_RICU_BASE_ADDR + 0x000000FC)
+#define RICU_AFE_ADC_CH_ALLOC_OFFSET      0x000000FC
+#define RICU_AFE_ADC_CH_ALLOC_INDEX       0x0000003F
+#define RICU_AFE_ADC_CH_ALLOC_RESET       0x000000FF
+
+static inline u8 ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_getf(struct cl_chip *chip)
+{
+	u32 local_val = cl_reg_read_chip(chip, RICU_AFE_ADC_CH_ALLOC_ADDR);
+
+	return (local_val >> 0);
+}
+
+static inline void ricu_afe_adc_ch_alloc_afe_adc_ch_alloc_setf(struct cl_chip *chip,
+							       u8 afeadcchalloc)
+{
+	cl_reg_write_chip(chip, RICU_AFE_ADC_CH_ALLOC_ADDR, (u32)afeadcchalloc << 0);
+}
+
+#define RIU_RSF_FILE_SIZE 0x60C
+
+/*
+ * @brief RSF_CONTROL register definition
+ *  resampling filter operation mode register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    rsf_init_en               1
+ *    07    rsf_tx_bypass_type        0
+ *    06    rsf_tx_bypass_mode        1
+ *    05    rsf_rx_bypass_type        0
+ *    04    rsf_rx_bypass_mode        1
+ *    01    rsf_rx_ctl_from_reg       1
+ * </pre>
+ */
+#define RIU_RSF_CONTROL_ADDR        (REG_RIU_BASE_ADDR + 0x000001A8)
+#define RIU_RSF_CONTROL_OFFSET      0x000001A8
+#define RIU_RSF_CONTROL_INDEX       0x0000006A
+#define RIU_RSF_CONTROL_RESET       0x80000053
+
+static inline void riu_rsf_control_rsf_init_en_setf(struct cl_hw *cl_hw, u8 rsfiniten)
+{
+	cl_reg_write(cl_hw, RIU_RSF_CONTROL_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RSF_CONTROL_ADDR) & ~((u32)0x80000000)) |
+		     ((u32)rsfiniten << 31));
+}
+
+/*
+ * @brief RSF_INIT register definition
+ *  resampling filter initialization data register description
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 RSF_INIT_DATA             0x0
+ * </pre>
+ */
+#define RIU_RSF_INIT_ADDR        (REG_RIU_BASE_ADDR + 0x000001AC)
+#define RIU_RSF_INIT_OFFSET      0x000001AC
+#define RIU_RSF_INIT_INDEX       0x0000006B
+#define RIU_RSF_INIT_RESET       0x00000000
+
+static inline void riu_rsf_init_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, RIU_RSF_INIT_ADDR, value);
+}
+
+/*
+ * @brief AGCFSM_RAM_INIT_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    AGC_FSM_RAM_INIT_EN       0
+ *    29    AGC_FSM_RAM_INIT_AINC2    0
+ *    28    AGC_FSM_RAM_INIT_AINC1    0
+ *    12    AGC_FSM_RAM_INIT_WPTR_SET 0
+ *    10:00 AGC_FSM_RAM_INIT_WPTR     0x0
+ * </pre>
+ */
+#define RIU_AGCFSM_RAM_INIT_1_ADDR        (REG_RIU_BASE_ADDR + 0x000001B0)
+#define RIU_AGCFSM_RAM_INIT_1_OFFSET      0x000001B0
+#define RIU_AGCFSM_RAM_INIT_1_INDEX       0x0000006C
+#define RIU_AGCFSM_RAM_INIT_1_RESET       0x00000000
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_en_setf(struct cl_hw *cl_hw,
+								  u8 agcfsmraminiten)
+{
+	cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+		     (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x80000000)) |
+		     ((u32)agcfsmraminiten << 31));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_ainc_1_setf(struct cl_hw *cl_hw,
+								      u8 agcfsmraminitainc1)
+{
+	ASSERT_ERR((((u32)agcfsmraminitainc1 << 28) & ~((u32)0x10000000)) == 0);
+	cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+		     (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x10000000)) |
+		     ((u32)agcfsmraminitainc1 << 28));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_set_setf(struct cl_hw *cl_hw,
+									u8 agcfsmraminitwptrset)
+{
+	ASSERT_ERR((((u32)agcfsmraminitwptrset << 12) & ~((u32)0x00001000)) == 0);
+	cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+		     (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x00001000)) |
+		     ((u32)agcfsmraminitwptrset << 12));
+}
+
+static inline void riu_agcfsm_ram_init_1_agc_fsm_ram_init_wptr_setf(struct cl_hw *cl_hw,
+								    u16 agcfsmraminitwptr)
+{
+	ASSERT_ERR((((u32)agcfsmraminitwptr << 0) & ~((u32)0x000007FF)) == 0);
+	cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR,
+		     (cl_reg_read(cl_hw, RIU_AGCFSM_RAM_INIT_1_ADDR) & ~((u32)0x000007FF)) |
+		     ((u32)agcfsmraminitwptr << 0));
+}
+
+/*
+ * @brief AGCFSM_RAM_INIT_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:00 AGC_FSM_RAM_INIT_WDATA    0x0
+ * </pre>
+ */
+#define RIU_AGCFSM_RAM_INIT_2_ADDR        (REG_RIU_BASE_ADDR + 0x000001B4)
+#define RIU_AGCFSM_RAM_INIT_2_OFFSET      0x000001B4
+#define RIU_AGCFSM_RAM_INIT_2_INDEX       0x0000006D
+#define RIU_AGCFSM_RAM_INIT_2_RESET       0x00000000
+
+static inline void riu_agcfsm_ram_init_2_set(struct cl_hw *cl_hw, u32 value)
+{
+	cl_reg_write(cl_hw, RIU_AGCFSM_RAM_INIT_2_ADDR, value);
+}
+
+/*
+ * @brief AGCINBDPOW_20_PNOISESTAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PNOISEDBM3      0x0
+ *    23:16 INBDPOW20_PNOISEDBM2      0x0
+ *    15:08 INBDPOW20_PNOISEDBM1      0x0
+ *    07:00 INBDPOW20_PNOISEDBM0      0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOW_20_PNOISESTAT_ADDR        (REG_RIU_BASE_ADDR + 0x00000228)
+#define RIU_AGCINBDPOW_20_PNOISESTAT_OFFSET      0x00000228
+#define RIU_AGCINBDPOW_20_PNOISESTAT_INDEX       0x0000008A
+#define RIU_AGCINBDPOW_20_PNOISESTAT_RESET       0x00000000
+
+static inline u32 riu_agcinbdpow_20_pnoisestat_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_AGCINBDPOW_20_PNOISESTAT_ADDR);
+}
+
+/*
+ * @brief AGCINBDPOWSECNOISESTAT register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:16 INBDPOW80_SNOISEDBM       0x0
+ *    15:08 INBDPOW40_SNOISEDBM       0x0
+ *    07:00 INBDPOW20_SNOISEDBM       0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWSECNOISESTAT_ADDR        (REG_RIU_BASE_ADDR + 0x00000230)
+#define RIU_AGCINBDPOWSECNOISESTAT_OFFSET      0x00000230
+#define RIU_AGCINBDPOWSECNOISESTAT_INDEX       0x0000008C
+#define RIU_AGCINBDPOWSECNOISESTAT_RESET       0x00000000
+
+static inline u32 riu_agcinbdpowsecnoisestat_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_AGCINBDPOWSECNOISESTAT_ADDR);
+}
+
+/*
+ * @brief RWNXAGCCNTL register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:26 COMBPATHSEL               0x3F
+ *    25:20 GAINKEEP                  0x0
+ *    16    HTSTFGAINEN               1
+ *    15    NOISE_CAPTURE_DELAY_MODE  0
+ *    14    EST_PATH_SEL_2            0
+ *    13    CCA_MDM_ST_CLEAR          0
+ *    12    AGCFSMRESET               0
+ *    11    RADARDETEN                0
+ *    10    RIFSDETEN                 1
+ *    09    DSSSONLY                  0
+ *    08    OFDMONLY                  0
+ *    07:04 GPSTATUS                  0x0
+ *    03    EST_PATH_SEL              0
+ *    01    ADC_SEL_RADAR_DETECTOR    0
+ *    00    ADC_SEL_COMP_MODULE       0
+ * </pre>
+ */
+#define RIU_RWNXAGCCNTL_ADDR        (REG_RIU_BASE_ADDR + 0x00000390)
+#define RIU_RWNXAGCCNTL_OFFSET      0x00000390
+#define RIU_RWNXAGCCNTL_INDEX       0x000000E4
+#define RIU_RWNXAGCCNTL_RESET       0xFC010400
+
+static inline void riu_rwnxagccntl_agcfsmreset_setf(struct cl_hw *cl_hw, u8 agcfsmreset)
+{
+	ASSERT_ERR((((u32)agcfsmreset << 12) & ~((u32)0x00001000)) == 0);
+	cl_reg_write(cl_hw, RIU_RWNXAGCCNTL_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCCNTL_ADDR) & ~((u32)0x00001000)) |
+		     ((u32)agcfsmreset << 12));
+}
+
+/*
+ * @brief RWNXAGCDSP_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    27:20 INBDPOWMINDBV             0xBF
+ *    17:16 INBDRND                   0x3
+ *    15:08 INBDPOWMINDBM_ANT1        0x9C
+ *    07:00 INBDPOWMINDBM_ANT0        0x9C
+ * </pre>
+ */
+#define RIU_RWNXAGCDSP_3_ADDR        (REG_RIU_BASE_ADDR + 0x000003A0)
+#define RIU_RWNXAGCDSP_3_OFFSET      0x000003A0
+#define RIU_RWNXAGCDSP_3_INDEX       0x000000E8
+#define RIU_RWNXAGCDSP_3_RESET       0x0BF39C9C
+
+static inline u8 riu_rwnxagcdsp_3_inbdpowmindbm_ant_1_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_3_ADDR);
+
+	return ((local_val & ((u32)0x0000FF00)) >> 8);
+}
+
+static inline void riu_rwnxagcdsp_3_inbdpowmindbm_ant_1_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant1)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_3_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_3_ADDR) & ~((u32)0x0000FF00)) |
+		     ((u32)inbdpowmindbmant1 << 8));
+}
+
+static inline u8 riu_rwnxagcdsp_3_inbdpowmindbm_ant_0_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_3_ADDR);
+
+	return ((local_val & ((u32)0x000000FF)) >> 0);
+}
+
+static inline void riu_rwnxagcdsp_3_inbdpowmindbm_ant_0_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant0)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_3_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_3_ADDR) & ~((u32)0x000000FF)) |
+		     ((u32)inbdpowmindbmant0 << 0));
+}
+
+/*
+ * @brief RWNXAGCCCA_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31    CCA_CNT_CLEAR             0
+ *    30:29 CCA_CNT_RATE              0x0
+ *    28:20 INBDCCAPOWMINDBM          0x1B5
+ *    19:12 CCAFALLTHRDBM             0xBF
+ *    10    CCAEnergy_Reset_Type      0
+ *    09    DISCCAEN                  1
+ *    08    SATCCAEN                  1
+ *    07:00 CCARISETHRDBM             0xC2
+ * </pre>
+ */
+#define RIU_RWNXAGCCCA_1_ADDR        (REG_RIU_BASE_ADDR + 0x000003AC)
+#define RIU_RWNXAGCCCA_1_OFFSET      0x000003AC
+#define RIU_RWNXAGCCCA_1_INDEX       0x000000EB
+#define RIU_RWNXAGCCCA_1_RESET       0x1B5BF3C2
+
+static inline void riu_rwnxagccca_1_cca_cnt_clear_setf(struct cl_hw *cl_hw, u8 ccacntclear)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCCCA_1_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCCCA_1_ADDR) & ~((u32)0x80000000)) |
+		     ((u32)ccacntclear << 31));
+}
+
+static inline void riu_rwnxagccca_1_cca_cnt_rate_setf(struct cl_hw *cl_hw, u8 ccacntrate)
+{
+	ASSERT_ERR((((u32)ccacntrate << 29) & ~((u32)0x60000000)) == 0);
+	cl_reg_write_direct(cl_hw, RIU_RWNXAGCCCA_1_ADDR,
+			    (cl_reg_read(cl_hw, RIU_RWNXAGCCCA_1_ADDR) & ~((u32)0x60000000)) |
+			    ((u32)ccacntrate << 29));
+}
+
+/*
+ * @brief RWNXAGCDSP_5 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWMINDBM_ANT5        0x9C
+ *    23:16 INBDPOWMINDBM_ANT4        0x9C
+ *    15:08 INBDPOWMINDBM_ANT3        0x9C
+ *    07:00 INBDPOWMINDBM_ANT2        0x9C
+ * </pre>
+ */
+#define RIU_RWNXAGCDSP_5_ADDR        (REG_RIU_BASE_ADDR + 0x000003EC)
+#define RIU_RWNXAGCDSP_5_OFFSET      0x000003EC
+#define RIU_RWNXAGCDSP_5_INDEX       0x000000FB
+#define RIU_RWNXAGCDSP_5_RESET       0x9C9C9C9C
+
+static inline u8 riu_rwnxagcdsp_5_inbdpowmindbm_ant_5_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR);
+
+	return ((local_val & ((u32)0xFF000000)) >> 24);
+}
+
+static inline void riu_rwnxagcdsp_5_inbdpowmindbm_ant_5_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant5)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_5_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR) & ~((u32)0xFF000000)) |
+		     ((u32)inbdpowmindbmant5 << 24));
+}
+
+static inline u8 riu_rwnxagcdsp_5_inbdpowmindbm_ant_4_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR);
+
+	return ((local_val & ((u32)0x00FF0000)) >> 16);
+}
+
+static inline void riu_rwnxagcdsp_5_inbdpowmindbm_ant_4_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant4)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_5_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR) & ~((u32)0x00FF0000)) |
+		     ((u32)inbdpowmindbmant4 << 16));
+}
+
+static inline u8 riu_rwnxagcdsp_5_inbdpowmindbm_ant_3_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR);
+
+	return ((local_val & ((u32)0x0000FF00)) >> 8);
+}
+
+static inline void riu_rwnxagcdsp_5_inbdpowmindbm_ant_3_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant3)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_5_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR) & ~((u32)0x0000FF00)) |
+		     ((u32)inbdpowmindbmant3 << 8));
+}
+
+static inline u8 riu_rwnxagcdsp_5_inbdpowmindbm_ant_2_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR);
+
+	return ((local_val & ((u32)0x000000FF)) >> 0);
+}
+
+static inline void riu_rwnxagcdsp_5_inbdpowmindbm_ant_2_setf(struct cl_hw *cl_hw,
+							     u8 inbdpowmindbmant2)
+{
+	cl_reg_write(cl_hw, RIU_RWNXAGCDSP_5_ADDR,
+		     (cl_reg_read(cl_hw, RIU_RWNXAGCDSP_5_ADDR) & ~((u32)0x000000FF)) |
+		     ((u32)inbdpowmindbmant2 << 0));
+}
+
+/*
+ * @brief AGCINBDPOWNOISEPER_20_STAT_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWNOISEDBMPER20_3    0x0
+ *    23:16 INBDPOWNOISEDBMPER20_2    0x0
+ *    15:08 INBDPOWNOISEDBMPER20_1    0x0
+ *    07:00 INBDPOWNOISEDBMPER20_0    0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_ADDR        (REG_RIU_BASE_ADDR + 0x00000478)
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_OFFSET      0x00000478
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_INDEX       0x0000011E
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_0_RESET       0x00000000
+
+static inline u32 riu_agcinbdpownoiseper_20_stat_0_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_AGCINBDPOWNOISEPER_20_STAT_0_ADDR);
+}
+
+/*
+ * @brief AGCINBDPOWNOISEPER_20_STAT_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWNOISEDBMPER20_7    0x0
+ *    23:16 INBDPOWNOISEDBMPER20_6    0x0
+ *    15:08 INBDPOWNOISEDBMPER20_5    0x0
+ *    07:00 INBDPOWNOISEDBMPER20_4    0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_ADDR        (REG_RIU_BASE_ADDR + 0x0000047C)
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_OFFSET      0x0000047C
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_INDEX       0x0000011F
+#define RIU_AGCINBDPOWNOISEPER_20_STAT_1_RESET       0x00000000
+
+static inline u32 riu_agcinbdpownoiseper_20_stat_1_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_AGCINBDPOWNOISEPER_20_STAT_1_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_0 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PDBMA3_MAC      0x0
+ *    23:16 INBDPOW20_PDBMA2_MAC      0x0
+ *    15:08 INBDPOW20_PDBMA1_MAC      0x0
+ *    07:00 INBDPOW20_PDBMA0_MAC      0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_0_ADDR        (REG_RIU_BASE_ADDR + 0x00000480)
+#define RIU_INBDPOWFORMAC_0_OFFSET      0x00000480
+#define RIU_INBDPOWFORMAC_0_INDEX       0x00000120
+#define RIU_INBDPOWFORMAC_0_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_0_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_0_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_1 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    15:08 INBDPOW20_PDBMA5_MAC      0x0
+ *    07:00 INBDPOW20_PDBMA4_MAC      0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_1_ADDR        (REG_RIU_BASE_ADDR + 0x00000484)
+#define RIU_INBDPOWFORMAC_1_OFFSET      0x00000484
+#define RIU_INBDPOWFORMAC_1_INDEX       0x00000121
+#define RIU_INBDPOWFORMAC_1_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_1_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_1_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    23:16 INBDPOW80_SDBM_MAC        0x0
+ *    15:08 INBDPOW40_SDBM_MAC        0x0
+ *    07:00 INBDPOW20_SDBM_MAC        0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_2_ADDR        (REG_RIU_BASE_ADDR + 0x00000488)
+#define RIU_INBDPOWFORMAC_2_OFFSET      0x00000488
+#define RIU_INBDPOWFORMAC_2_INDEX       0x00000122
+#define RIU_INBDPOWFORMAC_2_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_2_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_2_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_3 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWPER20_PDBM_3_MAC   0x0
+ *    23:16 INBDPOWPER20_PDBM_2_MAC   0x0
+ *    15:08 INBDPOWPER20_PDBM_1_MAC   0x0
+ *    07:00 INBDPOWPER20_PDBM_0_MAC   0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_3_ADDR        (REG_RIU_BASE_ADDR + 0x0000048C)
+#define RIU_INBDPOWFORMAC_3_OFFSET      0x0000048C
+#define RIU_INBDPOWFORMAC_3_INDEX       0x00000123
+#define RIU_INBDPOWFORMAC_3_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_3_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_3_ADDR);
+}
+
+/*
+ * @brief INBDPOWFORMAC_4 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOWPER20_PDBM_7_MAC   0x0
+ *    23:16 INBDPOWPER20_PDBM_6_MAC   0x0
+ *    15:08 INBDPOWPER20_PDBM_5_MAC   0x0
+ *    07:00 INBDPOWPER20_PDBM_4_MAC   0x0
+ * </pre>
+ */
+#define RIU_INBDPOWFORMAC_4_ADDR        (REG_RIU_BASE_ADDR + 0x00000490)
+#define RIU_INBDPOWFORMAC_4_OFFSET      0x00000490
+#define RIU_INBDPOWFORMAC_4_INDEX       0x00000124
+#define RIU_INBDPOWFORMAC_4_RESET       0x00000000
+
+static inline u32 riu_inbdpowformac_4_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_INBDPOWFORMAC_4_ADDR);
+}
+
+/*
+ * @brief AGCINBDPOW_20_PNOISESTAT_2 register definition
+ * <pre>
+ *   Bits           Field Name   Reset Value
+ *  -----   ------------------   -----------
+ *    31:24 INBDPOW20_PNOISEDBM5      0x0
+ *    23:16 INBDPOW20_PNOISEDBM4      0x0
+ *    15:08 ADCPOWDBM5                0x0
+ *    07:00 ADCPOWDBM4                0x0
+ * </pre>
+ */
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_ADDR        (REG_RIU_BASE_ADDR + 0x0000067C)
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_OFFSET      0x0000067C
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_INDEX       0x0000019F
+#define RIU_AGCINBDPOW_20_PNOISESTAT_2_RESET       0x00000000
+
+static inline u32 riu_agcinbdpow_20_pnoisestat_2_get(struct cl_hw *cl_hw)
+{
+	return cl_reg_read(cl_hw, RIU_AGCINBDPOW_20_PNOISESTAT_2_ADDR);
+}
+
+#define REG_RIU_RC_BASE_ADDR 0x00485000
+
+/*
+ * @brief SW_CTRL register definition
+ * This register provides write access to the radio SPI interface register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   31    START_DONE                0
+ *   30    MORE                      0
+ *   29    FASTWR_SPD                0
+ *   28    FASTWR_FORCE              0
+ *   27    FWR_HW_ENABLE             1
+ *   26    FWR_SW_ENABLE             1
+ *   25    FWR_ENABLE                1
+ *   24    RF_RESET_B                0
+ *   23:19 PRESCALER                 0x1
+ *   16    READNOTWRITE              0
+ *   14:08 ADDRESS                   0x0
+ *   07:00 DATA                      0x0
+ * </pre>
+ */
+#define RIU_RC_SW_CTRL_ADDR        (REG_RIU_RC_BASE_ADDR + 0x00000000)
+#define RIU_RC_SW_CTRL_OFFSET      0x00000000
+#define RIU_RC_SW_CTRL_INDEX       0x00000000
+#define RIU_RC_SW_CTRL_RESET       0x0E080000
+
+static inline void riu_rc_sw_ctrl_pack(struct cl_hw *cl_hw, u8 startdone, u8 more,
+				       u8 fastwrspd, u8 fastwrforce, u8 fwrhwenable,
+				       u8 fwrswenable, u8 fwrenable, u8 rfresetb,
+				       u8 prescaler, u8 readnotwrite, u8 address, u8 data)
+{
+	ASSERT_ERR((((u32)more << 30) & ~((u32)0x40000000)) == 0);
+	ASSERT_ERR((((u32)fastwrspd << 29) & ~((u32)0x20000000)) == 0);
+	ASSERT_ERR((((u32)fastwrforce << 28) & ~((u32)0x10000000)) == 0);
+	ASSERT_ERR((((u32)fwrhwenable << 27) & ~((u32)0x08000000)) == 0);
+	ASSERT_ERR((((u32)fwrswenable << 26) & ~((u32)0x04000000)) == 0);
+	ASSERT_ERR((((u32)fwrenable << 25) & ~((u32)0x02000000)) == 0);
+	ASSERT_ERR((((u32)rfresetb << 24) & ~((u32)0x01000000)) == 0);
+	ASSERT_ERR((((u32)prescaler << 19) & ~((u32)0x00F80000)) == 0);
+	ASSERT_ERR((((u32)readnotwrite << 16) & ~((u32)0x00010000)) == 0);
+	ASSERT_ERR((((u32)address << 8) & ~((u32)0x00007F00)) == 0);
+	cl_reg_write(cl_hw, RIU_RC_SW_CTRL_ADDR,
+		     ((u32)startdone << 31) | ((u32)more << 30) |
+		     ((u32)fastwrspd << 29) | ((u32)fastwrforce << 28) |
+		     ((u32)fwrhwenable << 27) | ((u32)fwrswenable << 26) |
+		     ((u32)fwrenable << 25) | ((u32)rfresetb << 24) |
+		     ((u32)prescaler << 19) | ((u32)readnotwrite << 16) |
+		     ((u32)address << 8) | ((u32)data << 0));
+}
+
+static inline u8 riu_rc_sw_ctrl_start_done_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RC_SW_CTRL_ADDR);
+
+	return ((local_val & ((u32)0x80000000)) >> 31);
+}
+
+static inline u8 riu_rc_sw_ctrl_data_getf(struct cl_hw *cl_hw)
+{
+	u32 local_val = cl_reg_read(cl_hw, RIU_RC_SW_CTRL_ADDR);
+
+	return ((local_val & ((u32)0x000000FF)) >> 0);
+}
+
+/*
+ * @brief RF_LNA_LUT register definition
+ * These registers provide control of the RF LNA assertion by decoding each possible value
+ * the AGC LNA gain setting, from minimum LNA gain to maximum LNA gain. register description
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   26:24 RFLNALUT6                 0x6
+ *   22:20 RFLNALUT5                 0x5
+ *   18:16 RFLNALUT4                 0x4
+ *   14:12 RFLNALUT3                 0x3
+ *   10:08 RFLNALUT2                 0x2
+ *   06:04 RFLNALUT1                 0x1
+ *   02:00 RFLNALUT0                 0x0
+ * </pre>
+ */
+
+/* Field definitions */
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_MASK    ((u32)0x07000000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_LSB    24
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_6_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_MASK    ((u32)0x00700000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_LSB    20
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_5_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_MASK    ((u32)0x00070000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_LSB    16
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_4_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_MASK    ((u32)0x00007000)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_LSB    12
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_3_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_MASK    ((u32)0x00000700)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_LSB    8
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_2_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_MASK    ((u32)0x00000070)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_LSB    4
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_1_WIDTH    ((u32)0x00000003)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_MASK    ((u32)0x00000007)
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_LSB    0
+#define RIU_RC_RF_LNA_LUT_RFLNALUT_0_WIDTH    ((u32)0x00000003)
+
+#define REG_IO_CTRL_BASE_ADDR 0x007C7000
+
+/*
+ * @brief RX_ACTIVE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000005C)
+#define IO_CTRL_RX_ACTIVE_0_OFFSET      0x0000005C
+#define IO_CTRL_RX_ACTIVE_0_INDEX       0x00000017
+#define IO_CTRL_RX_ACTIVE_0_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_RX_ACTIVE_0_GPIO_IN_BIT     ((u32)0x00002000)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_IN_POS     13
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OUT_BIT    ((u32)0x00001000)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OUT_POS    12
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OE_BIT     ((u32)0x00000800)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_OE_POS     11
+#define IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_BIT    ((u32)0x00000400)
+#define IO_CTRL_RX_ACTIVE_0_GPIO_ENABLE_POS    10
+#define IO_CTRL_RX_ACTIVE_0_INPUT_ENABLE_BIT    ((u32)0x00000200)
+#define IO_CTRL_RX_ACTIVE_0_INPUT_ENABLE_POS    9
+#define IO_CTRL_RX_ACTIVE_0_SLEW_RATE_BIT    ((u32)0x00000100)
+#define IO_CTRL_RX_ACTIVE_0_SLEW_RATE_POS    8
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_LSB    6
+#define IO_CTRL_RX_ACTIVE_0_DRIVER_PULL_STATE_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_MASK    ((u32)0x00000030)
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_LSB    4
+#define IO_CTRL_RX_ACTIVE_0_OUTPUT_PAD_STRENGTH_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_RX_ACTIVE_0_SCHMIT_TRIGER_BIT    ((u32)0x00000008)
+#define IO_CTRL_RX_ACTIVE_0_SCHMIT_TRIGER_POS    3
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_MASK    ((u32)0x00000007)
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_LSB    0
+#define IO_CTRL_RX_ACTIVE_0_MUX_SELECT_WIDTH    ((u32)0x00000003)
+
+static inline void io_ctrl_rx_active_0_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_0_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_0_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000060)
+#define IO_CTRL_RX_ACTIVE_1_OFFSET      0x00000060
+#define IO_CTRL_RX_ACTIVE_1_INDEX       0x00000018
+#define IO_CTRL_RX_ACTIVE_1_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_1_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_1_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_1_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_1_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000064)
+#define IO_CTRL_RX_ACTIVE_2_OFFSET      0x00000064
+#define IO_CTRL_RX_ACTIVE_2_INDEX       0x00000019
+#define IO_CTRL_RX_ACTIVE_2_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_2_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_2_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_2_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_2_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_2_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000068)
+#define IO_CTRL_RX_ACTIVE_3_OFFSET      0x00000068
+#define IO_CTRL_RX_ACTIVE_3_INDEX       0x0000001A
+#define IO_CTRL_RX_ACTIVE_3_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_3_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_3_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_3_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_3_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_3_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000006C)
+#define IO_CTRL_RX_ACTIVE_4_OFFSET      0x0000006C
+#define IO_CTRL_RX_ACTIVE_4_INDEX       0x0000001B
+#define IO_CTRL_RX_ACTIVE_4_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_4_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_4_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_4_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_4_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_4_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000070)
+#define IO_CTRL_RX_ACTIVE_5_OFFSET      0x00000070
+#define IO_CTRL_RX_ACTIVE_5_INDEX       0x0000001C
+#define IO_CTRL_RX_ACTIVE_5_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_5_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_5_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_5_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_5_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_5_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000074)
+#define IO_CTRL_RX_ACTIVE_6_OFFSET      0x00000074
+#define IO_CTRL_RX_ACTIVE_6_INDEX       0x0000001D
+#define IO_CTRL_RX_ACTIVE_6_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_6_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_6_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_6_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_6_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_6_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief RX_ACTIVE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   1
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x3
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_RX_ACTIVE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000078)
+#define IO_CTRL_RX_ACTIVE_7_OFFSET      0x00000078
+#define IO_CTRL_RX_ACTIVE_7_INDEX       0x0000001E
+#define IO_CTRL_RX_ACTIVE_7_RESET       0x000026D8
+
+static inline void io_ctrl_rx_active_7_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_7_ADDR, value);
+}
+
+static inline void io_ctrl_rx_active_7_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_RX_ACTIVE_7_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_RX_ACTIVE_7_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000007C)
+#define IO_CTRL_LNA_ENABLE_0_OFFSET      0x0000007C
+#define IO_CTRL_LNA_ENABLE_0_INDEX       0x0000001F
+#define IO_CTRL_LNA_ENABLE_0_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_LNA_ENABLE_0_GPIO_IN_BIT    ((u32)0x00002000)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_IN_POS    13
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OUT_BIT    ((u32)0x00001000)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OUT_POS    12
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OE_BIT    ((u32)0x00000800)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_OE_POS    11
+#define IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_BIT    ((u32)0x00000400)
+#define IO_CTRL_LNA_ENABLE_0_GPIO_ENABLE_POS    10
+#define IO_CTRL_LNA_ENABLE_0_INPUT_ENABLE_BIT    ((u32)0x00000200)
+#define IO_CTRL_LNA_ENABLE_0_INPUT_ENABLE_POS    9
+#define IO_CTRL_LNA_ENABLE_0_SLEW_RATE_BIT    ((u32)0x00000100)
+#define IO_CTRL_LNA_ENABLE_0_SLEW_RATE_POS    8
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_LSB    6
+#define IO_CTRL_LNA_ENABLE_0_DRIVER_PULL_STATE_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_MASK    ((u32)0x00000030)
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_LSB    4
+#define IO_CTRL_LNA_ENABLE_0_OUTPUT_PAD_STRENGTH_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_LNA_ENABLE_0_SCHMIT_TRIGER_BIT    ((u32)0x00000008)
+#define IO_CTRL_LNA_ENABLE_0_SCHMIT_TRIGER_POS    3
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_MASK    ((u32)0x00000007)
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_LSB    0
+#define IO_CTRL_LNA_ENABLE_0_MUX_SELECT_WIDTH    ((u32)0x00000003)
+
+static inline void io_ctrl_lna_enable_0_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_0_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_0_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000080)
+#define IO_CTRL_LNA_ENABLE_1_OFFSET      0x00000080
+#define IO_CTRL_LNA_ENABLE_1_INDEX       0x00000020
+#define IO_CTRL_LNA_ENABLE_1_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_1_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_1_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_1_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_1_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000084)
+#define IO_CTRL_LNA_ENABLE_2_OFFSET      0x00000084
+#define IO_CTRL_LNA_ENABLE_2_INDEX       0x00000021
+#define IO_CTRL_LNA_ENABLE_2_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_2_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_2_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_2_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_2_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_2_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000088)
+#define IO_CTRL_LNA_ENABLE_3_OFFSET      0x00000088
+#define IO_CTRL_LNA_ENABLE_3_INDEX       0x00000022
+#define IO_CTRL_LNA_ENABLE_3_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_3_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_3_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_3_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_3_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_3_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000008C)
+#define IO_CTRL_LNA_ENABLE_4_OFFSET      0x0000008C
+#define IO_CTRL_LNA_ENABLE_4_INDEX       0x00000023
+#define IO_CTRL_LNA_ENABLE_4_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_4_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_4_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_4_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_4_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_4_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000090)
+#define IO_CTRL_LNA_ENABLE_5_OFFSET      0x00000090
+#define IO_CTRL_LNA_ENABLE_5_INDEX       0x00000024
+#define IO_CTRL_LNA_ENABLE_5_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_5_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_5_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_5_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_5_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_5_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000094)
+#define IO_CTRL_LNA_ENABLE_6_OFFSET      0x00000094
+#define IO_CTRL_LNA_ENABLE_6_INDEX       0x00000025
+#define IO_CTRL_LNA_ENABLE_6_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_6_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_6_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_6_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_6_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_6_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000098)
+#define IO_CTRL_LNA_ENABLE_7_OFFSET      0x00000098
+#define IO_CTRL_LNA_ENABLE_7_INDEX       0x00000026
+#define IO_CTRL_LNA_ENABLE_7_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_7_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_7_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_7_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_7_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_7_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_8 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_8_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000009C)
+#define IO_CTRL_LNA_ENABLE_8_OFFSET      0x0000009C
+#define IO_CTRL_LNA_ENABLE_8_INDEX       0x00000027
+#define IO_CTRL_LNA_ENABLE_8_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_8_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_8_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_8_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_8_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_8_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_9 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_9_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A0)
+#define IO_CTRL_LNA_ENABLE_9_OFFSET      0x000000A0
+#define IO_CTRL_LNA_ENABLE_9_INDEX       0x00000028
+#define IO_CTRL_LNA_ENABLE_9_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_9_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_9_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_9_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_9_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_9_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_10 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_10_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A4)
+#define IO_CTRL_LNA_ENABLE_10_OFFSET      0x000000A4
+#define IO_CTRL_LNA_ENABLE_10_INDEX       0x00000029
+#define IO_CTRL_LNA_ENABLE_10_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_10_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_10_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_10_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_10_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_10_ADDR) &
+			   ~((u32)0x00000400)) | ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief LNA_ENABLE_11 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_LNA_ENABLE_11_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000A8)
+#define IO_CTRL_LNA_ENABLE_11_OFFSET      0x000000A8
+#define IO_CTRL_LNA_ENABLE_11_INDEX       0x0000002A
+#define IO_CTRL_LNA_ENABLE_11_RESET       0x00000698
+
+static inline void io_ctrl_lna_enable_11_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_11_ADDR, value);
+}
+
+static inline void io_ctrl_lna_enable_11_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_LNA_ENABLE_11_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_LNA_ENABLE_11_ADDR) &
+			   ~((u32)0x00000400)) | ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000AC)
+#define IO_CTRL_PA_ENABLE_0_OFFSET      0x000000AC
+#define IO_CTRL_PA_ENABLE_0_INDEX       0x0000002B
+#define IO_CTRL_PA_ENABLE_0_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_0_ADDR, value);
+}
+
+/* Field definitions */
+#define IO_CTRL_PA_ENABLE_0_GPIO_IN_BIT     ((u32)0x00002000)
+#define IO_CTRL_PA_ENABLE_0_GPIO_IN_POS     13
+#define IO_CTRL_PA_ENABLE_0_GPIO_OUT_BIT    ((u32)0x00001000)
+#define IO_CTRL_PA_ENABLE_0_GPIO_OUT_POS    12
+#define IO_CTRL_PA_ENABLE_0_GPIO_OE_BIT     ((u32)0x00000800)
+#define IO_CTRL_PA_ENABLE_0_GPIO_OE_POS     11
+#define IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_BIT    ((u32)0x00000400)
+#define IO_CTRL_PA_ENABLE_0_GPIO_ENABLE_POS    10
+#define IO_CTRL_PA_ENABLE_0_INPUT_ENABLE_BIT    ((u32)0x00000200)
+#define IO_CTRL_PA_ENABLE_0_INPUT_ENABLE_POS    9
+#define IO_CTRL_PA_ENABLE_0_SLEW_RATE_BIT    ((u32)0x00000100)
+#define IO_CTRL_PA_ENABLE_0_SLEW_RATE_POS    8
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_MASK    ((u32)0x000000C0)
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_LSB    6
+#define IO_CTRL_PA_ENABLE_0_DRIVER_PULL_STATE_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_MASK    ((u32)0x00000030)
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_LSB    4
+#define IO_CTRL_PA_ENABLE_0_OUTPUT_PAD_STRENGTH_WIDTH    ((u32)0x00000002)
+#define IO_CTRL_PA_ENABLE_0_SCHMIT_TRIGER_BIT    ((u32)0x00000008)
+#define IO_CTRL_PA_ENABLE_0_SCHMIT_TRIGER_POS    3
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_MASK    ((u32)0x00000007)
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_LSB    0
+#define IO_CTRL_PA_ENABLE_0_MUX_SELECT_WIDTH    ((u32)0x00000003)
+
+static inline void io_ctrl_pa_enable_0_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_0_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_0_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B0)
+#define IO_CTRL_PA_ENABLE_1_OFFSET      0x000000B0
+#define IO_CTRL_PA_ENABLE_1_INDEX       0x0000002C
+#define IO_CTRL_PA_ENABLE_1_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_1_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_1_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_1_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_1_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B4)
+#define IO_CTRL_PA_ENABLE_2_OFFSET      0x000000B4
+#define IO_CTRL_PA_ENABLE_2_INDEX       0x0000002D
+#define IO_CTRL_PA_ENABLE_2_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_2_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_2_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_2_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_2_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_2_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000B8)
+#define IO_CTRL_PA_ENABLE_3_OFFSET      0x000000B8
+#define IO_CTRL_PA_ENABLE_3_INDEX       0x0000002E
+#define IO_CTRL_PA_ENABLE_3_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_3_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_3_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_3_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_3_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_3_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000BC)
+#define IO_CTRL_PA_ENABLE_4_OFFSET      0x000000BC
+#define IO_CTRL_PA_ENABLE_4_INDEX       0x0000002F
+#define IO_CTRL_PA_ENABLE_4_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_4_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_4_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_4_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_4_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_4_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C0)
+#define IO_CTRL_PA_ENABLE_5_OFFSET      0x000000C0
+#define IO_CTRL_PA_ENABLE_5_INDEX       0x00000030
+#define IO_CTRL_PA_ENABLE_5_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_5_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_5_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_5_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_5_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_5_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C4)
+#define IO_CTRL_PA_ENABLE_6_OFFSET      0x000000C4
+#define IO_CTRL_PA_ENABLE_6_INDEX       0x00000031
+#define IO_CTRL_PA_ENABLE_6_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_6_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_6_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_6_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_6_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_6_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000C8)
+#define IO_CTRL_PA_ENABLE_7_OFFSET      0x000000C8
+#define IO_CTRL_PA_ENABLE_7_INDEX       0x00000032
+#define IO_CTRL_PA_ENABLE_7_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_7_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_7_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_7_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_7_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_7_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_8 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_8_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000CC)
+#define IO_CTRL_PA_ENABLE_8_OFFSET      0x000000CC
+#define IO_CTRL_PA_ENABLE_8_INDEX       0x00000033
+#define IO_CTRL_PA_ENABLE_8_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_8_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_8_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_8_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_8_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_8_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_9 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_9_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D0)
+#define IO_CTRL_PA_ENABLE_9_OFFSET      0x000000D0
+#define IO_CTRL_PA_ENABLE_9_INDEX       0x00000034
+#define IO_CTRL_PA_ENABLE_9_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_9_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_9_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_9_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_9_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_9_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_10 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_10_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D4)
+#define IO_CTRL_PA_ENABLE_10_OFFSET      0x000000D4
+#define IO_CTRL_PA_ENABLE_10_INDEX       0x00000035
+#define IO_CTRL_PA_ENABLE_10_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_10_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_10_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_10_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_10_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_10_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief PA_ENABLE_11 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               1
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 0
+ *   07:06 DRIVER_PULL_STATE         0x2
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_PA_ENABLE_11_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000D8)
+#define IO_CTRL_PA_ENABLE_11_OFFSET      0x000000D8
+#define IO_CTRL_PA_ENABLE_11_INDEX       0x00000036
+#define IO_CTRL_PA_ENABLE_11_RESET       0x00000698
+
+static inline void io_ctrl_pa_enable_11_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_11_ADDR, value);
+}
+
+static inline void io_ctrl_pa_enable_11_gpio_enable_setf(struct cl_chip *chip, u8 gpioenable)
+{
+	ASSERT_ERR_CHIP((((u32)gpioenable << 10) & ~((u32)0x00000400)) == 0);
+	cl_reg_write_chip(chip, IO_CTRL_PA_ENABLE_11_ADDR,
+			  (cl_reg_read_chip(chip, IO_CTRL_PA_ENABLE_11_ADDR) & ~((u32)0x00000400)) |
+			  ((u32)gpioenable << 10));
+}
+
+/*
+ * @brief SPICLK register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_SPICLK_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000DC)
+#define IO_CTRL_SPICLK_OFFSET      0x000000DC
+#define IO_CTRL_SPICLK_INDEX       0x00000037
+#define IO_CTRL_SPICLK_RESET       0x00000318
+
+static inline void io_ctrl_spiclk_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_SPICLK_ADDR, value);
+}
+
+/*
+ * @brief FWR_EN_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FWR_EN_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000F0)
+#define IO_CTRL_FWR_EN_1_OFFSET      0x000000F0
+#define IO_CTRL_FWR_EN_1_INDEX       0x0000003C
+#define IO_CTRL_FWR_EN_1_RESET       0x00000318
+
+static inline void io_ctrl_fwr_en_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FWR_EN_1_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_7 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_7_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000F8)
+#define IO_CTRL_FASTWR_7_OFFSET      0x000000F8
+#define IO_CTRL_FASTWR_7_INDEX       0x0000003E
+#define IO_CTRL_FASTWR_7_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_7_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_7_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_6 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_6_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x000000FC)
+#define IO_CTRL_FASTWR_6_OFFSET      0x000000FC
+#define IO_CTRL_FASTWR_6_INDEX       0x0000003F
+#define IO_CTRL_FASTWR_6_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_6_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_6_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_5 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_5_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000100)
+#define IO_CTRL_FASTWR_5_OFFSET      0x00000100
+#define IO_CTRL_FASTWR_5_INDEX       0x00000040
+#define IO_CTRL_FASTWR_5_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_5_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_5_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_4 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_4_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000104)
+#define IO_CTRL_FASTWR_4_OFFSET      0x00000104
+#define IO_CTRL_FASTWR_4_INDEX       0x00000041
+#define IO_CTRL_FASTWR_4_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_4_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_4_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_3 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_3_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000108)
+#define IO_CTRL_FASTWR_3_OFFSET      0x00000108
+#define IO_CTRL_FASTWR_3_INDEX       0x00000042
+#define IO_CTRL_FASTWR_3_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_3_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_3_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_2 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_2_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x0000010C)
+#define IO_CTRL_FASTWR_2_OFFSET      0x0000010C
+#define IO_CTRL_FASTWR_2_INDEX       0x00000043
+#define IO_CTRL_FASTWR_2_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_2_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_2_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_1 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_1_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000110)
+#define IO_CTRL_FASTWR_1_OFFSET      0x00000110
+#define IO_CTRL_FASTWR_1_INDEX       0x00000044
+#define IO_CTRL_FASTWR_1_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_1_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_1_ADDR, value);
+}
+
+/*
+ * @brief FASTWR_0 register definition
+ * <pre>
+ *  Bits           Field Name   Reset Value
+ * -----   ------------------   -----------
+ *   13    GPIO_IN                   0
+ *   12    GPIO_OUT                  0
+ *   11    GPIO_OE                   0
+ *   10    GPIO_ENABLE               0
+ *   09    input_enable              1
+ *   08    SLEW_RATE                 1
+ *   07:06 DRIVER_PULL_STATE         0x0
+ *   05:04 OUTPUT_PAD_STRENGTH       0x1
+ *   03    SCHMIT_TRIGER             1
+ *   02:00 MUX_SELECT                0x0
+ * </pre>
+ */
+#define IO_CTRL_FASTWR_0_ADDR        (REG_IO_CTRL_BASE_ADDR + 0x00000114)
+#define IO_CTRL_FASTWR_0_OFFSET      0x00000114
+#define IO_CTRL_FASTWR_0_INDEX       0x00000045
+#define IO_CTRL_FASTWR_0_RESET       0x00000318
+
+static inline void io_ctrl_fastwr_0_set(struct cl_chip *chip, u32 value)
+{
+	cl_reg_write_chip(chip, IO_CTRL_FASTWR_0_ADDR, value);
+}
+
+#endif /*CL_REG_DEFS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 66/96] cl8k: add rfic.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (64 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 65/96] cl8k: add reg/reg_defs.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
                   ` (29 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rfic.c | 232 ++++++++++++++++++++++++
 1 file changed, 232 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.c

diff --git a/drivers/net/wireless/celeno/cl8k/rfic.c b/drivers/net/wireless/celeno/cl8k/rfic.c
new file mode 100644
index 000000000000..5a3a595694b5
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rfic.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/namei.h>
+
+#include "reg/reg_defs.h"
+#include "phy.h"
+#include "utils.h"
+#include "rfic.h"
+
+#define PHY_DEV_NON_PHYSICAL 0x0
+#define MAX_LOOPS 15
+#define READ_REQ  1
+#define WRITE_REQ 0
+
+int cl_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val)
+{
+	struct mm_spi_read_cfm *cfm;
+	int ret = cl_msg_tx_spi_read(cl_hw, page, addr);
+
+	if (ret)
+		goto out;
+
+	cfm = (struct mm_spi_read_cfm *)(cl_hw->msg_cfm_params[MM_SPI_READ_CFM]);
+	if (!cfm) {
+		ret = -ENOMSG;
+		goto out;
+	}
+
+	if (cfm->status == 0) {
+		*val = cfm->val;
+	} else {
+		cl_dbg_err(cl_hw, "SPI read failed\n");
+		*val = 0;
+	}
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_SPI_READ_CFM);
+	return 0;
+
+out:
+	*val = 0;
+	return ret;
+}
+
+static int _cl_spi_driver_read(struct cl_hw *cl_hw, u8 more, u8 addr, u8 *val)
+{
+	u8 prescaler = 4;
+	int loops = MAX_LOOPS;
+
+	riu_rc_sw_ctrl_pack(cl_hw, 1, more, 0, 0, 1, 1, 1, 1, prescaler, READ_REQ, addr, 0xFF);
+	while (riu_rc_sw_ctrl_start_done_getf(cl_hw) && --loops)
+		;
+
+	if (!loops) {
+		cl_dbg_verbose(cl_hw, "Read error - addr [0x%02x]\n", addr);
+		return -EBADE;
+	}
+
+	*val = riu_rc_sw_ctrl_data_getf(cl_hw);
+
+	hwreg_pr(cl_hw, "more=%d, addr=0x%x, *val=0x%x\n", more, addr, *val);
+
+	return 0;
+}
+
+static int _cl_spi_driver_write(struct cl_hw *cl_hw, u8 more, u8 addr, u8 val)
+{
+	u8 prescaler =  4;
+	int loops = MAX_LOOPS;
+
+	hwreg_pr(cl_hw, "more=%d, addr=0x%x, val=0x%x\n", more, addr, val);
+
+	riu_rc_sw_ctrl_pack(cl_hw, 1, more, 0, 0, 1, 1, 1, 1, prescaler, WRITE_REQ, addr, val);
+
+	while (riu_rc_sw_ctrl_start_done_getf(cl_hw) && --loops)
+		;
+
+	if (!loops) {
+		cl_dbg_verbose(cl_hw, "Write error - addr [0x%02x] val [0x%02x]\n", addr, val);
+		return -EBADE;
+	}
+
+	return 0;
+}
+
+int cl_spi_driver_read_byte(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val)
+{
+	/* cl_spi_driver_read_byte should only be used when mac fw not loaded,
+	 * else use cl_spi_read
+	 */
+	int ret = 0;
+
+	spin_lock_bh(&cl_hw->chip->isr_lock);
+
+	ret = _cl_spi_driver_write(cl_hw, 1, 0x03, page);
+	if (ret)
+		goto read_exit;
+
+	ret = _cl_spi_driver_read(cl_hw, 0, addr, val);
+	if (ret)
+		goto read_exit;
+
+read_exit:
+	spin_unlock_bh(&cl_hw->chip->isr_lock);
+
+	return ret;
+}
+
+static u8 cl_rfic_str_to_cmd(struct cl_hw *cl_hw, char *str)
+{
+	if (!strcmp(str, "DONE"))
+		return OVERWRITE_DONE;
+	else if (!strcmp(str, "SPI_R"))
+		return SPI_RD_CMD;
+	else if (!strcmp(str, "SPI_W"))
+		return SPI_WR_CMD;
+	else if (!strcmp(str, "GCU_W"))
+		return GCU_WR_CMD;
+	else if (!strcmp(str, "RIU_W"))
+		return RIU_WR_CMD;
+	else if (!strcmp(str, "GEN_W"))
+		return GEN_WR_CMD;
+	else if (!strcmp(str, "DELAY"))
+		return UDELAY_CMD;
+
+	cl_dbg_err(cl_hw, "unknown command %s\n", str);
+	return OVERWRITE_DONE;
+}
+
+static void cl_parse_rf_command(struct cl_hw *cl_hw, char *str,
+				struct cl_rf_reg_overwrite_info *info)
+{
+	int i = 0;
+	char *ptr = NULL;
+	u32 res = 0;
+
+	while ((ptr = strsep(&str, " ")) && (*ptr != '\n')) {
+		if (i == 0) {
+			info->cmd = cl_rfic_str_to_cmd(cl_hw, ptr);
+		} else {
+			if (kstrtou32(ptr, 16, &res) != 0) {
+				pr_err("%s: invalid data - %s\n", __func__, ptr);
+				return;
+			}
+
+			info->data[i - 1] = cpu_to_le32(res);
+			res = 0;
+		}
+		i++;
+	}
+}
+
+#define RF_CMD_MAX_LEN 64
+
+static void cl_parse_rf_commands_from_buf(struct cl_hw *cl_hw, char *buf, loff_t size,
+					  struct cl_rf_reg_overwrite_info *info)
+{
+	int i = 0;
+	char *line = buf;
+	char str[RF_CMD_MAX_LEN];
+	char *end;
+	int line_length = 0;
+
+	while (line && (line != (buf + size))) {
+		if ((*line == '#') || (*line == '\n')) {
+			/* Skip comment or blank line */
+			line = strstr(line, "\n") + 1;
+		} else if (*line) {
+			end = strstr(line, "\n") + 1;
+			line_length = end - line;
+
+			if (line_length >= RF_CMD_MAX_LEN) {
+				cl_dbg_err(cl_hw, "Command too long (%u)\n", line_length);
+				return;
+			}
+
+			snprintf(str, line_length, "%s", line);
+			cl_parse_rf_command(cl_hw, str, &info[i++]);
+			line += line_length;
+		}
+	}
+}
+
+int cl_rfic_read_overwrite_file(struct cl_hw *cl_hw, struct cl_rf_reg_overwrite_info *info,
+				bool init)
+{
+	char *buf = NULL;
+	size_t size = 0;
+	char filename[CL_FILENAME_MAX] = {0};
+	char path_name[CL_PATH_MAX] = {0};
+	struct path path;
+
+	if (init)
+		snprintf(filename, sizeof(filename), "rf_init_overwrite.txt");
+	else
+		snprintf(filename, sizeof(filename), "rf_tcv%d_overwrite.txt", cl_hw->tcv_idx);
+
+	snprintf(path_name, sizeof(path_name), "/lib/firmware/cl8k/%s", filename);
+	if (kern_path(path_name, LOOKUP_FOLLOW, &path) < 0)
+		return 0;
+
+	size = cl_file_open_and_read(cl_hw->chip, filename, &buf);
+
+	if (!buf)
+		return 0;
+
+	cl_dbg_trace(cl_hw, "parsing %s !!!\n", filename);
+	cl_parse_rf_commands_from_buf(cl_hw, buf, size, info);
+	kfree(buf);
+	return 0;
+}
+
+static u8 cl_rfic_version(struct cl_hw *cl_hw)
+{
+	u8 value = 0xff;
+	int ret = cl_spi_driver_read_byte(cl_hw, 0, 0, &value);
+
+	if (ret < 0)
+		cl_dbg_err(cl_hw, "%s: spi read failed", __func__);
+
+	return value;
+}
+
+void cl_chip_set_rfic_version(struct cl_hw *cl_hw)
+{	/* Read version only on a physical phy */
+	if (cl_hw->chip->conf->ci_phy_dev == PHY_DEV_ATHOS ||
+	    cl_hw->chip->conf->ci_phy_dev == PHY_DEV_OLYMPUS)	{
+		cl_hw->chip->rfic_version = cl_rfic_version(cl_hw);
+	} else {
+		cl_hw->chip->rfic_version = PHY_DEV_NON_PHYSICAL;
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 67/96] cl8k: add rfic.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (65 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 66/96] cl8k: add rfic.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-06-02 20:40   ` Jeff Johnson
  2022-05-24 11:34 ` [RFC v2 68/96] cl8k: add rx.c viktor.barna
                   ` (28 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rfic.h | 29 +++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.h

diff --git a/drivers/net/wireless/celeno/cl8k/rfic.h b/drivers/net/wireless/celeno/cl8k/rfic.h
new file mode 100644
index 000000000000..686ebd6fcd98
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rfic.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_RFIC_H
+#define CL_RFIC_H
+
+#include "hw.h"
+
+#define ATHOS_A_VER    0xB1
+#define ATHOS_B_VER    0xB2
+
+enum cl_rf_overwrite_cmd {
+	OVERWRITE_DONE,
+	SPI_RD_CMD,
+	SPI_WR_CMD,
+	GCU_WR_CMD,
+	RIU_WR_CMD,
+	UDELAY_CMD,
+	GEN_WR_CMD,
+	RF_OVERWRITE_CMD_MAX = OVERWRITE_DONE
+};
+
+int cl_spi_driver_read_byte(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val);
+int cl_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val);
+int cl_rfic_read_overwrite_file(struct cl_hw *cl_hw,
+				struct cl_rf_reg_overwrite_info *info,
+				bool init);
+void cl_chip_set_rfic_version(struct cl_hw *cl_hw);
+#endif /* CL_RFIC_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 68/96] cl8k: add rx.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (66 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 69/96] cl8k: add rx.h viktor.barna
                   ` (27 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rx.c | 1845 +++++++++++++++++++++++++
 1 file changed, 1845 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx.c

diff --git a/drivers/net/wireless/celeno/cl8k/rx.c b/drivers/net/wireless/celeno/cl8k/rx.c
new file mode 100644
index 000000000000..b10c9b80fc06
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx.c
@@ -0,0 +1,1845 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/skbuff.h>
+#include <net/mac80211.h>
+
+#include "tx.h"
+#include "stats.h"
+#include "rates.h"
+#include "vns.h"
+#include "dfs.h"
+#include "recovery.h"
+#include "def.h"
+#include "mac80211.h"
+#include "reg/reg_defs.h"
+#include "key.h"
+#include "utils.h"
+#include "radio.h"
+#include "vif.h"
+#include "rx.h"
+
+/* Must correspond to FW definition of MM_SEC_DEFAULT_KEY_COUNT */
+#define MM_SEC_DEFAULT_KEY_COUNT 64
+
+#define VHT_MCS_MASK 0x0F
+#define VHT_MCS_OFT  0
+
+/* Number of entries in HW legacy rate conversion table */
+#define LEGACY_RATE_MAX 16
+#define KSR_MGTK_BCAST_OFFSET 31
+#define KSR_BLOCK_SIZE 4
+
+static const s8 legacy_rates_lut[LEGACY_RATE_MAX] = {
+	0,      /* 0: 1 Mbps   */
+	1,      /* 1: 2 Mbps   */
+	2,      /* 2: 5.5 Mbps */
+	3,      /* 3: 11 Mbps  */
+	-1,     /* 4: Invalid  */
+	-1,     /* 5: Invalid  */
+	-1,     /* 6: Invalid  */
+	-1,     /* 7: Invalid  */
+	10,     /* 8: 48 Mbps  */
+	8,      /* 9: 24 Mbps  */
+	6,      /* 10: 12 Mbps */
+	4,      /* 11: 6 Mbps  */
+	11,     /* 12: 54 Mbps */
+	9,      /* 13: 36 Mbps */
+	7,      /* 14: 18 Mbps */
+	5       /* 15: 9 Mbps  */
+};
+
+/*
+ * rx_skb_cnt is an atomic counter that tracks the total number of skbs in
+ * the entire host.
+ * The counter is incremented when skb is allocated, and freed when the skb
+ * is freed (=destructor function called).
+ * Therefore the counter is global (and not part of cl_hw or cl_chip).
+ *
+ * rx_skb_max is the configured to:
+ * max(chip0->conf->ci_rx_skb_max, chip1->conf->ci_rx_skb_max)
+ */
+static atomic_t rx_skb_cnt = ATOMIC_INIT(0);
+static u32 rx_skb_max;
+
+static void cl_rx_skb_destructor(struct sk_buff *skb)
+{
+	atomic_dec(&rx_skb_cnt);
+}
+
+static void cl_rx_skb_success(struct cl_vif *cl_vif, struct ieee80211_hdr *hdr,
+			      u32 rx_packets, u32 rx_bytes)
+{
+	if (cl_vif) {
+		u8 ac = cl_rx_get_skb_ac(hdr);
+
+		cl_vif->trfc_cntrs[ac].rx_packets += rx_packets;
+		cl_vif->trfc_cntrs[ac].rx_bytes += rx_bytes;
+	}
+}
+
+static DEFINE_PER_CPU(struct tasklet_struct, rx_remote_tasklet_mac[TCV_TOTAL]);
+
+static call_single_data_t csd_rx_remote_cpu_mac[TCV_TOTAL];
+static void cl_rx_remote_cpu_mac(struct cl_hw *cl_hw)
+{
+	int cpu = cl_hw->conf->ci_rx_remote_cpu_mac;
+	struct tasklet_struct *t = csd_rx_remote_cpu_mac[cl_hw->idx].info;
+
+	if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+		smp_call_function_single_async(cpu, &csd_rx_remote_cpu_mac[cl_hw->idx]);
+}
+
+static int cl_rx_check_err(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr)
+{
+	u32 status;
+
+	if (rxhdr->frm_successful_rx)
+		return 0;
+
+	/* The status field is in offset of 14 u32's */
+	status = *((u32 *)rxhdr + 14);
+
+	/* Ignore phy errors and do not drop the packet */
+	if (rxhdr->phy_err) {
+		cl_hw->radio_stats[CL_RADIO_PHY_ERROR]++;
+		cl_dbg_warn(cl_hw, "phy_err (status 0x%x)\n", status);
+		return 0;
+	}
+
+	/* From this point and on, drop the erroneous packets */
+	if (rxhdr->fcs_err) {
+		cl_hw->radio_stats[CL_RADIO_FCS_ERROR]++;
+		cl_dbg_err(cl_hw, "fcs_err (status 0x%x)\n", status);
+	}
+
+	if (rxhdr->rx_fifo_oflow) {
+		cl_hw->radio_stats[CL_RADIO_RX_FIFO_OVERFLOW]++;
+		cl_dbg_err(cl_hw, "rx_fifo_oflow (status 0x%x)\n", status);
+	}
+
+	if (rxhdr->undef_err) {
+		cl_hw->radio_stats[CL_RADIO_UNDEFINED_ERROR]++;
+		cl_dbg_err(cl_hw, "undef_err (status 0x%x)\n", status);
+	}
+
+	if (rxhdr->addr_mismatch) {
+		cl_hw->radio_stats[CL_RADIO_ADDRESS_MISMATCH]++;
+		cl_dbg_err(cl_hw, "addr_mismatch (status 0x%x)\n", status);
+	}
+
+	if (rxhdr->amsdu_present && rxhdr->msdu_cnt > 1)
+		cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_NOT_SUCCESS);
+
+	cl_hw->rx_info.pkt_drop_not_success++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+
+	return -EBADMSG;
+}
+
+static u8 chnl_bw_to_rate_info_bw[CHNL_BW_MAX] = {
+	[CHNL_BW_20] = RATE_INFO_BW_20,
+	[CHNL_BW_40] = RATE_INFO_BW_40,
+	[CHNL_BW_80] = RATE_INFO_BW_80,
+	[CHNL_BW_160] = RATE_INFO_BW_160,
+};
+
+static u8 chnl_bw_factor[CHNL_BW_MAX] = {
+	[CHNL_BW_20] = 0,
+	[CHNL_BW_40] = 3,
+	[CHNL_BW_80] = 6,
+	[CHNL_BW_160] = 9,
+};
+
+static int cl_rx_fill_status(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb,
+			     struct hw_rxhdr *rxhdr, u8 *encrypt_len)
+{
+	s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	u8 tid = ieee80211_get_tid(hdr);
+
+	memset(status, 0, sizeof(struct ieee80211_rx_status));
+
+	status->mactime = ((u64)le32_to_cpu((rxhdr->tsf_hi)) << 32) | le32_to_cpu(rxhdr->tsf_lo);
+	status->flag |= RX_FLAG_MACTIME_END;
+
+	if (cl_sta && cl_sta->tid_agg_rx[tid])
+		status->flag |= RX_FLAG_DUP_VALIDATED;
+
+	status->antenna = rxhdr->antenna_set;
+	status->band = cl_band_from_fw_idx(rxhdr->phy_band);
+
+	if (rxhdr->format_mod >= FORMATMOD_HE_SU) {
+		status->encoding = RX_ENC_HE;
+		status->rate_idx = (rxhdr->mcs & VHT_MCS_MASK) >> VHT_MCS_OFT;
+		status->nss = rxhdr->n_sts + 1;
+
+		/* he_gi expectes to get values according to enum nl80211_he_gi */
+		status->he_gi = cl_convert_gi_format_wrs_to_fw(WRS_MODE_HE, rxhdr->gi_type);
+	} else if (rxhdr->format_mod == FORMATMOD_VHT) {
+		status->encoding = RX_ENC_VHT;
+		status->rate_idx = (rxhdr->mcs & VHT_MCS_MASK) >> VHT_MCS_OFT;
+		status->nss = rxhdr->n_sts + 1;
+
+		if (rxhdr->gi_type)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+	} else if (rxhdr->format_mod == FORMATMOD_HT_GF) {
+		status->encoding = RX_ENC_HT;
+		status->enc_flags |= RX_ENC_FLAG_HT_GF;
+		status->rate_idx = rxhdr->mcs;
+
+		if (rxhdr->gi_type)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+	} else if (rxhdr->format_mod == FORMATMOD_HT_MF) {
+		status->encoding = RX_ENC_HT;
+		status->rate_idx = rxhdr->mcs;
+
+		if (rxhdr->gi_type)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+	} else {
+		if (legacy_rates_lut[rxhdr->leg_rate] != -1)
+			status->rate_idx = legacy_rates_lut[rxhdr->leg_rate];
+		if (status->band != NL80211_BAND_2GHZ)
+			status->rate_idx -= RATE_CTRL_OFFSET_OFDM;
+		if (!rxhdr->pre_type)
+			status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
+	}
+
+	if (rxhdr->aggregation) {
+		status->flag |= RX_FLAG_AMPDU_DETAILS;
+		status->ampdu_reference = rxhdr->ampdu_cnt;
+	}
+
+	/*
+	 * Set bw field
+	 */
+	if (rxhdr->ru_type) {
+		status->bw = RATE_INFO_BW_HE_RU;
+
+		if (rxhdr->ru_type == CL_MU_OFDMA_RU_TYPE_26)
+			cl_rssi_bw_adjust(cl_hw, rxhdr, -9);
+		else if (rxhdr->ru_type == CL_MU_OFDMA_RU_TYPE_52)
+			cl_rssi_bw_adjust(cl_hw, rxhdr, -6);
+		else if (rxhdr->ru_type == CL_MU_OFDMA_RU_TYPE_106)
+			cl_rssi_bw_adjust(cl_hw, rxhdr, -3);
+
+		status->he_ru = cl_ru_type_to_nl80211_he_ru_alloc(rxhdr->ru_type);
+	} else {
+		u8 factor = chnl_bw_factor[rxhdr->ch_bw];
+
+		status->bw = chnl_bw_to_rate_info_bw[rxhdr->ch_bw];
+		cl_rssi_bw_adjust(cl_hw, rxhdr, factor);
+	}
+
+	/*
+	 * TODO: check if when a frame is received on 40MHz or more bandwidth,
+	 * we need to take the center1_freq instead of the prim20_freq
+	 */
+	status->freq = Q2_TO_FREQ(rxhdr->phy_prim20_freq);
+
+	status->signal = cl_rssi_calc_equivalent(cl_hw, rssi);
+
+	switch (rxhdr->decr_status) {
+	case CL_RX_HDR_DECR_UNENC:
+		if (!ieee80211_has_protected(hdr->frame_control))
+			break;
+
+		cl_dbg_warn(cl_hw, "Protected frame unencrypted\n");
+		cl_hw->rx_info.pkt_drop_unencrypted++;
+		if (rxhdr->amsdu_present && rxhdr->msdu_cnt > 1)
+			cl_rx_amsdu_set_state_error(cl_hw, rxhdr,
+						    RX_AMSDU_ERR_UNENCRYPTED);
+		return -EBADMSG;
+	case CL_RX_HDR_DECR_ICVFAIL:
+	case CL_RX_HDR_DECR_AMSDUDISCARD:
+	case CL_RX_HDR_DECR_NULLKEY:
+	case CL_RX_HDR_DECR_CCMPFAIL:
+		cl_dbg_warn(cl_hw, "Decryption failed (%u)\n", rxhdr->decr_status);
+		cl_hw->rx_info.pkt_drop_decrypt_fail++;
+		*encrypt_len = 0;
+		if (rxhdr->amsdu_present && rxhdr->msdu_cnt > 1)
+			cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_DECRYPT_FAIL);
+		return -EBADMSG;
+	case CL_RX_HDR_DECR_WEPSUCCESS:
+	case CL_RX_HDR_DECR_TKIPSUCCESS:
+		*encrypt_len = IEEE80211_WEP_ICV_LEN;
+		status->flag |= (RX_FLAG_DECRYPTED | RX_FLAG_ICV_STRIPPED);
+		break;
+	case CL_RX_HDR_DECR_CCMPSUCCESS:
+		*encrypt_len = IEEE80211_CCMP_HDR_LEN;
+		status->flag |= (RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED);
+		break;
+	}
+
+	return 0;
+}
+
+static void cl_rx_handle_mesh_reconnect(struct cl_hw *cl_hw,
+					struct ieee80211_mgmt *mgmt, struct cl_sta *cl_sta)
+{
+	struct ieee80211_sta *sta = cl_sta->sta;
+	struct cl_tx_queue *tx_queue;
+	u8 action_code = mgmt->u.action.u.self_prot.action_code;
+	u8 i;
+
+	if (action_code == WLAN_SP_MESH_PEERING_CONFIRM) {
+		for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+			tx_queue = cl_sta->agg_tx_queues[i];
+
+			if (tx_queue)
+				ieee80211_stop_tx_ba_session(sta, i);
+		}
+	}
+}
+
+static void cl_rx_action_frame_handler(struct cl_hw *cl_hw, struct cl_ieee80211_mgmt *mgmt,
+				       int len, struct cl_sta *cl_sta)
+{
+	/* Verify action code is present */
+	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+		return;
+
+	switch (mgmt->u.action.category) {
+	case WLAN_CATEGORY_WNM:
+		break;
+	case WLAN_CATEGORY_SELF_PROTECTED:
+		if (cl_sta && cl_sta->cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT)
+			cl_rx_handle_mesh_reconnect(cl_hw, (struct ieee80211_mgmt *)mgmt, cl_sta);
+		break;
+	default:
+		break;
+	}
+}
+
+static struct ieee80211_he_6ghz_oper *
+cl_rx_get_he_6ghz_oper(const struct ieee80211_he_operation *he_oper)
+{
+	const u8 *ret = (void *)&he_oper->optional;
+	u32 he_oper_params;
+
+	he_oper_params = le32_to_cpu(he_oper->he_oper_params);
+
+	if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO))
+		return NULL;
+	if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
+		ret += 3;
+	if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
+		ret++;
+
+	return (void *)ret;
+}
+
+static void
+cl_rx_check_he_minrate_change(struct cl_sta *cl_sta,
+			      const struct ieee80211_he_operation *he_oper)
+{
+	struct ieee80211_he_6ghz_oper *
+		he_6ghz_oper = cl_rx_get_he_6ghz_oper(he_oper);
+
+	if (!he_6ghz_oper)
+		return;
+
+	if (he_6ghz_oper->minrate != cl_sta->wrs_sta.he_minrate)
+		cl_wrs_api_he_minrate_changed(cl_sta, he_6ghz_oper->minrate);
+}
+
+static void cl_rx_handle_beacon(struct cl_hw *cl_hw,
+				struct sk_buff *skb,
+				struct cl_sta *cl_sta)
+{
+	struct ieee802_11_elems elems;
+	struct cl_vif *cl_vif = cl_sta->cl_vif;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+	size_t baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+	struct ieee80211_bss_conf *bss_conf = &cl_vif->vif->bss_conf;
+
+	if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+		return;
+
+	cl_ieee802_11_parse_elems(mgmt->u.beacon.variable, skb->len - baselen, &elems);
+
+	if (!elems.parse_error && elems.he_operation && bss_conf->he_support)
+		cl_rx_check_he_minrate_change(cl_sta, elems.he_operation);
+}
+
+static bool cl_rx_mgmt_check(struct cl_hw *cl_hw, struct sk_buff *skb,
+			     struct cl_vif *cl_vif, struct cl_sta *cl_sta,
+			     struct hw_rxhdr *rxhdr)
+{
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+	__le16 fc = mgmt->frame_control;
+
+	if (!ieee80211_is_mgmt(fc))
+		return true;
+
+	if (cl_sta) {
+		if (ieee80211_is_beacon(fc))
+			cl_rx_handle_beacon(cl_hw, skb, cl_sta);
+		else if (ieee80211_is_action(fc))
+			cl_rx_action_frame_handler(cl_hw, (struct cl_ieee80211_mgmt *)mgmt,
+						   skb->len, cl_sta);
+	} else {
+		s8 rssi[MAX_ANTENNAS] = RX_HDR_RSSI(rxhdr);
+
+		cl_vns_mgmt_handler(cl_hw, mgmt->sa, rssi);
+
+		if (ieee80211_is_assoc_req(fc) || ieee80211_is_assoc_resp(fc)) {
+			cl_rssi_assoc_handle(cl_hw, mgmt->sa, rxhdr);
+			return true;
+		}
+	}
+
+	return true;
+}
+
+static void cl_rx_data_check(struct cl_hw *cl_hw, struct sk_buff *skb,
+			     struct cl_sta *cl_sta, u32 packet_len, struct hw_rxhdr *rxhdr)
+{
+	if (cl_sta) {
+		cl_traffic_rx_handler(cl_hw, cl_sta, packet_len);
+
+		if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+			cl_motion_sense_rssi_data(cl_hw, cl_sta, rxhdr);
+	}
+}
+
+static bool cl_rx_skb_done(struct cl_hw *cl_hw, struct sk_buff *skb,
+			   struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
+	struct cl_vif *cl_vif = NULL;
+
+	/* Update trigger base statistics */
+	cl_fw_dbg_trigger_based_update(cl_hw, rxhdr, hdr);
+	cl_fw_dbg_trigger_based_sta_update(cl_hw, rxhdr, hdr);
+
+	if (cl_sta) {
+		cl_vif = cl_sta->cl_vif;
+		skb->dev = cl_vif->dev;
+
+		cl_stats_update_rx_rate(cl_hw, cl_sta, rxhdr);
+
+		if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+			cl_rssi_rx_handler(cl_hw, cl_sta, rxhdr, status->signal);
+	} else {
+		cl_vif = cl_vif_get_by_mac(cl_hw, hdr->addr3);
+		skb->dev = cl_vif ? cl_vif->dev : NULL;
+
+		if (cl_hw_is_prod_or_listener(cl_hw))
+			cl_stats_update_rx_rate_production(cl_hw, rxhdr);
+	}
+
+	/* DATA */
+	if (ieee80211_is_data(fc)) {
+		cl_wrs_update_rx_rate(cl_hw, cl_sta, rxhdr);
+		cl_rx_data_check(cl_hw, skb, cl_sta, skb->len, rxhdr);
+		goto out;
+	}
+
+	/* MGMT/CTL */
+	if (cl_sta)
+		cl_motion_sense_rssi_mgmt_ctl(cl_hw, cl_sta, rxhdr);
+
+	/* MGMT */
+	if (!cl_rx_mgmt_check(cl_hw, skb, cl_vif, cl_sta, rxhdr))
+		return false;
+
+out:
+	if (rx_skb_max &&
+	    atomic_read(&rx_skb_cnt) >= rx_skb_max) {
+		cl_hw->rx_info.pkt_drop_host_limit++;
+		cl_rx_skb_drop(cl_hw, skb, 1);
+		kfree_skb(skb);
+		return false;
+	}
+
+	cl_rx_skb_success(cl_vif, hdr, 1, skb->len);
+
+	return true;
+}
+
+static void cl_rx_pass_to_mac(struct cl_hw *cl_hw,
+			      struct ieee80211_sta *sta,
+			      struct sk_buff_head *frames)
+{
+	if (cl_hw->conf->ci_rx_remote_cpu_mac == -1) {
+		struct sk_buff *skb = NULL;
+
+		while ((skb = __skb_dequeue(frames)))
+			ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+	} else {
+		struct sk_buff_head *rx_remote_queue_mac = &cl_hw->rx_remote_queue_mac;
+
+		spin_lock(&rx_remote_queue_mac->lock);
+		skb_queue_splice_tail_init(frames, rx_remote_queue_mac);
+		spin_unlock(&rx_remote_queue_mac->lock);
+
+		cl_rx_remote_cpu_mac(cl_hw);
+	}
+}
+
+static void cl_rx_amsdu_done_reorder(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				     struct sk_buff_head *frames)
+{
+	struct sk_buff *skb = NULL;
+	struct sk_buff_head reorder_buf;
+
+	/* Init the reorder buffer */
+	__skb_queue_head_init(&reorder_buf);
+
+	while ((skb = __skb_dequeue(frames)))
+		cl_rx_reorder_ampdu(cl_hw, cl_sta, skb, &reorder_buf);
+
+	if (!skb_queue_empty(&reorder_buf))
+		cl_rx_pass_to_mac(cl_hw, cl_sta->sta, &reorder_buf);
+}
+
+static void cl_rx_amsdu_done(struct cl_hw *cl_hw, struct cl_amsdu_rx_state *amsdu_rx_state)
+{
+	struct sk_buff_head *frames = &amsdu_rx_state->frames;
+	struct sk_buff *skb = __skb_peek(frames);
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct cl_sta *cl_sta;
+	struct cl_vif *cl_vif;
+	struct hw_rxhdr *rxhdr = amsdu_rx_state->rxhdr;
+	u32 packet_len = amsdu_rx_state->packet_len;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_sta *sta;
+
+	if (cl_rx_amsdu_check_aggregation_attack(amsdu_rx_state)) {
+		cl_hw->rx_info.pkt_drop_amsdu_inj_attack += amsdu_rx_state->msdu_cnt;
+		__skb_queue_purge(frames);
+		return;
+	}
+
+	/* START - cl_sta protected block */
+	cl_sta_lock(cl_hw);
+	cl_sta = cl_sta_get(cl_hw, amsdu_rx_state->sta_idx);
+
+	if (!cl_sta) {
+		cl_sta_unlock(cl_hw);
+		cl_hw->rx_info.pkt_drop_sta_null += amsdu_rx_state->msdu_cnt;
+		__skb_queue_purge(frames);
+		return;
+	}
+
+	sta = cl_sta->sta;
+	cl_vif = cl_sta->cl_vif;
+	skb->dev = cl_vif->dev;
+
+	cl_rx_data_check(cl_hw, skb, cl_sta, packet_len, rxhdr);
+	cl_stats_update_rx_rate(cl_hw, cl_sta, rxhdr);
+	cl_wrs_update_rx_rate(cl_hw, cl_sta, rxhdr);
+
+	if (!rxhdr->aggregation || (rxhdr->aggregation && rxhdr->mpdu_cnt == 0))
+		cl_rssi_rx_handler(cl_hw, cl_sta, rxhdr, status->signal);
+
+	cl_sta_unlock(cl_hw);
+	/* END - cl_sta protected block */
+
+	if (rx_skb_max &&
+	    (atomic_read(&rx_skb_cnt) + amsdu_rx_state->msdu_cnt) >= rx_skb_max) {
+		cl_hw->rx_info.pkt_drop_host_limit += amsdu_rx_state->msdu_cnt;
+		cl_rx_skb_drop(cl_hw, skb, amsdu_rx_state->msdu_cnt);
+		__skb_queue_purge(frames);
+		return;
+	}
+
+	cl_rx_skb_success(cl_vif, hdr, rxhdr->msdu_cnt, packet_len);
+
+	if (cl_sta->tid_agg_rx[amsdu_rx_state->tid])
+		cl_rx_amsdu_done_reorder(cl_hw, cl_sta, frames);
+	else
+		cl_rx_pass_to_mac(cl_hw, sta, frames);
+}
+
+static void cl_rx_invalid_tailroom(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr,
+				   struct sk_buff *skb, u32 len)
+{
+	cl_dbg_err(cl_hw, "Invalid RX header length - tailroom=%d, len=%u\n",
+		   skb_tailroom(skb), len);
+
+	if (rxhdr->amsdu_present && rxhdr->msdu_cnt > 1)
+		cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_INVALID_TAILROOM);
+
+	cl_hw->rx_info.pkt_drop_tailroom_error++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+static void cl_rx_invalid_pattern(struct cl_hw *cl_hw, struct sk_buff *skb, u32 pattern)
+{
+	cl_dbg_err(cl_hw, "WRONG PATTERN - 0x%x\n", pattern);
+	cl_hw->rx_info.pkt_drop_wrong_pattern++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+static int cl_rx_get_sta_idx(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+	int sta_idx = rxhdr->key_sram_index - MM_SEC_DEFAULT_KEY_COUNT;
+	u8 vif_type;
+
+	if (sta_idx < 0) {
+		vif_type = cl_hw_get_iface_conf(cl_hw);
+		if (vif_type ==  CL_IFCONF_MESH_AP || vif_type == CL_IFCONF_MESH_ONLY) {
+			sta_idx += KSR_MGTK_BCAST_OFFSET;
+			sta_idx /= KSR_BLOCK_SIZE;
+		}
+	}
+
+	if (sta_idx >= 0 && sta_idx < CL_MAX_NUM_STA)
+		return sta_idx;
+
+	cl_dbg_err(cl_hw, "invalid sta_idx %d, key_sram_index=%d\n",
+		   sta_idx, rxhdr->key_sram_index);
+
+	return -EINVAL;
+}
+
+static void cl_rx_handle_first_amsdu(struct cl_hw *cl_hw, struct sk_buff *skb,
+				     struct cl_amsdu_rx_state *amsdu_rx_state,
+				     struct hw_rxhdr *rxhdr, u8 sta_idx, u8 tid, u8 encrypt_len)
+{
+	/*
+	 * First MSDU recived frame:
+	 * ------------------------------------------
+	 * || WLAN_HDR || MSDU HDR || MSDU PAYLOAD ||
+	 * ------------------------------------------
+	 */
+	cl_rx_amsdu_stats(cl_hw, rxhdr->msdu_cnt);
+
+	if (rxhdr->corrupted_amsdu) {
+		cl_rx_amsdu_first_corrupted(cl_hw, skb, rxhdr);
+	} else {
+		cl_rx_amsdu_first(cl_hw, skb, rxhdr, sta_idx, tid, encrypt_len);
+
+		/* If there are more MSDU's, hold on with the update
+		 * to the upper layer until A-MSDU is complete
+		 */
+		if (amsdu_rx_state->msdu_remaining_cnt == 0)
+			cl_rx_amsdu_done(cl_hw, amsdu_rx_state);
+	}
+}
+
+static void cl_rx_handle_sub_amsdu(struct cl_hw *cl_hw, struct sk_buff *skb,
+				   struct cl_amsdu_rx_state *amsdu_rx_state)
+{
+	/* Update the remaining MSDU counter */
+	amsdu_rx_state->msdu_remaining_cnt--;
+
+	/* Free MSDU with error */
+	if (amsdu_rx_state->amsdu_error) {
+		cl_rx_amsdu_sub_error(cl_hw, skb);
+		return;
+	}
+
+	/* Add the sub-MSDU to the existing ones */
+	if (!cl_rx_amsdu_sub(cl_hw, skb))
+		return;
+
+	/* This is the last MSDU, A-MSDU is complete, push to upper layer */
+	if (amsdu_rx_state->msdu_remaining_cnt == 0)
+		cl_rx_amsdu_done(cl_hw, amsdu_rx_state);
+}
+
+static void cl_rx_handle_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+	struct ieee80211_sta *sta = cl_sta->sta;
+	bool is_ps;
+	__le16 fc = hdr->frame_control;
+
+	if (ieee80211_is_pspoll(fc) ||
+	    ieee80211_has_morefrags(fc) ||
+	    !(ieee80211_is_mgmt(fc) ||
+	      ieee80211_is_data(fc)))
+		return;
+
+	is_ps = ieee80211_has_pm(hdr->frame_control);
+
+	cl_sta_ps_notify(cl_hw, cl_sta, is_ps);
+	ieee80211_sta_ps_transition(sta, is_ps);
+}
+
+static void cl_rx_shift_rxhdr_rssi_values(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+	/* Fill in the rxhdr rssi "holes" so that values will start from rssi1 */
+	switch (cl_hw->first_riu_chain) {
+	case 1:
+		rxhdr->rssi1 = rxhdr->rssi2;
+		rxhdr->rssi2 = rxhdr->rssi3;
+		rxhdr->rssi3 = rxhdr->rssi4;
+		rxhdr->rssi4 = rxhdr->rssi5;
+		rxhdr->rssi5 = rxhdr->rssi6;
+		break;
+	case 2:
+		rxhdr->rssi1 = rxhdr->rssi3;
+		rxhdr->rssi2 = rxhdr->rssi4;
+		rxhdr->rssi3 = rxhdr->rssi5;
+		rxhdr->rssi4 = rxhdr->rssi6;
+		break;
+	case 3:
+		rxhdr->rssi1 = rxhdr->rssi4;
+		rxhdr->rssi2 = rxhdr->rssi5;
+		rxhdr->rssi3 = rxhdr->rssi6;
+		break;
+	case 4:
+		rxhdr->rssi1 = rxhdr->rssi5;
+		rxhdr->rssi2 = rxhdr->rssi6;
+		break;
+	case 5:
+		rxhdr->rssi1 = rxhdr->rssi6;
+		break;
+	default:
+		break;
+	}
+}
+
+static void cl_rx_handle_skb(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+	u8 encrypt_len = 0;
+	u8 tid = 0;
+	u32 mpdu_offset = 0;
+	u32 len = 0;
+	int sta_idx = -1;
+	bool skb_done = false;
+	struct cl_sta *cl_sta = NULL;
+	struct ieee80211_sta *sta = NULL;
+	struct hw_rxhdr *rxhdr = NULL;
+	struct cl_tid_ampdu_rx *tid_agg_rx = NULL;
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+	s8 remote_cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+	if (amsdu_rx_state->msdu_remaining_cnt > 0) {
+		cl_rx_handle_sub_amsdu(cl_hw, skb, amsdu_rx_state);
+		return;
+	}
+
+	rxhdr = (struct hw_rxhdr *)skb->data;
+	mpdu_offset = sizeof(struct hw_rxhdr);
+
+	if (rxhdr->rx_padding_done)
+		mpdu_offset += CL_PADDING_IN_BYTES;
+
+	/* Pull the HW RX header */
+	skb_reserve(skb, mpdu_offset);
+
+	/*
+	 * Sanity check - the embedded layer is responsible to validate the pattern correctness.
+	 * If pattern is invalid then it is likely that the embedded layer did some thing wrong.
+	 */
+	if (le32_to_cpu(rxhdr->pattern) != IPC_RX_DMA_OVER_PATTERN) {
+		cl_rx_invalid_pattern(cl_hw, skb, le32_to_cpu(rxhdr->pattern));
+		return;
+	}
+
+	if (cl_rx_check_err(cl_hw, skb, rxhdr))
+		return;
+
+	/* Convert gi from firmware format to driver format */
+	rxhdr->gi_type = cl_convert_gi_format_fw_to_wrs(rxhdr->format_mod, rxhdr->gi_type);
+
+	if (cl_hw->first_riu_chain > 0)
+		cl_rx_shift_rxhdr_rssi_values(cl_hw, rxhdr);
+
+	if (cl_hw->rssi_simulate)
+		cl_rssi_simulate(cl_hw, rxhdr);
+
+	if (rxhdr->key_sram_v)
+		sta_idx = cl_rx_get_sta_idx(cl_hw, rxhdr);
+
+	cl_sta_lock(cl_hw);
+
+	if (sta_idx != -1) {
+		cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+		if (cl_sta) {
+			sta = cl_sta->sta;
+
+			if (cl_hw->conf->ci_fast_rx_en) {
+				tid = ieee80211_get_tid((struct ieee80211_hdr *)skb->data);
+				tid_agg_rx = cl_sta->tid_agg_rx[tid];
+				cl_rx_handle_ps(cl_hw, cl_sta, skb);
+			}
+
+			/* Store the pointer to sta in the skb->sk field */
+			if (remote_cpu_mac != -1)
+				skb->sk = (struct sock *)sta;
+		}
+	}
+
+	if (unlikely(cl_rx_fill_status(cl_hw, cl_sta, skb, rxhdr, &encrypt_len))) {
+		cl_sta_unlock(cl_hw);
+		cl_rx_skb_error(cl_hw);
+		kfree_skb(skb);
+		return;
+	}
+
+	/* Is A-MSDU frame? */
+	if (rxhdr->amsdu_present) {
+		cl_rx_handle_first_amsdu(cl_hw, skb, amsdu_rx_state, rxhdr, sta_idx,
+					 tid, encrypt_len);
+		cl_sta_unlock(cl_hw);
+		return;
+	}
+
+	len = rxhdr->len;
+
+	if (skb_tailroom(skb) >= len) {
+		/* Push the WLAN HDR + MDPU payload to the skb data */
+		skb_put(skb, len);
+		cl_hw->rx_info.non_amsdu++;
+	} else {
+		cl_sta_unlock(cl_hw);
+		cl_rx_invalid_tailroom(cl_hw, rxhdr, skb, len);
+		return;
+	}
+
+	skb_done = cl_rx_skb_done(cl_hw, skb, cl_sta, rxhdr);
+
+	cl_sta_unlock(cl_hw);
+
+	if (!skb_done)
+		return;
+
+	if (tid_agg_rx) {
+		struct sk_buff_head reorder_buf;
+
+		/* Init the reorder buffer */
+		__skb_queue_head_init(&reorder_buf);
+		cl_rx_reorder_ampdu(cl_hw, cl_sta, skb, &reorder_buf);
+
+		if (!skb_queue_empty(&reorder_buf))
+			cl_rx_pass_to_mac(cl_hw, sta, &reorder_buf);
+	} else {
+		if (cl_key_handle_pn_validation(cl_hw, skb, cl_sta) == CL_PN_VALID_STATE_FAILED) {
+			kfree_skb(skb);
+			return;
+		}
+
+		if (remote_cpu_mac == -1) {
+			ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+		} else {
+			skb_queue_tail(&cl_hw->rx_remote_queue_mac, skb);
+			cl_rx_remote_cpu_mac(cl_hw);
+		}
+	}
+}
+
+static bool cl_is_rx_allowed(struct cl_hw *cl_hw)
+{
+	return !(cl_radio_is_off(cl_hw) ||
+		 !test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+		 test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags) ||
+		 cl_recovery_in_progress(cl_hw));
+}
+
+static void cl_rx_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct sk_buff *skb = NULL;
+	u16 pkt_cnt = 0;
+
+	if (unlikely(!cl_is_rx_allowed(cl_hw)))
+		return;
+
+	while ((skb = skb_dequeue(&cl_hw->rx_skb_queue))) {
+		cl_rx_handle_skb(cl_hw, skb);
+
+		if (++pkt_cnt > cl_hw->conf->ce_rx_pkts_budget) {
+			if (cl_hw->chip->conf->ci_rx_resched_tasklet)
+				tasklet_schedule(&cl_hw->rx_resched_tasklet);
+			else
+				tasklet_schedule(&cl_hw->rx_tasklet);
+
+			cl_hw->rx_info.exceed_pkt_budget++;
+			return;
+		}
+	}
+}
+
+static void cl_rx_resched_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+	tasklet_schedule(&cl_hw->rx_tasklet);
+}
+
+static void cl_rx_remote_tasklet_mac(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct sk_buff *skb = NULL;
+	struct ieee80211_sta *sta;
+
+	if (unlikely(!cl_is_rx_allowed(cl_hw)))
+		return;
+
+	cl_rx_remote_cpu_info(cl_hw);
+
+	while ((skb = skb_dequeue(&cl_hw->rx_remote_queue_mac))) {
+		/*
+		 * Get sta pointer from skb->sk (stored their in cl_rx_remote_cpu_mac)
+		 * and reset skb->sk.
+		 */
+		sta = (struct ieee80211_sta *)skb->sk;
+		skb->sk = NULL;
+
+		ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+	}
+}
+
+void cl_rx_init(struct cl_hw *cl_hw)
+{
+	s8 cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+	/* Set rx_skb_max to be the maximum of ci_rx_skb_max configured for each chip */
+	rx_skb_max = max(cl_hw->chip->conf->ci_rx_skb_max, rx_skb_max);
+
+	skb_queue_head_init(&cl_hw->rx_remote_queue_mac);
+	skb_queue_head_init(&cl_hw->rx_skb_queue);
+	__skb_queue_head_init(&cl_hw->amsdu_rx_state.frames);
+
+	tasklet_init(&cl_hw->rx_tasklet, cl_rx_tasklet, (unsigned long)cl_hw);
+	tasklet_init(&cl_hw->rx_resched_tasklet, cl_rx_resched_tasklet, (unsigned long)cl_hw);
+
+	if (cpu_mac >= 0) {
+		struct tasklet_struct *t = &per_cpu(rx_remote_tasklet_mac[cl_hw->idx], cpu_mac);
+
+		tasklet_init(t,
+			     cl_rx_remote_tasklet_mac,
+			     (unsigned long)cl_hw);
+
+		csd_rx_remote_cpu_mac[cl_hw->idx].func = cl_rx_remote_tasklet_sched;
+		csd_rx_remote_cpu_mac[cl_hw->idx].info = t;
+	}
+	cl_rx_pci_init(cl_hw);
+}
+
+void cl_rx_off(struct cl_hw *cl_hw)
+{
+	s8 cpu_mac = cl_hw->conf->ci_rx_remote_cpu_mac;
+
+	if (cpu_mac >= 0)
+		tasklet_kill(&per_cpu(rx_remote_tasklet_mac[cl_hw->idx], cpu_mac));
+
+	tasklet_kill(&cl_hw->rx_tasklet);
+	tasklet_kill(&cl_hw->rx_resched_tasklet);
+
+	skb_queue_purge(&cl_hw->rx_remote_queue_mac);
+	skb_queue_purge(&cl_hw->rx_skb_queue);
+
+	cl_rx_amsdu_reset(cl_hw);
+	cl_rx_pci_deinit(cl_hw);
+}
+
+void cl_rx_remote_tasklet_sched(void *t)
+{
+	tasklet_schedule((struct tasklet_struct *)t);
+}
+
+void cl_rx_remote_cpu_info(struct cl_hw *cl_hw)
+{
+	u32 processor_id = smp_processor_id();
+
+	if (processor_id < CPU_MAX_NUM)
+		cl_hw->rx_info.remote_cpu[processor_id]++;
+}
+
+void cl_rx_push_queue(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+	skb_queue_tail(&cl_hw->rx_skb_queue, skb);
+	tasklet_schedule(&cl_hw->rx_tasklet);
+}
+
+void cl_rx_skb_alloc_handler(struct sk_buff *skb)
+{
+	skb->destructor = cl_rx_skb_destructor;
+	atomic_inc(&rx_skb_cnt);
+}
+
+void cl_rx_skb_error(struct cl_hw *cl_hw)
+{
+	/*
+	 * When there is an error with the received packet we can't
+	 * know the interface and the AC.
+	 * So just use the first interface and BE.
+	 */
+	struct cl_vif *cl_vif = cl_vif_get_first(cl_hw);
+
+	if (!cl_vif) {
+		cl_dbg_err(cl_hw, "Couldn't find vif\n");
+		return;
+	}
+
+	cl_vif->trfc_cntrs[AC_BE].rx_errors++;
+}
+
+void cl_rx_skb_drop(struct cl_hw *cl_hw, struct sk_buff *skb, u8 cnt)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct cl_vif *cl_vif = cl_vif_get_by_mac(cl_hw, hdr->addr3);
+
+	if (cl_vif) {
+		u8 ac = cl_rx_get_skb_ac(hdr);
+
+		cl_vif->trfc_cntrs[ac].rx_dropped += cnt;
+	}
+}
+
+void cl_rx_post_recovery(struct cl_hw *cl_hw)
+{
+	if (!skb_queue_empty(&cl_hw->rx_skb_queue))
+		tasklet_schedule(&cl_hw->rx_tasklet);
+
+	if (!skb_queue_empty(&cl_hw->rx_remote_queue_mac))
+		tasklet_schedule(&per_cpu(rx_remote_tasklet_mac[cl_hw->idx],
+					  cl_hw->conf->ci_rx_remote_cpu_mac));
+}
+
+u8 cl_rx_get_skb_ac(struct ieee80211_hdr *hdr)
+{
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		u8 *qos_ctl = ieee80211_get_qos_ctl(hdr);
+		u8 tid = *qos_ctl & IEEE80211_QOS_CTL_TAG1D_MASK;
+		return tid_to_ac[tid];
+	}
+
+	return AC_BE;
+}
+
+bool cl_rx_process_in_irq(struct cl_hw *cl_hw)
+{
+	struct cl_ipc_ring_indices *indices = cl_hw->ipc_env->ring_indices_elem->indices;
+	u32 read_idx = le32_to_cpu(indices->rxdesc_read_idx[CL_RX_BUF_RXM]);
+	u32 write_idx = le32_to_cpu(indices->rxdesc_write_idx[CL_RX_BUF_RXM]);
+	u32 free_buffers = read_idx - write_idx;
+
+	if (free_buffers < (IPC_RXBUF_CNT_RXM / 2)) {
+		cl_hw->rx_info.buffer_process_irq++;
+		return true;
+	}
+
+	cl_hw->rx_info.buffer_process_tasklet++;
+	return false;
+}
+
+static bool cl_agg_rx_report_is_status_valid(u8 status)
+{
+	if (status == MM_AGG_RX_REPORT_STAT_OK ||
+	    status == MM_AGG_RX_REPORT_STAT_COLISION_WITH_COUNTER)
+		return true;
+
+	return false;
+}
+
+static void sync_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct cl_wrs_info *wrs_info,
+			 struct cl_wrs_params *wrs_params, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+
+	if (bw == rate_params->bw &&
+	    nss == rate_params->nss &&
+	    mcs == rate_params->mcs &&
+	    gi == rate_params->gi) {
+		cl_wrs_api_rate_sync(cl_hw, cl_sta, wrs_params);
+
+		wrs_info->synced = true;
+		wrs_info->quick_rate_check = true;
+		wrs_info->quick_rate_agg_cntr = 0;
+		wrs_info->quick_rate_pkt_cntr = 0;
+	} else {
+		wrs_info->sync_attempts++;
+	}
+}
+
+void cl_agg_rx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 sta_loc,
+			      struct mm_agg_rx_ind *agg_report)
+{
+	struct cl_wrs_info *wrs_info = NULL;
+	struct cl_wrs_params *wrs_params = cl_sta->wrs_sta.rx_params;
+	u16 success_cnt = le16_to_cpu(agg_report->correct_received_mpdu_count[sta_loc]);
+	u16 data_rate;
+	u8 nss = agg_report->nss_per_user[sta_loc];
+	u8 mcs = agg_report->mcs_rate[sta_loc];
+	u8 gi =  CL_TF_GI_LTF_TO_GI(agg_report->gi_ltf);
+	u8 bw;
+
+	if (!wrs_params ||
+	    !cl_agg_rx_report_is_status_valid(agg_report->status[sta_loc]))
+		return;
+
+	wrs_info = &cl_sta->wrs_info_rx;
+
+	{
+		u8 ru_type = cl_ru_alloc_to_ru_type(agg_report->ru_allocation[sta_loc]);
+
+		bw = cl_mu_ofdma_grp_convert_ru_type_to_bw(cl_hw, ru_type);
+	}
+
+	/* WRS sync mechanism */
+	if (!wrs_info->synced)
+		sync_rx_rate(cl_hw, cl_sta, wrs_info, wrs_params, bw, nss, mcs, gi);
+
+	data_rate = cl_data_rates_get_x10(WRS_MODE_HE, bw, nss, mcs, gi);
+
+	wrs_info->success += success_cnt;
+	wrs_info->fail += (le16_to_cpu(agg_report->incorrect_received_mpdu_count[sta_loc]) +
+			   le16_to_cpu(agg_report->incorrect_delimiter_count[sta_loc]));
+	wrs_info->epr_acc += ((u64)success_cnt * data_rate);
+}
+
+struct msduhdr {
+	u8 dest[ETH_ALEN];
+	u8 source[ETH_ALEN];
+	__be16 len;
+} __packed;
+
+static void cl_rx_set_flag_amsdu_more(struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+	rx_status->flag |= RX_FLAG_AMSDU_MORE;
+}
+
+static void cl_rx_clear_flag_amsdu_more(struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+	rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+}
+
+static void cl_rx_add_80211_hdr(struct cl_amsdu_rx_state *amsdu_rx_state,
+				struct sk_buff *skb, struct sk_buff *first_skb)
+{
+	/* Copy the 802.11 header of the first skb */
+	struct ieee80211_hdr *hdr_first = (struct ieee80211_hdr *)(first_skb->data);
+	u32 hdrlen_first = ieee80211_hdrlen(hdr_first->frame_control);
+	u32 total_bytes = hdrlen_first + amsdu_rx_state->encrypt_len;
+
+	skb_push(skb, total_bytes);
+	memcpy(skb->data, first_skb->data, total_bytes);
+}
+
+static void cl_rx_copy_status(struct cl_amsdu_rx_state *amsdu_rx_state,
+			      struct sk_buff *skb, struct sk_buff *first_skb)
+{
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_rx_status *rx_status_first = IEEE80211_SKB_RXCB(first_skb);
+
+	/* Copy rx_status from the first skb */
+	memcpy(rx_status, rx_status_first, sizeof(struct ieee80211_rx_status));
+
+	/* If it is the last sub-frame clear RX_FLAG_AMSDU_MORE */
+	if (amsdu_rx_state->msdu_remaining_cnt == 0)
+		rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+}
+
+static void cl_rx_amsdu_set_state(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr,
+				  u8 sta_idx, u8 tid, u32 packet_len, u8 encrypt_len)
+{
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+
+	amsdu_rx_state->msdu_cnt = rxhdr->msdu_cnt;
+	amsdu_rx_state->msdu_remaining_cnt = rxhdr->msdu_cnt - 1;
+	amsdu_rx_state->msdu_dma_align = rxhdr->msdu_dma_align;
+	amsdu_rx_state->amsdu_error = 0;
+	amsdu_rx_state->encrypt_len = encrypt_len;
+	amsdu_rx_state->packet_len = packet_len;
+	amsdu_rx_state->rxhdr = rxhdr;
+	amsdu_rx_state->first_skb = skb;
+	amsdu_rx_state->sta_idx = sta_idx;
+	amsdu_rx_state->tid = tid;
+
+	__skb_queue_head(&cl_hw->amsdu_rx_state.frames, skb);
+}
+
+static void cl_rx_amsdu_first_length_error(struct cl_hw *cl_hw, struct sk_buff *skb,
+					   struct hw_rxhdr *rxhdr, u32 len)
+{
+	cl_dbg_err(cl_hw, "RX-AMSDU length error (1/%u) - tailroom=%d, len=%u\n",
+		   rxhdr->msdu_cnt, skb_tailroom(skb), len);
+
+	cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_LENGTH);
+
+	cl_hw->rx_info.pkt_drop_amsdu_len_error++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+static void cl_rx_amsdu_sub_length_error(struct cl_hw *cl_hw, struct sk_buff *skb, u32 len)
+{
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+	struct sk_buff *skb_tail;
+	u8 sub_cnt = amsdu_rx_state->msdu_cnt - amsdu_rx_state->msdu_remaining_cnt;
+
+	cl_dbg_err(cl_hw, "RX-AMSDU length error (%u/%u) - tailroom=%d, len=%u\n",
+		   sub_cnt, amsdu_rx_state->msdu_cnt, skb_tailroom(skb), len);
+
+	/* All remaining skbs in the AMSDU will be treated as errors */
+	amsdu_rx_state->amsdu_error = RX_AMSDU_ERR_LENGTH;
+
+	/* Clear RX_FLAG_AMSDU_MORE in the last success skb that was received */
+	skb_tail = skb_peek_tail(&amsdu_rx_state->frames);
+	cl_rx_clear_flag_amsdu_more(skb_tail);
+
+	cl_hw->rx_info.pkt_drop_sub_amsdu_len_error++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+static bool cl_rx_amsdu_is_frame_aggregation_attack(struct ieee80211_hdr *hdr,
+						    const struct msduhdr *msdu_hdr)
+{
+	__le16 fc;
+	int to_ds;
+	int from_ds;
+
+	fc = hdr->frame_control;
+	to_ds = ieee80211_has_tods(fc);
+	from_ds = ieee80211_has_fromds(fc);
+
+	if (to_ds && memcmp(hdr->addr2, msdu_hdr->source, ETH_ALEN))
+		return true;
+
+	if (from_ds && memcmp(hdr->addr1, msdu_hdr->dest, ETH_ALEN) &&
+	    !(is_multicast_ether_addr(hdr->addr3)))
+		return true;
+
+	return false;
+}
+
+void cl_rx_amsdu_first(struct cl_hw *cl_hw, struct sk_buff *skb,
+		       struct hw_rxhdr *rxhdr, u8 sta_idx, u8 tid, u8 encrypt_len)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+	u32 hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	struct msduhdr *msdu_hdr = (struct msduhdr *)(skb->data + hdr_len + encrypt_len);
+	u32 packet_len = hdr_len + encrypt_len + sizeof(struct msduhdr) + ntohs(msdu_hdr->len);
+
+	if (skb_tailroom(skb) < packet_len) {
+		cl_rx_amsdu_first_length_error(cl_hw, skb, rxhdr, packet_len);
+		return;
+	}
+
+	/* Put the WLAN header + MSDU header + payload in the skb data */
+	skb_put(skb, packet_len);
+
+	cl_rx_amsdu_set_state(cl_hw, skb, rxhdr, sta_idx, tid, packet_len, encrypt_len);
+
+	/* Must be called after cl_rx_amsdu_set_state() */
+	if (cl_hw->amsdu_rx_state.msdu_remaining_cnt > 0)
+		cl_rx_set_flag_amsdu_more(skb);
+}
+
+bool cl_rx_amsdu_sub(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+	/*
+	 * ----------------------------------------------------------
+	 * | DMA padding 4 byte alignment | MSDU HDR | MSDU PAYLOAD |
+	 *  ---------------------------------------------------------
+	 */
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+	struct sk_buff *first_skb = amsdu_rx_state->first_skb;
+	struct msduhdr *msdu_hdr;
+	u32 packet_len;
+
+	/*
+	 * Push the dma alignment to the reserved area, so that skb->data will
+	 * point to the MSDU header
+	 */
+	skb_reserve(skb, amsdu_rx_state->msdu_dma_align);
+
+	msdu_hdr = (struct msduhdr *)(skb->data);
+	packet_len = sizeof(struct msduhdr) + ntohs(msdu_hdr->len);
+
+	if (skb_tailroom(skb) < packet_len) {
+		cl_rx_amsdu_sub_length_error(cl_hw, skb, packet_len);
+		return false;
+	}
+
+	/* Put the MSDU HDR + MSDU PAYLOAD into the skb data area */
+	skb_put(skb, packet_len);
+
+	amsdu_rx_state->packet_len += packet_len;
+
+	cl_rx_add_80211_hdr(amsdu_rx_state, skb, first_skb);
+	cl_rx_copy_status(amsdu_rx_state, skb, first_skb);
+
+	/* Store the pointer to sta in the skb->sk field */
+	skb->sk = first_skb->sk;
+
+	__skb_queue_tail(&amsdu_rx_state->frames, skb);
+
+	return true;
+}
+
+bool cl_rx_amsdu_check_aggregation_attack(struct cl_amsdu_rx_state *amsdu_rx_state)
+{
+	u32 hdrlen = 0;
+	struct sk_buff_head *frames = &amsdu_rx_state->frames;
+	struct hw_rxhdr *rxhdr = amsdu_rx_state->rxhdr;
+	struct ieee80211_hdr *hdr = NULL;
+	struct msduhdr *msdu_hdr = NULL;
+	struct sk_buff *skb = NULL;
+
+	/* Validate encryption info - forbid A-MSDU on pre-HT connections */
+	switch (rxhdr->decr_status) {
+	case CL_RX_HDR_DECR_ICVFAIL:
+	case CL_RX_HDR_DECR_WEPSUCCESS:
+	case CL_RX_HDR_DECR_TKIPSUCCESS:
+		return true;
+	default:
+		break;
+	}
+
+	skb_queue_walk(frames, skb) {
+		hdr = (struct ieee80211_hdr *)(skb->data);
+		hdrlen = ieee80211_hdrlen(hdr->frame_control);
+		msdu_hdr = (struct msduhdr *)(skb->data + hdrlen + amsdu_rx_state->encrypt_len);
+		if (cl_rx_amsdu_is_frame_aggregation_attack(hdr, msdu_hdr))
+			return true;
+	}
+
+	return false;
+}
+
+void cl_rx_amsdu_first_corrupted(struct cl_hw *cl_hw, struct sk_buff *skb,
+				 struct hw_rxhdr *rxhdr)
+{
+	struct ieee80211_hdr *mac_hdr = (struct ieee80211_hdr *)(skb->data);
+
+	cl_dbg_verbose(cl_hw, "Corrupted RX-AMSDU (1/%u), dest_addr=%pM\n",
+		       rxhdr->msdu_cnt, mac_hdr->addr1);
+
+	cl_rx_amsdu_set_state_error(cl_hw, rxhdr, RX_AMSDU_ERR_CORRUPTED);
+
+	cl_hw->rx_info.pkt_drop_amsdu_corrupted++;
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+void cl_rx_amsdu_sub_error(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+	u8 sub_cnt = amsdu_rx_state->msdu_cnt - amsdu_rx_state->msdu_remaining_cnt;
+
+	if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_CORRUPTED) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_corrupted++;
+
+		cl_dbg_verbose(cl_hw, "Corrupted RX-AMSDU (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	} else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_LENGTH) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_len_error++;
+
+		cl_dbg_verbose(cl_hw, "RX-AMSDU length error (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	} else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_NOT_SUCCESS) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_not_success++;
+
+		cl_dbg_verbose(cl_hw, "RX-AMSDU not success (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	} else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_UNENCRYPTED) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_unencrypted++;
+
+		cl_dbg_verbose(cl_hw, "Protected frame unencrypted (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	} else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_DECRYPT_FAIL) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_decrypt_fail++;
+
+		cl_dbg_verbose(cl_hw, "Decryption failed (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	} else if (amsdu_rx_state->amsdu_error & RX_AMSDU_ERR_INVALID_TAILROOM) {
+		cl_hw->rx_info.pkt_drop_sub_amsdu_tailroom_error++;
+
+		cl_dbg_verbose(cl_hw, "Invalid tailroom (%u/%u)\n",
+			       sub_cnt, amsdu_rx_state->msdu_cnt);
+	}
+
+	cl_rx_skb_error(cl_hw);
+	kfree_skb(skb);
+}
+
+void cl_rx_amsdu_set_state_error(struct cl_hw *cl_hw,
+				 struct hw_rxhdr *rxhdr,
+				 enum rx_amsdu_error err)
+{
+	struct cl_amsdu_rx_state *amsdu_rx_state = &cl_hw->amsdu_rx_state;
+
+	amsdu_rx_state->msdu_cnt = rxhdr->msdu_cnt;
+	amsdu_rx_state->msdu_remaining_cnt = rxhdr->msdu_cnt - 1;
+	amsdu_rx_state->amsdu_error = err;
+}
+
+void cl_rx_amsdu_reset(struct cl_hw *cl_hw)
+{
+	/* Free pending frames */
+	__skb_queue_purge(&cl_hw->amsdu_rx_state.frames);
+
+	/* Reset RX A-MSDU state */
+	memset(&cl_hw->amsdu_rx_state, 0, sizeof(struct cl_amsdu_rx_state));
+
+	__skb_queue_head_init(&cl_hw->amsdu_rx_state.frames);
+}
+
+void cl_rx_amsdu_stats(struct cl_hw *cl_hw, u8 msdu_cnt)
+{
+	/*
+	 * Update A-MSDU statistics
+	 * msdu_cnt 1 - 128 is mapped to 0 - 127.
+	 */
+	if (msdu_cnt <= RX_MAX_MSDU_IN_AMSDU)
+		cl_hw->rx_info.amsdu_cnt[msdu_cnt - 1]++;
+	else
+		cl_dbg_err(cl_hw, "Invalid msdu_cnt [%u]\n", msdu_cnt);
+}
+
+/* Only ieee80211_hw_set() is defined in mac80211.h */
+static inline void _ieee80211_hw_clear(struct ieee80211_hw *hw,
+				       enum ieee80211_hw_flags flg)
+{
+	return __clear_bit(flg, hw->flags);
+}
+
+#define ieee80211_hw_clear(hw, flg) _ieee80211_hw_clear(hw, IEEE80211_HW_##flg)
+
+void cl_rx_amsdu_hw_en(struct ieee80211_hw *hw, bool rxamsdu_en)
+{
+	if (rxamsdu_en)
+		ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
+	else
+		ieee80211_hw_clear(hw, SUPPORTS_AMSDU_IN_AMPDU);
+}
+
+u32 cl_rx_filter_update_flags(struct cl_hw *cl_hw, u32 filter)
+{
+	u32 rx_filter = 0;
+
+	if (filter & FIF_ALLMULTI)
+		rx_filter |= RX_CNTRL_ACCEPT_MULTICAST_BIT;
+
+	if (filter & (FIF_FCSFAIL | FIF_PLCPFAIL))
+		rx_filter |= RX_CNTRL_ACCEPT_ERROR_FRAMES_BIT;
+
+	if (filter & FIF_BCN_PRBRESP_PROMISC)
+		rx_filter |= RX_CNTRL_ACCEPT_OTHER_BSSID_BIT;
+
+	if (filter & FIF_CONTROL)
+		rx_filter |= RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_BIT |
+			     RX_CNTRL_ACCEPT_CF_END_BIT |
+			     RX_CNTRL_ACCEPT_ACK_BIT |
+			     RX_CNTRL_ACCEPT_CTS_BIT |
+			     RX_CNTRL_ACCEPT_RTS_BIT |
+			     RX_CNTRL_ACCEPT_BA_BIT | RX_CNTRL_ACCEPT_BAR_BIT;
+
+	if (filter & FIF_OTHER_BSS)
+		rx_filter |= RX_CNTRL_ACCEPT_OTHER_BSSID_BIT;
+
+	if (filter & FIF_PSPOLL)
+		rx_filter |= RX_CNTRL_ACCEPT_PS_POLL_BIT;
+
+	if (filter & FIF_PROBE_REQ)
+		rx_filter |= RX_CNTRL_ACCEPT_PROBE_REQ_BIT;
+
+	/* Add the filter flags that are set by default and cannot be changed here */
+	rx_filter |= CL_MAC80211_NOT_CHANGEABLE;
+
+	if (ieee80211_hw_check(cl_hw->hw, AMPDU_AGGREGATION))
+		rx_filter |= RX_CNTRL_ACCEPT_BA_BIT;
+
+	/*
+	 * work around for HW bug (AD 14672)
+	 * In order for the response frames to BAR and RTS be with correct
+	 * power they should always be accepted and found in the KSR
+	 */
+	rx_filter |= RX_CNTRL_ACCEPT_BAR_BIT | RX_CNTRL_ACCEPT_RTS_BIT;
+
+	return rx_filter;
+}
+
+static u32 cl_filter_get_flags(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	return sdata->local->filter_flags;
+}
+
+void cl_rx_filter_restore_flags(struct cl_hw *cl_hw)
+{
+	struct net_device *dev = cl_vif_get_first_net_device(cl_hw);
+	u32 filter = 0;
+
+	if (!dev)
+		return;
+
+	filter = cl_filter_get_flags(dev);
+	cl_dbg_verbose(cl_hw, "Restoring filter flags to 0x%x\n", filter);
+	cl_msg_tx_set_filter(cl_hw, filter, false);
+}
+
+void cl_rx_filter_set_promiscuous(struct cl_hw *cl_hw)
+{
+	u32 filter = ~(FIF_FCSFAIL | FIF_PLCPFAIL | (1 << 31));
+
+	cl_dbg_verbose(cl_hw, "set promiscuous mode 0x%x\n", filter);
+	cl_msg_tx_set_filter(cl_hw, filter, false);
+}
+
+#define REORDER_BUF_TIMEOUT (HZ / 10)
+#define REORDER_BUF_TIMEOUT_MS jiffies_to_msecs(REORDER_BUF_TIMEOUT + 1)
+
+static bool cl_rx_reorder_ready(struct cl_tid_ampdu_rx *tid_agg_rx, u8 index)
+{
+	struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
+	struct sk_buff *tail = skb_peek_tail(frames);
+	struct ieee80211_rx_status *status;
+
+	if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
+		return true;
+
+	if (!tail)
+		return false;
+
+	status = IEEE80211_SKB_RXCB(tail);
+
+	if (status->flag & RX_FLAG_AMSDU_MORE)
+		return false;
+
+	return true;
+}
+
+static void cl_rx_release_reorder_frame(struct cl_tid_ampdu_rx *tid_agg_rx, int index,
+					struct sk_buff_head *frames)
+{
+	struct cl_hw *cl_hw = tid_agg_rx->cl_hw;
+	struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index];
+	struct sk_buff *skb;
+	struct ieee80211_rx_status *status = NULL;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(tid_agg_rx->sta);
+	int pn_state = CL_PN_VALID_STATE_FAILED;
+
+	lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+	if (skb_queue_empty(skb_list))
+		goto no_frame;
+
+	tid_agg_rx->stored_mpdu_num--;
+
+	if (!cl_rx_reorder_ready(tid_agg_rx, index)) {
+		__skb_queue_purge(skb_list);
+		goto no_frame;
+	}
+
+	/* For NON AMSDU - Single skb in skb_list
+	 * For AMSDU - Validate first skb and set PN flag for rest.
+	 */
+	skb = skb_peek(skb_list);
+	pn_state = cl_key_handle_pn_validation(cl_hw, skb, cl_sta);
+	if (pn_state == CL_PN_VALID_STATE_FAILED) {
+		__skb_queue_purge(skb_list);
+		goto no_frame;
+	}
+
+	while ((skb = __skb_dequeue(skb_list))) {
+		if (pn_state == CL_PN_VALID_STATE_SUCCESS) {
+			status = IEEE80211_SKB_RXCB(skb);
+			status->flag |= RX_FLAG_PN_VALIDATED;
+		}
+		__skb_queue_tail(frames, skb);
+	}
+
+no_frame:
+	tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
+	tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
+}
+
+static void cl_rx_release_reorder_frames(struct cl_tid_ampdu_rx *tid_agg_rx,
+					 u16 head_seq_num,
+					 struct sk_buff_head *frames)
+{
+	int index;
+
+	lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+	while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+		index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+		cl_rx_release_reorder_frame(tid_agg_rx, index, frames);
+	}
+}
+
+static void cl_reorder_release(struct cl_tid_ampdu_rx *tid_agg_rx, struct sk_buff_head *frames)
+{
+	u8 index, i, j;
+
+	lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+	/* Release buffer until next hole */
+	index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+	if (!cl_rx_reorder_ready(tid_agg_rx, index) && tid_agg_rx->stored_mpdu_num) {
+		u8 skipped = 1;
+
+		for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
+		     j = (j + 1) % tid_agg_rx->buf_size) {
+			if (!cl_rx_reorder_ready(tid_agg_rx, j)) {
+				skipped++;
+				continue;
+			}
+			if (skipped &&
+			    !time_after(jiffies, tid_agg_rx->reorder_time[j] +
+					REORDER_BUF_TIMEOUT))
+				goto set_release_timer;
+
+			/* Incomplete A-MSDUs */
+			for (i = (index + 1) % tid_agg_rx->buf_size; i != j;
+			     i = (i + 1) % tid_agg_rx->buf_size) {
+				__skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
+			}
+
+			cl_rx_release_reorder_frame(tid_agg_rx, j, frames);
+
+			tid_agg_rx->head_seq_num =
+				(tid_agg_rx->head_seq_num +
+				 skipped) & IEEE80211_SN_MASK;
+			skipped = 0;
+		}
+	} else {
+		while (cl_rx_reorder_ready(tid_agg_rx, index)) {
+			cl_rx_release_reorder_frame(tid_agg_rx, index, frames);
+			index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+		}
+	}
+
+	if (tid_agg_rx->stored_mpdu_num) {
+		j = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
+		index = j;
+		for (; j != (index - 1) % tid_agg_rx->buf_size;
+		     j = (j + 1) % tid_agg_rx->buf_size) {
+			if (cl_rx_reorder_ready(tid_agg_rx, j))
+				break;
+		}
+
+ set_release_timer:
+		if (!tid_agg_rx->removed)
+			mod_timer(&tid_agg_rx->reorder_timer, tid_agg_rx->reorder_time[j] +
+				   msecs_to_jiffies(REORDER_BUF_TIMEOUT_MS));
+	} else {
+		del_timer(&tid_agg_rx->reorder_timer);
+	}
+}
+
+static void cl_rx_reorder_release_timeout(struct timer_list *t)
+{
+	struct cl_tid_ampdu_rx *tid_agg_rx = from_timer(tid_agg_rx, t, reorder_timer);
+	struct sk_buff *skb = NULL;
+	struct cl_hw *cl_hw = NULL;
+	struct ieee80211_sta *sta = NULL;
+	struct sk_buff_head buffer;
+
+	if (!tid_agg_rx)
+		return;
+
+	__skb_queue_head_init(&buffer);
+
+	spin_lock(&tid_agg_rx->reorder_lock);
+
+	cl_hw = tid_agg_rx->cl_hw;
+	sta = tid_agg_rx->sta;
+	cl_reorder_release(tid_agg_rx, &buffer);
+
+	spin_unlock(&tid_agg_rx->reorder_lock);
+
+	while (!skb_queue_empty(&buffer)) {
+		skb = __skb_dequeue(&buffer);
+		ieee80211_rx_napi(cl_hw->hw, sta, skb, NULL);
+	}
+}
+
+static bool cl_rx_manage_reorder_buf(struct cl_tid_ampdu_rx *tid_agg_rx,
+				     struct sk_buff *skb,
+				     struct sk_buff_head *ordered_mpdu)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	u16 sc = le16_to_cpu(hdr->seq_ctrl);
+	u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	u16 head_seq_num, buf_size;
+	u8 index;
+	bool ret = true;
+
+	if (unlikely(tid_agg_rx->auto_seq)) {
+		tid_agg_rx->auto_seq = false;
+		tid_agg_rx->ssn = mpdu_seq_num;
+		tid_agg_rx->head_seq_num = mpdu_seq_num;
+	}
+
+	buf_size = tid_agg_rx->buf_size;
+	head_seq_num = tid_agg_rx->head_seq_num;
+
+	/* Current SN is smaller than the SSN */
+	if (unlikely(!tid_agg_rx->started)) {
+		if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
+			ret = false;
+			goto out;
+		}
+		tid_agg_rx->started = true;
+	}
+
+	/* Out of date sequence number */
+	if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
+		dev_kfree_skb(skb);
+		goto out;
+	}
+
+	/* SN exceeds buffer window */
+	if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
+		head_seq_num = ieee80211_sn_inc(ieee80211_sn_sub(mpdu_seq_num, buf_size));
+		cl_rx_release_reorder_frames(tid_agg_rx, head_seq_num, ordered_mpdu);
+	}
+
+	index = mpdu_seq_num % tid_agg_rx->buf_size;
+
+	/* Frame already stored */
+	if (cl_rx_reorder_ready(tid_agg_rx, index)) {
+		dev_kfree_skb(skb);
+		goto out;
+	}
+
+	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
+	    tid_agg_rx->stored_mpdu_num == 0) {
+		if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
+			tid_agg_rx->head_seq_num =
+				ieee80211_sn_inc(tid_agg_rx->head_seq_num);
+		}
+		ret = false;
+		goto out;
+	}
+
+	/* Insert frame into reorder buffer */
+	__skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb);
+	if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
+		tid_agg_rx->reorder_time[index] = jiffies;
+		tid_agg_rx->stored_mpdu_num++;
+		cl_reorder_release(tid_agg_rx, ordered_mpdu);
+	}
+
+ out:
+	return ret;
+}
+
+void cl_rx_reorder_ampdu(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			 struct sk_buff *skb, struct sk_buff_head *ordered_mpdu)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct cl_tid_ampdu_rx *tid_agg_rx;
+	u8 tid, ack_policy;
+
+	if (!cl_sta)
+		return;
+
+	ack_policy = *ieee80211_get_qos_ctl(hdr) &
+		     IEEE80211_QOS_CTL_ACK_POLICY_MASK;
+	tid = ieee80211_get_tid(hdr);
+
+	tid_agg_rx = cl_sta->tid_agg_rx[tid];
+	if (!tid_agg_rx)
+		return;
+
+	spin_lock(&tid_agg_rx->reorder_lock);
+	if (!ieee80211_is_data_qos(hdr->frame_control) ||
+	    is_multicast_ether_addr(hdr->addr1))
+		goto dont_reorder;
+
+	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
+		goto dont_reorder;
+
+	if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+	    ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+		goto dont_reorder;
+
+	/* Ignore EAPOL frames */
+	if (cl_is_eapol(skb))
+		goto dont_reorder;
+
+	if (cl_rx_manage_reorder_buf(tid_agg_rx, skb, ordered_mpdu)) {
+		spin_unlock(&tid_agg_rx->reorder_lock);
+		return;
+	}
+
+ dont_reorder:
+	spin_unlock(&tid_agg_rx->reorder_lock);
+
+	if (cl_key_handle_pn_validation(cl_hw, skb, cl_sta) == CL_PN_VALID_STATE_FAILED) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	__skb_queue_tail(ordered_mpdu, skb);
+}
+
+void cl_rx_reorder_close(struct cl_sta *cl_sta, u8 tid)
+{
+	struct cl_tid_ampdu_rx *tid_agg_rx = cl_sta->tid_agg_rx[tid];
+	u16 i;
+
+	spin_lock_bh(&tid_agg_rx->reorder_lock);
+	tid_agg_rx->removed = true;
+	spin_unlock_bh(&tid_agg_rx->reorder_lock);
+
+	del_timer_sync(&tid_agg_rx->reorder_timer);
+
+	spin_lock_bh(&tid_agg_rx->reorder_lock);
+	for (i = 0; i < tid_agg_rx->buf_size; i++)
+		__skb_queue_purge(&tid_agg_rx->reorder_buf[i]);
+
+	kfree(tid_agg_rx->reorder_buf);
+	kfree(tid_agg_rx->reorder_time);
+	cl_sta->tid_agg_rx[tid] = NULL;
+
+	spin_unlock_bh(&tid_agg_rx->reorder_lock);
+	kfree(tid_agg_rx);
+}
+
+void cl_rx_reorder_init(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid, u16 buf_size)
+{
+	struct cl_tid_ampdu_rx *tid_agg_rx;
+	u16 i;
+
+	tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
+	if (!tid_agg_rx)
+		return;
+
+	spin_lock_init(&tid_agg_rx->reorder_lock);
+
+	timer_setup(&tid_agg_rx->reorder_timer, cl_rx_reorder_release_timeout, 0);
+
+	tid_agg_rx->reorder_buf =
+		kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
+	tid_agg_rx->reorder_time =
+		kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
+	if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
+		pr_err("Allocation failed!\n");
+		kfree(tid_agg_rx->reorder_buf);
+		kfree(tid_agg_rx->reorder_time);
+		return;
+	}
+
+	for (i = 0; i < buf_size; i++)
+		__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
+
+	tid_agg_rx->ssn = 0;
+	tid_agg_rx->head_seq_num = 0;
+	tid_agg_rx->buf_size = buf_size;
+	tid_agg_rx->stored_mpdu_num = 0;
+	tid_agg_rx->auto_seq = 0;
+	tid_agg_rx->started = false;
+	tid_agg_rx->reorder_buf_filtered = 0;
+	tid_agg_rx->tid = tid;
+	tid_agg_rx->sta = cl_sta->sta;
+	tid_agg_rx->cl_hw = cl_hw;
+	cl_sta->tid_agg_rx[tid] = tid_agg_rx;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 69/96] cl8k: add rx.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (67 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 68/96] cl8k: add rx.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 70/96] cl8k: add scan.c viktor.barna
                   ` (26 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/rx.h | 505 ++++++++++++++++++++++++++
 1 file changed, 505 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/rx.h

diff --git a/drivers/net/wireless/celeno/cl8k/rx.h b/drivers/net/wireless/celeno/cl8k/rx.h
new file mode 100644
index 000000000000..f460c3c37475
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/rx.h
@@ -0,0 +1,505 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_RX_H
+#define CL_RX_H
+
+#include <linux/skbuff.h>
+#include <net/mac80211.h>
+
+#include "ipc_shared.h"
+
+/* Decryption status subfields */
+enum cl_rx_hdr_decr {
+	CL_RX_HDR_DECR_UNENC,
+	CL_RX_HDR_DECR_ICVFAIL,
+	CL_RX_HDR_DECR_CCMPFAIL,
+	CL_RX_HDR_DECR_AMSDUDISCARD,
+	CL_RX_HDR_DECR_NULLKEY,
+	CL_RX_HDR_DECR_WEPSUCCESS,
+	CL_RX_HDR_DECR_TKIPSUCCESS,
+	CL_RX_HDR_DECR_CCMPSUCCESS
+};
+
+#define CL_PADDING_IN_BYTES 2
+
+struct hw_rxhdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 msdu_cnt           : 8,   /* [7:0] */
+	    corrupted_amsdu    : 1,   /* [8] */
+	    reserved           : 1,   /* [9] */
+	    msdu_dma_align     : 2,   /* [11:10] */
+	    amsdu_error_code   : 4,   /* [15:12] */
+	    reserved_2         :16;   /* [31:16] */
+#else
+	u32 reserved_2         :16,   /* [15:0] */
+	    amsdu_error_code   : 4,    /* [19:16] */
+	    msdu_dma_align     : 2,    /* [21:20] */
+	    reserved           : 1,    /* [22] */
+	    corrupted_amsdu    : 1,    /* [23] */
+	    msdu_cnt           : 8;    /* [31:24] */
+#endif
+	/* Total length for the MPDU transfer */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 len                :14,   /* [13:0] */
+	    ampdu_cnt          : 2,   /* [15:14] */
+	    rx_padding_done    : 1,   /* [16] */
+	    rx_class_rule_res  : 7,   /* [23:17] */
+	/* AMPDU Status Information */
+	    mpdu_cnt           : 8;   /* [31:24] */
+#else
+	u32 mpdu_cnt           : 8,   /* [7:0] */
+	    rx_class_rule_res  : 7,   /* [14:8] */
+	    rx_padding_done    : 1,   /* [15] */
+	    ampdu_cnt          : 2,   /* [17:16] */
+	    len                :14;   /* [31:18] */
+#endif
+
+	/* TSF Low */
+	__le32 tsf_lo;
+	/* TSF High */
+	__le32 tsf_hi;
+
+	/* Receive Vector 1a */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 leg_length         :12,   /* [11:0] */
+	    leg_rate           : 4,   /* [15:12] */
+	    ht_length_l        :16;   /* [31:16] */
+#else
+	u32 ht_length_l        :16,   /* [15:0] */
+	    leg_rate           :4,    /* [19:16] */
+	    leg_length         :12;   /* [31:20] */
+#endif
+
+	/* Receive Vector 1b */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 ht_length_h        : 8,   /* [7:0] */
+	    mcs                : 7,   /* [14:8] */
+	    pre_type           : 1,   /* [15] */
+	    format_mod         : 4,   /* [19:16] */
+	    reserved_1b        : 1,   /* [20] */
+	    n_sts              : 3,   /* [23:21] */
+	    lsig_valid         : 1,   /* [24] */
+	    sounding           : 1,   /* [25] */
+	    num_extn_ss        : 2,   /* [27:26] */
+	    aggregation        : 1,   /* [28] */
+	    fec_coding         : 1,   /* [29] */
+	    dyn_bw             : 1,   /* [30] */
+	    doze_not_allowed   : 1;   /* [31] */
+#else
+	u32 doze_not_allowed   : 1,   /* [0] */
+	    dyn_bw             : 1,   /* [1] */
+	    fec_coding         : 1,   /* [2] */
+	    aggregation        : 1,   /* [3] */
+	    num_extn_ss        : 2,   /* [5:4] */
+	    sounding           : 1,   /* [6] */
+	    lsig_valid         : 1,   /* [7] */
+	    n_sts              : 3,   /* [10:8] */
+	    reserved_1b        : 1,   /* [11] */
+	    format_mod         : 4,   /* [15:12] */
+	    pre_type           : 1,   /* [16] */
+	    mcs                : 7,   /* [23:17] */
+	    ht_length_h        : 8;   /* [31:24] */
+#endif
+
+	/* Receive Vector 1c */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 sn                 : 4,  /* [3:0] */
+	    warn_1c            : 1,  /* [4] */
+	    stbc               : 2,  /* [6:5] */
+	    smoothing          : 1,  /* [7] */
+	    partial_aid        : 9,  /* [16:8] */
+	    group_id           : 6,  /* [22:17] */
+	    reserved_1c        : 1,  /* [23] */
+	    rssi1              : 8;  /* [31:24] */
+#else
+	u32 rssi1              : 8,  /* [7:0] */
+	    reserved_1c        : 1,  /* [8] */
+	    group_id           : 6,  /* [14:9] */
+	    partial_aid        : 9,  /* [23:15] */
+	    smoothing          : 1,  /* [24] */
+	    stbc               : 2,  /* [26:25] */
+	    warn_1c            : 1,  /* [27] */
+	    sn                 : 4;  /* [31:28] */
+#endif
+
+	/* Receive Vector 1d */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	s32 rssi2              : 8,  /* [7:0] */
+	    rssi3              : 8,  /* [15:8] */
+	    rssi4              : 8,  /* [23:16] */
+	    rx_chains          : 8;  /* [31:24] */
+#else
+	s32 rx_chains          : 8,  /* [7:0] */
+	    rssi4              : 8,  /* [15:8] */
+	    rssi3              : 8,  /* [23:16] */
+	    rssi2              : 8;  /* [31:24] */
+#endif
+
+	/* Receive Vector 1e */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 txop_duration      : 7,  /* [6:0] */
+	    beam_change        : 1,  /* [7] */
+	    mcs_sig_b          : 3,  /* [10:8] */
+	    dcm                : 1,  /* [11] */
+	    dcm_sig_b          : 1,  /* [12] */
+	    beamformed         : 1,  /* [13] */
+	    ltf_type           : 2,  /* [15:14] */
+	    ru_band            : 1,  /* [16] */
+	    ru_type            : 3,  /* [19:17] */
+	    ru_index           : 6,  /* [25:20] */
+	    pe_duration        : 3,  /* [28:26] */
+	    ch_bw              : 2,  /* [30:29] */
+	    reserved_1e        : 1;  /* [31] */
+#else
+	u32 reserved_1e        : 1,  /* [0] */
+	    ch_bw              : 2,  /* [2:1] */
+	    pe_duration        : 3,  /* [5:3] */
+	    ru_index           : 6,  /* [11:6] */
+	    ru_type            : 3,  /* [14:12] */
+	    ru_band            : 1,  /* [15] */
+	    ltf_type           : 2,  /* [17:16] */
+	    beamformed         : 1,  /* [18] */
+	    dcm_sig_b          : 1,  /* [19] */
+	    dcm                : 1,  /* [20] */
+	    mcs_sig_b          : 3,  /* [23:21] */
+	    beam_change        : 1,  /* [24] */
+	    txop_duration      : 7;  /* [31:25] */
+#endif
+
+	/* Receive Vector 1f */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 spatial_reuse      : 16, /* [15:0] */
+	    service            : 16; /* [31:16] */
+#else
+	u32 service            : 16, /* [15:0] */
+	    spatial_reuse      : 16; /* [31:16] */
+#endif
+
+	/* Receive Vector 1g */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 bss_color          : 6,  /* [5:0] */
+	    gi_type            : 2,  /* [7:6] */
+	    antenna_set        : 16, /* [23:8] */
+	    rssi5              : 8;  /* [31:24] */
+#else
+	u32 rssi5              : 8,  /* [7:0] */
+	    antenna_set        : 16, /* [23:8] */
+	    gi_type            : 2,  /* [25:24] */
+	    bss_color          : 6;  /* [31:26] */
+#endif
+
+	/* Receive Vector 1h */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	s32 rssi6              : 8,  /* [7:0] */
+	    rssi7              : 8,  /* [15:8] */
+	    rssi8              : 8,  /* [23:16] */
+	    future_1           : 8;  /* [31:24] */
+#else
+	s32 future_1           : 8,  /* [7:0] */
+	    rssi8              : 8,  /* [15:8] */
+	    rssi7              : 8,  /* [23:16] */
+	    rssi6              : 8;  /* [31:24] */
+#endif
+
+	/* Receive Vector 2a */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 rcpi               : 8,  /* [7:0] */
+	    evm1               : 8,  /* [15:8] */
+	    evm2               : 8,  /* [23:16] */
+	    evm3               : 8;  /* [31:24] */
+#else
+	u32 evm3               : 8,  /* [7:0] */
+	    evm2               : 8,  /* [15:8] */
+	    evm1               : 8,  /* [23:16] */
+	    rcpi               : 8;  /* [31:24] */
+#endif
+
+	/* Receive Vector 2b */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 evm4               : 8,  /* [7:0] */
+	    warn_2b            : 1,  /* [8] */
+	    reserved2b_1       : 7,  /* [15:9] */
+	    reserved2b_2       : 8,  /* [23:16] */
+	    reserved2b_3       : 8;  /* [31:24] */
+#else
+	u32 reserved2b_3       : 8,  /* [7:0] */
+	    reserved2b_2       : 8,  /* [15:8] */
+	    reserved2b_1       : 7,  /* [22:16] */
+	    warn_2b            : 1,  /* [23] */
+	    evm4               : 8;  /* [31:24] */
+#endif
+
+	/* Status **/
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 rx_vect2_valid     : 1,  /* [0] */
+	    resp_frame         : 1,  /* [1] */
+	    decr_status        : 3,  /* [4:2] */
+	    rx_fifo_oflow      : 1,  /* [5] */
+	    undef_err          : 1,  /* [6] */
+	    phy_err            : 1,  /* [7] */
+	    fcs_err            : 1,  /* [8] */
+	    addr_mismatch      : 1,  /* [9] */
+	    ga_frame           : 1,  /* [10] */
+	    first_qos_data     : 1,  /* [11] */
+	    amsdu_present      : 1,  /* [12] */
+	    frm_successful_rx  : 1,  /* [13] */
+	    desc_done_rx       : 1,  /* [14] */
+	    desc_spare         : 1,  /* [15] */
+	    key_sram_index     : 9,  /* [24:16] */
+	    key_sram_v         : 1,  /* [25] */
+	    type               : 2,  /* [27:26] */
+	    subtype            : 4;  /* [31:28] */
+#else
+	u32 subtype            : 4,  /* [3:0] */
+	    type               : 2,  /* [5:4] */
+	    key_sram_v         : 1,  /* [6] */
+	    key_sram_index     : 9,  /* [15:7] */
+	    desc_spare         : 1,  /* [16] */
+	    desc_done_rx       : 1,  /* [17] */
+	    frm_successful_rx  : 1,  /* [18] */
+	    amsdu_present      : 1,  /* [19] */
+	    first_qos_data     : 1,  /* [20] */
+	    ga_frame           : 1,  /* [21] */
+	    addr_mismatch      : 1,  /* [22] */
+	    fcs_err            : 1,  /* [23] */
+	    phy_err            : 1,  /* [24] */
+	    undef_err          : 1,  /* [25] */
+	    rx_fifo_oflow      : 1,  /* [26] */
+	    decr_status        : 3,  /* [29:27] */
+	    resp_frame         : 1,  /* [30] */
+	    rx_vect2_valid     : 1;  /* [31] */
+#endif
+
+	/* PHY channel information 1 */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 phy_band           : 8,  /* [7:0] */
+	    phy_channel_type   : 8,  /* [15:8] */
+	    phy_prim20_freq    : 16; /* [31:16] */
+#else
+	u32 phy_prim20_freq    : 16, /* [15:0] */
+	    phy_channel_type   : 8,  /* [23:16] */
+	    phy_band           : 8;  /* [31:24] */
+#endif
+
+	/* PHY channel information 2 */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 phy_center1_freq   : 16, /* [15:0] */
+	    phy_center2_freq   : 16; /* [31:16] */
+#else
+	u32 phy_center2_freq   : 16, /* [15:0] */
+	    phy_center1_freq   : 16; /* [31:16] */
+#endif
+
+	/* Patten **/
+	__le32  pattern;
+};
+
+enum cl_radio_stats {
+	CL_RADIO_FCS_ERROR = 0,
+	CL_RADIO_PHY_ERROR,
+	CL_RADIO_RX_FIFO_OVERFLOW,
+	CL_RADIO_ADDRESS_MISMATCH,
+	CL_RADIO_UNDEFINED_ERROR,
+	CL_RADIO_ERRORS_MAX
+};
+
+struct cl_rx_path_info {
+	u32 rx_desc[CL_RX_BUF_MAX];
+	u32 netif_rx;
+	u32 elem_alloc_fail;
+	u32 skb_null;
+	u32 pkt_drop_amsdu_corrupted;
+	u32 pkt_drop_sub_amsdu_corrupted;
+	u32 pkt_drop_amsdu_len_error;
+	u32 pkt_drop_sub_amsdu_len_error;
+	u32 pkt_drop_wrong_pattern;
+	u32 pkt_drop_not_success;
+	u32 pkt_drop_sub_amsdu_not_success;
+	u32 pkt_drop_unencrypted;
+	u32 pkt_drop_sub_amsdu_unencrypted;
+	u32 pkt_drop_decrypt_fail;
+	u32 pkt_drop_sub_amsdu_decrypt_fail;
+	u32 pkt_drop_tailroom_error;
+	u32 pkt_drop_sub_amsdu_tailroom_error;
+	u32 pkt_drop_amsdu_inj_attack;
+	u32 pkt_drop_sta_null;
+	u32 pkt_drop_host_limit;
+	u32 pkt_drop_invalid_pn;
+	u32 remote_cpu[CPU_MAX_NUM];
+	u32 exceed_pkt_budget;
+	u32 pkt_handle_bucket_rxm[IPC_RXBUF_NUM_BUCKETS_RXM];
+	u32 pkt_handle_bucket_fw[IPC_RXBUF_NUM_BUCKETS_FW];
+	u32 amsdu_cnt[RX_MAX_MSDU_IN_AMSDU];
+	u32 non_amsdu;
+	u32 buffer_process_irq;
+	u32 buffer_process_tasklet;
+};
+
+struct cl_hw;
+struct cl_vif;
+struct cl_sta;
+struct mm_agg_rx_ind;
+
+void cl_rx_init(struct cl_hw *cl_hw);
+void cl_rx_off(struct cl_hw *cl_hw);
+void cl_rx_remote_tasklet_sched(void *t);
+void cl_rx_remote_cpu_info(struct cl_hw *cl_hw);
+void cl_rx_push_queue(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_rx_skb_alloc_handler(struct sk_buff *skb);
+void cl_rx_skb_error(struct cl_hw *cl_hw);
+void cl_rx_skb_drop(struct cl_hw *cl_hw, struct sk_buff *skb, u8 cnt);
+void cl_rx_post_recovery(struct cl_hw *cl_hw);
+void cl_rx_finish(struct cl_hw *cl_hw, struct sk_buff *skb, struct ieee80211_sta *sta);
+u8 cl_rx_get_skb_ac(struct ieee80211_hdr *hdr);
+bool cl_rx_process_in_irq(struct cl_hw *cl_hw);
+void cl_agg_rx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 sta_loc,
+			      struct mm_agg_rx_ind *agg_report);
+
+enum rx_amsdu_error {
+	RX_AMSDU_ERR_CORRUPTED = 0x1,
+	RX_AMSDU_ERR_LENGTH = 0x2,
+	RX_AMSDU_ERR_NOT_SUCCESS = 0x4,
+	RX_AMSDU_ERR_UNENCRYPTED = 0x8,
+	RX_AMSDU_ERR_DECRYPT_FAIL = 0x10,
+	RX_AMSDU_ERR_INVALID_TAILROOM = 0x20,
+};
+
+struct cl_amsdu_rx_state {
+	u8 msdu_cnt;
+	u8 msdu_remaining_cnt;
+	/*
+	 * MSDU padding - all MSDU pkt within A-MSDU are 4byte aligned (this
+	 * value holds the alignment value)
+	 * According to ieee80211 spec all MSDU share the same alignment
+	 */
+	u8 msdu_dma_align;
+	u8 amsdu_error;
+	u8 encrypt_len;
+	u8 sta_idx;
+	u8 tid;
+	u32 packet_len;
+	struct hw_rxhdr *rxhdr;
+	struct sk_buff *first_skb;
+	struct sk_buff_head frames;
+};
+
+void cl_rx_amsdu_first(struct cl_hw *cl_hw, struct sk_buff *skb, struct hw_rxhdr *rxhdr,
+		       u8 sta_idx, u8 tid, u8 encrypt_len);
+bool cl_rx_amsdu_sub(struct cl_hw *cl_hw, struct sk_buff *skb);
+bool cl_rx_amsdu_check_aggregation_attack(struct cl_amsdu_rx_state *amsdu_rx_state);
+void cl_rx_amsdu_first_corrupted(struct cl_hw *cl_hw, struct sk_buff *skb,
+				 struct hw_rxhdr *rxhdr);
+void cl_rx_amsdu_sub_error(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_rx_amsdu_set_state_error(struct cl_hw *cl_hw,
+				 struct hw_rxhdr *rxhdr,
+				 enum rx_amsdu_error err);
+void cl_rx_amsdu_reset(struct cl_hw *cl_hw);
+void cl_rx_amsdu_stats(struct cl_hw *cl_hw, u8 msdu_cnt);
+void cl_rx_amsdu_hw_en(struct ieee80211_hw *hw, bool rxamsdu_en);
+
+/* Field definitions */
+#define RX_CNTRL_EN_DUPLICATE_DETECTION_BIT      ((u32)0x80000000)
+#define RX_CNTRL_EN_DUPLICATE_DETECTION_POS      31
+#define RX_CNTRL_ACCEPT_UNKNOWN_BIT              ((u32)0x40000000)
+#define RX_CNTRL_ACCEPT_UNKNOWN_POS              30
+#define RX_CNTRL_ACCEPT_OTHER_DATA_FRAMES_BIT    ((u32)0x20000000)
+#define RX_CNTRL_ACCEPT_OTHER_DATA_FRAMES_POS    29
+#define RX_CNTRL_ACCEPT_QO_S_NULL_BIT            ((u32)0x10000000)
+#define RX_CNTRL_ACCEPT_QO_S_NULL_POS            28
+#define RX_CNTRL_ACCEPT_QCFWO_DATA_BIT           ((u32)0x08000000)
+#define RX_CNTRL_ACCEPT_QCFWO_DATA_POS           27
+#define RX_CNTRL_ACCEPT_Q_DATA_BIT               ((u32)0x04000000)
+#define RX_CNTRL_ACCEPT_Q_DATA_POS               26
+#define RX_CNTRL_ACCEPT_CFWO_DATA_BIT            ((u32)0x02000000)
+#define RX_CNTRL_ACCEPT_CFWO_DATA_POS            25
+#define RX_CNTRL_ACCEPT_DATA_BIT                 ((u32)0x01000000)
+#define RX_CNTRL_ACCEPT_DATA_POS                 24
+#define RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_BIT   ((u32)0x00800000)
+#define RX_CNTRL_ACCEPT_OTHER_CNTRL_FRAMES_POS   23
+#define RX_CNTRL_ACCEPT_CF_END_BIT               ((u32)0x00400000)
+#define RX_CNTRL_ACCEPT_CF_END_POS               22
+#define RX_CNTRL_ACCEPT_ACK_BIT                  ((u32)0x00200000)
+#define RX_CNTRL_ACCEPT_ACK_POS                  21
+#define RX_CNTRL_ACCEPT_CTS_BIT                  ((u32)0x00100000)
+#define RX_CNTRL_ACCEPT_CTS_POS                  20
+#define RX_CNTRL_ACCEPT_RTS_BIT                  ((u32)0x00080000)
+#define RX_CNTRL_ACCEPT_RTS_POS                  19
+#define RX_CNTRL_ACCEPT_PS_POLL_BIT              ((u32)0x00040000)
+#define RX_CNTRL_ACCEPT_PS_POLL_POS              18
+#define RX_CNTRL_ACCEPT_BA_BIT                   ((u32)0x00020000)
+#define RX_CNTRL_ACCEPT_BA_POS                   17
+#define RX_CNTRL_ACCEPT_BAR_BIT                  ((u32)0x00010000)
+#define RX_CNTRL_ACCEPT_BAR_POS                  16
+#define RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_BIT    ((u32)0x00008000)
+#define RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_POS    15
+#define RX_CNTRL_ACCEPT_ALL_BEACON_BIT           ((u32)0x00002000)
+#define RX_CNTRL_ACCEPT_ALL_BEACON_POS           13
+#define RX_CNTRL_ACCEPT_NOT_EXPECTED_BA_BIT      ((u32)0x00001000)
+#define RX_CNTRL_ACCEPT_NOT_EXPECTED_BA_POS      12
+#define RX_CNTRL_ACCEPT_DECRYPT_ERROR_FRAMES_BIT ((u32)0x00000800)
+#define RX_CNTRL_ACCEPT_DECRYPT_ERROR_FRAMES_POS 11
+#define RX_CNTRL_ACCEPT_BEACON_BIT               ((u32)0x00000400)
+#define RX_CNTRL_ACCEPT_BEACON_POS               10
+#define RX_CNTRL_ACCEPT_PROBE_RESP_BIT           ((u32)0x00000200)
+#define RX_CNTRL_ACCEPT_PROBE_RESP_POS           9
+#define RX_CNTRL_ACCEPT_PROBE_REQ_BIT            ((u32)0x00000100)
+#define RX_CNTRL_ACCEPT_PROBE_REQ_POS            8
+#define RX_CNTRL_ACCEPT_MY_UNICAST_BIT           ((u32)0x00000080)
+#define RX_CNTRL_ACCEPT_MY_UNICAST_POS           7
+#define RX_CNTRL_ACCEPT_UNICAST_BIT              ((u32)0x00000040)
+#define RX_CNTRL_ACCEPT_UNICAST_POS              6
+#define RX_CNTRL_ACCEPT_ERROR_FRAMES_BIT         ((u32)0x00000020)
+#define RX_CNTRL_ACCEPT_ERROR_FRAMES_POS         5
+#define RX_CNTRL_ACCEPT_OTHER_BSSID_BIT          ((u32)0x00000010)
+#define RX_CNTRL_ACCEPT_OTHER_BSSID_POS          4
+#define RX_CNTRL_ACCEPT_BROADCAST_BIT            ((u32)0x00000008)
+#define RX_CNTRL_ACCEPT_BROADCAST_POS            3
+#define RX_CNTRL_ACCEPT_MULTICAST_BIT            ((u32)0x00000004)
+#define RX_CNTRL_ACCEPT_MULTICAST_POS            2
+#define RX_CNTRL_DONT_DECRYPT_BIT                ((u32)0x00000002)
+#define RX_CNTRL_DONT_DECRYPT_POS                1
+#define RX_CNTRL_EXC_UNENCRYPTED_BIT             ((u32)0x00000001)
+#define RX_CNTRL_EXC_UNENCRYPTED_POS             0
+
+/* Default MAC Rx filters that cannot be changed by mac80211 */
+#define CL_MAC80211_NOT_CHANGEABLE (            \
+	RX_CNTRL_ACCEPT_QO_S_NULL_BIT         | \
+	RX_CNTRL_ACCEPT_Q_DATA_BIT            | \
+	RX_CNTRL_ACCEPT_DATA_BIT              | \
+	RX_CNTRL_ACCEPT_OTHER_MGMT_FRAMES_BIT | \
+	RX_CNTRL_ACCEPT_MY_UNICAST_BIT        | \
+	RX_CNTRL_ACCEPT_BROADCAST_BIT         | \
+	RX_CNTRL_ACCEPT_BEACON_BIT            | \
+	RX_CNTRL_ACCEPT_PROBE_RESP_BIT          \
+	)
+
+u32 cl_rx_filter_update_flags(struct cl_hw *cl_hw, u32 filter);
+void cl_rx_filter_restore_flags(struct cl_hw *cl_hw);
+void cl_rx_filter_set_promiscuous(struct cl_hw *cl_hw);
+
+struct cl_tid_ampdu_rx {
+	spinlock_t reorder_lock;
+	u64 reorder_buf_filtered;
+	struct sk_buff_head *reorder_buf;
+	unsigned long *reorder_time;
+	struct ieee80211_sta *sta;
+	struct timer_list reorder_timer;
+	struct cl_hw *cl_hw;
+	u16 head_seq_num;
+	u16 stored_mpdu_num;
+	u16 ssn;
+	u16 buf_size;
+	u16 timeout;
+	u8 tid;
+	u8 auto_seq:1,
+	   removed:1,
+	   started:1;
+};
+
+void cl_rx_reorder_ampdu(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			 struct sk_buff *skb, struct sk_buff_head *ordered_mpdu);
+void cl_rx_reorder_close(struct cl_sta *cl_sta, u8 tid);
+void cl_rx_reorder_init(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid, u16 buf_size);
+
+#endif /* CL_RX_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 70/96] cl8k: add scan.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (68 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 69/96] cl8k: add rx.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 71/96] cl8k: add scan.h viktor.barna
                   ` (25 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/scan.c | 392 ++++++++++++++++++++++++
 1 file changed, 392 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/scan.c

diff --git a/drivers/net/wireless/celeno/cl8k/scan.c b/drivers/net/wireless/celeno/cl8k/scan.c
new file mode 100644
index 000000000000..10076d93620e
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/scan.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "channel.h"
+#include "chip.h"
+#include "calib.h"
+#include "debug.h"
+#include "rates.h"
+#include "vif.h"
+#include "hw.h"
+#include "scan.h"
+
+#define CL_MIN_SCAN_TIME_MS 50
+#define CL_MIN_WAIT_TIME_MS 20
+
+static const char SCANNER_KTHREAD_NAME[] = "cl_scanner_kthread";
+
+int cl_scan_channel_switch(struct cl_hw *cl_hw, u8 channel, u8 bw,
+			   bool allow_recalib)
+{
+	struct cl_vif *cl_vif = cl_vif_get_first(cl_hw);
+	struct cfg80211_chan_def *chandef = NULL;
+	struct cfg80211_chan_def local_chandef;
+	struct ieee80211_channel *chan = NULL;
+	u16 freq = ieee80211_channel_to_frequency(channel, cl_hw->nl_band);
+	int ret = 0;
+
+	if (!cl_vif) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	chandef = &cl_vif->vif->bss_conf.chandef;
+	local_chandef = *chandef;
+
+	chan = ieee80211_get_channel(cl_hw->hw->wiphy, freq);
+	if (!chan) {
+		cl_dbg_err(cl_hw, "Channel %u wasn't found!\n", channel);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	local_chandef.chan = chan;
+	if (cl_chandef_calc(cl_hw, channel, bw,
+			    &local_chandef.width,
+			    &local_chandef.chan->center_freq,
+			    &local_chandef.center_freq1)) {
+		cl_dbg_err(cl_hw, "Failed to extract chandef data for ch:%d\n",
+			   channel);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	*chandef = local_chandef;
+	cl_hw->hw->conf.chandef = local_chandef;
+
+	if (cl_hw->chip->conf->ce_calib_runtime_en && allow_recalib)
+		ret = cl_calib_runtime_and_switch_channel(cl_hw, channel, bw,
+							  freq,
+							  chandef->center_freq1);
+	else
+		ret = cl_msg_tx_set_channel(cl_hw, channel, bw, freq,
+					    chandef->center_freq1,
+					    CL_CALIB_PARAMS_DEFAULT_STRUCT);
+exit:
+	return ret;
+}
+
+static int cl_scan_channel(struct cl_chan_scanner *scanner, u8 ch_idx)
+{
+	u8 main_channel;
+	enum cl_channel_bw main_bw;
+	s32 res = 0;
+	bool is_off_channel;
+	u64 scan_time_jiffies;
+
+	/*
+	 * 1. Save current channel
+	 * 2. Disable tx
+	 * 3. jump to new channel
+	 * 4. Enable promiscious
+	 * 5. Enable BSS collection
+	 * 6. Reset stats counters
+	 * 7. Sleep for scan_time
+	 * 8. Calculate stats
+	 * 9. Disable promiscious
+	 * 10. Disable BSS collection
+	 * 11. Switch to current channel
+	 * 12. Enable tx
+	 **/
+
+	cl_dbg_trace(scanner->cl_hw, "Starting scan on channel %u, scan time %u(ms)\n",
+		     scanner->channels[ch_idx].channel, scanner->scan_time);
+
+	/* Save current channel */
+	res = mutex_lock_interruptible(&scanner->cl_hw->set_channel_mutex);
+	if (res != 0)
+		return res;
+	main_channel = scanner->cl_hw->channel;
+	main_bw = scanner->cl_hw->bw;
+	mutex_unlock(&scanner->cl_hw->set_channel_mutex);
+
+	cl_dbg_trace(scanner->cl_hw, "Main channel is %u with bw %u\n",
+		     main_channel, main_bw);
+
+	is_off_channel = (scanner->channels[ch_idx].channel != main_channel) ||
+			 (scanner->channels[ch_idx].scan_bw != main_bw);
+
+	/* Jump to new channel */
+	if (is_off_channel) {
+		/* Disable tx */
+		cl_tx_en(scanner->cl_hw, CL_TX_EN_SCAN, false);
+
+		res = cl_scan_channel_switch(scanner->cl_hw,
+					     scanner->channels[ch_idx].channel,
+					     scanner->channels[ch_idx].scan_bw,
+					     false);
+		if (res) {
+			cl_dbg_err(scanner->cl_hw,
+				   "Channel switch failed: ch - %u, bw - %u, err - %d\n",
+				   scanner->channels[ch_idx].channel,
+				   scanner->channels[ch_idx].scan_bw, res);
+			goto enable_tx;
+		}
+	} else {
+		cl_dbg_trace(scanner->cl_hw, "Scan on main channel %u\n", main_channel);
+	}
+
+	/* Enable promiscious mode */
+	cl_rx_filter_set_promiscuous(scanner->cl_hw);
+
+	/* Reset channel stats */
+	cl_get_initial_channel_stats(scanner->cl_hw, &scanner->channels[ch_idx]);
+
+	/* Sleep for scan time */
+	scan_time_jiffies = msecs_to_jiffies(scanner->scan_time);
+	res = wait_for_completion_interruptible_timeout(&scanner->abort_completion,
+							scan_time_jiffies);
+	if (res > 0) {
+		cl_dbg_err(scanner->cl_hw, "Scan on channel %u, bw %u, idx %u was aborted\n",
+			   scanner->channels[ch_idx].channel,
+			   scanner->channels[ch_idx].scan_bw, ch_idx);
+		res = 0;
+	}
+
+	/* Calculate stats */
+	cl_get_final_channel_stats(scanner->cl_hw, &scanner->channels[ch_idx]);
+
+	/* Disable promiscious */
+	cl_rx_filter_restore_flags(scanner->cl_hw);
+
+	if (is_off_channel) {
+		res = cl_scan_channel_switch(scanner->cl_hw, main_channel, main_bw, false);
+		if (res)
+			cl_dbg_err(scanner->cl_hw,
+				   "Switching to main ch %u, bw %u failed, err - %d\n",
+				   main_channel, main_bw, res);
+enable_tx:
+		/* Enable tx */
+		cl_tx_en(scanner->cl_hw, CL_TX_EN_SCAN, true);
+	}
+
+	cl_dbg_trace(scanner->cl_hw, "Scan on channel %u finished, actual scan_time is %u ms\n",
+		     scanner->channels[ch_idx].channel, scanner->channels[ch_idx].scan_time_ms);
+
+	return res;
+}
+
+static s32 cl_run_off_channel_scan(struct cl_chan_scanner *scanner)
+{
+	u8 i = 0, scanned_channels = 0;
+	s32 ret = 0;
+
+	for (i = 0; i < scanner->channels_num && !scanner->scan_aborted; ++i) {
+		if (!scanner->channels[i].scan_enabled)
+			continue;
+
+		scanner->curr_ch_idx = i;
+		ret = cl_scan_channel(scanner, i);
+		if (ret)
+			cl_dbg_err(scanner->cl_hw, "scan failed, err - %d, channel - %u\n",
+				   ret, scanner->channels[i].channel);
+
+		if (scanner->scan_aborted)
+			break;
+
+		cl_dbg_trace(scanner->cl_hw, "Scan on chan %u finished, waiting for time %u\n",
+			     scanner->channels[i].channel, scanner->wait_time);
+
+		++scanned_channels;
+		if (scanned_channels != scanner->scan_channels_num) {
+			u64 wait_time_jiffies;
+
+			wait_time_jiffies = msecs_to_jiffies(scanner->wait_time);
+			ret = wait_for_completion_interruptible_timeout(&scanner->abort_completion,
+									wait_time_jiffies);
+			if (ret > 0) {
+				cl_dbg_err(scanner->cl_hw, "Off-channel scan was aborted\n");
+				ret = 0;
+			}
+		}
+	}
+
+	if (scanner->completion_cb)
+		scanner->completion_cb(scanner->cl_hw, scanner->completion_arg);
+
+	cl_dbg_info(scanner->cl_hw, "Off-channel scan on %u channels finished\n",
+		    scanner->scan_channels_num);
+
+	return ret;
+}
+
+static s32 cl_off_channel_scan_thread_fn(void *args)
+{
+	struct cl_chan_scanner *scanner = args;
+
+	while (!kthread_should_stop()) {
+		if (atomic_read(&scanner->scan_thread_busy)) {
+			cl_run_off_channel_scan(scanner);
+			atomic_set(&scanner->scan_thread_busy, 0);
+			wake_up_interruptible(&scanner->wq);
+		}
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+
+	return 0;
+}
+
+static bool cl_is_scan_available(struct cl_chan_scanner *scanner)
+{
+	if (atomic_cmpxchg(&scanner->scan_thread_busy, 0, 1) == 1) {
+		cl_dbg_warn(scanner->cl_hw, "Off-channel scan is already in progress\n");
+		return false;
+	}
+
+	return true;
+}
+
+static enum cl_channel_bw cl_scanner_fix_input_bw(struct cl_chan_scanner *scanner, u8 bw)
+{
+	return (bw >= CHNL_BW_MAX) ? scanner->cl_hw->bw : bw;
+}
+
+static void cl_scanner_disable_everywhere(struct cl_chan_scanner *scanner)
+{
+	u8 j;
+
+	for (j = 0; j < scanner->channels_num; ++j)
+		scanner->channels[j].scan_enabled = false;
+}
+
+s32 cl_trigger_off_channel_scan(struct cl_chan_scanner *scanner, u32 scan_time, u32 wait_time,
+				const u8 *channels, enum cl_channel_bw scan_bw, u8 channels_num,
+				void (*completion_cb)(struct cl_hw *cl_hw, void *arg),
+				void *completion_arg)
+{
+	u8 i, j;
+
+	if (!channels || scan_bw > CHNL_BW_MAX)
+		return -EINVAL;
+
+	if (!scanner->scans_enabled)
+		return 0;
+
+	if (channels_num > scanner->channels_num) {
+		cl_dbg_err(scanner->cl_hw, "channels num %u is invalid, max is %u\n",
+			   channels_num, scanner->channels_num);
+		return -ERANGE;
+	}
+
+	if (!cl_is_scan_available(scanner))
+		return -EBUSY;
+
+	scanner->completion_arg = completion_arg;
+	scanner->completion_cb = completion_cb;
+	scanner->scan_time = max_t(u32, scan_time, CL_MIN_SCAN_TIME_MS);
+	scanner->wait_time = max_t(u32, wait_time, CL_MIN_WAIT_TIME_MS);
+	scanner->scan_bw = cl_scanner_fix_input_bw(scanner, scan_bw);
+	scanner->scan_aborted = false;
+
+	cl_scanner_disable_everywhere(scanner);
+
+	scanner->scan_channels_num = 0;
+	for (j = 0; j < scanner->channels_num; ++j) {
+		for (i = 0; i < channels_num; ++i) {
+			if (channels[i] != scanner->channels[j].channel)
+				continue;
+
+			if (!cl_chan_info_get(scanner->cl_hw, scanner->channels[j].channel,
+					      scanner->scan_bw)) {
+				cl_dbg_warn(scanner->cl_hw, "channel %u with bw %u is disabled\n",
+					    scanner->channels[j].channel, scanner->scan_bw);
+				continue;
+			}
+
+			scanner->channels[j].scan_enabled = true;
+			++scanner->scan_channels_num;
+		}
+	}
+
+	reinit_completion(&scanner->abort_completion);
+
+	wake_up_process(scanner->scan_thread);
+
+	return 0;
+}
+
+void cl_abort_scan(struct cl_chan_scanner *scanner)
+{
+	scanner->scan_aborted = true;
+	complete(&scanner->abort_completion);
+	cl_dbg_info(scanner->cl_hw, "Off-channel scan was aborted\n");
+}
+
+bool cl_is_scan_in_progress(const struct cl_chan_scanner *scanner)
+{
+	return atomic_read(&scanner->scan_thread_busy);
+}
+
+int cl_scanner_init(struct cl_hw *cl_hw)
+{
+	u8 i, j;
+	s32 ret = 0;
+	u32 channels_num;
+	struct cl_chan_scanner *scanner;
+
+	cl_hw->scanner = vzalloc(sizeof(*cl_hw->scanner));
+	if (!cl_hw->scanner)
+		return -ENOMEM;
+
+	scanner = cl_hw->scanner;
+	init_completion(&scanner->abort_completion);
+
+	scanner->cl_hw = cl_hw;
+	scanner->scans_enabled = true;
+
+	channels_num = cl_channel_num(scanner->cl_hw);
+	for (i = 0, j = 0; i < channels_num; ++i) {
+		u32 freq;
+
+		freq = cl_channel_idx_to_freq(cl_hw, i);
+		if (!ieee80211_get_channel(cl_hw->hw->wiphy, freq))
+			continue;
+
+		ret = cl_init_channel_stats(scanner->cl_hw, &scanner->channels[j], freq);
+		if (ret)
+			return ret;
+
+		cl_dbg_trace(scanner->cl_hw, "Stats for channel %u at index %u initialized\n",
+			     scanner->channels[j].channel, j);
+		++j;
+	}
+
+	scanner->channels_num = j;
+
+	atomic_set(&scanner->scan_thread_busy, 0);
+	init_waitqueue_head(&scanner->wq);
+
+	scanner->scan_thread = kthread_run(cl_off_channel_scan_thread_fn,
+					   scanner, SCANNER_KTHREAD_NAME);
+	if (IS_ERR(scanner->scan_thread)) {
+		cl_dbg_err(scanner->cl_hw, "unable to create kthread %s, err - %ld\n",
+			   SCANNER_KTHREAD_NAME, PTR_ERR(scanner->scan_thread));
+		return PTR_ERR(scanner->scan_thread);
+	}
+	cl_dbg_trace(scanner->cl_hw, "%s kthread was created, pid - %u\n",
+		     SCANNER_KTHREAD_NAME, scanner->scan_thread->pid);
+
+	return ret;
+}
+
+void cl_scanner_deinit(struct cl_hw *cl_hw)
+{
+	struct cl_chan_scanner *scanner = cl_hw->scanner;
+
+	if (!scanner->scans_enabled)
+		goto out;
+
+	if (scanner->scan_thread)
+		kthread_stop(scanner->scan_thread);
+
+ out:
+	vfree(cl_hw->scanner);
+	cl_hw->scanner = NULL;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 71/96] cl8k: add scan.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (69 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 70/96] cl8k: add scan.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 72/96] cl8k: add sounding.c viktor.barna
                   ` (24 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/scan.h | 53 +++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/scan.h

diff --git a/drivers/net/wireless/celeno/cl8k/scan.h b/drivers/net/wireless/celeno/cl8k/scan.h
new file mode 100644
index 000000000000..857e1cfc1745
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/scan.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_SCAN_H
+#define CL_SCAN_H
+
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+
+#include "channel.h"
+
+struct cl_chan_scanner {
+	struct cl_channel_stats channels[MAX_CHANNELS];
+	enum cl_channel_bw scan_bw;
+	u8 channels_num;
+	u8 scan_channels_num;
+	u8 curr_ch_idx;
+
+	struct task_struct *scan_thread;
+	atomic_t scan_thread_busy;
+
+	u32 scan_time;
+	u32 wait_time;
+
+	bool scans_enabled;
+	bool scan_aborted;
+	struct completion abort_completion;
+
+	u8 prescan_bw;
+	u32 prescan_channel;
+
+	wait_queue_head_t wq;
+	struct cl_hw *cl_hw;
+
+	void (*completion_cb)(struct cl_hw *cl_hw, void *arg);
+	void *completion_arg;
+};
+
+/* Use CHNL scan_bw =_BW_MAX to perform scan on current bandwidth */
+s32 cl_trigger_off_channel_scan(struct cl_chan_scanner *scanner, u32 scan_time, u32 wait_time,
+				const u8 *channels, enum cl_channel_bw scan_bw, u8 channels_num,
+				void (*completion_cb)(struct cl_hw *cl_hw, void *arg),
+				void *completion_arg);
+void cl_abort_scan(struct cl_chan_scanner *scanner);
+int cl_scanner_init(struct cl_hw *cl_hw);
+void cl_scanner_deinit(struct cl_hw *cl_hw);
+int cl_scan_channel_switch(struct cl_hw *cl_hw, u8 channel, u8 bw, bool allow_recalib);
+bool cl_is_scan_in_progress(const struct cl_chan_scanner *scanner);
+
+#endif /* CL_SCAN_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 72/96] cl8k: add sounding.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (70 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 71/96] cl8k: add scan.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 73/96] cl8k: add sounding.h viktor.barna
                   ` (23 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sounding.c | 1121 +++++++++++++++++++
 1 file changed, 1121 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.c

diff --git a/drivers/net/wireless/celeno/cl8k/sounding.c b/drivers/net/wireless/celeno/cl8k/sounding.c
new file mode 100644
index 000000000000..09d43a01bb70
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sounding.c
@@ -0,0 +1,1121 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "debug.h"
+#include "bf.h"
+#include "chip.h"
+#include "utils.h"
+#include "recovery.h"
+#include "debug.h"
+#include "hw.h"
+#include "sounding.h"
+
+#define DBG_PREFIX_MAX_LENGTH 64
+#define sounding_pr(level, format, ...) \
+	do { \
+		if ((level) <= cl_hw->sounding.dbg_level) { \
+			char __dbg_prefix[DBG_PREFIX_MAX_LENGTH] = {0}; \
+			if ((level) >= DBG_LVL_TRACE) \
+				snprintf(__dbg_prefix, DBG_PREFIX_MAX_LENGTH, "[%s][%d]", \
+					 __func__, __LINE__); \
+			pr_debug("%s [Sounding] " format, __dbg_prefix, ##__VA_ARGS__); \
+		} \
+	} while (0)
+
+#define sounding_pr_verbose(...) sounding_pr(DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define sounding_pr_err(...)     sounding_pr(DBG_LVL_ERROR, ##__VA_ARGS__)
+#define sounding_pr_warn(...)    sounding_pr(DBG_LVL_WARNING, ##__VA_ARGS__)
+#define sounding_pr_trace(...)   sounding_pr(DBG_LVL_TRACE, ##__VA_ARGS__)
+#define sounding_pr_info(...)    sounding_pr(DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define CL_SOUNDING_ALL_STA          0xff
+#define CL_SOUNDING_LIFETIME_MAX     4095
+#define CL_SOUNDING_LIFETIME_FACTOR  5
+#define CL_SOUNDING_V_MATRIX_PADDING 32
+#define CL_V_MATRIX_MAC_OVERHEAD     41
+#define CL_Q_MATRIX_BITMAP_MASK      0xf
+
+enum cl_sounding_feedback_type {
+	CL_SOUNDING_FEEDBACK_TYPE_SU = 0,
+	CL_SOUNDING_FEEDBACK_TYPE_MU,
+};
+
+enum cl_sounding_ng {
+	CL_SOUNDING_NG_4 = 0,
+	CL_SOUNDING_NG_16,
+	CL_SOUNDING_NG_MAX
+};
+
+struct sounding_work_data {
+	struct work_struct  work;
+	struct cl_hw *cl_hw;
+	bool start;
+	bool is_recovery;
+	struct cl_sounding_info *elem; /* For stop and recovery cases */
+	enum sounding_type sounding_type;
+	u8 gid;
+	u8 sta_num;
+	u8 bw;
+	u8 q_matrix_bitmap;
+	u8 sta_indices[CL_MU_MAX_STA_PER_GROUP];
+};
+
+static u16 ng_bw_to_nsc[CL_SOUNDING_NG_MAX][CHNL_BW_MAX_HE] = {
+	{64, 128, 256, 512},
+	{32, 32, 64, 128}
+};
+
+static int cl_sounding_check_response(struct cl_hw *cl_hw, u8 param_err)
+{
+	int ret = -1;
+
+	switch (param_err) {
+	case CL_SOUNDING_RSP_OK:
+		sounding_pr_trace("param OK!\n");
+		ret = 0;
+		break;
+	case CL_SOUNDING_RSP_ERR_RLIMIT:
+		sounding_pr_err("error, resource limit reached\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_BW:
+		sounding_pr_err("error, unsupported BW tx requested\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_NSS:
+		sounding_pr_err("error, unsupported ndp NSS tx requested\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_INTERVAL:
+		sounding_pr_err("error, interval value is invalid\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_ALREADY:
+		sounding_pr_err("error, station already associated/disassociated with sounding\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_STA:
+		sounding_pr_err("error, station is inactive/active\n");
+		break;
+	case CL_SOUNDING_RSP_ERR_TYPE:
+		sounding_pr_err("error, invalid sounding type\n");
+		break;
+	default:
+		sounding_pr_err("error status unknown, BUG\n");
+		break;
+	}
+
+	return ret;
+}
+
+static u32 cl_sounding_get_lifetime(struct cl_hw *cl_hw, u32 interval)
+{
+	u32 lifetime = (interval * CL_SOUNDING_LIFETIME_FACTOR) >> 1;
+
+	if (lifetime > CL_SOUNDING_LIFETIME_MAX) {
+		sounding_pr_err("lifetime (%u) exceeds 4095\n", lifetime);
+		lifetime = CL_SOUNDING_LIFETIME_MAX;
+	}
+
+	return lifetime;
+}
+
+static bool cl_sounding_is_sta_ng_16_capable(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+					     bool mu_cap)
+{
+	struct ieee80211_sta_he_cap *he_cap = &cl_sta->sta->he_cap;
+
+	if (he_cap->has_he) {
+		if (mu_cap)
+			return (he_cap->he_cap_elem.phy_cap_info[5] &
+				IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK);
+		else
+			return (he_cap->he_cap_elem.phy_cap_info[5] &
+				IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK);
+	}
+
+	return false;
+}
+
+static bool cl_sounding_is_sta_codebook_size_75_capable(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct ieee80211_sta_he_cap *he_cap = &cl_sta->sta->he_cap;
+
+	if (he_cap->has_he)
+		return (he_cap->he_cap_elem.phy_cap_info[6] &
+			IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU);
+
+	return false;
+}
+
+static void cl_sounding_extract_ng_cb_size(struct cl_hw *cl_hw, u8 fb_type_ng_cb_size,
+					   enum cl_sounding_ng *ng, u8 *phi_psi_sum)
+{
+	enum cl_sounding_feedback_type fb_type =
+		SOUNDING_FEEDBACK_TYPE_VAL(fb_type_ng_cb_size);
+	u8 cb_size = SOUNDING_CODEBOOK_SIZE_VAL(fb_type_ng_cb_size);
+
+	*ng = SOUNDING_NG_VAL(fb_type_ng_cb_size);
+
+	switch (fb_type) {
+	case CL_SOUNDING_FEEDBACK_TYPE_SU:
+		*phi_psi_sum = (cb_size ? 10 : 6);
+		break;
+	case CL_SOUNDING_FEEDBACK_TYPE_MU:
+		*phi_psi_sum = (cb_size ? 16 : 12);
+		break;
+	default:
+		sounding_pr_err("Invalid feedback_type %d\n", fb_type);
+		break;
+	}
+}
+
+static u32 cl_sounding_get_v_matrix_size(struct cl_hw *cl_hw, u8 sta_idx, u8 bw, u8 nc, u8 nr,
+					 u8 fb_type_ng_cb_size)
+{
+	enum cl_sounding_ng ng = 0;
+	u8 phi_psi_sum = 0;
+	u8 nsc;
+	u32 v_size;
+
+	cl_sounding_extract_ng_cb_size(cl_hw, fb_type_ng_cb_size, &ng, &phi_psi_sum);
+	nsc = ng_bw_to_nsc[ng][bw];
+
+	/* NC and NR should start from 1 and not 0 for the below calculation */
+	nc++;
+	nr++;
+
+	/* v_size = [8*41 + 8*nc + (phi + psi)/2 * nsc*(nc * (2*nr-nc-1))] / 8 + extra padding */
+	v_size = CL_V_MATRIX_MAC_OVERHEAD + nc +
+		     ((phi_psi_sum * nsc * nc * (2 * nr - nc - 1)) >> 4) +
+		     CL_SOUNDING_V_MATRIX_PADDING;
+
+	sounding_pr_info("sta %u, nc %u, nr %u, ng %d, phi_psi_sum %u, nsc %u, v_size %u\n",
+			 sta_idx, nc, nr, ng, phi_psi_sum, nsc, v_size);
+
+	return v_size;
+}
+
+static u32 cl_sounding_get_v_matrices_data_size(struct cl_hw *cl_hw,
+						struct sounding_info_per_sta *info_per_sta,
+						u8 sta_num, u8 bw, u8 nr)
+{
+	u8 i;
+	u32 v_size = 0;
+
+	for (i = 0; i < sta_num; i++)
+		v_size += cl_sounding_get_v_matrix_size(cl_hw, info_per_sta[i].sta_idx,
+							bw, info_per_sta[i].nc,
+							nr, info_per_sta[i].fb_type_ng_cb_size);
+
+	sounding_pr_info("v_matrices data size %u, sta_num %u\n", v_size, sta_num);
+
+	return v_size;
+}
+
+static u32 cl_sounding_get_q_matrix_size(struct cl_hw *cl_hw,
+					 const struct sounding_info_per_sta *info_per_sta,
+					 u8 sta_num, u8 bw, u8 nr)
+{
+	u8 i;
+	u8 nc = 0;
+	enum cl_sounding_ng ng = 0;
+	u8 nsc, phi_psi_sum = 0;
+	u32 q_size = 0;
+
+	/*
+	 * NC and NR should start from 1 and not 0 for the below calculation
+	 * In MU-MIMO case, when sta_num > 1, we should take the sum of all nc's
+	 */
+	for (i = 0; i < sta_num; i++)
+		nc += info_per_sta[i].nc + 1;
+
+	nr++;
+
+	cl_sounding_extract_ng_cb_size(cl_hw, info_per_sta[0].fb_type_ng_cb_size, &ng,
+				       &phi_psi_sum);
+	nsc = ng_bw_to_nsc[ng][bw];
+	q_size = (nr * nc * nsc) << 2;
+
+	sounding_pr_info("q_matrix size %u, sta_num %u\n", q_size, sta_num);
+
+	return q_size;
+}
+
+static u32 cl_sounding_get_required_xmem_size(struct cl_hw *cl_hw,
+					      const struct mm_sounding_req *sounding_req,
+					      const struct sounding_info_per_sta *info_per_sta)
+{
+	u8 i;
+	u8 sta_num = sounding_req->sta_num;
+	u8 q_matrix_bitmap = sounding_req->q_matrix_bitmap;
+	u8 bw = sounding_req->req_txbw;
+	u8 nr = sounding_req->ndp_nsts;
+	u32 total_size = 0;
+
+	/*
+	 * In case of MU sounding only one Q matrix is generated.
+	 * Otherwise, the number of Q matrices equals to te number of stations
+	 */
+	if (sta_num > 1 &&
+	    sounding_req->sounding_type != SOUNDING_TYPE_HE_MU &&
+	    sounding_req->sounding_type != SOUNDING_TYPE_VHT_MU)
+		for (i = 0; i < sta_num; i++)
+			total_size +=
+			cl_sounding_get_q_matrix_size(cl_hw, &info_per_sta[i], 1, bw, nr);
+	else
+		total_size =
+			cl_sounding_get_q_matrix_size(cl_hw, info_per_sta, sta_num, bw, nr);
+
+	/*
+	 * If additional SU Q matrices should be generated - consider them also when calculating
+	 * the required XMEM space
+	 */
+	if (q_matrix_bitmap) {
+		for (i = 0; i < CL_MU_MIMO_MAX_STA_PER_GRP; i++)
+			if (q_matrix_bitmap & BIT(i))
+				total_size +=
+				cl_sounding_get_q_matrix_size(cl_hw, &info_per_sta[i], 1, bw, nr);
+	}
+
+	return total_size;
+}
+
+static bool cl_sounding_is_enough_xmem_space(struct cl_hw *cl_hw,
+					     const struct mm_sounding_req *sounding_req,
+					     const struct sounding_info_per_sta *info_per_sta,
+					     u32 *required_size)
+{
+	struct cl_xmem *xmem_db = &cl_hw->chip->xmem_db;
+	u32 req_mem = cl_sounding_get_required_xmem_size(cl_hw, sounding_req, info_per_sta);
+
+	if (required_size)
+		*required_size = req_mem;
+
+	return ((xmem_db->size - xmem_db->total_used) >= req_mem);
+}
+
+static void cl_sounding_fill_info_per_sta(struct cl_hw *cl_hw, u8 sounding_type, u8 bw, u8 sta_num,
+					  struct cl_sta **cl_sta_arr,
+					  struct sounding_info_per_sta *info_per_sta,
+					  u8 *n_sts)
+{
+	u8 i;
+	u8 min_sts = cl_hw->num_antennas;
+	struct cl_sta *cl_sta = NULL;
+	u8 mu_fb_type_ng_cb_size = FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+	u8 curr_fb_type_ng_cb_size;
+	bool should_update_fb_type_ng_cb_size = false;
+
+	for (i = 0; i < sta_num; i++) {
+		cl_sta = cl_sta_arr[i];
+
+		if (!cl_sta)
+			continue;
+
+		info_per_sta[i].sta_idx = cl_sta->sta_idx;
+		info_per_sta[i].nc = cl_sta->bf_db.nc;
+
+		min_sts = min(min_sts, cl_sta->bf_db.beamformee_sts);
+
+		switch (sounding_type) {
+		case SOUNDING_TYPE_HE_CQI:
+		case SOUNDING_TYPE_HE_SU:
+		case SOUNDING_TYPE_VHT_SU:
+		case SOUNDING_TYPE_VHT_MU:
+			info_per_sta[i].fb_type_ng_cb_size =
+				FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_4_2;
+			break;
+		case SOUNDING_TYPE_HE_SU_TB:
+			info_per_sta[i].fb_type_ng_cb_size =
+				FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_6_4;
+			break;
+		case SOUNDING_TYPE_HE_CQI_TB:
+			info_per_sta[i].fb_type_ng_cb_size =
+				FEEDBACK_TYPE_CQI_TB;
+			break;
+		case SOUNDING_TYPE_HE_MU:
+			if (bw == CHNL_BW_160 &&
+			    info_per_sta[i].nc >= WRS_SS_3 &&
+			    min_sts == MAX_ANTENNAS) {
+				should_update_fb_type_ng_cb_size = true;
+
+				if (cl_sounding_is_sta_codebook_size_75_capable(cl_hw, cl_sta)) {
+					curr_fb_type_ng_cb_size =
+						FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_7_5;
+				} else if (cl_sounding_is_sta_ng_16_capable(cl_hw, cl_sta, true)) {
+					curr_fb_type_ng_cb_size =
+						FEEDBACK_TYPE_MU_NG_16_CODEBOOK_SIZE_9_7;
+				} else {
+					curr_fb_type_ng_cb_size =
+						FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+					mu_fb_type_ng_cb_size =
+						FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7;
+					min_sts--;
+				}
+
+				if ((SOUNDING_NG_VAL(curr_fb_type_ng_cb_size) >
+							SOUNDING_NG_VAL(mu_fb_type_ng_cb_size)) ||
+				    (SOUNDING_CODEBOOK_SIZE_VAL(curr_fb_type_ng_cb_size) <
+				     SOUNDING_CODEBOOK_SIZE_VAL(mu_fb_type_ng_cb_size)))
+					mu_fb_type_ng_cb_size = curr_fb_type_ng_cb_size;
+			}
+
+			info_per_sta[i].fb_type_ng_cb_size = mu_fb_type_ng_cb_size;
+			break;
+		default:
+			sounding_pr_trace("Invalid sounding type %u\n", sounding_type);
+			break;
+		}
+	}
+
+	*n_sts = min_sts;
+
+	if (should_update_fb_type_ng_cb_size)
+		for (i = 0; i < sta_num; i++)
+			info_per_sta[i].fb_type_ng_cb_size = mu_fb_type_ng_cb_size;
+}
+
+static struct cl_sounding_info *cl_sounding_elem_alloc(struct cl_hw *cl_hw, u32 v_mat_len)
+{
+	struct cl_sounding_info *elem = NULL;
+	dma_addr_t phys_dma_addr;
+	struct v_matrix_header *buf = NULL;
+
+	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+
+	if (!elem) {
+		CL_DBG(cl_hw, DBG_LVL_ERROR, "kzalloc failed\n");
+		return NULL;
+	}
+
+	buf = dma_alloc_coherent(cl_hw->chip->dev, v_mat_len, &phys_dma_addr, GFP_KERNEL);
+
+	if (!buf) {
+		CL_DBG(cl_hw, DBG_LVL_ERROR, "dma_alloc_coherent failed. size=%u\n", v_mat_len);
+		kfree(elem);
+		return NULL;
+	}
+
+	elem->v_matrices_data = buf;
+	elem->v_matrices_dma_addr = phys_dma_addr;
+	elem->v_matrices_data_len = v_mat_len;
+
+	return elem;
+}
+
+static void cl_sounding_elem_free(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	struct v_matrix_header *v_data = elem->v_matrices_data;
+
+	if (v_data) {
+		dma_free_coherent(cl_hw->chip->dev, elem->v_matrices_data_len, (void *)v_data,
+				  elem->v_matrices_dma_addr);
+	} else {
+		sounding_pr_err("%s: v_matrices_data is NULL for sid %u\n",
+				__func__, elem->sounding_id);
+	}
+
+	elem->v_matrices_data = NULL;
+	kfree(elem);
+}
+
+static void cl_sounding_req_success(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	cl_bf_sounding_req_success(cl_hw, elem);
+}
+
+static void cl_sounding_req_failure(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	cl_bf_sounding_req_failure(cl_hw, elem);
+}
+
+static void cl_sounding_increase_num_profiles(struct cl_hw *cl_hw, u8 sounding_type, u8 sta_num)
+{
+	if (SOUNDING_TYPE_IS_CQI(sounding_type))
+		cl_hw->sounding.cqi_profiles += sta_num;
+	else
+		cl_hw->sounding.active_profiles += sta_num;
+}
+
+static void cl_sounding_decrease_num_profiles(struct cl_hw *cl_hw, u8 sounding_type, u8 sta_num)
+{
+	if (SOUNDING_TYPE_IS_CQI(sounding_type))
+		cl_hw->sounding.cqi_profiles -= sta_num;
+	else
+		cl_hw->sounding.active_profiles -= sta_num;
+}
+
+static void _cl_sounding_add(struct cl_hw *cl_hw, struct cl_sounding_info *elem, u8 sounding_id,
+			     u32 req_xmem)
+{
+	write_lock_bh(&cl_hw->sounding.list_lock);
+	elem->sounding_id = sounding_id;
+	elem->xmem_space = req_xmem;
+	cl_hw->chip->xmem_db.total_used += req_xmem;
+	cl_hw->sounding.num_soundings++;
+	list_add_tail(&elem->list, &cl_hw->sounding.head);
+	cl_sounding_increase_num_profiles(cl_hw, elem->type, elem->sta_num);
+	write_unlock_bh(&cl_hw->sounding.list_lock);
+}
+
+static void cl_sounding_remove_from_list(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	/* Remove the sounding sequence from the list and update the XMEM and profile counters */
+	write_lock_bh(&cl_hw->sounding.list_lock);
+	list_del(&elem->list);
+	cl_hw->chip->xmem_db.total_used -= elem->xmem_space;
+	cl_hw->sounding.num_soundings--;
+	cl_sounding_decrease_num_profiles(cl_hw, elem->type, elem->sta_num);
+	write_unlock_bh(&cl_hw->sounding.list_lock);
+}
+
+static void cl_sounding_remove_recovery(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	u8 i;
+
+	cl_sounding_remove_from_list(cl_hw, elem);
+
+	{
+		/* Set invalid sid for all STAs related to this sounding sequence */
+		for (i = 0; i < elem->sta_num; i++) {
+			struct cl_sta *cl_sta = elem->su_cl_sta_arr[i];
+
+			if (cl_sta)
+				cl_sta->su_sid = INVALID_SID;
+		}
+	}
+
+	/* Free the deleted sounding element */
+	cl_sounding_elem_free(cl_hw, elem);
+}
+
+static void cl_sounding_start_handler(struct cl_hw *cl_hw, struct sounding_work_data *data)
+{
+	struct mm_sounding_req sounding_req;
+	struct mm_sounding_cfm *cfm = NULL;
+	int ret = 0;
+	u32 len = 0;
+	u32 req_xmem = 0;
+	struct cl_sounding_info *elem = NULL;
+	u8 sounding_type = data->sounding_type;
+	u8 bw = data->bw;
+	u8 i, sta_num = 0;
+	u8 q_matrix_bitmap = data->q_matrix_bitmap;
+	u8 min_nsts = 0;
+	struct cl_sta *cl_sta_arr[CL_MU_MAX_STA_PER_GROUP] = {NULL};
+
+	cl_sta_lock_bh(cl_hw);
+
+	for (i = 0; i < data->sta_num; i++) {
+		u8 sta_idx = data->sta_indices[i];
+		struct cl_sta *cl_sta;
+
+		cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+		if (!cl_sta)
+			continue;
+
+		cl_sta_arr[sta_num] = cl_sta;
+		sta_num++;
+	}
+
+	if (!sta_num) {
+		cl_sta_unlock_bh(cl_hw);
+		sounding_pr_err("%s: No STA found!\n", __func__);
+		return;
+	}
+
+	q_matrix_bitmap &= CL_Q_MATRIX_BITMAP_MASK;
+
+	/* Configure sounding request parameters */
+	sounding_req.start = true;
+	sounding_req.sounding_type = sounding_type;
+	sounding_req.req_txbw = bw;
+	sounding_req.sta_num = sta_num;
+	sounding_req.interval = cl_sounding_get_interval(cl_hw);
+	sounding_req.lifetime = cl_sounding_get_lifetime(cl_hw, sounding_req.interval);
+	sounding_req.q_matrix_bitmap = q_matrix_bitmap;
+	cl_sounding_fill_info_per_sta(cl_hw, sounding_type, bw, sta_num, cl_sta_arr,
+				      sounding_req.info_per_sta, &min_nsts);
+	cl_sta_unlock_bh(cl_hw);
+
+	sounding_req.ndp_nsts = min_nsts;
+
+	if (data->is_recovery) {
+		elem = data->elem;
+	} else {
+		/*
+		 * Check if there is enough XMEM space.
+		 * Should be called after filling sounding req struct
+		 */
+		if (!cl_sounding_is_enough_xmem_space(cl_hw, &sounding_req,
+						      sounding_req.info_per_sta, &req_xmem)) {
+			sounding_pr_err("There is not enough space in XMEM!\n");
+			return;
+		}
+
+		/* Should be called after filling info per STA */
+		len = cl_sounding_get_v_matrices_data_size(cl_hw, sounding_req.info_per_sta,
+							   sta_num, bw, min_nsts);
+		elem = cl_sounding_elem_alloc(cl_hw, len);
+
+		if (!elem)
+			return;
+
+		elem->type = sounding_type;
+		elem->bw = bw;
+		elem->sta_num = sta_num;
+		elem->q_matrix_bitmap = q_matrix_bitmap;
+
+		if (data->gid)
+			elem->gid = data->gid;
+		else
+			memcpy(elem->su_cl_sta_arr, cl_sta_arr,
+			       sta_num * sizeof(cl_sta_arr[0]));
+	}
+
+	sounding_req.host_address = cpu_to_le32(elem->v_matrices_dma_addr);
+
+	/* Print request parameters */
+	sounding_pr_trace("Request: start=%u, bfr_lifetime=%u, interval=%u, "
+			   "req_txbw=%u, ndp_nsts=%u, sounding_type=%u\n",
+			   sounding_req.start,
+			   sounding_req.lifetime,
+			   sounding_req.interval,
+			   sounding_req.req_txbw,
+			   sounding_req.ndp_nsts,
+			   sounding_req.sounding_type);
+
+	/* Send message to firmware */
+	ret = cl_msg_tx_sounding(cl_hw, &sounding_req);
+
+	/* Check firmware response */
+	cfm = cl_hw->msg_cfm_params[MM_SOUNDING_CFM];
+	if (ret == 0 && cfm) {
+		ret = cl_sounding_check_response(cl_hw, cfm->param_err);
+
+		if (ret == 0) {
+			if (!data->is_recovery)
+				_cl_sounding_add(cl_hw, elem, cfm->sounding_id, req_xmem);
+
+			cl_sounding_req_success(cl_hw, elem);
+
+			sounding_pr_trace("Sounding %u was enabled successfully\n",
+					  cfm->sounding_id);
+		} else {
+			cl_sounding_req_failure(cl_hw, elem);
+
+			if (data->is_recovery)
+				cl_sounding_remove_recovery(cl_hw, elem);
+		}
+	} else {
+		sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+		cl_sounding_req_failure(cl_hw, elem);
+
+		if (data->is_recovery)
+			cl_sounding_remove_recovery(cl_hw, elem);
+		else
+			cl_sounding_elem_free(cl_hw, elem);
+	}
+
+	/* Free message confirmation */
+	cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_CFM);
+}
+
+static void _cl_sounding_remove(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	u8 i;
+	struct sounding_work_data data = {
+		.cl_hw = cl_hw,
+		.bw = elem->bw,
+		.start = true,
+		.is_recovery = false,
+		.sta_num = 0
+	};
+
+	cl_sounding_remove_from_list(cl_hw, elem);
+
+	/* Update invalid sid for all STAs related to this sounding sequence.
+	 * Also start sounding for STAs that didn't request to stop sounding.
+	 */
+
+	for (i = 0; i < elem->sta_num; i++) {
+		struct cl_sta *cl_sta = elem->su_cl_sta_arr[i];
+
+		if (!cl_sta)
+			continue;
+
+		cl_sta->su_sid = INVALID_SID;
+
+		/* After stopping the multi STA sounding - check if a new sounding is needed */
+		if (elem->sounding_restart_required) {
+			if (!cl_sta->bf_db.sounding_remove_required) {
+				data.sta_indices[data.sta_num] = cl_sta->sta_idx;
+				data.sta_num++;
+			} else {
+				cl_sta->bf_db.sounding_remove_required = false;
+			}
+		}
+	}
+
+	/* Start a new sounding for the remaining stations only when needed */
+	if (data.sta_num) {
+		/* Determine new sounding type */
+		if (SOUNDING_TYPE_IS_CQI(elem->type)) {
+			if (data.sta_num > 1)
+				data.sounding_type = elem->type;
+			else
+				data.sounding_type = SOUNDING_TYPE_HE_CQI;
+		} else if (SOUNDING_TYPE_IS_VHT(elem->type)) {
+			data.sounding_type = SOUNDING_TYPE_VHT_SU;
+		} else {
+			if (data.sta_num > 1)
+				data.sounding_type = SOUNDING_TYPE_HE_SU_TB;
+			else
+				data.sounding_type = SOUNDING_TYPE_HE_SU;
+		}
+
+		cl_sounding_start_handler(cl_hw, &data);
+	}
+
+	/* Free the deleted sounding element */
+	cl_sounding_elem_free(cl_hw, elem);
+}
+
+static void cl_sounding_stop_handler(struct cl_hw *cl_hw, struct cl_sounding_info *elem)
+{
+	struct mm_sounding_req sounding_req;
+	int ret = 0;
+
+	if (!elem) {
+		sounding_pr_err("elem is NULL!!\n");
+		return;
+	}
+
+	/* Configure sounding request parameters */
+	sounding_req.start = false;
+	sounding_req.sounding_type = elem->type;
+	sounding_req.sid = elem->sounding_id;
+
+	/* Print request parameters */
+	sounding_pr_trace("Delete request: sid=%u, sounding_type=%u\n",
+			  elem->sounding_id, elem->type);
+
+	/* Send message to firmware */
+	ret = cl_msg_tx_sounding(cl_hw, &sounding_req);
+
+	/* Check firmware response */
+	if (ret)
+		sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+	else
+		/* Free message confirmation */
+		cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_CFM);
+
+	/* Remove the sounding sequence from the list and update the used XMEM counter.
+	 * Notice that elem is freed and shouldn't be accessed after the call to this function.
+	 */
+	_cl_sounding_remove(cl_hw, elem);
+}
+
+static void cl_sounding_handler_send_request(struct work_struct *work)
+{
+	struct sounding_work_data *data = (struct sounding_work_data *)work;
+	struct cl_hw *cl_hw = data->cl_hw;
+
+	if (data->start) {
+		cl_sounding_start_handler(cl_hw, data);
+	} else {
+		u8 sid;
+
+		{
+			u8 sta_idx = data->sta_indices[0];
+			struct cl_sta *cl_sta;
+
+			cl_sta_lock_bh(cl_hw);
+			cl_sta = cl_sta_get(cl_hw, sta_idx);
+			sid = cl_sta ? cl_sta->su_sid : U8_MAX;
+			cl_sta_unlock_bh(cl_hw);
+		}
+
+		if (data->elem)
+			cl_sounding_stop_handler(cl_hw, data->elem);
+		else
+			cl_sounding_stop_by_sid(cl_hw, sid, false);
+	}
+
+	kfree(data);
+}
+
+static u16 cl_sounding_calc_interval(struct cl_hw *cl_hw, u8 active_profiles)
+{
+	/* Sounding interval = min interval + [(active_profiles - 1) / STA step] * interval step */
+
+	u16 *coefs = cl_hw->conf->ce_sounding_interval_coefs;
+	u16 min_interval = coefs[SOUNDING_INTERVAL_COEF_MIN_INTERVAL];
+	u16 max_interval = coefs[SOUNDING_INTERVAL_COEF_MAX_INTERVAL];
+	u8 sta_step = coefs[SOUNDING_INTERVAL_COEF_STA_STEP];
+	u8 interval_step = coefs[SOUNDING_INTERVAL_COEF_INTERVAL_STEP];
+	u16 ret = min_interval;
+
+	if (active_profiles <= sta_step)
+		return ret;
+
+	active_profiles--;
+	ret += (active_profiles / sta_step) * interval_step;
+
+	return min(ret, max_interval);
+}
+
+static void cl_sounding_handler_change_interval(struct work_struct *work)
+{
+	struct sounding_work_data *data = (struct sounding_work_data *)work;
+	struct cl_hw *cl_hw = data->cl_hw;
+	struct mm_sounding_interval_cfm *sounding_interval_cfm = NULL;
+	int ret = 0;
+	/* Configure sounding request parameters */
+	u16 interval = cl_sounding_get_interval(cl_hw);
+	u16 lifetime = cl_sounding_get_lifetime(cl_hw, interval);
+
+	sounding_pr_trace("Sounding interval request: sta_idx=%d, interval=%u, "
+			  "lifetime=%u, sounding_type=%u\n",
+			  CL_SOUNDING_ALL_STA, interval, lifetime, data->sounding_type);
+
+	/* Start/Stop synchronize sounding request periodically */
+	ret = cl_msg_tx_sounding_interval(cl_hw, interval, lifetime, data->sounding_type,
+					  CL_SOUNDING_ALL_STA);
+	sounding_interval_cfm = cl_hw->msg_cfm_params[MM_SOUNDING_INTERVAL_CFM];
+	if (ret == 0 && sounding_interval_cfm)
+		cl_sounding_check_response(cl_hw, sounding_interval_cfm->param_err);
+	else
+		sounding_pr_err("%s: failed to send message (%d)\n", __func__, ret);
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_SOUNDING_INTERVAL_CFM);
+	kfree(data);
+}
+
+static void cl_sounding_recovery_reset(struct cl_hw *cl_hw)
+{
+	struct cl_sounding_db *sounding_db = &cl_hw->sounding;
+
+	memset(sounding_db->active_profiles_prev, 0, sizeof(u8) * CL_SOUNDING_STABILITY_TIME);
+	sounding_db->active_profiles_idx = 0;
+	cl_sta_loop(cl_hw, cl_bf_reset_sounding_ind);
+}
+
+void cl_sounding_init(struct cl_hw *cl_hw)
+{
+	struct cl_sounding_db *sounding_db = &cl_hw->sounding;
+
+	memset(sounding_db, 0, sizeof(*sounding_db));
+	sounding_db->sounding_wq = create_workqueue("cl_sounding_wq");
+	sounding_db->current_interval =
+		cl_hw->conf->ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MIN_INTERVAL];
+	sounding_db->dbg_level = 1;
+	cl_hw->chip->xmem_db.size = XMEM_SIZE;
+	INIT_LIST_HEAD(&sounding_db->head);
+	rwlock_init(&sounding_db->list_lock);
+}
+
+void cl_sounding_close(struct cl_hw *cl_hw)
+{
+	struct cl_sounding_info *elem, *tmp;
+
+	if (cl_hw->sounding.sounding_wq)
+		destroy_workqueue(cl_hw->sounding.sounding_wq);
+
+	list_for_each_entry_safe(elem, tmp, &cl_hw->sounding.head, list) {
+		/* Don't try to start a new sounding sequence after stopping this one */
+		elem->sounding_restart_required = false;
+		cl_sounding_stop_handler(cl_hw, elem);
+	}
+}
+
+struct cl_sounding_info *cl_sounding_get_elem(struct cl_hw *cl_hw, u8 sounding_id)
+{
+	struct cl_sounding_info *elem = NULL;
+
+	read_lock_bh(&cl_hw->sounding.list_lock);
+
+	list_for_each_entry(elem, &cl_hw->sounding.head, list) {
+		if (elem->sounding_id == sounding_id) {
+			read_unlock_bh(&cl_hw->sounding.list_lock);
+			return elem;
+		}
+	}
+
+	read_unlock_bh(&cl_hw->sounding.list_lock);
+
+	return NULL;
+}
+
+void cl_sounding_send_request(struct cl_hw *cl_hw, struct cl_sta **cl_sta_arr,
+			      u8 sta_num, bool enable, u8 sounding_type, u8 bw,
+			      void *mu_grp,
+			      u8 q_matrix_bitmap, struct cl_sounding_info *recovery_elem)
+{
+	struct sounding_work_data *data;
+	struct cl_sounding_info *elem = NULL;
+	u8 i;
+	struct cl_sta *cl_sta = NULL;
+	bool background = (preempt_count() != 0);
+
+	if (cl_band_is_24g(cl_hw) && SOUNDING_TYPE_IS_VHT(sounding_type)) {
+		sounding_pr_err("A VHT sounding type (%u) is not supported in 2.4g band\n",
+				sounding_type);
+		return;
+	}
+
+	/*
+	 * When Multiple STAs are members of a single sounding process, that is about to be stopped,
+	 * we want to schedule the stopping work only once and possibly start another sounding
+	 * sequence for STAs that still want to use it.
+	 */
+	if (enable)
+		goto next;
+
+	cl_sta = cl_sta_arr[0];
+	if (cl_sta) {
+		u8 sid = cl_sta->su_sid;
+
+		if (sid != INVALID_SID) {
+			elem = cl_sounding_get_elem(cl_hw, sid);
+
+			if (!elem) {
+				sounding_pr_trace("Sounding %u not found\n", sid);
+				return;
+			}
+
+			cl_sta->bf_db.sounding_remove_required = true;
+
+			if (elem->sounding_restart_required)
+				return;
+			elem->sounding_restart_required = true;
+		}
+	}
+
+next:
+	/* data will be freed in work handler */
+	data = kzalloc(sizeof(*data), GFP_ATOMIC);
+
+	if (!data)
+		return;
+
+	data->cl_hw = cl_hw;
+	data->start = enable;
+	data->sounding_type = sounding_type;
+	data->bw = bw;
+	data->is_recovery = cl_recovery_in_progress(cl_hw);
+	data->elem = recovery_elem ? recovery_elem : elem;
+
+	/* Fill cl_sta_arr */
+	{
+		for (i = 0; i < sta_num; i++)
+			data->sta_indices[i] = cl_sta_arr[i]->sta_idx;
+
+		data->sta_num = sta_num;
+	}
+
+	if (background) {
+		INIT_WORK(&data->work, cl_sounding_handler_send_request);
+		queue_work(cl_hw->sounding.sounding_wq, &data->work);
+	} else {
+		cl_sounding_handler_send_request((struct work_struct *)data);
+	}
+}
+
+static void cl_sounding_change_interval(struct cl_hw *cl_hw, u8 sounding_type)
+{
+	/* Data will be freed in work handler */
+	struct sounding_work_data *data = kzalloc(sizeof(*data), GFP_ATOMIC);
+
+	if (!data)
+		return;
+
+	INIT_WORK(&data->work, cl_sounding_handler_change_interval);
+	data->cl_hw = cl_hw;
+	data->sounding_type = sounding_type;
+	queue_work(cl_hw->sounding.sounding_wq, &data->work);
+}
+
+void cl_sounding_stop_by_sid(struct cl_hw *cl_hw, u8 sid, bool sounding_restart_check)
+{
+	struct cl_sounding_info *elem = cl_sounding_get_elem(cl_hw, sid);
+
+	if (!elem) {
+		sounding_pr_trace("Sounding with id %u not found or is in the middle of removal\n",
+				  sid);
+		return;
+	}
+
+	elem->sounding_restart_required = sounding_restart_check;
+	cl_sounding_stop_handler(cl_hw, elem);
+}
+
+void cl_sounding_maintenance(struct cl_hw *cl_hw)
+{
+	/*
+	 * Change sounding_index accoording to number of active_profiles.
+	 * sounding_index is modified only if number of active_profiles is stable for 5 seconds.
+	 *
+	 * Examples:
+	 * e.g #1: active_profiles=2, active_profiles_prev=3,3,3,3,3 - stabilised on 3
+	 * e.g #3: active_profiles=2, active_profiles_prev=1,1,1,1,1 - stabilised on 1
+	 * e.g #2: active_profiles=5, active_profiles_prev=6,7,7,6,6 - stabilised on 6
+	 * e.g #4: active_profiles=5, active_profiles_prev=4,3,3,2,4 - stabilised on 4
+	 */
+
+	int i = 0;
+	u8 active_profiles_min = 255;
+	u8 active_profiles_max = 0;
+	u8 active_profiles = cl_hw->sounding.last_conf_active_profiles;
+	u8 active_profiles_new = 0;
+	u16 interval;
+	u16 interval_new;
+
+	/* Add to last 5 sec buffer */
+	cl_hw->sounding.active_profiles_prev[cl_hw->sounding.active_profiles_idx] =
+		cl_hw->sounding.active_profiles;
+
+	/* Increase cyclic index */
+	cl_hw->sounding.active_profiles_idx++;
+	if (cl_hw->sounding.active_profiles_idx == CL_SOUNDING_STABILITY_TIME)
+		cl_hw->sounding.active_profiles_idx = 0;
+
+	/* Find active_profiles min/max in last 5 seconds */
+	for (i = 0; i < CL_SOUNDING_STABILITY_TIME; i++) {
+		if (cl_hw->sounding.active_profiles_prev[i] < active_profiles_min)
+			active_profiles_min = cl_hw->sounding.active_profiles_prev[i];
+
+		if (cl_hw->sounding.active_profiles_prev[i] > active_profiles_max)
+			active_profiles_max = cl_hw->sounding.active_profiles_prev[i];
+	}
+
+	if (active_profiles < active_profiles_min)
+		active_profiles_new = active_profiles_min;
+	else if (active_profiles > active_profiles_max)
+		active_profiles_new = active_profiles_max;
+	else /* Active_profiles in last 5 seconds did not change or is not stable */
+		return;
+
+	interval = cl_sounding_calc_interval(cl_hw, active_profiles);
+	interval_new = cl_sounding_calc_interval(cl_hw, active_profiles_new);
+
+	/* Check if sounding interval changed */
+	if (interval != interval_new) {
+		cl_hw->sounding.last_conf_active_profiles = active_profiles_new;
+		cl_hw->sounding.current_interval = interval_new;
+		cl_sounding_change_interval(cl_hw, SOUNDING_TYPE_MAX);
+		sounding_pr_trace("Interval: current = %u, new = %u\n",
+				  interval, interval_new);
+	}
+}
+
+u16 cl_sounding_get_interval(struct cl_hw *cl_hw)
+{
+	return cl_hw->sounding.current_interval;
+}
+
+static void cl_sounding_indication_pr(struct cl_hw *cl_hw,
+				      struct mm_sounding_ind *ind,
+				      struct v_matrix_header *v_matrix,
+				      u8 *avg_snr)
+{
+	sounding_pr_info("Sounding indication: nc index = %u, BFR BW = %u, "
+		  "SNR1 = %u, SNR2 = %u, SNR3 = %u, SNR4 = %u, SNR5 = %u, SNR6 = %u,"
+		  "feedback type = %u, sta index = %u\n",
+		  v_matrix->nc_index, v_matrix->bw,
+		  avg_snr[0], avg_snr[1], avg_snr[2], avg_snr[3], avg_snr[4],
+		  avg_snr[5], ind->sounding_type, ind->sta_idx);
+}
+
+static void cl_sounding_indication_su(struct cl_hw *cl_hw,
+				      struct mm_sounding_ind *ind,
+				      struct cl_sounding_info *sounding_elem)
+{
+	struct cl_sta *cl_sta;
+	struct v_matrix_header *v_matrix = NULL;
+	u8 *avg_snr = NULL;
+	bool pairing = false;
+
+	v_matrix = sounding_elem->v_matrices_data + ind->v_matrix_offset[0];
+	avg_snr = (u8 *)v_matrix + v_matrix->padding;
+
+	cl_sta_lock(cl_hw);
+	cl_sta = cl_sta_get(cl_hw, ind->sta_idx);
+
+	if (cl_sta) {
+		struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+		/* Update Nc for the current STA */
+		bf_db->nc = v_matrix->nc_index;
+		bf_db->sounding_indications++;
+
+		if (bf_db->sounding_indications == 1) {
+			/*
+			 * After getting first indication disable the timer and set the BF
+			 * bit in the firmware rate flags.
+			 */
+			del_timer(&bf_db->timer);
+			cl_bf_update_rate(cl_hw, cl_sta);
+			pairing = true;
+		}
+	}
+
+	cl_sta_unlock(cl_hw);
+
+	/* Send a msg to fw to pair the STA with sounding ID */
+	if (pairing)
+		cl_msg_tx_sounding_pairing(cl_hw, ind->sid, ind->sounding_type, 0, ind->sta_idx);
+
+	cl_sounding_indication_pr(cl_hw, ind, v_matrix, avg_snr);
+}
+
+void cl_sounding_indication(struct cl_hw *cl_hw, struct mm_sounding_ind *ind)
+{
+	struct cl_sounding_info *sounding_elem = NULL;
+
+	sounding_elem = cl_sounding_get_elem(cl_hw, ind->sid);
+
+	if (!sounding_elem) {
+		sounding_pr_err("[%s]: sounding id %u not found!\n", __func__, ind->sid);
+		return;
+	}
+
+	switch (ind->sounding_type) {
+	case SOUNDING_TYPE_HE_SU:
+	case SOUNDING_TYPE_HE_SU_TB:
+	case SOUNDING_TYPE_VHT_SU:
+	case SOUNDING_TYPE_HE_CQI:
+	case SOUNDING_TYPE_HE_CQI_TB:
+		break;
+	default:
+		sounding_pr_err("[%s]: Invalid sounding type %u\n", __func__,
+				ind->sounding_type);
+		return;
+	}
+
+		cl_sounding_indication_su(cl_hw, ind, sounding_elem);
+}
+
+void cl_sounding_recovery(struct cl_hw *cl_hw)
+{
+	/*
+	 * After recovery process we need to update sounding requests and
+	 * sounding interval in firmware
+	 */
+	struct cl_sounding_info *elem;
+
+	/* No sounding is active */
+	if (!cl_hw->sounding.num_soundings)
+		return;
+
+	/* Reset sounding parameters */
+	cl_sounding_recovery_reset(cl_hw);
+
+	/*
+	 * Go over all clients that had sounding before recovery,
+	 * and send a new sounding request to firmware.
+	 */
+
+	sounding_pr_trace("Start sounding recovery\n");
+
+	list_for_each_entry(elem, &cl_hw->sounding.head, list)
+		cl_bf_sounding_start(cl_hw, elem->type, elem->su_cl_sta_arr, elem->sta_num, elem);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 73/96] cl8k: add sounding.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (71 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 72/96] cl8k: add sounding.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 74/96] cl8k: add sta.c viktor.barna
                   ` (22 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sounding.h | 151 ++++++++++++++++++++
 1 file changed, 151 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sounding.h

diff --git a/drivers/net/wireless/celeno/cl8k/sounding.h b/drivers/net/wireless/celeno/cl8k/sounding.h
new file mode 100644
index 000000000000..abdf834150f9
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sounding.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_SOUNDING_H
+#define CL_SOUNDING_H
+
+#include <linux/types.h>
+
+#include "fw.h"
+
+#define SOUNDING_ENABLE                                true
+#define SOUNDING_DISABLE                               false
+#define INVALID_SID                                    0xff
+#define XMEM_SIZE                                      (0x180 << 10) /* 384KB */
+#define CL_SOUNDING_STABILITY_TIME                     5
+#define CL_SOUNDING_FACTOR                             10
+
+#define SOUNDING_FEEDBACK_TYPE_SHIFT                   2
+#define SOUNDING_FEEDBACK_TYPE_MASK                    (BIT(SOUNDING_FEEDBACK_TYPE_SHIFT))
+#define SOUNDING_NG_SHIFT                              1
+#define SOUNDING_NG_MASK                               (BIT(SOUNDING_NG_SHIFT))
+#define SOUNDING_MU_CODEBOOK_SIZE_SHIFT                0
+#define SOUNDING_MU_CODEBOOK_SIZE_MASK                 (BIT(SOUNDING_MU_CODEBOOK_SIZE_SHIFT))
+#define SOUNDING_FEEDBACK_TYPE_VAL(fb_type_ng_cb_size) (((fb_type_ng_cb_size) & \
+							  SOUNDING_FEEDBACK_TYPE_MASK) >> \
+							  SOUNDING_FEEDBACK_TYPE_SHIFT)
+#define SOUNDING_NG_VAL(fb_type_ng_cb_size)            (((fb_type_ng_cb_size) & \
+							  SOUNDING_NG_MASK) >> SOUNDING_NG_SHIFT)
+#define SOUNDING_CODEBOOK_SIZE_VAL(fb_type_ng_cb_size) (((fb_type_ng_cb_size) & \
+							  SOUNDING_MU_CODEBOOK_SIZE_MASK) >> \
+							  SOUNDING_MU_CODEBOOK_SIZE_SHIFT)
+
+#define SOUNDING_TYPE_IS_VHT(type)                     ((type) == SOUNDING_TYPE_VHT_SU || \
+							(type) == SOUNDING_TYPE_VHT_MU)
+#define SOUNDING_TYPE_IS_CQI(type)                     ((type) == SOUNDING_TYPE_HE_CQI || \
+							(type) == SOUNDING_TYPE_HE_CQI_TB)
+
+enum fb_type_ng_cb_size {
+	FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_4_2 = 0x0,
+	FEEDBACK_TYPE_SU_NG_4_CODEBOOK_SIZE_6_4,
+	FEEDBACK_TYPE_SU_NG_16_CODEBOOK_SIZE_4_2,
+	FEEDBACK_TYPE_SU_NG_16_CODEBOOK_SIZE_6_4,
+	FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_7_5,
+	FEEDBACK_TYPE_MU_NG_4_CODEBOOK_SIZE_9_7,
+	FEEDBACK_TYPE_CQI_TB,
+	FEEDBACK_TYPE_MU_NG_16_CODEBOOK_SIZE_9_7,
+};
+
+enum cl_sounding_response {
+	CL_SOUNDING_RSP_OK = 0,
+
+	CL_SOUNDING_RSP_ERR_RLIMIT,
+	CL_SOUNDING_RSP_ERR_BW,
+	CL_SOUNDING_RSP_ERR_NSS,
+	CL_SOUNDING_RSP_ERR_INTERVAL,
+	CL_SOUNDING_RSP_ERR_ALREADY,
+	CL_SOUNDING_RSP_ERR_STA,
+	CL_SOUNDING_RSP_ERR_TYPE,
+};
+
+enum sounding_type {
+	SOUNDING_TYPE_HE_SU = 0,
+	SOUNDING_TYPE_HE_SU_TB,
+	SOUNDING_TYPE_VHT_SU,
+	SOUNDING_TYPE_HE_CQI,
+	SOUNDING_TYPE_HE_CQI_TB,
+	SOUNDING_TYPE_HE_MU,
+	SOUNDING_TYPE_VHT_MU,
+
+	SOUNDING_TYPE_MAX
+};
+
+enum sounding_interval_coef {
+	SOUNDING_INTERVAL_COEF_MIN_INTERVAL = 0,
+	SOUNDING_INTERVAL_COEF_STA_STEP,
+	SOUNDING_INTERVAL_COEF_INTERVAL_STEP,
+	SOUNDING_INTERVAL_COEF_MAX_INTERVAL,
+	SOUNDING_INTERVAL_COEF_MAX
+};
+
+struct v_matrix_header {
+	u32 format        : 2,
+	    rsv1          : 30;
+	u32 bw            : 2,
+	    nr_index      : 3,
+	    nc_index      : 3,
+	    rsv2          : 24;
+	u32 grouping      : 4,
+	    rsv3          : 28;
+	u32 feedback_type : 1,
+	    codebook_info : 3,
+	    rsv4          : 28;
+	u32 ru_start_idx  : 7,
+	    rsv5          : 25;
+	u32 ru_end_idx    : 7,
+	    rsv6          : 25;
+	u32 padding       : 6,
+	    rsv7          : 26;
+	u32 rsv8;
+};
+
+struct cl_sounding_info {
+	enum sounding_type type;
+	u8 sounding_id;
+	struct v_matrix_header *v_matrices_data;
+	u32 v_matrices_data_len;
+	u32 v_matrices_dma_addr;
+	u8 gid;
+	u8 bw;
+	u8 sta_num;
+	u8 q_matrix_bitmap;
+	struct cl_sta *su_cl_sta_arr[CL_MU_MAX_STA_PER_GROUP];
+	u32 xmem_space;
+	bool sounding_restart_required;
+	struct list_head list;
+};
+
+struct cl_sounding_db {
+	struct workqueue_struct *sounding_wq;
+	u8 num_soundings;
+	u8 cqi_profiles; /* Num of STAs with CQI active sounding */
+	u8 active_profiles; /* Num of STAs with non-CQI active sounding */
+	u8 active_profiles_prev[CL_SOUNDING_STABILITY_TIME];
+	u8 active_profiles_idx;
+	u8 dbg_level;
+	u8 current_interval;
+	u8 last_conf_active_profiles;
+	rwlock_t list_lock;
+	struct list_head head;
+};
+
+struct cl_xmem {
+	u32 total_used;
+	u32 size;
+};
+
+void cl_sounding_init(struct cl_hw *cl_hw);
+void cl_sounding_close(struct cl_hw *cl_hw);
+void cl_sounding_send_request(struct cl_hw *cl_hw, struct cl_sta **cl_sta_arr,
+			      u8 sta_num, bool enable, u8 sounding_type, u8 bw,
+			      void *mu_grp,
+			      u8 q_matrix_bitmap, struct cl_sounding_info *recovery_elem);
+void cl_sounding_switch_profile(struct cl_hw *cl_hw, u8 sta_idx_en, u8 sta_idx_dis);
+void cl_sounding_stop_by_sid(struct cl_hw *cl_hw, u8 sid, bool sounding_restart_check);
+void cl_sounding_maintenance(struct cl_hw *cl_hw);
+u16 cl_sounding_get_interval(struct cl_hw *cl_hw);
+void cl_sounding_recovery(struct cl_hw *cl_hw);
+struct cl_sounding_info *cl_sounding_get_elem(struct cl_hw *cl_hw, u8 sounding_id);
+void cl_sounding_indication(struct cl_hw *cl_hw, struct mm_sounding_ind *ind);
+
+#endif /* CL_SOUNDING_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 74/96] cl8k: add sta.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (72 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 73/96] cl8k: add sounding.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 75/96] cl8k: add sta.h viktor.barna
                   ` (21 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sta.c | 507 +++++++++++++++++++++++++
 1 file changed, 507 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.c

diff --git a/drivers/net/wireless/celeno/cl8k/sta.c b/drivers/net/wireless/celeno/cl8k/sta.c
new file mode 100644
index 000000000000..26c280b05266
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sta.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "phy.h"
+#include "bf.h"
+#include "vns.h"
+#include "tx.h"
+#include "radio.h"
+#include "motion_sense.h"
+#include "mac_addr.h"
+#include "recovery.h"
+#include "dfs.h"
+#include "stats.h"
+#include "utils.h"
+#include "sta.h"
+
+void cl_sta_init(struct cl_hw *cl_hw)
+{
+	u32 i;
+
+	rwlock_init(&cl_hw->cl_sta_db.lock);
+	INIT_LIST_HEAD(&cl_hw->cl_sta_db.head);
+
+	for (i = 0; i < CL_STA_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&cl_hw->cl_sta_db.hash[i]);
+}
+
+void cl_sta_init_sta(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+	if (!cl_recovery_in_progress(cl_hw)) {
+		struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+		/* Reset all cl_sta strcture */
+		memset(cl_sta, 0, sizeof(struct cl_sta));
+		cl_sta->sta = sta;
+		/*
+		 * Set sta_idx to 0xFF since FW expects this value as long as
+		 * the STA is not fully connected
+		 */
+		cl_sta->sta_idx = STA_IDX_INVALID;
+	}
+}
+
+static void cl_sta_add_to_lut(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cl_sta *cl_sta)
+{
+	write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+	cl_hw->cl_sta_db.num++;
+	cl_vif->num_sta++;
+	cl_hw->cl_sta_db.lut[cl_sta->sta_idx] = cl_sta;
+
+	/* Done here inside the lock because it allocates cl_stats */
+	cl_stats_sta_add(cl_hw, cl_sta);
+
+	write_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+	cl_dbg_verbose(cl_hw, "mac=%pM, sta_idx=%u, vif_index=%u\n",
+		       cl_sta->addr, cl_sta->sta_idx, cl_sta->cl_vif->vif_index);
+}
+
+static void cl_sta_add_to_list(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	u8 hash_idx = CL_STA_HASH_IDX(cl_sta->addr[5]);
+
+	write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+	/* Add to hash table */
+	list_add(&cl_sta->list_hash, &cl_hw->cl_sta_db.hash[hash_idx]);
+
+	/* Make sure that cl_sta's are stored in the list according to their sta_idx. */
+	if (list_empty(&cl_hw->cl_sta_db.head)) {
+		list_add(&cl_sta->list, &cl_hw->cl_sta_db.head);
+	} else if (list_is_singular(&cl_hw->cl_sta_db.head)) {
+		struct cl_sta *cl_sta_singular =
+			list_first_entry(&cl_hw->cl_sta_db.head, struct cl_sta, list);
+
+		if (cl_sta_singular->sta_idx < cl_sta->sta_idx)
+			list_add_tail(&cl_sta->list, &cl_hw->cl_sta_db.head);
+		else
+			list_add(&cl_sta->list, &cl_hw->cl_sta_db.head);
+	} else {
+		struct cl_sta *cl_sta_last =
+			list_last_entry(&cl_hw->cl_sta_db.head, struct cl_sta, list);
+
+		if (cl_sta->sta_idx > cl_sta_last->sta_idx) {
+			list_add_tail(&cl_sta->list, &cl_hw->cl_sta_db.head);
+		} else {
+			struct cl_sta *cl_sta_next = NULL;
+			struct cl_sta *cl_sta_prev = NULL;
+
+			list_for_each_entry(cl_sta_next, &cl_hw->cl_sta_db.head, list) {
+				if (cl_sta_next->sta_idx < cl_sta->sta_idx)
+					continue;
+
+				cl_sta_prev = list_prev_entry(cl_sta_next, list);
+				__list_add(&cl_sta->list, &cl_sta_prev->list, &cl_sta_next->list);
+				break;
+			}
+		}
+	}
+
+	write_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+	cl_sta->add_complete = true;
+}
+
+static void cl_connection_data_add(struct cl_vif *cl_vif)
+{
+	struct cl_connection_data *conn_data = cl_vif->conn_data;
+
+	if (cl_vif->num_sta > conn_data->max_client) {
+		conn_data->max_client = cl_vif->num_sta;
+		conn_data->max_client_timestamp = ktime_get_real_seconds();
+	}
+
+	if (cl_vif->num_sta == conn_data->watermark_threshold)
+		conn_data->watermark_reached_cnt++;
+}
+
+static void cl_connection_data_remove(struct cl_vif *cl_vif)
+{
+	struct cl_connection_data *conn_data = cl_vif->conn_data;
+
+	if (cl_vif->num_sta == conn_data->watermark_threshold)
+		conn_data->watermark_reached_cnt++;
+}
+
+static void _cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+	/* !!! Must be first !!! */
+	cl_sta_add_to_lut(cl_hw, cl_vif, cl_sta);
+
+	cl_baw_init(cl_sta);
+	cl_txq_sta_add(cl_hw, cl_sta);
+	cl_vns_sta_add(cl_hw, cl_sta);
+	cl_connection_data_add(cl_vif);
+
+	/*
+	 * Add rssi of association request to rssi pool
+	 * Make sure to call it before cl_wrs_api_sta_add()
+	 */
+	cl_rssi_assoc_find(cl_hw, cl_sta, cl_hw->cl_sta_db.num);
+
+	cl_motion_sense_sta_add(cl_hw, cl_sta);
+	cl_bf_sta_add(cl_hw, cl_sta, sta);
+	cl_wrs_api_sta_add(cl_hw, sta);
+	cl_wrs_api_set_smps_mode(cl_hw, sta, sta->bandwidth);
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	/* Should be called after cl_wrs_api_sta_add() */
+	cl_dyn_mcast_rate_update_upon_assoc(cl_hw, cl_sta->wrs_sta.mode,
+					    cl_hw->cl_sta_db.num);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_update_upon_assoc(cl_hw,
+					    cl_sta->wrs_sta.tx_su_params.rate_params.mcs,
+					    cl_hw->cl_sta_db.num);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+
+	/* !!! Must be last !!! */
+	cl_sta_add_to_list(cl_hw, cl_sta);
+}
+
+/*
+ * Parse the ampdu density to retrieve the value in usec, according to
+ * the values defined in ieee80211.h
+ */
+static u8 cl_sta_density2usec(u8 ampdu_density)
+{
+	switch (ampdu_density) {
+	case IEEE80211_HT_MPDU_DENSITY_NONE:
+		return 0;
+		/* 1 microsecond is our granularity */
+	case IEEE80211_HT_MPDU_DENSITY_0_25:
+	case IEEE80211_HT_MPDU_DENSITY_0_5:
+	case IEEE80211_HT_MPDU_DENSITY_1:
+		return 1;
+	case IEEE80211_HT_MPDU_DENSITY_2:
+		return 2;
+	case IEEE80211_HT_MPDU_DENSITY_4:
+		return 4;
+	case IEEE80211_HT_MPDU_DENSITY_8:
+		return 8;
+	case IEEE80211_HT_MPDU_DENSITY_16:
+		return 16;
+	default:
+		return 0;
+	}
+}
+
+static void cl_sta_set_min_spacing(struct cl_hw *cl_hw,
+				   struct ieee80211_sta *sta)
+{
+	bool is_6g = cl_band_is_6g(cl_hw);
+	u8 sta_min_spacing = 0;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+	if (is_6g)
+		sta_min_spacing =
+			cl_sta_density2usec(le16_get_bits(sta->he_6ghz_capa.capa,
+							  IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START));
+	else if (sta->ht_cap.ht_supported)
+		sta_min_spacing =
+			cl_sta_density2usec(sta->ht_cap.ampdu_density);
+	else
+		cl_dbg_err(cl_hw, "HT is not supported - cannot set sta_min_spacing\n");
+
+	cl_sta->ampdu_min_spacing =
+		max(cl_sta_density2usec(IEEE80211_HT_MPDU_DENSITY_1), sta_min_spacing);
+}
+
+u32 cl_sta_num(struct cl_hw *cl_hw)
+{
+	u32 num = 0;
+
+	read_lock(&cl_hw->cl_sta_db.lock);
+	num = cl_hw->cl_sta_db.num;
+	read_unlock(&cl_hw->cl_sta_db.lock);
+
+	return num;
+}
+
+u32 cl_sta_num_bh(struct cl_hw *cl_hw)
+{
+	u32 num = 0;
+
+	read_lock_bh(&cl_hw->cl_sta_db.lock);
+	num = cl_hw->cl_sta_db.num;
+	read_unlock_bh(&cl_hw->cl_sta_db.lock);
+
+	return num;
+}
+
+struct cl_sta *cl_sta_get(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	if (sta_idx < CL_MAX_NUM_STA)
+		return cl_hw->cl_sta_db.lut[sta_idx];
+
+	return NULL;
+}
+
+struct cl_sta *cl_sta_get_by_addr(struct cl_hw *cl_hw, u8 *addr)
+{
+	struct cl_sta *cl_sta = NULL;
+	u8 hash_idx = CL_STA_HASH_IDX(addr[5]);
+
+	if (is_multicast_ether_addr(addr))
+		return NULL;
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.hash[hash_idx], list_hash)
+		if (cl_mac_addr_compare(cl_sta->addr, addr))
+			return cl_sta;
+
+	return NULL;
+}
+
+void cl_sta_loop(struct cl_hw *cl_hw, sta_callback callback)
+{
+	struct cl_sta *cl_sta = NULL;
+
+	/* Go over all stations */
+	read_lock(&cl_hw->cl_sta_db.lock);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+		callback(cl_hw, cl_sta);
+
+	read_unlock(&cl_hw->cl_sta_db.lock);
+}
+
+void cl_sta_loop_bh(struct cl_hw *cl_hw, sta_callback callback)
+{
+	struct cl_sta *cl_sta = NULL;
+
+	/* Go over all stations - use bottom-half lock */
+	read_lock_bh(&cl_hw->cl_sta_db.lock);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list)
+		callback(cl_hw, cl_sta);
+
+	read_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+static int cl_sta_add_to_firmware(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+				  struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	struct mm_sta_add_cfm *sta_add_cfm;
+	int error = 0;
+	u8 recovery_sta_idx = 0;
+	u32 rate_ctrl_info = 0;
+
+	if (cl_recovery_in_progress(cl_hw)) {
+		struct cl_wrs_rate_params *rate_params = &cl_sta->wrs_sta.tx_su_params.rate_params;
+
+		/*
+		 * If station is added to firmware during recovery, the driver passes to firmware
+		 * the station index to be used instead of firmware selecting a free index
+		 */
+		recovery_sta_idx = cl_sta->sta_idx;
+
+		/* Keep current rate value */
+		rate_ctrl_info = cl_rate_ctrl_generate(cl_hw, cl_sta, rate_params->mode,
+						       rate_params->bw, rate_params->nss,
+						       rate_params->mcs, rate_params->gi,
+						       false, false);
+	} else {
+		bool is_cck = cl_band_is_24g(cl_hw) && cl_hw_mode_is_b_or_bg(cl_hw);
+		u8 mode = is_cck ? WRS_MODE_CCK : WRS_MODE_OFDM;
+
+		/*
+		 * Not in recovery:
+		 * firmware will set sta_idx and will return in confirmation message
+		 */
+		recovery_sta_idx = STA_IDX_INVALID;
+
+		/* Default rate value */
+		rate_ctrl_info = cl_rate_ctrl_generate(cl_hw, cl_sta, mode,
+						       0, 0, 0, 0, false, false);
+	}
+
+	/* Must be called before cl_msg_tx_sta_add() */
+	cl_sta_set_min_spacing(cl_hw, sta);
+
+	/* Send message to firmware */
+	error = cl_msg_tx_sta_add(cl_hw, sta, cl_vif, recovery_sta_idx, rate_ctrl_info);
+	if (error)
+		return error;
+
+	sta_add_cfm = (struct mm_sta_add_cfm *)(cl_hw->msg_cfm_params[MM_STA_ADD_CFM]);
+	if (!sta_add_cfm)
+		return -ENOMSG;
+
+	if (sta_add_cfm->status != 0) {
+		cl_dbg_verbose(cl_hw, "Status Error (%u)\n", sta_add_cfm->status);
+		cl_msg_tx_free_cfm_params(cl_hw, MM_STA_ADD_CFM);
+		return -EIO;
+	}
+
+	/* Save the index retrieved from firmware */
+	cl_sta->sta_idx = sta_add_cfm->sta_idx;
+
+	/* Release cfm msg */
+	cl_msg_tx_free_cfm_params(cl_hw, MM_STA_ADD_CFM);
+
+	return 0;
+}
+
+int cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+	       struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	int error = 0;
+
+	if (cl_radio_is_going_down(cl_hw))
+		return -EPERM;
+
+	if (vif->type == NL80211_IFTYPE_MESH_POINT &&
+	    cl_vif->num_sta >= CL_MAX_NUM_MESH_POINT)
+		return -EPERM;
+
+	cl_sta->cl_vif = cl_vif;
+	cl_mac_addr_copy(cl_sta->addr, sta->addr);
+
+	error = cl_sta_add_to_firmware(cl_hw, vif, sta);
+	if (error)
+		return error;
+
+	if (!cl_recovery_in_progress(cl_hw))
+		if (vif->type != NL80211_IFTYPE_STATION ||
+		    cl_hw->chip->conf->ce_production_mode)
+			_cl_sta_add(cl_hw, vif, sta);
+
+	if (vif->type == NL80211_IFTYPE_MESH_POINT && cl_vif->num_sta == 1)
+		set_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags);
+
+	return 0;
+}
+
+void cl_sta_mgd_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct ieee80211_sta *sta)
+{
+	/* Should be called in station mode */
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+
+	/* !!! Must be first !!! */
+	cl_sta_add_to_lut(cl_hw, cl_vif, cl_sta);
+
+	cl_baw_init(cl_sta);
+	cl_txq_sta_add(cl_hw, cl_sta);
+	cl_vns_sta_add(cl_hw, cl_sta);
+
+	/*
+	 * Add rssi of association response to rssi pool
+	 * Make sure to call it before cl_wrs_api_sta_add()
+	 */
+	cl_rssi_assoc_find(cl_hw, cl_sta, cl_hw->cl_sta_db.num);
+
+	cl_connection_data_add(cl_vif);
+
+	/* In station mode we assume that the AP we connect to is static */
+	cl_motion_sense_sta_add(cl_hw, cl_sta);
+	cl_bf_sta_add(cl_hw, cl_sta, sta);
+	cl_wrs_api_sta_add(cl_hw, sta);
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	/* Should be called after cl_wrs_api_sta_add() */
+	cl_dyn_mcast_rate_update_upon_assoc(cl_hw, cl_sta->wrs_sta.mode,
+					    cl_hw->cl_sta_db.num);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_update_upon_assoc(cl_hw,
+					    cl_sta->wrs_sta.tx_su_params.rate_params.mcs,
+					    cl_hw->cl_sta_db.num);
+
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+	/* !!! Must be last !!! */
+	cl_sta_add_to_list(cl_hw, cl_sta);
+}
+
+static void _cl_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	write_lock_bh(&cl_hw->cl_sta_db.lock);
+
+	list_del(&cl_sta->list);
+	list_del(&cl_sta->list_hash);
+
+	cl_hw->cl_sta_db.lut[cl_sta->sta_idx] = NULL;
+	cl_hw->cl_sta_db.num--;
+	cl_sta->cl_vif->num_sta--;
+
+	cl_dbg_verbose(cl_hw, "mac=%pM, sta_idx=%u, vif_index=%u\n",
+		       cl_sta->addr, cl_sta->sta_idx, cl_sta->cl_vif->vif_index);
+
+	write_unlock_bh(&cl_hw->cl_sta_db.lock);
+}
+
+void cl_sta_remove(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+	struct cl_vif *cl_vif = (struct cl_vif *)vif->drv_priv;
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+	u8 sta_idx = cl_sta->sta_idx;
+
+	cl_sta->remove_start = true;
+
+	/* !!! Must be first - remove from list and LUT !!! */
+	_cl_sta_remove(cl_hw, cl_sta);
+
+	cl_traffic_sta_remove(cl_hw, cl_sta);
+	cl_bf_sta_remove(cl_hw, cl_sta);
+	cl_connection_data_remove(cl_vif);
+#ifdef CONFIG_CL8K_DYN_MCAST_RATE
+	cl_dyn_mcast_rate_update_upon_disassoc(cl_hw,
+					       cl_sta->wrs_sta.mode,
+					       cl_hw->cl_sta_db.num);
+#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+	cl_dyn_bcast_rate_update_upon_disassoc(cl_hw,
+					       cl_sta->wrs_sta.tx_su_params.rate_params.mcs,
+					       cl_hw->cl_sta_db.num);
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+	cl_wrs_api_sta_remove(cl_hw, cl_sta);
+	cl_stats_sta_remove(cl_hw, cl_sta);
+
+	/*
+	 * TX stop flow:
+	 * 1) Flush TX queues
+	 * 2) Poll confirmation queue and clear enhanced TIM
+	 * 3) Send MM_STA_DEL_REQ message to firmware
+	 * 4) Flush confirmation queue
+	 * 5) Reset write index
+	 */
+
+	cl_txq_flush_sta(cl_hw, cl_sta);
+	cl_single_cfm_poll_empty_sta(cl_hw, sta_idx);
+	cl_txq_sta_remove(cl_hw, sta_idx);
+
+	if (cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT &&
+	    cl_vif->num_sta == 0) {
+		clear_bit(CL_DEV_MESH_AP, &cl_hw->drv_flags);
+	}
+
+	cl_single_cfm_flush_sta(cl_hw, sta_idx);
+
+	cl_msg_tx_sta_del(cl_hw, sta_idx);
+
+	if (cl_vif->num_sta == 0)
+		cl_radio_off_wake_up(cl_hw);
+}
+
+void cl_sta_ps_notify(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps)
+{
+	struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+	/*
+	 * PS-Poll & UAPSD are handled by FW, by setting
+	 * WLAN_STA_SP we ensure mac80211 does not re-handle.
+	 * flag is unset at ieee80211_sta_ps_deliver_wakeup
+	 */
+	if (is_ps)
+		set_sta_flag(stainfo, WLAN_STA_SP);
+
+	cl_stats_update_ps(cl_hw, cl_sta, is_ps);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 75/96] cl8k: add sta.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (73 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 74/96] cl8k: add sta.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
                   ` (20 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/sta.h | 99 ++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/sta.h

diff --git a/drivers/net/wireless/celeno/cl8k/sta.h b/drivers/net/wireless/celeno/cl8k/sta.h
new file mode 100644
index 000000000000..f3c6bc743b96
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/sta.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_STA_H
+#define CL_STA_H
+
+#include "sta_info.h"
+#include "mac80211.h"
+#include "rates.h"
+#include "motion_sense.h"
+#include "tx.h"
+#include "traffic.h"
+#include "bf.h"
+#include "vns.h"
+
+#define IEEE80211_STA_TO_CL_STA(sta) ((struct cl_sta *)(sta)->drv_priv)
+#define IEEE80211_STA_TO_STAINFO(ieee80211_sta) (container_of(ieee80211_sta, struct sta_info, sta))
+
+#define CL_MAX_NUM_MESH_POINT 8
+
+/*
+ * Structure used to save information relative to the managed stations.
+ * Will be used as the 'drv_priv' field of the "struct ieee80211_sta" structure.
+ */
+struct cl_sta {
+	struct list_head list;
+	struct list_head list_hash;
+	u8 sta_idx;
+	u8 su_sid;
+	bool key_disable;
+	u8 addr[ETH_ALEN];
+	struct cl_baw baws[IEEE80211_NUM_TIDS];
+	struct cl_amsdu_ctrl amsdu_anchor[IEEE80211_NUM_TIDS];
+	struct cl_tx_queue *agg_tx_queues[IEEE80211_NUM_TIDS];
+	u8 rx_pn[IEEE80211_NUM_TIDS][IEEE80211_CCMP_PN_LEN];
+	struct cl_vif *cl_vif;
+	struct ieee80211_sta *sta;
+	struct ieee80211_key_conf *key_conf;
+	struct cl_bf_sta_db bf_db;
+	struct cl_stats *stats;
+	s32 alpha_rssi;
+	bool manual_alpha_rssi;
+	s8 last_rssi[MAX_ANTENNAS];
+	u8 ampdu_min_spacing;
+	struct cl_traffic_sta traffic_db[TRAFFIC_DIRECTION_MAX];
+	struct cl_traffic_mon traffic_mon[CL_TRFC_MON_PROT_MAX][CL_TRFC_MON_DIR_MAX];
+	struct cl_vns_sta_db vns_db;
+	u32 retry_count;
+	u32 data_pending[AC_MAX];
+	struct cl_wrs_info wrs_info_tx_su;
+	struct cl_wrs_info wrs_info_tx_mu_mimo;
+	struct cl_wrs_info wrs_info_rx;
+	struct cl_wrs_rssi wrs_rssi;
+	bool add_complete;
+	bool remove_start;
+	struct cl_wrs_sta wrs_sta;
+	struct cl_motion_sense motion_sense;
+	union cl_rate_ctrl_info_he rate_ctrl_he;
+	bool tf_support_dis;
+	struct cl_tid_ampdu_rx *tid_agg_rx[IEEE80211_NUM_TIDS];
+	u64 tx_bytes;
+	u64 rx_bytes;
+	bool stop_tx;
+	bool pause_tx;
+
+};
+
+#define CL_STA_HASH_SIZE (CL_MAX_NUM_STA / 2)
+#define CL_STA_HASH_MASK (CL_STA_HASH_SIZE - 1)
+#define CL_STA_HASH_IDX(x) ((x) & CL_STA_HASH_MASK)
+
+struct cl_sta_db {
+	struct list_head head;
+	struct cl_sta *lut[CL_MAX_NUM_STA];
+	struct list_head hash[CL_STA_HASH_SIZE];
+	rwlock_t lock;
+	u32 num;
+};
+
+typedef void (*sta_callback)(struct cl_hw *, struct cl_sta *);
+
+/* These functions take the lock inside */
+u32 cl_sta_num(struct cl_hw *cl_hw);
+u32 cl_sta_num_bh(struct cl_hw *cl_hw);
+
+/* Must take lock before calling these functions */
+struct cl_sta *cl_sta_get(struct cl_hw *cl_hw, u8 sta_idx);
+struct cl_sta *cl_sta_get_by_addr(struct cl_hw *cl_hw, u8 *addr);
+
+void cl_sta_init(struct cl_hw *cl_hw);
+void cl_sta_loop(struct cl_hw *cl_hw, sta_callback callback);
+void cl_sta_loop_bh(struct cl_hw *cl_hw, sta_callback callback);
+void cl_sta_init_sta(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+int cl_sta_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
+void cl_sta_mgd_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct ieee80211_sta *sta);
+void cl_sta_remove(struct cl_hw *cl_hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
+void cl_sta_ps_notify(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps);
+
+#endif /* CL_STA_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 76/96] cl8k: add stats.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (74 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 75/96] cl8k: add sta.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-06-02 20:59   ` Jeff Johnson
  2022-05-24 11:34 ` [RFC v2 77/96] cl8k: add stats.h viktor.barna
                   ` (19 subsequent siblings)
  95 siblings, 1 reply; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/stats.c | 438 +++++++++++++++++++++++
 1 file changed, 438 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.c

diff --git a/drivers/net/wireless/celeno/cl8k/stats.c b/drivers/net/wireless/celeno/cl8k/stats.c
new file mode 100644
index 000000000000..c526199513f4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/stats.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/string.h>
+
+#include "reg/reg_access.h"
+#include "sta.h"
+#include "utils.h"
+#include "reg/reg_defs.h"
+#include "rates.h"
+#include "debug.h"
+#include "tx.h"
+#include "vif.h"
+#include "stats.h"
+
+static void cll_stats_config_ps(struct cl_sta *cl_sta)
+{
+	struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(cl_sta->sta);
+
+	cl_sta->stats->ps.timestamp_sleep = jiffies;
+	cl_sta->stats->ps.is_ps = test_sta_flag(stainfo, WLAN_STA_PS_STA);
+}
+
+static void cl_stats_free(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	kfree(cl_sta->stats);
+	cl_sta->stats = NULL;
+}
+
+static void cl_stats_disable(struct cl_hw *cl_hw)
+{
+	pr_debug("Statistics disabled\n");
+	cl_hw->conf->ci_stats_en = false;
+	cl_sta_loop(cl_hw, cl_stats_free);
+
+	if (cl_hw_is_prod_or_listener(cl_hw)) {
+		kfree(cl_hw->rx_stats);
+		cl_hw->rx_stats = NULL;
+	}
+}
+
+static void _cl_stats_update_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				struct cl_agg_tx_report *agg_report)
+{
+	struct cl_stats *stats = cl_sta->stats;
+	struct cl_tx_cntrs *cntrs;
+	union cl_rate_ctrl_info rate_ctrl_info = {
+		.word = le32_to_cpu(agg_report->rate_cntrl_info)};
+	u8 bw, nss, mcs, gi, bf;
+
+	switch (rate_ctrl_info.field.format_mod) {
+	case WRS_MODE_HE:
+		nss = (rate_ctrl_info.field.mcs_index >> 4);
+		mcs = (rate_ctrl_info.field.mcs_index & 0xF);
+		gi = rate_ctrl_info.field.gi;
+
+		{
+			bw = rate_ctrl_info.field.bw;
+			bf = agg_report->bf;
+
+				cntrs = &stats->tx.he[bw][nss][mcs][gi][bf];
+		}
+		break;
+	case WRS_MODE_VHT:
+		bw = rate_ctrl_info.field.bw;
+		nss = (rate_ctrl_info.field.mcs_index >> 4);
+		mcs = (rate_ctrl_info.field.mcs_index & 0xF);
+		gi = rate_ctrl_info.field.gi;
+		bf = agg_report->bf;
+
+			cntrs = &stats->tx.vht[bw][nss][mcs][gi][bf];
+		break;
+	case WRS_MODE_HT:
+		bw = rate_ctrl_info.field.bw;
+		nss = (rate_ctrl_info.field.mcs_index >> 3);
+		mcs = (rate_ctrl_info.field.mcs_index & 0x7);
+		gi = rate_ctrl_info.field.gi;
+		cntrs = &stats->tx.ht[bw][nss][mcs][gi];
+		break;
+	case WRS_MODE_OFDM:
+		mcs = rate_ctrl_info.field.mcs_index - RATE_CTRL_OFFSET_OFDM;
+		cntrs = &stats->tx.ofdm[mcs];
+		break;
+	case WRS_MODE_CCK:
+		mcs = rate_ctrl_info.field.mcs_index;
+		cntrs = &stats->tx.cck[mcs];
+		break;
+	default:
+		return;
+	}
+
+	cntrs->success += agg_report->success;
+	cntrs->fail += agg_report->fail;
+	stats->tx.packet_success += agg_report->success;
+	stats->tx.packet_fail += agg_report->fail;
+}
+
+static void _cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_rx_stats *rx_stats,
+				     struct hw_rxhdr *rxhdr)
+{
+	u8 bw, nss, mcs, gi;
+
+	switch (rxhdr->format_mod) {
+	case FORMATMOD_HE_TRIG:
+		nss = rxhdr->n_sts & 0x3;
+		mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+		gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+		rx_stats->he_trig[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_HE_TRIG;
+		break;
+	case FORMATMOD_HE_EXT:
+		nss = rxhdr->n_sts & 0x3;
+		mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+		gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+		rx_stats->he_ext[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_HE_EXT;
+		break;
+	case FORMATMOD_HE_MU:
+		nss = rxhdr->n_sts & 0x3;
+		mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+		gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+		rx_stats->he_mu[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_HE_MU;
+		break;
+	case FORMATMOD_HE_SU:
+		nss = rxhdr->n_sts & 0x3;
+		mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_HE);
+		gi = min_t(u8, rxhdr->gi_type, WRS_GI_MAX_HE);
+		rx_stats->he_su[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_HE_SU;
+		break;
+	case FORMATMOD_VHT:
+		nss = rxhdr->n_sts & 0x3;
+		mcs = min_t(u8, rxhdr->mcs, WRS_MCS_MAX_VHT);
+		gi = rxhdr->gi_type & 0x1;
+		rx_stats->vht[rxhdr->ch_bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_VHT;
+		break;
+	case FORMATMOD_HT_MF:
+	case FORMATMOD_HT_GF:
+		bw = rxhdr->ch_bw & 0x1;
+		nss = (rxhdr->mcs >> 3) & 0x3;
+		mcs = rxhdr->mcs & 0x7;
+		gi = rxhdr->gi_type & 0x1;
+		rx_stats->ht[bw][nss][mcs][gi] += rxhdr->frm_successful_rx;
+		rx_stats->flag |= RX_STATS_HT;
+		break;
+	case FORMATMOD_NON_HT:
+		if (rxhdr->mcs >= RATE_CTRL_OFFSET_OFDM) {
+			mcs = (rxhdr->mcs - RATE_CTRL_OFFSET_OFDM) & 0x7;
+			rx_stats->ofdm[mcs] += rxhdr->frm_successful_rx;
+			rx_stats->flag |= RX_STATS_OFDM;
+		} else if (cl_band_is_24g(cl_hw)) {
+			mcs = rxhdr->mcs & 0x3;
+			rx_stats->cck[mcs] += rxhdr->frm_successful_rx;
+			rx_stats->flag |= RX_STATS_CCK;
+		}
+		break;
+	}
+
+	rx_stats->packet_success += rxhdr->frm_successful_rx;
+}
+
+void cl_stats_init(struct cl_hw *cl_hw)
+{
+	spin_lock_init(&cl_hw->lock_stats);
+
+	if (cl_hw->conf->ci_stats_en && cl_hw_is_prod_or_listener(cl_hw)) {
+		cl_hw->rx_stats = kzalloc(sizeof(*cl_hw->rx_stats), GFP_ATOMIC);
+
+		if (!cl_hw->rx_stats)
+			cl_hw->conf->ci_stats_en = false;
+	}
+}
+
+void cl_stats_deinit(struct cl_hw *cl_hw)
+{
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	if (cl_hw->conf->ci_stats_en && (cl_hw_is_prod_or_listener(cl_hw))) {
+		cl_hw->conf->ci_stats_en = false;
+
+		kfree(cl_hw->rx_stats);
+		cl_hw->rx_stats = NULL;
+	}
+
+	spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+void cl_stats_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	/*
+	 * If allocation failed disable ci_stats_en
+	 * and free the memory of all other stations
+	 */
+	bool disable = false;
+
+	if (cl_hw->conf->ci_stats_en) {
+		/*
+		 * Take regular lock and not BH,
+		 * because cl_sta_add_to_lut() already disables BH
+		 */
+		spin_lock(&cl_hw->lock_stats);
+
+		cl_sta->stats = kzalloc(sizeof(*cl_sta->stats), GFP_ATOMIC);
+
+		if (cl_sta->stats)
+			cll_stats_config_ps(cl_sta);
+		else
+			disable = true;
+
+		spin_unlock(&cl_hw->lock_stats);
+	}
+
+	if (disable && cl_hw->conf->ci_stats_en) {
+		spin_lock_bh(&cl_hw->lock_stats);
+		cl_stats_disable(cl_hw);
+		spin_unlock_bh(&cl_hw->lock_stats);
+	}
+}
+
+void cl_stats_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	cl_stats_free(cl_hw, cl_sta);
+
+	spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			    struct cl_agg_tx_report *agg_report)
+{
+	struct cl_stats *stats = cl_sta->stats;
+
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock(&cl_hw->lock_stats);
+
+	stats->tx.agg_cntr++;
+	stats->tx.fail_cntr += agg_report->fail;
+	_cl_stats_update_tx(cl_hw, cl_sta, agg_report);
+
+	spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct cl_agg_tx_report *agg_report)
+{
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock(&cl_hw->lock_stats);
+
+	cl_sta->stats->tx.fail_cntr += agg_report->fail;
+	_cl_stats_update_tx(cl_hw, cl_sta, agg_report);
+
+	spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_rx_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			     s8 rssi[MAX_ANTENNAS])
+{
+	int i;
+	s8 rx_rssi;
+
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	for (i = 0; i < cl_hw->num_antennas; i++) {
+		rx_rssi = rssi[i] * -1;
+
+		if (rx_rssi >= 0 && rx_rssi < RSSI_ARR_SIZE)
+			cl_sta->stats->rssi[rx_rssi][i]++;
+	}
+
+	spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock(&cl_hw->lock_stats);
+
+	_cl_stats_update_rx_rate(cl_hw, &cl_sta->stats->rx, rxhdr);
+	cl_sta->stats->fec_coding[rxhdr->fec_coding]++;
+
+	spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_rx_rate_production(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr)
+{
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock(&cl_hw->lock_stats);
+
+	_cl_stats_update_rx_rate(cl_hw, cl_hw->rx_stats, rxhdr);
+
+	spin_unlock(&cl_hw->lock_stats);
+}
+
+void cl_stats_update_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps)
+{
+	struct cl_ps_stats *ps;
+
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	ps = &cl_sta->stats->ps;
+
+	if (ps->is_ps == is_ps)
+		goto out;
+
+	ps->is_ps = is_ps;
+
+	if (is_ps) {
+		ps->timestamp_sleep = jiffies;
+	} else {
+		unsigned long sleep_time = jiffies_to_msecs(jiffies - ps->timestamp_sleep);
+
+		if (sleep_time <= 50)
+			ps->period[PS_PERIOD_50MS]++;
+		else if (sleep_time <= 100)
+			ps->period[PS_PERIOD_100MS]++;
+		else if (sleep_time <= 250)
+			ps->period[PS_PERIOD_250MS]++;
+		else if (sleep_time <= 500)
+			ps->period[PS_PERIOD_500MS]++;
+		else if (sleep_time <= 750)
+			ps->period[PS_PERIOD_750MS]++;
+		else if (sleep_time <= 1000)
+			ps->period[PS_PERIOD_1000MS]++;
+		else if (sleep_time <= 2000)
+			ps->period[PS_PERIOD_2000MS]++;
+		else if (sleep_time <= 5000)
+			ps->period[PS_PERIOD_5000MS]++;
+		else if (sleep_time <= 10000)
+			ps->period[PS_PERIOD_10000MS]++;
+		else
+			ps->period[PS_PERIOD_ABOVE]++;
+	}
+
+out:
+	spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+int cl_stats_get_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_stats *stats = NULL;
+	u32 i = 0, j = 0;
+	u64 total_rssi = 0;
+	s8 avg_signal = 0;
+
+	if (!cl_hw->conf->ci_stats_en)
+		return 0;
+
+	u64 avg_rssi[MAX_ANTENNAS] = {0};
+	u64 sum_rssi[MAX_ANTENNAS] = {0};
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	stats = cl_sta->stats;
+
+	if (!stats)
+		goto out;
+
+	for (i = 0; i < RSSI_ARR_SIZE; i++) {
+		total_rssi = 0;
+
+		for (j = 0; j < cl_hw->num_antennas; j++) {
+			sum_rssi[j] += stats->rssi[i][j];
+			avg_rssi[j] += i * stats->rssi[i][j];
+		}
+	}
+
+	for (j = 0; j < cl_hw->num_antennas; j++)
+		if (sum_rssi[j])
+			avg_rssi[j] = div64_u64(avg_rssi[j], sum_rssi[j]);
+
+	for (j = 0; j < cl_hw->num_antennas; j++)
+		total_rssi += avg_rssi[j];
+
+	avg_signal = -div64_u64(total_rssi, cl_hw->num_antennas);
+out:
+	spin_unlock_bh(&cl_hw->lock_stats);
+
+	return avg_signal;
+}
+
+void cl_stats_get_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		     u64 *total_tx_success, u64 *total_tx_fail)
+{
+	if (!cl_hw->conf->ci_stats_en)
+		return;
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	if (!cl_sta->stats)
+		goto out;
+
+	*total_tx_success = cl_sta->stats->tx.packet_success;
+	*total_tx_fail = cl_sta->stats->tx.packet_fail;
+
+out:
+	spin_unlock_bh(&cl_hw->lock_stats);
+}
+
+u64 cl_stats_get_rx(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	u64 total_rx_packets = 0;
+
+	if (!cl_hw->conf->ci_stats_en)
+		return 0;
+
+	spin_lock_bh(&cl_hw->lock_stats);
+
+	if (!cl_sta->stats)
+		goto out;
+
+	total_rx_packets = cl_sta->stats->rx.packet_success;
+
+out:
+	spin_unlock_bh(&cl_hw->lock_stats);
+
+	return total_rx_packets;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 77/96] cl8k: add stats.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (75 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 78/96] cl8k: add tcv.c viktor.barna
                   ` (18 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/stats.h | 108 +++++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/stats.h

diff --git a/drivers/net/wireless/celeno/cl8k/stats.h b/drivers/net/wireless/celeno/cl8k/stats.h
new file mode 100644
index 000000000000..480c00b395f1
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/stats.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_STATS_H
+#define CL_STATS_H
+
+#include "wrs.h"
+
+enum cl_rx_stats_flag {
+	RX_STATS_CCK = 0x01,
+	RX_STATS_OFDM = 0x02,
+	RX_STATS_HT = 0x04,
+	RX_STATS_VHT = 0x08,
+	RX_STATS_HE_SU = 0x10,
+	RX_STATS_HE_MU = 0x20,
+	RX_STATS_HE_EXT = 0x40,
+	RX_STATS_HE_TRIG = 0x80,
+};
+
+struct cl_rx_stats {
+	u32 he_trig[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+	u32 he_ext[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+	u32 he_mu[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+	u32 he_su[CHNL_BW_MAX_HE][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+	u32 vht[CHNL_BW_MAX_VHT][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+	u32 ht[CHNL_BW_MAX_HT][WRS_SS_MAX][WRS_MCS_MAX_HT][WRS_GI_MAX_HT];
+	u32 ofdm[WRS_MCS_MAX_OFDM];
+	u32 cck[WRS_MCS_MAX_CCK];
+	u8 flag;
+	u64 packet_success;
+};
+
+#define RSSI_ARR_SIZE 128
+#define BF_IDX_MAX 2
+
+struct cl_tx_cntrs {
+	u32 success;
+	u32 fail;
+};
+
+struct cl_tx_stats {
+	struct cl_tx_cntrs he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX][WRS_GI_MAX][BF_IDX_MAX];
+	struct cl_tx_cntrs
+		vht[CHNL_BW_MAX_VHT][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT][BF_IDX_MAX];
+	struct cl_tx_cntrs ht[CHNL_BW_MAX_HT][WRS_SS_MAX][WRS_MCS_MAX_HT][WRS_GI_MAX_HT];
+	struct cl_tx_cntrs ofdm[WRS_MCS_MAX_OFDM];
+	struct cl_tx_cntrs cck[WRS_MCS_MAX_CCK];
+	u32 agg_cntr;
+	u32 fail_cntr;
+	u64 packet_success;
+	u64 packet_fail;
+};
+
+enum cl_ps_period {
+	PS_PERIOD_50MS,
+	PS_PERIOD_100MS,
+	PS_PERIOD_250MS,
+	PS_PERIOD_500MS,
+	PS_PERIOD_750MS,
+	PS_PERIOD_1000MS,
+	PS_PERIOD_2000MS,
+	PS_PERIOD_5000MS,
+	PS_PERIOD_10000MS,
+	PS_PERIOD_ABOVE,
+
+	PS_PERIOD_MAX
+};
+
+struct cl_ps_stats {
+	bool is_ps;
+	unsigned long timestamp_sleep;
+	u32 period[PS_PERIOD_MAX];
+};
+
+enum cl_fec_coding {
+	CL_FEC_CODING_BCC,
+	CL_FEC_CODING_LDPC,
+	CL_FEC_CODING_MAX
+};
+
+struct cl_stats {
+	struct cl_tx_stats tx;
+	struct cl_rx_stats rx;
+	u32 rssi[RSSI_ARR_SIZE][MAX_ANTENNAS];
+	u32 fec_coding[CL_FEC_CODING_MAX];
+	struct cl_ps_stats ps;
+};
+
+struct cl_vif;
+
+void cl_stats_init(struct cl_hw *cl_hw);
+void cl_stats_deinit(struct cl_hw *cl_hw);
+void cl_stats_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_stats_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_stats_update_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			    struct cl_agg_tx_report *agg_report);
+void cl_stats_update_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			       struct cl_agg_tx_report *agg_report);
+void cl_stats_update_rx_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_stats_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr);
+void cl_stats_update_rx_rate_production(struct cl_hw *cl_hw, struct hw_rxhdr *rxhdr);
+void cl_stats_update_ps(struct cl_hw *cl_hw, struct cl_sta *cl_sta, bool is_ps);
+void cl_stats_get_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		     u64 *total_success, u64 *total_fail);
+u64 cl_stats_get_rx(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+int cl_stats_get_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+
+#endif /* CL_STATS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 78/96] cl8k: add tcv.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (76 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 77/96] cl8k: add stats.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 79/96] cl8k: add tcv.h viktor.barna
                   ` (17 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tcv.c | 1259 ++++++++++++++++++++++++
 1 file changed, 1259 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv.c

diff --git a/drivers/net/wireless/celeno/cl8k/tcv.c b/drivers/net/wireless/celeno/cl8k/tcv.c
new file mode 100644
index 000000000000..1a17c4f4445a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tcv.c
@@ -0,0 +1,1259 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/uaccess.h>
+
+#include "chip.h"
+#include "recovery.h"
+#include "vns.h"
+#include "mac80211.h"
+#include "config.h"
+#include "rfic.h"
+#include "e2p.h"
+#include "hw.h"
+#include "radio.h"
+#include "utils.h"
+#include "tcv.h"
+
+#define CL_TX_BCN_PENDING_CHAIN_MIN_TIME 10 /* Usec */
+#define CL_MAX_NUM_OF_RETRY   15
+#define INVALID_CALIB_RX_GAIN 0xff
+
+static struct cl_tcv_conf conf = {
+	.ce_debug_level = DBG_LVL_ERROR,
+	.ce_radio_on = true,
+	.ce_ps_ctrl_enabled = true,
+	.ci_ieee80211h = false,
+	.ci_max_bss_num = ARRAY_SIZE(((struct cl_hw *)0)->addresses),
+	.ci_short_guard_interval = 1,
+	.ci_max_mpdu_len = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991,
+	.ci_max_ampdu_len_exp = IEEE80211_VHT_MAX_AMPDU_1024K,
+	.ce_dsp_code = "fwC.hex",
+	.ce_dsp_data = "fwD.hex",
+	.ce_dsp_external_data = "fwD.ext.hex",
+	.ci_uapsd_en = true,
+	.ce_eirp_regulatory_op_en = true,
+	.ce_eirp_regulatory_prod_en = false,
+	.ci_agg_tx = true,
+	.ci_agg_rx = true,
+	.ce_txldpc_en = true,
+	.ci_ht_rxldpc_en = true,
+	.ci_vht_rxldpc_en = true,
+	.ci_he_rxldpc_en = true,
+	.ci_cs_required = false,
+	.ci_rx_sensitivity_prod = {
+		[0 ... MAX_ANTENNAS - 1] = -100,
+	},
+	.ci_rx_sensitivity_op = {
+		[0 ... MAX_ANTENNAS - 1] = -100,
+	},
+	.ci_min_he_en = false,
+	.ce_cck_tx_ant_mask = 0x1,
+	.ce_cck_rx_ant_mask = 0x1,
+	.ce_rx_nss = 4,
+	.ce_tx_nss = 4,
+	.ce_num_antennas = 4,
+	.ce_max_agg_size_tx = IEEE80211_MAX_AMPDU_BUF_HE,
+	.ce_max_agg_size_rx = IEEE80211_MAX_AMPDU_BUF_HE,
+	.ce_rxamsdu_en = true,
+	.ce_txamsdu_en = CL_AMSDU_TX_PAYLOAD_MAX,
+	.ci_tx_amsdu_min_data_rate = 26, /* 26Mbps (= BW 20, NSS 0, MCS 3, GI 0) */
+	.ci_tx_sw_amsdu_max_packets = 0,
+	.ci_tx_packet_limit = 5000,
+	.ci_sw_txhdr_pool = 0,
+	.ci_amsdu_txhdr_pool = 0,
+	.ci_tx_queue_size_agg = 500,
+	.ci_tx_queue_size_single = 50,
+	.ci_tx_push_cntrs_stat_en = false,
+	.ci_traffic_mon_en = false,
+	.ci_ipc_rxbuf_size = {
+		[CL_RX_BUF_RXM] = IPC_RXBUF_SIZE,
+		[CL_RX_BUF_FW] = IPC_RXBUF_SIZE
+	},
+	.ce_max_retry = 8,
+	.ce_short_retry_limit = 4,
+	.ce_long_retry_limit = 4,
+	.ci_assoc_auth_retry_limit = 0,
+	.ci_cap_bandwidth = CHNL_BW_MAX,
+	.ci_chandef_channel = INVALID_CHAN_IDX,
+	.ci_chandef_bandwidth = CHNL_BW_MAX,
+	.ci_cck_in_hw_mode = true,
+	.ce_temp_comp_slope = 8,
+	.ci_fw_dbg_severity = CL_MACFW_DBG_SEV_WARNING,
+	.ci_fw_dbg_module = 0x0FFFFF,
+	.ci_lcu_dbg_cfg_inx = 4,
+	.ci_dsp_lcu_mode = 0,
+	.ci_hal_idle_to = CL_DEFAULT_HAL_IDLE_TIMEOUT,
+	.ci_tx_ac0_to = CL_TX_DEFAULT_AC0_TIMEOUT,
+	.ci_tx_ac1_to = CL_TX_DEFAULT_AC1_TIMEOUT,
+	.ci_tx_ac2_to = CL_TX_DEFAULT_AC2_TIMEOUT,
+	.ci_tx_ac3_to = CL_TX_DEFAULT_AC3_TIMEOUT,
+	.ci_tx_bcn_to = CL_TX_DEFAULT_BCN_TIMEOUT,
+	.ce_hardware_power_table = {0},
+	.ce_arr_gain = "0,3,4.75,6,7,7.75",
+	.ce_bf_gain_2_ant = "0",
+	.ce_bf_gain_3_ant = "0",
+	.ce_bf_gain_4_ant = "0",
+	.ce_bf_gain_5_ant = "0",
+	.ce_bf_gain_6_ant = "0",
+	.ce_ant_gain = "0",
+	.ce_ant_gain_36_64 = "0",
+	.ce_ant_gain_100_140 = "0",
+	.ce_ant_gain_149_165 = "0",
+	.ci_min_ant_pwr = "0",
+	.ci_bw_factor = "0,0,0,0",
+	.ce_mcast_rate = 0,
+	.ce_dyn_mcast_rate_en = false,
+	.ce_dyn_bcast_rate_en = false,
+	.ce_default_mcs_ofdm = 0,
+	.ce_default_mcs_cck = 0,
+	.ce_prot_log_nav_en = false,
+	.ce_prot_mode = TXL_PROT_RTS_FW,
+	.ce_prot_rate_format = 1,
+	.ce_prot_rate_mcs = 4,
+	.ce_prot_rate_pre_type = 0,
+	.ce_bw_signaling_mode = 0,
+	.ci_dyn_cts_sta_thr = 2,
+	.ci_vns_pwr_limit = 0,
+	.ci_vns_pwr_mode = VNS_MODE_ALL,
+	.ci_vns_rssi_auto_resp_thr = -40,
+	.ci_vns_rssi_thr = -40,
+	.ci_vns_rssi_hys = 3,
+	.ci_vns_maintenance_time = 2000,
+	.ce_bcn_tx_path_min_time = 1000,
+	.ci_backup_bcn_en = true,
+	.ce_tx_txop_cut_en = true,
+	.ci_bcns_flushed_cnt_thr = 3,
+	.ci_phy_err_prevents_phy_dump = false,
+	.ci_tx_rx_delay = 0,
+	.ci_fw_assert_time_diff_sec = 5,
+	.ci_fw_assert_storm_detect_thd = 10,
+	.ce_hw_assert_time_max  = CL_HW_ASSERT_TIME_MAX,
+	.ce_bg_assert_print = 1,
+	.ce_fw_watchdog_mode = FW_WD_INTERNAL_RECOVERY,
+	.ce_fw_watchdog_limit_count = 5,
+	.ce_fw_watchdog_limit_time = 30 * 1000, /* Msecs */
+	.ci_rx_remote_cpu_drv = -1,
+	.ci_rx_remote_cpu_mac = -1,
+	.ci_pending_queue_size = 500,
+	.ce_tx_power_control = 100,
+	.ce_acs_coex_en = false,
+	.ci_dfs_initial_gain = 77,
+	.ci_dfs_agc_cd_th = 48,
+	.ci_dfs_long_pulse_min = 100,
+	.ci_dfs_long_pulse_max = 5000,
+	.ce_dfs_tbl_overwrite = {0},
+	/* 6G */
+	.ce_ppmcs_offset_he_6g = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+		[WRS_MCS_10] = 0,
+		[WRS_MCS_11] = 0,
+	},
+	/* 5G */
+	.ce_ppmcs_offset_he_36_64 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+		[WRS_MCS_10] = 0,
+		[WRS_MCS_11] = 0,
+	},
+	.ce_ppmcs_offset_he_100_140 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+		[WRS_MCS_10] = 0,
+		[WRS_MCS_11] = 0,
+	},
+	.ce_ppmcs_offset_he_149_165 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+		[WRS_MCS_10] = 0,
+		[WRS_MCS_11] = 0,
+	},
+	.ce_ppmcs_offset_ht_vht_36_64 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+	},
+	.ce_ppmcs_offset_ht_vht_100_140 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+	},
+	.ce_ppmcs_offset_ht_vht_149_165 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+	},
+	.ce_ppmcs_offset_ofdm_36_64 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+	},
+	.ce_ppmcs_offset_ofdm_100_140 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+	},
+	.ce_ppmcs_offset_ofdm_149_165 = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+	},
+	/* 24G */
+	.ce_ppmcs_offset_he = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+		[WRS_MCS_8] = 0,
+		[WRS_MCS_9] = 0,
+		[WRS_MCS_10] = 0,
+		[WRS_MCS_11] = 0,
+	},
+	.ce_ppmcs_offset_ht = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+	},
+	.ce_ppmcs_offset_ofdm = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+		[WRS_MCS_4] = 0,
+		[WRS_MCS_5] = 0,
+		[WRS_MCS_6] = 0,
+		[WRS_MCS_7] = 0,
+	},
+	.ce_ppmcs_offset_cck = {
+		[WRS_MCS_0] = 0,
+		[WRS_MCS_1] = 0,
+		[WRS_MCS_2] = 0,
+		[WRS_MCS_3] = 0,
+	},
+	.ce_ppbw_offset = {
+		[CHNL_BW_20] = 0,
+		[CHNL_BW_40] = 0,
+		[CHNL_BW_80] = 0,
+		[CHNL_BW_160] = 0,
+	},
+	.ce_power_offset_prod_en = true,
+	.ci_bf_en = false,
+	.ci_bf_max_nss = 2,
+	.ce_sounding_interval_coefs = {
+		[SOUNDING_INTERVAL_COEF_MIN_INTERVAL] = 100,
+		[SOUNDING_INTERVAL_COEF_STA_STEP] = 4,
+		[SOUNDING_INTERVAL_COEF_INTERVAL_STEP] = 50,
+		[SOUNDING_INTERVAL_COEF_MAX_INTERVAL] = 500,
+	},
+	.ci_rate_fallback = {
+		[CL_RATE_FALLBACK_COUNT_SU] = 4,
+		[CL_RATE_FALLBACK_COUNT_MU] = 2,
+		[CL_RATE_FALLBACK_RETRY_COUNT_THR] = 2,
+		[CL_RATE_FALLBACK_BA_PER_THR] = 25,
+		[CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR] = 2,
+		[CL_RATE_FALLBACK_DISABLE_MCS] = 1
+	},
+	.ce_rx_pkts_budget = 512,
+	.ci_band_num = 5,
+	.ci_mult_ampdu_in_txop_en = false,
+	.ce_wmm_aifsn = {
+		[AC_BK] = 3,
+		[AC_BE] = 7,
+		[AC_VI] = 1,
+		[AC_VO] = 1
+	},
+	.ce_wmm_cwmin = {
+		[AC_BK] = 4,
+		[AC_BE] = 4,
+		[AC_VI] = 3,
+		[AC_VO] = 2
+	},
+	.ce_wmm_cwmax = {
+		[AC_BK] = 10,
+		[AC_BE] = 10,
+		[AC_VI] = 4,
+		[AC_VO] = 3
+	},
+	.ce_wmm_txop = {
+		[AC_BK] = 0,
+		[AC_BE] = 0,
+		[AC_VI] = 94,
+		[AC_VO] = 47
+	},
+	.ci_su_force_min_spacing = CL_TX_MPDU_SPACING_INVALID,
+	.ci_mu_force_min_spacing = CL_TX_MPDU_SPACING_INVALID,
+	.ci_tf_mac_pad_dur = 0,
+	.ci_cca_timeout = 300,
+	.ce_tx_ba_session_timeout = 30000,
+	.ci_motion_sense_en = true,
+	.ci_motion_sense_rssi_thr = 8,
+	.ci_wrs_max_bw = CHNL_BW_160,
+	.ci_wrs_min_bw = CHNL_BW_20,
+	.ci_wrs_fixed_rate = {
+		[WRS_FIXED_PARAM_MODE] = -1,
+		[WRS_FIXED_PARAM_BW] = -1,
+		[WRS_FIXED_PARAM_NSS] = -1,
+		[WRS_FIXED_PARAM_MCS] = -1,
+		[WRS_FIXED_PARAM_GI] = -1
+	},
+	.ce_he_mcs_nss_supp_tx = {
+		[WRS_SS_1 ... WRS_SS_4] = 11,
+	},
+	.ce_he_mcs_nss_supp_rx = {
+		[WRS_SS_1 ... WRS_SS_4] = 11,
+	},
+	.ce_vht_mcs_nss_supp_tx = {
+		[WRS_SS_1 ... WRS_SS_4] = 9,
+	},
+	.ce_vht_mcs_nss_supp_rx = {
+		[WRS_SS_1 ... WRS_SS_4] = 9,
+	},
+	.ci_pe_duration = U8_MAX,
+	.ci_pe_duration_bcast = PPE_16US,
+	.ci_gain_update_enable = 1,
+	.ci_mcs_sig_b = 0,
+	.ci_spp_ksr_value = 1,
+	.ci_rx_padding_en = false,
+	.ci_stats_en = false,
+	.ci_bar_disable = false,
+	.ci_ofdm_only = true,
+	.ci_hw_bsr = false,
+	.ci_drop_to_lower_bw = false,
+	.ci_force_icmp_single = false,
+	.ce_wrs_rx_en = false,
+	.ci_hr_factor = {
+		[CHNL_BW_20] = 2,
+		[CHNL_BW_40] = 2,
+		[CHNL_BW_80] = 2,
+		[CHNL_BW_160] = 1
+	},
+	.ci_csd_en = true,
+	.ci_signal_extension_en = false,
+	.ci_vht_cap_24g = false,
+	.ci_tx_digital_gain = 0x28282828,
+	.ci_tx_digital_gain_cck = 0x63636363,
+	.ci_ofdm_cck_power_offset = -13,
+	.ci_mac_clk_gating_en = true,
+	.ci_phy_clk_gating_en = true,
+	.ci_imaging_blocker = false,
+	.ci_sensing_ndp_tx_chain_mask = NDP_TX_PHY0,
+	.ci_sensing_ndp_tx_bw = CHNL_BW_MAX,
+	.ci_sensing_ndp_tx_format = FORMATMOD_NON_HT,
+	.ci_sensing_ndp_tx_num_ltf = LTF_X1,
+	.ci_calib_ant_tx = {
+		[0 ... MAX_ANTENNAS - 1] = U8_MAX,
+	},
+	.ci_calib_ant_rx = {
+		[0 ... MAX_ANTENNAS - 1] = U8_MAX,
+	},
+	.ci_cca_ed_rise_thr_dbm = -62,
+	.ci_cca_ed_fall_thr_dbm = -65,
+	.ci_cca_cs_en = 1,
+	.ci_cca_modem_en = 0xf,
+	.ci_cca_main_ant = 0,
+	.ci_cca_second_ant = 1,
+	.ci_cca_flag0_ctrl = 0x8,
+	.ci_cca_flag1_ctrl = 0x8,
+	.ci_cca_flag2_ctrl = 0x2,
+	.ci_cca_flag3_ctrl = 0xa,
+	.ci_cca_gi_rise_thr_dbm = -72,
+	.ci_cca_gi_fall_thr_dbm = -75,
+	.ci_cca_gi_pow_lim_dbm = -59,
+	.ci_cca_ed_en = 0x7ff,
+	.ci_cca_gi_en = 0,
+	.ci_rx_he_mu_ppdu = false,
+	.ci_fast_rx_en = true,
+	.ci_distance_auto_resp_all = 0,
+	.ci_distance_auto_resp_msta = 0,
+	.ci_fw_disable_recovery = false,
+	.ce_listener_en = 0,
+	.ci_tx_delay_tstamp_en = false,
+	.ci_calib_tx_init_tx_gain = {
+		[0 ... MAX_ANTENNAS - 1] = CALIB_TX_GAIN_DEFAULT,
+	},
+	.ci_calib_tx_init_rx_gain = {
+		[0 ... MAX_ANTENNAS - 1] = INVALID_CALIB_RX_GAIN,
+	},
+	.ci_calib_rx_init_tx_gain = {
+		[0 ... MAX_ANTENNAS - 1] = CALIB_TX_GAIN_DEFAULT,
+	},
+	.ci_calib_rx_init_rx_gain = {
+		[0 ... MAX_ANTENNAS - 1] = INVALID_CALIB_RX_GAIN,
+	},
+	.ci_calib_conf_rx_gain_upper_limit = INVALID_CALIB_RX_GAIN,
+	.ci_calib_conf_rx_gain_lower_limit = INVALID_CALIB_RX_GAIN,
+	.ci_calib_conf_tone_vector_20bw = {6, 10, 14, 18, 22, 24, 26, 27},
+	.ci_calib_conf_tone_vector_40bw = {10, 18, 26, 34, 41, 48, 53, 58},
+	.ci_calib_conf_tone_vector_80bw = {18, 34, 50, 66, 82, 98, 110, 122},
+	.ci_calib_conf_tone_vector_160bw = {18, 34, 66, 98, 130, 164, 224, 250},
+	.ci_calib_conf_gp_rad_trshld = GP_RAD_TRSHLD_DEFAULT,
+	.ci_calib_conf_ga_lin_upper_trshld = GA_LIN_UPPER_TRSHLD_DEFAULT,
+	.ci_calib_conf_ga_lin_lower_trshld = GA_LIN_LOWER_TRSHLD_DEFAULT,
+	.ci_calib_conf_singletons_num = SINGLETONS_NUM_DEFAULT,
+	.ci_calib_conf_rampup_time = RAMPUP_TIME,
+	.ci_calib_conf_lo_coarse_step = LO_COARSE_STEP,
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	.ci_calib_conf_lo_fine_step = LO_FINE_STEP,
+	.ci_calib_eeprom_channels_20mhz = {0},
+	.ci_calib_eeprom_channels_40mhz = {0},
+	.ci_calib_eeprom_channels_80mhz = {0},
+	.ci_calib_eeprom_channels_160mhz = {0},
+#endif
+	.ci_mesh_basic_rates = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static int cl_tcv_update_config(struct cl_hw *cl_hw, char *name, char *value)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	int ret = -ENOENT;
+
+	do {
+		READ_S8(ce_debug_level);
+		READ_BOOL(ce_radio_on);
+		READ_BOOL(ce_ps_ctrl_enabled);
+		READ_BOOL(ci_ieee80211h);
+		READ_U8(ci_max_bss_num);
+		READ_U8(ci_short_guard_interval);
+		READ_U8(ci_max_mpdu_len);
+		READ_U8(ci_max_ampdu_len_exp);
+		READ_STR(ce_dsp_code);
+		READ_STR(ce_dsp_data);
+		READ_STR(ce_dsp_external_data);
+		READ_BOOL(ci_uapsd_en);
+		READ_BOOL(ce_eirp_regulatory_op_en);
+		READ_BOOL(ce_eirp_regulatory_prod_en);
+		READ_BOOL(ci_agg_tx);
+		READ_BOOL(ci_agg_rx);
+		READ_BOOL(ce_txldpc_en);
+		READ_BOOL(ci_ht_rxldpc_en);
+		READ_BOOL(ci_vht_rxldpc_en);
+		READ_BOOL(ci_he_rxldpc_en);
+		READ_BOOL(ci_cs_required);
+		READ_S8_ARR(ci_rx_sensitivity_prod, MAX_ANTENNAS);
+		READ_S8_ARR(ci_rx_sensitivity_op, MAX_ANTENNAS);
+		READ_BOOL(ci_min_he_en);
+		READ_U8(ce_cck_tx_ant_mask);
+		READ_U8(ce_cck_rx_ant_mask);
+		READ_U8(ce_rx_nss);
+		READ_U8(ce_tx_nss);
+		READ_U8(ce_num_antennas);
+		READ_U16(ce_max_agg_size_tx);
+		READ_U16(ce_max_agg_size_rx);
+		READ_BOOL(ce_rxamsdu_en);
+		READ_U8(ce_txamsdu_en);
+		READ_U16(ci_tx_amsdu_min_data_rate);
+		READ_U8(ci_tx_sw_amsdu_max_packets);
+		READ_U16(ci_tx_packet_limit);
+		READ_U16(ci_sw_txhdr_pool);
+		READ_U16(ci_amsdu_txhdr_pool);
+		READ_U16(ci_tx_queue_size_agg);
+		READ_U16(ci_tx_queue_size_single);
+		READ_BOOL(ci_tx_push_cntrs_stat_en);
+		READ_BOOL(ci_traffic_mon_en);
+		READ_U16_ARR(ci_ipc_rxbuf_size, CL_RX_BUF_MAX, true);
+		READ_U16(ce_max_retry);
+		READ_U8(ce_short_retry_limit);
+		READ_U8(ce_long_retry_limit);
+		READ_U8(ci_assoc_auth_retry_limit);
+		READ_U8(ci_cap_bandwidth);
+		READ_U32(ci_chandef_channel);
+		READ_U8(ci_chandef_bandwidth);
+		READ_BOOL(ci_cck_in_hw_mode);
+		READ_S8(ce_temp_comp_slope);
+		READ_U32(ci_fw_dbg_severity);
+		READ_U32(ci_fw_dbg_module);
+		READ_U8(ci_lcu_dbg_cfg_inx);
+		READ_U8(ci_dsp_lcu_mode);
+		READ_U32(ci_hal_idle_to);
+		READ_U32(ci_tx_ac0_to);
+		READ_U32(ci_tx_ac1_to);
+		READ_U32(ci_tx_ac2_to);
+		READ_U32(ci_tx_ac3_to);
+		READ_U32(ci_tx_bcn_to);
+		READ_STR(ce_hardware_power_table);
+		READ_STR(ce_arr_gain);
+		READ_STR(ce_bf_gain_2_ant);
+		READ_STR(ce_bf_gain_3_ant);
+		READ_STR(ce_bf_gain_4_ant);
+		READ_STR(ce_bf_gain_5_ant);
+		READ_STR(ce_bf_gain_6_ant);
+		READ_STR(ce_ant_gain);
+		READ_STR(ce_ant_gain_36_64);
+		READ_STR(ce_ant_gain_100_140);
+		READ_STR(ce_ant_gain_149_165);
+		READ_STR(ci_min_ant_pwr);
+		READ_STR(ci_bw_factor);
+		READ_U8(ce_mcast_rate);
+		READ_BOOL(ce_dyn_mcast_rate_en);
+		READ_BOOL(ce_dyn_bcast_rate_en);
+		READ_U8(ce_default_mcs_ofdm);
+		READ_U8(ce_default_mcs_cck);
+		READ_BOOL(ce_prot_log_nav_en);
+		READ_U8(ce_prot_mode);
+		READ_U8(ce_prot_rate_format);
+		READ_U8(ce_prot_rate_mcs);
+		READ_U8(ce_prot_rate_pre_type);
+		READ_U8(ce_bw_signaling_mode);
+		READ_U8(ci_dyn_cts_sta_thr);
+		READ_S8(ci_vns_pwr_limit);
+		READ_U8(ci_vns_pwr_mode);
+		READ_S8(ci_vns_rssi_auto_resp_thr);
+		READ_S8(ci_vns_rssi_thr);
+		READ_S8(ci_vns_rssi_hys);
+		READ_U16(ci_vns_maintenance_time);
+		READ_U16(ce_bcn_tx_path_min_time);
+		READ_BOOL(ci_backup_bcn_en);
+		READ_BOOL(ce_tx_txop_cut_en);
+		READ_U8(ci_bcns_flushed_cnt_thr);
+		READ_BOOL(ci_phy_err_prevents_phy_dump);
+		READ_U8(ci_tx_rx_delay);
+		READ_U8(ci_fw_assert_time_diff_sec);
+		READ_U8(ci_fw_assert_storm_detect_thd);
+		READ_U32(ce_hw_assert_time_max);
+		READ_U8(ce_bg_assert_print);
+		READ_U8(ce_fw_watchdog_mode);
+		READ_U8(ce_fw_watchdog_limit_count);
+		READ_U32(ce_fw_watchdog_limit_time);
+		READ_S8(ci_rx_remote_cpu_drv);
+		READ_S8(ci_rx_remote_cpu_mac);
+		READ_U16(ci_pending_queue_size);
+		READ_U8(ce_tx_power_control);
+		READ_BOOL(ce_acs_coex_en);
+		READ_U8(ci_dfs_initial_gain);
+		READ_U8(ci_dfs_agc_cd_th);
+		READ_U16(ci_dfs_long_pulse_min);
+		READ_U16(ci_dfs_long_pulse_max);
+		READ_STR(ce_dfs_tbl_overwrite);
+		READ_S8_ARR(ce_ppmcs_offset_he_6g, WRS_MCS_MAX_HE);
+		READ_S8_ARR(ce_ppmcs_offset_he_36_64, WRS_MCS_MAX_HE);
+		READ_S8_ARR(ce_ppmcs_offset_he_100_140, WRS_MCS_MAX_HE);
+		READ_S8_ARR(ce_ppmcs_offset_he_149_165, WRS_MCS_MAX_HE);
+		READ_S8_ARR(ce_ppmcs_offset_ht_vht_36_64, WRS_MCS_MAX_VHT);
+		READ_S8_ARR(ce_ppmcs_offset_ht_vht_100_140, WRS_MCS_MAX_VHT);
+		READ_S8_ARR(ce_ppmcs_offset_ht_vht_149_165, WRS_MCS_MAX_VHT);
+		READ_S8_ARR(ce_ppmcs_offset_ofdm_36_64, WRS_MCS_MAX_OFDM);
+		READ_S8_ARR(ce_ppmcs_offset_ofdm_100_140, WRS_MCS_MAX_OFDM);
+		READ_S8_ARR(ce_ppmcs_offset_ofdm_149_165, WRS_MCS_MAX_OFDM);
+		READ_S8_ARR(ce_ppmcs_offset_he, WRS_MCS_MAX_HE);
+		READ_S8_ARR(ce_ppmcs_offset_ht, WRS_MCS_MAX_HT);
+		READ_S8_ARR(ce_ppmcs_offset_ofdm, WRS_MCS_MAX_OFDM);
+		READ_S8_ARR(ce_ppmcs_offset_cck, WRS_MCS_MAX_CCK);
+		READ_S8_ARR(ce_ppbw_offset, CHNL_BW_MAX);
+		READ_BOOL(ce_power_offset_prod_en);
+		READ_BOOL(ci_bf_en);
+		READ_U8(ci_bf_max_nss);
+		READ_U16_ARR(ce_sounding_interval_coefs, SOUNDING_INTERVAL_COEF_MAX, true);
+		READ_U8_ARR(ci_rate_fallback, CL_RATE_FALLBACK_MAX, true);
+		READ_U16(ce_rx_pkts_budget);
+		READ_U8(ci_band_num);
+		READ_BOOL(ci_mult_ampdu_in_txop_en);
+		READ_U8_ARR(ce_wmm_aifsn, AC_MAX, true);
+		READ_U8_ARR(ce_wmm_cwmin, AC_MAX, true);
+		READ_U8_ARR(ce_wmm_cwmax, AC_MAX, true);
+		READ_U16_ARR(ce_wmm_txop, AC_MAX, true);
+		READ_U8(ci_su_force_min_spacing);
+		READ_U8(ci_mu_force_min_spacing);
+		READ_U8(ci_tf_mac_pad_dur);
+		READ_U32(ci_cca_timeout);
+		READ_U16(ce_tx_ba_session_timeout);
+		READ_BOOL(ci_motion_sense_en);
+		READ_S8(ci_motion_sense_rssi_thr);
+		READ_U8(ci_wrs_max_bw);
+		READ_U8(ci_wrs_min_bw);
+		READ_S8_ARR(ci_wrs_fixed_rate, WRS_FIXED_PARAM_MAX);
+		READ_U8_ARR(ce_he_mcs_nss_supp_tx, WRS_SS_MAX, true);
+		READ_U8_ARR(ce_he_mcs_nss_supp_rx, WRS_SS_MAX, true);
+		READ_U8_ARR(ce_vht_mcs_nss_supp_tx, WRS_SS_MAX, true);
+		READ_U8_ARR(ce_vht_mcs_nss_supp_rx, WRS_SS_MAX, true);
+		READ_U8(ci_pe_duration);
+		READ_U8(ci_pe_duration_bcast);
+		READ_U8(ci_gain_update_enable);
+		READ_U8(ci_mcs_sig_b);
+		READ_U8(ci_spp_ksr_value);
+		READ_BOOL(ci_rx_padding_en);
+		READ_BOOL(ci_stats_en);
+		READ_BOOL(ci_bar_disable);
+		READ_BOOL(ci_ofdm_only);
+		READ_BOOL(ci_hw_bsr);
+		READ_BOOL(ci_drop_to_lower_bw);
+		READ_BOOL(ci_force_icmp_single);
+		READ_BOOL(ci_csd_en);
+		READ_BOOL(ce_wrs_rx_en);
+		READ_U8_ARR(ci_hr_factor, CHNL_BW_MAX, true);
+		READ_BOOL(ci_signal_extension_en);
+		READ_BOOL(ci_vht_cap_24g);
+		READ_U32(ci_tx_digital_gain);
+		READ_U32(ci_tx_digital_gain_cck);
+		READ_S8(ci_ofdm_cck_power_offset);
+		READ_BOOL(ci_mac_clk_gating_en);
+		READ_BOOL(ci_phy_clk_gating_en);
+		READ_BOOL(ci_imaging_blocker);
+		READ_U8(ci_sensing_ndp_tx_chain_mask);
+		READ_U8(ci_sensing_ndp_tx_bw);
+		READ_U8(ci_sensing_ndp_tx_format);
+		READ_U8(ci_sensing_ndp_tx_num_ltf);
+		READ_U8_ARR(ci_calib_ant_tx, MAX_ANTENNAS, true);
+		READ_U8_ARR(ci_calib_ant_rx, MAX_ANTENNAS, true);
+		READ_S8(ci_cca_ed_rise_thr_dbm);
+		READ_S8(ci_cca_ed_fall_thr_dbm);
+		READ_U8(ci_cca_cs_en);
+		READ_U8(ci_cca_modem_en);
+		READ_U8(ci_cca_main_ant);
+		READ_U8(ci_cca_second_ant);
+		READ_U8(ci_cca_flag0_ctrl);
+		READ_U8(ci_cca_flag1_ctrl);
+		READ_U8(ci_cca_flag2_ctrl);
+		READ_U8(ci_cca_flag3_ctrl);
+		READ_S8(ci_cca_gi_rise_thr_dbm);
+		READ_S8(ci_cca_gi_fall_thr_dbm);
+		READ_S8(ci_cca_gi_pow_lim_dbm);
+		READ_U16(ci_cca_ed_en);
+		READ_U8(ci_cca_gi_en);
+		READ_BOOL(ci_rx_he_mu_ppdu);
+		READ_BOOL(ci_fast_rx_en);
+		READ_U8(ci_distance_auto_resp_all);
+		READ_U8(ci_distance_auto_resp_msta);
+		READ_BOOL(ci_fw_disable_recovery);
+		READ_BOOL(ce_listener_en);
+		READ_BOOL(ci_tx_delay_tstamp_en);
+		READ_U8_ARR(ci_calib_tx_init_tx_gain, MAX_ANTENNAS, true);
+		READ_U8_ARR(ci_calib_tx_init_rx_gain, MAX_ANTENNAS, true);
+		READ_U8_ARR(ci_calib_rx_init_tx_gain, MAX_ANTENNAS, true);
+		READ_U8_ARR(ci_calib_rx_init_rx_gain, MAX_ANTENNAS, true);
+		READ_U8(ci_calib_conf_rx_gain_upper_limit);
+		READ_U8(ci_calib_conf_rx_gain_lower_limit);
+		READ_U8_ARR(ci_calib_conf_tone_vector_20bw, IQ_NUM_TONES_REQ, true);
+		READ_U8_ARR(ci_calib_conf_tone_vector_40bw, IQ_NUM_TONES_REQ, true);
+		READ_U8_ARR(ci_calib_conf_tone_vector_80bw, IQ_NUM_TONES_REQ, true);
+		READ_U8_ARR(ci_calib_conf_tone_vector_160bw, IQ_NUM_TONES_REQ, true);
+		READ_U32(ci_calib_conf_gp_rad_trshld);
+		READ_U32(ci_calib_conf_ga_lin_upper_trshld);
+		READ_U32(ci_calib_conf_ga_lin_lower_trshld);
+		READ_U8(ci_calib_conf_singletons_num);
+		READ_U16(ci_calib_conf_rampup_time);
+		READ_U16(ci_calib_conf_lo_coarse_step);
+		READ_U16(ci_calib_conf_lo_fine_step);
+
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+		if (cl_hw_is_tcv0(cl_hw)) {
+			READ_U16_ARR(ci_calib_eeprom_channels_20mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_40mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_80mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_160mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0, false);
+		}
+		if (cl_hw_is_tcv1(cl_hw)) {
+			READ_U16_ARR(ci_calib_eeprom_channels_20mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV1, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_40mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV1, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_80mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV1, false);
+			READ_U16_ARR(ci_calib_eeprom_channels_160mhz,
+				     EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV1, false);
+		}
+#endif
+		READ_U16_ARR(ci_mesh_basic_rates, MESH_BASIC_RATE_MAX, false);
+	} while (0);
+
+	if (ret == -ENOENT) {
+		if (cl_config_is_non_driver_param(name))
+			ret = 0;
+		else
+			CL_DBG_ERROR(cl_hw, "No matching conf for nvram parameter %s\n", name);
+	}
+
+	return ret;
+}
+
+static int cl_tcv_set_all_params_from_buf(struct cl_hw *cl_hw, char *buf, size_t size)
+{
+	char *line = buf;
+	char name[MAX_PARAM_NAME_LENGTH];
+	char value[STR_LEN_256B];
+	char *begin;
+	char *end;
+	int ret = 0;
+	int name_length = 0;
+	int value_length = 0;
+
+	while (line && strlen(line) && (line != (buf + size))) {
+		if ((*line == '#') || (*line == '\n')) {
+			/* Skip comment or blank line */
+			line = strstr(line, "\n") + 1;
+		} else if (*line) {
+			begin = line;
+			end = strstr(begin, "=");
+
+			if (!end) {
+				ret = -EBADMSG;
+				goto exit;
+			}
+
+			end++;
+			name_length = end - begin;
+			value_length = strstr(end, "\n") - end + 1;
+
+			if (name_length >= MAX_PARAM_NAME_LENGTH) {
+				cl_dbg_err(cl_hw,
+					   "Name too long (%u)\n", name_length);
+				ret = -EBADMSG;
+				goto exit;
+			}
+			if (value_length >= STR_LEN_256B) {
+				cl_dbg_err(cl_hw,
+					   "Value too long (%u)\n", value_length);
+				ret = -EBADMSG;
+				goto exit;
+			}
+
+			snprintf(name, name_length, "%s", begin);
+			snprintf(value, value_length, "%s", end);
+
+			ret = cl_tcv_update_config(cl_hw, name, value);
+			if (ret)
+				goto exit;
+
+			line = strstr(line, "\n") + 1;
+		}
+	}
+
+exit:
+
+	return ret;
+}
+
+static bool cl_tcv_is_valid_min_spacing(u8 min_spacing)
+{
+	return ((min_spacing == 0) ||
+		(min_spacing == 1) ||
+		(min_spacing == 2) ||
+		(min_spacing == 3) ||
+		(min_spacing == 4) ||
+		(min_spacing == 6) ||
+		(min_spacing == 8) ||
+		(min_spacing == 10) ||
+		(min_spacing == 12) ||
+		(min_spacing == 14) ||
+		(min_spacing == 16) ||
+		(min_spacing == 18) ||
+		(min_spacing == 20) ||
+		(min_spacing == 24) ||
+		(min_spacing ==  CL_TX_MPDU_SPACING_INVALID));
+}
+
+static bool cl_tcv_is_valid_cca_config(struct cl_hw *cl_hw, struct cl_tcv_conf *conf)
+{
+	if (conf->ci_cca_ed_rise_thr_dbm <= conf->ci_cca_ed_fall_thr_dbm) {
+		CL_DBG_ERROR(cl_hw, "cca_ed_rise_thr_dbm (%u) <= cca_ed_fall_thr_dbm (%u)\n",
+			     conf->ci_cca_ed_rise_thr_dbm, conf->ci_cca_ed_fall_thr_dbm);
+		return false;
+	}
+
+	if (conf->ci_cca_gi_rise_thr_dbm <= conf->ci_cca_gi_fall_thr_dbm) {
+		CL_DBG_ERROR(cl_hw, "cca_gi_rise_thr_dbm (%u) <= cca_gi_fall_thr_dbm (%u)\n",
+			     conf->ci_cca_gi_rise_thr_dbm, conf->ci_cca_gi_fall_thr_dbm);
+		return false;
+	}
+
+	if (conf->ci_cca_gi_pow_lim_dbm <= conf->ci_cca_ed_rise_thr_dbm) {
+		CL_DBG_ERROR(cl_hw, "cca_gi_pow_lim_dbm (%u) <= cca_ed_rise_thr_dbm (%u)\n",
+			     conf->ci_cca_gi_pow_lim_dbm, conf->ci_cca_ed_rise_thr_dbm);
+		return false;
+	}
+
+	return true;
+}
+
+static inline void cl_tcv_set_default_channel(u32 *channel, u32 value)
+{
+	if (*channel == INVALID_CHAN_IDX)
+		*channel = value;
+}
+
+static inline void cl_tcv_set_default_bandwidth(u8 *bw, u8 value)
+{
+	if (*bw == CHNL_BW_MAX)
+		*bw = value;
+}
+
+static inline bool cl_tcv_is_valid_bandwidth(u8 *bw, u8 max_value)
+{
+	return *bw <= max_value;
+}
+
+static bool cl_tcv_is_valid_channeling_context(struct cl_hw *cl_hw)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	u32 dflt_channel = 1;
+	u8 bw_limit = CHNL_BW_20;
+	char *band_str = "?";
+
+	if (cl_band_is_24g(cl_hw)) {
+		dflt_channel = 1;
+		bw_limit = CHNL_BW_40;
+		band_str = "24g";
+	} else if (cl_band_is_5g(cl_hw)) {
+		dflt_channel = 36;
+		bw_limit = CHNL_BW_160;
+		band_str = "5g";
+	} else {
+		dflt_channel = 1;
+		bw_limit = CHNL_BW_160;
+		band_str = "6g";
+	}
+
+	cl_tcv_set_default_channel(&conf->ci_chandef_channel, dflt_channel);
+	cl_tcv_set_default_bandwidth(&conf->ci_chandef_bandwidth, bw_limit);
+	cl_tcv_set_default_bandwidth(&conf->ci_cap_bandwidth, bw_limit);
+
+	/* Forcibly change BW limit for production mode in 24g */
+	if (cl_band_is_24g(cl_hw) && cl_hw->chip->conf->ce_production_mode)
+		bw_limit = CHNL_BW_160;
+
+	if (!cl_tcv_is_valid_bandwidth(&conf->ci_cap_bandwidth, bw_limit)) {
+		CL_DBG_ERROR(cl_hw, "Invalid channel bandwidth (%u) for %s\n",
+			     conf->ci_cap_bandwidth, band_str);
+		return false;
+	}
+
+	return true;
+}
+
+static int cl_tcv_post_configuration(struct cl_hw *cl_hw, const char *buf)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (conf->ci_max_bss_num > ARRAY_SIZE(cl_hw->addresses)) {
+		CL_DBG_ERROR(cl_hw, "Invalid ci_max_bss_num (%u)\n",
+			     conf->ci_max_bss_num);
+		return -EINVAL;
+	}
+
+	/* Production mode */
+	if (chip->conf->ce_production_mode) {
+		memcpy(cl_hw->rx_sensitivity, conf->ci_rx_sensitivity_prod, MAX_ANTENNAS);
+		conf->ce_prot_mode = 0;
+		/* Production is done in station mode */
+		cl_hw_set_iface_conf(cl_hw, CL_IFCONF_STA);
+
+	} else {
+		if (chip->conf->ci_phy_dev == PHY_DEV_LOOPBACK) {
+			s8 rx_sens_loopback[MAX_ANTENNAS] = {-96, -96, -96, -96, -96, -96};
+
+			memcpy(cl_hw->rx_sensitivity, rx_sens_loopback, MAX_ANTENNAS);
+		} else {
+			memcpy(cl_hw->rx_sensitivity, conf->ci_rx_sensitivity_op, MAX_ANTENNAS);
+		}
+	}
+
+	if (cl_hw_set_antennas(cl_hw)) {
+		CL_DBG_ERROR(cl_hw, "hw set antennas failed!\n");
+		return -EINVAL;
+	}
+
+	if (!cl_tcv_is_valid_cca_config(cl_hw, conf))
+		return -EINVAL;
+
+	if (conf->ce_num_antennas) {
+		/* Validate: ce_num_antennas, ce_rx_nss, ce_tx_nss */
+		if (conf->ce_num_antennas < MIN_ANTENNAS ||
+		    conf->ce_num_antennas > MAX_ANTENNAS) {
+			CL_DBG_ERROR(cl_hw, "Invalid ce_num_antennas (%u)\n",
+				     conf->ce_num_antennas);
+			return -EINVAL;
+		}
+
+		if (conf->ce_rx_nss < 1 ||
+		    conf->ce_rx_nss > WRS_SS_MAX ||
+		    conf->ce_rx_nss > conf->ce_num_antennas) {
+			CL_DBG_ERROR(cl_hw, "Invalid ce_rx_nss (%u)\n", conf->ce_rx_nss);
+			return -EINVAL;
+		}
+
+		if (conf->ce_tx_nss < 1 ||
+		    conf->ce_tx_nss > WRS_SS_MAX ||
+		    conf->ce_tx_nss > conf->ce_num_antennas) {
+			CL_DBG_ERROR(cl_hw, "Invalid ce_tx_nss (%u)\n", conf->ce_tx_nss);
+			return -EINVAL;
+		}
+
+		/* Validate: ce_cck_tx_ant_mask and ce_cck_rx_ant_mask */
+		if (cl_band_is_24g(cl_hw)) {
+			u8 ant_shift = cl_hw_ant_shift(cl_hw);
+			u8 ant_bitmap = (((1 << conf->ce_num_antennas) - 1) << ant_shift);
+			u8 num_cck_ant_tx = hweight8(conf->ce_cck_tx_ant_mask);
+			u8 num_cck_ant_rx = hweight8(conf->ce_cck_rx_ant_mask);
+
+			if ((ant_bitmap & conf->ce_cck_tx_ant_mask) != conf->ce_cck_tx_ant_mask) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask (0x%x), "
+						    "does not match ce_num_antennas mask (0x%x)\n",
+					     conf->ce_cck_tx_ant_mask, ant_bitmap);
+				return -EINVAL;
+			}
+
+			if ((ant_bitmap & conf->ce_cck_rx_ant_mask) != conf->ce_cck_rx_ant_mask) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask (0x%x), "
+						    "does not match ce_num_antennas mask (0x%x)\n",
+					     conf->ce_cck_rx_ant_mask, ant_bitmap);
+				return -EINVAL;
+			}
+
+			if (conf->ce_cck_tx_ant_mask == 0) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask, can't be 0x0\n");
+				return -EINVAL;
+			}
+
+			if (conf->ce_cck_rx_ant_mask == 0) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask, can't be 0x0\n");
+				return -EINVAL;
+			}
+
+			if (num_cck_ant_tx > MAX_ANTENNAS_CCK) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_tx_ant_mask (0x%x), "
+						    "number of set bits exceeds %u\n",
+					     num_cck_ant_tx, MAX_ANTENNAS_CCK);
+				return -EINVAL;
+			}
+
+			if (num_cck_ant_rx > MAX_ANTENNAS_CCK) {
+				CL_DBG_ERROR(cl_hw, "Invalid ce_cck_rx_ant_mask (0x%x), "
+						    "number of set bits exceeds %u\n",
+					     num_cck_ant_rx, MAX_ANTENNAS_CCK);
+				return -EINVAL;
+			}
+		}
+	}
+
+	if (conf->ce_prot_mode == TXL_PROT_RTS) {
+		CL_DBG_ERROR(cl_hw, "ce_prot_mode %u is not supported\n", TXL_PROT_RTS);
+		return -EINVAL;
+	}
+
+	if (!cl_tcv_is_valid_channeling_context(cl_hw))
+		return -EINVAL;
+
+	if (cl_band_is_5g(cl_hw)) {
+		if (!conf->ci_ofdm_only) {
+			CL_DBG_ERROR(cl_hw, "ci_ofdm_only must be set to 1 for 5g band\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Validate ce_bcn_tx_path_min_time */
+	if (conf->ce_bcn_tx_path_min_time <= CL_TX_BCN_PENDING_CHAIN_MIN_TIME) {
+		CL_DBG_ERROR(cl_hw, "Invalid ce_bcn_tx_path_min_time (%u)\n",
+			     conf->ce_bcn_tx_path_min_time);
+		return -EINVAL;
+	}
+
+	if (conf->ci_tx_sw_amsdu_max_packets > MAX_TX_SW_AMSDU_PACKET) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid ci_tx_sw_amsdu_max_packets (%u), set default (%u)\n",
+			   conf->ci_tx_sw_amsdu_max_packets, MAX_TX_SW_AMSDU_PACKET);
+
+		conf->ci_tx_sw_amsdu_max_packets = MAX_TX_SW_AMSDU_PACKET;
+	}
+
+	if (conf->ce_tx_power_control > 100 || conf->ce_tx_power_control < 1) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid ce_tx_power_control (%u), set default 100\n",
+			   conf->ce_tx_power_control);
+
+		conf->ce_tx_power_control = 100;
+	}
+
+	if (conf->ce_max_retry > CL_MAX_NUM_OF_RETRY) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid ce_max_retry (%u), set default to maximum (%u)\n",
+			   conf->ce_max_retry, CL_MAX_NUM_OF_RETRY);
+
+		conf->ce_max_retry = CL_MAX_NUM_OF_RETRY;
+	}
+
+	if (!cl_tcv_is_valid_min_spacing(conf->ci_su_force_min_spacing)) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid ci_su_force_min_spacing (%u), must be 0/1/2/3/4/6/8/10/12/14/16/18/20/24, set default %u\n",
+			   conf->ci_su_force_min_spacing, CL_TX_MPDU_SPACING_INVALID);
+
+		conf->ci_su_force_min_spacing = CL_TX_MPDU_SPACING_INVALID;
+	}
+
+	if (!cl_tcv_is_valid_min_spacing(conf->ci_mu_force_min_spacing)) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid ci_mu_force_min_spacing (%u), must be 0/1/2/3/4/6/8/10/12/14/16/18/20/24, set default %u\n",
+			   conf->ci_mu_force_min_spacing, CL_TX_MPDU_SPACING_INVALID);
+
+		conf->ci_mu_force_min_spacing = CL_TX_MPDU_SPACING_INVALID;
+	}
+
+	if (conf->ci_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 &&
+	    conf->ci_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 &&
+	    conf->ci_max_mpdu_len != IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid 'ci_max_mpdu_len' (%u). Must be 0/1/2. Setting to 0\n",
+			   conf->ci_max_mpdu_len);
+
+		conf->ci_max_mpdu_len = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+	}
+
+	if (cl_hw_is_tcv1(cl_hw) && cl_chip_is_both_enabled(chip)) {
+		/* Check that sum of ce_num_antennas in both TCV's is smaller than max_antennas */
+		struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
+		u8 num_ant_tcv0 = cl_hw_tcv0->conf->ce_num_antennas;
+		u8 num_ant_tcv1 = conf->ce_num_antennas;
+		u8 total_ant = num_ant_tcv0 + num_ant_tcv1;
+
+		if (total_ant > chip->max_antennas) {
+			CL_DBG_ERROR(cl_hw,
+				     "Invalid ce_num_antennas tcv0=%u, tcv1=%u, total=%u, max=%u\n",
+				     num_ant_tcv0, num_ant_tcv1, total_ant, chip->max_antennas);
+			return -1;
+		}
+	}
+
+	if (cl_hw_is_prod_or_listener(cl_hw) && !conf->ce_power_offset_prod_en) {
+		cl_dbg_err(cl_hw, "Disable PPMCS/PPBW in production mode\n");
+
+		if (cl_band_is_6g(cl_hw)) {
+			memset(conf->ce_ppmcs_offset_he_6g, 0,
+			       sizeof(conf->ce_ppmcs_offset_he_6g));
+		} else if (cl_band_is_5g(cl_hw)) {
+			memset(conf->ce_ppmcs_offset_he_36_64, 0,
+			       sizeof(conf->ce_ppmcs_offset_he_36_64));
+			memset(conf->ce_ppmcs_offset_he_100_140, 0,
+			       sizeof(conf->ce_ppmcs_offset_he_100_140));
+			memset(conf->ce_ppmcs_offset_he_149_165, 0,
+			       sizeof(conf->ce_ppmcs_offset_he_149_165));
+			memset(conf->ce_ppmcs_offset_ht_vht_36_64, 0,
+			       sizeof(conf->ce_ppmcs_offset_ht_vht_36_64));
+			memset(conf->ce_ppmcs_offset_ht_vht_100_140, 0,
+			       sizeof(conf->ce_ppmcs_offset_ht_vht_100_140));
+			memset(conf->ce_ppmcs_offset_ht_vht_149_165, 0,
+			       sizeof(conf->ce_ppmcs_offset_ht_vht_149_165));
+			memset(conf->ce_ppmcs_offset_ofdm_36_64, 0,
+			       sizeof(conf->ce_ppmcs_offset_ofdm_36_64));
+			memset(conf->ce_ppmcs_offset_ofdm_100_140, 0,
+			       sizeof(conf->ce_ppmcs_offset_ofdm_100_140));
+			memset(conf->ce_ppmcs_offset_ofdm_149_165, 0,
+			       sizeof(conf->ce_ppmcs_offset_ofdm_149_165));
+		} else {
+			memset(conf->ce_ppmcs_offset_he, 0, sizeof(conf->ce_ppmcs_offset_he));
+			memset(conf->ce_ppmcs_offset_ht, 0, sizeof(conf->ce_ppmcs_offset_ht));
+			memset(conf->ce_ppmcs_offset_ofdm, 0, sizeof(conf->ce_ppmcs_offset_ofdm));
+			memset(conf->ce_ppmcs_offset_cck, 0, sizeof(conf->ce_ppmcs_offset_cck));
+		}
+
+		memset(conf->ce_ppbw_offset, 0, sizeof(conf->ce_ppbw_offset));
+	}
+
+	if (!cl_band_is_24g(cl_hw) && cl_hw->conf->ci_signal_extension_en) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid 'ci_signal_extension_en' (%u). Must be 0 for non 2.4Ghz band. Setting to 0\n",
+			   conf->ce_dyn_mcast_rate_en);
+
+		conf->ci_signal_extension_en = false;
+	}
+
+	if (conf->ce_dyn_mcast_rate_en && cl_band_is_6g(cl_hw)) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid 'ce_dyn_mcast_rate_en' (%u). Must be 0 on 6Ghz band. Setting to 0\n",
+			   conf->ce_dyn_mcast_rate_en);
+
+		conf->ce_dyn_mcast_rate_en = 0;
+	}
+
+	if (conf->ce_dyn_bcast_rate_en && cl_band_is_6g(cl_hw)) {
+		cl_dbg_err(cl_hw, "ERROR: Invalid 'ce_dyn_bcast_rate_en' (%u). Must be 0 on 6Ghz band. Setting to 0\n",
+			   conf->ce_dyn_bcast_rate_en);
+
+		conf->ce_dyn_bcast_rate_en = 0;
+	}
+
+	return 0;
+}
+
+int cl_tcv_config_read(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	char *buf = NULL;
+	size_t size = 0;
+	int ret = 0;
+	char filename[CL_FILENAME_MAX] = {0};
+	u8 tcv_idx = cl_hw->idx;
+
+	snprintf(filename, sizeof(filename), "cl_tcv%u.dat", tcv_idx);
+	pr_debug("%s: %s\n", __func__, filename);
+	size = cl_file_open_and_read(chip, filename, &buf);
+
+	if (!buf) {
+		pr_err("read %s failed !!!\n", filename);
+		return -ENODATA;
+	}
+
+	ret = cl_tcv_set_all_params_from_buf(cl_hw, buf, size);
+	if (ret) {
+		kfree(buf);
+		return ret;
+	}
+
+	ret = cl_tcv_post_configuration(cl_hw, NULL);
+	if (ret) {
+		kfree(buf);
+		return ret;
+	}
+
+	kfree(buf);
+
+	return ret;
+}
+
+int cl_tcv_config_alloc(struct cl_hw *cl_hw)
+{
+	cl_hw->conf = kzalloc(sizeof(*cl_hw->conf), GFP_KERNEL);
+
+	if (!cl_hw->conf)
+		return -ENOMEM;
+
+	/* Copy default values */
+	memcpy(cl_hw->conf, &conf, sizeof(struct cl_tcv_conf));
+
+	return 0;
+}
+
+void cl_tcv_config_free(struct cl_hw *cl_hw)
+{
+	kfree(cl_hw->conf);
+	cl_hw->conf = NULL;
+}
+
+void cl_tcv_config_validate_calib_params(struct cl_hw *cl_hw)
+{
+	struct cl_tcv_conf *conf = cl_hw->conf;
+	u8 chain = 0;
+
+	if (cl_hw->chip->conf->ci_phy_dev == PHY_DEV_ATHOS) {
+		if (cl_hw->chip->rfic_version == ATHOS_B_VER) {
+			for (chain = 0; chain < MAX_ANTENNAS; chain++) {
+				if (conf->ci_calib_tx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+					conf->ci_calib_tx_init_rx_gain[chain] =
+						CALIB_RX_GAIN_DEFAULT_ATHOS_B;
+				if (conf->ci_calib_rx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+					conf->ci_calib_rx_init_rx_gain[chain] =
+						CALIB_RX_GAIN_DEFAULT_ATHOS_B;
+			}
+
+			if (conf->ci_calib_conf_rx_gain_upper_limit == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_conf_rx_gain_upper_limit =
+					CALIB_RX_GAIN_UPPER_LIMIT_ATHOS_B;
+			if (conf->ci_calib_conf_rx_gain_lower_limit == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_conf_rx_gain_lower_limit =
+					CALIB_RX_GAIN_LOWER_LIMIT_ATHOS_B;
+		} else {
+			for (chain = 0; chain < MAX_ANTENNAS; chain++) {
+				if (conf->ci_calib_tx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+					conf->ci_calib_tx_init_rx_gain[chain] =
+						CALIB_RX_GAIN_DEFAULT_ATHOS;
+				if (conf->ci_calib_rx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+					conf->ci_calib_rx_init_rx_gain[chain] =
+						CALIB_RX_GAIN_DEFAULT_ATHOS;
+			}
+
+			if (conf->ci_calib_conf_rx_gain_upper_limit == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_conf_rx_gain_upper_limit =
+					CALIB_RX_GAIN_UPPER_LIMIT_ATHOS;
+			if (conf->ci_calib_conf_rx_gain_lower_limit == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_conf_rx_gain_lower_limit =
+					CALIB_RX_GAIN_LOWER_LIMIT_ATHOS;
+		}
+	} else {
+		for (chain = 0; chain < MAX_ANTENNAS; chain++) {
+			if (conf->ci_calib_tx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_tx_init_rx_gain[chain] = CALIB_RX_GAIN_DEFAULT;
+
+			if (conf->ci_calib_rx_init_rx_gain[chain] == INVALID_CALIB_RX_GAIN)
+				conf->ci_calib_rx_init_rx_gain[chain] = CALIB_RX_GAIN_DEFAULT;
+		}
+
+		if (conf->ci_calib_conf_rx_gain_upper_limit == INVALID_CALIB_RX_GAIN)
+			conf->ci_calib_conf_rx_gain_upper_limit = CALIB_RX_GAIN_UPPER_LIMIT;
+		if (conf->ci_calib_conf_rx_gain_lower_limit == INVALID_CALIB_RX_GAIN)
+			conf->ci_calib_conf_rx_gain_lower_limit = CALIB_RX_GAIN_LOWER_LIMIT;
+	}
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 79/96] cl8k: add tcv.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (77 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 78/96] cl8k: add tcv.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 80/96] cl8k: add temperature.c viktor.barna
                   ` (16 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tcv.h | 283 +++++++++++++++++++++++++
 1 file changed, 283 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tcv.h

diff --git a/drivers/net/wireless/celeno/cl8k/tcv.h b/drivers/net/wireless/celeno/cl8k/tcv.h
new file mode 100644
index 000000000000..99cf0938c5c4
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tcv.h
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_TCV_CONFIG_H
+#define CL_TCV_CONFIG_H
+
+#include "def.h"
+#include "ipc_shared.h"
+#include "radio.h"
+#include "sounding.h"
+#include "eeprom.h"
+
+/**
+ * TCV (=Tranceiver) configuration, is related to the specific band on top
+ * of specific chipset.
+ */
+#define CL_DEFAULT_HAL_IDLE_TIMEOUT 16000  /* Idle request - 16ms */
+#define CL_TX_DEFAULT_AC0_TIMEOUT   500000 /* Background - 500ms */
+#define CL_TX_DEFAULT_AC1_TIMEOUT   300000 /* Best effort - 300ms */
+#define CL_TX_DEFAULT_AC2_TIMEOUT   200000 /* Video - 200ms */
+#define CL_TX_DEFAULT_AC3_TIMEOUT   200000 /* Voice - 200ms */
+#define CL_TX_DEFAULT_BCN_TIMEOUT   150000 /* Beacon - 150ms */
+
+/* Minimal MPDU spacing we support in TX - correspond to FW NX_TX_MPDU_SPACING */
+#define CL_TX_MPDU_SPACING_INVALID 0xFF
+
+enum {
+	CL_RATE_FALLBACK_COUNT_SU,
+	CL_RATE_FALLBACK_COUNT_MU,
+	CL_RATE_FALLBACK_RETRY_COUNT_THR,
+	CL_RATE_FALLBACK_BA_PER_THR,
+	CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR,
+	CL_RATE_FALLBACK_DISABLE_MCS,
+
+	CL_RATE_FALLBACK_MAX,
+};
+
+struct cl_tcv_conf {
+	s8 ce_debug_level;
+	bool ce_radio_on;
+	bool ce_ps_ctrl_enabled;
+	bool ci_ieee80211h;
+	u8 ci_max_bss_num;
+	u8 ci_short_guard_interval;
+	u8 ci_max_mpdu_len;
+	u8 ci_max_ampdu_len_exp;
+	s8 ce_dsp_code[STR_LEN_32B];
+	s8 ce_dsp_data[STR_LEN_32B];
+	s8 ce_dsp_external_data[STR_LEN_32B];
+	bool ci_uapsd_en;
+	bool ce_eirp_regulatory_op_en;
+	bool ce_eirp_regulatory_prod_en;
+	bool ci_agg_tx;
+	bool ci_agg_rx;
+	bool ce_txldpc_en;
+	bool ci_ht_rxldpc_en;
+	bool ci_vht_rxldpc_en;
+	bool ci_he_rxldpc_en;
+	bool ci_cs_required;
+	s8 ci_rx_sensitivity_prod[MAX_ANTENNAS];
+	s8 ci_rx_sensitivity_op[MAX_ANTENNAS];
+	bool ci_min_he_en;
+	u8 ce_cck_tx_ant_mask;
+	u8 ce_cck_rx_ant_mask;
+	u8 ce_rx_nss;
+	u8 ce_tx_nss;
+	u8 ce_num_antennas;
+	u16 ce_max_agg_size_tx;
+	u16 ce_max_agg_size_rx;
+	bool ce_rxamsdu_en;
+	u8 ce_txamsdu_en;
+	u16 ci_tx_amsdu_min_data_rate;
+	u8 ci_tx_sw_amsdu_max_packets;
+	u16 ci_tx_packet_limit;
+	u16 ci_sw_txhdr_pool;
+	u16 ci_amsdu_txhdr_pool;
+	u16 ci_tx_queue_size_agg;
+	u16 ci_tx_queue_size_single;
+	bool ci_tx_push_cntrs_stat_en;
+	bool ci_traffic_mon_en;
+	u16 ci_ipc_rxbuf_size[CL_RX_BUF_MAX];
+	u16 ce_max_retry;
+	u8 ce_short_retry_limit;
+	u8 ce_long_retry_limit;
+	u8 ci_assoc_auth_retry_limit;
+	u8 ci_cap_bandwidth;
+	u32 ci_chandef_channel;
+	u8 ci_chandef_bandwidth;
+	bool ci_cck_in_hw_mode;
+	s8 ce_temp_comp_slope;
+	u32 ci_fw_dbg_severity;
+	u32 ci_fw_dbg_module;
+	u8 ci_lcu_dbg_cfg_inx;
+	u8 ci_dsp_lcu_mode;
+	u32 ci_hal_idle_to;
+	u32 ci_tx_ac0_to;
+	u32 ci_tx_ac1_to;
+	u32 ci_tx_ac2_to;
+	u32 ci_tx_ac3_to;
+	u32 ci_tx_bcn_to;
+	s8 ce_hardware_power_table[STR_LEN_256B];
+	s8 ce_arr_gain[STR_LEN_32B];
+	s8 ce_bf_gain_2_ant[STR_LEN_32B];
+	s8 ce_bf_gain_3_ant[STR_LEN_32B];
+	s8 ce_bf_gain_4_ant[STR_LEN_32B];
+	s8 ce_bf_gain_5_ant[STR_LEN_32B];
+	s8 ce_bf_gain_6_ant[STR_LEN_32B];
+	s8 ce_ant_gain[STR_LEN_32B];
+	s8 ce_ant_gain_36_64[STR_LEN_32B];
+	s8 ce_ant_gain_100_140[STR_LEN_32B];
+	s8 ce_ant_gain_149_165[STR_LEN_32B];
+	s8 ci_min_ant_pwr[STR_LEN_32B];
+	s8 ci_bw_factor[STR_LEN_32B];
+	u8 ce_mcast_rate;
+	bool ce_dyn_mcast_rate_en;
+	bool ce_dyn_bcast_rate_en;
+	u8 ce_default_mcs_ofdm;
+	u8 ce_default_mcs_cck;
+	bool ce_prot_log_nav_en;
+	u8 ce_prot_mode;
+	u8 ce_prot_rate_format;
+	u8 ce_prot_rate_mcs;
+	u8 ce_prot_rate_pre_type;
+	u8 ce_bw_signaling_mode;
+	u8 ci_dyn_cts_sta_thr;
+	s8 ci_vns_pwr_limit;
+	u8 ci_vns_pwr_mode;
+	s8 ci_vns_rssi_auto_resp_thr;
+	s8 ci_vns_rssi_thr;
+	s8 ci_vns_rssi_hys;
+	u16 ci_vns_maintenance_time;
+	u16 ce_bcn_tx_path_min_time;
+	bool ci_backup_bcn_en;
+	bool ce_tx_txop_cut_en;
+	u8 ci_bcns_flushed_cnt_thr;
+	bool ci_phy_err_prevents_phy_dump;
+	u8 ci_tx_rx_delay;
+	u8 ci_fw_assert_time_diff_sec;
+	u8 ci_fw_assert_storm_detect_thd;
+	u32 ce_hw_assert_time_max;
+	u8 ce_bg_assert_print;
+	u8 ce_fw_watchdog_mode;
+	u8 ce_fw_watchdog_limit_count;
+	u32 ce_fw_watchdog_limit_time;
+	s8 ci_rx_remote_cpu_drv;
+	s8 ci_rx_remote_cpu_mac;
+	u16 ci_pending_queue_size;
+	u8 ce_tx_power_control;
+	bool ce_acs_coex_en;
+	u8 ci_dfs_initial_gain;
+	u8 ci_dfs_agc_cd_th;
+	u16 ci_dfs_long_pulse_min;
+	u16 ci_dfs_long_pulse_max;
+	s8 ce_dfs_tbl_overwrite[STR_LEN_64B];
+	/* Power Per MCS values - 6g */
+	s8 ce_ppmcs_offset_he_6g[WRS_MCS_MAX_HE];
+	/* Power Per MCS values - 5g */
+	s8 ce_ppmcs_offset_he_36_64[WRS_MCS_MAX_HE];
+	s8 ce_ppmcs_offset_he_100_140[WRS_MCS_MAX_HE];
+	s8 ce_ppmcs_offset_he_149_165[WRS_MCS_MAX_HE];
+	s8 ce_ppmcs_offset_ht_vht_36_64[WRS_MCS_MAX_VHT];
+	s8 ce_ppmcs_offset_ht_vht_100_140[WRS_MCS_MAX_VHT];
+	s8 ce_ppmcs_offset_ht_vht_149_165[WRS_MCS_MAX_VHT];
+	s8 ce_ppmcs_offset_ofdm_36_64[WRS_MCS_MAX_OFDM];
+	s8 ce_ppmcs_offset_ofdm_100_140[WRS_MCS_MAX_OFDM];
+	s8 ce_ppmcs_offset_ofdm_149_165[WRS_MCS_MAX_OFDM];
+	/* Power Per MCS values - 24g */
+	s8 ce_ppmcs_offset_he[WRS_MCS_MAX_HE];
+	s8 ce_ppmcs_offset_ht[WRS_MCS_MAX_HT];
+	s8 ce_ppmcs_offset_ofdm[WRS_MCS_MAX_OFDM];
+	s8 ce_ppmcs_offset_cck[WRS_MCS_MAX_CCK];
+	/* Power Per BW values - all bands */
+	s8 ce_ppbw_offset[CHNL_BW_MAX];
+	bool ce_power_offset_prod_en;
+	bool ci_bf_en;
+	u8 ci_bf_max_nss;
+	u16 ce_sounding_interval_coefs[SOUNDING_INTERVAL_COEF_MAX];
+	u8 ci_rate_fallback[CL_RATE_FALLBACK_MAX];
+	u16 ce_rx_pkts_budget;
+	u8 ci_band_num;
+	bool ci_mult_ampdu_in_txop_en;
+	u8 ce_wmm_aifsn[AC_MAX];
+	u8 ce_wmm_cwmin[AC_MAX];
+	u8 ce_wmm_cwmax[AC_MAX];
+	u16 ce_wmm_txop[AC_MAX];
+	u8 ci_su_force_min_spacing;
+	u8 ci_mu_force_min_spacing;
+	u8 ci_tf_mac_pad_dur;
+	u32 ci_cca_timeout;
+	u16 ce_tx_ba_session_timeout;
+	bool ci_motion_sense_en;
+	s8 ci_motion_sense_rssi_thr;
+	u8 ci_wrs_max_bw;
+	u8 ci_wrs_min_bw;
+	s8 ci_wrs_fixed_rate[WRS_FIXED_PARAM_MAX];
+	u8 ce_he_mcs_nss_supp_tx[WRS_SS_MAX];
+	u8 ce_he_mcs_nss_supp_rx[WRS_SS_MAX];
+	u8 ce_vht_mcs_nss_supp_tx[WRS_SS_MAX];
+	u8 ce_vht_mcs_nss_supp_rx[WRS_SS_MAX];
+	u8 ci_pe_duration;
+	u8 ci_pe_duration_bcast;
+	u8 ci_gain_update_enable;
+	u8 ci_mcs_sig_b;
+	u8 ci_spp_ksr_value;
+	bool ci_rx_padding_en;
+	bool ci_stats_en;
+	bool ci_bar_disable;
+	bool ci_ofdm_only;
+	bool ci_hw_bsr;
+	bool ci_drop_to_lower_bw;
+	bool ci_force_icmp_single;
+	bool ce_wrs_rx_en;
+	u8 ci_hr_factor[CHNL_BW_MAX];
+	bool ci_csd_en;
+	bool ci_signal_extension_en;
+	bool ci_vht_cap_24g;
+	u32 ci_tx_digital_gain;
+	u32 ci_tx_digital_gain_cck;
+	s8 ci_ofdm_cck_power_offset;
+	bool ci_mac_clk_gating_en;
+	bool ci_phy_clk_gating_en;
+	bool ci_imaging_blocker;
+	u8 ci_sensing_ndp_tx_chain_mask;
+	u8 ci_sensing_ndp_tx_bw;
+	u8 ci_sensing_ndp_tx_format;
+	u8 ci_sensing_ndp_tx_num_ltf;
+	u8 ci_calib_ant_tx[MAX_ANTENNAS];
+	u8 ci_calib_ant_rx[MAX_ANTENNAS];
+	s8 ci_cca_ed_rise_thr_dbm;
+	s8 ci_cca_ed_fall_thr_dbm;
+	u8 ci_cca_cs_en;
+	u8 ci_cca_modem_en;
+	u8 ci_cca_main_ant;
+	u8 ci_cca_second_ant;
+	u8 ci_cca_flag0_ctrl;
+	u8 ci_cca_flag1_ctrl;
+	u8 ci_cca_flag2_ctrl;
+	u8 ci_cca_flag3_ctrl;
+	s8 ci_cca_gi_rise_thr_dbm;
+	s8 ci_cca_gi_fall_thr_dbm;
+	s8 ci_cca_gi_pow_lim_dbm;
+	u16 ci_cca_ed_en;
+	u8 ci_cca_gi_en;
+	bool ci_rx_he_mu_ppdu;
+	bool ci_fast_rx_en;
+	u8 ci_distance_auto_resp_all;
+	u8 ci_distance_auto_resp_msta;
+	bool ci_fw_disable_recovery;
+	bool ce_listener_en;
+	bool ci_tx_delay_tstamp_en;
+	u8 ci_calib_tx_init_tx_gain[MAX_ANTENNAS];
+	u8 ci_calib_tx_init_rx_gain[MAX_ANTENNAS];
+	u8 ci_calib_rx_init_tx_gain[MAX_ANTENNAS];
+	u8 ci_calib_rx_init_rx_gain[MAX_ANTENNAS];
+	u8 ci_calib_conf_rx_gain_upper_limit;
+	u8 ci_calib_conf_rx_gain_lower_limit;
+	u8 ci_calib_conf_tone_vector_20bw[IQ_NUM_TONES_REQ];
+	u8 ci_calib_conf_tone_vector_40bw[IQ_NUM_TONES_REQ];
+	u8 ci_calib_conf_tone_vector_80bw[IQ_NUM_TONES_REQ];
+	u8 ci_calib_conf_tone_vector_160bw[IQ_NUM_TONES_REQ];
+	u32 ci_calib_conf_gp_rad_trshld;
+	u32 ci_calib_conf_ga_lin_upper_trshld;
+	u32 ci_calib_conf_ga_lin_lower_trshld;
+	u8 ci_calib_conf_singletons_num;
+	u16 ci_calib_conf_rampup_time;
+	u16 ci_calib_conf_lo_coarse_step;
+	u16 ci_calib_conf_lo_fine_step;
+#ifdef CONFIG_CL8K_EEPROM_STM24256
+	u16 ci_calib_eeprom_channels_20mhz[EEPROM_CALIB_DATA_ELEM_NUM_20MHZ_TCV0];
+	u16 ci_calib_eeprom_channels_40mhz[EEPROM_CALIB_DATA_ELEM_NUM_40MHZ_TCV0];
+	u16 ci_calib_eeprom_channels_80mhz[EEPROM_CALIB_DATA_ELEM_NUM_80MHZ_TCV0];
+	u16 ci_calib_eeprom_channels_160mhz[EEPROM_CALIB_DATA_ELEM_NUM_160MHZ_TCV0];
+#endif
+	u16 ci_mesh_basic_rates[MESH_BASIC_RATE_MAX];
+};
+
+int cl_tcv_config_read(struct cl_hw *cl_hw);
+u8 cl_tcv_config_get_num_ap(struct cl_hw *cl_hw);
+int cl_tcv_config_alloc(struct cl_hw *cl_hw);
+void cl_tcv_config_free(struct cl_hw *cl_hw);
+void cl_tcv_config_validate_calib_params(struct cl_hw *cl_hw);
+
+#endif /* CL_TCV_CONFIG_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 80/96] cl8k: add temperature.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (78 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 79/96] cl8k: add tcv.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 81/96] cl8k: add temperature.h viktor.barna
                   ` (15 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/temperature.c    | 634 ++++++++++++++++++
 1 file changed, 634 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.c

diff --git a/drivers/net/wireless/celeno/cl8k/temperature.c b/drivers/net/wireless/celeno/cl8k/temperature.c
new file mode 100644
index 000000000000..f3c773d957f6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/temperature.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/kthread.h>
+
+#include "hw.h"
+#include "e2p.h"
+#include "channel.h"
+#include "power.h"
+#include "debug.h"
+#include "utils.h"
+#include "radio.h"
+#include "temperature.h"
+
+#define TEMP_DIFF_INVALID 0x7F
+
+#define TEMPERATURE_MIN 0
+#define TEMPERATURE_MAX 127
+
+#define DUTY_CYCLE_MAX  100
+#define DUTY_CYCLE_MIN  20
+#define DUTY_CYCLE_STEP 20
+
+#define TEMP_MEASUREMENT_TIMEOUT msecs_to_jiffies(500)
+
+static int cl_temperature_read_fw(struct cl_hw *cl_hw, enum cl_temp_mode desired_temp_mode,
+				  u16 *raw_bits)
+{
+	u8 retval = 0;
+	struct mm_anamon_read_cfm *cfm;
+
+	if (cl_msg_tx_anamon_read(cl_hw, ANAMON_MODE_TEMPERATURE, desired_temp_mode, 0) != 0) {
+		cl_dbg_err(cl_hw, "cl_msg_tx_anamon_read failed\n");
+		cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+		return -1;
+	}
+
+	cfm = (struct mm_anamon_read_cfm *)(cl_hw->msg_cfm_params[MM_ANAMON_READ_CFM]);
+	if (!cfm)
+		return -ENOMSG;
+
+	retval = cfm->retval;
+	*raw_bits = ((le16_to_cpu(cfm->raw_bits_data_0) + le16_to_cpu(cfm->raw_bits_data_1)) / 2);
+	cl_msg_tx_free_cfm_params(cl_hw, MM_ANAMON_READ_CFM);
+
+	return retval ? 0 : -1;
+}
+
+static s16 cl_raw_bits_to_temperature(u16 raw_bits, enum cl_temp_mode desired_temp_mode)
+{
+	s16 adcmv = cl_adc_to_mv(raw_bits);
+
+	/* Calculation of external thermistor */
+	if (desired_temp_mode == TEMP_MODE_EXTERNAL) {
+		/*
+		 * External-temperature calculation:
+		 * Ext_tmp = -196 * adcv ^ 3 + 403 * adcv ^ 2 - 356 * adcv + 146
+		 *
+		 * Ext_tmp = -196 * (adcmv / 1000) ^ 3 +
+		 *           403 * (adcmv / 1000) ^ 2 -
+		 *           356 * (adcmv / 1000) +
+		 *           146
+		 *
+		 * Ext_tmp = (-196 * adcmv ^ 3 +
+		 *            403000 * adcmv ^ 2 -
+		 *            356000000 * adcmv +
+		 *            146000000000) / 1000000000
+		 */
+		return (s16)div_s64(-196ULL * adcmv * adcmv * adcmv +
+				    403000ULL * adcmv * adcmv -
+				    356000000ULL * adcmv +
+				    146000000000ULL,
+				    1000000000);
+	}
+
+	/* Calculation of internal thermistor - ADCmv * slope - 163 (slope=0.290) */
+	if (desired_temp_mode == TEMP_MODE_INTERNAL)
+		return ((adcmv * 29) / 100) - 163;
+
+	return 0;
+}
+
+static void cl_temperature_set_power_offset(struct cl_hw *cl_hw, s8 power_offset)
+{
+	s8 total_pwr_offset[MAX_ANTENNAS] = {0};
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	u8 i = 0;
+
+	cl_hw->temp_comp_db.power_offset = power_offset;
+
+	if (chan_idx == INVALID_CHAN_IDX)
+		goto out;
+
+	for (i = 0; i < MAX_ANTENNAS; i++) {
+		total_pwr_offset[i] =
+			(cl_hw->tx_pow_info[chan_idx][i].offset +
+			 POWER_OFFSET_RES * power_offset);
+	}
+
+out:
+	cl_msg_tx_set_ant_pwr_offset(cl_hw, total_pwr_offset);
+}
+
+static void cl_temperature_comp_tcv(struct cl_chip *chip, struct cl_hw *cl_hw, s16 temp_internal)
+{
+	struct cl_temp_comp_db *temp_comp_db = &cl_hw->temp_comp_db;
+	s8 new_power_offset = 0;
+
+	/* Accumulate temperature delta */
+	temp_comp_db->acc_temp_delta += (temp_internal - temp_comp_db->calib_temperature);
+
+	/* Check if it is time to make a new decision */
+	if ((chip->temperature.comp_iterations % CL_TEMP_COMP_ITERATIONS) != 0)
+		return;
+
+	/* Average the temperature delta over the last CL_TEMP_COMP_ITERATIONS samples */
+	temp_comp_db->avg_temp_delta = DIV_ROUND_CLOSEST(temp_comp_db->acc_temp_delta,
+							 CL_TEMP_COMP_ITERATIONS);
+
+	/* Reset accumulated temp delta */
+	temp_comp_db->acc_temp_delta = 0;
+
+	new_power_offset = (s8)DIV_ROUND_CLOSEST(temp_comp_db->avg_temp_delta *
+						 cl_hw->conf->ce_temp_comp_slope, 100);
+
+	if (temp_comp_db->power_offset == new_power_offset)
+		return;
+
+	cl_dbg_trace(cl_hw, "calib_temperature %d, avg_temp_delta %d, power_offset %d\n",
+		     temp_comp_db->calib_temperature,
+		     temp_comp_db->avg_temp_delta,
+		     new_power_offset);
+
+	cl_temperature_set_power_offset(cl_hw, new_power_offset);
+}
+
+static void cl_temperature_comp(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	s16 temp_internal = 0;
+
+	if (!chip->conf->ce_temp_comp_en)
+		return;
+
+	temp_internal = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL);
+	temperature->comp_iterations++;
+
+	cl_dbg_chip_trace(chip, "comp_iterations = %u, temp_internal = %d\n",
+			  (temperature->comp_iterations % CL_TEMP_COMP_ITERATIONS), temp_internal);
+
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_temperature_comp_tcv(chip, chip->cl_hw_tcv0, temp_internal);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_temperature_comp_tcv(chip, chip->cl_hw_tcv1, temp_internal);
+}
+
+static void cl_temperature_tx_duty_cycle(struct cl_chip *chip, u8 duty_cycle)
+{
+	u16 periodic_tx_time_on = chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+	u16 periodic_tx_time_off = chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+	if (cl_chip_is_tcv0_enabled(chip))
+		cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv0,
+						 periodic_tx_time_off, periodic_tx_time_on);
+
+	if (cl_chip_is_tcv1_enabled(chip))
+		cl_msg_tx_start_periodic_tx_time(chip->cl_hw_tcv1,
+						 periodic_tx_time_off, periodic_tx_time_on);
+}
+
+static void cl_temperature_protect_radio_off(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->force_radio_off)
+		return;
+
+	cl_radio_off_chip(chip);
+	temp_protect_db->force_radio_off = true;
+	cl_dbg_chip_verbose(chip, "temperature [%d] >= radio off threshold [%d] --> radio off!\n",
+			    temp_avg, conf->ce_temp_protect_radio_off_th);
+}
+
+static void cl_temperature_protect_radio_on(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+	s16 temp_thr = conf->ce_temp_protect_radio_off_th - CL_TEMP_PROTECT_RADIO_OFF_HYST;
+
+	if (temp_avg >= temp_thr)
+		return;
+
+	cl_radio_on_chip(chip);
+	temp_protect_db->force_radio_off = false;
+	cl_dbg_chip_verbose(chip, "temperature [%d] < radio off threshold - hysteresis [%d] "
+				  "--> radio on!\n",
+			    temp_avg, temp_thr);
+}
+
+static void cl_temperature_protect_dec_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->duty_cycle == DUTY_CYCLE_MIN)
+		return;
+
+	temp_protect_db->duty_cycle -= DUTY_CYCLE_STEP;
+	cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+	cl_dbg_chip_warn(chip,
+			 "temperature [%d] > protect_th_max [%d] --> decrease duty cycle [%u]!\n",
+			 temp_avg, conf->ce_temp_protect_th_max, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_inc_duty_cycle(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	if (temp_protect_db->duty_cycle == DUTY_CYCLE_MAX)
+		return;
+
+	temp_protect_db->duty_cycle += DUTY_CYCLE_STEP;
+	cl_temperature_tx_duty_cycle(chip, temp_protect_db->duty_cycle);
+	cl_dbg_chip_warn(chip,
+			 "temperature [%d] < protect_th_min [%d] --> increase duty cycle [%u]!\n",
+			 temp_avg, conf->ce_temp_protect_th_min, temp_protect_db->duty_cycle);
+}
+
+static void cl_temperature_protect_decision(struct cl_chip *chip, s16 temp_avg)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	struct cl_chip_conf *conf = chip->conf;
+
+	/* Test mode - force test_mode_duty_cycle */
+	if (unlikely(temp_protect_db->test_mode_duty_cycle != DUTY_CYCLE_MAX)) {
+		cl_temperature_tx_duty_cycle(chip, temp_protect_db->test_mode_duty_cycle);
+		return;
+	}
+
+	/* Temperature protection logic:
+	 *
+	 * If the temperature is greater or equal to the radio off threshold
+	 * then set the radio off.
+	 * If the temperature is below the (radio off threshold - hysteresis [10])
+	 * then set the radio on again.
+	 *
+	 * Any time the temperature is greater than the max threshold then we
+	 * decrease the duty cycle.
+	 * Any time the temperature is below the min threshold then we increase
+	 * the duty cycle.
+	 */
+	if (temp_avg >= conf->ce_temp_protect_radio_off_th) {
+		cl_temperature_protect_radio_off(chip, temp_avg);
+		return;
+	}
+
+	if (temp_protect_db->force_radio_off) {
+		cl_temperature_protect_radio_on(chip, temp_avg);
+		return;
+	}
+
+	if (temp_avg > conf->ce_temp_protect_th_max) {
+		cl_temperature_protect_dec_duty_cycle(chip, temp_avg);
+		return;
+	}
+
+	if (temp_avg < chip->conf->ce_temp_protect_th_min) {
+		cl_temperature_protect_inc_duty_cycle(chip, temp_avg);
+		return;
+	}
+}
+
+static s16 cl_temperature_avg_protect(struct cl_temp_protect_db *temp_protect_db)
+{
+	/* Calculate average of last_samples */
+	u8 i;
+	s32 temp_avg = 0;
+
+	for (i = 0; i < CL_TEMP_PROTECT_NUM_SAMPLES; i++)
+		temp_avg += temp_protect_db->last_samples[i];
+
+	return (s16)(temp_avg / CL_TEMP_PROTECT_NUM_SAMPLES);
+}
+
+static void cl_temperature_protect_handle_read(struct cl_chip *chip, s16 temp)
+{
+	struct cl_temp_protect_db *temp_protect_db = &chip->temperature.protect_db;
+	unsigned long curr_time = jiffies_to_msecs(jiffies);
+	unsigned long delta_time = curr_time - temp_protect_db->last_timestamp;
+
+	/* Add current read */
+	temp_protect_db->last_samples[temp_protect_db->curr_idx] = temp;
+	temp_protect_db->curr_idx = (temp_protect_db->curr_idx + 1) % CL_TEMP_PROTECT_NUM_SAMPLES;
+
+	if (delta_time >= CL_TEMP_PROTECT_INTERVAL_MS) {
+		s16 temp_avg = cl_temperature_avg_protect(temp_protect_db);
+
+		cl_dbg_chip_trace(chip, "temp_avg = %d, delta_time = %lu\n", temp_avg, delta_time);
+		cl_temperature_protect_decision(chip, temp_avg);
+		temp_protect_db->last_timestamp = curr_time;
+	}
+}
+
+static void cl_temperature_protect(struct cl_chip *chip, struct cl_hw *cl_hw)
+{
+	s16 protect_temp = 0;
+	struct cl_chip_conf *conf = chip->conf;
+
+	switch (conf->ce_temp_protect_en) {
+	case TEMP_PROTECT_OFF:
+		return;
+	case TEMP_PROTECT_INTERNAL:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) +
+			conf->ce_temp_protect_delta;
+		break;
+	case TEMP_PROTECT_EXTERNAL:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL) +
+			conf->ce_temp_protect_delta;
+		break;
+	case TEMP_PROTECT_DIFF:
+		protect_temp = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+			chip->temperature.diff_internal_external + conf->ce_temp_protect_delta;
+		break;
+	}
+
+	cl_temperature_protect_handle_read(chip, protect_temp);
+}
+
+static int cl_e2p_read_temp_diff(struct cl_chip *chip, s8 *temp_diff)
+{
+	/* Read temp_diff from eeprom */
+	return cl_e2p_read(chip, temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_e2p_write_temp_diff(struct cl_chip *chip, s8 temp_diff)
+{
+	/* Writing temp_diff to eeprom */
+	return cl_e2p_write(chip, (u8 *)&temp_diff, SIZE_GEN_TEMP_DIFF, ADDR_GEN_TEMP_DIFF);
+}
+
+static int cl_temperature_diff_update(struct cl_hw *cl_hw)
+{
+	s8 temp_diff = cl_temperature_read(cl_hw, TEMP_MODE_INTERNAL) -
+		cl_temperature_read(cl_hw, TEMP_MODE_EXTERNAL);
+
+	if (cl_e2p_write_temp_diff(cl_hw->chip, temp_diff)) {
+		cl_dbg_err(cl_hw, "Error occurred while writing temperature diff to EEPROM.\n");
+		return -1;
+	}
+
+	cl_hw->chip->temperature.diff_internal_external = temp_diff;
+	return 0;
+}
+
+static struct cl_hw *cl_init_measurement(struct cl_chip *chip)
+{
+	struct cl_hw *cl_hw = NULL;
+
+	mutex_lock(&chip->temperature.hw_lock);
+	cl_hw = cl_chip_is_tcv0_enabled(chip) ? chip->cl_hw_tcv0 : chip->cl_hw_tcv1;
+	if (cl_hw && test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) &&
+	    !(cl_hw->conf && cl_hw->conf->ce_listener_en))
+		set_bit(cl_hw->tcv_idx, &chip->temperature.used_hw_map);
+	else
+		cl_hw = NULL;
+	mutex_unlock(&chip->temperature.hw_lock);
+
+	return cl_hw;
+}
+
+static void cl_deinit_measurement(struct cl_hw *cl_hw)
+{
+	struct cl_temperature *temperature = &cl_hw->chip->temperature;
+
+	clear_bit(cl_hw->tcv_idx, &temperature->used_hw_map);
+	wake_up(&temperature->measurement_done);
+}
+
+void cl_temperature_wait_for_measurement(struct cl_chip *chip, u8 tcv_idx)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	int timeout = 0;
+
+	mutex_lock(&temperature->hw_lock);
+	if (!test_bit(tcv_idx, &temperature->used_hw_map))
+		goto exit;
+
+	timeout = wait_event_timeout(temperature->measurement_done,
+				     !test_bit(tcv_idx, &temperature->used_hw_map),
+				     TEMP_MEASUREMENT_TIMEOUT);
+	WARN_ONCE(timeout != 0, "Measurment timeout reached!\n");
+
+exit:
+	mutex_unlock(&temperature->hw_lock);
+}
+
+static int cl_temperature_kthread(void *arg)
+{
+	struct cl_chip *chip = (struct cl_chip *)arg;
+	struct cl_hw *cl_hw = NULL;
+	unsigned long timeout = msecs_to_jiffies(CL_TEMPERATURE_TIMER_INTERVAL_MS);
+
+	while (!kthread_should_stop()) {
+		cl_hw = cl_init_measurement(chip);
+		if (cl_hw) {
+			cl_temperature_comp(chip, cl_hw);
+			cl_temperature_protect(chip, cl_hw);
+			cl_deinit_measurement(cl_hw);
+		}
+
+		if (wait_event_timeout(chip->temperature.wait_done,
+				       kthread_should_stop(), timeout)) {
+			cl_dbg_chip_trace(chip, "exit temperature kthread\n");
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static void cl_temperature_recovery_protect(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+
+	if (chip->conf->ce_temp_protect_en != TEMP_PROTECT_OFF) {
+		u8 duty_cycle = chip->temperature.protect_db.duty_cycle;
+
+		if (duty_cycle < DUTY_CYCLE_MAX) {
+			u16 periodic_tx_time_on =
+				chip->conf->ce_temp_protect_tx_period_ms * duty_cycle / 100;
+			u16 periodic_tx_time_off =
+				chip->conf->ce_temp_protect_tx_period_ms - periodic_tx_time_on;
+
+			cl_msg_tx_start_periodic_tx_time(cl_hw, periodic_tx_time_off,
+							 periodic_tx_time_on);
+		}
+	}
+}
+
+static void cl_temperature_recovery_comp(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	s8 power_offset = cl_hw->temp_comp_db.power_offset;
+
+	if (!chip->conf->ce_temp_comp_en)
+		return;
+
+	if (power_offset)
+		cl_temperature_set_power_offset(cl_hw, power_offset);
+}
+
+void cl_temperature_init(struct cl_chip *chip)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+	struct cl_temp_protect_db *temp_protect_db = &temperature->protect_db;
+	unsigned long curr_time_ms = jiffies_to_msecs(jiffies);
+
+	init_waitqueue_head(&temperature->wait_done);
+	init_waitqueue_head(&temperature->measurement_done);
+
+	mutex_init(&temperature->mutex);
+	mutex_init(&temperature->hw_lock);
+
+	temperature->internal_last = UNCALIBRATED_TEMPERATURE;
+	temperature->internal_read_timestamp = curr_time_ms;
+	temperature->external_last = UNCALIBRATED_TEMPERATURE;
+	temperature->external_read_timestamp = curr_time_ms;
+
+	/* Temp_protect_db init */
+	temp_protect_db->duty_cycle = DUTY_CYCLE_MAX;
+	temp_protect_db->test_mode_duty_cycle = DUTY_CYCLE_MAX;
+	temp_protect_db->last_timestamp = curr_time_ms;
+
+	temperature->kthread = kthread_run(cl_temperature_kthread,
+					   chip,
+					   "cl_temperature_kthread_%u",
+					   chip->idx);
+	if (IS_ERR(temperature->kthread)) {
+		cl_dbg_chip_err(chip, "Failed to create temperature kthread\n");
+		temperature->kthread = NULL;
+	}
+}
+
+void cl_temperature_close(struct cl_chip *chip)
+{
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (temperature->kthread) {
+		cl_dbg_chip_trace(chip, "stopping temperature kthread\n");
+		if (kthread_stop(temperature->kthread) != -EINTR)
+			wake_up(&temperature->wait_done);
+
+		temperature->kthread = NULL;
+	}
+}
+
+s8 cl_temperature_read(struct cl_hw *cl_hw, enum cl_temp_mode mode)
+{
+	u16 raw_bits = 0;
+	s16 temp_val = 0;
+	unsigned long curr_time = jiffies_to_msecs(jiffies);
+	unsigned long diff_time = 0;
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (!IS_REAL_PHY(chip))
+		return UNCALIBRATED_TEMPERATURE;
+
+	mutex_lock(&temperature->mutex);
+
+	switch (mode) {
+	case TEMP_MODE_INTERNAL:
+		diff_time = curr_time - temperature->internal_read_timestamp;
+		if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+			temp_val = temperature->internal_last;
+			cl_dbg_chip_trace(chip, "Return last internal temperature %d\n", temp_val);
+			goto read_out;
+		}
+		break;
+	case TEMP_MODE_EXTERNAL:
+		diff_time = curr_time - temperature->external_read_timestamp;
+		if (diff_time <= CL_TEMPERATURE_UPDATE_INTERVAL_MS) {
+			temp_val = temperature->external_last;
+			cl_dbg_chip_trace(chip, "Return last external temperature %d\n", temp_val);
+			goto read_out;
+		}
+		break;
+	default:
+		cl_dbg_chip_err(chip, "Invalid temperature mode %d\n", mode);
+		goto read_err;
+	}
+
+	if (cl_temperature_read_fw(cl_hw, mode, &raw_bits)) {
+		cl_dbg_chip_err(chip, "Temperature read failed\n");
+		goto read_err;
+	}
+
+	temp_val = cl_raw_bits_to_temperature(raw_bits, mode);
+
+	if (temp_val > TEMPERATURE_MAX || temp_val < TEMPERATURE_MIN) {
+		cl_dbg_chip_err(chip, "Invalid temperature value %d\n", temp_val);
+		goto read_err;
+	}
+
+	/* Update temperature read db */
+	if (mode == TEMP_MODE_INTERNAL) {
+		temperature->internal_last = temp_val;
+		temperature->internal_read_timestamp = jiffies_to_msecs(jiffies);
+		cl_dbg_chip_trace(chip, "Read and save internal temperature %d\n", temp_val);
+	} else {
+		temperature->external_last = temp_val;
+		temperature->external_read_timestamp = jiffies_to_msecs(jiffies);
+		cl_dbg_chip_trace(chip, "Read and save external temperature %d\n", temp_val);
+	}
+
+read_out:
+	mutex_unlock(&temperature->mutex);
+	return temp_val;
+
+read_err:
+	/* If temperature read failed return the last valid value */
+	mutex_unlock(&temperature->mutex);
+
+	return (mode == TEMP_MODE_INTERNAL) ?
+		temperature->internal_last : temperature->external_last;
+}
+
+void cl_temperature_recovery(struct cl_hw *cl_hw)
+{
+	cl_temperature_recovery_protect(cl_hw);
+	cl_temperature_recovery_comp(cl_hw);
+}
+
+int cl_temperature_diff_e2p_read(struct cl_hw *cl_hw)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_temperature *temperature = &chip->temperature;
+
+	if (cl_e2p_read_temp_diff(chip, &temperature->diff_internal_external) ||
+	    temperature->diff_internal_external == TEMP_DIFF_INVALID) {
+		if (cl_temperature_diff_update(cl_hw))
+			return -1;
+
+		cl_dbg_chip_verbose(chip, "Temperature difference: Internal - External = %d\n",
+				    temperature->diff_internal_external);
+	}
+
+	return 0;
+}
+
+s16 cl_temperature_calib_calc(struct cl_hw *cl_hw, u16 raw_bits)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	s16 temperature = cl_raw_bits_to_temperature(raw_bits, TEMP_MODE_INTERNAL) +
+		chip->conf->ce_temp_protect_delta;
+
+	if (temperature >= TEMPERATURE_MIN && temperature <= TEMPERATURE_MAX)
+		return temperature;
+
+	cl_dbg_chip_err(chip, "Invalid temperature = %d\n", temperature);
+
+	return (chip->temperature.internal_last + chip->conf->ce_temp_protect_delta);
+}
+
+void cl_temperature_comp_update_calib(struct cl_hw *cl_hw)
+{
+	u8 chan_idx = cl_channel_to_index(cl_hw, cl_hw->channel);
+	u8 ant, ant_cnt = 0;
+	s16 total_temp = 0;
+	struct cl_tx_power_info *info = NULL;
+
+	if (unlikely(chan_idx == INVALID_CHAN_IDX)) {
+		cl_dbg_err(cl_hw, "Unsupported frequency %u\n", cl_hw->center_freq);
+		return;
+	}
+
+	info = &cl_hw->tx_pow_info[chan_idx][0];
+
+	/* Sum up the temperature of all phys */
+	for (ant = 0; ant < MAX_ANTENNAS && ant_cnt < cl_hw->num_antennas; ant++) {
+		if (!(cl_hw->mask_num_antennas & BIT(ant)))
+			continue;
+
+		total_temp += info[ant].temperature;
+		ant_cnt++;
+	}
+
+	/* Average the total temperature and update chan_params */
+	cl_hw->temp_comp_db.calib_temperature = DIV_ROUND_CLOSEST(total_temp, cl_hw->num_antennas);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 81/96] cl8k: add temperature.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (79 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 80/96] cl8k: add temperature.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 82/96] cl8k: add traffic.c viktor.barna
                   ` (14 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/temperature.h    | 71 +++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/temperature.h

diff --git a/drivers/net/wireless/celeno/cl8k/temperature.h b/drivers/net/wireless/celeno/cl8k/temperature.h
new file mode 100644
index 000000000000..e5ab770199e8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/temperature.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_TEMPERATURE_H
+#define CL_TEMPERATURE_H
+
+#include <net/mac80211.h>
+
+#define CL_TEMP_PROTECT_INTERVAL_MS       40000
+#define CL_TEMP_PROTECT_NUM_SAMPLES       4
+#define CL_TEMP_PROTECT_RADIO_OFF_HYST    10
+#define CL_TEMP_COMP_ITERATIONS           4
+#define CL_TEMPERATURE_TIMER_INTERVAL_MS  4000
+#define CL_TEMPERATURE_UPDATE_INTERVAL_MS (CL_TEMPERATURE_TIMER_INTERVAL_MS - 100)
+
+enum cl_temp_state {
+	TEMP_PROTECT_OFF,
+	TEMP_PROTECT_INTERNAL,
+	TEMP_PROTECT_EXTERNAL,
+	TEMP_PROTECT_DIFF
+};
+
+enum cl_temp_mode {
+	TEMP_MODE_INTERNAL,
+	TEMP_MODE_EXTERNAL
+};
+
+struct cl_temp_comp_db {
+	s8 calib_temperature;
+	s8 power_offset;
+	s32 acc_temp_delta;
+	s32 avg_temp_delta;
+};
+
+struct cl_temp_protect_db {
+	bool force_radio_off;
+	u8 duty_cycle;
+	u8 test_mode_duty_cycle;
+	u8 curr_idx;
+	s16 last_samples[CL_TEMP_PROTECT_NUM_SAMPLES];
+	unsigned long last_timestamp;
+};
+
+struct cl_temperature {
+	s8 diff_internal_external;
+	u8 comp_iterations;
+	struct cl_temp_protect_db protect_db;
+	struct task_struct *kthread;
+	wait_queue_head_t wait_done;
+	wait_queue_head_t measurement_done;
+	s16 internal_last;
+	s16 external_last;
+	unsigned long internal_read_timestamp;
+	unsigned long external_read_timestamp;
+	struct mutex mutex;
+	struct mutex hw_lock;
+	unsigned long used_hw_map;
+};
+
+struct cl_chip;
+
+void cl_temperature_init(struct cl_chip *chip);
+void cl_temperature_close(struct cl_chip *chip);
+s8 cl_temperature_read(struct cl_hw *cl_hw, enum cl_temp_mode mode);
+void cl_temperature_recovery(struct cl_hw *cl_hw);
+int cl_temperature_diff_e2p_read(struct cl_hw *cl_hw);
+s16 cl_temperature_calib_calc(struct cl_hw *cl_hw, u16 raw_bits);
+void cl_temperature_comp_update_calib(struct cl_hw *cl_hw);
+void cl_temperature_wait_for_measurement(struct cl_chip *chip, u8 tcv_idx);
+
+#endif /* CL_TEMPERATURE_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 82/96] cl8k: add traffic.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (80 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 81/96] cl8k: add temperature.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 83/96] cl8k: add traffic.h viktor.barna
                   ` (13 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/traffic.c | 254 +++++++++++++++++++++
 1 file changed, 254 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.c

diff --git a/drivers/net/wireless/celeno/cl8k/traffic.c b/drivers/net/wireless/celeno/cl8k/traffic.c
new file mode 100644
index 000000000000..788fd02e28a8
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/traffic.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+#include "bf.h"
+#include "tx.h"
+#include "radio.h"
+#include "utils.h"
+#include "debug.h"
+#include "hw.h"
+#include "traffic.h"
+
+#define TRAFFIC_CNTR_ACTIVE_THR     3       /* 3 * 100ms = 300ms */
+#define TRAFFIC_CNTR_IDLE_THR       20      /* 20 * 100ms = 2sec */
+
+/* Threshold in bytes */
+#define TRAFFIC_ACTIVE_THR_DRV      1920    /* = 150Kbit/sec (150 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_BF       26214   /* = 2mbit/sec (2 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_MU       131070  /* = 10mbit/sec (10 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_6G  2621440 /* = 200mbit/sec (200 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_5G  2621440 /* = 200mbit/sec (200 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_EDCA_24G 655360  /* = 50mbit/sec (50 * 1024 * 1024 / 8 / 10) */
+#define TRAFFIC_ACTIVE_THR_DFS      13107   /* = 1mbit/sec (1 * 1024 * 1024 / 8 / 10) */
+
+static void cl_traffic_mon_ipv4(struct sk_buff *skb, struct cl_sta *cl_sta,
+				enum cl_traffic_mon_direction direction)
+{
+	struct iphdr *iphdr = ip_hdr(skb);
+
+	if (iphdr->protocol == IPPROTO_UDP)
+		cl_sta->traffic_mon[CL_TRFC_MON_PROT_UDP][direction].bytes +=
+			ntohs(iphdr->tot_len) - IPV4_HDR_LEN(iphdr->ihl) - sizeof(struct udphdr);
+	else if (iphdr->protocol == IPPROTO_TCP)
+		cl_sta->traffic_mon[CL_TRFC_MON_PROT_TCP][direction].bytes +=
+			ntohs(iphdr->tot_len) - IPV4_HDR_LEN(iphdr->ihl) - sizeof(struct tcphdr);
+}
+
+static void cl_traffic_mon_ipv6(struct sk_buff *skb, struct cl_sta *cl_sta,
+				enum cl_traffic_mon_direction direction)
+{
+	struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
+
+	if (ipv6hdr->nexthdr == IPPROTO_UDP)
+		cl_sta->traffic_mon[CL_TRFC_MON_PROT_UDP][direction].bytes +=
+			ntohs(ipv6hdr->payload_len) - sizeof(struct udphdr);
+	else if (ipv6hdr->nexthdr == IPPROTO_TCP)
+		cl_sta->traffic_mon[CL_TRFC_MON_PROT_TCP][direction].bytes +=
+			ntohs(ipv6hdr->payload_len) - sizeof(struct tcphdr);
+}
+
+static void cl_traffic_mon_calc(struct sk_buff *skb, struct cl_sta *cl_sta,
+				enum cl_traffic_mon_direction direction)
+{
+	if (cl_set_network_header_if_proto(skb, ETH_P_IP))
+		cl_traffic_mon_ipv4(skb, cl_sta, direction);
+	else if (cl_set_network_header_if_proto(skb, ETH_P_IPV6))
+		cl_traffic_mon_ipv6(skb, cl_sta, direction);
+}
+
+void cl_traffic_mon_tx(struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+	struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+
+	if (cl_hw->conf->ci_traffic_mon_en)
+		cl_traffic_mon_calc(skb, cl_sta, CL_TRFC_MON_DIR_DL);
+}
+
+void cl_traffic_mon_rx(struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+	struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+
+	if (cl_hw->conf->ci_traffic_mon_en)
+		cl_traffic_mon_calc(skb, cl_sta, CL_TRFC_MON_DIR_UL);
+}
+
+void cl_traffic_mon_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	u8 i, j;
+
+	for (i = 0; i < CL_TRFC_MON_PROT_MAX; i++)
+		for (j = 0; j < CL_TRFC_MON_DIR_MAX; j++) {
+			cl_sta->traffic_mon[i][j].bytes_per_sec = cl_sta->traffic_mon[i][j].bytes;
+			cl_sta->traffic_mon[i][j].bytes = 0;
+		}
+}
+
+static void cl_traffic_sta_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				 enum cl_traffic_level level, enum cl_traffic_direction direction)
+{
+	cl_hw->traffic_db.num_active_sta_dir[direction][level]++;
+
+	/* If other direction is not active increase num_active_sta */
+	if (!cl_sta->traffic_db[1 - direction].activity_db[level].is_active)
+		cl_hw->traffic_db.num_active_sta[level]++;
+
+	if (level == TRAFFIC_LEVEL_DRV)	{
+		/*
+		 * Dynamic CTS:
+		 * If protection mode is disabled, environment is clean,
+		 * and station threshold was reached switch to CTS.
+		 */
+		if (cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DRV] ==
+		     cl_hw->conf->ci_dyn_cts_sta_thr) {
+			if (cl_prot_mode_get(cl_hw) == TXL_NO_PROT) {
+				cl_hw->traffic_db.dynamic_cts = true;
+				cl_prot_mode_set(cl_hw, TXL_PROT_CTS);
+			}
+		}
+	} else if (level == TRAFFIC_LEVEL_BF) {
+		if (direction == TRAFFIC_DIRECTION_TX)
+			cl_bf_sta_active(cl_hw, cl_sta, true);
+	}
+}
+
+static void cl_traffic_sta_stop(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				enum cl_traffic_level level, enum cl_traffic_direction direction)
+{
+	cl_hw->traffic_db.num_active_sta_dir[direction][level]--;
+
+	/* If other direction is not active decrease num_active_sta */
+	if (!cl_sta->traffic_db[1 - direction].activity_db[level].is_active)
+		cl_hw->traffic_db.num_active_sta[level]--;
+
+	if (level == TRAFFIC_LEVEL_DRV) {
+		/* Dynamic CTS:
+		 * If it was turned on and active station count became lower than
+		 * threshold --> return to no protection
+		 */
+		if (cl_hw->traffic_db.dynamic_cts) {
+			if (cl_hw->traffic_db.num_active_sta[TRAFFIC_LEVEL_DRV] ==
+			    (cl_hw->conf->ci_dyn_cts_sta_thr - 1)) {
+				cl_hw->traffic_db.dynamic_cts = false;
+				cl_prot_mode_set(cl_hw, TXL_NO_PROT);
+			}
+		}
+	} else if (level == TRAFFIC_LEVEL_BF) {
+		if (direction == TRAFFIC_DIRECTION_TX)
+			cl_bf_sta_active(cl_hw, cl_sta, false);
+	}
+}
+
+static void cl_traffic_check_activity(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				      enum cl_traffic_level level,
+				      enum cl_traffic_direction direction)
+{
+	struct cl_traffic_activity *activity_db =
+		&cl_sta->traffic_db[direction].activity_db[level];
+	u32 num_bytes = cl_sta->traffic_db[direction].num_bytes;
+
+	if (num_bytes > cl_hw->traffic_db.active_bytes_thr[level]) {
+		activity_db->cntr_active++;
+		activity_db->cntr_idle = 0;
+
+		/* If traffic is above threshold for X consective times change state to active */
+		if (!activity_db->is_active &&
+		    activity_db->cntr_active >= TRAFFIC_CNTR_ACTIVE_THR) {
+			activity_db->is_active = true;
+			cl_traffic_sta_start(cl_hw, cl_sta, level, direction);
+		}
+	} else {
+		activity_db->cntr_active = 0;
+		activity_db->cntr_idle++;
+
+		/* If traffic is below threshold for Y consective times change state to idle */
+		if (activity_db->is_active && activity_db->cntr_idle >= TRAFFIC_CNTR_IDLE_THR) {
+			activity_db->is_active = false;
+			cl_traffic_sta_stop(cl_hw, cl_sta, level, direction);
+		}
+	}
+}
+
+static void cl_traffic_monitor_sta_traffic(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	enum cl_traffic_level level = 0;
+
+	/* Check Tx & Rx activity in all levels */
+	for (level = 0; level < TRAFFIC_LEVEL_MAX; level++) {
+		cl_traffic_check_activity(cl_hw, cl_sta, level, TRAFFIC_DIRECTION_TX);
+		cl_traffic_check_activity(cl_hw, cl_sta, level, TRAFFIC_DIRECTION_RX);
+	}
+
+	/* Save previous Tx num bytes */
+	cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes_prev =
+		cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes;
+
+	/* Reset num_bytes */
+	cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes = 0;
+	cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].num_bytes = 0;
+}
+
+void cl_traffic_init(struct cl_hw *cl_hw)
+{
+	struct cl_traffic_main *traffic_db = &cl_hw->traffic_db;
+
+	traffic_db->active_bytes_thr[TRAFFIC_LEVEL_DRV] = TRAFFIC_ACTIVE_THR_DRV;
+	traffic_db->active_bytes_thr[TRAFFIC_LEVEL_BF] = TRAFFIC_ACTIVE_THR_BF;
+	traffic_db->active_bytes_thr[TRAFFIC_LEVEL_MU] = TRAFFIC_ACTIVE_THR_MU;
+
+	if (cl_band_is_6g(cl_hw))
+		traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_6G;
+	else if (cl_band_is_5g(cl_hw))
+		traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_5G;
+	else
+		traffic_db->active_bytes_thr[TRAFFIC_LEVEL_EDCA] = TRAFFIC_ACTIVE_THR_EDCA_24G;
+
+	traffic_db->active_bytes_thr[TRAFFIC_LEVEL_DFS] = TRAFFIC_ACTIVE_THR_DFS;
+}
+
+void cl_traffic_tx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes)
+{
+	cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes += num_bytes;
+	cl_sta->tx_bytes += num_bytes;
+}
+
+void cl_traffic_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes)
+{
+	cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].num_bytes += num_bytes;
+	cl_sta->rx_bytes += num_bytes;
+}
+
+void cl_traffic_maintenance(struct cl_hw *cl_hw)
+{
+	cl_sta_loop(cl_hw, cl_traffic_monitor_sta_traffic);
+}
+
+void cl_traffic_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	/* Check if station disconnected during traffic */
+	enum cl_traffic_level level = 0;
+	enum cl_traffic_direction direction = 0;
+
+	for (direction = 0; direction < TRAFFIC_DIRECTION_MAX; direction++) {
+		for (level = 0; level < TRAFFIC_LEVEL_MAX; level++) {
+			if (cl_sta->traffic_db[direction].activity_db[level].is_active)
+				cl_traffic_sta_stop(cl_hw, cl_sta, level, direction);
+		}
+
+		memset(&cl_sta->traffic_db, 0, sizeof(cl_sta->traffic_db));
+	}
+}
+
+bool cl_traffic_is_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	return (cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].activity_db[TRAFFIC_LEVEL_DRV].is_active ||
+		cl_sta->traffic_db[TRAFFIC_DIRECTION_RX].activity_db[TRAFFIC_LEVEL_DRV].is_active);
+}
+
+bool cl_traffic_is_sta_tx_exist(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	return ((cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes != 0) ||
+		(cl_sta->traffic_db[TRAFFIC_DIRECTION_TX].num_bytes_prev != 0));
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 83/96] cl8k: add traffic.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (81 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 82/96] cl8k: add traffic.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 84/96] cl8k: add tx.c viktor.barna
                   ` (12 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/traffic.h | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/traffic.h

diff --git a/drivers/net/wireless/celeno/cl8k/traffic.h b/drivers/net/wireless/celeno/cl8k/traffic.h
new file mode 100644
index 000000000000..1b820602c94a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/traffic.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_TRAFFIC_H
+#define CL_TRAFFIC_H
+
+#include <linux/dcache.h>
+#include <linux/skbuff.h>
+
+enum cl_traffic_mon_protocol {
+	CL_TRFC_MON_PROT_TCP,
+	CL_TRFC_MON_PROT_UDP,
+	CL_TRFC_MON_PROT_MAX,
+};
+
+enum cl_traffic_mon_direction {
+	CL_TRFC_MON_DIR_DL,
+	CL_TRFC_MON_DIR_UL,
+	CL_TRFC_MON_DIR_MAX,
+};
+
+struct cl_traffic_mon {
+	u32 bytes_per_sec;
+	u32 bytes;
+};
+
+enum cl_traffic_direction {
+	TRAFFIC_DIRECTION_TX,
+	TRAFFIC_DIRECTION_RX,
+
+	TRAFFIC_DIRECTION_MAX
+};
+
+enum cl_traffic_level {
+	TRAFFIC_LEVEL_DRV,
+	TRAFFIC_LEVEL_BF,
+	TRAFFIC_LEVEL_MU,
+	TRAFFIC_LEVEL_EDCA,
+	TRAFFIC_LEVEL_DFS,
+
+	TRAFFIC_LEVEL_MAX
+};
+
+struct cl_traffic_activity {
+	u8 cntr_active;
+	u8 cntr_idle;
+	bool is_active;
+};
+
+struct cl_traffic_sta {
+	struct cl_traffic_activity activity_db[TRAFFIC_LEVEL_MAX];
+	u32 num_bytes;
+	u32 num_bytes_prev;
+};
+
+struct cl_traffic_main {
+	u32 num_active_sta[TRAFFIC_LEVEL_MAX];
+	u32 num_active_sta_dir[TRAFFIC_DIRECTION_MAX][TRAFFIC_LEVEL_MAX];
+	u32 active_bytes_thr[TRAFFIC_LEVEL_MAX];
+	bool dynamic_cts;
+};
+
+struct cl_sta;
+struct cl_hw;
+
+void cl_traffic_mon_tx(struct cl_sta *cl_sta, struct sk_buff *skb);
+void cl_traffic_mon_rx(struct cl_sta *cl_sta, struct sk_buff *skb);
+void cl_traffic_mon_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_traffic_init(struct cl_hw *cl_hw);
+void cl_traffic_tx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes);
+void cl_traffic_rx_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u32 num_bytes);
+void cl_traffic_maintenance(struct cl_hw *cl_hw);
+void cl_traffic_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_traffic_is_sta_active(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_traffic_is_sta_tx_exist(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+
+#endif /* CL_TRAFFIC_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 84/96] cl8k: add tx.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (82 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 83/96] cl8k: add traffic.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 85/96] cl8k: add tx.h viktor.barna
                   ` (11 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx.c | 3397 +++++++++++++++++++++++++
 1 file changed, 3397 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx.c

diff --git a/drivers/net/wireless/celeno/cl8k/tx.c b/drivers/net/wireless/celeno/cl8k/tx.c
new file mode 100644
index 000000000000..52a8d558f3f2
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx.c
@@ -0,0 +1,3397 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "mac_addr.h"
+#include "sta.h"
+#include "hw.h"
+#include "utils.h"
+#include "fw.h"
+#include "key.h"
+#include "dfs.h"
+#include "radio.h"
+#include "enhanced_tim.h"
+#include "rates.h"
+#include "stats.h"
+#include "debug.h"
+#include "tx.h"
+
+/* Expected Acknowledgment */
+#define EXPECTED_NO_ACK 0
+#define EXPECTED_ACK    1
+
+void cl_tx_update_hist_tstamp(struct cl_tx_queue *tx_queue, struct sk_buff *skb,
+			      u32 tstamp_hist[], bool update_skb_ktime)
+{
+	s64 diff_ms;
+	ktime_t ktime = ktime_get();
+
+	diff_ms = ktime_ms_delta(ktime, skb->tstamp);
+
+	if (diff_ms >= DELAY_HIST_SIZE)
+		diff_ms = DELAY_HIST_SIZE - 1;
+
+	tstamp_hist[diff_ms]++;
+
+	if (update_skb_ktime)
+		skb->tstamp = ktime;
+}
+
+static void cl_tx_cpu_single(struct cl_hw *cl_hw)
+{
+	u32 processor_id = smp_processor_id();
+
+	if (processor_id < CPU_MAX_NUM)
+		cl_hw->cpu_cntr.tx_single[processor_id]++;
+}
+
+static void cl_tx_cpu_agg(struct cl_hw *cl_hw)
+{
+	u32 processor_id = smp_processor_id();
+
+	if (processor_id < CPU_MAX_NUM)
+		cl_hw->cpu_cntr.tx_agg[processor_id]++;
+}
+
+static char cl_tx_ctrl_single_frame_type(__le16 fc)
+{
+	if (ieee80211_is_data_qos(fc))
+		return CL_TX_SINGLE_FRAME_TYPE_QOS_DATA;
+	else if (ieee80211_is_qos_nullfunc(fc))
+		return CL_TX_SINGLE_FRAME_TYPE_QOS_NULL;
+	else if (ieee80211_is_mgmt(fc))
+		return CL_TX_SINGLE_FRAME_TYPE_MANAGEMENT;
+	else
+		return CL_TX_SINGLE_FRAME_TYPE_OTHER;
+}
+
+static void cl_tx_single_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+			      u16 frame_len, u8 hdr_pads, bool is_vns)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+	struct txdesc *txdesc = &sw_txhdr->txdesc;
+	struct tx_host_info *host_info = &txdesc->host_info;
+	struct cl_vif *cl_vif = NULL;
+
+	/* Reset txdesc */
+	memset(txdesc, 0, sizeof(struct txdesc));
+
+	/* Vif_index must be filled in even without header conversion */
+	cl_vif = (struct cl_vif *)tx_info->control.vif->drv_priv;
+	host_info->vif_index = cl_vif->vif_index;
+
+	if (hdr_pads)
+		host_info->host_padding |= BIT(0);
+
+	host_info->is_bcn = sw_txhdr->is_bcn;
+	host_info->expected_ack = (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+		EXPECTED_NO_ACK : EXPECTED_ACK;
+
+	/* Beware when prot and sta is unknown */
+	if (key_conf) {
+		frame_len += key_conf->icv_len;
+		host_info->is_protected = true;
+		host_info->hw_key_idx = key_conf->hw_key_idx;
+	}
+
+	host_info->packet_cnt = 1;
+
+	txdesc->umacdesc.packet_len[0] = cpu_to_le16(frame_len);
+	txdesc->e2w_txhdr_param.frame_ctrl = sw_txhdr->fc;
+	txdesc->e2w_result.bcmc = (sw_txhdr->sta_idx == STA_IDX_INVALID);
+	txdesc->e2w_result.tid = sw_txhdr->tid;
+	txdesc->e2w_result.is_vns = is_vns;
+	txdesc->e2w_result.is_txinject = false;
+	txdesc->e2w_result.single_type = cl_tx_ctrl_single_frame_type(sw_txhdr->fc);
+	txdesc->e2w_result.single_valid_sta__agg_e2w_tx_done = !!sw_txhdr->cl_sta;
+	txdesc->e2w_natt_param.sta_index = sw_txhdr->sta_idx;
+
+	/* Set rate control */
+	cl_rate_ctrl_update_desc_single(cl_hw, host_info, sw_txhdr);
+}
+
+static void cl_tx_sub_frame_set(struct cl_sta *cl_sta, u8 tid)
+{
+	struct cl_tx_queue *tx_queue = cl_sta->agg_tx_queues[tid];
+
+	if (tx_queue)
+		tx_queue->total_packets++;
+}
+
+static void cl_tx_send(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+		       struct cl_amsdu_ctrl *amsdu_anchor)
+{
+	struct cl_tx_queue *tx_queue = sw_txhdr->tx_queue;
+	struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+
+	tx_queue->total_packets++;
+
+	if (cl_txq_is_fw_full(tx_queue) || (cl_sta && cl_sta->pause_tx)) {
+		/* If firmware is full push the packet to the queue */
+		cl_txq_push(cl_hw, sw_txhdr);
+	} else if (amsdu_anchor && amsdu_anchor->is_sw_amsdu) {
+		cl_txq_push(cl_hw, sw_txhdr);
+		tasklet_schedule(&cl_hw->tx_task);
+	} else if (!list_empty(&tx_queue->hdrs) || cl_hw->tx_db.force_amsdu) {
+		/*
+		 * If queue in driver is not empty push the packet to the queue,
+		 * and call cl_txq_sched() to transfer packets from the queue to firmware
+		 */
+		cl_txq_push(cl_hw, sw_txhdr);
+		cl_txq_sched(cl_hw, tx_queue);
+	} else {
+		/* Push the packet directly to firmware */
+		cl_tx_push(cl_hw, sw_txhdr, tx_queue);
+	}
+}
+
+void cl_tx_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, struct cl_tx_queue *tx_queue)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	struct ieee80211_key_conf *keyconf = tx_info->control.hw_key;
+	struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+	struct cl_vif *cl_vif = sw_txhdr->cl_vif;
+	u8 tid = sw_txhdr->tid;
+	struct txdesc *txdesc = &sw_txhdr->txdesc;
+	struct tx_host_info *host_info = &txdesc->host_info;
+	struct cl_e2w_txhdr_param *e2w_txhdr_param = &txdesc->e2w_txhdr_param;
+	struct ieee80211_hdr *hdr80211 = sw_txhdr->hdr80211;
+	u8 queue_type = tx_queue->type;
+	bool is_mgmt = ieee80211_is_mgmt(sw_txhdr->fc);
+
+	if (cl_key_is_cipher_ccmp_gcmp(keyconf)) {
+		/*
+		 * In case of CCMP or GCMP encryption we need to inc pn.
+		 * In case of amsdu/header_conversion we need to pass it to firmware as well
+		 */
+		u64 pn = atomic64_inc_return(&keyconf->tx_pn);
+
+		if (txdesc->e2w_natt_param.hdr_conv_enable) {
+			memcpy(&e2w_txhdr_param->encrypt_pn, &pn, CL_CCMP_GCMP_PN_SIZE);
+		} else {
+			u8 hdrlen = ieee80211_hdrlen(sw_txhdr->fc);
+
+			cl_key_ccmp_gcmp_pn_to_hdr((u8 *)hdr80211 + hdrlen, pn, keyconf->keyidx);
+		}
+	}
+
+	if (queue_type == QUEUE_TYPE_AGG) {
+		struct cl_baw *baw = &cl_sta->baws[tid];
+		bool is_amsdu = cl_tx_ctrl_is_amsdu(tx_info);
+
+		if (is_amsdu) {
+			struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+
+			if (sw_txhdr->is_sw_amsdu) {
+				u8 pkt_cnt = sw_txhdr->sw_amsdu_packet_cnt;
+
+				if (pkt_cnt == 1)
+					cl_tx_amsdu_unset(sw_txhdr); /* Clear AMSDU bit. */
+
+				if (hdr80211)
+					hdr80211->seq_ctrl = cpu_to_le16(baw->tid_seq);
+
+				tx_queue->stats_sw_amsdu_cnt[pkt_cnt - 1]++;
+			} else {
+				u8 pkt_cnt = host_info->packet_cnt;
+
+				if (pkt_cnt == 1)
+					cl_tx_amsdu_unset(sw_txhdr); /* Clear AMSDU bit. */
+
+				tx_queue->stats_hw_amsdu_cnt[pkt_cnt - 1]++;
+			}
+
+			/* Reset anchor if needed */
+			if (amsdu_anchor->sw_txhdr == sw_txhdr)
+				cl_tx_amsdu_anchor_init(amsdu_anchor);
+		}
+
+		if (hdr80211)
+			hdr80211->seq_ctrl = cpu_to_le16(baw->tid_seq);
+
+		/* Update sequence number and increase it */
+		e2w_txhdr_param->seq_ctrl = cpu_to_le16(baw->tid_seq);
+		baw->tid_seq = INC_SN(baw->tid_seq);
+
+	} else {
+		/*
+		 * Update sequence number and increase it
+		 * Management sequence number is set by firmware.
+		 */
+		if (!is_mgmt) {
+			hdr80211->seq_ctrl |= cpu_to_le16(cl_vif->sequence_number);
+			cl_vif->sequence_number = INC_SN(cl_vif->sequence_number);
+		} else {
+			if (ieee80211_vif_is_mesh(cl_vif->vif)) {
+				struct ieee80211_mgmt *mgmt = (void *)sw_txhdr->skb->data;
+				u16 capab;
+
+				if (mgmt->u.action.u.addba_req.action_code ==
+				    WLAN_ACTION_ADDBA_RESP) {
+					capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+					capab &= ~IEEE80211_ADDBA_PARAM_AMSDU_MASK;
+					mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+				}
+			}
+		}
+	}
+
+	cl_drv_ops_pkt_fw_send(cl_hw, sw_txhdr, tx_queue);
+}
+
+void cl_tx_single_free_skb(struct cl_hw *cl_hw, struct sk_buff *skb)
+{
+	if (IEEE80211_SKB_CB(skb)->ack_frame_id)
+		ieee80211_tx_status(cl_hw->hw, skb);
+	else
+		dev_kfree_skb_any(skb);
+}
+
+void cl_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		  struct sk_buff *skb, bool is_vns, bool lock)
+{
+	struct cl_tx_queue *tx_queue;
+	struct cl_sw_txhdr *sw_txhdr;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct cl_vif *cl_vif = TX_INFO_TO_CL_VIF(cl_hw, tx_info);
+	struct ieee80211_hdr *hdr80211 = (struct ieee80211_hdr *)skb->data;
+	u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(hdr80211);
+	__le16 fc = hdr80211->frame_control;
+	u16 frame_len = (u16)skb->len;
+	u8 tid = ieee80211_is_data_qos(fc) ? ieee80211_get_tid(hdr80211) : 0;
+	u8 ac = tid_to_ac[tid];
+	bool is_beacon = ieee80211_is_beacon(fc);
+
+	cl_tx_cpu_single(cl_hw);
+
+	if (unlikely(!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+		     test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_hw->tx_packet_cntr.drop.dev_flags++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	if (unlikely(!cl_vif->tx_en || cl_hw->tx_disable_flags)) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_hw->tx_packet_cntr.drop.tx_disable++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	/* Check if packet length exceeds max size */
+	if (unlikely(frame_len > CL_TX_MAX_FRAME_LEN_SINGLE)) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_dbg_err(cl_hw, "frame_len (%u) exceeds max size\n", frame_len);
+		cl_hw->tx_packet_cntr.drop.length_limit++;
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		return;
+	}
+
+	if (cl_sta && cl_sta->key_disable) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_hw->tx_packet_cntr.drop.key_disable++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	/* Allocate sw_txhdr */
+	sw_txhdr = cl_sw_txhdr_alloc(cl_hw);
+
+	if (unlikely(!sw_txhdr)) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_dbg_verbose(cl_hw, "sw_txhdr alloc failed\n");
+		cl_hw->tx_packet_cntr.drop.txhdr_alloc_fail++;
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		return;
+	}
+
+	/* Prepare sw_txhdr */
+	sw_txhdr->hdr80211 = hdr80211;
+	sw_txhdr->hw_queue = tx_info->hw_queue;
+	sw_txhdr->is_bcn = is_beacon;
+	sw_txhdr->skb = skb;
+	sw_txhdr->map_len = frame_len + hdr_pads;
+	sw_txhdr->fc = fc;
+	sw_txhdr->cl_vif = cl_vif;
+	sw_txhdr->tid = tid;
+	sw_txhdr->ac = ac;
+
+	if (cl_sta) {
+		sw_txhdr->cl_sta = cl_sta;
+		sw_txhdr->sta_idx = cl_sta->sta_idx;
+	} else {
+		sw_txhdr->cl_sta = NULL;
+		sw_txhdr->sta_idx = STA_IDX_INVALID;
+	}
+
+	/* Prepare txdesc */
+	cl_tx_single_prep(cl_hw, sw_txhdr, frame_len, hdr_pads, is_vns);
+
+	/*
+	 * Fetch the driver queue.
+	 * IEEE80211_TX_CTL_AMPDU is not set in tx_info->flags, otherwise cl_tx_agg()
+	 * would have been called and not cl_tx_single().
+	 * Therefore there is no need to check if tx_queue is NULL or if queue type
+	 * is QUEUE_TYPE_AGG.
+	 */
+	tx_queue = cl_txq_get(cl_hw, sw_txhdr);
+	if (!tx_queue) {
+		cl_tx_single_free_skb(cl_hw, skb);
+		cl_dbg_verbose(cl_hw, "tx_queue is NULL\n");
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+		return;
+	}
+
+	sw_txhdr->tx_queue = tx_queue;
+
+	if (lock) {
+		if (tx_queue->type == QUEUE_TYPE_BCMC) {
+			/*
+			 * All other broadcast/multicast packets are buffered in
+			 * ieee80211_tx_h_multicast_ps_buf() and will follow the beacon.
+			 */
+			spin_lock_bh(&cl_hw->tx_lock_bcmc);
+			cl_tx_send(cl_hw, sw_txhdr, NULL);
+			spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+		} else {
+			spin_lock_bh(&cl_hw->tx_lock_single);
+			cl_tx_send(cl_hw, sw_txhdr, NULL);
+			spin_unlock_bh(&cl_hw->tx_lock_single);
+		}
+	} else {
+		cl_tx_send(cl_hw, sw_txhdr, NULL);
+	}
+}
+
+void cl_tx_fast_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		       struct sk_buff *skb, bool lock)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+
+	/* hw_key must be set before calling cl_tx_8023_to_wlan() */
+	tx_info->control.hw_key = cl_key_get(cl_sta);
+
+	/* Convert 802.3 to 802.11 header */
+	if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, tid) == 0) {
+		bool is_vns = cl_vns_is_very_near(cl_hw, cl_sta, skb);
+		u8 ac = tid_to_ac[tid];
+
+		tx_info->hw_queue = ac;
+		tx_info->control.vif = cl_sta->cl_vif->vif;
+
+		cl_hw->tx_packet_cntr.forward.drv_fast_single++;
+
+		cl_tx_single(cl_hw, cl_sta, skb, is_vns, lock);
+	}
+}
+
+void cl_tx_agg_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+		    u16 frame_len, u8 hdr_pads, bool hdr_conv)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+	struct txdesc *txdesc = &sw_txhdr->txdesc;
+	struct lmacapi *umacdesc = &txdesc->umacdesc;
+	struct tx_host_info *host_info = &txdesc->host_info;
+	u16 qos_ctrl = sw_txhdr->tid;
+
+	/* Reset txdesc */
+	memset(txdesc, 0, sizeof(struct txdesc));
+
+	txdesc->e2w_result.tid = sw_txhdr->tid;
+	txdesc->e2w_result.is_txinject = false;
+	txdesc->e2w_natt_param.sta_index = sw_txhdr->sta_idx;
+	txdesc->e2w_natt_param.ampdu = true;
+	txdesc->e2w_natt_param.hdr_conv_enable = hdr_conv;
+
+	if (hdr_conv) {
+		if (cl_tx_ctrl_is_amsdu(tx_info))
+			qos_ctrl |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+		txdesc->e2w_txhdr_param.frame_ctrl = sw_txhdr->fc;
+		txdesc->e2w_txhdr_param.qos_ctrl = cpu_to_le16(qos_ctrl);
+	}
+
+	if (hdr_pads)
+		host_info->host_padding |= BIT(0);
+
+	/* Vif_index must be filled in even without header conversion */
+	host_info->vif_index = sw_txhdr->cl_sta->cl_vif->vif_index;
+
+	/* Set the expected_ack flag */
+	host_info->expected_ack = (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+		EXPECTED_NO_ACK : EXPECTED_ACK;
+
+	if (key_conf) {
+		host_info->is_protected = true;
+		host_info->hw_key_idx = key_conf->hw_key_idx;
+
+		if (!hdr_conv)
+			frame_len += key_conf->icv_len;
+	}
+
+	host_info->packet_cnt = 1;
+	umacdesc->packet_len[0] = cpu_to_le16(frame_len);
+
+	/* Set rate control */
+	cl_rate_ctrl_update_desc_agg(cl_hw, host_info);
+}
+
+static __le16 cl_tx_agg_frame_control(struct cl_vif *cl_vif,
+				      struct ieee80211_key_conf *key_conf,
+				      u8 *hdrlen)
+{
+	struct ieee80211_vif *vif = cl_vif->vif;
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	enum nl80211_iftype type = vif->type;
+	__le16 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA);
+
+	if (type == NL80211_IFTYPE_AP) {
+		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+		*hdrlen = 26;
+	} else if (type == NL80211_IFTYPE_STATION) {
+		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+
+		if (sdata->u.mgd.use_4addr) {
+			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+			*hdrlen = 32;
+		} else {
+			*hdrlen = 26;
+		}
+	}
+
+	if (key_conf)
+		fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+
+	return fc;
+}
+
+static void _cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		       struct sk_buff *skb, bool hdr_conv)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct cl_tx_queue *tx_queue = NULL;
+	struct cl_vif *cl_vif = cl_sta->cl_vif;
+	u16 frame_len = (u16)skb->len;
+	u16 total_frame_len = 0;
+	u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+	u8 is_amsdu = cl_tx_ctrl_is_amsdu(tx_info);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+	u8 ac = tid_to_ac[tid];
+	u8 hdrlen = 0;
+
+	cl_tx_cpu_agg(cl_hw);
+
+	if (unlikely(!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+		     test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))) {
+		kfree_skb(skb);
+		cl_hw->tx_packet_cntr.drop.dev_flags++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	if (unlikely(!cl_vif->tx_en || cl_hw->tx_disable_flags)) {
+		kfree_skb(skb);
+		cl_hw->tx_packet_cntr.drop.tx_disable++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	/* Check if packet length exceeds max size */
+	if (unlikely(frame_len > CL_TX_MAX_FRAME_LEN_AGG)) {
+		kfree_skb(skb);
+		cl_dbg_err(cl_hw, "frame_len exceeds max size %d\n", frame_len);
+		cl_hw->tx_packet_cntr.drop.length_limit++;
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		return;
+	}
+
+	if (cl_sta->key_disable) {
+		kfree_skb(skb);
+		cl_hw->tx_packet_cntr.drop.key_disable++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	/* Check if amsdu is enable for current skb */
+	if (is_amsdu) {
+		enum cl_amsdu_result amsdu_res = cl_tx_amsdu_set(cl_hw, cl_sta, skb, tid);
+
+		switch (amsdu_res) {
+		case CL_AMSDU_SKIP:
+			is_amsdu = false;
+			tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+		case CL_AMSDU_ANCHOR_SET:
+			/*
+			 * If new anchor was set, or AMSDU is
+			 * skipped continue building sw_txhdr
+			 */
+			break;
+		case CL_AMSDU_SUB_FRAME_SET:
+			cl_tx_sub_frame_set(cl_sta, tid);
+			fallthrough;
+		case CL_AMSDU_FAILED:
+		default:
+			return;
+		}
+	} else {
+		/*
+		 * If not amsdu & anchor exist. reset current anchor
+		 * in order to avoid reordring packets.
+		 */
+		if (cl_sta->amsdu_anchor[tid].sw_txhdr)
+			cl_tx_amsdu_anchor_init(&cl_sta->amsdu_anchor[tid]);
+	}
+
+	/* Allocate sw_txhdr */
+	sw_txhdr = cl_sw_txhdr_alloc(cl_hw);
+	if (unlikely(!sw_txhdr)) {
+		kfree_skb(skb);
+		cl_dbg_err(cl_hw, "sw_txhdr alloc failed\n");
+		cl_hw->tx_packet_cntr.drop.txhdr_alloc_fail++;
+		cl_vif->trfc_cntrs[ac].tx_errors++;
+		return;
+	}
+
+	if (cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT)
+		tx_info->hw_queue = ac;
+
+	/* Fill sw_txhdr */
+	sw_txhdr->tid = tid;
+	sw_txhdr->ac = ac;
+	sw_txhdr->hw_queue = tx_info->hw_queue;
+	sw_txhdr->cl_sta = cl_sta;
+	sw_txhdr->sta_idx = cl_sta->sta_idx;
+	sw_txhdr->is_bcn = 0;
+	sw_txhdr->skb = skb;
+	sw_txhdr->map_len = frame_len + hdr_pads;
+	sw_txhdr->cl_vif = cl_vif;
+
+	if (cl_sta->amsdu_anchor[tid].is_sw_amsdu) {
+		sw_txhdr->is_sw_amsdu = true;
+		sw_txhdr->sw_amsdu_packet_cnt = 1;
+	} else {
+		sw_txhdr->is_sw_amsdu = false;
+	}
+
+	if (hdr_conv) {
+		sw_txhdr->hdr80211 = NULL;
+		sw_txhdr->fc = cl_tx_agg_frame_control(cl_vif, key_conf, &hdrlen);
+	} else {
+		struct ieee80211_hdr *hdr80211 = (struct ieee80211_hdr *)skb->data;
+		__le16 fc = hdr80211->frame_control;
+
+		sw_txhdr->hdr80211 = hdr80211;
+		sw_txhdr->fc = fc;
+		hdrlen = ieee80211_hdrlen(fc);
+	}
+
+	/* Fetch the relevant agg queue */
+	tx_queue = cl_sta->agg_tx_queues[tid];
+
+	if (unlikely(!tx_queue)) {
+		kfree_skb(skb);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+		cl_dbg_err(cl_hw, "tx_queue is NULL [sta_idx = %u] [tid = %u]\n",
+			   cl_sta->sta_idx, tid);
+		cl_hw->tx_packet_cntr.drop.queue_null++;
+		cl_vif->trfc_cntrs[ac].tx_dropped++;
+		return;
+	}
+
+	sw_txhdr->tx_queue = tx_queue;
+
+	total_frame_len = frame_len + hdrlen - sizeof(struct ethhdr);
+
+	if (key_conf)
+		total_frame_len += key_conf->icv_len;
+
+	/* Prepare txdesc */
+	cl_tx_agg_prep(cl_hw, sw_txhdr, frame_len, hdr_pads, hdr_conv);
+
+	/*
+	 * AMSDU - first sub frame
+	 * !!! Must be done after calling cl_tx_agg_prep() !!!
+	 */
+	if (is_amsdu)
+		cl_tx_amsdu_first_sub_frame(sw_txhdr, cl_sta, skb, tid);
+
+	cl_tx_send(cl_hw, sw_txhdr, &cl_sta->amsdu_anchor[tid]);
+}
+
+void cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+	       struct sk_buff *skb, bool hdr_conv, bool lock)
+{
+	if (lock) {
+		spin_lock_bh(&cl_hw->tx_lock_agg);
+		_cl_tx_agg(cl_hw, cl_sta, skb, hdr_conv);
+		spin_unlock_bh(&cl_hw->tx_lock_agg);
+	} else {
+		_cl_tx_agg(cl_hw, cl_sta, skb, hdr_conv);
+	}
+}
+
+static void cl_tx_reset_session_timer(struct ieee80211_sta *sta, u8 tid)
+{
+	struct tid_ampdu_tx *tid_tx = NULL;
+	struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(sta);
+
+	tid_tx = rcu_dereference(stainfo->ampdu_mlme.tid_tx[tid]);
+
+	if (tid_tx && tid_tx->timeout)
+		tid_tx->last_tx = jiffies;
+}
+
+void cl_tx_fast_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		    struct sk_buff *skb, bool lock)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = cl_sta->cl_vif->vif;
+	u16 ac = skb_get_queue_mapping(skb);
+	u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+
+	tx_info->control.vif = vif;
+	tx_info->control.hw_key = cl_key_get(cl_sta);
+	tx_info->hw_queue = vif->hw_queue[ac];
+	tx_info->flags |= IEEE80211_TX_CTL_AMPDU;
+
+	if (cl_sta->baws[tid].amsdu &&
+	    (cl_wrs_api_get_tx_sta_data_rate(cl_sta) > cl_hw->conf->ci_tx_amsdu_min_data_rate))
+		tx_info->control.flags |= IEEE80211_TX_CTRL_AMSDU;
+
+	cl_tx_agg(cl_hw, cl_sta, skb, true, lock);
+	cl_tx_reset_session_timer(cl_sta->sta, tid);
+	cl_hw->tx_packet_cntr.forward.drv_fast_agg++;
+}
+
+void cl_tx_wlan_to_8023(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ethhdr tmp_eth;
+	struct ethhdr *ehdr;
+	struct {
+		u8 hdr[ETH_ALEN]__aligned(2);
+		__be16 proto;
+	} payload;
+	u16 hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	u8 enc_len = cl_key_get_cipher_len(skb);
+
+	cl_mac_addr_copy(tmp_eth.h_dest, ieee80211_get_DA(hdr));
+	cl_mac_addr_copy(tmp_eth.h_source, ieee80211_get_SA(hdr));
+	skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
+	tmp_eth.h_proto = payload.proto;
+
+	if (enc_len) {
+		memcpy(skb->data + hdrlen,
+		       skb->data + hdrlen + enc_len,
+		       skb->len - hdrlen - enc_len);
+		skb_trim(skb, skb->len - enc_len);
+	}
+
+	if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
+		    tmp_eth.h_proto != htons(ETH_P_AARP) &&
+		    tmp_eth.h_proto != htons(ETH_P_IPX)) ||
+		   ether_addr_equal(payload.hdr, bridge_tunnel_header)))
+		/* Remove RFC1042 or Bridge-Tunnel encapsulation and replace ether_type */
+		hdrlen += ETH_ALEN + 2;
+	else
+		tmp_eth.h_proto = htons(skb->len - hdrlen);
+
+	skb_pull(skb, hdrlen);
+	ehdr = skb_push(skb, sizeof(struct ethhdr));
+	memcpy(ehdr, &tmp_eth, sizeof(tmp_eth));
+}
+
+u16 cl_tx_prepare_wlan_hdr(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			   struct sk_buff *skb, struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	u16 hdrlen = 0;
+	__le16 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
+	struct ieee80211_vif *vif = cl_sta->cl_vif->vif;
+
+	if (tx_info->control.hw_key)
+		fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_AP:
+		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+		/* DA BSSID SA */
+		memcpy(hdr->addr1, skb->data, ETH_ALEN);
+		memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+		memcpy(hdr->addr3, skb->data + ETH_ALEN, ETH_ALEN);
+		hdrlen = 24;
+		break;
+	case NL80211_IFTYPE_STATION:
+		{
+			struct wireless_dev *wdev = skb->dev->ieee80211_ptr;
+
+			if (wdev && wdev->use_4addr) {
+				fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+						IEEE80211_FCTL_TODS);
+				/* RA TA DA SA */
+				memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
+				memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+				memcpy(hdr->addr3, skb->data, ETH_ALEN);
+				memcpy(hdr->addr4, skb->data + ETH_ALEN, ETH_ALEN);
+				hdrlen = 30;
+			} else {
+				fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+				/* BSSID SA DA */
+				memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
+				memcpy(hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN);
+				memcpy(hdr->addr3, skb->data, ETH_ALEN);
+				hdrlen = 24;
+			}
+		}
+		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		cl_dbg_trace(cl_hw, "vif type mesh_point, invalid tx path\n");
+		return 0;
+	default:
+		cl_dbg_err(cl_hw, "Unknown vif type %d !!!\n", vif->type);
+		return 0;
+	}
+
+	if (cl_sta->sta->wme) {
+		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+		hdrlen += 2;
+	}
+
+	hdr->frame_control = fc;
+	hdr->duration_id = 0;
+	hdr->seq_ctrl = 0;
+
+	return hdrlen;
+}
+
+int cl_tx_8023_to_wlan(struct cl_hw *cl_hw, struct sk_buff *skb, struct cl_sta *cl_sta, u8 tid)
+{
+	struct ieee80211_hdr hdr;
+	int head_need, ret = 0;
+	u16 ethertype, hdrlen;
+	const u8 *encaps_data = NULL;
+	int encaps_len = 0, skip_header_bytes = ETH_HLEN;
+	u8 enc_len = cl_key_get_cipher_len(skb);
+
+	/* Convert Ethernet header to proper 802.11 header */
+	ethertype = (skb->data[12] << 8) | skb->data[13];
+
+	hdrlen = cl_tx_prepare_wlan_hdr(cl_hw, cl_sta, skb, &hdr);
+	if (!hdrlen) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	if (ethertype >= ETH_P_802_3_MIN) {
+		encaps_data = rfc1042_header;
+		encaps_len = sizeof(rfc1042_header);
+		skip_header_bytes -= 2;
+	}
+
+	skb_pull(skb, skip_header_bytes);
+	head_need = hdrlen + enc_len + encaps_len - skb_headroom(skb);
+
+	if (head_need > 0) {
+		head_need = ((head_need + 3) & ~3);
+		if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
+			ret = -ENOMEM;
+			goto free;
+		}
+	}
+
+	if (encaps_data)
+		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+
+	skb_push(skb, hdrlen + enc_len);
+
+	if (cl_sta->sta->wme) {
+		u16 qos_ctrl = tid;
+
+		memcpy(skb->data, &hdr, hdrlen - 2);
+		memcpy(skb->data + hdrlen - 2, &qos_ctrl, 2);
+	} else {
+		memcpy(skb->data, &hdr, hdrlen);
+	}
+
+	skb_reset_mac_header(skb);
+
+	return ret;
+free:
+	cl_hw->tx_packet_cntr.drop.build_hdr_fail++;
+	cl_sta->cl_vif->trfc_cntrs[tid_to_ac[tid]].tx_errors++;
+	kfree_skb(skb);
+	skb = NULL;
+
+	return ret;
+}
+
+void cl_tx_check_start_ba_session(struct cl_hw *cl_hw,
+				  struct ieee80211_sta *sta,
+				  struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct sta_info *stainfo = IEEE80211_STA_TO_STAINFO(sta);
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	u8 tid;
+
+	/* TODO: What about HE? */
+	if (!sta->ht_cap.ht_supported &&
+	    !sta->vht_cap.vht_supported &&
+	    !cl_band_is_6g(cl_hw))
+		return;
+
+	if (test_sta_flag(stainfo, WLAN_STA_PS_STA))
+		return;
+
+	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
+	    !(tx_info->flags & IEEE80211_TX_STAT_AMPDU))
+		return;
+
+	if (cl_tx_ctrl_is_eapol(tx_info))
+		return;
+
+	if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+		return;
+
+	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+		return;
+
+	tid = ieee80211_get_tid(hdr);
+
+	if (likely(stainfo->ampdu_mlme.tid_tx[tid]))
+		return;
+
+	ieee80211_start_tx_ba_session(sta, tid, cl_hw->conf->ce_tx_ba_session_timeout);
+}
+
+static void cl_tx_handle_beacon_tim(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)hw->priv;
+	struct cl_sta *cl_sta = NULL;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+	const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, mgmt->u.beacon.variable, skb->len);
+	struct ieee80211_tim_ie *tim = NULL;
+
+	/* Offset of the element */
+	tim = (void *)(tim_ie + BCN_IE_TIM_BIT_OFFSET);
+
+	cl_sta_lock(cl_hw);
+
+	/* Loop through all STA's */
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+		if (cl_traffic_is_sta_tx_exist(cl_hw, cl_sta)) {
+			u8 sta_aid = cl_sta->sta->aid;
+			u8 map_index = sta_aid / BITS_PER_BYTE;
+
+			/* Update STA's AID in TIM bit */
+			tim->virtual_map[map_index] |= BIT(sta_aid % BITS_PER_BYTE);
+		}
+	}
+
+	cl_sta_unlock(cl_hw);
+}
+
+static struct sk_buff *cl_tx_beacon_get(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif)
+{
+	struct sk_buff *skb = NULL;
+
+	skb = ieee80211_beacon_get(hw, vif);
+
+	/* Handle beacon TIM bitmap */
+	if (skb)
+		cl_tx_handle_beacon_tim(hw, skb);
+
+	return skb;
+}
+
+static void cl_tx_mc(struct cl_vif *cl_vif, int *mc_fw_free)
+{
+	struct cl_hw *cl_hw = cl_vif->cl_hw;
+	struct ieee80211_vif *vif = cl_vif->vif;
+	struct sk_buff *skb = NULL;
+	struct ieee80211_tx_info *tx_info;
+
+	if (unlikely(!vif))
+		return;
+
+	while (((*mc_fw_free) > 0) &&
+	       (skb = ieee80211_get_buffered_bc(cl_hw->hw, vif))) {
+		/* Route this MCBC frame to the BCN ipc queue */
+		tx_info = IEEE80211_SKB_CB(skb);
+		tx_info->hw_queue = CL_HWQ_BCN;
+
+		(*mc_fw_free)--;
+
+		/* Clear more data bit if this is the last frame in this SP */
+		if (*mc_fw_free == 0) {
+			struct ieee80211_hdr *hdr =
+					(struct ieee80211_hdr *)skb->data;
+			hdr->frame_control &=
+					cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+		}
+
+		cl_tx_single(cl_hw, NULL, skb, false, true);
+	}
+}
+
+void cl_tx_bcn_mesh_task(unsigned long data)
+{
+	struct cl_vif *cl_vif = NULL;
+	struct cl_hw *cl_hw = NULL;
+	struct ieee80211_tx_info *tx_info;
+	struct sk_buff *skb;
+	int mc_fw_free;
+
+	cl_vif = (struct cl_vif *)data;
+	if (!cl_vif)
+		return;
+
+	cl_hw = cl_vif->cl_hw;
+
+	if (!cl_hw || !cl_vif->vif || cl_vif->vif->type != NL80211_IFTYPE_MESH_POINT ||
+	    cl_radio_is_off(cl_hw) ||
+	    cl_recovery_in_progress(cl_hw) ||
+	    !test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+	    test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags) ||
+	    cl_hw->tx_disable_flags)
+		return;
+
+	skb = cl_tx_beacon_get(cl_hw->hw, cl_vif->vif);
+	if (!skb)
+		return;
+
+	/* Route this BCN to the BCN ipc queue */
+	tx_info = IEEE80211_SKB_CB(skb);
+	tx_info->hw_queue = CL_HWQ_BCN;
+
+	cl_tx_single(cl_hw, NULL, skb, false, true);
+
+	mc_fw_free = cl_hw->tx_queues->bcmc.fw_free_space;
+	cl_tx_mc(cl_vif, &mc_fw_free);
+}
+
+static void cl_tx_bcn(struct cl_vif *cl_vif)
+{
+	struct cl_hw *cl_hw = cl_vif->cl_hw;
+	struct ieee80211_vif *vif = cl_vif->vif;
+	struct ieee80211_tx_info *tx_info;
+	struct sk_buff *skb;
+
+	if (!vif || vif->type != NL80211_IFTYPE_AP)
+		return;
+
+	/*
+	 * If we are in the middle of the CAC, we allow regular channel switch
+	 * and retrigger the CAC (If needed).
+	 * Or - if radar is detected, we wait for all CSAs to be transmitted,
+	 * before allowing channel switch
+	 */
+	if (cl_dfs_is_in_cac(cl_hw) && vif->csa_active) {
+		ieee80211_csa_finish(vif);
+		return;
+	}
+
+	skb = cl_tx_beacon_get(cl_hw->hw, vif);
+	if (!skb)
+		return;
+
+	/* Route this BCN to the BCN ipc queue */
+	tx_info = IEEE80211_SKB_CB(skb);
+	tx_info->hw_queue = CL_HWQ_BCN;
+
+	cl_tx_single(cl_hw, NULL, skb, false, true);
+}
+
+bool cl_is_tx_allowed(struct cl_hw *cl_hw)
+{
+	return !(cl_radio_is_off(cl_hw) ||
+		 cl_hw->vif_db.num_iface_bcn == 0 ||
+		 cl_recovery_in_progress(cl_hw) ||
+		 cl_hw->tx_db.block_bcn ||
+		 cl_hw->tx_disable_flags ||
+		 !test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+		 test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags));
+}
+
+/* cl_tx_bcns_tasklet - generate BCNs and TX buffered MC frames each BCN DTIM interval
+ *
+ * Beacons are sent first followed by cyclic MC for fairness between VIF's
+ * the FW buffer is restricted to "IPC_TXDESC_CNT_BCMC" buffer size.
+ */
+void cl_tx_bcns_tasklet(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+	struct cl_vif *cl_vif = NULL;
+	int mc_fw_free = 0;
+
+	read_lock(&cl_hw->vif_db.lock);
+
+	if (!cl_is_tx_allowed(cl_hw))
+		goto out;
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		cl_tx_bcn(cl_vif);
+
+	cl_vif = cl_hw->mc_vif;
+	mc_fw_free = cl_hw->tx_queues->bcmc.fw_free_space;
+
+	do {
+		cl_tx_mc(cl_vif, &mc_fw_free);
+		/* Cl_vif_get_next() is cyclic */
+		cl_vif = cl_vif_get_next(cl_hw, cl_vif);
+	} while ((cl_vif != cl_hw->mc_vif) && mc_fw_free);
+
+	cl_hw->mc_vif = cl_vif_get_next(cl_hw, cl_hw->mc_vif);
+
+out:
+	read_unlock(&cl_hw->vif_db.lock);
+}
+
+void cl_tx_en(struct cl_hw *cl_hw, u8 reason, bool enable)
+{
+	unsigned long tx_disable_flags_prev = cl_hw->tx_disable_flags;
+
+	if (enable) {
+		clear_bit(reason, &cl_hw->tx_disable_flags);
+
+		if (tx_disable_flags_prev != 0 && cl_hw->tx_disable_flags == 0)
+			if (cl_hw->conf->ci_backup_bcn_en)
+				cl_msg_tx_backup_bcn_en(cl_hw, true);
+	} else {
+		set_bit(reason, &cl_hw->tx_disable_flags);
+
+		if (tx_disable_flags_prev == 0)
+			if (cl_hw->conf->ci_backup_bcn_en)
+				cl_msg_tx_backup_bcn_en(cl_hw, false);
+	}
+}
+
+static void cl_tx_flush(struct cl_hw *cl_hw)
+{
+	/* Flush bcmc */
+	spin_lock_bh(&cl_hw->tx_lock_bcmc);
+	cl_bcmc_cfm_flush_queue(cl_hw, NULL);
+	spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+
+	/* Flush single */
+	spin_lock_bh(&cl_hw->tx_lock_single);
+	cl_txq_flush_all_single(cl_hw);
+	cl_single_cfm_flush_all(cl_hw);
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+
+	/* Flush agg */
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+	cl_txq_flush_all_agg(cl_hw);
+	cl_agg_cfm_flush_all(cl_hw);
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+void cl_tx_off(struct cl_hw *cl_hw)
+{
+	cl_txq_stop(cl_hw);
+	cl_tx_flush(cl_hw);
+}
+
+void cl_tx_drop_skb(struct sk_buff *skb)
+{
+	skb->dev->stats.rx_dropped++;
+	kfree_skb(skb);
+}
+
+#define AGG_POLL_TIMEOUT 50
+
+/*
+ * cl_hw->agg_cfm_queues:
+ * These queues are used to keep pointers to skb's sent
+ * as aggregation and waiting for confirmation.
+ */
+
+void cl_agg_cfm_init(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		INIT_LIST_HEAD(&cl_hw->agg_cfm_queues[i].head);
+}
+
+void cl_agg_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u8 agg_idx)
+{
+	spin_lock(&cl_hw->tx_lock_cfm_agg);
+	list_add_tail(&sw_txhdr->cfm_list, &cl_hw->agg_cfm_queues[agg_idx].head);
+	spin_unlock(&cl_hw->tx_lock_cfm_agg);
+}
+
+static void cl_agg_cfm_amsdu_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	struct cl_amsdu_txhdr *amsdu_txhdr = NULL;
+	struct cl_amsdu_txhdr *tmp = NULL;
+	struct sk_buff *sub_skb = NULL;
+	struct ieee80211_tx_info *tx_info_sub_skb = NULL;
+
+	list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+		sub_skb = amsdu_txhdr->skb;
+		tx_info_sub_skb = IEEE80211_SKB_CB(sub_skb);
+
+		list_del(&amsdu_txhdr->list);
+		dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+				 (size_t)sub_skb->len, DMA_TO_DEVICE);
+		kfree_skb(sub_skb);
+		cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+	}
+}
+
+void cl_agg_cfm_free_head_skb(struct cl_hw *cl_hw,
+			      struct cl_agg_cfm_queue *cfm_queue,
+			      u8 ba_queue_idx)
+{
+	struct cl_sw_txhdr *sw_txhdr = list_first_entry(&cfm_queue->head,
+							struct cl_sw_txhdr,
+							cfm_list);
+	struct sk_buff *skb = sw_txhdr->skb;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	dma_addr_t dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+
+	if (cl_hw->conf->ci_tx_delay_tstamp_en)
+		cl_tx_update_hist_tstamp(cfm_queue->tx_queue, skb,
+					 cfm_queue->tx_queue->hist_push_to_cfm, false);
+
+	dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+	/* If amsdu list not empty free sub MSDU frames first, including amsdu_txhdr */
+	if (cl_tx_ctrl_is_amsdu(tx_info))
+		if (!list_empty(&sw_txhdr->amsdu_txhdr.list))
+			cl_agg_cfm_amsdu_free(cl_hw, sw_txhdr);
+
+	consume_skb(skb);
+	list_del(&sw_txhdr->cfm_list);
+	cl_sw_txhdr_free(cl_hw, sw_txhdr);
+}
+
+static void cl_agg_cfm_flush_queue(struct cl_hw *cl_hw, u8 agg_idx)
+{
+	struct cl_agg_cfm_queue *cfm_queue = &cl_hw->agg_cfm_queues[agg_idx];
+	struct cl_tx_queue *tx_queue = cfm_queue->tx_queue;
+	struct sk_buff *skb = NULL;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	dma_addr_t dma_addr = 0;
+	struct ieee80211_tx_info *tx_info;
+
+	if (!tx_queue)
+		return;
+
+	if (list_empty(&cfm_queue->head))
+		return;
+
+	do {
+		sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+		skb = sw_txhdr->skb;
+
+		dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+		dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+		tx_info = IEEE80211_SKB_CB(skb);
+
+		/* If amsdu list not empty free sub MSDU frames first, including amsdu_txhdr */
+		if (cl_tx_ctrl_is_amsdu(tx_info))
+			if (!list_empty(&sw_txhdr->amsdu_txhdr.list))
+				cl_agg_cfm_amsdu_free(cl_hw, sw_txhdr);
+
+		tx_queue->total_fw_cfm++;
+
+		kfree_skb(skb);
+		list_del(&sw_txhdr->cfm_list);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+	} while (!list_empty(&cfm_queue->head));
+
+	/*
+	 * Set fw_free_space back to maximum after flushing the queue
+	 * and clear the enhanced TIM.
+	 */
+	tx_queue->fw_free_space = tx_queue->fw_max_size;
+	cl_enhanced_tim_clear_tx_agg(cl_hw, agg_idx, tx_queue->hw_index,
+				     tx_queue->cl_sta, tx_queue->tid);
+
+	cfm_queue->tx_queue = NULL;
+}
+
+void cl_agg_cfm_flush_all(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	/* Don't use BH lock, because cl_agg_cfm_flush_all() is called with BH disabled */
+	spin_lock(&cl_hw->tx_lock_cfm_agg);
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		cl_agg_cfm_flush_queue(cl_hw, i);
+
+	spin_unlock(&cl_hw->tx_lock_cfm_agg);
+}
+
+static void cl_agg_cfm_poll_timeout(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+				    u8 agg_idx, bool flush)
+{
+	/*
+	 * When polling failed clear the enhanced TIM so that firmware will
+	 * not try to transmit these packets.
+	 * If flush is set cl_enhanced_tim_clear_tx_agg() is called inside
+	 * cl_agg_cfm_flush_queue().
+	 */
+	cl_dbg_err(cl_hw, "Polling timeout (queue_idx = %u)\n", agg_idx);
+
+	spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+
+	if (flush)
+		cl_agg_cfm_flush_queue(cl_hw, agg_idx);
+	else
+		cl_enhanced_tim_clear_tx_agg(cl_hw, agg_idx, tx_queue->hw_index,
+					     tx_queue->cl_sta, tx_queue->tid);
+
+	spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
+
+void cl_agg_cfm_poll_empty(struct cl_hw *cl_hw, u8 agg_idx, bool flush)
+{
+	struct cl_agg_cfm_queue *cfm_queue = &cl_hw->agg_cfm_queues[agg_idx];
+	bool empty = false;
+	int i = 0;
+
+	if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+		return;
+
+	while (true) {
+		spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+		empty = list_empty(&cfm_queue->head);
+		spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+
+		if (empty)
+			return;
+
+		if (++i == AGG_POLL_TIMEOUT) {
+			cl_agg_cfm_poll_timeout(cl_hw, cfm_queue->tx_queue, agg_idx, flush);
+			return;
+		}
+
+		msleep(20);
+	}
+}
+
+void cl_agg_cfm_poll_empty_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	int i = 0;
+	struct cl_tx_queue *tx_queue = NULL;
+
+	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+		tx_queue = cl_sta->agg_tx_queues[i];
+
+		if (tx_queue)
+			cl_agg_cfm_poll_empty(cl_hw, tx_queue->index, false);
+	}
+}
+
+void cl_agg_cfm_clear_tim_bit_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	int i = 0;
+	struct cl_tx_queue *tx_queue = NULL;
+
+	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+		tx_queue = cl_sta->agg_tx_queues[i];
+
+		if (tx_queue) {
+			spin_lock_bh(&cl_hw->tx_lock_agg);
+			cl_enhanced_tim_clear_tx_agg(cl_hw, tx_queue->index, tx_queue->hw_index,
+						     tx_queue->cl_sta, tx_queue->tid);
+			spin_unlock_bh(&cl_hw->tx_lock_agg);
+		}
+	}
+}
+
+void cl_agg_cfm_set_ssn(struct cl_hw *cl_hw, u16 ssn, u8 idx)
+{
+	spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+	cl_hw->agg_cfm_queues[idx].ssn = ssn;
+	spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
+
+void cl_agg_cfm_set_tx_queue(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 idx)
+{
+	spin_lock_bh(&cl_hw->tx_lock_cfm_agg);
+	cl_hw->agg_cfm_queues[idx].tx_queue = tx_queue;
+	spin_unlock_bh(&cl_hw->tx_lock_cfm_agg);
+}
+
+static bool cl_is_same_rate(struct cl_agg_tx_report *agg_report,
+			    struct cl_wrs_rate_params *rate_params)
+{
+	union cl_rate_ctrl_info rate_ctrl_info = {
+		.word = le32_to_cpu(agg_report->rate_cntrl_info)};
+	u8 mcs = U8_MAX, nss = U8_MAX;
+
+	if (agg_report->bw_requested != rate_params->bw)
+		return false;
+
+	cl_rate_ctrl_parse(&rate_ctrl_info, &nss, &mcs);
+
+	return ((mcs == rate_params->mcs) && (nss == rate_params->nss));
+}
+
+static void cl_sync_tx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			    struct cl_agg_tx_report *agg_report,
+			    struct cl_wrs_info *wrs_info, struct cl_wrs_params *wrs_params)
+{
+	if (!agg_report->is_fallback && cl_is_same_rate(agg_report, &wrs_params->rate_params)) {
+		cl_wrs_api_rate_sync(cl_hw, cl_sta, wrs_params);
+
+		wrs_info->synced = true;
+		wrs_info->quick_rate_check = true;
+		wrs_info->quick_rate_agg_cntr = 0;
+		wrs_info->quick_rate_pkt_cntr = 0;
+	} else {
+		wrs_info->sync_attempts++;
+	}
+}
+
+static void cl_ba_not_received_handler(struct cl_hw *cl_hw, struct cl_wrs_info *wrs_info,
+				       struct cl_agg_tx_report *agg_report)
+{
+	/* Ignore 'BA not received' if station is in power-save or if RTS limit was reached */
+	if (agg_report->is_sta_ps || agg_report->is_rts_retry_limit_reached)
+		return;
+
+	/* Count number of consecutive 'BA not received' */
+	wrs_info->ba_not_rcv_consecutive++;
+
+	/* Save longest sequence of consecutive 'BA not received' */
+	if (wrs_info->ba_not_rcv_consecutive > wrs_info->ba_not_rcv_consecutive_max)
+		wrs_info->ba_not_rcv_consecutive_max = wrs_info->ba_not_rcv_consecutive;
+
+	if (cl_hw->wrs_db.ba_not_rcv_collision_filter) {
+		/*
+		 * First 'BA not received' - might just be a collision.
+		 * Don't add fail to ba_not_rcv but keep aside.
+		 * Second consecutive 'BA not received' - not likely to be a collisions.
+		 * Add fail to ba_not_rcv including previous fail that was kept aside.
+		 * More than two consecutive 'BA not received' - very unlikely to be a collisions.
+		 * Add fail to ba_not_rcv.
+		 */
+		if (wrs_info->ba_not_rcv_consecutive == 1)
+			wrs_info->fail_prev = agg_report->fail;
+		else if (wrs_info->ba_not_rcv_consecutive == 2)
+			wrs_info->ba_not_rcv += (agg_report->fail + wrs_info->fail_prev);
+		else
+			wrs_info->ba_not_rcv += agg_report->fail;
+	} else {
+		wrs_info->ba_not_rcv += agg_report->fail;
+	}
+}
+
+void cl_agg_tx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			      struct cl_agg_tx_report *agg_report)
+{
+	struct cl_wrs_info *wrs_info = NULL;
+	struct cl_wrs_params *wrs_params = NULL;
+	u8 group_id;
+	bool skip_epr_update = false;
+	union cl_rate_ctrl_info rate_ctrl_info = {
+		.word = le32_to_cpu(agg_report->rate_cntrl_info)};
+
+	wrs_params = &cl_sta->wrs_sta.tx_su_params;
+	wrs_info = &cl_sta->wrs_info_tx_su;
+	group_id = 0;
+
+	/* Retry_count for cl_wlan */
+	cl_sta->retry_count += agg_report->success_after_retry;
+
+	/*
+	 * In case of big packets (4300 in VHT and 5400 in HE) and low
+	 * rate (BW 20, NSS 1, MCS 0), firmware will increase rate to MCS 1,
+	 * and give an indication to driver (set rate_fix_mcs1 in cl_agg_tx_report).
+	 * WRS should also move to MCS 1, and give the maximum time
+	 * penalty time from MCS 0 toMCS 1.
+	 */
+	if (agg_report->rate_fix_mcs1 &&
+	    !agg_report->is_fallback &&
+	    cl_wrs_api_up_mcs1(cl_hw, cl_sta, wrs_params))
+		return;
+
+	/* WRS sync mechanism */
+	if (!wrs_info->synced)
+		cl_sync_tx_rate(cl_hw, cl_sta, agg_report, wrs_info, wrs_params);
+
+	if (agg_report->bf && cl_sta->bf_db.is_on && !cl_sta->bf_db.synced) {
+		cl_sta->bf_db.synced = true;
+		/* Resetting the WRS UP weights */
+		cl_wrs_api_beamforming_sync(cl_hw, cl_sta);
+	}
+
+	if (agg_report->ba_not_received) {
+		cl_ba_not_received_handler(cl_hw, wrs_info, agg_report);
+	} else {
+		if (!skip_epr_update)
+			wrs_info->fail += agg_report->fail;
+
+		wrs_info->ba_not_rcv_consecutive = 0;
+	}
+
+	if (!skip_epr_update) {
+		u8 mcs = 0, nss = 0, bw = 0;
+		u16 data_rate = 0;
+
+		switch (agg_report->bw_requested) {
+		case CHNL_BW_160:
+			bw = (cl_hw->wrs_db.adjacent_interference20 ||
+			      cl_hw->wrs_db.adjacent_interference40 ||
+			      cl_hw->wrs_db.adjacent_interference80) ?
+				rate_ctrl_info.field.bw : agg_report->bw_requested;
+			break;
+		case CHNL_BW_80:
+			bw = (cl_hw->wrs_db.adjacent_interference20 ||
+			      cl_hw->wrs_db.adjacent_interference40) ?
+				rate_ctrl_info.field.bw : agg_report->bw_requested;
+			break;
+		case CHNL_BW_40:
+			bw = cl_hw->wrs_db.adjacent_interference20 ?
+				rate_ctrl_info.field.bw : agg_report->bw_requested;
+			break;
+		case CHNL_BW_20:
+			bw = agg_report->bw_requested;
+			break;
+		}
+
+		cl_rate_ctrl_parse(&rate_ctrl_info, &nss, &mcs);
+
+		data_rate = cl_data_rates_get_x10(rate_ctrl_info.field.format_mod,
+						  bw,
+						  nss,
+						  mcs,
+						  rate_ctrl_info.field.gi);
+
+		wrs_info->epr_acc += ((u64)agg_report->success * data_rate);
+		wrs_info->success += agg_report->success;
+	}
+
+	if (cl_hw->wrs_db.quick_down_en &&
+	    wrs_info->quick_rate_check &&
+	    cl_is_same_rate(agg_report, &wrs_params->rate_params)) {
+		wrs_info->quick_rate_agg_cntr++;
+		wrs_info->quick_rate_pkt_cntr += (agg_report->success + agg_report->fail);
+
+		if (wrs_info->quick_rate_agg_cntr >= cl_hw->wrs_db.quick_down_agg_thr &&
+		    wrs_info->quick_rate_pkt_cntr > cl_hw->wrs_db.quick_down_pkt_thr) {
+			wrs_info->quick_rate_check = false;
+			cl_wrs_api_quick_down_check(cl_hw, cl_sta, wrs_params);
+		}
+	}
+}
+
+void cl_agg_tx_report_simulate_for_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+					  struct cl_hw_tx_status *status)
+{
+	/* Assign statistics struct */
+	struct cl_agg_tx_report agg_report;
+	union cl_rate_ctrl_info rate_ctrl_info;
+
+	memset(&agg_report, 0, sizeof(struct cl_agg_tx_report));
+
+	agg_report.bf = status->bf;
+	agg_report.success = status->frm_successful;
+	agg_report.fail = status->num_mpdu_retries + (status->frm_successful ? 0 : 1);
+	agg_report.success_after_retry =
+		(status->frm_successful && status->num_mpdu_retries);
+	agg_report.retry_limit_reached = !status->frm_successful;
+	agg_report.success_more_one_retry =
+		(status->frm_successful && (status->num_mpdu_retries > 1));
+	agg_report.sta_idx = cl_sta->sta_idx;
+	agg_report.bw_requested = status->bw_requested;
+
+	rate_ctrl_info.field.bw = status->bw_transmitted;
+	rate_ctrl_info.field.gi = status->gi;
+	rate_ctrl_info.field.format_mod = status->format_mod;
+	rate_ctrl_info.field.mcs_index = status->mcs_index;
+
+	cl_rate_ctrl_convert(&rate_ctrl_info);
+
+	agg_report.rate_cntrl_info = cpu_to_le32(rate_ctrl_info.word);
+	cl_agg_tx_report_handler(cl_hw, cl_sta, &agg_report);
+	cl_stats_update_tx_single(cl_hw, cl_sta, &agg_report);
+}
+
+void cl_baw_init(struct cl_sta *cl_sta)
+{
+	u8 tid;
+
+	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++)
+		__skb_queue_head_init(&cl_sta->baws[tid].pending);
+}
+
+void cl_baw_start(struct cl_baw *baw, u16 ssn)
+{
+	baw->ssn = ssn;
+	baw->action_start = true;
+}
+
+void cl_baw_operational(struct cl_hw *cl_hw, struct cl_baw *baw,
+			u8 fw_agg_idx, bool amsdu_supported)
+{
+	baw->fw_agg_idx = fw_agg_idx;
+	baw->tid_seq = IEEE80211_SN_TO_SEQ(baw->ssn);
+	baw->action_start = false;
+	baw->amsdu = (cl_hw->txamsdu_en && amsdu_supported);
+}
+
+void cl_baw_stop(struct cl_baw *baw)
+{
+	baw->action_start = false;
+}
+
+void cl_baw_pending_to_agg(struct cl_hw *cl_hw,
+			   struct cl_sta *cl_sta,
+			   u8 tid)
+{
+	struct cl_baw *baw = &cl_sta->baws[tid];
+	struct sk_buff *skb;
+
+	while (!skb_queue_empty(&baw->pending)) {
+		skb = __skb_dequeue(&baw->pending);
+		cl_tx_fast_agg(cl_hw, cl_sta, skb, false);
+	}
+}
+
+void cl_baw_pending_to_single(struct cl_hw *cl_hw,
+			      struct cl_sta *cl_sta,
+			      struct cl_baw *baw)
+{
+	struct sk_buff *skb;
+
+	while (!skb_queue_empty(&baw->pending)) {
+		skb = __skb_dequeue(&baw->pending);
+		cl_tx_fast_single(cl_hw, cl_sta, skb, false);
+	}
+}
+
+void cl_baw_pending_purge(struct cl_baw *baw)
+{
+	if (!skb_queue_empty(&baw->pending))
+		__skb_queue_purge(&baw->pending);
+}
+
+/*
+ * cl_hw->bcmc_cfm_queue:
+ * This queue is used to keep pointers to already sent
+ * beacon skb's that are waiting for confirmation.
+ */
+
+static void cl_bcmc_free_sw_txhdr(struct cl_hw *cl_hw,
+				  struct cl_sw_txhdr *sw_txhdr)
+{
+	dma_addr_t dma_addr;
+	struct sk_buff *skb = NULL;
+
+	dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+	skb = sw_txhdr->skb;
+
+	dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+	dev_kfree_skb_irq(skb);
+	list_del(&sw_txhdr->cfm_list);
+	cl_sw_txhdr_free(cl_hw, sw_txhdr);
+}
+
+static bool cl_bcmc_is_list_empty_per_vif(struct cl_hw *cl_hw,
+					  struct cl_vif *cl_vif)
+{
+	struct cl_single_cfm_queue *cfm_queue = &cl_hw->bcmc_cfm_queue;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+
+	list_for_each_entry(sw_txhdr, &cfm_queue->head, cfm_list)
+		if (sw_txhdr->cl_vif == cl_vif)
+			return false;
+
+	return true;
+}
+
+void cl_bcmc_cfm_init(struct cl_hw *cl_hw)
+{
+	INIT_LIST_HEAD(&cl_hw->bcmc_cfm_queue.head);
+}
+
+void cl_bcmc_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	list_add_tail(&sw_txhdr->cfm_list, &cl_hw->bcmc_cfm_queue.head);
+}
+
+struct cl_sw_txhdr *cl_bcmc_cfm_find(struct cl_hw *cl_hw, dma_addr_t dma_addr, bool keep_in_list)
+{
+	struct cl_single_cfm_queue *cfm_queue = &cl_hw->bcmc_cfm_queue;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct cl_sw_txhdr *tmp = NULL;
+
+	list_for_each_entry_safe(sw_txhdr, tmp, &cfm_queue->head, cfm_list) {
+		if (le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]) == dma_addr) {
+			if (!keep_in_list)
+				list_del(&sw_txhdr->cfm_list);
+
+			return sw_txhdr;
+		}
+	}
+
+	return NULL;
+}
+
+void cl_bcmc_cfm_flush_queue(struct cl_hw *cl_hw,
+			     struct cl_vif *cl_vif)
+{
+	struct cl_single_cfm_queue *cfm_queue = &cl_hw->bcmc_cfm_queue;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct cl_sw_txhdr *tmp = NULL;
+
+	/* Only flush the specific cl_vif related confirmations */
+	if (cl_vif) {
+		list_for_each_entry_safe(sw_txhdr, tmp, &cfm_queue->head, cfm_list) {
+			if (sw_txhdr->cl_vif == cl_vif) {
+				cl_bcmc_free_sw_txhdr(cl_hw, sw_txhdr);
+				cl_hw->tx_queues->bcmc.fw_free_space++;
+			}
+		}
+
+		return;
+	}
+
+	while (!list_empty(&cfm_queue->head)) {
+		sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+		cl_bcmc_free_sw_txhdr(cl_hw, sw_txhdr);
+	}
+
+	/* Set fw_free_space back to maximum after flushing the queue */
+	cl_hw->tx_queues->bcmc.fw_free_space = cl_hw->tx_queues->bcmc.fw_max_size;
+}
+
+void cl_bcmc_cfm_poll_empty_per_vif(struct cl_hw *cl_hw,
+				    struct cl_vif *cl_vif)
+{
+	bool empty = false;
+	int i = 0;
+
+	if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+		return;
+
+	while (i++ < BCMC_POLL_TIMEOUT) {
+		spin_lock_bh(&cl_hw->tx_lock_bcmc);
+		empty = cl_bcmc_is_list_empty_per_vif(cl_hw, cl_vif);
+		spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+
+		if (empty)
+			return;
+
+		msleep(20);
+	}
+
+	cl_dbg_err(cl_hw, "Polling timeout vif_index %d\n", cl_vif->vif_index);
+
+	spin_lock_bh(&cl_hw->tx_lock_bcmc);
+	cl_bcmc_cfm_flush_queue(cl_hw, cl_vif);
+	spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+}
+
+/*
+ * cl_hw->single_cfm_queues:
+ * These queues are used to keep pointers to skb's sent
+ * as singles and waiting for confirmation.
+ */
+
+#define SINGLE_POLL_TIMEOUT 50
+
+void cl_single_cfm_init(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		INIT_LIST_HEAD(&cl_hw->single_cfm_queues[i].head);
+}
+
+void cl_single_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u32 queue_idx)
+{
+	list_add_tail(&sw_txhdr->cfm_list, &cl_hw->single_cfm_queues[queue_idx].head);
+}
+
+struct cl_sw_txhdr *cl_single_cfm_find(struct cl_hw *cl_hw, u32 queue_idx,
+				       dma_addr_t dma_addr)
+{
+	struct cl_single_cfm_queue *cfm_queue = NULL;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct cl_sw_txhdr *tmp = NULL;
+
+	if (queue_idx >= MAX_SINGLE_QUEUES)
+		return NULL;
+
+	cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+
+	list_for_each_entry_safe(sw_txhdr, tmp, &cfm_queue->head, cfm_list)
+		if (le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]) == dma_addr) {
+			list_del(&sw_txhdr->cfm_list);
+
+			return sw_txhdr;
+		}
+
+	return NULL;
+}
+
+static void cl_single_cfm_flush_queue(struct cl_hw *cl_hw, u32 queue_idx)
+{
+	struct cl_single_cfm_queue *cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+	struct cl_tx_queue *tx_queue = NULL;
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+	struct sk_buff *skb = NULL;
+	struct ieee80211_tx_info *tx_info = NULL;
+	dma_addr_t dma_addr;
+
+	if (list_empty(&cfm_queue->head))
+		return;
+
+	do {
+		sw_txhdr = list_first_entry(&cfm_queue->head, struct cl_sw_txhdr, cfm_list);
+		dma_addr = le32_to_cpu(sw_txhdr->txdesc.umacdesc.packet_addr[0]);
+		skb = sw_txhdr->skb;
+		tx_info = IEEE80211_SKB_CB(skb);
+
+		dma_unmap_single(cl_hw->chip->dev, dma_addr, sw_txhdr->map_len, DMA_TO_DEVICE);
+
+		cl_tx_single_free_skb(cl_hw, skb);
+		list_del(&sw_txhdr->cfm_list);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+	} while (!list_empty(&cfm_queue->head));
+
+	/*
+	 * Set fw_free_space back to maximum after flushing the queue
+	 * and clear the enhanced TIM.
+	 */
+	tx_queue = &cl_hw->tx_queues->single[queue_idx];
+	tx_queue->fw_free_space = tx_queue->fw_max_size;
+	cl_enhanced_tim_clear_tx_single(cl_hw, queue_idx, tx_queue->hw_index,
+					false, tx_queue->cl_sta, tx_queue->tid);
+}
+
+void cl_single_cfm_flush_all(struct cl_hw *cl_hw)
+{
+	u32 i = 0;
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		cl_single_cfm_flush_queue(cl_hw, i);
+}
+
+void cl_single_cfm_flush_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	/* Flush all single confirmation queues of this sta, and reset write index */
+	u8 ac;
+	u16 queue_idx;
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		queue_idx = QUEUE_IDX(sta_idx, ac);
+		cl_single_cfm_flush_queue(cl_hw, queue_idx);
+
+		cl_hw->ipc_env->ring_indices_elem->indices->txdesc_write_idx.single[queue_idx] = 0;
+	}
+
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_single_cfm_poll_timeout(struct cl_hw *cl_hw, u32 queue_idx)
+{
+	/*
+	 * When polling failed clear the enhanced TIM so that firmware will
+	 * not try to transmit these packets.
+	 */
+	struct cl_tx_queue *tx_queue = &cl_hw->tx_queues->single[queue_idx];
+
+	cl_dbg_err(cl_hw, "Polling timeout (queue_idx = %u)\n", queue_idx);
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+	cl_enhanced_tim_clear_tx_single(cl_hw, queue_idx, tx_queue->hw_index,
+					false, tx_queue->cl_sta, tx_queue->tid);
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_single_cfm_poll_empty(struct cl_hw *cl_hw, u32 queue_idx)
+{
+	struct cl_single_cfm_queue *cfm_queue = &cl_hw->single_cfm_queues[queue_idx];
+	bool empty = false;
+	int i = 0;
+
+	if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+		return;
+
+	while (true) {
+		spin_lock_bh(&cl_hw->tx_lock_single);
+		empty = list_empty(&cfm_queue->head);
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+
+		if (empty)
+			return;
+
+		if (++i == SINGLE_POLL_TIMEOUT) {
+			cl_single_cfm_poll_timeout(cl_hw, queue_idx);
+			return;
+		}
+
+		msleep(20);
+	}
+}
+
+static bool cl_list_hp_empty_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	struct cl_single_cfm_queue *hp_cfm_queue = &cl_hw->single_cfm_queues[HIGH_PRIORITY_QUEUE];
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+
+	list_for_each_entry(sw_txhdr, &hp_cfm_queue->head, cfm_list)
+		if (sw_txhdr->sta_idx == sta_idx)
+			return false;
+
+	return true;
+}
+
+static void cl_single_cfm_poll_empty_hp(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	bool empty = false;
+	int i = 0;
+
+	if (test_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags))
+		return;
+
+	while (true) {
+		spin_lock_bh(&cl_hw->tx_lock_single);
+		empty = cl_list_hp_empty_sta(cl_hw, sta_idx);
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+
+		if (empty)
+			return;
+
+		if (++i == SINGLE_POLL_TIMEOUT) {
+			cl_single_cfm_poll_timeout(cl_hw, HIGH_PRIORITY_QUEUE);
+			return;
+		}
+
+		msleep(20);
+	}
+}
+
+void cl_single_cfm_poll_empty_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	/*
+	 * Poll all single queues belonging to this station, and poll all
+	 * packets belonging to this station in the high priority queue.
+	 */
+	u8 ac;
+	u16 queue_idx;
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		queue_idx = QUEUE_IDX(sta_idx, ac);
+		cl_single_cfm_poll_empty(cl_hw, queue_idx);
+	}
+
+	cl_single_cfm_poll_empty_hp(cl_hw, sta_idx);
+}
+
+void cl_single_cfm_clear_tim_bit_sta(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	u8 ac;
+	u16 queue_idx;
+	struct cl_tx_queue *tx_queue = NULL;
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		queue_idx = QUEUE_IDX(sta_idx, ac);
+		tx_queue = &cl_hw->tx_queues->single[queue_idx];
+
+		spin_lock_bh(&cl_hw->tx_lock_single);
+		cl_enhanced_tim_clear_tx_single(cl_hw, queue_idx, tx_queue->hw_index,
+						false, tx_queue->cl_sta, tx_queue->tid);
+		spin_unlock_bh(&cl_hw->tx_lock_single);
+	}
+
+	tx_queue = &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE];
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+	cl_enhanced_tim_clear_tx_single(cl_hw, HIGH_PRIORITY_QUEUE, tx_queue->hw_index,
+					false, tx_queue->cl_sta, tx_queue->tid);
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static int cl_sw_txhdr_init_pool(struct cl_hw *cl_hw, u16 sw_txhdr_pool)
+{
+	u16 i = 0;
+	u32 sw_txhdr_pool_size = sw_txhdr_pool * sizeof(struct cl_sw_txhdr);
+	struct cl_sw_txhdr *sw_txhdr;
+
+	INIT_LIST_HEAD(&cl_hw->head_sw_txhdr_pool);
+	spin_lock_init(&cl_hw->lock_sw_txhdr_pool);
+
+	for (i = 0; i < sw_txhdr_pool; i++) {
+		sw_txhdr = kzalloc(sizeof(*sw_txhdr), GFP_ATOMIC);
+
+		if (unlikely(!sw_txhdr)) {
+			cl_dbg_verbose(cl_hw, "sw_txhdr NULL\n");
+			return -1;
+		}
+
+		list_add(&sw_txhdr->list_pool, &cl_hw->head_sw_txhdr_pool);
+	}
+
+	cl_dbg_verbose(cl_hw, " - pool %u, size %u\n", sw_txhdr_pool, sw_txhdr_pool_size);
+
+	return 0;
+}
+
+static int cl_sw_txhdr_init_cache(struct cl_hw *cl_hw)
+{
+	char sw_txhdr_cache_name[MODULE_NAME_LEN + 32] = {0};
+
+	snprintf(sw_txhdr_cache_name, sizeof(sw_txhdr_cache_name),
+		 "%s_sw_txhdr_cache", THIS_MODULE->name);
+
+	cl_hw->sw_txhdr_cache = kmem_cache_create(sw_txhdr_cache_name,
+						  sizeof(struct cl_sw_txhdr),
+						  0,
+						  (SLAB_HWCACHE_ALIGN | SLAB_PANIC),
+						  NULL);
+
+	if (!cl_hw->sw_txhdr_cache) {
+		cl_dbg_verbose(cl_hw, "sw_txhdr_cache NULL\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int cl_sw_txhdr_init(struct cl_hw *cl_hw)
+{
+	u16 sw_txhdr_pool = cl_hw->conf->ci_sw_txhdr_pool;
+
+	if (sw_txhdr_pool)
+		return cl_sw_txhdr_init_pool(cl_hw, sw_txhdr_pool);
+	else
+		return cl_sw_txhdr_init_cache(cl_hw);
+}
+
+static void cl_sw_txhdr_deinit_pool(struct cl_hw *cl_hw)
+{
+	struct cl_sw_txhdr *sw_txhdr, *tmp;
+
+	list_for_each_entry_safe(sw_txhdr, tmp, &cl_hw->head_sw_txhdr_pool, list_pool) {
+		list_del(&sw_txhdr->list_pool);
+		kfree(sw_txhdr);
+	}
+}
+
+static void cl_sw_txhdr_deinit_cache(struct cl_hw *cl_hw)
+{
+	kmem_cache_destroy(cl_hw->sw_txhdr_cache);
+}
+
+void cl_sw_txhdr_deinit(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_sw_txhdr_pool)
+		cl_sw_txhdr_deinit_pool(cl_hw);
+	else
+		cl_sw_txhdr_deinit_cache(cl_hw);
+}
+
+static inline struct cl_sw_txhdr *cl_sw_txhdr_alloc_pool(struct cl_hw *cl_hw)
+{
+	struct cl_sw_txhdr *sw_txhdr = NULL;
+
+	spin_lock_bh(&cl_hw->lock_sw_txhdr_pool);
+	sw_txhdr = list_first_entry_or_null(&cl_hw->head_sw_txhdr_pool,
+					    struct cl_sw_txhdr, list_pool);
+
+	if (sw_txhdr) {
+		list_del(&sw_txhdr->list_pool);
+		spin_unlock_bh(&cl_hw->lock_sw_txhdr_pool);
+		return sw_txhdr;
+	}
+
+	spin_unlock_bh(&cl_hw->lock_sw_txhdr_pool);
+	return NULL;
+}
+
+static inline struct cl_sw_txhdr *cl_sw_txhdr_alloc_cache(struct cl_hw *cl_hw)
+{
+	return kmem_cache_alloc(cl_hw->sw_txhdr_cache, GFP_ATOMIC);
+}
+
+struct cl_sw_txhdr *cl_sw_txhdr_alloc(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_sw_txhdr_pool)
+		return cl_sw_txhdr_alloc_pool(cl_hw);
+	else
+		return cl_sw_txhdr_alloc_cache(cl_hw);
+}
+
+static inline void cl_sw_txhdr_free_pool(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	spin_lock_bh(&cl_hw->lock_sw_txhdr_pool);
+	list_add_tail(&sw_txhdr->list_pool, &cl_hw->head_sw_txhdr_pool);
+	spin_unlock_bh(&cl_hw->lock_sw_txhdr_pool);
+}
+
+static inline void cl_sw_txhdr_free_cache(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	kmem_cache_free(cl_hw->sw_txhdr_cache, sw_txhdr);
+}
+
+void cl_sw_txhdr_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	if (cl_hw->conf->ci_sw_txhdr_pool)
+		cl_sw_txhdr_free_pool(cl_hw, sw_txhdr);
+	else
+		cl_sw_txhdr_free_cache(cl_hw, sw_txhdr);
+}
+
+#define CL_AMSDU_HDR_LEN 14
+
+static bool cl_tx_amsdu_is_sw(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			      struct sk_buff *skb, u16 pkt_len)
+{
+	bool syn_rst_push = false;
+	bool tcp_ack = false;
+
+	if (cl_hw->conf->ci_tx_sw_amsdu_max_packets <= 1)
+		return false;
+
+	tcp_ack = cl_is_tcp_ack(skb, &syn_rst_push);
+
+	if (!tcp_ack || syn_rst_push)
+		return false;
+
+	if ((cl_wrs_api_get_tx_sta_data_rate(cl_sta) * cl_sta->ampdu_min_spacing) <=
+	    (pkt_len << 3))
+		return false;
+
+	return true;
+}
+
+static int cl_tx_amsdu_anchor_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				  struct sk_buff *skb, u8 tid)
+{
+	/*
+	 * Packet length calculation in HW -
+	 * Add 802.11 header (maximum possible size) instead if 802.3
+	 * Add AMSDU header
+	 * Add RFC1042 header (according to ether-type)
+	 * Add IV and ICV (if there is encryption)
+	 */
+	struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+	u16 pkt_len = skb->len + CL_WLAN_HEADER_MAX_SIZE;
+
+	if (key_conf)
+		pkt_len += (key_conf->iv_len + key_conf->icv_len);
+
+	if (ethertype >= ETH_P_802_3_MIN)
+		pkt_len += sizeof(rfc1042_header);
+
+	amsdu_anchor->rem_len = amsdu_anchor->max_len - pkt_len;
+	amsdu_anchor->packet_cnt = 1;
+	amsdu_anchor->is_sw_amsdu = cl_tx_amsdu_is_sw(cl_hw, cl_sta, skb, pkt_len);
+
+	return CL_AMSDU_ANCHOR_SET;
+}
+
+static void cl_tx_amsdu_anchor_umacdesc_update(struct txdesc *txdesc, u8 idx,
+					       u16 len, dma_addr_t dma_addr,
+					       bool is_padding)
+{
+	struct lmacapi *umacdesc = &txdesc->umacdesc;
+
+	umacdesc->packet_len[idx] = cpu_to_le16(len);
+	umacdesc->packet_addr[idx] = cpu_to_le32(dma_addr);
+	txdesc->host_info.packet_cnt++;
+
+	/* Update padding bit of current msdu sub-frame */
+	if (is_padding)
+		txdesc->host_info.host_padding |= BIT(idx);
+}
+
+static struct cl_amsdu_txhdr *cl_tx_amsdu_txhdr_alloc(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_amsdu_txhdr_pool) {
+		struct cl_amsdu_txhdr *amsdu_txhdr =
+			list_first_entry_or_null(&cl_hw->head_amsdu_txhdr_pool,
+						 struct cl_amsdu_txhdr,
+						 list_pool);
+
+		if (amsdu_txhdr) {
+			list_del(&amsdu_txhdr->list_pool);
+			return amsdu_txhdr;
+		}
+
+		return NULL;
+	} else {
+		return kmem_cache_alloc(cl_hw->amsdu_txhdr_cache, GFP_ATOMIC);
+	}
+}
+
+static void _cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw,
+					 struct sk_buff *skb,
+					 struct cl_sta *cl_sta,
+					 u8 tid)
+{
+	struct ieee80211_tx_info *tx_info;
+
+	tx_info = IEEE80211_SKB_CB(skb);
+	tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+	tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+
+	if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, tid) == 0) {
+		cl_hw->tx_packet_cntr.transfer.agg_to_single++;
+		cl_tx_single(cl_hw, cl_sta, skb, false, false);
+	}
+}
+
+static void cl_tx_amsdu_set_sw_sub_amsdu_hdr(struct sk_buff *skb)
+{
+	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+	int rfc1042_len = 0;
+	void *data;
+	struct ethhdr *amsdu_hdr;
+
+	if (ethertype >= ETH_P_802_3_MIN)
+		rfc1042_len = sizeof(rfc1042_header);
+
+	data = skb_push(skb, rfc1042_len + 2);
+	memmove(data, data + rfc1042_len + 2, 2 * ETH_ALEN);
+
+	amsdu_hdr = (struct ethhdr *)data;
+	amsdu_hdr->h_proto = cpu_to_be16(skb->len - ETH_HLEN);
+
+	memcpy(data + ETH_HLEN, rfc1042_header, rfc1042_len);
+}
+
+static int cl_tx_amsdu_add_sw_amsdu_hdr(struct cl_hw *cl_hw,
+					struct cl_amsdu_ctrl *amsdu_anchor)
+{
+	struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+	struct sk_buff *skb = anchor_sw_txhdr->skb;
+	struct cl_sta *cl_sta = anchor_sw_txhdr->cl_sta;
+	struct ieee80211_hdr hdr;
+	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+	u16 hdrlen = cl_tx_prepare_wlan_hdr(cl_hw, cl_sta, skb, &hdr);
+	int rfc1042_len = 0;
+	int head_need = 0;
+	u8 enc_len = cl_key_get_cipher_len(skb);
+	u16 qos_ctrl = anchor_sw_txhdr->tid | IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+	if (!hdrlen)
+		return -EINVAL;
+
+	if (ethertype >= ETH_P_802_3_MIN)
+		rfc1042_len = sizeof(rfc1042_header);
+
+	amsdu_anchor->hdrlen = hdrlen;
+	head_need = hdrlen + enc_len + rfc1042_len - skb_headroom(skb);
+	if (head_need > 0) {
+		head_need = ((head_need + 3) & ~3);
+		if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
+			return -ENOMEM;
+	}
+
+	cl_tx_amsdu_set_sw_sub_amsdu_hdr(skb);
+
+	skb_push(skb, hdrlen + enc_len);
+	memcpy(skb->data, &hdr, hdrlen - 2);
+	memcpy(skb->data + hdrlen - 2, &qos_ctrl, 2);
+	skb_reset_mac_header(skb);
+	anchor_sw_txhdr->txdesc.e2w_natt_param.hdr_conv_enable = false;
+	anchor_sw_txhdr->hdr80211 = (struct ieee80211_hdr *)skb->data;
+
+	return 0;
+}
+
+static int cl_tx_amsdu_sw_aggregate(struct cl_hw *cl_hw,
+				    struct cl_amsdu_ctrl *amsdu_anchor,
+				    struct sk_buff *skb)
+{
+	struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+	struct sk_buff *anchor_skb = anchor_sw_txhdr->skb;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(anchor_skb);
+	struct ieee80211_key_conf *key_conf = tx_info->control.hw_key;
+	u16 total_frame_len = 0;
+	struct cl_tx_queue *tx_queue = anchor_sw_txhdr->tx_queue;
+	int head_pad = 0;
+	int sub_pad = 0;
+	bool syn_rst_push = false;
+	bool tcp_ack = cl_is_tcp_ack(skb, &syn_rst_push);
+
+	/* Worst case: rfc1042(6) + ET(2) + pad(2) = 10 */
+	if (!tcp_ack ||
+	    (skb_tailroom(anchor_skb) < (skb->len + 10))) {
+		if (tx_queue->num_packets == 1)
+			cl_txq_sched(cl_hw, tx_queue);
+		cl_tx_amsdu_anchor_init(amsdu_anchor);
+		return cl_tx_amsdu_anchor_set(cl_hw, anchor_sw_txhdr->cl_sta,
+					      skb, anchor_sw_txhdr->tid);
+	}
+
+	if (amsdu_anchor->packet_cnt == 1 &&
+	    cl_tx_amsdu_add_sw_amsdu_hdr(cl_hw, amsdu_anchor))
+		return CL_AMSDU_FAILED;
+
+	cl_tx_amsdu_set_sw_sub_amsdu_hdr(skb);
+	sub_pad = CL_SKB_DATA_ALIGN_PADS(anchor_skb->len -
+					 amsdu_anchor->hdrlen);
+	memset(skb_push(skb, sub_pad), 0, sub_pad);
+	memcpy(skb_put(anchor_skb, skb->len), skb->data, skb->len);
+
+	kfree_skb(skb);
+	amsdu_anchor->packet_cnt++;
+	anchor_sw_txhdr->sw_amsdu_packet_cnt++;
+	head_pad = CL_SKB_DATA_ALIGN_PADS(anchor_skb->data);
+
+	if (head_pad) {
+		anchor_sw_txhdr->map_len = anchor_skb->len + head_pad;
+		anchor_sw_txhdr->txdesc.host_info.host_padding |= BIT(0);
+	} else {
+		anchor_sw_txhdr->map_len = anchor_skb->len;
+		anchor_sw_txhdr->txdesc.host_info.host_padding = 0;
+	}
+
+	total_frame_len = anchor_skb->len;
+	if (key_conf)
+		total_frame_len += key_conf->icv_len;
+
+	anchor_sw_txhdr->txdesc.umacdesc.packet_len[0] = cpu_to_le16(total_frame_len);
+
+	if (amsdu_anchor->packet_cnt == cl_hw->conf->ci_tx_sw_amsdu_max_packets ||
+	    syn_rst_push) {
+		if (tx_queue->num_packets == 1)
+			cl_txq_sched(cl_hw, tx_queue);
+		cl_tx_amsdu_anchor_init(amsdu_anchor);
+	}
+
+	return CL_AMSDU_SUB_FRAME_SET;
+}
+
+void cl_tx_amsdu_anchor_init(struct cl_amsdu_ctrl *amsdu_anchor)
+{
+	amsdu_anchor->rem_len = amsdu_anchor->max_len;
+	amsdu_anchor->sw_txhdr = NULL;
+	amsdu_anchor->packet_cnt = 0;
+	amsdu_anchor->is_sw_amsdu = false;
+}
+
+void cl_tx_amsdu_anchor_reset(struct cl_amsdu_ctrl *amsdu_anchor)
+{
+	amsdu_anchor->sw_txhdr = NULL;
+	amsdu_anchor->rem_len = 0;
+	amsdu_anchor->max_len = 0;
+	amsdu_anchor->packet_cnt = 0;
+	amsdu_anchor->is_sw_amsdu = false;
+}
+
+void cl_tx_amsdu_set_max_len(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid)
+{
+	struct ieee80211_sta_vht_cap *vht_cap = &cl_sta->sta->vht_cap;
+	struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+	u32 length = U32_MAX;
+
+	amsdu_anchor->max_len = 3839;
+
+	if (cl_band_is_6g(cl_hw)) {
+		u16 capa = le16_to_cpu(cl_sta->sta->he_6ghz_capa.capa);
+
+		length = (capa & IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN) >>
+			HE_6GHZ_CAP_MAX_MPDU_LEN_OFFSET;
+	} else if (vht_cap->vht_supported) {
+		length = vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK;
+	}
+
+	switch (length) {
+	case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
+		amsdu_anchor->max_len = 3895;
+		break;
+	case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
+		amsdu_anchor->max_len = 7991;
+		break;
+	case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
+		amsdu_anchor->max_len = 11454;
+		break;
+	default:
+		break;
+	}
+
+	amsdu_anchor->rem_len = amsdu_anchor->max_len;
+
+	cl_dbg_trace(cl_hw, "AMSDU supported - sta_idx=%u, max_len=%d\n",
+		     cl_sta->sta_idx, amsdu_anchor->max_len);
+}
+
+void cl_tx_amsdu_first_sub_frame(struct cl_sw_txhdr *sw_txhdr, struct cl_sta *cl_sta,
+				 struct sk_buff *skb, u8 tid)
+{
+	/* Set the anchor sw_txhdr */
+	cl_sta->amsdu_anchor[tid].sw_txhdr = sw_txhdr;
+
+	INIT_LIST_HEAD(&sw_txhdr->amsdu_txhdr.list);
+	sw_txhdr->amsdu_txhdr.skb = skb;
+}
+
+void cl_tx_amsdu_flush_sub_frames(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	struct cl_amsdu_txhdr *amsdu_txhdr = NULL, *tmp = NULL;
+	struct sk_buff *sub_skb = NULL;
+
+	/* Free mid & last AMSDU sub frames */
+	list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+		sub_skb = amsdu_txhdr->skb;
+		list_del(&amsdu_txhdr->list);
+
+		dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+				 (size_t)sub_skb->len, DMA_TO_DEVICE);
+		kfree_skb(sub_skb);
+		cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+		cl_hw->tx_packet_cntr.drop.queue_flush++;
+		sw_txhdr->cl_vif->trfc_cntrs[sw_txhdr->ac].tx_dropped++;
+	}
+
+	/* Free first AMSDU sub frame */
+	kfree_skb(sw_txhdr->skb);
+	cl_sw_txhdr_free(cl_hw, sw_txhdr);
+}
+
+void cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	/*
+	 * Transfer all skbs in sw_txhdr to a temporary list, free sw_txhdr,
+	 * and then push the temporary list to the single path.
+	 */
+	struct cl_amsdu_txhdr *amsdu_txhdr, *tmp;
+	struct sk_buff *skb;
+	struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+	u8 tid = sw_txhdr->tid;
+
+	/* Transfer first AMSDU sub frame */
+	_cl_tx_amsdu_transfer_single(cl_hw, sw_txhdr->skb, cl_sta, tid);
+
+	/* Transfer mid & last AMSDU sub frames */
+	list_for_each_entry_safe(amsdu_txhdr, tmp, &sw_txhdr->amsdu_txhdr.list, list) {
+		skb = amsdu_txhdr->skb;
+
+		list_del(&amsdu_txhdr->list);
+		dma_unmap_single(cl_hw->chip->dev, amsdu_txhdr->dma_addr,
+				 (size_t)skb->len, DMA_TO_DEVICE);
+		cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+
+		_cl_tx_amsdu_transfer_single(cl_hw, skb, cl_sta, tid);
+	}
+}
+
+int cl_tx_amsdu_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb, u8 tid)
+{
+	struct cl_amsdu_ctrl *amsdu_anchor = &cl_sta->amsdu_anchor[tid];
+	struct cl_sw_txhdr *anchor_sw_txhdr = amsdu_anchor->sw_txhdr;
+	u16 packet_len = skb->len;
+	u8 packet_cnt;
+	bool is_mesh = ieee80211_vif_is_mesh(cl_sta->cl_vif->vif);
+	u8 packet_cnt_max = cl_hw->txamsdu_en;
+
+	/* Check if anchor exist */
+	if (!anchor_sw_txhdr) {
+		/* Sanity check - skb len < amsdu_max_len */
+		if (unlikely(packet_len > amsdu_anchor->max_len) || is_mesh)
+			return CL_AMSDU_SKIP;
+		else
+			return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+	}
+
+	if (amsdu_anchor->is_sw_amsdu)
+		return cl_tx_amsdu_sw_aggregate(cl_hw, amsdu_anchor, skb);
+
+	/*
+	 * 1. Check if there is enough space in AMSDU
+	 * 2. Check if A-MSDU packet count is less than maximum.
+	 */
+	packet_cnt = amsdu_anchor->packet_cnt;
+
+	if (amsdu_anchor->rem_len > packet_len &&
+	    packet_cnt < packet_cnt_max &&
+	    !is_mesh) {
+		struct cl_amsdu_txhdr *amsdu_txhdr = NULL;
+		u8 hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+		u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+		u16 total_packet_len = packet_len + hdr_pads;
+		u16 curr_amsdu_len = amsdu_anchor->max_len - amsdu_anchor->rem_len;
+		dma_addr_t dma_addr;
+
+		if (ethertype >= ETH_P_802_3_MIN)
+			total_packet_len += sizeof(rfc1042_header);
+
+		/*
+		 * High number of MSDUs in AMSDU can cause underrun in the
+		 * E2W module.
+		 * Therefore, host is required to set Num MSDU in AMSDU using
+		 * the following rules
+		 *
+		 * AMSDU Length      AMSDU agg size
+		 * len  < 4*256      3 or less
+		 * len >= 4*256      4 or less
+		 * len >= 5*256      5 or less
+		 * len >= 6*256      6 or less
+		 * len >= 7*256      7 or less
+		 * len >= 8*256      8 or less
+		 */
+		if (packet_cnt >= CL_AMSDU_MIN_AGG_SIZE) {
+			u16 new_amsdu_len = curr_amsdu_len + packet_len;
+
+			if (new_amsdu_len < ((packet_cnt + 1) * CL_AMSDU_CONST_LEN))
+				return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+		}
+
+		amsdu_txhdr = cl_tx_amsdu_txhdr_alloc(cl_hw);
+		if (unlikely(!amsdu_txhdr)) {
+			kfree_skb(skb);
+			cl_dbg_err(cl_hw, "AMSDU FAILED to alloc amsdu txhdr\n");
+			cl_hw->tx_packet_cntr.drop.amsdu_alloc_fail++;
+			cl_sta->cl_vif->trfc_cntrs[anchor_sw_txhdr->ac].tx_errors++;
+			return CL_AMSDU_FAILED;
+		}
+
+		amsdu_txhdr->skb = skb;
+		list_add_tail(&amsdu_txhdr->list, &anchor_sw_txhdr->amsdu_txhdr.list);
+
+		/* Update anchor fields */
+		amsdu_anchor->rem_len -= total_packet_len;
+		amsdu_anchor->packet_cnt++;
+
+		/* Get DMA address for skb */
+		dma_addr = dma_map_single(cl_hw->chip->dev, (u8 *)skb->data - hdr_pads,
+					  packet_len + hdr_pads, DMA_TO_DEVICE);
+		if (WARN_ON(dma_mapping_error(cl_hw->chip->dev, dma_addr))) {
+			kfree_skb(skb);
+			cl_tx_amsdu_txhdr_free(cl_hw, amsdu_txhdr);
+			cl_dbg_err(cl_hw, "dma_mapping_error\n");
+			cl_hw->tx_packet_cntr.drop.amsdu_dma_map_err++;
+			cl_sta->cl_vif->trfc_cntrs[anchor_sw_txhdr->ac].tx_errors++;
+			return CL_AMSDU_FAILED;
+		}
+
+		/* Add AMSDU HDR len of the first packet */
+		if (amsdu_anchor->packet_cnt == 2)
+			total_packet_len += CL_AMSDU_HDR_LEN;
+
+		amsdu_txhdr->dma_addr = dma_addr;
+
+		/* Update sw_txhdr packet_len, packet_addr, packet_cnt fields */
+		cl_tx_amsdu_anchor_umacdesc_update(&anchor_sw_txhdr->txdesc, packet_cnt,
+						   packet_len, dma_addr, hdr_pads);
+
+		/* If we reached max AMSDU payload count, mark anchor as NULL */
+		if (amsdu_anchor->packet_cnt >= packet_cnt_max)
+			cl_tx_amsdu_anchor_init(amsdu_anchor);
+
+		return CL_AMSDU_SUB_FRAME_SET;
+	}
+	/* Not enough space remain, set new anchor length is ok */
+	if (unlikely(packet_len > amsdu_anchor->max_len) || is_mesh) {
+		cl_tx_amsdu_anchor_init(amsdu_anchor);
+		return CL_AMSDU_SKIP;
+	} else {
+		return cl_tx_amsdu_anchor_set(cl_hw, cl_sta, skb, tid);
+	}
+}
+
+void cl_tx_amsdu_unset(struct cl_sw_txhdr *sw_txhdr)
+{
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+
+	tx_info->control.flags &= ~IEEE80211_TX_CTRL_AMSDU;
+
+	sw_txhdr->txdesc.e2w_txhdr_param.qos_ctrl &=
+				~cpu_to_le16(IEEE80211_QOS_CTL_A_MSDU_PRESENT);
+}
+
+/*
+ * Two options for allocating cl_amsdu_txhdr:
+ * 1) pool
+ * 2) cache
+ */
+
+static int cl_tx_amsdu_txhdr_init_pool(struct cl_hw *cl_hw)
+{
+	u16 amsdu_txhdr_pool = cl_hw->conf->ci_amsdu_txhdr_pool;
+	u32 i = 0;
+	u32 amsdu_txhdr_pool_size = amsdu_txhdr_pool * sizeof(struct cl_amsdu_txhdr);
+	struct cl_amsdu_txhdr *amsdu_txhdr;
+
+	INIT_LIST_HEAD(&cl_hw->head_amsdu_txhdr_pool);
+
+	for (i = 0; i < amsdu_txhdr_pool; i++) {
+		amsdu_txhdr = kzalloc(sizeof(*amsdu_txhdr), GFP_ATOMIC);
+
+		if (unlikely(!amsdu_txhdr)) {
+			cl_dbg_err(cl_hw, "amsdu_txhdr NULL\n");
+			return -1;
+		}
+
+		list_add(&amsdu_txhdr->list_pool, &cl_hw->head_amsdu_txhdr_pool);
+	}
+
+	cl_dbg_verbose(cl_hw, " - pool %u, size %u\n",
+		       amsdu_txhdr_pool, amsdu_txhdr_pool_size);
+
+	return 0;
+}
+
+static int cl_tx_amsdu_txhdr_init_cache(struct cl_hw *cl_hw)
+{
+	char amsdu_txhdr_cache_name[MODULE_NAME_LEN + 32] = {0};
+
+	snprintf(amsdu_txhdr_cache_name, sizeof(amsdu_txhdr_cache_name),
+		 "%s_amsdu_txhdr_cache", THIS_MODULE->name);
+
+	cl_hw->amsdu_txhdr_cache = kmem_cache_create(amsdu_txhdr_cache_name,
+						     sizeof(struct cl_amsdu_txhdr),
+						     0,
+						     (SLAB_HWCACHE_ALIGN | SLAB_PANIC),
+						     NULL);
+
+	if (!cl_hw->amsdu_txhdr_cache) {
+		cl_dbg_err(cl_hw, "amsdu_txhdr_cache NULL\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int cl_tx_amsdu_txhdr_init(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_amsdu_txhdr_pool)
+		return cl_tx_amsdu_txhdr_init_pool(cl_hw);
+	else
+		return cl_tx_amsdu_txhdr_init_cache(cl_hw);
+}
+
+static void cl_tx_amsdu_txhdr_deinit_pool(struct cl_hw *cl_hw)
+{
+	struct cl_amsdu_txhdr *amsdu_txhdr, *tmp;
+
+	list_for_each_entry_safe(amsdu_txhdr, tmp, &cl_hw->head_amsdu_txhdr_pool, list_pool) {
+		list_del(&amsdu_txhdr->list_pool);
+		kfree(amsdu_txhdr);
+	}
+}
+
+static void cl_tx_amsdu_txhdr_deinit_cache(struct cl_hw *cl_hw)
+{
+	kmem_cache_destroy(cl_hw->amsdu_txhdr_cache);
+}
+
+void cl_tx_amsdu_txhdr_deinit(struct cl_hw *cl_hw)
+{
+	if (cl_hw->conf->ci_amsdu_txhdr_pool)
+		cl_tx_amsdu_txhdr_deinit_pool(cl_hw);
+	else
+		cl_tx_amsdu_txhdr_deinit_cache(cl_hw);
+}
+
+void cl_tx_amsdu_txhdr_free(struct cl_hw *cl_hw, struct cl_amsdu_txhdr *amsdu_txhdr)
+{
+	if (cl_hw->conf->ci_amsdu_txhdr_pool)
+		list_add_tail(&amsdu_txhdr->list_pool, &cl_hw->head_amsdu_txhdr_pool);
+	else
+		kmem_cache_free(cl_hw->amsdu_txhdr_cache, amsdu_txhdr);
+}
+
+static const u8 cl_tid2hwq[IEEE80211_NUM_TIDS] = {
+	CL_HWQ_BE,
+	CL_HWQ_BK,
+	CL_HWQ_BK,
+	CL_HWQ_BE,
+	CL_HWQ_VI,
+	CL_HWQ_VI,
+	CL_HWQ_VO,
+	CL_HWQ_VO,
+	/* At the moment, all others TID are mapped to BE */
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+	CL_HWQ_BE,
+};
+
+static void cl_txq_sched_list_add(struct cl_tx_queue *tx_queue, struct cl_hw *cl_hw)
+{
+	/* Add to schedule queue */
+	if (tx_queue->sched)
+		return;
+
+	tx_queue->sched = true;
+	if (tx_queue->type == QUEUE_TYPE_AGG)
+		list_add_tail(&tx_queue->sched_list, &cl_hw->list_sched_q_agg);
+	else
+		list_add_tail(&tx_queue->sched_list, &cl_hw->list_sched_q_single);
+}
+
+static void cl_txq_sched_list_remove(struct cl_tx_queue *tx_queue)
+{
+	/* Remove from schedule queue */
+	if (tx_queue->sched) {
+		tx_queue->sched = false;
+		list_del(&tx_queue->sched_list);
+	}
+}
+
+static void cl_txq_sched_list_remove_if_empty(struct cl_tx_queue *tx_queue)
+{
+	/* If queue is empty remove it from schedule list */
+	if (list_empty(&tx_queue->hdrs))
+		cl_txq_sched_list_remove(tx_queue);
+}
+
+static void cl_txq_transfer_single_to_agg(struct cl_hw *cl_hw,
+					  struct cl_tx_queue *single_queue,
+					  struct cl_tx_queue *agg_queue, u8 tid)
+{
+	struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+	struct ieee80211_tx_info *tx_info;
+	struct sk_buff *skb;
+	u8 hdr_pads;
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+
+	if (single_queue->num_packets == 0)
+		goto out;
+
+	list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &single_queue->hdrs, tx_queue_list) {
+		if (sw_txhdr->tid != tid)
+			continue;
+
+		if (!ieee80211_is_data_qos(sw_txhdr->fc))
+			continue;
+
+		cl_hw->tx_packet_cntr.transfer.single_to_agg++;
+
+		/* Remove from single queue */
+		list_del(&sw_txhdr->tx_queue_list);
+
+		/* Update single queue counters */
+		single_queue->num_packets--;
+		single_queue->total_packets--;
+
+		/* Turn on AMPDU flag */
+		skb = sw_txhdr->skb;
+		tx_info = IEEE80211_SKB_CB(skb);
+		tx_info->flags |= IEEE80211_TX_CTL_AMPDU;
+
+		/* Convert header back and Push skb to agg queue */
+		cl_tx_wlan_to_8023(skb);
+		hdr_pads = CL_SKB_DATA_ALIGN_PADS(skb->data);
+		cl_tx_agg_prep(cl_hw, sw_txhdr, skb->len, hdr_pads, true);
+		agg_queue->total_packets++;
+		sw_txhdr->hdr80211 = NULL;
+		sw_txhdr->tx_queue = agg_queue;
+		cl_txq_push(cl_hw, sw_txhdr);
+
+		/* Schedule tasklet to try and empty the queue */
+		tasklet_schedule(&cl_hw->tx_task);
+	}
+
+	/* If single queue is empty remove it from schedule list */
+	cl_txq_sched_list_remove_if_empty(single_queue);
+
+out:
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_delete_packets(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 sta_idx)
+{
+	struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+
+	list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+		/*
+		 * Brodcast frames do not have cl_sta and should not be
+		 * deleted at station remove sequence.
+		 */
+		if (!sw_txhdr->cl_sta)
+			continue;
+
+		if (sw_txhdr->sta_idx != sta_idx)
+			continue;
+
+		list_del(&sw_txhdr->tx_queue_list);
+		tx_queue->num_packets--;
+
+		cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+	}
+
+	/* If queue is empty remove it from schedule list */
+	cl_txq_sched_list_remove_if_empty(tx_queue);
+}
+
+static void cl_txq_reset_counters(struct cl_tx_queue *tx_queue)
+{
+	tx_queue->total_fw_push_desc = 0;
+	tx_queue->total_fw_push_skb = 0;
+	tx_queue->total_fw_cfm = 0;
+	tx_queue->total_packets = 0;
+	tx_queue->dump_queue_full = 0;
+	tx_queue->dump_dma_map_fail = 0;
+
+	memset(tx_queue->stats_hw_amsdu_cnt, 0,
+	       sizeof(tx_queue->stats_hw_amsdu_cnt));
+
+	memset(tx_queue->stats_sw_amsdu_cnt, 0,
+	       sizeof(tx_queue->stats_sw_amsdu_cnt));
+}
+
+static void cl_txq_flush(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue)
+{
+	struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+	struct ieee80211_tx_info *tx_info;
+
+	if (tx_queue->num_packets == 0)
+		return;
+
+	list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+		list_del(&sw_txhdr->tx_queue_list);
+		tx_queue->num_packets--;
+
+		/* Can not send AMSDU frames as singles */
+		tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+
+		/* Free mid & last AMSDU sub frames */
+		if (cl_tx_ctrl_is_amsdu(tx_info)) {
+			cl_tx_amsdu_flush_sub_frames(cl_hw, sw_txhdr);
+		} else {
+			if (tx_queue->type == QUEUE_TYPE_SINGLE)
+				cl_tx_single_free_skb(cl_hw, sw_txhdr->skb);
+			else
+				kfree_skb(sw_txhdr->skb);
+
+			cl_hw->tx_packet_cntr.drop.queue_flush++;
+			sw_txhdr->cl_vif->trfc_cntrs[sw_txhdr->ac].tx_dropped++;
+			cl_sw_txhdr_free(cl_hw, sw_txhdr);
+		}
+	}
+
+	/* Remove from schedule queue */
+	cl_txq_sched_list_remove(tx_queue);
+
+	/* Sanity check that queue is empty */
+	WARN_ON(tx_queue->num_packets > 0);
+}
+
+static void cl_txq_agg_size_set(struct cl_hw *cl_hw)
+{
+	struct cl_tx_queue *tx_queue = NULL;
+	u16 new_size = 0;
+	u16 drv_max_size = 0;
+	int i = 0;
+	int j = 0;
+
+	if (!cl_hw->used_agg_queues || !cl_hw->conf->ci_tx_packet_limit)
+		return;
+
+	new_size = cl_hw->conf->ci_tx_packet_limit / cl_hw->used_agg_queues;
+	drv_max_size = max(new_size, cl_hw->conf->ci_tx_queue_size_agg);
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+		tx_queue = &cl_hw->tx_queues->agg[i];
+
+		if (!tx_queue->cl_sta)
+			continue;
+
+		tx_queue->max_packets = drv_max_size;
+
+		j++;
+		if (j == cl_hw->used_agg_queues)
+			break;
+	}
+
+	cl_dbg_trace(cl_hw, "drv_max_size = %u\n", drv_max_size);
+}
+
+static int cl_txq_request_find(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+	int i = 0;
+	struct cl_req_agg_db *req_agg_db = NULL;
+	u8 req_agg_queues = 0;
+
+	for (i = 0; (i < IPC_MAX_BA_SESSIONS) && (req_agg_queues < cl_hw->req_agg_queues); i++) {
+		req_agg_db = &cl_hw->req_agg_db[i];
+
+		if (!req_agg_db->is_used)
+			continue;
+
+		req_agg_queues++;
+
+		if (sta_idx == req_agg_db->sta_idx && tid == req_agg_db->tid)
+			return i;
+	}
+
+	return -1;
+}
+
+static void cl_txq_push_cntrs_update(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+				     u32 orig_drv_cnt, u32 orig_fw_cnt)
+{
+	u32 total_pushed;
+	u32 idx;
+
+	if (!cl_hw->conf->ci_tx_push_cntrs_stat_en)
+		return;
+
+	total_pushed = orig_drv_cnt - tx_queue->num_packets;
+	idx = tx_queue->push_cntrs_db.tx_push_logger_idx % TX_PUSH_LOGGER_SIZE;
+	tx_queue->push_cntrs_db.tx_push_cntr_hist[total_pushed]++;
+	tx_queue->push_cntrs_db.tx_push_logger[idx][TX_PUSH_LOGGER_DRV_CNT] = orig_drv_cnt;
+	tx_queue->push_cntrs_db.tx_push_logger[idx][TX_PUSH_LOGGER_FW_CNT] = orig_fw_cnt;
+	tx_queue->push_cntrs_db.tx_push_logger[idx][TX_PUSH_LOGGER_PKT_PUSHED] = total_pushed;
+	++tx_queue->push_cntrs_db.tx_push_logger_idx;
+}
+
+static void cl_txq_task_single(struct cl_hw *cl_hw)
+{
+	/* Schedule single queues */
+	struct cl_tx_queue *tx_queue, *tx_queue_tmp;
+
+	spin_lock(&cl_hw->tx_lock_single);
+
+	list_for_each_entry_safe(tx_queue, tx_queue_tmp, &cl_hw->list_sched_q_single, sched_list)
+		cl_txq_sched(cl_hw, tx_queue);
+
+	/* Rotate the queue so next schedule will start with a different queue */
+	list_rotate_left(&cl_hw->list_sched_q_single);
+
+	spin_unlock(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_task_agg(struct cl_hw *cl_hw)
+{
+	/* Schedule agg queueus */
+	struct cl_tx_queue *tx_queue, *tx_queue_tmp;
+
+	spin_lock(&cl_hw->tx_lock_agg);
+
+	list_for_each_entry_safe(tx_queue, tx_queue_tmp, &cl_hw->list_sched_q_agg, sched_list)
+		cl_txq_sched(cl_hw, tx_queue);
+
+	/* Rotate the queue so next schedule will start with a different queue */
+	list_rotate_left(&cl_hw->list_sched_q_agg);
+
+	spin_unlock(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_task(unsigned long data)
+{
+	struct cl_hw *cl_hw = (struct cl_hw *)data;
+
+	cl_txq_task_single(cl_hw);
+	cl_txq_task_agg(cl_hw);
+}
+
+static void cl_txq_agg_inc_usage_cntr(struct cl_hw *cl_hw)
+{
+	/* Should be called in cl_hw->tx_lock_agg context */
+	cl_hw->used_agg_queues++;
+	cl_txq_agg_size_set(cl_hw);
+}
+
+static void cl_txq_agg_dec_usage_cntr(struct cl_hw *cl_hw)
+{
+	/* Should be called in cl_hw->tx_lock_agg context */
+	WARN_ON_ONCE(cl_hw->used_agg_queues == 0);
+
+	cl_hw->used_agg_queues--;
+	cl_txq_agg_size_set(cl_hw);
+}
+
+static void cl_txq_init_single(struct cl_hw *cl_hw)
+{
+	struct cl_tx_queue *tx_queue;
+	u32 i;
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+
+	INIT_LIST_HEAD(&cl_hw->list_sched_q_single);
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++) {
+		tx_queue = &cl_hw->tx_queues->single[i];
+		memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+		INIT_LIST_HEAD(&tx_queue->hdrs);
+		tx_queue->hw_index = i / FW_MAX_NUM_STA;
+		tx_queue->fw_max_size = IPC_TXDESC_CNT_SINGLE;
+		tx_queue->fw_free_space = IPC_TXDESC_CNT_SINGLE;
+		tx_queue->index = i;
+		tx_queue->max_packets = cl_hw->conf->ci_tx_queue_size_single;
+		tx_queue->type = QUEUE_TYPE_SINGLE;
+	}
+
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+static void cl_txq_init_bcmc(struct cl_hw *cl_hw)
+{
+	struct cl_tx_queue *tx_queue;
+
+	spin_lock_bh(&cl_hw->tx_lock_bcmc);
+
+	tx_queue = &cl_hw->tx_queues->bcmc;
+	memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+	INIT_LIST_HEAD(&tx_queue->hdrs);
+	tx_queue->hw_index = CL_HWQ_BCN;
+	tx_queue->fw_max_size = IPC_TXDESC_CNT_BCMC;
+	tx_queue->fw_free_space = IPC_TXDESC_CNT_BCMC;
+	tx_queue->index = 0;
+	tx_queue->max_packets = 0;
+	tx_queue->type = QUEUE_TYPE_BCMC;
+
+	spin_unlock_bh(&cl_hw->tx_lock_bcmc);
+}
+
+static void cl_txq_init_agg(struct cl_hw *cl_hw)
+{
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+	INIT_LIST_HEAD(&cl_hw->list_sched_q_agg);
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+static void cl_txq_agg_request_reset(struct cl_hw *cl_hw)
+{
+	cl_hw->req_agg_queues = 0;
+	memset(cl_hw->req_agg_db, 0, sizeof(cl_hw->req_agg_db));
+}
+
+void cl_txq_init(struct cl_hw *cl_hw)
+{
+	tasklet_init(&cl_hw->tx_task, cl_txq_task, (unsigned long)cl_hw);
+
+	cl_txq_agg_request_reset(cl_hw);
+	cl_txq_init_single(cl_hw);
+	cl_txq_init_bcmc(cl_hw);
+	cl_txq_init_agg(cl_hw);
+}
+
+void cl_txq_stop(struct cl_hw *cl_hw)
+{
+	tasklet_kill(&cl_hw->tx_task);
+}
+
+struct cl_tx_queue *cl_txq_get(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(sw_txhdr->skb);
+	u8 hw_queue = sw_txhdr->hw_queue;
+
+	if (!cl_sta &&
+	    hw_queue == CL_HWQ_VO &&
+	    is_multicast_ether_addr(sw_txhdr->hdr80211->addr1)) {
+		/*
+		 * If HW queue is VO and packet is multicast, it was not buffered
+		 * by mac80211, and it should be pushed to the high-priority queue
+		 * and not to the bcmc queue.
+		 */
+		return &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE];
+	} else if (!cl_sta &&
+		   (hw_queue != CL_HWQ_BCN) &&
+		   !(tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+		/*
+		 * If station is NULL, but HW queue is not BCN,
+		 * it most go to the high-priority queue.
+		 */
+		tx_info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+		sw_txhdr->hw_queue = CL_HWQ_VO;
+		return &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE];
+	} else if (cl_sta && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
+		/* Agg packet */
+		return cl_sta->agg_tx_queues[sw_txhdr->tid];
+	} else if (hw_queue == CL_HWQ_BCN) {
+		return &cl_hw->tx_queues->bcmc;
+	} else if (tx_info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) {
+		/*
+		 * Only frames that are power save response or non-bufferable MMPDU
+		 * will have this flag set our driver will push those frame to the
+		 * highiest priority queue.
+		 */
+		return &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE];
+	}
+
+	return &cl_hw->tx_queues->single[QUEUE_IDX(sw_txhdr->sta_idx, hw_queue)];
+}
+
+void cl_txq_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr)
+{
+	struct cl_tx_queue *tx_queue = sw_txhdr->tx_queue;
+
+	if (tx_queue->num_packets < tx_queue->max_packets) {
+		tx_queue->num_packets++;
+
+		/*
+		 * This prioritization of action frames helps Samsung Galaxy Note 8 to
+		 * open BA session more easily, when phy dev is PHY_DEV_OLYMPUS
+		 * and helps open BA on all system emulators
+		 */
+		if (ieee80211_is_action(sw_txhdr->fc) && !IS_REAL_PHY(cl_hw->chip))
+			list_add(&sw_txhdr->tx_queue_list, &tx_queue->hdrs);
+		else
+			list_add_tail(&sw_txhdr->tx_queue_list, &tx_queue->hdrs);
+
+		/* If it is the first packet in the queue, add the queue to the sched list */
+		cl_txq_sched_list_add(tx_queue, cl_hw);
+	} else {
+		struct cl_sta *cl_sta = sw_txhdr->cl_sta;
+		u8 tid = sw_txhdr->tid;
+
+		/* If the SW queue full, release the packet */
+		tx_queue->dump_queue_full++;
+
+		if (cl_sta && cl_sta->amsdu_anchor[tid].sw_txhdr) {
+			if (cl_sta->amsdu_anchor[tid].sw_txhdr == sw_txhdr) {
+				cl_sta->amsdu_anchor[tid].sw_txhdr = NULL;
+				cl_sta->amsdu_anchor[tid].packet_cnt = 0;
+			}
+		}
+
+		dev_kfree_skb_any(sw_txhdr->skb);
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+
+		/* Schedule tasklet to try and empty the queue */
+		tasklet_schedule(&cl_hw->tx_task);
+	}
+}
+
+void cl_txq_sched(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue)
+{
+	struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+	u32 orig_drv_cnt = tx_queue->num_packets;
+	u32 orig_fw_cnt = cl_txq_desc_in_fw(tx_queue);
+	struct cl_sta *cl_sta = tx_queue->cl_sta;
+
+	if (!test_bit(CL_DEV_STARTED, &cl_hw->drv_flags) ||
+	    cl_hw->tx_disable_flags ||
+	    cl_txq_is_fw_full(tx_queue) ||
+	    (cl_sta && cl_sta->pause_tx))
+		return;
+
+	/* Go over all descriptors in queue */
+	list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &tx_queue->hdrs, tx_queue_list) {
+		list_del(&sw_txhdr->tx_queue_list);
+		tx_queue->num_packets--;
+
+		if (cl_hw->tx_db.force_amsdu &&
+		    sw_txhdr->txdesc.host_info.packet_cnt < cl_hw->txamsdu_en)
+			break;
+
+		cl_tx_push(cl_hw, sw_txhdr, tx_queue);
+
+		if (cl_txq_is_fw_full(tx_queue))
+			break;
+	}
+
+	cl_txq_push_cntrs_update(cl_hw, tx_queue, orig_drv_cnt, orig_fw_cnt);
+
+	/* If queue is empty remove it from schedule list */
+	cl_txq_sched_list_remove_if_empty(tx_queue);
+}
+
+void cl_txq_agg_alloc(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		      struct mm_ba_add_cfm *ba_add_cfm, u16 buf_size)
+{
+	u8 tid = ba_add_cfm->tid;
+	u8 fw_agg_idx = ba_add_cfm->agg_idx;
+	u8 sta_idx = cl_sta->sta_idx;
+	u8 ac = cl_tid2hwq[tid];
+	u16 single_queue_idx = QUEUE_IDX(sta_idx, ac);
+	struct cl_tx_queue *tx_queue = &cl_hw->tx_queues->agg[fw_agg_idx];
+
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+
+	/* Init aggregated queue struct */
+	memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+	INIT_LIST_HEAD(&tx_queue->hdrs);
+
+	/*
+	 * Firmware agg queues size is static and set to 512, so that for the worst
+	 * case of HE stations,that support AMPDU of 256, it has room for two full
+	 * aggregation.
+	 * To keep this logic, of room for two aggregations, for non-HE stations, or
+	 * for HE stations that do not support AMPDU of 256, we initialize fw_max_size
+	 to twice the buffer size supported by the station.
+	 */
+	tx_queue->fw_max_size = min_t(u16, TXDESC_AGG_Q_SIZE_MAX, buf_size * 2);
+	tx_queue->fw_free_space = tx_queue->fw_max_size;
+
+	tx_queue->max_packets = cl_hw->conf->ci_tx_queue_size_agg;
+	tx_queue->hw_index = ac;
+	tx_queue->cl_sta = cl_sta;
+	tx_queue->type = QUEUE_TYPE_AGG;
+	tx_queue->tid = tid;
+	tx_queue->index = fw_agg_idx;
+
+	/* Reset the synchronization counters between the fw and the IPC layer */
+	cl_hw->ipc_env->ring_indices_elem->indices->txdesc_write_idx.agg[fw_agg_idx] = 0;
+
+	/* Attach the cl_hw chosen queue to the station and agg queues DB */
+	cl_sta->agg_tx_queues[tid] = tx_queue;
+	cl_agg_cfm_set_tx_queue(cl_hw, tx_queue, fw_agg_idx);
+
+	/* Notify upper mac80211 layer of queues resources status */
+	cl_txq_agg_inc_usage_cntr(cl_hw);
+	cl_txq_agg_request_del(cl_hw, sta_idx, tid);
+
+	/*
+	 * Move the qos descriptors to the new allocated aggregated queues,
+	 * otherwise we might reorder packets)
+	 */
+	cl_txq_transfer_single_to_agg(cl_hw, &cl_hw->tx_queues->single[single_queue_idx],
+				      tx_queue, tid);
+	/* Move the BA window pending packets to agg path */
+	cl_baw_pending_to_agg(cl_hw, cl_sta, tid);
+
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+	cl_dbg_trace(cl_hw, "Allocate queue [%u] to station [%u] tid [%u]\n",
+		     fw_agg_idx, sta_idx, tid);
+}
+
+void cl_txq_agg_free(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+		     struct cl_sta *cl_sta, u8 tid)
+{
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+
+	cl_dbg_trace(cl_hw, "Free queue [%u] of station [%u] tid [%u]\n",
+		     tx_queue->index, cl_sta->sta_idx, tid);
+
+	memset(tx_queue, 0, sizeof(struct cl_tx_queue));
+
+	cl_txq_agg_dec_usage_cntr(cl_hw);
+
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+}
+
+void cl_txq_agg_stop(struct cl_sta *cl_sta, u8 tid)
+{
+	cl_sta->agg_tx_queues[tid] = NULL;
+}
+
+void cl_txq_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	/* Set cl_sta field for all single queues of this station */
+	u8 ac;
+	u16 queue_idx;
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		queue_idx = QUEUE_IDX(cl_sta->sta_idx, ac);
+		cl_hw->tx_queues->single[queue_idx].cl_sta = cl_sta;
+	}
+
+	/* Reset pointers to TX agg queues */
+	memset(cl_sta->agg_tx_queues, 0, sizeof(cl_sta->agg_tx_queues));
+}
+
+void cl_txq_sta_remove(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	/* Clear cl_sta field for all single queues of this station */
+	u8 ac;
+	u16 queue_idx;
+
+	for (ac = 0; ac < AC_MAX; ac++) {
+		queue_idx = QUEUE_IDX(sta_idx, ac);
+		cl_hw->tx_queues->single[queue_idx].cl_sta = NULL;
+	}
+}
+
+void cl_txq_transfer_agg_to_single(struct cl_hw *cl_hw, struct cl_tx_queue *agg_queue)
+{
+	/*
+	 * 1) Remove from aggregation queue
+	 * 2) Free sw_txhdr
+	 * 3) Push to single queue
+	 */
+	struct cl_sw_txhdr *sw_txhdr, *sw_txhdr_tmp;
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *tx_info;
+	struct cl_tx_queue *single_queue;
+	struct cl_sta *cl_sta = agg_queue->cl_sta;
+	u16 single_queue_idx = 0;
+
+	if (agg_queue->num_packets == 0)
+		return;
+
+	single_queue_idx = QUEUE_IDX(cl_sta->sta_idx, agg_queue->hw_index);
+	single_queue = &cl_hw->tx_queues->single[single_queue_idx];
+
+	list_for_each_entry_safe(sw_txhdr, sw_txhdr_tmp, &agg_queue->hdrs, tx_queue_list) {
+		list_del(&sw_txhdr->tx_queue_list);
+		agg_queue->num_packets--;
+
+		skb = sw_txhdr->skb;
+		tx_info = IEEE80211_SKB_CB(skb);
+
+		if (cl_tx_ctrl_is_amsdu(tx_info)) {
+			cl_tx_amsdu_transfer_single(cl_hw, sw_txhdr);
+		} else {
+			tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
+			if (cl_tx_8023_to_wlan(cl_hw, skb, cl_sta, sw_txhdr->tid) == 0) {
+				cl_hw->tx_packet_cntr.transfer.agg_to_single++;
+				cl_tx_single(cl_hw, cl_sta, skb, false, false);
+			}
+		}
+
+		cl_sw_txhdr_free(cl_hw, sw_txhdr);
+	}
+
+	/* If queue is empty remove it from schedule list */
+	cl_txq_sched_list_remove_if_empty(agg_queue);
+}
+
+void cl_txq_flush_agg(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, bool lock)
+{
+	if (lock) {
+		spin_lock_bh(&cl_hw->tx_lock_agg);
+		cl_txq_flush(cl_hw, tx_queue);
+		spin_unlock_bh(&cl_hw->tx_lock_agg);
+	} else {
+		cl_txq_flush(cl_hw, tx_queue);
+	}
+}
+
+void cl_txq_flush_all_agg(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		cl_txq_flush(cl_hw, &cl_hw->tx_queues->agg[i]);
+}
+
+void cl_txq_flush_all_single(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		cl_txq_flush(cl_hw, &cl_hw->tx_queues->single[i]);
+}
+
+void cl_txq_flush_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	int i = 0;
+	u8 sta_idx = cl_sta->sta_idx;
+	u32 queue_idx = 0;
+	struct cl_tx_queue *tx_queue = NULL;
+
+	spin_lock_bh(&cl_hw->tx_lock_agg);
+
+	/* Flush all aggregation queues for this station */
+	for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+		if (cl_sta->agg_tx_queues[i])
+			cl_txq_flush(cl_hw, cl_sta->agg_tx_queues[i]);
+
+	spin_unlock_bh(&cl_hw->tx_lock_agg);
+
+	spin_lock_bh(&cl_hw->tx_lock_single);
+
+	/* Flush all single queues for this station */
+	for (i = 0; i < AC_MAX; i++) {
+		queue_idx = QUEUE_IDX(sta_idx, i);
+		tx_queue = &cl_hw->tx_queues->single[queue_idx];
+		cl_txq_flush(cl_hw, tx_queue);
+		cl_txq_reset_counters(tx_queue);
+	}
+
+	/* Go over high prioirty queue and delete packets belonging to this station */
+	cl_txq_delete_packets(cl_hw, &cl_hw->tx_queues->single[HIGH_PRIORITY_QUEUE], sta_idx);
+
+	spin_unlock_bh(&cl_hw->tx_lock_single);
+}
+
+void cl_txq_agg_request_add(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+	int i = cl_txq_request_find(cl_hw, sta_idx, tid);
+	struct cl_req_agg_db *req_agg_db = NULL;
+
+	if (i != -1) {
+		cl_dbg_trace(cl_hw, "ALREADY_ADDED - entry = %d, sta_idx = %u, tid = %u\n",
+			     i, sta_idx, tid);
+		return;
+	}
+
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++) {
+		req_agg_db = &cl_hw->req_agg_db[i];
+
+		if (!req_agg_db->is_used) {
+			cl_dbg_trace(cl_hw, "ADD - entry = %d, sta_idx = %u, tid = %u\n",
+				     i, sta_idx, tid);
+			req_agg_db->is_used = true;
+			req_agg_db->sta_idx = sta_idx;
+			req_agg_db->tid = tid;
+			cl_hw->req_agg_queues++;
+			return;
+		}
+	}
+}
+
+void cl_txq_agg_request_del(struct cl_hw *cl_hw, u8 sta_idx, u8 tid)
+{
+	int i = cl_txq_request_find(cl_hw, sta_idx, tid);
+
+	if (i != -1) {
+		cl_dbg_trace(cl_hw, "DEL - entry = %d, sta_idx = %u, tid = %u\n",
+			     i, sta_idx, tid);
+		cl_hw->req_agg_db[i].is_used = false;
+		cl_hw->req_agg_queues--;
+	}
+}
+
+bool cl_txq_is_agg_available(struct cl_hw *cl_hw)
+{
+	u8 total_agg_queues = cl_hw->used_agg_queues + cl_hw->req_agg_queues;
+
+	return (total_agg_queues < IPC_MAX_BA_SESSIONS);
+}
+
+bool cl_txq_is_fw_empty(struct cl_tx_queue *tx_queue)
+{
+	return (tx_queue->fw_free_space == tx_queue->fw_max_size);
+}
+
+bool cl_txq_is_fw_full(struct cl_tx_queue *tx_queue)
+{
+	return (tx_queue->fw_free_space == 0);
+}
+
+u16 cl_txq_desc_in_fw(struct cl_tx_queue *tx_queue)
+{
+	return (tx_queue->fw_max_size - tx_queue->fw_free_space);
+}
+
+bool cl_txq_frames_pending(struct cl_hw *cl_hw)
+{
+	int i = 0;
+
+	/* Check if we have multicast/bradcast frame in FW queues */
+	if (!cl_txq_is_fw_empty(&cl_hw->tx_queues->bcmc))
+		return true;
+
+	/* Check if we have singles frame in FW queues */
+	for (i = 0; i < MAX_SINGLE_QUEUES; i++)
+		if (!cl_txq_is_fw_empty(&cl_hw->tx_queues->single[i]))
+			return true;
+
+	/* Check if we have aggregation frame in FW queues */
+	for (i = 0; i < IPC_MAX_BA_SESSIONS; i++)
+		if (!cl_txq_is_fw_empty(&cl_hw->tx_queues->agg[i]))
+			return true;
+
+	return false;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 85/96] cl8k: add tx.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (83 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 84/96] cl8k: add tx.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 86/96] cl8k: add utils.c viktor.barna
                   ` (10 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/tx.h | 467 ++++++++++++++++++++++++++
 1 file changed, 467 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/tx.h

diff --git a/drivers/net/wireless/celeno/cl8k/tx.h b/drivers/net/wireless/celeno/cl8k/tx.h
new file mode 100644
index 000000000000..d36a7d703df6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/tx.h
@@ -0,0 +1,467 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_TX_H
+#define CL_TX_H
+
+#include <linux/interrupt.h>
+
+#include "sta_info.h"
+#include "vif.h"
+#include "ipc_shared.h"
+#include "fw.h"
+#include "wrs.h"
+
+enum cl_queue_type {
+	QUEUE_TYPE_SINGLE,
+	QUEUE_TYPE_AGG,
+	QUEUE_TYPE_BCMC,
+
+	QUEUE_TYPE_MAX
+};
+
+#define QUEUE_IDX(sta, ac)  ((sta) + (ac) * FW_MAX_NUM_STA)
+
+#define TX_PUSH_LOGGER_SIZE 256
+
+#define BCMC_POLL_TIMEOUT 50
+
+enum cl_tx_push_logger_param {
+	TX_PUSH_LOGGER_DRV_CNT,
+	TX_PUSH_LOGGER_FW_CNT,
+	TX_PUSH_LOGGER_PKT_PUSHED,
+	TX_PUSH_LOGGER_MAX,
+};
+
+struct cl_tx_push_cntrs {
+	u32 tx_push_cntr_hist[TXDESC_AGG_Q_SIZE_MAX + 1];
+	u32 tx_push_logger[TX_PUSH_LOGGER_SIZE][TX_PUSH_LOGGER_MAX];
+	u32 tx_push_logger_idx;
+};
+
+struct cl_tx_queue {
+	struct list_head sched_list;
+	struct list_head hdrs;
+	struct cl_sta *cl_sta;
+	bool sched;
+	u16 fw_free_space;
+	u16 fw_max_size;
+	u8 type;
+	u8 tid;
+	u8 hw_index;
+	u16 index;
+	u16 max_packets;
+	u16 num_packets;
+	u32 total_packets;
+	u32 total_fw_push_desc;
+	u32 total_fw_push_skb;
+	u32 total_fw_cfm;
+	u32 dump_queue_full;
+	u32 dump_dma_map_fail;
+	u32 stats_hw_amsdu_cnt[CL_AMSDU_TX_PAYLOAD_MAX];
+	u32 stats_sw_amsdu_cnt[MAX_TX_SW_AMSDU_PACKET];
+	u32 hist_xmit_to_push[DELAY_HIST_SIZE];
+	u32 hist_push_to_cfm[DELAY_HIST_SIZE];
+	struct cl_tx_push_cntrs push_cntrs_db;
+};
+
+/*
+ * struct cl_tx_queues:
+ * This structure holds all driver TX queues,
+ * The queues buffer frames pushed by upper layer and push them to lower IPC layer.
+ */
+struct cl_tx_queues {
+	struct cl_tx_queue agg[IPC_MAX_BA_SESSIONS];
+	struct cl_tx_queue single[MAX_SINGLE_QUEUES];
+	struct cl_tx_queue bcmc;
+};
+
+struct cl_req_agg_db {
+	bool is_used;
+	u8 sta_idx;
+	u8 tid;
+};
+
+#define INC_SN(sn) (((sn) + 0x10) & IEEE80211_SCTL_SEQ)
+#define DEC_SN(sn) (((sn) - 0x10) & IEEE80211_SCTL_SEQ)
+
+#define CL_TX_LIFETIME_MS 4000
+
+#define CL_SKB_DATA_ALIGN_SZ      4
+#define CL_SKB_DATA_ALIGN_MSK     (CL_SKB_DATA_ALIGN_SZ - 1)
+#define CL_SKB_DATA_ALIGN_PADS(x) \
+	((CL_SKB_DATA_ALIGN_SZ - ((ptrdiff_t)(x) & CL_SKB_DATA_ALIGN_MSK)) & CL_SKB_DATA_ALIGN_MSK)
+
+#define CL_TX_MAX_FRAME_LEN_SINGLE 4096
+#define CL_TX_MAX_FRAME_LEN_AGG 2000
+
+struct cl_hw_tx_status {
+	u32 mcs_index          : 7; /* [6:0] */
+	u32 is_bcmc            : 1; /* [7] */
+	u32 num_mpdu_retries   : 4; /* [11:8] */
+	u32 rsv                : 4; /* [15:12] */
+	u32 format_mod         : 4; /* [19:16] */
+	u32 bw_requested       : 2; /* [21:20] */
+	u32 bf                 : 1; /* [22] */
+	u32 frm_successful     : 1; /* [23] */
+	u32 bw_transmitted     : 2; /* [25:24] */
+	u32 freespace_inc_skip : 1; /* [26] */
+	u32 keep_skb           : 1; /* [27] */
+	u32 gi                 : 2; /* [29:28] */
+	u32 descriptor_done_sw : 1; /* [30] */
+	u32 descriptor_done_hw : 1; /* [31] */
+};
+
+enum cl_tx_flags {
+	CL_TX_EN_DFS,
+	CL_TX_EN_SCAN
+};
+
+enum cl_tx_single_frame_type {
+	CL_TX_SINGLE_FRAME_TYPE_QOS_DATA,
+	CL_TX_SINGLE_FRAME_TYPE_QOS_NULL,
+	CL_TX_SINGLE_FRAME_TYPE_MANAGEMENT,
+	CL_TX_SINGLE_FRAME_TYPE_OTHER
+};
+
+struct cl_tx_db {
+	bool force_amsdu;
+	bool block_bcn;
+	bool block_prob_resp;
+};
+
+struct cl_tx_drop_cntr {
+	u32 radio_off;
+	u32 in_recovery;
+	u32 short_length;
+	u32 pending_full;
+	u32 packet_limit;
+	u32 dev_flags;
+	u32 tx_disable;
+	u32 length_limit;
+	u32 txhdr_alloc_fail;
+	u32 queue_null;
+	u32 amsdu_alloc_fail;
+	u32 amsdu_dma_map_err;
+	u32 build_hdr_fail;
+	u32 key_disable;
+	u32 queue_flush;
+	u32 probe_response;
+	u32 sta_null_in_agg;
+	u32 sta_stop_tx;
+};
+
+struct cl_tx_forward_cntr {
+	u32 tx_start;
+	u32 drv_fast_agg;
+	u32 drv_fast_single;
+	u32 to_mac;
+	u32 from_mac_single;
+	u32 from_mac_agg;
+};
+
+struct cl_tx_transfer_cntr {
+	u32 single_to_agg;
+	u32 agg_to_single;
+};
+
+struct cl_tx_packet_cntr {
+	struct cl_tx_forward_cntr forward;
+	struct cl_tx_drop_cntr drop;
+	struct cl_tx_transfer_cntr transfer;
+};
+
+struct cl_cpu_cntr {
+	u32 tx_agg[CPU_MAX_NUM];
+	u32 tx_single[CPU_MAX_NUM];
+};
+
+static inline bool cl_tx_ctrl_is_amsdu(struct ieee80211_tx_info *tx_info)
+{
+	return !!(tx_info->control.flags & IEEE80211_TX_CTRL_AMSDU);
+}
+
+static inline bool cl_tx_ctrl_is_eapol(struct ieee80211_tx_info *tx_info)
+{
+	return !!(tx_info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO);
+}
+
+struct cl_agg_cfm_queue {
+	struct list_head head;
+	struct cl_tx_queue *tx_queue;
+	u16 ssn;
+};
+
+/* Structure containing the parameters of the MM_AGG_TX_REPORT_IND message. */
+struct cl_agg_tx_report {
+	__le32 rate_cntrl_info;
+	__le32 rate_cntrl_info_he;
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u32 sta_idx                    : 8,
+	    is_sta_ps                  : 1,
+	    bw_requested               : 2,
+	    is_agg                     : 1,
+	    ba_not_received            : 1,
+	    ba_received_empty          : 1,
+	    bf                         : 1,
+	    is_fallback                : 1,
+	    mu_su_gid                  : 6,
+	    mu_mimo_valid              : 1,
+	    mu_ofdma_valid             : 1,
+	    rate_fix_mcs1              : 1,
+	    rsv0                       : 7;
+
+	u32 success                    : 9,
+	    fail                       : 9,
+	    below_baw_cnt              : 9,
+	    num_prot_retries           : 5;
+
+	u32 success_after_retry        : 9,
+	    success_more_one_retry     : 9,
+	    retry_limit_reached        : 9,
+	    is_retry                   : 1,
+	    is_rts_retry_limit_reached : 1,
+	    prot_type                  : 3;
+
+	u32 rssi1                      : 8,
+	    rssi2                      : 8,
+	    rssi3                      : 8,
+	    rssi4                      : 8;
+
+	u32 rssi5                      : 8,
+	    rssi6                      : 8,
+	    rsv1                       : 16;
+#else
+	u32 rsv0                       : 7,
+	    rate_fix_mcs1              : 1,
+	    mu_ofdma_valid             : 1,
+	    mu_mimo_valid              : 1,
+	    mu_su_gid                  : 6,
+	    is_fallback                : 1,
+	    bf                         : 1,
+	    ba_received_empty          : 1,
+	    ba_not_received            : 1,
+	    is_agg                     : 1,
+	    bw_requested               : 2,
+	    is_sta_ps                  : 1,
+	    sta_idx                    : 8;
+
+	u32 num_prot_retries           : 5,
+	    below_baw_cnt              : 9,
+	    fail                       : 9,
+	    success                    : 9;
+
+	u32 prot_type                  : 3,
+	    is_rts_retry_limit_reached : 1,
+	    is_retry                   : 1,
+	    retry_limit_reached        : 9,
+	    success_more_one_retry     : 9,
+	    success_after_retry        : 9;
+
+	u32 rssi4                      : 8,
+	    rssi3                      : 8,
+	    rssi2                      : 8,
+	    rssi1                      : 8;
+
+	u32 rsv1                       : 16,
+	    rssi6                      : 8,
+	    rssi5                      : 8;
+#endif
+	u16 new_ssn;
+	u8  tx_queue_idx;
+
+};
+
+void cl_agg_tx_report_handler(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			      struct cl_agg_tx_report *agg_report);
+void cl_agg_tx_report_simulate_for_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+					  struct cl_hw_tx_status *status);
+
+/* Per RA/TID Data for AMPDU TX */
+struct cl_baw {
+	u8 fw_agg_idx;
+	bool amsdu;
+	bool action_start;
+	u16 ssn;
+	u16 tid_seq;
+	struct sk_buff_head pending;
+};
+
+enum cl_amsdu_result {
+	CL_AMSDU_ANCHOR_SET,
+	CL_AMSDU_SUB_FRAME_SET,
+	CL_AMSDU_SKIP,
+	CL_AMSDU_FAILED
+};
+
+/* Max size of 802.11 WLAN header */
+#define CL_WLAN_HEADER_MAX_SIZE 36
+
+#define CL_AMSDU_MIN_AGG_SIZE 3
+#define CL_AMSDU_CONST_LEN    256
+
+struct cl_amsdu_txhdr {
+	struct list_head list;
+	struct list_head list_pool;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+};
+
+struct cl_amsdu_ctrl {
+	struct cl_sw_txhdr *sw_txhdr;
+	u16 rem_len;
+	u16 max_len;
+	u16 hdrlen;
+	u8 packet_cnt;
+	bool is_sw_amsdu;
+};
+
+struct cl_sw_txhdr {
+	struct list_head list_pool;
+	struct list_head tx_queue_list;
+	struct list_head cfm_list;
+	struct ieee80211_hdr *hdr80211;
+	struct cl_tx_queue *tx_queue;
+	struct cl_sta *cl_sta;
+	struct cl_vif *cl_vif;
+	struct cl_amsdu_txhdr amsdu_txhdr;
+	u8 hw_queue            : 3,
+	   is_bcn              : 1,
+	   tid                 : 4;
+	u8 ac                  : 2,
+	   is_sw_amsdu         : 1,
+	   sw_amsdu_packet_cnt : 4,
+	   rsv                 : 1;
+	/*
+	 * singles queue index used to push the txdesc to the ipc layer
+	 * this issue solve race condition in which we
+	 * CFM of packet that associated with disconnected STA and has invalid
+	 * cl_sta pointerinside this struct
+	 */
+	u8 sta_idx;
+	__le16 fc;
+	struct sk_buff *skb;
+	struct txdesc txdesc;
+	size_t map_len;
+	u16 total_pkt_len;
+};
+
+void cl_tx_init(struct cl_hw *cl_hw);
+void cl_tx_check_start_ba_session(struct cl_hw *cl_hw,
+				  struct ieee80211_sta *sta,
+				  struct sk_buff *skb);
+void cl_tx_bcns_tasklet(unsigned long data);
+void cl_tx_single_free_skb(struct cl_hw *cl_hw, struct sk_buff *skb);
+void cl_tx_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		  struct sk_buff *skb, bool is_vns, bool lock);
+void cl_tx_fast_single(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		       struct sk_buff *skb, bool lock);
+void cl_tx_agg_prep(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr,
+		    u16 frame_len, u8 hdr_pads, bool hdr_conv);
+void cl_tx_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+	       struct sk_buff *skb, bool hdr_conv, bool lock);
+void cl_tx_fast_agg(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		    struct sk_buff *skb, bool lock);
+u16 cl_tx_prepare_wlan_hdr(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			   struct sk_buff *skb, struct ieee80211_hdr *hdr);
+void cl_tx_wlan_to_8023(struct sk_buff *skb);
+int cl_tx_8023_to_wlan(struct cl_hw *cl_hw, struct sk_buff *skb, struct cl_sta *cl_sta, u8 tid);
+void cl_tx_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, struct cl_tx_queue *tx_queue);
+void cl_tx_bcn_mesh_task(unsigned long data);
+void cl_tx_en(struct cl_hw *cl_hw, u8 reason, bool enable);
+void cl_tx_off(struct cl_hw *cl_hw);
+void cl_tx_drop_skb(struct sk_buff *skb);
+void cl_tx_update_hist_tstamp(struct cl_tx_queue *tx_queue, struct sk_buff *skb,
+			      u32 tstamp_hist[DELAY_HIST_SIZE], bool update_skb_ktime);
+bool cl_is_tx_allowed(struct cl_hw *cl_hw);
+void cl_agg_cfm_init(struct cl_hw *cl_hw);
+void cl_agg_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u8 agg_idx);
+void cl_agg_cfm_free_head_skb(struct cl_hw *cl_hw,
+			      struct cl_agg_cfm_queue *cfm_queue,
+			      u8 ba_queue_idx);
+void cl_agg_cfm_flush_all(struct cl_hw *cl_hw);
+void cl_agg_cfm_poll_empty(struct cl_hw *cl_hw, u8 agg_idx, bool flush);
+void cl_agg_cfm_poll_empty_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_agg_cfm_clear_tim_bit_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_agg_cfm_set_ssn(struct cl_hw *cl_hw, u16 ssn, u8 idx);
+void cl_agg_cfm_set_tx_queue(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, u8 idx);
+void cl_baw_init(struct cl_sta *cl_sta);
+void cl_baw_start(struct cl_baw *baw, u16 ssn);
+void cl_baw_operational(struct cl_hw *cl_hw, struct cl_baw *baw,
+			u8 fw_agg_idx, bool amsdu_supported);
+void cl_baw_stop(struct cl_baw *baw);
+void cl_baw_pending_to_agg(struct cl_hw *cl_hw,
+			   struct cl_sta *cl_sta,
+			   u8 tid);
+void cl_baw_pending_to_single(struct cl_hw *cl_hw,
+			      struct cl_sta *cl_sta,
+			      struct cl_baw *baw);
+void cl_baw_pending_purge(struct cl_baw *baw);
+
+void cl_bcmc_cfm_init(struct cl_hw *cl_hw);
+void cl_bcmc_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+struct cl_sw_txhdr *cl_bcmc_cfm_find(struct cl_hw *cl_hw, dma_addr_t dma_addr,
+				     bool keep_in_list);
+void cl_bcmc_cfm_flush_queue(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+void cl_bcmc_cfm_poll_empty_per_vif(struct cl_hw *cl_hw,
+				    struct cl_vif *cl_vif);
+
+struct cl_single_cfm_queue {
+	struct list_head head;
+};
+
+void cl_single_cfm_init(struct cl_hw *cl_hw);
+void cl_single_cfm_add(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr, u32 queue_idx);
+struct cl_sw_txhdr *cl_single_cfm_find(struct cl_hw *cl_hw, u32 queue_idx,
+				       dma_addr_t dma_addr);
+void cl_single_cfm_flush_all(struct cl_hw *cl_hw);
+void cl_single_cfm_flush_sta(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_single_cfm_poll_empty(struct cl_hw *cl_hw, u32 queue_idx);
+void cl_single_cfm_poll_empty_sta(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_single_cfm_clear_tim_bit_sta(struct cl_hw *cl_hw, u8 sta_idx);
+
+int cl_sw_txhdr_init(struct cl_hw *cl_hw);
+void cl_sw_txhdr_deinit(struct cl_hw *cl_hw);
+struct cl_sw_txhdr *cl_sw_txhdr_alloc(struct cl_hw *cl_hw);
+void cl_sw_txhdr_free(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_tx_amsdu_anchor_init(struct cl_amsdu_ctrl *amsdu_anchor);
+void cl_tx_amsdu_anchor_reset(struct cl_amsdu_ctrl *amsdu_anchor);
+void cl_tx_amsdu_set_max_len(struct cl_hw *cl_hw, struct cl_sta *cl_sta, u8 tid);
+void cl_tx_amsdu_first_sub_frame(struct cl_sw_txhdr *sw_txhdr, struct cl_sta *cl_sta,
+				 struct sk_buff *skb, u8 tid);
+void cl_tx_amsdu_flush_sub_frames(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_tx_amsdu_transfer_single(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+int cl_tx_amsdu_set(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb, u8 tid);
+void cl_tx_amsdu_unset(struct cl_sw_txhdr *sw_txhdr);
+
+int cl_tx_amsdu_txhdr_init(struct cl_hw *cl_hw);
+void cl_tx_amsdu_txhdr_deinit(struct cl_hw *cl_hw);
+void cl_tx_amsdu_txhdr_free(struct cl_hw *cl_hw, struct cl_amsdu_txhdr *amsdu_txhdr);
+
+void cl_txq_init(struct cl_hw *cl_hw);
+void cl_txq_stop(struct cl_hw *cl_hw);
+struct cl_tx_queue *cl_txq_get(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_txq_push(struct cl_hw *cl_hw, struct cl_sw_txhdr *sw_txhdr);
+void cl_txq_sched(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue);
+void cl_txq_agg_alloc(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+		      struct mm_ba_add_cfm *ba_add_cfm, u16 buf_size);
+void cl_txq_agg_free(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue,
+		     struct cl_sta *cl_sta, u8 tid);
+void cl_txq_agg_stop(struct cl_sta *cl_sta, u8 tid);
+void cl_txq_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_txq_sta_remove(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_txq_transfer_agg_to_single(struct cl_hw *cl_hw, struct cl_tx_queue *agg_queue);
+void cl_txq_flush_agg(struct cl_hw *cl_hw, struct cl_tx_queue *tx_queue, bool lock);
+void cl_txq_flush_all_agg(struct cl_hw *cl_hw);
+void cl_txq_flush_all_single(struct cl_hw *cl_hw);
+void cl_txq_flush_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_txq_agg_request_add(struct cl_hw *cl_hw, u8 sta_idx, u8 tid);
+void cl_txq_agg_request_del(struct cl_hw *cl_hw, u8 sta_idx, u8 tid);
+bool cl_txq_is_agg_available(struct cl_hw *cl_hw);
+bool cl_txq_is_fw_empty(struct cl_tx_queue *tx_queue);
+bool cl_txq_is_fw_full(struct cl_tx_queue *tx_queue);
+u16 cl_txq_desc_in_fw(struct cl_tx_queue *tx_queue);
+bool cl_txq_frames_pending(struct cl_hw *cl_hw);
+
+#endif /* CL_TX_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 86/96] cl8k: add utils.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (84 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 85/96] cl8k: add tx.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 87/96] cl8k: add utils.h viktor.barna
                   ` (9 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils.c | 642 +++++++++++++++++++++++
 1 file changed, 642 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils.c

diff --git a/drivers/net/wireless/celeno/cl8k/utils.c b/drivers/net/wireless/celeno/cl8k/utils.c
new file mode 100644
index 000000000000..fadc586e9579
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <net/mac80211.h>
+#include <linux/sched/signal.h>
+#include <linux/firmware.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+#include "hw.h"
+#include "ipc_shared.h"
+#include "radio.h"
+#include "traffic.h"
+#include "reg/reg_defs.h"
+#include "utils.h"
+
+#define GI_08  0
+#define GI_16  1
+#define GI_32  2
+#define GI_04  3
+
+#define GI_MAX_FW 4
+#define GI_MAX_HE 3
+#define GI_MAX_HT_VHT 2
+
+static u8 conv_wrs_gi_ht_vht[GI_MAX_HT_VHT] = {
+	[WRS_GI_LONG] = GI_08,
+	[WRS_GI_SHORT] = GI_04
+};
+
+static u8 conv_wrs_gi_he[GI_MAX_HE] = {
+	[WRS_GI_LONG] = GI_32,
+	[WRS_GI_SHORT] = GI_16,
+	[WRS_GI_VSHORT] = GI_08
+};
+
+static u8 conv_fw_gi_ht_vht[GI_MAX_FW] = {
+	[GI_08] = WRS_GI_LONG,
+	[GI_16] = 0,
+	[GI_32] = 0,
+	[GI_04] = WRS_GI_SHORT,
+};
+
+static u8 conv_fw_gi_he[GI_MAX_FW] = {
+	[GI_08] = WRS_GI_VSHORT,
+	[GI_16] = WRS_GI_SHORT,
+	[GI_32] = WRS_GI_LONG,
+	[GI_04] = 0,
+};
+
+static const u8 cl_mu_ofdma_ru_type_to_bw_conversion[CL_MU_OFDMA_RU_TYPE_MAX] = {
+	CHNL_BW_2_5,
+	CHNL_BW_2_5,
+	CHNL_BW_5,
+	CHNL_BW_10,
+	CHNL_BW_20,
+	CHNL_BW_40,
+	CHNL_BW_80,
+	CHNL_BW_160
+};
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte)
+{
+	u8 *pt = buffer;
+	u32 i;
+	bool end_nl = false;
+	char buf[STR_LEN_256B] = {0};
+	int len = 0;
+
+	if (caption)
+		pr_debug("%s: %p, len = %u\n", caption, buffer, length);
+
+	if (is_byte) {
+		for (i = 0; i < length; i++) {
+			if (i % 16 == 0)
+				len += snprintf(buf + len, sizeof(buf) - len,
+						"0x%04x : ", i + offset);
+			len += snprintf(buf + len, sizeof(buf) - len,
+					"%02x ", ((u8)pt[i]));
+			end_nl = true;
+			if (i % 16 == 15) {
+				pr_debug("%s", buf);
+				len = 0;
+				end_nl = false;
+			}
+		}
+	} else {
+		for (i = 0; i < (length / sizeof(u32)); i++) {
+			if (i % 4 == 0)
+				len += snprintf(buf + len, sizeof(buf) - len,
+						"0x%04x : ",
+						(u32)(i * sizeof(u32) + offset));
+			len += snprintf(buf + len, sizeof(buf) - len,
+					"%08x ", *((u32 *)(pt + i * sizeof(u32))));
+			end_nl = true;
+			if (i % 4 == 3) {
+				pr_debug("%s", buf);
+				len = 0;
+				end_nl = false;
+			}
+		}
+	}
+
+	if (end_nl)
+		pr_debug("%s", buf);
+}
+
+u8 cl_convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi)
+{
+	if (wrs_mode == WRS_MODE_HE && gi < GI_MAX_HE)
+		return conv_wrs_gi_he[gi];
+	else if (wrs_mode > WRS_MODE_OFDM && gi < GI_MAX_HT_VHT)
+		return conv_wrs_gi_ht_vht[gi];
+	else
+		return 0;
+}
+
+u8 cl_convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi)
+{
+	if (gi < GI_MAX_FW) {
+		if (format_mode >= FORMATMOD_HE_SU)
+			return conv_fw_gi_he[gi];
+		else if (format_mode >= FORMATMOD_HT_MF)
+			return conv_fw_gi_ht_vht[gi];
+	}
+
+	return 0;
+}
+
+static u8 map_gi_to_ltf[WRS_GI_MAX] = {
+	[WRS_GI_LONG] = LTF_X4,
+	[WRS_GI_SHORT] = LTF_X2,
+	[WRS_GI_VSHORT] = LTF_X2,
+};
+
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi)
+{
+	if (mode == WRS_MODE_HE && gi < WRS_GI_MAX)
+		return map_gi_to_ltf[gi];
+
+	return 0;
+}
+
+/* This table holds 10^(-110 -> 0) Q39 values for rx RSSI and noise floor calculations */
+#define CL_EXP_TBL_SIZE 111 /* 10^x table size (-110 -> 0dBm) */
+
+static u64 CL_EXP_10[CL_EXP_TBL_SIZE] = {
+	0x7FFFFFFFFFULL, 0x65AC8C2F36ULL, 0x50C335D3DBULL, 0x4026E73CCDULL, 0x32F52CFEEAULL,
+	0x287A26C490ULL, 0x2026F30FBBULL, 0x198A13577CULL, 0x144960C577ULL, 0x101D3F2D96ULL,
+	0x0CCCCCCCCDULL, 0x0A2ADAD185ULL, 0x08138561FCULL, 0x066A4A52E1ULL, 0x0518847FE4ULL,
+	0x040C3713A8ULL, 0x0337184E5FULL, 0x028DCEBBF3ULL, 0x0207567A25ULL, 0x019C86515CULL,
+	0x0147AE147BULL, 0x01044914F4ULL, 0x00CEC089CCULL, 0x00A43AA1E3ULL, 0x008273A664ULL,
+	0x00679F1B91ULL, 0x00524F3B0AULL, 0x0041617932ULL, 0x0033EF0C37ULL, 0x002940A1BCULL,
+	0x0020C49BA6ULL, 0x001A074EE5ULL, 0x0014ACDA94ULL, 0x00106C4364ULL, 0x000D0B90A4ULL,
+	0x000A5CB5F5ULL, 0x00083B1F81ULL, 0x000689BF52ULL, 0x0005318139ULL, 0x000420102CULL,
+	0x000346DC5DULL, 0x00029A54B1ULL, 0x000211490FULL, 0x0001A46D24ULL, 0x00014DF4DDULL,
+	0x0001094565ULL, 0x0000D2B65AULL, 0x0000A75FEFULL, 0x000084F352ULL, 0x0000699B38ULL,
+	0x000053E2D6ULL, 0x000042A212ULL, 0x000034EDB5ULL, 0x00002A0AEAULL, 0x0000216549ULL,
+	0x00001A86F1ULL, 0x000015123CULL, 0x000010BCCBULL, 0x00000D4B88ULL, 0x00000A8F86ULL,
+	0x000008637CULL, 0x000006A9CFULL, 0x0000054AF8ULL, 0x000004344BULL, 0x00000356EEULL,
+	0x000002A718ULL, 0x0000021B6CULL, 0x000001AC7BULL, 0x000001545AULL, 0x0000010E5AULL,
+	0x000000D6C0ULL, 0x000000AA95ULL, 0x000000877FULL, 0x0000006BA1ULL, 0x000000557EULL,
+	0x00000043E9ULL, 0x00000035F1ULL, 0x0000002AD9ULL, 0x0000002209ULL, 0x0000001B09ULL,
+	0x000000157AULL, 0x000000110FULL, 0x0000000D8DULL, 0x0000000AC3ULL, 0x000000088DULL,
+	0x00000006CAULL, 0x0000000565ULL, 0x0000000449ULL, 0x0000000367ULL, 0x00000002B4ULL,
+	0x0000000226ULL, 0x00000001B5ULL, 0x000000015BULL, 0x0000000114ULL, 0x00000000DBULL,
+	0x00000000AEULL, 0x000000008AULL, 0x000000006EULL, 0x0000000057ULL, 0x0000000045ULL,
+	0x0000000037ULL, 0x000000002CULL, 0x0000000023ULL, 0x000000001CULL, 0x0000000016ULL,
+	0x0000000011ULL, 0x000000000EULL, 0x000000000BULL, 0x0000000009ULL, 0x0000000007ULL,
+	0x0000000005ULL
+};
+
+static s8 cl_eng_to_noise_floor(u64 eng)
+{
+	s8 i = 0;
+	s8 noise = 0;
+	s64 min_delta = S64_MAX;
+
+	for (i = CL_EXP_TBL_SIZE - 1; i >= 0; i--) {
+		if (abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i]))) < min_delta) {
+			min_delta = abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i])));
+			noise = i;
+		}
+	}
+
+	return (-noise);
+}
+
+static void cl_read_reg_noise(struct cl_hw *cl_hw, s8 res[4])
+{
+	u32 reg_val = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+	u8 i = 0;
+
+	for (i = 0; i < 4; i++) {
+		u8 curr_val = (reg_val >> (i * 8)) & 0xFF;
+		/* Convert reg value to real value */
+		res[i] = curr_val - 0xFF;
+	}
+}
+
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor)
+{
+	s8 noise_floor[4] = {0};
+	u64 noise_floor_eng = 0;
+
+	if (reg_noise_floor)
+		memcpy(noise_floor, reg_noise_floor, sizeof(noise_floor));
+	else
+		cl_read_reg_noise(cl_hw, noise_floor);
+
+	noise_floor[0] = abs(noise_floor[0]);
+	noise_floor[1] = abs(noise_floor[1]);
+	noise_floor[2] = abs(noise_floor[2]);
+	noise_floor[3] = abs(noise_floor[3]);
+
+	BUILD_BUG_ON(CL_EXP_TBL_SIZE > S8_MAX);
+	noise_floor_eng = (CL_EXP_10[min_t(s8, noise_floor[0], CL_EXP_TBL_SIZE - 1)] +
+			   CL_EXP_10[min_t(s8, noise_floor[1], CL_EXP_TBL_SIZE - 1)] +
+			   CL_EXP_10[min_t(s8, noise_floor[2], CL_EXP_TBL_SIZE - 1)] +
+			   CL_EXP_10[min_t(s8, noise_floor[3], CL_EXP_TBL_SIZE - 1)]);
+
+	noise_floor_eng = div64_u64(noise_floor_eng, 4);
+
+	return cl_eng_to_noise_floor(noise_floor_eng);
+}
+
+u8 cl_convert_signed_to_reg_value(s8 val)
+{
+	bool sign = val < 0;
+	u8 res = abs(val);
+
+	if (sign)
+		res |= (1 << 7);
+
+	return res;
+}
+
+static const int nl_width_to_phy_bw[] = {
+	[NL80211_CHAN_WIDTH_20_NOHT] = CHNL_BW_20,
+	[NL80211_CHAN_WIDTH_20]      = CHNL_BW_20,
+	[NL80211_CHAN_WIDTH_40]      = CHNL_BW_40,
+	[NL80211_CHAN_WIDTH_80]      = CHNL_BW_80,
+	[NL80211_CHAN_WIDTH_80P80]   = CHNL_BW_20,
+	[NL80211_CHAN_WIDTH_160]     = CHNL_BW_160,
+	[NL80211_CHAN_WIDTH_5]       = CHNL_BW_20,
+	[NL80211_CHAN_WIDTH_10]      = CHNL_BW_20,
+};
+
+u8 cl_width_to_bw(enum nl80211_chan_width width)
+{
+	if (width <= NL80211_CHAN_WIDTH_10)
+		return nl_width_to_phy_bw[width];
+
+	return CHNL_BW_20;
+}
+
+u8 cl_center_freq_offset(u8 bw)
+{
+	if (bw == CHNL_BW_160)
+		return 70;
+
+	if (bw == CHNL_BW_80)
+		return 30;
+
+	if (bw == CHNL_BW_40)
+		return 10;
+
+	return 0;
+}
+
+u8 cl_max_bw_idx(u8 wrs_mode, bool is_24g)
+{
+	if (wrs_mode < WRS_MODE_HT)
+		return CHNL_BW_20 + 1;
+
+	if (wrs_mode == WRS_MODE_HT || is_24g)
+		return CHNL_BW_40 + 1;
+
+	return CHNL_BW_MAX;
+}
+
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw)
+{
+	return (cl_hw->hw_mode == HW_MODE_B ||
+		cl_hw->hw_mode == HW_MODE_BG);
+}
+
+#define LENGTH_LLC   3
+#define LENGTH_SSNAP 5
+
+bool cl_is_eapol(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	__le16 fc = hdr->frame_control;
+	unsigned int hdrlen = 0;
+	unsigned short ethertype = 0;
+	u8 *temp = NULL;
+
+	/* Find the wireless header size */
+	hdrlen = ieee80211_has_a4(fc) ? 30 : 24;
+
+	if (ieee80211_is_data_qos(fc)) {
+		hdrlen += IEEE80211_QOS_CTL_LEN;
+
+		if (ieee80211_has_order(fc))
+			hdrlen += IEEE80211_HT_CTL_LEN;
+	}
+
+	/* Skip wireless header */
+	temp = (u8 *)(skb->data + hdrlen);
+
+	/* Skip LLC and SNAP header */
+	if (PKT_HAS_LLC_HDR(temp))
+		ethertype = cl_get_ether_type(LENGTH_LLC + LENGTH_SSNAP - 2, temp);
+
+	return ethertype == ETH_P_PAE;
+}
+
+u8 cl_ru_alloc_to_ru_type(u8 ru_alloc)
+{
+	if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_1)
+		return CL_MU_OFDMA_RU_TYPE_26;
+	else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_2)
+		return CL_MU_OFDMA_RU_TYPE_52;
+	else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_3)
+		return CL_MU_OFDMA_RU_TYPE_106;
+	else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_4)
+		return CL_MU_OFDMA_RU_TYPE_242;
+	else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_5)
+		return CL_MU_OFDMA_RU_TYPE_484;
+	else if (ru_alloc <= CL_TF_RU_ALLOC_MAX_TYPE_6)
+		return CL_MU_OFDMA_RU_TYPE_996;
+	else
+		return CL_MU_OFDMA_RU_TYPE_2x996;
+}
+
+bool cl_is_valid_g_rates(const u8 *rate_ie)
+{
+	int i, rate;
+
+	for (i = 0; i < rate_ie[1]; i++) {
+		rate = rate_ie[2 + i] & CL_SUPP_RATE_MASK;
+		switch (rate) {
+		case CL_80211G_RATE_6MB:
+		case CL_80211G_RATE_9MB:
+		case CL_80211G_RATE_12MB:
+		case CL_80211G_RATE_18MB:
+		case CL_80211G_RATE_24MB:
+		case CL_80211G_RATE_36MB:
+		case CL_80211G_RATE_48MB:
+		case CL_80211G_RATE_54MB:
+			return true;
+		}
+	}
+	return false;
+}
+
+enum cl_wireless_mode cl_recalc_wireless_mode(struct cl_hw *cl_hw,
+					      bool ieee80211n,
+					      bool ieee80211ac,
+					      bool ieee80211ax)
+{
+	enum cl_wireless_mode wireless_mode = cl_hw->wireless_mode;
+
+	if (!ieee80211n && !ieee80211ac && !ieee80211ax)
+		wireless_mode = WIRELESS_MODE_LEGACY;
+	else if (ieee80211n && (cl_band_is_24g(cl_hw) || ieee80211ac) && ieee80211ax)
+		wireless_mode = WIRELESS_MODE_HT_VHT_HE;
+	else if (ieee80211n && ieee80211ac)
+		wireless_mode =  WIRELESS_MODE_HT_VHT;
+	else if (ieee80211n)
+		wireless_mode = WIRELESS_MODE_HT;
+	else if (ieee80211ax)
+		wireless_mode = WIRELESS_MODE_HE;
+
+	return wireless_mode;
+}
+
+enum nl80211_he_ru_alloc cl_ru_type_to_nl80211_he_ru_alloc(enum cl_mu_ofdma_ru_type ru_type)
+{
+	switch (ru_type) {
+	case CL_MU_OFDMA_RU_TYPE_26:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_26;
+	case CL_MU_OFDMA_RU_TYPE_52:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_52;
+	case CL_MU_OFDMA_RU_TYPE_106:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_106;
+	case CL_MU_OFDMA_RU_TYPE_242:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_242;
+	case CL_MU_OFDMA_RU_TYPE_484:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_484;
+	case CL_MU_OFDMA_RU_TYPE_996:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_996;
+	case CL_MU_OFDMA_RU_TYPE_2x996:
+		return NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+	default:
+		return 0;
+	}
+}
+
+u8 cl_mu_ofdma_grp_convert_ru_type_to_bw(struct cl_hw *cl_hw, u8 ru_type)
+{
+	if (ru_type >= CL_MU_OFDMA_RU_TYPE_MAX) {
+		pr_err("Invalid RU type %u\n", ru_type);
+		return 0;
+	}
+
+	return cl_mu_ofdma_ru_type_to_bw_conversion[ru_type];
+}
+
+void cl_ieee802_11_parse_elems(const u8 *ies, size_t ies_len, struct ieee802_11_elems *elems)
+{
+	u8 *ie = NULL;
+
+	memset(elems, 0, sizeof(*elems));
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len);
+	if (ie) {
+		elems->ssid = (const u8 *)&ie[2];
+		elems->ssid_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
+	if (ie) {
+		elems->supp_rates = (const u8 *)&ie[2];
+		elems->supp_rates_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+	if (ie)
+		elems->ht_cap_elem = (struct ieee80211_ht_cap *)&ie[2];
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_OPERATION, ies, ies_len);
+	if (ie)
+		elems->ht_operation = (struct ieee80211_ht_operation *)&ie[2];
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
+	if (ie)
+		elems->vht_cap_elem =  (struct ieee80211_vht_cap *)&ie[2];
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_VHT_OPERATION, ies, ies_len);
+	if (ie)
+		elems->vht_operation =  (struct ieee80211_vht_operation *)&ie[2];
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len);
+	if (ie) {
+		elems->tim = (struct ieee80211_tim_ie *)&ie[2];
+		elems->tim_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ie(WLAN_EID_RSN, ies, ies_len);
+	if (ie) {
+		elems->rsn = (const u8 *)&ie[2];
+		elems->rsn_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
+	if (ie) {
+		elems->ext_supp_rates = (const u8 *)&ie[2];
+		elems->ext_supp_rates_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
+	if (ie) {
+		elems->he_cap = (const u8 *)&ie[2];
+		elems->he_cap_len = ie[1];
+	}
+
+	ie = (u8 *)cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
+	if (ie)
+		elems->he_operation = (struct ieee80211_he_operation *)&ie[2];
+}
+
+size_t cl_file_open_and_read(struct cl_chip *chip, const char *filename,
+			     char **buf)
+{
+	const struct firmware *fw;
+	size_t size = 0;
+	int ret = 0;
+	char path_name[CL_PATH_MAX] = {0};
+
+	snprintf(path_name, sizeof(path_name), "cl8k/%s", filename);
+	ret = request_firmware_direct(&fw, path_name, chip->dev);
+
+	if (ret) {
+		cl_dbg_chip_err(chip, "request_firmware_direct %s failed\n",
+				path_name);
+		return 0;
+	}
+
+	if (!fw || !fw->data) {
+		cl_dbg_chip_err(chip, "Invalid firmware %s\n", path_name);
+		goto out;
+	}
+
+	size = fw->size;
+
+	/*
+	 * Add one byte with a '\0' so that string manipulation functions
+	 * used for parsing these files can find the string '\0' terminator.
+	 * Make sure size is aligned to 4.
+	 */
+	*buf = kzalloc(ALIGN(size + 1, 4), GFP_KERNEL);
+	if (!(*buf)) {
+		size = 0;
+		goto out;
+	}
+
+	memcpy(*buf, fw->data, size);
+
+out:
+	release_firmware(fw);
+
+	return size;
+}
+
+static __be16 cl_get_eth_proto(struct sk_buff *skb)
+{
+	if (!skb->mac_header)
+		skb_reset_mac_header(skb);
+
+	if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
+		return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+	else
+		return eth_hdr(skb)->h_proto;
+}
+
+bool cl_set_network_header_if_proto(struct sk_buff *skb, u16 protocol)
+{
+	if (cl_get_eth_proto(skb) == htons(protocol)) {
+		const bool has_vlan_header = eth_hdr(skb)->h_proto == htons(ETH_P_8021Q);
+		const size_t h_offset =
+			(eth_hdr(skb) == (struct ethhdr *)(skb->data)) ? ETH_HLEN : 0;
+
+		skb_set_network_header(skb, h_offset + ((has_vlan_header) ? VLAN_HLEN : 0));
+
+		return true;
+	}
+
+	return false;
+}
+
+bool cl_is_ipv4_packet(struct sk_buff *skb)
+{
+	return cl_set_network_header_if_proto(skb, ETH_P_IP) &&
+	       (ip_hdr(skb)->ihl >= 5) &&
+	       (ip_hdr(skb)->version == IPVERSION);
+}
+
+bool cl_is_ipv6_packet(struct sk_buff *skb)
+{
+	return cl_set_network_header_if_proto(skb, ETH_P_IPV6) &&
+	       (ipv6_hdr(skb)->version == 6);
+}
+
+#define TCP_ACK_MAX_LEN 100
+
+bool cl_is_tcp_ack(struct sk_buff *skb, bool *syn_rst_push)
+{
+	if (skb->len > TCP_ACK_MAX_LEN)
+		goto out;
+
+	if (cl_is_ipv4_packet(skb)) {
+		struct iphdr *iphdr = ip_hdr(skb);
+
+		if (iphdr->protocol == IPPROTO_TCP) {
+			struct tcphdr *tcp_hdr = (struct tcphdr *)
+						 ((char *)iphdr +
+						  IPV4_HDR_LEN(iphdr->ihl));
+			u16 data_size = ntohs(iphdr->tot_len) -
+					IPV4_HDR_LEN(iphdr->ihl) -
+					(tcp_hdr->doff * 4);
+
+			*syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+			return (data_size == 0);
+		}
+	} else if (cl_is_ipv6_packet(skb)) {
+		struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
+
+		if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+			struct tcphdr *tcp_hdr = (struct tcphdr *)
+						 ((char *)ipv6hdr +
+						 sizeof(struct ipv6hdr));
+			u16 data_size = ntohs(ipv6hdr->payload_len) -
+					(tcp_hdr->doff * 4);
+
+			*syn_rst_push = tcp_hdr->syn || tcp_hdr->rst || tcp_hdr->psh;
+
+			return (data_size == 0);
+		}
+	}
+
+out:
+	*syn_rst_push = false;
+	return false;
+}
+
+bool cl_band_is_6g(struct cl_hw *cl_hw)
+{
+	return (cl_hw->conf->ci_band_num == 6);
+}
+
+bool cl_band_is_5g(struct cl_hw *cl_hw)
+{
+	return (cl_hw->conf->ci_band_num == 5);
+}
+
+bool cl_band_is_24g(struct cl_hw *cl_hw)
+{
+	return (cl_hw->conf->ci_band_num == 24);
+}
+
+u8 cl_band_to_fw_idx(struct cl_hw *cl_hw)
+{
+	if (cl_hw->nl_band == NL80211_BAND_6GHZ)
+		return FW_BAND_6GHZ;
+
+	if (cl_hw->nl_band == NL80211_BAND_5GHZ)
+		return FW_BAND_5GHZ;
+
+	return FW_BAND_2GHZ;
+}
+
+static u8 fw_to_nl_band[FW_BAND_MAX] = {
+	[FW_BAND_6GHZ] = NL80211_BAND_6GHZ,
+	[FW_BAND_5GHZ] = NL80211_BAND_5GHZ,
+	[FW_BAND_2GHZ] = NL80211_BAND_2GHZ,
+};
+
+u8 cl_band_from_fw_idx(u32 phy_band)
+{
+	if (phy_band < FW_BAND_MAX)
+		return fw_to_nl_band[phy_band];
+
+	return FW_BAND_MAX;
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 87/96] cl8k: add utils.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (85 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 86/96] cl8k: add utils.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 88/96] cl8k: add version.c viktor.barna
                   ` (8 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/utils.h | 185 +++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils.h

diff --git a/drivers/net/wireless/celeno/cl8k/utils.h b/drivers/net/wireless/celeno/cl8k/utils.h
new file mode 100644
index 000000000000..052687183dd3
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils.h
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_UTILS_H
+#define CL_UTILS_H
+
+#include "def.h"
+#include "ieee80211_i.h"
+#include "chip.h"
+
+/*
+ * GI_LTF field for common info
+ * 0 - 1x HE-LTF + 1.6 us GI
+ * 1 - 2x HE-LTF + 1.6 us GI
+ * 2 - 4x HE-LTF + 3.2 us GI
+ */
+enum cl_he_ltf_gi {
+	HE_LTF_X1_GI_16, /* Not supported */
+	HE_LTF_X2_GI_16,
+	HE_LTF_X4_GI_32,
+
+	HE_LTF_MAX
+};
+
+#define CL_TF_GI_LTF_TO_GI(gi_ltf) \
+	((gi_ltf) == HE_LTF_X4_GI_32 ? WRS_GI_LONG : \
+	 ((gi_ltf) == HE_LTF_X2_GI_16 ? WRS_GI_SHORT : \
+	   ((gi_ltf) == HE_LTF_X1_GI_16 ? WRS_GI_SHORT : WRS_GI_LONG)))
+
+#define CL_TF_GI_TO_GI_LTF(gi) \
+	((gi) == WRS_GI_LONG ? HE_LTF_X4_GI_32 : \
+	 ((gi) == WRS_GI_SHORT ? HE_LTF_X2_GI_16 : \
+	   ((gi) == WRS_GI_VSHORT ? HE_LTF_X2_GI_16 : HE_LTF_X4_GI_32)))
+
+#define CL_TF_RU_ALLOC_MAX_TYPE_1 36
+#define CL_TF_RU_ALLOC_MAX_TYPE_2 52
+#define CL_TF_RU_ALLOC_MAX_TYPE_3 60
+#define CL_TF_RU_ALLOC_MAX_TYPE_4 64
+#define CL_TF_RU_ALLOC_MAX_TYPE_5 66
+#define CL_TF_RU_ALLOC_MAX_TYPE_6 67
+#define CL_TF_RU_ALLOC_MAX_TYPE_7 68
+
+/*
+ *IEEE80211 G Rate provided by Hostapd in WLAN_EID_SUPP_RATES EID
+ *EID Rate = ieee802Rate/5
+ */
+#define CL_80211G_RATE_6MB     12
+#define CL_80211G_RATE_9MB     18
+#define CL_80211G_RATE_12MB     24
+#define CL_80211G_RATE_18MB     36
+#define CL_80211G_RATE_24MB     48
+#define CL_80211G_RATE_36MB     72
+#define CL_80211G_RATE_48MB     96
+#define CL_80211G_RATE_54MB     108
+
+#define CL_SUPP_RATE_MASK     0x7F
+
+#define BAND_IS_5G_6G(cl_hw) \
+		(cl_band_is_5g(cl_hw) || cl_band_is_6g(cl_hw))
+
+static const u8 tid_to_ac[] = {
+	AC_BE, AC_BK, AC_BK, AC_BE, AC_VI, AC_VI, AC_VO, AC_VO
+};
+
+static inline u16 cl_adc_to_mv(u16 adc)
+{
+	return (adc * 1800) >> 12;
+}
+
+static inline struct ieee80211_vif *NETDEV_TO_VIF(struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (!wdev)
+		return NULL;
+
+	return wdev_to_ieee80211_vif(wdev);
+}
+
+static inline struct cl_hw *NETDEV_TO_CL_HW(struct net_device *dev)
+{
+	struct ieee80211_hw *hw = wdev_priv(dev->ieee80211_ptr);
+
+	return hw->priv;
+}
+
+static inline struct cl_vif *NETDEV_TO_CL_VIF(struct net_device *dev)
+{
+	struct ieee80211_vif *vif = NETDEV_TO_VIF(dev);
+
+	WARN_ON(!vif);
+
+	if (unlikely(vif->type == NL80211_IFTYPE_AP_VLAN)) {
+		struct cl_hw *cl_hw = NETDEV_TO_CL_HW(dev);
+
+		return cl_vif_get_by_dev(cl_hw, dev);
+	}
+
+	return (struct cl_vif *)vif->drv_priv;
+}
+
+static inline struct cl_vif *TX_INFO_TO_CL_VIF(struct cl_hw *cl_hw,
+					       struct ieee80211_tx_info *tx_info)
+{
+	struct ieee80211_vif *vif = tx_info->control.vif;
+
+	WARN_ON(!vif);
+
+	if (unlikely(vif->type == NL80211_IFTYPE_AP_VLAN))
+		return cl_vif_get_by_mac(cl_hw, vif->addr);
+
+	return (struct cl_vif *)(vif->drv_priv);
+}
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte);
+u8 cl_convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi);
+u8 cl_convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi);
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi);
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor);
+u8 cl_convert_signed_to_reg_value(s8 val);
+u8 cl_width_to_bw(enum nl80211_chan_width width);
+u8 cl_center_freq_offset(u8 bw);
+u8 cl_max_bw_idx(u8 wrs_mode, bool is_24g);
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw);
+bool cl_is_eapol(struct sk_buff *skb);
+u8 cl_ru_alloc_to_ru_type(u8 ru_alloc);
+bool cl_is_valid_g_rates(const u8 *rate_ie);
+enum cl_wireless_mode cl_recalc_wireless_mode(struct cl_hw *cl_hw,
+					      bool ieee80211n,
+					      bool ieee80211ac,
+					      bool ieee80211ax);
+
+enum cl_mu_ofdma_ru_type {
+	CL_MU_OFDMA_RU_TYPE_NONE = 0,
+	CL_MU_OFDMA_RU_TYPE_26,    /* 2.5MHz */
+	CL_MU_OFDMA_RU_TYPE_52,    /* 5MHz */
+	CL_MU_OFDMA_RU_TYPE_106,   /* 10MHz */
+	CL_MU_OFDMA_RU_TYPE_242,   /* 20MHz */
+	CL_MU_OFDMA_RU_TYPE_484,   /* 40MHz */
+	CL_MU_OFDMA_RU_TYPE_996,   /* 80MHz */
+	CL_MU_OFDMA_RU_TYPE_2x996, /* 160MHz */
+	CL_MU_OFDMA_RU_TYPE_MAX
+};
+
+enum nl80211_he_ru_alloc cl_ru_type_to_nl80211_he_ru_alloc(enum cl_mu_ofdma_ru_type ru_type);
+u8 cl_mu_ofdma_grp_convert_ru_type_to_bw(struct cl_hw *cl_hw, u8 ru_type);
+void cl_ieee802_11_parse_elems(const u8 *ies, size_t ies_len, struct ieee802_11_elems *elems);
+
+/*
+ * cl_file_open_and_read - Read the whole file into an allocated buffer.
+ *
+ * Allocates a buffer large enough to hold the contents of file at @filename and reads the
+ * contents of that file into that buffer. Upon success, the address of the allocated buffer
+ * is returned (which needs to be free later). Upon failure, returns NULL.
+ */
+size_t cl_file_open_and_read(struct cl_chip *chip, const char *filename,
+			     char **buf);
+
+/* Traffic analysis */
+/* Check if a packet has specific LLC fields e.g. DSAP, SSAP and Control */
+#define PKT_HAS_LLC_HDR(a) ((a[0] == 0xAA) && (a[1] == 0xAA) && (a[2] == 0x03))
+
+/* Multiply by 4 because IHL is number of 32-bit words */
+#define IPV4_HDR_LEN(ihl) ((ihl) << 2)
+
+bool cl_set_network_header_if_proto(struct sk_buff *skb, u16 protocol);
+bool cl_is_ipv4_packet(struct sk_buff *skb);
+bool cl_is_ipv6_packet(struct sk_buff *skb);
+bool cl_is_tcp_ack(struct sk_buff *skb, bool *syn_rst_push);
+
+/* Band helpers */
+bool cl_band_is_6g(struct cl_hw *cl_hw);
+bool cl_band_is_5g(struct cl_hw *cl_hw);
+bool cl_band_is_24g(struct cl_hw *cl_hw);
+u8 cl_band_to_fw_idx(struct cl_hw *cl_hw);
+u8 cl_band_from_fw_idx(u32 phy_band);
+
+static inline unsigned short cl_get_ether_type(int offset, unsigned char *src_buf)
+{
+	unsigned short type_len = *(unsigned short *)(src_buf + offset);
+
+	return (unsigned short)be16_to_cpu(htons(type_len));
+}
+
+#endif /* CL_UTILS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 88/96] cl8k: add version.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (86 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 87/96] cl8k: add utils.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 89/96] cl8k: add version.h viktor.barna
                   ` (7 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/version.c | 147 +++++++++++++++++++++
 1 file changed, 147 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.c

diff --git a/drivers/net/wireless/celeno/cl8k/version.c b/drivers/net/wireless/celeno/cl8k/version.c
new file mode 100644
index 000000000000..1965190a833a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/version.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "debug.h"
+#include "chip.h"
+#include "rfic.h"
+#include "debug.h"
+#include "version.h"
+
+static int cl_version_request(struct cl_hw *cl_hw)
+{
+	struct mm_version_cfm *cfm = NULL;
+	struct cl_version_db *vd = &cl_hw->version_db;
+	int ret = 0;
+
+	ret = cl_msg_tx_version(cl_hw);
+	if (ret)
+		return ret;
+
+	cfm = (struct mm_version_cfm *)cl_hw->msg_cfm_params[MM_VERSION_CFM];
+	if (!cfm)
+		return -ENOMSG;
+
+	vd->last_update = jiffies;
+	vd->dsp = le32_to_cpu(cfm->versions.dsp);
+	vd->rfic_sw = le32_to_cpu(cfm->versions.rfic_sw);
+	vd->rfic_hw = le32_to_cpu(cfm->versions.rfic_hw);
+	vd->agcram = le32_to_cpu(cfm->versions.agcram);
+
+	cl_hw->rf_crystal_mhz = cfm->rf_crystal_mhz;
+
+	strncpy(vd->fw, cfm->versions.fw, sizeof(vd->fw));
+	vd->fw[sizeof(vd->fw) - 1] = '\0';
+
+	strncpy(vd->drv, CONFIG_CL8K_VERSION, sizeof(vd->drv));
+	vd->drv[sizeof(vd->drv) - 1] = '\0';
+
+	cl_msg_tx_free_cfm_params(cl_hw, MM_VERSION_CFM);
+
+	return ret;
+}
+
+int cl_version_read(struct cl_hw *cl_hw, char *buf, ssize_t buf_size, ssize_t *total_len)
+{
+	struct cl_chip *chip = cl_hw->chip;
+	struct cl_version_db *vd = &cl_hw->version_db;
+	struct cl_agc_profile *agc_profile1 = &cl_hw->phy_data_info.data->agc_params.profile1;
+	struct cl_agc_profile *agc_profile2 = &cl_hw->phy_data_info.data->agc_params.profile2;
+	ssize_t len = 0;
+	int ret = 0;
+	u32 version_agcram = 0;
+	u32 major = 0;
+	u32 minor = 0;
+	u32 internal = 0;
+
+	/* Request data if existing is not actual */
+	if (!vd->last_update) {
+		ret = cl_version_request(cl_hw);
+		if (ret)
+			return ret;
+	}
+
+	/* PHY components specifics */
+	len += scnprintf(buf + len, buf_size - len, "DRV VERSION: %s\n", vd->drv);
+	len += scnprintf(buf + len, buf_size - len, "FW VERSION: %s\n", vd->fw);
+	len += scnprintf(buf + len, buf_size - len, "DSP VERSION: 0x%-.8X\n", vd->dsp);
+	len += scnprintf(buf + len, buf_size - len, "RFIC SW VERSION: %u\n", vd->rfic_sw);
+	len += scnprintf(buf + len, buf_size - len, "RFIC HW VERSION: 0x%X\n", vd->rfic_hw);
+
+	version_agcram = vd->agcram;
+	major = (version_agcram >> 16) & 0xffff;
+	minor = (version_agcram >> 8) & 0xff;
+	internal = version_agcram & 0xff;
+
+	len += scnprintf(buf + len, buf_size - len,
+			 "AGC RAM VERSION: B.%x.%x.%x\n", major, minor, internal);
+
+	if (agc_profile1)
+		cl_agc_params_dump_profile_id(buf, buf_size, &len, agc_profile1->id,
+					      "AGC PARAMS PROFILE:");
+	if (agc_profile2)
+		cl_agc_params_dump_profile_id(buf, buf_size, &len, agc_profile2->id,
+					      "AGC PARAMS PROFILE (Elastic):");
+
+	len += scnprintf(buf + len, buf_size - len,
+			 "TX POWER VERSION: %u\n", cl_hw->tx_power_version);
+
+	switch (chip->conf->ci_phy_dev) {
+	case PHY_DEV_OLYMPUS:
+		len += scnprintf(buf + len, buf_size - len, "RFIC TYPE: OLYMPUS\n");
+		break;
+	case PHY_DEV_ATHOS:
+		len += scnprintf(buf + len, buf_size - len, "RFIC TYPE: %s\n",
+				 (cl_hw->chip->rfic_version == ATHOS_A_VER) ? "ATHOS" : "ATHOS B");
+		break;
+	case PHY_DEV_DUMMY:
+		len += scnprintf(buf + len, buf_size - len, "RFIC TYPE: DUMMY\n");
+		break;
+	case PHY_DEV_FRU:
+		len += scnprintf(buf + len, buf_size - len, "RFIC TYPE: FRU\n");
+		break;
+	case PHY_DEV_LOOPBACK:
+		len += scnprintf(buf + len, buf_size - len, "RFIC TYPE: LOOPBACK\n");
+		break;
+	}
+
+	len += scnprintf(buf + len, buf_size - len,
+			 "RF CRYSTAL: %uMHz\n", cl_hw->rf_crystal_mhz);
+	len += scnprintf(buf + len, buf_size - len,
+			 "CHIP ID: 0X%x\n", cl_chip_get_device_id(cl_hw->chip));
+	*total_len = len;
+
+	return 0;
+}
+
+int cl_version_update(struct cl_hw *cl_hw)
+{
+	char *buf = NULL;
+	ssize_t buf_size = PAGE_SIZE;
+	ssize_t len = 0;
+	int ret = 0;
+
+	buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* Force logic to update versions */
+	cl_hw->version_db.last_update = 0;
+
+	ret = cl_version_read(cl_hw, buf, buf_size, &len);
+
+	if (ret == 0) {
+		pr_debug("%s\n", buf);
+		/* Share version info */
+		cl_version_sync_wiphy(cl_hw, cl_hw->hw->wiphy);
+	}
+
+	kfree(buf);
+
+	return ret;
+}
+
+void cl_version_sync_wiphy(struct cl_hw *cl_hw, struct wiphy *wiphy)
+{
+	strncpy(wiphy->fw_version, cl_hw->version_db.fw, sizeof(wiphy->fw_version));
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 89/96] cl8k: add version.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (87 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 88/96] cl8k: add version.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 90/96] cl8k: add vif.c viktor.barna
                   ` (6 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/version.h | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/version.h

diff --git a/drivers/net/wireless/celeno/cl8k/version.h b/drivers/net/wireless/celeno/cl8k/version.h
new file mode 100644
index 000000000000..bc6d2ad4153a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/version.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_VERSION_H
+#define CL_VERSION_H
+
+#include "ipc_shared.h"
+
+struct cl_version_db {
+	u32 dsp;
+	u32 rfic_sw;
+	u32 rfic_hw;
+	u32 agcram;
+	char fw[CL_VERSION_STR_SIZE];
+	char drv[CL_VERSION_STR_SIZE];
+	unsigned long last_update;
+};
+
+int cl_version_read(struct cl_hw *cl_hw, char *buf, ssize_t buf_size, ssize_t *total_len);
+int cl_version_update(struct cl_hw *cl_hw);
+void cl_version_sync_wiphy(struct cl_hw *cl_hw, struct wiphy *wiphy);
+
+#endif /* CL_VERSION_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 90/96] cl8k: add vif.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (88 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 89/96] cl8k: add version.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 91/96] cl8k: add vif.h viktor.barna
                   ` (5 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vif.c | 162 +++++++++++++++++++++++++
 1 file changed, 162 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.c

diff --git a/drivers/net/wireless/celeno/cl8k/vif.c b/drivers/net/wireless/celeno/cl8k/vif.c
new file mode 100644
index 000000000000..7592f0d32e7a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vif.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/list.h>
+
+#include "hw.h"
+#include "mac_addr.h"
+#include "vif.h"
+
+void cl_vif_init(struct cl_hw *cl_hw)
+{
+	rwlock_init(&cl_hw->vif_db.lock);
+	INIT_LIST_HEAD(&cl_hw->vif_db.head);
+}
+
+void cl_vif_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	struct cl_vif_db *vif_db = &cl_hw->vif_db;
+
+	write_lock_bh(&vif_db->lock);
+	list_add_tail(&cl_vif->list, &vif_db->head);
+
+	if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+		vif_db->num_iface_bcn++;
+
+	/* Multicast vif set */
+	cl_hw->mc_vif = cl_vif;
+
+	write_unlock_bh(&vif_db->lock);
+}
+
+void cl_vif_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	struct cl_vif_db *vif_db = &cl_hw->vif_db;
+
+	write_lock_bh(&vif_db->lock);
+	/* Multicast vif unset */
+	if (cl_hw->mc_vif == cl_vif)
+		cl_hw->mc_vif = cl_vif_get_next(cl_hw, cl_hw->mc_vif);
+
+	list_del(&cl_vif->list);
+
+	if (cl_vif->vif->type != NL80211_IFTYPE_STATION)
+		vif_db->num_iface_bcn--;
+	write_unlock_bh(&vif_db->lock);
+
+	cl_bcmc_cfm_poll_empty_per_vif(cl_hw, cl_vif);
+}
+
+struct cl_vif *cl_vif_get_next(struct cl_hw *cl_hw, struct cl_vif *cl_vif)
+{
+	if (list_is_last(&cl_vif->list, &cl_hw->vif_db.head))
+		return list_first_entry_or_null(&cl_hw->vif_db.head,
+						struct cl_vif, list);
+	else
+		return list_next_entry(cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_by_dev(struct cl_hw *cl_hw, struct net_device *dev)
+{
+	struct cl_vif *cl_vif = NULL, *cl_vif_ret = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->dev == dev) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct cl_vif *cl_vif_get_by_mac(struct cl_hw *cl_hw, u8 *mac_addr)
+{
+	struct cl_vif *cl_vif, *cl_vif_ret = NULL;
+
+	read_lock(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_mac_addr_compare(cl_vif->vif->addr, mac_addr)) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct cl_vif *cl_vif_get_first(struct cl_hw *cl_hw)
+{
+	return list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+}
+
+struct cl_vif *cl_vif_get_first_ap(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif, *cl_vif_ret = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->vif->type == NL80211_IFTYPE_AP ||
+		    cl_vif->vif->type == NL80211_IFTYPE_MESH_POINT ||
+		    cl_hw->conf->ce_listener_en) {
+			cl_vif_ret = cl_vif;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return cl_vif_ret;
+}
+
+struct net_device *cl_vif_get_first_net_device(struct cl_hw *cl_hw)
+{
+	struct cl_vif *cl_vif = NULL;
+	struct net_device *dev = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	cl_vif = list_first_entry_or_null(&cl_hw->vif_db.head, struct cl_vif, list);
+	if (cl_vif)
+		dev = cl_vif->dev;
+	read_unlock_bh(&cl_hw->vif_db.lock);
+
+	return dev;
+}
+
+struct net_device *cl_vif_get_dev_by_index(struct cl_hw *cl_hw, u8 index)
+{
+	struct cl_vif *cl_vif = NULL;
+	struct net_device *dev = NULL;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list)
+		if (cl_vif->vif_index == index) {
+			dev = cl_vif->dev;
+			goto unlock;
+		}
+
+unlock:
+	read_unlock_bh(&cl_hw->vif_db.lock);
+	return dev;
+}
+
+void cl_vif_ap_tx_enable(struct cl_hw *cl_hw, bool enable)
+{
+	struct cl_vif *cl_vif;
+	struct ieee80211_vif *vif;
+
+	read_lock_bh(&cl_hw->vif_db.lock);
+	list_for_each_entry(cl_vif, &cl_hw->vif_db.head, list) {
+		vif = cl_vif->vif;
+
+		if (vif->type != NL80211_IFTYPE_AP)
+			continue;
+
+		cl_vif->tx_en = enable;
+		cl_dbg_verbose(cl_hw, "Set tx_en=%u for vif_index=%u\n",
+			       enable, cl_vif->vif_index);
+	}
+	read_unlock_bh(&cl_hw->vif_db.lock);
+}
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 91/96] cl8k: add vif.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (89 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 90/96] cl8k: add vif.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 92/96] cl8k: add vns.c viktor.barna
                   ` (4 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vif.h | 81 ++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vif.h

diff --git a/drivers/net/wireless/celeno/cl8k/vif.h b/drivers/net/wireless/celeno/cl8k/vif.h
new file mode 100644
index 000000000000..2563c6c3222d
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vif.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_VIF_H
+#define CL_VIF_H
+
+#include <linux/netdevice.h>
+
+#include "wrs.h"
+
+struct cl_connection_data {
+	u32 max_client;            /* MAX Clients of the SSID */
+	u32 max_client_timestamp;  /* MAX Clients Timestamp of the SSID */
+	u32 watermark_threshold;   /* Number of clients threshold for watermark */
+	u32 watermark_reached_cnt; /* Number of times the watermark threshold was reached */
+};
+
+struct cl_traffic_counters {
+	u64 tx_packets;
+	u64 tx_bytes;
+	u64 rx_packets;
+	u64 rx_bytes;
+	u32 tx_errors;
+	u32 rx_errors;
+	u32 tx_dropped;
+	u32 rx_dropped;
+};
+
+/*
+ * Structure used to save information relative to the managed interfaces.
+ * Will be used as the 'drv_priv' field of the "struct ieee80211_vif" structure.
+ * This is also linked within the cl_hw vifs list.
+ */
+struct cl_vif {
+	struct list_head list;
+	struct cl_hw *cl_hw;
+	struct ieee80211_vif *vif;
+	struct net_device *dev;
+	struct list_head key_list_head;
+	struct cl_key_conf *key;
+	int key_idx_default;
+	u32 unicast_tx;
+	u32 unicast_rx;
+	u32 multicast_tx;
+	u32 multicast_rx;
+	u32 broadcast_tx;
+	u32 broadcast_rx;
+	u16 sequence_number;
+	u8 num_sta; /* Number of station connected per SSID */
+	struct cl_connection_data *conn_data;
+	u8 vif_index;
+	bool tx_en;
+	/* Holds info for channel utilization stats */
+	u32 chan_util_last_tx_bytes;
+	u32 chan_util;
+	struct mcast_table *mcast_table;
+	struct cl_wrs_rate_params fixed_params;
+	struct cl_traffic_counters trfc_cntrs[AC_MAX];
+	bool wmm_enabled;
+	u16 mesh_basic_rates;
+};
+
+struct cl_vif_db {
+	struct list_head head;
+	rwlock_t lock;
+	u8 num_iface_bcn;
+};
+
+void cl_vif_init(struct cl_hw *cl_hw);
+void cl_vif_add(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+void cl_vif_remove(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+struct cl_vif *cl_vif_get_next(struct cl_hw *cl_hw, struct cl_vif *cl_vif);
+struct cl_vif *cl_vif_get_by_dev(struct cl_hw *cl_hw, struct net_device *dev);
+struct cl_vif *cl_vif_get_by_mac(struct cl_hw *cl_hw, u8 *mac_addr);
+struct cl_vif *cl_vif_get_first(struct cl_hw *cl_hw);
+struct cl_vif *cl_vif_get_first_ap(struct cl_hw *cl_hw);
+struct net_device *cl_vif_get_first_net_device(struct cl_hw *cl_hw);
+struct net_device *cl_vif_get_dev_by_index(struct cl_hw *cl_hw, u8 index);
+void cl_vif_ap_tx_enable(struct cl_hw *cl_hw, bool enable);
+
+#endif /* CL_VIF_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 92/96] cl8k: add vns.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (90 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 91/96] cl8k: add vif.h viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:34 ` [RFC v2 93/96] cl8k: add vns.h viktor.barna
                   ` (3 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vns.c | 354 +++++++++++++++++++++++++
 1 file changed, 354 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.c

diff --git a/drivers/net/wireless/celeno/cl8k/vns.c b/drivers/net/wireless/celeno/cl8k/vns.c
new file mode 100644
index 000000000000..6f79b36d0a5c
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vns.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include "maintenance.h"
+#include "mac_addr.h"
+#include "debug.h"
+#include "vns.h"
+
+#define CL_VNS_HASH_IDX    (ETH_ALEN - 2)
+#define CL_VNS_MGMT_AGEOUT 200
+
+#define vns_pr(...) \
+	do { \
+		if (unlikely(cl_hw->vns_db->dbg)) \
+			pr_debug("[VNS]" __VA_ARGS__); \
+	} while (0)
+
+#define vns_pr_pkt(...) \
+	do { \
+		if (unlikely(cl_hw->vns_db->dbg_per_packet)) \
+			pr_debug("[VNS-pkt]" __VA_ARGS__); \
+	} while (0)
+
+static void cl_vns_mgmt_list_add(struct cl_hw *cl_hw, u8 *addr, s8 strongset_rssi)
+{
+	/* Add entry to mgmt list */
+	struct cl_vns_rssi_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+
+	if (!entry)
+		return;
+
+	/* Fill entry parameters */
+	INIT_LIST_HEAD(&entry->list_all);
+	INIT_LIST_HEAD(&entry->list_addr);
+	cl_mac_addr_copy(entry->addr, addr);
+	entry->strongset_rssi = strongset_rssi;
+	entry->timestamp = jiffies;
+
+	/* Add to list */
+	cl_hw->vns_db->mgmt_db.num_entries++;
+	list_add(&entry->list_all, &cl_hw->vns_db->mgmt_db.list_all);
+	list_add(&entry->list_addr, &cl_hw->vns_db->mgmt_db.list_addr[addr[CL_VNS_HASH_IDX]]);
+}
+
+static void cl_vns_mgmt_list_remove(struct cl_hw *cl_hw, struct cl_vns_rssi_entry *entry)
+{
+	/* Remove entry from mgmt list */
+	cl_hw->vns_db->mgmt_db.num_entries--;
+	list_del(&entry->list_all);
+	list_del(&entry->list_addr);
+	kfree(entry);
+}
+
+static void cl_vns_mgmt_list_flush(struct cl_hw *cl_hw)
+{
+	/* Flush all mgmt list */
+	if (cl_hw->vns_db->mgmt_db.num_entries > 0) {
+		struct cl_vns_rssi_entry *entry = NULL, *tmp = NULL;
+
+		list_for_each_entry_safe(entry, tmp, &cl_hw->vns_db->mgmt_db.list_all, list_all)
+			cl_vns_mgmt_list_remove(cl_hw, entry);
+	}
+}
+
+static struct cl_vns_rssi_entry *cl_vns_mgmt_list_find(struct cl_hw *cl_hw, u8 *addr)
+{
+	/* Search for entry in mgmt list */
+	struct cl_vns_mgmt_db *mgmt_db = &cl_hw->vns_db->mgmt_db;
+
+	if (mgmt_db->num_entries > 0) {
+		struct cl_vns_rssi_entry *entry = NULL;
+
+		list_for_each_entry(entry, &mgmt_db->list_addr[addr[CL_VNS_HASH_IDX]], list_addr)
+			if (ether_addr_equal(entry->addr, addr))
+				return entry;
+	}
+
+	return NULL;
+}
+
+static bool cl_vns_mgmt_list_find_and_remove(struct cl_hw *cl_hw, u8 *addr)
+{
+	/*
+	 * Search for entry in mgmt list
+	 * If entry found remove it and return true
+	 */
+	struct cl_vns_rssi_entry *entry = cl_vns_mgmt_list_find(cl_hw, addr);
+
+	if (entry) {
+		cl_vns_mgmt_list_remove(cl_hw, entry);
+		return true;
+	}
+
+	return false;
+}
+
+static void cl_vns_mgmt_list_ageout(struct cl_hw *cl_hw)
+{
+	/* Remove old entries from mgmt list */
+	struct cl_vns_mgmt_db *mgmt_db = &cl_hw->vns_db->mgmt_db;
+
+	if (mgmt_db->num_entries > 0) {
+		struct cl_vns_rssi_entry *entry = NULL, *tmp = NULL;
+		unsigned long delta_time;
+
+		list_for_each_entry_safe(entry, tmp, &mgmt_db->list_all, list_all) {
+			delta_time = jiffies_to_msecs(jiffies - entry->timestamp);
+
+			if (delta_time > CL_VNS_MGMT_AGEOUT) {
+				vns_pr("sta %pM removed from list because of ageout\n",
+				       entry->addr);
+				cl_vns_mgmt_list_remove(cl_hw, entry);
+			}
+		}
+	}
+}
+
+static s8 cl_vns_get_strongest_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_vns_sta_db *vns_db = &cl_sta->vns_db;
+	s32 rssi_samples = vns_db->rssi_samples;
+
+	if (rssi_samples > 0) {
+		u8 i;
+		s32 strongest_rssi = S32_MIN;
+
+		for (i = 0; i < cl_hw->num_antennas; i++)
+			if (vns_db->rssi_sum[i] > strongest_rssi)
+				strongest_rssi = vns_db->rssi_sum[i];
+
+		/* Reset rssi for next time that cl_vns_get_strongest_rssi() will be called */
+		memset(vns_db->rssi_sum, 0, sizeof(vns_db->rssi_sum));
+		vns_db->rssi_samples = 0;
+
+		return (s8)(strongest_rssi / rssi_samples);
+	}
+
+	return 0;
+}
+
+static void cl_vns_monitor_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	/* Monitor RSSI of associated stations and update state if necessary */
+	struct cl_vns_sta_db *vns_db = &cl_sta->vns_db;
+	s8 strongset_rssi = cl_vns_get_strongest_rssi(cl_hw, cl_sta);
+	s8 rssi_thr = 0;
+	bool is_vns = false;
+
+	if (strongset_rssi == 0)
+		return;
+
+	/*
+	 * Calculate RSSI threshold (take hystersis into
+	 *  consideration according to current state)
+	 */
+	if (vns_db->is_very_near)
+		rssi_thr = cl_hw->conf->ci_vns_rssi_thr - cl_hw->conf->ci_vns_rssi_hys;
+	else
+		rssi_thr = cl_hw->conf->ci_vns_rssi_thr + cl_hw->conf->ci_vns_rssi_hys;
+
+	is_vns = strongset_rssi > rssi_thr;
+	/* Avoid toggling of VNS state - require two consecutive same decisions */
+	if (is_vns != vns_db->prev_decision) {
+		vns_db->prev_decision = is_vns;
+		return;
+	}
+
+	if (is_vns != vns_db->is_very_near) {
+		vns_pr("sta %pM changed state, strongset_rssi = %d, is_vns = %s\n",
+		       cl_sta->addr, strongset_rssi, is_vns ? "TRUE" : "FALSE");
+		vns_db->is_very_near = is_vns;
+		cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, is_vns);
+	}
+}
+
+static void cl_vns_recovery_sta(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	if (cl_sta->vns_db.is_very_near)
+		cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, true);
+}
+
+int cl_vns_init(struct cl_hw *cl_hw)
+{
+	int i = 0;
+	u8 vns_pwr_mode = cl_hw->conf->ci_vns_pwr_mode;
+
+	cl_hw->vns_db = vzalloc(sizeof(*cl_hw->vns_db));
+	if (!cl_hw->vns_db)
+		return -ENOMEM;
+
+	if (vns_pwr_mode == VNS_MODE_DATA || vns_pwr_mode == VNS_MODE_ALL)
+		cl_hw->vns_db->enable = true;
+
+	spin_lock_init(&cl_hw->vns_db->lock);
+
+	INIT_LIST_HEAD(&cl_hw->vns_db->mgmt_db.list_all);
+
+	for (i = 0; i < STA_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&cl_hw->vns_db->mgmt_db.list_addr[i]);
+
+	return 0;
+}
+
+void cl_vns_close(struct cl_hw *cl_hw)
+{
+	if (cl_hw->vns_db->enable) {
+		spin_lock_bh(&cl_hw->vns_db->lock);
+		cl_vns_mgmt_list_flush(cl_hw);
+		spin_unlock_bh(&cl_hw->vns_db->lock);
+
+		cl_hw->vns_db->enable = false;
+	}
+
+	vfree(cl_hw->vns_db);
+	cl_hw->vns_db = NULL;
+}
+
+void cl_vns_maintenance(struct cl_hw *cl_hw)
+{
+	/*
+	 * Maintenance:
+	 * 1) Remove old entries from mgmt list
+	 * 2) Update state for associated clients
+	 */
+	if (!cl_hw->vns_db || !cl_hw->vns_db->enable)
+		return;
+
+	cl_hw->vns_db->interval_period += CL_MAINTENANCE_PERIOD_SLOW_MS;
+
+	if (cl_hw->vns_db->interval_period < cl_hw->conf->ci_vns_maintenance_time)
+		return;
+
+	cl_hw->vns_db->interval_period = 0;
+
+	spin_lock_bh(&cl_hw->vns_db->lock);
+	cl_vns_mgmt_list_ageout(cl_hw);
+	spin_unlock_bh(&cl_hw->vns_db->lock);
+
+	/* Check RSSI of associated stations */
+	cl_sta_loop(cl_hw, cl_vns_monitor_rssi);
+}
+
+void cl_vns_mgmt_handler(struct cl_hw *cl_hw, u8 *addr, s8 rssi[MAX_ANTENNAS])
+{
+	/*
+	 * Handle management frames of non-associated stations,
+	 * and save the very-near ones in the mgmt list
+	 */
+	s8 strongset_rssi = 0;
+	struct cl_vns_rssi_entry *entry = NULL;
+
+	if (!cl_hw->vns_db->enable)
+		return;
+
+	strongset_rssi = cl_rssi_get_strongest(cl_hw, rssi);
+
+	spin_lock_bh(&cl_hw->vns_db->lock);
+
+	entry = cl_vns_mgmt_list_find(cl_hw, addr);
+
+	if (entry) {
+		if (strongset_rssi > cl_hw->conf->ci_vns_rssi_thr) {
+			/* Update exisiting entry */
+			entry->strongset_rssi = strongset_rssi;
+			entry->timestamp = jiffies;
+			vns_pr("sta %pM updated in list (rssi=%d)\n",
+			       addr, strongset_rssi);
+		} else {
+			/* Remove exisiting entry */
+			cl_vns_mgmt_list_remove(cl_hw, entry);
+			vns_pr("sta %pM removed from list (rssi=%d)\n",
+			       addr, strongset_rssi);
+		}
+	} else {
+		if (strongset_rssi > cl_hw->conf->ci_vns_rssi_thr) {
+			/* Add new entry */
+			cl_vns_mgmt_list_add(cl_hw, addr, strongset_rssi);
+			vns_pr("sta %pM added to list (rssi=%d)\n",
+			       addr, strongset_rssi);
+		}
+	}
+
+	spin_unlock_bh(&cl_hw->vns_db->lock);
+}
+
+bool cl_vns_is_very_near(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
+{
+	bool is_vns = false;
+	/* This function checks for every TX packet whether it's VNS or not */
+	if (!cl_hw->vns_db->enable)
+		return false;
+
+	if (unlikely(!cl_sta)) {
+		struct ieee80211_hdr *mac_hdr = (struct ieee80211_hdr *)skb->data;
+
+		spin_lock_bh(&cl_hw->vns_db->lock);
+		is_vns = cl_vns_mgmt_list_find(cl_hw, mac_hdr->addr1);
+		spin_unlock_bh(&cl_hw->vns_db->lock);
+
+		vns_pr_pkt("mgmt-sta %pM, is_vns = %s\n",
+			   mac_hdr->addr1, is_vns ? "TRUE" : "FALSE");
+
+		return is_vns;
+	}
+	is_vns = cl_sta->vns_db.is_very_near;
+
+	vns_pr_pkt("assoc-sta %pM, is_vns = %s\n",
+		   cl_sta->addr, is_vns ? "TRUE" : "FALSE");
+
+	return is_vns;
+}
+
+void cl_vns_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	/* Update is_very_near according to mgmt list */
+	bool is_vns = false;
+
+	if (!cl_hw->vns_db->enable)
+		return;
+
+	spin_lock_bh(&cl_hw->vns_db->lock);
+	is_vns = cl_vns_mgmt_list_find_and_remove(cl_hw, cl_sta->addr);
+	spin_unlock_bh(&cl_hw->vns_db->lock);
+
+	if (is_vns) {
+		vns_pr("sta %pM connected - is_vns = TRUE\n", cl_sta->addr);
+		cl_sta->vns_db.is_very_near = true;
+		cl_sta->vns_db.prev_decision = true;
+		cl_msg_tx_set_vns(cl_hw, cl_sta->sta_idx, true);
+	} else {
+		vns_pr("sta %pM connected - is_vns = FALSE\n", cl_sta->addr);
+	}
+}
+
+void cl_vns_handle_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS])
+{
+	/* Collect rssi samples */
+	int i;
+
+	if (!cl_hw->vns_db->enable)
+		return;
+
+	for (i = 0; i < cl_hw->num_antennas; i++)
+		cl_sta->vns_db.rssi_sum[i] += rssi[i];
+
+	cl_sta->vns_db.rssi_samples++;
+}
+
+void cl_vns_recovery(struct cl_hw *cl_hw)
+{
+	vns_pr("Recovery\n");
+	cl_sta_loop_bh(cl_hw, cl_vns_recovery_sta);
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 93/96] cl8k: add vns.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (91 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 92/96] cl8k: add vns.c viktor.barna
@ 2022-05-24 11:34 ` viktor.barna
  2022-05-24 11:35 ` [RFC v2 94/96] cl8k: add wrs.c viktor.barna
                   ` (2 subsequent siblings)
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:34 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/vns.h | 65 ++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/vns.h

diff --git a/drivers/net/wireless/celeno/cl8k/vns.h b/drivers/net/wireless/celeno/cl8k/vns.h
new file mode 100644
index 000000000000..904fa7a7fe1b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/vns.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_VNS_H
+#define CL_VNS_H
+
+#include "def.h"
+
+/**
+ * DOC: VNS (=Very Near STA)
+ *
+ * Feature is responsible for TX power adjustment regarding to the STA
+ * location. Near stations should get signal with lower power to avoid
+ * saturation. Power is contolled for both transmitted data (%VNS_MODE_DATA)
+ * and autoresponse frames (%VNS_AUTO_REPLY), including both cases for
+ * connected and not connected stations.
+ *
+ * In order to determine, whether a station is in VNS range, we rely on the
+ * RSSI values, received from the firmware for every RX frame.
+ */
+
+#define VNS_MODE_DATA       0x1
+#define VNS_MODE_AUTO_REPLY 0x2
+#define VNS_MODE_ALL        (VNS_MODE_DATA | VNS_MODE_AUTO_REPLY)
+
+struct cl_vns_rssi_entry {
+	struct list_head list_all;
+	struct list_head list_addr;
+	unsigned long timestamp;
+	s8 strongset_rssi;
+	u8 addr[ETH_ALEN];
+};
+
+struct cl_vns_mgmt_db {
+	u32 num_entries;
+	struct list_head list_all;
+	struct list_head list_addr[STA_HASH_SIZE];
+};
+
+struct cl_vns_db {
+	bool enable;
+	bool dbg;
+	bool dbg_per_packet;
+	u16 interval_period;
+	spinlock_t lock;
+	struct cl_vns_mgmt_db mgmt_db;
+};
+
+struct cl_vns_sta_db {
+	bool is_very_near;
+	bool prev_decision;
+	s32 rssi_sum[MAX_ANTENNAS];
+	s32 rssi_samples;
+};
+
+int cl_vns_init(struct cl_hw *cl_hw);
+void cl_vns_close(struct cl_hw *cl_hw);
+void cl_vns_maintenance(struct cl_hw *cl_hw);
+void cl_vns_mgmt_handler(struct cl_hw *cl_hw, u8 *addr, s8 rssi[MAX_ANTENNAS]);
+bool cl_vns_is_very_near(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb);
+void cl_vns_sta_add(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_vns_handle_rssi(struct cl_hw *cl_hw, struct cl_sta *cl_sta, s8 rssi[MAX_ANTENNAS]);
+void cl_vns_recovery(struct cl_hw *cl_hw);
+
+#endif /* CL_VNS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 94/96] cl8k: add wrs.c
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (92 preceding siblings ...)
  2022-05-24 11:34 ` [RFC v2 93/96] cl8k: add vns.h viktor.barna
@ 2022-05-24 11:35 ` viktor.barna
  2022-05-24 11:35 ` [RFC v2 95/96] cl8k: add wrs.h viktor.barna
  2022-05-24 11:35 ` [RFC v2 96/96] wireless: add Celeno vendor viktor.barna
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:35 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs.c | 3323 ++++++++++++++++++++++++
 1 file changed, 3323 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs.c

diff --git a/drivers/net/wireless/celeno/cl8k/wrs.c b/drivers/net/wireless/celeno/cl8k/wrs.c
new file mode 100644
index 000000000000..9f6b0d8154da
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs.c
@@ -0,0 +1,3323 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#include <linux/kernel.h>
+
+#include "rates.h"
+#include "chip.h"
+#include "utils.h"
+#include "hw.h"
+#include "reg/reg_defs.h"
+#include "debug.h"
+#include "radio.h"
+#include "wrs.h"
+
+#define wrs_pr(wrs_db, level, ...) \
+	do { \
+		if ((level) <= (wrs_db)->debug_level) \
+			pr_debug("[WRS]" __VA_ARGS__); \
+	} while (0)
+
+#define wrs_pr_verbose(wrs_db, ...) wrs_pr(wrs_db, DBG_LVL_VERBOSE, ##__VA_ARGS__)
+#define wrs_pr_err(wrs_db, ...)     wrs_pr(wrs_db, DBG_LVL_ERROR, ##__VA_ARGS__)
+#define wrs_pr_warn(wrs_db, ...)    wrs_pr(wrs_db, DBG_LVL_WARNING, ##__VA_ARGS__)
+#define wrs_pr_trace(wrs_db, ...)   wrs_pr(wrs_db, DBG_LVL_TRACE, ##__VA_ARGS__)
+#define wrs_pr_info(wrs_db, ...)    wrs_pr(wrs_db, DBG_LVL_INFO, ##__VA_ARGS__)
+
+#define WRS_LOGGER wrs_params->logger[wrs_params->logger_idx]
+
+static void cl_wrs_reset_params_cntrs(struct cl_wrs_params *wrs_params)
+{
+	wrs_params->frames_total = 0;
+	wrs_params->fail_total = 0;
+	wrs_params->ba_not_rcv_total = 0;
+	wrs_params->epr_acc = 0;
+	wrs_params->up_same_time_cnt = 0;
+	wrs_params->down_time_cnt = 0;
+}
+
+static bool cl_wrs_down_epr_check(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+				  struct cl_wrs_params *wrs_params, u8 drop_factor,
+				  enum cl_wrs_decision decision)
+{
+	u16 curr_rate_idx = wrs_params->rate_idx;
+	struct cl_wrs_table *curr_rate = &wrs_params->table[curr_rate_idx];
+	u64 curr_epr_acc = curr_rate->epr_acc;
+	u32 curr_total = curr_rate->frames_total;
+	u16 down_rate_idx = curr_rate->rate_down.rate_idx;
+	struct cl_wrs_table *down_rate = &wrs_params->table[down_rate_idx];
+	u64 down_epr_acc = down_rate->epr_acc;
+	u32 down_total = down_rate->frames_total;
+	u16 down_data_rate = 0;
+	u64 condition1 = 0, condition2 = 0;
+	bool down_decision = false, allow_penalty = true;
+
+	if (wrs_params->calc_ba_not_rcv) {
+		curr_total += curr_rate->ba_not_rcv_total;
+		down_total += down_rate->ba_not_rcv_total;
+	}
+
+	/*
+	 * In the EPR of down candidate is better than or equal to current EPR => return true
+	 *
+	 * (1) curr_epr <= down_epr * factor(%)
+	 *
+	 *       curr_epr_acc     down_epr_acc     factor
+	 * (2)  -------------- <= -------------- * --------
+	 *        curr_total       down_total       100
+	 *
+	 * (3) curr_epr_acc * down_total * 100 <= down_epr_acc * curr_total * factor
+	 *
+	 * (4) conditation1 <= conditation2
+	 *                                                         down_epr_acc
+	 * If (down_total == 0) we use down_data_rate instead of: --------------
+	 *                                                          down_total
+	 */
+	if (down_total) {
+		condition1 = curr_epr_acc * down_total * 100;
+		condition2 = down_epr_acc * curr_total * drop_factor;
+	} else {
+		down_data_rate = cl_data_rates_get_x10(wrs_params->rate_params.mode,
+						       down_rate->rate.bw,
+						       down_rate->rate.nss,
+						       down_rate->rate.mcs,
+						       down_rate->rate.gi);
+
+		condition1 = curr_epr_acc * 100;
+		condition2 = (u64)down_data_rate * curr_total * drop_factor;
+		allow_penalty = false;
+	}
+
+	wrs_params->penalty_decision_dn = wrs_db->step_down;
+
+	if (condition2 && condition1 <= condition2) {
+		down_decision = true;
+
+		if (allow_penalty) {
+			/*
+			 * The penalty is calculated as follow:
+			 *
+			 * penalty = MAX_STEP * penalty_factor
+			 *                                      epr_curr
+			 * penalty = MAX_STEP * (100% - 100% * ----------)
+			 *                                      epr_down
+			 *
+			 *                                    conditation1
+			 * penalty = MAX_STEP * (100% - 100% --------------)
+			 *                                    conditation2
+			 */
+
+			u64 penalty_factor = 100 - div64_u64(condition1 * 100, condition2);
+			u16 max_step = wrs_db->time_th_max_up - wrs_db->step_down;
+
+			wrs_params->penalty_decision_dn +=
+				div64_u64(max_step * penalty_factor, 100);
+		}
+
+		if (decision != WRS_DECISION_SAME)
+			wrs_pr_info(wrs_db,
+				    "[%s] EPR check: sta = %u, pkt_curr = %u, "
+				    "pkt_down = %u, epr_curr = %llu, epr_down * %u%% = %llu, "
+				    "penalty = %u\n",
+				    WRS_TYPE_STR(wrs_params->type),
+				    wrs_sta->sta_idx,
+				    curr_total,
+				    down_total,
+				    div64_u64(curr_epr_acc, curr_total * 10),
+				    drop_factor,
+				    down_total ?
+				    div64_u64(down_epr_acc * drop_factor, down_total * 1000) :
+				    (down_data_rate / 10),
+				    wrs_params->penalty_decision_dn);
+	}
+
+	if (wrs_params->is_logger_en && down_decision) {
+		WRS_LOGGER.curr_epr = (u16)div64_u64(curr_epr_acc, 10 * curr_total);
+		WRS_LOGGER.down_epr = down_total ?
+			(u16)div64_u64(down_epr_acc, down_total * 10) : (down_data_rate / 10),
+		WRS_LOGGER.down_epr_factorized = WRS_LOGGER.down_epr * drop_factor / 100;
+		WRS_LOGGER.penalty = wrs_params->penalty_decision_dn;
+	}
+
+	return down_decision;
+}
+
+static void cl_wrs_time_thr_max_handler(struct cl_wrs_db *wrs_db,
+					struct cl_wrs_table *table, u8 up_idx)
+{
+	/*
+	 * Check if there are at least two UP rates,
+	 * and all UP rates reached max time threshold
+	 */
+	u8 i = 0;
+	u8 time_th_max = 0;
+
+	for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++) {
+		if (table->rate_up[i].rate_idx == WRS_INVALID_RATE)
+			continue;
+
+		if (table->rate_up[i].time_th != wrs_db->time_th_max_up)
+			return;
+
+		time_th_max++;
+	}
+
+	if (time_th_max < 2)
+		return;
+
+	/* Find the next max rate, and decrease its time threshold by 1 */
+	i = 0;
+	while (i < WRS_TABLE_NODE_UP_MAX) {
+		up_idx++;
+		if (up_idx == WRS_TABLE_NODE_UP_MAX)
+			up_idx = WRS_TABLE_NODE_UP_MCS;
+
+		if (table->rate_up[up_idx].rate_idx != WRS_INVALID_RATE) {
+			/*
+			 * If all up rates reached max time threshold,the first up
+			 * rate will always be selected.
+			 * To overcome it, we decrease the time threshold of the next
+			 * up rate by 1 (so it will be samller and selected next time)
+			 */
+			table->rate_up[up_idx].time_th--;
+			break;
+		}
+
+		i++;
+	}
+}
+
+static bool cl_wrs_find_up_candidate(struct cl_wrs_db *wrs_db, struct cl_wrs_params *wrs_params,
+				     u16 *up_rate_idx, u32 *up_time_th)
+{
+	bool up_rate_valid = false;
+	u8 up_idx = 0;
+	u8 up_candidate = 0;
+	u16 rate_idx = 0;
+	struct cl_wrs_table *table = &wrs_params->table[wrs_params->rate_idx];
+
+	*up_rate_idx = WRS_INVALID_RATE;
+	*up_time_th = U32_MAX;
+
+	for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+		rate_idx = table->rate_up[up_idx].rate_idx;
+
+		if (rate_idx == WRS_INVALID_RATE)
+			continue;
+
+		if (wrs_db->quick_up_en && table->rate_up[up_idx].quick_up_check) {
+			*up_rate_idx = rate_idx;
+			*up_time_th = wrs_db->quick_up_interval;
+			up_rate_valid = true;
+			up_candidate = up_idx;
+			break;
+		} else if (table->rate_up[up_idx].time_th < *up_time_th) {
+			*up_rate_idx = rate_idx;
+			*up_time_th = table->rate_up[up_idx].time_th;
+			up_rate_valid = true;
+			up_candidate = up_idx;
+		}
+	}
+
+	if (wrs_db->time_th_max_up == *up_time_th)
+		cl_wrs_time_thr_max_handler(wrs_db, table, up_candidate);
+
+	return up_rate_valid;
+}
+
+static bool cl_wrs_epr_immeidate_down(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+				      struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+				      u16 down_rate_idx)
+{
+	if (cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+				  wrs_db->immediate_drop_epr_factor,
+				  WRS_DECISION_DOWN_IMMEDIATE)) {
+		/*
+		 * If there are several immediate drops in a row ignore them,
+		 * because it is probably not realted to bad TX rate
+		 */
+		wrs_params->immediate_drop_cntr++;
+
+		if (wrs_params->immediate_drop_cntr > wrs_db->immediate_drop_max_in_row) {
+			wrs_params->immediate_drop_ignore++;
+
+			cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+			cl_wrs_reset_params_cntrs(wrs_params);
+
+			wrs_pr_info(wrs_db,
+				    "[%s] sta %u - ignore immediate down decision (cntr=%u)\n",
+				    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx,
+				    wrs_params->immediate_drop_cntr);
+			return true;
+		}
+
+		cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+				     WRS_DECISION_DOWN_IMMEDIATE, down_rate_idx);
+		return true;
+	}
+
+	return false;
+}
+
+static void cl_wrs_decision_up(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			       struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			       u16 up_rate_idx, u32 up_th)
+{
+	enum cl_wrs_decision up_decision = (up_th == wrs_db->quick_up_interval) ?
+		WRS_DECISION_UP_QUICK : WRS_DECISION_UP;
+
+	if (wrs_params->is_logger_en)
+		WRS_LOGGER.up_time = wrs_params->up_same_time_cnt;
+
+	cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params, up_decision, up_rate_idx);
+}
+
+static void cl_wrs_decision_same(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+				 struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+				 u16 rate_idx)
+{
+	cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params, WRS_DECISION_SAME, rate_idx);
+}
+
+static void cl_wrs_epr_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+				struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	u16 curr_rate_idx = wrs_params->rate_idx;
+	struct cl_wrs_table *table = &wrs_params->table[curr_rate_idx];
+	u16 down_rate_idx = table->rate_down.rate_idx;
+	u16 up_rate_idx = 0;
+	u16 down_th = table->rate_down.time_th;
+	u32 up_th = 0;
+	bool up_rate_valid = false;
+
+	/* Check if we transmitted enough frames for taking decision */
+	if ((wrs_params->frames_total + wrs_params->ba_not_rcv_total) <
+	    wrs_db->min_frames_for_decision)
+		return;
+
+	if (wrs_params->is_logger_en) {
+		WRS_LOGGER.timestamp = jiffies_to_msecs(jiffies);
+		WRS_LOGGER.rate_idx = wrs_params->rate_idx;
+		WRS_LOGGER.success = wrs_params->frames_total - wrs_params->fail_total;
+		WRS_LOGGER.fail = wrs_params->fail_total;
+		WRS_LOGGER.ba_not_rcv = wrs_params->ba_not_rcv_total;
+	}
+
+	up_rate_valid = cl_wrs_find_up_candidate(wrs_db, wrs_params, &up_rate_idx, &up_th);
+
+	/* RSSI protect */
+	if (!WRS_TYPE_IS_TX_MU_MIMO(wrs_params) && wrs_db->rssi_protect_en)
+		if (cl_wrs_rssi_prot_decision(cl_hw, wrs_db, wrs_sta, wrs_params,
+					      up_rate_valid, up_rate_idx, down_rate_idx))
+			return;
+
+	if (down_rate_idx != curr_rate_idx) {
+		/* Down immediate */
+		if (wrs_db->immediate_drop_en)
+			if (cl_wrs_epr_immeidate_down(cl_hw, wrs_db, wrs_sta,
+						      wrs_params, down_rate_idx))
+				return;
+
+		/* Down */
+		if (wrs_params->down_time_cnt >= down_th) {
+			if (cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+						  wrs_db->epr_factor, WRS_DECISION_DOWN)) {
+				cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+						     WRS_DECISION_DOWN, down_rate_idx);
+				return;
+			}
+
+			wrs_params->down_time_cnt = 0;
+		}
+	}
+
+	/* Up-same */
+	if (wrs_params->up_same_time_cnt >= up_th) {
+		if (up_rate_valid)
+			cl_wrs_decision_up(cl_hw, wrs_db, wrs_sta, wrs_params, up_rate_idx, up_th);
+		else
+			cl_wrs_decision_same(cl_hw, wrs_db, wrs_sta, wrs_params, curr_rate_idx);
+
+		return;
+	}
+
+	/*
+	 * If there is no valid UP rate and the EPR is more
+	 * than EPR down threshold => make a same decision
+	 */
+	if (!up_rate_valid &&
+	    !cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+				   wrs_db->epr_factor, WRS_DECISION_SAME))
+		cl_wrs_decision_same(cl_hw, wrs_db, wrs_sta, wrs_params, curr_rate_idx);
+}
+
+static void cl_wrs_divide_weights_by_two(struct cl_wrs_table *table_node)
+{
+	u8 up_idx = 0;
+	struct cl_wrs_table_node *rate_up;
+
+	/*
+	 * Converge weights - divide all weights by 2
+	 * (make sure they do not go below their init value)
+	 */
+	if (table_node->rate_down.rate_idx != WRS_INVALID_RATE)
+		table_node->rate_down.time_th = max(table_node->rate_down.time_th >> 1,
+						    WRS_INIT_MSEC_WEIGHT_DOWN);
+
+	for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+		rate_up = &table_node->rate_up[up_idx];
+
+		if (rate_up->rate_idx != WRS_INVALID_RATE)
+			rate_up->time_th = max(rate_up->time_th >> 1, WRS_INIT_MSEC_WEIGHT_UP);
+
+		if (rate_up->time_th == WRS_INIT_MSEC_WEIGHT_UP)
+			rate_up->quick_up_check = false;
+	}
+}
+
+static void cl_wrs_converge_weights(struct cl_wrs_params *wrs_params)
+{
+	/*
+	 * Converge weights - divide the weights by 2 (except for the current rate),
+	 * and reset PER counters (except for current rate, down rate, and down-down rate).
+	 */
+	u16 i;
+	u16 curr_idx = wrs_params->rate_idx;
+	u16 down_idx = wrs_params->table[curr_idx].rate_down.rate_idx;
+	u16 down2_idx = wrs_params->table[down_idx].rate_down.rate_idx;
+
+	for (i = 0; i < wrs_params->table_size; i++) {
+		if (i == curr_idx)
+			continue;
+
+		cl_wrs_divide_weights_by_two(&wrs_params->table[i]);
+
+		if (i != down_idx && i != down2_idx) {
+			wrs_params->table[i].frames_total = 0;
+			wrs_params->table[i].ba_not_rcv_total = 0;
+			wrs_params->table[i].epr_acc = 0;
+		}
+	}
+}
+
+static void cl_wrs_converge_weights_idle_decision(struct cl_hw *cl_hw,
+						  struct cl_wrs_db *wrs_db,
+						  struct cl_wrs_sta *wrs_sta,
+						  struct cl_wrs_params *wrs_params)
+{
+	/*
+	 * Continue normal converge (just like during traffic).
+	 * After 6 seconds reset table, and select rate based on RSSI.
+	 */
+	if (!wrs_db->converge_idle_en)
+		return;
+
+	wrs_params->converge_time_idle += wrs_db->interval;
+
+	if (wrs_params->converge_mode == WRS_CONVERGE_MODE_RESET) {
+		if (wrs_params->converge_time_idle < wrs_db->converge_idle_interval_reset) {
+			cl_wrs_converge_weights(wrs_params);
+		} else {
+			wrs_params->converge_mode = WRS_CONVERGE_MODE_RSSI;
+			wrs_params->converge_time_idle = 0;
+
+			wrs_pr_info(wrs_db, "[%s] Converge weights: sta %u - RSSI\n",
+				    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx);
+
+			/* Reset table and choose new rate based on RSSI */
+			cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+
+			if (!WRS_TYPE_IS_TX_MU_MIMO(wrs_params))
+				cl_wrs_set_rate_idle(cl_hw, wrs_db, wrs_sta, wrs_params);
+		}
+	} else {
+		if (wrs_params->converge_time_idle < wrs_db->converge_idle_interval_rssi)
+			return;
+
+		/* Choose new rate */
+		if (!WRS_TYPE_IS_TX_MU_MIMO(wrs_params)) {
+			wrs_params->converge_time_idle = 0;
+			cl_wrs_set_rate_idle(cl_hw, wrs_db, wrs_sta, wrs_params);
+		}
+	}
+}
+
+static void cl_wrs_converge_weights_idle_reset(struct cl_wrs_db *wrs_db,
+					       struct cl_wrs_sta *wrs_sta,
+					       struct cl_wrs_params *wrs_params)
+{
+	/* There was traffic in last maintenance interval - reset converge parameteres */
+	wrs_params->converge_time_idle = 0;
+
+	if (wrs_params->converge_mode != WRS_CONVERGE_MODE_RESET) {
+		wrs_params->converge_mode = WRS_CONVERGE_MODE_RESET;
+		wrs_pr_info(wrs_db, "[%s] Converge weights: sta %u - RESET\n",
+			    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx);
+	}
+}
+
+static void cl_wrs_converge_weights_trfc_decision(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+						  struct cl_wrs_db *wrs_db,
+						  struct cl_wrs_params *wrs_params)
+{
+	u32 converge_interval = 0;
+
+	if (!wrs_db->converge_trfc_en)
+		return;
+
+	converge_interval = wrs_db->converge_trfc_interval_static;
+
+	if (!cl_motion_sense_is_static(cl_hw, cl_sta))
+		converge_interval = wrs_db->converge_trfc_interval_motion;
+
+	wrs_params->converge_time_trfc += wrs_db->interval;
+
+	if (wrs_params->converge_time_trfc >= converge_interval) {
+		wrs_params->converge_time_trfc = 0;
+		cl_wrs_converge_weights(wrs_params);
+	}
+}
+
+static u32 cl_wrs_get_sync_attempts(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+	struct cl_wrs_info *wrs_info = cl_wrs_info_get(cl_sta, wrs_params->type);
+
+	return wrs_info->sync_attempts;
+}
+
+static void cl_wrs_sta_no_sync_handler(struct cl_hw *cl_hw,
+				       struct cl_wrs_db *wrs_db,
+				       struct cl_wrs_sta *wrs_sta,
+				       struct cl_wrs_params *wrs_params)
+{
+	unsigned long time_delta = jiffies_to_msecs(jiffies - wrs_params->no_sync_timestamp);
+
+	if (time_delta < wrs_db->sync_timeout)
+		return;
+
+	if (cl_wrs_get_sync_attempts(wrs_sta, wrs_params) < wrs_db->sync_min_attempts) {
+		/*
+		 * Rate not synced but there is also hardly no traffic -
+		 * change mode to synced!
+		 */
+		wrs_params->sync = true;
+		wrs_params->sync_timestamp = jiffies;
+	} else {
+		struct cl_wrs_table *wrs_table = &wrs_params->table[wrs_params->rate_idx];
+		struct cl_wrs_rate *curr_rate = &wrs_table->rate;
+
+		if (IS_REAL_PHY(cl_hw->chip))
+			wrs_pr_warn(wrs_db,
+				    "[%s] NO SYNC - sta = %u, bw = %u, nss = %u, mcs = %u, gi = %u\n",
+				    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx, curr_rate->bw,
+				    curr_rate->nss, curr_rate->mcs, curr_rate->gi);
+
+		if (WRS_IS_DECISION_UP(wrs_params->last_decision)) {
+			cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+					     WRS_DECISION_DOWN_NO_SYNC,
+					     wrs_table->rate_down.rate_idx);
+		} else {
+			/* If the last decision was DOWN - change state to SYNCED. */
+			wrs_params->sync = true;
+			wrs_params->sync_timestamp = jiffies;
+		}
+	}
+}
+
+static void cl_wrs_update_ba_not_rcv(struct cl_wrs_db *wrs_db, struct cl_wrs_params *wrs_params)
+{
+	unsigned long time_since_sync = jiffies_to_msecs(jiffies - wrs_params->sync_timestamp);
+
+	wrs_params->calc_ba_not_rcv = (wrs_db->ba_not_rcv_force ||
+				       (time_since_sync < wrs_db->ba_not_rcv_time_since_sync));
+}
+
+static void _cl_wrs_cntrs_reset(struct cl_wrs_info *wrs_info)
+{
+	wrs_info->epr_acc = 0;
+	wrs_info->success = 0;
+	wrs_info->fail = 0;
+	wrs_info->ba_not_rcv = 0;
+	wrs_info->ba_not_rcv_consecutive_max = 0;
+}
+
+static void cl_wrs_cntrs_read(struct cl_wrs_sta *wrs_sta,
+			      struct cl_wrs_cntrs *cntrs,
+			      u8 type)
+{
+	struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+	struct cl_wrs_info *wrs_info = cl_wrs_info_get(cl_sta, type);
+
+	cntrs->epr_acc = wrs_info->epr_acc;
+	cntrs->total = wrs_info->success + wrs_info->fail;
+	cntrs->fail = wrs_info->fail;
+	cntrs->ba_not_rcv = wrs_info->ba_not_rcv;
+	cntrs->ba_not_rcv_consecutive = wrs_info->ba_not_rcv_consecutive_max;
+
+	_cl_wrs_cntrs_reset(wrs_info);
+}
+
+static void _cl_wrs_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				    struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	struct cl_wrs_cntrs cntrs = {0};
+
+	if (wrs_params->is_logger_en)
+		memset(&WRS_LOGGER, 0, sizeof(struct cl_wrs_logger));
+
+	if (!wrs_params->sync) {
+		cl_wrs_sta_no_sync_handler(cl_hw, wrs_db, wrs_sta, wrs_params);
+		goto end_logger;
+	}
+
+	if (!WRS_TYPE_IS_RX(wrs_params))
+		cl_wrs_update_ba_not_rcv(wrs_db, wrs_params);
+
+	cl_wrs_cntrs_read(wrs_sta, &cntrs, wrs_params->type);
+
+	if (wrs_params->is_fixed_rate) {
+		cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &cntrs);
+		goto end_logger;
+	}
+
+	wrs_params->down_time_cnt += wrs_db->interval;
+	wrs_params->up_same_time_cnt += wrs_db->interval;
+
+	if ((cntrs.total + cntrs.ba_not_rcv) < wrs_db->converge_idle_packet_th) {
+		/*
+		 * Very few frames were sent in last maintenance interval
+		 * Check if weights should be converged
+		 */
+		cl_wrs_converge_weights_idle_decision(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+		cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &cntrs);
+
+		goto end_logger;
+	} else {
+		/* There was traffic in last maintenance interval - reset converge parameteres */
+		cl_wrs_converge_weights_idle_reset(wrs_db, wrs_sta, wrs_params);
+	}
+
+	cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &cntrs);
+
+	wrs_params->quick_up_check =
+		(cntrs.ba_not_rcv_consecutive >= wrs_db->quick_up_ba_thr);
+	cl_wrs_epr_decision(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+	cl_wrs_converge_weights_trfc_decision(cl_hw, cl_sta, wrs_db, wrs_params);
+
+end_logger:
+	if (wrs_params->is_logger_en && WRS_LOGGER.decision != WRS_DECISION_NONE)
+		wrs_params->logger_idx = WRS_INC_POW2(wrs_params->logger_idx,
+						      wrs_params->logger_size);
+}
+
+static void cl_wrs_sta_maintenance(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	_cl_wrs_sta_maintenance(cl_hw, cl_sta, &cl_sta->wrs_sta.tx_su_params);
+
+	if (cl_sta->wrs_sta.rx_params)
+		_cl_wrs_sta_maintenance(cl_hw, cl_sta, cl_sta->wrs_sta.rx_params);
+}
+
+static void cl_wrs_cca_calc(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw)
+{
+	u32 cca_primary_new = mac_hw_edca_cca_busy_get(cl_hw);
+	u32 cca_sec80_new = (max_bw > CHNL_BW_80) ? mac_hw_add_cca_busy_sec_80_get(cl_hw) : 0;
+	u32 cca_sec40_new = (max_bw > CHNL_BW_40) ? mac_hw_add_cca_busy_sec_40_get(cl_hw) : 0;
+	u32 cca_sec20_new = mac_hw_add_cca_busy_sec_20_get(cl_hw);
+
+	u32 cca_primary_diff = cca_primary_new - wrs_db->cca_primary;
+	u32 cca_sec80_diff = cca_sec80_new - wrs_db->cca_sec80;
+	u32 cca_sec40_diff = cca_sec40_new - wrs_db->cca_sec40;
+	u32 cca_sec20_diff = cca_sec20_new - wrs_db->cca_sec20;
+
+	wrs_db->cca_primary = cca_primary_new;
+	wrs_db->cca_sec80 = cca_sec80_new;
+	wrs_db->cca_sec40 = cca_sec40_new;
+	wrs_db->cca_sec20 = cca_sec20_new;
+	wrs_db->cca_timestamp = jiffies;
+
+	/* Increase by 25% */
+	cca_primary_diff = cca_primary_diff * WRS_CCA_PRIMARY_FACTOR >> WRS_CCA_PRIMARY_SHIFT;
+
+	/* Adjacent interference - if secondary is higher than primary by 25%. */
+	wrs_db->adjacent_interference80 = (cca_sec80_diff > cca_primary_diff);
+	wrs_db->adjacent_interference40 = (cca_sec40_diff > cca_primary_diff);
+	wrs_db->adjacent_interference20 = (cca_sec20_diff > cca_primary_diff);
+}
+
+static void cl_wrs_cca_maintenance(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db)
+{
+	u8 max_bw = wrs_db->max_cap.bw;
+
+	if (max_bw == CHNL_BW_20)
+		return;
+
+	if (jiffies_to_msecs(jiffies - wrs_db->cca_timestamp) > WRS_CCA_PERIOD_MS)
+		cl_wrs_cca_calc(cl_hw, wrs_db, max_bw);
+}
+
+static void cl_wrs_maintenance(struct timer_list *t)
+{
+	struct cl_wrs_db *wrs_db = from_timer(wrs_db, t, timer_maintenance);
+	struct cl_hw *cl_hw = container_of(wrs_db, struct cl_hw, wrs_db);
+
+	cl_wrs_cca_maintenance(cl_hw, wrs_db);
+
+	cl_wrs_lock(wrs_db);
+	cl_sta_loop(cl_hw, cl_wrs_sta_maintenance);
+	cl_wrs_unlock(wrs_db);
+
+	mod_timer(&wrs_db->timer_maintenance, jiffies + msecs_to_jiffies(wrs_db->interval));
+}
+
+static void cl_wrs_down_decision_weights_update(struct cl_wrs_db *wrs_db,
+						struct cl_wrs_sta *wrs_sta,
+						u16 new_rate_idx,
+						struct cl_wrs_params *wrs_params)
+{
+	u16 old_rate_idx = wrs_params->rate_idx;
+	u8 up_idx = 0;
+	u16 down_th_min = wrs_db->time_th_min;
+	u16 step = wrs_db->step_down;
+	u16 *th_down = &wrs_params->table[old_rate_idx].rate_down.time_th;
+	u16 *th_up = NULL;
+	struct cl_wrs_table *table_node = &wrs_params->table[new_rate_idx];
+
+	/* Decrease the weight from old rate to new rate */
+	if (*th_down > (down_th_min + step))
+		*th_down -= step;
+	else
+		*th_down = down_th_min;
+
+	/* Increase the weight from new rate to old rate */
+	for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+		if (old_rate_idx == table_node->rate_up[up_idx].rate_idx) {
+			th_up = &table_node->rate_up[up_idx].time_th;
+			table_node->rate_up[up_idx].quick_up_check = !!wrs_params->quick_up_check;
+			step = wrs_params->penalty_decision_dn;
+			*th_up = min_t(u16, *th_up + step, wrs_db->time_th_max_up);
+			break;
+		}
+	}
+
+	wrs_pr_info(wrs_db,
+		    "[%s] Down update - sta = %u, "
+		    "down weight [%u-->%u] = %u, up weight [%u-->%u] = %u\n",
+		    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx, old_rate_idx, new_rate_idx,
+		    *th_down, new_rate_idx, old_rate_idx, th_up ? *th_up : 0);
+}
+
+static void cl_wrs_up_same_decision_weights_update(struct cl_wrs_db *wrs_db,
+						   struct cl_wrs_sta *wrs_sta,
+						   struct cl_wrs_params *wrs_params)
+{
+	u16 curr_rate_idx = wrs_params->rate_idx;
+	u16 down_rate_idx = wrs_params->table[curr_rate_idx].rate_down.rate_idx;
+	u8 up_idx = 0;
+	u16 up_th_min = wrs_db->time_th_min;
+	u16 step = wrs_db->step_up_same;
+	u16 *th_down = &wrs_params->table[curr_rate_idx].rate_down.time_th;
+	u16 *th_up = NULL;
+	u16 th_down_orig = *th_down;
+	u16 th_up_orig = 0;
+	struct cl_wrs_table *table_node = &wrs_params->table[down_rate_idx];
+
+	/* Increase the weight from current rate to down rate */
+	*th_down = min_t(u16, *th_down + step, wrs_db->time_th_max_down);
+
+	/* Decrease the weight from down rate to current rate */
+	for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+		if (curr_rate_idx == table_node->rate_up[up_idx].rate_idx) {
+			th_up = &table_node->rate_up[up_idx].time_th;
+			table_node->rate_up[up_idx].quick_up_check = false;
+
+			th_up_orig = *th_up;
+
+			if (*th_up > (up_th_min + step))
+				*th_up -= step;
+			else
+				*th_up = up_th_min;
+			break;
+		}
+	}
+
+	if (th_up && (th_up_orig != *th_up || th_down_orig != *th_down))
+		wrs_pr_info(wrs_db,
+			    "[%s] Up/same update - sta = %u, "
+			    "down weight [%u-->%u] = %u, up weight [%u-->%u] = %u\n",
+			    WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx, curr_rate_idx,
+			    down_rate_idx, *th_down, down_rate_idx, curr_rate_idx, *th_up);
+}
+
+static bool cl_wrs_is_rate_params_valid(struct cl_wrs_rate *rate_params)
+{
+	return (*(u16 *)rate_params != U16_MAX);
+}
+
+void cl_wrs_init(struct cl_hw *cl_hw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	/* Default configuration */
+	wrs_db->debug_level = DBG_LVL_ERROR;
+	wrs_db->rssi_protect_en = true;
+	wrs_db->rssi_protect_mode = WRS_RSSI_PROT_MODE_RSSI;
+	wrs_db->rssi_protect_up_thr = WRS_RSSI_PROTECT_UP_THR;
+	wrs_db->rssi_protect_dn_thr = WRS_RSSI_PROTECT_DN_THR;
+	wrs_db->min_frames_for_decision = WRS_MIN_FRAMES_FOR_DECISION;
+	wrs_db->epr_factor = WRS_EPR_FACTOR;
+	wrs_db->converge_idle_en = true;
+	wrs_db->converge_idle_interval_reset = WRS_CONVERGE_IDLE_INTERVAL_RESET;
+	wrs_db->converge_idle_interval_rssi = WRS_CONVERGE_IDLE_INTERVAL_RSSI;
+	wrs_db->converge_idle_packet_th = WRS_CONVERGE_IDLE_PACKET_TH;
+	wrs_db->converge_trfc_en = true;
+	wrs_db->converge_trfc_interval_static = WRS_CONVERGE_TRFC_INTERVAL_STATIC;
+	wrs_db->converge_trfc_interval_motion = WRS_CONVERGE_TRFC_INTERVAL_MOTION;
+	wrs_db->immediate_drop_en = true;
+	wrs_db->immediate_drop_epr_factor = WRS_IMMEDIATE_DROP_EPR_FACTOR;
+	wrs_db->immediate_drop_max_in_row = WRS_IMMEDIATE_DROP_MAX_IN_ROW;
+	wrs_db->time_th_min = WRS_MSEC_WEIGHT_MIN;
+	wrs_db->time_th_max_up = WRS_MSEC_WEIGHT_MAX_UP;
+	wrs_db->time_th_max_down = WRS_MSEC_WEIGHT_MAX_DOWN;
+	wrs_db->step_down = WRS_MSEC_STEP_DOWN;
+	wrs_db->step_up_same = WRS_MSEC_STEP_UP_SAME;
+	wrs_db->interval = msecs_round(WRS_MAINTENANCE_PERIOD_MS);
+	wrs_db->conservative_mcs_noisy_env = false;
+	wrs_db->conservative_nss_noisy_env = false;
+	wrs_db->quick_up_en = true;
+	wrs_db->quick_up_ba_thr = WRS_QUICK_UP_BA_THR;
+	wrs_db->quick_up_interval = msecs_round(WRS_QUICK_UP_INTERVAL_MS);
+	wrs_db->quick_down_en = true;
+	wrs_db->quick_down_epr_factor = WRS_QUICK_DOWN_EPR_FACTOR;
+	wrs_db->quick_down_agg_thr = WRS_QUICK_DOWN_AGG_THR;
+	wrs_db->quick_down_pkt_thr = WRS_QUICK_DOWN_PKT_THR;
+	wrs_db->ba_not_rcv_collision_filter = true;
+	/* Environment of 2.4 is much more noisy, so 'BA not received' are ignored. */
+	wrs_db->ba_not_rcv_force = cl_band_is_24g(cl_hw) ? false : true;
+	wrs_db->ba_not_rcv_time_since_sync = WRS_BA_NOT_RCV_TIME_SINCE_SYNC;
+	wrs_db->sync_timeout = WRS_SYNC_TIMEOUT;
+	wrs_db->sync_min_attempts = WRS_SYNC_MIN_ATTEMPTS;
+
+	/* Init WRS periodic timer */
+	timer_setup(&wrs_db->timer_maintenance, cl_wrs_maintenance, 0);
+
+	if (!cl_hw->chip->conf->ce_production_mode) {
+		wrs_db->cca_timestamp = jiffies;
+		mod_timer(&wrs_db->timer_maintenance,
+			  jiffies + msecs_to_jiffies(wrs_db->interval));
+	}
+
+	spin_lock_init(&wrs_db->lock);
+
+	if ((cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MODE] != -1) &&
+	    (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_BW] != -1) &&
+	    (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_NSS] != -1) &&
+	    (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_MCS] != -1) &&
+	    (cl_hw->conf->ci_wrs_fixed_rate[WRS_FIXED_PARAM_GI] != -1))
+		wrs_db->is_fixed_rate = WRS_FIXED_FALLBACK_DIS;
+}
+
+inline void cl_wrs_lock_bh(struct cl_wrs_db *wrs_db)
+{
+	spin_lock_bh(&wrs_db->lock);
+}
+
+inline void cl_wrs_unlock_bh(struct cl_wrs_db *wrs_db)
+{
+	spin_unlock_bh(&wrs_db->lock);
+}
+
+inline void cl_wrs_lock(struct cl_wrs_db *wrs_db)
+{
+	spin_lock(&wrs_db->lock);
+}
+
+inline void cl_wrs_unlock(struct cl_wrs_db *wrs_db)
+{
+	spin_unlock(&wrs_db->lock);
+}
+
+void cl_wrs_rate_param_sync(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			    struct cl_wrs_params *wrs_params)
+{
+	if (wrs_params->sync)
+		return;
+
+	cl_wrs_cntrs_reset(wrs_sta, wrs_params);
+
+	/* Reset counters */
+	cl_wrs_reset_params_cntrs(wrs_params);
+
+	/* Change state to SYNCED */
+	wrs_params->sync = true;
+	wrs_params->sync_timestamp = jiffies;
+
+	wrs_pr_trace(wrs_db, "[%s] Sync - timestamp = %u, sta = %u, rate_idx = %u\n",
+		     WRS_TYPE_STR(wrs_params->type),
+		     jiffies_to_msecs(jiffies),
+		     wrs_sta->sta_idx,
+		     wrs_params->rate_idx);
+}
+
+void cl_wrs_rate_params_update(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			       struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			       u16 new_rate_idx, bool is_sync_required, bool mu_valid)
+{
+	struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+	struct cl_wrs_rate *rate = &wrs_params->table[new_rate_idx].rate;
+	u16 fallback_rate_idx = wrs_params->table[new_rate_idx].rate_down.rate_idx;
+	struct cl_wrs_rate *rate_fallback = &wrs_params->table[fallback_rate_idx].rate;
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+
+	if (!WRS_TYPE_IS_RX(wrs_params)) {
+		struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+
+		cl_dyn_bcast_rate_change(cl_hw, cl_sta, rate_params->mcs, rate->mcs);
+	}
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+
+	rate_params->bw = rate->bw;
+	rate_params->nss = rate->nss;
+	rate_params->mcs = rate->mcs;
+	rate_params->gi = rate->gi;
+	rate_params->mode = wrs_sta->mode;
+	rate_params->fallback_en = (wrs_params->is_fixed_rate != WRS_FIXED_FALLBACK_DIS);
+
+	wrs_pr_trace(wrs_db,
+		     "[%s] Rate params update - "
+		     "sta = %u, rate_idx = %u, bw = %u, nss = %u, mcs = %u, gi = %u\n",
+		     WRS_TYPE_STR(wrs_params->type), wrs_sta->sta_idx,
+		     new_rate_idx, rate_params->bw, rate_params->nss,
+		     rate_params->mcs, rate_params->gi);
+
+	wrs_params->rate_idx = new_rate_idx;
+
+	/* Converge - restart the time for converging weights of all old rates */
+	wrs_params->converge_time_trfc = 0;
+
+	cl_wrs_rate_param_set(cl_hw, wrs_sta, wrs_params, rate_params,
+			      rate_fallback, mu_valid, true);
+
+	if (is_sync_required) {
+		wrs_params->sync = false;
+		wrs_params->no_sync_timestamp = jiffies;
+	} else {
+		wrs_params->sync = true;
+	}
+
+	/* Reset Counters */
+	cl_wrs_reset_params_cntrs(wrs_params);
+}
+
+void cl_wrs_decision_make(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			  enum cl_wrs_decision decision, u16 new_rate_idx)
+{
+	if (WRS_IS_DECISION_DOWN(decision)) {
+		cl_wrs_down_decision_weights_update(wrs_db, wrs_sta, new_rate_idx, wrs_params);
+	} else if (WRS_IS_DECISION_UP(decision)) {
+		cl_wrs_up_same_decision_weights_update(wrs_db, wrs_sta, wrs_params);
+
+		if (wrs_params->rate_idx != wrs_params->table[new_rate_idx].rate_down.rate_idx) {
+			/*
+			 * In case the down rate is different from the previous rate,
+			 * update down rate index and reset the thresholds
+			 */
+			struct cl_wrs_table_node *rate_down =
+				&wrs_params->table[new_rate_idx].rate_down;
+
+			rate_down->rate_idx = wrs_params->rate_idx;
+			rate_down->time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+		}
+	} else if (decision == WRS_DECISION_SAME) {
+		cl_wrs_up_same_decision_weights_update(wrs_db, wrs_sta, wrs_params);
+
+		/* Reset counters besides down_time_cnt */
+		wrs_params->frames_total = 0;
+		wrs_params->fail_total = 0;
+		wrs_params->ba_not_rcv_total = 0;
+		wrs_params->epr_acc = 0;
+		wrs_params->up_same_time_cnt = 0;
+	}
+
+	cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params, decision, new_rate_idx);
+
+	if (WRS_IS_DECISION_DOWN(decision) || WRS_IS_DECISION_UP(decision))
+		cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+					  new_rate_idx, true, wrs_params->is_mu_valid);
+}
+
+void cl_wrs_decision_update(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			    struct cl_wrs_params *wrs_params, enum cl_wrs_decision decision,
+			    u16 new_rate_idx)
+{
+	wrs_params->last_decision = decision;
+	wrs_params->decision_cnt[decision]++;
+
+	if (decision != WRS_DECISION_DOWN_IMMEDIATE)
+		wrs_params->immediate_drop_cntr = 0;
+
+	if (wrs_params->is_logger_en) {
+		WRS_LOGGER.decision = decision;
+		WRS_LOGGER.new_rate_idx = new_rate_idx;
+	}
+
+	if (decision == WRS_DECISION_SAME)
+		return;
+
+	wrs_pr_trace(wrs_db,
+		     "[%s] Decision update - timestamp [%u] sta [%u] decision [%s]\n",
+		     WRS_TYPE_STR(wrs_params->type),
+		     jiffies_to_msecs(jiffies),
+		     wrs_sta->sta_idx,
+		     WRS_DECISION_STR(decision));
+}
+
+void cl_wrs_fixed_rate_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			   struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			   u8 is_fixed_rate, u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi, bool mu_valid)
+{
+	u16 rate_idx = 0;
+	u8 type = wrs_params->type;
+
+	if (!is_fixed_rate) {
+		wrs_params->is_fixed_rate = WRS_AUTO_RATE;
+		wrs_pr_verbose(wrs_db, "[%s] Station %u was set to auto rate!\n",
+			       WRS_TYPE_STR(type), wrs_sta->sta_idx);
+		cl_wrs_set_rate_idle(cl_hw, wrs_db, wrs_sta, wrs_params);
+		return;
+	}
+
+	if (mode != wrs_sta->mode) {
+		/* Set fixed rate with a different format-mode */
+		struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+
+		if (cl_band_is_6g(cl_hw) && mode != WRS_MODE_HE) {
+			wrs_pr_verbose(wrs_db, "[%s] Invalid format mode [%u] for 6GHz band\n",
+				       WRS_TYPE_STR(type), mode);
+			return;
+		}
+#ifdef CONFIG_CL8K_DYN_BCAST_RATE
+
+		if (!WRS_TYPE_IS_RX(wrs_params)) {
+			struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+
+			cl_dyn_bcast_rate_change(cl_hw, cl_sta, rate_params->mcs, mcs);
+		}
+#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
+
+		rate_params->bw = bw;
+		rate_params->nss = nss;
+		rate_params->mcs = mcs;
+		rate_params->gi = gi;
+		rate_params->mode = mode;
+		rate_params->fallback_en = (wrs_params->is_fixed_rate != WRS_FIXED_FALLBACK_DIS);
+
+		wrs_params->is_fixed_rate = is_fixed_rate;
+
+		cl_wrs_rate_param_set(cl_hw, wrs_sta, wrs_params, rate_params,
+				      NULL, mu_valid, true);
+		wrs_pr_verbose(wrs_db,
+			       "[%s] Station %u set to %s - "
+			       "mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+			       WRS_TYPE_STR(type), wrs_sta->sta_idx, FIXED_RATE_STR(is_fixed_rate),
+			       mode, bw, nss, mcs, gi);
+		return;
+	}
+
+	rate_idx = cl_wrs_tables_find_rate_idx(wrs_params, bw, nss, mcs, gi);
+
+	if (rate_idx == WRS_INVALID_RATE) {
+		wrs_pr_err(wrs_db,
+			   "[%s] Invalid fixed rate - mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+			   WRS_TYPE_STR(type), mode, bw, nss, mcs, gi);
+		return;
+	}
+
+	wrs_params->is_fixed_rate = is_fixed_rate;
+	cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta, wrs_params, rate_idx, false, false);
+	wrs_pr_verbose(wrs_db,
+		       "[%s] Station %u set to %s - mode=%u, bw=%u, nss=%u, mcs=%u, gi=%u\n",
+			WRS_TYPE_STR(type), wrs_sta->sta_idx, FIXED_RATE_STR(is_fixed_rate),
+			mode, bw, nss, mcs, gi);
+}
+
+void cl_wrs_quick_down_check(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			     struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_cntrs cntrs = {0};
+	struct cl_wrs_table *table = NULL;
+	u16 curr_rate_idx = 0;
+	u16 down_rate_idx = 0;
+	u8 type = wrs_params->type;
+
+	if (!wrs_params->sync ||
+	    wrs_params->is_fixed_rate ||
+	    !WRS_IS_DECISION_UP(wrs_params->last_decision))
+		return;
+
+	if (!WRS_TYPE_IS_RX(wrs_params))
+		cl_wrs_update_ba_not_rcv(wrs_db, wrs_params);
+
+	cl_wrs_cntrs_read(wrs_sta, &cntrs, type);
+	cl_wrs_stats_per_update(wrs_db, wrs_sta, wrs_params, &cntrs);
+
+	curr_rate_idx = wrs_params->rate_idx;
+	table = &wrs_params->table[curr_rate_idx];
+	down_rate_idx = table->rate_down.rate_idx;
+
+	/* Check if we transmitted enough frames for taking decision */
+	if (wrs_params->frames_total < wrs_db->min_frames_for_decision)
+		return;
+
+	if (wrs_params->is_logger_en) {
+		memset(&WRS_LOGGER, 0, sizeof(struct cl_wrs_logger));
+		WRS_LOGGER.timestamp = jiffies_to_msecs(jiffies);
+		WRS_LOGGER.rate_idx = curr_rate_idx;
+		WRS_LOGGER.success = wrs_params->frames_total - wrs_params->fail_total;
+		WRS_LOGGER.fail = wrs_params->fail_total;
+		WRS_LOGGER.ba_not_rcv = wrs_params->ba_not_rcv_total;
+	}
+
+	/* Down decision check */
+	if (down_rate_idx != curr_rate_idx &&
+	    cl_wrs_down_epr_check(wrs_db, wrs_sta, wrs_params,
+				  wrs_db->quick_down_epr_factor, WRS_DECISION_DOWN_QUICK))
+		cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+				     WRS_DECISION_DOWN_QUICK, down_rate_idx);
+
+	if (wrs_params->is_logger_en && WRS_LOGGER.decision != WRS_DECISION_NONE)
+		wrs_params->logger_idx = WRS_INC_POW2(wrs_params->logger_idx,
+						      wrs_params->logger_size);
+}
+
+bool cl_wrs_up_mcs1(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+		    struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	/*
+	 * In case of big packets (4300 in VHT and 5400 in HE) and low
+	 * rate (BW 20, NSS 1, MCS 0), firmware will increase rate to MCS 1,
+	 * and give an indication to driver (set rate_fix_mcs1 in cl_agg_tx_report).
+	 * WRS should also move to MCS 1, and give the maximum time
+	 * penalty time from MCS 0 toMCS 1.
+	 */
+	u16 curr_rate_idx = wrs_params->rate_idx;
+	u16 up_rate_idx = 0;
+	struct cl_wrs_table *table = &wrs_params->table[curr_rate_idx];
+
+	if (!table || wrs_params->is_fixed_rate)
+		return false;
+
+	if (table->rate.bw != CHNL_BW_20 ||
+	    table->rate.nss != WRS_SS_1 ||
+	    table->rate.mcs != WRS_MCS_0)
+		return false;
+
+	up_rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+						  CHNL_BW_20, WRS_SS_1, WRS_MCS_1, table->rate.gi);
+
+	if (up_rate_idx == WRS_INVALID_RATE)
+		return false;
+
+	if (wrs_params->is_logger_en) {
+		memset(&WRS_LOGGER, 0, sizeof(struct cl_wrs_logger));
+		WRS_LOGGER.timestamp = jiffies_to_msecs(jiffies);
+		WRS_LOGGER.rate_idx = curr_rate_idx;
+	}
+
+	wrs_params->table[up_rate_idx].rate_down.time_th = wrs_db->time_th_max_up;
+
+	cl_wrs_cntrs_reset(wrs_sta, wrs_params);
+	cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params, WRS_DECISION_UP_MCS1, up_rate_idx);
+	cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+				  up_rate_idx, true, wrs_params->is_mu_valid);
+
+	if (wrs_params->is_logger_en)
+		wrs_params->logger_idx = WRS_INC_POW2(wrs_params->logger_idx,
+						      wrs_params->logger_size);
+
+	return true;
+}
+
+void cl_wrs_rate_param_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+			   struct cl_wrs_params *wrs_params,
+			   struct cl_wrs_rate_params *rate_params,
+			   struct cl_wrs_rate *rate_fallback,
+			   bool mu_mimo_valid, bool set_su)
+{
+	struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+	struct cl_wrs_info *wrs_info = NULL;
+	u8 op_mode = 0;
+	u8 ltf = 0;
+	u8 ltf_fallback = 0;
+	u8 sta_idx = cl_sta->sta_idx;
+	union cl_rate_ctrl_info rate_ctrl;
+	union cl_rate_ctrl_info rate_ctrl_fallback;
+	union cl_rate_ctrl_info_he rate_ctrl_he;
+
+	rate_ctrl_he.word = 0;
+	wrs_info = cl_wrs_info_get(cl_sta, wrs_params->type);
+
+	wrs_params->data_rate = cl_data_rates_get(rate_params->mode,
+						  rate_params->bw,
+						  rate_params->nss,
+						  rate_params->mcs,
+						  rate_params->gi);
+
+	/*
+	 * Trying to transmit MU-MIMO in bw < bw of sounding (which is STA's max bw) will fail,
+	 * So we prevent it from being transmitted with MU.
+	 */
+	if (rate_params->bw != cl_sta->sta->bandwidth)
+		mu_mimo_valid = false;
+
+	rate_ctrl.word = cl_rate_ctrl_generate(cl_hw, cl_sta, rate_params->mode,
+					       rate_params->bw, rate_params->nss,
+					       rate_params->mcs, rate_params->gi,
+					       rate_params->fallback_en, mu_mimo_valid);
+
+	/* For fallback rate use same mode (if it is NULL use same rate). */
+	if (rate_fallback) {
+		rate_ctrl_fallback.word = cl_rate_ctrl_generate(cl_hw,
+								cl_sta,
+								rate_params->mode,
+								rate_fallback->bw,
+								rate_fallback->nss,
+								rate_fallback->mcs,
+								rate_fallback->gi,
+								rate_params->fallback_en,
+								mu_mimo_valid);
+		ltf_fallback = cl_map_gi_to_ltf(rate_params->mode, rate_fallback->gi);
+	} else {
+		rate_ctrl_fallback.word = rate_ctrl.word;
+	}
+
+	/* Save current BF state and SS for the fallback rate */
+	if (WRS_TYPE_IS_TX_SU(wrs_params)) {
+		struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
+
+		bf_db->is_on = rate_ctrl.field.tx_bf;
+		bf_db->is_on_fallback = rate_ctrl_fallback.field.tx_bf;
+		bf_db->num_ss = rate_params->nss;
+		bf_db->num_ss_fallback = rate_fallback ? rate_fallback->nss : rate_params->nss;
+	}
+
+	/* Reset counters */
+	wrs_info->success = 0;
+	wrs_info->fail = 0;
+
+	/* Mark rate as unsynced */
+	wrs_info->synced = false;
+	wrs_info->quick_rate_check = false;
+	wrs_info->sync_attempts = 0;
+	ltf = cl_map_gi_to_ltf(rate_params->mode, rate_params->gi);
+
+	if (rate_params->mode == WRS_MODE_HE)
+		rate_ctrl_he.field.spatial_conf = RATE_CNTRL_HE_SPATIAL_CONF_DEF;
+
+	/* Send new rate to firmware */
+	if (set_su) {
+		if (WRS_TYPE_IS_TX_SU(wrs_params)) {
+			op_mode = RATE_OP_MODE_STA_SU;
+			cl_msg_tx_update_rate_dl(cl_hw, sta_idx, rate_ctrl.word,
+						 rate_ctrl_fallback.word, rate_params->bw,
+						 op_mode, wrs_params->group_id, mu_mimo_valid,
+						 ltf, ltf_fallback, rate_ctrl_he.word);
+		} else if (WRS_TYPE_IS_RX(wrs_params)) {
+			u8 ul_gi_ltf = CL_TF_GI_TO_GI_LTF(rate_params->gi);
+
+			cl_msg_tx_update_rate_ul(cl_hw, sta_idx, rate_params->bw,
+						 rate_params->nss, rate_params->mcs, ul_gi_ltf);
+		}
+	}
+}
+
+s8 cl_wrs_rssi_eq_calc(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+		       bool read_clear, s8 *sorted_rssi)
+{
+	struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+	struct cl_wrs_rssi *wrs_rssi = &cl_sta->wrs_rssi;
+	int i;
+
+	if (wrs_rssi->cnt == 0) {
+		memcpy(sorted_rssi, cl_sta->last_rssi, cl_hw->num_antennas);
+		goto sort;
+	}
+
+	for (i = 0; i < cl_hw->num_antennas; i++)
+		sorted_rssi[i] = (s8)(wrs_rssi->sum[i] / wrs_rssi->cnt);
+
+	if (read_clear)
+		memset(wrs_rssi, 0, sizeof(struct cl_wrs_rssi));
+
+sort:
+	/* Sort RSSI values in descending order */
+	cl_rssi_sort_descending(sorted_rssi, cl_hw->num_antennas);
+
+	/* Calc equivalent RSSI */
+	return cl_rssi_calc_equivalent(cl_hw, sorted_rssi);
+}
+
+void cl_wrs_cntrs_reset(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+	struct cl_wrs_info *wrs_info = cl_wrs_info_get(cl_sta, wrs_params->type);
+
+	_cl_wrs_cntrs_reset(wrs_info);
+}
+
+struct cl_wrs_info *cl_wrs_info_get(struct cl_sta *cl_sta, u8 type)
+{
+	if (type == WRS_TYPE_TX_SU)
+		return &cl_sta->wrs_info_tx_su;
+	else if (type == WRS_TYPE_RX)
+		return &cl_sta->wrs_info_rx;
+
+	return NULL;
+}
+
+struct cl_wrs_params *cl_wrs_params_get(struct cl_wrs_sta *wrs_sta, u8 type)
+{
+	if (type == WRS_TYPE_TX_SU)
+		return &wrs_sta->tx_su_params;
+	else if (type == WRS_TYPE_RX)
+		return wrs_sta->rx_params;
+
+	return NULL;
+}
+
+void cl_wrs_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr)
+{
+	struct cl_wrs_rate *rate_params = NULL;
+
+	if (!cl_sta ||
+	    !cl_sta->wrs_sta.rx_params ||
+	    rxhdr->format_mod == FORMATMOD_HE_TRIG)
+		return;
+
+	rate_params = &cl_sta->wrs_sta.rx_params->rx_rate_idle;
+
+	rate_params->bw = rxhdr->ch_bw;
+	rate_params->nss = rxhdr->n_sts;
+	rate_params->mcs = rxhdr->mcs;
+	rate_params->gi = rxhdr->gi_type;
+}
+
+bool cl_wrs_set_rate_idle(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_rate *rx_rate_idle = &wrs_params->rx_rate_idle;
+	s8 rssi_sort[MAX_ANTENNAS] = {0};
+	u16 new_rate_idx = 0;
+	u8 decision;
+
+	if (WRS_TYPE_IS_RX(wrs_params) &&
+	    cl_wrs_is_rate_params_valid(rx_rate_idle)) {
+		decision = WRS_DECISION_RX_RATE;
+		if (wrs_params->initial_rate_idx != WRS_INVALID_RATE)
+			new_rate_idx = wrs_params->initial_rate_idx;
+		else
+			/* Get rate from last data packet */
+			new_rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+								   rx_rate_idle->bw,
+								   rx_rate_idle->nss,
+								   rx_rate_idle->mcs,
+								   rx_rate_idle->gi);
+
+		cl_wrs_rx_rate_idle_reset(wrs_params);
+	} else {
+		/* Get rate from rssi */
+		cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+		new_rate_idx = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, wrs_params, rssi_sort);
+		decision = WRS_DECISION_RSSI_MGMT;
+	}
+
+	if (new_rate_idx != wrs_params->rate_idx) {
+		if (wrs_params->is_logger_en) {
+			memset(&WRS_LOGGER, 0, sizeof(struct cl_wrs_logger));
+			WRS_LOGGER.timestamp = jiffies_to_msecs(jiffies);
+			WRS_LOGGER.rate_idx = wrs_params->rate_idx;
+		}
+
+		cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params, decision, new_rate_idx);
+		cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+					  new_rate_idx, false, false);
+	} else {
+		wrs_params->sync = true;
+	}
+
+	return true;
+}
+
+struct cl_wrs_rate_params *cl_wrs_rx_rate_get(struct cl_sta *cl_sta)
+{
+	struct cl_wrs_params *rx_params = cl_sta->wrs_sta.rx_params;
+
+	if (rx_params)
+		return &rx_params->rate_params;
+
+	return NULL;
+}
+
+void cl_wrs_rx_rate_idle_reset(struct cl_wrs_params *rx_params)
+{
+	struct cl_wrs_rate *rate_idle = &rx_params->rx_rate_idle;
+
+	*(u16 *)rate_idle = U16_MAX;
+}
+
+static void cl_wrs_ap_set_bitmap(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db)
+{
+	u8 mcs, bw, nss, rate_idx;
+
+	memset(wrs_db->ap_supported_rates, 0, sizeof(wrs_db->ap_supported_rates));
+
+	for (bw = cl_hw->conf->ci_wrs_min_bw; bw <= wrs_db->max_cap.bw; bw++)
+		for (nss = 0; nss <= wrs_db->max_cap.nss; nss++)
+			for (mcs = 0; mcs <= wrs_db->max_cap.mcs; mcs++) {
+				rate_idx = mcs + (nss * WRS_MCS_MAX);
+				wrs_db->ap_supported_rates[bw] |= BIT(rate_idx);
+			}
+}
+
+void cl_wrs_ap_capab_set(struct cl_hw *cl_hw,
+			 u8 bw,
+			 u8 use_sgi)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_rate *max_cap = &wrs_db->max_cap;
+	u8 conf_nss = cl_hw->conf->ce_tx_nss - 1;
+
+	switch (cl_hw->wireless_mode) {
+	case WIRELESS_MODE_HE:
+	case WIRELESS_MODE_HT_VHT_HE:
+		wrs_db->mode = WRS_MODE_HE;
+		max_cap->bw = bw;
+		max_cap->nss = conf_nss;
+		max_cap->mcs = WRS_MCS_11;
+		max_cap->gi = use_sgi ? WRS_GI_VSHORT : 0;
+		break;
+	case WIRELESS_MODE_HT_VHT:
+		wrs_db->mode = WRS_MODE_VHT;
+		max_cap->bw = bw;
+		max_cap->nss = conf_nss;
+		max_cap->mcs = WRS_MCS_9;
+		max_cap->gi = use_sgi ? WRS_GI_SHORT : 0;
+		break;
+	case WIRELESS_MODE_HT:
+		wrs_db->mode = WRS_MODE_HT;
+		max_cap->bw = min_t(u8, bw, CHNL_BW_80);
+		max_cap->nss = conf_nss;
+		max_cap->mcs = WRS_MCS_7;
+		max_cap->gi = use_sgi ? WRS_GI_SHORT : 0;
+		break;
+	case WIRELESS_MODE_LEGACY:
+	default:
+		if (cl_hw->hw_mode == HW_MODE_B) {
+			wrs_db->mode = WRS_MODE_CCK;
+			max_cap->mcs = WRS_MCS_3;
+		} else {
+			wrs_db->mode = WRS_MODE_OFDM;
+			max_cap->mcs = WRS_MCS_7;
+		}
+
+		max_cap->bw = CHNL_BW_20;
+		max_cap->nss = 0;
+		max_cap->gi = 0;
+		break;
+	}
+
+	if (cl_hw->conf->ci_wrs_max_bw < max_cap->bw) {
+		max_cap->bw = cl_hw->conf->ci_wrs_max_bw;
+		wrs_pr_warn(wrs_db, "Max BW limited to %uMHz\n", BW_TO_MHZ(max_cap->bw));
+	}
+
+	wrs_db->coex_bw = max_t(u8, max_cap->bw, CHNL_BW_40);
+
+	cl_wrs_ap_set_bitmap(cl_hw, wrs_db);
+}
+
+void cl_wrs_ap_capab_modify_bw(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw)
+{
+	wrs_db->max_cap.bw = max_bw;
+
+	cl_wrs_ap_set_bitmap(cl_hw, wrs_db);
+}
+
+void cl_wrs_ap_capab_modify_gi(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 use_sgi)
+{
+	switch (cl_hw->wireless_mode) {
+	case WIRELESS_MODE_HE:
+	case WIRELESS_MODE_HT_VHT_HE:
+		wrs_db->max_cap.gi = use_sgi ? WRS_GI_VSHORT : 0;
+		break;
+	case WIRELESS_MODE_HT:
+	case WIRELESS_MODE_HT_VHT:
+		wrs_db->max_cap.gi = use_sgi ? WRS_GI_SHORT : 0;
+		break;
+	default:
+		wrs_db->max_cap.gi = 0;
+	}
+
+	cl_wrs_ap_set_bitmap(cl_hw, wrs_db);
+}
+
+void cl_wrs_api_init(struct cl_hw *cl_hw)
+{
+	cl_wrs_init(cl_hw);
+	cl_wrs_ap_capab_set(cl_hw, cl_hw->conf->ci_cap_bandwidth,
+			    cl_hw->conf->ci_short_guard_interval);
+}
+
+void cl_wrs_api_close(struct cl_hw *cl_hw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	del_timer_sync(&wrs_db->timer_maintenance);
+}
+
+void cl_wrs_api_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_wrs_sta_add(cl_hw, sta);
+
+	if (sta->he_cap.has_he && cl_hw->conf->ce_wrs_rx_en)
+		cl_wrs_sta_add_rx(cl_hw, sta);
+
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_wrs_sta_remove(cl_hw, wrs_db, cl_sta);
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bss_set_bw(struct cl_hw *cl_hw, u8 bw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_wrs_ap_capab_modify_bw(cl_hw, wrs_db, bw);
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bss_set_sgi(struct cl_hw *cl_hw, u8 use_sgi)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_wrs_ap_capab_modify_gi(cl_hw, wrs_db, use_sgi);
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+bool cl_wrs_api_bss_is_sgi_en(struct cl_hw *cl_hw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	bool ret = false;
+
+	cl_wrs_lock_bh(wrs_db);
+	ret = wrs_db->max_cap.gi != 0;
+	cl_wrs_unlock_bh(wrs_db);
+
+	return ret;
+}
+
+void cl_wrs_api_bss_capab_update(struct cl_hw *cl_hw, u8 bw, u8 use_sgi)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_wrs_ap_capab_set(cl_hw, bw, use_sgi);
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_nss_or_bw_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 nss, u8 bw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+	cl_wrs_lock_bh(wrs_db);
+
+	wrs_sta->max_rate_cap.nss = nss;
+	wrs_sta->max_rate_cap.bw = bw;
+	cl_wrs_sta_capabilities_set(wrs_db, sta);
+	cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->tx_su_params);
+
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_he_minrate_changed(struct cl_sta *cl_sta, u8 he_minrate)
+{
+	struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u8 mcs = 0, nss = 0, bw = 0;
+	u16 data_rate_x10 = 0;
+
+	cl_wrs_lock_bh(wrs_db);
+
+	wrs_sta->he_minrate = he_minrate;
+	cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->tx_su_params);
+
+	cl_wrs_unlock_bh(wrs_db);
+
+	for (bw = 0; bw < wrs_sta->max_rate_cap.bw; bw++) {
+		for (nss = 0; nss < wrs_sta->max_rate_cap.nss; nss++) {
+			for (mcs = 0; mcs < wrs_sta->max_rate_cap.mcs; mcs++) {
+				data_rate_x10 = cl_data_rates_get_x10(WRS_MODE_HE, bw,
+								      nss, mcs,
+								      WRS_GI_LONG);
+				if (data_rate_x10 >= (he_minrate * 10)) {
+					cl_rate_ctrl_set_default_per_he_minrate(cl_hw, bw,
+										nss, mcs,
+										WRS_GI_LONG);
+					return;
+				}
+			}
+		}
+	}
+}
+
+static void _cl_wrs_api_recovery(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+				 struct cl_wrs_params *wrs_params)
+{
+	u16 fallback_rate_idx = wrs_params->table[wrs_params->rate_idx].rate_down.rate_idx;
+	struct cl_wrs_rate *rate_fallback = &wrs_params->table[fallback_rate_idx].rate;
+	struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+	bool is_mu_valid = wrs_params->is_mu_valid;
+
+	cl_wrs_rate_param_set(cl_hw, wrs_sta, wrs_params, rate_params,
+			      rate_fallback, is_mu_valid, true);
+}
+
+void cl_wrs_api_recovery(struct cl_hw *cl_hw)
+{
+	struct cl_sta *cl_sta = NULL;
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_sta *wrs_sta = NULL;
+
+	cl_wrs_lock_bh(wrs_db);
+	cl_sta_lock(cl_hw);
+
+	list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+		wrs_sta = &cl_sta->wrs_sta;
+
+		_cl_wrs_api_recovery(cl_hw, wrs_sta, &wrs_sta->tx_su_params);
+
+		if (wrs_sta->rx_params)
+			_cl_wrs_api_recovery(cl_hw, wrs_sta, wrs_sta->rx_params);
+	}
+
+	cl_sta_unlock(cl_hw);
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_beamforming_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_params *wrs_params = &cl_sta->wrs_sta.tx_su_params;
+	u8 up_idx = 0;
+	u16 rate_idx = wrs_params->rate_idx;
+
+	cl_wrs_lock(wrs_db);
+
+	for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++)
+		wrs_params->table[rate_idx].rate_up[up_idx].time_th = WRS_INIT_MSEC_WEIGHT_UP;
+
+	cl_wrs_unlock(wrs_db);
+
+	wrs_pr_info(wrs_db, "[%s] sta %u - beamforming sync\n",
+		    WRS_TYPE_STR(wrs_params->type), cl_sta->sta_idx);
+}
+
+void cl_wrs_api_quick_down_check(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				 struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock(wrs_db);
+	cl_wrs_quick_down_check(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+	cl_wrs_unlock(wrs_db);
+}
+
+void cl_wrs_api_rate_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			  struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	cl_wrs_lock(wrs_db);
+	cl_wrs_rate_param_sync(wrs_db, &cl_sta->wrs_sta, wrs_params);
+	cl_wrs_unlock(wrs_db);
+}
+
+bool cl_wrs_api_up_mcs1(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	bool result = false;
+
+	cl_wrs_lock(wrs_db);
+	result = cl_wrs_up_mcs1(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+	cl_wrs_unlock(wrs_db);
+
+	return result;
+}
+
+void cl_wrs_api_set_smps_mode(struct cl_hw *cl_hw, struct ieee80211_sta *sta, const u8 bw)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u8 min_bw;
+
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC ||
+	    sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
+		/* If RTS is enabled, there is no need to go down to 1ss */
+		if (cl_prot_mode_get(cl_hw) == TXL_PROT_RTS_FW)
+			return;
+
+		wrs_sta->smps_enable = true;
+	} else if (sta->smps_mode == IEEE80211_SMPS_OFF && wrs_sta->smps_enable) {
+		wrs_sta->smps_enable = false;
+	}
+
+	cl_wrs_lock_bh(wrs_db);
+	min_bw = min_t(u8, bw, wrs_db->max_cap.bw);
+
+	if (wrs_sta->max_rate_cap.bw != min_bw) {
+		wrs_sta->max_rate_cap.bw = min_bw;
+		wrs_pr_trace(wrs_db, "[TX_SU] SMPS mode: sta %u, bw %u\n",
+			     wrs_sta->sta_idx, min_bw);
+		cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->tx_su_params);
+	}
+
+	cl_wrs_unlock_bh(wrs_db);
+}
+
+u16 cl_wrs_api_get_tx_sta_data_rate(struct cl_sta *cl_sta)
+{
+		return cl_sta->wrs_sta.tx_su_params.data_rate;
+}
+
+static enum rate_info_bw cl_wrs_mode_to_nl80211_rateinfo_bw(u8 bw)
+{
+	switch (bw) {
+	case CHNL_BW_20:
+		return RATE_INFO_BW_20;
+	case CHNL_BW_40:
+		return RATE_INFO_BW_40;
+	case CHNL_BW_80:
+		return RATE_INFO_BW_80;
+	case CHNL_BW_160:
+		return RATE_INFO_BW_160;
+	default:
+		return RATE_INFO_BW_20;
+	}
+}
+
+void cl_wrs_fill_sinfo_rates(struct rate_info *rate_info,
+			     const struct cl_wrs_params *wrs_params,
+			     const struct cl_sta *sta)
+{
+	rate_info->bw = cl_wrs_mode_to_nl80211_rateinfo_bw(wrs_params->rate_params.bw);
+	rate_info->mcs = wrs_params->rate_params.mcs;
+	rate_info->nss = wrs_params->rate_params.nss + 1;
+	rate_info->he_gi = wrs_params->rate_params.gi;
+
+	rate_info->flags = 0;
+	/* GI = 0.4 us */
+	if (wrs_params->rate_params.mode < WRS_MODE_HE && wrs_params->rate_params.gi == 1)
+		rate_info->flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+	if (wrs_params->rate_params.mode == WRS_MODE_HT)
+		rate_info->flags |= RATE_INFO_FLAGS_MCS;
+
+	if (wrs_params->rate_params.mode == WRS_MODE_VHT)
+		rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS;
+
+	if (wrs_params->rate_params.mode == WRS_MODE_HE) {
+		enum cl_mu_ofdma_ru_type ru_type = sta->rate_ctrl_he.field.ru_type;
+
+		rate_info->flags |= RATE_INFO_FLAGS_HE_MCS;
+		if (ru_type) {
+			rate_info->he_ru_alloc = cl_ru_type_to_nl80211_he_ru_alloc(ru_type);
+			rate_info->bw = RATE_INFO_BW_HE_RU;
+		}
+	}
+}
+
+/*
+ * Section #1:
+ * rate based on rssi.
+ */
+static s8 rssi_threshold_he[WRS_MCS_MAX_HE] = {
+	-35, -40, -45, -50, -55, -60, -65, -70, -75, -80, -85, -90
+};
+
+static s8 rssi_threshold_vht[WRS_MCS_MAX_VHT] = {
+	-36, -42, -48, -54, -60, -66, -72, -78, -84, -90
+};
+
+static s8 rssi_threshold_ht[WRS_MCS_MAX_HT] = {
+	-34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_ofdm[WRS_MCS_MAX_OFDM] = {
+	-34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_cck[WRS_MCS_MAX_CCK] = {
+	-45, -60, -75, -90
+};
+
+static u16 cl_wrs_rssi_find_rate_ht_vht_he(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+					   struct cl_wrs_sta *wrs_sta,
+					   struct cl_wrs_params *wrs_params,
+					   s8 *rssi_sort,
+					   s8 *thresholds)
+{
+	s8 max_ss = (s8)wrs_sta->max_rate_cap.nss;
+	s8 nss = 0;
+	u8 max_bw = wrs_sta->max_rate_cap.bw;
+	u8 bw = 0;
+	u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+	u8 mcs = 0;
+	u8 gi = WRS_GI_LONG;
+	u8 selected_mcs = 0;
+	u8 selected_nss = 0;
+	u8 selected_bw = 0;
+	u8 i = 0;
+	u16 rate_idx = 0;
+	u16 data_rate = 0;
+	u16 max_data_rate = 0;
+
+	if (max_bw > cl_hw->conf->ci_wrs_max_bw)
+		max_bw = cl_hw->conf->ci_wrs_max_bw;
+
+	for (i = 0; i <= max_mcs; i++) {
+		mcs = max_mcs - i;
+
+		for (nss = max_ss; nss >= 0; nss--) {
+			if (rssi_sort[nss] <= thresholds[i])
+				continue;
+
+			/* In last level decrease BW */
+			bw = ((i == max_mcs) && (max_bw > CHNL_BW_20)) ? (max_bw - 1) : max_bw;
+
+			if (wrs_sta->mode == WRS_MODE_HE) {
+				data_rate = data_rate_he_x10[nss][bw][mcs][WRS_GI_LONG];
+			} else {
+				if (wrs_sta->mode == WRS_MODE_VHT) {
+					/* 160MHz in VHT is valid only for 1/2 SS */
+					if (nss >= WRS_SS_3 && bw == CHNL_BW_160)
+						bw = CHNL_BW_80;
+
+					/* BW 80, 3 SS MCS 6 is invalid in VHT */
+					if (bw == CHNL_BW_80 &&
+					    nss == WRS_SS_3 &&
+					    mcs == WRS_MCS_6)
+						continue;
+				}
+
+				data_rate = data_rate_ht_vht_x10[bw][nss][mcs][gi];
+			}
+
+			if (data_rate > max_data_rate) {
+				selected_mcs = mcs;
+				selected_nss = nss;
+				selected_bw = bw;
+				max_data_rate = data_rate;
+				rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+								       bw, nss, mcs, gi);
+			}
+
+			break;
+		}
+	}
+
+	return rate_idx;
+}
+
+static u16 cl_wrs_rssi_find_rate_cck_ofdm(struct cl_wrs_sta *wrs_sta,
+					  s8 *rssi_sort, s8 *thresholds)
+{
+	struct cl_wrs_params *wrs_params = &wrs_sta->tx_su_params;
+	u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+	u8 mcs = 0;
+	u8 i = 0;
+
+	for (i = 0; i <= max_mcs; i++) {
+		mcs = max_mcs - i;
+
+		if (rssi_sort[WRS_SS_1] > thresholds[i])
+			return cl_wrs_tables_find_rate_idx(wrs_params,
+							   CHNL_BW_20, WRS_SS_1, mcs, WRS_GI_LONG);
+	}
+
+	return 0;
+}
+
+u16 cl_wrs_rssi_find_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta,
+			  struct cl_wrs_params *wrs_params,
+			  s8 *rssi_sort)
+{
+	u16 rate_idx = 0;
+
+	if (wrs_params->initial_rate_idx != WRS_INVALID_RATE)
+		return wrs_params->initial_rate_idx;
+
+	switch (wrs_sta->mode) {
+	case WRS_MODE_HE:
+		rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta, wrs_params,
+							   rssi_sort, rssi_threshold_he);
+		break;
+	case WRS_MODE_VHT:
+		rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta, wrs_params,
+							   rssi_sort, rssi_threshold_vht);
+		break;
+	case WRS_MODE_HT:
+		rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta, wrs_params,
+							   rssi_sort, rssi_threshold_ht);
+		break;
+	case WRS_MODE_OFDM:
+		rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+							  rssi_threshold_ofdm);
+		break;
+	case WRS_MODE_CCK:
+		rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+							  rssi_threshold_cck);
+		break;
+	default:
+		break;
+	}
+
+	if (rate_idx == WRS_INVALID_RATE)
+		rate_idx = 0;
+
+	wrs_pr_trace(wrs_db,
+		     "[%s] Select rate based rssi - sta=%u, rssi [%d,%d,%d,%d], "
+		     "rate_idx=%u, bw=%u, nss=%u, mcs=%u\n",
+		     WRS_TYPE_STR(wrs_params->type),
+		     wrs_sta->sta_idx,
+		     rssi_sort[0],
+		     rssi_sort[1],
+		     rssi_sort[2],
+		     rssi_sort[3],
+		     rate_idx,
+		     wrs_params->table[rate_idx].rate.bw,
+		     wrs_params->table[rate_idx].rate.nss,
+		     wrs_params->table[rate_idx].rate.mcs);
+
+	return rate_idx;
+}
+
+/*
+ * Section #2:
+ * rssi protect.
+ */
+static void cl_wrs_rssi_prot_set_avg(struct cl_wrs_sta *wrs_sta, s8 avg)
+{
+	struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+
+	memset(rssi_prot_db->samples_old, avg, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+	memset(rssi_prot_db->samples_new, avg, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+	rssi_prot_db->sum = avg << WRS_RSSI_PROTECT_SHIFT;
+}
+
+static s8 cl_wrs_rssi_prot_add_smpl(struct cl_wrs_sta *wrs_sta, s8 rssi_eq)
+{
+	struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+	u8 curr_idx_old = rssi_prot_db->curr_idx_old;
+	u8 curr_idx_new = rssi_prot_db->curr_idx_new;
+
+	rssi_prot_db->sum +=
+		rssi_prot_db->samples_new[curr_idx_new] - rssi_prot_db->samples_old[curr_idx_old];
+	rssi_prot_db->samples_old[curr_idx_old] = rssi_prot_db->samples_new[curr_idx_new];
+	rssi_prot_db->samples_new[curr_idx_new] = rssi_eq;
+
+	rssi_prot_db->curr_idx_old =
+		WRS_INC_POW2(rssi_prot_db->curr_idx_old, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+	WRS_INC(rssi_prot_db->curr_idx_new, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+
+	return (s8)(wrs_sta->rssi_prot_db.sum >> WRS_RSSI_PROTECT_SHIFT);
+}
+
+static bool cl_wrs_rssi_prot_decision_up(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+					 struct cl_wrs_sta *wrs_sta,
+					 struct cl_wrs_params *wrs_params,
+					 s8 rssi_avg, s8 rssi_eq,
+					 s8 *rssi_sort, u8 up_rate_idx)
+{
+	/* Decide UP only if all new samples are greater than old average */
+	s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+	s8 up_thr = rssi_avg + wrs_db->rssi_protect_up_thr;
+	u8 i = 0;
+
+	for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+		if (samples_new[i] <= up_thr)
+			return false;
+
+	if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+		u16 rate_idx_old = wrs_params->rate_idx;
+		u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta,
+							 wrs_params, rssi_sort);
+		struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+		struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+		u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+							  rate_old->nss, rate_old->mcs,
+							  rate_old->gi);
+		u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+							  rate_new->nss, rate_new->mcs,
+							  rate_new->gi);
+
+		if (rate_idx_old == rate_idx_new || data_rate_old >= data_rate_new)
+			rate_idx_new = up_rate_idx;
+
+		wrs_pr_info(wrs_db, "[%s] Increase rate based on RSSI - old [%u], new [%u]\n",
+			    WRS_TYPE_STR(wrs_params->type), rate_idx_old, rate_idx_new);
+		cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+				       WRS_DECISION_UP_RSSI, rate_idx_new);
+		cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta,
+					  wrs_params, rate_idx_new, true, false);
+	} else {
+		cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+				     WRS_DECISION_UP_RSSI, up_rate_idx);
+	}
+
+	cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+	cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+	return true;
+}
+
+static bool cl_wrs_rssi_prot_decision_down(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+					   struct cl_wrs_sta *wrs_sta,
+					   struct cl_wrs_params *wrs_params,
+					   s8 rssi_avg, s8 rssi_eq,
+					   s8 *rssi_sort, u8 down_rate_idx)
+{
+	/* Decide DOWN only if all new samples are smaller than old average */
+	s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+	s8 dn_thr = rssi_avg - wrs_db->rssi_protect_dn_thr;
+	u8 i = 0;
+
+	if (wrs_params->rate_idx == 0)
+		return false;
+
+	for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+		if (samples_new[i] >= dn_thr)
+			return false;
+
+	if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+		u16 rate_idx_old = wrs_params->rate_idx;
+		u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta,
+							 wrs_params, rssi_sort);
+		struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+		struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+		u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+							  rate_old->nss, rate_old->mcs,
+							  rate_old->gi);
+		u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+							  rate_new->nss, rate_new->mcs,
+							  rate_new->gi);
+
+		if (rate_idx_old == rate_idx_new || data_rate_old <= data_rate_new)
+			rate_idx_new = down_rate_idx;
+
+		wrs_pr_info(wrs_db, "[%s] Decrease rate based on RSSI - old [%u], new [%u]\n",
+			    WRS_TYPE_STR(wrs_params->type), rate_idx_old, rate_idx_new);
+		cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+				       WRS_DECISION_DOWN_RSSI, rate_idx_new);
+		cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+					  rate_idx_new, true, false);
+	} else {
+		cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+				     WRS_DECISION_DOWN_RSSI, down_rate_idx);
+	}
+
+	cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+	cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+	return true;
+}
+
+void cl_wrs_rssi_prot_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	s8 rssi_sort[MAX_ANTENNAS] = {0};
+	s8 rssi_eq = 0;
+
+	if (!cl_hw->wrs_db.rssi_protect_en)
+		return;
+
+	rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, false, rssi_sort);
+	cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+}
+
+bool cl_wrs_rssi_prot_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			       struct cl_wrs_sta *wrs_sta,
+			       struct cl_wrs_params *wrs_params,
+			       bool up_rate_valid,
+			       u8 up_rate_idx, u8 down_rate_idx)
+{
+	s8 rssi_avg = 0;
+	s8 rssi_eq = 0;
+	s8 rssi_sort[MAX_ANTENNAS] = {0};
+
+	rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+	rssi_avg = cl_wrs_rssi_prot_add_smpl(wrs_sta, rssi_eq);
+
+	if (up_rate_valid)
+		if (cl_wrs_rssi_prot_decision_up(cl_hw, wrs_db, wrs_sta, wrs_params, rssi_avg,
+						 rssi_eq, rssi_sort, up_rate_idx))
+			return true;
+
+	return cl_wrs_rssi_prot_decision_down(cl_hw, wrs_db, wrs_sta, wrs_params, rssi_avg,
+					      rssi_eq, rssi_sort, down_rate_idx);
+}
+
+static void cl_wrs_sta_info_set_he(struct cl_wrs_sta *wrs_sta)
+{
+	wrs_sta->mode = WRS_MODE_HE;
+
+	wrs_sta->gi_cap[CHNL_BW_20] = WRS_GI_VSHORT;
+	wrs_sta->gi_cap[CHNL_BW_40] = WRS_GI_VSHORT;
+	wrs_sta->gi_cap[CHNL_BW_80] = WRS_GI_VSHORT;
+	wrs_sta->gi_cap[CHNL_BW_160] = WRS_GI_VSHORT;
+}
+
+static void cl_wrs_sta_info_set_vht(struct cl_wrs_sta *wrs_sta,
+				    struct ieee80211_sta_vht_cap *vht_cap,
+				    struct ieee80211_sta_ht_cap *ht_cap)
+{
+	wrs_sta->mode = WRS_MODE_VHT;
+
+	wrs_sta->gi_cap[CHNL_BW_20] =
+		(ht_cap->cap & IEEE80211_HT_CAP_SGI_20) ? WRS_GI_SHORT : WRS_GI_LONG;
+	wrs_sta->gi_cap[CHNL_BW_40] =
+		(ht_cap->cap & IEEE80211_HT_CAP_SGI_40) ? WRS_GI_SHORT : WRS_GI_LONG;
+	wrs_sta->gi_cap[CHNL_BW_80] =
+		(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80) ? WRS_GI_SHORT : WRS_GI_LONG;
+	wrs_sta->gi_cap[CHNL_BW_160] =
+		(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160) ? WRS_GI_SHORT : WRS_GI_LONG;
+}
+
+static void cl_wrs_sta_info_set_ht(struct cl_wrs_sta *wrs_sta,
+				   struct ieee80211_sta_ht_cap *ht_cap)
+{
+	wrs_sta->mode = WRS_MODE_HT;
+
+	wrs_sta->gi_cap[CHNL_BW_20] =
+		(ht_cap->cap & IEEE80211_HT_CAP_SGI_20) ? WRS_GI_SHORT : WRS_GI_LONG;
+	wrs_sta->gi_cap[CHNL_BW_40] =
+		(ht_cap->cap & IEEE80211_HT_CAP_SGI_40) ? WRS_GI_SHORT : WRS_GI_LONG;
+}
+
+static void cl_wrs_sta_info_set_legacy(struct cl_wrs_sta *wrs_sta,
+				       struct ieee80211_sta *sta)
+{
+	if (sta->supp_rates[NL80211_BAND_5GHZ] ||
+	    (sta->supp_rates[NL80211_BAND_2GHZ] & 0xFF0))
+		wrs_sta->mode = WRS_MODE_OFDM;
+	else
+		wrs_sta->mode = WRS_MODE_CCK;
+}
+
+static void cl_wrs_sta_info_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+				struct ieee80211_sta *sta)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+	struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+	u8 bw = min_t(u8, sta->bandwidth, wrs_db->max_cap.bw);
+
+	if (he_cap->has_he)
+		cl_wrs_sta_info_set_he(wrs_sta);
+	else if (vht_cap->vht_supported && ht_cap->ht_supported)
+		cl_wrs_sta_info_set_vht(wrs_sta, vht_cap, ht_cap);
+	else if (ht_cap->ht_supported)
+		cl_wrs_sta_info_set_ht(wrs_sta, ht_cap);
+	else
+		cl_wrs_sta_info_set_legacy(wrs_sta, sta);
+
+	wrs_sta->max_rate_cap.nss = min_t(u8, sta->rx_nss, WRS_SS_MAX) - 1;
+
+	if (cl_band_is_24g(cl_hw))
+		wrs_sta->max_rate_cap.bw = min(bw, wrs_db->coex_bw);
+	else
+		wrs_sta->max_rate_cap.bw = bw;
+
+	wrs_sta->assoc_bw = bw;
+}
+
+#define TWO_BITS_MASK 0x3
+
+static u8 cl_wrs_calc_max_nss(u16 rx_mcs, u8 max_nss)
+{
+	u8 i, nss = 0;
+
+	for (i = 0; i <= max_nss; i++) {
+		if (((rx_mcs >> (2 * i)) & TWO_BITS_MASK) != IEEE80211_HE_MCS_NOT_SUPPORTED)
+			nss++;
+		else
+			break;
+	}
+
+	return nss;
+}
+
+static void cl_supported_rates_he_cap(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = (struct cl_sta *)sta->drv_priv;
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	struct ieee80211_he_mcs_nss_supp *mcs_nss = &sta->he_cap.he_mcs_nss_supp;
+	int mcs = 0;
+	int supported_mcs = 0;
+	u16 rx_mcs = 0;
+	u8 max_nss = wrs_sta->max_rate_cap.nss;
+	u8 nss = 0, bw = 0;
+	u8 max_nss_80, max_nss_160;
+
+	for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++) {
+		if (bw < CHNL_BW_160) {
+			rx_mcs = le16_to_cpu(mcs_nss->rx_mcs_80);
+		} else if (bw == CHNL_BW_160) {
+			max_nss_80 = cl_wrs_calc_max_nss(le16_to_cpu(mcs_nss->rx_mcs_80),
+							 max_nss) + 1;
+			rx_mcs = le16_to_cpu(mcs_nss->rx_mcs_160);
+			max_nss_160 = cl_wrs_calc_max_nss(rx_mcs, max_nss) + 1;
+			max_nss = max_nss * max_nss_160 / max_nss_80;
+		} else {
+			wrs_pr_err(wrs_db, "bw %u is not supported\n", bw);
+		}
+
+		for (nss = 0; nss <= max_nss; nss++) {
+			switch ((rx_mcs >> (2 * nss)) & TWO_BITS_MASK) {
+			case IEEE80211_HE_MCS_SUPPORT_0_7:
+				supported_mcs = WRS_MCS_7;
+				break;
+			case IEEE80211_HE_MCS_SUPPORT_0_9:
+				supported_mcs = WRS_MCS_9;
+				break;
+			case IEEE80211_HE_MCS_SUPPORT_0_11:
+				supported_mcs = WRS_MCS_11;
+				break;
+			case IEEE80211_HE_MCS_NOT_SUPPORTED:
+				supported_mcs = -1;
+				break;
+			}
+
+			for (mcs = 0; mcs <= supported_mcs; mcs++)
+				cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+		}
+	}
+}
+
+static void cl_supported_rates_vht_cap(struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map);
+	u8 bw = 0;
+	u8 nss = 0;
+	int mcs = 0;
+	int supported_mcs = 0;
+
+	for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++) {
+		for (nss = 0; nss <= wrs_sta->max_rate_cap.nss; nss++) {
+			switch ((mcs_map >> (2 * nss)) & TWO_BITS_MASK) {
+			case 0:
+				supported_mcs = WRS_MCS_7;
+				break;
+			case 1:
+				supported_mcs = WRS_MCS_8;
+				break;
+			case 2:
+				supported_mcs = WRS_MCS_9;
+				break;
+			case 3:
+				supported_mcs = -1;
+				break;
+			}
+
+			for (mcs = 0; mcs <= supported_mcs; mcs++)
+				cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+		}
+	}
+}
+
+static void cl_supported_rates_ht_cap(struct ieee80211_sta *sta)
+{
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u8 bw = 0;
+	u8 nss = 0;
+	u8 mcs = 0;
+
+	for (mcs = 0; mcs <= WRS_MCS_7; mcs++) {
+		for (nss = 0; nss <= wrs_sta->max_rate_cap.nss; nss++) {
+			if ((ht_cap->mcs.rx_mask[nss] & (1 << mcs)) == 0)
+				continue;
+
+			for (bw = 0; bw <= wrs_sta->max_rate_cap.bw; bw++)
+				cl_wrs_sta_set_supported_rate(wrs_sta, bw, nss, mcs);
+		}
+	}
+}
+
+static void cl_supported_rates_legacy_cap(struct cl_hw *cl_hw,
+					  struct ieee80211_sta *sta,
+					  u8 max_mcs)
+{
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	u8 mcs = 0;
+
+	for (mcs = 0; mcs < max_mcs; mcs++)
+		if (rate_supported(sta, cl_hw->nl_band, mcs))
+			cl_wrs_sta_set_supported_rate(wrs_sta, CHNL_BW_20, WRS_SS_1, mcs);
+}
+
+void cl_wrs_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	struct cl_wrs_params *wrs_params = &wrs_sta->tx_su_params;
+
+	wrs_params->type = WRS_TYPE_TX_SU;
+	wrs_params->is_mu_valid = false;
+	wrs_params->rate_idx = WRS_INVALID_RATE;
+	wrs_params->initial_rate_idx = WRS_INVALID_RATE;
+
+	wrs_sta->sta_idx = cl_sta->sta_idx;
+	cl_wrs_rssi_prot_start(cl_hw, cl_sta);
+	cl_wrs_stats_per_init(wrs_params);
+	cl_wrs_sta_info_set(cl_hw, wrs_sta, sta);
+	cl_wrs_sta_capabilities_set(wrs_db, sta);
+	cl_wrs_tables_build(cl_hw, wrs_sta, wrs_params);
+	cl_wrs_sta_select_first_rate(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+	wrs_pr_trace(wrs_db, "[%s] Add station %pM to database (sta_idx %u)\n",
+		     WRS_TYPE_STR(wrs_params->type), cl_sta->addr, cl_sta->sta_idx);
+}
+
+void cl_wrs_sta_add_rx(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+	struct cl_wrs_params *wrs_params;
+
+	if (wrs_sta->rx_params) {
+		wrs_pr_warn(wrs_db, "[RX] Params already allocated (sta_idx %u)\n",
+			    wrs_sta->sta_idx);
+		return;
+	}
+
+	wrs_params = kzalloc(sizeof(*wrs_params), GFP_ATOMIC);
+
+	if (!wrs_params)
+		return;
+
+	wrs_sta->rx_params = wrs_params;
+	wrs_params->type = WRS_TYPE_RX;
+	wrs_params->is_mu_valid = false;
+	wrs_params->rate_idx = WRS_INVALID_RATE;
+	wrs_params->initial_rate_idx = WRS_INVALID_RATE;
+
+	wrs_sta->sta_idx = cl_sta->sta_idx;
+
+	cl_wrs_rssi_prot_start(cl_hw, cl_sta);
+	cl_wrs_stats_per_init(wrs_params);
+	cl_wrs_sta_info_set(cl_hw, wrs_sta, sta);
+	cl_wrs_sta_capabilities_set(wrs_db, sta);
+	cl_wrs_tables_build(cl_hw, wrs_sta, wrs_params);
+	cl_wrs_sta_select_first_rate(cl_hw, wrs_db, wrs_sta, wrs_params);
+	cl_wrs_rx_rate_idle_reset(wrs_params);
+
+	wrs_pr_trace(wrs_db, "[%s] Add station %pM to database (sta_idx %u)\n",
+		     WRS_TYPE_STR(wrs_params->type), cl_sta->addr, cl_sta->sta_idx);
+}
+
+static void _cl_wrs_sta_remove(struct cl_wrs_params *wrs_params)
+{
+	if (wrs_params->is_logger_en) {
+		kfree(wrs_params->logger);
+		wrs_params->logger = NULL;
+	}
+
+	kfree(wrs_params->table);
+	wrs_params->table = NULL;
+
+	cl_wrs_stats_per_remove(wrs_params);
+}
+
+static void cl_wrs_sta_remove_rx(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta)
+{
+	struct cl_wrs_params *wrs_params = wrs_sta->rx_params;
+
+	if (!wrs_params) {
+		wrs_pr_warn(wrs_db, "[RX] Params already removed (sta_idx %u)\n",
+			    wrs_sta->sta_idx);
+		return;
+	}
+
+	_cl_wrs_sta_remove(wrs_params);
+
+	kfree(wrs_params);
+	wrs_sta->rx_params = NULL;
+
+	wrs_pr_err(wrs_db, "[RX] Remove params (sta_idx %u)\n", wrs_sta->sta_idx);
+}
+
+void cl_wrs_sta_remove(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, struct cl_sta *cl_sta)
+{
+	struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+	_cl_wrs_sta_remove(&wrs_sta->tx_su_params);
+
+	if (wrs_sta->rx_params)
+		cl_wrs_sta_remove_rx(wrs_db, wrs_sta);
+	wrs_pr_trace(wrs_db, "Remove station %pM from database (sta_idx %u)\n",
+		     cl_sta->addr, cl_sta->sta_idx);
+}
+
+struct cl_wrs_sta *cl_wrs_sta_get(struct cl_hw *cl_hw, u8 sta_idx)
+{
+	struct cl_sta *cl_sta = cl_sta_get(cl_hw, sta_idx);
+
+	return cl_sta ? &cl_sta->wrs_sta : NULL;
+}
+
+void cl_wrs_sta_select_first_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+				  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params)
+{
+	if (wrs_db->is_fixed_rate) {
+		s8 *fixed_rate = cl_hw->conf->ci_wrs_fixed_rate;
+
+		cl_wrs_fixed_rate_set(cl_hw, wrs_db, wrs_sta, wrs_params, wrs_db->is_fixed_rate,
+				      fixed_rate[WRS_FIXED_PARAM_MODE],
+				      fixed_rate[WRS_FIXED_PARAM_BW],
+				      fixed_rate[WRS_FIXED_PARAM_NSS],
+				      fixed_rate[WRS_FIXED_PARAM_MCS],
+				      fixed_rate[WRS_FIXED_PARAM_GI], 0);
+	} else {
+		struct cl_sta *cl_sta = container_of(wrs_sta, struct cl_sta, wrs_sta);
+		struct cl_wrs_rate_params *vif_fixed_params = &cl_sta->cl_vif->fixed_params;
+
+		if (vif_fixed_params->is_fixed)
+			cl_wrs_fixed_rate_set(cl_hw, wrs_db, wrs_sta, wrs_params,
+					      WRS_FIXED_FALLBACK_DIS,
+					      vif_fixed_params->mode,
+					      vif_fixed_params->bw,
+					      vif_fixed_params->nss,
+					      vif_fixed_params->mcs,
+					      vif_fixed_params->gi, 0);
+	}
+
+	if (!wrs_params->is_fixed_rate) {
+		bool result = cl_wrs_set_rate_idle(cl_hw, wrs_db, wrs_sta, wrs_params);
+
+		/*
+		 * If new rate wasn't selected according to
+		 * rssi (no samples) or data packets set rate to lowest possible
+		 */
+		if (!result)
+			cl_wrs_rate_params_update(cl_hw, wrs_db, wrs_sta,
+						  wrs_params, 0, false, false);
+	}
+}
+
+void cl_wrs_sta_capabilities_set(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta)
+{
+	struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+	enum cl_wrs_mode mode = cl_sta->wrs_sta.mode;
+
+	if (mode == WRS_MODE_HE) {
+		cl_supported_rates_he_cap(wrs_db, sta);
+	} else if (mode == WRS_MODE_VHT) {
+		cl_supported_rates_vht_cap(sta);
+	} else if (mode == WRS_MODE_HT) {
+		cl_supported_rates_ht_cap(sta);
+	} else {
+		struct cl_hw *cl_hw = cl_sta->cl_vif->cl_hw;
+		u8 max_mcs = (mode == WRS_MODE_OFDM) ? WRS_MCS_MAX_OFDM : WRS_MCS_MAX_CCK;
+
+		cl_supported_rates_legacy_cap(cl_hw, sta, max_mcs);
+	}
+}
+
+void cl_wrs_sta_set_supported_rate(struct cl_wrs_sta *wrs_sta, u8 bw, u8 nss, u8 mcs)
+{
+	u8 rate_idx = mcs + (nss * WRS_MCS_MAX);
+
+	wrs_sta->supported_rates[bw] |= BIT(rate_idx);
+}
+
+static struct cl_wrs_per_stats *cl_wrs_stats_per_entry(struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_per_stats *per_stats = NULL, *per_stats_new = NULL;
+	struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+	struct list_head *list_rates = &wrs_params->list_rates;
+	u8 bw = rate_params->bw;
+	u8 nss = rate_params->nss;
+	u8 mcs = rate_params->mcs;
+	u8 gi = rate_params->gi;
+
+	list_for_each_entry(per_stats, list_rates, list) {
+		if (per_stats->bw != bw ||
+		    per_stats->nss != nss ||
+		    per_stats->mcs != mcs ||
+		    per_stats->gi != gi)
+			continue;
+
+		/*
+		 * Move the entry to the beginning of the list, so that it
+		 * will be faster to find next time.
+		 */
+		if (per_stats != list_entry(list_rates->next, struct cl_wrs_per_stats, list)) {
+			list_del(&per_stats->list);
+			list_add(&per_stats->list, list_rates);
+		}
+
+		return per_stats;
+	}
+
+	/* Entry not found - allocate new entry and add to list */
+	per_stats_new = kzalloc(sizeof(*per_stats_new), GFP_ATOMIC);
+
+	if (!per_stats_new)
+		return NULL;
+
+	per_stats_new->bw = bw;
+	per_stats_new->nss = nss;
+	per_stats_new->mcs = mcs;
+	per_stats_new->gi = gi;
+
+	list_add(&per_stats_new->list, &wrs_params->list_rates);
+
+	return per_stats_new;
+}
+
+void cl_wrs_stats_per_update(struct cl_wrs_db *wrs_db,
+			     struct cl_wrs_sta *wrs_sta,
+			     struct cl_wrs_params *wrs_params,
+			     struct cl_wrs_cntrs *cntrs)
+{
+	u16 curr_rate_idx = wrs_params->rate_idx;
+	struct cl_wrs_table *table_node = &wrs_params->table[curr_rate_idx];
+	struct cl_wrs_per_stats *per_stats = cl_wrs_stats_per_entry(wrs_params);
+
+	if (!per_stats)
+		return;
+
+	wrs_params->frames_total += cntrs->total;
+	wrs_params->fail_total += cntrs->fail;
+	wrs_params->ba_not_rcv_total += cntrs->ba_not_rcv;
+	wrs_params->epr_acc += cntrs->epr_acc;
+
+	per_stats->frames_total += cntrs->total;
+	per_stats->frames_failed += cntrs->fail;
+	per_stats->epr_acc += cntrs->epr_acc;
+
+	if (wrs_params->calc_ba_not_rcv) {
+		per_stats->frames_total += cntrs->ba_not_rcv;
+		per_stats->frames_failed += cntrs->ba_not_rcv;
+	}
+
+	table_node->frames_total = wrs_params->frames_total;
+	table_node->ba_not_rcv_total = wrs_params->ba_not_rcv_total;
+	table_node->epr_acc = wrs_params->epr_acc;
+}
+
+void cl_wrs_stats_per_init(struct cl_wrs_params *wrs_params)
+{
+	INIT_LIST_HEAD(&wrs_params->list_rates);
+}
+
+void cl_wrs_stats_per_remove(struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_per_stats *per_stats = NULL, *per_stats_next = NULL;
+
+	list_for_each_entry_safe(per_stats, per_stats_next, &wrs_params->list_rates, list) {
+		list_del(&per_stats->list);
+		kfree(per_stats);
+	}
+}
+
+static struct cl_wrs_table
+	ap_rate_table_he[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_HE][WRS_GI_MAX_HE];
+static struct cl_wrs_table
+	ap_rate_table_ht_vht[CHNL_BW_MAX][WRS_SS_MAX][WRS_MCS_MAX_VHT][WRS_GI_MAX_VHT];
+
+/* Rate indexes sorted by data rate */
+static u16 rate_idx_sorted_by_data_rate_he[WRS_HE_RATE_TABLE_SIZE] = {0};
+static u16 rate_idx_sorted_by_data_rate_ht_vht[WRS_HT_VHT_RATE_TABLE_SIZE] = {0};
+
+static void cl_wrs_extract_rate_idx_vht(u16 idx, u8 *bw, u8 *nss, u8 *mcs, u8 *gi)
+{
+	*gi = idx % WRS_GI_MAX_VHT;
+	idx = (idx - *gi) / WRS_GI_MAX_VHT;
+	*mcs = idx % WRS_MCS_MAX_VHT;
+	idx = (idx - *mcs) / WRS_MCS_MAX_VHT;
+	*nss = idx % WRS_SS_MAX;
+	*bw = (idx - *nss) / CHNL_BW_MAX;
+}
+
+static void cl_wrs_extract_rate_idx_he(u16 idx, u8 *bw, u8 *nss, u8 *mcs, u8 *gi)
+{
+	*gi = idx % WRS_GI_MAX_HE;
+	idx = (idx - *gi) / WRS_GI_MAX_HE;
+	*mcs = idx % WRS_MCS_MAX_HE;
+	idx = (idx - *mcs) / WRS_MCS_MAX_HE;
+	*nss = idx % WRS_SS_MAX;
+	*bw = (idx - *nss) / CHNL_BW_MAX;
+}
+
+static void cl_wrs_tables_build_sorted_ht_vht(void)
+{
+	/* Sort according to HT/VHT data rate */
+	u16 i, j;
+	u8 bw1, nss1, mcs1, gi1, bw2, nss2, mcs2, gi2;
+
+	for (i = 0; i < WRS_HT_VHT_RATE_TABLE_SIZE; i++)
+		rate_idx_sorted_by_data_rate_ht_vht[i] = i;
+
+	for (i = 0; i < WRS_HT_VHT_RATE_TABLE_SIZE - 1; i++) {
+		for (j = 0; j < WRS_HT_VHT_RATE_TABLE_SIZE - i - 1; j++) {
+			cl_wrs_extract_rate_idx_vht(rate_idx_sorted_by_data_rate_ht_vht[j],
+						    &bw1, &nss1, &mcs1, &gi1);
+			cl_wrs_extract_rate_idx_vht(rate_idx_sorted_by_data_rate_ht_vht[j + 1],
+						    &bw2, &nss2, &mcs2, &gi2);
+
+			if (data_rate_ht_vht_x10[bw1][nss1][mcs1][gi1] >
+			    data_rate_ht_vht_x10[bw2][nss2][mcs2][gi2])
+				swap(rate_idx_sorted_by_data_rate_ht_vht[j],
+				     rate_idx_sorted_by_data_rate_ht_vht[j + 1]);
+		}
+	}
+}
+
+static void cl_wrs_tables_build_sorted_he(void)
+{
+	/* Sort according to HE data rate */
+	u16 i, j;
+	u8 bw1, nss1, mcs1, gi1, bw2, nss2, mcs2, gi2;
+
+	for (i = 0; i < WRS_HE_RATE_TABLE_SIZE; i++)
+		rate_idx_sorted_by_data_rate_he[i] = i;
+
+	for (i = 0; i < WRS_HE_RATE_TABLE_SIZE - 1; i++) {
+		for (j = 0; j < WRS_HE_RATE_TABLE_SIZE - i - 1; j++) {
+			cl_wrs_extract_rate_idx_he(rate_idx_sorted_by_data_rate_he[j],
+						   &bw1, &nss1, &mcs1, &gi1);
+			cl_wrs_extract_rate_idx_he(rate_idx_sorted_by_data_rate_he[j + 1],
+						   &bw2, &nss2, &mcs2, &gi2);
+
+			if (data_rate_he_x10[nss1][bw1][mcs1][gi1] >
+			    data_rate_he_x10[nss2][bw2][mcs2][gi2])
+				swap(rate_idx_sorted_by_data_rate_he[j],
+				     rate_idx_sorted_by_data_rate_he[j + 1]);
+		}
+	}
+}
+
+static u16 idx_to_offt_ht_vht(u32 bw, u32 nss, u32 mcs, u32 gi)
+{
+	if (bw < CHNL_BW_MAX &&
+	    nss < WRS_SS_MAX &&
+	    mcs < WRS_MCS_MAX_VHT &&
+	    gi < WRS_GI_MAX_VHT)
+		return (gi + WRS_GI_MAX_VHT * (mcs + WRS_MCS_MAX_VHT * (nss + bw * WRS_SS_MAX)));
+	else
+		return -1;
+}
+
+static u16 idx_to_offt_he(u32 bw, u32 nss, u32 mcs, u32 gi)
+{
+	if (bw < CHNL_BW_MAX &&
+	    nss < WRS_SS_MAX &&
+	    mcs < WRS_MCS_MAX_HE &&
+	    gi < WRS_GI_MAX_HE)
+		return (gi + WRS_GI_MAX_HE * (mcs + WRS_MCS_MAX_HE * (nss + bw * WRS_SS_MAX)));
+	else
+		return -1;
+}
+
+static u16 find_down_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi, u16 *data_rates,
+			      u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	u16 idx;
+
+	if (mcs > 0) {
+		idx = idx_to_offt(bw, nss, mcs - 1, gi);
+		if (data_rates[idx])
+			return idx;
+		if (mcs > 1)
+			return idx_to_offt(bw, nss, mcs - 2, gi);
+	}
+
+	if (bw > 0) {
+		idx = idx_to_offt(bw - 1, nss, mcs, gi);
+		if (data_rates[idx])
+			return idx;
+		if (bw > 1)
+			return idx_to_offt(bw - 2, nss, mcs, gi);
+	}
+
+	if (nss > 0) {
+		idx = idx_to_offt(bw, nss - 1, mcs, gi);
+		if (data_rates[idx])
+			return idx;
+		if (nss > 1) {
+			idx = idx_to_offt(bw, nss - 2, mcs, gi);
+			if (data_rates[idx])
+				return idx;
+		}
+	}
+
+	if (gi > 0)
+		return idx_to_offt(bw, nss, mcs, gi - 1);
+
+	return 0;
+}
+
+static u16 find_up_mcs_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi, u16 *data_rates,
+				u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	s16 idx = idx_to_offt(bw, nss, mcs + 1, gi);
+
+	if (idx < 0 || !data_rates[idx])
+		idx = idx_to_offt(bw, nss, mcs + 2, gi);
+
+	return (idx < 0) ? WRS_INVALID_RATE : idx;
+}
+
+static u16 find_up_bw_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+			       u16 *data_rates,
+			       u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+	s16 min_idx = WRS_INVALID_RATE;
+	s16 idx;
+	s32 min_rate_diff = S32_MAX;
+	s32 rate_diff;
+
+	for (idx = idx_to_offt(++bw, nss, mcs, gi); !(idx < 0);
+	     idx = idx_to_offt(bw, nss, --mcs, gi)) {
+		/*
+		 * If data_rates[idx] == 0, the difference will be negative,
+		 * so the condition below will not hold.
+		 * Therefore, no need to check this possiblity specifically.
+		 */
+		rate_diff = data_rates[idx] - cur_data_rate;
+		if (rate_diff > 0 &&
+		    rate_diff < min_rate_diff &&
+		    (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+			min_rate_diff = rate_diff;
+			min_idx = idx;
+		}
+	}
+
+	return min_idx;
+}
+
+static u16 find_up_nss_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+				u16 *data_rates,
+				u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+	s16 min_idx = WRS_INVALID_RATE;
+	s16 idx;
+	s32 min_rate_diff = S32_MAX;
+	s32 rate_diff;
+
+	for (idx = idx_to_offt(bw, ++nss, mcs, gi); !(idx < 0);
+	     idx = idx_to_offt(bw, nss, --mcs, gi)) {
+		/*
+		 * If data_rates[idx] == 0, the difference will be negative,
+		 * so the condition below will not hold.
+		 * Therefore, no need to check this possiblity specifically.
+		 */
+		rate_diff = data_rates[idx] - cur_data_rate;
+		if (rate_diff > 0 &&
+		    rate_diff < min_rate_diff &&
+		    (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+			min_rate_diff = rate_diff;
+			min_idx = idx;
+		}
+	}
+
+	return min_idx;
+}
+
+static u16 find_up_bf_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+			       u16 *data_rates,
+			       u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	s16 cur_data_rate = data_rates[idx_to_offt(bw, nss, mcs, gi)];
+	s16 min_idx = WRS_INVALID_RATE;
+	s16 idx;
+	s32 min_rate_diff = S32_MAX;
+	s16 rate_diff;
+
+	for (idx = idx_to_offt(bw, --nss, mcs, gi); !(idx < 0);
+	     idx = idx_to_offt(bw, nss, ++mcs, gi)) {
+		/*
+		 * If data_rates[idx] == 0, the difference will be negative,
+		 * so the condition below will not hold.
+		 * Therefore, no need to check this possiblity specifically.
+		 */
+		rate_diff = data_rates[idx] - cur_data_rate;
+		if (rate_diff > 0 &&
+		    rate_diff < min_rate_diff &&
+		    (data_rates[idx] * 100) > (cur_data_rate * WRS_EPR_FACTOR)) {
+			min_rate_diff = rate_diff;
+			min_idx = idx;
+		}
+	}
+
+	return min_idx;
+}
+
+static u16 find_up_gi_rate_idx(u32 bw, u32 nss, u32 mcs, u32 gi,
+			       u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	s16 idx = idx_to_offt(bw, nss, mcs, gi + 1);
+
+	return (idx < 0) ? WRS_INVALID_RATE : idx;
+}
+
+static void _cl_wrs_tables_init(struct cl_wrs_table *ap_rate_table,
+				u16 *data_rates,
+				u32 bw, u32 nss, u32 mcs, u32 gi,
+				u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi))
+{
+	struct cl_wrs_table *cur_entry = NULL;
+	int i = 0;
+	u16 offt = idx_to_offt(bw, nss, mcs, gi);
+
+	cur_entry = &ap_rate_table[offt];
+	cur_entry->rate.bw = bw;
+	cur_entry->rate.nss = nss;
+	cur_entry->rate.mcs = mcs;
+	cur_entry->rate.gi = gi;
+
+	/* If current rate is invalid, mark it as such and skip it. */
+	if (!data_rates[offt]) {
+		cur_entry->rate_down.rate_idx = WRS_INVALID_RATE;
+		cur_entry->rate_down.time_th = WRS_MSEC_WEIGHT_MAX_DOWN;
+
+		for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++) {
+			cur_entry->rate_up[i].rate_idx = WRS_INVALID_RATE;
+			cur_entry->rate_up[i].time_th = WRS_MSEC_WEIGHT_MAX_UP;
+		}
+
+		return;
+	}
+
+	cur_entry->rate_down.rate_idx =
+		find_down_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+	cur_entry->rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx =
+		find_up_mcs_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+	cur_entry->rate_up[WRS_TABLE_NODE_UP_BW].rate_idx =
+		find_up_bw_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+	cur_entry->rate_up[WRS_TABLE_NODE_UP_NSS].rate_idx =
+		find_up_nss_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+	cur_entry->rate_up[WRS_TABLE_NODE_UP_BF].rate_idx =
+		find_up_bf_rate_idx(bw, nss, mcs, gi, data_rates, idx_to_offt);
+	cur_entry->rate_up[WRS_TABLE_NODE_UP_GI].rate_idx =
+		find_up_gi_rate_idx(bw, nss, mcs, gi, idx_to_offt);
+
+	cur_entry->rate_down.time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+
+	for (i = 0; i < WRS_TABLE_NODE_UP_MAX; i++)
+		cur_entry->rate_up[i].time_th =
+			(cur_entry->rate_up[i].rate_idx == WRS_INVALID_RATE) ?
+			WRS_MSEC_WEIGHT_MAX_UP : WRS_INIT_MSEC_WEIGHT_UP;
+}
+
+static void cl_wrs_tables_init(u8 mode)
+{
+	u32 bw, nss, mcs, gi;
+	u32 max_bw, max_nss, max_mcs, max_gi;
+	u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi);
+	struct cl_wrs_table *ap_rate_table = NULL;
+	u16 *data_rates = NULL;
+
+	if (mode == WRS_MODE_HE) {
+		idx_to_offt = idx_to_offt_he;
+		max_bw = CHNL_BW_MAX;
+		max_nss = WRS_SS_MAX;
+		max_mcs = WRS_MCS_MAX_HE;
+		max_gi = WRS_GI_MAX_HE;
+		ap_rate_table = (struct cl_wrs_table *)ap_rate_table_he;
+		data_rates = (u16 *)data_rate_he_x10;
+	} else if (mode == WRS_MODE_VHT) {
+		idx_to_offt = idx_to_offt_ht_vht;
+		max_bw = CHNL_BW_MAX;
+		max_nss = WRS_SS_MAX;
+		max_mcs = WRS_MCS_MAX_VHT;
+		max_gi = WRS_GI_MAX_VHT;
+		ap_rate_table = (struct cl_wrs_table *)ap_rate_table_ht_vht;
+		data_rates = (u16 *)data_rate_ht_vht_x10;
+	} else {
+		return;
+	}
+
+	for (bw = 0; bw < max_bw; bw++)
+		for (nss = 0; nss < max_nss; nss++)
+			for (mcs = 0; mcs < max_mcs; mcs++)
+				for (gi = 0; gi < max_gi; gi++)
+					_cl_wrs_tables_init(ap_rate_table,
+							    data_rates,
+							    bw,
+							    nss,
+							    mcs,
+							    gi,
+							    idx_to_offt);
+}
+
+void cl_wrs_tables_global_build(void)
+{
+	cl_wrs_tables_init(WRS_MODE_HE);
+	cl_wrs_tables_init(WRS_MODE_VHT);
+	cl_wrs_tables_build_sorted_he();
+	cl_wrs_tables_build_sorted_ht_vht();
+}
+
+void cl_wrs_tables_reset(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			 struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_table_node *rate_up;
+	u16 rate_idx = 0;
+	u8 up_idx = 0;
+
+	for (rate_idx = 0; rate_idx < wrs_params->table_size; rate_idx++) {
+		if (wrs_params->table[rate_idx].rate_down.rate_idx != WRS_INVALID_RATE)
+			wrs_params->table[rate_idx].rate_down.time_th = WRS_INIT_MSEC_WEIGHT_DOWN;
+		else
+			wrs_params->table[rate_idx].rate_down.time_th = wrs_db->time_th_max_down;
+
+		wrs_params->table[rate_idx].rate_down.quick_up_check = false;
+
+		for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+			rate_up = &wrs_params->table[rate_idx].rate_up[up_idx];
+
+			if (rate_up->rate_idx != WRS_INVALID_RATE)
+				rate_up->time_th = WRS_INIT_MSEC_WEIGHT_UP;
+			else
+				rate_up->time_th = wrs_db->time_th_max_up;
+
+			rate_up->quick_up_check = false;
+		}
+
+		wrs_params->table[rate_idx].frames_total = 0;
+		wrs_params->table[rate_idx].ba_not_rcv_total = 0;
+		wrs_params->table[rate_idx].epr_acc = 0;
+	}
+}
+
+static bool cl_wrs_is_rate_valid_he(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+				    struct cl_wrs_params *wrs_params, u8 bw,
+				    u8 nss, u8 mcs, u8 gi)
+{
+	/* Disable rates according to ce_he_mcs_nss_supp_tx */
+	if ((cl_hw->conf->ce_he_mcs_nss_supp_tx[nss] + 1) <= mcs)
+		return false;
+
+	/* TB flow doesn't support 0.8us GI */
+	if (WRS_TYPE_IS_RX(wrs_params) && gi == WRS_GI_VSHORT)
+		return false;
+
+	if (data_rate_he_x10[nss][bw][mcs][gi] < (10 * wrs_sta->he_minrate))
+		return false;
+
+	return true;
+}
+
+static bool cl_wrs_is_rate_valid_vht(struct cl_hw *cl_hw, u8 bw, u8 nss, u8 mcs)
+{
+	/* Disable BW160 */
+	if (bw == CHNL_BW_160)
+		return false;
+
+	/* Disable VHT invalid rates (MCS9 20M 1SS, MCS9 20M 2SS, MCS6 80M 3SS, MCS9 20M 4SS) */
+	if (bw == CHNL_BW_20 && mcs == WRS_MCS_9)
+		if (nss == WRS_SS_1 || nss == WRS_SS_2 || nss == WRS_SS_4)
+			return false;
+
+	if (bw == CHNL_BW_80 && mcs == WRS_MCS_6 && nss == WRS_SS_3)
+		return false;
+
+	/* Disable rates according to ce_vht_mcs_nss_supp_tx */
+	if ((cl_hw->conf->ce_vht_mcs_nss_supp_tx[nss] + 1) <= mcs)
+		return false;
+
+	return true;
+}
+
+static bool cl_wrs_is_rate_valid(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+				 struct cl_wrs_params *wrs_params,
+				 u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+	if (gi > wrs_db->max_cap.gi || gi > wrs_sta->gi_cap[bw])
+		return false;
+
+	if (mode == WRS_MODE_HE)
+		return cl_wrs_is_rate_valid_he(cl_hw, wrs_sta, wrs_params, bw, nss, mcs, gi);
+
+	if (mode == WRS_MODE_VHT)
+		return cl_wrs_is_rate_valid_vht(cl_hw, bw, nss, mcs);
+
+	return true;
+}
+
+static bool cl_wrs_is_rate_supported(u64 *rate_bitmap, u8 bw, u8 nss, u8 mcs)
+{
+	u8 rate_idx = mcs + (nss * WRS_MCS_MAX);
+	u64 mask = BIT(rate_idx);
+
+	return rate_bitmap[bw] & mask;
+}
+
+static bool cl_wrs_tables_is_up_invalid(struct cl_wrs_table *table)
+{
+	/*
+	 * The UP_GI is not part of this if condition, because we would
+	 * like to set the same up candidate for LGI & SGI (except the
+	 * up from LGI to SGI).
+	 */
+	return ((table->rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx == WRS_INVALID_RATE) &&
+		(table->rate_up[WRS_TABLE_NODE_UP_BW].rate_idx == WRS_INVALID_RATE) &&
+		(table->rate_up[WRS_TABLE_NODE_UP_NSS].rate_idx == WRS_INVALID_RATE) &&
+		(table->rate_up[WRS_TABLE_NODE_UP_BF].rate_idx == WRS_INVALID_RATE) &&
+		(table->rate_up[WRS_TABLE_NODE_UP_GI].rate_idx == WRS_INVALID_RATE));
+}
+
+static int cl_wrs_tables_max(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+			     u8 *max_bw, u8 *max_nss, u8 *max_mcs, u8 *max_gi)
+{
+	*max_bw = wrs_sta->max_rate_cap.bw;
+	*max_nss = wrs_sta->smps_enable ? WRS_SS_1 : wrs_sta->max_rate_cap.nss;
+
+	switch (wrs_sta->mode) {
+	case WRS_MODE_CCK:
+		*max_mcs = WRS_MCS_3;
+		*max_gi = WRS_GI_LONG;
+		break;
+	case WRS_MODE_OFDM:
+		*max_mcs = WRS_MCS_7;
+		*max_gi = WRS_GI_LONG;
+		break;
+	case WRS_MODE_HT:
+		*max_mcs = WRS_MCS_7;
+		*max_gi = WRS_GI_SHORT;
+		break;
+	case WRS_MODE_VHT:
+		*max_mcs = WRS_MCS_9;
+		*max_gi = WRS_GI_SHORT;
+		break;
+	case WRS_MODE_HE:
+		*max_mcs = WRS_MCS_11;
+		*max_gi = WRS_GI_VSHORT;
+
+		if (!cl_hw->conf->ce_txldpc_en) {
+			struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+			wrs_pr_verbose(wrs_db,
+				       "TX LDPC disabled: limit BW to 20MHz and MCS to 9\n");
+			*max_mcs = WRS_MCS_9;
+			*max_bw = CHNL_BW_20;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+void cl_wrs_tables_build(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+			 struct cl_wrs_params *wrs_params)
+{
+	struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+	u8 bw = 0;
+	u8 nss = 0;
+	u8 mcs = 0;
+	u8 gi = 0;
+	u8 max_bw = 0;
+	u8 max_nss = 0;
+	u8 max_mcs = 0;
+	u8 max_gi = 0;
+	u8 up_idx = 0;
+	u8 type = wrs_params->type;
+	u16 rate_idx = 0;
+	u16 new_rate_idx = 0;
+	u16 tmp_rate_idx = 0;
+	u16 max_table_size = 0;
+	u16 new_table_size = 0;
+	u16 (*idx_to_offt)(u32 bw, u32 nss, u32 mcs, u32 gi);
+	u16 *rate_idx_sorted_by_data_rate;
+	struct cl_wrs_table *ap_rate_table;
+	struct cl_wrs_table *new_table = NULL;
+	struct cl_wrs_table_validity *valid_rates = NULL;
+
+	if (cl_wrs_tables_max(cl_hw, wrs_sta, &max_bw, &max_nss, &max_mcs, &max_gi))
+		return;
+
+	if (wrs_sta->mode == WRS_MODE_HE) {
+		max_table_size = WRS_HE_RATE_TABLE_SIZE;
+		idx_to_offt = idx_to_offt_he;
+		ap_rate_table = (struct cl_wrs_table *)ap_rate_table_he;
+		rate_idx_sorted_by_data_rate = rate_idx_sorted_by_data_rate_he;
+	} else {
+		max_table_size = WRS_HT_VHT_RATE_TABLE_SIZE;
+		idx_to_offt = idx_to_offt_ht_vht;
+		ap_rate_table = (struct cl_wrs_table *)ap_rate_table_ht_vht;
+		rate_idx_sorted_by_data_rate = rate_idx_sorted_by_data_rate_ht_vht;
+	}
+
+	valid_rates = kzalloc(max_table_size * sizeof(struct cl_wrs_table_validity), GFP_ATOMIC);
+	if (!valid_rates)
+		goto out;
+
+	wrs_sta->max_rate_cap.mcs = WRS_MCS_0;
+	wrs_sta->max_rate_cap.gi = WRS_GI_LONG;
+
+	for (bw = 0; bw <= max_bw; bw++) {
+		for (nss = 0; nss <= max_nss; nss++) {
+			for (mcs = 0; mcs <= max_mcs; mcs++) {
+				for (gi = 0; gi <= max_gi; gi++) {
+					rate_idx = idx_to_offt(bw, nss, mcs, gi);
+					valid_rates[rate_idx].is_valid =
+						cl_wrs_is_rate_supported(wrs_sta->supported_rates,
+									 bw, nss, mcs) &&
+						cl_wrs_is_rate_supported(wrs_db->ap_supported_rates,
+									 bw, nss, mcs) &&
+						cl_wrs_is_rate_valid(cl_hw, wrs_sta, wrs_params,
+								     wrs_sta->mode,
+								     bw, nss, mcs, gi);
+
+					if (!valid_rates[rate_idx].is_valid)
+						continue;
+
+					valid_rates[rate_idx].new_rate_idx = new_table_size;
+					new_table_size++;
+
+					if (WRS_TYPE_IS_TX_MU_MIMO(wrs_params))
+						continue;
+
+					if (mcs > wrs_sta->max_rate_cap.mcs)
+						wrs_sta->max_rate_cap.mcs = mcs;
+
+					if (gi > wrs_sta->max_rate_cap.gi)
+						wrs_sta->max_rate_cap.gi = gi;
+				}
+			}
+		}
+	}
+
+	if (new_table_size == 0) {
+		/* Error - size of table is 0, add single rate (mcs 0, 1 SS, bw 20 Mhz) */
+		wrs_pr_err(wrs_db, "[%s] Table build error - Size of table is 0\n",
+			   WRS_TYPE_STR(type));
+		cl_wrs_sta_set_supported_rate(wrs_sta, CHNL_BW_20, WRS_SS_1, WRS_MCS_0);
+		valid_rates[0].new_rate_idx = 0;
+		valid_rates[0].is_valid = 1;
+		new_table_size = 1;
+	}
+
+	new_table = kzalloc(new_table_size * sizeof(struct cl_wrs_table), GFP_ATOMIC);
+
+	if (!new_table)
+		goto out;
+
+	for (rate_idx = 0; rate_idx < max_table_size; rate_idx++) {
+		if (!valid_rates[rate_idx].is_valid)
+			continue;
+
+		memcpy(new_table + new_rate_idx,
+		       ap_rate_table + rate_idx,
+		       sizeof(struct cl_wrs_table));
+
+		/* Set down rate */
+		tmp_rate_idx = ap_rate_table[rate_idx].rate_down.rate_idx;
+
+		while ((!valid_rates[tmp_rate_idx].is_valid) &&
+		       (ap_rate_table[tmp_rate_idx].rate_down.rate_idx != tmp_rate_idx))
+			tmp_rate_idx = ap_rate_table[tmp_rate_idx].rate_down.rate_idx;
+
+		if (valid_rates[tmp_rate_idx].is_valid) {
+			new_table[new_rate_idx].rate_down.rate_idx =
+				valid_rates[tmp_rate_idx].new_rate_idx;
+		} else {
+			u16 i = 0;
+			u16 down_idx = 0;
+			u16 down_rate_idx = new_rate_idx;
+
+			while (new_table[new_rate_idx].rate_down.rate_idx !=
+			       rate_idx_sorted_by_data_rate[i]) {
+				down_idx = rate_idx_sorted_by_data_rate[i];
+
+				if (valid_rates[down_idx].is_valid)
+					down_rate_idx = valid_rates[down_idx].new_rate_idx;
+				i++;
+			}
+
+			new_table[new_rate_idx].rate_down.rate_idx = down_rate_idx;
+		}
+
+		/* Set up rates */
+		for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++) {
+			tmp_rate_idx = new_table[new_rate_idx].rate_up[up_idx].rate_idx;
+
+			if (tmp_rate_idx != WRS_INVALID_RATE &&
+			    valid_rates[tmp_rate_idx].is_valid)
+				new_table[new_rate_idx].rate_up[up_idx].rate_idx =
+					valid_rates[tmp_rate_idx].new_rate_idx;
+			else
+				new_table[new_rate_idx].rate_up[up_idx].rate_idx = WRS_INVALID_RATE;
+		}
+
+		/*
+		 * In case all the UP rates are invalid, find one available UP
+		 * rate based on PHY rate
+		 */
+		if (cl_wrs_tables_is_up_invalid(&new_table[new_rate_idx])) {
+			u16 i = 0;
+
+			for (i = 0; i < max_table_size; i++)
+				if (rate_idx == rate_idx_sorted_by_data_rate[i])
+					break;
+
+			i++;
+
+			while (i < max_table_size) {
+				tmp_rate_idx = rate_idx_sorted_by_data_rate[i];
+				if (!valid_rates[tmp_rate_idx].is_valid) {
+					i++;
+					continue;
+				}
+
+				new_table[new_rate_idx].rate_up[WRS_TABLE_NODE_UP_MCS].rate_idx =
+					valid_rates[tmp_rate_idx].new_rate_idx;
+				break;
+			}
+		}
+
+		new_rate_idx++;
+	}
+
+	if (wrs_params->table) {
+		/*
+		 * Copy epr_acc, frames_total and ba_not_rcv_total
+		 * from the old table to the new table.
+		 * Also, if initial_rate_idx is set, find the new
+		 * value in the new table.
+		 */
+		u16 old_rate_idx = 0;
+		struct cl_wrs_rate *initial_old_rate = NULL;
+
+		if (wrs_params->initial_rate_idx != WRS_INVALID_RATE) {
+			initial_old_rate = &wrs_params->table[wrs_params->initial_rate_idx].rate;
+			wrs_params->initial_rate_idx = WRS_INVALID_RATE;
+		}
+
+		for (rate_idx = 0; rate_idx < new_table_size; rate_idx++) {
+			old_rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+								   new_table[rate_idx].rate.bw,
+								   new_table[rate_idx].rate.nss,
+								   new_table[rate_idx].rate.mcs,
+								   new_table[rate_idx].rate.gi);
+
+			if (initial_old_rate &&
+			    new_table[rate_idx].rate.bw == initial_old_rate->bw &&
+			    new_table[rate_idx].rate.nss == initial_old_rate->nss &&
+			    new_table[rate_idx].rate.mcs == initial_old_rate->mcs &&
+			    new_table[rate_idx].rate.gi == initial_old_rate->gi) {
+				wrs_params->initial_rate_idx = rate_idx;
+				initial_old_rate = NULL;
+			}
+
+			if (old_rate_idx == WRS_INVALID_RATE)
+				continue;
+
+			new_table[rate_idx].epr_acc =
+				wrs_params->table[old_rate_idx].epr_acc;
+			new_table[rate_idx].frames_total =
+				wrs_params->table[old_rate_idx].frames_total;
+			new_table[rate_idx].ba_not_rcv_total =
+				wrs_params->table[old_rate_idx].ba_not_rcv_total;
+		}
+
+		kfree(wrs_params->table);
+	}
+
+	wrs_params->table = new_table;
+	wrs_params->table_size = new_table_size;
+
+	if (wrs_params->rate_idx != WRS_INVALID_RATE) {
+		/*
+		 * Check if current rate is included in the new table.
+		 * If not select a rate from the new table accroding to rssi.
+		 */
+		struct cl_wrs_rate_params *rate_params = &wrs_params->rate_params;
+
+		rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+						       rate_params->bw, rate_params->nss,
+						       rate_params->mcs, rate_params->gi);
+
+		if (rate_idx != WRS_INVALID_RATE) {
+			wrs_params->rate_idx = rate_idx;
+		} else {
+			if (wrs_params->is_fixed_rate) {
+				wrs_params->is_fixed_rate = false;
+				wrs_pr_verbose(wrs_db,
+					       "[%s] Disable fixed rate for station %u\n",
+					       WRS_TYPE_STR(type), wrs_sta->sta_idx);
+			}
+
+			cl_wrs_sta_select_first_rate(cl_hw, wrs_db, wrs_sta, wrs_params);
+			cl_wrs_cntrs_reset(wrs_sta, wrs_params);
+		}
+	}
+
+out:
+	kfree(valid_rates);
+}
+
+u16 cl_wrs_tables_find_rate_idx(struct cl_wrs_params *wrs_params,
+				u8 bw, u8 nss, u8 mcs, u8 gi)
+{
+	struct cl_wrs_table *table = wrs_params->table;
+	u16 rate_idx = 0;
+
+	for (rate_idx = 0; rate_idx < wrs_params->table_size; rate_idx++)
+		if (bw == table[rate_idx].rate.bw &&
+		    nss == table[rate_idx].rate.nss &&
+		    mcs == table[rate_idx].rate.mcs &&
+		    gi == table[rate_idx].rate.gi)
+			return rate_idx;
+
+	return WRS_INVALID_RATE;
+}
+
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 95/96] cl8k: add wrs.h
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (93 preceding siblings ...)
  2022-05-24 11:35 ` [RFC v2 94/96] cl8k: add wrs.c viktor.barna
@ 2022-05-24 11:35 ` viktor.barna
  2022-05-24 11:35 ` [RFC v2 96/96] wireless: add Celeno vendor viktor.barna
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:35 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/celeno/cl8k/wrs.h | 565 +++++++++++++++++++++++++
 1 file changed, 565 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs.h

diff --git a/drivers/net/wireless/celeno/cl8k/wrs.h b/drivers/net/wireless/celeno/cl8k/wrs.h
new file mode 100644
index 000000000000..158d61b92ffc
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs.h
@@ -0,0 +1,565 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
+
+#ifndef CL_WRS_H
+#define CL_WRS_H
+
+#include <net/mac80211.h>
+
+#include "def.h"
+#include "debug.h"
+#include "rx.h"
+
+/**
+ * WRS (=Weighted Rate Selection)
+ */
+
+struct cl_hw;
+struct cl_sta;
+struct cl_vif;
+
+/* Rate Table Size */
+#define WRS_HE_RATE_TABLE_SIZE     (WRS_MCS_MAX_HE * WRS_SS_MAX * CHNL_BW_MAX * WRS_GI_MAX_HE)
+#define WRS_HT_VHT_RATE_TABLE_SIZE (WRS_MCS_MAX_VHT * WRS_SS_MAX * CHNL_BW_MAX * WRS_GI_MAX_VHT)
+
+/* Initial Thresholds */
+#define WRS_INIT_MSEC_WEIGHT_DOWN  (WRS_MAINTENANCE_PERIOD_MS * 3) /* Msec */
+#define WRS_INIT_MSEC_WEIGHT_UP    (WRS_MAINTENANCE_PERIOD_MS * 3) /* Msec */
+
+#define WRS_MSEC_WEIGHT_MIN        (WRS_MAINTENANCE_PERIOD_MS * 2) /* Msec */
+#define WRS_MSEC_WEIGHT_MAX_UP     30000 /* Msec */
+#define WRS_MSEC_WEIGHT_MAX_DOWN   4000  /* Msec */
+#define WRS_MSEC_STEP_DOWN         5000  /* Msec */
+#define WRS_MSEC_STEP_UP_SAME      1000  /* Msec */
+#define WRS_INVALID_RATE           ((u16)(~0))
+
+enum cl_wrs_table_node_up {
+	WRS_TABLE_NODE_UP_MCS,
+	WRS_TABLE_NODE_UP_BW,
+	WRS_TABLE_NODE_UP_NSS,
+	WRS_TABLE_NODE_UP_BF,
+	WRS_TABLE_NODE_UP_GI,
+
+	WRS_TABLE_NODE_UP_MAX
+};
+
+struct cl_wrs_table_validity {
+	bool is_valid;
+	u16 new_rate_idx;
+};
+
+struct cl_wrs_table_node {
+	u16 rate_idx;
+	u16 time_th;
+	bool quick_up_check;
+};
+
+struct cl_wrs_rate {
+	u16 mcs : 4,
+	    nss : 3,
+	    bw  : 2,
+	    gi  : 2,
+	    rsv : 2;
+};
+
+struct cl_wrs_table {
+	struct cl_wrs_rate rate;
+	struct cl_wrs_table_node rate_down;
+	struct cl_wrs_table_node rate_up[WRS_TABLE_NODE_UP_MAX];
+	u32 frames_total;
+	u32 ba_not_rcv_total;
+	u64 epr_acc;
+};
+
+#define WRS_MAINTENANCE_PERIOD_MS         40
+#define WRS_DATA_RATE_FACTOR              10
+#define WRS_RSSI_PROTECT_UP_THR           10
+#define WRS_RSSI_PROTECT_DN_THR           10
+#define WRS_MIN_FRAMES_FOR_DECISION       15
+#define WRS_EPR_FACTOR                    105
+#define WRS_CONVERGE_IDLE_PACKET_TH       5
+#define WRS_CONVERGE_IDLE_INTERVAL_RESET  6000  /* 6 sec */
+#define WRS_CONVERGE_IDLE_INTERVAL_RSSI   2000  /* 2 sec */
+#define WRS_CONVERGE_TRFC_INTERVAL_STATIC 30000 /* 30 sec */
+#define WRS_CONVERGE_TRFC_INTERVAL_MOTION 1000  /* 1 sec */
+#define WRS_IMMEDIATE_DROP_EPR_FACTOR     70    /* 70% */
+#define WRS_IMMEDIATE_DROP_MAX_IN_ROW     U32_MAX
+#define WRS_SYNC_MIN_ATTEMPTS             4
+#define WRS_SYNC_TIMEOUT                  1000  /* 1 sec */
+#define WRS_QUICK_UP_BA_THR               5
+#define WRS_QUICK_UP_INTERVAL_MS          1000
+#define WRS_QUICK_DOWN_EPR_FACTOR         85
+#define WRS_QUICK_DOWN_AGG_THR            3
+#define WRS_QUICK_DOWN_PKT_THR            60
+#define WRS_RSSI_PROTECT_SHIFT            7
+#define WRS_RSSI_PROTECT_BUF_SZ_OLD       BIT(WRS_RSSI_PROTECT_SHIFT) /* 2 ^ 7 = 128 */
+#define WRS_RSSI_PROTECT_BUF_SZ_NEW       3
+#define WRS_BA_NOT_RCV_TIME_SINCE_SYNC    1000
+#define WRS_CCA_PERIOD_MS                 1000
+#define WRS_CCA_PRIMARY_SHIFT             7
+#define WRS_CCA_PRIMARY_FACTOR            160 /* 160 / 2^7 = 1.25 = 25% */
+
+enum cl_wrs_rssi_prot_mode {
+	WRS_RSSI_PROT_MODE_RSSI,     /* Up/down based on rssi */
+	WRS_RSSI_PROT_MODE_NEIGHBOR, /* Up/down based on neighbors */
+
+	WRS_RSSI_PROTECT_MODE_MAX
+};
+
+enum cl_wrs_fixed_rate {
+	WRS_AUTO_RATE,
+	WRS_FIXED_FALLBACK_EN,
+	WRS_FIXED_FALLBACK_DIS,
+
+	WRS_FIXED_RATE_MAX
+};
+
+enum cl_wrs_fixed_param {
+	WRS_FIXED_PARAM_MODE,
+	WRS_FIXED_PARAM_BW,
+	WRS_FIXED_PARAM_NSS,
+	WRS_FIXED_PARAM_MCS,
+	WRS_FIXED_PARAM_GI,
+
+	WRS_FIXED_PARAM_MAX
+};
+
+#define FIXED_RATE_STR(x) \
+	(((x) == WRS_AUTO_RATE) ? "auto rate" : \
+	(((x) == WRS_FIXED_FALLBACK_EN) ? "fixed rate (fallbacks enabled)" : \
+	"fixed rate (fallbacks disabled)"))
+
+enum cl_wrs_decision {
+	WRS_DECISION_NONE,
+	WRS_DECISION_SAME,
+	WRS_DECISION_UP,
+	WRS_DECISION_UP_QUICK,
+	WRS_DECISION_UP_RSSI,
+	WRS_DECISION_UP_MCS1,
+	WRS_DECISION_DOWN,
+	WRS_DECISION_DOWN_RSSI,
+	WRS_DECISION_DOWN_IMMEDIATE,
+	WRS_DECISION_DOWN_QUICK,
+	WRS_DECISION_DOWN_NO_SYNC,
+	WRS_DECISION_RSSI_MGMT,
+	WRS_DECISION_RX_RATE,
+
+	WRS_DECISION_MAX,
+};
+
+enum cl_wrs_mcs {
+	WRS_MCS_0,
+	WRS_MCS_1,
+	WRS_MCS_2,
+	WRS_MCS_3,
+	WRS_MCS_4,
+	WRS_MCS_5,
+	WRS_MCS_6,
+	WRS_MCS_7,
+	WRS_MCS_8,
+	WRS_MCS_9,
+	WRS_MCS_10,
+	WRS_MCS_11,
+	WRS_MCS_MAX,
+};
+
+#define WRS_MCS_MAX_CCK  WRS_MCS_4
+#define WRS_MCS_MAX_OFDM WRS_MCS_8
+#define WRS_MCS_MAX_HT   WRS_MCS_8
+#define WRS_MCS_MAX_VHT  WRS_MCS_10
+#define WRS_MCS_MAX_HE   WRS_MCS_MAX
+
+enum cl_wrs_ss {
+	WRS_SS_1,
+	WRS_SS_2,
+	WRS_SS_3,
+	WRS_SS_4,
+
+	WRS_SS_MAX
+};
+
+enum cl_wrs_gi {
+	WRS_GI_LONG,
+	WRS_GI_SHORT,
+	WRS_GI_VSHORT,
+
+	WRS_GI_MAX
+};
+
+#define WRS_GI_MAX_HT  WRS_GI_VSHORT
+#define WRS_GI_MAX_VHT WRS_GI_VSHORT
+#define WRS_GI_MAX_HE  WRS_GI_MAX
+
+enum cl_wrs_ltf {
+	LTF_X1,
+	LTF_X2,
+	LTF_X4,
+	LTF_MAX
+};
+
+enum cl_wrs_converge_mode {
+	WRS_CONVERGE_MODE_RESET,
+	WRS_CONVERGE_MODE_RSSI,
+
+	WRS_CONVERGE_MODE_MAX,
+};
+
+enum cl_wrs_mode {
+	WRS_MODE_CCK,
+	WRS_MODE_OFDM,
+	WRS_MODE_HT,
+	WRS_MODE_VHT,
+	WRS_MODE_HE,
+
+	WRS_MODE_MAX,
+};
+
+enum cl_wrs_type {
+	WRS_TYPE_TX_SU,
+	WRS_TYPE_TX_MU_MIMO,
+	WRS_TYPE_RX,
+
+	WRS_TYPE_MAX,
+};
+
+#define WRS_TYPE_STR(type) \
+		((type) == WRS_TYPE_TX_SU ? "TX_SU" : \
+		((type) == WRS_TYPE_RX ? "RX" : \
+		((type) == WRS_TYPE_TX_MU_MIMO ? "TX_MU-MIMO" : "")))
+
+#define WRS_TYPE_IS_TX_SU(wrs_params) ((wrs_params)->type == WRS_TYPE_TX_SU)
+#define WRS_TYPE_IS_TX_MU_MIMO(wrs_params) ((wrs_params)->type == WRS_TYPE_TX_MU_MIMO)
+#define WRS_TYPE_IS_RX(wrs_params) ((wrs_params)->type == WRS_TYPE_RX)
+
+/* m MUST be power of 2 ! */
+#define WRS_INC_POW2(c, m) (((c) + 1) & ((m) - 1))
+
+#define WRS_INC(c, m) \
+	do { \
+		(c)++; \
+		if ((c) == (m)) \
+			(c) = 0; \
+	} while (0)
+
+#define WRS_IS_DECISION_UP(decision) \
+	(((decision) >= WRS_DECISION_UP) && ((decision) <= WRS_DECISION_UP_MCS1))
+#define WRS_IS_DECISION_DOWN(decision) \
+	(((decision) >= WRS_DECISION_DOWN) && ((decision) <= WRS_DECISION_DOWN_NO_SYNC))
+
+#define WRS_DECISION_STR(decision) (                                   \
+	(decision) == WRS_DECISION_NONE           ? "NONE"           : \
+	(decision) == WRS_DECISION_SAME           ? "SAME"           : \
+	(decision) == WRS_DECISION_UP             ? "UP"             : \
+	(decision) == WRS_DECISION_UP_QUICK       ? "UP QUICK"       : \
+	(decision) == WRS_DECISION_UP_RSSI        ? "UP RSSI"        : \
+	(decision) == WRS_DECISION_UP_MCS1        ? "UP MCS1"        : \
+	(decision) == WRS_DECISION_DOWN           ? "DOWN"           : \
+	(decision) == WRS_DECISION_DOWN_RSSI      ? "DOWN RSSI"      : \
+	(decision) == WRS_DECISION_DOWN_IMMEDIATE ? "DOWN IMMEDIATE" : \
+	(decision) == WRS_DECISION_DOWN_QUICK     ? "DOWN QUICK"     : \
+	(decision) == WRS_DECISION_DOWN_NO_SYNC   ? "DOWN NO_SYNC"   : \
+	(decision) == WRS_DECISION_RSSI_MGMT      ? "RSSI MGMT"      : \
+	(decision) == WRS_DECISION_RX_RATE        ? "RX_RATE"        : \
+	"ERROR")
+
+struct cl_wrs_cntrs {
+	u64 epr_acc;
+	u32 total;
+	u32 fail;
+	u32 ba_not_rcv;
+	u32 ba_not_rcv_consecutive;
+};
+
+struct cl_wrs_rate_params {
+	u16 mode        : 3, /* Mode - 0 = CCK, 1 = OFDM, 2 = HT, 3 = VHT, 4 = HE. */
+	    gi          : 2, /* GI - O = Long, 1 = Short, 2 = Very short. */
+	    bw          : 2, /* Bandwidth - 0 = 20M, 1 = 40M, 2 = 80M, 3 = 160M. */
+	    nss         : 3, /* Spatial Streams - 0 = 1SS, 1 = 2SS, .. 7 = 8SS. */
+	    mcs         : 4, /* MCS - CCK (0 - 3), OFDM/HT (0 - 7), VHT (0 - 9), HE (0 - 11). */
+	    fallback_en : 1,
+	    is_fixed    : 1;
+};
+
+struct cl_wrs_logger {
+	unsigned long timestamp;
+	u16 rate_idx;
+	u32 success;
+	u32 fail;
+	u32 ba_not_rcv;
+	u16 down_rate_idx;
+	u16 up_rate_idx;
+	u16 curr_epr;
+	u16 down_epr;
+	u16 down_epr_factorized;
+	u16 penalty;
+	u16 up_time;
+	enum cl_wrs_decision decision;
+	u16 new_rate_idx;
+};
+
+struct cl_wrs_per_stats {
+	struct list_head list;
+	u8 mcs;
+	u8 bw;
+	u8 nss;
+	u8 gi;
+	u32 frames_total;
+	u32 frames_failed;
+	u64 epr_acc;
+};
+
+struct cl_wrs_rssi_prot_db {
+	s8 samples_old[WRS_RSSI_PROTECT_BUF_SZ_OLD];
+	s8 samples_new[WRS_RSSI_PROTECT_BUF_SZ_NEW];
+	u8 curr_idx_old;
+	u8 curr_idx_new;
+	s32 sum;
+};
+
+struct cl_wrs_params {
+	u8 group_id;
+	u8 is_mu_valid    : 1,
+	   is_fixed_rate  : 2,
+	   is_logger_en   : 1,
+	   quick_up_check : 1,
+	   type           : 2,
+	   rsv            : 1;
+	u32 up_same_time_cnt;
+	u32 down_time_cnt;
+	enum cl_wrs_converge_mode converge_mode;
+	u32 converge_time_idle;
+	u32 converge_time_trfc;
+	u16 data_rate;
+	u16 rate_idx;
+	u16 initial_rate_idx;
+	struct cl_wrs_table *table;
+	u16 table_size;
+	u16 penalty_decision_dn;
+	struct cl_wrs_rate_params rate_params;
+	struct cl_wrs_rate rx_rate_idle;
+	enum cl_wrs_decision last_decision;
+	u32 decision_cnt[WRS_DECISION_MAX];
+	struct list_head list_rates;
+	u32 frames_total;
+	u32 fail_total;
+	u32 ba_not_rcv_total;
+	u64 epr_acc;
+	bool calc_ba_not_rcv;
+	bool sync;
+	unsigned long sync_timestamp;
+	unsigned long no_sync_timestamp;
+	struct cl_wrs_logger *logger;
+	u16 logger_idx;
+	u16 logger_size;
+	u32 immediate_drop_cntr;
+	u32 immediate_drop_ignore;
+};
+
+struct cl_wrs_sta {
+	u8 sta_idx;
+	bool smps_enable;
+	u8 assoc_bw;
+	u8 he_minrate;
+	u8 gi_cap[CHNL_BW_MAX];
+	u64 supported_rates[CHNL_BW_MAX];
+	enum cl_wrs_mode mode;
+	struct cl_wrs_rate max_rate_cap;
+	struct cl_wrs_rssi_prot_db rssi_prot_db;
+	struct cl_wrs_params tx_su_params;
+	struct cl_wrs_params *rx_params;
+};
+
+struct cl_wrs_db {
+	/* General */
+	spinlock_t lock;
+	enum cl_dbg_level debug_level;
+	/* Timer */
+	struct timer_list timer_maintenance;
+	u32 interval;
+	/* Fixed rate */
+	u8 is_fixed_rate;
+	/* Conservative initial rate */
+	bool conservative_mcs_noisy_env;
+	bool conservative_nss_noisy_env;
+	/* Immediate drop */
+	bool immediate_drop_en;
+	u8 immediate_drop_epr_factor;
+	u32 immediate_drop_max_in_row;
+	/* Converge idle */
+	bool converge_idle_en;
+	u32 converge_idle_interval_reset;
+	u32 converge_idle_interval_rssi;
+	u32 converge_idle_packet_th;
+	/* Converge traffic */
+	bool converge_trfc_en;
+	u32 converge_trfc_interval_static;
+	u32 converge_trfc_interval_motion;
+	/* Supported rates */
+	u8 mode;
+	u64 ap_supported_rates[CHNL_BW_MAX]; /* Bit array for each bw */
+	struct cl_wrs_rate max_cap;
+	u8 coex_bw;
+	/* RSSI protect */
+	bool rssi_protect_en;
+	u8 rssi_protect_mode;
+	s8 rssi_protect_up_thr;
+	s8 rssi_protect_dn_thr;
+	/* Time + step thresholds */
+	u16 time_th_min;
+	u16 time_th_max_up;
+	u16 time_th_max_down;
+	u16 step_down;
+	u16 step_up_same;
+	/* Quick up */
+	bool quick_up_en;
+	u8 quick_up_ba_thr;
+	u16 quick_up_interval;
+	/* Quick down */
+	bool quick_down_en;
+	u8 quick_down_epr_factor;
+	u8 quick_down_agg_thr;
+	u16 quick_down_pkt_thr;
+	/* BA not received */
+	bool ba_not_rcv_collision_filter;
+	bool ba_not_rcv_force;
+	u32 ba_not_rcv_time_since_sync;
+	/* Sync */
+	u16 sync_timeout;
+	u8 sync_min_attempts;
+	/* CCA counters */
+	unsigned long cca_timestamp;
+	u32 cca_primary;
+	u32 cca_sec80;
+	u32 cca_sec40;
+	u32 cca_sec20;
+	bool adjacent_interference20;
+	bool adjacent_interference40;
+	bool adjacent_interference80;
+	/* All the rest */
+	u32 min_frames_for_decision;
+	u8 epr_factor;
+};
+
+struct cl_wrs_info {
+	u64 epr_acc;
+	u32 success;
+	u32 fail;
+	u32 fail_prev;
+	u32 ba_not_rcv;
+	u8 ba_not_rcv_consecutive;
+	u8 ba_not_rcv_consecutive_max;
+	bool synced;
+	u32 sync_attempts;
+	u8 quick_rate_agg_cntr;
+	u16 quick_rate_pkt_cntr;
+	bool quick_rate_check;
+};
+
+struct cl_wrs_rssi {
+	s32 sum[MAX_ANTENNAS];
+	s32 cnt;
+};
+
+bool cl_wrs_rssi_set_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta);
+void cl_wrs_rssi_prot_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+bool cl_wrs_rssi_prot_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			       struct cl_wrs_sta *wrs_sta,
+			       struct cl_wrs_params *wrs_params,
+			       bool up_rate_valid,
+			       u8 up_rate_idx, u8 down_rate_idx);
+u16 cl_wrs_rssi_find_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			  s8 *rssi_sort);
+void cl_wrs_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+bool cl_wrs_sta_add_mu(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta, u8 group_id);
+void cl_wrs_sta_add_rx(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+void cl_wrs_sta_remove(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, struct cl_sta *cl_sta);
+bool cl_wrs_sta_remove_mu(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta);
+struct cl_wrs_sta *cl_wrs_sta_get(struct cl_hw *cl_hw, u8 sta_idx);
+void cl_wrs_sta_select_first_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+				  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+void cl_wrs_sta_capabilities_set(struct cl_wrs_db *wrs_db, struct ieee80211_sta *sta);
+void cl_wrs_sta_set_supported_rate(struct cl_wrs_sta *wrs_sta, u8 bw, u8 nss, u8 mcs);
+void cl_wrs_stats_per_update(struct cl_wrs_db *wrs_db,
+			     struct cl_wrs_sta *wrs_sta,
+			     struct cl_wrs_params *wrs_params,
+			     struct cl_wrs_cntrs *cntrs);
+void cl_wrs_stats_per_init(struct cl_wrs_params *wrs_params);
+void cl_wrs_stats_per_remove(struct cl_wrs_params *wrs_params);
+void cl_wrs_tables_global_build(void);
+void cl_wrs_tables_reset(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			 struct cl_wrs_params *wrs_params);
+void cl_wrs_tables_build(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+			 struct cl_wrs_params *wrs_params);
+u16 cl_wrs_tables_find_rate_idx(struct cl_wrs_params *wrs_params,
+				u8 bw, u8 nss, u8 mcs, u8 gi);
+void cl_wrs_init(struct cl_hw *cl_hw);
+void cl_wrs_lock_bh(struct cl_wrs_db *wrs_db);
+void cl_wrs_unlock_bh(struct cl_wrs_db *wrs_db);
+void cl_wrs_lock(struct cl_wrs_db *wrs_db);
+void cl_wrs_unlock(struct cl_wrs_db *wrs_db);
+void cl_wrs_fixed_rate_set(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			   struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			   u8 is_fixed_rate, u8 mode, u8 bw, u8 nss, u8 mcs, u8 gi, bool mu_valid);
+void cl_wrs_rate_param_sync(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			    struct cl_wrs_params *wrs_params);
+void cl_wrs_rate_params_update(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			       struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			       u16 new_rate_idx, bool is_sync_required, bool mu_valid);
+void cl_wrs_decision_make(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params,
+			  enum cl_wrs_decision decision, u16 new_rate_idx);
+void cl_wrs_decision_update(struct cl_wrs_db *wrs_db, struct cl_wrs_sta *wrs_sta,
+			    struct cl_wrs_params *wrs_params, enum cl_wrs_decision decision,
+			    u16 new_rate_idx);
+void cl_wrs_quick_down_check(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			     struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+bool cl_wrs_up_mcs1(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+		    struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+void cl_wrs_rate_param_set(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+			   struct cl_wrs_params *wrs_params,
+			   struct cl_wrs_rate_params *rate_params,
+			   struct cl_wrs_rate *rate_fallback,
+			   bool mu_mimo_valid, bool set_su);
+s8 cl_wrs_rssi_eq_calc(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+		       bool read_clear, s8 *sorted_rssi);
+void cl_wrs_cntrs_reset(struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+struct cl_wrs_info *cl_wrs_info_get(struct cl_sta *cl_sta, u8 type);
+struct cl_wrs_params *cl_wrs_params_get(struct cl_wrs_sta *wrs_sta, u8 type);
+void cl_wrs_update_rx_rate(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct hw_rxhdr *rxhdr);
+bool cl_wrs_set_rate_idle(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+			  struct cl_wrs_sta *wrs_sta, struct cl_wrs_params *wrs_params);
+struct cl_wrs_rate_params *cl_wrs_rx_rate_get(struct cl_sta *cl_sta);
+void cl_wrs_rx_rate_idle_reset(struct cl_wrs_params *rx_params);
+void cl_wrs_ap_capab_set(struct cl_hw *cl_hw, u8 bw, u8 use_sgi);
+void cl_wrs_ap_capab_modify_bw(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 max_bw);
+void cl_wrs_ap_capab_modify_gi(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db, u8 use_sgi);
+void cl_wrs_ap_capab_update(struct cl_hw *cl_hw, u8 bw, u8 use_sgi);
+
+/* Driver --> WRS */
+void cl_wrs_api_init(struct cl_hw *cl_hw);
+void cl_wrs_api_close(struct cl_hw *cl_hw);
+void cl_wrs_api_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta);
+void cl_wrs_api_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_wrs_api_bss_set_bw(struct cl_hw *cl_hw, u8 bw);
+void cl_wrs_api_bss_set_sgi(struct cl_hw *cl_hw, u8 use_sgi);
+bool cl_wrs_api_bss_is_sgi_en(struct cl_hw *cl_hw);
+void cl_wrs_api_nss_or_bw_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 nss, u8 bw);
+void cl_wrs_api_he_minrate_changed(struct cl_sta *cl_sta, u8 he_minrate);
+void cl_wrs_api_recovery(struct cl_hw *cl_hw);
+void cl_wrs_api_beamforming_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta);
+void cl_wrs_api_quick_down_check(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+				 struct cl_wrs_params *wrs_params);
+void cl_wrs_api_rate_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			  struct cl_wrs_params *wrs_params);
+bool cl_wrs_api_up_mcs1(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+			struct cl_wrs_params *wrs_params);
+void cl_wrs_api_set_smps_mode(struct cl_hw *cl_hw, struct ieee80211_sta *sta, const u8 bw);
+u16 cl_wrs_api_get_tx_sta_data_rate(struct cl_sta *cl_sta);
+void cl_wrs_api_bss_capab_update(struct cl_hw *cl_hw, u8 bw, u8 use_sgi);
+void cl_wrs_fill_sinfo_rates(struct rate_info *rate_info,
+			     const struct cl_wrs_params *wrs_params,
+			     const struct cl_sta *sta);
+
+#endif /* CL_WRS_H */
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [RFC v2 96/96] wireless: add Celeno vendor
  2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
                   ` (94 preceding siblings ...)
  2022-05-24 11:35 ` [RFC v2 95/96] cl8k: add wrs.h viktor.barna
@ 2022-05-24 11:35 ` viktor.barna
  95 siblings, 0 replies; 125+ messages in thread
From: viktor.barna @ 2022-05-24 11:35 UTC (permalink / raw)
  To: linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar,
	Viktor Barna

From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 drivers/net/wireless/Kconfig  | 1 +
 drivers/net/wireless/Makefile | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7add2002ff4c..444c81e3da06 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -35,6 +35,7 @@ source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
 source "drivers/net/wireless/quantenna/Kconfig"
+source "drivers/net/wireless/celeno/Kconfig"
 
 config PCMCIA_RAYCS
 	tristate "Aviator/Raytheon 2.4GHz wireless support"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 80b324499786..3eb57351d0e5 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
 obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
 obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
+obj-$(CONFIG_WLAN_VENDOR_CELENO) += celeno/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [RFC v2 07/96] cl8k: add bf.c
  2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
@ 2022-05-24 17:24   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-24 17:24 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:33 AM, viktor.barna@celeno.com wrote:
[snip]

> +void cl_bf_sounding_start(struct cl_hw *cl_hw, enum sounding_type type, struct cl_sta **cl_sta_arr,
> +			  u8 sta_num, struct cl_sounding_info *recovery_elem)
> +{
> +#define STA_INDICES_STR_SIZE 64
> +
> +	/* Send request to start sounding */
> +	u8 i, bw = CHNL_BW_MAX;
> +	char sta_indices_str[STA_INDICES_STR_SIZE] = {0};
> +	u8 str_len = 0;
> +
> +	for (i = 0; i < sta_num; i++) {
> +		struct cl_sta *cl_sta = cl_sta_arr[i];
> +		struct cl_bf_sta_db *bf_db = &cl_sta->bf_db;
> +
> +		bw = cl_sta->wrs_sta.assoc_bw;
> +		bf_db->synced = false;
> +		bf_db->sounding_start = true;
> +		bf_db->sounding_indications = 0;
> +
> +		str_len += snprintf(sta_indices_str, STA_INDICES_STR_SIZE - str_len, "%u%s",
> +				    cl_sta->sta_idx, (i == sta_num - 1 ? ", " : ""));

note that this may not actually be safe from overflow due to the 
semantics of the snprintf return value.

using scnprintf() is preferred for this usage pattern

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 16/96] cl8k: add config.h
  2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
@ 2022-05-25 18:31   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-25 18:31 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:33 AM, viktor.barna@celeno.com wrote:
[snip]

> +#define READ_BOOL(param) \
> +{ \
> +	if (!strcmp(name, #param)) { \
> +		bool new_val = false; \
> +		ret = kstrtobool(value, &new_val); \
> +		if (ret) { \
> +			pr_err("%s: invalid value [%s]\n", #param, value); \
> +			break; \
> +		} \
> +		if (conf->param != new_val) { \
> +			pr_debug("%s: old value %u -> new value %u\n", \
> +				 #param, conf->param, new_val); \
> +			conf->param = new_val; \
> +		} \
> +		break; \
> +	} \
> +}

You should review the guidance on macros at
<https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl>

Note that things to avoid include:
1. macros that affect control flow
2. macros that depend on having a local variable with a magic name


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 19/96] cl8k: add def.h
  2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
@ 2022-05-25 18:39   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-25 18:39 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:33 AM, viktor.barna@celeno.com wrote:
> From: Viktor Barna <viktor.barna@celeno.com>
[snip]
> +#define ASSERT_ERR(condition) \
> +	do { \
> +		if (unlikely(!(condition))) \
> +			cl_dbg_err(cl_hw, ":ASSERT_ERR(" #condition ")\n"); \
> +	} while (0)
> +
> +#define ASSERT_ERR_CHIP(condition) \
> +	do { \
> +		if (unlikely(!(condition))) \
> +			cl_dbg_chip_err(chip, ":ASSERT_ERR(" #condition ")\n"); \
> +	} while (0)

Again you have macros with magic names cl_hw & chip


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 32/96] cl8k: add fw.h
  2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
@ 2022-05-25 18:58   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-25 18:58 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:33 AM, viktor.barna@celeno.com wrote:
[snip]

> +/* Message structure. */
> +struct cl_fw_msg {
> +	__le16 msg_id;  /* Message ID. */
> +	u8 dst_kern_id; /* Destination kernel ID. */
> +	u8 dst_task_id; /* Destination task ID. */
> +	u8 src_kern_id; /* Source kernel ID. */
> +	u8 src_task_id; /* Source task ID. */
> +	__le16 param_len;  /* Parameter embedded struct length. */
> +	__le32 param[1];   /* Parameter embedded struct - must be word-aligned. */

use of [1] is deprecated and this usage will potentially break with 
upcoming "fortify source" kernel changes

see 
<https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays>

when you change to use just [] make sure that any code that uses 
sizeof(the current struct) is modified to account for the removal of one 
__le32 from the struct

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 03/96] cl8k: add Kconfig
  2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
@ 2022-05-26 18:18   ` Johannes Berg
  2022-05-27  6:09     ` Kalle Valo
  2022-07-13  7:32   ` Kalle Valo
  1 sibling, 1 reply; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 18:18 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:33 +0300, viktor.barna@celeno.com wrote:
> +
> +config CL8K_VERSION
> +	string "Version"
> +	depends on CL8K
> +	default "8.1.x"
> +	help
> +	  Sets module version, which may be important for FW compatibility
> +	  analysis and syncing upstream codebase with the internal codebase.
> 

This, along with the def.h stuff using it, and MODULE_VERSION(), is all
rather pointless, I think you should remove it.

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 05/96] cl8k: add ampdu.c
  2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
@ 2022-05-26 18:19   ` Johannes Berg
  2022-05-26 18:22   ` Johannes Berg
  1 sibling, 0 replies; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 18:19 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:33 +0300, viktor.barna@celeno.com wrote:
> 
> +	if (!ieee80211_hw_check(cl_hw->hw, AMPDU_AGGREGATION) || !cl_hw->conf->ci_agg_tx)
> +		return -ENOTSUPP;
> +
> +	if (!cl_txq_is_agg_available(cl_hw)) {
> +		cl_dbg_warn(cl_hw, "No free aggregation queue for sta_idx [%u] tid [%u]\n",
> +			    cl_sta->sta_idx, tid);
> +		return -1;
> 

That'd be -EPERM, which is really not what you want to return - please
use symbolic errors throughout. Maybe -ENOSPC in this case.

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 05/96] cl8k: add ampdu.c
  2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
  2022-05-26 18:19   ` Johannes Berg
@ 2022-05-26 18:22   ` Johannes Berg
  1 sibling, 0 replies; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 18:22 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:33 +0300, viktor.barna@celeno.com wrote:
> 
> +	if (sta->vht_cap.vht_supported) {
> +		u32 vht_exp = (sta->vht_cap.cap &
> +			       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
> +			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;

You can (often) simplify that kind of thing using u32_get_bits()

> +	he_exp = (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
> +		HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_OFFSET;

or u8_get_bits(), etc.

There are even le/be versions.

> +		struct ieee80211_he_6ghz_capa *he_6g_cap = &sta->he_6ghz_capa;
> +		u8 he_exp_6ghz = (le16_to_cpu(he_6g_cap->capa) &
> +				  HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
> +				  HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP_OFFSET;

which you could use here.

I know we don't use it everywhere yet, but IMHO it's ultimately nicer
code, and I definitely try to use it in new code.

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 04/96] cl8k: add Makefile
  2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
@ 2022-05-26 18:24   ` Johannes Berg
  2022-07-13  7:39   ` Kalle Valo
  1 sibling, 0 replies; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 18:24 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:33 +0300, viktor.barna@celeno.com wrote:
> 
> +ccflags-y += -I$(src) -I$(srctree)/net/wireless -I$(srctree)/net/mac80211/
> +ccflags-y += -I$(src) -Werror

Neither of these should be here. *Maybe* -I$(src), but that's probably
not even needed.

> +
> +define cc_ver_cmp
> +$(shell [ "$$($(CC) -dumpversion | cut -d. -f1)" -$(1) "$(2)" ] && echo "true" || echo "false")
> +endef
> +
> +ifeq ($(call cc_ver_cmp,ge,8),true)
> +ccflags-y += -Wno-error=stringop-truncation
> +ccflags-y += -Wno-error=format-truncation
> +endif
> +
> +# Stop these C90 warnings. We use C99.
> +ccflags-y += -Wno-declaration-after-statement -g

No no, all of that needs to go, don't make up your own stuff here.

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 36/96] cl8k: add key.c
  2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
@ 2022-05-26 19:38   ` Johannes Berg
  2022-07-11 23:10     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 19:38 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:34 +0300, viktor.barna@celeno.com wrote:
> 
> +static inline void cl_ccmp_hdr2pn(u8 *pn, u8 *hdr)
> +{
> +	pn[0] = hdr[7];
> +	pn[1] = hdr[6];
> +	pn[2] = hdr[5];
> +	pn[3] = hdr[4];
> +	pn[4] = hdr[1];
> +	pn[5] = hdr[0];
> +}
> +
> +static int cl_key_validate_pn(struct cl_hw *cl_hw, struct cl_sta *cl_sta, struct sk_buff *skb)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	int hdrlen = 0, res = 0;
> +	u8 pn[IEEE80211_CCMP_PN_LEN];
> +	u8 tid = 0;
> +
> +	hdrlen = ieee80211_hdrlen(hdr->frame_control);
> +	tid = ieee80211_get_tid(hdr);
> +
> +	cl_ccmp_hdr2pn(pn, skb->data + hdrlen);
> +	res = memcmp(pn, cl_sta->rx_pn[tid], IEEE80211_CCMP_PN_LEN);
> +	if (res < 0) {
> +		cl_hw->rx_info.pkt_drop_invalid_pn++;
> +		return -1;
> +	}
> +
> +	memcpy(cl_sta->rx_pn[tid], pn, IEEE80211_CCMP_PN_LEN);
> +
> +	return 0;
> +}

Why do you do this stuff in the driver if it's effectively the same as
in mac80211?

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 38/96] cl8k: add mac80211.c
  2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
@ 2022-05-26 19:49   ` Johannes Berg
  2022-07-11 23:13     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 19:49 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:34 +0300, viktor.barna@celeno.com wrote:
> 
> +static void cl_ops_tx_single(struct cl_hw *cl_hw,
> +			     struct sk_buff *skb,
> +			     struct ieee80211_tx_info *tx_info,
> +			     struct cl_sta *cl_sta,
> +			     struct ieee80211_sta *sta)
> +{

...

> +	if (sta) {
> +		u32 sta_vht_cap = sta->vht_cap.cap;
> +		struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
> +
> +		if (!(sta_vht_cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK))
> +			goto out_tx;
> +
> +		if (ieee80211_is_assoc_resp(mgmt->frame_control)) {
> +			int len = skb->len - (mgmt->u.assoc_resp.variable - skb->data);
> +			const u8 *vht_cap_addr = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY,
> +								 mgmt->u.assoc_resp.variable,
> +								 len);
> +
> +			if (vht_cap_addr) {
> +				struct ieee80211_vht_cap *vht_cap =
> +					(struct ieee80211_vht_cap *)(2 + vht_cap_addr);
> +
> +				vht_cap->vht_cap_info &=
> +					~(cpu_to_le32(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK |
> +						      IEEE80211_VHT_CAP_SHORT_GI_160));
> +			}

Huh??


> +int cl_ops_config(struct ieee80211_hw *hw, u32 changed)
> +{
> +	/*
> +	 * Handler for configuration requests. IEEE 802.11 code calls this
> +	 * function to change hardware configuration, e.g., channel.
> +	 * This function should never fail but returns a negative error code
> +	 * if it does. The callback can sleep
> +	 */
> +	int error = 0;
> +
> +	if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
> +		error = cl_ops_conf_change_channel(hw);

I'm really surprised to see this callback in a modern driver - wouldn't
you want to support some form of multi-channel operation? Even just
using the chanctx callbacks might make some of the DFS things you have
there easier?


> 
> +void cl_ops_bss_info_changed(struct ieee80211_hw *hw,
> +			     struct ieee80211_vif *vif,
> +			     struct ieee80211_bss_conf *info,
> +			     u32 changed)
> +{

...

> +		if (beacon) {
> +			size_t ies_len = beacon->tail_len;
> +			const u8 *ies = beacon->tail;
> +			const u8 *cap =  NULL;
> +			int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
> +			int len = beacon->head_len - var_offset;
> +			const u8 *var_pos = beacon->head + var_offset;
> +			const u8 *rate_ie = NULL;
> +
> +			cl_vif->wmm_enabled = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
> +								      WLAN_OUI_TYPE_MICROSOFT_WMM,
> +								      ies,
> +								      ies_len);
> +			cl_dbg_info(cl_hw, "vif=%d wmm_enabled=%d\n",
> +				    cl_vif->vif_index,
> +				    cl_vif->wmm_enabled);
> +
> +			cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
> +			if (cap && cap[1] >= sizeof(*ht_cap)) {
> +				ht_cap = (void *)(cap + 2);
> +				sgi_en |= (le16_to_cpu(ht_cap->cap_info) &
> +					   IEEE80211_HT_CAP_SGI_20) ||
> +					  (le16_to_cpu(ht_cap->cap_info) &
> +					   IEEE80211_HT_CAP_SGI_40);
> +			}
> +
> +			cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
> +			if (cap && cap[1] >= sizeof(*vht_cap)) {
> +				vht_cap = (void *)(cap + 2);
> +				sgi_en |= (le32_to_cpu(vht_cap->vht_cap_info) &
> +					   IEEE80211_VHT_CAP_SHORT_GI_80) ||
> +					  (le32_to_cpu(vht_cap->vht_cap_info) &
> +					   IEEE80211_VHT_CAP_SHORT_GI_160);
> +			}
> +
> +			cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
> +			if (cap && cap[1] >= sizeof(*he_cap) + 1)
> +				he_cap = (void *)(cap + 3);
> +
> +			rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
> +			if (rate_ie) {
> +				if (cl_band_is_24g(cl_hw))
> +					if (cl_is_valid_g_rates(rate_ie))
> +						hw_mode = cl_hw->conf->ci_cck_in_hw_mode ?
> +							     HW_MODE_BG : HW_MODE_G;
> +					else
> +						hw_mode = HW_MODE_B;
> +				else
> +					hw_mode = HW_MODE_A;
> +			}
> +		} else {
> +			cl_dbg_warn(cl_hw, "beacon_data not set!\n");
> +		}
> +

This feels ... odd. You really shouldn't have to look into the beacon to
figure out these things?

And SGI etc. are per-STA rate control parameters anyway? Hmm.

> +/* This function is required for PS flow - do not remove */
> +int cl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
> +{
> +	return 0;
> +}

You have all this hardware/firmware and you implement this? Interesting
design choice. One that I'm sure you'll revisit for WiFi 7 ;-)

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 39/96] cl8k: add mac80211.h
  2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
@ 2022-05-26 19:52   ` Johannes Berg
  0 siblings, 0 replies; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 19:52 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:34 +0300, viktor.barna@celeno.com wrote:
> 
> +#define PPE_0US 0
> +#define PPE_8US 1
> +#define PPE_16US 2
> +
> +/*
> + * Extended Channel Switching capability to be set in the 1st byte of
> + * the @WLAN_EID_EXT_CAPABILITY information element
> + */
> +#define WLAN_EXT_CAPA1_2040_BSS_COEX_MGMT_ENABLED BIT(0)
> +
> +/* WLAN_EID_BSS_COEX_2040 = 72 */
> +/* 802.11n 7.3.2.61 */
> +struct ieee80211_bss_coex_20_40_ie {
> +	u8 element_id;
> +	u8 len;
> +	u8 info_req : 1;
> +	/* Inter-BSS set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS */
> +	u8 intolerant40 : 1;
> +	/* Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS */
> +	u8 bss20_width_req : 1;
> +	u8 obss_scan_exemp_req : 1;
> +	u8 obss_scan_exemp_grant : 1;
> +	u8 rsv : 3;
> +} __packed;

You should add these kinds of things to ieee80211.h, but of course they
should be endian safe and not use bitfields.


> +/* WLAN_EID_BSS_INTOLERANT_CHL_REPORT = 73 */
> +/*802.11n 7.3.2.59 */
> +struct ieee80211_bss_intolerant_chl_report_ie {
> +	u8 element_id;
> +	u8 len;
> +	u8 regulatory_class;
> +	u8 ch_list[0];

use [] not [0]

> +} __packed;
> +
> +/* Union options that are not included in 'struct ieee80211_mgmt' */

just add them

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 59/96] cl8k: add rates.h
  2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
@ 2022-05-26 19:54   ` Johannes Berg
  2022-07-11 23:17     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Johannes Berg @ 2022-05-26 19:54 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On Tue, 2022-05-24 at 14:34 +0300, viktor.barna@celeno.com wrote:
> 
> +/*
> + * sw_ctrl includes eights bits (16 - 23) to be used by software.


that makes it sound like these are firmware things and should be endian
safe?

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 40/96] cl8k: add mac_addr.c
  2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
@ 2022-05-26 22:31   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-26 22:31 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:34 AM, viktor.barna@celeno.com wrote:
[snip]

> +	/* Determine the bits necessary to cover the number of BSSIDs. */
> +	u8 num_bits_to_mask[ARRAY_SIZE(cl_hw->addresses) * TCV_MAX] = {

is there a reason this isn't static const?

> +		0, /* 0 : 00:1C:51:BD:FB:(0b 0000 0000) -> 0-bit diff (no LAM, original MAC) */
> +		0, /* 1 : 02:1C:51:BD:FB:(0b 0000 0000) -> 0-bit diff (LAM) */
> +
> +		1, /* 2 : 02:1C:51:BD:FB:(0b 0000 0001) -> 1-bit diff (LAM, between address #1) */
> +
> +		2, /* 3 : 02:1C:51:BD:FB:(0b 0000 0011) -> 2-bit diff (LAM) */
> +		2, /* 4 : 02:1C:51:BD:FB:(0b 0000 0010) -> 2-bit diff (LAM) */
> +
> +		3, /* 5 : 02:1C:51:BD:FB:(0b 0000 0111) -> 3-bit diff (LAM) */
> +		3, /* 6 : 02:1C:51:BD:FB:(0b 0000 0100) -> 3-bit diff (LAM) */
> +		3, /* 7 : 02:1C:51:BD:FB:(0b 0000 0101) -> 3-bit diff (LAM) */
> +		3, /* 8 : 02:1C:51:BD:FB:(0b 0000 0110) -> 3-bit diff (LAM) */
> +
> +		4, /* 9 : 02:1C:51:BD:FB:(0b 0000 1111) -> 4-bit diff (LAM) */
> +		4, /* 10: 02:1C:51:BD:FB:(0b 0000 1000) -> 4-bit diff (LAM) */
> +		4, /* 11: 02:1C:51:BD:FB:(0b 0000 1001) -> 4-bit diff (LAM) */
> +		4, /* 12: 02:1C:51:BD:FB:(0b 0000 1010) -> 4-bit diff (LAM) */
> +		4, /* 13: 02:1C:51:BD:FB:(0b 0000 1100) -> 4-bit diff (LAM) */
> +		4, /* 14: 02:1C:51:BD:FB:(0b 0000 1110) -> 4-bit diff (LAM) */
> +		4, /* 15: 02:1C:51:BD:FB:(0b 0000 1011) -> 4-bit diff (LAM) */
> +	};
> +

[snip]

> +	u8 lam_bit_mask[ARRAY_SIZE(cl_hw->addresses) * TCV_MAX] = {

static const?

> +		0b0000, /* 1 addr,  0-bit diff between MAC addrs, LAM is not affecting it */
> +		0b0000, /* 2 addrs, 0-bit diff between MAC addrs, first differs by LAM !!! */
> +		0b0001, /* 3 addrs, 1-bit diff */
> +		0b0011, /* 4 addrs, 2-bit diff */
> +		0b0011, /* 5 addrs, 2-bit diff */
> +
> +		0b0111, /* 6 addrs, 3-bit diff */
> +		0b0111, /* 7 addrs, 3-bit diff */
> +		0b0111, /* 8 addrs, 3-bit diff */
> +		0b0111, /* 9 addrs, 3-bit diff */
> +
> +		0b1111, /* 10 addrs, 4-bit diff */
> +		0b1111, /* 11 addrs, 4-bit diff */
> +		0b1111, /* 12 addrs, 4-bit diff */
> +		0b1111, /* 13 addrs, 4-bit diff */
> +		0b1111, /* 14 addrs, 4-bit diff */
> +		0b1111, /* 15 addrs, 4-bit diff */
> +		0b1111, /* 16 addrs, 4-bit diff */
> +	};

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 42/96] cl8k: add main.c
  2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
@ 2022-05-26 23:01   ` Jeff Johnson
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff Johnson @ 2022-05-26 23:01 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:34 AM, viktor.barna@celeno.com wrote:
> From: Viktor Barna <viktor.barna@celeno.com>
> 
> (Part of the split. Please, take a look at the cover letter for more
> details).
> 
> Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
> ---
>   drivers/net/wireless/celeno/cl8k/main.c | 603 ++++++++++++++++++++++++
>   1 file changed, 603 insertions(+)
>   create mode 100644 drivers/net/wireless/celeno/cl8k/main.c
> 
> diff --git a/drivers/net/wireless/celeno/cl8k/main.c b/drivers/net/wireless/celeno/cl8k/main.c
> new file mode 100644
> index 000000000000..08abb16987ef
> --- /dev/null
> +++ b/drivers/net/wireless/celeno/cl8k/main.c
> @@ -0,0 +1,603 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
> +
> +#include "tx.h"
> +#include "reg/reg_access.h"
> +#include "reg/reg_defs.h"
> +#include "stats.h"
> +#include "maintenance.h"
> +#include "vns.h"
> +#include "traffic.h"
> +#include "sounding.h"
> +#include "recovery.h"
> +#include "rates.h"
> +#include "utils.h"
> +#include "phy.h"
> +#include "radio.h"
> +#include "dsp.h"
> +#include "dfs.h"
> +#include "tcv.h"
> +#include "mac_addr.h"
> +#include "bf.h"
> +#include "rfic.h"
> +#include "e2p.h"
> +#include "chip.h"
> +#include "regdom.h"
> +#include "platform.h"
> +#include "mac80211.h"
> +#include "main.h"
> +
> +MODULE_DESCRIPTION("Celeno 11ax driver for Linux");
> +MODULE_VERSION(CONFIG_CL8K_VERSION);
> +MODULE_AUTHOR("Copyright(c) 2022 Celeno Communications Ltd");
> +MODULE_LICENSE("Dual BSD/GPL");
> +
> +static struct ieee80211_ops cl_ops = {

const?

> +	.tx                     = cl_ops_tx,
> +	.start                  = cl_ops_start,
> +	.stop                   = cl_ops_stop,
> +	.add_interface          = cl_ops_add_interface,
> +	.remove_interface       = cl_ops_remove_interface,
> +	.config                 = cl_ops_config,
> +	.bss_info_changed       = cl_ops_bss_info_changed,
> +	.start_ap               = cl_ops_start_ap,
> +	.stop_ap                = cl_ops_stop_ap,
> +	.prepare_multicast      = cl_ops_prepare_multicast,
> +	.configure_filter       = cl_ops_configure_filter,
> +	.set_key                = cl_ops_set_key,
> +	.sw_scan_start          = cl_ops_sw_scan_start,
> +	.sw_scan_complete       = cl_ops_sw_scan_complete,
> +	.sta_state              = cl_ops_sta_state,
> +	.sta_notify             = cl_ops_sta_notify,
> +	.conf_tx                = cl_ops_conf_tx,
> +	.sta_rc_update          = cl_ops_sta_rc_update,
> +	.ampdu_action           = cl_ops_ampdu_action,
> +	.post_channel_switch    = cl_ops_post_channel_switch,
> +	.flush                  = cl_ops_flush,
> +	.tx_frames_pending      = cl_ops_tx_frames_pending,
> +	.reconfig_complete      = cl_ops_reconfig_complete,
> +	.get_txpower            = cl_ops_get_txpower,
> +	.set_rts_threshold      = cl_ops_set_rts_threshold,
> +	.event_callback         = cl_ops_event_callback,
> +	.set_tim                = cl_ops_set_tim,
> +	.get_antenna            = cl_ops_get_antenna,
> +	.get_expected_throughput = cl_ops_get_expected_throughput,
> +	.sta_statistics         = cl_ops_sta_statistics,
> +	.get_survey             = cl_ops_get_survey,
> +	.hw_scan                = cl_ops_hw_scan,
> +	.cancel_hw_scan         = cl_ops_cancel_hw_scan
> +};
> +
> +static void cl_drv_workqueue_create(struct cl_hw *cl_hw)
> +{
> +	if (!cl_hw->drv_workqueue)
> +		cl_hw->drv_workqueue = create_singlethread_workqueue("drv_workqueue");
> +}
> +
> +static void cl_drv_workqueue_destroy(struct cl_hw *cl_hw)
> +{
> +	if (cl_hw->drv_workqueue) {
> +		destroy_workqueue(cl_hw->drv_workqueue);
> +		cl_hw->drv_workqueue = NULL;
> +	}
> +}
> +
> +static int cl_main_alloc(struct cl_hw *cl_hw)
> +{
> +	int ret = 0;

avoid initializers that are always overwritten, especially ones that are 
overwritten by the very first line of code

> +
> +	ret = cl_phy_data_alloc(cl_hw);
> +	if (ret)
> +		return ret;
> +
> +	ret = cl_calib_common_tables_alloc(cl_hw);
> +	if (ret)
> +		return ret;
> +
> +	ret = cl_power_table_alloc(cl_hw);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +static void cl_main_free(struct cl_hw *cl_hw)
> +{
> +	cl_phy_data_free(cl_hw);
> +	cl_calib_common_tables_free(cl_hw);
> +	cl_power_table_free(cl_hw);

hint: consider performing deinit steps in reverse order of init steps. 
it may not always matter, but when it does, you'll be happy that you're 
doing things consistently -- what happens when you try taking off your 
socks before you take off your shoes? :)

> +}
> +
> +static void cl_free_hw(struct cl_hw *cl_hw)
> +{
> +	if (!cl_hw)
> +		return;
> +
> +	cl_temperature_wait_for_measurement(cl_hw->chip, cl_hw->tcv_idx);
> +
> +	cl_tcv_config_free(cl_hw);
> +
> +	if (cl_hw->hw->wiphy->registered)
> +		ieee80211_unregister_hw(cl_hw->hw);
> +
> +	cl_chip_unset_hw(cl_hw->chip, cl_hw);
> +	ieee80211_free_hw(cl_hw->hw);

I'm paranoid so I always set pointers to NULL when I've freed the 
underlying data so that nothing else can later dereference them, and 
potentially lead to use-after-free or double-free

> +}
> +
> +static void cl_free_chip(struct cl_chip *chip)
> +{
> +	cl_free_hw(chip->cl_hw_tcv0);
> +	cl_free_hw(chip->cl_hw_tcv1);
> +}
> +
> +static int cl_prepare_hw(struct cl_chip *chip, u8 tcv_idx,
> +			 const struct cl_driver_ops *drv_ops)
> +{
> +	struct cl_hw *cl_hw = NULL;

another initializer that is immediately overwritten by the first line of 
code

> +	struct ieee80211_hw *hw;
> +	int ret = 0;
> +
> +	hw = ieee80211_alloc_hw(sizeof(struct cl_hw), &cl_ops);
> +	if (!hw) {
> +		cl_dbg_chip_err(chip, "ieee80211_alloc_hw failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	cl_hw_init(chip, hw->priv, tcv_idx);
> +
> +	cl_hw = hw->priv;
> +	cl_hw->hw = hw;
> +	cl_hw->tcv_idx = tcv_idx;
> +	cl_hw->sx_idx = chip->conf->ci_tcv1_chains_sx0 ? 0 : tcv_idx;
> +	cl_hw->chip = chip;
> +
> +	/*
> +	 * chip0, tcv0 --> 0
> +	 * chip0, tcv1 --> 1
> +	 * chip1, tcv0 --> 2
> +	 * chip1, tcv1 --> 3
> +	 */
> +	cl_hw->idx = chip->idx * CHIP_MAX + tcv_idx;
> +
> +	cl_hw->drv_ops = drv_ops;
> +
> +	SET_IEEE80211_DEV(hw, chip->dev);
> +
> +	ret = cl_tcv_config_alloc(cl_hw);
> +	if (ret)
> +		goto out_free_hw;
> +
> +	ret = cl_tcv_config_read(cl_hw);
> +	if (ret)
> +		goto out_free_hw;
> +
> +	cl_chip_set_hw(chip, cl_hw);
> +
> +	ret = cl_mac_addr_set(cl_hw);
> +	if (ret) {
> +		cl_dbg_err(cl_hw, "cl_mac_addr_set failed\n");
> +		goto out_free_hw;
> +	}
> +
> +	if (cl_band_is_6g(cl_hw))
> +		cl_hw->nl_band = NL80211_BAND_6GHZ;
> +	else if (cl_band_is_5g(cl_hw))
> +		cl_hw->nl_band = NL80211_BAND_5GHZ;
> +	else
> +		cl_hw->nl_band = NL80211_BAND_2GHZ;
> +
> +	if (cl_band_is_24g(cl_hw))
> +		cl_hw->hw_mode = HW_MODE_BG;
> +	else
> +		cl_hw->hw_mode = HW_MODE_A;
> +
> +	cl_hw->wireless_mode = WIRELESS_MODE_HT_VHT_HE;
> +
> +	cl_cap_dyn_params(cl_hw);
> +
> +	cl_dbg_verbose(cl_hw, "cl_hw created\n");
> +
> +	return 0;
> +
> +out_free_hw:
> +	cl_free_hw(cl_hw);
> +
> +	return ret;
> +}
> +
> +void cl_main_off(struct cl_hw *cl_hw)
> +{
> +	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
> +	cl_ipc_stop(cl_hw);
> +
> +	if (!test_bit(CL_DEV_INIT, &cl_hw->drv_flags)) {
> +		cl_tx_off(cl_hw);
> +		cl_rx_off(cl_hw);
> +		cl_msg_rx_flush_all(cl_hw);
> +	}
> +
> +	cl_fw_file_cleanup(cl_hw);
> +}
> +
> +static void _cl_main_deinit(struct cl_hw *cl_hw)
> +{
> +	if (!cl_hw)
> +		return;
> +
> +	ieee80211_unregister_hw(cl_hw->hw);
> +
> +	/* Send reset message to firmware */
> +	cl_msg_tx_reset(cl_hw);
> +
> +	cl_hw->is_stop_context = true;
> +
> +	cl_drv_workqueue_destroy(cl_hw);
> +
> +	cl_scanner_deinit(cl_hw);
> +
> +	cl_noise_close(cl_hw);
> +	cl_maintenance_close(cl_hw);
> +	cl_vns_close(cl_hw);
> +	cl_rssi_assoc_exit(cl_hw);
> +	cl_radar_close(cl_hw);
> +	cl_sounding_close(cl_hw);
> +	cl_chan_info_deinit(cl_hw);
> +	cl_wrs_api_close(cl_hw);
> +	cl_main_off(cl_hw);
> +	/* These 2 must be called after cl_tx_off() (which is called from cl_main_off) */
> +	cl_tx_amsdu_txhdr_deinit(cl_hw);
> +	cl_sw_txhdr_deinit(cl_hw);
> +	cl_fw_dbg_trigger_based_deinit(cl_hw);
> +	cl_stats_deinit(cl_hw);
> +	cl_main_free(cl_hw);
> +	cl_fw_file_release(cl_hw);
> +
> +	cl_ipc_deinit(cl_hw);
> +	cl_hw_deinit(cl_hw, cl_hw->tcv_idx);
> +	vfree(cl_hw->tx_queues);
> +}
> +
> +void cl_main_deinit(struct cl_chip *chip)
> +{
> +	struct cl_chip_conf *conf = chip->conf;
> +	struct cl_hw *cl_hw_tcv0 = chip->cl_hw_tcv0;
> +	struct cl_hw *cl_hw_tcv1 = chip->cl_hw_tcv1;
> +
> +	if (cl_chip_is_tcv1_enabled(chip) && cl_hw_tcv1)
> +		_cl_main_deinit(cl_hw_tcv1);
> +
> +	if (cl_chip_is_tcv0_enabled(chip) && cl_hw_tcv0)
> +		_cl_main_deinit(cl_hw_tcv0);
> +
> +	if (conf->ci_phy_dev != PHY_DEV_DUMMY) {
> +		if (!conf->ci_phy_load_bootdrv)
> +			cl_phy_off(cl_hw_tcv1);
> +
> +		cl_phy_off(cl_hw_tcv0);
> +	}
> +
> +	cl_platform_dealloc(chip);
> +
> +	cl_free_chip(chip);
> +}
> +
> +static struct cl_controller_reg all_controller_reg = {

if this is read-only then consider making it const

> +	.breset = XMAC_BRESET,
> +	.debug_enable = XMAC_DEBUG_ENABLE,
> +	.dreset = XMAC_DRESET,
> +	.ocd_halt_on_reset = XMAC_OCD_HALT_ON_RESET,
> +	.run_stall = XMAC_RUN_STALL
> +};
> +
> +void cl_main_reset(struct cl_chip *chip, struct cl_controller_reg *controller_reg)

would need to add const to 2nd param if you make the table const.
even if you didn't make the table const, it is good form to declare 
pointer params as const if you don't write back into the struct

> +{
> +	/* Release TRST & BReset to enable JTAG connection to FPGA A */
> +	u32 regval;
> +
> +	/* 1. return to reset value */
> +	regval = macsys_gcu_xt_control_get(chip);
> +	regval |= controller_reg->ocd_halt_on_reset;
> +	regval &= ~(controller_reg->dreset | controller_reg->run_stall | controller_reg->breset);
> +	macsys_gcu_xt_control_set(chip, regval);
> +
> +	regval = macsys_gcu_xt_control_get(chip);
> +	regval |= controller_reg->dreset;
> +	macsys_gcu_xt_control_set(chip, regval);
> +
> +	/* 2. stall xtensa & release ocd */
> +	regval = macsys_gcu_xt_control_get(chip);
> +	regval |= controller_reg->run_stall;
> +	regval &= ~controller_reg->ocd_halt_on_reset;
> +	macsys_gcu_xt_control_set(chip, regval);
> +
> +	/* 3. breset release & debug enable */
> +	regval = macsys_gcu_xt_control_get(chip);
> +	regval |= (controller_reg->debug_enable | controller_reg->breset);
> +	macsys_gcu_xt_control_set(chip, regval);
> +
> +	msleep(100);
> +}
> +
> +int cl_main_on(struct cl_hw *cl_hw)
> +{
> +	struct cl_chip *chip = cl_hw->chip;
> +	int ret;
> +	u32 regval;
> +
> +	cl_hw->fw_active = false;
> +
> +	cl_txq_init(cl_hw);
> +
> +	cl_hw_assert_info_init(cl_hw);
> +
> +	if (cl_recovery_in_progress(cl_hw))
> +		cl_main_reset(chip, &cl_hw->controller_reg);
> +
> +	ret = cl_fw_file_load(cl_hw);
> +	if (ret) {
> +		cl_dbg_err(cl_hw, "cl_fw_file_load failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Clear CL_DEV_FW_ERROR after firmware loaded */
> +	clear_bit(CL_DEV_FW_ERROR, &cl_hw->drv_flags);
> +
> +	if (cl_recovery_in_progress(cl_hw))
> +		cl_ipc_recovery(cl_hw);
> +
> +	regval = macsys_gcu_xt_control_get(chip);
> +
> +	/* Set fw to run */
> +	if (cl_hw->fw_active)
> +		regval &= ~cl_hw->controller_reg.run_stall;
> +
> +	/* Set umac to run */
> +	if (chip->umac_active)
> +		regval &= ~UMAC_RUN_STALL;
> +
> +	/* Ack all possibly pending IRQs */
> +	ipc_xmac_2_host_ack_set(chip, cl_hw->ipc_e2a_irq.all);
> +	macsys_gcu_xt_control_set(chip, regval);
> +	cl_irq_enable(cl_hw, cl_hw->ipc_e2a_irq.all);
> +	/*
> +	 * cl_irq_status_sync will set CL_DEV_FW_SYNC when fw raises IPC_IRQ_E2A_SYNC
> +	 * (indicate its ready to accept interrupts)
> +	 */
> +	ret = wait_event_interruptible_timeout(cl_hw->fw_sync_wq,
> +					       test_and_clear_bit(CL_DEV_FW_SYNC,
> +								  &cl_hw->drv_flags),
> +					       msecs_to_jiffies(5000));
> +
> +	if (ret == 0) {
> +		pr_err("[%s]: FW synchronization timeout.\n", __func__);
> +		cl_hw_assert_check(cl_hw);
> +		ret = -ETIMEDOUT;
> +		goto out_free_cached_fw;
> +	} else if (ret == -ERESTARTSYS) {
> +		goto out_free_cached_fw;
> +	}
> +
> +	return 0;
> +
> +out_free_cached_fw:
> +	cl_irq_disable(cl_hw, cl_hw->ipc_e2a_irq.all);
> +	cl_fw_file_release(cl_hw);
> +	return ret;
> +}
> +
> +static int __cl_main_init(struct cl_hw *cl_hw)
> +{
> +	int ret;
> +
> +	if (!cl_hw)
> +		return 0;
> +
> +	if (cl_regd_init(cl_hw, cl_hw->hw->wiphy))
> +		cl_dbg_err(cl_hw, "regulatory failed\n");
> +
> +	/*
> +	 * ieee80211_register_hw() will take care of calling wiphy_register() and
> +	 * also ieee80211_if_add() (because IFTYPE_STATION is supported)
> +	 * which will internally call register_netdev()
> +	 */
> +	ret = ieee80211_register_hw(cl_hw->hw);
> +	if (ret) {
> +		cl_dbg_err(cl_hw, "ieee80211_register_hw failed\n");
> +		cl_main_deinit(cl_hw->chip);
> +
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int _cl_main_init(struct cl_hw *cl_hw)
> +{
> +	int ret = 0;
> +
> +	if (!cl_hw)
> +		return 0;
> +
> +	set_bit(CL_DEV_INIT, &cl_hw->drv_flags);
> +
> +	/* By default, set FEM mode to opertional mode. */
> +	cl_hw->fem_mode = FEM_MODE_OPERETIONAL;
> +
> +	cl_vif_init(cl_hw);
> +
> +	cl_drv_workqueue_create(cl_hw);
> +
> +	init_waitqueue_head(&cl_hw->wait_queue);
> +	init_waitqueue_head(&cl_hw->fw_sync_wq);
> +	init_waitqueue_head(&cl_hw->radio_wait_queue);
> +
> +	mutex_init(&cl_hw->dbginfo.mutex);
> +	mutex_init(&cl_hw->msg_tx_mutex);
> +	mutex_init(&cl_hw->set_channel_mutex);
> +
> +	spin_lock_init(&cl_hw->tx_lock_agg);
> +	spin_lock_init(&cl_hw->tx_lock_cfm_agg);
> +	spin_lock_init(&cl_hw->tx_lock_single);
> +	spin_lock_init(&cl_hw->tx_lock_bcmc);
> +	spin_lock_init(&cl_hw->channel_info_lock);
> +
> +	ret = cl_ipc_init(cl_hw);
> +	if (ret) {
> +		cl_dbg_err(cl_hw, "cl_ipc_init failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	cl_chip_set_rfic_version(cl_hw);
> +
> +	/* Validate calib params should be called after setting the rfic version */
> +	cl_tcv_config_validate_calib_params(cl_hw);
> +
> +	cl_hw->tx_queues = vzalloc(sizeof(*cl_hw->tx_queues));
> +	if (!cl_hw->tx_queues) {
> +		cl_ipc_deinit(cl_hw);
> +		return -ENOMEM;
> +	}
> +
> +	ret = cl_main_on(cl_hw);
> +	if (ret) {
> +		cl_dbg_err(cl_hw, "cl_main_on failed %d\n", ret);
> +		cl_ipc_deinit(cl_hw);
> +		vfree(cl_hw->tx_queues);
> +
> +		return ret;
> +	}
> +
> +	ret = cl_main_alloc(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	/* Reset firmware */
> +	ret = cl_msg_tx_reset(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	cl_calib_power_read(cl_hw);
> +	cl_sta_init(cl_hw);
> +	cl_sw_txhdr_init(cl_hw);
> +	cl_tx_amsdu_txhdr_init(cl_hw);
> +	cl_rx_init(cl_hw);
> +	cl_prot_mode_init(cl_hw);
> +	cl_radar_init(cl_hw);
> +	cl_sounding_init(cl_hw);
> +	cl_traffic_init(cl_hw);
> +	ret = cl_vns_init(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	cl_maintenance_init(cl_hw);
> +	cl_rssi_assoc_init(cl_hw);
> +	cl_agg_cfm_init(cl_hw);
> +	cl_single_cfm_init(cl_hw);
> +	cl_bcmc_cfm_init(cl_hw);
> +#ifdef CONFIG_CL8K_DYN_MCAST_RATE
> +	cl_dyn_mcast_rate_init(cl_hw);
> +#endif /* CONFIG_CL8K_DYN_MCAST_RATE */
> +#ifdef CONFIG_CL8K_DYN_BCAST_RATE
> +	cl_dyn_bcast_rate_init(cl_hw);
> +#endif /* CONFIG_CL8K_DYN_BCAST_RATE */
> +	cl_wrs_api_init(cl_hw);
> +	cl_dfs_init(cl_hw);
> +	cl_noise_init(cl_hw);
> +	ret = cl_fw_dbg_trigger_based_init(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	cl_stats_init(cl_hw);
> +	cl_cca_init(cl_hw);
> +	cl_bf_init(cl_hw);
> +
> +	ret = cl_scanner_init(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	/* Start firmware */
> +	ret = cl_msg_tx_start(cl_hw);
> +	if (ret)
> +		goto out_free;
> +
> +	return 0;
> +
> +out_free:
> +	cl_main_free(cl_hw);
> +	vfree(cl_hw->tx_queues);
> +
> +	return ret;
> +}
> +
> +int cl_main_init(struct cl_chip *chip, const struct cl_driver_ops *drv_ops)
> +{
> +	int ret = 0;
> +	struct cl_chip_conf *conf = chip->conf;
> +
> +	/* All cores needs to be reset first (once per chip) */
> +	cl_main_reset(chip, &all_controller_reg);
> +
> +	/* Prepare HW for TCV0 */
> +	if (cl_chip_is_tcv0_enabled(chip)) {
> +		ret = cl_prepare_hw(chip, TCV0, drv_ops);
> +
> +		if (ret) {
> +			cl_dbg_chip_err(chip, "Prepare HW for TCV0 failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	/* Prepare HW for TCV1 */
> +	if (cl_chip_is_tcv1_enabled(chip)) {
> +		ret = cl_prepare_hw(chip, TCV1, drv_ops);
> +
> +		if (ret) {
> +			cl_dbg_chip_err(chip, "Prepare HW for TCV1 failed %d\n", ret);
> +			cl_free_hw(chip->cl_hw_tcv0);
> +			return ret;
> +		}
> +	}
> +
> +	if (!conf->ci_phy_load_bootdrv &&
> +	    conf->ci_phy_dev != PHY_DEV_DUMMY) {
> +		ret = cl_radio_boot(chip);
> +		if (ret) {
> +			cl_dbg_chip_err(chip, "RF boot failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		ret = cl_dsp_load_regular(chip);
> +		if (ret) {
> +			cl_dbg_chip_err(chip, "DSP load failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	ret = _cl_main_init(chip->cl_hw_tcv0);
> +	if (ret) {
> +		cl_free_chip(chip);
> +		return ret;
> +	}
> +
> +	ret = _cl_main_init(chip->cl_hw_tcv1);
> +	if (ret) {
> +		_cl_main_deinit(chip->cl_hw_tcv0);
> +		cl_free_chip(chip);
> +		return ret;
> +	}
> +
> +	ret = __cl_main_init(chip->cl_hw_tcv0);
> +	if (ret)
> +		return ret;
> +
> +	ret = __cl_main_init(chip->cl_hw_tcv1);
> +	if (ret)
> +		return ret;
> +
> +#ifdef CONFIG_CL8K_EEPROM_STM24256
> +	if (conf->ci_calib_eeprom_en && conf->ce_production_mode && conf->ce_calib_runtime_en)
> +		cl_e2p_read_eeprom_start_work(chip);
> +#endif
> +
> +	return ret;
> +}


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 03/96] cl8k: add Kconfig
  2022-05-26 18:18   ` Johannes Berg
@ 2022-05-27  6:09     ` Kalle Valo
  2022-07-11 23:04       ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Kalle Valo @ 2022-05-27  6:09 UTC (permalink / raw)
  To: Johannes Berg
  Cc: viktor.barna, linux-wireless, David S . Miller, Jakub Kicinski,
	Aviad Brikman, Eliav Farber, Maksym Kokhan, Oleksandr Savchenko,
	Shay Bar

Johannes Berg <johannes@sipsolutions.net> writes:

> On Tue, 2022-05-24 at 14:33 +0300, viktor.barna@celeno.com wrote:
>> +
>> +config CL8K_VERSION
>> +	string "Version"
>> +	depends on CL8K
>> +	default "8.1.x"
>> +	help
>> +	  Sets module version, which may be important for FW compatibility
>> +	  analysis and syncing upstream codebase with the internal codebase.
>> 
>
> This, along with the def.h stuff using it, and MODULE_VERSION(), is all
> rather pointless, I think you should remove it.

s/should/need to/ :)

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 50/96] cl8k: add phy.c
  2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
@ 2022-06-01  0:27   ` Jeff Johnson
  2022-07-11 23:16     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff Johnson @ 2022-06-01  0:27 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:34 AM, viktor.barna@celeno.com wrote:
> From: Viktor Barna <viktor.barna@celeno.com>
> 
> (Part of the split. Please, take a look at the cover letter for more
> details).
> 
> Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
> ---
>   drivers/net/wireless/celeno/cl8k/phy.c | 9648 ++++++++++++++++++++++++
>   1 file changed, 9648 insertions(+)
>   create mode 100644 drivers/net/wireless/celeno/cl8k/phy.c
> 
> diff --git a/drivers/net/wireless/celeno/cl8k/phy.c b/drivers/net/wireless/celeno/cl8k/phy.c
> new file mode 100644
> index 000000000000..dfc7f5a95d3d
> --- /dev/null
> +++ b/drivers/net/wireless/celeno/cl8k/phy.c
> @@ -0,0 +1,9648 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
> +
> +#include "tx.h"
> +#include "reg/reg_defs.h"
> +#include "radio.h"
> +#include "dsp.h"
> +#include "rfic.h"
> +#include "e2p.h"
> +#include "phy.h"
> +
> +#define FEM_LUT_EMPTY 0x0
> +
> +const struct common_lut_line athos_lut_6g_40_mhz[ATHOS_LUT_CHAN_6G_MAX] = {

in this file and in power.c you have multiple lookup tables that look 
like they could/should be static to limit their scope to the current file

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 67/96] cl8k: add rfic.h
  2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
@ 2022-06-02 20:40   ` Jeff Johnson
  2022-07-11 23:18     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff Johnson @ 2022-06-02 20:40 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:34 AM, viktor.barna@celeno.com wrote:
> From: Viktor Barna <viktor.barna@celeno.com>
> 
> (Part of the split. Please, take a look at the cover letter for more
> details).
> 
> Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
> ---
>   drivers/net/wireless/celeno/cl8k/rfic.h | 29 +++++++++++++++++++++++++
>   1 file changed, 29 insertions(+)
>   create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.h
> 
> diff --git a/drivers/net/wireless/celeno/cl8k/rfic.h b/drivers/net/wireless/celeno/cl8k/rfic.h
> new file mode 100644
> index 000000000000..686ebd6fcd98
> --- /dev/null
> +++ b/drivers/net/wireless/celeno/cl8k/rfic.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
> +/* Copyright(c) 2019-2022, Celeno Communications Ltd. */
> +
> +#ifndef CL_RFIC_H
> +#define CL_RFIC_H
> +
> +#include "hw.h"
> +
> +#define ATHOS_A_VER    0xB1
> +#define ATHOS_B_VER    0xB2
> +
> +enum cl_rf_overwrite_cmd {
> +	OVERWRITE_DONE,
> +	SPI_RD_CMD,
> +	SPI_WR_CMD,
> +	GCU_WR_CMD,
> +	RIU_WR_CMD,
> +	UDELAY_CMD,
> +	GEN_WR_CMD,
> +	RF_OVERWRITE_CMD_MAX = OVERWRITE_DONE

consider adding CL_ prefix to the enumerators to avoid namespace collision.

why is OVERWRITE_DONE the max command? that doesn't seem to make sense 
since other enumerators are defined after it.

> +};
> +
> +int cl_spi_driver_read_byte(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val);
> +int cl_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val);
> +int cl_rfic_read_overwrite_file(struct cl_hw *cl_hw,
> +				struct cl_rf_reg_overwrite_info *info,
> +				bool init);
> +void cl_chip_set_rfic_version(struct cl_hw *cl_hw);
> +#endif /* CL_RFIC_H */


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 76/96] cl8k: add stats.c
  2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
@ 2022-06-02 20:59   ` Jeff Johnson
  2022-07-11 23:20     ` Viktor Barna
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff Johnson @ 2022-06-02 20:59 UTC (permalink / raw)
  To: viktor.barna, linux-wireless
  Cc: Kalle Valo, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

On 5/24/2022 4:34 AM, viktor.barna@celeno.com wrote:
[snip]

> +static void _cl_stats_update_tx(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
> +				struct cl_agg_tx_report *agg_report)
> +{
> +	struct cl_stats *stats = cl_sta->stats;
> +	struct cl_tx_cntrs *cntrs;
> +	union cl_rate_ctrl_info rate_ctrl_info = {
> +		.word = le32_to_cpu(agg_report->rate_cntrl_info)};
> +	u8 bw, nss, mcs, gi, bf;
> +
> +	switch (rate_ctrl_info.field.format_mod) {
> +	case WRS_MODE_HE:
> +		nss = (rate_ctrl_info.field.mcs_index >> 4);
> +		mcs = (rate_ctrl_info.field.mcs_index & 0xF);
> +		gi = rate_ctrl_info.field.gi;
> +
> +		{

why an embedded block? seems to serve no purpose

> +			bw = rate_ctrl_info.field.bw;
> +			bf = agg_report->bf;
> +
> +				cntrs = &stats->tx.he[bw][nss][mcs][gi][bf];

bad indentation

> +		}
> +		break;
> +	case WRS_MODE_VHT:
> +		bw = rate_ctrl_info.field.bw;
> +		nss = (rate_ctrl_info.field.mcs_index >> 4);
> +		mcs = (rate_ctrl_info.field.mcs_index & 0xF);
> +		gi = rate_ctrl_info.field.gi;
> +		bf = agg_report->bf;
> +
> +			cntrs = &stats->tx.vht[bw][nss][mcs][gi][bf];

bad indentation

> +		break;
> +	case WRS_MODE_HT:
> +		bw = rate_ctrl_info.field.bw;
> +		nss = (rate_ctrl_info.field.mcs_index >> 3);
> +		mcs = (rate_ctrl_info.field.mcs_index & 0x7);
> +		gi = rate_ctrl_info.field.gi;
> +		cntrs = &stats->tx.ht[bw][nss][mcs][gi];
> +		break;
> +	case WRS_MODE_OFDM:
> +		mcs = rate_ctrl_info.field.mcs_index - RATE_CTRL_OFFSET_OFDM;
> +		cntrs = &stats->tx.ofdm[mcs];
> +		break;
> +	case WRS_MODE_CCK:
> +		mcs = rate_ctrl_info.field.mcs_index;
> +		cntrs = &stats->tx.cck[mcs];
> +		break;
> +	default:
> +		return;
> +	}

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 03/96] cl8k: add Kconfig
  2022-05-27  6:09     ` Kalle Valo
@ 2022-07-11 23:04       ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:04 UTC (permalink / raw)
  To: kvalo
  Cc: aviad.brikman, davem, eliav.farber, johannes, kuba,
	linux-wireless, maksym.kokhan, oleksandr.savchenko, shay.bar,
	viktor.barna

On Fri, 27 May 2022 09:09:19 +0300, kvalo@kernel.org wrote:
>
>> On Thu, 26 May 2022 20:18:35 +0200, johannes@sipsolutions.net wrote:
>> 
>> This, along with the def.h stuff using it, and MODULE_VERSION(), is all
>> rather pointless, I think you should remove it.
>
> s/should/need to/ :)
>

That is an unexpected comment:) Can you please clarify what is wrong with that
place and why it is pointless (regarding the fact that it can be used to keep
track of versions of the code, that were upstreamed)? I can see multiple
drivers with that macro and related defines.

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 36/96] cl8k: add key.c
  2022-05-26 19:38   ` Johannes Berg
@ 2022-07-11 23:10     ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:10 UTC (permalink / raw)
  To: johannes
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Thu, 26 May 2022 21:38:08 +0200, johannes@sipsolutions.net wrote:
> Why do you do this stuff in the driver if it's effectively the same as
> in mac80211?

Indeed, thanks, we will remove that. We just wanted to have replay protection
in our RX path. Another point to do something with our version is related to
the most recent WPA3SAE mesh test results, where this custom implementation
broke multicast/broadcast frames.

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 38/96] cl8k: add mac80211.c
  2022-05-26 19:49   ` Johannes Berg
@ 2022-07-11 23:13     ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:13 UTC (permalink / raw)
  To: johannes
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Thu, 26 May 2022 21:49:17 +0200, johannes@sipsolutions.net wrote:
> I'm really surprised to see this callback in a modern driver - wouldn't
> you want to support some form of multi-channel operation? Even just
> using the chanctx callbacks might make some of the DFS things you have
> there easier?

That is a good point. We picked the “old” channel API, which took less time to
implement – the benefits of channel context were not clear enough during that
time.

> This feels ... odd. You really shouldn't have to look into the beacon to
> figure out these things?
> 
> And SGI etc. are per-STA rate control parameters anyway? Hmm.

Information from this dynamic parsing is required for our driver and FW to
function properly.

> You have all this hardware/firmware and you implement this? Interesting
> design choice. One that I'm sure you'll revisit for WiFi 7 ;-)

Actually, the driver is doing that in cl_tx_handle_beacon_tim function as a
result of TBTT interrupt. However, the next version of the RFC will be without
that code – we are moving the routine to the FW side due to timing issues in
the multiclient setup.

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 50/96] cl8k: add phy.c
  2022-06-01  0:27   ` Jeff Johnson
@ 2022-07-11 23:16     ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:16 UTC (permalink / raw)
  To: quic_jjohnson
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Tue, 31 May 2022 17:27:36 -0700, quic_jjohnson@quicinc.com wrote:
> in this file and in power.c you have multiple lookup tables that look 
> like they could/should be static to limit their scope to the current file 

Yes, thanks, it makes sense.

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 59/96] cl8k: add rates.h
  2022-05-26 19:54   ` Johannes Berg
@ 2022-07-11 23:17     ` Viktor Barna
  2022-07-12  7:17       ` Johannes Berg
  0 siblings, 1 reply; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:17 UTC (permalink / raw)
  To: johannes
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Thu, 26 May 2022 21:54:36 +0200, johannes@sipsolutions.net wrote:
> that makes it sound like these are firmware things and should be endian
> safe? 

Yes, it should, thanks! PS: can you, please, clarify whether it is ok to reply
with “ACK” for all comments, those does not imply anything special in response?
Just to show, that we saw the comment and will take it into account. Or …is it
enough to mention that in RFCv3 changelist? We are grateful for the review!

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 67/96] cl8k: add rfic.h
  2022-06-02 20:40   ` Jeff Johnson
@ 2022-07-11 23:18     ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:18 UTC (permalink / raw)
  To: quic_jjohnson
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Thu, 2 Jun 2022 13:40:23 -0700, quic_jjohnson@quicinc.com wrote:
> consider adding CL_ prefix to the enumerators to avoid namespace collision.

Yes, thanks.

> why is OVERWRITE_DONE the max command? that doesn't seem to make sense 
> since other enumerators are defined after it.

Agree, that is an odd place. We likely will remove that in the next version of
the code.

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 76/96] cl8k: add stats.c
  2022-06-02 20:59   ` Jeff Johnson
@ 2022-07-11 23:20     ` Viktor Barna
  0 siblings, 0 replies; 125+ messages in thread
From: Viktor Barna @ 2022-07-11 23:20 UTC (permalink / raw)
  To: quic_jjohnson
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar, viktor.barna

On Thu, 2 Jun 2022 13:59:38 -0700, quic_jjohnson@quicinc.com wrote:
> why an embedded block? seems to serve no purpose
>
>> +			bw = rate_ctrl_info.field.bw;
>> +			bf = agg_report->bf;
>> +
>> +				cntrs = &stats->tx.he[bw][nss][mcs][gi][bf];
>
> bad indentation
>
>> +		}
>> +		break;
>> +	case WRS_MODE_VHT:
>> +		bw = rate_ctrl_info.field.bw;
>> +		nss = (rate_ctrl_info.field.mcs_index >> 4);
>> +		mcs = (rate_ctrl_info.field.mcs_index & 0xF);
>> +		gi = rate_ctrl_info.field.gi;
>> +		bf = agg_report->bf;
>> +
>> +			cntrs = &stats->tx.vht[bw][nss][mcs][gi][bf];
>
> bad indentation

Correct – that is an artifact from old version of code. Will fix that!

Best regards,
Viktor Barna

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 59/96] cl8k: add rates.h
  2022-07-11 23:17     ` Viktor Barna
@ 2022-07-12  7:17       ` Johannes Berg
  0 siblings, 0 replies; 125+ messages in thread
From: Johannes Berg @ 2022-07-12  7:17 UTC (permalink / raw)
  To: Viktor Barna
  Cc: aviad.brikman, davem, eliav.farber, kuba, kvalo, linux-wireless,
	maksym.kokhan, oleksandr.savchenko, shay.bar

On Tue, 2022-07-12 at 02:17 +0300, Viktor Barna wrote:
> On Thu, 26 May 2022 21:54:36 +0200, johannes@sipsolutions.net wrote:
> > that makes it sound like these are firmware things and should be endian
> > safe? 
> 
> Yes, it should, thanks! PS: can you, please, clarify whether it is ok to reply
> with “ACK” for all comments, those does not imply anything special in response?
> Just to show, that we saw the comment and will take it into account. Or …is it
> enough to mention that in RFCv3 changelist? We are grateful for the review!
> 

From my POV, it's sufficient to list in the version changelog "addressed
comments from <person>" or so, not like in gerrit where you have to mark
as "ack"/"done" for each comment :-)

Of course if there's something where you disagree or want to solve it in
another way, it's probably easier to continue the discussion with that
comment instead.

johannes

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 03/96] cl8k: add Kconfig
  2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
  2022-05-26 18:18   ` Johannes Berg
@ 2022-07-13  7:32   ` Kalle Valo
  1 sibling, 0 replies; 125+ messages in thread
From: Kalle Valo @ 2022-07-13  7:32 UTC (permalink / raw)
  To: viktor.barna
  Cc: linux-wireless, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

viktor.barna@celeno.com writes:

> From: Viktor Barna <viktor.barna@celeno.com>
>
> (Part of the split. Please, take a look at the cover letter for more
> details).
>
> Signed-off-by: Viktor Barna <viktor.barna@celeno.com>

I haven't looked at rest of the driver yet, will do that in a later
revision. Just looking at build scripts in this round.

> --- /dev/null
> +++ b/drivers/net/wireless/celeno/cl8k/Kconfig
> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +config CL8K
> +	tristate "Celeno CL8K WLAN support"
> +	depends on m
> +	depends on MAC80211
> +	help
> +	  This option enables support for Celeno CL8K WLAN.
> +	  Select M (recommended), if you have a wireless module.

Why depending on m? Drivers should be able to link to the kernel.

> +config CL8K_VERSION
> +	string "Version"
> +	depends on CL8K
> +	default "8.1.x"
> +	help
> +	  Sets module version, which may be important for FW compatibility
> +	  analysis and syncing upstream codebase with the internal codebase.

Johannes already commented on this.

> +config CL8K_EEPROM_STM24256
> +	bool "EEPROM STM24256 support"
> +	depends on CL8K
> +	default n
> +	help
> +	  Enables EEPROM STM24256 (specific for some of the platforms).

Kconfig should not be used for device configuration, ie. the same kernel
binary should work on all devices. Is there a better way to detect this
runtime? If not, I suggest to drop this in initial submission and submit
after the driver is accepted.

> +config CL8K_DYN_BCAST_RATE
> +	bool "Enable dynamic broadcast rate selection"
> +	depends on CL8K
> +	default n
> +	help
> +	  Enables dynamic broadcast rate selection,
> +	  that allows to tune rate of broadcast frames taking into account
> +	  capabilities of all associated stations.

I don't think features like this should be in Kconfig. Why not always enable this?

> +config CL8K_DYN_MCAST_RATE
> +	bool "Enable dynamic multicast rate selection"
> +	depends on CL8K
> +	default n
> +	help
> +	  Enables dynamic multicast rate selection,
> +	  that allows to tune rate of multicast frames taking into account
> +	  capabilities of all associated stations.

Same with this one.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [RFC v2 04/96] cl8k: add Makefile
  2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
  2022-05-26 18:24   ` Johannes Berg
@ 2022-07-13  7:39   ` Kalle Valo
  1 sibling, 0 replies; 125+ messages in thread
From: Kalle Valo @ 2022-07-13  7:39 UTC (permalink / raw)
  To: viktor.barna
  Cc: linux-wireless, David S . Miller, Jakub Kicinski, Aviad Brikman,
	Eliav Farber, Maksym Kokhan, Oleksandr Savchenko, Shay Bar

viktor.barna@celeno.com writes:

> +cl-objs += \
> +	wrs.o \
> +	phy.o \
> +	key.o \
> +	sta.o \
> +	hw.o \
> +	chip.o \
> +	fw.o \
> +	utils.o \
> +	channel.o \
> +	rx.o \
> +	tx.o \
> +	main.o \
> +	mac_addr.o \
> +	ampdu.o \
> +	dfs.o \
> +	enhanced_tim.o \
> +	e2p.o \
> +	calib.o \
> +	stats.o \
> +	power.o \
> +	motion_sense.o \
> +	bf.o \
> +	sounding.o \
> +	debug.o \
> +	temperature.o \
> +	recovery.o \
> +	rates.o \
> +	radio.o \
> +	config.o \
> +	tcv.o \
> +	traffic.o \
> +	vns.o \
> +	maintenance.o \
> +	ela.o \
> +	rfic.o \
> +	vif.o \
> +	dsp.o \
> +	pci.o \
> +	version.o \
> +	regdom.o \
> +	mac80211.o \
> +	platform.o \
> +	scan.o
> +
> +ifneq ($(CONFIG_CL8K),)
> +cl8k-y += $(cl-objs)
> +endif

I don't understand why you need ifneq here. Please check how are other
drivers (like iwlwifi) do it, Makefile can be really simple

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 125+ messages in thread

end of thread, other threads:[~2022-07-13  7:39 UTC | newest]

Thread overview: 125+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-24 11:33 [RFC v2 00/96] wireless: cl8k driver for Celeno IEEE 802.11ax devices viktor.barna
2022-05-24 11:33 ` [RFC v2 01/96] celeno: add Kconfig viktor.barna
2022-05-24 11:33 ` [RFC v2 02/96] celeno: add Makefile viktor.barna
2022-05-24 11:33 ` [RFC v2 03/96] cl8k: add Kconfig viktor.barna
2022-05-26 18:18   ` Johannes Berg
2022-05-27  6:09     ` Kalle Valo
2022-07-11 23:04       ` Viktor Barna
2022-07-13  7:32   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 04/96] cl8k: add Makefile viktor.barna
2022-05-26 18:24   ` Johannes Berg
2022-07-13  7:39   ` Kalle Valo
2022-05-24 11:33 ` [RFC v2 05/96] cl8k: add ampdu.c viktor.barna
2022-05-26 18:19   ` Johannes Berg
2022-05-26 18:22   ` Johannes Berg
2022-05-24 11:33 ` [RFC v2 06/96] cl8k: add ampdu.h viktor.barna
2022-05-24 11:33 ` [RFC v2 07/96] cl8k: add bf.c viktor.barna
2022-05-24 17:24   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 08/96] cl8k: add bf.h viktor.barna
2022-05-24 11:33 ` [RFC v2 09/96] cl8k: add calib.c viktor.barna
2022-05-24 11:33 ` [RFC v2 10/96] cl8k: add calib.h viktor.barna
2022-05-24 11:33 ` [RFC v2 11/96] cl8k: add channel.c viktor.barna
2022-05-24 11:33 ` [RFC v2 12/96] cl8k: add channel.h viktor.barna
2022-05-24 11:33 ` [RFC v2 13/96] cl8k: add chip.c viktor.barna
2022-05-24 11:33 ` [RFC v2 14/96] cl8k: add chip.h viktor.barna
2022-05-24 11:33 ` [RFC v2 15/96] cl8k: add config.c viktor.barna
2022-05-24 11:33 ` [RFC v2 16/96] cl8k: add config.h viktor.barna
2022-05-25 18:31   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 17/96] cl8k: add debug.c viktor.barna
2022-05-24 11:33 ` [RFC v2 18/96] cl8k: add debug.h viktor.barna
2022-05-24 11:33 ` [RFC v2 19/96] cl8k: add def.h viktor.barna
2022-05-25 18:39   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 20/96] cl8k: add dfs.c viktor.barna
2022-05-24 11:33 ` [RFC v2 21/96] cl8k: add dfs.h viktor.barna
2022-05-24 11:33 ` [RFC v2 22/96] cl8k: add dsp.c viktor.barna
2022-05-24 11:33 ` [RFC v2 23/96] cl8k: add dsp.h viktor.barna
2022-05-24 11:33 ` [RFC v2 24/96] cl8k: add e2p.c viktor.barna
2022-05-24 11:33 ` [RFC v2 25/96] cl8k: add e2p.h viktor.barna
2022-05-24 11:33 ` [RFC v2 26/96] cl8k: add eeprom.h viktor.barna
2022-05-24 11:33 ` [RFC v2 27/96] cl8k: add ela.c viktor.barna
2022-05-24 11:33 ` [RFC v2 28/96] cl8k: add ela.h viktor.barna
2022-05-24 11:33 ` [RFC v2 29/96] cl8k: add enhanced_tim.c viktor.barna
2022-05-24 11:33 ` [RFC v2 30/96] cl8k: add enhanced_tim.h viktor.barna
2022-05-24 11:33 ` [RFC v2 31/96] cl8k: add fw.c viktor.barna
2022-05-24 11:33 ` [RFC v2 32/96] cl8k: add fw.h viktor.barna
2022-05-25 18:58   ` Jeff Johnson
2022-05-24 11:33 ` [RFC v2 33/96] cl8k: add hw.c viktor.barna
2022-05-24 11:34 ` [RFC v2 34/96] cl8k: add hw.h viktor.barna
2022-05-24 11:34 ` [RFC v2 35/96] cl8k: add ipc_shared.h viktor.barna
2022-05-24 11:34 ` [RFC v2 36/96] cl8k: add key.c viktor.barna
2022-05-26 19:38   ` Johannes Berg
2022-07-11 23:10     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 37/96] cl8k: add key.h viktor.barna
2022-05-24 11:34 ` [RFC v2 38/96] cl8k: add mac80211.c viktor.barna
2022-05-26 19:49   ` Johannes Berg
2022-07-11 23:13     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 39/96] cl8k: add mac80211.h viktor.barna
2022-05-26 19:52   ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 40/96] cl8k: add mac_addr.c viktor.barna
2022-05-26 22:31   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 41/96] cl8k: add mac_addr.h viktor.barna
2022-05-24 11:34 ` [RFC v2 42/96] cl8k: add main.c viktor.barna
2022-05-26 23:01   ` Jeff Johnson
2022-05-24 11:34 ` [RFC v2 43/96] cl8k: add main.h viktor.barna
2022-05-24 11:34 ` [RFC v2 44/96] cl8k: add maintenance.c viktor.barna
2022-05-24 11:34 ` [RFC v2 45/96] cl8k: add maintenance.h viktor.barna
2022-05-24 11:34 ` [RFC v2 46/96] cl8k: add motion_sense.c viktor.barna
2022-05-24 11:34 ` [RFC v2 47/96] cl8k: add motion_sense.h viktor.barna
2022-05-24 11:34 ` [RFC v2 48/96] cl8k: add pci.c viktor.barna
2022-05-24 11:34 ` [RFC v2 49/96] cl8k: add pci.h viktor.barna
2022-05-24 11:34 ` [RFC v2 50/96] cl8k: add phy.c viktor.barna
2022-06-01  0:27   ` Jeff Johnson
2022-07-11 23:16     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 51/96] cl8k: add phy.h viktor.barna
2022-05-24 11:34 ` [RFC v2 52/96] cl8k: add platform.c viktor.barna
2022-05-24 11:34 ` [RFC v2 53/96] cl8k: add platform.h viktor.barna
2022-05-24 11:34 ` [RFC v2 54/96] cl8k: add power.c viktor.barna
2022-05-24 11:34 ` [RFC v2 55/96] cl8k: add power.h viktor.barna
2022-05-24 11:34 ` [RFC v2 56/96] cl8k: add radio.c viktor.barna
2022-05-24 11:34 ` [RFC v2 57/96] cl8k: add radio.h viktor.barna
2022-05-24 11:34 ` [RFC v2 58/96] cl8k: add rates.c viktor.barna
2022-05-24 11:34 ` [RFC v2 59/96] cl8k: add rates.h viktor.barna
2022-05-26 19:54   ` Johannes Berg
2022-07-11 23:17     ` Viktor Barna
2022-07-12  7:17       ` Johannes Berg
2022-05-24 11:34 ` [RFC v2 60/96] cl8k: add recovery.c viktor.barna
2022-05-24 11:34 ` [RFC v2 61/96] cl8k: add recovery.h viktor.barna
2022-05-24 11:34 ` [RFC v2 62/96] cl8k: add regdom.c viktor.barna
2022-05-24 11:34 ` [RFC v2 63/96] cl8k: add regdom.h viktor.barna
2022-05-24 11:34 ` [RFC v2 64/96] cl8k: add reg/reg_access.h viktor.barna
2022-05-24 11:34 ` [RFC v2 65/96] cl8k: add reg/reg_defs.h viktor.barna
2022-05-24 11:34 ` [RFC v2 66/96] cl8k: add rfic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 67/96] cl8k: add rfic.h viktor.barna
2022-06-02 20:40   ` Jeff Johnson
2022-07-11 23:18     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 68/96] cl8k: add rx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 69/96] cl8k: add rx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 70/96] cl8k: add scan.c viktor.barna
2022-05-24 11:34 ` [RFC v2 71/96] cl8k: add scan.h viktor.barna
2022-05-24 11:34 ` [RFC v2 72/96] cl8k: add sounding.c viktor.barna
2022-05-24 11:34 ` [RFC v2 73/96] cl8k: add sounding.h viktor.barna
2022-05-24 11:34 ` [RFC v2 74/96] cl8k: add sta.c viktor.barna
2022-05-24 11:34 ` [RFC v2 75/96] cl8k: add sta.h viktor.barna
2022-05-24 11:34 ` [RFC v2 76/96] cl8k: add stats.c viktor.barna
2022-06-02 20:59   ` Jeff Johnson
2022-07-11 23:20     ` Viktor Barna
2022-05-24 11:34 ` [RFC v2 77/96] cl8k: add stats.h viktor.barna
2022-05-24 11:34 ` [RFC v2 78/96] cl8k: add tcv.c viktor.barna
2022-05-24 11:34 ` [RFC v2 79/96] cl8k: add tcv.h viktor.barna
2022-05-24 11:34 ` [RFC v2 80/96] cl8k: add temperature.c viktor.barna
2022-05-24 11:34 ` [RFC v2 81/96] cl8k: add temperature.h viktor.barna
2022-05-24 11:34 ` [RFC v2 82/96] cl8k: add traffic.c viktor.barna
2022-05-24 11:34 ` [RFC v2 83/96] cl8k: add traffic.h viktor.barna
2022-05-24 11:34 ` [RFC v2 84/96] cl8k: add tx.c viktor.barna
2022-05-24 11:34 ` [RFC v2 85/96] cl8k: add tx.h viktor.barna
2022-05-24 11:34 ` [RFC v2 86/96] cl8k: add utils.c viktor.barna
2022-05-24 11:34 ` [RFC v2 87/96] cl8k: add utils.h viktor.barna
2022-05-24 11:34 ` [RFC v2 88/96] cl8k: add version.c viktor.barna
2022-05-24 11:34 ` [RFC v2 89/96] cl8k: add version.h viktor.barna
2022-05-24 11:34 ` [RFC v2 90/96] cl8k: add vif.c viktor.barna
2022-05-24 11:34 ` [RFC v2 91/96] cl8k: add vif.h viktor.barna
2022-05-24 11:34 ` [RFC v2 92/96] cl8k: add vns.c viktor.barna
2022-05-24 11:34 ` [RFC v2 93/96] cl8k: add vns.h viktor.barna
2022-05-24 11:35 ` [RFC v2 94/96] cl8k: add wrs.c viktor.barna
2022-05-24 11:35 ` [RFC v2 95/96] cl8k: add wrs.h viktor.barna
2022-05-24 11:35 ` [RFC v2 96/96] wireless: add Celeno vendor viktor.barna

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.