Staging: brcm80211: s/int8/s8/
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / phy / wlc_phy_lcn.c
blob7e028d3145c4b93b42baa669714b7ac10893791b
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 <linux/kernel.h>
21 #include <linux/string.h>
22 #include <linuxver.h>
23 #include <siutils.h>
24 #include <bitfuncs.h>
25 #include <hndpmu.h>
27 #include <wlc_phy_radio.h>
28 #include <wlc_phy_int.h>
29 #include <wlc_phy_lcn.h>
30 #include <wlc_phytbl_lcn.h>
32 #define PLL_2064_NDIV 90
33 #define PLL_2064_LOW_END_VCO 3000
34 #define PLL_2064_LOW_END_KVCO 27
35 #define PLL_2064_HIGH_END_VCO 4200
36 #define PLL_2064_HIGH_END_KVCO 68
37 #define PLL_2064_LOOP_BW_DOUBLER 200
38 #define PLL_2064_D30_DOUBLER 10500
39 #define PLL_2064_LOOP_BW 260
40 #define PLL_2064_D30 8000
41 #define PLL_2064_CAL_REF_TO 8
42 #define PLL_2064_MHZ 1000000
43 #define PLL_2064_OPEN_LOOP_DELAY 5
45 #define TEMPSENSE 1
46 #define VBATSENSE 2
48 #define NOISE_IF_UPD_CHK_INTERVAL 1
49 #define NOISE_IF_UPD_RST_INTERVAL 60
50 #define NOISE_IF_UPD_THRESHOLD_CNT 1
51 #define NOISE_IF_UPD_TRHRESHOLD 50
52 #define NOISE_IF_UPD_TIMEOUT 1000
53 #define NOISE_IF_OFF 0
54 #define NOISE_IF_CHK 1
55 #define NOISE_IF_ON 2
57 #define PAPD_BLANKING_PROFILE 3
58 #define PAPD2LUT 0
59 #define PAPD_CORR_NORM 0
60 #define PAPD_BLANKING_THRESHOLD 0
61 #define PAPD_STOP_AFTER_LAST_UPDATE 0
63 #define LCN_TARGET_PWR 60
65 #define LCN_VBAT_OFFSET_433X 34649679
66 #define LCN_VBAT_SLOPE_433X 8258032
68 #define LCN_VBAT_SCALE_NOM 53
69 #define LCN_VBAT_SCALE_DEN 432
71 #define LCN_TEMPSENSE_OFFSET 80812
72 #define LCN_TEMPSENSE_DEN 2647
74 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
75 (0 + 8)
76 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
77 (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
79 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
80 (0 + 8)
81 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
82 (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
84 #define wlc_lcnphy_enable_tx_gain_override(pi) \
85 wlc_lcnphy_set_tx_gain_override(pi, TRUE)
86 #define wlc_lcnphy_disable_tx_gain_override(pi) \
87 wlc_lcnphy_set_tx_gain_override(pi, FALSE)
89 #define wlc_lcnphy_iqcal_active(pi) \
90 (read_phy_reg((pi), 0x451) & \
91 ((0x1 << 15) | (0x1 << 14)))
93 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
94 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
95 (pi->temppwrctrl_capable)
96 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
97 (pi->hwpwrctrl_capable)
99 #define SWCTRL_BT_TX 0x18
100 #define SWCTRL_OVR_DISABLE 0x40
102 #define AFE_CLK_INIT_MODE_TXRX2X 1
103 #define AFE_CLK_INIT_MODE_PAPD 0
105 #define LCNPHY_TBL_ID_IQLOCAL 0x00
107 #define LCNPHY_TBL_ID_RFSEQ 0x08
108 #define LCNPHY_TBL_ID_GAIN_IDX 0x0d
109 #define LCNPHY_TBL_ID_SW_CTRL 0x0f
110 #define LCNPHY_TBL_ID_GAIN_TBL 0x12
111 #define LCNPHY_TBL_ID_SPUR 0x14
112 #define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
113 #define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
115 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
116 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
117 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
118 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
119 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
120 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
122 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
124 #define LCNPHY_TX_PWR_CTRL_START_NPT 1
125 #define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
127 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
129 #define LCNPHY_ACI_DETECT_START 1
130 #define LCNPHY_ACI_DETECT_PROGRESS 2
131 #define LCNPHY_ACI_DETECT_STOP 3
133 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
134 #define LCNPHY_ACI_GLITCH_TRSH 2000
135 #define LCNPHY_ACI_TMOUT 250
136 #define LCNPHY_ACI_DETECT_TIMEOUT 2
137 #define LCNPHY_ACI_START_DELAY 0
139 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
140 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
142 #define wlc_lcnphy_total_tx_frames(pi) \
143 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + OFFSETOF(macstat_t, txallfrm))
145 typedef struct {
146 uint16 gm_gain;
147 uint16 pga_gain;
148 uint16 pad_gain;
149 uint16 dac_gain;
150 } lcnphy_txgains_t;
152 typedef enum {
153 LCNPHY_CAL_FULL,
154 LCNPHY_CAL_RECAL,
155 LCNPHY_CAL_CURRECAL,
156 LCNPHY_CAL_DIGCAL,
157 LCNPHY_CAL_GCTRL
158 } lcnphy_cal_mode_t;
160 typedef struct {
161 lcnphy_txgains_t gains;
162 bool useindex;
163 u8 index;
164 } lcnphy_txcalgains_t;
166 typedef struct {
167 u8 chan;
168 int16 a;
169 int16 b;
170 } lcnphy_rx_iqcomp_t;
172 typedef struct {
173 int16 re;
174 int16 im;
175 } lcnphy_spb_tone_t;
177 typedef struct {
178 uint16 re;
179 uint16 im;
180 } lcnphy_unsign16_struct;
182 typedef struct {
183 uint32 iq_prod;
184 uint32 i_pwr;
185 uint32 q_pwr;
186 } lcnphy_iq_est_t;
188 typedef struct {
189 uint16 ptcentreTs20;
190 uint16 ptcentreFactor;
191 } lcnphy_sfo_cfg_t;
193 typedef enum {
194 LCNPHY_PAPD_CAL_CW,
195 LCNPHY_PAPD_CAL_OFDM
196 } lcnphy_papd_cal_type_t;
198 typedef uint16 iqcal_gain_params_lcnphy[9];
200 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
201 {0, 0, 0, 0, 0, 0, 0, 0, 0},
204 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
205 tbl_iqcal_gainparams_lcnphy_2G,
208 static const uint16 iqcal_gainparams_numgains_lcnphy[1] = {
209 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
210 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
213 static const lcnphy_sfo_cfg_t lcnphy_sfo_cfg[] = {
214 {965, 1087},
215 {967, 1085},
216 {969, 1082},
217 {971, 1080},
218 {973, 1078},
219 {975, 1076},
220 {977, 1073},
221 {979, 1071},
222 {981, 1069},
223 {983, 1067},
224 {985, 1065},
225 {987, 1063},
226 {989, 1060},
227 {994, 1055}
230 static const
231 uint16 lcnphy_iqcal_loft_gainladder[] = {
232 ((2 << 8) | 0),
233 ((3 << 8) | 0),
234 ((4 << 8) | 0),
235 ((6 << 8) | 0),
236 ((8 << 8) | 0),
237 ((11 << 8) | 0),
238 ((16 << 8) | 0),
239 ((16 << 8) | 1),
240 ((16 << 8) | 2),
241 ((16 << 8) | 3),
242 ((16 << 8) | 4),
243 ((16 << 8) | 5),
244 ((16 << 8) | 6),
245 ((16 << 8) | 7),
246 ((23 << 8) | 7),
247 ((32 << 8) | 7),
248 ((45 << 8) | 7),
249 ((64 << 8) | 7),
250 ((91 << 8) | 7),
251 ((128 << 8) | 7)
254 static const
255 uint16 lcnphy_iqcal_ir_gainladder[] = {
256 ((1 << 8) | 0),
257 ((2 << 8) | 0),
258 ((4 << 8) | 0),
259 ((6 << 8) | 0),
260 ((8 << 8) | 0),
261 ((11 << 8) | 0),
262 ((16 << 8) | 0),
263 ((23 << 8) | 0),
264 ((32 << 8) | 0),
265 ((45 << 8) | 0),
266 ((64 << 8) | 0),
267 ((64 << 8) | 1),
268 ((64 << 8) | 2),
269 ((64 << 8) | 3),
270 ((64 << 8) | 4),
271 ((64 << 8) | 5),
272 ((64 << 8) | 6),
273 ((64 << 8) | 7),
274 ((91 << 8) | 7),
275 ((128 << 8) | 7)
278 static const
279 lcnphy_spb_tone_t lcnphy_spb_tone_3750[] = {
280 {88, 0},
281 {73, 49},
282 {34, 81},
283 {-17, 86},
284 {-62, 62},
285 {-86, 17},
286 {-81, -34},
287 {-49, -73},
288 {0, -88},
289 {49, -73},
290 {81, -34},
291 {86, 17},
292 {62, 62},
293 {17, 86},
294 {-34, 81},
295 {-73, 49},
296 {-88, 0},
297 {-73, -49},
298 {-34, -81},
299 {17, -86},
300 {62, -62},
301 {86, -17},
302 {81, 34},
303 {49, 73},
304 {0, 88},
305 {-49, 73},
306 {-81, 34},
307 {-86, -17},
308 {-62, -62},
309 {-17, -86},
310 {34, -81},
311 {73, -49},
314 static const
315 uint16 iqlo_loopback_rf_regs[20] = {
316 RADIO_2064_REG036,
317 RADIO_2064_REG11A,
318 RADIO_2064_REG03A,
319 RADIO_2064_REG025,
320 RADIO_2064_REG028,
321 RADIO_2064_REG005,
322 RADIO_2064_REG112,
323 RADIO_2064_REG0FF,
324 RADIO_2064_REG11F,
325 RADIO_2064_REG00B,
326 RADIO_2064_REG113,
327 RADIO_2064_REG007,
328 RADIO_2064_REG0FC,
329 RADIO_2064_REG0FD,
330 RADIO_2064_REG012,
331 RADIO_2064_REG057,
332 RADIO_2064_REG059,
333 RADIO_2064_REG05C,
334 RADIO_2064_REG078,
335 RADIO_2064_REG092,
338 static const
339 uint16 tempsense_phy_regs[14] = {
340 0x503,
341 0x4a4,
342 0x4d0,
343 0x4d9,
344 0x4da,
345 0x4a6,
346 0x938,
347 0x939,
348 0x4d8,
349 0x4d0,
350 0x4d7,
351 0x4a5,
352 0x40d,
353 0x4a2,
356 static const
357 uint16 rxiq_cal_rf_reg[11] = {
358 RADIO_2064_REG098,
359 RADIO_2064_REG116,
360 RADIO_2064_REG12C,
361 RADIO_2064_REG06A,
362 RADIO_2064_REG00B,
363 RADIO_2064_REG01B,
364 RADIO_2064_REG113,
365 RADIO_2064_REG01D,
366 RADIO_2064_REG114,
367 RADIO_2064_REG02E,
368 RADIO_2064_REG12A,
371 static const
372 lcnphy_rx_iqcomp_t lcnphy_rx_iqcomp_table_rev0[] = {
373 {1, 0, 0},
374 {2, 0, 0},
375 {3, 0, 0},
376 {4, 0, 0},
377 {5, 0, 0},
378 {6, 0, 0},
379 {7, 0, 0},
380 {8, 0, 0},
381 {9, 0, 0},
382 {10, 0, 0},
383 {11, 0, 0},
384 {12, 0, 0},
385 {13, 0, 0},
386 {14, 0, 0},
387 {34, 0, 0},
388 {38, 0, 0},
389 {42, 0, 0},
390 {46, 0, 0},
391 {36, 0, 0},
392 {40, 0, 0},
393 {44, 0, 0},
394 {48, 0, 0},
395 {52, 0, 0},
396 {56, 0, 0},
397 {60, 0, 0},
398 {64, 0, 0},
399 {100, 0, 0},
400 {104, 0, 0},
401 {108, 0, 0},
402 {112, 0, 0},
403 {116, 0, 0},
404 {120, 0, 0},
405 {124, 0, 0},
406 {128, 0, 0},
407 {132, 0, 0},
408 {136, 0, 0},
409 {140, 0, 0},
410 {149, 0, 0},
411 {153, 0, 0},
412 {157, 0, 0},
413 {161, 0, 0},
414 {165, 0, 0},
415 {184, 0, 0},
416 {188, 0, 0},
417 {192, 0, 0},
418 {196, 0, 0},
419 {200, 0, 0},
420 {204, 0, 0},
421 {208, 0, 0},
422 {212, 0, 0},
423 {216, 0, 0},
426 static const uint32 lcnphy_23bitgaincode_table[] = {
427 0x200100,
428 0x200200,
429 0x200004,
430 0x200014,
431 0x200024,
432 0x200034,
433 0x200134,
434 0x200234,
435 0x200334,
436 0x200434,
437 0x200037,
438 0x200137,
439 0x200237,
440 0x200337,
441 0x200437,
442 0x000035,
443 0x000135,
444 0x000235,
445 0x000037,
446 0x000137,
447 0x000237,
448 0x000337,
449 0x00013f,
450 0x00023f,
451 0x00033f,
452 0x00034f,
453 0x00044f,
454 0x00144f,
455 0x00244f,
456 0x00254f,
457 0x00354f,
458 0x00454f,
459 0x00464f,
460 0x01464f,
461 0x02464f,
462 0x03464f,
463 0x04464f,
466 static const s8 lcnphy_gain_table[] = {
467 -16,
468 -13,
506 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
547 extern CONST u8 spur_tbl_rev0[];
548 extern CONST uint32 dot11lcnphytbl_rx_gain_info_sz_rev1;
549 extern CONST dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
550 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
551 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
553 typedef struct _chan_info_2064_lcnphy {
554 uint chan;
555 uint freq;
556 u8 logen_buftune;
557 u8 logen_rccr_tx;
558 u8 txrf_mix_tune_ctrl;
559 u8 pa_input_tune_g;
560 u8 logen_rccr_rx;
561 u8 pa_rxrf_lna1_freq_tune;
562 u8 pa_rxrf_lna2_freq_tune;
563 u8 rxrf_rxrf_spare1;
564 } chan_info_2064_lcnphy_t;
566 static chan_info_2064_lcnphy_t chan_info_2064_lcnphy[] = {
567 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
576 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
578 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
579 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
580 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
583 lcnphy_radio_regs_t lcnphy_radio_regs_2064[] = {
584 {0x00, 0, 0, 0, 0},
585 {0x01, 0x64, 0x64, 0, 0},
586 {0x02, 0x20, 0x20, 0, 0},
587 {0x03, 0x66, 0x66, 0, 0},
588 {0x04, 0xf8, 0xf8, 0, 0},
589 {0x05, 0, 0, 0, 0},
590 {0x06, 0x10, 0x10, 0, 0},
591 {0x07, 0, 0, 0, 0},
592 {0x08, 0, 0, 0, 0},
593 {0x09, 0, 0, 0, 0},
594 {0x0A, 0x37, 0x37, 0, 0},
595 {0x0B, 0x6, 0x6, 0, 0},
596 {0x0C, 0x55, 0x55, 0, 0},
597 {0x0D, 0x8b, 0x8b, 0, 0},
598 {0x0E, 0, 0, 0, 0},
599 {0x0F, 0x5, 0x5, 0, 0},
600 {0x10, 0, 0, 0, 0},
601 {0x11, 0xe, 0xe, 0, 0},
602 {0x12, 0, 0, 0, 0},
603 {0x13, 0xb, 0xb, 0, 0},
604 {0x14, 0x2, 0x2, 0, 0},
605 {0x15, 0x12, 0x12, 0, 0},
606 {0x16, 0x12, 0x12, 0, 0},
607 {0x17, 0xc, 0xc, 0, 0},
608 {0x18, 0xc, 0xc, 0, 0},
609 {0x19, 0xc, 0xc, 0, 0},
610 {0x1A, 0x8, 0x8, 0, 0},
611 {0x1B, 0x2, 0x2, 0, 0},
612 {0x1C, 0, 0, 0, 0},
613 {0x1D, 0x1, 0x1, 0, 0},
614 {0x1E, 0x12, 0x12, 0, 0},
615 {0x1F, 0x6e, 0x6e, 0, 0},
616 {0x20, 0x2, 0x2, 0, 0},
617 {0x21, 0x23, 0x23, 0, 0},
618 {0x22, 0x8, 0x8, 0, 0},
619 {0x23, 0, 0, 0, 0},
620 {0x24, 0, 0, 0, 0},
621 {0x25, 0xc, 0xc, 0, 0},
622 {0x26, 0x33, 0x33, 0, 0},
623 {0x27, 0x55, 0x55, 0, 0},
624 {0x28, 0, 0, 0, 0},
625 {0x29, 0x30, 0x30, 0, 0},
626 {0x2A, 0xb, 0xb, 0, 0},
627 {0x2B, 0x1b, 0x1b, 0, 0},
628 {0x2C, 0x3, 0x3, 0, 0},
629 {0x2D, 0x1b, 0x1b, 0, 0},
630 {0x2E, 0, 0, 0, 0},
631 {0x2F, 0x20, 0x20, 0, 0},
632 {0x30, 0xa, 0xa, 0, 0},
633 {0x31, 0, 0, 0, 0},
634 {0x32, 0x62, 0x62, 0, 0},
635 {0x33, 0x19, 0x19, 0, 0},
636 {0x34, 0x33, 0x33, 0, 0},
637 {0x35, 0x77, 0x77, 0, 0},
638 {0x36, 0, 0, 0, 0},
639 {0x37, 0x70, 0x70, 0, 0},
640 {0x38, 0x3, 0x3, 0, 0},
641 {0x39, 0xf, 0xf, 0, 0},
642 {0x3A, 0x6, 0x6, 0, 0},
643 {0x3B, 0xcf, 0xcf, 0, 0},
644 {0x3C, 0x1a, 0x1a, 0, 0},
645 {0x3D, 0x6, 0x6, 0, 0},
646 {0x3E, 0x42, 0x42, 0, 0},
647 {0x3F, 0, 0, 0, 0},
648 {0x40, 0xfb, 0xfb, 0, 0},
649 {0x41, 0x9a, 0x9a, 0, 0},
650 {0x42, 0x7a, 0x7a, 0, 0},
651 {0x43, 0x29, 0x29, 0, 0},
652 {0x44, 0, 0, 0, 0},
653 {0x45, 0x8, 0x8, 0, 0},
654 {0x46, 0xce, 0xce, 0, 0},
655 {0x47, 0x27, 0x27, 0, 0},
656 {0x48, 0x62, 0x62, 0, 0},
657 {0x49, 0x6, 0x6, 0, 0},
658 {0x4A, 0x58, 0x58, 0, 0},
659 {0x4B, 0xf7, 0xf7, 0, 0},
660 {0x4C, 0, 0, 0, 0},
661 {0x4D, 0xb3, 0xb3, 0, 0},
662 {0x4E, 0, 0, 0, 0},
663 {0x4F, 0x2, 0x2, 0, 0},
664 {0x50, 0, 0, 0, 0},
665 {0x51, 0x9, 0x9, 0, 0},
666 {0x52, 0x5, 0x5, 0, 0},
667 {0x53, 0x17, 0x17, 0, 0},
668 {0x54, 0x38, 0x38, 0, 0},
669 {0x55, 0, 0, 0, 0},
670 {0x56, 0, 0, 0, 0},
671 {0x57, 0xb, 0xb, 0, 0},
672 {0x58, 0, 0, 0, 0},
673 {0x59, 0, 0, 0, 0},
674 {0x5A, 0, 0, 0, 0},
675 {0x5B, 0, 0, 0, 0},
676 {0x5C, 0, 0, 0, 0},
677 {0x5D, 0, 0, 0, 0},
678 {0x5E, 0x88, 0x88, 0, 0},
679 {0x5F, 0xcc, 0xcc, 0, 0},
680 {0x60, 0x74, 0x74, 0, 0},
681 {0x61, 0x74, 0x74, 0, 0},
682 {0x62, 0x74, 0x74, 0, 0},
683 {0x63, 0x44, 0x44, 0, 0},
684 {0x64, 0x77, 0x77, 0, 0},
685 {0x65, 0x44, 0x44, 0, 0},
686 {0x66, 0x77, 0x77, 0, 0},
687 {0x67, 0x55, 0x55, 0, 0},
688 {0x68, 0x77, 0x77, 0, 0},
689 {0x69, 0x77, 0x77, 0, 0},
690 {0x6A, 0, 0, 0, 0},
691 {0x6B, 0x7f, 0x7f, 0, 0},
692 {0x6C, 0x8, 0x8, 0, 0},
693 {0x6D, 0, 0, 0, 0},
694 {0x6E, 0x88, 0x88, 0, 0},
695 {0x6F, 0x66, 0x66, 0, 0},
696 {0x70, 0x66, 0x66, 0, 0},
697 {0x71, 0x28, 0x28, 0, 0},
698 {0x72, 0x55, 0x55, 0, 0},
699 {0x73, 0x4, 0x4, 0, 0},
700 {0x74, 0, 0, 0, 0},
701 {0x75, 0, 0, 0, 0},
702 {0x76, 0, 0, 0, 0},
703 {0x77, 0x1, 0x1, 0, 0},
704 {0x78, 0xd6, 0xd6, 0, 0},
705 {0x79, 0, 0, 0, 0},
706 {0x7A, 0, 0, 0, 0},
707 {0x7B, 0, 0, 0, 0},
708 {0x7C, 0, 0, 0, 0},
709 {0x7D, 0, 0, 0, 0},
710 {0x7E, 0, 0, 0, 0},
711 {0x7F, 0, 0, 0, 0},
712 {0x80, 0, 0, 0, 0},
713 {0x81, 0, 0, 0, 0},
714 {0x82, 0, 0, 0, 0},
715 {0x83, 0xb4, 0xb4, 0, 0},
716 {0x84, 0x1, 0x1, 0, 0},
717 {0x85, 0x20, 0x20, 0, 0},
718 {0x86, 0x5, 0x5, 0, 0},
719 {0x87, 0xff, 0xff, 0, 0},
720 {0x88, 0x7, 0x7, 0, 0},
721 {0x89, 0x77, 0x77, 0, 0},
722 {0x8A, 0x77, 0x77, 0, 0},
723 {0x8B, 0x77, 0x77, 0, 0},
724 {0x8C, 0x77, 0x77, 0, 0},
725 {0x8D, 0x8, 0x8, 0, 0},
726 {0x8E, 0xa, 0xa, 0, 0},
727 {0x8F, 0x8, 0x8, 0, 0},
728 {0x90, 0x18, 0x18, 0, 0},
729 {0x91, 0x5, 0x5, 0, 0},
730 {0x92, 0x1f, 0x1f, 0, 0},
731 {0x93, 0x10, 0x10, 0, 0},
732 {0x94, 0x3, 0x3, 0, 0},
733 {0x95, 0, 0, 0, 0},
734 {0x96, 0, 0, 0, 0},
735 {0x97, 0xaa, 0xaa, 0, 0},
736 {0x98, 0, 0, 0, 0},
737 {0x99, 0x23, 0x23, 0, 0},
738 {0x9A, 0x7, 0x7, 0, 0},
739 {0x9B, 0xf, 0xf, 0, 0},
740 {0x9C, 0x10, 0x10, 0, 0},
741 {0x9D, 0x3, 0x3, 0, 0},
742 {0x9E, 0x4, 0x4, 0, 0},
743 {0x9F, 0x20, 0x20, 0, 0},
744 {0xA0, 0, 0, 0, 0},
745 {0xA1, 0, 0, 0, 0},
746 {0xA2, 0, 0, 0, 0},
747 {0xA3, 0, 0, 0, 0},
748 {0xA4, 0x1, 0x1, 0, 0},
749 {0xA5, 0x77, 0x77, 0, 0},
750 {0xA6, 0x77, 0x77, 0, 0},
751 {0xA7, 0x77, 0x77, 0, 0},
752 {0xA8, 0x77, 0x77, 0, 0},
753 {0xA9, 0x8c, 0x8c, 0, 0},
754 {0xAA, 0x88, 0x88, 0, 0},
755 {0xAB, 0x78, 0x78, 0, 0},
756 {0xAC, 0x57, 0x57, 0, 0},
757 {0xAD, 0x88, 0x88, 0, 0},
758 {0xAE, 0, 0, 0, 0},
759 {0xAF, 0x8, 0x8, 0, 0},
760 {0xB0, 0x88, 0x88, 0, 0},
761 {0xB1, 0, 0, 0, 0},
762 {0xB2, 0x1b, 0x1b, 0, 0},
763 {0xB3, 0x3, 0x3, 0, 0},
764 {0xB4, 0x24, 0x24, 0, 0},
765 {0xB5, 0x3, 0x3, 0, 0},
766 {0xB6, 0x1b, 0x1b, 0, 0},
767 {0xB7, 0x24, 0x24, 0, 0},
768 {0xB8, 0x3, 0x3, 0, 0},
769 {0xB9, 0, 0, 0, 0},
770 {0xBA, 0xaa, 0xaa, 0, 0},
771 {0xBB, 0, 0, 0, 0},
772 {0xBC, 0x4, 0x4, 0, 0},
773 {0xBD, 0, 0, 0, 0},
774 {0xBE, 0x8, 0x8, 0, 0},
775 {0xBF, 0x11, 0x11, 0, 0},
776 {0xC0, 0, 0, 0, 0},
777 {0xC1, 0, 0, 0, 0},
778 {0xC2, 0x62, 0x62, 0, 0},
779 {0xC3, 0x1e, 0x1e, 0, 0},
780 {0xC4, 0x33, 0x33, 0, 0},
781 {0xC5, 0x37, 0x37, 0, 0},
782 {0xC6, 0, 0, 0, 0},
783 {0xC7, 0x70, 0x70, 0, 0},
784 {0xC8, 0x1e, 0x1e, 0, 0},
785 {0xC9, 0x6, 0x6, 0, 0},
786 {0xCA, 0x4, 0x4, 0, 0},
787 {0xCB, 0x2f, 0x2f, 0, 0},
788 {0xCC, 0xf, 0xf, 0, 0},
789 {0xCD, 0, 0, 0, 0},
790 {0xCE, 0xff, 0xff, 0, 0},
791 {0xCF, 0x8, 0x8, 0, 0},
792 {0xD0, 0x3f, 0x3f, 0, 0},
793 {0xD1, 0x3f, 0x3f, 0, 0},
794 {0xD2, 0x3f, 0x3f, 0, 0},
795 {0xD3, 0, 0, 0, 0},
796 {0xD4, 0, 0, 0, 0},
797 {0xD5, 0, 0, 0, 0},
798 {0xD6, 0xcc, 0xcc, 0, 0},
799 {0xD7, 0, 0, 0, 0},
800 {0xD8, 0x8, 0x8, 0, 0},
801 {0xD9, 0x8, 0x8, 0, 0},
802 {0xDA, 0x8, 0x8, 0, 0},
803 {0xDB, 0x11, 0x11, 0, 0},
804 {0xDC, 0, 0, 0, 0},
805 {0xDD, 0x87, 0x87, 0, 0},
806 {0xDE, 0x88, 0x88, 0, 0},
807 {0xDF, 0x8, 0x8, 0, 0},
808 {0xE0, 0x8, 0x8, 0, 0},
809 {0xE1, 0x8, 0x8, 0, 0},
810 {0xE2, 0, 0, 0, 0},
811 {0xE3, 0, 0, 0, 0},
812 {0xE4, 0, 0, 0, 0},
813 {0xE5, 0xf5, 0xf5, 0, 0},
814 {0xE6, 0x30, 0x30, 0, 0},
815 {0xE7, 0x1, 0x1, 0, 0},
816 {0xE8, 0, 0, 0, 0},
817 {0xE9, 0xff, 0xff, 0, 0},
818 {0xEA, 0, 0, 0, 0},
819 {0xEB, 0, 0, 0, 0},
820 {0xEC, 0x22, 0x22, 0, 0},
821 {0xED, 0, 0, 0, 0},
822 {0xEE, 0, 0, 0, 0},
823 {0xEF, 0, 0, 0, 0},
824 {0xF0, 0x3, 0x3, 0, 0},
825 {0xF1, 0x1, 0x1, 0, 0},
826 {0xF2, 0, 0, 0, 0},
827 {0xF3, 0, 0, 0, 0},
828 {0xF4, 0, 0, 0, 0},
829 {0xF5, 0, 0, 0, 0},
830 {0xF6, 0, 0, 0, 0},
831 {0xF7, 0x6, 0x6, 0, 0},
832 {0xF8, 0, 0, 0, 0},
833 {0xF9, 0, 0, 0, 0},
834 {0xFA, 0x40, 0x40, 0, 0},
835 {0xFB, 0, 0, 0, 0},
836 {0xFC, 0x1, 0x1, 0, 0},
837 {0xFD, 0x80, 0x80, 0, 0},
838 {0xFE, 0x2, 0x2, 0, 0},
839 {0xFF, 0x10, 0x10, 0, 0},
840 {0x100, 0x2, 0x2, 0, 0},
841 {0x101, 0x1e, 0x1e, 0, 0},
842 {0x102, 0x1e, 0x1e, 0, 0},
843 {0x103, 0, 0, 0, 0},
844 {0x104, 0x1f, 0x1f, 0, 0},
845 {0x105, 0, 0x8, 0, 1},
846 {0x106, 0x2a, 0x2a, 0, 0},
847 {0x107, 0xf, 0xf, 0, 0},
848 {0x108, 0, 0, 0, 0},
849 {0x109, 0, 0, 0, 0},
850 {0x10A, 0, 0, 0, 0},
851 {0x10B, 0, 0, 0, 0},
852 {0x10C, 0, 0, 0, 0},
853 {0x10D, 0, 0, 0, 0},
854 {0x10E, 0, 0, 0, 0},
855 {0x10F, 0, 0, 0, 0},
856 {0x110, 0, 0, 0, 0},
857 {0x111, 0, 0, 0, 0},
858 {0x112, 0, 0, 0, 0},
859 {0x113, 0, 0, 0, 0},
860 {0x114, 0, 0, 0, 0},
861 {0x115, 0, 0, 0, 0},
862 {0x116, 0, 0, 0, 0},
863 {0x117, 0, 0, 0, 0},
864 {0x118, 0, 0, 0, 0},
865 {0x119, 0, 0, 0, 0},
866 {0x11A, 0, 0, 0, 0},
867 {0x11B, 0, 0, 0, 0},
868 {0x11C, 0x1, 0x1, 0, 0},
869 {0x11D, 0, 0, 0, 0},
870 {0x11E, 0, 0, 0, 0},
871 {0x11F, 0, 0, 0, 0},
872 {0x120, 0, 0, 0, 0},
873 {0x121, 0, 0, 0, 0},
874 {0x122, 0x80, 0x80, 0, 0},
875 {0x123, 0, 0, 0, 0},
876 {0x124, 0xf8, 0xf8, 0, 0},
877 {0x125, 0, 0, 0, 0},
878 {0x126, 0, 0, 0, 0},
879 {0x127, 0, 0, 0, 0},
880 {0x128, 0, 0, 0, 0},
881 {0x129, 0, 0, 0, 0},
882 {0x12A, 0, 0, 0, 0},
883 {0x12B, 0, 0, 0, 0},
884 {0x12C, 0, 0, 0, 0},
885 {0x12D, 0, 0, 0, 0},
886 {0x12E, 0, 0, 0, 0},
887 {0x12F, 0, 0, 0, 0},
888 {0x130, 0, 0, 0, 0},
889 {0xFFFF, 0, 0, 0, 0}
892 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
893 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
895 uint16
896 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
897 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
898 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
899 128, 64,},
900 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
901 167, 93,},
902 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
903 128, 64,},
904 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
905 170, 340, 170,},
906 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
907 256, 185, 256,},
908 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
909 256, 273, 256,},
910 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
911 256, 352, 256,},
912 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
913 128, 233, 128,},
914 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
915 1881, 256,},
916 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
917 1881, 256,},
918 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
919 384, 288,},
920 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
921 128, 384, 288,},
922 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
923 170, 340, 170,},
926 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
927 uint16
928 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
929 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
930 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
931 0x278, 0xfea0, 0x80, 0x100, 0x80,},
932 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
933 750, 0xFE2B, 212, 0xFFCE, 212,},
934 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
935 0xFEF2, 128, 0xFFE2, 128}
938 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
939 mod_phy_reg(pi, 0x4a4, \
940 (0x1ff << 0), \
941 (uint16)(idx) << 0)
943 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
944 mod_phy_reg(pi, 0x4a5, \
945 (0x7 << 8), \
946 (uint16)(npt) << 8)
948 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
949 (read_phy_reg((pi), 0x4a4) & \
950 ((0x1 << 15) | \
951 (0x1 << 14) | \
952 (0x1 << 13)))
954 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
955 ((read_phy_reg(pi, 0x4a5) & \
956 (0x7 << 8)) >> \
959 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
960 (read_phy_reg(pi, 0x473) & 0x1ff)
962 #define wlc_lcnphy_get_target_tx_pwr(pi) \
963 ((read_phy_reg(pi, 0x4a7) & \
964 (0xff << 0)) >> \
967 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
968 mod_phy_reg(pi, 0x4a7, \
969 (0xff << 0), \
970 (uint16)(target) << 0)
972 #define wlc_radio_2064_rcal_done(pi) (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
973 #define tempsense_done(pi) (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
975 #define LCNPHY_IQLOCC_READ(val) ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
976 #define FIXED_TXPWR 78
977 #define LCNPHY_TEMPSENSE(val) ((int16)((val > 255) ? (val - 512) : val))
979 static uint32 wlc_lcnphy_qdiv_roundup(uint32 divident, uint32 divisor,
980 u8 precision);
981 static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
982 uint16 ext_lna, uint16 trsw,
983 uint16 biq2, uint16 biq1,
984 uint16 tia, uint16 lna2,
985 uint16 lna1);
986 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
987 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 gain);
988 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
989 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0);
990 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
991 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
992 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
993 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
994 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
995 static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
996 lcnphy_txgains_t *target_gains);
997 static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, uint16 num_samps,
998 u8 wait_time, lcnphy_iq_est_t *iq_est);
999 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, uint16 num_samps);
1000 static uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
1001 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode);
1002 extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1003 extern void wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng,
1004 u8 rate, struct ether_addr *sa,
1005 uint32 wait_delay);
1006 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1007 u8 channel);
1009 static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1010 const lcnphy_tx_gain_tbl_entry *g);
1012 static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
1013 uint16 thresh, int16 *ptr, int mode);
1014 static int wlc_lcnphy_calc_floor(int16 coeff, int type);
1015 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1016 uint16 *values_to_save);
1017 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1018 uint16 *values_to_save);
1019 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x,
1020 int16 coeff_y);
1021 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1022 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1023 int num_levels, int step_size_lg2);
1024 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
1026 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
1027 chanspec_t chanspec);
1028 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1029 static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1030 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1031 static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1032 static void wlc_lcnphy_radio_init(phy_info_t *pi);
1033 static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1034 static void wlc_lcnphy_rcal(phy_info_t *pi);
1035 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1036 static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
1037 int16 filt_type);
1038 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 b);
1040 void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
1042 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1045 void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
1047 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1050 static void
1051 wlc_lcnphy_common_read_table(phy_info_t *pi, uint32 tbl_id,
1052 CONST void *tbl_ptr, uint32 tbl_len,
1053 uint32 tbl_width, uint32 tbl_offset)
1055 phytbl_info_t tab;
1056 tab.tbl_id = tbl_id;
1057 tab.tbl_ptr = tbl_ptr;
1058 tab.tbl_len = tbl_len;
1059 tab.tbl_width = tbl_width;
1060 tab.tbl_offset = tbl_offset;
1061 wlc_lcnphy_read_table(pi, &tab);
1064 static void
1065 wlc_lcnphy_common_write_table(phy_info_t *pi, uint32 tbl_id,
1066 CONST void *tbl_ptr, uint32 tbl_len,
1067 uint32 tbl_width, uint32 tbl_offset)
1070 phytbl_info_t tab;
1071 tab.tbl_id = tbl_id;
1072 tab.tbl_ptr = tbl_ptr;
1073 tab.tbl_len = tbl_len;
1074 tab.tbl_width = tbl_width;
1075 tab.tbl_offset = tbl_offset;
1076 wlc_lcnphy_write_table(pi, &tab);
1079 static uint32
1080 wlc_lcnphy_qdiv_roundup(uint32 dividend, uint32 divisor, u8 precision)
1082 uint32 quotient, remainder, roundup, rbit;
1084 ASSERT(divisor);
1086 quotient = dividend / divisor;
1087 remainder = dividend % divisor;
1088 rbit = divisor & 1;
1089 roundup = (divisor >> 1) + rbit;
1091 while (precision--) {
1092 quotient <<= 1;
1093 if (remainder >= roundup) {
1094 quotient++;
1095 remainder = ((remainder - roundup) << 1) + rbit;
1096 } else {
1097 remainder <<= 1;
1101 if (remainder >= roundup)
1102 quotient++;
1104 return quotient;
1107 static int wlc_lcnphy_calc_floor(int16 coeff_x, int type)
1109 int k;
1110 k = 0;
1111 if (type == 0) {
1112 if (coeff_x < 0) {
1113 k = (coeff_x - 1) / 2;
1114 } else {
1115 k = coeff_x / 2;
1118 if (type == 1) {
1119 if ((coeff_x + 1) < 0)
1120 k = (coeff_x) / 2;
1121 else
1122 k = (coeff_x + 1) / 2;
1124 return k;
1127 s8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1129 s8 index;
1130 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1132 if (txpwrctrl_off(pi))
1133 index = pi_lcn->lcnphy_current_index;
1134 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1135 index =
1136 (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1137 / 2);
1138 else
1139 index = pi_lcn->lcnphy_current_index;
1140 return index;
1143 static uint32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, uint16 nsamples)
1145 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
1147 if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1148 return 0;
1149 return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1152 void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
1154 uint16 afectrlovr, afectrlovrval;
1155 afectrlovr = read_phy_reg(pi, 0x43b);
1156 afectrlovrval = read_phy_reg(pi, 0x43c);
1157 if (channel != 0) {
1158 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1160 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1162 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1164 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1166 write_phy_reg(pi, 0x44b, 0xffff);
1167 wlc_lcnphy_tx_pu(pi, 1);
1169 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1171 or_phy_reg(pi, 0x6da, 0x0080);
1173 or_phy_reg(pi, 0x00a, 0x228);
1174 } else {
1175 and_phy_reg(pi, 0x00a, ~(0x228));
1177 and_phy_reg(pi, 0x6da, 0xFF7F);
1178 write_phy_reg(pi, 0x43b, afectrlovr);
1179 write_phy_reg(pi, 0x43c, afectrlovrval);
1183 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
1185 uint16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1187 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1188 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1190 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1191 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1193 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1194 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1196 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1197 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1200 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
1202 if (enable) {
1203 write_phy_reg(pi, 0x942, 0x7);
1204 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1205 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1207 write_phy_reg(pi, 0x44a, 0x084);
1208 write_phy_reg(pi, 0x44a, 0x080);
1209 write_phy_reg(pi, 0x6d3, 0x2222);
1210 write_phy_reg(pi, 0x6d3, 0x2220);
1211 } else {
1212 write_phy_reg(pi, 0x942, 0x0);
1213 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1214 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1216 wlapi_switch_macfreq(pi->sh->physhim, enable);
1219 void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
1221 u8 channel = CHSPEC_CHANNEL(chanspec);
1223 wlc_phy_chanspec_radio_set((wlc_phy_t *) pi, chanspec);
1225 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1227 or_phy_reg(pi, 0x44a, 0x44);
1228 write_phy_reg(pi, 0x44a, 0x80);
1230 if (!NORADIO_ENAB(pi->pubpi)) {
1231 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1232 OSL_DELAY(1000);
1235 wlc_lcnphy_toggle_afe_pwdn(pi);
1237 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1238 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1240 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1241 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1243 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 3);
1244 } else {
1245 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1247 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 2);
1250 wlc_lcnphy_load_tx_iir_filter(pi, TRUE, 0);
1252 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1256 static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, uint16 dac_gain)
1258 uint16 dac_ctrl;
1260 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1261 dac_ctrl = dac_ctrl & 0xc7f;
1262 dac_ctrl = dac_ctrl | (dac_gain << 7);
1263 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1267 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
1269 uint16 bit = bEnable ? 1 : 0;
1271 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1273 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1275 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1278 static uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1280 uint16 pa_gain;
1282 pa_gain = (read_phy_reg(pi, 0x4fb) &
1283 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1284 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1286 return pa_gain;
1289 static void
1290 wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
1292 uint16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1294 mod_phy_reg(pi, 0x4b5,
1295 (0xffff << 0),
1296 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1298 mod_phy_reg(pi, 0x4fb,
1299 (0x7fff << 0),
1300 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1302 mod_phy_reg(pi, 0x4fc,
1303 (0xffff << 0),
1304 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1306 mod_phy_reg(pi, 0x4fd,
1307 (0x7fff << 0),
1308 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1310 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1312 wlc_lcnphy_enable_tx_gain_override(pi);
1315 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0)
1317 uint16 m0m1 = (uint16) m0 << 8;
1318 phytbl_info_t tab;
1320 tab.tbl_ptr = &m0m1;
1321 tab.tbl_len = 1;
1322 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1323 tab.tbl_offset = 87;
1324 tab.tbl_width = 16;
1325 wlc_lcnphy_write_table(pi, &tab);
1328 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
1330 uint32 data_buf[64];
1331 phytbl_info_t tab;
1333 bzero(data_buf, sizeof(data_buf));
1335 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1336 tab.tbl_width = 32;
1337 tab.tbl_ptr = data_buf;
1339 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1341 tab.tbl_len = 30;
1342 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1343 wlc_lcnphy_write_table(pi, &tab);
1346 tab.tbl_len = 64;
1347 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1348 wlc_lcnphy_write_table(pi, &tab);
1351 typedef enum {
1352 LCNPHY_TSSI_PRE_PA,
1353 LCNPHY_TSSI_POST_PA,
1354 LCNPHY_TSSI_EXT
1355 } lcnphy_tssi_mode_t;
1357 static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
1359 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1361 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1363 if (LCNPHY_TSSI_POST_PA == pos) {
1364 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1366 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1368 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1369 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1370 } else {
1371 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1372 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1374 } else {
1375 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1377 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1379 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1380 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1381 } else {
1382 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
1383 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1386 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1388 if (LCNPHY_TSSI_EXT == pos) {
1389 write_radio_reg(pi, RADIO_2064_REG07F, 1);
1390 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
1391 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
1392 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
1396 static uint16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1398 uint16 N1, N2, N3, N4, N5, N6, N;
1399 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1400 >> 0);
1401 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1402 >> 12);
1403 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1404 >> 0);
1405 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1406 >> 8);
1407 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1408 >> 0);
1409 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1410 >> 8);
1411 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1412 if (N < 1600)
1413 N = 1600;
1414 return N;
1417 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1419 uint16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
1420 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1422 auxpga_vmid =
1423 (2 << 8) | (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
1424 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
1425 auxpga_gain_temp = 2;
1427 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
1429 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
1431 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
1433 mod_phy_reg(pi, 0x4db,
1434 (0x3ff << 0) |
1435 (0x7 << 12),
1436 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1438 mod_phy_reg(pi, 0x4dc,
1439 (0x3ff << 0) |
1440 (0x7 << 12),
1441 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1443 mod_phy_reg(pi, 0x40a,
1444 (0x3ff << 0) |
1445 (0x7 << 12),
1446 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1448 mod_phy_reg(pi, 0x40b,
1449 (0x3ff << 0) |
1450 (0x7 << 12),
1451 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1453 mod_phy_reg(pi, 0x40c,
1454 (0x3ff << 0) |
1455 (0x7 << 12),
1456 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1458 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
1461 static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
1463 phytbl_info_t tab;
1464 uint32 rfseq, ind;
1466 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1467 tab.tbl_width = 32;
1468 tab.tbl_ptr = &ind;
1469 tab.tbl_len = 1;
1470 tab.tbl_offset = 0;
1471 for (ind = 0; ind < 128; ind++) {
1472 wlc_lcnphy_write_table(pi, &tab);
1473 tab.tbl_offset++;
1475 tab.tbl_offset = 704;
1476 for (ind = 0; ind < 128; ind++) {
1477 wlc_lcnphy_write_table(pi, &tab);
1478 tab.tbl_offset++;
1480 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
1482 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
1484 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
1486 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
1487 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
1489 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
1491 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
1493 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
1495 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
1497 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
1499 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
1501 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
1503 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
1505 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
1507 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
1509 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
1511 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
1513 wlc_lcnphy_clear_tx_power_offsets(pi);
1515 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
1517 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
1519 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
1521 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1522 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
1523 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1524 } else {
1525 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1526 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
1529 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
1531 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1532 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1533 } else {
1534 if (CHSPEC_IS2G(pi->radio_chanspec))
1535 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1536 else
1537 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
1540 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
1541 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1542 else
1543 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
1545 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
1547 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
1549 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1550 mod_phy_reg(pi, 0x4d7,
1551 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
1554 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
1555 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
1556 tab.tbl_width = 16;
1557 tab.tbl_ptr = &rfseq;
1558 tab.tbl_len = 1;
1559 tab.tbl_offset = 6;
1560 wlc_lcnphy_write_table(pi, &tab);
1562 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
1564 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
1566 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1568 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
1570 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
1572 wlc_lcnphy_pwrctrl_rssiparams(pi);
1575 void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
1577 uint16 tx_cnt, tx_total, npt;
1578 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1580 tx_total = wlc_lcnphy_total_tx_frames(pi);
1581 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
1582 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
1584 if (tx_cnt > (1 << npt)) {
1586 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
1588 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
1589 pi_lcn->lcnphy_tssi_npt = npt;
1594 int32 wlc_lcnphy_tssi2dbm(int32 tssi, int32 a1, int32 b0, int32 b1)
1596 int32 a, b, p;
1598 a = 32768 + (a1 * tssi);
1599 b = (1024 * b0) + (64 * b1 * tssi);
1600 p = ((2 * b) + a) / (2 * a);
1602 return p;
1605 static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
1607 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1608 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1609 return;
1611 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
1612 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
1615 void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
1617 phytbl_info_t tab;
1618 uint32 rate_table[WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM +
1619 WLC_NUM_RATES_MCS_1_STREAM];
1620 uint i, j;
1621 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1622 return;
1624 for (i = 0, j = 0; i < ARRAYSIZE(rate_table); i++, j++) {
1626 if (i == WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM)
1627 j = TXP_FIRST_MCS_20_SISO;
1629 rate_table[i] = (uint32) ((int32) (-pi->tx_power_offset[j]));
1632 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1633 tab.tbl_width = 32;
1634 tab.tbl_len = ARRAYSIZE(rate_table);
1635 tab.tbl_ptr = rate_table;
1636 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1637 wlc_lcnphy_write_table(pi, &tab);
1639 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
1640 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
1642 wlc_lcnphy_txpower_reset_npt(pi);
1646 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, s8 index)
1648 uint32 cck_offset[4] = { 22, 22, 22, 22 };
1649 uint32 ofdm_offset, reg_offset_cck;
1650 int i;
1651 uint16 index2;
1652 phytbl_info_t tab;
1654 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1655 return;
1657 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1659 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
1661 or_phy_reg(pi, 0x6da, 0x0040);
1663 reg_offset_cck = 0;
1664 for (i = 0; i < 4; i++)
1665 cck_offset[i] -= reg_offset_cck;
1666 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1667 tab.tbl_width = 32;
1668 tab.tbl_len = 4;
1669 tab.tbl_ptr = cck_offset;
1670 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1671 wlc_lcnphy_write_table(pi, &tab);
1672 ofdm_offset = 0;
1673 tab.tbl_len = 1;
1674 tab.tbl_ptr = &ofdm_offset;
1675 for (i = 836; i < 862; i++) {
1676 tab.tbl_offset = i;
1677 wlc_lcnphy_write_table(pi, &tab);
1680 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
1682 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1684 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
1686 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
1688 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
1690 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
1692 index2 = (uint16) (index * 2);
1693 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1695 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1699 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1701 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
1702 int16 manp, meas_temp, temp_diff;
1703 bool neg = 0;
1704 uint16 temp;
1705 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1707 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1708 return pi_lcn->lcnphy_current_index;
1710 index = FIXED_TXPWR;
1712 if (NORADIO_ENAB(pi->pubpi))
1713 return index;
1715 if (pi_lcn->lcnphy_tempsense_slope == 0) {
1716 return index;
1718 temp = (uint16) wlc_lcnphy_tempsense(pi, 0);
1719 meas_temp = LCNPHY_TEMPSENSE(temp);
1721 if (pi->tx_power_min != 0) {
1722 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
1723 } else {
1724 delta_brd = 0;
1727 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
1728 temp_diff = manp - meas_temp;
1729 if (temp_diff < 0) {
1731 neg = 1;
1733 temp_diff = -temp_diff;
1736 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((uint32) (temp_diff * 192),
1737 (uint32) (pi_lcn->
1738 lcnphy_tempsense_slope
1739 * 10), 0);
1740 if (neg)
1741 delta_temp = -delta_temp;
1743 if (pi_lcn->lcnphy_tempsense_option == 3
1744 && LCNREV_IS(pi->pubpi.phy_rev, 0))
1745 delta_temp = 0;
1746 if (pi_lcn->lcnphy_tempcorrx > 31)
1747 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
1748 else
1749 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
1750 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1751 tempcorrx = 4;
1752 new_index =
1753 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1754 new_index += tempcorrx;
1756 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1757 index = 127;
1758 if (new_index < 0 || new_index > 126) {
1759 return index;
1761 return new_index;
1764 static uint16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, uint16 mode)
1767 uint16 current_mode = mode;
1768 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1769 mode == LCNPHY_TX_PWR_CTRL_HW)
1770 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1771 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1772 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1773 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1774 return current_mode;
1777 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, uint16 mode)
1779 uint16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1780 s8 index;
1781 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1783 ASSERT((LCNPHY_TX_PWR_CTRL_OFF == mode) ||
1784 (LCNPHY_TX_PWR_CTRL_SW == mode) ||
1785 (LCNPHY_TX_PWR_CTRL_HW == mode) ||
1786 (LCNPHY_TX_PWR_CTRL_TEMPBASED == mode));
1788 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
1789 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
1791 mod_phy_reg(pi, 0x6da, (0x1 << 6),
1792 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
1794 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
1795 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
1797 if (old_mode != mode) {
1798 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
1800 wlc_lcnphy_tx_pwr_update_npt(pi);
1802 wlc_lcnphy_clear_tx_power_offsets(pi);
1804 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
1806 wlc_lcnphy_txpower_recalc_target(pi);
1808 wlc_lcnphy_set_start_tx_pwr_idx(pi,
1809 pi_lcn->
1810 lcnphy_tssi_idx);
1811 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
1812 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
1814 pi_lcn->lcnphy_tssi_tx_cnt =
1815 wlc_lcnphy_total_tx_frames(pi);
1817 wlc_lcnphy_disable_tx_gain_override(pi);
1818 pi_lcn->lcnphy_tx_power_idx_override = -1;
1819 } else
1820 wlc_lcnphy_enable_tx_gain_override(pi);
1822 mod_phy_reg(pi, 0x4a4,
1823 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
1824 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
1825 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
1826 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
1827 pi_lcn->lcnphy_current_index = (s8)
1828 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1833 static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
1835 uint delay_count = 0;
1837 while (wlc_lcnphy_iqcal_active(pi)) {
1838 OSL_DELAY(100);
1839 delay_count++;
1841 if (delay_count > (10 * 500))
1842 break;
1845 return (0 == wlc_lcnphy_iqcal_active(pi));
1848 static void
1849 wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1850 lcnphy_txgains_t *target_gains,
1851 lcnphy_cal_mode_t cal_mode, bool keep_tone)
1854 lcnphy_txgains_t cal_gains, temp_gains;
1855 uint16 hash;
1856 u8 band_idx;
1857 int j;
1858 uint16 ncorr_override[5];
1859 uint16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1860 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1863 uint16 commands_fullcal[] = {
1864 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1866 uint16 commands_recal[] = {
1867 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1869 uint16 command_nums_fullcal[] = {
1870 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1872 uint16 command_nums_recal[] = {
1873 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1874 uint16 *command_nums = command_nums_fullcal;
1876 uint16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1877 uint16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1878 uint16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
1879 bool tx_gain_override_old;
1880 lcnphy_txgains_t old_gains;
1881 uint i, n_cal_cmds = 0, n_cal_start = 0;
1882 uint16 *values_to_save;
1883 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1885 if (NORADIO_ENAB(pi->pubpi))
1886 return;
1888 values_to_save = MALLOC(pi->sh->osh, sizeof(uint16) * 20);
1889 if (NULL == values_to_save) {
1890 return;
1893 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1894 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1896 or_phy_reg(pi, 0x6da, 0x40);
1897 or_phy_reg(pi, 0x6db, 0x3);
1899 switch (cal_mode) {
1900 case LCNPHY_CAL_FULL:
1901 start_coeffs = syst_coeffs;
1902 cal_cmds = commands_fullcal;
1903 n_cal_cmds = ARRAYSIZE(commands_fullcal);
1904 break;
1906 case LCNPHY_CAL_RECAL:
1907 ASSERT(pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid);
1909 start_coeffs = syst_coeffs;
1911 cal_cmds = commands_recal;
1912 n_cal_cmds = ARRAYSIZE(commands_recal);
1913 command_nums = command_nums_recal;
1914 break;
1915 default:
1916 ASSERT(FALSE);
1919 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1920 start_coeffs, 11, 16, 64);
1922 write_phy_reg(pi, 0x6da, 0xffff);
1923 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
1925 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1927 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1929 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1931 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
1933 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
1935 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
1937 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
1939 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1940 if (tx_gain_override_old)
1941 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1943 if (!target_gains) {
1944 if (!tx_gain_override_old)
1945 wlc_lcnphy_set_tx_pwr_by_index(pi,
1946 pi_lcn->lcnphy_tssi_idx);
1947 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
1948 target_gains = &temp_gains;
1951 hash = (target_gains->gm_gain << 8) |
1952 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
1954 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
1956 cal_gains = *target_gains;
1957 bzero(ncorr_override, sizeof(ncorr_override));
1958 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
1959 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
1960 cal_gains.gm_gain =
1961 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
1962 cal_gains.pga_gain =
1963 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
1964 cal_gains.pad_gain =
1965 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
1966 bcopy(&tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
1967 ncorr_override, sizeof(ncorr_override));
1968 break;
1972 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
1974 write_phy_reg(pi, 0x453, 0xaa9);
1975 write_phy_reg(pi, 0x93d, 0xc0);
1977 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1978 (CONST void *)
1979 lcnphy_iqcal_loft_gainladder,
1980 ARRAYSIZE(lcnphy_iqcal_loft_gainladder),
1981 16, 0);
1983 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1984 (CONST void *)lcnphy_iqcal_ir_gainladder,
1985 ARRAYSIZE(lcnphy_iqcal_ir_gainladder), 16,
1986 32);
1988 if (pi->phy_tx_tone_freq) {
1990 wlc_lcnphy_stop_tx_tone(pi);
1991 OSL_DELAY(5);
1992 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1993 } else {
1994 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1997 write_phy_reg(pi, 0x6da, 0xffff);
1999 for (i = n_cal_start; i < n_cal_cmds; i++) {
2000 uint16 zero_diq = 0;
2001 uint16 best_coeffs[11];
2002 uint16 command_num;
2004 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2006 command_num = command_nums[i];
2007 if (ncorr_override[cal_type])
2008 command_num =
2009 ncorr_override[cal_type] << 8 | (command_num &
2010 0xff);
2012 write_phy_reg(pi, 0x452, command_num);
2014 if ((cal_type == 3) || (cal_type == 4)) {
2016 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2017 &diq_start, 1, 16, 69);
2019 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2020 &zero_diq, 1, 16, 69);
2023 write_phy_reg(pi, 0x451, cal_cmds[i]);
2025 if (!wlc_lcnphy_iqcal_wait(pi)) {
2027 goto cleanup;
2030 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2031 best_coeffs,
2032 ARRAYSIZE(best_coeffs), 16, 96);
2033 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2034 best_coeffs,
2035 ARRAYSIZE(best_coeffs), 16, 64);
2037 if ((cal_type == 3) || (cal_type == 4)) {
2038 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2039 &diq_start, 1, 16, 69);
2041 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2042 pi_lcn->lcnphy_cal_results.
2043 txiqlocal_bestcoeffs,
2044 ARRAYSIZE(pi_lcn->
2045 lcnphy_cal_results.
2046 txiqlocal_bestcoeffs),
2047 16, 96);
2050 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2051 pi_lcn->lcnphy_cal_results.
2052 txiqlocal_bestcoeffs,
2053 ARRAYSIZE(pi_lcn->lcnphy_cal_results.
2054 txiqlocal_bestcoeffs), 16, 96);
2055 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = TRUE;
2057 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2058 &pi_lcn->lcnphy_cal_results.
2059 txiqlocal_bestcoeffs[0], 4, 16, 80);
2061 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2062 &pi_lcn->lcnphy_cal_results.
2063 txiqlocal_bestcoeffs[5], 2, 16, 85);
2065 cleanup:
2066 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2067 MFREE(pi->sh->osh, values_to_save, 20 * sizeof(uint16));
2069 if (!keep_tone)
2070 wlc_lcnphy_stop_tx_tone(pi);
2072 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2074 write_phy_reg(pi, 0x453, 0);
2076 if (tx_gain_override_old)
2077 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2078 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2080 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2081 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2085 static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
2087 bool suspend, tx_gain_override_old;
2088 lcnphy_txgains_t old_gains;
2089 phy_info_t *pi = (phy_info_t *) ppi;
2090 uint16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2091 idleTssi0_regvalue_2C;
2092 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2093 uint16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2094 uint16 SAVE_jtag_bb_afe_switch =
2095 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2096 uint16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2097 uint16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2098 idleTssi = read_phy_reg(pi, 0x4ab);
2099 suspend =
2100 (0 ==
2101 (R_REG(pi->sh->osh, &((phy_info_t *) pi)->regs->maccontrol) &
2102 MCTL_EN_MAC));
2103 if (!suspend)
2104 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2105 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2107 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2108 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2110 wlc_lcnphy_enable_tx_gain_override(pi);
2111 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2112 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2113 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2114 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2115 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2116 wlc_lcnphy_tssi_setup(pi);
2117 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
2118 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2119 >> 0);
2121 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2122 >> 0);
2124 if (idleTssi0_2C >= 256)
2125 idleTssi0_OB = idleTssi0_2C - 256;
2126 else
2127 idleTssi0_OB = idleTssi0_2C + 256;
2129 idleTssi0_regvalue_OB = idleTssi0_OB;
2130 if (idleTssi0_regvalue_OB >= 256)
2131 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2132 else
2133 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2134 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2136 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2138 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2139 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2140 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2142 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2143 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2144 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2145 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2146 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2147 if (!suspend)
2148 wlapi_enable_mac(pi->sh->physhim);
2151 static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, u8 mode)
2153 bool suspend;
2154 uint16 save_txpwrCtrlEn;
2155 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2156 uint16 auxpga_vmid;
2157 phytbl_info_t tab;
2158 uint32 val;
2159 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2160 save_reg112;
2161 uint16 values_to_save[14];
2162 s8 index;
2163 int i;
2164 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2165 OSL_DELAY(999);
2167 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2168 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2169 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2170 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2171 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2172 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2174 for (i = 0; i < 14; i++)
2175 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2176 suspend =
2177 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2178 if (!suspend)
2179 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2180 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2182 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2183 index = pi_lcn->lcnphy_current_index;
2184 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2185 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2186 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2187 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2188 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2190 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2192 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2194 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2196 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2198 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2200 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2202 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2204 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2206 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2208 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2210 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2212 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2214 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2216 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2218 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2220 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2222 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2224 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2226 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2228 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2230 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2232 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2234 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2235 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2236 tab.tbl_width = 16;
2237 tab.tbl_len = 1;
2238 tab.tbl_ptr = &val;
2239 tab.tbl_offset = 6;
2240 wlc_lcnphy_write_table(pi, &tab);
2241 if (mode == TEMPSENSE) {
2242 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2244 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2246 auxpga_vmidcourse = 8;
2247 auxpga_vmidfine = 0x4;
2248 auxpga_gain = 2;
2249 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2250 } else {
2251 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2253 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2255 auxpga_vmidcourse = 7;
2256 auxpga_vmidfine = 0xa;
2257 auxpga_gain = 2;
2259 auxpga_vmid =
2260 (uint16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2261 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2263 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2265 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2267 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2269 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2271 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2273 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
2274 if (!tempsense_done(pi))
2275 OSL_DELAY(10);
2277 write_radio_reg(pi, RADIO_2064_REG007, (uint16) save_reg007);
2278 write_radio_reg(pi, RADIO_2064_REG0FF, (uint16) save_reg0FF);
2279 write_radio_reg(pi, RADIO_2064_REG11F, (uint16) save_reg11F);
2280 write_radio_reg(pi, RADIO_2064_REG005, (uint16) save_reg005);
2281 write_radio_reg(pi, RADIO_2064_REG025, (uint16) save_reg025);
2282 write_radio_reg(pi, RADIO_2064_REG112, (uint16) save_reg112);
2283 for (i = 0; i < 14; i++)
2284 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2285 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
2287 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
2288 if (!suspend)
2289 wlapi_enable_mac(pi->sh->physhim);
2290 OSL_DELAY(999);
2293 void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi)
2295 lcnphy_txgains_t tx_gains;
2296 u8 bbmult;
2297 phytbl_info_t tab;
2298 int32 a1, b0, b1;
2299 int32 tssi, pwr, maxtargetpwr, mintargetpwr;
2300 bool suspend;
2301 phy_info_t *pi = (phy_info_t *) ppi;
2303 suspend =
2304 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2305 if (!suspend)
2306 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2308 if (NORADIO_ENAB(pi->pubpi)) {
2309 wlc_lcnphy_set_bbmult(pi, 0x30);
2310 if (!suspend)
2311 wlapi_enable_mac(pi->sh->physhim);
2312 return;
2315 if (!pi->hwpwrctrl_capable) {
2316 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2317 tx_gains.gm_gain = 4;
2318 tx_gains.pga_gain = 12;
2319 tx_gains.pad_gain = 12;
2320 tx_gains.dac_gain = 0;
2322 bbmult = 150;
2323 } else {
2324 tx_gains.gm_gain = 7;
2325 tx_gains.pga_gain = 15;
2326 tx_gains.pad_gain = 14;
2327 tx_gains.dac_gain = 0;
2329 bbmult = 150;
2331 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
2332 wlc_lcnphy_set_bbmult(pi, bbmult);
2333 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2334 } else {
2336 wlc_lcnphy_idle_tssi_est(ppi);
2338 wlc_lcnphy_clear_tx_power_offsets(pi);
2340 b0 = pi->txpa_2g[0];
2341 b1 = pi->txpa_2g[1];
2342 a1 = pi->txpa_2g[2];
2343 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
2344 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
2346 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2347 tab.tbl_width = 32;
2348 tab.tbl_ptr = &pwr;
2349 tab.tbl_len = 1;
2350 tab.tbl_offset = 0;
2351 for (tssi = 0; tssi < 128; tssi++) {
2352 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
2354 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
2355 wlc_lcnphy_write_table(pi, &tab);
2356 tab.tbl_offset++;
2359 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
2361 write_phy_reg(pi, 0x4a8, 10);
2363 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
2365 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
2367 if (!suspend)
2368 wlapi_enable_mac(pi->sh->physhim);
2371 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2373 uint16 m0m1;
2374 phytbl_info_t tab;
2376 tab.tbl_ptr = &m0m1;
2377 tab.tbl_len = 1;
2378 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2379 tab.tbl_offset = 87;
2380 tab.tbl_width = 16;
2381 wlc_lcnphy_read_table(pi, &tab);
2383 return (u8) ((m0m1 & 0xff00) >> 8);
2386 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 gain)
2388 mod_phy_reg(pi, 0x4fb,
2389 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
2390 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
2391 mod_phy_reg(pi, 0x4fd,
2392 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
2393 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
2396 void
2397 wlc_lcnphy_get_radio_loft(phy_info_t *pi,
2398 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
2400 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
2401 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
2402 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
2403 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
2406 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
2408 uint16 dac_gain;
2410 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2411 gains->dac_gain = (dac_gain & 0x380) >> 7;
2414 uint16 rfgain0, rfgain1;
2416 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
2417 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
2419 gains->gm_gain = rfgain0 & 0xff;
2420 gains->pga_gain = (rfgain0 >> 8) & 0xff;
2421 gains->pad_gain = rfgain1 & 0xff;
2425 void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, uint16 a, uint16 b)
2427 phytbl_info_t tab;
2428 uint16 iqcc[2];
2430 iqcc[0] = a;
2431 iqcc[1] = b;
2433 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2434 tab.tbl_width = 16;
2435 tab.tbl_ptr = iqcc;
2436 tab.tbl_len = 2;
2437 tab.tbl_offset = 80;
2438 wlc_lcnphy_write_table(pi, &tab);
2441 void wlc_lcnphy_set_tx_locc(phy_info_t *pi, uint16 didq)
2443 phytbl_info_t tab;
2445 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2446 tab.tbl_width = 16;
2447 tab.tbl_ptr = &didq;
2448 tab.tbl_len = 1;
2449 tab.tbl_offset = 85;
2450 wlc_lcnphy_write_table(pi, &tab);
2453 void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
2455 phytbl_info_t tab;
2456 uint16 a, b;
2457 u8 bb_mult;
2458 uint32 bbmultiqcomp, txgain, locoeffs, rfpower;
2459 lcnphy_txgains_t gains;
2460 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2462 ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2464 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
2465 pi_lcn->lcnphy_current_index = (u8) index;
2467 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2468 tab.tbl_width = 32;
2469 tab.tbl_len = 1;
2471 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2473 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
2474 tab.tbl_ptr = &bbmultiqcomp;
2475 wlc_lcnphy_read_table(pi, &tab);
2477 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
2478 tab.tbl_width = 32;
2479 tab.tbl_ptr = &txgain;
2480 wlc_lcnphy_read_table(pi, &tab);
2482 gains.gm_gain = (uint16) (txgain & 0xff);
2483 gains.pga_gain = (uint16) (txgain >> 8) & 0xff;
2484 gains.pad_gain = (uint16) (txgain >> 16) & 0xff;
2485 gains.dac_gain = (uint16) (bbmultiqcomp >> 28) & 0x07;
2486 wlc_lcnphy_set_tx_gain(pi, &gains);
2487 wlc_lcnphy_set_pa_gain(pi, (uint16) (txgain >> 24) & 0x7f);
2489 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
2490 wlc_lcnphy_set_bbmult(pi, bb_mult);
2492 wlc_lcnphy_enable_tx_gain_override(pi);
2494 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2496 a = (uint16) ((bbmultiqcomp >> 10) & 0x3ff);
2497 b = (uint16) (bbmultiqcomp & 0x3ff);
2498 wlc_lcnphy_set_tx_iqcc(pi, a, b);
2500 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
2501 tab.tbl_ptr = &locoeffs;
2502 wlc_lcnphy_read_table(pi, &tab);
2504 wlc_lcnphy_set_tx_locc(pi, (uint16) locoeffs);
2506 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
2507 tab.tbl_ptr = &rfpower;
2508 wlc_lcnphy_read_table(pi, &tab);
2509 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
2514 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
2517 mod_phy_reg(pi, 0x44d,
2518 (0x1 << 1) |
2519 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
2521 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
2524 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
2526 uint32 j;
2527 phytbl_info_t tab;
2528 uint32 temp_offset[128];
2529 tab.tbl_ptr = temp_offset;
2530 tab.tbl_len = 128;
2531 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
2532 tab.tbl_width = 32;
2533 tab.tbl_offset = 0;
2535 bzero(temp_offset, sizeof(temp_offset));
2536 for (j = 1; j < 128; j += 2)
2537 temp_offset[j] = 0x80000;
2539 wlc_lcnphy_write_table(pi, &tab);
2540 return;
2543 static void
2544 wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
2545 uint16 trsw,
2546 uint16 ext_lna,
2547 uint16 biq2,
2548 uint16 biq1,
2549 uint16 tia, uint16 lna2, uint16 lna1)
2551 uint16 gain0_15, gain16_19;
2553 gain16_19 = biq2 & 0xf;
2554 gain0_15 = ((biq1 & 0xf) << 12) |
2555 ((tia & 0xf) << 8) |
2556 ((lna2 & 0x3) << 6) |
2557 ((lna2 & 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
2559 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
2560 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
2561 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
2563 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2564 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2565 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
2566 } else {
2567 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
2569 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
2571 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2574 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
2578 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
2580 uint16 ebit = enable ? 1 : 0;
2582 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
2584 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
2586 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2587 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
2588 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
2589 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2590 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
2591 } else {
2592 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
2593 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
2594 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2597 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2598 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
2599 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
2603 void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
2605 if (!bEnable) {
2607 and_phy_reg(pi, 0x43b, ~(uint16) ((0x1 << 1) | (0x1 << 4)));
2609 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2611 and_phy_reg(pi, 0x44c,
2612 ~(uint16) ((0x1 << 3) |
2613 (0x1 << 5) |
2614 (0x1 << 12) |
2615 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2617 and_phy_reg(pi, 0x44d,
2618 ~(uint16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
2619 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
2621 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
2623 and_phy_reg(pi, 0x4f9,
2624 ~(uint16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2626 and_phy_reg(pi, 0x4fa,
2627 ~(uint16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2628 } else {
2630 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2631 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2633 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
2634 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
2636 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2637 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2639 wlc_lcnphy_set_trsw_override(pi, TRUE, FALSE);
2641 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
2642 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
2644 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2646 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2647 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
2649 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2650 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
2652 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2653 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
2655 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2656 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
2658 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2659 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
2660 } else {
2662 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2663 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
2665 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2666 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
2668 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2669 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
2671 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2672 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
2674 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2675 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
2680 static void
2681 wlc_lcnphy_run_samples(phy_info_t *pi,
2682 uint16 num_samps,
2683 uint16 num_loops, uint16 wait, bool iqcalmode)
2686 or_phy_reg(pi, 0x6da, 0x8080);
2688 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
2689 if (num_loops != 0xffff)
2690 num_loops--;
2691 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
2693 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
2695 if (iqcalmode) {
2697 and_phy_reg(pi, 0x453, (uint16) ~(0x1 << 15));
2698 or_phy_reg(pi, 0x453, (0x1 << 15));
2699 } else {
2700 write_phy_reg(pi, 0x63f, 1);
2701 wlc_lcnphy_tx_pu(pi, 1);
2704 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2707 void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
2710 u8 phybw40;
2711 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
2713 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2714 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2715 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2716 } else {
2717 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2718 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2721 if (phybw40 == 0) {
2722 mod_phy_reg((pi), 0x410,
2723 (0x1 << 6) |
2724 (0x1 << 5),
2725 ((CHSPEC_IS2G(pi->radio_chanspec)) ? (!mode) : 0) <<
2726 6 | (!mode) << 5);
2727 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
2731 void
2732 wlc_lcnphy_start_tx_tone(phy_info_t *pi, int32 f_kHz, uint16 max_val,
2733 bool iqcalmode)
2735 u8 phy_bw;
2736 uint16 num_samps, t, k;
2737 uint32 bw;
2738 fixed theta = 0, rot = 0;
2739 cint32 tone_samp;
2740 uint32 data_buf[64];
2741 uint16 i_samp, q_samp;
2742 phytbl_info_t tab;
2743 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2745 pi->phy_tx_tone_freq = f_kHz;
2747 wlc_lcnphy_deaf_mode(pi, TRUE);
2749 phy_bw = 40;
2750 if (pi_lcn->lcnphy_spurmod) {
2751 write_phy_reg(pi, 0x942, 0x2);
2752 write_phy_reg(pi, 0x93b, 0x0);
2753 write_phy_reg(pi, 0x93c, 0x0);
2754 wlc_lcnphy_txrx_spur_avoidance_mode(pi, FALSE);
2757 if (f_kHz) {
2758 k = 1;
2759 do {
2760 bw = phy_bw * 1000 * k;
2761 num_samps = bw / ABS(f_kHz);
2762 ASSERT(num_samps <= ARRAYSIZE(data_buf));
2763 k++;
2764 } while ((num_samps * (uint32) (ABS(f_kHz))) != bw);
2765 } else
2766 num_samps = 2;
2768 rot = FIXED((f_kHz * 36) / phy_bw) / 100;
2769 theta = 0;
2771 for (t = 0; t < num_samps; t++) {
2773 wlc_phy_cordic(theta, &tone_samp);
2775 theta += rot;
2777 i_samp = (uint16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2778 q_samp = (uint16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
2779 data_buf[t] = (i_samp << 10) | q_samp;
2782 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
2784 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
2786 tab.tbl_ptr = data_buf;
2787 tab.tbl_len = num_samps;
2788 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
2789 tab.tbl_offset = 0;
2790 tab.tbl_width = 32;
2791 wlc_lcnphy_write_table(pi, &tab);
2793 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
2796 void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
2798 int16 playback_status;
2799 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2801 pi->phy_tx_tone_freq = 0;
2802 if (pi_lcn->lcnphy_spurmod) {
2803 write_phy_reg(pi, 0x942, 0x7);
2804 write_phy_reg(pi, 0x93b, 0x2017);
2805 write_phy_reg(pi, 0x93c, 0x27c5);
2806 wlc_lcnphy_txrx_spur_avoidance_mode(pi, TRUE);
2809 playback_status = read_phy_reg(pi, 0x644);
2810 if (playback_status & (0x1 << 0)) {
2811 wlc_lcnphy_tx_pu(pi, 0);
2812 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
2813 } else if (playback_status & (0x1 << 1))
2814 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
2816 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
2818 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
2820 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
2822 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
2824 wlc_lcnphy_deaf_mode(pi, FALSE);
2827 static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
2830 and_phy_reg(pi, 0x44c, (uint16) ~((0x1 << 1) | (0x1 << 0)));
2833 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, uint16 *a, uint16 *b)
2835 uint16 iqcc[2];
2836 phytbl_info_t tab;
2838 tab.tbl_ptr = iqcc;
2839 tab.tbl_len = 2;
2840 tab.tbl_id = 0;
2841 tab.tbl_offset = 80;
2842 tab.tbl_width = 16;
2843 wlc_lcnphy_read_table(pi, &tab);
2845 *a = iqcc[0];
2846 *b = iqcc[1];
2849 uint16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2851 phytbl_info_t tab;
2852 uint16 didq;
2854 tab.tbl_id = 0;
2855 tab.tbl_width = 16;
2856 tab.tbl_ptr = &didq;
2857 tab.tbl_len = 1;
2858 tab.tbl_offset = 85;
2859 wlc_lcnphy_read_table(pi, &tab);
2861 return didq;
2864 static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
2867 lcnphy_txgains_t target_gains, old_gains;
2868 u8 save_bb_mult;
2869 uint16 a, b, didq, save_pa_gain = 0;
2870 uint idx, SAVE_txpwrindex = 0xFF;
2871 uint32 val;
2872 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2873 phytbl_info_t tab;
2874 u8 ei0, eq0, fi0, fq0;
2875 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2877 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2878 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
2880 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
2882 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
2883 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2885 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2887 target_gains.gm_gain = 7;
2888 target_gains.pga_gain = 0;
2889 target_gains.pad_gain = 21;
2890 target_gains.dac_gain = 0;
2891 wlc_lcnphy_set_tx_gain(pi, &target_gains);
2892 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2894 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
2896 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
2898 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2899 (pi_lcn->
2900 lcnphy_recal ? LCNPHY_CAL_RECAL :
2901 LCNPHY_CAL_FULL), FALSE);
2902 } else {
2904 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2907 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
2908 if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
2909 if (CHSPEC_IS5G(pi->radio_chanspec)) {
2910 target_gains.gm_gain = 255;
2911 target_gains.pga_gain = 255;
2912 target_gains.pad_gain = 0xf0;
2913 target_gains.dac_gain = 0;
2914 } else {
2915 target_gains.gm_gain = 7;
2916 target_gains.pga_gain = 45;
2917 target_gains.pad_gain = 186;
2918 target_gains.dac_gain = 0;
2921 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
2922 || pi_lcn->lcnphy_hw_iqcal_en) {
2924 target_gains.pga_gain = 0;
2925 target_gains.pad_gain = 30;
2926 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2927 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2928 LCNPHY_CAL_FULL, FALSE);
2929 } else {
2931 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2936 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
2938 didq = wlc_lcnphy_get_tx_locc(pi);
2940 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2941 tab.tbl_width = 32;
2942 tab.tbl_ptr = &val;
2944 tab.tbl_len = 1;
2945 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2947 for (idx = 0; idx < 128; idx++) {
2948 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
2950 wlc_lcnphy_read_table(pi, &tab);
2951 val = (val & 0xfff00000) |
2952 ((uint32) (a & 0x3FF) << 10) | (b & 0x3ff);
2953 wlc_lcnphy_write_table(pi, &tab);
2955 val = didq;
2956 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
2957 wlc_lcnphy_write_table(pi, &tab);
2960 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
2961 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
2962 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
2963 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
2964 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
2965 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
2966 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
2968 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
2969 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
2970 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2972 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
2973 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2974 else
2975 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
2978 int16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2980 uint16 tempsenseval1, tempsenseval2;
2981 int16 avg = 0;
2982 bool suspend = 0;
2984 if (NORADIO_ENAB(pi->pubpi))
2985 return -1;
2987 if (mode == 1) {
2988 suspend =
2989 (0 ==
2990 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2991 if (!suspend)
2992 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2993 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2995 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
2996 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
2998 if (tempsenseval1 > 255)
2999 avg = (int16) (tempsenseval1 - 512);
3000 else
3001 avg = (int16) tempsenseval1;
3003 if (tempsenseval2 > 255)
3004 avg += (int16) (tempsenseval2 - 512);
3005 else
3006 avg += (int16) tempsenseval2;
3008 avg /= 2;
3010 if (mode == 1) {
3012 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3014 OSL_DELAY(100);
3015 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3017 if (!suspend)
3018 wlapi_enable_mac(pi->sh->physhim);
3020 return avg;
3023 uint16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3025 uint16 tempsenseval1, tempsenseval2;
3026 int32 avg = 0;
3027 bool suspend = 0;
3028 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3029 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3031 if (NORADIO_ENAB(pi->pubpi))
3032 return -1;
3034 if (mode == 1) {
3035 suspend =
3036 (0 ==
3037 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3038 if (!suspend)
3039 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3040 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3042 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3043 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3045 if (tempsenseval1 > 255)
3046 avg = (int)(tempsenseval1 - 512);
3047 else
3048 avg = (int)tempsenseval1;
3050 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
3051 if (tempsenseval2 > 255)
3052 avg = (int)(avg - tempsenseval2 + 512);
3053 else
3054 avg = (int)(avg - tempsenseval2);
3055 } else {
3056 if (tempsenseval2 > 255)
3057 avg = (int)(avg + tempsenseval2 - 512);
3058 else
3059 avg = (int)(avg + tempsenseval2);
3060 avg = avg / 2;
3062 if (avg < 0)
3063 avg = avg + 512;
3065 if (pi_lcn->lcnphy_tempsense_option == 2)
3066 avg = tempsenseval1;
3068 if (mode)
3069 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3071 if (mode == 1) {
3073 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3075 OSL_DELAY(100);
3076 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3078 if (!suspend)
3079 wlapi_enable_mac(pi->sh->physhim);
3081 return (uint16) avg;
3084 s8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
3086 int32 degree = wlc_lcnphy_tempsense_new(pi, mode);
3087 degree =
3088 ((degree << 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
3089 / LCN_TEMPSENSE_DEN;
3090 return (s8) degree;
3093 s8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3095 uint16 vbatsenseval;
3096 int32 avg = 0;
3097 bool suspend = 0;
3099 if (NORADIO_ENAB(pi->pubpi))
3100 return -1;
3102 if (mode == 1) {
3103 suspend =
3104 (0 ==
3105 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3106 if (!suspend)
3107 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3108 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
3111 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
3113 if (vbatsenseval > 255)
3114 avg = (int32) (vbatsenseval - 512);
3115 else
3116 avg = (int32) vbatsenseval;
3118 avg =
3119 (avg * LCN_VBAT_SCALE_NOM +
3120 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
3122 if (mode == 1) {
3123 if (!suspend)
3124 wlapi_enable_mac(pi->sh->physhim);
3126 return (s8) avg;
3129 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode)
3131 u8 phybw40;
3132 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3134 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
3136 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
3137 (mode == AFE_CLK_INIT_MODE_TXRX2X))
3138 write_phy_reg(pi, 0x6d0, 0x7);
3140 wlc_lcnphy_toggle_afe_pwdn(pi);
3143 static bool
3144 wlc_lcnphy_rx_iq_est(phy_info_t *pi,
3145 uint16 num_samps,
3146 u8 wait_time, lcnphy_iq_est_t *iq_est)
3148 int wait_count = 0;
3149 bool result = TRUE;
3150 u8 phybw40;
3151 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3153 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
3155 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
3157 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
3159 mod_phy_reg(pi, 0x481, (0xff << 0), ((uint16) wait_time) << 0);
3161 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
3163 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
3165 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
3167 if (wait_count > (10 * 500)) {
3168 result = FALSE;
3169 goto cleanup;
3171 OSL_DELAY(100);
3172 wait_count++;
3175 iq_est->iq_prod = ((uint32) read_phy_reg(pi, 0x483) << 16) |
3176 (uint32) read_phy_reg(pi, 0x484);
3177 iq_est->i_pwr = ((uint32) read_phy_reg(pi, 0x485) << 16) |
3178 (uint32) read_phy_reg(pi, 0x486);
3179 iq_est->q_pwr = ((uint32) read_phy_reg(pi, 0x487) << 16) |
3180 (uint32) read_phy_reg(pi, 0x488);
3182 cleanup:
3183 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
3185 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
3187 return result;
3190 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, uint16 num_samps)
3192 #define LCNPHY_MIN_RXIQ_PWR 2
3193 bool result;
3194 uint16 a0_new, b0_new;
3195 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3196 int32 a, b, temp;
3197 int16 iq_nbits, qq_nbits, arsh, brsh;
3198 int32 iq;
3199 uint32 ii, qq;
3200 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3202 a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
3203 b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
3204 mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
3206 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
3208 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
3210 result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
3211 if (!result)
3212 goto cleanup;
3214 iq = (int32) iq_est.iq_prod;
3215 ii = iq_est.i_pwr;
3216 qq = iq_est.q_pwr;
3218 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
3219 result = FALSE;
3220 goto cleanup;
3223 iq_nbits = wlc_phy_nbits(iq);
3224 qq_nbits = wlc_phy_nbits(qq);
3226 arsh = 10 - (30 - iq_nbits);
3227 if (arsh >= 0) {
3228 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
3229 temp = (int32) (ii >> arsh);
3230 if (temp == 0) {
3231 return FALSE;
3233 } else {
3234 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3235 temp = (int32) (ii << -arsh);
3236 if (temp == 0) {
3237 return FALSE;
3240 a /= temp;
3241 brsh = qq_nbits - 31 + 20;
3242 if (brsh >= 0) {
3243 b = (qq << (31 - qq_nbits));
3244 temp = (int32) (ii >> brsh);
3245 if (temp == 0) {
3246 return FALSE;
3248 } else {
3249 b = (qq << (31 - qq_nbits));
3250 temp = (int32) (ii << -brsh);
3251 if (temp == 0) {
3252 return FALSE;
3255 b /= temp;
3256 b -= a * a;
3257 b = (int32) wlc_phy_sqrt_int((uint32) b);
3258 b -= (1 << 10);
3259 a0_new = (uint16) (a & 0x3ff);
3260 b0_new = (uint16) (b & 0x3ff);
3261 cleanup:
3263 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
3265 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
3267 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
3269 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
3270 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
3272 return result;
3275 static bool
3276 wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
3277 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3278 int tx_gain_idx)
3280 lcnphy_txgains_t old_gains;
3281 uint16 tx_pwr_ctrl;
3282 u8 tx_gain_index_old = 0;
3283 bool result = FALSE, tx_gain_override_old = FALSE;
3284 uint16 i, Core1TxControl_old, RFOverride0_old,
3285 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
3286 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
3287 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
3288 int tia_gain;
3289 uint32 received_power, rx_pwr_threshold;
3290 uint16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3291 uint16 values_to_save[11];
3292 int16 *ptr;
3293 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3295 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
3296 if (NULL == ptr) {
3297 return FALSE;
3299 if (module == 2) {
3300 ASSERT(iqcomp_sz);
3302 while (iqcomp_sz--) {
3303 if (iqcomp[iqcomp_sz].chan ==
3304 CHSPEC_CHANNEL(pi->radio_chanspec)) {
3306 wlc_lcnphy_set_rx_iq_comp(pi,
3307 (uint16)
3308 iqcomp[iqcomp_sz].a,
3309 (uint16)
3310 iqcomp[iqcomp_sz].b);
3311 result = TRUE;
3312 break;
3315 ASSERT(result);
3316 goto cal_done;
3319 if (module == 1) {
3321 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3322 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3324 for (i = 0; i < 11; i++) {
3325 values_to_save[i] =
3326 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
3328 Core1TxControl_old = read_phy_reg(pi, 0x631);
3330 or_phy_reg(pi, 0x631, 0x0015);
3332 RFOverride0_old = read_phy_reg(pi, 0x44c);
3333 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
3334 rfoverride2_old = read_phy_reg(pi, 0x4b0);
3335 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
3336 rfoverride3_old = read_phy_reg(pi, 0x4f9);
3337 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
3338 rfoverride4_old = read_phy_reg(pi, 0x938);
3339 rfoverride4val_old = read_phy_reg(pi, 0x939);
3340 afectrlovr_old = read_phy_reg(pi, 0x43b);
3341 afectrlovrval_old = read_phy_reg(pi, 0x43c);
3342 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3343 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
3345 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
3346 if (tx_gain_override_old) {
3347 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3348 tx_gain_index_old = pi_lcn->lcnphy_current_index;
3351 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
3353 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3354 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3356 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3357 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3359 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
3360 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
3361 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
3362 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
3363 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3364 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
3365 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
3366 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
3367 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
3368 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
3370 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
3371 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
3372 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
3373 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
3374 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
3375 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
3376 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
3377 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
3378 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
3379 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
3381 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3382 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3384 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
3385 write_phy_reg(pi, 0x6da, 0xffff);
3386 or_phy_reg(pi, 0x6db, 0x3);
3387 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
3388 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
3390 tia_gain = 8;
3391 rx_pwr_threshold = 950;
3392 while (tia_gain > 0) {
3393 tia_gain -= 1;
3394 wlc_lcnphy_set_rx_gain_by_distribution(pi,
3395 0, 0, 2, 2,
3396 (uint16)
3397 tia_gain, 1, 0);
3398 OSL_DELAY(500);
3400 received_power =
3401 wlc_lcnphy_measure_digital_power(pi, 2000);
3402 if (received_power < rx_pwr_threshold)
3403 break;
3405 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
3407 wlc_lcnphy_stop_tx_tone(pi);
3409 write_phy_reg(pi, 0x631, Core1TxControl_old);
3411 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
3412 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
3413 write_phy_reg(pi, 0x4b0, rfoverride2_old);
3414 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
3415 write_phy_reg(pi, 0x4f9, rfoverride3_old);
3416 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
3417 write_phy_reg(pi, 0x938, rfoverride4_old);
3418 write_phy_reg(pi, 0x939, rfoverride4val_old);
3419 write_phy_reg(pi, 0x43b, afectrlovr_old);
3420 write_phy_reg(pi, 0x43c, afectrlovrval_old);
3421 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3422 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
3424 wlc_lcnphy_clear_trsw_override(pi);
3426 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
3428 for (i = 0; i < 11; i++) {
3429 write_radio_reg(pi, rxiq_cal_rf_reg[i],
3430 values_to_save[i]);
3433 if (tx_gain_override_old) {
3434 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
3435 } else
3436 wlc_lcnphy_disable_tx_gain_override(pi);
3437 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
3439 wlc_lcnphy_rx_gain_override_enable(pi, FALSE);
3442 cal_done:
3443 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
3444 return result;
3447 static void wlc_lcnphy_temp_adj(phy_info_t *pi)
3449 if (NORADIO_ENAB(pi->pubpi))
3450 return;
3453 static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
3455 bool suspend;
3456 s8 index;
3457 uint16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3458 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3459 suspend =
3460 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3461 if (!suspend)
3462 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3463 wlc_lcnphy_deaf_mode(pi, TRUE);
3464 pi->phy_lastcal = pi->sh->now;
3465 pi->phy_forcecal = FALSE;
3466 index = pi_lcn->lcnphy_current_index;
3468 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3470 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3471 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3472 wlc_lcnphy_deaf_mode(pi, FALSE);
3473 if (!suspend)
3474 wlapi_enable_mac(pi->sh->physhim);
3478 static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
3480 bool suspend, full_cal;
3481 const lcnphy_rx_iqcomp_t *rx_iqcomp;
3482 int rx_iqcomp_sz;
3483 uint16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3484 s8 index;
3485 phytbl_info_t tab;
3486 int32 a1, b0, b1;
3487 int32 tssi, pwr, maxtargetpwr, mintargetpwr;
3488 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3490 if (NORADIO_ENAB(pi->pubpi))
3491 return;
3493 pi->phy_lastcal = pi->sh->now;
3494 pi->phy_forcecal = FALSE;
3495 full_cal =
3496 (pi_lcn->lcnphy_full_cal_channel !=
3497 CHSPEC_CHANNEL(pi->radio_chanspec));
3498 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
3499 index = pi_lcn->lcnphy_current_index;
3501 suspend =
3502 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3503 if (!suspend) {
3505 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
3506 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3508 wlc_lcnphy_deaf_mode(pi, TRUE);
3510 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3512 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
3513 rx_iqcomp_sz = ARRAYSIZE(lcnphy_rx_iqcomp_table_rev0);
3515 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
3516 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, TRUE, FALSE, 1, 40);
3517 else
3518 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, TRUE, FALSE, 1, 127);
3520 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
3522 wlc_lcnphy_idle_tssi_est((wlc_phy_t *) pi);
3524 b0 = pi->txpa_2g[0];
3525 b1 = pi->txpa_2g[1];
3526 a1 = pi->txpa_2g[2];
3527 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3528 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3530 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3531 tab.tbl_width = 32;
3532 tab.tbl_ptr = &pwr;
3533 tab.tbl_len = 1;
3534 tab.tbl_offset = 0;
3535 for (tssi = 0; tssi < 128; tssi++) {
3536 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3537 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3538 wlc_lcnphy_write_table(pi, &tab);
3539 tab.tbl_offset++;
3543 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3544 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3545 wlc_lcnphy_deaf_mode(pi, FALSE);
3546 if (!suspend)
3547 wlapi_enable_mac(pi->sh->physhim);
3550 void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
3552 uint16 temp_new;
3553 int temp1, temp2, temp_diff;
3554 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3556 switch (mode) {
3557 case PHY_PERICAL_CHAN:
3559 break;
3560 case PHY_FULLCAL:
3561 wlc_lcnphy_periodic_cal(pi);
3562 break;
3563 case PHY_PERICAL_PHYINIT:
3564 wlc_lcnphy_periodic_cal(pi);
3565 break;
3566 case PHY_PERICAL_WATCHDOG:
3567 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3568 temp_new = wlc_lcnphy_tempsense(pi, 0);
3569 temp1 = LCNPHY_TEMPSENSE(temp_new);
3570 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
3571 temp_diff = temp1 - temp2;
3572 if ((pi_lcn->lcnphy_cal_counter > 90) ||
3573 (temp_diff > 60) || (temp_diff < -60)) {
3574 wlc_lcnphy_glacial_timer_based_cal(pi);
3575 wlc_2064_vco_cal(pi);
3576 pi_lcn->lcnphy_cal_temper = temp_new;
3577 pi_lcn->lcnphy_cal_counter = 0;
3578 } else
3579 pi_lcn->lcnphy_cal_counter++;
3581 break;
3582 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
3583 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3584 wlc_lcnphy_tx_power_adjustment((wlc_phy_t *) pi);
3585 break;
3586 default:
3587 ASSERT(0);
3588 break;
3592 void wlc_lcnphy_get_tssi(phy_info_t *pi, s8 *ofdm_pwr, s8 *cck_pwr)
3594 s8 cck_offset;
3595 uint16 status;
3596 status = (read_phy_reg(pi, 0x4ab));
3597 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
3598 (status & (0x1 << 15))) {
3599 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
3600 >> 0) >> 1);
3602 if (wlc_phy_tpc_isenabled_lcnphy(pi))
3603 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
3604 else
3605 cck_offset = 0;
3607 *cck_pwr = *ofdm_pwr + cck_offset;
3608 } else {
3609 *cck_pwr = 0;
3610 *ofdm_pwr = 0;
3614 void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi)
3616 return;
3620 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
3622 u8 channel = CHSPEC_CHANNEL(chanspec);
3623 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3625 if (NORADIO_ENAB(pi->pubpi))
3626 return;
3628 if (channel == 14) {
3629 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
3631 } else {
3632 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
3635 pi_lcn->lcnphy_bandedge_corr = 2;
3636 if (channel == 1)
3637 pi_lcn->lcnphy_bandedge_corr = 4;
3639 if (channel == 1 || channel == 2 || channel == 3 ||
3640 channel == 4 || channel == 9 ||
3641 channel == 10 || channel == 11 || channel == 12) {
3642 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
3643 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
3644 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
3646 si_pmu_pllupd(pi->sh->sih);
3647 write_phy_reg(pi, 0x942, 0);
3648 wlc_lcnphy_txrx_spur_avoidance_mode(pi, FALSE);
3649 pi_lcn->lcnphy_spurmod = 0;
3650 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
3652 write_phy_reg(pi, 0x425, 0x5907);
3653 } else {
3654 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
3655 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
3656 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
3658 si_pmu_pllupd(pi->sh->sih);
3659 write_phy_reg(pi, 0x942, 0);
3660 wlc_lcnphy_txrx_spur_avoidance_mode(pi, TRUE);
3662 pi_lcn->lcnphy_spurmod = 0;
3663 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
3665 write_phy_reg(pi, 0x425, 0x590a);
3668 or_phy_reg(pi, 0x44a, 0x44);
3669 write_phy_reg(pi, 0x44a, 0x80);
3672 void
3673 wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng, u8 rate,
3674 struct ether_addr *sa, uint32 wait_delay)
3678 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3680 s8 index;
3681 uint16 index2;
3682 phy_info_t *pi = (phy_info_t *) ppi;
3683 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3684 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3685 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3686 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3687 index2 = (uint16) (index * 2);
3688 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3690 pi_lcn->lcnphy_current_index = (s8)
3691 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3695 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 b)
3697 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3699 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3701 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3703 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3705 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3707 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3711 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3713 u8 phybw40;
3714 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3715 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3717 pi_lcn->lcnphy_cal_counter = 0;
3718 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3720 or_phy_reg(pi, 0x44a, 0x80);
3721 and_phy_reg(pi, 0x44a, 0x7f);
3723 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3725 write_phy_reg(pi, 0x60a, 160);
3727 write_phy_reg(pi, 0x46a, 25);
3729 wlc_lcnphy_baseband_init(pi);
3731 wlc_lcnphy_radio_init(pi);
3733 if (CHSPEC_IS2G(pi->radio_chanspec))
3734 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3736 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3738 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3740 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3742 if ((pi->sh->boardflags & BFL_FEM)
3743 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3744 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
3746 wlc_lcnphy_agc_temp_init(pi);
3748 wlc_lcnphy_temp_adj(pi);
3750 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3752 OSL_DELAY(100);
3753 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3755 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3756 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
3757 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
3760 static void
3761 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, uint16 *values_to_save)
3763 uint16 vmid;
3764 int i;
3765 for (i = 0; i < 20; i++) {
3766 values_to_save[i] =
3767 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
3770 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3771 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3773 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3774 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3776 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3777 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3779 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3780 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3782 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
3783 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
3784 else
3785 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
3786 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
3788 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3789 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3790 OSL_DELAY(20);
3792 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3793 if (CHSPEC_IS5G(pi->radio_chanspec))
3794 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
3795 else
3796 or_radio_reg(pi, RADIO_2064_REG03A, 1);
3797 } else {
3798 if (CHSPEC_IS5G(pi->radio_chanspec))
3799 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
3800 else
3801 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
3804 OSL_DELAY(20);
3806 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
3807 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3808 if (CHSPEC_IS5G(pi->radio_chanspec))
3809 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
3810 else
3811 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
3812 } else {
3813 if (CHSPEC_IS5G(pi->radio_chanspec))
3814 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
3815 else
3816 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
3819 OSL_DELAY(20);
3821 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3822 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3823 OSL_DELAY(20);
3825 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3826 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3827 OSL_DELAY(20);
3829 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3830 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3831 OSL_DELAY(20);
3833 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3834 OSL_DELAY(20);
3836 vmid = 0x2A6;
3837 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
3838 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
3839 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3840 OSL_DELAY(20);
3842 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3843 OSL_DELAY(20);
3844 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
3845 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
3846 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
3847 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
3848 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
3849 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
3850 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
3853 static void
3854 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, uint16 thresh,
3855 int16 *ptr, int mode)
3857 uint32 curval1, curval2, stpptr, curptr, strptr, val;
3858 uint16 sslpnCalibClkEnCtrl, timer;
3859 uint16 old_sslpnCalibClkEnCtrl;
3860 int16 imag, real;
3861 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3863 timer = 0;
3864 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3866 curval1 = R_REG(pi->sh->osh, &pi->regs->psm_corectlsts);
3867 ptr[130] = 0;
3868 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, ((1 << 6) | curval1));
3870 W_REG(pi->sh->osh, &pi->regs->smpl_clct_strptr, 0x7E00);
3871 W_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr, 0x8000);
3872 OSL_DELAY(20);
3873 curval2 = R_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param);
3874 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2 | 0x30);
3876 write_phy_reg(pi, 0x555, 0x0);
3877 write_phy_reg(pi, 0x5a6, 0x5);
3879 write_phy_reg(pi, 0x5a2, (uint16) (mode | mode << 6));
3880 write_phy_reg(pi, 0x5cf, 3);
3881 write_phy_reg(pi, 0x5a5, 0x3);
3882 write_phy_reg(pi, 0x583, 0x0);
3883 write_phy_reg(pi, 0x584, 0x0);
3884 write_phy_reg(pi, 0x585, 0x0fff);
3885 write_phy_reg(pi, 0x586, 0x0000);
3887 write_phy_reg(pi, 0x580, 0x4501);
3889 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3890 write_phy_reg(pi, 0x6da, (uint32) (sslpnCalibClkEnCtrl | 0x2008));
3891 stpptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr);
3892 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3893 do {
3894 OSL_DELAY(10);
3895 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3896 timer++;
3897 } while ((curptr != stpptr) && (timer < 500));
3899 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, 0x2);
3900 strptr = 0x7E00;
3901 W_REG(pi->sh->osh, &pi->regs->tplatewrptr, strptr);
3902 while (strptr < 0x8000) {
3903 val = R_REG(pi->sh->osh, &pi->regs->tplatewrdata);
3904 imag = ((val >> 16) & 0x3ff);
3905 real = ((val) & 0x3ff);
3906 if (imag > 511) {
3907 imag -= 1024;
3909 if (real > 511) {
3910 real -= 1024;
3912 if (pi_lcn->lcnphy_iqcal_swp_dis)
3913 ptr[(strptr - 0x7E00) / 4] = real;
3914 else
3915 ptr[(strptr - 0x7E00) / 4] = imag;
3916 if (clip_detect_algo) {
3917 if (imag > thresh || imag < -thresh) {
3918 strptr = 0x8000;
3919 ptr[130] = 1;
3922 strptr += 4;
3925 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3926 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2);
3927 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, curval1);
3930 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
3932 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3934 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3935 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3936 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3937 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3939 wlc_lcnphy_a1(pi, 4, 0, 0);
3940 wlc_lcnphy_a1(pi, 3, 0, 0);
3941 wlc_lcnphy_a1(pi, 2, 3, 2);
3942 wlc_lcnphy_a1(pi, 0, 5, 8);
3943 wlc_lcnphy_a1(pi, 2, 2, 1);
3944 wlc_lcnphy_a1(pi, 0, 4, 3);
3946 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3947 locc2 = wlc_lcnphy_get_cc(pi, 2);
3948 locc3 = wlc_lcnphy_get_cc(pi, 3);
3949 locc4 = wlc_lcnphy_get_cc(pi, 4);
3952 static void
3953 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x, int16 coeff_y)
3955 uint16 di0dq0;
3956 uint16 x, y, data_rf;
3957 int k;
3958 switch (cal_type) {
3959 case 0:
3960 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3961 break;
3962 case 2:
3963 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3964 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3965 break;
3966 case 3:
3967 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3968 y = 8 + k;
3969 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3970 x = 8 - k;
3971 data_rf = (x * 16 + y);
3972 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3973 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3974 y = 8 + k;
3975 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3976 x = 8 - k;
3977 data_rf = (x * 16 + y);
3978 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3979 break;
3980 case 4:
3981 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3982 y = 8 + k;
3983 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3984 x = 8 - k;
3985 data_rf = (x * 16 + y);
3986 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3987 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3988 y = 8 + k;
3989 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3990 x = 8 - k;
3991 data_rf = (x * 16 + y);
3992 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3993 break;
3997 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3999 uint16 a, b, didq;
4000 u8 di0, dq0, ei, eq, fi, fq;
4001 lcnphy_unsign16_struct cc;
4002 cc.re = 0;
4003 cc.im = 0;
4004 switch (cal_type) {
4005 case 0:
4006 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
4007 cc.re = a;
4008 cc.im = b;
4009 break;
4010 case 2:
4011 didq = wlc_lcnphy_get_tx_locc(pi);
4012 di0 = (((didq & 0xff00) << 16) >> 24);
4013 dq0 = (((didq & 0x00ff) << 24) >> 24);
4014 cc.re = (uint16) di0;
4015 cc.im = (uint16) dq0;
4016 break;
4017 case 3:
4018 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4019 cc.re = (uint16) ei;
4020 cc.im = (uint16) eq;
4021 break;
4022 case 4:
4023 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4024 cc.re = (uint16) fi;
4025 cc.im = (uint16) fq;
4026 break;
4028 return cc;
4031 static void
4032 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
4034 const lcnphy_spb_tone_t *phy_c1;
4035 lcnphy_spb_tone_t phy_c2;
4036 lcnphy_unsign16_struct phy_c3;
4037 int phy_c4, phy_c5, k, l, j, phy_c6;
4038 uint16 phy_c7, phy_c8, phy_c9;
4039 int16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4040 int16 *ptr, phy_c17;
4041 int32 phy_c18, phy_c19;
4042 uint32 phy_c20, phy_c21;
4043 bool phy_c22, phy_c23, phy_c24, phy_c25;
4044 uint16 phy_c26, phy_c27;
4045 uint16 phy_c28, phy_c29, phy_c30;
4046 uint16 phy_c31;
4047 uint16 *phy_c32;
4048 phy_c21 = 0;
4049 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4050 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
4051 if (NULL == ptr) {
4052 return;
4055 phy_c32 = MALLOC(pi->sh->osh, sizeof(uint16) * 20);
4056 if (NULL == phy_c32) {
4057 return;
4059 phy_c26 = read_phy_reg(pi, 0x6da);
4060 phy_c27 = read_phy_reg(pi, 0x6db);
4061 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
4062 write_phy_reg(pi, 0x93d, 0xC0);
4064 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
4065 write_phy_reg(pi, 0x6da, 0xffff);
4066 or_phy_reg(pi, 0x6db, 0x3);
4068 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
4069 OSL_DELAY(500);
4070 phy_c28 = read_phy_reg(pi, 0x938);
4071 phy_c29 = read_phy_reg(pi, 0x4d7);
4072 phy_c30 = read_phy_reg(pi, 0x4d8);
4073 or_phy_reg(pi, 0x938, 0x1 << 2);
4074 or_phy_reg(pi, 0x4d7, 0x1 << 2);
4075 or_phy_reg(pi, 0x4d7, 0x1 << 3);
4076 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
4077 or_phy_reg(pi, 0x4d8, 1 << 0);
4078 or_phy_reg(pi, 0x4d8, 1 << 1);
4079 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
4080 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
4081 phy_c1 = &lcnphy_spb_tone_3750[0];
4082 phy_c4 = 32;
4084 if (num_levels == 0) {
4085 if (cal_type != 0) {
4086 num_levels = 4;
4087 } else {
4088 num_levels = 9;
4091 if (step_size_lg2 == 0) {
4092 if (cal_type != 0) {
4093 step_size_lg2 = 3;
4094 } else {
4095 step_size_lg2 = 8;
4099 phy_c7 = (1 << step_size_lg2);
4100 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
4101 phy_c15 = (int16) phy_c3.re;
4102 phy_c16 = (int16) phy_c3.im;
4103 if (cal_type == 2) {
4104 if (phy_c3.re > 127)
4105 phy_c15 = phy_c3.re - 256;
4106 if (phy_c3.im > 127)
4107 phy_c16 = phy_c3.im - 256;
4109 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4110 OSL_DELAY(20);
4111 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
4112 phy_c23 = 1;
4113 phy_c22 = 0;
4114 switch (cal_type) {
4115 case 0:
4116 phy_c10 = 511;
4117 break;
4118 case 2:
4119 phy_c10 = 127;
4120 break;
4121 case 3:
4122 phy_c10 = 15;
4123 break;
4124 case 4:
4125 phy_c10 = 15;
4126 break;
4129 phy_c9 = read_phy_reg(pi, 0x93d);
4130 phy_c9 = 2 * phy_c9;
4131 phy_c24 = 0;
4132 phy_c5 = 7;
4133 phy_c25 = 1;
4134 while (1) {
4135 write_radio_reg(pi, RADIO_2064_REG026,
4136 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
4137 OSL_DELAY(50);
4138 phy_c22 = 0;
4139 ptr[130] = 0;
4140 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
4141 if (ptr[130] == 1)
4142 phy_c22 = 1;
4143 if (phy_c22)
4144 phy_c5 -= 1;
4145 if ((phy_c22 != phy_c24) && (!phy_c25))
4146 break;
4147 if (!phy_c22)
4148 phy_c5 += 1;
4149 if (phy_c5 <= 0 || phy_c5 >= 7)
4150 break;
4151 phy_c24 = phy_c22;
4152 phy_c25 = 0;
4155 if (phy_c5 < 0)
4156 phy_c5 = 0;
4157 else if (phy_c5 > 7)
4158 phy_c5 = 7;
4160 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
4161 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
4162 phy_c11 = phy_c15 + k;
4163 phy_c12 = phy_c16 + l;
4165 if (phy_c11 < -phy_c10)
4166 phy_c11 = -phy_c10;
4167 else if (phy_c11 > phy_c10)
4168 phy_c11 = phy_c10;
4169 if (phy_c12 < -phy_c10)
4170 phy_c12 = -phy_c10;
4171 else if (phy_c12 > phy_c10)
4172 phy_c12 = phy_c10;
4173 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
4174 phy_c12);
4175 OSL_DELAY(20);
4176 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
4178 phy_c18 = 0;
4179 phy_c19 = 0;
4180 for (j = 0; j < 128; j++) {
4181 if (cal_type != 0) {
4182 phy_c6 = j % phy_c4;
4183 } else {
4184 phy_c6 = (2 * j) % phy_c4;
4186 phy_c2.re = phy_c1[phy_c6].re;
4187 phy_c2.im = phy_c1[phy_c6].im;
4188 phy_c17 = ptr[j];
4189 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
4190 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
4193 phy_c18 = phy_c18 >> 10;
4194 phy_c19 = phy_c19 >> 10;
4195 phy_c20 =
4196 ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
4198 if (phy_c23 || phy_c20 < phy_c21) {
4199 phy_c21 = phy_c20;
4200 phy_c13 = phy_c11;
4201 phy_c14 = phy_c12;
4203 phy_c23 = 0;
4206 phy_c23 = 1;
4207 phy_c15 = phy_c13;
4208 phy_c16 = phy_c14;
4209 phy_c7 = phy_c7 >> 1;
4210 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4211 OSL_DELAY(20);
4213 goto cleanup;
4214 cleanup:
4215 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
4216 wlc_lcnphy_stop_tx_tone(pi);
4217 write_phy_reg(pi, 0x6da, phy_c26);
4218 write_phy_reg(pi, 0x6db, phy_c27);
4219 write_phy_reg(pi, 0x938, phy_c28);
4220 write_phy_reg(pi, 0x4d7, phy_c29);
4221 write_phy_reg(pi, 0x4d8, phy_c30);
4222 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
4224 MFREE(pi->sh->osh, phy_c32, 20 * sizeof(uint16));
4225 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
4228 static void
4229 wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, uint16 *values_to_save)
4231 int i;
4233 and_phy_reg(pi, 0x44c, 0x0 >> 11);
4235 and_phy_reg(pi, 0x43b, 0xC);
4237 for (i = 0; i < 20; i++) {
4238 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
4239 values_to_save[i]);
4243 static void
4244 WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
4245 const lcnphy_tx_gain_tbl_entry *
4246 gain_table) {
4247 uint32 j;
4248 phytbl_info_t tab;
4249 uint32 val;
4250 uint16 pa_gain;
4251 uint16 gm_gain;
4253 if (CHSPEC_IS5G(pi->radio_chanspec))
4254 pa_gain = 0x70;
4255 else
4256 pa_gain = 0x70;
4258 if (pi->sh->boardflags & BFL_FEM)
4259 pa_gain = 0x10;
4260 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4261 tab.tbl_width = 32;
4262 tab.tbl_len = 1;
4263 tab.tbl_ptr = &val;
4265 for (j = 0; j < 128; j++) {
4266 gm_gain = gain_table[j].gm;
4267 val = (((uint32) pa_gain << 24) |
4268 (gain_table[j].pad << 16) |
4269 (gain_table[j].pga << 8) | gm_gain);
4271 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4272 wlc_lcnphy_write_table(pi, &tab);
4274 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4275 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4276 wlc_lcnphy_write_table(pi, &tab);
4280 static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
4282 phytbl_info_t tab;
4283 uint32 val, bbmult, rfgain;
4284 u8 index;
4285 u8 scale_factor = 1;
4286 int16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4288 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4289 tab.tbl_width = 32;
4290 tab.tbl_len = 1;
4292 for (index = 0; index < 128; index++) {
4293 tab.tbl_ptr = &bbmult;
4294 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4295 wlc_lcnphy_read_table(pi, &tab);
4296 bbmult = bbmult >> 20;
4298 tab.tbl_ptr = &rfgain;
4299 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4300 wlc_lcnphy_read_table(pi, &tab);
4302 qm_log10((int32) (bbmult), 0, &temp1, &qQ1);
4303 qm_log10((int32) (1 << 6), 0, &temp2, &qQ2);
4305 if (qQ1 < qQ2) {
4306 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4307 qQ = qQ1;
4308 } else {
4309 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4310 qQ = qQ2;
4312 temp = qm_sub16(temp1, temp2);
4314 if (qQ >= 4)
4315 shift = qQ - 4;
4316 else
4317 shift = 4 - qQ;
4319 val = (((index << shift) + (5 * temp) +
4320 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4321 shift - 2));
4323 tab.tbl_ptr = &val;
4324 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4325 wlc_lcnphy_write_table(pi, &tab);
4329 static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi)
4331 uint idx;
4332 u8 phybw40;
4333 phytbl_info_t tab;
4334 uint32 val;
4336 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4338 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
4339 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4342 if (pi->sh->boardflags & BFL_FEM_BT) {
4343 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4344 tab.tbl_width = 16;
4345 tab.tbl_ptr = &val;
4346 tab.tbl_len = 1;
4347 val = 100;
4348 tab.tbl_offset = 4;
4349 wlc_lcnphy_write_table(pi, &tab);
4352 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4353 tab.tbl_width = 16;
4354 tab.tbl_ptr = &val;
4355 tab.tbl_len = 1;
4357 val = 114;
4358 tab.tbl_offset = 0;
4359 wlc_lcnphy_write_table(pi, &tab);
4361 val = 130;
4362 tab.tbl_offset = 1;
4363 wlc_lcnphy_write_table(pi, &tab);
4365 val = 6;
4366 tab.tbl_offset = 8;
4367 wlc_lcnphy_write_table(pi, &tab);
4369 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4370 if (pi->sh->boardflags & BFL_FEM)
4371 wlc_lcnphy_load_tx_gain_table(pi,
4372 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4373 else
4374 wlc_lcnphy_load_tx_gain_table(pi,
4375 dot11lcnphy_2GHz_gaintable_rev0);
4378 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4379 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4380 for (idx = 0;
4381 idx < dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4382 idx++)
4383 if (pi->sh->boardflags & BFL_EXTLNA)
4384 wlc_lcnphy_write_table(pi,
4385 &dot11lcnphytbl_rx_gain_info_extlna_2G_rev2
4386 [idx]);
4387 else
4388 wlc_lcnphy_write_table(pi,
4389 &dot11lcnphytbl_rx_gain_info_2G_rev2
4390 [idx]);
4391 } else {
4392 for (idx = 0;
4393 idx < dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4394 idx++)
4395 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4396 wlc_lcnphy_write_table(pi,
4397 &dot11lcnphytbl_rx_gain_info_extlna_5G_rev2
4398 [idx]);
4399 else
4400 wlc_lcnphy_write_table(pi,
4401 &dot11lcnphytbl_rx_gain_info_5G_rev2
4402 [idx]);
4406 if ((pi->sh->boardflags & BFL_FEM)
4407 && !(pi->sh->boardflags & BFL_FEM_BT))
4408 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4409 else if (pi->sh->boardflags & BFL_FEM_BT) {
4410 if (pi->sh->boardrev < 0x1250)
4411 wlc_lcnphy_write_table(pi,
4412 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4413 else
4414 wlc_lcnphy_write_table(pi,
4415 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4416 } else
4417 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4419 wlc_lcnphy_load_rfpower(pi);
4421 wlc_lcnphy_clear_papd_comptable(pi);
4424 static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi)
4426 uint16 afectrl1;
4427 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4429 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4431 write_phy_reg(pi, 0x43b, 0x0);
4432 write_phy_reg(pi, 0x43c, 0x0);
4433 write_phy_reg(pi, 0x44c, 0x0);
4434 write_phy_reg(pi, 0x4e6, 0x0);
4435 write_phy_reg(pi, 0x4f9, 0x0);
4436 write_phy_reg(pi, 0x4b0, 0x0);
4437 write_phy_reg(pi, 0x938, 0x0);
4438 write_phy_reg(pi, 0x4b0, 0x0);
4439 write_phy_reg(pi, 0x44e, 0);
4441 or_phy_reg(pi, 0x567, 0x03);
4443 or_phy_reg(pi, 0x44a, 0x44);
4444 write_phy_reg(pi, 0x44a, 0x80);
4446 if (!(pi->sh->boardflags & BFL_FEM))
4447 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4449 if (0) {
4450 afectrl1 = 0;
4451 afectrl1 = (uint16) ((pi_lcn->lcnphy_rssi_vf) |
4452 (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4453 lcnphy_rssi_gs
4454 << 10));
4455 write_phy_reg(pi, 0x43e, afectrl1);
4458 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4459 if (pi->sh->boardflags & BFL_FEM) {
4460 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4462 write_phy_reg(pi, 0x910, 0x1);
4465 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4466 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4467 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4471 static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi)
4473 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4474 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4476 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4480 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
4482 int16 temp;
4483 phytbl_info_t tab;
4484 uint32 tableBuffer[2];
4485 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4487 if (NORADIO_ENAB(pi->pubpi))
4488 return;
4490 temp = (int16) read_phy_reg(pi, 0x4df);
4491 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4493 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4494 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4496 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4498 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4499 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4501 tab.tbl_ptr = tableBuffer;
4502 tab.tbl_len = 2;
4503 tab.tbl_id = 17;
4504 tab.tbl_offset = 59;
4505 tab.tbl_width = 32;
4506 wlc_lcnphy_read_table(pi, &tab);
4508 if (tableBuffer[0] > 63)
4509 tableBuffer[0] -= 128;
4510 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4512 if (tableBuffer[1] > 63)
4513 tableBuffer[1] -= 128;
4514 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4516 temp = (int16) (read_phy_reg(pi, 0x434)
4517 & (0xff << 0));
4518 if (temp > 127)
4519 temp -= 256;
4520 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4522 pi_lcn->lcnphy_Med_Low_Gain_db = (read_phy_reg(pi, 0x424)
4523 & (0xff << 8))
4524 >> 8;
4525 pi_lcn->lcnphy_Very_Low_Gain_db = (read_phy_reg(pi, 0x425)
4526 & (0xff << 0))
4527 >> 0;
4529 tab.tbl_ptr = tableBuffer;
4530 tab.tbl_len = 2;
4531 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4532 tab.tbl_offset = 28;
4533 tab.tbl_width = 32;
4534 wlc_lcnphy_read_table(pi, &tab);
4536 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4537 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4541 static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi)
4543 if (NORADIO_ENAB(pi->pubpi))
4544 return;
4546 or_phy_reg(pi, 0x805, 0x1);
4548 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4550 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4552 write_phy_reg(pi, 0x414, 0x1e10);
4553 write_phy_reg(pi, 0x415, 0x0640);
4555 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4557 or_phy_reg(pi, 0x44a, 0x44);
4558 write_phy_reg(pi, 0x44a, 0x80);
4559 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4561 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4563 if (!(pi->sh->boardrev < 0x1204))
4564 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4566 write_phy_reg(pi, 0x7d6, 0x0902);
4567 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4569 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4571 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4572 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4574 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4576 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4578 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4580 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4582 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4583 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4584 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4585 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4586 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4588 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4590 wlc_lcnphy_clear_tx_power_offsets(pi);
4591 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4596 static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi)
4599 wlc_lcnphy_tbl_init(pi);
4600 wlc_lcnphy_rev0_baseband_init(pi);
4601 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4602 wlc_lcnphy_rev2_baseband_init(pi);
4603 wlc_lcnphy_bu_tweaks(pi);
4606 static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi)
4608 uint32 i;
4609 lcnphy_radio_regs_t *lcnphyregs = NULL;
4611 lcnphyregs = lcnphy_radio_regs_2064;
4613 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4614 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4615 write_radio_reg(pi,
4616 ((lcnphyregs[i].address & 0x3fff) |
4617 RADIO_DEFAULT_CORE),
4618 (uint16) lcnphyregs[i].init_a);
4619 else if (lcnphyregs[i].do_init_g)
4620 write_radio_reg(pi,
4621 ((lcnphyregs[i].address & 0x3fff) |
4622 RADIO_DEFAULT_CORE),
4623 (uint16) lcnphyregs[i].init_g);
4625 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4626 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4628 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4630 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4632 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4634 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4635 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4636 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4639 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4640 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4642 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4644 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4646 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4648 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4650 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4652 write_phy_reg(pi, 0x4ea, 0x4688);
4654 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4656 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4658 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4660 wlc_lcnphy_set_tx_locc(pi, 0);
4662 wlc_lcnphy_rcal(pi);
4664 wlc_lcnphy_rc_cal(pi);
4667 static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi)
4669 if (NORADIO_ENAB(pi->pubpi))
4670 return;
4672 wlc_radio_2064_init(pi);
4675 static void wlc_lcnphy_rcal(phy_info_t *pi)
4677 u8 rcal_value;
4679 if (NORADIO_ENAB(pi->pubpi))
4680 return;
4682 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4684 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4685 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4687 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4688 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4690 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4692 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4693 OSL_DELAY(5000);
4694 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4696 if (wlc_radio_2064_rcal_done(pi)) {
4697 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4698 rcal_value = rcal_value & 0x1f;
4701 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4703 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4706 static void wlc_lcnphy_rc_cal(phy_info_t *pi)
4708 u8 dflt_rc_cal_val;
4709 uint16 flt_val;
4711 if (NORADIO_ENAB(pi->pubpi))
4712 return;
4714 dflt_rc_cal_val = 7;
4715 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4716 dflt_rc_cal_val = 11;
4717 flt_val =
4718 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4719 (dflt_rc_cal_val);
4720 write_phy_reg(pi, 0x933, flt_val);
4721 write_phy_reg(pi, 0x934, flt_val);
4722 write_phy_reg(pi, 0x935, flt_val);
4723 write_phy_reg(pi, 0x936, flt_val);
4724 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4726 return;
4729 static bool BCMATTACHFN(wlc_phy_txpwr_srom_read_lcnphy) (phy_info_t *pi)
4731 s8 txpwr = 0;
4732 int i;
4733 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4735 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4736 uint16 cckpo = 0;
4737 uint32 offset_ofdm, offset_mcs;
4739 pi_lcn->lcnphy_tr_isolation_mid =
4740 (u8) PHY_GETINTVAR(pi, "triso2g");
4742 pi_lcn->lcnphy_rx_power_offset =
4743 (u8) PHY_GETINTVAR(pi, "rxpo2g");
4745 pi->txpa_2g[0] = (int16) PHY_GETINTVAR(pi, "pa0b0");
4746 pi->txpa_2g[1] = (int16) PHY_GETINTVAR(pi, "pa0b1");
4747 pi->txpa_2g[2] = (int16) PHY_GETINTVAR(pi, "pa0b2");
4749 pi_lcn->lcnphy_rssi_vf = (u8) PHY_GETINTVAR(pi, "rssismf2g");
4750 pi_lcn->lcnphy_rssi_vc = (u8) PHY_GETINTVAR(pi, "rssismc2g");
4751 pi_lcn->lcnphy_rssi_gs = (u8) PHY_GETINTVAR(pi, "rssisav2g");
4754 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4755 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4756 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4758 pi_lcn->lcnphy_rssi_vf_hightemp =
4759 pi_lcn->lcnphy_rssi_vf;
4760 pi_lcn->lcnphy_rssi_vc_hightemp =
4761 pi_lcn->lcnphy_rssi_vc;
4762 pi_lcn->lcnphy_rssi_gs_hightemp =
4763 pi_lcn->lcnphy_rssi_gs;
4766 txpwr = (s8) PHY_GETINTVAR(pi, "maxp2ga0");
4767 pi->tx_srom_max_2g = txpwr;
4769 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4770 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4771 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4774 cckpo = (uint16) PHY_GETINTVAR(pi, "cck2gpo");
4775 if (cckpo) {
4776 uint max_pwr_chan = txpwr;
4778 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4779 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4780 ((cckpo & 0xf) * 2);
4781 cckpo >>= 4;
4784 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4785 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4786 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4787 ((offset_ofdm & 0xf) * 2);
4788 offset_ofdm >>= 4;
4790 } else {
4791 u8 opo = 0;
4793 opo = (u8) PHY_GETINTVAR(pi, "opo");
4795 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4796 pi->tx_srom_max_rate_2g[i] = txpwr;
4799 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4801 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4802 pi->tx_srom_max_rate_2g[i] = txpwr -
4803 ((offset_ofdm & 0xf) * 2);
4804 offset_ofdm >>= 4;
4806 offset_mcs =
4807 ((uint16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4808 (uint16) PHY_GETINTVAR(pi, "mcs2gpo0");
4809 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4810 for (i = TXP_FIRST_SISO_MCS_20;
4811 i <= TXP_LAST_SISO_MCS_20; i++) {
4812 pi->tx_srom_max_rate_2g[i] =
4813 txpwr - ((offset_mcs & 0xf) * 2);
4814 offset_mcs >>= 4;
4818 pi_lcn->lcnphy_rawtempsense =
4819 (uint16) PHY_GETINTVAR(pi, "rawtempsense");
4820 pi_lcn->lcnphy_measPower =
4821 (u8) PHY_GETINTVAR(pi, "measpower");
4822 pi_lcn->lcnphy_tempsense_slope =
4823 (u8) PHY_GETINTVAR(pi, "tempsense_slope");
4824 pi_lcn->lcnphy_hw_iqcal_en =
4825 (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
4826 pi_lcn->lcnphy_iqcal_swp_dis =
4827 (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
4828 pi_lcn->lcnphy_tempcorrx =
4829 (u8) PHY_GETINTVAR(pi, "tempcorrx");
4830 pi_lcn->lcnphy_tempsense_option =
4831 (u8) PHY_GETINTVAR(pi, "tempsense_option");
4832 pi_lcn->lcnphy_freqoffset_corr =
4833 (u8) PHY_GETINTVAR(pi, "freqoffset_corr");
4834 if ((u8) getintvar(pi->vars, "aa2g") > 1)
4835 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
4836 (u8) getintvar(pi->vars,
4837 "aa2g"));
4839 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4840 if (PHY_GETVAR(pi, "cckdigfilttype")) {
4841 int16 temp;
4842 temp = (int16) PHY_GETINTVAR(pi, "cckdigfilttype");
4843 if (temp >= 0) {
4844 pi_lcn->lcnphy_cck_dig_filt_type = temp;
4848 return TRUE;
4851 void wlc_2064_vco_cal(phy_info_t *pi)
4853 u8 calnrst;
4855 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4856 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4857 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4858 OSL_DELAY(1);
4859 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4860 OSL_DELAY(1);
4861 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4862 OSL_DELAY(300);
4863 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4866 static void
4867 wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, u8 channel)
4869 uint i;
4870 const chan_info_2064_lcnphy_t *ci;
4871 u8 rfpll_doubler = 0;
4872 u8 pll_pwrup, pll_pwrup_ovr;
4873 fixed qFxtal, qFref, qFvco, qFcal;
4874 u8 d15, d16, f16, e44, e45;
4875 uint32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
4876 uint16 loop_bw, d30, setCount;
4877 if (NORADIO_ENAB(pi->pubpi))
4878 return;
4879 ci = &chan_info_2064_lcnphy[0];
4880 rfpll_doubler = 1;
4882 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
4884 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
4885 if (!rfpll_doubler) {
4886 loop_bw = PLL_2064_LOOP_BW;
4887 d30 = PLL_2064_D30;
4888 } else {
4889 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
4890 d30 = PLL_2064_D30_DOUBLER;
4893 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4894 for (i = 0; i < ARRAYSIZE(chan_info_2064_lcnphy); i++)
4895 if (chan_info_2064_lcnphy[i].chan == channel)
4896 break;
4898 if (i >= ARRAYSIZE(chan_info_2064_lcnphy)) {
4899 return;
4902 ci = &chan_info_2064_lcnphy[i];
4905 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
4907 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
4909 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
4911 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
4913 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
4914 (ci->logen_rccr_rx) << 2);
4916 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
4918 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
4919 (ci->pa_rxrf_lna2_freq_tune) << 4);
4921 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
4923 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
4924 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
4926 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
4928 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
4929 e44 = 0;
4930 e45 = 0;
4932 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
4933 if (pi->xtalfreq > 26000000)
4934 e44 = 1;
4935 if (pi->xtalfreq > 52000000)
4936 e45 = 1;
4937 if (e44 == 0)
4938 fcal_div = 1;
4939 else if (e45 == 0)
4940 fcal_div = 2;
4941 else
4942 fcal_div = 4;
4943 fvco3 = (ci->freq * 3);
4944 fref3 = 2 * fpfd;
4946 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
4947 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
4948 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
4949 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
4951 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
4953 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
4954 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
4955 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
4957 d16 = (qFcal * 8 / (d15 + 1)) - 1;
4958 write_radio_reg(pi, RADIO_2064_REG051, d16);
4960 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
4961 setCount = f16 * 3 * (ci->freq) / 32 - 1;
4962 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
4963 (u8) (setCount >> 8));
4965 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
4966 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
4968 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
4970 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
4971 while (div_frac >= fref3) {
4972 div_int++;
4973 div_frac -= fref3;
4975 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
4977 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
4978 (u8) (div_int >> 4));
4979 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
4980 (u8) (div_int << 4));
4981 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
4982 (u8) (div_frac >> 16));
4983 write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
4984 write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
4986 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
4988 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
4989 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
4990 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
4993 u8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
4994 uint16 c29, c38, c30, g30, d28;
4995 c29 = loop_bw;
4996 d29 = 200;
4997 c38 = 1250;
4998 h29 = d29 / c29;
4999 h23 = 1;
5000 c28 = 30;
5001 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
5002 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
5003 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
5004 + PLL_2064_LOW_END_KVCO;
5005 h28_ten = (d28 * 10) / c28;
5006 c30 = 2640;
5007 e30 = (d30 - 680) / 490;
5008 g30 = 680 + (e30 * 490);
5009 h30_ten = (g30 * 10) / c30;
5010 cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
5011 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
5013 if (channel >= 1 && channel <= 5)
5014 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
5015 else
5016 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
5017 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
5019 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
5020 OSL_DELAY(1);
5022 wlc_2064_vco_cal(pi);
5024 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
5025 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
5026 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5027 write_radio_reg(pi, RADIO_2064_REG038, 3);
5028 write_radio_reg(pi, RADIO_2064_REG091, 7);
5032 bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
5034 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5035 return 0;
5036 else
5037 return (LCNPHY_TX_PWR_CTRL_HW ==
5038 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5041 void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
5043 uint16 pwr_ctrl;
5044 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5045 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5046 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5048 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5049 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5050 wlc_lcnphy_txpower_recalc_target(pi);
5052 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5053 } else
5054 return;
5057 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5059 MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5062 bool wlc_phy_attach_lcnphy(phy_info_t *pi)
5064 phy_info_lcnphy_t *pi_lcn;
5066 pi->u.pi_lcnphy =
5067 (phy_info_lcnphy_t *) MALLOC(pi->sh->osh,
5068 sizeof(phy_info_lcnphy_t));
5069 if (pi->u.pi_lcnphy == NULL) {
5070 return FALSE;
5072 bzero((char *)pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5074 pi_lcn = pi->u.pi_lcnphy;
5076 if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
5077 pi->hwpwrctrl = TRUE;
5078 pi->hwpwrctrl_capable = TRUE;
5081 pi->xtalfreq = si_alp_clock(pi->sh->sih);
5082 ASSERT(0 == (pi->xtalfreq % 1000));
5084 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5086 pi->pi_fptr.init = wlc_phy_init_lcnphy;
5087 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5088 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5089 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5090 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5091 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5092 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5093 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5094 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5096 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5097 return FALSE;
5099 if ((pi->sh->boardflags & BFL_FEM) && (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5100 if (pi_lcn->lcnphy_tempsense_option == 3) {
5101 pi->hwpwrctrl = TRUE;
5102 pi->hwpwrctrl_capable = TRUE;
5103 pi->temppwrctrl_capable = FALSE;
5104 } else {
5105 pi->hwpwrctrl = FALSE;
5106 pi->hwpwrctrl_capable = FALSE;
5107 pi->temppwrctrl_capable = TRUE;
5111 return TRUE;
5114 static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, uint32 gain)
5116 uint16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5118 trsw = (gain & ((uint32) 1 << 28)) ? 0 : 1;
5119 ext_lna = (uint16) (gain >> 29) & 0x01;
5120 lna1 = (uint16) (gain >> 0) & 0x0f;
5121 lna2 = (uint16) (gain >> 4) & 0x0f;
5122 tia = (uint16) (gain >> 8) & 0xf;
5123 biq0 = (uint16) (gain >> 12) & 0xf;
5124 biq1 = (uint16) (gain >> 16) & 0xf;
5126 gain0_15 = (uint16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5127 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5128 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5129 gain16_19 = biq1;
5131 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5132 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5133 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5134 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5135 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5137 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5138 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5139 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5141 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
5144 static uint32 wlc_lcnphy_get_receive_power(phy_info_t *pi, int32 *gain_index)
5146 uint32 received_power = 0;
5147 int32 max_index = 0;
5148 uint32 gain_code = 0;
5149 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5151 max_index = 36;
5152 if (*gain_index >= 0)
5153 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5155 if (-1 == *gain_index) {
5156 *gain_index = 0;
5157 while ((*gain_index <= (int32) max_index)
5158 && (received_power < 700)) {
5159 wlc_lcnphy_set_rx_gain(pi,
5160 lcnphy_23bitgaincode_table
5161 [*gain_index]);
5162 received_power =
5163 wlc_lcnphy_measure_digital_power(pi,
5164 pi_lcn->
5165 lcnphy_noise_samples);
5166 (*gain_index)++;
5168 (*gain_index)--;
5169 } else {
5170 wlc_lcnphy_set_rx_gain(pi, gain_code);
5171 received_power =
5172 wlc_lcnphy_measure_digital_power(pi,
5173 pi_lcn->
5174 lcnphy_noise_samples);
5177 return received_power;
5180 int32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, int32 gain_index)
5182 int32 gain = 0;
5183 int32 nominal_power_db;
5184 int32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5185 input_power_db;
5186 int32 received_power, temperature;
5187 uint freq;
5188 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5190 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5192 gain = lcnphy_gain_table[gain_index];
5194 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5197 uint32 power = (received_power * 16);
5198 uint32 msb1, msb2, val1, val2, diff1, diff2;
5199 msb1 = find_msbit(power);
5200 msb2 = msb1 + 1;
5201 val1 = 1 << msb1;
5202 val2 = 1 << msb2;
5203 diff1 = (power - val1);
5204 diff2 = (val2 - power);
5205 if (diff1 < diff2)
5206 log_val = msb1;
5207 else
5208 log_val = msb2;
5211 log_val = log_val * 3;
5213 gain_mismatch = (nominal_power_db / 2) - (log_val);
5215 desired_gain = gain + gain_mismatch;
5217 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5219 if (input_power_offset_db > 127)
5220 input_power_offset_db -= 256;
5222 input_power_db = input_power_offset_db - desired_gain;
5224 input_power_db =
5225 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5227 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5228 if ((freq > 2427) && (freq <= 2467))
5229 input_power_db = input_power_db - 1;
5231 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5233 if ((temperature - 15) < -30) {
5234 input_power_db =
5235 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5237 } else if ((temperature - 15) < 4) {
5238 input_power_db =
5239 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5241 } else {
5242 input_power_db =
5243 input_power_db + (((temperature - 10 - 25) * 286) >> 12);
5246 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5248 return input_power_db;
5251 static int
5252 wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, int16 filt_type)
5254 int16 filt_index = -1;
5255 int j;
5257 uint16 addr[] = {
5258 0x910,
5259 0x91e,
5260 0x91f,
5261 0x924,
5262 0x925,
5263 0x926,
5264 0x920,
5265 0x921,
5266 0x927,
5267 0x928,
5268 0x929,
5269 0x922,
5270 0x923,
5271 0x930,
5272 0x931,
5273 0x932
5276 uint16 addr_ofdm[] = {
5277 0x90f,
5278 0x900,
5279 0x901,
5280 0x906,
5281 0x907,
5282 0x908,
5283 0x902,
5284 0x903,
5285 0x909,
5286 0x90a,
5287 0x90b,
5288 0x904,
5289 0x905,
5290 0x90c,
5291 0x90d,
5292 0x90e
5295 if (!is_ofdm) {
5296 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
5297 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
5298 filt_index = (int16) j;
5299 break;
5303 if (filt_index == -1) {
5304 ASSERT(FALSE);
5305 } else {
5306 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5307 write_phy_reg(pi, addr[j],
5308 LCNPHY_txdigfiltcoeffs_cck
5309 [filt_index][j + 1]);
5312 } else {
5313 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
5314 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
5315 filt_index = (int16) j;
5316 break;
5320 if (filt_index == -1) {
5321 ASSERT(FALSE);
5322 } else {
5323 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5324 write_phy_reg(pi, addr_ofdm[j],
5325 LCNPHY_txdigfiltcoeffs_ofdm
5326 [filt_index][j + 1]);
5331 return (filt_index != -1) ? 0 : -1;