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