Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
178703 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2010 Broadcom Corporation3*/45#include <linux/kernel.h>6#include <linux/delay.h>7#include <linux/cordic.h>89#include <pmu.h>10#include <d11.h>11#include <phy_shim.h>12#include "phy_qmath.h"13#include "phy_hal.h"14#include "phy_radio.h"15#include "phytbl_lcn.h"16#include "phy_lcn.h"1718#define PLL_2064_NDIV 9019#define PLL_2064_LOW_END_VCO 300020#define PLL_2064_LOW_END_KVCO 2721#define PLL_2064_HIGH_END_VCO 420022#define PLL_2064_HIGH_END_KVCO 6823#define PLL_2064_LOOP_BW_DOUBLER 20024#define PLL_2064_D30_DOUBLER 1050025#define PLL_2064_LOOP_BW 26026#define PLL_2064_D30 800027#define PLL_2064_CAL_REF_TO 828#define PLL_2064_MHZ 100000029#define PLL_2064_OPEN_LOOP_DELAY 53031#define TEMPSENSE 132#define VBATSENSE 23334#define NOISE_IF_UPD_CHK_INTERVAL 135#define NOISE_IF_UPD_RST_INTERVAL 6036#define NOISE_IF_UPD_THRESHOLD_CNT 137#define NOISE_IF_UPD_TRHRESHOLD 5038#define NOISE_IF_UPD_TIMEOUT 100039#define NOISE_IF_OFF 040#define NOISE_IF_CHK 141#define NOISE_IF_ON 24243#define PAPD_BLANKING_PROFILE 344#define PAPD2LUT 045#define PAPD_CORR_NORM 046#define PAPD_BLANKING_THRESHOLD 047#define PAPD_STOP_AFTER_LAST_UPDATE 04849#define LCN_TARGET_PWR 605051#define LCN_VBAT_OFFSET_433X 3464967952#define LCN_VBAT_SLOPE_433X 82580325354#define LCN_VBAT_SCALE_NOM 5355#define LCN_VBAT_SCALE_DEN 4325657#define LCN_TEMPSENSE_OFFSET 8081258#define LCN_TEMPSENSE_DEN 26475960#define LCN_BW_LMT 20061#define LCN_CUR_LMT 125062#define LCN_MULT 163#define LCN_VCO_DIV 3064#define LCN_OFFSET 68065#define LCN_FACT 49066#define LCN_CUR_DIV 26406768#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \69(0 + 8)70#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \71(0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)7273#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \74(0 + 8)75#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \76(0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)7778#define wlc_lcnphy_enable_tx_gain_override(pi) \79wlc_lcnphy_set_tx_gain_override(pi, true)80#define wlc_lcnphy_disable_tx_gain_override(pi) \81wlc_lcnphy_set_tx_gain_override(pi, false)8283#define wlc_lcnphy_iqcal_active(pi) \84(read_phy_reg((pi), 0x451) & \85((0x1 << 15) | (0x1 << 14)))8687#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))88#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \89(pi->temppwrctrl_capable)90#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \91(pi->hwpwrctrl_capable)9293#define SWCTRL_BT_TX 0x1894#define SWCTRL_OVR_DISABLE 0x409596#define AFE_CLK_INIT_MODE_TXRX2X 197#define AFE_CLK_INIT_MODE_PAPD 09899#define LCNPHY_TBL_ID_IQLOCAL 0x00100101#define LCNPHY_TBL_ID_RFSEQ 0x08102#define LCNPHY_TBL_ID_GAIN_IDX 0x0d103#define LCNPHY_TBL_ID_SW_CTRL 0x0f104#define LCNPHY_TBL_ID_GAIN_TBL 0x12105#define LCNPHY_TBL_ID_SPUR 0x14106#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15107#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16108109#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832110#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128111#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192112#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320113#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448114#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576115116#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140117118#define LCNPHY_TX_PWR_CTRL_START_NPT 1119#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7120121#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000122123#define LCNPHY_ACI_DETECT_START 1124#define LCNPHY_ACI_DETECT_PROGRESS 2125#define LCNPHY_ACI_DETECT_STOP 3126127#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100128#define LCNPHY_ACI_GLITCH_TRSH 2000129#define LCNPHY_ACI_TMOUT 250130#define LCNPHY_ACI_DETECT_TIMEOUT 2131#define LCNPHY_ACI_START_DELAY 0132133#define wlc_lcnphy_tx_gain_override_enabled(pi) \134(0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))135136#define wlc_lcnphy_total_tx_frames(pi) \137wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \138offsetof(struct macstat, txallfrm))139140struct lcnphy_txgains {141u16 gm_gain;142u16 pga_gain;143u16 pad_gain;144u16 dac_gain;145};146147enum lcnphy_cal_mode {148LCNPHY_CAL_FULL,149LCNPHY_CAL_RECAL,150LCNPHY_CAL_CURRECAL,151LCNPHY_CAL_DIGCAL,152LCNPHY_CAL_GCTRL153};154155struct lcnphy_rx_iqcomp {156u8 chan;157s16 a;158s16 b;159};160161struct lcnphy_spb_tone {162s16 re;163s16 im;164};165166struct lcnphy_unsign16_struct {167u16 re;168u16 im;169};170171struct lcnphy_iq_est {172u32 iq_prod;173u32 i_pwr;174u32 q_pwr;175};176177struct lcnphy_sfo_cfg {178u16 ptcentreTs20;179u16 ptcentreFactor;180};181182enum lcnphy_papd_cal_type {183LCNPHY_PAPD_CAL_CW,184LCNPHY_PAPD_CAL_OFDM185};186187typedef u16 iqcal_gain_params_lcnphy[9];188189static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {190{0, 0, 0, 0, 0, 0, 0, 0, 0},191};192193static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {194tbl_iqcal_gainparams_lcnphy_2G,195};196197static const u16 iqcal_gainparams_numgains_lcnphy[1] = {198ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),199};200201static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {202{965, 1087},203{967, 1085},204{969, 1082},205{971, 1080},206{973, 1078},207{975, 1076},208{977, 1073},209{979, 1071},210{981, 1069},211{983, 1067},212{985, 1065},213{987, 1063},214{989, 1060},215{994, 1055}216};217218static const219u16 lcnphy_iqcal_loft_gainladder[] = {220((2 << 8) | 0),221((3 << 8) | 0),222((4 << 8) | 0),223((6 << 8) | 0),224((8 << 8) | 0),225((11 << 8) | 0),226((16 << 8) | 0),227((16 << 8) | 1),228((16 << 8) | 2),229((16 << 8) | 3),230((16 << 8) | 4),231((16 << 8) | 5),232((16 << 8) | 6),233((16 << 8) | 7),234((23 << 8) | 7),235((32 << 8) | 7),236((45 << 8) | 7),237((64 << 8) | 7),238((91 << 8) | 7),239((128 << 8) | 7)240};241242static const243u16 lcnphy_iqcal_ir_gainladder[] = {244((1 << 8) | 0),245((2 << 8) | 0),246((4 << 8) | 0),247((6 << 8) | 0),248((8 << 8) | 0),249((11 << 8) | 0),250((16 << 8) | 0),251((23 << 8) | 0),252((32 << 8) | 0),253((45 << 8) | 0),254((64 << 8) | 0),255((64 << 8) | 1),256((64 << 8) | 2),257((64 << 8) | 3),258((64 << 8) | 4),259((64 << 8) | 5),260((64 << 8) | 6),261((64 << 8) | 7),262((91 << 8) | 7),263((128 << 8) | 7)264};265266static const267struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {268{88, 0},269{73, 49},270{34, 81},271{-17, 86},272{-62, 62},273{-86, 17},274{-81, -34},275{-49, -73},276{0, -88},277{49, -73},278{81, -34},279{86, 17},280{62, 62},281{17, 86},282{-34, 81},283{-73, 49},284{-88, 0},285{-73, -49},286{-34, -81},287{17, -86},288{62, -62},289{86, -17},290{81, 34},291{49, 73},292{0, 88},293{-49, 73},294{-81, 34},295{-86, -17},296{-62, -62},297{-17, -86},298{34, -81},299{73, -49},300};301302static const303u16 iqlo_loopback_rf_regs[20] = {304RADIO_2064_REG036,305RADIO_2064_REG11A,306RADIO_2064_REG03A,307RADIO_2064_REG025,308RADIO_2064_REG028,309RADIO_2064_REG005,310RADIO_2064_REG112,311RADIO_2064_REG0FF,312RADIO_2064_REG11F,313RADIO_2064_REG00B,314RADIO_2064_REG113,315RADIO_2064_REG007,316RADIO_2064_REG0FC,317RADIO_2064_REG0FD,318RADIO_2064_REG012,319RADIO_2064_REG057,320RADIO_2064_REG059,321RADIO_2064_REG05C,322RADIO_2064_REG078,323RADIO_2064_REG092,324};325326static const327u16 tempsense_phy_regs[14] = {3280x503,3290x4a4,3300x4d0,3310x4d9,3320x4da,3330x4a6,3340x938,3350x939,3360x4d8,3370x4d0,3380x4d7,3390x4a5,3400x40d,3410x4a2,342};343344static const345u16 rxiq_cal_rf_reg[11] = {346RADIO_2064_REG098,347RADIO_2064_REG116,348RADIO_2064_REG12C,349RADIO_2064_REG06A,350RADIO_2064_REG00B,351RADIO_2064_REG01B,352RADIO_2064_REG113,353RADIO_2064_REG01D,354RADIO_2064_REG114,355RADIO_2064_REG02E,356RADIO_2064_REG12A,357};358359static const u32 lcnphy_23bitgaincode_table[] = {3600x200100,3610x200200,3620x200004,3630x200014,3640x200024,3650x200034,3660x200134,3670x200234,3680x200334,3690x200434,3700x200037,3710x200137,3720x200237,3730x200337,3740x200437,3750x000035,3760x000135,3770x000235,3780x000037,3790x000137,3800x000237,3810x000337,3820x00013f,3830x00023f,3840x00033f,3850x00034f,3860x00044f,3870x00144f,3880x00244f,3890x00254f,3900x00354f,3910x00454f,3920x00464f,3930x01464f,3940x02464f,3950x03464f,3960x04464f,397};398399static const s8 lcnphy_gain_table[] = {400-16,401-13,40210,4037,4044,4050,4063,4076,4089,40912,41015,41118,41221,41324,41427,41530,41633,41736,41839,41942,42045,42148,42250,42353,42456,42559,42662,42765,42868,42971,43074,43177,43280,43383,43486,43589,43692,437};438439static const s8 lcnphy_gain_index_offset_for_rssi[] = {4407,4417,4427,4437,4447,4457,4467,4478,4487,4497,4506,4517,4527,4534,4544,4554,4564,4574,4584,4594,4604,4613,4623,4633,4643,4653,4663,4674,4682,4692,4702,4712,4722,4732,474-1,475-2,476-2,477-2478};479480struct chan_info_2064_lcnphy {481uint chan;482uint freq;483u8 logen_buftune;484u8 logen_rccr_tx;485u8 txrf_mix_tune_ctrl;486u8 pa_input_tune_g;487u8 logen_rccr_rx;488u8 pa_rxrf_lna1_freq_tune;489u8 pa_rxrf_lna2_freq_tune;490u8 rxrf_rxrf_spare1;491};492493static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {494{1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},495{2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},496{3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},497{4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},498{5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},499{6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},500{7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},501{8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},502{9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},503{10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},504{11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},505{12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},506{13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},507{14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},508};509510static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {511{0x00, 0, 0, 0, 0},512{0x01, 0x64, 0x64, 0, 0},513{0x02, 0x20, 0x20, 0, 0},514{0x03, 0x66, 0x66, 0, 0},515{0x04, 0xf8, 0xf8, 0, 0},516{0x05, 0, 0, 0, 0},517{0x06, 0x10, 0x10, 0, 0},518{0x07, 0, 0, 0, 0},519{0x08, 0, 0, 0, 0},520{0x09, 0, 0, 0, 0},521{0x0A, 0x37, 0x37, 0, 0},522{0x0B, 0x6, 0x6, 0, 0},523{0x0C, 0x55, 0x55, 0, 0},524{0x0D, 0x8b, 0x8b, 0, 0},525{0x0E, 0, 0, 0, 0},526{0x0F, 0x5, 0x5, 0, 0},527{0x10, 0, 0, 0, 0},528{0x11, 0xe, 0xe, 0, 0},529{0x12, 0, 0, 0, 0},530{0x13, 0xb, 0xb, 0, 0},531{0x14, 0x2, 0x2, 0, 0},532{0x15, 0x12, 0x12, 0, 0},533{0x16, 0x12, 0x12, 0, 0},534{0x17, 0xc, 0xc, 0, 0},535{0x18, 0xc, 0xc, 0, 0},536{0x19, 0xc, 0xc, 0, 0},537{0x1A, 0x8, 0x8, 0, 0},538{0x1B, 0x2, 0x2, 0, 0},539{0x1C, 0, 0, 0, 0},540{0x1D, 0x1, 0x1, 0, 0},541{0x1E, 0x12, 0x12, 0, 0},542{0x1F, 0x6e, 0x6e, 0, 0},543{0x20, 0x2, 0x2, 0, 0},544{0x21, 0x23, 0x23, 0, 0},545{0x22, 0x8, 0x8, 0, 0},546{0x23, 0, 0, 0, 0},547{0x24, 0, 0, 0, 0},548{0x25, 0xc, 0xc, 0, 0},549{0x26, 0x33, 0x33, 0, 0},550{0x27, 0x55, 0x55, 0, 0},551{0x28, 0, 0, 0, 0},552{0x29, 0x30, 0x30, 0, 0},553{0x2A, 0xb, 0xb, 0, 0},554{0x2B, 0x1b, 0x1b, 0, 0},555{0x2C, 0x3, 0x3, 0, 0},556{0x2D, 0x1b, 0x1b, 0, 0},557{0x2E, 0, 0, 0, 0},558{0x2F, 0x20, 0x20, 0, 0},559{0x30, 0xa, 0xa, 0, 0},560{0x31, 0, 0, 0, 0},561{0x32, 0x62, 0x62, 0, 0},562{0x33, 0x19, 0x19, 0, 0},563{0x34, 0x33, 0x33, 0, 0},564{0x35, 0x77, 0x77, 0, 0},565{0x36, 0, 0, 0, 0},566{0x37, 0x70, 0x70, 0, 0},567{0x38, 0x3, 0x3, 0, 0},568{0x39, 0xf, 0xf, 0, 0},569{0x3A, 0x6, 0x6, 0, 0},570{0x3B, 0xcf, 0xcf, 0, 0},571{0x3C, 0x1a, 0x1a, 0, 0},572{0x3D, 0x6, 0x6, 0, 0},573{0x3E, 0x42, 0x42, 0, 0},574{0x3F, 0, 0, 0, 0},575{0x40, 0xfb, 0xfb, 0, 0},576{0x41, 0x9a, 0x9a, 0, 0},577{0x42, 0x7a, 0x7a, 0, 0},578{0x43, 0x29, 0x29, 0, 0},579{0x44, 0, 0, 0, 0},580{0x45, 0x8, 0x8, 0, 0},581{0x46, 0xce, 0xce, 0, 0},582{0x47, 0x27, 0x27, 0, 0},583{0x48, 0x62, 0x62, 0, 0},584{0x49, 0x6, 0x6, 0, 0},585{0x4A, 0x58, 0x58, 0, 0},586{0x4B, 0xf7, 0xf7, 0, 0},587{0x4C, 0, 0, 0, 0},588{0x4D, 0xb3, 0xb3, 0, 0},589{0x4E, 0, 0, 0, 0},590{0x4F, 0x2, 0x2, 0, 0},591{0x50, 0, 0, 0, 0},592{0x51, 0x9, 0x9, 0, 0},593{0x52, 0x5, 0x5, 0, 0},594{0x53, 0x17, 0x17, 0, 0},595{0x54, 0x38, 0x38, 0, 0},596{0x55, 0, 0, 0, 0},597{0x56, 0, 0, 0, 0},598{0x57, 0xb, 0xb, 0, 0},599{0x58, 0, 0, 0, 0},600{0x59, 0, 0, 0, 0},601{0x5A, 0, 0, 0, 0},602{0x5B, 0, 0, 0, 0},603{0x5C, 0, 0, 0, 0},604{0x5D, 0, 0, 0, 0},605{0x5E, 0x88, 0x88, 0, 0},606{0x5F, 0xcc, 0xcc, 0, 0},607{0x60, 0x74, 0x74, 0, 0},608{0x61, 0x74, 0x74, 0, 0},609{0x62, 0x74, 0x74, 0, 0},610{0x63, 0x44, 0x44, 0, 0},611{0x64, 0x77, 0x77, 0, 0},612{0x65, 0x44, 0x44, 0, 0},613{0x66, 0x77, 0x77, 0, 0},614{0x67, 0x55, 0x55, 0, 0},615{0x68, 0x77, 0x77, 0, 0},616{0x69, 0x77, 0x77, 0, 0},617{0x6A, 0, 0, 0, 0},618{0x6B, 0x7f, 0x7f, 0, 0},619{0x6C, 0x8, 0x8, 0, 0},620{0x6D, 0, 0, 0, 0},621{0x6E, 0x88, 0x88, 0, 0},622{0x6F, 0x66, 0x66, 0, 0},623{0x70, 0x66, 0x66, 0, 0},624{0x71, 0x28, 0x28, 0, 0},625{0x72, 0x55, 0x55, 0, 0},626{0x73, 0x4, 0x4, 0, 0},627{0x74, 0, 0, 0, 0},628{0x75, 0, 0, 0, 0},629{0x76, 0, 0, 0, 0},630{0x77, 0x1, 0x1, 0, 0},631{0x78, 0xd6, 0xd6, 0, 0},632{0x79, 0, 0, 0, 0},633{0x7A, 0, 0, 0, 0},634{0x7B, 0, 0, 0, 0},635{0x7C, 0, 0, 0, 0},636{0x7D, 0, 0, 0, 0},637{0x7E, 0, 0, 0, 0},638{0x7F, 0, 0, 0, 0},639{0x80, 0, 0, 0, 0},640{0x81, 0, 0, 0, 0},641{0x82, 0, 0, 0, 0},642{0x83, 0xb4, 0xb4, 0, 0},643{0x84, 0x1, 0x1, 0, 0},644{0x85, 0x20, 0x20, 0, 0},645{0x86, 0x5, 0x5, 0, 0},646{0x87, 0xff, 0xff, 0, 0},647{0x88, 0x7, 0x7, 0, 0},648{0x89, 0x77, 0x77, 0, 0},649{0x8A, 0x77, 0x77, 0, 0},650{0x8B, 0x77, 0x77, 0, 0},651{0x8C, 0x77, 0x77, 0, 0},652{0x8D, 0x8, 0x8, 0, 0},653{0x8E, 0xa, 0xa, 0, 0},654{0x8F, 0x8, 0x8, 0, 0},655{0x90, 0x18, 0x18, 0, 0},656{0x91, 0x5, 0x5, 0, 0},657{0x92, 0x1f, 0x1f, 0, 0},658{0x93, 0x10, 0x10, 0, 0},659{0x94, 0x3, 0x3, 0, 0},660{0x95, 0, 0, 0, 0},661{0x96, 0, 0, 0, 0},662{0x97, 0xaa, 0xaa, 0, 0},663{0x98, 0, 0, 0, 0},664{0x99, 0x23, 0x23, 0, 0},665{0x9A, 0x7, 0x7, 0, 0},666{0x9B, 0xf, 0xf, 0, 0},667{0x9C, 0x10, 0x10, 0, 0},668{0x9D, 0x3, 0x3, 0, 0},669{0x9E, 0x4, 0x4, 0, 0},670{0x9F, 0x20, 0x20, 0, 0},671{0xA0, 0, 0, 0, 0},672{0xA1, 0, 0, 0, 0},673{0xA2, 0, 0, 0, 0},674{0xA3, 0, 0, 0, 0},675{0xA4, 0x1, 0x1, 0, 0},676{0xA5, 0x77, 0x77, 0, 0},677{0xA6, 0x77, 0x77, 0, 0},678{0xA7, 0x77, 0x77, 0, 0},679{0xA8, 0x77, 0x77, 0, 0},680{0xA9, 0x8c, 0x8c, 0, 0},681{0xAA, 0x88, 0x88, 0, 0},682{0xAB, 0x78, 0x78, 0, 0},683{0xAC, 0x57, 0x57, 0, 0},684{0xAD, 0x88, 0x88, 0, 0},685{0xAE, 0, 0, 0, 0},686{0xAF, 0x8, 0x8, 0, 0},687{0xB0, 0x88, 0x88, 0, 0},688{0xB1, 0, 0, 0, 0},689{0xB2, 0x1b, 0x1b, 0, 0},690{0xB3, 0x3, 0x3, 0, 0},691{0xB4, 0x24, 0x24, 0, 0},692{0xB5, 0x3, 0x3, 0, 0},693{0xB6, 0x1b, 0x1b, 0, 0},694{0xB7, 0x24, 0x24, 0, 0},695{0xB8, 0x3, 0x3, 0, 0},696{0xB9, 0, 0, 0, 0},697{0xBA, 0xaa, 0xaa, 0, 0},698{0xBB, 0, 0, 0, 0},699{0xBC, 0x4, 0x4, 0, 0},700{0xBD, 0, 0, 0, 0},701{0xBE, 0x8, 0x8, 0, 0},702{0xBF, 0x11, 0x11, 0, 0},703{0xC0, 0, 0, 0, 0},704{0xC1, 0, 0, 0, 0},705{0xC2, 0x62, 0x62, 0, 0},706{0xC3, 0x1e, 0x1e, 0, 0},707{0xC4, 0x33, 0x33, 0, 0},708{0xC5, 0x37, 0x37, 0, 0},709{0xC6, 0, 0, 0, 0},710{0xC7, 0x70, 0x70, 0, 0},711{0xC8, 0x1e, 0x1e, 0, 0},712{0xC9, 0x6, 0x6, 0, 0},713{0xCA, 0x4, 0x4, 0, 0},714{0xCB, 0x2f, 0x2f, 0, 0},715{0xCC, 0xf, 0xf, 0, 0},716{0xCD, 0, 0, 0, 0},717{0xCE, 0xff, 0xff, 0, 0},718{0xCF, 0x8, 0x8, 0, 0},719{0xD0, 0x3f, 0x3f, 0, 0},720{0xD1, 0x3f, 0x3f, 0, 0},721{0xD2, 0x3f, 0x3f, 0, 0},722{0xD3, 0, 0, 0, 0},723{0xD4, 0, 0, 0, 0},724{0xD5, 0, 0, 0, 0},725{0xD6, 0xcc, 0xcc, 0, 0},726{0xD7, 0, 0, 0, 0},727{0xD8, 0x8, 0x8, 0, 0},728{0xD9, 0x8, 0x8, 0, 0},729{0xDA, 0x8, 0x8, 0, 0},730{0xDB, 0x11, 0x11, 0, 0},731{0xDC, 0, 0, 0, 0},732{0xDD, 0x87, 0x87, 0, 0},733{0xDE, 0x88, 0x88, 0, 0},734{0xDF, 0x8, 0x8, 0, 0},735{0xE0, 0x8, 0x8, 0, 0},736{0xE1, 0x8, 0x8, 0, 0},737{0xE2, 0, 0, 0, 0},738{0xE3, 0, 0, 0, 0},739{0xE4, 0, 0, 0, 0},740{0xE5, 0xf5, 0xf5, 0, 0},741{0xE6, 0x30, 0x30, 0, 0},742{0xE7, 0x1, 0x1, 0, 0},743{0xE8, 0, 0, 0, 0},744{0xE9, 0xff, 0xff, 0, 0},745{0xEA, 0, 0, 0, 0},746{0xEB, 0, 0, 0, 0},747{0xEC, 0x22, 0x22, 0, 0},748{0xED, 0, 0, 0, 0},749{0xEE, 0, 0, 0, 0},750{0xEF, 0, 0, 0, 0},751{0xF0, 0x3, 0x3, 0, 0},752{0xF1, 0x1, 0x1, 0, 0},753{0xF2, 0, 0, 0, 0},754{0xF3, 0, 0, 0, 0},755{0xF4, 0, 0, 0, 0},756{0xF5, 0, 0, 0, 0},757{0xF6, 0, 0, 0, 0},758{0xF7, 0x6, 0x6, 0, 0},759{0xF8, 0, 0, 0, 0},760{0xF9, 0, 0, 0, 0},761{0xFA, 0x40, 0x40, 0, 0},762{0xFB, 0, 0, 0, 0},763{0xFC, 0x1, 0x1, 0, 0},764{0xFD, 0x80, 0x80, 0, 0},765{0xFE, 0x2, 0x2, 0, 0},766{0xFF, 0x10, 0x10, 0, 0},767{0x100, 0x2, 0x2, 0, 0},768{0x101, 0x1e, 0x1e, 0, 0},769{0x102, 0x1e, 0x1e, 0, 0},770{0x103, 0, 0, 0, 0},771{0x104, 0x1f, 0x1f, 0, 0},772{0x105, 0, 0x8, 0, 1},773{0x106, 0x2a, 0x2a, 0, 0},774{0x107, 0xf, 0xf, 0, 0},775{0x108, 0, 0, 0, 0},776{0x109, 0, 0, 0, 0},777{0x10A, 0, 0, 0, 0},778{0x10B, 0, 0, 0, 0},779{0x10C, 0, 0, 0, 0},780{0x10D, 0, 0, 0, 0},781{0x10E, 0, 0, 0, 0},782{0x10F, 0, 0, 0, 0},783{0x110, 0, 0, 0, 0},784{0x111, 0, 0, 0, 0},785{0x112, 0, 0, 0, 0},786{0x113, 0, 0, 0, 0},787{0x114, 0, 0, 0, 0},788{0x115, 0, 0, 0, 0},789{0x116, 0, 0, 0, 0},790{0x117, 0, 0, 0, 0},791{0x118, 0, 0, 0, 0},792{0x119, 0, 0, 0, 0},793{0x11A, 0, 0, 0, 0},794{0x11B, 0, 0, 0, 0},795{0x11C, 0x1, 0x1, 0, 0},796{0x11D, 0, 0, 0, 0},797{0x11E, 0, 0, 0, 0},798{0x11F, 0, 0, 0, 0},799{0x120, 0, 0, 0, 0},800{0x121, 0, 0, 0, 0},801{0x122, 0x80, 0x80, 0, 0},802{0x123, 0, 0, 0, 0},803{0x124, 0xf8, 0xf8, 0, 0},804{0x125, 0, 0, 0, 0},805{0x126, 0, 0, 0, 0},806{0x127, 0, 0, 0, 0},807{0x128, 0, 0, 0, 0},808{0x129, 0, 0, 0, 0},809{0x12A, 0, 0, 0, 0},810{0x12B, 0, 0, 0, 0},811{0x12C, 0, 0, 0, 0},812{0x12D, 0, 0, 0, 0},813{0x12E, 0, 0, 0, 0},814{0x12F, 0, 0, 0, 0},815{0x130, 0, 0, 0, 0},816{0xFFFF, 0, 0, 0, 0}817};818819#define LCNPHY_NUM_DIG_FILT_COEFFS 16820#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13821822static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]823[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {824{0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,825128, 64,},826{1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,827167, 93,},828{2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,829128, 64,},830{3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,831170, 340, 170,},832{20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,833256, 185, 256,},834{21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,835256, 273, 256,},836{22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,837256, 352, 256,},838{23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,839128, 233, 128,},840{24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,8411881, 256,},842{25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,8431881, 256,},844{26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,845384, 288,},846{27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,847128, 384, 288,},848{30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,849170, 340, 170,},850};851852#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3853static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]854[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {855{0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,8560x278, 0xfea0, 0x80, 0x100, 0x80,},857{1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,858750, 0xFE2B, 212, 0xFFCE, 212,},859{2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,8600xFEF2, 128, 0xFFE2, 128}861};862863#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \864mod_phy_reg(pi, 0x4a4, \865(0x1ff << 0), \866(u16)(idx) << 0)867868#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \869mod_phy_reg(pi, 0x4a5, \870(0x7 << 8), \871(u16)(npt) << 8)872873#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \874(read_phy_reg((pi), 0x4a4) & \875((0x1 << 15) | \876(0x1 << 14) | \877(0x1 << 13)))878879#define wlc_lcnphy_get_tx_pwr_npt(pi) \880((read_phy_reg(pi, 0x4a5) & \881(0x7 << 8)) >> \8828)883884#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \885(read_phy_reg(pi, 0x473) & 0x1ff)886887#define wlc_lcnphy_get_target_tx_pwr(pi) \888((read_phy_reg(pi, 0x4a7) & \889(0xff << 0)) >> \8900)891892#define wlc_lcnphy_set_target_tx_pwr(pi, target) \893mod_phy_reg(pi, 0x4a7, \894(0xff << 0), \895(u16)(target) << 0)896897#define wlc_radio_2064_rcal_done(pi) \898(0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))899900#define tempsense_done(pi) \901(0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))902903#define LCNPHY_IQLOCC_READ(val) \904((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))905906#define FIXED_TXPWR 78907#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))908909void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)910{911wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);912}913914void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)915{916wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);917}918919static void920wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,921u16 *tbl_ptr, u32 tbl_len,922u32 tbl_width, u32 tbl_offset)923{924struct phytbl_info tab;925tab.tbl_id = tbl_id;926tab.tbl_ptr = tbl_ptr;927tab.tbl_len = tbl_len;928tab.tbl_width = tbl_width;929tab.tbl_offset = tbl_offset;930wlc_lcnphy_read_table(pi, &tab);931}932933static void934wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,935const u16 *tbl_ptr, u32 tbl_len,936u32 tbl_width, u32 tbl_offset)937{938939struct phytbl_info tab;940tab.tbl_id = tbl_id;941tab.tbl_ptr = tbl_ptr;942tab.tbl_len = tbl_len;943tab.tbl_width = tbl_width;944tab.tbl_offset = tbl_offset;945wlc_lcnphy_write_table(pi, &tab);946}947948static u32949wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)950{951u32 quotient, remainder, roundup, rbit;952953quotient = dividend / divisor;954remainder = dividend % divisor;955rbit = divisor & 1;956roundup = (divisor >> 1) + rbit;957958while (precision--) {959quotient <<= 1;960if (remainder >= roundup) {961quotient++;962remainder = ((remainder - roundup) << 1) + rbit;963} else {964remainder <<= 1;965}966}967968if (remainder >= roundup)969quotient++;970971return quotient;972}973974static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)975{976int k;977k = 0;978if (type == 0) {979if (coeff_x < 0)980k = (coeff_x - 1) / 2;981else982k = coeff_x / 2;983}984985if (type == 1) {986if ((coeff_x + 1) < 0)987k = (coeff_x) / 2;988else989k = (coeff_x + 1) / 2;990}991return k;992}993994static void995wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)996{997u16 dac_gain, rfgain0, rfgain1;998999dac_gain = read_phy_reg(pi, 0x439) >> 0;1000gains->dac_gain = (dac_gain & 0x380) >> 7;10011002rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;1003rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;10041005gains->gm_gain = rfgain0 & 0xff;1006gains->pga_gain = (rfgain0 >> 8) & 0xff;1007gains->pad_gain = rfgain1 & 0xff;1008}100910101011static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)1012{1013u16 dac_ctrl;10141015dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);1016dac_ctrl = dac_ctrl & 0xc7f;1017dac_ctrl = dac_ctrl | (dac_gain << 7);1018mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);10191020}10211022static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)1023{1024u16 bit = bEnable ? 1 : 0;10251026mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);10271028mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);10291030mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);1031}10321033static void1034wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)1035{1036u16 ebit = enable ? 1 : 0;10371038mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);10391040mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);10411042if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {1043mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);1044mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);1045mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);1046mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);1047} else {1048mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);1049mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);1050mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);1051}10521053if (CHSPEC_IS2G(pi->radio_chanspec)) {1054mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);1055mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);1056}1057}10581059static void1060wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,1061u16 trsw,1062u16 ext_lna,1063u16 biq2,1064u16 biq1,1065u16 tia, u16 lna2, u16 lna1)1066{1067u16 gain0_15, gain16_19;10681069gain16_19 = biq2 & 0xf;1070gain0_15 = ((biq1 & 0xf) << 12) |1071((tia & 0xf) << 8) |1072((lna2 & 0x3) << 6) |1073((lna2 & 0x3) << 4) |1074((lna1 & 0x3) << 2) |1075((lna1 & 0x3) << 0);10761077mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);1078mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);1079mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);10801081if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {1082mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);1083mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);1084} else {1085mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);10861087mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);10881089mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);1090}10911092mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);10931094}10951096static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)1097{10981099mod_phy_reg(pi, 0x44d,1100(0x1 << 1) |1101(0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));11021103or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));1104}11051106static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)1107{11081109and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));1110}11111112static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)1113{1114mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);11151116mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);11171118mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);11191120mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);11211122mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);11231124mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);11251126}11271128static bool1129wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,1130u16 num_samps,1131u8 wait_time, struct lcnphy_iq_est *iq_est)1132{1133int wait_count = 0;1134bool result = true;11351136mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);11371138mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);11391140mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);11411142mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);11431144mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);11451146mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);11471148while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {11491150if (wait_count > (10 * 500)) {1151result = false;1152goto cleanup;1153}1154udelay(100);1155wait_count++;1156}11571158iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |1159(u32) read_phy_reg(pi, 0x484);1160iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |1161(u32) read_phy_reg(pi, 0x486);1162iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |1163(u32) read_phy_reg(pi, 0x488);11641165cleanup:1166mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);11671168mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);11691170return result;1171}11721173static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)1174{1175#define LCNPHY_MIN_RXIQ_PWR 21176bool result;1177u16 a0_new, b0_new;1178struct lcnphy_iq_est iq_est = { 0, 0, 0 };1179s32 a, b, temp;1180s16 iq_nbits, qq_nbits, arsh, brsh;1181s32 iq;1182u32 ii, qq;1183struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;11841185a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);1186b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);1187mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);11881189mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);11901191wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);11921193result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);1194if (!result)1195goto cleanup;11961197iq = (s32) iq_est.iq_prod;1198ii = iq_est.i_pwr;1199qq = iq_est.q_pwr;12001201if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {1202result = false;1203goto cleanup;1204}12051206iq_nbits = wlc_phy_nbits(iq);1207qq_nbits = wlc_phy_nbits(qq);12081209arsh = 10 - (30 - iq_nbits);1210if (arsh >= 0) {1211a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));1212temp = (s32) (ii >> arsh);1213if (temp == 0)1214return false;1215} else {1216a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));1217temp = (s32) (ii << -arsh);1218if (temp == 0)1219return false;1220}1221a /= temp;1222brsh = qq_nbits - 31 + 20;1223if (brsh >= 0) {1224b = (qq << (31 - qq_nbits));1225temp = (s32) (ii >> brsh);1226if (temp == 0)1227return false;1228} else {1229b = (qq << (31 - qq_nbits));1230temp = (s32) (ii << -brsh);1231if (temp == 0)1232return false;1233}1234b /= temp;1235b -= a * a;1236b = (s32) int_sqrt((unsigned long) b);1237b -= (1 << 10);1238a0_new = (u16) (a & 0x3ff);1239b0_new = (u16) (b & 0x3ff);1240cleanup:12411242wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);12431244mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);12451246mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);12471248pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;1249pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;12501251return result;1252}12531254static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)1255{1256struct lcnphy_iq_est iq_est = { 0, 0, 0 };12571258if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))1259return 0;1260return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;1261}12621263static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,1264u16 tia_gain, u16 lna2_gain)1265{1266u32 i_thresh_l, q_thresh_l;1267u32 i_thresh_h, q_thresh_h;1268struct lcnphy_iq_est iq_est_h, iq_est_l;12691270wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,1271lna2_gain, 0);12721273wlc_lcnphy_rx_gain_override_enable(pi, true);1274wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);1275udelay(500);1276write_radio_reg(pi, RADIO_2064_REG112, 0);1277if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))1278return false;12791280wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);1281udelay(500);1282write_radio_reg(pi, RADIO_2064_REG112, 0);1283if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))1284return false;12851286i_thresh_l = (iq_est_l.i_pwr << 1);1287i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;12881289q_thresh_l = (iq_est_l.q_pwr << 1);1290q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;1291if ((iq_est_h.i_pwr > i_thresh_l) &&1292(iq_est_h.i_pwr < i_thresh_h) &&1293(iq_est_h.q_pwr > q_thresh_l) &&1294(iq_est_h.q_pwr < q_thresh_h))1295return true;12961297return false;1298}12991300static bool1301wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,1302const struct lcnphy_rx_iqcomp *iqcomp,1303int iqcomp_sz, bool tx_switch, bool rx_switch, int module,1304int tx_gain_idx)1305{1306struct lcnphy_txgains old_gains;1307u16 tx_pwr_ctrl;1308u8 tx_gain_index_old = 0;1309bool result = false, tx_gain_override_old = false;1310u16 i, Core1TxControl_old,1311RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,1312rfoverride3_old, rfoverride3val_old, rfoverride4_old,1313rfoverride4val_old, afectrlovr_old, afectrlovrval_old;1314int tia_gain, lna2_gain, biq1_gain;1315bool set_gain;1316u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;1317u16 values_to_save[11];1318s16 *ptr;1319struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;13201321ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);1322if (NULL == ptr)1323return false;1324if (module == 2) {1325while (iqcomp_sz--) {1326if (iqcomp[iqcomp_sz].chan ==1327CHSPEC_CHANNEL(pi->radio_chanspec)) {1328wlc_lcnphy_set_rx_iq_comp(pi,1329(u16)1330iqcomp[iqcomp_sz].a,1331(u16)1332iqcomp[iqcomp_sz].b);1333result = true;1334break;1335}1336}1337goto cal_done;1338}13391340WARN_ON(module != 1);1341tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);1342wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);13431344for (i = 0; i < 11; i++)1345values_to_save[i] =1346read_radio_reg(pi, rxiq_cal_rf_reg[i]);1347Core1TxControl_old = read_phy_reg(pi, 0x631);13481349or_phy_reg(pi, 0x631, 0x0015);13501351read_phy_reg(pi, 0x44c); /* RFOverride0_old */1352RFOverrideVal0_old = read_phy_reg(pi, 0x44d);1353rfoverride2_old = read_phy_reg(pi, 0x4b0);1354rfoverride2val_old = read_phy_reg(pi, 0x4b1);1355rfoverride3_old = read_phy_reg(pi, 0x4f9);1356rfoverride3val_old = read_phy_reg(pi, 0x4fa);1357rfoverride4_old = read_phy_reg(pi, 0x938);1358rfoverride4val_old = read_phy_reg(pi, 0x939);1359afectrlovr_old = read_phy_reg(pi, 0x43b);1360afectrlovrval_old = read_phy_reg(pi, 0x43c);1361old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);1362old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);13631364tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);1365if (tx_gain_override_old) {1366wlc_lcnphy_get_tx_gain(pi, &old_gains);1367tx_gain_index_old = pi_lcn->lcnphy_current_index;1368}13691370wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);13711372mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);1373mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);13741375mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);1376mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);13771378write_radio_reg(pi, RADIO_2064_REG116, 0x06);1379write_radio_reg(pi, RADIO_2064_REG12C, 0x07);1380write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);1381write_radio_reg(pi, RADIO_2064_REG098, 0x03);1382write_radio_reg(pi, RADIO_2064_REG00B, 0x7);1383mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);1384write_radio_reg(pi, RADIO_2064_REG01D, 0x01);1385write_radio_reg(pi, RADIO_2064_REG114, 0x01);1386write_radio_reg(pi, RADIO_2064_REG02E, 0x10);1387write_radio_reg(pi, RADIO_2064_REG12A, 0x08);13881389mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);1390mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);1391mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);1392mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);1393mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);1394mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);1395mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);1396mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);1397mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);1398mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);13991400mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);1401mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);14021403write_phy_reg(pi, 0x6da, 0xffff);1404or_phy_reg(pi, 0x6db, 0x3);14051406wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);1407for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {1408for (tia_gain = 4; tia_gain >= 0; tia_gain--) {1409for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {1410set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,1411(u16)1412biq1_gain,1413(u16)1414tia_gain,1415(u16)1416lna2_gain);1417if (!set_gain)1418continue;14191420result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);1421goto stop_tone;1422}1423}1424}14251426stop_tone:1427wlc_lcnphy_stop_tx_tone(pi);14281429write_phy_reg(pi, 0x631, Core1TxControl_old);14301431write_phy_reg(pi, 0x44c, RFOverrideVal0_old);1432write_phy_reg(pi, 0x44d, RFOverrideVal0_old);1433write_phy_reg(pi, 0x4b0, rfoverride2_old);1434write_phy_reg(pi, 0x4b1, rfoverride2val_old);1435write_phy_reg(pi, 0x4f9, rfoverride3_old);1436write_phy_reg(pi, 0x4fa, rfoverride3val_old);1437write_phy_reg(pi, 0x938, rfoverride4_old);1438write_phy_reg(pi, 0x939, rfoverride4val_old);1439write_phy_reg(pi, 0x43b, afectrlovr_old);1440write_phy_reg(pi, 0x43c, afectrlovrval_old);1441write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);1442write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);14431444wlc_lcnphy_clear_trsw_override(pi);14451446mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);14471448for (i = 0; i < 11; i++)1449write_radio_reg(pi, rxiq_cal_rf_reg[i],1450values_to_save[i]);14511452if (tx_gain_override_old)1453wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);1454else1455wlc_lcnphy_disable_tx_gain_override(pi);14561457wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);1458wlc_lcnphy_rx_gain_override_enable(pi, false);14591460cal_done:1461kfree(ptr);1462return result;1463}14641465s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)1466{1467s8 index;1468struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;14691470if (txpwrctrl_off(pi))1471index = pi_lcn->lcnphy_current_index;1472else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))1473index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(1474pi) / 2);1475else1476index = pi_lcn->lcnphy_current_index;1477return index;1478}14791480void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)1481{1482u16 afectrlovr, afectrlovrval;1483afectrlovr = read_phy_reg(pi, 0x43b);1484afectrlovrval = read_phy_reg(pi, 0x43c);1485if (channel != 0) {1486mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);14871488mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);14891490mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);14911492mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);14931494write_phy_reg(pi, 0x44b, 0xffff);1495wlc_lcnphy_tx_pu(pi, 1);14961497mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);14981499or_phy_reg(pi, 0x6da, 0x0080);15001501or_phy_reg(pi, 0x00a, 0x228);1502} else {1503and_phy_reg(pi, 0x00a, ~(0x228));15041505and_phy_reg(pi, 0x6da, 0xFF7F);1506write_phy_reg(pi, 0x43b, afectrlovr);1507write_phy_reg(pi, 0x43c, afectrlovrval);1508}1509}15101511static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)1512{1513u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;15141515save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);1516save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);15171518write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);1519write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);15201521write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);1522write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);15231524write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);1525write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);1526}15271528static void1529wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)1530{1531if (enable) {1532write_phy_reg(pi, 0x942, 0x7);1533write_phy_reg(pi, 0x93b, ((1 << 13) + 23));1534write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));15351536write_phy_reg(pi, 0x44a, 0x084);1537write_phy_reg(pi, 0x44a, 0x080);1538write_phy_reg(pi, 0x6d3, 0x2222);1539write_phy_reg(pi, 0x6d3, 0x2220);1540} else {1541write_phy_reg(pi, 0x942, 0x0);1542write_phy_reg(pi, 0x93b, ((0 << 13) + 23));1543write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));1544}1545wlapi_switch_macfreq(pi->sh->physhim, enable);1546}15471548static void1549wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)1550{1551u8 channel = CHSPEC_CHANNEL(chanspec);1552struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;15531554if (channel == 14)1555mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);1556else1557mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);15581559pi_lcn->lcnphy_bandedge_corr = 2;1560if (channel == 1)1561pi_lcn->lcnphy_bandedge_corr = 4;15621563if (channel == 1 || channel == 2 || channel == 3 ||1564channel == 4 || channel == 9 ||1565channel == 10 || channel == 11 || channel == 12) {1566bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,15670x03000c04);1568bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,1569~0x00ffffff, 0x0);1570bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,15710x200005c0);15721573bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,1574BCMA_CC_PMU_CTL_PLL_UPD);1575write_phy_reg(pi, 0x942, 0);1576wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);1577pi_lcn->lcnphy_spurmod = false;1578mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);15791580write_phy_reg(pi, 0x425, 0x5907);1581} else {1582bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,15830x03140c04);1584bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,1585~0x00ffffff, 0x333333);1586bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,15870x202c2820);15881589bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,1590BCMA_CC_PMU_CTL_PLL_UPD);1591write_phy_reg(pi, 0x942, 0);1592wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);15931594pi_lcn->lcnphy_spurmod = false;1595mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);15961597write_phy_reg(pi, 0x425, 0x590a);1598}15991600or_phy_reg(pi, 0x44a, 0x44);1601write_phy_reg(pi, 0x44a, 0x80);1602}16031604static void1605wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)1606{1607uint i;1608const struct chan_info_2064_lcnphy *ci;1609u8 rfpll_doubler = 0;1610u8 pll_pwrup, pll_pwrup_ovr;1611s32 qFcal;1612u8 d15, d16, f16, e44, e45;1613u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;1614u16 loop_bw, d30, setCount;16151616u8 h29, h28_ten, e30, h30_ten, cp_current;1617u16 g30, d28;16181619ci = &chan_info_2064_lcnphy[0];1620rfpll_doubler = 1;16211622mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);16231624write_radio_reg(pi, RADIO_2064_REG09E, 0xf);1625if (!rfpll_doubler) {1626loop_bw = PLL_2064_LOOP_BW;1627d30 = PLL_2064_D30;1628} else {1629loop_bw = PLL_2064_LOOP_BW_DOUBLER;1630d30 = PLL_2064_D30_DOUBLER;1631}16321633if (CHSPEC_IS2G(pi->radio_chanspec)) {1634for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)1635if (chan_info_2064_lcnphy[i].chan == channel)1636break;16371638if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))1639return;16401641ci = &chan_info_2064_lcnphy[i];1642}16431644write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);16451646mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);16471648mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);16491650mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);16511652mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,1653(ci->logen_rccr_rx) << 2);16541655mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);16561657mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,1658(ci->pa_rxrf_lna2_freq_tune) << 4);16591660write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);16611662pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);1663pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);16641665or_radio_reg(pi, RADIO_2064_REG044, 0x07);16661667or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);1668e44 = 0;1669e45 = 0;16701671fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);1672if (pi->xtalfreq > 26000000)1673e44 = 1;1674if (pi->xtalfreq > 52000000)1675e45 = 1;1676if (e44 == 0)1677fcal_div = 1;1678else if (e45 == 0)1679fcal_div = 2;1680else1681fcal_div = 4;1682fvco3 = (ci->freq * 3);1683fref3 = 2 * fpfd;16841685qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;16861687write_radio_reg(pi, RADIO_2064_REG04F, 0x02);16881689d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;1690write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));1691write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);16921693d16 = (qFcal * 8 / (d15 + 1)) - 1;1694write_radio_reg(pi, RADIO_2064_REG051, d16);16951696f16 = ((d16 + 1) * (d15 + 1)) / qFcal;1697setCount = f16 * 3 * (ci->freq) / 32 - 1;1698mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),1699(u8) (setCount >> 8));17001701or_radio_reg(pi, RADIO_2064_REG053, 0x10);1702write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));17031704div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;17051706div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;1707while (div_frac >= fref3) {1708div_int++;1709div_frac -= fref3;1710}1711div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);17121713mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),1714(u8) (div_int >> 4));1715mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),1716(u8) (div_int << 4));1717mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),1718(u8) (div_frac >> 16));1719write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);1720write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);17211722write_radio_reg(pi, RADIO_2064_REG040, 0xfb);17231724write_radio_reg(pi, RADIO_2064_REG041, 0x9A);1725write_radio_reg(pi, RADIO_2064_REG042, 0xA3);1726write_radio_reg(pi, RADIO_2064_REG043, 0x0C);17271728h29 = LCN_BW_LMT / loop_bw;1729d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *1730(fvco3 / 2 - PLL_2064_LOW_END_VCO)) /1731(PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))1732+ PLL_2064_LOW_END_KVCO;1733h28_ten = (d28 * 10) / LCN_VCO_DIV;1734e30 = (d30 - LCN_OFFSET) / LCN_FACT;1735g30 = LCN_OFFSET + (e30 * LCN_FACT);1736h30_ten = (g30 * 10) / LCN_CUR_DIV;1737cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;1738mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);17391740if (channel >= 1 && channel <= 5)1741write_radio_reg(pi, RADIO_2064_REG03C, 0x8);1742else1743write_radio_reg(pi, RADIO_2064_REG03C, 0x7);1744write_radio_reg(pi, RADIO_2064_REG03D, 0x3);17451746mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);1747udelay(1);17481749wlc_2064_vco_cal(pi);17501751write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);1752write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);1753if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {1754write_radio_reg(pi, RADIO_2064_REG038, 3);1755write_radio_reg(pi, RADIO_2064_REG091, 7);1756}17571758if (!(pi->sh->boardflags & BFL_FEM)) {1759static const u8 reg038[14] = {17600xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa,17610xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x01762};17631764write_radio_reg(pi, RADIO_2064_REG02A, 0xf);1765write_radio_reg(pi, RADIO_2064_REG091, 0x3);1766write_radio_reg(pi, RADIO_2064_REG038, 0x3);17671768write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);1769}1770}17711772static int1773wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)1774{1775s16 filt_index = -1;1776int j;17771778u16 addr[] = {17790x910,17800x91e,17810x91f,17820x924,17830x925,17840x926,17850x920,17860x921,17870x927,17880x928,17890x929,17900x922,17910x923,17920x930,17930x931,17940x9321795};17961797u16 addr_ofdm[] = {17980x90f,17990x900,18000x901,18010x906,18020x907,18030x908,18040x902,18050x903,18060x909,18070x90a,18080x90b,18090x904,18100x905,18110x90c,18120x90d,18130x90e1814};18151816if (!is_ofdm) {1817for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {1818if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {1819filt_index = (s16) j;1820break;1821}1822}18231824if (filt_index != -1) {1825for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)1826write_phy_reg(pi, addr[j],1827LCNPHY_txdigfiltcoeffs_cck1828[filt_index][j + 1]);1829}1830} else {1831for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {1832if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {1833filt_index = (s16) j;1834break;1835}1836}18371838if (filt_index != -1) {1839for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)1840write_phy_reg(pi, addr_ofdm[j],1841LCNPHY_txdigfiltcoeffs_ofdm1842[filt_index][j + 1]);1843}1844}18451846return (filt_index != -1) ? 0 : -1;1847}18481849static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)1850{1851u16 pa_gain;18521853pa_gain = (read_phy_reg(pi, 0x4fb) &1854LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>1855LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;18561857return pa_gain;1858}18591860static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,1861struct lcnphy_txgains *target_gains)1862{1863u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);18641865mod_phy_reg(1866pi, 0x4b5,1867(0xffff << 0),1868((target_gains->gm_gain) |1869(target_gains->pga_gain << 8)) <<18700);1871mod_phy_reg(pi, 0x4fb,1872(0x7fff << 0),1873((target_gains->pad_gain) | (pa_gain << 8)) << 0);18741875mod_phy_reg(1876pi, 0x4fc,1877(0xffff << 0),1878((target_gains->gm_gain) |1879(target_gains->pga_gain << 8)) <<18800);1881mod_phy_reg(pi, 0x4fd,1882(0x7fff << 0),1883((target_gains->pad_gain) | (pa_gain << 8)) << 0);18841885wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);18861887wlc_lcnphy_enable_tx_gain_override(pi);1888}18891890static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)1891{1892u16 m0m1;1893struct phytbl_info tab;18941895tab.tbl_ptr = &m0m1;1896tab.tbl_len = 1;1897tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;1898tab.tbl_offset = 87;1899tab.tbl_width = 16;1900wlc_lcnphy_read_table(pi, &tab);19011902return (u8) ((m0m1 & 0xff00) >> 8);1903}19041905static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)1906{1907u16 m0m1 = (u16) m0 << 8;1908struct phytbl_info tab;19091910tab.tbl_ptr = &m0m1;1911tab.tbl_len = 1;1912tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;1913tab.tbl_offset = 87;1914tab.tbl_width = 16;1915wlc_lcnphy_write_table(pi, &tab);1916}19171918static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)1919{1920u32 data_buf[64];1921struct phytbl_info tab;19221923memset(data_buf, 0, sizeof(data_buf));19241925tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;1926tab.tbl_width = 32;1927tab.tbl_ptr = data_buf;19281929if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {19301931tab.tbl_len = 30;1932tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;1933wlc_lcnphy_write_table(pi, &tab);1934}19351936tab.tbl_len = 64;1937tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;1938wlc_lcnphy_write_table(pi, &tab);1939}19401941enum lcnphy_tssi_mode {1942LCNPHY_TSSI_PRE_PA,1943LCNPHY_TSSI_POST_PA,1944LCNPHY_TSSI_EXT1945};19461947static void1948wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)1949{1950mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);19511952mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);19531954if (LCNPHY_TSSI_POST_PA == pos) {1955mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);19561957mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);19581959if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {1960mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);1961} else {1962mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);1963mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);1964mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);1965mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);1966mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);1967mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);1968mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);1969mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);1970mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);1971mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);1972mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);1973mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);1974}1975} else {1976mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);19771978mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);19791980if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {1981mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);1982} else {1983mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);1984mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);1985}1986}1987mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);19881989if (LCNPHY_TSSI_EXT == pos) {1990write_radio_reg(pi, RADIO_2064_REG07F, 1);1991mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);1992mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);1993mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);1994}1995}19961997static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)1998{1999u16 N1, N2, N3, N4, N5, N6, N;2000N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))2001>> 0);2002N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))2003>> 12);2004N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))2005>> 0);2006N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))2007>> 8);2008N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))2009>> 0);2010N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))2011>> 8);2012N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;2013if (N < 1600)2014N = 1600;2015return N;2016}20172018static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)2019{2020u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;2021struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;20222023auxpga_vmid = (2 << 8) |2024(pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;2025auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;2026auxpga_gain_temp = 2;20272028mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);20292030mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);20312032mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);20332034mod_phy_reg(pi, 0x4db,2035(0x3ff << 0) |2036(0x7 << 12),2037(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));20382039mod_phy_reg(pi, 0x4dc,2040(0x3ff << 0) |2041(0x7 << 12),2042(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));20432044mod_phy_reg(pi, 0x40a,2045(0x3ff << 0) |2046(0x7 << 12),2047(auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));20482049mod_phy_reg(pi, 0x40b,2050(0x3ff << 0) |2051(0x7 << 12),2052(auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));20532054mod_phy_reg(pi, 0x40c,2055(0x3ff << 0) |2056(0x7 << 12),2057(auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));20582059mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));2060mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));2061}20622063static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)2064{2065struct phytbl_info tab;2066u32 rfseq, ind;2067enum lcnphy_tssi_mode mode;2068u8 tssi_sel;20692070if (pi->sh->boardflags & BFL_FEM) {2071tssi_sel = 0x1;2072mode = LCNPHY_TSSI_EXT;2073} else {2074tssi_sel = 0xe;2075mode = LCNPHY_TSSI_POST_PA;2076}2077tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;2078tab.tbl_width = 32;2079tab.tbl_ptr = &ind;2080tab.tbl_len = 1;2081tab.tbl_offset = 0;2082for (ind = 0; ind < 128; ind++) {2083wlc_lcnphy_write_table(pi, &tab);2084tab.tbl_offset++;2085}2086tab.tbl_offset = 704;2087for (ind = 0; ind < 128; ind++) {2088wlc_lcnphy_write_table(pi, &tab);2089tab.tbl_offset++;2090}2091mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);20922093mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);20942095mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);20962097wlc_lcnphy_set_tssi_mux(pi, mode);2098mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);20992100mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);21012102mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);21032104mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);21052106mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);21072108mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);21092110mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);21112112mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);21132114mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);21152116mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);21172118mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);21192120mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);21212122mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);21232124wlc_lcnphy_clear_tx_power_offsets(pi);21252126mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);21272128mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);21292130mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);21312132if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {2133mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);2134mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);2135} else {2136mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);2137mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);2138mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);2139}21402141write_radio_reg(pi, RADIO_2064_REG025, 0xc);21422143if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {2144mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);2145} else {2146if (CHSPEC_IS2G(pi->radio_chanspec))2147mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);2148else2149mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);2150}21512152if (LCNREV_IS(pi->pubpi.phy_rev, 2))2153mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);2154else2155mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);21562157mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);21582159mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);21602161if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))2162mod_phy_reg(pi, 0x4d7,2163(0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);21642165rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);2166tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;2167tab.tbl_width = 16;2168tab.tbl_ptr = &rfseq;2169tab.tbl_len = 1;2170tab.tbl_offset = 6;2171wlc_lcnphy_write_table(pi, &tab);21722173mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);21742175mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);21762177mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);21782179mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);21802181mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);21822183mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);2184mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);2185mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);21862187wlc_lcnphy_pwrctrl_rssiparams(pi);2188}21892190void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)2191{2192u16 tx_cnt, tx_total, npt;2193struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;21942195tx_total = wlc_lcnphy_total_tx_frames(pi);2196tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;2197npt = wlc_lcnphy_get_tx_pwr_npt(pi);21982199if (tx_cnt > (1 << npt)) {22002201pi_lcn->lcnphy_tssi_tx_cnt = tx_total;22022203pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);2204pi_lcn->lcnphy_tssi_npt = npt;22052206}2207}22082209s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)2210{2211s32 a, b, p;22122213a = 32768 + (a1 * tssi);2214b = (1024 * b0) + (64 * b1 * tssi);2215p = ((2 * b) + a) / (2 * a);22162217return p;2218}22192220static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)2221{2222struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;2223if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))2224return;22252226pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;2227pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;2228}22292230void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)2231{2232struct phytbl_info tab;2233u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +2234BRCMS_NUM_RATES_MCS_1_STREAM];2235uint i, j;2236if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))2237return;22382239for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {22402241if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)2242j = TXP_FIRST_MCS_20_SISO;22432244rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));2245}22462247tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;2248tab.tbl_width = 32;2249tab.tbl_len = ARRAY_SIZE(rate_table);2250tab.tbl_ptr = rate_table;2251tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;2252wlc_lcnphy_write_table(pi, &tab);22532254if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {2255wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);22562257wlc_lcnphy_txpower_reset_npt(pi);2258}2259}22602261static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)2262{2263u32 cck_offset[4] = { 22, 22, 22, 22 };2264u32 ofdm_offset, reg_offset_cck;2265int i;2266u16 index2;2267struct phytbl_info tab;22682269if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))2270return;22712272mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);22732274mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);22752276or_phy_reg(pi, 0x6da, 0x0040);22772278reg_offset_cck = 0;2279for (i = 0; i < 4; i++)2280cck_offset[i] -= reg_offset_cck;2281tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;2282tab.tbl_width = 32;2283tab.tbl_len = 4;2284tab.tbl_ptr = cck_offset;2285tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;2286wlc_lcnphy_write_table(pi, &tab);2287ofdm_offset = 0;2288tab.tbl_len = 1;2289tab.tbl_ptr = &ofdm_offset;2290for (i = 836; i < 862; i++) {2291tab.tbl_offset = i;2292wlc_lcnphy_write_table(pi, &tab);2293}22942295mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);22962297mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);22982299mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);23002301mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);23022303mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);23042305mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);23062307index2 = (u16) (index * 2);2308mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);23092310mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);23112312}23132314static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)2315{2316s8 index, delta_brd, delta_temp, new_index, tempcorrx;2317s16 manp, meas_temp, temp_diff;2318bool neg = false;2319u16 temp;2320struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;23212322if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))2323return pi_lcn->lcnphy_current_index;23242325index = FIXED_TXPWR;23262327if (pi_lcn->lcnphy_tempsense_slope == 0)2328return index;23292330temp = (u16) wlc_lcnphy_tempsense(pi, 0);2331meas_temp = LCNPHY_TEMPSENSE(temp);23322333if (pi->tx_power_min != 0)2334delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);2335else2336delta_brd = 0;23372338manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);2339temp_diff = manp - meas_temp;2340if (temp_diff < 0) {2341neg = true;2342temp_diff = -temp_diff;2343}23442345delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),2346(u32) (pi_lcn->2347lcnphy_tempsense_slope2348* 10), 0);2349if (neg)2350delta_temp = -delta_temp;23512352if (pi_lcn->lcnphy_tempsense_option == 32353&& LCNREV_IS(pi->pubpi.phy_rev, 0))2354delta_temp = 0;2355if (pi_lcn->lcnphy_tempcorrx > 31)2356tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);2357else2358tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;2359if (LCNREV_IS(pi->pubpi.phy_rev, 1))2360tempcorrx = 4;2361new_index =2362index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;2363new_index += tempcorrx;23642365if (LCNREV_IS(pi->pubpi.phy_rev, 1))2366index = 127;23672368if (new_index < 0 || new_index > 126)2369return index;23702371return new_index;2372}23732374static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)2375{23762377u16 current_mode = mode;2378if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&2379mode == LCNPHY_TX_PWR_CTRL_HW)2380current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;2381if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&2382mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)2383current_mode = LCNPHY_TX_PWR_CTRL_HW;2384return current_mode;2385}23862387void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)2388{2389u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);2390s8 index;2391struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;23922393mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);2394old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);23952396mod_phy_reg(pi, 0x6da, (0x1 << 6),2397((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);23982399mod_phy_reg(pi, 0x6a3, (0x1 << 4),2400((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);24012402if (old_mode != mode) {2403if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {24042405wlc_lcnphy_tx_pwr_update_npt(pi);24062407wlc_lcnphy_clear_tx_power_offsets(pi);2408}2409if (LCNPHY_TX_PWR_CTRL_HW == mode) {24102411wlc_lcnphy_txpower_recalc_target(pi);24122413wlc_lcnphy_set_start_tx_pwr_idx(pi,2414pi_lcn->2415lcnphy_tssi_idx);2416wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);2417mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);24182419pi_lcn->lcnphy_tssi_tx_cnt =2420wlc_lcnphy_total_tx_frames(pi);24212422wlc_lcnphy_disable_tx_gain_override(pi);2423pi_lcn->lcnphy_tx_power_idx_override = -1;2424} else2425wlc_lcnphy_enable_tx_gain_override(pi);24262427mod_phy_reg(pi, 0x4a4,2428((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);2429if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {2430index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);2431wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);2432pi_lcn->lcnphy_current_index = (s8)2433((read_phy_reg(pi,24340x4a9) &24350xFF) / 2);2436}2437}2438}24392440static void2441wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)2442{2443u16 vmid;2444int i;2445for (i = 0; i < 20; i++)2446values_to_save[i] =2447read_radio_reg(pi, iqlo_loopback_rf_regs[i]);24482449mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);2450mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);24512452mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);2453mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);24542455mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);2456mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);24572458mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);2459mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);24602461if (LCNREV_IS(pi->pubpi.phy_rev, 2))2462and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);2463else2464and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);2465or_radio_reg(pi, RADIO_2064_REG11A, 0x1);24662467or_radio_reg(pi, RADIO_2064_REG036, 0x01);2468or_radio_reg(pi, RADIO_2064_REG11A, 0x18);2469udelay(20);24702471if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {2472if (CHSPEC_IS5G(pi->radio_chanspec))2473mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);2474else2475or_radio_reg(pi, RADIO_2064_REG03A, 1);2476} else {2477if (CHSPEC_IS5G(pi->radio_chanspec))2478mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);2479else2480or_radio_reg(pi, RADIO_2064_REG03A, 0x3);2481}24822483udelay(20);24842485write_radio_reg(pi, RADIO_2064_REG025, 0xF);2486if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {2487if (CHSPEC_IS5G(pi->radio_chanspec))2488mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);2489else2490mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);2491} else {2492if (CHSPEC_IS5G(pi->radio_chanspec))2493mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);2494else2495mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);2496}24972498udelay(20);24992500write_radio_reg(pi, RADIO_2064_REG005, 0x8);2501or_radio_reg(pi, RADIO_2064_REG112, 0x80);2502udelay(20);25032504or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);2505or_radio_reg(pi, RADIO_2064_REG11F, 0x44);2506udelay(20);25072508or_radio_reg(pi, RADIO_2064_REG00B, 0x7);2509or_radio_reg(pi, RADIO_2064_REG113, 0x10);2510udelay(20);25112512write_radio_reg(pi, RADIO_2064_REG007, 0x1);2513udelay(20);25142515vmid = 0x2A6;2516mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);2517write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));2518or_radio_reg(pi, RADIO_2064_REG11F, 0x44);2519udelay(20);25202521or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);2522udelay(20);2523write_radio_reg(pi, RADIO_2064_REG012, 0x02);2524or_radio_reg(pi, RADIO_2064_REG112, 0x06);2525write_radio_reg(pi, RADIO_2064_REG036, 0x11);2526write_radio_reg(pi, RADIO_2064_REG059, 0xcc);2527write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);2528write_radio_reg(pi, RADIO_2064_REG078, 0xd7);2529write_radio_reg(pi, RADIO_2064_REG092, 0x15);2530}25312532static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)2533{2534uint delay_count = 0;25352536while (wlc_lcnphy_iqcal_active(pi)) {2537udelay(100);2538delay_count++;25392540if (delay_count > (10 * 500))2541break;2542}25432544return (0 == wlc_lcnphy_iqcal_active(pi));2545}25462547static void2548wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)2549{2550int i;25512552and_phy_reg(pi, 0x44c, 0x0 >> 11);25532554and_phy_reg(pi, 0x43b, 0xC);25552556for (i = 0; i < 20; i++)2557write_radio_reg(pi, iqlo_loopback_rf_regs[i],2558values_to_save[i]);2559}25602561static void2562wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,2563struct lcnphy_txgains *target_gains,2564enum lcnphy_cal_mode cal_mode, bool keep_tone)2565{25662567struct lcnphy_txgains cal_gains, temp_gains;2568u16 hash;2569int j;2570u16 ncorr_override[5];2571u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,25720x0000, 0x0000, 0x0000, 0x0000, 0x0000};25732574u16 commands_fullcal[] = {25750x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x82342576};25772578u16 commands_recal[] = {25790x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x82342580};25812582u16 command_nums_fullcal[] = {25830x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b972584};25852586u16 command_nums_recal[] = {25870x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b972588};2589u16 *command_nums = command_nums_fullcal;25902591u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;2592u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;2593u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;2594bool tx_gain_override_old;2595struct lcnphy_txgains old_gains;2596uint i, n_cal_cmds = 0, n_cal_start = 0;2597u16 *values_to_save;2598struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;25992600if (WARN_ON(CHSPEC_IS5G(pi->radio_chanspec)))2601return;26022603values_to_save = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);2604if (NULL == values_to_save)2605return;26062607save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);2608save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);26092610or_phy_reg(pi, 0x6da, 0x40);2611or_phy_reg(pi, 0x6db, 0x3);26122613switch (cal_mode) {2614case LCNPHY_CAL_FULL:2615start_coeffs = syst_coeffs;2616cal_cmds = commands_fullcal;2617n_cal_cmds = ARRAY_SIZE(commands_fullcal);2618break;26192620case LCNPHY_CAL_RECAL:2621start_coeffs = syst_coeffs;2622cal_cmds = commands_recal;2623n_cal_cmds = ARRAY_SIZE(commands_recal);2624command_nums = command_nums_recal;2625break;26262627default:2628break;2629}26302631wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2632start_coeffs, 11, 16, 64);26332634write_phy_reg(pi, 0x6da, 0xffff);2635mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);26362637tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);26382639mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);26402641wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);26422643save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);26442645mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);26462647mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);26482649wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);26502651tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);2652if (tx_gain_override_old)2653wlc_lcnphy_get_tx_gain(pi, &old_gains);26542655if (!target_gains) {2656if (!tx_gain_override_old)2657wlc_lcnphy_set_tx_pwr_by_index(pi,2658pi_lcn->lcnphy_tssi_idx);2659wlc_lcnphy_get_tx_gain(pi, &temp_gains);2660target_gains = &temp_gains;2661}26622663hash = (target_gains->gm_gain << 8) |2664(target_gains->pga_gain << 4) | (target_gains->pad_gain);26652666cal_gains = *target_gains;2667memset(ncorr_override, 0, sizeof(ncorr_override));2668for (j = 0; j < iqcal_gainparams_numgains_lcnphy[0]; j++) {2669if (hash == tbl_iqcal_gainparams_lcnphy[0][j][0]) {2670cal_gains.gm_gain =2671tbl_iqcal_gainparams_lcnphy[0][j][1];2672cal_gains.pga_gain =2673tbl_iqcal_gainparams_lcnphy[0][j][2];2674cal_gains.pad_gain =2675tbl_iqcal_gainparams_lcnphy[0][j][3];2676memcpy(ncorr_override,2677&tbl_iqcal_gainparams_lcnphy[0][j][3],2678sizeof(ncorr_override));2679break;2680}2681}26822683wlc_lcnphy_set_tx_gain(pi, &cal_gains);26842685write_phy_reg(pi, 0x453, 0xaa9);2686write_phy_reg(pi, 0x93d, 0xc0);26872688wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2689lcnphy_iqcal_loft_gainladder,2690ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),269116, 0);26922693wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2694lcnphy_iqcal_ir_gainladder,2695ARRAY_SIZE(2696lcnphy_iqcal_ir_gainladder), 16,269732);26982699if (pi->phy_tx_tone_freq) {27002701wlc_lcnphy_stop_tx_tone(pi);2702udelay(5);2703wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);2704} else {2705wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);2706}27072708write_phy_reg(pi, 0x6da, 0xffff);27092710for (i = n_cal_start; i < n_cal_cmds; i++) {2711u16 zero_diq = 0;2712u16 best_coeffs[11];2713u16 command_num;27142715cal_type = (cal_cmds[i] & 0x0f00) >> 8;27162717command_num = command_nums[i];2718if (ncorr_override[cal_type])2719command_num =2720ncorr_override[cal_type] << 8 | (command_num &27210xff);27222723write_phy_reg(pi, 0x452, command_num);27242725if ((cal_type == 3) || (cal_type == 4)) {2726wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,2727&diq_start, 1, 16, 69);27282729wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2730&zero_diq, 1, 16, 69);2731}27322733write_phy_reg(pi, 0x451, cal_cmds[i]);27342735if (!wlc_lcnphy_iqcal_wait(pi))2736goto cleanup;27372738wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,2739best_coeffs,2740ARRAY_SIZE(best_coeffs), 16, 96);2741wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2742best_coeffs,2743ARRAY_SIZE(best_coeffs), 16, 64);27442745if ((cal_type == 3) || (cal_type == 4))2746wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2747&diq_start, 1, 16, 69);2748wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,2749pi_lcn->lcnphy_cal_results.2750txiqlocal_bestcoeffs,2751ARRAY_SIZE(pi_lcn->2752lcnphy_cal_results.2753txiqlocal_bestcoeffs),275416, 96);2755}27562757wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,2758pi_lcn->lcnphy_cal_results.2759txiqlocal_bestcoeffs,2760ARRAY_SIZE(pi_lcn->lcnphy_cal_results.2761txiqlocal_bestcoeffs), 16, 96);2762pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;27632764wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2765&pi_lcn->lcnphy_cal_results.2766txiqlocal_bestcoeffs[0], 4, 16, 80);27672768wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,2769&pi_lcn->lcnphy_cal_results.2770txiqlocal_bestcoeffs[5], 2, 16, 85);27712772cleanup:2773wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);2774kfree(values_to_save);27752776if (!keep_tone)2777wlc_lcnphy_stop_tx_tone(pi);27782779write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);27802781write_phy_reg(pi, 0x453, 0);27822783if (tx_gain_override_old)2784wlc_lcnphy_set_tx_gain(pi, &old_gains);2785wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);27862787write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);2788write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);27892790}27912792static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)2793{2794bool suspend, tx_gain_override_old;2795struct lcnphy_txgains old_gains;2796struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);2797u16 idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,2798idleTssi0_regvalue_2C;2799u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);2800u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);2801u16 SAVE_jtag_bb_afe_switch =2802read_radio_reg(pi, RADIO_2064_REG007) & 1;2803u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;2804u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;2805u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);28062807read_phy_reg(pi, 0x4ab); /* idleTssi */2808suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &2809MCTL_EN_MAC));2810if (!suspend)2811wlapi_suspend_mac_and_wait(pi->sh->physhim);2812wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);28132814tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);2815wlc_lcnphy_get_tx_gain(pi, &old_gains);28162817wlc_lcnphy_enable_tx_gain_override(pi);2818wlc_lcnphy_set_tx_pwr_by_index(pi, 127);2819write_radio_reg(pi, RADIO_2064_REG112, 0x6);2820mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);2821mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);2822mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);2823wlc_lcnphy_tssi_setup(pi);28242825mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));2826mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));28272828wlc_lcnphy_set_bbmult(pi, 0x0);28292830wlc_phy_do_dummy_tx(pi, true, OFF);2831read_phy_reg(pi, 0x4ab); /* idleTssi */28322833idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))2834>> 0);28352836if (idleTssi0_2C >= 256)2837idleTssi0_OB = idleTssi0_2C - 256;2838else2839idleTssi0_OB = idleTssi0_2C + 256;28402841idleTssi0_regvalue_OB = idleTssi0_OB;2842if (idleTssi0_regvalue_OB >= 256)2843idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;2844else2845idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;2846mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);28472848mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);28492850wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);2851wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);2852wlc_lcnphy_set_tx_gain(pi, &old_gains);2853wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);28542855write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);2856mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);2857mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);2858mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);2859mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);2860if (!suspend)2861wlapi_enable_mac(pi->sh->physhim);2862}28632864static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)2865{2866bool suspend;2867u16 save_txpwrCtrlEn;2868u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;2869u16 auxpga_vmid;2870struct phytbl_info tab;2871u32 val;2872u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,2873save_reg112;2874u16 values_to_save[14];2875s8 index;2876int i;2877struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;2878udelay(999);28792880save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);2881save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);2882save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);2883save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);2884save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);2885save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);28862887for (i = 0; i < 14; i++)2888values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);2889suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &2890MCTL_EN_MAC));2891if (!suspend)2892wlapi_suspend_mac_and_wait(pi->sh->physhim);2893save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);28942895wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);2896index = pi_lcn->lcnphy_current_index;2897wlc_lcnphy_set_tx_pwr_by_index(pi, 127);2898mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);2899mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);2900mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);2901mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);29022903mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);29042905mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);29062907mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);29082909mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);29102911mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);29122913mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);29142915mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);29162917mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);29182919mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);29202921mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);29222923mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);29242925mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);29262927mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);29282929mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);29302931mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);29322933mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);29342935mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);29362937write_radio_reg(pi, RADIO_2064_REG025, 0xC);29382939mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);29402941mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);29422943mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);29442945mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);29462947val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);2948tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;2949tab.tbl_width = 16;2950tab.tbl_len = 1;2951tab.tbl_ptr = &val;2952tab.tbl_offset = 6;2953wlc_lcnphy_write_table(pi, &tab);2954if (mode == TEMPSENSE) {2955mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);29562957mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);29582959auxpga_vmidcourse = 8;2960auxpga_vmidfine = 0x4;2961auxpga_gain = 2;2962mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);2963} else {2964mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);29652966mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);29672968auxpga_vmidcourse = 7;2969auxpga_vmidfine = 0xa;2970auxpga_gain = 2;2971}2972auxpga_vmid =2973(u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);2974mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);29752976mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);29772978mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);29792980mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);29812982mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);29832984write_radio_reg(pi, RADIO_2064_REG112, 0x6);29852986wlc_phy_do_dummy_tx(pi, true, OFF);2987if (!tempsense_done(pi))2988udelay(10);29892990write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);2991write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);2992write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);2993write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);2994write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);2995write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);2996for (i = 0; i < 14; i++)2997write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);2998wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);29993000write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);3001if (!suspend)3002wlapi_enable_mac(pi->sh->physhim);3003udelay(999);3004}30053006static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)3007{3008struct lcnphy_txgains tx_gains;3009u8 bbmult;3010struct phytbl_info tab;3011s32 a1, b0, b1;3012s32 tssi, pwr, mintargetpwr;3013bool suspend;3014struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);30153016suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &3017MCTL_EN_MAC));3018if (!suspend)3019wlapi_suspend_mac_and_wait(pi->sh->physhim);30203021if (!pi->hwpwrctrl_capable) {3022if (CHSPEC_IS2G(pi->radio_chanspec)) {3023tx_gains.gm_gain = 4;3024tx_gains.pga_gain = 12;3025tx_gains.pad_gain = 12;3026tx_gains.dac_gain = 0;30273028bbmult = 150;3029} else {3030tx_gains.gm_gain = 7;3031tx_gains.pga_gain = 15;3032tx_gains.pad_gain = 14;3033tx_gains.dac_gain = 0;30343035bbmult = 150;3036}3037wlc_lcnphy_set_tx_gain(pi, &tx_gains);3038wlc_lcnphy_set_bbmult(pi, bbmult);3039wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);3040} else {30413042wlc_lcnphy_idle_tssi_est(ppi);30433044wlc_lcnphy_clear_tx_power_offsets(pi);30453046b0 = pi->txpa_2g[0];3047b1 = pi->txpa_2g[1];3048a1 = pi->txpa_2g[2];3049mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);30503051tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;3052tab.tbl_width = 32;3053tab.tbl_ptr = &pwr;3054tab.tbl_len = 1;3055tab.tbl_offset = 0;3056for (tssi = 0; tssi < 128; tssi++) {3057pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);30583059pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;3060wlc_lcnphy_write_table(pi, &tab);3061tab.tbl_offset++;3062}3063mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);3064mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);3065mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);3066mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);3067mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);30683069mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);30703071write_phy_reg(pi, 0x4a8, 10);30723073wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);30743075wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);3076}3077if (!suspend)3078wlapi_enable_mac(pi->sh->physhim);3079}30803081static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)3082{3083mod_phy_reg(pi, 0x4fb,3084LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,3085gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);3086mod_phy_reg(pi, 0x4fd,3087LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,3088gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);3089}30903091void3092wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,3093u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)3094{3095*ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));3096*eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));3097*fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));3098*fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));3099}31003101void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)3102{3103struct phytbl_info tab;3104u16 iqcc[2];31053106iqcc[0] = a;3107iqcc[1] = b;31083109tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;3110tab.tbl_width = 16;3111tab.tbl_ptr = iqcc;3112tab.tbl_len = 2;3113tab.tbl_offset = 80;3114wlc_lcnphy_write_table(pi, &tab);3115}31163117void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)3118{3119struct phytbl_info tab;31203121tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;3122tab.tbl_width = 16;3123tab.tbl_ptr = &didq;3124tab.tbl_len = 1;3125tab.tbl_offset = 85;3126wlc_lcnphy_write_table(pi, &tab);3127}31283129void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)3130{3131struct phytbl_info tab;3132u16 a, b;3133u8 bb_mult;3134u32 bbmultiqcomp, txgain, locoeffs, rfpower;3135struct lcnphy_txgains gains;3136struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;31373138pi_lcn->lcnphy_tx_power_idx_override = (s8) index;3139pi_lcn->lcnphy_current_index = (u8) index;31403141tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;3142tab.tbl_width = 32;3143tab.tbl_len = 1;31443145wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);31463147tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;3148tab.tbl_ptr = &bbmultiqcomp;3149wlc_lcnphy_read_table(pi, &tab);31503151tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;3152tab.tbl_width = 32;3153tab.tbl_ptr = &txgain;3154wlc_lcnphy_read_table(pi, &tab);31553156gains.gm_gain = (u16) (txgain & 0xff);3157gains.pga_gain = (u16) (txgain >> 8) & 0xff;3158gains.pad_gain = (u16) (txgain >> 16) & 0xff;3159gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;3160wlc_lcnphy_set_tx_gain(pi, &gains);3161wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);31623163bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);3164wlc_lcnphy_set_bbmult(pi, bb_mult);31653166wlc_lcnphy_enable_tx_gain_override(pi);31673168if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {31693170a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);3171b = (u16) (bbmultiqcomp & 0x3ff);3172wlc_lcnphy_set_tx_iqcc(pi, a, b);31733174tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;3175tab.tbl_ptr = &locoeffs;3176wlc_lcnphy_read_table(pi, &tab);31773178wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);31793180tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;3181tab.tbl_ptr = &rfpower;3182wlc_lcnphy_read_table(pi, &tab);3183mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);31843185}3186}31873188static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)3189{3190u32 j;3191struct phytbl_info tab;3192u32 temp_offset[128];3193tab.tbl_ptr = temp_offset;3194tab.tbl_len = 128;3195tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;3196tab.tbl_width = 32;3197tab.tbl_offset = 0;31983199memset(temp_offset, 0, sizeof(temp_offset));3200for (j = 1; j < 128; j += 2)3201temp_offset[j] = 0x80000;32023203wlc_lcnphy_write_table(pi, &tab);3204return;3205}32063207void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)3208{3209if (!bEnable) {32103211and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));32123213mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);32143215and_phy_reg(pi, 0x44c,3216~(u16) ((0x1 << 3) |3217(0x1 << 5) |3218(0x1 << 12) |3219(0x1 << 0) | (0x1 << 1) | (0x1 << 2)));32203221and_phy_reg(pi, 0x44d,3222~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));3223mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);32243225mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));32263227and_phy_reg(pi, 0x4f9,3228~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));32293230and_phy_reg(pi, 0x4fa,3231~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));3232} else {32333234mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);3235mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);32363237mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);3238mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);32393240mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);3241mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);32423243wlc_lcnphy_set_trsw_override(pi, true, false);32443245mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);3246mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);32473248if (CHSPEC_IS2G(pi->radio_chanspec)) {32493250mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);3251mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);32523253mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);3254mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);32553256mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);3257mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);32583259mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);3260mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);32613262mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);3263mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);3264} else {32653266mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);3267mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);32683269mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);3270mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);32713272mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);3273mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);32743275mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);3276mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);32773278mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);3279mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);3280}3281}3282}32833284static void3285wlc_lcnphy_run_samples(struct brcms_phy *pi,3286u16 num_samps,3287u16 num_loops, u16 wait, bool iqcalmode)3288{32893290or_phy_reg(pi, 0x6da, 0x8080);32913292mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);3293if (num_loops != 0xffff)3294num_loops--;3295mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);32963297mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);32983299if (iqcalmode) {33003301and_phy_reg(pi, 0x453, 0xffff & ~(0x1 << 15));3302or_phy_reg(pi, 0x453, (0x1 << 15));3303} else {3304write_phy_reg(pi, 0x63f, 1);3305wlc_lcnphy_tx_pu(pi, 1);3306}33073308or_radio_reg(pi, RADIO_2064_REG112, 0x6);3309}33103311void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)3312{33133314u8 phybw40;3315phybw40 = CHSPEC_IS40(pi->radio_chanspec);33163317mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);3318mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);33193320if (phybw40 == 0) {3321mod_phy_reg((pi), 0x410,3322(0x1 << 6) |3323(0x1 << 5),3324((CHSPEC_IS2G(3325pi->radio_chanspec)) ? (!mode) : 0) <<33266 | (!mode) << 5);3327mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);3328}3329}33303331void3332wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,3333bool iqcalmode)3334{3335u8 phy_bw;3336u16 num_samps, t, k;3337u32 bw;3338s32 theta = 0, rot = 0;3339struct cordic_iq tone_samp;3340u32 data_buf[64];3341u16 i_samp, q_samp;3342struct phytbl_info tab;3343struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;33443345pi->phy_tx_tone_freq = f_kHz;33463347wlc_lcnphy_deaf_mode(pi, true);33483349phy_bw = 40;3350if (pi_lcn->lcnphy_spurmod) {3351write_phy_reg(pi, 0x942, 0x2);3352write_phy_reg(pi, 0x93b, 0x0);3353write_phy_reg(pi, 0x93c, 0x0);3354wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);3355}33563357if (f_kHz) {3358k = 1;3359do {3360bw = phy_bw * 1000 * k;3361num_samps = bw / abs(f_kHz);3362k++;3363} while ((num_samps * (u32) (abs(f_kHz))) != bw);3364} else3365num_samps = 2;33663367rot = ((f_kHz * 36) / phy_bw) / 100;3368theta = 0;33693370for (t = 0; t < num_samps; t++) {33713372tone_samp = cordic_calc_iq(theta);33733374theta += rot;33753376i_samp = (u16)(CORDIC_FLOAT(tone_samp.i * max_val) & 0x3ff);3377q_samp = (u16)(CORDIC_FLOAT(tone_samp.q * max_val) & 0x3ff);3378data_buf[t] = (i_samp << 10) | q_samp;3379}33803381mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);33823383mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);33843385tab.tbl_ptr = data_buf;3386tab.tbl_len = num_samps;3387tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;3388tab.tbl_offset = 0;3389tab.tbl_width = 32;3390wlc_lcnphy_write_table(pi, &tab);33913392wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);3393}33943395void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)3396{3397s16 playback_status;3398struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;33993400pi->phy_tx_tone_freq = 0;3401if (pi_lcn->lcnphy_spurmod) {3402write_phy_reg(pi, 0x942, 0x7);3403write_phy_reg(pi, 0x93b, 0x2017);3404write_phy_reg(pi, 0x93c, 0x27c5);3405wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);3406}34073408playback_status = read_phy_reg(pi, 0x644);3409if (playback_status & (0x1 << 0)) {3410wlc_lcnphy_tx_pu(pi, 0);3411mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);3412} else if (playback_status & (0x1 << 1))3413mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);34143415mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);34163417mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);34183419mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);34203421and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);34223423wlc_lcnphy_deaf_mode(pi, false);3424}34253426static void3427wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)3428{3429u16 di0dq0;3430u16 x, y, data_rf;3431int k;3432switch (cal_type) {3433case 0:3434wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);3435break;3436case 2:3437di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);3438wlc_lcnphy_set_tx_locc(pi, di0dq0);3439break;3440case 3:3441k = wlc_lcnphy_calc_floor(coeff_x, 0);3442y = 8 + k;3443k = wlc_lcnphy_calc_floor(coeff_x, 1);3444x = 8 - k;3445data_rf = (x * 16 + y);3446write_radio_reg(pi, RADIO_2064_REG089, data_rf);3447k = wlc_lcnphy_calc_floor(coeff_y, 0);3448y = 8 + k;3449k = wlc_lcnphy_calc_floor(coeff_y, 1);3450x = 8 - k;3451data_rf = (x * 16 + y);3452write_radio_reg(pi, RADIO_2064_REG08A, data_rf);3453break;3454case 4:3455k = wlc_lcnphy_calc_floor(coeff_x, 0);3456y = 8 + k;3457k = wlc_lcnphy_calc_floor(coeff_x, 1);3458x = 8 - k;3459data_rf = (x * 16 + y);3460write_radio_reg(pi, RADIO_2064_REG08B, data_rf);3461k = wlc_lcnphy_calc_floor(coeff_y, 0);3462y = 8 + k;3463k = wlc_lcnphy_calc_floor(coeff_y, 1);3464x = 8 - k;3465data_rf = (x * 16 + y);3466write_radio_reg(pi, RADIO_2064_REG08C, data_rf);3467break;3468}3469}34703471static struct lcnphy_unsign16_struct3472wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)3473{3474u16 a, b, didq;3475u8 di0, dq0, ei, eq, fi, fq;3476struct lcnphy_unsign16_struct cc;3477cc.re = 0;3478cc.im = 0;3479switch (cal_type) {3480case 0:3481wlc_lcnphy_get_tx_iqcc(pi, &a, &b);3482cc.re = a;3483cc.im = b;3484break;3485case 2:3486didq = wlc_lcnphy_get_tx_locc(pi);3487di0 = (((didq & 0xff00) << 16) >> 24);3488dq0 = (((didq & 0x00ff) << 24) >> 24);3489cc.re = (u16) di0;3490cc.im = (u16) dq0;3491break;3492case 3:3493wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);3494cc.re = (u16) ei;3495cc.im = (u16) eq;3496break;3497case 4:3498wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);3499cc.re = (u16) fi;3500cc.im = (u16) fq;3501break;3502}3503return cc;3504}35053506static void3507wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,3508s16 *ptr, int mode)3509{3510u32 curval1, curval2, stpptr, curptr, strptr, val;3511u16 sslpnCalibClkEnCtrl, timer;3512u16 old_sslpnCalibClkEnCtrl;3513s16 imag, real;3514struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;35153516timer = 0;3517old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);35183519curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));3520ptr[130] = 0;3521bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),3522((1 << 6) | curval1));35233524bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);3525bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);3526udelay(20);3527curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));3528bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),3529curval2 | 0x30);35303531write_phy_reg(pi, 0x555, 0x0);3532write_phy_reg(pi, 0x5a6, 0x5);35333534write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));3535write_phy_reg(pi, 0x5cf, 3);3536write_phy_reg(pi, 0x5a5, 0x3);3537write_phy_reg(pi, 0x583, 0x0);3538write_phy_reg(pi, 0x584, 0x0);3539write_phy_reg(pi, 0x585, 0x0fff);3540write_phy_reg(pi, 0x586, 0x0000);35413542write_phy_reg(pi, 0x580, 0x4501);35433544sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);3545write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));3546stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));3547curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));3548do {3549udelay(10);3550curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));3551timer++;3552} while ((curptr != stpptr) && (timer < 500));35533554bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);3555strptr = 0x7E00;3556bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);3557while (strptr < 0x8000) {3558val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));3559imag = ((val >> 16) & 0x3ff);3560real = ((val) & 0x3ff);3561if (imag > 511)3562imag -= 1024;35633564if (real > 511)3565real -= 1024;35663567if (pi_lcn->lcnphy_iqcal_swp_dis)3568ptr[(strptr - 0x7E00) / 4] = real;3569else3570ptr[(strptr - 0x7E00) / 4] = imag;35713572if (clip_detect_algo) {3573if (imag > thresh || imag < -thresh) {3574strptr = 0x8000;3575ptr[130] = 1;3576}3577}35783579strptr += 4;3580}35813582write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);3583bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);3584bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);3585}35863587static void3588wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,3589int step_size_lg2)3590{3591const struct lcnphy_spb_tone *phy_c1;3592struct lcnphy_spb_tone phy_c2;3593struct lcnphy_unsign16_struct phy_c3;3594int phy_c4, phy_c5, k, l, j, phy_c6;3595u16 phy_c7, phy_c8, phy_c9;3596s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;3597s16 *ptr, phy_c17;3598s32 phy_c18, phy_c19;3599u32 phy_c20, phy_c21;3600bool phy_c22, phy_c23, phy_c24, phy_c25;3601u16 phy_c26, phy_c27;3602u16 phy_c28, phy_c29, phy_c30;3603u16 phy_c31;3604u16 *phy_c32;3605phy_c21 = 0;3606phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;3607ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);3608if (NULL == ptr)3609return;36103611phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);3612if (NULL == phy_c32) {3613kfree(ptr);3614return;3615}3616phy_c26 = read_phy_reg(pi, 0x6da);3617phy_c27 = read_phy_reg(pi, 0x6db);3618phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);3619write_phy_reg(pi, 0x93d, 0xC0);36203621wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);3622write_phy_reg(pi, 0x6da, 0xffff);3623or_phy_reg(pi, 0x6db, 0x3);36243625wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);3626udelay(500);3627phy_c28 = read_phy_reg(pi, 0x938);3628phy_c29 = read_phy_reg(pi, 0x4d7);3629phy_c30 = read_phy_reg(pi, 0x4d8);3630or_phy_reg(pi, 0x938, 0x1 << 2);3631or_phy_reg(pi, 0x4d7, 0x1 << 2);3632or_phy_reg(pi, 0x4d7, 0x1 << 3);3633mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);3634or_phy_reg(pi, 0x4d8, 1 << 0);3635or_phy_reg(pi, 0x4d8, 1 << 1);3636mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);3637mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);3638phy_c1 = &lcnphy_spb_tone_3750[0];3639phy_c4 = 32;36403641if (num_levels == 0) {3642if (cal_type != 0)3643num_levels = 4;3644else3645num_levels = 9;3646}3647if (step_size_lg2 == 0) {3648if (cal_type != 0)3649step_size_lg2 = 3;3650else3651step_size_lg2 = 8;3652}36533654phy_c7 = (1 << step_size_lg2);3655phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);3656phy_c15 = (s16) phy_c3.re;3657phy_c16 = (s16) phy_c3.im;3658if (cal_type == 2) {3659if (phy_c3.re > 127)3660phy_c15 = phy_c3.re - 256;3661if (phy_c3.im > 127)3662phy_c16 = phy_c3.im - 256;3663}3664wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);3665udelay(20);3666for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {3667phy_c23 = true;3668phy_c22 = false;3669switch (cal_type) {3670case 0:3671phy_c10 = 511;3672break;3673case 2:3674phy_c10 = 127;3675break;3676case 3:3677phy_c10 = 15;3678break;3679case 4:3680phy_c10 = 15;3681break;3682}36833684phy_c9 = read_phy_reg(pi, 0x93d);3685phy_c9 = 2 * phy_c9;3686phy_c24 = false;3687phy_c5 = 7;3688phy_c25 = true;3689while (1) {3690write_radio_reg(pi, RADIO_2064_REG026,3691(phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));3692udelay(50);3693phy_c22 = false;3694ptr[130] = 0;3695wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);3696if (ptr[130] == 1)3697phy_c22 = true;3698if (phy_c22)3699phy_c5 -= 1;3700if ((phy_c22 != phy_c24) && (!phy_c25))3701break;3702if (!phy_c22)3703phy_c5 += 1;3704if (phy_c5 <= 0 || phy_c5 >= 7)3705break;3706phy_c24 = phy_c22;3707phy_c25 = false;3708}37093710if (phy_c5 < 0)3711phy_c5 = 0;3712else if (phy_c5 > 7)3713phy_c5 = 7;37143715for (k = -phy_c7; k <= phy_c7; k += phy_c7) {3716for (l = -phy_c7; l <= phy_c7; l += phy_c7) {3717phy_c11 = phy_c15 + k;3718phy_c12 = phy_c16 + l;37193720if (phy_c11 < -phy_c10)3721phy_c11 = -phy_c10;3722else if (phy_c11 > phy_c10)3723phy_c11 = phy_c10;3724if (phy_c12 < -phy_c10)3725phy_c12 = -phy_c10;3726else if (phy_c12 > phy_c10)3727phy_c12 = phy_c10;3728wlc_lcnphy_set_cc(pi, cal_type, phy_c11,3729phy_c12);3730udelay(20);3731wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);37323733phy_c18 = 0;3734phy_c19 = 0;3735for (j = 0; j < 128; j++) {3736if (cal_type != 0)3737phy_c6 = j % phy_c4;3738else3739phy_c6 = (2 * j) % phy_c4;37403741phy_c2.re = phy_c1[phy_c6].re;3742phy_c2.im = phy_c1[phy_c6].im;3743phy_c17 = ptr[j];3744phy_c18 = phy_c18 + phy_c17 * phy_c2.re;3745phy_c19 = phy_c19 + phy_c17 * phy_c2.im;3746}37473748phy_c18 = phy_c18 >> 10;3749phy_c19 = phy_c19 >> 10;3750phy_c20 = ((phy_c18 * phy_c18) +3751(phy_c19 * phy_c19));37523753if (phy_c23 || phy_c20 < phy_c21) {3754phy_c21 = phy_c20;3755phy_c13 = phy_c11;3756phy_c14 = phy_c12;3757}3758phy_c23 = false;3759}3760}3761phy_c23 = true;3762phy_c15 = phy_c13;3763phy_c16 = phy_c14;3764phy_c7 = phy_c7 >> 1;3765wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);3766udelay(20);3767}3768goto cleanup;3769cleanup:3770wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);3771wlc_lcnphy_stop_tx_tone(pi);3772write_phy_reg(pi, 0x6da, phy_c26);3773write_phy_reg(pi, 0x6db, phy_c27);3774write_phy_reg(pi, 0x938, phy_c28);3775write_phy_reg(pi, 0x4d7, phy_c29);3776write_phy_reg(pi, 0x4d8, phy_c30);3777write_radio_reg(pi, RADIO_2064_REG026, phy_c31);37783779kfree(phy_c32);3780kfree(ptr);3781}37823783void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)3784{3785u16 iqcc[2];3786struct phytbl_info tab;37873788tab.tbl_ptr = iqcc;3789tab.tbl_len = 2;3790tab.tbl_id = 0;3791tab.tbl_offset = 80;3792tab.tbl_width = 16;3793wlc_lcnphy_read_table(pi, &tab);37943795*a = iqcc[0];3796*b = iqcc[1];3797}37983799static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)3800{3801wlc_lcnphy_set_cc(pi, 0, 0, 0);3802wlc_lcnphy_set_cc(pi, 2, 0, 0);3803wlc_lcnphy_set_cc(pi, 3, 0, 0);3804wlc_lcnphy_set_cc(pi, 4, 0, 0);38053806wlc_lcnphy_a1(pi, 4, 0, 0);3807wlc_lcnphy_a1(pi, 3, 0, 0);3808wlc_lcnphy_a1(pi, 2, 3, 2);3809wlc_lcnphy_a1(pi, 0, 5, 8);3810wlc_lcnphy_a1(pi, 2, 2, 1);3811wlc_lcnphy_a1(pi, 0, 4, 3);38123813wlc_lcnphy_get_cc(pi, 0);3814wlc_lcnphy_get_cc(pi, 2);3815wlc_lcnphy_get_cc(pi, 3);3816wlc_lcnphy_get_cc(pi, 4);3817}38183819u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)3820{3821struct phytbl_info tab;3822u16 didq;38233824tab.tbl_id = 0;3825tab.tbl_width = 16;3826tab.tbl_ptr = &didq;3827tab.tbl_len = 1;3828tab.tbl_offset = 85;3829wlc_lcnphy_read_table(pi, &tab);38303831return didq;3832}38333834static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)3835{38363837struct lcnphy_txgains target_gains, old_gains;3838u8 save_bb_mult;3839u16 a, b, didq, save_pa_gain = 0;3840uint idx, SAVE_txpwrindex = 0xFF;3841u32 val;3842u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);3843struct phytbl_info tab;3844u8 ei0, eq0, fi0, fq0;3845struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;38463847wlc_lcnphy_get_tx_gain(pi, &old_gains);3848save_pa_gain = wlc_lcnphy_get_pa_gain(pi);38493850save_bb_mult = wlc_lcnphy_get_bbmult(pi);38513852if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)3853SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);38543855wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);38563857target_gains.gm_gain = 7;3858target_gains.pga_gain = 0;3859target_gains.pad_gain = 21;3860target_gains.dac_gain = 0;3861wlc_lcnphy_set_tx_gain(pi, &target_gains);38623863if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {38643865wlc_lcnphy_set_tx_pwr_by_index(pi, 30);38663867wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,3868(pi_lcn->3869lcnphy_recal ? LCNPHY_CAL_RECAL :3870LCNPHY_CAL_FULL), false);3871} else {3872wlc_lcnphy_set_tx_pwr_by_index(pi, 16);3873wlc_lcnphy_tx_iqlo_soft_cal_full(pi);3874}38753876wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);3877if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {3878if (CHSPEC_IS5G(pi->radio_chanspec)) {3879target_gains.gm_gain = 255;3880target_gains.pga_gain = 255;3881target_gains.pad_gain = 0xf0;3882target_gains.dac_gain = 0;3883} else {3884target_gains.gm_gain = 7;3885target_gains.pga_gain = 45;3886target_gains.pad_gain = 186;3887target_gains.dac_gain = 0;3888}38893890if (LCNREV_IS(pi->pubpi.phy_rev, 1)3891|| pi_lcn->lcnphy_hw_iqcal_en) {38923893target_gains.pga_gain = 0;3894target_gains.pad_gain = 30;3895wlc_lcnphy_set_tx_pwr_by_index(pi, 16);3896wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,3897LCNPHY_CAL_FULL, false);3898} else {3899wlc_lcnphy_tx_iqlo_soft_cal_full(pi);3900}3901}39023903wlc_lcnphy_get_tx_iqcc(pi, &a, &b);39043905didq = wlc_lcnphy_get_tx_locc(pi);39063907tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;3908tab.tbl_width = 32;3909tab.tbl_ptr = &val;39103911tab.tbl_len = 1;3912tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;39133914for (idx = 0; idx < 128; idx++) {3915tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;39163917wlc_lcnphy_read_table(pi, &tab);3918val = (val & 0xfff00000) |3919((u32) (a & 0x3FF) << 10) | (b & 0x3ff);3920wlc_lcnphy_write_table(pi, &tab);39213922val = didq;3923tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;3924wlc_lcnphy_write_table(pi, &tab);3925}39263927pi_lcn->lcnphy_cal_results.txiqlocal_a = a;3928pi_lcn->lcnphy_cal_results.txiqlocal_b = b;3929pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;3930pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;3931pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;3932pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;3933pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;39343935wlc_lcnphy_set_bbmult(pi, save_bb_mult);3936wlc_lcnphy_set_pa_gain(pi, save_pa_gain);3937wlc_lcnphy_set_tx_gain(pi, &old_gains);39383939if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)3940wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);3941else3942wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);3943}39443945s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)3946{3947u16 tempsenseval1, tempsenseval2;3948s16 avg = 0;3949bool suspend = false;39503951if (mode == 1) {3952suspend = (0 == (bcma_read32(pi->d11core,3953D11REGOFFS(maccontrol)) &3954MCTL_EN_MAC));3955if (!suspend)3956wlapi_suspend_mac_and_wait(pi->sh->physhim);3957wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);3958}3959tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;3960tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;39613962if (tempsenseval1 > 255)3963avg = (s16) (tempsenseval1 - 512);3964else3965avg = (s16) tempsenseval1;39663967if (tempsenseval2 > 255)3968avg += (s16) (tempsenseval2 - 512);3969else3970avg += (s16) tempsenseval2;39713972avg /= 2;39733974if (mode == 1) {39753976mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);39773978udelay(100);3979mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);39803981if (!suspend)3982wlapi_enable_mac(pi->sh->physhim);3983}3984return avg;3985}39863987u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)3988{3989u16 tempsenseval1, tempsenseval2;3990s32 avg = 0;3991bool suspend = false;3992u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);3993struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;39943995if (mode == 1) {3996suspend = (0 == (bcma_read32(pi->d11core,3997D11REGOFFS(maccontrol)) &3998MCTL_EN_MAC));3999if (!suspend)4000wlapi_suspend_mac_and_wait(pi->sh->physhim);4001wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);4002}4003tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;4004tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;40054006if (tempsenseval1 > 255)4007avg = (int)(tempsenseval1 - 512);4008else4009avg = (int)tempsenseval1;40104011if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {4012if (tempsenseval2 > 255)4013avg = (int)(avg - tempsenseval2 + 512);4014else4015avg = (int)(avg - tempsenseval2);4016} else {4017if (tempsenseval2 > 255)4018avg = (int)(avg + tempsenseval2 - 512);4019else4020avg = (int)(avg + tempsenseval2);4021avg = avg / 2;4022}4023if (avg < 0)4024avg = avg + 512;40254026if (pi_lcn->lcnphy_tempsense_option == 2)4027avg = tempsenseval1;40284029if (mode)4030wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);40314032if (mode == 1) {40334034mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);40354036udelay(100);4037mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);40384039if (!suspend)4040wlapi_enable_mac(pi->sh->physhim);4041}4042return (u16) avg;4043}40444045s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)4046{4047s32 degree = wlc_lcnphy_tempsense_new(pi, mode);4048degree =4049((degree <<405010) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))4051/ LCN_TEMPSENSE_DEN;4052return (s8) degree;4053}40544055s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)4056{4057u16 vbatsenseval;4058s32 avg = 0;4059bool suspend = false;40604061if (mode == 1) {4062suspend = (0 == (bcma_read32(pi->d11core,4063D11REGOFFS(maccontrol)) &4064MCTL_EN_MAC));4065if (!suspend)4066wlapi_suspend_mac_and_wait(pi->sh->physhim);4067wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);4068}40694070vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;40714072if (vbatsenseval > 255)4073avg = (s32) (vbatsenseval - 512);4074else4075avg = (s32) vbatsenseval;40764077avg = (avg * LCN_VBAT_SCALE_NOM +4078(LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;40794080if (mode == 1) {4081if (!suspend)4082wlapi_enable_mac(pi->sh->physhim);4083}4084return (s8) avg;4085}40864087static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)4088{4089u8 phybw40;4090phybw40 = CHSPEC_IS40(pi->radio_chanspec);40914092mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);40934094if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||4095(mode == AFE_CLK_INIT_MODE_TXRX2X))4096write_phy_reg(pi, 0x6d0, 0x7);40974098wlc_lcnphy_toggle_afe_pwdn(pi);4099}41004101static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)4102{4103}41044105static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)4106{4107bool suspend;4108s8 index;4109u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);4110struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;4111suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &4112MCTL_EN_MAC));4113if (!suspend)4114wlapi_suspend_mac_and_wait(pi->sh->physhim);4115wlc_lcnphy_deaf_mode(pi, true);4116pi->phy_lastcal = pi->sh->now;4117pi->phy_forcecal = false;4118index = pi_lcn->lcnphy_current_index;41194120wlc_lcnphy_txpwrtbl_iqlo_cal(pi);41214122wlc_lcnphy_set_tx_pwr_by_index(pi, index);4123wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);4124wlc_lcnphy_deaf_mode(pi, false);4125if (!suspend)4126wlapi_enable_mac(pi->sh->physhim);41274128}41294130static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)4131{4132bool suspend;4133u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);4134s8 index;4135struct phytbl_info tab;4136s32 a1, b0, b1;4137s32 tssi, pwr, mintargetpwr;4138struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;41394140pi->phy_lastcal = pi->sh->now;4141pi->phy_forcecal = false;4142pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);4143index = pi_lcn->lcnphy_current_index;41444145suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &4146MCTL_EN_MAC));4147if (!suspend) {4148wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);4149wlapi_suspend_mac_and_wait(pi->sh->physhim);4150}41514152wlc_lcnphy_deaf_mode(pi, true);41534154wlc_lcnphy_txpwrtbl_iqlo_cal(pi);41554156if (LCNREV_IS(pi->pubpi.phy_rev, 1))4157wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);4158else4159wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);41604161if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {41624163wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);41644165b0 = pi->txpa_2g[0];4166b1 = pi->txpa_2g[1];4167a1 = pi->txpa_2g[2];4168mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);41694170tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;4171tab.tbl_width = 32;4172tab.tbl_ptr = &pwr;4173tab.tbl_len = 1;4174tab.tbl_offset = 0;4175for (tssi = 0; tssi < 128; tssi++) {4176pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);4177pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;4178wlc_lcnphy_write_table(pi, &tab);4179tab.tbl_offset++;4180}4181}41824183wlc_lcnphy_set_tx_pwr_by_index(pi, index);4184wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);4185wlc_lcnphy_deaf_mode(pi, false);4186if (!suspend)4187wlapi_enable_mac(pi->sh->physhim);4188}41894190void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)4191{4192u16 temp_new;4193int temp1, temp2, temp_diff;4194struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;41954196switch (mode) {4197case PHY_PERICAL_CHAN:4198break;4199case PHY_FULLCAL:4200wlc_lcnphy_periodic_cal(pi);4201break;4202case PHY_PERICAL_PHYINIT:4203wlc_lcnphy_periodic_cal(pi);4204break;4205case PHY_PERICAL_WATCHDOG:4206if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {4207temp_new = wlc_lcnphy_tempsense(pi, 0);4208temp1 = LCNPHY_TEMPSENSE(temp_new);4209temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);4210temp_diff = temp1 - temp2;4211if ((pi_lcn->lcnphy_cal_counter > 90) ||4212(temp_diff > 60) || (temp_diff < -60)) {4213wlc_lcnphy_glacial_timer_based_cal(pi);4214wlc_2064_vco_cal(pi);4215pi_lcn->lcnphy_cal_temper = temp_new;4216pi_lcn->lcnphy_cal_counter = 0;4217} else4218pi_lcn->lcnphy_cal_counter++;4219}4220break;4221case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:4222if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))4223wlc_lcnphy_tx_power_adjustment(4224(struct brcms_phy_pub *) pi);4225break;4226}4227}42284229void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)4230{4231s8 cck_offset;4232u16 status;4233status = (read_phy_reg(pi, 0x4ab));4234if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&4235(status & (0x1 << 15))) {4236*ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))4237>> 0) >> 1);42384239if (wlc_phy_tpc_isenabled_lcnphy(pi))4240cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];4241else4242cck_offset = 0;42434244*cck_pwr = *ofdm_pwr + cck_offset;4245} else {4246*cck_pwr = 0;4247*ofdm_pwr = 0;4248}4249}42504251void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)4252{4253return;42544255}42564257void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)4258{4259s8 index;4260u16 index2;4261struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);4262struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;4263u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);4264if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&4265SAVE_txpwrctrl) {4266index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);4267index2 = (u16) (index * 2);4268mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);42694270pi_lcn->lcnphy_current_index =4271(s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);4272}4273}42744275static void4276wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,4277const struct lcnphy_tx_gain_tbl_entry *gain_table)4278{4279u32 j;4280struct phytbl_info tab;4281u32 val;4282u16 pa_gain;4283u16 gm_gain;42844285if (pi->sh->boardflags & BFL_FEM)4286pa_gain = 0x10;4287else4288pa_gain = 0x60;4289tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;4290tab.tbl_width = 32;4291tab.tbl_len = 1;4292tab.tbl_ptr = &val;42934294/* fixed gm_gain value for iPA */4295gm_gain = 15;4296for (j = 0; j < 128; j++) {4297if (pi->sh->boardflags & BFL_FEM)4298gm_gain = gain_table[j].gm;4299val = (((u32) pa_gain << 24) |4300(gain_table[j].pad << 16) |4301(gain_table[j].pga << 8) | gm_gain);43024303tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;4304wlc_lcnphy_write_table(pi, &tab);43054306val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);4307tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;4308wlc_lcnphy_write_table(pi, &tab);4309}4310}43114312static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)4313{4314struct phytbl_info tab;4315u32 val, bbmult, rfgain;4316u8 index;4317u8 scale_factor = 1;4318s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;43194320tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;4321tab.tbl_width = 32;4322tab.tbl_len = 1;43234324for (index = 0; index < 128; index++) {4325tab.tbl_ptr = &bbmult;4326tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;4327wlc_lcnphy_read_table(pi, &tab);4328bbmult = bbmult >> 20;43294330tab.tbl_ptr = &rfgain;4331tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;4332wlc_lcnphy_read_table(pi, &tab);43334334qm_log10((s32) (bbmult), 0, &temp1, &qQ1);4335qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);43364337if (qQ1 < qQ2) {4338temp2 = qm_shr16(temp2, qQ2 - qQ1);4339qQ = qQ1;4340} else {4341temp1 = qm_shr16(temp1, qQ1 - qQ2);4342qQ = qQ2;4343}4344temp = qm_sub16(temp1, temp2);43454346if (qQ >= 4)4347shift = qQ - 4;4348else4349shift = 4 - qQ;43504351val = (((index << shift) + (5 * temp) +4352(1 << (scale_factor + shift - 3))) >> (scale_factor +4353shift - 2));43544355tab.tbl_ptr = &val;4356tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;4357wlc_lcnphy_write_table(pi, &tab);4358}4359}43604361static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)4362{4363or_phy_reg(pi, 0x805, 0x1);43644365mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);43664367mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);43684369write_phy_reg(pi, 0x414, 0x1e10);4370write_phy_reg(pi, 0x415, 0x0640);43714372mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);43734374or_phy_reg(pi, 0x44a, 0x44);4375write_phy_reg(pi, 0x44a, 0x80);4376mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);43774378mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);43794380if (!(pi->sh->boardrev < 0x1204))4381mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);43824383write_phy_reg(pi, 0x7d6, 0x0902);4384mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);43854386mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);43874388if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {4389mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);43904391mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);43924393mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);43944395mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);43964397mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);43984399mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);4400mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);4401mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);4402mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);4403mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);44044405mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);44064407wlc_lcnphy_clear_tx_power_offsets(pi);4408mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);44094410}4411}44124413static void wlc_lcnphy_rcal(struct brcms_phy *pi)4414{4415u8 rcal_value;44164417and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);44184419or_radio_reg(pi, RADIO_2064_REG004, 0x40);4420or_radio_reg(pi, RADIO_2064_REG120, 0x10);44214422or_radio_reg(pi, RADIO_2064_REG078, 0x80);4423or_radio_reg(pi, RADIO_2064_REG129, 0x02);44244425or_radio_reg(pi, RADIO_2064_REG057, 0x01);44264427or_radio_reg(pi, RADIO_2064_REG05B, 0x02);4428mdelay(5);4429SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);44304431if (wlc_radio_2064_rcal_done(pi)) {4432rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);4433rcal_value = rcal_value & 0x1f;4434}44354436and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);44374438and_radio_reg(pi, RADIO_2064_REG057, 0xFE);4439}44404441static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)4442{4443u8 dflt_rc_cal_val;4444u16 flt_val;44454446dflt_rc_cal_val = 7;4447if (LCNREV_IS(pi->pubpi.phy_rev, 1))4448dflt_rc_cal_val = 11;4449flt_val =4450(dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |4451(dflt_rc_cal_val);4452write_phy_reg(pi, 0x933, flt_val);4453write_phy_reg(pi, 0x934, flt_val);4454write_phy_reg(pi, 0x935, flt_val);4455write_phy_reg(pi, 0x936, flt_val);4456write_phy_reg(pi, 0x937, (flt_val & 0x1FF));44574458return;4459}44604461static void wlc_radio_2064_init(struct brcms_phy *pi)4462{4463u32 i;4464const struct lcnphy_radio_regs *lcnphyregs = NULL;44654466lcnphyregs = lcnphy_radio_regs_2064;44674468for (i = 0; lcnphyregs[i].address != 0xffff; i++)4469if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)4470write_radio_reg(pi,4471((lcnphyregs[i].address & 0x3fff) |4472RADIO_DEFAULT_CORE),4473(u16) lcnphyregs[i].init_a);4474else if (lcnphyregs[i].do_init_g)4475write_radio_reg(pi,4476((lcnphyregs[i].address & 0x3fff) |4477RADIO_DEFAULT_CORE),4478(u16) lcnphyregs[i].init_g);44794480write_radio_reg(pi, RADIO_2064_REG032, 0x62);4481write_radio_reg(pi, RADIO_2064_REG033, 0x19);44824483write_radio_reg(pi, RADIO_2064_REG090, 0x10);44844485write_radio_reg(pi, RADIO_2064_REG010, 0x00);44864487if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {44884489write_radio_reg(pi, RADIO_2064_REG060, 0x7f);4490write_radio_reg(pi, RADIO_2064_REG061, 0x72);4491write_radio_reg(pi, RADIO_2064_REG062, 0x7f);4492}44934494write_radio_reg(pi, RADIO_2064_REG01D, 0x02);4495write_radio_reg(pi, RADIO_2064_REG01E, 0x06);44964497mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);44984499mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);45004501mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);45024503mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);45044505mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);45064507write_phy_reg(pi, 0x4ea, 0x4688);45084509if (pi->sh->boardflags & BFL_FEM)4510mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);4511else4512mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);45134514mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);45154516mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);45174518wlc_lcnphy_set_tx_locc(pi, 0);45194520wlc_lcnphy_rcal(pi);45214522wlc_lcnphy_rc_cal(pi);45234524if (!(pi->sh->boardflags & BFL_FEM)) {4525write_radio_reg(pi, RADIO_2064_REG032, 0x6f);4526write_radio_reg(pi, RADIO_2064_REG033, 0x19);4527write_radio_reg(pi, RADIO_2064_REG039, 0xe);4528}45294530}45314532static void wlc_lcnphy_radio_init(struct brcms_phy *pi)4533{4534wlc_radio_2064_init(pi);4535}45364537static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)4538{4539uint idx;4540struct phytbl_info tab;4541const struct phytbl_info *tb;4542u32 val;45434544for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)4545wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);45464547if (pi->sh->boardflags & BFL_FEM_BT) {4548tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;4549tab.tbl_width = 16;4550tab.tbl_ptr = &val;4551tab.tbl_len = 1;4552val = 100;4553tab.tbl_offset = 4;4554wlc_lcnphy_write_table(pi, &tab);4555}45564557if (!(pi->sh->boardflags & BFL_FEM)) {4558tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;4559tab.tbl_width = 16;4560tab.tbl_ptr = &val;4561tab.tbl_len = 1;45624563val = 150;4564tab.tbl_offset = 0;4565wlc_lcnphy_write_table(pi, &tab);45664567val = 220;4568tab.tbl_offset = 1;4569wlc_lcnphy_write_table(pi, &tab);4570}45714572if (CHSPEC_IS2G(pi->radio_chanspec)) {4573if (pi->sh->boardflags & BFL_FEM)4574wlc_lcnphy_load_tx_gain_table(4575pi,4576dot11lcnphy_2GHz_extPA_gaintable_rev0);4577else4578wlc_lcnphy_load_tx_gain_table(4579pi,4580dot11lcnphy_2GHz_gaintable_rev0);4581}45824583if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {4584int l;45854586if (CHSPEC_IS2G(pi->radio_chanspec)) {4587l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;4588if (pi->sh->boardflags & BFL_EXTLNA)4589tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;4590else4591tb = dot11lcnphytbl_rx_gain_info_2G_rev2;4592} else {4593l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;4594if (pi->sh->boardflags & BFL_EXTLNA_5GHz)4595tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;4596else4597tb = dot11lcnphytbl_rx_gain_info_5G_rev2;4598}45994600for (idx = 0; idx < l; idx++)4601wlc_lcnphy_write_table(pi, &tb[idx]);4602}46034604if (pi->sh->boardflags & BFL_FEM) {4605if (pi->sh->boardflags & BFL_FEM_BT) {4606if (pi->sh->boardrev < 0x1250)4607tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;4608else4609tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;4610} else {4611tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;4612}4613} else {4614if (pi->sh->boardflags & BFL_FEM_BT)4615tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;4616else4617tb = &dot11lcn_sw_ctrl_tbl_info_4313;4618}4619wlc_lcnphy_write_table(pi, tb);4620wlc_lcnphy_load_rfpower(pi);46214622wlc_lcnphy_clear_papd_comptable(pi);4623}46244625static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)4626{4627u16 afectrl1;4628struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;46294630write_radio_reg(pi, RADIO_2064_REG11C, 0x0);46314632write_phy_reg(pi, 0x43b, 0x0);4633write_phy_reg(pi, 0x43c, 0x0);4634write_phy_reg(pi, 0x44c, 0x0);4635write_phy_reg(pi, 0x4e6, 0x0);4636write_phy_reg(pi, 0x4f9, 0x0);4637write_phy_reg(pi, 0x4b0, 0x0);4638write_phy_reg(pi, 0x938, 0x0);4639write_phy_reg(pi, 0x4b0, 0x0);4640write_phy_reg(pi, 0x44e, 0);46414642or_phy_reg(pi, 0x567, 0x03);46434644or_phy_reg(pi, 0x44a, 0x44);4645write_phy_reg(pi, 0x44a, 0x80);46464647if (!(pi->sh->boardflags & BFL_FEM))4648wlc_lcnphy_set_tx_pwr_by_index(pi, 52);46494650if (0) {4651afectrl1 = 0;4652afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |4653(pi_lcn->lcnphy_rssi_vc << 4) |4654(pi_lcn->lcnphy_rssi_gs << 10));4655write_phy_reg(pi, 0x43e, afectrl1);4656}46574658mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);4659if (pi->sh->boardflags & BFL_FEM) {4660mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);46614662write_phy_reg(pi, 0x910, 0x1);4663}46644665mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);4666mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);4667mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);46684669}46704671static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)4672{4673if (CHSPEC_IS5G(pi->radio_chanspec)) {4674mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);4675mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);4676}4677}46784679static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)4680{4681s16 temp;4682struct phytbl_info tab;4683u32 tableBuffer[2];4684struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;46854686temp = (s16) read_phy_reg(pi, 0x4df);4687pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;46884689if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)4690pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;46914692pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;46934694if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)4695pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;46964697tab.tbl_ptr = tableBuffer;4698tab.tbl_len = 2;4699tab.tbl_id = 17;4700tab.tbl_offset = 59;4701tab.tbl_width = 32;4702wlc_lcnphy_read_table(pi, &tab);47034704if (tableBuffer[0] > 63)4705tableBuffer[0] -= 128;4706pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];47074708if (tableBuffer[1] > 63)4709tableBuffer[1] -= 128;4710pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];47114712temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));4713if (temp > 127)4714temp -= 256;4715pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;47164717pi_lcn->lcnphy_Med_Low_Gain_db =4718(read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;4719pi_lcn->lcnphy_Very_Low_Gain_db =4720(read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;47214722tab.tbl_ptr = tableBuffer;4723tab.tbl_len = 2;4724tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;4725tab.tbl_offset = 28;4726tab.tbl_width = 32;4727wlc_lcnphy_read_table(pi, &tab);47284729pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];4730pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];47314732}47334734static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)4735{47364737wlc_lcnphy_tbl_init(pi);4738wlc_lcnphy_rev0_baseband_init(pi);4739if (LCNREV_IS(pi->pubpi.phy_rev, 2))4740wlc_lcnphy_rev2_baseband_init(pi);4741wlc_lcnphy_bu_tweaks(pi);4742}47434744void wlc_phy_init_lcnphy(struct brcms_phy *pi)4745{4746struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;47474748pi_lcn->lcnphy_cal_counter = 0;4749pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;47504751or_phy_reg(pi, 0x44a, 0x80);4752and_phy_reg(pi, 0x44a, 0x7f);47534754wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);47554756write_phy_reg(pi, 0x60a, 160);47574758write_phy_reg(pi, 0x46a, 25);47594760wlc_lcnphy_baseband_init(pi);47614762wlc_lcnphy_radio_init(pi);47634764if (CHSPEC_IS2G(pi->radio_chanspec))4765wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);47664767wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);47684769bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);47704771bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,47720x03CDDDDD);47734774if ((pi->sh->boardflags & BFL_FEM)4775&& wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))4776wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);47774778wlc_lcnphy_agc_temp_init(pi);47794780wlc_lcnphy_temp_adj(pi);47814782mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);47834784udelay(100);4785mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);47864787wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);4788pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;4789wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);4790}47914792static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)4793{4794s8 txpwr = 0;4795int i;4796struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;4797struct ssb_sprom *sprom = &pi->d11core->bus->sprom;47984799if (CHSPEC_IS2G(pi->radio_chanspec)) {4800u16 cckpo = 0;4801u32 offset_ofdm, offset_mcs;48024803pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;48044805pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;48064807pi->txpa_2g[0] = sprom->pa0b0;4808pi->txpa_2g[1] = sprom->pa0b1;4809pi->txpa_2g[2] = sprom->pa0b2;48104811pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;4812pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;4813pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;48144815pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;4816pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;4817pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;48184819pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;4820pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;4821pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;48224823txpwr = sprom->core_pwr_info[0].maxpwr_2g;4824pi->tx_srom_max_2g = txpwr;48254826for (i = 0; i < PWRTBL_NUM_COEFF; i++) {4827pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];4828pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];4829}48304831cckpo = sprom->cck2gpo;4832offset_ofdm = sprom->ofdm2gpo;4833if (cckpo) {4834uint max_pwr_chan = txpwr;48354836for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {4837pi->tx_srom_max_rate_2g[i] =4838max_pwr_chan - ((cckpo & 0xf) * 2);4839cckpo >>= 4;4840}48414842for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {4843pi->tx_srom_max_rate_2g[i] =4844max_pwr_chan -4845((offset_ofdm & 0xf) * 2);4846offset_ofdm >>= 4;4847}4848} else {4849for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)4850pi->tx_srom_max_rate_2g[i] = txpwr;48514852for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {4853pi->tx_srom_max_rate_2g[i] = txpwr -4854((offset_ofdm & 0xf) * 2);4855offset_ofdm >>= 4;4856}4857offset_mcs = sprom->mcs2gpo[1] << 16;4858offset_mcs |= sprom->mcs2gpo[0];4859pi_lcn->lcnphy_mcs20_po = offset_mcs;4860for (i = TXP_FIRST_SISO_MCS_20;4861i <= TXP_LAST_SISO_MCS_20; i++) {4862pi->tx_srom_max_rate_2g[i] =4863txpwr - ((offset_mcs & 0xf) * 2);4864offset_mcs >>= 4;4865}4866}48674868pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;4869pi_lcn->lcnphy_measPower = sprom->measpower;4870pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;4871pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;4872pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;4873pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;4874pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;4875pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;4876if (sprom->ant_available_bg > 1)4877wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,4878sprom->ant_available_bg);4879}4880pi_lcn->lcnphy_cck_dig_filt_type = -1;48814882return true;4883}48844885void wlc_2064_vco_cal(struct brcms_phy *pi)4886{4887u8 calnrst;48884889mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);4890calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;4891write_radio_reg(pi, RADIO_2064_REG056, calnrst);4892udelay(1);4893write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);4894udelay(1);4895write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);4896udelay(300);4897mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);4898}48994900bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)4901{4902if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))4903return false;4904else4905return (LCNPHY_TX_PWR_CTRL_HW ==4906wlc_lcnphy_get_tx_pwr_ctrl((pi)));4907}49084909void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)4910{4911u16 pwr_ctrl;4912if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {4913wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);4914} else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {4915pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);4916wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);4917wlc_lcnphy_txpower_recalc_target(pi);4918wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);4919}4920}49214922void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)4923{4924u8 channel = CHSPEC_CHANNEL(chanspec);49254926wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);49274928wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);49294930or_phy_reg(pi, 0x44a, 0x44);4931write_phy_reg(pi, 0x44a, 0x80);49324933wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);4934udelay(1000);49354936wlc_lcnphy_toggle_afe_pwdn(pi);49374938write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);4939write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);49404941if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {4942mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);49434944wlc_lcnphy_load_tx_iir_filter(pi, false, 3);4945} else {4946mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);49474948wlc_lcnphy_load_tx_iir_filter(pi, false, 2);4949}49504951if (pi->sh->boardflags & BFL_FEM)4952wlc_lcnphy_load_tx_iir_filter(pi, true, 0);4953else4954wlc_lcnphy_load_tx_iir_filter(pi, true, 3);49554956mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);4957if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))4958wlc_lcnphy_tssi_setup(pi);4959}49604961void wlc_phy_detach_lcnphy(struct brcms_phy *pi)4962{4963kfree(pi->u.pi_lcnphy);4964}49654966bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)4967{4968struct brcms_phy_lcnphy *pi_lcn;49694970pi_lcn = kzalloc(sizeof(*pi_lcn), GFP_ATOMIC);4971if (!pi_lcn)4972return false;49734974pi->u.pi_lcnphy = pi_lcn;49754976if (0 == (pi->sh->boardflags & BFL_NOPA)) {4977pi->hwpwrctrl = true;4978pi->hwpwrctrl_capable = true;4979}49804981pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);4982pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;49834984pi->pi_fptr.init = wlc_phy_init_lcnphy;4985pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;4986pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;4987pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;4988pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;4989pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;4990pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;4991pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;4992pi->pi_fptr.detach = wlc_phy_detach_lcnphy;49934994if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) {4995kfree(pi->u.pi_lcnphy);4996return false;4997}49984999if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {5000if (pi_lcn->lcnphy_tempsense_option == 3) {5001pi->hwpwrctrl = true;5002pi->hwpwrctrl_capable = true;5003pi->temppwrctrl_capable = false;5004} else {5005pi->hwpwrctrl = false;5006pi->hwpwrctrl_capable = false;5007pi->temppwrctrl_capable = true;5008}5009}50105011return true;5012}50135014static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)5015{5016u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;50175018trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;5019ext_lna = (u16) (gain >> 29) & 0x01;5020lna1 = (u16) (gain >> 0) & 0x0f;5021lna2 = (u16) (gain >> 4) & 0x0f;5022tia = (u16) (gain >> 8) & 0xf;5023biq0 = (u16) (gain >> 12) & 0xf;5024biq1 = (u16) (gain >> 16) & 0xf;50255026gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |5027((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |5028((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));5029gain16_19 = biq1;50305031mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);5032mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);5033mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);5034mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);5035mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);50365037if (CHSPEC_IS2G(pi->radio_chanspec)) {5038mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);5039mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);5040}5041wlc_lcnphy_rx_gain_override_enable(pi, true);5042}50435044static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)5045{5046u32 received_power = 0;5047s32 max_index = 0;5048u32 gain_code = 0;5049struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;50505051max_index = 36;5052if (*gain_index >= 0)5053gain_code = lcnphy_23bitgaincode_table[*gain_index];50545055if (-1 == *gain_index) {5056*gain_index = 0;5057while ((*gain_index <= (s32) max_index)5058&& (received_power < 700)) {5059wlc_lcnphy_set_rx_gain(pi,5060lcnphy_23bitgaincode_table5061[*gain_index]);5062received_power =5063wlc_lcnphy_measure_digital_power(5064pi,5065pi_lcn->5066lcnphy_noise_samples);5067(*gain_index)++;5068}5069(*gain_index)--;5070} else {5071wlc_lcnphy_set_rx_gain(pi, gain_code);5072received_power =5073wlc_lcnphy_measure_digital_power(pi,5074pi_lcn->5075lcnphy_noise_samples);5076}50775078return received_power;5079}50805081s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)5082{5083s32 gain = 0;5084s32 nominal_power_db;5085s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,5086input_power_db;5087s32 received_power, temperature;5088u32 power;5089u32 msb1, msb2, val1, val2, diff1, diff2;5090uint freq;5091struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;50925093received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);50945095gain = lcnphy_gain_table[gain_index];50965097nominal_power_db = read_phy_reg(pi, 0x425) >> 8;50985099power = (received_power * 16);5100msb1 = ffs(power) - 1;5101msb2 = msb1 + 1;5102val1 = 1 << msb1;5103val2 = 1 << msb2;5104diff1 = (power - val1);5105diff2 = (val2 - power);5106if (diff1 < diff2)5107log_val = msb1;5108else5109log_val = msb2;51105111log_val = log_val * 3;51125113gain_mismatch = (nominal_power_db / 2) - (log_val);51145115desired_gain = gain + gain_mismatch;51165117input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;51185119if (input_power_offset_db > 127)5120input_power_offset_db -= 256;51215122input_power_db = input_power_offset_db - desired_gain;51235124input_power_db =5125input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];51265127freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));5128if ((freq > 2427) && (freq <= 2467))5129input_power_db = input_power_db - 1;51305131temperature = pi_lcn->lcnphy_lastsensed_temperature;51325133if ((temperature - 15) < -30)5134input_power_db =5135input_power_db +5136(((temperature - 10 - 25) * 286) >> 12) -51377;5138else if ((temperature - 15) < 4)5139input_power_db =5140input_power_db +5141(((temperature - 10 - 25) * 286) >> 12) -51423;5143else5144input_power_db = input_power_db +5145(((temperature - 10 - 25) * 286) >> 12);51465147wlc_lcnphy_rx_gain_override_enable(pi, 0);51485149return input_power_db;5150}515151525153