brcmsmac: change lcnphy receive i/q calibration routine
[linux/fpc-iii.git] / drivers / net / wireless / brcm80211 / brcmsmac / phy / phy_lcn.c
blob236e8d90a5bc7460291e95b2cec26a9b9ccd96e2
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 ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
213 static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
214 {965, 1087},
215 {967, 1085},
216 {969, 1082},
217 {971, 1080},
218 {973, 1078},
219 {975, 1076},
220 {977, 1073},
221 {979, 1071},
222 {981, 1069},
223 {983, 1067},
224 {985, 1065},
225 {987, 1063},
226 {989, 1060},
227 {994, 1055}
230 static const
231 u16 lcnphy_iqcal_loft_gainladder[] = {
232 ((2 << 8) | 0),
233 ((3 << 8) | 0),
234 ((4 << 8) | 0),
235 ((6 << 8) | 0),
236 ((8 << 8) | 0),
237 ((11 << 8) | 0),
238 ((16 << 8) | 0),
239 ((16 << 8) | 1),
240 ((16 << 8) | 2),
241 ((16 << 8) | 3),
242 ((16 << 8) | 4),
243 ((16 << 8) | 5),
244 ((16 << 8) | 6),
245 ((16 << 8) | 7),
246 ((23 << 8) | 7),
247 ((32 << 8) | 7),
248 ((45 << 8) | 7),
249 ((64 << 8) | 7),
250 ((91 << 8) | 7),
251 ((128 << 8) | 7)
254 static const
255 u16 lcnphy_iqcal_ir_gainladder[] = {
256 ((1 << 8) | 0),
257 ((2 << 8) | 0),
258 ((4 << 8) | 0),
259 ((6 << 8) | 0),
260 ((8 << 8) | 0),
261 ((11 << 8) | 0),
262 ((16 << 8) | 0),
263 ((23 << 8) | 0),
264 ((32 << 8) | 0),
265 ((45 << 8) | 0),
266 ((64 << 8) | 0),
267 ((64 << 8) | 1),
268 ((64 << 8) | 2),
269 ((64 << 8) | 3),
270 ((64 << 8) | 4),
271 ((64 << 8) | 5),
272 ((64 << 8) | 6),
273 ((64 << 8) | 7),
274 ((91 << 8) | 7),
275 ((128 << 8) | 7)
278 static const
279 struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
280 {88, 0},
281 {73, 49},
282 {34, 81},
283 {-17, 86},
284 {-62, 62},
285 {-86, 17},
286 {-81, -34},
287 {-49, -73},
288 {0, -88},
289 {49, -73},
290 {81, -34},
291 {86, 17},
292 {62, 62},
293 {17, 86},
294 {-34, 81},
295 {-73, 49},
296 {-88, 0},
297 {-73, -49},
298 {-34, -81},
299 {17, -86},
300 {62, -62},
301 {86, -17},
302 {81, 34},
303 {49, 73},
304 {0, 88},
305 {-49, 73},
306 {-81, 34},
307 {-86, -17},
308 {-62, -62},
309 {-17, -86},
310 {34, -81},
311 {73, -49},
314 static const
315 u16 iqlo_loopback_rf_regs[20] = {
316 RADIO_2064_REG036,
317 RADIO_2064_REG11A,
318 RADIO_2064_REG03A,
319 RADIO_2064_REG025,
320 RADIO_2064_REG028,
321 RADIO_2064_REG005,
322 RADIO_2064_REG112,
323 RADIO_2064_REG0FF,
324 RADIO_2064_REG11F,
325 RADIO_2064_REG00B,
326 RADIO_2064_REG113,
327 RADIO_2064_REG007,
328 RADIO_2064_REG0FC,
329 RADIO_2064_REG0FD,
330 RADIO_2064_REG012,
331 RADIO_2064_REG057,
332 RADIO_2064_REG059,
333 RADIO_2064_REG05C,
334 RADIO_2064_REG078,
335 RADIO_2064_REG092,
338 static const
339 u16 tempsense_phy_regs[14] = {
340 0x503,
341 0x4a4,
342 0x4d0,
343 0x4d9,
344 0x4da,
345 0x4a6,
346 0x938,
347 0x939,
348 0x4d8,
349 0x4d0,
350 0x4d7,
351 0x4a5,
352 0x40d,
353 0x4a2,
356 static const
357 u16 rxiq_cal_rf_reg[11] = {
358 RADIO_2064_REG098,
359 RADIO_2064_REG116,
360 RADIO_2064_REG12C,
361 RADIO_2064_REG06A,
362 RADIO_2064_REG00B,
363 RADIO_2064_REG01B,
364 RADIO_2064_REG113,
365 RADIO_2064_REG01D,
366 RADIO_2064_REG114,
367 RADIO_2064_REG02E,
368 RADIO_2064_REG12A,
371 static const
372 struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
373 {1, 0, 0},
374 {2, 0, 0},
375 {3, 0, 0},
376 {4, 0, 0},
377 {5, 0, 0},
378 {6, 0, 0},
379 {7, 0, 0},
380 {8, 0, 0},
381 {9, 0, 0},
382 {10, 0, 0},
383 {11, 0, 0},
384 {12, 0, 0},
385 {13, 0, 0},
386 {14, 0, 0},
387 {34, 0, 0},
388 {38, 0, 0},
389 {42, 0, 0},
390 {46, 0, 0},
391 {36, 0, 0},
392 {40, 0, 0},
393 {44, 0, 0},
394 {48, 0, 0},
395 {52, 0, 0},
396 {56, 0, 0},
397 {60, 0, 0},
398 {64, 0, 0},
399 {100, 0, 0},
400 {104, 0, 0},
401 {108, 0, 0},
402 {112, 0, 0},
403 {116, 0, 0},
404 {120, 0, 0},
405 {124, 0, 0},
406 {128, 0, 0},
407 {132, 0, 0},
408 {136, 0, 0},
409 {140, 0, 0},
410 {149, 0, 0},
411 {153, 0, 0},
412 {157, 0, 0},
413 {161, 0, 0},
414 {165, 0, 0},
415 {184, 0, 0},
416 {188, 0, 0},
417 {192, 0, 0},
418 {196, 0, 0},
419 {200, 0, 0},
420 {204, 0, 0},
421 {208, 0, 0},
422 {212, 0, 0},
423 {216, 0, 0},
426 static const u32 lcnphy_23bitgaincode_table[] = {
427 0x200100,
428 0x200200,
429 0x200004,
430 0x200014,
431 0x200024,
432 0x200034,
433 0x200134,
434 0x200234,
435 0x200334,
436 0x200434,
437 0x200037,
438 0x200137,
439 0x200237,
440 0x200337,
441 0x200437,
442 0x000035,
443 0x000135,
444 0x000235,
445 0x000037,
446 0x000137,
447 0x000237,
448 0x000337,
449 0x00013f,
450 0x00023f,
451 0x00033f,
452 0x00034f,
453 0x00044f,
454 0x00144f,
455 0x00244f,
456 0x00254f,
457 0x00354f,
458 0x00454f,
459 0x00464f,
460 0x01464f,
461 0x02464f,
462 0x03464f,
463 0x04464f,
466 static const s8 lcnphy_gain_table[] = {
467 -16,
468 -13,
506 static const s8 lcnphy_gain_index_offset_for_rssi[] = {
547 struct chan_info_2064_lcnphy {
548 uint chan;
549 uint freq;
550 u8 logen_buftune;
551 u8 logen_rccr_tx;
552 u8 txrf_mix_tune_ctrl;
553 u8 pa_input_tune_g;
554 u8 logen_rccr_rx;
555 u8 pa_rxrf_lna1_freq_tune;
556 u8 pa_rxrf_lna2_freq_tune;
557 u8 rxrf_rxrf_spare1;
560 static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
561 {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
562 {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
563 {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
564 {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
565 {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
566 {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
567 {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
568 {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
569 {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
570 {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
571 {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
572 {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
573 {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
574 {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
577 static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
578 {0x00, 0, 0, 0, 0},
579 {0x01, 0x64, 0x64, 0, 0},
580 {0x02, 0x20, 0x20, 0, 0},
581 {0x03, 0x66, 0x66, 0, 0},
582 {0x04, 0xf8, 0xf8, 0, 0},
583 {0x05, 0, 0, 0, 0},
584 {0x06, 0x10, 0x10, 0, 0},
585 {0x07, 0, 0, 0, 0},
586 {0x08, 0, 0, 0, 0},
587 {0x09, 0, 0, 0, 0},
588 {0x0A, 0x37, 0x37, 0, 0},
589 {0x0B, 0x6, 0x6, 0, 0},
590 {0x0C, 0x55, 0x55, 0, 0},
591 {0x0D, 0x8b, 0x8b, 0, 0},
592 {0x0E, 0, 0, 0, 0},
593 {0x0F, 0x5, 0x5, 0, 0},
594 {0x10, 0, 0, 0, 0},
595 {0x11, 0xe, 0xe, 0, 0},
596 {0x12, 0, 0, 0, 0},
597 {0x13, 0xb, 0xb, 0, 0},
598 {0x14, 0x2, 0x2, 0, 0},
599 {0x15, 0x12, 0x12, 0, 0},
600 {0x16, 0x12, 0x12, 0, 0},
601 {0x17, 0xc, 0xc, 0, 0},
602 {0x18, 0xc, 0xc, 0, 0},
603 {0x19, 0xc, 0xc, 0, 0},
604 {0x1A, 0x8, 0x8, 0, 0},
605 {0x1B, 0x2, 0x2, 0, 0},
606 {0x1C, 0, 0, 0, 0},
607 {0x1D, 0x1, 0x1, 0, 0},
608 {0x1E, 0x12, 0x12, 0, 0},
609 {0x1F, 0x6e, 0x6e, 0, 0},
610 {0x20, 0x2, 0x2, 0, 0},
611 {0x21, 0x23, 0x23, 0, 0},
612 {0x22, 0x8, 0x8, 0, 0},
613 {0x23, 0, 0, 0, 0},
614 {0x24, 0, 0, 0, 0},
615 {0x25, 0xc, 0xc, 0, 0},
616 {0x26, 0x33, 0x33, 0, 0},
617 {0x27, 0x55, 0x55, 0, 0},
618 {0x28, 0, 0, 0, 0},
619 {0x29, 0x30, 0x30, 0, 0},
620 {0x2A, 0xb, 0xb, 0, 0},
621 {0x2B, 0x1b, 0x1b, 0, 0},
622 {0x2C, 0x3, 0x3, 0, 0},
623 {0x2D, 0x1b, 0x1b, 0, 0},
624 {0x2E, 0, 0, 0, 0},
625 {0x2F, 0x20, 0x20, 0, 0},
626 {0x30, 0xa, 0xa, 0, 0},
627 {0x31, 0, 0, 0, 0},
628 {0x32, 0x62, 0x62, 0, 0},
629 {0x33, 0x19, 0x19, 0, 0},
630 {0x34, 0x33, 0x33, 0, 0},
631 {0x35, 0x77, 0x77, 0, 0},
632 {0x36, 0, 0, 0, 0},
633 {0x37, 0x70, 0x70, 0, 0},
634 {0x38, 0x3, 0x3, 0, 0},
635 {0x39, 0xf, 0xf, 0, 0},
636 {0x3A, 0x6, 0x6, 0, 0},
637 {0x3B, 0xcf, 0xcf, 0, 0},
638 {0x3C, 0x1a, 0x1a, 0, 0},
639 {0x3D, 0x6, 0x6, 0, 0},
640 {0x3E, 0x42, 0x42, 0, 0},
641 {0x3F, 0, 0, 0, 0},
642 {0x40, 0xfb, 0xfb, 0, 0},
643 {0x41, 0x9a, 0x9a, 0, 0},
644 {0x42, 0x7a, 0x7a, 0, 0},
645 {0x43, 0x29, 0x29, 0, 0},
646 {0x44, 0, 0, 0, 0},
647 {0x45, 0x8, 0x8, 0, 0},
648 {0x46, 0xce, 0xce, 0, 0},
649 {0x47, 0x27, 0x27, 0, 0},
650 {0x48, 0x62, 0x62, 0, 0},
651 {0x49, 0x6, 0x6, 0, 0},
652 {0x4A, 0x58, 0x58, 0, 0},
653 {0x4B, 0xf7, 0xf7, 0, 0},
654 {0x4C, 0, 0, 0, 0},
655 {0x4D, 0xb3, 0xb3, 0, 0},
656 {0x4E, 0, 0, 0, 0},
657 {0x4F, 0x2, 0x2, 0, 0},
658 {0x50, 0, 0, 0, 0},
659 {0x51, 0x9, 0x9, 0, 0},
660 {0x52, 0x5, 0x5, 0, 0},
661 {0x53, 0x17, 0x17, 0, 0},
662 {0x54, 0x38, 0x38, 0, 0},
663 {0x55, 0, 0, 0, 0},
664 {0x56, 0, 0, 0, 0},
665 {0x57, 0xb, 0xb, 0, 0},
666 {0x58, 0, 0, 0, 0},
667 {0x59, 0, 0, 0, 0},
668 {0x5A, 0, 0, 0, 0},
669 {0x5B, 0, 0, 0, 0},
670 {0x5C, 0, 0, 0, 0},
671 {0x5D, 0, 0, 0, 0},
672 {0x5E, 0x88, 0x88, 0, 0},
673 {0x5F, 0xcc, 0xcc, 0, 0},
674 {0x60, 0x74, 0x74, 0, 0},
675 {0x61, 0x74, 0x74, 0, 0},
676 {0x62, 0x74, 0x74, 0, 0},
677 {0x63, 0x44, 0x44, 0, 0},
678 {0x64, 0x77, 0x77, 0, 0},
679 {0x65, 0x44, 0x44, 0, 0},
680 {0x66, 0x77, 0x77, 0, 0},
681 {0x67, 0x55, 0x55, 0, 0},
682 {0x68, 0x77, 0x77, 0, 0},
683 {0x69, 0x77, 0x77, 0, 0},
684 {0x6A, 0, 0, 0, 0},
685 {0x6B, 0x7f, 0x7f, 0, 0},
686 {0x6C, 0x8, 0x8, 0, 0},
687 {0x6D, 0, 0, 0, 0},
688 {0x6E, 0x88, 0x88, 0, 0},
689 {0x6F, 0x66, 0x66, 0, 0},
690 {0x70, 0x66, 0x66, 0, 0},
691 {0x71, 0x28, 0x28, 0, 0},
692 {0x72, 0x55, 0x55, 0, 0},
693 {0x73, 0x4, 0x4, 0, 0},
694 {0x74, 0, 0, 0, 0},
695 {0x75, 0, 0, 0, 0},
696 {0x76, 0, 0, 0, 0},
697 {0x77, 0x1, 0x1, 0, 0},
698 {0x78, 0xd6, 0xd6, 0, 0},
699 {0x79, 0, 0, 0, 0},
700 {0x7A, 0, 0, 0, 0},
701 {0x7B, 0, 0, 0, 0},
702 {0x7C, 0, 0, 0, 0},
703 {0x7D, 0, 0, 0, 0},
704 {0x7E, 0, 0, 0, 0},
705 {0x7F, 0, 0, 0, 0},
706 {0x80, 0, 0, 0, 0},
707 {0x81, 0, 0, 0, 0},
708 {0x82, 0, 0, 0, 0},
709 {0x83, 0xb4, 0xb4, 0, 0},
710 {0x84, 0x1, 0x1, 0, 0},
711 {0x85, 0x20, 0x20, 0, 0},
712 {0x86, 0x5, 0x5, 0, 0},
713 {0x87, 0xff, 0xff, 0, 0},
714 {0x88, 0x7, 0x7, 0, 0},
715 {0x89, 0x77, 0x77, 0, 0},
716 {0x8A, 0x77, 0x77, 0, 0},
717 {0x8B, 0x77, 0x77, 0, 0},
718 {0x8C, 0x77, 0x77, 0, 0},
719 {0x8D, 0x8, 0x8, 0, 0},
720 {0x8E, 0xa, 0xa, 0, 0},
721 {0x8F, 0x8, 0x8, 0, 0},
722 {0x90, 0x18, 0x18, 0, 0},
723 {0x91, 0x5, 0x5, 0, 0},
724 {0x92, 0x1f, 0x1f, 0, 0},
725 {0x93, 0x10, 0x10, 0, 0},
726 {0x94, 0x3, 0x3, 0, 0},
727 {0x95, 0, 0, 0, 0},
728 {0x96, 0, 0, 0, 0},
729 {0x97, 0xaa, 0xaa, 0, 0},
730 {0x98, 0, 0, 0, 0},
731 {0x99, 0x23, 0x23, 0, 0},
732 {0x9A, 0x7, 0x7, 0, 0},
733 {0x9B, 0xf, 0xf, 0, 0},
734 {0x9C, 0x10, 0x10, 0, 0},
735 {0x9D, 0x3, 0x3, 0, 0},
736 {0x9E, 0x4, 0x4, 0, 0},
737 {0x9F, 0x20, 0x20, 0, 0},
738 {0xA0, 0, 0, 0, 0},
739 {0xA1, 0, 0, 0, 0},
740 {0xA2, 0, 0, 0, 0},
741 {0xA3, 0, 0, 0, 0},
742 {0xA4, 0x1, 0x1, 0, 0},
743 {0xA5, 0x77, 0x77, 0, 0},
744 {0xA6, 0x77, 0x77, 0, 0},
745 {0xA7, 0x77, 0x77, 0, 0},
746 {0xA8, 0x77, 0x77, 0, 0},
747 {0xA9, 0x8c, 0x8c, 0, 0},
748 {0xAA, 0x88, 0x88, 0, 0},
749 {0xAB, 0x78, 0x78, 0, 0},
750 {0xAC, 0x57, 0x57, 0, 0},
751 {0xAD, 0x88, 0x88, 0, 0},
752 {0xAE, 0, 0, 0, 0},
753 {0xAF, 0x8, 0x8, 0, 0},
754 {0xB0, 0x88, 0x88, 0, 0},
755 {0xB1, 0, 0, 0, 0},
756 {0xB2, 0x1b, 0x1b, 0, 0},
757 {0xB3, 0x3, 0x3, 0, 0},
758 {0xB4, 0x24, 0x24, 0, 0},
759 {0xB5, 0x3, 0x3, 0, 0},
760 {0xB6, 0x1b, 0x1b, 0, 0},
761 {0xB7, 0x24, 0x24, 0, 0},
762 {0xB8, 0x3, 0x3, 0, 0},
763 {0xB9, 0, 0, 0, 0},
764 {0xBA, 0xaa, 0xaa, 0, 0},
765 {0xBB, 0, 0, 0, 0},
766 {0xBC, 0x4, 0x4, 0, 0},
767 {0xBD, 0, 0, 0, 0},
768 {0xBE, 0x8, 0x8, 0, 0},
769 {0xBF, 0x11, 0x11, 0, 0},
770 {0xC0, 0, 0, 0, 0},
771 {0xC1, 0, 0, 0, 0},
772 {0xC2, 0x62, 0x62, 0, 0},
773 {0xC3, 0x1e, 0x1e, 0, 0},
774 {0xC4, 0x33, 0x33, 0, 0},
775 {0xC5, 0x37, 0x37, 0, 0},
776 {0xC6, 0, 0, 0, 0},
777 {0xC7, 0x70, 0x70, 0, 0},
778 {0xC8, 0x1e, 0x1e, 0, 0},
779 {0xC9, 0x6, 0x6, 0, 0},
780 {0xCA, 0x4, 0x4, 0, 0},
781 {0xCB, 0x2f, 0x2f, 0, 0},
782 {0xCC, 0xf, 0xf, 0, 0},
783 {0xCD, 0, 0, 0, 0},
784 {0xCE, 0xff, 0xff, 0, 0},
785 {0xCF, 0x8, 0x8, 0, 0},
786 {0xD0, 0x3f, 0x3f, 0, 0},
787 {0xD1, 0x3f, 0x3f, 0, 0},
788 {0xD2, 0x3f, 0x3f, 0, 0},
789 {0xD3, 0, 0, 0, 0},
790 {0xD4, 0, 0, 0, 0},
791 {0xD5, 0, 0, 0, 0},
792 {0xD6, 0xcc, 0xcc, 0, 0},
793 {0xD7, 0, 0, 0, 0},
794 {0xD8, 0x8, 0x8, 0, 0},
795 {0xD9, 0x8, 0x8, 0, 0},
796 {0xDA, 0x8, 0x8, 0, 0},
797 {0xDB, 0x11, 0x11, 0, 0},
798 {0xDC, 0, 0, 0, 0},
799 {0xDD, 0x87, 0x87, 0, 0},
800 {0xDE, 0x88, 0x88, 0, 0},
801 {0xDF, 0x8, 0x8, 0, 0},
802 {0xE0, 0x8, 0x8, 0, 0},
803 {0xE1, 0x8, 0x8, 0, 0},
804 {0xE2, 0, 0, 0, 0},
805 {0xE3, 0, 0, 0, 0},
806 {0xE4, 0, 0, 0, 0},
807 {0xE5, 0xf5, 0xf5, 0, 0},
808 {0xE6, 0x30, 0x30, 0, 0},
809 {0xE7, 0x1, 0x1, 0, 0},
810 {0xE8, 0, 0, 0, 0},
811 {0xE9, 0xff, 0xff, 0, 0},
812 {0xEA, 0, 0, 0, 0},
813 {0xEB, 0, 0, 0, 0},
814 {0xEC, 0x22, 0x22, 0, 0},
815 {0xED, 0, 0, 0, 0},
816 {0xEE, 0, 0, 0, 0},
817 {0xEF, 0, 0, 0, 0},
818 {0xF0, 0x3, 0x3, 0, 0},
819 {0xF1, 0x1, 0x1, 0, 0},
820 {0xF2, 0, 0, 0, 0},
821 {0xF3, 0, 0, 0, 0},
822 {0xF4, 0, 0, 0, 0},
823 {0xF5, 0, 0, 0, 0},
824 {0xF6, 0, 0, 0, 0},
825 {0xF7, 0x6, 0x6, 0, 0},
826 {0xF8, 0, 0, 0, 0},
827 {0xF9, 0, 0, 0, 0},
828 {0xFA, 0x40, 0x40, 0, 0},
829 {0xFB, 0, 0, 0, 0},
830 {0xFC, 0x1, 0x1, 0, 0},
831 {0xFD, 0x80, 0x80, 0, 0},
832 {0xFE, 0x2, 0x2, 0, 0},
833 {0xFF, 0x10, 0x10, 0, 0},
834 {0x100, 0x2, 0x2, 0, 0},
835 {0x101, 0x1e, 0x1e, 0, 0},
836 {0x102, 0x1e, 0x1e, 0, 0},
837 {0x103, 0, 0, 0, 0},
838 {0x104, 0x1f, 0x1f, 0, 0},
839 {0x105, 0, 0x8, 0, 1},
840 {0x106, 0x2a, 0x2a, 0, 0},
841 {0x107, 0xf, 0xf, 0, 0},
842 {0x108, 0, 0, 0, 0},
843 {0x109, 0, 0, 0, 0},
844 {0x10A, 0, 0, 0, 0},
845 {0x10B, 0, 0, 0, 0},
846 {0x10C, 0, 0, 0, 0},
847 {0x10D, 0, 0, 0, 0},
848 {0x10E, 0, 0, 0, 0},
849 {0x10F, 0, 0, 0, 0},
850 {0x110, 0, 0, 0, 0},
851 {0x111, 0, 0, 0, 0},
852 {0x112, 0, 0, 0, 0},
853 {0x113, 0, 0, 0, 0},
854 {0x114, 0, 0, 0, 0},
855 {0x115, 0, 0, 0, 0},
856 {0x116, 0, 0, 0, 0},
857 {0x117, 0, 0, 0, 0},
858 {0x118, 0, 0, 0, 0},
859 {0x119, 0, 0, 0, 0},
860 {0x11A, 0, 0, 0, 0},
861 {0x11B, 0, 0, 0, 0},
862 {0x11C, 0x1, 0x1, 0, 0},
863 {0x11D, 0, 0, 0, 0},
864 {0x11E, 0, 0, 0, 0},
865 {0x11F, 0, 0, 0, 0},
866 {0x120, 0, 0, 0, 0},
867 {0x121, 0, 0, 0, 0},
868 {0x122, 0x80, 0x80, 0, 0},
869 {0x123, 0, 0, 0, 0},
870 {0x124, 0xf8, 0xf8, 0, 0},
871 {0x125, 0, 0, 0, 0},
872 {0x126, 0, 0, 0, 0},
873 {0x127, 0, 0, 0, 0},
874 {0x128, 0, 0, 0, 0},
875 {0x129, 0, 0, 0, 0},
876 {0x12A, 0, 0, 0, 0},
877 {0x12B, 0, 0, 0, 0},
878 {0x12C, 0, 0, 0, 0},
879 {0x12D, 0, 0, 0, 0},
880 {0x12E, 0, 0, 0, 0},
881 {0x12F, 0, 0, 0, 0},
882 {0x130, 0, 0, 0, 0},
883 {0xFFFF, 0, 0, 0, 0}
886 #define LCNPHY_NUM_DIG_FILT_COEFFS 16
887 #define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
889 static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
890 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
891 {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
892 128, 64,},
893 {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
894 167, 93,},
895 {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
896 128, 64,},
897 {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
898 170, 340, 170,},
899 {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
900 256, 185, 256,},
901 {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
902 256, 273, 256,},
903 {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
904 256, 352, 256,},
905 {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
906 128, 233, 128,},
907 {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
908 1881, 256,},
909 {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
910 1881, 256,},
911 {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
912 384, 288,},
913 {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
914 128, 384, 288,},
915 {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
916 170, 340, 170,},
919 #define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
920 static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
921 [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
922 {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
923 0x278, 0xfea0, 0x80, 0x100, 0x80,},
924 {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
925 750, 0xFE2B, 212, 0xFFCE, 212,},
926 {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
927 0xFEF2, 128, 0xFFE2, 128}
930 #define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
931 mod_phy_reg(pi, 0x4a4, \
932 (0x1ff << 0), \
933 (u16)(idx) << 0)
935 #define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
936 mod_phy_reg(pi, 0x4a5, \
937 (0x7 << 8), \
938 (u16)(npt) << 8)
940 #define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
941 (read_phy_reg((pi), 0x4a4) & \
942 ((0x1 << 15) | \
943 (0x1 << 14) | \
944 (0x1 << 13)))
946 #define wlc_lcnphy_get_tx_pwr_npt(pi) \
947 ((read_phy_reg(pi, 0x4a5) & \
948 (0x7 << 8)) >> \
951 #define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
952 (read_phy_reg(pi, 0x473) & 0x1ff)
954 #define wlc_lcnphy_get_target_tx_pwr(pi) \
955 ((read_phy_reg(pi, 0x4a7) & \
956 (0xff << 0)) >> \
959 #define wlc_lcnphy_set_target_tx_pwr(pi, target) \
960 mod_phy_reg(pi, 0x4a7, \
961 (0xff << 0), \
962 (u16)(target) << 0)
964 #define wlc_radio_2064_rcal_done(pi) \
965 (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
967 #define tempsense_done(pi) \
968 (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
970 #define LCNPHY_IQLOCC_READ(val) \
971 ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
973 #define FIXED_TXPWR 78
974 #define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
976 void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
978 wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
981 void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
983 wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
986 static void
987 wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
988 const u16 *tbl_ptr, u32 tbl_len,
989 u32 tbl_width, u32 tbl_offset)
991 struct phytbl_info tab;
992 tab.tbl_id = tbl_id;
993 tab.tbl_ptr = tbl_ptr;
994 tab.tbl_len = tbl_len;
995 tab.tbl_width = tbl_width;
996 tab.tbl_offset = tbl_offset;
997 wlc_lcnphy_read_table(pi, &tab);
1000 static void
1001 wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
1002 const u16 *tbl_ptr, u32 tbl_len,
1003 u32 tbl_width, u32 tbl_offset)
1006 struct phytbl_info tab;
1007 tab.tbl_id = tbl_id;
1008 tab.tbl_ptr = tbl_ptr;
1009 tab.tbl_len = tbl_len;
1010 tab.tbl_width = tbl_width;
1011 tab.tbl_offset = tbl_offset;
1012 wlc_lcnphy_write_table(pi, &tab);
1015 static u32
1016 wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1018 u32 quotient, remainder, roundup, rbit;
1020 quotient = dividend / divisor;
1021 remainder = dividend % divisor;
1022 rbit = divisor & 1;
1023 roundup = (divisor >> 1) + rbit;
1025 while (precision--) {
1026 quotient <<= 1;
1027 if (remainder >= roundup) {
1028 quotient++;
1029 remainder = ((remainder - roundup) << 1) + rbit;
1030 } else {
1031 remainder <<= 1;
1035 if (remainder >= roundup)
1036 quotient++;
1038 return quotient;
1041 static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1043 int k;
1044 k = 0;
1045 if (type == 0) {
1046 if (coeff_x < 0)
1047 k = (coeff_x - 1) / 2;
1048 else
1049 k = coeff_x / 2;
1052 if (type == 1) {
1053 if ((coeff_x + 1) < 0)
1054 k = (coeff_x) / 2;
1055 else
1056 k = (coeff_x + 1) / 2;
1058 return k;
1061 static void
1062 wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
1064 u16 dac_gain, rfgain0, rfgain1;
1066 dac_gain = read_phy_reg(pi, 0x439) >> 0;
1067 gains->dac_gain = (dac_gain & 0x380) >> 7;
1069 rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
1070 rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
1072 gains->gm_gain = rfgain0 & 0xff;
1073 gains->pga_gain = (rfgain0 >> 8) & 0xff;
1074 gains->pad_gain = rfgain1 & 0xff;
1078 static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
1080 u16 dac_ctrl;
1082 dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1083 dac_ctrl = dac_ctrl & 0xc7f;
1084 dac_ctrl = dac_ctrl | (dac_gain << 7);
1085 mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1089 static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
1091 u16 bit = bEnable ? 1 : 0;
1093 mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1095 mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1097 mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1100 static void
1101 wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
1103 u16 ebit = enable ? 1 : 0;
1105 mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
1107 mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
1109 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1110 mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
1111 mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
1112 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1113 mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
1114 } else {
1115 mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
1116 mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
1117 mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1120 if (CHSPEC_IS2G(pi->radio_chanspec)) {
1121 mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
1122 mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
1126 static void
1127 wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
1128 u16 trsw,
1129 u16 ext_lna,
1130 u16 biq2,
1131 u16 biq1,
1132 u16 tia, u16 lna2, u16 lna1)
1134 u16 gain0_15, gain16_19;
1136 gain16_19 = biq2 & 0xf;
1137 gain0_15 = ((biq1 & 0xf) << 12) |
1138 ((tia & 0xf) << 8) |
1139 ((lna2 & 0x3) << 6) |
1140 ((lna2 & 0x3) << 4) |
1141 ((lna1 & 0x3) << 2) |
1142 ((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 wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
1333 u16 tia_gain, u16 lna2_gain)
1335 u32 i_thresh_l, q_thresh_l;
1336 u32 i_thresh_h, q_thresh_h;
1337 struct lcnphy_iq_est iq_est_h, iq_est_l;
1339 wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
1340 lna2_gain, 0);
1342 wlc_lcnphy_rx_gain_override_enable(pi, true);
1343 wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
1344 udelay(500);
1345 write_radio_reg(pi, RADIO_2064_REG112, 0);
1346 if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
1347 return false;
1349 wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
1350 udelay(500);
1351 write_radio_reg(pi, RADIO_2064_REG112, 0);
1352 if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
1353 return false;
1355 i_thresh_l = (iq_est_l.i_pwr << 1);
1356 i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
1358 q_thresh_l = (iq_est_l.q_pwr << 1);
1359 q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
1360 if ((iq_est_h.i_pwr > i_thresh_l) &&
1361 (iq_est_h.i_pwr < i_thresh_h) &&
1362 (iq_est_h.q_pwr > q_thresh_l) &&
1363 (iq_est_h.q_pwr < q_thresh_h))
1364 return true;
1366 return false;
1369 static bool
1370 wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1371 const struct lcnphy_rx_iqcomp *iqcomp,
1372 int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1373 int tx_gain_idx)
1375 struct lcnphy_txgains old_gains;
1376 u16 tx_pwr_ctrl;
1377 u8 tx_gain_index_old = 0;
1378 bool result = false, tx_gain_override_old = false;
1379 u16 i, Core1TxControl_old, RFOverride0_old,
1380 RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1381 rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1382 rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1383 int tia_gain, lna2_gain, biq1_gain;
1384 bool set_gain;
1385 u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1386 u16 values_to_save[11];
1387 s16 *ptr;
1388 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1390 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1391 if (NULL == ptr)
1392 return false;
1393 if (module == 2) {
1394 while (iqcomp_sz--) {
1395 if (iqcomp[iqcomp_sz].chan ==
1396 CHSPEC_CHANNEL(pi->radio_chanspec)) {
1397 wlc_lcnphy_set_rx_iq_comp(pi,
1398 (u16)
1399 iqcomp[iqcomp_sz].a,
1400 (u16)
1401 iqcomp[iqcomp_sz].b);
1402 result = true;
1403 break;
1406 goto cal_done;
1409 WARN_ON(module != 1);
1410 tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1411 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1413 for (i = 0; i < 11; i++)
1414 values_to_save[i] =
1415 read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1416 Core1TxControl_old = read_phy_reg(pi, 0x631);
1418 or_phy_reg(pi, 0x631, 0x0015);
1420 RFOverride0_old = read_phy_reg(pi, 0x44c);
1421 RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1422 rfoverride2_old = read_phy_reg(pi, 0x4b0);
1423 rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1424 rfoverride3_old = read_phy_reg(pi, 0x4f9);
1425 rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1426 rfoverride4_old = read_phy_reg(pi, 0x938);
1427 rfoverride4val_old = read_phy_reg(pi, 0x939);
1428 afectrlovr_old = read_phy_reg(pi, 0x43b);
1429 afectrlovrval_old = read_phy_reg(pi, 0x43c);
1430 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1431 old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1433 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1434 if (tx_gain_override_old) {
1435 wlc_lcnphy_get_tx_gain(pi, &old_gains);
1436 tx_gain_index_old = pi_lcn->lcnphy_current_index;
1439 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1441 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1442 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1444 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1445 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1447 write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1448 write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1449 write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1450 write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1451 write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1452 mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1453 write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1454 write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1455 write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1456 write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1458 mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1459 mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1460 mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1461 mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1462 mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1463 mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1464 mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1465 mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1466 mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1467 mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1469 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1470 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1472 write_phy_reg(pi, 0x6da, 0xffff);
1473 or_phy_reg(pi, 0x6db, 0x3);
1475 wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1476 for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {
1477 for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
1478 for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {
1479 set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1480 (u16)
1481 biq1_gain,
1482 (u16)
1483 tia_gain,
1484 (u16)
1485 lna2_gain);
1486 if (!set_gain)
1487 continue;
1489 result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1490 goto stop_tone;
1495 stop_tone:
1496 wlc_lcnphy_stop_tx_tone(pi);
1498 write_phy_reg(pi, 0x631, Core1TxControl_old);
1500 write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1501 write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1502 write_phy_reg(pi, 0x4b0, rfoverride2_old);
1503 write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1504 write_phy_reg(pi, 0x4f9, rfoverride3_old);
1505 write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1506 write_phy_reg(pi, 0x938, rfoverride4_old);
1507 write_phy_reg(pi, 0x939, rfoverride4val_old);
1508 write_phy_reg(pi, 0x43b, afectrlovr_old);
1509 write_phy_reg(pi, 0x43c, afectrlovrval_old);
1510 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1511 write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1513 wlc_lcnphy_clear_trsw_override(pi);
1515 mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1517 for (i = 0; i < 11; i++)
1518 write_radio_reg(pi, rxiq_cal_rf_reg[i],
1519 values_to_save[i]);
1521 if (tx_gain_override_old)
1522 wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1523 else
1524 wlc_lcnphy_disable_tx_gain_override(pi);
1526 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1527 wlc_lcnphy_rx_gain_override_enable(pi, false);
1529 cal_done:
1530 kfree(ptr);
1531 return result;
1534 s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1536 s8 index;
1537 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1539 if (txpwrctrl_off(pi))
1540 index = pi_lcn->lcnphy_current_index;
1541 else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1542 index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1543 pi) / 2);
1544 else
1545 index = pi_lcn->lcnphy_current_index;
1546 return index;
1549 void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1551 u16 afectrlovr, afectrlovrval;
1552 afectrlovr = read_phy_reg(pi, 0x43b);
1553 afectrlovrval = read_phy_reg(pi, 0x43c);
1554 if (channel != 0) {
1555 mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1557 mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1559 mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1561 mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1563 write_phy_reg(pi, 0x44b, 0xffff);
1564 wlc_lcnphy_tx_pu(pi, 1);
1566 mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1568 or_phy_reg(pi, 0x6da, 0x0080);
1570 or_phy_reg(pi, 0x00a, 0x228);
1571 } else {
1572 and_phy_reg(pi, 0x00a, ~(0x228));
1574 and_phy_reg(pi, 0x6da, 0xFF7F);
1575 write_phy_reg(pi, 0x43b, afectrlovr);
1576 write_phy_reg(pi, 0x43c, afectrlovrval);
1580 static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1582 u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1584 save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1585 save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1587 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1588 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1590 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1591 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1593 write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1594 write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1597 static void
1598 wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1600 if (enable) {
1601 write_phy_reg(pi, 0x942, 0x7);
1602 write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1603 write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1605 write_phy_reg(pi, 0x44a, 0x084);
1606 write_phy_reg(pi, 0x44a, 0x080);
1607 write_phy_reg(pi, 0x6d3, 0x2222);
1608 write_phy_reg(pi, 0x6d3, 0x2220);
1609 } else {
1610 write_phy_reg(pi, 0x942, 0x0);
1611 write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1612 write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1614 wlapi_switch_macfreq(pi->sh->physhim, enable);
1617 static void
1618 wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1620 u8 channel = CHSPEC_CHANNEL(chanspec);
1621 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1623 if (channel == 14)
1624 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1625 else
1626 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1628 pi_lcn->lcnphy_bandedge_corr = 2;
1629 if (channel == 1)
1630 pi_lcn->lcnphy_bandedge_corr = 4;
1632 if (channel == 1 || channel == 2 || channel == 3 ||
1633 channel == 4 || channel == 9 ||
1634 channel == 10 || channel == 11 || channel == 12) {
1635 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1636 0x03000c04);
1637 bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1638 ~0x00ffffff, 0x0);
1639 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1640 0x200005c0);
1642 bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1643 BCMA_CC_PMU_CTL_PLL_UPD);
1644 write_phy_reg(pi, 0x942, 0);
1645 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1646 pi_lcn->lcnphy_spurmod = false;
1647 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1649 write_phy_reg(pi, 0x425, 0x5907);
1650 } else {
1651 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1652 0x03140c04);
1653 bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1654 ~0x00ffffff, 0x333333);
1655 bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1656 0x202c2820);
1658 bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1659 BCMA_CC_PMU_CTL_PLL_UPD);
1660 write_phy_reg(pi, 0x942, 0);
1661 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1663 pi_lcn->lcnphy_spurmod = false;
1664 mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1666 write_phy_reg(pi, 0x425, 0x590a);
1669 or_phy_reg(pi, 0x44a, 0x44);
1670 write_phy_reg(pi, 0x44a, 0x80);
1673 static void
1674 wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1676 uint i;
1677 const struct chan_info_2064_lcnphy *ci;
1678 u8 rfpll_doubler = 0;
1679 u8 pll_pwrup, pll_pwrup_ovr;
1680 s32 qFxtal, qFref, qFvco, qFcal;
1681 u8 d15, d16, f16, e44, e45;
1682 u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1683 u16 loop_bw, d30, setCount;
1685 u8 h29, h28_ten, e30, h30_ten, cp_current;
1686 u16 g30, d28;
1688 ci = &chan_info_2064_lcnphy[0];
1689 rfpll_doubler = 1;
1691 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1693 write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1694 if (!rfpll_doubler) {
1695 loop_bw = PLL_2064_LOOP_BW;
1696 d30 = PLL_2064_D30;
1697 } else {
1698 loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1699 d30 = PLL_2064_D30_DOUBLER;
1702 if (CHSPEC_IS2G(pi->radio_chanspec)) {
1703 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1704 if (chan_info_2064_lcnphy[i].chan == channel)
1705 break;
1707 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1708 return;
1710 ci = &chan_info_2064_lcnphy[i];
1713 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1715 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1717 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1719 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1721 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1722 (ci->logen_rccr_rx) << 2);
1724 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1726 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1727 (ci->pa_rxrf_lna2_freq_tune) << 4);
1729 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1731 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1732 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1734 or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1736 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1737 e44 = 0;
1738 e45 = 0;
1740 fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1741 if (pi->xtalfreq > 26000000)
1742 e44 = 1;
1743 if (pi->xtalfreq > 52000000)
1744 e45 = 1;
1745 if (e44 == 0)
1746 fcal_div = 1;
1747 else if (e45 == 0)
1748 fcal_div = 2;
1749 else
1750 fcal_div = 4;
1751 fvco3 = (ci->freq * 3);
1752 fref3 = 2 * fpfd;
1754 qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
1755 qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
1756 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1757 qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
1759 write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1761 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1762 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1763 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1765 d16 = (qFcal * 8 / (d15 + 1)) - 1;
1766 write_radio_reg(pi, RADIO_2064_REG051, d16);
1768 f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1769 setCount = f16 * 3 * (ci->freq) / 32 - 1;
1770 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1771 (u8) (setCount >> 8));
1773 or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1774 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1776 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1778 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1779 while (div_frac >= fref3) {
1780 div_int++;
1781 div_frac -= fref3;
1783 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1785 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1786 (u8) (div_int >> 4));
1787 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1788 (u8) (div_int << 4));
1789 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1790 (u8) (div_frac >> 16));
1791 write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1792 write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1794 write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1796 write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1797 write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1798 write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1800 h29 = LCN_BW_LMT / loop_bw;
1801 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1802 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1803 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1804 + PLL_2064_LOW_END_KVCO;
1805 h28_ten = (d28 * 10) / LCN_VCO_DIV;
1806 e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1807 g30 = LCN_OFFSET + (e30 * LCN_FACT);
1808 h30_ten = (g30 * 10) / LCN_CUR_DIV;
1809 cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1810 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1812 if (channel >= 1 && channel <= 5)
1813 write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1814 else
1815 write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1816 write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1818 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1819 udelay(1);
1821 wlc_2064_vco_cal(pi);
1823 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1824 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1825 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1826 write_radio_reg(pi, RADIO_2064_REG038, 3);
1827 write_radio_reg(pi, RADIO_2064_REG091, 7);
1831 static int
1832 wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1834 s16 filt_index = -1;
1835 int j;
1837 u16 addr[] = {
1838 0x910,
1839 0x91e,
1840 0x91f,
1841 0x924,
1842 0x925,
1843 0x926,
1844 0x920,
1845 0x921,
1846 0x927,
1847 0x928,
1848 0x929,
1849 0x922,
1850 0x923,
1851 0x930,
1852 0x931,
1853 0x932
1856 u16 addr_ofdm[] = {
1857 0x90f,
1858 0x900,
1859 0x901,
1860 0x906,
1861 0x907,
1862 0x908,
1863 0x902,
1864 0x903,
1865 0x909,
1866 0x90a,
1867 0x90b,
1868 0x904,
1869 0x905,
1870 0x90c,
1871 0x90d,
1872 0x90e
1875 if (!is_ofdm) {
1876 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1877 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1878 filt_index = (s16) j;
1879 break;
1883 if (filt_index != -1) {
1884 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1885 write_phy_reg(pi, addr[j],
1886 LCNPHY_txdigfiltcoeffs_cck
1887 [filt_index][j + 1]);
1889 } else {
1890 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1891 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1892 filt_index = (s16) j;
1893 break;
1897 if (filt_index != -1) {
1898 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1899 write_phy_reg(pi, addr_ofdm[j],
1900 LCNPHY_txdigfiltcoeffs_ofdm
1901 [filt_index][j + 1]);
1905 return (filt_index != -1) ? 0 : -1;
1908 static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1910 u16 pa_gain;
1912 pa_gain = (read_phy_reg(pi, 0x4fb) &
1913 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1914 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1916 return pa_gain;
1919 static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1920 struct lcnphy_txgains *target_gains)
1922 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1924 mod_phy_reg(
1925 pi, 0x4b5,
1926 (0xffff << 0),
1927 ((target_gains->gm_gain) |
1928 (target_gains->pga_gain << 8)) <<
1930 mod_phy_reg(pi, 0x4fb,
1931 (0x7fff << 0),
1932 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1934 mod_phy_reg(
1935 pi, 0x4fc,
1936 (0xffff << 0),
1937 ((target_gains->gm_gain) |
1938 (target_gains->pga_gain << 8)) <<
1940 mod_phy_reg(pi, 0x4fd,
1941 (0x7fff << 0),
1942 ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1944 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1946 wlc_lcnphy_enable_tx_gain_override(pi);
1949 static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
1951 u16 m0m1;
1952 struct phytbl_info tab;
1954 tab.tbl_ptr = &m0m1;
1955 tab.tbl_len = 1;
1956 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1957 tab.tbl_offset = 87;
1958 tab.tbl_width = 16;
1959 wlc_lcnphy_read_table(pi, &tab);
1961 return (u8) ((m0m1 & 0xff00) >> 8);
1964 static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1966 u16 m0m1 = (u16) m0 << 8;
1967 struct phytbl_info tab;
1969 tab.tbl_ptr = &m0m1;
1970 tab.tbl_len = 1;
1971 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1972 tab.tbl_offset = 87;
1973 tab.tbl_width = 16;
1974 wlc_lcnphy_write_table(pi, &tab);
1977 static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1979 u32 data_buf[64];
1980 struct phytbl_info tab;
1982 memset(data_buf, 0, sizeof(data_buf));
1984 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1985 tab.tbl_width = 32;
1986 tab.tbl_ptr = data_buf;
1988 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
1990 tab.tbl_len = 30;
1991 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
1992 wlc_lcnphy_write_table(pi, &tab);
1995 tab.tbl_len = 64;
1996 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
1997 wlc_lcnphy_write_table(pi, &tab);
2000 enum lcnphy_tssi_mode {
2001 LCNPHY_TSSI_PRE_PA,
2002 LCNPHY_TSSI_POST_PA,
2003 LCNPHY_TSSI_EXT
2006 static void
2007 wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
2009 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
2011 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
2013 if (LCNPHY_TSSI_POST_PA == pos) {
2014 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
2016 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
2018 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2019 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2020 } else {
2021 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
2022 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2024 } else {
2025 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2027 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2029 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2030 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2031 } else {
2032 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2033 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2036 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2038 if (LCNPHY_TSSI_EXT == pos) {
2039 write_radio_reg(pi, RADIO_2064_REG07F, 1);
2040 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2041 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2042 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2046 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2048 u16 N1, N2, N3, N4, N5, N6, N;
2049 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2050 >> 0);
2051 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2052 >> 12);
2053 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2054 >> 0);
2055 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2056 >> 8);
2057 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2058 >> 0);
2059 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2060 >> 8);
2061 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2062 if (N < 1600)
2063 N = 1600;
2064 return N;
2067 static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2069 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2070 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2072 auxpga_vmid = (2 << 8) |
2073 (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2074 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2075 auxpga_gain_temp = 2;
2077 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2079 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2081 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2083 mod_phy_reg(pi, 0x4db,
2084 (0x3ff << 0) |
2085 (0x7 << 12),
2086 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2088 mod_phy_reg(pi, 0x4dc,
2089 (0x3ff << 0) |
2090 (0x7 << 12),
2091 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2093 mod_phy_reg(pi, 0x40a,
2094 (0x3ff << 0) |
2095 (0x7 << 12),
2096 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2098 mod_phy_reg(pi, 0x40b,
2099 (0x3ff << 0) |
2100 (0x7 << 12),
2101 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2103 mod_phy_reg(pi, 0x40c,
2104 (0x3ff << 0) |
2105 (0x7 << 12),
2106 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2108 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2111 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2113 struct phytbl_info tab;
2114 u32 rfseq, ind;
2116 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2117 tab.tbl_width = 32;
2118 tab.tbl_ptr = &ind;
2119 tab.tbl_len = 1;
2120 tab.tbl_offset = 0;
2121 for (ind = 0; ind < 128; ind++) {
2122 wlc_lcnphy_write_table(pi, &tab);
2123 tab.tbl_offset++;
2125 tab.tbl_offset = 704;
2126 for (ind = 0; ind < 128; ind++) {
2127 wlc_lcnphy_write_table(pi, &tab);
2128 tab.tbl_offset++;
2130 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2132 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2134 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2136 wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
2137 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2139 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2141 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2143 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2145 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2147 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2149 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2151 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2153 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2155 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2157 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2159 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2161 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2163 wlc_lcnphy_clear_tx_power_offsets(pi);
2165 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2167 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2169 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2171 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2172 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
2173 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2174 } else {
2175 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2176 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2179 write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2181 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2182 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2183 } else {
2184 if (CHSPEC_IS2G(pi->radio_chanspec))
2185 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2186 else
2187 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2190 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2191 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2192 else
2193 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2195 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2197 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2199 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2200 mod_phy_reg(pi, 0x4d7,
2201 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2203 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2204 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2205 tab.tbl_width = 16;
2206 tab.tbl_ptr = &rfseq;
2207 tab.tbl_len = 1;
2208 tab.tbl_offset = 6;
2209 wlc_lcnphy_write_table(pi, &tab);
2211 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2213 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2215 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2217 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2219 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2221 wlc_lcnphy_pwrctrl_rssiparams(pi);
2224 void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2226 u16 tx_cnt, tx_total, npt;
2227 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2229 tx_total = wlc_lcnphy_total_tx_frames(pi);
2230 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2231 npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2233 if (tx_cnt > (1 << npt)) {
2235 pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2237 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2238 pi_lcn->lcnphy_tssi_npt = npt;
2243 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2245 s32 a, b, p;
2247 a = 32768 + (a1 * tssi);
2248 b = (1024 * b0) + (64 * b1 * tssi);
2249 p = ((2 * b) + a) / (2 * a);
2251 return p;
2254 static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2256 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2257 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2258 return;
2260 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2261 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2264 void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2266 struct phytbl_info tab;
2267 u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2268 BRCMS_NUM_RATES_MCS_1_STREAM];
2269 uint i, j;
2270 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2271 return;
2273 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2275 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2276 j = TXP_FIRST_MCS_20_SISO;
2278 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2281 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2282 tab.tbl_width = 32;
2283 tab.tbl_len = ARRAY_SIZE(rate_table);
2284 tab.tbl_ptr = rate_table;
2285 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2286 wlc_lcnphy_write_table(pi, &tab);
2288 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2289 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2291 wlc_lcnphy_txpower_reset_npt(pi);
2295 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2297 u32 cck_offset[4] = { 22, 22, 22, 22 };
2298 u32 ofdm_offset, reg_offset_cck;
2299 int i;
2300 u16 index2;
2301 struct phytbl_info tab;
2303 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2304 return;
2306 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2308 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2310 or_phy_reg(pi, 0x6da, 0x0040);
2312 reg_offset_cck = 0;
2313 for (i = 0; i < 4; i++)
2314 cck_offset[i] -= reg_offset_cck;
2315 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2316 tab.tbl_width = 32;
2317 tab.tbl_len = 4;
2318 tab.tbl_ptr = cck_offset;
2319 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2320 wlc_lcnphy_write_table(pi, &tab);
2321 ofdm_offset = 0;
2322 tab.tbl_len = 1;
2323 tab.tbl_ptr = &ofdm_offset;
2324 for (i = 836; i < 862; i++) {
2325 tab.tbl_offset = i;
2326 wlc_lcnphy_write_table(pi, &tab);
2329 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2331 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2333 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2335 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2337 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2339 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2341 index2 = (u16) (index * 2);
2342 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2344 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2348 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2350 s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2351 s16 manp, meas_temp, temp_diff;
2352 bool neg = false;
2353 u16 temp;
2354 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2356 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2357 return pi_lcn->lcnphy_current_index;
2359 index = FIXED_TXPWR;
2361 if (pi_lcn->lcnphy_tempsense_slope == 0)
2362 return index;
2364 temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2365 meas_temp = LCNPHY_TEMPSENSE(temp);
2367 if (pi->tx_power_min != 0)
2368 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2369 else
2370 delta_brd = 0;
2372 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2373 temp_diff = manp - meas_temp;
2374 if (temp_diff < 0) {
2375 neg = true;
2376 temp_diff = -temp_diff;
2379 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2380 (u32) (pi_lcn->
2381 lcnphy_tempsense_slope
2382 * 10), 0);
2383 if (neg)
2384 delta_temp = -delta_temp;
2386 if (pi_lcn->lcnphy_tempsense_option == 3
2387 && LCNREV_IS(pi->pubpi.phy_rev, 0))
2388 delta_temp = 0;
2389 if (pi_lcn->lcnphy_tempcorrx > 31)
2390 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2391 else
2392 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2393 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2394 tempcorrx = 4;
2395 new_index =
2396 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2397 new_index += tempcorrx;
2399 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2400 index = 127;
2402 if (new_index < 0 || new_index > 126)
2403 return index;
2405 return new_index;
2408 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2411 u16 current_mode = mode;
2412 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2413 mode == LCNPHY_TX_PWR_CTRL_HW)
2414 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2415 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2416 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2417 current_mode = LCNPHY_TX_PWR_CTRL_HW;
2418 return current_mode;
2421 void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2423 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2424 s8 index;
2425 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2427 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2428 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2430 mod_phy_reg(pi, 0x6da, (0x1 << 6),
2431 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2433 mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2434 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2436 if (old_mode != mode) {
2437 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2439 wlc_lcnphy_tx_pwr_update_npt(pi);
2441 wlc_lcnphy_clear_tx_power_offsets(pi);
2443 if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2445 wlc_lcnphy_txpower_recalc_target(pi);
2447 wlc_lcnphy_set_start_tx_pwr_idx(pi,
2448 pi_lcn->
2449 lcnphy_tssi_idx);
2450 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2451 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2453 pi_lcn->lcnphy_tssi_tx_cnt =
2454 wlc_lcnphy_total_tx_frames(pi);
2456 wlc_lcnphy_disable_tx_gain_override(pi);
2457 pi_lcn->lcnphy_tx_power_idx_override = -1;
2458 } else
2459 wlc_lcnphy_enable_tx_gain_override(pi);
2461 mod_phy_reg(pi, 0x4a4,
2462 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2463 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2464 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2465 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2466 pi_lcn->lcnphy_current_index = (s8)
2467 ((read_phy_reg(pi,
2468 0x4a9) &
2469 0xFF) / 2);
2474 static void
2475 wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2477 u16 vmid;
2478 int i;
2479 for (i = 0; i < 20; i++)
2480 values_to_save[i] =
2481 read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2483 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2484 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2486 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2487 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2489 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2490 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2492 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2493 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2495 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2496 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2497 else
2498 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2499 or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2501 or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2502 or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2503 udelay(20);
2505 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2506 if (CHSPEC_IS5G(pi->radio_chanspec))
2507 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2508 else
2509 or_radio_reg(pi, RADIO_2064_REG03A, 1);
2510 } else {
2511 if (CHSPEC_IS5G(pi->radio_chanspec))
2512 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2513 else
2514 or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2517 udelay(20);
2519 write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2520 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2521 if (CHSPEC_IS5G(pi->radio_chanspec))
2522 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2523 else
2524 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2525 } else {
2526 if (CHSPEC_IS5G(pi->radio_chanspec))
2527 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2528 else
2529 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2532 udelay(20);
2534 write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2535 or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2536 udelay(20);
2538 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2539 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2540 udelay(20);
2542 or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2543 or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2544 udelay(20);
2546 write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2547 udelay(20);
2549 vmid = 0x2A6;
2550 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2551 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2552 or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2553 udelay(20);
2555 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2556 udelay(20);
2557 write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2558 or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2559 write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2560 write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2561 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2562 write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2563 write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2566 static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2568 uint delay_count = 0;
2570 while (wlc_lcnphy_iqcal_active(pi)) {
2571 udelay(100);
2572 delay_count++;
2574 if (delay_count > (10 * 500))
2575 break;
2578 return (0 == wlc_lcnphy_iqcal_active(pi));
2581 static void
2582 wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2584 int i;
2586 and_phy_reg(pi, 0x44c, 0x0 >> 11);
2588 and_phy_reg(pi, 0x43b, 0xC);
2590 for (i = 0; i < 20; i++)
2591 write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2592 values_to_save[i]);
2595 static void
2596 wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2597 struct lcnphy_txgains *target_gains,
2598 enum lcnphy_cal_mode cal_mode, bool keep_tone)
2601 struct lcnphy_txgains cal_gains, temp_gains;
2602 u16 hash;
2603 u8 band_idx;
2604 int j;
2605 u16 ncorr_override[5];
2606 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2607 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2609 u16 commands_fullcal[] = {
2610 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2613 u16 commands_recal[] = {
2614 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2617 u16 command_nums_fullcal[] = {
2618 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2621 u16 command_nums_recal[] = {
2622 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2624 u16 *command_nums = command_nums_fullcal;
2626 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2627 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2628 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2629 bool tx_gain_override_old;
2630 struct lcnphy_txgains old_gains;
2631 uint i, n_cal_cmds = 0, n_cal_start = 0;
2632 u16 *values_to_save;
2633 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2635 values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2636 if (NULL == values_to_save)
2637 return;
2639 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2640 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2642 or_phy_reg(pi, 0x6da, 0x40);
2643 or_phy_reg(pi, 0x6db, 0x3);
2645 switch (cal_mode) {
2646 case LCNPHY_CAL_FULL:
2647 start_coeffs = syst_coeffs;
2648 cal_cmds = commands_fullcal;
2649 n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2650 break;
2652 case LCNPHY_CAL_RECAL:
2653 start_coeffs = syst_coeffs;
2654 cal_cmds = commands_recal;
2655 n_cal_cmds = ARRAY_SIZE(commands_recal);
2656 command_nums = command_nums_recal;
2657 break;
2659 default:
2660 break;
2663 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2664 start_coeffs, 11, 16, 64);
2666 write_phy_reg(pi, 0x6da, 0xffff);
2667 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2669 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2671 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2673 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2675 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2677 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2679 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2681 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2683 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2684 if (tx_gain_override_old)
2685 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2687 if (!target_gains) {
2688 if (!tx_gain_override_old)
2689 wlc_lcnphy_set_tx_pwr_by_index(pi,
2690 pi_lcn->lcnphy_tssi_idx);
2691 wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2692 target_gains = &temp_gains;
2695 hash = (target_gains->gm_gain << 8) |
2696 (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2698 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2700 cal_gains = *target_gains;
2701 memset(ncorr_override, 0, sizeof(ncorr_override));
2702 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2703 if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2704 cal_gains.gm_gain =
2705 tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2706 cal_gains.pga_gain =
2707 tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2708 cal_gains.pad_gain =
2709 tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2710 memcpy(ncorr_override,
2711 &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2712 sizeof(ncorr_override));
2713 break;
2717 wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2719 write_phy_reg(pi, 0x453, 0xaa9);
2720 write_phy_reg(pi, 0x93d, 0xc0);
2722 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2723 lcnphy_iqcal_loft_gainladder,
2724 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2725 16, 0);
2727 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2728 lcnphy_iqcal_ir_gainladder,
2729 ARRAY_SIZE(
2730 lcnphy_iqcal_ir_gainladder), 16,
2731 32);
2733 if (pi->phy_tx_tone_freq) {
2735 wlc_lcnphy_stop_tx_tone(pi);
2736 udelay(5);
2737 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2738 } else {
2739 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2742 write_phy_reg(pi, 0x6da, 0xffff);
2744 for (i = n_cal_start; i < n_cal_cmds; i++) {
2745 u16 zero_diq = 0;
2746 u16 best_coeffs[11];
2747 u16 command_num;
2749 cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2751 command_num = command_nums[i];
2752 if (ncorr_override[cal_type])
2753 command_num =
2754 ncorr_override[cal_type] << 8 | (command_num &
2755 0xff);
2757 write_phy_reg(pi, 0x452, command_num);
2759 if ((cal_type == 3) || (cal_type == 4)) {
2760 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2761 &diq_start, 1, 16, 69);
2763 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2764 &zero_diq, 1, 16, 69);
2767 write_phy_reg(pi, 0x451, cal_cmds[i]);
2769 if (!wlc_lcnphy_iqcal_wait(pi))
2770 goto cleanup;
2772 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2773 best_coeffs,
2774 ARRAY_SIZE(best_coeffs), 16, 96);
2775 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2776 best_coeffs,
2777 ARRAY_SIZE(best_coeffs), 16, 64);
2779 if ((cal_type == 3) || (cal_type == 4))
2780 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2781 &diq_start, 1, 16, 69);
2782 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2783 pi_lcn->lcnphy_cal_results.
2784 txiqlocal_bestcoeffs,
2785 ARRAY_SIZE(pi_lcn->
2786 lcnphy_cal_results.
2787 txiqlocal_bestcoeffs),
2788 16, 96);
2791 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2792 pi_lcn->lcnphy_cal_results.
2793 txiqlocal_bestcoeffs,
2794 ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2795 txiqlocal_bestcoeffs), 16, 96);
2796 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2798 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2799 &pi_lcn->lcnphy_cal_results.
2800 txiqlocal_bestcoeffs[0], 4, 16, 80);
2802 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2803 &pi_lcn->lcnphy_cal_results.
2804 txiqlocal_bestcoeffs[5], 2, 16, 85);
2806 cleanup:
2807 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2808 kfree(values_to_save);
2810 if (!keep_tone)
2811 wlc_lcnphy_stop_tx_tone(pi);
2813 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2815 write_phy_reg(pi, 0x453, 0);
2817 if (tx_gain_override_old)
2818 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2819 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2821 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2822 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2826 static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2828 bool suspend, tx_gain_override_old;
2829 struct lcnphy_txgains old_gains;
2830 struct brcms_phy *pi = (struct brcms_phy *) ppi;
2831 u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2832 idleTssi0_regvalue_2C;
2833 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2834 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2835 u16 SAVE_jtag_bb_afe_switch =
2836 read_radio_reg(pi, RADIO_2064_REG007) & 1;
2837 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2838 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2839 idleTssi = read_phy_reg(pi, 0x4ab);
2840 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2841 MCTL_EN_MAC));
2842 if (!suspend)
2843 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2844 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2846 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2847 wlc_lcnphy_get_tx_gain(pi, &old_gains);
2849 wlc_lcnphy_enable_tx_gain_override(pi);
2850 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2851 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2852 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2853 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2854 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2855 wlc_lcnphy_tssi_setup(pi);
2856 wlc_phy_do_dummy_tx(pi, true, OFF);
2857 idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2858 >> 0);
2860 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2861 >> 0);
2863 if (idleTssi0_2C >= 256)
2864 idleTssi0_OB = idleTssi0_2C - 256;
2865 else
2866 idleTssi0_OB = idleTssi0_2C + 256;
2868 idleTssi0_regvalue_OB = idleTssi0_OB;
2869 if (idleTssi0_regvalue_OB >= 256)
2870 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2871 else
2872 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2873 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2875 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2877 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2878 wlc_lcnphy_set_tx_gain(pi, &old_gains);
2879 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2881 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2882 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2883 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2884 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2885 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2886 if (!suspend)
2887 wlapi_enable_mac(pi->sh->physhim);
2890 static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2892 bool suspend;
2893 u16 save_txpwrCtrlEn;
2894 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2895 u16 auxpga_vmid;
2896 struct phytbl_info tab;
2897 u32 val;
2898 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2899 save_reg112;
2900 u16 values_to_save[14];
2901 s8 index;
2902 int i;
2903 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2904 udelay(999);
2906 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2907 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2908 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2909 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2910 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2911 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2913 for (i = 0; i < 14; i++)
2914 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2915 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2916 MCTL_EN_MAC));
2917 if (!suspend)
2918 wlapi_suspend_mac_and_wait(pi->sh->physhim);
2919 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2921 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2922 index = pi_lcn->lcnphy_current_index;
2923 wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2924 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2925 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2926 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2927 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2929 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2931 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2933 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2935 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2937 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2939 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2941 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2943 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2945 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2947 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2949 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2951 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2953 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
2955 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
2957 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
2959 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
2961 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2963 write_radio_reg(pi, RADIO_2064_REG025, 0xC);
2965 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
2967 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2969 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2971 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2973 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2974 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2975 tab.tbl_width = 16;
2976 tab.tbl_len = 1;
2977 tab.tbl_ptr = &val;
2978 tab.tbl_offset = 6;
2979 wlc_lcnphy_write_table(pi, &tab);
2980 if (mode == TEMPSENSE) {
2981 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2983 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
2985 auxpga_vmidcourse = 8;
2986 auxpga_vmidfine = 0x4;
2987 auxpga_gain = 2;
2988 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
2989 } else {
2990 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
2992 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
2994 auxpga_vmidcourse = 7;
2995 auxpga_vmidfine = 0xa;
2996 auxpga_gain = 2;
2998 auxpga_vmid =
2999 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
3000 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
3002 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
3004 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
3006 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
3008 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
3010 write_radio_reg(pi, RADIO_2064_REG112, 0x6);
3012 wlc_phy_do_dummy_tx(pi, true, OFF);
3013 if (!tempsense_done(pi))
3014 udelay(10);
3016 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
3017 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
3018 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
3019 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
3020 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
3021 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
3022 for (i = 0; i < 14; i++)
3023 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
3024 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3026 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3027 if (!suspend)
3028 wlapi_enable_mac(pi->sh->physhim);
3029 udelay(999);
3032 static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3034 struct lcnphy_txgains tx_gains;
3035 u8 bbmult;
3036 struct phytbl_info tab;
3037 s32 a1, b0, b1;
3038 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3039 bool suspend;
3040 struct brcms_phy *pi = (struct brcms_phy *) ppi;
3042 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3043 MCTL_EN_MAC));
3044 if (!suspend)
3045 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3047 if (!pi->hwpwrctrl_capable) {
3048 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3049 tx_gains.gm_gain = 4;
3050 tx_gains.pga_gain = 12;
3051 tx_gains.pad_gain = 12;
3052 tx_gains.dac_gain = 0;
3054 bbmult = 150;
3055 } else {
3056 tx_gains.gm_gain = 7;
3057 tx_gains.pga_gain = 15;
3058 tx_gains.pad_gain = 14;
3059 tx_gains.dac_gain = 0;
3061 bbmult = 150;
3063 wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3064 wlc_lcnphy_set_bbmult(pi, bbmult);
3065 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3066 } else {
3068 wlc_lcnphy_idle_tssi_est(ppi);
3070 wlc_lcnphy_clear_tx_power_offsets(pi);
3072 b0 = pi->txpa_2g[0];
3073 b1 = pi->txpa_2g[1];
3074 a1 = pi->txpa_2g[2];
3075 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3076 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3078 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3079 tab.tbl_width = 32;
3080 tab.tbl_ptr = &pwr;
3081 tab.tbl_len = 1;
3082 tab.tbl_offset = 0;
3083 for (tssi = 0; tssi < 128; tssi++) {
3084 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3086 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3087 wlc_lcnphy_write_table(pi, &tab);
3088 tab.tbl_offset++;
3091 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3093 write_phy_reg(pi, 0x4a8, 10);
3095 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3097 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3099 if (!suspend)
3100 wlapi_enable_mac(pi->sh->physhim);
3103 static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3105 mod_phy_reg(pi, 0x4fb,
3106 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3107 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3108 mod_phy_reg(pi, 0x4fd,
3109 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3110 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3113 void
3114 wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3115 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3117 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3118 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3119 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3120 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3123 void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3125 struct phytbl_info tab;
3126 u16 iqcc[2];
3128 iqcc[0] = a;
3129 iqcc[1] = b;
3131 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3132 tab.tbl_width = 16;
3133 tab.tbl_ptr = iqcc;
3134 tab.tbl_len = 2;
3135 tab.tbl_offset = 80;
3136 wlc_lcnphy_write_table(pi, &tab);
3139 void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3141 struct phytbl_info tab;
3143 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3144 tab.tbl_width = 16;
3145 tab.tbl_ptr = &didq;
3146 tab.tbl_len = 1;
3147 tab.tbl_offset = 85;
3148 wlc_lcnphy_write_table(pi, &tab);
3151 void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3153 struct phytbl_info tab;
3154 u16 a, b;
3155 u8 bb_mult;
3156 u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3157 struct lcnphy_txgains gains;
3158 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3160 pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3161 pi_lcn->lcnphy_current_index = (u8) index;
3163 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3164 tab.tbl_width = 32;
3165 tab.tbl_len = 1;
3167 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3169 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3170 tab.tbl_ptr = &bbmultiqcomp;
3171 wlc_lcnphy_read_table(pi, &tab);
3173 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3174 tab.tbl_width = 32;
3175 tab.tbl_ptr = &txgain;
3176 wlc_lcnphy_read_table(pi, &tab);
3178 gains.gm_gain = (u16) (txgain & 0xff);
3179 gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3180 gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3181 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3182 wlc_lcnphy_set_tx_gain(pi, &gains);
3183 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3185 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3186 wlc_lcnphy_set_bbmult(pi, bb_mult);
3188 wlc_lcnphy_enable_tx_gain_override(pi);
3190 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3192 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3193 b = (u16) (bbmultiqcomp & 0x3ff);
3194 wlc_lcnphy_set_tx_iqcc(pi, a, b);
3196 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3197 tab.tbl_ptr = &locoeffs;
3198 wlc_lcnphy_read_table(pi, &tab);
3200 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3202 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3203 tab.tbl_ptr = &rfpower;
3204 wlc_lcnphy_read_table(pi, &tab);
3205 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3210 static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3212 u32 j;
3213 struct phytbl_info tab;
3214 u32 temp_offset[128];
3215 tab.tbl_ptr = temp_offset;
3216 tab.tbl_len = 128;
3217 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3218 tab.tbl_width = 32;
3219 tab.tbl_offset = 0;
3221 memset(temp_offset, 0, sizeof(temp_offset));
3222 for (j = 1; j < 128; j += 2)
3223 temp_offset[j] = 0x80000;
3225 wlc_lcnphy_write_table(pi, &tab);
3226 return;
3229 void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3231 if (!bEnable) {
3233 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3235 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3237 and_phy_reg(pi, 0x44c,
3238 ~(u16) ((0x1 << 3) |
3239 (0x1 << 5) |
3240 (0x1 << 12) |
3241 (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3243 and_phy_reg(pi, 0x44d,
3244 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3245 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3247 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3249 and_phy_reg(pi, 0x4f9,
3250 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3252 and_phy_reg(pi, 0x4fa,
3253 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3254 } else {
3256 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3257 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3259 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3260 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3262 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3263 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3265 wlc_lcnphy_set_trsw_override(pi, true, false);
3267 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3268 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3270 if (CHSPEC_IS2G(pi->radio_chanspec)) {
3272 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3273 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3275 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3276 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3278 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3279 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3281 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3282 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3284 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3285 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3286 } else {
3288 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3289 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3291 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3292 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3294 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3295 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3297 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3298 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3300 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3301 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3306 static void
3307 wlc_lcnphy_run_samples(struct brcms_phy *pi,
3308 u16 num_samps,
3309 u16 num_loops, u16 wait, bool iqcalmode)
3312 or_phy_reg(pi, 0x6da, 0x8080);
3314 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3315 if (num_loops != 0xffff)
3316 num_loops--;
3317 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3319 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3321 if (iqcalmode) {
3323 and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3324 or_phy_reg(pi, 0x453, (0x1 << 15));
3325 } else {
3326 write_phy_reg(pi, 0x63f, 1);
3327 wlc_lcnphy_tx_pu(pi, 1);
3330 or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3333 void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3336 u8 phybw40;
3337 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3339 if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3340 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3341 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3342 } else {
3343 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3344 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3347 if (phybw40 == 0) {
3348 mod_phy_reg((pi), 0x410,
3349 (0x1 << 6) |
3350 (0x1 << 5),
3351 ((CHSPEC_IS2G(
3352 pi->radio_chanspec)) ? (!mode) : 0) <<
3353 6 | (!mode) << 5);
3354 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3358 void
3359 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3360 bool iqcalmode)
3362 u8 phy_bw;
3363 u16 num_samps, t, k;
3364 u32 bw;
3365 s32 theta = 0, rot = 0;
3366 struct cordic_iq tone_samp;
3367 u32 data_buf[64];
3368 u16 i_samp, q_samp;
3369 struct phytbl_info tab;
3370 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3372 pi->phy_tx_tone_freq = f_kHz;
3374 wlc_lcnphy_deaf_mode(pi, true);
3376 phy_bw = 40;
3377 if (pi_lcn->lcnphy_spurmod) {
3378 write_phy_reg(pi, 0x942, 0x2);
3379 write_phy_reg(pi, 0x93b, 0x0);
3380 write_phy_reg(pi, 0x93c, 0x0);
3381 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3384 if (f_kHz) {
3385 k = 1;
3386 do {
3387 bw = phy_bw * 1000 * k;
3388 num_samps = bw / abs(f_kHz);
3389 k++;
3390 } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3391 } else
3392 num_samps = 2;
3394 rot = ((f_kHz * 36) / phy_bw) / 100;
3395 theta = 0;
3397 for (t = 0; t < num_samps; t++) {
3399 tone_samp = cordic_calc_iq(theta);
3401 theta += rot;
3403 i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3404 q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3405 data_buf[t] = (i_samp << 10) | q_samp;
3408 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3410 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3412 tab.tbl_ptr = data_buf;
3413 tab.tbl_len = num_samps;
3414 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3415 tab.tbl_offset = 0;
3416 tab.tbl_width = 32;
3417 wlc_lcnphy_write_table(pi, &tab);
3419 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3422 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3424 s16 playback_status;
3425 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3427 pi->phy_tx_tone_freq = 0;
3428 if (pi_lcn->lcnphy_spurmod) {
3429 write_phy_reg(pi, 0x942, 0x7);
3430 write_phy_reg(pi, 0x93b, 0x2017);
3431 write_phy_reg(pi, 0x93c, 0x27c5);
3432 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3435 playback_status = read_phy_reg(pi, 0x644);
3436 if (playback_status & (0x1 << 0)) {
3437 wlc_lcnphy_tx_pu(pi, 0);
3438 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3439 } else if (playback_status & (0x1 << 1))
3440 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3442 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3444 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3446 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3448 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3450 wlc_lcnphy_deaf_mode(pi, false);
3453 static void
3454 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3456 u16 di0dq0;
3457 u16 x, y, data_rf;
3458 int k;
3459 switch (cal_type) {
3460 case 0:
3461 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3462 break;
3463 case 2:
3464 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3465 wlc_lcnphy_set_tx_locc(pi, di0dq0);
3466 break;
3467 case 3:
3468 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3469 y = 8 + k;
3470 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3471 x = 8 - k;
3472 data_rf = (x * 16 + y);
3473 write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3474 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3475 y = 8 + k;
3476 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3477 x = 8 - k;
3478 data_rf = (x * 16 + y);
3479 write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3480 break;
3481 case 4:
3482 k = wlc_lcnphy_calc_floor(coeff_x, 0);
3483 y = 8 + k;
3484 k = wlc_lcnphy_calc_floor(coeff_x, 1);
3485 x = 8 - k;
3486 data_rf = (x * 16 + y);
3487 write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3488 k = wlc_lcnphy_calc_floor(coeff_y, 0);
3489 y = 8 + k;
3490 k = wlc_lcnphy_calc_floor(coeff_y, 1);
3491 x = 8 - k;
3492 data_rf = (x * 16 + y);
3493 write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3494 break;
3498 static struct lcnphy_unsign16_struct
3499 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3501 u16 a, b, didq;
3502 u8 di0, dq0, ei, eq, fi, fq;
3503 struct lcnphy_unsign16_struct cc;
3504 cc.re = 0;
3505 cc.im = 0;
3506 switch (cal_type) {
3507 case 0:
3508 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3509 cc.re = a;
3510 cc.im = b;
3511 break;
3512 case 2:
3513 didq = wlc_lcnphy_get_tx_locc(pi);
3514 di0 = (((didq & 0xff00) << 16) >> 24);
3515 dq0 = (((didq & 0x00ff) << 24) >> 24);
3516 cc.re = (u16) di0;
3517 cc.im = (u16) dq0;
3518 break;
3519 case 3:
3520 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3521 cc.re = (u16) ei;
3522 cc.im = (u16) eq;
3523 break;
3524 case 4:
3525 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3526 cc.re = (u16) fi;
3527 cc.im = (u16) fq;
3528 break;
3530 return cc;
3533 static void
3534 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3535 s16 *ptr, int mode)
3537 u32 curval1, curval2, stpptr, curptr, strptr, val;
3538 u16 sslpnCalibClkEnCtrl, timer;
3539 u16 old_sslpnCalibClkEnCtrl;
3540 s16 imag, real;
3541 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3543 timer = 0;
3544 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3546 curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3547 ptr[130] = 0;
3548 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3549 ((1 << 6) | curval1));
3551 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3552 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3553 udelay(20);
3554 curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3555 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3556 curval2 | 0x30);
3558 write_phy_reg(pi, 0x555, 0x0);
3559 write_phy_reg(pi, 0x5a6, 0x5);
3561 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3562 write_phy_reg(pi, 0x5cf, 3);
3563 write_phy_reg(pi, 0x5a5, 0x3);
3564 write_phy_reg(pi, 0x583, 0x0);
3565 write_phy_reg(pi, 0x584, 0x0);
3566 write_phy_reg(pi, 0x585, 0x0fff);
3567 write_phy_reg(pi, 0x586, 0x0000);
3569 write_phy_reg(pi, 0x580, 0x4501);
3571 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3572 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3573 stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3574 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3575 do {
3576 udelay(10);
3577 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3578 timer++;
3579 } while ((curptr != stpptr) && (timer < 500));
3581 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3582 strptr = 0x7E00;
3583 bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3584 while (strptr < 0x8000) {
3585 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3586 imag = ((val >> 16) & 0x3ff);
3587 real = ((val) & 0x3ff);
3588 if (imag > 511)
3589 imag -= 1024;
3591 if (real > 511)
3592 real -= 1024;
3594 if (pi_lcn->lcnphy_iqcal_swp_dis)
3595 ptr[(strptr - 0x7E00) / 4] = real;
3596 else
3597 ptr[(strptr - 0x7E00) / 4] = imag;
3599 if (clip_detect_algo) {
3600 if (imag > thresh || imag < -thresh) {
3601 strptr = 0x8000;
3602 ptr[130] = 1;
3606 strptr += 4;
3609 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3610 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3611 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3614 static void
3615 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3616 int step_size_lg2)
3618 const struct lcnphy_spb_tone *phy_c1;
3619 struct lcnphy_spb_tone phy_c2;
3620 struct lcnphy_unsign16_struct phy_c3;
3621 int phy_c4, phy_c5, k, l, j, phy_c6;
3622 u16 phy_c7, phy_c8, phy_c9;
3623 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3624 s16 *ptr, phy_c17;
3625 s32 phy_c18, phy_c19;
3626 u32 phy_c20, phy_c21;
3627 bool phy_c22, phy_c23, phy_c24, phy_c25;
3628 u16 phy_c26, phy_c27;
3629 u16 phy_c28, phy_c29, phy_c30;
3630 u16 phy_c31;
3631 u16 *phy_c32;
3632 phy_c21 = 0;
3633 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3634 ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3635 if (NULL == ptr)
3636 return;
3638 phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3639 if (NULL == phy_c32) {
3640 kfree(ptr);
3641 return;
3643 phy_c26 = read_phy_reg(pi, 0x6da);
3644 phy_c27 = read_phy_reg(pi, 0x6db);
3645 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3646 write_phy_reg(pi, 0x93d, 0xC0);
3648 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3649 write_phy_reg(pi, 0x6da, 0xffff);
3650 or_phy_reg(pi, 0x6db, 0x3);
3652 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3653 udelay(500);
3654 phy_c28 = read_phy_reg(pi, 0x938);
3655 phy_c29 = read_phy_reg(pi, 0x4d7);
3656 phy_c30 = read_phy_reg(pi, 0x4d8);
3657 or_phy_reg(pi, 0x938, 0x1 << 2);
3658 or_phy_reg(pi, 0x4d7, 0x1 << 2);
3659 or_phy_reg(pi, 0x4d7, 0x1 << 3);
3660 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3661 or_phy_reg(pi, 0x4d8, 1 << 0);
3662 or_phy_reg(pi, 0x4d8, 1 << 1);
3663 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3664 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3665 phy_c1 = &lcnphy_spb_tone_3750[0];
3666 phy_c4 = 32;
3668 if (num_levels == 0) {
3669 if (cal_type != 0)
3670 num_levels = 4;
3671 else
3672 num_levels = 9;
3674 if (step_size_lg2 == 0) {
3675 if (cal_type != 0)
3676 step_size_lg2 = 3;
3677 else
3678 step_size_lg2 = 8;
3681 phy_c7 = (1 << step_size_lg2);
3682 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3683 phy_c15 = (s16) phy_c3.re;
3684 phy_c16 = (s16) phy_c3.im;
3685 if (cal_type == 2) {
3686 if (phy_c3.re > 127)
3687 phy_c15 = phy_c3.re - 256;
3688 if (phy_c3.im > 127)
3689 phy_c16 = phy_c3.im - 256;
3691 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3692 udelay(20);
3693 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3694 phy_c23 = true;
3695 phy_c22 = false;
3696 switch (cal_type) {
3697 case 0:
3698 phy_c10 = 511;
3699 break;
3700 case 2:
3701 phy_c10 = 127;
3702 break;
3703 case 3:
3704 phy_c10 = 15;
3705 break;
3706 case 4:
3707 phy_c10 = 15;
3708 break;
3711 phy_c9 = read_phy_reg(pi, 0x93d);
3712 phy_c9 = 2 * phy_c9;
3713 phy_c24 = false;
3714 phy_c5 = 7;
3715 phy_c25 = true;
3716 while (1) {
3717 write_radio_reg(pi, RADIO_2064_REG026,
3718 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3719 udelay(50);
3720 phy_c22 = false;
3721 ptr[130] = 0;
3722 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3723 if (ptr[130] == 1)
3724 phy_c22 = true;
3725 if (phy_c22)
3726 phy_c5 -= 1;
3727 if ((phy_c22 != phy_c24) && (!phy_c25))
3728 break;
3729 if (!phy_c22)
3730 phy_c5 += 1;
3731 if (phy_c5 <= 0 || phy_c5 >= 7)
3732 break;
3733 phy_c24 = phy_c22;
3734 phy_c25 = false;
3737 if (phy_c5 < 0)
3738 phy_c5 = 0;
3739 else if (phy_c5 > 7)
3740 phy_c5 = 7;
3742 for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3743 for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3744 phy_c11 = phy_c15 + k;
3745 phy_c12 = phy_c16 + l;
3747 if (phy_c11 < -phy_c10)
3748 phy_c11 = -phy_c10;
3749 else if (phy_c11 > phy_c10)
3750 phy_c11 = phy_c10;
3751 if (phy_c12 < -phy_c10)
3752 phy_c12 = -phy_c10;
3753 else if (phy_c12 > phy_c10)
3754 phy_c12 = phy_c10;
3755 wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3756 phy_c12);
3757 udelay(20);
3758 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3760 phy_c18 = 0;
3761 phy_c19 = 0;
3762 for (j = 0; j < 128; j++) {
3763 if (cal_type != 0)
3764 phy_c6 = j % phy_c4;
3765 else
3766 phy_c6 = (2 * j) % phy_c4;
3768 phy_c2.re = phy_c1[phy_c6].re;
3769 phy_c2.im = phy_c1[phy_c6].im;
3770 phy_c17 = ptr[j];
3771 phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3772 phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3775 phy_c18 = phy_c18 >> 10;
3776 phy_c19 = phy_c19 >> 10;
3777 phy_c20 = ((phy_c18 * phy_c18) +
3778 (phy_c19 * phy_c19));
3780 if (phy_c23 || phy_c20 < phy_c21) {
3781 phy_c21 = phy_c20;
3782 phy_c13 = phy_c11;
3783 phy_c14 = phy_c12;
3785 phy_c23 = false;
3788 phy_c23 = true;
3789 phy_c15 = phy_c13;
3790 phy_c16 = phy_c14;
3791 phy_c7 = phy_c7 >> 1;
3792 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3793 udelay(20);
3795 goto cleanup;
3796 cleanup:
3797 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3798 wlc_lcnphy_stop_tx_tone(pi);
3799 write_phy_reg(pi, 0x6da, phy_c26);
3800 write_phy_reg(pi, 0x6db, phy_c27);
3801 write_phy_reg(pi, 0x938, phy_c28);
3802 write_phy_reg(pi, 0x4d7, phy_c29);
3803 write_phy_reg(pi, 0x4d8, phy_c30);
3804 write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3806 kfree(phy_c32);
3807 kfree(ptr);
3810 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3812 u16 iqcc[2];
3813 struct phytbl_info tab;
3815 tab.tbl_ptr = iqcc;
3816 tab.tbl_len = 2;
3817 tab.tbl_id = 0;
3818 tab.tbl_offset = 80;
3819 tab.tbl_width = 16;
3820 wlc_lcnphy_read_table(pi, &tab);
3822 *a = iqcc[0];
3823 *b = iqcc[1];
3826 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3828 struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3830 wlc_lcnphy_set_cc(pi, 0, 0, 0);
3831 wlc_lcnphy_set_cc(pi, 2, 0, 0);
3832 wlc_lcnphy_set_cc(pi, 3, 0, 0);
3833 wlc_lcnphy_set_cc(pi, 4, 0, 0);
3835 wlc_lcnphy_a1(pi, 4, 0, 0);
3836 wlc_lcnphy_a1(pi, 3, 0, 0);
3837 wlc_lcnphy_a1(pi, 2, 3, 2);
3838 wlc_lcnphy_a1(pi, 0, 5, 8);
3839 wlc_lcnphy_a1(pi, 2, 2, 1);
3840 wlc_lcnphy_a1(pi, 0, 4, 3);
3842 iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3843 locc2 = wlc_lcnphy_get_cc(pi, 2);
3844 locc3 = wlc_lcnphy_get_cc(pi, 3);
3845 locc4 = wlc_lcnphy_get_cc(pi, 4);
3848 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3850 struct phytbl_info tab;
3851 u16 didq;
3853 tab.tbl_id = 0;
3854 tab.tbl_width = 16;
3855 tab.tbl_ptr = &didq;
3856 tab.tbl_len = 1;
3857 tab.tbl_offset = 85;
3858 wlc_lcnphy_read_table(pi, &tab);
3860 return didq;
3863 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3866 struct lcnphy_txgains target_gains, old_gains;
3867 u8 save_bb_mult;
3868 u16 a, b, didq, save_pa_gain = 0;
3869 uint idx, SAVE_txpwrindex = 0xFF;
3870 u32 val;
3871 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3872 struct phytbl_info tab;
3873 u8 ei0, eq0, fi0, fq0;
3874 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3876 wlc_lcnphy_get_tx_gain(pi, &old_gains);
3877 save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3879 save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3881 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3882 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3884 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3886 target_gains.gm_gain = 7;
3887 target_gains.pga_gain = 0;
3888 target_gains.pad_gain = 21;
3889 target_gains.dac_gain = 0;
3890 wlc_lcnphy_set_tx_gain(pi, &target_gains);
3891 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3893 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3895 wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3897 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3898 (pi_lcn->
3899 lcnphy_recal ? LCNPHY_CAL_RECAL :
3900 LCNPHY_CAL_FULL), false);
3901 } else {
3902 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3905 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3906 if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3907 if (CHSPEC_IS5G(pi->radio_chanspec)) {
3908 target_gains.gm_gain = 255;
3909 target_gains.pga_gain = 255;
3910 target_gains.pad_gain = 0xf0;
3911 target_gains.dac_gain = 0;
3912 } else {
3913 target_gains.gm_gain = 7;
3914 target_gains.pga_gain = 45;
3915 target_gains.pad_gain = 186;
3916 target_gains.dac_gain = 0;
3919 if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3920 || pi_lcn->lcnphy_hw_iqcal_en) {
3922 target_gains.pga_gain = 0;
3923 target_gains.pad_gain = 30;
3924 wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3925 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3926 LCNPHY_CAL_FULL, false);
3927 } else {
3928 wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3932 wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3934 didq = wlc_lcnphy_get_tx_locc(pi);
3936 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3937 tab.tbl_width = 32;
3938 tab.tbl_ptr = &val;
3940 tab.tbl_len = 1;
3941 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3943 for (idx = 0; idx < 128; idx++) {
3944 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3946 wlc_lcnphy_read_table(pi, &tab);
3947 val = (val & 0xfff00000) |
3948 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3949 wlc_lcnphy_write_table(pi, &tab);
3951 val = didq;
3952 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
3953 wlc_lcnphy_write_table(pi, &tab);
3956 pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
3957 pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
3958 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
3959 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
3960 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
3961 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
3962 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
3964 wlc_lcnphy_set_bbmult(pi, save_bb_mult);
3965 wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
3966 wlc_lcnphy_set_tx_gain(pi, &old_gains);
3968 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
3969 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
3970 else
3971 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
3974 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
3976 u16 tempsenseval1, tempsenseval2;
3977 s16 avg = 0;
3978 bool suspend = false;
3980 if (mode == 1) {
3981 suspend = (0 == (bcma_read32(pi->d11core,
3982 D11REGOFFS(maccontrol)) &
3983 MCTL_EN_MAC));
3984 if (!suspend)
3985 wlapi_suspend_mac_and_wait(pi->sh->physhim);
3986 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3988 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
3989 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
3991 if (tempsenseval1 > 255)
3992 avg = (s16) (tempsenseval1 - 512);
3993 else
3994 avg = (s16) tempsenseval1;
3996 if (tempsenseval2 > 255)
3997 avg += (s16) (tempsenseval2 - 512);
3998 else
3999 avg += (s16) tempsenseval2;
4001 avg /= 2;
4003 if (mode == 1) {
4005 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4007 udelay(100);
4008 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4010 if (!suspend)
4011 wlapi_enable_mac(pi->sh->physhim);
4013 return avg;
4016 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4018 u16 tempsenseval1, tempsenseval2;
4019 s32 avg = 0;
4020 bool suspend = false;
4021 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4022 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4024 if (mode == 1) {
4025 suspend = (0 == (bcma_read32(pi->d11core,
4026 D11REGOFFS(maccontrol)) &
4027 MCTL_EN_MAC));
4028 if (!suspend)
4029 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4030 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4032 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4033 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4035 if (tempsenseval1 > 255)
4036 avg = (int)(tempsenseval1 - 512);
4037 else
4038 avg = (int)tempsenseval1;
4040 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4041 if (tempsenseval2 > 255)
4042 avg = (int)(avg - tempsenseval2 + 512);
4043 else
4044 avg = (int)(avg - tempsenseval2);
4045 } else {
4046 if (tempsenseval2 > 255)
4047 avg = (int)(avg + tempsenseval2 - 512);
4048 else
4049 avg = (int)(avg + tempsenseval2);
4050 avg = avg / 2;
4052 if (avg < 0)
4053 avg = avg + 512;
4055 if (pi_lcn->lcnphy_tempsense_option == 2)
4056 avg = tempsenseval1;
4058 if (mode)
4059 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4061 if (mode == 1) {
4063 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4065 udelay(100);
4066 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4068 if (!suspend)
4069 wlapi_enable_mac(pi->sh->physhim);
4071 return (u16) avg;
4074 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4076 s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4077 degree =
4078 ((degree <<
4079 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4080 / LCN_TEMPSENSE_DEN;
4081 return (s8) degree;
4084 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4086 u16 vbatsenseval;
4087 s32 avg = 0;
4088 bool suspend = false;
4090 if (mode == 1) {
4091 suspend = (0 == (bcma_read32(pi->d11core,
4092 D11REGOFFS(maccontrol)) &
4093 MCTL_EN_MAC));
4094 if (!suspend)
4095 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4096 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4099 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4101 if (vbatsenseval > 255)
4102 avg = (s32) (vbatsenseval - 512);
4103 else
4104 avg = (s32) vbatsenseval;
4106 avg = (avg * LCN_VBAT_SCALE_NOM +
4107 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4109 if (mode == 1) {
4110 if (!suspend)
4111 wlapi_enable_mac(pi->sh->physhim);
4113 return (s8) avg;
4116 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4118 u8 phybw40;
4119 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4121 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4123 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4124 (mode == AFE_CLK_INIT_MODE_TXRX2X))
4125 write_phy_reg(pi, 0x6d0, 0x7);
4127 wlc_lcnphy_toggle_afe_pwdn(pi);
4130 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4134 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4136 bool suspend;
4137 s8 index;
4138 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4139 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4140 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4141 MCTL_EN_MAC));
4142 if (!suspend)
4143 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4144 wlc_lcnphy_deaf_mode(pi, true);
4145 pi->phy_lastcal = pi->sh->now;
4146 pi->phy_forcecal = false;
4147 index = pi_lcn->lcnphy_current_index;
4149 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4151 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4152 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4153 wlc_lcnphy_deaf_mode(pi, false);
4154 if (!suspend)
4155 wlapi_enable_mac(pi->sh->physhim);
4159 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4161 bool suspend, full_cal;
4162 const struct lcnphy_rx_iqcomp *rx_iqcomp;
4163 int rx_iqcomp_sz;
4164 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4165 s8 index;
4166 struct phytbl_info tab;
4167 s32 a1, b0, b1;
4168 s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4169 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4171 pi->phy_lastcal = pi->sh->now;
4172 pi->phy_forcecal = false;
4173 full_cal =
4174 (pi_lcn->lcnphy_full_cal_channel !=
4175 CHSPEC_CHANNEL(pi->radio_chanspec));
4176 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4177 index = pi_lcn->lcnphy_current_index;
4179 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4180 MCTL_EN_MAC));
4181 if (!suspend) {
4182 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4183 wlapi_suspend_mac_and_wait(pi->sh->physhim);
4186 wlc_lcnphy_deaf_mode(pi, true);
4188 wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4190 rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4191 rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4193 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4194 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4195 else
4196 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4198 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4200 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4202 b0 = pi->txpa_2g[0];
4203 b1 = pi->txpa_2g[1];
4204 a1 = pi->txpa_2g[2];
4205 maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4206 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4208 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4209 tab.tbl_width = 32;
4210 tab.tbl_ptr = &pwr;
4211 tab.tbl_len = 1;
4212 tab.tbl_offset = 0;
4213 for (tssi = 0; tssi < 128; tssi++) {
4214 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4215 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4216 wlc_lcnphy_write_table(pi, &tab);
4217 tab.tbl_offset++;
4221 wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4222 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4223 wlc_lcnphy_deaf_mode(pi, false);
4224 if (!suspend)
4225 wlapi_enable_mac(pi->sh->physhim);
4228 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4230 u16 temp_new;
4231 int temp1, temp2, temp_diff;
4232 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4234 switch (mode) {
4235 case PHY_PERICAL_CHAN:
4236 break;
4237 case PHY_FULLCAL:
4238 wlc_lcnphy_periodic_cal(pi);
4239 break;
4240 case PHY_PERICAL_PHYINIT:
4241 wlc_lcnphy_periodic_cal(pi);
4242 break;
4243 case PHY_PERICAL_WATCHDOG:
4244 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4245 temp_new = wlc_lcnphy_tempsense(pi, 0);
4246 temp1 = LCNPHY_TEMPSENSE(temp_new);
4247 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4248 temp_diff = temp1 - temp2;
4249 if ((pi_lcn->lcnphy_cal_counter > 90) ||
4250 (temp_diff > 60) || (temp_diff < -60)) {
4251 wlc_lcnphy_glacial_timer_based_cal(pi);
4252 wlc_2064_vco_cal(pi);
4253 pi_lcn->lcnphy_cal_temper = temp_new;
4254 pi_lcn->lcnphy_cal_counter = 0;
4255 } else
4256 pi_lcn->lcnphy_cal_counter++;
4258 break;
4259 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4260 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4261 wlc_lcnphy_tx_power_adjustment(
4262 (struct brcms_phy_pub *) pi);
4263 break;
4267 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4269 s8 cck_offset;
4270 u16 status;
4271 status = (read_phy_reg(pi, 0x4ab));
4272 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4273 (status & (0x1 << 15))) {
4274 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4275 >> 0) >> 1);
4277 if (wlc_phy_tpc_isenabled_lcnphy(pi))
4278 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4279 else
4280 cck_offset = 0;
4282 *cck_pwr = *ofdm_pwr + cck_offset;
4283 } else {
4284 *cck_pwr = 0;
4285 *ofdm_pwr = 0;
4289 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4291 return;
4295 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4297 s8 index;
4298 u16 index2;
4299 struct brcms_phy *pi = (struct brcms_phy *) ppi;
4300 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4301 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4302 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4303 SAVE_txpwrctrl) {
4304 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4305 index2 = (u16) (index * 2);
4306 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4308 pi_lcn->lcnphy_current_index =
4309 (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4313 static void
4314 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4315 const struct lcnphy_tx_gain_tbl_entry *gain_table)
4317 u32 j;
4318 struct phytbl_info tab;
4319 u32 val;
4320 u16 pa_gain;
4321 u16 gm_gain;
4323 if (pi->sh->boardflags & BFL_FEM)
4324 pa_gain = 0x10;
4325 else
4326 pa_gain = 0x60;
4327 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4328 tab.tbl_width = 32;
4329 tab.tbl_len = 1;
4330 tab.tbl_ptr = &val;
4332 for (j = 0; j < 128; j++) {
4333 gm_gain = gain_table[j].gm;
4334 val = (((u32) pa_gain << 24) |
4335 (gain_table[j].pad << 16) |
4336 (gain_table[j].pga << 8) | gm_gain);
4338 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4339 wlc_lcnphy_write_table(pi, &tab);
4341 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4342 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4343 wlc_lcnphy_write_table(pi, &tab);
4347 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4349 struct phytbl_info tab;
4350 u32 val, bbmult, rfgain;
4351 u8 index;
4352 u8 scale_factor = 1;
4353 s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4355 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4356 tab.tbl_width = 32;
4357 tab.tbl_len = 1;
4359 for (index = 0; index < 128; index++) {
4360 tab.tbl_ptr = &bbmult;
4361 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4362 wlc_lcnphy_read_table(pi, &tab);
4363 bbmult = bbmult >> 20;
4365 tab.tbl_ptr = &rfgain;
4366 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4367 wlc_lcnphy_read_table(pi, &tab);
4369 qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4370 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4372 if (qQ1 < qQ2) {
4373 temp2 = qm_shr16(temp2, qQ2 - qQ1);
4374 qQ = qQ1;
4375 } else {
4376 temp1 = qm_shr16(temp1, qQ1 - qQ2);
4377 qQ = qQ2;
4379 temp = qm_sub16(temp1, temp2);
4381 if (qQ >= 4)
4382 shift = qQ - 4;
4383 else
4384 shift = 4 - qQ;
4386 val = (((index << shift) + (5 * temp) +
4387 (1 << (scale_factor + shift - 3))) >> (scale_factor +
4388 shift - 2));
4390 tab.tbl_ptr = &val;
4391 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4392 wlc_lcnphy_write_table(pi, &tab);
4396 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4398 or_phy_reg(pi, 0x805, 0x1);
4400 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4402 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4404 write_phy_reg(pi, 0x414, 0x1e10);
4405 write_phy_reg(pi, 0x415, 0x0640);
4407 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4409 or_phy_reg(pi, 0x44a, 0x44);
4410 write_phy_reg(pi, 0x44a, 0x80);
4411 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4413 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4415 if (!(pi->sh->boardrev < 0x1204))
4416 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4418 write_phy_reg(pi, 0x7d6, 0x0902);
4419 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4421 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4423 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4424 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4426 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4428 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4430 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4432 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4434 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4435 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4436 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4437 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4438 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4440 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4442 wlc_lcnphy_clear_tx_power_offsets(pi);
4443 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4448 static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4450 u8 rcal_value;
4452 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4454 or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4455 or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4457 or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4458 or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4460 or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4462 or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4463 mdelay(5);
4464 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4466 if (wlc_radio_2064_rcal_done(pi)) {
4467 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4468 rcal_value = rcal_value & 0x1f;
4471 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4473 and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4476 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4478 u8 dflt_rc_cal_val;
4479 u16 flt_val;
4481 dflt_rc_cal_val = 7;
4482 if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4483 dflt_rc_cal_val = 11;
4484 flt_val =
4485 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4486 (dflt_rc_cal_val);
4487 write_phy_reg(pi, 0x933, flt_val);
4488 write_phy_reg(pi, 0x934, flt_val);
4489 write_phy_reg(pi, 0x935, flt_val);
4490 write_phy_reg(pi, 0x936, flt_val);
4491 write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4493 return;
4496 static void wlc_radio_2064_init(struct brcms_phy *pi)
4498 u32 i;
4499 const struct lcnphy_radio_regs *lcnphyregs = NULL;
4501 lcnphyregs = lcnphy_radio_regs_2064;
4503 for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4504 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4505 write_radio_reg(pi,
4506 ((lcnphyregs[i].address & 0x3fff) |
4507 RADIO_DEFAULT_CORE),
4508 (u16) lcnphyregs[i].init_a);
4509 else if (lcnphyregs[i].do_init_g)
4510 write_radio_reg(pi,
4511 ((lcnphyregs[i].address & 0x3fff) |
4512 RADIO_DEFAULT_CORE),
4513 (u16) lcnphyregs[i].init_g);
4515 write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4516 write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4518 write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4520 write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4522 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4524 write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4525 write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4526 write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4529 write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4530 write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4532 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4534 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4536 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4538 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4540 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4542 write_phy_reg(pi, 0x4ea, 0x4688);
4544 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4546 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4548 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4550 wlc_lcnphy_set_tx_locc(pi, 0);
4552 wlc_lcnphy_rcal(pi);
4554 wlc_lcnphy_rc_cal(pi);
4557 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4559 wlc_radio_2064_init(pi);
4562 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4564 uint idx;
4565 u8 phybw40;
4566 struct phytbl_info tab;
4567 u32 val;
4569 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4571 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4572 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4574 if (pi->sh->boardflags & BFL_FEM_BT) {
4575 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4576 tab.tbl_width = 16;
4577 tab.tbl_ptr = &val;
4578 tab.tbl_len = 1;
4579 val = 100;
4580 tab.tbl_offset = 4;
4581 wlc_lcnphy_write_table(pi, &tab);
4584 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4585 tab.tbl_width = 16;
4586 tab.tbl_ptr = &val;
4587 tab.tbl_len = 1;
4589 val = 114;
4590 tab.tbl_offset = 0;
4591 wlc_lcnphy_write_table(pi, &tab);
4593 val = 130;
4594 tab.tbl_offset = 1;
4595 wlc_lcnphy_write_table(pi, &tab);
4597 val = 6;
4598 tab.tbl_offset = 8;
4599 wlc_lcnphy_write_table(pi, &tab);
4601 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4602 if (pi->sh->boardflags & BFL_FEM)
4603 wlc_lcnphy_load_tx_gain_table(
4605 dot11lcnphy_2GHz_extPA_gaintable_rev0);
4606 else
4607 wlc_lcnphy_load_tx_gain_table(
4609 dot11lcnphy_2GHz_gaintable_rev0);
4612 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4613 const struct phytbl_info *tb;
4614 int l;
4616 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4617 l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4618 if (pi->sh->boardflags & BFL_EXTLNA)
4619 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4620 else
4621 tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4622 } else {
4623 l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4624 if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4625 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4626 else
4627 tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4630 for (idx = 0; idx < l; idx++)
4631 wlc_lcnphy_write_table(pi, &tb[idx]);
4634 if ((pi->sh->boardflags & BFL_FEM)
4635 && !(pi->sh->boardflags & BFL_FEM_BT))
4636 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
4637 else if (pi->sh->boardflags & BFL_FEM_BT) {
4638 if (pi->sh->boardrev < 0x1250)
4639 wlc_lcnphy_write_table(
4641 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
4642 else
4643 wlc_lcnphy_write_table(
4645 &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
4646 } else
4647 wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
4649 wlc_lcnphy_load_rfpower(pi);
4651 wlc_lcnphy_clear_papd_comptable(pi);
4654 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4656 u16 afectrl1;
4657 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4659 write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4661 write_phy_reg(pi, 0x43b, 0x0);
4662 write_phy_reg(pi, 0x43c, 0x0);
4663 write_phy_reg(pi, 0x44c, 0x0);
4664 write_phy_reg(pi, 0x4e6, 0x0);
4665 write_phy_reg(pi, 0x4f9, 0x0);
4666 write_phy_reg(pi, 0x4b0, 0x0);
4667 write_phy_reg(pi, 0x938, 0x0);
4668 write_phy_reg(pi, 0x4b0, 0x0);
4669 write_phy_reg(pi, 0x44e, 0);
4671 or_phy_reg(pi, 0x567, 0x03);
4673 or_phy_reg(pi, 0x44a, 0x44);
4674 write_phy_reg(pi, 0x44a, 0x80);
4676 if (!(pi->sh->boardflags & BFL_FEM))
4677 wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4679 if (0) {
4680 afectrl1 = 0;
4681 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4682 (pi_lcn->lcnphy_rssi_vc << 4) |
4683 (pi_lcn->lcnphy_rssi_gs << 10));
4684 write_phy_reg(pi, 0x43e, afectrl1);
4687 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4688 if (pi->sh->boardflags & BFL_FEM) {
4689 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4691 write_phy_reg(pi, 0x910, 0x1);
4694 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4695 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4696 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4700 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4702 if (CHSPEC_IS5G(pi->radio_chanspec)) {
4703 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4704 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4708 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4710 s16 temp;
4711 struct phytbl_info tab;
4712 u32 tableBuffer[2];
4713 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4715 temp = (s16) read_phy_reg(pi, 0x4df);
4716 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4718 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4719 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4721 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4723 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4724 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4726 tab.tbl_ptr = tableBuffer;
4727 tab.tbl_len = 2;
4728 tab.tbl_id = 17;
4729 tab.tbl_offset = 59;
4730 tab.tbl_width = 32;
4731 wlc_lcnphy_read_table(pi, &tab);
4733 if (tableBuffer[0] > 63)
4734 tableBuffer[0] -= 128;
4735 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4737 if (tableBuffer[1] > 63)
4738 tableBuffer[1] -= 128;
4739 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4741 temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4742 if (temp > 127)
4743 temp -= 256;
4744 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4746 pi_lcn->lcnphy_Med_Low_Gain_db =
4747 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4748 pi_lcn->lcnphy_Very_Low_Gain_db =
4749 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4751 tab.tbl_ptr = tableBuffer;
4752 tab.tbl_len = 2;
4753 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4754 tab.tbl_offset = 28;
4755 tab.tbl_width = 32;
4756 wlc_lcnphy_read_table(pi, &tab);
4758 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4759 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4763 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4766 wlc_lcnphy_tbl_init(pi);
4767 wlc_lcnphy_rev0_baseband_init(pi);
4768 if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4769 wlc_lcnphy_rev2_baseband_init(pi);
4770 wlc_lcnphy_bu_tweaks(pi);
4773 void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4775 u8 phybw40;
4776 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4777 phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4779 pi_lcn->lcnphy_cal_counter = 0;
4780 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4782 or_phy_reg(pi, 0x44a, 0x80);
4783 and_phy_reg(pi, 0x44a, 0x7f);
4785 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4787 write_phy_reg(pi, 0x60a, 160);
4789 write_phy_reg(pi, 0x46a, 25);
4791 wlc_lcnphy_baseband_init(pi);
4793 wlc_lcnphy_radio_init(pi);
4795 if (CHSPEC_IS2G(pi->radio_chanspec))
4796 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4798 wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4800 bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4802 bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4803 0x03CDDDDD);
4805 if ((pi->sh->boardflags & BFL_FEM)
4806 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4807 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4809 wlc_lcnphy_agc_temp_init(pi);
4811 wlc_lcnphy_temp_adj(pi);
4813 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4815 udelay(100);
4816 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4818 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4819 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4820 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4823 static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4825 s8 txpwr = 0;
4826 int i;
4827 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4828 struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4830 if (CHSPEC_IS2G(pi->radio_chanspec)) {
4831 u16 cckpo = 0;
4832 u32 offset_ofdm, offset_mcs;
4834 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4836 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4838 pi->txpa_2g[0] = sprom->pa0b0;
4839 pi->txpa_2g[1] = sprom->pa0b1;
4840 pi->txpa_2g[2] = sprom->pa0b2;
4842 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4843 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4844 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4846 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4847 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4848 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4850 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4851 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4852 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4854 txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4855 pi->tx_srom_max_2g = txpwr;
4857 for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4858 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4859 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4862 cckpo = sprom->cck2gpo;
4863 offset_ofdm = sprom->ofdm2gpo;
4864 if (cckpo) {
4865 uint max_pwr_chan = txpwr;
4867 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4868 pi->tx_srom_max_rate_2g[i] =
4869 max_pwr_chan - ((cckpo & 0xf) * 2);
4870 cckpo >>= 4;
4873 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4874 pi->tx_srom_max_rate_2g[i] =
4875 max_pwr_chan -
4876 ((offset_ofdm & 0xf) * 2);
4877 offset_ofdm >>= 4;
4879 } else {
4880 u8 opo = 0;
4882 opo = sprom->opo;
4884 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4885 pi->tx_srom_max_rate_2g[i] = txpwr;
4887 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4888 pi->tx_srom_max_rate_2g[i] = txpwr -
4889 ((offset_ofdm & 0xf) * 2);
4890 offset_ofdm >>= 4;
4892 offset_mcs = sprom->mcs2gpo[1] << 16;
4893 offset_mcs |= sprom->mcs2gpo[0];
4894 pi_lcn->lcnphy_mcs20_po = offset_mcs;
4895 for (i = TXP_FIRST_SISO_MCS_20;
4896 i <= TXP_LAST_SISO_MCS_20; i++) {
4897 pi->tx_srom_max_rate_2g[i] =
4898 txpwr - ((offset_mcs & 0xf) * 2);
4899 offset_mcs >>= 4;
4903 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4904 pi_lcn->lcnphy_measPower = sprom->measpower;
4905 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4906 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4907 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4908 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4909 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4910 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4911 if (sprom->ant_available_bg > 1)
4912 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4913 sprom->ant_available_bg);
4915 pi_lcn->lcnphy_cck_dig_filt_type = -1;
4917 return true;
4920 void wlc_2064_vco_cal(struct brcms_phy *pi)
4922 u8 calnrst;
4924 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4925 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4926 write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4927 udelay(1);
4928 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4929 udelay(1);
4930 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4931 udelay(300);
4932 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4935 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4937 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4938 return 0;
4939 else
4940 return (LCNPHY_TX_PWR_CTRL_HW ==
4941 wlc_lcnphy_get_tx_pwr_ctrl((pi)));
4944 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
4946 u16 pwr_ctrl;
4947 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4948 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
4949 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4950 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4951 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
4952 wlc_lcnphy_txpower_recalc_target(pi);
4953 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
4957 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
4959 u8 channel = CHSPEC_CHANNEL(chanspec);
4961 wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
4963 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
4965 or_phy_reg(pi, 0x44a, 0x44);
4966 write_phy_reg(pi, 0x44a, 0x80);
4968 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
4969 udelay(1000);
4971 wlc_lcnphy_toggle_afe_pwdn(pi);
4973 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
4974 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
4976 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
4977 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
4979 wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
4980 } else {
4981 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
4983 wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
4986 if (pi->sh->boardflags & BFL_FEM)
4987 wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
4988 else
4989 wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
4991 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
4994 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
4996 kfree(pi->u.pi_lcnphy);
4999 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5001 struct brcms_phy_lcnphy *pi_lcn;
5003 pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5004 if (pi->u.pi_lcnphy == NULL)
5005 return false;
5007 pi_lcn = pi->u.pi_lcnphy;
5009 if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5010 pi->hwpwrctrl = true;
5011 pi->hwpwrctrl_capable = true;
5014 pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5015 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5017 pi->pi_fptr.init = wlc_phy_init_lcnphy;
5018 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5019 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5020 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5021 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5022 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5023 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5024 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5025 pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5027 if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5028 return false;
5030 if ((pi->sh->boardflags & BFL_FEM) &&
5031 (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
5032 if (pi_lcn->lcnphy_tempsense_option == 3) {
5033 pi->hwpwrctrl = true;
5034 pi->hwpwrctrl_capable = true;
5035 pi->temppwrctrl_capable = false;
5036 } else {
5037 pi->hwpwrctrl = false;
5038 pi->hwpwrctrl_capable = false;
5039 pi->temppwrctrl_capable = true;
5043 return true;
5046 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5048 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5050 trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5051 ext_lna = (u16) (gain >> 29) & 0x01;
5052 lna1 = (u16) (gain >> 0) & 0x0f;
5053 lna2 = (u16) (gain >> 4) & 0x0f;
5054 tia = (u16) (gain >> 8) & 0xf;
5055 biq0 = (u16) (gain >> 12) & 0xf;
5056 biq1 = (u16) (gain >> 16) & 0xf;
5058 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5059 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5060 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5061 gain16_19 = biq1;
5063 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5064 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5065 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5066 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5067 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5069 if (CHSPEC_IS2G(pi->radio_chanspec)) {
5070 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5071 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5073 wlc_lcnphy_rx_gain_override_enable(pi, true);
5076 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5078 u32 received_power = 0;
5079 s32 max_index = 0;
5080 u32 gain_code = 0;
5081 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5083 max_index = 36;
5084 if (*gain_index >= 0)
5085 gain_code = lcnphy_23bitgaincode_table[*gain_index];
5087 if (-1 == *gain_index) {
5088 *gain_index = 0;
5089 while ((*gain_index <= (s32) max_index)
5090 && (received_power < 700)) {
5091 wlc_lcnphy_set_rx_gain(pi,
5092 lcnphy_23bitgaincode_table
5093 [*gain_index]);
5094 received_power =
5095 wlc_lcnphy_measure_digital_power(
5097 pi_lcn->
5098 lcnphy_noise_samples);
5099 (*gain_index)++;
5101 (*gain_index)--;
5102 } else {
5103 wlc_lcnphy_set_rx_gain(pi, gain_code);
5104 received_power =
5105 wlc_lcnphy_measure_digital_power(pi,
5106 pi_lcn->
5107 lcnphy_noise_samples);
5110 return received_power;
5113 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5115 s32 gain = 0;
5116 s32 nominal_power_db;
5117 s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5118 input_power_db;
5119 s32 received_power, temperature;
5120 u32 power;
5121 u32 msb1, msb2, val1, val2, diff1, diff2;
5122 uint freq;
5123 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5125 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5127 gain = lcnphy_gain_table[gain_index];
5129 nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5131 power = (received_power * 16);
5132 msb1 = ffs(power) - 1;
5133 msb2 = msb1 + 1;
5134 val1 = 1 << msb1;
5135 val2 = 1 << msb2;
5136 diff1 = (power - val1);
5137 diff2 = (val2 - power);
5138 if (diff1 < diff2)
5139 log_val = msb1;
5140 else
5141 log_val = msb2;
5143 log_val = log_val * 3;
5145 gain_mismatch = (nominal_power_db / 2) - (log_val);
5147 desired_gain = gain + gain_mismatch;
5149 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5151 if (input_power_offset_db > 127)
5152 input_power_offset_db -= 256;
5154 input_power_db = input_power_offset_db - desired_gain;
5156 input_power_db =
5157 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5159 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5160 if ((freq > 2427) && (freq <= 2467))
5161 input_power_db = input_power_db - 1;
5163 temperature = pi_lcn->lcnphy_lastsensed_temperature;
5165 if ((temperature - 15) < -30)
5166 input_power_db =
5167 input_power_db +
5168 (((temperature - 10 - 25) * 286) >> 12) -
5170 else if ((temperature - 15) < 4)
5171 input_power_db =
5172 input_power_db +
5173 (((temperature - 10 - 25) * 286) >> 12) -
5175 else
5176 input_power_db = input_power_db +
5177 (((temperature - 10 - 25) * 286) >> 12);
5179 wlc_lcnphy_rx_gain_override_enable(pi, 0);
5181 return input_power_db;