1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2019-2022  Realtek Corporation
3  */
4 
5 #include "coex.h"
6 #include "fw.h"
7 #include "mac.h"
8 #include "phy.h"
9 #include "reg.h"
10 #include "rtw8852b.h"
11 #include "rtw8852b_table.h"
12 #include "txrx.h"
13 
14 static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = {
15 	[RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6,
16 			   &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6,
17 			   &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18,
18 			   &rtw89_mac_size.ple_qt58},
19 	[RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9,
20 			    &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4,
21 			    &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13,
22 			    &rtw89_mac_size.ple_qt13},
23 	[RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL,
24 			       NULL},
25 };
26 
27 static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse,
28 				    struct rtw8852b_efuse *map)
29 {
30 	ether_addr_copy(efuse->addr, map->e.mac_addr);
31 	efuse->rfe_type = map->rfe_type;
32 	efuse->xtal_cap = map->xtal_k;
33 }
34 
35 static void rtw8852b_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
36 					struct rtw8852b_efuse *map)
37 {
38 	struct rtw89_tssi_info *tssi = &rtwdev->tssi;
39 	struct rtw8852b_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi};
40 	u8 i, j;
41 
42 	tssi->thermal[RF_PATH_A] = map->path_a_therm;
43 	tssi->thermal[RF_PATH_B] = map->path_b_therm;
44 
45 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
46 		memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi,
47 		       sizeof(ofst[i]->cck_tssi));
48 
49 		for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++)
50 			rtw89_debug(rtwdev, RTW89_DBG_TSSI,
51 				    "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n",
52 				    i, j, tssi->tssi_cck[i][j]);
53 
54 		memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi,
55 		       sizeof(ofst[i]->bw40_tssi));
56 		memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM,
57 		       ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g));
58 
59 		for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++)
60 			rtw89_debug(rtwdev, RTW89_DBG_TSSI,
61 				    "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n",
62 				    i, j, tssi->tssi_mcs[i][j]);
63 	}
64 }
65 
66 static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low)
67 {
68 	if (high)
69 		*high = sign_extend32(FIELD_GET(GENMASK(7,  4), data), 3);
70 	if (low)
71 		*low = sign_extend32(FIELD_GET(GENMASK(3,  0), data), 3);
72 
73 	return data != 0xff;
74 }
75 
76 static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
77 					       struct rtw8852b_efuse *map)
78 {
79 	struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
80 	bool valid = false;
81 
82 	valid |= _decode_efuse_gain(map->rx_gain_2g_cck,
83 				    &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK],
84 				    &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK]);
85 	valid |= _decode_efuse_gain(map->rx_gain_2g_ofdm,
86 				    &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM],
87 				    &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM]);
88 	valid |= _decode_efuse_gain(map->rx_gain_5g_low,
89 				    &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW],
90 				    &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW]);
91 	valid |= _decode_efuse_gain(map->rx_gain_5g_mid,
92 				    &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID],
93 				    &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID]);
94 	valid |= _decode_efuse_gain(map->rx_gain_5g_high,
95 				    &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH],
96 				    &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]);
97 
98 	gain->offset_valid = valid;
99 }
100 
101 static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map)
102 {
103 	struct rtw89_efuse *efuse = &rtwdev->efuse;
104 	struct rtw8852b_efuse *map;
105 
106 	map = (struct rtw8852b_efuse *)log_map;
107 
108 	efuse->country_code[0] = map->country_code[0];
109 	efuse->country_code[1] = map->country_code[1];
110 	rtw8852b_efuse_parsing_tssi(rtwdev, map);
111 	rtw8852b_efuse_parsing_gain_offset(rtwdev, map);
112 
113 	switch (rtwdev->hci.type) {
114 	case RTW89_HCI_TYPE_PCIE:
115 		rtw8852be_efuse_parsing(efuse, map);
116 		break;
117 	default:
118 		return -EOPNOTSUPP;
119 	}
120 
121 	rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type);
122 
123 	return 0;
124 }
125 
126 static void rtw8852b_phycap_parsing_power_cal(struct rtw89_dev *rtwdev, u8 *phycap_map)
127 {
128 #define PWR_K_CHK_OFFSET 0x5E9
129 #define PWR_K_CHK_VALUE 0xAA
130 	u32 offset = PWR_K_CHK_OFFSET - rtwdev->chip->phycap_addr;
131 
132 	if (phycap_map[offset] == PWR_K_CHK_VALUE)
133 		rtwdev->efuse.power_k_valid = true;
134 }
135 
136 static void rtw8852b_phycap_parsing_tssi(struct rtw89_dev *rtwdev, u8 *phycap_map)
137 {
138 	struct rtw89_tssi_info *tssi = &rtwdev->tssi;
139 	static const u32 tssi_trim_addr[RF_PATH_NUM_8852B] = {0x5D6, 0x5AB};
140 	u32 addr = rtwdev->chip->phycap_addr;
141 	bool pg = false;
142 	u32 ofst;
143 	u8 i, j;
144 
145 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
146 		for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) {
147 			/* addrs are in decreasing order */
148 			ofst = tssi_trim_addr[i] - addr - j;
149 			tssi->tssi_trim[i][j] = phycap_map[ofst];
150 
151 			if (phycap_map[ofst] != 0xff)
152 				pg = true;
153 		}
154 	}
155 
156 	if (!pg) {
157 		memset(tssi->tssi_trim, 0, sizeof(tssi->tssi_trim));
158 		rtw89_debug(rtwdev, RTW89_DBG_TSSI,
159 			    "[TSSI][TRIM] no PG, set all trim info to 0\n");
160 	}
161 
162 	for (i = 0; i < RF_PATH_NUM_8852B; i++)
163 		for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++)
164 			rtw89_debug(rtwdev, RTW89_DBG_TSSI,
165 				    "[TSSI] path=%d idx=%d trim=0x%x addr=0x%x\n",
166 				    i, j, tssi->tssi_trim[i][j],
167 				    tssi_trim_addr[i] - j);
168 }
169 
170 static void rtw8852b_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev,
171 						 u8 *phycap_map)
172 {
173 	struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
174 	static const u32 thm_trim_addr[RF_PATH_NUM_8852B] = {0x5DF, 0x5DC};
175 	u32 addr = rtwdev->chip->phycap_addr;
176 	u8 i;
177 
178 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
179 		info->thermal_trim[i] = phycap_map[thm_trim_addr[i] - addr];
180 
181 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
182 			    "[THERMAL][TRIM] path=%d thermal_trim=0x%x\n",
183 			    i, info->thermal_trim[i]);
184 
185 		if (info->thermal_trim[i] != 0xff)
186 			info->pg_thermal_trim = true;
187 	}
188 }
189 
190 static void rtw8852b_thermal_trim(struct rtw89_dev *rtwdev)
191 {
192 #define __thm_setting(raw)				\
193 ({							\
194 	u8 __v = (raw);					\
195 	((__v & 0x1) << 3) | ((__v & 0x1f) >> 1);	\
196 })
197 	struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
198 	u8 i, val;
199 
200 	if (!info->pg_thermal_trim) {
201 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
202 			    "[THERMAL][TRIM] no PG, do nothing\n");
203 
204 		return;
205 	}
206 
207 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
208 		val = __thm_setting(info->thermal_trim[i]);
209 		rtw89_write_rf(rtwdev, i, RR_TM2, RR_TM2_OFF, val);
210 
211 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
212 			    "[THERMAL][TRIM] path=%d thermal_setting=0x%x\n",
213 			    i, val);
214 	}
215 #undef __thm_setting
216 }
217 
218 static void rtw8852b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev,
219 						 u8 *phycap_map)
220 {
221 	struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
222 	static const u32 pabias_trim_addr[RF_PATH_NUM_8852B] = {0x5DE, 0x5DB};
223 	u32 addr = rtwdev->chip->phycap_addr;
224 	u8 i;
225 
226 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
227 		info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr];
228 
229 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
230 			    "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n",
231 			    i, info->pa_bias_trim[i]);
232 
233 		if (info->pa_bias_trim[i] != 0xff)
234 			info->pg_pa_bias_trim = true;
235 	}
236 }
237 
238 static void rtw8852b_pa_bias_trim(struct rtw89_dev *rtwdev)
239 {
240 	struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
241 	u8 pabias_2g, pabias_5g;
242 	u8 i;
243 
244 	if (!info->pg_pa_bias_trim) {
245 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
246 			    "[PA_BIAS][TRIM] no PG, do nothing\n");
247 
248 		return;
249 	}
250 
251 	for (i = 0; i < RF_PATH_NUM_8852B; i++) {
252 		pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]);
253 		pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]);
254 
255 		rtw89_debug(rtwdev, RTW89_DBG_RFK,
256 			    "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n",
257 			    i, pabias_2g, pabias_5g);
258 
259 		rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG, pabias_2g);
260 		rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA, pabias_5g);
261 	}
262 }
263 
264 static void rtw8852b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map)
265 {
266 	static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = {
267 		{0x5BB, 0x5BA, 0, 0x5B9, 0x5B8},
268 		{0x590, 0x58F, 0, 0x58E, 0x58D},
269 	};
270 	struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
271 	u32 phycap_addr = rtwdev->chip->phycap_addr;
272 	bool valid = false;
273 	int path, i;
274 	u8 data;
275 
276 	for (path = 0; path < 2; path++)
277 		for (i = 0; i < RTW89_SUBBAND_2GHZ_5GHZ_NR; i++) {
278 			if (comp_addrs[path][i] == 0)
279 				continue;
280 
281 			data = phycap_map[comp_addrs[path][i] - phycap_addr];
282 			valid |= _decode_efuse_gain(data, NULL,
283 						    &gain->comp[path][i]);
284 		}
285 
286 	gain->comp_valid = valid;
287 }
288 
289 static int rtw8852b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map)
290 {
291 	rtw8852b_phycap_parsing_power_cal(rtwdev, phycap_map);
292 	rtw8852b_phycap_parsing_tssi(rtwdev, phycap_map);
293 	rtw8852b_phycap_parsing_thermal_trim(rtwdev, phycap_map);
294 	rtw8852b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map);
295 	rtw8852b_phycap_parsing_gain_comp(rtwdev, phycap_map);
296 
297 	return 0;
298 }
299 
300 static void rtw8852b_power_trim(struct rtw89_dev *rtwdev)
301 {
302 	rtw8852b_thermal_trim(rtwdev);
303 	rtw8852b_pa_bias_trim(rtwdev);
304 }
305 
306 static u32 rtw8852b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev,
307 				     enum rtw89_phy_idx phy_idx, s16 ref)
308 {
309 	const u16 tssi_16dbm_cw = 0x12c;
310 	const u8 base_cw_0db = 0x27;
311 	const s8 ofst_int = 0;
312 	s16 pwr_s10_3;
313 	s16 rf_pwr_cw;
314 	u16 bb_pwr_cw;
315 	u32 pwr_cw;
316 	u32 tssi_ofst_cw;
317 
318 	pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3);
319 	bb_pwr_cw = FIELD_GET(GENMASK(2, 0), pwr_s10_3);
320 	rf_pwr_cw = FIELD_GET(GENMASK(8, 3), pwr_s10_3);
321 	rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63);
322 	pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw;
323 
324 	tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3));
325 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
326 		    "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n",
327 		    tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw);
328 
329 	return FIELD_PREP(B_DPD_TSSI_CW, tssi_ofst_cw) |
330 	       FIELD_PREP(B_DPD_PWR_CW, pwr_cw) |
331 	       FIELD_PREP(B_DPD_REF, ref);
332 }
333 
334 static void rtw8852b_set_txpwr_ref(struct rtw89_dev *rtwdev,
335 				   enum rtw89_phy_idx phy_idx)
336 {
337 	static const u32 addr[RF_PATH_NUM_8852B] = {0x5800, 0x7800};
338 	const u32 mask = B_DPD_TSSI_CW | B_DPD_PWR_CW | B_DPD_REF;
339 	const u8 ofst_ofdm = 0x4;
340 	const u8 ofst_cck = 0x8;
341 	const s16 ref_ofdm = 0;
342 	const s16 ref_cck = 0;
343 	u32 val;
344 	u8 i;
345 
346 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n");
347 
348 	rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL,
349 				     B_AX_PWR_REF, 0x0);
350 
351 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n");
352 	val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm);
353 
354 	for (i = 0; i < RF_PATH_NUM_8852B; i++)
355 		rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val,
356 				      phy_idx);
357 
358 	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n");
359 	val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck);
360 
361 	for (i = 0; i < RF_PATH_NUM_8852B; i++)
362 		rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val,
363 				      phy_idx);
364 }
365 
366 static void rtw8852b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev,
367 					  u8 tx_shape_idx,
368 					  enum rtw89_phy_idx phy_idx)
369 {
370 #define __DFIR_CFG_ADDR(i) (R_TXFIR0 + ((i) << 2))
371 #define __DFIR_CFG_MASK 0xffffffff
372 #define __DFIR_CFG_NR 8
373 #define __DECL_DFIR_PARAM(_name, _val...) \
374 	static const u32 param_ ## _name[] = {_val}; \
375 	static_assert(ARRAY_SIZE(param_ ## _name) == __DFIR_CFG_NR)
376 
377 	__DECL_DFIR_PARAM(flat,
378 			  0x023D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053,
379 			  0x00F86F9A, 0x06FAEF92, 0x00FE5FCC, 0x00FFDFF5);
380 	__DECL_DFIR_PARAM(sharp,
381 			  0x023D83FF, 0x002C636A, 0x0013F204, 0x00008090,
382 			  0x00F87FB0, 0x06F99F83, 0x00FDBFBA, 0x00003FF5);
383 	__DECL_DFIR_PARAM(sharp_14,
384 			  0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E,
385 			  0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A);
386 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
387 	u8 ch = chan->channel;
388 	const u32 *param;
389 	u32 addr;
390 	int i;
391 
392 	if (ch > 14) {
393 		rtw89_warn(rtwdev,
394 			   "set tx shape dfir by unknown ch: %d on 2G\n", ch);
395 		return;
396 	}
397 
398 	if (ch == 14)
399 		param = param_sharp_14;
400 	else
401 		param = tx_shape_idx == 0 ? param_flat : param_sharp;
402 
403 	for (i = 0; i < __DFIR_CFG_NR; i++) {
404 		addr = __DFIR_CFG_ADDR(i);
405 		rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
406 			    "set tx shape dfir: 0x%x: 0x%x\n", addr, param[i]);
407 		rtw89_phy_write32_idx(rtwdev, addr, __DFIR_CFG_MASK, param[i],
408 				      phy_idx);
409 	}
410 
411 #undef __DECL_DFIR_PARAM
412 #undef __DFIR_CFG_NR
413 #undef __DFIR_CFG_MASK
414 #undef __DECL_CFG_ADDR
415 }
416 
417 static void rtw8852b_set_tx_shape(struct rtw89_dev *rtwdev,
418 				  const struct rtw89_chan *chan,
419 				  enum rtw89_phy_idx phy_idx)
420 {
421 	u8 band = chan->band_type;
422 	u8 regd = rtw89_regd_get(rtwdev, band);
423 	u8 tx_shape_cck = rtw89_8852b_tx_shape[band][RTW89_RS_CCK][regd];
424 	u8 tx_shape_ofdm = rtw89_8852b_tx_shape[band][RTW89_RS_OFDM][regd];
425 
426 	if (band == RTW89_BAND_2G)
427 		rtw8852b_bb_set_tx_shape_dfir(rtwdev, tx_shape_cck, phy_idx);
428 
429 	rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG,
430 			       tx_shape_ofdm);
431 }
432 
433 static void rtw8852b_set_txpwr(struct rtw89_dev *rtwdev,
434 			       const struct rtw89_chan *chan,
435 			       enum rtw89_phy_idx phy_idx)
436 {
437 	rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx);
438 	rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx);
439 	rtw8852b_set_tx_shape(rtwdev, chan, phy_idx);
440 	rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx);
441 	rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
442 }
443 
444 static void rtw8852b_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
445 				    enum rtw89_phy_idx phy_idx)
446 {
447 	rtw8852b_set_txpwr_ref(rtwdev, phy_idx);
448 }
449 
450 static
451 void rtw8852b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
452 				     s8 pw_ofst, enum rtw89_mac_idx mac_idx)
453 {
454 	u32 reg;
455 
456 	if (pw_ofst < -16 || pw_ofst > 15) {
457 		rtw89_warn(rtwdev, "[ULTB] Err pwr_offset=%d\n", pw_ofst);
458 		return;
459 	}
460 
461 	reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx);
462 	rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN);
463 
464 	reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx);
465 	rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst);
466 
467 	pw_ofst = max_t(s8, pw_ofst - 3, -16);
468 	reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx);
469 	rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst);
470 }
471 
472 static int
473 rtw8852b_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
474 {
475 	int ret;
476 
477 	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333);
478 	if (ret)
479 		return ret;
480 
481 	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000);
482 	if (ret)
483 		return ret;
484 
485 	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff);
486 	if (ret)
487 		return ret;
488 
489 	rtw8852b_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ?
490 						   RTW89_MAC_1 : RTW89_MAC_0);
491 
492 	return 0;
493 }
494 
495 static int rtw8852b_mac_enable_bb_rf(struct rtw89_dev *rtwdev)
496 {
497 	int ret;
498 
499 	rtw89_write8_set(rtwdev, R_AX_SYS_FUNC_EN,
500 			 B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN);
501 	rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x1);
502 	rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG);
503 	rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG);
504 	rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG);
505 
506 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC7,
507 				      FULL_BIT_MASK);
508 	if (ret)
509 		return ret;
510 
511 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC7,
512 				      FULL_BIT_MASK);
513 	if (ret)
514 		return ret;
515 
516 	rtw89_write8(rtwdev, R_AX_PHYREG_SET, PHYREG_SET_XYN_CYCLE);
517 
518 	return 0;
519 }
520 
521 static int rtw8852b_mac_disable_bb_rf(struct rtw89_dev *rtwdev)
522 {
523 	u8 wl_rfc_s0;
524 	u8 wl_rfc_s1;
525 	int ret;
526 
527 	rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN,
528 			 B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN);
529 
530 	ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, &wl_rfc_s0);
531 	if (ret)
532 		return ret;
533 	wl_rfc_s0 &= ~XTAL_SI_RF00S_EN;
534 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, wl_rfc_s0,
535 				      FULL_BIT_MASK);
536 	if (ret)
537 		return ret;
538 
539 	ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, &wl_rfc_s1);
540 	if (ret)
541 		return ret;
542 	wl_rfc_s1 &= ~XTAL_SI_RF10S_EN;
543 	ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, wl_rfc_s1,
544 				      FULL_BIT_MASK);
545 	return ret;
546 }
547 
548 static const struct rtw89_chip_ops rtw8852b_chip_ops = {
549 	.enable_bb_rf		= rtw8852b_mac_enable_bb_rf,
550 	.disable_bb_rf		= rtw8852b_mac_disable_bb_rf,
551 	.read_efuse		= rtw8852b_read_efuse,
552 	.read_phycap		= rtw8852b_read_phycap,
553 	.power_trim		= rtw8852b_power_trim,
554 	.set_txpwr		= rtw8852b_set_txpwr,
555 	.set_txpwr_ctrl		= rtw8852b_set_txpwr_ctrl,
556 	.init_txpwr_unit	= rtw8852b_init_txpwr_unit,
557 };
558 
559 const struct rtw89_chip_info rtw8852b_chip_info = {
560 	.chip_id		= RTL8852B,
561 	.ops			= &rtw8852b_chip_ops,
562 	.fifo_size		= 196608,
563 	.dle_scc_rsvd_size	= 98304,
564 	.dle_mem		= rtw8852b_dle_mem_pcie,
565 	.sec_ctrl_efuse_size	= 4,
566 	.physical_efuse_size	= 1216,
567 	.logical_efuse_size	= 2048,
568 	.limit_efuse_size	= 1280,
569 	.dav_phy_efuse_size	= 96,
570 	.dav_log_efuse_size	= 16,
571 	.phycap_addr		= 0x580,
572 	.phycap_size		= 128,
573 	.dma_ch_mask		= BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
574 				  BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
575 				  BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
576 };
577 EXPORT_SYMBOL(rtw8852b_chip_info);
578 
579 MODULE_FIRMWARE("rtw89/rtw8852b_fw.bin");
580 MODULE_AUTHOR("Realtek Corporation");
581 MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852B driver");
582 MODULE_LICENSE("Dual BSD/GPL");
583