1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2026 Realtek Corporation 3 */ 4 5 #include "chan.h" 6 #include "debug.h" 7 #include "phy.h" 8 #include "reg.h" 9 #include "rtw8922d.h" 10 #include "rtw8922d_rfk.h" 11 12 static const struct rtw89_reg5_def rtw8922d_nctl_post_defs[] = { 13 RTW89_DECL_RFK_WM(0x20c7c, 0x00e00000, 0x1), 14 }; 15 16 RTW89_DECLARE_RFK_TBL(rtw8922d_nctl_post_defs); 17 18 static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en, 19 enum rtw89_rf_path path, u8 phy_idx) 20 { 21 static const u32 tssi_trk_man[2] = {R_TSSI_EN_P0_BE4, 22 R_TSSI_EN_P0_BE4 + 0x100}; 23 24 if (en) 25 rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path], 26 B_TSSI_CONT_EN, 0, phy_idx); 27 else 28 rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path], 29 B_TSSI_CONT_EN, 1, phy_idx); 30 } 31 32 void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) 33 { 34 if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) { 35 if (phy_idx == RTW89_PHY_0) 36 rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx); 37 else 38 rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx); 39 } else { 40 rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx); 41 rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx); 42 } 43 } 44 45 static 46 void rtw8922d_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, 47 const struct rtw89_chan *chan) 48 { 49 u8 synpath; 50 u32 rf18; 51 52 synpath = rtw89_phy_get_syn_sel(rtwdev, phy); 53 rf18 = rtw89_chip_chan_to_rf18_val(rtwdev, chan); 54 55 rtw89_write_rf(rtwdev, synpath, RR_RSV1, RFREG_MASK, 0x0); 56 rtw89_write_rf(rtwdev, synpath, RR_MOD, RFREG_MASK, 0x30000); 57 rtw89_write_rf(rtwdev, synpath, RR_CFGCH, RFREG_MASK, rf18); 58 fsleep(400); 59 rtw89_write_rf(rtwdev, synpath, RR_RSV1, RFREG_MASK, 0x1); 60 rtw89_write_rf(rtwdev, synpath, RR_CFGCH_V1, RFREG_MASK, rf18); 61 } 62 63 void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev, 64 const struct rtw89_chan *chan, 65 enum rtw89_phy_idx phy_idx) 66 { 67 rtw8922d_ctl_band_ch_bw(rtwdev, phy_idx, chan); 68 } 69 70 enum _rf_syn_pow { 71 RF_SYN_ON_OFF, 72 RF_SYN_OFF_ON, 73 RF_SYN_ALLON, 74 RF_SYN_ALLOFF, 75 }; 76 77 static void rtw8922d_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) 78 { 79 rtw89_debug(rtwdev, RTW89_DBG_RFK, "SYN config=%d\n", syn); 80 81 if (syn == RF_SYN_ALLON) { 82 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0); 83 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0); 84 rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0); 85 rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0); 86 rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf); 87 rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf); 88 rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1); 89 rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1); 90 } else if (syn == RF_SYN_ON_OFF) { 91 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0); 92 rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0); 93 rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf); 94 rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0); 95 rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1); 96 } else if (syn == RF_SYN_OFF_ON) { 97 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0); 98 rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0); 99 rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0); 100 rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf); 101 rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1); 102 } else if (syn == RF_SYN_ALLOFF) { 103 rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0); 104 rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0); 105 } 106 } 107 108 static void rtw8922d_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) 109 { 110 bool mlo_linking = false; 111 112 if (idx > 2) { 113 rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)", idx); 114 return; 115 } 116 117 if (mlo_linking) { 118 if (kpath & RF_A) { 119 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_SW_SEL, 0x0); 120 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_SW_SEL, 0x0); 121 } 122 123 if (kpath & RF_B) { 124 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_SW_SEL, 0x0); 125 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_SW_SEL, 0x0); 126 } 127 128 return; 129 } 130 131 if (kpath & RF_A) { 132 rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_RST, 0x1); 133 rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX0, idx); 134 rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX1, idx); 135 136 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_TXG_SEL, 0x4 | idx); 137 rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx); 138 139 rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL0, idx & BIT(0)); 140 rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1); 141 } 142 143 if (kpath & RF_B) { 144 rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_RST, 0x1); 145 rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX0, idx); 146 rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX1, idx); 147 148 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_TXG_SEL, 0x4 | idx); 149 rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx); 150 151 rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL0, idx & BIT(0)); 152 rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1); 153 } 154 } 155 156 static u8 rtw8922d_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, 157 const struct rtw89_chan *chan, u8 path) 158 { 159 struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; 160 struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; 161 u8 tbl_sel; 162 163 for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { 164 struct rtw89_rfk_chan_desc *p = &desc[tbl_sel]; 165 166 p->ch = rfk_mcc->ch[tbl_sel]; 167 168 p->has_band = true; 169 p->band = rfk_mcc->band[tbl_sel]; 170 171 p->has_bw = true; 172 p->bw = rfk_mcc->bw[tbl_sel]; 173 } 174 175 tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); 176 177 rfk_mcc->ch[tbl_sel] = chan->channel; 178 rfk_mcc->band[tbl_sel] = chan->band_type; 179 rfk_mcc->bw[tbl_sel] = chan->band_width; 180 rfk_mcc->rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan); 181 182 /* shared table array, but tbl_sel can be independent by path */ 183 rfk_mcc[path].table_idx = tbl_sel; 184 185 return tbl_sel; 186 } 187 188 static void rtw8922d_chlk_reload(struct rtw89_dev *rtwdev) 189 { 190 const struct rtw89_chan *chan0, *chan1; 191 u8 s0_tbl, s1_tbl; 192 193 switch (rtwdev->mlo_dbcc_mode) { 194 default: 195 case MLO_2_PLUS_0_1RF: 196 chan0 = rtw89_mgnt_chan_get(rtwdev, 0); 197 chan1 = chan0; 198 break; 199 case MLO_0_PLUS_2_1RF: 200 chan1 = rtw89_mgnt_chan_get(rtwdev, 1); 201 chan0 = chan1; 202 break; 203 case MLO_1_PLUS_1_1RF: 204 chan0 = rtw89_mgnt_chan_get(rtwdev, 0); 205 chan1 = rtw89_mgnt_chan_get(rtwdev, 1); 206 break; 207 } 208 209 s0_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan0, 0); 210 s1_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan1, 1); 211 212 rtw8922d_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl); 213 rtw8922d_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl); 214 } 215 216 static enum _rf_syn_pow rtw8922d_get_syn_pow(struct rtw89_dev *rtwdev) 217 { 218 switch (rtwdev->mlo_dbcc_mode) { 219 case MLO_0_PLUS_2_1RF: 220 return RF_SYN_OFF_ON; 221 case MLO_0_PLUS_2_2RF: 222 case MLO_1_PLUS_1_2RF: 223 case MLO_2_PLUS_0_1RF: 224 case MLO_2_PLUS_0_2RF: 225 case MLO_2_PLUS_2_2RF: 226 case MLO_DBCC_NOT_SUPPORT: 227 default: 228 return RF_SYN_ON_OFF; 229 case MLO_1_PLUS_1_1RF: 230 case DBCC_LEGACY: 231 return RF_SYN_ALLON; 232 } 233 } 234 235 void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev) 236 { 237 enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev); 238 239 if (!rtwdev->dbcc_en) 240 goto set_rfk_reload; 241 242 rtw8922d_set_syn01(rtwdev, syn_pow); 243 244 set_rfk_reload: 245 rtw8922d_chlk_reload(rtwdev); 246 } 247 248 static void rtw8922d_x4k_setting(struct rtw89_dev *rtwdev) 249 { 250 u32 val; 251 252 val = rtw89_read_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000); 253 rtw89_write_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000, val); 254 val = rtw89_read_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000); 255 rtw89_write_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000, val); 256 257 rtw89_write_rf(rtwdev, RF_PATH_A, 0xC2, BIT(19), 0x1); 258 rtw89_write_rf(rtwdev, RF_PATH_B, 0xC2, BIT(19), 0x1); 259 } 260 261 void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev) 262 { 263 rtw8922d_x4k_setting(rtwdev); 264 } 265 266 void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) 267 { 268 bool mlo_1_1; 269 270 if (!rtwdev->dbcc_en) 271 return; 272 273 mlo_1_1 = rtw89_is_mlo_1_1(rtwdev); 274 if (mlo_1_1) 275 rtw8922d_set_syn01(rtwdev, RF_SYN_ALLON); 276 else if (phy_idx == RTW89_PHY_0) 277 rtw8922d_set_syn01(rtwdev, RF_SYN_ON_OFF); 278 else 279 rtw8922d_set_syn01(rtwdev, RF_SYN_OFF_ON); 280 281 fsleep(1000); 282 } 283 284 void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) 285 { 286 rtw8922d_rfk_mlo_ctrl(rtwdev); 287 } 288 289 static u8 _get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) 290 { 291 rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); 292 rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0); 293 rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); 294 295 fsleep(200); 296 297 return rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL_V1); 298 } 299 300 static void _lck_keep_thermal(struct rtw89_dev *rtwdev) 301 { 302 struct rtw89_lck_info *lck = &rtwdev->lck; 303 int path; 304 305 for (path = 0; path < rtwdev->chip->rf_path_num; path++) { 306 lck->thermal[path] = _get_thermal(rtwdev, path); 307 rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, 308 "[LCK] path=%d thermal=0x%x", path, lck->thermal[path]); 309 } 310 } 311 312 static void _lck(struct rtw89_dev *rtwdev) 313 { 314 enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev); 315 u8 path_mask = 0; 316 u32 tmp18, tmp5; 317 int path; 318 319 rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "[LCK] DO LCK\n"); 320 321 if (syn_pow == RF_SYN_ALLON) 322 path_mask = BIT(RF_PATH_A) | BIT(RF_PATH_B); 323 else if (syn_pow == RF_SYN_ON_OFF) 324 path_mask = BIT(RF_PATH_A); 325 else if (syn_pow == RF_SYN_OFF_ON) 326 path_mask = BIT(RF_PATH_B); 327 else 328 return; 329 330 for (path = 0; path < rtwdev->chip->rf_path_num; path++) { 331 if (!(path_mask & BIT(path))) 332 continue; 333 334 tmp18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, MASKDWORD); 335 tmp5 = rtw89_read_rf(rtwdev, path, RR_RSV1, MASKDWORD); 336 337 rtw89_write_rf(rtwdev, path, RR_MOD, MASKDWORD, 0x10000); 338 rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, 0x0); 339 rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); 340 rtw89_write_rf(rtwdev, path, RR_CFGCH, MASKDWORD, tmp18); 341 rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0); 342 343 fsleep(400); 344 345 rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, tmp5); 346 } 347 348 _lck_keep_thermal(rtwdev); 349 } 350 351 #define RTW8922D_LCK_TH 16 352 void rtw8922d_lck_track(struct rtw89_dev *rtwdev) 353 { 354 struct rtw89_lck_info *lck = &rtwdev->lck; 355 u8 cur_thermal; 356 int delta; 357 int path; 358 359 for (path = 0; path < rtwdev->chip->rf_path_num; path++) { 360 cur_thermal = _get_thermal(rtwdev, path); 361 delta = abs((int)cur_thermal - lck->thermal[path]); 362 363 rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, 364 "[LCK] path=%d current thermal=0x%x delta=0x%x\n", 365 path, cur_thermal, delta); 366 367 if (delta >= RTW8922D_LCK_TH) { 368 _lck(rtwdev); 369 return; 370 } 371 } 372 } 373