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 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_objs(s16, 131, 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 pll_pwrup, pll_pwrup_ovr; 1611 s32 qFcal; 1612 u8 d15, d16, f16, e44, e45; 1613 u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div; 1614 u16 loop_bw, d30, setCount; 1615 1616 u8 h29, h28_ten, e30, h30_ten, cp_current; 1617 u16 g30, d28; 1618 1619 ci = &chan_info_2064_lcnphy[0]; 1620 1621 mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2); 1622 1623 write_radio_reg(pi, RADIO_2064_REG09E, 0xf); 1624 loop_bw = PLL_2064_LOOP_BW_DOUBLER; 1625 d30 = PLL_2064_D30_DOUBLER; 1626 1627 if (CHSPEC_IS2G(pi->radio_chanspec)) { 1628 for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++) 1629 if (chan_info_2064_lcnphy[i].chan == channel) 1630 break; 1631 1632 if (i >= ARRAY_SIZE(chan_info_2064_lcnphy)) 1633 return; 1634 1635 ci = &chan_info_2064_lcnphy[i]; 1636 } 1637 1638 write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune); 1639 1640 mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx); 1641 1642 mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl); 1643 1644 mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g); 1645 1646 mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2, 1647 (ci->logen_rccr_rx) << 2); 1648 1649 mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune); 1650 1651 mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4, 1652 (ci->pa_rxrf_lna2_freq_tune) << 4); 1653 1654 write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1); 1655 1656 pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044); 1657 pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B); 1658 1659 or_radio_reg(pi, RADIO_2064_REG044, 0x07); 1660 1661 or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1); 1662 e44 = 0; 1663 e45 = 0; 1664 1665 fpfd = pi->xtalfreq << 1; 1666 if (pi->xtalfreq > 26000000) 1667 e44 = 1; 1668 if (pi->xtalfreq > 52000000) 1669 e45 = 1; 1670 if (e44 == 0) 1671 fcal_div = 1; 1672 else if (e45 == 0) 1673 fcal_div = 2; 1674 else 1675 fcal_div = 4; 1676 fvco3 = (ci->freq * 3); 1677 fref3 = 2 * fpfd; 1678 1679 qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ; 1680 1681 write_radio_reg(pi, RADIO_2064_REG04F, 0x02); 1682 1683 d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1; 1684 write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2))); 1685 write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5); 1686 1687 d16 = (qFcal * 8 / (d15 + 1)) - 1; 1688 write_radio_reg(pi, RADIO_2064_REG051, d16); 1689 1690 f16 = ((d16 + 1) * (d15 + 1)) / qFcal; 1691 setCount = f16 * 3 * (ci->freq) / 32 - 1; 1692 mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0), 1693 (u8) (setCount >> 8)); 1694 1695 or_radio_reg(pi, RADIO_2064_REG053, 0x10); 1696 write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff)); 1697 1698 div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4; 1699 1700 div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4; 1701 while (div_frac >= fref3) { 1702 div_int++; 1703 div_frac -= fref3; 1704 } 1705 div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20); 1706 1707 mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0), 1708 (u8) (div_int >> 4)); 1709 mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4), 1710 (u8) (div_int << 4)); 1711 mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0), 1712 (u8) (div_frac >> 16)); 1713 write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff); 1714 write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff); 1715 1716 write_radio_reg(pi, RADIO_2064_REG040, 0xfb); 1717 1718 write_radio_reg(pi, RADIO_2064_REG041, 0x9A); 1719 write_radio_reg(pi, RADIO_2064_REG042, 0xA3); 1720 write_radio_reg(pi, RADIO_2064_REG043, 0x0C); 1721 1722 h29 = LCN_BW_LMT / loop_bw; 1723 d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) * 1724 (fvco3 / 2 - PLL_2064_LOW_END_VCO)) / 1725 (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO)) 1726 + PLL_2064_LOW_END_KVCO; 1727 h28_ten = (d28 * 10) / LCN_VCO_DIV; 1728 e30 = (d30 - LCN_OFFSET) / LCN_FACT; 1729 g30 = LCN_OFFSET + (e30 * LCN_FACT); 1730 h30_ten = (g30 * 10) / LCN_CUR_DIV; 1731 cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten; 1732 mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current); 1733 1734 if (channel >= 1 && channel <= 5) 1735 write_radio_reg(pi, RADIO_2064_REG03C, 0x8); 1736 else 1737 write_radio_reg(pi, RADIO_2064_REG03C, 0x7); 1738 write_radio_reg(pi, RADIO_2064_REG03D, 0x3); 1739 1740 mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c); 1741 udelay(1); 1742 1743 wlc_2064_vco_cal(pi); 1744 1745 write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup); 1746 write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr); 1747 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { 1748 write_radio_reg(pi, RADIO_2064_REG038, 3); 1749 write_radio_reg(pi, RADIO_2064_REG091, 7); 1750 } 1751 1752 if (!(pi->sh->boardflags & BFL_FEM)) { 1753 static const u8 reg038[14] = { 1754 0xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa, 1755 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0 1756 }; 1757 1758 write_radio_reg(pi, RADIO_2064_REG02A, 0xf); 1759 write_radio_reg(pi, RADIO_2064_REG091, 0x3); 1760 write_radio_reg(pi, RADIO_2064_REG038, 0x3); 1761 1762 write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); 1763 } 1764 } 1765 1766 static int 1767 wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type) 1768 { 1769 s16 filt_index = -1; 1770 int j; 1771 1772 u16 addr[] = { 1773 0x910, 1774 0x91e, 1775 0x91f, 1776 0x924, 1777 0x925, 1778 0x926, 1779 0x920, 1780 0x921, 1781 0x927, 1782 0x928, 1783 0x929, 1784 0x922, 1785 0x923, 1786 0x930, 1787 0x931, 1788 0x932 1789 }; 1790 1791 u16 addr_ofdm[] = { 1792 0x90f, 1793 0x900, 1794 0x901, 1795 0x906, 1796 0x907, 1797 0x908, 1798 0x902, 1799 0x903, 1800 0x909, 1801 0x90a, 1802 0x90b, 1803 0x904, 1804 0x905, 1805 0x90c, 1806 0x90d, 1807 0x90e 1808 }; 1809 1810 if (!is_ofdm) { 1811 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) { 1812 if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) { 1813 filt_index = (s16) j; 1814 break; 1815 } 1816 } 1817 1818 if (filt_index != -1) { 1819 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) 1820 write_phy_reg(pi, addr[j], 1821 LCNPHY_txdigfiltcoeffs_cck 1822 [filt_index][j + 1]); 1823 } 1824 } else { 1825 for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) { 1826 if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) { 1827 filt_index = (s16) j; 1828 break; 1829 } 1830 } 1831 1832 if (filt_index != -1) { 1833 for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) 1834 write_phy_reg(pi, addr_ofdm[j], 1835 LCNPHY_txdigfiltcoeffs_ofdm 1836 [filt_index][j + 1]); 1837 } 1838 } 1839 1840 return (filt_index != -1) ? 0 : -1; 1841 } 1842 1843 static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi) 1844 { 1845 u16 pa_gain; 1846 1847 pa_gain = (read_phy_reg(pi, 0x4fb) & 1848 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >> 1849 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT; 1850 1851 return pa_gain; 1852 } 1853 1854 static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi, 1855 struct lcnphy_txgains *target_gains) 1856 { 1857 u16 pa_gain = wlc_lcnphy_get_pa_gain(pi); 1858 1859 mod_phy_reg( 1860 pi, 0x4b5, 1861 (0xffff << 0), 1862 ((target_gains->gm_gain) | 1863 (target_gains->pga_gain << 8)) << 1864 0); 1865 mod_phy_reg(pi, 0x4fb, 1866 (0x7fff << 0), 1867 ((target_gains->pad_gain) | (pa_gain << 8)) << 0); 1868 1869 mod_phy_reg( 1870 pi, 0x4fc, 1871 (0xffff << 0), 1872 ((target_gains->gm_gain) | 1873 (target_gains->pga_gain << 8)) << 1874 0); 1875 mod_phy_reg(pi, 0x4fd, 1876 (0x7fff << 0), 1877 ((target_gains->pad_gain) | (pa_gain << 8)) << 0); 1878 1879 wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain); 1880 1881 wlc_lcnphy_enable_tx_gain_override(pi); 1882 } 1883 1884 static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) 1885 { 1886 u16 m0m1; 1887 struct phytbl_info tab; 1888 1889 tab.tbl_ptr = &m0m1; 1890 tab.tbl_len = 1; 1891 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; 1892 tab.tbl_offset = 87; 1893 tab.tbl_width = 16; 1894 wlc_lcnphy_read_table(pi, &tab); 1895 1896 return (u8) ((m0m1 & 0xff00) >> 8); 1897 } 1898 1899 static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0) 1900 { 1901 u16 m0m1 = (u16) m0 << 8; 1902 struct phytbl_info tab; 1903 1904 tab.tbl_ptr = &m0m1; 1905 tab.tbl_len = 1; 1906 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; 1907 tab.tbl_offset = 87; 1908 tab.tbl_width = 16; 1909 wlc_lcnphy_write_table(pi, &tab); 1910 } 1911 1912 static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi) 1913 { 1914 u32 data_buf[64]; 1915 struct phytbl_info tab; 1916 1917 memset(data_buf, 0, sizeof(data_buf)); 1918 1919 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 1920 tab.tbl_width = 32; 1921 tab.tbl_ptr = data_buf; 1922 1923 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { 1924 1925 tab.tbl_len = 30; 1926 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; 1927 wlc_lcnphy_write_table(pi, &tab); 1928 } 1929 1930 tab.tbl_len = 64; 1931 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET; 1932 wlc_lcnphy_write_table(pi, &tab); 1933 } 1934 1935 enum lcnphy_tssi_mode { 1936 LCNPHY_TSSI_PRE_PA, 1937 LCNPHY_TSSI_POST_PA, 1938 LCNPHY_TSSI_EXT 1939 }; 1940 1941 static void 1942 wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) 1943 { 1944 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0); 1945 1946 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6); 1947 1948 if (LCNPHY_TSSI_POST_PA == pos) { 1949 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2); 1950 1951 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3); 1952 1953 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 1954 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); 1955 } else { 1956 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); 1957 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); 1958 mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); 1959 mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); 1960 mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); 1961 mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); 1962 mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); 1963 mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); 1964 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); 1965 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); 1966 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); 1967 mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4); 1968 } 1969 } else { 1970 mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); 1971 1972 mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3); 1973 1974 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 1975 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); 1976 } else { 1977 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); 1978 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); 1979 } 1980 } 1981 mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14); 1982 1983 if (LCNPHY_TSSI_EXT == pos) { 1984 write_radio_reg(pi, RADIO_2064_REG07F, 1); 1985 mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2); 1986 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7); 1987 mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3); 1988 } 1989 } 1990 1991 static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi) 1992 { 1993 u16 N1, N2, N3, N4, N5, N6, N; 1994 N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0)) 1995 >> 0); 1996 N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12)) 1997 >> 12); 1998 N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0)) 1999 >> 0); 2000 N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8)) 2001 >> 8); 2002 N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0)) 2003 >> 0); 2004 N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8)) 2005 >> 8); 2006 N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80; 2007 if (N < 1600) 2008 N = 1600; 2009 return N; 2010 } 2011 2012 static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) 2013 { 2014 u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp; 2015 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2016 2017 auxpga_vmid = (2 << 8) | 2018 (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf; 2019 auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4; 2020 auxpga_gain_temp = 2; 2021 2022 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0); 2023 2024 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1); 2025 2026 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3); 2027 2028 mod_phy_reg(pi, 0x4db, 2029 (0x3ff << 0) | 2030 (0x7 << 12), 2031 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); 2032 2033 mod_phy_reg(pi, 0x4dc, 2034 (0x3ff << 0) | 2035 (0x7 << 12), 2036 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); 2037 2038 mod_phy_reg(pi, 0x40a, 2039 (0x3ff << 0) | 2040 (0x7 << 12), 2041 (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); 2042 2043 mod_phy_reg(pi, 0x40b, 2044 (0x3ff << 0) | 2045 (0x7 << 12), 2046 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); 2047 2048 mod_phy_reg(pi, 0x40c, 2049 (0x3ff << 0) | 2050 (0x7 << 12), 2051 (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); 2052 2053 mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); 2054 mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0)); 2055 } 2056 2057 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) 2058 { 2059 struct phytbl_info tab; 2060 u32 rfseq, ind; 2061 enum lcnphy_tssi_mode mode; 2062 u8 tssi_sel; 2063 2064 if (pi->sh->boardflags & BFL_FEM) { 2065 tssi_sel = 0x1; 2066 mode = LCNPHY_TSSI_EXT; 2067 } else { 2068 tssi_sel = 0xe; 2069 mode = LCNPHY_TSSI_POST_PA; 2070 } 2071 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 2072 tab.tbl_width = 32; 2073 tab.tbl_ptr = &ind; 2074 tab.tbl_len = 1; 2075 tab.tbl_offset = 0; 2076 for (ind = 0; ind < 128; ind++) { 2077 wlc_lcnphy_write_table(pi, &tab); 2078 tab.tbl_offset++; 2079 } 2080 tab.tbl_offset = 704; 2081 for (ind = 0; ind < 128; ind++) { 2082 wlc_lcnphy_write_table(pi, &tab); 2083 tab.tbl_offset++; 2084 } 2085 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); 2086 2087 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); 2088 2089 mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); 2090 2091 wlc_lcnphy_set_tssi_mux(pi, mode); 2092 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); 2093 2094 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); 2095 2096 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); 2097 2098 mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0); 2099 2100 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); 2101 2102 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); 2103 2104 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); 2105 2106 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); 2107 2108 mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8); 2109 2110 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); 2111 2112 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8); 2113 2114 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6); 2115 2116 mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0); 2117 2118 wlc_lcnphy_clear_tx_power_offsets(pi); 2119 2120 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); 2121 2122 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0); 2123 2124 mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); 2125 2126 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 2127 mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); 2128 mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); 2129 } else { 2130 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1); 2131 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); 2132 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); 2133 } 2134 2135 write_radio_reg(pi, RADIO_2064_REG025, 0xc); 2136 2137 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 2138 mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); 2139 } else { 2140 if (CHSPEC_IS2G(pi->radio_chanspec)) 2141 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); 2142 else 2143 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1); 2144 } 2145 2146 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) 2147 mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); 2148 else 2149 mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2); 2150 2151 mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0); 2152 2153 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3); 2154 2155 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 2156 mod_phy_reg(pi, 0x4d7, 2157 (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12); 2158 2159 rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); 2160 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; 2161 tab.tbl_width = 16; 2162 tab.tbl_ptr = &rfseq; 2163 tab.tbl_len = 1; 2164 tab.tbl_offset = 6; 2165 wlc_lcnphy_write_table(pi, &tab); 2166 2167 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); 2168 2169 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); 2170 2171 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); 2172 2173 mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2); 2174 2175 mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); 2176 2177 mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); 2178 mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); 2179 mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); 2180 2181 wlc_lcnphy_pwrctrl_rssiparams(pi); 2182 } 2183 2184 void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi) 2185 { 2186 u16 tx_cnt, tx_total, npt; 2187 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2188 2189 tx_total = wlc_lcnphy_total_tx_frames(pi); 2190 tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt; 2191 npt = wlc_lcnphy_get_tx_pwr_npt(pi); 2192 2193 if (tx_cnt > (1 << npt)) { 2194 2195 pi_lcn->lcnphy_tssi_tx_cnt = tx_total; 2196 2197 pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi); 2198 pi_lcn->lcnphy_tssi_npt = npt; 2199 2200 } 2201 } 2202 2203 s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1) 2204 { 2205 s32 a, b, p; 2206 2207 a = 32768 + (a1 * tssi); 2208 b = (1024 * b0) + (64 * b1 * tssi); 2209 p = ((2 * b) + a) / (2 * a); 2210 2211 return p; 2212 } 2213 2214 static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi) 2215 { 2216 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2217 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 2218 return; 2219 2220 pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313; 2221 pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT; 2222 } 2223 2224 void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi) 2225 { 2226 struct phytbl_info tab; 2227 u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM + 2228 BRCMS_NUM_RATES_MCS_1_STREAM]; 2229 uint i, j; 2230 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 2231 return; 2232 2233 for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) { 2234 2235 if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM) 2236 j = TXP_FIRST_MCS_20_SISO; 2237 2238 rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j])); 2239 } 2240 2241 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 2242 tab.tbl_width = 32; 2243 tab.tbl_len = ARRAY_SIZE(rate_table); 2244 tab.tbl_ptr = rate_table; 2245 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; 2246 wlc_lcnphy_write_table(pi, &tab); 2247 2248 if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) { 2249 wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min); 2250 2251 wlc_lcnphy_txpower_reset_npt(pi); 2252 } 2253 } 2254 2255 static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index) 2256 { 2257 u32 cck_offset[4] = { 22, 22, 22, 22 }; 2258 u32 ofdm_offset, reg_offset_cck; 2259 int i; 2260 u16 index2; 2261 struct phytbl_info tab; 2262 2263 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) 2264 return; 2265 2266 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); 2267 2268 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14); 2269 2270 or_phy_reg(pi, 0x6da, 0x0040); 2271 2272 reg_offset_cck = 0; 2273 for (i = 0; i < 4; i++) 2274 cck_offset[i] -= reg_offset_cck; 2275 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 2276 tab.tbl_width = 32; 2277 tab.tbl_len = 4; 2278 tab.tbl_ptr = cck_offset; 2279 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; 2280 wlc_lcnphy_write_table(pi, &tab); 2281 ofdm_offset = 0; 2282 tab.tbl_len = 1; 2283 tab.tbl_ptr = &ofdm_offset; 2284 for (i = 836; i < 862; i++) { 2285 tab.tbl_offset = i; 2286 wlc_lcnphy_write_table(pi, &tab); 2287 } 2288 2289 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15); 2290 2291 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); 2292 2293 mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13); 2294 2295 mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7); 2296 2297 mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6); 2298 2299 mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15); 2300 2301 index2 = (u16) (index * 2); 2302 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); 2303 2304 mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4); 2305 2306 } 2307 2308 static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi) 2309 { 2310 s8 index, delta_brd, delta_temp, new_index, tempcorrx; 2311 s16 manp, meas_temp, temp_diff; 2312 bool neg = false; 2313 u16 temp; 2314 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2315 2316 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) 2317 return pi_lcn->lcnphy_current_index; 2318 2319 index = FIXED_TXPWR; 2320 2321 if (pi_lcn->lcnphy_tempsense_slope == 0) 2322 return index; 2323 2324 temp = (u16) wlc_lcnphy_tempsense(pi, 0); 2325 meas_temp = LCNPHY_TEMPSENSE(temp); 2326 2327 if (pi->tx_power_min != 0) 2328 delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min); 2329 else 2330 delta_brd = 0; 2331 2332 manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense); 2333 temp_diff = manp - meas_temp; 2334 if (temp_diff < 0) { 2335 neg = true; 2336 temp_diff = -temp_diff; 2337 } 2338 2339 delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192), 2340 (u32) (pi_lcn-> 2341 lcnphy_tempsense_slope 2342 * 10), 0); 2343 if (neg) 2344 delta_temp = -delta_temp; 2345 2346 if (pi_lcn->lcnphy_tempsense_option == 3 2347 && LCNREV_IS(pi->pubpi.phy_rev, 0)) 2348 delta_temp = 0; 2349 if (pi_lcn->lcnphy_tempcorrx > 31) 2350 tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64); 2351 else 2352 tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx; 2353 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) 2354 tempcorrx = 4; 2355 new_index = 2356 index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr; 2357 new_index += tempcorrx; 2358 2359 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) 2360 index = 127; 2361 2362 if (new_index < 0 || new_index > 126) 2363 return index; 2364 2365 return new_index; 2366 } 2367 2368 static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode) 2369 { 2370 2371 u16 current_mode = mode; 2372 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && 2373 mode == LCNPHY_TX_PWR_CTRL_HW) 2374 current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED; 2375 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && 2376 mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) 2377 current_mode = LCNPHY_TX_PWR_CTRL_HW; 2378 return current_mode; 2379 } 2380 2381 void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode) 2382 { 2383 u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi); 2384 s8 index; 2385 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2386 2387 mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode); 2388 old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode); 2389 2390 mod_phy_reg(pi, 0x6da, (0x1 << 6), 2391 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6); 2392 2393 mod_phy_reg(pi, 0x6a3, (0x1 << 4), 2394 ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4); 2395 2396 if (old_mode != mode) { 2397 if (LCNPHY_TX_PWR_CTRL_HW == old_mode) { 2398 2399 wlc_lcnphy_tx_pwr_update_npt(pi); 2400 2401 wlc_lcnphy_clear_tx_power_offsets(pi); 2402 } 2403 if (LCNPHY_TX_PWR_CTRL_HW == mode) { 2404 2405 wlc_lcnphy_txpower_recalc_target(pi); 2406 2407 wlc_lcnphy_set_start_tx_pwr_idx(pi, 2408 pi_lcn-> 2409 lcnphy_tssi_idx); 2410 wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt); 2411 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0); 2412 2413 pi_lcn->lcnphy_tssi_tx_cnt = 2414 wlc_lcnphy_total_tx_frames(pi); 2415 2416 wlc_lcnphy_disable_tx_gain_override(pi); 2417 pi_lcn->lcnphy_tx_power_idx_override = -1; 2418 } else 2419 wlc_lcnphy_enable_tx_gain_override(pi); 2420 2421 mod_phy_reg(pi, 0x4a4, 2422 ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode); 2423 if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) { 2424 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); 2425 wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index); 2426 pi_lcn->lcnphy_current_index = (s8) 2427 ((read_phy_reg(pi, 2428 0x4a9) & 2429 0xFF) / 2); 2430 } 2431 } 2432 } 2433 2434 static void 2435 wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save) 2436 { 2437 u16 vmid; 2438 int i; 2439 for (i = 0; i < 20; i++) 2440 values_to_save[i] = 2441 read_radio_reg(pi, iqlo_loopback_rf_regs[i]); 2442 2443 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); 2444 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); 2445 2446 mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11); 2447 mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13); 2448 2449 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); 2450 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); 2451 2452 mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); 2453 mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); 2454 2455 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) 2456 and_radio_reg(pi, RADIO_2064_REG03A, 0xFD); 2457 else 2458 and_radio_reg(pi, RADIO_2064_REG03A, 0xF9); 2459 or_radio_reg(pi, RADIO_2064_REG11A, 0x1); 2460 2461 or_radio_reg(pi, RADIO_2064_REG036, 0x01); 2462 or_radio_reg(pi, RADIO_2064_REG11A, 0x18); 2463 udelay(20); 2464 2465 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 2466 if (CHSPEC_IS5G(pi->radio_chanspec)) 2467 mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); 2468 else 2469 or_radio_reg(pi, RADIO_2064_REG03A, 1); 2470 } else { 2471 if (CHSPEC_IS5G(pi->radio_chanspec)) 2472 mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1); 2473 else 2474 or_radio_reg(pi, RADIO_2064_REG03A, 0x3); 2475 } 2476 2477 udelay(20); 2478 2479 write_radio_reg(pi, RADIO_2064_REG025, 0xF); 2480 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 2481 if (CHSPEC_IS5G(pi->radio_chanspec)) 2482 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4); 2483 else 2484 mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6); 2485 } else { 2486 if (CHSPEC_IS5G(pi->radio_chanspec)) 2487 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1); 2488 else 2489 mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1); 2490 } 2491 2492 udelay(20); 2493 2494 write_radio_reg(pi, RADIO_2064_REG005, 0x8); 2495 or_radio_reg(pi, RADIO_2064_REG112, 0x80); 2496 udelay(20); 2497 2498 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); 2499 or_radio_reg(pi, RADIO_2064_REG11F, 0x44); 2500 udelay(20); 2501 2502 or_radio_reg(pi, RADIO_2064_REG00B, 0x7); 2503 or_radio_reg(pi, RADIO_2064_REG113, 0x10); 2504 udelay(20); 2505 2506 write_radio_reg(pi, RADIO_2064_REG007, 0x1); 2507 udelay(20); 2508 2509 vmid = 0x2A6; 2510 mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3); 2511 write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff)); 2512 or_radio_reg(pi, RADIO_2064_REG11F, 0x44); 2513 udelay(20); 2514 2515 or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); 2516 udelay(20); 2517 write_radio_reg(pi, RADIO_2064_REG012, 0x02); 2518 or_radio_reg(pi, RADIO_2064_REG112, 0x06); 2519 write_radio_reg(pi, RADIO_2064_REG036, 0x11); 2520 write_radio_reg(pi, RADIO_2064_REG059, 0xcc); 2521 write_radio_reg(pi, RADIO_2064_REG05C, 0x2e); 2522 write_radio_reg(pi, RADIO_2064_REG078, 0xd7); 2523 write_radio_reg(pi, RADIO_2064_REG092, 0x15); 2524 } 2525 2526 static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi) 2527 { 2528 uint delay_count = 0; 2529 2530 while (wlc_lcnphy_iqcal_active(pi)) { 2531 udelay(100); 2532 delay_count++; 2533 2534 if (delay_count > (10 * 500)) 2535 break; 2536 } 2537 2538 return (0 == wlc_lcnphy_iqcal_active(pi)); 2539 } 2540 2541 static void 2542 wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save) 2543 { 2544 int i; 2545 2546 and_phy_reg(pi, 0x44c, 0x0 >> 11); 2547 2548 and_phy_reg(pi, 0x43b, 0xC); 2549 2550 for (i = 0; i < 20; i++) 2551 write_radio_reg(pi, iqlo_loopback_rf_regs[i], 2552 values_to_save[i]); 2553 } 2554 2555 static void 2556 wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi, 2557 struct lcnphy_txgains *target_gains, 2558 enum lcnphy_cal_mode cal_mode, bool keep_tone) 2559 { 2560 2561 struct lcnphy_txgains cal_gains, temp_gains; 2562 u16 hash; 2563 int j; 2564 u16 ncorr_override[5]; 2565 u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 2566 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; 2567 2568 u16 commands_fullcal[] = { 2569 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 2570 }; 2571 2572 u16 commands_recal[] = { 2573 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 2574 }; 2575 2576 u16 command_nums_fullcal[] = { 2577 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 2578 }; 2579 2580 u16 command_nums_recal[] = { 2581 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 2582 }; 2583 u16 *command_nums = command_nums_fullcal; 2584 2585 u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start; 2586 u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2; 2587 u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl; 2588 bool tx_gain_override_old; 2589 struct lcnphy_txgains old_gains; 2590 uint i, n_cal_cmds = 0, n_cal_start = 0; 2591 u16 *values_to_save; 2592 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2593 2594 if (WARN_ON(CHSPEC_IS5G(pi->radio_chanspec))) 2595 return; 2596 2597 values_to_save = kmalloc_array(20, sizeof(u16), GFP_ATOMIC); 2598 if (NULL == values_to_save) 2599 return; 2600 2601 save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); 2602 save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); 2603 2604 or_phy_reg(pi, 0x6da, 0x40); 2605 or_phy_reg(pi, 0x6db, 0x3); 2606 2607 switch (cal_mode) { 2608 case LCNPHY_CAL_FULL: 2609 start_coeffs = syst_coeffs; 2610 cal_cmds = commands_fullcal; 2611 n_cal_cmds = ARRAY_SIZE(commands_fullcal); 2612 break; 2613 2614 case LCNPHY_CAL_RECAL: 2615 start_coeffs = syst_coeffs; 2616 cal_cmds = commands_recal; 2617 n_cal_cmds = ARRAY_SIZE(commands_recal); 2618 command_nums = command_nums_recal; 2619 break; 2620 2621 default: 2622 break; 2623 } 2624 2625 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2626 start_coeffs, 11, 16, 64); 2627 2628 write_phy_reg(pi, 0x6da, 0xffff); 2629 mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3); 2630 2631 tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi); 2632 2633 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); 2634 2635 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 2636 2637 save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db); 2638 2639 mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0); 2640 2641 mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12); 2642 2643 wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save); 2644 2645 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); 2646 if (tx_gain_override_old) 2647 wlc_lcnphy_get_tx_gain(pi, &old_gains); 2648 2649 if (!target_gains) { 2650 if (!tx_gain_override_old) 2651 wlc_lcnphy_set_tx_pwr_by_index(pi, 2652 pi_lcn->lcnphy_tssi_idx); 2653 wlc_lcnphy_get_tx_gain(pi, &temp_gains); 2654 target_gains = &temp_gains; 2655 } 2656 2657 hash = (target_gains->gm_gain << 8) | 2658 (target_gains->pga_gain << 4) | (target_gains->pad_gain); 2659 2660 cal_gains = *target_gains; 2661 memset(ncorr_override, 0, sizeof(ncorr_override)); 2662 for (j = 0; j < iqcal_gainparams_numgains_lcnphy[0]; j++) { 2663 if (hash == tbl_iqcal_gainparams_lcnphy[0][j][0]) { 2664 cal_gains.gm_gain = 2665 tbl_iqcal_gainparams_lcnphy[0][j][1]; 2666 cal_gains.pga_gain = 2667 tbl_iqcal_gainparams_lcnphy[0][j][2]; 2668 cal_gains.pad_gain = 2669 tbl_iqcal_gainparams_lcnphy[0][j][3]; 2670 memcpy(ncorr_override, 2671 &tbl_iqcal_gainparams_lcnphy[0][j][3], 2672 sizeof(ncorr_override)); 2673 break; 2674 } 2675 } 2676 2677 wlc_lcnphy_set_tx_gain(pi, &cal_gains); 2678 2679 write_phy_reg(pi, 0x453, 0xaa9); 2680 write_phy_reg(pi, 0x93d, 0xc0); 2681 2682 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2683 lcnphy_iqcal_loft_gainladder, 2684 ARRAY_SIZE(lcnphy_iqcal_loft_gainladder), 2685 16, 0); 2686 2687 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2688 lcnphy_iqcal_ir_gainladder, 2689 ARRAY_SIZE( 2690 lcnphy_iqcal_ir_gainladder), 16, 2691 32); 2692 2693 if (pi->phy_tx_tone_freq) { 2694 2695 wlc_lcnphy_stop_tx_tone(pi); 2696 udelay(5); 2697 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); 2698 } else { 2699 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); 2700 } 2701 2702 write_phy_reg(pi, 0x6da, 0xffff); 2703 2704 for (i = n_cal_start; i < n_cal_cmds; i++) { 2705 u16 zero_diq = 0; 2706 u16 best_coeffs[11]; 2707 u16 command_num; 2708 2709 cal_type = (cal_cmds[i] & 0x0f00) >> 8; 2710 2711 command_num = command_nums[i]; 2712 if (ncorr_override[cal_type]) 2713 command_num = 2714 ncorr_override[cal_type] << 8 | (command_num & 2715 0xff); 2716 2717 write_phy_reg(pi, 0x452, command_num); 2718 2719 if ((cal_type == 3) || (cal_type == 4)) { 2720 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2721 &diq_start, 1, 16, 69); 2722 2723 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2724 &zero_diq, 1, 16, 69); 2725 } 2726 2727 write_phy_reg(pi, 0x451, cal_cmds[i]); 2728 2729 if (!wlc_lcnphy_iqcal_wait(pi)) 2730 goto cleanup; 2731 2732 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2733 best_coeffs, 2734 ARRAY_SIZE(best_coeffs), 16, 96); 2735 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2736 best_coeffs, 2737 ARRAY_SIZE(best_coeffs), 16, 64); 2738 2739 if ((cal_type == 3) || (cal_type == 4)) 2740 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2741 &diq_start, 1, 16, 69); 2742 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2743 pi_lcn->lcnphy_cal_results. 2744 txiqlocal_bestcoeffs, 2745 ARRAY_SIZE(pi_lcn-> 2746 lcnphy_cal_results. 2747 txiqlocal_bestcoeffs), 2748 16, 96); 2749 } 2750 2751 wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2752 pi_lcn->lcnphy_cal_results. 2753 txiqlocal_bestcoeffs, 2754 ARRAY_SIZE(pi_lcn->lcnphy_cal_results. 2755 txiqlocal_bestcoeffs), 16, 96); 2756 pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true; 2757 2758 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2759 &pi_lcn->lcnphy_cal_results. 2760 txiqlocal_bestcoeffs[0], 4, 16, 80); 2761 2762 wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, 2763 &pi_lcn->lcnphy_cal_results. 2764 txiqlocal_bestcoeffs[5], 2, 16, 85); 2765 2766 cleanup: 2767 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save); 2768 kfree(values_to_save); 2769 2770 if (!keep_tone) 2771 wlc_lcnphy_stop_tx_tone(pi); 2772 2773 write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2); 2774 2775 write_phy_reg(pi, 0x453, 0); 2776 2777 if (tx_gain_override_old) 2778 wlc_lcnphy_set_tx_gain(pi, &old_gains); 2779 wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old); 2780 2781 write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl); 2782 write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl); 2783 2784 } 2785 2786 static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) 2787 { 2788 bool suspend, tx_gain_override_old; 2789 struct lcnphy_txgains old_gains; 2790 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); 2791 u16 idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB, 2792 idleTssi0_regvalue_2C; 2793 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 2794 u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112); 2795 u16 SAVE_jtag_bb_afe_switch = 2796 read_radio_reg(pi, RADIO_2064_REG007) & 1; 2797 u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; 2798 u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; 2799 u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); 2800 2801 read_phy_reg(pi, 0x4ab); /* idleTssi */ 2802 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 2803 MCTL_EN_MAC)); 2804 if (!suspend) 2805 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2806 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 2807 2808 tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); 2809 wlc_lcnphy_get_tx_gain(pi, &old_gains); 2810 2811 wlc_lcnphy_enable_tx_gain_override(pi); 2812 wlc_lcnphy_set_tx_pwr_by_index(pi, 127); 2813 write_radio_reg(pi, RADIO_2064_REG112, 0x6); 2814 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1); 2815 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); 2816 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); 2817 wlc_lcnphy_tssi_setup(pi); 2818 2819 mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); 2820 mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); 2821 2822 wlc_lcnphy_set_bbmult(pi, 0x0); 2823 2824 wlc_phy_do_dummy_tx(pi, true, OFF); 2825 read_phy_reg(pi, 0x4ab); /* idleTssi */ 2826 2827 idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0)) 2828 >> 0); 2829 2830 if (idleTssi0_2C >= 256) 2831 idleTssi0_OB = idleTssi0_2C - 256; 2832 else 2833 idleTssi0_OB = idleTssi0_2C + 256; 2834 2835 idleTssi0_regvalue_OB = idleTssi0_OB; 2836 if (idleTssi0_regvalue_OB >= 256) 2837 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256; 2838 else 2839 idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256; 2840 mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0); 2841 2842 mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); 2843 2844 wlc_lcnphy_set_bbmult(pi, SAVE_bbmult); 2845 wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); 2846 wlc_lcnphy_set_tx_gain(pi, &old_gains); 2847 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); 2848 2849 write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain); 2850 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch); 2851 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga); 2852 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en); 2853 mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7); 2854 if (!suspend) 2855 wlapi_enable_mac(pi->sh->physhim); 2856 } 2857 2858 static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode) 2859 { 2860 bool suspend; 2861 u16 save_txpwrCtrlEn; 2862 u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain; 2863 u16 auxpga_vmid; 2864 struct phytbl_info tab; 2865 u32 val; 2866 u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025, 2867 save_reg112; 2868 u16 values_to_save[14]; 2869 s8 index; 2870 int i; 2871 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 2872 udelay(999); 2873 2874 save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007); 2875 save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF); 2876 save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F); 2877 save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005); 2878 save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025); 2879 save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112); 2880 2881 for (i = 0; i < 14; i++) 2882 values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]); 2883 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 2884 MCTL_EN_MAC)); 2885 if (!suspend) 2886 wlapi_suspend_mac_and_wait(pi->sh->physhim); 2887 save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4); 2888 2889 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 2890 index = pi_lcn->lcnphy_current_index; 2891 wlc_lcnphy_set_tx_pwr_by_index(pi, 127); 2892 mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1); 2893 mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4); 2894 mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2); 2895 mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); 2896 2897 mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); 2898 2899 mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); 2900 2901 mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15); 2902 2903 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); 2904 2905 mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); 2906 2907 mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); 2908 2909 mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); 2910 2911 mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); 2912 2913 mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8); 2914 2915 mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); 2916 2917 mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8); 2918 2919 mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4); 2920 2921 mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8); 2922 2923 mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12); 2924 2925 mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12); 2926 2927 mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13); 2928 2929 mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); 2930 2931 write_radio_reg(pi, RADIO_2064_REG025, 0xC); 2932 2933 mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3); 2934 2935 mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); 2936 2937 mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); 2938 2939 mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); 2940 2941 val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); 2942 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; 2943 tab.tbl_width = 16; 2944 tab.tbl_len = 1; 2945 tab.tbl_ptr = &val; 2946 tab.tbl_offset = 6; 2947 wlc_lcnphy_write_table(pi, &tab); 2948 if (mode == TEMPSENSE) { 2949 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); 2950 2951 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12); 2952 2953 auxpga_vmidcourse = 8; 2954 auxpga_vmidfine = 0x4; 2955 auxpga_gain = 2; 2956 mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5); 2957 } else { 2958 mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); 2959 2960 mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12); 2961 2962 auxpga_vmidcourse = 7; 2963 auxpga_vmidfine = 0xa; 2964 auxpga_gain = 2; 2965 } 2966 auxpga_vmid = 2967 (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine); 2968 mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0); 2969 2970 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2); 2971 2972 mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1); 2973 2974 mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12); 2975 2976 mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5); 2977 2978 write_radio_reg(pi, RADIO_2064_REG112, 0x6); 2979 2980 wlc_phy_do_dummy_tx(pi, true, OFF); 2981 if (!tempsense_done(pi)) 2982 udelay(10); 2983 2984 write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007); 2985 write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF); 2986 write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F); 2987 write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005); 2988 write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025); 2989 write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112); 2990 for (i = 0; i < 14; i++) 2991 write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]); 2992 wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index); 2993 2994 write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn); 2995 if (!suspend) 2996 wlapi_enable_mac(pi->sh->physhim); 2997 udelay(999); 2998 } 2999 3000 static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) 3001 { 3002 struct lcnphy_txgains tx_gains; 3003 u8 bbmult; 3004 struct phytbl_info tab; 3005 s32 a1, b0, b1; 3006 s32 tssi, pwr, mintargetpwr; 3007 bool suspend; 3008 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); 3009 3010 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 3011 MCTL_EN_MAC)); 3012 if (!suspend) 3013 wlapi_suspend_mac_and_wait(pi->sh->physhim); 3014 3015 if (!pi->hwpwrctrl_capable) { 3016 if (CHSPEC_IS2G(pi->radio_chanspec)) { 3017 tx_gains.gm_gain = 4; 3018 tx_gains.pga_gain = 12; 3019 tx_gains.pad_gain = 12; 3020 tx_gains.dac_gain = 0; 3021 3022 bbmult = 150; 3023 } else { 3024 tx_gains.gm_gain = 7; 3025 tx_gains.pga_gain = 15; 3026 tx_gains.pad_gain = 14; 3027 tx_gains.dac_gain = 0; 3028 3029 bbmult = 150; 3030 } 3031 wlc_lcnphy_set_tx_gain(pi, &tx_gains); 3032 wlc_lcnphy_set_bbmult(pi, bbmult); 3033 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); 3034 } else { 3035 3036 wlc_lcnphy_idle_tssi_est(ppi); 3037 3038 wlc_lcnphy_clear_tx_power_offsets(pi); 3039 3040 b0 = pi->txpa_2g[0]; 3041 b1 = pi->txpa_2g[1]; 3042 a1 = pi->txpa_2g[2]; 3043 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); 3044 3045 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 3046 tab.tbl_width = 32; 3047 tab.tbl_ptr = &pwr; 3048 tab.tbl_len = 1; 3049 tab.tbl_offset = 0; 3050 for (tssi = 0; tssi < 128; tssi++) { 3051 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); 3052 3053 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; 3054 wlc_lcnphy_write_table(pi, &tab); 3055 tab.tbl_offset++; 3056 } 3057 mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); 3058 mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); 3059 mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); 3060 mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); 3061 mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2); 3062 3063 mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); 3064 3065 write_phy_reg(pi, 0x4a8, 10); 3066 3067 wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR); 3068 3069 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); 3070 } 3071 if (!suspend) 3072 wlapi_enable_mac(pi->sh->physhim); 3073 } 3074 3075 static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain) 3076 { 3077 mod_phy_reg(pi, 0x4fb, 3078 LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK, 3079 gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT); 3080 mod_phy_reg(pi, 0x4fd, 3081 LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK, 3082 gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT); 3083 } 3084 3085 void 3086 wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, 3087 u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0) 3088 { 3089 *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089)); 3090 *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A)); 3091 *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B)); 3092 *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C)); 3093 } 3094 3095 void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b) 3096 { 3097 struct phytbl_info tab; 3098 u16 iqcc[2]; 3099 3100 iqcc[0] = a; 3101 iqcc[1] = b; 3102 3103 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; 3104 tab.tbl_width = 16; 3105 tab.tbl_ptr = iqcc; 3106 tab.tbl_len = 2; 3107 tab.tbl_offset = 80; 3108 wlc_lcnphy_write_table(pi, &tab); 3109 } 3110 3111 void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq) 3112 { 3113 struct phytbl_info tab; 3114 3115 tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; 3116 tab.tbl_width = 16; 3117 tab.tbl_ptr = &didq; 3118 tab.tbl_len = 1; 3119 tab.tbl_offset = 85; 3120 wlc_lcnphy_write_table(pi, &tab); 3121 } 3122 3123 void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index) 3124 { 3125 struct phytbl_info tab; 3126 u16 a, b; 3127 u8 bb_mult; 3128 u32 bbmultiqcomp, txgain, locoeffs, rfpower; 3129 struct lcnphy_txgains gains; 3130 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3131 3132 pi_lcn->lcnphy_tx_power_idx_override = (s8) index; 3133 pi_lcn->lcnphy_current_index = (u8) index; 3134 3135 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 3136 tab.tbl_width = 32; 3137 tab.tbl_len = 1; 3138 3139 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 3140 3141 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; 3142 tab.tbl_ptr = &bbmultiqcomp; 3143 wlc_lcnphy_read_table(pi, &tab); 3144 3145 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; 3146 tab.tbl_width = 32; 3147 tab.tbl_ptr = &txgain; 3148 wlc_lcnphy_read_table(pi, &tab); 3149 3150 gains.gm_gain = (u16) (txgain & 0xff); 3151 gains.pga_gain = (u16) (txgain >> 8) & 0xff; 3152 gains.pad_gain = (u16) (txgain >> 16) & 0xff; 3153 gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07; 3154 wlc_lcnphy_set_tx_gain(pi, &gains); 3155 wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f); 3156 3157 bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff); 3158 wlc_lcnphy_set_bbmult(pi, bb_mult); 3159 3160 wlc_lcnphy_enable_tx_gain_override(pi); 3161 3162 if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { 3163 3164 a = (u16) ((bbmultiqcomp >> 10) & 0x3ff); 3165 b = (u16) (bbmultiqcomp & 0x3ff); 3166 wlc_lcnphy_set_tx_iqcc(pi, a, b); 3167 3168 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index; 3169 tab.tbl_ptr = &locoeffs; 3170 wlc_lcnphy_read_table(pi, &tab); 3171 3172 wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs); 3173 3174 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; 3175 tab.tbl_ptr = &rfpower; 3176 wlc_lcnphy_read_table(pi, &tab); 3177 mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0); 3178 3179 } 3180 } 3181 3182 static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi) 3183 { 3184 u32 j; 3185 struct phytbl_info tab; 3186 u32 temp_offset[128]; 3187 tab.tbl_ptr = temp_offset; 3188 tab.tbl_len = 128; 3189 tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL; 3190 tab.tbl_width = 32; 3191 tab.tbl_offset = 0; 3192 3193 memset(temp_offset, 0, sizeof(temp_offset)); 3194 for (j = 1; j < 128; j += 2) 3195 temp_offset[j] = 0x80000; 3196 3197 wlc_lcnphy_write_table(pi, &tab); 3198 return; 3199 } 3200 3201 void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable) 3202 { 3203 if (!bEnable) { 3204 3205 and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4))); 3206 3207 mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1); 3208 3209 and_phy_reg(pi, 0x44c, 3210 ~(u16) ((0x1 << 3) | 3211 (0x1 << 5) | 3212 (0x1 << 12) | 3213 (0x1 << 0) | (0x1 << 1) | (0x1 << 2))); 3214 3215 and_phy_reg(pi, 0x44d, 3216 ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14))); 3217 mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2); 3218 3219 mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0)); 3220 3221 and_phy_reg(pi, 0x4f9, 3222 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); 3223 3224 and_phy_reg(pi, 0x4fa, 3225 ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); 3226 } else { 3227 3228 mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); 3229 mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); 3230 3231 mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4); 3232 mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6); 3233 3234 mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); 3235 mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); 3236 3237 wlc_lcnphy_set_trsw_override(pi, true, false); 3238 3239 mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2); 3240 mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2); 3241 3242 if (CHSPEC_IS2G(pi->radio_chanspec)) { 3243 3244 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); 3245 mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3); 3246 3247 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); 3248 mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5); 3249 3250 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); 3251 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1); 3252 3253 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); 3254 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2); 3255 3256 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); 3257 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0); 3258 } else { 3259 3260 mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); 3261 mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3); 3262 3263 mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); 3264 mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5); 3265 3266 mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); 3267 mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1); 3268 3269 mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); 3270 mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2); 3271 3272 mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); 3273 mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); 3274 } 3275 } 3276 } 3277 3278 static void 3279 wlc_lcnphy_run_samples(struct brcms_phy *pi, 3280 u16 num_samps, 3281 u16 num_loops, u16 wait, bool iqcalmode) 3282 { 3283 3284 or_phy_reg(pi, 0x6da, 0x8080); 3285 3286 mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0); 3287 if (num_loops != 0xffff) 3288 num_loops--; 3289 mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0); 3290 3291 mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0); 3292 3293 if (iqcalmode) { 3294 3295 and_phy_reg(pi, 0x453, 0xffff & ~(0x1 << 15)); 3296 or_phy_reg(pi, 0x453, (0x1 << 15)); 3297 } else { 3298 write_phy_reg(pi, 0x63f, 1); 3299 wlc_lcnphy_tx_pu(pi, 1); 3300 } 3301 3302 or_radio_reg(pi, RADIO_2064_REG112, 0x6); 3303 } 3304 3305 void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode) 3306 { 3307 3308 u8 phybw40; 3309 phybw40 = CHSPEC_IS40(pi->radio_chanspec); 3310 3311 mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); 3312 mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); 3313 3314 if (phybw40 == 0) { 3315 mod_phy_reg((pi), 0x410, 3316 (0x1 << 6) | 3317 (0x1 << 5), 3318 ((CHSPEC_IS2G( 3319 pi->radio_chanspec)) ? (!mode) : 0) << 3320 6 | (!mode) << 5); 3321 mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7); 3322 } 3323 } 3324 3325 void 3326 wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val, 3327 bool iqcalmode) 3328 { 3329 u8 phy_bw; 3330 u16 num_samps, t, k; 3331 u32 bw; 3332 s32 theta = 0, rot = 0; 3333 struct cordic_iq tone_samp; 3334 u32 data_buf[64]; 3335 u16 i_samp, q_samp; 3336 struct phytbl_info tab; 3337 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3338 3339 pi->phy_tx_tone_freq = f_kHz; 3340 3341 wlc_lcnphy_deaf_mode(pi, true); 3342 3343 phy_bw = 40; 3344 if (pi_lcn->lcnphy_spurmod) { 3345 write_phy_reg(pi, 0x942, 0x2); 3346 write_phy_reg(pi, 0x93b, 0x0); 3347 write_phy_reg(pi, 0x93c, 0x0); 3348 wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); 3349 } 3350 3351 if (f_kHz) { 3352 k = 1; 3353 do { 3354 bw = phy_bw * 1000 * k; 3355 num_samps = bw / abs(f_kHz); 3356 k++; 3357 } while ((num_samps * (u32) (abs(f_kHz))) != bw); 3358 } else 3359 num_samps = 2; 3360 3361 rot = ((f_kHz * 36) / phy_bw) / 100; 3362 theta = 0; 3363 3364 for (t = 0; t < num_samps; t++) { 3365 3366 tone_samp = cordic_calc_iq(theta); 3367 3368 theta += rot; 3369 3370 i_samp = (u16)(CORDIC_FLOAT(tone_samp.i * max_val) & 0x3ff); 3371 q_samp = (u16)(CORDIC_FLOAT(tone_samp.q * max_val) & 0x3ff); 3372 data_buf[t] = (i_samp << 10) | q_samp; 3373 } 3374 3375 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0); 3376 3377 mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3); 3378 3379 tab.tbl_ptr = data_buf; 3380 tab.tbl_len = num_samps; 3381 tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY; 3382 tab.tbl_offset = 0; 3383 tab.tbl_width = 32; 3384 wlc_lcnphy_write_table(pi, &tab); 3385 3386 wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode); 3387 } 3388 3389 void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi) 3390 { 3391 s16 playback_status; 3392 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3393 3394 pi->phy_tx_tone_freq = 0; 3395 if (pi_lcn->lcnphy_spurmod) { 3396 write_phy_reg(pi, 0x942, 0x7); 3397 write_phy_reg(pi, 0x93b, 0x2017); 3398 write_phy_reg(pi, 0x93c, 0x27c5); 3399 wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); 3400 } 3401 3402 playback_status = read_phy_reg(pi, 0x644); 3403 if (playback_status & (0x1 << 0)) { 3404 wlc_lcnphy_tx_pu(pi, 0); 3405 mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1); 3406 } else if (playback_status & (0x1 << 1)) 3407 mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15); 3408 3409 mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0); 3410 3411 mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3); 3412 3413 mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7); 3414 3415 and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9); 3416 3417 wlc_lcnphy_deaf_mode(pi, false); 3418 } 3419 3420 static void 3421 wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y) 3422 { 3423 u16 di0dq0; 3424 u16 x, y, data_rf; 3425 int k; 3426 switch (cal_type) { 3427 case 0: 3428 wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y); 3429 break; 3430 case 2: 3431 di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff); 3432 wlc_lcnphy_set_tx_locc(pi, di0dq0); 3433 break; 3434 case 3: 3435 k = wlc_lcnphy_calc_floor(coeff_x, 0); 3436 y = 8 + k; 3437 k = wlc_lcnphy_calc_floor(coeff_x, 1); 3438 x = 8 - k; 3439 data_rf = (x * 16 + y); 3440 write_radio_reg(pi, RADIO_2064_REG089, data_rf); 3441 k = wlc_lcnphy_calc_floor(coeff_y, 0); 3442 y = 8 + k; 3443 k = wlc_lcnphy_calc_floor(coeff_y, 1); 3444 x = 8 - k; 3445 data_rf = (x * 16 + y); 3446 write_radio_reg(pi, RADIO_2064_REG08A, data_rf); 3447 break; 3448 case 4: 3449 k = wlc_lcnphy_calc_floor(coeff_x, 0); 3450 y = 8 + k; 3451 k = wlc_lcnphy_calc_floor(coeff_x, 1); 3452 x = 8 - k; 3453 data_rf = (x * 16 + y); 3454 write_radio_reg(pi, RADIO_2064_REG08B, data_rf); 3455 k = wlc_lcnphy_calc_floor(coeff_y, 0); 3456 y = 8 + k; 3457 k = wlc_lcnphy_calc_floor(coeff_y, 1); 3458 x = 8 - k; 3459 data_rf = (x * 16 + y); 3460 write_radio_reg(pi, RADIO_2064_REG08C, data_rf); 3461 break; 3462 } 3463 } 3464 3465 static struct lcnphy_unsign16_struct 3466 wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type) 3467 { 3468 u16 a, b, didq; 3469 u8 di0, dq0, ei, eq, fi, fq; 3470 struct lcnphy_unsign16_struct cc; 3471 cc.re = 0; 3472 cc.im = 0; 3473 switch (cal_type) { 3474 case 0: 3475 wlc_lcnphy_get_tx_iqcc(pi, &a, &b); 3476 cc.re = a; 3477 cc.im = b; 3478 break; 3479 case 2: 3480 didq = wlc_lcnphy_get_tx_locc(pi); 3481 di0 = (((didq & 0xff00) << 16) >> 24); 3482 dq0 = (((didq & 0x00ff) << 24) >> 24); 3483 cc.re = (u16) di0; 3484 cc.im = (u16) dq0; 3485 break; 3486 case 3: 3487 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); 3488 cc.re = (u16) ei; 3489 cc.im = (u16) eq; 3490 break; 3491 case 4: 3492 wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); 3493 cc.re = (u16) fi; 3494 cc.im = (u16) fq; 3495 break; 3496 } 3497 return cc; 3498 } 3499 3500 static void 3501 wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, 3502 s16 *ptr, int mode) 3503 { 3504 u32 curval1, curval2, stpptr, curptr, strptr, val; 3505 u16 sslpnCalibClkEnCtrl, timer; 3506 u16 old_sslpnCalibClkEnCtrl; 3507 s16 imag, real; 3508 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3509 3510 timer = 0; 3511 old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); 3512 3513 curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts)); 3514 ptr[130] = 0; 3515 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), 3516 ((1 << 6) | curval1)); 3517 3518 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00); 3519 bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000); 3520 udelay(20); 3521 curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param)); 3522 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 3523 curval2 | 0x30); 3524 3525 write_phy_reg(pi, 0x555, 0x0); 3526 write_phy_reg(pi, 0x5a6, 0x5); 3527 3528 write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6)); 3529 write_phy_reg(pi, 0x5cf, 3); 3530 write_phy_reg(pi, 0x5a5, 0x3); 3531 write_phy_reg(pi, 0x583, 0x0); 3532 write_phy_reg(pi, 0x584, 0x0); 3533 write_phy_reg(pi, 0x585, 0x0fff); 3534 write_phy_reg(pi, 0x586, 0x0000); 3535 3536 write_phy_reg(pi, 0x580, 0x4501); 3537 3538 sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); 3539 write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008)); 3540 stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr)); 3541 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr)); 3542 do { 3543 udelay(10); 3544 curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr)); 3545 timer++; 3546 } while ((curptr != stpptr) && (timer < 500)); 3547 3548 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2); 3549 strptr = 0x7E00; 3550 bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr); 3551 while (strptr < 0x8000) { 3552 val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata)); 3553 imag = ((val >> 16) & 0x3ff); 3554 real = ((val) & 0x3ff); 3555 if (imag > 511) 3556 imag -= 1024; 3557 3558 if (real > 511) 3559 real -= 1024; 3560 3561 if (pi_lcn->lcnphy_iqcal_swp_dis) 3562 ptr[(strptr - 0x7E00) / 4] = real; 3563 else 3564 ptr[(strptr - 0x7E00) / 4] = imag; 3565 3566 if (clip_detect_algo) { 3567 if (imag > thresh || imag < -thresh) { 3568 strptr = 0x8000; 3569 ptr[130] = 1; 3570 } 3571 } 3572 3573 strptr += 4; 3574 } 3575 3576 write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); 3577 bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2); 3578 bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1); 3579 } 3580 3581 static void 3582 wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, 3583 int step_size_lg2) 3584 { 3585 const struct lcnphy_spb_tone *phy_c1; 3586 struct lcnphy_spb_tone phy_c2; 3587 struct lcnphy_unsign16_struct phy_c3; 3588 int phy_c4, phy_c5, k, l, j, phy_c6; 3589 u16 phy_c7, phy_c8, phy_c9; 3590 s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16; 3591 s16 *ptr, phy_c17; 3592 s32 phy_c18, phy_c19; 3593 u32 phy_c20, phy_c21; 3594 bool phy_c22, phy_c23, phy_c24, phy_c25; 3595 u16 phy_c26, phy_c27; 3596 u16 phy_c28, phy_c29, phy_c30; 3597 u16 phy_c31; 3598 u16 *phy_c32; 3599 phy_c21 = 0; 3600 phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0; 3601 ptr = kmalloc_objs(s16, 131, GFP_ATOMIC); 3602 if (NULL == ptr) 3603 return; 3604 3605 phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC); 3606 if (NULL == phy_c32) { 3607 kfree(ptr); 3608 return; 3609 } 3610 phy_c26 = read_phy_reg(pi, 0x6da); 3611 phy_c27 = read_phy_reg(pi, 0x6db); 3612 phy_c31 = read_radio_reg(pi, RADIO_2064_REG026); 3613 write_phy_reg(pi, 0x93d, 0xC0); 3614 3615 wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0); 3616 write_phy_reg(pi, 0x6da, 0xffff); 3617 or_phy_reg(pi, 0x6db, 0x3); 3618 3619 wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32); 3620 udelay(500); 3621 phy_c28 = read_phy_reg(pi, 0x938); 3622 phy_c29 = read_phy_reg(pi, 0x4d7); 3623 phy_c30 = read_phy_reg(pi, 0x4d8); 3624 or_phy_reg(pi, 0x938, 0x1 << 2); 3625 or_phy_reg(pi, 0x4d7, 0x1 << 2); 3626 or_phy_reg(pi, 0x4d7, 0x1 << 3); 3627 mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12); 3628 or_phy_reg(pi, 0x4d8, 1 << 0); 3629 or_phy_reg(pi, 0x4d8, 1 << 1); 3630 mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2); 3631 mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12); 3632 phy_c1 = &lcnphy_spb_tone_3750[0]; 3633 phy_c4 = 32; 3634 3635 if (num_levels == 0) { 3636 if (cal_type != 0) 3637 num_levels = 4; 3638 else 3639 num_levels = 9; 3640 } 3641 if (step_size_lg2 == 0) { 3642 if (cal_type != 0) 3643 step_size_lg2 = 3; 3644 else 3645 step_size_lg2 = 8; 3646 } 3647 3648 phy_c7 = (1 << step_size_lg2); 3649 phy_c3 = wlc_lcnphy_get_cc(pi, cal_type); 3650 phy_c15 = (s16) phy_c3.re; 3651 phy_c16 = (s16) phy_c3.im; 3652 if (cal_type == 2) { 3653 if (phy_c3.re > 127) 3654 phy_c15 = phy_c3.re - 256; 3655 if (phy_c3.im > 127) 3656 phy_c16 = phy_c3.im - 256; 3657 } 3658 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); 3659 udelay(20); 3660 for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) { 3661 phy_c23 = true; 3662 phy_c22 = false; 3663 switch (cal_type) { 3664 case 0: 3665 phy_c10 = 511; 3666 break; 3667 case 2: 3668 phy_c10 = 127; 3669 break; 3670 case 3: 3671 phy_c10 = 15; 3672 break; 3673 case 4: 3674 phy_c10 = 15; 3675 break; 3676 } 3677 3678 phy_c9 = read_phy_reg(pi, 0x93d); 3679 phy_c9 = 2 * phy_c9; 3680 phy_c24 = false; 3681 phy_c5 = 7; 3682 phy_c25 = true; 3683 while (1) { 3684 write_radio_reg(pi, RADIO_2064_REG026, 3685 (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4)); 3686 udelay(50); 3687 phy_c22 = false; 3688 ptr[130] = 0; 3689 wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2); 3690 if (ptr[130] == 1) 3691 phy_c22 = true; 3692 if (phy_c22) 3693 phy_c5 -= 1; 3694 if ((phy_c22 != phy_c24) && (!phy_c25)) 3695 break; 3696 if (!phy_c22) 3697 phy_c5 += 1; 3698 if (phy_c5 <= 0 || phy_c5 >= 7) 3699 break; 3700 phy_c24 = phy_c22; 3701 phy_c25 = false; 3702 } 3703 3704 if (phy_c5 < 0) 3705 phy_c5 = 0; 3706 else if (phy_c5 > 7) 3707 phy_c5 = 7; 3708 3709 for (k = -phy_c7; k <= phy_c7; k += phy_c7) { 3710 for (l = -phy_c7; l <= phy_c7; l += phy_c7) { 3711 phy_c11 = phy_c15 + k; 3712 phy_c12 = phy_c16 + l; 3713 3714 if (phy_c11 < -phy_c10) 3715 phy_c11 = -phy_c10; 3716 else if (phy_c11 > phy_c10) 3717 phy_c11 = phy_c10; 3718 if (phy_c12 < -phy_c10) 3719 phy_c12 = -phy_c10; 3720 else if (phy_c12 > phy_c10) 3721 phy_c12 = phy_c10; 3722 wlc_lcnphy_set_cc(pi, cal_type, phy_c11, 3723 phy_c12); 3724 udelay(20); 3725 wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2); 3726 3727 phy_c18 = 0; 3728 phy_c19 = 0; 3729 for (j = 0; j < 128; j++) { 3730 if (cal_type != 0) 3731 phy_c6 = j % phy_c4; 3732 else 3733 phy_c6 = (2 * j) % phy_c4; 3734 3735 phy_c2.re = phy_c1[phy_c6].re; 3736 phy_c2.im = phy_c1[phy_c6].im; 3737 phy_c17 = ptr[j]; 3738 phy_c18 = phy_c18 + phy_c17 * phy_c2.re; 3739 phy_c19 = phy_c19 + phy_c17 * phy_c2.im; 3740 } 3741 3742 phy_c18 = phy_c18 >> 10; 3743 phy_c19 = phy_c19 >> 10; 3744 phy_c20 = ((phy_c18 * phy_c18) + 3745 (phy_c19 * phy_c19)); 3746 3747 if (phy_c23 || phy_c20 < phy_c21) { 3748 phy_c21 = phy_c20; 3749 phy_c13 = phy_c11; 3750 phy_c14 = phy_c12; 3751 } 3752 phy_c23 = false; 3753 } 3754 } 3755 phy_c23 = true; 3756 phy_c15 = phy_c13; 3757 phy_c16 = phy_c14; 3758 phy_c7 = phy_c7 >> 1; 3759 wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); 3760 udelay(20); 3761 } 3762 goto cleanup; 3763 cleanup: 3764 wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32); 3765 wlc_lcnphy_stop_tx_tone(pi); 3766 write_phy_reg(pi, 0x6da, phy_c26); 3767 write_phy_reg(pi, 0x6db, phy_c27); 3768 write_phy_reg(pi, 0x938, phy_c28); 3769 write_phy_reg(pi, 0x4d7, phy_c29); 3770 write_phy_reg(pi, 0x4d8, phy_c30); 3771 write_radio_reg(pi, RADIO_2064_REG026, phy_c31); 3772 3773 kfree(phy_c32); 3774 kfree(ptr); 3775 } 3776 3777 void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b) 3778 { 3779 u16 iqcc[2]; 3780 struct phytbl_info tab; 3781 3782 tab.tbl_ptr = iqcc; 3783 tab.tbl_len = 2; 3784 tab.tbl_id = 0; 3785 tab.tbl_offset = 80; 3786 tab.tbl_width = 16; 3787 wlc_lcnphy_read_table(pi, &tab); 3788 3789 *a = iqcc[0]; 3790 *b = iqcc[1]; 3791 } 3792 3793 static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi) 3794 { 3795 wlc_lcnphy_set_cc(pi, 0, 0, 0); 3796 wlc_lcnphy_set_cc(pi, 2, 0, 0); 3797 wlc_lcnphy_set_cc(pi, 3, 0, 0); 3798 wlc_lcnphy_set_cc(pi, 4, 0, 0); 3799 3800 wlc_lcnphy_a1(pi, 4, 0, 0); 3801 wlc_lcnphy_a1(pi, 3, 0, 0); 3802 wlc_lcnphy_a1(pi, 2, 3, 2); 3803 wlc_lcnphy_a1(pi, 0, 5, 8); 3804 wlc_lcnphy_a1(pi, 2, 2, 1); 3805 wlc_lcnphy_a1(pi, 0, 4, 3); 3806 3807 wlc_lcnphy_get_cc(pi, 0); 3808 wlc_lcnphy_get_cc(pi, 2); 3809 wlc_lcnphy_get_cc(pi, 3); 3810 wlc_lcnphy_get_cc(pi, 4); 3811 } 3812 3813 u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi) 3814 { 3815 struct phytbl_info tab; 3816 u16 didq; 3817 3818 tab.tbl_id = 0; 3819 tab.tbl_width = 16; 3820 tab.tbl_ptr = &didq; 3821 tab.tbl_len = 1; 3822 tab.tbl_offset = 85; 3823 wlc_lcnphy_read_table(pi, &tab); 3824 3825 return didq; 3826 } 3827 3828 static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) 3829 { 3830 3831 struct lcnphy_txgains target_gains, old_gains; 3832 u8 save_bb_mult; 3833 u16 a, b, didq, save_pa_gain = 0; 3834 uint idx, SAVE_txpwrindex = 0xFF; 3835 u32 val; 3836 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 3837 struct phytbl_info tab; 3838 u8 ei0, eq0, fi0, fq0; 3839 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3840 3841 wlc_lcnphy_get_tx_gain(pi, &old_gains); 3842 save_pa_gain = wlc_lcnphy_get_pa_gain(pi); 3843 3844 save_bb_mult = wlc_lcnphy_get_bbmult(pi); 3845 3846 if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF) 3847 SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi); 3848 3849 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 3850 3851 target_gains.gm_gain = 7; 3852 target_gains.pga_gain = 0; 3853 target_gains.pad_gain = 21; 3854 target_gains.dac_gain = 0; 3855 wlc_lcnphy_set_tx_gain(pi, &target_gains); 3856 3857 if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { 3858 3859 wlc_lcnphy_set_tx_pwr_by_index(pi, 30); 3860 3861 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, 3862 (pi_lcn-> 3863 lcnphy_recal ? LCNPHY_CAL_RECAL : 3864 LCNPHY_CAL_FULL), false); 3865 } else { 3866 wlc_lcnphy_set_tx_pwr_by_index(pi, 16); 3867 wlc_lcnphy_tx_iqlo_soft_cal_full(pi); 3868 } 3869 3870 wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0); 3871 if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) { 3872 if (CHSPEC_IS5G(pi->radio_chanspec)) { 3873 target_gains.gm_gain = 255; 3874 target_gains.pga_gain = 255; 3875 target_gains.pad_gain = 0xf0; 3876 target_gains.dac_gain = 0; 3877 } else { 3878 target_gains.gm_gain = 7; 3879 target_gains.pga_gain = 45; 3880 target_gains.pad_gain = 186; 3881 target_gains.dac_gain = 0; 3882 } 3883 3884 if (LCNREV_IS(pi->pubpi.phy_rev, 1) 3885 || pi_lcn->lcnphy_hw_iqcal_en) { 3886 3887 target_gains.pga_gain = 0; 3888 target_gains.pad_gain = 30; 3889 wlc_lcnphy_set_tx_pwr_by_index(pi, 16); 3890 wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, 3891 LCNPHY_CAL_FULL, false); 3892 } else { 3893 wlc_lcnphy_tx_iqlo_soft_cal_full(pi); 3894 } 3895 } 3896 3897 wlc_lcnphy_get_tx_iqcc(pi, &a, &b); 3898 3899 didq = wlc_lcnphy_get_tx_locc(pi); 3900 3901 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 3902 tab.tbl_width = 32; 3903 tab.tbl_ptr = &val; 3904 3905 tab.tbl_len = 1; 3906 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; 3907 3908 for (idx = 0; idx < 128; idx++) { 3909 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx; 3910 3911 wlc_lcnphy_read_table(pi, &tab); 3912 val = (val & 0xfff00000) | 3913 ((u32) (a & 0x3FF) << 10) | (b & 0x3ff); 3914 wlc_lcnphy_write_table(pi, &tab); 3915 3916 val = didq; 3917 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx; 3918 wlc_lcnphy_write_table(pi, &tab); 3919 } 3920 3921 pi_lcn->lcnphy_cal_results.txiqlocal_a = a; 3922 pi_lcn->lcnphy_cal_results.txiqlocal_b = b; 3923 pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq; 3924 pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0; 3925 pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0; 3926 pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0; 3927 pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0; 3928 3929 wlc_lcnphy_set_bbmult(pi, save_bb_mult); 3930 wlc_lcnphy_set_pa_gain(pi, save_pa_gain); 3931 wlc_lcnphy_set_tx_gain(pi, &old_gains); 3932 3933 if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF) 3934 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); 3935 else 3936 wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex); 3937 } 3938 3939 s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode) 3940 { 3941 u16 tempsenseval1, tempsenseval2; 3942 s16 avg = 0; 3943 bool suspend = false; 3944 3945 if (mode == 1) { 3946 suspend = (0 == (bcma_read32(pi->d11core, 3947 D11REGOFFS(maccontrol)) & 3948 MCTL_EN_MAC)); 3949 if (!suspend) 3950 wlapi_suspend_mac_and_wait(pi->sh->physhim); 3951 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); 3952 } 3953 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; 3954 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; 3955 3956 if (tempsenseval1 > 255) 3957 avg = (s16) (tempsenseval1 - 512); 3958 else 3959 avg = (s16) tempsenseval1; 3960 3961 if (tempsenseval2 > 255) 3962 avg += (s16) (tempsenseval2 - 512); 3963 else 3964 avg += (s16) tempsenseval2; 3965 3966 avg /= 2; 3967 3968 if (mode == 1) { 3969 3970 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); 3971 3972 udelay(100); 3973 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); 3974 3975 if (!suspend) 3976 wlapi_enable_mac(pi->sh->physhim); 3977 } 3978 return avg; 3979 } 3980 3981 u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode) 3982 { 3983 u16 tempsenseval1, tempsenseval2; 3984 s32 avg = 0; 3985 bool suspend = false; 3986 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 3987 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 3988 3989 if (mode == 1) { 3990 suspend = (0 == (bcma_read32(pi->d11core, 3991 D11REGOFFS(maccontrol)) & 3992 MCTL_EN_MAC)); 3993 if (!suspend) 3994 wlapi_suspend_mac_and_wait(pi->sh->physhim); 3995 wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); 3996 } 3997 tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; 3998 tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; 3999 4000 if (tempsenseval1 > 255) 4001 avg = (int)(tempsenseval1 - 512); 4002 else 4003 avg = (int)tempsenseval1; 4004 4005 if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) { 4006 if (tempsenseval2 > 255) 4007 avg = (int)(avg - tempsenseval2 + 512); 4008 else 4009 avg = (int)(avg - tempsenseval2); 4010 } else { 4011 if (tempsenseval2 > 255) 4012 avg = (int)(avg + tempsenseval2 - 512); 4013 else 4014 avg = (int)(avg + tempsenseval2); 4015 avg = avg / 2; 4016 } 4017 if (avg < 0) 4018 avg = avg + 512; 4019 4020 if (pi_lcn->lcnphy_tempsense_option == 2) 4021 avg = tempsenseval1; 4022 4023 if (mode) 4024 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); 4025 4026 if (mode == 1) { 4027 4028 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); 4029 4030 udelay(100); 4031 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); 4032 4033 if (!suspend) 4034 wlapi_enable_mac(pi->sh->physhim); 4035 } 4036 return (u16) avg; 4037 } 4038 4039 s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode) 4040 { 4041 s32 degree = wlc_lcnphy_tempsense_new(pi, mode); 4042 degree = 4043 ((degree << 4044 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1)) 4045 / LCN_TEMPSENSE_DEN; 4046 return (s8) degree; 4047 } 4048 4049 s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode) 4050 { 4051 u16 vbatsenseval; 4052 s32 avg = 0; 4053 bool suspend = false; 4054 4055 if (mode == 1) { 4056 suspend = (0 == (bcma_read32(pi->d11core, 4057 D11REGOFFS(maccontrol)) & 4058 MCTL_EN_MAC)); 4059 if (!suspend) 4060 wlapi_suspend_mac_and_wait(pi->sh->physhim); 4061 wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE); 4062 } 4063 4064 vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF; 4065 4066 if (vbatsenseval > 255) 4067 avg = (s32) (vbatsenseval - 512); 4068 else 4069 avg = (s32) vbatsenseval; 4070 4071 avg = (avg * LCN_VBAT_SCALE_NOM + 4072 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN; 4073 4074 if (mode == 1) { 4075 if (!suspend) 4076 wlapi_enable_mac(pi->sh->physhim); 4077 } 4078 return (s8) avg; 4079 } 4080 4081 static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode) 4082 { 4083 u8 phybw40; 4084 phybw40 = CHSPEC_IS40(pi->radio_chanspec); 4085 4086 mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7); 4087 4088 if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) || 4089 (mode == AFE_CLK_INIT_MODE_TXRX2X)) 4090 write_phy_reg(pi, 0x6d0, 0x7); 4091 4092 wlc_lcnphy_toggle_afe_pwdn(pi); 4093 } 4094 4095 static void wlc_lcnphy_temp_adj(struct brcms_phy *pi) 4096 { 4097 } 4098 4099 static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi) 4100 { 4101 bool suspend; 4102 s8 index; 4103 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 4104 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4105 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 4106 MCTL_EN_MAC)); 4107 if (!suspend) 4108 wlapi_suspend_mac_and_wait(pi->sh->physhim); 4109 wlc_lcnphy_deaf_mode(pi, true); 4110 pi->phy_lastcal = pi->sh->now; 4111 pi->phy_forcecal = false; 4112 index = pi_lcn->lcnphy_current_index; 4113 4114 wlc_lcnphy_txpwrtbl_iqlo_cal(pi); 4115 4116 wlc_lcnphy_set_tx_pwr_by_index(pi, index); 4117 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); 4118 wlc_lcnphy_deaf_mode(pi, false); 4119 if (!suspend) 4120 wlapi_enable_mac(pi->sh->physhim); 4121 4122 } 4123 4124 static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) 4125 { 4126 bool suspend; 4127 u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 4128 s8 index; 4129 struct phytbl_info tab; 4130 s32 a1, b0, b1; 4131 s32 tssi, pwr, mintargetpwr; 4132 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4133 4134 pi->phy_lastcal = pi->sh->now; 4135 pi->phy_forcecal = false; 4136 pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec); 4137 index = pi_lcn->lcnphy_current_index; 4138 4139 suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & 4140 MCTL_EN_MAC)); 4141 if (!suspend) { 4142 wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); 4143 wlapi_suspend_mac_and_wait(pi->sh->physhim); 4144 } 4145 4146 wlc_lcnphy_deaf_mode(pi, true); 4147 4148 wlc_lcnphy_txpwrtbl_iqlo_cal(pi); 4149 4150 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) 4151 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40); 4152 else 4153 wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127); 4154 4155 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { 4156 4157 wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi); 4158 4159 b0 = pi->txpa_2g[0]; 4160 b1 = pi->txpa_2g[1]; 4161 a1 = pi->txpa_2g[2]; 4162 mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); 4163 4164 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 4165 tab.tbl_width = 32; 4166 tab.tbl_ptr = &pwr; 4167 tab.tbl_len = 1; 4168 tab.tbl_offset = 0; 4169 for (tssi = 0; tssi < 128; tssi++) { 4170 pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); 4171 pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; 4172 wlc_lcnphy_write_table(pi, &tab); 4173 tab.tbl_offset++; 4174 } 4175 } 4176 4177 wlc_lcnphy_set_tx_pwr_by_index(pi, index); 4178 wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); 4179 wlc_lcnphy_deaf_mode(pi, false); 4180 if (!suspend) 4181 wlapi_enable_mac(pi->sh->physhim); 4182 } 4183 4184 void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode) 4185 { 4186 u16 temp_new; 4187 int temp1, temp2, temp_diff; 4188 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4189 4190 switch (mode) { 4191 case PHY_PERICAL_CHAN: 4192 break; 4193 case PHY_FULLCAL: 4194 wlc_lcnphy_periodic_cal(pi); 4195 break; 4196 case PHY_PERICAL_PHYINIT: 4197 wlc_lcnphy_periodic_cal(pi); 4198 break; 4199 case PHY_PERICAL_WATCHDOG: 4200 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { 4201 temp_new = wlc_lcnphy_tempsense(pi, 0); 4202 temp1 = LCNPHY_TEMPSENSE(temp_new); 4203 temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper); 4204 temp_diff = temp1 - temp2; 4205 if ((pi_lcn->lcnphy_cal_counter > 90) || 4206 (temp_diff > 60) || (temp_diff < -60)) { 4207 wlc_lcnphy_glacial_timer_based_cal(pi); 4208 wlc_2064_vco_cal(pi); 4209 pi_lcn->lcnphy_cal_temper = temp_new; 4210 pi_lcn->lcnphy_cal_counter = 0; 4211 } else 4212 pi_lcn->lcnphy_cal_counter++; 4213 } 4214 break; 4215 case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL: 4216 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 4217 wlc_lcnphy_tx_power_adjustment( 4218 (struct brcms_phy_pub *) pi); 4219 break; 4220 } 4221 } 4222 4223 void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr) 4224 { 4225 s8 cck_offset; 4226 u16 status; 4227 status = (read_phy_reg(pi, 0x4ab)); 4228 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && 4229 (status & (0x1 << 15))) { 4230 *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) 4231 >> 0) >> 1); 4232 4233 if (wlc_phy_tpc_isenabled_lcnphy(pi)) 4234 cck_offset = pi->tx_power_offset[TXP_FIRST_CCK]; 4235 else 4236 cck_offset = 0; 4237 4238 *cck_pwr = *ofdm_pwr + cck_offset; 4239 } else { 4240 *cck_pwr = 0; 4241 *ofdm_pwr = 0; 4242 } 4243 } 4244 4245 void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi) 4246 { 4247 return; 4248 4249 } 4250 4251 void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi) 4252 { 4253 s8 index; 4254 u16 index2; 4255 struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); 4256 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4257 u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 4258 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && 4259 SAVE_txpwrctrl) { 4260 index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); 4261 index2 = (u16) (index * 2); 4262 mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); 4263 4264 pi_lcn->lcnphy_current_index = 4265 (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2); 4266 } 4267 } 4268 4269 static void 4270 wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, 4271 const struct lcnphy_tx_gain_tbl_entry *gain_table) 4272 { 4273 u32 j; 4274 struct phytbl_info tab; 4275 u32 val; 4276 u16 pa_gain; 4277 u16 gm_gain; 4278 4279 if (pi->sh->boardflags & BFL_FEM) 4280 pa_gain = 0x10; 4281 else 4282 pa_gain = 0x60; 4283 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 4284 tab.tbl_width = 32; 4285 tab.tbl_len = 1; 4286 tab.tbl_ptr = &val; 4287 4288 /* fixed gm_gain value for iPA */ 4289 gm_gain = 15; 4290 for (j = 0; j < 128; j++) { 4291 if (pi->sh->boardflags & BFL_FEM) 4292 gm_gain = gain_table[j].gm; 4293 val = (((u32) pa_gain << 24) | 4294 (gain_table[j].pad << 16) | 4295 (gain_table[j].pga << 8) | gm_gain); 4296 4297 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j; 4298 wlc_lcnphy_write_table(pi, &tab); 4299 4300 val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20); 4301 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j; 4302 wlc_lcnphy_write_table(pi, &tab); 4303 } 4304 } 4305 4306 static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi) 4307 { 4308 struct phytbl_info tab; 4309 u32 val, bbmult, rfgain; 4310 u8 index; 4311 u8 scale_factor = 1; 4312 s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift; 4313 4314 tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; 4315 tab.tbl_width = 32; 4316 tab.tbl_len = 1; 4317 4318 for (index = 0; index < 128; index++) { 4319 tab.tbl_ptr = &bbmult; 4320 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; 4321 wlc_lcnphy_read_table(pi, &tab); 4322 bbmult = bbmult >> 20; 4323 4324 tab.tbl_ptr = &rfgain; 4325 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; 4326 wlc_lcnphy_read_table(pi, &tab); 4327 4328 qm_log10((s32) (bbmult), 0, &temp1, &qQ1); 4329 qm_log10((s32) (1 << 6), 0, &temp2, &qQ2); 4330 4331 if (qQ1 < qQ2) { 4332 temp2 = qm_shr16(temp2, qQ2 - qQ1); 4333 qQ = qQ1; 4334 } else { 4335 temp1 = qm_shr16(temp1, qQ1 - qQ2); 4336 qQ = qQ2; 4337 } 4338 temp = qm_sub16(temp1, temp2); 4339 4340 if (qQ >= 4) 4341 shift = qQ - 4; 4342 else 4343 shift = 4 - qQ; 4344 4345 val = (((index << shift) + (5 * temp) + 4346 (1 << (scale_factor + shift - 3))) >> (scale_factor + 4347 shift - 2)); 4348 4349 tab.tbl_ptr = &val; 4350 tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; 4351 wlc_lcnphy_write_table(pi, &tab); 4352 } 4353 } 4354 4355 static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi) 4356 { 4357 or_phy_reg(pi, 0x805, 0x1); 4358 4359 mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0); 4360 4361 mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0); 4362 4363 write_phy_reg(pi, 0x414, 0x1e10); 4364 write_phy_reg(pi, 0x415, 0x0640); 4365 4366 mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8); 4367 4368 or_phy_reg(pi, 0x44a, 0x44); 4369 write_phy_reg(pi, 0x44a, 0x80); 4370 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0); 4371 4372 mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0); 4373 4374 if (!(pi->sh->boardrev < 0x1204)) 4375 mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0); 4376 4377 write_phy_reg(pi, 0x7d6, 0x0902); 4378 mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0); 4379 4380 mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4); 4381 4382 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { 4383 mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0); 4384 4385 mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0); 4386 4387 mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0); 4388 4389 mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0); 4390 4391 mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); 4392 4393 mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4); 4394 mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0); 4395 mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90); 4396 mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2); 4397 mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0); 4398 4399 mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2); 4400 4401 wlc_lcnphy_clear_tx_power_offsets(pi); 4402 mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6); 4403 4404 } 4405 } 4406 4407 static void wlc_lcnphy_rcal(struct brcms_phy *pi) 4408 { 4409 u8 rcal_value; 4410 4411 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); 4412 4413 or_radio_reg(pi, RADIO_2064_REG004, 0x40); 4414 or_radio_reg(pi, RADIO_2064_REG120, 0x10); 4415 4416 or_radio_reg(pi, RADIO_2064_REG078, 0x80); 4417 or_radio_reg(pi, RADIO_2064_REG129, 0x02); 4418 4419 or_radio_reg(pi, RADIO_2064_REG057, 0x01); 4420 4421 or_radio_reg(pi, RADIO_2064_REG05B, 0x02); 4422 mdelay(5); 4423 SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000); 4424 4425 if (wlc_radio_2064_rcal_done(pi)) { 4426 rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C); 4427 rcal_value = rcal_value & 0x1f; 4428 } 4429 4430 and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); 4431 4432 and_radio_reg(pi, RADIO_2064_REG057, 0xFE); 4433 } 4434 4435 static void wlc_lcnphy_rc_cal(struct brcms_phy *pi) 4436 { 4437 u8 dflt_rc_cal_val; 4438 u16 flt_val; 4439 4440 dflt_rc_cal_val = 7; 4441 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) 4442 dflt_rc_cal_val = 11; 4443 flt_val = 4444 (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) | 4445 (dflt_rc_cal_val); 4446 write_phy_reg(pi, 0x933, flt_val); 4447 write_phy_reg(pi, 0x934, flt_val); 4448 write_phy_reg(pi, 0x935, flt_val); 4449 write_phy_reg(pi, 0x936, flt_val); 4450 write_phy_reg(pi, 0x937, (flt_val & 0x1FF)); 4451 4452 return; 4453 } 4454 4455 static void wlc_radio_2064_init(struct brcms_phy *pi) 4456 { 4457 u32 i; 4458 const struct lcnphy_radio_regs *lcnphyregs = NULL; 4459 4460 lcnphyregs = lcnphy_radio_regs_2064; 4461 4462 for (i = 0; lcnphyregs[i].address != 0xffff; i++) 4463 if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a) 4464 write_radio_reg(pi, 4465 ((lcnphyregs[i].address & 0x3fff) | 4466 RADIO_DEFAULT_CORE), 4467 (u16) lcnphyregs[i].init_a); 4468 else if (lcnphyregs[i].do_init_g) 4469 write_radio_reg(pi, 4470 ((lcnphyregs[i].address & 0x3fff) | 4471 RADIO_DEFAULT_CORE), 4472 (u16) lcnphyregs[i].init_g); 4473 4474 write_radio_reg(pi, RADIO_2064_REG032, 0x62); 4475 write_radio_reg(pi, RADIO_2064_REG033, 0x19); 4476 4477 write_radio_reg(pi, RADIO_2064_REG090, 0x10); 4478 4479 write_radio_reg(pi, RADIO_2064_REG010, 0x00); 4480 4481 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { 4482 4483 write_radio_reg(pi, RADIO_2064_REG060, 0x7f); 4484 write_radio_reg(pi, RADIO_2064_REG061, 0x72); 4485 write_radio_reg(pi, RADIO_2064_REG062, 0x7f); 4486 } 4487 4488 write_radio_reg(pi, RADIO_2064_REG01D, 0x02); 4489 write_radio_reg(pi, RADIO_2064_REG01E, 0x06); 4490 4491 mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0); 4492 4493 mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3); 4494 4495 mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6); 4496 4497 mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9); 4498 4499 mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12); 4500 4501 write_phy_reg(pi, 0x4ea, 0x4688); 4502 4503 if (pi->sh->boardflags & BFL_FEM) 4504 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); 4505 else 4506 mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); 4507 4508 mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); 4509 4510 mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0); 4511 4512 wlc_lcnphy_set_tx_locc(pi, 0); 4513 4514 wlc_lcnphy_rcal(pi); 4515 4516 wlc_lcnphy_rc_cal(pi); 4517 4518 if (!(pi->sh->boardflags & BFL_FEM)) { 4519 write_radio_reg(pi, RADIO_2064_REG032, 0x6f); 4520 write_radio_reg(pi, RADIO_2064_REG033, 0x19); 4521 write_radio_reg(pi, RADIO_2064_REG039, 0xe); 4522 } 4523 4524 } 4525 4526 static void wlc_lcnphy_radio_init(struct brcms_phy *pi) 4527 { 4528 wlc_radio_2064_init(pi); 4529 } 4530 4531 static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) 4532 { 4533 uint idx; 4534 struct phytbl_info tab; 4535 const struct phytbl_info *tb; 4536 u32 val; 4537 4538 for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) 4539 wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]); 4540 4541 if (pi->sh->boardflags & BFL_FEM_BT) { 4542 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; 4543 tab.tbl_width = 16; 4544 tab.tbl_ptr = &val; 4545 tab.tbl_len = 1; 4546 val = 100; 4547 tab.tbl_offset = 4; 4548 wlc_lcnphy_write_table(pi, &tab); 4549 } 4550 4551 if (!(pi->sh->boardflags & BFL_FEM)) { 4552 tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; 4553 tab.tbl_width = 16; 4554 tab.tbl_ptr = &val; 4555 tab.tbl_len = 1; 4556 4557 val = 150; 4558 tab.tbl_offset = 0; 4559 wlc_lcnphy_write_table(pi, &tab); 4560 4561 val = 220; 4562 tab.tbl_offset = 1; 4563 wlc_lcnphy_write_table(pi, &tab); 4564 } 4565 4566 if (CHSPEC_IS2G(pi->radio_chanspec)) { 4567 if (pi->sh->boardflags & BFL_FEM) 4568 wlc_lcnphy_load_tx_gain_table( 4569 pi, 4570 dot11lcnphy_2GHz_extPA_gaintable_rev0); 4571 else 4572 wlc_lcnphy_load_tx_gain_table( 4573 pi, 4574 dot11lcnphy_2GHz_gaintable_rev0); 4575 } 4576 4577 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { 4578 int l; 4579 4580 if (CHSPEC_IS2G(pi->radio_chanspec)) { 4581 l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz; 4582 if (pi->sh->boardflags & BFL_EXTLNA) 4583 tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2; 4584 else 4585 tb = dot11lcnphytbl_rx_gain_info_2G_rev2; 4586 } else { 4587 l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz; 4588 if (pi->sh->boardflags & BFL_EXTLNA_5GHz) 4589 tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2; 4590 else 4591 tb = dot11lcnphytbl_rx_gain_info_5G_rev2; 4592 } 4593 4594 for (idx = 0; idx < l; idx++) 4595 wlc_lcnphy_write_table(pi, &tb[idx]); 4596 } 4597 4598 if (pi->sh->boardflags & BFL_FEM) { 4599 if (pi->sh->boardflags & BFL_FEM_BT) { 4600 if (pi->sh->boardrev < 0x1250) 4601 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa; 4602 else 4603 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250; 4604 } else { 4605 tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa; 4606 } 4607 } else { 4608 if (pi->sh->boardflags & BFL_FEM_BT) 4609 tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa; 4610 else 4611 tb = &dot11lcn_sw_ctrl_tbl_info_4313; 4612 } 4613 wlc_lcnphy_write_table(pi, tb); 4614 wlc_lcnphy_load_rfpower(pi); 4615 4616 wlc_lcnphy_clear_papd_comptable(pi); 4617 } 4618 4619 static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi) 4620 { 4621 u16 afectrl1; 4622 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4623 4624 write_radio_reg(pi, RADIO_2064_REG11C, 0x0); 4625 4626 write_phy_reg(pi, 0x43b, 0x0); 4627 write_phy_reg(pi, 0x43c, 0x0); 4628 write_phy_reg(pi, 0x44c, 0x0); 4629 write_phy_reg(pi, 0x4e6, 0x0); 4630 write_phy_reg(pi, 0x4f9, 0x0); 4631 write_phy_reg(pi, 0x4b0, 0x0); 4632 write_phy_reg(pi, 0x938, 0x0); 4633 write_phy_reg(pi, 0x4b0, 0x0); 4634 write_phy_reg(pi, 0x44e, 0); 4635 4636 or_phy_reg(pi, 0x567, 0x03); 4637 4638 or_phy_reg(pi, 0x44a, 0x44); 4639 write_phy_reg(pi, 0x44a, 0x80); 4640 4641 if (!(pi->sh->boardflags & BFL_FEM)) 4642 wlc_lcnphy_set_tx_pwr_by_index(pi, 52); 4643 4644 if (0) { 4645 afectrl1 = 0; 4646 afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) | 4647 (pi_lcn->lcnphy_rssi_vc << 4) | 4648 (pi_lcn->lcnphy_rssi_gs << 10)); 4649 write_phy_reg(pi, 0x43e, afectrl1); 4650 } 4651 4652 mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0); 4653 if (pi->sh->boardflags & BFL_FEM) { 4654 mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0); 4655 4656 write_phy_reg(pi, 0x910, 0x1); 4657 } 4658 4659 mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8); 4660 mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0); 4661 mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0); 4662 4663 } 4664 4665 static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi) 4666 { 4667 if (CHSPEC_IS5G(pi->radio_chanspec)) { 4668 mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0); 4669 mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8); 4670 } 4671 } 4672 4673 static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi) 4674 { 4675 s16 temp; 4676 struct phytbl_info tab; 4677 u32 tableBuffer[2]; 4678 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4679 4680 temp = (s16) read_phy_reg(pi, 0x4df); 4681 pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0; 4682 4683 if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127) 4684 pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256; 4685 4686 pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8; 4687 4688 if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127) 4689 pi_lcn->lcnphy_dsssgainidxtableoffset -= 256; 4690 4691 tab.tbl_ptr = tableBuffer; 4692 tab.tbl_len = 2; 4693 tab.tbl_id = 17; 4694 tab.tbl_offset = 59; 4695 tab.tbl_width = 32; 4696 wlc_lcnphy_read_table(pi, &tab); 4697 4698 if (tableBuffer[0] > 63) 4699 tableBuffer[0] -= 128; 4700 pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0]; 4701 4702 if (tableBuffer[1] > 63) 4703 tableBuffer[1] -= 128; 4704 pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1]; 4705 4706 temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0)); 4707 if (temp > 127) 4708 temp -= 256; 4709 pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp; 4710 4711 pi_lcn->lcnphy_Med_Low_Gain_db = 4712 (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8; 4713 pi_lcn->lcnphy_Very_Low_Gain_db = 4714 (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0; 4715 4716 tab.tbl_ptr = tableBuffer; 4717 tab.tbl_len = 2; 4718 tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX; 4719 tab.tbl_offset = 28; 4720 tab.tbl_width = 32; 4721 wlc_lcnphy_read_table(pi, &tab); 4722 4723 pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0]; 4724 pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1]; 4725 4726 } 4727 4728 static void wlc_lcnphy_baseband_init(struct brcms_phy *pi) 4729 { 4730 4731 wlc_lcnphy_tbl_init(pi); 4732 wlc_lcnphy_rev0_baseband_init(pi); 4733 if (LCNREV_IS(pi->pubpi.phy_rev, 2)) 4734 wlc_lcnphy_rev2_baseband_init(pi); 4735 wlc_lcnphy_bu_tweaks(pi); 4736 } 4737 4738 void wlc_phy_init_lcnphy(struct brcms_phy *pi) 4739 { 4740 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4741 4742 pi_lcn->lcnphy_cal_counter = 0; 4743 pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense; 4744 4745 or_phy_reg(pi, 0x44a, 0x80); 4746 and_phy_reg(pi, 0x44a, 0x7f); 4747 4748 wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X); 4749 4750 write_phy_reg(pi, 0x60a, 160); 4751 4752 write_phy_reg(pi, 0x46a, 25); 4753 4754 wlc_lcnphy_baseband_init(pi); 4755 4756 wlc_lcnphy_radio_init(pi); 4757 4758 if (CHSPEC_IS2G(pi->radio_chanspec)) 4759 wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi); 4760 4761 wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec); 4762 4763 bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9); 4764 4765 bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0, 4766 0x03CDDDDD); 4767 4768 if ((pi->sh->boardflags & BFL_FEM) 4769 && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 4770 wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR); 4771 4772 wlc_lcnphy_agc_temp_init(pi); 4773 4774 wlc_lcnphy_temp_adj(pi); 4775 4776 mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); 4777 4778 udelay(100); 4779 mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); 4780 4781 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); 4782 pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT; 4783 wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT); 4784 } 4785 4786 static void wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) 4787 { 4788 s8 txpwr = 0; 4789 int i; 4790 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 4791 struct ssb_sprom *sprom = &pi->d11core->bus->sprom; 4792 4793 if (CHSPEC_IS2G(pi->radio_chanspec)) { 4794 u16 cckpo = 0; 4795 u32 offset_ofdm, offset_mcs; 4796 4797 pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso; 4798 4799 pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g; 4800 4801 pi->txpa_2g[0] = sprom->pa0b0; 4802 pi->txpa_2g[1] = sprom->pa0b1; 4803 pi->txpa_2g[2] = sprom->pa0b2; 4804 4805 pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g; 4806 pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g; 4807 pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g; 4808 4809 pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf; 4810 pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc; 4811 pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs; 4812 4813 pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf; 4814 pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc; 4815 pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs; 4816 4817 txpwr = sprom->core_pwr_info[0].maxpwr_2g; 4818 pi->tx_srom_max_2g = txpwr; 4819 4820 for (i = 0; i < PWRTBL_NUM_COEFF; i++) { 4821 pi->txpa_2g_low_temp[i] = pi->txpa_2g[i]; 4822 pi->txpa_2g_high_temp[i] = pi->txpa_2g[i]; 4823 } 4824 4825 cckpo = sprom->cck2gpo; 4826 offset_ofdm = sprom->ofdm2gpo; 4827 if (cckpo) { 4828 uint max_pwr_chan = txpwr; 4829 4830 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) { 4831 pi->tx_srom_max_rate_2g[i] = 4832 max_pwr_chan - ((cckpo & 0xf) * 2); 4833 cckpo >>= 4; 4834 } 4835 4836 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { 4837 pi->tx_srom_max_rate_2g[i] = 4838 max_pwr_chan - 4839 ((offset_ofdm & 0xf) * 2); 4840 offset_ofdm >>= 4; 4841 } 4842 } else { 4843 for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) 4844 pi->tx_srom_max_rate_2g[i] = txpwr; 4845 4846 for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { 4847 pi->tx_srom_max_rate_2g[i] = txpwr - 4848 ((offset_ofdm & 0xf) * 2); 4849 offset_ofdm >>= 4; 4850 } 4851 offset_mcs = sprom->mcs2gpo[1] << 16; 4852 offset_mcs |= sprom->mcs2gpo[0]; 4853 pi_lcn->lcnphy_mcs20_po = offset_mcs; 4854 for (i = TXP_FIRST_SISO_MCS_20; 4855 i <= TXP_LAST_SISO_MCS_20; i++) { 4856 pi->tx_srom_max_rate_2g[i] = 4857 txpwr - ((offset_mcs & 0xf) * 2); 4858 offset_mcs >>= 4; 4859 } 4860 } 4861 4862 pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense; 4863 pi_lcn->lcnphy_measPower = sprom->measpower; 4864 pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope; 4865 pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en; 4866 pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis; 4867 pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx; 4868 pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option; 4869 pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr; 4870 if (sprom->ant_available_bg > 1) 4871 wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, 4872 sprom->ant_available_bg); 4873 } 4874 pi_lcn->lcnphy_cck_dig_filt_type = -1; 4875 } 4876 4877 void wlc_2064_vco_cal(struct brcms_phy *pi) 4878 { 4879 u8 calnrst; 4880 4881 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3); 4882 calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8; 4883 write_radio_reg(pi, RADIO_2064_REG056, calnrst); 4884 udelay(1); 4885 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03); 4886 udelay(1); 4887 write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07); 4888 udelay(300); 4889 mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0); 4890 } 4891 4892 bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi) 4893 { 4894 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) 4895 return false; 4896 else 4897 return (LCNPHY_TX_PWR_CTRL_HW == 4898 wlc_lcnphy_get_tx_pwr_ctrl((pi))); 4899 } 4900 4901 void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi) 4902 { 4903 u16 pwr_ctrl; 4904 if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { 4905 wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); 4906 } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { 4907 pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); 4908 wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); 4909 wlc_lcnphy_txpower_recalc_target(pi); 4910 wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl); 4911 } 4912 } 4913 4914 void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) 4915 { 4916 u8 channel = CHSPEC_CHANNEL(chanspec); 4917 4918 wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec); 4919 4920 wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); 4921 4922 or_phy_reg(pi, 0x44a, 0x44); 4923 write_phy_reg(pi, 0x44a, 0x80); 4924 4925 wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); 4926 udelay(1000); 4927 4928 wlc_lcnphy_toggle_afe_pwdn(pi); 4929 4930 write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); 4931 write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); 4932 4933 if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { 4934 mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); 4935 4936 wlc_lcnphy_load_tx_iir_filter(pi, false, 3); 4937 } else { 4938 mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); 4939 4940 wlc_lcnphy_load_tx_iir_filter(pi, false, 2); 4941 } 4942 4943 if (pi->sh->boardflags & BFL_FEM) 4944 wlc_lcnphy_load_tx_iir_filter(pi, true, 0); 4945 else 4946 wlc_lcnphy_load_tx_iir_filter(pi, true, 3); 4947 4948 mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); 4949 if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) 4950 wlc_lcnphy_tssi_setup(pi); 4951 } 4952 4953 void wlc_phy_detach_lcnphy(struct brcms_phy *pi) 4954 { 4955 kfree(pi->u.pi_lcnphy); 4956 } 4957 4958 bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) 4959 { 4960 struct brcms_phy_lcnphy *pi_lcn; 4961 4962 pi_lcn = kzalloc_obj(*pi_lcn, GFP_ATOMIC); 4963 if (!pi_lcn) 4964 return false; 4965 4966 pi->u.pi_lcnphy = pi_lcn; 4967 4968 if (0 == (pi->sh->boardflags & BFL_NOPA)) { 4969 pi->hwpwrctrl = true; 4970 pi->hwpwrctrl_capable = true; 4971 } 4972 4973 pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc); 4974 pi_lcn->lcnphy_papd_rxGnCtrl_init = 0; 4975 4976 pi->pi_fptr.init = wlc_phy_init_lcnphy; 4977 pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy; 4978 pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy; 4979 pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy; 4980 pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc; 4981 pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc; 4982 pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc; 4983 pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft; 4984 pi->pi_fptr.detach = wlc_phy_detach_lcnphy; 4985 4986 wlc_phy_txpwr_srom_read_lcnphy(pi); 4987 4988 if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { 4989 if (pi_lcn->lcnphy_tempsense_option == 3) { 4990 pi->hwpwrctrl = true; 4991 pi->hwpwrctrl_capable = true; 4992 pi->temppwrctrl_capable = false; 4993 } else { 4994 pi->hwpwrctrl = false; 4995 pi->hwpwrctrl_capable = false; 4996 pi->temppwrctrl_capable = true; 4997 } 4998 } 4999 5000 return true; 5001 } 5002 5003 static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain) 5004 { 5005 u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19; 5006 5007 trsw = (gain & ((u32) 1 << 28)) ? 0 : 1; 5008 ext_lna = (u16) (gain >> 29) & 0x01; 5009 lna1 = (u16) (gain >> 0) & 0x0f; 5010 lna2 = (u16) (gain >> 4) & 0x0f; 5011 tia = (u16) (gain >> 8) & 0xf; 5012 biq0 = (u16) (gain >> 12) & 0xf; 5013 biq1 = (u16) (gain >> 16) & 0xf; 5014 5015 gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) | 5016 ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) | 5017 ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12)); 5018 gain16_19 = biq1; 5019 5020 mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0); 5021 mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); 5022 mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); 5023 mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); 5024 mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); 5025 5026 if (CHSPEC_IS2G(pi->radio_chanspec)) { 5027 mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); 5028 mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); 5029 } 5030 wlc_lcnphy_rx_gain_override_enable(pi, true); 5031 } 5032 5033 static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index) 5034 { 5035 u32 received_power = 0; 5036 s32 max_index = 0; 5037 u32 gain_code = 0; 5038 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 5039 5040 max_index = 36; 5041 if (*gain_index >= 0) 5042 gain_code = lcnphy_23bitgaincode_table[*gain_index]; 5043 5044 if (-1 == *gain_index) { 5045 *gain_index = 0; 5046 while ((*gain_index <= (s32) max_index) 5047 && (received_power < 700)) { 5048 wlc_lcnphy_set_rx_gain(pi, 5049 lcnphy_23bitgaincode_table 5050 [*gain_index]); 5051 received_power = 5052 wlc_lcnphy_measure_digital_power( 5053 pi, 5054 pi_lcn-> 5055 lcnphy_noise_samples); 5056 (*gain_index)++; 5057 } 5058 (*gain_index)--; 5059 } else { 5060 wlc_lcnphy_set_rx_gain(pi, gain_code); 5061 received_power = 5062 wlc_lcnphy_measure_digital_power(pi, 5063 pi_lcn-> 5064 lcnphy_noise_samples); 5065 } 5066 5067 return received_power; 5068 } 5069 5070 s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index) 5071 { 5072 s32 gain = 0; 5073 s32 nominal_power_db; 5074 s32 log_val, gain_mismatch, desired_gain, input_power_offset_db, 5075 input_power_db; 5076 s32 received_power, temperature; 5077 u32 power; 5078 u32 msb1, msb2, val1, val2, diff1, diff2; 5079 uint freq; 5080 struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; 5081 5082 received_power = wlc_lcnphy_get_receive_power(pi, &gain_index); 5083 5084 gain = lcnphy_gain_table[gain_index]; 5085 5086 nominal_power_db = read_phy_reg(pi, 0x425) >> 8; 5087 5088 power = (received_power * 16); 5089 msb1 = ffs(power) - 1; 5090 msb2 = msb1 + 1; 5091 val1 = 1 << msb1; 5092 val2 = 1 << msb2; 5093 diff1 = (power - val1); 5094 diff2 = (val2 - power); 5095 if (diff1 < diff2) 5096 log_val = msb1; 5097 else 5098 log_val = msb2; 5099 5100 log_val = log_val * 3; 5101 5102 gain_mismatch = (nominal_power_db / 2) - (log_val); 5103 5104 desired_gain = gain + gain_mismatch; 5105 5106 input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF; 5107 5108 if (input_power_offset_db > 127) 5109 input_power_offset_db -= 256; 5110 5111 input_power_db = input_power_offset_db - desired_gain; 5112 5113 input_power_db = 5114 input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index]; 5115 5116 freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec)); 5117 if ((freq > 2427) && (freq <= 2467)) 5118 input_power_db = input_power_db - 1; 5119 5120 temperature = pi_lcn->lcnphy_lastsensed_temperature; 5121 5122 if ((temperature - 15) < -30) 5123 input_power_db = 5124 input_power_db + 5125 (((temperature - 10 - 25) * 286) >> 12) - 5126 7; 5127 else if ((temperature - 15) < 4) 5128 input_power_db = 5129 input_power_db + 5130 (((temperature - 10 - 25) * 286) >> 12) - 5131 3; 5132 else 5133 input_power_db = input_power_db + 5134 (((temperature - 10 - 25) * 286) >> 12); 5135 5136 wlc_lcnphy_rx_gain_override_enable(pi, 0); 5137 5138 return input_power_db; 5139 } 5140