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