brcmsmac: use sprom from bcma
[deliverable/linux.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) |
1140 ((lna2 &
1141 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
1142
1143 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
1144 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
1145 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1146
1147 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1148 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1149 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
1150 } else {
1151 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
1152
1153 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
1154
1155 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1156 }
1157
1158 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
1159
1160}
1161
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;
1345 int tia_gain;
1346 u32 received_power, rx_pwr_threshold;
1347 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1348 u16 values_to_save[11];
1349 s16 *ptr;
1350 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1351
1352 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1353 if (NULL == ptr)
1354 return false;
1355 if (module == 2) {
1356 while (iqcomp_sz--) {
1357 if (iqcomp[iqcomp_sz].chan ==
1358 CHSPEC_CHANNEL(pi->radio_chanspec)) {
1359 wlc_lcnphy_set_rx_iq_comp(pi,
1360 (u16)
1361 iqcomp[iqcomp_sz].a,
1362 (u16)
1363 iqcomp[iqcomp_sz].b);
1364 result = true;
1365 break;
1366 }
1367 }
1368 goto cal_done;
1369 }
1370
1371 if (module == 1) {
1372
1373 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1374 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1375
1376 for (i = 0; i < 11; i++)
1377 values_to_save[i] =
1378 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1379 Core1TxControl_old = read_phy_reg(pi, 0x631);
1380
1381 or_phy_reg(pi, 0x631, 0x0015);
1382
1383 RFOverride0_old = read_phy_reg(pi, 0x44c);
1384 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1385 rfoverride2_old = read_phy_reg(pi, 0x4b0);
1386 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1387 rfoverride3_old = read_phy_reg(pi, 0x4f9);
1388 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1389 rfoverride4_old = read_phy_reg(pi, 0x938);
1390 rfoverride4val_old = read_phy_reg(pi, 0x939);
1391 afectrlovr_old = read_phy_reg(pi, 0x43b);
1392 afectrlovrval_old = read_phy_reg(pi, 0x43c);
1393 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1394 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1395
1396 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1397 if (tx_gain_override_old) {
1398 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1399 tx_gain_index_old = pi_lcn->lcnphy_current_index;
1400 }
1401
1402 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1403
1404 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1405 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1406
1407 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1408 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1409
1410 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1411 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1412 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1413 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1414 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1415 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1416 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1417 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1418 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1419 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1420
1421 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1422 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1423 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1424 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1425 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1426 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1427 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1428 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1429 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1430 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1431
1432 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1433 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1434
1435 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
1436 write_phy_reg(pi, 0x6da, 0xffff);
1437 or_phy_reg(pi, 0x6db, 0x3);
1438 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1439 wlc_lcnphy_rx_gain_override_enable(pi, true);
1440
1441 tia_gain = 8;
1442 rx_pwr_threshold = 950;
1443 while (tia_gain > 0) {
1444 tia_gain -= 1;
1445 wlc_lcnphy_set_rx_gain_by_distribution(pi,
1446 0, 0, 2, 2,
1447 (u16)
1448 tia_gain, 1, 0);
1449 udelay(500);
1450
1451 received_power =
1452 wlc_lcnphy_measure_digital_power(pi, 2000);
1453 if (received_power < rx_pwr_threshold)
1454 break;
1455 }
1456 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
1457
1458 wlc_lcnphy_stop_tx_tone(pi);
1459
1460 write_phy_reg(pi, 0x631, Core1TxControl_old);
1461
1462 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1463 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1464 write_phy_reg(pi, 0x4b0, rfoverride2_old);
1465 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1466 write_phy_reg(pi, 0x4f9, rfoverride3_old);
1467 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1468 write_phy_reg(pi, 0x938, rfoverride4_old);
1469 write_phy_reg(pi, 0x939, rfoverride4val_old);
1470 write_phy_reg(pi, 0x43b, afectrlovr_old);
1471 write_phy_reg(pi, 0x43c, afectrlovrval_old);
1472 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1473 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1474
1475 wlc_lcnphy_clear_trsw_override(pi);
1476
1477 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1478
1479 for (i = 0; i < 11; i++)
1480 write_radio_reg(pi, rxiq_cal_rf_reg[i],
1481 values_to_save[i]);
1482
1483 if (tx_gain_override_old)
1484 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1485 else
1486 wlc_lcnphy_disable_tx_gain_override(pi);
1487
1488 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1489 wlc_lcnphy_rx_gain_override_enable(pi, false);
1490 }
1491
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
1863void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
1864{
1865 u8 channel = CHSPEC_CHANNEL(chanspec);
1866
1867 wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec);
1868
1869 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1870
1871 or_phy_reg(pi, 0x44a, 0x44);
1872 write_phy_reg(pi, 0x44a, 0x80);
1873
1874 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1875 udelay(1000);
1876
1877 wlc_lcnphy_toggle_afe_pwdn(pi);
1878
1879 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1880 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1881
1882 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1883 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1884
1885 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
1886 } else {
1887 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1888
1889 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
1890 }
1891
1892 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
1893
1894 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1895
1896}
1897
1898static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1899{
1900 u16 pa_gain;
1901
1902 pa_gain = (read_phy_reg(pi, 0x4fb) &
1903 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1904 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1905
1906 return pa_gain;
1907}
1908
1909static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1910 struct lcnphy_txgains *target_gains)
1911{
1912 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1913
1914 mod_phy_reg(
1915 pi, 0x4b5,
1916 (0xffff << 0),
1917 ((target_gains->gm_gain) |
1918 (target_gains->pga_gain << 8)) <<
1919 0);
1920 mod_phy_reg(pi, 0x4fb,
1921 (0x7fff << 0),
1922 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1923
1924 mod_phy_reg(
1925 pi, 0x4fc,
1926 (0xffff << 0),
1927 ((target_gains->gm_gain) |
1928 (target_gains->pga_gain << 8)) <<
1929 0);
1930 mod_phy_reg(pi, 0x4fd,
1931 (0x7fff << 0),
1932 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1933
1934 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1935
1936 wlc_lcnphy_enable_tx_gain_override(pi);
1937}
1938
1939static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1940{
1941 u16 m0m1 = (u16) m0 << 8;
1942 struct phytbl_info tab;
1943
1944 tab.tbl_ptr = &m0m1;
1945 tab.tbl_len = 1;
1946 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1947 tab.tbl_offset = 87;
1948 tab.tbl_width = 16;
1949 wlc_lcnphy_write_table(pi, &tab);
1950}
1951
1952static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1953{
1954 u32 data_buf[64];
1955 struct phytbl_info tab;
1956
1957 memset(data_buf, 0, sizeof(data_buf));
1958
1959 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1960 tab.tbl_width = 32;
1961 tab.tbl_ptr = data_buf;
1962
1963 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1964
1965 tab.tbl_len = 30;
1966 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1967 wlc_lcnphy_write_table(pi, &tab);
1968 }
1969
1970 tab.tbl_len = 64;
1971 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1972 wlc_lcnphy_write_table(pi, &tab);
1973}
1974
1975enum lcnphy_tssi_mode {
1976 LCNPHY_TSSI_PRE_PA,
1977 LCNPHY_TSSI_POST_PA,
1978 LCNPHY_TSSI_EXT
1979};
1980
1981static void
1982wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
1983{
1984 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1985
1986 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1987
1988 if (LCNPHY_TSSI_POST_PA == pos) {
1989 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1990
1991 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1992
1993 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1994 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1995 } else {
1996 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1997 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
1998 }
1999 } else {
2000 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2001
2002 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2003
2004 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2005 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2006 } else {
2007 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2008 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2009 }
2010 }
2011 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2012
2013 if (LCNPHY_TSSI_EXT == pos) {
2014 write_radio_reg(pi, RADIO_2064_REG07F, 1);
2015 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2016 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2017 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2018 }
2019}
2020
2021static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2022{
2023 u16 N1, N2, N3, N4, N5, N6, N;
2024 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2025 >> 0);
2026 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2027 >> 12);
2028 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2029 >> 0);
2030 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2031 >> 8);
2032 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2033 >> 0);
2034 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2035 >> 8);
2036 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2037 if (N < 1600)
2038 N = 1600;
2039 return N;
2040}
2041
2042static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2043{
2044 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2045 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2046
2047 auxpga_vmid = (2 << 8) |
2048 (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2049 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2050 auxpga_gain_temp = 2;
2051
2052 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2053
2054 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2055
2056 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2057
2058 mod_phy_reg(pi, 0x4db,
2059 (0x3ff << 0) |
2060 (0x7 << 12),
2061 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2062
2063 mod_phy_reg(pi, 0x4dc,
2064 (0x3ff << 0) |
2065 (0x7 << 12),
2066 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2067
2068 mod_phy_reg(pi, 0x40a,
2069 (0x3ff << 0) |
2070 (0x7 << 12),
2071 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2072
2073 mod_phy_reg(pi, 0x40b,
2074 (0x3ff << 0) |
2075 (0x7 << 12),
2076 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2077
2078 mod_phy_reg(pi, 0x40c,
2079 (0x3ff << 0) |
2080 (0x7 << 12),
2081 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2082
2083 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2084}
2085
2086static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2087{
2088 struct phytbl_info tab;
2089 u32 rfseq, ind;
2090
2091 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2092 tab.tbl_width = 32;
2093 tab.tbl_ptr = &ind;
2094 tab.tbl_len = 1;
2095 tab.tbl_offset = 0;
2096 for (ind = 0; ind < 128; ind++) {
2097 wlc_lcnphy_write_table(pi, &tab);
2098 tab.tbl_offset++;
2099 }
2100 tab.tbl_offset = 704;
2101 for (ind = 0; ind < 128; ind++) {
2102 wlc_lcnphy_write_table(pi, &tab);
2103 tab.tbl_offset++;
2104 }
2105 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2106
2107 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2108
2109 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2110
2111 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
2112 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2113
2114 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2115
2116 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2117
2118 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2119
2120 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2121
2122 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2123
2124 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2125
2126 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2127
2128 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2129
2130 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2131
2132 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2133
2134 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2135
2136 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2137
2138 wlc_lcnphy_clear_tx_power_offsets(pi);
2139
2140 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2141
2142 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2143
2144 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2145
2146 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2147 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
2148 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2149 } else {
2150 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2151 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2152 }
2153
2154 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2155
2156 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2157 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2158 } else {
2159 if (CHSPEC_IS2G(pi->radio_chanspec))
2160 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2161 else
2162 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2163 }
2164
2165 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2166 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2167 else
2168 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2169
2170 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2171
2172 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2173
2174 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2175 mod_phy_reg(pi, 0x4d7,
2176 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2177
2178 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2179 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2180 tab.tbl_width = 16;
2181 tab.tbl_ptr = &rfseq;
2182 tab.tbl_len = 1;
2183 tab.tbl_offset = 6;
2184 wlc_lcnphy_write_table(pi, &tab);
2185
2186 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2187
2188 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2189
2190 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2191
2192 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2193
2194 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2195
2196 wlc_lcnphy_pwrctrl_rssiparams(pi);
2197}
2198
2199void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2200{
2201 u16 tx_cnt, tx_total, npt;
2202 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2203
2204 tx_total = wlc_lcnphy_total_tx_frames(pi);
2205 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2206 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2207
2208 if (tx_cnt > (1 << npt)) {
2209
2210 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2211
2212 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2213 pi_lcn->lcnphy_tssi_npt = npt;
2214
2215 }
2216}
2217
2218s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2219{
2220 s32 a, b, p;
2221
2222 a = 32768 + (a1 * tssi);
2223 b = (1024 * b0) + (64 * b1 * tssi);
2224 p = ((2 * b) + a) / (2 * a);
2225
2226 return p;
2227}
2228
2229static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2230{
2231 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2232 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2233 return;
2234
2235 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2236 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2237}
2238
2239void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2240{
2241 struct phytbl_info tab;
2242 u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2243 BRCMS_NUM_RATES_MCS_1_STREAM];
2244 uint i, j;
2245 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2246 return;
2247
2248 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2249
2250 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2251 j = TXP_FIRST_MCS_20_SISO;
2252
2253 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2254 }
2255
2256 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2257 tab.tbl_width = 32;
2258 tab.tbl_len = ARRAY_SIZE(rate_table);
2259 tab.tbl_ptr = rate_table;
2260 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2261 wlc_lcnphy_write_table(pi, &tab);
2262
2263 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2264 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2265
2266 wlc_lcnphy_txpower_reset_npt(pi);
2267 }
2268}
2269
2270static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2271{
2272 u32 cck_offset[4] = { 22, 22, 22, 22 };
2273 u32 ofdm_offset, reg_offset_cck;
2274 int i;
2275 u16 index2;
2276 struct phytbl_info tab;
2277
2278 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2279 return;
2280
2281 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2282
2283 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2284
2285 or_phy_reg(pi, 0x6da, 0x0040);
2286
2287 reg_offset_cck = 0;
2288 for (i = 0; i < 4; i++)
2289 cck_offset[i] -= reg_offset_cck;
2290 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2291 tab.tbl_width = 32;
2292 tab.tbl_len = 4;
2293 tab.tbl_ptr = cck_offset;
2294 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2295 wlc_lcnphy_write_table(pi, &tab);
2296 ofdm_offset = 0;
2297 tab.tbl_len = 1;
2298 tab.tbl_ptr = &ofdm_offset;
2299 for (i = 836; i < 862; i++) {
2300 tab.tbl_offset = i;
2301 wlc_lcnphy_write_table(pi, &tab);
2302 }
2303
2304 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2305
2306 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2307
2308 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2309
2310 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2311
2312 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2313
2314 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2315
2316 index2 = (u16) (index * 2);
2317 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2318
2319 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2320
2321}
2322
2323static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2324{
2325 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2326 s16 manp, meas_temp, temp_diff;
3db1cd5c 2327 bool neg = false;
5b435de0
AS
2328 u16 temp;
2329 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2330
2331 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2332 return pi_lcn->lcnphy_current_index;
2333
2334 index = FIXED_TXPWR;
2335
2336 if (pi_lcn->lcnphy_tempsense_slope == 0)
2337 return index;
2338
2339 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2340 meas_temp = LCNPHY_TEMPSENSE(temp);
2341
2342 if (pi->tx_power_min != 0)
2343 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2344 else
2345 delta_brd = 0;
2346
2347 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2348 temp_diff = manp - meas_temp;
2349 if (temp_diff < 0) {
3db1cd5c 2350 neg = true;
5b435de0
AS
2351 temp_diff = -temp_diff;
2352 }
2353
2354 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2355 (u32) (pi_lcn->
2356 lcnphy_tempsense_slope
2357 * 10), 0);
2358 if (neg)
2359 delta_temp = -delta_temp;
2360
2361 if (pi_lcn->lcnphy_tempsense_option == 3
2362 && LCNREV_IS(pi->pubpi.phy_rev, 0))
2363 delta_temp = 0;
2364 if (pi_lcn->lcnphy_tempcorrx > 31)
2365 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2366 else
2367 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2368 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2369 tempcorrx = 4;
2370 new_index =
2371 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2372 new_index += tempcorrx;
2373
2374 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2375 index = 127;
2376
2377 if (new_index < 0 || new_index > 126)
2378 return index;
2379
2380 return new_index;
2381}
2382
2383static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2384{
2385
2386 u16 current_mode = mode;
2387 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2388 mode == LCNPHY_TX_PWR_CTRL_HW)
2389 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2390 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2391 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2392 current_mode = LCNPHY_TX_PWR_CTRL_HW;
2393 return current_mode;
2394}
2395
2396void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2397{
2398 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2399 s8 index;
2400 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2401
2402 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2403 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2404
2405 mod_phy_reg(pi, 0x6da, (0x1 << 6),
2406 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2407
2408 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2409 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2410
2411 if (old_mode != mode) {
2412 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2413
2414 wlc_lcnphy_tx_pwr_update_npt(pi);
2415
2416 wlc_lcnphy_clear_tx_power_offsets(pi);
2417 }
2418 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2419
2420 wlc_lcnphy_txpower_recalc_target(pi);
2421
2422 wlc_lcnphy_set_start_tx_pwr_idx(pi,
2423 pi_lcn->
2424 lcnphy_tssi_idx);
2425 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2426 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2427
2428 pi_lcn->lcnphy_tssi_tx_cnt =
2429 wlc_lcnphy_total_tx_frames(pi);
2430
2431 wlc_lcnphy_disable_tx_gain_override(pi);
2432 pi_lcn->lcnphy_tx_power_idx_override = -1;
2433 } else
2434 wlc_lcnphy_enable_tx_gain_override(pi);
2435
2436 mod_phy_reg(pi, 0x4a4,
2437 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2438 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2439 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2440 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2441 pi_lcn->lcnphy_current_index = (s8)
2442 ((read_phy_reg(pi,
2443 0x4a9) &
2444 0xFF) / 2);
2445 }
2446 }
2447}
2448
2449static void
2450wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2451{
2452 u16 vmid;
2453 int i;
2454 for (i = 0; i < 20; i++)
2455 values_to_save[i] =
2456 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2457
2458 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2459 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2460
2461 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2462 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2463
2464 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2465 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2466
2467 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2468 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2469
2470 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2471 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2472 else
2473 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2474 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2475
2476 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2477 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2478 udelay(20);
2479
2480 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2481 if (CHSPEC_IS5G(pi->radio_chanspec))
2482 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2483 else
2484 or_radio_reg(pi, RADIO_2064_REG03A, 1);
2485 } else {
2486 if (CHSPEC_IS5G(pi->radio_chanspec))
2487 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2488 else
2489 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2490 }
2491
2492 udelay(20);
2493
2494 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2495 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2496 if (CHSPEC_IS5G(pi->radio_chanspec))
2497 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2498 else
2499 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2500 } else {
2501 if (CHSPEC_IS5G(pi->radio_chanspec))
2502 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2503 else
2504 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2505 }
2506
2507 udelay(20);
2508
2509 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2510 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2511 udelay(20);
2512
2513 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2514 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2515 udelay(20);
2516
2517 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2518 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2519 udelay(20);
2520
2521 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2522 udelay(20);
2523
2524 vmid = 0x2A6;
2525 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2526 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2527 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2528 udelay(20);
2529
2530 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2531 udelay(20);
2532 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2533 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2534 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2535 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2536 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2537 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2538 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2539}
2540
2541static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2542{
2543 uint delay_count = 0;
2544
2545 while (wlc_lcnphy_iqcal_active(pi)) {
2546 udelay(100);
2547 delay_count++;
2548
2549 if (delay_count > (10 * 500))
2550 break;
2551 }
2552
2553 return (0 == wlc_lcnphy_iqcal_active(pi));
2554}
2555
2556static void
2557wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2558{
2559 int i;
2560
2561 and_phy_reg(pi, 0x44c, 0x0 >> 11);
2562
2563 and_phy_reg(pi, 0x43b, 0xC);
2564
2565 for (i = 0; i < 20; i++)
2566 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2567 values_to_save[i]);
2568}
2569
2570static void
2571wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2572 struct lcnphy_txgains *target_gains,
2573 enum lcnphy_cal_mode cal_mode, bool keep_tone)
2574{
2575
2576 struct lcnphy_txgains cal_gains, temp_gains;
2577 u16 hash;
2578 u8 band_idx;
2579 int j;
2580 u16 ncorr_override[5];
2581 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2582 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2583
2584 u16 commands_fullcal[] = {
2585 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2586 };
2587
2588 u16 commands_recal[] = {
2589 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2590 };
2591
2592 u16 command_nums_fullcal[] = {
2593 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2594 };
2595
2596 u16 command_nums_recal[] = {
2597 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2598 };
2599 u16 *command_nums = command_nums_fullcal;
2600
2601 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2602 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2603 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2604 bool tx_gain_override_old;
2605 struct lcnphy_txgains old_gains;
2606 uint i, n_cal_cmds = 0, n_cal_start = 0;
2607 u16 *values_to_save;
2608 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2609
2610 values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2611 if (NULL == values_to_save)
2612 return;
2613
2614 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2615 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2616
2617 or_phy_reg(pi, 0x6da, 0x40);
2618 or_phy_reg(pi, 0x6db, 0x3);
2619
2620 switch (cal_mode) {
2621 case LCNPHY_CAL_FULL:
2622 start_coeffs = syst_coeffs;
2623 cal_cmds = commands_fullcal;
2624 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2625 break;
2626
2627 case LCNPHY_CAL_RECAL:
2628 start_coeffs = syst_coeffs;
2629 cal_cmds = commands_recal;
2630 n_cal_cmds = ARRAY_SIZE(commands_recal);
2631 command_nums = command_nums_recal;
2632 break;
2633
2634 default:
2635 break;
2636 }
2637
2638 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2639 start_coeffs, 11, 16, 64);
2640
2641 write_phy_reg(pi, 0x6da, 0xffff);
2642 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2643
2644 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2645
2646 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2647
2648 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2649
2650 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2651
2652 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2653
2654 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2655
2656 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2657
2658 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2659 if (tx_gain_override_old)
2660 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2661
2662 if (!target_gains) {
2663 if (!tx_gain_override_old)
2664 wlc_lcnphy_set_tx_pwr_by_index(pi,
2665 pi_lcn->lcnphy_tssi_idx);
2666 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2667 target_gains = &temp_gains;
2668 }
2669
2670 hash = (target_gains->gm_gain << 8) |
2671 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2672
2673 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2674
2675 cal_gains = *target_gains;
2676 memset(ncorr_override, 0, sizeof(ncorr_override));
2677 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2678 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2679 cal_gains.gm_gain =
2680 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2681 cal_gains.pga_gain =
2682 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2683 cal_gains.pad_gain =
2684 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2685 memcpy(ncorr_override,
2686 &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2687 sizeof(ncorr_override));
2688 break;
2689 }
2690 }
2691
2692 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2693
2694 write_phy_reg(pi, 0x453, 0xaa9);
2695 write_phy_reg(pi, 0x93d, 0xc0);
2696
2697 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2698 lcnphy_iqcal_loft_gainladder,
2699 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2700 16, 0);
2701
2702 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2703 lcnphy_iqcal_ir_gainladder,
2704 ARRAY_SIZE(
2705 lcnphy_iqcal_ir_gainladder), 16,
2706 32);
2707
2708 if (pi->phy_tx_tone_freq) {
2709
2710 wlc_lcnphy_stop_tx_tone(pi);
2711 udelay(5);
2712 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2713 } else {
2714 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2715 }
2716
2717 write_phy_reg(pi, 0x6da, 0xffff);
2718
2719 for (i = n_cal_start; i < n_cal_cmds; i++) {
2720 u16 zero_diq = 0;
2721 u16 best_coeffs[11];
2722 u16 command_num;
2723
2724 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2725
2726 command_num = command_nums[i];
2727 if (ncorr_override[cal_type])
2728 command_num =
2729 ncorr_override[cal_type] << 8 | (command_num &
2730 0xff);
2731
2732 write_phy_reg(pi, 0x452, command_num);
2733
2734 if ((cal_type == 3) || (cal_type == 4)) {
2735 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2736 &diq_start, 1, 16, 69);
2737
2738 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2739 &zero_diq, 1, 16, 69);
2740 }
2741
2742 write_phy_reg(pi, 0x451, cal_cmds[i]);
2743
2744 if (!wlc_lcnphy_iqcal_wait(pi))
2745 goto cleanup;
2746
2747 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2748 best_coeffs,
2749 ARRAY_SIZE(best_coeffs), 16, 96);
2750 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2751 best_coeffs,
2752 ARRAY_SIZE(best_coeffs), 16, 64);
2753
2754 if ((cal_type == 3) || (cal_type == 4))
2755 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2756 &diq_start, 1, 16, 69);
2757 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2758 pi_lcn->lcnphy_cal_results.
2759 txiqlocal_bestcoeffs,
2760 ARRAY_SIZE(pi_lcn->
2761 lcnphy_cal_results.
2762 txiqlocal_bestcoeffs),
2763 16, 96);
2764 }
2765
2766 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2767 pi_lcn->lcnphy_cal_results.
2768 txiqlocal_bestcoeffs,
2769 ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2770 txiqlocal_bestcoeffs), 16, 96);
2771 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2772
2773 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2774 &pi_lcn->lcnphy_cal_results.
2775 txiqlocal_bestcoeffs[0], 4, 16, 80);
2776
2777 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2778 &pi_lcn->lcnphy_cal_results.
2779 txiqlocal_bestcoeffs[5], 2, 16, 85);
2780
2781cleanup:
2782 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2783 kfree(values_to_save);
2784
2785 if (!keep_tone)
2786 wlc_lcnphy_stop_tx_tone(pi);
2787
2788 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2789
2790 write_phy_reg(pi, 0x453, 0);
2791
2792 if (tx_gain_override_old)
2793 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2794 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2795
2796 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2797 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2798
2799}
2800
2801static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2802{
2803 bool suspend, tx_gain_override_old;
2804 struct lcnphy_txgains old_gains;
2805 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2806 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2807 idleTssi0_regvalue_2C;
2808 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2809 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2810 u16 SAVE_jtag_bb_afe_switch =
2811 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2812 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2813 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2814 idleTssi = read_phy_reg(pi, 0x4ab);
4b006b11
AS
2815 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2816 MCTL_EN_MAC));
5b435de0
AS
2817 if (!suspend)
2818 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2819 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2820
2821 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2822 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2823
2824 wlc_lcnphy_enable_tx_gain_override(pi);
2825 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2826 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2827 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2828 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2829 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2830 wlc_lcnphy_tssi_setup(pi);
2831 wlc_phy_do_dummy_tx(pi, true, OFF);
2832 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2833 >> 0);
2834
2835 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2836 >> 0);
2837
2838 if (idleTssi0_2C >= 256)
2839 idleTssi0_OB = idleTssi0_2C - 256;
2840 else
2841 idleTssi0_OB = idleTssi0_2C + 256;
2842
2843 idleTssi0_regvalue_OB = idleTssi0_OB;
2844 if (idleTssi0_regvalue_OB >= 256)
2845 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2846 else
2847 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2848 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2849
2850 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2851
2852 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2853 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2854 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2855
2856 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2857 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2858 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2859 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2860 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2861 if (!suspend)
2862 wlapi_enable_mac(pi->sh->physhim);
2863}
2864
2865static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2866{
2867 bool suspend;
2868 u16 save_txpwrCtrlEn;
2869 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2870 u16 auxpga_vmid;
2871 struct phytbl_info tab;
2872 u32 val;
2873 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2874 save_reg112;
2875 u16 values_to_save[14];
2876 s8 index;
2877 int i;
2878 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2879 udelay(999);
2880
2881 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2882 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2883 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2884 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2885 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2886 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2887
2888 for (i = 0; i < 14; i++)
2889 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
4b006b11
AS
2890 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2891 MCTL_EN_MAC));
5b435de0
AS
2892 if (!suspend)
2893 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2894 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2895
2896 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2897 index = pi_lcn->lcnphy_current_index;
2898 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2899 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2900 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2901 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2902 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2903
2904 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2905
2906 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2907
2908 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2909
2910 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2911
2912 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2913
2914 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2915
2916 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2917
2918 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2919
2920 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2921
2922 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2923
2924 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2925
2926 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2927
2928 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2929
2930 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2931
2932 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2933
2934 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2935
2936 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2937
2938 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2939
2940 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2941
2942 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2943
2944 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2945
2946 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2947
2948 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2949 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2950 tab.tbl_width = 16;
2951 tab.tbl_len = 1;
2952 tab.tbl_ptr = &val;
2953 tab.tbl_offset = 6;
2954 wlc_lcnphy_write_table(pi, &tab);
2955 if (mode == TEMPSENSE) {
2956 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2957
2958 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2959
2960 auxpga_vmidcourse = 8;
2961 auxpga_vmidfine = 0x4;
2962 auxpga_gain = 2;
2963 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2964 } else {
2965 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2966
2967 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2968
2969 auxpga_vmidcourse = 7;
2970 auxpga_vmidfine = 0xa;
2971 auxpga_gain = 2;
2972 }
2973 auxpga_vmid =
2974 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2975 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2976
2977 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2978
2979 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2980
2981 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2982
2983 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2984
2985 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2986
2987 wlc_phy_do_dummy_tx(pi, true, OFF);
2988 if (!tempsense_done(pi))
2989 udelay(10);
2990
2991 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2992 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2993 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2994 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2995 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2996 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
2997 for (i = 0; i < 14; i++)
2998 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
2999 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3000
3001 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3002 if (!suspend)
3003 wlapi_enable_mac(pi->sh->physhim);
3004 udelay(999);
3005}
3006
3007static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3008{
3009 struct lcnphy_txgains tx_gains;
3010 u8 bbmult;
3011 struct phytbl_info tab;
3012 s32 a1, b0, b1;
3013 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3014 bool suspend;
3015 struct brcms_phy *pi = (struct brcms_phy *) ppi;
3016
4b006b11
AS
3017 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3018 MCTL_EN_MAC));
5b435de0
AS
3019 if (!suspend)
3020 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3021
3022 if (!pi->hwpwrctrl_capable) {
3023 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3024 tx_gains.gm_gain = 4;
3025 tx_gains.pga_gain = 12;
3026 tx_gains.pad_gain = 12;
3027 tx_gains.dac_gain = 0;
3028
3029 bbmult = 150;
3030 } else {
3031 tx_gains.gm_gain = 7;
3032 tx_gains.pga_gain = 15;
3033 tx_gains.pad_gain = 14;
3034 tx_gains.dac_gain = 0;
3035
3036 bbmult = 150;
3037 }
3038 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3039 wlc_lcnphy_set_bbmult(pi, bbmult);
3040 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3041 } else {
3042
3043 wlc_lcnphy_idle_tssi_est(ppi);
3044
3045 wlc_lcnphy_clear_tx_power_offsets(pi);
3046
3047 b0 = pi->txpa_2g[0];
3048 b1 = pi->txpa_2g[1];
3049 a1 = pi->txpa_2g[2];
3050 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3051 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3052
3053 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3054 tab.tbl_width = 32;
3055 tab.tbl_ptr = &pwr;
3056 tab.tbl_len = 1;
3057 tab.tbl_offset = 0;
3058 for (tssi = 0; tssi < 128; tssi++) {
3059 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3060
3061 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3062 wlc_lcnphy_write_table(pi, &tab);
3063 tab.tbl_offset++;
3064 }
3065
3066 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3067
3068 write_phy_reg(pi, 0x4a8, 10);
3069
3070 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3071
3072 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3073 }
3074 if (!suspend)
3075 wlapi_enable_mac(pi->sh->physhim);
3076}
3077
3078static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
3079{
3080 u16 m0m1;
3081 struct phytbl_info tab;
3082
3083 tab.tbl_ptr = &m0m1;
3084 tab.tbl_len = 1;
3085 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3086 tab.tbl_offset = 87;
3087 tab.tbl_width = 16;
3088 wlc_lcnphy_read_table(pi, &tab);
3089
3090 return (u8) ((m0m1 & 0xff00) >> 8);
3091}
3092
3093static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3094{
3095 mod_phy_reg(pi, 0x4fb,
3096 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3097 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3098 mod_phy_reg(pi, 0x4fd,
3099 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3100 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3101}
3102
3103void
3104wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3105 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3106{
3107 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3108 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3109 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3110 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3111}
3112
3113void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3114{
3115 struct phytbl_info tab;
3116 u16 iqcc[2];
3117
3118 iqcc[0] = a;
3119 iqcc[1] = b;
3120
3121 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3122 tab.tbl_width = 16;
3123 tab.tbl_ptr = iqcc;
3124 tab.tbl_len = 2;
3125 tab.tbl_offset = 80;
3126 wlc_lcnphy_write_table(pi, &tab);
3127}
3128
3129void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3130{
3131 struct phytbl_info tab;
3132
3133 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3134 tab.tbl_width = 16;
3135 tab.tbl_ptr = &didq;
3136 tab.tbl_len = 1;
3137 tab.tbl_offset = 85;
3138 wlc_lcnphy_write_table(pi, &tab);
3139}
3140
3141void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3142{
3143 struct phytbl_info tab;
3144 u16 a, b;
3145 u8 bb_mult;
3146 u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3147 struct lcnphy_txgains gains;
3148 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3149
3150 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3151 pi_lcn->lcnphy_current_index = (u8) index;
3152
3153 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3154 tab.tbl_width = 32;
3155 tab.tbl_len = 1;
3156
3157 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3158
3159 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3160 tab.tbl_ptr = &bbmultiqcomp;
3161 wlc_lcnphy_read_table(pi, &tab);
3162
3163 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3164 tab.tbl_width = 32;
3165 tab.tbl_ptr = &txgain;
3166 wlc_lcnphy_read_table(pi, &tab);
3167
3168 gains.gm_gain = (u16) (txgain & 0xff);
3169 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3170 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3171 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3172 wlc_lcnphy_set_tx_gain(pi, &gains);
3173 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3174
3175 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3176 wlc_lcnphy_set_bbmult(pi, bb_mult);
3177
3178 wlc_lcnphy_enable_tx_gain_override(pi);
3179
3180 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3181
3182 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3183 b = (u16) (bbmultiqcomp & 0x3ff);
3184 wlc_lcnphy_set_tx_iqcc(pi, a, b);
3185
3186 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3187 tab.tbl_ptr = &locoeffs;
3188 wlc_lcnphy_read_table(pi, &tab);
3189
3190 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3191
3192 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3193 tab.tbl_ptr = &rfpower;
3194 wlc_lcnphy_read_table(pi, &tab);
3195 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3196
3197 }
3198}
3199
3200static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3201{
3202 u32 j;
3203 struct phytbl_info tab;
3204 u32 temp_offset[128];
3205 tab.tbl_ptr = temp_offset;
3206 tab.tbl_len = 128;
3207 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3208 tab.tbl_width = 32;
3209 tab.tbl_offset = 0;
3210
3211 memset(temp_offset, 0, sizeof(temp_offset));
3212 for (j = 1; j < 128; j += 2)
3213 temp_offset[j] = 0x80000;
3214
3215 wlc_lcnphy_write_table(pi, &tab);
3216 return;
3217}
3218
3219void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3220{
3221 if (!bEnable) {
3222
3223 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3224
3225 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3226
3227 and_phy_reg(pi, 0x44c,
3228 ~(u16) ((0x1 << 3) |
3229 (0x1 << 5) |
3230 (0x1 << 12) |
3231 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3232
3233 and_phy_reg(pi, 0x44d,
3234 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3235 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3236
3237 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3238
3239 and_phy_reg(pi, 0x4f9,
3240 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3241
3242 and_phy_reg(pi, 0x4fa,
3243 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3244 } else {
3245
3246 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3247 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3248
3249 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3250 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3251
3252 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3253 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3254
3255 wlc_lcnphy_set_trsw_override(pi, true, false);
3256
3257 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3258 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3259
3260 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3261
3262 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3263 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3264
3265 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3266 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3267
3268 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3269 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3270
3271 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3272 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3273
3274 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3275 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3276 } else {
3277
3278 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3279 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3280
3281 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3282 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3283
3284 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3285 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3286
3287 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3288 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3289
3290 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3291 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3292 }
3293 }
3294}
3295
3296static void
3297wlc_lcnphy_run_samples(struct brcms_phy *pi,
3298 u16 num_samps,
3299 u16 num_loops, u16 wait, bool iqcalmode)
3300{
3301
3302 or_phy_reg(pi, 0x6da, 0x8080);
3303
3304 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3305 if (num_loops != 0xffff)
3306 num_loops--;
3307 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3308
3309 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3310
3311 if (iqcalmode) {
3312
3313 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3314 or_phy_reg(pi, 0x453, (0x1 << 15));
3315 } else {
3316 write_phy_reg(pi, 0x63f, 1);
3317 wlc_lcnphy_tx_pu(pi, 1);
3318 }
3319
3320 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3321}
3322
3323void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3324{
3325
3326 u8 phybw40;
3327 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3328
3329 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3330 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3331 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3332 } else {
3333 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3334 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3335 }
3336
3337 if (phybw40 == 0) {
3338 mod_phy_reg((pi), 0x410,
3339 (0x1 << 6) |
3340 (0x1 << 5),
3341 ((CHSPEC_IS2G(
3342 pi->radio_chanspec)) ? (!mode) : 0) <<
3343 6 | (!mode) << 5);
3344 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3345 }
3346}
3347
3348void
3349wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3350 bool iqcalmode)
3351{
3352 u8 phy_bw;
3353 u16 num_samps, t, k;
3354 u32 bw;
3355 s32 theta = 0, rot = 0;
3356 struct cordic_iq tone_samp;
3357 u32 data_buf[64];
3358 u16 i_samp, q_samp;
3359 struct phytbl_info tab;
3360 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3361
3362 pi->phy_tx_tone_freq = f_kHz;
3363
3364 wlc_lcnphy_deaf_mode(pi, true);
3365
3366 phy_bw = 40;
3367 if (pi_lcn->lcnphy_spurmod) {
3368 write_phy_reg(pi, 0x942, 0x2);
3369 write_phy_reg(pi, 0x93b, 0x0);
3370 write_phy_reg(pi, 0x93c, 0x0);
3371 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3372 }
3373
3374 if (f_kHz) {
3375 k = 1;
3376 do {
3377 bw = phy_bw * 1000 * k;
3378 num_samps = bw / abs(f_kHz);
3379 k++;
3380 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3381 } else
3382 num_samps = 2;
3383
3384 rot = ((f_kHz * 36) / phy_bw) / 100;
3385 theta = 0;
3386
3387 for (t = 0; t < num_samps; t++) {
3388
3389 tone_samp = cordic_calc_iq(theta);
3390
3391 theta += rot;
3392
3393 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3394 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3395 data_buf[t] = (i_samp << 10) | q_samp;
3396 }
3397
3398 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3399
3400 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3401
3402 tab.tbl_ptr = data_buf;
3403 tab.tbl_len = num_samps;
3404 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3405 tab.tbl_offset = 0;
3406 tab.tbl_width = 32;
3407 wlc_lcnphy_write_table(pi, &tab);
3408
3409 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3410}
3411
3412void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3413{
3414 s16 playback_status;
3415 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3416
3417 pi->phy_tx_tone_freq = 0;
3418 if (pi_lcn->lcnphy_spurmod) {
3419 write_phy_reg(pi, 0x942, 0x7);
3420 write_phy_reg(pi, 0x93b, 0x2017);
3421 write_phy_reg(pi, 0x93c, 0x27c5);
3422 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3423 }
3424
3425 playback_status = read_phy_reg(pi, 0x644);
3426 if (playback_status & (0x1 << 0)) {
3427 wlc_lcnphy_tx_pu(pi, 0);
3428 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3429 } else if (playback_status & (0x1 << 1))
3430 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3431
3432 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3433
3434 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3435
3436 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3437
3438 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3439
3440 wlc_lcnphy_deaf_mode(pi, false);
3441}
3442
3443static void
3444wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3445{
3446 u16 di0dq0;
3447 u16 x, y, data_rf;
3448 int k;
3449 switch (cal_type) {
3450 case 0:
3451 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3452 break;
3453 case 2:
3454 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3455 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3456 break;
3457 case 3:
3458 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3459 y = 8 + k;
3460 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3461 x = 8 - k;
3462 data_rf = (x * 16 + y);
3463 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3464 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3465 y = 8 + k;
3466 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3467 x = 8 - k;
3468 data_rf = (x * 16 + y);
3469 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3470 break;
3471 case 4:
3472 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3473 y = 8 + k;
3474 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3475 x = 8 - k;
3476 data_rf = (x * 16 + y);
3477 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3478 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3479 y = 8 + k;
3480 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3481 x = 8 - k;
3482 data_rf = (x * 16 + y);
3483 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3484 break;
3485 }
3486}
3487
3488static struct lcnphy_unsign16_struct
3489wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3490{
3491 u16 a, b, didq;
3492 u8 di0, dq0, ei, eq, fi, fq;
3493 struct lcnphy_unsign16_struct cc;
3494 cc.re = 0;
3495 cc.im = 0;
3496 switch (cal_type) {
3497 case 0:
3498 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3499 cc.re = a;
3500 cc.im = b;
3501 break;
3502 case 2:
3503 didq = wlc_lcnphy_get_tx_locc(pi);
3504 di0 = (((didq & 0xff00) << 16) >> 24);
3505 dq0 = (((didq & 0x00ff) << 24) >> 24);
3506 cc.re = (u16) di0;
3507 cc.im = (u16) dq0;
3508 break;
3509 case 3:
3510 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3511 cc.re = (u16) ei;
3512 cc.im = (u16) eq;
3513 break;
3514 case 4:
3515 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3516 cc.re = (u16) fi;
3517 cc.im = (u16) fq;
3518 break;
3519 }
3520 return cc;
3521}
3522
3523static void
3524wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3525 s16 *ptr, int mode)
3526{
3527 u32 curval1, curval2, stpptr, curptr, strptr, val;
3528 u16 sslpnCalibClkEnCtrl, timer;
3529 u16 old_sslpnCalibClkEnCtrl;
3530 s16 imag, real;
3531 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3532
3533 timer = 0;
3534 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3535
4b006b11 3536 curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
5b435de0 3537 ptr[130] = 0;
4b006b11
AS
3538 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3539 ((1 << 6) | curval1));
5b435de0 3540
4b006b11
AS
3541 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3542 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
5b435de0 3543 udelay(20);
4b006b11
AS
3544 curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3545 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3546 curval2 | 0x30);
5b435de0
AS
3547
3548 write_phy_reg(pi, 0x555, 0x0);
3549 write_phy_reg(pi, 0x5a6, 0x5);
3550
3551 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3552 write_phy_reg(pi, 0x5cf, 3);
3553 write_phy_reg(pi, 0x5a5, 0x3);
3554 write_phy_reg(pi, 0x583, 0x0);
3555 write_phy_reg(pi, 0x584, 0x0);
3556 write_phy_reg(pi, 0x585, 0x0fff);
3557 write_phy_reg(pi, 0x586, 0x0000);
3558
3559 write_phy_reg(pi, 0x580, 0x4501);
3560
3561 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3562 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
4b006b11
AS
3563 stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3564 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
5b435de0
AS
3565 do {
3566 udelay(10);
4b006b11 3567 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
5b435de0
AS
3568 timer++;
3569 } while ((curptr != stpptr) && (timer < 500));
3570
4b006b11 3571 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
5b435de0 3572 strptr = 0x7E00;
4b006b11 3573 bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
5b435de0 3574 while (strptr < 0x8000) {
4b006b11 3575 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
5b435de0
AS
3576 imag = ((val >> 16) & 0x3ff);
3577 real = ((val) & 0x3ff);
3578 if (imag > 511)
3579 imag -= 1024;
3580
3581 if (real > 511)
3582 real -= 1024;
3583
3584 if (pi_lcn->lcnphy_iqcal_swp_dis)
3585 ptr[(strptr - 0x7E00) / 4] = real;
3586 else
3587 ptr[(strptr - 0x7E00) / 4] = imag;
3588
3589 if (clip_detect_algo) {
3590 if (imag > thresh || imag < -thresh) {
3591 strptr = 0x8000;
3592 ptr[130] = 1;
3593 }
3594 }
3595
3596 strptr += 4;
3597 }
3598
3599 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
4b006b11
AS
3600 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3601 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
5b435de0
AS
3602}
3603
3604static void
3605wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3606 int step_size_lg2)
3607{
3608 const struct lcnphy_spb_tone *phy_c1;
3609 struct lcnphy_spb_tone phy_c2;
3610 struct lcnphy_unsign16_struct phy_c3;
3611 int phy_c4, phy_c5, k, l, j, phy_c6;
3612 u16 phy_c7, phy_c8, phy_c9;
3613 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3614 s16 *ptr, phy_c17;
3615 s32 phy_c18, phy_c19;
3616 u32 phy_c20, phy_c21;
3617 bool phy_c22, phy_c23, phy_c24, phy_c25;
3618 u16 phy_c26, phy_c27;
3619 u16 phy_c28, phy_c29, phy_c30;
3620 u16 phy_c31;
3621 u16 *phy_c32;
3622 phy_c21 = 0;
3623 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3624 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3625 if (NULL == ptr)
3626 return;
3627
3628 phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3629 if (NULL == phy_c32) {
3630 kfree(ptr);
3631 return;
3632 }
3633 phy_c26 = read_phy_reg(pi, 0x6da);
3634 phy_c27 = read_phy_reg(pi, 0x6db);
3635 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3636 write_phy_reg(pi, 0x93d, 0xC0);
3637
3638 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3639 write_phy_reg(pi, 0x6da, 0xffff);
3640 or_phy_reg(pi, 0x6db, 0x3);
3641
3642 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3643 udelay(500);
3644 phy_c28 = read_phy_reg(pi, 0x938);
3645 phy_c29 = read_phy_reg(pi, 0x4d7);
3646 phy_c30 = read_phy_reg(pi, 0x4d8);
3647 or_phy_reg(pi, 0x938, 0x1 << 2);
3648 or_phy_reg(pi, 0x4d7, 0x1 << 2);
3649 or_phy_reg(pi, 0x4d7, 0x1 << 3);
3650 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3651 or_phy_reg(pi, 0x4d8, 1 << 0);
3652 or_phy_reg(pi, 0x4d8, 1 << 1);
3653 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3654 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3655 phy_c1 = &lcnphy_spb_tone_3750[0];
3656 phy_c4 = 32;
3657
3658 if (num_levels == 0) {
3659 if (cal_type != 0)
3660 num_levels = 4;
3661 else
3662 num_levels = 9;
3663 }
3664 if (step_size_lg2 == 0) {
3665 if (cal_type != 0)
3666 step_size_lg2 = 3;
3667 else
3668 step_size_lg2 = 8;
3669 }
3670
3671 phy_c7 = (1 << step_size_lg2);
3672 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3673 phy_c15 = (s16) phy_c3.re;
3674 phy_c16 = (s16) phy_c3.im;
3675 if (cal_type == 2) {
3676 if (phy_c3.re > 127)
3677 phy_c15 = phy_c3.re - 256;
3678 if (phy_c3.im > 127)
3679 phy_c16 = phy_c3.im - 256;
3680 }
3681 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3682 udelay(20);
3683 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3db1cd5c
RR
3684 phy_c23 = true;
3685 phy_c22 = false;
5b435de0
AS
3686 switch (cal_type) {
3687 case 0:
3688 phy_c10 = 511;
3689 break;
3690 case 2:
3691 phy_c10 = 127;
3692 break;
3693 case 3:
3694 phy_c10 = 15;
3695 break;
3696 case 4:
3697 phy_c10 = 15;
3698 break;
3699 }
3700
3701 phy_c9 = read_phy_reg(pi, 0x93d);
3702 phy_c9 = 2 * phy_c9;
3db1cd5c 3703 phy_c24 = false;
5b435de0 3704 phy_c5 = 7;
3db1cd5c 3705 phy_c25 = true;
5b435de0
AS
3706 while (1) {
3707 write_radio_reg(pi, RADIO_2064_REG026,
3708 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3709 udelay(50);
3db1cd5c 3710 phy_c22 = false;
5b435de0
AS
3711 ptr[130] = 0;
3712 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3713 if (ptr[130] == 1)
3db1cd5c 3714 phy_c22 = true;
5b435de0
AS
3715 if (phy_c22)
3716 phy_c5 -= 1;
3717 if ((phy_c22 != phy_c24) && (!phy_c25))
3718 break;
3719 if (!phy_c22)
3720 phy_c5 += 1;
3721 if (phy_c5 <= 0 || phy_c5 >= 7)
3722 break;
3723 phy_c24 = phy_c22;
3db1cd5c 3724 phy_c25 = false;
5b435de0
AS
3725 }
3726
3727 if (phy_c5 < 0)
3728 phy_c5 = 0;
3729 else if (phy_c5 > 7)
3730 phy_c5 = 7;
3731
3732 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3733 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3734 phy_c11 = phy_c15 + k;
3735 phy_c12 = phy_c16 + l;
3736
3737 if (phy_c11 < -phy_c10)
3738 phy_c11 = -phy_c10;
3739 else if (phy_c11 > phy_c10)
3740 phy_c11 = phy_c10;
3741 if (phy_c12 < -phy_c10)
3742 phy_c12 = -phy_c10;
3743 else if (phy_c12 > phy_c10)
3744 phy_c12 = phy_c10;
3745 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3746 phy_c12);
3747 udelay(20);
3748 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3749
3750 phy_c18 = 0;
3751 phy_c19 = 0;
3752 for (j = 0; j < 128; j++) {
3753 if (cal_type != 0)
3754 phy_c6 = j % phy_c4;
3755 else
3756 phy_c6 = (2 * j) % phy_c4;
3757
3758 phy_c2.re = phy_c1[phy_c6].re;
3759 phy_c2.im = phy_c1[phy_c6].im;
3760 phy_c17 = ptr[j];
3761 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3762 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3763 }
3764
3765 phy_c18 = phy_c18 >> 10;
3766 phy_c19 = phy_c19 >> 10;
3767 phy_c20 = ((phy_c18 * phy_c18) +
3768 (phy_c19 * phy_c19));
3769
3770 if (phy_c23 || phy_c20 < phy_c21) {
3771 phy_c21 = phy_c20;
3772 phy_c13 = phy_c11;
3773 phy_c14 = phy_c12;
3774 }
3db1cd5c 3775 phy_c23 = false;
5b435de0
AS
3776 }
3777 }
3db1cd5c 3778 phy_c23 = true;
5b435de0
AS
3779 phy_c15 = phy_c13;
3780 phy_c16 = phy_c14;
3781 phy_c7 = phy_c7 >> 1;
3782 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3783 udelay(20);
3784 }
3785 goto cleanup;
3786cleanup:
3787 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3788 wlc_lcnphy_stop_tx_tone(pi);
3789 write_phy_reg(pi, 0x6da, phy_c26);
3790 write_phy_reg(pi, 0x6db, phy_c27);
3791 write_phy_reg(pi, 0x938, phy_c28);
3792 write_phy_reg(pi, 0x4d7, phy_c29);
3793 write_phy_reg(pi, 0x4d8, phy_c30);
3794 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3795
3796 kfree(phy_c32);
3797 kfree(ptr);
3798}
3799
3800void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3801{
3802 u16 iqcc[2];
3803 struct phytbl_info tab;
3804
3805 tab.tbl_ptr = iqcc;
3806 tab.tbl_len = 2;
3807 tab.tbl_id = 0;
3808 tab.tbl_offset = 80;
3809 tab.tbl_width = 16;
3810 wlc_lcnphy_read_table(pi, &tab);
3811
3812 *a = iqcc[0];
3813 *b = iqcc[1];
3814}
3815
3816static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3817{
3818 struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3819
3820 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3821 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3822 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3823 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3824
3825 wlc_lcnphy_a1(pi, 4, 0, 0);
3826 wlc_lcnphy_a1(pi, 3, 0, 0);
3827 wlc_lcnphy_a1(pi, 2, 3, 2);
3828 wlc_lcnphy_a1(pi, 0, 5, 8);
3829 wlc_lcnphy_a1(pi, 2, 2, 1);
3830 wlc_lcnphy_a1(pi, 0, 4, 3);
3831
3832 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3833 locc2 = wlc_lcnphy_get_cc(pi, 2);
3834 locc3 = wlc_lcnphy_get_cc(pi, 3);
3835 locc4 = wlc_lcnphy_get_cc(pi, 4);
3836}
3837
3838u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3839{
3840 struct phytbl_info tab;
3841 u16 didq;
3842
3843 tab.tbl_id = 0;
3844 tab.tbl_width = 16;
3845 tab.tbl_ptr = &didq;
3846 tab.tbl_len = 1;
3847 tab.tbl_offset = 85;
3848 wlc_lcnphy_read_table(pi, &tab);
3849
3850 return didq;
3851}
3852
3853static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3854{
3855
3856 struct lcnphy_txgains target_gains, old_gains;
3857 u8 save_bb_mult;
3858 u16 a, b, didq, save_pa_gain = 0;
3859 uint idx, SAVE_txpwrindex = 0xFF;
3860 u32 val;
3861 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3862 struct phytbl_info tab;
3863 u8 ei0, eq0, fi0, fq0;
3864 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3865
3866 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3867 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3868
3869 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3870
3871 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3872 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3873
3874 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3875
3876 target_gains.gm_gain = 7;
3877 target_gains.pga_gain = 0;
3878 target_gains.pad_gain = 21;
3879 target_gains.dac_gain = 0;
3880 wlc_lcnphy_set_tx_gain(pi, &target_gains);
3881 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3882
3883 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3884
3885 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3886
3887 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3888 (pi_lcn->
3889 lcnphy_recal ? LCNPHY_CAL_RECAL :
3890 LCNPHY_CAL_FULL), false);
3891 } else {
3892 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3893 }
3894
3895 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3896 if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3897 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3898 target_gains.gm_gain = 255;
3899 target_gains.pga_gain = 255;
3900 target_gains.pad_gain = 0xf0;
3901 target_gains.dac_gain = 0;
3902 } else {
3903 target_gains.gm_gain = 7;
3904 target_gains.pga_gain = 45;
3905 target_gains.pad_gain = 186;
3906 target_gains.dac_gain = 0;
3907 }
3908
3909 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3910 || pi_lcn->lcnphy_hw_iqcal_en) {
3911
3912 target_gains.pga_gain = 0;
3913 target_gains.pad_gain = 30;
3914 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3915 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3916 LCNPHY_CAL_FULL, false);
3917 } else {
3918 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3919 }
3920 }
3921
3922 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3923
3924 didq = wlc_lcnphy_get_tx_locc(pi);
3925
3926 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3927 tab.tbl_width = 32;
3928 tab.tbl_ptr = &val;
3929
3930 tab.tbl_len = 1;
3931 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3932
3933 for (idx = 0; idx < 128; idx++) {
3934 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3935
3936 wlc_lcnphy_read_table(pi, &tab);
3937 val = (val & 0xfff00000) |
3938 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3939 wlc_lcnphy_write_table(pi, &tab);
3940
3941 val = didq;
3942 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
3943 wlc_lcnphy_write_table(pi, &tab);
3944 }
3945
3946 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
3947 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
3948 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
3949 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
3950 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
3951 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
3952 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
3953
3954 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
3955 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
3956 wlc_lcnphy_set_tx_gain(pi, &old_gains);
3957
3958 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
3959 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3960 else
3961 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
3962}
3963
3964s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
3965{
3966 u16 tempsenseval1, tempsenseval2;
3967 s16 avg = 0;
3db1cd5c 3968 bool suspend = false;
5b435de0
AS
3969
3970 if (mode == 1) {
4b006b11
AS
3971 suspend = (0 == (bcma_read32(pi->d11core,
3972 D11REGOFFS(maccontrol)) &
3973 MCTL_EN_MAC));
5b435de0
AS
3974 if (!suspend)
3975 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3976 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3977 }
3978 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3979 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3980
3981 if (tempsenseval1 > 255)
3982 avg = (s16) (tempsenseval1 - 512);
3983 else
3984 avg = (s16) tempsenseval1;
3985
3986 if (tempsenseval2 > 255)
3987 avg += (s16) (tempsenseval2 - 512);
3988 else
3989 avg += (s16) tempsenseval2;
3990
3991 avg /= 2;
3992
3993 if (mode == 1) {
3994
3995 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3996
3997 udelay(100);
3998 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
3999
4000 if (!suspend)
4001 wlapi_enable_mac(pi->sh->physhim);
4002 }
4003 return avg;
4004}
4005
4006u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4007{
4008 u16 tempsenseval1, tempsenseval2;
4009 s32 avg = 0;
3db1cd5c 4010 bool suspend = false;
5b435de0
AS
4011 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4012 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4013
4014 if (mode == 1) {
4b006b11
AS
4015 suspend = (0 == (bcma_read32(pi->d11core,
4016 D11REGOFFS(maccontrol)) &
4017 MCTL_EN_MAC));
5b435de0
AS
4018 if (!suspend)
4019 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4020 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4021 }
4022 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4023 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4024
4025 if (tempsenseval1 > 255)
4026 avg = (int)(tempsenseval1 - 512);
4027 else
4028 avg = (int)tempsenseval1;
4029
4030 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4031 if (tempsenseval2 > 255)
4032 avg = (int)(avg - tempsenseval2 + 512);
4033 else
4034 avg = (int)(avg - tempsenseval2);
4035 } else {
4036 if (tempsenseval2 > 255)
4037 avg = (int)(avg + tempsenseval2 - 512);
4038 else
4039 avg = (int)(avg + tempsenseval2);
4040 avg = avg / 2;
4041 }
4042 if (avg < 0)
4043 avg = avg + 512;
4044
4045 if (pi_lcn->lcnphy_tempsense_option == 2)
4046 avg = tempsenseval1;
4047
4048 if (mode)
4049 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4050
4051 if (mode == 1) {
4052
4053 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4054
4055 udelay(100);
4056 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4057
4058 if (!suspend)
4059 wlapi_enable_mac(pi->sh->physhim);
4060 }
4061 return (u16) avg;
4062}
4063
4064s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4065{
4066 s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4067 degree =
4068 ((degree <<
4069 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4070 / LCN_TEMPSENSE_DEN;
4071 return (s8) degree;
4072}
4073
4074s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4075{
4076 u16 vbatsenseval;
4077 s32 avg = 0;
3db1cd5c 4078 bool suspend = false;
5b435de0
AS
4079
4080 if (mode == 1) {
4b006b11
AS
4081 suspend = (0 == (bcma_read32(pi->d11core,
4082 D11REGOFFS(maccontrol)) &
4083 MCTL_EN_MAC));
5b435de0
AS
4084 if (!suspend)
4085 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4086 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4087 }
4088
4089 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4090
4091 if (vbatsenseval > 255)
4092 avg = (s32) (vbatsenseval - 512);
4093 else
4094 avg = (s32) vbatsenseval;
4095
4096 avg = (avg * LCN_VBAT_SCALE_NOM +
4097 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4098
4099 if (mode == 1) {
4100 if (!suspend)
4101 wlapi_enable_mac(pi->sh->physhim);
4102 }
4103 return (s8) avg;
4104}
4105
4106static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4107{
4108 u8 phybw40;
4109 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4110
4111 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4112
4113 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4114 (mode == AFE_CLK_INIT_MODE_TXRX2X))
4115 write_phy_reg(pi, 0x6d0, 0x7);
4116
4117 wlc_lcnphy_toggle_afe_pwdn(pi);
4118}
4119
4120static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4121{
4122}
4123
4124static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4125{
4126 bool suspend;
4127 s8 index;
4128 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4129 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4b006b11
AS
4130 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4131 MCTL_EN_MAC));
5b435de0
AS
4132 if (!suspend)
4133 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4134 wlc_lcnphy_deaf_mode(pi, true);
4135 pi->phy_lastcal = pi->sh->now;
4136 pi->phy_forcecal = false;
4137 index = pi_lcn->lcnphy_current_index;
4138
4139 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4140
4141 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4142 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4143 wlc_lcnphy_deaf_mode(pi, false);
4144 if (!suspend)
4145 wlapi_enable_mac(pi->sh->physhim);
4146
4147}
4148
4149static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4150{
4151 bool suspend, full_cal;
4152 const struct lcnphy_rx_iqcomp *rx_iqcomp;
4153 int rx_iqcomp_sz;
4154 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4155 s8 index;
4156 struct phytbl_info tab;
4157 s32 a1, b0, b1;
4158 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4159 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4160
4161 pi->phy_lastcal = pi->sh->now;
4162 pi->phy_forcecal = false;
4163 full_cal =
4164 (pi_lcn->lcnphy_full_cal_channel !=
4165 CHSPEC_CHANNEL(pi->radio_chanspec));
4166 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4167 index = pi_lcn->lcnphy_current_index;
4168
4b006b11
AS
4169 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4170 MCTL_EN_MAC));
5b435de0
AS
4171 if (!suspend) {
4172 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4173 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4174 }
4175
4176 wlc_lcnphy_deaf_mode(pi, true);
4177
4178 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4179
4180 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4181 rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4182
4183 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4184 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4185 else
4186 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4187
4188 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4189
4190 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4191
4192 b0 = pi->txpa_2g[0];
4193 b1 = pi->txpa_2g[1];
4194 a1 = pi->txpa_2g[2];
4195 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4196 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4197
4198 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4199 tab.tbl_width = 32;
4200 tab.tbl_ptr = &pwr;
4201 tab.tbl_len = 1;
4202 tab.tbl_offset = 0;
4203 for (tssi = 0; tssi < 128; tssi++) {
4204 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4205 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4206 wlc_lcnphy_write_table(pi, &tab);
4207 tab.tbl_offset++;
4208 }
4209 }
4210
4211 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4212 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4213 wlc_lcnphy_deaf_mode(pi, false);
4214 if (!suspend)
4215 wlapi_enable_mac(pi->sh->physhim);
4216}
4217
4218void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4219{
4220 u16 temp_new;
4221 int temp1, temp2, temp_diff;
4222 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4223
4224 switch (mode) {
4225 case PHY_PERICAL_CHAN:
4226 break;
4227 case PHY_FULLCAL:
4228 wlc_lcnphy_periodic_cal(pi);
4229 break;
4230 case PHY_PERICAL_PHYINIT:
4231 wlc_lcnphy_periodic_cal(pi);
4232 break;
4233 case PHY_PERICAL_WATCHDOG:
4234 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4235 temp_new = wlc_lcnphy_tempsense(pi, 0);
4236 temp1 = LCNPHY_TEMPSENSE(temp_new);
4237 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4238 temp_diff = temp1 - temp2;
4239 if ((pi_lcn->lcnphy_cal_counter > 90) ||
4240 (temp_diff > 60) || (temp_diff < -60)) {
4241 wlc_lcnphy_glacial_timer_based_cal(pi);
4242 wlc_2064_vco_cal(pi);
4243 pi_lcn->lcnphy_cal_temper = temp_new;
4244 pi_lcn->lcnphy_cal_counter = 0;
4245 } else
4246 pi_lcn->lcnphy_cal_counter++;
4247 }
4248 break;
4249 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4250 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4251 wlc_lcnphy_tx_power_adjustment(
4252 (struct brcms_phy_pub *) pi);
4253 break;
4254 }
4255}
4256
4257void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4258{
4259 s8 cck_offset;
4260 u16 status;
4261 status = (read_phy_reg(pi, 0x4ab));
4262 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4263 (status & (0x1 << 15))) {
4264 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4265 >> 0) >> 1);
4266
4267 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4268 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4269 else
4270 cck_offset = 0;
4271
4272 *cck_pwr = *ofdm_pwr + cck_offset;
4273 } else {
4274 *cck_pwr = 0;
4275 *ofdm_pwr = 0;
4276 }
4277}
4278
4279void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4280{
4281 return;
4282
4283}
4284
4285void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4286{
4287 s8 index;
4288 u16 index2;
4289 struct brcms_phy *pi = (struct brcms_phy *) ppi;
4290 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4291 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4292 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4293 SAVE_txpwrctrl) {
4294 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4295 index2 = (u16) (index * 2);
4296 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4297
4298 pi_lcn->lcnphy_current_index =
4299 (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4300 }
4301}
4302
4303static void
4304wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4305 const struct lcnphy_tx_gain_tbl_entry *gain_table)
4306{
4307 u32 j;
4308 struct phytbl_info tab;
4309 u32 val;
4310 u16 pa_gain;
4311 u16 gm_gain;
4312
4313 if (CHSPEC_IS5G(pi->radio_chanspec))
4314 pa_gain = 0x70;
4315 else
4316 pa_gain = 0x70;
4317
4318 if (pi->sh->boardflags & BFL_FEM)
4319 pa_gain = 0x10;
4320 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4321 tab.tbl_width = 32;
4322 tab.tbl_len = 1;
4323 tab.tbl_ptr = &val;
4324
4325 for (j = 0; j < 128; j++) {
4326 gm_gain = gain_table[j].gm;
4327 val = (((u32) pa_gain << 24) |
4328 (gain_table[j].pad << 16) |
4329 (gain_table[j].pga << 8) | gm_gain);
4330
4331 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4332 wlc_lcnphy_write_table(pi, &tab);
4333
4334 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4335 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4336 wlc_lcnphy_write_table(pi, &tab);
4337 }
4338}
4339
4340static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4341{
4342 struct phytbl_info tab;
4343 u32 val, bbmult, rfgain;
4344 u8 index;
4345 u8 scale_factor = 1;
4346 s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4347
4348 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4349 tab.tbl_width = 32;
4350 tab.tbl_len = 1;
4351
4352 for (index = 0; index < 128; index++) {
4353 tab.tbl_ptr = &bbmult;
4354 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4355 wlc_lcnphy_read_table(pi, &tab);
4356 bbmult = bbmult >> 20;
4357
4358 tab.tbl_ptr = &rfgain;
4359 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4360 wlc_lcnphy_read_table(pi, &tab);
4361
4362 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4363 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4364
4365 if (qQ1 < qQ2) {
4366 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4367 qQ = qQ1;
4368 } else {
4369 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4370 qQ = qQ2;
4371 }
4372 temp = qm_sub16(temp1, temp2);
4373
4374 if (qQ >= 4)
4375 shift = qQ - 4;
4376 else
4377 shift = 4 - qQ;
4378
4379 val = (((index << shift) + (5 * temp) +
4380 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4381 shift - 2));
4382
4383 tab.tbl_ptr = &val;
4384 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4385 wlc_lcnphy_write_table(pi, &tab);
4386 }
4387}
4388
4389static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4390{
4391 or_phy_reg(pi, 0x805, 0x1);
4392
4393 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4394
4395 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4396
4397 write_phy_reg(pi, 0x414, 0x1e10);
4398 write_phy_reg(pi, 0x415, 0x0640);
4399
4400 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4401
4402 or_phy_reg(pi, 0x44a, 0x44);
4403 write_phy_reg(pi, 0x44a, 0x80);
4404 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4405
4406 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4407
4408 if (!(pi->sh->boardrev < 0x1204))
4409 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4410
4411 write_phy_reg(pi, 0x7d6, 0x0902);
4412 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4413
4414 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4415
4416 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4417 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4418
4419 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4420
4421 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4422
4423 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4424
4425 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4426
4427 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4428 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4429 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4430 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4431 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4432
4433 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4434
4435 wlc_lcnphy_clear_tx_power_offsets(pi);
4436 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4437
4438 }
4439}
4440
4441static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4442{
4443 u8 rcal_value;
4444
4445 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4446
4447 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4448 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4449
4450 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4451 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4452
4453 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4454
4455 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4456 mdelay(5);
4457 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4458
4459 if (wlc_radio_2064_rcal_done(pi)) {
4460 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4461 rcal_value = rcal_value & 0x1f;
4462 }
4463
4464 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4465
4466 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4467}
4468
4469static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4470{
4471 u8 dflt_rc_cal_val;
4472 u16 flt_val;
4473
4474 dflt_rc_cal_val = 7;
4475 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4476 dflt_rc_cal_val = 11;
4477 flt_val =
4478 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4479 (dflt_rc_cal_val);
4480 write_phy_reg(pi, 0x933, flt_val);
4481 write_phy_reg(pi, 0x934, flt_val);
4482 write_phy_reg(pi, 0x935, flt_val);
4483 write_phy_reg(pi, 0x936, flt_val);
4484 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4485
4486 return;
4487}
4488
4489static void wlc_radio_2064_init(struct brcms_phy *pi)
4490{
4491 u32 i;
4492 const struct lcnphy_radio_regs *lcnphyregs = NULL;
4493
4494 lcnphyregs = lcnphy_radio_regs_2064;
4495
4496 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4497 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4498 write_radio_reg(pi,
4499 ((lcnphyregs[i].address & 0x3fff) |
4500 RADIO_DEFAULT_CORE),
4501 (u16) lcnphyregs[i].init_a);
4502 else if (lcnphyregs[i].do_init_g)
4503 write_radio_reg(pi,
4504 ((lcnphyregs[i].address & 0x3fff) |
4505 RADIO_DEFAULT_CORE),
4506 (u16) lcnphyregs[i].init_g);
4507
4508 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4509 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4510
4511 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4512
4513 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4514
4515 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4516
4517 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4518 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4519 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4520 }
4521
4522 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4523 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4524
4525 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4526
4527 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4528
4529 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4530
4531 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4532
4533 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4534
4535 write_phy_reg(pi, 0x4ea, 0x4688);
4536
4537 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4538
4539 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4540
4541 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4542
4543 wlc_lcnphy_set_tx_locc(pi, 0);
4544
4545 wlc_lcnphy_rcal(pi);
4546
4547 wlc_lcnphy_rc_cal(pi);
4548}
4549
4550static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4551{
4552 wlc_radio_2064_init(pi);
4553}
4554
4555static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4556{
4557 uint idx;
4558 u8 phybw40;
4559 struct phytbl_info tab;
4560 u32 val;
4561
4562 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4563
4564 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4565 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4566
4567 if (pi->sh->boardflags & BFL_FEM_BT) {
4568 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4569 tab.tbl_width = 16;
4570 tab.tbl_ptr = &val;
4571 tab.tbl_len = 1;
4572 val = 100;
4573 tab.tbl_offset = 4;
4574 wlc_lcnphy_write_table(pi, &tab);
4575 }
4576
4577 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4578 tab.tbl_width = 16;
4579 tab.tbl_ptr = &val;
4580 tab.tbl_len = 1;
4581
4582 val = 114;
4583 tab.tbl_offset = 0;
4584 wlc_lcnphy_write_table(pi, &tab);
4585
4586 val = 130;
4587 tab.tbl_offset = 1;
4588 wlc_lcnphy_write_table(pi, &tab);
4589
4590 val = 6;
4591 tab.tbl_offset = 8;
4592 wlc_lcnphy_write_table(pi, &tab);
4593
4594 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4595 if (pi->sh->boardflags & BFL_FEM)
4596 wlc_lcnphy_load_tx_gain_table(
4597 pi,
4598 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4599 else
4600 wlc_lcnphy_load_tx_gain_table(
4601 pi,
4602 dot11lcnphy_2GHz_gaintable_rev0);
4603 }
4604
4605 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4606 const struct phytbl_info *tb;
4607 int l;
4608
4609 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4610 l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4611 if (pi->sh->boardflags & BFL_EXTLNA)
4612 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4613 else
4614 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4615 } else {
4616 l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4617 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4618 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4619 else
4620 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4621 }
4622
4623 for (idx = 0; idx < l; idx++)
4624 wlc_lcnphy_write_table(pi, &tb[idx]);
4625 }
4626
4627 if ((pi->sh->boardflags & BFL_FEM)
4628 && !(pi->sh->boardflags & BFL_FEM_BT))
4629 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4630 else if (pi->sh->boardflags & BFL_FEM_BT) {
4631 if (pi->sh->boardrev < 0x1250)
4632 wlc_lcnphy_write_table(
4633 pi,
4634 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4635 else
4636 wlc_lcnphy_write_table(
4637 pi,
4638 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4639 } else
4640 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4641
4642 wlc_lcnphy_load_rfpower(pi);
4643
4644 wlc_lcnphy_clear_papd_comptable(pi);
4645}
4646
4647static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4648{
4649 u16 afectrl1;
4650 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4651
4652 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4653
4654 write_phy_reg(pi, 0x43b, 0x0);
4655 write_phy_reg(pi, 0x43c, 0x0);
4656 write_phy_reg(pi, 0x44c, 0x0);
4657 write_phy_reg(pi, 0x4e6, 0x0);
4658 write_phy_reg(pi, 0x4f9, 0x0);
4659 write_phy_reg(pi, 0x4b0, 0x0);
4660 write_phy_reg(pi, 0x938, 0x0);
4661 write_phy_reg(pi, 0x4b0, 0x0);
4662 write_phy_reg(pi, 0x44e, 0);
4663
4664 or_phy_reg(pi, 0x567, 0x03);
4665
4666 or_phy_reg(pi, 0x44a, 0x44);
4667 write_phy_reg(pi, 0x44a, 0x80);
4668
4669 if (!(pi->sh->boardflags & BFL_FEM))
4670 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4671
4672 if (0) {
4673 afectrl1 = 0;
4674 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4675 (pi_lcn->lcnphy_rssi_vc << 4) |
4676 (pi_lcn->lcnphy_rssi_gs << 10));
4677 write_phy_reg(pi, 0x43e, afectrl1);
4678 }
4679
4680 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4681 if (pi->sh->boardflags & BFL_FEM) {
4682 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4683
4684 write_phy_reg(pi, 0x910, 0x1);
4685 }
4686
4687 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4688 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4689 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4690
4691}
4692
4693static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4694{
4695 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4696 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4697 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4698 }
4699}
4700
4701static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4702{
4703 s16 temp;
4704 struct phytbl_info tab;
4705 u32 tableBuffer[2];
4706 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4707
4708 temp = (s16) read_phy_reg(pi, 0x4df);
4709 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4710
4711 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4712 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4713
4714 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4715
4716 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4717 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4718
4719 tab.tbl_ptr = tableBuffer;
4720 tab.tbl_len = 2;
4721 tab.tbl_id = 17;
4722 tab.tbl_offset = 59;
4723 tab.tbl_width = 32;
4724 wlc_lcnphy_read_table(pi, &tab);
4725
4726 if (tableBuffer[0] > 63)
4727 tableBuffer[0] -= 128;
4728 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4729
4730 if (tableBuffer[1] > 63)
4731 tableBuffer[1] -= 128;
4732 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4733
4734 temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4735 if (temp > 127)
4736 temp -= 256;
4737 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4738
4739 pi_lcn->lcnphy_Med_Low_Gain_db =
4740 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4741 pi_lcn->lcnphy_Very_Low_Gain_db =
4742 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4743
4744 tab.tbl_ptr = tableBuffer;
4745 tab.tbl_len = 2;
4746 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4747 tab.tbl_offset = 28;
4748 tab.tbl_width = 32;
4749 wlc_lcnphy_read_table(pi, &tab);
4750
4751 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4752 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4753
4754}
4755
4756static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4757{
4758
4759 wlc_lcnphy_tbl_init(pi);
4760 wlc_lcnphy_rev0_baseband_init(pi);
4761 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4762 wlc_lcnphy_rev2_baseband_init(pi);
4763 wlc_lcnphy_bu_tweaks(pi);
4764}
4765
4766void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4767{
4768 u8 phybw40;
4769 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4770 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4771
4772 pi_lcn->lcnphy_cal_counter = 0;
4773 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4774
4775 or_phy_reg(pi, 0x44a, 0x80);
4776 and_phy_reg(pi, 0x44a, 0x7f);
4777
4778 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4779
4780 write_phy_reg(pi, 0x60a, 160);
4781
4782 write_phy_reg(pi, 0x46a, 25);
4783
4784 wlc_lcnphy_baseband_init(pi);
4785
4786 wlc_lcnphy_radio_init(pi);
4787
4788 if (CHSPEC_IS2G(pi->radio_chanspec))
4789 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4790
4791 wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4792
4793 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
4794
4795 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
4796
4797 if ((pi->sh->boardflags & BFL_FEM)
4798 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4799 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4800
4801 wlc_lcnphy_agc_temp_init(pi);
4802
4803 wlc_lcnphy_temp_adj(pi);
4804
4805 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4806
4807 udelay(100);
4808 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4809
4810 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4811 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4812 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4813}
4814
4815static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4816{
4817 s8 txpwr = 0;
4818 int i;
4819 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
898d3c3b 4820 struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
5b435de0
AS
4821
4822 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4823 u16 cckpo = 0;
4824 u32 offset_ofdm, offset_mcs;
4825
898d3c3b 4826 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
5b435de0 4827
898d3c3b 4828 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
5b435de0 4829
898d3c3b
HM
4830 pi->txpa_2g[0] = sprom->pa0b0;
4831 pi->txpa_2g[1] = sprom->pa0b1;
4832 pi->txpa_2g[2] = sprom->pa0b2;
5b435de0 4833
898d3c3b
HM
4834 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4835 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4836 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
5b435de0
AS
4837
4838 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4839 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4840 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4841
4842 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4843 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4844 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4845
898d3c3b 4846 txpwr = sprom->core_pwr_info[0].maxpwr_2g;
5b435de0
AS
4847 pi->tx_srom_max_2g = txpwr;
4848
4849 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4850 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4851 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4852 }
4853
898d3c3b
HM
4854 cckpo = sprom->cck2gpo;
4855 offset_ofdm = sprom->ofdm2gpo;
5b435de0
AS
4856 if (cckpo) {
4857 uint max_pwr_chan = txpwr;
4858
4859 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4860 pi->tx_srom_max_rate_2g[i] =
4861 max_pwr_chan - ((cckpo & 0xf) * 2);
4862 cckpo >>= 4;
4863 }
4864
4865 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4866 pi->tx_srom_max_rate_2g[i] =
4867 max_pwr_chan -
4868 ((offset_ofdm & 0xf) * 2);
4869 offset_ofdm >>= 4;
4870 }
4871 } else {
4872 u8 opo = 0;
4873
898d3c3b 4874 opo = sprom->opo;
5b435de0
AS
4875
4876 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4877 pi->tx_srom_max_rate_2g[i] = txpwr;
4878
4879 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4880 pi->tx_srom_max_rate_2g[i] = txpwr -
4881 ((offset_ofdm & 0xf) * 2);
4882 offset_ofdm >>= 4;
4883 }
898d3c3b
HM
4884 offset_mcs = sprom->mcs2gpo[1] << 16;
4885 offset_mcs |= sprom->mcs2gpo[0];
5b435de0
AS
4886 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4887 for (i = TXP_FIRST_SISO_MCS_20;
4888 i <= TXP_LAST_SISO_MCS_20; i++) {
4889 pi->tx_srom_max_rate_2g[i] =
4890 txpwr - ((offset_mcs & 0xf) * 2);
4891 offset_mcs >>= 4;
4892 }
4893 }
4894
898d3c3b
HM
4895 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4896 pi_lcn->lcnphy_measPower = sprom->measpower;
4897 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4898 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4899 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4900 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4901 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4902 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4903 if (sprom->ant_available_bg > 1)
5b435de0 4904 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
898d3c3b 4905 sprom->ant_available_bg);
5b435de0
AS
4906 }
4907 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4908
4909 return true;
4910}
4911
4912void wlc_2064_vco_cal(struct brcms_phy *pi)
4913{
4914 u8 calnrst;
4915
4916 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4917 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4918 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4919 udelay(1);
4920 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4921 udelay(1);
4922 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4923 udelay(300);
4924 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4925}
4926
4927bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4928{
4929 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4930 return 0;
4931 else
4932 return (LCNPHY_TX_PWR_CTRL_HW ==
4933 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
4934}
4935
4936void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
4937{
4938 u16 pwr_ctrl;
4939 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4940 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
4941 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4942 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4943 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
4944 wlc_lcnphy_txpower_recalc_target(pi);
4945 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
4946 }
4947}
4948
4949void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
4950{
4951 kfree(pi->u.pi_lcnphy);
4952}
4953
4954bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
4955{
4956 struct brcms_phy_lcnphy *pi_lcn;
4957
4958 pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
4959 if (pi->u.pi_lcnphy == NULL)
4960 return false;
4961
4962 pi_lcn = pi->u.pi_lcnphy;
4963
4964 if (0 == (pi->sh->boardflags & BFL_NOPA)) {
4965 pi->hwpwrctrl = true;
4966 pi->hwpwrctrl_capable = true;
4967 }
4968
4969 pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
4970 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
4971
4972 pi->pi_fptr.init = wlc_phy_init_lcnphy;
4973 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
4974 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
4975 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
4976 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
4977 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
4978 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
4979 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
4980 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
4981
4982 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
4983 return false;
4984
4985 if ((pi->sh->boardflags & BFL_FEM) &&
4986 (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
4987 if (pi_lcn->lcnphy_tempsense_option == 3) {
4988 pi->hwpwrctrl = true;
4989 pi->hwpwrctrl_capable = true;
4990 pi->temppwrctrl_capable = false;
4991 } else {
4992 pi->hwpwrctrl = false;
4993 pi->hwpwrctrl_capable = false;
4994 pi->temppwrctrl_capable = true;
4995 }
4996 }
4997
4998 return true;
4999}
5000
5001static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5002{
5003 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5004
5005 trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5006 ext_lna = (u16) (gain >> 29) & 0x01;
5007 lna1 = (u16) (gain >> 0) & 0x0f;
5008 lna2 = (u16) (gain >> 4) & 0x0f;
5009 tia = (u16) (gain >> 8) & 0xf;
5010 biq0 = (u16) (gain >> 12) & 0xf;
5011 biq1 = (u16) (gain >> 16) & 0xf;
5012
5013 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5014 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5015 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5016 gain16_19 = biq1;
5017
5018 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5019 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5020 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5021 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5022 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5023
5024 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5025 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5026 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5027 }
5028 wlc_lcnphy_rx_gain_override_enable(pi, true);
5029}
5030
5031static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5032{
5033 u32 received_power = 0;
5034 s32 max_index = 0;
5035 u32 gain_code = 0;
5036 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5037
5038 max_index = 36;
5039 if (*gain_index >= 0)
5040 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5041
5042 if (-1 == *gain_index) {
5043 *gain_index = 0;
5044 while ((*gain_index <= (s32) max_index)
5045 && (received_power < 700)) {
5046 wlc_lcnphy_set_rx_gain(pi,
5047 lcnphy_23bitgaincode_table
5048 [*gain_index]);
5049 received_power =
5050 wlc_lcnphy_measure_digital_power(
5051 pi,
5052 pi_lcn->
5053 lcnphy_noise_samples);
5054 (*gain_index)++;
5055 }
5056 (*gain_index)--;
5057 } else {
5058 wlc_lcnphy_set_rx_gain(pi, gain_code);
5059 received_power =
5060 wlc_lcnphy_measure_digital_power(pi,
5061 pi_lcn->
5062 lcnphy_noise_samples);
5063 }
5064
5065 return received_power;
5066}
5067
5068s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5069{
5070 s32 gain = 0;
5071 s32 nominal_power_db;
5072 s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5073 input_power_db;
5074 s32 received_power, temperature;
5075 u32 power;
5076 u32 msb1, msb2, val1, val2, diff1, diff2;
5077 uint freq;
5078 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5079
5080 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5081
5082 gain = lcnphy_gain_table[gain_index];
5083
5084 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5085
5086 power = (received_power * 16);
5087 msb1 = ffs(power) - 1;
5088 msb2 = msb1 + 1;
5089 val1 = 1 << msb1;
5090 val2 = 1 << msb2;
5091 diff1 = (power - val1);
5092 diff2 = (val2 - power);
5093 if (diff1 < diff2)
5094 log_val = msb1;
5095 else
5096 log_val = msb2;
5097
5098 log_val = log_val * 3;
5099
5100 gain_mismatch = (nominal_power_db / 2) - (log_val);
5101
5102 desired_gain = gain + gain_mismatch;
5103
5104 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5105
5106 if (input_power_offset_db > 127)
5107 input_power_offset_db -= 256;
5108
5109 input_power_db = input_power_offset_db - desired_gain;
5110
5111 input_power_db =
5112 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5113
5114 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5115 if ((freq > 2427) && (freq <= 2467))
5116 input_power_db = input_power_db - 1;
5117
5118 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5119
5120 if ((temperature - 15) < -30)
5121 input_power_db =
5122 input_power_db +
5123 (((temperature - 10 - 25) * 286) >> 12) -
5124 7;
5125 else if ((temperature - 15) < 4)
5126 input_power_db =
5127 input_power_db +
5128 (((temperature - 10 - 25) * 286) >> 12) -
5129 3;
5130 else
5131 input_power_db = input_power_db +
5132 (((temperature - 10 - 25) * 286) >> 12);
5133
5134 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5135
5136 return input_power_db;
5137}
This page took 0.274674 seconds and 5 git commands to generate.