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