1 | /** @file wlan_platform_low.c |
---|
2 | * @brief Platform abstraction for CPU Low |
---|
3 | * |
---|
4 | * @copyright Copyright 2014-2019, Mango Communications. All rights reserved. |
---|
5 | * Distributed under the Mango Communications Reference Design License |
---|
6 | * See LICENSE.txt included in the design archive or |
---|
7 | * at http://mangocomm.com/802.11/license |
---|
8 | * |
---|
9 | * This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11) |
---|
10 | */ |
---|
11 | |
---|
12 | // SDK includes |
---|
13 | #include "xil_types.h" |
---|
14 | #include "xil_cache.h" |
---|
15 | #include "xil_assert.h" |
---|
16 | #include "xstatus.h" |
---|
17 | #include "xparameters.h" |
---|
18 | #include "stdarg.h" |
---|
19 | #include "stdlib.h" |
---|
20 | |
---|
21 | // Platform includes |
---|
22 | #include "w3_mac_phy_regs.h" |
---|
23 | #include "w3_low.h" |
---|
24 | #include "w3_common.h" |
---|
25 | #include "wlan_platform_common.h" |
---|
26 | #include "wlan_platform_debug_hdr.h" |
---|
27 | #include "wlan_platform_low.h" |
---|
28 | #include "w3_userio_util.h" |
---|
29 | #include "w3_phy_util.h" |
---|
30 | |
---|
31 | // Low framework includes |
---|
32 | #include "wlan_phy_util.h" |
---|
33 | #include "wlan_mac_low.h" |
---|
34 | #include "wlan_mac_common.h" |
---|
35 | #include "wlan_mac_mailbox_util.h" |
---|
36 | #include "wlan_common_types.h" |
---|
37 | |
---|
38 | // WARP v3 hardware includes |
---|
39 | #include "w3_userio.h" |
---|
40 | #include "w3_ad_controller.h" |
---|
41 | #include "w3_clock_controller.h" |
---|
42 | #include "radio_controller.h" |
---|
43 | #include "w3_phy_util.h" |
---|
44 | |
---|
45 | static channel_band_t gl_current_band; |
---|
46 | static int gl_enable_phy_cs; |
---|
47 | platform_common_dev_info_t platform_common_dev_info; |
---|
48 | |
---|
49 | /***************************************************************************** |
---|
50 | * Public functions - the functions below are exported to the low framework |
---|
51 | *****************************************************************************/ |
---|
52 | void wlan_platform_cpu_low_init() { |
---|
53 | |
---|
54 | Xil_AssertSetCallback((Xil_AssertCallback)wlan_assert_print); |
---|
55 | |
---|
56 | // Disable I and D cache |
---|
57 | Xil_DCacheDisable(); |
---|
58 | Xil_ICacheDisable(); |
---|
59 | |
---|
60 | // Enable exceptions - exceptions *must* be enabled on MicroBlaze |
---|
61 | // to handle unaligned memory accesses |
---|
62 | microblaze_enable_exceptions(); |
---|
63 | |
---|
64 | return; |
---|
65 | } |
---|
66 | |
---|
67 | void wlan_platform_low_userio_disp_status(userio_disp_low_status_t status, ...){ |
---|
68 | va_list valist; |
---|
69 | static u8 red_led_index = 0; |
---|
70 | static u8 green_led_index = 0; |
---|
71 | |
---|
72 | /* initialize valist for num number of arguments */ |
---|
73 | va_start(valist, status); |
---|
74 | |
---|
75 | switch(status){ |
---|
76 | |
---|
77 | case USERIO_DISP_STATUS_GOOD_FCS_EVENT: { |
---|
78 | green_led_index = (green_led_index + 1) % 4; |
---|
79 | userio_write_leds_green(USERIO_BASEADDR, (1<<green_led_index)); |
---|
80 | } break; |
---|
81 | |
---|
82 | case USERIO_DISP_STATUS_BAD_FCS_EVENT: { |
---|
83 | red_led_index = (red_led_index + 1) % 4; |
---|
84 | userio_write_leds_red(USERIO_BASEADDR, (1<<red_led_index)); |
---|
85 | } break; |
---|
86 | case USERIO_DISP_STATUS_CPU_ERROR: { |
---|
87 | u32 error_code = va_arg(valist, u32); |
---|
88 | if (error_code != WLAN_ERROR_CPU_STOP) { |
---|
89 | // Print error message |
---|
90 | xil_printf("\n\nERROR: CPU is halting with error code: E%X\n\n", (error_code & 0xF)); |
---|
91 | |
---|
92 | // Set the error code on the hex display |
---|
93 | set_hex_display_error_status(error_code & 0xF); |
---|
94 | |
---|
95 | // Enter infinite loop blinking the hex display |
---|
96 | blink_hex_display(0, 250000); |
---|
97 | } else { |
---|
98 | // Stop execution |
---|
99 | while (1) {}; |
---|
100 | } |
---|
101 | } break; |
---|
102 | |
---|
103 | default: |
---|
104 | break; |
---|
105 | } |
---|
106 | |
---|
107 | /* clean memory reserved for valist */ |
---|
108 | va_end(valist); |
---|
109 | return; |
---|
110 | } |
---|
111 | |
---|
112 | int wlan_platform_low_init() { |
---|
113 | int status; |
---|
114 | |
---|
115 | // Get the device info |
---|
116 | platform_common_dev_info = wlan_platform_common_get_dev_info(); |
---|
117 | |
---|
118 | status = w3_node_init(); |
---|
119 | if(status != 0) { |
---|
120 | xil_printf("ERROR in w3_node_init(): %d\n", status); |
---|
121 | return status; |
---|
122 | } |
---|
123 | |
---|
124 | w3_radio_init(); |
---|
125 | w3_agc_init(); |
---|
126 | |
---|
127 | wlan_platform_enable_phy_cs(0); //Call once so we know the global gets set. This will be overwritten when the Low Framework |
---|
128 | //finishes booting |
---|
129 | |
---|
130 | return WLAN_SUCCESS; |
---|
131 | } |
---|
132 | |
---|
133 | |
---|
134 | void max2829_tune_custom(u32 band_sel, u32 pll_div_int, u32 pll_div_frac) { |
---|
135 | // band_sel: 0=2.4GHz; 1=4.9-5.35GHz; 2=>5.35GHz |
---|
136 | // pll_div_int: integer part of PLL divider ratio |
---|
137 | // pll_div_frac: fractional part of PLL divider ratio as UFix16_16 |
---|
138 | |
---|
139 | // Assume only RF A |
---|
140 | u32 rfSel = RC_RFA; |
---|
141 | |
---|
142 | u16 reg3 = (pll_div_int & 0x0FF) | ((pll_div_frac & 0x3) << 12); //reg3[11:8] always 0 |
---|
143 | u16 reg4 = (pll_div_frac & 0xFFFC) >> 2; |
---|
144 | |
---|
145 | if(band_sel == 0) { |
---|
146 | //MAX2829 tuning process for 2.4GHz channels: |
---|
147 | // -Set reg5[0] to 0 (selects 2.4GHz) |
---|
148 | // -Set reg3, reg4 with PLL tuning params |
---|
149 | |
---|
150 | radio_controller_SPI_setRegBits(RC_BASEADDR, rfSel, 5, 0x1, 0x0); |
---|
151 | |
---|
152 | //Write the PLL parameters |
---|
153 | radio_controller_SPI_write(RC_BASEADDR, rfSel, 3, reg3); |
---|
154 | radio_controller_SPI_write(RC_BASEADDR, rfSel, 4, reg4); |
---|
155 | |
---|
156 | } else { |
---|
157 | //MAX2829 tuning process for 5GHz channels: |
---|
158 | //(Assumes default config of 5GHz sub-band tuning via FSM; see MAX2829 datasheet for details) |
---|
159 | // -Set: |
---|
160 | // -reg5[0] to 1 (selects 5GHz) |
---|
161 | // -reg5[6] based on selected freq (0:4.9-5.35GHz, 1:5.47-5.875GHz) |
---|
162 | // -Set reg3, reg4 with PLL tuning params |
---|
163 | |
---|
164 | if(band_sel == 1) |
---|
165 | radio_controller_SPI_setRegBits(RC_BASEADDR, rfSel, 5, 0x41, 0x01); |
---|
166 | else |
---|
167 | radio_controller_SPI_setRegBits(RC_BASEADDR, rfSel, 5, 0x41, 0x41); |
---|
168 | |
---|
169 | //Reset the band select FSM |
---|
170 | radio_controller_SPI_setRegBits(RC_BASEADDR, rfSel, 5, 0x80, 0x00); |
---|
171 | |
---|
172 | //Write the PLL parameters |
---|
173 | radio_controller_SPI_write(RC_BASEADDR, rfSel, 3, reg3); |
---|
174 | radio_controller_SPI_write(RC_BASEADDR, rfSel, 4, reg4); |
---|
175 | |
---|
176 | //Start the band select FSM |
---|
177 | radio_controller_SPI_setRegBits(RC_BASEADDR, rfSel, 5, 0x80, 0x80); |
---|
178 | } |
---|
179 | |
---|
180 | return; |
---|
181 | } |
---|
182 | |
---|
183 | void wlan_platform_low_param_handler(u8 mode, u32* payload) { |
---|
184 | if(mode != IPC_REG_WRITE_MODE) { |
---|
185 | xil_printf("ERROR wlan_platform_low_param_handler: unrecognized mode (%d) - mode must be WRITE\n", mode); |
---|
186 | return; |
---|
187 | } |
---|
188 | |
---|
189 | switch(payload[0]) { |
---|
190 | case LOW_PARAM_PKT_DET_MIN_POWER: { |
---|
191 | int min_pwr_arg = payload[1] & 0xFF; |
---|
192 | if(min_pwr_arg == 0) { |
---|
193 | // wlan_exp uses 0 to disable min power det logic |
---|
194 | wlan_platform_set_pkt_det_min_power(0); |
---|
195 | } else { |
---|
196 | //The value sent from wlan_exp will be unsigned with 0 representing PKT_DET_MIN_POWER_MIN |
---|
197 | wlan_platform_set_pkt_det_min_power(min_pwr_arg + PKT_DET_MIN_POWER_MIN); |
---|
198 | } |
---|
199 | } |
---|
200 | break; |
---|
201 | |
---|
202 | case LOW_PARAM_CUSTOM_MAX2829_TUNE: { |
---|
203 | // Tune MAX2829 PLL to non-standard center frequency |
---|
204 | max2829_tune_custom(payload[1], payload[2], payload[3]); |
---|
205 | } |
---|
206 | break; |
---|
207 | |
---|
208 | default: |
---|
209 | break; |
---|
210 | } |
---|
211 | |
---|
212 | return; |
---|
213 | } |
---|
214 | |
---|
215 | void wlan_platform_low_set_rx_ant_mode(u32 ant_mode) { |
---|
216 | |
---|
217 | // Disable PHY control of all RF interfaces - selected interfaces to re-enabled below |
---|
218 | radio_controller_setCtrlSource(RC_BASEADDR, RC_ALL_RF, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_REG); |
---|
219 | |
---|
220 | // Set the antenna mode |
---|
221 | // |
---|
222 | // For each antenna mode: |
---|
223 | // - Enable packet detection |
---|
224 | // - Select I/Q stream for Rx PHY |
---|
225 | // - Give PHY control of Tx/Rx status |
---|
226 | // - Configure AGC |
---|
227 | // |
---|
228 | switch (ant_mode) { |
---|
229 | case RX_ANTMODE_SISO_ANTA: |
---|
230 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFA, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
231 | break; |
---|
232 | |
---|
233 | case RX_ANTMODE_SISO_ANTB: |
---|
234 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFB, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
235 | break; |
---|
236 | |
---|
237 | case RX_ANTMODE_SISO_ANTC: |
---|
238 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFC, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
239 | break; |
---|
240 | |
---|
241 | case RX_ANTMODE_SISO_ANTD: |
---|
242 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFD, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
243 | break; |
---|
244 | |
---|
245 | case RX_ANTMODE_SISO_SELDIV_2ANT: |
---|
246 | // By enabling the antenna switching, the I/Q stream is automatically switched for Rx PHY |
---|
247 | radio_controller_setCtrlSource(RC_BASEADDR, (RC_RFA | RC_RFB), RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
248 | break; |
---|
249 | |
---|
250 | case RX_ANTMODE_SISO_SELDIV_4ANT: |
---|
251 | // By enabling the antenna switching, the I/Q stream is automatically switched for Rx PHY |
---|
252 | radio_controller_setCtrlSource(RC_BASEADDR, RC_ALL_RF, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
253 | break; |
---|
254 | |
---|
255 | default: |
---|
256 | // Default to SISO on A if user provides invalid mode |
---|
257 | xil_printf("wlan_platform_low_set_rx_ant_mode ERROR: Invalid Mode - Defaulting to SISO on A\n"); |
---|
258 | |
---|
259 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFA, RC_REG0_RXEN_CTRLSRC, RC_CTRLSRC_HW); |
---|
260 | break; |
---|
261 | } |
---|
262 | return; |
---|
263 | } |
---|
264 | |
---|
265 | int wlan_platform_low_set_samp_rate(phy_samp_rate_t phy_samp_rate) { |
---|
266 | if((phy_samp_rate != PHY_10M) && (phy_samp_rate != PHY_20M) && (phy_samp_rate != PHY_40M)) { |
---|
267 | xil_printf("Invalid PHY samp rate (%d)\n", phy_samp_rate); |
---|
268 | return WLAN_FAILURE; |
---|
269 | } |
---|
270 | |
---|
271 | // Assert PHY Tx/Rx and MAC Resets |
---|
272 | REG_SET_BITS(WLAN_RX_REG_CTRL, WLAN_RX_REG_CTRL_RESET); |
---|
273 | REG_SET_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_RESET); |
---|
274 | wlan_mac_reset(1); |
---|
275 | |
---|
276 | // Set RF interface clocking and interp/decimation filters |
---|
277 | switch(phy_samp_rate){ |
---|
278 | case PHY_40M: |
---|
279 | // Set ADC_CLK=DAC_CLK=40MHz, interp_rate=decim_rate=1 |
---|
280 | clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB)); |
---|
281 | ad_config_filters(AD_BASEADDR, AD_ALL_RF, 1, 1); |
---|
282 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x2F); |
---|
283 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x00); |
---|
284 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08); |
---|
285 | break; |
---|
286 | case PHY_20M: |
---|
287 | // Set ADC_CLK=DAC_CLK=40MHz, interp_rate=decim_rate=2 |
---|
288 | clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB)); |
---|
289 | |
---|
290 | ad_config_filters(AD_BASEADDR, AD_ALL_RF, 2, 2); |
---|
291 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x27); |
---|
292 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x00); |
---|
293 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08); |
---|
294 | break; |
---|
295 | case PHY_10M: |
---|
296 | // Set ADC_CLK=DAC_CLK=20MHz, interp_rate=decim_rate=2 |
---|
297 | clk_config_dividers(CLK_BASEADDR, 4, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB)); |
---|
298 | ad_config_filters(AD_BASEADDR, AD_ALL_RF, 2, 2); |
---|
299 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x27); |
---|
300 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x00); |
---|
301 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08); |
---|
302 | break; |
---|
303 | } |
---|
304 | |
---|
305 | switch(phy_samp_rate){ |
---|
306 | case PHY_40M: |
---|
307 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXLPF_BW, 3); |
---|
308 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLPF_BW, 3); |
---|
309 | break; |
---|
310 | case PHY_10M: |
---|
311 | case PHY_20M: |
---|
312 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXLPF_BW, 1); |
---|
313 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLPF_BW, 1); |
---|
314 | break; |
---|
315 | } |
---|
316 | |
---|
317 | // AGC timing: capt_rssi_1, capt_rssi_2, capt_v_db, agc_done |
---|
318 | switch(phy_samp_rate){ |
---|
319 | case PHY_40M: |
---|
320 | wlan_agc_set_AGC_timing(10, 30, 90, 96); |
---|
321 | break; |
---|
322 | case PHY_10M: |
---|
323 | case PHY_20M: |
---|
324 | wlan_agc_set_AGC_timing(1, 30, 90, 96); |
---|
325 | break; |
---|
326 | } |
---|
327 | |
---|
328 | |
---|
329 | // Configure auto-correlation packet detection |
---|
330 | // wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(corr_thresh, energy_thresh, min_dur, post_wait) |
---|
331 | switch(phy_samp_rate){ |
---|
332 | case PHY_40M: |
---|
333 | // TODO: investigate need for lower correlation threshold at 40MSps |
---|
334 | wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(100, 15, 4, 0x3F); |
---|
335 | break; |
---|
336 | case PHY_10M: |
---|
337 | case PHY_20M: |
---|
338 | wlan_phy_rx_pktDet_autoCorr_ofdm_cfg(100, 15, 4, 0x3F); |
---|
339 | break; |
---|
340 | } |
---|
341 | |
---|
342 | // Set post Rx extension |
---|
343 | // Number of sample periods post-Rx the PHY waits before asserting Rx END. This value |
---|
344 | // should be 6 usec and backdated by the delay through the Rx chain. This aligns the |
---|
345 | // Rx END event to the correct sample at the antenna. |
---|
346 | switch(phy_samp_rate){ |
---|
347 | case PHY_40M: |
---|
348 | wlan_phy_rx_set_extension((6*40) - (platform_common_dev_info.rx_analog_latency_100ns*4)); |
---|
349 | break; |
---|
350 | case PHY_20M: |
---|
351 | wlan_phy_rx_set_extension((6*20) - (platform_common_dev_info.rx_analog_latency_100ns*2)); |
---|
352 | break; |
---|
353 | case PHY_10M: |
---|
354 | wlan_phy_rx_set_extension((6*10) - (platform_common_dev_info.rx_analog_latency_100ns)); |
---|
355 | break; |
---|
356 | } |
---|
357 | |
---|
358 | // Set Tx duration extension, in units of sample periods. This value should be 6 usec, but |
---|
359 | // pushed forward to account for delay through the Tx chain. The results should be a Tx END |
---|
360 | // that asserts at the same time as an Rx END on the node receiving the packet (ignoring |
---|
361 | // propagation delay). |
---|
362 | switch(phy_samp_rate){ |
---|
363 | case PHY_40M: |
---|
364 | wlan_phy_tx_set_extension((6*40) + (platform_common_dev_info.tx_analog_latency_100ns*4)); |
---|
365 | |
---|
366 | // Set extension from last samp output to RF Tx -> Rx transition |
---|
367 | // This delay allows the Tx pipeline to finish driving samples into DACs |
---|
368 | // and for DAC->RF frontend to finish output Tx waveform |
---|
369 | wlan_phy_tx_set_txen_extension(100); |
---|
370 | |
---|
371 | // Set extension from RF Rx -> Tx to un-blocking Rx samples |
---|
372 | wlan_phy_tx_set_rx_invalid_extension(300); |
---|
373 | break; |
---|
374 | case PHY_20M: |
---|
375 | wlan_phy_tx_set_extension((6*20) + (platform_common_dev_info.tx_analog_latency_100ns*2)); |
---|
376 | |
---|
377 | // Set extension from last samp output to RF Tx -> Rx transition |
---|
378 | // This delay allows the Tx pipeline to finish driving samples into DACs |
---|
379 | // and for DAC->RF frontend to finish output Tx waveform |
---|
380 | wlan_phy_tx_set_txen_extension(50); //50 |
---|
381 | |
---|
382 | // Set extension from RF Rx -> Tx to un-blocking Rx samples |
---|
383 | wlan_phy_tx_set_rx_invalid_extension(150); |
---|
384 | break; |
---|
385 | case PHY_10M: |
---|
386 | wlan_phy_tx_set_extension((6*10) + (platform_common_dev_info.tx_analog_latency_100ns)); |
---|
387 | |
---|
388 | // Set extension from last samp output to RF Tx -> Rx transition |
---|
389 | // This delay allows the Tx pipeline to finish driving samples into DACs |
---|
390 | // and for DAC->RF frontend to finish output Tx waveform |
---|
391 | wlan_phy_tx_set_txen_extension(25); |
---|
392 | |
---|
393 | // Set extension from RF Rx -> Tx to un-blocking Rx samples |
---|
394 | wlan_phy_tx_set_rx_invalid_extension(75); |
---|
395 | break; |
---|
396 | } |
---|
397 | |
---|
398 | // Deassert PHY Tx/Rx and MAC Resets |
---|
399 | REG_CLEAR_BITS(WLAN_RX_REG_CTRL, WLAN_RX_REG_CTRL_RESET); |
---|
400 | REG_CLEAR_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_RESET); |
---|
401 | wlan_mac_reset(0); |
---|
402 | |
---|
403 | // Let PHY Tx take control of radio TXEN/RXEN |
---|
404 | REG_CLEAR_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_SET_RC_RXEN); |
---|
405 | REG_SET_BITS(WLAN_TX_REG_CFG, WLAN_TX_REG_CFG_SET_RC_RXEN); |
---|
406 | |
---|
407 | return WLAN_SUCCESS; |
---|
408 | } |
---|
409 | |
---|
410 | |
---|
411 | |
---|
412 | /*****************************************************************************/ |
---|
413 | /** |
---|
414 | * @brief Set the radio channel |
---|
415 | * |
---|
416 | * This function will set the radio channel for CPU LOW |
---|
417 | * |
---|
418 | * @param channel - Radio channel |
---|
419 | * @return None |
---|
420 | * |
---|
421 | */ |
---|
422 | int wlan_platform_low_set_radio_channel(u32 channel) { |
---|
423 | channel_band_t prev_band = gl_current_band; |
---|
424 | |
---|
425 | if(channel <= 14) { |
---|
426 | // 2.4GHz channel |
---|
427 | radio_controller_setCenterFrequency(RC_BASEADDR, (RC_ALL_RF), RC_24GHZ, w3_wlan_chan_to_rc_chan(channel)); |
---|
428 | gl_current_band = BAND_24GHZ; |
---|
429 | } else { |
---|
430 | // 5GHz channel |
---|
431 | radio_controller_setCenterFrequency(RC_BASEADDR, (RC_ALL_RF), RC_5GHZ, w3_wlan_chan_to_rc_chan(channel)); |
---|
432 | gl_current_band = BAND_5GHZ; |
---|
433 | } |
---|
434 | |
---|
435 | if(prev_band != gl_current_band){ |
---|
436 | //Update the CS thresh since the RSSI <-> Rx Power mapping as changed |
---|
437 | wlan_platform_enable_phy_cs(gl_enable_phy_cs); |
---|
438 | } |
---|
439 | |
---|
440 | return WLAN_SUCCESS; |
---|
441 | } |
---|
442 | |
---|
443 | |
---|
444 | /******************************************************************************** |
---|
445 | * Private functions - the functions below are not exported to the low framework |
---|
446 | ********************************************************************************/ |
---|
447 | |
---|
448 | |
---|
449 | /*****************************************************************************/ |
---|
450 | /** |
---|
451 | * Initialize the WARP v3 node |
---|
452 | * |
---|
453 | * @param None |
---|
454 | * |
---|
455 | * @return int - Status of the command: |
---|
456 | * WLAN_SUCCESS - Command completed successfully |
---|
457 | * WLAN_FAILURE - There was an error in the command |
---|
458 | * |
---|
459 | *****************************************************************************/ |
---|
460 | int w3_node_init() { |
---|
461 | |
---|
462 | int ret_val = WLAN_SUCCESS; |
---|
463 | int status; |
---|
464 | u32 clkmod_status; |
---|
465 | |
---|
466 | // Initialize w3_clock_controller hardware and AD9512 buffers |
---|
467 | // NOTE: The clock initialization will set the clock divider to 2 (for 40MHz clock) to RF A/B AD9963's |
---|
468 | status = clk_init(CLK_BASEADDR, 2); |
---|
469 | if(status != XST_SUCCESS) { |
---|
470 | xil_printf("ERROR: (w3_node_init) Clock initialization failed with error code: %d\n", status); |
---|
471 | ret_val = WLAN_FAILURE; |
---|
472 | } |
---|
473 | |
---|
474 | // Check for a clock module and configure clock inputs, outputs and dividers as needed |
---|
475 | clkmod_status = clk_config_read_clkmod_status(CLK_BASEADDR); |
---|
476 | |
---|
477 | switch(clkmod_status & CM_STATUS_SW) { |
---|
478 | case CM_STATUS_DET_NOCM: |
---|
479 | case CM_STATUS_DET_CMPLL_BYPASS: |
---|
480 | // No clock module - default config from HDL/driver is good as-is |
---|
481 | xil_printf("No clock module detected - selecting on-board clocks\n\n"); |
---|
482 | break; |
---|
483 | |
---|
484 | case CM_STATUS_DET_CMMMCX_CFG_A: |
---|
485 | // CM-MMCX config A: |
---|
486 | // Samp clk: on-board, RF clk: on-board |
---|
487 | // Samp MMCX output: 80MHz, RF MMCX output: 80MHz |
---|
488 | xil_printf("CM-MMCX Config A Detected:\n"); |
---|
489 | xil_printf(" RF: On-board\n Samp: On-board\n MMCX Outputs: Enabled\n\n"); |
---|
490 | |
---|
491 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
492 | clk_config_dividers(CLK_BASEADDR, 1, CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR); |
---|
493 | break; |
---|
494 | |
---|
495 | case CM_STATUS_DET_CMMMCX_CFG_B: |
---|
496 | // CM-MMCX config B: |
---|
497 | // Samp clk: off-board, RF clk: off-board |
---|
498 | // Samp MMCX output: 80MHz, RF MMCX output: 80MHz |
---|
499 | xil_printf("CM-MMCX Config B Detected:\n"); |
---|
500 | xil_printf(" RF: Off-board\n Samp: Off-board\n MMCX Outputs: Enabled\n\n"); |
---|
501 | |
---|
502 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
503 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
504 | clk_config_dividers(CLK_BASEADDR, 1, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
505 | break; |
---|
506 | |
---|
507 | case CM_STATUS_DET_CMMMCX_CFG_C: |
---|
508 | // CM-MMCX config C: |
---|
509 | // Samp clk: off-board, RF clk: off-board |
---|
510 | // Samp MMCX output: Off, RF MMCX output: Off |
---|
511 | xil_printf("CM-MMCX Config C Detected:\n"); |
---|
512 | xil_printf(" RF: Off-board\n Samp: Off-board\n MMCX Outputs: Disabled\n\n"); |
---|
513 | |
---|
514 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
515 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_OFF, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
516 | break; |
---|
517 | |
---|
518 | case CM_STATUS_DET_CMPLL_CFG_A: |
---|
519 | // CM-PLL config A: |
---|
520 | // Samp clk: clock module PLL |
---|
521 | // RF clk: on-board |
---|
522 | xil_printf("CM-PLL Config A Detected:\n"); |
---|
523 | xil_printf(" RF: On-board\n Samp: clock module PLL\n"); |
---|
524 | |
---|
525 | // No changes from configuration applied by HDL and clk_init() |
---|
526 | break; |
---|
527 | |
---|
528 | case CM_STATUS_DET_CMPLL_CFG_B: |
---|
529 | // CM-PLL config B: |
---|
530 | // Samp clk: clock module PLL |
---|
531 | // RF clk: clock module PLL |
---|
532 | xil_printf("CM-PLL Config B Detected:\n"); |
---|
533 | xil_printf(" RF: clock module PLL\n Samp: clock module PLL\n"); |
---|
534 | |
---|
535 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
536 | break; |
---|
537 | |
---|
538 | case CM_STATUS_DET_CMPLL_CFG_C: |
---|
539 | // CM-PLL config C: |
---|
540 | // Samp clk: clock module PLL |
---|
541 | // RF clk: clock module PLL |
---|
542 | xil_printf("CM-PLL Config C Detected:\n"); |
---|
543 | xil_printf(" RF: clock module PLL\n Samp: clock module PLL\n"); |
---|
544 | |
---|
545 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
546 | break; |
---|
547 | |
---|
548 | default: |
---|
549 | // Should be impossible |
---|
550 | xil_printf("ERROR: (w3_node_init) Invalid clock module switch settings! (0x%08x)\n", clkmod_status); |
---|
551 | ret_val = XST_FAILURE; |
---|
552 | break; |
---|
553 | } |
---|
554 | |
---|
555 | #ifdef WLAN_4RF_EN |
---|
556 | // Turn on clocks to FMC |
---|
557 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_FMC | CLK_RFREF_OUTSEL_FMC)); |
---|
558 | |
---|
559 | // FMC samp clock divider = 2 (40MHz sampling reference, same as on-board AD9963 ref clk) |
---|
560 | clk_config_dividers(CLK_BASEADDR, 2, CLK_SAMP_OUTSEL_FMC); |
---|
561 | |
---|
562 | // FMC RF ref clock divider = 2 (40MHz RF reference, same as on-board MAX2829 ref clk) |
---|
563 | clk_config_dividers(CLK_BASEADDR, 2, CLK_RFREF_OUTSEL_FMC); |
---|
564 | #endif |
---|
565 | |
---|
566 | // Initialize the AD9963 ADCs/DACs for on-board RF interfaces |
---|
567 | ad_init(AD_BASEADDR, AD_ALL_RF, 3); |
---|
568 | |
---|
569 | // Disable AD9963 Duty Cycle Stabilizer (recommended when ADCCLK < 75MHz) |
---|
570 | ad_config_clocks(AD_BASEADDR, AD_ALL_RF, AD_DACCLKSRC_EXT, AD_ADCCLKSRC_EXT, AD_ADCCLKDIV_1, AD_DCS_OFF); |
---|
571 | |
---|
572 | if(status != XST_SUCCESS) { |
---|
573 | xil_printf("ERROR: (w3_node_init) ADC/DAC initialization failed with error code: %d\n", status); |
---|
574 | ret_val = WLAN_FAILURE; |
---|
575 | } |
---|
576 | |
---|
577 | // Initialize the radio_controller core and MAX2829 transceivers for on-board RF interfaces |
---|
578 | status = radio_controller_init(RC_BASEADDR, RC_ALL_RF, 1, 1); |
---|
579 | |
---|
580 | if(status != XST_SUCCESS) { |
---|
581 | xil_printf("ERROR: (w3_node_init) Radio controller initialization failed with error code: %d\n", status); |
---|
582 | |
---|
583 | // Comment out the line below to allow the node to boot even if a radio PLL is unlocked |
---|
584 | ret_val = WLAN_FAILURE; |
---|
585 | } |
---|
586 | |
---|
587 | #ifdef WLAN_4RF_EN |
---|
588 | //TODO: 4RF mode not supported in 1.7.0. We will add it back in |
---|
589 | // in a future dot release. |
---|
590 | iic_eeprom_init(FMC_EEPROM_BASEADDR, 0x64); |
---|
591 | #endif |
---|
592 | |
---|
593 | // Give the PHY control of the red user LEDs (PHY counts 1-hot on SIGNAL errors) |
---|
594 | // |
---|
595 | // NOTE: Uncommenting this line will make the RED LEDs controlled by hardware. |
---|
596 | // This will move the LEDs on PHY bad signal events |
---|
597 | // |
---|
598 | // userio_set_ctrlSrc_hw(USERIO_BASEADDR, W3_USERIO_CTRLSRC_LEDS_RED); |
---|
599 | |
---|
600 | // Initialize Debug Header |
---|
601 | // Configure pins 15:12 as software controlled outputs, pins 11:0 as hardware controlled |
---|
602 | // This configuration is applied only by CPU Low to avoid races between CPUs at boot |
---|
603 | // Both CPUs can control the software-controlled pins |
---|
604 | wlan_mac_set_dbg_hdr_ctrlsrc(DBG_HDR_CTRLSRC_HW, 0x0FFF); |
---|
605 | wlan_mac_set_dbg_hdr_ctrlsrc(DBG_HDR_CTRLSRC_SW, 0xF000); |
---|
606 | wlan_mac_set_dbg_hdr_dir(DBG_HDR_DIR_OUTPUT, 0xF000); |
---|
607 | |
---|
608 | return ret_val; |
---|
609 | } |
---|
610 | |
---|
611 | /*****************************************************************************/ |
---|
612 | /** |
---|
613 | * Initialize the Radio Controller |
---|
614 | * |
---|
615 | * @param None |
---|
616 | * |
---|
617 | * @return None |
---|
618 | * |
---|
619 | * @note This function supports both 2RF and 4RF configurations. Also, there are |
---|
620 | * sections (ie #if sections) that have been added to assist if clocking changes |
---|
621 | * are needed. |
---|
622 | * |
---|
623 | *****************************************************************************/ |
---|
624 | void w3_radio_init() { |
---|
625 | |
---|
626 | #if 1 |
---|
627 | |
---|
628 | // Setup clocking and filtering (20MSps, 2x interp/decimate in AD9963) |
---|
629 | clk_config_dividers(CLK_BASEADDR, 2, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB)); |
---|
630 | ad_config_filters(AD_BASEADDR, AD_ALL_RF, 2, 2); |
---|
631 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x32, 0x27); |
---|
632 | ad_spi_write(AD_BASEADDR, (AD_ALL_RF), 0x33, 0x08); |
---|
633 | |
---|
634 | #else |
---|
635 | // Setup clocking and filtering: |
---|
636 | // 80MHz ref clk to AD9963 |
---|
637 | // 20MSps Tx/Rx at FPGA |
---|
638 | // 80MHz DAC, 4x interp in AD9963 |
---|
639 | // 40MHz ADC, 2x decimate in AD9963 |
---|
640 | // |
---|
641 | clk_config_dividers(CLK_BASEADDR, 1, (CLK_SAMP_OUTSEL_AD_RFA | CLK_SAMP_OUTSEL_AD_RFB)); |
---|
642 | |
---|
643 | ad_config_clocks(AD_BASEADDR, AD_ALL_RF, AD_DACCLKSRC_EXT, AD_ADCCLKSRC_EXT, AD_ADCCLKDIV_2, AD_DCS_OFF); |
---|
644 | |
---|
645 | ad_config_filters(AD_BASEADDR, AD_ALL_RF, 4, 2); |
---|
646 | #endif |
---|
647 | |
---|
648 | // Setup all RF interfaces |
---|
649 | radio_controller_TxRxDisable(RC_BASEADDR, RC_ALL_RF); |
---|
650 | |
---|
651 | radio_controller_apply_TxDCO_calibration(AD_BASEADDR, EEPROM_BASEADDR, (RC_RFA | RC_RFB)); |
---|
652 | #ifdef WLAN_4RF_EN |
---|
653 | radio_controller_apply_TxDCO_calibration(AD_BASEADDR, FMC_EEPROM_BASEADDR, (RC_RFC | RC_RFD)); |
---|
654 | #endif |
---|
655 | |
---|
656 | radio_controller_setCenterFrequency(RC_BASEADDR, RC_ALL_RF, RC_24GHZ, 4); |
---|
657 | |
---|
658 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RSSI_HIGH_BW_EN, 0); |
---|
659 | |
---|
660 | // Filter bandwidths |
---|
661 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXHPF_HIGH_CUTOFF_EN, 1); |
---|
662 | |
---|
663 | #if 0 |
---|
664 | // To set the gains manually for all radios: |
---|
665 | radio_controller_setCtrlSource(RC_BASEADDR, RC_ALL_RF, RC_REG0_RXHP_CTRLSRC, RC_CTRLSRC_REG); |
---|
666 | radio_controller_setRxHP(RC_BASEADDR, RC_ALL_RF, RC_RXHP_OFF); |
---|
667 | radio_controller_setRxGainSource(RC_BASEADDR, RC_ALL_RF, RC_GAINSRC_SPI); |
---|
668 | |
---|
669 | // Set Rx gains |
---|
670 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXGAIN_RF, 1); |
---|
671 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXGAIN_BB, 8); |
---|
672 | |
---|
673 | #else |
---|
674 | // AGC |
---|
675 | radio_controller_setCtrlSource(RC_BASEADDR, RC_ALL_RF, RC_REG0_RXHP_CTRLSRC, RC_CTRLSRC_HW); |
---|
676 | radio_controller_setRxGainSource(RC_BASEADDR, RC_ALL_RF, RC_GAINSRC_HW); |
---|
677 | #endif |
---|
678 | |
---|
679 | // Set Tx gains |
---|
680 | // |
---|
681 | // NOTE: To use software to control the Tx gains, use the following lines: |
---|
682 | // radio_controller_setTxGainSource(RC_BASEADDR, RC_ALL_RF, RC_GAINSRC_REG); //Used for software control of gains |
---|
683 | // radio_controller_setTxGainTarget(RC_BASEADDR, RC_ALL_RF, 45); |
---|
684 | // |
---|
685 | radio_controller_setTxGainSource(RC_BASEADDR, RC_ALL_RF, RC_GAINSRC_HW); //Used for hardware control of gains |
---|
686 | |
---|
687 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXGAIN_BB, 1); |
---|
688 | |
---|
689 | // Set misc radio params |
---|
690 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_PADRIVER, 2); |
---|
691 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_VGA, 0); |
---|
692 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_TXLINEARITY_UPCONV, 0); |
---|
693 | |
---|
694 | // Set Tx state machine timing |
---|
695 | // |
---|
696 | // NOTE: radio_controller_setTxDelays(dly_GainRamp, dly_PA, dly_TX, dly_PHY) |
---|
697 | // |
---|
698 | radio_controller_setTxDelays(RC_BASEADDR, 40, 20, 0, 0); //240 PA time after 180 PHY time is critical point |
---|
699 | |
---|
700 | // Configure the radio_controller Tx/Rx enable control sources |
---|
701 | // The Tx PHY drives a 4-bit TxEn, one bit per RF interface |
---|
702 | // The Tx PHY drives a 1-bit RxEn, common to all RF interfaces |
---|
703 | // MAC software should select active Rx interface by changing RFA/RFB RxEn ctrl src between _HW and _REG |
---|
704 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFA, (RC_REG0_RXEN_CTRLSRC), RC_CTRLSRC_HW); |
---|
705 | radio_controller_setCtrlSource(RC_BASEADDR, RC_RFB, (RC_REG0_RXEN_CTRLSRC), RC_CTRLSRC_REG); |
---|
706 | |
---|
707 | radio_controller_setCtrlSource(RC_BASEADDR, (RC_RFA | RC_RFB), (RC_REG0_TXEN_CTRLSRC), RC_CTRLSRC_HW); |
---|
708 | |
---|
709 | #ifdef WLAN_4RF_EN |
---|
710 | radio_controller_setCtrlSource(RC_BASEADDR, (RC_RFC | RC_RFD), (RC_REG0_TXEN_CTRLSRC), RC_CTRLSRC_HW); |
---|
711 | radio_controller_setCtrlSource(RC_BASEADDR, (RC_RFC | RC_RFD), (RC_REG0_RXEN_CTRLSRC), RC_CTRLSRC_REG); |
---|
712 | #else |
---|
713 | // Disable any hardware control of RFC/RFD |
---|
714 | radio_controller_setCtrlSource(RC_BASEADDR, (RC_RFC | RC_RFD), (RC_REG0_RXEN_CTRLSRC | RC_REG0_TXEN_CTRLSRC), RC_CTRLSRC_REG); |
---|
715 | #endif |
---|
716 | |
---|
717 | return; |
---|
718 | } |
---|
719 | |
---|
720 | int w3_agc_init() { |
---|
721 | |
---|
722 | // Post Rx_done reset delays for [rxhp, g_rf, g_bb] |
---|
723 | wlan_agc_set_reset_timing(4, 250, 250); |
---|
724 | |
---|
725 | // AGC config: |
---|
726 | // RFG Thresh 3->2, 2->1, Avg_len_sel, V_DB_Adj, Init G_BB |
---|
727 | wlan_agc_set_config((256 - 56), (256 - 37), 0, 6, 24); |
---|
728 | |
---|
729 | // AGC RSSI->Rx power offsets |
---|
730 | wlan_agc_set_RSSI_pwr_calib(100, 85, 70); |
---|
731 | |
---|
732 | // AGC timing: start_dco, en_iir_filt |
---|
733 | wlan_agc_set_DCO_timing(100, (100 + 34)); |
---|
734 | |
---|
735 | // AGC target output power (log scale) |
---|
736 | wlan_agc_set_target((64 - 16)); |
---|
737 | |
---|
738 | // Configure AGC to keep RXHP asserted between pkt det events |
---|
739 | // Note: this mode should be left 0 to prevent false positive OFDM |
---|
740 | // detection events immediately following a reception. |
---|
741 | wlan_agc_set_rxhp_mode(0); |
---|
742 | |
---|
743 | // Configure AGC to leave RXHP de-asserted until the AGC is triggered |
---|
744 | //wlan_agc_set_rxhp_mode(1); |
---|
745 | |
---|
746 | #if 0 |
---|
747 | // To set the gains manually: |
---|
748 | |
---|
749 | //xil_printf("Switching to MGC\n"); |
---|
750 | radio_controller_setCtrlSource(RC_BASEADDR, RC_ALL_RF, RC_REG0_RXHP_CTRLSRC, RC_CTRLSRC_REG); |
---|
751 | radio_controller_setRxHP(RC_BASEADDR, RC_ALL_RF, RC_RXHP_OFF); |
---|
752 | radio_controller_setRxGainSource(RC_BASEADDR, RC_ALL_RF, RC_GAINSRC_SPI); |
---|
753 | |
---|
754 | // Set Rx gains |
---|
755 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXGAIN_RF, 2); |
---|
756 | radio_controller_setRadioParam(RC_BASEADDR, RC_ALL_RF, RC_PARAMID_RXGAIN_BB, 8); |
---|
757 | #endif |
---|
758 | |
---|
759 | return WLAN_SUCCESS; |
---|
760 | } |
---|
761 | |
---|
762 | |
---|
763 | |
---|
764 | /*****************************************************************************/ |
---|
765 | /** |
---|
766 | * @brief Map the WLAN channel frequencies onto the convention used by the radio controller |
---|
767 | */ |
---|
768 | inline u32 w3_wlan_chan_to_rc_chan(u32 mac_channel) { |
---|
769 | int return_value = 0; |
---|
770 | |
---|
771 | switch(mac_channel){ |
---|
772 | // 2.4GHz channels |
---|
773 | case 1: |
---|
774 | case 2: |
---|
775 | case 3: |
---|
776 | case 4: |
---|
777 | case 5: |
---|
778 | case 6: |
---|
779 | case 7: |
---|
780 | case 8: |
---|
781 | case 9: |
---|
782 | case 10: |
---|
783 | case 11: |
---|
784 | return_value = mac_channel; |
---|
785 | break; |
---|
786 | |
---|
787 | // 5GHz channels |
---|
788 | case 36: // 5180 MHz |
---|
789 | return_value = 1; |
---|
790 | break; |
---|
791 | case 38: // 5190 MHz |
---|
792 | return_value = 2; |
---|
793 | break; |
---|
794 | case 40: // 5200 MHz |
---|
795 | return_value = 3; |
---|
796 | break; |
---|
797 | case 44: // 5220 MHz |
---|
798 | return_value = 4; |
---|
799 | break; |
---|
800 | case 46: // 5230 MHz |
---|
801 | return_value = 5; |
---|
802 | break; |
---|
803 | case 48: // 5240 MHz |
---|
804 | return_value = 6; |
---|
805 | break; |
---|
806 | #if 0 // Disable these channels by default |
---|
807 | case 52: // 5260 MHz |
---|
808 | return_value = 7; |
---|
809 | break; |
---|
810 | case 54: // 5270 MHz |
---|
811 | return_value = 8; |
---|
812 | break; |
---|
813 | case 56: // 5280 MHz |
---|
814 | return_value = 9; |
---|
815 | break; |
---|
816 | case 60: // 5300 MHz |
---|
817 | return_value = 10; |
---|
818 | break; |
---|
819 | case 62: // 5310 MHz |
---|
820 | return_value = 11; |
---|
821 | break; |
---|
822 | case 64: // 5320 MHz |
---|
823 | return_value = 12; |
---|
824 | break; |
---|
825 | case 100: // 5500 MHz |
---|
826 | return_value = 13; |
---|
827 | break; |
---|
828 | case 102: // 5510 MHz |
---|
829 | return_value = 14; |
---|
830 | break; |
---|
831 | case 104: // 5520 MHz |
---|
832 | return_value = 15; |
---|
833 | break; |
---|
834 | case 108: // 5540 MHz |
---|
835 | return_value = 16; |
---|
836 | break; |
---|
837 | case 110: // 5550 MHz |
---|
838 | return_value = 17; |
---|
839 | break; |
---|
840 | case 112: // 5560 MHz |
---|
841 | return_value = 18; |
---|
842 | break; |
---|
843 | case 116: // 5580 MHz |
---|
844 | return_value = 19; |
---|
845 | break; |
---|
846 | case 118: // 5590 MHz |
---|
847 | return_value = 20; |
---|
848 | break; |
---|
849 | case 120: // 5600 MHz |
---|
850 | return_value = 21; |
---|
851 | break; |
---|
852 | case 124: // 5620 MHz |
---|
853 | return_value = 22; |
---|
854 | break; |
---|
855 | case 126: // 5630 MHz |
---|
856 | return_value = 23; |
---|
857 | break; |
---|
858 | case 128: // 5640 MHz |
---|
859 | return_value = 24; |
---|
860 | break; |
---|
861 | case 132: // 5660 MHz |
---|
862 | return_value = 25; |
---|
863 | break; |
---|
864 | case 134: // 5670 MHz |
---|
865 | return_value = 26; |
---|
866 | break; |
---|
867 | case 136: // 5680 MHz |
---|
868 | return_value = 27; |
---|
869 | break; |
---|
870 | case 140: // 5700 MHz |
---|
871 | return_value = 28; |
---|
872 | break; |
---|
873 | case 142: // 5710 MHz |
---|
874 | return_value = 29; |
---|
875 | break; |
---|
876 | case 144: // 5720 MHz |
---|
877 | return_value = 30; |
---|
878 | break; |
---|
879 | case 149: // 5745 MHz |
---|
880 | return_value = 31; |
---|
881 | break; |
---|
882 | case 151: // 5755 MHz |
---|
883 | return_value = 32; |
---|
884 | break; |
---|
885 | case 153: // 5765 MHz |
---|
886 | return_value = 33; |
---|
887 | break; |
---|
888 | case 157: // 5785 MHz |
---|
889 | return_value = 34; |
---|
890 | break; |
---|
891 | case 159: // 5795 MHz |
---|
892 | return_value = 35; |
---|
893 | break; |
---|
894 | case 161: // 5805 MHz |
---|
895 | return_value = 36; |
---|
896 | break; |
---|
897 | case 165: // 5825 MHz |
---|
898 | return_value = 37; |
---|
899 | break; |
---|
900 | case 172: // 5860 MHz |
---|
901 | return_value = 38; |
---|
902 | break; |
---|
903 | case 174: // 5870 MHz |
---|
904 | return_value = 39; |
---|
905 | break; |
---|
906 | case 175: // 5875 MHz |
---|
907 | return_value = 40; |
---|
908 | break; |
---|
909 | case 176: // 5880 MHz |
---|
910 | return_value = 41; |
---|
911 | break; |
---|
912 | case 177: // 5885 MHz |
---|
913 | return_value = 42; |
---|
914 | break; |
---|
915 | case 178: // 5890 MHz |
---|
916 | return_value = 43; |
---|
917 | break; |
---|
918 | #endif |
---|
919 | } |
---|
920 | |
---|
921 | return return_value; |
---|
922 | } |
---|
923 | |
---|
924 | |
---|
925 | /*****************************************************************************/ |
---|
926 | /** |
---|
927 | * @brief Calculates Rx Power (in dBm) |
---|
928 | * |
---|
929 | * This function calculates receive power for a given band, RSSI and LNA gain. This |
---|
930 | * provides a reasonable estimate of Rx power, accurate to a few dB for standard waveforms. |
---|
931 | * |
---|
932 | * This function does not use the VGA gain setting or I/Q magnitudes. The PHY should use these |
---|
933 | * to refine its own power measurement if needed. |
---|
934 | * |
---|
935 | * NOTE: These lookup tables were developed as part of the RF characterization. See: |
---|
936 | * http://warpproject.org/trac/wiki/802.11/Benchmarks/Rx_Char |
---|
937 | * |
---|
938 | * |
---|
939 | * @param rssi - RSSI value from RF frontend |
---|
940 | * @param lna_gain - Value of LNA gain stage in RF frontend |
---|
941 | * @return int - Power in dBm |
---|
942 | */ |
---|
943 | static const s8 pow_lookup_B24[128] = {-90, -90, -89, -88, -88, -87, -87, -86, -86, -85, -84, -84, -83, -83, -82, -82, |
---|
944 | -81, -81, -80, -79, -79, -78, -78, -77, -77, -76, -75, -75, -74, -74, -73, -73, |
---|
945 | -72, -72, -71, -70, -70, -69, -69, -68, -68, -67, -66, -66, -65, -65, -64, -64, |
---|
946 | -63, -63, -62, -61, -61, -60, -60, -59, -59, -58, -58, -57, -56, -56, -55, -55, |
---|
947 | -54, -54, -53, -52, -52, -51, -51, -50, -50, -49, -49, -48, -47, -47, -46, -46, |
---|
948 | -45, -45, -44, -43, -43, -42, -42, -41, -41, -40, -40, -39, -38, -38, -37, -37, |
---|
949 | -36, -36, -35, -34, -34, -33, -33, -32, -32, -31, -31, -30, -29, -29, -28, -28, |
---|
950 | -27, -27, -26, -26, -25, -24, -24, -23, -23, -22, -22, -21, -20, -20, -19, -19}; |
---|
951 | |
---|
952 | static const s8 pow_lookup_B5[128] = {-97, -97, -96, -96, -95, -94, -94, -93, -93, -92, -92, -91, -90, -90, -89, -89, |
---|
953 | -88, -88, -87, -87, -86, -85, -85, -84, -84, -83, -83, -82, -81, -81, -80, -80, |
---|
954 | -79, -79, -78, -78, -77, -76, -76, -75, -75, -74, -74, -73, -72, -72, -71, -71, |
---|
955 | -70, -70, -69, -69, -68, -67, -67, -66, -66, -65, -65, -64, -63, -63, -62, -62, |
---|
956 | -61, -61, -60, -60, -59, -58, -58, -57, -57, -56, -56, -55, -54, -54, -53, -53, |
---|
957 | -52, -52, -51, -51, -50, -49, -49, -48, -48, -47, -47, -46, -45, -45, -44, -44, |
---|
958 | -43, -43, -42, -42, -41, -40, -40, -39, -39, -38, -38, -37, -36, -36, -35, -35, |
---|
959 | -34, -34, -33, -32, -32, -31, -31, -30, -30, -29, -29, -28, -27, -27, -26, -26}; |
---|
960 | |
---|
961 | |
---|
962 | inline int w3_rssi_to_rx_power(u16 rssi, u8 lna_gain, channel_band_t band) { |
---|
963 | |
---|
964 | int power = -100; |
---|
965 | u16 adj_rssi = 0; |
---|
966 | |
---|
967 | if(band == BAND_24GHZ) { |
---|
968 | switch(lna_gain) { |
---|
969 | case 0: |
---|
970 | case 1: |
---|
971 | // Low LNA Gain State |
---|
972 | adj_rssi = rssi + (440 << PHY_RX_RSSI_SUM_LEN_BITS); |
---|
973 | break; |
---|
974 | |
---|
975 | case 2: |
---|
976 | // Medium LNA Gain State |
---|
977 | adj_rssi = rssi + (220 << PHY_RX_RSSI_SUM_LEN_BITS); |
---|
978 | break; |
---|
979 | |
---|
980 | case 3: |
---|
981 | // High LNA Gain State |
---|
982 | adj_rssi = rssi; |
---|
983 | break; |
---|
984 | } |
---|
985 | |
---|
986 | power = pow_lookup_B24[(adj_rssi >> (PHY_RX_RSSI_SUM_LEN_BITS+POW_LOOKUP_SHIFT))]; |
---|
987 | |
---|
988 | } else if(band == BAND_5GHZ) { |
---|
989 | switch(lna_gain){ |
---|
990 | case 0: |
---|
991 | case 1: |
---|
992 | // Low LNA Gain State |
---|
993 | adj_rssi = rssi + (540 << PHY_RX_RSSI_SUM_LEN_BITS); |
---|
994 | break; |
---|
995 | |
---|
996 | case 2: |
---|
997 | // Medium LNA Gain State |
---|
998 | adj_rssi = rssi + (280 << PHY_RX_RSSI_SUM_LEN_BITS); |
---|
999 | break; |
---|
1000 | |
---|
1001 | case 3: |
---|
1002 | // High LNA Gain State |
---|
1003 | adj_rssi = rssi; |
---|
1004 | break; |
---|
1005 | } |
---|
1006 | |
---|
1007 | power = pow_lookup_B5[(adj_rssi >> (PHY_RX_RSSI_SUM_LEN_BITS+POW_LOOKUP_SHIFT))]; |
---|
1008 | } |
---|
1009 | |
---|
1010 | return power; |
---|
1011 | } |
---|
1012 | |
---|
1013 | |
---|
1014 | |
---|
1015 | /*****************************************************************************/ |
---|
1016 | /** |
---|
1017 | * @brief Calculates RSSI from Rx power (in dBm) |
---|
1018 | * |
---|
1019 | * This function calculates receive power for a given band, RSSI and LNA gain. This |
---|
1020 | * provides a reasonable estimate of Rx power, accurate to a few dB for standard waveforms. |
---|
1021 | * |
---|
1022 | * This function does not use the VGA gain setting or I/Q magnitudes. The PHY should use these |
---|
1023 | * to refine its own power measurement if needed. |
---|
1024 | * |
---|
1025 | * NOTE: These lookup tables were developed as part of the RF characterization. See: |
---|
1026 | * http://warpproject.org/trac/wiki/802.11/Benchmarks/Rx_Char |
---|
1027 | * |
---|
1028 | * |
---|
1029 | * @param rx_pow - Receive power in dBm |
---|
1030 | * @return u16 - RSSI value |
---|
1031 | * |
---|
1032 | * @note rx_pow must be in the range [PKT_DET_MIN_POWER_MIN, PKT_DET_MIN_POWER_MAX] inclusive |
---|
1033 | */ |
---|
1034 | static const u16 rssi_lookup_B24[61] = { 1, 16, 24, 40, 56, 72, 80, 96, 112, 128, 144, 152, 168, 184, 200, 208, |
---|
1035 | 224, 240, 256, 272, 280, 296, 312, 328, 336, 352, 368, 384, 400, 408, 424, 440, |
---|
1036 | 456, 472, 480, 496, 512, 528, 536, 552, 568, 584, 600, 608, 624, 640, 656, 664, |
---|
1037 | 680, 696, 712, 728, 736, 752, 768, 784, 792, 808, 824, 840, 856}; |
---|
1038 | |
---|
1039 | static const u16 rssi_lookup_B5[61] = { 96, 112, 128, 144, 160, 168, 184, 200, 216, 224, 240, 256, 272, 288, 296, 312, |
---|
1040 | 328, 344, 352, 368, 384, 400, 416, 424, 440, 456, 472, 480, 496, 512, 528, 544, |
---|
1041 | 552, 568, 584, 600, 608, 624, 640, 656, 672, 680, 696, 712, 728, 736, 752, 768, |
---|
1042 | 784, 800, 808, 824, 840, 856, 864, 880, 896, 912, 920, 936, 952}; |
---|
1043 | |
---|
1044 | |
---|
1045 | int w3_rx_power_to_rssi(s8 rx_pow, channel_band_t band) { |
---|
1046 | u16 rssi_val = 0; |
---|
1047 | |
---|
1048 | if ((rx_pow <= PKT_DET_MIN_POWER_MAX) && (rx_pow >= PKT_DET_MIN_POWER_MIN)) { |
---|
1049 | if(band == BAND_24GHZ){ |
---|
1050 | rssi_val = rssi_lookup_B24[rx_pow-PKT_DET_MIN_POWER_MIN]; |
---|
1051 | } else if(band == BAND_5GHZ){ |
---|
1052 | rssi_val = rssi_lookup_B5[rx_pow-PKT_DET_MIN_POWER_MIN]; |
---|
1053 | } |
---|
1054 | |
---|
1055 | return rssi_val; |
---|
1056 | |
---|
1057 | } else { |
---|
1058 | return WLAN_FAILURE; |
---|
1059 | } |
---|
1060 | } |
---|
1061 | |
---|
1062 | int wlan_platform_get_rx_pkt_pwr(u8 ant) { |
---|
1063 | u16 rssi; |
---|
1064 | u8 lna_gain; |
---|
1065 | int pwr; |
---|
1066 | |
---|
1067 | rssi = wlan_phy_rx_get_pkt_rssi(ant); |
---|
1068 | lna_gain = wlan_phy_rx_get_agc_RFG(ant); |
---|
1069 | pwr = w3_rssi_to_rx_power(rssi, lna_gain, gl_current_band); |
---|
1070 | |
---|
1071 | return pwr; |
---|
1072 | } |
---|
1073 | |
---|
1074 | void wlan_platform_enable_phy_cs(u8 enable) { |
---|
1075 | |
---|
1076 | gl_enable_phy_cs = enable; |
---|
1077 | |
---|
1078 | if(gl_enable_phy_cs == 0) { |
---|
1079 | // Disable physical CS |
---|
1080 | wlan_phy_rx_set_cca_thresh(0xFFFF); |
---|
1081 | return; |
---|
1082 | } |
---|
1083 | |
---|
1084 | wlan_phy_rx_set_cca_thresh(PHY_RX_RSSI_SUM_LEN * w3_rx_power_to_rssi(-62, gl_current_band)); |
---|
1085 | |
---|
1086 | return; |
---|
1087 | } |
---|
1088 | |
---|
1089 | /*****************************************************************************/ |
---|
1090 | /** |
---|
1091 | * @brief Set the minimum power for packet detection |
---|
1092 | * |
---|
1093 | * @param rx_pow - Receive power in dBm |
---|
1094 | * @return int - Status: 0 - Success; -1 - Failure |
---|
1095 | */ |
---|
1096 | int wlan_platform_set_pkt_det_min_power(int min_power) { |
---|
1097 | int rssi_val; |
---|
1098 | |
---|
1099 | if(min_power == 0) { |
---|
1100 | // 0 disables the min-power logic |
---|
1101 | wlan_phy_disable_req_both_pkt_det(); |
---|
1102 | return WLAN_SUCCESS; |
---|
1103 | |
---|
1104 | } else { |
---|
1105 | wlan_phy_enable_req_both_pkt_det(); |
---|
1106 | rssi_val = w3_rx_power_to_rssi(min_power, gl_current_band); |
---|
1107 | |
---|
1108 | if(rssi_val != -1) { |
---|
1109 | wlan_phy_rx_pktDet_RSSI_cfg( (PHY_RX_RSSI_SUM_LEN-1), (rssi_val << PHY_RX_RSSI_SUM_LEN_BITS), 1); |
---|
1110 | |
---|
1111 | return 0; |
---|
1112 | } else { |
---|
1113 | xil_printf("wlan_platform_set_pkt_det_min_power: invalid min_power argument: %d\n", min_power); |
---|
1114 | return WLAN_FAILURE; |
---|
1115 | } |
---|
1116 | } |
---|
1117 | } |
---|
1118 | |
---|
1119 | int wlan_platform_get_rx_pkt_gain(u8 ant) { |
---|
1120 | u8 bb_gain; |
---|
1121 | u8 rf_gain; |
---|
1122 | |
---|
1123 | switch(ant) { |
---|
1124 | case 0: // RF A |
---|
1125 | bb_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 0) & 0x1F; |
---|
1126 | rf_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 5) & 0x03; |
---|
1127 | break; |
---|
1128 | case 1: // RF B |
---|
1129 | bb_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 8) & 0x1F; |
---|
1130 | rf_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 13) & 0x03; |
---|
1131 | break; |
---|
1132 | case 2: // RF C |
---|
1133 | bb_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 16) & 0x1F; |
---|
1134 | rf_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 21) & 0x03; |
---|
1135 | break; |
---|
1136 | case 3: // RF D |
---|
1137 | bb_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 24) & 0x1F; |
---|
1138 | rf_gain = (Xil_In32(WLAN_RX_PKT_AGC_GAINS) >> 29) & 0x03; |
---|
1139 | break; |
---|
1140 | default: |
---|
1141 | xil_printf("wlan_platform_get_rx_pkt_gain: invalid antenna ID: %d\n", ant); |
---|
1142 | return WLAN_FAILURE; |
---|
1143 | break; |
---|
1144 | } |
---|
1145 | |
---|
1146 | // For MAX2829 RF interface construct 8-bit gain_index value as: |
---|
1147 | // [ 8]: 0 |
---|
1148 | // [6:5]: RF gain index (0, 1, 2) |
---|
1149 | // [4:0]: BB gain index (0, 1, ..., 31) |
---|
1150 | return ((rf_gain << 5) | bb_gain); |
---|
1151 | } |
---|
1152 | |
---|
1153 | |
---|
1154 | |
---|
1155 | |
---|
1156 | int wlan_platform_set_radio_tx_power(s8 power) { |
---|
1157 | // Empty function for WARP v3 - all Tx powers are configured per-packet via |
---|
1158 | // tx_frame_info and the mac_hw core driving the radio_controller's Tx gain pins |
---|
1159 | |
---|
1160 | return WLAN_SUCCESS; |
---|
1161 | } |
---|
1162 | |
---|
1163 | /*****************************************************************************/ |
---|
1164 | /** |
---|
1165 | * @brief Convert dBm to Tx Gain Target |
---|
1166 | * |
---|
1167 | * This function maps a transmit power (in dBm) to a radio gain target. |
---|
1168 | * |
---|
1169 | * @param s8 power - Power in dBm |
---|
1170 | * @return u32 gain_target - Tx attenuation (in dB) |
---|
1171 | */ |
---|
1172 | inline u32 wlan_platform_tx_power_to_gain_target(s8 power){ |
---|
1173 | s8 power_railed; |
---|
1174 | u32 return_value; |
---|
1175 | |
---|
1176 | if(power > TX_POWER_MAX_DBM){ |
---|
1177 | power_railed = TX_POWER_MAX_DBM; |
---|
1178 | } else if( power < TX_POWER_MIN_DBM){ |
---|
1179 | power_railed = TX_POWER_MIN_DBM; |
---|
1180 | } else { |
---|
1181 | power_railed = power; |
---|
1182 | } |
---|
1183 | |
---|
1184 | // This is only safe because 'power' is constrained to less than half the dynamic range of an s8 type |
---|
1185 | return_value = (u32)((power_railed << 1) + 20); |
---|
1186 | |
---|
1187 | return return_value; |
---|
1188 | } |
---|
1189 | |
---|
1190 | |
---|