staging: brcm80211: fix "ERROR: space prohibited after that ..."
[deliverable/linux.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 <siutils.h>
21 #include <bitfuncs.h>
22 #include <hndpmu.h>
23
24 #include <wlc_phy_radio.h>
25 #include <wlc_phy_int.h>
26 #include <wlc_phy_lcn.h>
27 #include <wlc_phytbl_lcn.h>
28
29 #define PLL_2064_NDIV 90
30 #define PLL_2064_LOW_END_VCO 3000
31 #define PLL_2064_LOW_END_KVCO 27
32 #define PLL_2064_HIGH_END_VCO 4200
33 #define PLL_2064_HIGH_END_KVCO 68
34 #define PLL_2064_LOOP_BW_DOUBLER 200
35 #define PLL_2064_D30_DOUBLER 10500
36 #define PLL_2064_LOOP_BW 260
37 #define PLL_2064_D30 8000
38 #define PLL_2064_CAL_REF_TO 8
39 #define PLL_2064_MHZ 1000000
40 #define PLL_2064_OPEN_LOOP_DELAY 5
41
42 #define TEMPSENSE 1
43 #define VBATSENSE 2
44
45 #define NOISE_IF_UPD_CHK_INTERVAL 1
46 #define NOISE_IF_UPD_RST_INTERVAL 60
47 #define NOISE_IF_UPD_THRESHOLD_CNT 1
48 #define NOISE_IF_UPD_TRHRESHOLD 50
49 #define NOISE_IF_UPD_TIMEOUT 1000
50 #define NOISE_IF_OFF 0
51 #define NOISE_IF_CHK 1
52 #define NOISE_IF_ON 2
53
54 #define PAPD_BLANKING_PROFILE 3
55 #define PAPD2LUT 0
56 #define PAPD_CORR_NORM 0
57 #define PAPD_BLANKING_THRESHOLD 0
58 #define PAPD_STOP_AFTER_LAST_UPDATE 0
59
60 #define LCN_TARGET_PWR 60
61
62 #define LCN_VBAT_OFFSET_433X 34649679
63 #define LCN_VBAT_SLOPE_433X 8258032
64
65 #define LCN_VBAT_SCALE_NOM 53
66 #define LCN_VBAT_SCALE_DEN 432
67
68 #define LCN_TEMPSENSE_OFFSET 80812
69 #define LCN_TEMPSENSE_DEN 2647
70
71 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
72 (0 + 8)
73 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
74 (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
75
76 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
77 (0 + 8)
78 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
79 (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
80
81 #define wlc_lcnphy_enable_tx_gain_override(pi) \
82 wlc_lcnphy_set_tx_gain_override(pi, TRUE)
83 #define wlc_lcnphy_disable_tx_gain_override(pi) \
84 wlc_lcnphy_set_tx_gain_override(pi, FALSE)
85
86 #define wlc_lcnphy_iqcal_active(pi) \
87 (read_phy_reg((pi), 0x451) & \
88 ((0x1 << 15) | (0x1 << 14)))
89
90 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
91 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
92 (pi->temppwrctrl_capable)
93 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
94 (pi->hwpwrctrl_capable)
95
96 #define SWCTRL_BT_TX 0x18
97 #define SWCTRL_OVR_DISABLE 0x40
98
99 #define AFE_CLK_INIT_MODE_TXRX2X 1
100 #define AFE_CLK_INIT_MODE_PAPD 0
101
102 #define LCNPHY_TBL_ID_IQLOCAL 0x00
103
104 #define LCNPHY_TBL_ID_RFSEQ 0x08
105 #define LCNPHY_TBL_ID_GAIN_IDX 0x0d
106 #define LCNPHY_TBL_ID_SW_CTRL 0x0f
107 #define LCNPHY_TBL_ID_GAIN_TBL 0x12
108 #define LCNPHY_TBL_ID_SPUR 0x14
109 #define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
110 #define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
111
112 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
113 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
114 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
115 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
116 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
117 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
118
119 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
120
121 #define LCNPHY_TX_PWR_CTRL_START_NPT 1
122 #define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
123
124 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
125
126 #define LCNPHY_ACI_DETECT_START 1
127 #define LCNPHY_ACI_DETECT_PROGRESS 2
128 #define LCNPHY_ACI_DETECT_STOP 3
129
130 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
131 #define LCNPHY_ACI_GLITCH_TRSH 2000
132 #define LCNPHY_ACI_TMOUT 250
133 #define LCNPHY_ACI_DETECT_TIMEOUT 2
134 #define LCNPHY_ACI_START_DELAY 0
135
136 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
137 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
138
139 #define wlc_lcnphy_total_tx_frames(pi) \
140 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + OFFSETOF(macstat_t, txallfrm))
141
142 typedef struct {
143 uint16 gm_gain;
144 uint16 pga_gain;
145 uint16 pad_gain;
146 uint16 dac_gain;
147 } lcnphy_txgains_t;
148
149 typedef enum {
150 LCNPHY_CAL_FULL,
151 LCNPHY_CAL_RECAL,
152 LCNPHY_CAL_CURRECAL,
153 LCNPHY_CAL_DIGCAL,
154 LCNPHY_CAL_GCTRL
155 } lcnphy_cal_mode_t;
156
157 typedef struct {
158 lcnphy_txgains_t gains;
159 bool useindex;
160 uint8 index;
161 } lcnphy_txcalgains_t;
162
163 typedef struct {
164 uint8 chan;
165 int16 a;
166 int16 b;
167 } lcnphy_rx_iqcomp_t;
168
169 typedef struct {
170 int16 re;
171 int16 im;
172 } lcnphy_spb_tone_t;
173
174 typedef struct {
175 uint16 re;
176 uint16 im;
177 } lcnphy_unsign16_struct;
178
179 typedef struct {
180 uint32 iq_prod;
181 uint32 i_pwr;
182 uint32 q_pwr;
183 } lcnphy_iq_est_t;
184
185 typedef struct {
186 uint16 ptcentreTs20;
187 uint16 ptcentreFactor;
188 } lcnphy_sfo_cfg_t;
189
190 typedef enum {
191 LCNPHY_PAPD_CAL_CW,
192 LCNPHY_PAPD_CAL_OFDM
193 } lcnphy_papd_cal_type_t;
194
195 typedef uint16 iqcal_gain_params_lcnphy[9];
196
197 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
198 {0, 0, 0, 0, 0, 0, 0, 0, 0},
199 };
200
201 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
202 tbl_iqcal_gainparams_lcnphy_2G,
203 };
204
205 static const uint16 iqcal_gainparams_numgains_lcnphy[1] = {
206 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
207 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
208 };
209
210 static const lcnphy_sfo_cfg_t lcnphy_sfo_cfg[] = {
211 {965, 1087},
212 {967, 1085},
213 {969, 1082},
214 {971, 1080},
215 {973, 1078},
216 {975, 1076},
217 {977, 1073},
218 {979, 1071},
219 {981, 1069},
220 {983, 1067},
221 {985, 1065},
222 {987, 1063},
223 {989, 1060},
224 {994, 1055}
225 };
226
227 static const
228 uint16 lcnphy_iqcal_loft_gainladder[] = {
229 ((2 << 8) | 0),
230 ((3 << 8) | 0),
231 ((4 << 8) | 0),
232 ((6 << 8) | 0),
233 ((8 << 8) | 0),
234 ((11 << 8) | 0),
235 ((16 << 8) | 0),
236 ((16 << 8) | 1),
237 ((16 << 8) | 2),
238 ((16 << 8) | 3),
239 ((16 << 8) | 4),
240 ((16 << 8) | 5),
241 ((16 << 8) | 6),
242 ((16 << 8) | 7),
243 ((23 << 8) | 7),
244 ((32 << 8) | 7),
245 ((45 << 8) | 7),
246 ((64 << 8) | 7),
247 ((91 << 8) | 7),
248 ((128 << 8) | 7)
249 };
250
251 static const
252 uint16 lcnphy_iqcal_ir_gainladder[] = {
253 ((1 << 8) | 0),
254 ((2 << 8) | 0),
255 ((4 << 8) | 0),
256 ((6 << 8) | 0),
257 ((8 << 8) | 0),
258 ((11 << 8) | 0),
259 ((16 << 8) | 0),
260 ((23 << 8) | 0),
261 ((32 << 8) | 0),
262 ((45 << 8) | 0),
263 ((64 << 8) | 0),
264 ((64 << 8) | 1),
265 ((64 << 8) | 2),
266 ((64 << 8) | 3),
267 ((64 << 8) | 4),
268 ((64 << 8) | 5),
269 ((64 << 8) | 6),
270 ((64 << 8) | 7),
271 ((91 << 8) | 7),
272 ((128 << 8) | 7)
273 };
274
275 static const
276 lcnphy_spb_tone_t lcnphy_spb_tone_3750[] = {
277 {88, 0},
278 {73, 49},
279 {34, 81},
280 {-17, 86},
281 {-62, 62},
282 {-86, 17},
283 {-81, -34},
284 {-49, -73},
285 {0, -88},
286 {49, -73},
287 {81, -34},
288 {86, 17},
289 {62, 62},
290 {17, 86},
291 {-34, 81},
292 {-73, 49},
293 {-88, 0},
294 {-73, -49},
295 {-34, -81},
296 {17, -86},
297 {62, -62},
298 {86, -17},
299 {81, 34},
300 {49, 73},
301 {0, 88},
302 {-49, 73},
303 {-81, 34},
304 {-86, -17},
305 {-62, -62},
306 {-17, -86},
307 {34, -81},
308 {73, -49},
309 };
310
311 static const
312 uint16 iqlo_loopback_rf_regs[20] = {
313 RADIO_2064_REG036,
314 RADIO_2064_REG11A,
315 RADIO_2064_REG03A,
316 RADIO_2064_REG025,
317 RADIO_2064_REG028,
318 RADIO_2064_REG005,
319 RADIO_2064_REG112,
320 RADIO_2064_REG0FF,
321 RADIO_2064_REG11F,
322 RADIO_2064_REG00B,
323 RADIO_2064_REG113,
324 RADIO_2064_REG007,
325 RADIO_2064_REG0FC,
326 RADIO_2064_REG0FD,
327 RADIO_2064_REG012,
328 RADIO_2064_REG057,
329 RADIO_2064_REG059,
330 RADIO_2064_REG05C,
331 RADIO_2064_REG078,
332 RADIO_2064_REG092,
333 };
334
335 static const
336 uint16 tempsense_phy_regs[14] = {
337 0x503,
338 0x4a4,
339 0x4d0,
340 0x4d9,
341 0x4da,
342 0x4a6,
343 0x938,
344 0x939,
345 0x4d8,
346 0x4d0,
347 0x4d7,
348 0x4a5,
349 0x40d,
350 0x4a2,
351 };
352
353 static const
354 uint16 rxiq_cal_rf_reg[11] = {
355 RADIO_2064_REG098,
356 RADIO_2064_REG116,
357 RADIO_2064_REG12C,
358 RADIO_2064_REG06A,
359 RADIO_2064_REG00B,
360 RADIO_2064_REG01B,
361 RADIO_2064_REG113,
362 RADIO_2064_REG01D,
363 RADIO_2064_REG114,
364 RADIO_2064_REG02E,
365 RADIO_2064_REG12A,
366 };
367
368 static const
369 lcnphy_rx_iqcomp_t lcnphy_rx_iqcomp_table_rev0[] = {
370 {1, 0, 0},
371 {2, 0, 0},
372 {3, 0, 0},
373 {4, 0, 0},
374 {5, 0, 0},
375 {6, 0, 0},
376 {7, 0, 0},
377 {8, 0, 0},
378 {9, 0, 0},
379 {10, 0, 0},
380 {11, 0, 0},
381 {12, 0, 0},
382 {13, 0, 0},
383 {14, 0, 0},
384 {34, 0, 0},
385 {38, 0, 0},
386 {42, 0, 0},
387 {46, 0, 0},
388 {36, 0, 0},
389 {40, 0, 0},
390 {44, 0, 0},
391 {48, 0, 0},
392 {52, 0, 0},
393 {56, 0, 0},
394 {60, 0, 0},
395 {64, 0, 0},
396 {100, 0, 0},
397 {104, 0, 0},
398 {108, 0, 0},
399 {112, 0, 0},
400 {116, 0, 0},
401 {120, 0, 0},
402 {124, 0, 0},
403 {128, 0, 0},
404 {132, 0, 0},
405 {136, 0, 0},
406 {140, 0, 0},
407 {149, 0, 0},
408 {153, 0, 0},
409 {157, 0, 0},
410 {161, 0, 0},
411 {165, 0, 0},
412 {184, 0, 0},
413 {188, 0, 0},
414 {192, 0, 0},
415 {196, 0, 0},
416 {200, 0, 0},
417 {204, 0, 0},
418 {208, 0, 0},
419 {212, 0, 0},
420 {216, 0, 0},
421 };
422
423 static const uint32 lcnphy_23bitgaincode_table[] = {
424 0x200100,
425 0x200200,
426 0x200004,
427 0x200014,
428 0x200024,
429 0x200034,
430 0x200134,
431 0x200234,
432 0x200334,
433 0x200434,
434 0x200037,
435 0x200137,
436 0x200237,
437 0x200337,
438 0x200437,
439 0x000035,
440 0x000135,
441 0x000235,
442 0x000037,
443 0x000137,
444 0x000237,
445 0x000337,
446 0x00013f,
447 0x00023f,
448 0x00033f,
449 0x00034f,
450 0x00044f,
451 0x00144f,
452 0x00244f,
453 0x00254f,
454 0x00354f,
455 0x00454f,
456 0x00464f,
457 0x01464f,
458 0x02464f,
459 0x03464f,
460 0x04464f,
461 };
462
463 static const int8 lcnphy_gain_table[] = {
464 -16,
465 -13,
466 10,
467 7,
468 4,
469 0,
470 3,
471 6,
472 9,
473 12,
474 15,
475 18,
476 21,
477 24,
478 27,
479 30,
480 33,
481 36,
482 39,
483 42,
484 45,
485 48,
486 50,
487 53,
488 56,
489 59,
490 62,
491 65,
492 68,
493 71,
494 74,
495 77,
496 80,
497 83,
498 86,
499 89,
500 92,
501 };
502
503 static const int8 lcnphy_gain_index_offset_for_rssi[] = {
504 7,
505 7,
506 7,
507 7,
508 7,
509 7,
510 7,
511 8,
512 7,
513 7,
514 6,
515 7,
516 7,
517 4,
518 4,
519 4,
520 4,
521 4,
522 4,
523 4,
524 4,
525 3,
526 3,
527 3,
528 3,
529 3,
530 3,
531 4,
532 2,
533 2,
534 2,
535 2,
536 2,
537 2,
538 -1,
539 -2,
540 -2,
541 -2
542 };
543
544 extern CONST uint8 spur_tbl_rev0[];
545 extern CONST uint32 dot11lcnphytbl_rx_gain_info_sz_rev1;
546 extern CONST dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
547 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
548 extern CONST dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
549
550 typedef struct _chan_info_2064_lcnphy {
551 uint chan;
552 uint freq;
553 uint8 logen_buftune;
554 uint8 logen_rccr_tx;
555 uint8 txrf_mix_tune_ctrl;
556 uint8 pa_input_tune_g;
557 uint8 logen_rccr_rx;
558 uint8 pa_rxrf_lna1_freq_tune;
559 uint8 pa_rxrf_lna2_freq_tune;
560 uint8 rxrf_rxrf_spare1;
561 } chan_info_2064_lcnphy_t;
562
563 static chan_info_2064_lcnphy_t chan_info_2064_lcnphy[] = {
564 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
565 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
566 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
567 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
576 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
578 };
579
580 lcnphy_radio_regs_t lcnphy_radio_regs_2064[] = {
581 {0x00, 0, 0, 0, 0},
582 {0x01, 0x64, 0x64, 0, 0},
583 {0x02, 0x20, 0x20, 0, 0},
584 {0x03, 0x66, 0x66, 0, 0},
585 {0x04, 0xf8, 0xf8, 0, 0},
586 {0x05, 0, 0, 0, 0},
587 {0x06, 0x10, 0x10, 0, 0},
588 {0x07, 0, 0, 0, 0},
589 {0x08, 0, 0, 0, 0},
590 {0x09, 0, 0, 0, 0},
591 {0x0A, 0x37, 0x37, 0, 0},
592 {0x0B, 0x6, 0x6, 0, 0},
593 {0x0C, 0x55, 0x55, 0, 0},
594 {0x0D, 0x8b, 0x8b, 0, 0},
595 {0x0E, 0, 0, 0, 0},
596 {0x0F, 0x5, 0x5, 0, 0},
597 {0x10, 0, 0, 0, 0},
598 {0x11, 0xe, 0xe, 0, 0},
599 {0x12, 0, 0, 0, 0},
600 {0x13, 0xb, 0xb, 0, 0},
601 {0x14, 0x2, 0x2, 0, 0},
602 {0x15, 0x12, 0x12, 0, 0},
603 {0x16, 0x12, 0x12, 0, 0},
604 {0x17, 0xc, 0xc, 0, 0},
605 {0x18, 0xc, 0xc, 0, 0},
606 {0x19, 0xc, 0xc, 0, 0},
607 {0x1A, 0x8, 0x8, 0, 0},
608 {0x1B, 0x2, 0x2, 0, 0},
609 {0x1C, 0, 0, 0, 0},
610 {0x1D, 0x1, 0x1, 0, 0},
611 {0x1E, 0x12, 0x12, 0, 0},
612 {0x1F, 0x6e, 0x6e, 0, 0},
613 {0x20, 0x2, 0x2, 0, 0},
614 {0x21, 0x23, 0x23, 0, 0},
615 {0x22, 0x8, 0x8, 0, 0},
616 {0x23, 0, 0, 0, 0},
617 {0x24, 0, 0, 0, 0},
618 {0x25, 0xc, 0xc, 0, 0},
619 {0x26, 0x33, 0x33, 0, 0},
620 {0x27, 0x55, 0x55, 0, 0},
621 {0x28, 0, 0, 0, 0},
622 {0x29, 0x30, 0x30, 0, 0},
623 {0x2A, 0xb, 0xb, 0, 0},
624 {0x2B, 0x1b, 0x1b, 0, 0},
625 {0x2C, 0x3, 0x3, 0, 0},
626 {0x2D, 0x1b, 0x1b, 0, 0},
627 {0x2E, 0, 0, 0, 0},
628 {0x2F, 0x20, 0x20, 0, 0},
629 {0x30, 0xa, 0xa, 0, 0},
630 {0x31, 0, 0, 0, 0},
631 {0x32, 0x62, 0x62, 0, 0},
632 {0x33, 0x19, 0x19, 0, 0},
633 {0x34, 0x33, 0x33, 0, 0},
634 {0x35, 0x77, 0x77, 0, 0},
635 {0x36, 0, 0, 0, 0},
636 {0x37, 0x70, 0x70, 0, 0},
637 {0x38, 0x3, 0x3, 0, 0},
638 {0x39, 0xf, 0xf, 0, 0},
639 {0x3A, 0x6, 0x6, 0, 0},
640 {0x3B, 0xcf, 0xcf, 0, 0},
641 {0x3C, 0x1a, 0x1a, 0, 0},
642 {0x3D, 0x6, 0x6, 0, 0},
643 {0x3E, 0x42, 0x42, 0, 0},
644 {0x3F, 0, 0, 0, 0},
645 {0x40, 0xfb, 0xfb, 0, 0},
646 {0x41, 0x9a, 0x9a, 0, 0},
647 {0x42, 0x7a, 0x7a, 0, 0},
648 {0x43, 0x29, 0x29, 0, 0},
649 {0x44, 0, 0, 0, 0},
650 {0x45, 0x8, 0x8, 0, 0},
651 {0x46, 0xce, 0xce, 0, 0},
652 {0x47, 0x27, 0x27, 0, 0},
653 {0x48, 0x62, 0x62, 0, 0},
654 {0x49, 0x6, 0x6, 0, 0},
655 {0x4A, 0x58, 0x58, 0, 0},
656 {0x4B, 0xf7, 0xf7, 0, 0},
657 {0x4C, 0, 0, 0, 0},
658 {0x4D, 0xb3, 0xb3, 0, 0},
659 {0x4E, 0, 0, 0, 0},
660 {0x4F, 0x2, 0x2, 0, 0},
661 {0x50, 0, 0, 0, 0},
662 {0x51, 0x9, 0x9, 0, 0},
663 {0x52, 0x5, 0x5, 0, 0},
664 {0x53, 0x17, 0x17, 0, 0},
665 {0x54, 0x38, 0x38, 0, 0},
666 {0x55, 0, 0, 0, 0},
667 {0x56, 0, 0, 0, 0},
668 {0x57, 0xb, 0xb, 0, 0},
669 {0x58, 0, 0, 0, 0},
670 {0x59, 0, 0, 0, 0},
671 {0x5A, 0, 0, 0, 0},
672 {0x5B, 0, 0, 0, 0},
673 {0x5C, 0, 0, 0, 0},
674 {0x5D, 0, 0, 0, 0},
675 {0x5E, 0x88, 0x88, 0, 0},
676 {0x5F, 0xcc, 0xcc, 0, 0},
677 {0x60, 0x74, 0x74, 0, 0},
678 {0x61, 0x74, 0x74, 0, 0},
679 {0x62, 0x74, 0x74, 0, 0},
680 {0x63, 0x44, 0x44, 0, 0},
681 {0x64, 0x77, 0x77, 0, 0},
682 {0x65, 0x44, 0x44, 0, 0},
683 {0x66, 0x77, 0x77, 0, 0},
684 {0x67, 0x55, 0x55, 0, 0},
685 {0x68, 0x77, 0x77, 0, 0},
686 {0x69, 0x77, 0x77, 0, 0},
687 {0x6A, 0, 0, 0, 0},
688 {0x6B, 0x7f, 0x7f, 0, 0},
689 {0x6C, 0x8, 0x8, 0, 0},
690 {0x6D, 0, 0, 0, 0},
691 {0x6E, 0x88, 0x88, 0, 0},
692 {0x6F, 0x66, 0x66, 0, 0},
693 {0x70, 0x66, 0x66, 0, 0},
694 {0x71, 0x28, 0x28, 0, 0},
695 {0x72, 0x55, 0x55, 0, 0},
696 {0x73, 0x4, 0x4, 0, 0},
697 {0x74, 0, 0, 0, 0},
698 {0x75, 0, 0, 0, 0},
699 {0x76, 0, 0, 0, 0},
700 {0x77, 0x1, 0x1, 0, 0},
701 {0x78, 0xd6, 0xd6, 0, 0},
702 {0x79, 0, 0, 0, 0},
703 {0x7A, 0, 0, 0, 0},
704 {0x7B, 0, 0, 0, 0},
705 {0x7C, 0, 0, 0, 0},
706 {0x7D, 0, 0, 0, 0},
707 {0x7E, 0, 0, 0, 0},
708 {0x7F, 0, 0, 0, 0},
709 {0x80, 0, 0, 0, 0},
710 {0x81, 0, 0, 0, 0},
711 {0x82, 0, 0, 0, 0},
712 {0x83, 0xb4, 0xb4, 0, 0},
713 {0x84, 0x1, 0x1, 0, 0},
714 {0x85, 0x20, 0x20, 0, 0},
715 {0x86, 0x5, 0x5, 0, 0},
716 {0x87, 0xff, 0xff, 0, 0},
717 {0x88, 0x7, 0x7, 0, 0},
718 {0x89, 0x77, 0x77, 0, 0},
719 {0x8A, 0x77, 0x77, 0, 0},
720 {0x8B, 0x77, 0x77, 0, 0},
721 {0x8C, 0x77, 0x77, 0, 0},
722 {0x8D, 0x8, 0x8, 0, 0},
723 {0x8E, 0xa, 0xa, 0, 0},
724 {0x8F, 0x8, 0x8, 0, 0},
725 {0x90, 0x18, 0x18, 0, 0},
726 {0x91, 0x5, 0x5, 0, 0},
727 {0x92, 0x1f, 0x1f, 0, 0},
728 {0x93, 0x10, 0x10, 0, 0},
729 {0x94, 0x3, 0x3, 0, 0},
730 {0x95, 0, 0, 0, 0},
731 {0x96, 0, 0, 0, 0},
732 {0x97, 0xaa, 0xaa, 0, 0},
733 {0x98, 0, 0, 0, 0},
734 {0x99, 0x23, 0x23, 0, 0},
735 {0x9A, 0x7, 0x7, 0, 0},
736 {0x9B, 0xf, 0xf, 0, 0},
737 {0x9C, 0x10, 0x10, 0, 0},
738 {0x9D, 0x3, 0x3, 0, 0},
739 {0x9E, 0x4, 0x4, 0, 0},
740 {0x9F, 0x20, 0x20, 0, 0},
741 {0xA0, 0, 0, 0, 0},
742 {0xA1, 0, 0, 0, 0},
743 {0xA2, 0, 0, 0, 0},
744 {0xA3, 0, 0, 0, 0},
745 {0xA4, 0x1, 0x1, 0, 0},
746 {0xA5, 0x77, 0x77, 0, 0},
747 {0xA6, 0x77, 0x77, 0, 0},
748 {0xA7, 0x77, 0x77, 0, 0},
749 {0xA8, 0x77, 0x77, 0, 0},
750 {0xA9, 0x8c, 0x8c, 0, 0},
751 {0xAA, 0x88, 0x88, 0, 0},
752 {0xAB, 0x78, 0x78, 0, 0},
753 {0xAC, 0x57, 0x57, 0, 0},
754 {0xAD, 0x88, 0x88, 0, 0},
755 {0xAE, 0, 0, 0, 0},
756 {0xAF, 0x8, 0x8, 0, 0},
757 {0xB0, 0x88, 0x88, 0, 0},
758 {0xB1, 0, 0, 0, 0},
759 {0xB2, 0x1b, 0x1b, 0, 0},
760 {0xB3, 0x3, 0x3, 0, 0},
761 {0xB4, 0x24, 0x24, 0, 0},
762 {0xB5, 0x3, 0x3, 0, 0},
763 {0xB6, 0x1b, 0x1b, 0, 0},
764 {0xB7, 0x24, 0x24, 0, 0},
765 {0xB8, 0x3, 0x3, 0, 0},
766 {0xB9, 0, 0, 0, 0},
767 {0xBA, 0xaa, 0xaa, 0, 0},
768 {0xBB, 0, 0, 0, 0},
769 {0xBC, 0x4, 0x4, 0, 0},
770 {0xBD, 0, 0, 0, 0},
771 {0xBE, 0x8, 0x8, 0, 0},
772 {0xBF, 0x11, 0x11, 0, 0},
773 {0xC0, 0, 0, 0, 0},
774 {0xC1, 0, 0, 0, 0},
775 {0xC2, 0x62, 0x62, 0, 0},
776 {0xC3, 0x1e, 0x1e, 0, 0},
777 {0xC4, 0x33, 0x33, 0, 0},
778 {0xC5, 0x37, 0x37, 0, 0},
779 {0xC6, 0, 0, 0, 0},
780 {0xC7, 0x70, 0x70, 0, 0},
781 {0xC8, 0x1e, 0x1e, 0, 0},
782 {0xC9, 0x6, 0x6, 0, 0},
783 {0xCA, 0x4, 0x4, 0, 0},
784 {0xCB, 0x2f, 0x2f, 0, 0},
785 {0xCC, 0xf, 0xf, 0, 0},
786 {0xCD, 0, 0, 0, 0},
787 {0xCE, 0xff, 0xff, 0, 0},
788 {0xCF, 0x8, 0x8, 0, 0},
789 {0xD0, 0x3f, 0x3f, 0, 0},
790 {0xD1, 0x3f, 0x3f, 0, 0},
791 {0xD2, 0x3f, 0x3f, 0, 0},
792 {0xD3, 0, 0, 0, 0},
793 {0xD4, 0, 0, 0, 0},
794 {0xD5, 0, 0, 0, 0},
795 {0xD6, 0xcc, 0xcc, 0, 0},
796 {0xD7, 0, 0, 0, 0},
797 {0xD8, 0x8, 0x8, 0, 0},
798 {0xD9, 0x8, 0x8, 0, 0},
799 {0xDA, 0x8, 0x8, 0, 0},
800 {0xDB, 0x11, 0x11, 0, 0},
801 {0xDC, 0, 0, 0, 0},
802 {0xDD, 0x87, 0x87, 0, 0},
803 {0xDE, 0x88, 0x88, 0, 0},
804 {0xDF, 0x8, 0x8, 0, 0},
805 {0xE0, 0x8, 0x8, 0, 0},
806 {0xE1, 0x8, 0x8, 0, 0},
807 {0xE2, 0, 0, 0, 0},
808 {0xE3, 0, 0, 0, 0},
809 {0xE4, 0, 0, 0, 0},
810 {0xE5, 0xf5, 0xf5, 0, 0},
811 {0xE6, 0x30, 0x30, 0, 0},
812 {0xE7, 0x1, 0x1, 0, 0},
813 {0xE8, 0, 0, 0, 0},
814 {0xE9, 0xff, 0xff, 0, 0},
815 {0xEA, 0, 0, 0, 0},
816 {0xEB, 0, 0, 0, 0},
817 {0xEC, 0x22, 0x22, 0, 0},
818 {0xED, 0, 0, 0, 0},
819 {0xEE, 0, 0, 0, 0},
820 {0xEF, 0, 0, 0, 0},
821 {0xF0, 0x3, 0x3, 0, 0},
822 {0xF1, 0x1, 0x1, 0, 0},
823 {0xF2, 0, 0, 0, 0},
824 {0xF3, 0, 0, 0, 0},
825 {0xF4, 0, 0, 0, 0},
826 {0xF5, 0, 0, 0, 0},
827 {0xF6, 0, 0, 0, 0},
828 {0xF7, 0x6, 0x6, 0, 0},
829 {0xF8, 0, 0, 0, 0},
830 {0xF9, 0, 0, 0, 0},
831 {0xFA, 0x40, 0x40, 0, 0},
832 {0xFB, 0, 0, 0, 0},
833 {0xFC, 0x1, 0x1, 0, 0},
834 {0xFD, 0x80, 0x80, 0, 0},
835 {0xFE, 0x2, 0x2, 0, 0},
836 {0xFF, 0x10, 0x10, 0, 0},
837 {0x100, 0x2, 0x2, 0, 0},
838 {0x101, 0x1e, 0x1e, 0, 0},
839 {0x102, 0x1e, 0x1e, 0, 0},
840 {0x103, 0, 0, 0, 0},
841 {0x104, 0x1f, 0x1f, 0, 0},
842 {0x105, 0, 0x8, 0, 1},
843 {0x106, 0x2a, 0x2a, 0, 0},
844 {0x107, 0xf, 0xf, 0, 0},
845 {0x108, 0, 0, 0, 0},
846 {0x109, 0, 0, 0, 0},
847 {0x10A, 0, 0, 0, 0},
848 {0x10B, 0, 0, 0, 0},
849 {0x10C, 0, 0, 0, 0},
850 {0x10D, 0, 0, 0, 0},
851 {0x10E, 0, 0, 0, 0},
852 {0x10F, 0, 0, 0, 0},
853 {0x110, 0, 0, 0, 0},
854 {0x111, 0, 0, 0, 0},
855 {0x112, 0, 0, 0, 0},
856 {0x113, 0, 0, 0, 0},
857 {0x114, 0, 0, 0, 0},
858 {0x115, 0, 0, 0, 0},
859 {0x116, 0, 0, 0, 0},
860 {0x117, 0, 0, 0, 0},
861 {0x118, 0, 0, 0, 0},
862 {0x119, 0, 0, 0, 0},
863 {0x11A, 0, 0, 0, 0},
864 {0x11B, 0, 0, 0, 0},
865 {0x11C, 0x1, 0x1, 0, 0},
866 {0x11D, 0, 0, 0, 0},
867 {0x11E, 0, 0, 0, 0},
868 {0x11F, 0, 0, 0, 0},
869 {0x120, 0, 0, 0, 0},
870 {0x121, 0, 0, 0, 0},
871 {0x122, 0x80, 0x80, 0, 0},
872 {0x123, 0, 0, 0, 0},
873 {0x124, 0xf8, 0xf8, 0, 0},
874 {0x125, 0, 0, 0, 0},
875 {0x126, 0, 0, 0, 0},
876 {0x127, 0, 0, 0, 0},
877 {0x128, 0, 0, 0, 0},
878 {0x129, 0, 0, 0, 0},
879 {0x12A, 0, 0, 0, 0},
880 {0x12B, 0, 0, 0, 0},
881 {0x12C, 0, 0, 0, 0},
882 {0x12D, 0, 0, 0, 0},
883 {0x12E, 0, 0, 0, 0},
884 {0x12F, 0, 0, 0, 0},
885 {0x130, 0, 0, 0, 0},
886 {0xFFFF, 0, 0, 0, 0}
887 };
888
889 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
890 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
891
892 uint16
893 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
894 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
895 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
896 128, 64,},
897 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
898 167, 93,},
899 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
900 128, 64,},
901 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
902 170, 340, 170,},
903 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
904 256, 185, 256,},
905 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
906 256, 273, 256,},
907 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
908 256, 352, 256,},
909 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
910 128, 233, 128,},
911 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
912 1881, 256,},
913 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
914 1881, 256,},
915 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
916 384, 288,},
917 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
918 128, 384, 288,},
919 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
920 170, 340, 170,},
921 };
922
923 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
924 uint16
925 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
926 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
927 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
928 0x278, 0xfea0, 0x80, 0x100, 0x80,},
929 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
930 750, 0xFE2B, 212, 0xFFCE, 212,},
931 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
932 0xFEF2, 128, 0xFFE2, 128}
933 };
934
935 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
936 mod_phy_reg(pi, 0x4a4, \
937 (0x1ff << 0), \
938 (uint16)(idx) << 0)
939
940 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
941 mod_phy_reg(pi, 0x4a5, \
942 (0x7 << 8), \
943 (uint16)(npt) << 8)
944
945 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
946 (read_phy_reg((pi), 0x4a4) & \
947 ((0x1 << 15) | \
948 (0x1 << 14) | \
949 (0x1 << 13)))
950
951 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
952 ((read_phy_reg(pi, 0x4a5) & \
953 (0x7 << 8)) >> \
954 8)
955
956 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
957 (read_phy_reg(pi, 0x473) & 0x1ff)
958
959 #define wlc_lcnphy_get_target_tx_pwr(pi) \
960 ((read_phy_reg(pi, 0x4a7) & \
961 (0xff << 0)) >> \
962 0)
963
964 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
965 mod_phy_reg(pi, 0x4a7, \
966 (0xff << 0), \
967 (uint16)(target) << 0)
968
969 #define wlc_radio_2064_rcal_done(pi) (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
970 #define tempsense_done(pi) (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
971
972 #define LCNPHY_IQLOCC_READ(val) ((uint8)(-(int8)(((val) & 0xf0) >> 4) + (int8)((val) & 0x0f)))
973 #define FIXED_TXPWR 78
974 #define LCNPHY_TEMPSENSE(val) ((int16)((val > 255)?(val - 512):val))
975
976 static uint32 wlc_lcnphy_qdiv_roundup(uint32 divident, uint32 divisor,
977 uint8 precision);
978 static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
979 uint16 ext_lna, uint16 trsw,
980 uint16 biq2, uint16 biq1,
981 uint16 tia, uint16 lna2,
982 uint16 lna1);
983 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
984 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 gain);
985 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
986 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, uint8 m0);
987 static uint8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
988 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
989 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
990 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
991 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
992 static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
993 lcnphy_txgains_t *target_gains);
994 static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, uint16 num_samps,
995 uint8 wait_time, lcnphy_iq_est_t *iq_est);
996 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, uint16 num_samps);
997 static uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
998 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, uint8 mode);
999 extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1000 extern void wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng,
1001 uint8 rate, struct ether_addr *sa,
1002 uint32 wait_delay);
1003 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1004 uint8 channel);
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 uint16 thresh, int16 *ptr, int mode);
1011 static int wlc_lcnphy_calc_floor(int16 coeff, int type);
1012 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1013 uint16 *values_to_save);
1014 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1015 uint16 *values_to_save);
1016 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x,
1017 int16 coeff_y);
1018 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1019 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1020 int num_levels, int step_size_lg2);
1021 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
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 int16 filt_type);
1035 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 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, uint32 tbl_id,
1049 CONST void *tbl_ptr, uint32 tbl_len,
1050 uint32 tbl_width, uint32 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, uint32 tbl_id,
1063 CONST void *tbl_ptr, uint32 tbl_len,
1064 uint32 tbl_width, uint32 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 uint32
1077 wlc_lcnphy_qdiv_roundup(uint32 dividend, uint32 divisor, uint8 precision)
1078 {
1079 uint32 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(int16 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 int8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1125 {
1126 int8 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 (int8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1134 / 2);
1135 else
1136 index = pi_lcn->lcnphy_current_index;
1137 return index;
1138 }
1139
1140 static uint32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, uint16 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 uint16 afectrlovr, afectrlovrval;
1152 afectrlovr = read_phy_reg(pi, 0x43b);
1153 afectrlovrval = read_phy_reg(pi, 0x43c);
1154 if (channel != 0) {
1155 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
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 uint16 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 uint8 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, uint16 dac_gain)
1254 {
1255 uint16 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 uint16 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 uint16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1276 {
1277 uint16 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 uint16 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, uint8 m0)
1313 {
1314 uint16 m0m1 = (uint16) 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 uint32 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 uint16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1394 {
1395 uint16 N1, N2, N3, N4, N5, N6, N;
1396 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1397 >> 0);
1398 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1399 >> 12);
1400 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1401 >> 0);
1402 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1403 >> 8);
1404 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1405 >> 0);
1406 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1407 >> 8);
1408 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1409 if (N < 1600)
1410 N = 1600;
1411 return N;
1412 }
1413
1414 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1415 {
1416 uint16 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 uint32 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 uint16 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 int32 wlc_lcnphy_tssi2dbm(int32 tssi, int32 a1, int32 b0, int32 b1)
1592 {
1593 int32 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 uint32 rate_table[WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM +
1616 WLC_NUM_RATES_MCS_1_STREAM];
1617 uint i, j;
1618 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1619 return;
1620
1621 for (i = 0, j = 0; i < ARRAYSIZE(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] = (uint32) ((int32) (-pi->tx_power_offset[j]));
1627 }
1628
1629 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1630 tab.tbl_width = 32;
1631 tab.tbl_len = ARRAYSIZE(rate_table);
1632 tab.tbl_ptr = rate_table;
1633 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1634 wlc_lcnphy_write_table(pi, &tab);
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, int8 index)
1644 {
1645 uint32 cck_offset[4] = { 22, 22, 22, 22 };
1646 uint32 ofdm_offset, reg_offset_cck;
1647 int i;
1648 uint16 index2;
1649 phytbl_info_t tab;
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 = (uint16) (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 int8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1697 {
1698 int8 index, delta_brd, delta_temp, new_index, tempcorrx;
1699 int16 manp, meas_temp, temp_diff;
1700 bool neg = 0;
1701 uint16 temp;
1702 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
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 = (uint16) 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 = (int8) wlc_lcnphy_qdiv_roundup((uint32) (temp_diff * 192),
1734 (uint32) (pi_lcn->
1735 lcnphy_tempsense_slope
1736 * 10), 0);
1737 if (neg)
1738 delta_temp = -delta_temp;
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 = (int8) (pi_lcn->lcnphy_tempcorrx - 64);
1745 else
1746 tempcorrx = (int8) pi_lcn->lcnphy_tempcorrx;
1747 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1748 tempcorrx = 4;
1749 new_index =
1750 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1751 new_index += tempcorrx;
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 uint16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, uint16 mode)
1762 {
1763
1764 uint16 current_mode = mode;
1765 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1766 mode == LCNPHY_TX_PWR_CTRL_HW)
1767 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1768 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1769 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1770 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1771 return current_mode;
1772 }
1773
1774 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, uint16 mode)
1775 {
1776 uint16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1777 int8 index;
1778 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
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 = (int8)
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 uint16 hash;
1853 uint8 band_idx;
1854 int j;
1855 uint16 ncorr_override[5];
1856 uint16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1857 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1858 };
1859
1860 uint16 commands_fullcal[] = {
1861 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1862
1863 uint16 commands_recal[] = {
1864 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1865
1866 uint16 command_nums_fullcal[] = {
1867 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1868
1869 uint16 command_nums_recal[] = {
1870 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1871 uint16 *command_nums = command_nums_fullcal;
1872
1873 uint16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1874 uint16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1875 uint16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
1876 bool tx_gain_override_old;
1877 lcnphy_txgains_t old_gains;
1878 uint i, n_cal_cmds = 0, n_cal_start = 0;
1879 uint16 *values_to_save;
1880 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1881
1882 if (NORADIO_ENAB(pi->pubpi))
1883 return;
1884
1885 values_to_save = MALLOC(pi->sh->osh, sizeof(uint16) * 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 = ARRAYSIZE(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 = ARRAYSIZE(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 ARRAYSIZE(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 ARRAYSIZE(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 uint16 zero_diq = 0;
1998 uint16 best_coeffs[11];
1999 uint16 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 ARRAYSIZE(best_coeffs), 16, 96);
2030 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2031 best_coeffs,
2032 ARRAYSIZE(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 ARRAYSIZE(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 ARRAYSIZE(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(uint16));
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 uint16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2088 idleTssi0_regvalue_2C;
2089 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2090 uint16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2091 uint16 SAVE_jtag_bb_afe_switch =
2092 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2093 uint16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2094 uint16 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, uint8 mode)
2149 {
2150 bool suspend;
2151 uint16 save_txpwrCtrlEn;
2152 uint8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2153 uint16 auxpga_vmid;
2154 phytbl_info_t tab;
2155 uint32 val;
2156 uint8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2157 save_reg112;
2158 uint16 values_to_save[14];
2159 int8 index;
2160 int i;
2161 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2162 OSL_DELAY(999);
2163
2164 save_reg007 = (uint8) read_radio_reg(pi, RADIO_2064_REG007);
2165 save_reg0FF = (uint8) read_radio_reg(pi, RADIO_2064_REG0FF);
2166 save_reg11F = (uint8) read_radio_reg(pi, RADIO_2064_REG11F);
2167 save_reg005 = (uint8) read_radio_reg(pi, RADIO_2064_REG005);
2168 save_reg025 = (uint8) read_radio_reg(pi, RADIO_2064_REG025);
2169 save_reg112 = (uint8) 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 (uint16) ((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, (uint16) save_reg007);
2275 write_radio_reg(pi, RADIO_2064_REG0FF, (uint16) save_reg0FF);
2276 write_radio_reg(pi, RADIO_2064_REG11F, (uint16) save_reg11F);
2277 write_radio_reg(pi, RADIO_2064_REG005, (uint16) save_reg005);
2278 write_radio_reg(pi, RADIO_2064_REG025, (uint16) save_reg025);
2279 write_radio_reg(pi, RADIO_2064_REG112, (uint16) 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 uint8 bbmult;
2294 phytbl_info_t tab;
2295 int32 a1, b0, b1;
2296 int32 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 uint8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2369 {
2370 uint16 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 (uint8) ((m0m1 & 0xff00) >> 8);
2381 }
2382
2383 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, uint16 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 uint8 *ei0, uint8 *eq0, uint8 *fi0, uint8 *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 uint16 dac_gain;
2406
2407 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2408 gains->dac_gain = (dac_gain & 0x380) >> 7;
2409
2410 {
2411 uint16 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, uint16 a, uint16 b)
2423 {
2424 phytbl_info_t tab;
2425 uint16 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, uint16 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 uint16 a, b;
2454 uint8 bb_mult;
2455 uint32 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 = (int8) index;
2462 pi_lcn->lcnphy_current_index = (uint8) 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 = (uint16) (txgain & 0xff);
2480 gains.pga_gain = (uint16) (txgain >> 8) & 0xff;
2481 gains.pad_gain = (uint16) (txgain >> 16) & 0xff;
2482 gains.dac_gain = (uint16) (bbmultiqcomp >> 28) & 0x07;
2483 wlc_lcnphy_set_tx_gain(pi, &gains);
2484 wlc_lcnphy_set_pa_gain(pi, (uint16) (txgain >> 24) & 0x7f);
2485
2486 bb_mult = (uint8) ((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 = (uint16) ((bbmultiqcomp >> 10) & 0x3ff);
2494 b = (uint16) (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, (uint16) 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 uint32 j;
2524 phytbl_info_t tab;
2525 uint32 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 uint16 trsw,
2543 uint16 ext_lna,
2544 uint16 biq2,
2545 uint16 biq1,
2546 uint16 tia, uint16 lna2, uint16 lna1)
2547 {
2548 uint16 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 uint16 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, ~(uint16) ((0x1 << 1) | (0x1 << 4)));
2605
2606 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2607
2608 and_phy_reg(pi, 0x44c,
2609 ~(uint16) ((0x1 << 3) |
2610 (0x1 << 5) |
2611 (0x1 << 12) |
2612 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2613
2614 and_phy_reg(pi, 0x44d,
2615 ~(uint16) ((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 ~(uint16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2622
2623 and_phy_reg(pi, 0x4fa,
2624 ~(uint16) ((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 uint16 num_samps,
2680 uint16 num_loops, uint16 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, (uint16) ~(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 uint8 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, int32 f_kHz, uint16 max_val,
2730 bool iqcalmode)
2731 {
2732 uint8 phy_bw;
2733 uint16 num_samps, t, k;
2734 uint32 bw;
2735 fixed theta = 0, rot = 0;
2736 cint32 tone_samp;
2737 uint32 data_buf[64];
2738 uint16 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 <= ARRAYSIZE(data_buf));
2760 k++;
2761 } while ((num_samps * (uint32) (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 = (uint16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2775 q_samp = (uint16) (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 int16 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, (uint16) ~((0x1 << 1) | (0x1 << 0)));
2828 }
2829
2830 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, uint16 *a, uint16 *b)
2831 {
2832 uint16 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 uint16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2847 {
2848 phytbl_info_t tab;
2849 uint16 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 uint8 save_bb_mult;
2866 uint16 a, b, didq, save_pa_gain = 0;
2867 uint idx, SAVE_txpwrindex = 0xFF;
2868 uint32 val;
2869 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2870 phytbl_info_t tab;
2871 uint8 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((int8) fi0) == 15) && (ABS((int8) 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 ((uint32) (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 int16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2976 {
2977 uint16 tempsenseval1, tempsenseval2;
2978 int16 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 = (int16) (tempsenseval1 - 512);
2997 else
2998 avg = (int16) tempsenseval1;
2999
3000 if (tempsenseval2 > 255)
3001 avg += (int16) (tempsenseval2 - 512);
3002 else
3003 avg += (int16) 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 uint16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3021 {
3022 uint16 tempsenseval1, tempsenseval2;
3023 int32 avg = 0;
3024 bool suspend = 0;
3025 uint16 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 (uint16) avg;
3079 }
3080
3081 int8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
3082 {
3083 int32 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 (int8) degree;
3088 }
3089
3090 int8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3091 {
3092 uint16 vbatsenseval;
3093 int32 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 = (int32) (vbatsenseval - 512);
3112 else
3113 avg = (int32) 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 (int8) avg;
3124 }
3125
3126 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, uint8 mode)
3127 {
3128 uint8 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 uint16 num_samps,
3143 uint8 wait_time, lcnphy_iq_est_t *iq_est)
3144 {
3145 int wait_count = 0;
3146 bool result = TRUE;
3147 uint8 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), ((uint16) 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 = ((uint32) read_phy_reg(pi, 0x483) << 16) |
3173 (uint32) read_phy_reg(pi, 0x484);
3174 iq_est->i_pwr = ((uint32) read_phy_reg(pi, 0x485) << 16) |
3175 (uint32) read_phy_reg(pi, 0x486);
3176 iq_est->q_pwr = ((uint32) read_phy_reg(pi, 0x487) << 16) |
3177 (uint32) 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, uint16 num_samps)
3188 {
3189 #define LCNPHY_MIN_RXIQ_PWR 2
3190 bool result;
3191 uint16 a0_new, b0_new;
3192 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3193 int32 a, b, temp;
3194 int16 iq_nbits, qq_nbits, arsh, brsh;
3195 int32 iq;
3196 uint32 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 = (int32) 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 = (int32) (ii >> arsh);
3227 if (temp == 0) {
3228 return FALSE;
3229 }
3230 } else {
3231 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3232 temp = (int32) (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 = (int32) (ii >> brsh);
3242 if (temp == 0) {
3243 return FALSE;
3244 }
3245 } else {
3246 b = (qq << (31 - qq_nbits));
3247 temp = (int32) (ii << -brsh);
3248 if (temp == 0) {
3249 return FALSE;
3250 }
3251 }
3252 b /= temp;
3253 b -= a * a;
3254 b = (int32) wlc_phy_sqrt_int((uint32) b);
3255 b -= (1 << 10);
3256 a0_new = (uint16) (a & 0x3ff);
3257 b0_new = (uint16) (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 uint16 tx_pwr_ctrl;
3279 uint8 tx_gain_index_old = 0;
3280 bool result = FALSE, tx_gain_override_old = FALSE;
3281 uint16 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 uint32 received_power, rx_pwr_threshold;
3287 uint16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3288 uint16 values_to_save[11];
3289 int16 *ptr;
3290 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3291
3292 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 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 (uint16)
3305 iqcomp[iqcomp_sz].a,
3306 (uint16)
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 (uint16)
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(int16));
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 int8 index;
3454 uint16 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 uint16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3481 int8 index;
3482 phytbl_info_t tab;
3483 int32 a1, b0, b1;
3484 int32 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 = ARRAYSIZE(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 uint16 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, int8 *ofdm_pwr, int8 *cck_pwr)
3590 {
3591 int8 cck_offset;
3592 uint16 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 = (int8) (((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 uint8 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
3670 wlc_lcnphy_pktengtx(wlc_phy_t *ppi, wl_pkteng_t *pkteng, uint8 rate,
3671 struct ether_addr *sa, uint32 wait_delay)
3672 {
3673 }
3674
3675 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3676 {
3677 int8 index;
3678 uint16 index2;
3679 phy_info_t *pi = (phy_info_t *) ppi;
3680 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3681 uint16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3682 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3683 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3684 index2 = (uint16) (index * 2);
3685 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3686
3687 pi_lcn->lcnphy_current_index = (int8)
3688 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3689 }
3690 }
3691
3692 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, uint16 a, uint16 b)
3693 {
3694 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3695
3696 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3697
3698 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3699
3700 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3701
3702 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3703
3704 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3705
3706 }
3707
3708 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3709 {
3710 uint8 phybw40;
3711 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3712 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3713
3714 pi_lcn->lcnphy_cal_counter = 0;
3715 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3716
3717 or_phy_reg(pi, 0x44a, 0x80);
3718 and_phy_reg(pi, 0x44a, 0x7f);
3719
3720 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3721
3722 write_phy_reg(pi, 0x60a, 160);
3723
3724 write_phy_reg(pi, 0x46a, 25);
3725
3726 wlc_lcnphy_baseband_init(pi);
3727
3728 wlc_lcnphy_radio_init(pi);
3729
3730 if (CHSPEC_IS2G(pi->radio_chanspec))
3731 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3732
3733 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3734
3735 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3736
3737 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3738
3739 if ((pi->sh->boardflags & BFL_FEM)
3740 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3741 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
3742
3743 wlc_lcnphy_agc_temp_init(pi);
3744
3745 wlc_lcnphy_temp_adj(pi);
3746
3747 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3748
3749 OSL_DELAY(100);
3750 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3751
3752 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3753 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
3754 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
3755 }
3756
3757 static void
3758 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, uint16 *values_to_save)
3759 {
3760 uint16 vmid;
3761 int i;
3762 for (i = 0; i < 20; i++) {
3763 values_to_save[i] =
3764 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
3765 }
3766
3767 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3768 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3769
3770 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3771 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3772
3773 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3774 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3775
3776 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3777 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3778
3779 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
3780 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
3781 else
3782 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
3783 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
3784
3785 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3786 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3787 OSL_DELAY(20);
3788
3789 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3790 if (CHSPEC_IS5G(pi->radio_chanspec))
3791 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
3792 else
3793 or_radio_reg(pi, RADIO_2064_REG03A, 1);
3794 } else {
3795 if (CHSPEC_IS5G(pi->radio_chanspec))
3796 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
3797 else
3798 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
3799 }
3800
3801 OSL_DELAY(20);
3802
3803 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
3804 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3805 if (CHSPEC_IS5G(pi->radio_chanspec))
3806 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
3807 else
3808 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
3809 } else {
3810 if (CHSPEC_IS5G(pi->radio_chanspec))
3811 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
3812 else
3813 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
3814 }
3815
3816 OSL_DELAY(20);
3817
3818 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3819 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3820 OSL_DELAY(20);
3821
3822 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3823 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3824 OSL_DELAY(20);
3825
3826 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3827 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3828 OSL_DELAY(20);
3829
3830 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3831 OSL_DELAY(20);
3832
3833 vmid = 0x2A6;
3834 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
3835 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
3836 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3837 OSL_DELAY(20);
3838
3839 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3840 OSL_DELAY(20);
3841 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
3842 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
3843 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
3844 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
3845 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
3846 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
3847 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
3848 }
3849
3850 static void
3851 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, uint16 thresh,
3852 int16 *ptr, int mode)
3853 {
3854 uint32 curval1, curval2, stpptr, curptr, strptr, val;
3855 uint16 sslpnCalibClkEnCtrl, timer;
3856 uint16 old_sslpnCalibClkEnCtrl;
3857 int16 imag, real;
3858 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3859
3860 timer = 0;
3861 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3862
3863 curval1 = R_REG(pi->sh->osh, &pi->regs->psm_corectlsts);
3864 ptr[130] = 0;
3865 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, ((1 << 6) | curval1));
3866
3867 W_REG(pi->sh->osh, &pi->regs->smpl_clct_strptr, 0x7E00);
3868 W_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr, 0x8000);
3869 OSL_DELAY(20);
3870 curval2 = R_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param);
3871 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2 | 0x30);
3872
3873 write_phy_reg(pi, 0x555, 0x0);
3874 write_phy_reg(pi, 0x5a6, 0x5);
3875
3876 write_phy_reg(pi, 0x5a2, (uint16) (mode | mode << 6));
3877 write_phy_reg(pi, 0x5cf, 3);
3878 write_phy_reg(pi, 0x5a5, 0x3);
3879 write_phy_reg(pi, 0x583, 0x0);
3880 write_phy_reg(pi, 0x584, 0x0);
3881 write_phy_reg(pi, 0x585, 0x0fff);
3882 write_phy_reg(pi, 0x586, 0x0000);
3883
3884 write_phy_reg(pi, 0x580, 0x4501);
3885
3886 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3887 write_phy_reg(pi, 0x6da, (uint32) (sslpnCalibClkEnCtrl | 0x2008));
3888 stpptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_stpptr);
3889 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3890 do {
3891 OSL_DELAY(10);
3892 curptr = R_REG(pi->sh->osh, &pi->regs->smpl_clct_curptr);
3893 timer++;
3894 } while ((curptr != stpptr) && (timer < 500));
3895
3896 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, 0x2);
3897 strptr = 0x7E00;
3898 W_REG(pi->sh->osh, &pi->regs->tplatewrptr, strptr);
3899 while (strptr < 0x8000) {
3900 val = R_REG(pi->sh->osh, &pi->regs->tplatewrdata);
3901 imag = ((val >> 16) & 0x3ff);
3902 real = ((val) & 0x3ff);
3903 if (imag > 511) {
3904 imag -= 1024;
3905 }
3906 if (real > 511) {
3907 real -= 1024;
3908 }
3909 if (pi_lcn->lcnphy_iqcal_swp_dis)
3910 ptr[(strptr - 0x7E00) / 4] = real;
3911 else
3912 ptr[(strptr - 0x7E00) / 4] = imag;
3913 if (clip_detect_algo) {
3914 if (imag > thresh || imag < -thresh) {
3915 strptr = 0x8000;
3916 ptr[130] = 1;
3917 }
3918 }
3919 strptr += 4;
3920 }
3921
3922 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3923 W_REG(pi->sh->osh, &pi->regs->psm_phy_hdr_param, curval2);
3924 W_REG(pi->sh->osh, &pi->regs->psm_corectlsts, curval1);
3925 }
3926
3927 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
3928 {
3929 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3930
3931 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3932 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3933 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3934 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3935
3936 wlc_lcnphy_a1(pi, 4, 0, 0);
3937 wlc_lcnphy_a1(pi, 3, 0, 0);
3938 wlc_lcnphy_a1(pi, 2, 3, 2);
3939 wlc_lcnphy_a1(pi, 0, 5, 8);
3940 wlc_lcnphy_a1(pi, 2, 2, 1);
3941 wlc_lcnphy_a1(pi, 0, 4, 3);
3942
3943 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3944 locc2 = wlc_lcnphy_get_cc(pi, 2);
3945 locc3 = wlc_lcnphy_get_cc(pi, 3);
3946 locc4 = wlc_lcnphy_get_cc(pi, 4);
3947 }
3948
3949 static void
3950 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, int16 coeff_x, int16 coeff_y)
3951 {
3952 uint16 di0dq0;
3953 uint16 x, y, data_rf;
3954 int k;
3955 switch (cal_type) {
3956 case 0:
3957 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3958 break;
3959 case 2:
3960 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3961 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3962 break;
3963 case 3:
3964 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3965 y = 8 + k;
3966 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3967 x = 8 - k;
3968 data_rf = (x * 16 + y);
3969 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3970 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3971 y = 8 + k;
3972 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3973 x = 8 - k;
3974 data_rf = (x * 16 + y);
3975 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3976 break;
3977 case 4:
3978 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3979 y = 8 + k;
3980 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3981 x = 8 - k;
3982 data_rf = (x * 16 + y);
3983 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3984 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3985 y = 8 + k;
3986 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3987 x = 8 - k;
3988 data_rf = (x * 16 + y);
3989 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3990 break;
3991 }
3992 }
3993
3994 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3995 {
3996 uint16 a, b, didq;
3997 uint8 di0, dq0, ei, eq, fi, fq;
3998 lcnphy_unsign16_struct cc;
3999 cc.re = 0;
4000 cc.im = 0;
4001 switch (cal_type) {
4002 case 0:
4003 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
4004 cc.re = a;
4005 cc.im = b;
4006 break;
4007 case 2:
4008 didq = wlc_lcnphy_get_tx_locc(pi);
4009 di0 = (((didq & 0xff00) << 16) >> 24);
4010 dq0 = (((didq & 0x00ff) << 24) >> 24);
4011 cc.re = (uint16) di0;
4012 cc.im = (uint16) dq0;
4013 break;
4014 case 3:
4015 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4016 cc.re = (uint16) ei;
4017 cc.im = (uint16) eq;
4018 break;
4019 case 4:
4020 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4021 cc.re = (uint16) fi;
4022 cc.im = (uint16) fq;
4023 break;
4024 }
4025 return cc;
4026 }
4027
4028 static void
4029 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
4030 {
4031 const lcnphy_spb_tone_t *phy_c1;
4032 lcnphy_spb_tone_t phy_c2;
4033 lcnphy_unsign16_struct phy_c3;
4034 int phy_c4, phy_c5, k, l, j, phy_c6;
4035 uint16 phy_c7, phy_c8, phy_c9;
4036 int16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4037 int16 *ptr, phy_c17;
4038 int32 phy_c18, phy_c19;
4039 uint32 phy_c20, phy_c21;
4040 bool phy_c22, phy_c23, phy_c24, phy_c25;
4041 uint16 phy_c26, phy_c27;
4042 uint16 phy_c28, phy_c29, phy_c30;
4043 uint16 phy_c31;
4044 uint16 *phy_c32;
4045 phy_c21 = 0;
4046 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4047 ptr = MALLOC(pi->sh->osh, sizeof(int16) * 131);
4048 if (NULL == ptr) {
4049 return;
4050 }
4051
4052 phy_c32 = MALLOC(pi->sh->osh, sizeof(uint16) * 20);
4053 if (NULL == phy_c32) {
4054 return;
4055 }
4056 phy_c26 = read_phy_reg(pi, 0x6da);
4057 phy_c27 = read_phy_reg(pi, 0x6db);
4058 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
4059 write_phy_reg(pi, 0x93d, 0xC0);
4060
4061 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
4062 write_phy_reg(pi, 0x6da, 0xffff);
4063 or_phy_reg(pi, 0x6db, 0x3);
4064
4065 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
4066 OSL_DELAY(500);
4067 phy_c28 = read_phy_reg(pi, 0x938);
4068 phy_c29 = read_phy_reg(pi, 0x4d7);
4069 phy_c30 = read_phy_reg(pi, 0x4d8);
4070 or_phy_reg(pi, 0x938, 0x1 << 2);
4071 or_phy_reg(pi, 0x4d7, 0x1 << 2);
4072 or_phy_reg(pi, 0x4d7, 0x1 << 3);
4073 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
4074 or_phy_reg(pi, 0x4d8, 1 << 0);
4075 or_phy_reg(pi, 0x4d8, 1 << 1);
4076 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
4077 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
4078 phy_c1 = &lcnphy_spb_tone_3750[0];
4079 phy_c4 = 32;
4080
4081 if (num_levels == 0) {
4082 if (cal_type != 0) {
4083 num_levels = 4;
4084 } else {
4085 num_levels = 9;
4086 }
4087 }
4088 if (step_size_lg2 == 0) {
4089 if (cal_type != 0) {
4090 step_size_lg2 = 3;
4091 } else {
4092 step_size_lg2 = 8;
4093 }
4094 }
4095
4096 phy_c7 = (1 << step_size_lg2);
4097 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
4098 phy_c15 = (int16) phy_c3.re;
4099 phy_c16 = (int16) phy_c3.im;
4100 if (cal_type == 2) {
4101 if (phy_c3.re > 127)
4102 phy_c15 = phy_c3.re - 256;
4103 if (phy_c3.im > 127)
4104 phy_c16 = phy_c3.im - 256;
4105 }
4106 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4107 OSL_DELAY(20);
4108 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
4109 phy_c23 = 1;
4110 phy_c22 = 0;
4111 switch (cal_type) {
4112 case 0:
4113 phy_c10 = 511;
4114 break;
4115 case 2:
4116 phy_c10 = 127;
4117 break;
4118 case 3:
4119 phy_c10 = 15;
4120 break;
4121 case 4:
4122 phy_c10 = 15;
4123 break;
4124 }
4125
4126 phy_c9 = read_phy_reg(pi, 0x93d);
4127 phy_c9 = 2 * phy_c9;
4128 phy_c24 = 0;
4129 phy_c5 = 7;
4130 phy_c25 = 1;
4131 while (1) {
4132 write_radio_reg(pi, RADIO_2064_REG026,
4133 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
4134 OSL_DELAY(50);
4135 phy_c22 = 0;
4136 ptr[130] = 0;
4137 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
4138 if (ptr[130] == 1)
4139 phy_c22 = 1;
4140 if (phy_c22)
4141 phy_c5 -= 1;
4142 if ((phy_c22 != phy_c24) && (!phy_c25))
4143 break;
4144 if (!phy_c22)
4145 phy_c5 += 1;
4146 if (phy_c5 <= 0 || phy_c5 >= 7)
4147 break;
4148 phy_c24 = phy_c22;
4149 phy_c25 = 0;
4150 }
4151
4152 if (phy_c5 < 0)
4153 phy_c5 = 0;
4154 else if (phy_c5 > 7)
4155 phy_c5 = 7;
4156
4157 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
4158 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
4159 phy_c11 = phy_c15 + k;
4160 phy_c12 = phy_c16 + l;
4161
4162 if (phy_c11 < -phy_c10)
4163 phy_c11 = -phy_c10;
4164 else if (phy_c11 > phy_c10)
4165 phy_c11 = phy_c10;
4166 if (phy_c12 < -phy_c10)
4167 phy_c12 = -phy_c10;
4168 else if (phy_c12 > phy_c10)
4169 phy_c12 = phy_c10;
4170 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
4171 phy_c12);
4172 OSL_DELAY(20);
4173 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
4174
4175 phy_c18 = 0;
4176 phy_c19 = 0;
4177 for (j = 0; j < 128; j++) {
4178 if (cal_type != 0) {
4179 phy_c6 = j % phy_c4;
4180 } else {
4181 phy_c6 = (2 * j) % phy_c4;
4182 }
4183 phy_c2.re = phy_c1[phy_c6].re;
4184 phy_c2.im = phy_c1[phy_c6].im;
4185 phy_c17 = ptr[j];
4186 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
4187 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
4188 }
4189
4190 phy_c18 = phy_c18 >> 10;
4191 phy_c19 = phy_c19 >> 10;
4192 phy_c20 =
4193 ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
4194
4195 if (phy_c23 || phy_c20 < phy_c21) {
4196 phy_c21 = phy_c20;
4197 phy_c13 = phy_c11;
4198 phy_c14 = phy_c12;
4199 }
4200 phy_c23 = 0;
4201 }
4202 }
4203 phy_c23 = 1;
4204 phy_c15 = phy_c13;
4205 phy_c16 = phy_c14;
4206 phy_c7 = phy_c7 >> 1;
4207 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
4208 OSL_DELAY(20);
4209 }
4210 goto cleanup;
4211 cleanup:
4212 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
4213 wlc_lcnphy_stop_tx_tone(pi);
4214 write_phy_reg(pi, 0x6da, phy_c26);
4215 write_phy_reg(pi, 0x6db, phy_c27);
4216 write_phy_reg(pi, 0x938, phy_c28);
4217 write_phy_reg(pi, 0x4d7, phy_c29);
4218 write_phy_reg(pi, 0x4d8, phy_c30);
4219 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
4220
4221 MFREE(pi->sh->osh, phy_c32, 20 * sizeof(uint16));
4222 MFREE(pi->sh->osh, ptr, 131 * sizeof(int16));
4223 }
4224
4225 static void
4226 wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi, uint16 *values_to_save)
4227 {
4228 int i;
4229
4230 and_phy_reg(pi, 0x44c, 0x0 >> 11);
4231
4232 and_phy_reg(pi, 0x43b, 0xC);
4233
4234 for (i = 0; i < 20; i++) {
4235 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
4236 values_to_save[i]);
4237 }
4238 }
4239
4240 static void
4241 WLBANDINITFN(wlc_lcnphy_load_tx_gain_table) (phy_info_t *pi,
4242 const lcnphy_tx_gain_tbl_entry *
4243 gain_table) {
4244 uint32 j;
4245 phytbl_info_t tab;
4246 uint32 val;
4247 uint16 pa_gain;
4248 uint16 gm_gain;
4249
4250 if (CHSPEC_IS5G(pi->radio_chanspec))
4251 pa_gain = 0x70;
4252 else
4253 pa_gain = 0x70;
4254
4255 if (pi->sh->boardflags & BFL_FEM)
4256 pa_gain = 0x10;
4257 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4258 tab.tbl_width = 32;
4259 tab.tbl_len = 1;
4260 tab.tbl_ptr = &val;
4261
4262 for (j = 0; j < 128; j++) {
4263 gm_gain = gain_table[j].gm;
4264 val = (((uint32) pa_gain << 24) |
4265 (gain_table[j].pad << 16) |
4266 (gain_table[j].pga << 8) | gm_gain);
4267
4268 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4269 wlc_lcnphy_write_table(pi, &tab);
4270
4271 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4272 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4273 wlc_lcnphy_write_table(pi, &tab);
4274 }
4275 }
4276
4277 static void wlc_lcnphy_load_rfpower(phy_info_t *pi)
4278 {
4279 phytbl_info_t tab;
4280 uint32 val, bbmult, rfgain;
4281 uint8 index;
4282 uint8 scale_factor = 1;
4283 int16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4284
4285 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4286 tab.tbl_width = 32;
4287 tab.tbl_len = 1;
4288
4289 for (index = 0; index < 128; index++) {
4290 tab.tbl_ptr = &bbmult;
4291 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4292 wlc_lcnphy_read_table(pi, &tab);
4293 bbmult = bbmult >> 20;
4294
4295 tab.tbl_ptr = &rfgain;
4296 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4297 wlc_lcnphy_read_table(pi, &tab);
4298
4299 qm_log10((int32) (bbmult), 0, &temp1, &qQ1);
4300 qm_log10((int32) (1 << 6), 0, &temp2, &qQ2);
4301
4302 if (qQ1 < qQ2) {
4303 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4304 qQ = qQ1;
4305 } else {
4306 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4307 qQ = qQ2;
4308 }
4309 temp = qm_sub16(temp1, temp2);
4310
4311 if (qQ >= 4)
4312 shift = qQ - 4;
4313 else
4314 shift = 4 - qQ;
4315
4316 val = (((index << shift) + (5 * temp) +
4317 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4318 shift - 2));
4319
4320 tab.tbl_ptr = &val;
4321 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4322 wlc_lcnphy_write_table(pi, &tab);
4323 }
4324 }
4325
4326 static void WLBANDINITFN(wlc_lcnphy_tbl_init) (phy_info_t *pi)
4327 {
4328 uint idx;
4329 uint8 phybw40;
4330 phytbl_info_t tab;
4331 uint32 val;
4332
4333 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4334
4335 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
4336 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4337 }
4338
4339 if (pi->sh->boardflags & BFL_FEM_BT) {
4340 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4341 tab.tbl_width = 16;
4342 tab.tbl_ptr = &val;
4343 tab.tbl_len = 1;
4344 val = 100;
4345 tab.tbl_offset = 4;
4346 wlc_lcnphy_write_table(pi, &tab);
4347 }
4348
4349 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4350 tab.tbl_width = 16;
4351 tab.tbl_ptr = &val;
4352 tab.tbl_len = 1;
4353
4354 val = 114;
4355 tab.tbl_offset = 0;
4356 wlc_lcnphy_write_table(pi, &tab);
4357
4358 val = 130;
4359 tab.tbl_offset = 1;
4360 wlc_lcnphy_write_table(pi, &tab);
4361
4362 val = 6;
4363 tab.tbl_offset = 8;
4364 wlc_lcnphy_write_table(pi, &tab);
4365
4366 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4367 if (pi->sh->boardflags & BFL_FEM)
4368 wlc_lcnphy_load_tx_gain_table(pi,
4369 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4370 else
4371 wlc_lcnphy_load_tx_gain_table(pi,
4372 dot11lcnphy_2GHz_gaintable_rev0);
4373 }
4374
4375 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4376 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4377 for (idx = 0;
4378 idx < dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4379 idx++)
4380 if (pi->sh->boardflags & BFL_EXTLNA)
4381 wlc_lcnphy_write_table(pi,
4382 &dot11lcnphytbl_rx_gain_info_extlna_2G_rev2
4383 [idx]);
4384 else
4385 wlc_lcnphy_write_table(pi,
4386 &dot11lcnphytbl_rx_gain_info_2G_rev2
4387 [idx]);
4388 } else {
4389 for (idx = 0;
4390 idx < dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4391 idx++)
4392 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4393 wlc_lcnphy_write_table(pi,
4394 &dot11lcnphytbl_rx_gain_info_extlna_5G_rev2
4395 [idx]);
4396 else
4397 wlc_lcnphy_write_table(pi,
4398 &dot11lcnphytbl_rx_gain_info_5G_rev2
4399 [idx]);
4400 }
4401 }
4402
4403 if ((pi->sh->boardflags & BFL_FEM)
4404 && !(pi->sh->boardflags & BFL_FEM_BT))
4405 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4406 else if (pi->sh->boardflags & BFL_FEM_BT) {
4407 if (pi->sh->boardrev < 0x1250)
4408 wlc_lcnphy_write_table(pi,
4409 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4410 else
4411 wlc_lcnphy_write_table(pi,
4412 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4413 } else
4414 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4415
4416 wlc_lcnphy_load_rfpower(pi);
4417
4418 wlc_lcnphy_clear_papd_comptable(pi);
4419 }
4420
4421 static void WLBANDINITFN(wlc_lcnphy_rev0_baseband_init) (phy_info_t *pi)
4422 {
4423 uint16 afectrl1;
4424 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4425
4426 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4427
4428 write_phy_reg(pi, 0x43b, 0x0);
4429 write_phy_reg(pi, 0x43c, 0x0);
4430 write_phy_reg(pi, 0x44c, 0x0);
4431 write_phy_reg(pi, 0x4e6, 0x0);
4432 write_phy_reg(pi, 0x4f9, 0x0);
4433 write_phy_reg(pi, 0x4b0, 0x0);
4434 write_phy_reg(pi, 0x938, 0x0);
4435 write_phy_reg(pi, 0x4b0, 0x0);
4436 write_phy_reg(pi, 0x44e, 0);
4437
4438 or_phy_reg(pi, 0x567, 0x03);
4439
4440 or_phy_reg(pi, 0x44a, 0x44);
4441 write_phy_reg(pi, 0x44a, 0x80);
4442
4443 if (!(pi->sh->boardflags & BFL_FEM))
4444 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4445
4446 if (0) {
4447 afectrl1 = 0;
4448 afectrl1 = (uint16) ((pi_lcn->lcnphy_rssi_vf) |
4449 (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
4450 lcnphy_rssi_gs
4451 << 10));
4452 write_phy_reg(pi, 0x43e, afectrl1);
4453 }
4454
4455 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4456 if (pi->sh->boardflags & BFL_FEM) {
4457 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4458
4459 write_phy_reg(pi, 0x910, 0x1);
4460 }
4461
4462 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4463 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4464 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4465
4466 }
4467
4468 static void WLBANDINITFN(wlc_lcnphy_rev2_baseband_init) (phy_info_t *pi)
4469 {
4470 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4471 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4472
4473 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4474 }
4475 }
4476
4477 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi)
4478 {
4479 int16 temp;
4480 phytbl_info_t tab;
4481 uint32 tableBuffer[2];
4482 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4483
4484 if (NORADIO_ENAB(pi->pubpi))
4485 return;
4486
4487 temp = (int16) read_phy_reg(pi, 0x4df);
4488 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4489
4490 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4491 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4492
4493 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4494
4495 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4496 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4497
4498 tab.tbl_ptr = tableBuffer;
4499 tab.tbl_len = 2;
4500 tab.tbl_id = 17;
4501 tab.tbl_offset = 59;
4502 tab.tbl_width = 32;
4503 wlc_lcnphy_read_table(pi, &tab);
4504
4505 if (tableBuffer[0] > 63)
4506 tableBuffer[0] -= 128;
4507 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4508
4509 if (tableBuffer[1] > 63)
4510 tableBuffer[1] -= 128;
4511 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4512
4513 temp = (int16) (read_phy_reg(pi, 0x434)
4514 & (0xff << 0));
4515 if (temp > 127)
4516 temp -= 256;
4517 pi_lcn->lcnphy_input_pwr_offset_db = (int8) temp;
4518
4519 pi_lcn->lcnphy_Med_Low_Gain_db = (read_phy_reg(pi, 0x424)
4520 & (0xff << 8))
4521 >> 8;
4522 pi_lcn->lcnphy_Very_Low_Gain_db = (read_phy_reg(pi, 0x425)
4523 & (0xff << 0))
4524 >> 0;
4525
4526 tab.tbl_ptr = tableBuffer;
4527 tab.tbl_len = 2;
4528 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4529 tab.tbl_offset = 28;
4530 tab.tbl_width = 32;
4531 wlc_lcnphy_read_table(pi, &tab);
4532
4533 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4534 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4535
4536 }
4537
4538 static void WLBANDINITFN(wlc_lcnphy_bu_tweaks) (phy_info_t *pi)
4539 {
4540 if (NORADIO_ENAB(pi->pubpi))
4541 return;
4542
4543 or_phy_reg(pi, 0x805, 0x1);
4544
4545 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4546
4547 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4548
4549 write_phy_reg(pi, 0x414, 0x1e10);
4550 write_phy_reg(pi, 0x415, 0x0640);
4551
4552 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4553
4554 or_phy_reg(pi, 0x44a, 0x44);
4555 write_phy_reg(pi, 0x44a, 0x80);
4556 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4557
4558 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4559
4560 if (!(pi->sh->boardrev < 0x1204))
4561 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4562
4563 write_phy_reg(pi, 0x7d6, 0x0902);
4564 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4565
4566 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4567
4568 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4569 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4570
4571 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4572
4573 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4574
4575 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4576
4577 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4578
4579 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4580 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4581 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4582 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4583 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4584
4585 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4586
4587 wlc_lcnphy_clear_tx_power_offsets(pi);
4588 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4589
4590 }
4591 }
4592
4593 static void WLBANDINITFN(wlc_lcnphy_baseband_init) (phy_info_t *pi)
4594 {
4595
4596 wlc_lcnphy_tbl_init(pi);
4597 wlc_lcnphy_rev0_baseband_init(pi);
4598 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4599 wlc_lcnphy_rev2_baseband_init(pi);
4600 wlc_lcnphy_bu_tweaks(pi);
4601 }
4602
4603 static void WLBANDINITFN(wlc_radio_2064_init) (phy_info_t *pi)
4604 {
4605 uint32 i;
4606 lcnphy_radio_regs_t *lcnphyregs = NULL;
4607
4608 lcnphyregs = lcnphy_radio_regs_2064;
4609
4610 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4611 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4612 write_radio_reg(pi,
4613 ((lcnphyregs[i].address & 0x3fff) |
4614 RADIO_DEFAULT_CORE),
4615 (uint16) lcnphyregs[i].init_a);
4616 else if (lcnphyregs[i].do_init_g)
4617 write_radio_reg(pi,
4618 ((lcnphyregs[i].address & 0x3fff) |
4619 RADIO_DEFAULT_CORE),
4620 (uint16) lcnphyregs[i].init_g);
4621
4622 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4623 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4624
4625 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4626
4627 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4628
4629 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4630
4631 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4632 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4633 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4634 }
4635
4636 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4637 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4638
4639 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4640
4641 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4642
4643 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4644
4645 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4646
4647 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4648
4649 write_phy_reg(pi, 0x4ea, 0x4688);
4650
4651 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4652
4653 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4654
4655 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4656
4657 wlc_lcnphy_set_tx_locc(pi, 0);
4658
4659 wlc_lcnphy_rcal(pi);
4660
4661 wlc_lcnphy_rc_cal(pi);
4662 }
4663
4664 static void WLBANDINITFN(wlc_lcnphy_radio_init) (phy_info_t *pi)
4665 {
4666 if (NORADIO_ENAB(pi->pubpi))
4667 return;
4668
4669 wlc_radio_2064_init(pi);
4670 }
4671
4672 static void wlc_lcnphy_rcal(phy_info_t *pi)
4673 {
4674 uint8 rcal_value;
4675
4676 if (NORADIO_ENAB(pi->pubpi))
4677 return;
4678
4679 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4680
4681 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4682 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4683
4684 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4685 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4686
4687 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4688
4689 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4690 OSL_DELAY(5000);
4691 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4692
4693 if (wlc_radio_2064_rcal_done(pi)) {
4694 rcal_value = (uint8) read_radio_reg(pi, RADIO_2064_REG05C);
4695 rcal_value = rcal_value & 0x1f;
4696 }
4697
4698 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4699
4700 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4701 }
4702
4703 static void wlc_lcnphy_rc_cal(phy_info_t *pi)
4704 {
4705 uint8 dflt_rc_cal_val;
4706 uint16 flt_val;
4707
4708 if (NORADIO_ENAB(pi->pubpi))
4709 return;
4710
4711 dflt_rc_cal_val = 7;
4712 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4713 dflt_rc_cal_val = 11;
4714 flt_val =
4715 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4716 (dflt_rc_cal_val);
4717 write_phy_reg(pi, 0x933, flt_val);
4718 write_phy_reg(pi, 0x934, flt_val);
4719 write_phy_reg(pi, 0x935, flt_val);
4720 write_phy_reg(pi, 0x936, flt_val);
4721 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4722
4723 return;
4724 }
4725
4726 static bool BCMATTACHFN(wlc_phy_txpwr_srom_read_lcnphy) (phy_info_t *pi)
4727 {
4728 int8 txpwr = 0;
4729 int i;
4730 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
4731
4732 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4733 uint16 cckpo = 0;
4734 uint32 offset_ofdm, offset_mcs;
4735
4736 pi_lcn->lcnphy_tr_isolation_mid =
4737 (uint8) PHY_GETINTVAR(pi, "triso2g");
4738
4739 pi_lcn->lcnphy_rx_power_offset =
4740 (uint8) PHY_GETINTVAR(pi, "rxpo2g");
4741
4742 pi->txpa_2g[0] = (int16) PHY_GETINTVAR(pi, "pa0b0");
4743 pi->txpa_2g[1] = (int16) PHY_GETINTVAR(pi, "pa0b1");
4744 pi->txpa_2g[2] = (int16) PHY_GETINTVAR(pi, "pa0b2");
4745
4746 pi_lcn->lcnphy_rssi_vf = (uint8) PHY_GETINTVAR(pi, "rssismf2g");
4747 pi_lcn->lcnphy_rssi_vc = (uint8) PHY_GETINTVAR(pi, "rssismc2g");
4748 pi_lcn->lcnphy_rssi_gs = (uint8) PHY_GETINTVAR(pi, "rssisav2g");
4749
4750 {
4751 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4752 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4753 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4754
4755 pi_lcn->lcnphy_rssi_vf_hightemp =
4756 pi_lcn->lcnphy_rssi_vf;
4757 pi_lcn->lcnphy_rssi_vc_hightemp =
4758 pi_lcn->lcnphy_rssi_vc;
4759 pi_lcn->lcnphy_rssi_gs_hightemp =
4760 pi_lcn->lcnphy_rssi_gs;
4761 }
4762
4763 txpwr = (int8) PHY_GETINTVAR(pi, "maxp2ga0");
4764 pi->tx_srom_max_2g = txpwr;
4765
4766 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4767 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4768 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4769 }
4770
4771 cckpo = (uint16) PHY_GETINTVAR(pi, "cck2gpo");
4772 if (cckpo) {
4773 uint max_pwr_chan = txpwr;
4774
4775 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4776 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4777 ((cckpo & 0xf) * 2);
4778 cckpo >>= 4;
4779 }
4780
4781 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4782 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4783 pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
4784 ((offset_ofdm & 0xf) * 2);
4785 offset_ofdm >>= 4;
4786 }
4787 } else {
4788 uint8 opo = 0;
4789
4790 opo = (uint8) PHY_GETINTVAR(pi, "opo");
4791
4792 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4793 pi->tx_srom_max_rate_2g[i] = txpwr;
4794 }
4795
4796 offset_ofdm = (uint32) PHY_GETINTVAR(pi, "ofdm2gpo");
4797
4798 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4799 pi->tx_srom_max_rate_2g[i] = txpwr -
4800 ((offset_ofdm & 0xf) * 2);
4801 offset_ofdm >>= 4;
4802 }
4803 offset_mcs =
4804 ((uint16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
4805 (uint16) PHY_GETINTVAR(pi, "mcs2gpo0");
4806 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4807 for (i = TXP_FIRST_SISO_MCS_20;
4808 i <= TXP_LAST_SISO_MCS_20; i++) {
4809 pi->tx_srom_max_rate_2g[i] =
4810 txpwr - ((offset_mcs & 0xf) * 2);
4811 offset_mcs >>= 4;
4812 }
4813 }
4814
4815 pi_lcn->lcnphy_rawtempsense =
4816 (uint16) PHY_GETINTVAR(pi, "rawtempsense");
4817 pi_lcn->lcnphy_measPower =
4818 (uint8) PHY_GETINTVAR(pi, "measpower");
4819 pi_lcn->lcnphy_tempsense_slope =
4820 (uint8) PHY_GETINTVAR(pi, "tempsense_slope");
4821 pi_lcn->lcnphy_hw_iqcal_en =
4822 (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
4823 pi_lcn->lcnphy_iqcal_swp_dis =
4824 (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
4825 pi_lcn->lcnphy_tempcorrx =
4826 (uint8) PHY_GETINTVAR(pi, "tempcorrx");
4827 pi_lcn->lcnphy_tempsense_option =
4828 (uint8) PHY_GETINTVAR(pi, "tempsense_option");
4829 pi_lcn->lcnphy_freqoffset_corr =
4830 (uint8) PHY_GETINTVAR(pi, "freqoffset_corr");
4831 if ((uint8) getintvar(pi->vars, "aa2g") > 1)
4832 wlc_phy_ant_rxdiv_set((wlc_phy_t *) pi,
4833 (uint8) getintvar(pi->vars,
4834 "aa2g"));
4835 }
4836 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4837 if (PHY_GETVAR(pi, "cckdigfilttype")) {
4838 int16 temp;
4839 temp = (int16) PHY_GETINTVAR(pi, "cckdigfilttype");
4840 if (temp >= 0) {
4841 pi_lcn->lcnphy_cck_dig_filt_type = temp;
4842 }
4843 }
4844
4845 return TRUE;
4846 }
4847
4848 void wlc_2064_vco_cal(phy_info_t *pi)
4849 {
4850 uint8 calnrst;
4851
4852 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4853 calnrst = (uint8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4854 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4855 OSL_DELAY(1);
4856 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4857 OSL_DELAY(1);
4858 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4859 OSL_DELAY(300);
4860 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4861 }
4862
4863 static void
4864 wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi, uint8 channel)
4865 {
4866 uint i;
4867 const chan_info_2064_lcnphy_t *ci;
4868 uint8 rfpll_doubler = 0;
4869 uint8 pll_pwrup, pll_pwrup_ovr;
4870 fixed qFxtal, qFref, qFvco, qFcal;
4871 uint8 d15, d16, f16, e44, e45;
4872 uint32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
4873 uint16 loop_bw, d30, setCount;
4874 if (NORADIO_ENAB(pi->pubpi))
4875 return;
4876 ci = &chan_info_2064_lcnphy[0];
4877 rfpll_doubler = 1;
4878
4879 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
4880
4881 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
4882 if (!rfpll_doubler) {
4883 loop_bw = PLL_2064_LOOP_BW;
4884 d30 = PLL_2064_D30;
4885 } else {
4886 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
4887 d30 = PLL_2064_D30_DOUBLER;
4888 }
4889
4890 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4891 for (i = 0; i < ARRAYSIZE(chan_info_2064_lcnphy); i++)
4892 if (chan_info_2064_lcnphy[i].chan == channel)
4893 break;
4894
4895 if (i >= ARRAYSIZE(chan_info_2064_lcnphy)) {
4896 return;
4897 }
4898
4899 ci = &chan_info_2064_lcnphy[i];
4900 }
4901
4902 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
4903
4904 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
4905
4906 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
4907
4908 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
4909
4910 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
4911 (ci->logen_rccr_rx) << 2);
4912
4913 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
4914
4915 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
4916 (ci->pa_rxrf_lna2_freq_tune) << 4);
4917
4918 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
4919
4920 pll_pwrup = (uint8) read_radio_reg(pi, RADIO_2064_REG044);
4921 pll_pwrup_ovr = (uint8) read_radio_reg(pi, RADIO_2064_REG12B);
4922
4923 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
4924
4925 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
4926 e44 = 0;
4927 e45 = 0;
4928
4929 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
4930 if (pi->xtalfreq > 26000000)
4931 e44 = 1;
4932 if (pi->xtalfreq > 52000000)
4933 e45 = 1;
4934 if (e44 == 0)
4935 fcal_div = 1;
4936 else if (e45 == 0)
4937 fcal_div = 2;
4938 else
4939 fcal_div = 4;
4940 fvco3 = (ci->freq * 3);
4941 fref3 = 2 * fpfd;
4942
4943 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
4944 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
4945 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
4946 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
4947
4948 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
4949
4950 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
4951 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
4952 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
4953
4954 d16 = (qFcal * 8 / (d15 + 1)) - 1;
4955 write_radio_reg(pi, RADIO_2064_REG051, d16);
4956
4957 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
4958 setCount = f16 * 3 * (ci->freq) / 32 - 1;
4959 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
4960 (uint8) (setCount >> 8));
4961
4962 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
4963 write_radio_reg(pi, RADIO_2064_REG054, (uint8) (setCount & 0xff));
4964
4965 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
4966
4967 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
4968 while (div_frac >= fref3) {
4969 div_int++;
4970 div_frac -= fref3;
4971 }
4972 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
4973
4974 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
4975 (uint8) (div_int >> 4));
4976 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
4977 (uint8) (div_int << 4));
4978 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
4979 (uint8) (div_frac >> 16));
4980 write_radio_reg(pi, RADIO_2064_REG047, (uint8) (div_frac >> 8) & 0xff);
4981 write_radio_reg(pi, RADIO_2064_REG048, (uint8) div_frac & 0xff);
4982
4983 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
4984
4985 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
4986 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
4987 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
4988
4989 {
4990 uint8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
4991 uint16 c29, c38, c30, g30, d28;
4992 c29 = loop_bw;
4993 d29 = 200;
4994 c38 = 1250;
4995 h29 = d29 / c29;
4996 h23 = 1;
4997 c28 = 30;
4998 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
4999 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
5000 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
5001 + PLL_2064_LOW_END_KVCO;
5002 h28_ten = (d28 * 10) / c28;
5003 c30 = 2640;
5004 e30 = (d30 - 680) / 490;
5005 g30 = 680 + (e30 * 490);
5006 h30_ten = (g30 * 10) / c30;
5007 cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
5008 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
5009 }
5010 if (channel >= 1 && channel <= 5)
5011 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
5012 else
5013 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
5014 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
5015
5016 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
5017 OSL_DELAY(1);
5018
5019 wlc_2064_vco_cal(pi);
5020
5021 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
5022 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
5023 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5024 write_radio_reg(pi, RADIO_2064_REG038, 3);
5025 write_radio_reg(pi, RADIO_2064_REG091, 7);
5026 }
5027 }
5028
5029 bool wlc_phy_tpc_isenabled_lcnphy(phy_info_t *pi)
5030 {
5031 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5032 return 0;
5033 else
5034 return (LCNPHY_TX_PWR_CTRL_HW ==
5035 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5036 }
5037
5038 void wlc_phy_txpower_recalc_target_lcnphy(phy_info_t *pi)
5039 {
5040 uint16 pwr_ctrl;
5041 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5042 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5043 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5044
5045 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5046 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5047 wlc_lcnphy_txpower_recalc_target(pi);
5048
5049 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5050 } else
5051 return;
5052 }
5053
5054 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5055 {
5056 MFREE(pi->sh->osh, pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5057 }
5058
5059 bool wlc_phy_attach_lcnphy(phy_info_t *pi)
5060 {
5061 phy_info_lcnphy_t *pi_lcn;
5062
5063 pi->u.pi_lcnphy =
5064 (phy_info_lcnphy_t *) MALLOC(pi->sh->osh,
5065 sizeof(phy_info_lcnphy_t));
5066 if (pi->u.pi_lcnphy == NULL) {
5067 return FALSE;
5068 }
5069 bzero((char *)pi->u.pi_lcnphy, sizeof(phy_info_lcnphy_t));
5070
5071 pi_lcn = pi->u.pi_lcnphy;
5072
5073 if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
5074 pi->hwpwrctrl = TRUE;
5075 pi->hwpwrctrl_capable = TRUE;
5076 }
5077
5078 pi->xtalfreq = si_alp_clock(pi->sh->sih);
5079 ASSERT(0 == (pi->xtalfreq % 1000));
5080
5081 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5082
5083 pi->pi_fptr.init = wlc_phy_init_lcnphy;
5084 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5085 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5086 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5087 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5088 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5089 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5090 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5091 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5092
5093 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5094 return FALSE;
5095
5096 if ((pi->sh->boardflags & BFL_FEM) && (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5097 if (pi_lcn->lcnphy_tempsense_option == 3) {
5098 pi->hwpwrctrl = TRUE;
5099 pi->hwpwrctrl_capable = TRUE;
5100 pi->temppwrctrl_capable = FALSE;
5101 } else {
5102 pi->hwpwrctrl = FALSE;
5103 pi->hwpwrctrl_capable = FALSE;
5104 pi->temppwrctrl_capable = TRUE;
5105 }
5106 }
5107
5108 return TRUE;
5109 }
5110
5111 static void wlc_lcnphy_set_rx_gain(phy_info_t *pi, uint32 gain)
5112 {
5113 uint16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5114
5115 trsw = (gain & ((uint32) 1 << 28)) ? 0 : 1;
5116 ext_lna = (uint16) (gain >> 29) & 0x01;
5117 lna1 = (uint16) (gain >> 0) & 0x0f;
5118 lna2 = (uint16) (gain >> 4) & 0x0f;
5119 tia = (uint16) (gain >> 8) & 0xf;
5120 biq0 = (uint16) (gain >> 12) & 0xf;
5121 biq1 = (uint16) (gain >> 16) & 0xf;
5122
5123 gain0_15 = (uint16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5124 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5125 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5126 gain16_19 = biq1;
5127
5128 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5129 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5130 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5131 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5132 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5133
5134 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5135 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5136 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5137 }
5138 wlc_lcnphy_rx_gain_override_enable(pi, TRUE);
5139 }
5140
5141 static uint32 wlc_lcnphy_get_receive_power(phy_info_t *pi, int32 *gain_index)
5142 {
5143 uint32 received_power = 0;
5144 int32 max_index = 0;
5145 uint32 gain_code = 0;
5146 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5147
5148 max_index = 36;
5149 if (*gain_index >= 0)
5150 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5151
5152 if (-1 == *gain_index) {
5153 *gain_index = 0;
5154 while ((*gain_index <= (int32) max_index)
5155 && (received_power < 700)) {
5156 wlc_lcnphy_set_rx_gain(pi,
5157 lcnphy_23bitgaincode_table
5158 [*gain_index]);
5159 received_power =
5160 wlc_lcnphy_measure_digital_power(pi,
5161 pi_lcn->
5162 lcnphy_noise_samples);
5163 (*gain_index)++;
5164 }
5165 (*gain_index)--;
5166 } else {
5167 wlc_lcnphy_set_rx_gain(pi, gain_code);
5168 received_power =
5169 wlc_lcnphy_measure_digital_power(pi,
5170 pi_lcn->
5171 lcnphy_noise_samples);
5172 }
5173
5174 return received_power;
5175 }
5176
5177 int32 wlc_lcnphy_rx_signal_power(phy_info_t *pi, int32 gain_index)
5178 {
5179 int32 gain = 0;
5180 int32 nominal_power_db;
5181 int32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5182 input_power_db;
5183 int32 received_power, temperature;
5184 uint freq;
5185 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
5186
5187 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5188
5189 gain = lcnphy_gain_table[gain_index];
5190
5191 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5192
5193 {
5194 uint32 power = (received_power * 16);
5195 uint32 msb1, msb2, val1, val2, diff1, diff2;
5196 msb1 = find_msbit(power);
5197 msb2 = msb1 + 1;
5198 val1 = 1 << msb1;
5199 val2 = 1 << msb2;
5200 diff1 = (power - val1);
5201 diff2 = (val2 - power);
5202 if (diff1 < diff2)
5203 log_val = msb1;
5204 else
5205 log_val = msb2;
5206 }
5207
5208 log_val = log_val * 3;
5209
5210 gain_mismatch = (nominal_power_db / 2) - (log_val);
5211
5212 desired_gain = gain + gain_mismatch;
5213
5214 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5215
5216 if (input_power_offset_db > 127)
5217 input_power_offset_db -= 256;
5218
5219 input_power_db = input_power_offset_db - desired_gain;
5220
5221 input_power_db =
5222 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5223
5224 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5225 if ((freq > 2427) && (freq <= 2467))
5226 input_power_db = input_power_db - 1;
5227
5228 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5229
5230 if ((temperature - 15) < -30) {
5231 input_power_db =
5232 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5233 7;
5234 } else if ((temperature - 15) < 4) {
5235 input_power_db =
5236 input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
5237 3;
5238 } else {
5239 input_power_db =
5240 input_power_db + (((temperature - 10 - 25) * 286) >> 12);
5241 }
5242
5243 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5244
5245 return input_power_db;
5246 }
5247
5248 static int
5249 wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm, int16 filt_type)
5250 {
5251 int16 filt_index = -1;
5252 int j;
5253
5254 uint16 addr[] = {
5255 0x910,
5256 0x91e,
5257 0x91f,
5258 0x924,
5259 0x925,
5260 0x926,
5261 0x920,
5262 0x921,
5263 0x927,
5264 0x928,
5265 0x929,
5266 0x922,
5267 0x923,
5268 0x930,
5269 0x931,
5270 0x932
5271 };
5272
5273 uint16 addr_ofdm[] = {
5274 0x90f,
5275 0x900,
5276 0x901,
5277 0x906,
5278 0x907,
5279 0x908,
5280 0x902,
5281 0x903,
5282 0x909,
5283 0x90a,
5284 0x90b,
5285 0x904,
5286 0x905,
5287 0x90c,
5288 0x90d,
5289 0x90e
5290 };
5291
5292 if (!is_ofdm) {
5293 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
5294 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
5295 filt_index = (int16) j;
5296 break;
5297 }
5298 }
5299
5300 if (filt_index == -1) {
5301 ASSERT(FALSE);
5302 } else {
5303 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5304 write_phy_reg(pi, addr[j],
5305 LCNPHY_txdigfiltcoeffs_cck
5306 [filt_index][j + 1]);
5307 }
5308 }
5309 } else {
5310 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
5311 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
5312 filt_index = (int16) j;
5313 break;
5314 }
5315 }
5316
5317 if (filt_index == -1) {
5318 ASSERT(FALSE);
5319 } else {
5320 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
5321 write_phy_reg(pi, addr_ofdm[j],
5322 LCNPHY_txdigfiltcoeffs_ofdm
5323 [filt_index][j + 1]);
5324 }
5325 }
5326 }
5327
5328 return (filt_index != -1) ? 0 : -1;
5329 }
This page took 0.137457 seconds and 6 git commands to generate.