Staging: brcm80211: remove FALSE #define
[GitHub/mt8127/android_kernel_alcatel_ttab.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 <linux/bitops.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 s16 a;
169 s16 b;
170 } lcnphy_rx_iqcomp_t;
171
172 typedef struct {
173 s16 re;
174 s16 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 u32 iq_prod;
184 u32 i_pwr;
185 u32 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 u32 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 u32 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) ((s16)((val > 255) ? (val - 512) : val))
978
979 static u32 wlc_lcnphy_qdiv_roundup(u32 divident, u32 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 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1004 u8 channel);
1005
1006 static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1007 const lcnphy_tx_gain_tbl_entry *g);
1008
1009 static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
1010 u16 thresh, s16 *ptr, int mode);
1011 static int wlc_lcnphy_calc_floor(s16 coeff, int type);
1012 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1013 u16 *values_to_save);
1014 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1015 u16 *values_to_save);
1016 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, s16 coeff_x,
1017 s16 coeff_y);
1018 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1019 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1020 int num_levels, int step_size_lg2);
1021 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
1022
1023 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
1024 chanspec_t chanspec);
1025 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1026 static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1027 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1028 static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1029 static void wlc_lcnphy_radio_init(phy_info_t *pi);
1030 static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1031 static void wlc_lcnphy_rcal(phy_info_t *pi);
1032 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1033 static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
1034 s16 filt_type);
1035 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b);
1036
1037 void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
1038 {
1039 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1040 }
1041
1042 void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
1043 {
1044 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1045 }
1046
1047 static void
1048 wlc_lcnphy_common_read_table(phy_info_t *pi, u32 tbl_id,
1049 const void *tbl_ptr, u32 tbl_len,
1050 u32 tbl_width, u32 tbl_offset)
1051 {
1052 phytbl_info_t tab;
1053 tab.tbl_id = tbl_id;
1054 tab.tbl_ptr = tbl_ptr;
1055 tab.tbl_len = tbl_len;
1056 tab.tbl_width = tbl_width;
1057 tab.tbl_offset = tbl_offset;
1058 wlc_lcnphy_read_table(pi, &tab);
1059 }
1060
1061 static void
1062 wlc_lcnphy_common_write_table(phy_info_t *pi, u32 tbl_id,
1063 const void *tbl_ptr, u32 tbl_len,
1064 u32 tbl_width, u32 tbl_offset)
1065 {
1066
1067 phytbl_info_t tab;
1068 tab.tbl_id = tbl_id;
1069 tab.tbl_ptr = tbl_ptr;
1070 tab.tbl_len = tbl_len;
1071 tab.tbl_width = tbl_width;
1072 tab.tbl_offset = tbl_offset;
1073 wlc_lcnphy_write_table(pi, &tab);
1074 }
1075
1076 static u32
1077 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1078 {
1079 u32 quotient, remainder, roundup, rbit;
1080
1081 ASSERT(divisor);
1082
1083 quotient = dividend / divisor;
1084 remainder = dividend % divisor;
1085 rbit = divisor & 1;
1086 roundup = (divisor >> 1) + rbit;
1087
1088 while (precision--) {
1089 quotient <<= 1;
1090 if (remainder >= roundup) {
1091 quotient++;
1092 remainder = ((remainder - roundup) << 1) + rbit;
1093 } else {
1094 remainder <<= 1;
1095 }
1096 }
1097
1098 if (remainder >= roundup)
1099 quotient++;
1100
1101 return quotient;
1102 }
1103
1104 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1105 {
1106 int k;
1107 k = 0;
1108 if (type == 0) {
1109 if (coeff_x < 0) {
1110 k = (coeff_x - 1) / 2;
1111 } else {
1112 k = coeff_x / 2;
1113 }
1114 }
1115 if (type == 1) {
1116 if ((coeff_x + 1) < 0)
1117 k = (coeff_x) / 2;
1118 else
1119 k = (coeff_x + 1) / 2;
1120 }
1121 return k;
1122 }
1123
1124 s8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1125 {
1126 s8 index;
1127 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1128
1129 if (txpwrctrl_off(pi))
1130 index = pi_lcn->lcnphy_current_index;
1131 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1132 index =
1133 (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1134 / 2);
1135 else
1136 index = pi_lcn->lcnphy_current_index;
1137 return index;
1138 }
1139
1140 static u32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, u16 nsamples)
1141 {
1142 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
1143
1144 if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1145 return 0;
1146 return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1147 }
1148
1149 void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
1150 {
1151 u16 afectrlovr, afectrlovrval;
1152 afectrlovr = read_phy_reg(pi, 0x43b);
1153 afectrlovrval = read_phy_reg(pi, 0x43c);
1154 if (channel != 0) {
1155 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1156
1157 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1158
1159 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1160
1161 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1162
1163 write_phy_reg(pi, 0x44b, 0xffff);
1164 wlc_lcnphy_tx_pu(pi, 1);
1165
1166 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1167
1168 or_phy_reg(pi, 0x6da, 0x0080);
1169
1170 or_phy_reg(pi, 0x00a, 0x228);
1171 } else {
1172 and_phy_reg(pi, 0x00a, ~(0x228));
1173
1174 and_phy_reg(pi, 0x6da, 0xFF7F);
1175 write_phy_reg(pi, 0x43b, afectrlovr);
1176 write_phy_reg(pi, 0x43c, afectrlovrval);
1177 }
1178 }
1179
1180 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
1181 {
1182 u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1183
1184 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1185 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1186
1187 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1188 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1189
1190 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1191 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1192
1193 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1194 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1195 }
1196
1197 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
1198 {
1199 if (enable) {
1200 write_phy_reg(pi, 0x942, 0x7);
1201 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1202 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1203
1204 write_phy_reg(pi, 0x44a, 0x084);
1205 write_phy_reg(pi, 0x44a, 0x080);
1206 write_phy_reg(pi, 0x6d3, 0x2222);
1207 write_phy_reg(pi, 0x6d3, 0x2220);
1208 } else {
1209 write_phy_reg(pi, 0x942, 0x0);
1210 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1211 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1212 }
1213 wlapi_switch_macfreq(pi->sh->physhim, enable);
1214 }
1215
1216 void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
1217 {
1218 u8 channel = CHSPEC_CHANNEL(chanspec);
1219
1220 wlc_phy_chanspec_radio_set((wlc_phy_t *) pi, chanspec);
1221
1222 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1223
1224 or_phy_reg(pi, 0x44a, 0x44);
1225 write_phy_reg(pi, 0x44a, 0x80);
1226
1227 if (!NORADIO_ENAB(pi->pubpi)) {
1228 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1229 OSL_DELAY(1000);
1230 }
1231
1232 wlc_lcnphy_toggle_afe_pwdn(pi);
1233
1234 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1235 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1236
1237 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1238 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1239
1240 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
1241 } else {
1242 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1243
1244 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
1245 }
1246
1247 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
1248
1249 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1250
1251 }
1252
1253 static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, u16 dac_gain)
1254 {
1255 u16 dac_ctrl;
1256
1257 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1258 dac_ctrl = dac_ctrl & 0xc7f;
1259 dac_ctrl = dac_ctrl | (dac_gain << 7);
1260 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1261
1262 }
1263
1264 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
1265 {
1266 u16 bit = bEnable ? 1 : 0;
1267
1268 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1269
1270 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1271
1272 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1273 }
1274
1275 static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1276 {
1277 u16 pa_gain;
1278
1279 pa_gain = (read_phy_reg(pi, 0x4fb) &
1280 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1281 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1282
1283 return pa_gain;
1284 }
1285
1286 static void
1287 wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
1288 {
1289 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1290
1291 mod_phy_reg(pi, 0x4b5,
1292 (0xffff << 0),
1293 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1294 0);
1295 mod_phy_reg(pi, 0x4fb,
1296 (0x7fff << 0),
1297 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1298
1299 mod_phy_reg(pi, 0x4fc,
1300 (0xffff << 0),
1301 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1302 0);
1303 mod_phy_reg(pi, 0x4fd,
1304 (0x7fff << 0),
1305 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1306
1307 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1308
1309 wlc_lcnphy_enable_tx_gain_override(pi);
1310 }
1311
1312 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0)
1313 {
1314 u16 m0m1 = (u16) m0 << 8;
1315 phytbl_info_t tab;
1316
1317 tab.tbl_ptr = &m0m1;
1318 tab.tbl_len = 1;
1319 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1320 tab.tbl_offset = 87;
1321 tab.tbl_width = 16;
1322 wlc_lcnphy_write_table(pi, &tab);
1323 }
1324
1325 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
1326 {
1327 u32 data_buf[64];
1328 phytbl_info_t tab;
1329
1330 bzero(data_buf, sizeof(data_buf));
1331
1332 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1333 tab.tbl_width = 32;
1334 tab.tbl_ptr = data_buf;
1335
1336 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1337
1338 tab.tbl_len = 30;
1339 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1340 wlc_lcnphy_write_table(pi, &tab);
1341 }
1342
1343 tab.tbl_len = 64;
1344 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1345 wlc_lcnphy_write_table(pi, &tab);
1346 }
1347
1348 typedef enum {
1349 LCNPHY_TSSI_PRE_PA,
1350 LCNPHY_TSSI_POST_PA,
1351 LCNPHY_TSSI_EXT
1352 } lcnphy_tssi_mode_t;
1353
1354 static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
1355 {
1356 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1357
1358 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1359
1360 if (LCNPHY_TSSI_POST_PA == pos) {
1361 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1362
1363 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1364
1365 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1366 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1367 } else {
1368 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1369 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1370 }
1371 } else {
1372 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1373
1374 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1375
1376 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1377 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1378 } else {
1379 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
1380 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1381 }
1382 }
1383 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1384
1385 if (LCNPHY_TSSI_EXT == pos) {
1386 write_radio_reg(pi, RADIO_2064_REG07F, 1);
1387 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
1388 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
1389 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
1390 }
1391 }
1392
1393 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1394 {
1395 u16 N1, N2, N3, N4, N5, N6, N;
1396 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1397 >> 0);
1398 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1399 >> 12);
1400 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1401 >> 0);
1402 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1403 >> 8);
1404 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1405 >> 0);
1406 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1407 >> 8);
1408 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1409 if (N < 1600)
1410 N = 1600;
1411 return N;
1412 }
1413
1414 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1415 {
1416 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
1417 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1418
1419 auxpga_vmid =
1420 (2 << 8) | (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
1421 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
1422 auxpga_gain_temp = 2;
1423
1424 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
1425
1426 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
1427
1428 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
1429
1430 mod_phy_reg(pi, 0x4db,
1431 (0x3ff << 0) |
1432 (0x7 << 12),
1433 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1434
1435 mod_phy_reg(pi, 0x4dc,
1436 (0x3ff << 0) |
1437 (0x7 << 12),
1438 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1439
1440 mod_phy_reg(pi, 0x40a,
1441 (0x3ff << 0) |
1442 (0x7 << 12),
1443 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1444
1445 mod_phy_reg(pi, 0x40b,
1446 (0x3ff << 0) |
1447 (0x7 << 12),
1448 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1449
1450 mod_phy_reg(pi, 0x40c,
1451 (0x3ff << 0) |
1452 (0x7 << 12),
1453 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1454
1455 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
1456 }
1457
1458 static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
1459 {
1460 phytbl_info_t tab;
1461 u32 rfseq, ind;
1462
1463 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1464 tab.tbl_width = 32;
1465 tab.tbl_ptr = &ind;
1466 tab.tbl_len = 1;
1467 tab.tbl_offset = 0;
1468 for (ind = 0; ind < 128; ind++) {
1469 wlc_lcnphy_write_table(pi, &tab);
1470 tab.tbl_offset++;
1471 }
1472 tab.tbl_offset = 704;
1473 for (ind = 0; ind < 128; ind++) {
1474 wlc_lcnphy_write_table(pi, &tab);
1475 tab.tbl_offset++;
1476 }
1477 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
1478
1479 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
1480
1481 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
1482
1483 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
1484 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
1485
1486 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
1487
1488 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
1489
1490 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
1491
1492 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
1493
1494 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
1495
1496 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
1497
1498 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
1499
1500 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
1501
1502 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
1503
1504 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
1505
1506 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
1507
1508 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
1509
1510 wlc_lcnphy_clear_tx_power_offsets(pi);
1511
1512 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
1513
1514 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
1515
1516 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
1517
1518 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1519 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
1520 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1521 } else {
1522 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1523 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
1524 }
1525
1526 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
1527
1528 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1529 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1530 } else {
1531 if (CHSPEC_IS2G(pi->radio_chanspec))
1532 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1533 else
1534 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
1535 }
1536
1537 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
1538 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1539 else
1540 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
1541
1542 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
1543
1544 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
1545
1546 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1547 mod_phy_reg(pi, 0x4d7,
1548 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
1549 }
1550
1551 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
1552 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
1553 tab.tbl_width = 16;
1554 tab.tbl_ptr = &rfseq;
1555 tab.tbl_len = 1;
1556 tab.tbl_offset = 6;
1557 wlc_lcnphy_write_table(pi, &tab);
1558
1559 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
1560
1561 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
1562
1563 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1564
1565 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
1566
1567 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
1568
1569 wlc_lcnphy_pwrctrl_rssiparams(pi);
1570 }
1571
1572 void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
1573 {
1574 u16 tx_cnt, tx_total, npt;
1575 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1576
1577 tx_total = wlc_lcnphy_total_tx_frames(pi);
1578 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
1579 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
1580
1581 if (tx_cnt > (1 << npt)) {
1582
1583 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
1584
1585 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
1586 pi_lcn->lcnphy_tssi_npt = npt;
1587
1588 }
1589 }
1590
1591 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
1592 {
1593 s32 a, b, p;
1594
1595 a = 32768 + (a1 * tssi);
1596 b = (1024 * b0) + (64 * b1 * tssi);
1597 p = ((2 * b) + a) / (2 * a);
1598
1599 return p;
1600 }
1601
1602 static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
1603 {
1604 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1605 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1606 return;
1607
1608 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
1609 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
1610 }
1611
1612 void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
1613 {
1614 phytbl_info_t tab;
1615 u32 rate_table[WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM +
1616 WLC_NUM_RATES_MCS_1_STREAM];
1617 uint i, j;
1618 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1619 return;
1620
1621 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
1622
1623 if (i == WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM)
1624 j = TXP_FIRST_MCS_20_SISO;
1625
1626 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
1627 }
1628
1629 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1630 tab.tbl_width = 32;
1631 tab.tbl_len = ARRAY_SIZE(rate_table);
1632 tab.tbl_ptr = rate_table;
1633 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1634 wlc_lcnphy_write_table(pi, &tab);
1635
1636 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
1637 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
1638
1639 wlc_lcnphy_txpower_reset_npt(pi);
1640 }
1641 }
1642
1643 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, s8 index)
1644 {
1645 u32 cck_offset[4] = { 22, 22, 22, 22 };
1646 u32 ofdm_offset, reg_offset_cck;
1647 int i;
1648 u16 index2;
1649 phytbl_info_t tab;
1650
1651 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1652 return;
1653
1654 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1655
1656 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
1657
1658 or_phy_reg(pi, 0x6da, 0x0040);
1659
1660 reg_offset_cck = 0;
1661 for (i = 0; i < 4; i++)
1662 cck_offset[i] -= reg_offset_cck;
1663 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1664 tab.tbl_width = 32;
1665 tab.tbl_len = 4;
1666 tab.tbl_ptr = cck_offset;
1667 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1668 wlc_lcnphy_write_table(pi, &tab);
1669 ofdm_offset = 0;
1670 tab.tbl_len = 1;
1671 tab.tbl_ptr = &ofdm_offset;
1672 for (i = 836; i < 862; i++) {
1673 tab.tbl_offset = i;
1674 wlc_lcnphy_write_table(pi, &tab);
1675 }
1676
1677 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
1678
1679 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1680
1681 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
1682
1683 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
1684
1685 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
1686
1687 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
1688
1689 index2 = (u16) (index * 2);
1690 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1691
1692 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1693
1694 }
1695
1696 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1697 {
1698 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
1699 s16 manp, meas_temp, temp_diff;
1700 bool neg = 0;
1701 u16 temp;
1702 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1703
1704 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1705 return pi_lcn->lcnphy_current_index;
1706
1707 index = FIXED_TXPWR;
1708
1709 if (NORADIO_ENAB(pi->pubpi))
1710 return index;
1711
1712 if (pi_lcn->lcnphy_tempsense_slope == 0) {
1713 return index;
1714 }
1715 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
1716 meas_temp = LCNPHY_TEMPSENSE(temp);
1717
1718 if (pi->tx_power_min != 0) {
1719 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
1720 } else {
1721 delta_brd = 0;
1722 }
1723
1724 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
1725 temp_diff = manp - meas_temp;
1726 if (temp_diff < 0) {
1727
1728 neg = 1;
1729
1730 temp_diff = -temp_diff;
1731 }
1732
1733 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
1734 (u32) (pi_lcn->
1735 lcnphy_tempsense_slope
1736 * 10), 0);
1737 if (neg)
1738 delta_temp = -delta_temp;
1739
1740 if (pi_lcn->lcnphy_tempsense_option == 3
1741 && LCNREV_IS(pi->pubpi.phy_rev, 0))
1742 delta_temp = 0;
1743 if (pi_lcn->lcnphy_tempcorrx > 31)
1744 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
1745 else
1746 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
1747 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1748 tempcorrx = 4;
1749 new_index =
1750 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1751 new_index += tempcorrx;
1752
1753 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1754 index = 127;
1755 if (new_index < 0 || new_index > 126) {
1756 return index;
1757 }
1758 return new_index;
1759 }
1760
1761 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, u16 mode)
1762 {
1763
1764 u16 current_mode = mode;
1765 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1766 mode == LCNPHY_TX_PWR_CTRL_HW)
1767 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1768 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1769 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1770 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1771 return current_mode;
1772 }
1773
1774 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, u16 mode)
1775 {
1776 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1777 s8 index;
1778 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1779
1780 ASSERT((LCNPHY_TX_PWR_CTRL_OFF == mode) ||
1781 (LCNPHY_TX_PWR_CTRL_SW == mode) ||
1782 (LCNPHY_TX_PWR_CTRL_HW == mode) ||
1783 (LCNPHY_TX_PWR_CTRL_TEMPBASED == mode));
1784
1785 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
1786 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
1787
1788 mod_phy_reg(pi, 0x6da, (0x1 << 6),
1789 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
1790
1791 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
1792 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
1793
1794 if (old_mode != mode) {
1795 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
1796
1797 wlc_lcnphy_tx_pwr_update_npt(pi);
1798
1799 wlc_lcnphy_clear_tx_power_offsets(pi);
1800 }
1801 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
1802
1803 wlc_lcnphy_txpower_recalc_target(pi);
1804
1805 wlc_lcnphy_set_start_tx_pwr_idx(pi,
1806 pi_lcn->
1807 lcnphy_tssi_idx);
1808 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
1809 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
1810
1811 pi_lcn->lcnphy_tssi_tx_cnt =
1812 wlc_lcnphy_total_tx_frames(pi);
1813
1814 wlc_lcnphy_disable_tx_gain_override(pi);
1815 pi_lcn->lcnphy_tx_power_idx_override = -1;
1816 } else
1817 wlc_lcnphy_enable_tx_gain_override(pi);
1818
1819 mod_phy_reg(pi, 0x4a4,
1820 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
1821 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
1822 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
1823 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
1824 pi_lcn->lcnphy_current_index = (s8)
1825 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1826 }
1827 }
1828 }
1829
1830 static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
1831 {
1832 uint delay_count = 0;
1833
1834 while (wlc_lcnphy_iqcal_active(pi)) {
1835 OSL_DELAY(100);
1836 delay_count++;
1837
1838 if (delay_count > (10 * 500))
1839 break;
1840 }
1841
1842 return (0 == wlc_lcnphy_iqcal_active(pi));
1843 }
1844
1845 static void
1846 wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1847 lcnphy_txgains_t *target_gains,
1848 lcnphy_cal_mode_t cal_mode, bool keep_tone)
1849 {
1850
1851 lcnphy_txgains_t cal_gains, temp_gains;
1852 u16 hash;
1853 u8 band_idx;
1854 int j;
1855 u16 ncorr_override[5];
1856 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1857 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1858 };
1859
1860 u16 commands_fullcal[] = {
1861 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1862
1863 u16 commands_recal[] = {
1864 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1865
1866 u16 command_nums_fullcal[] = {
1867 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1868
1869 u16 command_nums_recal[] = {
1870 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1871 u16 *command_nums = command_nums_fullcal;
1872
1873 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1874 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1875 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
1876 bool tx_gain_override_old;
1877 lcnphy_txgains_t old_gains;
1878 uint i, n_cal_cmds = 0, n_cal_start = 0;
1879 u16 *values_to_save;
1880 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1881
1882 if (NORADIO_ENAB(pi->pubpi))
1883 return;
1884
1885 values_to_save = MALLOC(pi->sh->osh, sizeof(u16) * 20);
1886 if (NULL == values_to_save) {
1887 return;
1888 }
1889
1890 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1891 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1892
1893 or_phy_reg(pi, 0x6da, 0x40);
1894 or_phy_reg(pi, 0x6db, 0x3);
1895
1896 switch (cal_mode) {
1897 case LCNPHY_CAL_FULL:
1898 start_coeffs = syst_coeffs;
1899 cal_cmds = commands_fullcal;
1900 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
1901 break;
1902
1903 case LCNPHY_CAL_RECAL:
1904 ASSERT(pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid);
1905
1906 start_coeffs = syst_coeffs;
1907
1908 cal_cmds = commands_recal;
1909 n_cal_cmds = ARRAY_SIZE(commands_recal);
1910 command_nums = command_nums_recal;
1911 break;
1912 default:
1913 ASSERT(false);
1914 }
1915
1916 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1917 start_coeffs, 11, 16, 64);
1918
1919 write_phy_reg(pi, 0x6da, 0xffff);
1920 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
1921
1922 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1923
1924 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1925
1926 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1927
1928 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
1929
1930 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
1931
1932 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
1933
1934 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
1935
1936 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1937 if (tx_gain_override_old)
1938 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1939
1940 if (!target_gains) {
1941 if (!tx_gain_override_old)
1942 wlc_lcnphy_set_tx_pwr_by_index(pi,
1943 pi_lcn->lcnphy_tssi_idx);
1944 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
1945 target_gains = &temp_gains;
1946 }
1947
1948 hash = (target_gains->gm_gain << 8) |
1949 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
1950
1951 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
1952
1953 cal_gains = *target_gains;
1954 bzero(ncorr_override, sizeof(ncorr_override));
1955 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
1956 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
1957 cal_gains.gm_gain =
1958 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
1959 cal_gains.pga_gain =
1960 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
1961 cal_gains.pad_gain =
1962 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
1963 bcopy(&tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
1964 ncorr_override, sizeof(ncorr_override));
1965 break;
1966 }
1967 }
1968
1969 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
1970
1971 write_phy_reg(pi, 0x453, 0xaa9);
1972 write_phy_reg(pi, 0x93d, 0xc0);
1973
1974 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1975 (const void *)
1976 lcnphy_iqcal_loft_gainladder,
1977 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
1978 16, 0);
1979
1980 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1981 (const void *)lcnphy_iqcal_ir_gainladder,
1982 ARRAY_SIZE(lcnphy_iqcal_ir_gainladder), 16,
1983 32);
1984
1985 if (pi->phy_tx_tone_freq) {
1986
1987 wlc_lcnphy_stop_tx_tone(pi);
1988 OSL_DELAY(5);
1989 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1990 } else {
1991 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1992 }
1993
1994 write_phy_reg(pi, 0x6da, 0xffff);
1995
1996 for (i = n_cal_start; i < n_cal_cmds; i++) {
1997 u16 zero_diq = 0;
1998 u16 best_coeffs[11];
1999 u16 command_num;
2000
2001 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2002
2003 command_num = command_nums[i];
2004 if (ncorr_override[cal_type])
2005 command_num =
2006 ncorr_override[cal_type] << 8 | (command_num &
2007 0xff);
2008
2009 write_phy_reg(pi, 0x452, command_num);
2010
2011 if ((cal_type == 3) || (cal_type == 4)) {
2012
2013 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2014 &diq_start, 1, 16, 69);
2015
2016 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2017 &zero_diq, 1, 16, 69);
2018 }
2019
2020 write_phy_reg(pi, 0x451, cal_cmds[i]);
2021
2022 if (!wlc_lcnphy_iqcal_wait(pi)) {
2023
2024 goto cleanup;
2025 }
2026
2027 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2028 best_coeffs,
2029 ARRAY_SIZE(best_coeffs), 16, 96);
2030 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2031 best_coeffs,
2032 ARRAY_SIZE(best_coeffs), 16, 64);
2033
2034 if ((cal_type == 3) || (cal_type == 4)) {
2035 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2036 &diq_start, 1, 16, 69);
2037 }
2038 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2039 pi_lcn->lcnphy_cal_results.
2040 txiqlocal_bestcoeffs,
2041 ARRAY_SIZE(pi_lcn->
2042 lcnphy_cal_results.
2043 txiqlocal_bestcoeffs),
2044 16, 96);
2045 }
2046
2047 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2048 pi_lcn->lcnphy_cal_results.
2049 txiqlocal_bestcoeffs,
2050 ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2051 txiqlocal_bestcoeffs), 16, 96);
2052 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2053
2054 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2055 &pi_lcn->lcnphy_cal_results.
2056 txiqlocal_bestcoeffs[0], 4, 16, 80);
2057
2058 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2059 &pi_lcn->lcnphy_cal_results.
2060 txiqlocal_bestcoeffs[5], 2, 16, 85);
2061
2062 cleanup:
2063 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2064 MFREE(pi->sh->osh, values_to_save, 20 * sizeof(u16));
2065
2066 if (!keep_tone)
2067 wlc_lcnphy_stop_tx_tone(pi);
2068
2069 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2070
2071 write_phy_reg(pi, 0x453, 0);
2072
2073 if (tx_gain_override_old)
2074 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2075 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2076
2077 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2078 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2079
2080 }
2081
2082 static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
2083 {
2084 bool suspend, tx_gain_override_old;
2085 lcnphy_txgains_t old_gains;
2086 phy_info_t *pi = (phy_info_t *) ppi;
2087 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2088 idleTssi0_regvalue_2C;
2089 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2090 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2091 u16 SAVE_jtag_bb_afe_switch =
2092 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2093 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2094 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2095 idleTssi = read_phy_reg(pi, 0x4ab);
2096 suspend =
2097 (0 ==
2098 (R_REG(pi->sh->osh, &((phy_info_t *) pi)->regs->maccontrol) &
2099 MCTL_EN_MAC));
2100 if (!suspend)
2101 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2102 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2103
2104 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2105 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2106
2107 wlc_lcnphy_enable_tx_gain_override(pi);
2108 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2109 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2110 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2111 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2112 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2113 wlc_lcnphy_tssi_setup(pi);
2114 wlc_phy_do_dummy_tx(pi, true, OFF);
2115 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2116 >> 0);
2117
2118 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2119 >> 0);
2120
2121 if (idleTssi0_2C >= 256)
2122 idleTssi0_OB = idleTssi0_2C - 256;
2123 else
2124 idleTssi0_OB = idleTssi0_2C + 256;
2125
2126 idleTssi0_regvalue_OB = idleTssi0_OB;
2127 if (idleTssi0_regvalue_OB >= 256)
2128 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2129 else
2130 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2131 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2132
2133 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2134
2135 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2136 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2137 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2138
2139 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2140 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2141 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2142 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2143 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2144 if (!suspend)
2145 wlapi_enable_mac(pi->sh->physhim);
2146 }
2147
2148 static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, u8 mode)
2149 {
2150 bool suspend;
2151 u16 save_txpwrCtrlEn;
2152 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2153 u16 auxpga_vmid;
2154 phytbl_info_t tab;
2155 u32 val;
2156 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2157 save_reg112;
2158 u16 values_to_save[14];
2159 s8 index;
2160 int i;
2161 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2162 OSL_DELAY(999);
2163
2164 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2165 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2166 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2167 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2168 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2169 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2170
2171 for (i = 0; i < 14; i++)
2172 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2173 suspend =
2174 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2175 if (!suspend)
2176 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2177 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2178
2179 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2180 index = pi_lcn->lcnphy_current_index;
2181 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2182 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2183 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2184 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2185 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2186
2187 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2188
2189 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2190
2191 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2192
2193 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2194
2195 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2196
2197 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2198
2199 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2200
2201 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2202
2203 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2204
2205 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2206
2207 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2208
2209 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2210
2211 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2212
2213 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2214
2215 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2216
2217 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2218
2219 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2220
2221 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2222
2223 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2224
2225 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2226
2227 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2228
2229 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2230
2231 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2232 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2233 tab.tbl_width = 16;
2234 tab.tbl_len = 1;
2235 tab.tbl_ptr = &val;
2236 tab.tbl_offset = 6;
2237 wlc_lcnphy_write_table(pi, &tab);
2238 if (mode == TEMPSENSE) {
2239 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2240
2241 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2242
2243 auxpga_vmidcourse = 8;
2244 auxpga_vmidfine = 0x4;
2245 auxpga_gain = 2;
2246 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2247 } else {
2248 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2249
2250 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2251
2252 auxpga_vmidcourse = 7;
2253 auxpga_vmidfine = 0xa;
2254 auxpga_gain = 2;
2255 }
2256 auxpga_vmid =
2257 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2258 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2259
2260 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2261
2262 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2263
2264 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2265
2266 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2267
2268 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2269
2270 wlc_phy_do_dummy_tx(pi, true, OFF);
2271 if (!tempsense_done(pi))
2272 OSL_DELAY(10);
2273
2274 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2275 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2276 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2277 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2278 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2279 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
2280 for (i = 0; i < 14; i++)
2281 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2282 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
2283
2284 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
2285 if (!suspend)
2286 wlapi_enable_mac(pi->sh->physhim);
2287 OSL_DELAY(999);
2288 }
2289
2290 void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi)
2291 {
2292 lcnphy_txgains_t tx_gains;
2293 u8 bbmult;
2294 phytbl_info_t tab;
2295 s32 a1, b0, b1;
2296 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
2297 bool suspend;
2298 phy_info_t *pi = (phy_info_t *) ppi;
2299
2300 suspend =
2301 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2302 if (!suspend)
2303 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2304
2305 if (NORADIO_ENAB(pi->pubpi)) {
2306 wlc_lcnphy_set_bbmult(pi, 0x30);
2307 if (!suspend)
2308 wlapi_enable_mac(pi->sh->physhim);
2309 return;
2310 }
2311
2312 if (!pi->hwpwrctrl_capable) {
2313 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2314 tx_gains.gm_gain = 4;
2315 tx_gains.pga_gain = 12;
2316 tx_gains.pad_gain = 12;
2317 tx_gains.dac_gain = 0;
2318
2319 bbmult = 150;
2320 } else {
2321 tx_gains.gm_gain = 7;
2322 tx_gains.pga_gain = 15;
2323 tx_gains.pad_gain = 14;
2324 tx_gains.dac_gain = 0;
2325
2326 bbmult = 150;
2327 }
2328 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
2329 wlc_lcnphy_set_bbmult(pi, bbmult);
2330 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2331 } else {
2332
2333 wlc_lcnphy_idle_tssi_est(ppi);
2334
2335 wlc_lcnphy_clear_tx_power_offsets(pi);
2336
2337 b0 = pi->txpa_2g[0];
2338 b1 = pi->txpa_2g[1];
2339 a1 = pi->txpa_2g[2];
2340 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
2341 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
2342
2343 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2344 tab.tbl_width = 32;
2345 tab.tbl_ptr = &pwr;
2346 tab.tbl_len = 1;
2347 tab.tbl_offset = 0;
2348 for (tssi = 0; tssi < 128; tssi++) {
2349 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
2350
2351 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
2352 wlc_lcnphy_write_table(pi, &tab);
2353 tab.tbl_offset++;
2354 }
2355
2356 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
2357
2358 write_phy_reg(pi, 0x4a8, 10);
2359
2360 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
2361
2362 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
2363 }
2364 if (!suspend)
2365 wlapi_enable_mac(pi->sh->physhim);
2366 }
2367
2368 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2369 {
2370 u16 m0m1;
2371 phytbl_info_t tab;
2372
2373 tab.tbl_ptr = &m0m1;
2374 tab.tbl_len = 1;
2375 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2376 tab.tbl_offset = 87;
2377 tab.tbl_width = 16;
2378 wlc_lcnphy_read_table(pi, &tab);
2379
2380 return (u8) ((m0m1 & 0xff00) >> 8);
2381 }
2382
2383 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain)
2384 {
2385 mod_phy_reg(pi, 0x4fb,
2386 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
2387 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
2388 mod_phy_reg(pi, 0x4fd,
2389 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
2390 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
2391 }
2392
2393 void
2394 wlc_lcnphy_get_radio_loft(phy_info_t *pi,
2395 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
2396 {
2397 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
2398 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
2399 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
2400 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
2401 }
2402
2403 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
2404 {
2405 u16 dac_gain;
2406
2407 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2408 gains->dac_gain = (dac_gain & 0x380) >> 7;
2409
2410 {
2411 u16 rfgain0, rfgain1;
2412
2413 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
2414 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
2415
2416 gains->gm_gain = rfgain0 & 0xff;
2417 gains->pga_gain = (rfgain0 >> 8) & 0xff;
2418 gains->pad_gain = rfgain1 & 0xff;
2419 }
2420 }
2421
2422 void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, u16 a, u16 b)
2423 {
2424 phytbl_info_t tab;
2425 u16 iqcc[2];
2426
2427 iqcc[0] = a;
2428 iqcc[1] = b;
2429
2430 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2431 tab.tbl_width = 16;
2432 tab.tbl_ptr = iqcc;
2433 tab.tbl_len = 2;
2434 tab.tbl_offset = 80;
2435 wlc_lcnphy_write_table(pi, &tab);
2436 }
2437
2438 void wlc_lcnphy_set_tx_locc(phy_info_t *pi, u16 didq)
2439 {
2440 phytbl_info_t tab;
2441
2442 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2443 tab.tbl_width = 16;
2444 tab.tbl_ptr = &didq;
2445 tab.tbl_len = 1;
2446 tab.tbl_offset = 85;
2447 wlc_lcnphy_write_table(pi, &tab);
2448 }
2449
2450 void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
2451 {
2452 phytbl_info_t tab;
2453 u16 a, b;
2454 u8 bb_mult;
2455 u32 bbmultiqcomp, txgain, locoeffs, rfpower;
2456 lcnphy_txgains_t gains;
2457 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2458
2459 ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2460
2461 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
2462 pi_lcn->lcnphy_current_index = (u8) index;
2463
2464 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2465 tab.tbl_width = 32;
2466 tab.tbl_len = 1;
2467
2468 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2469
2470 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
2471 tab.tbl_ptr = &bbmultiqcomp;
2472 wlc_lcnphy_read_table(pi, &tab);
2473
2474 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
2475 tab.tbl_width = 32;
2476 tab.tbl_ptr = &txgain;
2477 wlc_lcnphy_read_table(pi, &tab);
2478
2479 gains.gm_gain = (u16) (txgain & 0xff);
2480 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
2481 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
2482 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
2483 wlc_lcnphy_set_tx_gain(pi, &gains);
2484 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
2485
2486 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
2487 wlc_lcnphy_set_bbmult(pi, bb_mult);
2488
2489 wlc_lcnphy_enable_tx_gain_override(pi);
2490
2491 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2492
2493 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
2494 b = (u16) (bbmultiqcomp & 0x3ff);
2495 wlc_lcnphy_set_tx_iqcc(pi, a, b);
2496
2497 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
2498 tab.tbl_ptr = &locoeffs;
2499 wlc_lcnphy_read_table(pi, &tab);
2500
2501 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
2502
2503 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
2504 tab.tbl_ptr = &rfpower;
2505 wlc_lcnphy_read_table(pi, &tab);
2506 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
2507
2508 }
2509 }
2510
2511 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
2512 {
2513
2514 mod_phy_reg(pi, 0x44d,
2515 (0x1 << 1) |
2516 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
2517
2518 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
2519 }
2520
2521 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
2522 {
2523 u32 j;
2524 phytbl_info_t tab;
2525 u32 temp_offset[128];
2526 tab.tbl_ptr = temp_offset;
2527 tab.tbl_len = 128;
2528 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
2529 tab.tbl_width = 32;
2530 tab.tbl_offset = 0;
2531
2532 bzero(temp_offset, sizeof(temp_offset));
2533 for (j = 1; j < 128; j += 2)
2534 temp_offset[j] = 0x80000;
2535
2536 wlc_lcnphy_write_table(pi, &tab);
2537 return;
2538 }
2539
2540 static void
2541 wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
2542 u16 trsw,
2543 u16 ext_lna,
2544 u16 biq2,
2545 u16 biq1,
2546 u16 tia, u16 lna2, u16 lna1)
2547 {
2548 u16 gain0_15, gain16_19;
2549
2550 gain16_19 = biq2 & 0xf;
2551 gain0_15 = ((biq1 & 0xf) << 12) |
2552 ((tia & 0xf) << 8) |
2553 ((lna2 & 0x3) << 6) |
2554 ((lna2 & 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
2555
2556 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
2557 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
2558 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
2559
2560 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2561 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2562 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
2563 } else {
2564 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
2565
2566 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
2567
2568 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2569 }
2570
2571 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
2572
2573 }
2574
2575 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
2576 {
2577 u16 ebit = enable ? 1 : 0;
2578
2579 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
2580
2581 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
2582
2583 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2584 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
2585 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
2586 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2587 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
2588 } else {
2589 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
2590 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
2591 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2592 }
2593
2594 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2595 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
2596 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
2597 }
2598 }
2599
2600 void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
2601 {
2602 if (!bEnable) {
2603
2604 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
2605
2606 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2607
2608 and_phy_reg(pi, 0x44c,
2609 ~(u16) ((0x1 << 3) |
2610 (0x1 << 5) |
2611 (0x1 << 12) |
2612 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2613
2614 and_phy_reg(pi, 0x44d,
2615 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
2616 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
2617
2618 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
2619
2620 and_phy_reg(pi, 0x4f9,
2621 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2622
2623 and_phy_reg(pi, 0x4fa,
2624 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2625 } else {
2626
2627 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2628 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2629
2630 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
2631 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
2632
2633 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2634 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2635
2636 wlc_lcnphy_set_trsw_override(pi, true, false);
2637
2638 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
2639 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
2640
2641 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2642
2643 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2644 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
2645
2646 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2647 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
2648
2649 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2650 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
2651
2652 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2653 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
2654
2655 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2656 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
2657 } else {
2658
2659 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2660 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
2661
2662 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2663 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
2664
2665 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2666 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
2667
2668 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2669 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
2670
2671 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2672 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
2673 }
2674 }
2675 }
2676
2677 static void
2678 wlc_lcnphy_run_samples(phy_info_t *pi,
2679 u16 num_samps,
2680 u16 num_loops, u16 wait, bool iqcalmode)
2681 {
2682
2683 or_phy_reg(pi, 0x6da, 0x8080);
2684
2685 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
2686 if (num_loops != 0xffff)
2687 num_loops--;
2688 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
2689
2690 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
2691
2692 if (iqcalmode) {
2693
2694 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
2695 or_phy_reg(pi, 0x453, (0x1 << 15));
2696 } else {
2697 write_phy_reg(pi, 0x63f, 1);
2698 wlc_lcnphy_tx_pu(pi, 1);
2699 }
2700
2701 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2702 }
2703
2704 void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
2705 {
2706
2707 u8 phybw40;
2708 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
2709
2710 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2711 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2712 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2713 } else {
2714 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2715 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2716 }
2717
2718 if (phybw40 == 0) {
2719 mod_phy_reg((pi), 0x410,
2720 (0x1 << 6) |
2721 (0x1 << 5),
2722 ((CHSPEC_IS2G(pi->radio_chanspec)) ? (!mode) : 0) <<
2723 6 | (!mode) << 5);
2724 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
2725 }
2726 }
2727
2728 void
2729 wlc_lcnphy_start_tx_tone(phy_info_t *pi, s32 f_kHz, u16 max_val,
2730 bool iqcalmode)
2731 {
2732 u8 phy_bw;
2733 u16 num_samps, t, k;
2734 u32 bw;
2735 fixed theta = 0, rot = 0;
2736 cs32 tone_samp;
2737 u32 data_buf[64];
2738 u16 i_samp, q_samp;
2739 phytbl_info_t tab;
2740 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2741
2742 pi->phy_tx_tone_freq = f_kHz;
2743
2744 wlc_lcnphy_deaf_mode(pi, true);
2745
2746 phy_bw = 40;
2747 if (pi_lcn->lcnphy_spurmod) {
2748 write_phy_reg(pi, 0x942, 0x2);
2749 write_phy_reg(pi, 0x93b, 0x0);
2750 write_phy_reg(pi, 0x93c, 0x0);
2751 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
2752 }
2753
2754 if (f_kHz) {
2755 k = 1;
2756 do {
2757 bw = phy_bw * 1000 * k;
2758 num_samps = bw / ABS(f_kHz);
2759 ASSERT(num_samps <= ARRAY_SIZE(data_buf));
2760 k++;
2761 } while ((num_samps * (u32) (ABS(f_kHz))) != bw);
2762 } else
2763 num_samps = 2;
2764
2765 rot = FIXED((f_kHz * 36) / phy_bw) / 100;
2766 theta = 0;
2767
2768 for (t = 0; t < num_samps; t++) {
2769
2770 wlc_phy_cordic(theta, &tone_samp);
2771
2772 theta += rot;
2773
2774 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2775 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
2776 data_buf[t] = (i_samp << 10) | q_samp;
2777 }
2778
2779 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
2780
2781 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
2782
2783 tab.tbl_ptr = data_buf;
2784 tab.tbl_len = num_samps;
2785 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
2786 tab.tbl_offset = 0;
2787 tab.tbl_width = 32;
2788 wlc_lcnphy_write_table(pi, &tab);
2789
2790 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
2791 }
2792
2793 void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
2794 {
2795 s16 playback_status;
2796 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2797
2798 pi->phy_tx_tone_freq = 0;
2799 if (pi_lcn->lcnphy_spurmod) {
2800 write_phy_reg(pi, 0x942, 0x7);
2801 write_phy_reg(pi, 0x93b, 0x2017);
2802 write_phy_reg(pi, 0x93c, 0x27c5);
2803 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
2804 }
2805
2806 playback_status = read_phy_reg(pi, 0x644);
2807 if (playback_status & (0x1 << 0)) {
2808 wlc_lcnphy_tx_pu(pi, 0);
2809 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
2810 } else if (playback_status & (0x1 << 1))
2811 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
2812
2813 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
2814
2815 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
2816
2817 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
2818
2819 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
2820
2821 wlc_lcnphy_deaf_mode(pi, false);
2822 }
2823
2824 static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
2825 {
2826
2827 and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
2828 }
2829
2830 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, u16 *a, u16 *b)
2831 {
2832 u16 iqcc[2];
2833 phytbl_info_t tab;
2834
2835 tab.tbl_ptr = iqcc;
2836 tab.tbl_len = 2;
2837 tab.tbl_id = 0;
2838 tab.tbl_offset = 80;
2839 tab.tbl_width = 16;
2840 wlc_lcnphy_read_table(pi, &tab);
2841
2842 *a = iqcc[0];
2843 *b = iqcc[1];
2844 }
2845
2846 u16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2847 {
2848 phytbl_info_t tab;
2849 u16 didq;
2850
2851 tab.tbl_id = 0;
2852 tab.tbl_width = 16;
2853 tab.tbl_ptr = &didq;
2854 tab.tbl_len = 1;
2855 tab.tbl_offset = 85;
2856 wlc_lcnphy_read_table(pi, &tab);
2857
2858 return didq;
2859 }
2860
2861 static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
2862 {
2863
2864 lcnphy_txgains_t target_gains, old_gains;
2865 u8 save_bb_mult;
2866 u16 a, b, didq, save_pa_gain = 0;
2867 uint idx, SAVE_txpwrindex = 0xFF;
2868 u32 val;
2869 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2870 phytbl_info_t tab;
2871 u8 ei0, eq0, fi0, fq0;
2872 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2873
2874 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2875 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
2876
2877 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
2878
2879 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
2880 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2881
2882 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2883
2884 target_gains.gm_gain = 7;
2885 target_gains.pga_gain = 0;
2886 target_gains.pad_gain = 21;
2887 target_gains.dac_gain = 0;
2888 wlc_lcnphy_set_tx_gain(pi, &target_gains);
2889 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2890
2891 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
2892
2893 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
2894
2895 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2896 (pi_lcn->
2897 lcnphy_recal ? LCNPHY_CAL_RECAL :
2898 LCNPHY_CAL_FULL), false);
2899 } else {
2900
2901 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2902 }
2903
2904 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
2905 if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
2906 if (CHSPEC_IS5G(pi->radio_chanspec)) {
2907 target_gains.gm_gain = 255;
2908 target_gains.pga_gain = 255;
2909 target_gains.pad_gain = 0xf0;
2910 target_gains.dac_gain = 0;
2911 } else {
2912 target_gains.gm_gain = 7;
2913 target_gains.pga_gain = 45;
2914 target_gains.pad_gain = 186;
2915 target_gains.dac_gain = 0;
2916 }
2917
2918 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
2919 || pi_lcn->lcnphy_hw_iqcal_en) {
2920
2921 target_gains.pga_gain = 0;
2922 target_gains.pad_gain = 30;
2923 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2924 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2925 LCNPHY_CAL_FULL, false);
2926 } else {
2927
2928 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2929 }
2930
2931 }
2932
2933 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
2934
2935 didq = wlc_lcnphy_get_tx_locc(pi);
2936
2937 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2938 tab.tbl_width = 32;
2939 tab.tbl_ptr = &val;
2940
2941 tab.tbl_len = 1;
2942 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2943
2944 for (idx = 0; idx < 128; idx++) {
2945 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
2946
2947 wlc_lcnphy_read_table(pi, &tab);
2948 val = (val & 0xfff00000) |
2949 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
2950 wlc_lcnphy_write_table(pi, &tab);
2951
2952 val = didq;
2953 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
2954 wlc_lcnphy_write_table(pi, &tab);
2955 }
2956
2957 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
2958 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
2959 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
2960 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
2961 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
2962 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
2963 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
2964
2965 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
2966 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
2967 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2968
2969 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
2970 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2971 else
2972 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
2973 }
2974
2975 s16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2976 {
2977 u16 tempsenseval1, tempsenseval2;
2978 s16 avg = 0;
2979 bool suspend = 0;
2980
2981 if (NORADIO_ENAB(pi->pubpi))
2982 return -1;
2983
2984 if (mode == 1) {
2985 suspend =
2986 (0 ==
2987 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
2988 if (!suspend)
2989 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2990 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2991 }
2992 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
2993 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
2994
2995 if (tempsenseval1 > 255)
2996 avg = (s16) (tempsenseval1 - 512);
2997 else
2998 avg = (s16) tempsenseval1;
2999
3000 if (tempsenseval2 > 255)
3001 avg += (s16) (tempsenseval2 - 512);
3002 else
3003 avg += (s16) tempsenseval2;
3004
3005 avg /= 2;
3006
3007 if (mode == 1) {
3008
3009 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3010
3011 OSL_DELAY(100);
3012 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3013
3014 if (!suspend)
3015 wlapi_enable_mac(pi->sh->physhim);
3016 }
3017 return avg;
3018 }
3019
3020 u16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3021 {
3022 u16 tempsenseval1, tempsenseval2;
3023 s32 avg = 0;
3024 bool suspend = 0;
3025 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3026 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3027
3028 if (NORADIO_ENAB(pi->pubpi))
3029 return -1;
3030
3031 if (mode == 1) {
3032 suspend =
3033 (0 ==
3034 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3035 if (!suspend)
3036 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3037 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3038 }
3039 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3040 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3041
3042 if (tempsenseval1 > 255)
3043 avg = (int)(tempsenseval1 - 512);
3044 else
3045 avg = (int)tempsenseval1;
3046
3047 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
3048 if (tempsenseval2 > 255)
3049 avg = (int)(avg - tempsenseval2 + 512);
3050 else
3051 avg = (int)(avg - tempsenseval2);
3052 } else {
3053 if (tempsenseval2 > 255)
3054 avg = (int)(avg + tempsenseval2 - 512);
3055 else
3056 avg = (int)(avg + tempsenseval2);
3057 avg = avg / 2;
3058 }
3059 if (avg < 0)
3060 avg = avg + 512;
3061
3062 if (pi_lcn->lcnphy_tempsense_option == 2)
3063 avg = tempsenseval1;
3064
3065 if (mode)
3066 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3067
3068 if (mode == 1) {
3069
3070 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3071
3072 OSL_DELAY(100);
3073 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3074
3075 if (!suspend)
3076 wlapi_enable_mac(pi->sh->physhim);
3077 }
3078 return (u16) avg;
3079 }
3080
3081 s8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
3082 {
3083 s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
3084 degree =
3085 ((degree << 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
3086 / LCN_TEMPSENSE_DEN;
3087 return (s8) degree;
3088 }
3089
3090 s8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3091 {
3092 u16 vbatsenseval;
3093 s32 avg = 0;
3094 bool suspend = 0;
3095
3096 if (NORADIO_ENAB(pi->pubpi))
3097 return -1;
3098
3099 if (mode == 1) {
3100 suspend =
3101 (0 ==
3102 (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3103 if (!suspend)
3104 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3105 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
3106 }
3107
3108 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
3109
3110 if (vbatsenseval > 255)
3111 avg = (s32) (vbatsenseval - 512);
3112 else
3113 avg = (s32) vbatsenseval;
3114
3115 avg =
3116 (avg * LCN_VBAT_SCALE_NOM +
3117 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
3118
3119 if (mode == 1) {
3120 if (!suspend)
3121 wlapi_enable_mac(pi->sh->physhim);
3122 }
3123 return (s8) avg;
3124 }
3125
3126 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode)
3127 {
3128 u8 phybw40;
3129 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3130
3131 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
3132
3133 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
3134 (mode == AFE_CLK_INIT_MODE_TXRX2X))
3135 write_phy_reg(pi, 0x6d0, 0x7);
3136
3137 wlc_lcnphy_toggle_afe_pwdn(pi);
3138 }
3139
3140 static bool
3141 wlc_lcnphy_rx_iq_est(phy_info_t *pi,
3142 u16 num_samps,
3143 u8 wait_time, lcnphy_iq_est_t *iq_est)
3144 {
3145 int wait_count = 0;
3146 bool result = true;
3147 u8 phybw40;
3148 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3149
3150 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
3151
3152 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
3153
3154 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
3155
3156 mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
3157
3158 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
3159
3160 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
3161
3162 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
3163
3164 if (wait_count > (10 * 500)) {
3165 result = false;
3166 goto cleanup;
3167 }
3168 OSL_DELAY(100);
3169 wait_count++;
3170 }
3171
3172 iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
3173 (u32) read_phy_reg(pi, 0x484);
3174 iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
3175 (u32) read_phy_reg(pi, 0x486);
3176 iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
3177 (u32) read_phy_reg(pi, 0x488);
3178
3179 cleanup:
3180 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
3181
3182 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
3183
3184 return result;
3185 }
3186
3187 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps)
3188 {
3189 #define LCNPHY_MIN_RXIQ_PWR 2
3190 bool result;
3191 u16 a0_new, b0_new;
3192 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3193 s32 a, b, temp;
3194 s16 iq_nbits, qq_nbits, arsh, brsh;
3195 s32 iq;
3196 u32 ii, qq;
3197 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3198
3199 a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
3200 b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
3201 mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
3202
3203 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
3204
3205 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
3206
3207 result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
3208 if (!result)
3209 goto cleanup;
3210
3211 iq = (s32) iq_est.iq_prod;
3212 ii = iq_est.i_pwr;
3213 qq = iq_est.q_pwr;
3214
3215 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
3216 result = false;
3217 goto cleanup;
3218 }
3219
3220 iq_nbits = wlc_phy_nbits(iq);
3221 qq_nbits = wlc_phy_nbits(qq);
3222
3223 arsh = 10 - (30 - iq_nbits);
3224 if (arsh >= 0) {
3225 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
3226 temp = (s32) (ii >> arsh);
3227 if (temp == 0) {
3228 return false;
3229 }
3230 } else {
3231 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3232 temp = (s32) (ii << -arsh);
3233 if (temp == 0) {
3234 return false;
3235 }
3236 }
3237 a /= temp;
3238 brsh = qq_nbits - 31 + 20;
3239 if (brsh >= 0) {
3240 b = (qq << (31 - qq_nbits));
3241 temp = (s32) (ii >> brsh);
3242 if (temp == 0) {
3243 return false;
3244 }
3245 } else {
3246 b = (qq << (31 - qq_nbits));
3247 temp = (s32) (ii << -brsh);
3248 if (temp == 0) {
3249 return false;
3250 }
3251 }
3252 b /= temp;
3253 b -= a * a;
3254 b = (s32) wlc_phy_sqrt_int((u32) b);
3255 b -= (1 << 10);
3256 a0_new = (u16) (a & 0x3ff);
3257 b0_new = (u16) (b & 0x3ff);
3258 cleanup:
3259
3260 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
3261
3262 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
3263
3264 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
3265
3266 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
3267 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
3268
3269 return result;
3270 }
3271
3272 static bool
3273 wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
3274 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3275 int tx_gain_idx)
3276 {
3277 lcnphy_txgains_t old_gains;
3278 u16 tx_pwr_ctrl;
3279 u8 tx_gain_index_old = 0;
3280 bool result = false, tx_gain_override_old = false;
3281 u16 i, Core1TxControl_old, RFOverride0_old,
3282 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
3283 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
3284 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
3285 int tia_gain;
3286 u32 received_power, rx_pwr_threshold;
3287 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3288 u16 values_to_save[11];
3289 s16 *ptr;
3290 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3291
3292 ptr = MALLOC(pi->sh->osh, sizeof(s16) * 131);
3293 if (NULL == ptr) {
3294 return false;
3295 }
3296 if (module == 2) {
3297 ASSERT(iqcomp_sz);
3298
3299 while (iqcomp_sz--) {
3300 if (iqcomp[iqcomp_sz].chan ==
3301 CHSPEC_CHANNEL(pi->radio_chanspec)) {
3302
3303 wlc_lcnphy_set_rx_iq_comp(pi,
3304 (u16)
3305 iqcomp[iqcomp_sz].a,
3306 (u16)
3307 iqcomp[iqcomp_sz].b);
3308 result = true;
3309 break;
3310 }
3311 }
3312 ASSERT(result);
3313 goto cal_done;
3314 }
3315
3316 if (module == 1) {
3317
3318 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3319 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3320
3321 for (i = 0; i < 11; i++) {
3322 values_to_save[i] =
3323 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
3324 }
3325 Core1TxControl_old = read_phy_reg(pi, 0x631);
3326
3327 or_phy_reg(pi, 0x631, 0x0015);
3328
3329 RFOverride0_old = read_phy_reg(pi, 0x44c);
3330 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
3331 rfoverride2_old = read_phy_reg(pi, 0x4b0);
3332 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
3333 rfoverride3_old = read_phy_reg(pi, 0x4f9);
3334 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
3335 rfoverride4_old = read_phy_reg(pi, 0x938);
3336 rfoverride4val_old = read_phy_reg(pi, 0x939);
3337 afectrlovr_old = read_phy_reg(pi, 0x43b);
3338 afectrlovrval_old = read_phy_reg(pi, 0x43c);
3339 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3340 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
3341
3342 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
3343 if (tx_gain_override_old) {
3344 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3345 tx_gain_index_old = pi_lcn->lcnphy_current_index;
3346 }
3347
3348 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
3349
3350 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3351 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3352
3353 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3354 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3355
3356 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
3357 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
3358 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
3359 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
3360 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3361 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
3362 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
3363 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
3364 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
3365 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
3366
3367 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
3368 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
3369 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
3370 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
3371 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
3372 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
3373 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
3374 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
3375 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
3376 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
3377
3378 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3379 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3380
3381 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
3382 write_phy_reg(pi, 0x6da, 0xffff);
3383 or_phy_reg(pi, 0x6db, 0x3);
3384 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
3385 wlc_lcnphy_rx_gain_override_enable(pi, true);
3386
3387 tia_gain = 8;
3388 rx_pwr_threshold = 950;
3389 while (tia_gain > 0) {
3390 tia_gain -= 1;
3391 wlc_lcnphy_set_rx_gain_by_distribution(pi,
3392 0, 0, 2, 2,
3393 (u16)
3394 tia_gain, 1, 0);
3395 OSL_DELAY(500);
3396
3397 received_power =
3398 wlc_lcnphy_measure_digital_power(pi, 2000);
3399 if (received_power < rx_pwr_threshold)
3400 break;
3401 }
3402 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
3403
3404 wlc_lcnphy_stop_tx_tone(pi);
3405
3406 write_phy_reg(pi, 0x631, Core1TxControl_old);
3407
3408 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
3409 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
3410 write_phy_reg(pi, 0x4b0, rfoverride2_old);
3411 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
3412 write_phy_reg(pi, 0x4f9, rfoverride3_old);
3413 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
3414 write_phy_reg(pi, 0x938, rfoverride4_old);
3415 write_phy_reg(pi, 0x939, rfoverride4val_old);
3416 write_phy_reg(pi, 0x43b, afectrlovr_old);
3417 write_phy_reg(pi, 0x43c, afectrlovrval_old);
3418 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3419 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
3420
3421 wlc_lcnphy_clear_trsw_override(pi);
3422
3423 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
3424
3425 for (i = 0; i < 11; i++) {
3426 write_radio_reg(pi, rxiq_cal_rf_reg[i],
3427 values_to_save[i]);
3428 }
3429
3430 if (tx_gain_override_old) {
3431 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
3432 } else
3433 wlc_lcnphy_disable_tx_gain_override(pi);
3434 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
3435
3436 wlc_lcnphy_rx_gain_override_enable(pi, false);
3437 }
3438
3439 cal_done:
3440 MFREE(pi->sh->osh, ptr, 131 * sizeof(s16));
3441 return result;
3442 }
3443
3444 static void wlc_lcnphy_temp_adj(phy_info_t *pi)
3445 {
3446 if (NORADIO_ENAB(pi->pubpi))
3447 return;
3448 }
3449
3450 static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
3451 {
3452 bool suspend;
3453 s8 index;
3454 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3455 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3456 suspend =
3457 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3458 if (!suspend)
3459 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3460 wlc_lcnphy_deaf_mode(pi, true);
3461 pi->phy_lastcal = pi->sh->now;
3462 pi->phy_forcecal = false;
3463 index = pi_lcn->lcnphy_current_index;
3464
3465 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3466
3467 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3468 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3469 wlc_lcnphy_deaf_mode(pi, false);
3470 if (!suspend)
3471 wlapi_enable_mac(pi->sh->physhim);
3472
3473 }
3474
3475 static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
3476 {
3477 bool suspend, full_cal;
3478 const lcnphy_rx_iqcomp_t *rx_iqcomp;
3479 int rx_iqcomp_sz;
3480 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3481 s8 index;
3482 phytbl_info_t tab;
3483 s32 a1, b0, b1;
3484 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3485 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3486
3487 if (NORADIO_ENAB(pi->pubpi))
3488 return;
3489
3490 pi->phy_lastcal = pi->sh->now;
3491 pi->phy_forcecal = false;
3492 full_cal =
3493 (pi_lcn->lcnphy_full_cal_channel !=
3494 CHSPEC_CHANNEL(pi->radio_chanspec));
3495 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
3496 index = pi_lcn->lcnphy_current_index;
3497
3498 suspend =
3499 (0 == (R_REG(pi->sh->osh, &pi->regs->maccontrol) & MCTL_EN_MAC));
3500 if (!suspend) {
3501
3502 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
3503 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3504 }
3505 wlc_lcnphy_deaf_mode(pi, true);
3506
3507 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3508
3509 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
3510 rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
3511
3512 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
3513 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
3514 else
3515 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
3516
3517 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
3518
3519 wlc_lcnphy_idle_tssi_est((wlc_phy_t *) pi);
3520
3521 b0 = pi->txpa_2g[0];
3522 b1 = pi->txpa_2g[1];
3523 a1 = pi->txpa_2g[2];
3524 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3525 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3526
3527 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3528 tab.tbl_width = 32;
3529 tab.tbl_ptr = &pwr;
3530 tab.tbl_len = 1;
3531 tab.tbl_offset = 0;
3532 for (tssi = 0; tssi < 128; tssi++) {
3533 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3534 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3535 wlc_lcnphy_write_table(pi, &tab);
3536 tab.tbl_offset++;
3537 }
3538 }
3539
3540 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3541 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3542 wlc_lcnphy_deaf_mode(pi, false);
3543 if (!suspend)
3544 wlapi_enable_mac(pi->sh->physhim);
3545 }
3546
3547 void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
3548 {
3549 u16 temp_new;
3550 int temp1, temp2, temp_diff;
3551 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3552
3553 switch (mode) {
3554 case PHY_PERICAL_CHAN:
3555
3556 break;
3557 case PHY_FULLCAL:
3558 wlc_lcnphy_periodic_cal(pi);
3559 break;
3560 case PHY_PERICAL_PHYINIT:
3561 wlc_lcnphy_periodic_cal(pi);
3562 break;
3563 case PHY_PERICAL_WATCHDOG:
3564 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3565 temp_new = wlc_lcnphy_tempsense(pi, 0);
3566 temp1 = LCNPHY_TEMPSENSE(temp_new);
3567 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
3568 temp_diff = temp1 - temp2;
3569 if ((pi_lcn->lcnphy_cal_counter > 90) ||
3570 (temp_diff > 60) || (temp_diff < -60)) {
3571 wlc_lcnphy_glacial_timer_based_cal(pi);
3572 wlc_2064_vco_cal(pi);
3573 pi_lcn->lcnphy_cal_temper = temp_new;
3574 pi_lcn->lcnphy_cal_counter = 0;
3575 } else
3576 pi_lcn->lcnphy_cal_counter++;
3577 }
3578 break;
3579 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
3580 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3581 wlc_lcnphy_tx_power_adjustment((wlc_phy_t *) pi);
3582 break;
3583 default:
3584 ASSERT(0);
3585 break;
3586 }
3587 }
3588
3589 void wlc_lcnphy_get_tssi(phy_info_t *pi, s8 *ofdm_pwr, s8 *cck_pwr)
3590 {
3591 s8 cck_offset;
3592 u16 status;
3593 status = (read_phy_reg(pi, 0x4ab));
3594 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
3595 (status & (0x1 << 15))) {
3596 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
3597 >> 0) >> 1);
3598
3599 if (wlc_phy_tpc_isenabled_lcnphy(pi))
3600 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
3601 else
3602 cck_offset = 0;
3603
3604 *cck_pwr = *ofdm_pwr + cck_offset;
3605 } else {
3606 *cck_pwr = 0;
3607 *ofdm_pwr = 0;
3608 }
3609 }
3610
3611 void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi)
3612 {
3613 return;
3614
3615 }
3616
3617 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
3618 {
3619 u8 channel = CHSPEC_CHANNEL(chanspec);
3620 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3621
3622 if (NORADIO_ENAB(pi->pubpi))
3623 return;
3624
3625 if (channel == 14) {
3626 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
3627
3628 } else {
3629 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
3630
3631 }
3632 pi_lcn->lcnphy_bandedge_corr = 2;
3633 if (channel == 1)
3634 pi_lcn->lcnphy_bandedge_corr = 4;
3635
3636 if (channel == 1 || channel == 2 || channel == 3 ||
3637 channel == 4 || channel == 9 ||
3638 channel == 10 || channel == 11 || channel == 12) {
3639 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
3640 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
3641 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
3642
3643 si_pmu_pllupd(pi->sh->sih);
3644 write_phy_reg(pi, 0x942, 0);
3645 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3646 pi_lcn->lcnphy_spurmod = 0;
3647 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
3648
3649 write_phy_reg(pi, 0x425, 0x5907);
3650 } else {
3651 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
3652 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
3653 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
3654
3655 si_pmu_pllupd(pi->sh->sih);
3656 write_phy_reg(pi, 0x942, 0);
3657 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3658
3659 pi_lcn->lcnphy_spurmod = 0;
3660 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
3661
3662 write_phy_reg(pi, 0x425, 0x590a);
3663 }
3664
3665 or_phy_reg(pi, 0x44a, 0x44);
3666 write_phy_reg(pi, 0x44a, 0x80);
3667 }
3668
3669 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3670 {
3671 s8 index;
3672 u16 index2;
3673 phy_info_t *pi = (phy_info_t *) ppi;
3674 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3675 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3676 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3677 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3678 index2 = (u16) (index * 2);
3679 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3680
3681 pi_lcn->lcnphy_current_index = (s8)
3682 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3683 }
3684 }
3685
3686 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b)
3687 {
3688 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3689
3690 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3691
3692 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3693
3694 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3695
3696 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3697
3698 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3699
3700 }
3701
3702 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3703 {
3704 u8 phybw40;
3705 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3706 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3707
3708 pi_lcn->lcnphy_cal_counter = 0;
3709 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3710
3711 or_phy_reg(pi, 0x44a, 0x80);
3712 and_phy_reg(pi, 0x44a, 0x7f);
3713
3714 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3715
3716 write_phy_reg(pi, 0x60a, 160);
3717
3718 write_phy_reg(pi, 0x46a, 25);
3719
3720 wlc_lcnphy_baseband_init(pi);
3721
3722 wlc_lcnphy_radio_init(pi);
3723
3724 if (CHSPEC_IS2G(pi->radio_chanspec))
3725 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3726
3727 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3728
3729 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3730
3731 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3732
3733 if ((pi->sh->boardflags & BFL_FEM)
3734 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3735 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
3736
3737 wlc_lcnphy_agc_temp_init(pi);
3738
3739 wlc_lcnphy_temp_adj(pi);
3740
3741 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3742
3743 OSL_DELAY(100);
3744 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3745
3746 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3747 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
3748 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
3749 }
3750
3751 static void
3752 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, u16 *values_to_save)
3753 {
3754 u16 vmid;
3755 int i;
3756 for (i = 0; i < 20; i++) {
3757 values_to_save[i] =
3758 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
3759 }
3760
3761 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3762 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3763
3764 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3765 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3766
3767 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3768 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3769
3770 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3771 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3772
3773 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
3774 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
3775 else
3776 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
3777 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
3778
3779 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3780 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3781 OSL_DELAY(20);
3782
3783 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3784 if (CHSPEC_IS5G(pi->radio_chanspec))
3785 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
3786 else
3787 or_radio_reg(pi, RADIO_2064_REG03A, 1);
3788 } else {
3789 if (CHSPEC_IS5G(pi->radio_chanspec))
3790 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
3791 else
3792 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
3793 }
3794
3795 OSL_DELAY(20);
3796
3797 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
3798 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3799 if (CHSPEC_IS5G(pi->radio_chanspec))
3800 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
3801 else
3802 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
3803 } else {
3804 if (CHSPEC_IS5G(pi->radio_chanspec))
3805 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
3806 else
3807 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
3808 }
3809
3810 OSL_DELAY(20);
3811
3812 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3813 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3814 OSL_DELAY(20);
3815
3816 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3817 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3818 OSL_DELAY(20);
3819
3820 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3821 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3822 OSL_DELAY(20);
3823
3824 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3825 OSL_DELAY(20);
3826
3827 vmid = 0x2A6;
3828 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
3829 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
3830 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3831 OSL_DELAY(20);
3832
3833 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3834 OSL_DELAY(20);
3835 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
3836 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
3837 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
3838 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
3839 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
3840 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
3841 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
3842 }
3843
3844 static void
3845 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, u16 thresh,
3846 s16 *ptr, int mode)
3847 {
3848 u32 curval1, curval2, stpptr, curptr, strptr, val;
3849 u16 sslpnCalibClkEnCtrl, timer;
3850 u16 old_sslpnCalibClkEnCtrl;
3851 s16 imag, real;
3852 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3853
3854 timer = 0;
3855 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3856
3857 curval1 = R_REG(pi->sh->osh, &pi->regs->psm_corectlsts);
3858 ptr[130] = 0;
3859 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, ((1 << 6) | curval1));
3860
3861 W_REG(pi->sh->osh, &pi->regs->smpl_clct_strptr, 0x7E00);
3862 W_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr, 0x8000);
3863 OSL_DELAY(20);
3864 curval2 = R_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param);
3865 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2 | 0x30);
3866
3867 write_phy_reg(pi, 0x555, 0x0);
3868 write_phy_reg(pi, 0x5a6, 0x5);
3869
3870 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3871 write_phy_reg(pi, 0x5cf, 3);
3872 write_phy_reg(pi, 0x5a5, 0x3);
3873 write_phy_reg(pi, 0x583, 0x0);
3874 write_phy_reg(pi, 0x584, 0x0);
3875 write_phy_reg(pi, 0x585, 0x0fff);
3876 write_phy_reg(pi, 0x586, 0x0000);
3877
3878 write_phy_reg(pi, 0x580, 0x4501);
3879
3880 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3881 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3882 stpptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr);
3883 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3884 do {
3885 OSL_DELAY(10);
3886 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3887 timer++;
3888 } while ((curptr != stpptr) && (timer < 500));
3889
3890 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, 0x2);
3891 strptr = 0x7E00;
3892 W_REG(pi->sh->osh, &pi->regs->tplatewrptr, strptr);
3893 while (strptr < 0x8000) {
3894 val = R_REG(pi->sh->osh, &pi->regs->tplatewrdata);
3895 imag = ((val >> 16) & 0x3ff);
3896 real = ((val) & 0x3ff);
3897 if (imag > 511) {
3898 imag -= 1024;
3899 }
3900 if (real > 511) {
3901 real -= 1024;
3902 }
3903 if (pi_lcn->lcnphy_iqcal_swp_dis)
3904 ptr[(strptr - 0x7E00) / 4] = real;
3905 else
3906 ptr[(strptr - 0x7E00) / 4] = imag;
3907 if (clip_detect_algo) {
3908 if (imag > thresh || imag < -thresh) {
3909 strptr = 0x8000;
3910 ptr[130] = 1;
3911 }
3912 }
3913 strptr += 4;
3914 }
3915
3916 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3917 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2);
3918 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, curval1);
3919 }
3920
3921 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
3922 {
3923 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3924
3925 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3926 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3927 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3928 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3929
3930 wlc_lcnphy_a1(pi, 4, 0, 0);
3931 wlc_lcnphy_a1(pi, 3, 0, 0);
3932 wlc_lcnphy_a1(pi, 2, 3, 2);
3933 wlc_lcnphy_a1(pi, 0, 5, 8);
3934 wlc_lcnphy_a1(pi, 2, 2, 1);
3935 wlc_lcnphy_a1(pi, 0, 4, 3);
3936
3937 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3938 locc2 = wlc_lcnphy_get_cc(pi, 2);
3939 locc3 = wlc_lcnphy_get_cc(pi, 3);
3940 locc4 = wlc_lcnphy_get_cc(pi, 4);
3941 }
3942
3943 static void
3944 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3945 {
3946 u16 di0dq0;
3947 u16 x, y, data_rf;
3948 int k;
3949 switch (cal_type) {
3950 case 0:
3951 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3952 break;
3953 case 2:
3954 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3955 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3956 break;
3957 case 3:
3958 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3959 y = 8 + k;
3960 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3961 x = 8 - k;
3962 data_rf = (x * 16 + y);
3963 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3964 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3965 y = 8 + k;
3966 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3967 x = 8 - k;
3968 data_rf = (x * 16 + y);
3969 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3970 break;
3971 case 4:
3972 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3973 y = 8 + k;
3974 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3975 x = 8 - k;
3976 data_rf = (x * 16 + y);
3977 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3978 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3979 y = 8 + k;
3980 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3981 x = 8 - k;
3982 data_rf = (x * 16 + y);
3983 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3984 break;
3985 }
3986 }
3987
3988 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3989 {
3990 u16 a, b, didq;
3991 u8 di0, dq0, ei, eq, fi, fq;
3992 lcnphy_unsign16_struct cc;
3993 cc.re = 0;
3994 cc.im = 0;
3995 switch (cal_type) {
3996 case 0:
3997 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3998 cc.re = a;
3999 cc.im = b;
4000 break;
4001 case 2:
4002 didq = wlc_lcnphy_get_tx_locc(pi);
4003 di0 = (((didq & 0xff00) << 16) >> 24);
4004 dq0 = (((didq & 0x00ff) << 24) >> 24);
4005 cc.re = (u16) di0;
4006 cc.im = (u16) dq0;
4007 break;
4008 case 3:
4009 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4010 cc.re = (u16) ei;
4011 cc.im = (u16) eq;
4012 break;
4013 case 4:
4014 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4015 cc.re = (u16) fi;
4016 cc.im = (u16) fq;
4017 break;
4018 }
4019 return cc;
4020 }
4021
4022 static void
4023 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
4024 {
4025 const lcnphy_spb_tone_t *phy_c1;
4026 lcnphy_spb_tone_t phy_c2;
4027 lcnphy_unsign16_struct phy_c3;
4028 int phy_c4, phy_c5, k, l, j, phy_c6;
4029 u16 phy_c7, phy_c8, phy_c9;
4030 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4031 s16 *ptr, phy_c17;
4032 s32 phy_c18, phy_c19;
4033 u32 phy_c20, phy_c21;
4034 bool phy_c22, phy_c23, phy_c24, phy_c25;
4035 u16 phy_c26, phy_c27;
4036 u16 phy_c28, phy_c29, phy_c30;
4037 u16 phy_c31;
4038 u16 *phy_c32;
4039 phy_c21 = 0;
4040 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4041 ptr = MALLOC(pi->sh->osh, sizeof(s16) * 131);
4042 if (NULL == ptr) {
4043 return;
4044 }
4045
4046 phy_c32 = MALLOC(pi->sh->osh, sizeof(u16) * 20);
4047 if (NULL == phy_c32) {
4048 return;
4049 }
4050 phy_c26 = read_phy_reg(pi, 0x6da);
4051 phy_c27 = read_phy_reg(pi, 0x6db);
4052 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
4053 write_phy_reg(pi, 0x93d, 0xC0);
4054
4055 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
4056 write_phy_reg(pi, 0x6da, 0xffff);
4057 or_phy_reg(pi, 0x6db, 0x3);
4058
4059 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
4060 OSL_DELAY(500);
4061 phy_c28 = read_phy_reg(pi, 0x938);
4062 phy_c29 = read_phy_reg(pi, 0x4d7);
4063 phy_c30 = read_phy_reg(pi, 0x4d8);
4064 or_phy_reg(pi, 0x938, 0x1 << 2);
4065 or_phy_reg(pi, 0x4d7, 0x1 << 2);
4066 or_phy_reg(pi, 0x4d7, 0x1 << 3);
4067 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
4068 or_phy_reg(pi, 0x4d8, 1 << 0);
4069 or_phy_reg(pi, 0x4d8, 1 << 1);
4070 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
4071 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
4072 phy_c1 = &lcnphy_spb_tone_3750[0];
4073 phy_c4 = 32;
4074
4075 if (num_levels == 0) {
4076 if (cal_type != 0) {
4077 num_levels = 4;
4078 } else {
4079 num_levels = 9;
4080 }
4081 }
4082 if (step_size_lg2 == 0) {
4083 if (cal_type != 0) {
4084 step_size_lg2 = 3;
4085 } else {
4086 step_size_lg2 = 8;
4087 }
4088 }
4089
4090 phy_c7 = (1 << step_size_lg2);
4091 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
4092 phy_c15 = (s16) phy_c3.re;
4093 phy_c16 = (s16) phy_c3.im;
4094 if (cal_type == 2) {
4095 if (phy_c3.re > 127)
4096 phy_c15 = phy_c3.re - 256;
4097 if (phy_c3.im > 127)
4098 phy_c16 = phy_c3.im - 256;
4099 }
4100 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4101 OSL_DELAY(20);
4102 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
4103 phy_c23 = 1;
4104 phy_c22 = 0;
4105 switch (cal_type) {
4106 case 0:
4107 phy_c10 = 511;
4108 break;
4109 case 2:
4110 phy_c10 = 127;
4111 break;
4112 case 3:
4113 phy_c10 = 15;
4114 break;
4115 case 4:
4116 phy_c10 = 15;
4117 break;
4118 }
4119
4120 phy_c9 = read_phy_reg(pi, 0x93d);
4121 phy_c9 = 2 * phy_c9;
4122 phy_c24 = 0;
4123 phy_c5 = 7;
4124 phy_c25 = 1;
4125 while (1) {
4126 write_radio_reg(pi, RADIO_2064_REG026,
4127 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
4128 OSL_DELAY(50);
4129 phy_c22 = 0;
4130 ptr[130] = 0;
4131 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
4132 if (ptr[130] == 1)
4133 phy_c22 = 1;
4134 if (phy_c22)
4135 phy_c5 -= 1;
4136 if ((phy_c22 != phy_c24) && (!phy_c25))
4137 break;
4138 if (!phy_c22)
4139 phy_c5 += 1;
4140 if (phy_c5 <= 0 || phy_c5 >= 7)
4141 break;
4142 phy_c24 = phy_c22;
4143 phy_c25 = 0;
4144 }
4145
4146 if (phy_c5 < 0)
4147 phy_c5 = 0;
4148 else if (phy_c5 > 7)
4149 phy_c5 = 7;
4150
4151 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
4152 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
4153 phy_c11 = phy_c15 + k;
4154 phy_c12 = phy_c16 + l;
4155
4156 if (phy_c11 < -phy_c10)
4157 phy_c11 = -phy_c10;
4158 else if (phy_c11 > phy_c10)
4159 phy_c11 = phy_c10;
4160 if (phy_c12 < -phy_c10)
4161 phy_c12 = -phy_c10;
4162 else if (phy_c12 > phy_c10)
4163 phy_c12 = phy_c10;
4164 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
4165 phy_c12);
4166 OSL_DELAY(20);
4167 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
4168
4169 phy_c18 = 0;
4170 phy_c19 = 0;
4171 for (j = 0; j < 128; j++) {
4172 if (cal_type != 0) {
4173 phy_c6 = j % phy_c4;
4174 } else {
4175 phy_c6 = (2 * j) % phy_c4;
4176 }
4177 phy_c2.re = phy_c1[phy_c6].re;
4178 phy_c2.im = phy_c1[phy_c6].im;
4179 phy_c17 = ptr[j];
4180 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
4181 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
4182 }
4183
4184 phy_c18 = phy_c18 >> 10;
4185 phy_c19 = phy_c19 >> 10;
4186 phy_c20 =
4187 ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
4188
4189 if (phy_c23 || phy_c20 < phy_c21) {
4190 phy_c21 = phy_c20;
4191 phy_c13 = phy_c11;
4192 phy_c14 = phy_c12;
4193 }
4194 phy_c23 = 0;
4195 }
4196 }
4197 phy_c23 = 1;
4198 phy_c15 = phy_c13;
4199 phy_c16 = phy_c14;
4200 phy_c7 = phy_c7 >> 1;
4201 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4202 OSL_DELAY(20);
4203 }
4204 goto cleanup;
4205 cleanup:
4206 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
4207 wlc_lcnphy_stop_tx_tone(pi);
4208 write_phy_reg(pi, 0x6da, phy_c26);
4209 write_phy_reg(pi, 0x6db, phy_c27);
4210 write_phy_reg(pi, 0x938, phy_c28);
4211 write_phy_reg(pi, 0x4d7, phy_c29);
4212 write_phy_reg(pi, 0x4d8, phy_c30);
4213 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
4214
4215 MFREE(pi->sh->osh, phy_c32, 20 * sizeof(u16));
4216 MFREE(pi->sh->osh, ptr, 131 * sizeof(s16));
4217 }
4218
4219 static void
4220 wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, u16 *values_to_save)
4221 {
4222 int i;
4223
4224 and_phy_reg(pi, 0x44c, 0x0 >> 11);
4225
4226 and_phy_reg(pi, 0x43b, 0xC);
4227
4228 for (i = 0; i < 20; i++) {
4229 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
4230 values_to_save[i]);
4231 }
4232 }
4233
4234 static void
4235 WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
4236 const lcnphy_tx_gain_tbl_entry *
4237 gain_table) {
4238 u32 j;
4239 phytbl_info_t tab;
4240 u32 val;
4241 u16 pa_gain;
4242 u16 gm_gain;
4243
4244 if (CHSPEC_IS5G(pi->radio_chanspec))
4245 pa_gain = 0x70;
4246 else
4247 pa_gain = 0x70;
4248
4249 if (pi->sh->boardflags & BFL_FEM)
4250 pa_gain = 0x10;
4251 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4252 tab.tbl_width = 32;
4253 tab.tbl_len = 1;
4254 tab.tbl_ptr = &val;
4255
4256 for (j = 0; j < 128; j++) {
4257 gm_gain = gain_table[j].gm;
4258 val = (((u32) pa_gain << 24) |
4259 (gain_table[j].pad << 16) |
4260 (gain_table[j].pga << 8) | gm_gain);
4261
4262 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4263 wlc_lcnphy_write_table(pi, &tab);
4264
4265 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4266 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4267 wlc_lcnphy_write_table(pi, &tab);
4268 }
4269 }
4270
4271 static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
4272 {
4273 phytbl_info_t tab;
4274 u32 val, bbmult, rfgain;
4275 u8 index;
4276 u8 scale_factor = 1;
4277 s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4278
4279 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4280 tab.tbl_width = 32;
4281 tab.tbl_len = 1;
4282
4283 for (index = 0; index < 128; index++) {
4284 tab.tbl_ptr = &bbmult;
4285 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4286 wlc_lcnphy_read_table(pi, &tab);
4287 bbmult = bbmult >> 20;
4288
4289 tab.tbl_ptr = &rfgain;
4290 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4291 wlc_lcnphy_read_table(pi, &tab);
4292
4293 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4294 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4295
4296 if (qQ1 < qQ2) {
4297 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4298 qQ = qQ1;
4299 } else {
4300 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4301 qQ = qQ2;
4302 }
4303 temp = qm_sub16(temp1, temp2);
4304
4305 if (qQ >= 4)
4306 shift = qQ - 4;
4307 else
4308 shift = 4 - qQ;
4309
4310 val = (((index << shift) + (5 * temp) +
4311 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4312 shift - 2));
4313
4314 tab.tbl_ptr = &val;
4315 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4316 wlc_lcnphy_write_table(pi, &tab);
4317 }
4318 }
4319
4320 static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi)
4321 {
4322 uint idx;
4323 u8 phybw40;
4324 phytbl_info_t tab;
4325 u32 val;
4326
4327 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4328
4329 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
4330 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4331 }
4332
4333 if (pi->sh->boardflags & BFL_FEM_BT) {
4334 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4335 tab.tbl_width = 16;
4336 tab.tbl_ptr = &val;
4337 tab.tbl_len = 1;
4338 val = 100;
4339 tab.tbl_offset = 4;
4340 wlc_lcnphy_write_table(pi, &tab);
4341 }
4342
4343 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4344 tab.tbl_width = 16;
4345 tab.tbl_ptr = &val;
4346 tab.tbl_len = 1;
4347
4348 val = 114;
4349 tab.tbl_offset = 0;
4350 wlc_lcnphy_write_table(pi, &tab);
4351
4352 val = 130;
4353 tab.tbl_offset = 1;
4354 wlc_lcnphy_write_table(pi, &tab);
4355
4356 val = 6;
4357 tab.tbl_offset = 8;
4358 wlc_lcnphy_write_table(pi, &tab);
4359
4360 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4361 if (pi->sh->boardflags & BFL_FEM)
4362 wlc_lcnphy_load_tx_gain_table(pi,
4363 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4364 else
4365 wlc_lcnphy_load_tx_gain_table(pi,
4366 dot11lcnphy_2GHz_gaintable_rev0);
4367 }
4368
4369 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4370 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4371 for (idx = 0;
4372 idx < dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4373 idx++)
4374 if (pi->sh->boardflags & BFL_EXTLNA)
4375 wlc_lcnphy_write_table(pi,
4376 &dot11lcnphytbl_rx_gain_info_extlna_2G_rev2
4377 [idx]);
4378 else
4379 wlc_lcnphy_write_table(pi,
4380 &dot11lcnphytbl_rx_gain_info_2G_rev2
4381 [idx]);
4382 } else {
4383 for (idx = 0;
4384 idx < dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4385 idx++)
4386 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4387 wlc_lcnphy_write_table(pi,
4388 &dot11lcnphytbl_rx_gain_info_extlna_5G_rev2
4389 [idx]);
4390 else
4391 wlc_lcnphy_write_table(pi,
4392 &dot11lcnphytbl_rx_gain_info_5G_rev2
4393 [idx]);
4394 }
4395 }
4396
4397 if ((pi->sh->boardflags & BFL_FEM)
4398 && !(pi->sh->boardflags & BFL_FEM_BT))
4399 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4400 else if (pi->sh->boardflags & BFL_FEM_BT) {
4401 if (pi->sh->boardrev < 0x1250)
4402 wlc_lcnphy_write_table(pi,
4403 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4404 else
4405 wlc_lcnphy_write_table(pi,
4406 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4407 } else
4408 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4409
4410 wlc_lcnphy_load_rfpower(pi);
4411
4412 wlc_lcnphy_clear_papd_comptable(pi);
4413 }
4414
4415 static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi)
4416 {
4417 u16 afectrl1;
4418 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4419
4420 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4421
4422 write_phy_reg(pi, 0x43b, 0x0);
4423 write_phy_reg(pi, 0x43c, 0x0);
4424 write_phy_reg(pi, 0x44c, 0x0);
4425 write_phy_reg(pi, 0x4e6, 0x0);
4426 write_phy_reg(pi, 0x4f9, 0x0);
4427 write_phy_reg(pi, 0x4b0, 0x0);
4428 write_phy_reg(pi, 0x938, 0x0);
4429 write_phy_reg(pi, 0x4b0, 0x0);
4430 write_phy_reg(pi, 0x44e, 0);
4431
4432 or_phy_reg(pi, 0x567, 0x03);
4433
4434 or_phy_reg(pi, 0x44a, 0x44);
4435 write_phy_reg(pi, 0x44a, 0x80);
4436
4437 if (!(pi->sh->boardflags & BFL_FEM))
4438 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4439
4440 if (0) {
4441 afectrl1 = 0;
4442 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4443 (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4444 lcnphy_rssi_gs
4445 << 10));
4446 write_phy_reg(pi, 0x43e, afectrl1);
4447 }
4448
4449 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4450 if (pi->sh->boardflags & BFL_FEM) {
4451 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4452
4453 write_phy_reg(pi, 0x910, 0x1);
4454 }
4455
4456 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4457 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4458 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4459
4460 }
4461
4462 static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi)
4463 {
4464 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4465 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4466
4467 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4468 }
4469 }
4470
4471 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
4472 {
4473 s16 temp;
4474 phytbl_info_t tab;
4475 u32 tableBuffer[2];
4476 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4477
4478 if (NORADIO_ENAB(pi->pubpi))
4479 return;
4480
4481 temp = (s16) read_phy_reg(pi, 0x4df);
4482 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4483
4484 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4485 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4486
4487 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4488
4489 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4490 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4491
4492 tab.tbl_ptr = tableBuffer;
4493 tab.tbl_len = 2;
4494 tab.tbl_id = 17;
4495 tab.tbl_offset = 59;
4496 tab.tbl_width = 32;
4497 wlc_lcnphy_read_table(pi, &tab);
4498
4499 if (tableBuffer[0] > 63)
4500 tableBuffer[0] -= 128;
4501 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4502
4503 if (tableBuffer[1] > 63)
4504 tableBuffer[1] -= 128;
4505 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4506
4507 temp = (s16) (read_phy_reg(pi, 0x434)
4508 & (0xff << 0));
4509 if (temp > 127)
4510 temp -= 256;
4511 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4512
4513 pi_lcn->lcnphy_Med_Low_Gain_db = (read_phy_reg(pi, 0x424)
4514 & (0xff << 8))
4515 >> 8;
4516 pi_lcn->lcnphy_Very_Low_Gain_db = (read_phy_reg(pi, 0x425)
4517 & (0xff << 0))
4518 >> 0;
4519
4520 tab.tbl_ptr = tableBuffer;
4521 tab.tbl_len = 2;
4522 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4523 tab.tbl_offset = 28;
4524 tab.tbl_width = 32;
4525 wlc_lcnphy_read_table(pi, &tab);
4526
4527 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4528 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4529
4530 }
4531
4532 static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi)
4533 {
4534 if (NORADIO_ENAB(pi->pubpi))
4535 return;
4536
4537 or_phy_reg(pi, 0x805, 0x1);
4538
4539 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4540
4541 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4542
4543 write_phy_reg(pi, 0x414, 0x1e10);
4544 write_phy_reg(pi, 0x415, 0x0640);
4545
4546 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4547
4548 or_phy_reg(pi, 0x44a, 0x44);
4549 write_phy_reg(pi, 0x44a, 0x80);
4550 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4551
4552 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4553
4554 if (!(pi->sh->boardrev < 0x1204))
4555 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4556
4557 write_phy_reg(pi, 0x7d6, 0x0902);
4558 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4559
4560 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4561
4562 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4563 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4564
4565 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4566
4567 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4568
4569 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4570
4571 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4572
4573 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4574 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4575 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4576 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4577 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4578
4579 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4580
4581 wlc_lcnphy_clear_tx_power_offsets(pi);
4582 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4583
4584 }
4585 }
4586
4587 static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi)
4588 {
4589
4590 wlc_lcnphy_tbl_init(pi);
4591 wlc_lcnphy_rev0_baseband_init(pi);
4592 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4593 wlc_lcnphy_rev2_baseband_init(pi);
4594 wlc_lcnphy_bu_tweaks(pi);
4595 }
4596
4597 static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi)
4598 {
4599 u32 i;
4600 lcnphy_radio_regs_t *lcnphyregs = NULL;
4601
4602 lcnphyregs = lcnphy_radio_regs_2064;
4603
4604 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4605 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4606 write_radio_reg(pi,
4607 ((lcnphyregs[i].address & 0x3fff) |
4608 RADIO_DEFAULT_CORE),
4609 (u16) lcnphyregs[i].init_a);
4610 else if (lcnphyregs[i].do_init_g)
4611 write_radio_reg(pi,
4612 ((lcnphyregs[i].address & 0x3fff) |
4613 RADIO_DEFAULT_CORE),
4614 (u16) lcnphyregs[i].init_g);
4615
4616 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4617 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4618
4619 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4620
4621 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4622
4623 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4624
4625 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4626 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4627 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4628 }
4629
4630 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4631 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4632
4633 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4634
4635 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4636
4637 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4638
4639 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4640
4641 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4642
4643 write_phy_reg(pi, 0x4ea, 0x4688);
4644
4645 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4646
4647 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4648
4649 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4650
4651 wlc_lcnphy_set_tx_locc(pi, 0);
4652
4653 wlc_lcnphy_rcal(pi);
4654
4655 wlc_lcnphy_rc_cal(pi);
4656 }
4657
4658 static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi)
4659 {
4660 if (NORADIO_ENAB(pi->pubpi))
4661 return;
4662
4663 wlc_radio_2064_init(pi);
4664 }
4665
4666 static void wlc_lcnphy_rcal(phy_info_t *pi)
4667 {
4668 u8 rcal_value;
4669
4670 if (NORADIO_ENAB(pi->pubpi))
4671 return;
4672
4673 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4674
4675 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4676 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4677
4678 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4679 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4680
4681 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4682
4683 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4684 OSL_DELAY(5000);
4685 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4686
4687 if (wlc_radio_2064_rcal_done(pi)) {
4688 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4689 rcal_value = rcal_value & 0x1f;
4690 }
4691
4692 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4693
4694 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4695 }
4696
4697 static void wlc_lcnphy_rc_cal(phy_info_t *pi)
4698 {
4699 u8 dflt_rc_cal_val;
4700 u16 flt_val;
4701
4702 if (NORADIO_ENAB(pi->pubpi))
4703 return;
4704
4705 dflt_rc_cal_val = 7;
4706 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4707 dflt_rc_cal_val = 11;
4708 flt_val =
4709 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4710 (dflt_rc_cal_val);
4711 write_phy_reg(pi, 0x933, flt_val);
4712 write_phy_reg(pi, 0x934, flt_val);
4713 write_phy_reg(pi, 0x935, flt_val);
4714 write_phy_reg(pi, 0x936, flt_val);
4715 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4716
4717 return;
4718 }
4719
4720 static bool wlc_phy_txpwr_srom_read_lcnphy(phy_info_t *pi)
4721 {
4722 s8 txpwr = 0;
4723 int i;
4724 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4725
4726 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4727 u16 cckpo = 0;
4728 u32 offset_ofdm, offset_mcs;
4729
4730 pi_lcn->lcnphy_tr_isolation_mid =
4731 (u8) PHY_GETINTVAR(pi, "triso2g");
4732
4733 pi_lcn->lcnphy_rx_power_offset =
4734 (u8) PHY_GETINTVAR(pi, "rxpo2g");
4735
4736 pi->txpa_2g[0] = (s16) PHY_GETINTVAR(pi, "pa0b0");
4737 pi->txpa_2g[1] = (s16) PHY_GETINTVAR(pi, "pa0b1");
4738 pi->txpa_2g[2] = (s16) PHY_GETINTVAR(pi, "pa0b2");
4739
4740 pi_lcn->lcnphy_rssi_vf = (u8) PHY_GETINTVAR(pi, "rssismf2g");
4741 pi_lcn->lcnphy_rssi_vc = (u8) PHY_GETINTVAR(pi, "rssismc2g");
4742 pi_lcn->lcnphy_rssi_gs = (u8) PHY_GETINTVAR(pi, "rssisav2g");
4743
4744 {
4745 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4746 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4747 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4748
4749 pi_lcn->lcnphy_rssi_vf_hightemp =
4750 pi_lcn->lcnphy_rssi_vf;
4751 pi_lcn->lcnphy_rssi_vc_hightemp =
4752 pi_lcn->lcnphy_rssi_vc;
4753 pi_lcn->lcnphy_rssi_gs_hightemp =
4754 pi_lcn->lcnphy_rssi_gs;
4755 }
4756
4757 txpwr = (s8) PHY_GETINTVAR(pi, "maxp2ga0");
4758 pi->tx_srom_max_2g = txpwr;
4759
4760 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4761 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4762 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4763 }
4764
4765 cckpo = (u16) PHY_GETINTVAR(pi, "cck2gpo");
4766 if (cckpo) {
4767 uint max_pwr_chan = txpwr;
4768
4769 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4770 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4771 ((cckpo & 0xf) * 2);
4772 cckpo >>= 4;
4773 }
4774
4775 offset_ofdm = (u32) PHY_GETINTVAR(pi, "ofdm2gpo");
4776 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4777 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4778 ((offset_ofdm & 0xf) * 2);
4779 offset_ofdm >>= 4;
4780 }
4781 } else {
4782 u8 opo = 0;
4783
4784 opo = (u8) PHY_GETINTVAR(pi, "opo");
4785
4786 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4787 pi->tx_srom_max_rate_2g[i] = txpwr;
4788 }
4789
4790 offset_ofdm = (u32) PHY_GETINTVAR(pi, "ofdm2gpo");
4791
4792 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4793 pi->tx_srom_max_rate_2g[i] = txpwr -
4794 ((offset_ofdm & 0xf) * 2);
4795 offset_ofdm >>= 4;
4796 }
4797 offset_mcs =
4798 ((u16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4799 (u16) PHY_GETINTVAR(pi, "mcs2gpo0");
4800 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4801 for (i = TXP_FIRST_SISO_MCS_20;
4802 i <= TXP_LAST_SISO_MCS_20; i++) {
4803 pi->tx_srom_max_rate_2g[i] =
4804 txpwr - ((offset_mcs & 0xf) * 2);
4805 offset_mcs >>= 4;
4806 }
4807 }
4808
4809 pi_lcn->lcnphy_rawtempsense =
4810 (u16) PHY_GETINTVAR(pi, "rawtempsense");
4811 pi_lcn->lcnphy_measPower =
4812 (u8) PHY_GETINTVAR(pi, "measpower");
4813 pi_lcn->lcnphy_tempsense_slope =
4814 (u8) PHY_GETINTVAR(pi, "tempsense_slope");
4815 pi_lcn->lcnphy_hw_iqcal_en =
4816 (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
4817 pi_lcn->lcnphy_iqcal_swp_dis =
4818 (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
4819 pi_lcn->lcnphy_tempcorrx =
4820 (u8) PHY_GETINTVAR(pi, "tempcorrx");
4821 pi_lcn->lcnphy_tempsense_option =
4822 (u8) PHY_GETINTVAR(pi, "tempsense_option");
4823 pi_lcn->lcnphy_freqoffset_corr =
4824 (u8) PHY_GETINTVAR(pi, "freqoffset_corr");
4825 if ((u8) getintvar(pi->vars, "aa2g") > 1)
4826 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
4827 (u8) getintvar(pi->vars,
4828 "aa2g"));
4829 }
4830 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4831 if (PHY_GETVAR(pi, "cckdigfilttype")) {
4832 s16 temp;
4833 temp = (s16) PHY_GETINTVAR(pi, "cckdigfilttype");
4834 if (temp >= 0) {
4835 pi_lcn->lcnphy_cck_dig_filt_type = temp;
4836 }
4837 }
4838
4839 return true;
4840 }
4841
4842 void wlc_2064_vco_cal(phy_info_t *pi)
4843 {
4844 u8 calnrst;
4845
4846 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4847 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4848 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4849 OSL_DELAY(1);
4850 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4851 OSL_DELAY(1);
4852 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4853 OSL_DELAY(300);
4854 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4855 }
4856
4857 static void
4858 wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, u8 channel)
4859 {
4860 uint i;
4861 const chan_info_2064_lcnphy_t *ci;
4862 u8 rfpll_doubler = 0;
4863 u8 pll_pwrup, pll_pwrup_ovr;
4864 fixed qFxtal, qFref, qFvco, qFcal;
4865 u8 d15, d16, f16, e44, e45;
4866 u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
4867 u16 loop_bw, d30, setCount;
4868 if (NORADIO_ENAB(pi->pubpi))
4869 return;
4870 ci = &chan_info_2064_lcnphy[0];
4871 rfpll_doubler = 1;
4872
4873 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
4874
4875 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
4876 if (!rfpll_doubler) {
4877 loop_bw = PLL_2064_LOOP_BW;
4878 d30 = PLL_2064_D30;
4879 } else {
4880 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
4881 d30 = PLL_2064_D30_DOUBLER;
4882 }
4883
4884 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4885 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
4886 if (chan_info_2064_lcnphy[i].chan == channel)
4887 break;
4888
4889 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy)) {
4890 return;
4891 }
4892
4893 ci = &chan_info_2064_lcnphy[i];
4894 }
4895
4896 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
4897
4898 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
4899
4900 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
4901
4902 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
4903
4904 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
4905 (ci->logen_rccr_rx) << 2);
4906
4907 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
4908
4909 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
4910 (ci->pa_rxrf_lna2_freq_tune) << 4);
4911
4912 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
4913
4914 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
4915 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
4916
4917 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
4918
4919 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
4920 e44 = 0;
4921 e45 = 0;
4922
4923 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
4924 if (pi->xtalfreq > 26000000)
4925 e44 = 1;
4926 if (pi->xtalfreq > 52000000)
4927 e45 = 1;
4928 if (e44 == 0)
4929 fcal_div = 1;
4930 else if (e45 == 0)
4931 fcal_div = 2;
4932 else
4933 fcal_div = 4;
4934 fvco3 = (ci->freq * 3);
4935 fref3 = 2 * fpfd;
4936
4937 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
4938 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
4939 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
4940 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
4941
4942 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
4943
4944 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
4945 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
4946 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
4947
4948 d16 = (qFcal * 8 / (d15 + 1)) - 1;
4949 write_radio_reg(pi, RADIO_2064_REG051, d16);
4950
4951 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
4952 setCount = f16 * 3 * (ci->freq) / 32 - 1;
4953 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
4954 (u8) (setCount >> 8));
4955
4956 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
4957 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
4958
4959 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
4960
4961 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
4962 while (div_frac >= fref3) {
4963 div_int++;
4964 div_frac -= fref3;
4965 }
4966 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
4967
4968 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
4969 (u8) (div_int >> 4));
4970 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
4971 (u8) (div_int << 4));
4972 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
4973 (u8) (div_frac >> 16));
4974 write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
4975 write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
4976
4977 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
4978
4979 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
4980 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
4981 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
4982
4983 {
4984 u8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
4985 u16 c29, c38, c30, g30, d28;
4986 c29 = loop_bw;
4987 d29 = 200;
4988 c38 = 1250;
4989 h29 = d29 / c29;
4990 h23 = 1;
4991 c28 = 30;
4992 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
4993 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
4994 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
4995 + PLL_2064_LOW_END_KVCO;
4996 h28_ten = (d28 * 10) / c28;
4997 c30 = 2640;
4998 e30 = (d30 - 680) / 490;
4999 g30 = 680 + (e30 * 490);
5000 h30_ten = (g30 * 10) / c30;
5001 cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
5002 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
5003 }
5004 if (channel >= 1 && channel <= 5)
5005 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
5006 else
5007 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
5008 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
5009
5010 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
5011 OSL_DELAY(1);
5012
5013 wlc_2064_vco_cal(pi);
5014
5015 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
5016 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
5017 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5018 write_radio_reg(pi, RADIO_2064_REG038, 3);
5019 write_radio_reg(pi, RADIO_2064_REG091, 7);
5020 }
5021 }
5022
5023 bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
5024 {
5025 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5026 return 0;
5027 else
5028 return (LCNPHY_TX_PWR_CTRL_HW ==
5029 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5030 }
5031
5032 void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
5033 {
5034 u16 pwr_ctrl;
5035 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5036 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5037 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5038
5039 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5040 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5041 wlc_lcnphy_txpower_recalc_target(pi);
5042
5043 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5044 } else
5045 return;
5046 }
5047
5048 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5049 {
5050 MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5051 }
5052
5053 bool wlc_phy_attach_lcnphy(phy_info_t *pi)
5054 {
5055 phy_info_lcnphy_t *pi_lcn;
5056
5057 pi->u.pi_lcnphy =
5058 (phy_info_lcnphy_t *) MALLOC(pi->sh->osh,
5059 sizeof(phy_info_lcnphy_t));
5060 if (pi->u.pi_lcnphy == NULL) {
5061 return false;
5062 }
5063 bzero((char *)pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5064
5065 pi_lcn = pi->u.pi_lcnphy;
5066
5067 if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
5068 pi->hwpwrctrl = true;
5069 pi->hwpwrctrl_capable = true;
5070 }
5071
5072 pi->xtalfreq = si_alp_clock(pi->sh->sih);
5073 ASSERT(0 == (pi->xtalfreq % 1000));
5074
5075 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5076
5077 pi->pi_fptr.init = wlc_phy_init_lcnphy;
5078 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5079 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5080 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5081 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5082 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5083 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5084 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5085 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5086
5087 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5088 return false;
5089
5090 if ((pi->sh->boardflags & BFL_FEM) && (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5091 if (pi_lcn->lcnphy_tempsense_option == 3) {
5092 pi->hwpwrctrl = true;
5093 pi->hwpwrctrl_capable = true;
5094 pi->temppwrctrl_capable = false;
5095 } else {
5096 pi->hwpwrctrl = false;
5097 pi->hwpwrctrl_capable = false;
5098 pi->temppwrctrl_capable = true;
5099 }
5100 }
5101
5102 return true;
5103 }
5104
5105 static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, u32 gain)
5106 {
5107 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5108
5109 trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5110 ext_lna = (u16) (gain >> 29) & 0x01;
5111 lna1 = (u16) (gain >> 0) & 0x0f;
5112 lna2 = (u16) (gain >> 4) & 0x0f;
5113 tia = (u16) (gain >> 8) & 0xf;
5114 biq0 = (u16) (gain >> 12) & 0xf;
5115 biq1 = (u16) (gain >> 16) & 0xf;
5116
5117 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5118 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5119 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5120 gain16_19 = biq1;
5121
5122 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5123 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5124 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5125 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5126 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5127
5128 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5129 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5130 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5131 }
5132 wlc_lcnphy_rx_gain_override_enable(pi, true);
5133 }
5134
5135 static u32 wlc_lcnphy_get_receive_power(phy_info_t *pi, s32 *gain_index)
5136 {
5137 u32 received_power = 0;
5138 s32 max_index = 0;
5139 u32 gain_code = 0;
5140 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5141
5142 max_index = 36;
5143 if (*gain_index >= 0)
5144 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5145
5146 if (-1 == *gain_index) {
5147 *gain_index = 0;
5148 while ((*gain_index <= (s32) max_index)
5149 && (received_power < 700)) {
5150 wlc_lcnphy_set_rx_gain(pi,
5151 lcnphy_23bitgaincode_table
5152 [*gain_index]);
5153 received_power =
5154 wlc_lcnphy_measure_digital_power(pi,
5155 pi_lcn->
5156 lcnphy_noise_samples);
5157 (*gain_index)++;
5158 }
5159 (*gain_index)--;
5160 } else {
5161 wlc_lcnphy_set_rx_gain(pi, gain_code);
5162 received_power =
5163 wlc_lcnphy_measure_digital_power(pi,
5164 pi_lcn->
5165 lcnphy_noise_samples);
5166 }
5167
5168 return received_power;
5169 }
5170
5171 s32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, s32 gain_index)
5172 {
5173 s32 gain = 0;
5174 s32 nominal_power_db;
5175 s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5176 input_power_db;
5177 s32 received_power, temperature;
5178 uint freq;
5179 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5180
5181 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5182
5183 gain = lcnphy_gain_table[gain_index];
5184
5185 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5186
5187 {
5188 u32 power = (received_power * 16);
5189 u32 msb1, msb2, val1, val2, diff1, diff2;
5190 msb1 = ffs(power) - 1;
5191 msb2 = msb1 + 1;
5192 val1 = 1 << msb1;
5193 val2 = 1 << msb2;
5194 diff1 = (power - val1);
5195 diff2 = (val2 - power);
5196 if (diff1 < diff2)
5197 log_val = msb1;
5198 else
5199 log_val = msb2;
5200 }
5201
5202 log_val = log_val * 3;
5203
5204 gain_mismatch = (nominal_power_db / 2) - (log_val);
5205
5206 desired_gain = gain + gain_mismatch;
5207
5208 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5209
5210 if (input_power_offset_db > 127)
5211 input_power_offset_db -= 256;
5212
5213 input_power_db = input_power_offset_db - desired_gain;
5214
5215 input_power_db =
5216 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5217
5218 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5219 if ((freq > 2427) && (freq <= 2467))
5220 input_power_db = input_power_db - 1;
5221
5222 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5223
5224 if ((temperature - 15) < -30) {
5225 input_power_db =
5226 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5227 7;
5228 } else if ((temperature - 15) < 4) {
5229 input_power_db =
5230 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5231 3;
5232 } else {
5233 input_power_db =
5234 input_power_db + (((temperature - 10 - 25) * 286) >> 12);
5235 }
5236
5237 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5238
5239 return input_power_db;
5240 }
5241
5242 static int
5243 wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, s16 filt_type)
5244 {
5245 s16 filt_index = -1;
5246 int j;
5247
5248 u16 addr[] = {
5249 0x910,
5250 0x91e,
5251 0x91f,
5252 0x924,
5253 0x925,
5254 0x926,
5255 0x920,
5256 0x921,
5257 0x927,
5258 0x928,
5259 0x929,
5260 0x922,
5261 0x923,
5262 0x930,
5263 0x931,
5264 0x932
5265 };
5266
5267 u16 addr_ofdm[] = {
5268 0x90f,
5269 0x900,
5270 0x901,
5271 0x906,
5272 0x907,
5273 0x908,
5274 0x902,
5275 0x903,
5276 0x909,
5277 0x90a,
5278 0x90b,
5279 0x904,
5280 0x905,
5281 0x90c,
5282 0x90d,
5283 0x90e
5284 };
5285
5286 if (!is_ofdm) {
5287 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
5288 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
5289 filt_index = (s16) j;
5290 break;
5291 }
5292 }
5293
5294 if (filt_index == -1) {
5295 ASSERT(false);
5296 } else {
5297 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5298 write_phy_reg(pi, addr[j],
5299 LCNPHY_txdigfiltcoeffs_cck
5300 [filt_index][j + 1]);
5301 }
5302 }
5303 } else {
5304 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
5305 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
5306 filt_index = (s16) j;
5307 break;
5308 }
5309 }
5310
5311 if (filt_index == -1) {
5312 ASSERT(false);
5313 } else {
5314 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5315 write_phy_reg(pi, addr_ofdm[j],
5316 LCNPHY_txdigfiltcoeffs_ofdm
5317 [filt_index][j + 1]);
5318 }
5319 }
5320 }
5321
5322 return (filt_index != -1) ? 0 : -1;
5323 }