]> bbs.cooldavid.org Git - net-next-2.6.git/blob - 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
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>
20 #include <linux/kernel.h>
21 #include <linux/string.h>
22 #include <linuxver.h>
23 #include <siutils.h>
24 #include <bitfuncs.h>
25 #include <hndpmu.h>
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
145 typedef struct {
146         u16 gm_gain;
147         u16 pga_gain;
148         u16 pad_gain;
149         u16 dac_gain;
150 } lcnphy_txgains_t;
151
152 typedef enum {
153         LCNPHY_CAL_FULL,
154         LCNPHY_CAL_RECAL,
155         LCNPHY_CAL_CURRECAL,
156         LCNPHY_CAL_DIGCAL,
157         LCNPHY_CAL_GCTRL
158 } lcnphy_cal_mode_t;
159
160 typedef struct {
161         lcnphy_txgains_t gains;
162         bool useindex;
163         u8 index;
164 } lcnphy_txcalgains_t;
165
166 typedef struct {
167         u8 chan;
168         int16 a;
169         int16 b;
170 } lcnphy_rx_iqcomp_t;
171
172 typedef struct {
173         int16 re;
174         int16 im;
175 } lcnphy_spb_tone_t;
176
177 typedef struct {
178         u16 re;
179         u16 im;
180 } lcnphy_unsign16_struct;
181
182 typedef struct {
183         uint32 iq_prod;
184         uint32 i_pwr;
185         uint32 q_pwr;
186 } lcnphy_iq_est_t;
187
188 typedef struct {
189         u16 ptcentreTs20;
190         u16 ptcentreFactor;
191 } lcnphy_sfo_cfg_t;
192
193 typedef enum {
194         LCNPHY_PAPD_CAL_CW,
195         LCNPHY_PAPD_CAL_OFDM
196 } lcnphy_papd_cal_type_t;
197
198 typedef u16 iqcal_gain_params_lcnphy[9];
199
200 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
201         {0, 0, 0, 0, 0, 0, 0, 0, 0},
202 };
203
204 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
205         tbl_iqcal_gainparams_lcnphy_2G,
206 };
207
208 static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
209         sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
210             sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
211 };
212
213 static const lcnphy_sfo_cfg_t lcnphy_sfo_cfg[] = {
214         {965, 1087},
215         {967, 1085},
216         {969, 1082},
217         {971, 1080},
218         {973, 1078},
219         {975, 1076},
220         {977, 1073},
221         {979, 1071},
222         {981, 1069},
223         {983, 1067},
224         {985, 1065},
225         {987, 1063},
226         {989, 1060},
227         {994, 1055}
228 };
229
230 static const
231 u16 lcnphy_iqcal_loft_gainladder[] = {
232         ((2 << 8) | 0),
233         ((3 << 8) | 0),
234         ((4 << 8) | 0),
235         ((6 << 8) | 0),
236         ((8 << 8) | 0),
237         ((11 << 8) | 0),
238         ((16 << 8) | 0),
239         ((16 << 8) | 1),
240         ((16 << 8) | 2),
241         ((16 << 8) | 3),
242         ((16 << 8) | 4),
243         ((16 << 8) | 5),
244         ((16 << 8) | 6),
245         ((16 << 8) | 7),
246         ((23 << 8) | 7),
247         ((32 << 8) | 7),
248         ((45 << 8) | 7),
249         ((64 << 8) | 7),
250         ((91 << 8) | 7),
251         ((128 << 8) | 7)
252 };
253
254 static const
255 u16 lcnphy_iqcal_ir_gainladder[] = {
256         ((1 << 8) | 0),
257         ((2 << 8) | 0),
258         ((4 << 8) | 0),
259         ((6 << 8) | 0),
260         ((8 << 8) | 0),
261         ((11 << 8) | 0),
262         ((16 << 8) | 0),
263         ((23 << 8) | 0),
264         ((32 << 8) | 0),
265         ((45 << 8) | 0),
266         ((64 << 8) | 0),
267         ((64 << 8) | 1),
268         ((64 << 8) | 2),
269         ((64 << 8) | 3),
270         ((64 << 8) | 4),
271         ((64 << 8) | 5),
272         ((64 << 8) | 6),
273         ((64 << 8) | 7),
274         ((91 << 8) | 7),
275         ((128 << 8) | 7)
276 };
277
278 static const
279 lcnphy_spb_tone_t lcnphy_spb_tone_3750[] = {
280         {88, 0},
281         {73, 49},
282         {34, 81},
283         {-17, 86},
284         {-62, 62},
285         {-86, 17},
286         {-81, -34},
287         {-49, -73},
288         {0, -88},
289         {49, -73},
290         {81, -34},
291         {86, 17},
292         {62, 62},
293         {17, 86},
294         {-34, 81},
295         {-73, 49},
296         {-88, 0},
297         {-73, -49},
298         {-34, -81},
299         {17, -86},
300         {62, -62},
301         {86, -17},
302         {81, 34},
303         {49, 73},
304         {0, 88},
305         {-49, 73},
306         {-81, 34},
307         {-86, -17},
308         {-62, -62},
309         {-17, -86},
310         {34, -81},
311         {73, -49},
312 };
313
314 static const
315 u16 iqlo_loopback_rf_regs[20] = {
316         RADIO_2064_REG036,
317         RADIO_2064_REG11A,
318         RADIO_2064_REG03A,
319         RADIO_2064_REG025,
320         RADIO_2064_REG028,
321         RADIO_2064_REG005,
322         RADIO_2064_REG112,
323         RADIO_2064_REG0FF,
324         RADIO_2064_REG11F,
325         RADIO_2064_REG00B,
326         RADIO_2064_REG113,
327         RADIO_2064_REG007,
328         RADIO_2064_REG0FC,
329         RADIO_2064_REG0FD,
330         RADIO_2064_REG012,
331         RADIO_2064_REG057,
332         RADIO_2064_REG059,
333         RADIO_2064_REG05C,
334         RADIO_2064_REG078,
335         RADIO_2064_REG092,
336 };
337
338 static const
339 u16 tempsense_phy_regs[14] = {
340         0x503,
341         0x4a4,
342         0x4d0,
343         0x4d9,
344         0x4da,
345         0x4a6,
346         0x938,
347         0x939,
348         0x4d8,
349         0x4d0,
350         0x4d7,
351         0x4a5,
352         0x40d,
353         0x4a2,
354 };
355
356 static const
357 u16 rxiq_cal_rf_reg[11] = {
358         RADIO_2064_REG098,
359         RADIO_2064_REG116,
360         RADIO_2064_REG12C,
361         RADIO_2064_REG06A,
362         RADIO_2064_REG00B,
363         RADIO_2064_REG01B,
364         RADIO_2064_REG113,
365         RADIO_2064_REG01D,
366         RADIO_2064_REG114,
367         RADIO_2064_REG02E,
368         RADIO_2064_REG12A,
369 };
370
371 static const
372 lcnphy_rx_iqcomp_t lcnphy_rx_iqcomp_table_rev0[] = {
373         {1, 0, 0},
374         {2, 0, 0},
375         {3, 0, 0},
376         {4, 0, 0},
377         {5, 0, 0},
378         {6, 0, 0},
379         {7, 0, 0},
380         {8, 0, 0},
381         {9, 0, 0},
382         {10, 0, 0},
383         {11, 0, 0},
384         {12, 0, 0},
385         {13, 0, 0},
386         {14, 0, 0},
387         {34, 0, 0},
388         {38, 0, 0},
389         {42, 0, 0},
390         {46, 0, 0},
391         {36, 0, 0},
392         {40, 0, 0},
393         {44, 0, 0},
394         {48, 0, 0},
395         {52, 0, 0},
396         {56, 0, 0},
397         {60, 0, 0},
398         {64, 0, 0},
399         {100, 0, 0},
400         {104, 0, 0},
401         {108, 0, 0},
402         {112, 0, 0},
403         {116, 0, 0},
404         {120, 0, 0},
405         {124, 0, 0},
406         {128, 0, 0},
407         {132, 0, 0},
408         {136, 0, 0},
409         {140, 0, 0},
410         {149, 0, 0},
411         {153, 0, 0},
412         {157, 0, 0},
413         {161, 0, 0},
414         {165, 0, 0},
415         {184, 0, 0},
416         {188, 0, 0},
417         {192, 0, 0},
418         {196, 0, 0},
419         {200, 0, 0},
420         {204, 0, 0},
421         {208, 0, 0},
422         {212, 0, 0},
423         {216, 0, 0},
424 };
425
426 static const uint32 lcnphy_23bitgaincode_table[] = {
427         0x200100,
428         0x200200,
429         0x200004,
430         0x200014,
431         0x200024,
432         0x200034,
433         0x200134,
434         0x200234,
435         0x200334,
436         0x200434,
437         0x200037,
438         0x200137,
439         0x200237,
440         0x200337,
441         0x200437,
442         0x000035,
443         0x000135,
444         0x000235,
445         0x000037,
446         0x000137,
447         0x000237,
448         0x000337,
449         0x00013f,
450         0x00023f,
451         0x00033f,
452         0x00034f,
453         0x00044f,
454         0x00144f,
455         0x00244f,
456         0x00254f,
457         0x00354f,
458         0x00454f,
459         0x00464f,
460         0x01464f,
461         0x02464f,
462         0x03464f,
463         0x04464f,
464 };
465
466 static const s8 lcnphy_gain_table[] = {
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
506 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
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
547 extern const u8 spur_tbl_rev0[];
548 extern const uint32 dot11lcnphytbl_rx_gain_info_sz_rev1;
549 extern const dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
550 extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
551 extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
552
553 typedef struct _chan_info_2064_lcnphy {
554         uint chan;
555         uint freq;
556         u8 logen_buftune;
557         u8 logen_rccr_tx;
558         u8 txrf_mix_tune_ctrl;
559         u8 pa_input_tune_g;
560         u8 logen_rccr_rx;
561         u8 pa_rxrf_lna1_freq_tune;
562         u8 pa_rxrf_lna2_freq_tune;
563         u8 rxrf_rxrf_spare1;
564 } chan_info_2064_lcnphy_t;
565
566 static chan_info_2064_lcnphy_t chan_info_2064_lcnphy[] = {
567         {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568         {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569         {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570         {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571         {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572         {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573         {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574         {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575         {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
576         {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577         {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
578         {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
579         {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
580         {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
581 };
582
583 lcnphy_radio_regs_t lcnphy_radio_regs_2064[] = {
584         {0x00, 0, 0, 0, 0},
585         {0x01, 0x64, 0x64, 0, 0},
586         {0x02, 0x20, 0x20, 0, 0},
587         {0x03, 0x66, 0x66, 0, 0},
588         {0x04, 0xf8, 0xf8, 0, 0},
589         {0x05, 0, 0, 0, 0},
590         {0x06, 0x10, 0x10, 0, 0},
591         {0x07, 0, 0, 0, 0},
592         {0x08, 0, 0, 0, 0},
593         {0x09, 0, 0, 0, 0},
594         {0x0A, 0x37, 0x37, 0, 0},
595         {0x0B, 0x6, 0x6, 0, 0},
596         {0x0C, 0x55, 0x55, 0, 0},
597         {0x0D, 0x8b, 0x8b, 0, 0},
598         {0x0E, 0, 0, 0, 0},
599         {0x0F, 0x5, 0x5, 0, 0},
600         {0x10, 0, 0, 0, 0},
601         {0x11, 0xe, 0xe, 0, 0},
602         {0x12, 0, 0, 0, 0},
603         {0x13, 0xb, 0xb, 0, 0},
604         {0x14, 0x2, 0x2, 0, 0},
605         {0x15, 0x12, 0x12, 0, 0},
606         {0x16, 0x12, 0x12, 0, 0},
607         {0x17, 0xc, 0xc, 0, 0},
608         {0x18, 0xc, 0xc, 0, 0},
609         {0x19, 0xc, 0xc, 0, 0},
610         {0x1A, 0x8, 0x8, 0, 0},
611         {0x1B, 0x2, 0x2, 0, 0},
612         {0x1C, 0, 0, 0, 0},
613         {0x1D, 0x1, 0x1, 0, 0},
614         {0x1E, 0x12, 0x12, 0, 0},
615         {0x1F, 0x6e, 0x6e, 0, 0},
616         {0x20, 0x2, 0x2, 0, 0},
617         {0x21, 0x23, 0x23, 0, 0},
618         {0x22, 0x8, 0x8, 0, 0},
619         {0x23, 0, 0, 0, 0},
620         {0x24, 0, 0, 0, 0},
621         {0x25, 0xc, 0xc, 0, 0},
622         {0x26, 0x33, 0x33, 0, 0},
623         {0x27, 0x55, 0x55, 0, 0},
624         {0x28, 0, 0, 0, 0},
625         {0x29, 0x30, 0x30, 0, 0},
626         {0x2A, 0xb, 0xb, 0, 0},
627         {0x2B, 0x1b, 0x1b, 0, 0},
628         {0x2C, 0x3, 0x3, 0, 0},
629         {0x2D, 0x1b, 0x1b, 0, 0},
630         {0x2E, 0, 0, 0, 0},
631         {0x2F, 0x20, 0x20, 0, 0},
632         {0x30, 0xa, 0xa, 0, 0},
633         {0x31, 0, 0, 0, 0},
634         {0x32, 0x62, 0x62, 0, 0},
635         {0x33, 0x19, 0x19, 0, 0},
636         {0x34, 0x33, 0x33, 0, 0},
637         {0x35, 0x77, 0x77, 0, 0},
638         {0x36, 0, 0, 0, 0},
639         {0x37, 0x70, 0x70, 0, 0},
640         {0x38, 0x3, 0x3, 0, 0},
641         {0x39, 0xf, 0xf, 0, 0},
642         {0x3A, 0x6, 0x6, 0, 0},
643         {0x3B, 0xcf, 0xcf, 0, 0},
644         {0x3C, 0x1a, 0x1a, 0, 0},
645         {0x3D, 0x6, 0x6, 0, 0},
646         {0x3E, 0x42, 0x42, 0, 0},
647         {0x3F, 0, 0, 0, 0},
648         {0x40, 0xfb, 0xfb, 0, 0},
649         {0x41, 0x9a, 0x9a, 0, 0},
650         {0x42, 0x7a, 0x7a, 0, 0},
651         {0x43, 0x29, 0x29, 0, 0},
652         {0x44, 0, 0, 0, 0},
653         {0x45, 0x8, 0x8, 0, 0},
654         {0x46, 0xce, 0xce, 0, 0},
655         {0x47, 0x27, 0x27, 0, 0},
656         {0x48, 0x62, 0x62, 0, 0},
657         {0x49, 0x6, 0x6, 0, 0},
658         {0x4A, 0x58, 0x58, 0, 0},
659         {0x4B, 0xf7, 0xf7, 0, 0},
660         {0x4C, 0, 0, 0, 0},
661         {0x4D, 0xb3, 0xb3, 0, 0},
662         {0x4E, 0, 0, 0, 0},
663         {0x4F, 0x2, 0x2, 0, 0},
664         {0x50, 0, 0, 0, 0},
665         {0x51, 0x9, 0x9, 0, 0},
666         {0x52, 0x5, 0x5, 0, 0},
667         {0x53, 0x17, 0x17, 0, 0},
668         {0x54, 0x38, 0x38, 0, 0},
669         {0x55, 0, 0, 0, 0},
670         {0x56, 0, 0, 0, 0},
671         {0x57, 0xb, 0xb, 0, 0},
672         {0x58, 0, 0, 0, 0},
673         {0x59, 0, 0, 0, 0},
674         {0x5A, 0, 0, 0, 0},
675         {0x5B, 0, 0, 0, 0},
676         {0x5C, 0, 0, 0, 0},
677         {0x5D, 0, 0, 0, 0},
678         {0x5E, 0x88, 0x88, 0, 0},
679         {0x5F, 0xcc, 0xcc, 0, 0},
680         {0x60, 0x74, 0x74, 0, 0},
681         {0x61, 0x74, 0x74, 0, 0},
682         {0x62, 0x74, 0x74, 0, 0},
683         {0x63, 0x44, 0x44, 0, 0},
684         {0x64, 0x77, 0x77, 0, 0},
685         {0x65, 0x44, 0x44, 0, 0},
686         {0x66, 0x77, 0x77, 0, 0},
687         {0x67, 0x55, 0x55, 0, 0},
688         {0x68, 0x77, 0x77, 0, 0},
689         {0x69, 0x77, 0x77, 0, 0},
690         {0x6A, 0, 0, 0, 0},
691         {0x6B, 0x7f, 0x7f, 0, 0},
692         {0x6C, 0x8, 0x8, 0, 0},
693         {0x6D, 0, 0, 0, 0},
694         {0x6E, 0x88, 0x88, 0, 0},
695         {0x6F, 0x66, 0x66, 0, 0},
696         {0x70, 0x66, 0x66, 0, 0},
697         {0x71, 0x28, 0x28, 0, 0},
698         {0x72, 0x55, 0x55, 0, 0},
699         {0x73, 0x4, 0x4, 0, 0},
700         {0x74, 0, 0, 0, 0},
701         {0x75, 0, 0, 0, 0},
702         {0x76, 0, 0, 0, 0},
703         {0x77, 0x1, 0x1, 0, 0},
704         {0x78, 0xd6, 0xd6, 0, 0},
705         {0x79, 0, 0, 0, 0},
706         {0x7A, 0, 0, 0, 0},
707         {0x7B, 0, 0, 0, 0},
708         {0x7C, 0, 0, 0, 0},
709         {0x7D, 0, 0, 0, 0},
710         {0x7E, 0, 0, 0, 0},
711         {0x7F, 0, 0, 0, 0},
712         {0x80, 0, 0, 0, 0},
713         {0x81, 0, 0, 0, 0},
714         {0x82, 0, 0, 0, 0},
715         {0x83, 0xb4, 0xb4, 0, 0},
716         {0x84, 0x1, 0x1, 0, 0},
717         {0x85, 0x20, 0x20, 0, 0},
718         {0x86, 0x5, 0x5, 0, 0},
719         {0x87, 0xff, 0xff, 0, 0},
720         {0x88, 0x7, 0x7, 0, 0},
721         {0x89, 0x77, 0x77, 0, 0},
722         {0x8A, 0x77, 0x77, 0, 0},
723         {0x8B, 0x77, 0x77, 0, 0},
724         {0x8C, 0x77, 0x77, 0, 0},
725         {0x8D, 0x8, 0x8, 0, 0},
726         {0x8E, 0xa, 0xa, 0, 0},
727         {0x8F, 0x8, 0x8, 0, 0},
728         {0x90, 0x18, 0x18, 0, 0},
729         {0x91, 0x5, 0x5, 0, 0},
730         {0x92, 0x1f, 0x1f, 0, 0},
731         {0x93, 0x10, 0x10, 0, 0},
732         {0x94, 0x3, 0x3, 0, 0},
733         {0x95, 0, 0, 0, 0},
734         {0x96, 0, 0, 0, 0},
735         {0x97, 0xaa, 0xaa, 0, 0},
736         {0x98, 0, 0, 0, 0},
737         {0x99, 0x23, 0x23, 0, 0},
738         {0x9A, 0x7, 0x7, 0, 0},
739         {0x9B, 0xf, 0xf, 0, 0},
740         {0x9C, 0x10, 0x10, 0, 0},
741         {0x9D, 0x3, 0x3, 0, 0},
742         {0x9E, 0x4, 0x4, 0, 0},
743         {0x9F, 0x20, 0x20, 0, 0},
744         {0xA0, 0, 0, 0, 0},
745         {0xA1, 0, 0, 0, 0},
746         {0xA2, 0, 0, 0, 0},
747         {0xA3, 0, 0, 0, 0},
748         {0xA4, 0x1, 0x1, 0, 0},
749         {0xA5, 0x77, 0x77, 0, 0},
750         {0xA6, 0x77, 0x77, 0, 0},
751         {0xA7, 0x77, 0x77, 0, 0},
752         {0xA8, 0x77, 0x77, 0, 0},
753         {0xA9, 0x8c, 0x8c, 0, 0},
754         {0xAA, 0x88, 0x88, 0, 0},
755         {0xAB, 0x78, 0x78, 0, 0},
756         {0xAC, 0x57, 0x57, 0, 0},
757         {0xAD, 0x88, 0x88, 0, 0},
758         {0xAE, 0, 0, 0, 0},
759         {0xAF, 0x8, 0x8, 0, 0},
760         {0xB0, 0x88, 0x88, 0, 0},
761         {0xB1, 0, 0, 0, 0},
762         {0xB2, 0x1b, 0x1b, 0, 0},
763         {0xB3, 0x3, 0x3, 0, 0},
764         {0xB4, 0x24, 0x24, 0, 0},
765         {0xB5, 0x3, 0x3, 0, 0},
766         {0xB6, 0x1b, 0x1b, 0, 0},
767         {0xB7, 0x24, 0x24, 0, 0},
768         {0xB8, 0x3, 0x3, 0, 0},
769         {0xB9, 0, 0, 0, 0},
770         {0xBA, 0xaa, 0xaa, 0, 0},
771         {0xBB, 0, 0, 0, 0},
772         {0xBC, 0x4, 0x4, 0, 0},
773         {0xBD, 0, 0, 0, 0},
774         {0xBE, 0x8, 0x8, 0, 0},
775         {0xBF, 0x11, 0x11, 0, 0},
776         {0xC0, 0, 0, 0, 0},
777         {0xC1, 0, 0, 0, 0},
778         {0xC2, 0x62, 0x62, 0, 0},
779         {0xC3, 0x1e, 0x1e, 0, 0},
780         {0xC4, 0x33, 0x33, 0, 0},
781         {0xC5, 0x37, 0x37, 0, 0},
782         {0xC6, 0, 0, 0, 0},
783         {0xC7, 0x70, 0x70, 0, 0},
784         {0xC8, 0x1e, 0x1e, 0, 0},
785         {0xC9, 0x6, 0x6, 0, 0},
786         {0xCA, 0x4, 0x4, 0, 0},
787         {0xCB, 0x2f, 0x2f, 0, 0},
788         {0xCC, 0xf, 0xf, 0, 0},
789         {0xCD, 0, 0, 0, 0},
790         {0xCE, 0xff, 0xff, 0, 0},
791         {0xCF, 0x8, 0x8, 0, 0},
792         {0xD0, 0x3f, 0x3f, 0, 0},
793         {0xD1, 0x3f, 0x3f, 0, 0},
794         {0xD2, 0x3f, 0x3f, 0, 0},
795         {0xD3, 0, 0, 0, 0},
796         {0xD4, 0, 0, 0, 0},
797         {0xD5, 0, 0, 0, 0},
798         {0xD6, 0xcc, 0xcc, 0, 0},
799         {0xD7, 0, 0, 0, 0},
800         {0xD8, 0x8, 0x8, 0, 0},
801         {0xD9, 0x8, 0x8, 0, 0},
802         {0xDA, 0x8, 0x8, 0, 0},
803         {0xDB, 0x11, 0x11, 0, 0},
804         {0xDC, 0, 0, 0, 0},
805         {0xDD, 0x87, 0x87, 0, 0},
806         {0xDE, 0x88, 0x88, 0, 0},
807         {0xDF, 0x8, 0x8, 0, 0},
808         {0xE0, 0x8, 0x8, 0, 0},
809         {0xE1, 0x8, 0x8, 0, 0},
810         {0xE2, 0, 0, 0, 0},
811         {0xE3, 0, 0, 0, 0},
812         {0xE4, 0, 0, 0, 0},
813         {0xE5, 0xf5, 0xf5, 0, 0},
814         {0xE6, 0x30, 0x30, 0, 0},
815         {0xE7, 0x1, 0x1, 0, 0},
816         {0xE8, 0, 0, 0, 0},
817         {0xE9, 0xff, 0xff, 0, 0},
818         {0xEA, 0, 0, 0, 0},
819         {0xEB, 0, 0, 0, 0},
820         {0xEC, 0x22, 0x22, 0, 0},
821         {0xED, 0, 0, 0, 0},
822         {0xEE, 0, 0, 0, 0},
823         {0xEF, 0, 0, 0, 0},
824         {0xF0, 0x3, 0x3, 0, 0},
825         {0xF1, 0x1, 0x1, 0, 0},
826         {0xF2, 0, 0, 0, 0},
827         {0xF3, 0, 0, 0, 0},
828         {0xF4, 0, 0, 0, 0},
829         {0xF5, 0, 0, 0, 0},
830         {0xF6, 0, 0, 0, 0},
831         {0xF7, 0x6, 0x6, 0, 0},
832         {0xF8, 0, 0, 0, 0},
833         {0xF9, 0, 0, 0, 0},
834         {0xFA, 0x40, 0x40, 0, 0},
835         {0xFB, 0, 0, 0, 0},
836         {0xFC, 0x1, 0x1, 0, 0},
837         {0xFD, 0x80, 0x80, 0, 0},
838         {0xFE, 0x2, 0x2, 0, 0},
839         {0xFF, 0x10, 0x10, 0, 0},
840         {0x100, 0x2, 0x2, 0, 0},
841         {0x101, 0x1e, 0x1e, 0, 0},
842         {0x102, 0x1e, 0x1e, 0, 0},
843         {0x103, 0, 0, 0, 0},
844         {0x104, 0x1f, 0x1f, 0, 0},
845         {0x105, 0, 0x8, 0, 1},
846         {0x106, 0x2a, 0x2a, 0, 0},
847         {0x107, 0xf, 0xf, 0, 0},
848         {0x108, 0, 0, 0, 0},
849         {0x109, 0, 0, 0, 0},
850         {0x10A, 0, 0, 0, 0},
851         {0x10B, 0, 0, 0, 0},
852         {0x10C, 0, 0, 0, 0},
853         {0x10D, 0, 0, 0, 0},
854         {0x10E, 0, 0, 0, 0},
855         {0x10F, 0, 0, 0, 0},
856         {0x110, 0, 0, 0, 0},
857         {0x111, 0, 0, 0, 0},
858         {0x112, 0, 0, 0, 0},
859         {0x113, 0, 0, 0, 0},
860         {0x114, 0, 0, 0, 0},
861         {0x115, 0, 0, 0, 0},
862         {0x116, 0, 0, 0, 0},
863         {0x117, 0, 0, 0, 0},
864         {0x118, 0, 0, 0, 0},
865         {0x119, 0, 0, 0, 0},
866         {0x11A, 0, 0, 0, 0},
867         {0x11B, 0, 0, 0, 0},
868         {0x11C, 0x1, 0x1, 0, 0},
869         {0x11D, 0, 0, 0, 0},
870         {0x11E, 0, 0, 0, 0},
871         {0x11F, 0, 0, 0, 0},
872         {0x120, 0, 0, 0, 0},
873         {0x121, 0, 0, 0, 0},
874         {0x122, 0x80, 0x80, 0, 0},
875         {0x123, 0, 0, 0, 0},
876         {0x124, 0xf8, 0xf8, 0, 0},
877         {0x125, 0, 0, 0, 0},
878         {0x126, 0, 0, 0, 0},
879         {0x127, 0, 0, 0, 0},
880         {0x128, 0, 0, 0, 0},
881         {0x129, 0, 0, 0, 0},
882         {0x12A, 0, 0, 0, 0},
883         {0x12B, 0, 0, 0, 0},
884         {0x12C, 0, 0, 0, 0},
885         {0x12D, 0, 0, 0, 0},
886         {0x12E, 0, 0, 0, 0},
887         {0x12F, 0, 0, 0, 0},
888         {0x130, 0, 0, 0, 0},
889         {0xFFFF, 0, 0, 0, 0}
890 };
891
892 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
893 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
894
895 u16
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
927 u16
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), \
941                 (u16)(idx) << 0)
942
943 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
944         mod_phy_reg(pi, 0x4a5, \
945                 (0x7 << 8), \
946                 (u16)(npt) << 8)
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), \
970                 (u16)(target) << 0)
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
975 #define LCNPHY_IQLOCC_READ(val) ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
976 #define FIXED_TXPWR 78
977 #define LCNPHY_TEMPSENSE(val) ((int16)((val > 255) ? (val - 512) : val))
978
979 static uint32 wlc_lcnphy_qdiv_roundup(uint32 divident, uint32 divisor,
980                                       u8 precision);
981 static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
982                                                    u16 ext_lna, u16 trsw,
983                                                    u16 biq2, u16 biq1,
984                                                    u16 tia, u16 lna2,
985                                                    u16 lna1);
986 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
987 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain);
988 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
989 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0);
990 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
991 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
992 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
993 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
994 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
995 static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
996                                    lcnphy_txgains_t *target_gains);
997 static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, u16 num_samps,
998                                  u8 wait_time, lcnphy_iq_est_t *iq_est);
999 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps);
1000 static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
1001 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode);
1002 extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1003 extern void wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng,
1004                                 u8 rate, struct ether_addr *sa,
1005                                 uint32 wait_delay);
1006 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1007                                                     u8 channel);
1008
1009 static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1010                                           const lcnphy_tx_gain_tbl_entry *g);
1011
1012 static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
1013                                 u16 thresh, int16 *ptr, int mode);
1014 static int wlc_lcnphy_calc_floor(int16 coeff, int type);
1015 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1016                                         u16 *values_to_save);
1017 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1018                                                 u16 *values_to_save);
1019 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x,
1020                               int16 coeff_y);
1021 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1022 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1023                           int num_levels, int step_size_lg2);
1024 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
1025
1026 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
1027                                            chanspec_t chanspec);
1028 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1029 static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1030 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1031 static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1032 static void wlc_lcnphy_radio_init(phy_info_t *pi);
1033 static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1034 static void wlc_lcnphy_rcal(phy_info_t *pi);
1035 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1036 static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
1037                                          int16 filt_type);
1038 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b);
1039
1040 void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
1041 {
1042         wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1043 }
1044
1045 void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
1046 {
1047         wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1048 }
1049
1050 static void
1051 wlc_lcnphy_common_read_table(phy_info_t *pi, uint32 tbl_id,
1052                              const void *tbl_ptr, uint32 tbl_len,
1053                              uint32 tbl_width, uint32 tbl_offset)
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
1064 static void
1065 wlc_lcnphy_common_write_table(phy_info_t *pi, uint32 tbl_id,
1066                               const void *tbl_ptr, uint32 tbl_len,
1067                               uint32 tbl_width, uint32 tbl_offset)
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
1079 static uint32
1080 wlc_lcnphy_qdiv_roundup(uint32 dividend, uint32 divisor, u8 precision)
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
1107 static 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
1127 s8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1128 {
1129         s8 index;
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 =
1136                     (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1137                             / 2);
1138         else
1139                 index = pi_lcn->lcnphy_current_index;
1140         return index;
1141 }
1142
1143 static uint32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, u16 nsamples)
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
1152 void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
1153 {
1154         u16 afectrlovr, afectrlovrval;
1155         afectrlovr = read_phy_reg(pi, 0x43b);
1156         afectrlovrval = read_phy_reg(pi, 0x43c);
1157         if (channel != 0) {
1158                 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
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
1183 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
1184 {
1185         u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
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
1200 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
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
1219 void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
1220 {
1221         u8 channel = CHSPEC_CHANNEL(chanspec);
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
1256 static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, u16 dac_gain)
1257 {
1258         u16 dac_ctrl;
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
1267 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
1268 {
1269         u16 bit = bEnable ? 1 : 0;
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
1278 static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1279 {
1280         u16 pa_gain;
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
1289 static void
1290 wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
1291 {
1292         u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
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
1315 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0)
1316 {
1317         u16 m0m1 = (u16) m0 << 8;
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
1328 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
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
1351 typedef enum {
1352         LCNPHY_TSSI_PRE_PA,
1353         LCNPHY_TSSI_POST_PA,
1354         LCNPHY_TSSI_EXT
1355 } lcnphy_tssi_mode_t;
1356
1357 static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
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
1396 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1397 {
1398         u16 N1, N2, N3, N4, N5, N6, N;
1399         N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1400               >> 0);
1401         N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1402                    >> 12);
1403         N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1404               >> 0);
1405         N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1406                    >> 8);
1407         N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1408               >> 0);
1409         N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1410                    >> 8);
1411         N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1412         if (N < 1600)
1413                 N = 1600;
1414         return N;
1415 }
1416
1417 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1418 {
1419         u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
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
1461 static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
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
1575 void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
1576 {
1577         u16 tx_cnt, tx_total, npt;
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
1594 int32 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
1605 static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
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
1615 void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
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
1646 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, s8 index)
1647 {
1648         uint32 cck_offset[4] = { 22, 22, 22, 22 };
1649         uint32 ofdm_offset, reg_offset_cck;
1650         int i;
1651         u16 index2;
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
1692         index2 = (u16) (index * 2);
1693         mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1694
1695         mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1696
1697 }
1698
1699 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1700 {
1701         s8 index, delta_brd, delta_temp, new_index, tempcorrx;
1702         int16 manp, meas_temp, temp_diff;
1703         bool neg = 0;
1704         u16 temp;
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         }
1718         temp = (u16) wlc_lcnphy_tempsense(pi, 0);
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
1736         delta_temp = (s8) wlc_lcnphy_qdiv_roundup((uint32) (temp_diff * 192),
1737                                                     (uint32) (pi_lcn->
1738                                                               lcnphy_tempsense_slope
1739                                                               * 10), 0);
1740         if (neg)
1741                 delta_temp = -delta_temp;
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)
1747                 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
1748         else
1749                 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
1750         if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1751                 tempcorrx = 4;
1752         new_index =
1753             index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1754         new_index += tempcorrx;
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
1764 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, u16 mode)
1765 {
1766
1767         u16 current_mode = mode;
1768         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1769             mode == LCNPHY_TX_PWR_CTRL_HW)
1770                 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1771         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1772             mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1773                 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1774         return current_mode;
1775 }
1776
1777 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, u16 mode)
1778 {
1779         u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1780         s8 index;
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);
1827                         pi_lcn->lcnphy_current_index = (s8)
1828                             ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1829                 }
1830         }
1831 }
1832
1833 static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
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
1848 static void
1849 wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1850                        lcnphy_txgains_t *target_gains,
1851                        lcnphy_cal_mode_t cal_mode, bool keep_tone)
1852 {
1853
1854         lcnphy_txgains_t cal_gains, temp_gains;
1855         u16 hash;
1856         u8 band_idx;
1857         int j;
1858         u16 ncorr_override[5];
1859         u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1860                 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1861         };
1862
1863         u16 commands_fullcal[] = {
1864                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1865
1866         u16 commands_recal[] = {
1867                 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1868
1869         u16 command_nums_fullcal[] = {
1870                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1871
1872         u16 command_nums_recal[] = {
1873                 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1874         u16 *command_nums = command_nums_fullcal;
1875
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;
1879         bool tx_gain_override_old;
1880         lcnphy_txgains_t old_gains;
1881         uint i, n_cal_cmds = 0, n_cal_start = 0;
1882         u16 *values_to_save;
1883         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1884
1885         if (NORADIO_ENAB(pi->pubpi))
1886                 return;
1887
1888         values_to_save = MALLOC(pi->sh->osh, sizeof(u16) * 20);
1889         if (NULL == values_to_save) {
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,
1978                                       (const void *)
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,
1984                                       (const void *)lcnphy_iqcal_ir_gainladder,
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++) {
2000                 u16 zero_diq = 0;
2001                 u16 best_coeffs[11];
2002                 u16 command_num;
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);
2067         MFREE(pi->sh->osh, values_to_save, 20 * sizeof(u16));
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
2085 static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
2086 {
2087         bool suspend, tx_gain_override_old;
2088         lcnphy_txgains_t old_gains;
2089         phy_info_t *pi = (phy_info_t *) ppi;
2090         u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2091             idleTssi0_regvalue_2C;
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 =
2095             read_radio_reg(pi, RADIO_2064_REG007) & 1;
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;
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
2151 static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, u8 mode)
2152 {
2153         bool suspend;
2154         u16 save_txpwrCtrlEn;
2155         u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2156         u16 auxpga_vmid;
2157         phytbl_info_t tab;
2158         uint32 val;
2159         u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2160             save_reg112;
2161         u16 values_to_save[14];
2162         s8 index;
2163         int i;
2164         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2165         OSL_DELAY(999);
2166
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);
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 =
2260             (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
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
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);
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
2293 void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi)
2294 {
2295         lcnphy_txgains_t tx_gains;
2296         u8 bbmult;
2297         phytbl_info_t tab;
2298         int32 a1, b0, b1;
2299         int32 tssi, pwr, maxtargetpwr, mintargetpwr;
2300         bool suspend;
2301         phy_info_t *pi = (phy_info_t *) ppi;
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
2371 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2372 {
2373         u16 m0m1;
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
2383         return (u8) ((m0m1 & 0xff00) >> 8);
2384 }
2385
2386 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain)
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
2396 void
2397 wlc_lcnphy_get_radio_loft(phy_info_t *pi,
2398                           u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
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
2406 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
2407 {
2408         u16 dac_gain;
2409
2410         dac_gain = read_phy_reg(pi, 0x439) >> 0;
2411         gains->dac_gain = (dac_gain & 0x380) >> 7;
2412
2413         {
2414                 u16 rfgain0, rfgain1;
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
2425 void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, u16 a, u16 b)
2426 {
2427         phytbl_info_t tab;
2428         u16 iqcc[2];
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
2441 void wlc_lcnphy_set_tx_locc(phy_info_t *pi, u16 didq)
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
2453 void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
2454 {
2455         phytbl_info_t tab;
2456         u16 a, b;
2457         u8 bb_mult;
2458         uint32 bbmultiqcomp, txgain, locoeffs, rfpower;
2459         lcnphy_txgains_t gains;
2460         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2461
2462         ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2463
2464         pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
2465         pi_lcn->lcnphy_current_index = (u8) index;
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
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;
2486         wlc_lcnphy_set_tx_gain(pi, &gains);
2487         wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
2488
2489         bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
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
2496                 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
2497                 b = (u16) (bbmultiqcomp & 0x3ff);
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
2504                 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
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
2514 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
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
2524 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
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
2543 static void
2544 wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
2545                                        u16 trsw,
2546                                        u16 ext_lna,
2547                                        u16 biq2,
2548                                        u16 biq1,
2549                                        u16 tia, u16 lna2, u16 lna1)
2550 {
2551         u16 gain0_15, gain16_19;
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
2578 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
2579 {
2580         u16 ebit = enable ? 1 : 0;
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
2603 void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
2604 {
2605         if (!bEnable) {
2606
2607                 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
2608
2609                 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2610
2611                 and_phy_reg(pi, 0x44c,
2612                             ~(u16) ((0x1 << 3) |
2613                                        (0x1 << 5) |
2614                                        (0x1 << 12) |
2615                                        (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2616
2617                 and_phy_reg(pi, 0x44d,
2618                             ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
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,
2624                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2625
2626                 and_phy_reg(pi, 0x4fa,
2627                             ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
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
2680 static void
2681 wlc_lcnphy_run_samples(phy_info_t *pi,
2682                        u16 num_samps,
2683                        u16 num_loops, u16 wait, bool iqcalmode)
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
2697                 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
2698                 or_phy_reg(pi, 0x453, (0x1 << 15));
2699         } else {
2700                 write_phy_reg(pi, 0x63f, 1);
2701                 wlc_lcnphy_tx_pu(pi, 1);
2702         }
2703
2704         or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2705 }
2706
2707 void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
2708 {
2709
2710         u8 phybw40;
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
2731 void
2732 wlc_lcnphy_start_tx_tone(phy_info_t *pi, int32 f_kHz, u16 max_val,
2733                          bool iqcalmode)
2734 {
2735         u8 phy_bw;
2736         u16 num_samps, t, k;
2737         uint32 bw;
2738         fixed theta = 0, rot = 0;
2739         cint32 tone_samp;
2740         uint32 data_buf[64];
2741         u16 i_samp, q_samp;
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
2777                 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2778                 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
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
2796 void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
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
2827 static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
2828 {
2829
2830         and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
2831 }
2832
2833 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, u16 *a, u16 *b)
2834 {
2835         u16 iqcc[2];
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
2849 u16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2850 {
2851         phytbl_info_t tab;
2852         u16 didq;
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
2864 static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
2865 {
2866
2867         lcnphy_txgains_t target_gains, old_gains;
2868         u8 save_bb_mult;
2869         u16 a, b, didq, save_pa_gain = 0;
2870         uint idx, SAVE_txpwrindex = 0xFF;
2871         uint32 val;
2872         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2873         phytbl_info_t tab;
2874         u8 ei0, eq0, fi0, fq0;
2875         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
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);
2908         if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
2909                 if (CHSPEC_IS5G(pi->radio_chanspec)) {
2910                         target_gains.gm_gain = 255;
2911                         target_gains.pga_gain = 255;
2912                         target_gains.pad_gain = 0xf0;
2913                         target_gains.dac_gain = 0;
2914                 } else {
2915                         target_gains.gm_gain = 7;
2916                         target_gains.pga_gain = 45;
2917                         target_gains.pad_gain = 186;
2918                         target_gains.dac_gain = 0;
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
2978 int16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2979 {
2980         u16 tempsenseval1, tempsenseval2;
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
3023 u16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3024 {
3025         u16 tempsenseval1, tempsenseval2;
3026         int32 avg = 0;
3027         bool suspend = 0;
3028         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
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         }
3081         return (u16) avg;
3082 }
3083
3084 s8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
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;
3090         return (s8) degree;
3091 }
3092
3093 s8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3094 {
3095         u16 vbatsenseval;
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         }
3126         return (s8) avg;
3127 }
3128
3129 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode)
3130 {
3131         u8 phybw40;
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
3143 static bool
3144 wlc_lcnphy_rx_iq_est(phy_info_t *pi,
3145                      u16 num_samps,
3146                      u8 wait_time, lcnphy_iq_est_t *iq_est)
3147 {
3148         int wait_count = 0;
3149         bool result = TRUE;
3150         u8 phybw40;
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
3159         mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
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
3190 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps)
3191 {
3192 #define LCNPHY_MIN_RXIQ_PWR 2
3193         bool result;
3194         u16 a0_new, b0_new;
3195         lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3196         int32 a, b, temp;
3197         int16 iq_nbits, qq_nbits, arsh, brsh;
3198         int32 iq;
3199         uint32 ii, qq;
3200         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
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
3210         result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
3211         if (!result)
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);
3259         a0_new = (u16) (a & 0x3ff);
3260         b0_new = (u16) (b & 0x3ff);
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
3275 static bool
3276 wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
3277                      int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3278                      int tx_gain_idx)
3279 {
3280         lcnphy_txgains_t old_gains;
3281         u16 tx_pwr_ctrl;
3282         u8 tx_gain_index_old = 0;
3283         bool result = FALSE, tx_gain_override_old = FALSE;
3284         u16 i, Core1TxControl_old, RFOverride0_old,
3285             RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
3286             rfoverride3_old, rfoverride3val_old, rfoverride4_old,
3287             rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
3288         int tia_gain;
3289         uint32 received_power, rx_pwr_threshold;
3290         u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3291         u16 values_to_save[11];
3292         int16 *ptr;
3293         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3294
3295         ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
3296         if (NULL == ptr) {
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,
3307                                                           (u16)
3308                                                           iqcomp[iqcomp_sz].a,
3309                                                           (u16)
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,
3396                                                                (u16)
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
3447 static void wlc_lcnphy_temp_adj(phy_info_t *pi)
3448 {
3449         if (NORADIO_ENAB(pi->pubpi))
3450                 return;
3451 }
3452
3453 static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
3454 {
3455         bool suspend;
3456         s8 index;
3457         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3458         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3459         suspend =
3460             (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3461         if (!suspend)
3462                 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3463         wlc_lcnphy_deaf_mode(pi, TRUE);
3464         pi->phy_lastcal = pi->sh->now;
3465         pi->phy_forcecal = FALSE;
3466         index = pi_lcn->lcnphy_current_index;
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
3478 static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
3479 {
3480         bool suspend, full_cal;
3481         const lcnphy_rx_iqcomp_t *rx_iqcomp;
3482         int rx_iqcomp_sz;
3483         u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3484         s8 index;
3485         phytbl_info_t tab;
3486         int32 a1, b0, b1;
3487         int32 tssi, pwr, maxtargetpwr, mintargetpwr;
3488         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
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
3550 void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
3551 {
3552         u16 temp_new;
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
3592 void wlc_lcnphy_get_tssi(phy_info_t *pi, s8 *ofdm_pwr, s8 *cck_pwr)
3593 {
3594         s8 cck_offset;
3595         u16 status;
3596         status = (read_phy_reg(pi, 0x4ab));
3597         if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
3598             (status  & (0x1 << 15))) {
3599                 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
3600                                      >> 0) >> 1);
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
3614 void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi)
3615 {
3616         return;
3617
3618 }
3619
3620 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
3621 {
3622         u8 channel = CHSPEC_CHANNEL(chanspec);
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
3672 void
3673 wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng, u8 rate,
3674                     struct ether_addr *sa, uint32 wait_delay)
3675 {
3676 }
3677
3678 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3679 {
3680         s8 index;
3681         u16 index2;
3682         phy_info_t *pi = (phy_info_t *) ppi;
3683         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3684         u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3685         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3686                 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3687                 index2 = (u16) (index * 2);
3688                 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3689
3690                 pi_lcn->lcnphy_current_index = (s8)
3691                     ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3692         }
3693 }
3694
3695 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b)
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
3711 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3712 {
3713         u8 phybw40;
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
3760 static void
3761 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, u16 *values_to_save)
3762 {
3763         u16 vmid;
3764         int i;
3765         for (i = 0; i < 20; i++) {
3766                 values_to_save[i] =
3767                     read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
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
3853 static void
3854 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, u16 thresh,
3855                     int16 *ptr, int mode)
3856 {
3857         uint32 curval1, curval2, stpptr, curptr, strptr, val;
3858         u16 sslpnCalibClkEnCtrl, timer;
3859         u16 old_sslpnCalibClkEnCtrl;
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
3879         write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3880         write_phy_reg(pi, 0x5cf, 3);
3881         write_phy_reg(pi, 0x5a5, 0x3);
3882         write_phy_reg(pi, 0x583, 0x0);
3883         write_phy_reg(pi, 0x584, 0x0);
3884         write_phy_reg(pi, 0x585, 0x0fff);
3885         write_phy_reg(pi, 0x586, 0x0000);
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
3930 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
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
3952 static void
3953 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x, int16 coeff_y)
3954 {
3955         u16 di0dq0;
3956         u16 x, y, data_rf;
3957         int k;
3958         switch (cal_type) {
3959         case 0:
3960                 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3961                 break;
3962         case 2:
3963                 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3964                 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3965                 break;
3966         case 3:
3967                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3968                 y = 8 + k;
3969                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3970                 x = 8 - k;
3971                 data_rf = (x * 16 + y);
3972                 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3973                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3974                 y = 8 + k;
3975                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3976                 x = 8 - k;
3977                 data_rf = (x * 16 + y);
3978                 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3979                 break;
3980         case 4:
3981                 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3982                 y = 8 + k;
3983                 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3984                 x = 8 - k;
3985                 data_rf = (x * 16 + y);
3986                 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3987                 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3988                 y = 8 + k;
3989                 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3990                 x = 8 - k;
3991                 data_rf = (x * 16 + y);
3992                 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3993                 break;
3994         }
3995 }
3996
3997 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3998 {
3999         u16 a, b, didq;
4000         u8 di0, dq0, ei, eq, fi, fq;
4001         lcnphy_unsign16_struct cc;
4002         cc.re = 0;
4003         cc.im = 0;
4004         switch (cal_type) {
4005         case 0:
4006                 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
4007                 cc.re = a;
4008                 cc.im = b;
4009                 break;
4010         case 2:
4011                 didq = wlc_lcnphy_get_tx_locc(pi);
4012                 di0 = (((didq & 0xff00) << 16) >> 24);
4013                 dq0 = (((didq & 0x00ff) << 24) >> 24);
4014                 cc.re = (u16) di0;
4015                 cc.im = (u16) dq0;
4016                 break;
4017         case 3:
4018                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4019                 cc.re = (u16) ei;
4020                 cc.im = (u16) eq;
4021                 break;
4022         case 4:
4023                 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4024                 cc.re = (u16) fi;
4025                 cc.im = (u16) fq;
4026                 break;
4027         }
4028         return cc;
4029 }
4030
4031 static void
4032 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
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;
4038         u16 phy_c7, phy_c8, phy_c9;
4039         int16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4040         int16 *ptr, phy_c17;
4041         int32 phy_c18, phy_c19;
4042         uint32 phy_c20, phy_c21;
4043         bool phy_c22, phy_c23, phy_c24, phy_c25;
4044         u16 phy_c26, phy_c27;
4045         u16 phy_c28, phy_c29, phy_c30;
4046         u16 phy_c31;
4047         u16 *phy_c32;
4048         phy_c21 = 0;
4049         phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4050         ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
4051         if (NULL == ptr) {
4052                 return;
4053         }
4054
4055         phy_c32 = MALLOC(pi->sh->osh, sizeof(u16) * 20);
4056         if (NULL == phy_c32) {
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
4224         MFREE(pi->sh->osh, phy_c32, 20 * sizeof(u16));
4225         MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
4226 }
4227
4228 static void
4229 wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, u16 *values_to_save)
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
4243 static void
4244 WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
4245                                              const lcnphy_tx_gain_tbl_entry *
4246                                              gain_table) {
4247         uint32 j;
4248         phytbl_info_t tab;
4249         uint32 val;
4250         u16 pa_gain;
4251         u16 gm_gain;
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
4280 static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
4281 {
4282         phytbl_info_t tab;
4283         uint32 val, bbmult, rfgain;
4284         u8 index;
4285         u8 scale_factor = 1;
4286         int16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
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
4329 static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi)
4330 {
4331         uint idx;
4332         u8 phybw40;
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
4424 static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi)
4425 {
4426         u16 afectrl1;
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;
4451                 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4452                                      (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4453                                                                       lcnphy_rssi_gs
4454                                                                       << 10));
4455                 write_phy_reg(pi, 0x43e, afectrl1);
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
4471 static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi)
4472 {
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
4480 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
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;
4520         pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
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
4541 static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi)
4542 {
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
4596 static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi)
4597 {
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
4606 static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi)
4607 {
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),
4618                                         (u16) lcnphyregs[i].init_a);
4619                 else if (lcnphyregs[i].do_init_g)
4620                         write_radio_reg(pi,
4621                                         ((lcnphyregs[i].address & 0x3fff) |
4622                                          RADIO_DEFAULT_CORE),
4623                                         (u16) lcnphyregs[i].init_g);
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
4667 static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi)
4668 {
4669         if (NORADIO_ENAB(pi->pubpi))
4670                 return;
4671
4672         wlc_radio_2064_init(pi);
4673 }
4674
4675 static void wlc_lcnphy_rcal(phy_info_t *pi)
4676 {
4677         u8 rcal_value;
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)) {
4697                 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
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
4706 static void wlc_lcnphy_rc_cal(phy_info_t *pi)
4707 {
4708         u8 dflt_rc_cal_val;
4709         u16 flt_val;
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
4729 static bool BCMATTACHFN(wlc_phy_txpwr_srom_read_lcnphy) (phy_info_t *pi)
4730 {
4731         s8 txpwr = 0;
4732         int i;
4733         phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4734
4735         if (CHSPEC_IS2G(pi->radio_chanspec)) {
4736                 u16 cckpo = 0;
4737                 uint32 offset_ofdm, offset_mcs;
4738
4739                 pi_lcn->lcnphy_tr_isolation_mid =
4740                     (u8) PHY_GETINTVAR(pi, "triso2g");
4741
4742                 pi_lcn->lcnphy_rx_power_offset =
4743                     (u8) PHY_GETINTVAR(pi, "rxpo2g");
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
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");
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
4766                 txpwr = (s8) PHY_GETINTVAR(pi, "maxp2ga0");
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
4774                 cckpo = (u16) PHY_GETINTVAR(pi, "cck2gpo");
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 {
4791                         u8 opo = 0;
4792
4793                         opo = (u8) PHY_GETINTVAR(pi, "opo");
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 =
4807                             ((u16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4808                             (u16) PHY_GETINTVAR(pi, "mcs2gpo0");
4809                         pi_lcn->lcnphy_mcs20_po = offset_mcs;
4810                         for (i = TXP_FIRST_SISO_MCS_20;
4811                              i <= TXP_LAST_SISO_MCS_20; i++) {
4812                                 pi->tx_srom_max_rate_2g[i] =
4813                                     txpwr - ((offset_mcs & 0xf) * 2);
4814                                 offset_mcs >>= 4;
4815                         }
4816                 }
4817
4818                 pi_lcn->lcnphy_rawtempsense =
4819                     (u16) PHY_GETINTVAR(pi, "rawtempsense");
4820                 pi_lcn->lcnphy_measPower =
4821                     (u8) PHY_GETINTVAR(pi, "measpower");
4822                 pi_lcn->lcnphy_tempsense_slope =
4823                     (u8) PHY_GETINTVAR(pi, "tempsense_slope");
4824                 pi_lcn->lcnphy_hw_iqcal_en =
4825                     (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
4826                 pi_lcn->lcnphy_iqcal_swp_dis =
4827                     (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
4828                 pi_lcn->lcnphy_tempcorrx =
4829                     (u8) PHY_GETINTVAR(pi, "tempcorrx");
4830                 pi_lcn->lcnphy_tempsense_option =
4831                     (u8) PHY_GETINTVAR(pi, "tempsense_option");
4832                 pi_lcn->lcnphy_freqoffset_corr =
4833                     (u8) PHY_GETINTVAR(pi, "freqoffset_corr");
4834                 if ((u8) getintvar(pi->vars, "aa2g") > 1)
4835                         wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
4836                                               (u8) getintvar(pi->vars,
4837                                                                 "aa2g"));
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
4851 void wlc_2064_vco_cal(phy_info_t *pi)
4852 {
4853         u8 calnrst;
4854
4855         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4856         calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4857         write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4858         OSL_DELAY(1);
4859         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4860         OSL_DELAY(1);
4861         write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4862         OSL_DELAY(300);
4863         mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4864 }
4865
4866 static void
4867 wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, u8 channel)
4868 {
4869         uint i;
4870         const chan_info_2064_lcnphy_t *ci;
4871         u8 rfpll_doubler = 0;
4872         u8 pll_pwrup, pll_pwrup_ovr;
4873         fixed qFxtal, qFref, qFvco, qFcal;
4874         u8 d15, d16, f16, e44, e45;
4875         uint32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
4876         u16 loop_bw, d30, setCount;
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
4923         pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
4924         pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
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),
4963                       (u8) (setCount >> 8));
4964
4965         or_radio_reg(pi, RADIO_2064_REG053, 0x10);
4966         write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
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),
4978                       (u8) (div_int >> 4));
4979         mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
4980                       (u8) (div_int << 4));
4981         mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
4982                       (u8) (div_frac >> 16));
4983         write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
4984         write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
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         {
4993                 u8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
4994                 u16 c29, c38, c30, g30, d28;
4995                 c29 = loop_bw;
4996                 d29 = 200;
4997                 c38 = 1250;
4998                 h29 = d29 / c29;
4999                 h23 = 1;
5000                 c28 = 30;
5001                 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
5002                         (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
5003                        (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
5004                     + PLL_2064_LOW_END_KVCO;
5005                 h28_ten = (d28 * 10) / c28;
5006                 c30 = 2640;
5007                 e30 = (d30 - 680) / 490;
5008                 g30 = 680 + (e30 * 490);
5009                 h30_ten = (g30 * 10) / c30;
5010                 cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
5011                 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
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
5032 bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
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
5041 void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
5042 {
5043         u16 pwr_ctrl;
5044         if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5045                 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5046         } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
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
5057 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5058 {
5059         MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5060 }
5061
5062 bool wlc_phy_attach_lcnphy(phy_info_t *pi)
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
5114 static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, uint32 gain)
5115 {
5116         u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5117
5118         trsw = (gain & ((uint32) 1 << 28)) ? 0 : 1;
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) |
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
5144 static uint32 wlc_lcnphy_get_receive_power(phy_info_t *pi, int32 *gain_index)
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
5180 int32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, int32 gain_index)
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
5251 static int
5252 wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, int16 filt_type)
5253 {
5254         int16 filt_index = -1;
5255         int j;
5256
5257         u16 addr[] = {
5258                 0x910,
5259                 0x91e,
5260                 0x91f,
5261                 0x924,
5262                 0x925,
5263                 0x926,
5264                 0x920,
5265                 0x921,
5266                 0x927,
5267                 0x928,
5268                 0x929,
5269                 0x922,
5270                 0x923,
5271                 0x930,
5272                 0x931,
5273                 0x932
5274         };
5275
5276         u16 addr_ofdm[] = {
5277                 0x90f,
5278                 0x900,
5279                 0x901,
5280                 0x906,
5281                 0x907,
5282                 0x908,
5283                 0x902,
5284                 0x903,
5285                 0x909,
5286                 0x90a,
5287                 0x90b,
5288                 0x904,
5289                 0x905,
5290                 0x90c,
5291                 0x90d,
5292                 0x90e
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 }