]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/brcm80211/phy/wlc_phy_lcn.c
Staging: brcm80211: s/uint16/u16/
[net-next-2.6.git] / drivers / staging / brcm80211 / phy / wlc_phy_lcn.c
CommitLineData
a9533e7e
HP
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
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.
7 *
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.
15 */
16
17#include <wlc_cfg.h>
18#include <qmath.h>
19#include <osl.h>
3327989a
BR
20#include <linux/kernel.h>
21#include <linux/string.h>
22#include <linuxver.h>
a9533e7e
HP
23#include <siutils.h>
24#include <bitfuncs.h>
25#include <hndpmu.h>
26
27#include <wlc_phy_radio.h>
28#include <wlc_phy_int.h>
29#include <wlc_phy_lcn.h>
30#include <wlc_phytbl_lcn.h>
31
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
44
45#define TEMPSENSE 1
46#define VBATSENSE 2
47
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
56
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
62
63#define LCN_TARGET_PWR 60
64
65#define LCN_VBAT_OFFSET_433X 34649679
66#define LCN_VBAT_SLOPE_433X 8258032
67
68#define LCN_VBAT_SCALE_NOM 53
69#define LCN_VBAT_SCALE_DEN 432
70
71#define LCN_TEMPSENSE_OFFSET 80812
72#define LCN_TEMPSENSE_DEN 2647
73
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)
78
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)
83
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)
88
89#define wlc_lcnphy_iqcal_active(pi) \
90 (read_phy_reg((pi), 0x451) & \
91 ((0x1 << 15) | (0x1 << 14)))
92
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)
98
99#define SWCTRL_BT_TX 0x18
100#define SWCTRL_OVR_DISABLE 0x40
101
102#define AFE_CLK_INIT_MODE_TXRX2X 1
103#define AFE_CLK_INIT_MODE_PAPD 0
104
105#define LCNPHY_TBL_ID_IQLOCAL 0x00
106
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
114
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
121
122#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
123
124#define LCNPHY_TX_PWR_CTRL_START_NPT 1
125#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
126
127#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
128
129#define LCNPHY_ACI_DETECT_START 1
130#define LCNPHY_ACI_DETECT_PROGRESS 2
131#define LCNPHY_ACI_DETECT_STOP 3
132
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
138
139#define wlc_lcnphy_tx_gain_override_enabled(pi) \
140 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
141
142#define wlc_lcnphy_total_tx_frames(pi) \
143 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + OFFSETOF(macstat_t, txallfrm))
144
145typedef struct {
7d4df48e
GKH
146 u16 gm_gain;
147 u16 pga_gain;
148 u16 pad_gain;
149 u16 dac_gain;
a9533e7e
HP
150} lcnphy_txgains_t;
151
152typedef 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;
159
160typedef struct {
161 lcnphy_txgains_t gains;
162 bool useindex;
e868ab03 163 u8 index;
a9533e7e
HP
164} lcnphy_txcalgains_t;
165
166typedef struct {
e868ab03 167 u8 chan;
a9533e7e
HP
168 int16 a;
169 int16 b;
170} lcnphy_rx_iqcomp_t;
171
172typedef struct {
173 int16 re;
174 int16 im;
175} lcnphy_spb_tone_t;
176
177typedef struct {
7d4df48e
GKH
178 u16 re;
179 u16 im;
a9533e7e
HP
180} lcnphy_unsign16_struct;
181
182typedef struct {
183 uint32 iq_prod;
184 uint32 i_pwr;
185 uint32 q_pwr;
186} lcnphy_iq_est_t;
187
188typedef struct {
7d4df48e
GKH
189 u16 ptcentreTs20;
190 u16 ptcentreFactor;
a9533e7e
HP
191} lcnphy_sfo_cfg_t;
192
193typedef enum {
194 LCNPHY_PAPD_CAL_CW,
195 LCNPHY_PAPD_CAL_OFDM
196} lcnphy_papd_cal_type_t;
197
7d4df48e 198typedef u16 iqcal_gain_params_lcnphy[9];
a9533e7e
HP
199
200static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
201 {0, 0, 0, 0, 0, 0, 0, 0, 0},
202};
203
204static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
205 tbl_iqcal_gainparams_lcnphy_2G,
206};
207
7d4df48e 208static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
a9533e7e
HP
209 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
210 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
211};
212
213static 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}
228};
229
230static const
7d4df48e 231u16 lcnphy_iqcal_loft_gainladder[] = {
a9533e7e
HP
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)
252};
253
254static const
7d4df48e 255u16 lcnphy_iqcal_ir_gainladder[] = {
a9533e7e
HP
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)
276};
277
278static const
279lcnphy_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},
312};
313
314static const
7d4df48e 315u16 iqlo_loopback_rf_regs[20] = {
a9533e7e
HP
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,
336};
337
338static const
7d4df48e 339u16 tempsense_phy_regs[14] = {
a9533e7e
HP
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,
354};
355
356static const
7d4df48e 357u16 rxiq_cal_rf_reg[11] = {
a9533e7e
HP
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,
369};
370
371static const
372lcnphy_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},
424};
425
426static 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,
464};
465
562c8850 466static const s8 lcnphy_gain_table[] = {
a9533e7e
HP
467 -16,
468 -13,
469 10,
470 7,
471 4,
472 0,
473 3,
474 6,
475 9,
476 12,
477 15,
478 18,
479 21,
480 24,
481 27,
482 30,
483 33,
484 36,
485 39,
486 42,
487 45,
488 48,
489 50,
490 53,
491 56,
492 59,
493 62,
494 65,
495 68,
496 71,
497 74,
498 77,
499 80,
500 83,
501 86,
502 89,
503 92,
504};
505
562c8850 506static const s8 lcnphy_gain_index_offset_for_rssi[] = {
a9533e7e
HP
507 7,
508 7,
509 7,
510 7,
511 7,
512 7,
513 7,
514 8,
515 7,
516 7,
517 6,
518 7,
519 7,
520 4,
521 4,
522 4,
523 4,
524 4,
525 4,
526 4,
527 4,
528 3,
529 3,
530 3,
531 3,
532 3,
533 3,
534 4,
535 2,
536 2,
537 2,
538 2,
539 2,
540 2,
541 -1,
542 -2,
543 -2,
544 -2
545};
546
df8501c9
GKH
547extern const u8 spur_tbl_rev0[];
548extern const uint32 dot11lcnphytbl_rx_gain_info_sz_rev1;
549extern const dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
550extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
551extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
a9533e7e
HP
552
553typedef struct _chan_info_2064_lcnphy {
554 uint chan;
555 uint freq;
e868ab03
GKH
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;
a9533e7e
HP
564} chan_info_2064_lcnphy_t;
565
566static 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},
581};
582
583lcnphy_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}
890};
891
892#define LCNPHY_NUM_DIG_FILT_COEFFS 16
893#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
894
7d4df48e 895u16
a9533e7e
HP
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,},
924};
925
926#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
7d4df48e 927u16
a9533e7e
HP
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}
936};
937
938#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
939 mod_phy_reg(pi, 0x4a4, \
940 (0x1ff << 0), \
7d4df48e 941 (u16)(idx) << 0)
a9533e7e
HP
942
943#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
944 mod_phy_reg(pi, 0x4a5, \
945 (0x7 << 8), \
7d4df48e 946 (u16)(npt) << 8)
a9533e7e
HP
947
948#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
949 (read_phy_reg((pi), 0x4a4) & \
950 ((0x1 << 15) | \
951 (0x1 << 14) | \
952 (0x1 << 13)))
953
954#define wlc_lcnphy_get_tx_pwr_npt(pi) \
955 ((read_phy_reg(pi, 0x4a5) & \
956 (0x7 << 8)) >> \
957 8)
958
959#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
960 (read_phy_reg(pi, 0x473) & 0x1ff)
961
962#define wlc_lcnphy_get_target_tx_pwr(pi) \
963 ((read_phy_reg(pi, 0x4a7) & \
964 (0xff << 0)) >> \
965 0)
966
967#define wlc_lcnphy_set_target_tx_pwr(pi, target) \
968 mod_phy_reg(pi, 0x4a7, \
969 (0xff << 0), \
7d4df48e 970 (u16)(target) << 0)
a9533e7e
HP
971
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))
974
562c8850 975#define LCNPHY_IQLOCC_READ(val) ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
a9533e7e 976#define FIXED_TXPWR 78
fd64bcc4 977#define LCNPHY_TEMPSENSE(val) ((int16)((val > 255) ? (val - 512) : val))
a9533e7e
HP
978
979static uint32 wlc_lcnphy_qdiv_roundup(uint32 divident, uint32 divisor,
e868ab03 980 u8 precision);
7cc4a4c0 981static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
7d4df48e
GKH
982 u16 ext_lna, u16 trsw,
983 u16 biq2, u16 biq1,
984 u16 tia, u16 lna2,
985 u16 lna1);
7cc4a4c0 986static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
7d4df48e 987static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain);
7cc4a4c0 988static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
e868ab03
GKH
989static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0);
990static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
7cc4a4c0
JC
991static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
992static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
993static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
994static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
995static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
996 lcnphy_txgains_t *target_gains);
7d4df48e 997static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, u16 num_samps,
e868ab03 998 u8 wait_time, lcnphy_iq_est_t *iq_est);
7d4df48e
GKH
999static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps);
1000static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
e868ab03 1001static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode);
7cc4a4c0
JC
1002extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1003extern void wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng,
e868ab03 1004 u8 rate, struct ether_addr *sa,
a9533e7e 1005 uint32 wait_delay);
7cc4a4c0 1006static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
e868ab03 1007 u8 channel);
a9533e7e 1008
7cc4a4c0
JC
1009static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1010 const lcnphy_tx_gain_tbl_entry *g);
a9533e7e 1011
7cc4a4c0 1012static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
7d4df48e 1013 u16 thresh, int16 *ptr, int mode);
a9533e7e 1014static int wlc_lcnphy_calc_floor(int16 coeff, int type);
7cc4a4c0 1015static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
7d4df48e 1016 u16 *values_to_save);
7cc4a4c0 1017static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
7d4df48e 1018 u16 *values_to_save);
7cc4a4c0 1019static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x,
a9533e7e 1020 int16 coeff_y);
7cc4a4c0
JC
1021static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1022static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
a9533e7e 1023 int num_levels, int step_size_lg2);
7cc4a4c0 1024static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
a9533e7e 1025
7cc4a4c0 1026static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
a9533e7e 1027 chanspec_t chanspec);
7cc4a4c0
JC
1028static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1029static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1030static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1031static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1032static void wlc_lcnphy_radio_init(phy_info_t *pi);
1033static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1034static void wlc_lcnphy_rcal(phy_info_t *pi);
1035static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1036static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
a9533e7e 1037 int16 filt_type);
7d4df48e 1038static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b);
a9533e7e 1039
7cc4a4c0 1040void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
a9533e7e
HP
1041{
1042 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1043}
1044
7cc4a4c0 1045void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
a9533e7e
HP
1046{
1047 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1048}
1049
1050static void
7cc4a4c0 1051wlc_lcnphy_common_read_table(phy_info_t *pi, uint32 tbl_id,
df8501c9 1052 const void *tbl_ptr, uint32 tbl_len,
a9533e7e
HP
1053 uint32 tbl_width, uint32 tbl_offset)
1054{
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);
1062}
1063
1064static void
7cc4a4c0 1065wlc_lcnphy_common_write_table(phy_info_t *pi, uint32 tbl_id,
df8501c9 1066 const void *tbl_ptr, uint32 tbl_len,
a9533e7e
HP
1067 uint32 tbl_width, uint32 tbl_offset)
1068{
1069
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);
1077}
1078
1079static uint32
e868ab03 1080wlc_lcnphy_qdiv_roundup(uint32 dividend, uint32 divisor, u8 precision)
a9533e7e
HP
1081{
1082 uint32 quotient, remainder, roundup, rbit;
1083
1084 ASSERT(divisor);
1085
1086 quotient = dividend / divisor;
1087 remainder = dividend % divisor;
1088 rbit = divisor & 1;
1089 roundup = (divisor >> 1) + rbit;
1090
1091 while (precision--) {
1092 quotient <<= 1;
1093 if (remainder >= roundup) {
1094 quotient++;
1095 remainder = ((remainder - roundup) << 1) + rbit;
1096 } else {
1097 remainder <<= 1;
1098 }
1099 }
1100
1101 if (remainder >= roundup)
1102 quotient++;
1103
1104 return quotient;
1105}
1106
1107static int wlc_lcnphy_calc_floor(int16 coeff_x, int type)
1108{
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;
1116 }
1117 }
1118 if (type == 1) {
1119 if ((coeff_x + 1) < 0)
1120 k = (coeff_x) / 2;
1121 else
1122 k = (coeff_x + 1) / 2;
1123 }
1124 return k;
1125}
1126
562c8850 1127s8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
a9533e7e 1128{
562c8850 1129 s8 index;
a9533e7e
HP
1130 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1131
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 =
562c8850 1136 (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
a9533e7e
HP
1137 / 2);
1138 else
1139 index = pi_lcn->lcnphy_current_index;
1140 return index;
1141}
1142
7d4df48e 1143static uint32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, u16 nsamples)
a9533e7e
HP
1144{
1145 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
1146
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;
1150}
1151
7cc4a4c0 1152void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
a9533e7e 1153{
7d4df48e 1154 u16 afectrlovr, afectrlovrval;
a9533e7e
HP
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);
1159
1160 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1161
1162 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1163
1164 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1165
1166 write_phy_reg(pi, 0x44b, 0xffff);
1167 wlc_lcnphy_tx_pu(pi, 1);
1168
1169 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1170
1171 or_phy_reg(pi, 0x6da, 0x0080);
1172
1173 or_phy_reg(pi, 0x00a, 0x228);
1174 } else {
1175 and_phy_reg(pi, 0x00a, ~(0x228));
1176
1177 and_phy_reg(pi, 0x6da, 0xFF7F);
1178 write_phy_reg(pi, 0x43b, afectrlovr);
1179 write_phy_reg(pi, 0x43c, afectrlovrval);
1180 }
1181}
1182
7cc4a4c0 1183static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
a9533e7e 1184{
7d4df48e 1185 u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
a9533e7e
HP
1186
1187 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1188 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1189
1190 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1191 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1192
1193 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1194 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1195
1196 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1197 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1198}
1199
7cc4a4c0 1200static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
a9533e7e
HP
1201{
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));
1206
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));
1215 }
1216 wlapi_switch_macfreq(pi->sh->physhim, enable);
1217}
1218
7cc4a4c0 1219void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
a9533e7e 1220{
e868ab03 1221 u8 channel = CHSPEC_CHANNEL(chanspec);
a9533e7e
HP
1222
1223 wlc_phy_chanspec_radio_set((wlc_phy_t *) pi, chanspec);
1224
1225 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1226
1227 or_phy_reg(pi, 0x44a, 0x44);
1228 write_phy_reg(pi, 0x44a, 0x80);
1229
1230 if (!NORADIO_ENAB(pi->pubpi)) {
1231 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1232 OSL_DELAY(1000);
1233 }
1234
1235 wlc_lcnphy_toggle_afe_pwdn(pi);
1236
1237 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1238 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1239
1240 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1241 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1242
1243 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 3);
1244 } else {
1245 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1246
1247 wlc_lcnphy_load_tx_iir_filter(pi, FALSE, 2);
1248 }
1249
1250 wlc_lcnphy_load_tx_iir_filter(pi, TRUE, 0);
1251
1252 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1253
1254}
1255
7d4df48e 1256static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, u16 dac_gain)
a9533e7e 1257{
7d4df48e 1258 u16 dac_ctrl;
a9533e7e
HP
1259
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);
1264
1265}
1266
7cc4a4c0 1267static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
a9533e7e 1268{
7d4df48e 1269 u16 bit = bEnable ? 1 : 0;
a9533e7e
HP
1270
1271 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1272
1273 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1274
1275 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1276}
1277
7d4df48e 1278static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
a9533e7e 1279{
7d4df48e 1280 u16 pa_gain;
a9533e7e
HP
1281
1282 pa_gain = (read_phy_reg(pi, 0x4fb) &
1283 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1284 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1285
1286 return pa_gain;
1287}
1288
1289static void
7cc4a4c0 1290wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
a9533e7e 1291{
7d4df48e 1292 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
a9533e7e
HP
1293
1294 mod_phy_reg(pi, 0x4b5,
1295 (0xffff << 0),
1296 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1297 0);
1298 mod_phy_reg(pi, 0x4fb,
1299 (0x7fff << 0),
1300 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1301
1302 mod_phy_reg(pi, 0x4fc,
1303 (0xffff << 0),
1304 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1305 0);
1306 mod_phy_reg(pi, 0x4fd,
1307 (0x7fff << 0),
1308 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1309
1310 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1311
1312 wlc_lcnphy_enable_tx_gain_override(pi);
1313}
1314
e868ab03 1315static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0)
a9533e7e 1316{
7d4df48e 1317 u16 m0m1 = (u16) m0 << 8;
a9533e7e
HP
1318 phytbl_info_t tab;
1319
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);
1326}
1327
7cc4a4c0 1328static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
a9533e7e
HP
1329{
1330 uint32 data_buf[64];
1331 phytbl_info_t tab;
1332
1333 bzero(data_buf, sizeof(data_buf));
1334
1335 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1336 tab.tbl_width = 32;
1337 tab.tbl_ptr = data_buf;
1338
1339 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1340
1341 tab.tbl_len = 30;
1342 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1343 wlc_lcnphy_write_table(pi, &tab);
1344 }
1345
1346 tab.tbl_len = 64;
1347 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1348 wlc_lcnphy_write_table(pi, &tab);
1349}
1350
1351typedef enum {
1352 LCNPHY_TSSI_PRE_PA,
1353 LCNPHY_TSSI_POST_PA,
1354 LCNPHY_TSSI_EXT
1355} lcnphy_tssi_mode_t;
1356
7cc4a4c0 1357static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
a9533e7e
HP
1358{
1359 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1360
1361 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1362
1363 if (LCNPHY_TSSI_POST_PA == pos) {
1364 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1365
1366 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1367
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);
1373 }
1374 } else {
1375 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1376
1377 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1378
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);
1384 }
1385 }
1386 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1387
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);
1393 }
1394}
1395
7d4df48e 1396static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
a9533e7e 1397{
7d4df48e 1398 u16 N1, N2, N3, N4, N5, N6, N;
a9533e7e
HP
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;
1415}
1416
7cc4a4c0 1417static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
a9533e7e 1418{
7d4df48e 1419 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
a9533e7e
HP
1420 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1421
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;
1426
1427 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
1428
1429 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
1430
1431 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
1432
1433 mod_phy_reg(pi, 0x4db,
1434 (0x3ff << 0) |
1435 (0x7 << 12),
1436 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1437
1438 mod_phy_reg(pi, 0x4dc,
1439 (0x3ff << 0) |
1440 (0x7 << 12),
1441 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1442
1443 mod_phy_reg(pi, 0x40a,
1444 (0x3ff << 0) |
1445 (0x7 << 12),
1446 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1447
1448 mod_phy_reg(pi, 0x40b,
1449 (0x3ff << 0) |
1450 (0x7 << 12),
1451 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1452
1453 mod_phy_reg(pi, 0x40c,
1454 (0x3ff << 0) |
1455 (0x7 << 12),
1456 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1457
1458 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
1459}
1460
7cc4a4c0 1461static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
a9533e7e
HP
1462{
1463 phytbl_info_t tab;
1464 uint32 rfseq, ind;
1465
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++;
1474 }
1475 tab.tbl_offset = 704;
1476 for (ind = 0; ind < 128; ind++) {
1477 wlc_lcnphy_write_table(pi, &tab);
1478 tab.tbl_offset++;
1479 }
1480 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
1481
1482 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
1483
1484 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
1485
1486 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
1487 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
1488
1489 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
1490
1491 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
1492
1493 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
1494
1495 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
1496
1497 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
1498
1499 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
1500
1501 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
1502
1503 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
1504
1505 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
1506
1507 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
1508
1509 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
1510
1511 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
1512
1513 wlc_lcnphy_clear_tx_power_offsets(pi);
1514
1515 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
1516
1517 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
1518
1519 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
1520
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);
1527 }
1528
1529 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
1530
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);
1538 }
1539
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);
1544
1545 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
1546
1547 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
1548
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);
1552 }
1553
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);
1561
1562 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
1563
1564 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
1565
1566 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1567
1568 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
1569
1570 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
1571
1572 wlc_lcnphy_pwrctrl_rssiparams(pi);
1573}
1574
7cc4a4c0 1575void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
a9533e7e 1576{
7d4df48e 1577 u16 tx_cnt, tx_total, npt;
a9533e7e
HP
1578 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1579
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);
1583
1584 if (tx_cnt > (1 << npt)) {
1585
1586 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
1587
1588 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
1589 pi_lcn->lcnphy_tssi_npt = npt;
1590
1591 }
1592}
1593
1594int32 wlc_lcnphy_tssi2dbm(int32 tssi, int32 a1, int32 b0, int32 b1)
1595{
1596 int32 a, b, p;
1597
1598 a = 32768 + (a1 * tssi);
1599 b = (1024 * b0) + (64 * b1 * tssi);
1600 p = ((2 * b) + a) / (2 * a);
1601
1602 return p;
1603}
1604
7cc4a4c0 1605static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
a9533e7e
HP
1606{
1607 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1608 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1609 return;
1610
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;
1613}
1614
7cc4a4c0 1615void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
a9533e7e
HP
1616{
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;
1623
1624 for (i = 0, j = 0; i < ARRAYSIZE(rate_table); i++, j++) {
1625
1626 if (i == WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM)
1627 j = TXP_FIRST_MCS_20_SISO;
1628
1629 rate_table[i] = (uint32) ((int32) (-pi->tx_power_offset[j]));
1630 }
1631
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);
1638
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);
1641
1642 wlc_lcnphy_txpower_reset_npt(pi);
1643 }
1644}
1645
562c8850 1646static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, s8 index)
a9533e7e
HP
1647{
1648 uint32 cck_offset[4] = { 22, 22, 22, 22 };
1649 uint32 ofdm_offset, reg_offset_cck;
1650 int i;
7d4df48e 1651 u16 index2;
a9533e7e
HP
1652 phytbl_info_t tab;
1653
1654 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1655 return;
1656
1657 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1658
1659 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
1660
1661 or_phy_reg(pi, 0x6da, 0x0040);
1662
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);
1678 }
1679
1680 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
1681
1682 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1683
1684 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
1685
1686 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
1687
1688 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
1689
1690 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
1691
7d4df48e 1692 index2 = (u16) (index * 2);
a9533e7e
HP
1693 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1694
1695 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1696
1697}
1698
562c8850 1699static s8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
a9533e7e 1700{
562c8850 1701 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
a9533e7e
HP
1702 int16 manp, meas_temp, temp_diff;
1703 bool neg = 0;
7d4df48e 1704 u16 temp;
a9533e7e
HP
1705 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1706
1707 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1708 return pi_lcn->lcnphy_current_index;
1709
1710 index = FIXED_TXPWR;
1711
1712 if (NORADIO_ENAB(pi->pubpi))
1713 return index;
1714
1715 if (pi_lcn->lcnphy_tempsense_slope == 0) {
1716 return index;
1717 }
7d4df48e 1718 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
a9533e7e
HP
1719 meas_temp = LCNPHY_TEMPSENSE(temp);
1720
1721 if (pi->tx_power_min != 0) {
1722 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
1723 } else {
1724 delta_brd = 0;
1725 }
1726
1727 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
1728 temp_diff = manp - meas_temp;
1729 if (temp_diff < 0) {
1730
1731 neg = 1;
1732
1733 temp_diff = -temp_diff;
1734 }
1735
562c8850 1736 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((uint32) (temp_diff * 192),
a9533e7e
HP
1737 (uint32) (pi_lcn->
1738 lcnphy_tempsense_slope
1739 * 10), 0);
1740 if (neg)
1741 delta_temp = -delta_temp;
1742
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)
562c8850 1747 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
a9533e7e 1748 else
562c8850 1749 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
a9533e7e
HP
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;
1755
1756 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1757 index = 127;
1758 if (new_index < 0 || new_index > 126) {
1759 return index;
1760 }
1761 return new_index;
1762}
1763
7d4df48e 1764static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, u16 mode)
a9533e7e
HP
1765{
1766
7d4df48e 1767 u16 current_mode = mode;
a9533e7e
HP
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;
1775}
1776
7d4df48e 1777void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, u16 mode)
a9533e7e 1778{
7d4df48e 1779 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
562c8850 1780 s8 index;
a9533e7e
HP
1781 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1782
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));
1787
1788 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
1789 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
1790
1791 mod_phy_reg(pi, 0x6da, (0x1 << 6),
1792 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
1793
1794 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
1795 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
1796
1797 if (old_mode != mode) {
1798 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
1799
1800 wlc_lcnphy_tx_pwr_update_npt(pi);
1801
1802 wlc_lcnphy_clear_tx_power_offsets(pi);
1803 }
1804 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
1805
1806 wlc_lcnphy_txpower_recalc_target(pi);
1807
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);
1813
1814 pi_lcn->lcnphy_tssi_tx_cnt =
1815 wlc_lcnphy_total_tx_frames(pi);
1816
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);
1821
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);
562c8850 1827 pi_lcn->lcnphy_current_index = (s8)
a9533e7e
HP
1828 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1829 }
1830 }
1831}
1832
7cc4a4c0 1833static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
a9533e7e
HP
1834{
1835 uint delay_count = 0;
1836
1837 while (wlc_lcnphy_iqcal_active(pi)) {
1838 OSL_DELAY(100);
1839 delay_count++;
1840
1841 if (delay_count > (10 * 500))
1842 break;
1843 }
1844
1845 return (0 == wlc_lcnphy_iqcal_active(pi));
1846}
1847
1848static void
7cc4a4c0
JC
1849wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1850 lcnphy_txgains_t *target_gains,
a9533e7e
HP
1851 lcnphy_cal_mode_t cal_mode, bool keep_tone)
1852{
1853
1854 lcnphy_txgains_t cal_gains, temp_gains;
7d4df48e 1855 u16 hash;
e868ab03 1856 u8 band_idx;
a9533e7e 1857 int j;
7d4df48e
GKH
1858 u16 ncorr_override[5];
1859 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
a9533e7e
HP
1860 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1861 };
1862
7d4df48e 1863 u16 commands_fullcal[] = {
e5c4536f 1864 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
a9533e7e 1865
7d4df48e 1866 u16 commands_recal[] = {
e5c4536f 1867 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
a9533e7e 1868
7d4df48e 1869 u16 command_nums_fullcal[] = {
e5c4536f 1870 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
a9533e7e 1871
7d4df48e 1872 u16 command_nums_recal[] = {
e5c4536f 1873 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
7d4df48e 1874 u16 *command_nums = command_nums_fullcal;
a9533e7e 1875
7d4df48e
GKH
1876 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1877 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1878 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
a9533e7e
HP
1879 bool tx_gain_override_old;
1880 lcnphy_txgains_t old_gains;
1881 uint i, n_cal_cmds = 0, n_cal_start = 0;
7d4df48e 1882 u16 *values_to_save;
a9533e7e
HP
1883 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1884
1885 if (NORADIO_ENAB(pi->pubpi))
1886 return;
1887
7d4df48e 1888 values_to_save = MALLOC(pi->sh->osh, sizeof(u16) * 20);
ca8c1e59 1889 if (NULL == values_to_save) {
a9533e7e
HP
1890 return;
1891 }
1892
1893 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1894 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1895
1896 or_phy_reg(pi, 0x6da, 0x40);
1897 or_phy_reg(pi, 0x6db, 0x3);
1898
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;
1905
1906 case LCNPHY_CAL_RECAL:
1907 ASSERT(pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid);
1908
1909 start_coeffs = syst_coeffs;
1910
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);
1917 }
1918
1919 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1920 start_coeffs, 11, 16, 64);
1921
1922 write_phy_reg(pi, 0x6da, 0xffff);
1923 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
1924
1925 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1926
1927 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1928
1929 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1930
1931 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
1932
1933 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
1934
1935 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
1936
1937 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
1938
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);
1942
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;
1949 }
1950
1951 hash = (target_gains->gm_gain << 8) |
1952 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
1953
1954 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
1955
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;
1969 }
1970 }
1971
1972 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
1973
1974 write_phy_reg(pi, 0x453, 0xaa9);
1975 write_phy_reg(pi, 0x93d, 0xc0);
1976
1977 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
df8501c9 1978 (const void *)
a9533e7e
HP
1979 lcnphy_iqcal_loft_gainladder,
1980 ARRAYSIZE(lcnphy_iqcal_loft_gainladder),
1981 16, 0);
1982
1983 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
df8501c9 1984 (const void *)lcnphy_iqcal_ir_gainladder,
a9533e7e
HP
1985 ARRAYSIZE(lcnphy_iqcal_ir_gainladder), 16,
1986 32);
1987
1988 if (pi->phy_tx_tone_freq) {
1989
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);
1995 }
1996
1997 write_phy_reg(pi, 0x6da, 0xffff);
1998
1999 for (i = n_cal_start; i < n_cal_cmds; i++) {
7d4df48e
GKH
2000 u16 zero_diq = 0;
2001 u16 best_coeffs[11];
2002 u16 command_num;
a9533e7e
HP
2003
2004 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2005
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);
2011
2012 write_phy_reg(pi, 0x452, command_num);
2013
2014 if ((cal_type == 3) || (cal_type == 4)) {
2015
2016 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2017 &diq_start, 1, 16, 69);
2018
2019 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2020 &zero_diq, 1, 16, 69);
2021 }
2022
2023 write_phy_reg(pi, 0x451, cal_cmds[i]);
2024
2025 if (!wlc_lcnphy_iqcal_wait(pi)) {
2026
2027 goto cleanup;
2028 }
2029
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);
2036
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);
2040 }
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);
2048 }
2049
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;
2056
2057 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2058 &pi_lcn->lcnphy_cal_results.
2059 txiqlocal_bestcoeffs[0], 4, 16, 80);
2060
2061 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2062 &pi_lcn->lcnphy_cal_results.
2063 txiqlocal_bestcoeffs[5], 2, 16, 85);
2064
2065 cleanup:
2066 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
7d4df48e 2067 MFREE(pi->sh->osh, values_to_save, 20 * sizeof(u16));
a9533e7e
HP
2068
2069 if (!keep_tone)
2070 wlc_lcnphy_stop_tx_tone(pi);
2071
2072 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2073
2074 write_phy_reg(pi, 0x453, 0);
2075
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);
2079
2080 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2081 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2082
2083}
2084
7cc4a4c0 2085static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
a9533e7e
HP
2086{
2087 bool suspend, tx_gain_override_old;
2088 lcnphy_txgains_t old_gains;
2089 phy_info_t *pi = (phy_info_t *) ppi;
7d4df48e 2090 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
a9533e7e 2091 idleTssi0_regvalue_2C;
7d4df48e
GKH
2092 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2093 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2094 u16 SAVE_jtag_bb_afe_switch =
a9533e7e 2095 read_radio_reg(pi, RADIO_2064_REG007) & 1;
7d4df48e
GKH
2096 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2097 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
a9533e7e
HP
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);
2106
2107 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2108 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2109
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);
2120
2121 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2122 >> 0);
2123
2124 if (idleTssi0_2C >= 256)
2125 idleTssi0_OB = idleTssi0_2C - 256;
2126 else
2127 idleTssi0_OB = idleTssi0_2C + 256;
2128
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);
2135
2136 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2137
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);
2141
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);
2149}
2150
e868ab03 2151static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, u8 mode)
a9533e7e
HP
2152{
2153 bool suspend;
7d4df48e 2154 u16 save_txpwrCtrlEn;
e868ab03 2155 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
7d4df48e 2156 u16 auxpga_vmid;
a9533e7e
HP
2157 phytbl_info_t tab;
2158 uint32 val;
e868ab03 2159 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
a9533e7e 2160 save_reg112;
7d4df48e 2161 u16 values_to_save[14];
562c8850 2162 s8 index;
a9533e7e
HP
2163 int i;
2164 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2165 OSL_DELAY(999);
2166
e868ab03
GKH
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);
a9533e7e
HP
2173
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);
2181
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);
2189
2190 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2191
2192 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2193
2194 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2195
2196 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2197
2198 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2199
2200 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2201
2202 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2203
2204 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2205
2206 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2207
2208 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2209
2210 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2211
2212 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2213
2214 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2215
2216 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2217
2218 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2219
2220 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2221
2222 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2223
2224 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2225
2226 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2227
2228 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2229
2230 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2231
2232 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2233
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);
2243
2244 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2245
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);
2252
2253 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2254
2255 auxpga_vmidcourse = 7;
2256 auxpga_vmidfine = 0xa;
2257 auxpga_gain = 2;
2258 }
2259 auxpga_vmid =
7d4df48e 2260 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
a9533e7e
HP
2261 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2262
2263 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2264
2265 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2266
2267 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2268
2269 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2270
2271 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2272
2273 wlc_phy_do_dummy_tx(pi, TRUE, OFF);
2274 if (!tempsense_done(pi))
2275 OSL_DELAY(10);
2276
7d4df48e
GKH
2277 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2278 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2279 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2280 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2281 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2282 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
a9533e7e
HP
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);
2286
2287 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
2288 if (!suspend)
2289 wlapi_enable_mac(pi->sh->physhim);
2290 OSL_DELAY(999);
2291}
2292
a2627bc0
JC
2293void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi)
2294{
a9533e7e 2295 lcnphy_txgains_t tx_gains;
e868ab03 2296 u8 bbmult;
a9533e7e
HP
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;
2302
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);
2307
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;
2313 }
2314
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;
2321
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;
2328
2329 bbmult = 150;
2330 }
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 {
2335
2336 wlc_lcnphy_idle_tssi_est(ppi);
2337
2338 wlc_lcnphy_clear_tx_power_offsets(pi);
2339
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);
2345
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);
2353
2354 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
2355 wlc_lcnphy_write_table(pi, &tab);
2356 tab.tbl_offset++;
2357 }
2358
2359 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
2360
2361 write_phy_reg(pi, 0x4a8, 10);
2362
2363 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
2364
2365 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
2366 }
2367 if (!suspend)
2368 wlapi_enable_mac(pi->sh->physhim);
2369}
2370
e868ab03 2371static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
a9533e7e 2372{
7d4df48e 2373 u16 m0m1;
a9533e7e
HP
2374 phytbl_info_t tab;
2375
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);
2382
e868ab03 2383 return (u8) ((m0m1 & 0xff00) >> 8);
a9533e7e
HP
2384}
2385
7d4df48e 2386static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain)
a9533e7e
HP
2387{
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);
2394}
2395
2396void
7cc4a4c0 2397wlc_lcnphy_get_radio_loft(phy_info_t *pi,
e868ab03 2398 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
a9533e7e
HP
2399{
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));
2404}
2405
7cc4a4c0 2406static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
a9533e7e 2407{
7d4df48e 2408 u16 dac_gain;
a9533e7e
HP
2409
2410 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2411 gains->dac_gain = (dac_gain & 0x380) >> 7;
2412
2413 {
7d4df48e 2414 u16 rfgain0, rfgain1;
a9533e7e
HP
2415
2416 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
2417 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
2418
2419 gains->gm_gain = rfgain0 & 0xff;
2420 gains->pga_gain = (rfgain0 >> 8) & 0xff;
2421 gains->pad_gain = rfgain1 & 0xff;
2422 }
2423}
2424
7d4df48e 2425void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, u16 a, u16 b)
a9533e7e
HP
2426{
2427 phytbl_info_t tab;
7d4df48e 2428 u16 iqcc[2];
a9533e7e
HP
2429
2430 iqcc[0] = a;
2431 iqcc[1] = b;
2432
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);
2439}
2440
7d4df48e 2441void wlc_lcnphy_set_tx_locc(phy_info_t *pi, u16 didq)
a9533e7e
HP
2442{
2443 phytbl_info_t tab;
2444
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);
2451}
2452
7cc4a4c0 2453void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
a9533e7e
HP
2454{
2455 phytbl_info_t tab;
7d4df48e 2456 u16 a, b;
e868ab03 2457 u8 bb_mult;
a9533e7e
HP
2458 uint32 bbmultiqcomp, txgain, locoeffs, rfpower;
2459 lcnphy_txgains_t gains;
2460 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2461
2462 ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2463
562c8850 2464 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
e868ab03 2465 pi_lcn->lcnphy_current_index = (u8) index;
a9533e7e
HP
2466
2467 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2468 tab.tbl_width = 32;
2469 tab.tbl_len = 1;
2470
2471 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2472
2473 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
2474 tab.tbl_ptr = &bbmultiqcomp;
2475 wlc_lcnphy_read_table(pi, &tab);
2476
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);
2481
7d4df48e
GKH
2482 gains.gm_gain = (u16) (txgain & 0xff);
2483 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
2484 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
2485 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
a9533e7e 2486 wlc_lcnphy_set_tx_gain(pi, &gains);
7d4df48e 2487 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
a9533e7e 2488
e868ab03 2489 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
a9533e7e
HP
2490 wlc_lcnphy_set_bbmult(pi, bb_mult);
2491
2492 wlc_lcnphy_enable_tx_gain_override(pi);
2493
2494 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2495
7d4df48e
GKH
2496 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
2497 b = (u16) (bbmultiqcomp & 0x3ff);
a9533e7e
HP
2498 wlc_lcnphy_set_tx_iqcc(pi, a, b);
2499
2500 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
2501 tab.tbl_ptr = &locoeffs;
2502 wlc_lcnphy_read_table(pi, &tab);
2503
7d4df48e 2504 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
a9533e7e
HP
2505
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);
2510
2511 }
2512}
2513
7cc4a4c0 2514static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
a9533e7e
HP
2515{
2516
2517 mod_phy_reg(pi, 0x44d,
2518 (0x1 << 1) |
2519 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
2520
2521 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
2522}
2523
7cc4a4c0 2524static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
a9533e7e
HP
2525{
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;
2534
2535 bzero(temp_offset, sizeof(temp_offset));
2536 for (j = 1; j < 128; j += 2)
2537 temp_offset[j] = 0x80000;
2538
2539 wlc_lcnphy_write_table(pi, &tab);
2540 return;
2541}
2542
2543static void
7cc4a4c0 2544wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
7d4df48e
GKH
2545 u16 trsw,
2546 u16 ext_lna,
2547 u16 biq2,
2548 u16 biq1,
2549 u16 tia, u16 lna2, u16 lna1)
a9533e7e 2550{
7d4df48e 2551 u16 gain0_15, gain16_19;
a9533e7e
HP
2552
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);
2558
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);
2562
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);
2568
2569 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
2570
2571 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2572 }
2573
2574 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
2575
2576}
2577
7cc4a4c0 2578static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
a9533e7e 2579{
7d4df48e 2580 u16 ebit = enable ? 1 : 0;
a9533e7e
HP
2581
2582 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
2583
2584 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
2585
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);
2595 }
2596
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);
2600 }
2601}
2602
7cc4a4c0 2603void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
a9533e7e
HP
2604{
2605 if (!bEnable) {
2606
7d4df48e 2607 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
a9533e7e
HP
2608
2609 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2610
2611 and_phy_reg(pi, 0x44c,
7d4df48e 2612 ~(u16) ((0x1 << 3) |
a9533e7e
HP
2613 (0x1 << 5) |
2614 (0x1 << 12) |
2615 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2616
2617 and_phy_reg(pi, 0x44d,
7d4df48e 2618 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
a9533e7e
HP
2619 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
2620
2621 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
2622
2623 and_phy_reg(pi, 0x4f9,
7d4df48e 2624 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
a9533e7e
HP
2625
2626 and_phy_reg(pi, 0x4fa,
7d4df48e 2627 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
a9533e7e
HP
2628 } else {
2629
2630 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2631 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2632
2633 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
2634 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
2635
2636 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2637 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2638
2639 wlc_lcnphy_set_trsw_override(pi, TRUE, FALSE);
2640
2641 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
2642 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
2643
2644 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2645
2646 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2647 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
2648
2649 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2650 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
2651
2652 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2653 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
2654
2655 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2656 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
2657
2658 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2659 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
2660 } else {
2661
2662 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2663 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
2664
2665 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2666 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
2667
2668 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2669 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
2670
2671 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2672 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
2673
2674 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2675 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
2676 }
2677 }
2678}
2679
2680static void
7cc4a4c0 2681wlc_lcnphy_run_samples(phy_info_t *pi,
7d4df48e
GKH
2682 u16 num_samps,
2683 u16 num_loops, u16 wait, bool iqcalmode)
a9533e7e
HP
2684{
2685
2686 or_phy_reg(pi, 0x6da, 0x8080);
2687
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);
2692
2693 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
2694
2695 if (iqcalmode) {
2696
7d4df48e 2697 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
a9533e7e
HP
2698 or_phy_reg(pi, 0x453, (0x1 << 15));
2699 } else {
2700 write_phy_reg(pi, 0x63f, 1);
2701 wlc_lcnphy_tx_pu(pi, 1);
2702 }
2703
2704 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2705}
2706
7cc4a4c0 2707void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
a9533e7e
HP
2708{
2709
e868ab03 2710 u8 phybw40;
a9533e7e
HP
2711 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
2712
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);
2719 }
2720
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);
2728 }
2729}
2730
2731void
7d4df48e 2732wlc_lcnphy_start_tx_tone(phy_info_t *pi, int32 f_kHz, u16 max_val,
a9533e7e
HP
2733 bool iqcalmode)
2734{
e868ab03 2735 u8 phy_bw;
7d4df48e 2736 u16 num_samps, t, k;
a9533e7e
HP
2737 uint32 bw;
2738 fixed theta = 0, rot = 0;
2739 cint32 tone_samp;
2740 uint32 data_buf[64];
7d4df48e 2741 u16 i_samp, q_samp;
a9533e7e
HP
2742 phytbl_info_t tab;
2743 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2744
2745 pi->phy_tx_tone_freq = f_kHz;
2746
2747 wlc_lcnphy_deaf_mode(pi, TRUE);
2748
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);
2755 }
2756
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;
2767
2768 rot = FIXED((f_kHz * 36) / phy_bw) / 100;
2769 theta = 0;
2770
2771 for (t = 0; t < num_samps; t++) {
2772
2773 wlc_phy_cordic(theta, &tone_samp);
2774
2775 theta += rot;
2776
7d4df48e
GKH
2777 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2778 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
a9533e7e
HP
2779 data_buf[t] = (i_samp << 10) | q_samp;
2780 }
2781
2782 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
2783
2784 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
2785
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);
2792
2793 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
2794}
2795
7cc4a4c0 2796void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
a9533e7e
HP
2797{
2798 int16 playback_status;
2799 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2800
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);
2807 }
2808
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);
2815
2816 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
2817
2818 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
2819
2820 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
2821
2822 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
2823
2824 wlc_lcnphy_deaf_mode(pi, FALSE);
2825}
2826
7cc4a4c0 2827static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
a9533e7e
HP
2828{
2829
7d4df48e 2830 and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
a9533e7e
HP
2831}
2832
7d4df48e 2833void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, u16 *a, u16 *b)
a9533e7e 2834{
7d4df48e 2835 u16 iqcc[2];
a9533e7e
HP
2836 phytbl_info_t tab;
2837
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);
2844
2845 *a = iqcc[0];
2846 *b = iqcc[1];
2847}
2848
7d4df48e 2849u16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
a9533e7e
HP
2850{
2851 phytbl_info_t tab;
7d4df48e 2852 u16 didq;
a9533e7e
HP
2853
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);
2860
2861 return didq;
2862}
2863
7cc4a4c0 2864static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
a9533e7e
HP
2865{
2866
2867 lcnphy_txgains_t target_gains, old_gains;
e868ab03 2868 u8 save_bb_mult;
7d4df48e 2869 u16 a, b, didq, save_pa_gain = 0;
a9533e7e
HP
2870 uint idx, SAVE_txpwrindex = 0xFF;
2871 uint32 val;
7d4df48e 2872 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
a9533e7e 2873 phytbl_info_t tab;
e868ab03 2874 u8 ei0, eq0, fi0, fq0;
a9533e7e
HP
2875 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2876
2877 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2878 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
2879
2880 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
2881
2882 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
2883 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2884
2885 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2886
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);
2893
2894 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
2895
2896 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
2897
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 {
2903
2904 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2905 }
2906
2907 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
562c8850 2908 if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
a9533e7e
HP
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;
2919 }
2920
2921 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
2922 || pi_lcn->lcnphy_hw_iqcal_en) {
2923
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 {
2930
2931 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2932 }
2933
2934 }
2935
2936 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
2937
2938 didq = wlc_lcnphy_get_tx_locc(pi);
2939
2940 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2941 tab.tbl_width = 32;
2942 tab.tbl_ptr = &val;
2943
2944 tab.tbl_len = 1;
2945 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2946
2947 for (idx = 0; idx < 128; idx++) {
2948 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
2949
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);
2954
2955 val = didq;
2956 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
2957 wlc_lcnphy_write_table(pi, &tab);
2958 }
2959
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;
2967
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);
2971
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);
2976}
2977
7cc4a4c0 2978int16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
a9533e7e 2979{
7d4df48e 2980 u16 tempsenseval1, tempsenseval2;
a9533e7e
HP
2981 int16 avg = 0;
2982 bool suspend = 0;
2983
2984 if (NORADIO_ENAB(pi->pubpi))
2985 return -1;
2986
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);
2994 }
2995 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
2996 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
2997
2998 if (tempsenseval1 > 255)
2999 avg = (int16) (tempsenseval1 - 512);
3000 else
3001 avg = (int16) tempsenseval1;
3002
3003 if (tempsenseval2 > 255)
3004 avg += (int16) (tempsenseval2 - 512);
3005 else
3006 avg += (int16) tempsenseval2;
3007
3008 avg /= 2;
3009
3010 if (mode == 1) {
3011
3012 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3013
3014 OSL_DELAY(100);
3015 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3016
3017 if (!suspend)
3018 wlapi_enable_mac(pi->sh->physhim);
3019 }
3020 return avg;
3021}
3022
7d4df48e 3023u16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
a9533e7e 3024{
7d4df48e 3025 u16 tempsenseval1, tempsenseval2;
a9533e7e
HP
3026 int32 avg = 0;
3027 bool suspend = 0;
7d4df48e 3028 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
a9533e7e
HP
3029 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3030
3031 if (NORADIO_ENAB(pi->pubpi))
3032 return -1;
3033
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);
3041 }
3042 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3043 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3044
3045 if (tempsenseval1 > 255)
3046 avg = (int)(tempsenseval1 - 512);
3047 else
3048 avg = (int)tempsenseval1;
3049
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;
3061 }
3062 if (avg < 0)
3063 avg = avg + 512;
3064
3065 if (pi_lcn->lcnphy_tempsense_option == 2)
3066 avg = tempsenseval1;
3067
3068 if (mode)
3069 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3070
3071 if (mode == 1) {
3072
3073 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3074
3075 OSL_DELAY(100);
3076 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3077
3078 if (!suspend)
3079 wlapi_enable_mac(pi->sh->physhim);
3080 }
7d4df48e 3081 return (u16) avg;
a9533e7e
HP
3082}
3083
562c8850 3084s8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
a9533e7e
HP
3085{
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;
562c8850 3090 return (s8) degree;
a9533e7e
HP
3091}
3092
562c8850 3093s8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
a9533e7e 3094{
7d4df48e 3095 u16 vbatsenseval;
a9533e7e
HP
3096 int32 avg = 0;
3097 bool suspend = 0;
3098
3099 if (NORADIO_ENAB(pi->pubpi))
3100 return -1;
3101
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);
3109 }
3110
3111 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
3112
3113 if (vbatsenseval > 255)
3114 avg = (int32) (vbatsenseval - 512);
3115 else
3116 avg = (int32) vbatsenseval;
3117
3118 avg =
3119 (avg * LCN_VBAT_SCALE_NOM +
3120 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
3121
3122 if (mode == 1) {
3123 if (!suspend)
3124 wlapi_enable_mac(pi->sh->physhim);
3125 }
562c8850 3126 return (s8) avg;
a9533e7e
HP
3127}
3128
e868ab03 3129static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode)
a9533e7e 3130{
e868ab03 3131 u8 phybw40;
a9533e7e
HP
3132 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3133
3134 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
3135
3136 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
3137 (mode == AFE_CLK_INIT_MODE_TXRX2X))
3138 write_phy_reg(pi, 0x6d0, 0x7);
3139
3140 wlc_lcnphy_toggle_afe_pwdn(pi);
3141}
3142
3143static bool
7cc4a4c0 3144wlc_lcnphy_rx_iq_est(phy_info_t *pi,
7d4df48e 3145 u16 num_samps,
e868ab03 3146 u8 wait_time, lcnphy_iq_est_t *iq_est)
a9533e7e
HP
3147{
3148 int wait_count = 0;
3149 bool result = TRUE;
e868ab03 3150 u8 phybw40;
a9533e7e
HP
3151 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3152
3153 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
3154
3155 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
3156
3157 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
3158
7d4df48e 3159 mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
a9533e7e
HP
3160
3161 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
3162
3163 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
3164
3165 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
3166
3167 if (wait_count > (10 * 500)) {
3168 result = FALSE;
3169 goto cleanup;
3170 }
3171 OSL_DELAY(100);
3172 wait_count++;
3173 }
3174
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);
3181
3182 cleanup:
3183 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
3184
3185 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
3186
3187 return result;
3188}
3189
7d4df48e 3190static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps)
a9533e7e
HP
3191{
3192#define LCNPHY_MIN_RXIQ_PWR 2
3193 bool result;
7d4df48e 3194 u16 a0_new, b0_new;
a9533e7e
HP
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;
3201
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);
3205
3206 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
3207
3208 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
3209
ca8c1e59
JC
3210 result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
3211 if (!result)
a9533e7e
HP
3212 goto cleanup;
3213
3214 iq = (int32) iq_est.iq_prod;
3215 ii = iq_est.i_pwr;
3216 qq = iq_est.q_pwr;
3217
3218 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
3219 result = FALSE;
3220 goto cleanup;
3221 }
3222
3223 iq_nbits = wlc_phy_nbits(iq);
3224 qq_nbits = wlc_phy_nbits(qq);
3225
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;
3232 }
3233 } else {
3234 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3235 temp = (int32) (ii << -arsh);
3236 if (temp == 0) {
3237 return FALSE;
3238 }
3239 }
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;
3247 }
3248 } else {
3249 b = (qq << (31 - qq_nbits));
3250 temp = (int32) (ii << -brsh);
3251 if (temp == 0) {
3252 return FALSE;
3253 }
3254 }
3255 b /= temp;
3256 b -= a * a;
3257 b = (int32) wlc_phy_sqrt_int((uint32) b);
3258 b -= (1 << 10);
7d4df48e
GKH
3259 a0_new = (u16) (a & 0x3ff);
3260 b0_new = (u16) (b & 0x3ff);
a9533e7e
HP
3261 cleanup:
3262
3263 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
3264
3265 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
3266
3267 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
3268
3269 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
3270 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
3271
3272 return result;
3273}
3274
3275static bool
7cc4a4c0 3276wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
a9533e7e
HP
3277 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3278 int tx_gain_idx)
3279{
3280 lcnphy_txgains_t old_gains;
7d4df48e 3281 u16 tx_pwr_ctrl;
e868ab03 3282 u8 tx_gain_index_old = 0;
a9533e7e 3283 bool result = FALSE, tx_gain_override_old = FALSE;
7d4df48e 3284 u16 i, Core1TxControl_old, RFOverride0_old,
a9533e7e
HP
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;
7d4df48e
GKH
3290 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3291 u16 values_to_save[11];
a9533e7e
HP
3292 int16 *ptr;
3293 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3294
ca8c1e59
JC
3295 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
3296 if (NULL == ptr) {
a9533e7e
HP
3297 return FALSE;
3298 }
3299 if (module == 2) {
3300 ASSERT(iqcomp_sz);
3301
3302 while (iqcomp_sz--) {
3303 if (iqcomp[iqcomp_sz].chan ==
3304 CHSPEC_CHANNEL(pi->radio_chanspec)) {
3305
3306 wlc_lcnphy_set_rx_iq_comp(pi,
7d4df48e 3307 (u16)
a9533e7e 3308 iqcomp[iqcomp_sz].a,
7d4df48e 3309 (u16)
a9533e7e
HP
3310 iqcomp[iqcomp_sz].b);
3311 result = TRUE;
3312 break;
3313 }
3314 }
3315 ASSERT(result);
3316 goto cal_done;
3317 }
3318
3319 if (module == 1) {
3320
3321 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3322 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3323
3324 for (i = 0; i < 11; i++) {
3325 values_to_save[i] =
3326 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
3327 }
3328 Core1TxControl_old = read_phy_reg(pi, 0x631);
3329
3330 or_phy_reg(pi, 0x631, 0x0015);
3331
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);
3344
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;
3349 }
3350
3351 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
3352
3353 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3354 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3355
3356 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3357 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3358
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);
3369
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);
3380
3381 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3382 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3383
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);
3389
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,
7d4df48e 3396 (u16)
a9533e7e
HP
3397 tia_gain, 1, 0);
3398 OSL_DELAY(500);
3399
3400 received_power =
3401 wlc_lcnphy_measure_digital_power(pi, 2000);
3402 if (received_power < rx_pwr_threshold)
3403 break;
3404 }
3405 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
3406
3407 wlc_lcnphy_stop_tx_tone(pi);
3408
3409 write_phy_reg(pi, 0x631, Core1TxControl_old);
3410
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);
3423
3424 wlc_lcnphy_clear_trsw_override(pi);
3425
3426 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
3427
3428 for (i = 0; i < 11; i++) {
3429 write_radio_reg(pi, rxiq_cal_rf_reg[i],
3430 values_to_save[i]);
3431 }
3432
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);
3438
3439 wlc_lcnphy_rx_gain_override_enable(pi, FALSE);
3440 }
3441
3442 cal_done:
3443 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
3444 return result;
3445}
3446
7cc4a4c0 3447static void wlc_lcnphy_temp_adj(phy_info_t *pi)
a9533e7e
HP
3448{
3449 if (NORADIO_ENAB(pi->pubpi))
3450 return;
3451}
3452
7cc4a4c0 3453static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
a9533e7e
HP
3454{
3455 bool suspend;
562c8850 3456 s8 index;
7d4df48e 3457 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
a9533e7e
HP
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;
3467
3468 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3469
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);
3475
3476}
3477
7cc4a4c0 3478static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
a9533e7e
HP
3479{
3480 bool suspend, full_cal;
3481 const lcnphy_rx_iqcomp_t *rx_iqcomp;
3482 int rx_iqcomp_sz;
7d4df48e 3483 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
562c8850 3484 s8 index;
a9533e7e
HP
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;
3489
3490 if (NORADIO_ENAB(pi->pubpi))
3491 return;
3492
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;
3500
3501 suspend =
3502 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3503 if (!suspend) {
3504
3505 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
3506 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3507 }
3508 wlc_lcnphy_deaf_mode(pi, TRUE);
3509
3510 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3511
3512 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
3513 rx_iqcomp_sz = ARRAYSIZE(lcnphy_rx_iqcomp_table_rev0);
3514
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);
3519
3520 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
3521
3522 wlc_lcnphy_idle_tssi_est((wlc_phy_t *) pi);
3523
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);
3529
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++;
3540 }
3541 }
3542
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);
3548}
3549
7cc4a4c0 3550void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
a9533e7e 3551{
7d4df48e 3552 u16 temp_new;
a9533e7e
HP
3553 int temp1, temp2, temp_diff;
3554 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3555
3556 switch (mode) {
3557 case PHY_PERICAL_CHAN:
3558
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++;
3580 }
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;
3589 }
3590}
3591
562c8850 3592void wlc_lcnphy_get_tssi(phy_info_t *pi, s8 *ofdm_pwr, s8 *cck_pwr)
a9533e7e 3593{
562c8850 3594 s8 cck_offset;
7d4df48e 3595 u16 status;
ca8c1e59 3596 status = (read_phy_reg(pi, 0x4ab));
a9533e7e 3597 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
ca8c1e59 3598 (status & (0x1 << 15))) {
562c8850 3599 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
a9533e7e
HP
3600 >> 0) >> 1);
3601
3602 if (wlc_phy_tpc_isenabled_lcnphy(pi))
3603 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
3604 else
3605 cck_offset = 0;
3606
3607 *cck_pwr = *ofdm_pwr + cck_offset;
3608 } else {
3609 *cck_pwr = 0;
3610 *ofdm_pwr = 0;
3611 }
3612}
3613
a2627bc0
JC
3614void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi)
3615{
a9533e7e
HP
3616 return;
3617
3618}
3619
7cc4a4c0 3620static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
a9533e7e 3621{
e868ab03 3622 u8 channel = CHSPEC_CHANNEL(chanspec);
a9533e7e
HP
3623 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3624
3625 if (NORADIO_ENAB(pi->pubpi))
3626 return;
3627
3628 if (channel == 14) {
3629 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
3630
3631 } else {
3632 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
3633
3634 }
3635 pi_lcn->lcnphy_bandedge_corr = 2;
3636 if (channel == 1)
3637 pi_lcn->lcnphy_bandedge_corr = 4;
3638
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);
3645
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);
3651
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);
3657
3658 si_pmu_pllupd(pi->sh->sih);
3659 write_phy_reg(pi, 0x942, 0);
3660 wlc_lcnphy_txrx_spur_avoidance_mode(pi, TRUE);
3661
3662 pi_lcn->lcnphy_spurmod = 0;
3663 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
3664
3665 write_phy_reg(pi, 0x425, 0x590a);
3666 }
3667
3668 or_phy_reg(pi, 0x44a, 0x44);
3669 write_phy_reg(pi, 0x44a, 0x80);
3670}
3671
3672void
e868ab03 3673wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng, u8 rate,
a9533e7e
HP
3674 struct ether_addr *sa, uint32 wait_delay)
3675{
3676}
3677
7cc4a4c0 3678void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
a9533e7e 3679{
562c8850 3680 s8 index;
7d4df48e 3681 u16 index2;
a9533e7e
HP
3682 phy_info_t *pi = (phy_info_t *) ppi;
3683 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
7d4df48e 3684 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
a9533e7e
HP
3685 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3686 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
7d4df48e 3687 index2 = (u16) (index * 2);
a9533e7e
HP
3688 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3689
562c8850 3690 pi_lcn->lcnphy_current_index = (s8)
a9533e7e
HP
3691 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3692 }
3693}
3694
7d4df48e 3695static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b)
a9533e7e
HP
3696{
3697 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3698
3699 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3700
3701 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3702
3703 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3704
3705 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3706
3707 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3708
3709}
3710
a2627bc0
JC
3711void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3712{
e868ab03 3713 u8 phybw40;
a9533e7e
HP
3714 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3715 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3716
3717 pi_lcn->lcnphy_cal_counter = 0;
3718 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3719
3720 or_phy_reg(pi, 0x44a, 0x80);
3721 and_phy_reg(pi, 0x44a, 0x7f);
3722
3723 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3724
3725 write_phy_reg(pi, 0x60a, 160);
3726
3727 write_phy_reg(pi, 0x46a, 25);
3728
3729 wlc_lcnphy_baseband_init(pi);
3730
3731 wlc_lcnphy_radio_init(pi);
3732
3733 if (CHSPEC_IS2G(pi->radio_chanspec))
3734 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3735
3736 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3737
3738 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3739
3740 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3741
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);
3745
3746 wlc_lcnphy_agc_temp_init(pi);
3747
3748 wlc_lcnphy_temp_adj(pi);
3749
3750 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3751
3752 OSL_DELAY(100);
3753 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3754
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);
3758}
3759
3760static void
7d4df48e 3761wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, u16 *values_to_save)
a9533e7e 3762{
7d4df48e 3763 u16 vmid;
a9533e7e
HP
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]);
3768 }
3769
3770 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3771 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3772
3773 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3774 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3775
3776 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3777 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3778
3779 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3780 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3781
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);
3787
3788 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3789 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3790 OSL_DELAY(20);
3791
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);
3802 }
3803
3804 OSL_DELAY(20);
3805
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);
3817 }
3818
3819 OSL_DELAY(20);
3820
3821 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3822 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3823 OSL_DELAY(20);
3824
3825 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3826 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3827 OSL_DELAY(20);
3828
3829 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3830 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3831 OSL_DELAY(20);
3832
3833 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3834 OSL_DELAY(20);
3835
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);
3841
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);
3851}
3852
3853static void
7d4df48e 3854wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, u16 thresh,
7cc4a4c0 3855 int16 *ptr, int mode)
a9533e7e
HP
3856{
3857 uint32 curval1, curval2, stpptr, curptr, strptr, val;
7d4df48e
GKH
3858 u16 sslpnCalibClkEnCtrl, timer;
3859 u16 old_sslpnCalibClkEnCtrl;
a9533e7e
HP
3860 int16 imag, real;
3861 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3862
3863 timer = 0;
3864 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3865
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));
3869
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);
3875
3876 write_phy_reg(pi, 0x555, 0x0);
3877 write_phy_reg(pi, 0x5a6, 0x5);
3878
7d4df48e 3879 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
a9533e7e
HP
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);
3886
3887 write_phy_reg(pi, 0x580, 0x4501);
3888
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));
3898
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;
3908 }
3909 if (real > 511) {
3910 real -= 1024;
3911 }
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;
3920 }
3921 }
3922 strptr += 4;
3923 }
3924
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);
3928}
3929
7cc4a4c0 3930static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
a9533e7e
HP
3931{
3932 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3933
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);
3938
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);
3945
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);
3950}
3951
3952static void
7cc4a4c0 3953wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x, int16 coeff_y)
a9533e7e 3954{
7d4df48e
GKH
3955 u16 di0dq0;
3956 u16 x, y, data_rf;
a9533e7e
HP
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;
3994 }
3995}
3996
7cc4a4c0 3997static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
a9533e7e 3998{
7d4df48e 3999 u16 a, b, didq;
e868ab03 4000 u8 di0, dq0, ei, eq, fi, fq;
a9533e7e
HP
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);
7d4df48e
GKH
4014 cc.re = (u16) di0;
4015 cc.im = (u16) dq0;
a9533e7e
HP
4016 break;
4017 case 3:
4018 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
7d4df48e
GKH
4019 cc.re = (u16) ei;
4020 cc.im = (u16) eq;
a9533e7e
HP
4021 break;
4022 case 4:
4023 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
7d4df48e
GKH
4024 cc.re = (u16) fi;
4025 cc.im = (u16) fq;
a9533e7e
HP
4026 break;
4027 }
4028 return cc;
4029}
4030
4031static void
7cc4a4c0 4032wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
a9533e7e
HP
4033{
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;
7d4df48e 4038 u16 phy_c7, phy_c8, phy_c9;
a9533e7e
HP
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;
7d4df48e
GKH
4044 u16 phy_c26, phy_c27;
4045 u16 phy_c28, phy_c29, phy_c30;
4046 u16 phy_c31;
4047 u16 *phy_c32;
a9533e7e
HP
4048 phy_c21 = 0;
4049 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
ca8c1e59
JC
4050 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
4051 if (NULL == ptr) {
a9533e7e
HP
4052 return;
4053 }
4054
7d4df48e 4055 phy_c32 = MALLOC(pi->sh->osh, sizeof(u16) * 20);
ca8c1e59 4056 if (NULL == phy_c32) {
a9533e7e
HP
4057 return;
4058 }
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);
4063
4064 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
4065 write_phy_reg(pi, 0x6da, 0xffff);
4066 or_phy_reg(pi, 0x6db, 0x3);
4067
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;
4083
4084 if (num_levels == 0) {
4085 if (cal_type != 0) {
4086 num_levels = 4;
4087 } else {
4088 num_levels = 9;
4089 }
4090 }
4091 if (step_size_lg2 == 0) {
4092 if (cal_type != 0) {
4093 step_size_lg2 = 3;
4094 } else {
4095 step_size_lg2 = 8;
4096 }
4097 }
4098
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;
4108 }
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;
4127 }
4128
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;
4153 }
4154
4155 if (phy_c5 < 0)
4156 phy_c5 = 0;
4157 else if (phy_c5 > 7)
4158 phy_c5 = 7;
4159
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;
4164
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);
4177
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;
4185 }
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;
4191 }
4192
4193 phy_c18 = phy_c18 >> 10;
4194 phy_c19 = phy_c19 >> 10;
4195 phy_c20 =
4196 ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
4197
4198 if (phy_c23 || phy_c20 < phy_c21) {
4199 phy_c21 = phy_c20;
4200 phy_c13 = phy_c11;
4201 phy_c14 = phy_c12;
4202 }
4203 phy_c23 = 0;
4204 }
4205 }
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);
4212 }
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);
4223
7d4df48e 4224 MFREE(pi->sh->osh, phy_c32, 20 * sizeof(u16));
a9533e7e
HP
4225 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
4226}
4227
4228static void
7d4df48e 4229wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, u16 *values_to_save)
a9533e7e
HP
4230{
4231 int i;
4232
4233 and_phy_reg(pi, 0x44c, 0x0 >> 11);
4234
4235 and_phy_reg(pi, 0x43b, 0xC);
4236
4237 for (i = 0; i < 20; i++) {
4238 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
4239 values_to_save[i]);
4240 }
4241}
4242
4243static void
7cc4a4c0 4244WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
a9533e7e
HP
4245 const lcnphy_tx_gain_tbl_entry *
4246 gain_table) {
4247 uint32 j;
4248 phytbl_info_t tab;
4249 uint32 val;
7d4df48e
GKH
4250 u16 pa_gain;
4251 u16 gm_gain;
a9533e7e
HP
4252
4253 if (CHSPEC_IS5G(pi->radio_chanspec))
4254 pa_gain = 0x70;
4255 else
4256 pa_gain = 0x70;
4257
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;
4264
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);
4270
4271 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4272 wlc_lcnphy_write_table(pi, &tab);
4273
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);
4277 }
4278}
4279
7cc4a4c0 4280static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
a9533e7e
HP
4281{
4282 phytbl_info_t tab;
4283 uint32 val, bbmult, rfgain;
e868ab03
GKH
4284 u8 index;
4285 u8 scale_factor = 1;
a9533e7e
HP
4286 int16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4287
4288 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4289 tab.tbl_width = 32;
4290 tab.tbl_len = 1;
4291
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;
4297
4298 tab.tbl_ptr = &rfgain;
4299 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4300 wlc_lcnphy_read_table(pi, &tab);
4301
4302 qm_log10((int32) (bbmult), 0, &temp1, &qQ1);
4303 qm_log10((int32) (1 << 6), 0, &temp2, &qQ2);
4304
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;
4311 }
4312 temp = qm_sub16(temp1, temp2);
4313
4314 if (qQ >= 4)
4315 shift = qQ - 4;
4316 else
4317 shift = 4 - qQ;
4318
4319 val = (((index << shift) + (5 * temp) +
4320 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4321 shift - 2));
4322
4323 tab.tbl_ptr = &val;
4324 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4325 wlc_lcnphy_write_table(pi, &tab);
4326 }
4327}
4328
a2627bc0
JC
4329static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi)
4330{
a9533e7e 4331 uint idx;
e868ab03 4332 u8 phybw40;
a9533e7e
HP
4333 phytbl_info_t tab;
4334 uint32 val;
4335
4336 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4337
4338 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
4339 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4340 }
4341
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);
4350 }
4351
4352 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4353 tab.tbl_width = 16;
4354 tab.tbl_ptr = &val;
4355 tab.tbl_len = 1;
4356
4357 val = 114;
4358 tab.tbl_offset = 0;
4359 wlc_lcnphy_write_table(pi, &tab);
4360
4361 val = 130;
4362 tab.tbl_offset = 1;
4363 wlc_lcnphy_write_table(pi, &tab);
4364
4365 val = 6;
4366 tab.tbl_offset = 8;
4367 wlc_lcnphy_write_table(pi, &tab);
4368
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);
4376 }
4377
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]);
4403 }
4404 }
4405
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);
4418
4419 wlc_lcnphy_load_rfpower(pi);
4420
4421 wlc_lcnphy_clear_papd_comptable(pi);
4422}
4423
a2627bc0
JC
4424static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi)
4425{
7d4df48e 4426 u16 afectrl1;
a9533e7e
HP
4427 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4428
4429 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4430
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);
4440
4441 or_phy_reg(pi, 0x567, 0x03);
4442
4443 or_phy_reg(pi, 0x44a, 0x44);
4444 write_phy_reg(pi, 0x44a, 0x80);
4445
4446 if (!(pi->sh->boardflags & BFL_FEM))
4447 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4448
4449 if (0) {
4450 afectrl1 = 0;
7d4df48e 4451 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
a9533e7e
HP
4452 (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4453 lcnphy_rssi_gs
4454 << 10));
4455 write_phy_reg(pi, 0x43e, afectrl1);
4456 }
4457
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);
4461
4462 write_phy_reg(pi, 0x910, 0x1);
4463 }
4464
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);
4468
4469}
4470
a2627bc0
JC
4471static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi)
4472{
a9533e7e
HP
4473 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4474 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4475
4476 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4477 }
4478}
4479
7cc4a4c0 4480static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
a9533e7e
HP
4481{
4482 int16 temp;
4483 phytbl_info_t tab;
4484 uint32 tableBuffer[2];
4485 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4486
4487 if (NORADIO_ENAB(pi->pubpi))
4488 return;
4489
4490 temp = (int16) read_phy_reg(pi, 0x4df);
4491 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4492
4493 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4494 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4495
4496 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4497
4498 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4499 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4500
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);
4507
4508 if (tableBuffer[0] > 63)
4509 tableBuffer[0] -= 128;
4510 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4511
4512 if (tableBuffer[1] > 63)
4513 tableBuffer[1] -= 128;
4514 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4515
4516 temp = (int16) (read_phy_reg(pi, 0x434)
4517 & (0xff << 0));
4518 if (temp > 127)
4519 temp -= 256;
562c8850 4520 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
a9533e7e
HP
4521
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;
4528
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);
4535
4536 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4537 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4538
4539}
4540
a2627bc0
JC
4541static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi)
4542{
a9533e7e
HP
4543 if (NORADIO_ENAB(pi->pubpi))
4544 return;
4545
4546 or_phy_reg(pi, 0x805, 0x1);
4547
4548 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4549
4550 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4551
4552 write_phy_reg(pi, 0x414, 0x1e10);
4553 write_phy_reg(pi, 0x415, 0x0640);
4554
4555 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4556
4557 or_phy_reg(pi, 0x44a, 0x44);
4558 write_phy_reg(pi, 0x44a, 0x80);
4559 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4560
4561 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4562
4563 if (!(pi->sh->boardrev < 0x1204))
4564 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4565
4566 write_phy_reg(pi, 0x7d6, 0x0902);
4567 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4568
4569 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4570
4571 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4572 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4573
4574 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4575
4576 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4577
4578 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4579
4580 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4581
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);
4587
4588 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4589
4590 wlc_lcnphy_clear_tx_power_offsets(pi);
4591 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4592
4593 }
4594}
4595
a2627bc0
JC
4596static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi)
4597{
a9533e7e
HP
4598
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);
4604}
4605
a2627bc0
JC
4606static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi)
4607{
a9533e7e
HP
4608 uint32 i;
4609 lcnphy_radio_regs_t *lcnphyregs = NULL;
4610
4611 lcnphyregs = lcnphy_radio_regs_2064;
4612
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),
7d4df48e 4618 (u16) lcnphyregs[i].init_a);
a9533e7e
HP
4619 else if (lcnphyregs[i].do_init_g)
4620 write_radio_reg(pi,
4621 ((lcnphyregs[i].address & 0x3fff) |
4622 RADIO_DEFAULT_CORE),
7d4df48e 4623 (u16) lcnphyregs[i].init_g);
a9533e7e
HP
4624
4625 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4626 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4627
4628 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4629
4630 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4631
4632 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4633
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);
4637 }
4638
4639 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4640 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4641
4642 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4643
4644 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4645
4646 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4647
4648 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4649
4650 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4651
4652 write_phy_reg(pi, 0x4ea, 0x4688);
4653
4654 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4655
4656 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4657
4658 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4659
4660 wlc_lcnphy_set_tx_locc(pi, 0);
4661
4662 wlc_lcnphy_rcal(pi);
4663
4664 wlc_lcnphy_rc_cal(pi);
4665}
4666
a2627bc0
JC
4667static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi)
4668{
a9533e7e
HP
4669 if (NORADIO_ENAB(pi->pubpi))
4670 return;
4671
4672 wlc_radio_2064_init(pi);
4673}
4674
7cc4a4c0 4675static void wlc_lcnphy_rcal(phy_info_t *pi)
a9533e7e 4676{
e868ab03 4677 u8 rcal_value;
a9533e7e
HP
4678
4679 if (NORADIO_ENAB(pi->pubpi))
4680 return;
4681
4682 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4683
4684 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4685 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4686
4687 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4688 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4689
4690 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4691
4692 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4693 OSL_DELAY(5000);
4694 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4695
4696 if (wlc_radio_2064_rcal_done(pi)) {
e868ab03 4697 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
a9533e7e
HP
4698 rcal_value = rcal_value & 0x1f;
4699 }
4700
4701 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4702
4703 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4704}
4705
7cc4a4c0 4706static void wlc_lcnphy_rc_cal(phy_info_t *pi)
a9533e7e 4707{
e868ab03 4708 u8 dflt_rc_cal_val;
7d4df48e 4709 u16 flt_val;
a9533e7e
HP
4710
4711 if (NORADIO_ENAB(pi->pubpi))
4712 return;
4713
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));
4725
4726 return;
4727}
4728
a2627bc0
JC
4729static bool BCMATTACHFN(wlc_phy_txpwr_srom_read_lcnphy) (phy_info_t *pi)
4730{
562c8850 4731 s8 txpwr = 0;
a9533e7e
HP
4732 int i;
4733 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4734
4735 if (CHSPEC_IS2G(pi->radio_chanspec)) {
7d4df48e 4736 u16 cckpo = 0;
a9533e7e
HP
4737 uint32 offset_ofdm, offset_mcs;
4738
4739 pi_lcn->lcnphy_tr_isolation_mid =
e868ab03 4740 (u8) PHY_GETINTVAR(pi, "triso2g");
a9533e7e
HP
4741
4742 pi_lcn->lcnphy_rx_power_offset =
e868ab03 4743 (u8) PHY_GETINTVAR(pi, "rxpo2g");
a9533e7e
HP
4744
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");
4748
e868ab03
GKH
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");
a9533e7e
HP
4752
4753 {
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;
4757
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;
4764 }
4765
562c8850 4766 txpwr = (s8) PHY_GETINTVAR(pi, "maxp2ga0");
a9533e7e
HP
4767 pi->tx_srom_max_2g = txpwr;
4768
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];
4772 }
4773
7d4df48e 4774 cckpo = (u16) PHY_GETINTVAR(pi, "cck2gpo");
a9533e7e
HP
4775 if (cckpo) {
4776 uint max_pwr_chan = txpwr;
4777
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;
4782 }
4783
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;
4789 }
4790 } else {
e868ab03 4791 u8 opo = 0;
a9533e7e 4792
e868ab03 4793 opo = (u8) PHY_GETINTVAR(pi, "opo");
a9533e7e
HP
4794
4795 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4796 pi->tx_srom_max_rate_2g[i] = txpwr;
4797 }
4798
4799 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4800
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;
4805 }
4806 offset_mcs =
7d4df48e
GKH
4807 ((u16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4808 (u16) PHY_GETINTVAR(pi, "mcs2gpo0");
a9533e7e
HP
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;
4815 }
4816 }
4817
4818 pi_lcn->lcnphy_rawtempsense =
7d4df48e 4819 (u16) PHY_GETINTVAR(pi, "rawtempsense");
a9533e7e 4820 pi_lcn->lcnphy_measPower =
e868ab03 4821 (u8) PHY_GETINTVAR(pi, "measpower");
a9533e7e 4822 pi_lcn->lcnphy_tempsense_slope =
e868ab03 4823 (u8) PHY_GETINTVAR(pi, "tempsense_slope");
a9533e7e
HP
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 =
e868ab03 4829 (u8) PHY_GETINTVAR(pi, "tempcorrx");
a9533e7e 4830 pi_lcn->lcnphy_tempsense_option =
e868ab03 4831 (u8) PHY_GETINTVAR(pi, "tempsense_option");
a9533e7e 4832 pi_lcn->lcnphy_freqoffset_corr =
e868ab03
GKH
4833 (u8) PHY_GETINTVAR(pi, "freqoffset_corr");
4834 if ((u8) getintvar(pi->vars, "aa2g") > 1)
a9533e7e 4835 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
e868ab03 4836 (u8) getintvar(pi->vars,
a9533e7e
HP
4837 "aa2g"));
4838 }
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;
4845 }
4846 }
4847
4848 return TRUE;
4849}
4850
7cc4a4c0 4851void wlc_2064_vco_cal(phy_info_t *pi)
a9533e7e 4852{
e868ab03 4853 u8 calnrst;
a9533e7e
HP
4854
4855 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
e868ab03 4856 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
a9533e7e
HP
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);
4864}
4865
4866static void
e868ab03 4867wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, u8 channel)
a9533e7e
HP
4868{
4869 uint i;
4870 const chan_info_2064_lcnphy_t *ci;
e868ab03
GKH
4871 u8 rfpll_doubler = 0;
4872 u8 pll_pwrup, pll_pwrup_ovr;
a9533e7e 4873 fixed qFxtal, qFref, qFvco, qFcal;
e868ab03 4874 u8 d15, d16, f16, e44, e45;
a9533e7e 4875 uint32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
7d4df48e 4876 u16 loop_bw, d30, setCount;
a9533e7e
HP
4877 if (NORADIO_ENAB(pi->pubpi))
4878 return;
4879 ci = &chan_info_2064_lcnphy[0];
4880 rfpll_doubler = 1;
4881
4882 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
4883
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;
4891 }
4892
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;
4897
4898 if (i >= ARRAYSIZE(chan_info_2064_lcnphy)) {
4899 return;
4900 }
4901
4902 ci = &chan_info_2064_lcnphy[i];
4903 }
4904
4905 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
4906
4907 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
4908
4909 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
4910
4911 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
4912
4913 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
4914 (ci->logen_rccr_rx) << 2);
4915
4916 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
4917
4918 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
4919 (ci->pa_rxrf_lna2_freq_tune) << 4);
4920
4921 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
4922
e868ab03
GKH
4923 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
4924 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
a9533e7e
HP
4925
4926 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
4927
4928 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
4929 e44 = 0;
4930 e45 = 0;
4931
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;
4945
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);
4950
4951 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
4952
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);
4956
4957 d16 = (qFcal * 8 / (d15 + 1)) - 1;
4958 write_radio_reg(pi, RADIO_2064_REG051, d16);
4959
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),
e868ab03 4963 (u8) (setCount >> 8));
a9533e7e
HP
4964
4965 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
e868ab03 4966 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
a9533e7e
HP
4967
4968 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
4969
4970 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
4971 while (div_frac >= fref3) {
4972 div_int++;
4973 div_frac -= fref3;
4974 }
4975 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
4976
4977 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
e868ab03 4978 (u8) (div_int >> 4));
a9533e7e 4979 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
e868ab03 4980 (u8) (div_int << 4));
a9533e7e 4981 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
e868ab03
GKH
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);
a9533e7e
HP
4985
4986 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
4987
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);
4991
4992 {
e868ab03 4993 u8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
7d4df48e 4994 u16 c29, c38, c30, g30, d28;
a9533e7e
HP
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);
5012 }
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);
5018
5019 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
5020 OSL_DELAY(1);
5021
5022 wlc_2064_vco_cal(pi);
5023
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);
5029 }
5030}
5031
7cc4a4c0 5032bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
a9533e7e
HP
5033{
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)));
5039}
5040
7cc4a4c0 5041void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
a9533e7e 5042{
7d4df48e 5043 u16 pwr_ctrl;
a9533e7e
HP
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)) {
5047
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);
5051
5052 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5053 } else
5054 return;
5055}
5056
7cc4a4c0 5057void wlc_phy_detach_lcnphy(phy_info_t *pi)
a9533e7e
HP
5058{
5059 MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5060}
5061
7cc4a4c0 5062bool wlc_phy_attach_lcnphy(phy_info_t *pi)
a9533e7e
HP
5063{
5064 phy_info_lcnphy_t *pi_lcn;
5065
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;
5071 }
5072 bzero((char *)pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5073
5074 pi_lcn = pi->u.pi_lcnphy;
5075
5076 if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
5077 pi->hwpwrctrl = TRUE;
5078 pi->hwpwrctrl_capable = TRUE;
5079 }
5080
5081 pi->xtalfreq = si_alp_clock(pi->sh->sih);
5082 ASSERT(0 == (pi->xtalfreq % 1000));
5083
5084 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5085
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;
5095
5096 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5097 return FALSE;
5098
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;
5108 }
5109 }
5110
5111 return TRUE;
5112}
5113
7cc4a4c0 5114static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, uint32 gain)
a9533e7e 5115{
7d4df48e 5116 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
a9533e7e
HP
5117
5118 trsw = (gain & ((uint32) 1 << 28)) ? 0 : 1;
7d4df48e
GKH
5119 ext_lna = (u16) (gain >> 29) & 0x01;
5120 lna1 = (u16) (gain >> 0) & 0x0f;
5121 lna2 = (u16) (gain >> 4) & 0x0f;
5122 tia = (u16) (gain >> 8) & 0xf;
5123 biq0 = (u16) (gain >> 12) & 0xf;
5124 biq1 = (u16) (gain >> 16) & 0xf;
5125
5126 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
a9533e7e
HP
5127 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5128 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5129 gain16_19 = biq1;
5130
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);
5136
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);
5140 }
5141 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
5142}
5143
7cc4a4c0 5144static uint32 wlc_lcnphy_get_receive_power(phy_info_t *pi, int32 *gain_index)
a9533e7e
HP
5145{
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;
5150
5151 max_index = 36;
5152 if (*gain_index >= 0)
5153 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5154
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)++;
5167 }
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);
5175 }
5176
5177 return received_power;
5178}
5179
7cc4a4c0 5180int32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, int32 gain_index)
a9533e7e
HP
5181{
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;
5189
5190 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5191
5192 gain = lcnphy_gain_table[gain_index];
5193
5194 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5195
5196 {
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;
5209 }
5210
5211 log_val = log_val * 3;
5212
5213 gain_mismatch = (nominal_power_db / 2) - (log_val);
5214
5215 desired_gain = gain + gain_mismatch;
5216
5217 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5218
5219 if (input_power_offset_db > 127)
5220 input_power_offset_db -= 256;
5221
5222 input_power_db = input_power_offset_db - desired_gain;
5223
5224 input_power_db =
5225 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5226
5227 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5228 if ((freq > 2427) && (freq <= 2467))
5229 input_power_db = input_power_db - 1;
5230
5231 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5232
5233 if ((temperature - 15) < -30) {
5234 input_power_db =
5235 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5236 7;
5237 } else if ((temperature - 15) < 4) {
5238 input_power_db =
5239 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5240 3;
5241 } else {
5242 input_power_db =
5243 input_power_db + (((temperature - 10 - 25) * 286) >> 12);
5244 }
5245
5246 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5247
5248 return input_power_db;
5249}
5250
5251static int
7cc4a4c0 5252wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, int16 filt_type)
a9533e7e
HP
5253{
5254 int16 filt_index = -1;
5255 int j;
5256
7d4df48e 5257 u16 addr[] = {
a9533e7e
HP
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
5274 };
5275
7d4df48e 5276 u16 addr_ofdm[] = {
a9533e7e
HP
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
5293 };
5294
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;
5300 }
5301 }
5302
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]);
5310 }
5311 }
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;
5317 }
5318 }
5319
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]);
5327 }
5328 }
5329 }
5330
5331 return (filt_index != -1) ? 0 : -1;
5332}