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