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 <linux/pci.h>
24 #include <siutils.h>
25 #include <hndpmu.h>
26
27 #include <bcmdevs.h>
28 #include <sbhnddma.h>
29
30 #include <wlc_phy_radio.h>
31 #include <wlc_phy_int.h>
32 #include <wlc_phy_lcn.h>
33 #include <wlc_phytbl_lcn.h>
34
35 #define PLL_2064_NDIV 90
36 #define PLL_2064_LOW_END_VCO 3000
37 #define PLL_2064_LOW_END_KVCO 27
38 #define PLL_2064_HIGH_END_VCO 4200
39 #define PLL_2064_HIGH_END_KVCO 68
40 #define PLL_2064_LOOP_BW_DOUBLER 200
41 #define PLL_2064_D30_DOUBLER 10500
42 #define PLL_2064_LOOP_BW 260
43 #define PLL_2064_D30 8000
44 #define PLL_2064_CAL_REF_TO 8
45 #define PLL_2064_MHZ 1000000
46 #define PLL_2064_OPEN_LOOP_DELAY 5
47
48 #define TEMPSENSE 1
49 #define VBATSENSE 2
50
51 #define NOISE_IF_UPD_CHK_INTERVAL 1
52 #define NOISE_IF_UPD_RST_INTERVAL 60
53 #define NOISE_IF_UPD_THRESHOLD_CNT 1
54 #define NOISE_IF_UPD_TRHRESHOLD 50
55 #define NOISE_IF_UPD_TIMEOUT 1000
56 #define NOISE_IF_OFF 0
57 #define NOISE_IF_CHK 1
58 #define NOISE_IF_ON 2
59
60 #define PAPD_BLANKING_PROFILE 3
61 #define PAPD2LUT 0
62 #define PAPD_CORR_NORM 0
63 #define PAPD_BLANKING_THRESHOLD 0
64 #define PAPD_STOP_AFTER_LAST_UPDATE 0
65
66 #define LCN_TARGET_PWR 60
67
68 #define LCN_VBAT_OFFSET_433X 34649679
69 #define LCN_VBAT_SLOPE_433X 8258032
70
71 #define LCN_VBAT_SCALE_NOM 53
72 #define LCN_VBAT_SCALE_DEN 432
73
74 #define LCN_TEMPSENSE_OFFSET 80812
75 #define LCN_TEMPSENSE_DEN 2647
76
77 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
78 (0 + 8)
79 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
80 (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
81
82 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
83 (0 + 8)
84 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
85 (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
86
87 #define wlc_lcnphy_enable_tx_gain_override(pi) \
88 wlc_lcnphy_set_tx_gain_override(pi, true)
89 #define wlc_lcnphy_disable_tx_gain_override(pi) \
90 wlc_lcnphy_set_tx_gain_override(pi, false)
91
92 #define wlc_lcnphy_iqcal_active(pi) \
93 (read_phy_reg((pi), 0x451) & \
94 ((0x1 << 15) | (0x1 << 14)))
95
96 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
97 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
98 (pi->temppwrctrl_capable)
99 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
100 (pi->hwpwrctrl_capable)
101
102 #define SWCTRL_BT_TX 0x18
103 #define SWCTRL_OVR_DISABLE 0x40
104
105 #define AFE_CLK_INIT_MODE_TXRX2X 1
106 #define AFE_CLK_INIT_MODE_PAPD 0
107
108 #define LCNPHY_TBL_ID_IQLOCAL 0x00
109
110 #define LCNPHY_TBL_ID_RFSEQ 0x08
111 #define LCNPHY_TBL_ID_GAIN_IDX 0x0d
112 #define LCNPHY_TBL_ID_SW_CTRL 0x0f
113 #define LCNPHY_TBL_ID_GAIN_TBL 0x12
114 #define LCNPHY_TBL_ID_SPUR 0x14
115 #define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
116 #define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
117
118 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
119 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
120 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
121 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
122 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
123 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
124
125 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
126
127 #define LCNPHY_TX_PWR_CTRL_START_NPT 1
128 #define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
129
130 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
131
132 #define LCNPHY_ACI_DETECT_START 1
133 #define LCNPHY_ACI_DETECT_PROGRESS 2
134 #define LCNPHY_ACI_DETECT_STOP 3
135
136 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
137 #define LCNPHY_ACI_GLITCH_TRSH 2000
138 #define LCNPHY_ACI_TMOUT 250
139 #define LCNPHY_ACI_DETECT_TIMEOUT 2
140 #define LCNPHY_ACI_START_DELAY 0
141
142 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
143 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
144
145 #define wlc_lcnphy_total_tx_frames(pi) \
146 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + offsetof(macstat_t, txallfrm))
147
148 typedef struct {
149 u16 gm_gain;
150 u16 pga_gain;
151 u16 pad_gain;
152 u16 dac_gain;
153 } lcnphy_txgains_t;
154
155 typedef enum {
156 LCNPHY_CAL_FULL,
157 LCNPHY_CAL_RECAL,
158 LCNPHY_CAL_CURRECAL,
159 LCNPHY_CAL_DIGCAL,
160 LCNPHY_CAL_GCTRL
161 } lcnphy_cal_mode_t;
162
163 typedef struct {
164 lcnphy_txgains_t gains;
165 bool useindex;
166 u8 index;
167 } lcnphy_txcalgains_t;
168
169 typedef struct {
170 u8 chan;
171 s16 a;
172 s16 b;
173 } lcnphy_rx_iqcomp_t;
174
175 typedef struct {
176 s16 re;
177 s16 im;
178 } lcnphy_spb_tone_t;
179
180 typedef struct {
181 u16 re;
182 u16 im;
183 } lcnphy_unsign16_struct;
184
185 typedef struct {
186 u32 iq_prod;
187 u32 i_pwr;
188 u32 q_pwr;
189 } lcnphy_iq_est_t;
190
191 typedef struct {
192 u16 ptcentreTs20;
193 u16 ptcentreFactor;
194 } lcnphy_sfo_cfg_t;
195
196 typedef enum {
197 LCNPHY_PAPD_CAL_CW,
198 LCNPHY_PAPD_CAL_OFDM
199 } lcnphy_papd_cal_type_t;
200
201 typedef u16 iqcal_gain_params_lcnphy[9];
202
203 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
204 {0, 0, 0, 0, 0, 0, 0, 0, 0},
205 };
206
207 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
208 tbl_iqcal_gainparams_lcnphy_2G,
209 };
210
211 static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
212 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
213 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
214 };
215
216 static const lcnphy_sfo_cfg_t lcnphy_sfo_cfg[] = {
217 {965, 1087},
218 {967, 1085},
219 {969, 1082},
220 {971, 1080},
221 {973, 1078},
222 {975, 1076},
223 {977, 1073},
224 {979, 1071},
225 {981, 1069},
226 {983, 1067},
227 {985, 1065},
228 {987, 1063},
229 {989, 1060},
230 {994, 1055}
231 };
232
233 static const
234 u16 lcnphy_iqcal_loft_gainladder[] = {
235 ((2 << 8) | 0),
236 ((3 << 8) | 0),
237 ((4 << 8) | 0),
238 ((6 << 8) | 0),
239 ((8 << 8) | 0),
240 ((11 << 8) | 0),
241 ((16 << 8) | 0),
242 ((16 << 8) | 1),
243 ((16 << 8) | 2),
244 ((16 << 8) | 3),
245 ((16 << 8) | 4),
246 ((16 << 8) | 5),
247 ((16 << 8) | 6),
248 ((16 << 8) | 7),
249 ((23 << 8) | 7),
250 ((32 << 8) | 7),
251 ((45 << 8) | 7),
252 ((64 << 8) | 7),
253 ((91 << 8) | 7),
254 ((128 << 8) | 7)
255 };
256
257 static const
258 u16 lcnphy_iqcal_ir_gainladder[] = {
259 ((1 << 8) | 0),
260 ((2 << 8) | 0),
261 ((4 << 8) | 0),
262 ((6 << 8) | 0),
263 ((8 << 8) | 0),
264 ((11 << 8) | 0),
265 ((16 << 8) | 0),
266 ((23 << 8) | 0),
267 ((32 << 8) | 0),
268 ((45 << 8) | 0),
269 ((64 << 8) | 0),
270 ((64 << 8) | 1),
271 ((64 << 8) | 2),
272 ((64 << 8) | 3),
273 ((64 << 8) | 4),
274 ((64 << 8) | 5),
275 ((64 << 8) | 6),
276 ((64 << 8) | 7),
277 ((91 << 8) | 7),
278 ((128 << 8) | 7)
279 };
280
281 static const
282 lcnphy_spb_tone_t lcnphy_spb_tone_3750[] = {
283 {88, 0},
284 {73, 49},
285 {34, 81},
286 {-17, 86},
287 {-62, 62},
288 {-86, 17},
289 {-81, -34},
290 {-49, -73},
291 {0, -88},
292 {49, -73},
293 {81, -34},
294 {86, 17},
295 {62, 62},
296 {17, 86},
297 {-34, 81},
298 {-73, 49},
299 {-88, 0},
300 {-73, -49},
301 {-34, -81},
302 {17, -86},
303 {62, -62},
304 {86, -17},
305 {81, 34},
306 {49, 73},
307 {0, 88},
308 {-49, 73},
309 {-81, 34},
310 {-86, -17},
311 {-62, -62},
312 {-17, -86},
313 {34, -81},
314 {73, -49},
315 };
316
317 static const
318 u16 iqlo_loopback_rf_regs[20] = {
319 RADIO_2064_REG036,
320 RADIO_2064_REG11A,
321 RADIO_2064_REG03A,
322 RADIO_2064_REG025,
323 RADIO_2064_REG028,
324 RADIO_2064_REG005,
325 RADIO_2064_REG112,
326 RADIO_2064_REG0FF,
327 RADIO_2064_REG11F,
328 RADIO_2064_REG00B,
329 RADIO_2064_REG113,
330 RADIO_2064_REG007,
331 RADIO_2064_REG0FC,
332 RADIO_2064_REG0FD,
333 RADIO_2064_REG012,
334 RADIO_2064_REG057,
335 RADIO_2064_REG059,
336 RADIO_2064_REG05C,
337 RADIO_2064_REG078,
338 RADIO_2064_REG092,
339 };
340
341 static const
342 u16 tempsense_phy_regs[14] = {
343 0x503,
344 0x4a4,
345 0x4d0,
346 0x4d9,
347 0x4da,
348 0x4a6,
349 0x938,
350 0x939,
351 0x4d8,
352 0x4d0,
353 0x4d7,
354 0x4a5,
355 0x40d,
356 0x4a2,
357 };
358
359 static const
360 u16 rxiq_cal_rf_reg[11] = {
361 RADIO_2064_REG098,
362 RADIO_2064_REG116,
363 RADIO_2064_REG12C,
364 RADIO_2064_REG06A,
365 RADIO_2064_REG00B,
366 RADIO_2064_REG01B,
367 RADIO_2064_REG113,
368 RADIO_2064_REG01D,
369 RADIO_2064_REG114,
370 RADIO_2064_REG02E,
371 RADIO_2064_REG12A,
372 };
373
374 static const
375 lcnphy_rx_iqcomp_t lcnphy_rx_iqcomp_table_rev0[] = {
376 {1, 0, 0},
377 {2, 0, 0},
378 {3, 0, 0},
379 {4, 0, 0},
380 {5, 0, 0},
381 {6, 0, 0},
382 {7, 0, 0},
383 {8, 0, 0},
384 {9, 0, 0},
385 {10, 0, 0},
386 {11, 0, 0},
387 {12, 0, 0},
388 {13, 0, 0},
389 {14, 0, 0},
390 {34, 0, 0},
391 {38, 0, 0},
392 {42, 0, 0},
393 {46, 0, 0},
394 {36, 0, 0},
395 {40, 0, 0},
396 {44, 0, 0},
397 {48, 0, 0},
398 {52, 0, 0},
399 {56, 0, 0},
400 {60, 0, 0},
401 {64, 0, 0},
402 {100, 0, 0},
403 {104, 0, 0},
404 {108, 0, 0},
405 {112, 0, 0},
406 {116, 0, 0},
407 {120, 0, 0},
408 {124, 0, 0},
409 {128, 0, 0},
410 {132, 0, 0},
411 {136, 0, 0},
412 {140, 0, 0},
413 {149, 0, 0},
414 {153, 0, 0},
415 {157, 0, 0},
416 {161, 0, 0},
417 {165, 0, 0},
418 {184, 0, 0},
419 {188, 0, 0},
420 {192, 0, 0},
421 {196, 0, 0},
422 {200, 0, 0},
423 {204, 0, 0},
424 {208, 0, 0},
425 {212, 0, 0},
426 {216, 0, 0},
427 };
428
429 static const u32 lcnphy_23bitgaincode_table[] = {
430 0x200100,
431 0x200200,
432 0x200004,
433 0x200014,
434 0x200024,
435 0x200034,
436 0x200134,
437 0x200234,
438 0x200334,
439 0x200434,
440 0x200037,
441 0x200137,
442 0x200237,
443 0x200337,
444 0x200437,
445 0x000035,
446 0x000135,
447 0x000235,
448 0x000037,
449 0x000137,
450 0x000237,
451 0x000337,
452 0x00013f,
453 0x00023f,
454 0x00033f,
455 0x00034f,
456 0x00044f,
457 0x00144f,
458 0x00244f,
459 0x00254f,
460 0x00354f,
461 0x00454f,
462 0x00464f,
463 0x01464f,
464 0x02464f,
465 0x03464f,
466 0x04464f,
467 };
468
469 static const s8 lcnphy_gain_table[] = {
470 -16,
471 -13,
472 10,
473 7,
474 4,
475 0,
476 3,
477 6,
478 9,
479 12,
480 15,
481 18,
482 21,
483 24,
484 27,
485 30,
486 33,
487 36,
488 39,
489 42,
490 45,
491 48,
492 50,
493 53,
494 56,
495 59,
496 62,
497 65,
498 68,
499 71,
500 74,
501 77,
502 80,
503 83,
504 86,
505 89,
506 92,
507 };
508
509 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
510 7,
511 7,
512 7,
513 7,
514 7,
515 7,
516 7,
517 8,
518 7,
519 7,
520 6,
521 7,
522 7,
523 4,
524 4,
525 4,
526 4,
527 4,
528 4,
529 4,
530 4,
531 3,
532 3,
533 3,
534 3,
535 3,
536 3,
537 4,
538 2,
539 2,
540 2,
541 2,
542 2,
543 2,
544 -1,
545 -2,
546 -2,
547 -2
548 };
549
550 extern const u8 spur_tbl_rev0[];
551 extern const u32 dot11lcnphytbl_rx_gain_info_sz_rev1;
552 extern const dot11lcnphytbl_info_t dot11lcnphytbl_rx_gain_info_rev1[];
553 extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
554 extern const dot11lcnphytbl_info_t dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
555
556 typedef struct _chan_info_2064_lcnphy {
557 uint chan;
558 uint freq;
559 u8 logen_buftune;
560 u8 logen_rccr_tx;
561 u8 txrf_mix_tune_ctrl;
562 u8 pa_input_tune_g;
563 u8 logen_rccr_rx;
564 u8 pa_rxrf_lna1_freq_tune;
565 u8 pa_rxrf_lna2_freq_tune;
566 u8 rxrf_rxrf_spare1;
567 } chan_info_2064_lcnphy_t;
568
569 static chan_info_2064_lcnphy_t chan_info_2064_lcnphy[] = {
570 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
576 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
578 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
579 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
580 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
581 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
582 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
583 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
584 };
585
586 lcnphy_radio_regs_t lcnphy_radio_regs_2064[] = {
587 {0x00, 0, 0, 0, 0},
588 {0x01, 0x64, 0x64, 0, 0},
589 {0x02, 0x20, 0x20, 0, 0},
590 {0x03, 0x66, 0x66, 0, 0},
591 {0x04, 0xf8, 0xf8, 0, 0},
592 {0x05, 0, 0, 0, 0},
593 {0x06, 0x10, 0x10, 0, 0},
594 {0x07, 0, 0, 0, 0},
595 {0x08, 0, 0, 0, 0},
596 {0x09, 0, 0, 0, 0},
597 {0x0A, 0x37, 0x37, 0, 0},
598 {0x0B, 0x6, 0x6, 0, 0},
599 {0x0C, 0x55, 0x55, 0, 0},
600 {0x0D, 0x8b, 0x8b, 0, 0},
601 {0x0E, 0, 0, 0, 0},
602 {0x0F, 0x5, 0x5, 0, 0},
603 {0x10, 0, 0, 0, 0},
604 {0x11, 0xe, 0xe, 0, 0},
605 {0x12, 0, 0, 0, 0},
606 {0x13, 0xb, 0xb, 0, 0},
607 {0x14, 0x2, 0x2, 0, 0},
608 {0x15, 0x12, 0x12, 0, 0},
609 {0x16, 0x12, 0x12, 0, 0},
610 {0x17, 0xc, 0xc, 0, 0},
611 {0x18, 0xc, 0xc, 0, 0},
612 {0x19, 0xc, 0xc, 0, 0},
613 {0x1A, 0x8, 0x8, 0, 0},
614 {0x1B, 0x2, 0x2, 0, 0},
615 {0x1C, 0, 0, 0, 0},
616 {0x1D, 0x1, 0x1, 0, 0},
617 {0x1E, 0x12, 0x12, 0, 0},
618 {0x1F, 0x6e, 0x6e, 0, 0},
619 {0x20, 0x2, 0x2, 0, 0},
620 {0x21, 0x23, 0x23, 0, 0},
621 {0x22, 0x8, 0x8, 0, 0},
622 {0x23, 0, 0, 0, 0},
623 {0x24, 0, 0, 0, 0},
624 {0x25, 0xc, 0xc, 0, 0},
625 {0x26, 0x33, 0x33, 0, 0},
626 {0x27, 0x55, 0x55, 0, 0},
627 {0x28, 0, 0, 0, 0},
628 {0x29, 0x30, 0x30, 0, 0},
629 {0x2A, 0xb, 0xb, 0, 0},
630 {0x2B, 0x1b, 0x1b, 0, 0},
631 {0x2C, 0x3, 0x3, 0, 0},
632 {0x2D, 0x1b, 0x1b, 0, 0},
633 {0x2E, 0, 0, 0, 0},
634 {0x2F, 0x20, 0x20, 0, 0},
635 {0x30, 0xa, 0xa, 0, 0},
636 {0x31, 0, 0, 0, 0},
637 {0x32, 0x62, 0x62, 0, 0},
638 {0x33, 0x19, 0x19, 0, 0},
639 {0x34, 0x33, 0x33, 0, 0},
640 {0x35, 0x77, 0x77, 0, 0},
641 {0x36, 0, 0, 0, 0},
642 {0x37, 0x70, 0x70, 0, 0},
643 {0x38, 0x3, 0x3, 0, 0},
644 {0x39, 0xf, 0xf, 0, 0},
645 {0x3A, 0x6, 0x6, 0, 0},
646 {0x3B, 0xcf, 0xcf, 0, 0},
647 {0x3C, 0x1a, 0x1a, 0, 0},
648 {0x3D, 0x6, 0x6, 0, 0},
649 {0x3E, 0x42, 0x42, 0, 0},
650 {0x3F, 0, 0, 0, 0},
651 {0x40, 0xfb, 0xfb, 0, 0},
652 {0x41, 0x9a, 0x9a, 0, 0},
653 {0x42, 0x7a, 0x7a, 0, 0},
654 {0x43, 0x29, 0x29, 0, 0},
655 {0x44, 0, 0, 0, 0},
656 {0x45, 0x8, 0x8, 0, 0},
657 {0x46, 0xce, 0xce, 0, 0},
658 {0x47, 0x27, 0x27, 0, 0},
659 {0x48, 0x62, 0x62, 0, 0},
660 {0x49, 0x6, 0x6, 0, 0},
661 {0x4A, 0x58, 0x58, 0, 0},
662 {0x4B, 0xf7, 0xf7, 0, 0},
663 {0x4C, 0, 0, 0, 0},
664 {0x4D, 0xb3, 0xb3, 0, 0},
665 {0x4E, 0, 0, 0, 0},
666 {0x4F, 0x2, 0x2, 0, 0},
667 {0x50, 0, 0, 0, 0},
668 {0x51, 0x9, 0x9, 0, 0},
669 {0x52, 0x5, 0x5, 0, 0},
670 {0x53, 0x17, 0x17, 0, 0},
671 {0x54, 0x38, 0x38, 0, 0},
672 {0x55, 0, 0, 0, 0},
673 {0x56, 0, 0, 0, 0},
674 {0x57, 0xb, 0xb, 0, 0},
675 {0x58, 0, 0, 0, 0},
676 {0x59, 0, 0, 0, 0},
677 {0x5A, 0, 0, 0, 0},
678 {0x5B, 0, 0, 0, 0},
679 {0x5C, 0, 0, 0, 0},
680 {0x5D, 0, 0, 0, 0},
681 {0x5E, 0x88, 0x88, 0, 0},
682 {0x5F, 0xcc, 0xcc, 0, 0},
683 {0x60, 0x74, 0x74, 0, 0},
684 {0x61, 0x74, 0x74, 0, 0},
685 {0x62, 0x74, 0x74, 0, 0},
686 {0x63, 0x44, 0x44, 0, 0},
687 {0x64, 0x77, 0x77, 0, 0},
688 {0x65, 0x44, 0x44, 0, 0},
689 {0x66, 0x77, 0x77, 0, 0},
690 {0x67, 0x55, 0x55, 0, 0},
691 {0x68, 0x77, 0x77, 0, 0},
692 {0x69, 0x77, 0x77, 0, 0},
693 {0x6A, 0, 0, 0, 0},
694 {0x6B, 0x7f, 0x7f, 0, 0},
695 {0x6C, 0x8, 0x8, 0, 0},
696 {0x6D, 0, 0, 0, 0},
697 {0x6E, 0x88, 0x88, 0, 0},
698 {0x6F, 0x66, 0x66, 0, 0},
699 {0x70, 0x66, 0x66, 0, 0},
700 {0x71, 0x28, 0x28, 0, 0},
701 {0x72, 0x55, 0x55, 0, 0},
702 {0x73, 0x4, 0x4, 0, 0},
703 {0x74, 0, 0, 0, 0},
704 {0x75, 0, 0, 0, 0},
705 {0x76, 0, 0, 0, 0},
706 {0x77, 0x1, 0x1, 0, 0},
707 {0x78, 0xd6, 0xd6, 0, 0},
708 {0x79, 0, 0, 0, 0},
709 {0x7A, 0, 0, 0, 0},
710 {0x7B, 0, 0, 0, 0},
711 {0x7C, 0, 0, 0, 0},
712 {0x7D, 0, 0, 0, 0},
713 {0x7E, 0, 0, 0, 0},
714 {0x7F, 0, 0, 0, 0},
715 {0x80, 0, 0, 0, 0},
716 {0x81, 0, 0, 0, 0},
717 {0x82, 0, 0, 0, 0},
718 {0x83, 0xb4, 0xb4, 0, 0},
719 {0x84, 0x1, 0x1, 0, 0},
720 {0x85, 0x20, 0x20, 0, 0},
721 {0x86, 0x5, 0x5, 0, 0},
722 {0x87, 0xff, 0xff, 0, 0},
723 {0x88, 0x7, 0x7, 0, 0},
724 {0x89, 0x77, 0x77, 0, 0},
725 {0x8A, 0x77, 0x77, 0, 0},
726 {0x8B, 0x77, 0x77, 0, 0},
727 {0x8C, 0x77, 0x77, 0, 0},
728 {0x8D, 0x8, 0x8, 0, 0},
729 {0x8E, 0xa, 0xa, 0, 0},
730 {0x8F, 0x8, 0x8, 0, 0},
731 {0x90, 0x18, 0x18, 0, 0},
732 {0x91, 0x5, 0x5, 0, 0},
733 {0x92, 0x1f, 0x1f, 0, 0},
734 {0x93, 0x10, 0x10, 0, 0},
735 {0x94, 0x3, 0x3, 0, 0},
736 {0x95, 0, 0, 0, 0},
737 {0x96, 0, 0, 0, 0},
738 {0x97, 0xaa, 0xaa, 0, 0},
739 {0x98, 0, 0, 0, 0},
740 {0x99, 0x23, 0x23, 0, 0},
741 {0x9A, 0x7, 0x7, 0, 0},
742 {0x9B, 0xf, 0xf, 0, 0},
743 {0x9C, 0x10, 0x10, 0, 0},
744 {0x9D, 0x3, 0x3, 0, 0},
745 {0x9E, 0x4, 0x4, 0, 0},
746 {0x9F, 0x20, 0x20, 0, 0},
747 {0xA0, 0, 0, 0, 0},
748 {0xA1, 0, 0, 0, 0},
749 {0xA2, 0, 0, 0, 0},
750 {0xA3, 0, 0, 0, 0},
751 {0xA4, 0x1, 0x1, 0, 0},
752 {0xA5, 0x77, 0x77, 0, 0},
753 {0xA6, 0x77, 0x77, 0, 0},
754 {0xA7, 0x77, 0x77, 0, 0},
755 {0xA8, 0x77, 0x77, 0, 0},
756 {0xA9, 0x8c, 0x8c, 0, 0},
757 {0xAA, 0x88, 0x88, 0, 0},
758 {0xAB, 0x78, 0x78, 0, 0},
759 {0xAC, 0x57, 0x57, 0, 0},
760 {0xAD, 0x88, 0x88, 0, 0},
761 {0xAE, 0, 0, 0, 0},
762 {0xAF, 0x8, 0x8, 0, 0},
763 {0xB0, 0x88, 0x88, 0, 0},
764 {0xB1, 0, 0, 0, 0},
765 {0xB2, 0x1b, 0x1b, 0, 0},
766 {0xB3, 0x3, 0x3, 0, 0},
767 {0xB4, 0x24, 0x24, 0, 0},
768 {0xB5, 0x3, 0x3, 0, 0},
769 {0xB6, 0x1b, 0x1b, 0, 0},
770 {0xB7, 0x24, 0x24, 0, 0},
771 {0xB8, 0x3, 0x3, 0, 0},
772 {0xB9, 0, 0, 0, 0},
773 {0xBA, 0xaa, 0xaa, 0, 0},
774 {0xBB, 0, 0, 0, 0},
775 {0xBC, 0x4, 0x4, 0, 0},
776 {0xBD, 0, 0, 0, 0},
777 {0xBE, 0x8, 0x8, 0, 0},
778 {0xBF, 0x11, 0x11, 0, 0},
779 {0xC0, 0, 0, 0, 0},
780 {0xC1, 0, 0, 0, 0},
781 {0xC2, 0x62, 0x62, 0, 0},
782 {0xC3, 0x1e, 0x1e, 0, 0},
783 {0xC4, 0x33, 0x33, 0, 0},
784 {0xC5, 0x37, 0x37, 0, 0},
785 {0xC6, 0, 0, 0, 0},
786 {0xC7, 0x70, 0x70, 0, 0},
787 {0xC8, 0x1e, 0x1e, 0, 0},
788 {0xC9, 0x6, 0x6, 0, 0},
789 {0xCA, 0x4, 0x4, 0, 0},
790 {0xCB, 0x2f, 0x2f, 0, 0},
791 {0xCC, 0xf, 0xf, 0, 0},
792 {0xCD, 0, 0, 0, 0},
793 {0xCE, 0xff, 0xff, 0, 0},
794 {0xCF, 0x8, 0x8, 0, 0},
795 {0xD0, 0x3f, 0x3f, 0, 0},
796 {0xD1, 0x3f, 0x3f, 0, 0},
797 {0xD2, 0x3f, 0x3f, 0, 0},
798 {0xD3, 0, 0, 0, 0},
799 {0xD4, 0, 0, 0, 0},
800 {0xD5, 0, 0, 0, 0},
801 {0xD6, 0xcc, 0xcc, 0, 0},
802 {0xD7, 0, 0, 0, 0},
803 {0xD8, 0x8, 0x8, 0, 0},
804 {0xD9, 0x8, 0x8, 0, 0},
805 {0xDA, 0x8, 0x8, 0, 0},
806 {0xDB, 0x11, 0x11, 0, 0},
807 {0xDC, 0, 0, 0, 0},
808 {0xDD, 0x87, 0x87, 0, 0},
809 {0xDE, 0x88, 0x88, 0, 0},
810 {0xDF, 0x8, 0x8, 0, 0},
811 {0xE0, 0x8, 0x8, 0, 0},
812 {0xE1, 0x8, 0x8, 0, 0},
813 {0xE2, 0, 0, 0, 0},
814 {0xE3, 0, 0, 0, 0},
815 {0xE4, 0, 0, 0, 0},
816 {0xE5, 0xf5, 0xf5, 0, 0},
817 {0xE6, 0x30, 0x30, 0, 0},
818 {0xE7, 0x1, 0x1, 0, 0},
819 {0xE8, 0, 0, 0, 0},
820 {0xE9, 0xff, 0xff, 0, 0},
821 {0xEA, 0, 0, 0, 0},
822 {0xEB, 0, 0, 0, 0},
823 {0xEC, 0x22, 0x22, 0, 0},
824 {0xED, 0, 0, 0, 0},
825 {0xEE, 0, 0, 0, 0},
826 {0xEF, 0, 0, 0, 0},
827 {0xF0, 0x3, 0x3, 0, 0},
828 {0xF1, 0x1, 0x1, 0, 0},
829 {0xF2, 0, 0, 0, 0},
830 {0xF3, 0, 0, 0, 0},
831 {0xF4, 0, 0, 0, 0},
832 {0xF5, 0, 0, 0, 0},
833 {0xF6, 0, 0, 0, 0},
834 {0xF7, 0x6, 0x6, 0, 0},
835 {0xF8, 0, 0, 0, 0},
836 {0xF9, 0, 0, 0, 0},
837 {0xFA, 0x40, 0x40, 0, 0},
838 {0xFB, 0, 0, 0, 0},
839 {0xFC, 0x1, 0x1, 0, 0},
840 {0xFD, 0x80, 0x80, 0, 0},
841 {0xFE, 0x2, 0x2, 0, 0},
842 {0xFF, 0x10, 0x10, 0, 0},
843 {0x100, 0x2, 0x2, 0, 0},
844 {0x101, 0x1e, 0x1e, 0, 0},
845 {0x102, 0x1e, 0x1e, 0, 0},
846 {0x103, 0, 0, 0, 0},
847 {0x104, 0x1f, 0x1f, 0, 0},
848 {0x105, 0, 0x8, 0, 1},
849 {0x106, 0x2a, 0x2a, 0, 0},
850 {0x107, 0xf, 0xf, 0, 0},
851 {0x108, 0, 0, 0, 0},
852 {0x109, 0, 0, 0, 0},
853 {0x10A, 0, 0, 0, 0},
854 {0x10B, 0, 0, 0, 0},
855 {0x10C, 0, 0, 0, 0},
856 {0x10D, 0, 0, 0, 0},
857 {0x10E, 0, 0, 0, 0},
858 {0x10F, 0, 0, 0, 0},
859 {0x110, 0, 0, 0, 0},
860 {0x111, 0, 0, 0, 0},
861 {0x112, 0, 0, 0, 0},
862 {0x113, 0, 0, 0, 0},
863 {0x114, 0, 0, 0, 0},
864 {0x115, 0, 0, 0, 0},
865 {0x116, 0, 0, 0, 0},
866 {0x117, 0, 0, 0, 0},
867 {0x118, 0, 0, 0, 0},
868 {0x119, 0, 0, 0, 0},
869 {0x11A, 0, 0, 0, 0},
870 {0x11B, 0, 0, 0, 0},
871 {0x11C, 0x1, 0x1, 0, 0},
872 {0x11D, 0, 0, 0, 0},
873 {0x11E, 0, 0, 0, 0},
874 {0x11F, 0, 0, 0, 0},
875 {0x120, 0, 0, 0, 0},
876 {0x121, 0, 0, 0, 0},
877 {0x122, 0x80, 0x80, 0, 0},
878 {0x123, 0, 0, 0, 0},
879 {0x124, 0xf8, 0xf8, 0, 0},
880 {0x125, 0, 0, 0, 0},
881 {0x126, 0, 0, 0, 0},
882 {0x127, 0, 0, 0, 0},
883 {0x128, 0, 0, 0, 0},
884 {0x129, 0, 0, 0, 0},
885 {0x12A, 0, 0, 0, 0},
886 {0x12B, 0, 0, 0, 0},
887 {0x12C, 0, 0, 0, 0},
888 {0x12D, 0, 0, 0, 0},
889 {0x12E, 0, 0, 0, 0},
890 {0x12F, 0, 0, 0, 0},
891 {0x130, 0, 0, 0, 0},
892 {0xFFFF, 0, 0, 0, 0}
893 };
894
895 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
896 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
897
898 u16
899 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
900 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
901 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
902 128, 64,},
903 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
904 167, 93,},
905 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
906 128, 64,},
907 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
908 170, 340, 170,},
909 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
910 256, 185, 256,},
911 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
912 256, 273, 256,},
913 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
914 256, 352, 256,},
915 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
916 128, 233, 128,},
917 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
918 1881, 256,},
919 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
920 1881, 256,},
921 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
922 384, 288,},
923 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
924 128, 384, 288,},
925 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
926 170, 340, 170,},
927 };
928
929 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
930 u16
931 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
932 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
933 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
934 0x278, 0xfea0, 0x80, 0x100, 0x80,},
935 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
936 750, 0xFE2B, 212, 0xFFCE, 212,},
937 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
938 0xFEF2, 128, 0xFFE2, 128}
939 };
940
941 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
942 mod_phy_reg(pi, 0x4a4, \
943 (0x1ff << 0), \
944 (u16)(idx) << 0)
945
946 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
947 mod_phy_reg(pi, 0x4a5, \
948 (0x7 << 8), \
949 (u16)(npt) << 8)
950
951 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
952 (read_phy_reg((pi), 0x4a4) & \
953 ((0x1 << 15) | \
954 (0x1 << 14) | \
955 (0x1 << 13)))
956
957 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
958 ((read_phy_reg(pi, 0x4a5) & \
959 (0x7 << 8)) >> \
960 8)
961
962 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
963 (read_phy_reg(pi, 0x473) & 0x1ff)
964
965 #define wlc_lcnphy_get_target_tx_pwr(pi) \
966 ((read_phy_reg(pi, 0x4a7) & \
967 (0xff << 0)) >> \
968 0)
969
970 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
971 mod_phy_reg(pi, 0x4a7, \
972 (0xff << 0), \
973 (u16)(target) << 0)
974
975 #define wlc_radio_2064_rcal_done(pi) (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
976 #define tempsense_done(pi) (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
977
978 #define LCNPHY_IQLOCC_READ(val) ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
979 #define FIXED_TXPWR 78
980 #define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
981
982 static u32 wlc_lcnphy_qdiv_roundup(u32 divident, u32 divisor,
983 u8 precision);
984 static void wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
985 u16 ext_lna, u16 trsw,
986 u16 biq2, u16 biq1,
987 u16 tia, u16 lna2,
988 u16 lna1);
989 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi);
990 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain);
991 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx);
992 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0);
993 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi);
994 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains);
995 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable);
996 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi);
997 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable);
998 static void wlc_lcnphy_set_tx_gain(phy_info_t *pi,
999 lcnphy_txgains_t *target_gains);
1000 static bool wlc_lcnphy_rx_iq_est(phy_info_t *pi, u16 num_samps,
1001 u8 wait_time, lcnphy_iq_est_t *iq_est);
1002 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps);
1003 static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi);
1004 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode);
1005 extern void wlc_lcnphy_tx_pwr_ctrl_init(wlc_phy_t *ppi);
1006 static void wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t *pi,
1007 u8 channel);
1008
1009 static void wlc_lcnphy_load_tx_gain_table(phy_info_t *pi,
1010 const lcnphy_tx_gain_tbl_entry *g);
1011
1012 static void wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo,
1013 u16 thresh, s16 *ptr, int mode);
1014 static int wlc_lcnphy_calc_floor(s16 coeff, int type);
1015 static void wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi,
1016 u16 *values_to_save);
1017 static void wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t *pi,
1018 u16 *values_to_save);
1019 static void wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, s16 coeff_x,
1020 s16 coeff_y);
1021 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type);
1022 static void wlc_lcnphy_a1(phy_info_t *pi, int cal_type,
1023 int num_levels, int step_size_lg2);
1024 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi);
1025
1026 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi,
1027 chanspec_t chanspec);
1028 static void wlc_lcnphy_agc_temp_init(phy_info_t *pi);
1029 static void wlc_lcnphy_temp_adj(phy_info_t *pi);
1030 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi);
1031 static void wlc_lcnphy_baseband_init(phy_info_t *pi);
1032 static void wlc_lcnphy_radio_init(phy_info_t *pi);
1033 static void wlc_lcnphy_rc_cal(phy_info_t *pi);
1034 static void wlc_lcnphy_rcal(phy_info_t *pi);
1035 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable);
1036 static int wlc_lcnphy_load_tx_iir_filter(phy_info_t *pi, bool is_ofdm,
1037 s16 filt_type);
1038 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b);
1039
wlc_lcnphy_write_table(phy_info_t * pi,const phytbl_info_t * pti)1040 void wlc_lcnphy_write_table(phy_info_t *pi, const phytbl_info_t *pti)
1041 {
1042 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
1043 }
1044
wlc_lcnphy_read_table(phy_info_t * pi,phytbl_info_t * pti)1045 void wlc_lcnphy_read_table(phy_info_t *pi, phytbl_info_t *pti)
1046 {
1047 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
1048 }
1049
1050 static void
wlc_lcnphy_common_read_table(phy_info_t * pi,u32 tbl_id,const void * tbl_ptr,u32 tbl_len,u32 tbl_width,u32 tbl_offset)1051 wlc_lcnphy_common_read_table(phy_info_t *pi, u32 tbl_id,
1052 const void *tbl_ptr, u32 tbl_len,
1053 u32 tbl_width, u32 tbl_offset)
1054 {
1055 phytbl_info_t tab;
1056 tab.tbl_id = tbl_id;
1057 tab.tbl_ptr = tbl_ptr;
1058 tab.tbl_len = tbl_len;
1059 tab.tbl_width = tbl_width;
1060 tab.tbl_offset = tbl_offset;
1061 wlc_lcnphy_read_table(pi, &tab);
1062 }
1063
1064 static void
wlc_lcnphy_common_write_table(phy_info_t * pi,u32 tbl_id,const void * tbl_ptr,u32 tbl_len,u32 tbl_width,u32 tbl_offset)1065 wlc_lcnphy_common_write_table(phy_info_t *pi, u32 tbl_id,
1066 const void *tbl_ptr, u32 tbl_len,
1067 u32 tbl_width, u32 tbl_offset)
1068 {
1069
1070 phytbl_info_t tab;
1071 tab.tbl_id = tbl_id;
1072 tab.tbl_ptr = tbl_ptr;
1073 tab.tbl_len = tbl_len;
1074 tab.tbl_width = tbl_width;
1075 tab.tbl_offset = tbl_offset;
1076 wlc_lcnphy_write_table(pi, &tab);
1077 }
1078
1079 static u32
wlc_lcnphy_qdiv_roundup(u32 dividend,u32 divisor,u8 precision)1080 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1081 {
1082 u32 quotient, remainder, roundup, rbit;
1083
1084 ASSERT(divisor);
1085
1086 quotient = dividend / divisor;
1087 remainder = dividend % divisor;
1088 rbit = divisor & 1;
1089 roundup = (divisor >> 1) + rbit;
1090
1091 while (precision--) {
1092 quotient <<= 1;
1093 if (remainder >= roundup) {
1094 quotient++;
1095 remainder = ((remainder - roundup) << 1) + rbit;
1096 } else {
1097 remainder <<= 1;
1098 }
1099 }
1100
1101 if (remainder >= roundup)
1102 quotient++;
1103
1104 return quotient;
1105 }
1106
wlc_lcnphy_calc_floor(s16 coeff_x,int type)1107 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1108 {
1109 int k;
1110 k = 0;
1111 if (type == 0) {
1112 if (coeff_x < 0) {
1113 k = (coeff_x - 1) / 2;
1114 } else {
1115 k = coeff_x / 2;
1116 }
1117 }
1118 if (type == 1) {
1119 if ((coeff_x + 1) < 0)
1120 k = (coeff_x) / 2;
1121 else
1122 k = (coeff_x + 1) / 2;
1123 }
1124 return k;
1125 }
1126
wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t * pi)1127 s8 wlc_lcnphy_get_current_tx_pwr_idx(phy_info_t *pi)
1128 {
1129 s8 index;
1130 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1131
1132 if (txpwrctrl_off(pi))
1133 index = pi_lcn->lcnphy_current_index;
1134 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1135 index =
1136 (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
1137 / 2);
1138 else
1139 index = pi_lcn->lcnphy_current_index;
1140 return index;
1141 }
1142
wlc_lcnphy_measure_digital_power(phy_info_t * pi,u16 nsamples)1143 static u32 wlc_lcnphy_measure_digital_power(phy_info_t *pi, u16 nsamples)
1144 {
1145 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
1146
1147 if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1148 return 0;
1149 return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1150 }
1151
wlc_lcnphy_crsuprs(phy_info_t * pi,int channel)1152 void wlc_lcnphy_crsuprs(phy_info_t *pi, int channel)
1153 {
1154 u16 afectrlovr, afectrlovrval;
1155 afectrlovr = read_phy_reg(pi, 0x43b);
1156 afectrlovrval = read_phy_reg(pi, 0x43c);
1157 if (channel != 0) {
1158 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1159
1160 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1161
1162 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1163
1164 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1165
1166 write_phy_reg(pi, 0x44b, 0xffff);
1167 wlc_lcnphy_tx_pu(pi, 1);
1168
1169 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1170
1171 or_phy_reg(pi, 0x6da, 0x0080);
1172
1173 or_phy_reg(pi, 0x00a, 0x228);
1174 } else {
1175 and_phy_reg(pi, 0x00a, ~(0x228));
1176
1177 and_phy_reg(pi, 0x6da, 0xFF7F);
1178 write_phy_reg(pi, 0x43b, afectrlovr);
1179 write_phy_reg(pi, 0x43c, afectrlovrval);
1180 }
1181 }
1182
wlc_lcnphy_toggle_afe_pwdn(phy_info_t * pi)1183 static void wlc_lcnphy_toggle_afe_pwdn(phy_info_t *pi)
1184 {
1185 u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1186
1187 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1188 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1189
1190 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1191 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1192
1193 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1194 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1195
1196 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1197 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1198 }
1199
wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t * pi,bool enable)1200 static void wlc_lcnphy_txrx_spur_avoidance_mode(phy_info_t *pi, bool enable)
1201 {
1202 if (enable) {
1203 write_phy_reg(pi, 0x942, 0x7);
1204 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1205 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1206
1207 write_phy_reg(pi, 0x44a, 0x084);
1208 write_phy_reg(pi, 0x44a, 0x080);
1209 write_phy_reg(pi, 0x6d3, 0x2222);
1210 write_phy_reg(pi, 0x6d3, 0x2220);
1211 } else {
1212 write_phy_reg(pi, 0x942, 0x0);
1213 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1214 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1215 }
1216 wlapi_switch_macfreq(pi->sh->physhim, enable);
1217 }
1218
wlc_phy_chanspec_set_lcnphy(phy_info_t * pi,chanspec_t chanspec)1219 void wlc_phy_chanspec_set_lcnphy(phy_info_t *pi, chanspec_t chanspec)
1220 {
1221 u8 channel = CHSPEC_CHANNEL(chanspec);
1222
1223 wlc_phy_chanspec_radio_set((wlc_phy_t *) pi, chanspec);
1224
1225 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1226
1227 or_phy_reg(pi, 0x44a, 0x44);
1228 write_phy_reg(pi, 0x44a, 0x80);
1229
1230 if (!NORADIO_ENAB(pi->pubpi)) {
1231 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1232 udelay(1000);
1233 }
1234
1235 wlc_lcnphy_toggle_afe_pwdn(pi);
1236
1237 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1238 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1239
1240 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1241 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1242
1243 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
1244 } else {
1245 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1246
1247 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
1248 }
1249
1250 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
1251
1252 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1253
1254 }
1255
wlc_lcnphy_set_dac_gain(phy_info_t * pi,u16 dac_gain)1256 static void wlc_lcnphy_set_dac_gain(phy_info_t *pi, u16 dac_gain)
1257 {
1258 u16 dac_ctrl;
1259
1260 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1261 dac_ctrl = dac_ctrl & 0xc7f;
1262 dac_ctrl = dac_ctrl | (dac_gain << 7);
1263 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1264
1265 }
1266
wlc_lcnphy_set_tx_gain_override(phy_info_t * pi,bool bEnable)1267 static void wlc_lcnphy_set_tx_gain_override(phy_info_t *pi, bool bEnable)
1268 {
1269 u16 bit = bEnable ? 1 : 0;
1270
1271 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1272
1273 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1274
1275 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1276 }
1277
wlc_lcnphy_get_pa_gain(phy_info_t * pi)1278 static u16 wlc_lcnphy_get_pa_gain(phy_info_t *pi)
1279 {
1280 u16 pa_gain;
1281
1282 pa_gain = (read_phy_reg(pi, 0x4fb) &
1283 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1284 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1285
1286 return pa_gain;
1287 }
1288
1289 static void
wlc_lcnphy_set_tx_gain(phy_info_t * pi,lcnphy_txgains_t * target_gains)1290 wlc_lcnphy_set_tx_gain(phy_info_t *pi, lcnphy_txgains_t *target_gains)
1291 {
1292 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1293
1294 mod_phy_reg(pi, 0x4b5,
1295 (0xffff << 0),
1296 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1297 0);
1298 mod_phy_reg(pi, 0x4fb,
1299 (0x7fff << 0),
1300 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1301
1302 mod_phy_reg(pi, 0x4fc,
1303 (0xffff << 0),
1304 ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
1305 0);
1306 mod_phy_reg(pi, 0x4fd,
1307 (0x7fff << 0),
1308 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1309
1310 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1311
1312 wlc_lcnphy_enable_tx_gain_override(pi);
1313 }
1314
wlc_lcnphy_set_bbmult(phy_info_t * pi,u8 m0)1315 static void wlc_lcnphy_set_bbmult(phy_info_t *pi, u8 m0)
1316 {
1317 u16 m0m1 = (u16) m0 << 8;
1318 phytbl_info_t tab;
1319
1320 tab.tbl_ptr = &m0m1;
1321 tab.tbl_len = 1;
1322 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1323 tab.tbl_offset = 87;
1324 tab.tbl_width = 16;
1325 wlc_lcnphy_write_table(pi, &tab);
1326 }
1327
wlc_lcnphy_clear_tx_power_offsets(phy_info_t * pi)1328 static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi)
1329 {
1330 u32 data_buf[64];
1331 phytbl_info_t tab;
1332
1333 memset(data_buf, 0, sizeof(data_buf));
1334
1335 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1336 tab.tbl_width = 32;
1337 tab.tbl_ptr = data_buf;
1338
1339 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1340
1341 tab.tbl_len = 30;
1342 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1343 wlc_lcnphy_write_table(pi, &tab);
1344 }
1345
1346 tab.tbl_len = 64;
1347 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1348 wlc_lcnphy_write_table(pi, &tab);
1349 }
1350
1351 typedef enum {
1352 LCNPHY_TSSI_PRE_PA,
1353 LCNPHY_TSSI_POST_PA,
1354 LCNPHY_TSSI_EXT
1355 } lcnphy_tssi_mode_t;
1356
wlc_lcnphy_set_tssi_mux(phy_info_t * pi,lcnphy_tssi_mode_t pos)1357 static void wlc_lcnphy_set_tssi_mux(phy_info_t *pi, lcnphy_tssi_mode_t pos)
1358 {
1359 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1360
1361 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1362
1363 if (LCNPHY_TSSI_POST_PA == pos) {
1364 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1365
1366 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1367
1368 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1369 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1370 } else {
1371 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1372 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1373 }
1374 } else {
1375 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
1376
1377 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
1378
1379 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1380 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1381 } else {
1382 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
1383 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1384 }
1385 }
1386 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
1387
1388 if (LCNPHY_TSSI_EXT == pos) {
1389 write_radio_reg(pi, RADIO_2064_REG07F, 1);
1390 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
1391 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
1392 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
1393 }
1394 }
1395
wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t * pi)1396 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(phy_info_t *pi)
1397 {
1398 u16 N1, N2, N3, N4, N5, N6, N;
1399 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
1400 >> 0);
1401 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
1402 >> 12);
1403 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
1404 >> 0);
1405 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
1406 >> 8);
1407 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
1408 >> 0);
1409 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
1410 >> 8);
1411 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
1412 if (N < 1600)
1413 N = 1600;
1414 return N;
1415 }
1416
wlc_lcnphy_pwrctrl_rssiparams(phy_info_t * pi)1417 static void wlc_lcnphy_pwrctrl_rssiparams(phy_info_t *pi)
1418 {
1419 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
1420 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1421
1422 auxpga_vmid =
1423 (2 << 8) | (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
1424 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
1425 auxpga_gain_temp = 2;
1426
1427 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
1428
1429 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
1430
1431 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
1432
1433 mod_phy_reg(pi, 0x4db,
1434 (0x3ff << 0) |
1435 (0x7 << 12),
1436 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1437
1438 mod_phy_reg(pi, 0x4dc,
1439 (0x3ff << 0) |
1440 (0x7 << 12),
1441 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1442
1443 mod_phy_reg(pi, 0x40a,
1444 (0x3ff << 0) |
1445 (0x7 << 12),
1446 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
1447
1448 mod_phy_reg(pi, 0x40b,
1449 (0x3ff << 0) |
1450 (0x7 << 12),
1451 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1452
1453 mod_phy_reg(pi, 0x40c,
1454 (0x3ff << 0) |
1455 (0x7 << 12),
1456 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
1457
1458 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
1459 }
1460
wlc_lcnphy_tssi_setup(phy_info_t * pi)1461 static void wlc_lcnphy_tssi_setup(phy_info_t *pi)
1462 {
1463 phytbl_info_t tab;
1464 u32 rfseq, ind;
1465
1466 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1467 tab.tbl_width = 32;
1468 tab.tbl_ptr = &ind;
1469 tab.tbl_len = 1;
1470 tab.tbl_offset = 0;
1471 for (ind = 0; ind < 128; ind++) {
1472 wlc_lcnphy_write_table(pi, &tab);
1473 tab.tbl_offset++;
1474 }
1475 tab.tbl_offset = 704;
1476 for (ind = 0; ind < 128; ind++) {
1477 wlc_lcnphy_write_table(pi, &tab);
1478 tab.tbl_offset++;
1479 }
1480 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
1481
1482 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
1483
1484 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
1485
1486 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
1487 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
1488
1489 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
1490
1491 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
1492
1493 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
1494
1495 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
1496
1497 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
1498
1499 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
1500
1501 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
1502
1503 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
1504
1505 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
1506
1507 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
1508
1509 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
1510
1511 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
1512
1513 wlc_lcnphy_clear_tx_power_offsets(pi);
1514
1515 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
1516
1517 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
1518
1519 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
1520
1521 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1522 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
1523 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1524 } else {
1525 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1526 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
1527 }
1528
1529 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
1530
1531 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1532 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
1533 } else {
1534 if (CHSPEC_IS2G(pi->radio_chanspec))
1535 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1536 else
1537 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
1538 }
1539
1540 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
1541 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
1542 else
1543 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
1544
1545 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
1546
1547 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
1548
1549 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1550 mod_phy_reg(pi, 0x4d7,
1551 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
1552 }
1553
1554 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
1555 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
1556 tab.tbl_width = 16;
1557 tab.tbl_ptr = &rfseq;
1558 tab.tbl_len = 1;
1559 tab.tbl_offset = 6;
1560 wlc_lcnphy_write_table(pi, &tab);
1561
1562 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
1563
1564 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
1565
1566 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1567
1568 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
1569
1570 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
1571
1572 wlc_lcnphy_pwrctrl_rssiparams(pi);
1573 }
1574
wlc_lcnphy_tx_pwr_update_npt(phy_info_t * pi)1575 void wlc_lcnphy_tx_pwr_update_npt(phy_info_t *pi)
1576 {
1577 u16 tx_cnt, tx_total, npt;
1578 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1579
1580 tx_total = wlc_lcnphy_total_tx_frames(pi);
1581 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
1582 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
1583
1584 if (tx_cnt > (1 << npt)) {
1585
1586 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
1587
1588 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
1589 pi_lcn->lcnphy_tssi_npt = npt;
1590
1591 }
1592 }
1593
wlc_lcnphy_tssi2dbm(s32 tssi,s32 a1,s32 b0,s32 b1)1594 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
1595 {
1596 s32 a, b, p;
1597
1598 a = 32768 + (a1 * tssi);
1599 b = (1024 * b0) + (64 * b1 * tssi);
1600 p = ((2 * b) + a) / (2 * a);
1601
1602 return p;
1603 }
1604
wlc_lcnphy_txpower_reset_npt(phy_info_t * pi)1605 static void wlc_lcnphy_txpower_reset_npt(phy_info_t *pi)
1606 {
1607 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1608 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1609 return;
1610
1611 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
1612 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
1613 }
1614
wlc_lcnphy_txpower_recalc_target(phy_info_t * pi)1615 void wlc_lcnphy_txpower_recalc_target(phy_info_t *pi)
1616 {
1617 phytbl_info_t tab;
1618 u32 rate_table[WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM +
1619 WLC_NUM_RATES_MCS_1_STREAM];
1620 uint i, j;
1621 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
1622 return;
1623
1624 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
1625
1626 if (i == WLC_NUM_RATES_CCK + WLC_NUM_RATES_OFDM)
1627 j = TXP_FIRST_MCS_20_SISO;
1628
1629 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
1630 }
1631
1632 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1633 tab.tbl_width = 32;
1634 tab.tbl_len = ARRAY_SIZE(rate_table);
1635 tab.tbl_ptr = rate_table;
1636 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1637 wlc_lcnphy_write_table(pi, &tab);
1638
1639 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
1640 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
1641
1642 wlc_lcnphy_txpower_reset_npt(pi);
1643 }
1644 }
1645
wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t * pi,s8 index)1646 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(phy_info_t *pi, s8 index)
1647 {
1648 u32 cck_offset[4] = { 22, 22, 22, 22 };
1649 u32 ofdm_offset, reg_offset_cck;
1650 int i;
1651 u16 index2;
1652 phytbl_info_t tab;
1653
1654 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1655 return;
1656
1657 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1658
1659 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
1660
1661 or_phy_reg(pi, 0x6da, 0x0040);
1662
1663 reg_offset_cck = 0;
1664 for (i = 0; i < 4; i++)
1665 cck_offset[i] -= reg_offset_cck;
1666 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1667 tab.tbl_width = 32;
1668 tab.tbl_len = 4;
1669 tab.tbl_ptr = cck_offset;
1670 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1671 wlc_lcnphy_write_table(pi, &tab);
1672 ofdm_offset = 0;
1673 tab.tbl_len = 1;
1674 tab.tbl_ptr = &ofdm_offset;
1675 for (i = 836; i < 862; i++) {
1676 tab.tbl_offset = i;
1677 wlc_lcnphy_write_table(pi, &tab);
1678 }
1679
1680 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
1681
1682 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
1683
1684 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
1685
1686 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
1687
1688 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
1689
1690 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
1691
1692 index2 = (u16) (index * 2);
1693 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
1694
1695 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
1696
1697 }
1698
wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t * pi)1699 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(phy_info_t *pi)
1700 {
1701 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
1702 s16 manp, meas_temp, temp_diff;
1703 bool neg = 0;
1704 u16 temp;
1705 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1706
1707 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1708 return pi_lcn->lcnphy_current_index;
1709
1710 index = FIXED_TXPWR;
1711
1712 if (NORADIO_ENAB(pi->pubpi))
1713 return index;
1714
1715 if (pi_lcn->lcnphy_tempsense_slope == 0) {
1716 return index;
1717 }
1718 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
1719 meas_temp = LCNPHY_TEMPSENSE(temp);
1720
1721 if (pi->tx_power_min != 0) {
1722 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
1723 } else {
1724 delta_brd = 0;
1725 }
1726
1727 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
1728 temp_diff = manp - meas_temp;
1729 if (temp_diff < 0) {
1730
1731 neg = 1;
1732
1733 temp_diff = -temp_diff;
1734 }
1735
1736 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
1737 (u32) (pi_lcn->
1738 lcnphy_tempsense_slope
1739 * 10), 0);
1740 if (neg)
1741 delta_temp = -delta_temp;
1742
1743 if (pi_lcn->lcnphy_tempsense_option == 3
1744 && LCNREV_IS(pi->pubpi.phy_rev, 0))
1745 delta_temp = 0;
1746 if (pi_lcn->lcnphy_tempcorrx > 31)
1747 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
1748 else
1749 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
1750 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1751 tempcorrx = 4;
1752 new_index =
1753 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
1754 new_index += tempcorrx;
1755
1756 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
1757 index = 127;
1758 if (new_index < 0 || new_index > 126) {
1759 return index;
1760 }
1761 return new_index;
1762 }
1763
wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t * pi,u16 mode)1764 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(phy_info_t *pi, u16 mode)
1765 {
1766
1767 u16 current_mode = mode;
1768 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
1769 mode == LCNPHY_TX_PWR_CTRL_HW)
1770 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
1771 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
1772 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
1773 current_mode = LCNPHY_TX_PWR_CTRL_HW;
1774 return current_mode;
1775 }
1776
wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t * pi,u16 mode)1777 void wlc_lcnphy_set_tx_pwr_ctrl(phy_info_t *pi, u16 mode)
1778 {
1779 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1780 s8 index;
1781 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1782
1783 ASSERT((LCNPHY_TX_PWR_CTRL_OFF == mode) ||
1784 (LCNPHY_TX_PWR_CTRL_SW == mode) ||
1785 (LCNPHY_TX_PWR_CTRL_HW == mode) ||
1786 (LCNPHY_TX_PWR_CTRL_TEMPBASED == mode));
1787
1788 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
1789 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
1790
1791 mod_phy_reg(pi, 0x6da, (0x1 << 6),
1792 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
1793
1794 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
1795 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
1796
1797 if (old_mode != mode) {
1798 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
1799
1800 wlc_lcnphy_tx_pwr_update_npt(pi);
1801
1802 wlc_lcnphy_clear_tx_power_offsets(pi);
1803 }
1804 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
1805
1806 wlc_lcnphy_txpower_recalc_target(pi);
1807
1808 wlc_lcnphy_set_start_tx_pwr_idx(pi,
1809 pi_lcn->
1810 lcnphy_tssi_idx);
1811 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
1812 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
1813
1814 pi_lcn->lcnphy_tssi_tx_cnt =
1815 wlc_lcnphy_total_tx_frames(pi);
1816
1817 wlc_lcnphy_disable_tx_gain_override(pi);
1818 pi_lcn->lcnphy_tx_power_idx_override = -1;
1819 } else
1820 wlc_lcnphy_enable_tx_gain_override(pi);
1821
1822 mod_phy_reg(pi, 0x4a4,
1823 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
1824 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
1825 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
1826 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
1827 pi_lcn->lcnphy_current_index = (s8)
1828 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
1829 }
1830 }
1831 }
1832
wlc_lcnphy_iqcal_wait(phy_info_t * pi)1833 static bool wlc_lcnphy_iqcal_wait(phy_info_t *pi)
1834 {
1835 uint delay_count = 0;
1836
1837 while (wlc_lcnphy_iqcal_active(pi)) {
1838 udelay(100);
1839 delay_count++;
1840
1841 if (delay_count > (10 * 500))
1842 break;
1843 }
1844
1845 return (0 == wlc_lcnphy_iqcal_active(pi));
1846 }
1847
1848 static void
wlc_lcnphy_tx_iqlo_cal(phy_info_t * pi,lcnphy_txgains_t * target_gains,lcnphy_cal_mode_t cal_mode,bool keep_tone)1849 wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi,
1850 lcnphy_txgains_t *target_gains,
1851 lcnphy_cal_mode_t cal_mode, bool keep_tone)
1852 {
1853
1854 lcnphy_txgains_t cal_gains, temp_gains;
1855 u16 hash;
1856 u8 band_idx;
1857 int j;
1858 u16 ncorr_override[5];
1859 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
1860 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
1861 };
1862
1863 u16 commands_fullcal[] = {
1864 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1865
1866 u16 commands_recal[] = {
1867 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
1868
1869 u16 command_nums_fullcal[] = {
1870 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1871
1872 u16 command_nums_recal[] = {
1873 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
1874 u16 *command_nums = command_nums_fullcal;
1875
1876 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
1877 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
1878 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
1879 bool tx_gain_override_old;
1880 lcnphy_txgains_t old_gains;
1881 uint i, n_cal_cmds = 0, n_cal_start = 0;
1882 u16 *values_to_save;
1883 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
1884
1885 if (NORADIO_ENAB(pi->pubpi))
1886 return;
1887
1888 values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
1889 if (NULL == values_to_save) {
1890 return;
1891 }
1892
1893 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1894 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1895
1896 or_phy_reg(pi, 0x6da, 0x40);
1897 or_phy_reg(pi, 0x6db, 0x3);
1898
1899 switch (cal_mode) {
1900 case LCNPHY_CAL_FULL:
1901 start_coeffs = syst_coeffs;
1902 cal_cmds = commands_fullcal;
1903 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
1904 break;
1905
1906 case LCNPHY_CAL_RECAL:
1907 ASSERT(pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid);
1908
1909 start_coeffs = syst_coeffs;
1910
1911 cal_cmds = commands_recal;
1912 n_cal_cmds = ARRAY_SIZE(commands_recal);
1913 command_nums = command_nums_recal;
1914 break;
1915 default:
1916 ASSERT(false);
1917 }
1918
1919 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1920 start_coeffs, 11, 16, 64);
1921
1922 write_phy_reg(pi, 0x6da, 0xffff);
1923 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
1924
1925 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1926
1927 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
1928
1929 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1930
1931 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
1932
1933 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
1934
1935 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
1936
1937 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
1938
1939 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1940 if (tx_gain_override_old)
1941 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1942
1943 if (!target_gains) {
1944 if (!tx_gain_override_old)
1945 wlc_lcnphy_set_tx_pwr_by_index(pi,
1946 pi_lcn->lcnphy_tssi_idx);
1947 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
1948 target_gains = &temp_gains;
1949 }
1950
1951 hash = (target_gains->gm_gain << 8) |
1952 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
1953
1954 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
1955
1956 cal_gains = *target_gains;
1957 memset(ncorr_override, 0, sizeof(ncorr_override));
1958 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
1959 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
1960 cal_gains.gm_gain =
1961 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
1962 cal_gains.pga_gain =
1963 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
1964 cal_gains.pad_gain =
1965 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
1966 memcpy(ncorr_override,
1967 &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
1968 sizeof(ncorr_override));
1969 break;
1970 }
1971 }
1972
1973 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
1974
1975 write_phy_reg(pi, 0x453, 0xaa9);
1976 write_phy_reg(pi, 0x93d, 0xc0);
1977
1978 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1979 (const void *)
1980 lcnphy_iqcal_loft_gainladder,
1981 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
1982 16, 0);
1983
1984 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
1985 (const void *)lcnphy_iqcal_ir_gainladder,
1986 ARRAY_SIZE(lcnphy_iqcal_ir_gainladder), 16,
1987 32);
1988
1989 if (pi->phy_tx_tone_freq) {
1990
1991 wlc_lcnphy_stop_tx_tone(pi);
1992 udelay(5);
1993 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1994 } else {
1995 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
1996 }
1997
1998 write_phy_reg(pi, 0x6da, 0xffff);
1999
2000 for (i = n_cal_start; i < n_cal_cmds; i++) {
2001 u16 zero_diq = 0;
2002 u16 best_coeffs[11];
2003 u16 command_num;
2004
2005 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2006
2007 command_num = command_nums[i];
2008 if (ncorr_override[cal_type])
2009 command_num =
2010 ncorr_override[cal_type] << 8 | (command_num &
2011 0xff);
2012
2013 write_phy_reg(pi, 0x452, command_num);
2014
2015 if ((cal_type == 3) || (cal_type == 4)) {
2016
2017 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2018 &diq_start, 1, 16, 69);
2019
2020 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2021 &zero_diq, 1, 16, 69);
2022 }
2023
2024 write_phy_reg(pi, 0x451, cal_cmds[i]);
2025
2026 if (!wlc_lcnphy_iqcal_wait(pi)) {
2027
2028 goto cleanup;
2029 }
2030
2031 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2032 best_coeffs,
2033 ARRAY_SIZE(best_coeffs), 16, 96);
2034 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2035 best_coeffs,
2036 ARRAY_SIZE(best_coeffs), 16, 64);
2037
2038 if ((cal_type == 3) || (cal_type == 4)) {
2039 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2040 &diq_start, 1, 16, 69);
2041 }
2042 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2043 pi_lcn->lcnphy_cal_results.
2044 txiqlocal_bestcoeffs,
2045 ARRAY_SIZE(pi_lcn->
2046 lcnphy_cal_results.
2047 txiqlocal_bestcoeffs),
2048 16, 96);
2049 }
2050
2051 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2052 pi_lcn->lcnphy_cal_results.
2053 txiqlocal_bestcoeffs,
2054 ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2055 txiqlocal_bestcoeffs), 16, 96);
2056 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2057
2058 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2059 &pi_lcn->lcnphy_cal_results.
2060 txiqlocal_bestcoeffs[0], 4, 16, 80);
2061
2062 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2063 &pi_lcn->lcnphy_cal_results.
2064 txiqlocal_bestcoeffs[5], 2, 16, 85);
2065
2066 cleanup:
2067 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2068 kfree(values_to_save);
2069
2070 if (!keep_tone)
2071 wlc_lcnphy_stop_tx_tone(pi);
2072
2073 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2074
2075 write_phy_reg(pi, 0x453, 0);
2076
2077 if (tx_gain_override_old)
2078 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2079 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2080
2081 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2082 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2083
2084 }
2085
wlc_lcnphy_idle_tssi_est(wlc_phy_t * ppi)2086 static void wlc_lcnphy_idle_tssi_est(wlc_phy_t *ppi)
2087 {
2088 bool suspend, tx_gain_override_old;
2089 lcnphy_txgains_t old_gains;
2090 phy_info_t *pi = (phy_info_t *) ppi;
2091 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2092 idleTssi0_regvalue_2C;
2093 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2094 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2095 u16 SAVE_jtag_bb_afe_switch =
2096 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2097 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2098 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2099 idleTssi = read_phy_reg(pi, 0x4ab);
2100 suspend =
2101 (0 ==
2102 (R_REG(&((phy_info_t *) pi)->regs->maccontrol) &
2103 MCTL_EN_MAC));
2104 if (!suspend)
2105 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2106 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2107
2108 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2109 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2110
2111 wlc_lcnphy_enable_tx_gain_override(pi);
2112 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2113 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2114 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2115 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2116 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2117 wlc_lcnphy_tssi_setup(pi);
2118 wlc_phy_do_dummy_tx(pi, true, OFF);
2119 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2120 >> 0);
2121
2122 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2123 >> 0);
2124
2125 if (idleTssi0_2C >= 256)
2126 idleTssi0_OB = idleTssi0_2C - 256;
2127 else
2128 idleTssi0_OB = idleTssi0_2C + 256;
2129
2130 idleTssi0_regvalue_OB = idleTssi0_OB;
2131 if (idleTssi0_regvalue_OB >= 256)
2132 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2133 else
2134 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2135 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2136
2137 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2138
2139 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2140 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2141 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2142
2143 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2144 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2145 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2146 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2147 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2148 if (!suspend)
2149 wlapi_enable_mac(pi->sh->physhim);
2150 }
2151
wlc_lcnphy_vbat_temp_sense_setup(phy_info_t * pi,u8 mode)2152 static void wlc_lcnphy_vbat_temp_sense_setup(phy_info_t *pi, u8 mode)
2153 {
2154 bool suspend;
2155 u16 save_txpwrCtrlEn;
2156 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2157 u16 auxpga_vmid;
2158 phytbl_info_t tab;
2159 u32 val;
2160 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2161 save_reg112;
2162 u16 values_to_save[14];
2163 s8 index;
2164 int i;
2165 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2166 udelay(999);
2167
2168 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2169 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2170 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2171 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2172 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2173 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2174
2175 for (i = 0; i < 14; i++)
2176 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2177 suspend =
2178 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2179 if (!suspend)
2180 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2181 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2182
2183 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2184 index = pi_lcn->lcnphy_current_index;
2185 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2186 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2187 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2188 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2189 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2190
2191 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2192
2193 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2194
2195 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2196
2197 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2198
2199 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2200
2201 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2202
2203 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2204
2205 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2206
2207 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2208
2209 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2210
2211 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2212
2213 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2214
2215 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2216
2217 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2218
2219 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2220
2221 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2222
2223 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2224
2225 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2226
2227 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2228
2229 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2230
2231 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2232
2233 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2234
2235 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2236 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2237 tab.tbl_width = 16;
2238 tab.tbl_len = 1;
2239 tab.tbl_ptr = &val;
2240 tab.tbl_offset = 6;
2241 wlc_lcnphy_write_table(pi, &tab);
2242 if (mode == TEMPSENSE) {
2243 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2244
2245 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2246
2247 auxpga_vmidcourse = 8;
2248 auxpga_vmidfine = 0x4;
2249 auxpga_gain = 2;
2250 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2251 } else {
2252 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2253
2254 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2255
2256 auxpga_vmidcourse = 7;
2257 auxpga_vmidfine = 0xa;
2258 auxpga_gain = 2;
2259 }
2260 auxpga_vmid =
2261 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2262 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2263
2264 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2265
2266 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2267
2268 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2269
2270 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2271
2272 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2273
2274 wlc_phy_do_dummy_tx(pi, true, OFF);
2275 if (!tempsense_done(pi))
2276 udelay(10);
2277
2278 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2279 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2280 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2281 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2282 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2283 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
2284 for (i = 0; i < 14; i++)
2285 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2286 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
2287
2288 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
2289 if (!suspend)
2290 wlapi_enable_mac(pi->sh->physhim);
2291 udelay(999);
2292 }
2293
WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init)2294 void WLBANDINITFN(wlc_lcnphy_tx_pwr_ctrl_init) (wlc_phy_t *ppi)
2295 {
2296 lcnphy_txgains_t tx_gains;
2297 u8 bbmult;
2298 phytbl_info_t tab;
2299 s32 a1, b0, b1;
2300 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
2301 bool suspend;
2302 phy_info_t *pi = (phy_info_t *) ppi;
2303
2304 suspend =
2305 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2306 if (!suspend)
2307 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2308
2309 if (NORADIO_ENAB(pi->pubpi)) {
2310 wlc_lcnphy_set_bbmult(pi, 0x30);
2311 if (!suspend)
2312 wlapi_enable_mac(pi->sh->physhim);
2313 return;
2314 }
2315
2316 if (!pi->hwpwrctrl_capable) {
2317 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2318 tx_gains.gm_gain = 4;
2319 tx_gains.pga_gain = 12;
2320 tx_gains.pad_gain = 12;
2321 tx_gains.dac_gain = 0;
2322
2323 bbmult = 150;
2324 } else {
2325 tx_gains.gm_gain = 7;
2326 tx_gains.pga_gain = 15;
2327 tx_gains.pad_gain = 14;
2328 tx_gains.dac_gain = 0;
2329
2330 bbmult = 150;
2331 }
2332 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
2333 wlc_lcnphy_set_bbmult(pi, bbmult);
2334 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2335 } else {
2336
2337 wlc_lcnphy_idle_tssi_est(ppi);
2338
2339 wlc_lcnphy_clear_tx_power_offsets(pi);
2340
2341 b0 = pi->txpa_2g[0];
2342 b1 = pi->txpa_2g[1];
2343 a1 = pi->txpa_2g[2];
2344 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
2345 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
2346
2347 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2348 tab.tbl_width = 32;
2349 tab.tbl_ptr = &pwr;
2350 tab.tbl_len = 1;
2351 tab.tbl_offset = 0;
2352 for (tssi = 0; tssi < 128; tssi++) {
2353 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
2354
2355 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
2356 wlc_lcnphy_write_table(pi, &tab);
2357 tab.tbl_offset++;
2358 }
2359
2360 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
2361
2362 write_phy_reg(pi, 0x4a8, 10);
2363
2364 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
2365
2366 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
2367 }
2368 if (!suspend)
2369 wlapi_enable_mac(pi->sh->physhim);
2370 }
2371
wlc_lcnphy_get_bbmult(phy_info_t * pi)2372 static u8 wlc_lcnphy_get_bbmult(phy_info_t *pi)
2373 {
2374 u16 m0m1;
2375 phytbl_info_t tab;
2376
2377 tab.tbl_ptr = &m0m1;
2378 tab.tbl_len = 1;
2379 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2380 tab.tbl_offset = 87;
2381 tab.tbl_width = 16;
2382 wlc_lcnphy_read_table(pi, &tab);
2383
2384 return (u8) ((m0m1 & 0xff00) >> 8);
2385 }
2386
wlc_lcnphy_set_pa_gain(phy_info_t * pi,u16 gain)2387 static void wlc_lcnphy_set_pa_gain(phy_info_t *pi, u16 gain)
2388 {
2389 mod_phy_reg(pi, 0x4fb,
2390 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
2391 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
2392 mod_phy_reg(pi, 0x4fd,
2393 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
2394 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
2395 }
2396
2397 void
wlc_lcnphy_get_radio_loft(phy_info_t * pi,u8 * ei0,u8 * eq0,u8 * fi0,u8 * fq0)2398 wlc_lcnphy_get_radio_loft(phy_info_t *pi,
2399 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
2400 {
2401 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
2402 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
2403 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
2404 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
2405 }
2406
wlc_lcnphy_get_tx_gain(phy_info_t * pi,lcnphy_txgains_t * gains)2407 static void wlc_lcnphy_get_tx_gain(phy_info_t *pi, lcnphy_txgains_t *gains)
2408 {
2409 u16 dac_gain;
2410
2411 dac_gain = read_phy_reg(pi, 0x439) >> 0;
2412 gains->dac_gain = (dac_gain & 0x380) >> 7;
2413
2414 {
2415 u16 rfgain0, rfgain1;
2416
2417 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
2418 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
2419
2420 gains->gm_gain = rfgain0 & 0xff;
2421 gains->pga_gain = (rfgain0 >> 8) & 0xff;
2422 gains->pad_gain = rfgain1 & 0xff;
2423 }
2424 }
2425
wlc_lcnphy_set_tx_iqcc(phy_info_t * pi,u16 a,u16 b)2426 void wlc_lcnphy_set_tx_iqcc(phy_info_t *pi, u16 a, u16 b)
2427 {
2428 phytbl_info_t tab;
2429 u16 iqcc[2];
2430
2431 iqcc[0] = a;
2432 iqcc[1] = b;
2433
2434 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2435 tab.tbl_width = 16;
2436 tab.tbl_ptr = iqcc;
2437 tab.tbl_len = 2;
2438 tab.tbl_offset = 80;
2439 wlc_lcnphy_write_table(pi, &tab);
2440 }
2441
wlc_lcnphy_set_tx_locc(phy_info_t * pi,u16 didq)2442 void wlc_lcnphy_set_tx_locc(phy_info_t *pi, u16 didq)
2443 {
2444 phytbl_info_t tab;
2445
2446 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
2447 tab.tbl_width = 16;
2448 tab.tbl_ptr = &didq;
2449 tab.tbl_len = 1;
2450 tab.tbl_offset = 85;
2451 wlc_lcnphy_write_table(pi, &tab);
2452 }
2453
wlc_lcnphy_set_tx_pwr_by_index(phy_info_t * pi,int index)2454 void wlc_lcnphy_set_tx_pwr_by_index(phy_info_t *pi, int index)
2455 {
2456 phytbl_info_t tab;
2457 u16 a, b;
2458 u8 bb_mult;
2459 u32 bbmultiqcomp, txgain, locoeffs, rfpower;
2460 lcnphy_txgains_t gains;
2461 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2462
2463 ASSERT(index <= LCNPHY_MAX_TX_POWER_INDEX);
2464
2465 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
2466 pi_lcn->lcnphy_current_index = (u8) index;
2467
2468 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2469 tab.tbl_width = 32;
2470 tab.tbl_len = 1;
2471
2472 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2473
2474 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
2475 tab.tbl_ptr = &bbmultiqcomp;
2476 wlc_lcnphy_read_table(pi, &tab);
2477
2478 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
2479 tab.tbl_width = 32;
2480 tab.tbl_ptr = &txgain;
2481 wlc_lcnphy_read_table(pi, &tab);
2482
2483 gains.gm_gain = (u16) (txgain & 0xff);
2484 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
2485 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
2486 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
2487 wlc_lcnphy_set_tx_gain(pi, &gains);
2488 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
2489
2490 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
2491 wlc_lcnphy_set_bbmult(pi, bb_mult);
2492
2493 wlc_lcnphy_enable_tx_gain_override(pi);
2494
2495 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2496
2497 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
2498 b = (u16) (bbmultiqcomp & 0x3ff);
2499 wlc_lcnphy_set_tx_iqcc(pi, a, b);
2500
2501 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
2502 tab.tbl_ptr = &locoeffs;
2503 wlc_lcnphy_read_table(pi, &tab);
2504
2505 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
2506
2507 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
2508 tab.tbl_ptr = &rfpower;
2509 wlc_lcnphy_read_table(pi, &tab);
2510 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
2511
2512 }
2513 }
2514
wlc_lcnphy_set_trsw_override(phy_info_t * pi,bool tx,bool rx)2515 static void wlc_lcnphy_set_trsw_override(phy_info_t *pi, bool tx, bool rx)
2516 {
2517
2518 mod_phy_reg(pi, 0x44d,
2519 (0x1 << 1) |
2520 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
2521
2522 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
2523 }
2524
wlc_lcnphy_clear_papd_comptable(phy_info_t * pi)2525 static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi)
2526 {
2527 u32 j;
2528 phytbl_info_t tab;
2529 u32 temp_offset[128];
2530 tab.tbl_ptr = temp_offset;
2531 tab.tbl_len = 128;
2532 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
2533 tab.tbl_width = 32;
2534 tab.tbl_offset = 0;
2535
2536 memset(temp_offset, 0, sizeof(temp_offset));
2537 for (j = 1; j < 128; j += 2)
2538 temp_offset[j] = 0x80000;
2539
2540 wlc_lcnphy_write_table(pi, &tab);
2541 return;
2542 }
2543
2544 static void
wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t * pi,u16 trsw,u16 ext_lna,u16 biq2,u16 biq1,u16 tia,u16 lna2,u16 lna1)2545 wlc_lcnphy_set_rx_gain_by_distribution(phy_info_t *pi,
2546 u16 trsw,
2547 u16 ext_lna,
2548 u16 biq2,
2549 u16 biq1,
2550 u16 tia, u16 lna2, u16 lna1)
2551 {
2552 u16 gain0_15, gain16_19;
2553
2554 gain16_19 = biq2 & 0xf;
2555 gain0_15 = ((biq1 & 0xf) << 12) |
2556 ((tia & 0xf) << 8) |
2557 ((lna2 & 0x3) << 6) |
2558 ((lna2 & 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
2559
2560 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
2561 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
2562 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
2563
2564 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2565 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2566 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
2567 } else {
2568 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
2569
2570 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
2571
2572 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
2573 }
2574
2575 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
2576
2577 }
2578
wlc_lcnphy_rx_gain_override_enable(phy_info_t * pi,bool enable)2579 static void wlc_lcnphy_rx_gain_override_enable(phy_info_t *pi, bool enable)
2580 {
2581 u16 ebit = enable ? 1 : 0;
2582
2583 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
2584
2585 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
2586
2587 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2588 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
2589 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
2590 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2591 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
2592 } else {
2593 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
2594 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
2595 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
2596 }
2597
2598 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2599 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
2600 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
2601 }
2602 }
2603
wlc_lcnphy_tx_pu(phy_info_t * pi,bool bEnable)2604 void wlc_lcnphy_tx_pu(phy_info_t *pi, bool bEnable)
2605 {
2606 if (!bEnable) {
2607
2608 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
2609
2610 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
2611
2612 and_phy_reg(pi, 0x44c,
2613 ~(u16) ((0x1 << 3) |
2614 (0x1 << 5) |
2615 (0x1 << 12) |
2616 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2617
2618 and_phy_reg(pi, 0x44d,
2619 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
2620 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
2621
2622 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
2623
2624 and_phy_reg(pi, 0x4f9,
2625 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2626
2627 and_phy_reg(pi, 0x4fa,
2628 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
2629 } else {
2630
2631 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2632 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2633
2634 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
2635 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
2636
2637 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2638 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2639
2640 wlc_lcnphy_set_trsw_override(pi, true, false);
2641
2642 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
2643 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
2644
2645 if (CHSPEC_IS2G(pi->radio_chanspec)) {
2646
2647 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2648 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
2649
2650 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2651 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
2652
2653 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2654 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
2655
2656 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2657 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
2658
2659 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2660 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
2661 } else {
2662
2663 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
2664 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
2665
2666 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
2667 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
2668
2669 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
2670 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
2671
2672 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
2673 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
2674
2675 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
2676 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
2677 }
2678 }
2679 }
2680
2681 static void
wlc_lcnphy_run_samples(phy_info_t * pi,u16 num_samps,u16 num_loops,u16 wait,bool iqcalmode)2682 wlc_lcnphy_run_samples(phy_info_t *pi,
2683 u16 num_samps,
2684 u16 num_loops, u16 wait, bool iqcalmode)
2685 {
2686
2687 or_phy_reg(pi, 0x6da, 0x8080);
2688
2689 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
2690 if (num_loops != 0xffff)
2691 num_loops--;
2692 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
2693
2694 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
2695
2696 if (iqcalmode) {
2697
2698 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
2699 or_phy_reg(pi, 0x453, (0x1 << 15));
2700 } else {
2701 write_phy_reg(pi, 0x63f, 1);
2702 wlc_lcnphy_tx_pu(pi, 1);
2703 }
2704
2705 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
2706 }
2707
wlc_lcnphy_deaf_mode(phy_info_t * pi,bool mode)2708 void wlc_lcnphy_deaf_mode(phy_info_t *pi, bool mode)
2709 {
2710
2711 u8 phybw40;
2712 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
2713
2714 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
2715 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2716 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2717 } else {
2718 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
2719 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
2720 }
2721
2722 if (phybw40 == 0) {
2723 mod_phy_reg((pi), 0x410,
2724 (0x1 << 6) |
2725 (0x1 << 5),
2726 ((CHSPEC_IS2G(pi->radio_chanspec)) ? (!mode) : 0) <<
2727 6 | (!mode) << 5);
2728 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
2729 }
2730 }
2731
2732 void
wlc_lcnphy_start_tx_tone(phy_info_t * pi,s32 f_kHz,u16 max_val,bool iqcalmode)2733 wlc_lcnphy_start_tx_tone(phy_info_t *pi, s32 f_kHz, u16 max_val,
2734 bool iqcalmode)
2735 {
2736 u8 phy_bw;
2737 u16 num_samps, t, k;
2738 u32 bw;
2739 fixed theta = 0, rot = 0;
2740 cs32 tone_samp;
2741 u32 data_buf[64];
2742 u16 i_samp, q_samp;
2743 phytbl_info_t tab;
2744 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2745
2746 pi->phy_tx_tone_freq = f_kHz;
2747
2748 wlc_lcnphy_deaf_mode(pi, true);
2749
2750 phy_bw = 40;
2751 if (pi_lcn->lcnphy_spurmod) {
2752 write_phy_reg(pi, 0x942, 0x2);
2753 write_phy_reg(pi, 0x93b, 0x0);
2754 write_phy_reg(pi, 0x93c, 0x0);
2755 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
2756 }
2757
2758 if (f_kHz) {
2759 k = 1;
2760 do {
2761 bw = phy_bw * 1000 * k;
2762 num_samps = bw / ABS(f_kHz);
2763 ASSERT(num_samps <= ARRAY_SIZE(data_buf));
2764 k++;
2765 } while ((num_samps * (u32) (ABS(f_kHz))) != bw);
2766 } else
2767 num_samps = 2;
2768
2769 rot = FIXED((f_kHz * 36) / phy_bw) / 100;
2770 theta = 0;
2771
2772 for (t = 0; t < num_samps; t++) {
2773
2774 wlc_phy_cordic(theta, &tone_samp);
2775
2776 theta += rot;
2777
2778 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
2779 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
2780 data_buf[t] = (i_samp << 10) | q_samp;
2781 }
2782
2783 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
2784
2785 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
2786
2787 tab.tbl_ptr = data_buf;
2788 tab.tbl_len = num_samps;
2789 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
2790 tab.tbl_offset = 0;
2791 tab.tbl_width = 32;
2792 wlc_lcnphy_write_table(pi, &tab);
2793
2794 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
2795 }
2796
wlc_lcnphy_stop_tx_tone(phy_info_t * pi)2797 void wlc_lcnphy_stop_tx_tone(phy_info_t *pi)
2798 {
2799 s16 playback_status;
2800 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2801
2802 pi->phy_tx_tone_freq = 0;
2803 if (pi_lcn->lcnphy_spurmod) {
2804 write_phy_reg(pi, 0x942, 0x7);
2805 write_phy_reg(pi, 0x93b, 0x2017);
2806 write_phy_reg(pi, 0x93c, 0x27c5);
2807 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
2808 }
2809
2810 playback_status = read_phy_reg(pi, 0x644);
2811 if (playback_status & (0x1 << 0)) {
2812 wlc_lcnphy_tx_pu(pi, 0);
2813 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
2814 } else if (playback_status & (0x1 << 1))
2815 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
2816
2817 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
2818
2819 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
2820
2821 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
2822
2823 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
2824
2825 wlc_lcnphy_deaf_mode(pi, false);
2826 }
2827
wlc_lcnphy_clear_trsw_override(phy_info_t * pi)2828 static void wlc_lcnphy_clear_trsw_override(phy_info_t *pi)
2829 {
2830
2831 and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
2832 }
2833
wlc_lcnphy_get_tx_iqcc(phy_info_t * pi,u16 * a,u16 * b)2834 void wlc_lcnphy_get_tx_iqcc(phy_info_t *pi, u16 *a, u16 *b)
2835 {
2836 u16 iqcc[2];
2837 phytbl_info_t tab;
2838
2839 tab.tbl_ptr = iqcc;
2840 tab.tbl_len = 2;
2841 tab.tbl_id = 0;
2842 tab.tbl_offset = 80;
2843 tab.tbl_width = 16;
2844 wlc_lcnphy_read_table(pi, &tab);
2845
2846 *a = iqcc[0];
2847 *b = iqcc[1];
2848 }
2849
wlc_lcnphy_get_tx_locc(phy_info_t * pi)2850 u16 wlc_lcnphy_get_tx_locc(phy_info_t *pi)
2851 {
2852 phytbl_info_t tab;
2853 u16 didq;
2854
2855 tab.tbl_id = 0;
2856 tab.tbl_width = 16;
2857 tab.tbl_ptr = &didq;
2858 tab.tbl_len = 1;
2859 tab.tbl_offset = 85;
2860 wlc_lcnphy_read_table(pi, &tab);
2861
2862 return didq;
2863 }
2864
wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t * pi)2865 static void wlc_lcnphy_txpwrtbl_iqlo_cal(phy_info_t *pi)
2866 {
2867
2868 lcnphy_txgains_t target_gains, old_gains;
2869 u8 save_bb_mult;
2870 u16 a, b, didq, save_pa_gain = 0;
2871 uint idx, SAVE_txpwrindex = 0xFF;
2872 u32 val;
2873 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2874 phytbl_info_t tab;
2875 u8 ei0, eq0, fi0, fq0;
2876 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
2877
2878 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2879 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
2880
2881 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
2882
2883 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
2884 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2885
2886 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2887
2888 target_gains.gm_gain = 7;
2889 target_gains.pga_gain = 0;
2890 target_gains.pad_gain = 21;
2891 target_gains.dac_gain = 0;
2892 wlc_lcnphy_set_tx_gain(pi, &target_gains);
2893 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2894
2895 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
2896
2897 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
2898
2899 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2900 (pi_lcn->
2901 lcnphy_recal ? LCNPHY_CAL_RECAL :
2902 LCNPHY_CAL_FULL), false);
2903 } else {
2904
2905 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2906 }
2907
2908 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
2909 if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
2910 if (CHSPEC_IS5G(pi->radio_chanspec)) {
2911 target_gains.gm_gain = 255;
2912 target_gains.pga_gain = 255;
2913 target_gains.pad_gain = 0xf0;
2914 target_gains.dac_gain = 0;
2915 } else {
2916 target_gains.gm_gain = 7;
2917 target_gains.pga_gain = 45;
2918 target_gains.pad_gain = 186;
2919 target_gains.dac_gain = 0;
2920 }
2921
2922 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
2923 || pi_lcn->lcnphy_hw_iqcal_en) {
2924
2925 target_gains.pga_gain = 0;
2926 target_gains.pad_gain = 30;
2927 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
2928 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
2929 LCNPHY_CAL_FULL, false);
2930 } else {
2931
2932 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
2933 }
2934
2935 }
2936
2937 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
2938
2939 didq = wlc_lcnphy_get_tx_locc(pi);
2940
2941 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2942 tab.tbl_width = 32;
2943 tab.tbl_ptr = &val;
2944
2945 tab.tbl_len = 1;
2946 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2947
2948 for (idx = 0; idx < 128; idx++) {
2949 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
2950
2951 wlc_lcnphy_read_table(pi, &tab);
2952 val = (val & 0xfff00000) |
2953 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
2954 wlc_lcnphy_write_table(pi, &tab);
2955
2956 val = didq;
2957 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
2958 wlc_lcnphy_write_table(pi, &tab);
2959 }
2960
2961 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
2962 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
2963 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
2964 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
2965 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
2966 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
2967 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
2968
2969 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
2970 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
2971 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2972
2973 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
2974 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2975 else
2976 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
2977 }
2978
wlc_lcnphy_tempsense_new(phy_info_t * pi,bool mode)2979 s16 wlc_lcnphy_tempsense_new(phy_info_t *pi, bool mode)
2980 {
2981 u16 tempsenseval1, tempsenseval2;
2982 s16 avg = 0;
2983 bool suspend = 0;
2984
2985 if (NORADIO_ENAB(pi->pubpi))
2986 return -1;
2987
2988 if (mode == 1) {
2989 suspend =
2990 (0 ==
2991 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
2992 if (!suspend)
2993 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2994 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
2995 }
2996 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
2997 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
2998
2999 if (tempsenseval1 > 255)
3000 avg = (s16) (tempsenseval1 - 512);
3001 else
3002 avg = (s16) tempsenseval1;
3003
3004 if (tempsenseval2 > 255)
3005 avg += (s16) (tempsenseval2 - 512);
3006 else
3007 avg += (s16) tempsenseval2;
3008
3009 avg /= 2;
3010
3011 if (mode == 1) {
3012
3013 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3014
3015 udelay(100);
3016 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3017
3018 if (!suspend)
3019 wlapi_enable_mac(pi->sh->physhim);
3020 }
3021 return avg;
3022 }
3023
wlc_lcnphy_tempsense(phy_info_t * pi,bool mode)3024 u16 wlc_lcnphy_tempsense(phy_info_t *pi, bool mode)
3025 {
3026 u16 tempsenseval1, tempsenseval2;
3027 s32 avg = 0;
3028 bool suspend = 0;
3029 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3030 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3031
3032 if (NORADIO_ENAB(pi->pubpi))
3033 return -1;
3034
3035 if (mode == 1) {
3036 suspend =
3037 (0 ==
3038 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
3039 if (!suspend)
3040 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3041 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3042 }
3043 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3044 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3045
3046 if (tempsenseval1 > 255)
3047 avg = (int)(tempsenseval1 - 512);
3048 else
3049 avg = (int)tempsenseval1;
3050
3051 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
3052 if (tempsenseval2 > 255)
3053 avg = (int)(avg - tempsenseval2 + 512);
3054 else
3055 avg = (int)(avg - tempsenseval2);
3056 } else {
3057 if (tempsenseval2 > 255)
3058 avg = (int)(avg + tempsenseval2 - 512);
3059 else
3060 avg = (int)(avg + tempsenseval2);
3061 avg = avg / 2;
3062 }
3063 if (avg < 0)
3064 avg = avg + 512;
3065
3066 if (pi_lcn->lcnphy_tempsense_option == 2)
3067 avg = tempsenseval1;
3068
3069 if (mode)
3070 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3071
3072 if (mode == 1) {
3073
3074 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3075
3076 udelay(100);
3077 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3078
3079 if (!suspend)
3080 wlapi_enable_mac(pi->sh->physhim);
3081 }
3082 return (u16) avg;
3083 }
3084
wlc_lcnphy_tempsense_degree(phy_info_t * pi,bool mode)3085 s8 wlc_lcnphy_tempsense_degree(phy_info_t *pi, bool mode)
3086 {
3087 s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
3088 degree =
3089 ((degree << 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
3090 / LCN_TEMPSENSE_DEN;
3091 return (s8) degree;
3092 }
3093
wlc_lcnphy_vbatsense(phy_info_t * pi,bool mode)3094 s8 wlc_lcnphy_vbatsense(phy_info_t *pi, bool mode)
3095 {
3096 u16 vbatsenseval;
3097 s32 avg = 0;
3098 bool suspend = 0;
3099
3100 if (NORADIO_ENAB(pi->pubpi))
3101 return -1;
3102
3103 if (mode == 1) {
3104 suspend =
3105 (0 ==
3106 (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
3107 if (!suspend)
3108 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3109 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
3110 }
3111
3112 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
3113
3114 if (vbatsenseval > 255)
3115 avg = (s32) (vbatsenseval - 512);
3116 else
3117 avg = (s32) vbatsenseval;
3118
3119 avg =
3120 (avg * LCN_VBAT_SCALE_NOM +
3121 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
3122
3123 if (mode == 1) {
3124 if (!suspend)
3125 wlapi_enable_mac(pi->sh->physhim);
3126 }
3127 return (s8) avg;
3128 }
3129
wlc_lcnphy_afe_clk_init(phy_info_t * pi,u8 mode)3130 static void wlc_lcnphy_afe_clk_init(phy_info_t *pi, u8 mode)
3131 {
3132 u8 phybw40;
3133 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3134
3135 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
3136
3137 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
3138 (mode == AFE_CLK_INIT_MODE_TXRX2X))
3139 write_phy_reg(pi, 0x6d0, 0x7);
3140
3141 wlc_lcnphy_toggle_afe_pwdn(pi);
3142 }
3143
3144 static bool
wlc_lcnphy_rx_iq_est(phy_info_t * pi,u16 num_samps,u8 wait_time,lcnphy_iq_est_t * iq_est)3145 wlc_lcnphy_rx_iq_est(phy_info_t *pi,
3146 u16 num_samps,
3147 u8 wait_time, lcnphy_iq_est_t *iq_est)
3148 {
3149 int wait_count = 0;
3150 bool result = true;
3151 u8 phybw40;
3152 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3153
3154 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
3155
3156 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
3157
3158 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
3159
3160 mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
3161
3162 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
3163
3164 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
3165
3166 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
3167
3168 if (wait_count > (10 * 500)) {
3169 result = false;
3170 goto cleanup;
3171 }
3172 udelay(100);
3173 wait_count++;
3174 }
3175
3176 iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
3177 (u32) read_phy_reg(pi, 0x484);
3178 iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
3179 (u32) read_phy_reg(pi, 0x486);
3180 iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
3181 (u32) read_phy_reg(pi, 0x488);
3182
3183 cleanup:
3184 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
3185
3186 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
3187
3188 return result;
3189 }
3190
wlc_lcnphy_calc_rx_iq_comp(phy_info_t * pi,u16 num_samps)3191 static bool wlc_lcnphy_calc_rx_iq_comp(phy_info_t *pi, u16 num_samps)
3192 {
3193 #define LCNPHY_MIN_RXIQ_PWR 2
3194 bool result;
3195 u16 a0_new, b0_new;
3196 lcnphy_iq_est_t iq_est = { 0, 0, 0 };
3197 s32 a, b, temp;
3198 s16 iq_nbits, qq_nbits, arsh, brsh;
3199 s32 iq;
3200 u32 ii, qq;
3201 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3202
3203 a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
3204 b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
3205 mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
3206
3207 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
3208
3209 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
3210
3211 result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
3212 if (!result)
3213 goto cleanup;
3214
3215 iq = (s32) iq_est.iq_prod;
3216 ii = iq_est.i_pwr;
3217 qq = iq_est.q_pwr;
3218
3219 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
3220 result = false;
3221 goto cleanup;
3222 }
3223
3224 iq_nbits = wlc_phy_nbits(iq);
3225 qq_nbits = wlc_phy_nbits(qq);
3226
3227 arsh = 10 - (30 - iq_nbits);
3228 if (arsh >= 0) {
3229 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
3230 temp = (s32) (ii >> arsh);
3231 if (temp == 0) {
3232 return false;
3233 }
3234 } else {
3235 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
3236 temp = (s32) (ii << -arsh);
3237 if (temp == 0) {
3238 return false;
3239 }
3240 }
3241 a /= temp;
3242 brsh = qq_nbits - 31 + 20;
3243 if (brsh >= 0) {
3244 b = (qq << (31 - qq_nbits));
3245 temp = (s32) (ii >> brsh);
3246 if (temp == 0) {
3247 return false;
3248 }
3249 } else {
3250 b = (qq << (31 - qq_nbits));
3251 temp = (s32) (ii << -brsh);
3252 if (temp == 0) {
3253 return false;
3254 }
3255 }
3256 b /= temp;
3257 b -= a * a;
3258 b = (s32) wlc_phy_sqrt_int((u32) b);
3259 b -= (1 << 10);
3260 a0_new = (u16) (a & 0x3ff);
3261 b0_new = (u16) (b & 0x3ff);
3262 cleanup:
3263
3264 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
3265
3266 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
3267
3268 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
3269
3270 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
3271 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
3272
3273 return result;
3274 }
3275
3276 static bool
wlc_lcnphy_rx_iq_cal(phy_info_t * pi,const lcnphy_rx_iqcomp_t * iqcomp,int iqcomp_sz,bool tx_switch,bool rx_switch,int module,int tx_gain_idx)3277 wlc_lcnphy_rx_iq_cal(phy_info_t *pi, const lcnphy_rx_iqcomp_t *iqcomp,
3278 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
3279 int tx_gain_idx)
3280 {
3281 lcnphy_txgains_t old_gains;
3282 u16 tx_pwr_ctrl;
3283 u8 tx_gain_index_old = 0;
3284 bool result = false, tx_gain_override_old = false;
3285 u16 i, Core1TxControl_old, RFOverride0_old,
3286 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
3287 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
3288 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
3289 int tia_gain;
3290 u32 received_power, rx_pwr_threshold;
3291 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
3292 u16 values_to_save[11];
3293 s16 *ptr;
3294 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3295
3296 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3297 if (NULL == ptr) {
3298 return false;
3299 }
3300 if (module == 2) {
3301 ASSERT(iqcomp_sz);
3302
3303 while (iqcomp_sz--) {
3304 if (iqcomp[iqcomp_sz].chan ==
3305 CHSPEC_CHANNEL(pi->radio_chanspec)) {
3306
3307 wlc_lcnphy_set_rx_iq_comp(pi,
3308 (u16)
3309 iqcomp[iqcomp_sz].a,
3310 (u16)
3311 iqcomp[iqcomp_sz].b);
3312 result = true;
3313 break;
3314 }
3315 }
3316 ASSERT(result);
3317 goto cal_done;
3318 }
3319
3320 if (module == 1) {
3321
3322 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3323 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3324
3325 for (i = 0; i < 11; i++) {
3326 values_to_save[i] =
3327 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
3328 }
3329 Core1TxControl_old = read_phy_reg(pi, 0x631);
3330
3331 or_phy_reg(pi, 0x631, 0x0015);
3332
3333 RFOverride0_old = read_phy_reg(pi, 0x44c);
3334 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
3335 rfoverride2_old = read_phy_reg(pi, 0x4b0);
3336 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
3337 rfoverride3_old = read_phy_reg(pi, 0x4f9);
3338 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
3339 rfoverride4_old = read_phy_reg(pi, 0x938);
3340 rfoverride4val_old = read_phy_reg(pi, 0x939);
3341 afectrlovr_old = read_phy_reg(pi, 0x43b);
3342 afectrlovrval_old = read_phy_reg(pi, 0x43c);
3343 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3344 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
3345
3346 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
3347 if (tx_gain_override_old) {
3348 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3349 tx_gain_index_old = pi_lcn->lcnphy_current_index;
3350 }
3351
3352 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
3353
3354 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3355 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3356
3357 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3358 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3359
3360 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
3361 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
3362 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
3363 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
3364 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3365 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
3366 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
3367 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
3368 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
3369 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
3370
3371 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
3372 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
3373 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
3374 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
3375 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
3376 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
3377 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
3378 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
3379 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
3380 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
3381
3382 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3383 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3384
3385 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
3386 write_phy_reg(pi, 0x6da, 0xffff);
3387 or_phy_reg(pi, 0x6db, 0x3);
3388 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
3389 wlc_lcnphy_rx_gain_override_enable(pi, true);
3390
3391 tia_gain = 8;
3392 rx_pwr_threshold = 950;
3393 while (tia_gain > 0) {
3394 tia_gain -= 1;
3395 wlc_lcnphy_set_rx_gain_by_distribution(pi,
3396 0, 0, 2, 2,
3397 (u16)
3398 tia_gain, 1, 0);
3399 udelay(500);
3400
3401 received_power =
3402 wlc_lcnphy_measure_digital_power(pi, 2000);
3403 if (received_power < rx_pwr_threshold)
3404 break;
3405 }
3406 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
3407
3408 wlc_lcnphy_stop_tx_tone(pi);
3409
3410 write_phy_reg(pi, 0x631, Core1TxControl_old);
3411
3412 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
3413 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
3414 write_phy_reg(pi, 0x4b0, rfoverride2_old);
3415 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
3416 write_phy_reg(pi, 0x4f9, rfoverride3_old);
3417 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
3418 write_phy_reg(pi, 0x938, rfoverride4_old);
3419 write_phy_reg(pi, 0x939, rfoverride4val_old);
3420 write_phy_reg(pi, 0x43b, afectrlovr_old);
3421 write_phy_reg(pi, 0x43c, afectrlovrval_old);
3422 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3423 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
3424
3425 wlc_lcnphy_clear_trsw_override(pi);
3426
3427 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
3428
3429 for (i = 0; i < 11; i++) {
3430 write_radio_reg(pi, rxiq_cal_rf_reg[i],
3431 values_to_save[i]);
3432 }
3433
3434 if (tx_gain_override_old) {
3435 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
3436 } else
3437 wlc_lcnphy_disable_tx_gain_override(pi);
3438 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
3439
3440 wlc_lcnphy_rx_gain_override_enable(pi, false);
3441 }
3442
3443 cal_done:
3444 kfree(ptr);
3445 return result;
3446 }
3447
wlc_lcnphy_temp_adj(phy_info_t * pi)3448 static void wlc_lcnphy_temp_adj(phy_info_t *pi)
3449 {
3450 if (NORADIO_ENAB(pi->pubpi))
3451 return;
3452 }
3453
wlc_lcnphy_glacial_timer_based_cal(phy_info_t * pi)3454 static void wlc_lcnphy_glacial_timer_based_cal(phy_info_t *pi)
3455 {
3456 bool suspend;
3457 s8 index;
3458 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3459 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3460 suspend =
3461 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
3462 if (!suspend)
3463 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3464 wlc_lcnphy_deaf_mode(pi, true);
3465 pi->phy_lastcal = pi->sh->now;
3466 pi->phy_forcecal = false;
3467 index = pi_lcn->lcnphy_current_index;
3468
3469 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3470
3471 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3472 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3473 wlc_lcnphy_deaf_mode(pi, false);
3474 if (!suspend)
3475 wlapi_enable_mac(pi->sh->physhim);
3476
3477 }
3478
wlc_lcnphy_periodic_cal(phy_info_t * pi)3479 static void wlc_lcnphy_periodic_cal(phy_info_t *pi)
3480 {
3481 bool suspend, full_cal;
3482 const lcnphy_rx_iqcomp_t *rx_iqcomp;
3483 int rx_iqcomp_sz;
3484 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3485 s8 index;
3486 phytbl_info_t tab;
3487 s32 a1, b0, b1;
3488 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3489 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3490
3491 if (NORADIO_ENAB(pi->pubpi))
3492 return;
3493
3494 pi->phy_lastcal = pi->sh->now;
3495 pi->phy_forcecal = false;
3496 full_cal =
3497 (pi_lcn->lcnphy_full_cal_channel !=
3498 CHSPEC_CHANNEL(pi->radio_chanspec));
3499 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
3500 index = pi_lcn->lcnphy_current_index;
3501
3502 suspend =
3503 (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
3504 if (!suspend) {
3505
3506 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
3507 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3508 }
3509 wlc_lcnphy_deaf_mode(pi, true);
3510
3511 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
3512
3513 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
3514 rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
3515
3516 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
3517 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
3518 else
3519 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
3520
3521 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
3522
3523 wlc_lcnphy_idle_tssi_est((wlc_phy_t *) pi);
3524
3525 b0 = pi->txpa_2g[0];
3526 b1 = pi->txpa_2g[1];
3527 a1 = pi->txpa_2g[2];
3528 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3529 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3530
3531 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3532 tab.tbl_width = 32;
3533 tab.tbl_ptr = &pwr;
3534 tab.tbl_len = 1;
3535 tab.tbl_offset = 0;
3536 for (tssi = 0; tssi < 128; tssi++) {
3537 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3538 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3539 wlc_lcnphy_write_table(pi, &tab);
3540 tab.tbl_offset++;
3541 }
3542 }
3543
3544 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
3545 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
3546 wlc_lcnphy_deaf_mode(pi, false);
3547 if (!suspend)
3548 wlapi_enable_mac(pi->sh->physhim);
3549 }
3550
wlc_lcnphy_calib_modes(phy_info_t * pi,uint mode)3551 void wlc_lcnphy_calib_modes(phy_info_t *pi, uint mode)
3552 {
3553 u16 temp_new;
3554 int temp1, temp2, temp_diff;
3555 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3556
3557 switch (mode) {
3558 case PHY_PERICAL_CHAN:
3559
3560 break;
3561 case PHY_FULLCAL:
3562 wlc_lcnphy_periodic_cal(pi);
3563 break;
3564 case PHY_PERICAL_PHYINIT:
3565 wlc_lcnphy_periodic_cal(pi);
3566 break;
3567 case PHY_PERICAL_WATCHDOG:
3568 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3569 temp_new = wlc_lcnphy_tempsense(pi, 0);
3570 temp1 = LCNPHY_TEMPSENSE(temp_new);
3571 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
3572 temp_diff = temp1 - temp2;
3573 if ((pi_lcn->lcnphy_cal_counter > 90) ||
3574 (temp_diff > 60) || (temp_diff < -60)) {
3575 wlc_lcnphy_glacial_timer_based_cal(pi);
3576 wlc_2064_vco_cal(pi);
3577 pi_lcn->lcnphy_cal_temper = temp_new;
3578 pi_lcn->lcnphy_cal_counter = 0;
3579 } else
3580 pi_lcn->lcnphy_cal_counter++;
3581 }
3582 break;
3583 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
3584 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3585 wlc_lcnphy_tx_power_adjustment((wlc_phy_t *) pi);
3586 break;
3587 default:
3588 ASSERT(0);
3589 break;
3590 }
3591 }
3592
wlc_lcnphy_get_tssi(phy_info_t * pi,s8 * ofdm_pwr,s8 * cck_pwr)3593 void wlc_lcnphy_get_tssi(phy_info_t *pi, s8 *ofdm_pwr, s8 *cck_pwr)
3594 {
3595 s8 cck_offset;
3596 u16 status;
3597 status = (read_phy_reg(pi, 0x4ab));
3598 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
3599 (status & (0x1 << 15))) {
3600 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
3601 >> 0) >> 1);
3602
3603 if (wlc_phy_tpc_isenabled_lcnphy(pi))
3604 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
3605 else
3606 cck_offset = 0;
3607
3608 *cck_pwr = *ofdm_pwr + cck_offset;
3609 } else {
3610 *cck_pwr = 0;
3611 *ofdm_pwr = 0;
3612 }
3613 }
3614
WLBANDINITFN(wlc_phy_cal_init_lcnphy)3615 void WLBANDINITFN(wlc_phy_cal_init_lcnphy) (phy_info_t *pi)
3616 {
3617 return;
3618
3619 }
3620
wlc_lcnphy_set_chanspec_tweaks(phy_info_t * pi,chanspec_t chanspec)3621 static void wlc_lcnphy_set_chanspec_tweaks(phy_info_t *pi, chanspec_t chanspec)
3622 {
3623 u8 channel = CHSPEC_CHANNEL(chanspec);
3624 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3625
3626 if (NORADIO_ENAB(pi->pubpi))
3627 return;
3628
3629 if (channel == 14) {
3630 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
3631
3632 } else {
3633 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
3634
3635 }
3636 pi_lcn->lcnphy_bandedge_corr = 2;
3637 if (channel == 1)
3638 pi_lcn->lcnphy_bandedge_corr = 4;
3639
3640 if (channel == 1 || channel == 2 || channel == 3 ||
3641 channel == 4 || channel == 9 ||
3642 channel == 10 || channel == 11 || channel == 12) {
3643 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
3644 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
3645 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
3646
3647 si_pmu_pllupd(pi->sh->sih);
3648 write_phy_reg(pi, 0x942, 0);
3649 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3650 pi_lcn->lcnphy_spurmod = 0;
3651 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
3652
3653 write_phy_reg(pi, 0x425, 0x5907);
3654 } else {
3655 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
3656 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
3657 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
3658
3659 si_pmu_pllupd(pi->sh->sih);
3660 write_phy_reg(pi, 0x942, 0);
3661 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3662
3663 pi_lcn->lcnphy_spurmod = 0;
3664 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
3665
3666 write_phy_reg(pi, 0x425, 0x590a);
3667 }
3668
3669 or_phy_reg(pi, 0x44a, 0x44);
3670 write_phy_reg(pi, 0x44a, 0x80);
3671 }
3672
wlc_lcnphy_tx_power_adjustment(wlc_phy_t * ppi)3673 void wlc_lcnphy_tx_power_adjustment(wlc_phy_t *ppi)
3674 {
3675 s8 index;
3676 u16 index2;
3677 phy_info_t *pi = (phy_info_t *) ppi;
3678 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3679 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3680 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
3681 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
3682 index2 = (u16) (index * 2);
3683 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
3684
3685 pi_lcn->lcnphy_current_index = (s8)
3686 ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
3687 }
3688 }
3689
wlc_lcnphy_set_rx_iq_comp(phy_info_t * pi,u16 a,u16 b)3690 static void wlc_lcnphy_set_rx_iq_comp(phy_info_t *pi, u16 a, u16 b)
3691 {
3692 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
3693
3694 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
3695
3696 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
3697
3698 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
3699
3700 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
3701
3702 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
3703
3704 }
3705
WLBANDINITFN(wlc_phy_init_lcnphy)3706 void WLBANDINITFN(wlc_phy_init_lcnphy) (phy_info_t *pi)
3707 {
3708 u8 phybw40;
3709 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3710 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3711
3712 pi_lcn->lcnphy_cal_counter = 0;
3713 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
3714
3715 or_phy_reg(pi, 0x44a, 0x80);
3716 and_phy_reg(pi, 0x44a, 0x7f);
3717
3718 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
3719
3720 write_phy_reg(pi, 0x60a, 160);
3721
3722 write_phy_reg(pi, 0x46a, 25);
3723
3724 wlc_lcnphy_baseband_init(pi);
3725
3726 wlc_lcnphy_radio_init(pi);
3727
3728 if (CHSPEC_IS2G(pi->radio_chanspec))
3729 wlc_lcnphy_tx_pwr_ctrl_init((wlc_phy_t *) pi);
3730
3731 wlc_phy_chanspec_set((wlc_phy_t *) pi, pi->radio_chanspec);
3732
3733 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
3734
3735 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
3736
3737 if ((pi->sh->boardflags & BFL_FEM)
3738 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
3739 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
3740
3741 wlc_lcnphy_agc_temp_init(pi);
3742
3743 wlc_lcnphy_temp_adj(pi);
3744
3745 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3746
3747 udelay(100);
3748 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3749
3750 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3751 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
3752 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
3753 }
3754
3755 static void
wlc_lcnphy_tx_iqlo_loopback(phy_info_t * pi,u16 * values_to_save)3756 wlc_lcnphy_tx_iqlo_loopback(phy_info_t *pi, u16 *values_to_save)
3757 {
3758 u16 vmid;
3759 int i;
3760 for (i = 0; i < 20; i++) {
3761 values_to_save[i] =
3762 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
3763 }
3764
3765 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3766 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3767
3768 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
3769 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
3770
3771 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3772 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3773
3774 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
3775 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
3776
3777 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
3778 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
3779 else
3780 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
3781 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
3782
3783 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
3784 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
3785 udelay(20);
3786
3787 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3788 if (CHSPEC_IS5G(pi->radio_chanspec))
3789 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
3790 else
3791 or_radio_reg(pi, RADIO_2064_REG03A, 1);
3792 } else {
3793 if (CHSPEC_IS5G(pi->radio_chanspec))
3794 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
3795 else
3796 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
3797 }
3798
3799 udelay(20);
3800
3801 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
3802 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
3803 if (CHSPEC_IS5G(pi->radio_chanspec))
3804 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
3805 else
3806 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
3807 } else {
3808 if (CHSPEC_IS5G(pi->radio_chanspec))
3809 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
3810 else
3811 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
3812 }
3813
3814 udelay(20);
3815
3816 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
3817 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
3818 udelay(20);
3819
3820 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3821 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3822 udelay(20);
3823
3824 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
3825 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
3826 udelay(20);
3827
3828 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
3829 udelay(20);
3830
3831 vmid = 0x2A6;
3832 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
3833 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
3834 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
3835 udelay(20);
3836
3837 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
3838 udelay(20);
3839 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
3840 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
3841 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
3842 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
3843 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
3844 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
3845 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
3846 }
3847
3848 static void
wlc_lcnphy_samp_cap(phy_info_t * pi,int clip_detect_algo,u16 thresh,s16 * ptr,int mode)3849 wlc_lcnphy_samp_cap(phy_info_t *pi, int clip_detect_algo, u16 thresh,
3850 s16 *ptr, int mode)
3851 {
3852 u32 curval1, curval2, stpptr, curptr, strptr, val;
3853 u16 sslpnCalibClkEnCtrl, timer;
3854 u16 old_sslpnCalibClkEnCtrl;
3855 s16 imag, real;
3856 phy_info_lcnphy_t *pi_lcn = pi->u.pi_lcnphy;
3857
3858 timer = 0;
3859 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3860
3861 curval1 = R_REG(&pi->regs->psm_corectlsts);
3862 ptr[130] = 0;
3863 W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1));
3864
3865 W_REG(&pi->regs->smpl_clct_strptr, 0x7E00);
3866 W_REG(&pi->regs->smpl_clct_stpptr, 0x8000);
3867 udelay(20);
3868 curval2 = R_REG(&pi->regs->psm_phy_hdr_param);
3869 W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30);
3870
3871 write_phy_reg(pi, 0x555, 0x0);
3872 write_phy_reg(pi, 0x5a6, 0x5);
3873
3874 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3875 write_phy_reg(pi, 0x5cf, 3);
3876 write_phy_reg(pi, 0x5a5, 0x3);
3877 write_phy_reg(pi, 0x583, 0x0);
3878 write_phy_reg(pi, 0x584, 0x0);
3879 write_phy_reg(pi, 0x585, 0x0fff);
3880 write_phy_reg(pi, 0x586, 0x0000);
3881
3882 write_phy_reg(pi, 0x580, 0x4501);
3883
3884 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3885 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3886 stpptr = R_REG(&pi->regs->smpl_clct_stpptr);
3887 curptr = R_REG(&pi->regs->smpl_clct_curptr);
3888 do {
3889 udelay(10);
3890 curptr = R_REG(&pi->regs->smpl_clct_curptr);
3891 timer++;
3892 } while ((curptr != stpptr) && (timer < 500));
3893
3894 W_REG(&pi->regs->psm_phy_hdr_param, 0x2);
3895 strptr = 0x7E00;
3896 W_REG(&pi->regs->tplatewrptr, strptr);
3897 while (strptr < 0x8000) {
3898 val = R_REG(&pi->regs->tplatewrdata);
3899 imag = ((val >> 16) & 0x3ff);
3900 real = ((val) & 0x3ff);
3901 if (imag > 511) {
3902 imag -= 1024;
3903 }
3904 if (real > 511) {
3905 real -= 1024;
3906 }
3907 if (pi_lcn->lcnphy_iqcal_swp_dis)
3908 ptr[(strptr - 0x7E00) / 4] = real;
3909 else
3910 ptr[(strptr - 0x7E00) / 4] = imag;
3911 if (clip_detect_algo) {
3912 if (imag > thresh || imag < -thresh) {
3913 strptr = 0x8000;
3914 ptr[130] = 1;
3915 }
3916 }
3917 strptr += 4;
3918 }
3919
3920 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3921 W_REG(&pi->regs->psm_phy_hdr_param, curval2);
3922 W_REG(&pi->regs->psm_corectlsts, curval1);
3923 }
3924
wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t * pi)3925 static void wlc_lcnphy_tx_iqlo_soft_cal_full(phy_info_t *pi)
3926 {
3927 lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3928
3929 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3930 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3931 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3932 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3933
3934 wlc_lcnphy_a1(pi, 4, 0, 0);
3935 wlc_lcnphy_a1(pi, 3, 0, 0);
3936 wlc_lcnphy_a1(pi, 2, 3, 2);
3937 wlc_lcnphy_a1(pi, 0, 5, 8);
3938 wlc_lcnphy_a1(pi, 2, 2, 1);
3939 wlc_lcnphy_a1(pi, 0, 4, 3);
3940
3941 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3942 locc2 = wlc_lcnphy_get_cc(pi, 2);
3943 locc3 = wlc_lcnphy_get_cc(pi, 3);
3944 locc4 = wlc_lcnphy_get_cc(pi, 4);
3945 }
3946
3947 static void
wlc_lcnphy_set_cc(phy_info_t * pi,int cal_type,s16 coeff_x,s16 coeff_y)3948 wlc_lcnphy_set_cc(phy_info_t *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3949 {
3950 u16 di0dq0;
3951 u16 x, y, data_rf;
3952 int k;
3953 switch (cal_type) {
3954 case 0:
3955 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3956 break;
3957 case 2:
3958 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3959 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3960 break;
3961 case 3:
3962 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3963 y = 8 + k;
3964 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3965 x = 8 - k;
3966 data_rf = (x * 16 + y);
3967 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3968 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3969 y = 8 + k;
3970 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3971 x = 8 - k;
3972 data_rf = (x * 16 + y);
3973 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3974 break;
3975 case 4:
3976 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3977 y = 8 + k;
3978 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3979 x = 8 - k;
3980 data_rf = (x * 16 + y);
3981 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3982 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3983 y = 8 + k;
3984 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3985 x = 8 - k;
3986 data_rf = (x * 16 + y);
3987 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3988 break;
3989 }
3990 }
3991
wlc_lcnphy_get_cc(phy_info_t * pi,int cal_type)3992 static lcnphy_unsign16_struct wlc_lcnphy_get_cc(phy_info_t *pi, int cal_type)
3993 {
3994 u16 a, b, didq;
3995 u8 di0, dq0, ei, eq, fi, fq;
3996 lcnphy_unsign16_struct cc;
3997 cc.re = 0;
3998 cc.im = 0;
3999 switch (cal_type) {
4000 case 0:
4001 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
4002 cc.re = a;
4003 cc.im = b;
4004 break;
4005 case 2:
4006 didq = wlc_lcnphy_get_tx_locc(pi);
4007 di0 = (((didq & 0xff00) << 16) >> 24);
4008 dq0 = (((didq & 0x00ff) << 24) >> 24);
4009 cc.re = (u16) di0;
4010 cc.im = (u16) dq0;
4011 break;
4012 case 3:
4013 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4014 cc.re = (u16) ei;
4015 cc.im = (u16) eq;
4016 break;
4017 case 4:
4018 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
4019 cc.re = (u16) fi;
4020 cc.im = (u16) fq;
4021 break;
4022 }
4023 return cc;
4024 }
4025
4026 static void
wlc_lcnphy_a1(phy_info_t * pi,int cal_type,int num_levels,int step_size_lg2)4027 wlc_lcnphy_a1(phy_info_t *pi, int cal_type, int num_levels, int step_size_lg2)
4028 {
4029 const lcnphy_spb_tone_t *phy_c1;
4030 lcnphy_spb_tone_t phy_c2;
4031 lcnphy_unsign16_struct phy_c3;
4032 int phy_c4, phy_c5, k, l, j, phy_c6;
4033 u16 phy_c7, phy_c8, phy_c9;
4034 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
4035 s16 *ptr, phy_c17;
4036 s32 phy_c18, phy_c19;
4037 u32 phy_c20, phy_c21;
4038 bool phy_c22, phy_c23, phy_c24, phy_c25;
4039 u16 phy_c26, phy_c27;
4040 u16 phy_c28, phy_c29, phy_c30;
4041 u16 phy_c31;
4042 u16 *phy_c32;
4043 phy_c21 = 0;
4044 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
4045 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
4046 if (NULL == ptr) {
4047 return;
4048 }
4049
4050 phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
4051 if (NULL == phy_c32) {
4052 kfree(ptr);
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
wlc_lcnphy_tx_iqlo_loopback_cleanup(phy_info_t * pi,u16 * values_to_save)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
WLBANDINITFN(wlc_lcnphy_load_tx_gain_table)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
wlc_lcnphy_load_rfpower(phy_info_t * pi)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
WLBANDINITFN(wlc_lcnphy_tbl_init)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
WLBANDINITFN(wlc_lcnphy_rev0_baseband_init)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
WLBANDINITFN(wlc_lcnphy_rev2_baseband_init)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
wlc_lcnphy_agc_temp_init(phy_info_t * pi)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
WLBANDINITFN(wlc_lcnphy_bu_tweaks)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
WLBANDINITFN(wlc_lcnphy_baseband_init)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
WLBANDINITFN(wlc_radio_2064_init)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
WLBANDINITFN(wlc_lcnphy_radio_init)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
wlc_lcnphy_rcal(phy_info_t * pi)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
wlc_lcnphy_rc_cal(phy_info_t * pi)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
wlc_phy_txpwr_srom_read_lcnphy(phy_info_t * pi)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
wlc_2064_vco_cal(phy_info_t * pi)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
wlc_lcnphy_radio_2064_channel_tune_4313(phy_info_t * pi,u8 channel)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
wlc_phy_tpc_isenabled_lcnphy(phy_info_t * pi)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
wlc_phy_txpower_recalc_target_lcnphy(phy_info_t * pi)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
wlc_phy_detach_lcnphy(phy_info_t * pi)5053 void wlc_phy_detach_lcnphy(phy_info_t *pi)
5054 {
5055 kfree(pi->u.pi_lcnphy);
5056 }
5057
wlc_phy_attach_lcnphy(phy_info_t * pi)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
wlc_lcnphy_set_rx_gain(phy_info_t * pi,u32 gain)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
wlc_lcnphy_get_receive_power(phy_info_t * pi,s32 * gain_index)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
wlc_lcnphy_rx_signal_power(phy_info_t * pi,s32 gain_index)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
wlc_lcnphy_load_tx_iir_filter(phy_info_t * pi,bool is_ofdm,s16 filt_type)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 }
5326