1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /**
8  * @brief File containing API definitions for the
9  * FMAC IF Layer of the Wi-Fi driver.
10  */
11 
12 #include "host_rpu_umac_if.h"
13 #include "offload_raw_tx/phy_rf_params.h"
14 #include "offload_raw_tx/hal_api.h"
15 #include "offload_raw_tx/fmac_api.h"
16 #include "offload_raw_tx/fmac_cmd.h"
17 #include "offload_raw_tx/fmac_event.h"
18 #include "offload_raw_tx/fmac_structs.h"
19 #include "common/fmac_util.h"
20 #include <stdio.h>
21 
nrf_wifi_fmac_off_raw_tx_fw_init(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_phy_rf_params * rf_params,bool rf_params_valid,int sleep_type,unsigned int phy_calib,enum op_band op_band,bool beamforming,struct nrf_wifi_tx_pwr_ctrl_params * tx_pwr_ctrl,struct nrf_wifi_board_params * board_params,unsigned char * country_code)22 static enum nrf_wifi_status nrf_wifi_fmac_off_raw_tx_fw_init(
23 		struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
24 		struct nrf_wifi_phy_rf_params *rf_params,
25 		bool rf_params_valid,
26 #ifdef NRF_WIFI_LOW_POWER
27 		int sleep_type,
28 #endif /* NRF_WIFI_LOW_POWER */
29 		unsigned int phy_calib,
30 		enum op_band op_band,
31 		bool beamforming,
32 		struct nrf_wifi_tx_pwr_ctrl_params *tx_pwr_ctrl,
33 		struct nrf_wifi_board_params *board_params,
34 		unsigned char *country_code)
35 {
36 	unsigned long start_time_us = 0;
37 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
38 
39 	if (!fmac_dev_ctx) {
40 		nrf_wifi_osal_log_err("%s: Invalid device context",
41 				      __func__);
42 		goto out;
43 	}
44 
45 	status = umac_cmd_off_raw_tx_init(fmac_dev_ctx,
46 					  rf_params,
47 					  rf_params_valid,
48 #ifdef NRF_WIFI_LOW_POWER
49 					  sleep_type,
50 #endif /* NRF_WIFI_LOW_POWER */
51 					  phy_calib,
52 					  op_band,
53 					  beamforming,
54 					  tx_pwr_ctrl,
55 					  board_params,
56 					  country_code);
57 
58 	if (status != NRF_WIFI_STATUS_SUCCESS) {
59 		nrf_wifi_osal_log_err("%s: UMAC init failed",
60 				      __func__);
61 		goto out;
62 	}
63 
64 	start_time_us = nrf_wifi_osal_time_get_curr_us();
65 	while (!fmac_dev_ctx->fw_init_done) {
66 		nrf_wifi_osal_sleep_ms(1);
67 #define MAX_INIT_WAIT (5 * 1000 * 1000)
68 		if (nrf_wifi_osal_time_elapsed_us(start_time_us) >= MAX_INIT_WAIT) {
69 			break;
70 		}
71 	}
72 
73 	if (!fmac_dev_ctx->fw_init_done) {
74 		nrf_wifi_osal_log_err("%s: UMAC init timed out",
75 				      __func__);
76 		status = NRF_WIFI_STATUS_FAIL;
77 		goto out;
78 	}
79 
80 	status = NRF_WIFI_STATUS_SUCCESS;
81 out:
82 	return status;
83 }
84 
85 
nrf_wifi_off_raw_tx_fmac_init(void)86 struct nrf_wifi_fmac_priv *nrf_wifi_off_raw_tx_fmac_init(void)
87 {
88 	struct nrf_wifi_fmac_priv *fpriv = NULL;
89 	struct nrf_wifi_hal_cfg_params hal_cfg_params;
90 
91 	fpriv = nrf_wifi_osal_mem_zalloc(sizeof(*fpriv));
92 	if (!fpriv) {
93 		nrf_wifi_osal_log_err("%s: Unable to allocate fpriv",
94 				      __func__);
95 		goto out;
96 	}
97 
98 	nrf_wifi_osal_mem_set(&hal_cfg_params,
99 			      0,
100 			      sizeof(hal_cfg_params));
101 
102 	hal_cfg_params.max_cmd_size = MAX_NRF_WIFI_UMAC_CMD_SIZE;
103 	hal_cfg_params.max_event_size = MAX_EVENT_POOL_LEN;
104 
105 	fpriv->hpriv = nrf_wifi_hal_init(&hal_cfg_params,
106 					 &nrf_wifi_off_raw_tx_fmac_event_callback,
107 					 NULL);
108 	if (!fpriv->hpriv) {
109 		nrf_wifi_osal_log_err("%s: Unable to do HAL init",
110 				      __func__);
111 		nrf_wifi_osal_mem_free(fpriv);
112 		fpriv = NULL;
113 		goto out;
114 	}
115 
116 	fpriv->op_mode = NRF_WIFI_OP_MODE_OFF_RAW_TX;
117 out:
118 	return fpriv;
119 }
120 
121 
nrf_wifi_off_raw_tx_fmac_dev_add(struct nrf_wifi_fmac_priv * fpriv,void * os_dev_ctx)122 struct nrf_wifi_fmac_dev_ctx *nrf_wifi_off_raw_tx_fmac_dev_add(struct nrf_wifi_fmac_priv *fpriv,
123 							       void *os_dev_ctx)
124 {
125 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
126 	struct nrf_wifi_off_raw_tx_fmac_dev_ctx *off_raw_tx_fmac_dev_ctx;
127 
128 	if (!fpriv || !os_dev_ctx) {
129 		return NULL;
130 	}
131 
132 	if (fpriv->op_mode != NRF_WIFI_OP_MODE_OFF_RAW_TX) {
133 		nrf_wifi_osal_log_err("%s: Invalid op mode",
134 				      __func__);
135 		goto out;
136 	}
137 
138 	fmac_dev_ctx = nrf_wifi_osal_mem_zalloc(sizeof(*fmac_dev_ctx) + sizeof(*off_raw_tx_fmac_dev_ctx));
139 
140 	if (!fmac_dev_ctx) {
141 		nrf_wifi_osal_log_err("%s: Unable to allocate fmac_dev_ctx",
142 				      __func__);
143 		goto out;
144 	}
145 
146 	fmac_dev_ctx->fpriv = fpriv;
147 	fmac_dev_ctx->os_dev_ctx = os_dev_ctx;
148 
149 	fmac_dev_ctx->hal_dev_ctx = nrf_wifi_off_raw_tx_hal_dev_add(fpriv->hpriv,
150 								    fmac_dev_ctx);
151 
152 	if (!fmac_dev_ctx->hal_dev_ctx) {
153 		nrf_wifi_osal_log_err("%s: nrf_wifi_off_raw_tx_hal_dev_add failed",
154 				      __func__);
155 
156 		nrf_wifi_osal_mem_free(fmac_dev_ctx);
157 		fmac_dev_ctx = NULL;
158 		goto out;
159 	}
160 
161 	fmac_dev_ctx->op_mode = NRF_WIFI_OP_MODE_OFF_RAW_TX;
162 out:
163 	return fmac_dev_ctx;
164 }
165 
166 
nrf_wifi_off_raw_tx_fmac_dev_init(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,int sleep_type,unsigned int phy_calib,enum op_band op_band,bool beamforming,struct nrf_wifi_tx_pwr_ctrl_params * tx_pwr_ctrl_params,struct nrf_wifi_tx_pwr_ceil_params * tx_pwr_ceil_params,struct nrf_wifi_board_params * board_params,unsigned char * country_code)167 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_dev_init(
168 		struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
169 #ifdef NRF_WIFI_LOW_POWER
170 		int sleep_type,
171 #endif /* NRF_WIFI_LOW_POWER */
172 		unsigned int phy_calib,
173 		enum op_band op_band,
174 		bool beamforming,
175 		struct nrf_wifi_tx_pwr_ctrl_params *tx_pwr_ctrl_params,
176 		struct nrf_wifi_tx_pwr_ceil_params *tx_pwr_ceil_params,
177 		struct nrf_wifi_board_params *board_params,
178 		unsigned char *country_code)
179 {
180 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
181 	struct nrf_wifi_fmac_otp_info otp_info;
182 	struct nrf_wifi_phy_rf_params phy_rf_params;
183 
184 	if (!fmac_dev_ctx) {
185 		nrf_wifi_osal_log_err("%s: Invalid device context",
186 				      __func__);
187 		goto out;
188 	}
189 
190 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
191 		nrf_wifi_osal_log_err("%s: Invalid op mode",
192 				      __func__);
193 		goto out;
194 	}
195 
196 	status = nrf_wifi_hal_dev_init(fmac_dev_ctx->hal_dev_ctx);
197 	if (status != NRF_WIFI_STATUS_SUCCESS) {
198 		nrf_wifi_osal_log_err("%s: nrf_wifi_hal_dev_init failed",
199 				      __func__);
200 		goto out;
201 	}
202 
203 	fmac_dev_ctx->tx_pwr_ceil_params = nrf_wifi_osal_mem_alloc(sizeof(*tx_pwr_ceil_params));
204 	nrf_wifi_osal_mem_cpy(fmac_dev_ctx->tx_pwr_ceil_params,
205 			      tx_pwr_ceil_params,
206 			      sizeof(*tx_pwr_ceil_params));
207 
208 	nrf_wifi_osal_mem_set(&otp_info,
209 			      0xFF,
210 			      sizeof(otp_info));
211 
212 	status = nrf_wifi_hal_otp_info_get(fmac_dev_ctx->hal_dev_ctx,
213 					   &otp_info.info,
214 					   &otp_info.flags);
215 	if (status != NRF_WIFI_STATUS_SUCCESS) {
216 		nrf_wifi_osal_log_err("%s: Fetching of RPU OTP information failed",
217 				      __func__);
218 		goto out;
219 	}
220 
221 	status = nrf_wifi_off_raw_tx_fmac_rf_params_get(fmac_dev_ctx,
222 							&phy_rf_params);
223 
224 	if (status != NRF_WIFI_STATUS_SUCCESS) {
225 		nrf_wifi_osal_log_err("%s: RF parameters get failed",
226 				     __func__);
227 		goto out;
228 	}
229 
230 	status = nrf_wifi_fmac_off_raw_tx_fw_init(fmac_dev_ctx,
231 						  &phy_rf_params,
232 						  true,
233 #ifdef NRF_WIFI_LOW_POWER
234 						  sleep_type,
235 #endif /* NRF_WIFI_LOW_POWER */
236 						  phy_calib,
237 						  op_band,
238 						  beamforming,
239 						  tx_pwr_ctrl_params,
240 						  board_params,
241 						  country_code);
242 
243 	if (status == NRF_WIFI_STATUS_FAIL) {
244 		nrf_wifi_osal_log_err("%s: nrf_wifi_fmac_off_raw_tx_fw_init failed",
245 				      __func__);
246 		goto out;
247 	}
248 out:
249 	return status;
250 }
251 
252 
nrf_wifi_off_raw_tx_fmac_conf(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_offload_ctrl_params * off_ctrl_params,struct nrf_wifi_offload_tx_ctrl * off_tx_params)253 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_conf(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
254 					           struct nrf_wifi_offload_ctrl_params *off_ctrl_params,
255 						   struct nrf_wifi_offload_tx_ctrl *off_tx_params)
256 {
257 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
258 	struct nrf_wifi_off_raw_tx_fmac_dev_ctx *dev_ctx_off_raw_tx;
259 	struct nrf_wifi_fmac_reg_info reg_domain_info = {0};
260 	unsigned char count = 0;
261 
262 	if (!fmac_dev_ctx) {
263 		nrf_wifi_osal_log_err("%s: Invalid device context",
264 				      __func__);
265 		goto out;
266 	}
267 
268 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
269 		nrf_wifi_osal_log_err("%s: Invalid op mode",
270 				      __func__);
271 		goto out;
272 	}
273 
274 	dev_ctx_off_raw_tx = wifi_dev_priv(fmac_dev_ctx);
275 	dev_ctx_off_raw_tx->off_raw_tx_cmd_done = true;
276 
277 	if (!off_ctrl_params || !off_tx_params) {
278 		nrf_wifi_osal_log_err("%s: Invalid offloaded raw tx params",
279 				      __func__);
280 		goto out;
281 	}
282 
283 	status = umac_cmd_off_raw_tx_conf(fmac_dev_ctx,
284 					  off_ctrl_params,
285 					  off_tx_params);
286 
287 	if (status != NRF_WIFI_STATUS_SUCCESS) {
288 		nrf_wifi_osal_log_err("%s: umac_cmd_offload_raw_tx_conf failed", __func__);
289 		goto out;
290 	}
291 
292 	do {
293 		nrf_wifi_osal_sleep_ms(1);
294 		count++;
295 	} while ((dev_ctx_off_raw_tx->off_raw_tx_cmd_done == true) &&
296 		 (count < NRF_WIFI_FMAC_PARAMS_RECV_TIMEOUT));
297 
298 	if (count == NRF_WIFI_FMAC_PARAMS_RECV_TIMEOUT) {
299 		nrf_wifi_osal_log_err("%s: Timed out",
300 				      __func__);
301 		goto out;
302 	}
303 
304 	if (dev_ctx_off_raw_tx->off_raw_tx_cmd_status != NRF_WIFI_UMAC_CMD_SUCCESS) {
305 		status = nrf_wifi_fmac_get_reg(fmac_dev_ctx, &reg_domain_info);
306 		if (status != NRF_WIFI_STATUS_SUCCESS) {
307 			nrf_wifi_osal_log_err("%s: Failed to get regulatory domain",
308 					      __func__);
309 			goto out;
310 		}
311 
312 		nrf_wifi_osal_log_err("%s: Failed to set configuration, check config against %.2s regulatory domain rules",
313 				      __func__,
314 				      dev_ctx_off_raw_tx->country_code);
315 		status = NRF_WIFI_STATUS_FAIL;
316 		goto out;
317 	}
318 
319 	status = NRF_WIFI_STATUS_SUCCESS;
320 out:
321 	return status;
322 }
323 
nrf_wifi_off_raw_tx_fmac_start(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)324 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_start(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
325 {
326 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
327 
328 	if (!fmac_dev_ctx) {
329 		nrf_wifi_osal_log_err("%s: Invalid device context",
330 				      __func__);
331 		goto out;
332 	}
333 
334 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
335 		nrf_wifi_osal_log_err("%s: Invalid op mode",
336 				      __func__);
337 		goto out;
338 	}
339 
340 	status = umac_cmd_off_raw_tx_ctrl(fmac_dev_ctx, 1);
341 
342 	if (status != NRF_WIFI_STATUS_SUCCESS) {
343 		nrf_wifi_osal_log_err("%s: umac_cmd_off_raw_tx_ctrl failed", __func__);
344 		goto out;
345 	}
346 out:
347 	return status;
348 }
349 
nrf_wifi_off_raw_tx_fmac_stop(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)350 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_stop(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
351 {
352 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
353 
354 	if (!fmac_dev_ctx) {
355 		nrf_wifi_osal_log_err("%s: Invalid device context",
356 				      __func__);
357 		goto out;
358 	}
359 
360 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
361 		nrf_wifi_osal_log_err("%s: Invalid op mode",
362 				      __func__);
363 		goto out;
364 	}
365 
366 	status = umac_cmd_off_raw_tx_ctrl(fmac_dev_ctx, 0);
367 
368 	if (status != NRF_WIFI_STATUS_SUCCESS) {
369 		nrf_wifi_osal_log_err("%s: umac_cmd_offload_raw_tx_ctrl failed", __func__);
370 		goto out;
371 	}
372 out:
373 	return status;
374 }
375 
376 
nrf_wifi_off_raw_tx_fmac_stats_get(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,enum rpu_op_mode op_mode,struct rpu_off_raw_tx_op_stats * stats)377 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_stats_get(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
378 							enum rpu_op_mode op_mode,
379 							struct rpu_off_raw_tx_op_stats *stats)
380 {
381 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
382 	unsigned char count = 0;
383 
384 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
385 		nrf_wifi_osal_log_err("%s: Invalid op mode",
386 				      __func__);
387 		goto out;
388 	}
389 
390 	if (fmac_dev_ctx->stats_req == true) {
391 		nrf_wifi_osal_log_err("%s: Stats request already pending",
392 				      __func__);
393 		goto out;
394 	}
395 
396 	fmac_dev_ctx->stats_req = true;
397 	fmac_dev_ctx->fw_stats = &stats->fw;
398 
399 	status = umac_cmd_off_raw_tx_prog_stats_get(fmac_dev_ctx);
400 
401 	if (status != NRF_WIFI_STATUS_SUCCESS) {
402 		goto out;
403 	}
404 
405 	do {
406 		nrf_wifi_osal_sleep_ms(1);
407 		count++;
408 	} while ((fmac_dev_ctx->stats_req == true) &&
409 		 (count < NRF_WIFI_FMAC_STATS_RECV_TIMEOUT));
410 
411 	if (count == NRF_WIFI_FMAC_STATS_RECV_TIMEOUT) {
412 		nrf_wifi_osal_log_err("%s: Timed out",
413 				      __func__);
414 		goto out;
415 	}
416 
417 	status = NRF_WIFI_STATUS_SUCCESS;
418 out:
419 	return status;
420 }
421 
nrf_wifi_off_raw_tx_fmac_phy_rf_params_init(struct nrf_wifi_phy_rf_params * prf,unsigned int package_info,unsigned char * str)422 static int nrf_wifi_off_raw_tx_fmac_phy_rf_params_init(struct nrf_wifi_phy_rf_params *prf,
423 						       unsigned int package_info,
424 						       unsigned char *str)
425 {
426 	int ret = -1;
427 	unsigned int rf_param_offset = BAND_2G_LW_ED_BKF_DSSS_OFST - NRF_WIFI_RF_PARAMS_CONF_SIZE;
428 	/* Initilaize reserved bytes */
429 	nrf_wifi_osal_mem_set(prf,
430 			      0x0,
431 			      sizeof(prf));
432 	/* Initialize PD adjust values for MCS7. Currently these 4 bytes are not being used */
433 	prf->pd_adjust_val.pd_adjt_lb_chan = PD_ADJUST_VAL;
434 	prf->pd_adjust_val.pd_adjt_hb_low_chan = PD_ADJUST_VAL;
435 	prf->pd_adjust_val.pd_adjt_hb_mid_chan = PD_ADJUST_VAL;
436 	prf->pd_adjust_val.pd_adjt_hb_high_chan = PD_ADJUST_VAL;
437 
438 	/* RX Gain offsets */
439 	prf->rx_gain_offset.rx_gain_lb_chan = CTRL_PWR_OPTIMIZATIONS;
440 	prf->rx_gain_offset.rx_gain_hb_low_chan = RX_GAIN_OFFSET_HB_LOW_CHAN;
441 	prf->rx_gain_offset.rx_gain_hb_mid_chan = RX_GAIN_OFFSET_HB_MID_CHAN;
442 	prf->rx_gain_offset.rx_gain_hb_high_chan = RX_GAIN_OFFSET_HB_HIGH_CHAN;
443 
444 	if (package_info == CSP_PACKAGE_INFO) {
445 		prf->xo_offset.xo_freq_offset = CSP_XO_VAL;
446 
447 		/* Configure systematic offset value */
448 		prf->syst_tx_pwr_offset.syst_off_lb_chan = CSP_SYSTEM_OFFSET_LB;
449 		prf->syst_tx_pwr_offset.syst_off_hb_low_chan = CSP_SYSTEM_OFFSET_HB_CHAN_LOW;
450 		prf->syst_tx_pwr_offset.syst_off_hb_mid_chan = CSP_SYSTEM_OFFSET_HB_CHAN_MID;
451 		prf->syst_tx_pwr_offset.syst_off_hb_high_chan = CSP_SYSTEM_OFFSET_HB_CHAN_HIGH;
452 
453 		/* TX power ceiling */
454 		prf->max_pwr_ceil.max_dsss_pwr = CSP_MAX_TX_PWR_DSSS;
455 		prf->max_pwr_ceil.max_lb_mcs7_pwr = CSP_MAX_TX_PWR_LB_MCS7;
456 		prf->max_pwr_ceil.max_lb_mcs0_pwr = CSP_MAX_TX_PWR_LB_MCS0;
457 		prf->max_pwr_ceil.max_hb_low_chan_mcs7_pwr = CSP_MAX_TX_PWR_HB_LOW_CHAN_MCS7;
458 		prf->max_pwr_ceil.max_hb_mid_chan_mcs7_pwr = CSP_MAX_TX_PWR_HB_MID_CHAN_MCS7;
459 		prf->max_pwr_ceil.max_hb_high_chan_mcs7_pwr = CSP_MAX_TX_PWR_HB_HIGH_CHAN_MCS7;
460 		prf->max_pwr_ceil.max_hb_low_chan_mcs0_pwr = CSP_MAX_TX_PWR_HB_LOW_CHAN_MCS0;
461 		prf->max_pwr_ceil.max_hb_mid_chan_mcs0_pwr = CSP_MAX_TX_PWR_HB_MID_CHAN_MCS0;
462 		prf->max_pwr_ceil.max_hb_high_chan_mcs0_pwr = CSP_MAX_TX_PWR_HB_HIGH_CHAN_MCS0;
463 	} else {
464 		/** If nothing is written to OTP field corresponding to package info byte
465 		 * or if the package info field is corrupted then the default package
466 		 * package is QFN.
467 		 */
468 
469 		/* Initialize XO */
470 		prf->xo_offset.xo_freq_offset = QFN_XO_VAL;
471 
472 		/* Configure systematic offset value */
473 		prf->syst_tx_pwr_offset.syst_off_lb_chan = QFN_SYSTEM_OFFSET_LB;
474 		prf->syst_tx_pwr_offset.syst_off_hb_low_chan = QFN_SYSTEM_OFFSET_HB_CHAN_LOW;
475 		prf->syst_tx_pwr_offset.syst_off_hb_mid_chan = QFN_SYSTEM_OFFSET_HB_CHAN_MID;
476 		prf->syst_tx_pwr_offset.syst_off_hb_high_chan = QFN_SYSTEM_OFFSET_HB_CHAN_HIGH;
477 
478 		/* TX power ceiling */
479 		prf->max_pwr_ceil.max_dsss_pwr = QFN_MAX_TX_PWR_DSSS;
480 		prf->max_pwr_ceil.max_lb_mcs7_pwr = QFN_MAX_TX_PWR_LB_MCS7;
481 		prf->max_pwr_ceil.max_lb_mcs0_pwr = QFN_MAX_TX_PWR_LB_MCS0;
482 		prf->max_pwr_ceil.max_hb_low_chan_mcs7_pwr = QFN_MAX_TX_PWR_HB_LOW_CHAN_MCS7;
483 		prf->max_pwr_ceil.max_hb_mid_chan_mcs7_pwr = QFN_MAX_TX_PWR_HB_MID_CHAN_MCS7;
484 		prf->max_pwr_ceil.max_hb_high_chan_mcs7_pwr = QFN_MAX_TX_PWR_HB_HIGH_CHAN_MCS7;
485 		prf->max_pwr_ceil.max_hb_low_chan_mcs0_pwr = QFN_MAX_TX_PWR_HB_LOW_CHAN_MCS0;
486 		prf->max_pwr_ceil.max_hb_mid_chan_mcs0_pwr = QFN_MAX_TX_PWR_HB_MID_CHAN_MCS0;
487 		prf->max_pwr_ceil.max_hb_high_chan_mcs0_pwr = QFN_MAX_TX_PWR_HB_HIGH_CHAN_MCS0;
488 	}
489 
490 	ret = nrf_wifi_utils_hex_str_to_val((unsigned char *)&prf->phy_params,
491 					    sizeof(prf->phy_params),
492 					    str);
493 
494 	prf->phy_params[rf_param_offset]  = NRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS;
495 	prf->phy_params[rf_param_offset + 1]  = NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT;
496 	prf->phy_params[rf_param_offset + 2]  = NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE;
497 	prf->phy_params[rf_param_offset + 3]  = NRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS;
498 	prf->phy_params[rf_param_offset + 4]  = NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT;
499 	prf->phy_params[rf_param_offset + 5]  = NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE;
500 	prf->phy_params[rf_param_offset + 6]  = NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT;
501 	prf->phy_params[rf_param_offset + 7]  = NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE;
502 	prf->phy_params[rf_param_offset + 8]  = NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT;
503 	prf->phy_params[rf_param_offset + 9]  = NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE;
504 	prf->phy_params[rf_param_offset + 10]  = NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT;
505 	prf->phy_params[rf_param_offset + 11]  = NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE;
506 	prf->phy_params[rf_param_offset + 12]  = NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT;
507 	prf->phy_params[rf_param_offset + 13]  = NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE;
508 	prf->phy_params[rf_param_offset + 14]  = NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT;
509 	prf->phy_params[rf_param_offset + 15]  = NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE;
510 	prf->phy_params[rf_param_offset + 16]  = NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT;
511 	prf->phy_params[rf_param_offset + 17]  = NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE;
512 	prf->phy_params[rf_param_offset + 18]  = NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT;
513 	prf->phy_params[rf_param_offset + 19]  = NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE;
514 	prf->phy_params[rf_param_offset + 20]  = NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT;
515 	prf->phy_params[rf_param_offset + 21]  = NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE;
516 	prf->phy_params[rf_param_offset + 22]  = NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT;
517 	prf->phy_params[rf_param_offset + 23]  = NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE;
518 	prf->phy_params[rf_param_offset + 24]  = NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT;
519 	prf->phy_params[rf_param_offset + 25]  = NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE;
520 	prf->phy_params[rf_param_offset + 26]  = NRF70_ANT_GAIN_2G;
521 	prf->phy_params[rf_param_offset + 27]  = NRF70_ANT_GAIN_5G_BAND1;
522 	prf->phy_params[rf_param_offset + 28]  = NRF70_ANT_GAIN_5G_BAND2;
523 	prf->phy_params[rf_param_offset + 29]  = NRF70_ANT_GAIN_5G_BAND3;
524 	prf->phy_params[rf_param_offset + 30]  = NRF70_PCB_LOSS_2G;
525 	prf->phy_params[rf_param_offset + 31]  = NRF70_PCB_LOSS_5G_BAND1;
526 	prf->phy_params[rf_param_offset + 32]  = NRF70_PCB_LOSS_5G_BAND2;
527 	prf->phy_params[rf_param_offset + 33]  = NRF70_PCB_LOSS_5G_BAND3;
528 
529 	return(ret);
530 }
531 
532 
nrf_wifi_off_raw_tx_fmac_rf_params_get(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_phy_rf_params * phy_rf_params)533 enum nrf_wifi_status nrf_wifi_off_raw_tx_fmac_rf_params_get(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
534 							    struct nrf_wifi_phy_rf_params *phy_rf_params)
535 {
536 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
537 	struct nrf_wifi_fmac_otp_info otp_info;
538 	unsigned int ft_prog_ver;
539 	int ret = -1;
540 	/* If package_info is not written to OTP then the default value will be 0xFF. */
541 	unsigned int package_info = 0xFFFFFFFF;
542 	struct nrf_wifi_tx_pwr_ceil_params *tx_pwr_ceil_params;
543 	unsigned char backoff_2g_dsss = 0, backoff_2g_ofdm = 0;
544 	unsigned char backoff_5g_lowband = 0, backoff_5g_midband = 0, backoff_5g_highband = 0;
545 
546 	if (!fmac_dev_ctx || !phy_rf_params) {
547 		nrf_wifi_osal_log_err("%s: Invalid parameters",
548 				      __func__);
549 		goto out;
550 	}
551 
552 	if (!fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
553 		nrf_wifi_osal_log_err("%s: Invalid op mode",
554 				      __func__);
555 		goto out;
556 	}
557 
558 	tx_pwr_ceil_params = fmac_dev_ctx->tx_pwr_ceil_params;
559 
560 	nrf_wifi_osal_mem_set(&otp_info,
561 			      0xFF,
562 			      sizeof(otp_info));
563 
564 	status = nrf_wifi_hal_otp_info_get(fmac_dev_ctx->hal_dev_ctx,
565 					   &otp_info.info,
566 					   &otp_info.flags);
567 
568 	if (status != NRF_WIFI_STATUS_SUCCESS) {
569 		nrf_wifi_osal_log_err("%s: Fetching of RPU OTP information failed",
570 				      __func__);
571 		goto out;
572 	}
573 
574 	status = nrf_wifi_hal_otp_ft_prog_ver_get(fmac_dev_ctx->hal_dev_ctx,
575 						  &ft_prog_ver);
576 	if (status != NRF_WIFI_STATUS_SUCCESS) {
577 		nrf_wifi_osal_log_err("%s: Fetching of FT program version failed",
578 				      __func__);
579 		goto out;
580 	}
581 
582 	status = nrf_wifi_hal_otp_pack_info_get(fmac_dev_ctx->hal_dev_ctx,
583 						&package_info);
584 	if (status != NRF_WIFI_STATUS_SUCCESS) {
585 		nrf_wifi_osal_log_err("%s: Fetching of Package info failed",
586 				      __func__);
587 		goto out;
588 	}
589 
590 	ret = nrf_wifi_off_raw_tx_fmac_phy_rf_params_init(phy_rf_params,
591 							  package_info,
592 							  NRF_WIFI_OFF_RAW_TX_DEF_RF_PARAMS);
593 
594 	if (ret == -1) {
595 		nrf_wifi_osal_log_err("%s: Initialization of RF params with default values failed",
596 				      __func__);
597 		status = NRF_WIFI_STATUS_FAIL;
598 		goto out;
599 	}
600 	if (!(otp_info.flags & (~CALIB_XO_FLAG_MASK))) {
601 		nrf_wifi_osal_mem_cpy(&phy_rf_params->xo_offset.xo_freq_offset,
602 				      (char *)otp_info.info.calib + OTP_OFF_CALIB_XO,
603 				      OTP_SZ_CALIB_XO);
604 
605 	}
606 
607 	ft_prog_ver = (ft_prog_ver & FT_PROG_VER_MASK) >> 16;
608 
609 	if (ft_prog_ver == FT_PROG_VER1) {
610 		backoff_2g_dsss = FT_PROG_VER1_2G_DSSS_TXCEIL_BKOFF;
611 		backoff_2g_ofdm = FT_PROG_VER1_2G_OFDM_TXCEIL_BKOFF;
612 		backoff_5g_lowband = FT_PROG_VER1_5G_LOW_OFDM_TXCEIL_BKOFF;
613 		backoff_5g_midband = FT_PROG_VER1_5G_MID_OFDM_TXCEIL_BKOFF;
614 		backoff_5g_highband = FT_PROG_VER1_5G_HIGH_OFDM_TXCEIL_BKOFF;
615 	} else if (ft_prog_ver == FT_PROG_VER2) {
616 		backoff_2g_dsss = FT_PROG_VER2_2G_DSSS_TXCEIL_BKOFF;
617 		backoff_2g_ofdm = FT_PROG_VER2_2G_OFDM_TXCEIL_BKOFF;
618 		backoff_5g_lowband = FT_PROG_VER2_5G_LOW_OFDM_TXCEIL_BKOFF;
619 		backoff_5g_midband = FT_PROG_VER2_5G_MID_OFDM_TXCEIL_BKOFF;
620 		backoff_5g_highband = FT_PROG_VER2_5G_HIGH_OFDM_TXCEIL_BKOFF;
621 	} else if (ft_prog_ver == FT_PROG_VER3) {
622 		backoff_2g_dsss = FT_PROG_VER3_2G_DSSS_TXCEIL_BKOFF;
623 		backoff_2g_ofdm = FT_PROG_VER3_2G_OFDM_TXCEIL_BKOFF;
624 		backoff_5g_lowband = FT_PROG_VER3_5G_LOW_OFDM_TXCEIL_BKOFF;
625 		backoff_5g_midband = FT_PROG_VER3_5G_MID_OFDM_TXCEIL_BKOFF;
626 		backoff_5g_highband = FT_PROG_VER3_5G_HIGH_OFDM_TXCEIL_BKOFF;
627 	}
628 	phy_rf_params->max_pwr_ceil.max_dsss_pwr =
629 	MIN(tx_pwr_ceil_params->max_pwr_2g_dsss, phy_rf_params->max_pwr_ceil.max_dsss_pwr)
630 	- backoff_2g_dsss;
631 	phy_rf_params->max_pwr_ceil.max_lb_mcs7_pwr =
632 	MIN(tx_pwr_ceil_params->max_pwr_2g_mcs7, phy_rf_params->max_pwr_ceil.max_lb_mcs7_pwr)
633 	- backoff_2g_ofdm;
634 	phy_rf_params->max_pwr_ceil.max_lb_mcs0_pwr =
635 	MIN(tx_pwr_ceil_params->max_pwr_2g_mcs0, phy_rf_params->max_pwr_ceil.max_lb_mcs0_pwr)
636 	- backoff_2g_ofdm;
637 #ifndef NRF70_2_4G_ONLY
638 	phy_rf_params->max_pwr_ceil.max_hb_low_chan_mcs7_pwr =
639 	MIN(tx_pwr_ceil_params->max_pwr_5g_low_mcs7,
640 		phy_rf_params->max_pwr_ceil.max_hb_low_chan_mcs7_pwr) - backoff_5g_lowband;
641 	phy_rf_params->max_pwr_ceil.max_hb_mid_chan_mcs7_pwr =
642 	MIN(tx_pwr_ceil_params->max_pwr_5g_mid_mcs7,
643 		phy_rf_params->max_pwr_ceil.max_hb_mid_chan_mcs7_pwr) - backoff_5g_midband;
644 	phy_rf_params->max_pwr_ceil.max_hb_high_chan_mcs7_pwr =
645 	MIN(tx_pwr_ceil_params->max_pwr_5g_high_mcs7,
646 		phy_rf_params->max_pwr_ceil.max_hb_high_chan_mcs7_pwr) - backoff_5g_highband;
647 	phy_rf_params->max_pwr_ceil.max_hb_low_chan_mcs0_pwr =
648 	MIN(tx_pwr_ceil_params->max_pwr_5g_low_mcs0,
649 		phy_rf_params->max_pwr_ceil.max_hb_low_chan_mcs0_pwr) - backoff_5g_lowband;
650 	phy_rf_params->max_pwr_ceil.max_hb_mid_chan_mcs0_pwr =
651 	MIN(tx_pwr_ceil_params->max_pwr_5g_mid_mcs0,
652 	        phy_rf_params->max_pwr_ceil.max_hb_mid_chan_mcs0_pwr) - backoff_5g_midband;
653 	phy_rf_params->max_pwr_ceil.max_hb_high_chan_mcs0_pwr =
654 	MIN(tx_pwr_ceil_params->max_pwr_5g_high_mcs0,
655 	        phy_rf_params->max_pwr_ceil.max_hb_high_chan_mcs0_pwr) - backoff_5g_highband;
656 #endif /* NRF70_2_4G_ONLY */
657 
658 	status = NRF_WIFI_STATUS_SUCCESS;
659 out:
660 	return status;
661 }
662