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