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