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