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