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