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