Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c
178701 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2010 Broadcom Corporation3*/4#include <linux/kernel.h>5#include <linux/delay.h>6#include <linux/bitops.h>78#include <brcm_hw_ids.h>9#include <chipcommon.h>10#include <aiutils.h>11#include <d11.h>12#include <phy_shim.h>13#include "phy_hal.h"14#include "phy_int.h"15#include "phy_radio.h"16#include "phy_lcn.h"17#include "phyreg_n.h"1819#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \20(radioid == BCM2056_ID) || \21(radioid == BCM2057_ID))2223#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID)2425#define VALID_RADIO(pi, radioid) ( \26(ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \27(ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))2829/* basic mux operation - can be optimized on several architectures */30#define MUX(pred, true, false) ((pred) ? (true) : (false))3132/* modulo inc/dec - assumes x E [0, bound - 1] */33#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)3435/* modulo inc/dec, bound = 2^k */36#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))37#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))3839struct chan_info_basic {40u16 chan;41u16 freq;42};4344static const struct chan_info_basic chan_info_all[] = {45{1, 2412},46{2, 2417},47{3, 2422},48{4, 2427},49{5, 2432},50{6, 2437},51{7, 2442},52{8, 2447},53{9, 2452},54{10, 2457},55{11, 2462},56{12, 2467},57{13, 2472},58{14, 2484},5960{34, 5170},61{38, 5190},62{42, 5210},63{46, 5230},6465{36, 5180},66{40, 5200},67{44, 5220},68{48, 5240},69{52, 5260},70{56, 5280},71{60, 5300},72{64, 5320},7374{100, 5500},75{104, 5520},76{108, 5540},77{112, 5560},78{116, 5580},79{120, 5600},80{124, 5620},81{128, 5640},82{132, 5660},83{136, 5680},84{140, 5700},8586{149, 5745},87{153, 5765},88{157, 5785},89{161, 5805},90{165, 5825},9192{184, 4920},93{188, 4940},94{192, 4960},95{196, 4980},96{200, 5000},97{204, 5020},98{208, 5040},99{212, 5060},100{216, 5080}101};102103static const u8 ofdm_rate_lookup[] = {104105BRCM_RATE_48M,106BRCM_RATE_24M,107BRCM_RATE_12M,108BRCM_RATE_6M,109BRCM_RATE_54M,110BRCM_RATE_36M,111BRCM_RATE_18M,112BRCM_RATE_9M113};114115#define PHY_WREG_LIMIT 24116117void wlc_phyreg_enter(struct brcms_phy_pub *pih)118{119struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);120wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);121}122123void wlc_phyreg_exit(struct brcms_phy_pub *pih)124{125struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);126wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);127}128129u16 read_radio_reg(struct brcms_phy *pi, u16 addr)130{131u16 data;132133if (addr == RADIO_IDCODE)134return 0xffff;135136switch (pi->pubpi.phy_type) {137case PHY_TYPE_N:138if (!CONF_HAS(PHYTYPE, PHY_TYPE_N))139break;140if (NREV_GE(pi->pubpi.phy_rev, 7))141addr |= RADIO_2057_READ_OFF;142else143addr |= RADIO_2055_READ_OFF;144break;145146case PHY_TYPE_LCN:147if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN))148break;149addr |= RADIO_2064_READ_OFF;150break;151152default:153break;154}155156if ((D11REV_GE(pi->sh->corerev, 24)) ||157(D11REV_IS(pi->sh->corerev, 22)158&& (pi->pubpi.phy_type != PHY_TYPE_SSN))) {159bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);160data = bcma_read16(pi->d11core, D11REGOFFS(radioregdata));161} else {162bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);163data = bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));164}165pi->phy_wreg = 0;166167return data;168}169170void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)171{172if ((D11REV_GE(pi->sh->corerev, 24)) ||173(D11REV_IS(pi->sh->corerev, 22)174&& (pi->pubpi.phy_type != PHY_TYPE_SSN))) {175176bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), addr);177bcma_write16(pi->d11core, D11REGOFFS(radioregdata), val);178} else {179bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), addr);180bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val);181}182183if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&184(++pi->phy_wreg >= pi->phy_wreg_limit)) {185(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));186pi->phy_wreg = 0;187}188}189190static u32 read_radio_id(struct brcms_phy *pi)191{192u32 id;193194if (D11REV_GE(pi->sh->corerev, 24)) {195u32 b0, b1, b2;196197bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 0);198b0 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));199bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 1);200b1 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));201bcma_wflush16(pi->d11core, D11REGOFFS(radioregaddr), 2);202b2 = (u32) bcma_read16(pi->d11core, D11REGOFFS(radioregdata));203204id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)205& 0xf);206} else {207bcma_wflush16(pi->d11core, D11REGOFFS(phy4waddr), RADIO_IDCODE);208id = (u32) bcma_read16(pi->d11core, D11REGOFFS(phy4wdatalo));209id |= (u32) bcma_read16(pi->d11core,210D11REGOFFS(phy4wdatahi)) << 16;211}212pi->phy_wreg = 0;213return id;214}215216void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)217{218u16 rval;219220rval = read_radio_reg(pi, addr);221write_radio_reg(pi, addr, (rval & val));222}223224void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)225{226u16 rval;227228rval = read_radio_reg(pi, addr);229write_radio_reg(pi, addr, (rval | val));230}231232void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)233{234u16 rval;235236rval = read_radio_reg(pi, addr);237write_radio_reg(pi, addr, (rval ^ mask));238}239240void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)241{242u16 rval;243244rval = read_radio_reg(pi, addr);245write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));246}247248u16 read_phy_reg(struct brcms_phy *pi, u16 addr)249{250bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);251252pi->phy_wreg = 0;253return bcma_read16(pi->d11core, D11REGOFFS(phyregdata));254}255256void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)257{258#ifdef CONFIG_BCM47XX259bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);260bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val);261if (addr == 0x72)262(void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata));263#else264bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16));265if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&266(++pi->phy_wreg >= pi->phy_wreg_limit)) {267pi->phy_wreg = 0;268(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));269}270#endif271}272273void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)274{275bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);276bcma_mask16(pi->d11core, D11REGOFFS(phyregdata), val);277pi->phy_wreg = 0;278}279280void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)281{282bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);283bcma_set16(pi->d11core, D11REGOFFS(phyregdata), val);284pi->phy_wreg = 0;285}286287void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)288{289val &= mask;290bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr);291bcma_maskset16(pi->d11core, D11REGOFFS(phyregdata), ~mask, val);292pi->phy_wreg = 0;293}294295static void wlc_set_phy_uninitted(struct brcms_phy *pi)296{297int i, j;298299pi->initialized = false;300301pi->tx_vos = 0xffff;302pi->nrssi_table_delta = 0x7fffffff;303pi->rc_cal = 0xffff;304pi->mintxbias = 0xffff;305pi->txpwridx = -1;306if (ISNPHY(pi)) {307pi->phy_spuravoid = SPURAVOID_DISABLE;308309if (NREV_GE(pi->pubpi.phy_rev, 3)310&& NREV_LT(pi->pubpi.phy_rev, 7))311pi->phy_spuravoid = SPURAVOID_AUTO;312313pi->nphy_papd_skip = 0;314pi->nphy_papd_epsilon_offset[0] = 0xf588;315pi->nphy_papd_epsilon_offset[1] = 0xf588;316pi->nphy_txpwr_idx[0] = 128;317pi->nphy_txpwr_idx[1] = 128;318pi->nphy_txpwrindex[0].index_internal = 40;319pi->nphy_txpwrindex[1].index_internal = 40;320pi->phy_pabias = 0;321} else {322pi->phy_spuravoid = SPURAVOID_AUTO;323}324pi->radiopwr = 0xffff;325for (i = 0; i < STATIC_NUM_RF; i++) {326for (j = 0; j < STATIC_NUM_BB; j++)327pi->stats_11b_txpower[i][j] = -1;328}329}330331struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)332{333struct shared_phy *sh;334335sh = kzalloc(sizeof(*sh), GFP_ATOMIC);336if (sh == NULL)337return NULL;338339sh->physhim = shp->physhim;340sh->unit = shp->unit;341sh->corerev = shp->corerev;342343sh->vid = shp->vid;344sh->did = shp->did;345sh->chip = shp->chip;346sh->chiprev = shp->chiprev;347sh->chippkg = shp->chippkg;348sh->sromrev = shp->sromrev;349sh->boardtype = shp->boardtype;350sh->boardrev = shp->boardrev;351sh->boardflags = shp->boardflags;352sh->boardflags2 = shp->boardflags2;353354sh->fast_timer = PHY_SW_TIMER_FAST;355sh->slow_timer = PHY_SW_TIMER_SLOW;356sh->glacial_timer = PHY_SW_TIMER_GLACIAL;357358sh->rssi_mode = RSSI_ANT_MERGE_MAX;359360return sh;361}362363static void wlc_phy_timercb_phycal(void *ptr)364{365struct brcms_phy *pi = ptr;366uint delay = 5;367368if (PHY_PERICAL_MPHASE_PENDING(pi)) {369if (!pi->sh->up) {370wlc_phy_cal_perical_mphase_reset(pi);371return;372}373374if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {375376delay = 1000;377wlc_phy_cal_perical_mphase_restart(pi);378} else379wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);380wlapi_add_timer(pi->phycal_timer, delay, 0);381return;382}383384}385386static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)387{388u32 ver;389390ver = read_radio_id(pi);391392return ver;393}394395struct brcms_phy_pub *396wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core,397int bandtype, struct wiphy *wiphy)398{399struct brcms_phy *pi;400u32 sflags = 0;401uint phyversion;402u32 idcode;403int i;404405if (D11REV_IS(sh->corerev, 4))406sflags = SISF_2G_PHY | SISF_5G_PHY;407else408sflags = bcma_aread32(d11core, BCMA_IOST);409410if (bandtype == BRCM_BAND_5G) {411if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)412return NULL;413}414415pi = sh->phy_head;416if ((sflags & SISF_DB_PHY) && pi) {417wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);418pi->refcnt++;419return &pi->pubpi_ro;420}421422pi = kzalloc(sizeof(*pi), GFP_ATOMIC);423if (pi == NULL)424return NULL;425pi->wiphy = wiphy;426pi->d11core = d11core;427pi->sh = sh;428pi->phy_init_por = true;429pi->phy_wreg_limit = PHY_WREG_LIMIT;430431pi->txpwr_percent = 100;432433pi->do_initcal = true;434435pi->phycal_tempdelta = 0;436437if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))438pi->pubpi.coreflags = SICF_GMODE;439440wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);441phyversion = bcma_read16(pi->d11core, D11REGOFFS(phyversion));442443pi->pubpi.phy_type = PHY_TYPE(phyversion);444pi->pubpi.phy_rev = phyversion & PV_PV_MASK;445446if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {447pi->pubpi.phy_type = PHY_TYPE_N;448pi->pubpi.phy_rev += LCNXN_BASEREV;449}450pi->pubpi.phy_corenum = PHY_CORE_NUM_2;451pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;452453if (pi->pubpi.phy_type != PHY_TYPE_N &&454pi->pubpi.phy_type != PHY_TYPE_LCN)455goto err;456457if (bandtype == BRCM_BAND_5G) {458if (!ISNPHY(pi))459goto err;460} else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {461goto err;462}463464wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);465466idcode = wlc_phy_get_radio_ver(pi);467pi->pubpi.radioid =468(idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;469pi->pubpi.radiorev =470(idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;471pi->pubpi.radiover =472(idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;473if (!VALID_RADIO(pi, pi->pubpi.radioid))474goto err;475476wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);477478wlc_set_phy_uninitted(pi);479480pi->bw = WL_CHANSPEC_BW_20;481pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?482ch20mhz_chspec(1) : ch20mhz_chspec(36);483484pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;485pi->rxiq_antsel = ANT_RX_DIV_DEF;486487pi->watchdog_override = true;488489pi->cal_type_override = PHY_PERICAL_AUTO;490491pi->nphy_saved_noisevars.bufcount = 0;492493if (ISNPHY(pi))494pi->min_txpower = PHY_TXPWR_MIN_NPHY;495else496pi->min_txpower = PHY_TXPWR_MIN;497498pi->sh->phyrxchain = 0x3;499500pi->rx2tx_biasentry = -1;501502pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;503pi->phy_txcore_enable_temp =504PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;505pi->phy_tempsense_offset = 0;506pi->phy_txcore_heatedup = false;507508pi->nphy_lastcal_temp = -50;509510pi->phynoise_polling = true;511if (ISNPHY(pi) || ISLCNPHY(pi))512pi->phynoise_polling = false;513514for (i = 0; i < TXP_NUM_RATES; i++) {515pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;516pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;517pi->tx_user_target[i] = BRCMS_TXPWR_MAX;518}519520pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;521522pi->user_txpwr_at_rfport = false;523524if (ISNPHY(pi)) {525526pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,527wlc_phy_timercb_phycal,528pi, "phycal");529if (!pi->phycal_timer)530goto err;531532wlc_phy_attach_nphy(pi);533534} else if (ISLCNPHY(pi)) {535if (!wlc_phy_attach_lcnphy(pi))536goto err;537538}539540pi->refcnt++;541pi->next = pi->sh->phy_head;542sh->phy_head = pi;543544memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));545546return &pi->pubpi_ro;547548err:549kfree(pi);550return NULL;551}552553void wlc_phy_detach(struct brcms_phy_pub *pih)554{555struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);556557if (pih) {558if (--pi->refcnt)559return;560561if (pi->phycal_timer) {562wlapi_free_timer(pi->phycal_timer);563pi->phycal_timer = NULL;564}565566if (pi->sh->phy_head == pi)567pi->sh->phy_head = pi->next;568else if (pi->sh->phy_head->next == pi)569pi->sh->phy_head->next = NULL;570571if (pi->pi_fptr.detach)572(pi->pi_fptr.detach)(pi);573574kfree(pi);575}576}577578bool579wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,580u16 *radioid, u16 *radiover)581{582struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);583*phytype = (u16) pi->pubpi.phy_type;584*phyrev = (u16) pi->pubpi.phy_rev;585*radioid = pi->pubpi.radioid;586*radiover = pi->pubpi.radiorev;587588return true;589}590591bool wlc_phy_get_encore(struct brcms_phy_pub *pih)592{593struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);594return pi->pubpi.abgphy_encore;595}596597u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)598{599struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);600return pi->pubpi.coreflags;601}602603void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)604{605struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);606607if (ISNPHY(pi)) {608if (on) {609if (NREV_GE(pi->pubpi.phy_rev, 3)) {610write_phy_reg(pi, 0xa6, 0x0d);611write_phy_reg(pi, 0x8f, 0x0);612write_phy_reg(pi, 0xa7, 0x0d);613write_phy_reg(pi, 0xa5, 0x0);614} else {615write_phy_reg(pi, 0xa5, 0x0);616}617} else {618if (NREV_GE(pi->pubpi.phy_rev, 3)) {619write_phy_reg(pi, 0x8f, 0x07ff);620write_phy_reg(pi, 0xa6, 0x0fd);621write_phy_reg(pi, 0xa5, 0x07ff);622write_phy_reg(pi, 0xa7, 0x0fd);623} else {624write_phy_reg(pi, 0xa5, 0x7fff);625}626}627} else if (ISLCNPHY(pi)) {628if (on) {629and_phy_reg(pi, 0x43b,630~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));631} else {632or_phy_reg(pi, 0x43c,633(0x1 << 0) | (0x1 << 1) | (0x1 << 2));634or_phy_reg(pi, 0x43b,635(0x1 << 0) | (0x1 << 1) | (0x1 << 2));636}637}638}639640u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)641{642struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);643644u32 phy_bw_clkbits = 0;645646if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {647switch (pi->bw) {648case WL_CHANSPEC_BW_10:649phy_bw_clkbits = SICF_BW10;650break;651case WL_CHANSPEC_BW_20:652phy_bw_clkbits = SICF_BW20;653break;654case WL_CHANSPEC_BW_40:655phy_bw_clkbits = SICF_BW40;656break;657default:658break;659}660}661662return phy_bw_clkbits;663}664665void wlc_phy_por_inform(struct brcms_phy_pub *ppi)666{667struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);668669pi->phy_init_por = true;670}671672void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)673{674struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);675676pi->do_initcal = initcal;677}678679void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)680{681struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);682683if (!pi || !pi->sh)684return;685686pi->sh->clk = newstate;687}688689void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)690{691struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);692693if (!pi || !pi->sh)694return;695696pi->sh->up = newstate;697}698699void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)700{701u32 mc;702void (*phy_init)(struct brcms_phy *) = NULL;703struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);704705if (pi->init_in_progress)706return;707708pi->init_in_progress = true;709710pi->radio_chanspec = chanspec;711712mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));713if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))714return;715716if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))717pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;718719if (WARN(!(bcma_aread32(pi->d11core, BCMA_IOST) & SISF_FCLKA),720"HW error SISF_FCLKA\n"))721return;722723phy_init = pi->pi_fptr.init;724725if (phy_init == NULL)726return;727728wlc_phy_anacore(pih, ON);729730if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)731wlapi_bmac_bw_set(pi->sh->physhim,732CHSPEC_BW(pi->radio_chanspec));733734pi->nphy_gain_boost = true;735736wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);737738(*phy_init)(pi);739740pi->phy_init_por = false;741742if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))743wlc_phy_do_dummy_tx(pi, true, OFF);744745if (!(ISNPHY(pi)))746wlc_phy_txpower_update_shm(pi);747748wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv);749750pi->init_in_progress = false;751}752753void wlc_phy_cal_init(struct brcms_phy_pub *pih)754{755struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);756void (*cal_init)(struct brcms_phy *) = NULL;757758if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &759MCTL_EN_MAC) != 0, "HW error: MAC enabled during phy cal\n"))760return;761762if (!pi->initialized) {763cal_init = pi->pi_fptr.calinit;764if (cal_init)765(*cal_init)(pi);766767pi->initialized = true;768}769}770771int wlc_phy_down(struct brcms_phy_pub *pih)772{773struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);774int callbacks = 0;775776if (pi->phycal_timer777&& !wlapi_del_timer(pi->phycal_timer))778callbacks++;779780pi->nphy_iqcal_chanspec_2G = 0;781pi->nphy_iqcal_chanspec_5G = 0;782783return callbacks;784}785786void787wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,788u16 tblAddr, u16 tblDataHi, u16 tblDataLo)789{790write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);791792pi->tbl_data_hi = tblDataHi;793pi->tbl_data_lo = tblDataLo;794795if (pi->sh->chip == BCMA_CHIP_ID_BCM43224 &&796pi->sh->chiprev == 1) {797pi->tbl_addr = tblAddr;798pi->tbl_save_id = tbl_id;799pi->tbl_save_offset = tbl_offset;800}801}802803void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)804{805if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&806(pi->sh->chiprev == 1) &&807(pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {808read_phy_reg(pi, pi->tbl_data_lo);809810write_phy_reg(pi, pi->tbl_addr,811(pi->tbl_save_id << 10) | pi->tbl_save_offset);812pi->tbl_save_offset++;813}814815if (width == 32) {816write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));817write_phy_reg(pi, pi->tbl_data_lo, (u16) val);818} else {819write_phy_reg(pi, pi->tbl_data_lo, (u16) val);820}821}822823void824wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,825u16 tblAddr, u16 tblDataHi, u16 tblDataLo)826{827uint idx;828uint tbl_id = ptbl_info->tbl_id;829uint tbl_offset = ptbl_info->tbl_offset;830uint tbl_width = ptbl_info->tbl_width;831const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;832const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;833const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;834835write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);836837for (idx = 0; idx < ptbl_info->tbl_len; idx++) {838839if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&840(pi->sh->chiprev == 1) &&841(tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {842read_phy_reg(pi, tblDataLo);843844write_phy_reg(pi, tblAddr,845(tbl_id << 10) | (tbl_offset + idx));846}847848if (tbl_width == 32) {849write_phy_reg(pi, tblDataHi,850(u16) (ptbl_32b[idx] >> 16));851write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);852} else if (tbl_width == 16) {853write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);854} else {855write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);856}857}858}859860void861wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,862u16 tblAddr, u16 tblDataHi, u16 tblDataLo)863{864uint idx;865uint tbl_id = ptbl_info->tbl_id;866uint tbl_offset = ptbl_info->tbl_offset;867uint tbl_width = ptbl_info->tbl_width;868u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;869u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;870u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;871872write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);873874for (idx = 0; idx < ptbl_info->tbl_len; idx++) {875876if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) &&877(pi->sh->chiprev == 1)) {878(void)read_phy_reg(pi, tblDataLo);879880write_phy_reg(pi, tblAddr,881(tbl_id << 10) | (tbl_offset + idx));882}883884if (tbl_width == 32) {885ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);886ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);887} else if (tbl_width == 16) {888ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);889} else {890ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);891}892}893}894895uint896wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,897struct radio_20xx_regs *radioregs)898{899uint i = 0;900901do {902if (radioregs[i].do_init)903write_radio_reg(pi, radioregs[i].address,904(u16) radioregs[i].init);905906i++;907} while (radioregs[i].address != 0xffff);908909return i;910}911912uint913wlc_phy_init_radio_regs(struct brcms_phy *pi,914const struct radio_regs *radioregs,915u16 core_offset)916{917uint i = 0;918uint count = 0;919920do {921if (CHSPEC_IS5G(pi->radio_chanspec)) {922if (radioregs[i].do_init_a) {923write_radio_reg(pi,924radioregs[i].925address | core_offset,926(u16) radioregs[i].init_a);927if (ISNPHY(pi) && (++count % 4 == 0))928BRCMS_PHY_WAR_PR51571(pi);929}930} else {931if (radioregs[i].do_init_g) {932write_radio_reg(pi,933radioregs[i].934address | core_offset,935(u16) radioregs[i].init_g);936if (ISNPHY(pi) && (++count % 4 == 0))937BRCMS_PHY_WAR_PR51571(pi);938}939}940941i++;942} while (radioregs[i].address != 0xffff);943944return i;945}946947void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)948{949#define DUMMY_PKT_LEN 20950struct bcma_device *core = pi->d11core;951int i, count;952u8 ofdmpkt[DUMMY_PKT_LEN] = {9530xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,9540x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00955};956u8 cckpkt[DUMMY_PKT_LEN] = {9570x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,9580x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00959};960u32 *dummypkt;961962dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);963wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,964dummypkt);965966bcma_write16(core, D11REGOFFS(xmtsel), 0);967968if (D11REV_GE(pi->sh->corerev, 11))969bcma_write16(core, D11REGOFFS(wepctl), 0x100);970else971bcma_write16(core, D11REGOFFS(wepctl), 0);972973bcma_write16(core, D11REGOFFS(txe_phyctl),974(ofdm ? 1 : 0) | PHY_TXC_ANT_0);975if (ISNPHY(pi) || ISLCNPHY(pi))976bcma_write16(core, D11REGOFFS(txe_phyctl1), 0x1A02);977978bcma_write16(core, D11REGOFFS(txe_wm_0), 0);979bcma_write16(core, D11REGOFFS(txe_wm_1), 0);980981bcma_write16(core, D11REGOFFS(xmttplatetxptr), 0);982bcma_write16(core, D11REGOFFS(xmttxcnt), DUMMY_PKT_LEN);983984bcma_write16(core, D11REGOFFS(xmtsel),985((8 << 8) | (1 << 5) | (1 << 2) | 2));986987bcma_write16(core, D11REGOFFS(txe_ctl), 0);988989if (!pa_on) {990if (ISNPHY(pi))991wlc_phy_pa_override_nphy(pi, OFF);992}993994if (ISNPHY(pi) || ISLCNPHY(pi))995bcma_write16(core, D11REGOFFS(txe_aux), 0xD0);996else997bcma_write16(core, D11REGOFFS(txe_aux), ((1 << 5) | (1 << 4)));998999(void)bcma_read16(core, D11REGOFFS(txe_aux));10001001i = 0;1002count = ofdm ? 30 : 250;1003while ((i++ < count)1004&& (bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 7)))1005udelay(10);10061007i = 0;10081009while ((i++ < 10) &&1010((bcma_read16(core, D11REGOFFS(txe_status)) & (1 << 10)) == 0))1011udelay(10);10121013i = 0;10141015while ((i++ < 10) &&1016((bcma_read16(core, D11REGOFFS(ifsstat)) & (1 << 8))))1017udelay(10);10181019if (!pa_on) {1020if (ISNPHY(pi))1021wlc_phy_pa_override_nphy(pi, ON);1022}1023}10241025void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)1026{1027struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);10281029if (set)1030mboolset(pi->measure_hold, id);1031else1032mboolclr(pi->measure_hold, id);10331034return;1035}10361037void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)1038{1039struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);10401041if (mute)1042mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);1043else1044mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);10451046if (!mute && (flags & PHY_MUTE_FOR_PREISM))1047pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;1048return;1049}10501051static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)1052{1053return false;1054}10551056void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)1057{1058struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);1059(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));10601061if (ISNPHY(pi)) {1062wlc_phy_switch_radio_nphy(pi, on);1063} else if (ISLCNPHY(pi)) {1064if (on) {1065and_phy_reg(pi, 0x44c,1066~((0x1 << 8) |1067(0x1 << 9) |1068(0x1 << 10) | (0x1 << 11) | (0x1 << 12)));1069and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));1070and_phy_reg(pi, 0x4f9, ~(0x1 << 3));1071} else {1072and_phy_reg(pi, 0x44d,1073~((0x1 << 10) |1074(0x1 << 11) |1075(0x1 << 12) | (0x1 << 13) | (0x1 << 14)));1076or_phy_reg(pi, 0x44c,1077(0x1 << 8) |1078(0x1 << 9) |1079(0x1 << 10) | (0x1 << 11) | (0x1 << 12));10801081and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));1082and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));1083or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));1084and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));1085or_phy_reg(pi, 0x4f9, (0x1 << 3));1086}1087}1088}10891090void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)1091{1092struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);10931094pi->bw = bw;1095}10961097void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)1098{1099struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1100pi->radio_chanspec = newch;11011102}11031104u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)1105{1106struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);11071108return pi->radio_chanspec;1109}11101111void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)1112{1113struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1114u16 m_cur_channel;1115void (*chanspec_set)(struct brcms_phy *, u16) = NULL;1116m_cur_channel = CHSPEC_CHANNEL(chanspec);1117if (CHSPEC_IS5G(chanspec))1118m_cur_channel |= D11_CURCHANNEL_5G;1119if (CHSPEC_IS40(chanspec))1120m_cur_channel |= D11_CURCHANNEL_40;1121wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);11221123chanspec_set = pi->pi_fptr.chanset;1124if (chanspec_set)1125(*chanspec_set)(pi, chanspec);11261127}11281129void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,1130bool wide_filter)1131{1132struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);11331134pi->channel_14_wide_filter = wide_filter;11351136}11371138int wlc_phy_channel2freq(uint channel)1139{1140uint i;11411142for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)1143if (chan_info_all[i].chan == channel)1144return chan_info_all[i].freq;1145return 0;1146}11471148void1149wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,1150struct brcms_chanvec *channels)1151{1152struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1153uint i;1154uint channel;11551156memset(channels, 0, sizeof(struct brcms_chanvec));11571158for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {1159channel = chan_info_all[i].chan;11601161if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)1162&& (channel <= LAST_REF5_CHANNUM))1163continue;11641165if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||1166(band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))1167setbit(channels->vec, channel);1168}1169}11701171int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)1172{1173struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);11741175*qdbm = pi->tx_user_target[0];1176if (override != NULL)1177*override = pi->txpwroverride;1178return 0;1179}11801181int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)1182{1183struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1184int i;11851186if (qdbm > 127)1187return -EINVAL;11881189for (i = 0; i < TXP_NUM_RATES; i++)1190pi->tx_user_target[i] = (u8) qdbm;11911192pi->txpwroverride = false;11931194if (pi->sh->up) {1195if (!SCAN_INPROG_PHY(pi)) {1196bool suspend;11971198suspend = (0 == (bcma_read32(pi->d11core,1199D11REGOFFS(maccontrol)) &1200MCTL_EN_MAC));12011202if (!suspend)1203wlapi_suspend_mac_and_wait(pi->sh->physhim);12041205wlc_phy_txpower_recalc_target(pi);1206wlc_phy_cal_txpower_recalc_sw(pi);12071208if (!suspend)1209wlapi_enable_mac(pi->sh->physhim);1210}1211}1212return 0;1213}12141215void1216wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,1217u8 *max_pwr, int txp_rate_idx)1218{1219struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1220uint i;12211222*min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;12231224if (ISNPHY(pi)) {1225if (txp_rate_idx < 0)1226txp_rate_idx = TXP_FIRST_CCK;1227wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,1228(u8) txp_rate_idx);12291230} else if ((channel <= CH_MAX_2G_CHANNEL)) {1231if (txp_rate_idx < 0)1232txp_rate_idx = TXP_FIRST_CCK;1233*max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];1234} else {12351236*max_pwr = BRCMS_TXPWR_MAX;12371238if (txp_rate_idx < 0)1239txp_rate_idx = TXP_FIRST_OFDM;12401241for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {1242if (channel == chan_info_all[i].chan)1243break;1244}12451246if (pi->hwtxpwr) {1247*max_pwr = pi->hwtxpwr[i];1248} else {12491250if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))1251*max_pwr =1252pi->tx_srom_max_rate_5g_mid[txp_rate_idx];1253if ((i >= FIRST_HIGH_5G_CHAN)1254&& (i <= LAST_HIGH_5G_CHAN))1255*max_pwr =1256pi->tx_srom_max_rate_5g_hi[txp_rate_idx];1257if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))1258*max_pwr =1259pi->tx_srom_max_rate_5g_low[txp_rate_idx];1260}1261}1262}12631264static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)1265{1266if (ISLCNPHY(pi))1267return wlc_lcnphy_vbatsense(pi, 0);1268else1269return 0;1270}12711272static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)1273{1274if (ISLCNPHY(pi))1275return wlc_lcnphy_tempsense_degree(pi, 0);1276else1277return 0;1278}12791280static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)1281{1282u8 i;12831284for (i = 0; i < TXP_NUM_RATES; i++)1285pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;12861287wlc_phy_env_measure_vbat(pi);1288wlc_phy_env_measure_temperature(pi);1289}12901291static s81292wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,1293u8 rate)1294{1295return 0;1296}12971298void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)1299{1300u8 maxtxpwr, mintxpwr, rate, pactrl;1301uint target_chan;1302u8 tx_pwr_target[TXP_NUM_RATES];1303u8 tx_pwr_max = 0;1304u8 tx_pwr_min = 255;1305u8 tx_pwr_max_rate_ind = 0;1306u8 max_num_rate;1307u8 start_rate = 0;1308u16 chspec;1309u32 band = CHSPEC2BAND(pi->radio_chanspec);1310void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;13111312chspec = pi->radio_chanspec;1313if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)1314target_chan = CHSPEC_CHANNEL(chspec);1315else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)1316target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));1317else1318target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));13191320pactrl = 0;1321if (ISLCNPHY(pi)) {1322u32 offset_mcs, i;13231324if (CHSPEC_IS40(pi->radio_chanspec)) {1325offset_mcs = pi->mcs40_po;1326for (i = TXP_FIRST_SISO_MCS_20;1327i <= TXP_LAST_SISO_MCS_20; i++) {1328pi->tx_srom_max_rate_2g[i - 8] =1329pi->tx_srom_max_2g -1330((offset_mcs & 0xf) * 2);1331offset_mcs >>= 4;1332}1333} else {1334offset_mcs = pi->mcs20_po;1335for (i = TXP_FIRST_SISO_MCS_20;1336i <= TXP_LAST_SISO_MCS_20; i++) {1337pi->tx_srom_max_rate_2g[i - 8] =1338pi->tx_srom_max_2g -1339((offset_mcs & 0xf) * 2);1340offset_mcs >>= 4;1341}1342}1343}13441345max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :1346((ISLCNPHY(pi)) ?1347(TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));13481349wlc_phy_upd_env_txpwr_rate_limits(pi, band);13501351for (rate = start_rate; rate < max_num_rate; rate++) {13521353tx_pwr_target[rate] = pi->tx_user_target[rate];13541355if (pi->user_txpwr_at_rfport)1356tx_pwr_target[rate] +=1357wlc_user_txpwr_antport_to_rfport(pi,1358target_chan,1359band,1360rate);13611362wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,1363target_chan,1364&mintxpwr, &maxtxpwr, rate);13651366maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);13671368maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;13691370maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;13711372maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);13731374if (pi->txpwr_percent <= 100)1375maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;13761377tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);13781379tx_pwr_target[rate] =1380min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);13811382if (tx_pwr_target[rate] > tx_pwr_max)1383tx_pwr_max_rate_ind = rate;13841385tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);1386tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);1387}13881389memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));1390pi->tx_power_max = tx_pwr_max;1391pi->tx_power_min = tx_pwr_min;1392pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;1393for (rate = 0; rate < max_num_rate; rate++) {13941395pi->tx_power_target[rate] = tx_pwr_target[rate];13961397if (!pi->hwpwrctrl || ISNPHY(pi))1398pi->tx_power_offset[rate] =1399pi->tx_power_max - pi->tx_power_target[rate];1400else1401pi->tx_power_offset[rate] =1402pi->tx_power_target[rate] - pi->tx_power_min;1403}14041405txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;1406if (txpwr_recalc_fn)1407(*txpwr_recalc_fn)(pi);1408}14091410static void1411wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,1412u16 chanspec)1413{1414u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];1415u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;1416int rate_start_index = 0, rate1, rate2, k;14171418for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;1419rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)1420pi->txpwr_limit[rate1] = txpwr->cck[rate2];14211422for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;1423rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)1424pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];14251426if (ISNPHY(pi)) {14271428for (k = 0; k < 4; k++) {1429switch (k) {1430case 0:14311432txpwr_ptr1 = txpwr->mcs_20_siso;1433txpwr_ptr2 = txpwr->ofdm;1434rate_start_index = WL_TX_POWER_OFDM_FIRST;1435break;1436case 1:14371438txpwr_ptr1 = txpwr->mcs_20_cdd;1439txpwr_ptr2 = txpwr->ofdm_cdd;1440rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;1441break;1442case 2:14431444txpwr_ptr1 = txpwr->mcs_40_siso;1445txpwr_ptr2 = txpwr->ofdm_40_siso;1446rate_start_index =1447WL_TX_POWER_OFDM40_SISO_FIRST;1448break;1449case 3:14501451txpwr_ptr1 = txpwr->mcs_40_cdd;1452txpwr_ptr2 = txpwr->ofdm_40_cdd;1453rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;1454break;1455}14561457for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;1458rate2++) {1459tmp_txpwr_limit[rate2] = 0;1460tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =1461txpwr_ptr1[rate2];1462}1463wlc_phy_mcs_to_ofdm_powers_nphy(1464tmp_txpwr_limit, 0,1465BRCMS_NUM_RATES_OFDM -14661, BRCMS_NUM_RATES_OFDM);1467for (rate1 = rate_start_index, rate2 = 0;1468rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)1469pi->txpwr_limit[rate1] =1470min(txpwr_ptr2[rate2],1471tmp_txpwr_limit[rate2]);1472}14731474for (k = 0; k < 4; k++) {1475switch (k) {1476case 0:14771478txpwr_ptr1 = txpwr->ofdm;1479txpwr_ptr2 = txpwr->mcs_20_siso;1480rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;1481break;1482case 1:14831484txpwr_ptr1 = txpwr->ofdm_cdd;1485txpwr_ptr2 = txpwr->mcs_20_cdd;1486rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;1487break;1488case 2:14891490txpwr_ptr1 = txpwr->ofdm_40_siso;1491txpwr_ptr2 = txpwr->mcs_40_siso;1492rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;1493break;1494case 3:14951496txpwr_ptr1 = txpwr->ofdm_40_cdd;1497txpwr_ptr2 = txpwr->mcs_40_cdd;1498rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;1499break;1500}1501for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;1502rate2++) {1503tmp_txpwr_limit[rate2] = 0;1504tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =1505txpwr_ptr1[rate2];1506}1507wlc_phy_ofdm_to_mcs_powers_nphy(1508tmp_txpwr_limit, 0,1509BRCMS_NUM_RATES_OFDM -15101, BRCMS_NUM_RATES_OFDM);1511for (rate1 = rate_start_index, rate2 = 0;1512rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;1513rate1++, rate2++)1514pi->txpwr_limit[rate1] =1515min(txpwr_ptr2[rate2],1516tmp_txpwr_limit[rate2]);1517}15181519for (k = 0; k < 2; k++) {1520switch (k) {1521case 0:15221523rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;1524txpwr_ptr1 = txpwr->mcs_20_stbc;1525break;1526case 1:15271528rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;1529txpwr_ptr1 = txpwr->mcs_40_stbc;1530break;1531}1532for (rate1 = rate_start_index, rate2 = 0;1533rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;1534rate1++, rate2++)1535pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];1536}15371538for (k = 0; k < 2; k++) {1539switch (k) {1540case 0:15411542rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;1543txpwr_ptr1 = txpwr->mcs_20_mimo;1544break;1545case 1:15461547rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;1548txpwr_ptr1 = txpwr->mcs_40_mimo;1549break;1550}1551for (rate1 = rate_start_index, rate2 = 0;1552rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;1553rate1++, rate2++)1554pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];1555}15561557pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;15581559pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =1560min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],1561pi->txpwr_limit[WL_TX_POWER_MCS_32]);1562pi->txpwr_limit[WL_TX_POWER_MCS_32] =1563pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];1564}1565}15661567void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)1568{1569struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);15701571pi->sh->machwcap = machwcap;1572}15731574void1575wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,1576u16 chanspec)1577{1578struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);15791580wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);15811582if (ISLCNPHY(pi)) {1583int i, j;1584for (i = TXP_FIRST_OFDM_20_CDD, j = 0;1585j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {1586if (txpwr->mcs_20_siso[j])1587pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];1588else1589pi->txpwr_limit[i] = txpwr->ofdm[j];1590}1591}15921593wlapi_suspend_mac_and_wait(pi->sh->physhim);15941595wlc_phy_txpower_recalc_target(pi);1596wlc_phy_cal_txpower_recalc_sw(pi);1597wlapi_enable_mac(pi->sh->physhim);1598}15991600void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)1601{1602struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);16031604pi->ofdm_rateset_war = war;1605}16061607void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)1608{1609struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);16101611pi->bf_preempt_4306 = bf_preempt;1612}16131614void wlc_phy_txpower_update_shm(struct brcms_phy *pi)1615{1616int j;1617if (ISNPHY(pi))1618return;16191620if (!pi->sh->clk)1621return;16221623if (pi->hwpwrctrl) {1624u16 offset;16251626wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);1627wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,16281 << NUM_TSSI_FRAMES);16291630wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,1631pi->tx_power_min << NUM_TSSI_FRAMES);16321633wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,1634pi->hwpwr_txcur);16351636for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {1637static const u8 ucode_ofdm_rates[] = {16380x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c1639};1640offset = wlapi_bmac_rate_shm_offset(1641pi->sh->physhim,1642ucode_ofdm_rates[j - TXP_FIRST_OFDM]);1643wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,1644pi->tx_power_offset[j]);1645wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,1646-(pi->tx_power_offset[j] / 2));1647}16481649wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,1650MHF2_HWPWRCTL, BRCM_BAND_ALL);1651} else {1652int i;16531654for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)1655pi->tx_power_offset[i] =1656(u8) roundup(pi->tx_power_offset[i], 8);1657wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,1658(u16)1659((pi->tx_power_offset[TXP_FIRST_OFDM]1660+ 7) >> 3));1661}1662}16631664bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)1665{1666struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);16671668if (ISNPHY(pi))1669return pi->nphy_txpwrctrl;1670else1671return pi->hwpwrctrl;1672}16731674void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)1675{16761677if (NREV_GE(pi->pubpi.phy_rev, 3)) {1678pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);1679pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);1680} else {1681pi->ipa2g_on = false;1682pi->ipa5g_on = false;1683}1684}16851686static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)1687{1688s16 tx0_status, tx1_status;1689u16 estPower1, estPower2;1690u8 pwr0, pwr1, adj_pwr0, adj_pwr1;1691u32 est_pwr;16921693estPower1 = read_phy_reg(pi, 0x118);1694estPower2 = read_phy_reg(pi, 0x119);16951696if ((estPower1 & (0x1 << 8)) == (0x1 << 8))1697pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;1698else1699pwr0 = 0x80;17001701if ((estPower2 & (0x1 << 8)) == (0x1 << 8))1702pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;1703else1704pwr1 = 0x80;17051706tx0_status = read_phy_reg(pi, 0x1ed);1707tx1_status = read_phy_reg(pi, 0x1ee);17081709if ((tx0_status & (0x1 << 15)) == (0x1 << 15))1710adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;1711else1712adj_pwr0 = 0x80;1713if ((tx1_status & (0x1 << 15)) == (0x1 << 15))1714adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;1715else1716adj_pwr1 = 0x80;17171718est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |1719adj_pwr1);17201721return est_pwr;1722}17231724void1725wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,1726uint channel)1727{1728struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1729uint rate, num_rates;1730u8 min_pwr, max_pwr;17311732#if WL_TX_POWER_RATES != TXP_NUM_RATES1733#error "struct tx_power out of sync with this fn"1734#endif17351736if (ISNPHY(pi)) {1737power->rf_cores = 2;1738power->flags |= (WL_TX_POWER_F_MIMO);1739if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)1740power->flags |=1741(WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);1742} else if (ISLCNPHY(pi)) {1743power->rf_cores = 1;1744power->flags |= (WL_TX_POWER_F_SISO);1745if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)1746power->flags |= WL_TX_POWER_F_ENABLED;1747if (pi->hwpwrctrl)1748power->flags |= WL_TX_POWER_F_HW;1749}17501751num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :1752((ISLCNPHY(pi)) ?1753(TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));17541755for (rate = 0; rate < num_rates; rate++) {1756power->user_limit[rate] = pi->tx_user_target[rate];1757wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,1758rate);1759power->board_limit[rate] = (u8) max_pwr;1760power->target[rate] = pi->tx_power_target[rate];1761}17621763if (ISNPHY(pi)) {1764u32 est_pout;17651766wlapi_suspend_mac_and_wait(pi->sh->physhim);1767wlc_phyreg_enter((struct brcms_phy_pub *) pi);1768est_pout = wlc_phy_txpower_est_power_nphy(pi);1769wlc_phyreg_exit((struct brcms_phy_pub *) pi);1770wlapi_enable_mac(pi->sh->physhim);17711772power->est_Pout[0] = (est_pout >> 8) & 0xff;1773power->est_Pout[1] = est_pout & 0xff;17741775power->est_Pout_act[0] = est_pout >> 24;1776power->est_Pout_act[1] = (est_pout >> 16) & 0xff;17771778if (power->est_Pout[0] == 0x80)1779power->est_Pout[0] = 0;1780if (power->est_Pout[1] == 0x80)1781power->est_Pout[1] = 0;17821783if (power->est_Pout_act[0] == 0x80)1784power->est_Pout_act[0] = 0;1785if (power->est_Pout_act[1] == 0x80)1786power->est_Pout_act[1] = 0;17871788power->est_Pout_cck = 0;17891790power->tx_power_max[0] = pi->tx_power_max;1791power->tx_power_max[1] = pi->tx_power_max;17921793power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;1794power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;1795} else if (pi->hwpwrctrl && pi->sh->up) {17961797wlc_phyreg_enter(ppi);1798if (ISLCNPHY(pi)) {17991800power->tx_power_max[0] = pi->tx_power_max;1801power->tx_power_max[1] = pi->tx_power_max;18021803power->tx_power_max_rate_ind[0] =1804pi->tx_power_max_rate_ind;1805power->tx_power_max_rate_ind[1] =1806pi->tx_power_max_rate_ind;18071808if (wlc_phy_tpc_isenabled_lcnphy(pi))1809power->flags |=1810(WL_TX_POWER_F_HW |1811WL_TX_POWER_F_ENABLED);1812else1813power->flags &=1814~(WL_TX_POWER_F_HW |1815WL_TX_POWER_F_ENABLED);18161817wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],1818(s8 *) &power->est_Pout_cck);1819}1820wlc_phyreg_exit(ppi);1821}1822}18231824void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)1825{1826struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);18271828pi->antsel_type = antsel_type;1829}18301831void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)1832{1833struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);1834bool suspend;18351836pi->sh->rx_antdiv = val;18371838if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {1839if (val > ANT_RX_DIV_FORCE_1)1840wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,1841MHF1_ANTDIV, BRCM_BAND_ALL);1842else1843wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,1844BRCM_BAND_ALL);1845}18461847if (ISNPHY(pi))1848return;18491850if (!pi->sh->clk)1851return;18521853suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &1854MCTL_EN_MAC));1855if (!suspend)1856wlapi_suspend_mac_and_wait(pi->sh->physhim);18571858if (ISLCNPHY(pi)) {1859if (val > ANT_RX_DIV_FORCE_1) {1860mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);1861mod_phy_reg(pi, 0x410,1862(0x1 << 0),1863((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);1864} else {1865mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);1866mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);1867}1868}18691870if (!suspend)1871wlapi_enable_mac(pi->sh->physhim);18721873return;1874}18751876static bool1877wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)1878{1879s8 cmplx_pwr_dbm[PHY_CORE_MAX];1880u8 i;18811882memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));1883wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);18841885for (i = 0; i < pi->pubpi.phy_corenum; i++) {1886if (NREV_GE(pi->pubpi.phy_rev, 3))1887cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;1888else18891890cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);1891}18921893for (i = 0; i < pi->pubpi.phy_corenum; i++) {1894pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];1895pwr_ant[i] = cmplx_pwr_dbm[i];1896}1897pi->nphy_noise_index =1898MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);1899return true;1900}19011902static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)1903{1904if (!pi->phynoise_state)1905return;19061907if (pi->phynoise_state & PHY_NOISE_STATE_MON) {1908if (pi->phynoise_chan_watchdog == channel) {1909pi->sh->phy_noise_window[pi->sh->phy_noise_index] =1910noise_dbm;1911pi->sh->phy_noise_index =1912MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);1913}1914pi->phynoise_state &= ~PHY_NOISE_STATE_MON;1915}19161917if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)1918pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;19191920}19211922static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)1923{1924u32 cmplx_pwr[PHY_CORE_MAX];1925s8 noise_dbm_ant[PHY_CORE_MAX];1926u16 lo, hi;1927u32 cmplx_pwr_tot = 0;1928s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;1929u8 idx, core;19301931memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));1932memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));19331934for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,1935core++) {1936lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));1937hi = wlapi_bmac_read_shm(pi->sh->physhim,1938M_PWRIND_MAP(idx + 1));1939cmplx_pwr[core] = (hi << 16) + lo;1940cmplx_pwr_tot += cmplx_pwr[core];1941if (cmplx_pwr[core] == 0)1942noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;1943else1944cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;1945}19461947if (cmplx_pwr_tot != 0)1948wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);19491950for (core = 0; core < pi->pubpi.phy_corenum; core++) {1951pi->nphy_noise_win[core][pi->nphy_noise_index] =1952noise_dbm_ant[core];19531954if (noise_dbm_ant[core] > noise_dbm)1955noise_dbm = noise_dbm_ant[core];1956}1957pi->nphy_noise_index =1958MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);19591960return noise_dbm;19611962}19631964void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)1965{1966struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);1967u16 jssi_aux;1968u8 channel = 0;1969s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;19701971if (ISLCNPHY(pi)) {1972u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;1973u16 lo, hi;1974s32 pwr_offset_dB, gain_dB;1975u16 status_0, status_1;19761977jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);1978channel = jssi_aux & D11_CURCHANNEL_MAX;19791980lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);1981hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);1982cmplx_pwr0 = (hi << 16) + lo;19831984lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);1985hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);1986cmplx_pwr1 = (hi << 16) + lo;1987cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;19881989status_0 = 0x44;1990status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);1991if ((cmplx_pwr > 0 && cmplx_pwr < 500)1992&& ((status_1 & 0xc000) == 0x4000)) {19931994wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,1995pi->pubpi.phy_corenum);1996pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);1997if (pwr_offset_dB > 127)1998pwr_offset_dB -= 256;19992000noise_dbm += (s8) (pwr_offset_dB - 30);20012002gain_dB = (status_0 & 0x1ff);2003noise_dbm -= (s8) (gain_dB);2004} else {2005noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;2006}2007} else if (ISNPHY(pi)) {20082009jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);2010channel = jssi_aux & D11_CURCHANNEL_MAX;20112012noise_dbm = wlc_phy_noise_read_shmem(pi);2013}20142015wlc_phy_noise_cb(pi, channel, noise_dbm);20162017}20182019static void2020wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)2021{2022struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);2023s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;2024bool sampling_in_progress = (pi->phynoise_state != 0);2025bool wait_for_intr = true;20262027switch (reason) {2028case PHY_NOISE_SAMPLE_MON:2029pi->phynoise_chan_watchdog = ch;2030pi->phynoise_state |= PHY_NOISE_STATE_MON;2031break;20322033case PHY_NOISE_SAMPLE_EXTERNAL:2034pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;2035break;20362037default:2038break;2039}20402041if (sampling_in_progress)2042return;20432044pi->phynoise_now = pi->sh->now;20452046if (pi->phy_fixed_noise) {2047if (ISNPHY(pi)) {2048pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =2049PHY_NOISE_FIXED_VAL_NPHY;2050pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =2051PHY_NOISE_FIXED_VAL_NPHY;2052pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,2053PHY_NOISE_WINDOW_SZ);2054noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;2055} else {2056noise_dbm = PHY_NOISE_FIXED_VAL;2057}20582059wait_for_intr = false;2060goto done;2061}20622063if (ISLCNPHY(pi)) {2064if (!pi->phynoise_polling2065|| (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {2066wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);2067wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);2068wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);2069wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);2070wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);20712072bcma_set32(pi->d11core, D11REGOFFS(maccommand),2073MCMD_BG_NOISE);2074} else {2075wlapi_suspend_mac_and_wait(pi->sh->physhim);2076wlc_lcnphy_deaf_mode(pi, (bool) 0);2077noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);2078wlc_lcnphy_deaf_mode(pi, (bool) 1);2079wlapi_enable_mac(pi->sh->physhim);2080wait_for_intr = false;2081}2082} else if (ISNPHY(pi)) {2083if (!pi->phynoise_polling2084|| (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {20852086wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);2087wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);2088wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);2089wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);20902091bcma_set32(pi->d11core, D11REGOFFS(maccommand),2092MCMD_BG_NOISE);2093} else {2094struct phy_iq_est est[PHY_CORE_MAX];2095u32 cmplx_pwr[PHY_CORE_MAX];2096s8 noise_dbm_ant[PHY_CORE_MAX];2097u16 log_num_samps, num_samps, classif_state = 0;2098u8 wait_time = 32;2099u8 wait_crs = 0;2100u8 i;21012102memset((u8 *) est, 0, sizeof(est));2103memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));2104memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));21052106log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;2107num_samps = 1 << log_num_samps;21082109wlapi_suspend_mac_and_wait(pi->sh->physhim);2110classif_state = wlc_phy_classifier_nphy(pi, 0, 0);2111wlc_phy_classifier_nphy(pi, 3, 0);2112wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,2113wait_crs);2114wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);2115wlapi_enable_mac(pi->sh->physhim);21162117for (i = 0; i < pi->pubpi.phy_corenum; i++)2118cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>2119log_num_samps;21202121wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);21222123for (i = 0; i < pi->pubpi.phy_corenum; i++) {2124pi->nphy_noise_win[i][pi->nphy_noise_index] =2125noise_dbm_ant[i];21262127if (noise_dbm_ant[i] > noise_dbm)2128noise_dbm = noise_dbm_ant[i];2129}2130pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,2131PHY_NOISE_WINDOW_SZ);21322133wait_for_intr = false;2134}2135}21362137done:21382139if (!wait_for_intr)2140wlc_phy_noise_cb(pi, ch, noise_dbm);21412142}21432144static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {21458,21468,21478,21488,21498,21508,21518,21529,215310,21548,21558,21567,21577,21581,21592,21602,21612,21622,21632,21642,21652,21662,21672,21682,21692,21702,21712,21722,21732,21742,21752,21762,21771,21781,21790,21800,21810,218202183};21842185void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)2186{2187u8 msb, secondmsb, i;2188u32 tmp;21892190for (i = 0; i < core; i++) {2191secondmsb = 0;2192tmp = cmplx_pwr[i];2193msb = fls(tmp);2194if (msb)2195secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);2196p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);2197}2198}21992200int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,2201struct d11rxhdr *rxh)2202{2203int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;2204uint radioid = pih->radioid;2205struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);22062207if ((pi->sh->corerev >= 11)2208&& !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {2209rssi = BRCMS_RSSI_INVALID;2210goto end;2211}22122213if (ISLCNPHY(pi)) {2214u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;2215struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;22162217if (rssi > 127)2218rssi -= 256;22192220rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];2221if ((rssi > -46) && (gidx > 18))2222rssi = rssi + 7;22232224rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;22252226rssi = rssi + 2;22272228}22292230if (ISLCNPHY(pi)) {2231if (rssi > 127)2232rssi -= 256;2233} else if (radioid == BCM2055_ID || radioid == BCM2056_ID2234|| radioid == BCM2057_ID) {2235rssi = wlc_phy_rssi_compute_nphy(pi, rxh);2236}22372238end:2239return rssi;2240}22412242void wlc_phy_watchdog(struct brcms_phy_pub *pih)2243{2244struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);2245bool delay_phy_cal = false;2246pi->sh->now++;22472248if (!pi->watchdog_override)2249return;22502251if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))2252wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,2253PHY_NOISE_SAMPLE_MON,2254CHSPEC_CHANNEL(pi->2255radio_chanspec));22562257if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)2258pi->phynoise_state = 0;22592260if ((!pi->phycal_txpower) ||2261((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {22622263if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))2264pi->phycal_txpower = pi->sh->now;2265}22662267if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)2268|| ASSOC_INPROG_PHY(pi)))2269return;22702271if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {22722273if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&2274(pi->nphy_perical != PHY_PERICAL_MANUAL) &&2275((pi->sh->now - pi->nphy_perical_last) >=2276pi->sh->glacial_timer))2277wlc_phy_cal_perical((struct brcms_phy_pub *) pi,2278PHY_PERICAL_WATCHDOG);22792280wlc_phy_txpwr_papd_cal_nphy(pi);2281}22822283if (ISLCNPHY(pi)) {2284if (pi->phy_forcecal ||2285((pi->sh->now - pi->phy_lastcal) >=2286pi->sh->glacial_timer)) {2287if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))2288wlc_lcnphy_calib_modes(2289pi,2290LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);2291if (!2292(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)2293|| ASSOC_INPROG_PHY(pi)2294|| pi->carrier_suppr_disable2295|| pi->disable_percal))2296wlc_lcnphy_calib_modes(pi,2297PHY_PERICAL_WATCHDOG);2298}2299}2300}23012302void2303wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)2304{2305*eps_imag = (epsilon >> 13);2306if (*eps_imag > 0xfff)2307*eps_imag -= 0x2000;23082309*eps_real = (epsilon & 0x1fff);2310if (*eps_real > 0xfff)2311*eps_real -= 0x2000;2312}23132314void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)2315{2316wlapi_del_timer(pi->phycal_timer);23172318pi->cal_type_override = PHY_PERICAL_AUTO;2319pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;2320pi->mphase_txcal_cmdidx = 0;2321}23222323static void2324wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)2325{23262327if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&2328(pi->nphy_perical != PHY_PERICAL_MANUAL))2329return;23302331wlapi_del_timer(pi->phycal_timer);23322333pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;2334wlapi_add_timer(pi->phycal_timer, delay, 0);2335}23362337void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)2338{2339s16 nphy_currtemp = 0;2340s16 delta_temp = 0;2341bool do_periodic_cal = true;2342struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);23432344if (!ISNPHY(pi))2345return;23462347if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||2348(pi->nphy_perical == PHY_PERICAL_MANUAL))2349return;23502351switch (reason) {2352case PHY_PERICAL_DRIVERUP:2353break;23542355case PHY_PERICAL_PHYINIT:2356if (pi->nphy_perical == PHY_PERICAL_MPHASE) {2357if (PHY_PERICAL_MPHASE_PENDING(pi))2358wlc_phy_cal_perical_mphase_reset(pi);23592360wlc_phy_cal_perical_mphase_schedule(2361pi,2362PHY_PERICAL_INIT_DELAY);2363}2364break;23652366case PHY_PERICAL_JOIN_BSS:2367case PHY_PERICAL_START_IBSS:2368case PHY_PERICAL_UP_BSS:2369if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&2370PHY_PERICAL_MPHASE_PENDING(pi))2371wlc_phy_cal_perical_mphase_reset(pi);23722373pi->first_cal_after_assoc = true;23742375pi->cal_type_override = PHY_PERICAL_FULL;23762377if (pi->phycal_tempdelta)2378pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);23792380wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);2381break;23822383case PHY_PERICAL_WATCHDOG:2384if (pi->phycal_tempdelta) {2385nphy_currtemp = wlc_phy_tempsense_nphy(pi);2386delta_temp =2387(nphy_currtemp > pi->nphy_lastcal_temp) ?2388nphy_currtemp - pi->nphy_lastcal_temp :2389pi->nphy_lastcal_temp - nphy_currtemp;23902391if ((delta_temp < (s16) pi->phycal_tempdelta) &&2392(pi->nphy_txiqlocal_chanspec ==2393pi->radio_chanspec))2394do_periodic_cal = false;2395else2396pi->nphy_lastcal_temp = nphy_currtemp;2397}23982399if (do_periodic_cal) {2400if (pi->nphy_perical == PHY_PERICAL_MPHASE) {2401if (!PHY_PERICAL_MPHASE_PENDING(pi))2402wlc_phy_cal_perical_mphase_schedule(2403pi,2404PHY_PERICAL_WDOG_DELAY);2405} else if (pi->nphy_perical == PHY_PERICAL_SPHASE)2406wlc_phy_cal_perical_nphy_run(pi,2407PHY_PERICAL_AUTO);2408}2409break;2410default:2411break;2412}2413}24142415void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)2416{2417pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;2418pi->mphase_txcal_cmdidx = 0;2419}24202421u8 wlc_phy_nbits(s32 value)2422{2423s32 abs_val;2424u8 nbits = 0;24252426abs_val = abs(value);2427while ((abs_val >> nbits) > 0)2428nbits++;24292430return nbits;2431}24322433void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)2434{2435struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);24362437pi->sh->hw_phytxchain = txchain;2438pi->sh->hw_phyrxchain = rxchain;2439pi->sh->phytxchain = txchain;2440pi->sh->phyrxchain = rxchain;2441pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);2442}24432444void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)2445{2446struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);24472448pi->sh->phytxchain = txchain;24492450if (ISNPHY(pi))2451wlc_phy_rxcore_setstate_nphy(pih, rxchain);24522453pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);2454}24552456u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)2457{2458s16 nphy_currtemp;2459u8 active_bitmap;2460struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);24612462active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;24632464if (!pi->watchdog_override)2465return active_bitmap;24662467if (NREV_GE(pi->pubpi.phy_rev, 6)) {2468wlapi_suspend_mac_and_wait(pi->sh->physhim);2469nphy_currtemp = wlc_phy_tempsense_nphy(pi);2470wlapi_enable_mac(pi->sh->physhim);24712472if (!pi->phy_txcore_heatedup) {2473if (nphy_currtemp >= pi->phy_txcore_disable_temp) {2474active_bitmap &= 0xFD;2475pi->phy_txcore_heatedup = true;2476}2477} else {2478if (nphy_currtemp <= pi->phy_txcore_enable_temp) {2479active_bitmap |= 0x2;2480pi->phy_txcore_heatedup = false;2481}2482}2483}24842485return active_bitmap;2486}24872488const u8 *wlc_phy_get_ofdm_rate_lookup(void)2489{2490return ofdm_rate_lookup;2491}24922493void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)2494{2495return;2496}249724982499