1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
2 | /* Copyright(c) 2023 Realtek Corporation |
3 | */ |
4 | |
5 | #include "chan.h" |
6 | #include "debug.h" |
7 | #include "mac.h" |
8 | #include "phy.h" |
9 | #include "reg.h" |
10 | #include "rtw8922a.h" |
11 | #include "rtw8922a_rfk.h" |
12 | |
13 | static void rtw8922a_tssi_cont_en(struct rtw89_dev *rtwdev, bool en, |
14 | enum rtw89_rf_path path) |
15 | { |
16 | static const u32 tssi_trk_man[2] = {R_TSSI_PWR_P0, R_TSSI_PWR_P1}; |
17 | |
18 | if (en) |
19 | rtw89_phy_write32_mask(rtwdev, addr: tssi_trk_man[path], B_TSSI_CONT_EN, data: 0); |
20 | else |
21 | rtw89_phy_write32_mask(rtwdev, addr: tssi_trk_man[path], B_TSSI_CONT_EN, data: 1); |
22 | } |
23 | |
24 | void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) |
25 | { |
26 | if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) { |
27 | if (phy_idx == RTW89_PHY_0) |
28 | rtw8922a_tssi_cont_en(rtwdev, en, path: RF_PATH_A); |
29 | else |
30 | rtw8922a_tssi_cont_en(rtwdev, en, path: RF_PATH_B); |
31 | } else { |
32 | rtw8922a_tssi_cont_en(rtwdev, en, path: RF_PATH_A); |
33 | rtw8922a_tssi_cont_en(rtwdev, en, path: RF_PATH_B); |
34 | } |
35 | } |
36 | |
37 | static |
38 | void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, |
39 | u8 central_ch, enum rtw89_band band, |
40 | enum rtw89_bandwidth bw) |
41 | { |
42 | const u32 rf_addr[2] = {RR_CFGCH, RR_CFGCH_V1}; |
43 | struct rtw89_hal *hal = &rtwdev->hal; |
44 | u32 rf_reg[RF_PATH_NUM_8922A][2]; |
45 | u8 synpath; |
46 | u32 rf18; |
47 | u8 kpath; |
48 | u8 path; |
49 | u8 i; |
50 | |
51 | rf_reg[RF_PATH_A][0] = rtw89_read_rf(rtwdev, rf_path: RF_PATH_A, addr: rf_addr[0], RFREG_MASK); |
52 | rf_reg[RF_PATH_A][1] = rtw89_read_rf(rtwdev, rf_path: RF_PATH_A, addr: rf_addr[1], RFREG_MASK); |
53 | rf_reg[RF_PATH_B][0] = rtw89_read_rf(rtwdev, rf_path: RF_PATH_B, addr: rf_addr[0], RFREG_MASK); |
54 | rf_reg[RF_PATH_B][1] = rtw89_read_rf(rtwdev, rf_path: RF_PATH_B, addr: rf_addr[1], RFREG_MASK); |
55 | |
56 | kpath = rtw89_phy_get_kpath(rtwdev, phy_idx: phy); |
57 | synpath = rtw89_phy_get_syn_sel(rtwdev, phy_idx: phy); |
58 | |
59 | rf18 = rtw89_read_rf(rtwdev, rf_path: synpath, RR_CFGCH, RFREG_MASK); |
60 | if (rf18 == INV_RF_DATA) { |
61 | rtw89_warn(rtwdev, "[RFK] Invalid RF18 value\n" ); |
62 | return; |
63 | } |
64 | |
65 | for (path = 0; path < RF_PATH_NUM_8922A; path++) { |
66 | if (!(kpath & BIT(path))) |
67 | continue; |
68 | |
69 | for (i = 0; i < 2; i++) { |
70 | if (rf_reg[path][i] == INV_RF_DATA) { |
71 | rtw89_warn(rtwdev, |
72 | "[RFK] Invalid RF_0x18 for Path-%d\n" , path); |
73 | return; |
74 | } |
75 | |
76 | rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW | |
77 | RR_CFGCH_BAND0 | RR_CFGCH_CH); |
78 | rf_reg[path][i] |= u32_encode_bits(v: central_ch, RR_CFGCH_CH); |
79 | |
80 | if (band == RTW89_BAND_2G) |
81 | rtw89_write_rf(rtwdev, rf_path: path, RR_SMD, RR_VCO2, data: 0x0); |
82 | else |
83 | rtw89_write_rf(rtwdev, rf_path: path, RR_SMD, RR_VCO2, data: 0x1); |
84 | |
85 | switch (band) { |
86 | case RTW89_BAND_2G: |
87 | default: |
88 | break; |
89 | case RTW89_BAND_5G: |
90 | rf_reg[path][i] |= |
91 | u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | |
92 | u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); |
93 | break; |
94 | case RTW89_BAND_6G: |
95 | rf_reg[path][i] |= |
96 | u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | |
97 | u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); |
98 | break; |
99 | } |
100 | |
101 | switch (bw) { |
102 | case RTW89_CHANNEL_WIDTH_5: |
103 | case RTW89_CHANNEL_WIDTH_10: |
104 | case RTW89_CHANNEL_WIDTH_20: |
105 | default: |
106 | break; |
107 | case RTW89_CHANNEL_WIDTH_40: |
108 | rf_reg[path][i] |= |
109 | u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); |
110 | break; |
111 | case RTW89_CHANNEL_WIDTH_80: |
112 | rf_reg[path][i] |= |
113 | u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); |
114 | break; |
115 | case RTW89_CHANNEL_WIDTH_160: |
116 | rf_reg[path][i] |= |
117 | u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); |
118 | break; |
119 | case RTW89_CHANNEL_WIDTH_320: |
120 | rf_reg[path][i] |= |
121 | u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); |
122 | break; |
123 | } |
124 | |
125 | rtw89_write_rf(rtwdev, rf_path: path, addr: rf_addr[i], |
126 | RFREG_MASK, data: rf_reg[path][i]); |
127 | fsleep(usecs: 100); |
128 | } |
129 | } |
130 | |
131 | if (hal->cv != CHIP_CAV) |
132 | return; |
133 | |
134 | if (band == RTW89_BAND_2G) { |
135 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWE, RFREG_MASK, data: 0x80000); |
136 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWA, RFREG_MASK, data: 0x00003); |
137 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWD1, RFREG_MASK, data: 0x0c990); |
138 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWD0, RFREG_MASK, data: 0xebe38); |
139 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWE, RFREG_MASK, data: 0x00000); |
140 | } else { |
141 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWE, RFREG_MASK, data: 0x80000); |
142 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWA, RFREG_MASK, data: 0x00003); |
143 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWD1, RFREG_MASK, data: 0x0c190); |
144 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWD0, RFREG_MASK, data: 0xebe38); |
145 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_LUTWE, RFREG_MASK, data: 0x00000); |
146 | } |
147 | } |
148 | |
149 | void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, |
150 | const struct rtw89_chan *chan, |
151 | enum rtw89_phy_idx phy_idx) |
152 | { |
153 | rtw8922a_ctl_band_ch_bw(rtwdev, phy: phy_idx, central_ch: chan->channel, band: chan->band_type, |
154 | bw: chan->band_width); |
155 | } |
156 | |
157 | enum _rf_syn_pow { |
158 | RF_SYN_ON_OFF, |
159 | RF_SYN_OFF_ON, |
160 | RF_SYN_ALLON, |
161 | RF_SYN_ALLOFF, |
162 | }; |
163 | |
164 | static void rtw8922a_set_syn01_cav(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) |
165 | { |
166 | if (syn == RF_SYN_ALLON) { |
167 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x3); |
168 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x2); |
169 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x3); |
170 | |
171 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x3); |
172 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x2); |
173 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x3); |
174 | } else if (syn == RF_SYN_ON_OFF) { |
175 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x3); |
176 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x2); |
177 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x3); |
178 | |
179 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x0); |
180 | } else if (syn == RF_SYN_OFF_ON) { |
181 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x0); |
182 | |
183 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x3); |
184 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x2); |
185 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x3); |
186 | } else if (syn == RF_SYN_ALLOFF) { |
187 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN, data: 0x0); |
188 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN, data: 0x0); |
189 | } |
190 | } |
191 | |
192 | static void rtw8922a_set_syn01_cbv(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) |
193 | { |
194 | if (syn == RF_SYN_ALLON) { |
195 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN_V1, data: 0xf); |
196 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN_V1, data: 0xf); |
197 | } else if (syn == RF_SYN_ON_OFF) { |
198 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN_V1, data: 0xf); |
199 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN_V1, data: 0x0); |
200 | } else if (syn == RF_SYN_OFF_ON) { |
201 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN_V1, data: 0x0); |
202 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN_V1, data: 0xf); |
203 | } else if (syn == RF_SYN_ALLOFF) { |
204 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_POW, RR_POW_SYN_V1, data: 0x0); |
205 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_POW, RR_POW_SYN_V1, data: 0x0); |
206 | } |
207 | } |
208 | |
209 | static void rtw8922a_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) |
210 | { |
211 | struct rtw89_hal *hal = &rtwdev->hal; |
212 | |
213 | rtw89_debug(rtwdev, mask: RTW89_DBG_RFK, fmt: "SYN config=%d\n" , syn); |
214 | |
215 | if (hal->cv == CHIP_CAV) |
216 | rtw8922a_set_syn01_cav(rtwdev, syn); |
217 | else |
218 | rtw8922a_set_syn01_cbv(rtwdev, syn); |
219 | } |
220 | |
221 | static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) |
222 | { |
223 | u32 tmp; |
224 | |
225 | if (idx > 2) { |
226 | rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)" , idx); |
227 | return; |
228 | } |
229 | |
230 | if (kpath & RF_A) { |
231 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_EN, data: 0x1); |
232 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1, data: idx); |
233 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_MDPD_V1, data: idx); |
234 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_A, RR_MODOPT, RR_TXG_SEL, data: 0x4 | idx); |
235 | |
236 | tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, BIT(0)); |
237 | rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, data: tmp); |
238 | tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, BIT(1)); |
239 | rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G5, data: tmp); |
240 | } |
241 | |
242 | if (kpath & RF_B) { |
243 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_EN, data: 0x1); |
244 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1, data: idx); |
245 | rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_MDPD_V1, data: idx); |
246 | rtw89_write_rf(rtwdev, rf_path: RF_PATH_B, RR_MODOPT, RR_TXG_SEL, data: 0x4 | idx); |
247 | |
248 | tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, BIT(0)); |
249 | rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT_C1, B_CFIR_LUT_G3, data: tmp); |
250 | tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, BIT(1)); |
251 | rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT_C1, B_CFIR_LUT_G5, data: tmp); |
252 | } |
253 | } |
254 | |
255 | static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) |
256 | { |
257 | struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; |
258 | enum rtw89_sub_entity_idx sub_entity_idx; |
259 | const struct rtw89_chan *chan; |
260 | enum rtw89_entity_mode mode; |
261 | u8 s0_tbl, s1_tbl; |
262 | u8 tbl_sel; |
263 | |
264 | mode = rtw89_get_entity_mode(rtwdev); |
265 | switch (mode) { |
266 | case RTW89_ENTITY_MODE_MCC_PREPARE: |
267 | sub_entity_idx = RTW89_SUB_ENTITY_1; |
268 | tbl_sel = 1; |
269 | break; |
270 | default: |
271 | sub_entity_idx = RTW89_SUB_ENTITY_0; |
272 | tbl_sel = 0; |
273 | break; |
274 | } |
275 | |
276 | chan = rtw89_chan_get(rtwdev, idx: sub_entity_idx); |
277 | |
278 | rfk_mcc->ch[tbl_sel] = chan->channel; |
279 | rfk_mcc->band[tbl_sel] = chan->band_type; |
280 | rfk_mcc->bw[tbl_sel] = chan->band_width; |
281 | rfk_mcc->table_idx = tbl_sel; |
282 | |
283 | s0_tbl = tbl_sel; |
284 | s1_tbl = tbl_sel; |
285 | |
286 | rtw8922a_chlk_ktbl_sel(rtwdev, kpath: RF_A, idx: s0_tbl); |
287 | rtw8922a_chlk_ktbl_sel(rtwdev, kpath: RF_B, idx: s1_tbl); |
288 | } |
289 | |
290 | static void rtw8922a_rfk_mlo_ctrl(struct rtw89_dev *rtwdev) |
291 | { |
292 | enum _rf_syn_pow syn_pow; |
293 | |
294 | if (!rtwdev->dbcc_en) |
295 | goto set_rfk_reload; |
296 | |
297 | switch (rtwdev->mlo_dbcc_mode) { |
298 | case MLO_0_PLUS_2_1RF: |
299 | syn_pow = RF_SYN_OFF_ON; |
300 | break; |
301 | case MLO_0_PLUS_2_2RF: |
302 | case MLO_1_PLUS_1_2RF: |
303 | case MLO_2_PLUS_0_1RF: |
304 | case MLO_2_PLUS_0_2RF: |
305 | case MLO_2_PLUS_2_2RF: |
306 | case MLO_DBCC_NOT_SUPPORT: |
307 | default: |
308 | syn_pow = RF_SYN_ON_OFF; |
309 | break; |
310 | case MLO_1_PLUS_1_1RF: |
311 | case DBCC_LEGACY: |
312 | syn_pow = RF_SYN_ALLON; |
313 | break; |
314 | } |
315 | |
316 | rtw8922a_set_syn01(rtwdev, syn: syn_pow); |
317 | |
318 | set_rfk_reload: |
319 | rtw8922a_chlk_reload(rtwdev); |
320 | } |
321 | |
322 | static void rtw8922a_rfk_pll_init(struct rtw89_dev *rtwdev) |
323 | { |
324 | int ret; |
325 | u8 tmp; |
326 | |
327 | ret = rtw89_mac_read_xtal_si(rtwdev, offset: XTAL_SI_PLL_1, val: &tmp); |
328 | if (ret) |
329 | return; |
330 | ret = rtw89_mac_write_xtal_si(rtwdev, offset: XTAL_SI_PLL_1, val: tmp | 0xf8, mask: 0xFF); |
331 | if (ret) |
332 | return; |
333 | |
334 | ret = rtw89_mac_read_xtal_si(rtwdev, offset: XTAL_SI_APBT, val: &tmp); |
335 | if (ret) |
336 | return; |
337 | ret = rtw89_mac_write_xtal_si(rtwdev, offset: XTAL_SI_APBT, val: tmp & ~0x60, mask: 0xFF); |
338 | if (ret) |
339 | return; |
340 | |
341 | ret = rtw89_mac_read_xtal_si(rtwdev, offset: XTAL_SI_XTAL_PLL, val: &tmp); |
342 | if (ret) |
343 | return; |
344 | ret = rtw89_mac_write_xtal_si(rtwdev, offset: XTAL_SI_XTAL_PLL, val: tmp | 0x38, mask: 0xFF); |
345 | if (ret) |
346 | return; |
347 | } |
348 | |
349 | void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev) |
350 | { |
351 | if (rtwdev->dbcc_en) |
352 | rtw8922a_rfk_mlo_ctrl(rtwdev); |
353 | |
354 | rtw8922a_rfk_pll_init(rtwdev); |
355 | } |
356 | |
357 | void rtw8922a_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) |
358 | { |
359 | bool mlo_1_1; |
360 | |
361 | if (!rtwdev->dbcc_en) |
362 | return; |
363 | |
364 | mlo_1_1 = rtw89_is_mlo_1_1(rtwdev); |
365 | if (mlo_1_1) |
366 | rtw8922a_set_syn01(rtwdev, syn: RF_SYN_ALLON); |
367 | else if (phy_idx == RTW89_PHY_0) |
368 | rtw8922a_set_syn01(rtwdev, syn: RF_SYN_ON_OFF); |
369 | else |
370 | rtw8922a_set_syn01(rtwdev, syn: RF_SYN_OFF_ON); |
371 | |
372 | fsleep(usecs: 1000); |
373 | } |
374 | |
375 | void rtw8922a_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) |
376 | { |
377 | rtw8922a_rfk_mlo_ctrl(rtwdev); |
378 | } |
379 | |