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