File Index
Files and directories
Sign in
FILE

coex.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/realtek/rtw89/coex.c C
    1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2/* Copyright(c) 2019-2020  Realtek Corporation
    3 */
    4
    5#include "chan.h"
    6#include "coex.h"
    7#include "debug.h"
    8#include "fw.h"
    9#include "mac.h"
   10#include "phy.h"
   11#include "ps.h"
   12#include "reg.h"
   13
   14#define RTW89_COEX_VERSION 0x09000013
   15#define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
   16#define BTC_E2G_LIMIT_DEF 80
   17
   18enum btc_fbtc_tdma_template {
   19	CXTD_OFF = 0x0,
   20	CXTD_OFF_B2,
   21	CXTD_OFF_EXT,
   22	CXTD_FIX,
   23	CXTD_PFIX,
   24	CXTD_AUTO,
   25	CXTD_PAUTO,
   26	CXTD_AUTO2,
   27	CXTD_PAUTO2,
   28	CXTD_MAX,
   29};
   30
   31enum btc_fbtc_tdma_type {
   32	CXTDMA_OFF = 0x0,
   33	CXTDMA_FIX = 0x1,
   34	CXTDMA_AUTO = 0x2,
   35	CXTDMA_AUTO2 = 0x3,
   36	CXTDMA_MAX
   37};
   38
   39enum btc_fbtc_tdma_rx_flow_ctrl {
   40	CXFLC_OFF = 0x0,
   41	CXFLC_NULLP = 0x1,
   42	CXFLC_QOSNULL = 0x2,
   43	CXFLC_CTS = 0x3,
   44	CXFLC_MAX
   45};
   46
   47enum btc_fbtc_tdma_wlan_tx_pause {
   48	CXTPS_OFF = 0x0,  /* no wl tx pause*/
   49	CXTPS_ON = 0x1,
   50	CXTPS_MAX
   51};
   52
   53enum btc_mlme_state {
   54	MLME_NO_LINK,
   55	MLME_LINKING,
   56	MLME_LINKED,
   57};
   58
   59struct btc_fbtc_1slot {
   60	u8 fver;
   61	u8 sid; /* slot id */
   62	struct rtw89_btc_fbtc_slot slot;
   63} __packed;
   64
   65static const struct rtw89_btc_fbtc_tdma t_def[] = {
   66	[CXTD_OFF]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
   67	[CXTD_OFF_B2]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0},
   68	[CXTD_OFF_EXT]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 2, 0, 0},
   69	[CXTD_FIX]	= { CXTDMA_FIX,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
   70	[CXTD_PFIX]	= { CXTDMA_FIX,  CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
   71	[CXTD_AUTO]	= { CXTDMA_AUTO,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
   72	[CXTD_PAUTO]	= { CXTDMA_AUTO, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
   73	[CXTD_AUTO2]	= {CXTDMA_AUTO2,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
   74	[CXTD_PAUTO2]	= {CXTDMA_AUTO2, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0}
   75};
   76
   77#define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \
   78	{ .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \
   79	  .cxtype = cpu_to_le16(__cxtype),}
   80
   81static const struct rtw89_btc_fbtc_slot s_def[] = {
   82	[CXST_OFF]	= __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
   83	[CXST_B2W]	= __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_ISO),
   84	[CXST_W1]	= __DEF_FBTC_SLOT(70,  0xea5a5a5a, SLOT_ISO),
   85	[CXST_W2]	= __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
   86	[CXST_W2B]	= __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
   87	[CXST_B1]	= __DEF_FBTC_SLOT(250, 0xe5555555, SLOT_MIX),
   88	[CXST_B2]	= __DEF_FBTC_SLOT(7,   0xea5a5a5a, SLOT_MIX),
   89	[CXST_B3]	= __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
   90	[CXST_B4]	= __DEF_FBTC_SLOT(50,  0xe5555555, SLOT_MIX),
   91	[CXST_LK]	= __DEF_FBTC_SLOT(20,  0xea5a5a5a, SLOT_ISO),
   92	[CXST_BLK]	= __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX),
   93	[CXST_E2G]	= __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_MIX),
   94	[CXST_E5G]	= __DEF_FBTC_SLOT(5,   0xffffffff, SLOT_ISO),
   95	[CXST_EBT]	= __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
   96	[CXST_ENULL]	= __DEF_FBTC_SLOT(5,   0x55555555, SLOT_MIX),
   97	[CXST_WLK]	= __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
   98	[CXST_W1FDD]	= __DEF_FBTC_SLOT(50,  0xffffffff, SLOT_ISO),
   99	[CXST_B1FDD]	= __DEF_FBTC_SLOT(50,  0xffffdfff, SLOT_ISO),
  100};
  101
  102static const u32 cxtbl[] = {
  103	0xffffffff, /* 0 */
  104	0xaaaaaaaa, /* 1 */
  105	0xe5555555, /* 2 */
  106	0xee555555, /* 3 */
  107	0xd5555555, /* 4 */
  108	0x5a5a5a5a, /* 5 */
  109	0xfa5a5a5a, /* 6 */
  110	0xda5a5a5a, /* 7 */
  111	0xea5a5a5a, /* 8 */
  112	0x6a5a5aaa, /* 9 */
  113	0x6a5a6a5a, /* 10 */
  114	0x6a5a6aaa, /* 11 */
  115	0x6afa5afa, /* 12 */
  116	0xaaaa5aaa, /* 13 */
  117	0xaaffffaa, /* 14 */
  118	0xaa5555aa, /* 15 */
  119	0xfafafafa, /* 16 */
  120	0xffffddff, /* 17 */
  121	0xdaffdaff, /* 18 */
  122	0xfafadafa, /* 19 */
  123	0xea6a6a6a, /* 20 */
  124	0xea55556a, /* 21 */
  125	0xaafafafa, /* 22 */
  126	0xfafaaafa, /* 23 */
  127	0xfafffaff, /* 24 */
  128	0xea6a5a5a, /* 25 */
  129	0xfaff5aff, /* 26 */
  130	0xffffdfff, /* 27 */
  131	0xe6555555, /* 28 */
  132};
  133
  134static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
  135	/* firmware version must be in decreasing order for each chip */
  136	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 122, 0),
  137	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  138	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  139	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  140	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  141	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  142	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
  143	},
  144	{RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0),
  145	 .fcxbtcrpt = 7, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  146	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  147	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  148	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  149	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  150	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
  151	},
  152	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0),
  153	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  154	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  155	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  156	 .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
  157	 .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800,
  158	 .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
  159	},
  160	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0),
  161	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  162	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  163	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  164	 .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
  165	 .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800,
  166	 .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
  167	},
  168	{RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0),
  169	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  170	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  171	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  172	 .fwlrole = 8,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  173	 .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800,
  174	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  175	},
  176	{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
  177	 .fcxbtcrpt = 105, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 5,
  178	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
  179	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  180	 .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  181	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  182	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  183	},
  184	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
  185	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  186	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  187	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  188	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  189	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  190	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  191	},
  192	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0),
  193	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  194	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  195	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  196	 .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
  197	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  198	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  199	},
  200	{RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0),
  201	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  202	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  203	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  204	 .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
  205	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  206	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  207	},
  208	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0),
  209	 .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  210	 .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  211	 .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  212	 .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  213	 .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  214	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
  215	},
  216	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0),
  217	 .fcxbtcrpt = 105, .fcxtdma = 3,  .fcxslots = 1, .fcxcysta = 5,
  218	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
  219	 .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  220	 .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  221	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  222	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  223	},
  224	{RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
  225	 .fcxbtcrpt = 5, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 4,
  226	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  227	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  228	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  229	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  230	 .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  231	},
  232	{RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0),
  233	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  234	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  235	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  236	 .fwlrole = 1,   .frptmap = 1,    .fcxctrl = 1,  .fcxinit = 0,
  237	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  238	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  239	},
  240	{RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0),
  241	 .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  242	 .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  243	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  244	 .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  245	 .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280,
  246	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  247	},
  248	{RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0),
  249	 .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
  250	 .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
  251	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  252	 .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
  253	 .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024,
  254	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  255	},
  256
  257	/* keep it to be the last as default entry */
  258	{0, RTW89_FW_VER_CODE(0, 0, 0, 0),
  259	 .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
  260	 .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
  261	 .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  262	 .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
  263	 .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024,
  264	 .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
  265	},
  266};
  267
  268#define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1)
  269
  270static const union rtw89_btc_wl_state_map btc_scanning_map = {
  271	.map = {
  272		.scan = 1,
  273		.connecting = 1,
  274		.roaming = 1,
  275		.dbccing = 1,
  276		._4way = 1,
  277	},
  278};
  279
  280static u32 chip_id_to_bt_rom_code_id(u32 id)
  281{
  282	switch (id) {
  283	case RTL8852A:
  284	case RTL8852B:
  285	case RTL8852C:
  286	case RTL8852BT:
  287		return 0x8852;
  288	case RTL8851B:
  289		return 0x8851;
  290	case RTL8922A:
  291		return 0x8922;
  292	default:
  293		return 0;
  294	}
  295}
  296
  297#define CASE_BTC_MLME_STATE(e) case MLME_##e: return #e
  298
  299static const char *id_to_mlme_state(u32 id)
  300{
  301	switch (id) {
  302	CASE_BTC_MLME_STATE(NO_LINK);
  303	CASE_BTC_MLME_STATE(LINKING);
  304	CASE_BTC_MLME_STATE(LINKED);
  305	default:
  306		return "unknown";
  307	}
  308}
  309
  310static char *chip_id_str(u32 id)
  311{
  312	switch (id) {
  313	case RTL8852A:
  314		return "RTL8852A";
  315	case RTL8852B:
  316		return "RTL8852B";
  317	case RTL8852C:
  318		return "RTL8852C";
  319	case RTL8852BT:
  320		return "RTL8852BT";
  321	case RTL8851B:
  322		return "RTL8851B";
  323	case RTL8922A:
  324		return "RTL8922A";
  325	default:
  326		return "UNKNOWN";
  327	}
  328}
  329
  330struct rtw89_btc_btf_tlv {
  331	u8 type;
  332	u8 len;
  333	u8 val[];
  334} __packed;
  335
  336struct rtw89_btc_btf_tlv_v7 {
  337	u8 type;
  338	u8 ver;
  339	u8 len;
  340	u8 val[];
  341} __packed;
  342
  343enum btc_btf_set_report_en {
  344	RPT_EN_TDMA,
  345	RPT_EN_CYCLE,
  346	RPT_EN_MREG,
  347	RPT_EN_BT_VER_INFO,
  348	RPT_EN_BT_SCAN_INFO,
  349	RPT_EN_BT_DEVICE_INFO,
  350	RPT_EN_BT_AFH_MAP,
  351	RPT_EN_BT_AFH_MAP_LE,
  352	RPT_EN_BT_TX_PWR_LVL,
  353	RPT_EN_FW_STEP_INFO,
  354	RPT_EN_TEST,
  355	RPT_EN_WL_ALL,
  356	RPT_EN_BT_ALL,
  357	RPT_EN_ALL,
  358	RPT_EN_MONITER,
  359};
  360
  361struct rtw89_btc_btf_set_report_v1 {
  362	u8 fver;
  363	__le32 enable;
  364	__le32 para;
  365} __packed;
  366
  367struct rtw89_btc_btf_set_report_v8 {
  368	u8 type;
  369	u8 fver;
  370	u8 len;
  371	__le32 map;
  372} __packed;
  373
  374union rtw89_fbtc_rtp_ctrl {
  375	struct rtw89_btc_btf_set_report_v1 v1;
  376	struct rtw89_btc_btf_set_report_v8 v8;
  377};
  378
  379#define BTF_SET_SLOT_TABLE_VER 1
  380struct rtw89_btc_btf_set_slot_table {
  381	u8 fver;
  382	u8 tbl_num;
  383	struct rtw89_btc_fbtc_slot tbls[] __counted_by(tbl_num);
  384} __packed;
  385
  386struct rtw89_btc_btf_set_slot_table_v7 {
  387	u8 type;
  388	u8 ver;
  389	u8 len;
  390	struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX];
  391} __packed;
  392
  393struct rtw89_btc_btf_set_mon_reg_v1 {
  394	u8 fver;
  395	u8 reg_num;
  396	struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num);
  397} __packed;
  398
  399struct rtw89_btc_btf_set_mon_reg_v7 {
  400	u8 type;
  401	u8 fver;
  402	u8 len;
  403	struct rtw89_btc_fbtc_mreg regs[] __counted_by(len);
  404} __packed;
  405
  406union rtw89_fbtc_set_mon_reg {
  407	struct rtw89_btc_btf_set_mon_reg_v1 v1;
  408	struct rtw89_btc_btf_set_mon_reg_v7 v7;
  409} __packed;
  410
  411struct _wl_rinfo_now {
  412	u8 link_mode;
  413	u32 dbcc_2g_phy: 2;
  414};
  415
  416enum btc_btf_set_cx_policy {
  417	CXPOLICY_TDMA = 0x0,
  418	CXPOLICY_SLOT = 0x1,
  419	CXPOLICY_TYPE = 0x2,
  420	CXPOLICY_MAX,
  421};
  422
  423enum btc_b2w_scoreboard {
  424	BTC_BSCB_ACT = BIT(0),
  425	BTC_BSCB_ON = BIT(1),
  426	BTC_BSCB_WHQL = BIT(2),
  427	BTC_BSCB_BT_S1 = BIT(3),
  428	BTC_BSCB_A2DP_ACT = BIT(4),
  429	BTC_BSCB_RFK_RUN = BIT(5),
  430	BTC_BSCB_RFK_REQ = BIT(6),
  431	BTC_BSCB_LPS = BIT(7),
  432	BTC_BSCB_BT_LNAB0 = BIT(8),
  433	BTC_BSCB_BT_LNAB1 = BIT(10),
  434	BTC_BSCB_WLRFK = BIT(11),
  435	BTC_BSCB_BT_HILNA = BIT(13),
  436	BTC_BSCB_BT_CONNECT = BIT(16),
  437	BTC_BSCB_PATCH_CODE = BIT(30),
  438	BTC_BSCB_ALL = GENMASK(30, 0),
  439};
  440
  441enum btc_phymap {
  442	BTC_PHY_0 = BIT(0),
  443	BTC_PHY_1 = BIT(1),
  444	BTC_PHY_ALL = BIT(0) | BIT(1),
  445};
  446
  447enum btc_cx_state_map {
  448	BTC_WIDLE = 0,
  449	BTC_WBUSY_BNOSCAN,
  450	BTC_WBUSY_BSCAN,
  451	BTC_WSCAN_BNOSCAN,
  452	BTC_WSCAN_BSCAN,
  453	BTC_WLINKING
  454};
  455
  456enum btc_ant_phase {
  457	BTC_ANT_WPOWERON = 0,
  458	BTC_ANT_WINIT,
  459	BTC_ANT_WONLY,
  460	BTC_ANT_WOFF,
  461	BTC_ANT_W2G,
  462	BTC_ANT_W5G,
  463	BTC_ANT_W25G,
  464	BTC_ANT_FREERUN,
  465	BTC_ANT_WRFK,
  466	BTC_ANT_WRFK2,
  467	BTC_ANT_BRFK,
  468	BTC_ANT_MAX
  469};
  470
  471enum btc_plt {
  472	BTC_PLT_NONE = 0,
  473	BTC_PLT_LTE_RX = BIT(0),
  474	BTC_PLT_GNT_BT_TX = BIT(1),
  475	BTC_PLT_GNT_BT_RX = BIT(2),
  476	BTC_PLT_GNT_WL = BIT(3),
  477	BTC_PLT_BT = BIT(1) | BIT(2),
  478	BTC_PLT_ALL = 0xf
  479};
  480
  481enum btc_cx_poicy_main_type {
  482	BTC_CXP_OFF = 0,
  483	BTC_CXP_OFFB,
  484	BTC_CXP_OFFE,
  485	BTC_CXP_FIX,
  486	BTC_CXP_PFIX,
  487	BTC_CXP_AUTO,
  488	BTC_CXP_PAUTO,
  489	BTC_CXP_AUTO2,
  490	BTC_CXP_PAUTO2,
  491	BTC_CXP_MANUAL,
  492	BTC_CXP_USERDEF0,
  493	BTC_CXP_MAIN_MAX
  494};
  495
  496enum btc_cx_poicy_type {
  497	/* TDMA off + pri: BT > WL */
  498	BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,
  499
  500	/* TDMA off + pri: WL > BT */
  501	BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,
  502
  503	/* TDMA off + pri: BT = WL */
  504	BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,
  505
  506	/* TDMA off + pri: BT = WL > BT_Lo */
  507	BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,
  508
  509	/* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
  510	BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,
  511
  512	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
  513	BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
  514
  515	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
  516	BTC_CXP_OFF_EQ4 = (BTC_CXP_OFF << 8) | 6,
  517
  518	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
  519	BTC_CXP_OFF_EQ5 = (BTC_CXP_OFF << 8) | 7,
  520
  521	/* TDMA off + pri: BT_Hi > WL > BT_Lo */
  522	BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 8,
  523
  524	/* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
  525	BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 9,
  526
  527	/* TDMA off + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */
  528	BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 10,
  529
  530	/* TDMA off + pri: WL_Hi-Tx = BT */
  531	BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 11,
  532
  533	/* TDMA off + pri: WL > BT, Block-BT*/
  534	BTC_CXP_OFF_WL2 = (BTC_CXP_OFF << 8) | 12,
  535
  536	/* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
  537	BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
  538
  539	/* TDMA off + Ext-Ctrl + pri: default */
  540	BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,
  541
  542	/* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
  543	BTC_CXP_OFFE_DEF2 = (BTC_CXP_OFFE << 8) | 1,
  544
  545	/* TDMA off + Ext-Ctrl + pri: default */
  546	BTC_CXP_OFFE_2GBWISOB = (BTC_CXP_OFFE << 8) | 2,
  547
  548	/* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
  549	BTC_CXP_OFFE_2GISOB = (BTC_CXP_OFFE << 8) | 3,
  550
  551	/* TDMA off + Ext-Ctrl + pri: E2G-slot WL > BT */
  552	BTC_CXP_OFFE_2GBWMIXB = (BTC_CXP_OFFE << 8) | 4,
  553
  554	/* TDMA off + Ext-Ctrl + pri: E2G/EBT-slot WL > BT */
  555	BTC_CXP_OFFE_WL = (BTC_CXP_OFFE << 8) | 5,
  556
  557	/* TDMA off + Ext-Ctrl + pri: default */
  558	BTC_CXP_OFFE_2GBWMIXB2 = (BTC_CXP_OFFE << 8) | 6,
  559
  560	/* TDMA Fix slot-0: W1:B1 = 30:30 */
  561	BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,
  562
  563	/* TDMA Fix slot-1: W1:B1 = 50:50 */
  564	BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,
  565
  566	/* TDMA Fix slot-2: W1:B1 = 20:30 */
  567	BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,
  568
  569	/* TDMA Fix slot-3: W1:B1 = 40:10 */
  570	BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,
  571
  572	/* TDMA Fix slot-4: W1:B1 = 70:10 */
  573	BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,
  574
  575	/* TDMA Fix slot-5: W1:B1 = 20:60 */
  576	BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,
  577
  578	/* TDMA Fix slot-6: W1:B1 = 30:60 */
  579	BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,
  580
  581	/* TDMA Fix slot-7: W1:B1 = 20:80 */
  582	BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,
  583
  584	/* TDMA Fix slot-8: W1:B1 = user-define */
  585	BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
  586
  587	/* TDMA Fix slot-9: W1:B1 = 40:10 */
  588	BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9,
  589
  590	/* TDMA Fix slot-10: W1:B1 = 40:10 */
  591	BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10,
  592
  593	/* TDMA Fix slot-11: W1:B1 = 40:10 */
  594	BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11,
  595
  596	/* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
  597	BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
  598
  599	/* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
  600	BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,
  601
  602	/* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
  603	BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,
  604
  605	/* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
  606	BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,
  607
  608	/* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
  609	BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,
  610
  611	/* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
  612	BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,
  613
  614	/* PS-TDMA Fix slot-6: W1:B1 = user-define */
  615	BTC_CXP_PFIX_TDW1B1 = (BTC_CXP_PFIX << 8) | 6,
  616
  617	/* TDMA Auto slot-0: W1:B1 = 50:200 */
  618	BTC_CXP_AUTO_TD50B1 = (BTC_CXP_AUTO << 8) | 0,
  619
  620	/* TDMA Auto slot-1: W1:B1 = 60:200 */
  621	BTC_CXP_AUTO_TD60B1 = (BTC_CXP_AUTO << 8) | 1,
  622
  623	/* TDMA Auto slot-2: W1:B1 = 20:200 */
  624	BTC_CXP_AUTO_TD20B1 = (BTC_CXP_AUTO << 8) | 2,
  625
  626	/* TDMA Auto slot-3: W1:B1 = user-define */
  627	BTC_CXP_AUTO_TDW1B1 = (BTC_CXP_AUTO << 8) | 3,
  628
  629	/* PS-TDMA Auto slot-0: W1:B1 = 50:200 */
  630	BTC_CXP_PAUTO_TD50B1 = (BTC_CXP_PAUTO << 8) | 0,
  631
  632	/* PS-TDMA Auto slot-1: W1:B1 = 60:200 */
  633	BTC_CXP_PAUTO_TD60B1 = (BTC_CXP_PAUTO << 8) | 1,
  634
  635	/* PS-TDMA Auto slot-2: W1:B1 = 20:200 */
  636	BTC_CXP_PAUTO_TD20B1 = (BTC_CXP_PAUTO << 8) | 2,
  637
  638	/* PS-TDMA Auto slot-3: W1:B1 = user-define */
  639	BTC_CXP_PAUTO_TDW1B1 = (BTC_CXP_PAUTO << 8) | 3,
  640
  641	/* TDMA Auto slot2-0: W1:B4 = 30:50 */
  642	BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,
  643
  644	/* TDMA Auto slot2-1: W1:B4 = 30:70 */
  645	BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,
  646
  647	/* TDMA Auto slot2-2: W1:B4 = 50:50 */
  648	BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,
  649
  650	/* TDMA Auto slot2-3: W1:B4 = 60:60 */
  651	BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,
  652
  653	/* TDMA Auto slot2-4: W1:B4 = 20:80 */
  654	BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,
  655
  656	/* TDMA Auto slot2-5: W1:B4 = user-define */
  657	BTC_CXP_AUTO2_TDW1B4 = (BTC_CXP_AUTO2 << 8) | 5,
  658
  659	/* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
  660	BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,
  661
  662	/* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
  663	BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,
  664
  665	/* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
  666	BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,
  667
  668	/* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
  669	BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,
  670
  671	/* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
  672	BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,
  673
  674	/* PS-TDMA Auto slot2-5: W1:B4 = user-define */
  675	BTC_CXP_PAUTO2_TDW1B4 = (BTC_CXP_PAUTO2 << 8) | 5,
  676
  677	BTC_CXP_MAX = 0xffff
  678};
  679
  680enum btc_wl_rfk_result {
  681	BTC_WRFK_REJECT = 0,
  682	BTC_WRFK_ALLOW = 1,
  683};
  684
  685enum btc_coex_info_map_en {
  686	BTC_COEX_INFO_CX = BIT(0),
  687	BTC_COEX_INFO_WL = BIT(1),
  688	BTC_COEX_INFO_BT = BIT(2),
  689	BTC_COEX_INFO_DM = BIT(3),
  690	BTC_COEX_INFO_MREG = BIT(4),
  691	BTC_COEX_INFO_SUMMARY = BIT(5),
  692	BTC_COEX_INFO_ALL = GENMASK(7, 0),
  693};
  694
  695#define BTC_CXP_MASK GENMASK(15, 8)
  696
  697enum btc_w2b_scoreboard {
  698	BTC_WSCB_ACTIVE = BIT(0),
  699	BTC_WSCB_ON = BIT(1),
  700	BTC_WSCB_SCAN = BIT(2),
  701	BTC_WSCB_UNDERTEST = BIT(3),
  702	BTC_WSCB_RXGAIN = BIT(4),
  703	BTC_WSCB_WLBUSY = BIT(7),
  704	BTC_WSCB_EXTFEM = BIT(8),
  705	BTC_WSCB_TDMA = BIT(9),
  706	BTC_WSCB_FIX2M = BIT(10),
  707	BTC_WSCB_WLRFK = BIT(11),
  708	BTC_WSCB_RXSCAN_PRI = BIT(12),
  709	BTC_WSCB_BT_HILNA = BIT(13),
  710	BTC_WSCB_BTLOG = BIT(14),
  711	BTC_WSCB_ALL = GENMASK(23, 0),
  712};
  713
  714enum btc_wl_link_mode {
  715	BTC_WLINK_NOLINK = 0x0,
  716	BTC_WLINK_2G_STA,
  717	BTC_WLINK_2G_AP,
  718	BTC_WLINK_2G_GO,
  719	BTC_WLINK_2G_GC,
  720	BTC_WLINK_2G_SCC,
  721	BTC_WLINK_2G_MCC,
  722	BTC_WLINK_25G_MCC,
  723	BTC_WLINK_25G_DBCC,
  724	BTC_WLINK_5G,
  725	BTC_WLINK_2G_NAN,
  726	BTC_WLINK_OTHER,
  727	BTC_WLINK_MAX
  728};
  729
  730#define CASE_BTC_WL_LINK_MODE(e) case BTC_WLINK_## e: return #e
  731
  732static const char *id_to_linkmode(u8 id)
  733{
  734	switch (id) {
  735	CASE_BTC_WL_LINK_MODE(NOLINK);
  736	CASE_BTC_WL_LINK_MODE(2G_STA);
  737	CASE_BTC_WL_LINK_MODE(2G_AP);
  738	CASE_BTC_WL_LINK_MODE(2G_GO);
  739	CASE_BTC_WL_LINK_MODE(2G_GC);
  740	CASE_BTC_WL_LINK_MODE(2G_SCC);
  741	CASE_BTC_WL_LINK_MODE(2G_MCC);
  742	CASE_BTC_WL_LINK_MODE(25G_MCC);
  743	CASE_BTC_WL_LINK_MODE(25G_DBCC);
  744	CASE_BTC_WL_LINK_MODE(5G);
  745	CASE_BTC_WL_LINK_MODE(OTHER);
  746	default:
  747		return "unknown";
  748	}
  749}
  750
  751enum btc_wl_mrole_type {
  752	BTC_WLMROLE_NONE = 0x0,
  753	BTC_WLMROLE_STA_GC,
  754	BTC_WLMROLE_STA_GC_NOA,
  755	BTC_WLMROLE_STA_GO,
  756	BTC_WLMROLE_STA_GO_NOA,
  757	BTC_WLMROLE_STA_STA,
  758	BTC_WLMROLE_MAX
  759};
  760
  761enum btc_bt_hid_type {
  762	BTC_HID_218 = BIT(0),
  763	BTC_HID_418 = BIT(1),
  764	BTC_HID_BLE = BIT(2),
  765	BTC_HID_RCU = BIT(3),
  766	BTC_HID_RCU_VOICE = BIT(4),
  767	BTC_HID_OTHER_LEGACY = BIT(5)
  768};
  769
  770enum btc_reset_module {
  771	BTC_RESET_CX = BIT(0),
  772	BTC_RESET_DM = BIT(1),
  773	BTC_RESET_CTRL = BIT(2),
  774	BTC_RESET_CXDM = BIT(0) | BIT(1),
  775	BTC_RESET_BTINFO = BIT(3),
  776	BTC_RESET_MDINFO = BIT(4),
  777	BTC_RESET_ALL =  GENMASK(7, 0),
  778};
  779
  780enum btc_gnt_state {
  781	BTC_GNT_HW	= 0,
  782	BTC_GNT_SW_LO,
  783	BTC_GNT_SW_HI,
  784	BTC_GNT_MAX
  785};
  786
  787enum btc_ctr_path {
  788	BTC_CTRL_BY_BT = 0,
  789	BTC_CTRL_BY_WL
  790};
  791
  792enum btc_wlact_state {
  793	BTC_WLACT_HW = 0,
  794	BTC_WLACT_SW_LO,
  795	BTC_WLACT_SW_HI,
  796	BTC_WLACT_MAX,
  797};
  798
  799enum btc_wl_max_tx_time {
  800	BTC_MAX_TX_TIME_L1 = 500,
  801	BTC_MAX_TX_TIME_L2 = 1000,
  802	BTC_MAX_TX_TIME_L3 = 2000,
  803	BTC_MAX_TX_TIME_DEF = 5280
  804};
  805
  806enum btc_wl_max_tx_retry {
  807	BTC_MAX_TX_RETRY_L1 = 7,
  808	BTC_MAX_TX_RETRY_L2 = 15,
  809	BTC_MAX_TX_RETRY_DEF = 31,
  810};
  811
  812enum btc_reason_and_action {
  813	BTC_RSN_NONE,
  814	BTC_RSN_NTFY_INIT,
  815	BTC_RSN_NTFY_SWBAND,
  816	BTC_RSN_NTFY_WL_STA,
  817	BTC_RSN_NTFY_RADIO_STATE,
  818	BTC_RSN_UPDATE_BT_SCBD,
  819	BTC_RSN_NTFY_WL_RFK,
  820	BTC_RSN_UPDATE_BT_INFO,
  821	BTC_RSN_NTFY_SCAN_START,
  822	BTC_RSN_NTFY_SCAN_FINISH,
  823	BTC_RSN_NTFY_SPECIFIC_PACKET,
  824	BTC_RSN_NTFY_POWEROFF,
  825	BTC_RSN_NTFY_ROLE_INFO,
  826	BTC_RSN_CMD_SET_COEX,
  827	BTC_RSN_ACT1_WORK,
  828	BTC_RSN_BT_DEVINFO_WORK,
  829	BTC_RSN_RFK_CHK_WORK,
  830	BTC_RSN_NUM,
  831	BTC_ACT_NONE = 100,
  832	BTC_ACT_WL_ONLY,
  833	BTC_ACT_WL_5G,
  834	BTC_ACT_WL_OTHER,
  835	BTC_ACT_WL_IDLE,
  836	BTC_ACT_WL_NC,
  837	BTC_ACT_WL_RFK,
  838	BTC_ACT_WL_INIT,
  839	BTC_ACT_WL_OFF,
  840	BTC_ACT_FREERUN,
  841	BTC_ACT_BT_WHQL,
  842	BTC_ACT_BT_RFK,
  843	BTC_ACT_BT_OFF,
  844	BTC_ACT_BT_IDLE,
  845	BTC_ACT_BT_HFP,
  846	BTC_ACT_BT_HID,
  847	BTC_ACT_BT_A2DP,
  848	BTC_ACT_BT_A2DPSINK,
  849	BTC_ACT_BT_PAN,
  850	BTC_ACT_BT_A2DP_HID,
  851	BTC_ACT_BT_A2DP_PAN,
  852	BTC_ACT_BT_PAN_HID,
  853	BTC_ACT_BT_A2DP_PAN_HID,
  854	BTC_ACT_WL_25G_MCC,
  855	BTC_ACT_WL_2G_MCC,
  856	BTC_ACT_WL_2G_SCC,
  857	BTC_ACT_WL_2G_AP,
  858	BTC_ACT_WL_2G_GO,
  859	BTC_ACT_WL_2G_GC,
  860	BTC_ACT_WL_2G_NAN,
  861	BTC_ACT_LAST,
  862	BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE,
  863	BTC_ACT_EXT_BIT = BIT(14),
  864	BTC_POLICY_EXT_BIT = BIT(15),
  865};
  866
  867#define BTC_FREERUN_ANTISO_MIN 30
  868#define BTC_TDMA_BTHID_MAX 2
  869#define BTC_BLINK_NOCONNECT 0
  870#define BTC_B1_MAX 250 /* unit ms */
  871
  872static void _run_coex(struct rtw89_dev *rtwdev,
  873		      enum btc_reason_and_action reason);
  874static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
  875static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);
  876
  877static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
  878			void *param, u16 len)
  879{
  880	struct rtw89_btc *btc = &rtwdev->btc;
  881	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
  882	struct rtw89_btc_cx *cx = &btc->cx;
  883	struct rtw89_btc_wl_info *wl = &cx->wl;
  884	struct rtw89_btc_dm *dm = &btc->dm;
  885	int ret;
  886
  887	if (len > BTC_H2C_MAXLEN || len == 0) {
  888		btc->fwinfo.cnt_h2c_fail++;
  889		dm->error.map.h2c_buffer_over = true;
  890		return -EINVAL;
  891	} else if (!wl->status.map.init_ok) {
  892		rtw89_debug(rtwdev, RTW89_DBG_BTC,
  893			    "[BTC], %s(): return by btc not init!!\n", __func__);
  894		pfwinfo->cnt_h2c_fail++;
  895		return -EINVAL;
  896	} else if ((wl->status.map.rf_off_pre == BTC_LPS_RF_OFF &&
  897		    wl->status.map.rf_off == BTC_LPS_RF_OFF) ||
  898		   (wl->status.map.lps_pre == BTC_LPS_RF_OFF &&
  899		    wl->status.map.lps == BTC_LPS_RF_OFF)) {
  900		rtw89_debug(rtwdev, RTW89_DBG_BTC,
  901			    "[BTC], %s(): return by wl off!!\n", __func__);
  902		pfwinfo->cnt_h2c_fail++;
  903		return -EINVAL;
  904	}
  905
  906	ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len,
  907					false, true);
  908	if (ret)
  909		pfwinfo->cnt_h2c_fail++;
  910	else
  911		pfwinfo->cnt_h2c++;
  912
  913	return ret;
  914}
  915
  916#define BTC_BT_DEF_BR_TX_PWR 4
  917#define BTC_BT_DEF_LE_TX_PWR 4
  918
  919static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
  920{
  921	struct rtw89_btc *btc = &rtwdev->btc;
  922	const struct rtw89_btc_ver *ver = btc->ver;
  923	struct rtw89_btc_cx *cx = &btc->cx;
  924	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
  925	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
  926	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
  927	struct rtw89_btc_wl_link_info *wl_linfo;
  928	u8 i;
  929
  930	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
  931
  932	if (type & BTC_RESET_CX)
  933		memset(cx, 0, sizeof(*cx));
  934
  935	if (type & BTC_RESET_BTINFO) /* only for BT enable */
  936		memset(bt, 0, sizeof(*bt));
  937
  938	if (type & BTC_RESET_CTRL) {
  939		memset(&btc->ctrl, 0, sizeof(btc->ctrl));
  940		btc->manual_ctrl = false;
  941		if (ver->fcxctrl != 7)
  942			btc->ctrl.ctrl.trace_step = FCXDEF_STEP;
  943	}
  944
  945	/* Init Coex variables that are not zero */
  946	if (type & BTC_RESET_DM) {
  947		memset(&btc->dm, 0, sizeof(btc->dm));
  948		memset(bt_linfo->rssi_state, 0, sizeof(bt_linfo->rssi_state));
  949		for (i = 0; i < RTW89_PORT_NUM; i++) {
  950			if (btc->ver->fwlrole == 8)
  951				wl_linfo = &wl->rlink_info[i][0];
  952			else
  953				wl_linfo = &wl->link_info[i];
  954			memset(wl_linfo->rssi_state, 0, sizeof(wl_linfo->rssi_state));
  955		}
  956
  957		/* set the slot_now table to original */
  958		btc->dm.tdma_now = t_def[CXTD_OFF];
  959		btc->dm.tdma = t_def[CXTD_OFF];
  960		if (ver->fcxslots >= 7) {
  961			for (i = 0; i < ARRAY_SIZE(s_def); i++) {
  962				btc->dm.slot.v7[i].dur = s_def[i].dur;
  963				btc->dm.slot.v7[i].cxtype = s_def[i].cxtype;
  964				btc->dm.slot.v7[i].cxtbl = s_def[i].cxtbl;
  965			}
  966			memcpy(&btc->dm.slot_now.v7, &btc->dm.slot.v7,
  967			       sizeof(btc->dm.slot_now.v7));
  968		} else {
  969			memcpy(&btc->dm.slot_now.v1, s_def,
  970			       sizeof(btc->dm.slot_now.v1));
  971			memcpy(&btc->dm.slot.v1, s_def,
  972			       sizeof(btc->dm.slot.v1));
  973		}
  974
  975		btc->policy_len = 0;
  976		btc->bt_req_len = 0;
  977
  978		btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
  979		btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
  980		btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
  981		btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND;
  982		btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND;
  983	}
  984
  985	if (type & BTC_RESET_MDINFO)
  986		memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
  987
  988	bt->link_info.bt_txpwr_desc.br_dbm = BTC_BT_DEF_BR_TX_PWR;
  989	bt->link_info.bt_txpwr_desc.le_dbm = BTC_BT_DEF_LE_TX_PWR;
  990}
  991
  992static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target)
  993{
  994	const struct rtw89_chip_info *chip = rtwdev->chip;
  995	u8 i;
  996
  997	for (i = 0; i < mreg_num; i++)
  998		if (le16_to_cpu(chip->mon_reg[i].type) == reg_type &&
  999		    le32_to_cpu(chip->mon_reg[i].offset) == target) {
 1000			return i;
 1001	}
 1002	return BTC_REG_NOTFOUND;
 1003}
 1004
 1005static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
 1006{
 1007	struct rtw89_btc *btc = &rtwdev->btc;
 1008	const struct rtw89_btc_ver *ver = btc->ver;
 1009	union rtw89_btc_module_info *md = &btc->mdinfo;
 1010	union rtw89_btc_fbtc_mreg_val *pmreg;
 1011	u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
 1012	u32 reg_val;
 1013	u8 idx, switch_type;
 1014
 1015	if (ver->fcxinit == 7)
 1016		switch_type = md->md_v7.switch_type;
 1017	else
 1018		switch_type = md->md.switch_type;
 1019
 1020	if (btc->btg_pos == RF_PATH_A)
 1021		pre_agc_addr = R_BTC_BB_PRE_AGC_S0;
 1022
 1023	switch (type) {
 1024	case BTC_CSTATUS_TXDIV_POS:
 1025		if (switch_type == BTC_SWITCH_INTERNAL)
 1026			*val = BTC_ANT_DIV_MAIN;
 1027		break;
 1028	case BTC_CSTATUS_RXDIV_POS:
 1029		if (switch_type == BTC_SWITCH_INTERNAL)
 1030			*val = BTC_ANT_DIV_MAIN;
 1031		break;
 1032	case BTC_CSTATUS_BB_GNT_MUX:
 1033		reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX);
 1034		*val = !(reg_val & B_BTC_BB_GNT_MUX);
 1035		break;
 1036	case BTC_CSTATUS_BB_GNT_MUX_MON:
 1037		if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
 1038			return;
 1039
 1040		pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
 1041		if (ver->fcxmreg == 1) {
 1042			idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
 1043						REG_BB, R_BTC_BB_BTG_RX);
 1044			if (idx == BTC_REG_NOTFOUND) {
 1045				*val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
 1046			} else {
 1047				reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]);
 1048				*val = !(reg_val & B_BTC_BB_GNT_MUX);
 1049			}
 1050		} else if (ver->fcxmreg == 2) {
 1051			idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
 1052						REG_BB, R_BTC_BB_BTG_RX);
 1053			if (idx == BTC_REG_NOTFOUND) {
 1054				*val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
 1055			} else {
 1056				reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]);
 1057				*val = !(reg_val & B_BTC_BB_GNT_MUX);
 1058			}
 1059		}
 1060		break;
 1061	case BTC_CSTATUS_BB_PRE_AGC:
 1062		reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr);
 1063		reg_val &= B_BTC_BB_PRE_AGC_MASK;
 1064		*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
 1065		break;
 1066	case BTC_CSTATUS_BB_PRE_AGC_MON:
 1067		if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
 1068			return;
 1069
 1070		pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
 1071		if (ver->fcxmreg == 1) {
 1072			idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
 1073						REG_BB, pre_agc_addr);
 1074			if (idx == BTC_REG_NOTFOUND) {
 1075				*val = BTC_PREAGC_NOTFOUND;
 1076			} else {
 1077				reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) &
 1078					  B_BTC_BB_PRE_AGC_MASK;
 1079				*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
 1080			}
 1081		} else if (ver->fcxmreg == 2) {
 1082			idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
 1083						REG_BB, pre_agc_addr);
 1084			if (idx == BTC_REG_NOTFOUND) {
 1085				*val = BTC_PREAGC_NOTFOUND;
 1086			} else {
 1087				reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) &
 1088					  B_BTC_BB_PRE_AGC_MASK;
 1089				*val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
 1090			}
 1091		}
 1092		break;
 1093	default:
 1094		break;
 1095	}
 1096}
 1097
 1098#define BTC_RPT_HDR_SIZE 3
 1099#define BTC_CHK_WLSLOT_DRIFT_MAX 15
 1100#define BTC_CHK_BTSLOT_DRIFT_MAX 15
 1101#define BTC_CHK_HANG_MAX 3
 1102
 1103static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
 1104{
 1105	struct rtw89_btc *btc = &rtwdev->btc;
 1106	struct rtw89_btc_cx *cx = &btc->cx;
 1107	struct rtw89_btc_bt_info *bt = &cx->bt;
 1108	struct rtw89_btc_wl_info *wl = &cx->wl;
 1109	struct rtw89_btc_dm *dm = &btc->dm;
 1110
 1111	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1112		    "[BTC], %s(): type:%d cnt:%d\n",
 1113		    __func__, type, cnt);
 1114
 1115	switch (type) {
 1116	case BTC_DCNT_WL_FW_VER_MATCH:
 1117		if ((wl->ver_info.fw_coex & 0xffff0000) !=
 1118		     rtwdev->chip->wlcx_desired) {
 1119			wl->fw_ver_mismatch = true;
 1120			dm->error.map.wl_ver_mismatch = true;
 1121		} else {
 1122			wl->fw_ver_mismatch = false;
 1123			dm->error.map.wl_ver_mismatch = false;
 1124		}
 1125		break;
 1126	case BTC_DCNT_RPT_HANG:
 1127		if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
 1128			dm->cnt_dm[BTC_DCNT_RPT_HANG]++;
 1129		else
 1130			dm->cnt_dm[BTC_DCNT_RPT_HANG] = 0;
 1131
 1132		if (dm->cnt_dm[BTC_DCNT_RPT_HANG] >= BTC_CHK_HANG_MAX)
 1133			dm->error.map.wl_fw_hang = true;
 1134		else
 1135			dm->error.map.wl_fw_hang = false;
 1136
 1137		dm->cnt_dm[BTC_DCNT_RPT] = cnt;
 1138		break;
 1139	case BTC_DCNT_CYCLE_HANG:
 1140		if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
 1141		    (dm->tdma_now.type != CXTDMA_OFF ||
 1142		     dm->tdma_now.ext_ctrl == CXECTL_EXT))
 1143			dm->cnt_dm[BTC_DCNT_CYCLE_HANG]++;
 1144		else
 1145			dm->cnt_dm[BTC_DCNT_CYCLE_HANG] = 0;
 1146
 1147		if (dm->cnt_dm[BTC_DCNT_CYCLE_HANG] >= BTC_CHK_HANG_MAX)
 1148			dm->error.map.cycle_hang = true;
 1149		else
 1150			dm->error.map.cycle_hang = false;
 1151
 1152		dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
 1153		break;
 1154	case BTC_DCNT_W1_HANG:
 1155		if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
 1156		    dm->tdma_now.type != CXTDMA_OFF)
 1157			dm->cnt_dm[BTC_DCNT_W1_HANG]++;
 1158		else
 1159			dm->cnt_dm[BTC_DCNT_W1_HANG] = 0;
 1160
 1161		if (dm->cnt_dm[BTC_DCNT_W1_HANG] >= BTC_CHK_HANG_MAX)
 1162			dm->error.map.w1_hang = true;
 1163		else
 1164			dm->error.map.w1_hang = false;
 1165
 1166		dm->cnt_dm[BTC_DCNT_W1] = cnt;
 1167		break;
 1168	case BTC_DCNT_B1_HANG:
 1169		if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
 1170		    dm->tdma_now.type != CXTDMA_OFF)
 1171			dm->cnt_dm[BTC_DCNT_B1_HANG]++;
 1172		else
 1173			dm->cnt_dm[BTC_DCNT_B1_HANG] = 0;
 1174
 1175		if (dm->cnt_dm[BTC_DCNT_B1_HANG] >= BTC_CHK_HANG_MAX)
 1176			dm->error.map.b1_hang = true;
 1177		else
 1178			dm->error.map.b1_hang = false;
 1179
 1180		dm->cnt_dm[BTC_DCNT_B1] = cnt;
 1181		break;
 1182	case BTC_DCNT_E2G_HANG:
 1183		if (dm->cnt_dm[BTC_DCNT_E2G] == cnt &&
 1184		    dm->tdma_now.ext_ctrl == CXECTL_EXT)
 1185			dm->cnt_dm[BTC_DCNT_E2G_HANG]++;
 1186		else
 1187			dm->cnt_dm[BTC_DCNT_E2G_HANG] = 0;
 1188
 1189		if (dm->cnt_dm[BTC_DCNT_E2G_HANG] >= BTC_CHK_HANG_MAX)
 1190			dm->error.map.wl_e2g_hang = true;
 1191		else
 1192			dm->error.map.wl_e2g_hang = false;
 1193
 1194		dm->cnt_dm[BTC_DCNT_E2G] = cnt;
 1195		break;
 1196	case BTC_DCNT_TDMA_NONSYNC:
 1197		if (cnt != 0) /* if tdma not sync between drv/fw  */
 1198			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
 1199		else
 1200			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;
 1201
 1202		if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
 1203			dm->error.map.tdma_no_sync = true;
 1204		else
 1205			dm->error.map.tdma_no_sync = false;
 1206		break;
 1207	case BTC_DCNT_SLOT_NONSYNC:
 1208		if (cnt != 0) /* if slot not sync between drv/fw  */
 1209			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
 1210		else
 1211			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;
 1212
 1213		if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
 1214			dm->error.map.slot_no_sync = true;
 1215		else
 1216			dm->error.map.slot_no_sync = false;
 1217		break;
 1218	case BTC_DCNT_BTTX_HANG:
 1219		cnt = cx->cnt_bt[BTC_BCNT_LOPRI_TX];
 1220
 1221		if (cnt == 0 && bt->link_info.slave_role)
 1222			dm->cnt_dm[BTC_DCNT_BTTX_HANG]++;
 1223		else
 1224			dm->cnt_dm[BTC_DCNT_BTTX_HANG] = 0;
 1225
 1226		if (dm->cnt_dm[BTC_DCNT_BTTX_HANG] >= BTC_CHK_HANG_MAX)
 1227			dm->error.map.bt_tx_hang = true;
 1228		else
 1229			dm->error.map.bt_tx_hang = false;
 1230		break;
 1231	case BTC_DCNT_BTCNT_HANG:
 1232		cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
 1233		      cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
 1234		      cx->cnt_bt[BTC_BCNT_LOPRI_RX] +
 1235		      cx->cnt_bt[BTC_BCNT_LOPRI_TX];
 1236
 1237		if (cnt == 0)
 1238			dm->cnt_dm[BTC_DCNT_BTCNT_HANG]++;
 1239		else
 1240			dm->cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
 1241
 1242		if ((dm->cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX &&
 1243		     bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_HANG] &&
 1244		     !bt->enable.now))
 1245			_update_bt_scbd(rtwdev, false);
 1246		break;
 1247	case BTC_DCNT_WL_SLOT_DRIFT:
 1248		if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
 1249			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
 1250		else
 1251			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;
 1252
 1253		if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
 1254			dm->error.map.wl_slot_drift = true;
 1255		else
 1256			dm->error.map.wl_slot_drift = false;
 1257		break;
 1258	case BTC_DCNT_BT_SLOT_DRIFT:
 1259		if (cnt >= BTC_CHK_BTSLOT_DRIFT_MAX)
 1260			dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT]++;
 1261		else
 1262			dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] = 0;
 1263
 1264		if (dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
 1265			dm->error.map.bt_slot_drift = true;
 1266		else
 1267			dm->error.map.bt_slot_drift = false;
 1268
 1269		break;
 1270	}
 1271}
 1272
 1273static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
 1274{
 1275	struct rtw89_btc *btc = &rtwdev->btc;
 1276	const struct rtw89_btc_ver *ver = btc->ver;
 1277	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 1278	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 1279	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
 1280	union  rtw89_btc_fbtc_btver *pver = &btc->fwinfo.rpt_fbtc_btver.finfo;
 1281	struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL;
 1282	struct rtw89_btc_fbtc_btafh_v7 *pafh_v7 = NULL;
 1283	struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
 1284	struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL;
 1285	struct rtw89_btc_fbtc_btscan_v1 *pscan_v1;
 1286	struct rtw89_btc_fbtc_btscan_v2 *pscan_v2;
 1287	struct rtw89_btc_fbtc_btscan_v7 *pscan_v7;
 1288	bool scan_update = true;
 1289	int i;
 1290
 1291	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1292		    "[BTC], %s(): rpt_type:%d\n",
 1293		    __func__, rpt_type);
 1294
 1295	switch (rpt_type) {
 1296	case BTC_RPT_TYPE_BT_VER:
 1297		if (ver->fcxbtver == 7) {
 1298			pver->v7 = *(struct rtw89_btc_fbtc_btver_v7 *)pfinfo;
 1299			bt->ver_info.fw = le32_to_cpu(pver->v7.fw_ver);
 1300			bt->ver_info.fw_coex = le32_get_bits(pver->v7.coex_ver,
 1301							     GENMASK(7, 0));
 1302			bt->feature = le32_to_cpu(pver->v7.feature);
 1303		} else {
 1304			pver->v1 = *(struct rtw89_btc_fbtc_btver_v1 *)pfinfo;
 1305			bt->ver_info.fw = le32_to_cpu(pver->v1.fw_ver);
 1306			bt->ver_info.fw_coex = le32_get_bits(pver->v1.coex_ver,
 1307							     GENMASK(7, 0));
 1308			bt->feature = le32_to_cpu(pver->v1.feature);
 1309		}
 1310		break;
 1311	case BTC_RPT_TYPE_BT_SCAN:
 1312		if (ver->fcxbtscan == 1) {
 1313			pscan_v1 = (struct rtw89_btc_fbtc_btscan_v1 *)pfinfo;
 1314			for (i = 0; i < BTC_SCAN_MAX1; i++) {
 1315				bt->scan_info_v1[i] = pscan_v1->scan[i];
 1316				if (bt->scan_info_v1[i].win == 0 &&
 1317				    bt->scan_info_v1[i].intvl == 0)
 1318					scan_update = false;
 1319			}
 1320		} else if (ver->fcxbtscan == 2) {
 1321			pscan_v2 = (struct rtw89_btc_fbtc_btscan_v2 *)pfinfo;
 1322			for (i = 0; i < CXSCAN_MAX; i++) {
 1323				bt->scan_info_v2[i] = pscan_v2->para[i];
 1324				if ((pscan_v2->type & BIT(i)) &&
 1325				    pscan_v2->para[i].win == 0 &&
 1326				    pscan_v2->para[i].intvl == 0)
 1327					scan_update = false;
 1328			}
 1329		} else if (ver->fcxbtscan == 7) {
 1330			pscan_v7 = (struct rtw89_btc_fbtc_btscan_v7 *)pfinfo;
 1331			for (i = 0; i < CXSCAN_MAX; i++) {
 1332				bt->scan_info_v2[i] = pscan_v7->para[i];
 1333				if ((pscan_v7->type & BIT(i)) &&
 1334				    pscan_v7->para[i].win == 0 &&
 1335				    pscan_v7->para[i].intvl == 0)
 1336					scan_update = false;
 1337			}
 1338		}
 1339		if (scan_update)
 1340			bt->scan_info_update = 1;
 1341		break;
 1342	case BTC_RPT_TYPE_BT_AFH:
 1343		if (ver->fcxbtafh == 2) {
 1344			pafh_v2 = (struct rtw89_btc_fbtc_btafh_v2 *)pfinfo;
 1345			if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LEGACY) {
 1346				memcpy(&bt_linfo->afh_map[0], pafh_v2->afh_l, 4);
 1347				memcpy(&bt_linfo->afh_map[4], pafh_v2->afh_m, 4);
 1348				memcpy(&bt_linfo->afh_map[8], pafh_v2->afh_h, 2);
 1349			}
 1350			if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LE) {
 1351				memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4);
 1352				memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1);
 1353			}
 1354		} else if (ver->fcxbtafh == 7) {
 1355			pafh_v7 = (struct rtw89_btc_fbtc_btafh_v7 *)pfinfo;
 1356			if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LEGACY) {
 1357				memcpy(&bt_linfo->afh_map[0], pafh_v7->afh_l, 4);
 1358				memcpy(&bt_linfo->afh_map[4], pafh_v7->afh_m, 4);
 1359				memcpy(&bt_linfo->afh_map[8], pafh_v7->afh_h, 2);
 1360			}
 1361			if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LE) {
 1362				memcpy(&bt_linfo->afh_map_le[0], pafh_v7->afh_le_a, 4);
 1363				memcpy(&bt_linfo->afh_map_le[4], pafh_v7->afh_le_b, 1);
 1364			}
 1365		} else if (ver->fcxbtafh == 1) {
 1366			pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo;
 1367			memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4);
 1368			memcpy(&bt_linfo->afh_map[4], pafh_v1->afh_m, 4);
 1369			memcpy(&bt_linfo->afh_map[8], pafh_v1->afh_h, 2);
 1370		}
 1371		break;
 1372	case BTC_RPT_TYPE_BT_DEVICE:
 1373		pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
 1374		a2dp->device_name = le32_to_cpu(pdev->dev_name);
 1375		a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
 1376		a2dp->flush_time = le32_to_cpu(pdev->flush_time);
 1377		break;
 1378	default:
 1379		break;
 1380	}
 1381}
 1382
 1383static void rtw89_btc_fw_rpt_evnt_ver(struct rtw89_dev *rtwdev, u8 *index)
 1384{
 1385	struct rtw89_btc *btc = &rtwdev->btc;
 1386	const struct rtw89_btc_ver *ver = btc->ver;
 1387
 1388	if (ver->fwevntrptl == 1)
 1389		return;
 1390
 1391	if (*index <= __BTC_RPT_TYPE_V0_SAME)
 1392		return;
 1393	else if (*index <= __BTC_RPT_TYPE_V0_MAX)
 1394		(*index)++;
 1395	else
 1396		*index = BTC_RPT_TYPE_MAX;
 1397}
 1398
 1399#define BTC_LEAK_AP_TH 10
 1400#define BTC_CYSTA_CHK_PERIOD 100
 1401
 1402struct rtw89_btc_prpt {
 1403	u8 type;
 1404	__le16 len;
 1405	u8 content[];
 1406} __packed;
 1407
 1408static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
 1409			   struct rtw89_btc_btf_fwinfo *pfwinfo,
 1410			   u8 *prptbuf, u32 index)
 1411{
 1412	struct rtw89_btc *btc = &rtwdev->btc;
 1413	struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver;
 1414	const struct rtw89_btc_ver *ver = btc->ver;
 1415	struct rtw89_btc_dm *dm = &btc->dm;
 1416	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
 1417	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 1418	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 1419	union rtw89_btc_fbtc_rpt_ctrl_ver_info *prpt = NULL;
 1420	union rtw89_btc_fbtc_cysta_info *pcysta = NULL;
 1421	struct rtw89_btc_prpt *btc_prpt = NULL;
 1422	void *rpt_content = NULL, *pfinfo = NULL;
 1423	u8 rpt_type = 0;
 1424	u16 wl_slot_set = 0, wl_slot_real = 0, val16;
 1425	u32 trace_step = 0, rpt_len = 0, diff_t = 0;
 1426	u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
 1427	u8 i, val = 0, val1, val2;
 1428
 1429	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1430		    "[BTC], %s(): index:%d\n",
 1431		    __func__, index);
 1432
 1433	if (!prptbuf) {
 1434		pfwinfo->err[BTFRE_INVALID_INPUT]++;
 1435		return 0;
 1436	}
 1437
 1438	btc_prpt = (struct rtw89_btc_prpt *)&prptbuf[index];
 1439	rpt_type = btc_prpt->type;
 1440	rpt_len = le16_to_cpu(btc_prpt->len);
 1441	rpt_content = btc_prpt->content;
 1442
 1443	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1444		    "[BTC], %s(): rpt_type:%d\n",
 1445		    __func__, rpt_type);
 1446
 1447	rtw89_btc_fw_rpt_evnt_ver(rtwdev, &rpt_type);
 1448
 1449	switch (rpt_type) {
 1450	case BTC_RPT_TYPE_CTRL:
 1451		pcinfo = &pfwinfo->rpt_ctrl.cinfo;
 1452		prpt = &pfwinfo->rpt_ctrl.finfo;
 1453		if (ver->fcxbtcrpt == 1) {
 1454			pfinfo = &pfwinfo->rpt_ctrl.finfo.v1;
 1455			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1);
 1456			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v1.fver;
 1457		} else if (ver->fcxbtcrpt == 4) {
 1458			pfinfo = &pfwinfo->rpt_ctrl.finfo.v4;
 1459			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4);
 1460			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v4.fver;
 1461		} else if (ver->fcxbtcrpt == 5) {
 1462			pfinfo = &pfwinfo->rpt_ctrl.finfo.v5;
 1463			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5);
 1464			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v5.fver;
 1465		} else if (ver->fcxbtcrpt == 105) {
 1466			pfinfo = &pfwinfo->rpt_ctrl.finfo.v105;
 1467			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105);
 1468			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver;
 1469			pcinfo->req_fver = 5;
 1470			break;
 1471		} else if (ver->fcxbtcrpt == 8) {
 1472			pfinfo = &pfwinfo->rpt_ctrl.finfo.v8;
 1473			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8);
 1474			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v8.fver;
 1475		} else if (ver->fcxbtcrpt == 7) {
 1476			pfinfo = &pfwinfo->rpt_ctrl.finfo.v7;
 1477			pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7);
 1478			fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver;
 1479		} else {
 1480			goto err;
 1481		}
 1482		pcinfo->req_fver = ver->fcxbtcrpt;
 1483		break;
 1484	case BTC_RPT_TYPE_TDMA:
 1485		pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
 1486		if (ver->fcxtdma == 1) {
 1487			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
 1488			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
 1489			fwsubver->fcxtdma = 0;
 1490		} else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) {
 1491			pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
 1492			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
 1493			fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver;
 1494		} else {
 1495			goto err;
 1496		}
 1497		pcinfo->req_fver = ver->fcxtdma;
 1498		break;
 1499	case BTC_RPT_TYPE_SLOT:
 1500		pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
 1501		if (ver->fcxslots == 1) {
 1502			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1;
 1503			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1);
 1504			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver;
 1505		} else if (ver->fcxslots == 7) {
 1506			pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7;
 1507			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7);
 1508			fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v7.fver;
 1509		} else {
 1510			goto err;
 1511		}
 1512		pcinfo->req_fver = ver->fcxslots;
 1513		break;
 1514	case BTC_RPT_TYPE_CYSTA:
 1515		pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
 1516		pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
 1517		if (ver->fcxcysta == 2) {
 1518			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
 1519			pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
 1520			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2);
 1521			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v2.fver;
 1522		} else if (ver->fcxcysta == 3) {
 1523			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
 1524			pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
 1525			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3);
 1526			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v3.fver;
 1527		} else if (ver->fcxcysta == 4) {
 1528			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4;
 1529			pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4;
 1530			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4);
 1531			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v4.fver;
 1532		} else if (ver->fcxcysta == 5) {
 1533			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
 1534			pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
 1535			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5);
 1536			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver;
 1537		} else if (ver->fcxcysta == 7) {
 1538			pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
 1539			pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
 1540			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7);
 1541			fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v7.fver;
 1542		} else {
 1543			goto err;
 1544		}
 1545		pcinfo->req_fver = ver->fcxcysta;
 1546		break;
 1547	case BTC_RPT_TYPE_STEP:
 1548		pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
 1549		if (ver->fcxctrl != 7)
 1550			trace_step = btc->ctrl.ctrl.trace_step;
 1551
 1552		if (ver->fcxstep == 2) {
 1553			pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2;
 1554			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) *
 1555					  trace_step +
 1556					  offsetof(struct rtw89_btc_fbtc_steps_v2, step);
 1557			fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v2.fver;
 1558		} else if (ver->fcxstep == 3) {
 1559			pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3;
 1560			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) *
 1561					  trace_step +
 1562					  offsetof(struct rtw89_btc_fbtc_steps_v3, step);
 1563			fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v3.fver;
 1564		} else {
 1565			goto err;
 1566		}
 1567		pcinfo->req_fver = ver->fcxstep;
 1568		break;
 1569	case BTC_RPT_TYPE_NULLSTA:
 1570		pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
 1571		if (ver->fcxnullsta == 1) {
 1572			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v1;
 1573			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1);
 1574			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v1.fver;
 1575		} else if (ver->fcxnullsta == 2) {
 1576			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2;
 1577			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2);
 1578			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v2.fver;
 1579		} else if (ver->fcxnullsta == 7) {
 1580			pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7;
 1581			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7);
 1582			fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v7.fver;
 1583		} else {
 1584			goto err;
 1585		}
 1586		pcinfo->req_fver = ver->fcxnullsta;
 1587		break;
 1588	case BTC_RPT_TYPE_MREG:
 1589		pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
 1590		if (ver->fcxmreg == 1) {
 1591			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v1;
 1592			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v1);
 1593			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v1.fver;
 1594		} else if (ver->fcxmreg == 2) {
 1595			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
 1596			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2);
 1597			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v2.fver;
 1598		} else if (ver->fcxmreg == 7) {
 1599			pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
 1600			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7);
 1601			fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v7.fver;
 1602		} else {
 1603			goto err;
 1604		}
 1605		pcinfo->req_fver = ver->fcxmreg;
 1606		break;
 1607	case BTC_RPT_TYPE_GPIO_DBG:
 1608		pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
 1609		if (ver->fcxgpiodbg == 7) {
 1610			pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7;
 1611			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7);
 1612			fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7.fver;
 1613		} else {
 1614			pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1;
 1615			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1);
 1616			fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1.fver;
 1617		}
 1618		pcinfo->req_fver = ver->fcxgpiodbg;
 1619		break;
 1620	case BTC_RPT_TYPE_BT_VER:
 1621		pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
 1622		if (ver->fcxbtver == 1) {
 1623			pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1;
 1624			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1);
 1625			fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v1.fver;
 1626		} else if (ver->fcxbtver == 7) {
 1627			pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7;
 1628			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7);
 1629			fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver;
 1630		}
 1631		pcinfo->req_fver = ver->fcxbtver;
 1632		break;
 1633	case BTC_RPT_TYPE_BT_SCAN:
 1634		pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
 1635		if (ver->fcxbtscan == 1) {
 1636			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v1;
 1637			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v1);
 1638			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v1.fver;
 1639		} else if (ver->fcxbtscan == 2) {
 1640			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2;
 1641			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2);
 1642			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v2.fver;
 1643		} else if (ver->fcxbtscan == 7) {
 1644			pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7;
 1645			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7);
 1646			fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver;
 1647		} else {
 1648			goto err;
 1649		}
 1650		pcinfo->req_fver = ver->fcxbtscan;
 1651		break;
 1652	case BTC_RPT_TYPE_BT_AFH:
 1653		pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
 1654		if (ver->fcxbtafh == 1) {
 1655			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1;
 1656			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1);
 1657			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v1.fver;
 1658		} else if (ver->fcxbtafh == 2) {
 1659			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2;
 1660			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2);
 1661			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v2.fver;
 1662		} else if (ver->fcxbtafh == 7) {
 1663			pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7;
 1664			pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7);
 1665			fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver;
 1666		} else {
 1667			goto err;
 1668		}
 1669		pcinfo->req_fver = ver->fcxbtafh;
 1670		break;
 1671	case BTC_RPT_TYPE_BT_DEVICE:
 1672		pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
 1673		pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo;
 1674		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo);
 1675		fwsubver->fcxbtdevinfo = pfwinfo->rpt_fbtc_btdev.finfo.fver;
 1676		pcinfo->req_fver = ver->fcxbtdevinfo;
 1677		break;
 1678	default:
 1679		pfwinfo->err[BTFRE_UNDEF_TYPE]++;
 1680		return 0;
 1681	}
 1682
 1683	pcinfo->rx_len = rpt_len;
 1684	pcinfo->rx_cnt++;
 1685
 1686	if (rpt_len != pcinfo->req_len) {
 1687		if (rpt_type < BTC_RPT_TYPE_MAX)
 1688			pfwinfo->len_mismch |= (0x1 << rpt_type);
 1689		else
 1690			pfwinfo->len_mismch |= BIT(31);
 1691		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1692			    "[BTC], %s(): %d rpt_len:%d!=req_len:%d\n",
 1693			    __func__, rpt_type, rpt_len, pcinfo->req_len);
 1694
 1695		pcinfo->valid = 0;
 1696		return 0;
 1697	} else if (!pfinfo || !rpt_content || !pcinfo->req_len) {
 1698		pfwinfo->err[BTFRE_EXCEPTION]++;
 1699		pcinfo->valid = 0;
 1700		return 0;
 1701	}
 1702
 1703	memcpy(pfinfo, rpt_content, pcinfo->req_len);
 1704	pcinfo->valid = 1;
 1705
 1706	switch (rpt_type) {
 1707	case BTC_RPT_TYPE_CTRL:
 1708		if (ver->fcxbtcrpt == 1) {
 1709			prpt->v1 = pfwinfo->rpt_ctrl.finfo.v1;
 1710			btc->fwinfo.rpt_en_map = prpt->v1.rpt_enable;
 1711			wl->ver_info.fw_coex = prpt->v1.wl_fw_coex_ver;
 1712			wl->ver_info.fw = prpt->v1.wl_fw_ver;
 1713			dm->wl_fw_cx_offload = !!prpt->v1.wl_fw_cx_offload;
 1714
 1715			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
 1716				     pfwinfo->event[BTF_EVNT_RPT]);
 1717
 1718			/* To avoid I/O if WL LPS or power-off */
 1719			if (wl->status.map.lps != BTC_LPS_RF_OFF &&
 1720			    !wl->status.map.rf_off) {
 1721				rtwdev->chip->ops->btc_update_bt_cnt(rtwdev);
 1722				_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1723
 1724				btc->cx.cnt_bt[BTC_BCNT_POLUT] =
 1725					rtw89_mac_get_plt_cnt(rtwdev,
 1726							      RTW89_MAC_0);
 1727			}
 1728		} else if (ver->fcxbtcrpt == 4) {
 1729			prpt->v4 = pfwinfo->rpt_ctrl.finfo.v4;
 1730			btc->fwinfo.rpt_en_map = le32_to_cpu(prpt->v4.rpt_info.en);
 1731			wl->ver_info.fw_coex = le32_to_cpu(prpt->v4.wl_fw_info.cx_ver);
 1732			wl->ver_info.fw = le32_to_cpu(prpt->v4.wl_fw_info.fw_ver);
 1733			dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload);
 1734
 1735			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
 1736				memcpy(&dm->gnt.band[i], &prpt->v4.gnt_val[i],
 1737				       sizeof(dm->gnt.band[i]));
 1738
 1739			btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
 1740				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]);
 1741			btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
 1742				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_RX]);
 1743			btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
 1744				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]);
 1745			btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
 1746				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]);
 1747			btc->cx.cnt_bt[BTC_BCNT_POLUT] =
 1748				le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]);
 1749
 1750			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1751			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
 1752				     pfwinfo->event[BTF_EVNT_RPT]);
 1753
 1754			if (le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
 1755				bt->rfk_info.map.timeout = 1;
 1756			else
 1757				bt->rfk_info.map.timeout = 0;
 1758
 1759			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
 1760		} else if (ver->fcxbtcrpt == 5) {
 1761			prpt->v5 = pfwinfo->rpt_ctrl.finfo.v5;
 1762			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v5.rpt_info.en);
 1763			wl->ver_info.fw_coex = le32_to_cpu(prpt->v5.rpt_info.cx_ver);
 1764			wl->ver_info.fw = le32_to_cpu(prpt->v5.rpt_info.fw_ver);
 1765			dm->wl_fw_cx_offload = 0;
 1766
 1767			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
 1768				memcpy(&dm->gnt.band[i], &prpt->v5.gnt_val[i][0],
 1769				       sizeof(dm->gnt.band[i]));
 1770
 1771			btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
 1772				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]);
 1773			btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
 1774				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_RX]);
 1775			btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
 1776				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]);
 1777			btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
 1778				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]);
 1779			btc->cx.cnt_bt[BTC_BCNT_POLUT] =
 1780				le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]);
 1781
 1782			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1783			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
 1784				     pfwinfo->event[BTF_EVNT_RPT]);
 1785
 1786			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
 1787		} else if (ver->fcxbtcrpt == 105) {
 1788			prpt->v105 = pfwinfo->rpt_ctrl.finfo.v105;
 1789			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v105.rpt_info.en);
 1790			wl->ver_info.fw_coex = le32_to_cpu(prpt->v105.rpt_info.cx_ver);
 1791			wl->ver_info.fw = le32_to_cpu(prpt->v105.rpt_info.fw_ver);
 1792			dm->wl_fw_cx_offload = 0;
 1793
 1794			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
 1795				memcpy(&dm->gnt.band[i], &prpt->v105.gnt_val[i][0],
 1796				       sizeof(dm->gnt.band[i]));
 1797
 1798			btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
 1799				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_TX_V105]);
 1800			btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
 1801				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_RX_V105]);
 1802			btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
 1803				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_TX_V105]);
 1804			btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
 1805				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_RX_V105]);
 1806			btc->cx.cnt_bt[BTC_BCNT_POLUT] =
 1807				le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_POLLUTED_V105]);
 1808
 1809			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1810			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
 1811				     pfwinfo->event[BTF_EVNT_RPT]);
 1812
 1813			dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
 1814		} else if (ver->fcxbtcrpt == 7) {
 1815			prpt->v7 = pfwinfo->rpt_ctrl.finfo.v7;
 1816			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v7.rpt_info.en);
 1817			wl->ver_info.fw_coex = le32_to_cpu(prpt->v7.rpt_info.cx_ver);
 1818			wl->ver_info.fw = le32_to_cpu(prpt->v7.rpt_info.fw_ver);
 1819
 1820			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
 1821				memcpy(&dm->gnt.band[i], &prpt->v7.gnt_val[i][0],
 1822				       sizeof(dm->gnt.band[i]));
 1823
 1824			btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
 1825				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_TX_V105]);
 1826			btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
 1827				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_RX_V105]);
 1828			btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
 1829				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_TX_V105]);
 1830			btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
 1831				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_RX_V105]);
 1832
 1833			val1 = le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);
 1834			if (val1 > btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW])
 1835				val1 -= btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW]; /* diff */
 1836
 1837			btc->cx.cnt_bt[BTC_BCNT_POLUT_DIFF] = val1;
 1838			btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW] =
 1839				le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);
 1840
 1841			val1 = pfwinfo->event[BTF_EVNT_RPT];
 1842			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1843			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
 1844			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
 1845			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
 1846		} else if (ver->fcxbtcrpt == 8) {
 1847			prpt->v8 = pfwinfo->rpt_ctrl.finfo.v8;
 1848			pfwinfo->rpt_en_map = le32_to_cpu(prpt->v8.rpt_info.en);
 1849			wl->ver_info.fw_coex = le32_to_cpu(prpt->v8.rpt_info.cx_ver);
 1850			wl->ver_info.fw = le32_to_cpu(prpt->v8.rpt_info.fw_ver);
 1851
 1852			for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
 1853				memcpy(&dm->gnt.band[i], &prpt->v8.gnt_val[i][0],
 1854				       sizeof(dm->gnt.band[i]));
 1855
 1856			btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
 1857				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_TX_V105]);
 1858			btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
 1859				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_RX_V105]);
 1860			btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
 1861				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_TX_V105]);
 1862			btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
 1863				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_RX_V105]);
 1864
 1865			val1 = le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
 1866			if (val1 > btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW])
 1867				val1 -= btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW]; /* diff */
 1868
 1869			btc->cx.cnt_bt[BTC_BCNT_POLUT_DIFF] = val1;
 1870			btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW] =
 1871				le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
 1872
 1873			val1 = pfwinfo->event[BTF_EVNT_RPT];
 1874			if (((prpt->v8.rpt_len_max_h << 8) +
 1875			      prpt->v8.rpt_len_max_l) != ver->info_buf)
 1876				dm->error.map.h2c_c2h_buffer_mismatch = true;
 1877			else
 1878				dm->error.map.h2c_c2h_buffer_mismatch = false;
 1879
 1880			_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
 1881			_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
 1882			_chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
 1883			_chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
 1884		} else {
 1885			goto err;
 1886		}
 1887		break;
 1888	case BTC_RPT_TYPE_TDMA:
 1889		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1890			    "[BTC], %s(): check %d %zu\n", __func__,
 1891			    BTC_DCNT_TDMA_NONSYNC,
 1892			    sizeof(dm->tdma_now));
 1893		if (ver->fcxtdma == 1)
 1894			_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
 1895				     memcmp(&dm->tdma_now,
 1896					    &pfwinfo->rpt_fbtc_tdma.finfo.v1,
 1897					    sizeof(dm->tdma_now)));
 1898		else if (ver->fcxtdma == 3 || ver->fcxtdma == 7)
 1899			_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
 1900				     memcmp(&dm->tdma_now,
 1901					    &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
 1902					    sizeof(dm->tdma_now)));
 1903		else
 1904			goto err;
 1905		break;
 1906	case BTC_RPT_TYPE_SLOT:
 1907		if (ver->fcxslots == 7) {
 1908			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1909				    "[BTC], %s(): check %d %zu\n",
 1910				    __func__, BTC_DCNT_SLOT_NONSYNC,
 1911				    sizeof(dm->slot_now.v7));
 1912			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
 1913				     memcmp(dm->slot_now.v7,
 1914					    pfwinfo->rpt_fbtc_slots.finfo.v7.slot,
 1915					    sizeof(dm->slot_now.v7)));
 1916		} else if (ver->fcxslots == 1) {
 1917			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 1918				    "[BTC], %s(): check %d %zu\n",
 1919				    __func__, BTC_DCNT_SLOT_NONSYNC,
 1920				    sizeof(dm->slot_now.v1));
 1921			_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
 1922				     memcmp(dm->slot_now.v1,
 1923					    pfwinfo->rpt_fbtc_slots.finfo.v1.slot,
 1924					    sizeof(dm->slot_now.v1)));
 1925		}
 1926		break;
 1927	case BTC_RPT_TYPE_CYSTA:
 1928		if (ver->fcxcysta == 2) {
 1929			if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD)
 1930				break;
 1931			/* Check Leak-AP */
 1932			if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 &&
 1933			    le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) {
 1934				if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) <
 1935				    BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt))
 1936					dm->leak_ap = 1;
 1937			}
 1938
 1939			/* Check diff time between WL slot and W1/E2G slot */
 1940			if (dm->tdma_now.type == CXTDMA_OFF &&
 1941			    dm->tdma_now.ext_ctrl == CXECTL_EXT) {
 1942				if (ver->fcxslots == 1)
 1943					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_E2G].dur);
 1944				else if (ver->fcxslots == 7)
 1945					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_E2G].dur);
 1946			} else {
 1947				if (ver->fcxslots == 1)
 1948					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
 1949				else if (ver->fcxslots == 7)
 1950					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
 1951			}
 1952
 1953			if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) {
 1954				diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set;
 1955				_chk_btc_err(rtwdev,
 1956					     BTC_DCNT_WL_SLOT_DRIFT, diff_t);
 1957			}
 1958
 1959			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 1960				     le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1]));
 1961			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 1962				     le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1]));
 1963			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 1964				     le16_to_cpu(pcysta->v2.cycles));
 1965		} else if (ver->fcxcysta == 3) {
 1966			if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD)
 1967				break;
 1968
 1969			cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]);
 1970			cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr);
 1971
 1972			/* Check Leak-AP */
 1973			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
 1974			    dm->tdma_now.rxflctrl) {
 1975				if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
 1976					dm->leak_ap = 1;
 1977			}
 1978
 1979			/* Check diff time between real WL slot and W1 slot */
 1980			if (dm->tdma_now.type == CXTDMA_OFF) {
 1981				if (ver->fcxslots == 1)
 1982					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
 1983				else if (ver->fcxslots == 7)
 1984					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
 1985				wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]);
 1986				if (wl_slot_real > wl_slot_set) {
 1987					diff_t = wl_slot_real - wl_slot_set;
 1988					_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
 1989				}
 1990			}
 1991
 1992			/* Check diff time between real BT slot and EBT/E5G slot */
 1993			if (dm->tdma_now.type == CXTDMA_OFF &&
 1994			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
 1995			    btc->bt_req_len != 0) {
 1996				bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]);
 1997				if (btc->bt_req_len > bt_slot_real) {
 1998					diff_t = btc->bt_req_len - bt_slot_real;
 1999					_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
 2000				}
 2001			}
 2002
 2003			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 2004				     le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1]));
 2005			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
 2006				     le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1]));
 2007			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 2008				     le16_to_cpu(pcysta->v3.cycles));
 2009		} else if (ver->fcxcysta == 4) {
 2010			if (le16_to_cpu(pcysta->v4.cycles) < BTC_CYSTA_CHK_PERIOD)
 2011				break;
 2012
 2013			cnt_leak_slot = le16_to_cpu(pcysta->v4.slot_cnt[CXST_LK]);
 2014			cnt_rx_imr = le32_to_cpu(pcysta->v4.leak_slot.cnt_rximr);
 2015
 2016			/* Check Leak-AP */
 2017			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
 2018			    dm->tdma_now.rxflctrl) {
 2019				if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
 2020					dm->leak_ap = 1;
 2021			}
 2022
 2023			/* Check diff time between real WL slot and W1 slot */
 2024			if (dm->tdma_now.type == CXTDMA_OFF) {
 2025				if (ver->fcxslots == 1)
 2026					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
 2027				else if (ver->fcxslots == 7)
 2028					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
 2029				wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]);
 2030				if (wl_slot_real > wl_slot_set) {
 2031					diff_t = wl_slot_real - wl_slot_set;
 2032					_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
 2033				}
 2034			}
 2035
 2036			/* Check diff time between real BT slot and EBT/E5G slot */
 2037			if (dm->tdma_now.type == CXTDMA_OFF &&
 2038			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
 2039			    btc->bt_req_len != 0) {
 2040				bt_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_BT]);
 2041
 2042				if (btc->bt_req_len > bt_slot_real) {
 2043					diff_t = btc->bt_req_len - bt_slot_real;
 2044					_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
 2045				}
 2046			}
 2047
 2048			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 2049				     le16_to_cpu(pcysta->v4.slot_cnt[CXST_W1]));
 2050			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
 2051				     le16_to_cpu(pcysta->v4.slot_cnt[CXST_B1]));
 2052			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 2053				     le16_to_cpu(pcysta->v4.cycles));
 2054		} else if (ver->fcxcysta == 5) {
 2055			if (dm->fddt_train == BTC_FDDT_ENABLE)
 2056				break;
 2057			cnt_leak_slot = le16_to_cpu(pcysta->v5.slot_cnt[CXST_LK]);
 2058			cnt_rx_imr = le32_to_cpu(pcysta->v5.leak_slot.cnt_rximr);
 2059
 2060			/* Check Leak-AP */
 2061			if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
 2062			    dm->tdma_now.rxflctrl) {
 2063				if (le16_to_cpu(pcysta->v5.cycles) >= BTC_CYSTA_CHK_PERIOD &&
 2064				    cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
 2065					dm->leak_ap = 1;
 2066			}
 2067
 2068			/* Check diff time between real WL slot and W1 slot */
 2069			if (dm->tdma_now.type == CXTDMA_OFF) {
 2070				if (ver->fcxslots == 1)
 2071					wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
 2072				else if (ver->fcxslots == 7)
 2073					wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
 2074				wl_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_WL]);
 2075
 2076				if (wl_slot_real > wl_slot_set)
 2077					diff_t = wl_slot_real - wl_slot_set;
 2078				else
 2079					diff_t = wl_slot_set - wl_slot_real;
 2080			}
 2081			_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
 2082
 2083			/* Check diff time between real BT slot and EBT/E5G slot */
 2084			bt_slot_set = btc->bt_req_len;
 2085			bt_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_BT]);
 2086			diff_t = 0;
 2087			if (dm->tdma_now.type == CXTDMA_OFF &&
 2088			    dm->tdma_now.ext_ctrl == CXECTL_EXT &&
 2089			    bt_slot_set != 0) {
 2090				if (bt_slot_set > bt_slot_real)
 2091					diff_t = bt_slot_set - bt_slot_real;
 2092				else
 2093					diff_t = bt_slot_real - bt_slot_set;
 2094			}
 2095
 2096			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
 2097			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
 2098				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_E2G]));
 2099			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 2100				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_W1]));
 2101			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
 2102				     le16_to_cpu(pcysta->v5.slot_cnt[CXST_B1]));
 2103			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 2104				     le16_to_cpu(pcysta->v5.cycles));
 2105		} else if (ver->fcxcysta == 7) {
 2106			if (dm->fddt_train == BTC_FDDT_ENABLE)
 2107				break;
 2108
 2109			pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
 2110
 2111			if (dm->tdma_now.type != CXTDMA_OFF) {
 2112				/* Check diff time between real WL slot and W1 slot */
 2113				val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_WL]);
 2114				_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, val16);
 2115
 2116				/* Check Leak-AP */
 2117				val1 = le32_to_cpu(pcysta->v7.leak_slot.cnt_rximr) *
 2118				       BTC_LEAK_AP_TH;
 2119				val2 = le16_to_cpu(pcysta->v7.slot_cnt[CXST_LK]);
 2120
 2121				val16 = le16_to_cpu(pcysta->v7.cycles);
 2122				if (dm->tdma_now.rxflctrl &&
 2123				    val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
 2124					dm->leak_ap = 1;
 2125			} else if (dm->tdma_now.ext_ctrl == CXECTL_EXT) {
 2126				val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_BT]);
 2127				/* Check diff between real BT slot and EBT/E5G slot */
 2128				_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, val16);
 2129
 2130				/* Check bt slot length for P2P mode*/
 2131				val1 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt_timeout) *
 2132				       BTC_SLOT_REQ_TH;
 2133				val2 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt);
 2134
 2135				val16 = le16_to_cpu(pcysta->v7.cycles);
 2136				if (val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
 2137					dm->slot_req_more = 1;
 2138				else if (bt->link_info.status.map.connect == 0)
 2139					dm->slot_req_more = 0;
 2140			}
 2141
 2142			_chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
 2143				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_E2G]));
 2144			_chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
 2145				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_W1]));
 2146			_chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
 2147				     le16_to_cpu(pcysta->v7.slot_cnt[CXST_B1]));
 2148
 2149			/* "BT_SLOT_FLOOD" error-check MUST before "CYCLE_HANG" */
 2150			_chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_FLOOD,
 2151				     le16_to_cpu(pcysta->v7.cycles));
 2152			_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
 2153				     le16_to_cpu(pcysta->v7.cycles));
 2154		} else {
 2155			goto err;
 2156		}
 2157		break;
 2158	case BTC_RPT_TYPE_MREG:
 2159		if (ver->fcxmreg == 7)
 2160			break;
 2161		_get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX_MON, &val);
 2162		if (dm->wl_btg_rx == BTC_BTGCTRL_BB_GNT_FWCTRL)
 2163			dm->wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_FWCTRL;
 2164		else
 2165			dm->wl_btg_rx_rb = val;
 2166
 2167		_get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC_MON, &val);
 2168		if (dm->wl_pre_agc == BTC_PREAGC_BB_FWCTRL)
 2169			dm->wl_pre_agc_rb = BTC_PREAGC_BB_FWCTRL;
 2170		else
 2171			dm->wl_pre_agc_rb = val;
 2172		break;
 2173	case BTC_RPT_TYPE_BT_VER:
 2174	case BTC_RPT_TYPE_BT_SCAN:
 2175	case BTC_RPT_TYPE_BT_AFH:
 2176	case BTC_RPT_TYPE_BT_DEVICE:
 2177		_update_bt_report(rtwdev, rpt_type, pfinfo);
 2178		break;
 2179	}
 2180	return (rpt_len + BTC_RPT_HDR_SIZE);
 2181
 2182err:
 2183	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2184		    "[BTC], %s(): Undefined version for type=%d\n", __func__, rpt_type);
 2185	return 0;
 2186}
 2187
 2188static void _parse_btc_report(struct rtw89_dev *rtwdev,
 2189			      struct rtw89_btc_btf_fwinfo *pfwinfo,
 2190			      u8 *pbuf, u32 buf_len)
 2191{
 2192	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
 2193	struct rtw89_btc_prpt *btc_prpt = NULL;
 2194	u32 index = 0, rpt_len = 0;
 2195
 2196	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2197		    "[BTC], %s(): buf_len:%d\n",
 2198		    __func__, buf_len);
 2199
 2200	while (pbuf) {
 2201		btc_prpt = (struct rtw89_btc_prpt *)&pbuf[index];
 2202		if (index + 2 >= ver->info_buf)
 2203			break;
 2204		/* At least 3 bytes: type(1) & len(2) */
 2205		rpt_len = le16_to_cpu(btc_prpt->len);
 2206		if ((index + rpt_len + BTC_RPT_HDR_SIZE) > buf_len)
 2207			break;
 2208
 2209		rpt_len = _chk_btc_report(rtwdev, pfwinfo, pbuf, index);
 2210		if (!rpt_len)
 2211			break;
 2212		index += rpt_len;
 2213	}
 2214}
 2215
 2216#define BTC_TLV_HDR_LEN 2
 2217#define BTC_TLV_HDR_LEN_V7 3
 2218
 2219static void _append_tdma(struct rtw89_dev *rtwdev)
 2220{
 2221	struct rtw89_btc *btc = &rtwdev->btc;
 2222	const struct rtw89_btc_ver *ver = btc->ver;
 2223	struct rtw89_btc_dm *dm = &btc->dm;
 2224	struct rtw89_btc_btf_tlv *tlv;
 2225	struct rtw89_btc_btf_tlv_v7 *tlv_v7;
 2226	struct rtw89_btc_fbtc_tdma *v;
 2227	struct rtw89_btc_fbtc_tdma_v3 *v3;
 2228	u16 len = btc->policy_len;
 2229
 2230	if (!btc->update_policy_force &&
 2231	    !memcmp(&dm->tdma, &dm->tdma_now, sizeof(dm->tdma))) {
 2232		rtw89_debug(rtwdev,
 2233			    RTW89_DBG_BTC, "[BTC], %s(): tdma no change!\n",
 2234			    __func__);
 2235		return;
 2236	}
 2237
 2238	tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
 2239	tlv->type = CXPOLICY_TDMA;
 2240	if (ver->fcxtdma == 1) {
 2241		v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0];
 2242		tlv->len = sizeof(*v);
 2243		*v = dm->tdma;
 2244		btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
 2245	} else if (ver->fcxtdma == 7) {
 2246		tlv_v7 = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
 2247		tlv_v7->len = sizeof(dm->tdma);
 2248		tlv_v7->ver = ver->fcxtdma;
 2249		tlv_v7->type = CXPOLICY_TDMA;
 2250		memcpy(tlv_v7->val, &dm->tdma, tlv_v7->len);
 2251		btc->policy_len += BTC_TLV_HDR_LEN_V7 + tlv_v7->len;
 2252	} else {
 2253		tlv->len = sizeof(*v3);
 2254		v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0];
 2255		v3->fver = ver->fcxtdma;
 2256		v3->tdma = dm->tdma;
 2257		btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3);
 2258	}
 2259
 2260	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2261		    "[BTC], %s(): type:%d, rxflctrl=%d, txpause=%d, wtgle_n=%d, leak_n=%d, ext_ctrl=%d\n",
 2262		    __func__, dm->tdma.type, dm->tdma.rxflctrl,
 2263		    dm->tdma.txpause, dm->tdma.wtgle_n, dm->tdma.leak_n,
 2264		    dm->tdma.ext_ctrl);
 2265}
 2266
 2267static void _append_slot_v1(struct rtw89_dev *rtwdev)
 2268{
 2269	struct rtw89_btc *btc = &rtwdev->btc;
 2270	struct rtw89_btc_dm *dm = &btc->dm;
 2271	struct rtw89_btc_btf_tlv *tlv = NULL;
 2272	struct btc_fbtc_1slot *v = NULL;
 2273	u16 len = 0;
 2274	u8 i, cnt = 0;
 2275
 2276	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2277		    "[BTC], %s(): A:btc->policy_len = %d\n",
 2278		    __func__, btc->policy_len);
 2279
 2280	for (i = 0; i < CXST_MAX; i++) {
 2281		if (!btc->update_policy_force &&
 2282		    !memcmp(&dm->slot.v1[i], &dm->slot_now.v1[i],
 2283			    sizeof(dm->slot.v1[i])))
 2284			continue;
 2285
 2286		len = btc->policy_len;
 2287
 2288		tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
 2289		v = (struct btc_fbtc_1slot *)&tlv->val[0];
 2290		tlv->type = CXPOLICY_SLOT;
 2291		tlv->len = sizeof(*v);
 2292
 2293		v->fver = btc->ver->fcxslots;
 2294		v->sid = i;
 2295		v->slot = dm->slot.v1[i];
 2296
 2297		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2298			    "[BTC], %s(): slot-%d: dur=%d, table=0x%08x, type=%d\n",
 2299			    __func__, i, dm->slot.v1[i].dur, dm->slot.v1[i].cxtbl,
 2300			    dm->slot.v1[i].cxtype);
 2301		cnt++;
 2302
 2303		btc->policy_len += BTC_TLV_HDR_LEN  + sizeof(*v);
 2304	}
 2305
 2306	if (cnt > 0)
 2307		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2308			    "[BTC], %s(): slot update (cnt=%d)!!\n",
 2309			    __func__, cnt);
 2310}
 2311
 2312static void _append_slot_v7(struct rtw89_dev *rtwdev)
 2313{
 2314	struct rtw89_btc_btf_tlv_v7 *tlv = NULL;
 2315	struct rtw89_btc *btc = &rtwdev->btc;
 2316	struct rtw89_btc_dm *dm = &btc->dm;
 2317	u8 i, cnt = 0;
 2318	u16 len;
 2319
 2320	for (i = 0; i < CXST_MAX; i++) {
 2321		if (!btc->update_policy_force &&
 2322		    !memcmp(&dm->slot.v7[i], &dm->slot_now.v7[i],
 2323			    sizeof(dm->slot.v7[i])))
 2324			continue;
 2325
 2326		len = btc->policy_len;
 2327
 2328		if (!tlv) {
 2329			if ((len + BTC_TLV_HDR_LEN_V7) > RTW89_BTC_POLICY_MAXLEN) {
 2330				rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2331					    "[BTC], %s(): buff overflow!\n", __func__);
 2332				break;
 2333			}
 2334
 2335			tlv = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
 2336			tlv->type = CXPOLICY_SLOT;
 2337			tlv->ver = btc->ver->fcxslots;
 2338			tlv->len = sizeof(dm->slot.v7[0]) + BTC_TLV_SLOT_ID_LEN_V7;
 2339			len += BTC_TLV_HDR_LEN_V7;
 2340		}
 2341
 2342		if ((len + (u16)tlv->len) > RTW89_BTC_POLICY_MAXLEN) {
 2343			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2344				    "[BTC], %s(): buff overflow!\n", __func__);
 2345			break;
 2346		}
 2347
 2348		btc->policy[len] = i; /* slot-id */
 2349		memcpy(&btc->policy[len + 1], &dm->slot.v7[i],
 2350		       sizeof(dm->slot.v7[0]));
 2351		len += tlv->len;
 2352
 2353		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2354			    "[BTC], %s: policy_len=%d, slot-%d: dur=%d, type=%d, table=0x%08x\n",
 2355			    __func__, btc->policy_len, i, dm->slot.v7[i].dur,
 2356			    dm->slot.v7[i].cxtype, dm->slot.v7[i].cxtbl);
 2357		cnt++;
 2358		btc->policy_len = len; /* update total length */
 2359	}
 2360
 2361	if (cnt > 0)
 2362		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2363			    "[BTC], %s: slot update (cnt=%d, len=%d)!!\n",
 2364			    __func__, cnt, btc->policy_len);
 2365}
 2366
 2367static void _append_slot(struct rtw89_dev *rtwdev)
 2368{
 2369	struct rtw89_btc *btc = &rtwdev->btc;
 2370
 2371	if (btc->ver->fcxslots == 7)
 2372		_append_slot_v7(rtwdev);
 2373	else
 2374		_append_slot_v1(rtwdev);
 2375}
 2376
 2377static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
 2378{
 2379	struct rtw89_btc *btc = &rtwdev->btc;
 2380	const struct rtw89_btc_ver *ver = btc->ver;
 2381	u32 bit_map = 0;
 2382
 2383	switch (rpt_map) {
 2384	case RPT_EN_TDMA:
 2385		bit_map = BIT(0);
 2386		break;
 2387	case RPT_EN_CYCLE:
 2388		bit_map = BIT(1);
 2389		break;
 2390	case RPT_EN_MREG:
 2391		bit_map = BIT(2);
 2392		break;
 2393	case RPT_EN_BT_VER_INFO:
 2394		bit_map = BIT(3);
 2395		break;
 2396	case RPT_EN_BT_SCAN_INFO:
 2397		bit_map = BIT(4);
 2398		break;
 2399	case RPT_EN_BT_DEVICE_INFO:
 2400		switch (ver->frptmap) {
 2401		case 0:
 2402		case 1:
 2403		case 2:
 2404			bit_map = BIT(6);
 2405			break;
 2406		case 3:
 2407		case 4:
 2408			bit_map = BIT(5);
 2409			break;
 2410		default:
 2411			break;
 2412		}
 2413		break;
 2414	case RPT_EN_BT_AFH_MAP:
 2415		switch (ver->frptmap) {
 2416		case 0:
 2417		case 1:
 2418		case 2:
 2419			bit_map = BIT(5);
 2420			break;
 2421		case 3:
 2422		case 4:
 2423			bit_map = BIT(6);
 2424			break;
 2425		default:
 2426			break;
 2427		}
 2428		break;
 2429	case RPT_EN_BT_AFH_MAP_LE:
 2430		switch (ver->frptmap) {
 2431		case 2:
 2432			bit_map = BIT(8);
 2433			break;
 2434		case 3:
 2435		case 4:
 2436			bit_map = BIT(7);
 2437			break;
 2438		default:
 2439			break;
 2440		}
 2441		break;
 2442	case RPT_EN_BT_TX_PWR_LVL:
 2443		switch (ver->frptmap) {
 2444		case 0:
 2445		case 1:
 2446		case 2:
 2447		case 3:
 2448			break;
 2449		case 4:
 2450			bit_map = BIT(8);
 2451			break;
 2452		default:
 2453			break;
 2454		}
 2455		break;
 2456	case RPT_EN_FW_STEP_INFO:
 2457		switch (ver->frptmap) {
 2458		case 1:
 2459		case 2:
 2460			bit_map = BIT(7);
 2461			break;
 2462		case 3:
 2463			bit_map = BIT(8);
 2464			break;
 2465		case 4:
 2466			bit_map = BIT(9);
 2467			break;
 2468		default:
 2469			break;
 2470		}
 2471		break;
 2472	case RPT_EN_TEST:
 2473		bit_map = BIT(31);
 2474		break;
 2475	case RPT_EN_WL_ALL:
 2476		switch (ver->frptmap) {
 2477		case 0:
 2478		case 1:
 2479		case 2:
 2480			bit_map = GENMASK(2, 0);
 2481			break;
 2482		case 3:
 2483			bit_map = GENMASK(2, 0) | BIT(8);
 2484			break;
 2485		case 4:
 2486			bit_map = GENMASK(2, 0) | BIT(9);
 2487			break;
 2488		default:
 2489			break;
 2490		}
 2491		break;
 2492	case RPT_EN_BT_ALL:
 2493		switch (ver->frptmap) {
 2494		case 0:
 2495		case 1:
 2496			bit_map = GENMASK(6, 3);
 2497			break;
 2498		case 2:
 2499			bit_map = GENMASK(6, 3) | BIT(8);
 2500			break;
 2501		case 3:
 2502			bit_map = GENMASK(7, 3);
 2503			break;
 2504		case 4:
 2505			bit_map = GENMASK(8, 3);
 2506			break;
 2507		default:
 2508			break;
 2509		}
 2510		break;
 2511	case RPT_EN_ALL:
 2512		switch (ver->frptmap) {
 2513		case 0:
 2514			bit_map = GENMASK(6, 0);
 2515			break;
 2516		case 1:
 2517			bit_map = GENMASK(7, 0);
 2518			break;
 2519		case 2:
 2520		case 3:
 2521			bit_map = GENMASK(8, 0);
 2522			break;
 2523		case 4:
 2524			bit_map = GENMASK(9, 0);
 2525			break;
 2526		default:
 2527			break;
 2528		}
 2529		break;
 2530	case RPT_EN_MONITER:
 2531		switch (ver->frptmap) {
 2532		case 0:
 2533		case 1:
 2534			bit_map = GENMASK(6, 2);
 2535			break;
 2536		case 2:
 2537			bit_map = GENMASK(6, 2) | BIT(8);
 2538			break;
 2539		case 3:
 2540			bit_map = GENMASK(8, 2);
 2541			break;
 2542		case 4:
 2543			bit_map = GENMASK(9, 2);
 2544			break;
 2545		default:
 2546			break;
 2547		}
 2548		break;
 2549	}
 2550
 2551	return bit_map;
 2552}
 2553
 2554static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev)
 2555{
 2556	struct rtw89_btc *btc = &rtwdev->btc;
 2557	const struct rtw89_btc_ver *ver = btc->ver;
 2558	struct rtw89_btc_btf_tlv_v7 *tlv_v7 = NULL;
 2559	struct rtw89_btc_btf_set_slot_table *tbl;
 2560	struct rtw89_btc_dm *dm = &btc->dm;
 2561	u16 n, len;
 2562
 2563	if (ver->fcxslots == 7) {
 2564		len = sizeof(*tlv_v7) + sizeof(dm->slot.v7);
 2565		tlv_v7 = kmalloc(len, GFP_KERNEL);
 2566		if (!tlv_v7)
 2567			return;
 2568
 2569		tlv_v7->type = SET_SLOT_TABLE;
 2570		tlv_v7->ver = ver->fcxslots;
 2571		tlv_v7->len = ARRAY_SIZE(dm->slot.v7);
 2572		memcpy(tlv_v7->val, dm->slot.v7, sizeof(dm->slot.v7));
 2573
 2574		_send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, (u8 *)tlv_v7, len);
 2575
 2576		kfree(tlv_v7);
 2577	} else {
 2578		n = struct_size(tbl, tbls, CXST_MAX);
 2579		tbl = kmalloc(n, GFP_KERNEL);
 2580		if (!tbl)
 2581			return;
 2582
 2583		tbl->fver = BTF_SET_SLOT_TABLE_VER;
 2584		tbl->tbl_num = CXST_MAX;
 2585		memcpy(tbl->tbls, dm->slot.v1, flex_array_size(tbl, tbls, CXST_MAX));
 2586
 2587		_send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, tbl, n);
 2588
 2589		kfree(tbl);
 2590	}
 2591}
 2592
 2593static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
 2594				u32 rpt_map, bool rpt_state)
 2595{
 2596	struct rtw89_btc *btc = &rtwdev->btc;
 2597	struct rtw89_btc_wl_smap *wl_smap = &btc->cx.wl.status.map;
 2598	struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo;
 2599	union rtw89_fbtc_rtp_ctrl r;
 2600	u32 val, bit_map;
 2601	int ret;
 2602
 2603	if ((wl_smap->rf_off || wl_smap->lps != BTC_LPS_OFF) && rpt_state != 0)
 2604		return;
 2605
 2606	bit_map = rtw89_btc_fw_rpt_ver(rtwdev, rpt_map);
 2607
 2608	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2609		    "[BTC], %s(): rpt_map=%x, rpt_state=%x\n",
 2610		    __func__, rpt_map, rpt_state);
 2611
 2612	if (rpt_state)
 2613		val = fwinfo->rpt_en_map | bit_map;
 2614	else
 2615		val = fwinfo->rpt_en_map & ~bit_map;
 2616
 2617	if (val == fwinfo->rpt_en_map)
 2618		return;
 2619
 2620	if (btc->ver->fcxbtcrpt == 7 || btc->ver->fcxbtcrpt == 8) {
 2621		r.v8.type = SET_REPORT_EN;
 2622		r.v8.fver = btc->ver->fcxbtcrpt;
 2623		r.v8.len = sizeof(r.v8.map);
 2624		r.v8.map = cpu_to_le32(val);
 2625		ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v8,
 2626				   sizeof(r.v8));
 2627	} else {
 2628		if (btc->ver->fcxbtcrpt == 105)
 2629			r.v1.fver = 5;
 2630		else
 2631			r.v1.fver = btc->ver->fcxbtcrpt;
 2632		r.v1.enable = cpu_to_le32(val);
 2633		r.v1.para = cpu_to_le32(rpt_state);
 2634		ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v1,
 2635				   sizeof(r.v1));
 2636	}
 2637
 2638	if (!ret)
 2639		fwinfo->rpt_en_map = val;
 2640}
 2641
 2642static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
 2643{
 2644	const struct rtw89_chip_info *chip = rtwdev->chip;
 2645	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
 2646	struct rtw89_btc_btf_set_mon_reg_v1 *v1 = NULL;
 2647	struct rtw89_btc_btf_set_mon_reg_v7 *v7 = NULL;
 2648	u8 i, n, ulen, cxmreg_max;
 2649	u16 sz = 0;
 2650
 2651	n = chip->mon_reg_num;
 2652	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2653		    "[BTC], %s(): mon_reg_num=%d\n", __func__, n);
 2654
 2655	if (ver->fcxmreg == 1)
 2656		cxmreg_max = CXMREG_MAX;
 2657	else
 2658		cxmreg_max = CXMREG_MAX_V2;
 2659
 2660	if (n > cxmreg_max) {
 2661		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2662			    "[BTC], %s(): mon reg count %d > %d\n",
 2663			    __func__, n, cxmreg_max);
 2664		return;
 2665	}
 2666
 2667	ulen = sizeof(struct rtw89_btc_fbtc_mreg);
 2668
 2669	if (ver->fcxmreg == 7) {
 2670		sz = struct_size(v7, regs, n);
 2671		v7 = kmalloc(sz, GFP_KERNEL);
 2672		if (!v7)
 2673			return;
 2674		v7->type = RPT_EN_MREG;
 2675		v7->fver = ver->fcxmreg;
 2676		v7->len = n;
 2677		for (i = 0; i < n; i++) {
 2678			v7->regs[i].type = chip->mon_reg[i].type;
 2679			v7->regs[i].bytes = chip->mon_reg[i].bytes;
 2680			v7->regs[i].offset = chip->mon_reg[i].offset;
 2681		}
 2682
 2683		_send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v7, sz);
 2684		kfree(v7);
 2685	} else {
 2686		sz = struct_size(v1, regs, n);
 2687		v1 = kmalloc(sz, GFP_KERNEL);
 2688		if (!v1)
 2689			return;
 2690		v1->fver = ver->fcxmreg;
 2691		v1->reg_num = n;
 2692		memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n));
 2693
 2694		_send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v1, sz);
 2695		kfree(v1);
 2696	}
 2697
 2698	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2699		    "[BTC], %s(): sz=%d ulen=%d n=%d\n",
 2700		    __func__, sz, ulen, n);
 2701
 2702	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
 2703}
 2704
 2705static void _update_dm_step(struct rtw89_dev *rtwdev,
 2706			    enum btc_reason_and_action reason_or_action)
 2707{
 2708	struct rtw89_btc *btc = &rtwdev->btc;
 2709	struct rtw89_btc_dm *dm = &btc->dm;
 2710
 2711	/* use ring-structure to store dm step */
 2712	dm->dm_step.step[dm->dm_step.step_pos] = reason_or_action;
 2713	dm->dm_step.step_pos++;
 2714
 2715	if (dm->dm_step.step_pos >= ARRAY_SIZE(dm->dm_step.step)) {
 2716		dm->dm_step.step_pos = 0;
 2717		dm->dm_step.step_ov = true;
 2718	}
 2719}
 2720
 2721static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
 2722			   enum btc_reason_and_action action)
 2723{
 2724	struct rtw89_btc *btc = &rtwdev->btc;
 2725	struct rtw89_btc_dm *dm = &btc->dm;
 2726	int ret;
 2727
 2728	dm->run_action = action;
 2729
 2730	_update_dm_step(rtwdev, action | BTC_ACT_EXT_BIT);
 2731	_update_dm_step(rtwdev, policy_type | BTC_POLICY_EXT_BIT);
 2732
 2733	btc->policy_len = 0;
 2734	btc->policy_type = policy_type;
 2735
 2736	_append_tdma(rtwdev);
 2737	_append_slot(rtwdev);
 2738
 2739	if (btc->policy_len == 0 || btc->policy_len > RTW89_BTC_POLICY_MAXLEN)
 2740		return;
 2741
 2742	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2743		    "[BTC], %s(): action = %d -> policy type/len: 0x%04x/%d\n",
 2744		    __func__, action, policy_type, btc->policy_len);
 2745
 2746	if (dm->tdma.rxflctrl == CXFLC_NULLP ||
 2747	    dm->tdma.rxflctrl == CXFLC_QOSNULL)
 2748		btc->lps = 1;
 2749	else
 2750		btc->lps = 0;
 2751
 2752	if (btc->lps == 1)
 2753		rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
 2754
 2755	ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
 2756			   btc->policy, btc->policy_len);
 2757	if (!ret) {
 2758		memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
 2759		if (btc->ver->fcxslots == 7)
 2760			memcpy(&dm->slot_now.v7, &dm->slot.v7, sizeof(dm->slot_now.v7));
 2761		else
 2762			memcpy(&dm->slot_now.v1, &dm->slot.v1, sizeof(dm->slot_now.v1));
 2763	}
 2764
 2765	if (btc->update_policy_force)
 2766		btc->update_policy_force = false;
 2767
 2768	if (btc->lps == 0)
 2769		rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
 2770}
 2771
 2772static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type)
 2773{
 2774	struct rtw89_btc *btc = &rtwdev->btc;
 2775	const struct rtw89_btc_ver *ver = btc->ver;
 2776	struct rtw89_btc_dm *dm = &btc->dm;
 2777	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 2778	struct rtw89_btc_rf_trx_para rf_para = dm->rf_trx_para;
 2779
 2780	switch (type) {
 2781	case CXDRVINFO_INIT:
 2782		if (ver->fcxinit == 7)
 2783			rtw89_fw_h2c_cxdrv_init_v7(rtwdev, type);
 2784		else
 2785			rtw89_fw_h2c_cxdrv_init(rtwdev, type);
 2786		break;
 2787	case CXDRVINFO_ROLE:
 2788		if (ver->fwlrole == 0)
 2789			rtw89_fw_h2c_cxdrv_role(rtwdev, type);
 2790		else if (ver->fwlrole == 1)
 2791			rtw89_fw_h2c_cxdrv_role_v1(rtwdev, type);
 2792		else if (ver->fwlrole == 2)
 2793			rtw89_fw_h2c_cxdrv_role_v2(rtwdev, type);
 2794		else if (ver->fwlrole == 7)
 2795			rtw89_fw_h2c_cxdrv_role_v7(rtwdev, type);
 2796		else if (ver->fwlrole == 8)
 2797			rtw89_fw_h2c_cxdrv_role_v8(rtwdev, type);
 2798		break;
 2799	case CXDRVINFO_CTRL:
 2800		if (ver->drvinfo_type == 1)
 2801			type = 2;
 2802
 2803		if (ver->fcxctrl == 7)
 2804			rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev, type);
 2805		else
 2806			rtw89_fw_h2c_cxdrv_ctrl(rtwdev, type);
 2807		break;
 2808	case CXDRVINFO_TRX:
 2809		if (ver->drvinfo_type == 1)
 2810			type = 3;
 2811
 2812		dm->trx_info.tx_power = u32_get_bits(rf_para.wl_tx_power,
 2813						     RTW89_BTC_WL_DEF_TX_PWR);
 2814		dm->trx_info.rx_gain = u32_get_bits(rf_para.wl_rx_gain,
 2815						    RTW89_BTC_WL_DEF_TX_PWR);
 2816		dm->trx_info.bt_tx_power = u32_get_bits(rf_para.bt_tx_power,
 2817							RTW89_BTC_WL_DEF_TX_PWR);
 2818		dm->trx_info.bt_rx_gain = u32_get_bits(rf_para.bt_rx_gain,
 2819						       RTW89_BTC_WL_DEF_TX_PWR);
 2820		dm->trx_info.cn = wl->cn_report;
 2821		dm->trx_info.nhm = wl->nhm.pwr;
 2822		rtw89_fw_h2c_cxdrv_trx(rtwdev, type);
 2823		break;
 2824	case CXDRVINFO_RFK:
 2825		if (ver->drvinfo_type == 1)
 2826			return;
 2827
 2828		rtw89_fw_h2c_cxdrv_rfk(rtwdev, type);
 2829		break;
 2830	case CXDRVINFO_TXPWR:
 2831	case CXDRVINFO_FDDT:
 2832	case CXDRVINFO_MLO:
 2833	case CXDRVINFO_OSI:
 2834		if (!ver->fcxosi)
 2835			return;
 2836
 2837		if (ver->drvinfo_type == 2)
 2838			type = 7;
 2839		else
 2840			return;
 2841
 2842		rtw89_fw_h2c_cxdrv_osi_info(rtwdev, type);
 2843		break;
 2844	default:
 2845		break;
 2846	}
 2847}
 2848
 2849static
 2850void btc_fw_event(struct rtw89_dev *rtwdev, u8 evt_id, void *data, u32 len)
 2851{
 2852	struct rtw89_btc *btc = &rtwdev->btc;
 2853	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 2854
 2855	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 2856		    "[BTC], %s(): evt_id:%d len:%d\n",
 2857		    __func__, evt_id, len);
 2858
 2859	if (!len || !data)
 2860		return;
 2861
 2862	switch (evt_id) {
 2863	case BTF_EVNT_RPT:
 2864		_parse_btc_report(rtwdev, pfwinfo, data, len);
 2865		break;
 2866	default:
 2867		break;
 2868	}
 2869}
 2870
 2871static void _set_gnt(struct rtw89_dev *rtwdev, u8 phy_map, u8 wl_state, u8 bt_state)
 2872{
 2873	struct rtw89_btc *btc = &rtwdev->btc;
 2874	struct rtw89_btc_dm *dm = &btc->dm;
 2875	struct rtw89_mac_ax_gnt *g = dm->gnt.band;
 2876	u8 i;
 2877
 2878	if (phy_map > BTC_PHY_ALL)
 2879		return;
 2880
 2881	for (i = 0; i < RTW89_PHY_NUM; i++) {
 2882		if (!(phy_map & BIT(i)))
 2883			continue;
 2884
 2885		switch (wl_state) {
 2886		case BTC_GNT_HW:
 2887			g[i].gnt_wl_sw_en = 0;
 2888			g[i].gnt_wl = 0;
 2889			break;
 2890		case BTC_GNT_SW_LO:
 2891			g[i].gnt_wl_sw_en = 1;
 2892			g[i].gnt_wl = 0;
 2893			break;
 2894		case BTC_GNT_SW_HI:
 2895			g[i].gnt_wl_sw_en = 1;
 2896			g[i].gnt_wl = 1;
 2897			break;
 2898		}
 2899
 2900		switch (bt_state) {
 2901		case BTC_GNT_HW:
 2902			g[i].gnt_bt_sw_en = 0;
 2903			g[i].gnt_bt = 0;
 2904			break;
 2905		case BTC_GNT_SW_LO:
 2906			g[i].gnt_bt_sw_en = 1;
 2907			g[i].gnt_bt = 0;
 2908			break;
 2909		case BTC_GNT_SW_HI:
 2910			g[i].gnt_bt_sw_en = 1;
 2911			g[i].gnt_bt = 1;
 2912			break;
 2913		}
 2914	}
 2915
 2916	rtw89_chip_mac_cfg_gnt(rtwdev, &dm->gnt);
 2917}
 2918
 2919static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map,
 2920			u8 wl_state, u8 bt_state, u8 wlact_state)
 2921{
 2922	struct rtw89_btc *btc = &rtwdev->btc;
 2923	struct rtw89_btc_dm *dm = &btc->dm;
 2924	struct rtw89_btc_fbtc_outsrc_set_info *osi = &dm->ost_info;
 2925	struct rtw89_mac_ax_wl_act *b = dm->gnt.bt;
 2926	struct rtw89_mac_ax_gnt *g = dm->gnt.band;
 2927	u8 i, bt_idx = dm->bt_select + 1;
 2928
 2929	if (phy_map > BTC_PHY_ALL)
 2930		return;
 2931
 2932	for (i = 0; i < RTW89_PHY_NUM; i++) {
 2933		if (!(phy_map & BIT(i)))
 2934			continue;
 2935
 2936		switch (wl_state) {
 2937		case BTC_GNT_HW:
 2938			g[i].gnt_wl_sw_en = 0;
 2939			g[i].gnt_wl = 0;
 2940			break;
 2941		case BTC_GNT_SW_LO:
 2942			g[i].gnt_wl_sw_en = 1;
 2943			g[i].gnt_wl = 0;
 2944			break;
 2945		case BTC_GNT_SW_HI:
 2946			g[i].gnt_wl_sw_en = 1;
 2947			g[i].gnt_wl = 1;
 2948			break;
 2949		}
 2950
 2951		switch (bt_state) {
 2952		case BTC_GNT_HW:
 2953			g[i].gnt_bt_sw_en = 0;
 2954			g[i].gnt_bt = 0;
 2955			break;
 2956		case BTC_GNT_SW_LO:
 2957			g[i].gnt_bt_sw_en = 1;
 2958			g[i].gnt_bt = 0;
 2959			break;
 2960		case BTC_GNT_SW_HI:
 2961			g[i].gnt_bt_sw_en = 1;
 2962			g[i].gnt_bt = 1;
 2963			break;
 2964		}
 2965	}
 2966
 2967	if (rtwdev->chip->para_ver & BTC_FEAT_WLAN_ACT_MUX) {
 2968		for (i = 0; i < 2; i++) {
 2969			if (!(bt_idx & BIT(i)))
 2970				continue;
 2971
 2972			switch (wlact_state) {
 2973			case BTC_WLACT_HW:
 2974				b[i].wlan_act_en = 0;
 2975				b[i].wlan_act = 0;
 2976				break;
 2977			case BTC_WLACT_SW_LO:
 2978				b[i].wlan_act_en = 1;
 2979				b[i].wlan_act = 0;
 2980				break;
 2981			case BTC_WLACT_SW_HI:
 2982				b[i].wlan_act_en = 1;
 2983				b[i].wlan_act = 1;
 2984				break;
 2985			}
 2986		}
 2987	}
 2988
 2989	if (!btc->ver->fcxosi) {
 2990		rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt);
 2991		return;
 2992	}
 2993
 2994	memcpy(osi->gnt_set, dm->gnt.band, sizeof(osi->gnt_set));
 2995	memcpy(osi->wlact_set, dm->gnt.bt, sizeof(osi->wlact_set));
 2996
 2997	/* GBT source should be GBT_S1 in 1+1 (HWB0:5G + HWB1:2G) case */
 2998	if (osi->rf_band[BTC_RF_S0] == 1 &&
 2999	    osi->rf_band[BTC_RF_S1] == 0)
 3000		osi->rf_gbt_source = BTC_RF_S1;
 3001	else
 3002		osi->rf_gbt_source = BTC_RF_S0;
 3003}
 3004
 3005#define BTC_TDMA_WLROLE_MAX 3
 3006
 3007static void _set_bt_ignore_wlan_act(struct rtw89_dev *rtwdev, u8 enable)
 3008{
 3009	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3010		    "[BTC], %s(): set bt %s wlan_act\n", __func__,
 3011		    enable ? "ignore" : "do not ignore");
 3012
 3013	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_IGNORE_WLAN_ACT, &enable, 1);
 3014}
 3015
 3016#define WL_TX_POWER_NO_BTC_CTRL	GENMASK(31, 0)
 3017#define WL_TX_POWER_ALL_TIME GENMASK(15, 0)
 3018#define WL_TX_POWER_WITH_BT GENMASK(31, 16)
 3019#define WL_TX_POWER_INT_PART GENMASK(8, 2)
 3020#define WL_TX_POWER_FRA_PART GENMASK(1, 0)
 3021#define B_BTC_WL_TX_POWER_SIGN BIT(7)
 3022#define B_TSSI_WL_TX_POWER_SIGN BIT(8)
 3023
 3024static void _set_wl_tx_power(struct rtw89_dev *rtwdev, u32 level)
 3025{
 3026	const struct rtw89_chip_info *chip = rtwdev->chip;
 3027	struct rtw89_btc *btc = &rtwdev->btc;
 3028	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3029	u32 pwr_val;
 3030
 3031	if (wl->rf_para.tx_pwr_freerun == level)
 3032		return;
 3033
 3034	wl->rf_para.tx_pwr_freerun = level;
 3035	btc->dm.rf_trx_para.wl_tx_power = level;
 3036
 3037	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3038		    "[BTC], %s(): level = %d\n",
 3039		    __func__, level);
 3040
 3041	if (level == RTW89_BTC_WL_DEF_TX_PWR) {
 3042		pwr_val = WL_TX_POWER_NO_BTC_CTRL;
 3043	} else { /* only apply "force tx power" */
 3044		pwr_val = FIELD_PREP(WL_TX_POWER_INT_PART, level);
 3045		if (pwr_val > RTW89_BTC_WL_DEF_TX_PWR)
 3046			pwr_val = RTW89_BTC_WL_DEF_TX_PWR;
 3047
 3048		if (level & B_BTC_WL_TX_POWER_SIGN)
 3049			pwr_val |= B_TSSI_WL_TX_POWER_SIGN;
 3050		pwr_val |= WL_TX_POWER_WITH_BT;
 3051	}
 3052
 3053	chip->ops->btc_set_wl_txpwr_ctrl(rtwdev, pwr_val);
 3054}
 3055
 3056static void _set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
 3057{
 3058	const struct rtw89_chip_info *chip = rtwdev->chip;
 3059	struct rtw89_btc *btc = &rtwdev->btc;
 3060	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3061
 3062	if (wl->rf_para.rx_gain_freerun == level)
 3063		return;
 3064
 3065	wl->rf_para.rx_gain_freerun = level;
 3066	btc->dm.rf_trx_para.wl_rx_gain = level;
 3067
 3068	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3069		    "[BTC], %s(): level = %d\n",
 3070		    __func__, level);
 3071
 3072	chip->ops->btc_set_wl_rx_gain(rtwdev, level);
 3073}
 3074
 3075static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level)
 3076{
 3077	struct rtw89_btc *btc = &rtwdev->btc;
 3078	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3079	int ret;
 3080	u8 buf;
 3081
 3082	if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0)
 3083		return;
 3084
 3085	if (bt->rf_para.tx_pwr_freerun == level)
 3086		return;
 3087
 3088	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3089		    "[BTC], %s(): level = %d\n",
 3090		    __func__, level);
 3091
 3092	buf = (s8)(-level);
 3093	ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1);
 3094	if (!ret) {
 3095		bt->rf_para.tx_pwr_freerun = level;
 3096		btc->dm.rf_trx_para.bt_tx_power = level;
 3097	}
 3098}
 3099
 3100#define BTC_BT_RX_NORMAL_LVL 7
 3101
 3102static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
 3103{
 3104	struct rtw89_btc *btc = &rtwdev->btc;
 3105	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3106
 3107	if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0)
 3108		return;
 3109
 3110	if ((bt->rf_para.rx_gain_freerun == level ||
 3111	     level > BTC_BT_RX_NORMAL_LVL) &&
 3112	    (!rtwdev->chip->scbd || bt->lna_constrain == level))
 3113		return;
 3114
 3115	bt->rf_para.rx_gain_freerun = level;
 3116	btc->dm.rf_trx_para.bt_rx_gain = level;
 3117
 3118	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3119		    "[BTC], %s(): level = %d\n",
 3120		    __func__, level);
 3121
 3122	if (level == BTC_BT_RX_NORMAL_LVL)
 3123		_write_scbd(rtwdev, BTC_WSCB_RXGAIN, false);
 3124	else
 3125		_write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
 3126
 3127	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, sizeof(level));
 3128}
 3129
 3130static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
 3131{
 3132	const struct rtw89_chip_info *chip = rtwdev->chip;
 3133	struct rtw89_btc *btc = &rtwdev->btc;
 3134	const struct rtw89_btc_ver *ver = btc->ver;
 3135	struct rtw89_btc_dm *dm = &btc->dm;
 3136	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3137	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3138	struct rtw89_btc_bt_link_info *b = &bt->link_info;
 3139	struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
 3140	struct rtw89_btc_rf_trx_para para;
 3141	u32 wl_stb_chg = 0;
 3142	u8 level_id = 0, link_mode = 0, i, dbcc_2g_phy = 0;
 3143
 3144	if (ver->fwlrole == 0) {
 3145		link_mode = wl->role_info.link_mode;
 3146		for (i = 0; i < RTW89_PHY_NUM; i++) {
 3147			if (wl->dbcc_info.real_band[i] == RTW89_BAND_2G)
 3148				dbcc_2g_phy = i;
 3149		}
 3150	} else if (ver->fwlrole == 1) {
 3151		link_mode = wl->role_info_v1.link_mode;
 3152		dbcc_2g_phy = wl->role_info_v1.dbcc_2g_phy;
 3153	} else if (ver->fwlrole == 2) {
 3154		link_mode = wl->role_info_v2.link_mode;
 3155		dbcc_2g_phy = wl->role_info_v2.dbcc_2g_phy;
 3156	}
 3157
 3158	/* decide trx_para_level */
 3159	if (btc->ant_type == BTC_ANT_SHARED) {
 3160		/* fix LNA2 + TIA gain not change by GNT_BT */
 3161		if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) ||
 3162		    dm->bt_only == 1)
 3163			dm->trx_para_level = 1; /* for better BT ACI issue */
 3164		else
 3165			dm->trx_para_level = 0;
 3166	} else { /* non-shared antenna  */
 3167		dm->trx_para_level = 5;
 3168		/* modify trx_para if WK 2.4G-STA-DL + bt link */
 3169		if (b->profile_cnt.now != 0 &&
 3170		    link_mode == BTC_WLINK_2G_STA &&
 3171		    wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */
 3172			if (wl->rssi_level == 4 && bt->rssi_level > 2)
 3173				dm->trx_para_level = 6;
 3174			else if (wl->rssi_level == 3 && bt->rssi_level > 3)
 3175				dm->trx_para_level = 7;
 3176		}
 3177	}
 3178
 3179	level_id = dm->trx_para_level;
 3180	if (level_id >= chip->rf_para_dlink_num ||
 3181	    level_id >= chip->rf_para_ulink_num) {
 3182		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3183			    "[BTC], %s(): invalid level_id: %d\n",
 3184			    __func__, level_id);
 3185		return;
 3186	}
 3187
 3188	if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
 3189		para = chip->rf_para_ulink[level_id];
 3190	else
 3191		para = chip->rf_para_dlink[level_id];
 3192
 3193	if (dm->fddt_train) {
 3194		_set_wl_rx_gain(rtwdev, 1);
 3195		_write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
 3196	} else {
 3197		_set_wl_tx_power(rtwdev, para.wl_tx_power);
 3198		_set_wl_rx_gain(rtwdev, para.wl_rx_gain);
 3199		_set_bt_tx_power(rtwdev, para.bt_tx_power);
 3200		_set_bt_rx_gain(rtwdev, para.bt_rx_gain);
 3201	}
 3202
 3203	if (!bt->enable.now || dm->wl_only || wl_smap->rf_off ||
 3204	    wl_smap->lps == BTC_LPS_RF_OFF ||
 3205	    link_mode == BTC_WLINK_5G ||
 3206	    link_mode == BTC_WLINK_NOLINK ||
 3207	    (rtwdev->dbcc_en && dbcc_2g_phy != RTW89_PHY_1))
 3208		wl_stb_chg = 0;
 3209	else
 3210		wl_stb_chg = 1;
 3211
 3212	if (wl_stb_chg != dm->wl_stb_chg) {
 3213		dm->wl_stb_chg = wl_stb_chg;
 3214		chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
 3215	}
 3216}
 3217
 3218static void _update_btc_state_map(struct rtw89_dev *rtwdev)
 3219{
 3220	struct rtw89_btc *btc = &rtwdev->btc;
 3221	struct rtw89_btc_cx *cx = &btc->cx;
 3222	struct rtw89_btc_wl_info *wl = &cx->wl;
 3223	struct rtw89_btc_bt_info *bt = &cx->bt;
 3224	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 3225
 3226	if (wl->status.map.connecting || wl->status.map._4way ||
 3227	    wl->status.map.roaming || wl->status.map.dbccing) {
 3228		cx->state_map = BTC_WLINKING;
 3229	} else if (wl->status.map.scan) { /* wl scan */
 3230		if (bt_linfo->status.map.inq_pag)
 3231			cx->state_map = BTC_WSCAN_BSCAN;
 3232		else
 3233			cx->state_map = BTC_WSCAN_BNOSCAN;
 3234	} else if (wl->status.map.busy) { /* only busy */
 3235		if (bt_linfo->status.map.inq_pag)
 3236			cx->state_map = BTC_WBUSY_BSCAN;
 3237		else
 3238			cx->state_map = BTC_WBUSY_BNOSCAN;
 3239	} else { /* wl idle */
 3240		cx->state_map = BTC_WIDLE;
 3241	}
 3242}
 3243
 3244static void _set_bt_afh_info_v0(struct rtw89_dev *rtwdev)
 3245{
 3246	const struct rtw89_chip_info *chip = rtwdev->chip;
 3247	struct rtw89_btc *btc = &rtwdev->btc;
 3248	const struct rtw89_btc_ver *ver = btc->ver;
 3249	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3250	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3251	struct rtw89_btc_bt_link_info *b = &bt->link_info;
 3252	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 3253	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 3254	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 3255	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 3256	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 3257	struct rtw89_btc_wl_active_role *r;
 3258	struct rtw89_btc_wl_active_role_v1 *r1;
 3259	struct rtw89_btc_wl_active_role_v2 *r2;
 3260	struct rtw89_btc_wl_active_role_v7 *r7;
 3261	struct rtw89_btc_wl_rlink *rlink;
 3262	u8 en = 0, i, ch = 0, bw = 0;
 3263	u8 mode, connect_cnt;
 3264
 3265	if (btc->manual_ctrl || wl->status.map.scan)
 3266		return;
 3267
 3268	if (ver->fwlrole == 0) {
 3269		mode = wl_rinfo->link_mode;
 3270		connect_cnt = wl_rinfo->connect_cnt;
 3271	} else if (ver->fwlrole == 1) {
 3272		mode = wl_rinfo_v1->link_mode;
 3273		connect_cnt = wl_rinfo_v1->connect_cnt;
 3274	} else if (ver->fwlrole == 2) {
 3275		mode = wl_rinfo_v2->link_mode;
 3276		connect_cnt = wl_rinfo_v2->connect_cnt;
 3277	} else if (ver->fwlrole == 7) {
 3278		mode = wl_rinfo_v7->link_mode;
 3279		connect_cnt = wl_rinfo_v7->connect_cnt;
 3280	} else if (ver->fwlrole == 8) {
 3281		mode = wl_rinfo_v8->link_mode;
 3282		connect_cnt = wl_rinfo_v8->connect_cnt;
 3283	} else {
 3284		return;
 3285	}
 3286
 3287	if (wl->status.map.rf_off || bt->whql_test ||
 3288	    mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_5G ||
 3289	    connect_cnt > BTC_TDMA_WLROLE_MAX) {
 3290		en = false;
 3291	} else if (mode == BTC_WLINK_2G_MCC || mode == BTC_WLINK_2G_SCC) {
 3292		en = true;
 3293		/* get p2p channel */
 3294		for (i = 0; i < RTW89_PORT_NUM; i++) {
 3295			r = &wl_rinfo->active_role[i];
 3296			r1 = &wl_rinfo_v1->active_role_v1[i];
 3297			r2 = &wl_rinfo_v2->active_role_v2[i];
 3298			r7 = &wl_rinfo_v7->active_role[i];
 3299			rlink = &wl_rinfo_v8->rlink[i][0];
 3300
 3301			if (ver->fwlrole == 0 &&
 3302			    (r->role == RTW89_WIFI_ROLE_P2P_GO ||
 3303			     r->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3304				ch = r->ch;
 3305				bw = r->bw;
 3306				break;
 3307			} else if (ver->fwlrole == 1 &&
 3308				   (r1->role == RTW89_WIFI_ROLE_P2P_GO ||
 3309				    r1->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3310				ch = r1->ch;
 3311				bw = r1->bw;
 3312				break;
 3313			} else if (ver->fwlrole == 2 &&
 3314				   (r2->role == RTW89_WIFI_ROLE_P2P_GO ||
 3315				    r2->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3316				ch = r2->ch;
 3317				bw = r2->bw;
 3318				break;
 3319			} else if (ver->fwlrole == 7 &&
 3320				   (r7->role == RTW89_WIFI_ROLE_P2P_GO ||
 3321				    r7->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3322				ch = r7->ch;
 3323				bw = r7->bw;
 3324				break;
 3325			} else if (ver->fwlrole == 8 &&
 3326				   (rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
 3327				    rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3328				ch = rlink->ch;
 3329				bw = rlink->bw;
 3330				break;
 3331			}
 3332		}
 3333	} else {
 3334		en = true;
 3335		/* get 2g channel  */
 3336		for (i = 0; i < RTW89_PORT_NUM; i++) {
 3337			r = &wl_rinfo->active_role[i];
 3338			r1 = &wl_rinfo_v1->active_role_v1[i];
 3339			r2 = &wl_rinfo_v2->active_role_v2[i];
 3340			r7 = &wl_rinfo_v7->active_role[i];
 3341			rlink = &wl_rinfo_v8->rlink[i][0];
 3342
 3343			if (ver->fwlrole == 0 &&
 3344			    r->connected && r->band == RTW89_BAND_2G) {
 3345				ch = r->ch;
 3346				bw = r->bw;
 3347				break;
 3348			} else if (ver->fwlrole == 1 &&
 3349				   r1->connected && r1->band == RTW89_BAND_2G) {
 3350				ch = r1->ch;
 3351				bw = r1->bw;
 3352				break;
 3353			} else if (ver->fwlrole == 2 &&
 3354				   r2->connected && r2->band == RTW89_BAND_2G) {
 3355				ch = r2->ch;
 3356				bw = r2->bw;
 3357				break;
 3358			} else if (ver->fwlrole == 7 &&
 3359				   r7->connected && r7->band == RTW89_BAND_2G) {
 3360				ch = r7->ch;
 3361				bw = r7->bw;
 3362				break;
 3363			} else if (ver->fwlrole == 8 &&
 3364				   rlink->connected && rlink->rf_band == RTW89_BAND_2G) {
 3365				ch = rlink->ch;
 3366				bw = rlink->bw;
 3367				break;
 3368			}
 3369		}
 3370	}
 3371
 3372	switch (bw) {
 3373	case RTW89_CHANNEL_WIDTH_20:
 3374		bw = 20 + chip->afh_guard_ch * 2;
 3375		break;
 3376	case RTW89_CHANNEL_WIDTH_40:
 3377		bw = 40 + chip->afh_guard_ch * 2;
 3378		break;
 3379	case RTW89_CHANNEL_WIDTH_5:
 3380		bw = 5 + chip->afh_guard_ch * 2;
 3381		break;
 3382	case RTW89_CHANNEL_WIDTH_10:
 3383		bw = 10 + chip->afh_guard_ch * 2;
 3384		break;
 3385	default:
 3386		bw = 0;
 3387		en = false; /* turn off AFH info if BW > 40 */
 3388		break;
 3389	}
 3390
 3391	if (wl->afh_info.en == en &&
 3392	    wl->afh_info.ch == ch &&
 3393	    wl->afh_info.bw == bw &&
 3394	    b->profile_cnt.last == b->profile_cnt.now) {
 3395		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3396			    "[BTC], %s(): return because no change!\n",
 3397			    __func__);
 3398		return;
 3399	}
 3400
 3401	wl->afh_info.en = en;
 3402	wl->afh_info.ch = ch;
 3403	wl->afh_info.bw = bw;
 3404
 3405	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3);
 3406
 3407	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3408		    "[BTC], %s(): en=%d, ch=%d, bw=%d\n",
 3409		    __func__, en, ch, bw);
 3410	btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++;
 3411}
 3412
 3413static void _set_bt_afh_info_v1(struct rtw89_dev *rtwdev)
 3414{
 3415	const struct rtw89_chip_info *chip = rtwdev->chip;
 3416	struct rtw89_btc *btc = &rtwdev->btc;
 3417	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3418	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 3419	struct rtw89_btc_wl_afh_info *wl_afh = &wl->afh_info;
 3420	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3421	struct rtw89_btc_wl_rlink *rlink;
 3422	u8 en = 0, ch = 0, bw = 0, buf[3] = {};
 3423	u8 i, j, link_mode;
 3424
 3425	if (btc->manual_ctrl || wl->status.map.scan)
 3426		return;
 3427
 3428	link_mode = wl_rinfo->link_mode;
 3429
 3430	for (i = 0; i < btc->ver->max_role_num; i++) {
 3431		for (j = RTW89_MAC_0; j < RTW89_MAC_NUM; j++) {
 3432			if (wl->status.map.rf_off || bt->whql_test ||
 3433			    link_mode == BTC_WLINK_NOLINK ||
 3434			    link_mode == BTC_WLINK_5G)
 3435				break;
 3436
 3437			rlink = &wl_rinfo->rlink[i][j];
 3438
 3439			/* Don't care no-connected/non-2G-band role */
 3440			if (!rlink->connected || !rlink->active ||
 3441			    rlink->rf_band != RTW89_BAND_2G)
 3442				continue;
 3443
 3444			en = 1;
 3445			ch = rlink->ch;
 3446			bw = rlink->bw;
 3447
 3448			if (link_mode == BTC_WLINK_2G_MCC &&
 3449			    (rlink->role == RTW89_WIFI_ROLE_AP ||
 3450			     rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
 3451			     rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
 3452				/* for 2.4G MCC, take role = ap/go/gc */
 3453				break;
 3454			} else if (link_mode != BTC_WLINK_2G_SCC ||
 3455				   rlink->bw == RTW89_CHANNEL_WIDTH_40) {
 3456				/* for 2.4G scc, take bw = 40M */
 3457				break;
 3458			}
 3459		}
 3460	}
 3461
 3462	/* default AFH channel sapn = center-ch +- 6MHz */
 3463	switch (bw) {
 3464	case RTW89_CHANNEL_WIDTH_20:
 3465		if (btc->dm.freerun || btc->dm.fddt_train)
 3466			bw = 48;
 3467		else
 3468			bw = 20 + chip->afh_guard_ch * 2;
 3469		break;
 3470	case RTW89_CHANNEL_WIDTH_40:
 3471		if (btc->dm.freerun)
 3472			bw = 40 + chip->afh_guard_ch * 2;
 3473		else
 3474			bw = 40;
 3475		break;
 3476	case RTW89_CHANNEL_WIDTH_5:
 3477		bw = 5 + chip->afh_guard_ch * 2;
 3478		break;
 3479	case RTW89_CHANNEL_WIDTH_10:
 3480		bw = 10 + chip->afh_guard_ch * 2;
 3481		break;
 3482	default:
 3483		en = false; /* turn off AFH info if invalid BW */
 3484		bw = 0;
 3485		ch = 0;
 3486		break;
 3487	}
 3488
 3489	if (!en || ch > 14 || ch == 0) {
 3490		en = false;
 3491		bw = 0;
 3492		ch = 0;
 3493	}
 3494
 3495	if (wl_afh->en == en &&
 3496	    wl_afh->ch == ch &&
 3497	    wl_afh->bw == bw &&
 3498	    (!bt->enable.now || bt->enable.last))
 3499		return;
 3500
 3501	wl_afh->en = buf[0];
 3502	wl_afh->ch = buf[1];
 3503	wl_afh->bw = buf[2];
 3504
 3505	if (_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3)) {
 3506		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 3507			    "[BTC], %s(): en=%d, ch=%d, bw=%d\n",
 3508			    __func__, en, ch, bw);
 3509
 3510		btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++;
 3511	}
 3512}
 3513
 3514static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
 3515{
 3516	if (rtwdev->chip->chip_id == RTL8922A)
 3517		_set_bt_afh_info_v1(rtwdev);
 3518	else
 3519		_set_bt_afh_info_v0(rtwdev);
 3520}
 3521
 3522static bool _check_freerun(struct rtw89_dev *rtwdev)
 3523{
 3524	struct rtw89_btc *btc = &rtwdev->btc;
 3525	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 3526	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 3527	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 3528	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 3529	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 3530	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 3531	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 3532	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 3533	struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
 3534	union rtw89_btc_module_info *md = &btc->mdinfo;
 3535	const struct rtw89_btc_ver *ver = btc->ver;
 3536	u8 isolation, connect_cnt = 0;
 3537
 3538	if (ver->fcxinit == 7)
 3539		isolation = md->md_v7.ant.isolation;
 3540	else
 3541		isolation = md->md.ant.isolation;
 3542
 3543	if (ver->fwlrole == 0)
 3544		connect_cnt = wl_rinfo->connect_cnt;
 3545	else if (ver->fwlrole == 1)
 3546		connect_cnt = wl_rinfo_v1->connect_cnt;
 3547	else if (ver->fwlrole == 2)
 3548		connect_cnt = wl_rinfo_v2->connect_cnt;
 3549	else if (ver->fwlrole == 7)
 3550		connect_cnt = wl_rinfo_v7->connect_cnt;
 3551	else if (ver->fwlrole == 8)
 3552		connect_cnt = wl_rinfo_v8->connect_cnt;
 3553
 3554	if (btc->ant_type == BTC_ANT_SHARED) {
 3555		btc->dm.trx_para_level = 0;
 3556		return false;
 3557	}
 3558
 3559	/* The below is dedicated antenna case */
 3560	if (connect_cnt > BTC_TDMA_WLROLE_MAX) {
 3561		btc->dm.trx_para_level = 5;
 3562		return true;
 3563	}
 3564
 3565	if (bt_linfo->profile_cnt.now == 0) {
 3566		btc->dm.trx_para_level = 5;
 3567		return true;
 3568	}
 3569
 3570	if (hid->pair_cnt > BTC_TDMA_BTHID_MAX) {
 3571		btc->dm.trx_para_level = 5;
 3572		return true;
 3573	}
 3574
 3575	/* TODO get isolation by BT psd */
 3576	if (isolation >= BTC_FREERUN_ANTISO_MIN) {
 3577		btc->dm.trx_para_level = 5;
 3578		return true;
 3579	}
 3580
 3581	if (!wl->status.map.busy) {/* wl idle -> freerun */
 3582		btc->dm.trx_para_level = 5;
 3583		return true;
 3584	} else if (wl->rssi_level > 1) {/* WL rssi < 50% (-60dBm) */
 3585		btc->dm.trx_para_level = 0;
 3586		return false;
 3587	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
 3588		if (wl->rssi_level == 0 && bt_linfo->rssi > 31) {
 3589			btc->dm.trx_para_level = 6;
 3590			return true;
 3591		} else if (wl->rssi_level == 1 && bt_linfo->rssi > 36) {
 3592			btc->dm.trx_para_level = 7;
 3593			return true;
 3594		}
 3595		btc->dm.trx_para_level = 0;
 3596		return false;
 3597	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) {
 3598		if (bt_linfo->rssi > 28) {
 3599			btc->dm.trx_para_level = 6;
 3600			return true;
 3601		}
 3602	}
 3603
 3604	btc->dm.trx_para_level = 0;
 3605	return false;
 3606}
 3607
 3608#define _tdma_set_flctrl(btc, flc) ({(btc)->dm.tdma.rxflctrl = flc; })
 3609#define _tdma_set_flctrl_role(btc, role) ({(btc)->dm.tdma.rxflctrl_role = role; })
 3610#define _tdma_set_tog(btc, wtg) ({(btc)->dm.tdma.wtgle_n = wtg; })
 3611#define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
 3612
 3613struct btc_btinfo_lb2 {
 3614	u8 connect: 1;
 3615	u8 sco_busy: 1;
 3616	u8 inq_pag: 1;
 3617	u8 acl_busy: 1;
 3618	u8 hfp: 1;
 3619	u8 hid: 1;
 3620	u8 a2dp: 1;
 3621	u8 pan: 1;
 3622};
 3623
 3624struct btc_btinfo_lb3 {
 3625	u8 retry: 4;
 3626	u8 cqddr: 1;
 3627	u8 inq: 1;
 3628	u8 mesh_busy: 1;
 3629	u8 pag: 1;
 3630};
 3631
 3632struct btc_btinfo_hb0 {
 3633	s8 rssi;
 3634};
 3635
 3636struct btc_btinfo_hb1 {
 3637	u8 ble_connect: 1;
 3638	u8 reinit: 1;
 3639	u8 relink: 1;
 3640	u8 igno_wl: 1;
 3641	u8 voice: 1;
 3642	u8 ble_scan: 1;
 3643	u8 role_sw: 1;
 3644	u8 multi_link: 1;
 3645};
 3646
 3647struct btc_btinfo_hb2 {
 3648	u8 pan_active: 1;
 3649	u8 afh_update: 1;
 3650	u8 a2dp_active: 1;
 3651	u8 slave: 1;
 3652	u8 hid_slot: 2;
 3653	u8 hid_cnt: 2;
 3654};
 3655
 3656struct btc_btinfo_hb3 {
 3657	u8 a2dp_bitpool: 6;
 3658	u8 tx_3m: 1;
 3659	u8 a2dp_sink: 1;
 3660};
 3661
 3662union btc_btinfo {
 3663	u8 val;
 3664	struct btc_btinfo_lb2 lb2;
 3665	struct btc_btinfo_lb3 lb3;
 3666	struct btc_btinfo_hb0 hb0;
 3667	struct btc_btinfo_hb1 hb1;
 3668	struct btc_btinfo_hb2 hb2;
 3669	struct btc_btinfo_hb3 hb3;
 3670};
 3671
 3672static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
 3673			enum btc_reason_and_action action)
 3674{
 3675	const struct rtw89_chip_info *chip = rtwdev->chip;
 3676
 3677	chip->ops->btc_set_policy(rtwdev, policy_type);
 3678	_fw_set_policy(rtwdev, policy_type, action);
 3679}
 3680
 3681#define BTC_B1_MAX 250 /* unit ms */
 3682void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
 3683{
 3684	struct rtw89_btc *btc = &rtwdev->btc;
 3685	struct rtw89_btc_dm *dm = &btc->dm;
 3686	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
 3687	struct rtw89_btc_fbtc_slot *s = dm->slot.v1;
 3688	u8 type;
 3689	u32 tbl_w1, tbl_b1, tbl_b4;
 3690
 3691	if (btc->ant_type == BTC_ANT_SHARED) {
 3692		if (btc->cx.wl.status.map._4way)
 3693			tbl_w1 = cxtbl[1];
 3694		else
 3695			tbl_w1 = cxtbl[8];
 3696		tbl_b1 = cxtbl[3];
 3697		tbl_b4 = cxtbl[3];
 3698	} else {
 3699		tbl_w1 = cxtbl[16];
 3700		tbl_b1 = cxtbl[17];
 3701		tbl_b4 = cxtbl[17];
 3702	}
 3703
 3704	type = (u8)((policy_type & BTC_CXP_MASK) >> 8);
 3705	btc->bt_req_en = false;
 3706
 3707	switch (type) {
 3708	case BTC_CXP_USERDEF0:
 3709		*t = t_def[CXTD_OFF];
 3710		s[CXST_OFF] = s_def[CXST_OFF];
 3711		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
 3712		btc->update_policy_force = true;
 3713		break;
 3714	case BTC_CXP_OFF: /* TDMA off */
 3715		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
 3716		*t = t_def[CXTD_OFF];
 3717		s[CXST_OFF] = s_def[CXST_OFF];
 3718
 3719		switch (policy_type) {
 3720		case BTC_CXP_OFF_BT:
 3721			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
 3722			break;
 3723		case BTC_CXP_OFF_WL:
 3724			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
 3725			break;
 3726		case BTC_CXP_OFF_EQ0:
 3727			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
 3728			break;
 3729		case BTC_CXP_OFF_EQ1:
 3730			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
 3731			break;
 3732		case BTC_CXP_OFF_EQ2:
 3733			_slot_set_tbl(btc, CXST_OFF, cxtbl[17]);
 3734			break;
 3735		case BTC_CXP_OFF_EQ3:
 3736			_slot_set_tbl(btc, CXST_OFF, cxtbl[18]);
 3737			break;
 3738		case BTC_CXP_OFF_BWB0:
 3739			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
 3740			break;
 3741		case BTC_CXP_OFF_BWB1:
 3742			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
 3743			break;
 3744		case BTC_CXP_OFF_BWB3:
 3745			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
 3746			break;
 3747		}
 3748		break;
 3749	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
 3750		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
 3751		*t = t_def[CXTD_OFF_B2];
 3752		s[CXST_OFF] = s_def[CXST_OFF];
 3753		switch (policy_type) {
 3754		case BTC_CXP_OFFB_BWB0:
 3755			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
 3756			break;
 3757		}
 3758		break;
 3759	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
 3760		btc->bt_req_en = true;
 3761		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3762		*t = t_def[CXTD_OFF_EXT];
 3763		switch (policy_type) {
 3764		case BTC_CXP_OFFE_DEF:
 3765			s[CXST_E2G] = s_def[CXST_E2G];
 3766			s[CXST_E5G] = s_def[CXST_E5G];
 3767			s[CXST_EBT] = s_def[CXST_EBT];
 3768			s[CXST_ENULL] = s_def[CXST_ENULL];
 3769			break;
 3770		case BTC_CXP_OFFE_DEF2:
 3771			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
 3772			s[CXST_E5G] = s_def[CXST_E5G];
 3773			s[CXST_EBT] = s_def[CXST_EBT];
 3774			s[CXST_ENULL] = s_def[CXST_ENULL];
 3775			break;
 3776		}
 3777		break;
 3778	case BTC_CXP_FIX: /* TDMA Fix-Slot */
 3779		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3780		*t = t_def[CXTD_FIX];
 3781		switch (policy_type) {
 3782		case BTC_CXP_FIX_TD3030:
 3783			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3784			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 3785			break;
 3786		case BTC_CXP_FIX_TD5050:
 3787			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3788			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
 3789			break;
 3790		case BTC_CXP_FIX_TD2030:
 3791			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3792			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 3793			break;
 3794		case BTC_CXP_FIX_TD4010:
 3795			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
 3796			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 3797			break;
 3798		case BTC_CXP_FIX_TD4010ISO:
 3799			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
 3800			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 3801			break;
 3802		case BTC_CXP_FIX_TD4010ISO_DL:
 3803			_slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
 3804			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
 3805			break;
 3806		case BTC_CXP_FIX_TD4010ISO_UL:
 3807			_slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
 3808			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
 3809			break;
 3810		case BTC_CXP_FIX_TD7010:
 3811			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
 3812			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 3813			break;
 3814		case BTC_CXP_FIX_TD2060:
 3815			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3816			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 3817			break;
 3818		case BTC_CXP_FIX_TD3060:
 3819			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3820			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 3821			break;
 3822		case BTC_CXP_FIX_TD2080:
 3823			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3824			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
 3825			break;
 3826		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
 3827			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 3828				  tbl_w1, SLOT_ISO);
 3829			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 3830				  tbl_b1, SLOT_MIX);
 3831			break;
 3832		}
 3833		break;
 3834	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
 3835		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3836		*t = t_def[CXTD_PFIX];
 3837		if (btc->cx.wl.role_info.role_map.role.ap)
 3838			_tdma_set_flctrl(btc, CXFLC_QOSNULL);
 3839
 3840		switch (policy_type) {
 3841		case BTC_CXP_PFIX_TD3030:
 3842			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3843			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 3844			break;
 3845		case BTC_CXP_PFIX_TD5050:
 3846			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3847			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
 3848			break;
 3849		case BTC_CXP_PFIX_TD2030:
 3850			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3851			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 3852			break;
 3853		case BTC_CXP_PFIX_TD2060:
 3854			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3855			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 3856			break;
 3857		case BTC_CXP_PFIX_TD3070:
 3858			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3859			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 3860			break;
 3861		case BTC_CXP_PFIX_TD2080:
 3862			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3863			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
 3864			break;
 3865		}
 3866		break;
 3867	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
 3868		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3869		*t = t_def[CXTD_AUTO];
 3870		switch (policy_type) {
 3871		case BTC_CXP_AUTO_TD50B1:
 3872			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3873			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3874			break;
 3875		case BTC_CXP_AUTO_TD60B1:
 3876			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
 3877			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3878			break;
 3879		case BTC_CXP_AUTO_TD20B1:
 3880			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3881			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3882			break;
 3883		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
 3884			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 3885				  tbl_w1, SLOT_ISO);
 3886			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 3887				  tbl_b1, SLOT_MIX);
 3888			break;
 3889		}
 3890		break;
 3891	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
 3892		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3893		*t = t_def[CXTD_PAUTO];
 3894		switch (policy_type) {
 3895		case BTC_CXP_PAUTO_TD50B1:
 3896			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3897			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3898			break;
 3899		case BTC_CXP_PAUTO_TD60B1:
 3900			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
 3901			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3902			break;
 3903		case BTC_CXP_PAUTO_TD20B1:
 3904			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3905			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3906			break;
 3907		case BTC_CXP_PAUTO_TDW1B1:
 3908			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 3909				  tbl_w1, SLOT_ISO);
 3910			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 3911				  tbl_b1, SLOT_MIX);
 3912			break;
 3913		}
 3914		break;
 3915	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
 3916		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3917		*t = t_def[CXTD_AUTO2];
 3918		switch (policy_type) {
 3919		case BTC_CXP_AUTO2_TD3050:
 3920			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3921			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
 3922			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3923			break;
 3924		case BTC_CXP_AUTO2_TD3070:
 3925			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3926			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
 3927			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3928			break;
 3929		case BTC_CXP_AUTO2_TD5050:
 3930			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3931			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
 3932			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3933			break;
 3934		case BTC_CXP_AUTO2_TD6060:
 3935			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
 3936			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
 3937			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3938			break;
 3939		case BTC_CXP_AUTO2_TD2080:
 3940			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3941			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
 3942			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3943			break;
 3944		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
 3945			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 3946				  tbl_w1, SLOT_ISO);
 3947			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
 3948				  tbl_b4, SLOT_MIX);
 3949			break;
 3950		}
 3951		break;
 3952	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
 3953		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 3954		*t = t_def[CXTD_PAUTO2];
 3955		switch (policy_type) {
 3956		case BTC_CXP_PAUTO2_TD3050:
 3957			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3958			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
 3959			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3960			break;
 3961		case BTC_CXP_PAUTO2_TD3070:
 3962			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 3963			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
 3964			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3965			break;
 3966		case BTC_CXP_PAUTO2_TD5050:
 3967			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 3968			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
 3969			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3970			break;
 3971		case BTC_CXP_PAUTO2_TD6060:
 3972			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
 3973			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
 3974			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3975			break;
 3976		case BTC_CXP_PAUTO2_TD2080:
 3977			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 3978			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
 3979			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 3980			break;
 3981		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
 3982			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 3983				  tbl_w1, SLOT_ISO);
 3984			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
 3985				  tbl_b4, SLOT_MIX);
 3986			break;
 3987		}
 3988		break;
 3989	}
 3990}
 3991EXPORT_SYMBOL(rtw89_btc_set_policy);
 3992
 3993void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
 3994{
 3995	struct rtw89_btc *btc = &rtwdev->btc;
 3996	struct rtw89_btc_dm *dm = &btc->dm;
 3997	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
 3998	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1;
 3999	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
 4000	struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc;
 4001	struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc;
 4002	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4003	u8 type, null_role;
 4004	u32 tbl_w1, tbl_b1, tbl_b4;
 4005	u16 dur_2;
 4006
 4007	if (wl->status.map.lps) {
 4008		_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
 4009			     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
 4010		_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
 4011			     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
 4012		_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
 4013			     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4014	}
 4015
 4016	type = FIELD_GET(BTC_CXP_MASK, policy_type);
 4017
 4018	if (btc->ant_type == BTC_ANT_SHARED) {
 4019		if (btc->cx.wl.status.map._4way)
 4020			tbl_w1 = cxtbl[1];
 4021		else if (hid->exist && hid->type == BTC_HID_218)
 4022			tbl_w1 = cxtbl[7]; /* Ack/BA no break bt Hi-Pri-rx */
 4023		else
 4024			tbl_w1 = cxtbl[8];
 4025
 4026		if (dm->leak_ap &&
 4027		    (type == BTC_CXP_PFIX || type == BTC_CXP_PAUTO2)) {
 4028			tbl_b1 = cxtbl[3];
 4029			tbl_b4 = cxtbl[3];
 4030		} else if (hid->exist && hid->type == BTC_HID_218) {
 4031			tbl_b1 = cxtbl[4]; /* Ack/BA no break bt Hi-Pri-rx */
 4032			tbl_b4 = cxtbl[4];
 4033		} else {
 4034			tbl_b1 = cxtbl[2];
 4035			tbl_b4 = cxtbl[2];
 4036		}
 4037	} else {
 4038		tbl_b1 = cxtbl[17];
 4039		tbl_b4 = cxtbl[17];
 4040
 4041		if (wl->bg_mode)
 4042			tbl_w1 = cxtbl[8];
 4043		else if ((wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) &&
 4044			 hid->exist)
 4045			tbl_w1 = cxtbl[19];
 4046		else
 4047			tbl_w1 = cxtbl[16];
 4048	}
 4049
 4050	switch (type) {
 4051	case BTC_CXP_USERDEF0:
 4052		btc->update_policy_force = true;
 4053		*t = t_def[CXTD_OFF];
 4054		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
 4055			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 4056		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
 4057		break;
 4058	case BTC_CXP_OFF: /* TDMA off */
 4059		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
 4060		*t = t_def[CXTD_OFF];
 4061		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
 4062			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 4063
 4064		switch (policy_type) {
 4065		case BTC_CXP_OFF_BT:
 4066			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
 4067			break;
 4068		case BTC_CXP_OFF_WL:
 4069			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
 4070			break;
 4071		case BTC_CXP_OFF_WL2:
 4072			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
 4073			_slot_set_type(btc, CXST_OFF, SLOT_ISO);
 4074			break;
 4075		case BTC_CXP_OFF_EQ0:
 4076			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
 4077			_slot_set_type(btc, CXST_OFF, SLOT_ISO);
 4078			break;
 4079		case BTC_CXP_OFF_EQ1:
 4080			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
 4081			break;
 4082		case BTC_CXP_OFF_EQ2:
 4083			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
 4084			break;
 4085		case BTC_CXP_OFF_EQ3:
 4086			_slot_set_tbl(btc, CXST_OFF, cxtbl[24]);
 4087			break;
 4088		case BTC_CXP_OFF_EQ4:
 4089			_slot_set_tbl(btc, CXST_OFF, cxtbl[26]);
 4090			break;
 4091		case BTC_CXP_OFF_EQ5:
 4092			_slot_set_tbl(btc, CXST_OFF, cxtbl[27]);
 4093			break;
 4094		case BTC_CXP_OFF_BWB0:
 4095			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
 4096			break;
 4097		case BTC_CXP_OFF_BWB1:
 4098			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
 4099			break;
 4100		case BTC_CXP_OFF_BWB2:
 4101			_slot_set_tbl(btc, CXST_OFF, cxtbl[7]);
 4102			break;
 4103		case BTC_CXP_OFF_BWB3:
 4104			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
 4105			break;
 4106		default:
 4107			break;
 4108		}
 4109		break;
 4110	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
 4111		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
 4112		*t = t_def[CXTD_OFF_B2];
 4113		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
 4114			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 4115
 4116		switch (policy_type) {
 4117		case BTC_CXP_OFFB_BWB0:
 4118			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
 4119			break;
 4120		default:
 4121			break;
 4122		}
 4123		break;
 4124	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
 4125		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4126		*t = t_def[CXTD_OFF_EXT];
 4127
 4128		/* To avoid wl-s0 tx break by hid/hfp tx */
 4129		if (hid->exist || hfp->exist)
 4130			tbl_w1 = cxtbl[16];
 4131
 4132		dur_2 = dm->e2g_slot_limit;
 4133
 4134		switch (policy_type) {
 4135		case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */
 4136			_slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_ISO);
 4137			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
 4138				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4139			_slot_set_dur(btc, CXST_EBT, dur_2);
 4140			break;
 4141		case BTC_CXP_OFFE_2GISOB: /* for bt no-link */
 4142			_slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_ISO);
 4143			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
 4144				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4145			_slot_set_dur(btc, CXST_EBT, dur_2);
 4146			break;
 4147		case BTC_CXP_OFFE_DEF:
 4148			_slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
 4149				     s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
 4150			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
 4151				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
 4152			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
 4153				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4154			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
 4155				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
 4156			_slot_set_dur(btc, CXST_EBT, dur_2);
 4157			break;
 4158		case BTC_CXP_OFFE_DEF2:
 4159			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
 4160			_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
 4161				     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
 4162			_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
 4163				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4164			_slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
 4165				     s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
 4166			_slot_set_dur(btc, CXST_EBT, dur_2);
 4167			break;
 4168		case BTC_CXP_OFFE_2GBWMIXB:
 4169			if (a2dp->exist)
 4170				_slot_set(btc, CXST_E2G, 5, cxtbl[2], SLOT_MIX);
 4171			else
 4172				_slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX);
 4173			_slot_set_le(btc, CXST_EBT, cpu_to_le16(40),
 4174				     s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
 4175			_slot_set_dur(btc, CXST_EBT, dur_2);
 4176			break;
 4177		case BTC_CXP_OFFE_WL: /* for 4-way */
 4178			_slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_MIX);
 4179			_slot_set(btc, CXST_EBT, 5, cxtbl[1], SLOT_MIX);
 4180			break;
 4181		default:
 4182			break;
 4183		}
 4184		_slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
 4185			     s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
 4186		_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
 4187			     s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
 4188		break;
 4189	case BTC_CXP_FIX: /* TDMA Fix-Slot */
 4190		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4191		*t = t_def[CXTD_FIX];
 4192
 4193		switch (policy_type) {
 4194		case BTC_CXP_FIX_TD3030:
 4195			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 4196			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 4197			break;
 4198		case BTC_CXP_FIX_TD5050:
 4199			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 4200			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
 4201			break;
 4202		case BTC_CXP_FIX_TD2030:
 4203			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4204			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 4205			break;
 4206		case BTC_CXP_FIX_TD4010:
 4207			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
 4208			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 4209			break;
 4210		case BTC_CXP_FIX_TD4010ISO:
 4211			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
 4212			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 4213			break;
 4214		case BTC_CXP_FIX_TD4010ISO_DL:
 4215			_slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
 4216			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
 4217			break;
 4218		case BTC_CXP_FIX_TD4010ISO_UL:
 4219			_slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
 4220			_slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
 4221			break;
 4222		case BTC_CXP_FIX_TD7010:
 4223			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
 4224			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
 4225			break;
 4226		case BTC_CXP_FIX_TD2060:
 4227			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4228			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 4229			break;
 4230		case BTC_CXP_FIX_TD3060:
 4231			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 4232			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 4233			break;
 4234		case BTC_CXP_FIX_TD2080:
 4235			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4236			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
 4237			break;
 4238		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
 4239			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4240				  tbl_w1, SLOT_ISO);
 4241			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4242				  tbl_b1, SLOT_MIX);
 4243			break;
 4244		default:
 4245			break;
 4246		}
 4247		break;
 4248	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
 4249		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4250		*t = t_def[CXTD_PFIX];
 4251
 4252		switch (policy_type) {
 4253		case BTC_CXP_PFIX_TD3030:
 4254			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 4255			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 4256			break;
 4257		case BTC_CXP_PFIX_TD5050:
 4258			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
 4259			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
 4260			break;
 4261		case BTC_CXP_PFIX_TD2030:
 4262			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4263			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
 4264			break;
 4265		case BTC_CXP_PFIX_TD2060:
 4266			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4267			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 4268			break;
 4269		case BTC_CXP_PFIX_TD3070:
 4270			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
 4271			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
 4272			break;
 4273		case BTC_CXP_PFIX_TD2080:
 4274			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
 4275			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
 4276			break;
 4277		case BTC_CXP_PFIX_TDW1B1: /* W1:B1 = user-define */
 4278			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4279				  tbl_w1, SLOT_ISO);
 4280			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4281				  tbl_b1, SLOT_MIX);
 4282			break;
 4283		default:
 4284			break;
 4285		}
 4286		break;
 4287	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
 4288		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4289		*t = t_def[CXTD_AUTO];
 4290
 4291		switch (policy_type) {
 4292		case BTC_CXP_AUTO_TD50B1:
 4293			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
 4294			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4295			break;
 4296		case BTC_CXP_AUTO_TD60B1:
 4297			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
 4298			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4299			break;
 4300		case BTC_CXP_AUTO_TD20B1:
 4301			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
 4302			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4303			break;
 4304		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
 4305			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4306				  tbl_w1, SLOT_ISO);
 4307			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4308				  tbl_b1, SLOT_MIX);
 4309			break;
 4310		default:
 4311			break;
 4312		}
 4313		break;
 4314	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
 4315		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4316		*t = t_def[CXTD_PAUTO];
 4317
 4318		switch (policy_type) {
 4319		case BTC_CXP_PAUTO_TD50B1:
 4320			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
 4321			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4322			break;
 4323		case BTC_CXP_PAUTO_TD60B1:
 4324			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
 4325			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4326			break;
 4327		case BTC_CXP_PAUTO_TD20B1:
 4328			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
 4329			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4330			break;
 4331		case BTC_CXP_PAUTO_TDW1B1:
 4332			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4333				  tbl_w1, SLOT_ISO);
 4334			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4335				  tbl_b1, SLOT_MIX);
 4336			break;
 4337		default:
 4338			break;
 4339		}
 4340		break;
 4341	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
 4342		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4343		*t = t_def[CXTD_AUTO2];
 4344
 4345		switch (policy_type) {
 4346		case BTC_CXP_AUTO2_TD3050:
 4347			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
 4348			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4349			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
 4350			break;
 4351		case BTC_CXP_AUTO2_TD3070:
 4352			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
 4353			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4354			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
 4355			break;
 4356		case BTC_CXP_AUTO2_TD5050:
 4357			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
 4358			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4359			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
 4360			break;
 4361		case BTC_CXP_AUTO2_TD6060:
 4362			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
 4363			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4364			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
 4365			break;
 4366		case BTC_CXP_AUTO2_TD2080:
 4367			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
 4368			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4369			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
 4370			break;
 4371		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
 4372			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4373				  tbl_w1, SLOT_ISO);
 4374			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4375				  tbl_b1, SLOT_MIX);
 4376			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
 4377				  tbl_b4, SLOT_MIX);
 4378			break;
 4379		default:
 4380			break;
 4381		}
 4382		break;
 4383	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
 4384		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
 4385		*t = t_def[CXTD_PAUTO2];
 4386
 4387		switch (policy_type) {
 4388		case BTC_CXP_PAUTO2_TD3050:
 4389			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
 4390			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4391			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
 4392			break;
 4393		case BTC_CXP_PAUTO2_TD3070:
 4394			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
 4395			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4396			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
 4397			break;
 4398		case BTC_CXP_PAUTO2_TD5050:
 4399			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
 4400			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4401			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
 4402			break;
 4403		case BTC_CXP_PAUTO2_TD6060:
 4404			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
 4405			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4406			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
 4407			break;
 4408		case BTC_CXP_PAUTO2_TD2080:
 4409			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
 4410			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
 4411			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
 4412			break;
 4413		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
 4414			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
 4415				  tbl_w1, SLOT_ISO);
 4416			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
 4417				  tbl_b1, SLOT_MIX);
 4418			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
 4419				  tbl_b4, SLOT_MIX);
 4420			break;
 4421		default:
 4422			break;
 4423		}
 4424		break;
 4425	}
 4426
 4427	if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC && dm->tdma.rxflctrl) {
 4428		null_role = FIELD_PREP(0x0f, dm->wl_scc.null_role1) |
 4429			    FIELD_PREP(0xf0, dm->wl_scc.null_role2);
 4430		_tdma_set_flctrl_role(btc, null_role);
 4431	}
 4432
 4433	/* enter leak_slot after each null-1 */
 4434	if (dm->leak_ap && dm->tdma.leak_n > 1)
 4435		_tdma_set_lek(btc, 1);
 4436
 4437	if (dm->tdma_instant_excute) {
 4438		btc->dm.tdma.option_ctrl |= BIT(0);
 4439		btc->update_policy_force = true;
 4440	}
 4441}
 4442EXPORT_SYMBOL(rtw89_btc_set_policy_v1);
 4443
 4444static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map,
 4445			 u8 tx_val, u8 rx_val)
 4446{
 4447	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 4448	struct rtw89_mac_ax_plt plt;
 4449
 4450	plt.tx = tx_val;
 4451	plt.rx = rx_val;
 4452
 4453	if (rtwdev->btc.ver->fwlrole == 8) {
 4454		plt.band = wl->pta_req_mac;
 4455		if (wl->bt_polut_type[plt.band] == tx_val)
 4456			return;
 4457
 4458		wl->bt_polut_type[plt.band] = tx_val;
 4459		rtw89_mac_cfg_plt(rtwdev, &plt);
 4460	} else {
 4461		plt.band = RTW89_MAC_0;
 4462
 4463		if (phy_map & BTC_PHY_0)
 4464			rtw89_mac_cfg_plt(rtwdev, &plt);
 4465
 4466		if (!rtwdev->dbcc_en)
 4467			return;
 4468
 4469		plt.band = RTW89_MAC_1;
 4470		if (phy_map & BTC_PHY_1)
 4471			rtw89_mac_cfg_plt(rtwdev, &plt);
 4472	}
 4473}
 4474
 4475static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
 4476			u8 phy_map, u8 type)
 4477{
 4478	struct rtw89_btc *btc = &rtwdev->btc;
 4479	struct rtw89_btc_dm *dm = &btc->dm;
 4480	struct rtw89_btc_cx *cx = &btc->cx;
 4481	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4482	struct rtw89_btc_bt_info *bt = &cx->bt;
 4483	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 4484	u8 gnt_wl_ctrl, gnt_bt_ctrl, plt_ctrl, i, b2g = 0;
 4485	bool dbcc_chg = false;
 4486	u32 ant_path_type;
 4487
 4488	ant_path_type = ((phy_map << 8) + type);
 4489
 4490	if (btc->ver->fwlrole == 1)
 4491		dbcc_chg = wl->role_info_v1.dbcc_chg;
 4492	else if (btc->ver->fwlrole == 2)
 4493		dbcc_chg = wl->role_info_v2.dbcc_chg;
 4494	else if (btc->ver->fwlrole == 7)
 4495		dbcc_chg = wl->role_info_v7.dbcc_chg;
 4496	else if (btc->ver->fwlrole == 8)
 4497		dbcc_chg = wl->role_info_v8.dbcc_chg;
 4498
 4499	if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
 4500	    btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
 4501	    btc->dm.run_reason == BTC_RSN_CMD_SET_COEX || dbcc_chg)
 4502		force_exec = FC_EXEC;
 4503
 4504	if (!force_exec && ant_path_type == dm->set_ant_path) {
 4505		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4506			    "[BTC], %s(): return by no change!!\n",
 4507			     __func__);
 4508		return;
 4509	} else if (bt->rfk_info.map.run) {
 4510		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4511			    "[BTC], %s(): return by bt rfk!!\n", __func__);
 4512		return;
 4513	} else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
 4514		   wl->rfk_info.state != BTC_WRFK_STOP) {
 4515		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4516			    "[BTC], %s(): return by wl rfk!!\n", __func__);
 4517		return;
 4518	}
 4519
 4520	dm->set_ant_path = ant_path_type;
 4521
 4522	rtw89_debug(rtwdev,
 4523		    RTW89_DBG_BTC,
 4524		    "[BTC], %s(): path=0x%x, set_type=0x%x\n",
 4525		    __func__, phy_map, dm->set_ant_path & 0xff);
 4526
 4527	switch (type) {
 4528	case BTC_ANT_WPOWERON:
 4529		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
 4530		break;
 4531	case BTC_ANT_WINIT:
 4532		if (bt->enable.now)
 4533			_set_gnt(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI);
 4534		else
 4535			_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
 4536
 4537		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4538		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_BT, BTC_PLT_BT);
 4539		break;
 4540	case BTC_ANT_WONLY:
 4541		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
 4542		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4543		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
 4544		break;
 4545	case BTC_ANT_WOFF:
 4546		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
 4547		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
 4548		break;
 4549	case BTC_ANT_W2G:
 4550		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4551		if (rtwdev->dbcc_en) {
 4552			for (i = 0; i < RTW89_PHY_NUM; i++) {
 4553				b2g = (wl_dinfo->real_band[i] == RTW89_BAND_2G);
 4554
 4555				gnt_wl_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
 4556				gnt_bt_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
 4557				/* BT should control by GNT_BT if WL_2G at S0 */
 4558				if (i == 1 &&
 4559				    wl_dinfo->real_band[0] == RTW89_BAND_2G &&
 4560				    wl_dinfo->real_band[1] == RTW89_BAND_5G)
 4561					gnt_bt_ctrl = BTC_GNT_HW;
 4562				_set_gnt(rtwdev, BIT(i), gnt_wl_ctrl, gnt_bt_ctrl);
 4563				plt_ctrl = b2g ? BTC_PLT_BT : BTC_PLT_NONE;
 4564				_set_bt_plut(rtwdev, BIT(i),
 4565					     plt_ctrl, plt_ctrl);
 4566			}
 4567		} else {
 4568			_set_gnt(rtwdev, phy_map, BTC_GNT_HW, BTC_GNT_HW);
 4569			_set_bt_plut(rtwdev, BTC_PHY_ALL,
 4570				     BTC_PLT_BT, BTC_PLT_BT);
 4571		}
 4572		break;
 4573	case BTC_ANT_W5G:
 4574		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4575		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_HW);
 4576		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
 4577		break;
 4578	case BTC_ANT_W25G:
 4579		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4580		_set_gnt(rtwdev, phy_map, BTC_GNT_HW, BTC_GNT_HW);
 4581		_set_bt_plut(rtwdev, BTC_PHY_ALL,
 4582			     BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
 4583		break;
 4584	case BTC_ANT_FREERUN:
 4585		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4586		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_HI);
 4587		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
 4588		break;
 4589	case BTC_ANT_WRFK:
 4590	case BTC_ANT_WRFK2:
 4591		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
 4592		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
 4593		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
 4594		break;
 4595	case BTC_ANT_BRFK:
 4596		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
 4597		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI);
 4598		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
 4599		break;
 4600	default:
 4601		break;
 4602	}
 4603}
 4604
 4605static void _set_ant_v1(struct rtw89_dev *rtwdev, bool force_exec,
 4606			u8 phy_map, u8 type)
 4607{
 4608	struct rtw89_btc *btc = &rtwdev->btc;
 4609	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4610	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 4611	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 4612	u32 ant_path_type = rtw89_get_antpath_type(phy_map, type);
 4613	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 4614	struct rtw89_btc_dm *dm = &btc->dm;
 4615	u8 gwl = BTC_GNT_HW;
 4616
 4617	if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
 4618	    btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
 4619	    btc->dm.run_reason == BTC_RSN_CMD_SET_COEX || wl_rinfo->dbcc_chg)
 4620		force_exec = FC_EXEC;
 4621
 4622	if (wl_rinfo->link_mode != BTC_WLINK_25G_MCC &&
 4623	    btc->dm.wl_btg_rx == 2)
 4624		force_exec = FC_EXEC;
 4625
 4626	if (!force_exec && ant_path_type == dm->set_ant_path) {
 4627		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4628			    "[BTC], %s(): return by no change!!\n",
 4629			     __func__);
 4630		return;
 4631	} else if (bt->rfk_info.map.run) {
 4632		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4633			    "[BTC], %s(): return by bt rfk!!\n", __func__);
 4634		return;
 4635	} else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
 4636		   wl->rfk_info.state != BTC_WRFK_STOP) {
 4637		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4638			    "[BTC], %s(): return by wl rfk!!\n", __func__);
 4639		return;
 4640	}
 4641
 4642	dm->set_ant_path = ant_path_type;
 4643
 4644	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 4645		    "[BTC], %s(): path=0x%x, set_type=0x%x\n",
 4646		    __func__, phy_map, dm->set_ant_path & 0xff);
 4647
 4648	switch (type) {
 4649	case BTC_ANT_WINIT:
 4650		/* To avoid BT MP driver case (bt_enable but no mailbox) */
 4651		if (bt->enable.now && bt->run_patch_code)
 4652			_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
 4653				    BTC_WLACT_SW_LO);
 4654		else
 4655			_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
 4656				    BTC_WLACT_SW_HI);
 4657		break;
 4658	case BTC_ANT_WONLY:
 4659		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
 4660			    BTC_WLACT_SW_HI);
 4661		break;
 4662	case BTC_ANT_WOFF:
 4663		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
 4664			    BTC_WLACT_SW_LO);
 4665		break;
 4666	case BTC_ANT_W2G:
 4667	case BTC_ANT_W25G:
 4668		if (wl_rinfo->dbcc_en) {
 4669			if (wl_dinfo->real_band[RTW89_PHY_0] == RTW89_BAND_2G)
 4670				gwl = BTC_GNT_HW;
 4671			else
 4672				gwl = BTC_GNT_SW_HI;
 4673			_set_gnt_v1(rtwdev, BTC_PHY_0, gwl, BTC_GNT_HW, BTC_WLACT_HW);
 4674
 4675			if (wl_dinfo->real_band[RTW89_PHY_1] == RTW89_BAND_2G)
 4676				gwl = BTC_GNT_HW;
 4677			else
 4678				gwl = BTC_GNT_SW_HI;
 4679			_set_gnt_v1(rtwdev, BTC_PHY_1, gwl, BTC_GNT_HW, BTC_WLACT_HW);
 4680		} else {
 4681			gwl = BTC_GNT_HW;
 4682			_set_gnt_v1(rtwdev, phy_map, gwl, BTC_GNT_HW, BTC_WLACT_HW);
 4683		}
 4684		break;
 4685	case BTC_ANT_W5G:
 4686		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_HW, BTC_WLACT_HW);
 4687		break;
 4688	case BTC_ANT_FREERUN:
 4689		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_HI,
 4690			    BTC_WLACT_SW_LO);
 4691		break;
 4692	case BTC_ANT_WRFK:
 4693		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
 4694			    BTC_WLACT_HW);
 4695		break;
 4696	case BTC_ANT_WRFK2:
 4697		_set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
 4698			    BTC_WLACT_SW_HI); /* no BT-Tx */
 4699		break;
 4700	default:
 4701		return;
 4702	}
 4703
 4704	_set_bt_plut(rtwdev, phy_map, BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
 4705}
 4706
 4707static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
 4708		     u8 phy_map, u8 type)
 4709{
 4710	if (rtwdev->chip->chip_id == RTL8922A)
 4711		_set_ant_v1(rtwdev, force_exec, phy_map, type);
 4712	else
 4713		_set_ant_v0(rtwdev, force_exec, phy_map, type);
 4714}
 4715
 4716static void _action_wl_only(struct rtw89_dev *rtwdev)
 4717{
 4718	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
 4719	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_ONLY);
 4720}
 4721
 4722static void _action_wl_init(struct rtw89_dev *rtwdev)
 4723{
 4724	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 4725
 4726	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WINIT);
 4727	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
 4728}
 4729
 4730static void _action_wl_off(struct rtw89_dev *rtwdev, u8 mode)
 4731{
 4732	struct rtw89_btc *btc = &rtwdev->btc;
 4733	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4734
 4735	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 4736
 4737	if (wl->status.map.rf_off || btc->dm.bt_only) {
 4738		_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
 4739	} else if (wl->status.map.lps == BTC_LPS_RF_ON) {
 4740		if (mode == BTC_WLINK_5G)
 4741			_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
 4742		else
 4743			_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4744	}
 4745
 4746	if (mode == BTC_WLINK_5G) {
 4747		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OFF);
 4748	} else if (wl->status.map.lps == BTC_LPS_RF_ON) {
 4749		if (btc->cx.bt.link_info.a2dp_desc.active)
 4750			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
 4751		else
 4752			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_WL_OFF);
 4753	} else {
 4754		_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
 4755	}
 4756}
 4757
 4758static void _action_freerun(struct rtw89_dev *rtwdev)
 4759{
 4760	struct rtw89_btc *btc = &rtwdev->btc;
 4761
 4762	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 4763
 4764	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_FREERUN);
 4765	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_FREERUN);
 4766
 4767	btc->dm.freerun = true;
 4768}
 4769
 4770static void _action_bt_whql(struct rtw89_dev *rtwdev)
 4771{
 4772	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 4773
 4774	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4775	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_WHQL);
 4776}
 4777
 4778static void _action_bt_off(struct rtw89_dev *rtwdev)
 4779{
 4780	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 4781
 4782	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
 4783	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_OFF);
 4784}
 4785
 4786static void _action_bt_idle(struct rtw89_dev *rtwdev)
 4787{
 4788	struct rtw89_btc *btc = &rtwdev->btc;
 4789	struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info;
 4790	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4791
 4792	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4793
 4794	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 4795		switch (btc->cx.state_map) {
 4796		case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
 4797		case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
 4798			if (b->status.map.connect)
 4799				_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_IDLE);
 4800			else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
 4801				_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_DL, BTC_ACT_BT_IDLE);
 4802			else
 4803				_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_UL, BTC_ACT_BT_IDLE);
 4804			break;
 4805		case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
 4806			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
 4807				    BTC_ACT_BT_IDLE);
 4808			break;
 4809		case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
 4810			_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
 4811				    BTC_ACT_BT_IDLE);
 4812			break;
 4813		case BTC_WLINKING: /* wl-connecting + bt-inq or bt-idle */
 4814			_set_policy(rtwdev, BTC_CXP_FIX_TD7010,
 4815				    BTC_ACT_BT_IDLE);
 4816			break;
 4817		case BTC_WIDLE:  /* wl-idle + bt-idle */
 4818			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_IDLE);
 4819			break;
 4820		}
 4821	} else { /* dedicated-antenna */
 4822		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_BT_IDLE);
 4823	}
 4824}
 4825
 4826static void _action_bt_hfp(struct rtw89_dev *rtwdev)
 4827{
 4828	struct rtw89_btc *btc = &rtwdev->btc;
 4829	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4830
 4831	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4832
 4833	if (btc->ant_type == BTC_ANT_SHARED) {
 4834		if (btc->cx.wl.status.map._4way) {
 4835			_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP);
 4836		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
 4837			btc->cx.bt.scan_rx_low_pri = true;
 4838			_set_policy(rtwdev, BTC_CXP_OFF_BWB2, BTC_ACT_BT_HFP);
 4839		} else {
 4840			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
 4841		}
 4842	} else {
 4843		if (wl->bg_mode)
 4844			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
 4845		else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
 4846			_set_policy(rtwdev, BTC_CXP_OFF_EQ5, BTC_ACT_BT_HFP);
 4847		else
 4848			_set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
 4849	}
 4850}
 4851
 4852static void _action_bt_hid(struct rtw89_dev *rtwdev)
 4853{
 4854	const struct rtw89_chip_info *chip = rtwdev->chip;
 4855	struct rtw89_btc *btc = &rtwdev->btc;
 4856	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 4857	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 4858	struct rtw89_btc_bt_hid_desc *hid = &bt->link_info.hid_desc;
 4859	u16 policy_type = BTC_CXP_OFF_BT;
 4860
 4861	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4862
 4863	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 4864		if (wl->status.map._4way) {
 4865			policy_type = BTC_CXP_OFF_WL;
 4866		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
 4867			btc->cx.bt.scan_rx_low_pri = true;
 4868			if (hid->type & BTC_HID_BLE)
 4869				policy_type = BTC_CXP_OFF_BWB0;
 4870			else
 4871				policy_type = BTC_CXP_OFF_BWB2;
 4872		} else if (hid->type == BTC_HID_218) {
 4873			bt->scan_rx_low_pri = true;
 4874			policy_type = BTC_CXP_OFF_BWB2;
 4875		} else if (chip->para_ver == 0x1) {
 4876			policy_type = BTC_CXP_OFF_BWB3;
 4877		} else {
 4878			policy_type = BTC_CXP_OFF_BWB1;
 4879		}
 4880	} else { /* dedicated-antenna */
 4881		if (wl->bg_mode)
 4882			policy_type = BTC_CXP_OFF_BWB1;
 4883		else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
 4884			policy_type = BTC_CXP_OFF_EQ4;
 4885		else
 4886			policy_type = BTC_CXP_OFF_EQ3;
 4887	}
 4888
 4889	_set_policy(rtwdev, policy_type, BTC_ACT_BT_HID);
 4890}
 4891
 4892static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
 4893{
 4894	struct rtw89_btc *btc = &rtwdev->btc;
 4895	struct rtw89_btc_dm *dm = &btc->dm;
 4896
 4897	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4898
 4899	dm->slot_dur[CXST_W1] = 20;
 4900	dm->slot_dur[CXST_B1] = BTC_B1_MAX;
 4901
 4902	switch (btc->cx.state_map) {
 4903	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP */
 4904		_set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
 4905		break;
 4906	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP */
 4907		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP);
 4908		break;
 4909	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP */
 4910		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP);
 4911		break;
 4912	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP */
 4913	case BTC_WLINKING: /* wl-connecting + bt-A2DP */
 4914		if (btc->cx.wl.rfk_info.con_rfk)
 4915			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP);
 4916		else
 4917			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP);
 4918		break;
 4919	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
 4920		_set_policy(rtwdev, BTC_CXP_AUTO_TD20B1, BTC_ACT_BT_A2DP);
 4921		break;
 4922	}
 4923}
 4924
 4925static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
 4926{
 4927	struct rtw89_btc *btc = &rtwdev->btc;
 4928
 4929	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4930
 4931	switch (btc->cx.state_map) {
 4932	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2dp_Sink */
 4933		_set_policy(rtwdev, BTC_CXP_PFIX_TD2030, BTC_ACT_BT_A2DPSINK);
 4934		break;
 4935	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2dp_Sink */
 4936		_set_policy(rtwdev, BTC_CXP_PFIX_TD2060, BTC_ACT_BT_A2DPSINK);
 4937		break;
 4938	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2dp_Sink */
 4939		_set_policy(rtwdev, BTC_CXP_FIX_TD2030, BTC_ACT_BT_A2DPSINK);
 4940		break;
 4941	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2dp_Sink */
 4942		_set_policy(rtwdev, BTC_CXP_FIX_TD2060, BTC_ACT_BT_A2DPSINK);
 4943		break;
 4944	case BTC_WLINKING: /* wl-connecting + bt-A2dp_Sink */
 4945		if (btc->cx.wl.rfk_info.con_rfk)
 4946			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DPSINK);
 4947		else
 4948			_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
 4949		break;
 4950	case BTC_WIDLE: /* wl-idle + bt-A2dp_Sink */
 4951		_set_policy(rtwdev, BTC_CXP_FIX_TD2080, BTC_ACT_BT_A2DPSINK);
 4952		break;
 4953	}
 4954}
 4955
 4956static void _action_bt_pan(struct rtw89_dev *rtwdev)
 4957{
 4958	struct rtw89_btc *btc = &rtwdev->btc;
 4959	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
 4960	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
 4961	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
 4962
 4963	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4964
 4965	switch (btc->cx.state_map) {
 4966	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */
 4967		if (a2dp.active || !pan.exist) {
 4968			btc->dm.slot_dur[CXST_W1] = 80;
 4969			btc->dm.slot_dur[CXST_B1] = 20;
 4970			_set_policy(rtwdev, BTC_CXP_PFIX_TDW1B1, BTC_ACT_BT_PAN);
 4971		} else {
 4972			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
 4973		}
 4974		break;
 4975	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */
 4976		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN);
 4977		break;
 4978	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN */
 4979		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN);
 4980		break;
 4981	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN */
 4982		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
 4983		break;
 4984	case BTC_WLINKING: /* wl-connecting + bt-PAN */
 4985		_set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO, BTC_ACT_BT_PAN);
 4986		break;
 4987	case BTC_WIDLE: /* wl-idle + bt-pan */
 4988		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
 4989		break;
 4990	}
 4991}
 4992
 4993static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
 4994{
 4995	struct rtw89_btc *btc = &rtwdev->btc;
 4996	struct rtw89_btc_dm *dm = &btc->dm;
 4997
 4998	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 4999
 5000	dm->slot_dur[CXST_W1] = 20;
 5001	dm->slot_dur[CXST_B1] = BTC_B1_MAX;
 5002
 5003	switch (btc->cx.state_map) {
 5004	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+HID */
 5005	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
 5006		_set_policy(rtwdev, BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
 5007		break;
 5008	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+HID */
 5009		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_HID);
 5010		break;
 5011
 5012	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+HID */
 5013		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
 5014		break;
 5015	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+HID */
 5016	case BTC_WLINKING: /* wl-connecting + bt-A2DP+HID */
 5017		if (btc->cx.wl.rfk_info.con_rfk)
 5018			_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_A2DP_HID);
 5019		else
 5020			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
 5021		break;
 5022	}
 5023}
 5024
 5025static void _action_bt_a2dp_pan(struct rtw89_dev *rtwdev)
 5026{
 5027	struct rtw89_btc *btc = &rtwdev->btc;
 5028
 5029	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5030
 5031	switch (btc->cx.state_map) {
 5032	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN */
 5033		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
 5034		break;
 5035	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN */
 5036		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
 5037		break;
 5038	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN */
 5039		_set_policy(rtwdev, BTC_CXP_AUTO2_TD5050, BTC_ACT_BT_A2DP_PAN);
 5040		break;
 5041	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN */
 5042		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
 5043		break;
 5044	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN */
 5045		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_PAN);
 5046		break;
 5047	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN */
 5048		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080, BTC_ACT_BT_A2DP_PAN);
 5049		break;
 5050	}
 5051}
 5052
 5053static void _action_bt_pan_hid(struct rtw89_dev *rtwdev)
 5054{
 5055	struct rtw89_btc *btc = &rtwdev->btc;
 5056
 5057	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5058
 5059	switch (btc->cx.state_map) {
 5060	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN+HID */
 5061		_set_policy(rtwdev, BTC_CXP_PFIX_TD3030, BTC_ACT_BT_PAN_HID);
 5062		break;
 5063	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN+HID */
 5064		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN_HID);
 5065		break;
 5066	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN+HID */
 5067		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN_HID);
 5068		break;
 5069	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN+HID */
 5070		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN_HID);
 5071		break;
 5072	case BTC_WLINKING: /* wl-connecting + bt-PAN+HID */
 5073		_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_PAN_HID);
 5074		break;
 5075	case BTC_WIDLE: /* wl-idle + bt-PAN+HID */
 5076		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN_HID);
 5077		break;
 5078	}
 5079}
 5080
 5081static void _action_bt_a2dp_pan_hid(struct rtw89_dev *rtwdev)
 5082{
 5083	struct rtw89_btc *btc = &rtwdev->btc;
 5084
 5085	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5086
 5087	switch (btc->cx.state_map) {
 5088	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN+HID */
 5089		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
 5090			    BTC_ACT_BT_A2DP_PAN_HID);
 5091		break;
 5092	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN+HID */
 5093		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
 5094			    BTC_ACT_BT_A2DP_PAN_HID);
 5095		break;
 5096	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN+HID */
 5097		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070,
 5098			    BTC_ACT_BT_A2DP_PAN_HID);
 5099		break;
 5100	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN+HID */
 5101	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN+HID */
 5102		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050,
 5103			    BTC_ACT_BT_A2DP_PAN_HID);
 5104		break;
 5105	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN+HID */
 5106		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080,
 5107			    BTC_ACT_BT_A2DP_PAN_HID);
 5108		break;
 5109	}
 5110}
 5111
 5112static void _action_wl_5g(struct rtw89_dev *rtwdev)
 5113{
 5114	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
 5115	_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_5G);
 5116}
 5117
 5118static void _action_wl_other(struct rtw89_dev *rtwdev)
 5119{
 5120	struct rtw89_btc *btc = &rtwdev->btc;
 5121
 5122	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5123
 5124	if (btc->ant_type == BTC_ANT_SHARED)
 5125		_set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER);
 5126	else
 5127		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER);
 5128}
 5129
 5130static void _action_wl_nc(struct rtw89_dev *rtwdev)
 5131{
 5132	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5133	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_NC);
 5134}
 5135
 5136static void _action_wl_rfk(struct rtw89_dev *rtwdev)
 5137{
 5138	struct rtw89_btc *btc = &rtwdev->btc;
 5139	struct rtw89_btc_wl_rfk_info rfk = btc->cx.wl.rfk_info;
 5140
 5141	if (rfk.state != BTC_WRFK_START)
 5142		return;
 5143
 5144	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n",
 5145		    __func__, rfk.band);
 5146
 5147	btc->dm.tdma_instant_excute = 1;
 5148
 5149	if (rfk.state == BTC_WRFK_ONESHOT_START ||
 5150	    btc->ant_type == BTC_ANT_SHARED) {
 5151		_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK2);
 5152		_set_policy(rtwdev, BTC_CXP_OFF_WL2, BTC_ACT_WL_RFK);
 5153	} else {
 5154		_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
 5155		_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
 5156	}
 5157}
 5158
 5159static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
 5160{
 5161	struct rtw89_btc *btc = &rtwdev->btc;
 5162	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5163	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 5164	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 5165	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 5166	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 5167	struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info;
 5168	struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info;
 5169	const struct rtw89_chip_info *chip = rtwdev->chip;
 5170	const struct rtw89_btc_ver *ver = btc->ver;
 5171	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5172	struct rtw89_btc_dm *dm = &btc->dm;
 5173	struct _wl_rinfo_now wl_rinfo;
 5174	u32 is_btg = BTC_BTGCTRL_DISABLE;
 5175
 5176	if (btc->manual_ctrl)
 5177		return;
 5178
 5179	if (ver->fwlrole == 0)
 5180		wl_rinfo.link_mode = wl_rinfo_v0->link_mode;
 5181	else if (ver->fwlrole == 1)
 5182		wl_rinfo.link_mode = wl_rinfo_v1->link_mode;
 5183	else if (ver->fwlrole == 2)
 5184		wl_rinfo.link_mode = wl_rinfo_v2->link_mode;
 5185	else if (ver->fwlrole == 7)
 5186		wl_rinfo.link_mode = wl_rinfo_v7->link_mode;
 5187	else if (ver->fwlrole == 8)
 5188		wl_rinfo.link_mode = wl_rinfo_v8->link_mode;
 5189	else
 5190		return;
 5191
 5192	/* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
 5193	if (btc->ant_type == BTC_ANT_SHARED) {
 5194		if (!(bt->run_patch_code && bt->enable.now))
 5195			is_btg = BTC_BTGCTRL_DISABLE;
 5196		else if (wl_rinfo.link_mode != BTC_WLINK_5G)
 5197			is_btg = BTC_BTGCTRL_ENABLE;
 5198		else
 5199			is_btg = BTC_BTGCTRL_DISABLE;
 5200
 5201		/* bb call ctrl_btg() in WL FW by slot */
 5202		if (!ver->fcxosi &&
 5203		    wl_rinfo.link_mode == BTC_WLINK_25G_MCC)
 5204			is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL;
 5205	}
 5206
 5207	if (is_btg == dm->wl_btg_rx)
 5208		return;
 5209	else
 5210		dm->wl_btg_rx = is_btg;
 5211
 5212	/* skip setup if btg_ctrl set by wl fw */
 5213	if (!ver->fcxosi && is_btg > BTC_BTGCTRL_ENABLE)
 5214		return;
 5215
 5216	/* Below flow is for BTC_FEAT_NEW_BBAPI_FLOW = 1 */
 5217	if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */
 5218		if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */
 5219			o_info->btg_rx[BTC_RF_S0] = BTC_BTGCTRL_DISABLE;
 5220		else
 5221			o_info->btg_rx[BTC_RF_S0] = is_btg;
 5222
 5223		if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */
 5224			o_info->btg_rx[BTC_RF_S1] = BTC_BTGCTRL_DISABLE;
 5225		else
 5226			o_info->btg_rx[BTC_RF_S1] = is_btg;
 5227	} else { /* 2+0 or 0+2 */
 5228		o_info->btg_rx[BTC_RF_S0] = is_btg;
 5229		o_info->btg_rx[BTC_RF_S1] = is_btg;
 5230	}
 5231
 5232	if (ver->fcxosi)
 5233		return;
 5234
 5235	chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S0],
 5236				  RTW89_PHY_0);
 5237	if (chip->chip_id != RTL8922A)
 5238		return;
 5239
 5240	chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S1],
 5241				  RTW89_PHY_1);
 5242}
 5243
 5244static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev)
 5245{
 5246	struct rtw89_btc *btc = &rtwdev->btc;
 5247	struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info;
 5248	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
 5249	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5250	struct rtw89_btc_wl_role_info_v2 *rinfo_v2 = &wl->role_info_v2;
 5251	struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7;
 5252	struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8;
 5253	const struct rtw89_chip_info *chip = rtwdev->chip;
 5254	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5255	struct rtw89_btc_dm *dm = &btc->dm;
 5256	u8 is_preagc, val, link_mode, dbcc_2g_phy;
 5257	u8 role_ver = rtwdev->btc.ver->fwlrole;
 5258	bool dbcc_en;
 5259
 5260	if (btc->manual_ctrl)
 5261		return;
 5262
 5263	if (role_ver == 2) {
 5264		dbcc_en = rinfo_v2->dbcc_en;
 5265		link_mode = rinfo_v2->link_mode;
 5266		dbcc_2g_phy = rinfo_v2->dbcc_2g_phy;
 5267	} else if (role_ver == 7) {
 5268		dbcc_en = rinfo_v7->dbcc_en;
 5269		link_mode = rinfo_v7->link_mode;
 5270		dbcc_2g_phy = rinfo_v7->dbcc_2g_phy;
 5271	} else if (role_ver == 8) {
 5272		dbcc_en = rinfo_v8->dbcc_en;
 5273		link_mode = rinfo_v8->link_mode;
 5274		dbcc_2g_phy = rinfo_v7->dbcc_2g_phy;
 5275	} else {
 5276		return;
 5277	}
 5278
 5279	if (!(bt->run_patch_code && bt->enable.now)) {
 5280		is_preagc = BTC_PREAGC_DISABLE;
 5281	} else if (link_mode == BTC_WLINK_5G) {
 5282		is_preagc = BTC_PREAGC_DISABLE;
 5283	} else if (link_mode == BTC_WLINK_NOLINK ||
 5284		 btc->cx.bt.link_info.profile_cnt.now == 0) {
 5285		is_preagc = BTC_PREAGC_DISABLE;
 5286	} else if (dm->tdma_now.type != CXTDMA_OFF &&
 5287		 !bt_linfo->hfp_desc.exist &&
 5288		 !bt_linfo->hid_desc.exist &&
 5289		 dm->fddt_train == BTC_FDDT_DISABLE) {
 5290		is_preagc = BTC_PREAGC_DISABLE;
 5291	} else if (dbcc_en && (dbcc_2g_phy != RTW89_PHY_1)) {
 5292		is_preagc = BTC_PREAGC_DISABLE;
 5293	} else if (btc->ant_type == BTC_ANT_SHARED) {
 5294		is_preagc = BTC_PREAGC_DISABLE;
 5295	} else {
 5296		is_preagc = BTC_PREAGC_ENABLE;
 5297	}
 5298
 5299	if (!btc->ver->fcxosi && link_mode == BTC_WLINK_25G_MCC)
 5300		is_preagc = BTC_PREAGC_BB_FWCTRL;
 5301
 5302	if (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
 5303	    dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) {
 5304		_get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val);
 5305		dm->wl_pre_agc_rb = val;
 5306	}
 5307
 5308	if ((wl->coex_mode == BTC_MODE_NORMAL &&
 5309	     (dm->run_reason == BTC_RSN_NTFY_INIT ||
 5310	      dm->run_reason == BTC_RSN_NTFY_SWBAND ||
 5311	      dm->wl_pre_agc_rb != dm->wl_pre_agc)) ||
 5312	    is_preagc != dm->wl_pre_agc) {
 5313		dm->wl_pre_agc = is_preagc;
 5314
 5315		if (!btc->ver->fcxosi && is_preagc > BTC_PREAGC_ENABLE)
 5316			return;
 5317
 5318		if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */
 5319			if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */
 5320				o_info->nbtg_tx[BTC_RF_S0] = BTC_PREAGC_DISABLE;
 5321			else
 5322				o_info->nbtg_tx[BTC_RF_S0] = is_preagc;
 5323
 5324			if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */
 5325				o_info->nbtg_tx[BTC_RF_S1] = BTC_PREAGC_DISABLE;
 5326			else
 5327				o_info->nbtg_tx[BTC_RF_S1] = is_preagc;
 5328
 5329		} else { /* 2+0 or 0+2 */
 5330			o_info->nbtg_tx[BTC_RF_S0] = is_preagc;
 5331			o_info->nbtg_tx[BTC_RF_S1] = is_preagc;
 5332		}
 5333
 5334		if (btc->ver->fcxosi)
 5335			return;
 5336
 5337		chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S0],
 5338					   RTW89_PHY_0);
 5339		if (chip->chip_id != RTL8922A)
 5340			return;
 5341		chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S1],
 5342					   RTW89_PHY_1);
 5343	}
 5344}
 5345
 5346struct rtw89_txtime_data {
 5347	struct rtw89_dev *rtwdev;
 5348	int type;
 5349	u32 tx_time;
 5350	u8 tx_retry;
 5351	u16 enable;
 5352	bool reenable;
 5353};
 5354
 5355static void __rtw89_tx_time_iter(struct rtw89_vif_link *rtwvif_link,
 5356				 struct rtw89_sta_link *rtwsta_link,
 5357				 struct rtw89_txtime_data *iter_data)
 5358{
 5359	struct rtw89_dev *rtwdev = iter_data->rtwdev;
 5360	struct rtw89_btc *btc = &rtwdev->btc;
 5361	struct rtw89_btc_cx *cx = &btc->cx;
 5362	struct rtw89_btc_wl_info *wl = &cx->wl;
 5363	struct rtw89_btc_wl_link_info *plink = NULL;
 5364	u8 port = rtwvif_link->port;
 5365	u32 tx_time = iter_data->tx_time;
 5366	u8 tx_retry = iter_data->tx_retry;
 5367	u16 enable = iter_data->enable;
 5368	bool reenable = iter_data->reenable;
 5369
 5370	if (btc->ver->fwlrole == 8)
 5371		plink = &wl->rlink_info[port][0];
 5372	else
 5373		plink = &wl->link_info[port];
 5374
 5375	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 5376		    "[BTC], %s(): port = %d\n", __func__, port);
 5377
 5378	if (!plink->connected) {
 5379		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 5380			    "[BTC], %s(): connected = %d\n",
 5381			    __func__, plink->connected);
 5382		return;
 5383	}
 5384
 5385	/* backup the original tx time before tx-limit on */
 5386	if (reenable) {
 5387		rtw89_mac_get_tx_time(rtwdev, rtwsta_link, &plink->tx_time);
 5388		rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, &plink->tx_retry);
 5389		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 5390			    "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n",
 5391			    __func__, plink->tx_time, plink->tx_retry);
 5392	}
 5393
 5394	/* restore the original tx time if no tx-limit */
 5395	if (!enable) {
 5396		rtw89_mac_set_tx_time(rtwdev, rtwsta_link, true, plink->tx_time);
 5397		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, true,
 5398					     plink->tx_retry);
 5399		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 5400			    "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n",
 5401			    __func__, plink->tx_time, plink->tx_retry);
 5402
 5403	} else {
 5404		rtw89_mac_set_tx_time(rtwdev, rtwsta_link, false, tx_time);
 5405		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, tx_retry);
 5406		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 5407			    "[BTC], %s(): set, tx_time=%d tx_retry= %d\n",
 5408			    __func__, tx_time, tx_retry);
 5409	}
 5410}
 5411
 5412static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
 5413{
 5414	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
 5415	struct rtw89_txtime_data *iter_data =
 5416				(struct rtw89_txtime_data *)data;
 5417	struct rtw89_vif_link *rtwvif_link;
 5418	struct rtw89_sta_link *rtwsta_link;
 5419	unsigned int link_id;
 5420
 5421	rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
 5422		rtwvif_link = rtwsta_link->rtwvif_link;
 5423		__rtw89_tx_time_iter(rtwvif_link, rtwsta_link, iter_data);
 5424	}
 5425}
 5426
 5427static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
 5428{
 5429	struct rtw89_btc *btc = &rtwdev->btc;
 5430	const struct rtw89_btc_ver *ver = btc->ver;
 5431	struct rtw89_btc_cx *cx = &btc->cx;
 5432	struct rtw89_btc_dm *dm = &btc->dm;
 5433	struct rtw89_btc_wl_info *wl = &cx->wl;
 5434	struct rtw89_btc_bt_info *bt = &cx->bt;
 5435	struct rtw89_btc_bt_link_info *b = &bt->link_info;
 5436	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
 5437	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
 5438	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 5439	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 5440	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 5441	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 5442	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 5443	struct rtw89_txtime_data data = {.rtwdev = rtwdev};
 5444	u8 mode, igno_bt, tx_retry;
 5445	u32 tx_time;
 5446	u16 enable;
 5447	bool reenable = false;
 5448
 5449	if (btc->manual_ctrl)
 5450		return;
 5451
 5452	if (ver->fwlrole == 0)
 5453		mode = wl_rinfo->link_mode;
 5454	else if (ver->fwlrole == 1)
 5455		mode = wl_rinfo_v1->link_mode;
 5456	else if (ver->fwlrole == 2)
 5457		mode = wl_rinfo_v2->link_mode;
 5458	else if (ver->fwlrole == 7)
 5459		mode = wl_rinfo_v7->link_mode;
 5460	else if (ver->fwlrole == 8)
 5461		mode = wl_rinfo_v8->link_mode;
 5462	else
 5463		return;
 5464
 5465	if (ver->fcxctrl == 7)
 5466		igno_bt = btc->ctrl.ctrl_v7.igno_bt;
 5467	else
 5468		igno_bt = btc->ctrl.ctrl.igno_bt;
 5469
 5470	if (btc->dm.freerun || igno_bt || b->profile_cnt.now == 0 ||
 5471	    mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) {
 5472		enable = 0;
 5473		tx_time = BTC_MAX_TX_TIME_DEF;
 5474		tx_retry = BTC_MAX_TX_RETRY_DEF;
 5475	} else if ((hfp->exist && hid->exist) || hid->pair_cnt > 1) {
 5476		enable = 1;
 5477		tx_time = BTC_MAX_TX_TIME_L2;
 5478		tx_retry = BTC_MAX_TX_RETRY_L1;
 5479	} else if (hfp->exist || hid->exist) {
 5480		enable = 1;
 5481		tx_time = BTC_MAX_TX_TIME_L3;
 5482		tx_retry = BTC_MAX_TX_RETRY_L1;
 5483	} else {
 5484		enable = 0;
 5485		tx_time = BTC_MAX_TX_TIME_DEF;
 5486		tx_retry = BTC_MAX_TX_RETRY_DEF;
 5487	}
 5488
 5489	if (dm->wl_tx_limit.enable == enable &&
 5490	    dm->wl_tx_limit.tx_time == tx_time &&
 5491	    dm->wl_tx_limit.tx_retry == tx_retry)
 5492		return;
 5493
 5494	if (!dm->wl_tx_limit.enable && enable)
 5495		reenable = true;
 5496
 5497	dm->wl_tx_limit.enable = enable;
 5498	dm->wl_tx_limit.tx_time = tx_time;
 5499	dm->wl_tx_limit.tx_retry = tx_retry;
 5500
 5501	data.enable = enable;
 5502	data.tx_time = tx_time;
 5503	data.tx_retry = tx_retry;
 5504	data.reenable = reenable;
 5505
 5506	ieee80211_iterate_stations_atomic(rtwdev->hw,
 5507					  rtw89_tx_time_iter,
 5508					  &data);
 5509}
 5510
 5511static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
 5512{
 5513	struct rtw89_btc *btc = &rtwdev->btc;
 5514	const struct rtw89_btc_ver *ver = btc->ver;
 5515	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5516	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 5517	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 5518	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 5519	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 5520	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 5521	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5522	bool bt_hi_lna_rx = false;
 5523	u8 mode;
 5524
 5525	if (ver->fwlrole == 0)
 5526		mode = wl_rinfo->link_mode;
 5527	else if (ver->fwlrole == 1)
 5528		mode = wl_rinfo_v1->link_mode;
 5529	else if (ver->fwlrole == 2)
 5530		mode = wl_rinfo_v2->link_mode;
 5531	else if (ver->fwlrole == 7)
 5532		mode = wl_rinfo_v7->link_mode;
 5533	else if (ver->fwlrole == 8)
 5534		mode = wl_rinfo_v8->link_mode;
 5535	else
 5536		return;
 5537
 5538	if (mode != BTC_WLINK_NOLINK && btc->dm.wl_btg_rx)
 5539		bt_hi_lna_rx = true;
 5540
 5541	if (bt_hi_lna_rx == bt->hi_lna_rx)
 5542		return;
 5543
 5544	_write_scbd(rtwdev, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
 5545}
 5546
 5547static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
 5548{
 5549	struct rtw89_btc *btc = &rtwdev->btc;
 5550	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5551
 5552	_write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri));
 5553}
 5554
 5555static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac)
 5556{
 5557	struct rtw89_btc *btc = &rtwdev->btc;
 5558	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5559	struct rtw89_btc_dm *dm = &btc->dm;
 5560	u32 add;
 5561
 5562	if (mac == wl->pta_req_mac)
 5563		return;
 5564
 5565	dm->ost_info.pta_req_hw_band = mac;
 5566	wl->pta_req_mac = mac;
 5567	wl->pta_reg_mac_chg = true;
 5568
 5569	if (btc->ver->fcxosi)
 5570		return;
 5571
 5572	if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
 5573		add = R_BE_BTC_CFG;
 5574	else
 5575		add = R_AX_BTC_CFG;
 5576
 5577	if (mac == RTW89_MAC_0)
 5578		rtw89_write32_clr(rtwdev, add, B_AX_WL_SRC);
 5579	else
 5580		rtw89_write32_set(rtwdev, add, B_AX_WL_SRC);
 5581}
 5582
 5583static void _action_common(struct rtw89_dev *rtwdev)
 5584{
 5585	struct rtw89_btc *btc = &rtwdev->btc;
 5586	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5587	struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8;
 5588	struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
 5589	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5590	struct rtw89_btc_dm *dm = &btc->dm;
 5591	u32 bt_rom_code_id, bt_fw_ver;
 5592
 5593	if (btc->ver->fwlrole == 8)
 5594		_wl_req_mac(rtwdev, rinfo_v8->pta_req_band);
 5595
 5596	_set_btg_ctrl(rtwdev);
 5597	_set_wl_preagc_ctrl(rtwdev);
 5598	_set_wl_tx_limit(rtwdev);
 5599	_set_bt_afh_info(rtwdev);
 5600	_set_bt_rx_agc(rtwdev);
 5601	_set_rf_trx_para(rtwdev);
 5602	_set_bt_rx_scan_pri(rtwdev);
 5603
 5604	bt_rom_code_id = chip_id_to_bt_rom_code_id(rtwdev->btc.ver->chip_id);
 5605	bt_fw_ver = bt->ver_info.fw & 0xffff;
 5606	if (bt->enable.now &&
 5607	    (bt_fw_ver == 0 ||
 5608	     (bt_fw_ver == bt_rom_code_id && bt->run_patch_code && rtwdev->chip->scbd)))
 5609		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, 1);
 5610	else
 5611		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, 0);
 5612
 5613	if (dm->run_reason == BTC_RSN_NTFY_INIT ||
 5614	    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE ||
 5615	    dm->run_reason == BTC_RSN_NTFY_POWEROFF) {
 5616		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 5617
 5618		if (wl_smap->rf_off == 1 || wl_smap->lps != BTC_LPS_OFF)
 5619			rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
 5620		else
 5621			rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
 5622	}
 5623
 5624	if (wl->scbd_change) {
 5625		rtw89_mac_cfg_sb(rtwdev, wl->scbd);
 5626		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], write scbd: 0x%08x\n",
 5627			    wl->scbd);
 5628		wl->scbd_change = false;
 5629		btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++;
 5630	}
 5631
 5632	if (btc->ver->fcxosi) {
 5633		if (memcmp(&dm->ost_info_last, &dm->ost_info,
 5634			   sizeof(dm->ost_info_last)) ||
 5635		    dm->run_reason == BTC_RSN_NTFY_INIT ||
 5636		    dm->run_reason == BTC_RSN_NTFY_RADIO_STATE) {
 5637			dm->ost_info_last = dm->ost_info;
 5638			_fw_set_drv_info(rtwdev, CXDRVINFO_OSI);
 5639		}
 5640	}
 5641	btc->dm.tdma_instant_excute = 0;
 5642	wl->pta_reg_mac_chg = false;
 5643}
 5644
 5645static void _action_by_bt(struct rtw89_dev *rtwdev)
 5646{
 5647	struct rtw89_btc *btc = &rtwdev->btc;
 5648	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5649	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 5650	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
 5651	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
 5652	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
 5653	struct rtw89_btc_dm *dm = &btc->dm;
 5654	u8 profile_map = 0;
 5655
 5656	if (dm->freerun_chk) {
 5657		_action_freerun(rtwdev);
 5658		return;
 5659	}
 5660
 5661	if (bt_linfo->hfp_desc.exist)
 5662		profile_map |= BTC_BT_HFP;
 5663
 5664	if (bt_linfo->hid_desc.exist)
 5665		profile_map |= BTC_BT_HID;
 5666
 5667	if (bt_linfo->a2dp_desc.exist)
 5668		profile_map |= BTC_BT_A2DP;
 5669
 5670	if (bt_linfo->pan_desc.exist)
 5671		profile_map |= BTC_BT_PAN;
 5672
 5673	switch (profile_map) {
 5674	case BTC_BT_NOPROFILE:
 5675		if (pan.active)
 5676			_action_bt_pan(rtwdev);
 5677		else
 5678			_action_bt_idle(rtwdev);
 5679		break;
 5680	case BTC_BT_HFP:
 5681		_action_bt_hfp(rtwdev);
 5682		break;
 5683	case BTC_BT_HFP | BTC_BT_HID:
 5684	case BTC_BT_HID:
 5685		_action_bt_hid(rtwdev);
 5686		break;
 5687	case BTC_BT_A2DP:
 5688		if (a2dp.sink)
 5689			_action_bt_a2dpsink(rtwdev);
 5690		else if (bt_linfo->multi_link.now && !hid.pair_cnt)
 5691			_action_bt_a2dp_pan(rtwdev);
 5692		else
 5693			_action_bt_a2dp(rtwdev);
 5694		break;
 5695	case BTC_BT_PAN:
 5696		_action_bt_pan(rtwdev);
 5697		break;
 5698	case BTC_BT_A2DP | BTC_BT_HFP:
 5699	case BTC_BT_A2DP | BTC_BT_HID:
 5700	case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
 5701		if (a2dp.sink)
 5702			_action_bt_a2dpsink(rtwdev);
 5703		else if (pan.active)
 5704			_action_bt_a2dp_pan_hid(rtwdev);
 5705		else
 5706			_action_bt_a2dp_hid(rtwdev);
 5707		break;
 5708	case BTC_BT_A2DP | BTC_BT_PAN:
 5709		if (a2dp.sink)
 5710			_action_bt_a2dpsink(rtwdev);
 5711		else
 5712			_action_bt_a2dp_pan(rtwdev);
 5713		break;
 5714	case BTC_BT_PAN | BTC_BT_HFP:
 5715	case BTC_BT_PAN | BTC_BT_HID:
 5716	case BTC_BT_PAN | BTC_BT_HFP | BTC_BT_HID:
 5717		_action_bt_pan_hid(rtwdev);
 5718		break;
 5719	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID:
 5720	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP:
 5721	default:
 5722		if (a2dp.sink)
 5723			_action_bt_a2dpsink(rtwdev);
 5724		else
 5725			_action_bt_a2dp_pan_hid(rtwdev);
 5726		break;
 5727	}
 5728}
 5729
 5730static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
 5731{
 5732	_action_by_bt(rtwdev);
 5733}
 5734
 5735static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
 5736{
 5737	struct rtw89_btc *btc = &rtwdev->btc;
 5738	u16 policy_type = BTC_CXP_OFF_BT;
 5739
 5740	if (btc->ant_type == BTC_ANT_SHARED) {
 5741		if (btc->cx.wl.status.map._4way)
 5742			policy_type = BTC_CXP_OFFE_WL;
 5743		else if (btc->cx.wl.status.val & btc_scanning_map.val)
 5744			policy_type = BTC_CXP_OFFE_2GBWMIXB;
 5745		else if (btc->cx.bt.link_info.status.map.connect == 0)
 5746			policy_type = BTC_CXP_OFFE_2GISOB;
 5747		else
 5748			policy_type = BTC_CXP_OFFE_2GBWISOB;
 5749	} else { /* dedicated-antenna */
 5750		policy_type = BTC_CXP_OFF_EQ0;
 5751	}
 5752
 5753	btc->dm.e2g_slot_limit = BTC_E2G_LIMIT_DEF;
 5754
 5755	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
 5756	_set_policy(rtwdev, policy_type, BTC_ACT_WL_25G_MCC);
 5757}
 5758
 5759static void _action_wl_scan(struct rtw89_dev *rtwdev)
 5760{
 5761	struct rtw89_btc *btc = &rtwdev->btc;
 5762	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5763	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 5764
 5765	if (btc->cx.state_map != BTC_WLINKING &&
 5766	    RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
 5767		_action_wl_25g_mcc(rtwdev);
 5768		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], Scan offload!\n");
 5769	} else if (rtwdev->dbcc_en) {
 5770		if (wl_dinfo->real_band[RTW89_PHY_0] != RTW89_BAND_2G &&
 5771		    wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
 5772			_action_wl_5g(rtwdev);
 5773		else
 5774			_action_by_bt(rtwdev);
 5775	} else {
 5776		if (wl->scan_info.band[RTW89_PHY_0] != RTW89_BAND_2G)
 5777			_action_wl_5g(rtwdev);
 5778		else
 5779			_action_by_bt(rtwdev);
 5780	}
 5781}
 5782
 5783static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
 5784{	struct rtw89_btc *btc = &rtwdev->btc;
 5785
 5786	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5787
 5788	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 5789		if (btc->cx.bt.link_info.profile_cnt.now == 0)
 5790			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
 5791				    BTC_ACT_WL_2G_MCC);
 5792		else
 5793			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
 5794				    BTC_ACT_WL_2G_MCC);
 5795	} else { /* dedicated-antenna */
 5796		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_MCC);
 5797	}
 5798}
 5799
 5800static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
 5801{
 5802	struct rtw89_btc *btc = &rtwdev->btc;
 5803
 5804	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5805
 5806	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 5807		if (btc->cx.bt.link_info.profile_cnt.now == 0)
 5808			_set_policy(rtwdev,
 5809				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
 5810		else
 5811			_set_policy(rtwdev,
 5812				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_SCC);
 5813	} else { /* dedicated-antenna */
 5814		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_SCC);
 5815	}
 5816}
 5817
 5818static void _action_wl_2g_scc_v1(struct rtw89_dev *rtwdev)
 5819{
 5820	struct rtw89_btc *btc = &rtwdev->btc;
 5821	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5822	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5823	struct rtw89_btc_dm *dm = &btc->dm;
 5824	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
 5825	u16 policy_type = BTC_CXP_OFF_BT;
 5826	u32 dur;
 5827
 5828	if (btc->ant_type == BTC_ANT_DEDICATED) {
 5829		policy_type = BTC_CXP_OFF_EQ0;
 5830	} else {
 5831		/* shared-antenna */
 5832		switch (wl_rinfo->mrole_type) {
 5833		case BTC_WLMROLE_STA_GC:
 5834			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5835			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_P2P_CLIENT;
 5836			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
 5837			_action_by_bt(rtwdev);
 5838			return;
 5839		case BTC_WLMROLE_STA_STA:
 5840			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5841			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_STATION;
 5842			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
 5843			_action_by_bt(rtwdev);
 5844			return;
 5845		case BTC_WLMROLE_STA_GC_NOA:
 5846		case BTC_WLMROLE_STA_GO:
 5847		case BTC_WLMROLE_STA_GO_NOA:
 5848			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5849			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_NONE;
 5850			dur = wl_rinfo->mrole_noa_duration;
 5851
 5852			if (wl->status.map._4way) {
 5853				dm->wl_scc.ebt_null = 0;
 5854				policy_type = BTC_CXP_OFFE_WL;
 5855			} else if (bt->link_info.status.map.connect == 0) {
 5856				dm->wl_scc.ebt_null = 0;
 5857				policy_type = BTC_CXP_OFFE_2GISOB;
 5858			} else if (bt->link_info.a2dp_desc.exist &&
 5859				   dur < btc->bt_req_len) {
 5860				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
 5861				policy_type = BTC_CXP_OFFE_2GBWMIXB2;
 5862			} else if (bt->link_info.a2dp_desc.exist ||
 5863				   bt->link_info.pan_desc.exist) {
 5864				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
 5865				policy_type = BTC_CXP_OFFE_2GBWISOB;
 5866			} else {
 5867				dm->wl_scc.ebt_null = 0;
 5868				policy_type = BTC_CXP_OFFE_2GBWISOB;
 5869			}
 5870			break;
 5871		default:
 5872			break;
 5873		}
 5874	}
 5875
 5876	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5877	_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
 5878}
 5879
 5880static void _action_wl_2g_scc_v2(struct rtw89_dev *rtwdev)
 5881{
 5882	struct rtw89_btc *btc = &rtwdev->btc;
 5883	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5884	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5885	struct rtw89_btc_dm *dm = &btc->dm;
 5886	struct rtw89_btc_wl_role_info_v2 *rinfo_v2 = &wl->role_info_v2;
 5887	struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7;
 5888	u32 dur, mrole_type, mrole_noa_duration;
 5889	u16 policy_type = BTC_CXP_OFF_BT;
 5890
 5891	if (btc->ver->fwlrole == 2) {
 5892		mrole_type = rinfo_v2->mrole_type;
 5893		mrole_noa_duration = rinfo_v2->mrole_noa_duration;
 5894	} else if (btc->ver->fwlrole == 7) {
 5895		mrole_type = rinfo_v7->mrole_type;
 5896		mrole_noa_duration = rinfo_v7->mrole_noa_duration;
 5897	} else {
 5898		return;
 5899	}
 5900
 5901	if (btc->ant_type == BTC_ANT_DEDICATED) {
 5902		policy_type = BTC_CXP_OFF_EQ0;
 5903	} else {
 5904		/* shared-antenna */
 5905		switch (mrole_type) {
 5906		case BTC_WLMROLE_STA_GC:
 5907			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5908			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_P2P_CLIENT;
 5909			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
 5910			_action_by_bt(rtwdev);
 5911			return;
 5912		case BTC_WLMROLE_STA_STA:
 5913			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5914			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_STATION;
 5915			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
 5916			_action_by_bt(rtwdev);
 5917			return;
 5918		case BTC_WLMROLE_STA_GC_NOA:
 5919		case BTC_WLMROLE_STA_GO:
 5920		case BTC_WLMROLE_STA_GO_NOA:
 5921			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
 5922			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_NONE;
 5923			dur = mrole_noa_duration;
 5924
 5925			if (wl->status.map._4way) {
 5926				dm->wl_scc.ebt_null = 0;
 5927				policy_type = BTC_CXP_OFFE_WL;
 5928			} else if (bt->link_info.status.map.connect == 0) {
 5929				dm->wl_scc.ebt_null = 0;
 5930				policy_type = BTC_CXP_OFFE_2GISOB;
 5931			} else if (bt->link_info.a2dp_desc.exist &&
 5932				   dur < btc->bt_req_len) {
 5933				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
 5934				policy_type = BTC_CXP_OFFE_2GBWMIXB2;
 5935			} else if (bt->link_info.a2dp_desc.exist ||
 5936				   bt->link_info.pan_desc.exist) {
 5937				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
 5938				policy_type = BTC_CXP_OFFE_2GBWISOB;
 5939			} else {
 5940				dm->wl_scc.ebt_null = 0;
 5941				policy_type = BTC_CXP_OFFE_2GBWISOB;
 5942			}
 5943			break;
 5944		default:
 5945			break;
 5946		}
 5947	}
 5948
 5949	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5950	_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
 5951}
 5952
 5953static void _action_wl_2g_scc_v8(struct rtw89_dev *rtwdev)
 5954{
 5955	struct rtw89_btc *btc = &rtwdev->btc;
 5956	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 5957	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 5958	struct rtw89_btc_dm *dm = &btc->dm;
 5959	u16 policy_type = BTC_CXP_OFF_BT;
 5960
 5961	if (btc->ant_type == BTC_ANT_SHARED) {
 5962		if (wl->status.map._4way)
 5963			policy_type = BTC_CXP_OFFE_WL;
 5964		else if (bt->link_info.status.map.connect == 0)
 5965			policy_type = BTC_CXP_OFFE_2GISOB;
 5966		else
 5967			policy_type = BTC_CXP_OFFE_2GBWISOB;
 5968	} else {
 5969		policy_type = BTC_CXP_OFF_EQ0;
 5970	}
 5971
 5972	dm->e2g_slot_limit = BTC_E2G_LIMIT_DEF;
 5973
 5974	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5975	_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
 5976}
 5977
 5978static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
 5979{
 5980	struct rtw89_btc *btc = &rtwdev->btc;
 5981
 5982	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 5983
 5984	if (btc->ant_type == BTC_ANT_SHARED) {
 5985		if (btc->cx.bt.link_info.profile_cnt.now == 0)
 5986			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
 5987				    BTC_ACT_WL_2G_AP);
 5988		else
 5989			_set_policy(rtwdev, BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_AP);
 5990	} else {/* dedicated-antenna */
 5991		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_AP);
 5992	}
 5993}
 5994
 5995static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
 5996{
 5997	struct rtw89_btc *btc = &rtwdev->btc;
 5998
 5999	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 6000
 6001	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 6002		if (btc->cx.bt.link_info.profile_cnt.now == 0)
 6003			_set_policy(rtwdev,
 6004				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
 6005		else
 6006			_set_policy(rtwdev,
 6007				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_GO);
 6008	} else { /* dedicated-antenna */
 6009		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GO);
 6010	}
 6011}
 6012
 6013static void _action_wl_2g_gc(struct rtw89_dev *rtwdev)
 6014{
 6015	struct rtw89_btc *btc = &rtwdev->btc;
 6016
 6017	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 6018
 6019	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 6020		_action_by_bt(rtwdev);
 6021	} else {/* dedicated-antenna */
 6022		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC);
 6023	}
 6024}
 6025
 6026static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
 6027{
 6028	struct rtw89_btc *btc = &rtwdev->btc;
 6029
 6030	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
 6031
 6032	if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
 6033		if (btc->cx.bt.link_info.profile_cnt.now == 0)
 6034			_set_policy(rtwdev,
 6035				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
 6036		else
 6037			_set_policy(rtwdev,
 6038				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_NAN);
 6039	} else { /* dedicated-antenna */
 6040		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_NAN);
 6041	}
 6042}
 6043
 6044static u32 _read_scbd(struct rtw89_dev *rtwdev)
 6045{
 6046	const struct rtw89_chip_info *chip = rtwdev->chip;
 6047	struct rtw89_btc *btc = &rtwdev->btc;
 6048	u32 scbd_val = 0;
 6049
 6050	if (!chip->scbd)
 6051		return 0;
 6052
 6053	scbd_val = rtw89_mac_get_sb(rtwdev);
 6054	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], read scbd: 0x%08x\n",
 6055		    scbd_val);
 6056
 6057	btc->cx.cnt_bt[BTC_BCNT_SCBDREAD]++;
 6058	return scbd_val;
 6059}
 6060
 6061static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state)
 6062{
 6063	const struct rtw89_chip_info *chip = rtwdev->chip;
 6064	struct rtw89_btc *btc = &rtwdev->btc;
 6065	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 6066	u32 scbd_val = 0;
 6067	u8 force_exec = false;
 6068
 6069	if (!chip->scbd)
 6070		return;
 6071
 6072	scbd_val = state ? wl->scbd | val : wl->scbd & ~val;
 6073
 6074	if (val & BTC_WSCB_ACTIVE || val & BTC_WSCB_ON)
 6075		force_exec = true;
 6076
 6077	if (scbd_val != wl->scbd || force_exec) {
 6078		wl->scbd = scbd_val;
 6079		wl->scbd_change = true;
 6080	}
 6081}
 6082
 6083static u8
 6084_update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh)
 6085{
 6086	const struct rtw89_chip_info *chip = rtwdev->chip;
 6087	u8 next_state, tol = chip->rssi_tol;
 6088
 6089	if (pre_state == BTC_RSSI_ST_LOW ||
 6090	    pre_state == BTC_RSSI_ST_STAY_LOW) {
 6091		if (rssi >= (thresh + tol))
 6092			next_state = BTC_RSSI_ST_HIGH;
 6093		else
 6094			next_state = BTC_RSSI_ST_STAY_LOW;
 6095	} else {
 6096		if (rssi < thresh)
 6097			next_state = BTC_RSSI_ST_LOW;
 6098		else
 6099			next_state = BTC_RSSI_ST_STAY_HIGH;
 6100	}
 6101
 6102	return next_state;
 6103}
 6104
 6105static
 6106void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
 6107{
 6108	struct rtw89_btc *btc = &rtwdev->btc;
 6109
 6110	btc->cx.wl.dbcc_info.real_band[phy_idx] =
 6111		btc->cx.wl.scan_info.phy_map & BIT(phy_idx) ?
 6112		btc->cx.wl.dbcc_info.scan_band[phy_idx] :
 6113		btc->cx.wl.dbcc_info.op_band[phy_idx];
 6114}
 6115
 6116static void _update_wl_info(struct rtw89_dev *rtwdev)
 6117{
 6118	struct rtw89_btc *btc = &rtwdev->btc;
 6119	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 6120	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
 6121	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 6122	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 6123	u8 i, cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
 6124	u8 cnt_2g = 0, cnt_5g = 0, phy;
 6125	u32 wl_2g_ch[2] = {0}, wl_5g_ch[2] = {0};
 6126	bool b2g = false, b5g = false, client_joined = false;
 6127
 6128	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
 6129
 6130	for (i = 0; i < RTW89_PORT_NUM; i++) {
 6131		/* check if role active? */
 6132		if (!wl_linfo[i].active)
 6133			continue;
 6134
 6135		cnt_active++;
 6136		wl_rinfo->active_role[cnt_active - 1].role = wl_linfo[i].role;
 6137		wl_rinfo->active_role[cnt_active - 1].pid = wl_linfo[i].pid;
 6138		wl_rinfo->active_role[cnt_active - 1].phy = wl_linfo[i].phy;
 6139		wl_rinfo->active_role[cnt_active - 1].band = wl_linfo[i].band;
 6140		wl_rinfo->active_role[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
 6141		wl_rinfo->active_role[cnt_active - 1].connected = 0;
 6142
 6143		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
 6144
 6145		phy = wl_linfo[i].phy;
 6146
 6147		/* check dbcc role */
 6148		if (rtwdev->dbcc_en && phy < RTW89_PHY_NUM) {
 6149			wl_dinfo->role[phy] = wl_linfo[i].role;
 6150			wl_dinfo->op_band[phy] = wl_linfo[i].band;
 6151			_update_dbcc_band(rtwdev, phy);
 6152			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 6153		}
 6154
 6155		if (wl_linfo[i].connected == MLME_NO_LINK) {
 6156			continue;
 6157		} else if (wl_linfo[i].connected == MLME_LINKING) {
 6158			cnt_connecting++;
 6159		} else {
 6160			cnt_connect++;
 6161			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
 6162			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
 6163			     wl_linfo[i].client_cnt > 1)
 6164				client_joined = true;
 6165		}
 6166
 6167		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
 6168		wl_rinfo->active_role[cnt_active - 1].ch = wl_linfo[i].ch;
 6169		wl_rinfo->active_role[cnt_active - 1].bw = wl_linfo[i].bw;
 6170		wl_rinfo->active_role[cnt_active - 1].connected = 1;
 6171
 6172		/* only care 2 roles + BT coex */
 6173		if (wl_linfo[i].band != RTW89_BAND_2G) {
 6174			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
 6175				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
 6176			cnt_5g++;
 6177			b5g = true;
 6178		} else {
 6179			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
 6180				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
 6181			cnt_2g++;
 6182			b2g = true;
 6183		}
 6184	}
 6185
 6186	wl_rinfo->connect_cnt = cnt_connect;
 6187
 6188	/* Be careful to change the following sequence!! */
 6189	if (cnt_connect == 0) {
 6190		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6191		wl_rinfo->role_map.role.none = 1;
 6192	} else if (!b2g && b5g) {
 6193		wl_rinfo->link_mode = BTC_WLINK_5G;
 6194	} else if (wl_rinfo->role_map.role.nan) {
 6195		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
 6196	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
 6197		wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6198	} else  if (b2g && b5g && cnt_connect == 2) {
 6199		if (rtwdev->dbcc_en) {
 6200			switch (wl_dinfo->role[RTW89_PHY_0]) {
 6201			case RTW89_WIFI_ROLE_STATION:
 6202				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6203				break;
 6204			case RTW89_WIFI_ROLE_P2P_GO:
 6205				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6206				break;
 6207			case RTW89_WIFI_ROLE_P2P_CLIENT:
 6208				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6209				break;
 6210			case RTW89_WIFI_ROLE_AP:
 6211				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6212				break;
 6213			default:
 6214				wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6215				break;
 6216			}
 6217		} else {
 6218			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
 6219		}
 6220	} else if (!b5g && cnt_connect == 2) {
 6221		if (wl_rinfo->role_map.role.station &&
 6222		    (wl_rinfo->role_map.role.p2p_go ||
 6223		    wl_rinfo->role_map.role.p2p_gc ||
 6224		    wl_rinfo->role_map.role.ap)) {
 6225			if (wl_2g_ch[0] == wl_2g_ch[1])
 6226				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
 6227			else
 6228				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6229		} else {
 6230			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6231		}
 6232	} else if (!b5g && cnt_connect == 1) {
 6233		if (wl_rinfo->role_map.role.station)
 6234			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6235		else if (wl_rinfo->role_map.role.ap)
 6236			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6237		else if (wl_rinfo->role_map.role.p2p_go)
 6238			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6239		else if (wl_rinfo->role_map.role.p2p_gc)
 6240			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6241		else
 6242			wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6243	}
 6244
 6245	/* if no client_joined, don't care P2P-GO/AP role */
 6246	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
 6247		if (!client_joined) {
 6248			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
 6249			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
 6250				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6251				wl_rinfo->connect_cnt = 1;
 6252			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
 6253				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
 6254				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6255				wl_rinfo->connect_cnt = 0;
 6256			}
 6257		}
 6258	}
 6259
 6260	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 6261		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
 6262		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
 6263
 6264	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 6265}
 6266
 6267static void _update_wl_info_v1(struct rtw89_dev *rtwdev)
 6268{
 6269	struct rtw89_btc *btc = &rtwdev->btc;
 6270	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 6271	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
 6272	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
 6273	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 6274	u8 cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
 6275	u8 cnt_2g = 0, cnt_5g = 0, phy;
 6276	u32 wl_2g_ch[2] = {}, wl_5g_ch[2] = {};
 6277	bool b2g = false, b5g = false, client_joined = false;
 6278	u8 i;
 6279
 6280	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
 6281
 6282	for (i = 0; i < RTW89_PORT_NUM; i++) {
 6283		if (!wl_linfo[i].active)
 6284			continue;
 6285
 6286		cnt_active++;
 6287		wl_rinfo->active_role_v1[cnt_active - 1].role = wl_linfo[i].role;
 6288		wl_rinfo->active_role_v1[cnt_active - 1].pid = wl_linfo[i].pid;
 6289		wl_rinfo->active_role_v1[cnt_active - 1].phy = wl_linfo[i].phy;
 6290		wl_rinfo->active_role_v1[cnt_active - 1].band = wl_linfo[i].band;
 6291		wl_rinfo->active_role_v1[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
 6292		wl_rinfo->active_role_v1[cnt_active - 1].connected = 0;
 6293
 6294		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
 6295
 6296		phy = wl_linfo[i].phy;
 6297
 6298		if (rtwdev->dbcc_en && phy < RTW89_PHY_NUM) {
 6299			wl_dinfo->role[phy] = wl_linfo[i].role;
 6300			wl_dinfo->op_band[phy] = wl_linfo[i].band;
 6301			_update_dbcc_band(rtwdev, phy);
 6302			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 6303		}
 6304
 6305		if (wl_linfo[i].connected == MLME_NO_LINK) {
 6306			continue;
 6307		} else if (wl_linfo[i].connected == MLME_LINKING) {
 6308			cnt_connecting++;
 6309		} else {
 6310			cnt_connect++;
 6311			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
 6312			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
 6313			     wl_linfo[i].client_cnt > 1)
 6314				client_joined = true;
 6315		}
 6316
 6317		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
 6318		wl_rinfo->active_role_v1[cnt_active - 1].ch = wl_linfo[i].ch;
 6319		wl_rinfo->active_role_v1[cnt_active - 1].bw = wl_linfo[i].bw;
 6320		wl_rinfo->active_role_v1[cnt_active - 1].connected = 1;
 6321
 6322		/* only care 2 roles + BT coex */
 6323		if (wl_linfo[i].band != RTW89_BAND_2G) {
 6324			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
 6325				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
 6326			cnt_5g++;
 6327			b5g = true;
 6328		} else {
 6329			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
 6330				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
 6331			cnt_2g++;
 6332			b2g = true;
 6333		}
 6334	}
 6335
 6336	wl_rinfo->connect_cnt = cnt_connect;
 6337
 6338	/* Be careful to change the following sequence!! */
 6339	if (cnt_connect == 0) {
 6340		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6341		wl_rinfo->role_map.role.none = 1;
 6342	} else if (!b2g && b5g) {
 6343		wl_rinfo->link_mode = BTC_WLINK_5G;
 6344	} else if (wl_rinfo->role_map.role.nan) {
 6345		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
 6346	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
 6347		wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6348	} else  if (b2g && b5g && cnt_connect == 2) {
 6349		if (rtwdev->dbcc_en) {
 6350			switch (wl_dinfo->role[RTW89_PHY_0]) {
 6351			case RTW89_WIFI_ROLE_STATION:
 6352				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6353				break;
 6354			case RTW89_WIFI_ROLE_P2P_GO:
 6355				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6356				break;
 6357			case RTW89_WIFI_ROLE_P2P_CLIENT:
 6358				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6359				break;
 6360			case RTW89_WIFI_ROLE_AP:
 6361				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6362				break;
 6363			default:
 6364				wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6365				break;
 6366			}
 6367		} else {
 6368			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
 6369		}
 6370	} else if (!b5g && cnt_connect == 2) {
 6371		if (wl_rinfo->role_map.role.station &&
 6372		    (wl_rinfo->role_map.role.p2p_go ||
 6373		    wl_rinfo->role_map.role.p2p_gc ||
 6374		    wl_rinfo->role_map.role.ap)) {
 6375			if (wl_2g_ch[0] == wl_2g_ch[1])
 6376				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
 6377			else
 6378				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6379		} else {
 6380			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6381		}
 6382	} else if (!b5g && cnt_connect == 1) {
 6383		if (wl_rinfo->role_map.role.station)
 6384			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6385		else if (wl_rinfo->role_map.role.ap)
 6386			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6387		else if (wl_rinfo->role_map.role.p2p_go)
 6388			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6389		else if (wl_rinfo->role_map.role.p2p_gc)
 6390			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6391		else
 6392			wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6393	}
 6394
 6395	/* if no client_joined, don't care P2P-GO/AP role */
 6396	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
 6397		if (!client_joined) {
 6398			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
 6399			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
 6400				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6401				wl_rinfo->connect_cnt = 1;
 6402			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
 6403				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
 6404				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6405				wl_rinfo->connect_cnt = 0;
 6406			}
 6407		}
 6408	}
 6409
 6410	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 6411		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
 6412		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
 6413
 6414	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 6415}
 6416
 6417static void _update_wl_info_v2(struct rtw89_dev *rtwdev)
 6418{
 6419	struct rtw89_btc *btc = &rtwdev->btc;
 6420	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 6421	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
 6422	struct rtw89_btc_wl_role_info_v2 *wl_rinfo = &wl->role_info_v2;
 6423	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 6424	u8 cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
 6425	u8 cnt_2g = 0, cnt_5g = 0, phy;
 6426	u32 wl_2g_ch[2] = {}, wl_5g_ch[2] = {};
 6427	bool b2g = false, b5g = false, client_joined = false;
 6428	u8 i;
 6429
 6430	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
 6431
 6432	for (i = 0; i < RTW89_PORT_NUM; i++) {
 6433		if (!wl_linfo[i].active)
 6434			continue;
 6435
 6436		cnt_active++;
 6437		wl_rinfo->active_role_v2[cnt_active - 1].role = wl_linfo[i].role;
 6438		wl_rinfo->active_role_v2[cnt_active - 1].pid = wl_linfo[i].pid;
 6439		wl_rinfo->active_role_v2[cnt_active - 1].phy = wl_linfo[i].phy;
 6440		wl_rinfo->active_role_v2[cnt_active - 1].band = wl_linfo[i].band;
 6441		wl_rinfo->active_role_v2[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
 6442		wl_rinfo->active_role_v2[cnt_active - 1].connected = 0;
 6443
 6444		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
 6445
 6446		phy = wl_linfo[i].phy;
 6447
 6448		if (rtwdev->dbcc_en && phy < RTW89_PHY_NUM) {
 6449			wl_dinfo->role[phy] = wl_linfo[i].role;
 6450			wl_dinfo->op_band[phy] = wl_linfo[i].band;
 6451			_update_dbcc_band(rtwdev, phy);
 6452			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 6453		}
 6454
 6455		if (wl_linfo[i].connected == MLME_NO_LINK) {
 6456			continue;
 6457		} else if (wl_linfo[i].connected == MLME_LINKING) {
 6458			cnt_connecting++;
 6459		} else {
 6460			cnt_connect++;
 6461			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
 6462			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
 6463			     wl_linfo[i].client_cnt > 1)
 6464				client_joined = true;
 6465		}
 6466
 6467		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
 6468		wl_rinfo->active_role_v2[cnt_active - 1].ch = wl_linfo[i].ch;
 6469		wl_rinfo->active_role_v2[cnt_active - 1].bw = wl_linfo[i].bw;
 6470		wl_rinfo->active_role_v2[cnt_active - 1].connected = 1;
 6471
 6472		/* only care 2 roles + BT coex */
 6473		if (wl_linfo[i].band != RTW89_BAND_2G) {
 6474			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
 6475				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
 6476			cnt_5g++;
 6477			b5g = true;
 6478		} else {
 6479			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
 6480				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
 6481			cnt_2g++;
 6482			b2g = true;
 6483		}
 6484	}
 6485
 6486	wl_rinfo->connect_cnt = cnt_connect;
 6487
 6488	/* Be careful to change the following sequence!! */
 6489	if (cnt_connect == 0) {
 6490		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6491		wl_rinfo->role_map.role.none = 1;
 6492	} else if (!b2g && b5g) {
 6493		wl_rinfo->link_mode = BTC_WLINK_5G;
 6494	} else if (wl_rinfo->role_map.role.nan) {
 6495		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
 6496	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
 6497		wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6498	} else  if (b2g && b5g && cnt_connect == 2) {
 6499		if (rtwdev->dbcc_en) {
 6500			switch (wl_dinfo->role[RTW89_PHY_0]) {
 6501			case RTW89_WIFI_ROLE_STATION:
 6502				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6503				break;
 6504			case RTW89_WIFI_ROLE_P2P_GO:
 6505				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6506				break;
 6507			case RTW89_WIFI_ROLE_P2P_CLIENT:
 6508				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6509				break;
 6510			case RTW89_WIFI_ROLE_AP:
 6511				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6512				break;
 6513			default:
 6514				wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6515				break;
 6516			}
 6517		} else {
 6518			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
 6519		}
 6520	} else if (!b5g && cnt_connect == 2) {
 6521		if (wl_rinfo->role_map.role.station &&
 6522		    (wl_rinfo->role_map.role.p2p_go ||
 6523		    wl_rinfo->role_map.role.p2p_gc ||
 6524		    wl_rinfo->role_map.role.ap)) {
 6525			if (wl_2g_ch[0] == wl_2g_ch[1])
 6526				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
 6527			else
 6528				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6529		} else {
 6530			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
 6531		}
 6532	} else if (!b5g && cnt_connect == 1) {
 6533		if (wl_rinfo->role_map.role.station)
 6534			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6535		else if (wl_rinfo->role_map.role.ap)
 6536			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
 6537		else if (wl_rinfo->role_map.role.p2p_go)
 6538			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
 6539		else if (wl_rinfo->role_map.role.p2p_gc)
 6540			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
 6541		else
 6542			wl_rinfo->link_mode = BTC_WLINK_OTHER;
 6543	}
 6544
 6545	/* if no client_joined, don't care P2P-GO/AP role */
 6546	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
 6547		if (!client_joined) {
 6548			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
 6549			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
 6550				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 6551				wl_rinfo->connect_cnt = 1;
 6552			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
 6553				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
 6554				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 6555				wl_rinfo->connect_cnt = 0;
 6556			}
 6557		}
 6558	}
 6559
 6560	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 6561		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
 6562		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
 6563
 6564	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 6565}
 6566
 6567#define BTC_CHK_HANG_MAX 3
 6568#define BTC_SCB_INV_VALUE GENMASK(31, 0)
 6569
 6570static u8 _get_role_link_mode(u8 role)
 6571{
 6572	switch (role) {
 6573	case RTW89_WIFI_ROLE_STATION:
 6574		return BTC_WLINK_2G_STA;
 6575	case RTW89_WIFI_ROLE_P2P_GO:
 6576		return BTC_WLINK_2G_GO;
 6577	case RTW89_WIFI_ROLE_P2P_CLIENT:
 6578		return BTC_WLINK_2G_GC;
 6579	case RTW89_WIFI_ROLE_AP:
 6580		return BTC_WLINK_2G_AP;
 6581	default:
 6582		return BTC_WLINK_OTHER;
 6583	}
 6584}
 6585
 6586static bool _chk_role_ch_group(const struct rtw89_btc_chdef *r1,
 6587			       const struct rtw89_btc_chdef *r2)
 6588{
 6589	if (r1->chan != r2->chan) { /* primary ch is different */
 6590		return false;
 6591	} else if (r1->bw == RTW89_CHANNEL_WIDTH_40 &&
 6592		   r2->bw == RTW89_CHANNEL_WIDTH_40) {
 6593		if (r1->offset != r2->offset)
 6594			return false;
 6595	}
 6596	return true;
 6597}
 6598
 6599static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch,
 6600		    u8 *phy, u8 *role, u8 link_cnt)
 6601{
 6602	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 6603	struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7;
 6604	struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8;
 6605	bool is_2g_ch_exist = false, is_multi_role_in_2g_phy = false;
 6606	u8 j, k, dbcc_2g_cid, dbcc_2g_cid2, dbcc_2g_phy, pta_req_band;
 6607
 6608	/* find out the 2G-PHY by connect-id ->ch  */
 6609	for (j = 0; j < link_cnt; j++) {
 6610		if (ch[j].center_ch <= 14) {
 6611			is_2g_ch_exist = true;
 6612			break;
 6613		}
 6614	}
 6615
 6616	/* If no any 2G-port exist, it's impossible because 5G-exclude */
 6617	if (!is_2g_ch_exist)
 6618		return BTC_WLINK_5G;
 6619
 6620	dbcc_2g_cid = j;
 6621	dbcc_2g_phy = phy[dbcc_2g_cid];
 6622
 6623	if (dbcc_2g_phy == RTW89_PHY_1)
 6624		pta_req_band = RTW89_PHY_1;
 6625	else
 6626		pta_req_band = RTW89_PHY_0;
 6627
 6628	if (rtwdev->btc.ver->fwlrole == 7) {
 6629		rinfo_v7->dbcc_2g_phy = dbcc_2g_phy;
 6630	} else if (rtwdev->btc.ver->fwlrole == 8) {
 6631		rinfo_v8->dbcc_2g_phy = dbcc_2g_phy;
 6632		rinfo_v8->pta_req_band = pta_req_band;
 6633	}
 6634
 6635	/* connect_cnt <= 2 */
 6636	if (link_cnt < BTC_TDMA_WLROLE_MAX)
 6637		return (_get_role_link_mode((role[dbcc_2g_cid])));
 6638
 6639	/* find the other-port in the 2G-PHY, ex: PHY-0:6G, PHY1: mcc/scc */
 6640	for (k = 0; k < link_cnt; k++) {
 6641		if (k == dbcc_2g_cid)
 6642			continue;
 6643
 6644		if (phy[k] == dbcc_2g_phy) {
 6645			is_multi_role_in_2g_phy = true;
 6646			dbcc_2g_cid2 = k;
 6647			break;
 6648		}
 6649	}
 6650
 6651	/* Single-role in 2G-PHY */
 6652	if (!is_multi_role_in_2g_phy)
 6653		return (_get_role_link_mode(role[dbcc_2g_cid]));
 6654
 6655	/* 2-role in 2G-PHY */
 6656	if (ch[dbcc_2g_cid2].center_ch > 14)
 6657		return BTC_WLINK_25G_MCC;
 6658	else if (_chk_role_ch_group(&ch[dbcc_2g_cid], &ch[dbcc_2g_cid2]))
 6659		return BTC_WLINK_2G_SCC;
 6660	else
 6661		return BTC_WLINK_2G_MCC;
 6662}
 6663
 6664static void _update_role_link_mode(struct rtw89_dev *rtwdev,
 6665				   bool client_joined, u32 noa)
 6666{
 6667	struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &rtwdev->btc.cx.wl.role_info_v8;
 6668	struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &rtwdev->btc.cx.wl.role_info_v7;
 6669	u8 role_ver = rtwdev->btc.ver->fwlrole;
 6670	u32 type = BTC_WLMROLE_NONE, dur = 0;
 6671	u8 link_mode, connect_cnt;
 6672	u32 wl_role;
 6673
 6674	if (role_ver == 7) {
 6675		wl_role = rinfo_v7->role_map;
 6676		link_mode = rinfo_v7->link_mode;
 6677		connect_cnt = rinfo_v7->connect_cnt;
 6678	} else if (role_ver == 8) {
 6679		wl_role = rinfo_v8->role_map;
 6680		link_mode = rinfo_v8->link_mode;
 6681		connect_cnt = rinfo_v8->connect_cnt;
 6682	} else {
 6683		return;
 6684	}
 6685
 6686	/* if no client_joined, don't care P2P-GO/AP role */
 6687	if (((wl_role & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
 6688	     (wl_role & BIT(RTW89_WIFI_ROLE_AP))) && !client_joined) {
 6689		if (link_mode == BTC_WLINK_2G_SCC) {
 6690			if (role_ver == 7) {
 6691				rinfo_v7->link_mode = BTC_WLINK_2G_STA;
 6692				rinfo_v7->connect_cnt--;
 6693			} else if (role_ver == 8) {
 6694				rinfo_v8->link_mode = BTC_WLINK_2G_STA;
 6695				rinfo_v8->connect_cnt--;
 6696			}
 6697		} else if (link_mode == BTC_WLINK_2G_GO ||
 6698			   link_mode == BTC_WLINK_2G_AP) {
 6699			if (role_ver == 7) {
 6700				rinfo_v7->link_mode = BTC_WLINK_NOLINK;
 6701				rinfo_v7->connect_cnt--;
 6702			} else if (role_ver == 8) {
 6703				rinfo_v8->link_mode = BTC_WLINK_NOLINK;
 6704				rinfo_v8->connect_cnt--;
 6705			}
 6706		}
 6707	}
 6708
 6709	/* Identify 2-Role type  */
 6710	if (connect_cnt >= 2 &&
 6711	    (link_mode == BTC_WLINK_2G_SCC ||
 6712	     link_mode == BTC_WLINK_2G_MCC ||
 6713	     link_mode == BTC_WLINK_25G_MCC ||
 6714	     link_mode == BTC_WLINK_5G)) {
 6715		if ((wl_role & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
 6716		    (wl_role & BIT(RTW89_WIFI_ROLE_AP)))
 6717			type = noa ? BTC_WLMROLE_STA_GO_NOA : BTC_WLMROLE_STA_GO;
 6718		else if (wl_role & BIT(RTW89_WIFI_ROLE_P2P_CLIENT))
 6719			type = noa ? BTC_WLMROLE_STA_GC_NOA : BTC_WLMROLE_STA_GC;
 6720		else
 6721			type = BTC_WLMROLE_STA_STA;
 6722
 6723		dur = noa;
 6724	}
 6725
 6726	if (role_ver == 7) {
 6727		rinfo_v7->mrole_type = type;
 6728		rinfo_v7->mrole_noa_duration = dur;
 6729	} else if (role_ver == 8) {
 6730		rinfo_v8->mrole_type = type;
 6731		rinfo_v8->mrole_noa_duration = dur;
 6732	}
 6733}
 6734
 6735static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid)
 6736{
 6737	struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER];
 6738	struct rtw89_btc *btc = &rtwdev->btc;
 6739	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 6740	struct rtw89_btc_wl_role_info_v7 *wl_rinfo = &wl->role_info_v7;
 6741	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
 6742	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
 6743	struct rtw89_btc_wl_active_role_v7 *act_role = NULL;
 6744	u8 i, mode, cnt = 0, cnt_2g = 0, cnt_5g = 0, phy_now = RTW89_PHY_NUM, phy_dbcc;
 6745	bool b2g = false, b5g = false, client_joined = false, client_inc_2g = false;
 6746	u8 client_cnt_last[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 6747	u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 6748	u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 6749	u8 mac = RTW89_MAC_0, dbcc_2g_phy = RTW89_PHY_0;
 6750	u32 noa_duration = 0;
 6751
 6752	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
 6753
 6754	for (i = 0; i < RTW89_PORT_NUM; i++) {
 6755		if (!wl_linfo[i].active || wl_linfo[i].phy >= RTW89_PHY_NUM)
 6756			continue;
 6757
 6758		act_role = &wl_rinfo->active_role[i];
 6759		act_role->role = wl_linfo[i].role;
 6760
 6761		/* check if role connect? */
 6762		if (wl_linfo[i].connected == MLME_NO_LINK) {
 6763			act_role->connected = 0;
 6764			continue;
 6765		} else if (wl_linfo[i].connected == MLME_LINKING) {
 6766			continue;
 6767		}
 6768
 6769		cnt++;
 6770		act_role->connected = 1;
 6771		act_role->pid = wl_linfo[i].pid;
 6772		act_role->phy = wl_linfo[i].phy;
 6773		act_role->band = wl_linfo[i].band;
 6774		act_role->ch = wl_linfo[i].ch;
 6775		act_role->bw = wl_linfo[i].bw;
 6776		act_role->noa = wl_linfo[i].noa;
 6777		act_role->noa_dur = wl_linfo[i].noa_duration;
 6778		cid_ch[cnt - 1] = wl_linfo[i].chdef;
 6779		cid_phy[cnt - 1] = wl_linfo[i].phy;
 6780		cid_role[cnt - 1] = wl_linfo[i].role;
 6781		wl_rinfo->role_map |= BIT(wl_linfo[i].role);
 6782
 6783		if (rid == i)
 6784			phy_now = act_role->phy;
 6785
 6786		if (wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
 6787		    wl_linfo[i].role == RTW89_WIFI_ROLE_AP) {
 6788			if (wl_linfo[i].client_cnt > 1)
 6789				client_joined = true;
 6790			if (client_cnt_last[i] < wl_linfo[i].client_cnt &&
 6791			    wl_linfo[i].chdef.band == RTW89_BAND_2G)
 6792				client_inc_2g = true;
 6793			act_role->client_cnt = wl_linfo[i].client_cnt;
 6794		} else {
 6795			act_role->client_cnt = 0;
 6796		}
 6797
 6798		if (act_role->noa && act_role->noa_dur > 0)
 6799			noa_duration = act_role->noa_dur;
 6800
 6801		if (rtwdev->dbcc_en) {
 6802			phy_dbcc = wl_linfo[i].phy;
 6803			wl_dinfo->role[phy_dbcc] |= BIT(wl_linfo[i].role);
 6804			wl_dinfo->op_band[phy_dbcc] = wl_linfo[i].chdef.band;
 6805		}
 6806
 6807		if (wl_linfo[i].chdef.band != RTW89_BAND_2G) {
 6808			cnt_5g++;
 6809			b5g = true;
 6810		} else {
 6811			if (((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
 6812			      wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
 6813			     client_joined) ||
 6814			    wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_CLIENT)
 6815				wl_rinfo->p2p_2g = 1;
 6816
 6817			if ((wl_linfo[i].mode & BIT(BTC_WL_MODE_11B)) ||
 6818			    (wl_linfo[i].mode & BIT(BTC_WL_MODE_11G)))
 6819				wl->bg_mode = 1;
 6820			else if (wl_linfo[i].mode & BIT(BTC_WL_MODE_HE))
 6821				wl->he_mode = true;
 6822
 6823			cnt_2g++;
 6824			b2g = true;
 6825		}
 6826
 6827		if (act_role->band == RTW89_BAND_5G && act_role->ch >= 100)
 6828			wl->is_5g_hi_channel = 1;
 6829		else
 6830			wl->is_5g_hi_channel = 0;
 6831	}
 6832
 6833	wl_rinfo->connect_cnt = cnt;
 6834	wl->client_cnt_inc_2g = client_inc_2g;
 6835
 6836	if (cnt == 0) {
 6837		mode = BTC_WLINK_NOLINK;
 6838		wl_rinfo->role_map = BIT(RTW89_WIFI_ROLE_NONE);
 6839	} else if (!b2g && b5g) {
 6840		mode = BTC_WLINK_5G;
 6841	} else if (wl_rinfo->role_map & BIT(RTW89_WIFI_ROLE_NAN)) {
 6842		mode = BTC_WLINK_2G_NAN;
 6843	} else if (cnt > BTC_TDMA_WLROLE_MAX) {
 6844		mode = BTC_WLINK_OTHER;
 6845	} else if (rtwdev->dbcc_en) {
 6846		mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt);
 6847
 6848		/* correct 2G-located PHY band for gnt ctrl */
 6849		if (dbcc_2g_phy < RTW89_PHY_NUM)
 6850			wl_dinfo->op_band[dbcc_2g_phy] = RTW89_BAND_2G;
 6851	} else if (b2g && b5g && cnt == 2) {
 6852		mode = BTC_WLINK_25G_MCC;
 6853	} else if (!b5g && cnt == 2) { /* cnt_connect = 2 */
 6854		if (_chk_role_ch_group(&cid_ch[0], &cid_ch[cnt - 1]))
 6855			mode = BTC_WLINK_2G_SCC;
 6856		else
 6857			mode = BTC_WLINK_2G_MCC;
 6858	} else if (!b5g && cnt == 1) { /* cnt_connect = 1 */
 6859		mode = _get_role_link_mode(cid_role[0]);
 6860	} else {
 6861		mode = BTC_WLINK_NOLINK;
 6862	}
 6863
 6864	wl_rinfo->link_mode = mode;
 6865	_update_role_link_mode(rtwdev, client_joined, noa_duration);
 6866
 6867	/* todo DBCC related event */
 6868	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] wl_info phy_now=%d\n", phy_now);
 6869	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 6870		    "[BTC] rlink cnt_2g=%d cnt_5g=%d\n", cnt_2g, cnt_5g);
 6871
 6872	if (wl_rinfo->dbcc_en != rtwdev->dbcc_en) {
 6873		wl_rinfo->dbcc_chg = 1;
 6874		wl_rinfo->dbcc_en = rtwdev->dbcc_en;
 6875		btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++;
 6876	}
 6877
 6878	if (rtwdev->dbcc_en) {
 6879		wl_rinfo->dbcc_2g_phy = dbcc_2g_phy;
 6880
 6881		if (dbcc_2g_phy == RTW89_PHY_1)
 6882			mac = RTW89_MAC_1;
 6883
 6884		_update_dbcc_band(rtwdev, RTW89_PHY_0);
 6885		_update_dbcc_band(rtwdev, RTW89_PHY_1);
 6886	}
 6887	_wl_req_mac(rtwdev, mac);
 6888	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 6889}
 6890
 6891static u8 _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type)
 6892{
 6893	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 6894	struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info;
 6895	u8 mode = BTC_WLINK_NOLINK;
 6896
 6897	switch (type) {
 6898	case RTW89_MR_WTYPE_NONE: /* no-link */
 6899		mode = BTC_WLINK_NOLINK;
 6900		break;
 6901	case RTW89_MR_WTYPE_NONMLD:  /* Non_MLO 1-role 2+0/0+2 */
 6902	case RTW89_MR_WTYPE_MLD1L1R: /* MLO only-1 link 2+0/0+2 */
 6903		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
 6904			mode = BTC_WLINK_5G;
 6905		} else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) {
 6906			mode = BTC_WLINK_2G_GO;
 6907		} else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) {
 6908			if (wl->role_info_v8.p2p_2g)
 6909				mode = BTC_WLINK_2G_GC;
 6910			else
 6911				mode = BTC_WLINK_2G_STA;
 6912		}
 6913		break;
 6914	case RTW89_MR_WTYPE_NONMLD_NONMLD: /* Non_MLO 2-role 2+0/0+2 */
 6915	case RTW89_MR_WTYPE_MLD1L1R_NONMLD: /* MLO only-1 link + P2P 2+0/0+2 */
 6916		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
 6917			mode = BTC_WLINK_5G;
 6918		} else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_5GHZ ||
 6919			   mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_6GHZ) {
 6920			mode = BTC_WLINK_25G_MCC;
 6921		} else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ) {
 6922			mode = BTC_WLINK_2G_MCC;
 6923		} else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_2GHZ) {
 6924			mode = BTC_WLINK_2G_SCC;
 6925		}
 6926		break;
 6927	case RTW89_MR_WTYPE_MLD2L1R: /* MLO_MLSR 2+0/0+2 */
 6928		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G)
 6929			mode = BTC_WLINK_5G;
 6930		else if (wl->role_info_v8.p2p_2g)
 6931			mode = BTC_WLINK_2G_GC;
 6932		else
 6933			mode = BTC_WLINK_2G_STA;
 6934		break;
 6935	case RTW89_MR_WTYPE_MLD2L1R_NONMLD: /* MLO_MLSR + P2P 2+0/0+2 */
 6936	case RTW89_MR_WTYPE_MLD2L2R_NONMLD: /* MLO_MLMR + P2P 1+1/2+2 */
 6937		/* driver may doze 1-link to
 6938		 * 2G+5G   -> TDMA slot switch by E2G/E5G
 6939		 * 5G only -> TDMA slot switch by E5G
 6940		 */
 6941		mode = BTC_WLINK_25G_MCC;
 6942		break;
 6943	case RTW89_MR_WTYPE_MLD2L2R: /* MLO_MLMR  1+1/2+2 */
 6944		if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) {
 6945			mode = BTC_WLINK_5G;
 6946		} else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) {
 6947			mode = BTC_WLINK_2G_GO;
 6948		} else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) {
 6949			if (wl->role_info_v8.p2p_2g)
 6950				mode = BTC_WLINK_2G_GC;
 6951			else
 6952				mode = BTC_WLINK_2G_STA;
 6953		}
 6954		break;
 6955	}
 6956	return mode;
 6957}
 6958
 6959static void _update_wl_mlo_info(struct rtw89_dev *rtwdev)
 6960{
 6961	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 6962	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 6963	struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info;
 6964	struct rtw89_mr_chanctx_info qinfo;
 6965	u8 track_band = RTW89_PHY_0;
 6966	u8 rf_band = RTW89_BAND_2G;
 6967	u8 i, type;
 6968
 6969	/* parse MLO info form PHL API for each HW-band */
 6970	for (i = RTW89_MAC_0; i <= RTW89_MAC_1; i++) {
 6971		memset(&qinfo, 0, sizeof(qinfo));
 6972
 6973		rtw89_query_mr_chanctx_info(rtwdev, i, &qinfo);
 6974		mlo_info->wmode[i] = qinfo.wmode;
 6975		mlo_info->ch_type[i] = qinfo.ctxtype;
 6976		mlo_info->wtype = qinfo.wtype;
 6977
 6978		if (mlo_info->ch_type[i] == RTW89_MR_CTX1_5GHZ ||
 6979		    mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ ||
 6980		    mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ_6GHZ)
 6981			mlo_info->hwb_rf_band[i] = RTW89_BAND_5G;
 6982		else if (mlo_info->ch_type[i] == RTW89_MR_CTX1_6GHZ ||
 6983			 mlo_info->ch_type[i] == RTW89_MR_CTX2_6GHZ)
 6984			mlo_info->hwb_rf_band[i] = RTW89_BAND_6G;
 6985		else /* check if "2G-included" or unknown in each HW-band */
 6986			mlo_info->hwb_rf_band[i] = RTW89_BAND_2G;
 6987	}
 6988
 6989	mlo_info->link_status = rtwdev->mlo_dbcc_mode;
 6990	type = mlo_info->wtype;
 6991
 6992	if (mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R ||
 6993	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R ||
 6994	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R ||
 6995	    mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R_NONMLD ||
 6996	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD ||
 6997	    mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R_NONMLD)
 6998		mlo_info->mlo_en = 1;
 6999	else
 7000		mlo_info->mlo_en = 0;
 7001
 7002	if (mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_NONE &&
 7003	    mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_UNKNOWN &&
 7004	    mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_NONE &&
 7005	    mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_UNKNOWN)
 7006		mlo_info->dual_hw_band_en = 1; /* two HW-hand link exist */
 7007	else
 7008		mlo_info->dual_hw_band_en = 0;
 7009
 7010	if (mlo_info->link_status == MLO_2_PLUS_0_2RF ||
 7011	    mlo_info->link_status == MLO_0_PLUS_2_2RF ||
 7012	    mlo_info->link_status == MLO_2_PLUS_2_2RF)
 7013		mlo_info->mlo_adie = 2;
 7014	else
 7015		mlo_info->mlo_adie = 1;
 7016
 7017	switch (mlo_info->link_status) {
 7018	default:
 7019	case MLO_2_PLUS_0_1RF: /* 2+0 */
 7020	case MLO_2_PLUS_0_2RF:
 7021		mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_0;
 7022		track_band = RTW89_MAC_0;
 7023		rf_band = mlo_info->hwb_rf_band[RTW89_MAC_0];
 7024		mlo_info->path_rf_band[BTC_RF_S0] = rf_band;
 7025		mlo_info->path_rf_band[BTC_RF_S1] = rf_band;
 7026
 7027		wl_rinfo->pta_req_band = RTW89_MAC_0;
 7028		wl_rinfo->dbcc_2g_phy = RTW89_PHY_0;
 7029		wl_rinfo->dbcc_en = 0;
 7030		break;
 7031	case MLO_0_PLUS_2_1RF: /* 0+2 */
 7032	case MLO_0_PLUS_2_2RF:
 7033		mlo_info->rf_combination = BTC_MLO_RF_0_PLUS_2;
 7034		track_band = RTW89_MAC_1;
 7035		rf_band = mlo_info->hwb_rf_band[RTW89_MAC_1];
 7036		mlo_info->path_rf_band[BTC_RF_S0] = rf_band;
 7037		mlo_info->path_rf_band[BTC_RF_S1] = rf_band;
 7038
 7039		wl_rinfo->pta_req_band = RTW89_MAC_1;
 7040		wl_rinfo->dbcc_2g_phy = RTW89_PHY_1;
 7041		wl_rinfo->dbcc_en = 0;
 7042		break;
 7043	case MLO_1_PLUS_1_1RF: /* 1+1 */
 7044	case MLO_1_PLUS_1_2RF: /* 1+1 */
 7045	case MLO_2_PLUS_2_2RF: /* 2+2 */
 7046	case DBCC_LEGACY: /* DBCC 1+1 */
 7047		if (mlo_info->link_status == MLO_2_PLUS_2_2RF)
 7048			mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_2;
 7049		else
 7050			mlo_info->rf_combination = BTC_MLO_RF_1_PLUS_1;
 7051
 7052		if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G)
 7053			track_band = RTW89_MAC_0;
 7054		else
 7055			track_band = RTW89_MAC_1;
 7056
 7057		mlo_info->path_rf_band[BTC_RF_S0] =
 7058					mlo_info->hwb_rf_band[RTW89_MAC_0];
 7059		mlo_info->path_rf_band[BTC_RF_S1] =
 7060					mlo_info->hwb_rf_band[RTW89_MAC_1];
 7061
 7062		/* Check ch count from ch_type @ 2.4G HW-band, and modify type */
 7063		if (mlo_info->ch_type[track_band] == RTW89_MR_CTX1_2GHZ)
 7064			type = RTW89_MR_WTYPE_NONMLD; /* only 1-role at 2G */
 7065		else
 7066			type = RTW89_MR_WTYPE_NONMLD_NONMLD;
 7067
 7068		if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G) {
 7069			wl_rinfo->pta_req_band = RTW89_MAC_0;
 7070			wl_rinfo->dbcc_2g_phy = RTW89_PHY_0;
 7071		} else {
 7072			wl_rinfo->pta_req_band = RTW89_MAC_1;
 7073			wl_rinfo->dbcc_2g_phy = RTW89_PHY_1;
 7074		}
 7075
 7076		if (mlo_info->wmode[RTW89_MAC_0] == RTW89_MR_WMODE_NONE &&
 7077		    mlo_info->wmode[RTW89_MAC_1] == RTW89_MR_WMODE_NONE)
 7078			wl_rinfo->dbcc_en = 0;
 7079		else
 7080			wl_rinfo->dbcc_en = 1;
 7081		break;
 7082	}
 7083
 7084	wl_rinfo->link_mode = _update_wl_link_mode(rtwdev, track_band, type);
 7085
 7086	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(), mode=%s, pta_band=%d",
 7087		    __func__, id_to_linkmode(wl_rinfo->link_mode),
 7088		    wl_rinfo->pta_req_band);
 7089}
 7090
 7091static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev)
 7092{
 7093	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 7094	struct rtw89_btc_wl_rlink *rlink = NULL;
 7095	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 7096	struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 7097	u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 7098	u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
 7099	bool b2g = false, b5g = false, outloop = false;
 7100	u8 mode = BTC_WLINK_NOLINK;
 7101	u8 cnt_2g = 0, cnt_5g = 0;
 7102	u8 i, j, cnt = 0;
 7103
 7104	for (j = RTW89_PHY_0; j < RTW89_PHY_NUM; j++) {
 7105		for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
 7106			rlink = &wl_rinfo->rlink[i][j];
 7107
 7108			if (!rlink->active || !rlink->connected)
 7109				continue;
 7110
 7111			if (cnt >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER) {
 7112				outloop = true;
 7113				break;
 7114			}
 7115
 7116			cid_ch[cnt] = wl->rlink_info[i][j].chdef;
 7117			cid_phy[cnt] = rlink->phy;
 7118			cid_role[cnt] = rlink->role;
 7119			cnt++;
 7120
 7121			if (rlink->rf_band != RTW89_BAND_2G) {
 7122				cnt_5g++;
 7123				b5g = true;
 7124			} else {
 7125				cnt_2g++;
 7126				b2g = true;
 7127			}
 7128		}
 7129		if (outloop)
 7130			break;
 7131	}
 7132
 7133	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7134		    "[BTC], %s(): cnt_2g=%d, cnt_5g=%d\n", __func__, cnt_2g, cnt_5g);
 7135
 7136	wl_rinfo->dbcc_en = rtwdev->dbcc_en;
 7137	/* Be careful to change the following sequence!! */
 7138	if (cnt == 0) {
 7139		mode = BTC_WLINK_NOLINK;
 7140	} else if (!b2g && b5g) {
 7141		mode = BTC_WLINK_5G;
 7142	} else if (wl_rinfo->dbcc_en) {
 7143		mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt);
 7144	} else if (b2g && b5g) {
 7145		mode = BTC_WLINK_25G_MCC;
 7146	} else if (!b5g && cnt >= 2) {
 7147		if (_chk_role_ch_group(&cid_ch[0], &cid_ch[1]))
 7148			mode = BTC_WLINK_2G_SCC;
 7149		else
 7150			mode = BTC_WLINK_2G_MCC;
 7151	} else if (!b5g) { /* cnt_connect = 1 */
 7152		mode = _get_role_link_mode(cid_role[0]);
 7153	}
 7154
 7155	wl_rinfo->link_mode = mode;
 7156}
 7157
 7158static void _modify_role_link_mode(struct rtw89_dev *rtwdev)
 7159{
 7160	struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
 7161	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 7162	u8 go_cleint_exist = wl->go_client_exist;
 7163	u8 link_mode = wl_rinfo->link_mode;
 7164	u32 role_map = wl_rinfo->role_map;
 7165	u8 noa_exist = wl->noa_exist;
 7166	u32 mrole = BTC_WLMROLE_NONE;
 7167
 7168	/* if no client_joined, don't care P2P-GO/AP role */
 7169	if (((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
 7170	     (role_map & BIT(RTW89_WIFI_ROLE_AP))) && !go_cleint_exist) {
 7171		if (link_mode == BTC_WLINK_2G_SCC) {
 7172			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
 7173		} else if (link_mode == BTC_WLINK_2G_GO ||
 7174			   link_mode == BTC_WLINK_2G_AP) {
 7175			wl_rinfo->link_mode = BTC_WLINK_NOLINK;
 7176		}
 7177	}
 7178
 7179	/* Identify 2-Role type */
 7180	if  (link_mode == BTC_WLINK_2G_SCC ||
 7181	     link_mode == BTC_WLINK_2G_MCC ||
 7182	     link_mode == BTC_WLINK_25G_MCC ||
 7183	     link_mode == BTC_WLINK_5G) {
 7184		if ((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
 7185		    (role_map & BIT(RTW89_WIFI_ROLE_AP))) {
 7186			if (noa_exist)
 7187				mrole = BTC_WLMROLE_STA_GO_NOA;
 7188			else
 7189				mrole = BTC_WLMROLE_STA_GO;
 7190		} else if (role_map & BIT(RTW89_WIFI_ROLE_P2P_CLIENT)) {
 7191			if (noa_exist)
 7192				mrole = BTC_WLMROLE_STA_GC_NOA;
 7193			else
 7194				mrole = BTC_WLMROLE_STA_GC;
 7195		} else {
 7196			mrole = BTC_WLMROLE_STA_STA;
 7197		}
 7198	}
 7199
 7200	wl_rinfo->mrole_type = mrole;
 7201
 7202	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7203		    "[BTC], %s(): link_mode=%s, mrole_type=%d\n", __func__,
 7204		    id_to_linkmode(wl_rinfo->link_mode), wl_rinfo->mrole_type);
 7205}
 7206
 7207static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id,
 7208			       enum btc_role_state state)
 7209{
 7210	struct rtw89_btc_wl_rlink *rlink = NULL;
 7211	struct rtw89_btc_wl_link_info *wl_linfo;
 7212	struct rtw89_btc *btc = &rtwdev->btc;
 7213	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7214	struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
 7215	bool client_joined = false, noa_exist = false, p2p_exist = false;
 7216	bool is_5g_hi_channel = false, bg_mode = false, dbcc_en_ori;
 7217	u8 i, j, link_mode_ori;
 7218	u32 role_map = 0;
 7219
 7220	if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id >= RTW89_MAC_NUM)
 7221		return;
 7222
 7223	/* Extract wl->link_info[role_id][rlink_id] to wl->role_info
 7224	 * role_id: role index
 7225	 * rlink_id: rlink index (= HW-band index)
 7226	 * pid: port_index
 7227	 */
 7228
 7229	wl_linfo = &wl->rlink_info[role_id][rlink_id];
 7230	rlink = &wl_rinfo->rlink[role_id][rlink_id];
 7231
 7232	rlink->role = wl_linfo->role;
 7233	rlink->active = wl_linfo->active; /* Doze or not */
 7234	rlink->pid = wl_linfo->pid;
 7235	rlink->phy = wl_linfo->phy;
 7236	rlink->rf_band = wl_linfo->band;
 7237	rlink->ch = wl_linfo->ch;
 7238	rlink->bw = wl_linfo->bw;
 7239	rlink->noa = wl_linfo->noa;
 7240	rlink->noa_dur = wl_linfo->noa_duration / 1000;
 7241	rlink->client_cnt = wl_linfo->client_cnt;
 7242	rlink->mode = wl_linfo->mode;
 7243
 7244	switch (wl_linfo->connected) {
 7245	case MLME_NO_LINK:
 7246		rlink->connected = 0;
 7247		break;
 7248	case MLME_LINKED:
 7249		rlink->connected = 1;
 7250		break;
 7251	default:
 7252		return;
 7253	}
 7254
 7255	for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) {
 7256		for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
 7257			rlink = &wl_rinfo->rlink[i][j];
 7258
 7259			if (!rlink->active || !rlink->connected)
 7260				continue;
 7261
 7262			role_map |= BIT(rlink->role);
 7263
 7264			/* only one noa-role exist */
 7265			if (rlink->noa && rlink->noa_dur > 0)
 7266				noa_exist = true;
 7267
 7268			/* for WL 5G-Rx interfered with BT issue */
 7269			if (rlink->rf_band == RTW89_BAND_5G) {
 7270				if (rlink->ch >= 100)
 7271					is_5g_hi_channel = true;
 7272
 7273				continue;
 7274			}
 7275
 7276			/* only if client connect for p2p-Go/AP */
 7277			if ((rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
 7278			     rlink->role == RTW89_WIFI_ROLE_AP) &&
 7279			     rlink->client_cnt > 1) {
 7280				p2p_exist = true;
 7281				client_joined = true;
 7282			}
 7283
 7284			/* Identify if P2P-Go (GO/GC/AP) exist at 2G band */
 7285			if (rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)
 7286				p2p_exist = true;
 7287
 7288			if ((rlink->mode & BIT(BTC_WL_MODE_11B)) ||
 7289			    (rlink->mode & BIT(BTC_WL_MODE_11G)))
 7290				bg_mode = true;
 7291		}
 7292	}
 7293
 7294	link_mode_ori = wl_rinfo->link_mode;
 7295	wl->is_5g_hi_channel = is_5g_hi_channel;
 7296	wl->bg_mode = bg_mode;
 7297	wl->go_client_exist = client_joined;
 7298	wl->noa_exist = noa_exist;
 7299	wl_rinfo->p2p_2g = p2p_exist;
 7300	wl_rinfo->role_map = role_map;
 7301
 7302	dbcc_en_ori = wl_rinfo->dbcc_en;
 7303
 7304	if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) {
 7305		/* for MLO-supported, link-mode from driver directly */
 7306		_update_wl_mlo_info(rtwdev);
 7307	} else {
 7308		/* for non-MLO-supported, link-mode by BTC */
 7309		_update_wl_non_mlo_info(rtwdev);
 7310	}
 7311
 7312	_modify_role_link_mode(rtwdev);
 7313
 7314	if (link_mode_ori != wl_rinfo->link_mode)
 7315		wl->link_mode_chg = true;
 7316
 7317	if (wl_rinfo->dbcc_en != dbcc_en_ori) {
 7318		wl->dbcc_chg = true;
 7319		btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++;
 7320	}
 7321}
 7322
 7323void rtw89_coex_act1_work(struct wiphy *wiphy, struct wiphy_work *work)
 7324{
 7325	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7326						coex_act1_work.work);
 7327	struct rtw89_btc *btc = &rtwdev->btc;
 7328	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
 7329	struct rtw89_btc_cx *cx = &btc->cx;
 7330	struct rtw89_btc_wl_info *wl = &cx->wl;
 7331
 7332	lockdep_assert_wiphy(wiphy);
 7333
 7334	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
 7335	dm->cnt_notify[BTC_NCNT_TIMER]++;
 7336	if (wl->status.map._4way)
 7337		wl->status.map._4way = false;
 7338	if (wl->status.map.connecting)
 7339		wl->status.map.connecting = false;
 7340
 7341	_run_coex(rtwdev, BTC_RSN_ACT1_WORK);
 7342}
 7343
 7344void rtw89_coex_bt_devinfo_work(struct wiphy *wiphy, struct wiphy_work *work)
 7345{
 7346	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7347						coex_bt_devinfo_work.work);
 7348	struct rtw89_btc *btc = &rtwdev->btc;
 7349	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
 7350	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
 7351
 7352	lockdep_assert_wiphy(wiphy);
 7353
 7354	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
 7355	dm->cnt_notify[BTC_NCNT_TIMER]++;
 7356	a2dp->play_latency = 0;
 7357	_run_coex(rtwdev, BTC_RSN_BT_DEVINFO_WORK);
 7358}
 7359
 7360void rtw89_coex_rfk_chk_work(struct wiphy *wiphy, struct wiphy_work *work)
 7361{
 7362	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7363						coex_rfk_chk_work.work);
 7364	struct rtw89_btc *btc = &rtwdev->btc;
 7365	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
 7366	struct rtw89_btc_cx *cx = &btc->cx;
 7367	struct rtw89_btc_wl_info *wl = &cx->wl;
 7368
 7369	lockdep_assert_wiphy(wiphy);
 7370
 7371	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
 7372	dm->cnt_notify[BTC_NCNT_TIMER]++;
 7373	if (wl->rfk_info.state != BTC_WRFK_STOP) {
 7374		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7375			    "[BTC], %s(): RFK timeout\n", __func__);
 7376		cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]++;
 7377		dm->error.map.wl_rfk_timeout = true;
 7378		wl->rfk_info.state = BTC_WRFK_STOP;
 7379		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
 7380		_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
 7381	}
 7382}
 7383
 7384static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
 7385{
 7386	const struct rtw89_chip_info *chip = rtwdev->chip;
 7387	struct rtw89_btc *btc = &rtwdev->btc;
 7388	struct rtw89_btc_cx *cx = &btc->cx;
 7389	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 7390	u32 val;
 7391	bool status_change = false;
 7392
 7393	if (!chip->scbd)
 7394		return;
 7395
 7396	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
 7397
 7398	val = _read_scbd(rtwdev);
 7399	if (val == BTC_SCB_INV_VALUE) {
 7400		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7401			    "[BTC], %s(): return by invalid scbd value\n",
 7402			    __func__);
 7403		return;
 7404	}
 7405
 7406	if (!(val & BTC_BSCB_ON))
 7407		bt->enable.now = 0;
 7408	else
 7409		bt->enable.now = 1;
 7410
 7411	if (bt->enable.now != bt->enable.last)
 7412		status_change = true;
 7413
 7414	/* reset bt info if bt re-enable */
 7415	if (bt->enable.now && !bt->enable.last) {
 7416		_reset_btc_var(rtwdev, BTC_RESET_BTINFO);
 7417		cx->cnt_bt[BTC_BCNT_REENABLE]++;
 7418		bt->enable.now = 1;
 7419	}
 7420
 7421	bt->enable.last = bt->enable.now;
 7422	bt->scbd = val;
 7423	bt->mbx_avl = !!(val & BTC_BSCB_ACT);
 7424
 7425	if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
 7426		status_change = true;
 7427
 7428	bt->whql_test = !!(val & BTC_BSCB_WHQL);
 7429	bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
 7430	bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
 7431
 7432	bt->lna_constrain = !!(val & BTC_BSCB_BT_LNAB0) +
 7433			    !!(val & BTC_BSCB_BT_LNAB1) * 2 + 4;
 7434
 7435	/* if rfk run 1->0 */
 7436	if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
 7437		status_change = true;
 7438
 7439	bt->rfk_info.map.run  = !!(val & BTC_BSCB_RFK_RUN);
 7440	bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ);
 7441	bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
 7442	bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT);
 7443	if (bt->run_patch_code != !!(val & BTC_BSCB_PATCH_CODE))
 7444		status_change = true;
 7445	bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
 7446
 7447	if (!only_update && status_change)
 7448		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
 7449}
 7450
 7451#define BTC_BTINFO_PWR_LEN 5
 7452static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
 7453{
 7454	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt;
 7455	struct rtw89_btc_bt_link_info *b = &bt->link_info;
 7456
 7457	if (len != BTC_BTINFO_PWR_LEN)
 7458		return;
 7459
 7460	if (!memcmp(bt->txpwr_info, buf, sizeof(bt->txpwr_info))) {
 7461		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7462			    "[BTC], %s return by info duplicate!\n", __func__);
 7463		return;
 7464	}
 7465
 7466	memcpy(bt->txpwr_info, buf, BTC_BTINFO_MAX);
 7467	memcpy(&b->bt_txpwr_desc, &buf[2], sizeof(b->bt_txpwr_desc));
 7468}
 7469
 7470static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
 7471{
 7472	struct rtw89_btc *btc = &rtwdev->btc;
 7473	struct rtw89_btc_cx *cx = &btc->cx;
 7474	struct rtw89_btc_bt_info *bt = &cx->bt;
 7475
 7476	_update_bt_scbd(rtwdev, true);
 7477
 7478	cx->cnt_wl[BTC_WCNT_RFK_REQ]++;
 7479
 7480	if ((bt->rfk_info.map.run || bt->rfk_info.map.req) &&
 7481	    !bt->rfk_info.map.timeout) {
 7482		cx->cnt_wl[BTC_WCNT_RFK_REJECT]++;
 7483	} else {
 7484		cx->cnt_wl[BTC_WCNT_RFK_GO]++;
 7485		return true;
 7486	}
 7487	return false;
 7488}
 7489
 7490static
 7491void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
 7492{
 7493	struct rtw89_btc *btc = &rtwdev->btc;
 7494	const struct rtw89_btc_ver *ver = btc->ver;
 7495	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
 7496	struct rtw89_btc_cx *cx = &btc->cx;
 7497	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7498	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 7499	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 7500	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 7501	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 7502	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 7503	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 7504	u8 mode, igno_bt, always_freerun;
 7505
 7506	lockdep_assert_wiphy(rtwdev->hw->wiphy);
 7507
 7508	dm->run_reason = reason;
 7509	_update_dm_step(rtwdev, reason);
 7510	_update_btc_state_map(rtwdev);
 7511
 7512	if (ver->fwlrole == 0)
 7513		mode = wl_rinfo->link_mode;
 7514	else if (ver->fwlrole == 1)
 7515		mode = wl_rinfo_v1->link_mode;
 7516	else if (ver->fwlrole == 2)
 7517		mode = wl_rinfo_v2->link_mode;
 7518	else if (ver->fwlrole == 7)
 7519		mode = wl_rinfo_v7->link_mode;
 7520	else if (ver->fwlrole == 8)
 7521		mode = wl_rinfo_v8->link_mode;
 7522	else
 7523		return;
 7524
 7525	if (ver->fcxctrl == 7) {
 7526		igno_bt = btc->ctrl.ctrl_v7.igno_bt;
 7527		always_freerun = btc->ctrl.ctrl_v7.always_freerun;
 7528	} else {
 7529		igno_bt = btc->ctrl.ctrl.igno_bt;
 7530		always_freerun = btc->ctrl.ctrl.always_freerun;
 7531	}
 7532
 7533	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
 7534		    __func__, reason, mode);
 7535	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
 7536		    __func__, dm->wl_only, dm->bt_only);
 7537
 7538	/* Be careful to change the following function sequence!! */
 7539	if (btc->manual_ctrl) {
 7540		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7541			    "[BTC], %s(): return for Manual CTRL!!\n",
 7542			    __func__);
 7543		return;
 7544	}
 7545
 7546	if (igno_bt &&
 7547	    (reason == BTC_RSN_UPDATE_BT_INFO ||
 7548	     reason == BTC_RSN_UPDATE_BT_SCBD)) {
 7549		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7550			    "[BTC], %s(): return for Stop Coex DM!!\n",
 7551			    __func__);
 7552		return;
 7553	}
 7554
 7555	if (!wl->status.map.init_ok) {
 7556		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7557			    "[BTC], %s(): return for WL init fail!!\n",
 7558			    __func__);
 7559		return;
 7560	}
 7561
 7562	if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
 7563	    wl->status.map.lps_pre == wl->status.map.lps) {
 7564		if (reason == BTC_RSN_NTFY_POWEROFF ||
 7565		    reason == BTC_RSN_NTFY_RADIO_STATE) {
 7566			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7567				    "[BTC], %s(): return for WL rf off state no change!!\n",
 7568				    __func__);
 7569			return;
 7570		}
 7571		if (wl->status.map.rf_off == 1 ||
 7572		    wl->status.map.lps == BTC_LPS_RF_OFF) {
 7573			rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7574				    "[BTC], %s(): return for WL rf off state!!\n",
 7575				    __func__);
 7576			return;
 7577		}
 7578	}
 7579
 7580	dm->freerun = false;
 7581	dm->cnt_dm[BTC_DCNT_RUN]++;
 7582	dm->fddt_train = BTC_FDDT_DISABLE;
 7583	bt->scan_rx_low_pri = false;
 7584	igno_bt = false;
 7585
 7586	dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */
 7587
 7588	if (always_freerun) {
 7589		_action_freerun(rtwdev);
 7590		igno_bt = true;
 7591		goto exit;
 7592	}
 7593
 7594	if (dm->wl_only) {
 7595		_action_wl_only(rtwdev);
 7596		igno_bt = true;
 7597		goto exit;
 7598	}
 7599
 7600	if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
 7601		_action_wl_off(rtwdev, mode);
 7602		igno_bt = true;
 7603		goto exit;
 7604	}
 7605
 7606	if (reason == BTC_RSN_NTFY_INIT) {
 7607		_action_wl_init(rtwdev);
 7608		goto exit;
 7609	}
 7610
 7611	if (!cx->bt.enable.now && !cx->other.type) {
 7612		_action_bt_off(rtwdev);
 7613		goto exit;
 7614	}
 7615
 7616	if (cx->bt.whql_test) {
 7617		_action_bt_whql(rtwdev);
 7618		goto exit;
 7619	}
 7620
 7621	if (wl->rfk_info.state != BTC_WRFK_STOP) {
 7622		_action_wl_rfk(rtwdev);
 7623		goto exit;
 7624	}
 7625
 7626	if (wl->status.val & btc_scanning_map.val && !wl->rfk_info.con_rfk) {
 7627		_action_wl_scan(rtwdev);
 7628		bt->scan_rx_low_pri = true;
 7629		goto exit;
 7630	}
 7631
 7632	switch (mode) {
 7633	case BTC_WLINK_NOLINK:
 7634		_action_wl_nc(rtwdev);
 7635		break;
 7636	case BTC_WLINK_2G_STA:
 7637		if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
 7638			bt->scan_rx_low_pri = true;
 7639		_action_wl_2g_sta(rtwdev);
 7640		break;
 7641	case BTC_WLINK_2G_AP:
 7642		bt->scan_rx_low_pri = true;
 7643		_action_wl_2g_ap(rtwdev);
 7644		break;
 7645	case BTC_WLINK_2G_GO:
 7646		bt->scan_rx_low_pri = true;
 7647		_action_wl_2g_go(rtwdev);
 7648		break;
 7649	case BTC_WLINK_2G_GC:
 7650		bt->scan_rx_low_pri = true;
 7651		_action_wl_2g_gc(rtwdev);
 7652		break;
 7653	case BTC_WLINK_2G_SCC:
 7654		bt->scan_rx_low_pri = true;
 7655		if (ver->fwlrole == 0)
 7656			_action_wl_2g_scc(rtwdev);
 7657		else if (ver->fwlrole == 1)
 7658			_action_wl_2g_scc_v1(rtwdev);
 7659		else if (ver->fwlrole == 2 || ver->fwlrole == 7)
 7660			_action_wl_2g_scc_v2(rtwdev);
 7661		else if (ver->fwlrole == 8)
 7662			_action_wl_2g_scc_v8(rtwdev);
 7663		break;
 7664	case BTC_WLINK_2G_MCC:
 7665		bt->scan_rx_low_pri = true;
 7666		_action_wl_2g_mcc(rtwdev);
 7667		break;
 7668	case BTC_WLINK_25G_MCC:
 7669		bt->scan_rx_low_pri = true;
 7670		_action_wl_25g_mcc(rtwdev);
 7671		break;
 7672	case BTC_WLINK_5G:
 7673		_action_wl_5g(rtwdev);
 7674		break;
 7675	case BTC_WLINK_2G_NAN:
 7676		_action_wl_2g_nan(rtwdev);
 7677		break;
 7678	default:
 7679		_action_wl_other(rtwdev);
 7680		break;
 7681	}
 7682
 7683exit:
 7684	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
 7685	if (ver->fcxctrl == 7)
 7686		btc->ctrl.ctrl_v7.igno_bt = igno_bt;
 7687	else
 7688		btc->ctrl.ctrl.igno_bt = igno_bt;
 7689	_action_common(rtwdev);
 7690}
 7691
 7692void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
 7693{
 7694	struct rtw89_btc *btc = &rtwdev->btc;
 7695
 7696	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 7697	btc->dm.cnt_notify[BTC_NCNT_POWER_ON]++;
 7698}
 7699
 7700void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
 7701{
 7702	struct rtw89_btc *btc = &rtwdev->btc;
 7703	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7704
 7705	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
 7706	btc->dm.cnt_notify[BTC_NCNT_POWER_OFF]++;
 7707
 7708	btc->cx.wl.status.map.rf_off = 1;
 7709	btc->cx.wl.status.map.busy = 0;
 7710	wl->status.map.lps = BTC_LPS_OFF;
 7711
 7712	_write_scbd(rtwdev, BTC_WSCB_ALL, false);
 7713	_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
 7714
 7715	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
 7716
 7717	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
 7718}
 7719
 7720static void _set_init_info(struct rtw89_dev *rtwdev)
 7721{
 7722	const struct rtw89_chip_info *chip = rtwdev->chip;
 7723	struct rtw89_btc *btc = &rtwdev->btc;
 7724	const struct rtw89_btc_ver *ver = btc->ver;
 7725	struct rtw89_btc_dm *dm = &btc->dm;
 7726	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7727
 7728	if (ver->fcxinit == 7) {
 7729		dm->init_info.init_v7.wl_only = (u8)dm->wl_only;
 7730		dm->init_info.init_v7.bt_only = (u8)dm->bt_only;
 7731		dm->init_info.init_v7.wl_init_ok = (u8)wl->status.map.init_ok;
 7732		dm->init_info.init_v7.cx_other = btc->cx.other.type;
 7733		dm->init_info.init_v7.wl_guard_ch = chip->afh_guard_ch;
 7734		dm->init_info.init_v7.module = btc->mdinfo.md_v7;
 7735	} else {
 7736		dm->init_info.init.wl_only = (u8)dm->wl_only;
 7737		dm->init_info.init.bt_only = (u8)dm->bt_only;
 7738		dm->init_info.init.wl_init_ok = (u8)wl->status.map.init_ok;
 7739		dm->init_info.init.dbcc_en = rtwdev->dbcc_en;
 7740		dm->init_info.init.cx_other = btc->cx.other.type;
 7741		dm->init_info.init.wl_guard_ch = chip->afh_guard_ch;
 7742		dm->init_info.init.module = btc->mdinfo.md;
 7743	}
 7744}
 7745
 7746void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
 7747{
 7748	struct rtw89_btc *btc = &rtwdev->btc;
 7749	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
 7750	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7751	const struct rtw89_chip_info *chip = rtwdev->chip;
 7752	const struct rtw89_btc_ver *ver = btc->ver;
 7753
 7754	_reset_btc_var(rtwdev, BTC_RESET_ALL);
 7755	btc->dm.run_reason = BTC_RSN_NONE;
 7756	btc->dm.run_action = BTC_ACT_NONE;
 7757	if (ver->fcxctrl == 7)
 7758		btc->ctrl.ctrl_v7.igno_bt = true;
 7759	else
 7760		btc->ctrl.ctrl.igno_bt = true;
 7761
 7762	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7763		    "[BTC], %s(): mode=%d\n", __func__, mode);
 7764
 7765	wl->coex_mode = mode;
 7766	dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
 7767	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
 7768	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
 7769	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
 7770
 7771	chip->ops->btc_set_rfe(rtwdev);
 7772	chip->ops->btc_init_cfg(rtwdev);
 7773
 7774	if (!wl->status.map.init_ok) {
 7775		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7776			    "[BTC], %s(): return for WL init fail!!\n",
 7777			    __func__);
 7778		dm->error.map.init = true;
 7779		return;
 7780	}
 7781
 7782	_write_scbd(rtwdev,
 7783		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
 7784	_update_bt_scbd(rtwdev, true);
 7785	if (rtw89_mac_get_ctrl_path(rtwdev)) {
 7786		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7787			    "[BTC], %s(): PTA owner warning!!\n",
 7788			    __func__);
 7789		dm->error.map.pta_owner = true;
 7790	}
 7791
 7792	_set_init_info(rtwdev);
 7793	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR);
 7794	btc_fw_set_monreg(rtwdev);
 7795	rtw89_btc_fw_set_slots(rtwdev);
 7796	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
 7797	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
 7798
 7799	_run_coex(rtwdev, BTC_RSN_NTFY_INIT);
 7800}
 7801
 7802void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
 7803{
 7804	struct rtw89_btc *btc = &rtwdev->btc;
 7805	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7806
 7807	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7808		    "[BTC], %s(): phy_idx=%d, band=%d\n",
 7809		    __func__, phy_idx, band);
 7810
 7811	if (phy_idx >= RTW89_PHY_NUM)
 7812		return;
 7813
 7814	btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
 7815	wl->status.map.scan = true;
 7816	wl->scan_info.band[phy_idx] = band;
 7817	wl->scan_info.phy_map |= BIT(phy_idx);
 7818	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
 7819
 7820	if (rtwdev->dbcc_en) {
 7821		wl->dbcc_info.scan_band[phy_idx] = band;
 7822		_update_dbcc_band(rtwdev, phy_idx);
 7823		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 7824	}
 7825
 7826	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_START);
 7827}
 7828
 7829void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
 7830{
 7831	struct rtw89_btc *btc = &rtwdev->btc;
 7832	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7833
 7834	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7835		    "[BTC], %s(): phy_idx=%d\n", __func__, phy_idx);
 7836	btc->dm.cnt_notify[BTC_NCNT_SCAN_FINISH]++;
 7837
 7838	wl->status.map.scan = false;
 7839	wl->scan_info.phy_map &= ~BIT(phy_idx);
 7840	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
 7841
 7842	if (rtwdev->dbcc_en) {
 7843		_update_dbcc_band(rtwdev, phy_idx);
 7844		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 7845	}
 7846
 7847	btc->dm.tdma_instant_excute = 1;
 7848
 7849	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
 7850}
 7851
 7852void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
 7853{
 7854	struct rtw89_btc *btc = &rtwdev->btc;
 7855	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 7856
 7857	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7858		    "[BTC], %s(): phy_idx=%d, band=%d\n",
 7859		    __func__, phy_idx, band);
 7860
 7861	if (phy_idx >= RTW89_PHY_NUM)
 7862		return;
 7863
 7864	btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
 7865
 7866	if (rtwdev->dbcc_en) {
 7867		wl->dbcc_info.scan_band[phy_idx] = band;
 7868		_update_dbcc_band(rtwdev, phy_idx);
 7869		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
 7870	}
 7871	_run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
 7872}
 7873
 7874void rtw89_btc_ntfy_specific_packet(struct rtw89_dev *rtwdev,
 7875				    enum btc_pkt_type pkt_type)
 7876{
 7877	struct rtw89_btc *btc = &rtwdev->btc;
 7878	struct rtw89_btc_cx *cx = &btc->cx;
 7879	struct rtw89_btc_wl_info *wl = &cx->wl;
 7880	struct rtw89_btc_bt_link_info *b = &cx->bt.link_info;
 7881	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
 7882	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
 7883	u32 cnt;
 7884	u32 delay = RTW89_COEX_ACT1_WORK_PERIOD;
 7885	bool delay_work = false;
 7886
 7887	switch (pkt_type) {
 7888	case PACKET_DHCP:
 7889		cnt = ++cx->cnt_wl[BTC_WCNT_DHCP];
 7890		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7891			    "[BTC], %s(): DHCP cnt=%d\n", __func__, cnt);
 7892		wl->status.map.connecting = true;
 7893		delay_work = true;
 7894		break;
 7895	case PACKET_EAPOL:
 7896		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
 7897		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7898			    "[BTC], %s(): EAPOL cnt=%d\n", __func__, cnt);
 7899		wl->status.map._4way = true;
 7900		delay_work = true;
 7901		if (hfp->exist || hid->exist)
 7902			delay /= 2;
 7903		break;
 7904	case PACKET_EAPOL_END:
 7905		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
 7906		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7907			    "[BTC], %s(): EAPOL_End cnt=%d\n",
 7908			    __func__, cnt);
 7909		wl->status.map._4way = false;
 7910		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
 7911		break;
 7912	case PACKET_ARP:
 7913		cnt = ++cx->cnt_wl[BTC_WCNT_ARP];
 7914		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7915			    "[BTC], %s(): ARP cnt=%d\n", __func__, cnt);
 7916		return;
 7917	case PACKET_ICMP:
 7918		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7919			    "[BTC], %s(): ICMP pkt\n", __func__);
 7920		return;
 7921	default:
 7922		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 7923			    "[BTC], %s(): unknown packet type %d\n",
 7924			    __func__, pkt_type);
 7925		return;
 7926	}
 7927
 7928	if (delay_work) {
 7929		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_act1_work);
 7930		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
 7931					 &rtwdev->coex_act1_work, delay);
 7932	}
 7933
 7934	btc->dm.cnt_notify[BTC_NCNT_SPECIAL_PACKET]++;
 7935	_run_coex(rtwdev, BTC_RSN_NTFY_SPECIFIC_PACKET);
 7936}
 7937
 7938void rtw89_btc_ntfy_eapol_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
 7939{
 7940	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7941						btc.eapol_notify_work);
 7942
 7943	lockdep_assert_wiphy(wiphy);
 7944
 7945	rtw89_leave_ps_mode(rtwdev);
 7946	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL);
 7947}
 7948
 7949void rtw89_btc_ntfy_arp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
 7950{
 7951	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7952						btc.arp_notify_work);
 7953
 7954	lockdep_assert_wiphy(wiphy);
 7955
 7956	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP);
 7957}
 7958
 7959void rtw89_btc_ntfy_dhcp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
 7960{
 7961	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7962						btc.dhcp_notify_work);
 7963
 7964	lockdep_assert_wiphy(wiphy);
 7965
 7966	rtw89_leave_ps_mode(rtwdev);
 7967	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP);
 7968}
 7969
 7970void rtw89_btc_ntfy_icmp_packet_work(struct wiphy *wiphy, struct wiphy_work *work)
 7971{
 7972	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
 7973						btc.icmp_notify_work);
 7974
 7975	lockdep_assert_wiphy(wiphy);
 7976
 7977	rtw89_leave_ps_mode(rtwdev);
 7978	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ICMP);
 7979}
 7980
 7981static u8 _update_bt_rssi_level(struct rtw89_dev *rtwdev, u8 rssi)
 7982{
 7983	const struct rtw89_chip_info *chip = rtwdev->chip;
 7984	struct rtw89_btc *btc = &rtwdev->btc;
 7985	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 7986	u8 *rssi_st, rssi_th, rssi_level = 0;
 7987	u8 i;
 7988
 7989	/* for rssi locate in which {40, 36, 31, 28}
 7990	 * if rssi >= 40% (-60dBm) --> rssi_level = 4
 7991	 * if 36% <= rssi < 40%    --> rssi_level = 3
 7992	 * if 31% <= rssi < 36%    --> rssi_level = 2
 7993	 * if 28% <= rssi < 31%    --> rssi_level = 1
 7994	 * if rssi < 28%           --> rssi_level = 0
 7995	 */
 7996
 7997	/* check if rssi across bt_rssi_thres boundary */
 7998	for (i = 0; i < BTC_BT_RSSI_THMAX; i++) {
 7999		rssi_th = chip->bt_rssi_thres[i];
 8000		rssi_st = &bt->link_info.rssi_state[i];
 8001
 8002		*rssi_st = _update_rssi_state(rtwdev, *rssi_st, rssi, rssi_th);
 8003
 8004		if (BTC_RSSI_HIGH(*rssi_st)) {
 8005			rssi_level = BTC_BT_RSSI_THMAX - i;
 8006			break;
 8007		}
 8008	}
 8009	return rssi_level;
 8010}
 8011
 8012static void _update_zb_coex_tbl(struct rtw89_dev *rtwdev)
 8013{
 8014	u8 mode = rtwdev->btc.cx.wl.role_info.link_mode;
 8015	u32 zb_tbl0 = 0xda5a5a5a, zb_tbl1 = 0xda5a5a5a;
 8016
 8017	if (mode == BTC_WLINK_5G || rtwdev->btc.dm.freerun) {
 8018		zb_tbl0 = 0xffffffff;
 8019		zb_tbl1 = 0xffffffff;
 8020	} else if (mode == BTC_WLINK_25G_MCC) {
 8021		zb_tbl0 = 0xffffffff; /* for E5G slot */
 8022		zb_tbl1 = 0xda5a5a5a; /* for E2G slot */
 8023	}
 8024	rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_0, zb_tbl0);
 8025	rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, zb_tbl1);
 8026}
 8027
 8028#define BT_PROFILE_PROTOCOL_MASK GENMASK(7, 4)
 8029
 8030static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
 8031{
 8032	const struct rtw89_chip_info *chip = rtwdev->chip;
 8033	struct rtw89_btc *btc = &rtwdev->btc;
 8034	struct rtw89_btc_cx *cx = &btc->cx;
 8035	struct rtw89_btc_bt_info *bt = &cx->bt;
 8036	struct rtw89_btc_bt_link_info *b = &bt->link_info;
 8037	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
 8038	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
 8039	struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
 8040	struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
 8041	union btc_btinfo btinfo;
 8042
 8043	if (buf[BTC_BTINFO_L1] != 6)
 8044		return;
 8045
 8046	if (!memcmp(bt->raw_info, buf, BTC_BTINFO_MAX)) {
 8047		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8048			    "[BTC], %s(): return by bt-info duplicate!!\n",
 8049			    __func__);
 8050		cx->cnt_bt[BTC_BCNT_INFOSAME]++;
 8051		return;
 8052	}
 8053
 8054	memcpy(bt->raw_info, buf, BTC_BTINFO_MAX);
 8055
 8056	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8057		    "[BTC], %s(): bt_info[2]=0x%02x\n",
 8058		    __func__, bt->raw_info[2]);
 8059
 8060	b->profile_cnt.last = b->profile_cnt.now;
 8061	b->profile_cnt.now = 0;
 8062	hid->type = 0;
 8063
 8064	/* parse raw info low-Byte2 */
 8065	btinfo.val = bt->raw_info[BTC_BTINFO_L2];
 8066	b->status.map.connect = btinfo.lb2.connect;
 8067	b->status.map.sco_busy = btinfo.lb2.sco_busy;
 8068	b->status.map.acl_busy = btinfo.lb2.acl_busy;
 8069	b->status.map.inq_pag = btinfo.lb2.inq_pag;
 8070	bt->inq_pag.now = btinfo.lb2.inq_pag;
 8071	cx->cnt_bt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
 8072
 8073	hfp->exist = btinfo.lb2.hfp;
 8074	b->profile_cnt.now += (u8)hfp->exist;
 8075	hid->exist = btinfo.lb2.hid;
 8076	b->profile_cnt.now += (u8)hid->exist;
 8077	a2dp->exist = btinfo.lb2.a2dp;
 8078	b->profile_cnt.now += (u8)a2dp->exist;
 8079	pan->exist = btinfo.lb2.pan;
 8080	b->profile_cnt.now += (u8)pan->exist;
 8081	btc->dm.trx_info.bt_profile = u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK);
 8082
 8083	/* parse raw info low-Byte3 */
 8084	btinfo.val = bt->raw_info[BTC_BTINFO_L3];
 8085	if (btinfo.lb3.retry != 0)
 8086		cx->cnt_bt[BTC_BCNT_RETRY]++;
 8087	b->cqddr = btinfo.lb3.cqddr;
 8088	cx->cnt_bt[BTC_BCNT_INQ] += !!(btinfo.lb3.inq && !bt->inq);
 8089	bt->inq = btinfo.lb3.inq;
 8090	cx->cnt_bt[BTC_BCNT_PAGE] += !!(btinfo.lb3.pag && !bt->pag);
 8091	bt->pag = btinfo.lb3.pag;
 8092
 8093	b->status.map.mesh_busy = btinfo.lb3.mesh_busy;
 8094	/* parse raw info high-Byte0 */
 8095	btinfo.val = bt->raw_info[BTC_BTINFO_H0];
 8096	/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
 8097	b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
 8098	bt->rssi_level = _update_bt_rssi_level(rtwdev, b->rssi);
 8099	btc->dm.trx_info.bt_rssi = bt->rssi_level;
 8100
 8101	/* parse raw info high-Byte1 */
 8102	btinfo.val = bt->raw_info[BTC_BTINFO_H1];
 8103	b->status.map.ble_connect = btinfo.hb1.ble_connect;
 8104	if (btinfo.hb1.ble_connect) {
 8105		if (hid->exist)
 8106			hid->type |= BTC_HID_BLE;
 8107		else if (btinfo.hb1.voice)
 8108			hid->type |= BTC_HID_RCU_VOICE;
 8109		else
 8110			hid->type |= BTC_HID_RCU;
 8111	}
 8112
 8113	cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
 8114	bt->reinit = btinfo.hb1.reinit;
 8115	cx->cnt_bt[BTC_BCNT_RELINK] += !!(btinfo.hb1.relink && !b->relink.now);
 8116	b->relink.now = btinfo.hb1.relink;
 8117	cx->cnt_bt[BTC_BCNT_IGNOWL] += !!(btinfo.hb1.igno_wl && !bt->igno_wl);
 8118	bt->igno_wl = btinfo.hb1.igno_wl;
 8119
 8120	if (bt->igno_wl && !cx->wl.status.map.rf_off)
 8121		_set_bt_ignore_wlan_act(rtwdev, false);
 8122
 8123	bt->ble_scan_en = btinfo.hb1.ble_scan;
 8124
 8125	cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
 8126	b->role_sw = btinfo.hb1.role_sw;
 8127
 8128	b->multi_link.now = btinfo.hb1.multi_link;
 8129
 8130	/* parse raw info high-Byte2 */
 8131	btinfo.val = bt->raw_info[BTC_BTINFO_H2];
 8132	pan->active = !!btinfo.hb2.pan_active;
 8133
 8134	cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
 8135	b->afh_update = btinfo.hb2.afh_update;
 8136	a2dp->active = btinfo.hb2.a2dp_active;
 8137	b->slave_role = btinfo.hb2.slave;
 8138	hid->slot_info = btinfo.hb2.hid_slot;
 8139	hid->pair_cnt = btinfo.hb2.hid_cnt;
 8140	if (!b->status.map.ble_connect || hid->pair_cnt > 1)
 8141		hid->type |= (hid->slot_info == BTC_HID_218 ?
 8142			      BTC_HID_218 : BTC_HID_418);
 8143	/* parse raw info high-Byte3 */
 8144	btinfo.val = bt->raw_info[BTC_BTINFO_H3];
 8145	a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
 8146
 8147	if (b->tx_3m != (u32)btinfo.hb3.tx_3m)
 8148		cx->cnt_bt[BTC_BCNT_RATECHG]++;
 8149	b->tx_3m = (u32)btinfo.hb3.tx_3m;
 8150
 8151	a2dp->sink = btinfo.hb3.a2dp_sink;
 8152
 8153	if (!a2dp->exist_last && a2dp->exist) {
 8154		a2dp->vendor_id = 0;
 8155		a2dp->flush_time = 0;
 8156		a2dp->play_latency = 1;
 8157		wiphy_delayed_work_queue(rtwdev->hw->wiphy,
 8158					 &rtwdev->coex_bt_devinfo_work,
 8159					 RTW89_COEX_BT_DEVINFO_WORK_PERIOD);
 8160	}
 8161
 8162	_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
 8163}
 8164
 8165void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
 8166			      struct rtw89_vif_link *rtwvif_link,
 8167			      struct rtw89_sta_link *rtwsta_link,
 8168			      enum btc_role_state state)
 8169{
 8170	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
 8171						       rtwvif_link->chanctx_idx);
 8172	struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
 8173	struct ieee80211_bss_conf *bss_conf;
 8174	struct ieee80211_link_sta *link_sta;
 8175	struct rtw89_btc *btc = &rtwdev->btc;
 8176	const struct rtw89_btc_ver *ver = btc->ver;
 8177	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 8178	struct rtw89_btc_wl_link_info r = {0};
 8179	struct rtw89_btc_wl_link_info *wlinfo = NULL;
 8180	u8 mode = 0, rlink_id, link_mode_ori, pta_req_mac_ori, wa_type;
 8181
 8182	rcu_read_lock();
 8183
 8184	bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
 8185
 8186	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
 8187	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8188		    "[BTC], role is STA=%d\n",
 8189		    vif->type == NL80211_IFTYPE_STATION);
 8190	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif_link->port);
 8191	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
 8192		    chan->band_type, chan->channel, chan->band_width);
 8193	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
 8194		    state == BTC_ROLE_MSTS_STA_CONN_END);
 8195	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8196		    "[BTC], bcn_period=%d dtim_period=%d\n",
 8197		    bss_conf->beacon_int, bss_conf->dtim_period);
 8198
 8199	if (rtwsta_link) {
 8200		link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
 8201
 8202		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
 8203			    rtwsta_link->mac_id);
 8204
 8205		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8206			    "[BTC], STA support HE=%d VHT=%d HT=%d\n",
 8207			    link_sta->he_cap.has_he,
 8208			    link_sta->vht_cap.vht_supported,
 8209			    link_sta->ht_cap.ht_supported);
 8210		if (link_sta->he_cap.has_he)
 8211			mode |= BIT(BTC_WL_MODE_HE);
 8212		if (link_sta->vht_cap.vht_supported)
 8213			mode |= BIT(BTC_WL_MODE_VHT);
 8214		if (link_sta->ht_cap.ht_supported)
 8215			mode |= BIT(BTC_WL_MODE_HT);
 8216
 8217		r.mode = mode;
 8218	}
 8219
 8220	if (rtwvif_link->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) {
 8221		rcu_read_unlock();
 8222		return;
 8223	}
 8224
 8225	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8226		    "[BTC], wifi_role=%d\n", rtwvif_link->wifi_role);
 8227
 8228	r.role = rtwvif_link->wifi_role;
 8229	r.phy = rtwvif_link->phy_idx;
 8230	r.pid = rtwvif_link->port;
 8231	r.active = true;
 8232	r.connected = MLME_LINKED;
 8233	r.bcn_period = bss_conf->beacon_int;
 8234	r.dtim_period = bss_conf->dtim_period;
 8235	r.band = chan->band_type;
 8236	r.ch = chan->channel;
 8237	r.bw = chan->band_width;
 8238	r.chdef.band = chan->band_type;
 8239	r.chdef.center_ch = chan->channel;
 8240	r.chdef.bw = chan->band_width;
 8241	r.chdef.chan = chan->primary_channel;
 8242	ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr);
 8243
 8244	rcu_read_unlock();
 8245
 8246	if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION)
 8247		r.mac_id = rtwsta_link->mac_id;
 8248
 8249	btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
 8250
 8251	wlinfo = &wl->link_info[r.pid];
 8252
 8253	if (ver->fwlrole == 0) {
 8254		*wlinfo = r;
 8255		_update_wl_info(rtwdev);
 8256	} else if (ver->fwlrole == 1) {
 8257		*wlinfo = r;
 8258		_update_wl_info_v1(rtwdev);
 8259	} else if (ver->fwlrole == 2) {
 8260		*wlinfo = r;
 8261		_update_wl_info_v2(rtwdev);
 8262	} else if (ver->fwlrole == 7) {
 8263		*wlinfo = r;
 8264		_update_wl_info_v7(rtwdev, r.pid);
 8265	} else if (ver->fwlrole == 8) {
 8266		rlink_id = rtwvif_link->mac_idx;
 8267		wlinfo = &wl->rlink_info[r.pid][rlink_id];
 8268		*wlinfo = r;
 8269		link_mode_ori = wl->role_info_v8.link_mode;
 8270		pta_req_mac_ori = wl->pta_req_mac;
 8271		_update_wl_info_v8(rtwdev, r.pid, rlink_id, state);
 8272
 8273		if (wl->role_info_v8.link_mode != link_mode_ori) {
 8274			wl->role_info_v8.link_mode_chg = 1;
 8275			if (ver->fcxinit == 7)
 8276				wa_type = btc->mdinfo.md_v7.wa_type;
 8277			else
 8278				wa_type = btc->mdinfo.md.wa_type;
 8279
 8280			if (wa_type & BTC_WA_HFP_ZB)
 8281				_update_zb_coex_tbl(rtwdev);
 8282		}
 8283
 8284		if (wl->pta_req_mac != pta_req_mac_ori)
 8285			wl->pta_reg_mac_chg = 1;
 8286	}
 8287
 8288	if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
 8289	    wlinfo->connected == MLME_NO_LINK)
 8290		btc->dm.leak_ap = 0;
 8291
 8292	if (state == BTC_ROLE_MSTS_STA_CONN_START)
 8293		wl->status.map.connecting = 1;
 8294	else
 8295		wl->status.map.connecting = 0;
 8296
 8297	if (state == BTC_ROLE_MSTS_STA_DIS_CONN ||
 8298	    state == BTC_ROLE_MSTS_STA_CONN_END)
 8299		wl->status.map._4way = false;
 8300
 8301	_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
 8302}
 8303
 8304void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
 8305{
 8306	const struct rtw89_chip_info *chip = rtwdev->chip;
 8307	struct rtw89_btc *btc = &rtwdev->btc;
 8308	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 8309	u32 val;
 8310
 8311	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rf_state = %d\n",
 8312		    __func__, rf_state);
 8313	btc->dm.cnt_notify[BTC_NCNT_RADIO_STATE]++;
 8314
 8315	switch (rf_state) {
 8316	case BTC_RFCTRL_WL_OFF:
 8317		wl->status.map.rf_off = 1;
 8318		wl->status.map.lps = BTC_LPS_OFF;
 8319		wl->status.map.busy = 0;
 8320		break;
 8321	case BTC_RFCTRL_FW_CTRL:
 8322		wl->status.map.rf_off = 0;
 8323		wl->status.map.lps = BTC_LPS_RF_OFF;
 8324		wl->status.map.busy = 0;
 8325		break;
 8326	case BTC_RFCTRL_LPS_WL_ON: /* LPS-Protocol (RFon) */
 8327		wl->status.map.rf_off = 0;
 8328		wl->status.map.lps = BTC_LPS_RF_ON;
 8329		wl->status.map.busy = 0;
 8330		break;
 8331	case BTC_RFCTRL_WL_ON:
 8332	default:
 8333		wl->status.map.rf_off = 0;
 8334		wl->status.map.lps = BTC_LPS_OFF;
 8335		break;
 8336	}
 8337
 8338	if (rf_state == BTC_RFCTRL_WL_ON) {
 8339		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, true);
 8340		val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG;
 8341		_write_scbd(rtwdev, val, true);
 8342		_update_bt_scbd(rtwdev, true);
 8343		chip->ops->btc_init_cfg(rtwdev);
 8344	} else {
 8345		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
 8346		if (rf_state == BTC_RFCTRL_FW_CTRL)
 8347			_write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
 8348		else if (rf_state == BTC_RFCTRL_WL_OFF)
 8349			_write_scbd(rtwdev, BTC_WSCB_ALL, false);
 8350		else
 8351			_write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
 8352
 8353		if (rf_state == BTC_RFCTRL_LPS_WL_ON &&
 8354		    wl->status.map.lps_pre != BTC_LPS_OFF)
 8355			_update_bt_scbd(rtwdev, true);
 8356	}
 8357
 8358	btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
 8359	btc->dm.tdma_instant_excute = 1;
 8360
 8361	_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
 8362	wl->status.map.rf_off_pre = wl->status.map.rf_off;
 8363	wl->status.map.lps_pre = wl->status.map.lps;
 8364}
 8365
 8366static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
 8367			 enum btc_wl_rfk_type type,
 8368			 enum btc_wl_rfk_state state)
 8369{
 8370	struct rtw89_btc *btc = &rtwdev->btc;
 8371	struct rtw89_btc_cx *cx = &btc->cx;
 8372	struct rtw89_btc_wl_info *wl = &cx->wl;
 8373	bool result = BTC_WRFK_REJECT;
 8374
 8375	wl->rfk_info.type = type;
 8376	wl->rfk_info.path_map = FIELD_GET(BTC_RFK_PATH_MAP, phy_path);
 8377	wl->rfk_info.phy_map = FIELD_GET(BTC_RFK_PHY_MAP, phy_path);
 8378	wl->rfk_info.band = FIELD_GET(BTC_RFK_BAND_MAP, phy_path);
 8379
 8380	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8381		    "[BTC], %s()_start: phy=0x%x, path=0x%x, type=%d, state=%d\n",
 8382		    __func__, wl->rfk_info.phy_map, wl->rfk_info.path_map,
 8383		    type, state);
 8384
 8385	switch (state) {
 8386	case BTC_WRFK_START:
 8387		result = _chk_wl_rfk_request(rtwdev);
 8388		wl->rfk_info.state = result ? BTC_WRFK_START : BTC_WRFK_STOP;
 8389
 8390		_write_scbd(rtwdev, BTC_WSCB_WLRFK, result);
 8391
 8392		btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
 8393		break;
 8394	case BTC_WRFK_ONESHOT_START:
 8395	case BTC_WRFK_ONESHOT_STOP:
 8396		if (wl->rfk_info.state == BTC_WRFK_STOP) {
 8397			result = BTC_WRFK_REJECT;
 8398		} else {
 8399			result = BTC_WRFK_ALLOW;
 8400			wl->rfk_info.state = state;
 8401		}
 8402		break;
 8403	case BTC_WRFK_STOP:
 8404		result = BTC_WRFK_ALLOW;
 8405		wl->rfk_info.state = BTC_WRFK_STOP;
 8406
 8407		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
 8408		wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->coex_rfk_chk_work);
 8409		break;
 8410	default:
 8411		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8412			    "[BTC], %s() warning state=%d\n", __func__, state);
 8413		break;
 8414	}
 8415
 8416	if (result == BTC_WRFK_ALLOW) {
 8417		if (wl->rfk_info.state == BTC_WRFK_START ||
 8418		    wl->rfk_info.state == BTC_WRFK_STOP)
 8419			_run_coex(rtwdev, BTC_RSN_NTFY_WL_RFK);
 8420
 8421		if (wl->rfk_info.state == BTC_WRFK_START)
 8422			wiphy_delayed_work_queue(rtwdev->hw->wiphy,
 8423						 &rtwdev->coex_rfk_chk_work,
 8424						 RTW89_COEX_RFK_CHK_WORK_PERIOD);
 8425	}
 8426
 8427	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8428		    "[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
 8429		    __func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
 8430
 8431	return result == BTC_WRFK_ALLOW;
 8432}
 8433
 8434void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
 8435			   enum btc_wl_rfk_type type,
 8436			   enum btc_wl_rfk_state state)
 8437{
 8438	u8 band;
 8439	bool allow;
 8440	int ret;
 8441
 8442	lockdep_assert_wiphy(rtwdev->hw->wiphy);
 8443
 8444	band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
 8445
 8446	rtw89_debug(rtwdev, RTW89_DBG_RFK,
 8447		    "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
 8448		    band == RTW89_BAND_2G ? "2G" :
 8449		    band == RTW89_BAND_5G ? "5G" : "6G",
 8450		    !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
 8451		    type,
 8452		    FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
 8453		    state == BTC_WRFK_STOP ? "RFK_STOP" :
 8454		    state == BTC_WRFK_START ? "RFK_START" :
 8455		    state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
 8456		    "ONE-SHOT_STOP");
 8457
 8458	if (state != BTC_WRFK_START || rtwdev->is_bt_iqk_timeout) {
 8459		_ntfy_wl_rfk(rtwdev, phy_map, type, state);
 8460		return;
 8461	}
 8462
 8463	ret = read_poll_timeout(_ntfy_wl_rfk, allow, allow, 40, 100000, false,
 8464				rtwdev, phy_map, type, state);
 8465	if (ret) {
 8466		rtw89_warn(rtwdev, "RFK notify timeout\n");
 8467		rtwdev->is_bt_iqk_timeout = true;
 8468	}
 8469}
 8470EXPORT_SYMBOL(rtw89_btc_ntfy_wl_rfk);
 8471
 8472struct rtw89_btc_wl_sta_iter_data {
 8473	struct rtw89_dev *rtwdev;
 8474	u8 busy_all;
 8475	u8 dir_all;
 8476	u8 rssi_map_all;
 8477	bool is_sta_change;
 8478	bool is_traffic_change;
 8479};
 8480
 8481static
 8482void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link,
 8483				  struct rtw89_sta_link *rtwsta_link,
 8484				  struct rtw89_btc_wl_sta_iter_data *iter_data)
 8485{
 8486	struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
 8487	struct rtw89_dev *rtwdev = iter_data->rtwdev;
 8488	struct rtw89_btc *btc = &rtwdev->btc;
 8489	struct rtw89_btc_dm *dm = &btc->dm;
 8490	const struct rtw89_btc_ver *ver = btc->ver;
 8491	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 8492	struct rtw89_btc_wl_link_info *link_info = NULL;
 8493	struct rtw89_traffic_stats *link_info_t = NULL;
 8494	struct rtw89_traffic_stats *stats = &rtwvif->stats;
 8495	const struct rtw89_chip_info *chip = rtwdev->chip;
 8496	struct rtw89_btc_wl_role_info *r;
 8497	struct rtw89_btc_wl_role_info_v1 *r1;
 8498	u32 last_tx_rate, last_rx_rate;
 8499	u16 last_tx_lvl, last_rx_lvl;
 8500	u8 port = rtwvif_link->port;
 8501	u8 rssi;
 8502	u8 busy = 0;
 8503	u8 dir = 0;
 8504	u8 rssi_map = 0;
 8505	u8 i = 0;
 8506	bool is_sta_change = false, is_traffic_change = false;
 8507
 8508	rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
 8509	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
 8510
 8511	if (btc->ver->fwlrole != 8)
 8512		link_info = &wl->link_info[port];
 8513	else
 8514		link_info = &wl->rlink_info[port][rtwvif_link->mac_idx];
 8515
 8516	link_info->stat.traffic = *stats;
 8517	link_info_t = &link_info->stat.traffic;
 8518
 8519	if (link_info->connected == MLME_NO_LINK) {
 8520		link_info->rx_rate_drop_cnt = 0;
 8521		return;
 8522	}
 8523
 8524	link_info->stat.rssi = rssi;
 8525	for (i = 0; i < BTC_WL_RSSI_THMAX; i++) {
 8526		link_info->rssi_state[i] =
 8527			_update_rssi_state(rtwdev,
 8528					   link_info->rssi_state[i],
 8529					   link_info->stat.rssi,
 8530					   chip->wl_rssi_thres[i]);
 8531		if (BTC_RSSI_LOW(link_info->rssi_state[i]))
 8532			rssi_map |= BIT(i);
 8533
 8534		if (btc->ant_type == BTC_ANT_DEDICATED &&
 8535		    BTC_RSSI_CHANGE(link_info->rssi_state[i]))
 8536			is_sta_change = true;
 8537	}
 8538	iter_data->rssi_map_all |= rssi_map;
 8539
 8540	last_tx_rate = link_info_t->tx_rate;
 8541	last_rx_rate = link_info_t->rx_rate;
 8542	last_tx_lvl = (u16)link_info_t->tx_tfc_lv;
 8543	last_rx_lvl = (u16)link_info_t->rx_tfc_lv;
 8544
 8545	if (stats->tx_tfc_lv != RTW89_TFC_IDLE ||
 8546	    stats->rx_tfc_lv != RTW89_TFC_IDLE)
 8547		busy = 1;
 8548
 8549	if (stats->tx_tfc_lv > stats->rx_tfc_lv)
 8550		dir = RTW89_TFC_UL;
 8551	else
 8552		dir = RTW89_TFC_DL;
 8553
 8554	link_info = &wl->link_info[port];
 8555	if (link_info->busy != busy || link_info->dir != dir) {
 8556		is_sta_change = true;
 8557		link_info->busy = busy;
 8558		link_info->dir = dir;
 8559	}
 8560
 8561	iter_data->busy_all |= busy;
 8562	iter_data->dir_all |= BIT(dir);
 8563
 8564	if (rtwsta_link->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
 8565	    last_rx_rate > RTW89_HW_RATE_CCK2 &&
 8566	    link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
 8567		link_info->rx_rate_drop_cnt++;
 8568
 8569	if (last_tx_rate != rtwsta_link->ra_report.hw_rate ||
 8570	    last_rx_rate != rtwsta_link->rx_hw_rate ||
 8571	    last_tx_lvl != link_info_t->tx_tfc_lv ||
 8572	    last_rx_lvl != link_info_t->rx_tfc_lv)
 8573		is_traffic_change = true;
 8574
 8575	link_info_t->tx_rate = rtwsta_link->ra_report.hw_rate;
 8576	link_info_t->rx_rate = rtwsta_link->rx_hw_rate;
 8577
 8578	if (link_info->role == RTW89_WIFI_ROLE_STATION ||
 8579	    link_info->role == RTW89_WIFI_ROLE_P2P_CLIENT) {
 8580		dm->trx_info.tx_rate = link_info_t->tx_rate;
 8581		dm->trx_info.rx_rate = link_info_t->rx_rate;
 8582	}
 8583
 8584	if (ver->fwlrole == 0) {
 8585		r = &wl->role_info;
 8586		r->active_role[port].tx_lvl = stats->tx_tfc_lv;
 8587		r->active_role[port].rx_lvl = stats->rx_tfc_lv;
 8588		r->active_role[port].tx_rate = rtwsta_link->ra_report.hw_rate;
 8589		r->active_role[port].rx_rate = rtwsta_link->rx_hw_rate;
 8590	} else if (ver->fwlrole == 1) {
 8591		r1 = &wl->role_info_v1;
 8592		r1->active_role_v1[port].tx_lvl = stats->tx_tfc_lv;
 8593		r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv;
 8594		r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate;
 8595		r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate;
 8596	}
 8597
 8598	dm->trx_info.tx_lvl = stats->tx_tfc_lv;
 8599	dm->trx_info.rx_lvl = stats->rx_tfc_lv;
 8600	dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate;
 8601	dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate;
 8602	dm->trx_info.tx_tp = link_info_t->tx_throughput;
 8603	dm->trx_info.rx_tp = link_info_t->rx_throughput;
 8604
 8605	/* Trigger coex-run if 0x10980 reg-value is diff with coex setup */
 8606	if ((dm->wl_btg_rx_rb != dm->wl_btg_rx &&
 8607	     dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) ||
 8608	     (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
 8609	      dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND))
 8610		iter_data->is_sta_change = true;
 8611
 8612	if (is_sta_change)
 8613		iter_data->is_sta_change = true;
 8614
 8615	if (is_traffic_change)
 8616		iter_data->is_traffic_change = true;
 8617}
 8618
 8619static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
 8620{
 8621	struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
 8622	struct rtw89_btc_wl_sta_iter_data *iter_data =
 8623				(struct rtw89_btc_wl_sta_iter_data *)data;
 8624	struct rtw89_vif_link *rtwvif_link;
 8625	struct rtw89_sta_link *rtwsta_link;
 8626	unsigned int link_id;
 8627
 8628	rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
 8629		rtwvif_link = rtwsta_link->rtwvif_link;
 8630		__rtw89_btc_ntfy_wl_sta_iter(rtwvif_link, rtwsta_link, iter_data);
 8631	}
 8632}
 8633
 8634#define BTC_NHM_CHK_INTVL 20
 8635
 8636void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
 8637{
 8638	struct rtw89_btc *btc = &rtwdev->btc;
 8639	struct rtw89_btc_dm *dm = &btc->dm;
 8640	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 8641	struct rtw89_btc_wl_sta_iter_data data = {.rtwdev = rtwdev};
 8642	u8 i;
 8643
 8644	ieee80211_iterate_stations_atomic(rtwdev->hw,
 8645					  rtw89_btc_ntfy_wl_sta_iter,
 8646					  &data);
 8647
 8648	wl->rssi_level = 0;
 8649	btc->dm.cnt_notify[BTC_NCNT_WL_STA]++;
 8650	for (i = BTC_WL_RSSI_THMAX; i > 0; i--) {
 8651		/* set RSSI level 4 ~ 0 if rssi bit map match */
 8652		if (data.rssi_map_all & BIT(i - 1)) {
 8653			wl->rssi_level = i;
 8654			break;
 8655		}
 8656	}
 8657
 8658	if (dm->trx_info.wl_rssi != wl->rssi_level)
 8659		dm->trx_info.wl_rssi = wl->rssi_level;
 8660
 8661	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
 8662		    __func__, !!wl->status.map.busy);
 8663
 8664	_write_scbd(rtwdev, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
 8665
 8666	if (data.is_traffic_change)
 8667		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
 8668	if (data.is_sta_change) {
 8669		wl->status.map.busy = data.busy_all;
 8670		wl->status.map.traffic_dir = data.dir_all;
 8671		_run_coex(rtwdev, BTC_RSN_NTFY_WL_STA);
 8672	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] >=
 8673		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] + BTC_NHM_CHK_INTVL) {
 8674		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
 8675			btc->dm.cnt_notify[BTC_NCNT_WL_STA];
 8676	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] <
 8677		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST]) {
 8678		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
 8679		btc->dm.cnt_notify[BTC_NCNT_WL_STA];
 8680	}
 8681}
 8682
 8683static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func)
 8684{
 8685	struct rtw89_btc *btc = &rtwdev->btc;
 8686	const struct rtw89_btc_ver *ver = btc->ver;
 8687
 8688	switch (func) {
 8689	case BTF_EVNT_RPT:
 8690	case BTF_EVNT_BT_INFO:
 8691	case BTF_EVNT_BT_SCBD:
 8692	case BTF_EVNT_BT_REG:
 8693	case BTF_EVNT_CX_RUNINFO:
 8694	case BTF_EVNT_BT_PSD:
 8695		return func;
 8696	case BTF_EVNT_BT_DEV_INFO:
 8697		if (ver->fwc2hfunc == 0)
 8698			return BTF_EVNT_BUF_OVERFLOW;
 8699		else
 8700			return BTF_EVNT_BT_DEV_INFO;
 8701	case BTF_EVNT_BT_LEAUDIO_INFO:
 8702		if (ver->fwc2hfunc == 0)
 8703			return BTF_EVNT_C2H_LOOPBACK;
 8704		else if (ver->fwc2hfunc == 1)
 8705			return BTF_EVNT_BUF_OVERFLOW;
 8706		else if (ver->fwc2hfunc == 2)
 8707			return func;
 8708		else if (ver->fwc2hfunc == 3)
 8709			return BTF_EVNT_BUF_OVERFLOW;
 8710		else
 8711			return BTF_EVNT_MAX;
 8712	case BTF_EVNT_BUF_OVERFLOW:
 8713		if (ver->fwc2hfunc == 0)
 8714			return BTF_EVNT_MAX;
 8715		else if (ver->fwc2hfunc == 1)
 8716			return BTF_EVNT_C2H_LOOPBACK;
 8717		else if (ver->fwc2hfunc == 2)
 8718			return func;
 8719		else if (ver->fwc2hfunc == 3)
 8720			return BTF_EVNT_C2H_LOOPBACK;
 8721		else
 8722			return BTF_EVNT_MAX;
 8723	case BTF_EVNT_C2H_LOOPBACK:
 8724		if (ver->fwc2hfunc == 2)
 8725			return func;
 8726		else if (ver->fwc2hfunc == 3)
 8727			return BTF_EVNT_BT_LEAUDIO_INFO;
 8728		else
 8729			return BTF_EVNT_MAX;
 8730	case BTF_EVNT_BT_QUERY_TXPWR:
 8731		if (ver->fwc2hfunc == 3)
 8732			return func;
 8733		else
 8734			return BTF_EVNT_MAX;
 8735	case BTF_EVNT_MAX:
 8736	default:
 8737		return BTF_EVNT_MAX;
 8738	}
 8739}
 8740
 8741void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
 8742			  u32 len, u8 class, u8 func)
 8743{
 8744	struct rtw89_btc *btc = &rtwdev->btc;
 8745	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 8746	u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
 8747
 8748	len -= RTW89_C2H_HEADER_LEN;
 8749
 8750	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8751		    "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n",
 8752		    __func__, len, class, func);
 8753
 8754	if (class != BTFC_FW_EVENT)
 8755		return;
 8756
 8757	func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func);
 8758	pfwinfo->cnt_c2h++;
 8759
 8760	switch (func) {
 8761	case BTF_EVNT_BUF_OVERFLOW:
 8762		pfwinfo->event[func]++;
 8763		break;
 8764	case BTF_EVNT_RPT:
 8765		pfwinfo->event[func]++;
 8766		/* Don't need rtw89_leave_ps_mode() */
 8767		btc_fw_event(rtwdev, func, buf, len);
 8768		break;
 8769	case BTF_EVNT_BT_INFO:
 8770		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8771			    "[BTC], handle C2H BT INFO with data %8ph\n", buf);
 8772		btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++;
 8773		_update_bt_info(rtwdev, buf, len);
 8774		break;
 8775	case BTF_EVNT_BT_SCBD:
 8776		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 8777			    "[BTC], handle C2H BT SCBD with data %8ph\n", buf);
 8778		btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++;
 8779		_update_bt_scbd(rtwdev, false);
 8780		break;
 8781	case BTF_EVNT_BT_PSD:
 8782		break;
 8783	case BTF_EVNT_BT_REG:
 8784		btc->dbg.rb_done = true;
 8785		btc->dbg.rb_val = le32_to_cpu(*((__le32 *)buf));
 8786
 8787		break;
 8788	case BTF_EVNT_C2H_LOOPBACK:
 8789		btc->dbg.rb_done = true;
 8790		btc->dbg.rb_val = buf[0];
 8791		break;
 8792	case BTF_EVNT_CX_RUNINFO:
 8793		btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
 8794		break;
 8795	case BTF_EVNT_BT_QUERY_TXPWR:
 8796		btc->cx.cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]++;
 8797		_update_bt_txpwr_info(rtwdev, buf, len);
 8798	}
 8799}
 8800
 8801#define BTC_CX_FW_OFFLOAD 0
 8802
 8803static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 8804{
 8805	union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
 8806	const struct rtw89_chip_info *chip = rtwdev->chip;
 8807	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
 8808	struct rtw89_hal *hal = &rtwdev->hal;
 8809	struct rtw89_btc *btc = &rtwdev->btc;
 8810	struct rtw89_btc_dm *dm = &btc->dm;
 8811	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 8812	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 8813	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
 8814	u8 cv, rfe, iso, ant_num, ant_single_pos;
 8815	char *p = buf, *end = buf + bufsz;
 8816
 8817	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
 8818		return 0;
 8819
 8820	p += scnprintf(p, end - p,
 8821		       "\n========== [BTC COEX INFO (%s)] ==========\n",
 8822		       chip_id_str(chip->chip_id));
 8823
 8824	ver_main = FIELD_GET(GENMASK(31, 24), RTW89_COEX_VERSION);
 8825	ver_sub = FIELD_GET(GENMASK(23, 16), RTW89_COEX_VERSION);
 8826	ver_hotfix = FIELD_GET(GENMASK(15, 8), RTW89_COEX_VERSION);
 8827	id_branch = FIELD_GET(GENMASK(7, 0), RTW89_COEX_VERSION);
 8828	p += scnprintf(p, end - p, " %-15s : Coex:%d.%d.%d(branch:%d), ",
 8829		       "[coex_version]", ver_main, ver_sub, ver_hotfix,
 8830		       id_branch);
 8831
 8832	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
 8833	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw_coex);
 8834	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw_coex);
 8835	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw_coex);
 8836	p += scnprintf(p, end - p, "WL_FW_coex:%d.%d.%d(branch:%d)",
 8837		       ver_main, ver_sub, ver_hotfix, id_branch);
 8838
 8839	ver_main = FIELD_GET(GENMASK(31, 24), chip->wlcx_desired);
 8840	ver_sub = FIELD_GET(GENMASK(23, 16), chip->wlcx_desired);
 8841	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->wlcx_desired);
 8842	p += scnprintf(p, end - p, "(%s, desired:%d.%d.%d), ",
 8843		       (wl->ver_info.fw_coex >= chip->wlcx_desired ?
 8844			"Match" : "Mismatch"), ver_main, ver_sub, ver_hotfix);
 8845
 8846	p += scnprintf(p, end - p, "BT_FW_coex:%d(%s, desired:%d)\n",
 8847		       bt->ver_info.fw_coex,
 8848		       (bt->ver_info.fw_coex >= ver->bt_desired ?
 8849			"Match" : "Mismatch"), ver->bt_desired);
 8850
 8851	if (bt->enable.now && bt->ver_info.fw == 0)
 8852		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true);
 8853	else
 8854		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false);
 8855
 8856	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw);
 8857	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw);
 8858	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
 8859	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
 8860	p += scnprintf(p, end - p,
 8861		       " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n",
 8862		       "[sub_module]",
 8863		       ver_main, ver_sub, ver_hotfix, id_branch,
 8864		       bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
 8865
 8866	if (ver->fcxinit == 7) {
 8867		cv = md->md_v7.kt_ver;
 8868		rfe = md->md_v7.rfe_type;
 8869		iso = md->md_v7.ant.isolation;
 8870		ant_num = md->md_v7.ant.num;
 8871		ant_single_pos = md->md_v7.ant.single_pos;
 8872	} else {
 8873		cv = md->md.cv;
 8874		rfe = md->md.rfe_type;
 8875		iso = md->md.ant.isolation;
 8876		ant_num = md->md.ant.num;
 8877		ant_single_pos = md->md.ant.single_pos;
 8878	}
 8879
 8880	p += scnprintf(p, end - p,
 8881		       " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
 8882		       "[hw_info]", cv, rfe, iso, ant_num,
 8883		       ant_num > 1 ? "" :
 8884		       ant_single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, ");
 8885
 8886	p += scnprintf(p, end - p,
 8887		       "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
 8888		       btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss,
 8889		       hal->rx_nss);
 8890
 8891	return p - buf;
 8892}
 8893
 8894static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 8895{
 8896	struct rtw89_btc *btc = &rtwdev->btc;
 8897	struct rtw89_btc_wl_link_info *plink = NULL;
 8898	struct rtw89_traffic_stats *t;
 8899	char *p = buf, *end = buf + bufsz;
 8900	u8 i, j;
 8901
 8902	for (i = 0; i < btc->ver->max_role_num; i++) {
 8903		for (j = 0; j < RTW89_MAC_NUM; j++) {
 8904			if (btc->ver->fwlrole == 8)
 8905				plink = &btc->cx.wl.rlink_info[i][j];
 8906			else
 8907				plink = &btc->cx.wl.link_info[i];
 8908
 8909			if (!plink->active)
 8910				continue;
 8911
 8912			p += scnprintf(p, end - p,
 8913				       " [port_%d]        : role=%d(phy-%d), connect=%s(client_cnt=%d), mode=%d, center_ch=%d, bw=%d",
 8914				       plink->pid, plink->role, plink->phy,
 8915				       id_to_mlme_state(plink->connected),
 8916				       plink->client_cnt - 1, plink->mode,
 8917				       plink->ch, plink->bw);
 8918
 8919			if (plink->connected == MLME_NO_LINK)
 8920				continue;
 8921
 8922			p += scnprintf(p, end - p,
 8923				       ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
 8924				       plink->mac_id, plink->tx_time, plink->tx_retry);
 8925
 8926			p += scnprintf(p, end - p,
 8927				       " [port_%d]        : rssi=-%ddBm(%d), busy=%d, dir=%s, ",
 8928				       plink->pid, 110 - plink->stat.rssi,
 8929				       plink->stat.rssi, plink->busy,
 8930				       plink->dir == RTW89_TFC_UL ? "UL" : "DL");
 8931
 8932			t = &plink->stat.traffic;
 8933
 8934			p += scnprintf(p, end - p,
 8935				       "tx[rate:%d/busy_level:%d], ",
 8936				       t->tx_rate, t->tx_tfc_lv);
 8937
 8938			p += scnprintf(p, end - p,
 8939				       "rx[rate:%d/busy_level:%d/drop:%d]\n",
 8940				       t->rx_rate,
 8941				       t->rx_tfc_lv, plink->rx_rate_drop_cnt);
 8942		}
 8943	}
 8944	return p - buf;
 8945}
 8946
 8947static int _show_wl_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 8948{
 8949	struct rtw89_btc *btc = &rtwdev->btc;
 8950	const struct rtw89_btc_ver *ver = btc->ver;
 8951	struct rtw89_btc_cx *cx = &btc->cx;
 8952	struct rtw89_btc_wl_info *wl = &cx->wl;
 8953	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
 8954	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
 8955	struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
 8956	struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7;
 8957	struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
 8958	char *p = buf, *end = buf + bufsz;
 8959	u8 mode;
 8960
 8961	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
 8962		return 0;
 8963
 8964	p += scnprintf(p, end - p, "========== [WL Status] ==========\n");
 8965
 8966	if (ver->fwlrole == 0)
 8967		mode = wl_rinfo->link_mode;
 8968	else if (ver->fwlrole == 1)
 8969		mode = wl_rinfo_v1->link_mode;
 8970	else if (ver->fwlrole == 2)
 8971		mode = wl_rinfo_v2->link_mode;
 8972	else if (ver->fwlrole == 7)
 8973		mode = wl_rinfo_v7->link_mode;
 8974	else if (ver->fwlrole == 8)
 8975		mode = wl_rinfo_v8->link_mode;
 8976	else
 8977		goto out;
 8978
 8979	p += scnprintf(p, end - p, " %-15s : link_mode:%s, ", "[status]",
 8980		       id_to_linkmode(mode));
 8981
 8982	p += scnprintf(p, end - p,
 8983		       "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ",
 8984		       wl->status.map.rf_off, wl->status.map.lps,
 8985		       wl->status.map.scan ? "Y" : "N",
 8986		       wl->scan_info.band[RTW89_PHY_0], wl->scan_info.phy_map);
 8987
 8988	p += scnprintf(p, end - p,
 8989		       "connecting:%s, roam:%s, 4way:%s, init_ok:%s\n",
 8990		       wl->status.map.connecting ? "Y" : "N",
 8991		       wl->status.map.roaming ?  "Y" : "N",
 8992		       wl->status.map._4way ? "Y" : "N",
 8993		       wl->status.map.init_ok ? "Y" : "N");
 8994
 8995	p += _show_wl_role_info(rtwdev, p, end - p);
 8996
 8997out:
 8998	return p - buf;
 8999}
 9000
 9001enum btc_bt_a2dp_type {
 9002	BTC_A2DP_LEGACY = 0,
 9003	BTC_A2DP_TWS_SNIFF = 1,
 9004	BTC_A2DP_TWS_RELAY = 2,
 9005};
 9006
 9007static int _show_bt_profile_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9008{
 9009	struct rtw89_btc *btc = &rtwdev->btc;
 9010	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
 9011	struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
 9012	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
 9013	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
 9014	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
 9015	char *p = buf, *end = buf + bufsz;
 9016
 9017	if (hfp.exist) {
 9018		p += scnprintf(p, end - p,
 9019			       " %-15s : type:%s, sut_pwr:%d, golden-rx:%d",
 9020			       "[HFP]", (hfp.type == 0 ? "SCO" : "eSCO"),
 9021			       bt_linfo->sut_pwr_level[0],
 9022			       bt_linfo->golden_rx_shift[0]);
 9023	}
 9024
 9025	if (hid.exist) {
 9026		p += scnprintf(p, end - p,
 9027			       "\n\r %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
 9028			       "[HID]",
 9029			       hid.type & BTC_HID_218 ? "2/18," : "",
 9030			       hid.type & BTC_HID_418 ? "4/18," : "",
 9031			       hid.type & BTC_HID_BLE ? "BLE," : "",
 9032			       hid.type & BTC_HID_RCU ? "RCU," : "",
 9033			       hid.type & BTC_HID_RCU_VOICE ? "RCU-Voice," : "",
 9034			       hid.pair_cnt, bt_linfo->sut_pwr_level[1],
 9035			       bt_linfo->golden_rx_shift[1]);
 9036	}
 9037
 9038	if (a2dp.exist) {
 9039		p += scnprintf(p, end - p,
 9040			       " %-15s : type:%s, bit-pool:%d, flush-time:%d, ",
 9041			       "[A2DP]",
 9042			       a2dp.type == BTC_A2DP_LEGACY ? "Legacy" : "TWS",
 9043			       a2dp.bitpool, a2dp.flush_time);
 9044
 9045		p += scnprintf(p, end - p,
 9046			       "vid:0x%x, Dev-name:0x%x, sut_pwr:%d, golden-rx:%d\n",
 9047			       a2dp.vendor_id, a2dp.device_name,
 9048			       bt_linfo->sut_pwr_level[2],
 9049			       bt_linfo->golden_rx_shift[2]);
 9050	}
 9051
 9052	if (pan.exist) {
 9053		p += scnprintf(p, end - p,
 9054			       " %-15s : sut_pwr:%d, golden-rx:%d\n",
 9055			       "[PAN]",
 9056			       bt_linfo->sut_pwr_level[3],
 9057			       bt_linfo->golden_rx_shift[3]);
 9058	}
 9059
 9060	return p - buf;
 9061}
 9062
 9063static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9064{
 9065	struct rtw89_btc *btc = &rtwdev->btc;
 9066	const struct rtw89_btc_ver *ver = btc->ver;
 9067	struct rtw89_btc_cx *cx = &btc->cx;
 9068	struct rtw89_btc_bt_info *bt = &cx->bt;
 9069	struct rtw89_btc_wl_info *wl = &cx->wl;
 9070	u32 ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
 9071	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 9072	union rtw89_btc_module_info *md = &btc->mdinfo;
 9073	s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm;
 9074	s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm;
 9075	char *p = buf, *end = buf + bufsz;
 9076	u8 *afh = bt_linfo->afh_map;
 9077	u8 *afh_le = bt_linfo->afh_map_le;
 9078	u8 bt_pos;
 9079
 9080	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
 9081		return 0;
 9082
 9083	if (ver->fcxinit == 7)
 9084		bt_pos = md->md_v7.bt_pos;
 9085	else
 9086		bt_pos = md->md.bt_pos;
 9087
 9088	p += scnprintf(p, end - p, "========== [BT Status] ==========\n");
 9089
 9090	p += scnprintf(p, end - p,
 9091		       " %-15s : enable:%s, btg:%s%s, connect:%s, ",
 9092		       "[status]", bt->enable.now ? "Y" : "N",
 9093		       bt->btg_type ? "Y" : "N",
 9094		       (bt->enable.now && (bt->btg_type != bt_pos) ?
 9095			"(efuse-mismatch!!)" : ""),
 9096		       (bt_linfo->status.map.connect ? "Y" : "N"));
 9097
 9098	p += scnprintf(p, end - p,
 9099		       "igno_wl:%s, mailbox_avl:%s, rfk_state:0x%x\n",
 9100		       bt->igno_wl ? "Y" : "N",
 9101		       bt->mbx_avl ? "Y" : "N", bt->rfk_info.val);
 9102
 9103	p += scnprintf(p, end - p, " %-15s : profile:%s%s%s%s%s ",
 9104		       "[profile]",
 9105		       (bt_linfo->profile_cnt.now == 0) ? "None," : "",
 9106		       bt_linfo->hfp_desc.exist ? "HFP," : "",
 9107		       bt_linfo->hid_desc.exist ? "HID," : "",
 9108		       bt_linfo->a2dp_desc.exist ?
 9109		       (bt_linfo->a2dp_desc.sink ? "A2DP_sink," : "A2DP,") : "",
 9110		       bt_linfo->pan_desc.exist ? "PAN," : "");
 9111
 9112	p += scnprintf(p, end - p,
 9113		       "multi-link:%s, role:%s, ble-connect:%s, CQDDR:%s, A2DP_active:%s, PAN_active:%s\n",
 9114		       bt_linfo->multi_link.now ? "Y" : "N",
 9115		       bt_linfo->slave_role ? "Slave" : "Master",
 9116		       bt_linfo->status.map.ble_connect ? "Y" : "N",
 9117		       bt_linfo->cqddr ? "Y" : "N",
 9118		       bt_linfo->a2dp_desc.active ? "Y" : "N",
 9119		       bt_linfo->pan_desc.active ? "Y" : "N");
 9120
 9121	p += scnprintf(p, end - p,
 9122		       " %-15s : rssi:%ddBm(lvl:%d), tx_rate:%dM, %s%s%s",
 9123		       "[link]", bt_linfo->rssi - 100,
 9124		       bt->rssi_level,
 9125		       bt_linfo->tx_3m ? 3 : 2,
 9126		       bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
 9127		       bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
 9128		       bt_linfo->status.map.mesh_busy ? " mesh_busy!!" : "");
 9129
 9130	p += scnprintf(p, end - p,
 9131		       "%s afh_map[%02x%02x_%02x%02x_%02x%02x_%02x%02x_%02x%02x], ",
 9132		       bt_linfo->relink.now ? " ReLink!!" : "",
 9133		       afh[0], afh[1], afh[2], afh[3], afh[4],
 9134		       afh[5], afh[6], afh[7], afh[8], afh[9]);
 9135
 9136	if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect)
 9137		p += scnprintf(p, end - p,
 9138			       "LE[%02x%02x_%02x_%02x%02x]",
 9139			       afh_le[0], afh_le[1], afh_le[2],
 9140			       afh_le[3], afh_le[4]);
 9141
 9142	p += scnprintf(p, end - p, "wl_ch_map[en:%d/ch:%d/bw:%d]\n",
 9143		       wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw);
 9144
 9145	p += scnprintf(p, end - p,
 9146		       " %-15s : retry:%d, relink:%d, rate_chg:%d, reinit:%d, reenable:%d, ",
 9147		       "[stat_cnt]", cx->cnt_bt[BTC_BCNT_RETRY],
 9148		       cx->cnt_bt[BTC_BCNT_RELINK],
 9149		       cx->cnt_bt[BTC_BCNT_RATECHG],
 9150		       cx->cnt_bt[BTC_BCNT_REINIT],
 9151		       cx->cnt_bt[BTC_BCNT_REENABLE]);
 9152
 9153	p += scnprintf(p, end - p,
 9154		       "role-switch:%d, afh:%d, inq_page:%d(inq:%d/page:%d), igno_wl:%d\n",
 9155		       cx->cnt_bt[BTC_BCNT_ROLESW], cx->cnt_bt[BTC_BCNT_AFH],
 9156		       cx->cnt_bt[BTC_BCNT_INQPAG], cx->cnt_bt[BTC_BCNT_INQ],
 9157		       cx->cnt_bt[BTC_BCNT_PAGE], cx->cnt_bt[BTC_BCNT_IGNOWL]);
 9158
 9159	p += _show_bt_profile_info(rtwdev, p, end - p);
 9160
 9161	p += scnprintf(p, end - p,
 9162		       " %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
 9163		       "[bt_info]", bt->raw_info[2], bt->raw_info[3],
 9164		       bt->raw_info[4], bt->raw_info[5], bt->raw_info[6],
 9165		       bt->raw_info[7],
 9166		       bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
 9167		       cx->cnt_bt[BTC_BCNT_INFOUPDATE],
 9168		       cx->cnt_bt[BTC_BCNT_INFOSAME]);
 9169
 9170	p += scnprintf(p, end - p,
 9171		       " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)",
 9172		       "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX],
 9173		       cx->cnt_bt[BTC_BCNT_HIPRI_TX],
 9174		       cx->cnt_bt[BTC_BCNT_LOPRI_RX],
 9175		       cx->cnt_bt[BTC_BCNT_LOPRI_TX],
 9176		       cx->cnt_bt[BTC_BCNT_POLUT]);
 9177
 9178	if (!bt->scan_info_update) {
 9179		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_SCAN_INFO, true);
 9180		p += scnprintf(p, end - p, "\n");
 9181	} else {
 9182		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_SCAN_INFO, false);
 9183		if (ver->fcxbtscan == 1) {
 9184			p += scnprintf(p, end - p,
 9185				       "(INQ:%d-%d/PAGE:%d-%d/LE:%d-%d/INIT:%d-%d)",
 9186				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INQ].win),
 9187				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INQ].intvl),
 9188				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_PAGE].win),
 9189				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_PAGE].intvl),
 9190				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_BLE].win),
 9191				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_BLE].intvl),
 9192				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INIT].win),
 9193				       le16_to_cpu(bt->scan_info_v1[BTC_SCAN_INIT].intvl));
 9194		} else if (ver->fcxbtscan == 2) {
 9195			p += scnprintf(p, end - p,
 9196				       "(BG:%d-%d/INIT:%d-%d/LE:%d-%d)",
 9197				       le16_to_cpu(bt->scan_info_v2[CXSCAN_BG].win),
 9198				       le16_to_cpu(bt->scan_info_v2[CXSCAN_BG].intvl),
 9199				       le16_to_cpu(bt->scan_info_v2[CXSCAN_INIT].win),
 9200				       le16_to_cpu(bt->scan_info_v2[CXSCAN_INIT].intvl),
 9201				       le16_to_cpu(bt->scan_info_v2[CXSCAN_LE].win),
 9202				       le16_to_cpu(bt->scan_info_v2[CXSCAN_LE].intvl));
 9203		}
 9204		p += scnprintf(p, end - p, "\n");
 9205	}
 9206
 9207	if (ver_main >= 9 && bt_linfo->profile_cnt.now)
 9208		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, true);
 9209	else
 9210		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, false);
 9211
 9212	if (cx->cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]) {
 9213		p += scnprintf(p, end - p,
 9214			       " %-15s : br_index:0x%x, le_index:0x%x",
 9215			       "[bt_txpwr_lvl]",
 9216			       bt->link_info.bt_txpwr_desc.br_gain_index,
 9217			       bt->link_info.bt_txpwr_desc.le_gain_index);
 9218		p += scnprintf(p, end - p, ", br_dbm:%d dBm", br_dbm);
 9219		p += scnprintf(p, end - p, ", le_dbm:%d dBm", le_dbm);
 9220	} else {
 9221		p += scnprintf(p, end - p,
 9222			       " %-15s : br_index:NA, le_index:NA, br_dbm:%d dBm[def], le_dbm:%d dBm[def]",
 9223			       "[bt_txpwr_lvl]",
 9224			       bt->link_info.bt_txpwr_desc.br_dbm,
 9225			       bt->link_info.bt_txpwr_desc.le_dbm);
 9226	}
 9227	p += scnprintf(p, end - p, "\n");
 9228
 9229	if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect)
 9230		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true);
 9231	else
 9232		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, false);
 9233
 9234	if (ver->fcxbtafh == 2 && bt_linfo->status.map.ble_connect)
 9235		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, true);
 9236	else
 9237		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP_LE, false);
 9238
 9239	if (bt_linfo->a2dp_desc.exist &&
 9240	    (bt_linfo->a2dp_desc.flush_time == 0 ||
 9241	     bt_linfo->a2dp_desc.vendor_id == 0 ||
 9242	     bt_linfo->a2dp_desc.play_latency == 1))
 9243		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, true);
 9244	else
 9245		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, false);
 9246
 9247	return p - buf;
 9248}
 9249
 9250#define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e
 9251#define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e
 9252#define CASE_BTC_POLICY_STR(e) \
 9253	case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
 9254#define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e
 9255#define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e
 9256#define CASE_BTC_INIT(e) case BTC_MODE_## e: return #e
 9257#define CASE_BTC_ANTPATH_STR(e) case BTC_ANT_##e: return #e
 9258#define CASE_BTC_POLUT_STR(e) case BTC_PLT_## e: return #e
 9259#define CASE_BTC_REGTYPE_STR(e) case REG_## e: return #e
 9260#define CASE_BTC_GDBG_STR(e) case BTC_DBG_## e: return #e
 9261
 9262static const char *id_to_polut(u32 id)
 9263{
 9264	switch (id) {
 9265	CASE_BTC_POLUT_STR(NONE);
 9266	CASE_BTC_POLUT_STR(GNT_BT_TX);
 9267	CASE_BTC_POLUT_STR(GNT_BT_RX);
 9268	CASE_BTC_POLUT_STR(GNT_WL);
 9269	CASE_BTC_POLUT_STR(BT);
 9270	CASE_BTC_POLUT_STR(ALL);
 9271	default:
 9272		return "unknown";
 9273	}
 9274}
 9275
 9276static const char *id_to_regtype(u32 id)
 9277{
 9278	switch (id) {
 9279	CASE_BTC_REGTYPE_STR(MAC);
 9280	CASE_BTC_REGTYPE_STR(BB);
 9281	CASE_BTC_REGTYPE_STR(RF);
 9282	CASE_BTC_REGTYPE_STR(BT_RF);
 9283	CASE_BTC_REGTYPE_STR(BT_MODEM);
 9284	CASE_BTC_REGTYPE_STR(BT_BLUEWIZE);
 9285	CASE_BTC_REGTYPE_STR(BT_VENDOR);
 9286	CASE_BTC_REGTYPE_STR(BT_LE);
 9287	default:
 9288		return "unknown";
 9289	}
 9290}
 9291
 9292static const char *id_to_gdbg(u32 id)
 9293{
 9294	switch (id) {
 9295	CASE_BTC_GDBG_STR(GNT_BT);
 9296	CASE_BTC_GDBG_STR(GNT_WL);
 9297	CASE_BTC_GDBG_STR(BCN_EARLY);
 9298	CASE_BTC_GDBG_STR(WL_NULL0);
 9299	CASE_BTC_GDBG_STR(WL_NULL1);
 9300	CASE_BTC_GDBG_STR(WL_RXISR);
 9301	CASE_BTC_GDBG_STR(TDMA_ENTRY);
 9302	CASE_BTC_GDBG_STR(A2DP_EMPTY);
 9303	CASE_BTC_GDBG_STR(BT_RETRY);
 9304	CASE_BTC_GDBG_STR(BT_RELINK);
 9305	CASE_BTC_GDBG_STR(SLOT_WL);
 9306	CASE_BTC_GDBG_STR(SLOT_BT);
 9307	CASE_BTC_GDBG_STR(WL_ERR);
 9308	CASE_BTC_GDBG_STR(WL_OK);
 9309	CASE_BTC_GDBG_STR(SLOT_B2W);
 9310	CASE_BTC_GDBG_STR(SLOT_W1);
 9311	CASE_BTC_GDBG_STR(SLOT_W2);
 9312	CASE_BTC_GDBG_STR(SLOT_W2B);
 9313	CASE_BTC_GDBG_STR(SLOT_B1);
 9314	CASE_BTC_GDBG_STR(SLOT_B2);
 9315	CASE_BTC_GDBG_STR(SLOT_B3);
 9316	CASE_BTC_GDBG_STR(SLOT_B4);
 9317	CASE_BTC_GDBG_STR(SLOT_LK);
 9318	CASE_BTC_GDBG_STR(SLOT_E2G);
 9319	CASE_BTC_GDBG_STR(SLOT_E5G);
 9320	CASE_BTC_GDBG_STR(SLOT_EBT);
 9321	CASE_BTC_GDBG_STR(SLOT_WLK);
 9322	CASE_BTC_GDBG_STR(SLOT_B1FDD);
 9323	CASE_BTC_GDBG_STR(BT_CHANGE);
 9324	CASE_BTC_GDBG_STR(WL_CCA);
 9325	CASE_BTC_GDBG_STR(BT_LEAUDIO);
 9326	CASE_BTC_GDBG_STR(USER_DEF);
 9327	default:
 9328		return "unknown";
 9329	}
 9330}
 9331
 9332static const char *steps_to_str(u16 step)
 9333{
 9334	switch (step) {
 9335	CASE_BTC_RSN_STR(NONE);
 9336	CASE_BTC_RSN_STR(NTFY_INIT);
 9337	CASE_BTC_RSN_STR(NTFY_SWBAND);
 9338	CASE_BTC_RSN_STR(NTFY_WL_STA);
 9339	CASE_BTC_RSN_STR(NTFY_RADIO_STATE);
 9340	CASE_BTC_RSN_STR(UPDATE_BT_SCBD);
 9341	CASE_BTC_RSN_STR(NTFY_WL_RFK);
 9342	CASE_BTC_RSN_STR(UPDATE_BT_INFO);
 9343	CASE_BTC_RSN_STR(NTFY_SCAN_START);
 9344	CASE_BTC_RSN_STR(NTFY_SCAN_FINISH);
 9345	CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET);
 9346	CASE_BTC_RSN_STR(NTFY_POWEROFF);
 9347	CASE_BTC_RSN_STR(NTFY_ROLE_INFO);
 9348	CASE_BTC_RSN_STR(CMD_SET_COEX);
 9349	CASE_BTC_RSN_STR(ACT1_WORK);
 9350	CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
 9351	CASE_BTC_RSN_STR(RFK_CHK_WORK);
 9352
 9353	CASE_BTC_ACT_STR(NONE);
 9354	CASE_BTC_ACT_STR(WL_ONLY);
 9355	CASE_BTC_ACT_STR(WL_5G);
 9356	CASE_BTC_ACT_STR(WL_OTHER);
 9357	CASE_BTC_ACT_STR(WL_IDLE);
 9358	CASE_BTC_ACT_STR(WL_NC);
 9359	CASE_BTC_ACT_STR(WL_RFK);
 9360	CASE_BTC_ACT_STR(WL_INIT);
 9361	CASE_BTC_ACT_STR(WL_OFF);
 9362	CASE_BTC_ACT_STR(FREERUN);
 9363	CASE_BTC_ACT_STR(BT_WHQL);
 9364	CASE_BTC_ACT_STR(BT_RFK);
 9365	CASE_BTC_ACT_STR(BT_OFF);
 9366	CASE_BTC_ACT_STR(BT_IDLE);
 9367	CASE_BTC_ACT_STR(BT_HFP);
 9368	CASE_BTC_ACT_STR(BT_HID);
 9369	CASE_BTC_ACT_STR(BT_A2DP);
 9370	CASE_BTC_ACT_STR(BT_A2DPSINK);
 9371	CASE_BTC_ACT_STR(BT_PAN);
 9372	CASE_BTC_ACT_STR(BT_A2DP_HID);
 9373	CASE_BTC_ACT_STR(BT_A2DP_PAN);
 9374	CASE_BTC_ACT_STR(BT_PAN_HID);
 9375	CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
 9376	CASE_BTC_ACT_STR(WL_25G_MCC);
 9377	CASE_BTC_ACT_STR(WL_2G_MCC);
 9378	CASE_BTC_ACT_STR(WL_2G_SCC);
 9379	CASE_BTC_ACT_STR(WL_2G_AP);
 9380	CASE_BTC_ACT_STR(WL_2G_GO);
 9381	CASE_BTC_ACT_STR(WL_2G_GC);
 9382	CASE_BTC_ACT_STR(WL_2G_NAN);
 9383
 9384	CASE_BTC_POLICY_STR(OFF_BT);
 9385	CASE_BTC_POLICY_STR(OFF_WL);
 9386	CASE_BTC_POLICY_STR(OFF_EQ0);
 9387	CASE_BTC_POLICY_STR(OFF_EQ1);
 9388	CASE_BTC_POLICY_STR(OFF_EQ2);
 9389	CASE_BTC_POLICY_STR(OFF_EQ3);
 9390	CASE_BTC_POLICY_STR(OFF_EQ4);
 9391	CASE_BTC_POLICY_STR(OFF_EQ5);
 9392	CASE_BTC_POLICY_STR(OFF_BWB0);
 9393	CASE_BTC_POLICY_STR(OFF_BWB1);
 9394	CASE_BTC_POLICY_STR(OFF_BWB2);
 9395	CASE_BTC_POLICY_STR(OFF_BWB3);
 9396	CASE_BTC_POLICY_STR(OFF_WL2);
 9397	CASE_BTC_POLICY_STR(OFFB_BWB0);
 9398	CASE_BTC_POLICY_STR(OFFE_DEF);
 9399	CASE_BTC_POLICY_STR(OFFE_DEF2);
 9400	CASE_BTC_POLICY_STR(OFFE_2GBWISOB);
 9401	CASE_BTC_POLICY_STR(OFFE_2GISOB);
 9402	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB);
 9403	CASE_BTC_POLICY_STR(OFFE_WL);
 9404	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB2);
 9405	CASE_BTC_POLICY_STR(FIX_TD3030);
 9406	CASE_BTC_POLICY_STR(FIX_TD5050);
 9407	CASE_BTC_POLICY_STR(FIX_TD2030);
 9408	CASE_BTC_POLICY_STR(FIX_TD4010);
 9409	CASE_BTC_POLICY_STR(FIX_TD7010);
 9410	CASE_BTC_POLICY_STR(FIX_TD2060);
 9411	CASE_BTC_POLICY_STR(FIX_TD3060);
 9412	CASE_BTC_POLICY_STR(FIX_TD2080);
 9413	CASE_BTC_POLICY_STR(FIX_TDW1B1);
 9414	CASE_BTC_POLICY_STR(FIX_TD4010ISO);
 9415	CASE_BTC_POLICY_STR(FIX_TD4010ISO_DL);
 9416	CASE_BTC_POLICY_STR(FIX_TD4010ISO_UL);
 9417	CASE_BTC_POLICY_STR(PFIX_TD3030);
 9418	CASE_BTC_POLICY_STR(PFIX_TD5050);
 9419	CASE_BTC_POLICY_STR(PFIX_TD2030);
 9420	CASE_BTC_POLICY_STR(PFIX_TD2060);
 9421	CASE_BTC_POLICY_STR(PFIX_TD3070);
 9422	CASE_BTC_POLICY_STR(PFIX_TD2080);
 9423	CASE_BTC_POLICY_STR(PFIX_TDW1B1);
 9424	CASE_BTC_POLICY_STR(AUTO_TD50B1);
 9425	CASE_BTC_POLICY_STR(AUTO_TD60B1);
 9426	CASE_BTC_POLICY_STR(AUTO_TD20B1);
 9427	CASE_BTC_POLICY_STR(AUTO_TDW1B1);
 9428	CASE_BTC_POLICY_STR(PAUTO_TD50B1);
 9429	CASE_BTC_POLICY_STR(PAUTO_TD60B1);
 9430	CASE_BTC_POLICY_STR(PAUTO_TD20B1);
 9431	CASE_BTC_POLICY_STR(PAUTO_TDW1B1);
 9432	CASE_BTC_POLICY_STR(AUTO2_TD3050);
 9433	CASE_BTC_POLICY_STR(AUTO2_TD3070);
 9434	CASE_BTC_POLICY_STR(AUTO2_TD5050);
 9435	CASE_BTC_POLICY_STR(AUTO2_TD6060);
 9436	CASE_BTC_POLICY_STR(AUTO2_TD2080);
 9437	CASE_BTC_POLICY_STR(AUTO2_TDW1B4);
 9438	CASE_BTC_POLICY_STR(PAUTO2_TD3050);
 9439	CASE_BTC_POLICY_STR(PAUTO2_TD3070);
 9440	CASE_BTC_POLICY_STR(PAUTO2_TD5050);
 9441	CASE_BTC_POLICY_STR(PAUTO2_TD6060);
 9442	CASE_BTC_POLICY_STR(PAUTO2_TD2080);
 9443	CASE_BTC_POLICY_STR(PAUTO2_TDW1B4);
 9444	default:
 9445		return "unknown step";
 9446	}
 9447}
 9448
 9449static const char *id_to_slot(u32 id)
 9450{
 9451	switch (id) {
 9452	CASE_BTC_SLOT_STR(OFF);
 9453	CASE_BTC_SLOT_STR(B2W);
 9454	CASE_BTC_SLOT_STR(W1);
 9455	CASE_BTC_SLOT_STR(W2);
 9456	CASE_BTC_SLOT_STR(W2B);
 9457	CASE_BTC_SLOT_STR(B1);
 9458	CASE_BTC_SLOT_STR(B2);
 9459	CASE_BTC_SLOT_STR(B3);
 9460	CASE_BTC_SLOT_STR(B4);
 9461	CASE_BTC_SLOT_STR(LK);
 9462	CASE_BTC_SLOT_STR(BLK);
 9463	CASE_BTC_SLOT_STR(E2G);
 9464	CASE_BTC_SLOT_STR(E5G);
 9465	CASE_BTC_SLOT_STR(EBT);
 9466	CASE_BTC_SLOT_STR(ENULL);
 9467	CASE_BTC_SLOT_STR(WLK);
 9468	CASE_BTC_SLOT_STR(W1FDD);
 9469	CASE_BTC_SLOT_STR(B1FDD);
 9470	default:
 9471		return "unknown";
 9472	}
 9473}
 9474
 9475static const char *id_to_evt(u32 id)
 9476{
 9477	switch (id) {
 9478	CASE_BTC_EVT_STR(TDMA_ENTRY);
 9479	CASE_BTC_EVT_STR(WL_TMR);
 9480	CASE_BTC_EVT_STR(B1_TMR);
 9481	CASE_BTC_EVT_STR(B2_TMR);
 9482	CASE_BTC_EVT_STR(B3_TMR);
 9483	CASE_BTC_EVT_STR(B4_TMR);
 9484	CASE_BTC_EVT_STR(W2B_TMR);
 9485	CASE_BTC_EVT_STR(B2W_TMR);
 9486	CASE_BTC_EVT_STR(BCN_EARLY);
 9487	CASE_BTC_EVT_STR(A2DP_EMPTY);
 9488	CASE_BTC_EVT_STR(LK_END);
 9489	CASE_BTC_EVT_STR(RX_ISR);
 9490	CASE_BTC_EVT_STR(RX_FC0);
 9491	CASE_BTC_EVT_STR(RX_FC1);
 9492	CASE_BTC_EVT_STR(BT_RELINK);
 9493	CASE_BTC_EVT_STR(BT_RETRY);
 9494	CASE_BTC_EVT_STR(E2G);
 9495	CASE_BTC_EVT_STR(E5G);
 9496	CASE_BTC_EVT_STR(EBT);
 9497	CASE_BTC_EVT_STR(ENULL);
 9498	CASE_BTC_EVT_STR(DRV_WLK);
 9499	CASE_BTC_EVT_STR(BCN_OK);
 9500	CASE_BTC_EVT_STR(BT_CHANGE);
 9501	CASE_BTC_EVT_STR(EBT_EXTEND);
 9502	CASE_BTC_EVT_STR(E2G_NULL1);
 9503	CASE_BTC_EVT_STR(B1FDD_TMR);
 9504	default:
 9505		return "unknown";
 9506	}
 9507}
 9508
 9509static const char *id_to_mode(u8 id)
 9510{
 9511	switch (id) {
 9512	CASE_BTC_INIT(NORMAL);
 9513	CASE_BTC_INIT(WL);
 9514	CASE_BTC_INIT(BT);
 9515	CASE_BTC_INIT(WLOFF);
 9516	default:
 9517		return "unknown";
 9518	}
 9519}
 9520
 9521static const char *id_to_ant(u32 id)
 9522{
 9523	switch (id) {
 9524	CASE_BTC_ANTPATH_STR(WPOWERON);
 9525	CASE_BTC_ANTPATH_STR(WINIT);
 9526	CASE_BTC_ANTPATH_STR(WONLY);
 9527	CASE_BTC_ANTPATH_STR(WOFF);
 9528	CASE_BTC_ANTPATH_STR(W2G);
 9529	CASE_BTC_ANTPATH_STR(W5G);
 9530	CASE_BTC_ANTPATH_STR(W25G);
 9531	CASE_BTC_ANTPATH_STR(FREERUN);
 9532	CASE_BTC_ANTPATH_STR(WRFK);
 9533	CASE_BTC_ANTPATH_STR(BRFK);
 9534	CASE_BTC_ANTPATH_STR(MAX);
 9535	default:
 9536		return "unknown";
 9537	}
 9538}
 9539
 9540static
 9541int scnprintf_segment(char *buf, size_t bufsz, const char *prefix, const u16 *data,
 9542		      u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
 9543{
 9544	char *p = buf, *end = buf + bufsz;
 9545	u8 cur_index;
 9546	u8 i;
 9547
 9548	for (i = 0; i < len ; i++) {
 9549		if ((i % seg_len) == 0)
 9550			p += scnprintf(p, end - p, " %-15s : ", prefix);
 9551		cur_index = (start_idx + i) % ring_len;
 9552		if (i % 3 == 0)
 9553			p += scnprintf(p, end - p, "-> %-20s",
 9554				       steps_to_str(*(data + cur_index)));
 9555		else if (i % 3 == 1)
 9556			p += scnprintf(p, end - p, "-> %-15s",
 9557				       steps_to_str(*(data + cur_index)));
 9558		else
 9559			p += scnprintf(p, end - p, "-> %-13s",
 9560				       steps_to_str(*(data + cur_index)));
 9561		if (i == (len - 1) || (i % seg_len) == (seg_len - 1))
 9562			p += scnprintf(p, end - p, "\n");
 9563	}
 9564
 9565	return p - buf;
 9566}
 9567
 9568static int _show_dm_step(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9569{
 9570	struct rtw89_btc *btc = &rtwdev->btc;
 9571	struct rtw89_btc_dm *dm = &btc->dm;
 9572	char *p = buf, *end = buf + bufsz;
 9573	u8 start_idx;
 9574	u8 len;
 9575
 9576	len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos;
 9577	start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0;
 9578
 9579	p += scnprintf_segment(p, end - p, "[dm_steps]", dm->dm_step.step, len,
 9580			       6, start_idx, ARRAY_SIZE(dm->dm_step.step));
 9581
 9582	return p - buf;
 9583}
 9584
 9585static int _show_dm_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9586{
 9587	struct rtw89_btc *btc = &rtwdev->btc;
 9588	const struct rtw89_btc_ver *ver = btc->ver;
 9589	struct rtw89_btc_dm *dm = &btc->dm;
 9590	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 9591	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 9592	char *p = buf, *end = buf + bufsz;
 9593	u8 igno_bt;
 9594
 9595	if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
 9596		return 0;
 9597
 9598	p += scnprintf(p, end - p,
 9599		       "========== [Mechanism Status %s] ==========\n",
 9600		       (btc->manual_ctrl ? "(Manual)" : "(Auto)"));
 9601
 9602	p += scnprintf(p, end - p,
 9603		       " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n",
 9604		       "[status]",
 9605		       btc->ant_type == BTC_ANT_SHARED ? "shared" : "dedicated",
 9606		       steps_to_str(dm->run_reason),
 9607		       steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
 9608		       id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)),
 9609		       id_to_mode(wl->coex_mode),
 9610		       dm->cnt_dm[BTC_DCNT_RUN]);
 9611
 9612	p += _show_dm_step(rtwdev, p, end - p);
 9613
 9614	if (ver->fcxctrl == 7)
 9615		igno_bt = btc->ctrl.ctrl_v7.igno_bt;
 9616	else
 9617		igno_bt = btc->ctrl.ctrl.igno_bt;
 9618
 9619	p += scnprintf(p, end - p,
 9620		       " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
 9621		       "[dm_flag]", dm->wl_only, dm->bt_only, igno_bt,
 9622		       dm->freerun, btc->lps, dm->wl_mimo_ps);
 9623
 9624	p += scnprintf(p, end - p, "leak_ap:%d, fw_offload:%s%s\n",
 9625		       dm->leak_ap,
 9626		       (BTC_CX_FW_OFFLOAD ? "Y" : "N"),
 9627		       (dm->wl_fw_cx_offload == BTC_CX_FW_OFFLOAD ?
 9628			"" : "(Mismatch!!)"));
 9629
 9630	if (dm->rf_trx_para.wl_tx_power == 0xff)
 9631		p += scnprintf(p, end - p,
 9632			       " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:orig, ",
 9633			       "[trx_ctrl]", wl->rssi_level,
 9634			       dm->trx_para_level);
 9635
 9636	else
 9637		p += scnprintf(p, end - p,
 9638			       " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:%d, ",
 9639			       "[trx_ctrl]", wl->rssi_level,
 9640			       dm->trx_para_level,
 9641			       dm->rf_trx_para.wl_tx_power);
 9642
 9643	p += scnprintf(p, end - p,
 9644		       "wl_rx_lvl:%d, bt_tx_pwr_dec:%d, bt_rx_lna:%d(%s-tbl), wl_btg_rx:%d\n",
 9645		       dm->rf_trx_para.wl_rx_gain,
 9646		       dm->rf_trx_para.bt_tx_power,
 9647		       dm->rf_trx_para.bt_rx_gain,
 9648		       (bt->hi_lna_rx ? "Hi" : "Ori"), dm->wl_btg_rx);
 9649
 9650	p += scnprintf(p, end - p,
 9651		       " %-15s : wl_tx_limit[en:%d/max_t:%dus/max_retry:%d], bt_slot_reg:%d-TU, bt_scan_rx_low_pri:%d\n",
 9652		       "[dm_ctrl]", dm->wl_tx_limit.enable,
 9653		       dm->wl_tx_limit.tx_time,
 9654		       dm->wl_tx_limit.tx_retry, btc->bt_req_len,
 9655		       bt->scan_rx_low_pri);
 9656
 9657	return p - buf;
 9658}
 9659
 9660static int _show_error(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9661{
 9662	struct rtw89_btc *btc = &rtwdev->btc;
 9663	const struct rtw89_btc_ver *ver = btc->ver;
 9664	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 9665	union rtw89_btc_fbtc_cysta_info *pcysta;
 9666	char *p = buf, *end = buf + bufsz;
 9667	u32 except_cnt, exception_map;
 9668
 9669	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
 9670	if (ver->fcxcysta == 2) {
 9671		pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
 9672		except_cnt = le32_to_cpu(pcysta->v2.except_cnt);
 9673		exception_map = le32_to_cpu(pcysta->v2.exception);
 9674	} else if (ver->fcxcysta == 3) {
 9675		pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
 9676		except_cnt = le32_to_cpu(pcysta->v3.except_cnt);
 9677		exception_map = le32_to_cpu(pcysta->v3.except_map);
 9678	} else if (ver->fcxcysta == 4) {
 9679		pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4;
 9680		except_cnt = pcysta->v4.except_cnt;
 9681		exception_map = le32_to_cpu(pcysta->v4.except_map);
 9682	} else if (ver->fcxcysta == 5) {
 9683		pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
 9684		except_cnt = pcysta->v5.except_cnt;
 9685		exception_map = le32_to_cpu(pcysta->v5.except_map);
 9686	} else if (ver->fcxcysta == 7) {
 9687		pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
 9688		except_cnt = pcysta->v7.except_cnt;
 9689		exception_map = le32_to_cpu(pcysta->v7.except_map);
 9690	} else {
 9691		return 0;
 9692	}
 9693
 9694	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 &&
 9695	    !pfwinfo->len_mismch && !pfwinfo->fver_mismch)
 9696		return 0;
 9697
 9698	p += scnprintf(p, end - p, " %-15s : ", "[error]");
 9699
 9700	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]) {
 9701		p += scnprintf(p, end - p,
 9702			       "overflow-cnt: %d, ",
 9703			       pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]);
 9704	}
 9705
 9706	if (pfwinfo->len_mismch) {
 9707		p += scnprintf(p, end - p,
 9708			       "len-mismatch: 0x%x, ",
 9709			       pfwinfo->len_mismch);
 9710	}
 9711
 9712	if (pfwinfo->fver_mismch) {
 9713		p += scnprintf(p, end - p,
 9714			       "fver-mismatch: 0x%x, ",
 9715			       pfwinfo->fver_mismch);
 9716	}
 9717
 9718	/* cycle statistics exceptions */
 9719	if (exception_map || except_cnt) {
 9720		p += scnprintf(p, end - p,
 9721			       "exception-type: 0x%x, exception-cnt = %d",
 9722			       exception_map, except_cnt);
 9723	}
 9724	p += scnprintf(p, end - p, "\n");
 9725
 9726	return p - buf;
 9727}
 9728
 9729static int _show_fbtc_tdma(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9730{
 9731	struct rtw89_btc *btc = &rtwdev->btc;
 9732	const struct rtw89_btc_ver *ver = btc->ver;
 9733	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 9734	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
 9735	struct rtw89_btc_fbtc_tdma *t = NULL;
 9736	char *p = buf, *end = buf + bufsz;
 9737
 9738	pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
 9739	if (!pcinfo->valid)
 9740		return 0;
 9741
 9742	if (ver->fcxtdma == 1)
 9743		t = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
 9744	else
 9745		t = &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma;
 9746
 9747	p += scnprintf(p, end - p,
 9748		       " %-15s : ", "[tdma_policy]");
 9749	p += scnprintf(p, end - p,
 9750		       "type:%d, rx_flow_ctrl:%d, tx_pause:%d, ",
 9751		       (u32)t->type,
 9752		       t->rxflctrl, t->txpause);
 9753
 9754	p += scnprintf(p, end - p,
 9755		       "wl_toggle_n:%d, leak_n:%d, ext_ctrl:%d, ",
 9756		       t->wtgle_n, t->leak_n, t->ext_ctrl);
 9757
 9758	p += scnprintf(p, end - p,
 9759		       "policy_type:%d",
 9760		       (u32)btc->policy_type);
 9761
 9762	p += scnprintf(p, end - p, "\n");
 9763
 9764	return p - buf;
 9765}
 9766
 9767static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9768{
 9769	struct rtw89_btc *btc = &rtwdev->btc;
 9770	struct rtw89_btc_dm *dm = &btc->dm;
 9771	char *p = buf, *end = buf + bufsz;
 9772	u16 dur, cxtype;
 9773	u32 tbl;
 9774	u8 i = 0;
 9775
 9776	for (i = 0; i < CXST_MAX; i++) {
 9777		if (btc->ver->fcxslots == 1) {
 9778			dur = le16_to_cpu(dm->slot_now.v1[i].dur);
 9779			tbl = le32_to_cpu(dm->slot_now.v1[i].cxtbl);
 9780			cxtype = le16_to_cpu(dm->slot_now.v1[i].cxtype);
 9781		} else if (btc->ver->fcxslots == 7) {
 9782			dur = le16_to_cpu(dm->slot_now.v7[i].dur);
 9783			tbl = le32_to_cpu(dm->slot_now.v7[i].cxtbl);
 9784			cxtype = le16_to_cpu(dm->slot_now.v7[i].cxtype);
 9785		} else {
 9786			return 0;
 9787		}
 9788
 9789		if (i % 5 == 0)
 9790			p += scnprintf(p, end - p,
 9791				       " %-15s : %5s[%03d/0x%x/%d]",
 9792				       "[slot_list]",
 9793				       id_to_slot((u32)i),
 9794				       dur, tbl, cxtype);
 9795		else
 9796			p += scnprintf(p, end - p,
 9797				       ", %5s[%03d/0x%x/%d]",
 9798				       id_to_slot((u32)i),
 9799				       dur, tbl, cxtype);
 9800
 9801		if (i % 5 == 4)
 9802			p += scnprintf(p, end - p, "\n");
 9803	}
 9804
 9805	return p - buf;
 9806}
 9807
 9808static int _show_fbtc_cysta_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9809{
 9810	struct rtw89_btc *btc = &rtwdev->btc;
 9811	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 9812	struct rtw89_btc_dm *dm = &btc->dm;
 9813	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
 9814	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
 9815	struct rtw89_btc_fbtc_cysta_v2 *pcysta_le32 = NULL;
 9816	union rtw89_btc_fbtc_rxflct r;
 9817	u16 cycle, c_begin, c_end, store_index;
 9818	char *p = buf, *end = buf + bufsz;
 9819	u8 i, cnt = 0, slot_pair;
 9820
 9821	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
 9822	if (!pcinfo->valid)
 9823		return 0;
 9824
 9825	pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
 9826	p += scnprintf(p, end - p,
 9827		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
 9828		       "[cycle_cnt]",
 9829		       le16_to_cpu(pcysta_le32->cycles),
 9830		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL]),
 9831		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_ALL_OK]),
 9832		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_SLOT]),
 9833		       le32_to_cpu(pcysta_le32->bcn_cnt[CXBCN_BT_OK]));
 9834
 9835	for (i = 0; i < CXST_MAX; i++) {
 9836		if (!le32_to_cpu(pcysta_le32->slot_cnt[i]))
 9837			continue;
 9838		p += scnprintf(p, end - p, ", %s:%d", id_to_slot((u32)i),
 9839			       le32_to_cpu(pcysta_le32->slot_cnt[i]));
 9840	}
 9841
 9842	if (dm->tdma_now.rxflctrl) {
 9843		p += scnprintf(p, end - p, ", leak_rx:%d",
 9844			       le32_to_cpu(pcysta_le32->leakrx_cnt));
 9845	}
 9846
 9847	if (le32_to_cpu(pcysta_le32->collision_cnt)) {
 9848		p += scnprintf(p, end - p, ", collision:%d",
 9849			       le32_to_cpu(pcysta_le32->collision_cnt));
 9850	}
 9851
 9852	if (le32_to_cpu(pcysta_le32->skip_cnt)) {
 9853		p += scnprintf(p, end - p, ", skip:%d",
 9854			       le32_to_cpu(pcysta_le32->skip_cnt));
 9855	}
 9856	p += scnprintf(p, end - p, "\n");
 9857
 9858	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
 9859		       "[cycle_time]",
 9860		       le16_to_cpu(pcysta_le32->tavg_cycle[CXT_WL]),
 9861		       le16_to_cpu(pcysta_le32->tavg_cycle[CXT_BT]),
 9862		       le16_to_cpu(pcysta_le32->tavg_lk) / 1000,
 9863		       le16_to_cpu(pcysta_le32->tavg_lk) % 1000);
 9864	p += scnprintf(p, end - p, ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
 9865		       le16_to_cpu(pcysta_le32->tmax_cycle[CXT_WL]),
 9866		       le16_to_cpu(pcysta_le32->tmax_cycle[CXT_BT]),
 9867		       le16_to_cpu(pcysta_le32->tmax_lk) / 1000,
 9868		       le16_to_cpu(pcysta_le32->tmax_lk) % 1000);
 9869	p += scnprintf(p, end - p, ", maxdiff_t[wl:%d/bt:%d]\n",
 9870		       le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_WL]),
 9871		       le16_to_cpu(pcysta_le32->tmaxdiff_cycle[CXT_BT]));
 9872
 9873	if (le16_to_cpu(pcysta_le32->cycles) <= 1)
 9874		goto out;
 9875
 9876	/* 1 cycle record 1 wl-slot and 1 bt-slot */
 9877	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
 9878
 9879	if (le16_to_cpu(pcysta_le32->cycles) <= slot_pair)
 9880		c_begin = 1;
 9881	else
 9882		c_begin = le16_to_cpu(pcysta_le32->cycles) - slot_pair + 1;
 9883
 9884	c_end = le16_to_cpu(pcysta_le32->cycles);
 9885
 9886	for (cycle = c_begin; cycle <= c_end; cycle++) {
 9887		cnt++;
 9888		store_index = ((cycle - 1) % slot_pair) * 2;
 9889
 9890		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1)
 9891			p += scnprintf(p, end - p,
 9892				       " %-15s : ->b%02d->w%02d",
 9893				       "[cycle_step]",
 9894				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index]),
 9895				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1]));
 9896		else
 9897			p += scnprintf(p, end - p,
 9898				       "->b%02d->w%02d",
 9899				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index]),
 9900				       le16_to_cpu(pcysta_le32->tslot_cycle[store_index + 1]));
 9901		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
 9902			p += scnprintf(p, end - p, "\n");
 9903	}
 9904
 9905	if (a2dp->exist) {
 9906		p += scnprintf(p, end - p,
 9907			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
 9908			       "[a2dp_t_sta]",
 9909			       le16_to_cpu(pcysta_le32->a2dpept),
 9910			       le16_to_cpu(pcysta_le32->a2dpeptto));
 9911
 9912		p += scnprintf(p, end - p,
 9913			       ", avg_t:%d, max_t:%d",
 9914			       le16_to_cpu(pcysta_le32->tavg_a2dpept),
 9915			       le16_to_cpu(pcysta_le32->tmax_a2dpept));
 9916		r.val = dm->tdma_now.rxflctrl;
 9917
 9918		if (r.type && r.tgln_n) {
 9919			p += scnprintf(p, end - p,
 9920				       ", cycle[PSTDMA:%d/TDMA:%d], ",
 9921				       le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_ON]),
 9922				       le16_to_cpu(pcysta_le32->cycles_a2dp[CXT_FLCTRL_OFF]));
 9923
 9924			p += scnprintf(p, end - p,
 9925				       "avg_t[PSTDMA:%d/TDMA:%d], ",
 9926				       le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_ON]),
 9927				       le16_to_cpu(pcysta_le32->tavg_a2dp[CXT_FLCTRL_OFF]));
 9928
 9929			p += scnprintf(p, end - p,
 9930				       "max_t[PSTDMA:%d/TDMA:%d]",
 9931				       le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_ON]),
 9932				       le16_to_cpu(pcysta_le32->tmax_a2dp[CXT_FLCTRL_OFF]));
 9933		}
 9934		p += scnprintf(p, end - p, "\n");
 9935	}
 9936
 9937out:
 9938	return p - buf;
 9939}
 9940
 9941static int _show_fbtc_cysta_v3(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
 9942{
 9943	struct rtw89_btc *btc = &rtwdev->btc;
 9944	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
 9945	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 9946	struct rtw89_btc_dm *dm = &btc->dm;
 9947	struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx;
 9948	struct rtw89_btc_fbtc_cysta_v3 *pcysta;
 9949	struct rtw89_btc_rpt_cmn_info *pcinfo;
 9950	u8 i, cnt = 0, slot_pair, divide_cnt;
 9951	u16 cycle, c_begin, c_end, store_index;
 9952	char *p = buf, *end = buf + bufsz;
 9953
 9954	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
 9955	if (!pcinfo->valid)
 9956		return 0;
 9957
 9958	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
 9959	p += scnprintf(p, end - p,
 9960		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
 9961		       "[cycle_cnt]",
 9962		       le16_to_cpu(pcysta->cycles),
 9963		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
 9964		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
 9965		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
 9966		       le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
 9967
 9968	for (i = 0; i < CXST_MAX; i++) {
 9969		if (!le32_to_cpu(pcysta->slot_cnt[i]))
 9970			continue;
 9971
 9972		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
 9973			       le32_to_cpu(pcysta->slot_cnt[i]));
 9974	}
 9975
 9976	if (dm->tdma_now.rxflctrl)
 9977		p += scnprintf(p, end - p, ", leak_rx:%d",
 9978			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
 9979
 9980	if (le32_to_cpu(pcysta->collision_cnt))
 9981		p += scnprintf(p, end - p, ", collision:%d",
 9982			       le32_to_cpu(pcysta->collision_cnt));
 9983
 9984	if (le32_to_cpu(pcysta->skip_cnt))
 9985		p += scnprintf(p, end - p, ", skip:%d",
 9986			       le32_to_cpu(pcysta->skip_cnt));
 9987
 9988	p += scnprintf(p, end - p, "\n");
 9989
 9990	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
 9991		       "[cycle_time]",
 9992		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
 9993		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
 9994		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
 9995		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
 9996	p += scnprintf(p, end - p,
 9997		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
 9998		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
 9999		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
10000		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
10001		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
10002	p += scnprintf(p, end - p,
10003		       ", maxdiff_t[wl:%d/bt:%d]\n",
10004		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]),
10005		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT]));
10006
10007	cycle = le16_to_cpu(pcysta->cycles);
10008	if (cycle <= 1)
10009		goto out;
10010
10011	/* 1 cycle record 1 wl-slot and 1 bt-slot */
10012	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
10013
10014	if (cycle <= slot_pair)
10015		c_begin = 1;
10016	else
10017		c_begin = cycle - slot_pair + 1;
10018
10019	c_end = cycle;
10020
10021	if (a2dp->exist)
10022		divide_cnt = 3;
10023	else
10024		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
10025
10026	for (cycle = c_begin; cycle <= c_end; cycle++) {
10027		cnt++;
10028		store_index = ((cycle - 1) % slot_pair) * 2;
10029
10030		if (cnt % divide_cnt == 1)
10031			p += scnprintf(p, end - p, " %-15s : ",
10032				       "[cycle_step]");
10033
10034		p += scnprintf(p, end - p, "->b%02d",
10035			       le16_to_cpu(pcysta->slot_step_time[store_index]));
10036		if (a2dp->exist) {
10037			a2dp_trx = &pcysta->a2dp_trx[store_index];
10038			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10039				       a2dp_trx->empty_cnt,
10040				       a2dp_trx->retry_cnt,
10041				       a2dp_trx->tx_rate ? 3 : 2,
10042				       a2dp_trx->tx_cnt,
10043				       a2dp_trx->ack_cnt,
10044				       a2dp_trx->nack_cnt);
10045		}
10046		p += scnprintf(p, end - p, "->w%02d",
10047			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
10048		if (a2dp->exist) {
10049			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
10050			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10051				       a2dp_trx->empty_cnt,
10052				       a2dp_trx->retry_cnt,
10053				       a2dp_trx->tx_rate ? 3 : 2,
10054				       a2dp_trx->tx_cnt,
10055				       a2dp_trx->ack_cnt,
10056				       a2dp_trx->nack_cnt);
10057		}
10058		if (cnt % divide_cnt == 0 || cnt == c_end)
10059			p += scnprintf(p, end - p, "\n");
10060	}
10061
10062	if (a2dp->exist) {
10063		p += scnprintf(p, end - p,
10064			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
10065			       "[a2dp_t_sta]",
10066			       le16_to_cpu(pcysta->a2dp_ept.cnt),
10067			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
10068
10069		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
10070			       le16_to_cpu(pcysta->a2dp_ept.tavg),
10071			       le16_to_cpu(pcysta->a2dp_ept.tmax));
10072
10073		p += scnprintf(p, end - p, "\n");
10074	}
10075
10076out:
10077	return p - buf;
10078}
10079
10080static int _show_fbtc_cysta_v4(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10081{
10082	struct rtw89_btc *btc = &rtwdev->btc;
10083	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
10084	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10085	struct rtw89_btc_dm *dm = &btc->dm;
10086	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
10087	struct rtw89_btc_fbtc_cysta_v4 *pcysta;
10088	struct rtw89_btc_rpt_cmn_info *pcinfo;
10089	u8 i, cnt = 0, slot_pair, divide_cnt;
10090	u16 cycle, c_begin, c_end, store_index;
10091	char *p = buf, *end = buf + bufsz;
10092
10093	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
10094	if (!pcinfo->valid)
10095		return 0;
10096
10097	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v4;
10098	p += scnprintf(p, end - p,
10099		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
10100		       "[cycle_cnt]",
10101		       le16_to_cpu(pcysta->cycles),
10102		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
10103		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
10104		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
10105		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
10106
10107	for (i = 0; i < CXST_MAX; i++) {
10108		if (!le16_to_cpu(pcysta->slot_cnt[i]))
10109			continue;
10110
10111		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
10112			       le16_to_cpu(pcysta->slot_cnt[i]));
10113	}
10114
10115	if (dm->tdma_now.rxflctrl)
10116		p += scnprintf(p, end - p, ", leak_rx:%d",
10117			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
10118
10119	if (pcysta->collision_cnt)
10120		p += scnprintf(p, end - p, ", collision:%d",
10121			       pcysta->collision_cnt);
10122
10123	if (le16_to_cpu(pcysta->skip_cnt))
10124		p += scnprintf(p, end - p, ", skip:%d",
10125			       le16_to_cpu(pcysta->skip_cnt));
10126
10127	p += scnprintf(p, end - p, "\n");
10128
10129	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
10130		       "[cycle_time]",
10131		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
10132		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
10133		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
10134		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
10135	p += scnprintf(p, end - p,
10136		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
10137		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
10138		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
10139		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
10140		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
10141	p += scnprintf(p, end - p,
10142		       ", maxdiff_t[wl:%d/bt:%d]\n",
10143		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]),
10144		       le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT]));
10145
10146	cycle = le16_to_cpu(pcysta->cycles);
10147	if (cycle <= 1)
10148		goto out;
10149
10150	/* 1 cycle record 1 wl-slot and 1 bt-slot */
10151	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
10152
10153	if (cycle <= slot_pair)
10154		c_begin = 1;
10155	else
10156		c_begin = cycle - slot_pair + 1;
10157
10158	c_end = cycle;
10159
10160	if (a2dp->exist)
10161		divide_cnt = 3;
10162	else
10163		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
10164
10165	for (cycle = c_begin; cycle <= c_end; cycle++) {
10166		cnt++;
10167		store_index = ((cycle - 1) % slot_pair) * 2;
10168
10169		if (cnt % divide_cnt == 1)
10170			p += scnprintf(p, end - p, " %-15s : ",
10171				       "[cycle_step]");
10172
10173		p += scnprintf(p, end - p, "->b%02d",
10174			       le16_to_cpu(pcysta->slot_step_time[store_index]));
10175		if (a2dp->exist) {
10176			a2dp_trx = &pcysta->a2dp_trx[store_index];
10177			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10178				       a2dp_trx->empty_cnt,
10179				       a2dp_trx->retry_cnt,
10180				       a2dp_trx->tx_rate ? 3 : 2,
10181				       a2dp_trx->tx_cnt,
10182				       a2dp_trx->ack_cnt,
10183				       a2dp_trx->nack_cnt);
10184		}
10185		p += scnprintf(p, end - p, "->w%02d",
10186			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
10187		if (a2dp->exist) {
10188			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
10189			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10190				       a2dp_trx->empty_cnt,
10191				       a2dp_trx->retry_cnt,
10192				       a2dp_trx->tx_rate ? 3 : 2,
10193				       a2dp_trx->tx_cnt,
10194				       a2dp_trx->ack_cnt,
10195				       a2dp_trx->nack_cnt);
10196		}
10197		if (cnt % divide_cnt == 0 || cnt == c_end)
10198			p += scnprintf(p, end - p, "\n");
10199	}
10200
10201	if (a2dp->exist) {
10202		p += scnprintf(p, end - p,
10203			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
10204			       "[a2dp_t_sta]",
10205			       le16_to_cpu(pcysta->a2dp_ept.cnt),
10206			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
10207
10208		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
10209			       le16_to_cpu(pcysta->a2dp_ept.tavg),
10210			       le16_to_cpu(pcysta->a2dp_ept.tmax));
10211
10212		p += scnprintf(p, end - p, "\n");
10213	}
10214
10215out:
10216	return p - buf;
10217}
10218
10219static int _show_fbtc_cysta_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10220{
10221	struct rtw89_btc *btc = &rtwdev->btc;
10222	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
10223	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10224	struct rtw89_btc_dm *dm = &btc->dm;
10225	struct rtw89_btc_fbtc_a2dp_trx_stat_v4 *a2dp_trx;
10226	struct rtw89_btc_fbtc_cysta_v5 *pcysta;
10227	struct rtw89_btc_rpt_cmn_info *pcinfo;
10228	u8 i, cnt = 0, slot_pair, divide_cnt;
10229	u16 cycle, c_begin, c_end, store_index;
10230	char *p = buf, *end = buf + bufsz;
10231
10232	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
10233	if (!pcinfo->valid)
10234		return 0;
10235
10236	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
10237	p += scnprintf(p, end - p,
10238		       " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
10239		       "[cycle_cnt]",
10240		       le16_to_cpu(pcysta->cycles),
10241		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
10242		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
10243		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
10244		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
10245
10246	for (i = 0; i < CXST_MAX; i++) {
10247		if (!le16_to_cpu(pcysta->slot_cnt[i]))
10248			continue;
10249
10250		p += scnprintf(p, end - p, ", %s:%d", id_to_slot(i),
10251			       le16_to_cpu(pcysta->slot_cnt[i]));
10252	}
10253
10254	if (dm->tdma_now.rxflctrl)
10255		p += scnprintf(p, end - p, ", leak_rx:%d",
10256			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
10257
10258	if (pcysta->collision_cnt)
10259		p += scnprintf(p, end - p, ", collision:%d",
10260			       pcysta->collision_cnt);
10261
10262	if (le16_to_cpu(pcysta->skip_cnt))
10263		p += scnprintf(p, end - p, ", skip:%d",
10264			       le16_to_cpu(pcysta->skip_cnt));
10265
10266	p += scnprintf(p, end - p, "\n");
10267
10268	p += scnprintf(p, end - p, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
10269		       "[cycle_time]",
10270		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
10271		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
10272		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
10273		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
10274	p += scnprintf(p, end - p,
10275		       ", max_t[wl:%d/bt:%d/lk:%d.%03d]\n",
10276		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
10277		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
10278		       le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
10279		       le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
10280
10281	cycle = le16_to_cpu(pcysta->cycles);
10282	if (cycle <= 1)
10283		goto out;
10284
10285	/* 1 cycle record 1 wl-slot and 1 bt-slot */
10286	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
10287
10288	if (cycle <= slot_pair)
10289		c_begin = 1;
10290	else
10291		c_begin = cycle - slot_pair + 1;
10292
10293	c_end = cycle;
10294
10295	if (a2dp->exist)
10296		divide_cnt = 3;
10297	else
10298		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
10299
10300	if (c_begin > c_end)
10301		goto out;
10302
10303	for (cycle = c_begin; cycle <= c_end; cycle++) {
10304		cnt++;
10305		store_index = ((cycle - 1) % slot_pair) * 2;
10306
10307		if (cnt % divide_cnt == 1)
10308			p += scnprintf(p, end - p, " %-15s : ",
10309				       "[cycle_step]");
10310
10311		p += scnprintf(p, end - p, "->b%02d",
10312			       le16_to_cpu(pcysta->slot_step_time[store_index]));
10313		if (a2dp->exist) {
10314			a2dp_trx = &pcysta->a2dp_trx[store_index];
10315			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10316				       a2dp_trx->empty_cnt,
10317				       a2dp_trx->retry_cnt,
10318				       a2dp_trx->tx_rate ? 3 : 2,
10319				       a2dp_trx->tx_cnt,
10320				       a2dp_trx->ack_cnt,
10321				       a2dp_trx->nack_cnt);
10322		}
10323		p += scnprintf(p, end - p, "->w%02d",
10324			       le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
10325		if (a2dp->exist) {
10326			a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
10327			p += scnprintf(p, end - p, "(%d/%d/%dM/%d/%d/%d)",
10328				       a2dp_trx->empty_cnt,
10329				       a2dp_trx->retry_cnt,
10330				       a2dp_trx->tx_rate ? 3 : 2,
10331				       a2dp_trx->tx_cnt,
10332				       a2dp_trx->ack_cnt,
10333				       a2dp_trx->nack_cnt);
10334		}
10335		if (cnt % divide_cnt == 0 || cnt == c_end)
10336			p += scnprintf(p, end - p, "\n");
10337	}
10338
10339	if (a2dp->exist) {
10340		p += scnprintf(p, end - p,
10341			       " %-15s : a2dp_ept:%d, a2dp_late:%d",
10342			       "[a2dp_t_sta]",
10343			       le16_to_cpu(pcysta->a2dp_ept.cnt),
10344			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
10345
10346		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
10347			       le16_to_cpu(pcysta->a2dp_ept.tavg),
10348			       le16_to_cpu(pcysta->a2dp_ept.tmax));
10349
10350		p += scnprintf(p, end - p, "\n");
10351	}
10352
10353out:
10354	return p - buf;
10355}
10356
10357static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10358{
10359	struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt;
10360	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt->link_info.a2dp_desc;
10361	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
10362	struct rtw89_btc_fbtc_cysta_v7 *pcysta = NULL;
10363	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
10364	struct rtw89_btc_rpt_cmn_info *pcinfo;
10365	char *p = buf, *end = buf + bufsz;
10366	u16 cycle, c_begin, c_end, s_id;
10367	u8 i, cnt = 0, divide_cnt;
10368	u8 slot_pair;
10369
10370	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
10371	if (!pcinfo->valid)
10372		return 0;
10373
10374	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
10375	p += scnprintf(p, end - p, "\n %-15s : cycle:%d", "[slot_stat]",
10376		       le16_to_cpu(pcysta->cycles));
10377
10378	for (i = 0; i < CXST_MAX; i++) {
10379		if (!le16_to_cpu(pcysta->slot_cnt[i]))
10380			continue;
10381		p += scnprintf(p, end - p, ", %s:%d",
10382			       id_to_slot(i),
10383			       le16_to_cpu(pcysta->slot_cnt[i]));
10384	}
10385
10386	if (dm->tdma_now.rxflctrl)
10387		p += scnprintf(p, end - p, ", leak_rx:%d",
10388			       le32_to_cpu(pcysta->leak_slot.cnt_rximr));
10389
10390	if (pcysta->collision_cnt)
10391		p += scnprintf(p, end - p, ", collision:%d",
10392			       pcysta->collision_cnt);
10393
10394	if (pcysta->skip_cnt)
10395		p += scnprintf(p, end - p, ", skip:%d",
10396			       le16_to_cpu(pcysta->skip_cnt));
10397
10398	p += scnprintf(p, end - p,
10399		       "\n\r %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
10400		       "[cycle_stat]",
10401		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
10402		       le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
10403		       le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
10404		       le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
10405	p += scnprintf(p, end - p,
10406		       ", max_t[wl:%d/bt:%d(>%dms:%d)/lk:%d.%03d]",
10407		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
10408		       le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
10409		       dm->bt_slot_flood, dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD],
10410		       le16_to_cpu(pcysta->leak_slot.tamx) / 1000,
10411		       le16_to_cpu(pcysta->leak_slot.tamx) % 1000);
10412	p += scnprintf(p, end - p, ", bcn[all:%d/ok:%d/in_bt:%d/in_bt_ok:%d]",
10413		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
10414		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
10415		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
10416		       le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
10417
10418	if (a2dp->exist) {
10419		p += scnprintf(p, end - p,
10420			       "\n\r %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
10421			       "[a2dp_stat]",
10422			       le16_to_cpu(pcysta->a2dp_ept.cnt),
10423			       le16_to_cpu(pcysta->a2dp_ept.cnt_timeout),
10424			       a2dp->no_empty_streak_2s,
10425			       a2dp->no_empty_streak_max);
10426
10427		p += scnprintf(p, end - p, ", avg_t:%d, max_t:%d",
10428			       le16_to_cpu(pcysta->a2dp_ept.tavg),
10429			       le16_to_cpu(pcysta->a2dp_ept.tmax));
10430	}
10431
10432	if (le16_to_cpu(pcysta->cycles) <= 1)
10433		goto out;
10434
10435	/* 1 cycle = 1 wl-slot + 1 bt-slot */
10436	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
10437
10438	if (le16_to_cpu(pcysta->cycles) <= slot_pair)
10439		c_begin = 1;
10440	else
10441		c_begin = le16_to_cpu(pcysta->cycles) - slot_pair + 1;
10442
10443	c_end = le16_to_cpu(pcysta->cycles);
10444
10445	if (a2dp->exist)
10446		divide_cnt = 2;
10447	else
10448		divide_cnt = 6;
10449
10450	if (c_begin > c_end)
10451		goto out;
10452
10453	for (cycle = c_begin; cycle <= c_end; cycle++) {
10454		cnt++;
10455		s_id = ((cycle - 1) % slot_pair) * 2;
10456
10457		if (cnt % divide_cnt == 1) {
10458			if (a2dp->exist)
10459				p += scnprintf(p, end - p, "\n\r %-15s : ",
10460					       "[slotT_wermtan]");
10461			else
10462				p += scnprintf(p, end - p, "\n\r %-15s : ",
10463					       "[slotT_rxerr]");
10464		}
10465
10466		p += scnprintf(p, end - p, "->b%d",
10467			       le16_to_cpu(pcysta->slot_step_time[s_id]));
10468
10469		if (a2dp->exist)
10470			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
10471				       pcysta->wl_rx_err_ratio[s_id],
10472				       pcysta->a2dp_trx[s_id].empty_cnt,
10473				       pcysta->a2dp_trx[s_id].retry_cnt,
10474				       (pcysta->a2dp_trx[s_id].tx_rate ? 3 : 2),
10475				       pcysta->a2dp_trx[s_id].tx_cnt,
10476				       pcysta->a2dp_trx[s_id].ack_cnt,
10477				       pcysta->a2dp_trx[s_id].nack_cnt);
10478		else
10479			p += scnprintf(p, end - p, "(%d)",
10480				       pcysta->wl_rx_err_ratio[s_id]);
10481
10482		p += scnprintf(p, end - p, "->w%d",
10483			       le16_to_cpu(pcysta->slot_step_time[s_id + 1]));
10484
10485		if (a2dp->exist)
10486			p += scnprintf(p, end - p, "(%d/%d/%d/%dM/%d/%d/%d)",
10487				       pcysta->wl_rx_err_ratio[s_id + 1],
10488				       pcysta->a2dp_trx[s_id + 1].empty_cnt,
10489				       pcysta->a2dp_trx[s_id + 1].retry_cnt,
10490				       (pcysta->a2dp_trx[s_id + 1].tx_rate ? 3 : 2),
10491				       pcysta->a2dp_trx[s_id + 1].tx_cnt,
10492				       pcysta->a2dp_trx[s_id + 1].ack_cnt,
10493				       pcysta->a2dp_trx[s_id + 1].nack_cnt);
10494		else
10495			p += scnprintf(p, end - p, "(%d)",
10496				       pcysta->wl_rx_err_ratio[s_id + 1]);
10497	}
10498
10499out:
10500	return p - buf;
10501}
10502
10503static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10504{
10505	struct rtw89_btc *btc = &rtwdev->btc;
10506	const struct rtw89_btc_ver *ver = btc->ver;
10507	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10508	struct rtw89_btc_rpt_cmn_info *pcinfo;
10509	union rtw89_btc_fbtc_cynullsta_info *ns;
10510	char *p = buf, *end = buf + bufsz;
10511	u8 i = 0;
10512
10513	if (!btc->dm.tdma_now.rxflctrl)
10514		return 0;
10515
10516	pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
10517	if (!pcinfo->valid)
10518		return 0;
10519
10520	ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
10521	if (ver->fcxnullsta == 1) {
10522		for (i = 0; i < 2; i++) {
10523			p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
10524			p += scnprintf(p, end - p, "null-%d", i);
10525			p += scnprintf(p, end - p, "[ok:%d/",
10526				       le32_to_cpu(ns->v1.result[i][1]));
10527			p += scnprintf(p, end - p, "fail:%d/",
10528				       le32_to_cpu(ns->v1.result[i][0]));
10529			p += scnprintf(p, end - p, "on_time:%d/",
10530				       le32_to_cpu(ns->v1.result[i][2]));
10531			p += scnprintf(p, end - p, "retry:%d/",
10532				       le32_to_cpu(ns->v1.result[i][3]));
10533			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
10534				       le32_to_cpu(ns->v1.avg_t[i]) / 1000,
10535				       le32_to_cpu(ns->v1.avg_t[i]) % 1000);
10536			p += scnprintf(p, end - p, "max_t:%d.%03d]",
10537				       le32_to_cpu(ns->v1.max_t[i]) / 1000,
10538				       le32_to_cpu(ns->v1.max_t[i]) % 1000);
10539		}
10540	} else if (ver->fcxnullsta == 7) {
10541		for (i = 0; i < 2; i++) {
10542			p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
10543			p += scnprintf(p, end - p, "null-%d", i);
10544			p += scnprintf(p, end - p, "[Tx:%d/",
10545				       le32_to_cpu(ns->v7.result[i][4]));
10546			p += scnprintf(p, end - p, "[ok:%d/",
10547				       le32_to_cpu(ns->v7.result[i][1]));
10548			p += scnprintf(p, end - p, "fail:%d/",
10549				       le32_to_cpu(ns->v7.result[i][0]));
10550			p += scnprintf(p, end - p, "on_time:%d/",
10551				       le32_to_cpu(ns->v7.result[i][2]));
10552			p += scnprintf(p, end - p, "retry:%d/",
10553				       le32_to_cpu(ns->v7.result[i][3]));
10554			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
10555				       le32_to_cpu(ns->v7.tavg[i]) / 1000,
10556				       le32_to_cpu(ns->v7.tavg[i]) % 1000);
10557			p += scnprintf(p, end - p, "max_t:%d.%03d]",
10558				       le32_to_cpu(ns->v7.tmax[i]) / 1000,
10559				       le32_to_cpu(ns->v7.tmax[i]) % 1000);
10560		}
10561	} else {
10562		for (i = 0; i < 2; i++) {
10563			p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]");
10564			p += scnprintf(p, end - p, "null-%d", i);
10565			p += scnprintf(p, end - p, "[Tx:%d/",
10566				       le32_to_cpu(ns->v2.result[i][4]));
10567			p += scnprintf(p, end - p, "[ok:%d/",
10568				       le32_to_cpu(ns->v2.result[i][1]));
10569			p += scnprintf(p, end - p, "fail:%d/",
10570				       le32_to_cpu(ns->v2.result[i][0]));
10571			p += scnprintf(p, end - p, "on_time:%d/",
10572				       le32_to_cpu(ns->v2.result[i][2]));
10573			p += scnprintf(p, end - p, "retry:%d/",
10574				       le32_to_cpu(ns->v2.result[i][3]));
10575			p += scnprintf(p, end - p, "avg_t:%d.%03d/",
10576				       le32_to_cpu(ns->v2.avg_t[i]) / 1000,
10577				       le32_to_cpu(ns->v2.avg_t[i]) % 1000);
10578			p += scnprintf(p, end - p, "max_t:%d.%03d]",
10579				       le32_to_cpu(ns->v2.max_t[i]) / 1000,
10580				       le32_to_cpu(ns->v2.max_t[i]) % 1000);
10581		}
10582	}
10583
10584	return p - buf;
10585}
10586
10587static int _show_fbtc_step_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10588{
10589	struct rtw89_btc *btc = &rtwdev->btc;
10590	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10591	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
10592	struct rtw89_btc_fbtc_steps_v2 *pstep = NULL;
10593	const struct rtw89_btc_ver *ver = btc->ver;
10594	char *p = buf, *end = buf + bufsz;
10595	u8 type, val, cnt = 0, state = 0;
10596	bool outloop = false;
10597	u16 i, diff_t, n_start = 0, n_stop = 0;
10598	u16 pos_old, pos_new, trace_step;
10599
10600	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
10601	if (!pcinfo->valid)
10602		return 0;
10603
10604	pstep = &pfwinfo->rpt_fbtc_step.finfo.v2;
10605	pos_old = le16_to_cpu(pstep->pos_old);
10606	pos_new = le16_to_cpu(pstep->pos_new);
10607
10608	if (pcinfo->req_fver != pstep->fver)
10609		return 0;
10610
10611	/* store step info by using ring instead of FIFO*/
10612	do {
10613		switch (state) {
10614		case 0:
10615			if (ver->fcxctrl == 7 || ver->fcxctrl == 1)
10616				trace_step = 50;
10617			else
10618				trace_step = btc->ctrl.ctrl.trace_step;
10619
10620			n_start = pos_old;
10621			if (pos_new >=  pos_old)
10622				n_stop = pos_new;
10623			else
10624				n_stop = trace_step - 1;
10625
10626			state = 1;
10627			break;
10628		case 1:
10629			for (i = n_start; i <= n_stop; i++) {
10630				type = pstep->step[i].type;
10631				val = pstep->step[i].val;
10632				diff_t = le16_to_cpu(pstep->step[i].difft);
10633
10634				if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
10635					continue;
10636
10637				if (cnt % 10 == 0)
10638					p += scnprintf(p, end - p,
10639						       " %-15s : ", "[steps]");
10640
10641				p += scnprintf(p, end - p,
10642					       "-> %s(%02d)(%02d)",
10643					       (type == CXSTEP_SLOT ? "SLT" :
10644						"EVT"), (u32)val, diff_t);
10645				if (cnt % 10 == 9)
10646					p += scnprintf(p, end - p, "\n");
10647				cnt++;
10648			}
10649
10650			state = 2;
10651			break;
10652		case 2:
10653			if (pos_new <  pos_old && n_start != 0) {
10654				n_start = 0;
10655				n_stop = pos_new;
10656				state = 1;
10657			} else {
10658				outloop = true;
10659			}
10660			break;
10661		}
10662	} while (!outloop);
10663
10664	return p - buf;
10665}
10666
10667static int _show_fbtc_step_v3(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10668{
10669	struct rtw89_btc *btc = &rtwdev->btc;
10670	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10671	struct rtw89_btc_rpt_cmn_info *pcinfo;
10672	struct rtw89_btc_fbtc_steps_v3 *pstep;
10673	u32 i, n_begin, n_end, array_idx, cnt = 0;
10674	char *p = buf, *end = buf + bufsz;
10675	u8 type, val;
10676	u16 diff_t;
10677
10678	if ((pfwinfo->rpt_en_map &
10679	     rtw89_btc_fw_rpt_ver(rtwdev, RPT_EN_FW_STEP_INFO)) == 0)
10680		return 0;
10681
10682	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
10683	if (!pcinfo->valid)
10684		return 0;
10685
10686	pstep = &pfwinfo->rpt_fbtc_step.finfo.v3;
10687	if (pcinfo->req_fver != pstep->fver)
10688		return 0;
10689
10690	if (le32_to_cpu(pstep->cnt) <= FCXDEF_STEP)
10691		n_begin = 1;
10692	else
10693		n_begin = le32_to_cpu(pstep->cnt) - FCXDEF_STEP + 1;
10694
10695	n_end = le32_to_cpu(pstep->cnt);
10696
10697	if (n_begin > n_end)
10698		return 0;
10699
10700	/* restore step info by using ring instead of FIFO */
10701	for (i = n_begin; i <= n_end; i++) {
10702		array_idx = (i - 1) % FCXDEF_STEP;
10703		type = pstep->step[array_idx].type;
10704		val = pstep->step[array_idx].val;
10705		diff_t = le16_to_cpu(pstep->step[array_idx].difft);
10706
10707		if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
10708			continue;
10709
10710		if (cnt % 10 == 0)
10711			p += scnprintf(p, end - p, " %-15s : ", "[steps]");
10712
10713		p += scnprintf(p, end - p, "-> %s(%02d)",
10714			       (type == CXSTEP_SLOT ?
10715				id_to_slot((u32)val) :
10716				id_to_evt((u32)val)), diff_t);
10717
10718		if (cnt % 10 == 9)
10719			p += scnprintf(p, end - p, "\n");
10720
10721		cnt++;
10722	}
10723
10724	return p - buf;
10725}
10726
10727static int _show_fw_dm_msg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10728{
10729	struct rtw89_btc *btc = &rtwdev->btc;
10730	const struct rtw89_btc_ver *ver = btc->ver;
10731	char *p = buf, *end = buf + bufsz;
10732
10733	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
10734		goto out;
10735
10736	p += _show_error(rtwdev, p, end - p);
10737	p += _show_fbtc_tdma(rtwdev, p, end - p);
10738	p += _show_fbtc_slots(rtwdev, p, end - p);
10739
10740	if (ver->fcxcysta == 2)
10741		p += _show_fbtc_cysta_v2(rtwdev, p, end - p);
10742	else if (ver->fcxcysta == 3)
10743		p += _show_fbtc_cysta_v3(rtwdev, p, end - p);
10744	else if (ver->fcxcysta == 4)
10745		p += _show_fbtc_cysta_v4(rtwdev, p, end - p);
10746	else if (ver->fcxcysta == 5)
10747		p += _show_fbtc_cysta_v5(rtwdev, p, end - p);
10748	else if (ver->fcxcysta == 7)
10749		p += _show_fbtc_cysta_v7(rtwdev, p, end - p);
10750
10751	p += _show_fbtc_nullsta(rtwdev, p, end - p);
10752
10753	if (ver->fcxstep == 2)
10754		p += _show_fbtc_step_v2(rtwdev, p, end - p);
10755	else if (ver->fcxstep == 3)
10756		p += _show_fbtc_step_v3(rtwdev, p, end - p);
10757
10758out:
10759	return p - buf;
10760}
10761
10762static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt_cfg)
10763{
10764	const struct rtw89_chip_info *chip = rtwdev->chip;
10765	struct rtw89_mac_ax_gnt *gnt;
10766	u32 val, status;
10767
10768	if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
10769	    chip->chip_id == RTL8851B || chip->chip_id == RTL8852BT) {
10770		rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
10771		rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status);
10772
10773		gnt = &gnt_cfg->band[0];
10774		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SW_CTRL);
10775		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0_STA);
10776		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SW_CTRL);
10777		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0_STA);
10778
10779		gnt = &gnt_cfg->band[1];
10780		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SW_CTRL);
10781		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1_STA);
10782		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SW_CTRL);
10783		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1_STA);
10784	} else if (chip->chip_id == RTL8852C) {
10785		val = rtw89_read32(rtwdev, R_AX_GNT_SW_CTRL);
10786		status = rtw89_read32(rtwdev, R_AX_GNT_VAL_V1);
10787
10788		gnt = &gnt_cfg->band[0];
10789		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SWCTRL);
10790		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0);
10791		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SWCTRL);
10792		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0);
10793
10794		gnt = &gnt_cfg->band[1];
10795		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SWCTRL);
10796		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1);
10797		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SWCTRL);
10798		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1);
10799	} else {
10800		return;
10801	}
10802}
10803
10804static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10805{
10806	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
10807	const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
10808	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
10809	union rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
10810	char *p = buf, *end = buf + bufsz;
10811	u8 *gpio_map, i;
10812	u32 en_map;
10813
10814	pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
10815	gdbg = &rtwdev->btc.fwinfo.rpt_fbtc_gpio_dbg.finfo;
10816	if (!pcinfo->valid) {
10817		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10818			    "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
10819			    __func__);
10820		goto out;
10821	}
10822
10823	if (ver->fcxgpiodbg == 7) {
10824		en_map = le32_to_cpu(gdbg->v7.en_map);
10825		gpio_map = gdbg->v7.gpio_map;
10826	} else {
10827		en_map = le32_to_cpu(gdbg->v1.en_map);
10828		gpio_map = gdbg->v1.gpio_map;
10829	}
10830
10831	if (!en_map)
10832		goto out;
10833
10834	p += scnprintf(p, end - p, " %-15s : enable_map:0x%08x",
10835		       "[gpio_dbg]", en_map);
10836
10837	for (i = 0; i < BTC_DBG_MAX1; i++) {
10838		if (!(en_map & BIT(i)))
10839			continue;
10840		p += scnprintf(p, end - p, ", %s->GPIO%d", id_to_gdbg(i),
10841			       gpio_map[i]);
10842	}
10843	p += scnprintf(p, end - p, "\n");
10844
10845out:
10846	return p - buf;
10847}
10848
10849static int _show_mreg_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10850{
10851	const struct rtw89_chip_info *chip = rtwdev->chip;
10852	struct rtw89_btc *btc = &rtwdev->btc;
10853	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10854	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
10855	struct rtw89_btc_fbtc_mreg_val_v1 *pmreg = NULL;
10856	struct rtw89_btc_cx *cx = &btc->cx;
10857	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10858	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
10859	struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
10860	struct rtw89_mac_ax_gnt gnt;
10861	char *p = buf, *end = buf + bufsz;
10862	u8 i = 0, type = 0, cnt = 0;
10863	u32 val, offset;
10864
10865	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
10866		return 0;
10867
10868	p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
10869
10870	p += scnprintf(p, end - p,
10871		       " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
10872		       "[scoreboard]", wl->scbd,
10873		       cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
10874		       bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
10875		       cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
10876
10877	btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
10878	_get_gnt(rtwdev, &gnt_cfg);
10879
10880	gnt = gnt_cfg.band[0];
10881	p += scnprintf(p, end - p,
10882		       " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
10883		       "[gnt_status]",
10884		       chip->chip_id == RTL8852C ? "HW" :
10885		       btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
10886		       gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
10887		       gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
10888
10889	gnt = gnt_cfg.band[1];
10890	p += scnprintf(p, end - p, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
10891		       gnt.gnt_wl_sw_en ? "SW" : "HW",
10892		       gnt.gnt_wl,
10893		       gnt.gnt_bt_sw_en ? "SW" : "HW",
10894		       gnt.gnt_bt);
10895
10896	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
10897	if (!pcinfo->valid) {
10898		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10899			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
10900			    __func__);
10901		goto out;
10902	}
10903
10904	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v1;
10905	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10906		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
10907		    __func__, pmreg->reg_num);
10908
10909	for (i = 0; i < pmreg->reg_num; i++) {
10910		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
10911		offset = le32_to_cpu(chip->mon_reg[i].offset);
10912		val = le32_to_cpu(pmreg->mreg_val[i]);
10913
10914		if (cnt % 6 == 0)
10915			p += scnprintf(p, end - p,
10916				       " %-15s : %d_0x%04x=0x%08x",
10917				       "[reg]", (u32)type, offset, val);
10918		else
10919			p += scnprintf(p, end - p, ", %d_0x%04x=0x%08x",
10920				       (u32)type,
10921				       offset, val);
10922		if (cnt % 6 == 5)
10923			p += scnprintf(p, end - p, "\n");
10924		cnt++;
10925
10926		if (i >= pmreg->reg_num)
10927			p += scnprintf(p, end - p, "\n");
10928	}
10929
10930out:
10931	return p - buf;
10932}
10933
10934static int _show_mreg_v2(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
10935{
10936	const struct rtw89_chip_info *chip = rtwdev->chip;
10937	struct rtw89_btc *btc = &rtwdev->btc;
10938	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
10939	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
10940	struct rtw89_btc_fbtc_mreg_val_v2 *pmreg = NULL;
10941	struct rtw89_btc_cx *cx = &btc->cx;
10942	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
10943	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
10944	struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
10945	struct rtw89_mac_ax_gnt gnt;
10946	char *p = buf, *end = buf + bufsz;
10947	u8 i = 0, type = 0, cnt = 0;
10948	u32 val, offset;
10949
10950	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
10951		return 0;
10952
10953	p += scnprintf(p, end - p, "========== [HW Status] ==========\n");
10954
10955	p += scnprintf(p, end - p,
10956		       " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
10957		       "[scoreboard]", wl->scbd,
10958		       cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
10959		       bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
10960		       cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
10961
10962	btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
10963	_get_gnt(rtwdev, &gnt_cfg);
10964
10965	gnt = gnt_cfg.band[0];
10966	p += scnprintf(p, end - p,
10967		       " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], polut_type:%s",
10968		       "[gnt_status]",
10969		       chip->chip_id == RTL8852C ? "HW" :
10970		       btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
10971		       gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
10972		       gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt,
10973		       id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
10974
10975	gnt = gnt_cfg.band[1];
10976	p += scnprintf(p, end - p, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
10977		       gnt.gnt_wl_sw_en ? "SW" : "HW",
10978		       gnt.gnt_wl,
10979		       gnt.gnt_bt_sw_en ? "SW" : "HW",
10980		       gnt.gnt_bt);
10981
10982	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
10983	if (!pcinfo->valid) {
10984		rtw89_debug(rtwdev, RTW89_DBG_BTC,
10985			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
10986			    __func__);
10987		goto out;
10988	}
10989
10990	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
10991	rtw89_debug(rtwdev, RTW89_DBG_BTC,
10992		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
10993		    __func__, pmreg->reg_num);
10994
10995	for (i = 0; i < pmreg->reg_num; i++) {
10996		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
10997		offset = le32_to_cpu(chip->mon_reg[i].offset);
10998		val = le32_to_cpu(pmreg->mreg_val[i]);
10999
11000		if (cnt % 6 == 0)
11001			p += scnprintf(p, end - p,
11002				       " %-15s : %d_0x%04x=0x%08x",
11003				       "[reg]", (u32)type, offset, val);
11004		else
11005			p += scnprintf(p, end - p, ", %d_0x%04x=0x%08x",
11006				       (u32)type,
11007				       offset, val);
11008		if (cnt % 6 == 5)
11009			p += scnprintf(p, end - p, "\n");
11010		cnt++;
11011
11012		if (i >= pmreg->reg_num)
11013			p += scnprintf(p, end - p, "\n");
11014	}
11015
11016out:
11017	return p - buf;
11018}
11019
11020static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11021{
11022	struct rtw89_btc *btc = &rtwdev->btc;
11023	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11024	struct rtw89_btc_fbtc_mreg_val_v7 *pmreg = NULL;
11025	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11026	struct rtw89_btc_cx *cx = &btc->cx;
11027	struct rtw89_btc_wl_info *wl = &cx->wl;
11028	struct rtw89_btc_bt_info *bt = &cx->bt;
11029	struct rtw89_mac_ax_gnt *gnt = NULL;
11030	struct rtw89_btc_dm *dm = &btc->dm;
11031	char *p = buf, *end = buf + bufsz;
11032	u8 i, type, cnt = 0;
11033	u32 val, offset;
11034
11035	if (!(dm->coex_info_map & BTC_COEX_INFO_MREG))
11036		return 0;
11037
11038	p += scnprintf(p, end - p, "\n\r========== [HW Status] ==========");
11039
11040	p += scnprintf(p, end - p,
11041		       "\n\r %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)",
11042		       "[scoreboard]", wl->scbd,
11043		       cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
11044		       bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
11045		       cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
11046
11047	/* To avoid I/O if WL LPS or power-off  */
11048	dm->pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
11049
11050	p += scnprintf(p, end - p,
11051		       "\n\r %-15s : pta_owner:%s, pta_req_mac:MAC%d, rf_gnt_source: polut_type:%s",
11052		       "[gnt_status]",
11053		       rtwdev->chip->para_ver & BTC_FEAT_PTA_ONOFF_CTRL ? "HW" :
11054		       dm->pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
11055		       wl->pta_req_mac,
11056		       id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
11057
11058	gnt = &dm->gnt.band[RTW89_PHY_0];
11059
11060	p += scnprintf(p, end - p, ", phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d]",
11061		       gnt->gnt_wl_sw_en ? "SW" : "HW", gnt->gnt_wl,
11062		       gnt->gnt_bt_sw_en ? "SW" : "HW", gnt->gnt_bt);
11063
11064	if (rtwdev->dbcc_en) {
11065		gnt = &dm->gnt.band[RTW89_PHY_1];
11066		p += scnprintf(p, end - p,
11067			       ", phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]",
11068			       gnt->gnt_wl_sw_en ? "SW" : "HW", gnt->gnt_wl,
11069			       gnt->gnt_bt_sw_en ? "SW" : "HW", gnt->gnt_bt);
11070	}
11071
11072	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
11073	if (!pcinfo->valid)
11074		goto out;
11075
11076	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
11077
11078	for (i = 0; i < pmreg->reg_num; i++) {
11079		type = (u8)le16_to_cpu(rtwdev->chip->mon_reg[i].type);
11080		offset = le32_to_cpu(rtwdev->chip->mon_reg[i].offset);
11081		val = le32_to_cpu(pmreg->mreg_val[i]);
11082
11083		if (cnt % 6 == 0)
11084			p += scnprintf(p, end - p,
11085				       "\n\r %-15s : %s_0x%x=0x%x", "[reg]",
11086				       id_to_regtype(type), offset, val);
11087		else
11088			p += scnprintf(p, end - p, ", %s_0x%x=0x%x",
11089				       id_to_regtype(type), offset, val);
11090		cnt++;
11091	}
11092
11093out:
11094	return p - buf;
11095}
11096
11097static int _show_summary_v1(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11098{
11099	struct rtw89_btc *btc = &rtwdev->btc;
11100	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11101	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11102	struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl = NULL;
11103	struct rtw89_btc_cx *cx = &btc->cx;
11104	struct rtw89_btc_dm *dm = &btc->dm;
11105	struct rtw89_btc_wl_info *wl = &cx->wl;
11106	struct rtw89_btc_bt_info *bt = &cx->bt;
11107	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
11108	char *p = buf, *end = buf + bufsz;
11109	u8 i;
11110
11111	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11112		return 0;
11113
11114	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
11115
11116	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11117	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
11118		prptctrl = &pfwinfo->rpt_ctrl.finfo.v1;
11119
11120		p += scnprintf(p, end - p,
11121			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
11122			       "[summary]", pfwinfo->cnt_h2c,
11123			       pfwinfo->cnt_h2c_fail, prptctrl->h2c_cnt,
11124			       pfwinfo->cnt_c2h, prptctrl->c2h_cnt);
11125
11126		p += scnprintf(p, end - p,
11127			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
11128			       pfwinfo->event[BTF_EVNT_RPT],
11129			       prptctrl->rpt_cnt,
11130			       prptctrl->rpt_enable, dm->error.val);
11131
11132		if (dm->error.map.wl_fw_hang)
11133			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11134		p += scnprintf(p, end - p, "\n");
11135		p += scnprintf(p, end - p,
11136			       " %-15s : send_ok:%d, send_fail:%d, recv:%d",
11137			       "[mailbox]", prptctrl->mb_send_ok_cnt,
11138			       prptctrl->mb_send_fail_cnt,
11139			       prptctrl->mb_recv_cnt);
11140
11141		p += scnprintf(p, end - p,
11142			       "(A2DP_empty:%d, A2DP_flowstop:%d, A2DP_full:%d)\n",
11143			       prptctrl->mb_a2dp_empty_cnt,
11144			       prptctrl->mb_a2dp_flct_cnt,
11145			       prptctrl->mb_a2dp_full_cnt);
11146
11147		p += scnprintf(p, end - p,
11148			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
11149			       "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11150			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11151			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11152			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
11153
11154		p += scnprintf(p, end - p,
11155			       ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
11156			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REQ],
11157			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_GO],
11158			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REJECT],
11159			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT],
11160			       prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_FAIL]);
11161
11162		if (prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
11163			bt->rfk_info.map.timeout = 1;
11164		else
11165			bt->rfk_info.map.timeout = 0;
11166
11167		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
11168	} else {
11169		p += scnprintf(p, end - p,
11170			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
11171			       "[summary]", pfwinfo->cnt_h2c,
11172			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
11173			       pfwinfo->event[BTF_EVNT_RPT],
11174			       btc->fwinfo.rpt_en_map);
11175		p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
11176	}
11177
11178	for (i = 0; i < BTC_NCNT_NUM; i++)
11179		cnt_sum += dm->cnt_notify[i];
11180
11181	p += scnprintf(p, end - p,
11182		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11183		       "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11184		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11185
11186	p += scnprintf(p, end - p,
11187		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
11188		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11189		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11190		       cnt[BTC_NCNT_WL_STA]);
11191
11192	p += scnprintf(p, end - p,
11193		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
11194		       "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
11195		       cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
11196		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11197
11198	p += scnprintf(p, end - p,
11199		       "timer=%d, control=%d, customerize=%d\n",
11200		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
11201		       cnt[BTC_NCNT_CUSTOMERIZE]);
11202
11203	return p - buf;
11204}
11205
11206static int _show_summary_v4(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11207{
11208	struct rtw89_btc *btc = &rtwdev->btc;
11209	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11210	struct rtw89_btc_fbtc_rpt_ctrl_v4 *prptctrl;
11211	struct rtw89_btc_rpt_cmn_info *pcinfo;
11212	struct rtw89_btc_cx *cx = &btc->cx;
11213	struct rtw89_btc_dm *dm = &btc->dm;
11214	struct rtw89_btc_wl_info *wl = &cx->wl;
11215	struct rtw89_btc_bt_info *bt = &cx->bt;
11216	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
11217	char *p = buf, *end = buf + bufsz;
11218	u8 i;
11219
11220	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11221		return 0;
11222
11223	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
11224
11225	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11226	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
11227		prptctrl = &pfwinfo->rpt_ctrl.finfo.v4;
11228
11229		p += scnprintf(p, end - p,
11230			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
11231			       "[summary]", pfwinfo->cnt_h2c,
11232			       pfwinfo->cnt_h2c_fail,
11233			       le32_to_cpu(prptctrl->rpt_info.cnt_h2c),
11234			       pfwinfo->cnt_c2h,
11235			       le32_to_cpu(prptctrl->rpt_info.cnt_c2h));
11236
11237		p += scnprintf(p, end - p,
11238			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
11239			       pfwinfo->event[BTF_EVNT_RPT],
11240			       le32_to_cpu(prptctrl->rpt_info.cnt),
11241			       le32_to_cpu(prptctrl->rpt_info.en),
11242			       dm->error.val);
11243
11244		if (dm->error.map.wl_fw_hang)
11245			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11246		p += scnprintf(p, end - p, "\n");
11247		p += scnprintf(p, end - p,
11248			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
11249			       "[mailbox]",
11250			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
11251			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
11252			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
11253
11254		p += scnprintf(p, end - p,
11255			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
11256			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
11257			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
11258			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
11259			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
11260			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
11261
11262		p += scnprintf(p, end - p,
11263			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
11264			       "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11265			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11266			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11267			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
11268
11269		p += scnprintf(p, end - p,
11270			       ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
11271			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]),
11272			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_GO]),
11273			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REJECT]),
11274			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]),
11275			       le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_FAIL]));
11276
11277		if (le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
11278			bt->rfk_info.map.timeout = 1;
11279		else
11280			bt->rfk_info.map.timeout = 0;
11281
11282		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
11283	} else {
11284		p += scnprintf(p, end - p,
11285			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
11286			       "[summary]", pfwinfo->cnt_h2c,
11287			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
11288			       pfwinfo->event[BTF_EVNT_RPT],
11289			       btc->fwinfo.rpt_en_map);
11290		p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
11291	}
11292
11293	for (i = 0; i < BTC_NCNT_NUM; i++)
11294		cnt_sum += dm->cnt_notify[i];
11295
11296	p += scnprintf(p, end - p,
11297		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11298		       "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11299		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11300
11301	p += scnprintf(p, end - p,
11302		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
11303		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11304		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11305		       cnt[BTC_NCNT_WL_STA]);
11306
11307	p += scnprintf(p, end - p,
11308		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
11309		       "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
11310		       cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
11311		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11312
11313	p += scnprintf(p, end - p,
11314		       "timer=%d, control=%d, customerize=%d\n",
11315		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
11316		       cnt[BTC_NCNT_CUSTOMERIZE]);
11317
11318	return p - buf;
11319}
11320
11321static int _show_summary_v5(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11322{
11323	struct rtw89_btc *btc = &rtwdev->btc;
11324	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11325	struct rtw89_btc_fbtc_rpt_ctrl_v5 *prptctrl;
11326	struct rtw89_btc_rpt_cmn_info *pcinfo;
11327	struct rtw89_btc_cx *cx = &btc->cx;
11328	struct rtw89_btc_dm *dm = &btc->dm;
11329	struct rtw89_btc_wl_info *wl = &cx->wl;
11330	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
11331	char *p = buf, *end = buf + bufsz;
11332	u8 i;
11333
11334	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11335		return 0;
11336
11337	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
11338
11339	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11340	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
11341		prptctrl = &pfwinfo->rpt_ctrl.finfo.v5;
11342
11343		p += scnprintf(p, end - p,
11344			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ",
11345			       "[summary]", pfwinfo->cnt_h2c,
11346			       pfwinfo->cnt_h2c_fail,
11347			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
11348			       pfwinfo->cnt_c2h,
11349			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
11350			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
11351
11352		p += scnprintf(p, end - p,
11353			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
11354			       pfwinfo->event[BTF_EVNT_RPT],
11355			       le16_to_cpu(prptctrl->rpt_info.cnt),
11356			       le32_to_cpu(prptctrl->rpt_info.en));
11357
11358		if (dm->error.map.wl_fw_hang)
11359			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11360		p += scnprintf(p, end - p, "\n");
11361		p += scnprintf(p, end - p,
11362			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
11363			       "[mailbox]",
11364			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
11365			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
11366			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
11367
11368		p += scnprintf(p, end - p,
11369			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
11370			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
11371			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
11372			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
11373			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
11374			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
11375
11376		p += scnprintf(p, end - p,
11377			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]",
11378			       "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11379			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11380			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11381			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
11382
11383		p += scnprintf(p, end - p,
11384			       ", bt_rfk[req:%d]",
11385			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
11386
11387		p += scnprintf(p, end - p,
11388			       ", AOAC[RF_on:%d/RF_off:%d]",
11389			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
11390			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
11391	} else {
11392		p += scnprintf(p, end - p,
11393			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d",
11394			       "[summary]", pfwinfo->cnt_h2c,
11395			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h);
11396	}
11397
11398	if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch ||
11399	    pfwinfo->err[BTFRE_EXCEPTION]) {
11400		p += scnprintf(p, end - p, "\n");
11401		p += scnprintf(p, end - p,
11402			       " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:"
11403			       "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]",
11404			       "[ERROR]", pcinfo->valid, pfwinfo->len_mismch,
11405			       pfwinfo->fver_mismch,
11406			       pfwinfo->err[BTFRE_EXCEPTION],
11407			       wl->status.map.lps, wl->status.map.rf_off);
11408	}
11409
11410	for (i = 0; i < BTC_NCNT_NUM; i++)
11411		cnt_sum += dm->cnt_notify[i];
11412
11413	p += scnprintf(p, end - p, "\n");
11414	p += scnprintf(p, end - p,
11415		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11416		       "[notify_cnt]",
11417		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11418		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11419
11420	p += scnprintf(p, end - p,
11421		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
11422		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11423		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11424		       cnt[BTC_NCNT_WL_STA]);
11425
11426	p += scnprintf(p, end - p, "\n");
11427	p += scnprintf(p, end - p,
11428		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
11429		       "[notify_cnt]",
11430		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
11431		       cnt[BTC_NCNT_SWITCH_BAND],
11432		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11433
11434	p += scnprintf(p, end - p,
11435		       "timer=%d, control=%d, customerize=%d",
11436		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
11437		       cnt[BTC_NCNT_CUSTOMERIZE]);
11438
11439	return p - buf;
11440}
11441
11442static int _show_summary_v105(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11443{
11444	struct rtw89_btc *btc = &rtwdev->btc;
11445	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
11446	struct rtw89_btc_fbtc_rpt_ctrl_v105 *prptctrl;
11447	struct rtw89_btc_rpt_cmn_info *pcinfo;
11448	struct rtw89_btc_cx *cx = &btc->cx;
11449	struct rtw89_btc_dm *dm = &btc->dm;
11450	struct rtw89_btc_wl_info *wl = &cx->wl;
11451	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
11452	char *p = buf, *end = buf + bufsz;
11453	u8 i;
11454
11455	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11456		return 0;
11457
11458	p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
11459
11460	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11461	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
11462		prptctrl = &pfwinfo->rpt_ctrl.finfo.v105;
11463
11464		p += scnprintf(p, end - p,
11465			       " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d), ",
11466			       "[summary]", pfwinfo->cnt_h2c,
11467			       pfwinfo->cnt_h2c_fail,
11468			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
11469			       pfwinfo->cnt_c2h,
11470			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
11471			       le16_to_cpu(prptctrl->rpt_info.len_c2h));
11472
11473		p += scnprintf(p, end - p,
11474			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
11475			       pfwinfo->event[BTF_EVNT_RPT],
11476			       le16_to_cpu(prptctrl->rpt_info.cnt),
11477			       le32_to_cpu(prptctrl->rpt_info.en));
11478
11479		if (dm->error.map.wl_fw_hang)
11480			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11481		p += scnprintf(p, end - p, "\n");
11482		p += scnprintf(p, end - p,
11483			       " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
11484			       "[mailbox]",
11485			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
11486			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
11487			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
11488
11489		p += scnprintf(p, end - p,
11490			       "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
11491			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
11492			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
11493			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
11494			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
11495			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
11496
11497		p += scnprintf(p, end - p,
11498			       " %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d]",
11499			       "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11500			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11501			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11502			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
11503
11504		p += scnprintf(p, end - p,
11505			       ", bt_rfk[req:%d]",
11506			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
11507
11508		p += scnprintf(p, end - p,
11509			       ", AOAC[RF_on:%d/RF_off:%d]",
11510			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
11511			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
11512	} else {
11513		p += scnprintf(p, end - p,
11514			       " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d",
11515			       "[summary]", pfwinfo->cnt_h2c,
11516			       pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h);
11517	}
11518
11519	if (!pcinfo->valid || pfwinfo->len_mismch || pfwinfo->fver_mismch ||
11520	    pfwinfo->err[BTFRE_EXCEPTION]) {
11521		p += scnprintf(p, end - p, "\n");
11522		p += scnprintf(p, end - p,
11523			       " %-15s : WL FW rpt error!![rpt_ctrl_valid:%d/len:"
11524			       "0x%x/ver:0x%x/ex:%d/lps=%d/rf_off=%d]",
11525			       "[ERROR]", pcinfo->valid, pfwinfo->len_mismch,
11526			       pfwinfo->fver_mismch,
11527			       pfwinfo->err[BTFRE_EXCEPTION],
11528			       wl->status.map.lps, wl->status.map.rf_off);
11529	}
11530
11531	for (i = 0; i < BTC_NCNT_NUM; i++)
11532		cnt_sum += dm->cnt_notify[i];
11533
11534	p += scnprintf(p, end - p, "\n");
11535	p += scnprintf(p, end - p,
11536		       " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11537		       "[notify_cnt]",
11538		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11539		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11540
11541	p += scnprintf(p, end - p,
11542		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
11543		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11544		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11545		       cnt[BTC_NCNT_WL_STA]);
11546
11547	p += scnprintf(p, end - p, "\n");
11548	p += scnprintf(p, end - p,
11549		       " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
11550		       "[notify_cnt]",
11551		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
11552		       cnt[BTC_NCNT_SWITCH_BAND],
11553		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11554
11555	p += scnprintf(p, end - p,
11556		       "timer=%d, control=%d, customerize=%d",
11557		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
11558		       cnt[BTC_NCNT_CUSTOMERIZE]);
11559
11560	return p - buf;
11561}
11562
11563static int _show_summary_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11564{
11565	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
11566	struct rtw89_btc_fbtc_rpt_ctrl_v7 *prptctrl = NULL;
11567	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11568	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
11569	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
11570	struct rtw89_btc_wl_info *wl = &cx->wl;
11571	u32 *cnt = rtwdev->btc.dm.cnt_notify;
11572	char *p = buf, *end = buf + bufsz;
11573	u32 cnt_sum = 0;
11574	u8 i;
11575
11576	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11577		return 0;
11578
11579	p += scnprintf(p, end - p, "%s",
11580		       "\n\r========== [Statistics] ==========");
11581
11582	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11583	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
11584	    !wl->status.map.rf_off) {
11585		prptctrl = &pfwinfo->rpt_ctrl.finfo.v7;
11586
11587		p += scnprintf(p, end - p,
11588			       "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d),"
11589			       "c2h_cnt=%d(fw_send:%d, len:%d, max:%d), ",
11590			       "[summary]", pfwinfo->cnt_h2c,
11591			       pfwinfo->cnt_h2c_fail,
11592			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
11593			       pfwinfo->cnt_c2h,
11594			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
11595			       le16_to_cpu(prptctrl->rpt_info.len_c2h),
11596			       rtwdev->btc.ver->info_buf);
11597
11598		p += scnprintf(p, end - p,
11599			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
11600			       pfwinfo->event[BTF_EVNT_RPT],
11601			       le16_to_cpu(prptctrl->rpt_info.cnt),
11602			       le32_to_cpu(prptctrl->rpt_info.en));
11603
11604		if (dm->error.map.wl_fw_hang)
11605			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11606
11607		p += scnprintf(p, end - p,
11608			       "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
11609			       "[mailbox]",
11610			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
11611			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
11612			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
11613
11614		p += scnprintf(p, end - p,
11615			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
11616			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
11617			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
11618			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
11619			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
11620			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
11621
11622		p += scnprintf(p, end - p,
11623			       "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
11624			       "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11625			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11626			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11627			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT],
11628			       wl->rfk_info.proc_time);
11629
11630		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
11631			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
11632
11633		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
11634			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
11635			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
11636	} else {
11637		p += scnprintf(p, end - p,
11638			       "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
11639			       "[summary]",
11640			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
11641			       pfwinfo->cnt_c2h,
11642			       wl->status.map.lps, wl->status.map.rf_off);
11643	}
11644
11645	for (i = 0; i < BTC_NCNT_NUM; i++)
11646		cnt_sum += dm->cnt_notify[i];
11647
11648	p += scnprintf(p, end - p,
11649		       "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11650		       "[notify_cnt]",
11651		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11652		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11653
11654	p += scnprintf(p, end - p,
11655		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
11656		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11657		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11658		       cnt[BTC_NCNT_WL_STA]);
11659
11660	p += scnprintf(p, end - p,
11661		       "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
11662		       "[notify_cnt]",
11663		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
11664		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
11665		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11666
11667	p += scnprintf(p, end - p,
11668		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
11669		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
11670		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
11671		       cnt[BTC_NCNT_COUNTRYCODE]);
11672
11673	return p - buf;
11674}
11675
11676static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11677{
11678	struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
11679	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
11680	struct rtw89_btc_fbtc_rpt_ctrl_v8 *prptctrl = NULL;
11681	struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
11682	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
11683	struct rtw89_btc_wl_info *wl = &cx->wl;
11684	u32 *cnt = rtwdev->btc.dm.cnt_notify;
11685	char *p = buf, *end = buf + bufsz;
11686	u32 cnt_sum = 0;
11687	u8 i;
11688
11689	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
11690		return 0;
11691
11692	p += scnprintf(p, end - p, "%s",
11693		       "\n\r========== [Statistics] ==========");
11694
11695	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
11696	if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
11697	    !wl->status.map.rf_off) {
11698		prptctrl = &pfwinfo->rpt_ctrl.finfo.v8;
11699
11700		p += scnprintf(p, end - p,
11701			       "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
11702			       "[summary]", pfwinfo->cnt_h2c,
11703			       pfwinfo->cnt_h2c_fail,
11704			       le16_to_cpu(prptctrl->rpt_info.cnt_h2c),
11705			       pfwinfo->cnt_c2h,
11706			       le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
11707			       le16_to_cpu(prptctrl->rpt_info.len_c2h),
11708			       (prptctrl->rpt_len_max_h << 8) + prptctrl->rpt_len_max_l,
11709			       rtwdev->btc.ver->info_buf);
11710
11711		p += scnprintf(p, end - p,
11712			       "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
11713			       pfwinfo->event[BTF_EVNT_RPT],
11714			       le16_to_cpu(prptctrl->rpt_info.cnt),
11715			       le32_to_cpu(prptctrl->rpt_info.en));
11716
11717		if (dm->error.map.wl_fw_hang)
11718			p += scnprintf(p, end - p, " (WL FW Hang!!)");
11719
11720		p += scnprintf(p, end - p,
11721			       "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
11722			       "[mailbox]",
11723			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
11724			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
11725			       le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
11726
11727		p += scnprintf(p, end - p,
11728			       "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
11729			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
11730			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
11731			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
11732			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
11733			       le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
11734
11735		p += scnprintf(p, end - p,
11736			       "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
11737			       "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
11738			       cx->cnt_wl[BTC_WCNT_RFK_GO],
11739			       cx->cnt_wl[BTC_WCNT_RFK_REJECT],
11740			       cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT],
11741			       wl->rfk_info.proc_time);
11742
11743		p += scnprintf(p, end - p, ", bt_rfk[req:%d]",
11744			       le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
11745
11746		p += scnprintf(p, end - p, ", AOAC[RF_on:%d/RF_off:%d]",
11747			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
11748			       le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
11749	} else {
11750		p += scnprintf(p, end - p,
11751			       "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
11752			       "[summary]",
11753			       pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
11754			       pfwinfo->cnt_c2h,
11755			       wl->status.map.lps, wl->status.map.rf_off);
11756	}
11757
11758	for (i = 0; i < BTC_NCNT_NUM; i++)
11759		cnt_sum += dm->cnt_notify[i];
11760
11761	p += scnprintf(p, end - p,
11762		       "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
11763		       "[notify_cnt]",
11764		       cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
11765		       cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
11766
11767	p += scnprintf(p, end - p,
11768		       "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
11769		       cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
11770		       cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
11771		       cnt[BTC_NCNT_WL_STA]);
11772
11773	p += scnprintf(p, end - p,
11774		       "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
11775		       "[notify_cnt]",
11776		       cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
11777		       cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
11778		       cnt[BTC_NCNT_SPECIAL_PACKET]);
11779
11780	p += scnprintf(p, end - p,
11781		       "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
11782		       cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
11783		       rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
11784		       cnt[BTC_NCNT_COUNTRYCODE]);
11785
11786	return p - buf;
11787}
11788
11789ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
11790{
11791	struct rtw89_btc *btc = &rtwdev->btc;
11792	struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver;
11793	const struct rtw89_btc_ver *ver = btc->ver;
11794	struct rtw89_btc_dm *dm = &btc->dm;
11795	char *p = buf, *end = buf + bufsz;
11796
11797	dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++;
11798
11799	p += scnprintf(p, end - p,
11800		       "\n\n\n** Page:%3d/RunCNT:%3d **",
11801		       dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO],
11802		       dm->cnt_dm[BTC_DCNT_RUN]);
11803	p += scnprintf(p, end - p,
11804		       "\n========== [BTC FEATURE SUB VER] ==========");
11805	p += scnprintf(p, end - p,
11806		       "\n %-15s : fcxbtcrpt[%d/%d], fcxtdma[%d/%d], fcxslots[%d/%d], fcxcysta[%d/%d]",
11807		       "[FW/DRV]", fwsubver->fcxbtcrpt, ver->fcxbtcrpt,
11808		       fwsubver->fcxtdma, ver->fcxtdma, fwsubver->fcxslots,
11809		       ver->fcxslots, fwsubver->fcxcysta, ver->fcxcysta);
11810	p += scnprintf(p, end - p,
11811		       "\n %-15s : fcxstep[%d/%d], fcxnullsta[%d/%d], fcxmreg[%d/%d], fcxgpiodbg[%d/%d]",
11812		       "[FW/DRV]", fwsubver->fcxstep, ver->fcxstep,
11813		       fwsubver->fcxnullsta, ver->fcxnullsta, fwsubver->fcxmreg,
11814		       ver->fcxmreg, fwsubver->fcxgpiodbg, ver->fcxgpiodbg);
11815	p += scnprintf(p, end - p,
11816		       "\n %-15s : fcxbtver[%d/%d], fcxbtscan[%d/%d], fcxbtafh[%d/%d], fcxbtdevinfo[%d/%d]",
11817		       "[FW/DRV]", fwsubver->fcxbtver, ver->fcxbtver,
11818		       fwsubver->fcxbtscan, ver->fcxbtscan, fwsubver->fcxbtafh,
11819		       ver->fcxbtafh, fwsubver->fcxbtdevinfo, ver->fcxbtdevinfo);
11820	p += scnprintf(p, end - p,
11821		       "\n %-15s : fcxosi[%d/%d], fcxmlo[%d/%d],",
11822		       "[FW/DRV]", fwsubver->fcxosi, ver->fcxosi,
11823		       fwsubver->fcxmlo, ver->fcxmlo);
11824
11825	p += _show_cx_info(rtwdev, p, end - p);
11826	p += _show_wl_info(rtwdev, p, end - p);
11827	p += _show_bt_info(rtwdev, p, end - p);
11828	p += _show_dm_info(rtwdev, p, end - p);
11829	p += _show_fw_dm_msg(rtwdev, p, end - p);
11830
11831	if (ver->fcxmreg == 1)
11832		p += _show_mreg_v1(rtwdev, p, end - p);
11833	else if (ver->fcxmreg == 2)
11834		p += _show_mreg_v2(rtwdev, p, end - p);
11835	else if (ver->fcxmreg == 7)
11836		p += _show_mreg_v7(rtwdev, p, end - p);
11837
11838	p += _show_gpio_dbg(rtwdev, p, end - p);
11839
11840	if (ver->fcxbtcrpt == 1)
11841		p += _show_summary_v1(rtwdev, p, end - p);
11842	else if (ver->fcxbtcrpt == 4)
11843		p += _show_summary_v4(rtwdev, p, end - p);
11844	else if (ver->fcxbtcrpt == 5)
11845		p += _show_summary_v5(rtwdev, p, end - p);
11846	else if (ver->fcxbtcrpt == 105)
11847		p += _show_summary_v105(rtwdev, p, end - p);
11848	else if (ver->fcxbtcrpt == 7)
11849		p += _show_summary_v7(rtwdev, p, end - p);
11850	else if (ver->fcxbtcrpt == 8)
11851		p += _show_summary_v8(rtwdev, p, end - p);
11852
11853	return p - buf;
11854}
11855
11856void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev)
11857{
11858	const struct rtw89_chip_info *chip = rtwdev->chip;
11859	struct rtw89_btc *btc = &rtwdev->btc;
11860	const struct rtw89_btc_ver *btc_ver_def;
11861	const struct rtw89_fw_suit *fw_suit;
11862	u32 suit_ver_code;
11863	int i;
11864
11865	fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL);
11866	suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit);
11867
11868	for (i = 0; i < ARRAY_SIZE(rtw89_btc_ver_defs); i++) {
11869		btc_ver_def = &rtw89_btc_ver_defs[i];
11870
11871		if (chip->chip_id != btc_ver_def->chip_id)
11872			continue;
11873
11874		if (suit_ver_code >= btc_ver_def->fw_ver_code) {
11875			btc->ver = btc_ver_def;
11876			goto out;
11877		}
11878	}
11879
11880	btc->ver = &rtw89_btc_ver_defs[RTW89_DEFAULT_BTC_VER_IDX];
11881
11882out:
11883	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] use version def[%d] = 0x%08x\n",
11884		    (int)(btc->ver - rtw89_btc_ver_defs), btc->ver->fw_ver_code);
11885}
11886
11887void rtw89_btc_ntfy_preserve_bt_time(struct rtw89_dev *rtwdev, u32 ms)
11888{
11889	struct rtw89_btc_bt_link_info *bt_linfo = &rtwdev->btc.cx.bt.link_info;
11890	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
11891
11892	if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
11893		return;
11894
11895	if (!a2dp.exist)
11896		return;
11897
11898	fsleep(ms * 1000);
11899}
11900EXPORT_SYMBOL(rtw89_btc_ntfy_preserve_bt_time);
11901
11902void rtw89_btc_ntfy_conn_rfk(struct rtw89_dev *rtwdev, bool state)
11903{
11904	rtwdev->btc.cx.wl.rfk_info.con_rfk = state;
11905}
11906EXPORT_SYMBOL(rtw89_btc_ntfy_conn_rfk);
~/ Read-only file preview.