spi-topcliff-pch: supports a spi mode setup and bit order setup by IO control
[zen-stable.git] / drivers / net / wireless / brcm80211 / brcmsmac / phy / phy_lcn.c
blobce8562aa5db0bee06c59244ef9c3099b6cf58c81
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/kernel.h>
18 #include <linux/delay.h>
19 #include <linux/cordic.h>
21 #include <pmu.h>
22 #include <d11.h>
23 #include <phy_shim.h>
24 #include "phy_qmath.h"
25 #include "phy_hal.h"
26 #include "phy_radio.h"
27 #include "phytbl_lcn.h"
28 #include "phy_lcn.h"
30 #define PLL_2064_NDIV 90
31 #define PLL_2064_LOW_END_VCO 3000
32 #define PLL_2064_LOW_END_KVCO 27
33 #define PLL_2064_HIGH_END_VCO 4200
34 #define PLL_2064_HIGH_END_KVCO 68
35 #define PLL_2064_LOOP_BW_DOUBLER 200
36 #define PLL_2064_D30_DOUBLER 10500
37 #define PLL_2064_LOOP_BW 260
38 #define PLL_2064_D30 8000
39 #define PLL_2064_CAL_REF_TO 8
40 #define PLL_2064_MHZ 1000000
41 #define PLL_2064_OPEN_LOOP_DELAY 5
43 #define TEMPSENSE 1
44 #define VBATSENSE 2
46 #define NOISE_IF_UPD_CHK_INTERVAL 1
47 #define NOISE_IF_UPD_RST_INTERVAL 60
48 #define NOISE_IF_UPD_THRESHOLD_CNT 1
49 #define NOISE_IF_UPD_TRHRESHOLD 50
50 #define NOISE_IF_UPD_TIMEOUT 1000
51 #define NOISE_IF_OFF 0
52 #define NOISE_IF_CHK 1
53 #define NOISE_IF_ON 2
55 #define PAPD_BLANKING_PROFILE 3
56 #define PAPD2LUT 0
57 #define PAPD_CORR_NORM 0
58 #define PAPD_BLANKING_THRESHOLD 0
59 #define PAPD_STOP_AFTER_LAST_UPDATE 0
61 #define LCN_TARGET_PWR 60
63 #define LCN_VBAT_OFFSET_433X 34649679
64 #define LCN_VBAT_SLOPE_433X 8258032
66 #define LCN_VBAT_SCALE_NOM 53
67 #define LCN_VBAT_SCALE_DEN 432
69 #define LCN_TEMPSENSE_OFFSET 80812
70 #define LCN_TEMPSENSE_DEN 2647
72 #define LCN_BW_LMT 200
73 #define LCN_CUR_LMT 1250
74 #define LCN_MULT 1
75 #define LCN_VCO_DIV 30
76 #define LCN_OFFSET 680
77 #define LCN_FACT 490
78 #define LCN_CUR_DIV 2640
80 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
81 (0 + 8)
82 #define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
83 (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
85 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
86 (0 + 8)
87 #define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
88 (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
90 #define wlc_lcnphy_enable_tx_gain_override(pi) \
91 wlc_lcnphy_set_tx_gain_override(pi, true)
92 #define wlc_lcnphy_disable_tx_gain_override(pi) \
93 wlc_lcnphy_set_tx_gain_override(pi, false)
95 #define wlc_lcnphy_iqcal_active(pi) \
96 (read_phy_reg((pi), 0x451) & \
97 ((0x1 << 15) | (0x1 << 14)))
99 #define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
100 #define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
101 (pi->temppwrctrl_capable)
102 #define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
103 (pi->hwpwrctrl_capable)
105 #define SWCTRL_BT_TX 0x18
106 #define SWCTRL_OVR_DISABLE 0x40
108 #define AFE_CLK_INIT_MODE_TXRX2X 1
109 #define AFE_CLK_INIT_MODE_PAPD 0
111 #define LCNPHY_TBL_ID_IQLOCAL 0x00
113 #define LCNPHY_TBL_ID_RFSEQ 0x08
114 #define LCNPHY_TBL_ID_GAIN_IDX 0x0d
115 #define LCNPHY_TBL_ID_SW_CTRL 0x0f
116 #define LCNPHY_TBL_ID_GAIN_TBL 0x12
117 #define LCNPHY_TBL_ID_SPUR 0x14
118 #define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
119 #define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
121 #define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
122 #define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
123 #define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
124 #define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
125 #define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
126 #define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
128 #define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
130 #define LCNPHY_TX_PWR_CTRL_START_NPT 1
131 #define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
133 #define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
135 #define LCNPHY_ACI_DETECT_START 1
136 #define LCNPHY_ACI_DETECT_PROGRESS 2
137 #define LCNPHY_ACI_DETECT_STOP 3
139 #define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
140 #define LCNPHY_ACI_GLITCH_TRSH 2000
141 #define LCNPHY_ACI_TMOUT 250
142 #define LCNPHY_ACI_DETECT_TIMEOUT 2
143 #define LCNPHY_ACI_START_DELAY 0
145 #define wlc_lcnphy_tx_gain_override_enabled(pi) \
146 (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
148 #define wlc_lcnphy_total_tx_frames(pi) \
149 wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
150 offsetof(struct macstat, txallfrm))
152 struct lcnphy_txgains {
153 u16 gm_gain;
154 u16 pga_gain;
155 u16 pad_gain;
156 u16 dac_gain;
159 enum lcnphy_cal_mode {
160 LCNPHY_CAL_FULL,
161 LCNPHY_CAL_RECAL,
162 LCNPHY_CAL_CURRECAL,
163 LCNPHY_CAL_DIGCAL,
164 LCNPHY_CAL_GCTRL
167 struct lcnphy_rx_iqcomp {
168 u8 chan;
169 s16 a;
170 s16 b;
173 struct lcnphy_spb_tone {
174 s16 re;
175 s16 im;
178 struct lcnphy_unsign16_struct {
179 u16 re;
180 u16 im;
183 struct lcnphy_iq_est {
184 u32 iq_prod;
185 u32 i_pwr;
186 u32 q_pwr;
189 struct lcnphy_sfo_cfg {
190 u16 ptcentreTs20;
191 u16 ptcentreFactor;
194 enum lcnphy_papd_cal_type {
195 LCNPHY_PAPD_CAL_CW,
196 LCNPHY_PAPD_CAL_OFDM
199 typedef u16 iqcal_gain_params_lcnphy[9];
201 static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
202 {0, 0, 0, 0, 0, 0, 0, 0, 0},
205 static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
206 tbl_iqcal_gainparams_lcnphy_2G,
209 static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
210 sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
211 sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
214 static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
215 {965, 1087},
216 {967, 1085},
217 {969, 1082},
218 {971, 1080},
219 {973, 1078},
220 {975, 1076},
221 {977, 1073},
222 {979, 1071},
223 {981, 1069},
224 {983, 1067},
225 {985, 1065},
226 {987, 1063},
227 {989, 1060},
228 {994, 1055}
231 static const
232 u16 lcnphy_iqcal_loft_gainladder[] = {
233 ((2 << 8) | 0),
234 ((3 << 8) | 0),
235 ((4 << 8) | 0),
236 ((6 << 8) | 0),
237 ((8 << 8) | 0),
238 ((11 << 8) | 0),
239 ((16 << 8) | 0),
240 ((16 << 8) | 1),
241 ((16 << 8) | 2),
242 ((16 << 8) | 3),
243 ((16 << 8) | 4),
244 ((16 << 8) | 5),
245 ((16 << 8) | 6),
246 ((16 << 8) | 7),
247 ((23 << 8) | 7),
248 ((32 << 8) | 7),
249 ((45 << 8) | 7),
250 ((64 << 8) | 7),
251 ((91 << 8) | 7),
252 ((128 << 8) | 7)
255 static const
256 u16 lcnphy_iqcal_ir_gainladder[] = {
257 ((1 << 8) | 0),
258 ((2 << 8) | 0),
259 ((4 << 8) | 0),
260 ((6 << 8) | 0),
261 ((8 << 8) | 0),
262 ((11 << 8) | 0),
263 ((16 << 8) | 0),
264 ((23 << 8) | 0),
265 ((32 << 8) | 0),
266 ((45 << 8) | 0),
267 ((64 << 8) | 0),
268 ((64 << 8) | 1),
269 ((64 << 8) | 2),
270 ((64 << 8) | 3),
271 ((64 << 8) | 4),
272 ((64 << 8) | 5),
273 ((64 << 8) | 6),
274 ((64 << 8) | 7),
275 ((91 << 8) | 7),
276 ((128 << 8) | 7)
279 static const
280 struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
281 {88, 0},
282 {73, 49},
283 {34, 81},
284 {-17, 86},
285 {-62, 62},
286 {-86, 17},
287 {-81, -34},
288 {-49, -73},
289 {0, -88},
290 {49, -73},
291 {81, -34},
292 {86, 17},
293 {62, 62},
294 {17, 86},
295 {-34, 81},
296 {-73, 49},
297 {-88, 0},
298 {-73, -49},
299 {-34, -81},
300 {17, -86},
301 {62, -62},
302 {86, -17},
303 {81, 34},
304 {49, 73},
305 {0, 88},
306 {-49, 73},
307 {-81, 34},
308 {-86, -17},
309 {-62, -62},
310 {-17, -86},
311 {34, -81},
312 {73, -49},
315 static const
316 u16 iqlo_loopback_rf_regs[20] = {
317 RADIO_2064_REG036,
318 RADIO_2064_REG11A,
319 RADIO_2064_REG03A,
320 RADIO_2064_REG025,
321 RADIO_2064_REG028,
322 RADIO_2064_REG005,
323 RADIO_2064_REG112,
324 RADIO_2064_REG0FF,
325 RADIO_2064_REG11F,
326 RADIO_2064_REG00B,
327 RADIO_2064_REG113,
328 RADIO_2064_REG007,
329 RADIO_2064_REG0FC,
330 RADIO_2064_REG0FD,
331 RADIO_2064_REG012,
332 RADIO_2064_REG057,
333 RADIO_2064_REG059,
334 RADIO_2064_REG05C,
335 RADIO_2064_REG078,
336 RADIO_2064_REG092,
339 static const
340 u16 tempsense_phy_regs[14] = {
341 0x503,
342 0x4a4,
343 0x4d0,
344 0x4d9,
345 0x4da,
346 0x4a6,
347 0x938,
348 0x939,
349 0x4d8,
350 0x4d0,
351 0x4d7,
352 0x4a5,
353 0x40d,
354 0x4a2,
357 static const
358 u16 rxiq_cal_rf_reg[11] = {
359 RADIO_2064_REG098,
360 RADIO_2064_REG116,
361 RADIO_2064_REG12C,
362 RADIO_2064_REG06A,
363 RADIO_2064_REG00B,
364 RADIO_2064_REG01B,
365 RADIO_2064_REG113,
366 RADIO_2064_REG01D,
367 RADIO_2064_REG114,
368 RADIO_2064_REG02E,
369 RADIO_2064_REG12A,
372 static const
373 struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
374 {1, 0, 0},
375 {2, 0, 0},
376 {3, 0, 0},
377 {4, 0, 0},
378 {5, 0, 0},
379 {6, 0, 0},
380 {7, 0, 0},
381 {8, 0, 0},
382 {9, 0, 0},
383 {10, 0, 0},
384 {11, 0, 0},
385 {12, 0, 0},
386 {13, 0, 0},
387 {14, 0, 0},
388 {34, 0, 0},
389 {38, 0, 0},
390 {42, 0, 0},
391 {46, 0, 0},
392 {36, 0, 0},
393 {40, 0, 0},
394 {44, 0, 0},
395 {48, 0, 0},
396 {52, 0, 0},
397 {56, 0, 0},
398 {60, 0, 0},
399 {64, 0, 0},
400 {100, 0, 0},
401 {104, 0, 0},
402 {108, 0, 0},
403 {112, 0, 0},
404 {116, 0, 0},
405 {120, 0, 0},
406 {124, 0, 0},
407 {128, 0, 0},
408 {132, 0, 0},
409 {136, 0, 0},
410 {140, 0, 0},
411 {149, 0, 0},
412 {153, 0, 0},
413 {157, 0, 0},
414 {161, 0, 0},
415 {165, 0, 0},
416 {184, 0, 0},
417 {188, 0, 0},
418 {192, 0, 0},
419 {196, 0, 0},
420 {200, 0, 0},
421 {204, 0, 0},
422 {208, 0, 0},
423 {212, 0, 0},
424 {216, 0, 0},
427 static const u32 lcnphy_23bitgaincode_table[] = {
428 0x200100,
429 0x200200,
430 0x200004,
431 0x200014,
432 0x200024,
433 0x200034,
434 0x200134,
435 0x200234,
436 0x200334,
437 0x200434,
438 0x200037,
439 0x200137,
440 0x200237,
441 0x200337,
442 0x200437,
443 0x000035,
444 0x000135,
445 0x000235,
446 0x000037,
447 0x000137,
448 0x000237,
449 0x000337,
450 0x00013f,
451 0x00023f,
452 0x00033f,
453 0x00034f,
454 0x00044f,
455 0x00144f,
456 0x00244f,
457 0x00254f,
458 0x00354f,
459 0x00454f,
460 0x00464f,
461 0x01464f,
462 0x02464f,
463 0x03464f,
464 0x04464f,
467 static const s8 lcnphy_gain_table[] = {
468 -16,
469 -13,
507 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
548 struct chan_info_2064_lcnphy {
549 uint chan;
550 uint freq;
551 u8 logen_buftune;
552 u8 logen_rccr_tx;
553 u8 txrf_mix_tune_ctrl;
554 u8 pa_input_tune_g;
555 u8 logen_rccr_rx;
556 u8 pa_rxrf_lna1_freq_tune;
557 u8 pa_rxrf_lna2_freq_tune;
558 u8 rxrf_rxrf_spare1;
561 static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
562 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
563 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
564 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
565 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
566 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
567 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
575 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
578 static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
579 {0x00, 0, 0, 0, 0},
580 {0x01, 0x64, 0x64, 0, 0},
581 {0x02, 0x20, 0x20, 0, 0},
582 {0x03, 0x66, 0x66, 0, 0},
583 {0x04, 0xf8, 0xf8, 0, 0},
584 {0x05, 0, 0, 0, 0},
585 {0x06, 0x10, 0x10, 0, 0},
586 {0x07, 0, 0, 0, 0},
587 {0x08, 0, 0, 0, 0},
588 {0x09, 0, 0, 0, 0},
589 {0x0A, 0x37, 0x37, 0, 0},
590 {0x0B, 0x6, 0x6, 0, 0},
591 {0x0C, 0x55, 0x55, 0, 0},
592 {0x0D, 0x8b, 0x8b, 0, 0},
593 {0x0E, 0, 0, 0, 0},
594 {0x0F, 0x5, 0x5, 0, 0},
595 {0x10, 0, 0, 0, 0},
596 {0x11, 0xe, 0xe, 0, 0},
597 {0x12, 0, 0, 0, 0},
598 {0x13, 0xb, 0xb, 0, 0},
599 {0x14, 0x2, 0x2, 0, 0},
600 {0x15, 0x12, 0x12, 0, 0},
601 {0x16, 0x12, 0x12, 0, 0},
602 {0x17, 0xc, 0xc, 0, 0},
603 {0x18, 0xc, 0xc, 0, 0},
604 {0x19, 0xc, 0xc, 0, 0},
605 {0x1A, 0x8, 0x8, 0, 0},
606 {0x1B, 0x2, 0x2, 0, 0},
607 {0x1C, 0, 0, 0, 0},
608 {0x1D, 0x1, 0x1, 0, 0},
609 {0x1E, 0x12, 0x12, 0, 0},
610 {0x1F, 0x6e, 0x6e, 0, 0},
611 {0x20, 0x2, 0x2, 0, 0},
612 {0x21, 0x23, 0x23, 0, 0},
613 {0x22, 0x8, 0x8, 0, 0},
614 {0x23, 0, 0, 0, 0},
615 {0x24, 0, 0, 0, 0},
616 {0x25, 0xc, 0xc, 0, 0},
617 {0x26, 0x33, 0x33, 0, 0},
618 {0x27, 0x55, 0x55, 0, 0},
619 {0x28, 0, 0, 0, 0},
620 {0x29, 0x30, 0x30, 0, 0},
621 {0x2A, 0xb, 0xb, 0, 0},
622 {0x2B, 0x1b, 0x1b, 0, 0},
623 {0x2C, 0x3, 0x3, 0, 0},
624 {0x2D, 0x1b, 0x1b, 0, 0},
625 {0x2E, 0, 0, 0, 0},
626 {0x2F, 0x20, 0x20, 0, 0},
627 {0x30, 0xa, 0xa, 0, 0},
628 {0x31, 0, 0, 0, 0},
629 {0x32, 0x62, 0x62, 0, 0},
630 {0x33, 0x19, 0x19, 0, 0},
631 {0x34, 0x33, 0x33, 0, 0},
632 {0x35, 0x77, 0x77, 0, 0},
633 {0x36, 0, 0, 0, 0},
634 {0x37, 0x70, 0x70, 0, 0},
635 {0x38, 0x3, 0x3, 0, 0},
636 {0x39, 0xf, 0xf, 0, 0},
637 {0x3A, 0x6, 0x6, 0, 0},
638 {0x3B, 0xcf, 0xcf, 0, 0},
639 {0x3C, 0x1a, 0x1a, 0, 0},
640 {0x3D, 0x6, 0x6, 0, 0},
641 {0x3E, 0x42, 0x42, 0, 0},
642 {0x3F, 0, 0, 0, 0},
643 {0x40, 0xfb, 0xfb, 0, 0},
644 {0x41, 0x9a, 0x9a, 0, 0},
645 {0x42, 0x7a, 0x7a, 0, 0},
646 {0x43, 0x29, 0x29, 0, 0},
647 {0x44, 0, 0, 0, 0},
648 {0x45, 0x8, 0x8, 0, 0},
649 {0x46, 0xce, 0xce, 0, 0},
650 {0x47, 0x27, 0x27, 0, 0},
651 {0x48, 0x62, 0x62, 0, 0},
652 {0x49, 0x6, 0x6, 0, 0},
653 {0x4A, 0x58, 0x58, 0, 0},
654 {0x4B, 0xf7, 0xf7, 0, 0},
655 {0x4C, 0, 0, 0, 0},
656 {0x4D, 0xb3, 0xb3, 0, 0},
657 {0x4E, 0, 0, 0, 0},
658 {0x4F, 0x2, 0x2, 0, 0},
659 {0x50, 0, 0, 0, 0},
660 {0x51, 0x9, 0x9, 0, 0},
661 {0x52, 0x5, 0x5, 0, 0},
662 {0x53, 0x17, 0x17, 0, 0},
663 {0x54, 0x38, 0x38, 0, 0},
664 {0x55, 0, 0, 0, 0},
665 {0x56, 0, 0, 0, 0},
666 {0x57, 0xb, 0xb, 0, 0},
667 {0x58, 0, 0, 0, 0},
668 {0x59, 0, 0, 0, 0},
669 {0x5A, 0, 0, 0, 0},
670 {0x5B, 0, 0, 0, 0},
671 {0x5C, 0, 0, 0, 0},
672 {0x5D, 0, 0, 0, 0},
673 {0x5E, 0x88, 0x88, 0, 0},
674 {0x5F, 0xcc, 0xcc, 0, 0},
675 {0x60, 0x74, 0x74, 0, 0},
676 {0x61, 0x74, 0x74, 0, 0},
677 {0x62, 0x74, 0x74, 0, 0},
678 {0x63, 0x44, 0x44, 0, 0},
679 {0x64, 0x77, 0x77, 0, 0},
680 {0x65, 0x44, 0x44, 0, 0},
681 {0x66, 0x77, 0x77, 0, 0},
682 {0x67, 0x55, 0x55, 0, 0},
683 {0x68, 0x77, 0x77, 0, 0},
684 {0x69, 0x77, 0x77, 0, 0},
685 {0x6A, 0, 0, 0, 0},
686 {0x6B, 0x7f, 0x7f, 0, 0},
687 {0x6C, 0x8, 0x8, 0, 0},
688 {0x6D, 0, 0, 0, 0},
689 {0x6E, 0x88, 0x88, 0, 0},
690 {0x6F, 0x66, 0x66, 0, 0},
691 {0x70, 0x66, 0x66, 0, 0},
692 {0x71, 0x28, 0x28, 0, 0},
693 {0x72, 0x55, 0x55, 0, 0},
694 {0x73, 0x4, 0x4, 0, 0},
695 {0x74, 0, 0, 0, 0},
696 {0x75, 0, 0, 0, 0},
697 {0x76, 0, 0, 0, 0},
698 {0x77, 0x1, 0x1, 0, 0},
699 {0x78, 0xd6, 0xd6, 0, 0},
700 {0x79, 0, 0, 0, 0},
701 {0x7A, 0, 0, 0, 0},
702 {0x7B, 0, 0, 0, 0},
703 {0x7C, 0, 0, 0, 0},
704 {0x7D, 0, 0, 0, 0},
705 {0x7E, 0, 0, 0, 0},
706 {0x7F, 0, 0, 0, 0},
707 {0x80, 0, 0, 0, 0},
708 {0x81, 0, 0, 0, 0},
709 {0x82, 0, 0, 0, 0},
710 {0x83, 0xb4, 0xb4, 0, 0},
711 {0x84, 0x1, 0x1, 0, 0},
712 {0x85, 0x20, 0x20, 0, 0},
713 {0x86, 0x5, 0x5, 0, 0},
714 {0x87, 0xff, 0xff, 0, 0},
715 {0x88, 0x7, 0x7, 0, 0},
716 {0x89, 0x77, 0x77, 0, 0},
717 {0x8A, 0x77, 0x77, 0, 0},
718 {0x8B, 0x77, 0x77, 0, 0},
719 {0x8C, 0x77, 0x77, 0, 0},
720 {0x8D, 0x8, 0x8, 0, 0},
721 {0x8E, 0xa, 0xa, 0, 0},
722 {0x8F, 0x8, 0x8, 0, 0},
723 {0x90, 0x18, 0x18, 0, 0},
724 {0x91, 0x5, 0x5, 0, 0},
725 {0x92, 0x1f, 0x1f, 0, 0},
726 {0x93, 0x10, 0x10, 0, 0},
727 {0x94, 0x3, 0x3, 0, 0},
728 {0x95, 0, 0, 0, 0},
729 {0x96, 0, 0, 0, 0},
730 {0x97, 0xaa, 0xaa, 0, 0},
731 {0x98, 0, 0, 0, 0},
732 {0x99, 0x23, 0x23, 0, 0},
733 {0x9A, 0x7, 0x7, 0, 0},
734 {0x9B, 0xf, 0xf, 0, 0},
735 {0x9C, 0x10, 0x10, 0, 0},
736 {0x9D, 0x3, 0x3, 0, 0},
737 {0x9E, 0x4, 0x4, 0, 0},
738 {0x9F, 0x20, 0x20, 0, 0},
739 {0xA0, 0, 0, 0, 0},
740 {0xA1, 0, 0, 0, 0},
741 {0xA2, 0, 0, 0, 0},
742 {0xA3, 0, 0, 0, 0},
743 {0xA4, 0x1, 0x1, 0, 0},
744 {0xA5, 0x77, 0x77, 0, 0},
745 {0xA6, 0x77, 0x77, 0, 0},
746 {0xA7, 0x77, 0x77, 0, 0},
747 {0xA8, 0x77, 0x77, 0, 0},
748 {0xA9, 0x8c, 0x8c, 0, 0},
749 {0xAA, 0x88, 0x88, 0, 0},
750 {0xAB, 0x78, 0x78, 0, 0},
751 {0xAC, 0x57, 0x57, 0, 0},
752 {0xAD, 0x88, 0x88, 0, 0},
753 {0xAE, 0, 0, 0, 0},
754 {0xAF, 0x8, 0x8, 0, 0},
755 {0xB0, 0x88, 0x88, 0, 0},
756 {0xB1, 0, 0, 0, 0},
757 {0xB2, 0x1b, 0x1b, 0, 0},
758 {0xB3, 0x3, 0x3, 0, 0},
759 {0xB4, 0x24, 0x24, 0, 0},
760 {0xB5, 0x3, 0x3, 0, 0},
761 {0xB6, 0x1b, 0x1b, 0, 0},
762 {0xB7, 0x24, 0x24, 0, 0},
763 {0xB8, 0x3, 0x3, 0, 0},
764 {0xB9, 0, 0, 0, 0},
765 {0xBA, 0xaa, 0xaa, 0, 0},
766 {0xBB, 0, 0, 0, 0},
767 {0xBC, 0x4, 0x4, 0, 0},
768 {0xBD, 0, 0, 0, 0},
769 {0xBE, 0x8, 0x8, 0, 0},
770 {0xBF, 0x11, 0x11, 0, 0},
771 {0xC0, 0, 0, 0, 0},
772 {0xC1, 0, 0, 0, 0},
773 {0xC2, 0x62, 0x62, 0, 0},
774 {0xC3, 0x1e, 0x1e, 0, 0},
775 {0xC4, 0x33, 0x33, 0, 0},
776 {0xC5, 0x37, 0x37, 0, 0},
777 {0xC6, 0, 0, 0, 0},
778 {0xC7, 0x70, 0x70, 0, 0},
779 {0xC8, 0x1e, 0x1e, 0, 0},
780 {0xC9, 0x6, 0x6, 0, 0},
781 {0xCA, 0x4, 0x4, 0, 0},
782 {0xCB, 0x2f, 0x2f, 0, 0},
783 {0xCC, 0xf, 0xf, 0, 0},
784 {0xCD, 0, 0, 0, 0},
785 {0xCE, 0xff, 0xff, 0, 0},
786 {0xCF, 0x8, 0x8, 0, 0},
787 {0xD0, 0x3f, 0x3f, 0, 0},
788 {0xD1, 0x3f, 0x3f, 0, 0},
789 {0xD2, 0x3f, 0x3f, 0, 0},
790 {0xD3, 0, 0, 0, 0},
791 {0xD4, 0, 0, 0, 0},
792 {0xD5, 0, 0, 0, 0},
793 {0xD6, 0xcc, 0xcc, 0, 0},
794 {0xD7, 0, 0, 0, 0},
795 {0xD8, 0x8, 0x8, 0, 0},
796 {0xD9, 0x8, 0x8, 0, 0},
797 {0xDA, 0x8, 0x8, 0, 0},
798 {0xDB, 0x11, 0x11, 0, 0},
799 {0xDC, 0, 0, 0, 0},
800 {0xDD, 0x87, 0x87, 0, 0},
801 {0xDE, 0x88, 0x88, 0, 0},
802 {0xDF, 0x8, 0x8, 0, 0},
803 {0xE0, 0x8, 0x8, 0, 0},
804 {0xE1, 0x8, 0x8, 0, 0},
805 {0xE2, 0, 0, 0, 0},
806 {0xE3, 0, 0, 0, 0},
807 {0xE4, 0, 0, 0, 0},
808 {0xE5, 0xf5, 0xf5, 0, 0},
809 {0xE6, 0x30, 0x30, 0, 0},
810 {0xE7, 0x1, 0x1, 0, 0},
811 {0xE8, 0, 0, 0, 0},
812 {0xE9, 0xff, 0xff, 0, 0},
813 {0xEA, 0, 0, 0, 0},
814 {0xEB, 0, 0, 0, 0},
815 {0xEC, 0x22, 0x22, 0, 0},
816 {0xED, 0, 0, 0, 0},
817 {0xEE, 0, 0, 0, 0},
818 {0xEF, 0, 0, 0, 0},
819 {0xF0, 0x3, 0x3, 0, 0},
820 {0xF1, 0x1, 0x1, 0, 0},
821 {0xF2, 0, 0, 0, 0},
822 {0xF3, 0, 0, 0, 0},
823 {0xF4, 0, 0, 0, 0},
824 {0xF5, 0, 0, 0, 0},
825 {0xF6, 0, 0, 0, 0},
826 {0xF7, 0x6, 0x6, 0, 0},
827 {0xF8, 0, 0, 0, 0},
828 {0xF9, 0, 0, 0, 0},
829 {0xFA, 0x40, 0x40, 0, 0},
830 {0xFB, 0, 0, 0, 0},
831 {0xFC, 0x1, 0x1, 0, 0},
832 {0xFD, 0x80, 0x80, 0, 0},
833 {0xFE, 0x2, 0x2, 0, 0},
834 {0xFF, 0x10, 0x10, 0, 0},
835 {0x100, 0x2, 0x2, 0, 0},
836 {0x101, 0x1e, 0x1e, 0, 0},
837 {0x102, 0x1e, 0x1e, 0, 0},
838 {0x103, 0, 0, 0, 0},
839 {0x104, 0x1f, 0x1f, 0, 0},
840 {0x105, 0, 0x8, 0, 1},
841 {0x106, 0x2a, 0x2a, 0, 0},
842 {0x107, 0xf, 0xf, 0, 0},
843 {0x108, 0, 0, 0, 0},
844 {0x109, 0, 0, 0, 0},
845 {0x10A, 0, 0, 0, 0},
846 {0x10B, 0, 0, 0, 0},
847 {0x10C, 0, 0, 0, 0},
848 {0x10D, 0, 0, 0, 0},
849 {0x10E, 0, 0, 0, 0},
850 {0x10F, 0, 0, 0, 0},
851 {0x110, 0, 0, 0, 0},
852 {0x111, 0, 0, 0, 0},
853 {0x112, 0, 0, 0, 0},
854 {0x113, 0, 0, 0, 0},
855 {0x114, 0, 0, 0, 0},
856 {0x115, 0, 0, 0, 0},
857 {0x116, 0, 0, 0, 0},
858 {0x117, 0, 0, 0, 0},
859 {0x118, 0, 0, 0, 0},
860 {0x119, 0, 0, 0, 0},
861 {0x11A, 0, 0, 0, 0},
862 {0x11B, 0, 0, 0, 0},
863 {0x11C, 0x1, 0x1, 0, 0},
864 {0x11D, 0, 0, 0, 0},
865 {0x11E, 0, 0, 0, 0},
866 {0x11F, 0, 0, 0, 0},
867 {0x120, 0, 0, 0, 0},
868 {0x121, 0, 0, 0, 0},
869 {0x122, 0x80, 0x80, 0, 0},
870 {0x123, 0, 0, 0, 0},
871 {0x124, 0xf8, 0xf8, 0, 0},
872 {0x125, 0, 0, 0, 0},
873 {0x126, 0, 0, 0, 0},
874 {0x127, 0, 0, 0, 0},
875 {0x128, 0, 0, 0, 0},
876 {0x129, 0, 0, 0, 0},
877 {0x12A, 0, 0, 0, 0},
878 {0x12B, 0, 0, 0, 0},
879 {0x12C, 0, 0, 0, 0},
880 {0x12D, 0, 0, 0, 0},
881 {0x12E, 0, 0, 0, 0},
882 {0x12F, 0, 0, 0, 0},
883 {0x130, 0, 0, 0, 0},
884 {0xFFFF, 0, 0, 0, 0}
887 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
888 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
890 static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
891 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
892 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
893 128, 64,},
894 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
895 167, 93,},
896 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
897 128, 64,},
898 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
899 170, 340, 170,},
900 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
901 256, 185, 256,},
902 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
903 256, 273, 256,},
904 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
905 256, 352, 256,},
906 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
907 128, 233, 128,},
908 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
909 1881, 256,},
910 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
911 1881, 256,},
912 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
913 384, 288,},
914 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
915 128, 384, 288,},
916 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
917 170, 340, 170,},
920 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
921 static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
922 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
923 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
924 0x278, 0xfea0, 0x80, 0x100, 0x80,},
925 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
926 750, 0xFE2B, 212, 0xFFCE, 212,},
927 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
928 0xFEF2, 128, 0xFFE2, 128}
931 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
932 mod_phy_reg(pi, 0x4a4, \
933 (0x1ff << 0), \
934 (u16)(idx) << 0)
936 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
937 mod_phy_reg(pi, 0x4a5, \
938 (0x7 << 8), \
939 (u16)(npt) << 8)
941 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
942 (read_phy_reg((pi), 0x4a4) & \
943 ((0x1 << 15) | \
944 (0x1 << 14) | \
945 (0x1 << 13)))
947 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
948 ((read_phy_reg(pi, 0x4a5) & \
949 (0x7 << 8)) >> \
952 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
953 (read_phy_reg(pi, 0x473) & 0x1ff)
955 #define wlc_lcnphy_get_target_tx_pwr(pi) \
956 ((read_phy_reg(pi, 0x4a7) & \
957 (0xff << 0)) >> \
960 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
961 mod_phy_reg(pi, 0x4a7, \
962 (0xff << 0), \
963 (u16)(target) << 0)
965 #define wlc_radio_2064_rcal_done(pi) \
966 (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
968 #define tempsense_done(pi) \
969 (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
971 #define LCNPHY_IQLOCC_READ(val) \
972 ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
974 #define FIXED_TXPWR 78
975 #define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
977 void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
979 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
982 void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
984 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
987 static void
988 wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
989 const u16 *tbl_ptr, u32 tbl_len,
990 u32 tbl_width, u32 tbl_offset)
992 struct phytbl_info tab;
993 tab.tbl_id = tbl_id;
994 tab.tbl_ptr = tbl_ptr;
995 tab.tbl_len = tbl_len;
996 tab.tbl_width = tbl_width;
997 tab.tbl_offset = tbl_offset;
998 wlc_lcnphy_read_table(pi, &tab);
1001 static void
1002 wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
1003 const u16 *tbl_ptr, u32 tbl_len,
1004 u32 tbl_width, u32 tbl_offset)
1007 struct phytbl_info tab;
1008 tab.tbl_id = tbl_id;
1009 tab.tbl_ptr = tbl_ptr;
1010 tab.tbl_len = tbl_len;
1011 tab.tbl_width = tbl_width;
1012 tab.tbl_offset = tbl_offset;
1013 wlc_lcnphy_write_table(pi, &tab);
1016 static u32
1017 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1019 u32 quotient, remainder, roundup, rbit;
1021 quotient = dividend / divisor;
1022 remainder = dividend % divisor;
1023 rbit = divisor & 1;
1024 roundup = (divisor >> 1) + rbit;
1026 while (precision--) {
1027 quotient <<= 1;
1028 if (remainder >= roundup) {
1029 quotient++;
1030 remainder = ((remainder - roundup) << 1) + rbit;
1031 } else {
1032 remainder <<= 1;
1036 if (remainder >= roundup)
1037 quotient++;
1039 return quotient;
1042 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1044 int k;
1045 k = 0;
1046 if (type == 0) {
1047 if (coeff_x < 0)
1048 k = (coeff_x - 1) / 2;
1049 else
1050 k = coeff_x / 2;
1053 if (type == 1) {
1054 if ((coeff_x + 1) < 0)
1055 k = (coeff_x) / 2;
1056 else
1057 k = (coeff_x + 1) / 2;
1059 return k;
1062 static void
1063 wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
1065 u16 dac_gain, rfgain0, rfgain1;
1067 dac_gain = read_phy_reg(pi, 0x439) >> 0;
1068 gains->dac_gain = (dac_gain & 0x380) >> 7;
1070 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
1071 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
1073 gains->gm_gain = rfgain0 & 0xff;
1074 gains->pga_gain = (rfgain0 >> 8) & 0xff;
1075 gains->pad_gain = rfgain1 & 0xff;
1079 static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
1081 u16 dac_ctrl;
1083 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1084 dac_ctrl = dac_ctrl & 0xc7f;
1085 dac_ctrl = dac_ctrl | (dac_gain << 7);
1086 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1090 static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
1092 u16 bit = bEnable ? 1 : 0;
1094 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1096 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1098 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1101 static void
1102 wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
1104 u16 ebit = enable ? 1 : 0;
1106 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
1108 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
1110 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1111 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
1112 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
1113 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1114 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
1115 } else {
1116 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
1117 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
1118 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1121 if (CHSPEC_IS2G(pi->radio_chanspec)) {
1122 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
1123 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
1127 static void
1128 wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
1129 u16 trsw,
1130 u16 ext_lna,
1131 u16 biq2,
1132 u16 biq1,
1133 u16 tia, u16 lna2, u16 lna1)
1135 u16 gain0_15, gain16_19;
1137 gain16_19 = biq2 & 0xf;
1138 gain0_15 = ((biq1 & 0xf) << 12) |
1139 ((tia & 0xf) << 8) |
1140 ((lna2 & 0x3) << 6) |
1141 ((lna2 &
1142 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
1144 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
1145 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
1146 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1148 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1149 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1150 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
1151 } else {
1152 mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
1154 mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
1156 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1159 mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
1163 static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
1166 mod_phy_reg(pi, 0x44d,
1167 (0x1 << 1) |
1168 (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
1170 or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
1173 static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
1176 and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
1179 static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
1181 mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
1183 mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
1185 mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
1187 mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
1189 mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
1191 mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
1195 static bool
1196 wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
1197 u16 num_samps,
1198 u8 wait_time, struct lcnphy_iq_est *iq_est)
1200 int wait_count = 0;
1201 bool result = true;
1202 u8 phybw40;
1203 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
1205 mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
1207 mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
1209 mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
1211 mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
1213 mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
1215 mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
1217 while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
1219 if (wait_count > (10 * 500)) {
1220 result = false;
1221 goto cleanup;
1223 udelay(100);
1224 wait_count++;
1227 iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
1228 (u32) read_phy_reg(pi, 0x484);
1229 iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
1230 (u32) read_phy_reg(pi, 0x486);
1231 iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
1232 (u32) read_phy_reg(pi, 0x488);
1234 cleanup:
1235 mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
1237 mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
1239 return result;
1242 static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
1244 #define LCNPHY_MIN_RXIQ_PWR 2
1245 bool result;
1246 u16 a0_new, b0_new;
1247 struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1248 s32 a, b, temp;
1249 s16 iq_nbits, qq_nbits, arsh, brsh;
1250 s32 iq;
1251 u32 ii, qq;
1252 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1254 a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
1255 b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
1256 mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
1258 mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
1260 wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
1262 result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
1263 if (!result)
1264 goto cleanup;
1266 iq = (s32) iq_est.iq_prod;
1267 ii = iq_est.i_pwr;
1268 qq = iq_est.q_pwr;
1270 if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
1271 result = false;
1272 goto cleanup;
1275 iq_nbits = wlc_phy_nbits(iq);
1276 qq_nbits = wlc_phy_nbits(qq);
1278 arsh = 10 - (30 - iq_nbits);
1279 if (arsh >= 0) {
1280 a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
1281 temp = (s32) (ii >> arsh);
1282 if (temp == 0)
1283 return false;
1284 } else {
1285 a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
1286 temp = (s32) (ii << -arsh);
1287 if (temp == 0)
1288 return false;
1290 a /= temp;
1291 brsh = qq_nbits - 31 + 20;
1292 if (brsh >= 0) {
1293 b = (qq << (31 - qq_nbits));
1294 temp = (s32) (ii >> brsh);
1295 if (temp == 0)
1296 return false;
1297 } else {
1298 b = (qq << (31 - qq_nbits));
1299 temp = (s32) (ii << -brsh);
1300 if (temp == 0)
1301 return false;
1303 b /= temp;
1304 b -= a * a;
1305 b = (s32) int_sqrt((unsigned long) b);
1306 b -= (1 << 10);
1307 a0_new = (u16) (a & 0x3ff);
1308 b0_new = (u16) (b & 0x3ff);
1309 cleanup:
1311 wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
1313 mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
1315 mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
1317 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
1318 pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
1320 return result;
1323 static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
1325 struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1327 if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1328 return 0;
1329 return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1332 static bool
1333 wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1334 const struct lcnphy_rx_iqcomp *iqcomp,
1335 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1336 int tx_gain_idx)
1338 struct lcnphy_txgains old_gains;
1339 u16 tx_pwr_ctrl;
1340 u8 tx_gain_index_old = 0;
1341 bool result = false, tx_gain_override_old = false;
1342 u16 i, Core1TxControl_old, RFOverride0_old,
1343 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1344 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1345 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1346 int tia_gain;
1347 u32 received_power, rx_pwr_threshold;
1348 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1349 u16 values_to_save[11];
1350 s16 *ptr;
1351 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1353 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1354 if (NULL == ptr)
1355 return false;
1356 if (module == 2) {
1357 while (iqcomp_sz--) {
1358 if (iqcomp[iqcomp_sz].chan ==
1359 CHSPEC_CHANNEL(pi->radio_chanspec)) {
1360 wlc_lcnphy_set_rx_iq_comp(pi,
1361 (u16)
1362 iqcomp[iqcomp_sz].a,
1363 (u16)
1364 iqcomp[iqcomp_sz].b);
1365 result = true;
1366 break;
1369 goto cal_done;
1372 if (module == 1) {
1374 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1375 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1377 for (i = 0; i < 11; i++)
1378 values_to_save[i] =
1379 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1380 Core1TxControl_old = read_phy_reg(pi, 0x631);
1382 or_phy_reg(pi, 0x631, 0x0015);
1384 RFOverride0_old = read_phy_reg(pi, 0x44c);
1385 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1386 rfoverride2_old = read_phy_reg(pi, 0x4b0);
1387 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1388 rfoverride3_old = read_phy_reg(pi, 0x4f9);
1389 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1390 rfoverride4_old = read_phy_reg(pi, 0x938);
1391 rfoverride4val_old = read_phy_reg(pi, 0x939);
1392 afectrlovr_old = read_phy_reg(pi, 0x43b);
1393 afectrlovrval_old = read_phy_reg(pi, 0x43c);
1394 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1395 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1397 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1398 if (tx_gain_override_old) {
1399 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1400 tx_gain_index_old = pi_lcn->lcnphy_current_index;
1403 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1405 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1406 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1408 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1409 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1411 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1412 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1413 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1414 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1415 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1416 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1417 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1418 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1419 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1420 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1422 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1423 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1424 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1425 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1426 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1427 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1428 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1429 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1430 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1431 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1433 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1434 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1436 wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
1437 write_phy_reg(pi, 0x6da, 0xffff);
1438 or_phy_reg(pi, 0x6db, 0x3);
1439 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1440 wlc_lcnphy_rx_gain_override_enable(pi, true);
1442 tia_gain = 8;
1443 rx_pwr_threshold = 950;
1444 while (tia_gain > 0) {
1445 tia_gain -= 1;
1446 wlc_lcnphy_set_rx_gain_by_distribution(pi,
1447 0, 0, 2, 2,
1448 (u16)
1449 tia_gain, 1, 0);
1450 udelay(500);
1452 received_power =
1453 wlc_lcnphy_measure_digital_power(pi, 2000);
1454 if (received_power < rx_pwr_threshold)
1455 break;
1457 result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
1459 wlc_lcnphy_stop_tx_tone(pi);
1461 write_phy_reg(pi, 0x631, Core1TxControl_old);
1463 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1464 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1465 write_phy_reg(pi, 0x4b0, rfoverride2_old);
1466 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1467 write_phy_reg(pi, 0x4f9, rfoverride3_old);
1468 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1469 write_phy_reg(pi, 0x938, rfoverride4_old);
1470 write_phy_reg(pi, 0x939, rfoverride4val_old);
1471 write_phy_reg(pi, 0x43b, afectrlovr_old);
1472 write_phy_reg(pi, 0x43c, afectrlovrval_old);
1473 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1474 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1476 wlc_lcnphy_clear_trsw_override(pi);
1478 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1480 for (i = 0; i < 11; i++)
1481 write_radio_reg(pi, rxiq_cal_rf_reg[i],
1482 values_to_save[i]);
1484 if (tx_gain_override_old)
1485 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1486 else
1487 wlc_lcnphy_disable_tx_gain_override(pi);
1489 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1490 wlc_lcnphy_rx_gain_override_enable(pi, false);
1493 cal_done:
1494 kfree(ptr);
1495 return result;
1498 s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1500 s8 index;
1501 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1503 if (txpwrctrl_off(pi))
1504 index = pi_lcn->lcnphy_current_index;
1505 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1506 index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1507 pi) / 2);
1508 else
1509 index = pi_lcn->lcnphy_current_index;
1510 return index;
1513 void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1515 u16 afectrlovr, afectrlovrval;
1516 afectrlovr = read_phy_reg(pi, 0x43b);
1517 afectrlovrval = read_phy_reg(pi, 0x43c);
1518 if (channel != 0) {
1519 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1521 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1523 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1525 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1527 write_phy_reg(pi, 0x44b, 0xffff);
1528 wlc_lcnphy_tx_pu(pi, 1);
1530 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1532 or_phy_reg(pi, 0x6da, 0x0080);
1534 or_phy_reg(pi, 0x00a, 0x228);
1535 } else {
1536 and_phy_reg(pi, 0x00a, ~(0x228));
1538 and_phy_reg(pi, 0x6da, 0xFF7F);
1539 write_phy_reg(pi, 0x43b, afectrlovr);
1540 write_phy_reg(pi, 0x43c, afectrlovrval);
1544 static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1546 u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1548 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1549 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1551 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1552 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1554 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1555 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1557 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1558 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1561 static void
1562 wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1564 if (enable) {
1565 write_phy_reg(pi, 0x942, 0x7);
1566 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1567 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1569 write_phy_reg(pi, 0x44a, 0x084);
1570 write_phy_reg(pi, 0x44a, 0x080);
1571 write_phy_reg(pi, 0x6d3, 0x2222);
1572 write_phy_reg(pi, 0x6d3, 0x2220);
1573 } else {
1574 write_phy_reg(pi, 0x942, 0x0);
1575 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1576 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1578 wlapi_switch_macfreq(pi->sh->physhim, enable);
1581 static void
1582 wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1584 u8 channel = CHSPEC_CHANNEL(chanspec);
1585 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1587 if (channel == 14)
1588 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1589 else
1590 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1592 pi_lcn->lcnphy_bandedge_corr = 2;
1593 if (channel == 1)
1594 pi_lcn->lcnphy_bandedge_corr = 4;
1596 if (channel == 1 || channel == 2 || channel == 3 ||
1597 channel == 4 || channel == 9 ||
1598 channel == 10 || channel == 11 || channel == 12) {
1599 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
1600 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
1601 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
1603 si_pmu_pllupd(pi->sh->sih);
1604 write_phy_reg(pi, 0x942, 0);
1605 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1606 pi_lcn->lcnphy_spurmod = false;
1607 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1609 write_phy_reg(pi, 0x425, 0x5907);
1610 } else {
1611 si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
1612 si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
1613 si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
1615 si_pmu_pllupd(pi->sh->sih);
1616 write_phy_reg(pi, 0x942, 0);
1617 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1619 pi_lcn->lcnphy_spurmod = false;
1620 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1622 write_phy_reg(pi, 0x425, 0x590a);
1625 or_phy_reg(pi, 0x44a, 0x44);
1626 write_phy_reg(pi, 0x44a, 0x80);
1629 static void
1630 wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1632 uint i;
1633 const struct chan_info_2064_lcnphy *ci;
1634 u8 rfpll_doubler = 0;
1635 u8 pll_pwrup, pll_pwrup_ovr;
1636 s32 qFxtal, qFref, qFvco, qFcal;
1637 u8 d15, d16, f16, e44, e45;
1638 u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1639 u16 loop_bw, d30, setCount;
1641 u8 h29, h28_ten, e30, h30_ten, cp_current;
1642 u16 g30, d28;
1644 ci = &chan_info_2064_lcnphy[0];
1645 rfpll_doubler = 1;
1647 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1649 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1650 if (!rfpll_doubler) {
1651 loop_bw = PLL_2064_LOOP_BW;
1652 d30 = PLL_2064_D30;
1653 } else {
1654 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1655 d30 = PLL_2064_D30_DOUBLER;
1658 if (CHSPEC_IS2G(pi->radio_chanspec)) {
1659 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1660 if (chan_info_2064_lcnphy[i].chan == channel)
1661 break;
1663 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1664 return;
1666 ci = &chan_info_2064_lcnphy[i];
1669 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1671 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1673 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1675 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1677 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1678 (ci->logen_rccr_rx) << 2);
1680 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1682 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1683 (ci->pa_rxrf_lna2_freq_tune) << 4);
1685 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1687 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1688 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1690 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1692 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1693 e44 = 0;
1694 e45 = 0;
1696 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1697 if (pi->xtalfreq > 26000000)
1698 e44 = 1;
1699 if (pi->xtalfreq > 52000000)
1700 e45 = 1;
1701 if (e44 == 0)
1702 fcal_div = 1;
1703 else if (e45 == 0)
1704 fcal_div = 2;
1705 else
1706 fcal_div = 4;
1707 fvco3 = (ci->freq * 3);
1708 fref3 = 2 * fpfd;
1710 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
1711 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
1712 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1713 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
1715 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1717 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1718 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1719 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1721 d16 = (qFcal * 8 / (d15 + 1)) - 1;
1722 write_radio_reg(pi, RADIO_2064_REG051, d16);
1724 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1725 setCount = f16 * 3 * (ci->freq) / 32 - 1;
1726 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1727 (u8) (setCount >> 8));
1729 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1730 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1732 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1734 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1735 while (div_frac >= fref3) {
1736 div_int++;
1737 div_frac -= fref3;
1739 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1741 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1742 (u8) (div_int >> 4));
1743 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1744 (u8) (div_int << 4));
1745 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1746 (u8) (div_frac >> 16));
1747 write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1748 write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1750 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1752 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1753 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1754 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1756 h29 = LCN_BW_LMT / loop_bw;
1757 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1758 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1759 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1760 + PLL_2064_LOW_END_KVCO;
1761 h28_ten = (d28 * 10) / LCN_VCO_DIV;
1762 e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1763 g30 = LCN_OFFSET + (e30 * LCN_FACT);
1764 h30_ten = (g30 * 10) / LCN_CUR_DIV;
1765 cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1766 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1768 if (channel >= 1 && channel <= 5)
1769 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1770 else
1771 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1772 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1774 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1775 udelay(1);
1777 wlc_2064_vco_cal(pi);
1779 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1780 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1781 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1782 write_radio_reg(pi, RADIO_2064_REG038, 3);
1783 write_radio_reg(pi, RADIO_2064_REG091, 7);
1787 static int
1788 wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1790 s16 filt_index = -1;
1791 int j;
1793 u16 addr[] = {
1794 0x910,
1795 0x91e,
1796 0x91f,
1797 0x924,
1798 0x925,
1799 0x926,
1800 0x920,
1801 0x921,
1802 0x927,
1803 0x928,
1804 0x929,
1805 0x922,
1806 0x923,
1807 0x930,
1808 0x931,
1809 0x932
1812 u16 addr_ofdm[] = {
1813 0x90f,
1814 0x900,
1815 0x901,
1816 0x906,
1817 0x907,
1818 0x908,
1819 0x902,
1820 0x903,
1821 0x909,
1822 0x90a,
1823 0x90b,
1824 0x904,
1825 0x905,
1826 0x90c,
1827 0x90d,
1828 0x90e
1831 if (!is_ofdm) {
1832 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1833 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1834 filt_index = (s16) j;
1835 break;
1839 if (filt_index != -1) {
1840 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1841 write_phy_reg(pi, addr[j],
1842 LCNPHY_txdigfiltcoeffs_cck
1843 [filt_index][j + 1]);
1845 } else {
1846 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1847 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1848 filt_index = (s16) j;
1849 break;
1853 if (filt_index != -1) {
1854 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1855 write_phy_reg(pi, addr_ofdm[j],
1856 LCNPHY_txdigfiltcoeffs_ofdm
1857 [filt_index][j + 1]);
1861 return (filt_index != -1) ? 0 : -1;
1864 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
1866 u8 channel = CHSPEC_CHANNEL(chanspec);
1868 wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec);
1870 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
1872 or_phy_reg(pi, 0x44a, 0x44);
1873 write_phy_reg(pi, 0x44a, 0x80);
1875 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
1876 udelay(1000);
1878 wlc_lcnphy_toggle_afe_pwdn(pi);
1880 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
1881 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
1883 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
1884 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1886 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
1887 } else {
1888 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1890 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
1893 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
1895 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
1899 static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1901 u16 pa_gain;
1903 pa_gain = (read_phy_reg(pi, 0x4fb) &
1904 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1905 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1907 return pa_gain;
1910 static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1911 struct lcnphy_txgains *target_gains)
1913 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1915 mod_phy_reg(
1916 pi, 0x4b5,
1917 (0xffff << 0),
1918 ((target_gains->gm_gain) |
1919 (target_gains->pga_gain << 8)) <<
1921 mod_phy_reg(pi, 0x4fb,
1922 (0x7fff << 0),
1923 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1925 mod_phy_reg(
1926 pi, 0x4fc,
1927 (0xffff << 0),
1928 ((target_gains->gm_gain) |
1929 (target_gains->pga_gain << 8)) <<
1931 mod_phy_reg(pi, 0x4fd,
1932 (0x7fff << 0),
1933 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1935 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1937 wlc_lcnphy_enable_tx_gain_override(pi);
1940 static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1942 u16 m0m1 = (u16) m0 << 8;
1943 struct phytbl_info tab;
1945 tab.tbl_ptr = &m0m1;
1946 tab.tbl_len = 1;
1947 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1948 tab.tbl_offset = 87;
1949 tab.tbl_width = 16;
1950 wlc_lcnphy_write_table(pi, &tab);
1953 static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1955 u32 data_buf[64];
1956 struct phytbl_info tab;
1958 memset(data_buf, 0, sizeof(data_buf));
1960 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1961 tab.tbl_width = 32;
1962 tab.tbl_ptr = data_buf;
1964 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1966 tab.tbl_len = 30;
1967 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1968 wlc_lcnphy_write_table(pi, &tab);
1971 tab.tbl_len = 64;
1972 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1973 wlc_lcnphy_write_table(pi, &tab);
1976 enum lcnphy_tssi_mode {
1977 LCNPHY_TSSI_PRE_PA,
1978 LCNPHY_TSSI_POST_PA,
1979 LCNPHY_TSSI_EXT
1982 static void
1983 wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
1985 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
1987 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
1989 if (LCNPHY_TSSI_POST_PA == pos) {
1990 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
1992 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
1994 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
1995 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
1996 } else {
1997 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
1998 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2000 } else {
2001 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2003 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2005 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2006 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2007 } else {
2008 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2009 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2012 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2014 if (LCNPHY_TSSI_EXT == pos) {
2015 write_radio_reg(pi, RADIO_2064_REG07F, 1);
2016 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2017 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2018 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2022 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2024 u16 N1, N2, N3, N4, N5, N6, N;
2025 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2026 >> 0);
2027 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2028 >> 12);
2029 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2030 >> 0);
2031 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2032 >> 8);
2033 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2034 >> 0);
2035 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2036 >> 8);
2037 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2038 if (N < 1600)
2039 N = 1600;
2040 return N;
2043 static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2045 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2046 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2048 auxpga_vmid = (2 << 8) |
2049 (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2050 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2051 auxpga_gain_temp = 2;
2053 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2055 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2057 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2059 mod_phy_reg(pi, 0x4db,
2060 (0x3ff << 0) |
2061 (0x7 << 12),
2062 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2064 mod_phy_reg(pi, 0x4dc,
2065 (0x3ff << 0) |
2066 (0x7 << 12),
2067 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2069 mod_phy_reg(pi, 0x40a,
2070 (0x3ff << 0) |
2071 (0x7 << 12),
2072 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2074 mod_phy_reg(pi, 0x40b,
2075 (0x3ff << 0) |
2076 (0x7 << 12),
2077 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2079 mod_phy_reg(pi, 0x40c,
2080 (0x3ff << 0) |
2081 (0x7 << 12),
2082 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2084 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2087 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2089 struct phytbl_info tab;
2090 u32 rfseq, ind;
2092 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2093 tab.tbl_width = 32;
2094 tab.tbl_ptr = &ind;
2095 tab.tbl_len = 1;
2096 tab.tbl_offset = 0;
2097 for (ind = 0; ind < 128; ind++) {
2098 wlc_lcnphy_write_table(pi, &tab);
2099 tab.tbl_offset++;
2101 tab.tbl_offset = 704;
2102 for (ind = 0; ind < 128; ind++) {
2103 wlc_lcnphy_write_table(pi, &tab);
2104 tab.tbl_offset++;
2106 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2108 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2110 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2112 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
2113 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2115 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2117 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2119 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2121 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2123 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2125 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2127 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2129 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2131 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2133 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2135 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2137 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2139 wlc_lcnphy_clear_tx_power_offsets(pi);
2141 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2143 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2145 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2147 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2148 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
2149 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2150 } else {
2151 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2152 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2155 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2157 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2158 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2159 } else {
2160 if (CHSPEC_IS2G(pi->radio_chanspec))
2161 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2162 else
2163 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2166 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2167 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2168 else
2169 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2171 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2173 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2175 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2176 mod_phy_reg(pi, 0x4d7,
2177 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2179 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2180 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2181 tab.tbl_width = 16;
2182 tab.tbl_ptr = &rfseq;
2183 tab.tbl_len = 1;
2184 tab.tbl_offset = 6;
2185 wlc_lcnphy_write_table(pi, &tab);
2187 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2189 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2191 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2193 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2195 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2197 wlc_lcnphy_pwrctrl_rssiparams(pi);
2200 void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2202 u16 tx_cnt, tx_total, npt;
2203 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2205 tx_total = wlc_lcnphy_total_tx_frames(pi);
2206 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2207 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2209 if (tx_cnt > (1 << npt)) {
2211 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2213 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2214 pi_lcn->lcnphy_tssi_npt = npt;
2219 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2221 s32 a, b, p;
2223 a = 32768 + (a1 * tssi);
2224 b = (1024 * b0) + (64 * b1 * tssi);
2225 p = ((2 * b) + a) / (2 * a);
2227 return p;
2230 static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2232 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2233 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2234 return;
2236 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2237 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2240 void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2242 struct phytbl_info tab;
2243 u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2244 BRCMS_NUM_RATES_MCS_1_STREAM];
2245 uint i, j;
2246 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2247 return;
2249 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2251 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2252 j = TXP_FIRST_MCS_20_SISO;
2254 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2257 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2258 tab.tbl_width = 32;
2259 tab.tbl_len = ARRAY_SIZE(rate_table);
2260 tab.tbl_ptr = rate_table;
2261 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2262 wlc_lcnphy_write_table(pi, &tab);
2264 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2265 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2267 wlc_lcnphy_txpower_reset_npt(pi);
2271 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2273 u32 cck_offset[4] = { 22, 22, 22, 22 };
2274 u32 ofdm_offset, reg_offset_cck;
2275 int i;
2276 u16 index2;
2277 struct phytbl_info tab;
2279 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2280 return;
2282 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2284 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2286 or_phy_reg(pi, 0x6da, 0x0040);
2288 reg_offset_cck = 0;
2289 for (i = 0; i < 4; i++)
2290 cck_offset[i] -= reg_offset_cck;
2291 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2292 tab.tbl_width = 32;
2293 tab.tbl_len = 4;
2294 tab.tbl_ptr = cck_offset;
2295 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2296 wlc_lcnphy_write_table(pi, &tab);
2297 ofdm_offset = 0;
2298 tab.tbl_len = 1;
2299 tab.tbl_ptr = &ofdm_offset;
2300 for (i = 836; i < 862; i++) {
2301 tab.tbl_offset = i;
2302 wlc_lcnphy_write_table(pi, &tab);
2305 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2307 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2309 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2311 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2313 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2315 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2317 index2 = (u16) (index * 2);
2318 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2320 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2324 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2326 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2327 s16 manp, meas_temp, temp_diff;
2328 bool neg = false;
2329 u16 temp;
2330 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2332 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2333 return pi_lcn->lcnphy_current_index;
2335 index = FIXED_TXPWR;
2337 if (pi_lcn->lcnphy_tempsense_slope == 0)
2338 return index;
2340 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2341 meas_temp = LCNPHY_TEMPSENSE(temp);
2343 if (pi->tx_power_min != 0)
2344 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2345 else
2346 delta_brd = 0;
2348 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2349 temp_diff = manp - meas_temp;
2350 if (temp_diff < 0) {
2351 neg = true;
2352 temp_diff = -temp_diff;
2355 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2356 (u32) (pi_lcn->
2357 lcnphy_tempsense_slope
2358 * 10), 0);
2359 if (neg)
2360 delta_temp = -delta_temp;
2362 if (pi_lcn->lcnphy_tempsense_option == 3
2363 && LCNREV_IS(pi->pubpi.phy_rev, 0))
2364 delta_temp = 0;
2365 if (pi_lcn->lcnphy_tempcorrx > 31)
2366 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2367 else
2368 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2369 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2370 tempcorrx = 4;
2371 new_index =
2372 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2373 new_index += tempcorrx;
2375 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2376 index = 127;
2378 if (new_index < 0 || new_index > 126)
2379 return index;
2381 return new_index;
2384 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2387 u16 current_mode = mode;
2388 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2389 mode == LCNPHY_TX_PWR_CTRL_HW)
2390 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2391 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2392 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2393 current_mode = LCNPHY_TX_PWR_CTRL_HW;
2394 return current_mode;
2397 void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2399 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2400 s8 index;
2401 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2403 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2404 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2406 mod_phy_reg(pi, 0x6da, (0x1 << 6),
2407 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2409 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2410 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2412 if (old_mode != mode) {
2413 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2415 wlc_lcnphy_tx_pwr_update_npt(pi);
2417 wlc_lcnphy_clear_tx_power_offsets(pi);
2419 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2421 wlc_lcnphy_txpower_recalc_target(pi);
2423 wlc_lcnphy_set_start_tx_pwr_idx(pi,
2424 pi_lcn->
2425 lcnphy_tssi_idx);
2426 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2427 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2429 pi_lcn->lcnphy_tssi_tx_cnt =
2430 wlc_lcnphy_total_tx_frames(pi);
2432 wlc_lcnphy_disable_tx_gain_override(pi);
2433 pi_lcn->lcnphy_tx_power_idx_override = -1;
2434 } else
2435 wlc_lcnphy_enable_tx_gain_override(pi);
2437 mod_phy_reg(pi, 0x4a4,
2438 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2439 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2440 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2441 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2442 pi_lcn->lcnphy_current_index = (s8)
2443 ((read_phy_reg(pi,
2444 0x4a9) &
2445 0xFF) / 2);
2450 static void
2451 wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2453 u16 vmid;
2454 int i;
2455 for (i = 0; i < 20; i++)
2456 values_to_save[i] =
2457 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2459 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2460 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2462 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2463 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2465 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2466 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2468 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2469 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2471 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2472 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2473 else
2474 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2475 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2477 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2478 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2479 udelay(20);
2481 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2482 if (CHSPEC_IS5G(pi->radio_chanspec))
2483 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2484 else
2485 or_radio_reg(pi, RADIO_2064_REG03A, 1);
2486 } else {
2487 if (CHSPEC_IS5G(pi->radio_chanspec))
2488 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2489 else
2490 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2493 udelay(20);
2495 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2496 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2497 if (CHSPEC_IS5G(pi->radio_chanspec))
2498 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2499 else
2500 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2501 } else {
2502 if (CHSPEC_IS5G(pi->radio_chanspec))
2503 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2504 else
2505 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2508 udelay(20);
2510 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2511 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2512 udelay(20);
2514 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2515 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2516 udelay(20);
2518 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2519 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2520 udelay(20);
2522 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2523 udelay(20);
2525 vmid = 0x2A6;
2526 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2527 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2528 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2529 udelay(20);
2531 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2532 udelay(20);
2533 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2534 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2535 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2536 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2537 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2538 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2539 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2542 static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2544 uint delay_count = 0;
2546 while (wlc_lcnphy_iqcal_active(pi)) {
2547 udelay(100);
2548 delay_count++;
2550 if (delay_count > (10 * 500))
2551 break;
2554 return (0 == wlc_lcnphy_iqcal_active(pi));
2557 static void
2558 wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2560 int i;
2562 and_phy_reg(pi, 0x44c, 0x0 >> 11);
2564 and_phy_reg(pi, 0x43b, 0xC);
2566 for (i = 0; i < 20; i++)
2567 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2568 values_to_save[i]);
2571 static void
2572 wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2573 struct lcnphy_txgains *target_gains,
2574 enum lcnphy_cal_mode cal_mode, bool keep_tone)
2577 struct lcnphy_txgains cal_gains, temp_gains;
2578 u16 hash;
2579 u8 band_idx;
2580 int j;
2581 u16 ncorr_override[5];
2582 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2583 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2585 u16 commands_fullcal[] = {
2586 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2589 u16 commands_recal[] = {
2590 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2593 u16 command_nums_fullcal[] = {
2594 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2597 u16 command_nums_recal[] = {
2598 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2600 u16 *command_nums = command_nums_fullcal;
2602 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2603 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2604 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2605 bool tx_gain_override_old;
2606 struct lcnphy_txgains old_gains;
2607 uint i, n_cal_cmds = 0, n_cal_start = 0;
2608 u16 *values_to_save;
2609 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2611 values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2612 if (NULL == values_to_save)
2613 return;
2615 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2616 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2618 or_phy_reg(pi, 0x6da, 0x40);
2619 or_phy_reg(pi, 0x6db, 0x3);
2621 switch (cal_mode) {
2622 case LCNPHY_CAL_FULL:
2623 start_coeffs = syst_coeffs;
2624 cal_cmds = commands_fullcal;
2625 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2626 break;
2628 case LCNPHY_CAL_RECAL:
2629 start_coeffs = syst_coeffs;
2630 cal_cmds = commands_recal;
2631 n_cal_cmds = ARRAY_SIZE(commands_recal);
2632 command_nums = command_nums_recal;
2633 break;
2635 default:
2636 break;
2639 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2640 start_coeffs, 11, 16, 64);
2642 write_phy_reg(pi, 0x6da, 0xffff);
2643 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2645 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2647 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2649 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2651 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2653 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2655 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2657 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2659 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2660 if (tx_gain_override_old)
2661 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2663 if (!target_gains) {
2664 if (!tx_gain_override_old)
2665 wlc_lcnphy_set_tx_pwr_by_index(pi,
2666 pi_lcn->lcnphy_tssi_idx);
2667 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2668 target_gains = &temp_gains;
2671 hash = (target_gains->gm_gain << 8) |
2672 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2674 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2676 cal_gains = *target_gains;
2677 memset(ncorr_override, 0, sizeof(ncorr_override));
2678 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2679 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2680 cal_gains.gm_gain =
2681 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2682 cal_gains.pga_gain =
2683 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2684 cal_gains.pad_gain =
2685 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2686 memcpy(ncorr_override,
2687 &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2688 sizeof(ncorr_override));
2689 break;
2693 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2695 write_phy_reg(pi, 0x453, 0xaa9);
2696 write_phy_reg(pi, 0x93d, 0xc0);
2698 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2699 lcnphy_iqcal_loft_gainladder,
2700 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2701 16, 0);
2703 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2704 lcnphy_iqcal_ir_gainladder,
2705 ARRAY_SIZE(
2706 lcnphy_iqcal_ir_gainladder), 16,
2707 32);
2709 if (pi->phy_tx_tone_freq) {
2711 wlc_lcnphy_stop_tx_tone(pi);
2712 udelay(5);
2713 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2714 } else {
2715 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2718 write_phy_reg(pi, 0x6da, 0xffff);
2720 for (i = n_cal_start; i < n_cal_cmds; i++) {
2721 u16 zero_diq = 0;
2722 u16 best_coeffs[11];
2723 u16 command_num;
2725 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2727 command_num = command_nums[i];
2728 if (ncorr_override[cal_type])
2729 command_num =
2730 ncorr_override[cal_type] << 8 | (command_num &
2731 0xff);
2733 write_phy_reg(pi, 0x452, command_num);
2735 if ((cal_type == 3) || (cal_type == 4)) {
2736 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2737 &diq_start, 1, 16, 69);
2739 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2740 &zero_diq, 1, 16, 69);
2743 write_phy_reg(pi, 0x451, cal_cmds[i]);
2745 if (!wlc_lcnphy_iqcal_wait(pi))
2746 goto cleanup;
2748 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2749 best_coeffs,
2750 ARRAY_SIZE(best_coeffs), 16, 96);
2751 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2752 best_coeffs,
2753 ARRAY_SIZE(best_coeffs), 16, 64);
2755 if ((cal_type == 3) || (cal_type == 4))
2756 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2757 &diq_start, 1, 16, 69);
2758 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2759 pi_lcn->lcnphy_cal_results.
2760 txiqlocal_bestcoeffs,
2761 ARRAY_SIZE(pi_lcn->
2762 lcnphy_cal_results.
2763 txiqlocal_bestcoeffs),
2764 16, 96);
2767 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2768 pi_lcn->lcnphy_cal_results.
2769 txiqlocal_bestcoeffs,
2770 ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2771 txiqlocal_bestcoeffs), 16, 96);
2772 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2774 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2775 &pi_lcn->lcnphy_cal_results.
2776 txiqlocal_bestcoeffs[0], 4, 16, 80);
2778 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2779 &pi_lcn->lcnphy_cal_results.
2780 txiqlocal_bestcoeffs[5], 2, 16, 85);
2782 cleanup:
2783 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2784 kfree(values_to_save);
2786 if (!keep_tone)
2787 wlc_lcnphy_stop_tx_tone(pi);
2789 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2791 write_phy_reg(pi, 0x453, 0);
2793 if (tx_gain_override_old)
2794 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2795 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2797 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2798 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2802 static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2804 bool suspend, tx_gain_override_old;
2805 struct lcnphy_txgains old_gains;
2806 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2807 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2808 idleTssi0_regvalue_2C;
2809 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2810 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2811 u16 SAVE_jtag_bb_afe_switch =
2812 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2813 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2814 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2815 idleTssi = read_phy_reg(pi, 0x4ab);
2816 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2817 MCTL_EN_MAC));
2818 if (!suspend)
2819 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2820 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2822 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2823 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2825 wlc_lcnphy_enable_tx_gain_override(pi);
2826 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2827 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2828 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2829 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2830 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2831 wlc_lcnphy_tssi_setup(pi);
2832 wlc_phy_do_dummy_tx(pi, true, OFF);
2833 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2834 >> 0);
2836 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2837 >> 0);
2839 if (idleTssi0_2C >= 256)
2840 idleTssi0_OB = idleTssi0_2C - 256;
2841 else
2842 idleTssi0_OB = idleTssi0_2C + 256;
2844 idleTssi0_regvalue_OB = idleTssi0_OB;
2845 if (idleTssi0_regvalue_OB >= 256)
2846 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2847 else
2848 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2849 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2851 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2853 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2854 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2855 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2857 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2858 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2859 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2860 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2861 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2862 if (!suspend)
2863 wlapi_enable_mac(pi->sh->physhim);
2866 static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2868 bool suspend;
2869 u16 save_txpwrCtrlEn;
2870 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2871 u16 auxpga_vmid;
2872 struct phytbl_info tab;
2873 u32 val;
2874 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2875 save_reg112;
2876 u16 values_to_save[14];
2877 s8 index;
2878 int i;
2879 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2880 udelay(999);
2882 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2883 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2884 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2885 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2886 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2887 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2889 for (i = 0; i < 14; i++)
2890 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2891 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2892 MCTL_EN_MAC));
2893 if (!suspend)
2894 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2895 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2897 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2898 index = pi_lcn->lcnphy_current_index;
2899 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2900 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2901 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2902 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2903 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2905 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2907 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2909 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2911 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2913 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2915 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2917 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2919 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2921 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2923 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2925 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2927 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2929 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2931 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2933 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2935 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2937 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2939 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2941 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2943 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2945 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2947 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2949 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2950 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2951 tab.tbl_width = 16;
2952 tab.tbl_len = 1;
2953 tab.tbl_ptr = &val;
2954 tab.tbl_offset = 6;
2955 wlc_lcnphy_write_table(pi, &tab);
2956 if (mode == TEMPSENSE) {
2957 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2959 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2961 auxpga_vmidcourse = 8;
2962 auxpga_vmidfine = 0x4;
2963 auxpga_gain = 2;
2964 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2965 } else {
2966 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2968 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2970 auxpga_vmidcourse = 7;
2971 auxpga_vmidfine = 0xa;
2972 auxpga_gain = 2;
2974 auxpga_vmid =
2975 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
2976 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
2978 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
2980 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
2982 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
2984 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
2986 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2988 wlc_phy_do_dummy_tx(pi, true, OFF);
2989 if (!tempsense_done(pi))
2990 udelay(10);
2992 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
2993 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
2994 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
2995 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
2996 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
2997 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
2998 for (i = 0; i < 14; i++)
2999 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
3000 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3002 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3003 if (!suspend)
3004 wlapi_enable_mac(pi->sh->physhim);
3005 udelay(999);
3008 static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3010 struct lcnphy_txgains tx_gains;
3011 u8 bbmult;
3012 struct phytbl_info tab;
3013 s32 a1, b0, b1;
3014 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3015 bool suspend;
3016 struct brcms_phy *pi = (struct brcms_phy *) ppi;
3018 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3019 MCTL_EN_MAC));
3020 if (!suspend)
3021 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3023 if (!pi->hwpwrctrl_capable) {
3024 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3025 tx_gains.gm_gain = 4;
3026 tx_gains.pga_gain = 12;
3027 tx_gains.pad_gain = 12;
3028 tx_gains.dac_gain = 0;
3030 bbmult = 150;
3031 } else {
3032 tx_gains.gm_gain = 7;
3033 tx_gains.pga_gain = 15;
3034 tx_gains.pad_gain = 14;
3035 tx_gains.dac_gain = 0;
3037 bbmult = 150;
3039 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3040 wlc_lcnphy_set_bbmult(pi, bbmult);
3041 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3042 } else {
3044 wlc_lcnphy_idle_tssi_est(ppi);
3046 wlc_lcnphy_clear_tx_power_offsets(pi);
3048 b0 = pi->txpa_2g[0];
3049 b1 = pi->txpa_2g[1];
3050 a1 = pi->txpa_2g[2];
3051 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3052 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3054 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3055 tab.tbl_width = 32;
3056 tab.tbl_ptr = &pwr;
3057 tab.tbl_len = 1;
3058 tab.tbl_offset = 0;
3059 for (tssi = 0; tssi < 128; tssi++) {
3060 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3062 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3063 wlc_lcnphy_write_table(pi, &tab);
3064 tab.tbl_offset++;
3067 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3069 write_phy_reg(pi, 0x4a8, 10);
3071 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3073 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3075 if (!suspend)
3076 wlapi_enable_mac(pi->sh->physhim);
3079 static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
3081 u16 m0m1;
3082 struct phytbl_info tab;
3084 tab.tbl_ptr = &m0m1;
3085 tab.tbl_len = 1;
3086 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3087 tab.tbl_offset = 87;
3088 tab.tbl_width = 16;
3089 wlc_lcnphy_read_table(pi, &tab);
3091 return (u8) ((m0m1 & 0xff00) >> 8);
3094 static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3096 mod_phy_reg(pi, 0x4fb,
3097 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3098 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3099 mod_phy_reg(pi, 0x4fd,
3100 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3101 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3104 void
3105 wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3106 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3108 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3109 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3110 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3111 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3114 void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3116 struct phytbl_info tab;
3117 u16 iqcc[2];
3119 iqcc[0] = a;
3120 iqcc[1] = b;
3122 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3123 tab.tbl_width = 16;
3124 tab.tbl_ptr = iqcc;
3125 tab.tbl_len = 2;
3126 tab.tbl_offset = 80;
3127 wlc_lcnphy_write_table(pi, &tab);
3130 void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3132 struct phytbl_info tab;
3134 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3135 tab.tbl_width = 16;
3136 tab.tbl_ptr = &didq;
3137 tab.tbl_len = 1;
3138 tab.tbl_offset = 85;
3139 wlc_lcnphy_write_table(pi, &tab);
3142 void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3144 struct phytbl_info tab;
3145 u16 a, b;
3146 u8 bb_mult;
3147 u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3148 struct lcnphy_txgains gains;
3149 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3151 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3152 pi_lcn->lcnphy_current_index = (u8) index;
3154 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3155 tab.tbl_width = 32;
3156 tab.tbl_len = 1;
3158 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3160 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3161 tab.tbl_ptr = &bbmultiqcomp;
3162 wlc_lcnphy_read_table(pi, &tab);
3164 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3165 tab.tbl_width = 32;
3166 tab.tbl_ptr = &txgain;
3167 wlc_lcnphy_read_table(pi, &tab);
3169 gains.gm_gain = (u16) (txgain & 0xff);
3170 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3171 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3172 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3173 wlc_lcnphy_set_tx_gain(pi, &gains);
3174 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3176 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3177 wlc_lcnphy_set_bbmult(pi, bb_mult);
3179 wlc_lcnphy_enable_tx_gain_override(pi);
3181 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3183 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3184 b = (u16) (bbmultiqcomp & 0x3ff);
3185 wlc_lcnphy_set_tx_iqcc(pi, a, b);
3187 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3188 tab.tbl_ptr = &locoeffs;
3189 wlc_lcnphy_read_table(pi, &tab);
3191 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3193 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3194 tab.tbl_ptr = &rfpower;
3195 wlc_lcnphy_read_table(pi, &tab);
3196 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3201 static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3203 u32 j;
3204 struct phytbl_info tab;
3205 u32 temp_offset[128];
3206 tab.tbl_ptr = temp_offset;
3207 tab.tbl_len = 128;
3208 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3209 tab.tbl_width = 32;
3210 tab.tbl_offset = 0;
3212 memset(temp_offset, 0, sizeof(temp_offset));
3213 for (j = 1; j < 128; j += 2)
3214 temp_offset[j] = 0x80000;
3216 wlc_lcnphy_write_table(pi, &tab);
3217 return;
3220 void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3222 if (!bEnable) {
3224 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3226 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3228 and_phy_reg(pi, 0x44c,
3229 ~(u16) ((0x1 << 3) |
3230 (0x1 << 5) |
3231 (0x1 << 12) |
3232 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3234 and_phy_reg(pi, 0x44d,
3235 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3236 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3238 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3240 and_phy_reg(pi, 0x4f9,
3241 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3243 and_phy_reg(pi, 0x4fa,
3244 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3245 } else {
3247 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3248 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3250 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3251 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3253 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3254 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3256 wlc_lcnphy_set_trsw_override(pi, true, false);
3258 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3259 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3261 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3263 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3264 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3266 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3267 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3269 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3270 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3272 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3273 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3275 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3276 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3277 } else {
3279 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3280 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3282 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3283 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3285 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3286 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3288 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3289 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3291 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3292 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3297 static void
3298 wlc_lcnphy_run_samples(struct brcms_phy *pi,
3299 u16 num_samps,
3300 u16 num_loops, u16 wait, bool iqcalmode)
3303 or_phy_reg(pi, 0x6da, 0x8080);
3305 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3306 if (num_loops != 0xffff)
3307 num_loops--;
3308 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3310 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3312 if (iqcalmode) {
3314 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3315 or_phy_reg(pi, 0x453, (0x1 << 15));
3316 } else {
3317 write_phy_reg(pi, 0x63f, 1);
3318 wlc_lcnphy_tx_pu(pi, 1);
3321 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3324 void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3327 u8 phybw40;
3328 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3330 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3331 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3332 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3333 } else {
3334 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3335 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3338 if (phybw40 == 0) {
3339 mod_phy_reg((pi), 0x410,
3340 (0x1 << 6) |
3341 (0x1 << 5),
3342 ((CHSPEC_IS2G(
3343 pi->radio_chanspec)) ? (!mode) : 0) <<
3344 6 | (!mode) << 5);
3345 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3349 void
3350 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3351 bool iqcalmode)
3353 u8 phy_bw;
3354 u16 num_samps, t, k;
3355 u32 bw;
3356 s32 theta = 0, rot = 0;
3357 struct cordic_iq tone_samp;
3358 u32 data_buf[64];
3359 u16 i_samp, q_samp;
3360 struct phytbl_info tab;
3361 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3363 pi->phy_tx_tone_freq = f_kHz;
3365 wlc_lcnphy_deaf_mode(pi, true);
3367 phy_bw = 40;
3368 if (pi_lcn->lcnphy_spurmod) {
3369 write_phy_reg(pi, 0x942, 0x2);
3370 write_phy_reg(pi, 0x93b, 0x0);
3371 write_phy_reg(pi, 0x93c, 0x0);
3372 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3375 if (f_kHz) {
3376 k = 1;
3377 do {
3378 bw = phy_bw * 1000 * k;
3379 num_samps = bw / abs(f_kHz);
3380 k++;
3381 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3382 } else
3383 num_samps = 2;
3385 rot = ((f_kHz * 36) / phy_bw) / 100;
3386 theta = 0;
3388 for (t = 0; t < num_samps; t++) {
3390 tone_samp = cordic_calc_iq(theta);
3392 theta += rot;
3394 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3395 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3396 data_buf[t] = (i_samp << 10) | q_samp;
3399 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3401 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3403 tab.tbl_ptr = data_buf;
3404 tab.tbl_len = num_samps;
3405 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3406 tab.tbl_offset = 0;
3407 tab.tbl_width = 32;
3408 wlc_lcnphy_write_table(pi, &tab);
3410 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3413 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3415 s16 playback_status;
3416 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3418 pi->phy_tx_tone_freq = 0;
3419 if (pi_lcn->lcnphy_spurmod) {
3420 write_phy_reg(pi, 0x942, 0x7);
3421 write_phy_reg(pi, 0x93b, 0x2017);
3422 write_phy_reg(pi, 0x93c, 0x27c5);
3423 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3426 playback_status = read_phy_reg(pi, 0x644);
3427 if (playback_status & (0x1 << 0)) {
3428 wlc_lcnphy_tx_pu(pi, 0);
3429 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3430 } else if (playback_status & (0x1 << 1))
3431 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3433 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3435 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3437 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3439 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3441 wlc_lcnphy_deaf_mode(pi, false);
3444 static void
3445 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3447 u16 di0dq0;
3448 u16 x, y, data_rf;
3449 int k;
3450 switch (cal_type) {
3451 case 0:
3452 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3453 break;
3454 case 2:
3455 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3456 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3457 break;
3458 case 3:
3459 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3460 y = 8 + k;
3461 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3462 x = 8 - k;
3463 data_rf = (x * 16 + y);
3464 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3465 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3466 y = 8 + k;
3467 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3468 x = 8 - k;
3469 data_rf = (x * 16 + y);
3470 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3471 break;
3472 case 4:
3473 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3474 y = 8 + k;
3475 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3476 x = 8 - k;
3477 data_rf = (x * 16 + y);
3478 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3479 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3480 y = 8 + k;
3481 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3482 x = 8 - k;
3483 data_rf = (x * 16 + y);
3484 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3485 break;
3489 static struct lcnphy_unsign16_struct
3490 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3492 u16 a, b, didq;
3493 u8 di0, dq0, ei, eq, fi, fq;
3494 struct lcnphy_unsign16_struct cc;
3495 cc.re = 0;
3496 cc.im = 0;
3497 switch (cal_type) {
3498 case 0:
3499 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3500 cc.re = a;
3501 cc.im = b;
3502 break;
3503 case 2:
3504 didq = wlc_lcnphy_get_tx_locc(pi);
3505 di0 = (((didq & 0xff00) << 16) >> 24);
3506 dq0 = (((didq & 0x00ff) << 24) >> 24);
3507 cc.re = (u16) di0;
3508 cc.im = (u16) dq0;
3509 break;
3510 case 3:
3511 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3512 cc.re = (u16) ei;
3513 cc.im = (u16) eq;
3514 break;
3515 case 4:
3516 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3517 cc.re = (u16) fi;
3518 cc.im = (u16) fq;
3519 break;
3521 return cc;
3524 static void
3525 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3526 s16 *ptr, int mode)
3528 u32 curval1, curval2, stpptr, curptr, strptr, val;
3529 u16 sslpnCalibClkEnCtrl, timer;
3530 u16 old_sslpnCalibClkEnCtrl;
3531 s16 imag, real;
3532 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3534 timer = 0;
3535 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3537 curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3538 ptr[130] = 0;
3539 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3540 ((1 << 6) | curval1));
3542 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3543 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3544 udelay(20);
3545 curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3546 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3547 curval2 | 0x30);
3549 write_phy_reg(pi, 0x555, 0x0);
3550 write_phy_reg(pi, 0x5a6, 0x5);
3552 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3553 write_phy_reg(pi, 0x5cf, 3);
3554 write_phy_reg(pi, 0x5a5, 0x3);
3555 write_phy_reg(pi, 0x583, 0x0);
3556 write_phy_reg(pi, 0x584, 0x0);
3557 write_phy_reg(pi, 0x585, 0x0fff);
3558 write_phy_reg(pi, 0x586, 0x0000);
3560 write_phy_reg(pi, 0x580, 0x4501);
3562 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3563 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3564 stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3565 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3566 do {
3567 udelay(10);
3568 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3569 timer++;
3570 } while ((curptr != stpptr) && (timer < 500));
3572 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3573 strptr = 0x7E00;
3574 bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3575 while (strptr < 0x8000) {
3576 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3577 imag = ((val >> 16) & 0x3ff);
3578 real = ((val) & 0x3ff);
3579 if (imag > 511)
3580 imag -= 1024;
3582 if (real > 511)
3583 real -= 1024;
3585 if (pi_lcn->lcnphy_iqcal_swp_dis)
3586 ptr[(strptr - 0x7E00) / 4] = real;
3587 else
3588 ptr[(strptr - 0x7E00) / 4] = imag;
3590 if (clip_detect_algo) {
3591 if (imag > thresh || imag < -thresh) {
3592 strptr = 0x8000;
3593 ptr[130] = 1;
3597 strptr += 4;
3600 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3601 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3602 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3605 static void
3606 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3607 int step_size_lg2)
3609 const struct lcnphy_spb_tone *phy_c1;
3610 struct lcnphy_spb_tone phy_c2;
3611 struct lcnphy_unsign16_struct phy_c3;
3612 int phy_c4, phy_c5, k, l, j, phy_c6;
3613 u16 phy_c7, phy_c8, phy_c9;
3614 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3615 s16 *ptr, phy_c17;
3616 s32 phy_c18, phy_c19;
3617 u32 phy_c20, phy_c21;
3618 bool phy_c22, phy_c23, phy_c24, phy_c25;
3619 u16 phy_c26, phy_c27;
3620 u16 phy_c28, phy_c29, phy_c30;
3621 u16 phy_c31;
3622 u16 *phy_c32;
3623 phy_c21 = 0;
3624 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3625 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3626 if (NULL == ptr)
3627 return;
3629 phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3630 if (NULL == phy_c32) {
3631 kfree(ptr);
3632 return;
3634 phy_c26 = read_phy_reg(pi, 0x6da);
3635 phy_c27 = read_phy_reg(pi, 0x6db);
3636 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3637 write_phy_reg(pi, 0x93d, 0xC0);
3639 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3640 write_phy_reg(pi, 0x6da, 0xffff);
3641 or_phy_reg(pi, 0x6db, 0x3);
3643 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3644 udelay(500);
3645 phy_c28 = read_phy_reg(pi, 0x938);
3646 phy_c29 = read_phy_reg(pi, 0x4d7);
3647 phy_c30 = read_phy_reg(pi, 0x4d8);
3648 or_phy_reg(pi, 0x938, 0x1 << 2);
3649 or_phy_reg(pi, 0x4d7, 0x1 << 2);
3650 or_phy_reg(pi, 0x4d7, 0x1 << 3);
3651 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3652 or_phy_reg(pi, 0x4d8, 1 << 0);
3653 or_phy_reg(pi, 0x4d8, 1 << 1);
3654 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3655 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3656 phy_c1 = &lcnphy_spb_tone_3750[0];
3657 phy_c4 = 32;
3659 if (num_levels == 0) {
3660 if (cal_type != 0)
3661 num_levels = 4;
3662 else
3663 num_levels = 9;
3665 if (step_size_lg2 == 0) {
3666 if (cal_type != 0)
3667 step_size_lg2 = 3;
3668 else
3669 step_size_lg2 = 8;
3672 phy_c7 = (1 << step_size_lg2);
3673 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3674 phy_c15 = (s16) phy_c3.re;
3675 phy_c16 = (s16) phy_c3.im;
3676 if (cal_type == 2) {
3677 if (phy_c3.re > 127)
3678 phy_c15 = phy_c3.re - 256;
3679 if (phy_c3.im > 127)
3680 phy_c16 = phy_c3.im - 256;
3682 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3683 udelay(20);
3684 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3685 phy_c23 = true;
3686 phy_c22 = false;
3687 switch (cal_type) {
3688 case 0:
3689 phy_c10 = 511;
3690 break;
3691 case 2:
3692 phy_c10 = 127;
3693 break;
3694 case 3:
3695 phy_c10 = 15;
3696 break;
3697 case 4:
3698 phy_c10 = 15;
3699 break;
3702 phy_c9 = read_phy_reg(pi, 0x93d);
3703 phy_c9 = 2 * phy_c9;
3704 phy_c24 = false;
3705 phy_c5 = 7;
3706 phy_c25 = true;
3707 while (1) {
3708 write_radio_reg(pi, RADIO_2064_REG026,
3709 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3710 udelay(50);
3711 phy_c22 = false;
3712 ptr[130] = 0;
3713 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3714 if (ptr[130] == 1)
3715 phy_c22 = true;
3716 if (phy_c22)
3717 phy_c5 -= 1;
3718 if ((phy_c22 != phy_c24) && (!phy_c25))
3719 break;
3720 if (!phy_c22)
3721 phy_c5 += 1;
3722 if (phy_c5 <= 0 || phy_c5 >= 7)
3723 break;
3724 phy_c24 = phy_c22;
3725 phy_c25 = false;
3728 if (phy_c5 < 0)
3729 phy_c5 = 0;
3730 else if (phy_c5 > 7)
3731 phy_c5 = 7;
3733 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3734 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3735 phy_c11 = phy_c15 + k;
3736 phy_c12 = phy_c16 + l;
3738 if (phy_c11 < -phy_c10)
3739 phy_c11 = -phy_c10;
3740 else if (phy_c11 > phy_c10)
3741 phy_c11 = phy_c10;
3742 if (phy_c12 < -phy_c10)
3743 phy_c12 = -phy_c10;
3744 else if (phy_c12 > phy_c10)
3745 phy_c12 = phy_c10;
3746 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3747 phy_c12);
3748 udelay(20);
3749 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3751 phy_c18 = 0;
3752 phy_c19 = 0;
3753 for (j = 0; j < 128; j++) {
3754 if (cal_type != 0)
3755 phy_c6 = j % phy_c4;
3756 else
3757 phy_c6 = (2 * j) % phy_c4;
3759 phy_c2.re = phy_c1[phy_c6].re;
3760 phy_c2.im = phy_c1[phy_c6].im;
3761 phy_c17 = ptr[j];
3762 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3763 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3766 phy_c18 = phy_c18 >> 10;
3767 phy_c19 = phy_c19 >> 10;
3768 phy_c20 = ((phy_c18 * phy_c18) +
3769 (phy_c19 * phy_c19));
3771 if (phy_c23 || phy_c20 < phy_c21) {
3772 phy_c21 = phy_c20;
3773 phy_c13 = phy_c11;
3774 phy_c14 = phy_c12;
3776 phy_c23 = false;
3779 phy_c23 = true;
3780 phy_c15 = phy_c13;
3781 phy_c16 = phy_c14;
3782 phy_c7 = phy_c7 >> 1;
3783 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3784 udelay(20);
3786 goto cleanup;
3787 cleanup:
3788 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3789 wlc_lcnphy_stop_tx_tone(pi);
3790 write_phy_reg(pi, 0x6da, phy_c26);
3791 write_phy_reg(pi, 0x6db, phy_c27);
3792 write_phy_reg(pi, 0x938, phy_c28);
3793 write_phy_reg(pi, 0x4d7, phy_c29);
3794 write_phy_reg(pi, 0x4d8, phy_c30);
3795 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3797 kfree(phy_c32);
3798 kfree(ptr);
3801 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3803 u16 iqcc[2];
3804 struct phytbl_info tab;
3806 tab.tbl_ptr = iqcc;
3807 tab.tbl_len = 2;
3808 tab.tbl_id = 0;
3809 tab.tbl_offset = 80;
3810 tab.tbl_width = 16;
3811 wlc_lcnphy_read_table(pi, &tab);
3813 *a = iqcc[0];
3814 *b = iqcc[1];
3817 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3819 struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3821 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3822 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3823 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3824 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3826 wlc_lcnphy_a1(pi, 4, 0, 0);
3827 wlc_lcnphy_a1(pi, 3, 0, 0);
3828 wlc_lcnphy_a1(pi, 2, 3, 2);
3829 wlc_lcnphy_a1(pi, 0, 5, 8);
3830 wlc_lcnphy_a1(pi, 2, 2, 1);
3831 wlc_lcnphy_a1(pi, 0, 4, 3);
3833 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3834 locc2 = wlc_lcnphy_get_cc(pi, 2);
3835 locc3 = wlc_lcnphy_get_cc(pi, 3);
3836 locc4 = wlc_lcnphy_get_cc(pi, 4);
3839 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3841 struct phytbl_info tab;
3842 u16 didq;
3844 tab.tbl_id = 0;
3845 tab.tbl_width = 16;
3846 tab.tbl_ptr = &didq;
3847 tab.tbl_len = 1;
3848 tab.tbl_offset = 85;
3849 wlc_lcnphy_read_table(pi, &tab);
3851 return didq;
3854 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3857 struct lcnphy_txgains target_gains, old_gains;
3858 u8 save_bb_mult;
3859 u16 a, b, didq, save_pa_gain = 0;
3860 uint idx, SAVE_txpwrindex = 0xFF;
3861 u32 val;
3862 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3863 struct phytbl_info tab;
3864 u8 ei0, eq0, fi0, fq0;
3865 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3867 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3868 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3870 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3872 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3873 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3875 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3877 target_gains.gm_gain = 7;
3878 target_gains.pga_gain = 0;
3879 target_gains.pad_gain = 21;
3880 target_gains.dac_gain = 0;
3881 wlc_lcnphy_set_tx_gain(pi, &target_gains);
3882 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3884 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3886 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3888 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3889 (pi_lcn->
3890 lcnphy_recal ? LCNPHY_CAL_RECAL :
3891 LCNPHY_CAL_FULL), false);
3892 } else {
3893 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3896 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3897 if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3898 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3899 target_gains.gm_gain = 255;
3900 target_gains.pga_gain = 255;
3901 target_gains.pad_gain = 0xf0;
3902 target_gains.dac_gain = 0;
3903 } else {
3904 target_gains.gm_gain = 7;
3905 target_gains.pga_gain = 45;
3906 target_gains.pad_gain = 186;
3907 target_gains.dac_gain = 0;
3910 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3911 || pi_lcn->lcnphy_hw_iqcal_en) {
3913 target_gains.pga_gain = 0;
3914 target_gains.pad_gain = 30;
3915 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3916 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3917 LCNPHY_CAL_FULL, false);
3918 } else {
3919 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3923 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3925 didq = wlc_lcnphy_get_tx_locc(pi);
3927 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3928 tab.tbl_width = 32;
3929 tab.tbl_ptr = &val;
3931 tab.tbl_len = 1;
3932 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3934 for (idx = 0; idx < 128; idx++) {
3935 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3937 wlc_lcnphy_read_table(pi, &tab);
3938 val = (val & 0xfff00000) |
3939 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3940 wlc_lcnphy_write_table(pi, &tab);
3942 val = didq;
3943 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
3944 wlc_lcnphy_write_table(pi, &tab);
3947 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
3948 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
3949 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
3950 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
3951 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
3952 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
3953 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
3955 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
3956 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
3957 wlc_lcnphy_set_tx_gain(pi, &old_gains);
3959 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
3960 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3961 else
3962 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
3965 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
3967 u16 tempsenseval1, tempsenseval2;
3968 s16 avg = 0;
3969 bool suspend = false;
3971 if (mode == 1) {
3972 suspend = (0 == (bcma_read32(pi->d11core,
3973 D11REGOFFS(maccontrol)) &
3974 MCTL_EN_MAC));
3975 if (!suspend)
3976 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3977 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3979 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3980 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3982 if (tempsenseval1 > 255)
3983 avg = (s16) (tempsenseval1 - 512);
3984 else
3985 avg = (s16) tempsenseval1;
3987 if (tempsenseval2 > 255)
3988 avg += (s16) (tempsenseval2 - 512);
3989 else
3990 avg += (s16) tempsenseval2;
3992 avg /= 2;
3994 if (mode == 1) {
3996 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
3998 udelay(100);
3999 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4001 if (!suspend)
4002 wlapi_enable_mac(pi->sh->physhim);
4004 return avg;
4007 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4009 u16 tempsenseval1, tempsenseval2;
4010 s32 avg = 0;
4011 bool suspend = false;
4012 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4013 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4015 if (mode == 1) {
4016 suspend = (0 == (bcma_read32(pi->d11core,
4017 D11REGOFFS(maccontrol)) &
4018 MCTL_EN_MAC));
4019 if (!suspend)
4020 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4021 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4023 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4024 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4026 if (tempsenseval1 > 255)
4027 avg = (int)(tempsenseval1 - 512);
4028 else
4029 avg = (int)tempsenseval1;
4031 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4032 if (tempsenseval2 > 255)
4033 avg = (int)(avg - tempsenseval2 + 512);
4034 else
4035 avg = (int)(avg - tempsenseval2);
4036 } else {
4037 if (tempsenseval2 > 255)
4038 avg = (int)(avg + tempsenseval2 - 512);
4039 else
4040 avg = (int)(avg + tempsenseval2);
4041 avg = avg / 2;
4043 if (avg < 0)
4044 avg = avg + 512;
4046 if (pi_lcn->lcnphy_tempsense_option == 2)
4047 avg = tempsenseval1;
4049 if (mode)
4050 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4052 if (mode == 1) {
4054 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4056 udelay(100);
4057 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4059 if (!suspend)
4060 wlapi_enable_mac(pi->sh->physhim);
4062 return (u16) avg;
4065 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4067 s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4068 degree =
4069 ((degree <<
4070 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4071 / LCN_TEMPSENSE_DEN;
4072 return (s8) degree;
4075 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4077 u16 vbatsenseval;
4078 s32 avg = 0;
4079 bool suspend = false;
4081 if (mode == 1) {
4082 suspend = (0 == (bcma_read32(pi->d11core,
4083 D11REGOFFS(maccontrol)) &
4084 MCTL_EN_MAC));
4085 if (!suspend)
4086 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4087 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4090 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4092 if (vbatsenseval > 255)
4093 avg = (s32) (vbatsenseval - 512);
4094 else
4095 avg = (s32) vbatsenseval;
4097 avg = (avg * LCN_VBAT_SCALE_NOM +
4098 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4100 if (mode == 1) {
4101 if (!suspend)
4102 wlapi_enable_mac(pi->sh->physhim);
4104 return (s8) avg;
4107 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4109 u8 phybw40;
4110 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4112 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4114 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4115 (mode == AFE_CLK_INIT_MODE_TXRX2X))
4116 write_phy_reg(pi, 0x6d0, 0x7);
4118 wlc_lcnphy_toggle_afe_pwdn(pi);
4121 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4125 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4127 bool suspend;
4128 s8 index;
4129 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4130 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4131 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4132 MCTL_EN_MAC));
4133 if (!suspend)
4134 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4135 wlc_lcnphy_deaf_mode(pi, true);
4136 pi->phy_lastcal = pi->sh->now;
4137 pi->phy_forcecal = false;
4138 index = pi_lcn->lcnphy_current_index;
4140 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4142 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4143 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4144 wlc_lcnphy_deaf_mode(pi, false);
4145 if (!suspend)
4146 wlapi_enable_mac(pi->sh->physhim);
4150 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4152 bool suspend, full_cal;
4153 const struct lcnphy_rx_iqcomp *rx_iqcomp;
4154 int rx_iqcomp_sz;
4155 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4156 s8 index;
4157 struct phytbl_info tab;
4158 s32 a1, b0, b1;
4159 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4160 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4162 pi->phy_lastcal = pi->sh->now;
4163 pi->phy_forcecal = false;
4164 full_cal =
4165 (pi_lcn->lcnphy_full_cal_channel !=
4166 CHSPEC_CHANNEL(pi->radio_chanspec));
4167 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4168 index = pi_lcn->lcnphy_current_index;
4170 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4171 MCTL_EN_MAC));
4172 if (!suspend) {
4173 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4174 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4177 wlc_lcnphy_deaf_mode(pi, true);
4179 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4181 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4182 rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4184 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4185 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4186 else
4187 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4189 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4191 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4193 b0 = pi->txpa_2g[0];
4194 b1 = pi->txpa_2g[1];
4195 a1 = pi->txpa_2g[2];
4196 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4197 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4199 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4200 tab.tbl_width = 32;
4201 tab.tbl_ptr = &pwr;
4202 tab.tbl_len = 1;
4203 tab.tbl_offset = 0;
4204 for (tssi = 0; tssi < 128; tssi++) {
4205 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4206 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4207 wlc_lcnphy_write_table(pi, &tab);
4208 tab.tbl_offset++;
4212 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4213 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4214 wlc_lcnphy_deaf_mode(pi, false);
4215 if (!suspend)
4216 wlapi_enable_mac(pi->sh->physhim);
4219 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4221 u16 temp_new;
4222 int temp1, temp2, temp_diff;
4223 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4225 switch (mode) {
4226 case PHY_PERICAL_CHAN:
4227 break;
4228 case PHY_FULLCAL:
4229 wlc_lcnphy_periodic_cal(pi);
4230 break;
4231 case PHY_PERICAL_PHYINIT:
4232 wlc_lcnphy_periodic_cal(pi);
4233 break;
4234 case PHY_PERICAL_WATCHDOG:
4235 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4236 temp_new = wlc_lcnphy_tempsense(pi, 0);
4237 temp1 = LCNPHY_TEMPSENSE(temp_new);
4238 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4239 temp_diff = temp1 - temp2;
4240 if ((pi_lcn->lcnphy_cal_counter > 90) ||
4241 (temp_diff > 60) || (temp_diff < -60)) {
4242 wlc_lcnphy_glacial_timer_based_cal(pi);
4243 wlc_2064_vco_cal(pi);
4244 pi_lcn->lcnphy_cal_temper = temp_new;
4245 pi_lcn->lcnphy_cal_counter = 0;
4246 } else
4247 pi_lcn->lcnphy_cal_counter++;
4249 break;
4250 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4251 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4252 wlc_lcnphy_tx_power_adjustment(
4253 (struct brcms_phy_pub *) pi);
4254 break;
4258 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4260 s8 cck_offset;
4261 u16 status;
4262 status = (read_phy_reg(pi, 0x4ab));
4263 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4264 (status & (0x1 << 15))) {
4265 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4266 >> 0) >> 1);
4268 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4269 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4270 else
4271 cck_offset = 0;
4273 *cck_pwr = *ofdm_pwr + cck_offset;
4274 } else {
4275 *cck_pwr = 0;
4276 *ofdm_pwr = 0;
4280 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4282 return;
4286 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4288 s8 index;
4289 u16 index2;
4290 struct brcms_phy *pi = (struct brcms_phy *) ppi;
4291 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4292 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4293 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4294 SAVE_txpwrctrl) {
4295 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4296 index2 = (u16) (index * 2);
4297 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4299 pi_lcn->lcnphy_current_index =
4300 (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4304 static void
4305 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4306 const struct lcnphy_tx_gain_tbl_entry *gain_table)
4308 u32 j;
4309 struct phytbl_info tab;
4310 u32 val;
4311 u16 pa_gain;
4312 u16 gm_gain;
4314 if (CHSPEC_IS5G(pi->radio_chanspec))
4315 pa_gain = 0x70;
4316 else
4317 pa_gain = 0x70;
4319 if (pi->sh->boardflags & BFL_FEM)
4320 pa_gain = 0x10;
4321 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4322 tab.tbl_width = 32;
4323 tab.tbl_len = 1;
4324 tab.tbl_ptr = &val;
4326 for (j = 0; j < 128; j++) {
4327 gm_gain = gain_table[j].gm;
4328 val = (((u32) pa_gain << 24) |
4329 (gain_table[j].pad << 16) |
4330 (gain_table[j].pga << 8) | gm_gain);
4332 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4333 wlc_lcnphy_write_table(pi, &tab);
4335 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4336 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4337 wlc_lcnphy_write_table(pi, &tab);
4341 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4343 struct phytbl_info tab;
4344 u32 val, bbmult, rfgain;
4345 u8 index;
4346 u8 scale_factor = 1;
4347 s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4349 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4350 tab.tbl_width = 32;
4351 tab.tbl_len = 1;
4353 for (index = 0; index < 128; index++) {
4354 tab.tbl_ptr = &bbmult;
4355 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4356 wlc_lcnphy_read_table(pi, &tab);
4357 bbmult = bbmult >> 20;
4359 tab.tbl_ptr = &rfgain;
4360 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4361 wlc_lcnphy_read_table(pi, &tab);
4363 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4364 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4366 if (qQ1 < qQ2) {
4367 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4368 qQ = qQ1;
4369 } else {
4370 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4371 qQ = qQ2;
4373 temp = qm_sub16(temp1, temp2);
4375 if (qQ >= 4)
4376 shift = qQ - 4;
4377 else
4378 shift = 4 - qQ;
4380 val = (((index << shift) + (5 * temp) +
4381 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4382 shift - 2));
4384 tab.tbl_ptr = &val;
4385 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4386 wlc_lcnphy_write_table(pi, &tab);
4390 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4392 or_phy_reg(pi, 0x805, 0x1);
4394 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4396 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4398 write_phy_reg(pi, 0x414, 0x1e10);
4399 write_phy_reg(pi, 0x415, 0x0640);
4401 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4403 or_phy_reg(pi, 0x44a, 0x44);
4404 write_phy_reg(pi, 0x44a, 0x80);
4405 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4407 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4409 if (!(pi->sh->boardrev < 0x1204))
4410 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4412 write_phy_reg(pi, 0x7d6, 0x0902);
4413 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4415 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4417 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4418 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4420 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4422 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4424 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4426 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4428 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4429 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4430 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4431 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4432 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4434 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4436 wlc_lcnphy_clear_tx_power_offsets(pi);
4437 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4442 static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4444 u8 rcal_value;
4446 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4448 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4449 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4451 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4452 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4454 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4456 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4457 mdelay(5);
4458 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4460 if (wlc_radio_2064_rcal_done(pi)) {
4461 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4462 rcal_value = rcal_value & 0x1f;
4465 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4467 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4470 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4472 u8 dflt_rc_cal_val;
4473 u16 flt_val;
4475 dflt_rc_cal_val = 7;
4476 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4477 dflt_rc_cal_val = 11;
4478 flt_val =
4479 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4480 (dflt_rc_cal_val);
4481 write_phy_reg(pi, 0x933, flt_val);
4482 write_phy_reg(pi, 0x934, flt_val);
4483 write_phy_reg(pi, 0x935, flt_val);
4484 write_phy_reg(pi, 0x936, flt_val);
4485 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4487 return;
4490 static void wlc_radio_2064_init(struct brcms_phy *pi)
4492 u32 i;
4493 const struct lcnphy_radio_regs *lcnphyregs = NULL;
4495 lcnphyregs = lcnphy_radio_regs_2064;
4497 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4498 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4499 write_radio_reg(pi,
4500 ((lcnphyregs[i].address & 0x3fff) |
4501 RADIO_DEFAULT_CORE),
4502 (u16) lcnphyregs[i].init_a);
4503 else if (lcnphyregs[i].do_init_g)
4504 write_radio_reg(pi,
4505 ((lcnphyregs[i].address & 0x3fff) |
4506 RADIO_DEFAULT_CORE),
4507 (u16) lcnphyregs[i].init_g);
4509 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4510 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4512 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4514 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4516 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4518 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4519 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4520 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4523 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4524 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4526 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4528 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4530 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4532 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4534 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4536 write_phy_reg(pi, 0x4ea, 0x4688);
4538 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4540 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4542 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4544 wlc_lcnphy_set_tx_locc(pi, 0);
4546 wlc_lcnphy_rcal(pi);
4548 wlc_lcnphy_rc_cal(pi);
4551 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4553 wlc_radio_2064_init(pi);
4556 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4558 uint idx;
4559 u8 phybw40;
4560 struct phytbl_info tab;
4561 u32 val;
4563 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4565 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4566 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4568 if (pi->sh->boardflags & BFL_FEM_BT) {
4569 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4570 tab.tbl_width = 16;
4571 tab.tbl_ptr = &val;
4572 tab.tbl_len = 1;
4573 val = 100;
4574 tab.tbl_offset = 4;
4575 wlc_lcnphy_write_table(pi, &tab);
4578 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4579 tab.tbl_width = 16;
4580 tab.tbl_ptr = &val;
4581 tab.tbl_len = 1;
4583 val = 114;
4584 tab.tbl_offset = 0;
4585 wlc_lcnphy_write_table(pi, &tab);
4587 val = 130;
4588 tab.tbl_offset = 1;
4589 wlc_lcnphy_write_table(pi, &tab);
4591 val = 6;
4592 tab.tbl_offset = 8;
4593 wlc_lcnphy_write_table(pi, &tab);
4595 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4596 if (pi->sh->boardflags & BFL_FEM)
4597 wlc_lcnphy_load_tx_gain_table(
4599 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4600 else
4601 wlc_lcnphy_load_tx_gain_table(
4603 dot11lcnphy_2GHz_gaintable_rev0);
4606 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4607 const struct phytbl_info *tb;
4608 int l;
4610 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4611 l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4612 if (pi->sh->boardflags & BFL_EXTLNA)
4613 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4614 else
4615 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4616 } else {
4617 l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4618 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4619 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4620 else
4621 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4624 for (idx = 0; idx < l; idx++)
4625 wlc_lcnphy_write_table(pi, &tb[idx]);
4628 if ((pi->sh->boardflags & BFL_FEM)
4629 && !(pi->sh->boardflags & BFL_FEM_BT))
4630 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4631 else if (pi->sh->boardflags & BFL_FEM_BT) {
4632 if (pi->sh->boardrev < 0x1250)
4633 wlc_lcnphy_write_table(
4635 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4636 else
4637 wlc_lcnphy_write_table(
4639 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4640 } else
4641 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4643 wlc_lcnphy_load_rfpower(pi);
4645 wlc_lcnphy_clear_papd_comptable(pi);
4648 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4650 u16 afectrl1;
4651 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4653 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4655 write_phy_reg(pi, 0x43b, 0x0);
4656 write_phy_reg(pi, 0x43c, 0x0);
4657 write_phy_reg(pi, 0x44c, 0x0);
4658 write_phy_reg(pi, 0x4e6, 0x0);
4659 write_phy_reg(pi, 0x4f9, 0x0);
4660 write_phy_reg(pi, 0x4b0, 0x0);
4661 write_phy_reg(pi, 0x938, 0x0);
4662 write_phy_reg(pi, 0x4b0, 0x0);
4663 write_phy_reg(pi, 0x44e, 0);
4665 or_phy_reg(pi, 0x567, 0x03);
4667 or_phy_reg(pi, 0x44a, 0x44);
4668 write_phy_reg(pi, 0x44a, 0x80);
4670 if (!(pi->sh->boardflags & BFL_FEM))
4671 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4673 if (0) {
4674 afectrl1 = 0;
4675 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4676 (pi_lcn->lcnphy_rssi_vc << 4) |
4677 (pi_lcn->lcnphy_rssi_gs << 10));
4678 write_phy_reg(pi, 0x43e, afectrl1);
4681 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4682 if (pi->sh->boardflags & BFL_FEM) {
4683 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4685 write_phy_reg(pi, 0x910, 0x1);
4688 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4689 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4690 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4694 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4696 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4697 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4698 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4702 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4704 s16 temp;
4705 struct phytbl_info tab;
4706 u32 tableBuffer[2];
4707 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4709 temp = (s16) read_phy_reg(pi, 0x4df);
4710 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4712 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4713 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4715 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4717 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4718 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4720 tab.tbl_ptr = tableBuffer;
4721 tab.tbl_len = 2;
4722 tab.tbl_id = 17;
4723 tab.tbl_offset = 59;
4724 tab.tbl_width = 32;
4725 wlc_lcnphy_read_table(pi, &tab);
4727 if (tableBuffer[0] > 63)
4728 tableBuffer[0] -= 128;
4729 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4731 if (tableBuffer[1] > 63)
4732 tableBuffer[1] -= 128;
4733 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4735 temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4736 if (temp > 127)
4737 temp -= 256;
4738 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4740 pi_lcn->lcnphy_Med_Low_Gain_db =
4741 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4742 pi_lcn->lcnphy_Very_Low_Gain_db =
4743 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4745 tab.tbl_ptr = tableBuffer;
4746 tab.tbl_len = 2;
4747 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4748 tab.tbl_offset = 28;
4749 tab.tbl_width = 32;
4750 wlc_lcnphy_read_table(pi, &tab);
4752 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4753 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4757 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4760 wlc_lcnphy_tbl_init(pi);
4761 wlc_lcnphy_rev0_baseband_init(pi);
4762 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4763 wlc_lcnphy_rev2_baseband_init(pi);
4764 wlc_lcnphy_bu_tweaks(pi);
4767 void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4769 u8 phybw40;
4770 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4771 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4773 pi_lcn->lcnphy_cal_counter = 0;
4774 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4776 or_phy_reg(pi, 0x44a, 0x80);
4777 and_phy_reg(pi, 0x44a, 0x7f);
4779 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4781 write_phy_reg(pi, 0x60a, 160);
4783 write_phy_reg(pi, 0x46a, 25);
4785 wlc_lcnphy_baseband_init(pi);
4787 wlc_lcnphy_radio_init(pi);
4789 if (CHSPEC_IS2G(pi->radio_chanspec))
4790 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4792 wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4794 si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
4796 si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
4798 if ((pi->sh->boardflags & BFL_FEM)
4799 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4800 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4802 wlc_lcnphy_agc_temp_init(pi);
4804 wlc_lcnphy_temp_adj(pi);
4806 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4808 udelay(100);
4809 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4811 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4812 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4813 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4816 static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4818 s8 txpwr = 0;
4819 int i;
4820 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4821 struct phy_shim_info *shim = pi->sh->physhim;
4823 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4824 u16 cckpo = 0;
4825 u32 offset_ofdm, offset_mcs;
4827 pi_lcn->lcnphy_tr_isolation_mid =
4828 (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
4830 pi_lcn->lcnphy_rx_power_offset =
4831 (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
4833 pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
4834 pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
4835 pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
4837 pi_lcn->lcnphy_rssi_vf =
4838 (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
4839 pi_lcn->lcnphy_rssi_vc =
4840 (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
4841 pi_lcn->lcnphy_rssi_gs =
4842 (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
4844 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4845 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4846 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4848 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4849 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4850 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4852 txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
4853 pi->tx_srom_max_2g = txpwr;
4855 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4856 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4857 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4860 cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
4861 offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
4862 if (cckpo) {
4863 uint max_pwr_chan = txpwr;
4865 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4866 pi->tx_srom_max_rate_2g[i] =
4867 max_pwr_chan - ((cckpo & 0xf) * 2);
4868 cckpo >>= 4;
4871 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4872 pi->tx_srom_max_rate_2g[i] =
4873 max_pwr_chan -
4874 ((offset_ofdm & 0xf) * 2);
4875 offset_ofdm >>= 4;
4877 } else {
4878 u8 opo = 0;
4880 opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
4882 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4883 pi->tx_srom_max_rate_2g[i] = txpwr;
4885 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4886 pi->tx_srom_max_rate_2g[i] = txpwr -
4887 ((offset_ofdm & 0xf) * 2);
4888 offset_ofdm >>= 4;
4890 offset_mcs =
4891 wlapi_getintvar(shim,
4892 BRCMS_SROM_MCS2GPO1) << 16;
4893 offset_mcs |=
4894 (u16) wlapi_getintvar(shim,
4895 BRCMS_SROM_MCS2GPO0);
4896 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4897 for (i = TXP_FIRST_SISO_MCS_20;
4898 i <= TXP_LAST_SISO_MCS_20; i++) {
4899 pi->tx_srom_max_rate_2g[i] =
4900 txpwr - ((offset_mcs & 0xf) * 2);
4901 offset_mcs >>= 4;
4905 pi_lcn->lcnphy_rawtempsense =
4906 (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
4907 pi_lcn->lcnphy_measPower =
4908 (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
4909 pi_lcn->lcnphy_tempsense_slope =
4910 (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
4911 pi_lcn->lcnphy_hw_iqcal_en =
4912 (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
4913 pi_lcn->lcnphy_iqcal_swp_dis =
4914 (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
4915 pi_lcn->lcnphy_tempcorrx =
4916 (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
4917 pi_lcn->lcnphy_tempsense_option =
4918 (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
4919 pi_lcn->lcnphy_freqoffset_corr =
4920 (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
4921 if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
4922 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4923 (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
4925 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4927 return true;
4930 void wlc_2064_vco_cal(struct brcms_phy *pi)
4932 u8 calnrst;
4934 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4935 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4936 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4937 udelay(1);
4938 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4939 udelay(1);
4940 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4941 udelay(300);
4942 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4945 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4947 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4948 return 0;
4949 else
4950 return (LCNPHY_TX_PWR_CTRL_HW ==
4951 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
4954 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
4956 u16 pwr_ctrl;
4957 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4958 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
4959 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4960 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4961 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
4962 wlc_lcnphy_txpower_recalc_target(pi);
4963 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
4967 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
4969 kfree(pi->u.pi_lcnphy);
4972 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
4974 struct brcms_phy_lcnphy *pi_lcn;
4976 pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
4977 if (pi->u.pi_lcnphy == NULL)
4978 return false;
4980 pi_lcn = pi->u.pi_lcnphy;
4982 if (0 == (pi->sh->boardflags & BFL_NOPA)) {
4983 pi->hwpwrctrl = true;
4984 pi->hwpwrctrl_capable = true;
4987 pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
4988 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
4990 pi->pi_fptr.init = wlc_phy_init_lcnphy;
4991 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
4992 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
4993 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
4994 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
4995 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
4996 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
4997 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
4998 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5000 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5001 return false;
5003 if ((pi->sh->boardflags & BFL_FEM) &&
5004 (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5005 if (pi_lcn->lcnphy_tempsense_option == 3) {
5006 pi->hwpwrctrl = true;
5007 pi->hwpwrctrl_capable = true;
5008 pi->temppwrctrl_capable = false;
5009 } else {
5010 pi->hwpwrctrl = false;
5011 pi->hwpwrctrl_capable = false;
5012 pi->temppwrctrl_capable = true;
5016 return true;
5019 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5021 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5023 trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5024 ext_lna = (u16) (gain >> 29) & 0x01;
5025 lna1 = (u16) (gain >> 0) & 0x0f;
5026 lna2 = (u16) (gain >> 4) & 0x0f;
5027 tia = (u16) (gain >> 8) & 0xf;
5028 biq0 = (u16) (gain >> 12) & 0xf;
5029 biq1 = (u16) (gain >> 16) & 0xf;
5031 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5032 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5033 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5034 gain16_19 = biq1;
5036 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5037 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5038 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5039 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5040 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5042 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5043 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5044 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5046 wlc_lcnphy_rx_gain_override_enable(pi, true);
5049 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5051 u32 received_power = 0;
5052 s32 max_index = 0;
5053 u32 gain_code = 0;
5054 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5056 max_index = 36;
5057 if (*gain_index >= 0)
5058 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5060 if (-1 == *gain_index) {
5061 *gain_index = 0;
5062 while ((*gain_index <= (s32) max_index)
5063 && (received_power < 700)) {
5064 wlc_lcnphy_set_rx_gain(pi,
5065 lcnphy_23bitgaincode_table
5066 [*gain_index]);
5067 received_power =
5068 wlc_lcnphy_measure_digital_power(
5070 pi_lcn->
5071 lcnphy_noise_samples);
5072 (*gain_index)++;
5074 (*gain_index)--;
5075 } else {
5076 wlc_lcnphy_set_rx_gain(pi, gain_code);
5077 received_power =
5078 wlc_lcnphy_measure_digital_power(pi,
5079 pi_lcn->
5080 lcnphy_noise_samples);
5083 return received_power;
5086 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5088 s32 gain = 0;
5089 s32 nominal_power_db;
5090 s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5091 input_power_db;
5092 s32 received_power, temperature;
5093 u32 power;
5094 u32 msb1, msb2, val1, val2, diff1, diff2;
5095 uint freq;
5096 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5098 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5100 gain = lcnphy_gain_table[gain_index];
5102 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5104 power = (received_power * 16);
5105 msb1 = ffs(power) - 1;
5106 msb2 = msb1 + 1;
5107 val1 = 1 << msb1;
5108 val2 = 1 << msb2;
5109 diff1 = (power - val1);
5110 diff2 = (val2 - power);
5111 if (diff1 < diff2)
5112 log_val = msb1;
5113 else
5114 log_val = msb2;
5116 log_val = log_val * 3;
5118 gain_mismatch = (nominal_power_db / 2) - (log_val);
5120 desired_gain = gain + gain_mismatch;
5122 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5124 if (input_power_offset_db > 127)
5125 input_power_offset_db -= 256;
5127 input_power_db = input_power_offset_db - desired_gain;
5129 input_power_db =
5130 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5132 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5133 if ((freq > 2427) && (freq <= 2467))
5134 input_power_db = input_power_db - 1;
5136 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5138 if ((temperature - 15) < -30)
5139 input_power_db =
5140 input_power_db +
5141 (((temperature - 10 - 25) * 286) >> 12) -
5143 else if ((temperature - 15) < 4)
5144 input_power_db =
5145 input_power_db +
5146 (((temperature - 10 - 25) * 286) >> 12) -
5148 else
5149 input_power_db = input_power_db +
5150 (((temperature - 10 - 25) * 286) >> 12);
5152 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5154 return input_power_db;