xref: /linux/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c (revision 9c2f79b4d912dc96bbe5b4dadccd1099d430436d)
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