staging: brcm80211: fix 'ERROR: "foo * bar" should be "foo *bar"'
[linux-2.6/libata-dev.git] / drivers / staging / brcm80211 / phy / wlc_phy_lcn.c
blobc8eee3915818fcb9b85ac89ca800ce543d8d6a9c
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <wlc_cfg.h>
18 #include <qmath.h>
19 #include <osl.h>
20 #include <siutils.h>
21 #include <bitfuncs.h>
22 #include <hndpmu.h>
24 #include <wlc_phy_radio.h>
25 #include <wlc_phy_int.h>
26 #include <wlc_phy_lcn.h>
27 #include <wlc_phytbl_lcn.h>
29 #define PLL_2064_NDIV 90
30 #define PLL_2064_LOW_END_VCO 3000
31 #define PLL_2064_LOW_END_KVCO 27
32 #define PLL_2064_HIGH_END_VCO 4200
33 #define PLL_2064_HIGH_END_KVCO 68
34 #define PLL_2064_LOOP_BW_DOUBLER 200
35 #define PLL_2064_D30_DOUBLER 10500
36 #define PLL_2064_LOOP_BW 260
37 #define PLL_2064_D30 8000
38 #define PLL_2064_CAL_REF_TO 8
39 #define PLL_2064_MHZ 1000000
40 #define PLL_2064_OPEN_LOOP_DELAY 5
42 #define TEMPSENSE 1
43 #define VBATSENSE 2
45 #define NOISE_IF_UPD_CHK_INTERVAL 1
46 #define NOISE_IF_UPD_RST_INTERVAL 60
47 #define NOISE_IF_UPD_THRESHOLD_CNT 1
48 #define NOISE_IF_UPD_TRHRESHOLD 50
49 #define NOISE_IF_UPD_TIMEOUT 1000
50 #define NOISE_IF_OFF 0
51 #define NOISE_IF_CHK 1
52 #define NOISE_IF_ON 2
54 #define PAPD_BLANKING_PROFILE 3
55 #define PAPD2LUT 0
56 #define PAPD_CORR_NORM 0
57 #define PAPD_BLANKING_THRESHOLD 0
58 #define PAPD_STOP_AFTER_LAST_UPDATE 0
60 #define LCN_TARGET_PWR 60
62 #define LCN_VBAT_OFFSET_433X 34649679
63 #define LCN_VBAT_SLOPE_433X 8258032
65 #define LCN_VBAT_SCALE_NOM 53
66 #define LCN_VBAT_SCALE_DEN 432
68 #define LCN_TEMPSENSE_OFFSET 80812
69 #define LCN_TEMPSENSE_DEN 2647
71 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
72 (0 + 8)
73 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
74 (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
76 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
77 (0 + 8)
78 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
79 (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
81 #define wlc_lcnphy_enable_tx_gain_override(pi) \
82 wlc_lcnphy_set_tx_gain_override(pi, TRUE)
83 #define wlc_lcnphy_disable_tx_gain_override(pi) \
84 wlc_lcnphy_set_tx_gain_override(pi, FALSE)
86 #define wlc_lcnphy_iqcal_active(pi) \
87 (read_phy_reg((pi), 0x451) & \
88 ((0x1 << 15) | (0x1 << 14)))
90 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
91 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
92 (pi->temppwrctrl_capable)
93 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
94 (pi->hwpwrctrl_capable)
96 #define SWCTRL_BT_TX 0x18
97 #define SWCTRL_OVR_DISABLE 0x40
99 #define AFE_CLK_INIT_MODE_TXRX2X 1
100 #define AFE_CLK_INIT_MODE_PAPD 0
102 #define LCNPHY_TBL_ID_IQLOCAL 0x00
104 #define LCNPHY_TBL_ID_RFSEQ 0x08
105 #define LCNPHY_TBL_ID_GAIN_IDX 0x0d
106 #define LCNPHY_TBL_ID_SW_CTRL 0x0f
107 #define LCNPHY_TBL_ID_GAIN_TBL 0x12
108 #define LCNPHY_TBL_ID_SPUR 0x14
109 #define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
110 #define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
112 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
113 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
114 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
115 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
116 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
117 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
119 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
121 #define LCNPHY_TX_PWR_CTRL_START_NPT 1
122 #define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
124 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
126 #define LCNPHY_ACI_DETECT_START 1
127 #define LCNPHY_ACI_DETECT_PROGRESS 2
128 #define LCNPHY_ACI_DETECT_STOP 3
130 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
131 #define LCNPHY_ACI_GLITCH_TRSH 2000
132 #define LCNPHY_ACI_TMOUT 250
133 #define LCNPHY_ACI_DETECT_TIMEOUT 2
134 #define LCNPHY_ACI_START_DELAY 0
136 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
137 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
139 #define wlc_lcnphy_total_tx_frames(pi) \
140 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + OFFSETOF(macstat_t, txallfrm))
142 typedef struct {
143 uint16 gm_gain;
144 uint16 pga_gain;
145 uint16 pad_gain;
146 uint16 dac_gain;
147 } lcnphy_txgains_t;
149 typedef enum {
150 LCNPHY_CAL_FULL,
151 LCNPHY_CAL_RECAL,
152 LCNPHY_CAL_CURRECAL,
153 LCNPHY_CAL_DIGCAL,
154 LCNPHY_CAL_GCTRL
155 } lcnphy_cal_mode_t;
157 typedef struct {
158 lcnphy_txgains_t gains;
159 bool useindex;
160 uint8 index;
161 } lcnphy_txcalgains_t;
163 typedef struct {
164 uint8 chan;
165 int16 a;
166 int16 b;
167 } lcnphy_rx_iqcomp_t;
169 typedef struct {
170 int16 re;
171 int16 im;
172 } lcnphy_spb_tone_t;
174 typedef struct {
175 uint16 re;
176 uint16 im;
177 } lcnphy_unsign16_struct;
179 typedef struct {
180 uint32 iq_prod;
181 uint32 i_pwr;
182 uint32 q_pwr;
183 } lcnphy_iq_est_t;
185 typedef struct {
186 uint16 ptcentreTs20;
187 uint16 ptcentreFactor;
188 } lcnphy_sfo_cfg_t;
190 typedef enum {
191 LCNPHY_PAPD_CAL_CW,
192 LCNPHY_PAPD_CAL_OFDM
193 } lcnphy_papd_cal_type_t;
195 typedef uint16 iqcal_gain_params_lcnphy[9];
197 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
198 {0, 0, 0, 0, 0, 0, 0, 0, 0},
201 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
202 tbl_iqcal_gainparams_lcnphy_2G,
205 static const uint16 iqcal_gainparams_numgains_lcnphy[1] = {
206 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
207 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
210 static const lcnphy_sfo_cfg_t lcnphy_sfo_cfg[] = {
211 {965, 1087},
212 {967, 1085},
213 {969, 1082},
214 {971, 1080},
215 {973, 1078},
216 {975, 1076},
217 {977, 1073},
218 {979, 1071},
219 {981, 1069},
220 {983, 1067},
221 {985, 1065},
222 {987, 1063},
223 {989, 1060},
224 {994, 1055}
227 static const
228 uint16 lcnphy_iqcal_loft_gainladder[] = {
229 ((2 << 8) | 0),
230 ((3 << 8) | 0),
231 ((4 << 8) | 0),
232 ((6 << 8) | 0),
233 ((8 << 8) | 0),
234 ((11 << 8) | 0),
235 ((16 << 8) | 0),
236 ((16 << 8) | 1),
237 ((16 << 8) | 2),
238 ((16 << 8) | 3),
239 ((16 << 8) | 4),
240 ((16 << 8) | 5),
241 ((16 << 8) | 6),
242 ((16 << 8) | 7),
243 ((23 << 8) | 7),
244 ((32 << 8) | 7),
245 ((45 << 8) | 7),
246 ((64 << 8) | 7),
247 ((91 << 8) | 7),
248 ((128 << 8) | 7)
251 static const
252 uint16 lcnphy_iqcal_ir_gainladder[] = {
253 ((1 << 8) | 0),
254 ((2 << 8) | 0),
255 ((4 << 8) | 0),
256 ((6 << 8) | 0),
257 ((8 << 8) | 0),
258 ((11 << 8) | 0),
259 ((16 << 8) | 0),
260 ((23 << 8) | 0),
261 ((32 << 8) | 0),
262 ((45 << 8) | 0),
263 ((64 << 8) | 0),
264 ((64 << 8) | 1),
265 ((64 << 8) | 2),
266 ((64 << 8) | 3),
267 ((64 << 8) | 4),
268 ((64 << 8) | 5),
269 ((64 << 8) | 6),
270 ((64 << 8) | 7),
271 ((91 << 8) | 7),
272 ((128 << 8) | 7)
275 static const
276 lcnphy_spb_tone_t lcnphy_spb_tone_3750[] = {
277 {88, 0},
278 {73, 49},
279 {34, 81},
280 {-17, 86},
281 {-62, 62},
282 {-86, 17},
283 {-81, -34},
284 {-49, -73},
285 {0, -88},
286 {49, -73},
287 {81, -34},
288 {86, 17},
289 {62, 62},
290 {17, 86},
291 {-34, 81},
292 {-73, 49},
293 {-88, 0},
294 {-73, -49},
295 {-34, -81},
296 {17, -86},
297 {62, -62},
298 {86, -17},
299 {81, 34},
300 {49, 73},
301 {0, 88},
302 {-49, 73},
303 {-81, 34},
304 {-86, -17},
305 {-62, -62},
306 {-17, -86},
307 {34, -81},
308 {73, -49},
311 static const
312 uint16 iqlo_loopback_rf_regs[20] = {
313 RADIO_2064_REG036,
314 RADIO_2064_REG11A,
315 RADIO_2064_REG03A,
316 RADIO_2064_REG025,
317 RADIO_2064_REG028,
318 RADIO_2064_REG005,
319 RADIO_2064_REG112,
320 RADIO_2064_REG0FF,
321 RADIO_2064_REG11F,
322 RADIO_2064_REG00B,
323 RADIO_2064_REG113,
324 RADIO_2064_REG007,
325 RADIO_2064_REG0FC,
326 RADIO_2064_REG0FD,
327 RADIO_2064_REG012,
328 RADIO_2064_REG057,
329 RADIO_2064_REG059,
330 RADIO_2064_REG05C,
331 RADIO_2064_REG078,
332 RADIO_2064_REG092,
335 static const
336 uint16 tempsense_phy_regs[14] = {
337 0x503,
338 0x4a4,
339 0x4d0,
340 0x4d9,
341 0x4da,
342 0x4a6,
343 0x938,
344 0x939,
345 0x4d8,
346 0x4d0,
347 0x4d7,
348 0x4a5,
349 0x40d,
350 0x4a2,
353 static const
354 uint16 rxiq_cal_rf_reg[11] = {
355 RADIO_2064_REG098,
356 RADIO_2064_REG116,
357 RADIO_2064_REG12C,
358 RADIO_2064_REG06A,
359 RADIO_2064_REG00B,
360 RADIO_2064_REG01B,
361 RADIO_2064_REG113,
362 RADIO_2064_REG01D,
363 RADIO_2064_REG114,
364 RADIO_2064_REG02E,
365 RADIO_2064_REG12A,
368 static const
369 lcnphy_rx_iqcomp_t lcnphy_rx_iqcomp_table_rev0[] = {
370 {1, 0, 0},
371 {2, 0, 0},
372 {3, 0, 0},
373 {4, 0, 0},
374 {5, 0, 0},
375 {6, 0, 0},
376 {7, 0, 0},
377 {8, 0, 0},
378 {9, 0, 0},
379 {10, 0, 0},
380 {11, 0, 0},
381 {12, 0, 0},
382 {13, 0, 0},
383 {14, 0, 0},
384 {34, 0, 0},
385 {38, 0, 0},
386 {42, 0, 0},
387 {46, 0, 0},
388 {36, 0, 0},
389 {40, 0, 0},
390 {44, 0, 0},
391 {48, 0, 0},
392 {52, 0, 0},
393 {56, 0, 0},
394 {60, 0, 0},
395 {64, 0, 0},
396 {100, 0, 0},
397 {104, 0, 0},
398 {108, 0, 0},
399 {112, 0, 0},
400 {116, 0, 0},
401 {120, 0, 0},
402 {124, 0, 0},
403 {128, 0, 0},
404 {132, 0, 0},
405 {136, 0, 0},
406 {140, 0, 0},
407 {149, 0, 0},
408 {153, 0, 0},
409 {157, 0, 0},
410 {161, 0, 0},
411 {165, 0, 0},
412 {184, 0, 0},
413 {188, 0, 0},
414 {192, 0, 0},
415 {196, 0, 0},
416 {200, 0, 0},
417 {204, 0, 0},
418 {208, 0, 0},
419 {212, 0, 0},
420 {216, 0, 0},
423 static const uint32 lcnphy_23bitgaincode_table[] = {
424 0x200100,
425 0x200200,
426 0x200004,
427 0x200014,
428 0x200024,
429 0x200034,
430 0x200134,
431 0x200234,
432 0x200334,
433 0x200434,
434 0x200037,
435 0x200137,
436 0x200237,
437 0x200337,
438 0x200437,
439 0x000035,
440 0x000135,
441 0x000235,
442 0x000037,
443 0x000137,
444 0x000237,
445 0x000337,
446 0x00013f,
447 0x00023f,
448 0x00033f,
449 0x00034f,
450 0x00044f,
451 0x00144f,
452 0x00244f,
453 0x00254f,
454 0x00354f,
455 0x00454f,
456 0x00464f,
457 0x01464f,
458 0x02464f,
459 0x03464f,
460 0x04464f,
463 static const int8 lcnphy_gain_table[] = {
464 -16,
465 -13,
503 static const int8 lcnphy_gain_index_offset_for_rssi[] = {
544 extern CONST uint8 spur_tbl_rev0[];
545 extern CONST uint32 dot11lcnphytbl_rx_gain_info_sz_rev1;
546 extern CONST dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
547 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
548 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
550 typedef struct _chan_info_2064_lcnphy {
551 uint chan;
552 uint freq;
553 uint8 logen_buftune;
554 uint8 logen_rccr_tx;
555 uint8 txrf_mix_tune_ctrl;
556 uint8 pa_input_tune_g;
557 uint8 logen_rccr_rx;
558 uint8 pa_rxrf_lna1_freq_tune;
559 uint8 pa_rxrf_lna2_freq_tune;
560 uint8 rxrf_rxrf_spare1;
561 } chan_info_2064_lcnphy_t;
563 static chan_info_2064_lcnphy_t chan_info_2064_lcnphy[] = {
564 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
565 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
566 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
567 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
576 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
580 lcnphy_radio_regs_t lcnphy_radio_regs_2064[] = {
581 {0x00, 0, 0, 0, 0},
582 {0x01, 0x64, 0x64, 0, 0},
583 {0x02, 0x20, 0x20, 0, 0},
584 {0x03, 0x66, 0x66, 0, 0},
585 {0x04, 0xf8, 0xf8, 0, 0},
586 {0x05, 0, 0, 0, 0},
587 {0x06, 0x10, 0x10, 0, 0},
588 {0x07, 0, 0, 0, 0},
589 {0x08, 0, 0, 0, 0},
590 {0x09, 0, 0, 0, 0},
591 {0x0A, 0x37, 0x37, 0, 0},
592 {0x0B, 0x6, 0x6, 0, 0},
593 {0x0C, 0x55, 0x55, 0, 0},
594 {0x0D, 0x8b, 0x8b, 0, 0},
595 {0x0E, 0, 0, 0, 0},
596 {0x0F, 0x5, 0x5, 0, 0},
597 {0x10, 0, 0, 0, 0},
598 {0x11, 0xe, 0xe, 0, 0},
599 {0x12, 0, 0, 0, 0},
600 {0x13, 0xb, 0xb, 0, 0},
601 {0x14, 0x2, 0x2, 0, 0},
602 {0x15, 0x12, 0x12, 0, 0},
603 {0x16, 0x12, 0x12, 0, 0},
604 {0x17, 0xc, 0xc, 0, 0},
605 {0x18, 0xc, 0xc, 0, 0},
606 {0x19, 0xc, 0xc, 0, 0},
607 {0x1A, 0x8, 0x8, 0, 0},
608 {0x1B, 0x2, 0x2, 0, 0},
609 {0x1C, 0, 0, 0, 0},
610 {0x1D, 0x1, 0x1, 0, 0},
611 {0x1E, 0x12, 0x12, 0, 0},
612 {0x1F, 0x6e, 0x6e, 0, 0},
613 {0x20, 0x2, 0x2, 0, 0},
614 {0x21, 0x23, 0x23, 0, 0},
615 {0x22, 0x8, 0x8, 0, 0},
616 {0x23, 0, 0, 0, 0},
617 {0x24, 0, 0, 0, 0},
618 {0x25, 0xc, 0xc, 0, 0},
619 {0x26, 0x33, 0x33, 0, 0},
620 {0x27, 0x55, 0x55, 0, 0},
621 {0x28, 0, 0, 0, 0},
622 {0x29, 0x30, 0x30, 0, 0},
623 {0x2A, 0xb, 0xb, 0, 0},
624 {0x2B, 0x1b, 0x1b, 0, 0},
625 {0x2C, 0x3, 0x3, 0, 0},
626 {0x2D, 0x1b, 0x1b, 0, 0},
627 {0x2E, 0, 0, 0, 0},
628 {0x2F, 0x20, 0x20, 0, 0},
629 {0x30, 0xa, 0xa, 0, 0},
630 {0x31, 0, 0, 0, 0},
631 {0x32, 0x62, 0x62, 0, 0},
632 {0x33, 0x19, 0x19, 0, 0},
633 {0x34, 0x33, 0x33, 0, 0},
634 {0x35, 0x77, 0x77, 0, 0},
635 {0x36, 0, 0, 0, 0},
636 {0x37, 0x70, 0x70, 0, 0},
637 {0x38, 0x3, 0x3, 0, 0},
638 {0x39, 0xf, 0xf, 0, 0},
639 {0x3A, 0x6, 0x6, 0, 0},
640 {0x3B, 0xcf, 0xcf, 0, 0},
641 {0x3C, 0x1a, 0x1a, 0, 0},
642 {0x3D, 0x6, 0x6, 0, 0},
643 {0x3E, 0x42, 0x42, 0, 0},
644 {0x3F, 0, 0, 0, 0},
645 {0x40, 0xfb, 0xfb, 0, 0},
646 {0x41, 0x9a, 0x9a, 0, 0},
647 {0x42, 0x7a, 0x7a, 0, 0},
648 {0x43, 0x29, 0x29, 0, 0},
649 {0x44, 0, 0, 0, 0},
650 {0x45, 0x8, 0x8, 0, 0},
651 {0x46, 0xce, 0xce, 0, 0},
652 {0x47, 0x27, 0x27, 0, 0},
653 {0x48, 0x62, 0x62, 0, 0},
654 {0x49, 0x6, 0x6, 0, 0},
655 {0x4A, 0x58, 0x58, 0, 0},
656 {0x4B, 0xf7, 0xf7, 0, 0},
657 {0x4C, 0, 0, 0, 0},
658 {0x4D, 0xb3, 0xb3, 0, 0},
659 {0x4E, 0, 0, 0, 0},
660 {0x4F, 0x2, 0x2, 0, 0},
661 {0x50, 0, 0, 0, 0},
662 {0x51, 0x9, 0x9, 0, 0},
663 {0x52, 0x5, 0x5, 0, 0},
664 {0x53, 0x17, 0x17, 0, 0},
665 {0x54, 0x38, 0x38, 0, 0},
666 {0x55, 0, 0, 0, 0},
667 {0x56, 0, 0, 0, 0},
668 {0x57, 0xb, 0xb, 0, 0},
669 {0x58, 0, 0, 0, 0},
670 {0x59, 0, 0, 0, 0},
671 {0x5A, 0, 0, 0, 0},
672 {0x5B, 0, 0, 0, 0},
673 {0x5C, 0, 0, 0, 0},
674 {0x5D, 0, 0, 0, 0},
675 {0x5E, 0x88, 0x88, 0, 0},
676 {0x5F, 0xcc, 0xcc, 0, 0},
677 {0x60, 0x74, 0x74, 0, 0},
678 {0x61, 0x74, 0x74, 0, 0},
679 {0x62, 0x74, 0x74, 0, 0},
680 {0x63, 0x44, 0x44, 0, 0},
681 {0x64, 0x77, 0x77, 0, 0},
682 {0x65, 0x44, 0x44, 0, 0},
683 {0x66, 0x77, 0x77, 0, 0},
684 {0x67, 0x55, 0x55, 0, 0},
685 {0x68, 0x77, 0x77, 0, 0},
686 {0x69, 0x77, 0x77, 0, 0},
687 {0x6A, 0, 0, 0, 0},
688 {0x6B, 0x7f, 0x7f, 0, 0},
689 {0x6C, 0x8, 0x8, 0, 0},
690 {0x6D, 0, 0, 0, 0},
691 {0x6E, 0x88, 0x88, 0, 0},
692 {0x6F, 0x66, 0x66, 0, 0},
693 {0x70, 0x66, 0x66, 0, 0},
694 {0x71, 0x28, 0x28, 0, 0},
695 {0x72, 0x55, 0x55, 0, 0},
696 {0x73, 0x4, 0x4, 0, 0},
697 {0x74, 0, 0, 0, 0},
698 {0x75, 0, 0, 0, 0},
699 {0x76, 0, 0, 0, 0},
700 {0x77, 0x1, 0x1, 0, 0},
701 {0x78, 0xd6, 0xd6, 0, 0},
702 {0x79, 0, 0, 0, 0},
703 {0x7A, 0, 0, 0, 0},
704 {0x7B, 0, 0, 0, 0},
705 {0x7C, 0, 0, 0, 0},
706 {0x7D, 0, 0, 0, 0},
707 {0x7E, 0, 0, 0, 0},
708 {0x7F, 0, 0, 0, 0},
709 {0x80, 0, 0, 0, 0},
710 {0x81, 0, 0, 0, 0},
711 {0x82, 0, 0, 0, 0},
712 {0x83, 0xb4, 0xb4, 0, 0},
713 {0x84, 0x1, 0x1, 0, 0},
714 {0x85, 0x20, 0x20, 0, 0},
715 {0x86, 0x5, 0x5, 0, 0},
716 {0x87, 0xff, 0xff, 0, 0},
717 {0x88, 0x7, 0x7, 0, 0},
718 {0x89, 0x77, 0x77, 0, 0},
719 {0x8A, 0x77, 0x77, 0, 0},
720 {0x8B, 0x77, 0x77, 0, 0},
721 {0x8C, 0x77, 0x77, 0, 0},
722 {0x8D, 0x8, 0x8, 0, 0},
723 {0x8E, 0xa, 0xa, 0, 0},
724 {0x8F, 0x8, 0x8, 0, 0},
725 {0x90, 0x18, 0x18, 0, 0},
726 {0x91, 0x5, 0x5, 0, 0},
727 {0x92, 0x1f, 0x1f, 0, 0},
728 {0x93, 0x10, 0x10, 0, 0},
729 {0x94, 0x3, 0x3, 0, 0},
730 {0x95, 0, 0, 0, 0},
731 {0x96, 0, 0, 0, 0},
732 {0x97, 0xaa, 0xaa, 0, 0},
733 {0x98, 0, 0, 0, 0},
734 {0x99, 0x23, 0x23, 0, 0},
735 {0x9A, 0x7, 0x7, 0, 0},
736 {0x9B, 0xf, 0xf, 0, 0},
737 {0x9C, 0x10, 0x10, 0, 0},
738 {0x9D, 0x3, 0x3, 0, 0},
739 {0x9E, 0x4, 0x4, 0, 0},
740 {0x9F, 0x20, 0x20, 0, 0},
741 {0xA0, 0, 0, 0, 0},
742 {0xA1, 0, 0, 0, 0},
743 {0xA2, 0, 0, 0, 0},
744 {0xA3, 0, 0, 0, 0},
745 {0xA4, 0x1, 0x1, 0, 0},
746 {0xA5, 0x77, 0x77, 0, 0},
747 {0xA6, 0x77, 0x77, 0, 0},
748 {0xA7, 0x77, 0x77, 0, 0},
749 {0xA8, 0x77, 0x77, 0, 0},
750 {0xA9, 0x8c, 0x8c, 0, 0},
751 {0xAA, 0x88, 0x88, 0, 0},
752 {0xAB, 0x78, 0x78, 0, 0},
753 {0xAC, 0x57, 0x57, 0, 0},
754 {0xAD, 0x88, 0x88, 0, 0},
755 {0xAE, 0, 0, 0, 0},
756 {0xAF, 0x8, 0x8, 0, 0},
757 {0xB0, 0x88, 0x88, 0, 0},
758 {0xB1, 0, 0, 0, 0},
759 {0xB2, 0x1b, 0x1b, 0, 0},
760 {0xB3, 0x3, 0x3, 0, 0},
761 {0xB4, 0x24, 0x24, 0, 0},
762 {0xB5, 0x3, 0x3, 0, 0},
763 {0xB6, 0x1b, 0x1b, 0, 0},
764 {0xB7, 0x24, 0x24, 0, 0},
765 {0xB8, 0x3, 0x3, 0, 0},
766 {0xB9, 0, 0, 0, 0},
767 {0xBA, 0xaa, 0xaa, 0, 0},
768 {0xBB, 0, 0, 0, 0},
769 {0xBC, 0x4, 0x4, 0, 0},
770 {0xBD, 0, 0, 0, 0},
771 {0xBE, 0x8, 0x8, 0, 0},
772 {0xBF, 0x11, 0x11, 0, 0},
773 {0xC0, 0, 0, 0, 0},
774 {0xC1, 0, 0, 0, 0},
775 {0xC2, 0x62, 0x62, 0, 0},
776 {0xC3, 0x1e, 0x1e, 0, 0},
777 {0xC4, 0x33, 0x33, 0, 0},
778 {0xC5, 0x37, 0x37, 0, 0},
779 {0xC6, 0, 0, 0, 0},
780 {0xC7, 0x70, 0x70, 0, 0},
781 {0xC8, 0x1e, 0x1e, 0, 0},
782 {0xC9, 0x6, 0x6, 0, 0},
783 {0xCA, 0x4, 0x4, 0, 0},
784 {0xCB, 0x2f, 0x2f, 0, 0},
785 {0xCC, 0xf, 0xf, 0, 0},
786 {0xCD, 0, 0, 0, 0},
787 {0xCE, 0xff, 0xff, 0, 0},
788 {0xCF, 0x8, 0x8, 0, 0},
789 {0xD0, 0x3f, 0x3f, 0, 0},
790 {0xD1, 0x3f, 0x3f, 0, 0},
791 {0xD2, 0x3f, 0x3f, 0, 0},
792 {0xD3, 0, 0, 0, 0},
793 {0xD4, 0, 0, 0, 0},
794 {0xD5, 0, 0, 0, 0},
795 {0xD6, 0xcc, 0xcc, 0, 0},
796 {0xD7, 0, 0, 0, 0},
797 {0xD8, 0x8, 0x8, 0, 0},
798 {0xD9, 0x8, 0x8, 0, 0},
799 {0xDA, 0x8, 0x8, 0, 0},
800 {0xDB, 0x11, 0x11, 0, 0},
801 {0xDC, 0, 0, 0, 0},
802 {0xDD, 0x87, 0x87, 0, 0},
803 {0xDE, 0x88, 0x88, 0, 0},
804 {0xDF, 0x8, 0x8, 0, 0},
805 {0xE0, 0x8, 0x8, 0, 0},
806 {0xE1, 0x8, 0x8, 0, 0},
807 {0xE2, 0, 0, 0, 0},
808 {0xE3, 0, 0, 0, 0},
809 {0xE4, 0, 0, 0, 0},
810 {0xE5, 0xf5, 0xf5, 0, 0},
811 {0xE6, 0x30, 0x30, 0, 0},
812 {0xE7, 0x1, 0x1, 0, 0},
813 {0xE8, 0, 0, 0, 0},
814 {0xE9, 0xff, 0xff, 0, 0},
815 {0xEA, 0, 0, 0, 0},
816 {0xEB, 0, 0, 0, 0},
817 {0xEC, 0x22, 0x22, 0, 0},
818 {0xED, 0, 0, 0, 0},
819 {0xEE, 0, 0, 0, 0},
820 {0xEF, 0, 0, 0, 0},
821 {0xF0, 0x3, 0x3, 0, 0},
822 {0xF1, 0x1, 0x1, 0, 0},
823 {0xF2, 0, 0, 0, 0},
824 {0xF3, 0, 0, 0, 0},
825 {0xF4, 0, 0, 0, 0},
826 {0xF5, 0, 0, 0, 0},
827 {0xF6, 0, 0, 0, 0},
828 {0xF7, 0x6, 0x6, 0, 0},
829 {0xF8, 0, 0, 0, 0},
830 {0xF9, 0, 0, 0, 0},
831 {0xFA, 0x40, 0x40, 0, 0},
832 {0xFB, 0, 0, 0, 0},
833 {0xFC, 0x1, 0x1, 0, 0},
834 {0xFD, 0x80, 0x80, 0, 0},
835 {0xFE, 0x2, 0x2, 0, 0},
836 {0xFF, 0x10, 0x10, 0, 0},
837 {0x100, 0x2, 0x2, 0, 0},
838 {0x101, 0x1e, 0x1e, 0, 0},
839 {0x102, 0x1e, 0x1e, 0, 0},
840 {0x103, 0, 0, 0, 0},
841 {0x104, 0x1f, 0x1f, 0, 0},
842 {0x105, 0, 0x8, 0, 1},
843 {0x106, 0x2a, 0x2a, 0, 0},
844 {0x107, 0xf, 0xf, 0, 0},
845 {0x108, 0, 0, 0, 0},
846 {0x109, 0, 0, 0, 0},
847 {0x10A, 0, 0, 0, 0},
848 {0x10B, 0, 0, 0, 0},
849 {0x10C, 0, 0, 0, 0},
850 {0x10D, 0, 0, 0, 0},
851 {0x10E, 0, 0, 0, 0},
852 {0x10F, 0, 0, 0, 0},
853 {0x110, 0, 0, 0, 0},
854 {0x111, 0, 0, 0, 0},
855 {0x112, 0, 0, 0, 0},
856 {0x113, 0, 0, 0, 0},
857 {0x114, 0, 0, 0, 0},
858 {0x115, 0, 0, 0, 0},
859 {0x116, 0, 0, 0, 0},
860 {0x117, 0, 0, 0, 0},
861 {0x118, 0, 0, 0, 0},
862 {0x119, 0, 0, 0, 0},
863 {0x11A, 0, 0, 0, 0},
864 {0x11B, 0, 0, 0, 0},
865 {0x11C, 0x1, 0x1, 0, 0},
866 {0x11D, 0, 0, 0, 0},
867 {0x11E, 0, 0, 0, 0},
868 {0x11F, 0, 0, 0, 0},
869 {0x120, 0, 0, 0, 0},
870 {0x121, 0, 0, 0, 0},
871 {0x122, 0x80, 0x80, 0, 0},
872 {0x123, 0, 0, 0, 0},
873 {0x124, 0xf8, 0xf8, 0, 0},
874 {0x125, 0, 0, 0, 0},
875 {0x126, 0, 0, 0, 0},
876 {0x127, 0, 0, 0, 0},
877 {0x128, 0, 0, 0, 0},
878 {0x129, 0, 0, 0, 0},
879 {0x12A, 0, 0, 0, 0},
880 {0x12B, 0, 0, 0, 0},
881 {0x12C, 0, 0, 0, 0},
882 {0x12D, 0, 0, 0, 0},
883 {0x12E, 0, 0, 0, 0},
884 {0x12F, 0, 0, 0, 0},
885 {0x130, 0, 0, 0, 0},
886 {0xFFFF, 0, 0, 0, 0}
889 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
890 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
892 uint16
893 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
894 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
895 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
896 128, 64,},
897 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
898 167, 93,},
899 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
900 128, 64,},
901 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
902 170, 340, 170,},
903 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
904 256, 185, 256,},
905 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
906 256, 273, 256,},
907 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
908 256, 352, 256,},
909 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
910 128, 233, 128,},
911 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
912 1881, 256,},
913 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
914 1881, 256,},
915 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
916 384, 288,},
917 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
918 128, 384, 288,},
919 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
920 170, 340, 170,},
923 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
924 uint16
925 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
926 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
927 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
928 0x278, 0xfea0, 0x80, 0x100, 0x80,},
929 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
930 750, 0xFE2B, 212, 0xFFCE, 212,},
931 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
932 0xFEF2, 128, 0xFFE2, 128}
935 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
936 mod_phy_reg(pi, 0x4a4, \
937 (0x1ff << 0), \
938 (uint16)(idx) << 0)
940 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
941 mod_phy_reg(pi, 0x4a5, \
942 (0x7 << 8), \
943 (uint16)(npt) << 8)
945 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
946 (read_phy_reg((pi), 0x4a4) & \
947 ((0x1 << 15) | \
948 (0x1 << 14) | \
949 (0x1 << 13)))
951 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
952 ((read_phy_reg(pi, 0x4a5) & \
953 (0x7 << 8)) >> \
956 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
957 (read_phy_reg(pi, 0x473) & 0x1ff)
959 #define wlc_lcnphy_get_target_tx_pwr(pi) \
960 ((read_phy_reg(pi, 0x4a7) & \
961 (0xff << 0)) >> \
964 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
965 mod_phy_reg(pi, 0x4a7, \
966 (0xff << 0), \
967 (uint16)(target) << 0)
969 #define wlc_radio_2064_rcal_done(pi) (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
970 #define tempsense_done(pi) (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
972 #define LCNPHY_IQLOCC_READ(val) ((uint8)(-(int8)(((val) & 0xf0) >> 4) + (int8)((val) & 0x0f)))
973 #define FIXED_TXPWR 78
974 #define LCNPHY_TEMPSENSE(val) ((int16)((val > 255)?(val - 512):val))
976 static uint32 wlc_lcnphy_qdiv_roundup(uint32 divident, uint32 divisor,
977 uint8 precision);
978 static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
979 uint16 ext_lna, uint16 trsw,
980 uint16 biq2, uint16 biq1,
981 uint16 tia, uint16 lna2,
982 uint16 lna1);
983 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
984 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 gain);
985 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
986 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, uint8 m0);
987 static uint8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
988 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
989 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
990 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
991 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
992 static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
993 lcnphy_txgains_t *target_gains);
994 static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, uint16 num_samps,
995 uint8 wait_time, lcnphy_iq_est_t *iq_est);
996 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, uint16 num_samps);
997 static uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
998 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, uint8 mode);
999 extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1000 extern void wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng,
1001 uint8 rate, struct ether_addr *sa,
1002 uint32 wait_delay);
1003 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1004 uint8 channel);
1006 static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1007 const lcnphy_tx_gain_tbl_entry *g);
1009 static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
1010 uint16 thresh, int16 *ptr, int mode);
1011 static int wlc_lcnphy_calc_floor(int16 coeff, int type);
1012 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1013 uint16 *values_to_save);
1014 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1015 uint16 *values_to_save);
1016 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x,
1017 int16 coeff_y);
1018 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1019 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1020 int num_levels, int step_size_lg2);
1021 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
1023 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
1024 chanspec_t chanspec);
1025 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1026 static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1027 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1028 static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1029 static void wlc_lcnphy_radio_init(phy_info_t *pi);
1030 static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1031 static void wlc_lcnphy_rcal(phy_info_t *pi);
1032 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1033 static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
1034 int16 filt_type);
1035 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 b);
1037 void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
1039 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1042 void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
1044 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1047 static void
1048 wlc_lcnphy_common_read_table(phy_info_t *pi, uint32 tbl_id,
1049 CONST void *tbl_ptr, uint32 tbl_len,
1050 uint32 tbl_width, uint32 tbl_offset)
1052 phytbl_info_t tab;
1053 tab.tbl_id = tbl_id;
1054 tab.tbl_ptr = tbl_ptr;
1055 tab.tbl_len = tbl_len;
1056 tab.tbl_width = tbl_width;
1057 tab.tbl_offset = tbl_offset;
1058 wlc_lcnphy_read_table(pi, &tab);
1061 static void
1062 wlc_lcnphy_common_write_table(phy_info_t *pi, uint32 tbl_id,
1063 CONST void *tbl_ptr, uint32 tbl_len,
1064 uint32 tbl_width, uint32 tbl_offset)
1067 phytbl_info_t tab;
1068 tab.tbl_id = tbl_id;
1069 tab.tbl_ptr = tbl_ptr;
1070 tab.tbl_len = tbl_len;
1071 tab.tbl_width = tbl_width;
1072 tab.tbl_offset = tbl_offset;
1073 wlc_lcnphy_write_table(pi, &tab);
1076 static uint32
1077 wlc_lcnphy_qdiv_roundup(uint32 dividend, uint32 divisor, uint8 precision)
1079 uint32 quotient, remainder, roundup, rbit;
1081 ASSERT(divisor);
1083 quotient = dividend / divisor;
1084 remainder = dividend % divisor;
1085 rbit = divisor & 1;
1086 roundup = (divisor >> 1) + rbit;
1088 while (precision--) {
1089 quotient <<= 1;
1090 if (remainder >= roundup) {
1091 quotient++;
1092 remainder = ((remainder - roundup) << 1) + rbit;
1093 } else {
1094 remainder <<= 1;
1098 if (remainder >= roundup)
1099 quotient++;
1101 return quotient;
1104 static int wlc_lcnphy_calc_floor(int16 coeff_x, int type)
1106 int k;
1107 k = 0;
1108 if (type == 0) {
1109 if (coeff_x < 0) {
1110 k = (coeff_x - 1) / 2;
1111 } else {
1112 k = coeff_x / 2;
1115 if (type == 1) {
1116 if ((coeff_x + 1) < 0)
1117 k = (coeff_x) / 2;
1118 else
1119 k = (coeff_x + 1) / 2;
1121 return k;
1124 int8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1126 int8 index;
1127 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1129 if (txpwrctrl_off(pi))
1130 index = pi_lcn->lcnphy_current_index;
1131 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1132 index =
1133 (int8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1134 / 2);
1135 else
1136 index = pi_lcn->lcnphy_current_index;
1137 return index;
1140 static uint32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, uint16 nsamples)
1142 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
1144 if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1145 return 0;
1146 return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1149 void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
1151 uint16 afectrlovr, afectrlovrval;
1152 afectrlovr = read_phy_reg(pi, 0x43b);
1153 afectrlovrval = read_phy_reg(pi, 0x43c);
1154 if (channel != 0) {
1155 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1157 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1159 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1161 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1163 write_phy_reg(pi, 0x44b, 0xffff);
1164 wlc_lcnphy_tx_pu(pi, 1);
1166 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1168 or_phy_reg(pi, 0x6da, 0x0080);
1170 or_phy_reg(pi, 0x00a, 0x228);
1171 } else {
1172 and_phy_reg(pi, 0x00a, ~(0x228));
1174 and_phy_reg(pi, 0x6da, 0xFF7F);
1175 write_phy_reg(pi, 0x43b, afectrlovr);
1176 write_phy_reg(pi, 0x43c, afectrlovrval);
1180 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
1182 uint16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1184 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1185 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1187 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1188 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1190 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1191 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1193 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1194 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1197 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
1199 if (enable) {
1200 write_phy_reg(pi, 0x942, 0x7);
1201 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1202 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1204 write_phy_reg(pi, 0x44a, 0x084);
1205 write_phy_reg(pi, 0x44a, 0x080);
1206 write_phy_reg(pi, 0x6d3, 0x2222);
1207 write_phy_reg(pi, 0x6d3, 0x2220);
1208 } else {
1209 write_phy_reg(pi, 0x942, 0x0);
1210 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1211 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1213 wlapi_switch_macfreq(pi->sh->physhim, enable);
1216 void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
1218 uint8 channel = CHSPEC_CHANNEL(chanspec);
1220 wlc_phy_chanspec_radio_set((wlc_phy_t *) pi, chanspec);
1222 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1224 or_phy_reg(pi, 0x44a, 0x44);
1225 write_phy_reg(pi, 0x44a, 0x80);
1227 if (!NORADIO_ENAB(pi->pubpi)) {
1228 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1229 OSL_DELAY(1000);
1232 wlc_lcnphy_toggle_afe_pwdn(pi);
1234 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1235 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1237 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1238 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1240 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 3);
1241 } else {
1242 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1244 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 2);
1247 wlc_lcnphy_load_tx_iir_filter(pi, TRUE, 0);
1249 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1253 static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, uint16 dac_gain)
1255 uint16 dac_ctrl;
1257 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1258 dac_ctrl = dac_ctrl & 0xc7f;
1259 dac_ctrl = dac_ctrl | (dac_gain << 7);
1260 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1264 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
1266 uint16 bit = bEnable ? 1 : 0;
1268 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1270 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1272 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1275 static uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1277 uint16 pa_gain;
1279 pa_gain = (read_phy_reg(pi, 0x4fb) &
1280 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1281 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1283 return pa_gain;
1286 static void
1287 wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
1289 uint16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1291 mod_phy_reg(pi, 0x4b5,
1292 (0xffff << 0),
1293 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1295 mod_phy_reg(pi, 0x4fb,
1296 (0x7fff << 0),
1297 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1299 mod_phy_reg(pi, 0x4fc,
1300 (0xffff << 0),
1301 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1303 mod_phy_reg(pi, 0x4fd,
1304 (0x7fff << 0),
1305 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1307 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1309 wlc_lcnphy_enable_tx_gain_override(pi);
1312 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, uint8 m0)
1314 uint16 m0m1 = (uint16) m0 << 8;
1315 phytbl_info_t tab;
1317 tab.tbl_ptr = &m0m1;
1318 tab.tbl_len = 1;
1319 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1320 tab.tbl_offset = 87;
1321 tab.tbl_width = 16;
1322 wlc_lcnphy_write_table(pi, &tab);
1325 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
1327 uint32 data_buf[64];
1328 phytbl_info_t tab;
1330 bzero(data_buf, sizeof(data_buf));
1332 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1333 tab.tbl_width = 32;
1334 tab.tbl_ptr = data_buf;
1336 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1338 tab.tbl_len = 30;
1339 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1340 wlc_lcnphy_write_table(pi, &tab);
1343 tab.tbl_len = 64;
1344 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1345 wlc_lcnphy_write_table(pi, &tab);
1348 typedef enum {
1349 LCNPHY_TSSI_PRE_PA,
1350 LCNPHY_TSSI_POST_PA,
1351 LCNPHY_TSSI_EXT
1352 } lcnphy_tssi_mode_t;
1354 static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
1356 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1358 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1360 if (LCNPHY_TSSI_POST_PA == pos) {
1361 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1363 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1365 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1366 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1367 } else {
1368 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1369 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1371 } else {
1372 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1374 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1376 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1377 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1378 } else {
1379 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
1380 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1383 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1385 if (LCNPHY_TSSI_EXT == pos) {
1386 write_radio_reg(pi, RADIO_2064_REG07F, 1);
1387 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
1388 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
1389 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
1393 static uint16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1395 uint16 N1, N2, N3, N4, N5, N6, N;
1396 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1397 >> 0);
1398 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1399 >> 12);
1400 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1401 >> 0);
1402 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1403 >> 8);
1404 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1405 >> 0);
1406 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1407 >> 8);
1408 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1409 if (N < 1600)
1410 N = 1600;
1411 return N;
1414 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1416 uint16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
1417 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1419 auxpga_vmid =
1420 (2 << 8) | (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
1421 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
1422 auxpga_gain_temp = 2;
1424 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
1426 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
1428 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
1430 mod_phy_reg(pi, 0x4db,
1431 (0x3ff << 0) |
1432 (0x7 << 12),
1433 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1435 mod_phy_reg(pi, 0x4dc,
1436 (0x3ff << 0) |
1437 (0x7 << 12),
1438 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1440 mod_phy_reg(pi, 0x40a,
1441 (0x3ff << 0) |
1442 (0x7 << 12),
1443 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1445 mod_phy_reg(pi, 0x40b,
1446 (0x3ff << 0) |
1447 (0x7 << 12),
1448 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1450 mod_phy_reg(pi, 0x40c,
1451 (0x3ff << 0) |
1452 (0x7 << 12),
1453 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1455 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
1458 static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
1460 phytbl_info_t tab;
1461 uint32 rfseq, ind;
1463 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1464 tab.tbl_width = 32;
1465 tab.tbl_ptr = &ind;
1466 tab.tbl_len = 1;
1467 tab.tbl_offset = 0;
1468 for (ind = 0; ind < 128; ind++) {
1469 wlc_lcnphy_write_table(pi, &tab);
1470 tab.tbl_offset++;
1472 tab.tbl_offset = 704;
1473 for (ind = 0; ind < 128; ind++) {
1474 wlc_lcnphy_write_table(pi, &tab);
1475 tab.tbl_offset++;
1477 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
1479 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
1481 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
1483 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
1484 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
1486 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
1488 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
1490 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
1492 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
1494 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
1496 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
1498 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
1500 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
1502 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
1504 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
1506 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
1508 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
1510 wlc_lcnphy_clear_tx_power_offsets(pi);
1512 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
1514 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
1516 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
1518 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1519 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
1520 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1521 } else {
1522 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1523 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
1526 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
1528 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1529 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1530 } else {
1531 if (CHSPEC_IS2G(pi->radio_chanspec))
1532 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1533 else
1534 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
1537 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
1538 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1539 else
1540 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
1542 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
1544 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
1546 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1547 mod_phy_reg(pi, 0x4d7,
1548 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
1551 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
1552 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
1553 tab.tbl_width = 16;
1554 tab.tbl_ptr = &rfseq;
1555 tab.tbl_len = 1;
1556 tab.tbl_offset = 6;
1557 wlc_lcnphy_write_table(pi, &tab);
1559 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
1561 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
1563 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1565 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
1567 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
1569 wlc_lcnphy_pwrctrl_rssiparams(pi);
1572 void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
1574 uint16 tx_cnt, tx_total, npt;
1575 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1577 tx_total = wlc_lcnphy_total_tx_frames(pi);
1578 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
1579 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
1581 if (tx_cnt > (1 << npt)) {
1583 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
1585 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
1586 pi_lcn->lcnphy_tssi_npt = npt;
1591 int32 wlc_lcnphy_tssi2dbm(int32 tssi, int32 a1, int32 b0, int32 b1)
1593 int32 a, b, p;
1595 a = 32768 + (a1 * tssi);
1596 b = (1024 * b0) + (64 * b1 * tssi);
1597 p = ((2 * b) + a) / (2 * a);
1599 return p;
1602 static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
1604 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1605 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1606 return;
1608 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
1609 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
1612 void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
1614 phytbl_info_t tab;
1615 uint32 rate_table[WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM +
1616 WLC_NUM_RATES_MCS_1_STREAM];
1617 uint i, j;
1618 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1619 return;
1621 for (i = 0, j = 0; i < ARRAYSIZE(rate_table); i++, j++) {
1623 if (i == WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM)
1624 j = TXP_FIRST_MCS_20_SISO;
1626 rate_table[i] = (uint32) ((int32) (-pi->tx_power_offset[j]));
1629 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1630 tab.tbl_width = 32;
1631 tab.tbl_len = ARRAYSIZE(rate_table);
1632 tab.tbl_ptr = rate_table;
1633 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1634 wlc_lcnphy_write_table(pi, &tab);
1636 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
1637 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
1639 wlc_lcnphy_txpower_reset_npt(pi);
1643 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, int8 index)
1645 uint32 cck_offset[4] = { 22, 22, 22, 22 };
1646 uint32 ofdm_offset, reg_offset_cck;
1647 int i;
1648 uint16 index2;
1649 phytbl_info_t tab;
1651 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1652 return;
1654 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1656 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
1658 or_phy_reg(pi, 0x6da, 0x0040);
1660 reg_offset_cck = 0;
1661 for (i = 0; i < 4; i++)
1662 cck_offset[i] -= reg_offset_cck;
1663 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1664 tab.tbl_width = 32;
1665 tab.tbl_len = 4;
1666 tab.tbl_ptr = cck_offset;
1667 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1668 wlc_lcnphy_write_table(pi, &tab);
1669 ofdm_offset = 0;
1670 tab.tbl_len = 1;
1671 tab.tbl_ptr = &ofdm_offset;
1672 for (i = 836; i < 862; i++) {
1673 tab.tbl_offset = i;
1674 wlc_lcnphy_write_table(pi, &tab);
1677 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
1679 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1681 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
1683 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
1685 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
1687 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
1689 index2 = (uint16) (index * 2);
1690 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1692 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1696 static int8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1698 int8 index, delta_brd, delta_temp, new_index, tempcorrx;
1699 int16 manp, meas_temp, temp_diff;
1700 bool neg = 0;
1701 uint16 temp;
1702 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1704 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1705 return pi_lcn->lcnphy_current_index;
1707 index = FIXED_TXPWR;
1709 if (NORADIO_ENAB(pi->pubpi))
1710 return index;
1712 if (pi_lcn->lcnphy_tempsense_slope == 0) {
1713 return index;
1715 temp = (uint16) wlc_lcnphy_tempsense(pi, 0);
1716 meas_temp = LCNPHY_TEMPSENSE(temp);
1718 if (pi->tx_power_min != 0) {
1719 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
1720 } else {
1721 delta_brd = 0;
1724 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
1725 temp_diff = manp - meas_temp;
1726 if (temp_diff < 0) {
1728 neg = 1;
1730 temp_diff = -temp_diff;
1733 delta_temp = (int8) wlc_lcnphy_qdiv_roundup((uint32) (temp_diff * 192),
1734 (uint32) (pi_lcn->
1735 lcnphy_tempsense_slope
1736 * 10), 0);
1737 if (neg)
1738 delta_temp = -delta_temp;
1740 if (pi_lcn->lcnphy_tempsense_option == 3
1741 && LCNREV_IS(pi->pubpi.phy_rev, 0))
1742 delta_temp = 0;
1743 if (pi_lcn->lcnphy_tempcorrx > 31)
1744 tempcorrx = (int8) (pi_lcn->lcnphy_tempcorrx - 64);
1745 else
1746 tempcorrx = (int8) pi_lcn->lcnphy_tempcorrx;
1747 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1748 tempcorrx = 4;
1749 new_index =
1750 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1751 new_index += tempcorrx;
1753 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1754 index = 127;
1755 if (new_index < 0 || new_index > 126) {
1756 return index;
1758 return new_index;
1761 static uint16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, uint16 mode)
1764 uint16 current_mode = mode;
1765 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1766 mode == LCNPHY_TX_PWR_CTRL_HW)
1767 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1768 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1769 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1770 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1771 return current_mode;
1774 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, uint16 mode)
1776 uint16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1777 int8 index;
1778 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1780 ASSERT((LCNPHY_TX_PWR_CTRL_OFF == mode) ||
1781 (LCNPHY_TX_PWR_CTRL_SW == mode) ||
1782 (LCNPHY_TX_PWR_CTRL_HW == mode) ||
1783 (LCNPHY_TX_PWR_CTRL_TEMPBASED == mode));
1785 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
1786 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
1788 mod_phy_reg(pi, 0x6da, (0x1 << 6),
1789 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
1791 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
1792 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
1794 if (old_mode != mode) {
1795 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
1797 wlc_lcnphy_tx_pwr_update_npt(pi);
1799 wlc_lcnphy_clear_tx_power_offsets(pi);
1801 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
1803 wlc_lcnphy_txpower_recalc_target(pi);
1805 wlc_lcnphy_set_start_tx_pwr_idx(pi,
1806 pi_lcn->
1807 lcnphy_tssi_idx);
1808 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
1809 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
1811 pi_lcn->lcnphy_tssi_tx_cnt =
1812 wlc_lcnphy_total_tx_frames(pi);
1814 wlc_lcnphy_disable_tx_gain_override(pi);
1815 pi_lcn->lcnphy_tx_power_idx_override = -1;
1816 } else
1817 wlc_lcnphy_enable_tx_gain_override(pi);
1819 mod_phy_reg(pi, 0x4a4,
1820 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
1821 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
1822 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
1823 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
1824 pi_lcn->lcnphy_current_index = (int8)
1825 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1830 static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
1832 uint delay_count = 0;
1834 while (wlc_lcnphy_iqcal_active(pi)) {
1835 OSL_DELAY(100);
1836 delay_count++;
1838 if (delay_count > (10 * 500))
1839 break;
1842 return (0 == wlc_lcnphy_iqcal_active(pi));
1845 static void
1846 wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1847 lcnphy_txgains_t *target_gains,
1848 lcnphy_cal_mode_t cal_mode, bool keep_tone)
1851 lcnphy_txgains_t cal_gains, temp_gains;
1852 uint16 hash;
1853 uint8 band_idx;
1854 int j;
1855 uint16 ncorr_override[5];
1856 uint16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1857 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1860 uint16 commands_fullcal[] =
1861 { 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1863 uint16 commands_recal[] =
1864 { 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1866 uint16 command_nums_fullcal[] =
1867 { 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1869 uint16 command_nums_recal[] =
1870 { 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1871 uint16 *command_nums = command_nums_fullcal;
1873 uint16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1874 uint16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1875 uint16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
1876 bool tx_gain_override_old;
1877 lcnphy_txgains_t old_gains;
1878 uint i, n_cal_cmds = 0, n_cal_start = 0;
1879 uint16 *values_to_save;
1880 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1882 if (NORADIO_ENAB(pi->pubpi))
1883 return;
1885 if (NULL == (values_to_save = MALLOC(pi->sh->osh, sizeof(uint16) * 20))) {
1886 return;
1889 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1890 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1892 or_phy_reg(pi, 0x6da, 0x40);
1893 or_phy_reg(pi, 0x6db, 0x3);
1895 switch (cal_mode) {
1896 case LCNPHY_CAL_FULL:
1897 start_coeffs = syst_coeffs;
1898 cal_cmds = commands_fullcal;
1899 n_cal_cmds = ARRAYSIZE(commands_fullcal);
1900 break;
1902 case LCNPHY_CAL_RECAL:
1903 ASSERT(pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid);
1905 start_coeffs = syst_coeffs;
1907 cal_cmds = commands_recal;
1908 n_cal_cmds = ARRAYSIZE(commands_recal);
1909 command_nums = command_nums_recal;
1910 break;
1911 default:
1912 ASSERT(FALSE);
1915 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1916 start_coeffs, 11, 16, 64);
1918 write_phy_reg(pi, 0x6da, 0xffff);
1919 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
1921 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1923 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1925 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1927 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
1929 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
1931 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
1933 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
1935 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1936 if (tx_gain_override_old)
1937 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1939 if (!target_gains) {
1940 if (!tx_gain_override_old)
1941 wlc_lcnphy_set_tx_pwr_by_index(pi,
1942 pi_lcn->lcnphy_tssi_idx);
1943 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
1944 target_gains = &temp_gains;
1947 hash = (target_gains->gm_gain << 8) |
1948 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
1950 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
1952 cal_gains = *target_gains;
1953 bzero(ncorr_override, sizeof(ncorr_override));
1954 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
1955 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
1956 cal_gains.gm_gain =
1957 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
1958 cal_gains.pga_gain =
1959 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
1960 cal_gains.pad_gain =
1961 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
1962 bcopy(&tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
1963 ncorr_override, sizeof(ncorr_override));
1964 break;
1968 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
1970 write_phy_reg(pi, 0x453, 0xaa9);
1971 write_phy_reg(pi, 0x93d, 0xc0);
1973 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1974 (CONST void *)
1975 lcnphy_iqcal_loft_gainladder,
1976 ARRAYSIZE(lcnphy_iqcal_loft_gainladder),
1977 16, 0);
1979 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1980 (CONST void *)lcnphy_iqcal_ir_gainladder,
1981 ARRAYSIZE(lcnphy_iqcal_ir_gainladder), 16,
1982 32);
1984 if (pi->phy_tx_tone_freq) {
1986 wlc_lcnphy_stop_tx_tone(pi);
1987 OSL_DELAY(5);
1988 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1989 } else {
1990 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1993 write_phy_reg(pi, 0x6da, 0xffff);
1995 for (i = n_cal_start; i < n_cal_cmds; i++) {
1996 uint16 zero_diq = 0;
1997 uint16 best_coeffs[11];
1998 uint16 command_num;
2000 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2002 command_num = command_nums[i];
2003 if (ncorr_override[cal_type])
2004 command_num =
2005 ncorr_override[cal_type] << 8 | (command_num &
2006 0xff);
2008 write_phy_reg(pi, 0x452, command_num);
2010 if ((cal_type == 3) || (cal_type == 4)) {
2012 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2013 &diq_start, 1, 16, 69);
2015 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2016 &zero_diq, 1, 16, 69);
2019 write_phy_reg(pi, 0x451, cal_cmds[i]);
2021 if (!wlc_lcnphy_iqcal_wait(pi)) {
2023 goto cleanup;
2026 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2027 best_coeffs,
2028 ARRAYSIZE(best_coeffs), 16, 96);
2029 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2030 best_coeffs,
2031 ARRAYSIZE(best_coeffs), 16, 64);
2033 if ((cal_type == 3) || (cal_type == 4)) {
2034 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2035 &diq_start, 1, 16, 69);
2037 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2038 pi_lcn->lcnphy_cal_results.
2039 txiqlocal_bestcoeffs,
2040 ARRAYSIZE(pi_lcn->
2041 lcnphy_cal_results.
2042 txiqlocal_bestcoeffs),
2043 16, 96);
2046 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2047 pi_lcn->lcnphy_cal_results.
2048 txiqlocal_bestcoeffs,
2049 ARRAYSIZE(pi_lcn->lcnphy_cal_results.
2050 txiqlocal_bestcoeffs), 16, 96);
2051 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = TRUE;
2053 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2054 &pi_lcn->lcnphy_cal_results.
2055 txiqlocal_bestcoeffs[0], 4, 16, 80);
2057 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2058 &pi_lcn->lcnphy_cal_results.
2059 txiqlocal_bestcoeffs[5], 2, 16, 85);
2061 cleanup:
2062 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2063 MFREE(pi->sh->osh, values_to_save, 20 * sizeof(uint16));
2065 if (!keep_tone)
2066 wlc_lcnphy_stop_tx_tone(pi);
2068 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2070 write_phy_reg(pi, 0x453, 0);
2072 if (tx_gain_override_old)
2073 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2074 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2076 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2077 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2081 static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
2083 bool suspend, tx_gain_override_old;
2084 lcnphy_txgains_t old_gains;
2085 phy_info_t *pi = (phy_info_t *) ppi;
2086 uint16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2087 idleTssi0_regvalue_2C;
2088 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2089 uint16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2090 uint16 SAVE_jtag_bb_afe_switch =
2091 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2092 uint16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2093 uint16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2094 idleTssi = read_phy_reg(pi, 0x4ab);
2095 suspend =
2096 (0 ==
2097 (R_REG(pi->sh->osh, &((phy_info_t *) pi)->regs->maccontrol) &
2098 MCTL_EN_MAC));
2099 if (!suspend)
2100 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2101 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2103 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2104 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2106 wlc_lcnphy_enable_tx_gain_override(pi);
2107 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2108 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2109 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2110 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2111 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2112 wlc_lcnphy_tssi_setup(pi);
2113 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
2114 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2115 >> 0);
2117 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2118 >> 0);
2120 if (idleTssi0_2C >= 256)
2121 idleTssi0_OB = idleTssi0_2C - 256;
2122 else
2123 idleTssi0_OB = idleTssi0_2C + 256;
2125 idleTssi0_regvalue_OB = idleTssi0_OB;
2126 if (idleTssi0_regvalue_OB >= 256)
2127 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2128 else
2129 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2130 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2132 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2134 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2135 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2136 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2138 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2139 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2140 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2141 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2142 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2143 if (!suspend)
2144 wlapi_enable_mac(pi->sh->physhim);
2147 static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, uint8 mode)
2149 bool suspend;
2150 uint16 save_txpwrCtrlEn;
2151 uint8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2152 uint16 auxpga_vmid;
2153 phytbl_info_t tab;
2154 uint32 val;
2155 uint8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2156 save_reg112;
2157 uint16 values_to_save[14];
2158 int8 index;
2159 int i;
2160 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2161 OSL_DELAY(999);
2163 save_reg007 = (uint8) read_radio_reg(pi, RADIO_2064_REG007);
2164 save_reg0FF = (uint8) read_radio_reg(pi, RADIO_2064_REG0FF);
2165 save_reg11F = (uint8) read_radio_reg(pi, RADIO_2064_REG11F);
2166 save_reg005 = (uint8) read_radio_reg(pi, RADIO_2064_REG005);
2167 save_reg025 = (uint8) read_radio_reg(pi, RADIO_2064_REG025);
2168 save_reg112 = (uint8) read_radio_reg(pi, RADIO_2064_REG112);
2170 for (i = 0; i < 14; i++)
2171 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2172 suspend =
2173 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2174 if (!suspend)
2175 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2176 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2178 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2179 index = pi_lcn->lcnphy_current_index;
2180 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2181 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2182 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2183 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2184 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2186 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2188 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2190 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2192 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2194 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2196 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2198 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2200 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2202 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2204 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2206 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2208 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2210 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2212 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2214 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2216 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2218 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2220 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2222 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2224 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2226 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2228 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2230 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2231 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2232 tab.tbl_width = 16;
2233 tab.tbl_len = 1;
2234 tab.tbl_ptr = &val;
2235 tab.tbl_offset = 6;
2236 wlc_lcnphy_write_table(pi, &tab);
2237 if (mode == TEMPSENSE) {
2238 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2240 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2242 auxpga_vmidcourse = 8;
2243 auxpga_vmidfine = 0x4;
2244 auxpga_gain = 2;
2245 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2246 } else {
2247 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2249 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2251 auxpga_vmidcourse = 7;
2252 auxpga_vmidfine = 0xa;
2253 auxpga_gain = 2;
2255 auxpga_vmid =
2256 (uint16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2257 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2259 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2261 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2263 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2265 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2267 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2269 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
2270 if (!tempsense_done(pi))
2271 OSL_DELAY(10);
2273 write_radio_reg(pi, RADIO_2064_REG007, (uint16) save_reg007);
2274 write_radio_reg(pi, RADIO_2064_REG0FF, (uint16) save_reg0FF);
2275 write_radio_reg(pi, RADIO_2064_REG11F, (uint16) save_reg11F);
2276 write_radio_reg(pi, RADIO_2064_REG005, (uint16) save_reg005);
2277 write_radio_reg(pi, RADIO_2064_REG025, (uint16) save_reg025);
2278 write_radio_reg(pi, RADIO_2064_REG112, (uint16) save_reg112);
2279 for (i = 0; i < 14; i++)
2280 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2281 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
2283 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
2284 if (!suspend)
2285 wlapi_enable_mac(pi->sh->physhim);
2286 OSL_DELAY(999);
2289 void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi) {
2290 lcnphy_txgains_t tx_gains;
2291 uint8 bbmult;
2292 phytbl_info_t tab;
2293 int32 a1, b0, b1;
2294 int32 tssi, pwr, maxtargetpwr, mintargetpwr;
2295 bool suspend;
2296 phy_info_t *pi = (phy_info_t *) ppi;
2298 suspend =
2299 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2300 if (!suspend)
2301 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2303 if (NORADIO_ENAB(pi->pubpi)) {
2304 wlc_lcnphy_set_bbmult(pi, 0x30);
2305 if (!suspend)
2306 wlapi_enable_mac(pi->sh->physhim);
2307 return;
2310 if (!pi->hwpwrctrl_capable) {
2311 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2312 tx_gains.gm_gain = 4;
2313 tx_gains.pga_gain = 12;
2314 tx_gains.pad_gain = 12;
2315 tx_gains.dac_gain = 0;
2317 bbmult = 150;
2318 } else {
2319 tx_gains.gm_gain = 7;
2320 tx_gains.pga_gain = 15;
2321 tx_gains.pad_gain = 14;
2322 tx_gains.dac_gain = 0;
2324 bbmult = 150;
2326 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
2327 wlc_lcnphy_set_bbmult(pi, bbmult);
2328 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2329 } else {
2331 wlc_lcnphy_idle_tssi_est(ppi);
2333 wlc_lcnphy_clear_tx_power_offsets(pi);
2335 b0 = pi->txpa_2g[0];
2336 b1 = pi->txpa_2g[1];
2337 a1 = pi->txpa_2g[2];
2338 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
2339 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
2341 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2342 tab.tbl_width = 32;
2343 tab.tbl_ptr = &pwr;
2344 tab.tbl_len = 1;
2345 tab.tbl_offset = 0;
2346 for (tssi = 0; tssi < 128; tssi++) {
2347 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
2349 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
2350 wlc_lcnphy_write_table(pi, &tab);
2351 tab.tbl_offset++;
2354 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
2356 write_phy_reg(pi, 0x4a8, 10);
2358 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
2360 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
2362 if (!suspend)
2363 wlapi_enable_mac(pi->sh->physhim);
2366 static uint8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2368 uint16 m0m1;
2369 phytbl_info_t tab;
2371 tab.tbl_ptr = &m0m1;
2372 tab.tbl_len = 1;
2373 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2374 tab.tbl_offset = 87;
2375 tab.tbl_width = 16;
2376 wlc_lcnphy_read_table(pi, &tab);
2378 return (uint8) ((m0m1 & 0xff00) >> 8);
2381 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 gain)
2383 mod_phy_reg(pi, 0x4fb,
2384 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
2385 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
2386 mod_phy_reg(pi, 0x4fd,
2387 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
2388 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
2391 void
2392 wlc_lcnphy_get_radio_loft(phy_info_t *pi,
2393 uint8 *ei0, uint8 *eq0, uint8 *fi0, uint8 *fq0)
2395 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
2396 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
2397 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
2398 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
2401 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
2403 uint16 dac_gain;
2405 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2406 gains->dac_gain = (dac_gain & 0x380) >> 7;
2409 uint16 rfgain0, rfgain1;
2411 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
2412 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
2414 gains->gm_gain = rfgain0 & 0xff;
2415 gains->pga_gain = (rfgain0 >> 8) & 0xff;
2416 gains->pad_gain = rfgain1 & 0xff;
2420 void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, uint16 a, uint16 b)
2422 phytbl_info_t tab;
2423 uint16 iqcc[2];
2425 iqcc[0] = a;
2426 iqcc[1] = b;
2428 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2429 tab.tbl_width = 16;
2430 tab.tbl_ptr = iqcc;
2431 tab.tbl_len = 2;
2432 tab.tbl_offset = 80;
2433 wlc_lcnphy_write_table(pi, &tab);
2436 void wlc_lcnphy_set_tx_locc(phy_info_t *pi, uint16 didq)
2438 phytbl_info_t tab;
2440 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2441 tab.tbl_width = 16;
2442 tab.tbl_ptr = &didq;
2443 tab.tbl_len = 1;
2444 tab.tbl_offset = 85;
2445 wlc_lcnphy_write_table(pi, &tab);
2448 void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
2450 phytbl_info_t tab;
2451 uint16 a, b;
2452 uint8 bb_mult;
2453 uint32 bbmultiqcomp, txgain, locoeffs, rfpower;
2454 lcnphy_txgains_t gains;
2455 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2457 ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2459 pi_lcn->lcnphy_tx_power_idx_override = (int8) index;
2460 pi_lcn->lcnphy_current_index = (uint8) index;
2462 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2463 tab.tbl_width = 32;
2464 tab.tbl_len = 1;
2466 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2468 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
2469 tab.tbl_ptr = &bbmultiqcomp;
2470 wlc_lcnphy_read_table(pi, &tab);
2472 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
2473 tab.tbl_width = 32;
2474 tab.tbl_ptr = &txgain;
2475 wlc_lcnphy_read_table(pi, &tab);
2477 gains.gm_gain = (uint16) (txgain & 0xff);
2478 gains.pga_gain = (uint16) (txgain >> 8) & 0xff;
2479 gains.pad_gain = (uint16) (txgain >> 16) & 0xff;
2480 gains.dac_gain = (uint16) (bbmultiqcomp >> 28) & 0x07;
2481 wlc_lcnphy_set_tx_gain(pi, &gains);
2482 wlc_lcnphy_set_pa_gain(pi, (uint16) (txgain >> 24) & 0x7f);
2484 bb_mult = (uint8) ((bbmultiqcomp >> 20) & 0xff);
2485 wlc_lcnphy_set_bbmult(pi, bb_mult);
2487 wlc_lcnphy_enable_tx_gain_override(pi);
2489 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2491 a = (uint16) ((bbmultiqcomp >> 10) & 0x3ff);
2492 b = (uint16) (bbmultiqcomp & 0x3ff);
2493 wlc_lcnphy_set_tx_iqcc(pi, a, b);
2495 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
2496 tab.tbl_ptr = &locoeffs;
2497 wlc_lcnphy_read_table(pi, &tab);
2499 wlc_lcnphy_set_tx_locc(pi, (uint16) locoeffs);
2501 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
2502 tab.tbl_ptr = &rfpower;
2503 wlc_lcnphy_read_table(pi, &tab);
2504 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
2509 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
2512 mod_phy_reg(pi, 0x44d,
2513 (0x1 << 1) |
2514 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
2516 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
2519 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
2521 uint32 j;
2522 phytbl_info_t tab;
2523 uint32 temp_offset[128];
2524 tab.tbl_ptr = temp_offset;
2525 tab.tbl_len = 128;
2526 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
2527 tab.tbl_width = 32;
2528 tab.tbl_offset = 0;
2530 bzero(temp_offset, sizeof(temp_offset));
2531 for (j = 1; j < 128; j += 2)
2532 temp_offset[j] = 0x80000;
2534 wlc_lcnphy_write_table(pi, &tab);
2535 return;
2538 static void
2539 wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
2540 uint16 trsw,
2541 uint16 ext_lna,
2542 uint16 biq2,
2543 uint16 biq1,
2544 uint16 tia, uint16 lna2, uint16 lna1)
2546 uint16 gain0_15, gain16_19;
2548 gain16_19 = biq2 & 0xf;
2549 gain0_15 = ((biq1 & 0xf) << 12) |
2550 ((tia & 0xf) << 8) |
2551 ((lna2 & 0x3) << 6) |
2552 ((lna2 & 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
2554 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
2555 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
2556 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
2558 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2559 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2560 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
2561 } else {
2562 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
2564 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
2566 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2569 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
2573 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
2575 uint16 ebit = enable ? 1 : 0;
2577 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
2579 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
2581 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2582 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
2583 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
2584 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2585 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
2586 } else {
2587 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
2588 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
2589 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2592 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2593 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
2594 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
2598 void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
2600 if (!bEnable) {
2602 and_phy_reg(pi, 0x43b, ~(uint16) ((0x1 << 1) | (0x1 << 4)));
2604 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2606 and_phy_reg(pi, 0x44c,
2607 ~(uint16) ((0x1 << 3) |
2608 (0x1 << 5) |
2609 (0x1 << 12) |
2610 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2612 and_phy_reg(pi, 0x44d,
2613 ~(uint16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
2614 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
2616 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
2618 and_phy_reg(pi, 0x4f9,
2619 ~(uint16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2621 and_phy_reg(pi, 0x4fa,
2622 ~(uint16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2623 } else {
2625 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2626 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2628 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
2629 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
2631 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2632 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2634 wlc_lcnphy_set_trsw_override(pi, TRUE, FALSE);
2636 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
2637 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
2639 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2641 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2642 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
2644 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2645 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
2647 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2648 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
2650 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2651 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
2653 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2654 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
2655 } else {
2657 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2658 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
2660 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2661 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
2663 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2664 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
2666 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2667 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
2669 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2670 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
2675 static void
2676 wlc_lcnphy_run_samples(phy_info_t *pi,
2677 uint16 num_samps,
2678 uint16 num_loops, uint16 wait, bool iqcalmode)
2681 or_phy_reg(pi, 0x6da, 0x8080);
2683 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
2684 if (num_loops != 0xffff)
2685 num_loops--;
2686 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
2688 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
2690 if (iqcalmode) {
2692 and_phy_reg(pi, 0x453, (uint16) ~ (0x1 << 15));
2693 or_phy_reg(pi, 0x453, (0x1 << 15));
2694 } else {
2695 write_phy_reg(pi, 0x63f, 1);
2696 wlc_lcnphy_tx_pu(pi, 1);
2699 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2702 void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
2705 uint8 phybw40;
2706 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
2708 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2709 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2710 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2711 } else {
2712 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2713 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2716 if (phybw40 == 0) {
2717 mod_phy_reg((pi), 0x410,
2718 (0x1 << 6) |
2719 (0x1 << 5),
2720 ((CHSPEC_IS2G(pi->radio_chanspec)) ? (!mode) : 0) <<
2721 6 | (!mode) << 5);
2722 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
2726 void
2727 wlc_lcnphy_start_tx_tone(phy_info_t *pi, int32 f_kHz, uint16 max_val,
2728 bool iqcalmode)
2730 uint8 phy_bw;
2731 uint16 num_samps, t, k;
2732 uint32 bw;
2733 fixed theta = 0, rot = 0;
2734 cint32 tone_samp;
2735 uint32 data_buf[64];
2736 uint16 i_samp, q_samp;
2737 phytbl_info_t tab;
2738 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2740 pi->phy_tx_tone_freq = f_kHz;
2742 wlc_lcnphy_deaf_mode(pi, TRUE);
2744 phy_bw = 40;
2745 if (pi_lcn->lcnphy_spurmod) {
2746 write_phy_reg(pi, 0x942, 0x2);
2747 write_phy_reg(pi, 0x93b, 0x0);
2748 write_phy_reg(pi, 0x93c, 0x0);
2749 wlc_lcnphy_txrx_spur_avoidance_mode(pi, FALSE);
2752 if (f_kHz) {
2753 k = 1;
2754 do {
2755 bw = phy_bw * 1000 * k;
2756 num_samps = bw / ABS(f_kHz);
2757 ASSERT(num_samps <= ARRAYSIZE(data_buf));
2758 k++;
2759 } while ((num_samps * (uint32) (ABS(f_kHz))) != bw);
2760 } else
2761 num_samps = 2;
2763 rot = FIXED((f_kHz * 36) / phy_bw) / 100;
2764 theta = 0;
2766 for (t = 0; t < num_samps; t++) {
2768 wlc_phy_cordic(theta, &tone_samp);
2770 theta += rot;
2772 i_samp = (uint16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2773 q_samp = (uint16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
2774 data_buf[t] = (i_samp << 10) | q_samp;
2777 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
2779 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
2781 tab.tbl_ptr = data_buf;
2782 tab.tbl_len = num_samps;
2783 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
2784 tab.tbl_offset = 0;
2785 tab.tbl_width = 32;
2786 wlc_lcnphy_write_table(pi, &tab);
2788 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
2791 void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
2793 int16 playback_status;
2794 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2796 pi->phy_tx_tone_freq = 0;
2797 if (pi_lcn->lcnphy_spurmod) {
2798 write_phy_reg(pi, 0x942, 0x7);
2799 write_phy_reg(pi, 0x93b, 0x2017);
2800 write_phy_reg(pi, 0x93c, 0x27c5);
2801 wlc_lcnphy_txrx_spur_avoidance_mode(pi, TRUE);
2804 playback_status = read_phy_reg(pi, 0x644);
2805 if (playback_status & (0x1 << 0)) {
2806 wlc_lcnphy_tx_pu(pi, 0);
2807 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
2808 } else if (playback_status & (0x1 << 1))
2809 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
2811 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
2813 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
2815 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
2817 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
2819 wlc_lcnphy_deaf_mode(pi, FALSE);
2822 static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
2825 and_phy_reg(pi, 0x44c, (uint16) ~ ((0x1 << 1) | (0x1 << 0)));
2828 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, uint16 *a, uint16 *b)
2830 uint16 iqcc[2];
2831 phytbl_info_t tab;
2833 tab.tbl_ptr = iqcc;
2834 tab.tbl_len = 2;
2835 tab.tbl_id = 0;
2836 tab.tbl_offset = 80;
2837 tab.tbl_width = 16;
2838 wlc_lcnphy_read_table(pi, &tab);
2840 *a = iqcc[0];
2841 *b = iqcc[1];
2844 uint16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2846 phytbl_info_t tab;
2847 uint16 didq;
2849 tab.tbl_id = 0;
2850 tab.tbl_width = 16;
2851 tab.tbl_ptr = &didq;
2852 tab.tbl_len = 1;
2853 tab.tbl_offset = 85;
2854 wlc_lcnphy_read_table(pi, &tab);
2856 return didq;
2859 static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
2862 lcnphy_txgains_t target_gains, old_gains;
2863 uint8 save_bb_mult;
2864 uint16 a, b, didq, save_pa_gain = 0;
2865 uint idx, SAVE_txpwrindex = 0xFF;
2866 uint32 val;
2867 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2868 phytbl_info_t tab;
2869 uint8 ei0, eq0, fi0, fq0;
2870 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2872 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2873 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
2875 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
2877 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
2878 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2880 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2882 target_gains.gm_gain = 7;
2883 target_gains.pga_gain = 0;
2884 target_gains.pad_gain = 21;
2885 target_gains.dac_gain = 0;
2886 wlc_lcnphy_set_tx_gain(pi, &target_gains);
2887 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2889 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
2891 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
2893 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2894 (pi_lcn->
2895 lcnphy_recal ? LCNPHY_CAL_RECAL :
2896 LCNPHY_CAL_FULL), FALSE);
2897 } else {
2899 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2902 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
2903 if ((ABS((int8) fi0) == 15) && (ABS((int8) fq0) == 15)) {
2904 if (CHSPEC_IS5G(pi->radio_chanspec)) {
2905 target_gains.gm_gain = 255;
2906 target_gains.pga_gain = 255;
2907 target_gains.pad_gain = 0xf0;
2908 target_gains.dac_gain = 0;
2909 } else {
2910 target_gains.gm_gain = 7;
2911 target_gains.pga_gain = 45;
2912 target_gains.pad_gain = 186;
2913 target_gains.dac_gain = 0;
2916 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
2917 || pi_lcn->lcnphy_hw_iqcal_en) {
2919 target_gains.pga_gain = 0;
2920 target_gains.pad_gain = 30;
2921 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2922 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2923 LCNPHY_CAL_FULL, FALSE);
2924 } else {
2926 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2931 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
2933 didq = wlc_lcnphy_get_tx_locc(pi);
2935 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2936 tab.tbl_width = 32;
2937 tab.tbl_ptr = &val;
2939 tab.tbl_len = 1;
2940 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2942 for (idx = 0; idx < 128; idx++) {
2943 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
2945 wlc_lcnphy_read_table(pi, &tab);
2946 val = (val & 0xfff00000) |
2947 ((uint32) (a & 0x3FF) << 10) | (b & 0x3ff);
2948 wlc_lcnphy_write_table(pi, &tab);
2950 val = didq;
2951 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
2952 wlc_lcnphy_write_table(pi, &tab);
2955 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
2956 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
2957 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
2958 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
2959 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
2960 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
2961 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
2963 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
2964 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
2965 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2967 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
2968 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2969 else
2970 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
2973 int16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2975 uint16 tempsenseval1, tempsenseval2;
2976 int16 avg = 0;
2977 bool suspend = 0;
2979 if (NORADIO_ENAB(pi->pubpi))
2980 return -1;
2982 if (mode == 1) {
2983 suspend =
2984 (0 ==
2985 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2986 if (!suspend)
2987 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2988 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2990 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
2991 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
2993 if (tempsenseval1 > 255)
2994 avg = (int16) (tempsenseval1 - 512);
2995 else
2996 avg = (int16) tempsenseval1;
2998 if (tempsenseval2 > 255)
2999 avg += (int16) (tempsenseval2 - 512);
3000 else
3001 avg += (int16) tempsenseval2;
3003 avg /= 2;
3005 if (mode == 1) {
3007 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3009 OSL_DELAY(100);
3010 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3012 if (!suspend)
3013 wlapi_enable_mac(pi->sh->physhim);
3015 return avg;
3018 uint16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3020 uint16 tempsenseval1, tempsenseval2;
3021 int32 avg = 0;
3022 bool suspend = 0;
3023 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3024 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3026 if (NORADIO_ENAB(pi->pubpi))
3027 return -1;
3029 if (mode == 1) {
3030 suspend =
3031 (0 ==
3032 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3033 if (!suspend)
3034 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3035 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3037 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3038 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3040 if (tempsenseval1 > 255)
3041 avg = (int)(tempsenseval1 - 512);
3042 else
3043 avg = (int)tempsenseval1;
3045 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
3046 if (tempsenseval2 > 255)
3047 avg = (int)(avg - tempsenseval2 + 512);
3048 else
3049 avg = (int)(avg - tempsenseval2);
3050 } else {
3051 if (tempsenseval2 > 255)
3052 avg = (int)(avg + tempsenseval2 - 512);
3053 else
3054 avg = (int)(avg + tempsenseval2);
3055 avg = avg / 2;
3057 if (avg < 0)
3058 avg = avg + 512;
3060 if (pi_lcn->lcnphy_tempsense_option == 2)
3061 avg = tempsenseval1;
3063 if (mode)
3064 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3066 if (mode == 1) {
3068 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3070 OSL_DELAY(100);
3071 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3073 if (!suspend)
3074 wlapi_enable_mac(pi->sh->physhim);
3076 return (uint16) avg;
3079 int8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
3081 int32 degree = wlc_lcnphy_tempsense_new(pi, mode);
3082 degree =
3083 ((degree << 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
3084 / LCN_TEMPSENSE_DEN;
3085 return (int8) degree;
3088 int8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3090 uint16 vbatsenseval;
3091 int32 avg = 0;
3092 bool suspend = 0;
3094 if (NORADIO_ENAB(pi->pubpi))
3095 return -1;
3097 if (mode == 1) {
3098 suspend =
3099 (0 ==
3100 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3101 if (!suspend)
3102 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3103 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
3106 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
3108 if (vbatsenseval > 255)
3109 avg = (int32) (vbatsenseval - 512);
3110 else
3111 avg = (int32) vbatsenseval;
3113 avg =
3114 (avg * LCN_VBAT_SCALE_NOM +
3115 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
3117 if (mode == 1) {
3118 if (!suspend)
3119 wlapi_enable_mac(pi->sh->physhim);
3121 return (int8) avg;
3124 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, uint8 mode)
3126 uint8 phybw40;
3127 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3129 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
3131 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
3132 (mode == AFE_CLK_INIT_MODE_TXRX2X))
3133 write_phy_reg(pi, 0x6d0, 0x7);
3135 wlc_lcnphy_toggle_afe_pwdn(pi);
3138 static bool
3139 wlc_lcnphy_rx_iq_est(phy_info_t *pi,
3140 uint16 num_samps,
3141 uint8 wait_time, lcnphy_iq_est_t *iq_est)
3143 int wait_count = 0;
3144 bool result = TRUE;
3145 uint8 phybw40;
3146 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3148 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
3150 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
3152 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
3154 mod_phy_reg(pi, 0x481, (0xff << 0), ((uint16) wait_time) << 0);
3156 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
3158 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
3160 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
3162 if (wait_count > (10 * 500)) {
3163 result = FALSE;
3164 goto cleanup;
3166 OSL_DELAY(100);
3167 wait_count++;
3170 iq_est->iq_prod = ((uint32) read_phy_reg(pi, 0x483) << 16) |
3171 (uint32) read_phy_reg(pi, 0x484);
3172 iq_est->i_pwr = ((uint32) read_phy_reg(pi, 0x485) << 16) |
3173 (uint32) read_phy_reg(pi, 0x486);
3174 iq_est->q_pwr = ((uint32) read_phy_reg(pi, 0x487) << 16) |
3175 (uint32) read_phy_reg(pi, 0x488);
3177 cleanup:
3178 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
3180 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
3182 return result;
3185 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, uint16 num_samps)
3187 #define LCNPHY_MIN_RXIQ_PWR 2
3188 bool result;
3189 uint16 a0_new, b0_new;
3190 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3191 int32 a, b, temp;
3192 int16 iq_nbits, qq_nbits, arsh, brsh;
3193 int32 iq;
3194 uint32 ii, qq;
3195 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3197 a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
3198 b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
3199 mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
3201 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
3203 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
3205 if (!(result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est)))
3206 goto cleanup;
3208 iq = (int32) iq_est.iq_prod;
3209 ii = iq_est.i_pwr;
3210 qq = iq_est.q_pwr;
3212 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
3213 result = FALSE;
3214 goto cleanup;
3217 iq_nbits = wlc_phy_nbits(iq);
3218 qq_nbits = wlc_phy_nbits(qq);
3220 arsh = 10 - (30 - iq_nbits);
3221 if (arsh >= 0) {
3222 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
3223 temp = (int32) (ii >> arsh);
3224 if (temp == 0) {
3225 return FALSE;
3227 } else {
3228 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3229 temp = (int32) (ii << -arsh);
3230 if (temp == 0) {
3231 return FALSE;
3234 a /= temp;
3235 brsh = qq_nbits - 31 + 20;
3236 if (brsh >= 0) {
3237 b = (qq << (31 - qq_nbits));
3238 temp = (int32) (ii >> brsh);
3239 if (temp == 0) {
3240 return FALSE;
3242 } else {
3243 b = (qq << (31 - qq_nbits));
3244 temp = (int32) (ii << -brsh);
3245 if (temp == 0) {
3246 return FALSE;
3249 b /= temp;
3250 b -= a * a;
3251 b = (int32) wlc_phy_sqrt_int((uint32) b);
3252 b -= (1 << 10);
3253 a0_new = (uint16) (a & 0x3ff);
3254 b0_new = (uint16) (b & 0x3ff);
3255 cleanup:
3257 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
3259 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
3261 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
3263 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
3264 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
3266 return result;
3269 static bool
3270 wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
3271 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3272 int tx_gain_idx)
3274 lcnphy_txgains_t old_gains;
3275 uint16 tx_pwr_ctrl;
3276 uint8 tx_gain_index_old = 0;
3277 bool result = FALSE, tx_gain_override_old = FALSE;
3278 uint16 i, Core1TxControl_old, RFOverride0_old,
3279 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
3280 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
3281 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
3282 int tia_gain;
3283 uint32 received_power, rx_pwr_threshold;
3284 uint16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3285 uint16 values_to_save[11];
3286 int16 *ptr;
3287 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3289 if (NULL == (ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131))) {
3290 return FALSE;
3292 if (module == 2) {
3293 ASSERT(iqcomp_sz);
3295 while (iqcomp_sz--) {
3296 if (iqcomp[iqcomp_sz].chan ==
3297 CHSPEC_CHANNEL(pi->radio_chanspec)) {
3299 wlc_lcnphy_set_rx_iq_comp(pi,
3300 (uint16)
3301 iqcomp[iqcomp_sz].a,
3302 (uint16)
3303 iqcomp[iqcomp_sz].b);
3304 result = TRUE;
3305 break;
3308 ASSERT(result);
3309 goto cal_done;
3312 if (module == 1) {
3314 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3315 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3317 for (i = 0; i < 11; i++) {
3318 values_to_save[i] =
3319 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
3321 Core1TxControl_old = read_phy_reg(pi, 0x631);
3323 or_phy_reg(pi, 0x631, 0x0015);
3325 RFOverride0_old = read_phy_reg(pi, 0x44c);
3326 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
3327 rfoverride2_old = read_phy_reg(pi, 0x4b0);
3328 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
3329 rfoverride3_old = read_phy_reg(pi, 0x4f9);
3330 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
3331 rfoverride4_old = read_phy_reg(pi, 0x938);
3332 rfoverride4val_old = read_phy_reg(pi, 0x939);
3333 afectrlovr_old = read_phy_reg(pi, 0x43b);
3334 afectrlovrval_old = read_phy_reg(pi, 0x43c);
3335 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3336 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
3338 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
3339 if (tx_gain_override_old) {
3340 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3341 tx_gain_index_old = pi_lcn->lcnphy_current_index;
3344 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
3346 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3347 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3349 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3350 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3352 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
3353 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
3354 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
3355 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
3356 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3357 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
3358 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
3359 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
3360 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
3361 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
3363 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
3364 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
3365 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
3366 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
3367 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
3368 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
3369 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
3370 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
3371 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
3372 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
3374 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3375 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3377 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
3378 write_phy_reg(pi, 0x6da, 0xffff);
3379 or_phy_reg(pi, 0x6db, 0x3);
3380 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
3381 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
3383 tia_gain = 8;
3384 rx_pwr_threshold = 950;
3385 while (tia_gain > 0) {
3386 tia_gain -= 1;
3387 wlc_lcnphy_set_rx_gain_by_distribution(pi,
3388 0, 0, 2, 2,
3389 (uint16)
3390 tia_gain, 1, 0);
3391 OSL_DELAY(500);
3393 received_power =
3394 wlc_lcnphy_measure_digital_power(pi, 2000);
3395 if (received_power < rx_pwr_threshold)
3396 break;
3398 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
3400 wlc_lcnphy_stop_tx_tone(pi);
3402 write_phy_reg(pi, 0x631, Core1TxControl_old);
3404 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
3405 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
3406 write_phy_reg(pi, 0x4b0, rfoverride2_old);
3407 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
3408 write_phy_reg(pi, 0x4f9, rfoverride3_old);
3409 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
3410 write_phy_reg(pi, 0x938, rfoverride4_old);
3411 write_phy_reg(pi, 0x939, rfoverride4val_old);
3412 write_phy_reg(pi, 0x43b, afectrlovr_old);
3413 write_phy_reg(pi, 0x43c, afectrlovrval_old);
3414 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3415 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
3417 wlc_lcnphy_clear_trsw_override(pi);
3419 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
3421 for (i = 0; i < 11; i++) {
3422 write_radio_reg(pi, rxiq_cal_rf_reg[i],
3423 values_to_save[i]);
3426 if (tx_gain_override_old) {
3427 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
3428 } else
3429 wlc_lcnphy_disable_tx_gain_override(pi);
3430 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
3432 wlc_lcnphy_rx_gain_override_enable(pi, FALSE);
3435 cal_done:
3436 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
3437 return result;
3440 static void wlc_lcnphy_temp_adj(phy_info_t *pi)
3442 if (NORADIO_ENAB(pi->pubpi))
3443 return;
3446 static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
3448 bool suspend;
3449 int8 index;
3450 uint16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3451 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3452 suspend =
3453 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3454 if (!suspend)
3455 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3456 wlc_lcnphy_deaf_mode(pi, TRUE);
3457 pi->phy_lastcal = pi->sh->now;
3458 pi->phy_forcecal = FALSE;
3459 index = pi_lcn->lcnphy_current_index;
3461 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3463 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3464 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3465 wlc_lcnphy_deaf_mode(pi, FALSE);
3466 if (!suspend)
3467 wlapi_enable_mac(pi->sh->physhim);
3471 static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
3473 bool suspend, full_cal;
3474 const lcnphy_rx_iqcomp_t *rx_iqcomp;
3475 int rx_iqcomp_sz;
3476 uint16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3477 int8 index;
3478 phytbl_info_t tab;
3479 int32 a1, b0, b1;
3480 int32 tssi, pwr, maxtargetpwr, mintargetpwr;
3481 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3483 if (NORADIO_ENAB(pi->pubpi))
3484 return;
3486 pi->phy_lastcal = pi->sh->now;
3487 pi->phy_forcecal = FALSE;
3488 full_cal =
3489 (pi_lcn->lcnphy_full_cal_channel !=
3490 CHSPEC_CHANNEL(pi->radio_chanspec));
3491 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
3492 index = pi_lcn->lcnphy_current_index;
3494 suspend =
3495 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3496 if (!suspend) {
3498 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
3499 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3501 wlc_lcnphy_deaf_mode(pi, TRUE);
3503 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3505 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
3506 rx_iqcomp_sz = ARRAYSIZE(lcnphy_rx_iqcomp_table_rev0);
3508 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
3509 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, TRUE, FALSE, 1, 40);
3510 else
3511 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, TRUE, FALSE, 1, 127);
3513 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
3515 wlc_lcnphy_idle_tssi_est((wlc_phy_t *) pi);
3517 b0 = pi->txpa_2g[0];
3518 b1 = pi->txpa_2g[1];
3519 a1 = pi->txpa_2g[2];
3520 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3521 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3523 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3524 tab.tbl_width = 32;
3525 tab.tbl_ptr = &pwr;
3526 tab.tbl_len = 1;
3527 tab.tbl_offset = 0;
3528 for (tssi = 0; tssi < 128; tssi++) {
3529 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3530 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3531 wlc_lcnphy_write_table(pi, &tab);
3532 tab.tbl_offset++;
3536 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3537 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3538 wlc_lcnphy_deaf_mode(pi, FALSE);
3539 if (!suspend)
3540 wlapi_enable_mac(pi->sh->physhim);
3543 void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
3545 uint16 temp_new;
3546 int temp1, temp2, temp_diff;
3547 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3549 switch (mode) {
3550 case PHY_PERICAL_CHAN:
3552 break;
3553 case PHY_FULLCAL:
3554 wlc_lcnphy_periodic_cal(pi);
3555 break;
3556 case PHY_PERICAL_PHYINIT:
3557 wlc_lcnphy_periodic_cal(pi);
3558 break;
3559 case PHY_PERICAL_WATCHDOG:
3560 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3561 temp_new = wlc_lcnphy_tempsense(pi, 0);
3562 temp1 = LCNPHY_TEMPSENSE(temp_new);
3563 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
3564 temp_diff = temp1 - temp2;
3565 if ((pi_lcn->lcnphy_cal_counter > 90) ||
3566 (temp_diff > 60) || (temp_diff < -60)) {
3567 wlc_lcnphy_glacial_timer_based_cal(pi);
3568 wlc_2064_vco_cal(pi);
3569 pi_lcn->lcnphy_cal_temper = temp_new;
3570 pi_lcn->lcnphy_cal_counter = 0;
3571 } else
3572 pi_lcn->lcnphy_cal_counter++;
3574 break;
3575 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
3576 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3577 wlc_lcnphy_tx_power_adjustment((wlc_phy_t *) pi);
3578 break;
3579 default:
3580 ASSERT(0);
3581 break;
3585 void wlc_lcnphy_get_tssi(phy_info_t *pi, int8 *ofdm_pwr, int8 *cck_pwr)
3587 int8 cck_offset;
3588 uint16 status;
3589 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
3590 ((status = (read_phy_reg(pi, 0x4ab))) & (0x1 << 15))) {
3591 *ofdm_pwr = (int8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
3592 >> 0) >> 1);
3594 if (wlc_phy_tpc_isenabled_lcnphy(pi))
3595 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
3596 else
3597 cck_offset = 0;
3599 *cck_pwr = *ofdm_pwr + cck_offset;
3600 } else {
3601 *cck_pwr = 0;
3602 *ofdm_pwr = 0;
3606 void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi) {
3607 return;
3611 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
3613 uint8 channel = CHSPEC_CHANNEL(chanspec);
3614 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3616 if (NORADIO_ENAB(pi->pubpi))
3617 return;
3619 if (channel == 14) {
3620 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
3622 } else {
3623 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
3626 pi_lcn->lcnphy_bandedge_corr = 2;
3627 if (channel == 1)
3628 pi_lcn->lcnphy_bandedge_corr = 4;
3630 if (channel == 1 || channel == 2 || channel == 3 ||
3631 channel == 4 || channel == 9 ||
3632 channel == 10 || channel == 11 || channel == 12) {
3633 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
3634 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
3635 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
3637 si_pmu_pllupd(pi->sh->sih);
3638 write_phy_reg(pi, 0x942, 0);
3639 wlc_lcnphy_txrx_spur_avoidance_mode(pi, FALSE);
3640 pi_lcn->lcnphy_spurmod = 0;
3641 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
3643 write_phy_reg(pi, 0x425, 0x5907);
3644 } else {
3645 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
3646 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
3647 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
3649 si_pmu_pllupd(pi->sh->sih);
3650 write_phy_reg(pi, 0x942, 0);
3651 wlc_lcnphy_txrx_spur_avoidance_mode(pi, TRUE);
3653 pi_lcn->lcnphy_spurmod = 0;
3654 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
3656 write_phy_reg(pi, 0x425, 0x590a);
3659 or_phy_reg(pi, 0x44a, 0x44);
3660 write_phy_reg(pi, 0x44a, 0x80);
3663 void
3664 wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng, uint8 rate,
3665 struct ether_addr *sa, uint32 wait_delay)
3669 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3671 int8 index;
3672 uint16 index2;
3673 phy_info_t *pi = (phy_info_t *) ppi;
3674 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3675 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3676 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3677 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3678 index2 = (uint16) (index * 2);
3679 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3681 pi_lcn->lcnphy_current_index = (int8)
3682 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3686 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 b)
3688 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3690 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3692 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3694 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3696 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3698 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3702 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi) {
3703 uint8 phybw40;
3704 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3705 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3707 pi_lcn->lcnphy_cal_counter = 0;
3708 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3710 or_phy_reg(pi, 0x44a, 0x80);
3711 and_phy_reg(pi, 0x44a, 0x7f);
3713 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3715 write_phy_reg(pi, 0x60a, 160);
3717 write_phy_reg(pi, 0x46a, 25);
3719 wlc_lcnphy_baseband_init(pi);
3721 wlc_lcnphy_radio_init(pi);
3723 if (CHSPEC_IS2G(pi->radio_chanspec))
3724 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3726 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3728 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3730 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3732 if ((pi->sh->boardflags & BFL_FEM)
3733 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3734 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
3736 wlc_lcnphy_agc_temp_init(pi);
3738 wlc_lcnphy_temp_adj(pi);
3740 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3742 OSL_DELAY(100);
3743 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3745 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3746 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
3747 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
3750 static void
3751 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, uint16 *values_to_save)
3753 uint16 vmid;
3754 int i;
3755 for (i = 0; i < 20; i++) {
3756 values_to_save[i] =
3757 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
3760 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3761 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3763 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3764 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3766 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3767 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3769 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3770 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3772 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
3773 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
3774 else
3775 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
3776 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
3778 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3779 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3780 OSL_DELAY(20);
3782 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3783 if (CHSPEC_IS5G(pi->radio_chanspec))
3784 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
3785 else
3786 or_radio_reg(pi, RADIO_2064_REG03A, 1);
3787 } else {
3788 if (CHSPEC_IS5G(pi->radio_chanspec))
3789 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
3790 else
3791 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
3794 OSL_DELAY(20);
3796 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
3797 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3798 if (CHSPEC_IS5G(pi->radio_chanspec))
3799 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
3800 else
3801 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
3802 } else {
3803 if (CHSPEC_IS5G(pi->radio_chanspec))
3804 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
3805 else
3806 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
3809 OSL_DELAY(20);
3811 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3812 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3813 OSL_DELAY(20);
3815 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3816 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3817 OSL_DELAY(20);
3819 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3820 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3821 OSL_DELAY(20);
3823 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3824 OSL_DELAY(20);
3826 vmid = 0x2A6;
3827 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
3828 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
3829 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3830 OSL_DELAY(20);
3832 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3833 OSL_DELAY(20);
3834 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
3835 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
3836 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
3837 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
3838 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
3839 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
3840 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
3843 static void
3844 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, uint16 thresh,
3845 int16 *ptr, int mode)
3847 uint32 curval1, curval2, stpptr, curptr, strptr, val;
3848 uint16 sslpnCalibClkEnCtrl, timer;
3849 uint16 old_sslpnCalibClkEnCtrl;
3850 int16 imag, real;
3851 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3853 timer = 0;
3854 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3856 curval1 = R_REG(pi->sh->osh, &pi->regs->psm_corectlsts);
3857 ptr[130] = 0;
3858 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, ((1 << 6) | curval1));
3860 W_REG(pi->sh->osh, &pi->regs->smpl_clct_strptr, 0x7E00);
3861 W_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr, 0x8000);
3862 OSL_DELAY(20);
3863 curval2 = R_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param);
3864 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2 | 0x30);
3866 write_phy_reg(pi, 0x555, 0x0);
3867 write_phy_reg(pi, 0x5a6, 0x5);
3869 write_phy_reg(pi, 0x5a2, (uint16) (mode | mode << 6));
3870 write_phy_reg(pi, 0x5cf, 3);
3871 write_phy_reg(pi, 0x5a5, 0x3);
3872 write_phy_reg(pi, 0x583, 0x0);
3873 write_phy_reg(pi, 0x584, 0x0);
3874 write_phy_reg(pi, 0x585, 0x0fff);
3875 write_phy_reg(pi, 0x586, 0x0000);
3877 write_phy_reg(pi, 0x580, 0x4501);
3879 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3880 write_phy_reg(pi, 0x6da, (uint32) (sslpnCalibClkEnCtrl | 0x2008));
3881 stpptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr);
3882 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3883 do {
3884 OSL_DELAY(10);
3885 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3886 timer++;
3887 } while ((curptr != stpptr) && (timer < 500));
3889 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, 0x2);
3890 strptr = 0x7E00;
3891 W_REG(pi->sh->osh, &pi->regs->tplatewrptr, strptr);
3892 while (strptr < 0x8000) {
3893 val = R_REG(pi->sh->osh, &pi->regs->tplatewrdata);
3894 imag = ((val >> 16) & 0x3ff);
3895 real = ((val) & 0x3ff);
3896 if (imag > 511) {
3897 imag -= 1024;
3899 if (real > 511) {
3900 real -= 1024;
3902 if (pi_lcn->lcnphy_iqcal_swp_dis)
3903 ptr[(strptr - 0x7E00) / 4] = real;
3904 else
3905 ptr[(strptr - 0x7E00) / 4] = imag;
3906 if (clip_detect_algo) {
3907 if (imag > thresh || imag < -thresh) {
3908 strptr = 0x8000;
3909 ptr[130] = 1;
3912 strptr += 4;
3915 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3916 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2);
3917 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, curval1);
3920 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
3922 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3924 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3925 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3926 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3927 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3929 wlc_lcnphy_a1(pi, 4, 0, 0);
3930 wlc_lcnphy_a1(pi, 3, 0, 0);
3931 wlc_lcnphy_a1(pi, 2, 3, 2);
3932 wlc_lcnphy_a1(pi, 0, 5, 8);
3933 wlc_lcnphy_a1(pi, 2, 2, 1);
3934 wlc_lcnphy_a1(pi, 0, 4, 3);
3936 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3937 locc2 = wlc_lcnphy_get_cc(pi, 2);
3938 locc3 = wlc_lcnphy_get_cc(pi, 3);
3939 locc4 = wlc_lcnphy_get_cc(pi, 4);
3942 static void
3943 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x, int16 coeff_y)
3945 uint16 di0dq0;
3946 uint16 x, y, data_rf;
3947 int k;
3948 switch (cal_type) {
3949 case 0:
3950 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3951 break;
3952 case 2:
3953 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3954 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3955 break;
3956 case 3:
3957 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3958 y = 8 + k;
3959 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3960 x = 8 - k;
3961 data_rf = (x * 16 + y);
3962 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3963 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3964 y = 8 + k;
3965 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3966 x = 8 - k;
3967 data_rf = (x * 16 + y);
3968 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3969 break;
3970 case 4:
3971 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3972 y = 8 + k;
3973 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3974 x = 8 - k;
3975 data_rf = (x * 16 + y);
3976 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3977 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3978 y = 8 + k;
3979 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3980 x = 8 - k;
3981 data_rf = (x * 16 + y);
3982 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3983 break;
3987 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3989 uint16 a, b, didq;
3990 uint8 di0, dq0, ei, eq, fi, fq;
3991 lcnphy_unsign16_struct cc;
3992 cc.re = 0;
3993 cc.im = 0;
3994 switch (cal_type) {
3995 case 0:
3996 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3997 cc.re = a;
3998 cc.im = b;
3999 break;
4000 case 2:
4001 didq = wlc_lcnphy_get_tx_locc(pi);
4002 di0 = (((didq & 0xff00) << 16) >> 24);
4003 dq0 = (((didq & 0x00ff) << 24) >> 24);
4004 cc.re = (uint16) di0;
4005 cc.im = (uint16) dq0;
4006 break;
4007 case 3:
4008 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4009 cc.re = (uint16) ei;
4010 cc.im = (uint16) eq;
4011 break;
4012 case 4:
4013 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4014 cc.re = (uint16) fi;
4015 cc.im = (uint16) fq;
4016 break;
4018 return cc;
4021 static void
4022 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
4024 const lcnphy_spb_tone_t *phy_c1;
4025 lcnphy_spb_tone_t phy_c2;
4026 lcnphy_unsign16_struct phy_c3;
4027 int phy_c4, phy_c5, k, l, j, phy_c6;
4028 uint16 phy_c7, phy_c8, phy_c9;
4029 int16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4030 int16 *ptr, phy_c17;
4031 int32 phy_c18, phy_c19;
4032 uint32 phy_c20, phy_c21;
4033 bool phy_c22, phy_c23, phy_c24, phy_c25;
4034 uint16 phy_c26, phy_c27;
4035 uint16 phy_c28, phy_c29, phy_c30;
4036 uint16 phy_c31;
4037 uint16 *phy_c32;
4038 phy_c21 = 0;
4039 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4040 if (NULL == (ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131))) {
4041 return;
4044 if (NULL == (phy_c32 = MALLOC(pi->sh->osh, sizeof(uint16) * 20))) {
4045 return;
4047 phy_c26 = read_phy_reg(pi, 0x6da);
4048 phy_c27 = read_phy_reg(pi, 0x6db);
4049 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
4050 write_phy_reg(pi, 0x93d, 0xC0);
4052 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
4053 write_phy_reg(pi, 0x6da, 0xffff);
4054 or_phy_reg(pi, 0x6db, 0x3);
4056 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
4057 OSL_DELAY(500);
4058 phy_c28 = read_phy_reg(pi, 0x938);
4059 phy_c29 = read_phy_reg(pi, 0x4d7);
4060 phy_c30 = read_phy_reg(pi, 0x4d8);
4061 or_phy_reg(pi, 0x938, 0x1 << 2);
4062 or_phy_reg(pi, 0x4d7, 0x1 << 2);
4063 or_phy_reg(pi, 0x4d7, 0x1 << 3);
4064 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
4065 or_phy_reg(pi, 0x4d8, 1 << 0);
4066 or_phy_reg(pi, 0x4d8, 1 << 1);
4067 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
4068 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
4069 phy_c1 = &lcnphy_spb_tone_3750[0];
4070 phy_c4 = 32;
4072 if (num_levels == 0) {
4073 if (cal_type != 0) {
4074 num_levels = 4;
4075 } else {
4076 num_levels = 9;
4079 if (step_size_lg2 == 0) {
4080 if (cal_type != 0) {
4081 step_size_lg2 = 3;
4082 } else {
4083 step_size_lg2 = 8;
4087 phy_c7 = (1 << step_size_lg2);
4088 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
4089 phy_c15 = (int16) phy_c3.re;
4090 phy_c16 = (int16) phy_c3.im;
4091 if (cal_type == 2) {
4092 if (phy_c3.re > 127)
4093 phy_c15 = phy_c3.re - 256;
4094 if (phy_c3.im > 127)
4095 phy_c16 = phy_c3.im - 256;
4097 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4098 OSL_DELAY(20);
4099 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
4100 phy_c23 = 1;
4101 phy_c22 = 0;
4102 switch (cal_type) {
4103 case 0:
4104 phy_c10 = 511;
4105 break;
4106 case 2:
4107 phy_c10 = 127;
4108 break;
4109 case 3:
4110 phy_c10 = 15;
4111 break;
4112 case 4:
4113 phy_c10 = 15;
4114 break;
4117 phy_c9 = read_phy_reg(pi, 0x93d);
4118 phy_c9 = 2 * phy_c9;
4119 phy_c24 = 0;
4120 phy_c5 = 7;
4121 phy_c25 = 1;
4122 while (1) {
4123 write_radio_reg(pi, RADIO_2064_REG026,
4124 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
4125 OSL_DELAY(50);
4126 phy_c22 = 0;
4127 ptr[130] = 0;
4128 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
4129 if (ptr[130] == 1)
4130 phy_c22 = 1;
4131 if (phy_c22)
4132 phy_c5 -= 1;
4133 if ((phy_c22 != phy_c24) && (!phy_c25))
4134 break;
4135 if (!phy_c22)
4136 phy_c5 += 1;
4137 if (phy_c5 <= 0 || phy_c5 >= 7)
4138 break;
4139 phy_c24 = phy_c22;
4140 phy_c25 = 0;
4143 if (phy_c5 < 0)
4144 phy_c5 = 0;
4145 else if (phy_c5 > 7)
4146 phy_c5 = 7;
4148 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
4149 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
4150 phy_c11 = phy_c15 + k;
4151 phy_c12 = phy_c16 + l;
4153 if (phy_c11 < -phy_c10)
4154 phy_c11 = -phy_c10;
4155 else if (phy_c11 > phy_c10)
4156 phy_c11 = phy_c10;
4157 if (phy_c12 < -phy_c10)
4158 phy_c12 = -phy_c10;
4159 else if (phy_c12 > phy_c10)
4160 phy_c12 = phy_c10;
4161 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
4162 phy_c12);
4163 OSL_DELAY(20);
4164 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
4166 phy_c18 = 0;
4167 phy_c19 = 0;
4168 for (j = 0; j < 128; j++) {
4169 if (cal_type != 0) {
4170 phy_c6 = j % phy_c4;
4171 } else {
4172 phy_c6 = (2 * j) % phy_c4;
4174 phy_c2.re = phy_c1[phy_c6].re;
4175 phy_c2.im = phy_c1[phy_c6].im;
4176 phy_c17 = ptr[j];
4177 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
4178 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
4181 phy_c18 = phy_c18 >> 10;
4182 phy_c19 = phy_c19 >> 10;
4183 phy_c20 =
4184 ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
4186 if (phy_c23 || phy_c20 < phy_c21) {
4187 phy_c21 = phy_c20;
4188 phy_c13 = phy_c11;
4189 phy_c14 = phy_c12;
4191 phy_c23 = 0;
4194 phy_c23 = 1;
4195 phy_c15 = phy_c13;
4196 phy_c16 = phy_c14;
4197 phy_c7 = phy_c7 >> 1;
4198 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4199 OSL_DELAY(20);
4201 goto cleanup;
4202 cleanup:
4203 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
4204 wlc_lcnphy_stop_tx_tone(pi);
4205 write_phy_reg(pi, 0x6da, phy_c26);
4206 write_phy_reg(pi, 0x6db, phy_c27);
4207 write_phy_reg(pi, 0x938, phy_c28);
4208 write_phy_reg(pi, 0x4d7, phy_c29);
4209 write_phy_reg(pi, 0x4d8, phy_c30);
4210 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
4212 MFREE(pi->sh->osh, phy_c32, 20 * sizeof(uint16));
4213 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
4216 static void
4217 wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, uint16 *values_to_save)
4219 int i;
4221 and_phy_reg(pi, 0x44c, 0x0 >> 11);
4223 and_phy_reg(pi, 0x43b, 0xC);
4225 for (i = 0; i < 20; i++) {
4226 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
4227 values_to_save[i]);
4231 static void
4232 WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
4233 const lcnphy_tx_gain_tbl_entry *
4234 gain_table) {
4235 uint32 j;
4236 phytbl_info_t tab;
4237 uint32 val;
4238 uint16 pa_gain;
4239 uint16 gm_gain;
4241 if (CHSPEC_IS5G(pi->radio_chanspec))
4242 pa_gain = 0x70;
4243 else
4244 pa_gain = 0x70;
4246 if (pi->sh->boardflags & BFL_FEM)
4247 pa_gain = 0x10;
4248 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4249 tab.tbl_width = 32;
4250 tab.tbl_len = 1;
4251 tab.tbl_ptr = &val;
4253 for (j = 0; j < 128; j++) {
4254 gm_gain = gain_table[j].gm;
4255 val = (((uint32) pa_gain << 24) |
4256 (gain_table[j].pad << 16) |
4257 (gain_table[j].pga << 8) | gm_gain);
4259 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4260 wlc_lcnphy_write_table(pi, &tab);
4262 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4263 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4264 wlc_lcnphy_write_table(pi, &tab);
4268 static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
4270 phytbl_info_t tab;
4271 uint32 val, bbmult, rfgain;
4272 uint8 index;
4273 uint8 scale_factor = 1;
4274 int16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4276 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4277 tab.tbl_width = 32;
4278 tab.tbl_len = 1;
4280 for (index = 0; index < 128; index++) {
4281 tab.tbl_ptr = &bbmult;
4282 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4283 wlc_lcnphy_read_table(pi, &tab);
4284 bbmult = bbmult >> 20;
4286 tab.tbl_ptr = &rfgain;
4287 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4288 wlc_lcnphy_read_table(pi, &tab);
4290 qm_log10((int32) (bbmult), 0, &temp1, &qQ1);
4291 qm_log10((int32) (1 << 6), 0, &temp2, &qQ2);
4293 if (qQ1 < qQ2) {
4294 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4295 qQ = qQ1;
4296 } else {
4297 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4298 qQ = qQ2;
4300 temp = qm_sub16(temp1, temp2);
4302 if (qQ >= 4)
4303 shift = qQ - 4;
4304 else
4305 shift = 4 - qQ;
4307 val = (((index << shift) + (5 * temp) +
4308 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4309 shift - 2));
4311 tab.tbl_ptr = &val;
4312 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4313 wlc_lcnphy_write_table(pi, &tab);
4317 static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi) {
4318 uint idx;
4319 uint8 phybw40;
4320 phytbl_info_t tab;
4321 uint32 val;
4323 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4325 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
4326 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4329 if (pi->sh->boardflags & BFL_FEM_BT) {
4330 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4331 tab.tbl_width = 16;
4332 tab.tbl_ptr = &val;
4333 tab.tbl_len = 1;
4334 val = 100;
4335 tab.tbl_offset = 4;
4336 wlc_lcnphy_write_table(pi, &tab);
4339 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4340 tab.tbl_width = 16;
4341 tab.tbl_ptr = &val;
4342 tab.tbl_len = 1;
4344 val = 114;
4345 tab.tbl_offset = 0;
4346 wlc_lcnphy_write_table(pi, &tab);
4348 val = 130;
4349 tab.tbl_offset = 1;
4350 wlc_lcnphy_write_table(pi, &tab);
4352 val = 6;
4353 tab.tbl_offset = 8;
4354 wlc_lcnphy_write_table(pi, &tab);
4356 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4357 if (pi->sh->boardflags & BFL_FEM)
4358 wlc_lcnphy_load_tx_gain_table(pi,
4359 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4360 else
4361 wlc_lcnphy_load_tx_gain_table(pi,
4362 dot11lcnphy_2GHz_gaintable_rev0);
4365 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4366 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4367 for (idx = 0;
4368 idx < dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4369 idx++)
4370 if (pi->sh->boardflags & BFL_EXTLNA)
4371 wlc_lcnphy_write_table(pi,
4372 &dot11lcnphytbl_rx_gain_info_extlna_2G_rev2
4373 [idx]);
4374 else
4375 wlc_lcnphy_write_table(pi,
4376 &dot11lcnphytbl_rx_gain_info_2G_rev2
4377 [idx]);
4378 } else {
4379 for (idx = 0;
4380 idx < dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4381 idx++)
4382 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4383 wlc_lcnphy_write_table(pi,
4384 &dot11lcnphytbl_rx_gain_info_extlna_5G_rev2
4385 [idx]);
4386 else
4387 wlc_lcnphy_write_table(pi,
4388 &dot11lcnphytbl_rx_gain_info_5G_rev2
4389 [idx]);
4393 if ((pi->sh->boardflags & BFL_FEM)
4394 && !(pi->sh->boardflags & BFL_FEM_BT))
4395 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4396 else if (pi->sh->boardflags & BFL_FEM_BT) {
4397 if (pi->sh->boardrev < 0x1250)
4398 wlc_lcnphy_write_table(pi,
4399 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4400 else
4401 wlc_lcnphy_write_table(pi,
4402 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4403 } else
4404 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4406 wlc_lcnphy_load_rfpower(pi);
4408 wlc_lcnphy_clear_papd_comptable(pi);
4411 static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi) {
4412 uint16 afectrl1;
4413 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4415 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4417 write_phy_reg(pi, 0x43b, 0x0);
4418 write_phy_reg(pi, 0x43c, 0x0);
4419 write_phy_reg(pi, 0x44c, 0x0);
4420 write_phy_reg(pi, 0x4e6, 0x0);
4421 write_phy_reg(pi, 0x4f9, 0x0);
4422 write_phy_reg(pi, 0x4b0, 0x0);
4423 write_phy_reg(pi, 0x938, 0x0);
4424 write_phy_reg(pi, 0x4b0, 0x0);
4425 write_phy_reg(pi, 0x44e, 0);
4427 or_phy_reg(pi, 0x567, 0x03);
4429 or_phy_reg(pi, 0x44a, 0x44);
4430 write_phy_reg(pi, 0x44a, 0x80);
4432 if (!(pi->sh->boardflags & BFL_FEM))
4433 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4435 if (0) {
4436 afectrl1 = 0;
4437 afectrl1 = (uint16) ((pi_lcn->lcnphy_rssi_vf) |
4438 (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4439 lcnphy_rssi_gs
4440 << 10));
4441 write_phy_reg(pi, 0x43e, afectrl1);
4444 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4445 if (pi->sh->boardflags & BFL_FEM) {
4446 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4448 write_phy_reg(pi, 0x910, 0x1);
4451 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4452 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4453 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4457 static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi) {
4458 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4459 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4461 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4465 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
4467 int16 temp;
4468 phytbl_info_t tab;
4469 uint32 tableBuffer[2];
4470 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4472 if (NORADIO_ENAB(pi->pubpi))
4473 return;
4475 temp = (int16) read_phy_reg(pi, 0x4df);
4476 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4478 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4479 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4481 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4483 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4484 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4486 tab.tbl_ptr = tableBuffer;
4487 tab.tbl_len = 2;
4488 tab.tbl_id = 17;
4489 tab.tbl_offset = 59;
4490 tab.tbl_width = 32;
4491 wlc_lcnphy_read_table(pi, &tab);
4493 if (tableBuffer[0] > 63)
4494 tableBuffer[0] -= 128;
4495 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4497 if (tableBuffer[1] > 63)
4498 tableBuffer[1] -= 128;
4499 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4501 temp = (int16) (read_phy_reg(pi, 0x434)
4502 & (0xff << 0));
4503 if (temp > 127)
4504 temp -= 256;
4505 pi_lcn->lcnphy_input_pwr_offset_db = (int8) temp;
4507 pi_lcn->lcnphy_Med_Low_Gain_db = (read_phy_reg(pi, 0x424)
4508 & (0xff << 8))
4509 >> 8;
4510 pi_lcn->lcnphy_Very_Low_Gain_db = (read_phy_reg(pi, 0x425)
4511 & (0xff << 0))
4512 >> 0;
4514 tab.tbl_ptr = tableBuffer;
4515 tab.tbl_len = 2;
4516 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4517 tab.tbl_offset = 28;
4518 tab.tbl_width = 32;
4519 wlc_lcnphy_read_table(pi, &tab);
4521 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4522 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4526 static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi) {
4527 if (NORADIO_ENAB(pi->pubpi))
4528 return;
4530 or_phy_reg(pi, 0x805, 0x1);
4532 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4534 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4536 write_phy_reg(pi, 0x414, 0x1e10);
4537 write_phy_reg(pi, 0x415, 0x0640);
4539 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4541 or_phy_reg(pi, 0x44a, 0x44);
4542 write_phy_reg(pi, 0x44a, 0x80);
4543 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4545 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4547 if (!(pi->sh->boardrev < 0x1204))
4548 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4550 write_phy_reg(pi, 0x7d6, 0x0902);
4551 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4553 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4555 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4556 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4558 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4560 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4562 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4564 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4566 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4567 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4568 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4569 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4570 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4572 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4574 wlc_lcnphy_clear_tx_power_offsets(pi);
4575 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4580 static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi) {
4582 wlc_lcnphy_tbl_init(pi);
4583 wlc_lcnphy_rev0_baseband_init(pi);
4584 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4585 wlc_lcnphy_rev2_baseband_init(pi);
4586 wlc_lcnphy_bu_tweaks(pi);
4589 static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi) {
4590 uint32 i;
4591 lcnphy_radio_regs_t *lcnphyregs = NULL;
4593 lcnphyregs = lcnphy_radio_regs_2064;
4595 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4596 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4597 write_radio_reg(pi,
4598 ((lcnphyregs[i].address & 0x3fff) |
4599 RADIO_DEFAULT_CORE),
4600 (uint16) lcnphyregs[i].init_a);
4601 else if (lcnphyregs[i].do_init_g)
4602 write_radio_reg(pi,
4603 ((lcnphyregs[i].address & 0x3fff) |
4604 RADIO_DEFAULT_CORE),
4605 (uint16) lcnphyregs[i].init_g);
4607 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4608 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4610 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4612 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4614 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4616 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4617 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4618 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4621 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4622 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4624 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4626 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4628 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4630 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4632 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4634 write_phy_reg(pi, 0x4ea, 0x4688);
4636 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4638 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4640 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4642 wlc_lcnphy_set_tx_locc(pi, 0);
4644 wlc_lcnphy_rcal(pi);
4646 wlc_lcnphy_rc_cal(pi);
4649 static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi) {
4650 if (NORADIO_ENAB(pi->pubpi))
4651 return;
4653 wlc_radio_2064_init(pi);
4656 static void wlc_lcnphy_rcal(phy_info_t *pi)
4658 uint8 rcal_value;
4660 if (NORADIO_ENAB(pi->pubpi))
4661 return;
4663 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4665 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4666 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4668 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4669 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4671 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4673 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4674 OSL_DELAY(5000);
4675 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4677 if (wlc_radio_2064_rcal_done(pi)) {
4678 rcal_value = (uint8) read_radio_reg(pi, RADIO_2064_REG05C);
4679 rcal_value = rcal_value & 0x1f;
4682 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4684 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4687 static void wlc_lcnphy_rc_cal(phy_info_t *pi)
4689 uint8 dflt_rc_cal_val;
4690 uint16 flt_val;
4692 if (NORADIO_ENAB(pi->pubpi))
4693 return;
4695 dflt_rc_cal_val = 7;
4696 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4697 dflt_rc_cal_val = 11;
4698 flt_val =
4699 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4700 (dflt_rc_cal_val);
4701 write_phy_reg(pi, 0x933, flt_val);
4702 write_phy_reg(pi, 0x934, flt_val);
4703 write_phy_reg(pi, 0x935, flt_val);
4704 write_phy_reg(pi, 0x936, flt_val);
4705 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4707 return;
4710 static bool BCMATTACHFN(wlc_phy_txpwr_srom_read_lcnphy) (phy_info_t *pi) {
4711 int8 txpwr = 0;
4712 int i;
4713 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4715 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4716 uint16 cckpo = 0;
4717 uint32 offset_ofdm, offset_mcs;
4719 pi_lcn->lcnphy_tr_isolation_mid =
4720 (uint8) PHY_GETINTVAR(pi, "triso2g");
4722 pi_lcn->lcnphy_rx_power_offset =
4723 (uint8) PHY_GETINTVAR(pi, "rxpo2g");
4725 pi->txpa_2g[0] = (int16) PHY_GETINTVAR(pi, "pa0b0");
4726 pi->txpa_2g[1] = (int16) PHY_GETINTVAR(pi, "pa0b1");
4727 pi->txpa_2g[2] = (int16) PHY_GETINTVAR(pi, "pa0b2");
4729 pi_lcn->lcnphy_rssi_vf = (uint8) PHY_GETINTVAR(pi, "rssismf2g");
4730 pi_lcn->lcnphy_rssi_vc = (uint8) PHY_GETINTVAR(pi, "rssismc2g");
4731 pi_lcn->lcnphy_rssi_gs = (uint8) PHY_GETINTVAR(pi, "rssisav2g");
4734 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4735 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4736 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4738 pi_lcn->lcnphy_rssi_vf_hightemp =
4739 pi_lcn->lcnphy_rssi_vf;
4740 pi_lcn->lcnphy_rssi_vc_hightemp =
4741 pi_lcn->lcnphy_rssi_vc;
4742 pi_lcn->lcnphy_rssi_gs_hightemp =
4743 pi_lcn->lcnphy_rssi_gs;
4746 txpwr = (int8) PHY_GETINTVAR(pi, "maxp2ga0");
4747 pi->tx_srom_max_2g = txpwr;
4749 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4750 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4751 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4754 cckpo = (uint16) PHY_GETINTVAR(pi, "cck2gpo");
4755 if (cckpo) {
4756 uint max_pwr_chan = txpwr;
4758 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4759 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4760 ((cckpo & 0xf) * 2);
4761 cckpo >>= 4;
4764 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4765 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4766 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4767 ((offset_ofdm & 0xf) * 2);
4768 offset_ofdm >>= 4;
4770 } else {
4771 uint8 opo = 0;
4773 opo = (uint8) PHY_GETINTVAR(pi, "opo");
4775 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4776 pi->tx_srom_max_rate_2g[i] = txpwr;
4779 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4781 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4782 pi->tx_srom_max_rate_2g[i] = txpwr -
4783 ((offset_ofdm & 0xf) * 2);
4784 offset_ofdm >>= 4;
4786 offset_mcs =
4787 ((uint16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4788 (uint16) PHY_GETINTVAR(pi, "mcs2gpo0");
4789 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4790 for (i = TXP_FIRST_SISO_MCS_20;
4791 i <= TXP_LAST_SISO_MCS_20; i++) {
4792 pi->tx_srom_max_rate_2g[i] =
4793 txpwr - ((offset_mcs & 0xf) * 2);
4794 offset_mcs >>= 4;
4798 pi_lcn->lcnphy_rawtempsense =
4799 (uint16) PHY_GETINTVAR(pi, "rawtempsense");
4800 pi_lcn->lcnphy_measPower =
4801 (uint8) PHY_GETINTVAR(pi, "measpower");
4802 pi_lcn->lcnphy_tempsense_slope =
4803 (uint8) PHY_GETINTVAR(pi, "tempsense_slope");
4804 pi_lcn->lcnphy_hw_iqcal_en =
4805 (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
4806 pi_lcn->lcnphy_iqcal_swp_dis =
4807 (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
4808 pi_lcn->lcnphy_tempcorrx =
4809 (uint8) PHY_GETINTVAR(pi, "tempcorrx");
4810 pi_lcn->lcnphy_tempsense_option =
4811 (uint8) PHY_GETINTVAR(pi, "tempsense_option");
4812 pi_lcn->lcnphy_freqoffset_corr =
4813 (uint8) PHY_GETINTVAR(pi, "freqoffset_corr");
4814 if ((uint8) getintvar(pi->vars, "aa2g") > 1)
4815 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
4816 (uint8) getintvar(pi->vars,
4817 "aa2g"));
4819 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4820 if (PHY_GETVAR(pi, "cckdigfilttype")) {
4821 int16 temp;
4822 temp = (int16) PHY_GETINTVAR(pi, "cckdigfilttype");
4823 if (temp >= 0) {
4824 pi_lcn->lcnphy_cck_dig_filt_type = temp;
4828 return TRUE;
4831 void wlc_2064_vco_cal(phy_info_t *pi)
4833 uint8 calnrst;
4835 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4836 calnrst = (uint8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4837 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4838 OSL_DELAY(1);
4839 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4840 OSL_DELAY(1);
4841 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4842 OSL_DELAY(300);
4843 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4846 static void
4847 wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, uint8 channel)
4849 uint i;
4850 const chan_info_2064_lcnphy_t *ci;
4851 uint8 rfpll_doubler = 0;
4852 uint8 pll_pwrup, pll_pwrup_ovr;
4853 fixed qFxtal, qFref, qFvco, qFcal;
4854 uint8 d15, d16, f16, e44, e45;
4855 uint32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
4856 uint16 loop_bw, d30, setCount;
4857 if (NORADIO_ENAB(pi->pubpi))
4858 return;
4859 ci = &chan_info_2064_lcnphy[0];
4860 rfpll_doubler = 1;
4862 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
4864 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
4865 if (!rfpll_doubler) {
4866 loop_bw = PLL_2064_LOOP_BW;
4867 d30 = PLL_2064_D30;
4868 } else {
4869 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
4870 d30 = PLL_2064_D30_DOUBLER;
4873 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4874 for (i = 0; i < ARRAYSIZE(chan_info_2064_lcnphy); i++)
4875 if (chan_info_2064_lcnphy[i].chan == channel)
4876 break;
4878 if (i >= ARRAYSIZE(chan_info_2064_lcnphy)) {
4879 return;
4882 ci = &chan_info_2064_lcnphy[i];
4885 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
4887 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
4889 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
4891 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
4893 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
4894 (ci->logen_rccr_rx) << 2);
4896 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
4898 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
4899 (ci->pa_rxrf_lna2_freq_tune) << 4);
4901 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
4903 pll_pwrup = (uint8) read_radio_reg(pi, RADIO_2064_REG044);
4904 pll_pwrup_ovr = (uint8) read_radio_reg(pi, RADIO_2064_REG12B);
4906 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
4908 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
4909 e44 = 0;
4910 e45 = 0;
4912 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
4913 if (pi->xtalfreq > 26000000)
4914 e44 = 1;
4915 if (pi->xtalfreq > 52000000)
4916 e45 = 1;
4917 if (e44 == 0)
4918 fcal_div = 1;
4919 else if (e45 == 0)
4920 fcal_div = 2;
4921 else
4922 fcal_div = 4;
4923 fvco3 = (ci->freq * 3);
4924 fref3 = 2 * fpfd;
4926 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
4927 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
4928 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
4929 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
4931 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
4933 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
4934 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
4935 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
4937 d16 = (qFcal * 8 / (d15 + 1)) - 1;
4938 write_radio_reg(pi, RADIO_2064_REG051, d16);
4940 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
4941 setCount = f16 * 3 * (ci->freq) / 32 - 1;
4942 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
4943 (uint8) (setCount >> 8));
4945 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
4946 write_radio_reg(pi, RADIO_2064_REG054, (uint8) (setCount & 0xff));
4948 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
4950 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
4951 while (div_frac >= fref3) {
4952 div_int++;
4953 div_frac -= fref3;
4955 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
4957 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
4958 (uint8) (div_int >> 4));
4959 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
4960 (uint8) (div_int << 4));
4961 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
4962 (uint8) (div_frac >> 16));
4963 write_radio_reg(pi, RADIO_2064_REG047, (uint8) (div_frac >> 8) & 0xff);
4964 write_radio_reg(pi, RADIO_2064_REG048, (uint8) div_frac & 0xff);
4966 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
4968 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
4969 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
4970 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
4973 uint8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
4974 uint16 c29, c38, c30, g30, d28;
4975 c29 = loop_bw;
4976 d29 = 200;
4977 c38 = 1250;
4978 h29 = d29 / c29;
4979 h23 = 1;
4980 c28 = 30;
4981 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
4982 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
4983 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
4984 + PLL_2064_LOW_END_KVCO;
4985 h28_ten = (d28 * 10) / c28;
4986 c30 = 2640;
4987 e30 = (d30 - 680) / 490;
4988 g30 = 680 + (e30 * 490);
4989 h30_ten = (g30 * 10) / c30;
4990 cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
4991 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
4993 if (channel >= 1 && channel <= 5)
4994 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
4995 else
4996 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
4997 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
4999 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
5000 OSL_DELAY(1);
5002 wlc_2064_vco_cal(pi);
5004 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
5005 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
5006 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5007 write_radio_reg(pi, RADIO_2064_REG038, 3);
5008 write_radio_reg(pi, RADIO_2064_REG091, 7);
5012 bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
5014 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5015 return 0;
5016 else
5017 return (LCNPHY_TX_PWR_CTRL_HW ==
5018 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5021 void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
5023 uint16 pwr_ctrl;
5024 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5025 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5026 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5028 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5029 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5030 wlc_lcnphy_txpower_recalc_target(pi);
5032 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5033 } else
5034 return;
5037 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5039 MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5042 bool wlc_phy_attach_lcnphy(phy_info_t *pi)
5044 phy_info_lcnphy_t *pi_lcn;
5046 pi->u.pi_lcnphy =
5047 (phy_info_lcnphy_t *) MALLOC(pi->sh->osh,
5048 sizeof(phy_info_lcnphy_t));
5049 if (pi->u.pi_lcnphy == NULL) {
5050 return FALSE;
5052 bzero((char *)pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5054 pi_lcn = pi->u.pi_lcnphy;
5056 if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
5057 pi->hwpwrctrl = TRUE;
5058 pi->hwpwrctrl_capable = TRUE;
5061 pi->xtalfreq = si_alp_clock(pi->sh->sih);
5062 ASSERT(0 == (pi->xtalfreq % 1000));
5064 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5066 pi->pi_fptr.init = wlc_phy_init_lcnphy;
5067 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5068 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5069 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5070 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5071 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5072 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5073 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5074 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5076 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5077 return FALSE;
5079 if ((pi->sh->boardflags & BFL_FEM) && (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5080 if (pi_lcn->lcnphy_tempsense_option == 3) {
5081 pi->hwpwrctrl = TRUE;
5082 pi->hwpwrctrl_capable = TRUE;
5083 pi->temppwrctrl_capable = FALSE;
5084 } else {
5085 pi->hwpwrctrl = FALSE;
5086 pi->hwpwrctrl_capable = FALSE;
5087 pi->temppwrctrl_capable = TRUE;
5091 return TRUE;
5094 static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, uint32 gain)
5096 uint16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5098 trsw = (gain & ((uint32) 1 << 28)) ? 0 : 1;
5099 ext_lna = (uint16) (gain >> 29) & 0x01;
5100 lna1 = (uint16) (gain >> 0) & 0x0f;
5101 lna2 = (uint16) (gain >> 4) & 0x0f;
5102 tia = (uint16) (gain >> 8) & 0xf;
5103 biq0 = (uint16) (gain >> 12) & 0xf;
5104 biq1 = (uint16) (gain >> 16) & 0xf;
5106 gain0_15 = (uint16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5107 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5108 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5109 gain16_19 = biq1;
5111 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5112 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5113 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5114 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5115 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5117 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5118 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5119 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5121 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
5124 static uint32 wlc_lcnphy_get_receive_power(phy_info_t *pi, int32 *gain_index)
5126 uint32 received_power = 0;
5127 int32 max_index = 0;
5128 uint32 gain_code = 0;
5129 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5131 max_index = 36;
5132 if (*gain_index >= 0)
5133 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5135 if (-1 == *gain_index) {
5136 *gain_index = 0;
5137 while ((*gain_index <= (int32) max_index)
5138 && (received_power < 700)) {
5139 wlc_lcnphy_set_rx_gain(pi,
5140 lcnphy_23bitgaincode_table
5141 [*gain_index]);
5142 received_power =
5143 wlc_lcnphy_measure_digital_power(pi,
5144 pi_lcn->
5145 lcnphy_noise_samples);
5146 (*gain_index)++;
5148 (*gain_index)--;
5149 } else {
5150 wlc_lcnphy_set_rx_gain(pi, gain_code);
5151 received_power =
5152 wlc_lcnphy_measure_digital_power(pi,
5153 pi_lcn->
5154 lcnphy_noise_samples);
5157 return received_power;
5160 int32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, int32 gain_index)
5162 int32 gain = 0;
5163 int32 nominal_power_db;
5164 int32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5165 input_power_db;
5166 int32 received_power, temperature;
5167 uint freq;
5168 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5170 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5172 gain = lcnphy_gain_table[gain_index];
5174 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5177 uint32 power = (received_power * 16);
5178 uint32 msb1, msb2, val1, val2, diff1, diff2;
5179 msb1 = find_msbit(power);
5180 msb2 = msb1 + 1;
5181 val1 = 1 << msb1;
5182 val2 = 1 << msb2;
5183 diff1 = (power - val1);
5184 diff2 = (val2 - power);
5185 if (diff1 < diff2)
5186 log_val = msb1;
5187 else
5188 log_val = msb2;
5191 log_val = log_val * 3;
5193 gain_mismatch = (nominal_power_db / 2) - (log_val);
5195 desired_gain = gain + gain_mismatch;
5197 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5199 if (input_power_offset_db > 127)
5200 input_power_offset_db -= 256;
5202 input_power_db = input_power_offset_db - desired_gain;
5204 input_power_db =
5205 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5207 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5208 if ((freq > 2427) && (freq <= 2467))
5209 input_power_db = input_power_db - 1;
5211 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5213 if ((temperature - 15) < -30) {
5214 input_power_db =
5215 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5217 } else if ((temperature - 15) < 4) {
5218 input_power_db =
5219 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5221 } else {
5222 input_power_db =
5223 input_power_db + (((temperature - 10 - 25) * 286) >> 12);
5226 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5228 return input_power_db;
5231 static int
5232 wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, int16 filt_type)
5234 int16 filt_index = -1;
5235 int j;
5237 uint16 addr[] = {
5238 0x910,
5239 0x91e,
5240 0x91f,
5241 0x924,
5242 0x925,
5243 0x926,
5244 0x920,
5245 0x921,
5246 0x927,
5247 0x928,
5248 0x929,
5249 0x922,
5250 0x923,
5251 0x930,
5252 0x931,
5253 0x932
5256 uint16 addr_ofdm[] = {
5257 0x90f,
5258 0x900,
5259 0x901,
5260 0x906,
5261 0x907,
5262 0x908,
5263 0x902,
5264 0x903,
5265 0x909,
5266 0x90a,
5267 0x90b,
5268 0x904,
5269 0x905,
5270 0x90c,
5271 0x90d,
5272 0x90e
5275 if (!is_ofdm) {
5276 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
5277 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
5278 filt_index = (int16) j;
5279 break;
5283 if (filt_index == -1) {
5284 ASSERT(FALSE);
5285 } else {
5286 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5287 write_phy_reg(pi, addr[j],
5288 LCNPHY_txdigfiltcoeffs_cck
5289 [filt_index][j + 1]);
5292 } else {
5293 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
5294 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
5295 filt_index = (int16) j;
5296 break;
5300 if (filt_index == -1) {
5301 ASSERT(FALSE);
5302 } else {
5303 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5304 write_phy_reg(pi, addr_ofdm[j],
5305 LCNPHY_txdigfiltcoeffs_ofdm
5306 [filt_index][j + 1]);
5311 return (filt_index != -1) ? 0 : -1;